feat: parser slice 27 — test declarations + bundled test { } mock blocks #5

Manually merged
hkowalski merged 8 commits from feat/005-feat-parser-slice-27-test-declarations-bundled into master 2026-01-09 08:00:00 +01:00
Owner

feat: parser slice 27 — test declarations + bundled test { } mock blocks

Along the way:

  • feat: parser slice 28 — mod X provides Effect as a module-header clause
  • feat: parser slice 29 — actor declarations (actor + 8 slots)
  • test: scaffold tests/corpus/ — runnable example apps
  • docs: runtime stage — test-runner-first sequencing + floor architecture
  • chore: project quality review + training scaffolding
  • refactor(parser slice 29): drop uses/<- — effects resolve callee-driven
  • docs: slice 29 — actor declarations (impl docs)

Touches 105 files: docs/README.md, docs/ai-training.md, docs/effects.md, docs/impl/02-lexer.md, docs/impl/03-parser.md, docs/impl/README.md and 99 more.

feat: parser slice 27 — test declarations + bundled test { } mock blocks Along the way: - feat: parser slice 28 — `mod X provides Effect` as a module-header clause - feat: parser slice 29 — actor declarations (actor + 8 slots) - test: scaffold tests/corpus/ — runnable example apps - docs: runtime stage — test-runner-first sequencing + floor architecture - chore: project quality review + training scaffolding - refactor(parser slice 29): drop uses/`<-` — effects resolve callee-driven - docs: slice 29 — actor declarations (impl docs) Touches 105 files: `docs/README.md`, `docs/ai-training.md`, `docs/effects.md`, `docs/impl/02-lexer.md`, `docs/impl/03-parser.md`, `docs/impl/README.md` and 99 more.
hkowalski requested changes 2026-01-08 08:00:00 +01:00
Dismissed
hkowalski left a comment

Two things inline. The one in src/rust/crates/ck_parser/src/tests/actor_decl.rs is the one I care about.

Two things inline. The one in `src/rust/crates/ck_parser/src/tests/actor_decl.rs` is the one I care about.
@ -0,0 +155,4 @@
}
#[test]
fn receive_missing_open_paren_emits_e0107() {
Owner

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

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

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

Split. The decision in `receive_missing_open_paren_emits_e0107` is a pure function now, with its own tests in `src/rust/crates/ck_parser/src/tests/actor_decl.rs`.
hkowalski approved these changes 2026-01-09 07:55:00 +01:00
hkowalski left a comment

Good. The second pass on src/rust/crates/ck_parser/src/tests/actor_decl.rs is what I hoped for.

Good. The second pass on `src/rust/crates/ck_parser/src/tests/actor_decl.rs` is what I hoped for.
Author
Owner

Pushed a fix for both. The second pass on src/rust/crates/ck_parser/src/tests/actor_decl.rs is much smaller than the first.

Pushed a fix for both. The second pass on `src/rust/crates/ck_parser/src/tests/actor_decl.rs` is much smaller than the first.
Lands the `test` keyword's two grammatical roles:

- top-level `test fn name(...) { ... }` → TestDecl wrapping a reused FnDecl
- `test { ... }` mock block in an effect body → TestBlock with `state { }`
  (StateBlock/StateField), operation bodies (reused FnDecl), and `seed fn`
  helpers (SeedFn). Replaces slice 26's brace-balanced E0090 recovery.

Decisions (documented in docs/impl/03-parser.md):
- `seed` stays a contextual identifier, not a keyword — it also names a
  record field and a member-access path, so a hard keyword would break
  those. A seed fn is recognized by the `Ident fn` shape; the resolver
  verifies the modifier is literally `seed`.
- A state field is a binding with a mandatory initial value (`Ident : T =
  E`, E0100), by analogy with `const`. Empty `state {}` is well-formed.

5 new SyntaxKind nodes, 9 new diagnostics (E0092..E0100), E0090 message
broadened to "expected `fn`, `test`, or `}` in effect body". No lexer
change. Gates green: fmt, clippy -D warnings, 499 tests.
Lands the provider-module form. The grammar was specified two
incompatible ways across the locked docs; resolved (2026-05-24) in favor
of modules.md:

  ModuleHeader   ::= mod Ident ProvidesClause?
  ProvidesClause ::= provides TypePath GenericArgs?

`mod X provides Effect` is a HEADER CLAUSE, not a braced top-level
declaration: the file is the provider and its top-level fns are the
operation implementations. modules.md forbids `mod { ... }` blocks inside
files, so a braced `mod X provides Effect { ... }` declaration cannot
exist (and would force a redundant second `mod`). The effects.md /
syntax.md braced examples were illustrative grouping, not grammar, and
are corrected to the header-line form here.

Decisions (documented in docs/impl/03-parser.md):
- The effect reference reuses impl's shape (`parse_type_path` head +
  optional `parse_generic_args`), so `provides File` and the marker
  `provides Alloc<Ctx>` both parse. Generic args are optional here,
  unlike impl's mandatory `<TypeArgs>`.
- `mod` leaves the top-level dispatch and the `is_top_level_decl_start`
  sync set: a `mod` token only ever opens the file header, so a stray
  mid-file `mod` now emits the generic E0013 instead of placeholder E0012.
