forked from Mirrors/openclonk
Store a copy of the proplist the preparser created for include/appendto
The parser now copies the contents of the proplists in the order of their source scripts into the final proplist. This way, local variable contents get properly included, and the list of functions has one user less.rope
parent
e26bc8e33a
commit
487a0ea38f
|
@ -148,6 +148,18 @@ C4AulScriptFunc::C4AulScriptFunc(C4AulScript *pOwner, const C4AulScriptFunc &Fro
|
|||
ParType[i] = FromFunc.ParType[i];
|
||||
}
|
||||
|
||||
C4AulScriptFunc::~C4AulScriptFunc()
|
||||
{
|
||||
if (OwnerOverloaded) OwnerOverloaded->DecRef();
|
||||
}
|
||||
|
||||
void C4AulScriptFunc::SetOverloaded(C4AulFunc * f)
|
||||
{
|
||||
if (OwnerOverloaded) OwnerOverloaded->DecRef();
|
||||
OwnerOverloaded = f;
|
||||
if (f) f->IncRef();
|
||||
}
|
||||
|
||||
/*--- C4AulScriptEngine ---*/
|
||||
|
||||
C4AulScriptEngine::C4AulScriptEngine():
|
||||
|
@ -204,21 +216,6 @@ void C4AulScriptEngine::Clear()
|
|||
GlobalNamed.SetNameList(&GlobalNamedNames);
|
||||
}
|
||||
|
||||
|
||||
void C4AulScriptEngine::UnLink()
|
||||
{
|
||||
// unlink scripts
|
||||
for (C4ScriptHost *s = Child0; s; s = s->Next)
|
||||
s->UnLink();
|
||||
C4AulScript::UnLink();
|
||||
// Do not clear global variables and constants, because they are registered by the
|
||||
// preparser or other parts. Note that keeping those fields means that you cannot delete a global
|
||||
// variable or constant at runtime by removing it from the script.
|
||||
//GlobalNamedNames.Reset();
|
||||
//GlobalConstNames.Reset();
|
||||
}
|
||||
|
||||
|
||||
void C4AulScriptEngine::RegisterGlobalConstant(const char *szName, const C4Value &rValue)
|
||||
{
|
||||
// Register name and set value.
|
||||
|
|
|
@ -186,6 +186,7 @@ class C4AulScriptFunc : public C4AulFunc
|
|||
{
|
||||
public:
|
||||
C4AulFunc *OwnerOverloaded; // overloaded owner function; if present
|
||||
void SetOverloaded(C4AulFunc *);
|
||||
C4AulScriptFunc *SFunc() { return this; } // type check func...
|
||||
protected:
|
||||
int CodePos; // code pos
|
||||
|
@ -201,9 +202,9 @@ public:
|
|||
|
||||
C4AulScriptFunc(C4AulScript *pOwner, C4ScriptHost *pOrgScript, const char *pName, const char *Script);
|
||||
C4AulScriptFunc(C4AulScript *pOwner, const C4AulScriptFunc &FromFunc); // copy script/code, etc from given func
|
||||
~C4AulScriptFunc();
|
||||
|
||||
void ParseFn(C4AulScriptContext* context = NULL);
|
||||
virtual void UnLink();
|
||||
|
||||
virtual bool GetPublic() { return true; }
|
||||
virtual int GetParCount() { return ParCount; }
|
||||
|
|
|
@ -750,8 +750,6 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
if (!pFunc)
|
||||
throw new C4AulExecError(FormatString("'->': no function \"%s\" in object \"%s\"", pCPos->Par.s->GetCStr(), pTargetVal->GetDataString().getData()).getData());
|
||||
|
||||
assert(!pFunc->OverloadedBy);
|
||||
|
||||
// Save current position
|
||||
pCurCtx->CPos = pCPos;
|
||||
assert(pCurCtx->Func->GetCode() <= pCPos);
|
||||
|
|
|
@ -25,8 +25,7 @@
|
|||
C4AulFunc::C4AulFunc(C4AulScript *pOwner, const char *pName):
|
||||
iRefCnt(0),
|
||||
Name(pName ? Strings.RegString(pName) : 0),
|
||||
MapNext(NULL),
|
||||
OverloadedBy (NULL)
|
||||
MapNext(NULL)
|
||||
{
|
||||
AppendToScript(pOwner);
|
||||
IncRef(); // see C4AulScript::Clear()
|
||||
|
|
|
@ -77,8 +77,6 @@ protected:
|
|||
virtual ~C4AulFunc();
|
||||
|
||||
public:
|
||||
C4AulFunc *OverloadedBy; // function by which this one is overloaded
|
||||
|
||||
virtual C4AulScriptFunc *SFunc() { return NULL; } // type check func...
|
||||
|
||||
// Wether this function should be visible to players
|
||||
|
@ -91,7 +89,6 @@ public:
|
|||
return Exec(p, pPars->Par, fPassErrors);
|
||||
}
|
||||
virtual C4Value Exec(C4PropList * p, C4Value pPars[], bool fPassErrors=false) = 0;
|
||||
virtual void UnLink() { OverloadedBy = NULL; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -116,26 +116,17 @@ bool C4ScriptHost::ResolveIncludes(C4DefList *rDefs)
|
|||
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));
|
||||
}
|
||||
}
|
||||
|
||||
void C4ScriptHost::UnLink()
|
||||
{
|
||||
// do not unlink temporary (e.g., DirectExec-script in ReloadDef)
|
||||
if (Temporary) return;
|
||||
|
||||
C4PropList * p = GetPropList();
|
||||
if (p) p->C4PropList::Thaw();
|
||||
if (p)
|
||||
{
|
||||
p->C4PropList::Clear();
|
||||
p->SetProperty(P_Prototype, C4VPropList(Engine->GetPropList()));
|
||||
}
|
||||
|
||||
// delete included/appended functions
|
||||
C4AulFunc* pFunc = FuncL;
|
||||
|
@ -143,17 +134,6 @@ void C4ScriptHost::UnLink()
|
|||
{
|
||||
C4AulFunc* pNextFunc = pFunc->Prev;
|
||||
|
||||
// clear stuff that's set in LinkFunctions
|
||||
pFunc->UnLink();
|
||||
C4Value v;
|
||||
if (p && p->GetFunc(pFunc->Name) == pFunc && pFunc->SFunc())
|
||||
{
|
||||
p->ResetProperty(pFunc->Name);
|
||||
C4AulFunc * overloaded = pFunc->SFunc()->OwnerOverloaded;
|
||||
if (overloaded && overloaded != p->GetFunc(pFunc->Name))
|
||||
p->SetPropertyByS(pFunc->Name, C4VFunction(overloaded));
|
||||
}
|
||||
|
||||
if (pFunc->SFunc() && pFunc->Owner != Engine && pFunc->Owner != pFunc->SFunc()->pOrgScript)
|
||||
{
|
||||
pFunc->RemoveFromScript();
|
||||
|
@ -169,11 +149,18 @@ void C4ScriptHost::UnLink()
|
|||
if (State > ASS_PREPARSED) State = ASS_PREPARSED;
|
||||
}
|
||||
|
||||
void C4AulScriptFunc::UnLink()
|
||||
void C4AulScriptEngine::UnLink()
|
||||
{
|
||||
OwnerOverloaded = NULL;
|
||||
|
||||
C4AulFunc::UnLink();
|
||||
// unlink scripts
|
||||
for (C4ScriptHost *s = Child0; s; s = s->Next)
|
||||
s->UnLink();
|
||||
GetPropList()->Thaw();
|
||||
if (State > ASS_PREPARSED) State = ASS_PREPARSED;
|
||||
// Do not clear global variables and constants, because they are registered by the
|
||||
// preparser or other parts. Note that keeping those fields means that you cannot delete a global
|
||||
// variable or constant at runtime by removing it from the script.
|
||||
//GlobalNamedNames.Reset();
|
||||
//GlobalConstNames.Reset();
|
||||
}
|
||||
|
||||
bool C4AulScript::ReloadScript(const char *szPath, const char *szLanguage)
|
||||
|
@ -194,9 +181,6 @@ void C4AulScriptEngine::Link(C4DefList *rDefs)
|
|||
for (C4ScriptHost *s = Child0; s; s = s->Next)
|
||||
s->ResolveIncludes(rDefs);
|
||||
|
||||
// put script functions into the proplist
|
||||
LinkFunctions();
|
||||
|
||||
// parse the scripts to byte code
|
||||
for (C4ScriptHost *s = Child0; s; s = s->Next)
|
||||
s->Parse();
|
||||
|
|
|
@ -770,11 +770,9 @@ bool C4ScriptHost::Preparse()
|
|||
// clear stuff
|
||||
Includes.clear(); Appends.clear();
|
||||
|
||||
if (GetPropList())
|
||||
{
|
||||
GetPropList()->C4PropList::Clear();
|
||||
GetPropList()->SetProperty(P_Prototype, C4VPropList(Engine->GetPropList()));
|
||||
}
|
||||
GetPropList()->C4PropList::Clear();
|
||||
GetPropList()->SetProperty(P_Prototype, C4VPropList(Engine->GetPropList()));
|
||||
LocalValues.Clear();
|
||||
|
||||
// reset code
|
||||
ClearCode();
|
||||
|
@ -785,6 +783,9 @@ bool C4ScriptHost::Preparse()
|
|||
// #include will have to be resolved now...
|
||||
IncludesResolved = false;
|
||||
|
||||
// Parse will write the properties back after the ones from included scripts
|
||||
GetPropList()->Properties.Swap(&LocalValues);
|
||||
|
||||
// return success
|
||||
C4AulScript::State = ASS_PREPARSED;
|
||||
return true;
|
||||
|
@ -1389,22 +1390,24 @@ void C4AulParse::Parse_Function()
|
|||
else
|
||||
owner = a;
|
||||
Fn = 0;
|
||||
C4AulFunc * f = owner->Func0;
|
||||
C4AulFunc * f = owner->GetPropList()->GetFunc(Idtf);
|
||||
while (f)
|
||||
{
|
||||
if (SEqual(f->GetName(), Idtf) && f->SFunc() && f->SFunc()->pOrgScript == pOrgScript)
|
||||
if (f->SFunc() && f->SFunc()->pOrgScript == pOrgScript && f->Owner == owner)
|
||||
{
|
||||
if (Fn)
|
||||
//throw new C4AulParseError(this, "Duplicate function ", Idtf);
|
||||
Warn("Duplicate function %s", Idtf);
|
||||
Fn = f->SFunc();
|
||||
}
|
||||
f = f->Next;
|
||||
f = f->SFunc() ? f->SFunc()->OwnerOverloaded : 0;
|
||||
}
|
||||
// first preparser run or a new func in a reloaded script
|
||||
if (!Fn && Type == PREPARSER)
|
||||
{
|
||||
Fn = new C4AulScriptFunc(owner, pOrgScript, Idtf, SPos);
|
||||
Fn->SetOverloaded(owner->GetPropList()->GetFunc(Fn->Name));
|
||||
owner->GetPropList()->SetPropertyByS(Fn->Name, C4VFunction(Fn));
|
||||
}
|
||||
assert(Fn);
|
||||
if (Type == PARSER)
|
||||
|
@ -1898,8 +1901,9 @@ C4Value C4AulParse::Parse_ConstPropList(const C4PropListStatic * parent, C4Strin
|
|||
throw new C4AulParseError(this, "internal error: constant proplist is not static");
|
||||
if (p->GetParent() != parent || p->GetParentKeyName() != Name)
|
||||
{
|
||||
// the proplist was overwritten by one in another script
|
||||
// create a temporary replacement
|
||||
// the proplist is from another definition, so don't change it
|
||||
// create a replacement for this defnition
|
||||
// FIXME: shouldn't the copy be made in parse, like functions are handled?
|
||||
v.SetPropList(C4PropList::NewAnon(NULL, parent, Name));
|
||||
p = v.getPropList()->IsStatic();
|
||||
}
|
||||
|
@ -2921,8 +2925,34 @@ bool C4ScriptHost::Parse()
|
|||
}
|
||||
Func0 = FuncL = 0;
|
||||
|
||||
C4PropList * p = GetPropList();
|
||||
|
||||
for (std::list<C4ScriptHost *>::iterator s = SourceScripts.begin(); s != SourceScripts.end(); ++s)
|
||||
{
|
||||
// append all funcs and local variable initializations
|
||||
const C4Property * prop = (*s)->LocalValues.First();
|
||||
while (prop)
|
||||
{
|
||||
switch(prop->Value.GetType())
|
||||
{
|
||||
case C4V_Function:
|
||||
{
|
||||
C4AulScriptFunc * sf = prop->Value.getFunction()->SFunc();
|
||||
assert(sf->pOrgScript == *s);
|
||||
C4AulScriptFunc *sfc;
|
||||
if (sf->pOrgScript != this)
|
||||
sfc = new C4AulScriptFunc(this, *sf);
|
||||
else
|
||||
sfc = sf;
|
||||
sfc->SetOverloaded(p->GetFunc(sf->Name));
|
||||
p->SetPropertyByS(prop->Key, C4VFunction(sfc));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
p->SetPropertyByS(prop->Key, prop->Value);
|
||||
}
|
||||
prop = (*s)->LocalValues.Next(prop);
|
||||
}
|
||||
if (*s == this)
|
||||
{
|
||||
C4AulFunc *f = thisfuncs, *n;
|
||||
|
@ -2937,22 +2967,11 @@ bool C4ScriptHost::Parse()
|
|||
// 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)
|
||||
// funcs from other scripts get appended directly from their script
|
||||
if ((sf = f->SFunc()) && sf->pOrgScript == *s)
|
||||
{
|
||||
// append: create copy
|
||||
C4AulScriptFunc *sfc = new C4AulScriptFunc(this, *sf);
|
||||
}
|
||||
// copy local var definitions
|
||||
for (int ivar = 0; ivar < (*s)->LocalNamed.iSize; ivar ++)
|
||||
LocalNamed.AddName((*s)->LocalNamed.pNames[ivar]);
|
||||
}
|
||||
|
||||
LinkFunctions();
|
||||
|
||||
// parse
|
||||
C4AulParse state(this, C4AulParse::PARSER);
|
||||
for (std::list<C4ScriptHost *>::iterator s = SourceScripts.begin(); s != SourceScripts.end(); ++s)
|
||||
|
|
|
@ -126,6 +126,7 @@ private:
|
|||
C4Set<C4Property> Properties;
|
||||
C4PropList * prototype;
|
||||
bool constant; // if true, this proplist is not changeable
|
||||
friend class C4ScriptHost;
|
||||
public:
|
||||
int32_t Status;
|
||||
};
|
||||
|
|
|
@ -215,6 +215,18 @@ public:
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
void Swap(C4Set<T> * S2)
|
||||
{
|
||||
unsigned int Capacity2 = S2->Capacity;
|
||||
unsigned int Size2 = S2->Size;
|
||||
T * Table2 = S2->Table;
|
||||
S2->Capacity = Capacity;
|
||||
S2->Size = Size;
|
||||
S2->Table = Table;
|
||||
Capacity = Capacity2;
|
||||
Size = Size2;
|
||||
Table = Table2;
|
||||
}
|
||||
};
|
||||
|
||||
template<> template<>
|
||||
|
|
Loading…
Reference in New Issue