How do I write macro arguments which capture parenthesis? - macros

I am hoping to write a Rust macro which forwards its entire argument to a second macro — even when that argument contains exciting parenthesization.
Here is what I have tried so far:
macro_rules! parse {
(done) => (println!("done!"));
(if ($cond:tt) {$then:tt}) => (println!("if! "); parse!($cond); parse($then));
}
macro_rules! forward {
($($e:tt)*) => (parse!($($e)*; done));
}
fn main() {
forward!(if (done) {done} );
}
This doesn't work, and produces the error:
error: no rules expected the token `if`
What am I doing wrong here?
Edit: Beyond simply forwarding the arguments to forward, I was hoping to "paste" the tokens ; done on to the end of forward's arguments. Is there a way to make this work while preserving that behavior?

The problem is the ; done in forward. What's going on here is that the macro expansion code matches literal input tokens against arms one at a time. If an arm doesn't match, it gives up and tries the next one. When it runs out of arms to try, it has to fail and explain why.
But which token in the input was the problem? Answering that when there are potentially multiple arms involved is hard, so instead it just picks the first token and says "this was the problem".
Whenever you see a macro expansion complaining about the first token in the input not matching, it's quite possible it's something later in the input that tripped it up.
Fixing that (and fixing the parse invocation that's missing its !) gives:
macro_rules! parse {
(done) => (println!("done!"));
(if ($cond:tt) {$then:tt}) => (println!("if! "); parse!($cond); parse!($then));
}
macro_rules! forward {
($($e:tt)*) => (parse!($($e)*));
}
fn main() {
forward!(if (done) {done} );
}

Related

How to pass named loop labels to a macro in Rust?

Using a macro that breaks out of a loop works, but I want to pass in a label to be able to define which outer loop to break out of.
Passing the argument in as an expression gave a syntax error, the only way I managed to get this to work was to pass in a block however this isn't very elegant, e.g.:
my_macro({ break 'outer; });
Is there a way to pass:
my_macro('outer);
... that can be written in the macro as break $my_label; that expands into break 'outer; ?
Passing it as the versatile tt (token tree) works:
macro_rules! my_break {
($label:tt) => { break $label; }
}
fn main() {
'outer: loop {
println!("Start of outer");
loop {
println!("Start of inner");
my_break!('outer);
println!("Not reachable");
}
println!("End of outer");
}
println!("End of main");
}
Playground
To future readers, there's an accepted RFC adding a lifetime specifier for macro parameters.

What does the tt metavariable type mean in Rust macros?

I'm reading a book about Rust, and start playing with Rust macros. All metavariable types are explained there and have examples, except the last one – tt. According to the book, it is a “a single token tree”. I'm curious, what is it and what is it used for? Can you please provide an example?
That's a notion introduced to ensure that whatever is in a macro invocation correctly matches (), [] and {} pairs. tt will match any single token or any pair of parenthesis/brackets/braces with their content.
For example, for the following program:
fn main() {
println!("Hello world!");
}
The token trees would be:
fn
main
()
∅
{ println!("Hello world!"); }
println
!
("Hello world!")
"Hello world!"
;
Each one forms a tree where simple tokens (fn, main etc.) are leaves, and anything surrounded by (), [] or {} has a subtree. Note that ( does not appear alone in the token tree: it's not possible to match ( without matching the corresponding ).
For example:
macro_rules! {
(fn $name:ident $params:tt $body:tt) => { /* … */ }
}
would match the above function with $name → main, $params → (), $body → { println!("Hello world!"); }.
Token tree is the least demanding metavariable type: it matches anything. It's often used in macros which have a “don't really care” part, and especially in macros which have a “head” and a “tail” part. For example, the println! macros have a branch matching ($fmt:expr, $($arg:tt)*) where $fmt is the format string, and $($arg:tt)* means “all the rest” and is just forwarded to format_args!. Which means that println! does not need to know the actual format and do complicated matching with it.

Ordering macro argument execution

I'm using a library for string interning (string-cache), that uses macros to efficient create elements (atom!). However for simplification here is a similar macro that demonstrates the problem
macro_rules! string_intern {
("d") => ("Found D");
}
say I need to call this macro from another macro and give it a string version of an identifier.
macro_rules! print_ident {
($id:ident) => (
string_intern!(stringify!($id));
);
}
However calling this macro
fn main() {
print_ident!(d);
}
Fails with error:
error: no rules expected the token `stringify`
--> <anon>:7:24
|
7 | string_intern!(stringify!($id));
| ^^^^^^^^^
Playground link
I know stringify! correctly converts to identifier d to string "d", because giving it to println! works as expected. Is there a way to pass the identifier I want turned into string to string_intern?
println! lets you do this because it uses format_args! under the covers, which is a compiler-provided "intrinsic" that forcibly evaluates its first argument before using it. You cannot do this from a user-defined macro; you'd have to write a compiler plugin (which requires a nightly compiler and no guarantee of stability).
So, yeah; you can't. Sorry. The only thing you can do is redefine the macro in such a way that you don't need an actual string literal, or change how you invoke it.
Your definition of string_intern! is expecting a literal "d" and nothing else, but you are passing in these tokens: stringify, !, ... which why it fails. The definition of string_intern! that you want is probably:
macro_rules! string_intern {
($e:expr) => {
match $e {
"d" => "Found D",
_ => "Not found",
}
}
}
which can accept any expression that evaluates to a string type.

How do I write a wrapper for a macro without repeating the rules?

I am trying to make a wrapper for a macro. The trouble is that I don't want to repeat the same rules in both macro. Is there a way to do that?
Here is what I tried:
macro_rules! inner {
($test:ident) => { stringify!($test) };
($test:ident.run()) => { format!("{}.run()", stringify!($test)) };
}
macro_rules! outer {
($expression:expr) => {
println!("{}", inner!($expression));
}
}
fn main() {
println!("{}", inner!(test));
println!("{}", inner!(test.run()));
outer!(test);
outer!(test.run());
}
but I get the following error:
src/main.rs:8:31: 8:42 error: expected ident, found test
src/main.rs:8 println!("{}", inner!($expression));
^~~~~~~~~~~
If I change the outer macro for this, the code compile:
macro_rules! outer {
($expression:expr) => {
println!("{}", stringify!($expression));
}
}
What am I doing wrong?
macro_rules! is both cleverer and dumber than you might realise.
Initially, all input to a macro begins life as undifferentiated token soup. An Ident here, StrLit there, etc. However, when you match and capture a bit of the input, generally the input will be parsed in an Abstract Syntax Tree node; this is the case with expr.
The "clever" bit is that when you substitute this capture (for example, $expression), you don't just substitute the tokens that were originally matched: you substitute the entire AST node as a single token. So there's now this weird not-really-a-token in the output that's an entire syntax element.
The "dumb" bit is that this process is basically irreversible and mostly totally invisible. So let's take your example:
outer!(test);
We run this through one level of expansion, and it becomes this:
println!("{}", inner!(test));
Except, that's not what it looks like. To make things clearer, I'm going to invent some non-standard syntax:
println!("{}", inner!( $(test):expr ));
Pretend that $(test):expr is a single token: it's an expression which can be represented by the token sequence test. It is not simply the token sequence test. This is important, because when the macro interpreter goes to expand that inner! macro, it checks the first rule:
($test:ident) => { stringify!($test) };
The problem is that $(test):expr is an expression, not an identifier. Yes, it contains an identifier, but the macro interpreter doesn't look that deep. It sees an expression and just gives up.
It fails to match the second rule for the same reason.
So what do you do? ... Well, that depends. If outer! doesn't do any sort of processing on its input, you can use a tt matcher instead:
macro_rules! outer {
($($tts:tt)*) => {
println!("{}", inner!($($tts)*));
}
}
tt will match any token tree (see the Macros chapter of the Rust Book). $($tts:tt)* will match any sequence of tokens, without changing them. This of this as a way to safely forward a bunch of tokens to another macro.
If you need to do processing on the input and forward it on to the inner! macro... you're probably going to have to repeat the rules.
I had some success with the $($stuff: expr),+ syntax.
macro_rules! println {
( $($stuff: expr),+) => {
avr_device::interrupt::free(|cs| {
uwriteln!(unsafe { &SERIAL_STATIC}.borrow(cs).borrow_mut().as_mut().unwrap(),
$($stuff),+)
})
}
}

; expected but <place your favourite keyword here> found

I'm trying to write a class for a scala project and I get this error in multiple places with keywords such as class, def, while.
It happens in places like this:
var continue = true
while (continue) {
[..]
}
And I'm sure the error is not there since when I isolate that code in another class it doesn't give me any error.
Could you please give me a rule of thumb for such errors? Where should I find them? are there some common syntactic errors elsewhere when this happens?
It sounds like you're using reserved keywords as variable names. "Continue", for instance, is a Java keyword.
You probably don't have parentheses or braces matched somewhere, and the compiler can't tell until it hits a structure that looks like the one you showed.
The other possibility is that Scala sometimes has trouble distinguishing between the end of a statement with a new one on the next line, and a multi-line statement. In that case, just drop the ; at the end of the first line and see if the compiler's happy. (This doesn't seem like it fits your case, as Scala should be able to tell that nothing should come after true, and that you're done assigning a variable.)
Can you let us know what this code is inside? Scala expects "expressions" i.e. things that resolve to a particular value/type. In the case of "var continue = true", this does not evaluate to a value, so it cannot be at the end of an expression (i.e. inside an if-expression or match-expression or function block).
i.e.
def foo() = {
var continue = true
while (continue) {
[..]
}
}
This is a problem, as the function block is an expression and needs to have an (ignored?) return value, i.e.
def foo() = {
var continue = true
while (continue) {
[..]
}
()
}
() => a value representing the "Unit" type.
I get this error when I forget to put an = sign after a function definition:
def function(val: String):Boolean {
// Some stuff
}