1
use super::ParseContext;
2
use super::util::{get_tree, query_toplevel};
3
use crate::diagnostics::source_map::SourceMap;
4
use crate::errors::FatalParseError;
5
use crate::expression::parse_expression;
6
use crate::util::node_is_expression;
7
use conjure_cp_core::ast::{Expression, SymbolTablePtr};
8
#[allow(unused)]
9
use uniplate::Uniplate;
10

            
11
9
pub fn parse_expr(src: &str, symbols_ptr: SymbolTablePtr) -> Result<Expression, FatalParseError> {
12
9
    let exprs = parse_exprs(src, symbols_ptr)?;
13
9
    if exprs.len() != 1 {
14
1
        return Err(FatalParseError::internal_error(
15
1
            "Expected a single expression".to_string(),
16
1
            None,
17
1
        ));
18
8
    }
19
8
    Ok(exprs[0].clone())
20
9
}
21

            
22
10
pub fn parse_exprs(
23
10
    src: &str,
24
10
    symbols_ptr: SymbolTablePtr,
25
10
) -> Result<Vec<Expression>, FatalParseError> {
26
10
    let (tree, source_code) = get_tree(src).ok_or(FatalParseError::TreeSitterError(
27
10
        "Failed to parse Essence source code".to_string(),
28
10
    ))?;
29

            
30
10
    let root = tree.root_node();
31
10
    let mut source_map = SourceMap::default();
32
10
    let mut errors = Vec::new();
33
10
    let mut ctx = ParseContext::new(
34
10
        &source_code,
35
10
        &root,
36
10
        Some(symbols_ptr),
37
10
        &mut errors,
38
10
        &mut source_map,
39
    );
40
10
    let mut ans = Vec::new();
41
11
    for expr in query_toplevel(&root, &node_is_expression) {
42
11
        let Some(expr) = parse_expression(&mut ctx, expr)? else {
43
1
            continue;
44
        };
45
10
        ans.push(expr);
46
    }
47
10
    Ok(ans)
48
10
}
49

            
50
mod 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
1
    pub fn test_parse_constant() {
68
1
        let symbols = SymbolTablePtr::new();
69

            
70
1
        assert_eq!(
71
1
            parse_expr("42", symbols.clone()).unwrap(),
72
1
            Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Int(42)))
73
        );
74
1
        assert_eq!(
75
1
            parse_expr("true", symbols.clone()).unwrap(),
76
1
            Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Bool(true)))
77
        );
78
1
        assert_eq!(
79
1
            parse_expr("false", symbols).unwrap(),
80
1
            Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Bool(false)))
81
        )
82
1
    }
83

            
84
    #[test]
85
1
    pub fn test_parse_expressions() {
86
1
        let src = "x >= 5, y = a / 2";
87
1
        let symbols = SymbolTablePtr::new();
88
1
        let x = DeclarationPtr::new_find(
89
1
            Name::User("x".into()),
90
1
            Domain::int(vec![conjure_cp_core::ast::Range::Bounded(0, 10)]),
91
        );
92

            
93
1
        let y = DeclarationPtr::new_find(
94
1
            Name::User("y".into()),
95
1
            Domain::int(vec![conjure_cp_core::ast::Range::Bounded(0, 10)]),
96
        );
97

            
98
1
        let a = DeclarationPtr::new_find(
99
1
            Name::User("a".into()),
100
1
            Domain::int(vec![conjure_cp_core::ast::Range::Bounded(0, 10)]),
101
        );
102

            
103
        // Clone the Rc when inserting!
104
1
        symbols
105
1
            .write()
106
1
            .insert(x.clone())
107
1
            .expect("x should not exist in the symbol-table yet, so we should be able to add it");
108

            
109
1
        symbols
110
1
            .write()
111
1
            .insert(y.clone())
112
1
            .expect("y should not exist in the symbol-table yet, so we should be able to add it");
113

            
114
1
        symbols
115
1
            .write()
116
1
            .insert(a.clone())
117
1
            .expect("a should not exist in the symbol-table yet, so we should be able to add it");
118

            
119
1
        let exprs = parse_exprs(src, symbols).unwrap();
120
1
        assert_eq!(exprs.len(), 2);
121

            
122
1
        assert_eq!(
123
1
            exprs[0],
124
1
            Expression::Geq(
125
1
                Metadata::new(),
126
1
                Moo::new(Expression::Atomic(Metadata::new(), Atom::new_ref(x))),
127
1
                Moo::new(Expression::Atomic(Metadata::new(), 5.into()))
128
1
            )
129
        );
130

            
131
1
        assert_eq!(
132
1
            exprs[1],
133
1
            Expression::Eq(
134
1
                Metadata::new(),
135
1
                Moo::new(Expression::Atomic(Metadata::new(), Atom::new_ref(y))),
136
1
                Moo::new(Expression::UnsafeDiv(
137
1
                    Metadata::new(),
138
1
                    Moo::new(Expression::Atomic(Metadata::new(), Atom::new_ref(a))),
139
1
                    Moo::new(Expression::Atomic(Metadata::new(), 2.into()))
140
1
                ))
141
1
            )
142
        );
143
1
    }
144
}