If you were to replace the =>
with a :
in the maplit!
macro you'd get this error:
error: `$key:expr` is followed by `:`, which is not allowed for `expr` fragments
--> src/lib.rs:6:17
|
6 | ($($key:expr: $value:expr),*) => {
| ^ not allowed after `expr` fragments
|
= note: allowed there are: `=>`, `,` or `;`
The specific problem is that the macro accepts any arbitrary expression as the key type. You could still have the { key: value }
syntax, but only if the key
is an ident
(for example) instead of an expr
.
You can read the Follow-set Ambiguity Restrictions section of Macros by Example in the Rust Reference:
The parser used by the macro system is reasonably powerful, but it is limited in order to prevent ambiguity in current or future versions of the language.
[...]
expr
and stmt
may only be followed by one of: =>
, ,
, or ;
.
That's not to say its necessarily ambiguous, though it may get confusing to parse in examples with a lot of :
s like MyEnum::Variant: ::std::collections::Vec::new()
. Its designed like that because only the documented tokens are guaranteed to indicate the end of an expression and other tokens may become ambiguous in the future.
You'll see though, that this only limits how macro_rules!
patterns are handled and would not affect a procedural macro since you have free reign to decide how the tokens are parsed.
I tried to create a simple procedural macro using syn
to aid in parsing expressions, but it chokes on the Expr : Expr
syntax because it attempts to eagerly parse the first expression as a type ascription expression which is a yet-to-be-completed feature. This is the kind of future expansion that the macro_rules!
guards against.
Going with a token tree and using parenthesis for ambiguity in Aiden4's answer is the way to go if you really want :
instead of =>
. This still could be done with a procedural macro, but it would not be as readily available and would be ambiguous if type ascription expressions gets added to the language.