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