Pattern Matching for Declarative Macros in Rust

Last Updated on

Macros are like functions but only better. They are triggered based on their patterns using pattern matching for declarative Macros. Macros also group our codes into a unit (or units), and there are two types of macros in Rust – declarative and procedural. This brief post is about declarative macros.

The Simplest Pattern and Macro

The most straightforward macro does nothing!

Running the macro produces the following result.

Running the simplest declarative macro

The macro works because we used its name and the pattern that refers to a block of codes to execute. The pattern matching for the declarative macros worked!

Overloaded Pattern and Macro

A macro can be overloaded. It can have many blocks of codes based on pattern signatures we define. For instance, we have the following codes.

Now there are three blocks of codes. Each runs for a specific pattern, as shown in the following codes.

Pattern matching with declarative macros

What if we run these codes?

We will get these errors.

my_macro does not have that pattern defined for a block of codes.

Pattern Matching for Macro Parameters

The macro we have so far does not use any data outside itself. We need to pass data to it. So how to do that? Modify the pattern by prefixing a token with a $ sign followed by “:” and specific type. A type can be either the following.

  1. ident: an identifier. Examples: x; foo.
  2. path: a qualified name. Example: T::SpecialA.
  3. expr: an expression. Examples: 2 + 2; if true { 1 } else { 2 }; f(42).
  4. ty: a type. Examples: i32; Vec<(char, String)>; &T.
  5. pat: a pattern. Examples: Some(t); (17, ‘a’); _.
  6. stmt: a single statement. Example: let x = 3.
  7. block: a brace-delimited sequence of statements. Example: { log(error, “hi”); return 12; }.
  8. item: an item. Examples: fn foo() { }; struct Bar;.
  9. meta: a “meta item”, as found in attributes. Example: cfg(target_os = “windows”).
  10. tt: a single token tree.

We can come up with the following codes based on the previous ones.

And this is the output:

Again, the pattern matching for declarative macros worked!

Tested with Rust 1.40.0.

For more information, please see https://doc.rust-lang.org/book/ch19-06-macros.html.

Karl San Gabriel

Karl San Gabriel

Professional Software Developer