qrlew/expr/
dsl.rs

1//! A simple DSL to write expressions
2
3// https://veykril.github.io/tlborm/introduction.html
4// https://stackoverflow.com/questions/36721733/is-there-a-way-to-pattern-match-infix-operations-with-precedence-in-rust-macros
5// Macro DSL for exprs
6#![allow(unused)]
7macro_rules! expr {
8    // Process functions
9    (@expf [$($f:tt)*][$([$($x:tt)*])*]) => {$($f)*($(expr!(@exp+ $($x)*)),*)};
10    (@expf [$($f:tt)*][$([$($x:tt)*])*][$($y:tt)*]) => {expr!(@expf [$($f)*][$([$($x)*])*[$($y)*]])}; // Consume until the op
11    (@expf [$($f:tt)*][$([$($x:tt)*])*][$($y:tt)*] , $($t:tt)*) => {expr!(@expf [$($f)*][$([$($x)*])*[$($y)*]][] $($t)*)}; // Consume until the op
12    (@expf [$($f:tt)*][$([$($x:tt)*])*][$($y:tt)*] $h:tt $($t:tt)*) => {expr!(@expf [$($f)*][$([$($x)*])*][$($y)*$h] $($t)*)}; // Consume the tokens until we find the right op
13    (@expf [$($f:tt)*] $($t:tt)*) => {expr!(@expf [$($f)*][][] $($t)*)}; // Start consuming tokens
14    // Look for terminal nodes
15    (@expt $fun:ident($($t:tt)*)) => {expr!(@expf [Expr::$fun] $($t)*)};
16    // (@expt $fun:ident($($t:tt)*)) => {Expr::$fun(expr!($($t)*))};
17    (@expt $col:ident) => {Expr::col(stringify!($col))};
18    (@expt $val:literal) => {Expr::val($val)};
19    (@expt ($($t:tt)*)) => {(expr!($($t)*))};
20    // Look for /
21    (@exp/ [$($x:tt)*]) => {expr!(@expt $($x)*)}; // We are done, look for lower priority ops
22    (@exp/ [$($x:tt)*] / $($t:tt)*) => {Expr::divide(expr!(@expt $($x)*), expr!(@exp/ $($t)*))}; // Consume until the op
23    (@exp/ [$($x:tt)*] $h:tt $($t:tt)*) => {expr!(@exp/ [$($x)* $h] $($t)*)}; // Consume the tokens until we find the right op
24    (@exp/ $($t:tt)*) => {expr!(@exp/ [] $($t)*)}; // Start consuming tokens
25    // Look for *
26    (@exp* [$($x:tt)*]) => {expr!(@exp/ $($x)*)}; // We are done, look for lower priority ops
27    (@exp* [$($x:tt)*] * $($t:tt)*) => {Expr::multiply(expr!(@exp/ $($x)*), expr!(@exp* $($t)*))}; // Consume until the op
28    (@exp* [$($x:tt)*] $h:tt $($t:tt)*) => {expr!(@exp* [$($x)* $h] $($t)*)}; // Consume the tokens until we find the right op
29    (@exp* $($t:tt)*) => {expr!(@exp* [] $($t)*)}; // Start consuming tokens
30    // Look for -
31    (@exp- [$($x:tt)*]) => {expr!(@exp* $($x)*)}; // We are done, look for lower priority ops
32    (@exp- [$($x:tt)*] - $($t:tt)*) => {Expr::minus(expr!(@exp* $($x)*), expr!(@exp- $($t)*))}; // Consume until the op
33    (@exp- [$($x:tt)*] $h:tt $($t:tt)*) => {expr!(@exp- [$($x)* $h] $($t)*)}; // Consume the tokens until we find the right op
34    (@exp- $($t:tt)*) => {expr!(@exp- [] $($t)*)}; // Start consuming tokens
35    // Look for +
36    (@exp+ [$($x:tt)*]) => {expr!(@exp- $($x)*)}; // We are done, look for lower priority ops
37    (@exp+ [$($x:tt)*] + $($t:tt)*) => {Expr::plus(expr!(@exp- $($x)*), expr!(@exp+ $($t)*))}; // Consume until the op
38    (@exp+ [$($x:tt)*] $h:tt $($t:tt)*) => {expr!(@exp+ [$($x)* $h] $($t)*)}; // Consume the tokens until we find the right op
39    (@exp+ $($t:tt)*) => {expr!(@exp+ [] $($t)*)}; // Start consuming tokens
40    // Look for high priority ops first
41    ($($t:tt)*) => {expr!(@exp+ $($t)*)};
42}