forked from Mirrors/openclonk
Merge branch script
commit
b54ddc7663
|
@ -467,20 +467,14 @@ set(OC_CLONK_SOURCES
|
|||
src/game/C4FullScreen.h
|
||||
src/game/C4Game.cpp
|
||||
src/game/C4Game.h
|
||||
src/game/C4GameScript.cpp
|
||||
src/game/C4GameScript.h
|
||||
src/game/C4GameVersion.h
|
||||
src/game/C4GraphicsSystem.cpp
|
||||
src/game/C4GraphicsSystem.h
|
||||
src/game/C4Physics.h
|
||||
src/game/C4Viewport.cpp
|
||||
src/game/C4Viewport.h
|
||||
src/gamescript/C4Effect.cpp
|
||||
src/gamescript/C4Effect.h
|
||||
src/gamescript/C4FindObject.cpp
|
||||
src/gamescript/C4FindObject.h
|
||||
src/gamescript/C4GameScript.cpp
|
||||
src/gamescript/C4GameScript.h
|
||||
src/gamescript/C4TransferZone.cpp
|
||||
src/gamescript/C4TransferZone.h
|
||||
src/graphics/Bitmap256.cpp
|
||||
src/graphics/Bitmap256.h
|
||||
src/graphics/C4Draw.cpp
|
||||
|
@ -627,6 +621,8 @@ set(OC_CLONK_SOURCES
|
|||
src/landscape/C4Texture.h
|
||||
src/landscape/C4TextureShape.cpp
|
||||
src/landscape/C4TextureShape.h
|
||||
src/landscape/C4TransferZone.cpp
|
||||
src/landscape/C4TransferZone.h
|
||||
src/landscape/C4Weather.cpp
|
||||
src/landscape/C4Weather.h
|
||||
src/lib/C4LogBuf.cpp
|
||||
|
@ -697,6 +693,8 @@ set(OC_CLONK_SOURCES
|
|||
src/object/C4Def.h
|
||||
src/object/C4DefList.cpp
|
||||
src/object/C4DefList.h
|
||||
src/object/C4FindObject.cpp
|
||||
src/object/C4FindObject.h
|
||||
src/object/C4GameObjects.cpp
|
||||
src/object/C4GameObjects.h
|
||||
src/object/C4Id.cpp
|
||||
|
@ -1057,6 +1055,8 @@ src/script/C4AulLink.cpp
|
|||
src/script/C4AulParse.cpp
|
||||
src/script/C4AulScriptFunc.cpp
|
||||
src/script/C4AulScriptFunc.h
|
||||
src/script/C4Effect.cpp
|
||||
src/script/C4Effect.h
|
||||
src/script/C4PropList.cpp
|
||||
src/script/C4PropList.h
|
||||
src/script/C4Script.cpp
|
||||
|
|
|
@ -28,7 +28,6 @@ class C4AulDefFunc;
|
|||
class C4AulExec;
|
||||
class C4AulFunc;
|
||||
struct C4AulParSet;
|
||||
class C4AulScript;
|
||||
struct C4AulScriptContext;
|
||||
class C4AulScriptEngine;
|
||||
class C4AulScriptFunc;
|
||||
|
|
|
@ -356,7 +356,7 @@ C4Value C4GameObjects::GRBroadcast(const char *szFunction, C4AulParSet *pPars, b
|
|||
for (C4Object *pObj : *this)
|
||||
if (pObj && (pObj->Category & (C4D_Goal | C4D_Rule | C4D_Environment)) && pObj->Status)
|
||||
{
|
||||
C4Value vResult = pObj->Call(szFunction, pPars/*, fPassError*/);
|
||||
C4Value vResult = pObj->Call(szFunction, pPars, fPassError);
|
||||
// rejection tests abort on first nonzero result
|
||||
if (fRejectTest && !!vResult) return vResult;
|
||||
}
|
||||
|
|
|
@ -41,86 +41,12 @@ const char *C4AulError::what() const noexcept
|
|||
return sMessage ? sMessage.getData() : "(unknown error)";
|
||||
}
|
||||
|
||||
C4AulScript::C4AulScript()
|
||||
{
|
||||
// not compiled
|
||||
State = ASS_NONE;
|
||||
|
||||
// prepare lists
|
||||
Prev = Next = NULL;
|
||||
Engine = NULL;
|
||||
}
|
||||
|
||||
C4AulScript::~C4AulScript()
|
||||
{
|
||||
// clear
|
||||
Clear();
|
||||
// unreg
|
||||
Unreg();
|
||||
}
|
||||
|
||||
|
||||
void C4AulScript::Unreg()
|
||||
{
|
||||
// remove from list
|
||||
if (Prev) Prev->Next = Next; else if (Engine) Engine->Child0 = Next;
|
||||
if (Next) Next->Prev = Prev; else if (Engine) Engine->ChildL = Prev;
|
||||
Prev = Next = NULL;
|
||||
Engine = NULL;
|
||||
}
|
||||
|
||||
|
||||
void C4AulScript::Clear()
|
||||
{
|
||||
// reset flags
|
||||
State = ASS_NONE;
|
||||
}
|
||||
|
||||
|
||||
void C4AulScript::Reg2List(C4AulScriptEngine *pEngine)
|
||||
{
|
||||
// already regged? (def reloaded)
|
||||
if (Engine) return;
|
||||
// reg to list
|
||||
if ((Engine = pEngine))
|
||||
{
|
||||
if ((Prev = Engine->ChildL))
|
||||
Prev->Next = this;
|
||||
else
|
||||
Engine->Child0 = this;
|
||||
Engine->ChildL = this;
|
||||
}
|
||||
else
|
||||
Prev = NULL;
|
||||
Next = NULL;
|
||||
}
|
||||
|
||||
std::string C4AulScript::Translate(const std::string &text) const
|
||||
{
|
||||
try
|
||||
{
|
||||
if (stringTable)
|
||||
return stringTable->Translate(text);
|
||||
}
|
||||
catch (C4LangStringTable::NoSuchTranslation &)
|
||||
{
|
||||
// Ignore, soldier on
|
||||
}
|
||||
if (Engine && Engine != this)
|
||||
return Engine->Translate(text);
|
||||
throw C4LangStringTable::NoSuchTranslation(text);
|
||||
}
|
||||
|
||||
/*--- C4AulScriptEngine ---*/
|
||||
|
||||
C4AulScriptEngine::C4AulScriptEngine():
|
||||
GlobalPropList(C4PropList::NewStatic(NULL, NULL, ::Strings.RegString("Global"))),
|
||||
C4PropListStaticMember(NULL, NULL, ::Strings.RegString("Global")),
|
||||
warnCnt(0), errCnt(0), lineCnt(0)
|
||||
{
|
||||
// /me r b engine
|
||||
Engine = this;
|
||||
ScriptName.Ref(C4CFN_System);
|
||||
|
||||
GlobalNamedNames.Reset();
|
||||
GlobalNamed.Reset();
|
||||
GlobalNamed.SetNameList(&GlobalNamedNames);
|
||||
|
@ -128,12 +54,7 @@ C4AulScriptEngine::C4AulScriptEngine():
|
|||
GlobalConsts.Reset();
|
||||
GlobalConsts.SetNameList(&GlobalConstNames);
|
||||
Child0 = ChildL = NULL;
|
||||
RegisterGlobalConstant("Global", GlobalPropList);
|
||||
}
|
||||
|
||||
C4PropListStatic * C4AulScriptEngine::GetPropList()
|
||||
{
|
||||
return GlobalPropList._getPropList()->IsStatic();
|
||||
RegisterGlobalConstant("Global", C4VPropList(this));
|
||||
}
|
||||
|
||||
C4AulScriptEngine::~C4AulScriptEngine()
|
||||
|
@ -151,9 +72,7 @@ void C4AulScriptEngine::Clear()
|
|||
if (Child0->Delete()) delete Child0;
|
||||
else Child0->Unreg();
|
||||
// clear own stuff
|
||||
GlobalPropList._getPropList()->Clear();
|
||||
// clear inherited
|
||||
C4AulScript::Clear();
|
||||
C4PropListStaticMember::Clear();
|
||||
// reset values
|
||||
warnCnt = errCnt = lineCnt = 0;
|
||||
// resetting name lists will reset all data lists, too
|
||||
|
@ -162,7 +81,7 @@ void C4AulScriptEngine::Clear()
|
|||
GlobalConstNames.Reset();
|
||||
GlobalConsts.Reset();
|
||||
GlobalConsts.SetNameList(&GlobalConstNames);
|
||||
RegisterGlobalConstant("Global", GlobalPropList);
|
||||
RegisterGlobalConstant("Global", C4VPropList(this));
|
||||
GlobalNamed.Reset();
|
||||
GlobalNamed.SetNameList(&GlobalNamedNames);
|
||||
UserFiles.clear();
|
||||
|
@ -190,12 +109,12 @@ bool C4AulScriptEngine::GetGlobalConstant(const char *szName, C4Value *pTargetVa
|
|||
return true;
|
||||
}
|
||||
|
||||
bool C4AulScriptEngine::Denumerate(C4ValueNumbers * numbers)
|
||||
void C4AulScriptEngine::Denumerate(C4ValueNumbers * numbers)
|
||||
{
|
||||
GlobalNamed.Denumerate(numbers);
|
||||
// runtime data only: don't denumerate consts
|
||||
GameScript.ScenPropList.Denumerate(numbers);
|
||||
return true;
|
||||
C4PropListStaticMember::Denumerate(numbers);
|
||||
}
|
||||
|
||||
void C4AulScriptEngine::CompileFunc(StdCompiler *pComp, C4ValueNumbers * numbers)
|
||||
|
@ -291,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;
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ public:
|
|||
class C4AulParseError : public C4AulError
|
||||
{
|
||||
public:
|
||||
C4AulParseError(C4AulScript *pScript, const char *pMsg, const char *pIdtf = NULL, bool Warn = false); // constructor
|
||||
C4AulParseError(C4ScriptHost *pScript, const char *pMsg, const char *pIdtf = NULL, bool Warn = false); // constructor
|
||||
C4AulParseError(class C4AulParse * state, const char *pMsg, const char *pIdtf = NULL, bool Warn = false); // constructor
|
||||
};
|
||||
|
||||
|
@ -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 };
|
||||
|
@ -75,44 +75,6 @@ protected:
|
|||
friend class C4ScriptHost;
|
||||
};
|
||||
|
||||
|
||||
// aul script state
|
||||
enum C4AulScriptState
|
||||
{
|
||||
ASS_ERROR, // erroneous script
|
||||
ASS_NONE, // nothing
|
||||
ASS_PREPARSED, // function list built; CodeSize set
|
||||
ASS_LINKED, // includes and appends resolved
|
||||
ASS_PARSED // byte code generated
|
||||
};
|
||||
|
||||
|
||||
// script profiler entry
|
||||
class C4AulProfiler
|
||||
{
|
||||
private:
|
||||
// map entry
|
||||
struct Entry
|
||||
{
|
||||
C4AulScriptFunc *pFunc;
|
||||
uint32_t tProfileTime;
|
||||
|
||||
bool operator < (const Entry &e2) const { return tProfileTime < e2.tProfileTime ; }
|
||||
};
|
||||
|
||||
// items
|
||||
std::vector<Entry> Times;
|
||||
|
||||
public:
|
||||
void CollectEntry(C4AulScriptFunc *pFunc, uint32_t tProfileTime);
|
||||
void Show();
|
||||
|
||||
static void Abort();
|
||||
static void StartProfiling(C4AulScript *pScript);
|
||||
static void StopProfiling();
|
||||
};
|
||||
|
||||
|
||||
// user text file to which scripts can write using FileWrite().
|
||||
// actually just writes to an internal buffer
|
||||
class C4AulUserFile
|
||||
|
@ -130,68 +92,16 @@ public:
|
|||
int32_t GetHandle() const { return handle; }
|
||||
};
|
||||
|
||||
|
||||
// script class
|
||||
class C4AulScript
|
||||
{
|
||||
public:
|
||||
C4AulScript(); // constructor
|
||||
virtual ~C4AulScript(); // destructor
|
||||
virtual void Clear(); // remove script, byte code and children
|
||||
void Reg2List(C4AulScriptEngine *pEngine); // reg to linked list
|
||||
void Unreg(); // remove from list
|
||||
virtual bool Delete() { return true; } // allow deletion on pure class
|
||||
|
||||
StdCopyStrBuf ScriptName; // script name
|
||||
|
||||
virtual C4PropListStatic * GetPropList() { return 0; }
|
||||
virtual C4ScriptHost * GetScriptHost() { return 0; }
|
||||
|
||||
virtual void ResetProfilerTimes(); // zero all profiler times of owned functions
|
||||
virtual void CollectProfilerTimes(class C4AulProfiler &rProfiler);
|
||||
|
||||
bool IsReady() { return State == ASS_PARSED; } // whether script calls may be done
|
||||
|
||||
// helper functions
|
||||
void Warn(const char *pMsg, ...) GNUC_FORMAT_ATTRIBUTE_O;
|
||||
|
||||
friend class C4AulParseError;
|
||||
friend class C4AulFunc;
|
||||
friend class C4AulScriptFunc;
|
||||
friend class C4AulScriptEngine;
|
||||
friend class C4AulParse;
|
||||
friend class C4AulDebug;
|
||||
friend class C4ScriptHost;
|
||||
|
||||
// Translate a string using the script's lang table
|
||||
std::string Translate(const std::string &text) const;
|
||||
|
||||
protected:
|
||||
C4LangStringTable *stringTable;
|
||||
|
||||
C4AulScriptEngine *Engine; //owning engine
|
||||
C4AulScript *Prev, *Next; // tree structure
|
||||
|
||||
C4AulScriptState State; // script state
|
||||
|
||||
virtual bool ReloadScript(const char *szPath, const char *szLanguage); // reload given script
|
||||
virtual bool Parse();
|
||||
virtual bool ResolveIncludes(C4DefList *rDefs);
|
||||
virtual bool ResolveAppends(C4DefList *rDefs);
|
||||
virtual void UnLink();
|
||||
};
|
||||
|
||||
// holds all C4AulScripts
|
||||
class C4AulScriptEngine : public C4AulScript
|
||||
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); }
|
||||
C4Value GlobalPropList;
|
||||
C4AulScript *Child0, *ChildL; // tree structure
|
||||
C4ScriptHost *Child0, *ChildL; // tree structure
|
||||
|
||||
// all open user files
|
||||
// user files aren't saved - they are just open temporary e.g. during game saving
|
||||
|
@ -216,21 +126,16 @@ public:
|
|||
void Clear(); // clear data
|
||||
void Link(C4DefList *rDefs); // link and parse all scripts
|
||||
void ReLink(C4DefList *rDefs); // unlink, link and parse all scripts
|
||||
virtual C4PropListStatic * GetPropList();
|
||||
C4Value Call(const char * k, C4AulParSet *pPars=0, bool fPassErrors=false)
|
||||
{ return GetPropList()->Call(k, pPars, fPassErrors); }
|
||||
using C4AulScript::ReloadScript;
|
||||
C4PropListStatic * GetPropList() { return this; }
|
||||
bool ReloadScript(const char *szScript, const char *szLanguage); // search script and reload, if found
|
||||
|
||||
// For the list of functions in the PropertyDlg
|
||||
std::list<const char*> GetFunctionNames(C4PropList *);
|
||||
void ResetProfilerTimes(); // zero all profiler times of owned functions
|
||||
void CollectProfilerTimes(class C4AulProfiler &rProfiler);
|
||||
|
||||
void RegisterGlobalConstant(const char *szName, const C4Value &rValue); // creates a new constants or overwrites an old one
|
||||
bool GetGlobalConstant(const char *szName, C4Value *pTargetValue); // check if a constant exists; assign value to pTargetValue if not NULL
|
||||
|
||||
bool Denumerate(C4ValueNumbers *);
|
||||
void Denumerate(C4ValueNumbers *);
|
||||
void UnLink(); // called when a script is being reloaded (clears string table)
|
||||
|
||||
// Compile scenario script data (without strings and constants)
|
||||
|
@ -242,10 +147,10 @@ public:
|
|||
C4AulUserFile *GetUserFile(int32_t handle); // get user file given by handle
|
||||
|
||||
friend class C4AulFunc;
|
||||
friend class C4AulProfiler;
|
||||
friend class C4ScriptHost;
|
||||
friend class C4AulParse;
|
||||
friend class C4AulDebug;
|
||||
friend class C4AulScript;
|
||||
};
|
||||
|
||||
extern C4AulScriptEngine ScriptEngine;
|
||||
|
|
|
@ -248,7 +248,7 @@ C4AulDebug::ProcessLineResult C4AulDebug::ProcessLine(const StdStrBuf &Line)
|
|||
}
|
||||
else if (SEqualNoCase(szCmd, "LST"))
|
||||
{
|
||||
for (C4AulScript* script = ScriptEngine.Child0; script; script = script->Next)
|
||||
for (C4ScriptHost* script = ScriptEngine.Child0; script; script = script->Next)
|
||||
{
|
||||
SendLine(RelativePath(script->ScriptName));
|
||||
}
|
||||
|
@ -266,14 +266,14 @@ C4AulDebug::ProcessLineResult C4AulDebug::ProcessLine(const StdStrBuf &Line)
|
|||
int line = atoi(&scriptPath[colonPos+1]);
|
||||
scriptPath.erase(colonPos);
|
||||
|
||||
C4AulScript *script;
|
||||
C4ScriptHost *script;
|
||||
for (script = ScriptEngine.Child0; script; script = script->Next)
|
||||
{
|
||||
if (SEqualNoCase(RelativePath(script->ScriptName), scriptPath.c_str()))
|
||||
break;
|
||||
}
|
||||
|
||||
auto sh = script ? script->GetScriptHost() : NULL;
|
||||
auto sh = script;
|
||||
if (sh)
|
||||
{
|
||||
C4AulBCC * found = NULL;
|
||||
|
@ -333,7 +333,7 @@ C4AulDebug::ProcessLineResult C4AulDebug::ProcessLine(const StdStrBuf &Line)
|
|||
}
|
||||
else if ((varIndex = pCtx->Func->VarNamed.GetItemNr(szData)) != -1)
|
||||
{
|
||||
val = &pCtx->Vars[varIndex];
|
||||
val = &pCtx->Pars[pCtx->Func->GetParCount() + varIndex];
|
||||
}
|
||||
}
|
||||
const char* typeName = val ? GetC4VName(val->GetType()) : "any";
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -56,24 +56,23 @@ StdStrBuf C4AulScriptContext::ReturnDump(StdStrBuf Dump)
|
|||
Dump.AppendChar('(');
|
||||
int iNullPars = 0;
|
||||
for (int i = 0; i < Func->GetParCount(); i++)
|
||||
if (Pars + i < Vars)
|
||||
{
|
||||
if (!Pars[i])
|
||||
iNullPars++;
|
||||
else
|
||||
{
|
||||
if (!Pars[i])
|
||||
iNullPars++;
|
||||
else
|
||||
if (i > iNullPars)
|
||||
Dump.AppendChar(',');
|
||||
// Insert missing null parameters
|
||||
while (iNullPars > 0)
|
||||
{
|
||||
if (i > iNullPars)
|
||||
Dump.AppendChar(',');
|
||||
// Insert missing null parameters
|
||||
while (iNullPars > 0)
|
||||
{
|
||||
Dump.Append("0,");
|
||||
iNullPars--;
|
||||
}
|
||||
// Insert parameter
|
||||
Dump.Append(Pars[i].GetDataString());
|
||||
Dump.Append("0,");
|
||||
iNullPars--;
|
||||
}
|
||||
// Insert parameter
|
||||
Dump.Append(Pars[i].GetDataString());
|
||||
}
|
||||
}
|
||||
Dump.AppendChar(')');
|
||||
}
|
||||
else
|
||||
|
@ -146,37 +145,52 @@ void C4AulExec::ClearPointers(C4Object * obj)
|
|||
|
||||
C4Value C4AulExec::Exec(C4AulScriptFunc *pSFunc, C4PropList * p, C4Value *pnPars, bool fPassErrors)
|
||||
{
|
||||
// Push parameters
|
||||
C4Value *pPars = pCurVal + 1;
|
||||
if (pnPars)
|
||||
for (int i = 0; i < C4AUL_MAX_Par; i++)
|
||||
PushValue(pnPars[i]);
|
||||
if (pCurVal + 1 - pPars > pSFunc->GetParCount())
|
||||
PopValues(pCurVal + 1 - pPars - pSFunc->GetParCount());
|
||||
else
|
||||
PushNullVals(pSFunc->GetParCount() - (pCurVal + 1 - pPars));
|
||||
|
||||
// Push a new context
|
||||
C4AulScriptContext ctx;
|
||||
ctx.tTime = 0;
|
||||
ctx.Obj = p;
|
||||
ctx.Return = NULL;
|
||||
ctx.Pars = pPars;
|
||||
ctx.Vars = pCurVal + 1;
|
||||
ctx.Func = pSFunc;
|
||||
ctx.CPos = NULL;
|
||||
PushContext(ctx);
|
||||
|
||||
// Execute
|
||||
return Exec(pSFunc->GetCode(), fPassErrors);
|
||||
}
|
||||
|
||||
C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
||||
{
|
||||
|
||||
// Save start context
|
||||
C4AulScriptContext *pOldCtx = pCurCtx;
|
||||
C4Value *pPars = pCurVal + 1;
|
||||
try
|
||||
{
|
||||
// Push parameters
|
||||
assert(pnPars);
|
||||
for (int i = 0; i < pSFunc->GetParCount(); i++)
|
||||
PushValue(pnPars[i]);
|
||||
|
||||
// Push a new context
|
||||
C4AulScriptContext ctx;
|
||||
ctx.tTime = 0;
|
||||
ctx.Obj = p;
|
||||
ctx.Return = NULL;
|
||||
ctx.Pars = pPars;
|
||||
ctx.Func = pSFunc;
|
||||
ctx.CPos = NULL;
|
||||
PushContext(ctx);
|
||||
|
||||
// Execute
|
||||
return Exec(pSFunc->GetCode());
|
||||
}
|
||||
catch (C4AulError &e)
|
||||
{
|
||||
if(!e.shown) e.show();
|
||||
// Unwind stack
|
||||
while (pCurCtx > pOldCtx)
|
||||
{
|
||||
pCurCtx->dump(StdStrBuf(" by: "));
|
||||
PopContext();
|
||||
}
|
||||
PopValuesUntil(pPars - 1);
|
||||
// Pass?
|
||||
if (fPassErrors)
|
||||
throw;
|
||||
// Trace
|
||||
LogCallStack();
|
||||
}
|
||||
|
||||
// Return nothing
|
||||
return C4VNull;
|
||||
}
|
||||
|
||||
C4Value C4AulExec::Exec(C4AulBCC *pCPos)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
|
@ -231,14 +245,10 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
case AB_ERR:
|
||||
throw C4AulExecError("syntax error: see above for details");
|
||||
|
||||
case AB_PARN_CONTEXT:
|
||||
case AB_DUP_CONTEXT:
|
||||
PushValue(AulExec.GetContext(AulExec.GetContextDepth()-2)->Pars[pCPos->Par.i]);
|
||||
break;
|
||||
|
||||
case AB_VARN_CONTEXT:
|
||||
PushValue(AulExec.GetContext(AulExec.GetContextDepth()-2)->Vars[pCPos->Par.i]);
|
||||
break;
|
||||
|
||||
case AB_LOCALN:
|
||||
if (!pCurCtx->Obj)
|
||||
throw C4AulExecError("can't access local variables without this");
|
||||
|
@ -717,7 +727,7 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
if (pCurVal->_getInt() >= pArray->GetSize())
|
||||
break;
|
||||
// Get next
|
||||
pCurCtx->Vars[pCPos->Par.i] = pArray->GetItem(iItem);
|
||||
pCurVal[pCPos->Par.i] = pArray->GetItem(iItem);
|
||||
// Save position
|
||||
pCurVal->SetInt(iItem + 1);
|
||||
// Jump over next instruction
|
||||
|
@ -792,29 +802,11 @@ C4Value C4AulExec::Exec(C4AulBCC *pCPos, bool fPassErrors)
|
|||
}
|
||||
catch (C4AulError &e)
|
||||
{
|
||||
if(!e.shown) e.show();
|
||||
// Save current position
|
||||
assert(pCurCtx->Func->GetCode() <= pCPos);
|
||||
pCurCtx->CPos = pCPos;
|
||||
// Unwind stack
|
||||
C4Value *pUntil = NULL;
|
||||
while (pCurCtx >= pOldCtx)
|
||||
{
|
||||
pCurCtx->dump(StdStrBuf(" by: "));
|
||||
pUntil = pCurCtx->Pars - 1;
|
||||
PopContext();
|
||||
}
|
||||
if (pUntil)
|
||||
PopValuesUntil(pUntil);
|
||||
// Pass?
|
||||
if (fPassErrors)
|
||||
throw;
|
||||
// Trace
|
||||
LogCallStack();
|
||||
throw;
|
||||
}
|
||||
|
||||
// Return nothing
|
||||
return C4VNull;
|
||||
}
|
||||
|
||||
C4AulBCC *C4AulExec::Call(C4AulFunc *pFunc, C4Value *pReturn, C4Value *pPars, C4PropList *pContext)
|
||||
|
@ -839,7 +831,6 @@ C4AulBCC *C4AulExec::Call(C4AulFunc *pFunc, C4Value *pReturn, C4Value *pPars, C4
|
|||
throw C4AulExecError("using removed object");
|
||||
ctx.Return = pReturn;
|
||||
ctx.Pars = pPars;
|
||||
ctx.Vars = pCurVal + 1;
|
||||
ctx.Func = pSFunc;
|
||||
ctx.CPos = NULL;
|
||||
PushContext(ctx);
|
||||
|
@ -912,33 +903,20 @@ void C4AulExec::StartTrace()
|
|||
iTraceStart = ContextStackSize();
|
||||
}
|
||||
|
||||
void C4AulExec::StartProfiling(C4AulScript *pProfiledScript)
|
||||
void C4AulExec::StartProfiling(C4ScriptHost *pProfiledScript)
|
||||
{
|
||||
// stop previous profiler run
|
||||
if (fProfiling) AbortProfiling();
|
||||
if (fProfiling) StopProfiling();
|
||||
fProfiling = true;
|
||||
// resets profling times and starts recording the times
|
||||
this->pProfiledScript = pProfiledScript;
|
||||
C4TimeMilliseconds tNow = C4TimeMilliseconds::Now();
|
||||
tDirectExecStart = tNow; // in case profiling is started from DirectExec
|
||||
tDirectExecTotal = 0;
|
||||
pProfiledScript->ResetProfilerTimes();
|
||||
for (C4AulScriptContext *pCtx = Contexts; pCtx <= pCurCtx; ++pCtx)
|
||||
pCtx->tTime = tNow;
|
||||
}
|
||||
|
||||
void C4AulExec::StopProfiling()
|
||||
{
|
||||
// stop the profiler and displays results
|
||||
if (!fProfiling) return;
|
||||
fProfiling = false;
|
||||
// collect profiler times
|
||||
C4AulProfiler Profiler;
|
||||
Profiler.CollectEntry(NULL, tDirectExecTotal);
|
||||
pProfiledScript->CollectProfilerTimes(Profiler);
|
||||
Profiler.Show();
|
||||
}
|
||||
|
||||
void C4AulExec::PushContext(const C4AulScriptContext &rContext)
|
||||
{
|
||||
if (pCurCtx >= Contexts + MAX_CONTEXT_STACK - 1)
|
||||
|
@ -977,19 +955,27 @@ void C4AulExec::PopContext()
|
|||
pCurCtx--;
|
||||
}
|
||||
|
||||
void C4AulProfiler::StartProfiling(C4AulScript *pScript)
|
||||
void C4AulProfiler::StartProfiling(C4ScriptHost *pScript)
|
||||
{
|
||||
AulExec.StartProfiling(pScript);
|
||||
if(pScript)
|
||||
ResetTimes(pScript->GetPropList());
|
||||
else
|
||||
ResetTimes();
|
||||
}
|
||||
|
||||
void C4AulProfiler::StopProfiling()
|
||||
{
|
||||
if (!AulExec.IsProfiling()) return;
|
||||
AulExec.StopProfiling();
|
||||
}
|
||||
|
||||
void C4AulProfiler::Abort()
|
||||
{
|
||||
AulExec.AbortProfiling();
|
||||
// collect profiler times
|
||||
C4AulProfiler Profiler;
|
||||
Profiler.CollectEntry(NULL, AulExec.tDirectExecTotal);
|
||||
if(AulExec.pProfiledScript)
|
||||
Profiler.CollectTimes(AulExec.pProfiledScript->GetPropList());
|
||||
else
|
||||
Profiler.CollectTimes();
|
||||
Profiler.Show();
|
||||
}
|
||||
|
||||
void C4AulProfiler::CollectEntry(C4AulScriptFunc *pFunc, uint32_t tProfileTime)
|
||||
|
@ -1032,65 +1018,66 @@ C4Value C4AulExec::DirectExec(C4PropList *p, const char *szScript, const char *s
|
|||
#endif
|
||||
// profiler
|
||||
StartDirectExec();
|
||||
C4AulScript * script = &::GameScript;
|
||||
if (p == ::ScriptEngine.GetPropList())
|
||||
script = &::ScriptEngine;
|
||||
C4PropListStatic * script = ::GameScript.GetPropList();
|
||||
if (p && p->IsStatic())
|
||||
script = p->IsStatic();
|
||||
else if (p && p->GetDef())
|
||||
script = &p->GetDef()->Script;
|
||||
script = p->GetDef();
|
||||
// Add a new function
|
||||
C4AulScriptFunc *pFunc = new C4AulScriptFunc(script->GetPropList(), script->GetScriptHost(), 0, szScript);
|
||||
auto pFunc = std::make_unique<C4AulScriptFunc>(script, nullptr, nullptr, szScript);
|
||||
// Parse function
|
||||
try
|
||||
{
|
||||
pFunc->ParseFn(context);
|
||||
C4Value vRetVal(Exec(pFunc, p, NULL, fPassErrors));
|
||||
delete pFunc; pFunc = 0;
|
||||
pFunc->ParseFn(&::ScriptEngine, context);
|
||||
C4AulParSet Pars;
|
||||
C4Value vRetVal(Exec(pFunc.get(), p, Pars.Par, fPassErrors));
|
||||
// profiler
|
||||
StopDirectExec();
|
||||
return vRetVal;
|
||||
}
|
||||
catch (C4AulError &ex)
|
||||
{
|
||||
delete pFunc;
|
||||
if(fPassErrors)
|
||||
throw;
|
||||
ex.show();
|
||||
LogCallStack();
|
||||
StopDirectExec();
|
||||
return C4VNull;
|
||||
}
|
||||
}
|
||||
|
||||
void C4AulScript::ResetProfilerTimes()
|
||||
void C4AulProfiler::ResetTimes(C4PropListStatic * p)
|
||||
{
|
||||
// zero all profiler times of owned functions
|
||||
C4AulScriptFunc *pSFunc;
|
||||
for (C4String *pFn = GetPropList()->EnumerateOwnFuncs(); pFn; pFn = GetPropList()->EnumerateOwnFuncs(pFn))
|
||||
if ((pSFunc = GetPropList()->GetFunc(pFn)->SFunc()))
|
||||
for (C4String *pFn = p->EnumerateOwnFuncs(); pFn; pFn = p->EnumerateOwnFuncs(pFn))
|
||||
if ((pSFunc = p->GetFunc(pFn)->SFunc()))
|
||||
pSFunc->tProfileTime = 0;
|
||||
}
|
||||
|
||||
void C4AulScript::CollectProfilerTimes(C4AulProfiler &rProfiler)
|
||||
void C4AulProfiler::CollectTimes(C4PropListStatic * p)
|
||||
{
|
||||
// collect all profiler times of owned functions
|
||||
C4AulScriptFunc *pSFunc;
|
||||
for (C4String *pFn = GetPropList()->EnumerateOwnFuncs(); pFn; pFn = GetPropList()->EnumerateOwnFuncs(pFn))
|
||||
if ((pSFunc = GetPropList()->GetFunc(pFn)->SFunc()))
|
||||
rProfiler.CollectEntry(pSFunc, pSFunc->tProfileTime);
|
||||
for (C4String *pFn = p->EnumerateOwnFuncs(); pFn; pFn = p->EnumerateOwnFuncs(pFn))
|
||||
if ((pSFunc = p->GetFunc(pFn)->SFunc()))
|
||||
CollectEntry(pSFunc, pSFunc->tProfileTime);
|
||||
}
|
||||
|
||||
void C4AulScriptEngine::ResetProfilerTimes()
|
||||
void C4AulProfiler::ResetTimes()
|
||||
{
|
||||
// zero all profiler times of owned functions
|
||||
C4AulScript::ResetProfilerTimes();
|
||||
ResetTimes(::ScriptEngine.GetPropList());
|
||||
// reset sub-scripts
|
||||
for (C4AulScript *pScript = Child0; pScript; pScript = pScript->Next)
|
||||
pScript->ResetProfilerTimes();
|
||||
for (C4ScriptHost *pScript = ::ScriptEngine.Child0; pScript; pScript = pScript->Next)
|
||||
ResetTimes(pScript->GetPropList());
|
||||
}
|
||||
|
||||
void C4AulScriptEngine::CollectProfilerTimes(C4AulProfiler &rProfiler)
|
||||
void C4AulProfiler::CollectTimes()
|
||||
{
|
||||
// collect all profiler times of owned functions
|
||||
C4AulScript::CollectProfilerTimes(rProfiler);
|
||||
CollectTimes(::ScriptEngine.GetPropList());
|
||||
// collect sub-scripts
|
||||
for (C4AulScript *pScript = Child0; pScript; pScript = pScript->Next)
|
||||
pScript->CollectProfilerTimes(rProfiler);
|
||||
for (C4ScriptHost *pScript = ::ScriptEngine.Child0; pScript; pScript = pScript->Next)
|
||||
CollectTimes(pScript->GetPropList());
|
||||
}
|
||||
|
|
|
@ -43,7 +43,6 @@ struct C4AulScriptContext
|
|||
C4PropList *Obj;
|
||||
C4Value *Return;
|
||||
C4Value *Pars;
|
||||
C4Value *Vars;
|
||||
C4AulScriptFunc *Func;
|
||||
C4AulBCC *CPos;
|
||||
C4TimeMilliseconds tTime; // initialized only by profiler if active
|
||||
|
@ -68,20 +67,20 @@ private:
|
|||
bool fProfiling;
|
||||
C4TimeMilliseconds tDirectExecStart;
|
||||
uint32_t tDirectExecTotal; // profiler time for DirectExec
|
||||
C4AulScript *pProfiledScript;
|
||||
C4ScriptHost *pProfiledScript;
|
||||
|
||||
C4AulScriptContext Contexts[MAX_CONTEXT_STACK];
|
||||
C4Value Values[MAX_VALUE_STACK];
|
||||
|
||||
void StartProfiling(C4ScriptHost *pScript); // starts recording the times
|
||||
bool IsProfiling() { return fProfiling; }
|
||||
void StopProfiling() { fProfiling=false; }
|
||||
friend class C4AulProfiler;
|
||||
public:
|
||||
C4Value Exec(C4AulScriptFunc *pSFunc, C4PropList * p, C4Value pPars[], bool fPassErrors);
|
||||
C4Value Exec(C4AulBCC *pCPos, bool fPassErrors);
|
||||
C4Value DirectExec(C4PropList *p, const char *szScript, const char *szContext, bool fPassErrors = false, C4AulScriptContext* context = NULL);
|
||||
|
||||
void StartTrace();
|
||||
void StartProfiling(C4AulScript *pScript); // resets profling times and starts recording the times
|
||||
void StopProfiling(); // stop the profiler and displays results
|
||||
void AbortProfiling() { fProfiling=false; }
|
||||
inline void StartDirectExec() { if (fProfiling) tDirectExecStart = C4TimeMilliseconds::Now(); }
|
||||
inline void StopDirectExec() { if (fProfiling) tDirectExecTotal += C4TimeMilliseconds::Now() - tDirectExecStart; }
|
||||
|
||||
|
@ -93,6 +92,7 @@ public:
|
|||
void ClearPointers(C4Object *);
|
||||
|
||||
private:
|
||||
C4Value Exec(C4AulBCC *pCPos);
|
||||
void PushContext(const C4AulScriptContext &rContext);
|
||||
void PopContext();
|
||||
|
||||
|
@ -184,7 +184,7 @@ private:
|
|||
int LocalValueStackSize() const
|
||||
{
|
||||
return ContextStackSize()
|
||||
? pCurVal - pCurCtx->Vars - pCurCtx->Func->VarNamed.iSize + 1
|
||||
? pCurVal - pCurCtx->Pars - pCurCtx->Func->GetParCount() - pCurCtx->Func->VarNamed.iSize + 1
|
||||
: pCurVal - Values + 1;
|
||||
}
|
||||
|
||||
|
@ -231,4 +231,32 @@ private:
|
|||
|
||||
extern C4AulExec AulExec;
|
||||
|
||||
// script profiler entry
|
||||
class C4AulProfiler
|
||||
{
|
||||
private:
|
||||
// map entry
|
||||
struct Entry
|
||||
{
|
||||
C4AulScriptFunc *pFunc;
|
||||
uint32_t tProfileTime;
|
||||
|
||||
bool operator < (const Entry &e2) const { return tProfileTime < e2.tProfileTime ; }
|
||||
};
|
||||
|
||||
// items
|
||||
std::vector<Entry> Times;
|
||||
|
||||
void CollectEntry(C4AulScriptFunc *pFunc, uint32_t tProfileTime);
|
||||
void CollectTimes(C4PropListStatic * p);
|
||||
void CollectTimes();
|
||||
static void ResetTimes(C4PropListStatic * p);
|
||||
static void ResetTimes();
|
||||
void Show();
|
||||
public:
|
||||
static void Abort() { AulExec.StopProfiling(); }
|
||||
static void StartProfiling(C4ScriptHost *pScript); // reset times and start collecting new ones
|
||||
static void StopProfiling(); // stop the profiler and displays results
|
||||
};
|
||||
|
||||
#endif // C4AULEXEC_H
|
||||
|
|
|
@ -46,7 +46,6 @@ struct C4AulParSet
|
|||
// base function class
|
||||
class C4AulFunc: public C4RefCnt
|
||||
{
|
||||
friend class C4AulScript;
|
||||
friend class C4AulScriptEngine;
|
||||
friend class C4AulFuncMap;
|
||||
friend class C4AulParse;
|
||||
|
|
|
@ -24,16 +24,6 @@
|
|||
#include <C4Game.h>
|
||||
#include <C4GameObjects.h>
|
||||
|
||||
bool C4AulScript::ResolveIncludes(C4DefList *rDefs)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool C4AulScript::ResolveAppends(C4DefList *rDefs)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// ResolveAppends and ResolveIncludes must be called both
|
||||
// for each script. ResolveAppends has to be called first!
|
||||
bool C4ScriptHost::ResolveAppends(C4DefList *rDefs)
|
||||
|
@ -47,8 +37,8 @@ bool C4ScriptHost::ResolveAppends(C4DefList *rDefs)
|
|||
C4Def *Def = rDefs ? rDefs->GetByName(*a) : NULL;
|
||||
if (Def)
|
||||
{
|
||||
if (std::find(Def->Script.SourceScripts.begin(), Def->Script.SourceScripts.end(), GetScriptHost()) == Def->Script.SourceScripts.end())
|
||||
Def->Script.SourceScripts.push_back(GetScriptHost());
|
||||
if (std::find(Def->Script.SourceScripts.begin(), Def->Script.SourceScripts.end(), this) == Def->Script.SourceScripts.end())
|
||||
Def->Script.SourceScripts.push_back(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -67,8 +57,8 @@ bool C4ScriptHost::ResolveAppends(C4DefList *rDefs)
|
|||
if (!pDef) break;
|
||||
if (pDef == GetPropList()) continue;
|
||||
// append
|
||||
if (std::find(pDef->Script.SourceScripts.begin(), pDef->Script.SourceScripts.end(), GetScriptHost()) == pDef->Script.SourceScripts.end())
|
||||
pDef->Script.SourceScripts.push_back(GetScriptHost());
|
||||
if (std::find(pDef->Script.SourceScripts.begin(), pDef->Script.SourceScripts.end(), this) == pDef->Script.SourceScripts.end())
|
||||
pDef->Script.SourceScripts.push_back(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -103,8 +93,8 @@ bool C4ScriptHost::ResolveIncludes(C4DefList *rDefs)
|
|||
|
||||
for (std::list<C4ScriptHost *>::reverse_iterator s = Def->Script.SourceScripts.rbegin(); s != Def->Script.SourceScripts.rend(); ++s)
|
||||
{
|
||||
if (std::find(GetScriptHost()->SourceScripts.begin(), GetScriptHost()->SourceScripts.end(), *s) == GetScriptHost()->SourceScripts.end())
|
||||
GetScriptHost()->SourceScripts.push_front(*s);
|
||||
if (std::find(SourceScripts.begin(), SourceScripts.end(), *s) == SourceScripts.end())
|
||||
SourceScripts.push_front(*s);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -122,11 +112,6 @@ bool C4ScriptHost::ResolveIncludes(C4DefList *rDefs)
|
|||
return true;
|
||||
}
|
||||
|
||||
void C4AulScript::UnLink()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void C4ScriptHost::UnLink()
|
||||
{
|
||||
C4PropList * p = GetPropList();
|
||||
|
@ -147,44 +132,35 @@ void C4AulScriptEngine::UnLink()
|
|||
warnCnt = errCnt = lineCnt = 0;
|
||||
|
||||
// unlink scripts
|
||||
for (C4AulScript *s = Child0; s; s = s->Next)
|
||||
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.
|
||||
}
|
||||
|
||||
bool C4AulScript::ReloadScript(const char *szPath, const char *szLanguage)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void C4AulScriptEngine::Link(C4DefList *rDefs)
|
||||
{
|
||||
try
|
||||
{
|
||||
// resolve appends
|
||||
for (C4AulScript *s = Child0; s; s = s->Next)
|
||||
for (C4ScriptHost *s = Child0; s; s = s->Next)
|
||||
s->ResolveAppends(rDefs);
|
||||
|
||||
// resolve includes
|
||||
for (C4AulScript *s = Child0; s; s = s->Next)
|
||||
for (C4ScriptHost *s = Child0; s; s = s->Next)
|
||||
s->ResolveIncludes(rDefs);
|
||||
|
||||
// parse the scripts to byte code
|
||||
for (C4AulScript *s = Child0; s; s = s->Next)
|
||||
for (C4ScriptHost *s = Child0; s; s = s->Next)
|
||||
s->Parse();
|
||||
|
||||
// engine is always parsed (for global funcs)
|
||||
State = ASS_PARSED;
|
||||
|
||||
if (rDefs)
|
||||
rDefs->CallEveryDefinition();
|
||||
|
||||
// Done modifying the proplists now
|
||||
for (C4AulScript *s = Child0; s; s = s->Next)
|
||||
for (C4ScriptHost *s = Child0; s; s = s->Next)
|
||||
s->GetPropList()->Freeze();
|
||||
GetPropList()->Freeze();
|
||||
}
|
||||
|
@ -217,7 +193,7 @@ void C4AulScriptEngine::ReLink(C4DefList *rDefs)
|
|||
|
||||
bool C4AulScriptEngine::ReloadScript(const char *szScript, const char *szLanguage)
|
||||
{
|
||||
C4AulScript * s;
|
||||
C4ScriptHost * s;
|
||||
for (s = Child0; s; s = s->Next)
|
||||
if (s->ReloadScript(szScript, szLanguage))
|
||||
break;
|
||||
|
|
|
@ -129,11 +129,11 @@ public:
|
|||
iStack(0),
|
||||
pLoopStack(NULL)
|
||||
{ }
|
||||
C4AulParse(C4AulScriptFunc * Fn, C4AulScriptContext* context, enum Type Type):
|
||||
Fn(Fn), Host(Fn->pOrgScript), pOrgScript(Fn->pOrgScript), Engine(pOrgScript->Engine),
|
||||
C4AulParse(C4AulScriptFunc * Fn, C4AulScriptContext* context, C4AulScriptEngine *Engine):
|
||||
Fn(Fn), Host(NULL), pOrgScript(NULL), Engine(Engine),
|
||||
SPos(Fn->Script), TokenSPos(SPos),
|
||||
TokenType(ATT_INVALID),
|
||||
Type(Type),
|
||||
Type(C4AulParse::PARSER),
|
||||
ContextToExecIn(context),
|
||||
fJump(false),
|
||||
iStack(0),
|
||||
|
@ -168,7 +168,6 @@ private:
|
|||
void Parse_For();
|
||||
void Parse_ForEach();
|
||||
void Parse_Expression(int iParentPrio = -1);
|
||||
void Parse_Expression2(int iParentPrio = -1);
|
||||
void Parse_Var();
|
||||
void Parse_Local();
|
||||
void Parse_Static();
|
||||
|
@ -179,12 +178,10 @@ private:
|
|||
|
||||
bool AdvanceSpaces(); // skip whitespaces; return whether script ended
|
||||
int GetOperator(const char* pScript);
|
||||
// Simply discard the string, put it in the Table and delete it with the script or delete it when refcount drops
|
||||
enum OperatorPolicy { OperatorsPlease = 0, StarsPlease };
|
||||
void ClearToken(); // clear any data held with the current token
|
||||
C4AulTokenType GetNextToken(OperatorPolicy Operator = OperatorsPlease); // get next token of SPos
|
||||
C4AulTokenType GetNextToken(); // get next token of SPos
|
||||
|
||||
void Shift(OperatorPolicy Operator = OperatorsPlease);
|
||||
void Shift();
|
||||
void Match(C4AulTokenType TokenType, const char * Expected = NULL);
|
||||
void Check(C4AulTokenType TokenType, const char * Expected = NULL);
|
||||
void UnexpectedToken(const char * Expected) NORETURN;
|
||||
|
@ -231,7 +228,7 @@ private:
|
|||
friend class C4AulParseError;
|
||||
};
|
||||
|
||||
void C4AulScript::Warn(const char *pMsg, ...)
|
||||
void C4ScriptHost::Warn(const char *pMsg, ...)
|
||||
{
|
||||
va_list args; va_start(args, pMsg);
|
||||
StdStrBuf Buf;
|
||||
|
@ -303,7 +300,7 @@ C4AulParseError::C4AulParseError(C4AulParse * state, const char *pMsg, const cha
|
|||
|
||||
}
|
||||
|
||||
C4AulParseError::C4AulParseError(C4AulScript *pScript, const char *pMsg, const char *pIdtf, bool Warn)
|
||||
C4AulParseError::C4AulParseError(C4ScriptHost *pScript, const char *pMsg, const char *pIdtf, bool Warn)
|
||||
{
|
||||
// compose error string
|
||||
sMessage.Format("%s: %s%s",
|
||||
|
@ -466,7 +463,7 @@ void C4AulParse::ClearToken()
|
|||
}
|
||||
}
|
||||
|
||||
C4AulTokenType C4AulParse::GetNextToken(OperatorPolicy Operator)
|
||||
C4AulTokenType C4AulParse::GetNextToken()
|
||||
{
|
||||
// clear mem of prev token
|
||||
ClearToken();
|
||||
|
@ -519,8 +516,6 @@ C4AulTokenType C4AulParse::GetNextToken(OperatorPolicy Operator)
|
|||
{ SPos+=2; return ATT_CALLFS;}// "->~"
|
||||
else if (C == '-' && *SPos == '>')
|
||||
{ ++SPos; return ATT_CALL; } // "->"
|
||||
else if (C == '*' && Operator == StarsPlease)
|
||||
return ATT_STAR; // "*"
|
||||
else if ((cInt = GetOperator(SPos - 1)) != -1)
|
||||
{
|
||||
SPos += SLen(C4ScriptOpMap[cInt].Identifier) - 1;
|
||||
|
@ -641,9 +636,6 @@ static const char * GetTTName(C4AulBCCType e)
|
|||
case AB_THIS: return "THIS";
|
||||
case AB_FUNC: return "FUNC"; // function
|
||||
|
||||
case AB_PARN_CONTEXT: return "AB_PARN_CONTEXT";
|
||||
case AB_VARN_CONTEXT: return "AB_VARN_CONTEXT";
|
||||
|
||||
// prefix
|
||||
case AB_Inc: return "Inc"; // ++
|
||||
case AB_Dec: return "Dec"; // --
|
||||
|
@ -682,6 +674,7 @@ static const char * GetTTName(C4AulBCCType e)
|
|||
case AB_NIL: return "NIL"; // constant: nil
|
||||
case AB_NEW_ARRAY: return "NEW_ARRAY"; // semi-constant: array
|
||||
case AB_DUP: return "DUP"; // duplicate value from stack
|
||||
case AB_DUP_CONTEXT: return "AB_DUP_CONTEXT"; // duplicate value from stack of parent function
|
||||
case AB_NEW_PROPLIST: return "NEW_PROPLIST"; // create a new proplist
|
||||
case AB_POP_TO: return "POP_TO"; // initialization of named var
|
||||
case AB_JUMP: return "JUMP"; // jump
|
||||
|
@ -808,7 +801,7 @@ bool C4ScriptHost::Preparse()
|
|||
GetPropList()->Properties.Swap(&LocalValues);
|
||||
|
||||
// return success
|
||||
C4AulScript::State = ASS_PREPARSED;
|
||||
this->State = ASS_PREPARSED;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -824,11 +817,10 @@ int C4AulParse::GetStackValue(C4AulBCCType eType, intptr_t X)
|
|||
case AB_CARRAY:
|
||||
case AB_CFUNCTION:
|
||||
case AB_NIL:
|
||||
case AB_PARN_CONTEXT:
|
||||
case AB_VARN_CONTEXT:
|
||||
case AB_LOCALN:
|
||||
case AB_GLOBALN:
|
||||
case AB_DUP:
|
||||
case AB_DUP_CONTEXT:
|
||||
case AB_THIS:
|
||||
return 1;
|
||||
|
||||
|
@ -977,6 +969,13 @@ int C4AulParse::AddBCC(C4AulBCCType eType, intptr_t X)
|
|||
return Fn->GetCodePos() - 1;
|
||||
}
|
||||
|
||||
// Join POP_TO + DUP to AB_STACK_SET if both target the same slot
|
||||
if(eType == AB_DUP && pCPos1->bccType == AB_POP_TO && X == pCPos1->Par.i + 1)
|
||||
{
|
||||
pCPos1->bccType = AB_STACK_SET;
|
||||
return Fn->GetCodePos() - 1;
|
||||
}
|
||||
|
||||
// Reduce some constructs like SUM + INT 1 to INC or DEC
|
||||
if((eType == AB_Sum || eType == AB_Sub) &&
|
||||
pCPos1->bccType == AB_INT &&
|
||||
|
@ -990,11 +989,11 @@ int C4AulParse::AddBCC(C4AulBCCType eType, intptr_t X)
|
|||
return Fn->GetCodePos() - 1;
|
||||
}
|
||||
|
||||
// Reduce Not + CONDN to COND
|
||||
if(eType == AB_CONDN && pCPos1->bccType == AB_Not)
|
||||
// Reduce Not + CONDN to COND, Not + COND to CONDN
|
||||
if((eType == AB_CONDN || eType == AB_COND) && pCPos1->bccType == AB_Not)
|
||||
{
|
||||
pCPos1->bccType = AB_COND;
|
||||
pCPos1->Par.i = X;
|
||||
pCPos1->bccType = eType == AB_CONDN ? AB_COND : AB_CONDN;
|
||||
pCPos1->Par.i = X + 1;
|
||||
return Fn->GetCodePos() - 1;
|
||||
}
|
||||
|
||||
|
@ -1013,7 +1012,7 @@ void C4AulParse::RemoveLastBCC()
|
|||
{
|
||||
// Security: This is unsafe on anything that might get optimized away
|
||||
C4AulBCC *pBCC = Fn->GetLastCode();
|
||||
assert(pBCC->bccType != AB_STACK);
|
||||
assert(pBCC->bccType != AB_STACK && pBCC->bccType != AB_STACK_SET && pBCC->bccType != AB_POP_TO);
|
||||
// Correct stack
|
||||
iStack -= GetStackValue(pBCC->bccType, pBCC->Par.X);
|
||||
// Remove
|
||||
|
@ -1036,7 +1035,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)
|
||||
|
@ -1078,6 +1077,7 @@ C4AulBCC C4AulParse::MakeSetter(bool fLeaveValue)
|
|||
// the setter additionally has the new value on the stack
|
||||
--Setter.Par.i;
|
||||
break;
|
||||
case AB_STACK_SET: Setter.bccType = AB_STACK_SET; break;
|
||||
case AB_LOCALN:
|
||||
Setter.bccType = AB_LOCALN_SET;
|
||||
Setter.Par.s->IncRef(); // so string isn't dropped by RemoveLastBCC, see also C4AulScript::AddBCC
|
||||
|
@ -1090,21 +1090,34 @@ C4AulBCC C4AulParse::MakeSetter(bool fLeaveValue)
|
|||
default:
|
||||
throw C4AulParseError(this, "assignment to a constant");
|
||||
}
|
||||
// Remove value BCC
|
||||
RemoveLastBCC();
|
||||
// Want the value?
|
||||
if(fLeaveValue)
|
||||
// If the new value is produced using the old one, the parameters to get the old one need to be duplicated.
|
||||
// Otherwise, the setter can just use the parameters originally meant for the getter.
|
||||
// All getters push one value, so the parameter count is one more than the values they pop from the stack.
|
||||
int iParCount = 1 - GetStackValue(Value.bccType, Value.Par.X);
|
||||
if (Value.bccType == AB_STACK_SET)
|
||||
{
|
||||
// STACK_SET has a side effect, so it can't be simply removed.
|
||||
// Discard the unused value the usual way instead.
|
||||
if (!fLeaveValue)
|
||||
AddBCC(AB_STACK, -1);
|
||||
// The original parameter isn't needed anymore, since in contrast to the other getters
|
||||
// it does not indicate a position.
|
||||
iParCount = 0;
|
||||
}
|
||||
else if (!fLeaveValue || iParCount)
|
||||
{
|
||||
RemoveLastBCC();
|
||||
fJump = true; // In case the original BCC was a jump target
|
||||
}
|
||||
if (fLeaveValue && iParCount)
|
||||
{
|
||||
// Duplicate parameters on stack
|
||||
// (all push one value on the stack as result, so we have -(N-1) parameters)
|
||||
int iParCount = -GetStackValue(Value.bccType, Value.Par.X) + 1;
|
||||
for(int i = 0; i < iParCount; i++)
|
||||
AddBCC(AB_DUP, 1 - iParCount);
|
||||
// Finally re-add original BCC
|
||||
AddBCC(Value.bccType, Value.Par.X);
|
||||
}
|
||||
// Done. The returned BCC should be added later once the value to be set was pushed on top.
|
||||
assert(GetStackValue(Value.bccType, Value.Par.X) == GetStackValue(Setter.bccType, Setter.Par.X)+1);
|
||||
assert(iParCount == -GetStackValue(Setter.bccType, Setter.Par.X));
|
||||
return Setter;
|
||||
}
|
||||
|
||||
|
@ -1204,7 +1217,6 @@ const char * C4AulParse::GetTokenName(C4AulTokenType TokenType)
|
|||
case ATT_BLCLOSE: return "'}'";
|
||||
case ATT_CALL: return "'->'";
|
||||
case ATT_CALLFS: return "'->~'";
|
||||
case ATT_STAR: return "'*'";
|
||||
case ATT_LDOTS: return "'...'";
|
||||
case ATT_SET: return "'='";
|
||||
case ATT_OPERATOR: return "operator";
|
||||
|
@ -1213,9 +1225,9 @@ const char * C4AulParse::GetTokenName(C4AulTokenType TokenType)
|
|||
}
|
||||
}
|
||||
|
||||
void C4AulParse::Shift(OperatorPolicy Operator)
|
||||
void C4AulParse::Shift()
|
||||
{
|
||||
TokenType = GetNextToken(Operator);
|
||||
TokenType = GetNextToken();
|
||||
}
|
||||
void C4AulParse::Check(C4AulTokenType RefTokenType, const char * Expected)
|
||||
{
|
||||
|
@ -1232,11 +1244,11 @@ void C4AulParse::UnexpectedToken(const char * Expected)
|
|||
throw C4AulParseError(this, FormatString("%s expected, but found %s", Expected, GetTokenName(TokenType)).getData());
|
||||
}
|
||||
|
||||
void C4AulScriptFunc::ParseFn(C4AulScriptContext* context)
|
||||
void C4AulScriptFunc::ParseFn(C4AulScriptEngine *Engine, C4AulScriptContext* context)
|
||||
{
|
||||
ClearCode();
|
||||
// parse
|
||||
C4AulParse state(this, context, C4AulParse::PARSER);
|
||||
C4AulParse state(this, context, Engine);
|
||||
state.Parse_DirectExec();
|
||||
}
|
||||
|
||||
|
@ -1287,8 +1299,7 @@ void C4AulParse::Parse_Script(C4ScriptHost * scripthost)
|
|||
{
|
||||
if (pOrgScript->GetPropList()->GetDef())
|
||||
throw C4AulParseError(this, "#appendto in a Definition");
|
||||
// for #appendto * '*' needs to be ATT_STAR, not an operator.
|
||||
Shift(StarsPlease);
|
||||
Shift();
|
||||
if (Type == PREPARSER)
|
||||
{
|
||||
// get id of script to include/append
|
||||
|
@ -1298,9 +1309,13 @@ void C4AulParse::Parse_Script(C4ScriptHost * scripthost)
|
|||
case ATT_IDTF:
|
||||
Id = StdCopyStrBuf(Idtf);
|
||||
break;
|
||||
case ATT_STAR: // "*"
|
||||
Id = StdCopyStrBuf("*");
|
||||
break;
|
||||
case ATT_OPERATOR:
|
||||
if (SEqual(C4ScriptOpMap[cInt].Identifier, "*"))
|
||||
{
|
||||
Id = StdCopyStrBuf("*");
|
||||
break;
|
||||
}
|
||||
//fallthrough
|
||||
default:
|
||||
// -> ID expected
|
||||
UnexpectedToken("identifier or '*'");
|
||||
|
@ -1695,16 +1710,11 @@ 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;
|
||||
do switch (TokenType)
|
||||
while(TokenType != ATT_BCLOSE) switch(TokenType)
|
||||
{
|
||||
case ATT_BCLOSE:
|
||||
Shift();
|
||||
fDone = true;
|
||||
break;
|
||||
case ATT_COMMA:
|
||||
// got no parameter before a ","
|
||||
if (sWarn && Config.Developer.ExtraWarnings)
|
||||
|
@ -1723,26 +1733,29 @@ int C4AulParse::Parse_Params(int iMaxCnt, const char * sWarn, C4AulFunc * pFunc)
|
|||
// Push all unnamed parameters of the current function as parameters
|
||||
for (int i = Fn->ParNamed.iSize; i < C4AUL_MAX_Par; ++i)
|
||||
{
|
||||
AddBCC(AB_DUP, 1 + i - (iStack + Fn->VarNamed.iSize + Fn->GetParCount()));
|
||||
++size;
|
||||
if (size >= iMaxCnt)
|
||||
break;
|
||||
AddBCC(AB_DUP, 1 + i - (iStack + Fn->VarNamed.iSize + Fn->GetParCount()));
|
||||
++size;
|
||||
}
|
||||
// Do not allow more parameters even if there is place left
|
||||
fDone = true;
|
||||
Match(ATT_BCLOSE);
|
||||
// Do not allow more parameters even if there is space left
|
||||
Check(ATT_BCLOSE);
|
||||
break;
|
||||
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))
|
||||
{
|
||||
|
@ -1751,17 +1764,14 @@ int C4AulParse::Parse_Params(int iMaxCnt, const char * sWarn, C4AulFunc * pFunc)
|
|||
}
|
||||
++size;
|
||||
// end of parameter list?
|
||||
if (TokenType == ATT_BCLOSE)
|
||||
{
|
||||
Shift();
|
||||
fDone = true;
|
||||
}
|
||||
else Match(ATT_COMMA, "',' or ')'");
|
||||
if (TokenType != ATT_BCLOSE)
|
||||
Match(ATT_COMMA, "',' or ')'");
|
||||
break;
|
||||
} while (!fDone);
|
||||
}
|
||||
Match(ATT_BCLOSE);
|
||||
// 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);
|
||||
|
@ -1931,7 +1941,11 @@ void C4AulParse::Parse_DoWhile()
|
|||
PushLoop();
|
||||
// Execute body
|
||||
Parse_Statement();
|
||||
int BeforeCond = JumpHere();
|
||||
int BeforeCond = -1;
|
||||
if (Type == PARSER)
|
||||
for (Loop::Control *pCtrl2 = pLoopStack->Controls; pCtrl2; pCtrl2 = pCtrl2->Next)
|
||||
if (!pCtrl2->Break)
|
||||
BeforeCond = JumpHere();
|
||||
// Execute condition
|
||||
if (TokenType != ATT_IDTF || !SEqual(Idtf, C4AUL_While))
|
||||
UnexpectedToken("'while'");
|
||||
|
@ -2105,7 +2119,7 @@ void C4AulParse::Parse_ForEach()
|
|||
// push initial position (0)
|
||||
AddBCC(AB_INT);
|
||||
// get array element
|
||||
int iStart = AddBCC(AB_FOREACH_NEXT, iVarID);
|
||||
int iStart = AddBCC(AB_FOREACH_NEXT, 1 + iVarID - (iStack + Fn->VarNamed.iSize));
|
||||
// jump out (FOREACH_NEXT will jump over this if
|
||||
// we're not at the end of the array yet)
|
||||
int iCond = AddBCC(AB_JUMP);
|
||||
|
@ -2129,6 +2143,13 @@ void C4AulParse::Parse_ForEach()
|
|||
AddBCC(AB_STACK, -2);
|
||||
}
|
||||
|
||||
static bool GetPropertyByS(const C4PropList * p, const char * s, C4Value & v)
|
||||
{
|
||||
C4String * k = Strings.FindString(s);
|
||||
if (!k) return false;
|
||||
return p->GetPropertyByS(k, &v);
|
||||
}
|
||||
|
||||
void C4AulParse::Parse_Expression(int iParentPrio)
|
||||
{
|
||||
int ndx;
|
||||
|
@ -2154,22 +2175,37 @@ void C4AulParse::Parse_Expression(int iParentPrio)
|
|||
}
|
||||
else if (ContextToExecIn && (ndx = ContextToExecIn->Func->ParNamed.GetItemNr(Idtf)) != -1)
|
||||
{
|
||||
AddBCC(AB_PARN_CONTEXT, ndx);
|
||||
AddBCC(AB_DUP_CONTEXT, ndx);
|
||||
Shift();
|
||||
}
|
||||
else if (ContextToExecIn && (ndx = ContextToExecIn->Func->VarNamed.GetItemNr(Idtf)) != -1)
|
||||
{
|
||||
AddBCC(AB_VARN_CONTEXT, ndx);
|
||||
AddBCC(AB_DUP_CONTEXT, ContextToExecIn->Func->GetParCount() + ndx);
|
||||
Shift();
|
||||
}
|
||||
// check for variable (local)
|
||||
else if (Host && Host->GetPropList() == Fn->Parent && Host->LocalNamed.GetItemNr(Idtf) != -1)
|
||||
{
|
||||
// insert variable by id
|
||||
C4String * pKey = Strings.RegString(Idtf);
|
||||
AddBCC(AB_LOCALN, (intptr_t) pKey);
|
||||
AddBCC(AB_LOCALN, (intptr_t) Strings.RegString(Idtf));
|
||||
Shift();
|
||||
}
|
||||
else if ((!Host || Host->GetPropList() != Fn->Parent) && GetPropertyByS(Fn->Parent, Idtf, val))
|
||||
{
|
||||
if (FoundFn = val.getFunction())
|
||||
{
|
||||
if (Config.Developer.ExtraWarnings && !FoundFn->GetPublic())
|
||||
Warn("using deprecated function %s", Idtf);
|
||||
Shift();
|
||||
Parse_Params(FoundFn->GetParCount(), FoundFn->GetName(), FoundFn);
|
||||
AddBCC(AB_FUNC, (intptr_t) FoundFn);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddBCC(AB_LOCALN, (intptr_t) Strings.RegString(Idtf));
|
||||
Shift();
|
||||
}
|
||||
}
|
||||
else if (SEqual(Idtf, C4AUL_True))
|
||||
{
|
||||
AddBCC(AB_BOOL, 1);
|
||||
|
@ -2236,7 +2272,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
|
||||
|
@ -2258,7 +2294,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)))
|
||||
{
|
||||
|
@ -2369,11 +2405,7 @@ void C4AulParse::Parse_Expression(int iParentPrio)
|
|||
default:
|
||||
UnexpectedToken("expression");
|
||||
}
|
||||
Parse_Expression2(iParentPrio);
|
||||
}
|
||||
|
||||
void C4AulParse::Parse_Expression2(int iParentPrio)
|
||||
{
|
||||
while (1) switch (TokenType)
|
||||
{
|
||||
case ATT_SET:
|
||||
|
@ -2522,7 +2554,6 @@ void C4AulParse::Parse_Expression2(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();
|
||||
|
@ -2532,10 +2563,9 @@ void C4AulParse::Parse_Expression2(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;
|
||||
|
@ -2833,11 +2863,6 @@ void C4AulParse::Parse_Const()
|
|||
}
|
||||
}
|
||||
|
||||
bool C4AulScript::Parse()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void C4ScriptHost::CopyPropList(C4Set<C4Property> & from, C4PropListStatic * to)
|
||||
{
|
||||
// append all funcs and local variable initializations
|
||||
|
|
|
@ -30,6 +30,7 @@ enum C4AulBCCType
|
|||
AB_ARRAY_SLICE, // array slicing
|
||||
AB_ARRAY_SLICE_SET,
|
||||
AB_DUP, // duplicate value from stack
|
||||
AB_DUP_CONTEXT, // duplicate value from stack of parent function
|
||||
AB_STACK_SET, // copy top of stack to stack
|
||||
AB_POP_TO, // pop top of stack to stack
|
||||
AB_LOCALN, // a property of this
|
||||
|
@ -40,9 +41,6 @@ enum C4AulBCCType
|
|||
AB_THIS, // this()
|
||||
AB_FUNC, // function
|
||||
|
||||
AB_PARN_CONTEXT,
|
||||
AB_VARN_CONTEXT,
|
||||
|
||||
// prefix
|
||||
AB_Inc, // ++
|
||||
AB_Dec, // --
|
||||
|
@ -145,7 +143,7 @@ public:
|
|||
C4AulScriptFunc(C4PropListStatic * Parent, const C4AulScriptFunc &FromFunc); // copy script/code, etc from given func
|
||||
~C4AulScriptFunc();
|
||||
|
||||
void ParseFn(C4AulScriptContext* context = NULL);
|
||||
void ParseFn(C4AulScriptEngine *Engine, C4AulScriptContext* context = NULL);
|
||||
|
||||
virtual bool GetPublic() const { return true; }
|
||||
virtual int GetParCount() const { return ParCount; }
|
||||
|
|
|
@ -661,11 +661,11 @@ static bool FnStartCallTrace(C4PropList * _this)
|
|||
static bool FnStartScriptProfiler(C4PropList * _this, C4Def * pDef)
|
||||
{
|
||||
// get script to profile
|
||||
C4AulScript *pScript;
|
||||
C4ScriptHost *pScript;
|
||||
if (pDef)
|
||||
pScript = &pDef->Script;
|
||||
else
|
||||
pScript = &::ScriptEngine;
|
||||
pScript = NULL;
|
||||
// profile it
|
||||
C4AulProfiler::StartProfiling(pScript);
|
||||
return true;
|
||||
|
|
|
@ -24,7 +24,11 @@
|
|||
|
||||
/*--- C4ScriptHost ---*/
|
||||
|
||||
C4ScriptHost::C4ScriptHost()
|
||||
C4ScriptHost::C4ScriptHost():
|
||||
// prepare lists
|
||||
Prev(NULL), Next(NULL),
|
||||
Engine(NULL),
|
||||
State(ASS_NONE) // not compiled
|
||||
{
|
||||
Script = NULL;
|
||||
stringTable = 0;
|
||||
|
@ -38,12 +42,12 @@ C4ScriptHost::C4ScriptHost()
|
|||
}
|
||||
C4ScriptHost::~C4ScriptHost()
|
||||
{
|
||||
Unreg();
|
||||
Clear();
|
||||
}
|
||||
|
||||
void C4ScriptHost::Clear()
|
||||
{
|
||||
C4AulScript::Clear();
|
||||
ComponentHost.Clear();
|
||||
Script.Clear();
|
||||
LocalNamed.Reset();
|
||||
|
@ -58,6 +62,35 @@ void C4ScriptHost::Clear()
|
|||
// remove includes
|
||||
Includes.clear();
|
||||
Appends.clear();
|
||||
// reset flags
|
||||
State = ASS_NONE;
|
||||
}
|
||||
|
||||
void C4ScriptHost::Unreg()
|
||||
{
|
||||
// remove from list
|
||||
if (Prev) Prev->Next = Next; else if (Engine) Engine->Child0 = Next;
|
||||
if (Next) Next->Prev = Prev; else if (Engine) Engine->ChildL = Prev;
|
||||
Prev = Next = NULL;
|
||||
Engine = NULL;
|
||||
}
|
||||
|
||||
void C4ScriptHost::Reg2List(C4AulScriptEngine *pEngine)
|
||||
{
|
||||
// already regged? (def reloaded)
|
||||
if (Engine) return;
|
||||
// reg to list
|
||||
if ((Engine = pEngine))
|
||||
{
|
||||
if ((Prev = Engine->ChildL))
|
||||
Prev->Next = this;
|
||||
else
|
||||
Engine->Child0 = this;
|
||||
Engine->ChildL = this;
|
||||
}
|
||||
else
|
||||
Prev = NULL;
|
||||
Next = NULL;
|
||||
}
|
||||
|
||||
bool C4ScriptHost::Load(C4Group &hGroup, const char *szFilename,
|
||||
|
@ -138,12 +171,13 @@ bool C4ScriptHost::ReloadScript(const char *szPath, const char *szLanguage)
|
|||
return false;
|
||||
}
|
||||
|
||||
void C4ScriptHost::SetError(const char *szMessage)
|
||||
std::string C4ScriptHost::Translate(const std::string &text) const
|
||||
{
|
||||
|
||||
if (stringTable)
|
||||
return stringTable->Translate(text);
|
||||
throw C4LangStringTable::NoSuchTranslation(text);
|
||||
}
|
||||
|
||||
|
||||
/*--- C4ExtraScriptHost ---*/
|
||||
|
||||
C4ExtraScriptHost::C4ExtraScriptHost(C4String *parent_key_name):
|
||||
|
|
|
@ -23,47 +23,68 @@
|
|||
#include <C4ComponentHost.h>
|
||||
#include <C4Aul.h>
|
||||
|
||||
// aul script state
|
||||
enum C4AulScriptState
|
||||
{
|
||||
ASS_NONE, // nothing
|
||||
ASS_PREPARSED, // function list built; CodeSize set
|
||||
ASS_LINKED, // includes and appends resolved
|
||||
ASS_PARSED // byte code generated
|
||||
};
|
||||
|
||||
// generic script host for objects
|
||||
class C4ScriptHost : public C4AulScript
|
||||
class C4ScriptHost
|
||||
{
|
||||
public:
|
||||
~C4ScriptHost();
|
||||
bool Delete() { return false; } // do NOT delete this - it's just a class member!
|
||||
virtual ~C4ScriptHost();
|
||||
virtual bool Delete() { return false; } // do NOT delete this - it's just a class member!
|
||||
|
||||
void Clear();
|
||||
virtual bool Load(C4Group &hGroup, const char *szFilename,
|
||||
const char *szLanguage, C4LangStringTable *pLocalTable);
|
||||
virtual bool LoadData(const char *szFilename, const char *szData, class C4LangStringTable *pLocalTable);
|
||||
void Reg2List(C4AulScriptEngine *pEngine); // reg to linked list
|
||||
virtual C4PropListStatic * GetPropList() { return 0; }
|
||||
const char *GetScript() const { return Script.getData(); }
|
||||
virtual C4ScriptHost * GetScriptHost() { return this; }
|
||||
bool IsReady() { return State == ASS_PARSED; } // whether script calls may be done
|
||||
// Translate a string using the script's lang table
|
||||
std::string Translate(const std::string &text) const;
|
||||
std::list<C4ScriptHost *> SourceScripts;
|
||||
StdCopyStrBuf ScriptName; // script name
|
||||
protected:
|
||||
C4ScriptHost();
|
||||
void SetError(const char *szMessage);
|
||||
void Unreg(); // remove from list
|
||||
void MakeScript();
|
||||
bool ReloadScript(const char *szPath, const char *szLanguage);
|
||||
virtual bool ReloadScript(const char *szPath, const char *szLanguage);
|
||||
C4ComponentHost ComponentHost;
|
||||
|
||||
bool Preparse(); // preparse script; return if successfull
|
||||
virtual bool Parse(); // parse preparsed script; return if successfull
|
||||
virtual void UnLink(); // reset to unlinked state
|
||||
|
||||
void Warn(const char *pMsg, ...) GNUC_FORMAT_ATTRIBUTE_O;
|
||||
|
||||
C4AulScriptEngine *Engine; //owning engine
|
||||
C4ScriptHost *Prev, *Next; // tree structure
|
||||
|
||||
std::list<StdCopyStrBuf> Includes; // include list
|
||||
std::list<StdCopyStrBuf> Appends; // append list
|
||||
|
||||
virtual void AddEngineFunctions() {}; // add any engine functions specific to this script host
|
||||
void CopyPropList(C4Set<C4Property> & from, C4PropListStatic * to);
|
||||
bool ResolveIncludes(C4DefList *rDefs); // resolve includes
|
||||
bool ResolveAppends(C4DefList *rDefs); // resolve appends
|
||||
virtual bool ResolveIncludes(C4DefList *rDefs); // resolve includes
|
||||
virtual bool ResolveAppends(C4DefList *rDefs); // resolve appends
|
||||
bool Resolving; // set while include-resolving, to catch circular includes
|
||||
bool IncludesResolved;
|
||||
|
||||
StdStrBuf Script; // script
|
||||
C4LangStringTable *stringTable;
|
||||
C4ValueMapNames LocalNamed;
|
||||
C4Set<C4Property> LocalValues;
|
||||
C4AulScriptState State; // script state
|
||||
friend class C4AulParse;
|
||||
friend class C4AulScriptFunc;
|
||||
friend class C4AulProfiler;
|
||||
friend class C4AulScriptEngine;
|
||||
friend class C4AulDebug;
|
||||
};
|
||||
|
||||
|
|
|
@ -303,7 +303,7 @@ C4String *C4StringTable::RegString(StdStrBuf String)
|
|||
return new C4String(String);
|
||||
}
|
||||
|
||||
C4String *C4StringTable::FindString(const char *strString)
|
||||
C4String *C4StringTable::FindString(const char *strString) const
|
||||
{
|
||||
return Set.Get(strString);
|
||||
}
|
||||
|
|
|
@ -483,7 +483,7 @@ public:
|
|||
C4String *RegString(StdStrBuf String);
|
||||
C4String *RegString(const char * s) { return RegString(StdStrBuf(s)); }
|
||||
// Find existing C4String
|
||||
C4String *FindString(const char *strString);
|
||||
C4String *FindString(const char *strString) const;
|
||||
|
||||
private:
|
||||
C4Set<C4String *> Set;
|
||||
|
|
|
@ -141,13 +141,6 @@ public:
|
|||
// Change and set Type to int in case it was nil or bool before
|
||||
// Use with care: These don't handle int32_t overflow
|
||||
C4Value & operator += (int32_t by) { Data.Int += by; Type=C4V_Int; return *this; }
|
||||
C4Value & operator -= (int32_t by) { Data.Int -= by; Type=C4V_Int; return *this; }
|
||||
C4Value & operator *= (int32_t by) { Data.Int *= by; Type=C4V_Int; return *this; }
|
||||
C4Value & operator /= (int32_t by) { Data.Int /= by; Type=C4V_Int; return *this; }
|
||||
C4Value & operator %= (int32_t by) { Data.Int %= by; Type=C4V_Int; return *this; }
|
||||
C4Value & operator &= (int32_t by) { Data.Int &= by; Type=C4V_Int; return *this; }
|
||||
C4Value & operator ^= (int32_t by) { Data.Int ^= by; Type=C4V_Int; return *this; }
|
||||
C4Value & operator |= (int32_t by) { Data.Int |= by; Type=C4V_Int; return *this; }
|
||||
C4Value & operator ++ () { Data.Int++; Type=C4V_Int; return *this; }
|
||||
C4Value operator ++ (int) { C4Value old = *this; ++(*this); return old; }
|
||||
C4Value & operator -- () { Data.Int--; Type=C4V_Int; return *this; }
|
||||
|
|
|
@ -37,7 +37,6 @@ class C4ValueArray;
|
|||
class C4Def;
|
||||
class C4Effect;
|
||||
class C4AulParSet;
|
||||
class C4AulScript;
|
||||
class C4AulScriptFunc;
|
||||
#include "script/C4Value.h"
|
||||
|
||||
|
|
|
@ -81,9 +81,9 @@ TEST(DirectExecTest, HostUnmodifedByParseTest)
|
|||
TestHost host2 = host;
|
||||
host.test_equality(host2);
|
||||
char szScript[] = "8*5";
|
||||
C4AulScriptFunc *pFunc = new C4AulScriptFunc(host.GetPropList(), host.GetScriptHost(), 0, szScript);
|
||||
C4AulScriptFunc *pFunc = new C4AulScriptFunc(host.GetPropList(), nullptr, nullptr, szScript);
|
||||
host.test_equality(host2);
|
||||
pFunc->ParseFn();
|
||||
pFunc->ParseFn(&::ScriptEngine);
|
||||
host.test_equality(host2);
|
||||
delete pFunc;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ TEST_F(AulPredefFunctionTest, Translate)
|
|||
{
|
||||
// Expect the engine to warn when it can't find a translation
|
||||
LogMock log;
|
||||
EXPECT_CALL(log, DebugLogF(R"(WARNING: Translate: no translation for string "%s")", _));
|
||||
EXPECT_CALL(log, DebugLogF(testing::StrEq(R"(WARNING: Translate: no translation for string "%s")"), _));
|
||||
EXPECT_CALL(log, DebugLog(StartsWith(" by: "))).Times(AnyNumber()); // ignore stack trace
|
||||
|
||||
EXPECT_EQ(C4VString("a"), RunExpr("Translate(\"a\")"));
|
||||
|
|
|
@ -123,3 +123,9 @@ TEST_F(AulTest, Eval)
|
|||
EXPECT_EQ(C4VInt(42), RunCode("local i = 42; func Main() { return eval(\"this.i\"); }", false));
|
||||
EXPECT_EQ(C4VInt(42), RunCode("local i; func Main() { eval(\"this.i = 42\"); return i; }", false));
|
||||
}
|
||||
|
||||
TEST_F(AulTest, Vars)
|
||||
{
|
||||
EXPECT_EQ(C4VInt(42), RunCode("var i = 21; i = i + i; return i;"));
|
||||
EXPECT_EQ(C4VInt(42), RunCode("var i = -42; i = Abs(i); return i;"));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue