From b7005e8378e217149013cf8e071e4a7274bb871a Mon Sep 17 00:00:00 2001 From: Peter Ammon Date: Sat, 3 May 2025 19:45:30 -0700 Subject: [PATCH] ast: clean up NodeVisitorMut This eliminates a bunch of the different functions from NodeVisitorMut. It also removes the runtime polymorphism - now it's a generic instead of using &dyn. The reason is that there's only one implementation of NodeVisitorMut so there's no size savings from polymorphism. --- src/ast.rs | 94 +++++++++++++----------------------------------------- 1 file changed, 22 insertions(+), 72 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 3461aea3f..47e018ba5 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -63,30 +63,19 @@ pub struct MissingEndError { pub type VisitResult = ControlFlow; -/** - * Similar to NodeVisitor, but for mutable nodes. - * - * Note that this breaks out various node types into their own functions. - */ +/// Similar to NodeVisitor, but for mutable nodes. trait NodeVisitorMut { /// will_visit (did_visit) is called before (after) a node's fields are visited. - fn will_visit_fields_of(&mut self, node: &mut dyn NodeMut); - fn visit_mut(&mut self, node: &mut dyn NodeMut) -> VisitResult; - fn did_visit_fields_of<'a>(&'a mut self, node: &'a dyn NodeMut, flow: VisitResult); + fn will_visit_fields_of(&mut self, node: &mut N); + fn visit_mut(&mut self, node: &mut N) -> VisitResult; + fn did_visit_fields_of<'a, N: NodeMut>(&'a mut self, node: &'a mut N, flow: VisitResult); fn visit_argument_or_redirection(&mut self, _node: &mut ArgumentOrRedirection) -> VisitResult; fn visit_block_statement_header(&mut self, _node: &mut BlockStatementHeader) -> VisitResult; fn visit_statement(&mut self, _node: &mut Statement) -> VisitResult; - fn visit_decorated_statement_decorator( - &mut self, - _node: &mut Option, - ); - fn visit_job_conjunction_decorator(&mut self, _node: &mut Option); - fn visit_else_clause(&mut self, _node: &mut Option); - fn visit_semi_nl(&mut self, _node: &mut Option); - fn visit_time(&mut self, _node: &mut Option); - fn visit_token_background(&mut self, _node: &mut Option); + // Visit an optional field, perhaps populating it. + fn visit_optional_mut(&mut self, node: &mut Option) -> VisitResult; } /** @@ -95,11 +84,11 @@ fn visit_decorated_statement_decorator( * It generally invokes the right visit() method on each of its children. */ trait AcceptorMut { - fn accept_mut(&mut self, visitor: &mut dyn NodeVisitorMut); + fn accept_mut(&mut self, visitor: &mut V); } impl AcceptorMut for Option { - fn accept_mut(&mut self, visitor: &mut dyn NodeVisitorMut) { + fn accept_mut(&mut self, visitor: &mut V) { if let Some(node) = self { node.accept_mut(visitor) } @@ -364,7 +353,7 @@ fn allows_keyword(&self, kw: ParseKeyword) -> bool { } /// This is for optional values and for lists. -trait CheckParse { +trait CheckParse: Default { /// A true return means we should descend into the production, false means stop. fn can_be_parsed(pop: &mut Populator<'_>) -> bool; } @@ -410,7 +399,7 @@ fn accept<'a>(&'a self, visitor: &mut dyn NodeVisitor<'a>) {} } impl AcceptorMut for $name { #[allow(unused_variables)] - fn accept_mut(&mut self, visitor: &mut dyn NodeVisitorMut) { + fn accept_mut(&mut self, visitor: &mut V) { visitor.will_visit_fields_of(self); visitor.did_visit_fields_of(self, VisitResult::Continue(())); } @@ -547,7 +536,7 @@ fn accept<'a>(&'a self, visitor: &mut dyn NodeVisitor<'a>) { } impl AcceptorMut for $name { - fn accept_mut(&mut self, visitor: &mut dyn NodeVisitorMut) { + fn accept_mut(&mut self, visitor: &mut V) { visitor.will_visit_fields_of(self); let flow = self .0 @@ -579,7 +568,7 @@ fn accept<'a>(&'a self, visitor: &mut dyn NodeVisitor<'a>){ } impl AcceptorMut for $name { #[allow(unused_variables)] - fn accept_mut(&mut self, visitor: &mut dyn NodeVisitorMut) { + fn accept_mut(&mut self, visitor: &mut V) { visitor.will_visit_fields_of(self); let flow = visitor_accept_field!( accept_mut, @@ -681,32 +670,10 @@ macro_rules! visit_optional_field { $field:expr, $visitor:ident ) => {{ - visit_optional_field_mut!($field_type, $field, $visitor); - VisitResult::Continue(()) + $visitor.visit_optional_mut(&mut $field) }}; } -macro_rules! visit_optional_field_mut { - (DecoratedStatementDecorator, $field:expr, $visitor:ident) => { - $visitor.visit_decorated_statement_decorator(&mut $field); - }; - (JobConjunctionDecorator, $field:expr, $visitor:ident) => { - $visitor.visit_job_conjunction_decorator(&mut $field); - }; - (ElseClause, $field:expr, $visitor:ident) => { - $visitor.visit_else_clause(&mut $field); - }; - (SemiNl, $field:expr, $visitor:ident) => { - $visitor.visit_semi_nl(&mut $field); - }; - (KeywordTime, $field:expr, $visitor:ident) => { - $visitor.visit_time(&mut $field); - }; - (TokenBackground, $field:expr, $visitor:ident) => { - $visitor.visit_token_background(&mut $field); - }; -} - /// A redirection has an operator like > or 2>, and a target like /dev/null or &1. /// Note that pipes are not redirections. #[derive(Default, Debug)] @@ -748,7 +715,7 @@ fn accept<'a>(&'a self, visitor: &mut dyn NodeVisitor<'a>) { } } impl AcceptorMut for ArgumentOrRedirection { - fn accept_mut(&mut self, visitor: &mut dyn NodeVisitorMut) { + fn accept_mut(&mut self, visitor: &mut V) { visitor.will_visit_fields_of(self); let flow = visitor.visit_argument_or_redirection(self); visitor.did_visit_fields_of(self, flow); @@ -842,7 +809,7 @@ fn accept<'a>(&'a self, visitor: &mut dyn NodeVisitor<'a>) { } impl AcceptorMut for Statement { - fn accept_mut(&mut self, visitor: &mut dyn NodeVisitorMut) { + fn accept_mut(&mut self, visitor: &mut V) { visitor.will_visit_fields_of(self); let flow = visitor.visit_statement(self); visitor.did_visit_fields_of(self, flow); @@ -1473,7 +1440,7 @@ fn accept<'a>(&'a self, visitor: &mut dyn NodeVisitor<'a>) { } } impl AcceptorMut for BlockStatementHeader { - fn accept_mut(&mut self, visitor: &mut dyn NodeVisitorMut) { + fn accept_mut(&mut self, visitor: &mut V) { visitor.will_visit_fields_of(self); let flow = visitor.visit_block_statement_header(self); visitor.did_visit_fields_of(self, flow); @@ -2023,7 +1990,7 @@ struct Populator<'a> { } impl<'s> NodeVisitorMut for Populator<'s> { - fn visit_mut(&mut self, node: &mut dyn NodeMut) -> VisitResult { + fn visit_mut(&mut self, node: &mut N) -> VisitResult { use KindMut as KM; match node.kind_mut() { // Leaves @@ -2077,7 +2044,7 @@ fn visit_mut(&mut self, node: &mut dyn NodeMut) -> VisitResult { VisitResult::Continue(()) } - fn will_visit_fields_of(&mut self, node: &mut dyn NodeMut) { + fn will_visit_fields_of(&mut self, node: &mut N) { FLOGF!( ast_construction, "%*swill_visit %ls", @@ -2088,7 +2055,7 @@ fn will_visit_fields_of(&mut self, node: &mut dyn NodeMut) { self.depth += 1 } - fn did_visit_fields_of<'a>(&'a mut self, node: &'a dyn NodeMut, flow: VisitResult) { + fn did_visit_fields_of<'a, N: NodeMut>(&'a mut self, node: &'a mut N, flow: VisitResult) { self.depth -= 1; if self.unwinding { @@ -2195,26 +2162,9 @@ fn visit_statement(&mut self, node: &mut Statement) -> VisitResult { VisitResult::Continue(()) } - fn visit_decorated_statement_decorator( - &mut self, - node: &mut Option, - ) { - *node = self.try_parse::(); - } - fn visit_job_conjunction_decorator(&mut self, node: &mut Option) { - *node = self.try_parse::(); - } - fn visit_else_clause(&mut self, node: &mut Option) { - *node = self.try_parse::(); - } - fn visit_semi_nl(&mut self, node: &mut Option) { - *node = self.try_parse::(); - } - fn visit_time(&mut self, node: &mut Option) { - *node = self.try_parse::(); - } - fn visit_token_background(&mut self, node: &mut Option) { - *node = self.try_parse::(); + fn visit_optional_mut(&mut self, node: &mut Option) -> VisitResult { + *node = self.try_parse::(); + VisitResult::Continue(()) } }