1use dmntk_common::{write, AsciiLine, AsciiNode, ColorMode};
4use dmntk_feel::{FeelType, Name};
5use std::fmt;
6use std::fmt::Write;
7
8#[derive(Debug, Clone, PartialEq)]
10pub enum AstNode {
11 Add(Box<AstNode>, Box<AstNode>),
13
14 And(Box<AstNode>, Box<AstNode>),
16
17 At(String),
19
20 Between(Box<AstNode>, Box<AstNode>, Box<AstNode>),
22
23 Boolean(bool),
25
26 CommaList(Vec<AstNode>),
28
29 Context(Vec<AstNode>),
32
33 ContextEntry(Box<AstNode>, Box<AstNode>),
35
36 ContextEntryKey(Name),
40
41 ContextType(Vec<AstNode>),
45
46 ContextTypeEntry(
48 Box<AstNode>,
50 Box<AstNode>,
52 ),
53
54 ContextTypeEntryKey(Name),
57
58 Div(Box<AstNode>, Box<AstNode>),
60
61 Eq(Box<AstNode>, Box<AstNode>),
63
64 EvaluatedExpression(Box<AstNode>),
66
67 Every(
69 Box<AstNode>,
71 Box<AstNode>,
73 ),
74
75 Exp(Box<AstNode>, Box<AstNode>),
77
78 ExpressionList(Vec<AstNode>),
80
81 FeelType(FeelType),
83
84 Filter(Box<AstNode>, Box<AstNode>),
86
87 For(
89 Box<AstNode>,
91 Box<AstNode>,
93 ),
94
95 FormalParameter(
97 Box<AstNode>,
99 Box<AstNode>,
101 ),
102
103 FormalParameters(Vec<AstNode>),
105
106 FunctionBody(Box<AstNode>, bool),
109
110 FunctionDefinition(Box<AstNode>, Box<AstNode>),
113
114 FunctionInvocation(Box<AstNode>, Box<AstNode>),
116
117 FunctionType(
119 Box<AstNode>,
121 Box<AstNode>,
123 ),
124
125 Ge(Box<AstNode>, Box<AstNode>),
127
128 Gt(Box<AstNode>, Box<AstNode>),
130
131 If(
133 Box<AstNode>,
135 Box<AstNode>,
137 Box<AstNode>,
139 ),
140
141 In(Box<AstNode>, Box<AstNode>),
143
144 InstanceOf(
146 Box<AstNode>,
148 Box<AstNode>,
150 ),
151
152 IntervalEnd(Box<AstNode>, bool),
154
155 IntervalStart(Box<AstNode>, bool),
157
158 Irrelevant,
160
161 IterationContexts(Vec<AstNode>),
163
164 IterationContextSingle(
166 Box<AstNode>,
168 Box<AstNode>,
170 ),
171
172 IterationContextRange(
174 Box<AstNode>,
176 Box<AstNode>,
178 Box<AstNode>,
180 ),
181
182 Le(Box<AstNode>, Box<AstNode>),
184
185 Lt(Box<AstNode>, Box<AstNode>),
187
188 List(Vec<AstNode>),
190
191 ListType(Box<AstNode>),
193
194 Mul(Box<AstNode>, Box<AstNode>),
196
197 Name(Name),
199
200 NamedParameter(
202 Box<AstNode>,
204 Box<AstNode>,
206 ),
207
208 NamedParameters(Vec<AstNode>),
210
211 NegatedList(Vec<AstNode>),
213
214 Neg(Box<AstNode>),
216
217 Nq(Box<AstNode>, Box<AstNode>),
219
220 Null,
222
223 Numeric(String, String),
225
226 Or(Box<AstNode>, Box<AstNode>),
228
229 Out(Box<AstNode>, Box<AstNode>),
231
232 ParameterName(Name),
234
235 ParameterTypes(Vec<AstNode>),
237
238 Path(Box<AstNode>, Box<AstNode>),
240
241 PositionalParameters(Vec<AstNode>),
243
244 QualifiedName(Vec<AstNode>),
246
247 QualifiedNameSegment(Name),
249
250 QuantifiedContexts(Vec<AstNode>),
252
253 QuantifiedContext(
255 Box<AstNode>,
257 Box<AstNode>,
259 ),
260
261 Range(Box<AstNode>, Box<AstNode>),
263
264 RangeType(Box<AstNode>),
266
267 Satisfies(Box<AstNode>),
269
270 Some(
272 Box<AstNode>,
274 Box<AstNode>,
276 ),
277
278 String(String),
280
281 Sub(Box<AstNode>, Box<AstNode>),
283
284 UnaryGe(Box<AstNode>),
286
287 UnaryGt(Box<AstNode>),
289
290 UnaryLe(Box<AstNode>),
292
293 UnaryLt(Box<AstNode>),
295}
296
297impl fmt::Display for AstNode {
298 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
300 write!(f, "{}\n ", ast_tree(self, &ColorMode::Off))
301 }
302}
303
304impl AstNode {
305 pub fn trace(&self) -> String {
307 let output = format!(" AST:{self}");
308 println!("{output}");
309 output
310 }
311}
312
313pub fn ast_tree(node: &AstNode, color_mode: &ColorMode) -> String {
315 let mut tree = String::new();
316 let _ = write(&mut tree, &ast_node_to_tree(node), color_mode);
317 let mut output = String::new();
318 for line in tree.lines() {
319 let _ = write!(&mut output, "\n {}", line);
320 }
321 output
322}
323
324fn ast_node_to_tree(node: &AstNode) -> AsciiNode {
326 match node {
327 AstNode::Add(lhs, rhs) => node_2("Add", lhs, rhs),
328 AstNode::And(lhs, rhs) => node_2("And", lhs, rhs),
329 AstNode::At(mid) => node_and_leaf("At", &format!("`{mid}`")),
330 AstNode::Between(lhs, mid, rhs) => node_3("Between", lhs, mid, rhs),
331 AstNode::Boolean(mid) => node_and_leaf("Boolean", &format!("`{mid}`")),
332 AstNode::CommaList(mid) => node_n("CommaList", mid),
333 AstNode::Context(items) => node_n("Context", items),
334 AstNode::ContextEntry(lhs, rhs) => node_2("ContextEntry", lhs, rhs),
335 AstNode::ContextEntryKey(mid) => node_and_leaf("ContextEntryKey", &format!("`{mid}`")),
336 AstNode::ContextType(items) => node_n("ContextType", items),
337 AstNode::ContextTypeEntry(lhs, rhs) => node_2("ContextTypeEntry", lhs, rhs),
338 AstNode::ContextTypeEntryKey(mid) => node_and_leaf("Name", &format!("`{mid}`")),
339 AstNode::Div(lhs, rhs) => node_2("Div", lhs, rhs),
340 AstNode::Eq(lhs, rhs) => node_2("Eq", lhs, rhs),
341 AstNode::EvaluatedExpression(mid) => node_1("EvaluatedExpression", mid),
342 AstNode::Every(lhs, rhs) => node_2("Every", lhs, rhs),
343 AstNode::Exp(lhs, rhs) => node_2("Exp", lhs, rhs),
344 AstNode::ExpressionList(items) => node_n("ExpressionList", items),
345 AstNode::FeelType(lhs) => node_and_leaf("FeelType", &lhs.to_string()),
346 AstNode::Filter(lhs, rhs) => node_2("Filter", lhs, rhs),
347 AstNode::For(lhs, rhs) => node_2("For", lhs, rhs),
348 AstNode::FormalParameter(lhs, rhs) => node_2("FormalParameter", lhs, rhs),
349 AstNode::FormalParameters(items) => node_n("FormalParameters", items),
350 AstNode::FunctionBody(lhs, external) => node_and_label("FunctionBody", lhs, " (external)", "", *external),
351 AstNode::FunctionDefinition(lhs, rhs) => node_2("FunctionDefinition", lhs, rhs),
352 AstNode::FunctionInvocation(lhs, rhs) => node_2("FunctionInvocation", lhs, rhs),
353 AstNode::FunctionType(lhs, rhs) => node_2("FunctionType", lhs, rhs),
354 AstNode::Ge(lhs, rhs) => node_2("Ge", lhs, rhs),
355 AstNode::Gt(lhs, rhs) => node_2("Gt", lhs, rhs),
356 AstNode::If(lhs, mid, rhs) => node_3("If", lhs, mid, rhs),
357 AstNode::In(lhs, rhs) => node_2("In", lhs, rhs),
358 AstNode::InstanceOf(lhs, rhs) => node_2("InstanceOf", lhs, rhs),
359 AstNode::IntervalEnd(lhs, closed) => node_and_label("IntervalEnd", lhs, " (closed)", " (opened)", *closed),
360 AstNode::IntervalStart(lhs, closed) => node_and_label("IntervalStart", lhs, " (closed)", " (opened)", *closed),
361 AstNode::Irrelevant => leaf("Irrelevant"),
362 AstNode::IterationContexts(items) => node_n("IterationContexts", items),
363 AstNode::IterationContextSingle(lhs, rhs) => node_2("IterationContextSingle", lhs, rhs),
364 AstNode::IterationContextRange(lhs, mid, rhs) => node_3("IterationContextRange", lhs, mid, rhs),
365 AstNode::Le(lhs, rhs) => node_2("Le", lhs, rhs),
366 AstNode::List(mid) => node_n("List", mid),
367 AstNode::ListType(lhs) => node_1("ListType", lhs),
368 AstNode::Lt(lhs, rhs) => node_2("Lt", lhs, rhs),
369 AstNode::Mul(lhs, rhs) => node_2("Mul", lhs, rhs),
370 AstNode::Name(mid) => node_and_leaf("Name", &format!("`{mid}`")),
371 AstNode::NamedParameter(lhs, rhs) => node_2("NamedParameter", lhs, rhs),
372 AstNode::NamedParameters(items) => node_n("NamedParameters", items),
373 AstNode::Neg(mid) => node_1("Neg", mid),
374 AstNode::NegatedList(mid) => node_n("NegatedList", mid),
375 AstNode::Nq(lhs, rhs) => node_2("Nq", lhs, rhs),
376 AstNode::Null => leaf("Null"),
377 AstNode::Numeric(lhs, rhs) => node_and_leaf("Numeric", &format!("`{lhs}.{rhs}`")),
378 AstNode::Or(lhs, rhs) => node_2("Or", lhs, rhs),
379 AstNode::Out(lhs, rhs) => node_2("Out", lhs, rhs),
380 AstNode::ParameterName(lhs) => node_and_leaf("ParameterName", &format!("`{lhs}`")),
381 AstNode::ParameterTypes(items) => node_n("ParameterTypes", items),
382 AstNode::Path(lhs, rhs) => node_2("Path", lhs, rhs),
383 AstNode::PositionalParameters(items) => node_n("PositionalParameters", items),
384 AstNode::QualifiedName(items) => node_n("QualifiedName", items),
385 AstNode::QualifiedNameSegment(lhs) => node_and_leaf("Name", &format!("`{lhs}`")),
386 AstNode::QuantifiedContext(lhs, rhs) => node_2("QuantifiedContext", lhs, rhs),
387 AstNode::QuantifiedContexts(items) => node_n("QuantifiedContexts", items),
388 AstNode::Range(lhs, rhs) => node_2("Range", lhs, rhs),
389 AstNode::RangeType(lhs) => node_1("RangeType", lhs),
390 AstNode::Satisfies(mid) => node_1("Satisfies", mid),
391 AstNode::Some(lhs, rhs) => node_2("Some", lhs, rhs),
392 AstNode::String(mid) => node_and_leaf("String", &format!("`{mid}`")),
393 AstNode::Sub(lhs, rhs) => node_2("Sub", lhs, rhs),
394 AstNode::UnaryGe(mid) => node_1("UnaryGe", mid),
395 AstNode::UnaryGt(mid) => node_1("UnaryGt", mid),
396 AstNode::UnaryLe(mid) => node_1("UnaryLe", mid),
397 AstNode::UnaryLt(mid) => node_1("UnaryLt", mid),
398 }
399}
400
401fn node_1(name: &str, mid: &AstNode) -> AsciiNode {
403 AsciiNode::node_builder(AsciiLine::builder().text(name).build()).child(ast_node_to_tree(mid)).build()
404}
405
406fn node_2(name: &str, lhs: &AstNode, rhs: &AstNode) -> AsciiNode {
408 AsciiNode::node_builder(AsciiLine::builder().text(name).build())
409 .child(ast_node_to_tree(lhs))
410 .child(ast_node_to_tree(rhs))
411 .build()
412}
413
414fn node_3(name: &str, lhs: &AstNode, mid: &AstNode, rhs: &AstNode) -> AsciiNode {
416 AsciiNode::node_builder(AsciiLine::builder().text(name).build())
417 .child(ast_node_to_tree(lhs))
418 .child(ast_node_to_tree(mid))
419 .child(ast_node_to_tree(rhs))
420 .build()
421}
422
423fn node_n(name: &str, items: &[AstNode]) -> AsciiNode {
425 let mut node_builder = AsciiNode::node_builder(AsciiLine::builder().text(name).build());
426 if items.is_empty() {
427 node_builder.add_child(AsciiNode::leaf_builder().line(AsciiLine::builder().text("(empty)").build()).build());
428 } else {
429 for item in items {
430 node_builder.add_child(ast_node_to_tree(item));
431 }
432 }
433 node_builder.build()
434}
435
436fn node_and_leaf(name: &str, leaf: &str) -> AsciiNode {
438 AsciiNode::node_builder(AsciiLine::builder().text(name).build())
439 .child(AsciiNode::leaf_builder().line(AsciiLine::builder().text(leaf).build()).build())
440 .build()
441}
442
443fn node_and_label(name: &str, lhs: &AstNode, label_true: &str, label_false: &str, label_flag: bool) -> AsciiNode {
445 let name_label = if label_flag { label_true } else { label_false };
446 AsciiNode::node_builder(AsciiLine::builder().text(name).text(name_label).build())
447 .child(ast_node_to_tree(lhs))
448 .build()
449}
450
451fn leaf(leaf: &str) -> AsciiNode {
453 AsciiNode::leaf_builder().line(AsciiLine::builder().text(leaf).build()).build()
454}