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>(
73 &self,
74 mut func: F,
75 ) where
76 F: FnMut(&Self) + Clone,
77 {
78 {
79 func(self);
80 };
81
82 match self {
83 Node::Null => {},
84 Node::Bool(_) => {},
85 Node::Number(_) => {},
86 Node::String(_) => {},
87 Node::Pointer => {},
88 Node::Identifier(_) => {},
89 Node::Root => {},
90 Node::Error { node, .. } => {
91 if let Some(n) = node {
92 n.walk(func.clone())
93 }
94 },
95 Node::TemplateString(parts) => {
96 parts.iter().for_each(|n| n.walk(func.clone()))
97 },
98 Node::Array(parts) => {
99 parts.iter().for_each(|n| n.walk(func.clone()))
100 },
101 Node::Object(obj) => obj.iter().for_each(|(k, v)| {
102 k.walk(func.clone());
103 v.walk(func.clone());
104 }),
105 Node::Assignments { list, output } => {
106 list.iter().for_each(|(k, v)| {
107 k.walk(func.clone());
108 v.walk(func.clone());
109 });
110
111 if let Some(output) = output {
112 output.walk(func.clone());
113 }
114 },
115 Node::Closure(closure) => closure.walk(func.clone()),
116 Node::Parenthesized(c) => c.walk(func.clone()),
117 Node::Member { node, property } => {
118 node.walk(func.clone());
119 property.walk(func.clone());
120 },
121 Node::Slice { node, to, from } => {
122 node.walk(func.clone());
123 if let Some(to) = to {
124 to.walk(func.clone());
125 }
126
127 if let Some(from) = from {
128 from.walk(func.clone());
129 }
130 },
131 Node::Interval { left, right, .. } => {
132 left.walk(func.clone());
133 right.walk(func.clone());
134 },
135 Node::Unary { node, .. } => {
136 node.walk(func);
137 },
138 Node::Binary { left, right, .. } => {
139 left.walk(func.clone());
140 right.walk(func.clone());
141 },
142 Node::FunctionCall { arguments, .. } => {
143 arguments.iter().for_each(|n| n.walk(func.clone()));
144 },
145 Node::MethodCall { this, arguments, .. } => {
146 this.walk(func.clone());
147 arguments.iter().for_each(|n| n.walk(func.clone()));
148 },
149 Node::Conditional { on_true, condition, on_false } => {
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(&self) -> Option<AstNodeError> {
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, .. } => {
178 Some(span.clone())
179 },
180 AstNodeError::UnexpectedToken { span, .. } => {
181 Some(span.clone())
182 },
183 AstNodeError::InvalidNumber { span, .. } => Some(span.clone()),
184 AstNodeError::InvalidBoolean { span, .. } => Some(span.clone()),
185 AstNodeError::InvalidProperty { span, .. } => {
186 Some(span.clone())
187 },
188 AstNodeError::MissingToken { position, .. } => {
189 Some((*position as u32, *position as u32))
190 },
191 AstNodeError::Custom { span, .. } => Some(span.clone()),
192 },
193 _ => None,
194 }
195 }
196
197 pub(crate) fn member_key(
198 &self,
199 vec: &mut BumpVec<&'a str>,
200 ) -> Option<()> {
201 match self {
202 Node::Member { node, property } => {
203 node.member_key(vec)?;
204
205 let property_key = match property {
206 Node::String(key) => Some(*key),
207 Node::Root => Some("$root"),
208 _ => None,
209 }?;
210
211 vec.push(property_key);
212 Some(())
213 },
214 Node::Identifier(name) => {
215 vec.push(name);
216 Some(())
217 },
218 Node::Root => {
219 vec.push("$root");
220 Some(())
221 },
222 _ => None,
223 }
224 }
225}
226
227#[derive(Debug, PartialEq, Eq, Clone, Error)]
228pub enum AstNodeError<'a> {
229 #[error("Unknown function `{name}` at ({}, {})", span.0, span.1)]
230 UnknownBuiltIn { name: &'a str, span: (u32, u32) },
231
232 #[error("Unknown method `{name}` at ({}, {})", span.0, span.1)]
233 UnknownMethod { name: &'a str, span: (u32, u32) },
234
235 #[error("Unexpected identifier: {received} at ({}, {}); Expected {expected}.", span.0, span.1)]
236 UnexpectedIdentifier {
237 received: &'a str,
238 expected: &'a str,
239 span: (u32, u32),
240 },
241
242 #[error("Unexpected token: {received} at ({}, {}); Expected {expected}.", span.0, span.1)]
243 UnexpectedToken { received: &'a str, expected: &'a str, span: (u32, u32) },
244
245 #[error("Invalid number: {number} at ({}, {})", span.0, span.1)]
246 InvalidNumber { number: &'a str, span: (u32, u32) },
247
248 #[error("Invalid boolean: {boolean} at ({}, {})", span.0, span.1)]
249 InvalidBoolean { boolean: &'a str, span: (u32, u32) },
250
251 #[error("Invalid property: {property} at ({}, {})", span.0, span.1)]
252 InvalidProperty { property: &'a str, span: (u32, u32) },
253
254 #[error("Missing expected token: {expected} at {position}")]
255 MissingToken { expected: &'a str, position: usize },
256
257 #[error("{message} at ({}, {})", span.0, span.1)]
258 Custom { message: &'a str, span: (u32, u32) },
259}