feat: ck_playground — render .cktest fixtures via cktest parser #1

Manually merged
hkowalski merged 5 commits from feat/001-feat-ck-playground-render-cktest-fixtures-via into master 2026-01-05 16:03:13 +01:00
Owner

feat: ck_playground — render .cktest fixtures via cktest parser

Along the way:

  • chore: add scripts/run.sh and scripts/test.sh
  • feat: parser slice 5 — top-level item loop, record decl, minimal TypeExpr
  • chore: architectural quality pass — R3/R4 gates, refactors, lossless-CST tests
  • feat: parser slices 6 + 7 — data decls + fn signatures with brace-balanced body

Touches 42 files: docs/impl/02-lexer.md, docs/impl/03-parser.md, scripts/run.sh, scripts/test.sh, src/rust/crates/ck_driver/tests/architecture.rs, src/rust/crates/ck_lex/src/lib.rs and 36 more.

feat: ck_playground — render .cktest fixtures via cktest parser Along the way: - chore: add scripts/run.sh and scripts/test.sh - feat: parser slice 5 — top-level item loop, record decl, minimal TypeExpr - chore: architectural quality pass — R3/R4 gates, refactors, lossless-CST tests - feat: parser slices 6 + 7 — data decls + fn signatures with brace-balanced body Touches 42 files: `docs/impl/02-lexer.md`, `docs/impl/03-parser.md`, `scripts/run.sh`, `scripts/test.sh`, `src/rust/crates/ck_driver/tests/architecture.rs`, `src/rust/crates/ck_lex/src/lib.rs` and 36 more.
hkowalski approved these changes 2026-01-05 14:04:07 +01:00
hkowalski left a comment

Happy with this. I ran the suite against the branch and it is green, src/rust/crates/ck_lex/src/tests.rs included.

Happy with this. I ran the suite against the branch and it is green, `src/rust/crates/ck_lex/src/tests.rs` included.
@ -0,0 +49,4 @@
}
#[test]
fn long_decimal() {
Owner

long_decimal reads, decides and writes in one function. The deciding part is the piece I would want to test on its own. Worth splitting?

`long_decimal` reads, decides and writes in one function. The deciding part is the piece I would want to test on its own. Worth splitting?
@ -0,0 +377,4 @@
"unexpected diagnostics: {:?}",
out.diagnostics
);
let f = find_first(&out.tree, SyntaxKind::FnDecl).expect("FnDecl");
Owner

The expect message on f is the only thing a user sees if this fires. Does it say what they should do, or only what we assumed?

The expect message on `f` is the only thing a user sees if this fires. Does it say what they should do, or only what we assumed?
Author
Owner

Split. The decision in long_decimal is a pure function now, with its own tests in src/rust/crates/ck_lex/src/tests.rs.

Split. The decision in `long_decimal` is a pure function now, with its own tests in `src/rust/crates/ck_lex/src/tests.rs`.
Author
Owner

It said what I assumed. Reworded in src/rust/crates/ck_parser/src/tests.rs so it names the input that broke it, which is what the bug report will need.

It said what I assumed. Reworded in `src/rust/crates/ck_parser/src/tests.rs` so it names the input that broke it, which is what the bug report will need.
Feeding a raw .cktest file to the lexer flooded the diagnostics pane
with E0001 on every `# page:` / `# expected:` marker. Route .cktest
through ck_cktest::parse and load the first page's source; show a muted
status line ("page 1/N — path") so it's clear which slice is in the
buffer. Multi-page fixtures lose pages 2..N for now — a page selector
can wait until something needs it.
run.sh launches ck_playground from the repo root; test.sh mirrors the
pre-commit hook (fmt --check, clippy -D warnings, test --workspace) so
the same gates can be run locally without staging. Any divergence
between test.sh and .githooks/pre-commit is a bug.
Why: slice 3 landed `mod Name` end-to-end but parse_source_file then
drained tokens unparsed. Records are the smallest locked declaration
that doesn't drag in expressions, so this slice builds the scaffolding
(top-level loop, brace-balanced sync) plus one real vertical (record).

Changes:
- `ck_parser`: top-level item loop after parse_module_header; placeholder
  parsers for every locked-but-unimplemented decl keyword (`fn`, `data`,
  `const`, `effect`, `trait`, `test`, `actor`, `impl`, nested `mod`) that
  recognize the keyword and brace-balance to the next sync point.
