Macro Objects


#1

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.