DEV Community

dougfort
dougfort

Posted on

Simple Rust Macros:

I don't often think of macros as a resource in Rust. But I've been playing with a Rust substrate for Paul Graham's Bel dialect of Lisp.

/// Bel has four fundamental data types:
/// symbols, pairs, characters, and streams.
/// Instances of the four fundamental types are called objects
/// https://sep.yimg.com/ty/cdn/paulgraham/bellanguage.txt
#[derive(Debug, PartialEq, Clone)]
pub enum Object {
    Symbol(String),
    Pair(Box<(Object, Object)>),
    Char(String),
    Stream,
}
Enter fullscreen mode Exit fullscreen mode

There's a lot of code like this:

Object::Pair(Object::Symbol("a".to_string()), Object::Symbol("nil".to_string()))
Enter fullscreen mode Exit fullscreen mode

In Rust for Rustaceans, Jon Gjengset says:

Declarative macros are primarily useful when you find yourself writing the same code over and over, and you'd like to, well, not do that.

So I added some simple macros. I got a lot of help from Rust by Example

/// nil object (aka 'false')
macro_rules! nil {
    () => {
        Object::Symbol("nil".to_string())
    };
}

/// 'true' object (true is not a good name for a macro)
macro_rules! t {
    () => {
        Object::Symbol("t".to_string())
    };
}

/// general symbol
macro_rules! symbol {
    ($n:expr) => {
        Object::Symbol($n.to_string())
    };
}

/// pair, probably part of a list
macro_rules! pair {
    ($a:expr, $b:expr) => {
        Object::Pair(Box::new(($a, $b)))
    };
}
Enter fullscreen mode Exit fullscreen mode

Now I write:

pair!(symbol!("a"), nil!())
Enter fullscreen mode Exit fullscreen mode

Much better, and not nearly as hard as I expected.

You can see the WIP code here

Top comments (1)

Collapse
 
chayimfriedman2 profile image
Chayim Friedman

You should avoid macros as much as you can. All of your examples can be rewritten to use functions, and it is a much better approach (plus, it saves the ! keystroke!). Macros are needed when we want to perform some syntactical transformation otherwise impossible.