1use crate::functions::FunctionKind;
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 Error {
56 node: Option<&'a Node<'a>>,
57 error: AstNodeError<'a>,
58 },
59}
60
61impl<'a> Node<'a> {
62 pub fn walk<F>(&self, mut func: F)
63 where
64 F: FnMut(&Self) + Clone,
65 {
66 {
67 func(self);
68 };
69
70 match self {
71 Node::Null => {}
72 Node::Bool(_) => {}
73 Node::Number(_) => {}
74 Node::String(_) => {}
75 Node::Pointer => {}
76 Node::Identifier(_) => {}
77 Node::Root => {}
78 Node::Error { node, .. } => {
79 if let Some(n) = node {
80 n.walk(func.clone())
81 }
82 }
83 Node::TemplateString(parts) => parts.iter().for_each(|n| n.walk(func.clone())),
84 Node::Array(parts) => parts.iter().for_each(|n| n.walk(func.clone())),
85 Node::Object(obj) => obj.iter().for_each(|(k, v)| {
86 k.walk(func.clone());
87 v.walk(func.clone());
88 }),
89 Node::Closure(closure) => closure.walk(func.clone()),
90 Node::Parenthesized(c) => c.walk(func.clone()),
91 Node::Member { node, property } => {
92 node.walk(func.clone());
93 property.walk(func.clone());
94 }
95 Node::Slice { node, to, from } => {
96 node.walk(func.clone());
97 if let Some(to) = to {
98 to.walk(func.clone());
99 }
100
101 if let Some(from) = from {
102 from.walk(func.clone());
103 }
104 }
105 Node::Interval { left, right, .. } => {
106 left.walk(func.clone());
107 right.walk(func.clone());
108 }
109 Node::Unary { node, .. } => {
110 node.walk(func);
111 }
112 Node::Binary { left, right, .. } => {
113 left.walk(func.clone());
114 right.walk(func.clone());
115 }
116 Node::FunctionCall { arguments, .. } => {
117 arguments.iter().for_each(|n| n.walk(func.clone()));
118 }
119 Node::Conditional {
120 on_true,
121 condition,
122 on_false,
123 } => {
124 condition.walk(func.clone());
125 on_true.walk(func.clone());
126 on_false.walk(func.clone());
127 }
128 };
129 }
130
131 pub fn first_error(&self) -> Option<AstNodeError> {
132 let error_cell = Cell::new(None);
133 self.walk(|n| {
134 if let Node::Error { error, .. } = n {
135 error_cell.set(Some(error.clone()))
136 }
137 });
138
139 error_cell.into_inner()
140 }
141
142 pub fn has_error(&self) -> bool {
143 self.first_error().is_some()
144 }
145
146 pub(crate) fn span(&self) -> Option<(u32, u32)> {
147 match self {
148 Node::Error { error, .. } => match error {
149 AstNodeError::UnknownBuiltIn { span, .. } => Some(span.clone()),
150 AstNodeError::UnexpectedIdentifier { span, .. } => Some(span.clone()),
151 AstNodeError::UnexpectedToken { span, .. } => Some(span.clone()),
152 AstNodeError::InvalidNumber { span, .. } => Some(span.clone()),
153 AstNodeError::InvalidBoolean { span, .. } => Some(span.clone()),
154 AstNodeError::InvalidProperty { span, .. } => Some(span.clone()),
155 AstNodeError::MissingToken { position, .. } => {
156 Some((*position as u32, *position as u32))
157 }
158 AstNodeError::Custom { span, .. } => Some(span.clone()),
159 },
160 _ => None,
161 }
162 }
163}
164
165#[derive(Debug, PartialEq, Eq, Clone, Error)]
166pub enum AstNodeError<'a> {
167 #[error("Unknown built in: {name} at ({}, {})", span.0, span.1)]
168 UnknownBuiltIn { name: &'a str, span: (u32, u32) },
169
170 #[error("Unexpected identifier: {received} at ({}, {}); Expected {expected}.", span.0, span.1)]
171 UnexpectedIdentifier {
172 received: &'a str,
173 expected: &'a str,
174 span: (u32, u32),
175 },
176
177 #[error("Unexpected token: {received} at ({}, {}); Expected {expected}.", span.0, span.1)]
178 UnexpectedToken {
179 received: &'a str,
180 expected: &'a str,
181 span: (u32, u32),
182 },
183
184 #[error("Invalid number: {number} at ({}, {})", span.0, span.1)]
185 InvalidNumber { number: &'a str, span: (u32, u32) },
186
187 #[error("Invalid boolean: {boolean} at ({}, {})", span.0, span.1)]
188 InvalidBoolean { boolean: &'a str, span: (u32, u32) },
189
190 #[error("Invalid property: {property} at ({}, {})", span.0, span.1)]
191 InvalidProperty { property: &'a str, span: (u32, u32) },
192
193 #[error("Missing expected token: {expected} at {position}")]
194 MissingToken { expected: &'a str, position: usize },
195
196 #[error("{message} at ({}, {})", span.0, span.1)]
197 Custom { message: &'a str, span: (u32, u32) },
198}