conjure_cp_essence_parser/parser/
parse_exprs.rs1use super::util::{get_tree, query_toplevel};
2use crate::errors::EssenceParseError;
3use crate::expression::parse_expression;
4use crate::util::node_is_expression;
5use conjure_cp_core::ast::{Expression, SymbolTable};
6use std::cell::RefCell;
7use std::rc::Rc;
8#[allow(unused)]
9use uniplate::Uniplate;
10
11pub 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
22pub 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
44mod 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 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}