- `ck_parser`: full record-decl production —
  `record Name <Generics>? <Traits>? { Field* }`, with `Field = Ident :
  TypeExpr ,?` and minimal `TypeExpr = TypePath GenericArgs?` over
  `Ident (:: Ident)*` paths. Recovery for missing name / `{` / `}` / `:`.
- `ck_lex`: new `Traits` keyword (plural, distinct from singular `Trait`
  per docs/records.md). 7 new SyntaxKind node variants.
- Diagnostic codes E0012..E0022 added to the stable contract; both the
  parser doc-comment and docs/impl/03-parser.md updated.
- 11 new parser unit tests + 9 new `.cktest` fixtures under tests/parse/.
  Existing `tests/lex/program_*.cktest` re-blessed (CST now shows record
  structure rather than a flat token list).
- Trivia attribution refined: node spans end at their last significant
  token, so trailing whitespace consistently belongs to the parent
  regardless of trailing-comma presence.

Quality gates: cargo fmt --check clean, cargo clippy --all-targets -D
warnings clean, all 127 workspace tests green.
Lock the front end's discipline before the next parser slice grows it past
the point where backfilling these gates becomes expensive.

Architectural gates (ck_driver/tests/architecture.rs):
- R3 caps any .rs under crates/*/src or crates/*/tests at 1000 lines.
- R4 caps any function body at 80 lines; 2-entry allow-list with
  justifications (ck_cktest::parse state machine, panes/module_header
  render egui chain). Stale-allow-list-entry check included.
- R1 now also verifies the set of directories under crates/ matches
  EXPECTED_GRAPH — previously a missing crate (ck_playground) was
  invisible to R1 and skipped silently by every other rule.
- Adds ck_playground to EXPECTED_GRAPH with its 6 workspace deps.

ck_lex refactor (lib.rs: 1736 → 984 LoC):
- Move the #[cfg(test)] mod tests block into a sibling tests.rs.
- Extract consume_one_logical_char and sweep_to_char_close from
  scan_char_lit (84 → 47 LoC); now under the R4 cap.
- Unify push_unterminated and a near-duplicate new push_lit_diag into
  one widened helper; collapse two more inline span+diag sites
  (E0001 unknown byte, E0002 unterminated block comment).

Lossless-CST contract:
- ck_syntax::cst_to_source walks the tree concatenating each token's
  source slice; round-trip test feeds real lexer output through a
  synthetic SourceFile node across 8 sources.
- ck_parser test runs the same round-trip against the actual parser
  on 7 sources including error-recovery paths.

Pane-state fixes (ck_playground):
- CktestRegistry::discover surfaces IO failures as
  parsed: Err("io: ...") instead of unwrap_or_default → confusing
  empty parse.
- load_into_buffer doc rewritten to match impl (primary page only,
  matching what analysis runs on).
- Buffer::mark_dirty doc rewritten to permit per-keystroke calls; the
  existing edit loop already does that.

131/131 tests pass (was 127). 0 clippy warnings under all+pedantic
with -D warnings.
Slice 6 adds `DataDecl` with three variant shapes (bare, positional payload,
named-field payload). Named-variant fields reuse `RecordField` so a record
body and a named-variant payload project to the same AST. Diagnostics
E0023–E0028.

Slice 7 adds `FnDecl` covering the signature (generics, params, return,
effect clause) plus a brace-balanced `Block` placeholder for the body that
the expression slice will refine. Diagnostics E0029–E0036. The production
lives in `ck_parser/src/fn_decl.rs` to keep `lib.rs` under the R3 cap.

R3 ratchets from 1000 → 850 after extracting `SyntaxKind`/`Token` into
`ck_lex/src/syntax_kind.rs` and the parser test module into
`ck_parser/src/tests.rs`. New worst case: `ck_lex/src/lib.rs` at 819 lines.

Existing `.cktest` fixtures that previously matched the placeholder `fn`
parser are updated to the real `FnDecl` shape; `tests/parse/placeholder_decl`
switches to `const` (still a placeholder) so the recovery path is exercised
without depending on the now-implemented `fn`. New `tests/parser/{data,fn}/`
fixtures cover the happy paths and each new error code.
hkowalski manually merged commit fde138b2ad into master 2026-01-05 16:03:13 +01:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
northgale/cklang-bootstrap!1
No description provided.