Skip to main content

transform

Function transform 

Source
pub fn transform<N, F>(
    src: &Arena<N>,
    root: Id<N>,
    dst: &mut Arena<N>,
    f: F,
) -> Option<Id<N>>
where N: Node, F: FnMut(N) -> N,
Expand description

Rebuilds the tree rooted at root from src into dst, passing every node through f, and returns the handle of the new root.

This is the rewrite (fold) operation: a copy of the subtree is built in the destination arena, and f gets a chance to replace each node as it is rebuilt. Nodes are processed post-order — every child is rebuilt and allocated into dst before its parent — so when f receives a node, that node’s child handles have already been remapped to point at their new selves in dst. With f set to the identity (|node| node), the result is a faithful deep copy: same shape, same span on every node.

The traversal is the iterative walk, so an arbitrarily deep tree is rebuilt without recursing on the call stack. It assumes a tree — each node reachable from root exactly once; a shared sub-node would be copied once per path to it.

§Returns

The handle of the rebuilt root in dst, or None if root names no live node in src, or if dst runs out of capacity while allocating. Either way dst is left holding whatever was allocated before the stop, and never panics.

§Examples

Deep-copy a tree, doubling every literal on the way:

use ast_lang::{transform, walk, Arena, Flow, Id, Node, Span, Visitor};

#[derive(Clone)]
enum Expr {
    Lit(i64, Span),
    Add(Id<Expr>, Id<Expr>, Span),
}

impl Node for Expr {
    fn span(&self) -> Span {
        match self {
            Expr::Lit(_, s) | Expr::Add(_, _, s) => *s,
        }
    }
    fn each_child(&self, f: &mut dyn FnMut(Id<Self>)) {
        if let Expr::Add(a, b, _) = self {
            f(*a);
            f(*b);
        }
    }
    fn map_children(&self, f: &mut dyn FnMut(Id<Self>) -> Id<Self>) -> Self {
        match self {
            Expr::Lit(v, s) => Expr::Lit(*v, *s),
            Expr::Add(a, b, s) => Expr::Add(f(*a), f(*b), *s),
        }
    }
}

let mut src = Arena::new();
let one = src.alloc(Expr::Lit(1, Span::new(0, 1)));
let two = src.alloc(Expr::Lit(2, Span::new(4, 5)));
let add = src.alloc(Expr::Add(one, two, Span::new(0, 5)));

let mut dst = Arena::new();
let new_root = transform(&src, add, &mut dst, |node| match node {
    Expr::Lit(v, s) => Expr::Lit(v * 2, s),
    other => other,
})
.expect("root is live");

// The rebuilt tree sums to 2*(1) + 2*(2) = 6.
struct Sum(i64);
impl Visitor<Expr> for Sum {
    fn enter(&mut self, _: &Arena<Expr>, _: Id<Expr>, node: &Expr) -> Flow {
        if let Expr::Lit(v, _) = node {
            self.0 += *v;
        }
        Flow::Continue
    }
}
let mut sum = Sum(0);
walk(&dst, new_root, &mut sum);
assert_eq!(sum.0, 6);