1use crate::functions::{
2 ClosureFunction, DateMethod, DeprecatedFunction, FunctionKind, InternalFunction, MethodKind,
3};
4use crate::lexer::{Bracket, ComparisonOperator, Identifier, LogicalOperator, Operator, TokenKind};
5use crate::parser::ast::{AstNodeError, Node};
6use crate::parser::constants::{Associativity, BINARY_OPERATORS, UNARY_OPERATORS};
7use crate::parser::parser::{Parser, ParserContext};
8use crate::parser::unary::UnaryNodeBehaviour::CompareWithReference;
9use crate::parser::{NodeMetadata, ParserResult};
10
11#[derive(Debug)]
12pub struct Unary;
13
14const ROOT_NODE: Node<'static> = Node::Identifier("$");
15
16impl<'arena, 'token_ref> Parser<'arena, 'token_ref, Unary> {
17 pub fn parse(&self) -> ParserResult<'arena> {
18 let root = self.root_expression();
19
20 ParserResult {
21 root,
22 is_complete: self.is_done(),
23 metadata: self.node_metadata.clone().map(|t| t.into_inner()),
24 }
25 }
26
27 fn root_expression(&self) -> &'arena Node<'arena> {
28 let mut left_node = self.expression_pair();
29
30 while !self.is_done() {
31 let Some(current_token) = self.current() else {
32 break;
33 };
34
35 let join_operator = match ¤t_token.kind {
36 TokenKind::Operator(Operator::Logical(LogicalOperator::And)) => {
37 Operator::Logical(LogicalOperator::And)
38 }
39 TokenKind::Operator(Operator::Logical(LogicalOperator::Or))
40 | TokenKind::Operator(Operator::Comma) => Operator::Logical(LogicalOperator::Or),
41 _ => {
42 return self.error(AstNodeError::Custom {
43 message: self.bump.alloc_str(
44 format!("Invalid join operator `{}`", current_token.kind).as_str(),
45 ),
46 span: current_token.span,
47 })
48 }
49 };
50
51 self.next();
52 let right_node = self.expression_pair();
53 left_node = self.node(
54 Node::Binary {
55 left: left_node,
56 operator: join_operator,
57 right: right_node,
58 },
59 |h| NodeMetadata {
60 span: h.span(left_node, right_node).unwrap_or_default(),
61 },
62 );
63 }
64
65 left_node
66 }
67
68 fn expression_pair(&self) -> &'arena Node<'arena> {
69 let mut left_node = &ROOT_NODE;
70 let current_token = self.current();
71
72 if let Some(TokenKind::Operator(Operator::Comparison(_))) = self.current_kind() {
73 } else {
75 left_node = self.binary_expression(0, ParserContext::Global);
76 }
77
78 match self.current_kind() {
79 Some(TokenKind::Operator(Operator::Comparison(comparison))) => {
80 self.next();
81 let right_node = self.binary_expression(0, ParserContext::Global);
82 left_node = self.node(
83 Node::Binary {
84 left: left_node,
85 operator: Operator::Comparison(*comparison),
86 right: right_node,
87 },
88 |h| NodeMetadata {
89 span: (
90 current_token.map(|t| t.span.0).unwrap_or_default(),
91 h.metadata(right_node).map(|n| n.span.1).unwrap_or_default(),
92 ),
93 },
94 );
95 }
96 _ => {
97 let behaviour = UnaryNodeBehaviour::from(left_node);
98 match behaviour {
99 CompareWithReference(comparator) => {
100 left_node = self.node(
101 Node::Binary {
102 left: &ROOT_NODE,
103 operator: Operator::Comparison(comparator),
104 right: left_node,
105 },
106 |h| NodeMetadata {
107 span: (
108 current_token.map(|t| t.span.0).unwrap_or_default(),
109 h.metadata(left_node).map(|n| n.span.1).unwrap_or_default(),
110 ),
111 },
112 )
113 }
114 UnaryNodeBehaviour::AsBoolean => {
115 left_node = self.node(
116 Node::FunctionCall {
117 kind: FunctionKind::Internal(InternalFunction::Bool),
118 arguments: self.bump.alloc_slice_clone(&[left_node]),
119 },
120 |h| NodeMetadata {
121 span: (
122 current_token.map(|t| t.span.0).unwrap_or_default(),
123 h.metadata(left_node).map(|n| n.span.1).unwrap_or_default(),
124 ),
125 },
126 )
127 }
128 }
129 }
130 }
131
132 left_node
133 }
134
135 #[cfg_attr(feature = "stack-protection", recursive::recursive)]
136 fn binary_expression(&self, precedence: u8, ctx: ParserContext) -> &'arena Node<'arena> {
137 let mut node_left = self.unary_expression();
138 let Some(mut token) = self.current() else {
139 return node_left;
140 };
141
142 while let TokenKind::Operator(operator) = &token.kind {
143 if self.is_done() {
144 break;
145 }
146
147 if ctx == ParserContext::Global
148 && matches!(
149 operator,
150 Operator::Comma
151 | Operator::Logical(LogicalOperator::And)
152 | Operator::Logical(LogicalOperator::Or)
153 )
154 {
155 break;
156 }
157
158 let Some(op) = BINARY_OPERATORS.get(operator) else {
159 break;
160 };
161
162 if op.precedence < precedence {
163 break;
164 }
165
166 self.next();
167 let node_right = match op.associativity {
168 Associativity::Left => {
169 self.binary_expression(op.precedence + 1, ParserContext::Global)
170 }
171 _ => self.binary_expression(op.precedence, ParserContext::Global),
172 };
173
174 node_left = self.node(
175 Node::Binary {
176 operator: *operator,
177 left: node_left,
178 right: node_right,
179 },
180 |h| NodeMetadata {
181 span: h.span(node_left, node_right).unwrap_or_default(),
182 },
183 );
184
185 let Some(t) = self.current() else {
186 break;
187 };
188 token = t;
189 }
190
191 if precedence == 0 {
192 if let Some(conditional_node) =
193 self.conditional(node_left, |c| self.binary_expression(0, c))
194 {
195 node_left = conditional_node;
196 }
197 }
198
199 node_left
200 }
201
202 fn unary_expression(&self) -> &'arena Node<'arena> {
203 let Some(token) = self.current() else {
204 return self.literal(|c| self.binary_expression(0, c));
205 };
206
207 if self.depth() > 0 && token.kind == TokenKind::Identifier(Identifier::CallbackReference) {
208 self.next();
209
210 let node = self.node(Node::Pointer, |_| NodeMetadata { span: token.span });
211 return self.with_postfix(node, |c| self.binary_expression(0, c));
212 }
213
214 if let TokenKind::Operator(operator) = &token.kind {
215 let Some(unary_operator) = UNARY_OPERATORS.get(operator) else {
216 return self.error(AstNodeError::UnexpectedToken {
217 expected: self.bump.alloc_str("UnaryOperator"),
218 received: self.bump.alloc_str(token.kind.to_string().as_str()),
219 span: token.span,
220 });
221 };
222
223 self.next();
224 let expr = self.binary_expression(unary_operator.precedence, ParserContext::Global);
225 let node = self.node(
226 Node::Unary {
227 operator: *operator,
228 node: expr,
229 },
230 |h| NodeMetadata {
231 span: (
232 token.span.0,
233 h.metadata(expr).map(|n| n.span.1).unwrap_or_default(),
234 ),
235 },
236 );
237
238 return node;
239 }
240
241 if let Some(interval_node) = self.interval(|c| self.binary_expression(0, c)) {
242 return interval_node;
243 }
244
245 if token.kind == TokenKind::Bracket(Bracket::LeftParenthesis) {
246 let p_start = self.current().map(|s| s.span.0);
247
248 self.next();
249 let binary_node = self.binary_expression(0, ParserContext::Global);
250 if let Some(error_node) = self.expect(TokenKind::Bracket(Bracket::RightParenthesis)) {
251 return error_node;
252 };
253
254 let expr = self.node(Node::Parenthesized(binary_node), |_| NodeMetadata {
255 span: (p_start.unwrap_or_default(), self.prev_token_end()),
256 });
257
258 return self.with_postfix(expr, |c| self.binary_expression(0, c));
259 }
260
261 self.literal(|c| self.binary_expression(0, c))
262 }
263}
264
265#[derive(Debug, PartialEq)]
278enum UnaryNodeBehaviour {
279 CompareWithReference(ComparisonOperator),
280 AsBoolean,
281}
282
283impl From<&Node<'_>> for UnaryNodeBehaviour {
284 fn from(value: &Node) -> Self {
285 use ComparisonOperator::*;
286 use UnaryNodeBehaviour::*;
287
288 match value {
289 Node::Null => CompareWithReference(Equal),
290 Node::Root => CompareWithReference(Equal),
291 Node::Bool(_) => CompareWithReference(Equal),
292 Node::Number(_) => CompareWithReference(Equal),
293 Node::String(_) => CompareWithReference(Equal),
294 Node::TemplateString(_) => CompareWithReference(Equal),
295 Node::Object(_) => CompareWithReference(Equal),
296 Node::Pointer => AsBoolean,
297 Node::Array(_) => CompareWithReference(In),
298 Node::Identifier(_) => CompareWithReference(Equal),
299 Node::Closure(_) => AsBoolean,
300 Node::Member { .. } => CompareWithReference(Equal),
301 Node::Slice { .. } => CompareWithReference(In),
302 Node::Interval { .. } => CompareWithReference(In),
303 Node::Conditional {
304 on_true, on_false, ..
305 } => {
306 let a = UnaryNodeBehaviour::from(*on_true);
307 let b = UnaryNodeBehaviour::from(*on_false);
308
309 if a == b {
310 a
311 } else {
312 CompareWithReference(Equal)
313 }
314 }
315 Node::Unary { node, .. } => UnaryNodeBehaviour::from(*node),
316 Node::Parenthesized(n) => UnaryNodeBehaviour::from(*n),
317 Node::Binary {
318 left,
319 operator,
320 right,
321 } => match operator {
322 Operator::Arithmetic(_) => {
323 let a = UnaryNodeBehaviour::from(*left);
324 let b = UnaryNodeBehaviour::from(*right);
325
326 if a == b {
327 a
328 } else {
329 CompareWithReference(Equal)
330 }
331 }
332 Operator::Logical(_) => AsBoolean,
333 Operator::Comparison(_) => AsBoolean,
334 Operator::Range => CompareWithReference(In),
335 Operator::Slice => CompareWithReference(In),
336 Operator::Comma => AsBoolean,
337 Operator::Dot => AsBoolean,
338 Operator::QuestionMark => AsBoolean,
339 },
340 Node::FunctionCall { kind, .. } => match kind {
341 FunctionKind::Internal(i) => match i {
342 InternalFunction::Len => CompareWithReference(Equal),
343 InternalFunction::Upper => CompareWithReference(Equal),
344 InternalFunction::Lower => CompareWithReference(Equal),
345 InternalFunction::Trim => CompareWithReference(Equal),
346 InternalFunction::Abs => CompareWithReference(Equal),
347 InternalFunction::Sum => CompareWithReference(Equal),
348 InternalFunction::Avg => CompareWithReference(Equal),
349 InternalFunction::Min => CompareWithReference(Equal),
350 InternalFunction::Max => CompareWithReference(Equal),
351 InternalFunction::Rand => CompareWithReference(Equal),
352 InternalFunction::Median => CompareWithReference(Equal),
353 InternalFunction::Mode => CompareWithReference(Equal),
354 InternalFunction::Floor => CompareWithReference(Equal),
355 InternalFunction::Ceil => CompareWithReference(Equal),
356 InternalFunction::Round => CompareWithReference(Equal),
357 InternalFunction::Trunc => CompareWithReference(Equal),
358 InternalFunction::String => CompareWithReference(Equal),
359 InternalFunction::Number => CompareWithReference(Equal),
360 InternalFunction::Bool => CompareWithReference(Equal),
361 InternalFunction::Flatten => CompareWithReference(In),
362 InternalFunction::Extract => CompareWithReference(In),
363 InternalFunction::Contains => AsBoolean,
364 InternalFunction::StartsWith => AsBoolean,
365 InternalFunction::EndsWith => AsBoolean,
366 InternalFunction::Matches => AsBoolean,
367 InternalFunction::FuzzyMatch => CompareWithReference(Equal),
368 InternalFunction::Split => CompareWithReference(In),
369 InternalFunction::IsNumeric => AsBoolean,
370 InternalFunction::Keys => CompareWithReference(In),
371 InternalFunction::Values => CompareWithReference(In),
372 InternalFunction::Type => CompareWithReference(Equal),
373 InternalFunction::Date => CompareWithReference(Equal),
374 },
375 FunctionKind::Deprecated(d) => match d {
376 DeprecatedFunction::Date => CompareWithReference(Equal),
377 DeprecatedFunction::Time => CompareWithReference(Equal),
378 DeprecatedFunction::Duration => CompareWithReference(Equal),
379 DeprecatedFunction::Year => CompareWithReference(Equal),
380 DeprecatedFunction::DayOfWeek => CompareWithReference(Equal),
381 DeprecatedFunction::DayOfMonth => CompareWithReference(Equal),
382 DeprecatedFunction::DayOfYear => CompareWithReference(Equal),
383 DeprecatedFunction::WeekOfYear => CompareWithReference(Equal),
384 DeprecatedFunction::MonthOfYear => CompareWithReference(Equal),
385 DeprecatedFunction::MonthString => CompareWithReference(Equal),
386 DeprecatedFunction::DateString => CompareWithReference(Equal),
387 DeprecatedFunction::WeekdayString => CompareWithReference(Equal),
388 DeprecatedFunction::StartOf => CompareWithReference(Equal),
389 DeprecatedFunction::EndOf => CompareWithReference(Equal),
390 },
391 FunctionKind::Closure(c) => match c {
392 ClosureFunction::All => AsBoolean,
393 ClosureFunction::Some => AsBoolean,
394 ClosureFunction::None => AsBoolean,
395 ClosureFunction::One => AsBoolean,
396 ClosureFunction::Filter => CompareWithReference(In),
397 ClosureFunction::Map => CompareWithReference(In),
398 ClosureFunction::FlatMap => CompareWithReference(In),
399 ClosureFunction::Count => CompareWithReference(Equal),
400 },
401 },
402 Node::MethodCall { kind, .. } => match kind {
403 MethodKind::DateMethod(dm) => match dm {
404 DateMethod::Add => CompareWithReference(Equal),
405 DateMethod::Sub => CompareWithReference(Equal),
406 DateMethod::Format => CompareWithReference(Equal),
407 DateMethod::Month => CompareWithReference(Equal),
408 DateMethod::Year => CompareWithReference(Equal),
409 DateMethod::Set => CompareWithReference(Equal),
410 DateMethod::StartOf => CompareWithReference(Equal),
411 DateMethod::EndOf => CompareWithReference(Equal),
412 DateMethod::Diff => CompareWithReference(Equal),
413 DateMethod::Tz => CompareWithReference(Equal),
414 DateMethod::Second => CompareWithReference(Equal),
415 DateMethod::Minute => CompareWithReference(Equal),
416 DateMethod::Hour => CompareWithReference(Equal),
417 DateMethod::Day => CompareWithReference(Equal),
418 DateMethod::DayOfYear => CompareWithReference(Equal),
419 DateMethod::Week => CompareWithReference(Equal),
420 DateMethod::Weekday => CompareWithReference(Equal),
421 DateMethod::Quarter => CompareWithReference(Equal),
422 DateMethod::Timestamp => CompareWithReference(Equal),
423 DateMethod::OffsetName => CompareWithReference(Equal),
424 DateMethod::IsSame => AsBoolean,
425 DateMethod::IsBefore => AsBoolean,
426 DateMethod::IsAfter => AsBoolean,
427 DateMethod::IsSameOrBefore => AsBoolean,
428 DateMethod::IsSameOrAfter => AsBoolean,
429 DateMethod::IsValid => AsBoolean,
430 DateMethod::IsYesterday => AsBoolean,
431 DateMethod::IsToday => AsBoolean,
432 DateMethod::IsTomorrow => AsBoolean,
433 DateMethod::IsLeapYear => AsBoolean,
434 },
435 },
436 Node::Error { .. } => AsBoolean,
437 }
438 }
439}