zen_expression/parser/
ast.rs

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}