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}