conjure_essence_macros/lib.rs
1use proc_macro::TokenStream;
2use proc_macro2::{Delimiter, Group, TokenStream as TokenStream2, TokenTree};
3
4mod expand;
5mod expression;
6
7use expand::{expand_expr, expand_expr_vec};
8
9/// Parses an Essence expression into its corresponding Conjure AST at compile time.
10///
11/// ## Input
12/// The input can be one of the following:
13/// - The raw Essence tokens (`essence_expr!(2 + 2)`)
14/// - A string literal (`essence_expr!("2 + 2")`)
15///
16/// The macro may reference variables in the current scope (called "metavars")
17/// using the syntax `&<name>`. For example:
18/// ```
19/// use conjure_essence_macros::essence_expr;
20/// let x = 42;
21/// essence_expr!(2 + &x);
22/// ```
23///
24/// ## Expansion
25/// If the input is valid Essence, expands to a valid AST constructor
26///
27/// ## Note
28/// Some characters (e.g. `\`) are valid Essence tokens, but not Rust tokens.
29/// If you encounter an error similar to:
30///
31/// > rustc: unknown start of token: \
32///
33/// The workaround is to wrap the Essence code in a string literal (e.g. `r"a /\ b"`).
34#[proc_macro]
35pub fn essence_expr(args: TokenStream) -> TokenStream {
36 let ts = TokenStream2::from(args);
37 let tt = TokenTree::Group(Group::new(Delimiter::None, ts));
38 match expand_expr(&tt) {
39 Ok(tokens) => tokens.into(),
40 Err(err) => err.to_compile_error().into(),
41 }
42}
43
44/// Parses a sequence of Essence expressions into a vector of Conjure AST instances
45///
46/// ## Example
47/// ```rust
48/// use conjure_core::ast::{Atom, Expression};
49/// use conjure_core::matrix_expr;
50/// use conjure_core::metadata::Metadata;
51/// use conjure_essence_macros::essence_vec;
52///
53/// let exprs = essence_vec!(a + 2, b = true);
54/// println!("{:?}", exprs);
55/// assert_eq!(exprs.len(), 2);
56/// assert_eq!(
57/// exprs[0],
58/// Expression::Sum(Metadata::new(), Box::new(matrix_expr![
59/// Expression::Atomic(Metadata::new(), Atom::new_uref("a")),
60/// Expression::Atomic(Metadata::new(), Atom::new_ilit(2))
61/// ]))
62/// );
63/// assert_eq!(
64/// exprs[1],
65/// Expression::Eq(Metadata::new(),
66/// Box::new(Expression::Atomic(Metadata::new(), Atom::new_uref("b"))),
67/// Box::new(Expression::Atomic(Metadata::new(), Atom::new_blit(true)))
68/// )
69/// );
70/// ```
71#[proc_macro]
72pub fn essence_vec(args: TokenStream) -> TokenStream {
73 let ts = TokenStream2::from(args);
74 let tt = TokenTree::Group(Group::new(Delimiter::None, ts));
75 match expand_expr_vec(&tt) {
76 Ok(tokens) => tokens.into(),
77 Err(err) => err.to_compile_error().into(),
78 }
79}