mf_expression/parser/
ast.rs

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