Implement the following plan:
Fix #86: Support scoped declarations in variant receive case bodies
Context
Variant protocol receive (ch ? CASE) case bodies only support a single statement. When a case body has a scoped declaration (e.g., BOOL x :) followed by a compound statement (SEQ ...), parsing fails. This blocks historical-examples/life.occ (issue #72).
The fix follows the identical pattern already used by IF, CASE, and ALT — change Body from a single Statement to []Statement and use parseBodyStatements().
Changes
1. AST — ast/ast.go line 458
Change VariantCase.Body from single to multi-statement:
Body Statement → Body []Statement
2. Parser — parser/parser.go
parseVariantReceive() (lines 1384-1393): Replace single-statement parse with parseBodyStatements():
// Before:
if p.peekTokenIs(lexer.INDENT) {
p.nextToken() // consume INDENT
p.nextToken() // move to body
vc.Body = p.parseStatement()
if !p.curTokenIs(lexer.NEWLINE) && !p.curTokenIs(lexer.DEDENT) && !p.curTokenIs(lexer.EOF) {
p.nextToken()
}
}
// After:
if p.peekTokenIs(lexer.INDENT) {
p.nextToken() // consume INDENT
vc.Body = p.parseBodyStatements()
}
parseVariantReceiveWithIndex() (lines 1479-1487): Same change.
Note: parseBodyStatements() handles p.nextToken() internally (line 1924: "move past INDENT") and manages its own DEDENT/NEWLINE tracking, so the manual advance code is removed.
3. Codegen — codegen/codegen.go
generateVariantReceive() (lines 1420-1422): Loop over body statements:
// Before:
if vc.Body != nil {
g.generateStatement(vc.Body)
}
// After:
for _, s := range vc.Body {
g.generateStatement(s)
}
All containsX() scanner functions that walk vc.Body — 6 occurrences (containsPar, containsPrint, containsTimer, containsStop, containsMostExpr, walkStatements) plus collectChanProtocols, collectBoolVars, collectRecordVars, containsRetypes, containsAltReplicator. Change from:
if c.Body != nil && g.containsX(c.Body) {
to:
for _, inner := range c.Body {
if g.containsX(inner) {
return true
}
}
This matches the pattern used by IF/CASE choice.Body iteration throughout the file.
4. Tests
- Add a parser test in
parser/parser_test.go for variant receive with scoped declarations
- Add an e2e test in
codegen/e2e_test.go that transpiles, compiles, and runs a program using variant receive with declarations in case bodies
Verification
go test ./... # all tests pass
# Specific test for the new feature:
cat > /tmp/test_variant_decl.occ << 'EOF'
PROTOCOL CMD
CASE
set.state; BOOL
evolve
terminate
:
PROC test(CHAN OF CMD control)
BOOL state, not.finished :
SEQ
state := FALSE
not.finished := TRUE
WHILE not.finished
control ? CASE
set.state; state
SKIP
evolve
BOOL next.state :
SEQ
next.state := TRUE
state := next.state
terminate
not.finished := FALSE
:
CHAN OF CMD ch :
PAR
test(ch)
SEQ
ch ! set.state; TRUE
ch ! evolve
ch ! terminate
EOF
./occam2go -o /tmp/test_variant_decl.go /tmp/test_variant_decl.occ
go run /tmp/test_variant_decl.go
If you need specific details from before exiting plan mode (like exact code snippets, error messages, or content you generated), read the full transcript at: /home/david/.claude/projects/-home-david-projects-code-associates-occam2go/6850029e-5661-4653-84d5-19bc82f092a9.jsonl