diff --git a/core/engine/src/handler/table/zen.rs b/core/engine/src/handler/table/zen.rs index a9f20046..732b900e 100644 --- a/core/engine/src/handler/table/zen.rs +++ b/core/engine/src/handler/table/zen.rs @@ -150,18 +150,18 @@ impl<'a> DecisionTableHandler<'a> { if let Some(description) = rule.get("_description") { expressions.insert("_description".to_string(), description.clone()); } - + for input in &content.inputs { let rule_value = rule.get(input.id.as_str())?; - let mut input_identifier = input.id.clone(); - if let Some(input_field) = &input.field { - input_identifier = format!("{input_field}[{input_identifier}]"); + let Some(input_field) = &input.field else { + continue; + }; + + if let Some(reference) = self.isolate.get_reference(input_field.as_str()) { + reference_map.insert(input_field.clone(), reference); } - - if let Some(reference) = self.isolate.get_reference(input_identifier.as_str()) { - reference_map.insert(input_identifier.clone(), reference); - } - + + let input_identifier = format!("{input_field}[{}]", &input.id); expressions.insert(input_identifier, rule_value.clone()); } diff --git a/core/expression/src/compiler/compiler.rs b/core/expression/src/compiler/compiler.rs index 8a39867a..13209453 100644 --- a/core/expression/src/compiler/compiler.rs +++ b/core/expression/src/compiler/compiler.rs @@ -132,6 +132,7 @@ impl<'arena, 'bytecode_ref> CompilerInner<'arena, 'bytecode_ref> { } Node::Identifier(v) => Ok(self.emit(Opcode::FetchEnv(v))), Node::Closure(v) => self.compile_node(v), + Node::Parenthesized(v) => self.compile_node(v), Node::Member { node, property } => { self.compile_node(node)?; self.compile_node(property)?; @@ -588,7 +589,7 @@ impl<'arena, 'bytecode_ref> CompilerInner<'arena, 'bytecode_ref> { Ok(self.emit(Opcode::End)) } }, - Node::Error(_) => Err(CompilerError::UnexpectedErrorNode), + Node::Error { .. } => Err(CompilerError::UnexpectedErrorNode), } } } diff --git a/core/expression/src/intellisense/mod.rs b/core/expression/src/intellisense/mod.rs index aeae964e..e84f7503 100644 --- a/core/expression/src/intellisense/mod.rs +++ b/core/expression/src/intellisense/mod.rs @@ -63,7 +63,10 @@ impl<'arena> IntelliSense<'arena> { let typ = type_data.get_type(node); r.push(IntelliSenseToken { - span: metadata.get(&addr).map(|s| s.span).unwrap_or_default(), + span: node + .span() + .or_else(|| metadata.get(&addr).map(|s| s.span)) + .unwrap_or_default(), node_kind: node.into(), error: typ.map(|t| t.error.clone()).flatten(), kind: typ diff --git a/core/expression/src/intellisense/types/provider.rs b/core/expression/src/intellisense/types/provider.rs index ea445359..d3af6275 100644 --- a/core/expression/src/intellisense/types/provider.rs +++ b/core/expression/src/intellisense/types/provider.rs @@ -229,11 +229,11 @@ impl TypesProvider { match operator { Operator::Arithmetic(arith) => match arith { - ArithmeticOperator::Add => match (left_type.kind.as_ref(), right_type.kind.as_ref()) { + ArithmeticOperator::Add => match (left_type.omit_const(), right_type.omit_const()) { (VariableType::Number, VariableType::Number) => V(VariableType::Number), (VariableType::String, VariableType::String) => V(VariableType::String), - (VariableType::Any, _) => V(VariableType::Any), - (_, VariableType::Any) => V(VariableType::Any), + (VariableType::Any, VariableType::Number | VariableType::String) => V(VariableType::Any), + (VariableType::Number | VariableType::String, VariableType::Any) => V(VariableType::Any), _ => Error(format!( "Operator `{operator}` cannot be applied to types `{left_type}` and `{right_type}`." )), @@ -242,10 +242,8 @@ impl TypesProvider { | ArithmeticOperator::Multiply | ArithmeticOperator::Divide | ArithmeticOperator::Modulus - | ArithmeticOperator::Power => match (left_type.kind.as_ref(), &right_type.kind.as_ref()) { - (VariableType::Number, VariableType::Number) => V(VariableType::Number), - (VariableType::Any, _) => V(VariableType::Number), - (_, VariableType::Any) => V(VariableType::Number), + | ArithmeticOperator::Power => match (left_type.omit_const(), right_type.omit_const()) { + (VariableType::Number | VariableType::Any, VariableType::Number | VariableType::Any) => V(VariableType::Number), _ => Error(format!( "Operator `{operator}` cannot be applied to types `{left_type}` and `{right_type}`." )), @@ -253,10 +251,8 @@ impl TypesProvider { }, Operator::Logical(l) => match l { LogicalOperator::And | LogicalOperator::Or | LogicalOperator::Not => { - match (left_type.kind.as_ref(), &right_type.kind.as_ref()) { - (VariableType::Bool, VariableType::Bool) => V(VariableType::Bool), - (VariableType::Any, _) => V(VariableType::Bool), - (_, VariableType::Any) => V(VariableType::Bool), + match (left_type.omit_const(), right_type.omit_const()) { + (VariableType::Bool | VariableType::Any, VariableType::Bool | VariableType::Any) => V(VariableType::Bool), _ => Error(format!( "Operator `{operator}` cannot be applied to types `{left_type}` and `{right_type}`." )), @@ -270,10 +266,8 @@ impl TypesProvider { ComparisonOperator::LessThan | ComparisonOperator::GreaterThan | ComparisonOperator::LessThanOrEqual - | ComparisonOperator::GreaterThanOrEqual => match (left_type.kind.as_ref(), right_type.kind.as_ref()) { - (VariableType::Number, VariableType::Number) => V(VariableType::Bool), - (VariableType::Any, _) => V(VariableType::Bool), - (_, VariableType::Any) => V(VariableType::Bool), + | ComparisonOperator::GreaterThanOrEqual => match (left_type.omit_const(), right_type.omit_const()) { + (VariableType::Number | VariableType::Any, VariableType::Number | VariableType::Any) => V(VariableType::Bool), _ => Error(format!( "Operator `{operator}` cannot be applied to types `{left_type}` and `{right_type}`." )), @@ -694,7 +688,20 @@ impl TypesProvider { } } Node::Closure(c) => self.determine(c, scope.clone(), false), - Node::Error(_) => V(VariableType::Any), + Node::Parenthesized(c) => self.determine(c, scope.clone(), false), + Node::Error { node, error } => match node { + None => TypeInfo { + kind: Rc::new(VariableType::Any), + error: Some(error.to_string()), + }, + Some(n) => { + let typ = self.determine(n, scope.clone(), false); + TypeInfo { + kind: typ.kind, + error: Some(error.to_string()), + } + } + }, }; self.set_type(node, node_type.clone()); diff --git a/core/expression/src/parser/ast.rs b/core/expression/src/parser/ast.rs index 5c8ba8a7..36bb4fa9 100644 --- a/core/expression/src/parser/ast.rs +++ b/core/expression/src/parser/ast.rs @@ -17,6 +17,7 @@ pub enum Node<'a> { Object(&'a [(&'a Node<'a>, &'a Node<'a>)]), Identifier(&'a str), Closure(&'a Node<'a>), + Parenthesized(&'a Node<'a>), Root, Member { node: &'a Node<'a>, @@ -51,7 +52,10 @@ pub enum Node<'a> { kind: BuiltInFunction, arguments: &'a [&'a Node<'a>], }, - Error(AstNodeError), + Error { + node: Option<&'a Node<'a>>, + error: AstNodeError, + }, } impl<'a> Node<'a> { @@ -64,7 +68,6 @@ impl<'a> Node<'a> { }; match self { - Node::Error(_) => {} Node::Null => {} Node::Bool(_) => {} Node::Number(_) => {} @@ -72,6 +75,11 @@ impl<'a> Node<'a> { Node::Pointer => {} Node::Identifier(_) => {} Node::Root => {} + Node::Error { node, .. } => { + if let Some(n) = node { + n.walk(func.clone()) + } + } Node::TemplateString(parts) => parts.iter().for_each(|n| n.walk(func.clone())), Node::Array(parts) => parts.iter().for_each(|n| n.walk(func.clone())), Node::Object(obj) => obj.iter().for_each(|(k, v)| { @@ -79,6 +87,7 @@ impl<'a> Node<'a> { v.walk(func.clone()); }), Node::Closure(closure) => closure.walk(func.clone()), + Node::Parenthesized(c) => c.walk(func.clone()), Node::Member { node, property } => { node.walk(func.clone()); property.walk(func.clone()); @@ -120,19 +129,37 @@ impl<'a> Node<'a> { } pub fn first_error(&self) -> Option { - let error = Cell::new(None); + let error_cell = Cell::new(None); self.walk(|n| { - if let Node::Error(err) = n { - error.set(Some(err.clone())) + if let Node::Error { error, .. } = n { + error_cell.set(Some(error.clone())) } }); - error.into_inner() + error_cell.into_inner() } pub fn has_error(&self) -> bool { self.first_error().is_some() } + + pub(crate) fn span(&self) -> Option<(u32, u32)> { + match self { + Node::Error { error, .. } => match error { + AstNodeError::UnknownBuiltIn { span, .. } => Some(span.clone()), + AstNodeError::UnexpectedIdentifier { span, .. } => Some(span.clone()), + AstNodeError::UnexpectedToken { span, .. } => Some(span.clone()), + AstNodeError::InvalidNumber { span, .. } => Some(span.clone()), + AstNodeError::InvalidBoolean { span, .. } => Some(span.clone()), + AstNodeError::InvalidProperty { span, .. } => Some(span.clone()), + AstNodeError::MissingToken { position, .. } => { + Some((*position as u32, *position as u32)) + } + AstNodeError::Custom { span, .. } => Some(span.clone()), + }, + _ => None, + } + } } #[derive(Debug, PartialEq, Eq, Clone, Error)] @@ -168,7 +195,4 @@ pub enum AstNodeError { #[error("{message} at ({}, {})", span.0, span.1)] Custom { message: String, span: (u32, u32) }, - - #[error("Invalid")] - Invalid, } diff --git a/core/expression/src/parser/parser.rs b/core/expression/src/parser/parser.rs index e2137e54..5c601488 100644 --- a/core/expression/src/parser/parser.rs +++ b/core/expression/src/parser/parser.rs @@ -19,6 +19,14 @@ use crate::parser::standard::Standard; use crate::parser::unary::Unary; use crate::parser::NodeMetadata; +macro_rules! expect { + ($self:ident, $token:expr) => { + if let Some(error_node) = $self.expect($token) { + return error_node; + } + }; +} + #[derive(Debug)] pub struct BaseParser; @@ -90,16 +98,6 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { self } - fn get_metadata(&self, node: &'arena Node<'arena>) -> Option { - let Some(node_metadata) = &self.node_metadata else { - return None; - }; - - let nm = node_metadata.borrow(); - let address = node as *const Node as usize; - - nm.get(&address).cloned() - } pub(crate) fn current(&self) -> Option<&Token<'arena>> { self.current.get() } @@ -115,6 +113,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { } } + #[allow(dead_code)] fn token_end(&self) -> u32 { match self.current() { None => self.tokens.last().map(|t| t.span.1).unwrap_or_default(), @@ -122,7 +121,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { } } - fn prev_token_end(&self) -> u32 { + pub(crate) fn prev_token_end(&self) -> u32 { match self.tokens.get(self.position() - 1) { None => self.token_start(), Some(t) => t.span.1, @@ -172,8 +171,23 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { } pub(crate) fn error(&self, error: AstNodeError) -> &'arena Node<'arena> { - // TODO - self.node(Node::Error(error), |_| NodeMetadata { span: (0, 0) }) + self.node(Node::Error { error, node: None }, |_| NodeMetadata { + span: (self.prev_token_end(), self.prev_token_end()), + }) + } + + pub(crate) fn error_with_node( + &self, + error: AstNodeError, + node: &'arena Node<'arena>, + ) -> &'arena Node<'arena> { + self.node( + Node::Error { + error, + node: Some(node), + }, + |_| NodeMetadata { span: (0, 0) }, + ) } pub(crate) fn next(&self) { @@ -260,10 +274,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { } pub(crate) fn simple_string(&self, quote_mark: &QuotationMark) -> &'arena Node<'arena> { - if let Some(error_node) = self.expect(TokenKind::QuotationMark(quote_mark.clone())) { - return error_node; - } - + expect!(self, TokenKind::QuotationMark(quote_mark.clone())); let string_value = self.current(); let error_literal = self.expect(TokenKind::Literal); @@ -273,16 +284,24 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { .or(error_mark_end) .or(string_value .map(|t| self.node(Node::String(t.value), |_| NodeMetadata { span: t.span }))) - .unwrap_or_else(|| self.error(AstNodeError::Invalid)) + .unwrap_or_else(|| { + self.error(AstNodeError::Custom { + message: format!( + "Failed to parse string `{}`", + string_value.map(|s| s.value).unwrap_or_default() + ), + span: string_value + .map(|s| s.span) + .unwrap_or((self.prev_token_end(), self.prev_token_end())), + }) + }) } pub(crate) fn template_string(&self, expression_parser: F) -> &'arena Node<'arena> where F: Fn() -> &'arena Node<'arena>, { - if let Some(error_node) = self.expect(TokenKind::QuotationMark(QuotationMark::Backtick)) { - return error_node; - } + expect!(self, TokenKind::QuotationMark(QuotationMark::Backtick)); let Some(mut current_token) = self.current() else { return self.error(AstNodeError::MissingToken { @@ -330,10 +349,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { } } - if let Some(err) = self.expect(TokenKind::QuotationMark(QuotationMark::Backtick)) { - return err; - }; - + expect!(self, TokenKind::QuotationMark(QuotationMark::Backtick)); self.node(Node::TemplateString(nodes.into_bump_slice()), |_| { NodeMetadata { span } }) @@ -351,7 +367,6 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { return node; }; - let start_token = postfix_token; let postfix_kind = PostfixKind::from(postfix_token); let processed_token = match postfix_kind { @@ -362,13 +377,22 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { self.next(); let property = match property_token { - None => self.error(AstNodeError::Invalid), + None => self.error_with_node( + AstNodeError::Custom { + message: "Expected a property".to_string(), + span: (self.prev_token_end(), self.prev_token_end()), + }, + node, + ), Some(t) => match is_valid_property(t) { true => self.node(Node::String(t.value), |_| NodeMetadata { span: t.span }), - false => self.error(AstNodeError::InvalidProperty { - property: t.value.to_string(), - span: t.span, - }), + false => self.error_with_node( + AstNodeError::InvalidProperty { + property: t.value.to_string(), + span: t.span, + }, + node, + ), }, }; @@ -382,14 +406,26 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { let mut to: Option<&'arena Node<'arena>> = None; let Some(mut c) = self.current() else { - return self.error(AstNodeError::Invalid); + return self.error_with_node( + AstNodeError::Custom { + message: "Expected a property".to_string(), + span: (self.prev_token_end(), self.prev_token_end()), + }, + node, + ); }; if c.kind == TokenKind::Operator(Operator::Slice) { self.next(); let Some(cc) = self.current() else { - return self.error(AstNodeError::Invalid); + return self.error_with_node( + AstNodeError::Custom { + message: "Unexpected token".to_string(), + span: (self.prev_token_end(), self.prev_token_end()), + }, + node, + ); }; c = cc; @@ -397,7 +433,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { to = Some(expression_parser()); } - self.expect(TokenKind::Bracket(Bracket::RightSquareBracket)); + expect!(self, TokenKind::Bracket(Bracket::RightSquareBracket)); self.node(Node::Slice { node, to, from }, |h| NodeMetadata { span: ( h.metadata(node).map(|m| m.span.0).unwrap_or_default(), @@ -405,16 +441,39 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { ), }) } else { - from = Some(expression_parser()); + let from_node = expression_parser(); + from = Some(from_node); let Some(cc) = self.current() else { - return self.error(AstNodeError::Invalid); + return self.error_with_node( + AstNodeError::Custom { + message: "Unexpected token".to_string(), + span: (self.prev_token_end(), self.prev_token_end()), + }, + self.node( + Node::Member { + node, + property: from_node, + }, + |h| NodeMetadata { + span: h.span(node, from_node).unwrap_or_default(), + }, + ), + ); }; c = cc; if c.kind == TokenKind::Operator(Operator::Slice) { self.next(); let Some(cc) = self.current() else { - return self.error(AstNodeError::Invalid); + return self.error_with_node( + AstNodeError::Custom { + message: "Invalid slice syntax".to_string(), + span: (self.prev_token_end(), self.prev_token_end()), + }, + self.node(Node::Slice { node, from, to }, |h| NodeMetadata { + span: h.span(node, from_node).unwrap_or_default(), + }), + ); }; c = cc; @@ -422,21 +481,35 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { to = Some(expression_parser()); } - self.expect(TokenKind::Bracket(Bracket::RightSquareBracket)); - self.node(Node::Slice { node, from, to }, |_| NodeMetadata { - span: (start_token.span.0, self.prev_token_end()), + expect!(self, TokenKind::Bracket(Bracket::RightSquareBracket)); + self.node(Node::Slice { node, from, to }, |h| NodeMetadata { + span: ( + h.metadata(node).map(|m| m.span.0).unwrap_or_default(), + self.prev_token_end(), + ), }) } else { // Slice operator [:] was not found, // it should be just an index node. - self.expect(TokenKind::Bracket(Bracket::RightSquareBracket)); + expect!(self, TokenKind::Bracket(Bracket::RightSquareBracket)); self.node( Node::Member { node, - property: from.unwrap_or_else(|| self.error(AstNodeError::Invalid)), + property: from.unwrap_or_else(|| { + return self.error_with_node( + AstNodeError::Custom { + message: "Invalid index property".to_string(), + span: (self.prev_token_end(), self.prev_token_end()), + }, + node, + ); + }), }, - |_| NodeMetadata { - span: (start_token.span.0, self.prev_token_end()), + |h| NodeMetadata { + span: ( + h.metadata(node).map(|m| m.span.0).unwrap_or_default(), + self.prev_token_end(), + ), }, ) } @@ -481,14 +554,18 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { // ok } _ => { - return self.node(Node::Error(AstNodeError::Invalid), |_| NodeMetadata { + return self.error(AstNodeError::Custom { + message: format!("Expected an `identifier`, received `{}`.", token.kind), span: token.span, - }) + }); } } let Some(identifier_token) = self.current() else { - return self.error(AstNodeError::Invalid); + return self.error(AstNodeError::Custom { + message: "Expected an `identifier`.".to_string(), + span: (self.prev_token_end(), self.prev_token_end()), + }); }; self.next(); @@ -540,6 +617,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { } Arity::Closure => { let arg1 = expression_parser(); + self.expect(TokenKind::Operator(Operator::Comma)); let arg2 = self.closure(&expression_parser); self.expect(TokenKind::Bracket(Bracket::RightParenthesis)); @@ -648,7 +726,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { == Some(TokenKind::Bracket(Bracket::RightSquareBracket))) { if !nodes.is_empty() { - self.expect(TokenKind::Operator(Operator::Comma)); + expect!(self, TokenKind::Operator(Operator::Comma)); if self.current().map(|t| t.kind) == Some(TokenKind::Bracket(Bracket::RightSquareBracket)) { @@ -659,7 +737,8 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { nodes.push(expression_parser()); } - self.expect(TokenKind::Bracket(Bracket::RightSquareBracket)); + expect!(self, TokenKind::Bracket(Bracket::RightSquareBracket)); + let node = Node::Array(nodes.into_bump_slice()); self.with_postfix( @@ -675,9 +754,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { F: Fn() -> &'arena Node<'arena>, { let span_start = self.token_start(); - if let Some(err_node) = self.expect(TokenKind::Bracket(Bracket::LeftCurlyBracket)) { - return err_node; - }; + expect!(self, TokenKind::Bracket(Bracket::LeftCurlyBracket)); let mut key_value_pairs = BumpVec::new_in(self.bump); if let Some(TokenKind::Bracket(Bracket::RightCurlyBracket)) = self.current().map(|t| t.kind) @@ -692,7 +769,7 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { loop { let key = self.object_key(&expression_parser); - self.expect(TokenKind::Operator(Operator::Slice)); + expect!(self, TokenKind::Operator(Operator::Slice)); let value = expression_parser(); key_value_pairs.push((key, value)); @@ -703,14 +780,19 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { match current_token.kind { TokenKind::Operator(Operator::Comma) => { - self.expect(TokenKind::Operator(Operator::Comma)); + expect!(self, TokenKind::Operator(Operator::Comma)); } TokenKind::Bracket(Bracket::RightCurlyBracket) => break, - _ => return self.error(AstNodeError::Invalid), + _ => { + return self.error(AstNodeError::Custom { + message: "Invalid object syntax".to_string(), + span: current_token.span, + }) + } } } - self.expect(TokenKind::Bracket(Bracket::RightCurlyBracket)); + expect!(self, TokenKind::Bracket(Bracket::RightCurlyBracket)); self.node(Node::Object(key_value_pairs.into_bump_slice()), |_| { NodeMetadata { span: (span_start, self.prev_token_end()), @@ -723,7 +805,10 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { F: Fn() -> &'arena Node<'arena>, { let Some(key_token) = self.current() else { - return self.error(AstNodeError::Invalid); + return self.error(AstNodeError::Custom { + message: "Expected an object key".to_string(), + span: (self.prev_token_end(), self.prev_token_end()), + }); }; let key = match key_token.kind { @@ -761,9 +846,9 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { } TokenKind::Bracket(bracket) => match bracket { Bracket::LeftSquareBracket => { - self.expect(TokenKind::Bracket(Bracket::LeftSquareBracket)); + expect!(self, TokenKind::Bracket(Bracket::LeftSquareBracket)); let token = expression_parser(); - self.expect(TokenKind::Bracket(Bracket::RightSquareBracket)); + expect!(self, TokenKind::Bracket(Bracket::RightSquareBracket)); token } @@ -822,7 +907,10 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { self.next(); let on_true = expression_parser(); - self.expect(TokenKind::Operator(Operator::Slice)); + if let Some(error_node) = self.expect(TokenKind::Operator(Operator::Slice)) { + return Some(error_node); + } + let on_false = expression_parser(); let conditional_node = Node::Conditional { @@ -842,7 +930,10 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { F: Fn() -> &'arena Node<'arena>, { let Some(current_token) = self.current() else { - return self.error(AstNodeError::Invalid); + return self.error(AstNodeError::Custom { + message: "Expected a literal".to_string(), + span: (self.prev_token_end(), self.prev_token_end()), + }); }; match ¤t_token.kind { @@ -862,9 +953,14 @@ impl<'arena, 'token_ref, Flavor> Parser<'arena, 'token_ref, Flavor> { TokenKind::Bracket(bracket) => match bracket { Bracket::LeftParenthesis | Bracket::RightParenthesis - | Bracket::RightSquareBracket => self - .interval(&expression_parser) - .unwrap_or_else(|| self.error(AstNodeError::Invalid)), + | Bracket::RightSquareBracket => { + self.interval(&expression_parser).unwrap_or_else(|| { + self.error(AstNodeError::Custom { + message: "Invalid syntax".to_string(), + span: (self.prev_token_end(), self.prev_token_end()), + }) + }) + } Bracket::LeftSquareBracket => self .interval(&expression_parser) .unwrap_or_else(|| self.array(&expression_parser)), diff --git a/core/expression/src/parser/standard.rs b/core/expression/src/parser/standard.rs index db87eb08..7095c2ba 100644 --- a/core/expression/src/parser/standard.rs +++ b/core/expression/src/parser/standard.rs @@ -74,7 +74,10 @@ impl<'arena, 'token_ref> Parser<'arena, 'token_ref, Standard> { fn unary_expression(&self) -> &'arena Node<'arena> { let Some(token) = self.current() else { - return self.error(AstNodeError::Invalid); + return self.error(AstNodeError::Custom { + message: "Unexpected end of unary expression".to_string(), + span: (self.prev_token_end(), self.prev_token_end()), + }); }; if self.depth() > 0 && token.kind == TokenKind::Identifier(Identifier::CallbackReference) { @@ -116,9 +119,18 @@ impl<'arena, 'token_ref> Parser<'arena, 'token_ref, Standard> { } if token.kind == TokenKind::Bracket(Bracket::LeftParenthesis) { + let p_start = self.current().map(|s| s.span.0); + self.next(); - let expr = self.binary_expression(0); - self.expect(TokenKind::Bracket(Bracket::RightParenthesis)); + let binary_node = self.binary_expression(0); + if let Some(error_node) = self.expect(TokenKind::Bracket(Bracket::RightParenthesis)) { + return error_node; + }; + + let expr = self.node(Node::Parenthesized(binary_node), |_| NodeMetadata { + span: (p_start.unwrap_or_default(), self.prev_token_end()), + }); + return self.with_postfix(expr, || self.binary_expression(0)); } diff --git a/core/expression/src/parser/unary.rs b/core/expression/src/parser/unary.rs index 4f72b3cb..f7fbc5cb 100644 --- a/core/expression/src/parser/unary.rs +++ b/core/expression/src/parser/unary.rs @@ -36,7 +36,12 @@ impl<'arena, 'token_ref> Parser<'arena, 'token_ref, Unary> { } TokenKind::Operator(Operator::Logical(LogicalOperator::Or)) | TokenKind::Operator(Operator::Comma) => Operator::Logical(LogicalOperator::Or), - _ => return self.error(AstNodeError::Invalid), + _ => { + return self.error(AstNodeError::Custom { + message: format!("Invalid join operator `{}`", current_token.kind), + span: current_token.span, + }) + } }; self.next(); @@ -208,9 +213,18 @@ impl<'arena, 'token_ref> Parser<'arena, 'token_ref, Unary> { } if token.kind == TokenKind::Bracket(Bracket::LeftParenthesis) { + let p_start = self.current().map(|s| s.span.0); + self.next(); - let expr = self.binary_expression(0); - self.expect(TokenKind::Bracket(Bracket::RightParenthesis)); + let binary_node = self.binary_expression(0); + if let Some(error_node) = self.expect(TokenKind::Bracket(Bracket::RightParenthesis)) { + return error_node; + }; + + let expr = self.node(Node::Parenthesized(binary_node), |_| NodeMetadata { + span: (p_start.unwrap_or_default(), self.prev_token_end()), + }); + return self.with_postfix(expr, || self.binary_expression(0)); } @@ -269,6 +283,7 @@ impl From<&Node<'_>> for UnaryNodeBehaviour { } } Node::Unary { node, .. } => UnaryNodeBehaviour::from(*node), + Node::Parenthesized(n) => UnaryNodeBehaviour::from(*n), Node::Binary { left, operator, @@ -345,7 +360,7 @@ impl From<&Node<'_>> for UnaryNodeBehaviour { BuiltInFunction::One => AsBoolean, BuiltInFunction::Type => CompareWithReference(Equal), }, - Node::Error(_) => AsBoolean, + Node::Error { .. } => AsBoolean, } } } diff --git a/core/expression/tests/standard.rs b/core/expression/tests/standard.rs index 04501523..1e500f7d 100644 --- a/core/expression/tests/standard.rs +++ b/core/expression/tests/standard.rs @@ -86,11 +86,11 @@ fn standard_test() { StandardTest { src: "(1 - 2) * 3", result: &Node::Binary { - left: &Node::Binary { + left: &Node::Parenthesized(&Node::Binary { left: &Node::Number(D1), operator: Operator::Arithmetic(ArithmeticOperator::Subtract), right: &Node::Number(D2), - }, + }), operator: Operator::Arithmetic(ArithmeticOperator::Multiply), right: &Node::Number(D3), }, @@ -123,11 +123,11 @@ fn standard_test() { src: "(a or b) and c", result: &Node::Binary { operator: Operator::Logical(LogicalOperator::And), - left: &Node::Binary { + left: &Node::Parenthesized(&Node::Binary { left: &Node::Identifier("a"), right: &Node::Identifier("b"), operator: Operator::Logical(LogicalOperator::Or), - }, + }), right: &Node::Identifier("c"), }, },