aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/CodeGen/CallGen.cc10
-rw-r--r--lib/CodeGen/FunctionGen.cc27
-rw-r--r--lib/CodeGen/OperatorGen.cc8
-rw-r--r--lib/CodeGen/TemplateClone.cc1
-rw-r--r--lib/Lexer/Lexer.cc1
-rw-r--r--lib/Parser/ParserFunction.cc13
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) {