Skip to main content

hermes_ast/
visitor.rs

1//! AST traversal.
2use crate::node::{Node, NodeField};
3use crate::context::GCLock;
4
5/// Read-only visitor. Implementors override `visit_node`; the default recurses.
6/// (Unchanged from phase 1 — used by the GC marker in `context.rs`.)
7pub trait Visitor<'gc> {
8    /// Called once for `node`. The default recurses into its children.
9    fn visit_node(&mut self, node: &'gc Node<'gc>) {
10        node.visit_children(self);
11    }
12}
13
14/// The path to the node currently being visited: its parent and the field of
15/// the parent it occupies. Mirrors juno's `Path`.
16#[derive(Debug, Copy, Clone)]
17pub struct Path<'gc> {
18    /// The node that owns the field being visited.
19    pub parent: &'gc Node<'gc>,
20    /// Which structural child field of `parent` the visited node occupies.
21    pub field: NodeField,
22}
23
24impl<'gc> Path<'gc> {
25    /// Build a path from a parent node and one of its child fields.
26    pub fn new(parent: &'gc Node<'gc>, field: NodeField) -> Path<'gc> {
27        Path { parent, field }
28    }
29}
30
31/// What a [`VisitorMut`] did to an element of the AST.
32#[derive(Debug)]
33pub enum TransformResult<T> {
34    /// No change.
35    Unchanged,
36    /// Remove the element if possible. A required single child that is removed
37    /// is replaced with an `EmptyStatement`; an optional child becomes `None`;
38    /// a list element is dropped.
39    Removed,
40    /// Replace the element with the wrapped one.
41    Changed(T),
42    /// Replace the element with several (only valid inside a `NodeList`).
43    Expanded(Vec<T>),
44}
45
46/// The transforming visitor. `call` returns how `node` should be transformed.
47/// A typical impl matches specific nodes and otherwise recurses+rebuilds via
48/// `node.visit_children_mut(ctx, self)`.
49pub trait VisitorMut<'gc> {
50    /// Visit `node`, reached via `path` (`None` at the root), and return how
51    /// it should be transformed.
52    fn call(
53        &mut self,
54        ctx: &'gc GCLock<'_, '_>,
55        node: &'gc Node<'gc>,
56        path: Option<Path<'gc>>,
57    ) -> TransformResult<&'gc Node<'gc>>;
58}