A normalized AST node. Uses a data-driven { kind, children } representation
instead of a large enum with differently-shaped variants. This allows generic
traversal algorithms (count_nodes, reindex, count_matching, extract) to work
without exhaustive matching on every variant.
Re-index all placeholders in a sub-tree so that indices start from 0
per kind, assigned by first-occurrence depth-first order.
This allows comparing sub-trees extracted from different function contexts.