ANSWER: is a grammar a convention, or a region?

Both, at different layers -- and it is the same split as serialization: the
convention is the BASIS, never the ACT.

  lexeme -> token      `fn` means function-start because someone said so   CONVENTION
  shape recognition    given tokens, which construct is this               REGION
  source -> structure  parsing is transduction onto that basis             GEOMETRY
  byte traversal       something must read them in order                   IRREDUCIBLE

Three things push the ACT toward region rather than convention: ambiguity
(a * b needs context; a grammar resolves it with the lexer hack, a region by
neighbourhood), error recovery (nearest-region is free), and precedence, which
is ordering along an axis with a conventional parameter.

AND THE SHOULD GATE SAYS NO TO THE OBVIOUS MOVE

Every other table this session moved to data. This one stays code. The keyword
set is CLOSED by the language definition -- it does not leak the way an
allowlist does -- and the lexer runs before the program is understood, so a
program can never declare its own keywords. Externalising it costs file I/O on
every compile and buys nothing. Same verdict as is_digit in ASCII.

WHAT WAS ACTUALLY WRONG: five of 46 keywords were consumed by no parser or
codegen path. sealed, activate, seed, protocol, impl. Each stole an identifier
from users for nothing.

SECOND SILENT MISCOMPILATION OF THE DAY. Using one did not fail to parse:

    let seed = 42
    let impl = seed + 1

compiled CLEAN -- zero cc errors -- and printed 0 instead of 44. No diagnostic
at any layer. Fixed by removing the five.

A DEFECT IN MY OWN MEASUREMENT, caught before it did damage: my first pass
checked only parser.el and reported `test` as inert too. codegen consumes it at
4135 for --test mode, and the tree has 408 uses. Removing it would have broken
every test in the suite. The measurement was re-run across all four consumers.

100/100 native + 2 new, 31/31 integration, fixpoint ok.
This commit is contained in:
bigmerge
2026-08-17 09:43:58 -05:00
parent 15d4352bac
commit 0143cc458a
2 changed files with 40 additions and 5 deletions
+16 -5
View File
@@ -145,6 +145,22 @@ fn tok_append(tokens: [Any], kind: String, value: String) -> [Any] {
// -- Keyword lookup ------------------------------------------------------------
// keyword_kind the language's reserved spellings.
//
// A grammar is a BASIS: `fn` means function-start because someone said so, and
// nothing derives it. But unlike the other tables moved out this session, this
// one stays code, and the SHOULD gate is why. The keyword set is closed by the
// language definition -- it does not leak the way an allowlist does -- and the
// lexer runs before the program is understood, so a program can never declare
// its own keywords. Externalising it would cost file I/O on every compile and
// buy nothing.
//
// Removed 2026-08-17: sealed, activate, seed, protocol, impl. Reserved in the
// lexer, consumed by no parser or codegen path, and each one stole an
// identifier from users for nothing. `test` LOOKED inert by the same measure
// and is not -- codegen consumes it at 4135 for --test mode, 408 uses in the
// tree. The first measurement checked only parser.el and would have broken all
// of them.
fn keyword_kind(word: String) -> String {
if word == "let" { return "Let" }
if word == "fn" { return "Fn" }
@@ -161,14 +177,9 @@ fn keyword_kind(word: String) -> String {
if word == "from" { return "From" }
if word == "as" { return "As" }
if word == "with" { return "With" }
if word == "sealed" { return "Sealed" }
if word == "activate" { return "Activate" }
if word == "where" { return "Where" }
if word == "test" { return "Test" }
if word == "seed" { return "Seed" }
if word == "assert" { return "Assert" }
if word == "protocol" { return "Protocol" }
if word == "impl" { return "Impl" }
if word == "retry" { return "Retry" }
if word == "times" { return "Times" }
if word == "fallback" { return "Fallback" }