Skip to content

fix: 89 non-reserved keywords now work as identifiers (#696) - #714

Open
dpsiderius wants to merge 1 commit into
fix/698-leading-trailing-commentsfrom
fix/696-fallback-keywords
Open

dpsiderius wants to merge 1 commit into
fix/698-leading-trailing-commentsfrom
fix/696-fallback-keywords

Conversation

@dpsiderius

Copy link
Copy Markdown
Contributor

Stacked on #698 (fix/698-leading-trailing-comments) — merge that first.

What

parse.y's %fallback set: 89 of our 146 reserved keywords are non-reserved
in SQLite — they act as keywords where the grammar expects one and as
ordinary identifiers everywhere else. Threaded fallback acceptance through
identifier() (the single choke point) and the bare column-reference arm
of primary_expr.

Regression found and fixed during development: extending bare
(no-AS) alias parsing to fallback keywords broke a NATURAL JOIN b /
t LEFT JOIN (...)NATURAL/LEFT got swallowed as an alias. Reverted
that part; AS <fallback-keyword> is the safe form and is what SQLite's
grammar actually allows.

Oracle-measured

  • All 89 fallback words accepted as column names, matching the oracle.
  • All 57 truly reserved words still rejected, matching the oracle.
  • SQE's exact table — CREATE TABLE p(namespace TEXT, key TEXT, value TEXT, PRIMARY KEY(namespace, key)) + INSERT + SELECT — byte-identical
    to the oracle.
  • Each word used both as a keyword and as an identifier in one statement
    (PRIMARY KEY(key) + ORDER BY key) passes.
  • .openspec/grammar/sqlite.ebnf's identifier rule gained the
    fallback-keyword alternative, [parse.y:272 fallback] annotated;
    make check-grammar-drift passes.

Bonus: fixed one previously-misclassified extracted SELECT baseline
(SELECT_INVALID_BASELINE ratcheted 2→1).

Test plan

  • tests/corpus/ — 5 new fallback-keyword tests, all oracle-diffed.
  • make test, make lint, make test-corpus, make check-grammar-drift, make check-mvl-limit, make check-mod-files, make assurance all pass.

Refs: 002/Req-2, #678, #695
Closes #696

spend: matched estimate

…2 fallback (#696)

We reserved all 146 keywords unconditionally; real SQLite's `parse.y:272`
`%fallback ID` declares 89 of them non-reserved, retrying them as a plain
ID wherever the grammar can't shift them as the keyword itself. That
blocked schemas as ordinary as `CREATE TABLE p(namespace TEXT, key TEXT,
value TEXT, PRIMARY KEY(namespace, key))` -- SQE's actual table.

`parser::grammar`'s `identifier()` is the single choke point nearly every
identifier-accepting production already funneled through (table/column
names, PRIMARY KEY column lists, USING columns, aliases via `AS`, ...),
so threading fallback acceptance through it is one change plus a mirror
in `primary_expr`'s bare-column-reference arm (needed separately since
that arm matches on `TokenKind` directly rather than calling
`identifier()`). `tokenizer::is_fallback_keyword`/`keyword_text` hold the
89-word set and its reverse lookup back to source text.

Deliberately not extended to a bare (no-`AS`) alias: doing so regressed
`SELECT * FROM a NATURAL JOIN b` and `t LEFT JOIN (...)` by swallowing
NATURAL/LEFT as a bare alias for the preceding table -- real SQLite
resolves that via LALR shift/reduce precedence this recursive-descent
parser has no equivalent for. `AS <fallback-keyword>` is the safe,
unambiguous form and is what the ticket requires.

tests/corpus/fallback_keyword_test.rs diffs all 89 fallback words and all
57 still-reserved words against the pinned oracle as column names, plus
the SQE table end-to-end, the both-keyword-and-identifier-in-one-statement
case (`PRIMARY KEY(key)` + `ORDER BY key`), and `AS first`.

tests/corpus/extracted_sql_test.rs's SELECT_INVALID_BASELINE ratchet drops
2 -> 1: one previously-misclassified extracted SELECT now parses.

.openspec/grammar/sqlite.ebnf's `identifier` rule gains the
`fallback-keyword` alternative, annotated `[parse.y:272 fallback]`;
`make check-grammar-drift` clean (the annotation isn't a Lemon
nonterminal, so it isn't part of the rule-name coverage count, same as
the file's existing `%token_class`/`%fallback` header note).

Refs: 002/Req-2

spend: within the "medium" estimate.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: 89 keywords are reserved that SQLite treats as identifiers (parse.y's %fallback) — blocks SQE's 'key' column

1 participant