[colobot] 46/74: Add implicit cast and null for passing arguments
Didier Raboud
odyx at moszumanska.debian.org
Mon Nov 7 07:50:04 UTC 2016
This is an automated email from the git hooks/post-receive script.
odyx pushed a commit to branch debian/master
in repository colobot.
commit 4a14a44f3f07ee103161fbec2bcaa4bf5e6e2a84
Author: melex750 <melex750 at users.noreply.github.com>
Date: Sat Sep 17 07:58:39 2016 -0400
Add implicit cast and null for passing arguments
---
src/CBot/CBotEnums.h | 1 +
src/CBot/CBotInstr/CBotFunction.cpp | 107 +++++++++++++++++++++-------------
src/CBot/CBotInstr/CBotInstrUtils.cpp | 10 +++-
src/common/restext.cpp | 1 +
test/unit/CBot/CBot_test.cpp | 88 ++++++++++++++++++++++++++++
5 files changed, 165 insertions(+), 42 deletions(-)
diff --git a/src/CBot/CBotEnums.h b/src/CBot/CBotEnums.h
index 24e0095..da0dbea 100644
--- a/src/CBot/CBotEnums.h
+++ b/src/CBot/CBotEnums.h
@@ -236,6 +236,7 @@ enum CBotError : int
CBotErrPrivate = 5041, //!< protected item
CBotErrNoPublic = 5042, //!< missing word "public"
CBotErrNoExpression = 5043, //!< expression expected after =
+ CBotErrAmbiguousCall = 5044, //!< ambiguous call to overloaded function
// Runtime errors
CBotErrZeroDiv = 6000, //!< division by zero
diff --git a/src/CBot/CBotInstr/CBotFunction.cpp b/src/CBot/CBotInstr/CBotFunction.cpp
index d00e8ea..1e7e0b9 100644
--- a/src/CBot/CBotInstr/CBotFunction.cpp
+++ b/src/CBot/CBotInstr/CBotFunction.cpp
@@ -466,8 +466,7 @@ CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const std::string& n
if ( name.empty() ) return nullptr;
- int delta = 99999; // seeks the lowest signature
- CBotFunction* pFunc = nullptr; // the best function found
+ std::map<CBotFunction*, int> funcMap;
if ( this != nullptr )
{
@@ -482,44 +481,48 @@ CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const std::string& n
CBotVar* pw = ppVars[i++]; // provided list parameter
while ( pv != nullptr && pw != nullptr)
{
- if (!TypesCompatibles(pv->GetTypResult(), pw->GetTypResult()))
+ CBotTypResult paramType = pv->GetTypResult();
+ CBotTypResult argType = pw->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
+
+ if (!TypesCompatibles(paramType, argType))
{
- if ( pFunc == nullptr ) TypeOrError = CBotErrBadParam;
+ if ( funcMap.empty() ) TypeOrError.SetType(CBotErrBadParam);
break;
}
- int d = pv->GetType() - pw->GetType(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
- alpha += d>0 ? d : -10*d; // quality loss, 10 times more expensive!
+ if (paramType.Eq(CBotTypPointer) && !argType.Eq(CBotTypNullPointer))
+ {
+ CBotClass* c1 = paramType.GetClass();
+ CBotClass* c2 = argType.GetClass();
+ while (c2 != c1 && c2 != nullptr) // implicit cast
+ {
+ alpha += 10;
+ c2 = c2->GetParent();
+ }
+ }
+ else
+ {
+ int d = pv->GetType() - pw->GetType(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
+ alpha += d>0 ? d : -10*d; // quality loss, 10 times more expensive!
+ }
pv = pv->GetNext();
pw = ppVars[i++];
}
if ( pw != nullptr )
{
- if ( pFunc != nullptr ) continue;
+ if ( !funcMap.empty() ) continue;
if ( TypeOrError.Eq(CBotErrLowParam) ) TypeOrError.SetType(CBotErrNbParam);
if ( TypeOrError.Eq(CBotErrUndefCall)) TypeOrError.SetType(CBotErrOverParam);
continue; // too many parameters
}
if ( pv != nullptr )
{
- if ( pFunc != nullptr ) continue;
+ if ( !funcMap.empty() ) continue;
if ( TypeOrError.Eq(CBotErrOverParam) ) TypeOrError.SetType(CBotErrNbParam);
if ( TypeOrError.Eq(CBotErrUndefCall) ) TypeOrError.SetType(CBotErrLowParam);
continue; // not enough parameters
}
-
- if (alpha == 0) // perfect signature
- {
- nIdent = pt->m_nFuncIdent;
- TypeOrError = pt->m_retTyp;
- return pt;
- }
-
- if ( alpha < delta ) // a better signature?
- {
- pFunc = pt;
- delta = alpha;
- }
+ funcMap.insert( std::pair<CBotFunction*, int>(pt, alpha) );
}
}
}
@@ -537,50 +540,72 @@ CBotFunction* CBotFunction::FindLocalOrPublic(long& nIdent, const std::string& n
CBotVar* pw = ppVars[i++]; // list of provided parameters
while ( pv != nullptr && pw != nullptr)
{
- if (!TypesCompatibles(pv->GetTypResult(), pw->GetTypResult()))
+ CBotTypResult paramType = pv->GetTypResult();
+ CBotTypResult argType = pw->GetTypResult(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
+
+ if (!TypesCompatibles(paramType, argType))
{
- if ( pFunc == nullptr ) TypeOrError = CBotErrBadParam;
+ if ( funcMap.empty() ) TypeOrError.SetType(CBotErrBadParam);
break;
}
- int d = pv->GetType() - pw->GetType(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
- alpha += d>0 ? d : -10*d; // quality loss, 10 times more expensive!
+ if (paramType.Eq(CBotTypPointer) && !argType.Eq(CBotTypNullPointer))
+ {
+ CBotClass* c1 = paramType.GetClass();
+ CBotClass* c2 = argType.GetClass();
+ while (c2 != c1 && c2 != nullptr) // implicit cast
+ {
+ alpha += 10;
+ c2 = c2->GetParent();
+ }
+ }
+ else
+ {
+ int d = pv->GetType() - pw->GetType(CBotVar::GetTypeMode::CLASS_AS_INTRINSIC);
+ alpha += d>0 ? d : -10*d; // quality loss, 10 times more expensive!
+ }
pv = pv->GetNext();
pw = ppVars[i++];
}
if ( pw != nullptr )
{
- if ( pFunc != nullptr ) continue;
+ if ( !funcMap.empty() ) continue; // previous useable function
if ( TypeOrError.Eq(CBotErrLowParam) ) TypeOrError.SetType(CBotErrNbParam);
if ( TypeOrError.Eq(CBotErrUndefCall)) TypeOrError.SetType(CBotErrOverParam);
continue; // to many parameters
}
if ( pv != nullptr )
{
- if ( pFunc != nullptr ) continue;
+ if ( !funcMap.empty() ) continue; // previous useable function
if ( TypeOrError.Eq(CBotErrOverParam) ) TypeOrError.SetType(CBotErrNbParam);
if ( TypeOrError.Eq(CBotErrUndefCall) ) TypeOrError.SetType(CBotErrLowParam);
continue; // not enough parameters
}
-
- if (alpha == 0) // perfect signature
- {
- nIdent = pt->m_nFuncIdent;
- TypeOrError = pt->m_retTyp;
- return pt;
- }
-
- if ( alpha < delta ) // a better signature?
- {
- pFunc = pt;
- delta = alpha;
- }
+ funcMap.insert( std::pair<CBotFunction*, int>(pt, alpha) );
}
}
}
- if ( pFunc != nullptr )
+ if ( !funcMap.empty() )
{
+ auto it = funcMap.begin();
+ CBotFunction* pFunc = it->first; // the best function found
+ signed int delta = it->second; // seeks the lowest signature
+
+ for (++it ; it != funcMap.end() ; it++)
+ {
+ if (it->second < delta) // a better signature?
+ {
+ TypeOrError.SetType(CBotNoErr);
+ pFunc = it->first;
+ delta = it->second;
+ continue;
+ }
+
+ if (it->second == delta) TypeOrError.SetType(CBotErrAmbiguousCall);
+ }
+
+ if (TypeOrError.Eq(CBotErrAmbiguousCall)) return nullptr;
nIdent = pFunc->m_nFuncIdent;
TypeOrError = pFunc->m_retTyp;
return pFunc;
diff --git a/src/CBot/CBotInstr/CBotInstrUtils.cpp b/src/CBot/CBotInstr/CBotInstrUtils.cpp
index bbe80b2..067f443 100644
--- a/src/CBot/CBotInstr/CBotInstrUtils.cpp
+++ b/src/CBot/CBotInstr/CBotInstrUtils.cpp
@@ -149,12 +149,20 @@ bool TypesCompatibles(const CBotTypResult& type1, const CBotTypResult& type2)
if (max >= CBotTypBoolean)
{
+ if (t1 == CBotTypPointer && t2 == CBotTypNullPointer) return true;
if (t2 != t1) return false;
+ if (max == CBotTypPointer)
+ {
+ CBotClass* c1 = type1.GetClass();
+ CBotClass* c2 = type2.GetClass();
+ return c2->IsChildOf(c1);
+ }
+
if (max == CBotTypArrayPointer)
return TypesCompatibles(type1.GetTypElem(), type2.GetTypElem());
- if (max == CBotTypClass || max == CBotTypPointer)
+ if (max == CBotTypClass)
return type1.GetClass() == type2.GetClass() ;
return true ;
diff --git a/src/common/restext.cpp b/src/common/restext.cpp
index 9770c32..859a61f 100644
--- a/src/common/restext.cpp
+++ b/src/common/restext.cpp
@@ -717,6 +717,7 @@ void InitializeRestext()
stringsCbot[CBot::CBotErrPrivate] = TR("Private element");
stringsCbot[CBot::CBotErrNoPublic] = TR("Public required");
stringsCbot[CBot::CBotErrNoExpression] = TR("Expression expected after =");
+ stringsCbot[CBot::CBotErrAmbiguousCall] = TR("Ambiguous call to overloaded function");
stringsCbot[CBot::CBotErrZeroDiv] = TR("Dividing by zero");
stringsCbot[CBot::CBotErrNotInit] = TR("Variable not initialized");
diff --git a/test/unit/CBot/CBot_test.cpp b/test/unit/CBot/CBot_test.cpp
index 071abb9..2a112d7 100644
--- a/test/unit/CBot/CBot_test.cpp
+++ b/test/unit/CBot/CBot_test.cpp
@@ -1786,3 +1786,91 @@ TEST_F(CBotUT, ClassNewConstructorMethodChain)
"}\n"
);
}
+
+TEST_F(CBotUT, PassNullAsArgument)
+{
+ auto publicProgram = ExecuteTest(
+ "public class BaseClass {}\n"
+ "public class SubClass extends BaseClass {}\n"
+ );
+
+ ExecuteTest(
+ "bool Test(BaseClass b) {\n"
+ " return (b == null);\n"
+ "}\n"
+ "extern void PassNullAsArgument() {\n"
+ " ASSERT(true == Test(null));\n"
+ "}\n"
+ );
+
+ ExecuteTest(
+ "void Test(BaseClass b) {}\n"
+ "void Test(SubClass s) {}\n"
+ "\n"
+ "extern void AmbiguousCallArgumentNull() {\n"
+ " Test(null);\n"
+ "}\n",
+ CBotErrAmbiguousCall
+ );
+}
+
+TEST_F(CBotUT, ClassImplicitCastArguments)
+{
+ auto publicProgram = ExecuteTest(
+ "public class BaseClass { int a = 360; }\n"
+ "public class SubClass extends BaseClass {}\n"
+ );
+
+ ExecuteTest(
+ "bool Test(BaseClass b) {\n"
+ " SubClass s = b;\n"
+ " return (360 == s.a);\n"
+ "}\n"
+ "extern void UpcastPassingArguments() {\n"
+ " ASSERT(true == Test(new SubClass()));\n"
+ "}\n"
+ );
+
+ ExecuteTest(
+ "void Test(BaseClass b, SubClass s) {}\n"
+ "void Test(SubClass s, BaseClass b) {}\n"
+ "\n"
+ "extern void UpcastAmbiguousCall() {\n"
+ " Test(new SubClass(), new SubClass());\n"
+ "}\n",
+ CBotErrAmbiguousCall
+ );
+
+ ExecuteTest(
+ "bool Test(BaseClass b, SubClass s) { return false; }\n"
+ "bool Test(SubClass s, BaseClass b) { return false; }\n"
+ "bool Test(SubClass s, SubClass s2) { return true; }\n"
+ "\n"
+ "extern void NoErrorMoreSpecific() {\n"
+ " ASSERT(true == Test(new SubClass(), new SubClass()));\n"
+ "}\n"
+ );
+}
+
+TEST_F(CBotUT, AmbiguousCallWithNumbers)
+{
+ ExecuteTest(
+ "void Test(int i, float f) {}\n"
+ "void Test(float f, int i) {}\n"
+ "\n"
+ "extern void AmbiguousCallNumbers() {\n"
+ " Test(1, 2);\n"
+ "}\n",
+ CBotErrAmbiguousCall
+ );
+
+ ExecuteTest(
+ "bool Test(int i, float f) { return false; }\n"
+ "bool Test(float f, int i) { return false; }\n"
+ "bool Test(int i, int ii) { return true; }\n"
+ "\n"
+ "extern void NoErrorMoreSpecific() {\n"
+ " ASSERT(true == Test(1, 2));\n"
+ "}\n"
+ );
+}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/colobot.git
More information about the Pkg-games-commits
mailing list