0

I am learning rust macros.
In the part on repetition, the following macro is used to demonstrate how repetitions work:

macro_rules! repeat_two { ($($i:ident)*, $($i2:ident)*) => { $( let $i: (); let $i2: (); )* } } repeat_two!( a b c d e f, u v w x y z ); 

Rust playground expands it to:

#![feature(prelude_import)] #[prelude_import] use std::prelude::rust_2024::*; #[macro_use] extern crate std; macro_rules! repeat_two { ($($i:ident)*, $($i2:ident)*) => { $(let $i: (); let $i2: ();)* } } fn main() { let a: (); let u: (); let b: (); let v: (); let c: (); let w: (); let d: (); let x: (); let e: (); let y: (); let f: (); let z: (); } 

I need help understanding how the $s are capturing the variables and/or expressions and how the separators are supplied.
How does it know that is the separator? Moreover, does the after the *, specify that there must be a after the , in the macro call?

1 Answer 1

3

How does it know that is the separator?

Narrowly looking at the $($i:ident)* portion - there is no separator dictated. It is just repeatedly matching identifiers.

It is actually not possible for a macro to dictate whitespace whatsoever since whitespace is not significant to the lexing (except to disambiguate adjacent tokens that would otherwise be merged). It just so happens that you need whitespace between identifiers to distinguish them. If the caller had written repeat_two!( abcdef, ... ) then that would be seen as one idenfifier.

The macro just sees tokens and whitespaces are not tokens.

Moreover, does the after the *, specify that there must be a after the , in the macro call?

No, that whitespace is insignificant. You can try for yourself that repeat_two!(a,u) works even with the space there in the macro_rules!, and repeat_two!(a, u) will work even without a space in the macro_rules!.

Also, what dictates the order of the generated declarations?

Since i and i2 are repeated variables, they need to be expanded in $( ... )*. The expansion will essentially repeat the body with each of the values. This expansion in particular has two variables - i and i2 - which will both be iterated at the same time. Essentially zipping the identifiers.

That is why you get a (the first value of i) and then u (the first value of i2) before going on to b and v and so on.

Sign up to request clarification or add additional context in comments.

3 Comments

I understand. Also, what dictates the order of the generated declarations?
I don't quite understand that question @kesarling, it's 1:1 the input order.
@kesarling I edited to include explanation of the expansion.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.