Skip to content

Parser: spawn, select, and emit productions (§8.2, §8.6, §8.9, §11.1, §11.3, §16) #93

Description

@StreamDemon

Summary

spawn, select, and emit are reserved keywords with zero parse productions — every actor spawn (§8.2/§8.7), multiplexed receive (§8.6), non-actor task (§8.9), and event emission (§11.1/§11.3) fails today, including §4.6's own spawn move || { ... } example. This blocks #67 and #68: round-trip validation and corpus growth cover the spec's §8 examples, and nearly all of them spawn actors. priority/high is deliberate — this is milestone 1's exit criterion, not a peer of the remaining medium issues.

Grammar basis (§16, verbatim — no spec amendment needed)

expr        = ... | "spawn" expr | "spawn" "async" block | ... | select_expr | ... ;
select_expr = "select" "{" { select_arm } "}" ;
select_arm  = pattern "=" expr "=>" ( expr "," | block ) ;
emit_stmt   = "emit" IDENT "{" field_inits "}" ";" ;

Design (adversarially reviewed; see PR for the review-folded changes)

AST: ExprKind::Spawn(Box<Expr>), SpawnAsync { body: Block } (raw block like Loop — it's a block by production), Select { arms: Vec<SelectArm> } with SelectArm { pattern, source, body } (unboxed, source names the receive-source expr; body block-wrapped per MatchArm); Stmt::Emit { event: String, fields: Vec<(String, Option<Expr>)> } reusing field_inits shorthand.

Parser: spawn_expr() — operand via plain expr(0), not cond_expr() (spawn is not a block-head-restricted position; spawn Worker { count: 0 } must parse); select_expr() modeled on match_expr() (same arm loop, recovery, comma discipline; arms defer pattern? exactly like match_arm); emit as a block_inner() statement arm next to return (reserved keyword, unambiguous head). can_begin_expr gains Spawn/Select only — send spawn … / send select {…} open send-statements whose operands fail the method-call check (same consequence class as closures, pinned by test). Emit is statement-only: no prefix() arm.

Span discipline (explicit, per the #92 lesson): all new expressions anchor at their keyword token (expect_keyword span, never prev_span()-before-consume), select ends at its closing }, Stmt::Emit spanless per the Stmt enum convention. Pinned by a *_spans_anchor_correctly test.

Documented decisions:

Scope / acceptance criteria

  • All three productions + AST nodes, with the span/test decisions above.
  • Unit tests (~16): structural asserts for all five node shapes; §8.2/§8.7/§8.2a spawn chains inside map; §4.6 spawn move || verbatim; §8.9 spawn async with typed let; §8.6 select (adapted return arm; wildcard + timeout(5000); mixed bodies); §11.1/§11.3 emit with to shorthand; send-head consequence; pipe pins (spawn (x |> f) greedy reading, select {…} |> f, pipe in arm body); struct-literal pins (spawn operand, select source); negatives (spawn alone, spawn async x, select arm missing =/=>, emit missing braces/semi, emit in expression position, unclosed select); error-recovery count; degenerate spawn { block }; non-tail ; behavior.
  • Corpus fixture tests/corpus/spawn_select_emit.sp from §8.2/§8.2a/§8.6/§8.7/§8.9/§11.1/§11.3 examples (return arms adapted, noted).
  • crates/AGENTS.md sync: the three keywords move to Accepted with parse-only caveats; four now-stale sentences updated (patterns-wired-into list gains select arms; send-head list gains spawn/select; non-tail-; set gains select/spawn async; the Spec drift: §5.2/§3.7 examples do not derive from the §16 grammar (return-as-expression, ref field-pat shorthand) #89 rejection note covers select arm bodies).

Filed from an adversarially-reviewed design draft (12 findings folded in, APPROVE-WITH-CHANGES).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions