ADR-0024 Phase F (full) step 3: delete legacy parser modules
Removes the last consumers of `dsl::lexer`, `dsl::keyword`, and
`dsl::ident_slot`, then deletes the modules.
- `Theme::token_color(&TokenKind)` deleted along with its test;
`Theme::highlight_class_color(HighlightClass)` is the sole
highlight-colour mapper (the walker's `per_byte_class` feeds
it directly).
- `IdentSource` (`dsl::grammar`) absorbs the schema-list /
expected-label / round-trip semantics that previously lived
on `IdentSlot`. Adds `completes_from_schema`, `expected_label`,
and `from_expected_label` methods. The walker's
`Expectation::Ident { source }` and the schema-lookup request
on the database worker now share one enum.
- `SchemaCache::for_slot(IdentSlot)` → `for_source(IdentSource)`.
- `Database::list_names_for` and the `Request::ListNamesFor`
worker variant take `IdentSource`. Internal tables and column
/ relationship lookups dispatch on the same enum.
- `InvalidIdent.slot: IdentSlot` → `InvalidIdent.source: IdentSource`.
The `invalid_ident_at_cursor` rendering branch in
`input_render.rs::ambient_hint` updates accordingly.
- Completion's keyword filter (`Keyword::from_word`) becomes
"backticked items whose payload is all ASCII alphabetic" —
punct and digit literals still surface through their own
candidate sources (composite-literal, flag, schema-ident);
the alphabetic filter excludes them from the keyword bucket.
- `friendly::keys::tests::keyword_and_punct_have_complete_token_vocabulary`
is dropped. It cross-checked `Keyword::ALL` / `Punct::ALL`
against catalog entries; both enums are gone. The
`parse.token.keyword.*` / `parse.token.punct.*` catalog
entries themselves survive for one more commit (catalog
cleanup, ADR-0024 §cleanup-pass); the
`keys_validate_against_catalog` test still pins them.
- Modules deleted: `src/dsl/lexer.rs`, `src/dsl/keyword.rs`,
`src/dsl/ident_slot.rs`.
Tests: 806 passing, 0 failing, 1 ignored. The drop from 852
reflects the removed module-internal tests (~32 lexer, 7
keyword, 4 ident_slot, 1 theme token_color, 1 friendly keys
keyword/punct), and is the expected outcome.
Clippy clean with `nursery` lints + `-D warnings`.
This commit is contained in:
+33
-28
@@ -14,8 +14,7 @@
|
||||
//! The cycling memo (`LastCompletion` on `App`) lives in
|
||||
//! `app.rs`; this module owns the candidate computation.
|
||||
|
||||
use crate::dsl::ident_slot::IdentSlot;
|
||||
use crate::dsl::keyword::Keyword;
|
||||
use crate::dsl::grammar::IdentSource;
|
||||
use crate::dsl::types::Type;
|
||||
use crate::dsl::{ParseError, parse_command};
|
||||
|
||||
@@ -53,15 +52,15 @@ pub struct SchemaCache {
|
||||
|
||||
impl SchemaCache {
|
||||
/// Lookup the candidate list for an identifier slot.
|
||||
/// `NewName` always returns `&[]` — the user invents
|
||||
/// these names.
|
||||
/// Sources that don't read from the schema (`NewName`,
|
||||
/// `Types`, `Free`) return `&[]`.
|
||||
#[must_use]
|
||||
pub fn for_slot(&self, slot: IdentSlot) -> &[String] {
|
||||
match slot {
|
||||
IdentSlot::NewName => &[],
|
||||
IdentSlot::TableName => &self.tables,
|
||||
IdentSlot::Column => &self.columns,
|
||||
IdentSlot::RelationshipName => &self.relationships,
|
||||
pub fn for_source(&self, source: IdentSource) -> &[String] {
|
||||
match source {
|
||||
IdentSource::Tables => &self.tables,
|
||||
IdentSource::Columns => &self.columns,
|
||||
IdentSource::Relationships => &self.relationships,
|
||||
IdentSource::NewName | IdentSource::Types | IdentSource::Free => &[],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,7 +109,7 @@ pub struct Completion {
|
||||
/// bare keywords (excluding punctuation and descriptive
|
||||
/// labels per ADR-0022 §10).
|
||||
/// - **Schema identifiers**: when the parser's expected-set
|
||||
/// includes an `IdentSlot::expected_label()`, the matching
|
||||
/// includes an `IdentSource::expected_label()`, the matching
|
||||
/// schema list from `cache` is added (skipping the `NewName`
|
||||
/// slot — the user invents those).
|
||||
///
|
||||
@@ -172,7 +171,13 @@ pub fn candidates_at_cursor(
|
||||
let mut keywords: Vec<String> = expected
|
||||
.iter()
|
||||
.filter_map(|item| strip_backticks(item))
|
||||
.filter_map(|name| Keyword::from_word(name).map(|_| name.to_string()))
|
||||
// Backticked items are walker `Expectation::Word`s or
|
||||
// `Expectation::Literal`s. Keywords are the
|
||||
// alphabetic-only ones; punct (`,`, `=`) and digit
|
||||
// literals (`1`) live in the same expected-set but
|
||||
// surface through other candidate sources.
|
||||
.filter(|name| !name.is_empty() && name.chars().all(|c| c.is_ascii_alphabetic()))
|
||||
.map(str::to_string)
|
||||
.filter(|name| matches_prefix(name))
|
||||
.collect();
|
||||
let mut seen_kw = std::collections::HashSet::new();
|
||||
@@ -245,8 +250,8 @@ pub fn candidates_at_cursor(
|
||||
// matching known-set slot. `NewName` slots return `&[]`.
|
||||
let mut identifiers: Vec<String> = expected
|
||||
.iter()
|
||||
.filter_map(|item| IdentSlot::from_expected_label(item))
|
||||
.flat_map(|slot| cache.for_slot(slot).iter().cloned())
|
||||
.filter_map(|item| IdentSource::from_expected_label(item))
|
||||
.flat_map(|source| cache.for_source(source).iter().cloned())
|
||||
.filter(|name| matches_prefix(name))
|
||||
.collect();
|
||||
identifiers.sort();
|
||||
@@ -365,7 +370,7 @@ pub struct InvalidIdent {
|
||||
/// The text the user typed in the slot.
|
||||
pub found: String,
|
||||
/// Which known-set slot this position expected.
|
||||
pub slot: IdentSlot,
|
||||
pub source: IdentSource,
|
||||
}
|
||||
|
||||
/// "User is typing a name" cursor state (round-3 follow-up).
|
||||
@@ -408,8 +413,8 @@ pub fn typing_name_at_cursor(input: &str, cursor: usize) -> Option<TypingName> {
|
||||
let expected = expected_set(leading);
|
||||
let is_new_name_slot = expected
|
||||
.iter()
|
||||
.filter_map(|item| IdentSlot::from_expected_label(item))
|
||||
.any(|slot| slot == IdentSlot::NewName);
|
||||
.filter_map(|item| IdentSource::from_expected_label(item))
|
||||
.any(|source| source == IdentSource::NewName);
|
||||
if !is_new_name_slot {
|
||||
return None;
|
||||
}
|
||||
@@ -485,34 +490,34 @@ pub fn invalid_ident_at_cursor(
|
||||
return None;
|
||||
}
|
||||
// Find every known-set slot in the expected list.
|
||||
let slots: Vec<IdentSlot> = expected
|
||||
let sources: Vec<IdentSource> = expected
|
||||
.iter()
|
||||
.filter_map(|item| IdentSlot::from_expected_label(item))
|
||||
.filter(|slot| slot.completes_from_schema())
|
||||
.filter_map(|item| IdentSource::from_expected_label(item))
|
||||
.filter(|s| s.completes_from_schema())
|
||||
.collect();
|
||||
if slots.is_empty() {
|
||||
if sources.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let lowered = partial.to_lowercase();
|
||||
// If any schema entry across the matching slots matches
|
||||
// the prefix, the partial is not "invalid" — it's an
|
||||
// in-progress lookup.
|
||||
let any_match = slots
|
||||
let any_match = sources
|
||||
.iter()
|
||||
.flat_map(|slot| cache.for_slot(*slot))
|
||||
.flat_map(|s| cache.for_source(*s))
|
||||
.any(|name| name.to_lowercase().starts_with(&lowered));
|
||||
if any_match {
|
||||
return None;
|
||||
}
|
||||
// Pick the first slot kind for the diagnostic — when
|
||||
// Pick the first source kind for the diagnostic — when
|
||||
// multiple are expected (e.g. `drop relationship …`
|
||||
// expects RelationshipName *or* the `from` keyword;
|
||||
// here only the schema slot survives the filter) we
|
||||
// expects Relationships *or* the `from` keyword;
|
||||
// here only the schema source survives the filter) we
|
||||
// surface the first.
|
||||
Some(InvalidIdent {
|
||||
range: (start, cursor),
|
||||
found: partial.to_string(),
|
||||
slot: slots[0],
|
||||
source: sources[0],
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1123,7 +1128,7 @@ mod tests {
|
||||
.expect("should be invalid");
|
||||
assert_eq!(invalid.range, (10, 15));
|
||||
assert_eq!(invalid.found, "Custp");
|
||||
assert_eq!(invalid.slot, IdentSlot::TableName);
|
||||
assert_eq!(invalid.source, IdentSource::Tables);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user