///|
/// One method per node category, for `accept`. Every `visit_*` method
/// defaults to `Continue` and `leave` to nothing, so a visitor implements
/// only what it needs; the `Control` it returns steers the walk as in
/// `walk`.
pub(open) trait Visitor {
/// The file.
fn visit_file(Self, NodeRef) -> Control = _
/// Control, metadata, namespace and use statements.
fn visit_statement(Self, NodeRef) -> Control = _
/// Shape statements, apply statements and inline shapes.
fn visit_shape(Self, NodeRef) -> Control = _
/// Members and enum members.
fn visit_member(Self, NodeRef) -> Control = _
/// Applied traits.
fn visit_trait(Self, NodeRef) -> Control = _
/// Node values and their object entries.
fn visit_value(Self, NodeRef) -> Control = _
/// Doc comments and comments.
fn visit_comment(Self, NodeRef) -> Control = _
/// Every other node: mixins, operation properties, shape IDs and names.
fn visit_other(Self, NodeRef) -> Control = _
/// Runs after a node's children, as in `walk`.
fn leave(Self, NodeRef) -> Unit = _
}
///|
impl Visitor with fn visit_file(_self, _node) {
Continue
}
///|
impl Visitor with fn visit_statement(_self, _node) {
Continue
}
///|
impl Visitor with fn visit_shape(_self, _node) {
Continue
}
///|
impl Visitor with fn visit_member(_self, _node) {
Continue
}
///|
impl Visitor with fn visit_trait(_self, _node) {
Continue
}
///|
impl Visitor with fn visit_value(_self, _node) {
Continue
}
///|
impl Visitor with fn visit_comment(_self, _node) {
Continue
}
///|
impl Visitor with fn visit_other(_self, _node) {
Continue
}
///|
impl Visitor with fn leave(_self, _node) {
()
}
///|
fn[V : Visitor] dispatch(visitor : V, n : NodeRef) -> Control {
match n {
File(_, _) => visitor.visit_file(n)
Control(_) | Metadata(_) | Namespace(_) | Use(_) =>
visitor.visit_statement(n)
Shape(_) | Apply(_) | Inline(_) => visitor.visit_shape(n)
Member(_) | EnumMember(_) => visitor.visit_member(n)
Trait(_) => visitor.visit_trait(n)
Value(_) | Entry(_) => visitor.visit_value(n)
Doc(_) | Comment(_) => visitor.visit_comment(n)
Mixins(_) | Property(_) | ShapeIdRef(_) | Name(_) => visitor.visit_other(n)
}
}
///|
/// Walk `root` and call one `Visitor` method per node by its category, and
/// `leave` after its children, in `walk`'s order.
///
/// A visitor is a type of yours with `impl Visitor` for the methods it
/// needs; its own fields hold its state.
pub fn[V : Visitor] accept(root : NodeRef, visitor : V) -> Unit {
walk(root, n => dispatch(visitor, n), leave=n => visitor.leave(n))
}