Skip to main content

conjure_cp_essence_parser/parser/
parse_exprs.rs

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