aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-17 10:30:02 +0000
committer_ov4 <ov4@ov4.org>2026-10-17 10:30:02 +0000
commitf5246db6d045ffb86d6717e1b1c37f03bcb2b75b (patch)
tree468f4fba2e7ef75f29f90fd64af7d4e1fe05f50f
parent066a378ca09ccc5d8074a942cf4bf1b9d4f40729 (diff)
feat(parser): parse OVERLOAD prefix on FUNCTION and PROCEDURE
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
-rw-r--r--include/cps/FunctionAST.h6
-rw-r--r--include/cps/Lexer.h1
-rw-r--r--include/cps/Parser.h4
-rw-r--r--lib/Lexer/Lexer.cc1
-rw-r--r--lib/Parser/Parser.cc10
-rw-r--r--lib/Parser/ParserFunction.cc8
-rw-r--r--lib/Parser/ParserType.cc17
-rw-r--r--tests/iii/overload-syntax-error/case.json1
-rw-r--r--tests/iii/overload-syntax-error/program.cps1
9 files changed, 35 insertions, 14 deletions
diff --git a/include/cps/FunctionAST.h b/include/cps/FunctionAST.h
index 4dfe908..9995a4c 100644
--- a/include/cps/FunctionAST.h
+++ b/include/cps/FunctionAST.h
@@ -30,6 +30,7 @@ class PrototypeAST {
std::vector<ParamDecl> Params;
std::string ReturnType;
bool IsExternal;
+ bool IsOverload;
std::string OwnerClass;
bool IsPublic;
@@ -37,13 +38,14 @@ public:
PrototypeAST(const std::string &Name,
std::vector<ParamDecl> Params,
const std::string &ReturnType,
- bool IsExternal = false, std::string OwnerClass = {}, bool IsPublic = true)
- : Name(Name), Params(std::move(Params)), ReturnType(ReturnType), IsExternal(IsExternal),
+ bool IsExternal = false, std::string OwnerClass = {}, bool IsPublic = true, bool IsOverload = false)
+ : Name(Name), Params(std::move(Params)), ReturnType(ReturnType), IsExternal(IsExternal), IsOverload(IsOverload),
OwnerClass(std::move(OwnerClass)), IsPublic(IsPublic) {}
const std::string &getName() const { return Name; }
const std::vector<ParamDecl> &getParams() const { return Params; }
const std::string &getReturnType() const { return ReturnType; }
+ bool isOverload() const { return IsOverload; }
bool isExternal() const { return IsExternal; }
const std::string &getOwnerClass() const { return OwnerClass; }
bool isPublic() const { return IsPublic; }
diff --git a/include/cps/Lexer.h b/include/cps/Lexer.h
index 957ca48..40f168e 100644
--- a/include/cps/Lexer.h
+++ b/include/cps/Lexer.h
@@ -67,6 +67,7 @@ enum Token {
tok_colon = -300, // :
+ tok_overload = -399,
tok_function = -400,
tok_endfunction = -401,
tok_return = -402,
diff --git a/include/cps/Parser.h b/include/cps/Parser.h
index 9a53e95..d9e8358 100644
--- a/include/cps/Parser.h
+++ b/include/cps/Parser.h
@@ -73,8 +73,8 @@ class Parser {
std::vector<std::unique_ptr<FunctionDefAST>> *Methods = nullptr);
bool ParseRecordField(std::vector<RecordFieldDecl> &Out, bool IsPublic);
- std::unique_ptr<FunctionDefAST> ParseFunction(const std::string &OwnerClass = {}, bool IsPublic = true);
- std::unique_ptr<FunctionDefAST> ParseProcedure(const std::string &OwnerClass = {}, bool IsPublic = true);
+ std::unique_ptr<FunctionDefAST> ParseFunction(const std::string &OwnerClass = {}, bool IsPublic = true, bool IsOverload = false);
+ std::unique_ptr<FunctionDefAST> ParseProcedure(const std::string &OwnerClass = {}, bool IsPublic = true, bool IsOverload = false);
std::unique_ptr<StmtAST> ParseCallStmt();
std::unique_ptr<StmtAST> ParseReturnStmt();
std::optional<std::vector<ParamDecl>> ParsePrototypeArgs(bool AllowByRef);
diff --git a/lib/Lexer/Lexer.cc b/lib/Lexer/Lexer.cc
index 44d40e5..9956cd9 100644
--- a/lib/Lexer/Lexer.cc
+++ b/lib/Lexer/Lexer.cc
@@ -130,6 +130,7 @@ int Lexer::readToken() {
if (IdentifierStr == "OR") return tok_or;
if (IdentifierStr == "NOT") return tok_not;
+ if (IdentifierStr == "OVERLOAD") return tok_overload;
if (IdentifierStr == "FUNCTION") return tok_function;
if (IdentifierStr == "ENDFUNCTION") return tok_endfunction;
if (IdentifierStr == "PROCEDURE") return tok_procedure;
diff --git a/lib/Parser/Parser.cc b/lib/Parser/Parser.cc
index d4dd18e..f7817ec 100644
--- a/lib/Parser/Parser.cc
+++ b/lib/Parser/Parser.cc
@@ -50,7 +50,7 @@ void Parser::syncToStatementStart() {
case tok_delete: case tok_constant: case tok_declare: case tok_identifier: case tok_input: case tok_output:
case tok_case: case tok_endcase: case tok_otherwise:
case tok_if: case tok_while: case tok_repeat: case tok_for:
- case tok_function: case tok_procedure: case tok_call: case tok_return:
+ case tok_overload: case tok_function: case tok_procedure: case tok_call: case tok_return:
case tok_else: case tok_endif: case tok_endwhile: case tok_until:
case tok_next: case tok_endfunction: case tok_endprocedure:
case tok_openfile: case tok_readfile: case tok_writefile: case tok_closefile:
@@ -212,6 +212,14 @@ std::unique_ptr<StmtAST> Parser::ParseStatementImpl() {
else if (CurTok == tok_for) {
return ParseForStmt();
}
+ else if (CurTok == tok_overload) {
+ int Line = Lex.getLine();
+ 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);
+ return nullptr;
+ }
else if (CurTok == tok_function) {
return ParseFunction();
}
diff --git a/lib/Parser/ParserFunction.cc b/lib/Parser/ParserFunction.cc
index fa46dcf..3df324c 100644
--- a/lib/Parser/ParserFunction.cc
+++ b/lib/Parser/ParserFunction.cc
@@ -130,7 +130,7 @@ std::optional<std::vector<ParamDecl>> Parser::ParsePrototypeArgs(bool AllowByRef
return Params;
}
-std::unique_ptr<FunctionDefAST> Parser::ParseFunction(const std::string &OwnerClass, bool IsPublic) {
+std::unique_ptr<FunctionDefAST> Parser::ParseFunction(const std::string &OwnerClass, bool IsPublic, bool IsOverload) {
int Line = Lex.getLine();
getNextToken();
if (CurTok == tok_delete || (CurTok == tok_identifier && sameIdentifier(Lex.IdentifierStr, "DELETE"))) {
@@ -167,7 +167,7 @@ std::unique_ptr<FunctionDefAST> Parser::ParseFunction(const std::string &OwnerCl
}
}
- auto Proto = std::make_unique<PrototypeAST>(Name, std::move(*Args), RetType, false, OwnerClass, IsPublic);
+ auto Proto = std::make_unique<PrototypeAST>(Name, std::move(*Args), RetType, false, OwnerClass, IsPublic, IsOverload);
std::vector<std::unique_ptr<StmtAST>> Body = ParseBlock({tok_endfunction});
@@ -182,7 +182,7 @@ std::unique_ptr<FunctionDefAST> Parser::ParseFunction(const std::string &OwnerCl
return Def;
}
-std::unique_ptr<FunctionDefAST> Parser::ParseProcedure(const std::string &OwnerClass, bool IsPublic) {
+std::unique_ptr<FunctionDefAST> Parser::ParseProcedure(const std::string &OwnerClass, bool IsPublic, bool IsOverload) {
int Line = Lex.getLine();
getNextToken();
if (CurTok != tok_identifier && CurTok != tok_new && CurTok != tok_delete) {
@@ -207,7 +207,7 @@ std::unique_ptr<FunctionDefAST> Parser::ParseProcedure(const std::string &OwnerC
cps::sourceDiagnostic(Lex.getLine(), "error: destructor DELETE must have no parameters at line %d\n", Line);
return nullptr;
}
- auto Proto = std::make_unique<PrototypeAST>(Name, std::move(*Args), "VOID", false, OwnerClass, IsPublic);
+ auto Proto = std::make_unique<PrototypeAST>(Name, std::move(*Args), "VOID", false, OwnerClass, IsPublic, IsOverload);
std::vector<std::unique_ptr<StmtAST>> Body = ParseBlock({tok_endprocedure});
diff --git a/lib/Parser/ParserType.cc b/lib/Parser/ParserType.cc
index b67558f..d281293 100644
--- a/lib/Parser/ParserType.cc
+++ b/lib/Parser/ParserType.cc
@@ -116,7 +116,7 @@ std::optional<std::vector<RecordFieldDecl>> Parser::ParseRecordBody(
const char *EndKeyword = IsClass ? "ENDCLASS" : "ENDTYPE";
auto AtField = [&] {
return IsClass ? (CurTok == tok_public || CurTok == tok_private || CurTok == tok_identifier ||
- CurTok == tok_function || CurTok == tok_procedure)
+ CurTok == tok_overload || CurTok == tok_function || CurTok == tok_procedure)
: CurTok == tok_declare;
};
std::vector<RecordFieldDecl> Fields;
@@ -126,11 +126,18 @@ std::optional<std::vector<RecordFieldDecl>> Parser::ParseRecordBody(
// Class fields default to public, like record fields.
bool IsPublic = CurTok != tok_private;
if (IsClass && (CurTok == tok_public || CurTok == tok_private) &&
- (Lex.peekToken() == tok_function || Lex.peekToken() == tok_procedure))
+ (Lex.peekToken() == tok_overload || Lex.peekToken() == tok_function || Lex.peekToken() == tok_procedure))
getNextToken();
- if (IsClass && (CurTok == tok_function || CurTok == tok_procedure)) {
- auto Method = CurTok == tok_function ? ParseFunction(Name, IsPublic)
- : ParseProcedure(Name, IsPublic);
+ if (IsClass && (CurTok == tok_overload || CurTok == tok_function || CurTok == tok_procedure)) {
+ 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());
+ HadFieldError = true;
+ continue;
+ }
+ auto Method = CurTok == tok_function ? ParseFunction(Name, IsPublic, IsOverload)
+ : ParseProcedure(Name, IsPublic, IsOverload);
if (Method && Methods) {
Methods->push_back(std::move(Method));
continue;
diff --git a/tests/iii/overload-syntax-error/case.json b/tests/iii/overload-syntax-error/case.json
new file mode 100644
index 0000000..3fcb463
--- /dev/null
+++ b/tests/iii/overload-syntax-error/case.json
@@ -0,0 +1 @@
+{"errors": [{"reason": "OVERLOAD must be followed by FUNCTION or PROCEDURE", "line": 1}]}
diff --git a/tests/iii/overload-syntax-error/program.cps b/tests/iii/overload-syntax-error/program.cps
new file mode 100644
index 0000000..923163b
--- /dev/null
+++ b/tests/iii/overload-syntax-error/program.cps
@@ -0,0 +1 @@
+OVERLOAD DECLARE x : INTEGER