diff --git a/compiler/parser/parser.go b/compiler/parser/parser.go index d2498a6..98a72b2 100644 --- a/compiler/parser/parser.go +++ b/compiler/parser/parser.go @@ -1313,8 +1313,13 @@ func (p *Parser) parseIf() *ast.IfStmt { } endPos := p.current.Pos - if !p.match(token.ENDIF) { - p.match(token.END) // alternative + if !p.match(token.ENDIF) && !p.match(token.END) { + // Without this, a missing ENDIF lets parseStmtBlock above + // swallow every subsequent top-level FUNCTION as part of the + // IF body — the build then "succeeds" with a near-empty + // prg_*.go and dies at runtime with "function not found". + p.error(fmt.Sprintf("expected ENDIF or END to close IF at %s, got %v %q", + ifPos, p.current.Kind, p.current.Literal)) } p.expectEndOfStmt() @@ -1399,8 +1404,9 @@ func (p *Parser) parseDoWhile() *ast.DoWhileStmt { body := p.parseStmtBlock(token.ENDDO, token.END) endPos := p.current.Pos - if !p.match(token.ENDDO) { - p.match(token.END) + if !p.match(token.ENDDO) && !p.match(token.END) { + p.error(fmt.Sprintf("expected ENDDO or END to close WHILE at %s, got %v %q", + doPos, p.current.Kind, p.current.Literal)) } p.expectEndOfStmt() @@ -1438,8 +1444,9 @@ func (p *Parser) parseFor() ast.Stmt { body := p.parseStmtBlock(token.NEXT, token.END) nextPos := p.current.Pos - if !p.match(token.NEXT) { - p.match(token.END) + if !p.match(token.NEXT) && !p.match(token.END) { + p.error(fmt.Sprintf("expected NEXT or END to close FOR at %s, got %v %q", + forPos, p.current.Kind, p.current.Literal)) } // Skip optional counter variable after NEXT (e.g. NEXT nVar) if p.current.Kind != token.NEWLINE && p.current.Kind != token.EOF { @@ -1476,8 +1483,9 @@ func (p *Parser) parseForEach(forPos token.Position) *ast.ForEachStmt { body := p.parseStmtBlock(token.NEXT, token.END) nextPos := p.current.Pos - if !p.match(token.NEXT) { - p.match(token.END) + if !p.match(token.NEXT) && !p.match(token.END) { + p.error(fmt.Sprintf("expected NEXT or END to close FOR EACH at %s, got %v %q", + forPos, p.current.Kind, p.current.Literal)) } // Skip optional counter variable after NEXT if p.current.Kind != token.NEWLINE && p.current.Kind != token.EOF { @@ -1531,8 +1539,9 @@ func (p *Parser) parseDoCase() *ast.IfStmt { } endPos := p.current.Pos - if !p.match(token.ENDCASE) { - p.match(token.END) + if !p.match(token.ENDCASE) && !p.match(token.END) { + p.error(fmt.Sprintf("expected ENDCASE or END to close DO CASE at %s, got %v %q", + doPos, p.current.Kind, p.current.Literal)) } p.expectEndOfStmt() @@ -1569,10 +1578,9 @@ func (p *Parser) parseSwitch() *ast.SwitchStmt { } endPos := p.current.Pos - if !p.match(token.ENDSWITCH) { - if !p.match(token.ENDCASE) { - p.match(token.END) - } + if !p.match(token.ENDSWITCH) && !p.match(token.ENDCASE) && !p.match(token.END) { + p.error(fmt.Sprintf("expected ENDSWITCH or END to close SWITCH at %s, got %v %q", + switchPos, p.current.Kind, p.current.Literal)) } p.expectEndOfStmt()