- The clause production lives in its own file (`provides_clause.rs`) per
  the R3 per-file convention; `parse_module_header` calls into it.

One new diagnostic (E0101); a malformed generic list reuses E0020. No
lexer change — `provides` was already a keyword.

Re-blessed tests/lex/program_effects.cktest: `mod RuntimePanic provides
Panic` now parses as a clean ProvidesClause. Also fixed that fixture's
stale `fn boom() -> Nothing with Panic` to the canonical effect-clause
keyword (`effect Panic`), turning a 3-diagnostic parse into a fully clean
one (now `diagnostics: (none)`).

Gates green: fmt, clippy -D warnings, 387 parser tests, architecture
R1–R4, conformance.
Parse `actor Name { ... }` with all eight slots — const / uses / spawn /
receive / state / despawn / test / http — plus internal `fn` helpers.

- Lexer: add `receive` / `despawn` / `http` keywords and the `<-` (LArrow)
  token for `uses` bindings; extract the keyword table into keywords.rs to
  stay under the R3 file cap.
- Parser: new actor_decl.rs — ActorDecl + ActorConst / UsesBlock /
  UsesBinding / SpawnSlot / ReceiveSlot / DespawnSlot / HttpSlot. spawn/
  despawn/http share one signature-shaped helper; receive is separate
  (untyped `(msg)` / `(_)` binder, type comes from `<T>`). Actor-root
  `const x = e` has no type annotation or `;` (inferred, block-style),
  distinct from the module-level ConstDecl.
- Reuse + extend the slice-27 test block to also accept actor slots
  (spawn / receive / despawn) alongside state / fn / seed fn.
- Retire the last top-level placeholder (`actor`); drop E0012.
- New diagnostics E0102–E0115; ratchet MAX_FILE_LOC 828 → 783 after the
  keyword extraction.

Doc updates (03-parser.md slice-29 section, slices.md Done row, 02-lexer.md
keyword table) and the `<-`-vs-reuse-existing-token decision are
deliberately deferred, not forgotten.
A corpus of real, complete example programs (one .ck per app) for reading
and discussion, separate from .cktest parser fixtures: no golden sections,
ignored by the conformance harness (it ingests only `.cktest`), and free to
use the full intended language even where the bootstrap parser can't parse
it yet. The bar is the inverse of a fixture's — every construct must be real
and meaningful (no invented primitives, no placeholder mocks).

First app: greeter.ck — effect `Log` + its mock, an effectful `greet`,
production injection via `uses { Log <- StdoutLog }`, and a `test fn` that
exercises the mock. Each construct cites its source in the docs.
Runtime contract (docs/runtime.md): one actor semantics, three compiler
lowerings (native leaf / synchronous local / concurrent) under an as-if
rule, and the native floor defined by the regress/composition/physical
rule. Runtime slice plan R1–R12 (docs/impl/runtime/) sequenced
test-runner-first — start from the smallest engine that runs one `test fn`
and emits a MetaStream, then widen outward to the floor.

slices.md repoints the post-parser stage at runtime/README.md; todo.md #9
records the three open runtime sub-questions; principles / open-questions /
effects / effect_alloc / README cross-reference the new contract.
review.md — whole-project senior PL/compiler quality review (span fidelity,
error-reporting discipline, IR layering, parser recovery, lex hot-path).
docs/ai-training.md + scripts/training/ — local model-training scaffolding
(hand-kicked on the 4090; no CI).
An effect has one canonical provider, so there is no per-actor provider
choice to declare. The dependency graph is built from callees (each slot's
effect rows), and the production provider is selected once per environment
by infra-as-code config — never bound per actor. So the binding slot has
nothing to bind.

- Lexer: remove the `<-` (LArrow) token and the now-dead `uses` keyword
  (`uses` lexes as an ordinary identifier again).
- Parser: remove UsesBlock / UsesBinding node kinds and the parse_uses_*
  productions; the actor body loses its `uses` member.
- Renumber slice-29 diagnostics to stay contiguous now that the uses codes
  (old E0106–E0109) are gone: receive / const / slot-body are E0102–E0111.
- Fixtures + corpus: strip `uses`/`<-`; greeter.ck now explains callee-driven
  resolution and the `effect X with Log { test {} }` custom-mock mechanism.

Reverses the `uses`/`<-` mechanism introduced in the slice-29 commit, per
the design conversation that followed it.
Completes the slice-29 landing per the doc-update discipline:

- 03-parser.md: new "Slice 29: actor declarations" section (grammar + the
  five locked decisions, incl. why there is no `uses`/`<-`), the actor row
  flipped to locked, the placeholder paragraph updated for E0012's
  retirement, the running diagnostics paragraph extended, and E0102–E0111
  added to the code table (E0012 marked retired, not reused).
- slices.md: slice 29 moved to Done; the pending parser table is now empty
  (both sub-cascades closed); a note records the uses/`<-` removal.
- 02-lexer.md: `Receive` / `Despawn` / `Http` added to the reserved-keyword
  table, `Uses` removed, with a note that no `<-` token exists.

Design-layer docs (actors.md `uses` section, effects.md references) still
describe the old per-actor binding and are left for a separate pass.
hkowalski manually merged commit 6077c23a0c into master 2026-01-09 08:00:00 +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!5
No description provided.