aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-22 15:14:35 +0000
committer_ov4 <ov4@ov4.org>2026-10-22 15:33:15 +0000
commit17993103e1ba1d142205eb2e41291edebc0e3a89 (patch)
tree4a3208d9c0edb1bdd7ae317da0d6dd0d098279b6
parentcb62de1eba07d4c522213bdd8331686684b3468c (diff)
fix(parser): report missing THEN and ')' on the line that needs them
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
-rw-r--r--include/cps/Parser.h4
-rw-r--r--lib/Parser/Parser.cc1
-rw-r--r--lib/Parser/ParserControlFlow.cc13
-rw-r--r--lib/Parser/ParserExpression.cc2
-rw-r--r--tests/iii/missing-parenthesis/case.json2
5 files changed, 15 insertions, 7 deletions
diff --git a/include/cps/Parser.h b/include/cps/Parser.h
index eff25a5..e710150 100644
--- a/include/cps/Parser.h
+++ b/include/cps/Parser.h
@@ -19,6 +19,7 @@ class Parser {
Lexer &Lex;
int CurTok = tok_eof;
bool StartsLine = true;
+ int PrevTokLine = 0; // line of the token before CurTok
bool ParsingCaseLabel = false;
std::vector<unsigned> CaseBodyDepths;
unsigned NumErrors = 0;
@@ -33,6 +34,9 @@ class Parser {
};
void getNextToken();
+ // Line for a diagnostic about a token missing before CurTok: the previous
+ // line when CurTok starts a new one.
+ int missingLine() const { return StartsLine ? PrevTokLine : Lex.getLine(); }
int GetTokPrecedence();
std::unique_ptr<ExprAST> ParseExpression();
diff --git a/lib/Parser/Parser.cc b/lib/Parser/Parser.cc
index d17856b..ad2e408 100644
--- a/lib/Parser/Parser.cc
+++ b/lib/Parser/Parser.cc
@@ -30,6 +30,7 @@ Parser::Parser(Lexer &L) : Lex(L) {
void Parser::getNextToken() {
int PreviousLine = CurTok == tok_eof ? 0 : Lex.getLine();
+ PrevTokLine = PreviousLine;
CurTok = Lex.gettok();
StartsLine = Lex.getLine() != PreviousLine;
}
diff --git a/lib/Parser/ParserControlFlow.cc b/lib/Parser/ParserControlFlow.cc
index 7caf555..542ef0e 100644
--- a/lib/Parser/ParserControlFlow.cc
+++ b/lib/Parser/ParserControlFlow.cc
@@ -26,10 +26,13 @@ std::unique_ptr<StmtAST> Parser::ParseIfStmt() {
if (!Cond) return nullptr;
if (CurTok != tok_then) {
- cps::sourceError(Lex.getLine(), "expected THEN");
- return nullptr;
+ cps::sourceError(missingLine(), "expected THEN");
+ // A THEN missing at the end of a line is reported and then treated as
+ // present so the rest of the statement still parses.
+ if (!StartsLine) return nullptr;
+ } else {
+ getNextToken();
}
- getNextToken();
std::vector<std::unique_ptr<StmtAST>> ThenStmts = ParseBlock({tok_else, tok_endif});
@@ -93,7 +96,7 @@ std::unique_ptr<StmtAST> Parser::ParseForStmt() {
getNextToken();
if (CurTok != tok_assign) {
- cps::sourceError(Lex.getLine(), "expected '<-' in FOR loop");
+ cps::sourceError(missingLine(), "expected '<-' in FOR loop");
return nullptr;
}
getNextToken();
@@ -102,7 +105,7 @@ std::unique_ptr<StmtAST> Parser::ParseForStmt() {
if (!Start) return nullptr;
if (CurTok != tok_to) {
- cps::sourceError(Lex.getLine(), "expected TO in FOR loop");
+ cps::sourceError(missingLine(), "expected TO in FOR loop");
return nullptr;
}
getNextToken();
diff --git a/lib/Parser/ParserExpression.cc b/lib/Parser/ParserExpression.cc
index 8c5e8ce..b75f704 100644
--- a/lib/Parser/ParserExpression.cc
+++ b/lib/Parser/ParserExpression.cc
@@ -211,7 +211,7 @@ std::unique_ptr<ExprAST> Parser::ParseParenExpr() {
auto V = ParseExpression();
if (!V) return nullptr;
if (CurTok != ')') {
- cps::sourceError(Lex.getLine(), "expected ')'");
+ cps::sourceError(missingLine(), "expected ')'");
return nullptr;
}
getNextToken();
diff --git a/tests/iii/missing-parenthesis/case.json b/tests/iii/missing-parenthesis/case.json
index 3ccd080..5421130 100644
--- a/tests/iii/missing-parenthesis/case.json
+++ b/tests/iii/missing-parenthesis/case.json
@@ -2,7 +2,7 @@
"errors": [
{
"reason": "expected\\ '\\)'",
- "line": 3
+ "line": 2
}
]
}