From c89477d615fb0ce4d89786ef848ffe6aca1da088 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Sat, 17 Oct 2026 06:50:29 +0000 Subject: feat(classes): support explicit NEW constructor method calls Co-Authored-By: Claude Opus 5.5 --- lib/CodeGen/Designator.cc | 4 +--- lib/Lexer/Lexer.cc | 1 + lib/Parser/ParserExpression.cc | 4 ++-- lib/Parser/ParserFunction.cc | 12 ++++++++++-- 4 files changed, 14 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/CodeGen/Designator.cc b/lib/CodeGen/Designator.cc index adf08f1..13eb25f 100644 --- a/lib/CodeGen/Designator.cc +++ b/lib/CodeGen/Designator.cc @@ -56,9 +56,7 @@ void CodeGen::runTypePrePass(const std::vector> &Statem for (const auto &Method : Class->getMethods()) { SaveAndRestore Location(DiagnosticLine, Method->getLine()); const std::string &Name = Method->getProto()->getName(); - if (sameIdentifier(Name, "NEW")) { - reportError("NEW constructors are not implemented"); - } else if (sameIdentifier(Name, "this")) { + if (sameIdentifier(Name, "this")) { reportError("A method cannot be named this"); } else if (!Names.insert(Name).second) { reportError("Duplicate member %s in class %s", Name.c_str(), Class->getName().c_str()); diff --git a/lib/Lexer/Lexer.cc b/lib/Lexer/Lexer.cc index 9203db1..8f86ced 100644 --- a/lib/Lexer/Lexer.cc +++ b/lib/Lexer/Lexer.cc @@ -150,6 +150,7 @@ int Lexer::readToken() { if (IdentifierStr == "ENDTYPE") return tok_endtype; if (IdentifierStr == "SET") return tok_set; if (IdentifierStr == "DEFINE") return tok_define; + if (IdentifierStr == "NEW") return tok_new; if (IdentifierStr == "CLASS") return tok_class; if (IdentifierStr == "ENDCLASS") return tok_endclass; if (IdentifierStr == "PUBLIC") return tok_public; diff --git a/lib/Parser/ParserExpression.cc b/lib/Parser/ParserExpression.cc index e9b0dcc..f4e074e 100644 --- a/lib/Parser/ParserExpression.cc +++ b/lib/Parser/ParserExpression.cc @@ -109,13 +109,13 @@ bool Parser::ParseDesignatorSuffix(std::vector &Out) { Out.push_back(std::move(A)); } else if (CurTok == '.') { getNextToken(); - if (CurTok != tok_identifier) { + if (CurTok != tok_identifier && CurTok != tok_new) { fprintf(stderr, "error: Expected field name after '.' at line %d\n", Lex.getLine()); return false; } DesignatorAccess A; A.Kind = AccessKind::Field; - A.FieldName = Lex.IdentifierStr; + A.FieldName = CurTok == tok_new ? "NEW" : Lex.IdentifierStr; Out.push_back(std::move(A)); getNextToken(); } else if (CurTok == '^') { diff --git a/lib/Parser/ParserFunction.cc b/lib/Parser/ParserFunction.cc index ad187c8..1b8b470 100644 --- a/lib/Parser/ParserFunction.cc +++ b/lib/Parser/ParserFunction.cc @@ -132,6 +132,10 @@ std::optional> Parser::ParsePrototypeArgs(bool AllowByRef std::unique_ptr Parser::ParseFunction(const std::string &OwnerClass, bool IsPublic) { int Line = Lex.getLine(); getNextToken(); + if (CurTok == tok_new || (CurTok == tok_identifier && sameIdentifier(Lex.IdentifierStr, "NEW"))) { + fprintf(stderr, "error: constructor NEW must be a PROCEDURE at line %d\n", Line); + return nullptr; + } if (CurTok != tok_identifier) { fprintf(stderr, "error: Expected function name\n"); return nullptr; @@ -176,12 +180,16 @@ std::unique_ptr Parser::ParseFunction(const std::string &OwnerCl std::unique_ptr Parser::ParseProcedure(const std::string &OwnerClass, bool IsPublic) { int Line = Lex.getLine(); getNextToken(); - if (CurTok != tok_identifier) { + if (CurTok != tok_identifier && CurTok != tok_new) { fprintf(stderr, "error: Expected procedure name\n"); return nullptr; } - std::string Name = Lex.IdentifierStr; + std::string Name = CurTok == tok_new ? "NEW" : Lex.IdentifierStr; + if (OwnerClass.empty() && sameIdentifier(Name, "NEW")) { + fprintf(stderr, "error: constructor NEW is only allowed in a CLASS at line %d\n", Line); + return nullptr; + } getNextToken(); auto Args = ParsePrototypeArgs(/*AllowByRef=*/true); -- cgit v1.3.1-4-g156e