Seven frontends borrow rparser.inc's helpers
The measurement (2026-08-19)
-dPXX_NO_RUST alone: 198 errors, none of them Rust's. With Zig also
omitted: 74. With Zig and the six esoteric probes omitted: 0.
| symbol | callers outside rparser | what it actually is |
|---|---|---|
RMakeIdent (72 refs) |
zparser, gparser, eparser, fparser, lparser | AllocNode(AN_IDENT) — an AST constructor |
RSeqAppend (65) |
same | AST statement-list append |
RBinOp (42) |
same | AllocNode(AN_BINOP) |
RStoredName (10) |
zparser (9), eparser (1) | token-char-buffer interning |
RWiden (7) |
zparser (3), fparser, lparser, gparser (2 each) | numeric widening — language semantics |
REmitParamRegSpill (1) |
zparser | emits raw x86-64 (REX bytes) |
Rust was the first skeleton written, so the ones after it reached for what was
there. The R prefix then hid what had happened: it reads as "Rust's", so nobody
asked whether an ALGOL parser should be calling it.
Three layers, three different right answers
This is why the fix is not "move the R functions to a shared file".
-
RMakeIdent/RSeqAppend/RBinOp— share, and they already are. Per [[the-substrate-is-ast-and-ir-not-the-parser]] the AST is the shared substrate; these are AST constructors and sharing them is correct. The bug is only the file and the prefix. Move to a sharedastbuild.inc, drop theR. -
RStoredName— share, but it lies in the error path. Its overflow message reads'Rust: token char buffer overflow'. An Erlang or Zig program that overflows the buffer is told it is Rust. Move and reword. -
RWiden— do NOT share. This isa numeric widening rule, i.e. a piece of one language's specification, and the same doc says duplicate semantics across languages because "a shared parser helper couples two specs and is wrong in both." The concrete case: Zig has no implicit numeric widening at all — it requires explicit casts — yetzparser.inccalls Rust's widening in three places. Whether those three sites sit on a path where it is observable is a Track Z question and is NOT asserted here; what is asserted is that the coupling exists and is the wrong shape. Each frontend should own its widening. -
REmitParamRegSpill— does not belong in a frontend at all. Raw x86-64 register-spill emission, called from Zig's parser. Same species ascparser.inc's_startstub ([[refactor-a-backend-machine-code-lives-in-six-shared-files]]) and as the Pascal-only signal runtime ([[bug-a-only-the-pascal-driver-emits-the-signal-runtime]]) — three frontends now, each holding a private piece of target machinery. That is no longer a coincidence; it is the missing layer between the frontends and the backends showing up once per frontend.
Consequence today
PXX_NO_RUST ships, but it is only usable together with PXX_NO_ZIG and the six
probe defines — documented in the feature ticket rather than enforced, because an
implicit "this define turns on those six" would hide exactly the coupling this
ticket exists to remove. Doing 1-3 makes PXX_NO_RUST stand alone.
MERGED 2026-08-29 — refactor-a-the-greenfield-frontends-share-each-others-parser-helpers
Same finding, filed twice, with two independent measurements of it. Surfaced by
progress check's NEAR-DUP scan (4 shared slug words). Kept here because this
ticket carries the layer analysis; the other is a tombstone in rejected/.
What the duplicate measured that this ticket did not: omitting rparser.inc
breaks zparser.inc in 123 places, plus gparser/eparser/fparser. This
ticket counted 198 errors for PXX_NO_RUST across six frontends. Two
different cuts of one coupling — worth keeping both numbers, since they bound the
job from different directions.
Its framing, which is the stronger statement of why this matters: the
greenfield frontends call each other's support functions, which is exactly what
devdocs/dev/the-substrate-is-ast-and-ir-not-the-parser.md says not to do —
share the AST and the IR, duplicate the parser and its helpers per language.
It costs nothing today and couples two language specs; the price is paid the
first time one spec needs its helper to behave differently, and then it is paid
in the wrong file.
Prio: this ticket 22, the duplicate 18. Left at 22, not averaged and not raised — the higher of two independent low estimates is still a low estimate, and re-ranking on a merge invents a signal neither author gave.