er1t
er1t

Reputation: 73

How to use & and | signs in macro_rules pattern

I'm trying to write a simple macro like this, to facilitate the writing of my code

enum Term {
    Or(Box<Term>, Box<Term>),
    And(Box<Term>, Box<Term>),
    Value(u8),
}

macro_rules! term {
    ($value_1:expr & $value_2:expr) => {
        Term::And(Box::new($value_1), Box::new($value_2))
    };
    ($value_1:expr | $value_2: expr) => {
        Term::Or(Box::new($value_1), Box::new($value_2))
    };
    ($value: expr) => {
        Term::Value($value)
    };
}

However, I cannot put a & or | after an expr in my pattern. I tried using tt, but it didn't work because I'm not always just putting one token in my $value. pat_param doesn't seem to work with & either.
The only option that seems to work would be to use (($value_1:expr) & ($value_2:expr)), but if I could do without the extra parentheses, it'd be better.
Is there a way to do this?

Upvotes: 0

Views: 286

Answers (2)

Chayim Friedman
Chayim Friedman

Reputation: 71025

If you only want to allow a single variable, optionally with a method call after, you can use the following macro (note it does not handle generic method call syntax):

macro_rules! term {
    (
        $name:ident $( .$method:ident( $($argument:expr),* $(,)? ) )?
        $($rest:tt)+
    ) => {
        term!(@parsed_lhs
            ( $name $( .$method( $($argument),* ) )? )
            $($rest)*
        )
    };
    (@parsed_lhs $value_1:tt & $value_2:expr) => {
        Term::And(Box::new($value_1), Box::new($value_2))
    };
    (@parsed_lhs $value_1:tt | $value_2:expr) => {
        Term::Or(Box::new($value_1), Box::new($value_2))
    };
    ($value:expr) => {
        Term::Value($value)
    };
}

This macro is not perfect, it has some edge cases, but it should be good enough.

Upvotes: 1

cafce25
cafce25

Reputation: 27437

& isn't allowed to avoid ambiguity, there is no way to have & as a token directly after an expr parameter in a declarative macro.

expr and stmt may only be followed by one of: =>, ,, or ;.

Upvotes: 2

Related Questions