1use crate::functions::{FunctionKind, MethodKind};
2use crate::lexer::{Bracket, Operator};
3use rust_decimal::Decimal;
4use std::cell::Cell;
5use strum_macros::IntoStaticStr;
6use thiserror::Error;
7
8#[derive(Debug, PartialEq, Clone, IntoStaticStr)]
11pub enum Node<'a> {
12 Null,
14 Bool(bool),
16 Number(Decimal),
18 String(&'a str),
20 TemplateString(&'a [&'a Node<'a>]),
22 Pointer,
24 Array(&'a [&'a Node<'a>]),
26 Object(&'a [(&'a Node<'a>, &'a Node<'a>)]),
28 Identifier(&'a str),
30 Closure(&'a Node<'a>),
32 Parenthesized(&'a Node<'a>),
34 Root,
36 Member {
38 node: &'a Node<'a>, property: &'a Node<'a>, },
41 Slice {
43 node: &'a Node<'a>, from: Option<&'a Node<'a>>, to: Option<&'a Node<'a>>, },
47 Interval {
49 left: &'a Node<'a>, right: &'a Node<'a>, left_bracket: Bracket, right_bracket: Bracket, },
54 Conditional {
56 condition: &'a Node<'a>, on_true: &'a Node<'a>, on_false: &'a Node<'a>, },
60 Unary {
62 node: &'a Node<'a>, operator: Operator, },
65 Binary {
67 left: &'a Node<'a>, operator: Operator, right: &'a Node<'a>, },
71 FunctionCall {
73 kind: FunctionKind, arguments: &'a [&'a Node<'a>], },
76 MethodCall {
78 kind: MethodKind, this: &'a Node<'a>, arguments: &'a [&'a Node<'a>], },
82 Error {
84 node: Option<&'a Node<'a>>, error: AstNodeError<'a>, },
87}
88
89impl<'a> Node<'a> {
90 pub fn walk<F>(
93 &self,
94 mut func: F,
95 ) where
96 F: FnMut(&Self) + Clone,
97 {
98 {
100 func(self);
101 };
102
103 match self {
105 Node::Null => {},
107 Node::Bool(_) => {},
108 Node::Number(_) => {},
109 Node::String(_) => {},
110 Node::Pointer => {},
111 Node::Identifier(_) => {},
112 Node::Root => {},
113
114 Node::Error { node, .. } => {
116 if let Some(n) = node {
117 n.walk(func.clone())
118 }
119 },
120
121 Node::TemplateString(parts) => {
123 parts.iter().for_each(|n| n.walk(func.clone()))
124 },
125 Node::Array(parts) => {
126 parts.iter().for_each(|n| n.walk(func.clone()))
127 },
128 Node::Object(obj) => obj.iter().for_each(|(k, v)| {
129 k.walk(func.clone());
130 v.walk(func.clone());
131 }),
132
133 Node::Closure(closure) => closure.walk(func.clone()),
135 Node::Parenthesized(c) => c.walk(func.clone()),
136
137 Node::Member { node, property } => {
139 node.walk(func.clone());
140 property.walk(func.clone());
141 },
142 Node::Slice { node, to, from } => {
143 node.walk(func.clone());
144 if let Some(to) = to {
145 to.walk(func.clone());
146 }
147 if let Some(from) = from {
148 from.walk(func.clone());
149 }
150 },
151 Node::Interval { left, right, .. } => {
152 left.walk(func.clone());
153 right.walk(func.clone());
154 },
155
156 Node::Unary { node, .. } => {
158 node.walk(func);
159 },
160
161 Node::Binary { left, right, .. } => {
163 left.walk(func.clone());
164 right.walk(func.clone());
165 },
166
167 Node::FunctionCall { arguments, .. } => {
169 arguments.iter().for_each(|n| n.walk(func.clone()));
170 },
171
172 Node::MethodCall { this, arguments, .. } => {
174 this.walk(func.clone());
175 arguments.iter().for_each(|n| n.walk(func.clone()));
176 },
177
178 Node::Conditional { on_true, condition, on_false } => {
180 condition.walk(func.clone());
181 on_true.walk(func.clone());
182 on_false.walk(func.clone());
183 },
184 };
185 }
186
187 pub fn first_error(&self) -> Option<AstNodeError> {
190 let error_cell = Cell::new(None);
191 self.walk(|n| {
192 if let Node::Error { error, .. } = n {
193 error_cell.set(Some(error.clone()))
194 }
195 });
196
197 error_cell.into_inner()
198 }
199
200 pub fn has_error(&self) -> bool {
202 self.first_error().is_some()
203 }
204
205 pub(crate) fn span(&self) -> Option<(u32, u32)> {
208 match self {
209 Node::Error { error, .. } => match error {
210 AstNodeError::UnknownBuiltIn { span, .. } => Some(span.clone()),
211 AstNodeError::UnknownMethod { span, .. } => Some(span.clone()),
212 AstNodeError::UnexpectedIdentifier { span, .. } => {
213 Some(span.clone())
214 },
215 AstNodeError::UnexpectedToken { span, .. } => {
216 Some(span.clone())
217 },
218 AstNodeError::InvalidNumber { span, .. } => Some(span.clone()),
219 AstNodeError::InvalidBoolean { span, .. } => Some(span.clone()),
220 AstNodeError::InvalidProperty { span, .. } => {
221 Some(span.clone())
222 },
223 AstNodeError::MissingToken { position, .. } => {
224 Some((*position as u32, *position as u32))
225 },
226 AstNodeError::Custom { span, .. } => Some(span.clone()),
227 },
228 _ => None,
229 }
230 }
231}
232
233#[derive(Debug, PartialEq, Eq, Clone, Error)]
236pub enum AstNodeError<'a> {
237 #[error("Unknown function `{name}` at ({}, {})", span.0, span.1)]
239 UnknownBuiltIn { name: &'a str, span: (u32, u32) },
240
241 #[error("Unknown method `{name}` at ({}, {})", span.0, span.1)]
243 UnknownMethod { name: &'a str, span: (u32, u32) },
244
245 #[error("Unexpected identifier: {received} at ({}, {}); Expected {expected}.", span.0, span.1)]
247 UnexpectedIdentifier {
248 received: &'a str, expected: &'a str, span: (u32, u32), },
252
253 #[error("Unexpected token: {received} at ({}, {}); Expected {expected}.", span.0, span.1)]
255 UnexpectedToken {
256 received: &'a str, expected: &'a str, span: (u32, u32), },
260
261 #[error("Invalid number: {number} at ({}, {})", span.0, span.1)]
263 InvalidNumber { number: &'a str, span: (u32, u32) },
264
265 #[error("Invalid boolean: {boolean} at ({}, {})", span.0, span.1)]
267 InvalidBoolean { boolean: &'a str, span: (u32, u32) },
268
269 #[error("Invalid property: {property} at ({}, {})", span.0, span.1)]
271 InvalidProperty { property: &'a str, span: (u32, u32) },
272
273 #[error("Missing expected token: {expected} at {position}")]
275 MissingToken { expected: &'a str, position: usize },
276
277 #[error("{message} at ({}, {})", span.0, span.1)]
279 Custom { message: &'a str, span: (u32, u32) },
280}