ADR-0024 Phase C: create table with column-list value literals

Migrate `create table <Name> [with pk [<col>:<type>[, ...]]]`
to the walker. Exercises Repeated{separator: Some(Punct(','))}
for the first time — the with-pk column-spec list.

Walker behaviour changes:
- Optional now backtracks on partial-match failure (Incomplete
  or Failed-Mismatch from a Seq mid-shape). Path / per-byte
  state rolls back to before the partial attempt; the inner's
  expected-set propagates as `skipped` so callers see "what
  would have completed it". Matches chumsky's `or_not`
  semantics. ValidationFailed (content errors) does NOT
  backtrack — the user means to fix those.
- Bridge: ValidationFailed errors now classify as
  `at_eof = true`, mirroring the chumsky-side custom-error
  convention. This is what lets `create table Customers`
  classify as IncompleteAtEof rather than DefiniteErrorAt
  (the user can still continue typing `with pk …`).

Grammar:
- src/dsl/grammar/ddl.rs gains CREATE: shape is
  Seq(Word("table"), Ident{NewName,table_name}, Optional(WITH_PK))
  where WITH_PK = Seq(Word("with"), Word("pk"),
  Optional(Repeated{COL_SPEC, separator: Punct(','), min:1})).
  AST builder enforces `with pk needs at least one column`
  with the existing parse.custom.create_table_needs_pk catalog
  wording; `with pk` alone defaults to id:serial.

Tests:
- 6 new walker-specific tests for create_table: with-pk
  default, named typed PK, compound PK, whitespace tolerance
  around `:` and `,`, bare-create-table-errors-with-with-pk-
  hint, case-insensitive keywords.
- Total: 825 passed, 0 failed, 1 ignored (was 819 / 1).
- cargo clippy --all-targets -- -D warnings clean.
This commit is contained in:
claude@clouddev1
2026-05-15 07:12:22 +00:00
parent 7e79ca865a
commit 6bb688251b
5 changed files with 277 additions and 29 deletions
+28 -1
View File
@@ -570,7 +570,34 @@ fn walk_optional(
skipped: expected,
}
}
other => other,
// Partial-match failure (mid-shape Incomplete or
// structural Mismatch). Match chumsky's `or_not`
// semantics: roll back any state the partial match
// pushed and treat the optional as skipped, carrying
// the partial's expected-set as `skipped` so callers
// can surface "what would have completed it" at the
// failure point. Validation errors do NOT backtrack —
// those are content failures the user means to fix.
NodeWalkResult::Incomplete { expected, .. } => {
path.items.truncate(saved_path_len);
per_byte.truncate(saved_byte_len);
NodeWalkResult::Matched {
end: position,
skipped: expected,
}
}
NodeWalkResult::Failed {
kind: FailureKind::Mismatch { expected },
..
} => {
path.items.truncate(saved_path_len);
per_byte.truncate(saved_byte_len);
NodeWalkResult::Matched {
end: position,
skipped: expected,
}
}
validation_failure @ NodeWalkResult::Failed { .. } => validation_failure,
}
}