Implement the function overload tree using the proplists

Instead of carefully inserting functions at the start or end of the list,
build the list just before the parser runs, at the same time as filling
the proplist where the functions are looked up.

This way, the overloaded function is simply the one that was previously in
the proplist, is not needed outside of the overloading function, and can thus
be replaced in the proplist.
Günther Brammer 2012-01-27 00:20:55 +01:00
parent f61ebfc453
commit 18038f45d3
6 changed files with 99 additions and 167 deletions

View File

@ -45,48 +45,34 @@ void C4AulError::show()
DebugLog(sMessage.getData());
}
C4AulFunc::C4AulFunc(C4AulScript *pOwner, const char *pName, bool bAtEnd):
C4AulFunc::C4AulFunc(C4AulScript *pOwner, const char *pName):
Name(pName ? Strings.RegString(pName) : 0),
MapNext(NULL),
LinkedTo (NULL),
OverloadedBy (NULL)
{
// reg2list (at end or at the beginning)
AppendToScript(pOwner);
}
void C4AulFunc::AppendToScript(C4AulScript * pOwner)
{
Owner = pOwner;
if (bAtEnd)
if ((Prev = Owner->FuncL))
{
if ((Prev = Owner->FuncL))
{
Prev->Next = this;
Owner->FuncL = this;
}
else
{
Owner->Func0 = this;
Owner->FuncL = this;
}
Next = NULL;
Prev->Next = this;
Owner->FuncL = this;
}
else
{
if ((Next = Owner->Func0))
{
Next->Prev = this;
Owner->Func0 = this;
}
else
{
Owner->Func0 = this;
Owner->FuncL = this;
}
Prev = NULL;
Owner->Func0 = this;
Owner->FuncL = this;
}
Next = NULL;
// add to global lookuptable with this name
if (GetName())
Owner->Engine->FuncLookUp.Add(this, bAtEnd);
Owner->Engine->FuncLookUp.Add(this, true);
}
C4AulFunc::~C4AulFunc()
{
// if it's a global: remove the global link!
@ -240,60 +226,6 @@ void C4AulScript::Reg2List(C4AulScriptEngine *pEngine, C4AulScript *pOwner)
Next = NULL;
}
C4AulFunc *C4AulScript::GetOverloadedFunc(C4AulFunc *ByFunc)
{
assert(ByFunc);
// search local list
C4AulFunc *f = ByFunc;
if (f) f = f->Prev; else f = FuncL;
while (f)
{
if (SEqual(ByFunc->GetName(), f->GetName())) break;
f = f->Prev;
}
#ifdef _DEBUG
C4AulFunc * f2 = Engine ? Engine->GetFunc(ByFunc->GetName(), this, ByFunc) : NULL;
assert (f == f2);
#endif
// nothing found? then search owner, if existant
if (!f && Owner)
{
if ((f = Owner->GetFuncRecursive(ByFunc->GetName())))
// just found the global link?
if (ByFunc && f->LinkedTo == ByFunc)
f = Owner->GetOverloadedFunc(f);
}
// return found fn
return f;
}
C4AulFunc *C4AulScript::GetFuncRecursive(const char *pIdtf)
{
// search local list
C4AulFunc *f = GetFunc(pIdtf);
if (f) return f;
// nothing found? then search owner, if existant
else if (Owner) return Owner->GetFuncRecursive(pIdtf);
return NULL;
}
C4AulFunc *C4AulScript::GetFunc(const char *pIdtf)
{
C4AulFunc * f = Engine ? Engine->GetFunc(pIdtf, this, NULL) : NULL;
#if 0
// search func list
C4AulFunc *f2 = FuncL;
while (f2)
{
if (SEqual(pIdtf, f2->Name)) break;
f2 = f2->Prev;
}
assert (f == f2);
#endif
return f;
}
std::string C4AulScript::Translate(const std::string &text) const
{
const C4AulScript *cursor = this;
@ -314,16 +246,10 @@ std::string C4AulScript::Translate(const std::string &text) const
throw C4LangStringTable::NoSuchTranslation(text);
}
C4AulScriptFunc::C4AulScriptFunc(C4AulScript *pOwner, const char *pName, bool bAtEnd):
C4AulFunc(pOwner, pName, bAtEnd), OwnerOverloaded(NULL), ParCount(0), tProfileTime(0)
C4AulScriptFunc::C4AulScriptFunc(C4AulScript *pOwner, const char *pName):
C4AulFunc(pOwner, pName), OwnerOverloaded(NULL), ParCount(0), tProfileTime(0)
{
for (int i = 0; i < C4AUL_MAX_Par; i++) ParType[i] = C4V_Any;
if (Owner->GetPropList() && Name)
{
// Don't overwrite a function that's overloading this one
if (bAtEnd || !Owner->GetPropList()->HasProperty(Name))
Owner->GetPropList()->SetPropertyByS(Name, C4VFunction(this));
}
}
void C4AulScriptFunc::CopyBody(C4AulScriptFunc &FromFunc)
@ -532,22 +458,6 @@ C4AulFunc * C4AulFuncMap::GetNextSNFunc(const C4AulFunc * After)
return Func;
}
C4AulFunc * C4AulFuncMap::GetFunc(const char * Name, const C4AulScript * Owner, const C4AulFunc * After)
{
if (!Name) return NULL;
C4AulFunc * Func = Funcs[Hash(Name) % Capacity];
if (After)
{
while (Func && Func != After)
Func = Func->MapNext;
if (Func)
Func = Func->MapNext;
}
while (Func && (Func->Owner != Owner || !SEqual(Name, Func->GetName())))
Func = Func->MapNext;
return Func;
}
void C4AulFuncMap::Add(C4AulFunc * func, bool bAtStart)
{
if (++FuncCnt > Capacity)

View File

@ -215,7 +215,7 @@ class C4AulFunc
friend class C4ScriptHost;
public:
C4AulFunc(C4AulScript *pOwner, const char *pName, bool bAtEnd = true); // constructor
C4AulFunc(C4AulScript *pOwner, const char *pName);
virtual ~C4AulFunc(); // destructor
C4AulScript *Owner; // owner
@ -227,6 +227,7 @@ protected:
C4AulFunc *Prev, *Next; // linked list members
C4AulFunc *MapNext; // map member
C4AulFunc *LinkedTo; // points to next linked function; destructor will destroy linked func, too
void AppendToScript(C4AulScript *);
public:
C4AulFunc *OverloadedBy; // function by which this one is overloaded
@ -266,7 +267,7 @@ public:
void AddPar(const char * Idtf) { ParNamed.AddName(Idtf); ++ParCount; }
C4ScriptHost *pOrgScript; // the orginal script (!= Owner if included or appended)
C4AulScriptFunc(C4AulScript *pOwner, const char *pName, bool bAtEnd = true);
C4AulScriptFunc(C4AulScript *pOwner, const char *pName);
void ParseFn(bool fExprOnly = false, C4AulScriptContext* context = NULL);
virtual void UnLink();
@ -313,7 +314,6 @@ class C4AulFuncMap
public:
C4AulFuncMap();
~C4AulFuncMap();
C4AulFunc * GetFunc(const char * Name, const C4AulScript * Owner, const C4AulFunc * After);
C4AulFunc * GetFirstFunc(const char * Name);
C4AulFunc * GetNextSNFunc(const C4AulFunc * After);
private:
@ -325,6 +325,7 @@ protected:
void Add(C4AulFunc * func, bool bAtEnd = true);
void Remove(C4AulFunc * func);
friend class C4AulFunc;
friend class C4ScriptHost;
};
@ -382,7 +383,6 @@ public:
virtual C4PropList * GetPropList() { return 0; }
virtual C4ScriptHost * GetScriptHost() { return 0; }
C4AulFunc *GetFuncRecursive(const char *pIdtf); // search function by identifier, including global funcs
void AddFunc(const char *pIdtf, C4ScriptFnDef* Def); // add def def func to table
@ -419,14 +419,10 @@ protected:
std::list<C4ID> Includes; // include list
std::list<C4ID> Appends; // append list
// internal function used to find overloaded functions
C4AulFunc *GetOverloadedFunc(C4AulFunc *ByFunc);
C4AulFunc *GetFunc(const char *pIdtf); // get local function by name
bool ResolveIncludes(C4DefList *rDefs); // resolve includes
bool ResolveAppends(C4DefList *rDefs); // resolve appends
void LinkFunctions();
bool IncludesResolved;
void AppendTo(C4AulScript &Scr, bool bHighPrio); // append to given script
virtual void UnLink(); // reset to unlinked state
virtual void AfterLink(); // called after linking is completed; presearch common funcs here
virtual bool ReloadScript(const char *szPath, const char *szLanguage); // reload given script
@ -467,8 +463,6 @@ public:
virtual void AfterLink();
C4AulFunc * GetFirstFunc(const char * Name)
{ return FuncLookUp.GetFirstFunc(Name); }
C4AulFunc * GetFunc(const char * Name, const C4AulScript * Owner, const C4AulFunc * After)
{ return FuncLookUp.GetFunc(Name, Owner, After); }
C4AulFunc * GetNextSNFunc(const C4AulFunc * After)
{ return FuncLookUp.GetNextSNFunc(After); }
@ -487,6 +481,7 @@ public:
void CompileFunc(StdCompiler *pComp, C4ValueNumbers * numbers);
friend class C4AulFunc;
friend class C4ScriptHost;
friend class C4AulParseState;
friend class C4AulDebug;
friend class C4AulScript;

