Optionally warn about too many parameters in -> calls, too

While at it, only consult the right function for direct calls, not any
other function with the same name.
liquid_container
Günther Brammer 2016-02-01 02:14:54 +01:00
parent b2c263bd0e
commit 6a6c0d8b0b
4 changed files with 25 additions and 21 deletions

View File

@ -210,11 +210,11 @@ unsigned int C4AulFuncMap::Hash(const char * name)
return h;
}
C4AulFunc * C4AulFuncMap::GetFirstFunc(C4String * Name)
C4AulFunc * C4AulFuncMap::GetFirstFunc(const char * Name)
{
if (!Name) return NULL;
C4AulFunc * Func = Funcs[Hash(Name->GetCStr()) % HashSize];
while (Func && Name->GetCStr() != Func->GetName())
C4AulFunc * Func = Funcs[Hash(Name) % HashSize];
while (Func && !SEqual(Name, Func->GetName()))
Func = Func->MapNext;
return Func;
}

View File

@ -61,7 +61,7 @@ class C4AulFuncMap
public:
C4AulFuncMap();
~C4AulFuncMap();
C4AulFunc * GetFirstFunc(C4String * Name);
C4AulFunc * GetFirstFunc(const char * Name);
C4AulFunc * GetNextSNFunc(const C4AulFunc * After);
private:
enum { HashSize = 1025 };
@ -97,7 +97,7 @@ class C4AulScriptEngine: public C4PropListStaticMember
{
protected:
C4AulFuncMap FuncLookUp;
C4AulFunc * GetFirstFunc(C4String * Name)
C4AulFunc * GetFirstFunc(const char * Name)
{ return FuncLookUp.GetFirstFunc(Name); }
C4AulFunc * GetNextSNFunc(const C4AulFunc * After)
{ return FuncLookUp.GetNextSNFunc(After); }

View File

@ -221,6 +221,8 @@ public:
pFunc(pFunc), ParType {C4ValueConv<ParTypes>::Type()...}, Public(Public)
{
Parent->SetPropertyByS(Name, C4VFunction(this));
for(int i = GetParCount(); i < C4AUL_MAX_Par; ++i)
ParType[i] = C4V_Any;
}
virtual int GetParCount() const
@ -250,7 +252,7 @@ public:
}
protected:
Func pFunc;
C4V_Type ParType[10];// type of the parameters
C4V_Type ParType[C4AUL_MAX_Par];// type of the parameters
bool Public;
};

View File

@ -1036,7 +1036,7 @@ C4V_Type C4AulParse::GetLastRetType(C4V_Type to)
case AB_CALL: case AB_CALLFS:
{
C4String * pName = Fn->GetLastCode()->Par.s;
C4AulFunc * pFunc2 = Engine->GetFirstFunc(pName);
C4AulFunc * pFunc2 = Engine->GetFirstFunc(pName->GetCStr());
bool allwarn = true;
from = C4V_Any;
while (pFunc2 && allwarn)
@ -1711,7 +1711,7 @@ void C4AulParse::Parse_Statement()
int C4AulParse::Parse_Params(int iMaxCnt, const char * sWarn, C4AulFunc * pFunc)
{
int size = 0;
int size = 0, WarnCnt = iMaxCnt;
// so it's a regular function; force "("
Match(ATT_BOPEN);
bool fDone = false;
@ -1751,14 +1751,18 @@ int C4AulParse::Parse_Params(int iMaxCnt, const char * sWarn, C4AulFunc * pFunc)
default:
// get a parameter
Parse_Expression();
if (pFunc && (Type == PARSER) && size < iMaxCnt)
C4AulFunc * pFunc2 = pFunc ? pFunc : Engine->GetFirstFunc(sWarn);
if (pFunc2 && (Type == PARSER) && size < iMaxCnt)
{
C4V_Type to = pFunc->GetParType()[size];
// pFunc either is the return value from a GetFirstFunc-Call or
// the only function that could be called. When in doubt, don't warn.
C4AulFunc * pFunc2 = pFunc;
while ((pFunc2 = Engine->GetNextSNFunc(pFunc2)))
WarnCnt = pFunc2->GetParCount();
C4V_Type to = pFunc2->GetParType()[size];
// While script can arrange to call any function by changing proplists, the parser has
// no hope of anticipating that, so checking functions of the same name will have to do.
if(!pFunc) while ((pFunc2 = Engine->GetNextSNFunc(pFunc2)))
{
WarnCnt = std::max(WarnCnt, pFunc2->GetParCount());
if (pFunc2->GetParType()[size] != to) to = C4V_Any;
}
C4V_Type from = GetLastRetType(to);
if (C4Value::WarnAboutConversion(from, to))
{
@ -1776,8 +1780,8 @@ int C4AulParse::Parse_Params(int iMaxCnt, const char * sWarn, C4AulFunc * pFunc)
break;
} while (!fDone);
// too many parameters?
if (sWarn && size > iMaxCnt && Type == PARSER)
Warn(FormatString("call to %s gives %d parameters, but only %d are used", sWarn, size, iMaxCnt).getData(), NULL);
if (sWarn && size > WarnCnt && Type == PARSER && !SEqual(sWarn, C4AUL_Inherited) && (pFunc || Config.Developer.ExtraWarnings))
Warn(FormatString("call to %s gives %d parameters, but only %d are used", sWarn, size, WarnCnt).getData(), NULL);
// Balance stack// FIXME: not for CALL/FUNC
if (size != iMaxCnt)
AddBCC(AB_STACK, iMaxCnt - size);
@ -2278,7 +2282,7 @@ void C4AulParse::Parse_Expression(int iParentPrio)
if (Fn->OwnerOverloaded)
{
// add direct call to byte code
Parse_Params(Fn->OwnerOverloaded->GetParCount(), NULL, Fn->OwnerOverloaded);
Parse_Params(Fn->OwnerOverloaded->GetParCount(), C4AUL_Inherited, Fn->OwnerOverloaded);
AddBCC(AB_FUNC, (intptr_t) Fn->OwnerOverloaded);
}
else
@ -2300,7 +2304,7 @@ void C4AulParse::Parse_Expression(int iParentPrio)
// will be defined: if no '(' follows, it must be a variable or constant,
// otherwise a function with parameters
if (TokenType == ATT_BOPEN)
Parse_Params(10, NULL);
Parse_Params(C4AUL_MAX_Par, NULL);
}
else if ((FoundFn = Fn->Parent->GetFunc(Idtf)))
{
@ -2560,7 +2564,6 @@ void C4AulParse::Parse_Expression(int iParentPrio)
break;
case ATT_CALL: case ATT_CALLFS:
{
C4AulFunc *pFunc = NULL;
C4String *pName = NULL;
C4AulBCCType eCallType = (TokenType == ATT_CALL) ? AB_CALL : AB_CALLFS;
Shift();
@ -2570,10 +2573,9 @@ void C4AulParse::Parse_Expression(int iParentPrio)
if (Type == PARSER)
{
pName = ::Strings.RegString(Idtf);
pFunc = Engine->GetFirstFunc(pName);
}
Shift();
Parse_Params(C4AUL_MAX_Par, pName ? pName->GetCStr() : Idtf, pFunc);
Parse_Params(C4AUL_MAX_Par, pName ? pName->GetCStr() : Idtf, NULL);
AddBCC(eCallType, reinterpret_cast<intptr_t>(pName));
}
break;