Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can macros expand to a combination of patterns?

As of Rust 1.0, there is no way to group multiple patterns into one binding:

// It does not compile
match x as char {
    b @ ('A' | 'Z') => println!("A or Z: {}", b),
    _ => println!("Try again")
}

// Correct version
match x as char {
    b @ 'A' | b @ 'Z' => println!("A or Z: {}", b),
    _ => println!("Try again")
}

I was wondering if a macro could do the dirty job of binding all the different possibilities. Here is a partial attempt:

macro_rules! bind_alternatives {
    ($x:ident, $e:expr) => ($x @ $e);
    ($x:ident, $e1:expr, $e2:expr) => (
        $x @ $e1 | $x @ $e2
    );
}

fn main() {
    let x = 'a';

    match x {
        bind_alternatives!(z, 'a', 'c') => println!("Matched"),
        _ => println!("No luck")
    };
}

This does not compile:

example.rs:4:18: 4:19 error: macro expansion ignores token `|` and any following
example.rs:4         $x @ $e1 | $x @ $e2
                                      ^
example.rs:12:9: 12:40 note: caused by the macro expansion here; the usage of `bind_alternatives` is likely invalid in this context
example.rs:12         bind_alternatives!(z, 'a', 'c') => println!("Matched"),

I understand that macros can be expanded into patterns, and the first brace of bind_alternatives does work. Is it possible to generalize to more than 1 possibility? If not, what prevents it?

like image 1000
rvidal Avatar asked Jun 03 '15 16:06

rvidal


1 Answers

A macro is able to expand to things like patterns, expressions and items, but not everything; specifically, macros expand to complete AST nodes, but what you’re dealing with here is not a complete AST node.

Each branch of a match expression can have one or more patterns, separated by pipes, and an optional pattern guard (if condition). This is all special match-specific syntax, and thus not a complete AST node, and thus not something that a macro can expand to.

The parser is looking for a pattern at that point of its parsing, so it expands the macro as a pattern, which concludes before the |, which doesn’t fit in a pattern grammar. The macro has thus produced more than can be consumed, and the rest is discarded with an error.

like image 82
Chris Morgan Avatar answered Sep 21 '22 06:09

Chris Morgan