Using declarative macros in match

I have some code as below

match expression.expr_instance {
    Some(ExprInstance::EDivBody(ref mut ediv)) if ediv.p1.is_some() && ediv.p2.is_some() => {
        let (left, right) = func2( ediv.p1.take().unwrap(), ediv.p2.take().unwrap())?;
        ediv.p1 = Some(left);
        ediv.p2 = Some(right);
    },
    Some(ExprInstance::EModBody(ref mut emod)) if emod.p1.is_some() && emod.p2.is_some() => {
        let (left, right) = func2( emod.p1.take().unwrap(), emod.p2.take().unwrap())?;
        emod.p1 = Some(left);
        emod.p2 = Some(right);
    },
    Some(ExprInstance::EPercentPercentBody(ref mut epercentpercent)) if epercentpercent.p1.is_some() && epercentpercent.p2.is_some() => {
        let (left, right) = func2( epercentpercent.p1.take().unwrap(), epercentpercent.p2.take().unwrap())?;
        epercentpercent.p1 = Some(left);
        epercentpercent.p2 = Some(right);
    },
    Some(ExprInstance::EPlusBody(ref mut eplus)) if eplus.p1.is_some() && eplus.p2.is_some() => {
        let (left, right) = func2( eplus.p1.take().unwrap(), eplus.p2.take().unwrap())?;
        eplus.p1 = Some(left);
        eplus.p2 = Some(right);
    },
    Some(ExprInstance::EMinusBody(ref mut eminus)) if eminus.p1.is_some() && eminus.p2.is_some() => {
        let (left, right) = func2( eminus.p1.take().unwrap(), eminus.p2.take().unwrap())?;
        eminus.p1 = Some(left);
        eminus.p2 = Some(right);
    },
}

As you can see, the case branches in match are similar.
So I want to use declarative macro in the case branches.

macro_rules! case_binary_expr_instance{
    ($x:expr)=>{
    {
        Some($x(ref mut var)) if var.p1.is_some() && var.p2.is_some() => {
            let (left, right) = func2( var.p1.take().unwrap(), var.p2.take().unwrap())?;
            var.p1 = Some(left);
            var.p2 = Some(right);
        },
    }
}



match expression.expr_instance {
    case_binary_expr_instance!(ExprInstance::EMultBody),
}

But it does not work.

unexpected `,` in pattern

Now I have to do it in this way:

macro_rules! handle_binary_expr_instance{
    ($x:expr, $f:expr)=>{
        {
            let (left, right) = $f( $x.p1.take().unwrap(), $x.p2.take().unwrap())?;
            $x.p1 = Some(left);
            $x.p2 = Some(right);
        }
    }
}

match expression.expr_instance {
    Some(ExprInstance::EMultBody(ref mut emult)) if emult.p1.is_some() && emult.p2.is_some() => {
        handle_binary_expr_instance!(emult, func2)
    },
}

Can I somehow use declarative macros in match as a branch?

Thanks in advance

Macros can only generate specific types of things: Expressions, statements, patterns, types, and item-likes. match arms are not one of these things.

The following resource is a bit dated (e.g. attribute proc macros and macros in type position do exist now, and have existed for quite a while), but reading it may help explain why some of these limitations exist:

https://danielkeep.github.io/tlborm/book/mbe-syn-macros-in-the-ast.html

Though basically it's this: You know how rust macros don't require tricks like wrapping the output in parentheses and etc. to be correctly nested after expansion? Part of how that works is that macro calls are embedded into the AST before they are expanded. If a macro was allowed to produce anything, then there would be ambiguities in what kind of AST node to create for a macro call.

(and other chapters in the book provide examples of how you can work within these limitations.)

2 Likes