From 00b8ceac3306e1de52ac6bba2ba9fc601d5bb2bd Mon Sep 17 00:00:00 2001 From: SpontanCombust <61706594+SpontanCombust@users.noreply.github.com> Date: Wed, 14 Aug 2024 03:36:31 +0200 Subject: [PATCH] Rewrote node traversal to allow visitations to error nodes --- crates/core/src/ast/classes.rs | 53 +++- crates/core/src/ast/conditionals.rs | 135 +++++++--- crates/core/src/ast/enums.rs | 57 ++++- crates/core/src/ast/expressions.rs | 374 +++++++++++++++++++++------- crates/core/src/ast/functions.rs | 232 ++++++++++++++--- crates/core/src/ast/loops.rs | 126 +++++++--- crates/core/src/ast/root.rs | 19 +- crates/core/src/ast/states.rs | 38 ++- crates/core/src/ast/structs.rs | 115 ++++++++- crates/core/src/ast/vars.rs | 46 +++- crates/core/src/syntax_error.rs | 7 +- crates/core/src/syntax_node.rs | 94 +++++-- 12 files changed, 1058 insertions(+), 238 deletions(-) diff --git a/crates/core/src/ast/classes.rs b/crates/core/src/ast/classes.rs index 4fbbe3d..da541fb 100644 --- a/crates/core/src/ast/classes.rs +++ b/crates/core/src/ast/classes.rs @@ -61,11 +61,27 @@ impl<'script> TryFrom> for ClassDeclarationNode<'script> { impl SyntaxNodeTraversal for ClassDeclarationNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_class_decl(self); - if tp.traverse_definition { + + if tp.any() { ctx.push(TraversalContext::Class); - self.definition().accept(visitor, ctx); + + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((definition, Some("definition"))) if tp.traverse_definition => { + let definition: ClassBlockNode = definition.into(); + + definition.accept_with_policy(visitor, ctx, tp.clone()); + } + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx) + }, + _ => {} + } + } + ctx.pop(); } + visitor.exit_class_decl(self); } } @@ -82,6 +98,23 @@ impl<'script> ClassBlockNode<'script> { pub fn iter(&self) -> impl Iterator> { self.named_children().map(|n| n.into()) } + + + fn accept_with_policy(&self, visitor: &mut V, ctx: &mut TraversalContextStack, tp: ClassDeclarationTraversalPolicy) { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((prop, _)) => { + let prop: ClassPropertyNode = prop.into(); + + prop.accept(visitor, ctx); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } + } } impl Debug for ClassBlockNode<'_> { @@ -107,6 +140,7 @@ impl<'script> TryFrom> for ClassBlockNode<'script> { impl SyntaxNodeTraversal for ClassBlockNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { + // UNUSED self.iter().for_each(|s| s.accept(visitor, ctx)); } } @@ -253,7 +287,20 @@ impl<'script> TryFrom> for AutobindDeclarationNode<'script> { impl SyntaxNodeTraversal for AutobindDeclarationNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { - visitor.visit_autobind_decl(self, ctx); + let tp = visitor.visit_autobind_decl(self, ctx); + + if tp.any() { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Err(e) => { + e.accept(visitor, ctx) + }, + _ => {} + } + } + } + + visitor.exit_autobind_decl(self, ctx); } } diff --git a/crates/core/src/ast/conditionals.rs b/crates/core/src/ast/conditionals.rs index 5056742..826523f 100644 --- a/crates/core/src/ast/conditionals.rs +++ b/crates/core/src/ast/conditionals.rs @@ -57,21 +57,39 @@ impl<'script> TryFrom> for IfConditionalNode<'script> { impl SyntaxNodeTraversal for IfConditionalNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_if_stmt(self, ctx); - if tp.traverse_cond { - ctx.push(TraversalContext::IfConditionalCond); - self.cond().accept(visitor, ctx); - ctx.pop(); - } - if tp.traverse_body { - ctx.push(TraversalContext::IfConditionalBody); - self.body().accept(visitor, ctx); - ctx.pop(); - } - if tp.traverse_else_body { - ctx.push(TraversalContext::IfConditionalElseBody); - self.else_body().map(|s| s.accept(visitor, ctx)); - ctx.pop(); + + if tp.any() { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((cond, Some("cond"))) if tp.traverse_cond => { + let cond: ExpressionNode = cond.into(); + + ctx.push(TraversalContext::IfConditionalCond); + cond.accept(visitor, ctx); + ctx.pop(); + }, + Ok((body, Some("body"))) if tp.traverse_body => { + let body: FunctionStatementNode = body.into(); + + ctx.push(TraversalContext::IfConditionalBody); + body.accept(visitor, ctx); + ctx.pop(); + }, + Ok((else_body, Some("else"))) if tp.traverse_else_body => { + let else_body: FunctionStatementNode = else_body.into(); + + ctx.push(TraversalContext::IfConditionalElseBody); + else_body.accept(visitor, ctx); + ctx.pop(); + } + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx) + }, + _ => {} + } + } } + visitor.exit_if_stmt(self, ctx); } } @@ -118,16 +136,32 @@ impl<'script> TryFrom> for SwitchConditionalNode<'script> { impl SyntaxNodeTraversal for SwitchConditionalNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_switch_stmt(self, ctx); - if tp.traverse_cond { - ctx.push(TraversalContext::SwitchConditionalCond); - self.cond().accept(visitor, ctx); - ctx.pop(); - } - if tp.traverse_body { - ctx.push(TraversalContext::SwitchConditionalBody); - self.body().accept(visitor, ctx); - ctx.pop(); + + if tp.any() { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((cond, Some("cond"))) if tp.traverse_cond => { + let cond: ExpressionNode = cond.into(); + + ctx.push(TraversalContext::SwitchConditionalCond); + cond.accept(visitor, ctx); + ctx.pop(); + }, + Ok((body, Some("body"))) if tp.traverse_body => { + let body: SwitchConditionalBlockNode = body.into(); + + ctx.push(TraversalContext::SwitchConditionalBody); + body.accept_with_policy(visitor, ctx, tp.clone()); + ctx.pop(); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } } + visitor.exit_switch_stmt(self, ctx); } } @@ -144,6 +178,23 @@ impl<'script> SwitchConditionalBlockNode<'script> { pub fn sections(&self) -> impl Iterator> { self.named_children().map(|n| n.into()) } + + + fn accept_with_policy(&self, visitor: &mut V, ctx: &mut TraversalContextStack, tp: SwitchConditionalTraversalPolicy) { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((section, _)) => { + let section: SwitchConditionalSectionNode = section.into(); + + section.accept(visitor, ctx) + } + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx) + }, + _ => {} + } + } + } } impl Debug for SwitchConditionalBlockNode<'_> { @@ -169,6 +220,7 @@ impl<'script> TryFrom> for SwitchConditionalBlockNode<'script> impl SyntaxNodeTraversal for SwitchConditionalBlockNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { + // UNUSED self.sections().for_each(|s| s.accept(visitor, ctx)); } } @@ -283,11 +335,25 @@ impl<'script> TryFrom> for SwitchConditionalCaseLabelNode<'scri impl SyntaxNodeTraversal for SwitchConditionalCaseLabelNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_switch_stmt_case(self, ctx); - if tp.traverse_value { - ctx.push(TraversalContext::SwitchConditionalCaseLabel); - self.value().accept(visitor, ctx); - ctx.pop(); + + if tp.any() { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((value, Some("value"))) if tp.traverse_value => { + let value: ExpressionNode = value.into(); + + ctx.push(TraversalContext::SwitchConditionalCaseLabel); + value.accept(visitor, ctx); + ctx.pop(); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + } + _ => {} + } + } } + visitor.exit_switch_stmt_case(self, ctx); } } @@ -320,6 +386,19 @@ impl<'script> TryFrom> for SwitchConditionalDefaultLabelNode<'s impl SyntaxNodeTraversal for SwitchConditionalDefaultLabelNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { - visitor.visit_switch_stmt_default(self, ctx); + let tp = visitor.visit_switch_stmt_default(self, ctx); + + if tp.any() { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + } + _ => {} + } + } + } + + visitor.exit_switch_stmt_default(self, ctx); } } \ No newline at end of file diff --git a/crates/core/src/ast/enums.rs b/crates/core/src/ast/enums.rs index 1c93e44..c3e65ff 100644 --- a/crates/core/src/ast/enums.rs +++ b/crates/core/src/ast/enums.rs @@ -50,11 +50,25 @@ impl<'script> TryFrom> for EnumDeclarationNode<'script> { impl SyntaxNodeTraversal for EnumDeclarationNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_enum_decl(self); - if tp.traverse_definition { - ctx.push(TraversalContext::Enum); - self.definition().accept(visitor, ctx); - ctx.pop(); + + if tp.any() { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((def, Some("definition"))) if tp.traverse_definition => { + let def: EnumBlockNode = def.into(); + + ctx.push(TraversalContext::Enum); + def.accept_with_policy(visitor, ctx, tp.clone()); + ctx.pop(); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } } + visitor.exit_enum_decl(self); } } @@ -71,6 +85,23 @@ impl<'script> EnumBlockNode<'script> { pub fn iter(&self) -> impl Iterator> { self.named_children().map(|n| n.into()) } + + + fn accept_with_policy(&self, visitor: &mut V, ctx: &mut TraversalContextStack, tp: EnumDeclarationTraversalPolicy) { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((variant, _)) => { + let variant: EnumVariantDeclarationNode = variant.into(); + + variant.accept(visitor, ctx); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } + } } impl Debug for EnumBlockNode<'_> { @@ -96,6 +127,7 @@ impl<'script> TryFrom> for EnumBlockNode<'script> { impl SyntaxNodeTraversal for EnumBlockNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { + // UNUSED self.iter().for_each(|s| s.accept(visitor, ctx)); } } @@ -146,8 +178,21 @@ impl<'script> TryFrom> for EnumVariantDeclarationNode<'script> } impl SyntaxNodeTraversal for EnumVariantDeclarationNode<'_> { - fn accept(&self, visitor: &mut V, _: &mut TraversalContextStack) { - visitor.visit_enum_variant_decl(self); + fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { + let tp = visitor.visit_enum_variant_decl(self); + + if tp.any() { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } + } + + visitor.exit_enum_variant_decl(self); } } diff --git a/crates/core/src/ast/expressions.rs b/crates/core/src/ast/expressions.rs index 92ce90c..e7c7580 100644 --- a/crates/core/src/ast/expressions.rs +++ b/crates/core/src/ast/expressions.rs @@ -1,6 +1,6 @@ use std::fmt::Debug; use lsp_types as lsp; -use crate::{tokens::*, AnyNode, DebugMaybeAlternate, DebugRange, NamedSyntaxNode, SyntaxNode}; +use crate::{tokens::*, AnyNode, DebugMaybeAlternate, DebugRange, ErrorNode, NamedSyntaxNode, SyntaxNode}; use super::*; @@ -59,11 +59,26 @@ impl<'script> TryFrom> for NestedExpressionNode<'script> { impl SyntaxNodeTraversal for NestedExpressionNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_nested_expr(self, ctx); - if tp.traverse_inner { - ctx.push(TraversalContext::NestedExpressionInner); - self.inner().accept(visitor, ctx); - ctx.pop(); + + if tp.any() { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((inner, _)) if tp.traverse_inner => { + ctx.push(TraversalContext::NestedExpressionInner); + + let inner: ExpressionNode = inner.into(); + inner.accept(visitor, ctx); + + ctx.pop(); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx) + }, + _ => {} + } + } } + visitor.exit_nested_expr(self, ctx); } } @@ -246,14 +261,31 @@ impl<'script> TryFrom> for FunctionCallExpressionNode<'script> impl SyntaxNodeTraversal for FunctionCallExpressionNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_func_call_expr(self, ctx); - if tp.traverse_func { - ctx.push(TraversalContext::FunctionCallExpressionFunc); - self.func().accept(visitor, ctx); - ctx.pop(); - } - if tp.traverse_args { - self.args().map(|n| n.accept(visitor, ctx)); + + if tp.any() { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((func, Some("func"))) if tp.traverse_func => { + ctx.push(TraversalContext::FunctionCallExpressionFunc); + + let func: ExpressionNode = func.into(); + func.accept(visitor, ctx); + + ctx.pop(); + }, + Ok((args, Some("args"))) if tp.traverse_args => { + let args: FunctionCallArgumentsNode = args.into(); + + args.accept_with_policy(visitor, ctx, tp.clone()); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } } + visitor.exit_func_call_expr(self, ctx); } } @@ -268,23 +300,56 @@ impl NamedSyntaxNode for FunctionCallArgumentsNode<'_> { impl<'script> FunctionCallArgumentsNode<'script> { pub fn iter(&self) -> impl Iterator> { - let children = self.children(); + self.iter_result().filter_map(|n| n.ok()) + } - let mut args = Vec::new(); + pub fn iter_result(&self) -> impl Iterator, ErrorNode<'script>>> { + let mut iter = self.children_detailed().must_be_named(false); let mut previous_was_comma = true; - for n in children { - if n.tree_node.is_named() { - args.push(FunctionCallArgument::Some(n.into())); - previous_was_comma = false; - } else { - if previous_was_comma { - args.push(FunctionCallArgument::Omitted(n.range())); + + std::iter::from_fn(move || { + iter.find_map(|ch| { + match ch { + Ok((n, _)) => { + if n.is_named() { + let arg = FunctionCallArgument::Some(n.into()); + previous_was_comma = false; + + Some(Ok(arg)) + } else { + if previous_was_comma { + let arg = FunctionCallArgument::Omitted(n.range()); + previous_was_comma = true; + + Some(Ok(arg)) + } else { + previous_was_comma = true; + + None + } + } + }, + Err(e) => { + previous_was_comma = false; + Some(Err(e)) + } } - previous_was_comma = true; + }) + }) + } + + fn accept_with_policy(&self, visitor: &mut V, ctx: &mut TraversalContextStack, tp: FunctionCallExpressionTraversalPolicy) { + for res in self.iter_result() { + match res { + Ok(arg) => { + arg.accept(visitor, ctx) + } + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx) + }, + _ => {} } } - - args.into_iter() } } @@ -356,6 +421,8 @@ impl Debug for FunctionCallArgument<'_> { impl SyntaxNodeTraversal for FunctionCallArgument<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_func_call_arg(self, ctx); + // the argument node is either an expression or nothing (an ommited optional arg) + // there are no error nodes to look for at this point if tp.traverse_expr { if let FunctionCallArgument::Some(n) = self { ctx.push(TraversalContext::FunctionCallArg); @@ -409,16 +476,32 @@ impl<'script> TryFrom> for ArrayExpressionNode<'script> { impl SyntaxNodeTraversal for ArrayExpressionNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_array_expr(self, ctx); - if tp.traverse_accessor { - ctx.push(TraversalContext::ArrayExpressionAccessor); - self.accessor().accept(visitor, ctx); - ctx.pop(); - } - if tp.traverse_index { - ctx.push(TraversalContext::ArrayExpressionIndex); - self.index().accept(visitor, ctx); - ctx.pop(); + + if tp.any() { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((accessor, Some("accessor"))) if tp.traverse_accessor => { + let accessor: ExpressionNode = accessor.into(); + + ctx.push(TraversalContext::ArrayExpressionAccessor); + accessor.accept(visitor, ctx); + ctx.pop(); + }, + Ok((index, Some("index"))) if tp.traverse_index => { + let index: ExpressionNode = index.into(); + + ctx.push(TraversalContext::ArrayExpressionIndex); + index.accept(visitor, ctx); + ctx.pop(); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } } + visitor.exit_array_expr(self, ctx); } } @@ -465,11 +548,26 @@ impl<'script> TryFrom> for MemberAccessExpressionNode<'script> impl SyntaxNodeTraversal for MemberAccessExpressionNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_member_access_expr(self, ctx); - if tp.traverse_accessor { - ctx.push(TraversalContext::MemberAccessExpressionAccessor); - self.accessor().accept(visitor, ctx); - ctx.pop(); + + if tp.any() { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((accessor, Some("accessor"))) if tp.traverse_accessor => { + let accessor: ExpressionNode = accessor.into(); + + ctx.push(TraversalContext::MemberAccessExpressionAccessor); + accessor.accept(visitor, ctx); + ctx.pop(); + + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } } + visitor.exit_member_access_expr(self, ctx); } } @@ -516,11 +614,25 @@ impl<'script> TryFrom> for NewExpressionNode<'script> { impl SyntaxNodeTraversal for NewExpressionNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_new_expr(self, ctx); - if tp.traverse_lifetime_obj { - ctx.push(TraversalContext::NewExpressionLifetimeObj); - self.lifetime_obj().map(|n| n.accept(visitor, ctx)); - ctx.pop(); + + if tp.any() { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((lifetime_obj, Some("lifetime_obj"))) if tp.traverse_lifetime_obj => { + let lifetime_obj: ExpressionNode = lifetime_obj.into(); + + ctx.push(TraversalContext::NewExpressionLifetimeObj); + lifetime_obj.accept(visitor, ctx); + ctx.pop(); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } } + visitor.exit_new_expr(self, ctx); } } @@ -567,11 +679,25 @@ impl<'script> TryFrom> for TypeCastExpressionNode<'script> { impl SyntaxNodeTraversal for TypeCastExpressionNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_type_cast_expr(self, ctx); - if tp.traverse_value { - ctx.push(TraversalContext::TypeCastExpressionValue); - self.value().accept(visitor, ctx); - ctx.pop(); + + if tp.any() { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((value, Some("value"))) if tp.traverse_value => { + let value: ExpressionNode = value.into(); + + ctx.push(TraversalContext::TypeCastExpressionValue); + value.accept(visitor, ctx); + ctx.pop(); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } } + visitor.exit_type_cast_expr(self, ctx); } } @@ -618,11 +744,25 @@ impl<'script> TryFrom> for UnaryOperationExpressionNode<'script impl SyntaxNodeTraversal for UnaryOperationExpressionNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_unary_op_expr(self, ctx); - if tp.traverse_right { - ctx.push(TraversalContext::UnaryOperationExpressionRight); - self.right().accept(visitor, ctx); - ctx.pop(); + + if tp.any() { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((right, Some("right"))) if tp.traverse_right => { + let right: ExpressionNode = right.into(); + + ctx.push(TraversalContext::UnaryOperationExpressionRight); + right.accept(visitor, ctx); + ctx.pop(); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } } + visitor.exit_unary_op_expr(self, ctx); } } @@ -674,16 +814,32 @@ impl<'script> TryFrom> for BinaryOperationExpressionNode<'scrip impl SyntaxNodeTraversal for BinaryOperationExpressionNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_binary_op_expr(self, ctx); - if tp.traverse_left { - ctx.push(TraversalContext::BinaryOperationExpressionLeft); - self.left().accept(visitor, ctx); - ctx.pop(); - } - if tp.traverse_right { - ctx.push(TraversalContext::BinaryOperationExpressionRight); - self.right().accept(visitor, ctx); - ctx.pop(); + + if tp.any() { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((left, Some("left"))) if tp.traverse_left => { + let left: ExpressionNode = left.into(); + + ctx.push(TraversalContext::BinaryOperationExpressionLeft); + left.accept(visitor, ctx); + ctx.pop(); + }, + Ok((right, Some("right"))) if tp.traverse_right => { + let right: ExpressionNode = right.into(); + + ctx.push(TraversalContext::BinaryOperationExpressionRight); + right.accept(visitor, ctx); + ctx.pop(); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } } + visitor.exit_binary_op_expr(self, ctx); } } @@ -735,16 +891,32 @@ impl<'script> TryFrom> for AssignmentOperationExpressionNode<'s impl SyntaxNodeTraversal for AssignmentOperationExpressionNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_assign_op_expr(self, ctx); - if tp.traverse_left { - ctx.push(TraversalContext::AssignmentOperationExpressionLeft); - self.left().accept(visitor, ctx); - ctx.pop(); - } - if tp.traverse_right { - ctx.push(TraversalContext::AssignmentOperationExpressionRight); - self.right().accept(visitor, ctx); - ctx.pop(); + + if tp.any() { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((left, Some("left"))) if tp.traverse_left => { + let left: ExpressionNode = left.into(); + + ctx.push(TraversalContext::AssignmentOperationExpressionLeft); + left.accept(visitor, ctx); + ctx.pop(); + }, + Ok((right, Some("right"))) if tp.traverse_right => { + let right: ExpressionNode = right.into(); + + ctx.push(TraversalContext::AssignmentOperationExpressionRight); + right.accept(visitor, ctx); + ctx.pop(); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } } + visitor.exit_assign_op_expr(self, ctx); } } @@ -796,21 +968,39 @@ impl<'script> TryFrom> for TernaryConditionalExpressionNode<'sc impl SyntaxNodeTraversal for TernaryConditionalExpressionNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_ternary_cond_expr(self, ctx); - if tp.traverse_cond { - ctx.push(TraversalContext::TernaryConditionalExpressionCond); - self.cond().accept(visitor, ctx); - ctx.pop(); - } - if tp.traverse_conseq { - ctx.push(TraversalContext::TernaryConditionalExpressionConseq); - self.conseq().accept(visitor, ctx); - ctx.pop(); - } - if tp.traverse_alt { - ctx.push(TraversalContext::TernaryConditionalExpressionAlt); - self.alt().accept(visitor, ctx); - ctx.pop(); + + if tp.any() { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((cond, Some("cond"))) if tp.traverse_cond => { + let cond: ExpressionNode = cond.into(); + + ctx.push(TraversalContext::TernaryConditionalExpressionCond); + cond.accept(visitor, ctx); + ctx.pop(); + }, + Ok((conseq, Some("conseq"))) if tp.traverse_conseq => { + let conseq: ExpressionNode = conseq.into(); + + ctx.push(TraversalContext::TernaryConditionalExpressionConseq); + conseq.accept(visitor, ctx); + ctx.pop(); + }, + Ok((alt, Some("alt"))) if tp.traverse_alt => { + let alt: ExpressionNode = alt.into(); + + ctx.push(TraversalContext::TernaryConditionalExpressionAlt); + alt.accept(visitor, ctx); + ctx.pop(); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } } + visitor.exit_ternary_cond_expr(self, ctx); } } @@ -1091,11 +1281,25 @@ impl<'script> TryFrom> for ExpressionStatementNode<'script> { impl SyntaxNodeTraversal for ExpressionStatementNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_expr_stmt(self, ctx); - if tp.traverse_expr { - ctx.push(TraversalContext::ExpressionStatement); - self.expr().accept(visitor, ctx); - ctx.pop(); + + if tp.any() { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((expr, _)) if tp.traverse_expr => { + let expr: ExpressionNode = expr.into(); + + ctx.push(TraversalContext::ExpressionStatement); + expr.accept(visitor, ctx); + ctx.pop(); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } } + visitor.exit_expr_stmt(self, ctx); } } \ No newline at end of file diff --git a/crates/core/src/ast/functions.rs b/crates/core/src/ast/functions.rs index d49501c..5e391e5 100644 --- a/crates/core/src/ast/functions.rs +++ b/crates/core/src/ast/functions.rs @@ -68,15 +68,31 @@ impl SyntaxNodeTraversal for EventDeclarationNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_event_decl(self, ctx); - ctx.push(TraversalContext::Event); - if tp.traverse_params { - self.params().accept(visitor, ctx); - } - if tp.traverse_definition { - self.definition().accept(visitor, ctx); + if tp.any() { + ctx.push(TraversalContext::Event); + + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((params, Some("params"))) if tp.traverse_params => { + let params: FunctionParametersNode = params.into(); + + params.accept_with_policy(visitor, ctx, tp.traverse_errors); + }, + Ok((def, Some("definition"))) if tp.traverse_definition => { + let def: FunctionDefinitionNode = def.into(); + + def.accept_with_policy(visitor, ctx, tp.traverse_errors); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } + + ctx.pop(); } - ctx.pop(); - + visitor.exit_event_decl(self, ctx); } } @@ -147,30 +163,51 @@ impl<'script> TryFrom> for FunctionDeclarationNode<'script> { impl SyntaxNodeTraversal for FunctionDeclarationNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { + // closure to not repeat code below + let accept_proper = |self_: &Self, visitor: &mut V, ctx: &mut TraversalContextStack, tp: FunctionDeclarationTraversalPolicy| { + for ch in self_.children_detailed().must_be_named(true) { + match ch { + Ok((params, Some("params"))) if tp.traverse_params => { + let params: FunctionParametersNode = params.into(); + + params.accept_with_policy(visitor, ctx, tp.traverse_errors); + }, + Ok((def, Some("definition"))) if tp.traverse_definition => { + let def: FunctionDefinitionNode = def.into(); + + def.accept_with_policy(visitor, ctx, tp.traverse_errors); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } + }; + + if ctx.top() == TraversalContext::Global { let tp = visitor.visit_global_func_decl(self); - ctx.push(TraversalContext::GlobalFunction); - if tp.traverse_params { - self.params().accept(visitor, ctx); - } - if tp.traverse_definition { - self.definition().accept(visitor, ctx); - } - ctx.pop(); + if tp.any() { + ctx.push(TraversalContext::GlobalFunction); + + accept_proper(self, visitor, ctx, tp); + ctx.pop(); + } + visitor.exit_global_func_decl(self); } else { let tp = visitor.visit_member_func_decl(self, ctx); - ctx.push(TraversalContext::MemberFunction); - if tp.traverse_params { - self.params().accept(visitor, ctx); - } - if tp.traverse_definition { - self.definition().accept(visitor, ctx); + if tp.any() { + ctx.push(TraversalContext::MemberFunction); + + accept_proper(self, visitor, ctx, tp); + + ctx.pop(); } - ctx.pop(); visitor.exit_member_func_decl(self, ctx); } @@ -204,6 +241,13 @@ impl<'script> FunctionDefinitionNode<'script> { _ => panic!("Unknown function definition node: {} {}", self.tree_node.kind(), self.range().debug()) } } + + + fn accept_with_policy(&self, visitor: &mut V, ctx: &mut TraversalContextStack, traverse_errors: bool) { + if let FunctionDefinition::Some(block) = self.clone().value() { + block.accept_with_policy(visitor, ctx, traverse_errors); + } + } } impl Debug for FunctionDefinitionNode<'_> { @@ -230,6 +274,7 @@ impl<'script> TryFrom> for FunctionDefinitionNode<'script> { impl SyntaxNodeTraversal for FunctionDefinitionNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { + // UNUSED if let FunctionDefinition::Some(block) = self.clone().value() { block.accept(visitor, ctx); } @@ -248,6 +293,23 @@ impl<'script> FunctionBlockNode<'script> { pub fn iter(&self) -> impl Iterator> { self.named_children().map(|n| n.into()) } + + + fn accept_with_policy(&self, visitor: &mut V, ctx: &mut TraversalContextStack, traverse_errors: bool) { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((stmt, _)) => { + let stmt: FunctionStatementNode = stmt.into(); + + stmt.accept(visitor, ctx); + }, + Err(e) if traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } + } } impl Debug for FunctionBlockNode<'_> { @@ -273,6 +335,7 @@ impl<'script> TryFrom> for FunctionBlockNode<'script> { impl SyntaxNodeTraversal for FunctionBlockNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { + // UNUSED self.iter().for_each(|s| s.accept(visitor, ctx)); } } @@ -289,6 +352,23 @@ impl<'script> FunctionParametersNode<'script> { pub fn iter(&self) -> impl Iterator> { self.named_children().map(|n| n.into()) } + + + fn accept_with_policy(&self, visitor: &mut V, ctx: &mut TraversalContextStack, traverse_errors: bool) { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((param_group, _)) => { + let param_group: FunctionParameterGroupNode = param_group.into(); + + param_group.accept(visitor, ctx); + }, + Err(e) if traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } + } } impl Debug for FunctionParametersNode<'_> { @@ -314,6 +394,7 @@ impl<'script> TryFrom> for FunctionParametersNode<'script> { impl SyntaxNodeTraversal for FunctionParametersNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { + // UNUSED self.iter().for_each(|s| s.accept(visitor, ctx)); } } @@ -364,7 +445,20 @@ impl<'script> TryFrom> for FunctionParameterGroupNode<'script> impl SyntaxNodeTraversal for FunctionParameterGroupNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { - visitor.visit_func_param_group(self, ctx); + let tp = visitor.visit_func_param_group(self, ctx); + + if tp.any() { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } + } + + visitor.exit_func_param_group(self, ctx); } } @@ -513,7 +607,20 @@ impl<'script> TryFrom> for BreakStatementNode<'script> { impl SyntaxNodeTraversal for BreakStatementNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { - visitor.visit_break_stmt(self, ctx); + let tp = visitor.visit_break_stmt(self, ctx); + + if tp.any() { + for ch in self.children_detailed() { + match ch { + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } + } + + visitor.exit_break_stmt(self, ctx); } } @@ -547,7 +654,20 @@ impl<'script> TryFrom> for ContinueStatementNode<'script> { impl SyntaxNodeTraversal for ContinueStatementNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { - visitor.visit_continue_stmt(self, ctx); + let tp = visitor.visit_continue_stmt(self, ctx); + + if tp.any() { + for ch in self.children_detailed() { + match ch { + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } + } + + visitor.exit_continue_stmt(self, ctx); } } @@ -588,11 +708,27 @@ impl<'script> TryFrom> for ReturnStatementNode<'script> { impl SyntaxNodeTraversal for ReturnStatementNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_return_stmt(self, ctx); - if tp.traverse_value { + + if tp.any() { ctx.push(TraversalContext::ReturnStatement); - self.value().map(|expr| expr.accept(visitor, ctx)); + + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((value, _)) if tp.traverse_value => { + let value: ExpressionNode = value.into(); + + value.accept(visitor, ctx); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } + ctx.pop(); } + visitor.exit_return_stmt(self, ctx); } } @@ -634,11 +770,27 @@ impl<'script> TryFrom> for DeleteStatementNode<'script> { impl SyntaxNodeTraversal for DeleteStatementNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_delete_stmt(self, ctx); - if tp.traverse_value { + + if tp.any() { ctx.push(TraversalContext::DeleteStatement); - self.value().accept(visitor, ctx); + + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((value, _)) if tp.traverse_value => { + let value: ExpressionNode = value.into(); + + value.accept(visitor, ctx); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } + ctx.pop(); } + visitor.exit_delete_stmt(self, ctx); } } @@ -681,11 +833,27 @@ impl<'script> TryFrom> for CompoundStatementNode<'script> { impl SyntaxNodeTraversal for CompoundStatementNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_compound_stmt(self, ctx); - if tp.traverse { + + if tp.any() { ctx.push(TraversalContext::CompoundStatement); - self.iter().for_each(|s| s.accept(visitor, ctx)); + + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((stmt, _)) if tp.traverse => { + let stmt: FunctionStatementNode = stmt.into(); + + stmt.accept(visitor, ctx); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } + ctx.pop(); } + visitor.exit_compound_stmt(self, ctx); } } \ No newline at end of file diff --git a/crates/core/src/ast/loops.rs b/crates/core/src/ast/loops.rs index e850a25..7722b7c 100644 --- a/crates/core/src/ast/loops.rs +++ b/crates/core/src/ast/loops.rs @@ -60,26 +60,46 @@ impl<'script> TryFrom> for ForLoopNode<'script> { impl SyntaxNodeTraversal for ForLoopNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_for_stmt(self, ctx); - if tp.traverse_init { - ctx.push(TraversalContext::ForLoopInit); - self.init().map(|init| init.accept(visitor, ctx)); - ctx.pop(); - } - if tp.traverse_cond { - ctx.push(TraversalContext::ForLoopCond); - self.cond().map(|cond| cond.accept(visitor, ctx)); - ctx.pop(); - } - if tp.traverse_iter { - ctx.push(TraversalContext::ForLoopIter); - self.iter().map(|iter| iter.accept(visitor, ctx)); - ctx.pop(); - } - if tp.traverse_body { - ctx.push(TraversalContext::ForLoopBody); - self.body().accept(visitor, ctx); - ctx.pop(); + + if tp.any() { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((init, Some("init"))) if tp.traverse_init => { + let init: ExpressionNode = init.into(); + + ctx.push(TraversalContext::ForLoopInit); + init.accept(visitor, ctx); + ctx.pop(); + }, + Ok((cond, Some("cond"))) if tp.traverse_cond => { + let cond: ExpressionNode = cond.into(); + + ctx.push(TraversalContext::ForLoopCond); + cond.accept(visitor, ctx); + ctx.pop(); + }, + Ok((iter, Some("iter"))) if tp.traverse_iter => { + let iter: ExpressionNode = iter.into(); + + ctx.push(TraversalContext::ForLoopIter); + iter.accept(visitor, ctx); + ctx.pop(); + }, + Ok((body, Some("body"))) if tp.traverse_body => { + let body: FunctionStatementNode = body.into(); + + ctx.push(TraversalContext::ForLoopBody); + body.accept(visitor, ctx); + ctx.pop(); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } } + visitor.exit_for_stmt(self, ctx); } } @@ -126,16 +146,32 @@ impl<'script> TryFrom> for WhileLoopNode<'script> { impl SyntaxNodeTraversal for WhileLoopNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_while_stmt(self, ctx); - if tp.traverse_cond { - ctx.push(TraversalContext::WhileLoopCond); - self.cond().accept(visitor, ctx); - ctx.pop(); - } - if tp.traverse_body { - ctx.push(TraversalContext::WhileLoopBody); - self.body().accept(visitor, ctx); - ctx.pop(); + + if tp.any() { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((cond, Some("cond"))) if tp.traverse_cond => { + let cond: ExpressionNode = cond.into(); + + ctx.push(TraversalContext::WhileLoopCond); + cond.accept(visitor, ctx); + ctx.pop(); + }, + Ok((body, Some("body"))) if tp.traverse_body => { + let body: FunctionStatementNode = body.into(); + + ctx.push(TraversalContext::WhileLoopBody); + body.accept(visitor, ctx); + ctx.pop(); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } } + visitor.exit_while_stmt(self, ctx); } } @@ -182,16 +218,32 @@ impl<'script> TryFrom> for DoWhileLoopNode<'script> { impl SyntaxNodeTraversal for DoWhileLoopNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_do_while_stmt(self, ctx); - if tp.traverse_cond { - ctx.push(TraversalContext::DoWhileLoopCond); - self.cond().accept(visitor, ctx); - ctx.pop(); - } - if tp.traverse_body { - ctx.push(TraversalContext::DoWhileLoopBody); - self.body().accept(visitor, ctx); - ctx.pop(); + + if tp.any() { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((cond, Some("cond"))) if tp.traverse_cond => { + let cond: ExpressionNode = cond.into(); + + ctx.push(TraversalContext::DoWhileLoopCond); + cond.accept(visitor, ctx); + ctx.pop(); + }, + Ok((body, Some("body"))) if tp.traverse_body => { + let body: FunctionStatementNode = body.into(); + + ctx.push(TraversalContext::DoWhileLoopBody); + body.accept(visitor, ctx); + ctx.pop(); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } } + visitor.exit_do_while_stmt(self, ctx); } } \ No newline at end of file diff --git a/crates/core/src/ast/root.rs b/crates/core/src/ast/root.rs index 262e441..9e65900 100644 --- a/crates/core/src/ast/root.rs +++ b/crates/core/src/ast/root.rs @@ -130,9 +130,24 @@ impl<'script> TryFrom> for RootNode<'script> { impl SyntaxNodeTraversal for RootNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_root(self); - if tp.traverse { + + if tp.any() { ctx.push(TraversalContext::Global); - self.iter().for_each(|s| s.accept(visitor, ctx)); + + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((stmt, _)) if tp.traverse => { + let stmt: RootStatementNode = stmt.into(); + + stmt.accept(visitor, ctx); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } + ctx.pop(); } } diff --git a/crates/core/src/ast/states.rs b/crates/core/src/ast/states.rs index 78ec5f1..a58ab24 100644 --- a/crates/core/src/ast/states.rs +++ b/crates/core/src/ast/states.rs @@ -64,11 +64,27 @@ impl<'script> TryFrom> for StateDeclarationNode<'script> { impl SyntaxNodeTraversal for StateDeclarationNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_state_decl(self); - if tp.traverse_definition { + + if tp.any() { ctx.push(TraversalContext::State); - self.definition().accept(visitor, ctx); + + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((def, Some("definition"))) if tp.traverse_definition => { + let def: StateBlockNode = def.into(); + + def.accept_with_policy(visitor, ctx, tp.traverse_errors); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } + ctx.pop(); } + visitor.exit_state_decl(self); } } @@ -84,6 +100,23 @@ impl<'script> StateBlockNode<'script> { pub fn iter(&self) -> impl Iterator> { self.named_children().map(|n| n.into()) } + + + fn accept_with_policy(&self, visitor: &mut V, ctx: &mut TraversalContextStack, traverse_errors: bool) { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((prop, _)) => { + let prop: ClassPropertyNode = prop.into(); + + prop.accept(visitor, ctx); + }, + Err(e) if traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } + } } impl Debug for StateBlockNode<'_> { @@ -109,6 +142,7 @@ impl<'script> TryFrom> for StateBlockNode<'script> { impl SyntaxNodeTraversal for StateBlockNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { + // UNUSED self.iter().for_each(|s| s.accept(visitor, ctx)); } } \ No newline at end of file diff --git a/crates/core/src/ast/structs.rs b/crates/core/src/ast/structs.rs index 4bcdac3..a0f34f5 100644 --- a/crates/core/src/ast/structs.rs +++ b/crates/core/src/ast/structs.rs @@ -58,11 +58,27 @@ impl<'script> TryFrom> for StructDeclarationNode<'script> { impl SyntaxNodeTraversal for StructDeclarationNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_struct_decl(self); - if tp.traverse_definition { + + if tp.any() { ctx.push(TraversalContext::Struct); - self.definition().accept(visitor, ctx); + + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((def, Some("definition"))) if tp.traverse_definition => { + let def: StructBlockNode = def.into(); + + def.accept_with_policy(visitor, ctx, tp.traverse_errors); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } + ctx.pop(); } + visitor.exit_struct_decl(self); } } @@ -79,6 +95,23 @@ impl<'script> StructBlockNode<'script> { pub fn iter(&self) -> impl Iterator { self.named_children().map(|n| n.into()) } + + + fn accept_with_policy(&self, visitor: &mut V, ctx: &mut TraversalContextStack, traverse_errors: bool) { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((prop, _)) => { + let prop: StructPropertyNode = prop.into(); + + prop.accept(visitor, ctx); + }, + Err(e) if traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } + } } impl Debug for StructBlockNode<'_> { @@ -104,6 +137,7 @@ impl<'script> TryFrom> for StructBlockNode<'script> { impl SyntaxNodeTraversal for StructBlockNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { + // UNUSED self.iter().for_each(|s| s.accept(visitor, ctx)); } } @@ -184,7 +218,7 @@ impl SyntaxNodeTraversal for StructPropertyNode<'_> { } - +//TODO move this and similar to a new misc_props.rs pub type MemberDefaultsBlockNode<'script> = SyntaxNode<'script, tags::MemberDefaultsBlock>; impl NamedSyntaxNode for MemberDefaultsBlockNode<'_> { @@ -221,9 +255,23 @@ impl<'script> TryFrom> for MemberDefaultsBlockNode<'script> { impl SyntaxNodeTraversal for MemberDefaultsBlockNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_member_defaults_block(self, ctx); - if tp.traverse { - self.iter().for_each(|n| n.accept(visitor, ctx)); + + if tp.any() { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((assign, _)) if tp.traverse => { + let assign: MemberDefaultsBlockAssignmentNode = assign.into(); + + assign.accept(visitor, ctx); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } } + visitor.exit_member_defaults_block(self, ctx); } } @@ -270,11 +318,27 @@ impl<'script> TryFrom> for MemberDefaultsBlockAssignmentNode<'s impl SyntaxNodeTraversal for MemberDefaultsBlockAssignmentNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_member_defaults_block_assignment(self, ctx); - if tp.traverse_value { + + if tp.any() { ctx.push(TraversalContext::MemberDefaultValue); - self.value().accept(visitor, ctx); - ctx.pop(); + + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((value, Some("value"))) if tp.traverse_value => { + let value: ExpressionNode = value.into(); + + value.accept(visitor, ctx); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } + + ctx.pop(); } + visitor.exit_member_defaults_block_assignment(self, ctx); } } @@ -321,11 +385,27 @@ impl<'script> TryFrom> for MemberDefaultValueNode<'script> { impl SyntaxNodeTraversal for MemberDefaultValueNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_member_default_val(self, ctx); - if tp.traverse_value { + + if tp.any() { ctx.push(TraversalContext::MemberDefaultValue); - self.value().accept(visitor, ctx); + + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((value, Some("value"))) if tp.traverse_value => { + let value: ExpressionNode = value.into(); + + value.accept(visitor, ctx); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } + ctx.pop(); } + visitor.exit_member_default_val(self, ctx); } } @@ -371,6 +451,19 @@ impl<'script> TryFrom> for MemberHintNode<'script> { impl SyntaxNodeTraversal for MemberHintNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { - visitor.visit_member_hint(self, ctx); + let tp = visitor.visit_member_hint(self, ctx); + + if tp.any() { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } + } + + visitor.exit_member_hint(self, ctx); } } diff --git a/crates/core/src/ast/vars.rs b/crates/core/src/ast/vars.rs index 8733bcc..81929b6 100644 --- a/crates/core/src/ast/vars.rs +++ b/crates/core/src/ast/vars.rs @@ -94,11 +94,25 @@ impl<'script> TryFrom> for LocalVarDeclarationNode<'script> { impl SyntaxNodeTraversal for LocalVarDeclarationNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { let tp = visitor.visit_local_var_decl_stmt(self, ctx); - if tp.traverse_init_value { - ctx.push(TraversalContext::LocalVarDeclarationInitValue); - self.init_value().map(|init_value| init_value.accept(visitor, ctx)); - ctx.pop(); + + if tp.any() { + for ch in self.children_detailed().must_be_named(true) { + match ch { + Ok((init_value, Some("init_value"))) if tp.traverse_init_value => { + let init_value: ExpressionNode = init_value.into(); + + ctx.push(TraversalContext::LocalVarDeclarationInitValue); + init_value.accept(visitor, ctx); + ctx.pop(); + }, + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } } + visitor.exit_local_var_decl_stmt(self, ctx); } } @@ -154,10 +168,30 @@ impl<'script> TryFrom> for MemberVarDeclarationNode<'script> { impl SyntaxNodeTraversal for MemberVarDeclarationNode<'_> { fn accept(&self, visitor: &mut V, ctx: &mut TraversalContextStack) { + // closure to avoid code repetition below + let accept_proper = |self_: &Self, visitor: &mut V, ctx: &mut TraversalContextStack, tp: MemberVarDeclarationTraversalPolicy| { + for ch in self_.children_detailed().must_be_named(true) { + match ch { + Err(e) if tp.traverse_errors => { + e.accept(visitor, ctx); + }, + _ => {} + } + } + }; + if ctx.top() == TraversalContext::Global { - visitor.visit_global_var_decl(self); + let tp = visitor.visit_global_var_decl(self); + + accept_proper(self, visitor, ctx, tp); + + visitor.exit_global_var_decl(self); } else { - visitor.visit_member_var_decl(self, ctx); + let tp = visitor.visit_member_var_decl(self, ctx); + + accept_proper(self, visitor, ctx, tp); + + visitor.exit_member_var_decl(self, ctx); } } } \ No newline at end of file diff --git a/crates/core/src/syntax_error.rs b/crates/core/src/syntax_error.rs index 50c4419..aef8b87 100644 --- a/crates/core/src/syntax_error.rs +++ b/crates/core/src/syntax_error.rs @@ -31,8 +31,11 @@ impl<'script> SyntaxNodeTraversal for ErrorNode<'script> { let tp = visitor.visit_error(self, ctx); ctx.push(TraversalContext::Error); if tp.traverse { - for ch in self.children().allow_errors(true) { - ch.accept(visitor, ctx); + for res in self.children_detailed() { + match res { + Ok((n, _)) => n.accept(visitor, ctx), + Err(e) => e.accept(visitor, ctx) + } } } ctx.pop(); diff --git a/crates/core/src/syntax_node.rs b/crates/core/src/syntax_node.rs index 38f9a09..06bf571 100644 --- a/crates/core/src/syntax_node.rs +++ b/crates/core/src/syntax_node.rs @@ -28,7 +28,7 @@ impl<'script, T> SyntaxNode<'script, T> { phantom: PhantomData, } } - + //TODO rename to unsafe_into /// Interpret this node into a node with a different underlying type. /// Gives no guarantees as to whether that target type is actually valid, so it's not exposed by the crate #[inline] @@ -41,15 +41,6 @@ impl<'script, T> SyntaxNode<'script, T> { AnyNode::new(self.tree_node) } - #[inline] - pub fn into_result(self) -> Result, ErrorNode<'script>> { - if self.is_error() { - Err(self.into()) - } else { - Ok(self.into()) - } - } - /// Returns an iterator over non-error children of this node as AnyNodes #[inline] pub fn children(&self) -> SyntaxNodeChildren<'script> { @@ -88,6 +79,12 @@ impl<'script, T> SyntaxNode<'script, T> { SyntaxNodeFieldChildren::new(&self.tree_node, None, field) } + /// Returns an iterator over children (including errors) of this node as node results with field names + #[inline] + pub fn children_detailed(&self) -> SyntaxNodeChildrenDetailed<'script> { + SyntaxNodeChildrenDetailed::new(&self.tree_node, None).must_be_named(false) + } + /// Invoke a function using cursor stored in self. The invoked function should return back the cursor it got in the parameter. /// Cursor is created only for the first and only time on the first call of [`Self::use_cursor`] on self. /// Thanks to this method a new cursor doesn't need to be unnecesaily allocated @@ -289,10 +286,7 @@ pub struct SyntaxNodeChildren<'script> { cursor: ts::TreeCursor<'script>, any_children_left: bool, - must_be_named: bool, - allow_errors: bool, - - pub prev_field_name: Option<&'static str>, + must_be_named: bool } impl<'script> SyntaxNodeChildren<'script> { @@ -303,10 +297,8 @@ impl<'script> SyntaxNodeChildren<'script> { Self { cursor, any_children_left, - prev_field_name: None, - must_be_named: false, - allow_errors: false + must_be_named: false } } @@ -314,11 +306,6 @@ impl<'script> SyntaxNodeChildren<'script> { self.must_be_named = b; self } - - pub fn allow_errors(mut self, b: bool) -> Self { - self.allow_errors = b; - self - } } impl<'script> Iterator for SyntaxNodeChildren<'script> { @@ -328,7 +315,7 @@ impl<'script> Iterator for SyntaxNodeChildren<'script> { if self.any_children_left { let mut n = self.cursor.node(); while n.is_extra() - || (!self.allow_errors && n.is_error()) + || n.is_error() || (self.must_be_named && !n.is_named()) { if self.cursor.goto_next_sibling() { n = self.cursor.node(); @@ -337,7 +324,6 @@ impl<'script> Iterator for SyntaxNodeChildren<'script> { } } - self.prev_field_name = self.cursor.field_name(); self.any_children_left = self.cursor.goto_next_sibling(); Some(AnyNode::new(n)) } else { @@ -394,6 +380,66 @@ impl<'script> Iterator for SyntaxNodeFieldChildren<'script> { +pub struct SyntaxNodeChildrenDetailed<'script> { + cursor: ts::TreeCursor<'script>, + any_children_left: bool, + + must_be_named: bool +} + +impl<'script> SyntaxNodeChildrenDetailed<'script> { + fn new(tree_node: &ts::Node<'script>, cursor: Option>) -> Self { + let mut cursor = cursor.unwrap_or(tree_node.walk()); + let any_children_left = cursor.goto_first_child(); + + Self { + cursor, + any_children_left, + + must_be_named: false + } + } + + pub fn must_be_named(mut self, b: bool) -> Self { + self.must_be_named = b; + self + } +} + +impl<'script> Iterator for SyntaxNodeChildrenDetailed<'script> { + type Item = Result<(AnyNode<'script>, Option<&'static str>), ErrorNode<'script>>; + + fn next(&mut self) -> Option { + if self.any_children_left { + let mut n = self.cursor.node(); + while n.is_extra() + || (self.must_be_named && !n.is_named()) { + if self.cursor.goto_next_sibling() { + n = self.cursor.node(); + } else { + return None; + } + } + + + let res = if n.is_error() { + Err(ErrorNode::new(n)) + } else { + let field_name = self.cursor.field_name(); + Ok((AnyNode::new(n), field_name)) + }; + + self.any_children_left = self.cursor.goto_next_sibling(); + + Some(res) + } else { + None + } + } +} + + + /// Describes the name, by which a node is identified in tree-sitter's grammar pub trait NamedSyntaxNode { const NODE_KIND: &'static str;