how to pass +, -, etc. to macro in Nim - macros

I want to do something like this macro in Nim
#define BINARY_OP(op) \
do { \
double left = getLast(); \
double right = getLast(); \
push(right op left); \
} while (false)
I tried to do this:
macro binaryOp(op: untyped) =
let right = getLast()
let left = getLast()
vm.push(left op right)
But the compiler throws an error:
Error: attempting to call routine: 'op'
How can I fix this?
Update
I want to use the macro like this:
binaryop(+)

Nim macros are not like C macros, they're code generators that take in source code. What you want is a template, which is akin to C macros, but still more sophisticated.
template binaryOp(op: untyped) =
let right = 10
let left = 20
echo op(left, right)
binaryOp(`+`)
In this case you need to use backticks to lexically strop +, explained here.

Related

Julia: Macros, Expressions and Meta.parse

All these following lines of code are Julia expressions:
x = 10
1 + 1
println("hi")
if you want to pass an expression to a macro, it works like this. Macro foo just returns the given expression, which will be executed:
macro foo(ex)
return ex
end
#foo println("yes") # prints yes
x = #foo 1+1
println(x) # prints 2
If you want to convert a string into an expression, you can use Meta.parse():
string = "1+1"
expr = Meta.parse(string)
x = #foo expr
println(x) # prints 1 + 1
But, obviously, the macro treats expr as a symbol. What am i getting wrong here?
Thanks in advance!
Macro hygiene is important "macros must ensure that the variables they introduce in their returned expressions do not accidentally clash with existing variables in the surrounding code they expand into." There is a section in the docs. It is easiest just to show a simple case:
macro foo(x)
return :($x)
end
When you enter an ordinary expression in the REPL, it is evaluated immediately. To suppress that evaluation, surround the expression with :( ).
julia> 1 + 1
2
julia> :(1 + 1)
:(1 + 1)
# note this is the same result as you get using Meta.parse
julia> Meta.parse("1 + 1")
:(1 + 1)
So, Meta.parse will convert an appropriate string to an expression. And if you eval the result, the expression will be evaluated. Note that printing a simple expression removes the outer :( )
julia> expr = Meta.parse("1 + 1")
:(1 + 1)
julia> print(expr)
1 + 1
julia> result = eval(expr)
2
Usually, macros are used to manipulate things before the usual evaluation of expressions; they are syntax transformations, mostly. Macros are performed before other source code is compiled/evaluated/executed.
Rather than seeking a macro that evaluates a string as if it were typed directly into the REPL (without quotes), use this function instead.
evalstr(x::AbstractString) = eval(Meta.parse(x))
While I do not recommend this next macro, it is good to know the technique.
A macro named <name>_str is used like this <name>"<string contents>" :
julia> macro eval_str(x)
:(eval(Meta.parse($x)))
end
julia> eval"1 + 1"
2
(p.s. do not reuse Base function names as variable names, use str not string)
Please let me know if there is something I have not addressed.

Why can I not access a variable declared in a macro unless I pass in the name of the variable?

I have this macro:
macro_rules! set_vars {
( $($x:ident),* ) => {
let outer = 42;
$( let $x = outer; )*
}
}
Which expands this invocation:
set_vars!(x, y, z);
into what I expect (from --pretty=expanded):
let outer = 42;
let x = outer;
let y = outer;
let z = outer;
In the subsequent code I can print x, y, and z just fine, but outer seems to be undefined:
error[E0425]: cannot find value `outer` in this scope
--> src/main.rs:11:5
|
11 | outer;
| ^^^^^ not found in this scope
I can access the outer variable if I pass it as an explicit macro parameter.
Is this intentional, something to do with "macro hygiene"? If so, then it would probably make sense to mark such "internal" variables in --pretty=expanded in some special way?
Yes, this is macro hygiene. Identifiers declared within the macro are not available outside of the macro (and vice versa). Rust macros are not C macros (that is, Rust macros are more than glorified text replacement).
See also:
The Little Book of Rust Macros
A Practical Intro to Macros
So, what are hygienic macros anyway?

