Here's a summary of what was found and fixed:
Root Causes
Two distinct infinite loop bugs were identified:
1. Nested/Replicated IF within IF (parser.go:parseIfStatement)
When an IF keyword appeared as a choice inside another IF block (e.g., IF i = 0 FOR n used as a replicated choice), parseExpression(LOWEST) was called on the IF token. Since IF isn't a valid expression prefix, parseExpression returned nil without advancing the cursor. The main loop had no progress guard, so it re-parsed the same IF token forever.
Fix: Detect curToken == IF in the choices loop and recursively call parseIfStatement() to properly parse it as a nested IF. Store the result in a new NestedIf *IfStatement field on IfChoice. Also added a progress guard as a safety net.
2. Unknown types in variant receive (parser.go:parseVariantReceive)
When a variant ? CASE block contained declarations with unknown types (e.g., COORDINATES p: where COORDINATES is parsed as an IDENT), the parser treated it as a variant tag name but never advanced past it. The next iteration of the loop saw the same IDENT token and looped forever.
Fix: Added progress guards to both parseVariantReceive and parseVariantReceiveWithIndex. When no progress is detected, the parser forces advancement or breaks. Also changed the "unexpected tag" error path to skip the token with continue instead of returning immediately.
Changes Made
| File |
Change |
ast/ast.go |
Added NestedIf *IfStatement to IfChoice |
parser/parser.go |
Detect nested IF in parseIfStatement, add progress guards to parseIfStatement, parseCaseStatement, parseVariantReceive, parseVariantReceiveWithIndex, parseAltCases |
codegen/codegen.go |
Refactored generateIfStatement into flattenIfChoices (inlines non-replicated nested IFs), generateReplicatedIfLoop, and generateIfChoiceChain (handles mixed choices with _ifmatched flag). Updated 6 scanner functions to traverse NestedIf. |
codegen/e2e_control_test.go |
Added 4 new e2e tests: replicated IF with default, no-match fallthrough, preceding normal choice, non-replicated nested IF |