fix: unary closure expression (#301)

This commit is contained in:
stefan-gorules
2025-01-20 14:08:13 +01:00
committed by GitHub
parent 17ab3c8977
commit df2a44f8b3
4 changed files with 62 additions and 51 deletions
+32 -26
View File
@@ -313,7 +313,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> {
pub(crate) fn template_string<F>(&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<F>(&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 <Identifier> or <Identifier Expression>
pub(crate) fn identifier<F>(&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<F>(&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<F>(&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<F>(&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<F>(&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<F>(&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,
}
+5 -5
View File
@@ -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))
}
}
+24 -20
View File
@@ -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))
}
}
+1
View File
@@ -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
Can't render this file because it contains an unexpected character in line 4 and column 8.