conjure_cp_essence_parser/parser/
parse_exprs.rs

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