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