Aegonek
Aegonek

Reputation: 57

Declarative macros - bracketed expressions can be followed by arbitrary matchers. Why?

I was experimenting with declarative macros and I thought about recreating F# sequence expressions using them. First attempt triggered the compilation error:

macro_rules! genexp {
  (for $item:ident in $range:expr -> $expr:expr) => {
    $range.map(|$item| $expr)
  }
}

`$range:expr` is followed by `->`, which is not allowed for `expr` fragments
allowed there are: `=>`, `,` or `;`rustc

However, following code compiles and works just fine:

macro_rules! genexp {
  (for $item:ident in [$range:expr] -> $expr:expr) => {
    $range.map(|$item| $expr)
  }
}

fn main() {
    let foo = genexp!(for x in [0..20] -> x * x);
    println!("{:?}", foo.collect::<Vec<_>>())
}

//OUTPUT: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361]

My question is, why? Macros By Example section in Rust Reference states that:

  • expr and stmt may only be followed by one of: =>, ,, or ;.

I see no info about special treatment of various brackets or other delimiters.

Upvotes: 2

Views: 240

Answers (1)

orlp
orlp

Reputation: 117681

$range:expr ->

The Rust language could be expanded in the future where -> becomes a valid part of an expression. The idea is that macros are unambiguously future-compatible with updates to Rust, so this is disallowed to be conservative.

[$range:expr] ->

The Rust language will never be expanded with features that involve unbalanced brackets/parents/braces [](){}. Therefore, when the Rust parser sees [ it can scan for the matching ] immediately. It is thus unambiguous which portion of this macro is the expression, and where the expression stops and the ] -> occurs, even in the face of future language expansions.

Upvotes: 2

Related Questions