rust_lisp/
macros.rs

1/// A macro for more easily creating s-expressions from within Rust code
2/// ```ignore
3/// fn parse_basic_expression() {
4///     let ast1 = parse(
5///         "
6///        (+ 3 1)",
7///     )
8///     .next()
9///     .unwrap()
10///     .unwrap();
11///
12///     let n = 2;
13///     let ast2 = lisp! {
14///         (+ { Value::Int(n + 1) } 1)
15///     };
16///
17///     assert_eq!(
18///         ast1,
19///         ast2
20///     );
21/// }
22/// ```
23#[allow(unused_macros)]
24#[macro_export]
25macro_rules! lisp {
26
27
28    // Embed a Rust expression with { }
29    ( { $e:expr } ) => {
30        $e
31    };
32
33
34    // Lists
35    ( ( $($val:tt)* ) ) => {
36        $crate::model::Value::List([ $(lisp!{ $val }),* ].iter().collect::<$crate::model::List>())
37    };
38
39
40    // 🦀 Very special!
41    // Special atoms
42    (nil) => { $crate::model::Value::NIL   };
43    (NIL) => { $crate::model::Value::NIL   };
44    (t) =>   { $crate::model::Value::True  };
45    (T) =>   { $crate::model::Value::True  };
46    (f) =>   { $crate::model::Value::False };
47    (F) =>   { $crate::model::Value::False };
48
49
50    // Symbols
51    ($sym:ident) => {
52        $crate::model::Value::Symbol($crate::model::Symbol(String::from(stringify!( $sym ))))
53    };
54    // these aren't valid Rust identifiers
55    ( + ) =>  { $crate::model::Value::Symbol($crate::model::Symbol(String::from("+"))) };
56    ( - ) =>  { $crate::model::Value::Symbol($crate::model::Symbol(String::from("-"))) };
57    ( * ) =>  { $crate::model::Value::Symbol($crate::model::Symbol(String::from("*"))) };
58    ( / ) =>  { $crate::model::Value::Symbol($crate::model::Symbol(String::from("/"))) };
59    ( == ) => { $crate::model::Value::Symbol($crate::model::Symbol(String::from("=="))) };
60    ( != ) => { $crate::model::Value::Symbol($crate::model::Symbol(String::from("!="))) };
61    ( < ) =>  { $crate::model::Value::Symbol($crate::model::Symbol(String::from("<"))) };
62    ( <= ) => { $crate::model::Value::Symbol($crate::model::Symbol(String::from("<="))) };
63    ( > ) =>  { $crate::model::Value::Symbol($crate::model::Symbol(String::from(">"))) };
64    ( >= ) => { $crate::model::Value::Symbol($crate::model::Symbol(String::from(">="))) };
65
66
67    // Literals
68    ($e:literal) => {
69        // HACK: Macros don't have a good way to
70        // distinguish different kinds of literals,
71        // so we just kick those out to be parsed
72        // at runtime.
73        $crate::parser::parse(stringify!($e)).next().unwrap().unwrap()
74    };
75}