ADR-0024 Phase D: data commands at chumsky parity
Migrate the four data commands at four entry words: show
(show data / show table), insert, update, delete. Walker now
owns the entire command set introduced through ADR-0014.
Scope deviation from ADR-0024: full schema-aware value typing
via DynamicSubgrammar(column_value_list) is deferred. The
walker accepts any value at any position — matching the
existing chumsky parser's behaviour, where per-column type
checks happen at bind time. The DynamicSubgrammar Node
variant and WalkContext schema fields stay declared so the
infrastructure is in place when the schema cache plumbs
through parse_command (a future refinement). All existing
tests pass on the new shape.
Walker extensions:
- StringLit terminal — wired to the consume_string_literal
helper that mirrors the legacy lexer's `''` escape handling.
MatchedItem text carries the unescaped payload; span covers
the surrounding quotes.
- Bridge: Incomplete error wording now appends `, found end
of input` (matching the chumsky-side structural error
contract that `structural_error_for_show_data_without_arg`
asserts on).
Grammar:
- src/dsl/grammar/data.rs: SHOW (Choice of show_data /
show_table), INSERT (three forms folded into a single shape
via a Choice ordered to disambiguate Form B's `values`
keyword from Forms A/C's `(`-prefixed content; the inner
paren list is a Choice(VALUE_LITERAL, Ident{Columns}) with
VALUE_LITERAL ordered first so `true`/`false`/`null` match
their Word branch rather than the broader identifier catch-
all), UPDATE (assignments + filter), DELETE (filter).
- VALUE_LITERAL = Choice(Word("null"), Word("true"),
Word("false"), NumberLit, StringLit) — matches the chumsky
`value_literal()`.
- WHERE_CLAUSE / FILTER_CLAUSE shared between update and
delete.
- AST builders walk MatchedPath items in order, using role
tags (`update_set_column`, `filter_column`,
`insert_first_item`) to discriminate column references
belonging to different shapes within the same command.
Tests:
- 13 new walker-specific tests covering all data forms:
show data / show table, insert with each of three forms,
insert with negative numbers, update with single + multiple
assignments + where, update with --all-rows, delete with
where, delete with --all-rows, update/delete without filter
errors, replay still routes via chumsky.
- Total: 838 passed, 0 failed, 1 ignored (was 825 / 1).
- cargo clippy --all-targets -- -D warnings clean.
This commit is contained in:
@@ -24,7 +24,8 @@
|
||||
use crate::dsl::grammar::{HighlightClass, Node, ValidationError};
|
||||
use crate::dsl::walker::context::WalkContext;
|
||||
use crate::dsl::walker::lex_helpers::{
|
||||
consume_bare_path, consume_flag, consume_ident, consume_number_literal, skip_whitespace,
|
||||
consume_bare_path, consume_flag, consume_ident, consume_number_literal,
|
||||
consume_string_literal, skip_whitespace,
|
||||
};
|
||||
use crate::dsl::walker::outcome::{
|
||||
ByteClass, Expectation, MatchedItem, MatchedKind, MatchedPath,
|
||||
@@ -94,12 +95,13 @@ pub fn walk_node(
|
||||
} => walk_ident(source, pos, *src, role, *validator, path, per_byte),
|
||||
Node::NumberLit { validator } => walk_number_lit(source, pos, *validator, path, per_byte),
|
||||
Node::Literal(literal) => walk_literal(source, pos, literal, path, per_byte),
|
||||
Node::StringLit | Node::BlobLit | Node::DynamicSubgrammar(_) => {
|
||||
// Phase A-B: not exercised yet. Reaching this branch
|
||||
// means a Phase D+ grammar got declared without the
|
||||
// walker support landing — surface as a hard failure
|
||||
// so tests catch it loudly rather than silently
|
||||
// mis-parsing.
|
||||
Node::StringLit => walk_string_lit(source, pos, path, per_byte),
|
||||
Node::BlobLit | Node::DynamicSubgrammar(_) => {
|
||||
// Phase A-D: not exercised yet. Reaching this branch
|
||||
// means a future-phase grammar got declared without
|
||||
// the walker support landing — surface as a hard
|
||||
// failure so tests catch it loudly rather than
|
||||
// silently mis-parsing.
|
||||
NodeWalkResult::Failed {
|
||||
position: pos,
|
||||
kind: FailureKind::Mismatch { expected: vec![] },
|
||||
@@ -220,6 +222,34 @@ fn walk_ident(
|
||||
NodeWalkResult::Matched { end, skipped: Vec::new() }
|
||||
}
|
||||
|
||||
fn walk_string_lit(
|
||||
source: &str,
|
||||
position: usize,
|
||||
path: &mut MatchedPath,
|
||||
per_byte: &mut Vec<ByteClass>,
|
||||
) -> NodeWalkResult {
|
||||
let Some(((start, end), content)) = consume_string_literal(source, position) else {
|
||||
return NodeWalkResult::NoMatch {
|
||||
position,
|
||||
expected: vec![Expectation::StringLit],
|
||||
};
|
||||
};
|
||||
path.push(MatchedItem {
|
||||
kind: MatchedKind::StringLit,
|
||||
text: content,
|
||||
span: (start, end),
|
||||
});
|
||||
per_byte.push(ByteClass {
|
||||
start,
|
||||
end,
|
||||
class: HighlightClass::String,
|
||||
});
|
||||
NodeWalkResult::Matched {
|
||||
end,
|
||||
skipped: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_literal(
|
||||
source: &str,
|
||||
position: usize,
|
||||
|
||||
Reference in New Issue
Block a user