Expand description
Arena-to-arena AST transformation via the Fold trait.
§Overview
Fold is the transformation counterpart of crate::visitor::Visitor.
Where Visitor walks a tree read-only, Fold rebuilds it — reading from an
input node (in any arena '_) and writing into a caller-supplied output arena
'new. This is the only sound design for arena-allocated ASTs: in-place
mutation (VisitorMut) would let you write a &'new Expr into a slot that
requires a &'old Expr, silently breaking the arena lifetime invariant.
§Lifetimes
'src— the source-text lifetime, bound on theFoldtrait.&'src strslices that point directly into the original PHP source are passed through unchanged across the fold; they are never re-allocated.'new— the output arena lifetime; a generic on each method so oneimpl Fold<'src>can fold into different arenas over its lifetime.'_— the input arena lifetime, intentionally erased. The fold never reads back through output-arena pointers, so the input and output arenas are fully independent.
§Arena-allocated strings
Several AST nodes store &'arena str values that were not borrowed from
the source buffer — for example string literals, StmtKind::Label, and
ExprKind::Nowdoc values. The identity fold re-allocates these via
arena.alloc_str(s) so the output nodes are self-contained within the
new arena. Source-borrowed NameStr values (NameStr::__src) are
preserved as-is without copying.
§Usage
use bumpalo::Bump;
use php_ast::fold::{Fold, fold_program};
use php_ast::ast::*;
/// An identity fold — rebuilds the AST without changes.
struct Identity;
impl<'src> Fold<'src> for Identity {}
// Fold `program` (in `src_arena`) into `out_arena`:
// let folded = Identity.fold_program(&out_arena, &program);To transform specific nodes, override the corresponding method and call the
free fold_* function for the default recursion:
use bumpalo::Bump;
use php_ast::fold::{Fold, fold_expr};
use php_ast::ast::*;
struct NegateInts;
impl<'src> Fold<'src> for NegateInts {
fn fold_expr<'new>(&mut self, arena: &'new Bump, expr: &Expr<'_, 'src>) -> Expr<'new, 'src> {
if let ExprKind::Int(n) = expr.kind {
return Expr { kind: ExprKind::Int(-n), span: expr.span };
}
fold_expr(self, arena, expr)
}
}Traits§
- Fold
- Trait for arena-to-arena PHP AST transformation.