zen_expression/parser/
ast.rs

1use crate::functions::{FunctionKind, MethodKind};
2use crate::lexer::{Bracket, Operator};
3use bumpalo::collections::Vec as BumpVec;
4use rust_decimal::Decimal;
5use std::cell::Cell;
6use strum_macros::IntoStaticStr;
7use thiserror::Error;
8
9#[derive(Debug, PartialEq, Clone, IntoStaticStr)]
10pub enum Node<'a> {
11    Null,
12    Bool(bool),
13    Number(Decimal),
14    String(&'a str),
15    TemplateString(&'a [&'a Node<'a>]),
16    Pointer,
17    Array(&'a [&'a Node<'a>]),
18    Object(&'a [(&'a Node<'a>, &'a Node<'a>)]),
19    Assignments {
20        list: &'a [(&'a Node<'a>, &'a Node<'a>)],
21        output: Option<&'a Node<'a>>,
22    },
23    Identifier(&'a str),
24    Closure {
25        body: &'a Node<'a>,
26        alias: Option<&'a str>,
27    },
28    Parenthesized(&'a Node<'a>),
29    Root,
30    Member {
31        node: &'a Node<'a>,
32        property: &'a Node<'a>,
33    },
34    Slice {
35        node: &'a Node<'a>,
36        from: Option<&'a Node<'a>>,
37        to: Option<&'a Node<'a>>,
38    },
39    Interval {
40        left: &'a Node<'a>,
41        right: &'a Node<'a>,
42        left_bracket: Bracket,
43        right_bracket: Bracket,
44    },
45    Conditional {
46        condition: &'a Node<'a>,
47        on_true: &'a Node<'a>,
48        on_false: &'a Node<'a>,
49    },
50    Unary {
51        node: &'a Node<'a>,
52        operator: Operator,
53    },
54    Binary {
55        left: &'a Node<'a>,
56        operator: Operator,
57        right: &'a Node<'a>,
58    },
59    FunctionCall {
60        kind: FunctionKind,
61        arguments: &'a [&'a Node<'a>],
62    },
63    MethodCall {
64        kind: MethodKind,
65        this: &'a Node<'a>,
66        arguments: &'a [&'a Node<'a>],
67    },
68    Error {
69        node: Option<&'a Node<'a>>,
70        error: AstNodeError<'a>,
71    },
72}
73
74impl<'a> Node<'a> {
75    pub fn walk<F>(&self, mut func: F)
76    where
77        F: FnMut(&Self) + Clone,
78    {
79        {
80            func(self);
81        };
82
83        match self {
84            Node::Null => {}
85            Node::Bool(_) => {}
86            Node::Number(_) => {}
87            Node::String(_) => {}
88            Node::Pointer => {}
89            Node::Identifier(_) => {}
90            Node::Root => {}
91            Node::Error { node, .. } => {
92                if let Some(n) = node {
93                    n.walk(func.clone())
94                }
95            }
96            Node::TemplateString(parts) => parts.iter().for_each(|n| n.walk(func.clone())),
97            Node::Array(parts) => parts.iter().for_each(|n| n.walk(func.clone())),
98            Node::Object(obj) => obj.iter().for_each(|(k, v)| {
99                k.walk(func.clone());
100                v.walk(func.clone());
101            }),
102            Node::Assignments { list, output } => {
103                list.iter().for_each(|(k, v)| {
104                    k.walk(func.clone());
105                    v.walk(func.clone());
106                });
107
108                if let Some(output) = output {
109                    output.walk(func.clone());
110                }
111            }
112            Node::Closure { body, .. } => body.walk(func.clone()),
113            Node::Parenthesized(c) => c.walk(func.clone()),
114            Node::Member { node, property } => {
115                node.walk(func.clone());
116                property.walk(func.clone());
117            }
118            Node::Slice { node, to, from } => {
119                node.walk(func.clone());
120                if let Some(to) = to {
121                    to.walk(func.clone());
122                }
123
124                if let Some(from) = from {
125                    from.walk(func.clone());
126                }
127            }
128            Node::Interval { left, right, .. } => {
129                left.walk(func.clone());
130                right.walk(func.clone());
131            }
132            Node::Unary { node, .. } => {
133                node.walk(func);
134            }
135            Node::Binary { left, right, .. } => {
136                left.walk(func.clone());
137                right.walk(func.clone());
138            }
139            Node::FunctionCall { arguments, .. } => {
140                arguments.iter().for_each(|n| n.walk(func.clone()));
141            }
142            Node::MethodCall {
143                this, arguments, ..
144            } => {
145                this.walk(func.clone());
146                arguments.iter().for_each(|n| n.walk(func.clone()));
147            }
148            Node::Conditional {
149                on_true,
150                condition,
151                on_false,
152            } => {
153                condition.walk(func.clone());
154                on_true.walk(func.clone());
155                on_false.walk(func.clone());
156            }
157        };
158    }
159
160    pub fn first_error(&'a self) -> Option<AstNodeError<'a>> {
161        let error_cell = Cell::new(None);
162        self.walk(|n| {
163            if let Node::Error { error, .. } = n {
164                error_cell.set(Some(error.clone()))
165            }
166        });
167
168        error_cell.into_inner()
169    }
170
171    pub fn has_error(&self) -> bool {
172        self.first_error().is_some()
173    }
174
175    pub(crate) fn span(&self) -> Option<(u32, u32)> {
176        match self {
177            Node::Error { error, .. } => match error {
178                AstNodeError::UnknownBuiltIn { span, .. } => Some(span.clone()),
179                AstNodeError::UnknownMethod { span, .. } => Some(span.clone()),
180                AstNodeError::UnexpectedIdentifier { span, .. } => Some(span.clone()),
181                AstNodeError::UnexpectedToken { span, .. } => Some(span.clone()),
182                AstNodeError::InvalidNumber { span, .. } => Some(span.clone()),
183                AstNodeError::InvalidBoolean { span, .. } => Some(span.clone()),
184                AstNodeError::InvalidProperty { span, .. } => Some(span.clone()),
185                AstNodeError::MissingToken { position, .. } => {
186                    Some((*position as u32, *position as u32))
187                }
188                AstNodeError::Custom { span, .. } => Some(span.clone()),
189            },
190            _ => None,
191        }
192    }
193
194    pub(crate) fn member_key(&self, vec: &mut BumpVec<&'a str>) -> Option<()> {
195        match self {
196            Node::Member { node, property } => {
197                node.member_key(vec)?;
198
199                let property_key = match property {
200                    Node::String(key) => Some(*key),
201                    Node::Root => Some("$root"),
202                    _ => None,
203                }?;
204
205                vec.push(property_key);
206                Some(())
207            }
208            Node::Identifier(name) => {
209                vec.push(name);
210                Some(())
211            }
212            Node::Root => {
213                vec.push("$root");
214                Some(())
215            }
216            _ => None,
217        }
218    }
219}
220
221#[derive(Debug, PartialEq, Eq, Clone, Error)]
222pub enum AstNodeError<'a> {
223    #[error("Unknown function `{name}` at ({}, {})", span.0, span.1)]
224    UnknownBuiltIn { name: &'a str, span: (u32, u32) },
225
226    #[error("Unknown method `{name}` at ({}, {})", span.0, span.1)]
227    UnknownMethod { name: &'a str, span: (u32, u32) },
228
229    #[error("Unexpected identifier: {received} at ({}, {}); Expected {expected}.", span.0, span.1)]
230    UnexpectedIdentifier {
231        received: &'a str,
232        expected: &'a str,
233        span: (u32, u32),
234    },
235
236    #[error("Unexpected token: {received} at ({}, {}); Expected {expected}.", span.0, span.1)]
237    UnexpectedToken {
238        received: &'a str,
239        expected: &'a str,
240        span: (u32, u32),
241    },
242
243    #[error("Invalid number: {number} at ({}, {})", span.0, span.1)]
244    InvalidNumber { number: &'a str, span: (u32, u32) },
245
246    #[error("Invalid boolean: {boolean} at ({}, {})", span.0, span.1)]
247    InvalidBoolean { boolean: &'a str, span: (u32, u32) },
248
249    #[error("Invalid property: {property} at ({}, {})", span.0, span.1)]
250    InvalidProperty { property: &'a str, span: (u32, u32) },
251
252    #[error("Missing expected token: {expected} at {position}")]
253    MissingToken { expected: &'a str, position: usize },
254
255    #[error("{message} at ({}, {})", span.0, span.1)]
256    Custom { message: &'a str, span: (u32, u32) },
257}