forked from Mirrors/openclonk
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.
parent
f61ebfc453
commit
18038f45d3
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue