Skip to main content

dsntk_feel_parser/
ast.rs

1//! Implementation of a node in Abstract Syntax Tree for `FEEL` grammar.
2
3use antex::{Color, ColorMode, StyledText, TreeNode, leaf, node};
4use dsntk_feel::{FeelType, IntervalType, Name};
5use std::fmt;
6use std::fmt::{Display, Write};
7
8/// Default color of the tree arms.
9const DEFAULT_COLOR: Color = Color::White;
10
11/// Node of the Abstract Syntax Tree for `FEEL` grammar.
12#[derive(Debug, Clone, PartialEq)]
13pub enum AstNode {
14  /// Node representing an arithmetic operator `+` (addition).
15  Add(Box<AstNode>, Box<AstNode>),
16
17  /// Node representing a logical operator `and` (conjunction).
18  And(Box<AstNode>, Box<AstNode>),
19
20  /// Node representing `@` (at) literal.
21  At(String),
22
23  /// Node representing a comparison operator `between`.
24  Between(Box<AstNode>, Box<AstNode>, Box<AstNode>),
25
26  /// Node representing a value of type `boolean`.
27  Boolean(bool),
28
29  /// Node representing a comma separated list of AST nodes, used internally by parser.
30  CommaList(Vec<AstNode>),
31
32  /// Node representing a context.
33  /// Context entries are stored in the order of appearance in definition.
34  Context(Vec<AstNode>),
35
36  /// Node representing single context entry; key-value pair.
37  ContextEntry(Box<AstNode>, Box<AstNode>),
38
39  /// Node representing the key of the context entry; the key in context entry
40  /// may be a name or string literal. String literals are converted to one segment names
41  /// containing exactly the value of the string.
42  ContextEntryKey(Name),
43
44  /// Node representing the type of the context. Context type is defined by names
45  /// and types of all entries. This node contains a collection of types
46  /// for all context entries in the order of appearance in context type definition.
47  ContextType(Vec<AstNode>),
48
49  /// Node representing single context type entry.
50  ContextTypeEntry(
51    /// Node representing entry name of the context key.
52    Box<AstNode>,
53    /// Node representing `FEEL` type of the context entry.
54    Box<AstNode>,
55  ),
56
57  /// Node representing the key of the entry in context type definition.
58  /// In context type definition, only `FEEL` name is allowed as an entry key.
59  ContextTypeEntryKey(Name),
60
61  /// Node representing arithmetic operator `/` (division).
62  Div(Box<AstNode>, Box<AstNode>),
63
64  /// Node representing `equal` comparison.
65  Eq(Box<AstNode>, Box<AstNode>),
66
67  /// Node representing an expression evaluated as a body of `for` expression.
68  EvaluatedExpression(Box<AstNode>),
69
70  /// Quantified expression `every`.
71  Every(
72    /// Node representing quantified contexts.
73    Box<AstNode>,
74    /// Node representing an expression after `satisfies` clause.
75    Box<AstNode>,
76  ),
77
78  /// Node representing exponential function.
79  Exp(Box<AstNode>, Box<AstNode>),
80
81  /// Node representing a list of expressions.
82  ExpressionList(Vec<AstNode>),
83
84  /// Node representing `FEEL` type.
85  FeelType(FeelType),
86
87  /// Node representing filter expression.
88  Filter(Box<AstNode>, Box<AstNode>),
89
90  /// Node representing `for` expression.
91  For(
92    /// Node representing [iteration contexts](AstNode::IterationContexts).
93    Box<AstNode>,
94    /// Node representing an expression to be evaluated.
95    Box<AstNode>,
96  ),
97
98  /// Node representing function's formal parameter.
99  FormalParameter(
100    /// Node representing the name of the parameter.
101    Box<AstNode>,
102    /// Node representing the `FEEL` type of the parameter.
103    Box<AstNode>,
104  ),
105
106  /// Node representing a list of formal parameters.
107  FormalParameters(Vec<AstNode>),
108
109  /// Node representing function's body. This node holds mandatory function body
110  /// and a flag indicating if the function is external.
111  FunctionBody(Box<AstNode>, bool),
112
113  /// Node representing function definition.
114  /// This node holds function's formal parameter list and  function's body.
115  FunctionDefinition(Box<AstNode>, Box<AstNode>),
116
117  /// Node representing function invocation.
118  FunctionInvocation(Box<AstNode>, Box<AstNode>),
119
120  /// Node representing function type.
121  FunctionType(
122    /// Node representing function's parameter types as [AstNode::ParameterTypes].
123    Box<AstNode>,
124    /// Node representing function's result type.
125    Box<AstNode>,
126  ),
127
128  /// Node representing `greater or equal` comparison.
129  Ge(Box<AstNode>, Box<AstNode>),
130
131  /// Node representing `greater than` comparison.
132  Gt(Box<AstNode>, Box<AstNode>),
133
134  /// Node representing `if` expression.
135  If(
136    /// Node representing the condition.
137    Box<AstNode>,
138    /// Node representing the expression to be evaluated when condition is `true`.
139    Box<AstNode>,
140    /// Node representing the expression to be evaluated when condition is `false`.
141    Box<AstNode>,
142  ),
143
144  /// Node representing `in` operator.
145  In(Box<AstNode>, Box<AstNode>),
146
147  /// Node representing type checking function.
148  InstanceOf(
149    /// Node representing the tested value.
150    Box<AstNode>,
151    /// Node representing `FELL` type to be checked.
152    Box<AstNode>,
153  ),
154
155  /// Node representing the interval end used in ranges.
156  IntervalEnd(
157    /// Value at the interval end.
158    Box<AstNode>,
159    /// Type of the interval end: opened or closed.
160    IntervalType,
161  ),
162
163  /// Node representing the interval start used in ranges.
164  IntervalStart(
165    /// Value at the interval start.
166    Box<AstNode>,
167    /// Type of the interval end: opened or closed.
168    IntervalType,
169  ),
170
171  /// Node representing the comparison operator `irrelevant`.
172  Irrelevant,
173
174  /// List of iteration contexts.
175  IterationContexts(Vec<AstNode>),
176
177  /// Node representing iteration context containing a single value to iterate over.
178  IterationContextSingle(
179    /// Node representing variable name used in this iteration context.
180    Box<AstNode>,
181    /// Node representing a single value to iterate over.
182    Box<AstNode>,
183  ),
184
185  /// Node representing iteration context containing the variable name
186  /// and a staring and ending value of the interval to iterate over.
187  IterationContextInterval(
188    /// Node representing variable name used in this iteration context.
189    Box<AstNode>,
190    /// Node representing the `start` value of the interval to iterate over.
191    Box<AstNode>,
192    /// Node representing the `end` value of the interval to iterate over.
193    Box<AstNode>,
194  ),
195
196  /// Node representing `less or equal` comparison.
197  Le(Box<AstNode>, Box<AstNode>),
198
199  /// Node representing `less than` comparison.
200  Lt(Box<AstNode>, Box<AstNode>),
201
202  /// Node representing a list.
203  List(Vec<AstNode>),
204
205  /// Node representing a list type.
206  ListType(Box<AstNode>),
207
208  /// Node representing arithmetic operator `*` (multiplication).
209  Mul(Box<AstNode>, Box<AstNode>),
210
211  /// Node representing a `FEEL` name.
212  Name(Name),
213
214  /// Node representing single named parameter.
215  NamedParameter(
216    /// Node representing parameter name.
217    Box<AstNode>,
218    /// Node representing parameter type.
219    Box<AstNode>,
220  ),
221
222  /// Node representing a collection of named parameters.
223  NamedParameters(Vec<AstNode>),
224
225  /// Node representing a negated list (used in negated unary tests).
226  NegatedList(Vec<AstNode>),
227
228  /// Node representing the unary arithmetic negation `-`.
229  Neg(Box<AstNode>),
230
231  /// Node representing `not equal` comparison.
232  Nq(Box<AstNode>, Box<AstNode>),
233
234  /// Node representing a value of type `Null`.
235  Null,
236
237  /// Node representing a value of type `number`.
238  Numeric(
239    /// Digits before decimal separator.
240    String,
241    /// Digits after decimal separator.
242    String,
243    /// Sign of the exponent.
244    char,
245    /// Digits of the exponent.
246    String,
247  ),
248
249  /// Node representing a logical operator `or` (disjunction).
250  Or(Box<AstNode>, Box<AstNode>),
251
252  /// Node representing expression for selecting decision table's output value.
253  Out(Box<AstNode>, Box<AstNode>),
254
255  /// Node representing a name of the function's formal parameter.
256  ParameterName(Name),
257
258  /// Node representing a collection of function parameter types.
259  ParameterTypes(Vec<AstNode>),
260
261  /// Node representing a path expression.
262  Path(Box<AstNode>, Box<AstNode>),
263
264  /// Node representing a collection of positional parameters.
265  PositionalParameters(Vec<AstNode>),
266
267  /// Node representing a collection of names that constitute a qualified name.
268  QualifiedName(Vec<AstNode>),
269
270  /// Node representing a segment of a qualified name.
271  QualifiedNameSegment(Name),
272
273  /// List of quantified contexts.
274  QuantifiedContexts(Vec<AstNode>),
275
276  /// Quantified context containing variable name and evaluation expression.
277  QuantifiedContext(
278    /// Node representing variable name used in this quantified context.
279    Box<AstNode>,
280    /// Node representing evaluation expression.
281    Box<AstNode>,
282  ),
283
284  /// Node representing a range of values.
285  Range(Box<AstNode>, Box<AstNode>),
286
287  /// Node representing range type.
288  RangeType(Box<AstNode>),
289
290  /// Node representing `satisfies` clause in quantified expression.
291  Satisfies(Box<AstNode>),
292
293  /// Node representing quantified expression `some`.
294  Some(
295    /// Node representing quantified contexts.
296    Box<AstNode>,
297    /// Node representing an expression after `satisfies` clause.
298    Box<AstNode>,
299  ),
300
301  /// Node representing a value of type `string`.
302  String(String),
303
304  /// Node representing an arithmetic operator `-` (subtraction).
305  Sub(Box<AstNode>, Box<AstNode>),
306
307  /// Node representing unary comparison operator `>=`.
308  UnaryGe(Box<AstNode>),
309
310  /// Node representing unary comparison operator `>`.
311  UnaryGt(Box<AstNode>),
312
313  /// Node representing unary comparison operator `<=>`.
314  UnaryLe(Box<AstNode>),
315
316  /// Node representing unary comparison operator `<less than>`.
317  UnaryLt(Box<AstNode>),
318
319  /// Node representing unary comparison operator `=`.
320  UnaryEq(Box<AstNode>),
321
322  /// Node representing unary comparison operator `!=`.
323  UnaryNe(Box<AstNode>),
324}
325
326impl Display for AstNode {
327  /// Converts [AstNode] to its textual representation.
328  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
329    write!(f, "{}", self.tree(0, ColorMode::Off))
330  }
331}
332
333impl AstNode {
334  /// Converts [AstNode] to its textual representation with indentation and color mode.
335  pub fn tree(&self, indent: usize, cm: ColorMode) -> String {
336    let root = ast_node_to_tree(self, cm);
337    let mut output = String::new();
338    _ = write!(output, "{:indent$}", root);
339    output
340  }
341
342  /// Returns AST as text for testing purposes.
343  pub fn trace(&self) -> String {
344    let root = ast_node_to_tree(self, ColorMode::Off);
345    let mut output = String::new();
346    _ = write!(output, "\n{:6}    ", root);
347    output
348  }
349}
350
351/// Converts [AstNode] into ASCII [TreeNode] node.
352fn ast_node_to_tree(node: &AstNode, cm: ColorMode) -> TreeNode {
353  match node {
354    AstNode::Add(lhs, rhs) => ast_node_2("Add", lhs, rhs, cm),
355    AstNode::And(lhs, rhs) => ast_node_2("And", lhs, rhs, cm),
356    AstNode::At(mid) => ast_node_and_leaf("At", &format!("`{mid}`"), cm),
357    AstNode::Between(lhs, mid, rhs) => ast_node_3("Between", lhs, mid, rhs, cm),
358    AstNode::Boolean(mid) => ast_node_and_leaf("Boolean", &format!("`{mid}`"), cm),
359    AstNode::CommaList(mid) => ast_node_n("CommaList", mid, cm),
360    AstNode::Context(items) => ast_node_n("Context", items, cm),
361    AstNode::ContextEntry(lhs, rhs) => ast_node_2("ContextEntry", lhs, rhs, cm),
362    AstNode::ContextEntryKey(mid) => ast_node_and_leaf("ContextEntryKey", &format!("`{mid}`"), cm),
363    AstNode::ContextType(items) => ast_node_n("ContextType", items, cm),
364    AstNode::ContextTypeEntry(lhs, rhs) => ast_node_2("ContextTypeEntry", lhs, rhs, cm),
365    AstNode::ContextTypeEntryKey(mid) => ast_node_and_leaf("Name", &format!("`{mid}`"), cm),
366    AstNode::Div(lhs, rhs) => ast_node_2("Div", lhs, rhs, cm),
367    AstNode::Eq(lhs, rhs) => ast_node_2("Eq", lhs, rhs, cm),
368    AstNode::EvaluatedExpression(mid) => ast_node_1("EvaluatedExpression", mid, cm),
369    AstNode::Every(lhs, rhs) => ast_node_2("Every", lhs, rhs, cm),
370    AstNode::Exp(lhs, rhs) => ast_node_2("Exp", lhs, rhs, cm),
371    AstNode::ExpressionList(items) => ast_node_n("ExpressionList", items, cm),
372    AstNode::FeelType(lhs) => ast_node_and_leaf("FeelType", &lhs.to_string(), cm),
373    AstNode::Filter(lhs, rhs) => ast_node_2("Filter", lhs, rhs, cm),
374    AstNode::For(lhs, rhs) => ast_node_2("For", lhs, rhs, cm),
375    AstNode::FormalParameter(lhs, rhs) => ast_node_2("FormalParameter", lhs, rhs, cm),
376    AstNode::FormalParameters(items) => ast_node_n("FormalParameters", items, cm),
377    AstNode::FunctionBody(lhs, external) => ast_node_and_conditional_label("FunctionBody", lhs, " (external)", "", *external, cm),
378    AstNode::FunctionDefinition(lhs, rhs) => ast_node_2("FunctionDefinition", lhs, rhs, cm),
379    AstNode::FunctionInvocation(lhs, rhs) => ast_node_2("FunctionInvocation", lhs, rhs, cm),
380    AstNode::FunctionType(lhs, rhs) => ast_node_2("FunctionType", lhs, rhs, cm),
381    AstNode::Ge(lhs, rhs) => ast_node_2("Ge", lhs, rhs, cm),
382    AstNode::Gt(lhs, rhs) => ast_node_2("Gt", lhs, rhs, cm),
383    AstNode::If(lhs, mid, rhs) => ast_node_3("If", lhs, mid, rhs, cm),
384    AstNode::In(lhs, rhs) => ast_node_2("In", lhs, rhs, cm),
385    AstNode::InstanceOf(lhs, rhs) => ast_node_2("InstanceOf", lhs, rhs, cm),
386    AstNode::IntervalEnd(lhs, interval_type) => ast_node_and_label("IntervalEnd", lhs, interval_type.to_string(), cm),
387    AstNode::IntervalStart(lhs, interval_type) => ast_node_and_label("IntervalStart", lhs, interval_type.to_string(), cm),
388    AstNode::Irrelevant => ast_leaf("Irrelevant", cm),
389    AstNode::IterationContexts(items) => ast_node_n("IterationContexts", items, cm),
390    AstNode::IterationContextSingle(lhs, rhs) => ast_node_2("IterationContextSingle", lhs, rhs, cm),
391    AstNode::IterationContextInterval(lhs, mid, rhs) => ast_node_3("IterationContextInterval", lhs, mid, rhs, cm),
392    AstNode::Le(lhs, rhs) => ast_node_2("Le", lhs, rhs, cm),
393    AstNode::List(mid) => ast_node_n("List", mid, cm),
394    AstNode::ListType(lhs) => ast_node_1("ListType", lhs, cm),
395    AstNode::Lt(lhs, rhs) => ast_node_2("Lt", lhs, rhs, cm),
396    AstNode::Mul(lhs, rhs) => ast_node_2("Mul", lhs, rhs, cm),
397    AstNode::Name(mid) => ast_node_and_leaf("Name", &format!("`{mid}`"), cm),
398    AstNode::NamedParameter(lhs, rhs) => ast_node_2("NamedParameter", lhs, rhs, cm),
399    AstNode::NamedParameters(items) => ast_node_n("NamedParameters", items, cm),
400    AstNode::Neg(mid) => ast_node_1("Neg", mid, cm),
401    AstNode::NegatedList(mid) => ast_node_n("NegatedList", mid, cm),
402    AstNode::Nq(lhs, rhs) => ast_node_2("Nq", lhs, rhs, cm),
403    AstNode::Null => ast_leaf("Null", cm),
404    AstNode::Numeric(before, after, sign, exponent) => ast_node_and_leaf("Numeric", &numeric_to_string(before, after, sign, exponent), cm),
405    AstNode::Or(lhs, rhs) => ast_node_2("Or", lhs, rhs, cm),
406    AstNode::Out(lhs, rhs) => ast_node_2("Out", lhs, rhs, cm),
407    AstNode::ParameterName(lhs) => ast_node_and_leaf("ParameterName", &format!("`{lhs}`"), cm),
408    AstNode::ParameterTypes(items) => ast_node_n("ParameterTypes", items, cm),
409    AstNode::Path(lhs, rhs) => ast_node_2("Path", lhs, rhs, cm),
410    AstNode::PositionalParameters(items) => ast_node_n("PositionalParameters", items, cm),
411    AstNode::QualifiedName(items) => ast_node_n("QualifiedName", items, cm),
412    AstNode::QualifiedNameSegment(lhs) => ast_node_and_leaf("Name", &format!("`{lhs}`"), cm),
413    AstNode::QuantifiedContext(lhs, rhs) => ast_node_2("QuantifiedContext", lhs, rhs, cm),
414    AstNode::QuantifiedContexts(items) => ast_node_n("QuantifiedContexts", items, cm),
415    AstNode::Range(lhs, rhs) => ast_node_2("Range", lhs, rhs, cm),
416    AstNode::RangeType(lhs) => ast_node_1("RangeType", lhs, cm),
417    AstNode::Satisfies(mid) => ast_node_1("Satisfies", mid, cm),
418    AstNode::Some(lhs, rhs) => ast_node_2("Some", lhs, rhs, cm),
419    AstNode::String(mid) => ast_node_and_leaf("String", &format!("`{mid}`"), cm),
420    AstNode::Sub(lhs, rhs) => ast_node_2("Sub", lhs, rhs, cm),
421    AstNode::UnaryGe(mid) => ast_node_1("UnaryGe", mid, cm),
422    AstNode::UnaryGt(mid) => ast_node_1("UnaryGt", mid, cm),
423    AstNode::UnaryLe(mid) => ast_node_1("UnaryLe", mid, cm),
424    AstNode::UnaryLt(mid) => ast_node_1("UnaryLt", mid, cm),
425    AstNode::UnaryEq(mid) => ast_node_1("UnaryEq", mid, cm),
426    AstNode::UnaryNe(mid) => ast_node_1("UnaryNe", mid, cm),
427  }
428}
429
430/// Creates a tree node with one child node.
431fn ast_node_1(name: &str, mid: &AstNode, cm: ColorMode) -> TreeNode {
432  node(DEFAULT_COLOR, cm).line().s(name).end().child(ast_node_to_tree(mid, cm)).end()
433}
434
435/// Creates a tree node with two child nodes.
436fn ast_node_2(name: &str, lhs: &AstNode, rhs: &AstNode, cm: ColorMode) -> TreeNode {
437  node(DEFAULT_COLOR, cm)
438    .line()
439    .s(name)
440    .end()
441    .child(ast_node_to_tree(lhs, cm))
442    .child(ast_node_to_tree(rhs, cm))
443    .end()
444}
445
446/// Creates a tree node with three child nodes.
447fn ast_node_3(name: &str, lhs: &AstNode, mid: &AstNode, rhs: &AstNode, cm: ColorMode) -> TreeNode {
448  node(DEFAULT_COLOR, cm)
449    .line()
450    .s(name)
451    .end()
452    .child(ast_node_to_tree(lhs, cm))
453    .child(ast_node_to_tree(mid, cm))
454    .child(ast_node_to_tree(rhs, cm))
455    .end()
456}
457
458/// Creates a tree node with multiple child nodes.
459fn ast_node_n(name: &str, items: &[AstNode], cm: ColorMode) -> TreeNode {
460  let mut node_builder = node(DEFAULT_COLOR, cm).line().s(name).end();
461  if items.is_empty() {
462    node_builder.add_child(leaf(cm).line().s("(empty)").end().end());
463  } else {
464    for item in items {
465      node_builder.add_child(ast_node_to_tree(item, cm));
466    }
467  }
468  node_builder.end()
469}
470
471/// Creates a node with single leaf node.
472fn ast_node_and_leaf(name: &str, leaf_caption: &str, cm: ColorMode) -> TreeNode {
473  node(DEFAULT_COLOR, cm).line().s(name).end().child(leaf(cm).line().s(leaf_caption).end().end()).end()
474}
475
476/// Creates a single node with conditional label.
477fn ast_node_and_conditional_label(name: &str, lhs: &AstNode, label_true: &str, label_false: &str, label_flag: bool, cm: ColorMode) -> TreeNode {
478  let name_label = if label_flag { label_true } else { label_false };
479  node(DEFAULT_COLOR, cm).line().s(name).s(name_label).end().child(ast_node_to_tree(lhs, cm)).end()
480}
481
482/// Creates a single node with label.
483fn ast_node_and_label(name: &str, lhs: &AstNode, label: impl AsRef<str>, cm: ColorMode) -> TreeNode {
484  let label = format!(" ({})", label.as_ref());
485  node(DEFAULT_COLOR, cm).line().s(name).s(label).end().child(ast_node_to_tree(lhs, cm)).end()
486}
487
488/// Creates a leaf node.
489fn ast_leaf(leaf_caption: &str, cm: ColorMode) -> TreeNode {
490  leaf(cm).line().s(leaf_caption).end().end()
491}
492
493/// Converts a numeric AST node into string representation used in tree visualisation.
494fn numeric_to_string(before: &str, after: &str, sign: &char, exponent: &str) -> String {
495  let mut output = String::new();
496  let _ = write!(&mut output, "`{before}");
497  if !after.is_empty() {
498    let _ = write!(&mut output, ".{after}");
499  }
500  if !exponent.is_empty() {
501    let _ = write!(&mut output, "e{sign}{exponent}");
502  }
503  let _ = write!(&mut output, "`");
504  output
505}