diff --git a/Cargo.lock b/Cargo.lock index 620f675b..bdfeffa1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -965,8 +965,8 @@ dependencies = [ [[package]] name = "tree-sitter-witcherscript" -version = "0.5.0" -source = "git+https://github.com/SpontanCombust/tree-sitter-witcherscript.git?tag=v0.5.0#3d37bd22c471f90240babe170df612928a0a97b0" +version = "0.6.1" +source = "git+https://github.com/SpontanCombust/tree-sitter-witcherscript.git?tag=v0.6.1#558dec145d75bb9338238c5f953020ceda433f3c" dependencies = [ "cc", "tree-sitter", diff --git a/crates/analysis/src/jobs/syntax_analysis/syntax_error_visitor.rs b/crates/analysis/src/jobs/syntax_analysis/syntax_error_visitor.rs index 8d993926..a9fe06a5 100644 --- a/crates/analysis/src/jobs/syntax_analysis/syntax_error_visitor.rs +++ b/crates/analysis/src/jobs/syntax_analysis/syntax_error_visitor.rs @@ -26,6 +26,7 @@ impl SyntaxErrorVisitor<'_> { }) } + /// Returns true if the node is present, false otherwise fn check_missing(&mut self, n: SyntaxNode<'_, T>, expected: &str) -> bool { if n.is_missing() { self.missing_element(n.range(), expected.to_string()); @@ -35,6 +36,7 @@ impl SyntaxErrorVisitor<'_> { } } + /// Returns true if the identifier is present, false otherwise fn check_identifier(&mut self, n: IdentifierNode) -> bool { self.check_missing(n, "identifier") } @@ -49,11 +51,13 @@ impl SyntaxErrorVisitor<'_> { self.check_errors(&n); } + /// Returns true if the literal is present, false otherwise fn check_literal_int(&mut self, n: LiteralIntNode) -> bool { self.check_missing(n, "integer number") } - fn check_literal_string(&mut self, n: LiteralStringNode) -> bool{ + /// Returns true if the literal is present, false otherwise + fn check_literal_string(&mut self, n: LiteralStringNode) -> bool { self.check_missing(n, "string") } @@ -67,6 +71,20 @@ impl SyntaxErrorVisitor<'_> { } } + /// Returns whether the definition contains no errors + fn check_function_def(&mut self, n: FunctionDefinitionNode) -> bool { + if self.check_missing(n.clone(), "{ or ;") { + if let FunctionDefinition::Some(block) = n.value() { + if block.has_errors() { + self.check_errors(&block); + return false; + } + } + } + + true + } + fn check_errors(&mut self, n: &SyntaxNode<'_, T>) -> bool { let errors = n.errors(); if errors.is_empty() { @@ -246,16 +264,15 @@ impl StatementVisitor for SyntaxErrorVisitor<'_> { n.return_type().map(|n| self.check_type_annot(n)); self.check_errors(n); - - if let Some(def) = n.definition() { - if def.has_errors() { - self.check_errors(&def); - return true; - } + + if !self.check_function_def(n.definition()) { + return true; } } - - false + + //FIXME check for errors in params - maybe grammar should have a named node for the entirety of params? Apply this thinking to other repeating rules. + // false + true } fn visit_member_func_decl(&mut self, n: &MemberFunctionDeclarationNode) -> bool { @@ -268,15 +285,14 @@ impl StatementVisitor for SyntaxErrorVisitor<'_> { self.check_errors(n); - if let Some(def) = n.definition() { - if def.has_errors() { - self.check_errors(&def); - return true; - } + if !self.check_function_def(n.definition()) { + return true; } } - - false + + //FIXME check for errors in params + // false + true } fn visit_event_decl(&mut self, n: &EventDeclarationNode) -> bool { @@ -284,16 +300,15 @@ impl StatementVisitor for SyntaxErrorVisitor<'_> { self.check_identifier(n.name()); self.check_errors(n); - - if let Some(def) = n.definition() { - if def.has_errors() { - self.check_errors(&def); - return true; - } + + if !self.check_function_def(n.definition()) { + return true; } } - - false + + //FIXME check for errors in params + // false + true } fn visit_block_stmt(&mut self, n: &FunctionBlockNode) -> bool { @@ -432,13 +447,6 @@ impl StatementVisitor for SyntaxErrorVisitor<'_> { self.check_errors(n); } } - - fn visit_nop_stmt(&mut self, n: &NopNode) { - self.diagnostics.push(Diagnostic { - range: n.range(), - body: InfoDiagnostic::TrailingSemicolon.into() - }) - } } impl ExpressionVisitor for SyntaxErrorVisitor<'_> { diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 013abea9..cd7a8006 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -17,4 +17,4 @@ encoding_rs_io = "0.1" [dependencies.tree-sitter-witcherscript] git = "https://github.com/SpontanCombust/tree-sitter-witcherscript.git" -tag = "v0.5.0" \ No newline at end of file +tag = "v0.6.1" \ No newline at end of file diff --git a/crates/core/src/ast/expressions.rs b/crates/core/src/ast/expressions.rs index 1b99d80e..334318f5 100644 --- a/crates/core/src/ast/expressions.rs +++ b/crates/core/src/ast/expressions.rs @@ -769,7 +769,7 @@ impl ExpressionTraversal for TernaryConditionalExpressionNode<'_> { -// Represents the anonymous $._expr node +// Represents the unnamed $._expr node #[derive(Clone)] pub enum Expression<'script> { Nested(NestedExpressionNode<'script>), @@ -836,7 +836,12 @@ impl<'script> ExpressionNode<'script> { ParentExpressionNode::NODE_KIND => Expression::Parent(self.into()), VirtualParentExpressionNode::NODE_KIND => Expression::VirtualParent(self.into()), IdentifierNode::NODE_KIND => Expression::Identifier(self.into()), - LiteralNode::NODE_KIND => Expression::Literal(self.into()), + LiteralIntNode::NODE_KIND | + LiteralFloatNode::NODE_KIND | + LiteralBoolNode::NODE_KIND | + LiteralStringNode::NODE_KIND | + LiteralNameNode::NODE_KIND | + LiteralNullNode::NODE_KIND => Expression::Literal(self.into()), _ => panic!("Unknown expression type: {}", self.tree_node.kind()) } } @@ -873,7 +878,12 @@ impl<'script> TryFrom> for ExpressionNode<'script> { ParentExpressionNode::NODE_KIND | VirtualParentExpressionNode::NODE_KIND | IdentifierNode::NODE_KIND | - LiteralNode::NODE_KIND => Ok(value.into()), + LiteralIntNode::NODE_KIND | + LiteralFloatNode::NODE_KIND | + LiteralBoolNode::NODE_KIND | + LiteralStringNode::NODE_KIND | + LiteralNameNode::NODE_KIND | + LiteralNullNode::NODE_KIND => Ok(value.into()), _ => Err(()) } } diff --git a/crates/core/src/ast/functions.rs b/crates/core/src/ast/functions.rs index 4f9044d1..328ffa66 100644 --- a/crates/core/src/ast/functions.rs +++ b/crates/core/src/ast/functions.rs @@ -21,8 +21,8 @@ impl EventDeclarationNode<'_> { self.field_children("params").map(|n| n.into()) } - pub fn definition(&self) -> Option { - self.field_child("definition").map(|n| n.into()) + pub fn definition(&self) -> FunctionDefinitionNode { + self.field_child("definition").unwrap().into() } } @@ -52,7 +52,7 @@ impl StatementTraversal for EventDeclarationNode<'_> { fn accept(&self, visitor: &mut V) { if visitor.visit_event_decl(self) { self.params().for_each(|p| p.accept(visitor)); - self.definition().map(|s| s.accept(visitor)); + self.definition().accept(visitor); } visitor.exit_event_decl(self); } @@ -90,8 +90,8 @@ impl GlobalFunctionDeclarationNode<'_> { self.field_child("return_type").map(|n| n.into()) } - pub fn definition(&self) -> Option { - self.field_child("definition").map(|n| n.into()) + pub fn definition(&self) -> FunctionDefinitionNode { + self.field_child("definition").unwrap().into() } } @@ -124,7 +124,7 @@ impl StatementTraversal for GlobalFunctionDeclarationNode<'_> { fn accept(&self, visitor: &mut V) { if visitor.visit_global_func_decl(self) { self.params().for_each(|p| p.accept(visitor)); - self.definition().map(|s| s.accept(visitor)); + self.definition().accept(visitor); } visitor.exit_global_func_decl(self); } @@ -162,8 +162,8 @@ impl MemberFunctionDeclarationNode<'_> { self.field_child("return_type").map(|n| n.into()) } - pub fn definition(&self) -> Option { - self.field_child("definition").map(|n| n.into()) + pub fn definition(&self) -> FunctionDefinitionNode { + self.field_child("definition").unwrap().into() } } @@ -196,7 +196,7 @@ impl StatementTraversal for MemberFunctionDeclarationNode<'_> { fn accept(&self, visitor: &mut V) { if visitor.visit_member_func_decl(self) { self.params().for_each(|p| p.accept(visitor)); - self.definition().map(|s| s.accept(visitor)); + self.definition().accept(visitor); } visitor.exit_member_func_decl(self); } @@ -204,6 +204,64 @@ impl StatementTraversal for MemberFunctionDeclarationNode<'_> { +#[derive(Clone)] +pub enum FunctionDefinition<'script> { + Some(FunctionBlockNode<'script>), + None(NopNode<'script>) +} + +impl Debug for FunctionDefinition<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Some(n) => f.debug_tuple("Some").field(n).finish(), + Self::None(_) => f.debug_tuple("None").finish(), + } + } +} + +pub type FunctionDefinitionNode<'script> = SyntaxNode<'script, FunctionDefinition<'script>>; + +impl<'script> FunctionDefinitionNode<'script> { + pub fn value(self) -> FunctionDefinition<'script> { + match self.tree_node.kind() { + FunctionBlockNode::NODE_KIND => FunctionDefinition::Some(self.into()), + NopNode::NODE_KIND => FunctionDefinition::None(self.into()), + _ => panic!("Unknown function definition node: {}", self.tree_node.kind()) + } + } +} + +impl Debug for FunctionDefinitionNode<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_maybe_alternate(&self.clone().value()) + } +} + +impl<'script> TryFrom> for FunctionDefinitionNode<'script> { + type Error = (); + + fn try_from(value: AnyNode<'script>) -> Result { + if !value.tree_node.is_named() { + return Err(()); + } + + match value.tree_node.kind() { + FunctionBlockNode::NODE_KIND | + NopNode::NODE_KIND => Ok(value.into()), + _ => Err(()) + } + } +} + +impl StatementTraversal for FunctionDefinitionNode<'_> { + fn accept(&self, visitor: &mut V) { + if let FunctionDefinition::Some(block) = self.clone().value() { + block.accept(visitor); + } + } +} + + #[derive(Debug, Clone)] pub struct FunctionParameterGroup; @@ -407,6 +465,7 @@ impl<'script> TryFrom> for FunctionBlockNode<'script> { impl StatementTraversal for FunctionBlockNode<'_> { fn accept(&self, visitor: &mut V) { + visitor.visit_block_stmt(self); self.statements().for_each(|s| s.accept(visitor)); } } diff --git a/crates/core/src/tokens/literals.rs b/crates/core/src/tokens/literals.rs index 36e13edf..dd905d78 100644 --- a/crates/core/src/tokens/literals.rs +++ b/crates/core/src/tokens/literals.rs @@ -247,6 +247,7 @@ impl<'script> TryFrom> for LiteralNullNode<'script> { } +// Represents the unnamed $._literal node #[derive(Clone, PartialEq)] pub enum Literal<'script> { Int(LiteralIntNode<'script>), @@ -272,28 +273,23 @@ impl Debug for Literal<'_> { pub type LiteralNode<'script> = SyntaxNode<'script, Literal<'script>>; -impl NamedSyntaxNode for LiteralNode<'_> { - const NODE_KIND: &'static str = "literal"; -} - -impl LiteralNode<'_> { - pub fn value(&self) -> Literal<'_> { - let child = self.first_child(true).unwrap(); - match child.tree_node.kind() { - LiteralIntNode::NODE_KIND => Literal::Int(child.into()), - LiteralFloatNode::NODE_KIND => Literal::Float(child.into()), - LiteralBoolNode::NODE_KIND => Literal::Bool(child.into()), - LiteralStringNode::NODE_KIND => Literal::String(child.into()), - LiteralNameNode::NODE_KIND => Literal::Name(child.into()), - LiteralNullNode::NODE_KIND => Literal::Null(child.into()), - _ => panic!("Unknown literal type: {}", child.tree_node.kind()) +impl<'script> LiteralNode<'script> { + pub fn value(self) -> Literal<'script> { + match self.tree_node.kind() { + LiteralIntNode::NODE_KIND => Literal::Int(self.into()), + LiteralFloatNode::NODE_KIND => Literal::Float(self.into()), + LiteralBoolNode::NODE_KIND => Literal::Bool(self.into()), + LiteralStringNode::NODE_KIND => Literal::String(self.into()), + LiteralNameNode::NODE_KIND => Literal::Name(self.into()), + LiteralNullNode::NODE_KIND => Literal::Null(self.into()), + _ => panic!("Unknown literal type: {}", self.tree_node.kind()) } } } impl Debug for LiteralNode<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_maybe_alternate(&self.value()) + f.debug_maybe_alternate(&self.clone().value()) } } @@ -301,10 +297,18 @@ impl<'script> TryFrom> for LiteralNode<'script> { type Error = (); fn try_from(value: AnyNode<'script>) -> Result { - if value.tree_node.kind() == Self::NODE_KIND { - Ok(value.into()) - } else { - Err(()) + if !value.tree_node.is_named() { + return Err(()); + } + + match value.tree_node.kind() { + LiteralIntNode::NODE_KIND | + LiteralFloatNode::NODE_KIND | + LiteralBoolNode::NODE_KIND | + LiteralStringNode::NODE_KIND | + LiteralNameNode::NODE_KIND | + LiteralNullNode::NODE_KIND => Ok(value.into()), + _ => Err(()) } } }