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}