From 8285a11a26d78784f26b76e6bcdfa479f6c1a345 Mon Sep 17 00:00:00 2001 From: faketruth Date: Tue, 8 Nov 2011 01:25:01 +0000 Subject: It's a Squirrel!! In SquirrelBindings.h use #define USE_SQUIRREL 1 to enable squirrel git-svn-id: http://mc-server.googlecode.com/svn/trunk@76 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- squirrel_3_0_1_stable/sqplus/SquirrelVM.cpp | 505 ++++++++++++++++++++++++++++ 1 file changed, 505 insertions(+) create mode 100644 squirrel_3_0_1_stable/sqplus/SquirrelVM.cpp (limited to 'squirrel_3_0_1_stable/sqplus/SquirrelVM.cpp') diff --git a/squirrel_3_0_1_stable/sqplus/SquirrelVM.cpp b/squirrel_3_0_1_stable/sqplus/SquirrelVM.cpp new file mode 100644 index 000000000..2d506d700 --- /dev/null +++ b/squirrel_3_0_1_stable/sqplus/SquirrelVM.cpp @@ -0,0 +1,505 @@ +#include +#include +#include + +#define _DEBUG_DUMP + +#include "sqplus.h" + +#include +#include +#include +#include +#include +#include + + +HSQUIRRELVM SquirrelVM::_VM; +bool SquirrelVM::_no_vm_ref; +int SquirrelVM::_CallState = -1; +SquirrelObject* SquirrelVM::_root; +HSQUIRRELVM SquirrelVM::_sandboxVM; +SquirrelObject SquirrelVM::_vm; + + +// Helper struct to keep track of all SQSharedState:s created by SquirrelVM. +#include "../squirrel/sqpcheader.h" +#include "../squirrel/sqvm.h" +struct SQSharedStateNode { + SQSharedStateNode( SQSharedState* ps ); + ~SQSharedStateNode( ); + SQSharedState* m_ps; + SQSharedStateNode* m_nxt; +}; + +// Linked list of shared states +static SQSharedStateNode* g_sqss_fst; + +SQSharedStateNode::SQSharedStateNode( SQSharedState* ps ) : m_ps(ps), m_nxt(g_sqss_fst) { + g_sqss_fst = this; +} + +SQSharedStateNode::~SQSharedStateNode() { + if(m_ps) sq_delete(m_ps,SQSharedState); + delete m_nxt; +} + +static struct SquirrelVM_ModConstr { + ~SquirrelVM_ModConstr(){ + // Delete any shared states we created + delete g_sqss_fst; + g_sqss_fst = NULL; + } +} g_squirrelvm_mod_constr; + + + +SquirrelError::SquirrelError() +{ + const SQChar *s; + sq_getlasterror(SquirrelVM::_VM); + sq_getstring(SquirrelVM::_VM,-1,&s); + if(s) { + desc = s; + } + else { + desc = _SC("unknown error"); + } +} + + +SquirrelVMSys::~SquirrelVMSys() { + // Must take care to release object with the 'ref' VM + PushRefVM( _vm.GetObjectHandle()._unVal.pThread ); + _vm.Reset(); + PopRefVM(); +} + +void SquirrelVMSys::Set( HSQUIRRELVM v ){ + // Must take care to release object with the 'ref' VM + PushRefVM( v ); + _vm = v; + PopRefVM( ); +} + +void SquirrelVMSys::Set( const SquirrelObject& ov ){ + assert( ov.GetObjectHandle()._type==OT_THREAD ); + // Must take care to release object with the 'ref' VM + PushRefVM( ov.GetObjectHandle()._unVal.pThread ); + _vm = ov; + PopRefVM( ); +} + +SquirrelVMSys::operator HSQUIRRELVM () const { + // Avoid const madness + SquirrelObject *pvm = (SquirrelObject*)&_vm; + assert( pvm->GetObjectHandle()._type==OT_THREAD ); + return pvm->GetObjectHandle()._unVal.pThread; +} + + +// When doing a SquirrelObject assignment, a reference using the current +// VM is done. +HSQUIRRELVM g_VM_pushed; +void SquirrelVMSys::PushRefVM( HSQUIRRELVM v ){ + assert( !g_VM_pushed ); + g_VM_pushed = SquirrelVM::_VM; + SquirrelVM::_VM = v; +} + +void SquirrelVMSys::PopRefVM( ){ + SquirrelVM::_VM = g_VM_pushed; + g_VM_pushed = NULL; +} + + +bool SquirrelVM::Init( HSQUIRRELVM v ){ + if( v && v==_VM ) + return true; + + // Do we have a previous state? + Release( ); + + bool created_new = false; + if( !v ){ + // Create a new VM - a root VM with new SharedState. + v = sq_open(1024); + if( !v ) return false; + // Store the associated shared state in a linked list. The state will only + // be destroyed at app shutdown. Often that is fine, but if using many + // VM:s briefly, this allocation is not optimal. + new SQSharedStateNode( _ss(v) ); + created_new = true; + sq_setprintfunc(v,SquirrelVM::PrintFunc, SquirrelVM::PrintFunc); + sq_pushroottable(v); + sqstd_register_iolib(v); + sqstd_register_bloblib(v); + sqstd_register_mathlib(v); + sqstd_register_stringlib(v); +#ifdef SQPLUS_SQUIRRELVM_WITH_SYSTEMLIB + sqstd_register_systemlib(v); +#endif + sqstd_seterrorhandlers(v); + //TODO error handler, compiler error handler + sq_pop(v,1); + } + + // After this we hold a ref + _no_vm_ref = false; + _VM = v; + _vm = v; + + // In the case where Squirrel is ref counted we currently + // hold two references to the VM (since it is created with + // a ref count of 1). In the GC case, it is outside of the + // chain of valid objects, so it is not referenced. Compensate + // in ref counted case. + if( created_new ) + DropVMRefIfRefCounted( v ); + + return true; +} + +bool SquirrelVM::InitNoRef( HSQUIRRELVM v ){ + if( v && v==_VM ) + return true; + + // Do we have a previous state? + Release( ); + + // Set pointer to this VM, without referencing it + _no_vm_ref = true; + _VM = v; + + return true; +} + +/* +void SquirrelVM::Init( HSQUIRRELVM v ) +{ + if( v && v==_VM ) { + return; + } + + // Do we have a previous state? + Release(); + + if( !v ){ + // Create a new VM and own it + _VM = sq_open(1024); + sq_setprintfunc(_VM,SquirrelVM::PrintFunc); + sq_pushroottable(_VM); + sqstd_register_iolib(_VM); + sqstd_register_bloblib(_VM); + sqstd_register_mathlib(_VM); + sqstd_register_stringlib(_VM); + sqstd_seterrorhandlers(_VM); + //TODO error handler, compiler error handler + sq_pop(_VM,1); + } + else { + _VM = v; + } + // After this we hold a ref + _vm = _VM; +} +*/ + +void SquirrelVM::Release() { + // Release root table object if we have one + if( _root ){ + delete _root; + _root = NULL; + } + + // Release our ref on VM - if we should + if( !_no_vm_ref ) + _vm.Reset(); + + _VM = NULL; +} + +void SquirrelVM::DropVMRefIfRefCounted( HSQUIRRELVM v ){ +#ifdef NO_GARBAGE_COLLECTOR + if( v ){ + SQObject t; + t._unVal.pThread = v; + t._type = OT_THREAD; + sq_release( v, &t ); + } +#endif +} + +BOOL SquirrelVM::Update() +{ + //update remote debugger + return TRUE; +} + +void SquirrelVM::PrintFunc(HSQUIRRELVM v,const SQChar* s,...) +{ + static SQChar temp[2048]; + va_list vl; + va_start(vl, s); + scvsprintf( temp,s, vl); + SCPUTS(temp); + va_end(vl); +} + +SquirrelObject SquirrelVM::CompileScript(const SQChar *s) +{ + SquirrelObject ret; + if(SQ_SUCCEEDED(sqstd_loadfile(_VM,s,1))) { + ret.AttachToStackObject(-1); + sq_pop(_VM,1); + return ret; + } + throw SquirrelError(); +} + +SquirrelObject SquirrelVM::CompileBuffer(const SQChar *s,const SQChar * debugInfo) +{ + SquirrelObject ret; + if(SQ_SUCCEEDED(sq_compilebuffer(_VM,s,(int)scstrlen(s)*sizeof(SQChar),debugInfo,1))) { + ret.AttachToStackObject(-1); + sq_pop(_VM,1); + return ret; + } + throw SquirrelError(); +} + +SquirrelObject SquirrelVM::RunScript(const SquirrelObject &o,SquirrelObject *_this) +{ + SquirrelObject ret; + sq_pushobject(_VM,o._o); + if(_this) { + sq_pushobject(_VM,_this->_o); + } + else { + sq_pushroottable(_VM); + } + if(SQ_SUCCEEDED(sq_call(_VM,1,SQTrue,SQ_CALL_RAISE_ERROR))) { + ret.AttachToStackObject(-1); + sq_pop(_VM,2); + return ret; + } + sq_pop(_VM,1); + throw SquirrelError(); + +} + + +BOOL SquirrelVM::BeginCall(const SquirrelObject &func) +{ + if(_CallState != -1) + return FALSE; + _CallState = 1; + sq_pushobject(_VM,func._o); + sq_pushroottable(_VM); + return TRUE; +} + +BOOL SquirrelVM::BeginCall(const SquirrelObject &func,SquirrelObject &_this) +{ + if(_CallState != -1) + throw SquirrelError(_SC("call already initialized")); + _CallState = 1; + sq_pushobject(_VM,func._o); + sq_pushobject(_VM,_this._o); + return TRUE; +} + +#define _CHECK_CALL_STATE \ + if(_CallState == -1) \ + throw SquirrelError(_SC("call not initialized")); + +void SquirrelVM::PushParam(const SquirrelObject &o) +{ + _CHECK_CALL_STATE + sq_pushobject(_VM,o._o); + _CallState++; +} + +void SquirrelVM::PushParam(const SQChar *s) +{ + _CHECK_CALL_STATE + sq_pushstring(_VM,s,-1); + _CallState++; +} + +void SquirrelVM::PushParam(SQInteger n) +{ + _CHECK_CALL_STATE + sq_pushinteger(_VM,n); + _CallState++; +} + +void SquirrelVM::PushParam(SQFloat f) +{ + _CHECK_CALL_STATE + sq_pushfloat(_VM,f); + _CallState++; +} + +void SquirrelVM::PushParamNull() +{ + _CHECK_CALL_STATE + sq_pushnull(_VM); + _CallState++; +} + +void SquirrelVM::PushParam(SQUserPointer up) +{ + _CHECK_CALL_STATE + sq_pushuserpointer(_VM,up); + _CallState++; +} + +SquirrelObject SquirrelVM::EndCall() +{ + SquirrelObject ret; + if(_CallState >= 0) { + int oldtop = sq_gettop(_VM); + int nparams = _CallState; + _CallState = -1; + if(SQ_SUCCEEDED(sq_call(_VM,nparams,SQTrue,SQ_CALL_RAISE_ERROR))) { + ret.AttachToStackObject(-1); + sq_pop(_VM,2); + }else { + sq_settop(_VM,oldtop-(nparams+1)); + throw SquirrelError(); + } + + } + return ret; +} + +SquirrelObject SquirrelVM::CreateInstance(SquirrelObject &oclass) +{ + SquirrelObject ret; + int oldtop = sq_gettop(_VM); + sq_pushobject(_VM,oclass._o); + if(SQ_FAILED(sq_createinstance(_VM,-1))) { + sq_settop(_VM,oldtop); + throw SquirrelError(); + } + ret.AttachToStackObject(-1); + sq_pop(_VM,2); + return ret; +} + +SquirrelObject SquirrelVM::CreateTable() +{ + SquirrelObject ret; + sq_newtable(_VM); + ret.AttachToStackObject(-1); + sq_pop(_VM,1); + return ret; +} + +SquirrelObject SquirrelVM::CreateString(const SQChar *s) +{ + SquirrelObject ret; + sq_pushstring(_VM,s,-1); + ret.AttachToStackObject(-1); + sq_pop(_VM,1); + return ret; +} + + +SquirrelObject SquirrelVM::CreateArray(int size) +{ + SquirrelObject ret; + sq_newarray(_VM,size); + ret.AttachToStackObject(-1); + sq_pop(_VM,1); + return ret; +} + +SquirrelObject SquirrelVM::CreateFunction(SQFUNCTION func) +{ + SquirrelObject ret; + sq_newclosure(_VM,func,0); + ret.AttachToStackObject(-1); + sq_pop(_VM,1); + return ret; +} + +SquirrelObject SquirrelVM::CreateUserData(int size) { + SquirrelObject ret; + sq_newuserdata(_VM,size); + ret.AttachToStackObject(-1); + sq_pop(_VM,1); + return ret; +} + +const SquirrelObject &SquirrelVM::GetRootTable() +{ + if( !_root ){ + sq_pushroottable(_VM); + _root = new SquirrelObject(); + _root->AttachToStackObject(-1); + sq_pop(_VM,1); + } + return *_root; +} + +void SquirrelVM::PushRootTable(void) { + sq_pushroottable(_VM); +} // SquirrelVM::PushRootTable + +// Creates a function in the table or class currently on the stack. +//void CreateFunction(HSQUIRRELVM v,const SQChar * scriptFuncName,SQFUNCTION func,int numParams=0,const SQChar * typeMask=0) { +SquirrelObject SquirrelVM::CreateFunction(SQFUNCTION func,const SQChar * scriptFuncName,const SQChar * typeMask) { + sq_pushstring(_VM,scriptFuncName,-1); + sq_newclosure(_VM,func,0); + SquirrelObject ret; + ret.AttachToStackObject(-1); + SQChar tm[64]; + SQChar * ptm = tm; + int numParams = SQ_MATCHTYPEMASKSTRING; + if (typeMask) { + if (typeMask[0] == '*') { + ptm = 0; // Variable args: don't check parameters. + numParams = 0; // Clear SQ_MATCHTYPEMASKSTRING (does not mean match 0 params. See sq_setparamscheck()). + } else { + if (SCSNPRINTF(tm,sizeof(tm),_SC("t|y|x%s"),typeMask) < 0) { +// sq_throwerror(_VM,_SC("CreateFunction: typeMask string too long.")); + throw SquirrelError(_SC("CreateFunction: typeMask string too long.")); + } // if + } // if + } else { // Need to check object type on stack: table, class, instance, etc. + SCSNPRINTF(tm,sizeof(tm),_SC("%s"),_SC("t|y|x")); // table, class, instance. +// tm[0] = 't'; +// tm[1] = 0; + } // if +#if 0 + sq_setparamscheck(_VM,numParams+1,ptm); // Parameters are table+args (thus, the +1). +#else + if (ptm) { + sq_setparamscheck(_VM,numParams,ptm); // Determine arg count from type string. + } // if +#endif +#ifdef _DEBUG + sq_setnativeclosurename(_VM,-1,scriptFuncName); // For debugging only. +#endif + sq_createslot(_VM,-3); // Create slot in table or class (assigning function to slot at scriptNameFunc). + return ret; +} // SquirrelVM::CreateFunction + +SquirrelObject SquirrelVM::CreateFunction(SquirrelObject & so,SQFUNCTION func,const SQChar * scriptFuncName,const SQChar * typeMask) { + PushObject(so); + SquirrelObject ret = CreateFunction(func,scriptFuncName,typeMask); + Pop(1); + return ret; +} // SquirrelVM::CreateFunction + +// Create a Global function on the root table. +//void CreateFunctionGlobal(HSQUIRRELVM v,const SQChar * scriptFuncName,SQFUNCTION func,int numParams=0,const SQChar * typeMask=0) { +SquirrelObject SquirrelVM::CreateFunctionGlobal(SQFUNCTION func,const SQChar * scriptFuncName,const SQChar * typeMask) { + PushRootTable(); // Push root table. + // CreateFunction(scriptFuncName,func,numParams,typeMask); + SquirrelObject ret = CreateFunction(func,scriptFuncName,typeMask); + Pop(1); // Pop root table. + return ret; +} // SquirrelVM::CreateFunctionGlobal -- cgit v1.2.3