diff --git a/codegen/codegen.go b/codegen/codegen.go index 418f5f0..cec8b5b 100644 --- a/codegen/codegen.go +++ b/codegen/codegen.go @@ -1902,9 +1902,21 @@ func (g *Generator) generateAltBlock(alt *ast.AltBlock) { g.write(fmt.Sprintf("case %s = <-%s:\n", goIdent(c.Variable), goIdent(c.Channel))) } g.indent++ + guardedSkip := c.IsSkip && c.Guard != nil + if guardedSkip { + g.builder.WriteString(strings.Repeat("\t", g.indent)) + g.write("if ") + g.generateExpression(c.Guard) + g.write(" {\n") + g.indent++ + } for _, s := range c.Body { g.generateStatement(s) } + if guardedSkip { + g.indent-- + g.writeLine("}") + } g.indent-- } g.writeLine("}") diff --git a/codegen/e2e_misc_test.go b/codegen/e2e_misc_test.go index dadfbb1..0d142fa 100644 --- a/codegen/e2e_misc_test.go +++ b/codegen/e2e_misc_test.go @@ -233,6 +233,59 @@ func TestE2E_AltGuardedSkip(t *testing.T) { } } +func TestE2E_AltGuardedSkipTrue(t *testing.T) { + // Issue #77: ALT with channel case and guarded SKIP where guard is TRUE + // The SKIP fires immediately, then the channel send proceeds + occam := `SEQ + CHAN OF INT c: + INT result: + BOOL ready: + ready := TRUE + result := 0 + PAR + SEQ + ALT + ready & SKIP + result := 99 + c ? result + SKIP + c ! 42 + c ? result + print.int(result) +` + output := transpileCompileRun(t, occam) + expected := "42\n" + if output != expected { + t.Errorf("expected %q, got %q", expected, output) + } +} + +func TestE2E_AltGuardedSkipFalse(t *testing.T) { + // Issue #77: ALT with channel case and guarded SKIP where guard is FALSE + // The SKIP guard is false, so the channel case fires + occam := `SEQ + CHAN OF INT c: + INT result: + BOOL ready: + ready := FALSE + result := 0 + PAR + SEQ + ALT + ready & SKIP + result := 99 + c ? result + SKIP + c ! 77 + print.int(result) +` + output := transpileCompileRun(t, occam) + expected := "77\n" + if output != expected { + t.Errorf("expected %q, got %q", expected, output) + } +} + func TestE2E_MultiLineAbbreviation(t *testing.T) { // Issue #79: IS at end of line as continuation occam := `SEQ diff --git a/parser/parser_test.go b/parser/parser_test.go index 85a9104..d4b8bb1 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -349,6 +349,38 @@ func TestAltBlockWithGuard(t *testing.T) { } } +func TestAltBlockWithGuardedSkip(t *testing.T) { + input := `ALT + ready & SKIP + some.proc() +` + l := lexer.New(input) + p := New(l) + program := p.ParseProgram() + checkParserErrors(t, p) + + if len(program.Statements) != 1 { + t.Fatalf("expected 1 statement, got %d", len(program.Statements)) + } + + alt, ok := program.Statements[0].(*ast.AltBlock) + if !ok { + t.Fatalf("expected AltBlock, got %T", program.Statements[0]) + } + + if len(alt.Cases) != 1 { + t.Fatalf("expected 1 case, got %d", len(alt.Cases)) + } + + c := alt.Cases[0] + if !c.IsSkip { + t.Error("expected IsSkip to be true") + } + if c.Guard == nil { + t.Error("expected guard expression, got nil") + } +} + func TestWhileLoop(t *testing.T) { input := `WHILE x > 0 x := x - 1