Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to define a macro which handles grammatical cases?

Tags:

macros

rust

I'd like to define a macro callme which can be applied like this.

fn main() {
    let a=4;
    let b=5;
    callme!(
        a (b) => { a+b } ;
        a (b) => { a*b } ;
        a (b) ~ C
    );
}

I do not know how to get a working macro definition for callme. Currently I'm trying something like this:

macro_rules! callme {
    (
        $($A: ident ($B: ident) => {$E: expr}) ; *
    ) => (
        $(
            println!("{:?} {:?} {:?}", $A, $B, $E);
        ) *
    );
    (
        $($A: ident ($B: ident) ~ $Q: ident) ; *
    ) => (
        $(
            println!("We got {:?} . {:?} . {:?}", $A, $B, $Q);
        ) *
    );
}

This does not work, because I cannot use both syntax cases at once.

like image 680
Leonard7E Avatar asked Jan 29 '23 14:01

Leonard7E


1 Answers

When you're working with a token stream, it's easier to leave it to recursion to process your pieces in cases like this. You could for instance do:

macro_rules! callme {
    ($A:ident ($B:ident) => { $E:expr }; $($rest:tt)*) => {
        println!("{:?} {:?} {:?}", $A, $B, $E);

        callme!($($rest)*);
    };
    ($A:ident ($B:ident) ~ $Q:ident; $($rest:tt)*) => {
        println!("We got {:?} . {:?} . {:?}", $A, $B, $Q);

        callme!($($rest)*);
    };
    () => {};
}

fn main() {
    let a=4;
    let b=5;
    let c = "C";
    callme!(
        a (b) => { a+b } ;
        a (b) => { a*b } ;
        a (b) ~ c;
    );
}

(On Playground)

Note that after each set of tokens, you gather all the remaining tokens and leave them to be handled by a later call to callme!, with a final () => {} to indicate a completion condition.

like image 62
loganfsmyth Avatar answered Feb 03 '23 14:02

loganfsmyth