Skip to content

Commit

Permalink
Remove the CST Visitor API
Browse files Browse the repository at this point in the history
  • Loading branch information
Xanewok committed Nov 20, 2023
1 parent 22a2be4 commit b7e986b
Show file tree
Hide file tree
Showing 7 changed files with 0 additions and 303 deletions.
1 change: 0 additions & 1 deletion crates/codegen/parser/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ pub(crate) mod lexer;
pub mod parse_error;
pub mod parse_output;
pub mod text_index;
pub mod visitor;

#[cfg(feature = "slang_napi_interfaces")]
pub mod napi;
75 changes: 0 additions & 75 deletions crates/codegen/parser/runtime/src/visitor.rs
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(()));
}
}
}
}
77 changes: 0 additions & 77 deletions crates/solidity/outputs/cargo/crate/src/generated/visitor.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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.

77 changes: 0 additions & 77 deletions crates/solidity/outputs/npm/crate/src/generated/visitor.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 0 additions & 16 deletions documentation/public/user-guide/cargo-crate/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,24 +46,8 @@ You can then iterate over the resulting children, and assert that they match the
For many code analysis tasks, it is useful to traverse the parse tree and visit each node.
The `Cursor` object allows callers to traverse the parse tree in a pre-order depth-first manner.

This is an internal iterator. The `Cursor` can drive an external iterator i.e. the `Visitor` trait, which is described below.

The below example uses a cursor to collect the names of all contracts in a source file, and returns them as a `Vec<String>`:

```{ .rust }
--8<-- "crates/solidity/outputs/cargo/tests/src/doc_examples/cursor_api.rs"
```

## Visitor API

The `Visitor` trait allows callers to implement a visitor that will be called for each node in the tree.
The `std::ops::ControlFlow` enum coupled with the `Step` enum allows callers to control the traversal behavior.

For example, if the visitor is only interested in the top-level nodes, it can return `ControlFlow::Continue(Step::Over)` to skip the children of the current node.
If the visitor is interested in the children of the current node, it can return `ControlFlow::Continue(Step::In)` to visit them.

The below example defines a visitor that collects the names of all contracts in a source file, and returns them as a `Vec<String>`:

```{ .rust }
--8<-- "crates/solidity/outputs/cargo/tests/src/doc_examples/visitor_api.rs"
```

0 comments on commit b7e986b

Please sign in to comment.