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