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