-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
We discussed internally that the Visitor API for (dynamically typed) CST is a lot less useful now that we have the `Iterator` interface implemented in Rust (and hopefully [`Iterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators#iterators) protocol in TS in the future), so let's remove the CST Visitor API altogether. The Visitor [pattern](https://rust-unofficial.github.io/patterns/patterns/behavioural/visitor.html) will be a lot useful once we have typed, heterogenous data such as the new AST (#634), so let's wait until then with designing and exposing such interface.
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@nomicfoundation/slang": minor | ||
--- | ||
|
||
Remove the CST Visitor API in favor of the Cursor API |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,76 +1 @@ | ||
use std::ops::ControlFlow; | ||
use std::rc::Rc; | ||
|
||
use super::{cst::*, cursor::Cursor}; | ||
|
||
/// A Visitor pattern for traversing the CST. | ||
/// | ||
/// The trait supports fallible iteration, i.e. the visitor can early return an error from the visit. | ||
pub trait Visitor<E> { | ||
/// Called when the [`Visitor`] enters a [`RuleNode`]. | ||
fn rule_enter( | ||
&mut self, | ||
_node: &Rc<RuleNode>, | ||
_cursor: &Cursor, | ||
) -> Result<ControlFlow<(), Step>, E> { | ||
Ok(ControlFlow::Continue(Step::In)) | ||
} | ||
|
||
/// Called when the [`Visitor`] exits a [`RuleNode`]. | ||
fn rule_exit(&mut self, _node: &Rc<RuleNode>, _cursor: &Cursor) -> Result<ControlFlow<()>, E> { | ||
Ok(ControlFlow::Continue(())) | ||
} | ||
|
||
/// Called when the [`Visitor`] enters a [`TokenNode`]. | ||
fn token(&mut self, _node: &Rc<TokenNode>, _cursor: &Cursor) -> Result<ControlFlow<()>, E> { | ||
Ok(ControlFlow::Continue(())) | ||
} | ||
} | ||
|
||
/// Whether the [`Visitor`] should should enter the children of a [`RuleNode`] or not. | ||
pub enum Step { | ||
In, | ||
Over, | ||
} | ||
|
||
impl Cursor { | ||
pub fn drive_visitor<E, V: Visitor<E>>( | ||
&mut self, | ||
visitor: &mut V, | ||
) -> Result<ControlFlow<()>, E> { | ||
if self.is_completed() { | ||
return Ok(ControlFlow::Continue(())); | ||
} | ||
|
||
loop { | ||
// Node clone is cheap because it's just an enum around an Rc | ||
match self.node() { | ||
Node::Rule(rule_node) => { | ||
match visitor.rule_enter(&rule_node, self)? { | ||
ControlFlow::Break(()) => return Ok(ControlFlow::Break(())), | ||
ControlFlow::Continue(Step::In) => { | ||
if self.go_to_first_child() { | ||
self.drive_visitor(visitor)?; | ||
self.go_to_parent(); | ||
} | ||
} | ||
ControlFlow::Continue(Step::Over) => {} | ||
} | ||
if visitor.rule_exit(&rule_node, self)? == ControlFlow::Break(()) { | ||
return Ok(ControlFlow::Break(())); | ||
} | ||
} | ||
|
||
Node::Token(token_node) => { | ||
if visitor.token(&token_node, self)? == ControlFlow::Break(()) { | ||
return Ok(ControlFlow::Break(())); | ||
} | ||
} | ||
} | ||
|
||
if !self.go_to_next_sibling() { | ||
return Ok(ControlFlow::Continue(())); | ||
} | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,2 @@ | ||
mod cursor_api; | ||
mod simple_contract; | ||
mod visitor_api; |
This file was deleted.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.