stateful_macro_rules!() { /* proc-macro */ }
Expand description
Generate macro_rules!
macros that have states.
§Basic: Macro name and body
To specify the generated macro name and its final expanded content, use
name() { body }
.
For example, the code below generates a macro called foo!()
and it
expands to "foo"
.
stateful_macro_rules! {
foo() { "foo" };
}
§States
To define states, add them to the ()
after the macro name. A state can
be defined as state_name: (pattern) = (default_value))
. Multiple
states are separated by ,
. States can be referred by their pattern
name.
For example, the code below defines a plus!()
macro with x
and y
states (but there is no real way to use this macro):
stateful_macro_rules! {
pos(x: ($x:expr) = (0), y: ($y:expr) = (0)) { ($x, $y) };
}
§Rules
To make the macro useful, macro rules like (pattern) => { body }
are
needed. Unlike rules in classic macro_rules!
, the pattern
matches
incomplete tokens (use ...
to mark the incomplete portion), and body
can only contain changes to states like state_name.set(tokens)
, or
state_name.append(tokens)
.
stateful_macro_rules! {
pos(x: ($x:expr) = (0), y: ($y:expr) = (0)) { ($x, $y) };
(incx($i:expr) ...) => { x.set($x + $i); };
(incx ...) => { x.set($x + 1); };
(incy($i:expr) ...) => { y.set($y + $i); };
(incy ...) => { y.set($y + 1); };
// `...` is implicitly at the end
(reset) => { x.set(0); y.set(0); };
// `...` can be in the middle
(eval( ... )) => { };
}
assert_eq!(pos!(incx(3) reset incy incy(10) incx), (1, 11));
assert_eq!(pos!(eval(incx(10) incy(20))), (10, 20));
§Conditional Rules
Rules can be disabled by states. This is done by the when
block.
stateful_macro_rules! {
toggle(result: ($v:tt) = (0)) { $v };
(T) when { result: (0) } => { result.set(1); };
(T) when { result: (1) } => { result.set(0); };
}
assert_eq!(toggle![T T T], 1);
§Debugging
If the debug
feature is on, debug;
can be used to print the
generated code to stderr. The code can be used as a drop-in macro
replacement to help debugging.