diff --git a/CMakeLists.txt b/CMakeLists.txt index 35a9276f3..e8ba8ccae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1051,6 +1051,8 @@ src/script/C4AulFunc.h src/script/C4Aul.h src/script/C4AulLink.cpp src/script/C4AulParse.cpp +src/script/C4AulScriptFunc.cpp +src/script/C4AulScriptFunc.h src/script/C4PropList.cpp src/script/C4PropList.h src/script/C4Script.cpp diff --git a/src/C4Prototypes.h b/src/C4Prototypes.h index 4fab9eb76..f50fcb475 100644 --- a/src/C4Prototypes.h +++ b/src/C4Prototypes.h @@ -23,11 +23,13 @@ // class declarations class C4AbstractApp; class C4Action; -struct C4AulContext; +struct C4AulBCC; class C4AulDefFunc; +class C4AulExec; class C4AulFunc; struct C4AulParSet; class C4AulScript; +struct C4AulScriptContext; class C4AulScriptEngine; class C4AulScriptFunc; class C4BltTransform; diff --git a/src/control/C4Control.cpp b/src/control/C4Control.cpp index 7abb139e9..8f101c62b 100644 --- a/src/control/C4Control.cpp +++ b/src/control/C4Control.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include diff --git a/src/script/C4Aul.cpp b/src/script/C4Aul.cpp index a410eab07..7ac9d4fcf 100644 --- a/src/script/C4Aul.cpp +++ b/src/script/C4Aul.cpp @@ -111,46 +111,6 @@ std::string C4AulScript::Translate(const std::string &text) const throw C4LangStringTable::NoSuchTranslation(text); } -C4AulScriptFunc::C4AulScriptFunc(C4PropListStatic * Parent, C4ScriptHost *pOrgScript, const char *pName, const char *Script): - C4AulFunc(Parent, pName), - OwnerOverloaded(NULL), - ParCount(0), - Script(Script), - pOrgScript(pOrgScript), - tProfileTime(0) -{ - for (int i = 0; i < C4AUL_MAX_Par; i++) ParType[i] = C4V_Any; - AddBCC(AB_EOFN); -} - -C4AulScriptFunc::C4AulScriptFunc(C4PropListStatic * Parent, const C4AulScriptFunc &FromFunc): - C4AulFunc(Parent, FromFunc.GetName()), - OwnerOverloaded(NULL), - ParCount(FromFunc.ParCount), - Script(FromFunc.Script), - VarNamed(FromFunc.VarNamed), - ParNamed(FromFunc.ParNamed), - pOrgScript(FromFunc.pOrgScript), - tProfileTime(0) -{ - for (int i = 0; i < C4AUL_MAX_Par; i++) - ParType[i] = FromFunc.ParType[i]; - AddBCC(AB_EOFN); -} - -C4AulScriptFunc::~C4AulScriptFunc() -{ - if (OwnerOverloaded) OwnerOverloaded->DecRef(); - ClearCode(); -} - -void C4AulScriptFunc::SetOverloaded(C4AulFunc * f) -{ - if (OwnerOverloaded) OwnerOverloaded->DecRef(); - OwnerOverloaded = f; - if (f) f->IncRef(); -} - /*--- C4AulScriptEngine ---*/ C4AulScriptEngine::C4AulScriptEngine(): diff --git a/src/script/C4Aul.h b/src/script/C4Aul.h index 8adcd1c4c..6b5633522 100644 --- a/src/script/C4Aul.h +++ b/src/script/C4Aul.h @@ -57,164 +57,6 @@ public: C4AulExecError(const char *szError); }; -// byte code chunk type -// some special script functions defined hard-coded to reduce the exec context -enum C4AulBCCType -{ - AB_ARRAYA, // array or proplist access - AB_ARRAYA_SET, - AB_PROP, // proplist access with static key - AB_PROP_SET, - AB_ARRAY_SLICE, // array slicing - AB_ARRAY_SLICE_SET, - AB_DUP, // duplicate value from stack - AB_STACK_SET, // copy top of stack to stack - AB_POP_TO, // pop top of stack to stack - AB_LOCALN, // a property of this - AB_LOCALN_SET, - AB_GLOBALN, // a named global - AB_GLOBALN_SET, - AB_PAR, // Par statement - AB_THIS, // this() - AB_FUNC, // function - - AB_PARN_CONTEXT, - AB_VARN_CONTEXT, - -// prefix - AB_Inc, // ++ - AB_Dec, // -- - AB_BitNot, // ~ - AB_Not, // ! - AB_Neg, // - - -// postfix - AB_Pow, // ** - AB_Div, // / - AB_Mul, // * - AB_Mod, // % - AB_Sub, // - - AB_Sum, // + - AB_LeftShift, // << - AB_RightShift, // >> - AB_LessThan, // < - AB_LessThanEqual, // <= - AB_GreaterThan, // > - AB_GreaterThanEqual, // >= - AB_Equal, // == - AB_NotEqual, // != - AB_BitAnd, // & - AB_BitXOr, // ^ - AB_BitOr, // | - - AB_CALL, // direct object call - AB_CALLFS, // failsafe direct call - AB_STACK, // push nulls / pop - AB_INT, // constant: int - AB_BOOL, // constant: bool - AB_STRING, // constant: string - AB_CPROPLIST, // constant: proplist - AB_CARRAY, // constant: array - AB_CFUNCTION, // constant: function - AB_NIL, // constant: nil - AB_NEW_ARRAY, // semi-constant: array - AB_NEW_PROPLIST, // create a new proplist - AB_JUMP, // jump - AB_JUMPAND, // jump if convertible to false, else pop the stack - AB_JUMPOR, // jump if convertible to true, else pop the stack - AB_JUMPNNIL, // jump if not nil, else pop the stack - AB_CONDN, // conditional jump (negated, pops stack) - AB_COND, // conditional jump (pops stack) - AB_FOREACH_NEXT, // foreach: next element - AB_RETURN, // return statement - AB_ERR, // parse error at this position - AB_DEBUG, // debug break - AB_EOFN, // end of function -}; - -// byte code chunk -struct C4AulBCC -{ - C4AulBCCType bccType; // chunk type - union - { - int32_t i; - C4String * s; - C4PropList * p; - C4ValueArray * a; - C4AulFunc * f; - intptr_t X; - } Par; // extra info -}; - -// execution context -struct C4AulScriptContext -{ - C4PropList *Obj; - C4Value *Return; - C4Value *Pars; - C4Value *Vars; - C4AulScriptFunc *Func; - C4AulBCC *CPos; - C4TimeMilliseconds tTime; // initialized only by profiler if active - - void dump(StdStrBuf Dump = StdStrBuf("")); - StdStrBuf ReturnDump(StdStrBuf Dump = StdStrBuf("")); -}; - -// script function class -class C4AulScriptFunc : public C4AulFunc -{ -public: - C4AulFunc *OwnerOverloaded; // overloaded owner function; if present - void SetOverloaded(C4AulFunc *); - C4AulScriptFunc *SFunc() { return this; } // type check func... -protected: - void AddBCC(C4AulBCCType eType, intptr_t = 0, const char * SPos = 0); // add byte code chunk and advance - void RemoveLastBCC(); - void ClearCode(); - int GetCodePos() const { return Code.size(); } - C4AulBCC *GetCodeByPos(int iPos) { return &Code[iPos]; } - C4AulBCC *GetLastCode() { return Code.empty() ? NULL : &Code.back(); } - std::vector Code; - std::vector PosForCode; - int ParCount; - C4V_Type ParType[C4AUL_MAX_Par]; // parameter types - -public: - const char *Script; // script pos - C4ValueMapNames VarNamed; // list of named vars in this function - C4ValueMapNames ParNamed; // list of named pars in this function - void AddPar(const char * Idtf) - { - assert(ParCount < C4AUL_MAX_Par); - assert(ParCount == ParNamed.iSize); - ParNamed.AddName(Idtf); - ++ParCount; - } - C4ScriptHost *pOrgScript; // the orginal script (!= Owner if included or appended) - - C4AulScriptFunc(C4PropListStatic * Parent, C4ScriptHost *pOrgScript, const char *pName, const char *Script); - C4AulScriptFunc(C4PropListStatic * Parent, const C4AulScriptFunc &FromFunc); // copy script/code, etc from given func - ~C4AulScriptFunc(); - - void ParseFn(C4AulScriptContext* context = NULL); - - virtual bool GetPublic() const { return true; } - virtual int GetParCount() const { return ParCount; } - virtual const C4V_Type *GetParType() const { return ParType; } - virtual C4V_Type GetRetType() const { return C4V_Any; } - virtual C4Value Exec(C4PropList * p, C4Value pPars[], bool fPassErrors=false); // execute func - - int GetLineOfCode(C4AulBCC * bcc); - C4AulBCC * GetCode(); - - uint32_t tProfileTime; // internally set by profiler - - friend class C4AulParse; - friend class C4ScriptHost; -}; - class C4AulFuncMap { public: diff --git a/src/script/C4AulDebug.h b/src/script/C4AulDebug.h index 74956904c..ce9703335 100644 --- a/src/script/C4AulDebug.h +++ b/src/script/C4AulDebug.h @@ -18,7 +18,6 @@ #ifndef NOAULDEBUG -#include "C4Aul.h" #include "C4NetIO.h" // manages a debugging interface @@ -33,7 +32,7 @@ public: private: bool fInit, fConnected; - class C4AulExec *pExec; + C4AulExec *pExec; static C4AulDebug *pDebug; C4NetIO::addr_t PeerAddr, AllowedAddr; StdCopyStrBuf Password; diff --git a/src/script/C4AulExec.cpp b/src/script/C4AulExec.cpp index f7f26d395..f77a539ac 100644 --- a/src/script/C4AulExec.cpp +++ b/src/script/C4AulExec.cpp @@ -16,10 +16,11 @@ // executes script functions #include -#include #include -#include +#include +#include +#include #include #include #include @@ -1024,11 +1025,6 @@ void C4AulProfiler::Show() // done! } -C4Value C4AulScriptFunc::Exec(C4PropList * p, C4Value pPars[], bool fPassErrors) -{ - return AulExec.Exec(this, p, pPars, fPassErrors); -} - C4Value C4AulScript::DirectExec(C4Object *pObj, const char *szScript, const char *szContext, bool fPassErrors, C4AulScriptContext* context) { #ifdef DEBUGREC_SCRIPT diff --git a/src/script/C4AulExec.h b/src/script/C4AulExec.h index 422186b95..f0f3bf613 100644 --- a/src/script/C4AulExec.h +++ b/src/script/C4AulExec.h @@ -21,6 +21,7 @@ #include #include "C4TimeMilliseconds.h" +#include const int MAX_CONTEXT_STACK = 512; const int MAX_VALUE_STACK = 1024; @@ -36,6 +37,21 @@ const int MAX_VALUE_STACK = 1024; temporary values */ +// execution context +struct C4AulScriptContext +{ + C4PropList *Obj; + C4Value *Return; + C4Value *Pars; + C4Value *Vars; + C4AulScriptFunc *Func; + C4AulBCC *CPos; + C4TimeMilliseconds tTime; // initialized only by profiler if active + + void dump(StdStrBuf Dump = StdStrBuf("")); + StdStrBuf ReturnDump(StdStrBuf Dump = StdStrBuf("")); +}; + class C4AulExec { diff --git a/src/script/C4AulFunc.h b/src/script/C4AulFunc.h index 2d9a12f9d..19c91b494 100644 --- a/src/script/C4AulFunc.h +++ b/src/script/C4AulFunc.h @@ -17,6 +17,10 @@ #ifndef INC_C4AulFunc #define INC_C4AulFunc +#ifndef INC_C4Value +#error Include C4Value.h instead of C4AulFunc.h +#endif + #include #define C4AUL_MAX_Par 10 // max number of parameters diff --git a/src/script/C4AulParse.cpp b/src/script/C4AulParse.cpp index 37d1f296e..92aee74f7 100644 --- a/src/script/C4AulParse.cpp +++ b/src/script/C4AulParse.cpp @@ -19,8 +19,9 @@ #include #include - #include +#include +#include #include #include #include @@ -783,63 +784,6 @@ void C4AulParse::DumpByteCode() } } -void C4AulScriptFunc::AddBCC(C4AulBCCType eType, intptr_t X, const char * SPos) -{ - // store chunk - C4AulBCC bcc; - bcc.bccType = eType; - bcc.Par.X = X; - Code.push_back(bcc); - PosForCode.push_back(SPos); - - switch (eType) - { - case AB_STRING: case AB_CALL: case AB_CALLFS: case AB_LOCALN: case AB_PROP: - /* case AB_LOCALN_SET/AB_PROP_SET: -- expected to already have a reference upon creation, see MakeSetter */ - bcc.Par.s->IncRef(); - break; - case AB_CARRAY: - bcc.Par.a->IncRef(); - break; - default: break; - } -} - -void C4AulScriptFunc::RemoveLastBCC() -{ - C4AulBCC *pBCC = &Code.back(); - switch (pBCC->bccType) - { - case AB_STRING: case AB_CALL: case AB_CALLFS: case AB_LOCALN: case AB_LOCALN_SET: case AB_PROP: case AB_PROP_SET: - pBCC->Par.s->DecRef(); - break; - case AB_CARRAY: - pBCC->Par.a->DecRef(); - break; - default: break; - } - Code.pop_back(); - PosForCode.pop_back(); -} - -void C4AulScriptFunc::ClearCode() -{ - while(Code.size() > 0) - RemoveLastBCC(); - // This function is now broken until an AddBCC call -} - -int C4AulScriptFunc::GetLineOfCode(C4AulBCC * bcc) -{ - return SGetLine(pOrgScript ? pOrgScript->GetScript() : Script, PosForCode[bcc - &Code[0]]); -} - -C4AulBCC * C4AulScriptFunc::GetCode() -{ - assert(!Code.empty()); - return &Code[0]; -} - bool C4ScriptHost::Preparse() { // handle easiest case first diff --git a/src/script/C4AulScriptFunc.cpp b/src/script/C4AulScriptFunc.cpp new file mode 100644 index 000000000..184ba8109 --- /dev/null +++ b/src/script/C4AulScriptFunc.cpp @@ -0,0 +1,122 @@ +/* + * OpenClonk, http://www.openclonk.org + * + * Copyright (c) 2009-2014, The OpenClonk Team and contributors + * + * Distributed under the terms of the ISC license; see accompanying file + * "COPYING" for details. + * + * "Clonk" is a registered trademark of Matthes Bender, used with permission. + * See accompanying file "TRADEMARK" for details. + * + * To redistribute this file separately, substitute the full license texts + * for the above references. + */ + +#include +#include + +#include +#include + +C4AulScriptFunc::C4AulScriptFunc(C4PropListStatic * Parent, C4ScriptHost *pOrgScript, const char *pName, const char *Script): + C4AulFunc(Parent, pName), + OwnerOverloaded(NULL), + ParCount(0), + Script(Script), + pOrgScript(pOrgScript), + tProfileTime(0) +{ + for (int i = 0; i < C4AUL_MAX_Par; i++) ParType[i] = C4V_Any; + AddBCC(AB_EOFN); +} + +C4AulScriptFunc::C4AulScriptFunc(C4PropListStatic * Parent, const C4AulScriptFunc &FromFunc): + C4AulFunc(Parent, FromFunc.GetName()), + OwnerOverloaded(NULL), + ParCount(FromFunc.ParCount), + Script(FromFunc.Script), + VarNamed(FromFunc.VarNamed), + ParNamed(FromFunc.ParNamed), + pOrgScript(FromFunc.pOrgScript), + tProfileTime(0) +{ + for (int i = 0; i < C4AUL_MAX_Par; i++) + ParType[i] = FromFunc.ParType[i]; + AddBCC(AB_EOFN); +} + +C4AulScriptFunc::~C4AulScriptFunc() +{ + if (OwnerOverloaded) OwnerOverloaded->DecRef(); + ClearCode(); +} + +void C4AulScriptFunc::SetOverloaded(C4AulFunc * f) +{ + if (OwnerOverloaded) OwnerOverloaded->DecRef(); + OwnerOverloaded = f; + if (f) f->IncRef(); +} + +void C4AulScriptFunc::AddBCC(C4AulBCCType eType, intptr_t X, const char * SPos) +{ + // store chunk + C4AulBCC bcc; + bcc.bccType = eType; + bcc.Par.X = X; + Code.push_back(bcc); + PosForCode.push_back(SPos); + + switch (eType) + { + case AB_STRING: case AB_CALL: case AB_CALLFS: case AB_LOCALN: case AB_PROP: + /* case AB_LOCALN_SET/AB_PROP_SET: -- expected to already have a reference upon creation, see MakeSetter */ + bcc.Par.s->IncRef(); + break; + case AB_CARRAY: + bcc.Par.a->IncRef(); + break; + default: break; + } +} + +void C4AulScriptFunc::RemoveLastBCC() +{ + C4AulBCC *pBCC = &Code.back(); + switch (pBCC->bccType) + { + case AB_STRING: case AB_CALL: case AB_CALLFS: case AB_LOCALN: case AB_LOCALN_SET: case AB_PROP: case AB_PROP_SET: + pBCC->Par.s->DecRef(); + break; + case AB_CARRAY: + pBCC->Par.a->DecRef(); + break; + default: break; + } + Code.pop_back(); + PosForCode.pop_back(); +} + +void C4AulScriptFunc::ClearCode() +{ + while(Code.size() > 0) + RemoveLastBCC(); + // This function is now broken until an AddBCC call +} + +int C4AulScriptFunc::GetLineOfCode(C4AulBCC * bcc) +{ + return SGetLine(pOrgScript ? pOrgScript->GetScript() : Script, PosForCode[bcc - &Code[0]]); +} + +C4AulBCC * C4AulScriptFunc::GetCode() +{ + assert(!Code.empty()); + return &Code[0]; +} + +C4Value C4AulScriptFunc::Exec(C4PropList * p, C4Value pPars[], bool fPassErrors) +{ + return AulExec.Exec(this, p, pPars, fPassErrors); +} diff --git a/src/script/C4AulScriptFunc.h b/src/script/C4AulScriptFunc.h new file mode 100644 index 000000000..71b5b9909 --- /dev/null +++ b/src/script/C4AulScriptFunc.h @@ -0,0 +1,165 @@ +/* + * OpenClonk, http://www.openclonk.org + * + * Copyright (c) 2001-2014, The OpenClonk Team and contributors + * + * Distributed under the terms of the ISC license; see accompanying file + * "COPYING" for details. + * + * "Clonk" is a registered trademark of Matthes Bender, used with permission. + * See accompanying file "TRADEMARK" for details. + * + * To redistribute this file separately, substitute the full license texts + * for the above references. + */ + +#ifndef C4AULSCRIPTFUNC_H_ +#define C4AULSCRIPTFUNC_H_ + +#include +#include + +// byte code chunk type +// some special script functions defined hard-coded to reduce the exec context +enum C4AulBCCType +{ + AB_ARRAYA, // array or proplist access + AB_ARRAYA_SET, + AB_PROP, // proplist access with static key + AB_PROP_SET, + AB_ARRAY_SLICE, // array slicing + AB_ARRAY_SLICE_SET, + AB_DUP, // duplicate value from stack + AB_STACK_SET, // copy top of stack to stack + AB_POP_TO, // pop top of stack to stack + AB_LOCALN, // a property of this + AB_LOCALN_SET, + AB_GLOBALN, // a named global + AB_GLOBALN_SET, + AB_PAR, // Par statement + AB_THIS, // this() + AB_FUNC, // function + + AB_PARN_CONTEXT, + AB_VARN_CONTEXT, + +// prefix + AB_Inc, // ++ + AB_Dec, // -- + AB_BitNot, // ~ + AB_Not, // ! + AB_Neg, // - + +// postfix + AB_Pow, // ** + AB_Div, // / + AB_Mul, // * + AB_Mod, // % + AB_Sub, // - + AB_Sum, // + + AB_LeftShift, // << + AB_RightShift, // >> + AB_LessThan, // < + AB_LessThanEqual, // <= + AB_GreaterThan, // > + AB_GreaterThanEqual, // >= + AB_Equal, // == + AB_NotEqual, // != + AB_BitAnd, // & + AB_BitXOr, // ^ + AB_BitOr, // | + + AB_CALL, // direct object call + AB_CALLFS, // failsafe direct call + AB_STACK, // push nulls / pop + AB_INT, // constant: int + AB_BOOL, // constant: bool + AB_STRING, // constant: string + AB_CPROPLIST, // constant: proplist + AB_CARRAY, // constant: array + AB_CFUNCTION, // constant: function + AB_NIL, // constant: nil + AB_NEW_ARRAY, // semi-constant: array + AB_NEW_PROPLIST, // create a new proplist + AB_JUMP, // jump + AB_JUMPAND, // jump if convertible to false, else pop the stack + AB_JUMPOR, // jump if convertible to true, else pop the stack + AB_JUMPNNIL, // jump if not nil, else pop the stack + AB_CONDN, // conditional jump (negated, pops stack) + AB_COND, // conditional jump (pops stack) + AB_FOREACH_NEXT, // foreach: next element + AB_RETURN, // return statement + AB_ERR, // parse error at this position + AB_DEBUG, // debug break + AB_EOFN, // end of function +}; + +// byte code chunk +struct C4AulBCC +{ + C4AulBCCType bccType; // chunk type + union + { + int32_t i; + C4String * s; + C4PropList * p; + C4ValueArray * a; + C4AulFunc * f; + intptr_t X; + } Par; // extra info +}; + +// script function class +class C4AulScriptFunc : public C4AulFunc +{ +public: + C4AulFunc *OwnerOverloaded; // overloaded owner function; if present + void SetOverloaded(C4AulFunc *); + C4AulScriptFunc *SFunc() { return this; } // type check func... +protected: + void AddBCC(C4AulBCCType eType, intptr_t = 0, const char * SPos = 0); // add byte code chunk and advance + void RemoveLastBCC(); + void ClearCode(); + int GetCodePos() const { return Code.size(); } + C4AulBCC *GetCodeByPos(int iPos) { return &Code[iPos]; } + C4AulBCC *GetLastCode() { return Code.empty() ? NULL : &Code.back(); } + std::vector Code; + std::vector PosForCode; + int ParCount; + C4V_Type ParType[C4AUL_MAX_Par]; // parameter types + +public: + const char *Script; // script pos + C4ValueMapNames VarNamed; // list of named vars in this function + C4ValueMapNames ParNamed; // list of named pars in this function + void AddPar(const char * Idtf) + { + assert(ParCount < C4AUL_MAX_Par); + assert(ParCount == ParNamed.iSize); + ParNamed.AddName(Idtf); + ++ParCount; + } + C4ScriptHost *pOrgScript; // the orginal script (!= Owner if included or appended) + + C4AulScriptFunc(C4PropListStatic * Parent, C4ScriptHost *pOrgScript, const char *pName, const char *Script); + C4AulScriptFunc(C4PropListStatic * Parent, const C4AulScriptFunc &FromFunc); // copy script/code, etc from given func + ~C4AulScriptFunc(); + + void ParseFn(C4AulScriptContext* context = NULL); + + virtual bool GetPublic() const { return true; } + virtual int GetParCount() const { return ParCount; } + virtual const C4V_Type *GetParType() const { return ParType; } + virtual C4V_Type GetRetType() const { return C4V_Any; } + virtual C4Value Exec(C4PropList * p, C4Value pPars[], bool fPassErrors=false); // execute func + + int GetLineOfCode(C4AulBCC * bcc); + C4AulBCC * GetCode(); + + uint32_t tProfileTime; // internally set by profiler + + friend class C4AulParse; + friend class C4ScriptHost; +}; + +#endif /* C4AULSCRIPTFUNC_H_ */