diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-28 13:36:16 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-28 13:36:16 +0000 |
| commit | b28384fed1ce638e8b00b72dba974e9fd7e55eb4 (patch) | |
| tree | b0b342b148c1d5b33197f7a59d0a7a7edb92af1c /lib | |
| parent | caa88a9b36d9e1dfae40ecb31aee05bc2891fa17 (diff) | |
feat(overload): support default return types
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/CodeGen/CallGen.cc | 10 | ||||
| -rw-r--r-- | lib/CodeGen/FunctionGen.cc | 27 | ||||
| -rw-r--r-- | lib/CodeGen/OperatorGen.cc | 8 | ||||
| -rw-r--r-- | lib/CodeGen/TemplateClone.cc | 1 | ||||
| -rw-r--r-- | lib/Lexer/Lexer.cc | 1 | ||||
| -rw-r--r-- | lib/Parser/ParserFunction.cc | 13 |
6 files changed, 58 insertions, 2 deletions
diff --git a/lib/CodeGen/CallGen.cc b/lib/CodeGen/CallGen.cc index f3a6a9d..0741763 100644 --- a/lib/CodeGen/CallGen.cc +++ b/lib/CodeGen/CallGen.cc @@ -204,7 +204,7 @@ const FuncSig *CodeGen::resolveCall(const std::string &Name, } // A context with a type prefers candidates that return it; a strict // context requires one. Without a context (or after a cast's preference - // finds nothing) selection stays parameter-only. + // finds nothing) a default may resolve return-only ambiguity. const bool PreferResult = Context && Context->Type; auto ReturnsWanted = [&](const FuncSig *Sig) { const TypeInfo *Ret = resolveType(Sig->ReturnTypeName); @@ -217,6 +217,7 @@ const FuncSig *CodeGen::resolveCall(const std::string &Name, // FilterReturn keeps only candidates whose result is the wanted type. auto Scan = [&](bool Lenient, bool FilterReturn) -> const FuncSig * { const FuncSig *First = nullptr; + std::vector<const FuncSig *> Matches; Count = 0; for (const FuncSig *Sig : Overloads) { if (HasExplicit) break; @@ -235,8 +236,15 @@ const FuncSig *CodeGen::resolveCall(const std::string &Name, ParamMatched = true; if (FilterReturn && !ReturnsWanted(Sig)) continue; ++Count; + Matches.push_back(Sig); if (!First) First = Sig; } + if (!FilterReturn && Count > 1) { + if (const FuncSig *Default = FunctionGen::selectDefaultReturn(Matches)) { + Count = 1; + return Default; + } + } return First; }; auto ReportAmbiguous = [&](bool FilterReturn) { diff --git a/lib/CodeGen/FunctionGen.cc b/lib/CodeGen/FunctionGen.cc index c162b46..a0c520d 100644 --- a/lib/CodeGen/FunctionGen.cc +++ b/lib/CodeGen/FunctionGen.cc @@ -113,9 +113,30 @@ const FuncSig *FunctionGen::getSignatureByLink(const std::string &Name) const { return &Signatures.at(It->second.first)[It->second.second]; } +// Defaults resolve only return-type ambiguity within one parameter signature. +const FuncSig *FunctionGen::selectDefaultReturn(const std::vector<const FuncSig *> &Candidates) { + const FuncSig *Selected = nullptr; + for (const FuncSig *Sig : Candidates) { + if (!sameIdentifier(Sig->Name, Candidates.front()->Name) || + !sameIdentifier(Sig->ParamKey, Candidates.front()->ParamKey)) return nullptr; + if (Sig->IsDefaultReturn) { + if (Selected) return nullptr; + Selected = Sig; + } + } + return Selected; +} + // Copy-constructor, operator, MAIN and name-collision rules for a // FUNCTION/PROCEDURE prototype; reports the first violation. bool FunctionGen::validatePrototype(PrototypeAST *Proto) { + if (Proto->isDefaultReturn()) { + const TypeInfo *Return = Types.resolve(Proto->getReturnType()); + if (!Proto->isOverload() || (Return && Return->isVoid())) { + reportError("DEFAULT requires a non-VOID OVERLOAD FUNCTION"); + return false; + } + } if (!Proto->getOwnerClass().empty() && sameIdentifier(Proto->getName(), "NEW") && Proto->getParams().size() == 1) { const auto &P = Proto->getParams()[0]; @@ -192,6 +213,7 @@ Function *FunctionGen::emitPrototype(PrototypeAST *Proto) { Sig.OwnerUnit = CurrentUnit; Sig.Name = Proto->getLinkName(); Sig.IsOverload = Proto->isOverload(); + Sig.IsDefaultReturn = Proto->isDefaultReturn(); Sig.Prototype = Proto; Sig.ReturnTypeName = Proto->getReturnType(); @@ -247,6 +269,11 @@ Function *FunctionGen::emitPrototype(PrototypeAST *Proto) { return nullptr; } if (sameIdentifier(Existing.ParamKey, Sig.ParamKey) && + Existing.IsDefaultReturn && Sig.IsDefaultReturn) { + reportError("Duplicate DEFAULT return for %s(%s)", Sig.Name.c_str(), Sig.ParamKey.c_str()); + return nullptr; + } + if (sameIdentifier(Existing.ParamKey, Sig.ParamKey) && sameIdentifier(Existing.ReturnKey, Sig.ReturnKey)) { if (Existing.OwnerUnit != CurrentUnit) reportError("Duplicate definition %s in %s and %s", Sig.Name.c_str(), diff --git a/lib/CodeGen/OperatorGen.cc b/lib/CodeGen/OperatorGen.cc index 560b167..7cfac00 100644 --- a/lib/CodeGen/OperatorGen.cc +++ b/lib/CodeGen/OperatorGen.cc @@ -38,6 +38,7 @@ CodeGen::OperatorResolution CodeGen::resolveOperator( if (Lenient && !CanConvert) break; const FuncSig *Selected = nullptr; int Count = 0; + std::vector<const FuncSig *> Matches; for (const FuncSig *Sig : Candidates) { bool Member = !Sig->Prototype->getOwnerClass().empty(); if (Sig->Prototype->getOperator() != Op || @@ -47,8 +48,15 @@ CodeGen::OperatorResolution CodeGen::resolveOperator( ParamMatched = true; if (FilterReturn && !ReturnsWanted(Sig)) continue; ++Count; + Matches.push_back(Sig); if (!Selected) Selected = Sig; } + if (!FilterReturn && Count > 1) { + if (const FuncSig *Default = FunctionGen::selectDefaultReturn(Matches)) { + Selected = Default; + Count = 1; + } + } if (Selected) { Result.Signature = Selected; Result.Ambiguous = Count > 1; diff --git a/lib/CodeGen/TemplateClone.cc b/lib/CodeGen/TemplateClone.cc index 7374ee8..b0aaf0c 100644 --- a/lib/CodeGen/TemplateClone.cc +++ b/lib/CodeGen/TemplateClone.cc @@ -220,6 +220,7 @@ std::unique_ptr<FunctionDefAST> TemplateClone::function(const FunctionDefAST *So auto CopyProto = std::make_unique<PrototypeAST>(Name, std::move(Params), type(Proto->getReturnType()), Proto->isExternal(), OwnerClass, Proto->isPublic(), Proto->isOverload()); CopyProto->setOperator(Proto->getOperator()); + CopyProto->setDefaultReturn(Proto->isDefaultReturn()); CopyProto->setVariadic(Proto->isVariadic()); auto Copy = located(std::make_unique<FunctionDefAST>(std::move(CopyProto), body(Source->getBody())), Source); PackNames = std::move(SavedNames); diff --git a/lib/Lexer/Lexer.cc b/lib/Lexer/Lexer.cc index 40bfce3..e75cbba 100644 --- a/lib/Lexer/Lexer.cc +++ b/lib/Lexer/Lexer.cc @@ -77,6 +77,7 @@ const std::unordered_map<std::string, int> Keywords = { {"ENDPROCEDURE", tok_endprocedure}, {"RETURN", tok_return}, {"RETURNS", tok_returns}, + {"DEFAULT", tok_default}, {"CALL", tok_call}, {"BYREF", tok_byref}, {"BYVAL", tok_byval}, diff --git a/lib/Parser/ParserFunction.cc b/lib/Parser/ParserFunction.cc index 8f3a117..2f80c42 100644 --- a/lib/Parser/ParserFunction.cc +++ b/lib/Parser/ParserFunction.cc @@ -203,8 +203,13 @@ std::unique_ptr<FunctionDefAST> Parser::ParseFunction(const std::string &OwnerCl if (!Args) return nullptr; std::string RetType = "INTEGER"; + bool IsDefaultReturn = false; if (CurTok == tok_returns) { getNextToken(); + if (CurTok == tok_default) { + IsDefaultReturn = true; + getNextToken(); + } if (CurTok == tok_array) { cps::sourceError(Lex.getLine(), "A FUNCTION cannot RETURN an array; use a BYREF PROCEDURE parameter instead"); return nullptr; @@ -218,8 +223,14 @@ std::unique_ptr<FunctionDefAST> Parser::ParseFunction(const std::string &OwnerCl auto Proto = std::make_unique<PrototypeAST>(Name, std::move(*Args), RetType, false, OwnerClass, IsPublic, IsOverload); Proto->setOperator(Operator); + Proto->setDefaultReturn(IsDefaultReturn); - return ParseFunctionBody(std::move(Proto), tok_endfunction, "expected ENDFUNCTION", Line); + auto Def = ParseFunctionBody(std::move(Proto), tok_endfunction, "expected ENDFUNCTION", Line); + if (IsDefaultReturn && !CurrentTemplate.empty()) { + sourceError(Line, "DEFAULT return types are not supported in templates"); + return nullptr; + } + return Def; } std::unique_ptr<FunctionDefAST> Parser::ParseProcedure(const std::string &OwnerClass, bool IsPublic, bool IsOverload) { |
