#![cfg_attr(not(test), no_std)]
#[macro_export(local_inner_macros)]
macro_rules! defmac {
(@nest $name:ident ($dol:tt) => (
[$($arg:ident)*] $($result_body:tt)+)
) => {
macro_rules! $name {
($($dol $arg : expr), *) => {
$($result_body)+
}
}
};
(@nest $name:ident ($dol:tt) => (
[$($arg:ident)*] $($result_body:tt)+
)
$p1:pat $(, $p2:pat)*
) => {
defmac!{@nest $name ($dol) => (
[marg $($arg)*]
match {$dol marg} { $p1 => $($result_body)+ }
)
$($p2),* }
};
(@revpats [$($args:tt)*] [$($pr:pat),*]) => {
defmac!{@nest $($args)* $($pr),*}
};
(@revpats [$($args:tt)*] [$($pr:pat),*] $p1:pat $(, $p2:pat)*) => {
defmac!{@revpats [$($args)*] [$p1 $(, $pr)*] $($p2),*}
};
($name:ident $($p1:pat),* => $result:expr) => {
defmac!{@revpats [$name ($) => ([] $result)] [] $($p1),*}
};
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
let value = "xyz";
defmac!(none => value);
assert_eq!(none!(), "xyz");
defmac!(one x => x);
assert_eq!(one!(2), 2);
defmac!(two x, y => x + y);
assert_eq!(two!(1., 2.), 3.);
defmac!(three x, y, z => (x, y, z));
assert_eq!(three!(1, (2, 3), (4, 5, 6)), (1, (2, 3), (4, 5, 6)));
defmac!(four w, x, y, z => (w + x, z, y));
assert_eq!(four!(3, 4, "a", "b"), (7, "b", "a"));
defmac!(many a, b, c, d, e, f, g, h, i, j, k => (a, b + c, d + e + f,
g + h + i + j + k));
assert_eq!(many!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
(1, 5, 15, 45));
}
#[test]
fn eval_order() {
use std::cell::Cell;
let v = Cell::new(0);
let f = || {
let n = v.get();
v.set(n + 1);
n
};
defmac!(two x, y => (x, y));
let result = two!(f(), f());
assert_eq!(result, (0, 1));
assert_eq!(f(), 2);
}
defmac! { triple value => [value; 3] }
#[test]
fn module_macro() {
assert_eq!(triple!(3), [3, 3, 3]);
}
}