1
use proc_macro::TokenStream;
2
use proc_macro2::{Delimiter, Group, TokenStream as TokenStream2, TokenTree};
3

            
4
mod expand;
5

            
6
use expand::{expand_expr, expand_expr_vec};
7

            
8
/// Parses an Essence expression into its corresponding Conjure AST at compile time.
9
///
10
/// ## Input
11
/// The input can be one of the following:
12
/// - The raw Essence tokens (`essence_expr!(2 + 2)`)
13
/// - A string literal (`essence_expr!("2 + 2")`)
14
///
15
/// The macro may reference variables in the current scope (called "metavars")
16
/// using the syntax `&<name>`. For example:
17
/// ```rust
18
/// use conjure_cp_essence_macros::essence_expr;
19
/// let x = 42;
20
/// let expr = essence_expr!(2 + &x);
21
/// ```
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
///
35
/// ## Example
36
///
37
/// ```rust
38
/// use conjure_cp::ast::{Atom, Expression, Moo, Metadata};
39
/// use conjure_cp::matrix_expr;
40
/// use conjure_cp_essence_macros::essence_expr;
41
/// let x = 42;
42
/// let expr = essence_expr!(2 + &x);
43
/// assert_eq!(
44
///     expr,
45
///     Expression::Sum(Metadata::new(), Moo::new(matrix_expr![
46
///         Expression::Atomic(Metadata::new(), 2.into()),
47
///         Expression::Atomic(Metadata::new(), 42.into())
48
///     ]))
49
/// );
50
/// ```
51
#[proc_macro]
52
192
pub fn essence_expr(args: TokenStream) -> TokenStream {
53
192
    let ts = TokenStream2::from(args);
54
192
    let tt = TokenTree::Group(Group::new(Delimiter::None, ts));
55
192
    match expand_expr(&tt) {
56
192
        Ok(tokens) => tokens.into(),
57
        Err(err) => err.to_compile_error().into(),
58
    }
59
192
}
60

            
61
/// Parses a sequence of Essence expressions into a vector of Conjure AST instances
62
///
63
/// ## Example
64
/// ```rust
65
/// use conjure_cp::ast::{Atom, Expression, Moo, Metadata};
66
/// use conjure_cp::matrix_expr;
67
/// use conjure_cp_essence_macros::essence_vec;
68
///
69
/// let exprs = essence_vec!(2 + 2, false = true);
70
/// println!("{:?}", exprs);
71
/// assert_eq!(exprs.len(), 2);
72
/// assert_eq!(
73
///     exprs[0],
74
///     Expression::Sum(Metadata::new(), Moo::new(matrix_expr![
75
///         Expression::Atomic(Metadata::new(), 2.into()),
76
///         Expression::Atomic(Metadata::new(), 2.into())
77
///     ]))
78
/// );
79
/// assert_eq!(
80
///    exprs[1],
81
///     Expression::Eq(Metadata::new(),
82
///         Moo::new(Expression::Atomic(Metadata::new(), false.into())),
83
///         Moo::new(Expression::Atomic(Metadata::new(), true.into()))
84
///     )
85
/// );
86
/// ```
87
#[proc_macro]
88
1
pub fn essence_vec(args: TokenStream) -> TokenStream {
89
1
    let ts = TokenStream2::from(args);
90
1
    let tt = TokenTree::Group(Group::new(Delimiter::None, ts));
91
1
    match expand_expr_vec(&tt) {
92
1
        Ok(tokens) => tokens.into(),
93
        Err(err) => err.to_compile_error().into(),
94
    }
95
1
}