Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
gensym macro
/// This auxiliary macro generates an ident for each argument passed to it,
/// and then calls another macro back with the generated idents.
macro_rules! gensym {
// base case: we send all the collected idents back to the other macro
(@go $callback:ident ($($args:tt)*) ($($i:ident)*)) => {
$callback!($($args)* $($i)*)
};
// recursion: here, we add in a new ident named "x" (but distinct from every other "x")
(@go $callback:ident $args:tt ($($i:ident)*) $head:tt $($tail:tt)*) => {
gensym!(@go $callback $args ($($i)* x) $($tail)*)
// ^ notice I pass through one fewer arg ($head is gone)
// ^ new ident!!!
};
// entry point: here, you pass in N tokens for $scratch, and the macro recurses that many times
($callback:ident!$args:tt $($scratch:tt)*) => {
gensym!(@go $callback $args () $($scratch)*)
// | | | | | | || ^----------^ at the end are the arguments telling us how many times to recurse
// | | | | | | ^^ in this list we'll collect generated idents
// | | | | ^---^ arguments to pass along to the other macro
// | | ^------^ the macro to call back
// ^-^ jump to inner macro rule
}
}
/// Silly macro that uses N idents to declare some variables, init them to zero, and print them
macro_rules! thing {
// this is the callback rule (gensym! calls this after generating idents)
(@go [$($t:ty)*] $($i:ident)*) => {{
$(let $i: $t = 0;)*
format!("{:?}", ($($i + <$t as Default>::default()),*))
}};
// entry point rule
($($t:ty)*) => {
gensym!(thing!(@go [$($t)*]) $(($t))*)
// | | ^------^ pass along all the types, wrapped in parens just to make sure they are one tt each
// ^------------------^ first part tells gensym! how to call us back
}
}
fn main() {
println!("{}", thing!(u8 u32 u16));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment