Can I specify an operator or other syntactic literal within a macro input?

First, I know this is not a good use of macros but I’m learning what I can do.

I have a struct Rational:

pub struct Rational{
    pub n: i128,
    pub d : i128
}

I have a macro that builds these:

macro_rules! rat{
    ($n : expr,  $d : expr) => {
        Rational{n : $n,d:  $d}
    }
}

The syntax for calling that macro looks like : rat!(1, 3). I would like it to visually show a fractional format, so you would call it like rat!(1 / 3) instead, and the macro would parse that expression to yield the same result. (Note that if it first evaluates 1/3, even as a float type, it will not exactly correspond as 1/3 does not correspond exactly to any float.)

I’m hoping there’s some syntax like:

macro_rules! rat{
    ($n : expr `/` $d : expr) => {
        Rational{n : $n,d:  $d}
    }
}

where I can specify syntax to be used in the call. (That attempt does not compile, of course.)

Again, obviously this is silly and an X/Y problem and all that. For context, I’m considering building an equation wrangling system, and at some point I’d like to be able to parse things from a math-y syntax, which might actually justify the use of macros. This is just a baby step.

Does such a thing exist using declarative macros?
If not, is it possible with procedural macros?
Finally, I know that in Scala macros there would be no way to make that work for literal values, because the expression 1/3 would be resolved so early in the compilation process the AST would be gone by the time even macros are called. Is that also the case in Rust?

>Solution :

Yes, you can use the / token directly in the rule:

#[derive(Debug)]
struct Rational{
    n: i128,
    d: i128
}

macro_rules! rat {
    ($n:literal / $d:literal) => {
        Rational { n: $n, d: $d }
    };
}

fn main() {
    println!("rat!(1 / 3) = {:?}", rat!(1 / 3));
}
rat!(1 / 3) = Rational { n: 1, d: 3 }

However, notice I have changed the arguments from expr to literal. Your question seems to imply this is fine for your use-case, but I bring it up because at least the first parameter $n cannot be an expr. It would cause a parsing ambiguity because / is a valid continuation of an expression and Rust simply doesn’t allow / as a separator after a expr.

Leave a Reply