zen_expression/parser/
ast.rs

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}