View File

@ -40,7 +40,7 @@ bool C4AulScript::ResolveAppends(C4DefList *rDefs)
{
C4Def *Def = rDefs->ID2Def(*a);
if (Def)
AppendTo(Def->Script, true);
Def->Script.SourceScripts.push_back(GetScriptHost());
else
{
// save id in buffer because AulWarn will use the buffer of C4IdText
@ -58,7 +58,7 @@ bool C4AulScript::ResolveAppends(C4DefList *rDefs)
if (!pDef) break;
if (pDef == GetPropList()) continue;
// append
AppendTo(pDef->Script, true);
pDef->Script.SourceScripts.push_back(GetScriptHost());
}
}
}
@ -81,7 +81,7 @@ bool C4AulScript::ResolveIncludes(C4DefList *rDefs)
}
Resolving=true;
// append all includes to local script
for (std::list<C4ID>::iterator i = Includes.begin(); i != Includes.end(); ++i)
for (std::list<C4ID>::reverse_iterator i = Includes.rbegin(); i != Includes.rend(); ++i)
{
C4Def *Def = rDefs->ID2Def(*i);
if (Def)
@ -91,7 +91,8 @@ bool C4AulScript::ResolveIncludes(C4DefList *rDefs)
if (!Def->Script.ResolveIncludes(rDefs))
continue; // skip this #include
Def->Script.AppendTo(*this, false);
for (std::list<C4ScriptHost *>::reverse_iterator s = Def->Script.SourceScripts.rbegin(); s != Def->Script.SourceScripts.rend(); ++s)
GetScriptHost()->SourceScripts.push_front(*s);
}
else
{
@ -108,47 +109,6 @@ bool C4AulScript::ResolveIncludes(C4DefList *rDefs)
return true;
}
void C4AulScript::AppendTo(C4AulScript &Scr, bool bHighPrio)
{
// definition appends
if (GetPropList() && GetPropList()->GetDef() && Scr.GetPropList() && Scr.GetPropList()->GetDef())
Scr.GetPropList()->GetDef()->IncludeDefinition(GetPropList()->GetDef());
// append all funcs
// (in reverse order if inserted at begin of list)
C4AulScriptFunc *sf;
for (C4AulFunc *f = bHighPrio ? Func0 : FuncL; f; f = bHighPrio ? f->Next : f->Prev)
// script funcs only
if ((sf = f->SFunc()))
// no need to append global funcs
if (sf->Access != AA_GLOBAL)
{
// append: create copy
// (if high priority, insert at end, otherwise at the beginning)
C4AulScriptFunc *sfc = new C4AulScriptFunc(&Scr, sf->GetName(), bHighPrio);
sfc->CopyBody(*sf);
// link the copy to a local function
if (sf->LinkedTo)
{
sfc->LinkedTo = sf->LinkedTo;
sf->LinkedTo = sfc;
}
else
{
sfc->LinkedTo = sf;
sf->LinkedTo = sfc;
}
}
// mark as linked
// increase code size needed
// append all local vars (if any existing)
if (LocalNamed.iSize == 0)
return;
// copy local var definitions
for (int ivar = 0; ivar < LocalNamed.iSize; ivar ++)
Scr.LocalNamed.AddName(LocalNamed.pNames[ivar]);
}
void C4AulScript::UnLink()
{
// do not unlink temporary (e.g., DirectExec-script in ReloadDef)
@ -216,6 +176,9 @@ void C4AulScriptEngine::Link(C4DefList *rDefs)
for (C4AulScript *s = Child0; s; s = s->Next)
s->ResolveIncludes(rDefs);
// put script functions into the proplist
LinkFunctions();
// parse the scripts to byte code
for (C4AulScript *s = Child0; s; s = s->Next)
s->Parse();

View File

@ -1201,11 +1201,6 @@ void C4AulParseState::UnexpectedToken(const char * Expected)
void C4AulScriptFunc::ParseFn(bool fExprOnly, C4AulScriptContext* context)
{
// check if fn overloads other fn (all func tables are built now)
// *MUST* check Fn->Owner-list, because it may be the engine (due to linked globals)
if ((OwnerOverloaded = Owner->GetOverloadedFunc(this)))
if (Owner == OwnerOverloaded->Owner)
OwnerOverloaded->OverloadedBy=this;
// store byte code pos
// (relative position to code start; code pointer may change while
// parsing)
@ -1255,7 +1250,7 @@ void C4AulParseState::Parse_Script()
if (Type == PREPARSER)
{
// add to include list
a->Includes.push_front(C4ID(StdStrBuf(Idtf)));
a->Includes.push_back(C4ID(StdStrBuf(Idtf)));
}
Shift();
}
@ -2826,6 +2821,19 @@ bool C4AulScript::Parse()
return true;
}
void C4AulScript::LinkFunctions()
{
for (C4AulFunc *f = Func0; f; f = f->Next)
{
C4AulScriptFunc *sf = f->SFunc();
if (!sf) continue;
sf->OwnerOverloaded = GetPropList()->GetFunc(sf->Name);
if (sf->OwnerOverloaded && sf->OwnerOverloaded->Owner == this)
sf->OwnerOverloaded->OverloadedBy = sf;
GetPropList()->SetPropertyByS(sf->Name, C4VFunction(sf));
}
}
bool C4ScriptHost::Parse()
{
if (DEBUG_BYTECODE_DUMP)
@ -2838,6 +2846,58 @@ bool C4ScriptHost::Parse()
// delete existing code
ClearCode();
C4AulFunc * thisfuncs = Func0;
for (C4AulFunc *f = thisfuncs; f; f = f->Next)
if (f->GetName() && f->SFunc())
{
Engine->FuncLookUp.Remove(f);
}
Func0 = FuncL = 0;
for (std::list<C4ScriptHost *>::iterator s = SourceScripts.begin(); s != SourceScripts.end(); ++s)
{
if (*s == this)
{
C4AulFunc *f = thisfuncs, *n;
while (f)
{
n = f->Next;
f->AppendToScript(this);
f = n;
}
continue;
}
// definition appends
if (GetPropList() && GetPropList()->GetDef() && (*s)->GetPropList() && (*s)->GetPropList()->GetDef())
GetPropList()->GetDef()->IncludeDefinition((*s)->GetPropList()->GetDef());
// append all funcs
C4AulScriptFunc *sf;
for (C4AulFunc *f = (*s)->Func0; f; f = f->Next)
// script funcs only, no need to append global funcs
if ((sf = f->SFunc()) && sf->Access != AA_GLOBAL && sf->pOrgScript == *s)
{
// append: create copy
C4AulScriptFunc *sfc = new C4AulScriptFunc(this, sf->GetName());
sfc->CopyBody(*sf);
// link the copy to a local function
if (sf->LinkedTo)
{
sfc->LinkedTo = sf->LinkedTo;
sf->LinkedTo = sfc;
}
else
{
sfc->LinkedTo = sf;
sf->LinkedTo = sfc;
}
}
// copy local var definitions
for (int ivar = 0; ivar < (*s)->LocalNamed.iSize; ivar ++)
LocalNamed.AddName((*s)->LocalNamed.pNames[ivar]);
}
LinkFunctions();
// parse script funcs
C4AulFunc *f;
for (f = Func0; f; f = f->Next)

View File

@ -41,6 +41,7 @@ C4ScriptHost::C4ScriptHost()
Code.clear();
LastCode = NULL;
stringTable = 0;
SourceScripts.push_back(this);
}
C4ScriptHost::~C4ScriptHost() { Clear(); }
@ -50,6 +51,8 @@ void C4ScriptHost::Clear()
ComponentHost.Clear();
Script.Clear();
ClearCode();
SourceScripts.clear();
SourceScripts.push_back(this);
}
bool C4ScriptHost::Load(C4Group &hGroup, const char *szFilename,

View File

@ -39,6 +39,7 @@ public:
const char *szLanguage, C4LangStringTable *pLocalTable);
const char *GetScript() const { return Script.getData(); }
virtual C4ScriptHost * GetScriptHost() { return this; }
std::list<C4ScriptHost *> SourceScripts;
protected:
C4ScriptHost();
void SetError(const char *szMessage);