From df2a44f8b38eee19ffbdf9b59fafd4594680a61e Mon Sep 17 00:00:00 2001 From: stefan-gorules <127550877+stefan-gorules@users.noreply.github.com> Date: Mon, 20 Jan 2025 14:08:13 +0100 Subject: [PATCH] fix: unary closure expression (#301) --- core/expression/src/parser/parser.rs | 58 ++++++++++++++------------ core/expression/src/parser/standard.rs | 10 ++--- core/expression/src/parser/unary.rs | 44 ++++++++++--------- core/expression/tests/data/unary.csv | 1 + 4 files changed, 62 insertions(+), 51 deletions(-) diff --git a/core/expression/src/parser/parser.rs b/core/expression/src/parser/parser.rs index 1a880493..696ae0a2 100644 --- a/core/expression/src/parser/parser.rs +++ b/core/expression/src/parser/parser.rs @@ -313,7 +313,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { pub(crate) fn template_string(&self, expression_parser: F) -> &'arena Node<'arena> where - F: Fn() -> &'arena Node<'arena>, + F: Fn(ParserContext) -> &'arena Node<'arena>, { expect!(self, TokenKind::QuotationMark(QuotationMark::Backtick)); @@ -332,7 +332,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { TokenKind::TemplateString(template) => match template { TemplateString::ExpressionStart => { self.next(); - nodes.push(expression_parser()); + nodes.push(expression_parser(ParserContext::Global)); } TemplateString::ExpressionEnd => { self.next(); @@ -375,7 +375,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { expression_parser: F, ) -> &'arena Node<'arena> where - F: Fn() -> &'arena Node<'arena>, + F: Fn(ParserContext) -> &'arena Node<'arena>, { let Some(postfix_token) = self.current() else { return node; @@ -444,7 +444,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { c = cc; if c.kind != TokenKind::Bracket(Bracket::RightSquareBracket) { - to = Some(expression_parser()); + to = Some(expression_parser(ParserContext::Global)); } expect!(self, TokenKind::Bracket(Bracket::RightSquareBracket)); @@ -455,7 +455,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { ), }) } else { - let from_node = expression_parser(); + let from_node = expression_parser(ParserContext::Global); from = Some(from_node); let Some(cc) = self.current() else { return self.error_with_node( @@ -492,7 +492,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { c = cc; if c.kind != TokenKind::Bracket(Bracket::RightSquareBracket) { - to = Some(expression_parser()); + to = Some(expression_parser(ParserContext::Global)); } expect!(self, TokenKind::Bracket(Bracket::RightSquareBracket)); @@ -537,12 +537,12 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { /// Closure pub(crate) fn closure(&self, expression_parser: F) -> &'arena Node<'arena> where - F: Fn() -> &'arena Node<'arena>, + F: Fn(ParserContext) -> &'arena Node<'arena>, { let start = self.token_start(); self.depth.set(self.depth.get() + 1); - let node = expression_parser(); + let node = expression_parser(ParserContext::Closure); self.depth.set(self.depth.get() - 1); self.node(Node::Closure(node), |_| NodeMetadata { @@ -554,7 +554,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { /// Either or pub(crate) fn identifier(&self, expression_parser: F) -> &'arena Node<'arena> where - F: Fn() -> &'arena Node<'arena>, + F: Fn(ParserContext) -> &'arena Node<'arena>, { let Some(token) = self.current() else { return self.error(AstNodeError::MissingToken { @@ -610,7 +610,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { self.next(); let builtin_node = match builtin.arity() { Arity::Single => { - let arg = expression_parser(); + let arg = expression_parser(ParserContext::Global); self.expect(TokenKind::Bracket(Bracket::RightParenthesis)); Node::BuiltIn { @@ -619,9 +619,9 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { } } Arity::Dual => { - let arg1 = expression_parser(); + let arg1 = expression_parser(ParserContext::Global); self.expect(TokenKind::Operator(Operator::Comma)); - let arg2 = expression_parser(); + let arg2 = expression_parser(ParserContext::Global); self.expect(TokenKind::Bracket(Bracket::RightParenthesis)); Node::BuiltIn { @@ -630,7 +630,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { } } Arity::Closure => { - let arg1 = expression_parser(); + let arg1 = expression_parser(ParserContext::Global); self.expect(TokenKind::Operator(Operator::Comma)); let arg2 = self.closure(&expression_parser); @@ -654,7 +654,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { /// Interval node pub(crate) fn interval(&self, expression_parser: F) -> Option<&'arena Node<'arena>> where - F: Fn() -> &'arena Node<'arena>, + F: Fn(ParserContext) -> &'arena Node<'arena>, { // Performance optimisation: skip if expression does not contain an interval for faster evaluation if !self.has_range_operator { @@ -674,7 +674,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { }; self.next(); - let left = expression_parser(); + let left = expression_parser(ParserContext::Global); if left.has_error() { self.set_position(initial_position); return None; @@ -685,7 +685,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { return None; }; - let right = expression_parser(); + let right = expression_parser(ParserContext::Global); if right.has_error() { self.set_position(initial_position); return None; @@ -717,7 +717,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { /// Array nodes pub(crate) fn array(&self, expression_parser: F) -> &'arena Node<'arena> where - F: Fn() -> &'arena Node<'arena>, + F: Fn(ParserContext) -> &'arena Node<'arena>, { let Some(current_token) = self.current() else { return self.error(AstNodeError::MissingToken { @@ -748,7 +748,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { } } - nodes.push(expression_parser()); + nodes.push(expression_parser(ParserContext::Global)); } expect!(self, TokenKind::Bracket(Bracket::RightSquareBracket)); @@ -765,7 +765,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { pub(crate) fn object(&self, expression_parser: F) -> &'arena Node<'arena> where - F: Fn() -> &'arena Node<'arena>, + F: Fn(ParserContext) -> &'arena Node<'arena>, { let span_start = self.token_start(); expect!(self, TokenKind::Bracket(Bracket::LeftCurlyBracket)); @@ -784,7 +784,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { loop { let key = self.object_key(&expression_parser); expect!(self, TokenKind::Operator(Operator::Slice)); - let value = expression_parser(); + let value = expression_parser(ParserContext::Global); key_value_pairs.push((key, value)); @@ -816,7 +816,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { pub(crate) fn object_key(&self, expression_parser: F) -> &'arena Node<'arena> where - F: Fn() -> &'arena Node<'arena>, + F: Fn(ParserContext) -> &'arena Node<'arena>, { let Some(key_token) = self.current() else { return self.error(AstNodeError::Custom { @@ -861,7 +861,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { TokenKind::Bracket(bracket) => match bracket { Bracket::LeftSquareBracket => { expect!(self, TokenKind::Bracket(Bracket::LeftSquareBracket)); - let token = expression_parser(); + let token = expression_parser(ParserContext::Global); expect!(self, TokenKind::Bracket(Bracket::RightSquareBracket)); token @@ -914,7 +914,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { expression_parser: F, ) -> Option<&'arena Node<'arena>> where - F: Fn() -> &'arena Node<'arena>, + F: Fn(ParserContext) -> &'arena Node<'arena>, { let Some(current_token) = self.current() else { return None; @@ -925,12 +925,12 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { self.next(); - let on_true = expression_parser(); + let on_true = expression_parser(ParserContext::Global); if let Some(error_node) = self.expect(TokenKind::Operator(Operator::Slice)) { return Some(error_node); } - let on_false = expression_parser(); + let on_false = expression_parser(ParserContext::Global); let conditional_node = Node::Conditional { condition, @@ -946,7 +946,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { /// Literal - number, string, array etc. pub(crate) fn literal(&self, expression_parser: F) -> &'arena Node<'arena> where - F: Fn() -> &'arena Node<'arena>, + F: Fn(ParserContext) -> &'arena Node<'arena>, { let Some(current_token) = self.current() else { return self.error(AstNodeError::Custom { @@ -1053,3 +1053,9 @@ impl<'a, 'arena> MetadataHelper<'a, 'arena> { n as *const Node as usize } } + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum ParserContext { + Global, + Closure, +} diff --git a/core/expression/src/parser/standard.rs b/core/expression/src/parser/standard.rs index 0c3ac790..b349d54d 100644 --- a/core/expression/src/parser/standard.rs +++ b/core/expression/src/parser/standard.rs @@ -63,7 +63,7 @@ impl<'arena, 'token_ref> Parser<'arena, 'token_ref, Standard> { if precedence == 0 { if let Some(conditional_node) = - self.conditional(node_left, || self.binary_expression(0)) + self.conditional(node_left, |_| self.binary_expression(0)) { node_left = conditional_node; } @@ -84,7 +84,7 @@ impl<'arena, 'token_ref> Parser<'arena, 'token_ref, Standard> { self.next(); let node = self.node(Node::Pointer, |_| NodeMetadata { span: token.span }); - return self.with_postfix(node, || self.binary_expression(0)); + return self.with_postfix(node, |_| self.binary_expression(0)); } if let TokenKind::Operator(operator) = &token.kind { @@ -114,7 +114,7 @@ impl<'arena, 'token_ref> Parser<'arena, 'token_ref, Standard> { return node; } - if let Some(interval_node) = self.interval(|| self.binary_expression(0)) { + if let Some(interval_node) = self.interval(|_| self.binary_expression(0)) { return interval_node; } @@ -131,9 +131,9 @@ impl<'arena, 'token_ref> Parser<'arena, 'token_ref, Standard> { span: (p_start.unwrap_or_default(), self.prev_token_end()), }); - return self.with_postfix(expr, || self.binary_expression(0)); + return self.with_postfix(expr, |_| self.binary_expression(0)); } - self.literal(|| self.binary_expression(0)) + self.literal(|_| self.binary_expression(0)) } } diff --git a/core/expression/src/parser/unary.rs b/core/expression/src/parser/unary.rs index 8c045b34..1fb3e8be 100644 --- a/core/expression/src/parser/unary.rs +++ b/core/expression/src/parser/unary.rs @@ -2,7 +2,7 @@ use crate::lexer::{Bracket, ComparisonOperator, Identifier, LogicalOperator, Ope use crate::parser::ast::{AstNodeError, Node}; use crate::parser::builtin::BuiltInFunction; use crate::parser::constants::{Associativity, BINARY_OPERATORS, UNARY_OPERATORS}; -use crate::parser::parser::Parser; +use crate::parser::parser::{Parser, ParserContext}; use crate::parser::unary::UnaryNodeBehaviour::CompareWithReference; use crate::parser::{NodeMetadata, ParserResult}; @@ -70,13 +70,13 @@ impl<'arena, 'token_ref> Parser<'arena, 'token_ref, Unary> { if let Some(TokenKind::Operator(Operator::Comparison(_))) = self.current_kind() { // Skips } else { - left_node = self.binary_expression(0); + left_node = self.binary_expression(0, ParserContext::Global); } match self.current_kind() { Some(TokenKind::Operator(Operator::Comparison(comparison))) => { self.next(); - let right_node = self.binary_expression(0); + let right_node = self.binary_expression(0, ParserContext::Global); left_node = self.node( Node::Binary { left: left_node, @@ -130,7 +130,7 @@ impl<'arena, 'token_ref> Parser<'arena, 'token_ref, Unary> { left_node } - fn binary_expression(&self, precedence: u8) -> &'arena Node<'arena> { + fn binary_expression(&self, precedence: u8, ctx: ParserContext) -> &'arena Node<'arena> { let mut node_left = self.unary_expression(); let Some(mut token) = self.current() else { return node_left; @@ -141,12 +141,14 @@ impl<'arena, 'token_ref> Parser<'arena, 'token_ref, Unary> { break; } - if matches!( - operator, - Operator::Comma - | Operator::Logical(LogicalOperator::And) - | Operator::Logical(LogicalOperator::Or) - ) { + if ctx == ParserContext::Global + && matches!( + operator, + Operator::Comma + | Operator::Logical(LogicalOperator::And) + | Operator::Logical(LogicalOperator::Or) + ) + { break; } @@ -160,8 +162,10 @@ impl<'arena, 'token_ref> Parser<'arena, 'token_ref, Unary> { self.next(); let node_right = match op.associativity { - Associativity::Left => self.binary_expression(op.precedence + 1), - _ => self.binary_expression(op.precedence), + Associativity::Left => { + self.binary_expression(op.precedence + 1, ParserContext::Global) + } + _ => self.binary_expression(op.precedence, ParserContext::Global), }; node_left = self.node( @@ -183,7 +187,7 @@ impl<'arena, 'token_ref> Parser<'arena, 'token_ref, Unary> { if precedence == 0 { if let Some(conditional_node) = - self.conditional(node_left, || self.binary_expression(0)) + self.conditional(node_left, |c| self.binary_expression(0, c)) { node_left = conditional_node; } @@ -194,14 +198,14 @@ impl<'arena, 'token_ref> Parser<'arena, 'token_ref, Unary> { fn unary_expression(&self) -> &'arena Node<'arena> { let Some(token) = self.current() else { - return self.literal(|| self.binary_expression(0)); + return self.literal(|c| self.binary_expression(0, c)); }; if self.depth() > 0 && token.kind == TokenKind::Identifier(Identifier::CallbackReference) { self.next(); let node = self.node(Node::Pointer, |_| NodeMetadata { span: token.span }); - return self.with_postfix(node, || self.binary_expression(0)); + return self.with_postfix(node, |c| self.binary_expression(0, c)); } if let TokenKind::Operator(operator) = &token.kind { @@ -214,7 +218,7 @@ impl<'arena, 'token_ref> Parser<'arena, 'token_ref, Unary> { }; self.next(); - let expr = self.binary_expression(unary_operator.precedence); + let expr = self.binary_expression(unary_operator.precedence, ParserContext::Global); let node = self.node( Node::Unary { operator: *operator, @@ -231,7 +235,7 @@ impl<'arena, 'token_ref> Parser<'arena, 'token_ref, Unary> { return node; } - if let Some(interval_node) = self.interval(|| self.binary_expression(0)) { + if let Some(interval_node) = self.interval(|c| self.binary_expression(0, c)) { return interval_node; } @@ -239,7 +243,7 @@ impl<'arena, 'token_ref> Parser<'arena, 'token_ref, Unary> { let p_start = self.current().map(|s| s.span.0); self.next(); - let binary_node = self.binary_expression(0); + let binary_node = self.binary_expression(0, ParserContext::Global); if let Some(error_node) = self.expect(TokenKind::Bracket(Bracket::RightParenthesis)) { return error_node; }; @@ -248,10 +252,10 @@ impl<'arena, 'token_ref> Parser<'arena, 'token_ref, Unary> { span: (p_start.unwrap_or_default(), self.prev_token_end()), }); - return self.with_postfix(expr, || self.binary_expression(0)); + return self.with_postfix(expr, |c| self.binary_expression(0, c)); } - self.literal(|| self.binary_expression(0)) + self.literal(|c| self.binary_expression(0, c)) } } diff --git a/core/expression/tests/data/unary.csv b/core/expression/tests/data/unary.csv index 273f9f3f..c0b413f2 100644 --- a/core/expression/tests/data/unary.csv +++ b/core/expression/tests/data/unary.csv @@ -64,6 +64,7 @@ rand(100) >= 0 and rand(100) <= 100; { "$": true }; true sum([1, 2, 3, 4, 5]) / len([1, 2, 3, 4, 5]); { "$": 3 }; true median([4, 2, 7, 5, 3]); { "$": 4 }; true mode([1, 2, 2, 3, 3, 3, 4, 4, 4, 4]); { "$": 4 }; true +some($, # > 10 and # < 20); { "$": [1, 2, 3, 15] }; true # String expressions 'GB','US';{$: 'US'};true