Skip to main content

conjure_cp_essence_parser/parser/
parse_exprs.rs

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