PEGO

G040: Copy-on-Change Attribute Normalization

Preparing a grammar should not copy every expression node when its attributes and children already have the normalized form. Copy-on-change reuses unchanged paths.

Mechanism and Invariants

NormalizeAttributes returns an original node when no supported child or attribute changes. A changed descendant requires copying each modified ancestor before replacement, preserving the source AST. Attribute order, binding, validation, diagnostics and legacy nil/empty container shapes remain exact. Opaque extension values remain opaque. The prepared grammar can share unchanged nodes with its source; it is not a detached deep copy.

Scope and State

Default shared compilation/generation preprocessing. Matching in all six backends is unchanged. No standalone runtime attribute-normalization path is implied.

Reference Control

Internal compilation option EagerAttributeCopies restores the eager same-source normalizer. Selection occurs during compilation and adds no matching-loop branch.

Evidence and Implementation

Record 095 reports workload-specific allocation reductions and a longer recheck that did not reproduce an initial synthetic slowdown. Generated parsers remain byte-identical. These compilation measurements do not establish a universal preparation speedup or a matching benefit.

Evidence records: 095.

Source owners: NormalizeAttributes, Options.EagerAttributeCopies, source immutability and reference checks.

The comparison policy distinguishes same-source controls, historical changes and full checkpoints.

Related mechanisms: G080, G090.

Optimization Catalog