Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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.