Skip to main content

conjure_cp_essence_parser/parser/
parse_exprs.rs

1use super::util::{get_tree, query_toplevel};
2use crate::errors::FatalParseError;
3use crate::expression::parse_expression;
4use crate::util::node_is_expression;
5use conjure_cp_core::ast::{Expression, SymbolTablePtr};
6#[allow(unused)]
7use uniplate::Uniplate;
8
9pub fn parse_expr(src: &str, symbols_ptr: SymbolTablePtr) -> Result<Expression, FatalParseError> {
10    let exprs = parse_exprs(src, symbols_ptr)?;
11    if exprs.len() != 1 {
12        return Err(FatalParseError::syntax_error(
13            "Expected a single expression".to_string(),
14            None,
15        ));
16    }
17    Ok(exprs[0].clone())
18}
19
20pub fn parse_exprs(
21    src: &str,
22    symbols_ptr: SymbolTablePtr,
23) -> Result<Vec<Expression>, FatalParseError> {
24    let (tree, source_code) = get_tree(src).ok_or(FatalParseError::TreeSitterError(
25        "Failed to parse Essence source code".to_string(),
26    ))?;
27
28    let root = tree.root_node();
29    let mut ans = Vec::new();
30    for expr in query_toplevel(&root, &node_is_expression) {
31        ans.push(parse_expression(
32            expr,
33            &source_code,
34            &root,
35            Some(symbols_ptr.clone()),
36            &mut Vec::new(),
37        )?);
38    }
39    Ok(ans)
40}
41
42mod test {
43    #[allow(unused)]
44    use super::{parse_expr, parse_exprs};
45    #[allow(unused)]
46    use conjure_cp_core::ast::SymbolTablePtr;
47    #[allow(unused)]
48    use conjure_cp_core::ast::{
49        Atom, DeclarationPtr, Domain, Expression, Literal, Metadata, Moo, Name, SymbolTable,
50    };
51    #[allow(unused)]
52    use std::collections::HashMap;
53    #[allow(unused)]
54    use std::sync::Arc;
55    #[allow(unused)]
56    use tree_sitter::Range;
57
58    #[test]
59    pub fn test_parse_constant() {
60        let symbols = SymbolTablePtr::new();
61
62        assert_eq!(
63            parse_expr("42", symbols.clone()).unwrap(),
64            Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Int(42)))
65        );
66        assert_eq!(
67            parse_expr("true", symbols.clone()).unwrap(),
68            Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Bool(true)))
69        );
70        assert_eq!(
71            parse_expr("false", symbols).unwrap(),
72            Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Bool(false)))
73        )
74    }
75
76    #[test]
77    pub fn test_parse_expressions() {
78        let src = "x >= 5, y = a / 2";
79        let symbols = SymbolTablePtr::new();
80        let x = DeclarationPtr::new_find(
81            Name::User("x".into()),
82            Domain::int(vec![conjure_cp_core::ast::Range::Bounded(0, 10)]),
83        );
84
85        let y = DeclarationPtr::new_find(
86            Name::User("y".into()),
87            Domain::int(vec![conjure_cp_core::ast::Range::Bounded(0, 10)]),
88        );
89
90        let a = DeclarationPtr::new_find(
91            Name::User("a".into()),
92            Domain::int(vec![conjure_cp_core::ast::Range::Bounded(0, 10)]),
93        );
94
95        // Clone the Rc when inserting!
96        symbols
97            .write()
98            .insert(x.clone())
99            .expect("x should not exist in the symbol-table yet, so we should be able to add it");
100
101        symbols
102            .write()
103            .insert(y.clone())
104            .expect("y should not exist in the symbol-table yet, so we should be able to add it");
105
106        symbols
107            .write()
108            .insert(a.clone())
109            .expect("a should not exist in the symbol-table yet, so we should be able to add it");
110
111        let exprs = parse_exprs(src, symbols).unwrap();
112        assert_eq!(exprs.len(), 2);
113
114        assert_eq!(
115            exprs[0],
116            Expression::Geq(
117                Metadata::new(),
118                Moo::new(Expression::Atomic(Metadata::new(), Atom::new_ref(x))),
119                Moo::new(Expression::Atomic(Metadata::new(), 5.into()))
120            )
121        );
122
123        assert_eq!(
124            exprs[1],
125            Expression::Eq(
126                Metadata::new(),
127                Moo::new(Expression::Atomic(Metadata::new(), Atom::new_ref(y))),
128                Moo::new(Expression::UnsafeDiv(
129                    Metadata::new(),
130                    Moo::new(Expression::Atomic(Metadata::new(), Atom::new_ref(a))),
131                    Moo::new(Expression::Atomic(Metadata::new(), 2.into()))
132                ))
133            )
134        );
135    }
136}