We should extend the Visitor API to make it easily consumable downstream.
Proposal
pub struct VisitCtx<'a> {
pub cst: &'a Cst,
text: &'a str,
ancestors: &'a [NodeId],
}
impl VisitCtx<'_> {
pub fn text(&self, span: Span) -> &str;
pub fn ancestors(&self) -> &[NodeId];
pub fn parent(&self) -> Option<NodeId>;
pub fn depth(&self) -> usize;
}
// Visitor
fn enter_tree(&mut self, ctx: &VisitCtx, node: &Node, id: NodeId) -> Visit;
fn exit_tree(&mut self, ctx: &VisitCtx, node: &Node, id: NodeId) -> Visit;
fn visit_token(&mut self, ctx: &VisitCtx, token: &Token, id: TokenId, parent: NodeId) -> Visit;
// Cst
pub fn walk_range<V: Visitor>(&self, range: Span, text: &str, visitor: &mut V)
Visit semantics
#188 landed the contract at the CST layer: exit_tree runs exactly once for every entered node while a Stop unwinds, Skip is scoped per callback, and Cst::walk returns WalkOutcome. Two things follow for this issue:
AST layer
The scope stack use case exists identically one layer up, and the AST Visitor from #185 has no ctx at all. Once AST nodes carry their originating NodeId (see #176), the AST visitor can reuse the same VisitCtx shape with ancestors as CST ids resolved on demand, so the machinery is written once instead of per layer.
walk_range
Misc
- If node spans later become
TokenRange derived, a ctx.text_of(id) next to ctx.text(span) keeps callers away from how spans materialize.
Related to alanpq/ritobin-lsp#57
We should extend the Visitor API to make it easily consumable downstream.
Proposal
Visit semantics
#188 landed the contract at the CST layer:
exit_treeruns exactly once for every entered node while aStopunwinds,Skipis scoped per callback, andCst::walkreturnsWalkOutcome. Two things follow for this issue:Stopfrom children skipsexiton every open ancestor, and itswalk_allhas aVisit::Skip => breakarm that skips remaining siblings undocumented. It should adopt the fix!(ltk_ritobin): half-open spans and balanced visitor unwinding #188 contract,WalkOutcomeincluded, so downstream only has one model to hold.AST layer
The scope stack use case exists identically one layer up, and the AST
Visitorfrom #185 has no ctx at all. Once AST nodes carry their originatingNodeId(see #176), the AST visitor can reuse the sameVisitCtxshape withancestorsas CST ids resolved on demand, so the machinery is written once instead of per layer.walk_rangeCst::common_ancestors(ltk_ritobin: Add Locator API #176) so it starts at the deepest node containing the range instead of re-descending from the root.Span::containshalf-open since fix!(ltk_ritobin): half-open spans and balanced visitor unwinding #188, the inclusion rule just needs stating explicitly, probablyintersects.WalkOutcomelikeCst::walkdoes now.Misc
TokenRangederived, actx.text_of(id)next toctx.text(span)keeps callers away from how spans materialize.Related to alanpq/ritobin-lsp#57