diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-21 14:03:31 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-21 14:03:31 +0000 |
| commit | b4ffb2d9498560557821714e2d4651279dd6817c (patch) | |
| tree | 995ad02bdb8cc461f48a53683c4fd7f2ddd8656b /lib/Parser | |
| parent | f1f5fa394a67a789914ccf2b24d534a0e466ae1b (diff) | |
feat(diagnostics): print source diagnostics in gcc file:line: layout
Lexer, parser, driver and codegen diagnostics now read
"<path>:<line>: error: <message>" instead of "error: <message> at line N
in <path>". The path is always printed as given on the command line.
Call sites pass the bare message to cps::sourceError/sourceWarning, which
carry printf format checking; reportError routes through the same helper.
The suite iii harness parses the new layout and matches the reason
against the message only. iii/template-class-pack-field passed only
because its reason regex matched the case path, so it is now
case-insensitive.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'lib/Parser')
| -rw-r--r-- | lib/Parser/Parser.cc | 34 | ||||
| -rw-r--r-- | lib/Parser/ParserControlFlow.cc | 34 | ||||
| -rw-r--r-- | lib/Parser/ParserExpression.cc | 37 | ||||
| -rw-r--r-- | lib/Parser/ParserFile.cc | 15 | ||||
| -rw-r--r-- | lib/Parser/ParserFunction.cc | 97 | ||||
| -rw-r--r-- | lib/Parser/ParserType.cc | 97 |
6 files changed, 151 insertions, 163 deletions
diff --git a/lib/Parser/Parser.cc b/lib/Parser/Parser.cc index 3d45a97..b5c842f 100644 --- a/lib/Parser/Parser.cc +++ b/lib/Parser/Parser.cc @@ -100,7 +100,7 @@ std::unique_ptr<StmtAST> Parser::ParseStatementImpl() { if (CurTok == tok_template) return ParseTemplateDecl(); if (CurTok == tok_extern) { if (BlockDepth != 1) { - sourceDiagnostic(Lex.getLine(), "error: EXTERN is only allowed at top level at line %d\n", Lex.getLine()); + sourceError(Lex.getLine(), "EXTERN is only allowed at top level"); getNextToken(); return nullptr; } @@ -113,12 +113,12 @@ std::unique_ptr<StmtAST> Parser::ParseStatementImpl() { int Line = Lex.getLine(); getNextToken(); if (BlockDepth != 1) { - sourceDiagnostic(Line, "error: %s is only allowed at top level at line %d\n", Keyword, Line); + sourceError(Line, "%s is only allowed at top level", Keyword); return nullptr; } if (Include) { if (CurTok != tok_string_literal) { - sourceDiagnostic(Line, "error: %s requires a string literal at line %d\n", Keyword, Line); + sourceError(Line, "%s requires a string literal", Keyword); return nullptr; } std::unique_ptr<StmtAST> Stmt; @@ -129,14 +129,14 @@ std::unique_ptr<StmtAST> Parser::ParseStatementImpl() { } auto Body = ParseBlock({tok_endglobal}); if (CurTok != tok_endglobal) { - sourceDiagnostic(Line, "error: Expected ENDGLOBAL at line %d\n", Lex.getLine()); + sourceError(Lex.getLine(), "Expected ENDGLOBAL"); return nullptr; } getNextToken(); return std::make_unique<GlobalBlockAST>(std::move(Body)); } if (CurTok == tok_endglobal) { - sourceDiagnostic(Lex.getLine(), "error: ENDGLOBAL without matching GLOBAL at line %d\n", Lex.getLine()); + sourceError(Lex.getLine(), "ENDGLOBAL without matching GLOBAL"); getNextToken(); return nullptr; } @@ -144,7 +144,7 @@ std::unique_ptr<StmtAST> Parser::ParseStatementImpl() { int Line = Lex.getLine(); getNextToken(); if (CurTok != tok_identifier) { - cps::sourceDiagnostic(Lex.getLine(), "error: DELETE requires an object designator at line %d\n", Line); + cps::sourceError(Line, "DELETE requires an object designator"); return nullptr; } std::string Name = Lex.IdentifierStr; @@ -156,7 +156,7 @@ std::unique_ptr<StmtAST> Parser::ParseStatementImpl() { } if (CurTok == tok_case) return ParseCaseStmt(); if (CurTok == tok_endcase || CurTok == tok_otherwise) { - cps::sourceDiagnostic(Lex.getLine(), "error: Unexpected CASE terminator at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Unexpected CASE terminator"); getNextToken(); return nullptr; } @@ -170,7 +170,7 @@ std::unique_ptr<StmtAST> Parser::ParseStatementImpl() { else if (CurTok == tok_input) { getNextToken(); if (CurTok != tok_identifier) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected variable name after INPUT at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected variable name after INPUT"); return nullptr; } std::string Name = Lex.IdentifierStr; @@ -211,8 +211,8 @@ std::unique_ptr<StmtAST> Parser::ParseStatementImpl() { return std::make_unique<ThrowStmtAST>(); } else if (CurTok == tok_catch || CurTok == tok_endtry) { - cps::sourceDiagnostic(Lex.getLine(), "error: Unexpected %s without matching TRY at line %d\n", - CurTok == tok_catch ? "CATCH" : "ENDTRY", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Unexpected %s without matching TRY", + CurTok == tok_catch ? "CATCH" : "ENDTRY"); getNextToken(); return nullptr; } @@ -230,7 +230,7 @@ std::unique_ptr<StmtAST> Parser::ParseStatementImpl() { getNextToken(); if (CurTok == tok_function) return ParseFunction({}, true, true); if (CurTok == tok_procedure) return ParseProcedure({}, true, true); - cps::sourceDiagnostic(Line, "error: OVERLOAD must be followed by FUNCTION or PROCEDURE at line %d\n", Line); + cps::sourceError(Line, "OVERLOAD must be followed by FUNCTION or PROCEDURE"); return nullptr; } else if (CurTok == tok_function) { @@ -261,22 +261,22 @@ std::unique_ptr<StmtAST> Parser::ParseStatementImpl() { return ParseTypeDecl(); } else if (CurTok == tok_define) { - cps::sourceDiagnostic(Lex.getLine(), "error: DEFINE (SET literals) is not implemented at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "DEFINE (SET literals) is not implemented"); getNextToken(); return nullptr; } else if (CurTok == tok_endtype) { - cps::sourceDiagnostic(Lex.getLine(), "error: ENDTYPE without matching TYPE at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "ENDTYPE without matching TYPE"); getNextToken(); return nullptr; } else if (CurTok == tok_endclass) { - cps::sourceDiagnostic(Lex.getLine(), "error: ENDCLASS without matching CLASS at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "ENDCLASS without matching CLASS"); getNextToken(); return nullptr; } - cps::sourceDiagnostic(Lex.getLine(), "error: Unexpected token at line %d when expecting a statement\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Unexpected token when expecting a statement"); getNextToken(); // guarantee progress so error recovery cannot loop forever return nullptr; } @@ -302,7 +302,7 @@ std::unique_ptr<StmtAST> Parser::ParseAssignStmt() { if (!Parsed) return nullptr; TemplateArgs = std::move(*Parsed); if (CurTok != '(') { - sourceDiagnostic(Line, "error: Expected '(' after explicit template arguments at line %d\n", Line); + sourceError(Line, "Expected '(' after explicit template arguments"); return nullptr; } } @@ -329,7 +329,7 @@ std::unique_ptr<StmtAST> Parser::ParseAssignStmt() { } if (CurTok != tok_assign) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected '<-' after identifier '%s' at line %d\n", Name.c_str(), Line); + cps::sourceError(Line, "Expected '<-' after identifier '%s'", Name.c_str()); return nullptr; } getNextToken(); diff --git a/lib/Parser/ParserControlFlow.cc b/lib/Parser/ParserControlFlow.cc index 8ca024d..8cb5c4e 100644 --- a/lib/Parser/ParserControlFlow.cc +++ b/lib/Parser/ParserControlFlow.cc @@ -9,13 +9,13 @@ std::unique_ptr<StmtAST> Parser::ParseTryStmt() { getNextToken(); auto Body = ParseBlock({tok_catch, tok_endtry}); if (CurTok != tok_catch) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected CATCH in TRY at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected CATCH in TRY"); return nullptr; } getNextToken(); auto CatchBody = ParseBlock({tok_endtry, tok_catch}); if (CurTok != tok_endtry) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected ENDTRY after CATCH at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected ENDTRY after CATCH"); return nullptr; } getNextToken(); @@ -28,7 +28,7 @@ std::unique_ptr<StmtAST> Parser::ParseIfStmt() { if (!Cond) return nullptr; if (CurTok != tok_then) { - cps::sourceDiagnostic(Lex.getLine(), "error: expected THEN at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "expected THEN"); return nullptr; } getNextToken(); @@ -42,7 +42,7 @@ std::unique_ptr<StmtAST> Parser::ParseIfStmt() { } if (CurTok != tok_endif) { - cps::sourceDiagnostic(Lex.getLine(), "error: expected ENDIF at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "expected ENDIF"); return nullptr; } getNextToken(); @@ -60,7 +60,7 @@ std::unique_ptr<StmtAST> Parser::ParseWhileStmt() { std::vector<std::unique_ptr<StmtAST>> Body = ParseBlock({tok_endwhile}); if (CurTok != tok_endwhile) { - cps::sourceDiagnostic(Lex.getLine(), "error: expected ENDWHILE\n"); + cps::sourceError(Lex.getLine(), "expected ENDWHILE"); return nullptr; } getNextToken(); @@ -74,7 +74,7 @@ std::unique_ptr<StmtAST> Parser::ParseRepeatStmt() { std::vector<std::unique_ptr<StmtAST>> Body = ParseBlock({tok_until}); if (CurTok != tok_until) { - cps::sourceDiagnostic(Lex.getLine(), "error: expected UNTIL\n"); + cps::sourceError(Lex.getLine(), "expected UNTIL"); return nullptr; } getNextToken(); @@ -88,14 +88,14 @@ std::unique_ptr<StmtAST> Parser::ParseRepeatStmt() { std::unique_ptr<StmtAST> Parser::ParseForStmt() { getNextToken(); if (CurTok != tok_identifier) { - cps::sourceDiagnostic(Lex.getLine(), "error: expected identifier after FOR\n"); + cps::sourceError(Lex.getLine(), "expected identifier after FOR"); return nullptr; } std::string VarName = Lex.IdentifierStr; getNextToken(); if (CurTok != tok_assign) { - cps::sourceDiagnostic(Lex.getLine(), "error: expected '<-' in FOR loop\n"); + cps::sourceError(Lex.getLine(), "expected '<-' in FOR loop"); return nullptr; } getNextToken(); @@ -104,7 +104,7 @@ std::unique_ptr<StmtAST> Parser::ParseForStmt() { if (!Start) return nullptr; if (CurTok != tok_to) { - cps::sourceDiagnostic(Lex.getLine(), "error: expected TO in FOR loop\n"); + cps::sourceError(Lex.getLine(), "expected TO in FOR loop"); return nullptr; } getNextToken(); @@ -122,18 +122,18 @@ std::unique_ptr<StmtAST> Parser::ParseForStmt() { std::vector<std::unique_ptr<StmtAST>> Body = ParseBlock({tok_next}); if (CurTok != tok_next) { - cps::sourceDiagnostic(Lex.getLine(), "error: expected NEXT\n"); + cps::sourceError(Lex.getLine(), "expected NEXT"); return nullptr; } getNextToken(); if (CurTok != tok_identifier) { - cps::sourceDiagnostic(Lex.getLine(), "error: expected identifier after NEXT (e.g., NEXT %s)\n", VarName.c_str()); + cps::sourceError(Lex.getLine(), "expected identifier after NEXT (e.g., NEXT %s)", VarName.c_str()); return nullptr; } if (!sameIdentifier(Lex.IdentifierStr, VarName)) { - cps::sourceDiagnostic(Lex.getLine(), "error: NEXT identifier '%s' does not match FOR variable '%s'\n", + cps::sourceError(Lex.getLine(), "NEXT identifier '%s' does not match FOR variable '%s'", Lex.IdentifierStr.c_str(), VarName.c_str()); return nullptr; } @@ -178,12 +178,12 @@ bool Parser::atCaseBoundary() { std::unique_ptr<StmtAST> Parser::ParseCaseStmt() { getNextToken(); if (CurTok != tok_of) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected OF after CASE at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected OF after CASE"); return nullptr; } getNextToken(); if (CurTok != tok_identifier) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected identifier after CASE OF at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected identifier after CASE OF"); return nullptr; } std::string Selector = Lex.IdentifierStr; @@ -192,7 +192,7 @@ std::unique_ptr<StmtAST> Parser::ParseCaseStmt() { bool SeenOtherwise = false; while (CurTok != tok_endcase && CurTok != tok_eof) { if (SeenOtherwise || !isCaseLabel()) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected CASE label on a new line (OTHERWISE must be last) at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected CASE label on a new line (OTHERWISE must be last)"); return nullptr; } CaseBranch Branch; @@ -213,7 +213,7 @@ std::unique_ptr<StmtAST> Parser::ParseCaseStmt() { if (!Branch.Lower) return nullptr; } if (CurTok != tok_colon) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected ':' after CASE label at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected ':' after CASE label"); return nullptr; } getNextToken(); @@ -221,7 +221,7 @@ std::unique_ptr<StmtAST> Parser::ParseCaseStmt() { Branches.push_back(std::move(Branch)); } if (CurTok != tok_endcase || Branches.empty()) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected nonempty CASE and ENDCASE at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected nonempty CASE and ENDCASE"); return nullptr; } getNextToken(); diff --git a/lib/Parser/ParserExpression.cc b/lib/Parser/ParserExpression.cc index ef8e1d3..754d1f2 100644 --- a/lib/Parser/ParserExpression.cc +++ b/lib/Parser/ParserExpression.cc @@ -19,7 +19,7 @@ int Parser::GetTokPrecedence() { bool Parser::ParseIntegerValue(bool Negative, int64_t &Out) { const uint64_t Max = uint64_t(std::numeric_limits<int64_t>::max()); if (Lex.NumVal > Max + (Negative ? 1u : 0u)) { - cps::sourceDiagnostic(Lex.getLine(), "error: Integer literal is outside the i64 range at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Integer literal is outside the i64 range"); getNextToken(); return false; } @@ -88,14 +88,14 @@ std::unique_ptr<ExprAST> Parser::ParseIdentifierExpr() { if (PackNames.count(IdName)) { if (CurTok != tok_ellipsis) { - sourceDiagnostic(Line, "error: A parameter pack must be expanded with '...' at line %d\n", Line); + sourceError(Line, "A parameter pack must be expanded with '...'"); return nullptr; } getNextToken(); return std::make_unique<PackExpansionExprAST>(IdName, Line); } if (CurTok == tok_ellipsis) { - sourceDiagnostic(Line, "error: Only a parameter pack may be expanded at line %d\n", Line); + sourceError(Line, "Only a parameter pack may be expanded"); getNextToken(); return nullptr; } @@ -110,8 +110,7 @@ std::unique_ptr<ExprAST> Parser::ParseIdentifierExpr() { auto Args = ParseExprList(')', true); if (!Args) return nullptr; if (CurTok == '[' || CurTok == '^') { - cps::sourceDiagnostic(Lex.getLine(), "error: record/array/pointer access on a function result is not supported at line %d\n", - Lex.getLine()); + cps::sourceError(Lex.getLine(), "record/array/pointer access on a function result is not supported"); return nullptr; } return ParseResultMethods(std::make_unique<CallExprAST>(IdName, std::move(*Args), Line, std::move(TemplateArgs)), Line); @@ -135,7 +134,7 @@ std::unique_ptr<ExprAST> Parser::ParseIdentifierExpr() { std::unique_ptr<MemberCallExprAST> Parser::ParseMemberCall( const std::string &Name, std::vector<DesignatorAccess> Accesses, int Line) { if (Accesses.empty() || Accesses.back().Kind != AccessKind::Field) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected a method name after '.' at line %d\n", Line); + cps::sourceError(Line, "Expected a method name after '.'"); return nullptr; } std::string Method = Accesses.back().FieldName; @@ -149,8 +148,7 @@ std::unique_ptr<MemberCallExprAST> Parser::ParseMemberCall( Args = std::move(*Parsed); } if (CurTok == '[' || CurTok == '^') { - cps::sourceDiagnostic(Lex.getLine(), "error: record/array/pointer access on a function result is not supported at line %d\n", - Lex.getLine()); + cps::sourceError(Lex.getLine(), "record/array/pointer access on a function result is not supported"); return nullptr; } auto Result = ParseResultMethods(std::make_unique<MemberCallExprAST>(std::move(Receiver), Method, std::move(Args), Line), Line); @@ -172,7 +170,7 @@ bool Parser::ParseDesignatorSuffix(std::vector<DesignatorAccess> &Out) { } else if (CurTok == '.') { getNextToken(); if (CurTok != tok_identifier && CurTok != tok_new && CurTok != tok_delete && CurTok != tok_operator) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected field name after '.' at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected field name after '.'"); return false; } DesignatorAccess A; @@ -209,7 +207,7 @@ std::unique_ptr<ExprAST> Parser::ParseParenExpr() { std::string TypeName = ParseTypeName(); if (TypeName.empty()) return nullptr; if (CurTok != ')') { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected ')' after cast type at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected ')' after cast type"); return nullptr; } getNextToken(); @@ -220,7 +218,7 @@ std::unique_ptr<ExprAST> Parser::ParseParenExpr() { auto V = ParseExpression(); if (!V) return nullptr; if (CurTok != ')') { - cps::sourceDiagnostic(Lex.getLine(), "error: expected ')' at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "expected ')'"); return nullptr; } getNextToken(); @@ -239,11 +237,11 @@ std::unique_ptr<ExprAST> Parser::ParseResultMethods(std::unique_ptr<ExprAST> Exp Name = CurTok == tok_delete ? "DELETE" : Lex.IdentifierStr; getNextToken(); } else { - sourceDiagnostic(Lex.getLine(), "error: Expected method name at line %d\n", Lex.getLine()); + sourceError(Lex.getLine(), "Expected method name"); return nullptr; } if (CurTok != '(') { - sourceDiagnostic(Lex.getLine(), "error: Expected '(' after method name at line %d\n", Lex.getLine()); + sourceError(Lex.getLine(), "Expected '(' after method name"); return nullptr; } getNextToken(); @@ -264,7 +262,7 @@ std::unique_ptr<ExprAST> Parser::ParsePrimary() { std::unique_ptr<ExprAST> Parser::ParsePrimaryImpl() { switch (CurTok) { case tok_new: - cps::sourceDiagnostic(Lex.getLine(), "error: NEW is only allowed on the right of an assignment at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "NEW is only allowed on the right of an assignment"); return nullptr; case tok_identifier: case tok_operator: return ParseIdentifierExpr(); case tok_number_int: return ParseNumberExpr(); @@ -289,8 +287,8 @@ std::unique_ptr<ExprAST> Parser::ParsePrimaryImpl() { } case '(': return ParseParenExpr(); default: - cps::sourceDiagnostic(Lex.getLine(), "error: unknown token '%c' (%d) at line %d when expecting an expression\n", - (char)CurTok, CurTok, Lex.getLine()); + cps::sourceError(Lex.getLine(), "unknown token '%c' (%d) when expecting an expression", + (char)CurTok, CurTok); return nullptr; } } @@ -315,14 +313,13 @@ std::unique_ptr<ExprAST> Parser::ParseUnaryImpl() { int Line = Lex.getLine(); getNextToken(); if (CurTok != tok_identifier) { - cps::sourceDiagnostic(Lex.getLine(), "error: '^' (address-of) requires a variable, array element or record field at line %d\n", - Line); + cps::sourceError(Line, "'^' (address-of) requires a variable, array element or record field"); return nullptr; } std::string BaseName = Lex.IdentifierStr; getNextToken(); if (CurTok == '(') { - cps::sourceDiagnostic(Lex.getLine(), "error: cannot take the address of a function result at line %d\n", Line); + cps::sourceError(Line, "cannot take the address of a function result"); return nullptr; } std::vector<DesignatorAccess> Accesses; @@ -389,7 +386,7 @@ std::optional<std::vector<std::unique_ptr<ExprAST>>> Parser::ParseExprList(char if (CurTok == CloseDelim) break; if (CurTok != ',') { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected ',' or '%c' at line %d\n", CloseDelim, Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected ',' or '%c'", CloseDelim); return std::nullopt; } getNextToken(); diff --git a/lib/Parser/ParserFile.cc b/lib/Parser/ParserFile.cc index 99a939f..c51c7e7 100644 --- a/lib/Parser/ParserFile.cc +++ b/lib/Parser/ParserFile.cc @@ -14,7 +14,7 @@ std::unique_ptr<StmtAST> Parser::ParseOpenFile() { if (!FileName) return nullptr; if (CurTok != tok_for) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected FOR after OPENFILE filename at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected FOR after OPENFILE filename"); return nullptr; } getNextToken(); // eat FOR @@ -25,11 +25,10 @@ std::unique_ptr<StmtAST> Parser::ParseOpenFile() { case tok_write: Mode = FileMode::Write; break; case tok_append: Mode = FileMode::Append; break; case tok_random: - cps::sourceDiagnostic(Lex.getLine(), "error: File mode RANDOM is not implemented (text files only) at line %d\n", - Lex.getLine()); + cps::sourceError(Lex.getLine(), "File mode RANDOM is not implemented (text files only)"); return nullptr; default: - cps::sourceDiagnostic(Lex.getLine(), "error: Expected file mode READ, WRITE or APPEND at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected file mode READ, WRITE or APPEND"); return nullptr; } getNextToken(); // eat the mode keyword @@ -46,13 +45,13 @@ std::unique_ptr<StmtAST> Parser::ParseReadFile() { if (!FileName) return nullptr; if (CurTok != ',') { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected ',' after READFILE filename at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected ',' after READFILE filename"); return nullptr; } getNextToken(); // eat ',' if (CurTok != tok_identifier) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected variable name after ',' in READFILE at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected variable name after ',' in READFILE"); return nullptr; } std::string VarName = Lex.IdentifierStr; @@ -62,7 +61,7 @@ std::unique_ptr<StmtAST> Parser::ParseReadFile() { // Consume the whole designator so it cannot replay as statements. std::vector<DesignatorAccess> Dummy; ParseDesignatorSuffix(Dummy); - cps::sourceDiagnostic(Lex.getLine(), "error: READFILE target must be a plain STRING variable at line %d\n", Line); + cps::sourceError(Line, "READFILE target must be a plain STRING variable"); return nullptr; } @@ -78,7 +77,7 @@ std::unique_ptr<StmtAST> Parser::ParseWriteFile() { if (!FileName) return nullptr; if (CurTok != ',') { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected ',' after WRITEFILE filename at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected ',' after WRITEFILE filename"); return nullptr; } getNextToken(); // eat ',' diff --git a/lib/Parser/ParserFunction.cc b/lib/Parser/ParserFunction.cc index a1f04c0..823e17f 100644 --- a/lib/Parser/ParserFunction.cc +++ b/lib/Parser/ParserFunction.cc @@ -15,8 +15,7 @@ bool Parser::ParseSignedIntBound(int64_t &Out) { getNextToken(); } if (CurTok != tok_number_int) { - cps::sourceDiagnostic(Lex.getLine(), "error: Array parameter bounds must be integer literals at line %d\n", - Lex.getLine()); + cps::sourceError(Lex.getLine(), "Array parameter bounds must be integer literals"); return false; } return ParseIntegerValue(Negative, Out); @@ -37,8 +36,7 @@ std::optional<std::vector<ParamDecl>> Parser::ParsePrototypeArgs(bool AllowByRef while (CurTok != ')') { if (CurTok == tok_byref) { if (!AllowByRef) { - cps::sourceDiagnostic(Lex.getLine(), "error: BYREF parameters are not allowed in a FUNCTION (procedures only) at line %d\n", - Lex.getLine()); + cps::sourceError(Lex.getLine(), "BYREF parameters are not allowed in a FUNCTION (procedures only)"); return std::nullopt; } Current = PassMode::ByRef; @@ -49,7 +47,7 @@ std::optional<std::vector<ParamDecl>> Parser::ParsePrototypeArgs(bool AllowByRef } if (CurTok != tok_identifier) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected argument name at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected argument name"); return std::nullopt; } ParamDecl P; @@ -59,7 +57,7 @@ std::optional<std::vector<ParamDecl>> Parser::ParsePrototypeArgs(bool AllowByRef getNextToken(); if (CurTok != tok_colon) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected ':' after argument name at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected ':' after argument name"); return std::nullopt; } getNextToken(); @@ -73,8 +71,7 @@ std::optional<std::vector<ParamDecl>> Parser::ParsePrototypeArgs(bool AllowByRef int64_t Lo = 0, Hi = 0; if (!ParseSignedIntBound(Lo)) return std::nullopt; if (CurTok != tok_colon) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected ':' between array parameter bounds at line %d\n", - Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected ':' between array parameter bounds"); return std::nullopt; } getNextToken(); @@ -82,8 +79,7 @@ std::optional<std::vector<ParamDecl>> Parser::ParsePrototypeArgs(bool AllowByRef P.DeclaredBounds.emplace_back(Lo, Hi); if (CurTok == ']') break; if (CurTok != ',') { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected ',' or ']' in array parameter bounds at line %d\n", - Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected ',' or ']' in array parameter bounds"); return std::nullopt; } getNextToken(); @@ -94,8 +90,8 @@ std::optional<std::vector<ParamDecl>> Parser::ParsePrototypeArgs(bool AllowByRef P.Rank = 1; // ARRAY OF T: bounds travel with the argument } if (CurTok != tok_of) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected OF after ARRAY in parameter '%s' at line %d\n", - P.Name.c_str(), Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected OF after ARRAY in parameter '%s'", + P.Name.c_str()); return std::nullopt; } getNextToken(); @@ -103,29 +99,29 @@ std::optional<std::vector<ParamDecl>> Parser::ParsePrototypeArgs(bool AllowByRef P.TypeName = ParseTypeName(false); if (P.TypeName.empty()) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected argument type for '%s'\n", P.Name.c_str()); + cps::sourceError(Lex.getLine(), "Expected argument type for '%s'", P.Name.c_str()); return std::nullopt; } if (CurTok == tok_ellipsis) { if (P.IsArray || !isTemplatePack(P.TypeName)) { - sourceDiagnostic(P.Line, "error: A pack parameter must use the current template pack and cannot be ARRAY at line %d\n", P.Line); + sourceError(P.Line, "A pack parameter must use the current template pack and cannot be ARRAY"); return std::nullopt; } P.IsPack = true; getNextToken(); if (CurTok != ')') { - sourceDiagnostic(P.Line, "error: A pack parameter must be last at line %d\n", P.Line); + sourceError(P.Line, "A pack parameter must be last"); return std::nullopt; } } else if (isTemplatePack(P.TypeName)) { - sourceDiagnostic(P.Line, "error: A template parameter pack requires '...' at line %d\n", P.Line); + sourceError(P.Line, "A template parameter pack requires '...'"); return std::nullopt; } for (const ParamDecl &Prev : Params) { if (sameIdentifier(Prev.Name, P.Name)) { - cps::sourceDiagnostic(Lex.getLine(), "error: Duplicate parameter name '%s' at line %d\n", - P.Name.c_str(), Lex.getLine()); + cps::sourceError(Lex.getLine(), "Duplicate parameter name '%s'", + P.Name.c_str()); return std::nullopt; } } @@ -133,12 +129,12 @@ std::optional<std::vector<ParamDecl>> Parser::ParsePrototypeArgs(bool AllowByRef if (CurTok == ')') break; if (CurTok != ',') { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected ',' or ')'\n"); + cps::sourceError(Lex.getLine(), "Expected ',' or ')'"); return std::nullopt; } getNextToken(); if (CurTok == ')') { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected another parameter after ',' at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected another parameter after ','"); return std::nullopt; } } @@ -150,13 +146,13 @@ std::string Parser::ParseOperatorName(int &Op) { getNextToken(); // OPERATOR Op = CurTok; if (operatorSpelling(Op).empty()) { - sourceDiagnostic(Lex.getLine(), "error: Expected a supported operator after OPERATOR at line %d\n", Lex.getLine()); + sourceError(Lex.getLine(), "Expected a supported operator after OPERATOR"); getNextToken(); return {}; } getNextToken(); if (CurTok != '(') { - sourceDiagnostic(Lex.getLine(), "error: Expected '(' after operator name at line %d\n", Lex.getLine()); + sourceError(Lex.getLine(), "Expected '(' after operator name"); return {}; } return operatorName(Op); @@ -166,15 +162,15 @@ std::unique_ptr<FunctionDefAST> Parser::ParseFunction(const std::string &OwnerCl int Line = Lex.getLine(); getNextToken(); if (CurTok == tok_delete || (CurTok == tok_identifier && sameIdentifier(Lex.IdentifierStr, "DELETE"))) { - cps::sourceDiagnostic(Lex.getLine(), "error: destructor DELETE must be a PROCEDURE at line %d\n", Line); + cps::sourceError(Line, "destructor DELETE must be a PROCEDURE"); return nullptr; } if (CurTok == tok_new || (CurTok == tok_identifier && sameIdentifier(Lex.IdentifierStr, "NEW"))) { - cps::sourceDiagnostic(Lex.getLine(), "error: constructor NEW must be a PROCEDURE at line %d\n", Line); + cps::sourceError(Line, "constructor NEW must be a PROCEDURE"); return nullptr; } if (CurTok != tok_identifier && CurTok != tok_operator) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected function name\n"); + cps::sourceError(Lex.getLine(), "Expected function name"); return nullptr; } @@ -184,7 +180,7 @@ std::unique_ptr<FunctionDefAST> Parser::ParseFunction(const std::string &OwnerCl Name = ParseOperatorName(Operator); if (Name.empty()) return nullptr; if (!IsOverload) { - sourceDiagnostic(Line, "error: An operator function must be declared OVERLOAD at line %d\n", Line); + sourceError(Line, "An operator function must be declared OVERLOAD"); return nullptr; } } else { @@ -199,13 +195,12 @@ std::unique_ptr<FunctionDefAST> Parser::ParseFunction(const std::string &OwnerCl if (CurTok == tok_returns) { getNextToken(); if (CurTok == tok_array) { - cps::sourceDiagnostic(Lex.getLine(), "error: A FUNCTION cannot RETURN an array; use a BYREF PROCEDURE parameter instead at line %d\n", - Lex.getLine()); + cps::sourceError(Lex.getLine(), "A FUNCTION cannot RETURN an array; use a BYREF PROCEDURE parameter instead"); return nullptr; } RetType = ParseTypeName(true); if (RetType.empty()) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected return type for function '%s'\n", Name.c_str()); + cps::sourceError(Lex.getLine(), "Expected return type for function '%s'", Name.c_str()); return nullptr; } } @@ -220,7 +215,7 @@ std::unique_ptr<FunctionDefAST> Parser::ParseFunction(const std::string &OwnerCl PackNames = std::move(SavedPacks); if (CurTok != tok_endfunction) { - cps::sourceDiagnostic(Lex.getLine(), "error: expected ENDFUNCTION\n"); + cps::sourceError(Lex.getLine(), "expected ENDFUNCTION"); return nullptr; } getNextToken(); @@ -234,7 +229,7 @@ std::unique_ptr<FunctionDefAST> Parser::ParseProcedure(const std::string &OwnerC int Line = Lex.getLine(); getNextToken(); if (CurTok != tok_identifier && CurTok != tok_new && CurTok != tok_delete && CurTok != tok_operator) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected procedure name\n"); + cps::sourceError(Lex.getLine(), "Expected procedure name"); return nullptr; } @@ -245,17 +240,17 @@ std::unique_ptr<FunctionDefAST> Parser::ParseProcedure(const std::string &OwnerC OperatorName = ParseOperatorName(Operator); if (OperatorName.empty()) return nullptr; if (Operator != tok_assign || OwnerClass.empty() || !IsOverload) { - sourceDiagnostic(Line, "error: Assignment operator must be an OVERLOAD member PROCEDURE at line %d\n", Line); + sourceError(Line, "Assignment operator must be an OVERLOAD member PROCEDURE"); return nullptr; } } std::string Name = IsOperator ? OperatorName : CurTok == tok_new ? "NEW" : CurTok == tok_delete ? "DELETE" : Lex.IdentifierStr; if (OwnerClass.empty() && sameIdentifier(Name, "DELETE")) { - cps::sourceDiagnostic(Lex.getLine(), "error: destructor DELETE is only allowed in a CLASS at line %d\n", Line); + cps::sourceError(Line, "destructor DELETE is only allowed in a CLASS"); return nullptr; } if (OwnerClass.empty() && sameIdentifier(Name, "NEW")) { - cps::sourceDiagnostic(Lex.getLine(), "error: constructor NEW is only allowed in a CLASS at line %d\n", Line); + cps::sourceError(Line, "constructor NEW is only allowed in a CLASS"); return nullptr; } if (!IsOperator) getNextToken(); @@ -263,7 +258,7 @@ std::unique_ptr<FunctionDefAST> Parser::ParseProcedure(const std::string &OwnerC auto Args = ParsePrototypeArgs(/*AllowByRef=*/true); if (!Args) return nullptr; if (sameIdentifier(Name, "DELETE") && !Args->empty()) { - cps::sourceDiagnostic(Lex.getLine(), "error: destructor DELETE must have no parameters at line %d\n", Line); + cps::sourceError(Line, "destructor DELETE must have no parameters"); return nullptr; } auto Proto = std::make_unique<PrototypeAST>(Name, std::move(*Args), "VOID", false, OwnerClass, IsPublic, IsOverload); @@ -276,7 +271,7 @@ std::unique_ptr<FunctionDefAST> Parser::ParseProcedure(const std::string &OwnerC PackNames = std::move(SavedPacks); if (CurTok != tok_endprocedure) { - cps::sourceDiagnostic(Lex.getLine(), "error: expected ENDPROCEDURE\n"); + cps::sourceError(Lex.getLine(), "expected ENDPROCEDURE"); return nullptr; } getNextToken(); @@ -293,19 +288,18 @@ std::unique_ptr<StmtAST> Parser::ParseExternDecl() { int Line = Lex.getLine(); getNextToken(); if (CurTok != tok_string_literal || Lex.StringVal != "C") { - cps::sourceDiagnostic(Lex.getLine(), "error: EXTERN must be followed by \"C\" at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "EXTERN must be followed by \"C\""); return nullptr; } getNextToken(); if (CurTok != tok_extern_function && CurTok != tok_extern_procedure) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected EXTERN_FUNCTION or EXTERN_PROCEDURE after EXTERN \"C\" at line %d\n", - Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected EXTERN_FUNCTION or EXTERN_PROCEDURE after EXTERN \"C\""); return nullptr; } bool IsFunction = CurTok == tok_extern_function; getNextToken(); if (CurTok != tok_identifier) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected C function name at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected C function name"); return nullptr; } std::string Name = Lex.IdentifierStr; @@ -314,8 +308,8 @@ std::unique_ptr<StmtAST> Parser::ParseExternDecl() { std::vector<ParamDecl> Params; bool IsVariadic = false; if (CurTok != '(') { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected '(' after C function name '%s' at line %d\n", - Name.c_str(), Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected '(' after C function name '%s'", + Name.c_str()); return nullptr; } getNextToken(); @@ -324,14 +318,13 @@ std::unique_ptr<StmtAST> Parser::ParseExternDecl() { IsVariadic = true; getNextToken(); if (CurTok != ')') { - cps::sourceDiagnostic(Lex.getLine(), "error: '...' must be the last parameter at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "'...' must be the last parameter"); return nullptr; } break; } if (CurTok == tok_byref || CurTok == tok_byval) { - cps::sourceDiagnostic(Lex.getLine(), "error: EXTERN parameters cannot be BYREF or BYVAL; use a C pointer type at line %d\n", - Lex.getLine()); + cps::sourceError(Lex.getLine(), "EXTERN parameters cannot be BYREF or BYVAL; use a C pointer type"); return nullptr; } ParamDecl P; @@ -342,12 +335,12 @@ std::unique_ptr<StmtAST> Parser::ParseExternDecl() { Params.push_back(std::move(P)); if (CurTok == ')') break; if (CurTok != ',') { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected ',' or ')' at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected ',' or ')'"); return nullptr; } getNextToken(); if (CurTok == ')') { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected another parameter after ',' at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected another parameter after ','"); return nullptr; } } @@ -356,15 +349,15 @@ std::unique_ptr<StmtAST> Parser::ParseExternDecl() { std::string RetType = "VOID"; if (CurTok == tok_returns) { if (!IsFunction) { - cps::sourceDiagnostic(Lex.getLine(), "error: EXTERN_PROCEDURE cannot have RETURNS at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "EXTERN_PROCEDURE cannot have RETURNS"); return nullptr; } getNextToken(); RetType = ParseTypeName(false); if (RetType.empty()) return nullptr; } else if (IsFunction) { - cps::sourceDiagnostic(Lex.getLine(), "error: EXTERN_FUNCTION '%s' requires RETURNS at line %d\n", - Name.c_str(), Line); + cps::sourceError(Line, "EXTERN_FUNCTION '%s' requires RETURNS", + Name.c_str()); return nullptr; } @@ -379,7 +372,7 @@ std::unique_ptr<StmtAST> Parser::ParseCallStmt() { int Line = Lex.getLine(); getNextToken(); if (CurTok != tok_identifier && CurTok != tok_operator) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected callee name after CALL\n"); + cps::sourceError(Lex.getLine(), "Expected callee name after CALL"); return nullptr; } @@ -399,7 +392,7 @@ std::unique_ptr<StmtAST> Parser::ParseCallStmt() { if (!Parsed) return nullptr; TemplateArgs = std::move(*Parsed); if (CurTok != '(') { - sourceDiagnostic(Line, "error: Expected '(' after explicit template arguments at line %d\n", Line); + sourceError(Line, "Expected '(' after explicit template arguments"); return nullptr; } } diff --git a/lib/Parser/ParserType.cc b/lib/Parser/ParserType.cc index 21696d0..22cffeb 100644 --- a/lib/Parser/ParserType.cc +++ b/lib/Parser/ParserType.cc @@ -18,7 +18,7 @@ std::unique_ptr<StmtAST> Parser::ParseTemplateDecl() { bool AtTopLevel = BlockDepth == 1 && CurrentTemplate.empty(); getNextToken(); if (CurTok != '<') { - sourceDiagnostic(Line, "error: Expected '<' after TEMPLATE at line %d\n", Line); + sourceError(Line, "Expected '<' after TEMPLATE"); return nullptr; } getNextToken(); @@ -28,19 +28,19 @@ std::unique_ptr<StmtAST> Parser::ParseTemplateDecl() { bool SeenPack = false; while (true) { if (CurTok != tok_identifier) { - sourceDiagnostic(Lex.getLine(), "error: Expected template parameter name at line %d\n", Lex.getLine()); + sourceError(Lex.getLine(), "Expected template parameter name"); return nullptr; } TemplateParam P{Lex.IdentifierStr, false, Lex.getLine()}; if (!Names.insert(P.Name).second) { - sourceDiagnostic(P.Line, "error: Duplicate template parameter '%s' at line %d\n", P.Name.c_str(), P.Line); + sourceError(P.Line, "Duplicate template parameter '%s'", P.Name.c_str()); Invalid = true; } getNextToken(); if (CurTok == tok_ellipsis) { P.IsPack = true; if (SeenPack) { - sourceDiagnostic(P.Line, "error: A template may have only one parameter pack at line %d\n", P.Line); + sourceError(P.Line, "A template may have only one parameter pack"); Invalid = true; } SeenPack = true; @@ -49,11 +49,11 @@ std::unique_ptr<StmtAST> Parser::ParseTemplateDecl() { Params.push_back(std::move(P)); if (CurTok == '>') break; if (CurTok != ',') { - sourceDiagnostic(Lex.getLine(), "error: Expected ',' or '>' in TEMPLATE at line %d\n", Lex.getLine()); + sourceError(Lex.getLine(), "Expected ',' or '>' in TEMPLATE"); return nullptr; } if (Params.back().IsPack) { - sourceDiagnostic(Params.back().Line, "error: A template parameter pack must be last at line %d\n", Params.back().Line); + sourceError(Params.back().Line, "A template parameter pack must be last"); Invalid = true; } getNextToken(); @@ -70,7 +70,7 @@ std::unique_ptr<StmtAST> Parser::ParseTemplateDecl() { if (CurTok == tok_function || CurTok == tok_procedure) { bool Operator = Lex.peekToken() == tok_operator; if (Operator) { - sourceDiagnostic(Line, "error: Operator templates are not supported at line %d\n", Line); + sourceError(Line, "Operator templates are not supported"); Invalid = true; int End = CurTok == tok_function ? tok_endfunction : tok_endprocedure; do { getNextToken(); } while (CurTok != End && CurTok != tok_eof); @@ -89,17 +89,17 @@ std::unique_ptr<StmtAST> Parser::ParseTemplateDecl() { std::unique_ptr<ClassTypeDeclAST>(static_cast<ClassTypeDeclAST *>(Class.release()))); } } else if (CurTok == tok_type) { - sourceDiagnostic(Line, "error: TEMPLATE cannot prefix TYPE; use CLASS at line %d\n", Line); + sourceError(Line, "TEMPLATE cannot prefix TYPE; use CLASS"); ParseTypeDecl(); Invalid = true; } else { - sourceDiagnostic(Line, "error: TEMPLATE must be followed by FUNCTION, PROCEDURE or CLASS at line %d\n", Line); + sourceError(Line, "TEMPLATE must be followed by FUNCTION, PROCEDURE or CLASS"); Invalid = true; } CurrentTemplate = std::move(SavedTemplate); TypeNames = std::move(SavedTypes); if (!AtTopLevel) { - sourceDiagnostic(Line, "error: TEMPLATE declarations are only allowed at top level at line %d\n", Line); + sourceError(Line, "TEMPLATE declarations are only allowed at top level"); Invalid = true; } if (Invalid || !Decl) return nullptr; @@ -117,7 +117,7 @@ std::optional<std::vector<std::string>> Parser::ParseTemplateArgs() { if (Type.empty()) return std::nullopt; if (CurTok == tok_ellipsis) { if (!isTemplatePack(Type)) { - sourceDiagnostic(Line, "error: Only the current template parameter pack may use '...' in a type argument at line %d\n", Line); + sourceError(Line, "Only the current template parameter pack may use '...' in a type argument"); return std::nullopt; } Type += "..."; @@ -126,7 +126,7 @@ std::optional<std::vector<std::string>> Parser::ParseTemplateArgs() { Args.push_back(std::move(Type)); if (CurTok == '>') break; if (CurTok != ',') { - sourceDiagnostic(Lex.getLine(), "error: Expected ',' or '>' in template arguments at line %d\n", Lex.getLine()); + sourceError(Lex.getLine(), "Expected ',' or '>' in template arguments"); return std::nullopt; } getNextToken(); @@ -153,7 +153,7 @@ std::unique_ptr<StmtAST> Parser::ParseTypeDecl() { getNextToken(); // eat TYPE or CLASS if (CurTok != tok_identifier && !(IsClass && CurTok == tok_string_kw)) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected type name after %s at line %d\n", Keyword, Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected type name after %s", Keyword); if (IsClass) ParseRecordBody("<unnamed>", Line, tok_endclass); return nullptr; } @@ -169,18 +169,18 @@ std::unique_ptr<StmtAST> Parser::ParseTypeDecl() { if (CurTok == tok_c_type) { getNextToken(); if (CurTok != '(') { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected '(' after C_TYPE at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected '(' after C_TYPE"); return nullptr; } getNextToken(); if (CurTok != tok_string_literal) { - cps::sourceDiagnostic(Lex.getLine(), "error: C_TYPE requires a string literal at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "C_TYPE requires a string literal"); return nullptr; } std::string Expression = Lex.StringVal; getNextToken(); if (CurTok != ')') { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected ')' after C_TYPE string at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected ')' after C_TYPE string"); return nullptr; } getNextToken(); @@ -190,16 +190,16 @@ std::unique_ptr<StmtAST> Parser::ParseTypeDecl() { std::vector<std::string> Values; while (true) { if (CurTok != tok_identifier) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected an enum value name in TYPE %s at line %d\n", - Name.c_str(), Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected an enum value name in TYPE %s", + Name.c_str()); return nullptr; } Values.push_back(Lex.IdentifierStr); getNextToken(); if (CurTok == ')') break; if (CurTok != ',') { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected ',' or ')' in TYPE %s at line %d\n", - Name.c_str(), Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected ',' or ')' in TYPE %s", + Name.c_str()); return nullptr; } getNextToken(); @@ -212,12 +212,12 @@ std::unique_ptr<StmtAST> Parser::ParseTypeDecl() { if (Pointee.empty()) return nullptr; Decl = std::make_unique<PointerTypeDeclAST>(Name, Pointee); } else if (CurTok == tok_set) { - cps::sourceDiagnostic(Lex.getLine(), "error: SET OF types are not implemented at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "SET OF types are not implemented"); getNextToken(); return nullptr; } else { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected '(', '^' or C_TYPE after '=' in TYPE %s at line %d\n", - Name.c_str(), Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected '(', '^' or C_TYPE after '=' in TYPE %s", + Name.c_str()); return nullptr; } } else { @@ -231,7 +231,7 @@ std::unique_ptr<StmtAST> Parser::ParseTypeDecl() { } if (!AtTopLevel) { - cps::sourceDiagnostic(Lex.getLine(), "error: %s declarations are only allowed at top level at line %d\n", Keyword, Line); + cps::sourceError(Line, "%s declarations are only allowed at top level", Keyword); return nullptr; } TypeNames.insert(Name); @@ -272,7 +272,7 @@ std::optional<std::vector<RecordFieldDecl>> Parser::ParseRecordBody( bool IsOverload = CurTok == tok_overload; if (IsOverload) getNextToken(); if (CurTok != tok_function && CurTok != tok_procedure) { - cps::sourceDiagnostic(Lex.getLine(), "error: OVERLOAD must be followed by FUNCTION or PROCEDURE at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "OVERLOAD must be followed by FUNCTION or PROCEDURE"); HadFieldError = true; continue; } @@ -284,9 +284,9 @@ std::optional<std::vector<RecordFieldDecl>> Parser::ParseRecordBody( } } else if (ParseRecordField(Fields, IsPublic)) continue; } else { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected %s or %s in %s %s at line %d\n", + cps::sourceError(Lex.getLine(), "Expected %s or %s in %s %s", IsClass ? "field, method, PUBLIC or PRIVATE" : "DECLARE", EndKeyword, - Keyword, Name.c_str(), Lex.getLine()); + Keyword, Name.c_str()); } HadFieldError = true; // Consume invalid bodies rather than replaying their contents as @@ -305,14 +305,14 @@ std::optional<std::vector<RecordFieldDecl>> Parser::ParseRecordBody( } } if (CurTok != EndToken) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected %s in %s %s at line %d\n", - EndKeyword, Keyword, Name.c_str(), Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected %s in %s %s", + EndKeyword, Keyword, Name.c_str()); return std::nullopt; } getNextToken(); // eat body terminator if (Fields.empty() && (!Methods || Methods->empty()) && !HadFieldError) { - cps::sourceDiagnostic(Lex.getLine(), "error: %s %s has no %s at line %d\n", Keyword, Name.c_str(), - IsClass ? "members" : "fields", Line); + cps::sourceError(Line, "%s %s has no %s", Keyword, Name.c_str(), + IsClass ? "members" : "fields"); return std::nullopt; } if (HadFieldError) return std::nullopt; @@ -326,29 +326,28 @@ bool Parser::ParseRecordField(std::vector<RecordFieldDecl> &Out, bool IsPublic) : CurTok == tok_public ? "PUBLIC" : "PRIVATE"; if (CurTok != tok_identifier) getNextToken(); // optional class access keyword if (CurTok != tok_identifier) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected field name after %s at line %d\n", Introducer, Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected field name after %s", Introducer); return false; } std::string FieldName = Lex.IdentifierStr; getNextToken(); if (CurTok != tok_colon) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected ':' after field name %s at line %d\n", - FieldName.c_str(), Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected ':' after field name %s", + FieldName.c_str()); return false; } getNextToken(); if (CurTok == tok_array) { - cps::sourceDiagnostic(Lex.getLine(), "error: Array fields inside records are not implemented at line %d\n", - Lex.getLine()); + cps::sourceError(Lex.getLine(), "Array fields inside records are not implemented"); return false; } std::string TypeName = ParseTypeName(false); if (TypeName.empty()) return false; if (CurTok == tok_ellipsis || isTemplatePack(TypeName)) { - sourceDiagnostic(Line, "error: Pack fields are not supported at line %d\n", Line); + sourceError(Line, "Pack fields are not supported"); if (CurTok == tok_ellipsis) getNextToken(); return false; } @@ -388,7 +387,7 @@ std::string Parser::ParseTypeName(bool AllowVoid) { if (CurTok == tok_identifier) { std::string TypeName = Lex.IdentifierStr; if (!AllowVoid && sameIdentifier(TypeName, "VOID")) { - cps::sourceDiagnostic(Lex.getLine(), "error: VOID is not allowed here\n"); + cps::sourceError(Lex.getLine(), "VOID is not allowed here"); return ""; } getNextToken(); @@ -405,7 +404,7 @@ std::string Parser::ParseTypeName(bool AllowVoid) { return TypeName; } - cps::sourceDiagnostic(Lex.getLine(), "error: Unknown type name\n"); + cps::sourceError(Lex.getLine(), "Unknown type name"); return ""; } @@ -413,14 +412,14 @@ std::string Parser::ParseTypeName(bool AllowVoid) { std::unique_ptr<StmtAST> Parser::ParseDeclare() { getNextToken(); if (CurTok != tok_identifier) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected identifier after DECLARE at line %d\n", Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected identifier after DECLARE"); return nullptr; } std::string Name = Lex.IdentifierStr; getNextToken(); if (CurTok != tok_colon) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected ':' after variable name '%s' at line %d\n", Name.c_str(), Lex.getLine()); + cps::sourceError(Lex.getLine(), "Expected ':' after variable name '%s'", Name.c_str()); return nullptr; } getNextToken(); @@ -428,7 +427,7 @@ std::unique_ptr<StmtAST> Parser::ParseDeclare() { if (CurTok == tok_array) { getNextToken(); if (CurTok != '[') { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected '[' after ARRAY\n"); + cps::sourceError(Lex.getLine(), "Expected '[' after ARRAY"); return nullptr; } getNextToken(); @@ -440,7 +439,7 @@ std::unique_ptr<StmtAST> Parser::ParseDeclare() { if (!Lower) return nullptr; if (CurTok != tok_colon) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected ':' in array range (e.g. 1:10)\n"); + cps::sourceError(Lex.getLine(), "Expected ':' in array range (e.g. 1:10)"); return nullptr; } getNextToken(); @@ -455,13 +454,13 @@ std::unique_ptr<StmtAST> Parser::ParseDeclare() { getNextToken(); continue; } - cps::sourceDiagnostic(Lex.getLine(), "error: Expected ',' or ']' in array dims\n"); + cps::sourceError(Lex.getLine(), "Expected ',' or ']' in array dims"); return nullptr; } getNextToken(); if (CurTok != tok_of) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected OF after array dims\n"); + cps::sourceError(Lex.getLine(), "Expected OF after array dims"); return nullptr; } getNextToken(); @@ -494,13 +493,13 @@ std::unique_ptr<StmtAST> Parser::ParseConstant() { int Line = Lex.getLine(); getNextToken(); if (CurTok != tok_identifier) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected identifier after CONSTANT at line %d\n", Line); + cps::sourceError(Line, "Expected identifier after CONSTANT"); return nullptr; } std::string Name = Lex.IdentifierStr; getNextToken(); if (CurTok != tok_eq) { - cps::sourceDiagnostic(Lex.getLine(), "error: Expected '=' in CONSTANT declaration at line %d\n", Line); + cps::sourceError(Line, "Expected '=' in CONSTANT declaration"); return nullptr; } getNextToken(); @@ -510,7 +509,7 @@ std::unique_ptr<StmtAST> Parser::ParseConstant() { bool Literal = Numeric || CurTok == tok_true || CurTok == tok_false || CurTok == tok_string_literal || CurTok == tok_c_string_literal || CurTok == tok_char_literal; if (!Literal || (Negative && !Numeric)) { - cps::sourceDiagnostic(Lex.getLine(), "error: CONSTANT initializer must be a literal at line %d\n", Line); + cps::sourceError(Line, "CONSTANT initializer must be a literal"); return nullptr; } std::unique_ptr<ExprAST> Value; @@ -526,7 +525,7 @@ std::unique_ptr<StmtAST> Parser::ParseConstant() { if (Negative) Value = std::make_unique<UnaryExprAST>('-', std::move(Value)); } if (GetTokPrecedence() >= 0) { - cps::sourceDiagnostic(Lex.getLine(), "error: CONSTANT initializer must be a literal, not an expression, at line %d\n", Line); + cps::sourceError(Line, "CONSTANT initializer must be a literal, not an expression"); return nullptr; } return std::make_unique<ConstantStmtAST>(std::move(Name), std::move(Value)); |
