Syntax.Walk
Generic traversal over the surface syntax tree.
The design is uniplate-shaped: two hand-written total functions per sort give the immediate same-sort children of a node (expr_children) and put a replacement child list back (expr_rebuild), and every generic operation derives from that pair (expr_universe, expr_count, expr_any, expr_fold, and every strategy in Control.Rewrite applied to expr_layer). The one-layer functions are the only place that names constructors, so a new Expr constructor is one arm in each and every derived traversal follows; totality of the two matches is the drift guard.
The pair is written out rather than derived, and the reason is the span. deriving (Plate) walks through a carrier record, so a derived instance on Expr yields children of type Expr with the spanned wrappers already consumed: its rebuild puts the original spans back, but its children has dropped them, and a spanned child is what every query here returns. Deriving on the wrapper instead yields no children at all, because an Sp(a) holds no Sp(a). The instance that would say the right thing is one at Sp(Expr), and it cannot be written: a deriving clause names a declaration rather than an instantiation, and instance dispatch keys on the head constructor alone, so Sp(Expr) and Sp(Pat) would be a single instance.
Functions and Values
expr_children
expr_children : (Syntax.Ast.Sp(Syntax.Ast.Expr)) -> List(Syntax.Ast.Sp(Syntax.Ast.Expr))
The immediate Expr children of one node, in source order. Children held inside carrier records (match arms, handler arms, qualifiers, path steps and updates, parameter defaults, named fields) are included; a leaf yields the empty list.
expr_rebuild
expr_rebuild : (Syntax.Ast.Sp(Syntax.Ast.Expr), List(Syntax.Ast.Sp(Syntax.Ast.Expr))) -> Syntax.Ast.Sp(Syntax.Ast.Expr)
Put a replacement child list back into one node, in expr_children order, keeping the node’s span and its synthetic bit.
This is the inverse half of expr_children, and the pair is everything a generic strategy needs to descend a tree. It fails closed: a child list that does not match the node’s shape (a different length, a carrier arity that does not line up) yields the node unchanged rather than a silently reshaped one, so expr_rebuild(e, expr_children(e)) is the identity and a garbage child list cannot forge a node.
expr_layer
expr_layer : () -> Control.Layer.Layer(Syntax.Ast.Sp(Syntax.Ast.Expr))
The children-and-rebuild pair for spanned expressions, which is what every strategy in Control.Rewrite and every query in Control.Layer takes.
expr_universe
expr_universe : (Syntax.Ast.Sp(Syntax.Ast.Expr)) -> List(Syntax.Ast.Sp(Syntax.Ast.Expr))
Every node of the tree, root first, in depth-first source order.
expr_count(lit_probe(7))
1
lit_probe
lit_probe : (Int) -> Syntax.Ast.Sp(Syntax.Ast.Expr)
A span-zero literal, a convenience for building test trees.
expr_count
expr_count : (Syntax.Ast.Sp(Syntax.Ast.Expr)) -> Int
The number of nodes in the tree.
expr_any
expr_any : ((Syntax.Ast.Sp(Syntax.Ast.Expr)) -> Bool, Syntax.Ast.Sp(Syntax.Ast.Expr)) -> Bool
Whether any node satisfies the predicate.
expr_fold
expr_fold : forall e0 a. ((a, Syntax.Ast.Sp(Syntax.Ast.Expr)) -> a ! {e0}, a, Syntax.Ast.Sp(Syntax.Ast.Expr)) -> a ! {e0}
Left-fold the accumulator through every node, root first.