E010: Value-Free Rule Bodies
A rule can consume input without retaining the intermediate tree used to match its body. This removes Node and child-list construction when an action needs named captures but no positional body values.
Mechanism and Invariants
leanBody selects value-free lowering for an action that does not read
positional body values ($n).
Streaming bodies keep their general route. Captures still build the values their
actions need.
type B = { B node[string] }
rule ws = [ ]+
rule b = [a-z]
rule a = ws b:b ws => B{B: $b}
a needs $b, but no positional body value. Both ws calls still match and
consume whitespace; their unused Node values are omitted. Capture b still
builds the value stored in B.B. If ws has its own action, ordinary parsing
still evaluates it: an unused call result does not authorize skipping the
callee's action. CST twins, Operators Rule line elision and recognition are
separately analyzed mechanisms.
Scope and State
Applied by default to eligible bodies in closure, both VMs, generated Go Node, typed Go and TypeScript. It does not mean that every value inside a lean body is discarded.
Reference Control
No body-elision-only same-source control is maintained across all backends. Comparing recognition with a valued parse changes the requested operation and cannot isolate this mechanism.
Evidence and Implementation
Record 001 reports historical JSON from 442 to 144 ms and 183 to 76 MB for the combined body/twin/transient-rule change. That result cannot be attributed wholly to body elision; current isolated all-backend effects are unmeasured.
Evidence records: 001.
Source owners: leanBody,
Walker.compileRule, body value lowering, direct body build mode, TypeScript body build mode.
The comparison policy distinguishes same-source controls, historical changes and full checkpoints.