1
use super::util::{get_tree, query_toplevel};
2
use crate::errors::EssenceParseError;
3
use crate::expression::parse_expression;
4
use crate::util::node_is_expression;
5
use conjure_cp_core::ast::{Expression, SymbolTable};
6
use std::cell::RefCell;
7
use std::rc::Rc;
8
#[allow(unused)]
9
use uniplate::Uniplate;
10

            
11
pub 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

            
22
pub 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

            
44
mod 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
}