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:
claude@clouddev1
2026-05-15 08:33:59 +00:00
parent a41400e532
commit 266b4c2ef4
11 changed files with 153 additions and 1236 deletions
+31 -30
View File
@@ -507,7 +507,7 @@ enum Request {
/// duplicates. The reply is small even for projects with
/// hundreds of tables/columns.
ListNamesFor {
slot: crate::dsl::ident_slot::IdentSlot,
source: crate::dsl::grammar::IdentSource,
reply: oneshot::Sender<Result<Vec<String>, DbError>>,
},
}
@@ -854,30 +854,31 @@ impl Database {
recv.await.map_err(|_| DbError::WorkerGone)?
}
/// List schema entity names for an identifier slot
/// (ADR-0022 §9).
/// List schema entity names for an identifier source
/// (ADR-0022 §9, ADR-0024 §architecture).
///
/// Returns alphabetised, deduplicated names suitable for
/// the completion menu:
/// - `IdentSlot::TableName` → user tables (filters
/// - `IdentSource::Tables` → user tables (filters
/// `__rdbms_*` internal tables);
/// - `IdentSlot::Column` → distinct column names across
/// all user tables (v1 simplification — no
/// - `IdentSource::Columns` → distinct column names
/// across all user tables (v1 simplification — no
/// table-context binding);
/// - `IdentSlot::RelationshipName` → relationship
/// names from the metadata table;
/// - `IdentSlot::NewName` → returns `Ok(vec![])`
/// immediately without a worker round-trip (the user
/// invents these names).
/// - `IdentSource::Relationships` → relationship names
/// from the metadata table;
/// - `IdentSource::NewName`, `Types`, `Free` → returns
/// `Ok(vec![])` immediately without a worker round-trip
/// (the user invents these names, or the source is
/// synthetic).
pub async fn list_names_for(
&self,
slot: crate::dsl::ident_slot::IdentSlot,
source: crate::dsl::grammar::IdentSource,
) -> Result<Vec<String>, DbError> {
if !slot.completes_from_schema() {
if !source.completes_from_schema() {
return Ok(Vec::new());
}
let (reply, recv) = oneshot::channel();
self.send(Request::ListNamesFor { slot, reply }).await?;
self.send(Request::ListNamesFor { source, reply }).await?;
recv.await.map_err(|_| DbError::WorkerGone)?
}
@@ -1202,25 +1203,24 @@ fn handle_request(conn: &Connection, persistence: Option<&Persistence>, req: Req
let result = do_find_rows_matching(conn, &table, &column, &value, limit);
let _ = reply.send(result);
}
Request::ListNamesFor { slot, reply } => {
let result = do_list_names_for(conn, slot);
Request::ListNamesFor { source, reply } => {
let result = do_list_names_for(conn, source);
let _ = reply.send(result);
}
}
}
/// Schema-name lookup for the completion engine
/// (ADR-0022 §9). `NewName` never reaches here — the public
/// `list_names_for` short-circuits.
/// (ADR-0022 §9). Non-schema sources (`NewName`, `Types`, `Free`)
/// never reach here — the public `list_names_for` short-circuits.
fn do_list_names_for(
conn: &Connection,
slot: crate::dsl::ident_slot::IdentSlot,
source: crate::dsl::grammar::IdentSource,
) -> Result<Vec<String>, DbError> {
use crate::dsl::ident_slot::IdentSlot;
match slot {
IdentSlot::NewName => Ok(Vec::new()),
IdentSlot::TableName => do_list_tables(conn),
IdentSlot::Column => {
use crate::dsl::grammar::IdentSource;
match source {
IdentSource::Tables => do_list_tables(conn),
IdentSource::Columns => {
// Distinct column names across all user tables.
// v1 simplification: no table-context binding
// (ADR-0022 stage 6 note).
@@ -1240,7 +1240,7 @@ fn do_list_names_for(
}
Ok(out)
}
IdentSlot::RelationshipName => {
IdentSource::Relationships => {
let mut stmt = conn
.prepare(&format!(
"SELECT name FROM {REL_TABLE} ORDER BY name;"
@@ -1255,6 +1255,7 @@ fn do_list_names_for(
}
Ok(out)
}
IdentSource::NewName | IdentSource::Types | IdentSource::Free => Ok(Vec::new()),
}
}
@@ -7136,7 +7137,7 @@ mod tests {
// touching the worker.
let db = db();
let names = db
.list_names_for(crate::dsl::ident_slot::IdentSlot::NewName)
.list_names_for(crate::dsl::grammar::IdentSource::NewName)
.await
.unwrap();
assert!(names.is_empty());
@@ -7148,7 +7149,7 @@ mod tests {
make_id_table(&db, "Customers").await;
make_id_table(&db, "Orders").await;
let names = db
.list_names_for(crate::dsl::ident_slot::IdentSlot::TableName)
.list_names_for(crate::dsl::grammar::IdentSource::Tables)
.await
.unwrap();
assert_eq!(names, vec!["Customers".to_string(), "Orders".to_string()]);
@@ -7161,7 +7162,7 @@ mod tests {
let db = db();
make_id_table(&db, "Customers").await;
let names = db
.list_names_for(crate::dsl::ident_slot::IdentSlot::TableName)
.list_names_for(crate::dsl::grammar::IdentSource::Tables)
.await
.unwrap();
assert_eq!(names, vec!["Customers".to_string()]);
@@ -7195,7 +7196,7 @@ mod tests {
.await
.unwrap();
let names = db
.list_names_for(crate::dsl::ident_slot::IdentSlot::Column)
.list_names_for(crate::dsl::grammar::IdentSource::Columns)
.await
.unwrap();
// `id` appears once despite being in both tables (DISTINCT).
@@ -7238,7 +7239,7 @@ mod tests {
.await
.unwrap();
let names = db
.list_names_for(crate::dsl::ident_slot::IdentSlot::RelationshipName)
.list_names_for(crate::dsl::grammar::IdentSource::Relationships)
.await
.unwrap();
assert_eq!(names, vec!["cust_orders".to_string()]);