Insert grammar: Form C type-awareness via lookahead (ADR-0024 §Phase D)

Form C (`insert into T (vals)`) shared the `(` opener with Form A,
so its paren was an untyped Repeated(Choice(literal, ident)) — values
weren't type- or count-checked at parse time (handoff-12 §2.2).

New Node::Lookahead variant: a factory that peeks the source. The
insert first-paren factory inspects the first token — a value literal
routes the contents through the typed column_value_list (Form B
dispatch contract: per-non-auto-column typed slots); an identifier or
empty paren routes to a Form A column-name list. So Form C now gets
the same per-column typed slots, hints, and parse-time type/count
checking Form B has.

The explicit-Choice-branch split is impossible here (committed-choice
semantics commit after `(` matches); lookahead is the only route, and
DynamicSubgrammar factories couldn't see the source. Node::Lookahead
is not memoized — its output depends on source — but it returns only
a small node (a Repeated, or a thin DynamicSubgrammar wrapper that
delegates to the memoized column_value_list).

`insert into T (` now cleanly shows Form A column candidates instead
of mixed Form-A/C suggestions. Form C matrix tests updated for the
type-aware behaviour.
This commit is contained in:
claude@clouddev1
2026-05-15 22:27:53 +00:00
parent 9bbb96e735
commit 90e3f5dbfb
18 changed files with 411 additions and 262 deletions
+14
View File
@@ -212,6 +212,20 @@ fn walk_node_inner(
let resolved = resolve_dynamic(*factory, ctx);
walk_node(source, pos, resolved, ctx, path, per_byte)
}
Node::Lookahead(factory) => {
// ADR-0024 §Phase D Form-C type-awareness: the
// factory peeks the source at `pos` (e.g. to tell a
// Form A column list from a Form C value list) and
// returns the shape to walk. Not memoized — the
// result depends on the source — but the factory
// returns a small node (a Repeated, or a thin
// DynamicSubgrammar wrapper that delegates to the
// memoized `column_value_list`), so the per-walk
// leak is a few bytes, not a whole typed tree.
let resolved: &'static Node =
Box::leak(Box::new(factory(ctx, source, pos)));
walk_node(source, pos, resolved, ctx, path, per_byte)
}
Node::TypedValueSlot {
ty,
column_name,