WHERE expressions: matrix cells + predicate_tail grammar fix (ADR-0026 step 6)

Adds tests/typing_surface/where_expression.rs — 9 matrix
cells for the complex WHERE / show-data limit typing surface:
operator candidates after an operand, AND / OR after a
predicate, NOT, BETWEEN / IN bounds, and `show data`
where / limit.

Writing the cells surfaced a grammar bug. `predicate_tail`'s
`[NOT] negatable` branch started with `Optional(not)`, and an
Optional-first `Seq` always "commits" — so on an incomplete
input the walker's `Choice` returned that branch's
`Incomplete` early and discarded every sibling branch's
expected set, dropping `is` and the comparison operators from
completion after a column. Fixed by splitting it into
explicit `NOT negatable` and bare `negatable` branches — no
`predicate_tail` branch starts with an `Optional` now. The
matched terminal sequence is unchanged, so `build_expr` is
untouched.

Docs: ADR-0026 gains an "As-built notes" section recording
the option-1 builder realization, its two deviations from the
§3 sketch, and the deferral of §7 diagnostic flagging to
ADR-0027. requirements.md C5a -> [x] (steps 1-4) with the
test baseline refreshed to 1079; CLAUDE.md's deferred list
reconciled (C5a implemented; the QA1/QA2 note now points at
ADR-0028).
This commit is contained in:
claude@clouddev1
2026-05-18 23:19:53 +00:00
parent f75f71bbe4
commit a50c6cdf70
15 changed files with 733 additions and 34 deletions
@@ -416,6 +416,66 @@ suite and the typing-surface matrix:
walker.
6. Typing-surface matrix cells for the new surface.
### As-built notes (2026-05-18)
Steps 14 are implemented and committed; step 5 (the §7
diagnostic flagging) is deferred — see below. Realization
choices, and where they deviate from the design sketch above:
- **§3 builder — option 1 ("reconstruct in builder"),**
chosen with the project owner before implementation. The
stratified grammar is walked normally; its terminals flow
into the flat `MatchedPath` unchanged (driving highlight /
completion / the expected-set). `grammar::expr::build_expr`
then folds that flat terminal slice into the `Expr` — a
deterministic recursive descent mirroring the grammar
tiers, run only at submit-time dispatch, never per
keystroke. Two honest deviations from the §3 wording:
- **No `MatchedKind::Expr` variant.** `MatchedPath` stays
purely terminals — arguably more faithful to "MatchedPath
stays flat" than carrying a built `Expr` in it. The
`Expr` is assembled in the command `ast_builder`s
(`build_update` / `build_delete` / `build_show`), which
already reconstruct structured `Command`s from the flat
path; `build_expr` is the same pattern, one tier deeper.
- **There is a second structural pass** over the
expression tokens, scoped to submit-time dispatch. "No
second parse" is read as "no separate parser framework":
the walk validates and drives assistance, `build_expr`
is the single `ast_builder` for the fragment — the same
category as `build_insert`.
- **Grammar shape.** `predicate` is factored as `operand
predicate_tail` (shared operand prefix), and the infix
`NOT` is factored in front of the `LIKE` / `BETWEEN` /
`IN` choice — so the walker's first-commit-wins `Choice`
semantics discriminate branches on a cleanly-failing first
token.
- **`Subgrammar` depth.** `MAX_SUBGRAMMAR_DEPTH = 64` counts
active `Subgrammar` recursion frames. The stratified
grammar descends ~45 frames per parenthesis level, so the
effective parenthesis-nesting limit is roughly a dozen —
far past any hand-written filter; the cap is purely a
stack-overflow guard.
- **§8 hints.** The expression's right-hand operands resolve
through a schema-aware `DynamicSubgrammar` (`where_rhs_
operand`) so the hint panel narrows to the compared
column's type, exactly as the pre-ADR `where col = val`
slot did. The operand grammar carries no validators —
permissive per §7.
- **Step 5 deferred to ADR-0027.** The §7 *behaviour*
relaxation is done: `bind_where_literal` binds a
type-mismatched WHERE literal by its syntactic shape, and
the pre-ADR bind-time rejection is gone. The §7
*diagnostic flagging* — surfacing a type-mismatched
comparison or `= NULL` as an error-class highlight + hint
— is the seam with ADR-0027, which designs the walker
diagnostics-severity model that flagging belongs in (and
whose WARNING severity is defined to have "no triggers
until ADR-0026 is implemented"). Building the flagging as
a standalone mechanism first would be reworked by
ADR-0027; the recommendation is to implement it as the
first triggers of ADR-0027's model.
## See also
- ADR-0009 — DSL command syntax conventions (`--` flags,