Reputation: 650
The following rust code does not compile because of the macro error
error: local ambiguity: multiple parsing options: built-in NTs stmt ('s') or 1 other option.
macro A is fine. Macro B shows the error.
macro_rules! A {
($x: ident, $($s: stmt)*) => {
println!("hello");
};
}
macro_rules! B {
($x: ident, $($s: stmt)*; $e: expr) => {
println!("hello");
};
}
fn main() {
A![my_name, let x=5];
B![my_name, let x=5; 5];
}
This minimal reproducible example in B is exactly what I need. I want the macro to accept multiple let statements and terminate by some other expression.
What is the ambiguity that is being referred to?
Is there a way around it?
Of those tokens accepted after statement fragments I have tried several combinations yet none appear to make a difference. Neither does swapping the statement with a token tree.
Upvotes: 1
Views: 2201
Reputation: 29981
Expressions are statements, so $($s: stmt)*; $e: expr
is ambiguous because the compiler can't decide between using s
or e
when it encounters one.
Since you only expect bindings, you can easily expand them yourself:
macro_rules! A {
($x: ident, $($s: stmt)*) => {
println!("hello");
};
}
macro_rules! B {
($x: ident, $(let $p:pat = $v:expr)*; $e: expr) => {
$(let $p = $v);*
println!("hello: {}", $e);
};
}
fn main() {
A![my_name, let x=5];
B![my_name, let x=5; x+2];
}
Note that this doesn't support including types in the binding (let a: i32 = 42;
) because pat
can't be followed by :
.
Upvotes: 6