Why are macros based on abstract syntax trees better than macros based on string preprocessing?

I am beginning my journey of learning Rust. I came across this line in Rust by Example:
However, unlike macros in C and other languages, Rust macros are expanded into abstract syntax trees, rather than string preprocessing, so you don't get unexpected precedence bugs.
Why is an abstract syntax tree better than string preprocessing?
If you have this in C:
#define X(A,B) A+B
int r = X(1,2) * 3;
The value of r will be 7, because the preprocessor expands it to 1+2 * 3, which is 1+(2*3).
In Rust, you would have:
macro_rules! X { ($a:expr,$b:expr) => { $a+$b } }
let r = X!(1,2) * 3;
This will evaluate to 9, because the compiler will interpret the expansion as (1+2)*3. This is because the compiler knows that the result of the macro is supposed to be a complete, self-contained expression.
That said, the C macro could also be defined like so:
#define X(A,B) ((A)+(B))
This would avoid any non-obvious evaluation problems, including the arguments themselves being reinterpreted due to context. However, when you're using a macro, you can never be sure whether or not the macro has correctly accounted for every possible way it could be used, so it's hard to tell what any given macro expansion will do.
By using AST nodes instead of text, Rust ensures this ambiguity can't happen.
A classic example using the C preprocessor is
#define MUL(a, b) a * b
// ...
int res = MUL(x + y, 5);
The use of the macro will expand to
int res = x + y * 5;
which is very far from the expected
int res = (x + y) * 5;
This happens because the C preprocessor really just does simple text-based substitutions, it's not really an integral part of the language itself. Preprocessing and parsing are two separate steps.
If the preprocessor instead parsed the macro like the rest of the compiler, which happens for languages where macros are part of the actual language syntax, this is no longer a problem as things like precedence (as mentioned) and associativity are taken into account.

Trying to write a macro, but not sure what's wrong

I've been playing around with macros. I saw an interesting post where I can structure my macro in a function like structure here. I've tried to implement one and here is what I currently have.
#define Max(X,Y) \
do { \
auto var1 = x; \
auto var2 = y; \
var1 > var2 ? var1 : var2; \
} while (0)
and in my main function
void main()
{
int result = Max(10, 5)
}
but I'm getting all these errors,
error C2059: syntax error : 'do'
error C2143: syntax error : missing ';' before '{'
Not sure what I did wrong. I just copied the code from the hyperlink above and just modified the code. Any help would be greatly appreciated!
Consider what the macro expands into:
int result = do {
auto var1 = x;
auto var2 = y;
var1 > var2 ? var1 : var2;
} while (0);
That's not valid C++ because loops don't have return values in C++.
Oh, and I actually did notice a small problem with the macro. The parameter names are capitalized (X, Y) but used as lower-case (x, y). That will not work as expected. You have to use the same name in the macro body as you used for the macro parameters.

Calling a macro

I have the following macro:
#define testMethod(a, b) \
if (a.length > b.length) \
return a; \
return b;
When I try to call it with:
NSString *s = testMethod(#"fir", #"sec");
I get an error:
"Excepted ";" at end of declaration"
Why?
if is a statement, not an expression. It can't return a value like that.
You probably mean:
#define testMethod(a, b) ((a).length > (b).length ? (a) : (b))
The extra parenthesis around the arguments on the right side are common, and are there to protect you against unexpected precendence-related incidents.
Also note that because the above is pre-processed by doing textual replacement, it will probably construct more objects than the equivalent function would.
If you want to use the macro within expressions, it should be defined as an expression itself, not as a group of statements. You end up with a syntax error because the macro is literally substituted, and statements are not allowed within another statement.
GCC has an extension called "statement expressions" that can help you achieve this, but it is non-standard:
#define testMethod(a, b) ({ \
typeof(a) result = (a).length > (b).length ? (a) : (b); \
result; \
})
Actually, in your case none of this is needed because the statements can be easily converted to an expression:
#define testMethod(a, b) ((a).length > (b).length ? (a) : (b))
You need not to use the return statement... try to use the following code
#define testMethod(a,b) ((a) < (b) ? (a) : (b))
may this will help you..