## Macros

• Idea as old as computing; map from text to text using textual "functions"

• Famous macro systems: LISP, M4, TeX, CPP, Scheme

• Often a "preprocessor" like CPP: source-to-source

• Modern macro systems are a bit lower-level

## Rust Macros

• Mappings from parsed source tokens to source tokens

• Two kinds:

• "Declarative", which use rules and matching: e.g. println!()

• "Procedural", which call Rust functions with token trees: e.g. #derive

• Book / I will only talk about declarative

• Procedural is much easier than it used to be; see the documentation and examples online.

## Introducing A Macro

• macro_rules! itself looks / acts like a macro

• Argument is a sequence of rules

• Each rule has a LHS that is a token pattern to match, and a RHS that is tokens to rewrite using the match

• Both sides are lexed by the compiler: you can't use arbitrary text

• playground

## Rules Run In Order

• The macro rules match from top to bottom. The first matching rule is chosen

• A rule may suffer from type: the patterns match syntactically, but the pattern type is wrong. If this happens, compilation will fail right there

## Macro Bugs

• Double-expansion is dangerous, as with CPP

• Macros are just tokenized, so weird errors (such as including the fragment type in the expansion) won't be caught at macro expansion time -- they will be caught at code compile time

## Rules Can Be Recursive

• Note that our debug! example expands eprintln!. It can also expand itself, either directly or indirectly

• There is an expansion recursion depth limit of 64 to prevent runaway macros from grinding up all the machine resources. The depth limit can be increased with #![recursion_limit = "256"] or something similar

• #![feature(trace_macros)] can be useful here for debugging expansions

## Other Macro Debugging

• log_syntax!() will print its arguments to the terminal at compile time

• rustc -Z unstable-options --pretty expanded can be used to show the preprocessed program as text

## Repetition and Condition

• Powerful, but easy to get wrong

• playground

• Varargs is 70% of the reason for Rust macros

## More Facilities

• Lots of compiler builtins, e.g. line!(). See the book for details

• Lots of "fragment types", e.g. ident, ty, tt

• A tt fragment is special: it matches any "token tree" the Rust compiler can build. This is either a list of stuff inside some kind of outer brackets, or it's a single token of arbitrary kind.

## Scope Stuff

• Local variables and arguments created inside a macro "cannot escape": they are in a different namespace and thus "hygienic"

playground

• Rust 2015 Edition:

• Making macros visible to another crate requires #[macro_export] per-macro

• Making macros from another crate visible requires #[macro_use] per crate

• Rust 2018 Edition:

• Macro visibility is controlled by normal import rules