Continuing the discussion from More macro sugar?:
Something I’d like to see is macro objects. These would allow encapsulation of patterns and the resulting data. Here’s a strawman mockup:
macro_object! cons($head:expr, $tail:macro) {
() => ($head$tail!!print_as_tail());
head() => ($head);
tail() => ($tail);
print_as_tail() => (, $head$tail!!print_as_tail());
}
macro_object! null() {
() => ();
print_as_tail() => ();
}
macro_rules! list {
() => (null!());
($head:expr $(, $tail:expr)*) =>
(cons!($head, list!($($tail),*)));
}
I’m using macro
as a designator to match invocations of a macros (potentially including “member” accesses), and !!
to access object “members”. “Member” access would occur after expansion to a macro object invocation. This also would allow for macro chaining:
macro_rules! my_if {
($cond:expr) $block:block => (if_chain!(if_branch!($cond, $block)));
}
macro_rules! if_branch {
($cond:expr, $block:block) => (if ($cond) $block);
}
macro_object! if_chain($($if_branch:macro),+) {
() => ($($if_branch)else+);
my_else_if($cond:expr) $block:block =>
(if_chain!($($if_branch,)+ if_branch!($cond, $block));
my_else $block:block =>
(if_else_chain!($($if_branch),+; $block));
}
macro_object! if_else_chain($($if_branch:macro),+; $else_block:block) {
() => ($($if_branch else)+ $else_block);
}
Example use:
my_if!(x==0) {
...
} !! my_else_if(x==1) {
...
} !! my_else {
...
}
Here, since the end result is a macro_object
, the compiler appends a !!()
to it, which is one of many liberties I’ve taken in these examples, such as using a bare block
non-terminal in place of a matcher, and using [ident] (parens | [parens] curlies)
macro invocation forms.