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