Skip to main content

Module fold

Module fold 

Source
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 the Fold trait. &'src str slices 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 one impl 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.

Functions§

fold_arg
fold_attribute
fold_catch_clause
fold_class_member
fold_enum_member
fold_expr
fold_match_arm
fold_name
fold_name_str
fold_param
fold_program
fold_property_hook
fold_stmt
fold_trait_adaptation
fold_trait_use
fold_type_hint