What is the reason for that particular design decision versus providing a more general Visitor implementation?
Two options for a generalised Visitor trait come to mind:
- expose pre + post trait method variants for every AST node type, or
- expose only two trait methods (
pre_visit + post_visit) with signatures like fn pre_visit(&mut self, node: &AstNode) -> ControlFlow<Self::Break> - where AstNode is an enum with a wrapper variant for every AST node type found in src/ast/mod.rs and can be matched against.
Would the maintainers be interested in a PR that implements one of the above two approaches?
My preference would be for option 2 because it would not break the trait when node types are added/removed.
Suggested approach:
- Define a new
RawVisitor trait (and RawVisitorMut trait) like this:
pubtraitRawVisitor{typeBreak;fnpre_visit(&mutself,node:&AstNode) -> ControlFlow<Self::Break>;fnpost_visit(&mutself,node:&AstNode) -> ControlFlow<Self::Break>;}- Define an adapter type (
RawVisitorAdapter ?) that accepts a V: Visitor generic argument and implements RawVisitor & RawVisitorMut, which calls the appropriate method on V (or none at all)
structRawVisitorAdapter<V:Visitor>(v);impl<V:Visitor>RawVisitorforRawVisitorAdapter<V>{typeBreak = V::Break;fnpre_visit(&mutself,node:&AstNode) -> ControlFlow<Self::Break>{match node {AstNode(Statement) => self.0.pre_visit_statement(...),// etc}}fnpost_visit(&mutself,node:&AstNode) -> ControlFlow<Self::Break>;}- Change the
Visit derivation macros to generate code in terms of RawVisitor & RawVisitorMut instead of Visitor, like this:
pubtraitVisit{fnvisit_raw<V:RawVisitor>(&self,visitor:&mutV) -> ControlFlow<V::Break>;// This has an identical signature to the existing trait, but has a default implementationfnvisit<V:Visitor>(&self,visitor:&mutV) -> ControlFlow<V::Break>{self.visit_raw(RawVisitorAdapter::new(visitor))}}
What is the reason for that particular design decision versus providing a more general
Visitorimplementation?Two options for a generalised Visitor trait come to mind:
pre_visit+post_visit) with signatures likefn pre_visit(&mut self, node: &AstNode) -> ControlFlow<Self::Break>- whereAstNodeis an enum with a wrapper variant for every AST node type found insrc/ast/mod.rsand can bematched against.Would the maintainers be interested in a PR that implements one of the above two approaches?
My preference would be for option 2 because it would not break the trait when node types are added/removed.
Suggested approach:
RawVisitortrait (andRawVisitorMuttrait) like this:RawVisitorAdapter?) that accepts aV: Visitorgeneric argument and implementsRawVisitor&RawVisitorMut, which calls the appropriate method onV(or none at all)Visitderivation macros to generate code in terms ofRawVisitor&RawVisitorMutinstead ofVisitor, like this: