Can macros expand to a combination of patterns?

As in Rust 1.0, there is no way to group multiple templates 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 work of linking all the different features. 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 will 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 extended into templates, and the first bind_alternatives bracket really works. Is it possible to generalize to more than 1 possibility? If not, what's stopping you?

+5
source share
1 answer

A macro can expand to such things as patterns, expressions, and elements, but not all; in particular, macros expand to full AST nodes, but what you have here is not a full AST node.

Each branch of a match expression can have one or more templates separated by pipes, and optional template protection ( if condition ). This is a special match syntax and therefore not a full AST node, and therefore not something a macro can extend to.

The parser searches for a pattern at this point in its parsing, so it expands the macro as a pattern that ends before | that does not fit into the grammar of the template. Thus, the macro produces more than can be consumed, and the rest is discarded with an error.

+4
source

All Articles