G050: One Generated Form per Option Set
Resource checks can cost generated parsing even when no work control is active. A generated Go parser therefore has one form of its functions, chosen at generation time by the options.
Mechanism and Invariants
The generator prints each execution function (rule bodies and other functions taking the parser as their first parameter) once, from Flow IR, in the form the options select:
- Without
-work-controlsand without-documentthe parser holds the ordinary form only: the 16 runtime helpers that have a hand-writtenOrdinaryform (NewNode,NewTerminal,NewBranch,NewMatch,SetCapture,Expect,Peek,MatchLiteral,MatchLiteralFold,MatchAny,AtEnd,AtLineStart,AtEndBatch,AtLineStartBatch,AtLineEnd,InputWork), no step or input-work charges, no control reads in conditions and class tests, and a compact peek. A parse that passes a control option fails. - With
-work-controlsthe parser holds the controlled form only: step and input-work charges, the general runtime helpers and class tests that consult the control. A parse that sets no limit runs the same code; the few inline tests ofp.Control(in literal and large-class tests) take the unmetered path, and the helpers test the control themselves. The terms of an action carry no charge, and neither do the generated constructors of typed values: only repetition is charged, by the runtime's loops over the elements of a list (map,filter,foldl,foldr), one step per element. - With
-documentthe in-place reads of literals and characters carry the guardp.Document == nil, so that a Document parse reaches the primitives that record what a rule examined. Without-work-controlsthat form has no charges and no control reads.
There is no second body, no run-time choice between forms, and no splice. Metered paths keep their checks, cancellation and budgets. Work accounting is a resource contract, not an optimization in itself. A user who needs both forms generates two parsers.
Scope and State
Applied by default in generated Go Node/recognition and typed Go output. Generated TypeScript chooses its form with the same option but prints its own charges (see G210). Closure and VM work-control implementations do not use this Go mechanism.
Evidence and Implementation
A parser generated with -work-controls has one controlled form of its functions. The parser.go of
the same parser generated without the option is 0.50 to 0.85 of its size (every grammar of parsers/,
Node-only, with -types, with -types -recognize or with -types -typed-only; larger grammars save
more, and duckdb with -typed-only is the smallest at 0.50). A parse that sets no limit runs
the controlled form without a fast path: on the YAML and CSV benchmark inputs it is slower than a
parse of a parser generated without -work-controls by 17% (YAML Parse), 27% (YAML Recognize),
27% (CSV Parse) and 69% (CSV Recognize). Records
096 and
121 hold earlier measurements of the ordinary body of a
function and of the inlined runtime helpers.
Source owners: Flow printer, helper names, metered runtime helpers.
The comparison policy distinguishes same-source controls, historical changes and full checkpoints.