feat: H1a parse-error gaps G2–G4 + advanced near-miss matrix (ADR-0042)
Close the three remaining ADR-0042 triage gaps, each test-first, and lock the advanced-mode near-miss matrix. G2 — bare `select` dumped the 14-item expression first-set. Collapse it to "a projection: `*`, a column, or an expression" in the error message only (parser::format_walker_error), detected by the joint `distinct`+`all` quantifier signature unique to a projection start. Render-only: completion/hints still expand the full set (typing-surface matrix unchanged). G3 — the usage block was mode-blind: advanced `create table` showed the DSL `create table … with pk …` template. usage_key(s)_for_input gain mode-aware `_in_mode` variants selecting candidates by CommandCategory; render_usage_block and the typing-time ambient usage thread the submission mode. Advanced `create` now shows both SQL forms. A fallback covers shared SQL nodes (insert/update/delete) that declare no usage_ids of their own — without it they regressed to the available-commands fallback (caught by the new advanced matrix). G4 — `with` borrowed `select`'s usage template; give it its own parse.usage.with CTE template. Tests: new near_miss_matrix_advanced_mode (12 SQL-surface cases incl. the available-commands regression guard) + per-gap tests; removed the temporary baseline_dump. Full suite green (lib 1578 / it 386 / typing_surface_matrix 192); clippy clean.
This commit is contained in:
+25
-2
@@ -296,14 +296,37 @@ fn format_expectation(e: &crate::dsl::walker::outcome::Expectation) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
/// ADR-0042 G2: a projection start (`select |`, or the projection
|
||||
/// position inside a subquery / CTE body) expects the full
|
||||
/// expression first-set — 14 alternatives — plus the SELECT
|
||||
/// quantifiers `distinct` and `all`. Those two quantifiers are
|
||||
/// jointly expectable *only* at a projection start, so their joint
|
||||
/// presence is a precise signature for collapsing the noisy list
|
||||
/// into one gloss. Render-only: this fires inside
|
||||
/// `format_walker_error` (the error message), not in the expected
|
||||
/// set the completion/hint layer consumes.
|
||||
fn is_select_projection_start(expected: &[crate::dsl::walker::outcome::Expectation]) -> bool {
|
||||
use crate::dsl::walker::outcome::Expectation;
|
||||
let has_word = |w: &str| {
|
||||
expected
|
||||
.iter()
|
||||
.any(|e| matches!(e, Expectation::Word(x) if x.eq_ignore_ascii_case(w)))
|
||||
};
|
||||
has_word("distinct") && has_word("all")
|
||||
}
|
||||
|
||||
fn format_walker_error(
|
||||
source: &str,
|
||||
position: usize,
|
||||
at_eof: bool,
|
||||
expected: &[crate::dsl::walker::outcome::Expectation],
|
||||
) -> String {
|
||||
let parts: Vec<String> = expected.iter().map(format_expectation).collect();
|
||||
let joined = oxford_join(&parts);
|
||||
let joined = if is_select_projection_start(expected) {
|
||||
crate::t!("parse.expect.select_projection")
|
||||
} else {
|
||||
let parts: Vec<String> = expected.iter().map(format_expectation).collect();
|
||||
oxford_join(&parts)
|
||||
};
|
||||
|
||||
// Mirror the chumsky-side wording: "after `<consumed>`,
|
||||
// expected …" when the parser already consumed something
|
||||
|
||||
Reference in New Issue
Block a user