PEGO

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-controls and without -document the parser holds the ordinary form only: the 16 runtime helpers that have a hand-written Ordinary form (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-controls the 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 of p.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 -document the in-place reads of literals and characters carry the guard p.Document == nil, so that a Document parse reaches the primitives that record what a rule examined. Without -work-controls that 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.

Related mechanisms: G010, G060.

Optimization Catalog