conjure_cp_essence_parser/parser/
parse_exprs.rs1use super::ParseContext;
2use super::util::{get_expr_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};
8use std::collections::BTreeMap;
9#[allow(unused)]
10use uniplate::Uniplate;
11
12pub fn parse_expr(
13 src: &str,
14 symbols_ptr: SymbolTablePtr,
15) -> Result<Option<Expression>, FatalParseError> {
16 let exprs = parse_exprs(src, symbols_ptr)?;
17 if exprs.len() != 1 {
18 return Ok(None);
19 }
20 Ok(Some(exprs[0].clone()))
21}
22
23pub fn parse_exprs(
24 src: &str,
25 symbols_ptr: SymbolTablePtr,
26) -> Result<Vec<Expression>, FatalParseError> {
27 let Some((tree, source_code)) = get_expr_tree(src) else {
28 return Ok(Vec::new());
29 };
30
31 let root = tree.root_node();
32 let mut source_map = SourceMap::default();
33 let mut decl_spans = BTreeMap::new();
34 let mut errors = Vec::new();
35 let mut ctx = ParseContext::new(
36 &source_code,
37 &root,
38 Some(symbols_ptr),
39 &mut errors,
40 &mut source_map,
41 &mut decl_spans,
42 );
43 let mut ans = Vec::new();
44 for expr in query_toplevel(&root, &node_is_expression) {
45 let Some(expr) = parse_expression(&mut ctx, expr)? else {
46 continue;
47 };
48 ans.push(expr);
49 }
50 Ok(ans)
51}
52
53mod test {
54 #[allow(unused)]
55 use super::{parse_expr, parse_exprs};
56 #[allow(unused)]
57 use conjure_cp_core::ast::SymbolTablePtr;
58 #[allow(unused)]
59 use conjure_cp_core::ast::{
60 Atom, DeclarationPtr, Domain, Expression, Literal, Metadata, Moo, Name, SymbolTable,
61 };
62 #[allow(unused)]
63 use std::collections::HashMap;
64 #[allow(unused)]
65 use std::sync::Arc;
66 #[allow(unused)]
67 use tree_sitter::Range;
68
69 #[test]
70 pub fn test_parse_constant() {
71 let symbols = SymbolTablePtr::new();
72
73 assert_eq!(
74 parse_expr("42", symbols.clone()).unwrap().unwrap(),
75 Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Int(42)))
76 );
77 assert_eq!(
78 parse_expr("true", symbols.clone()).unwrap().unwrap(),
79 Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Bool(true)))
80 );
81 assert_eq!(
82 parse_expr("false", symbols).unwrap().unwrap(),
83 Expression::Atomic(Metadata::new(), Atom::Literal(Literal::Bool(false)))
84 )
85 }
86
87 #[test]
88 pub fn test_parse_expressions() {
89 let src = "x >= 5, y = a / 2";
90 let symbols = SymbolTablePtr::new();
91 let x = DeclarationPtr::new_find(
92 Name::User("x".into()),
93 Domain::int(vec![conjure_cp_core::ast::Range::Bounded(0, 10)]),
94 );
95
96 let y = DeclarationPtr::new_find(
97 Name::User("y".into()),
98 Domain::int(vec![conjure_cp_core::ast::Range::Bounded(0, 10)]),
99 );
100
101 let a = DeclarationPtr::new_find(
102 Name::User("a".into()),
103 Domain::int(vec![conjure_cp_core::ast::Range::Bounded(0, 10)]),
104 );
105
106 symbols
108 .write()
109 .insert(x.clone())
110 .expect("x should not exist in the symbol-table yet, so we should be able to add it");
111
112 symbols
113 .write()
114 .insert(y.clone())
115 .expect("y should not exist in the symbol-table yet, so we should be able to add it");
116
117 symbols
118 .write()
119 .insert(a.clone())
120 .expect("a should not exist in the symbol-table yet, so we should be able to add it");
121
122 let exprs = parse_exprs(src, symbols).unwrap();
123 assert_eq!(exprs.len(), 2);
124
125 assert_eq!(
126 exprs[0],
127 Expression::Geq(
128 Metadata::new(),
129 Moo::new(Expression::Atomic(Metadata::new(), Atom::new_ref(x))),
130 Moo::new(Expression::Atomic(Metadata::new(), 5.into()))
131 )
132 );
133
134 assert_eq!(
135 exprs[1],
136 Expression::Eq(
137 Metadata::new(),
138 Moo::new(Expression::Atomic(Metadata::new(), Atom::new_ref(y))),
139 Moo::new(Expression::UnsafeDiv(
140 Metadata::new(),
141 Moo::new(Expression::Atomic(Metadata::new(), Atom::new_ref(a))),
142 Moo::new(Expression::Atomic(Metadata::new(), 2.into()))
143 ))
144 )
145 );
146 }
147}