diff options
Diffstat (limited to 'squirrel_3_0_1_stable/squirrel')
28 files changed, 10732 insertions, 10732 deletions
diff --git a/squirrel_3_0_1_stable/squirrel/sqapi.cpp b/squirrel_3_0_1_stable/squirrel/sqapi.cpp index 05338ce23..4c9b4c706 100644 --- a/squirrel_3_0_1_stable/squirrel/sqapi.cpp +++ b/squirrel_3_0_1_stable/squirrel/sqapi.cpp @@ -1,1456 +1,1456 @@ -/*
- see copyright notice in squirrel.h
-*/
-#include "sqpcheader.h"
-#include "sqvm.h"
-#include "sqstring.h"
-#include "sqtable.h"
-#include "sqarray.h"
-#include "sqfuncproto.h"
-#include "sqclosure.h"
-#include "squserdata.h"
-#include "sqcompiler.h"
-#include "sqfuncstate.h"
-#include "sqclass.h"
-
-bool sq_aux_gettypedarg(HSQUIRRELVM v,SQInteger idx,SQObjectType type,SQObjectPtr **o)
-{
- *o = &stack_get(v,idx);
- if(type(**o) != type){
- SQObjectPtr oval = v->PrintObjVal(**o);
- v->Raise_Error(_SC("wrong argument type, expected '%s' got '%.50s'"),IdType2Name(type),_stringval(oval));
- return false;
- }
- return true;
-}
-
-#define _GETSAFE_OBJ(v,idx,type,o) { if(!sq_aux_gettypedarg(v,idx,type,&o)) return SQ_ERROR; }
-
-#define sq_aux_paramscheck(v,count) \
-{ \
- if(sq_gettop(v) < count){ v->Raise_Error(_SC("not enough params in the stack")); return SQ_ERROR; }\
-}
-
-
-SQInteger sq_aux_invalidtype(HSQUIRRELVM v,SQObjectType type)
-{
- scsprintf(_ss(v)->GetScratchPad(100), _SC("unexpected type %s"), IdType2Name(type));
- return sq_throwerror(v, _ss(v)->GetScratchPad(-1));
-}
-
-HSQUIRRELVM sq_open(SQInteger initialstacksize)
-{
- SQSharedState *ss;
- SQVM *v;
- sq_new(ss, SQSharedState);
- ss->Init();
- v = (SQVM *)SQ_MALLOC(sizeof(SQVM));
- new (v) SQVM(ss);
- ss->_root_vm = v;
- if(v->Init(NULL, initialstacksize)) {
- return v;
- } else {
- sq_delete(v, SQVM);
- return NULL;
- }
- return v;
-}
-
-HSQUIRRELVM sq_newthread(HSQUIRRELVM friendvm, SQInteger initialstacksize)
-{
- SQSharedState *ss;
- SQVM *v;
- ss=_ss(friendvm);
-
- v= (SQVM *)SQ_MALLOC(sizeof(SQVM));
- new (v) SQVM(ss);
-
- if(v->Init(friendvm, initialstacksize)) {
- friendvm->Push(v);
- return v;
- } else {
- sq_delete(v, SQVM);
- return NULL;
- }
-}
-
-SQInteger sq_getvmstate(HSQUIRRELVM v)
-{
- if(v->_suspended)
- return SQ_VMSTATE_SUSPENDED;
- else {
- if(v->_callsstacksize != 0) return SQ_VMSTATE_RUNNING;
- else return SQ_VMSTATE_IDLE;
- }
-}
-
-void sq_seterrorhandler(HSQUIRRELVM v)
-{
- SQObject o = stack_get(v, -1);
- if(sq_isclosure(o) || sq_isnativeclosure(o) || sq_isnull(o)) {
- v->_errorhandler = o;
- v->Pop();
- }
-}
-
-void sq_setnativedebughook(HSQUIRRELVM v,SQDEBUGHOOK hook)
-{
- v->_debughook_native = hook;
- v->_debughook_closure.Null();
- v->_debughook = hook?true:false;
-}
-
-void sq_setdebughook(HSQUIRRELVM v)
-{
- SQObject o = stack_get(v,-1);
- if(sq_isclosure(o) || sq_isnativeclosure(o) || sq_isnull(o)) {
- v->_debughook_closure = o;
- v->_debughook_native = NULL;
- v->_debughook = !sq_isnull(o);
- v->Pop();
- }
-}
-
-void sq_close(HSQUIRRELVM v)
-{
- SQSharedState *ss = _ss(v);
- _thread(ss->_root_vm)->Finalize();
- sq_delete(ss, SQSharedState);
-}
-
-SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,const SQChar *sourcename,SQBool raiseerror)
-{
- SQObjectPtr o;
-#ifndef NO_COMPILER
- if(Compile(v, read, p, sourcename, o, raiseerror?true:false, _ss(v)->_debuginfo)) {
- v->Push(SQClosure::Create(_ss(v), _funcproto(o)));
- return SQ_OK;
- }
- return SQ_ERROR;
-#else
- return sq_throwerror(v,_SC("this is a no compiler build"));
-#endif
-}
-
-void sq_enabledebuginfo(HSQUIRRELVM v, SQBool enable)
-{
- _ss(v)->_debuginfo = enable?true:false;
-}
-
-void sq_notifyallexceptions(HSQUIRRELVM v, SQBool enable)
-{
- _ss(v)->_notifyallexceptions = enable?true:false;
-}
-
-void sq_addref(HSQUIRRELVM v,HSQOBJECT *po)
-{
- if(!ISREFCOUNTED(type(*po))) return;
-#ifdef NO_GARBAGE_COLLECTOR
- __AddRef(po->_type,po->_unVal);
-#else
- _ss(v)->_refs_table.AddRef(*po);
-#endif
-}
-
-SQUnsignedInteger sq_getrefcount(HSQUIRRELVM v,HSQOBJECT *po)
-{
- if(!ISREFCOUNTED(type(*po))) return 0;
-#ifdef NO_GARBAGE_COLLECTOR
- return po->_unVal.pRefCounted->_uiRef;
-#else
- return _ss(v)->_refs_table.GetRefCount(*po);
-#endif
-}
-
-SQBool sq_release(HSQUIRRELVM v,HSQOBJECT *po)
-{
- if(!ISREFCOUNTED(type(*po))) return SQTrue;
-#ifdef NO_GARBAGE_COLLECTOR
- bool ret = (po->_unVal.pRefCounted->_uiRef <= 1) ? SQTrue : SQFalse;
- __Release(po->_type,po->_unVal);
- return ret; //the ret val doesn't work(and cannot be fixed)
-#else
- return _ss(v)->_refs_table.Release(*po);
-#endif
-}
-
-const SQChar *sq_objtostring(const HSQOBJECT *o)
-{
- if(sq_type(*o) == OT_STRING) {
- return _stringval(*o);
- }
- return NULL;
-}
-
-SQInteger sq_objtointeger(const HSQOBJECT *o)
-{
- if(sq_isnumeric(*o)) {
- return tointeger(*o);
- }
- return 0;
-}
-
-SQFloat sq_objtofloat(const HSQOBJECT *o)
-{
- if(sq_isnumeric(*o)) {
- return tofloat(*o);
- }
- return 0;
-}
-
-SQBool sq_objtobool(const HSQOBJECT *o)
-{
- if(sq_isbool(*o)) {
- return _integer(*o);
- }
- return SQFalse;
-}
-
-SQUserPointer sq_objtouserpointer(const HSQOBJECT *o)
-{
- if(sq_isuserpointer(*o)) {
- return _userpointer(*o);
- }
- return 0;
-}
-
-void sq_pushnull(HSQUIRRELVM v)
-{
- v->PushNull();
-}
-
-void sq_pushstring(HSQUIRRELVM v,const SQChar *s,SQInteger len)
-{
- if(s)
- v->Push(SQObjectPtr(SQString::Create(_ss(v), s, len)));
- else v->PushNull();
-}
-
-void sq_pushinteger(HSQUIRRELVM v,SQInteger n)
-{
- v->Push(n);
-}
-
-void sq_pushbool(HSQUIRRELVM v,SQBool b)
-{
- v->Push(b?true:false);
-}
-
-void sq_pushfloat(HSQUIRRELVM v,SQFloat n)
-{
- v->Push(n);
-}
-
-void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p)
-{
- v->Push(p);
-}
-
-SQUserPointer sq_newuserdata(HSQUIRRELVM v,SQUnsignedInteger size)
-{
- SQUserData *ud = SQUserData::Create(_ss(v), size);
- v->Push(ud);
- return (SQUserPointer)sq_aligning(ud + 1);
-}
-
-void sq_newtable(HSQUIRRELVM v)
-{
- v->Push(SQTable::Create(_ss(v), 0));
-}
-
-void sq_newtableex(HSQUIRRELVM v,SQInteger initialcapacity)
-{
- v->Push(SQTable::Create(_ss(v), initialcapacity));
-}
-
-void sq_newarray(HSQUIRRELVM v,SQInteger size)
-{
- v->Push(SQArray::Create(_ss(v), size));
-}
-
-SQRESULT sq_newclass(HSQUIRRELVM v,SQBool hasbase)
-{
- SQClass *baseclass = NULL;
- if(hasbase) {
- SQObjectPtr &base = stack_get(v,-1);
- if(type(base) != OT_CLASS)
- return sq_throwerror(v,_SC("invalid base type"));
- baseclass = _class(base);
- }
- SQClass *newclass = SQClass::Create(_ss(v), baseclass);
- if(baseclass) v->Pop();
- v->Push(newclass);
- return SQ_OK;
-}
-
-SQBool sq_instanceof(HSQUIRRELVM v)
-{
- SQObjectPtr &inst = stack_get(v,-1);
- SQObjectPtr &cl = stack_get(v,-2);
- if(type(inst) != OT_INSTANCE || type(cl) != OT_CLASS)
- return sq_throwerror(v,_SC("invalid param type"));
- return _instance(inst)->InstanceOf(_class(cl))?SQTrue:SQFalse;
-}
-
-SQRESULT sq_arrayappend(HSQUIRRELVM v,SQInteger idx)
-{
- sq_aux_paramscheck(v,2);
- SQObjectPtr *arr;
- _GETSAFE_OBJ(v, idx, OT_ARRAY,arr);
- _array(*arr)->Append(v->GetUp(-1));
- v->Pop();
- return SQ_OK;
-}
-
-SQRESULT sq_arraypop(HSQUIRRELVM v,SQInteger idx,SQBool pushval)
-{
- sq_aux_paramscheck(v, 1);
- SQObjectPtr *arr;
- _GETSAFE_OBJ(v, idx, OT_ARRAY,arr);
- if(_array(*arr)->Size() > 0) {
- if(pushval != 0){ v->Push(_array(*arr)->Top()); }
- _array(*arr)->Pop();
- return SQ_OK;
- }
- return sq_throwerror(v, _SC("empty array"));
-}
-
-SQRESULT sq_arrayresize(HSQUIRRELVM v,SQInteger idx,SQInteger newsize)
-{
- sq_aux_paramscheck(v,1);
- SQObjectPtr *arr;
- _GETSAFE_OBJ(v, idx, OT_ARRAY,arr);
- if(newsize >= 0) {
- _array(*arr)->Resize(newsize);
- return SQ_OK;
- }
- return sq_throwerror(v,_SC("negative size"));
-}
-
-
-SQRESULT sq_arrayreverse(HSQUIRRELVM v,SQInteger idx)
-{
- sq_aux_paramscheck(v, 1);
- SQObjectPtr *o;
- _GETSAFE_OBJ(v, idx, OT_ARRAY,o);
- SQArray *arr = _array(*o);
- if(arr->Size() > 0) {
- SQObjectPtr t;
- SQInteger size = arr->Size();
- SQInteger n = size >> 1; size -= 1;
- for(SQInteger i = 0; i < n; i++) {
- t = arr->_values[i];
- arr->_values[i] = arr->_values[size-i];
- arr->_values[size-i] = t;
- }
- return SQ_OK;
- }
- return SQ_OK;
-}
-
-SQRESULT sq_arrayremove(HSQUIRRELVM v,SQInteger idx,SQInteger itemidx)
-{
- sq_aux_paramscheck(v, 1);
- SQObjectPtr *arr;
- _GETSAFE_OBJ(v, idx, OT_ARRAY,arr);
- return _array(*arr)->Remove(itemidx) ? SQ_OK : sq_throwerror(v,_SC("index out of range"));
-}
-
-SQRESULT sq_arrayinsert(HSQUIRRELVM v,SQInteger idx,SQInteger destpos)
-{
- sq_aux_paramscheck(v, 1);
- SQObjectPtr *arr;
- _GETSAFE_OBJ(v, idx, OT_ARRAY,arr);
- SQRESULT ret = _array(*arr)->Insert(destpos, v->GetUp(-1)) ? SQ_OK : sq_throwerror(v,_SC("index out of range"));
- v->Pop();
- return ret;
-}
-
-void sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,SQUnsignedInteger nfreevars)
-{
- SQNativeClosure *nc = SQNativeClosure::Create(_ss(v), func,nfreevars);
- nc->_nparamscheck = 0;
- for(SQUnsignedInteger i = 0; i < nfreevars; i++) {
- nc->_outervalues[i] = v->Top();
- v->Pop();
- }
- v->Push(SQObjectPtr(nc));
-}
-
-SQRESULT sq_getclosureinfo(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger *nparams,SQUnsignedInteger *nfreevars)
-{
- SQObject o = stack_get(v, idx);
- if(type(o) == OT_CLOSURE) {
- SQClosure *c = _closure(o);
- SQFunctionProto *proto = c->_function;
- *nparams = (SQUnsignedInteger)proto->_nparameters;
- *nfreevars = (SQUnsignedInteger)proto->_noutervalues;
- return SQ_OK;
- }
- else if(type(o) == OT_NATIVECLOSURE)
- {
- SQNativeClosure *c = _nativeclosure(o);
- *nparams = (SQUnsignedInteger)c->_nparamscheck;
- *nfreevars = c->_noutervalues;
- return SQ_OK;
- }
- return sq_throwerror(v,_SC("the object is not a closure"));
-}
-
-SQRESULT sq_setnativeclosurename(HSQUIRRELVM v,SQInteger idx,const SQChar *name)
-{
- SQObject o = stack_get(v, idx);
- if(sq_isnativeclosure(o)) {
- SQNativeClosure *nc = _nativeclosure(o);
- nc->_name = SQString::Create(_ss(v),name);
- return SQ_OK;
- }
- return sq_throwerror(v,_SC("the object is not a nativeclosure"));
-}
-
-SQRESULT sq_setparamscheck(HSQUIRRELVM v,SQInteger nparamscheck,const SQChar *typemask)
-{
- SQObject o = stack_get(v, -1);
- if(!sq_isnativeclosure(o))
- return sq_throwerror(v, _SC("native closure expected"));
- SQNativeClosure *nc = _nativeclosure(o);
- nc->_nparamscheck = nparamscheck;
- if(typemask) {
- SQIntVec res;
- if(!CompileTypemask(res, typemask))
- return sq_throwerror(v, _SC("invalid typemask"));
- nc->_typecheck.copy(res);
- }
- else {
- nc->_typecheck.resize(0);
- }
- if(nparamscheck == SQ_MATCHTYPEMASKSTRING) {
- nc->_nparamscheck = nc->_typecheck.size();
- }
- return SQ_OK;
-}
-
-SQRESULT sq_bindenv(HSQUIRRELVM v,SQInteger idx)
-{
- SQObjectPtr &o = stack_get(v,idx);
- if(!sq_isnativeclosure(o) &&
- !sq_isclosure(o))
- return sq_throwerror(v,_SC("the target is not a closure"));
- SQObjectPtr &env = stack_get(v,-1);
- if(!sq_istable(env) &&
- !sq_isclass(env) &&
- !sq_isinstance(env))
- return sq_throwerror(v,_SC("invalid environment"));
- SQWeakRef *w = _refcounted(env)->GetWeakRef(type(env));
- SQObjectPtr ret;
- if(sq_isclosure(o)) {
- SQClosure *c = _closure(o)->Clone();
- __ObjRelease(c->_env);
- c->_env = w;
- __ObjAddRef(c->_env);
- if(_closure(o)->_base) {
- c->_base = _closure(o)->_base;
- __ObjAddRef(c->_base);
- }
- ret = c;
- }
- else { //then must be a native closure
- SQNativeClosure *c = _nativeclosure(o)->Clone();
- __ObjRelease(c->_env);
- c->_env = w;
- __ObjAddRef(c->_env);
- ret = c;
- }
- v->Pop();
- v->Push(ret);
- return SQ_OK;
-}
-
-SQRESULT sq_clear(HSQUIRRELVM v,SQInteger idx)
-{
- SQObject &o=stack_get(v,idx);
- switch(type(o)) {
- case OT_TABLE: _table(o)->Clear(); break;
- case OT_ARRAY: _array(o)->Resize(0); break;
- default:
- return sq_throwerror(v, _SC("clear only works on table and array"));
- break;
-
- }
- return SQ_OK;
-}
-
-void sq_pushroottable(HSQUIRRELVM v)
-{
- v->Push(v->_roottable);
-}
-
-void sq_pushregistrytable(HSQUIRRELVM v)
-{
- v->Push(_ss(v)->_registry);
-}
-
-void sq_pushconsttable(HSQUIRRELVM v)
-{
- v->Push(_ss(v)->_consts);
-}
-
-SQRESULT sq_setroottable(HSQUIRRELVM v)
-{
- SQObject o = stack_get(v, -1);
- if(sq_istable(o) || sq_isnull(o)) {
- v->_roottable = o;
- v->Pop();
- return SQ_OK;
- }
- return sq_throwerror(v, _SC("ivalid type"));
-}
-
-SQRESULT sq_setconsttable(HSQUIRRELVM v)
-{
- SQObject o = stack_get(v, -1);
- if(sq_istable(o)) {
- _ss(v)->_consts = o;
- v->Pop();
- return SQ_OK;
- }
- return sq_throwerror(v, _SC("ivalid type, expected table"));
-}
-
-void sq_setforeignptr(HSQUIRRELVM v,SQUserPointer p)
-{
- v->_foreignptr = p;
-}
-
-SQUserPointer sq_getforeignptr(HSQUIRRELVM v)
-{
- return v->_foreignptr;
-}
-
-void sq_push(HSQUIRRELVM v,SQInteger idx)
-{
- v->Push(stack_get(v, idx));
-}
-
-SQObjectType sq_gettype(HSQUIRRELVM v,SQInteger idx)
-{
- return type(stack_get(v, idx));
-}
-
-
-SQRESULT sq_tostring(HSQUIRRELVM v,SQInteger idx)
-{
- SQObjectPtr &o = stack_get(v, idx);
- SQObjectPtr res;
- if(!v->ToString(o,res)) {
- return SQ_ERROR;
- }
- v->Push(res);
- return SQ_OK;
-}
-
-void sq_tobool(HSQUIRRELVM v, SQInteger idx, SQBool *b)
-{
- SQObjectPtr &o = stack_get(v, idx);
- *b = SQVM::IsFalse(o)?SQFalse:SQTrue;
-}
-
-SQRESULT sq_getinteger(HSQUIRRELVM v,SQInteger idx,SQInteger *i)
-{
- SQObjectPtr &o = stack_get(v, idx);
- if(sq_isnumeric(o)) {
- *i = tointeger(o);
- return SQ_OK;
- }
- return SQ_ERROR;
-}
-
-SQRESULT sq_getfloat(HSQUIRRELVM v,SQInteger idx,SQFloat *f)
-{
- SQObjectPtr &o = stack_get(v, idx);
- if(sq_isnumeric(o)) {
- *f = tofloat(o);
- return SQ_OK;
- }
- return SQ_ERROR;
-}
-
-SQRESULT sq_getbool(HSQUIRRELVM v,SQInteger idx,SQBool *b)
-{
- SQObjectPtr &o = stack_get(v, idx);
- if(sq_isbool(o)) {
- *b = _integer(o);
- return SQ_OK;
- }
- return SQ_ERROR;
-}
-
-SQRESULT sq_getstring(HSQUIRRELVM v,SQInteger idx,const SQChar **c)
-{
- SQObjectPtr *o = NULL;
- _GETSAFE_OBJ(v, idx, OT_STRING,o);
- *c = _stringval(*o);
- return SQ_OK;
-}
-
-SQRESULT sq_getthread(HSQUIRRELVM v,SQInteger idx,HSQUIRRELVM *thread)
-{
- SQObjectPtr *o = NULL;
- _GETSAFE_OBJ(v, idx, OT_THREAD,o);
- *thread = _thread(*o);
- return SQ_OK;
-}
-
-SQRESULT sq_clone(HSQUIRRELVM v,SQInteger idx)
-{
- SQObjectPtr &o = stack_get(v,idx);
- v->PushNull();
- if(!v->Clone(o, stack_get(v, -1))){
- v->Pop();
- return SQ_ERROR;
- }
- return SQ_OK;
-}
-
-SQInteger sq_getsize(HSQUIRRELVM v, SQInteger idx)
-{
- SQObjectPtr &o = stack_get(v, idx);
- SQObjectType type = type(o);
- switch(type) {
- case OT_STRING: return _string(o)->_len;
- case OT_TABLE: return _table(o)->CountUsed();
- case OT_ARRAY: return _array(o)->Size();
- case OT_USERDATA: return _userdata(o)->_size;
- case OT_INSTANCE: return _instance(o)->_class->_udsize;
- case OT_CLASS: return _class(o)->_udsize;
- default:
- return sq_aux_invalidtype(v, type);
- }
-}
-
-SQRESULT sq_getuserdata(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p,SQUserPointer *typetag)
-{
- SQObjectPtr *o = NULL;
- _GETSAFE_OBJ(v, idx, OT_USERDATA,o);
- (*p) = _userdataval(*o);
- if(typetag) *typetag = _userdata(*o)->_typetag;
- return SQ_OK;
-}
-
-SQRESULT sq_settypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer typetag)
-{
- SQObjectPtr &o = stack_get(v,idx);
- switch(type(o)) {
- case OT_USERDATA: _userdata(o)->_typetag = typetag; break;
- case OT_CLASS: _class(o)->_typetag = typetag; break;
- default: return sq_throwerror(v,_SC("invalid object type"));
- }
- return SQ_OK;
-}
-
-SQRESULT sq_getobjtypetag(const HSQOBJECT *o,SQUserPointer * typetag)
-{
- switch(type(*o)) {
- case OT_INSTANCE: *typetag = _instance(*o)->_class->_typetag; break;
- case OT_USERDATA: *typetag = _userdata(*o)->_typetag; break;
- case OT_CLASS: *typetag = _class(*o)->_typetag; break;
- default: return SQ_ERROR;
- }
- return SQ_OK;
-}
-
-SQRESULT sq_gettypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer *typetag)
-{
- SQObjectPtr &o = stack_get(v,idx);
- if(SQ_FAILED(sq_getobjtypetag(&o,typetag)))
- return sq_throwerror(v,_SC("invalid object type"));
- return SQ_OK;
-}
-
-SQRESULT sq_getuserpointer(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p)
-{
- SQObjectPtr *o = NULL;
- _GETSAFE_OBJ(v, idx, OT_USERPOINTER,o);
- (*p) = _userpointer(*o);
- return SQ_OK;
-}
-
-SQRESULT sq_setinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer p)
-{
- SQObjectPtr &o = stack_get(v,idx);
- if(type(o) != OT_INSTANCE) return sq_throwerror(v,_SC("the object is not a class instance"));
- _instance(o)->_userpointer = p;
- return SQ_OK;
-}
-
-SQRESULT sq_setclassudsize(HSQUIRRELVM v, SQInteger idx, SQInteger udsize)
-{
- SQObjectPtr &o = stack_get(v,idx);
- if(type(o) != OT_CLASS) return sq_throwerror(v,_SC("the object is not a class"));
- if(_class(o)->_locked) return sq_throwerror(v,_SC("the class is locked"));
- _class(o)->_udsize = udsize;
- return SQ_OK;
-}
-
-
-SQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p,SQUserPointer typetag)
-{
- SQObjectPtr &o = stack_get(v,idx);
- if(type(o) != OT_INSTANCE) return sq_throwerror(v,_SC("the object is not a class instance"));
- (*p) = _instance(o)->_userpointer;
- if(typetag != 0) {
- SQClass *cl = _instance(o)->_class;
- do{
- if(cl->_typetag == typetag)
- return SQ_OK;
- cl = cl->_base;
- }while(cl != NULL);
- return sq_throwerror(v,_SC("invalid type tag"));
- }
- return SQ_OK;
-}
-
-SQInteger sq_gettop(HSQUIRRELVM v)
-{
- return (v->_top) - v->_stackbase;
-}
-
-void sq_settop(HSQUIRRELVM v, SQInteger newtop)
-{
- SQInteger top = sq_gettop(v);
- if(top > newtop)
- sq_pop(v, top - newtop);
- else
- while(top++ < newtop) sq_pushnull(v);
-}
-
-void sq_pop(HSQUIRRELVM v, SQInteger nelemstopop)
-{
- assert(v->_top >= nelemstopop);
- v->Pop(nelemstopop);
-}
-
-void sq_poptop(HSQUIRRELVM v)
-{
- assert(v->_top >= 1);
- v->Pop();
-}
-
-
-void sq_remove(HSQUIRRELVM v, SQInteger idx)
-{
- v->Remove(idx);
-}
-
-SQInteger sq_cmp(HSQUIRRELVM v)
-{
- SQInteger res;
- v->ObjCmp(stack_get(v, -1), stack_get(v, -2),res);
- return res;
-}
-
-SQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx, SQBool bstatic)
-{
- sq_aux_paramscheck(v, 3);
- SQObjectPtr &self = stack_get(v, idx);
- if(type(self) == OT_TABLE || type(self) == OT_CLASS) {
- SQObjectPtr &key = v->GetUp(-2);
- if(type(key) == OT_NULL) return sq_throwerror(v, _SC("null is not a valid key"));
- v->NewSlot(self, key, v->GetUp(-1),bstatic?true:false);
- v->Pop(2);
- }
- return SQ_OK;
-}
-
-SQRESULT sq_deleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval)
-{
- sq_aux_paramscheck(v, 2);
- SQObjectPtr *self;
- _GETSAFE_OBJ(v, idx, OT_TABLE,self);
- SQObjectPtr &key = v->GetUp(-1);
- if(type(key) == OT_NULL) return sq_throwerror(v, _SC("null is not a valid key"));
- SQObjectPtr res;
- if(!v->DeleteSlot(*self, key, res)){
- return SQ_ERROR;
- }
- if(pushval) v->GetUp(-1) = res;
- else v->Pop();
- return SQ_OK;
-}
-
-SQRESULT sq_set(HSQUIRRELVM v,SQInteger idx)
-{
- SQObjectPtr &self = stack_get(v, idx);
- if(v->Set(self, v->GetUp(-2), v->GetUp(-1),DONT_FALL_BACK)) {
- v->Pop(2);
- return SQ_OK;
- }
- return SQ_ERROR;
-}
-
-SQRESULT sq_rawset(HSQUIRRELVM v,SQInteger idx)
-{
- SQObjectPtr &self = stack_get(v, idx);
- if(type(v->GetUp(-2)) == OT_NULL) return sq_throwerror(v, _SC("null key"));
- switch(type(self)) {
- case OT_TABLE:
- _table(self)->NewSlot(v->GetUp(-2), v->GetUp(-1));
- v->Pop(2);
- return SQ_OK;
- break;
- case OT_CLASS:
- _class(self)->NewSlot(_ss(v), v->GetUp(-2), v->GetUp(-1),false);
- v->Pop(2);
- return SQ_OK;
- break;
- case OT_INSTANCE:
- if(_instance(self)->Set(v->GetUp(-2), v->GetUp(-1))) {
- v->Pop(2);
- return SQ_OK;
- }
- break;
- case OT_ARRAY:
- if(v->Set(self, v->GetUp(-2), v->GetUp(-1),false)) {
- v->Pop(2);
- return SQ_OK;
- }
- break;
- default:
- v->Pop(2);
- return sq_throwerror(v, _SC("rawset works only on array/table/class and instance"));
- }
- v->Raise_IdxError(v->GetUp(-2));return SQ_ERROR;
-}
-
-SQRESULT sq_setdelegate(HSQUIRRELVM v,SQInteger idx)
-{
- SQObjectPtr &self = stack_get(v, idx);
- SQObjectPtr &mt = v->GetUp(-1);
- SQObjectType type = type(self);
- switch(type) {
- case OT_TABLE:
- if(type(mt) == OT_TABLE) {
- if(!_table(self)->SetDelegate(_table(mt))) return sq_throwerror(v, _SC("delagate cycle")); v->Pop();}
- else if(type(mt)==OT_NULL) {
- _table(self)->SetDelegate(NULL); v->Pop(); }
- else return sq_aux_invalidtype(v,type);
- break;
- case OT_USERDATA:
- if(type(mt)==OT_TABLE) {
- _userdata(self)->SetDelegate(_table(mt)); v->Pop(); }
- else if(type(mt)==OT_NULL) {
- _userdata(self)->SetDelegate(NULL); v->Pop(); }
- else return sq_aux_invalidtype(v, type);
- break;
- default:
- return sq_aux_invalidtype(v, type);
- break;
- }
- return SQ_OK;
-}
-
-SQRESULT sq_rawdeleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval)
-{
- sq_aux_paramscheck(v, 2);
- SQObjectPtr *self;
- _GETSAFE_OBJ(v, idx, OT_TABLE,self);
- SQObjectPtr &key = v->GetUp(-1);
- SQObjectPtr t;
- if(_table(*self)->Get(key,t)) {
- _table(*self)->Remove(key);
- }
- if(pushval != 0)
- v->GetUp(-1) = t;
- else
- v->Pop();
- return SQ_OK;
-}
-
-SQRESULT sq_getdelegate(HSQUIRRELVM v,SQInteger idx)
-{
- SQObjectPtr &self=stack_get(v,idx);
- switch(type(self)){
- case OT_TABLE:
- case OT_USERDATA:
- if(!_delegable(self)->_delegate){
- v->PushNull();
- break;
- }
- v->Push(SQObjectPtr(_delegable(self)->_delegate));
- break;
- default: return sq_throwerror(v,_SC("wrong type")); break;
- }
- return SQ_OK;
-
-}
-
-SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx)
-{
- SQObjectPtr &self=stack_get(v,idx);
- if(v->Get(self,v->GetUp(-1),v->GetUp(-1),false,DONT_FALL_BACK))
- return SQ_OK;
- v->Pop();
- return SQ_ERROR;
-}
-
-SQRESULT sq_rawget(HSQUIRRELVM v,SQInteger idx)
-{
- SQObjectPtr &self=stack_get(v,idx);
- switch(type(self)) {
- case OT_TABLE:
- if(_table(self)->Get(v->GetUp(-1),v->GetUp(-1)))
- return SQ_OK;
- break;
- case OT_CLASS:
- if(_class(self)->Get(v->GetUp(-1),v->GetUp(-1)))
- return SQ_OK;
- break;
- case OT_INSTANCE:
- if(_instance(self)->Get(v->GetUp(-1),v->GetUp(-1)))
- return SQ_OK;
- break;
- case OT_ARRAY:{
- SQObjectPtr& key = v->GetUp(-1);
- if(sq_isnumeric(key)){
- if(_array(self)->Get(tointeger(key),v->GetUp(-1))) {
- return SQ_OK;
- }
- }
- else {
- v->Pop();
- return sq_throwerror(v,_SC("invalid index type for an array"));
- }
- }
- break;
- default:
- v->Pop();
- return sq_throwerror(v,_SC("rawget works only on array/table/instance and class"));
- }
- v->Pop();
- return sq_throwerror(v,_SC("the index doesn't exist"));
-}
-
-SQRESULT sq_getstackobj(HSQUIRRELVM v,SQInteger idx,HSQOBJECT *po)
-{
- *po=stack_get(v,idx);
- return SQ_OK;
-}
-
-const SQChar *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger idx)
-{
- SQUnsignedInteger cstksize=v->_callsstacksize;
- SQUnsignedInteger lvl=(cstksize-level)-1;
- SQInteger stackbase=v->_stackbase;
- if(lvl<cstksize){
- for(SQUnsignedInteger i=0;i<level;i++){
- SQVM::CallInfo &ci=v->_callsstack[(cstksize-i)-1];
- stackbase-=ci._prevstkbase;
- }
- SQVM::CallInfo &ci=v->_callsstack[lvl];
- if(type(ci._closure)!=OT_CLOSURE)
- return NULL;
- SQClosure *c=_closure(ci._closure);
- SQFunctionProto *func=c->_function;
- if(func->_noutervalues > (SQInteger)idx) {
- v->Push(*_outer(c->_outervalues[idx])->_valptr);
- return _stringval(func->_outervalues[idx]._name);
- }
- idx -= func->_noutervalues;
- return func->GetLocal(v,stackbase,idx,(SQInteger)(ci._ip-func->_instructions)-1);
- }
- return NULL;
-}
-
-void sq_pushobject(HSQUIRRELVM v,HSQOBJECT obj)
-{
- v->Push(SQObjectPtr(obj));
-}
-
-void sq_resetobject(HSQOBJECT *po)
-{
- po->_unVal.pUserPointer=NULL;po->_type=OT_NULL;
-}
-
-SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err)
-{
- v->_lasterror=SQString::Create(_ss(v),err);
- return SQ_ERROR;
-}
-
-SQRESULT sq_throwobject(HSQUIRRELVM v)
-{
- v->_lasterror = v->GetUp(-1);
- v->Pop();
- return SQ_ERROR;
-}
-
-
-void sq_reseterror(HSQUIRRELVM v)
-{
- v->_lasterror.Null();
-}
-
-void sq_getlasterror(HSQUIRRELVM v)
-{
- v->Push(v->_lasterror);
-}
-
-SQRESULT sq_reservestack(HSQUIRRELVM v,SQInteger nsize)
-{
- if (((SQUnsignedInteger)v->_top + nsize) > v->_stack.size()) {
- if(v->_nmetamethodscall) {
- return sq_throwerror(v,_SC("cannot resize stack while in a metamethod"));
- }
- v->_stack.resize(v->_stack.size() + ((v->_top + nsize) - v->_stack.size()));
- }
- return SQ_OK;
-}
-
-SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool raiseerror)
-{
- if(type(v->GetUp(-1))==OT_GENERATOR){
- v->PushNull(); //retval
- if(!v->Execute(v->GetUp(-2),0,v->_top,v->GetUp(-1),raiseerror,SQVM::ET_RESUME_GENERATOR))
- {v->Raise_Error(v->_lasterror); return SQ_ERROR;}
- if(!retval)
- v->Pop();
- return SQ_OK;
- }
- return sq_throwerror(v,_SC("only generators can be resumed"));
-}
-
-SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool raiseerror)
-{
- SQObjectPtr res;
- if(v->Call(v->GetUp(-(params+1)),params,v->_top-params,res,raiseerror?true:false)){
-
- if(!v->_suspended) {
- v->Pop(params);//pop closure and args
- }
- if(retval){
- v->Push(res); return SQ_OK;
- }
- return SQ_OK;
- }
- else {
- v->Pop(params);
- return SQ_ERROR;
- }
- if(!v->_suspended)
- v->Pop(params);
- return sq_throwerror(v,_SC("call failed"));
-}
-
-SQRESULT sq_suspendvm(HSQUIRRELVM v)
-{
- return v->Suspend();
-}
-
-SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool wakeupret,SQBool retval,SQBool raiseerror,SQBool throwerror)
-{
- SQObjectPtr ret;
- if(!v->_suspended)
- return sq_throwerror(v,_SC("cannot resume a vm that is not running any code"));
- SQInteger target = v->_suspended_target;
- if(wakeupret) {
- if(target != -1) {
- v->GetAt(v->_stackbase+v->_suspended_target)=v->GetUp(-1); //retval
- }
- v->Pop();
- } else if(target != -1) { v->GetAt(v->_stackbase+v->_suspended_target).Null(); }
- SQObjectPtr dummy;
- if(!v->Execute(dummy,-1,-1,ret,raiseerror,throwerror?SQVM::ET_RESUME_THROW_VM : SQVM::ET_RESUME_VM)) {
- return SQ_ERROR;
- }
- if(retval)
- v->Push(ret);
- return SQ_OK;
-}
-
-void sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook)
-{
- if(sq_gettop(v) >= 1){
- SQObjectPtr &ud=stack_get(v,idx);
- switch( type(ud) ) {
- case OT_USERDATA: _userdata(ud)->_hook = hook; break;
- case OT_INSTANCE: _instance(ud)->_hook = hook; break;
- case OT_CLASS: _class(ud)->_hook = hook; break;
- default: break; //shutup compiler
- }
- }
-}
-
-void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f)
-{
- _ss(v)->_compilererrorhandler = f;
-}
-
-SQRESULT sq_writeclosure(HSQUIRRELVM v,SQWRITEFUNC w,SQUserPointer up)
-{
- SQObjectPtr *o = NULL;
- _GETSAFE_OBJ(v, -1, OT_CLOSURE,o);
- unsigned short tag = SQ_BYTECODE_STREAM_TAG;
- if(w(up,&tag,2) != 2)
- return sq_throwerror(v,_SC("io error"));
- if(!_closure(*o)->Save(v,up,w))
- return SQ_ERROR;
- return SQ_OK;
-}
-
-SQRESULT sq_readclosure(HSQUIRRELVM v,SQREADFUNC r,SQUserPointer up)
-{
- SQObjectPtr closure;
-
- unsigned short tag;
- if(r(up,&tag,2) != 2)
- return sq_throwerror(v,_SC("io error"));
- if(tag != SQ_BYTECODE_STREAM_TAG)
- return sq_throwerror(v,_SC("invalid stream"));
- if(!SQClosure::Load(v,up,r,closure))
- return SQ_ERROR;
- v->Push(closure);
- return SQ_OK;
-}
-
-SQChar *sq_getscratchpad(HSQUIRRELVM v,SQInteger minsize)
-{
- return _ss(v)->GetScratchPad(minsize);
-}
-
-SQRESULT sq_resurrectunreachable(HSQUIRRELVM v)
-{
-#ifndef NO_GARBAGE_COLLECTOR
- _ss(v)->ResurrectUnreachable(v);
- return SQ_OK;
-#else
- return sq_throwerror(v,_SC("sq_resurrectunreachable requires a garbage collector build"));
-#endif
-}
-
-SQInteger sq_collectgarbage(HSQUIRRELVM v)
-{
-#ifndef NO_GARBAGE_COLLECTOR
- return _ss(v)->CollectGarbage(v);
-#else
- return -1;
-#endif
-}
-
-SQRESULT sq_getcallee(HSQUIRRELVM v)
-{
- if(v->_callsstacksize > 1)
- {
- v->Push(v->_callsstack[v->_callsstacksize - 2]._closure);
- return SQ_OK;
- }
- return sq_throwerror(v,_SC("no closure in the calls stack"));
-}
-
-const SQChar *sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval)
-{
- SQObjectPtr &self=stack_get(v,idx);
- const SQChar *name = NULL;
- switch(type(self))
- {
- case OT_CLOSURE:{
- SQClosure *clo = _closure(self);
- SQFunctionProto *fp = clo->_function;
- if(((SQUnsignedInteger)fp->_noutervalues) > nval) {
- v->Push(*(_outer(clo->_outervalues[nval])->_valptr));
- SQOuterVar &ov = fp->_outervalues[nval];
- name = _stringval(ov._name);
- }
- }
- break;
- case OT_NATIVECLOSURE:{
- SQNativeClosure *clo = _nativeclosure(self);
- if(clo->_noutervalues > nval) {
- v->Push(clo->_outervalues[nval]);
- name = _SC("@NATIVE");
- }
- }
- break;
- default: break; //shutup compiler
- }
- return name;
-}
-
-SQRESULT sq_setfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval)
-{
- SQObjectPtr &self=stack_get(v,idx);
- switch(type(self))
- {
- case OT_CLOSURE:{
- SQFunctionProto *fp = _closure(self)->_function;
- if(((SQUnsignedInteger)fp->_noutervalues) > nval){
- *(_outer(_closure(self)->_outervalues[nval])->_valptr) = stack_get(v,-1);
- }
- else return sq_throwerror(v,_SC("invalid free var index"));
- }
- break;
- case OT_NATIVECLOSURE:
- if(_nativeclosure(self)->_noutervalues > nval){
- _nativeclosure(self)->_outervalues[nval] = stack_get(v,-1);
- }
- else return sq_throwerror(v,_SC("invalid free var index"));
- break;
- default:
- return sq_aux_invalidtype(v,type(self));
- }
- v->Pop();
- return SQ_OK;
-}
-
-SQRESULT sq_setattributes(HSQUIRRELVM v,SQInteger idx)
-{
- SQObjectPtr *o = NULL;
- _GETSAFE_OBJ(v, idx, OT_CLASS,o);
- SQObjectPtr &key = stack_get(v,-2);
- SQObjectPtr &val = stack_get(v,-1);
- SQObjectPtr attrs;
- if(type(key) == OT_NULL) {
- attrs = _class(*o)->_attributes;
- _class(*o)->_attributes = val;
- v->Pop(2);
- v->Push(attrs);
- return SQ_OK;
- }else if(_class(*o)->GetAttributes(key,attrs)) {
- _class(*o)->SetAttributes(key,val);
- v->Pop(2);
- v->Push(attrs);
- return SQ_OK;
- }
- return sq_throwerror(v,_SC("wrong index"));
-}
-
-SQRESULT sq_getattributes(HSQUIRRELVM v,SQInteger idx)
-{
- SQObjectPtr *o = NULL;
- _GETSAFE_OBJ(v, idx, OT_CLASS,o);
- SQObjectPtr &key = stack_get(v,-1);
- SQObjectPtr attrs;
- if(type(key) == OT_NULL) {
- attrs = _class(*o)->_attributes;
- v->Pop();
- v->Push(attrs);
- return SQ_OK;
- }
- else if(_class(*o)->GetAttributes(key,attrs)) {
- v->Pop();
- v->Push(attrs);
- return SQ_OK;
- }
- return sq_throwerror(v,_SC("wrong index"));
-}
-
-SQRESULT sq_getmemberhandle(HSQUIRRELVM v,SQInteger idx,HSQMEMBERHANDLE *handle)
-{
- SQObjectPtr *o = NULL;
- _GETSAFE_OBJ(v, idx, OT_CLASS,o);
- SQObjectPtr &key = stack_get(v,-1);
- SQTable *m = _class(*o)->_members;
- SQObjectPtr val;
- if(m->Get(key,val)) {
- handle->_static = _isfield(val) ? SQFalse : SQTrue;
- handle->_index = _member_idx(val);
- v->Pop();
- return SQ_OK;
- }
- return sq_throwerror(v,_SC("wrong index"));
-}
-
-SQRESULT _getmemberbyhandle(HSQUIRRELVM v,SQObjectPtr &self,HSQMEMBERHANDLE *handle,SQObjectPtr *&val)
-{
- switch(type(self)) {
- case OT_INSTANCE: {
- SQInstance *i = _instance(self);
- if(handle->_static) {
- SQClass *c = i->_class;
- val = &c->_methods[handle->_index].val;
- }
- else {
- val = &i->_values[handle->_index];
-
- }
- }
- break;
- case OT_CLASS: {
- SQClass *c = _class(self);
- if(handle->_static) {
- val = &c->_methods[handle->_index].val;
- }
- else {
- val = &c->_defaultvalues[handle->_index].val;
- }
- }
- break;
- default:
- return sq_throwerror(v,_SC("wrong type(expected class or instance)"));
- }
- return SQ_OK;
-}
-
-SQRESULT sq_getbyhandle(HSQUIRRELVM v,SQInteger idx,HSQMEMBERHANDLE *handle)
-{
- SQObjectPtr &self = stack_get(v,idx);
- SQObjectPtr *val = NULL;
- if(SQ_FAILED(_getmemberbyhandle(v,self,handle,val))) {
- return SQ_ERROR;
- }
- v->Push(_realval(*val));
- return SQ_OK;
-}
-
-SQRESULT sq_setbyhandle(HSQUIRRELVM v,SQInteger idx,HSQMEMBERHANDLE *handle)
-{
- SQObjectPtr &self = stack_get(v,idx);
- SQObjectPtr &newval = stack_get(v,-1);
- SQObjectPtr *val = NULL;
- if(SQ_FAILED(_getmemberbyhandle(v,self,handle,val))) {
- return SQ_ERROR;
- }
- *val = newval;
- v->Pop();
- return SQ_OK;
-}
-
-SQRESULT sq_getbase(HSQUIRRELVM v,SQInteger idx)
-{
- SQObjectPtr *o = NULL;
- _GETSAFE_OBJ(v, idx, OT_CLASS,o);
- if(_class(*o)->_base)
- v->Push(SQObjectPtr(_class(*o)->_base));
- else
- v->PushNull();
- return SQ_OK;
-}
-
-SQRESULT sq_getclass(HSQUIRRELVM v,SQInteger idx)
-{
- SQObjectPtr *o = NULL;
- _GETSAFE_OBJ(v, idx, OT_INSTANCE,o);
- v->Push(SQObjectPtr(_instance(*o)->_class));
- return SQ_OK;
-}
-
-SQRESULT sq_createinstance(HSQUIRRELVM v,SQInteger idx)
-{
- SQObjectPtr *o = NULL;
- _GETSAFE_OBJ(v, idx, OT_CLASS,o);
- v->Push(_class(*o)->CreateInstance());
- return SQ_OK;
-}
-
-void sq_weakref(HSQUIRRELVM v,SQInteger idx)
-{
- SQObject &o=stack_get(v,idx);
- if(ISREFCOUNTED(type(o))) {
- v->Push(_refcounted(o)->GetWeakRef(type(o)));
- return;
- }
- v->Push(o);
-}
-
-SQRESULT sq_getweakrefval(HSQUIRRELVM v,SQInteger idx)
-{
- SQObjectPtr &o = stack_get(v,idx);
- if(type(o) != OT_WEAKREF) {
- return sq_throwerror(v,_SC("the object must be a weakref"));
- }
- v->Push(_weakref(o)->_obj);
- return SQ_OK;
-}
-
-SQRESULT sq_getdefaultdelegate(HSQUIRRELVM v,SQObjectType t)
-{
- SQSharedState *ss = _ss(v);
- switch(t) {
- case OT_TABLE: v->Push(ss->_table_default_delegate); break;
- case OT_ARRAY: v->Push(ss->_array_default_delegate); break;
- case OT_STRING: v->Push(ss->_string_default_delegate); break;
- case OT_INTEGER: case OT_FLOAT: v->Push(ss->_number_default_delegate); break;
- case OT_GENERATOR: v->Push(ss->_generator_default_delegate); break;
- case OT_CLOSURE: case OT_NATIVECLOSURE: v->Push(ss->_closure_default_delegate); break;
- case OT_THREAD: v->Push(ss->_thread_default_delegate); break;
- case OT_CLASS: v->Push(ss->_class_default_delegate); break;
- case OT_INSTANCE: v->Push(ss->_instance_default_delegate); break;
- case OT_WEAKREF: v->Push(ss->_weakref_default_delegate); break;
- default: return sq_throwerror(v,_SC("the type doesn't have a default delegate"));
- }
- return SQ_OK;
-}
-
-SQRESULT sq_next(HSQUIRRELVM v,SQInteger idx)
-{
- SQObjectPtr o=stack_get(v,idx),&refpos = stack_get(v,-1),realkey,val;
- if(type(o) == OT_GENERATOR) {
- return sq_throwerror(v,_SC("cannot iterate a generator"));
- }
- int faketojump;
- if(!v->FOREACH_OP(o,realkey,val,refpos,0,666,faketojump))
- return SQ_ERROR;
- if(faketojump != 666) {
- v->Push(realkey);
- v->Push(val);
- return SQ_OK;
- }
- return SQ_ERROR;
-}
-
-struct BufState{
- const SQChar *buf;
- SQInteger ptr;
- SQInteger size;
-};
-
-SQInteger buf_lexfeed(SQUserPointer file)
-{
- BufState *buf=(BufState*)file;
- if(buf->size<(buf->ptr+1))
- return 0;
- return buf->buf[buf->ptr++];
-}
-
-SQRESULT sq_compilebuffer(HSQUIRRELVM v,const SQChar *s,SQInteger size,const SQChar *sourcename,SQBool raiseerror) {
- BufState buf;
- buf.buf = s;
- buf.size = size;
- buf.ptr = 0;
- return sq_compile(v, buf_lexfeed, &buf, sourcename, raiseerror);
-}
-
-void sq_move(HSQUIRRELVM dest,HSQUIRRELVM src,SQInteger idx)
-{
- dest->Push(stack_get(src,idx));
-}
-
-void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc,SQPRINTFUNCTION errfunc)
-{
- _ss(v)->_printfunc = printfunc;
- _ss(v)->_errorfunc = errfunc;
-}
-
-SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v)
-{
- return _ss(v)->_printfunc;
-}
-
-SQPRINTFUNCTION sq_geterrorfunc(HSQUIRRELVM v)
-{
- return _ss(v)->_errorfunc;
-}
-
-void *sq_malloc(SQUnsignedInteger size)
-{
- return SQ_MALLOC(size);
-}
-
-void *sq_realloc(void* p,SQUnsignedInteger oldsize,SQUnsignedInteger newsize)
-{
- return SQ_REALLOC(p,oldsize,newsize);
-}
-
-void sq_free(void *p,SQUnsignedInteger size)
-{
- SQ_FREE(p,size);
-}
+/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include "sqvm.h" +#include "sqstring.h" +#include "sqtable.h" +#include "sqarray.h" +#include "sqfuncproto.h" +#include "sqclosure.h" +#include "squserdata.h" +#include "sqcompiler.h" +#include "sqfuncstate.h" +#include "sqclass.h" + +bool sq_aux_gettypedarg(HSQUIRRELVM v,SQInteger idx,SQObjectType type,SQObjectPtr **o) +{ + *o = &stack_get(v,idx); + if(type(**o) != type){ + SQObjectPtr oval = v->PrintObjVal(**o); + v->Raise_Error(_SC("wrong argument type, expected '%s' got '%.50s'"),IdType2Name(type),_stringval(oval)); + return false; + } + return true; +} + +#define _GETSAFE_OBJ(v,idx,type,o) { if(!sq_aux_gettypedarg(v,idx,type,&o)) return SQ_ERROR; } + +#define sq_aux_paramscheck(v,count) \ +{ \ + if(sq_gettop(v) < count){ v->Raise_Error(_SC("not enough params in the stack")); return SQ_ERROR; }\ +} + + +SQInteger sq_aux_invalidtype(HSQUIRRELVM v,SQObjectType type) +{ + scsprintf(_ss(v)->GetScratchPad(100), _SC("unexpected type %s"), IdType2Name(type)); + return sq_throwerror(v, _ss(v)->GetScratchPad(-1)); +} + +HSQUIRRELVM sq_open(SQInteger initialstacksize) +{ + SQSharedState *ss; + SQVM *v; + sq_new(ss, SQSharedState); + ss->Init(); + v = (SQVM *)SQ_MALLOC(sizeof(SQVM)); + new (v) SQVM(ss); + ss->_root_vm = v; + if(v->Init(NULL, initialstacksize)) { + return v; + } else { + sq_delete(v, SQVM); + return NULL; + } + return v; +} + +HSQUIRRELVM sq_newthread(HSQUIRRELVM friendvm, SQInteger initialstacksize) +{ + SQSharedState *ss; + SQVM *v; + ss=_ss(friendvm); + + v= (SQVM *)SQ_MALLOC(sizeof(SQVM)); + new (v) SQVM(ss); + + if(v->Init(friendvm, initialstacksize)) { + friendvm->Push(v); + return v; + } else { + sq_delete(v, SQVM); + return NULL; + } +} + +SQInteger sq_getvmstate(HSQUIRRELVM v) +{ + if(v->_suspended) + return SQ_VMSTATE_SUSPENDED; + else { + if(v->_callsstacksize != 0) return SQ_VMSTATE_RUNNING; + else return SQ_VMSTATE_IDLE; + } +} + +void sq_seterrorhandler(HSQUIRRELVM v) +{ + SQObject o = stack_get(v, -1); + if(sq_isclosure(o) || sq_isnativeclosure(o) || sq_isnull(o)) { + v->_errorhandler = o; + v->Pop(); + } +} + +void sq_setnativedebughook(HSQUIRRELVM v,SQDEBUGHOOK hook) +{ + v->_debughook_native = hook; + v->_debughook_closure.Null(); + v->_debughook = hook?true:false; +} + +void sq_setdebughook(HSQUIRRELVM v) +{ + SQObject o = stack_get(v,-1); + if(sq_isclosure(o) || sq_isnativeclosure(o) || sq_isnull(o)) { + v->_debughook_closure = o; + v->_debughook_native = NULL; + v->_debughook = !sq_isnull(o); + v->Pop(); + } +} + +void sq_close(HSQUIRRELVM v) +{ + SQSharedState *ss = _ss(v); + _thread(ss->_root_vm)->Finalize(); + sq_delete(ss, SQSharedState); +} + +SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,const SQChar *sourcename,SQBool raiseerror) +{ + SQObjectPtr o; +#ifndef NO_COMPILER + if(Compile(v, read, p, sourcename, o, raiseerror?true:false, _ss(v)->_debuginfo)) { + v->Push(SQClosure::Create(_ss(v), _funcproto(o))); + return SQ_OK; + } + return SQ_ERROR; +#else + return sq_throwerror(v,_SC("this is a no compiler build")); +#endif +} + +void sq_enabledebuginfo(HSQUIRRELVM v, SQBool enable) +{ + _ss(v)->_debuginfo = enable?true:false; +} + +void sq_notifyallexceptions(HSQUIRRELVM v, SQBool enable) +{ + _ss(v)->_notifyallexceptions = enable?true:false; +} + +void sq_addref(HSQUIRRELVM v,HSQOBJECT *po) +{ + if(!ISREFCOUNTED(type(*po))) return; +#ifdef NO_GARBAGE_COLLECTOR + __AddRef(po->_type,po->_unVal); +#else + _ss(v)->_refs_table.AddRef(*po); +#endif +} + +SQUnsignedInteger sq_getrefcount(HSQUIRRELVM v,HSQOBJECT *po) +{ + if(!ISREFCOUNTED(type(*po))) return 0; +#ifdef NO_GARBAGE_COLLECTOR + return po->_unVal.pRefCounted->_uiRef; +#else + return _ss(v)->_refs_table.GetRefCount(*po); +#endif +} + +SQBool sq_release(HSQUIRRELVM v,HSQOBJECT *po) +{ + if(!ISREFCOUNTED(type(*po))) return SQTrue; +#ifdef NO_GARBAGE_COLLECTOR + bool ret = (po->_unVal.pRefCounted->_uiRef <= 1) ? SQTrue : SQFalse; + __Release(po->_type,po->_unVal); + return ret; //the ret val doesn't work(and cannot be fixed) +#else + return _ss(v)->_refs_table.Release(*po); +#endif +} + +const SQChar *sq_objtostring(const HSQOBJECT *o) +{ + if(sq_type(*o) == OT_STRING) { + return _stringval(*o); + } + return NULL; +} + +SQInteger sq_objtointeger(const HSQOBJECT *o) +{ + if(sq_isnumeric(*o)) { + return tointeger(*o); + } + return 0; +} + +SQFloat sq_objtofloat(const HSQOBJECT *o) +{ + if(sq_isnumeric(*o)) { + return tofloat(*o); + } + return 0; +} + +SQBool sq_objtobool(const HSQOBJECT *o) +{ + if(sq_isbool(*o)) { + return _integer(*o); + } + return SQFalse; +} + +SQUserPointer sq_objtouserpointer(const HSQOBJECT *o) +{ + if(sq_isuserpointer(*o)) { + return _userpointer(*o); + } + return 0; +} + +void sq_pushnull(HSQUIRRELVM v) +{ + v->PushNull(); +} + +void sq_pushstring(HSQUIRRELVM v,const SQChar *s,SQInteger len) +{ + if(s) + v->Push(SQObjectPtr(SQString::Create(_ss(v), s, len))); + else v->PushNull(); +} + +void sq_pushinteger(HSQUIRRELVM v,SQInteger n) +{ + v->Push(n); +} + +void sq_pushbool(HSQUIRRELVM v,SQBool b) +{ + v->Push(b?true:false); +} + +void sq_pushfloat(HSQUIRRELVM v,SQFloat n) +{ + v->Push(n); +} + +void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p) +{ + v->Push(p); +} + +SQUserPointer sq_newuserdata(HSQUIRRELVM v,SQUnsignedInteger size) +{ + SQUserData *ud = SQUserData::Create(_ss(v), size); + v->Push(ud); + return (SQUserPointer)sq_aligning(ud + 1); +} + +void sq_newtable(HSQUIRRELVM v) +{ + v->Push(SQTable::Create(_ss(v), 0)); +} + +void sq_newtableex(HSQUIRRELVM v,SQInteger initialcapacity) +{ + v->Push(SQTable::Create(_ss(v), initialcapacity)); +} + +void sq_newarray(HSQUIRRELVM v,SQInteger size) +{ + v->Push(SQArray::Create(_ss(v), size)); +} + +SQRESULT sq_newclass(HSQUIRRELVM v,SQBool hasbase) +{ + SQClass *baseclass = NULL; + if(hasbase) { + SQObjectPtr &base = stack_get(v,-1); + if(type(base) != OT_CLASS) + return sq_throwerror(v,_SC("invalid base type")); + baseclass = _class(base); + } + SQClass *newclass = SQClass::Create(_ss(v), baseclass); + if(baseclass) v->Pop(); + v->Push(newclass); + return SQ_OK; +} + +SQBool sq_instanceof(HSQUIRRELVM v) +{ + SQObjectPtr &inst = stack_get(v,-1); + SQObjectPtr &cl = stack_get(v,-2); + if(type(inst) != OT_INSTANCE || type(cl) != OT_CLASS) + return sq_throwerror(v,_SC("invalid param type")); + return _instance(inst)->InstanceOf(_class(cl))?SQTrue:SQFalse; +} + +SQRESULT sq_arrayappend(HSQUIRRELVM v,SQInteger idx) +{ + sq_aux_paramscheck(v,2); + SQObjectPtr *arr; + _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); + _array(*arr)->Append(v->GetUp(-1)); + v->Pop(); + return SQ_OK; +} + +SQRESULT sq_arraypop(HSQUIRRELVM v,SQInteger idx,SQBool pushval) +{ + sq_aux_paramscheck(v, 1); + SQObjectPtr *arr; + _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); + if(_array(*arr)->Size() > 0) { + if(pushval != 0){ v->Push(_array(*arr)->Top()); } + _array(*arr)->Pop(); + return SQ_OK; + } + return sq_throwerror(v, _SC("empty array")); +} + +SQRESULT sq_arrayresize(HSQUIRRELVM v,SQInteger idx,SQInteger newsize) +{ + sq_aux_paramscheck(v,1); + SQObjectPtr *arr; + _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); + if(newsize >= 0) { + _array(*arr)->Resize(newsize); + return SQ_OK; + } + return sq_throwerror(v,_SC("negative size")); +} + + +SQRESULT sq_arrayreverse(HSQUIRRELVM v,SQInteger idx) +{ + sq_aux_paramscheck(v, 1); + SQObjectPtr *o; + _GETSAFE_OBJ(v, idx, OT_ARRAY,o); + SQArray *arr = _array(*o); + if(arr->Size() > 0) { + SQObjectPtr t; + SQInteger size = arr->Size(); + SQInteger n = size >> 1; size -= 1; + for(SQInteger i = 0; i < n; i++) { + t = arr->_values[i]; + arr->_values[i] = arr->_values[size-i]; + arr->_values[size-i] = t; + } + return SQ_OK; + } + return SQ_OK; +} + +SQRESULT sq_arrayremove(HSQUIRRELVM v,SQInteger idx,SQInteger itemidx) +{ + sq_aux_paramscheck(v, 1); + SQObjectPtr *arr; + _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); + return _array(*arr)->Remove(itemidx) ? SQ_OK : sq_throwerror(v,_SC("index out of range")); +} + +SQRESULT sq_arrayinsert(HSQUIRRELVM v,SQInteger idx,SQInteger destpos) +{ + sq_aux_paramscheck(v, 1); + SQObjectPtr *arr; + _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); + SQRESULT ret = _array(*arr)->Insert(destpos, v->GetUp(-1)) ? SQ_OK : sq_throwerror(v,_SC("index out of range")); + v->Pop(); + return ret; +} + +void sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,SQUnsignedInteger nfreevars) +{ + SQNativeClosure *nc = SQNativeClosure::Create(_ss(v), func,nfreevars); + nc->_nparamscheck = 0; + for(SQUnsignedInteger i = 0; i < nfreevars; i++) { + nc->_outervalues[i] = v->Top(); + v->Pop(); + } + v->Push(SQObjectPtr(nc)); +} + +SQRESULT sq_getclosureinfo(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger *nparams,SQUnsignedInteger *nfreevars) +{ + SQObject o = stack_get(v, idx); + if(type(o) == OT_CLOSURE) { + SQClosure *c = _closure(o); + SQFunctionProto *proto = c->_function; + *nparams = (SQUnsignedInteger)proto->_nparameters; + *nfreevars = (SQUnsignedInteger)proto->_noutervalues; + return SQ_OK; + } + else if(type(o) == OT_NATIVECLOSURE) + { + SQNativeClosure *c = _nativeclosure(o); + *nparams = (SQUnsignedInteger)c->_nparamscheck; + *nfreevars = c->_noutervalues; + return SQ_OK; + } + return sq_throwerror(v,_SC("the object is not a closure")); +} + +SQRESULT sq_setnativeclosurename(HSQUIRRELVM v,SQInteger idx,const SQChar *name) +{ + SQObject o = stack_get(v, idx); + if(sq_isnativeclosure(o)) { + SQNativeClosure *nc = _nativeclosure(o); + nc->_name = SQString::Create(_ss(v),name); + return SQ_OK; + } + return sq_throwerror(v,_SC("the object is not a nativeclosure")); +} + +SQRESULT sq_setparamscheck(HSQUIRRELVM v,SQInteger nparamscheck,const SQChar *typemask) +{ + SQObject o = stack_get(v, -1); + if(!sq_isnativeclosure(o)) + return sq_throwerror(v, _SC("native closure expected")); + SQNativeClosure *nc = _nativeclosure(o); + nc->_nparamscheck = nparamscheck; + if(typemask) { + SQIntVec res; + if(!CompileTypemask(res, typemask)) + return sq_throwerror(v, _SC("invalid typemask")); + nc->_typecheck.copy(res); + } + else { + nc->_typecheck.resize(0); + } + if(nparamscheck == SQ_MATCHTYPEMASKSTRING) { + nc->_nparamscheck = nc->_typecheck.size(); + } + return SQ_OK; +} + +SQRESULT sq_bindenv(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &o = stack_get(v,idx); + if(!sq_isnativeclosure(o) && + !sq_isclosure(o)) + return sq_throwerror(v,_SC("the target is not a closure")); + SQObjectPtr &env = stack_get(v,-1); + if(!sq_istable(env) && + !sq_isclass(env) && + !sq_isinstance(env)) + return sq_throwerror(v,_SC("invalid environment")); + SQWeakRef *w = _refcounted(env)->GetWeakRef(type(env)); + SQObjectPtr ret; + if(sq_isclosure(o)) { + SQClosure *c = _closure(o)->Clone(); + __ObjRelease(c->_env); + c->_env = w; + __ObjAddRef(c->_env); + if(_closure(o)->_base) { + c->_base = _closure(o)->_base; + __ObjAddRef(c->_base); + } + ret = c; + } + else { //then must be a native closure + SQNativeClosure *c = _nativeclosure(o)->Clone(); + __ObjRelease(c->_env); + c->_env = w; + __ObjAddRef(c->_env); + ret = c; + } + v->Pop(); + v->Push(ret); + return SQ_OK; +} + +SQRESULT sq_clear(HSQUIRRELVM v,SQInteger idx) +{ + SQObject &o=stack_get(v,idx); + switch(type(o)) { + case OT_TABLE: _table(o)->Clear(); break; + case OT_ARRAY: _array(o)->Resize(0); break; + default: + return sq_throwerror(v, _SC("clear only works on table and array")); + break; + + } + return SQ_OK; +} + +void sq_pushroottable(HSQUIRRELVM v) +{ + v->Push(v->_roottable); +} + +void sq_pushregistrytable(HSQUIRRELVM v) +{ + v->Push(_ss(v)->_registry); +} + +void sq_pushconsttable(HSQUIRRELVM v) +{ + v->Push(_ss(v)->_consts); +} + +SQRESULT sq_setroottable(HSQUIRRELVM v) +{ + SQObject o = stack_get(v, -1); + if(sq_istable(o) || sq_isnull(o)) { + v->_roottable = o; + v->Pop(); + return SQ_OK; + } + return sq_throwerror(v, _SC("ivalid type")); +} + +SQRESULT sq_setconsttable(HSQUIRRELVM v) +{ + SQObject o = stack_get(v, -1); + if(sq_istable(o)) { + _ss(v)->_consts = o; + v->Pop(); + return SQ_OK; + } + return sq_throwerror(v, _SC("ivalid type, expected table")); +} + +void sq_setforeignptr(HSQUIRRELVM v,SQUserPointer p) +{ + v->_foreignptr = p; +} + +SQUserPointer sq_getforeignptr(HSQUIRRELVM v) +{ + return v->_foreignptr; +} + +void sq_push(HSQUIRRELVM v,SQInteger idx) +{ + v->Push(stack_get(v, idx)); +} + +SQObjectType sq_gettype(HSQUIRRELVM v,SQInteger idx) +{ + return type(stack_get(v, idx)); +} + + +SQRESULT sq_tostring(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &o = stack_get(v, idx); + SQObjectPtr res; + if(!v->ToString(o,res)) { + return SQ_ERROR; + } + v->Push(res); + return SQ_OK; +} + +void sq_tobool(HSQUIRRELVM v, SQInteger idx, SQBool *b) +{ + SQObjectPtr &o = stack_get(v, idx); + *b = SQVM::IsFalse(o)?SQFalse:SQTrue; +} + +SQRESULT sq_getinteger(HSQUIRRELVM v,SQInteger idx,SQInteger *i) +{ + SQObjectPtr &o = stack_get(v, idx); + if(sq_isnumeric(o)) { + *i = tointeger(o); + return SQ_OK; + } + return SQ_ERROR; +} + +SQRESULT sq_getfloat(HSQUIRRELVM v,SQInteger idx,SQFloat *f) +{ + SQObjectPtr &o = stack_get(v, idx); + if(sq_isnumeric(o)) { + *f = tofloat(o); + return SQ_OK; + } + return SQ_ERROR; +} + +SQRESULT sq_getbool(HSQUIRRELVM v,SQInteger idx,SQBool *b) +{ + SQObjectPtr &o = stack_get(v, idx); + if(sq_isbool(o)) { + *b = _integer(o); + return SQ_OK; + } + return SQ_ERROR; +} + +SQRESULT sq_getstring(HSQUIRRELVM v,SQInteger idx,const SQChar **c) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_STRING,o); + *c = _stringval(*o); + return SQ_OK; +} + +SQRESULT sq_getthread(HSQUIRRELVM v,SQInteger idx,HSQUIRRELVM *thread) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_THREAD,o); + *thread = _thread(*o); + return SQ_OK; +} + +SQRESULT sq_clone(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &o = stack_get(v,idx); + v->PushNull(); + if(!v->Clone(o, stack_get(v, -1))){ + v->Pop(); + return SQ_ERROR; + } + return SQ_OK; +} + +SQInteger sq_getsize(HSQUIRRELVM v, SQInteger idx) +{ + SQObjectPtr &o = stack_get(v, idx); + SQObjectType type = type(o); + switch(type) { + case OT_STRING: return _string(o)->_len; + case OT_TABLE: return _table(o)->CountUsed(); + case OT_ARRAY: return _array(o)->Size(); + case OT_USERDATA: return _userdata(o)->_size; + case OT_INSTANCE: return _instance(o)->_class->_udsize; + case OT_CLASS: return _class(o)->_udsize; + default: + return sq_aux_invalidtype(v, type); + } +} + +SQRESULT sq_getuserdata(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p,SQUserPointer *typetag) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_USERDATA,o); + (*p) = _userdataval(*o); + if(typetag) *typetag = _userdata(*o)->_typetag; + return SQ_OK; +} + +SQRESULT sq_settypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer typetag) +{ + SQObjectPtr &o = stack_get(v,idx); + switch(type(o)) { + case OT_USERDATA: _userdata(o)->_typetag = typetag; break; + case OT_CLASS: _class(o)->_typetag = typetag; break; + default: return sq_throwerror(v,_SC("invalid object type")); + } + return SQ_OK; +} + +SQRESULT sq_getobjtypetag(const HSQOBJECT *o,SQUserPointer * typetag) +{ + switch(type(*o)) { + case OT_INSTANCE: *typetag = _instance(*o)->_class->_typetag; break; + case OT_USERDATA: *typetag = _userdata(*o)->_typetag; break; + case OT_CLASS: *typetag = _class(*o)->_typetag; break; + default: return SQ_ERROR; + } + return SQ_OK; +} + +SQRESULT sq_gettypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer *typetag) +{ + SQObjectPtr &o = stack_get(v,idx); + if(SQ_FAILED(sq_getobjtypetag(&o,typetag))) + return sq_throwerror(v,_SC("invalid object type")); + return SQ_OK; +} + +SQRESULT sq_getuserpointer(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_USERPOINTER,o); + (*p) = _userpointer(*o); + return SQ_OK; +} + +SQRESULT sq_setinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer p) +{ + SQObjectPtr &o = stack_get(v,idx); + if(type(o) != OT_INSTANCE) return sq_throwerror(v,_SC("the object is not a class instance")); + _instance(o)->_userpointer = p; + return SQ_OK; +} + +SQRESULT sq_setclassudsize(HSQUIRRELVM v, SQInteger idx, SQInteger udsize) +{ + SQObjectPtr &o = stack_get(v,idx); + if(type(o) != OT_CLASS) return sq_throwerror(v,_SC("the object is not a class")); + if(_class(o)->_locked) return sq_throwerror(v,_SC("the class is locked")); + _class(o)->_udsize = udsize; + return SQ_OK; +} + + +SQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p,SQUserPointer typetag) +{ + SQObjectPtr &o = stack_get(v,idx); + if(type(o) != OT_INSTANCE) return sq_throwerror(v,_SC("the object is not a class instance")); + (*p) = _instance(o)->_userpointer; + if(typetag != 0) { + SQClass *cl = _instance(o)->_class; + do{ + if(cl->_typetag == typetag) + return SQ_OK; + cl = cl->_base; + }while(cl != NULL); + return sq_throwerror(v,_SC("invalid type tag")); + } + return SQ_OK; +} + +SQInteger sq_gettop(HSQUIRRELVM v) +{ + return (v->_top) - v->_stackbase; +} + +void sq_settop(HSQUIRRELVM v, SQInteger newtop) +{ + SQInteger top = sq_gettop(v); + if(top > newtop) + sq_pop(v, top - newtop); + else + while(top++ < newtop) sq_pushnull(v); +} + +void sq_pop(HSQUIRRELVM v, SQInteger nelemstopop) +{ + assert(v->_top >= nelemstopop); + v->Pop(nelemstopop); +} + +void sq_poptop(HSQUIRRELVM v) +{ + assert(v->_top >= 1); + v->Pop(); +} + + +void sq_remove(HSQUIRRELVM v, SQInteger idx) +{ + v->Remove(idx); +} + +SQInteger sq_cmp(HSQUIRRELVM v) +{ + SQInteger res; + v->ObjCmp(stack_get(v, -1), stack_get(v, -2),res); + return res; +} + +SQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx, SQBool bstatic) +{ + sq_aux_paramscheck(v, 3); + SQObjectPtr &self = stack_get(v, idx); + if(type(self) == OT_TABLE || type(self) == OT_CLASS) { + SQObjectPtr &key = v->GetUp(-2); + if(type(key) == OT_NULL) return sq_throwerror(v, _SC("null is not a valid key")); + v->NewSlot(self, key, v->GetUp(-1),bstatic?true:false); + v->Pop(2); + } + return SQ_OK; +} + +SQRESULT sq_deleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval) +{ + sq_aux_paramscheck(v, 2); + SQObjectPtr *self; + _GETSAFE_OBJ(v, idx, OT_TABLE,self); + SQObjectPtr &key = v->GetUp(-1); + if(type(key) == OT_NULL) return sq_throwerror(v, _SC("null is not a valid key")); + SQObjectPtr res; + if(!v->DeleteSlot(*self, key, res)){ + return SQ_ERROR; + } + if(pushval) v->GetUp(-1) = res; + else v->Pop(); + return SQ_OK; +} + +SQRESULT sq_set(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &self = stack_get(v, idx); + if(v->Set(self, v->GetUp(-2), v->GetUp(-1),DONT_FALL_BACK)) { + v->Pop(2); + return SQ_OK; + } + return SQ_ERROR; +} + +SQRESULT sq_rawset(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &self = stack_get(v, idx); + if(type(v->GetUp(-2)) == OT_NULL) return sq_throwerror(v, _SC("null key")); + switch(type(self)) { + case OT_TABLE: + _table(self)->NewSlot(v->GetUp(-2), v->GetUp(-1)); + v->Pop(2); + return SQ_OK; + break; + case OT_CLASS: + _class(self)->NewSlot(_ss(v), v->GetUp(-2), v->GetUp(-1),false); + v->Pop(2); + return SQ_OK; + break; + case OT_INSTANCE: + if(_instance(self)->Set(v->GetUp(-2), v->GetUp(-1))) { + v->Pop(2); + return SQ_OK; + } + break; + case OT_ARRAY: + if(v->Set(self, v->GetUp(-2), v->GetUp(-1),false)) { + v->Pop(2); + return SQ_OK; + } + break; + default: + v->Pop(2); + return sq_throwerror(v, _SC("rawset works only on array/table/class and instance")); + } + v->Raise_IdxError(v->GetUp(-2));return SQ_ERROR; +} + +SQRESULT sq_setdelegate(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &self = stack_get(v, idx); + SQObjectPtr &mt = v->GetUp(-1); + SQObjectType type = type(self); + switch(type) { + case OT_TABLE: + if(type(mt) == OT_TABLE) { + if(!_table(self)->SetDelegate(_table(mt))) return sq_throwerror(v, _SC("delagate cycle")); v->Pop();} + else if(type(mt)==OT_NULL) { + _table(self)->SetDelegate(NULL); v->Pop(); } + else return sq_aux_invalidtype(v,type); + break; + case OT_USERDATA: + if(type(mt)==OT_TABLE) { + _userdata(self)->SetDelegate(_table(mt)); v->Pop(); } + else if(type(mt)==OT_NULL) { + _userdata(self)->SetDelegate(NULL); v->Pop(); } + else return sq_aux_invalidtype(v, type); + break; + default: + return sq_aux_invalidtype(v, type); + break; + } + return SQ_OK; +} + +SQRESULT sq_rawdeleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval) +{ + sq_aux_paramscheck(v, 2); + SQObjectPtr *self; + _GETSAFE_OBJ(v, idx, OT_TABLE,self); + SQObjectPtr &key = v->GetUp(-1); + SQObjectPtr t; + if(_table(*self)->Get(key,t)) { + _table(*self)->Remove(key); + } + if(pushval != 0) + v->GetUp(-1) = t; + else + v->Pop(); + return SQ_OK; +} + +SQRESULT sq_getdelegate(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &self=stack_get(v,idx); + switch(type(self)){ + case OT_TABLE: + case OT_USERDATA: + if(!_delegable(self)->_delegate){ + v->PushNull(); + break; + } + v->Push(SQObjectPtr(_delegable(self)->_delegate)); + break; + default: return sq_throwerror(v,_SC("wrong type")); break; + } + return SQ_OK; + +} + +SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &self=stack_get(v,idx); + if(v->Get(self,v->GetUp(-1),v->GetUp(-1),false,DONT_FALL_BACK)) + return SQ_OK; + v->Pop(); + return SQ_ERROR; +} + +SQRESULT sq_rawget(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &self=stack_get(v,idx); + switch(type(self)) { + case OT_TABLE: + if(_table(self)->Get(v->GetUp(-1),v->GetUp(-1))) + return SQ_OK; + break; + case OT_CLASS: + if(_class(self)->Get(v->GetUp(-1),v->GetUp(-1))) + return SQ_OK; + break; + case OT_INSTANCE: + if(_instance(self)->Get(v->GetUp(-1),v->GetUp(-1))) + return SQ_OK; + break; + case OT_ARRAY:{ + SQObjectPtr& key = v->GetUp(-1); + if(sq_isnumeric(key)){ + if(_array(self)->Get(tointeger(key),v->GetUp(-1))) { + return SQ_OK; + } + } + else { + v->Pop(); + return sq_throwerror(v,_SC("invalid index type for an array")); + } + } + break; + default: + v->Pop(); + return sq_throwerror(v,_SC("rawget works only on array/table/instance and class")); + } + v->Pop(); + return sq_throwerror(v,_SC("the index doesn't exist")); +} + +SQRESULT sq_getstackobj(HSQUIRRELVM v,SQInteger idx,HSQOBJECT *po) +{ + *po=stack_get(v,idx); + return SQ_OK; +} + +const SQChar *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger idx) +{ + SQUnsignedInteger cstksize=v->_callsstacksize; + SQUnsignedInteger lvl=(cstksize-level)-1; + SQInteger stackbase=v->_stackbase; + if(lvl<cstksize){ + for(SQUnsignedInteger i=0;i<level;i++){ + SQVM::CallInfo &ci=v->_callsstack[(cstksize-i)-1]; + stackbase-=ci._prevstkbase; + } + SQVM::CallInfo &ci=v->_callsstack[lvl]; + if(type(ci._closure)!=OT_CLOSURE) + return NULL; + SQClosure *c=_closure(ci._closure); + SQFunctionProto *func=c->_function; + if(func->_noutervalues > (SQInteger)idx) { + v->Push(*_outer(c->_outervalues[idx])->_valptr); + return _stringval(func->_outervalues[idx]._name); + } + idx -= func->_noutervalues; + return func->GetLocal(v,stackbase,idx,(SQInteger)(ci._ip-func->_instructions)-1); + } + return NULL; +} + +void sq_pushobject(HSQUIRRELVM v,HSQOBJECT obj) +{ + v->Push(SQObjectPtr(obj)); +} + +void sq_resetobject(HSQOBJECT *po) +{ + po->_unVal.pUserPointer=NULL;po->_type=OT_NULL; +} + +SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err) +{ + v->_lasterror=SQString::Create(_ss(v),err); + return SQ_ERROR; +} + +SQRESULT sq_throwobject(HSQUIRRELVM v) +{ + v->_lasterror = v->GetUp(-1); + v->Pop(); + return SQ_ERROR; +} + + +void sq_reseterror(HSQUIRRELVM v) +{ + v->_lasterror.Null(); +} + +void sq_getlasterror(HSQUIRRELVM v) +{ + v->Push(v->_lasterror); +} + +SQRESULT sq_reservestack(HSQUIRRELVM v,SQInteger nsize) +{ + if (((SQUnsignedInteger)v->_top + nsize) > v->_stack.size()) { + if(v->_nmetamethodscall) { + return sq_throwerror(v,_SC("cannot resize stack while in a metamethod")); + } + v->_stack.resize(v->_stack.size() + ((v->_top + nsize) - v->_stack.size())); + } + return SQ_OK; +} + +SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool raiseerror) +{ + if(type(v->GetUp(-1))==OT_GENERATOR){ + v->PushNull(); //retval + if(!v->Execute(v->GetUp(-2),0,v->_top,v->GetUp(-1),raiseerror,SQVM::ET_RESUME_GENERATOR)) + {v->Raise_Error(v->_lasterror); return SQ_ERROR;} + if(!retval) + v->Pop(); + return SQ_OK; + } + return sq_throwerror(v,_SC("only generators can be resumed")); +} + +SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool raiseerror) +{ + SQObjectPtr res; + if(v->Call(v->GetUp(-(params+1)),params,v->_top-params,res,raiseerror?true:false)){ + + if(!v->_suspended) { + v->Pop(params);//pop closure and args + } + if(retval){ + v->Push(res); return SQ_OK; + } + return SQ_OK; + } + else { + v->Pop(params); + return SQ_ERROR; + } + if(!v->_suspended) + v->Pop(params); + return sq_throwerror(v,_SC("call failed")); +} + +SQRESULT sq_suspendvm(HSQUIRRELVM v) +{ + return v->Suspend(); +} + +SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool wakeupret,SQBool retval,SQBool raiseerror,SQBool throwerror) +{ + SQObjectPtr ret; + if(!v->_suspended) + return sq_throwerror(v,_SC("cannot resume a vm that is not running any code")); + SQInteger target = v->_suspended_target; + if(wakeupret) { + if(target != -1) { + v->GetAt(v->_stackbase+v->_suspended_target)=v->GetUp(-1); //retval + } + v->Pop(); + } else if(target != -1) { v->GetAt(v->_stackbase+v->_suspended_target).Null(); } + SQObjectPtr dummy; + if(!v->Execute(dummy,-1,-1,ret,raiseerror,throwerror?SQVM::ET_RESUME_THROW_VM : SQVM::ET_RESUME_VM)) { + return SQ_ERROR; + } + if(retval) + v->Push(ret); + return SQ_OK; +} + +void sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook) +{ + if(sq_gettop(v) >= 1){ + SQObjectPtr &ud=stack_get(v,idx); + switch( type(ud) ) { + case OT_USERDATA: _userdata(ud)->_hook = hook; break; + case OT_INSTANCE: _instance(ud)->_hook = hook; break; + case OT_CLASS: _class(ud)->_hook = hook; break; + default: break; //shutup compiler + } + } +} + +void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f) +{ + _ss(v)->_compilererrorhandler = f; +} + +SQRESULT sq_writeclosure(HSQUIRRELVM v,SQWRITEFUNC w,SQUserPointer up) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, -1, OT_CLOSURE,o); + unsigned short tag = SQ_BYTECODE_STREAM_TAG; + if(w(up,&tag,2) != 2) + return sq_throwerror(v,_SC("io error")); + if(!_closure(*o)->Save(v,up,w)) + return SQ_ERROR; + return SQ_OK; +} + +SQRESULT sq_readclosure(HSQUIRRELVM v,SQREADFUNC r,SQUserPointer up) +{ + SQObjectPtr closure; + + unsigned short tag; + if(r(up,&tag,2) != 2) + return sq_throwerror(v,_SC("io error")); + if(tag != SQ_BYTECODE_STREAM_TAG) + return sq_throwerror(v,_SC("invalid stream")); + if(!SQClosure::Load(v,up,r,closure)) + return SQ_ERROR; + v->Push(closure); + return SQ_OK; +} + +SQChar *sq_getscratchpad(HSQUIRRELVM v,SQInteger minsize) +{ + return _ss(v)->GetScratchPad(minsize); +} + +SQRESULT sq_resurrectunreachable(HSQUIRRELVM v) +{ +#ifndef NO_GARBAGE_COLLECTOR + _ss(v)->ResurrectUnreachable(v); + return SQ_OK; +#else + return sq_throwerror(v,_SC("sq_resurrectunreachable requires a garbage collector build")); +#endif +} + +SQInteger sq_collectgarbage(HSQUIRRELVM v) +{ +#ifndef NO_GARBAGE_COLLECTOR + return _ss(v)->CollectGarbage(v); +#else + return -1; +#endif +} + +SQRESULT sq_getcallee(HSQUIRRELVM v) +{ + if(v->_callsstacksize > 1) + { + v->Push(v->_callsstack[v->_callsstacksize - 2]._closure); + return SQ_OK; + } + return sq_throwerror(v,_SC("no closure in the calls stack")); +} + +const SQChar *sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval) +{ + SQObjectPtr &self=stack_get(v,idx); + const SQChar *name = NULL; + switch(type(self)) + { + case OT_CLOSURE:{ + SQClosure *clo = _closure(self); + SQFunctionProto *fp = clo->_function; + if(((SQUnsignedInteger)fp->_noutervalues) > nval) { + v->Push(*(_outer(clo->_outervalues[nval])->_valptr)); + SQOuterVar &ov = fp->_outervalues[nval]; + name = _stringval(ov._name); + } + } + break; + case OT_NATIVECLOSURE:{ + SQNativeClosure *clo = _nativeclosure(self); + if(clo->_noutervalues > nval) { + v->Push(clo->_outervalues[nval]); + name = _SC("@NATIVE"); + } + } + break; + default: break; //shutup compiler + } + return name; +} + +SQRESULT sq_setfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval) +{ + SQObjectPtr &self=stack_get(v,idx); + switch(type(self)) + { + case OT_CLOSURE:{ + SQFunctionProto *fp = _closure(self)->_function; + if(((SQUnsignedInteger)fp->_noutervalues) > nval){ + *(_outer(_closure(self)->_outervalues[nval])->_valptr) = stack_get(v,-1); + } + else return sq_throwerror(v,_SC("invalid free var index")); + } + break; + case OT_NATIVECLOSURE: + if(_nativeclosure(self)->_noutervalues > nval){ + _nativeclosure(self)->_outervalues[nval] = stack_get(v,-1); + } + else return sq_throwerror(v,_SC("invalid free var index")); + break; + default: + return sq_aux_invalidtype(v,type(self)); + } + v->Pop(); + return SQ_OK; +} + +SQRESULT sq_setattributes(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_CLASS,o); + SQObjectPtr &key = stack_get(v,-2); + SQObjectPtr &val = stack_get(v,-1); + SQObjectPtr attrs; + if(type(key) == OT_NULL) { + attrs = _class(*o)->_attributes; + _class(*o)->_attributes = val; + v->Pop(2); + v->Push(attrs); + return SQ_OK; + }else if(_class(*o)->GetAttributes(key,attrs)) { + _class(*o)->SetAttributes(key,val); + v->Pop(2); + v->Push(attrs); + return SQ_OK; + } + return sq_throwerror(v,_SC("wrong index")); +} + +SQRESULT sq_getattributes(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_CLASS,o); + SQObjectPtr &key = stack_get(v,-1); + SQObjectPtr attrs; + if(type(key) == OT_NULL) { + attrs = _class(*o)->_attributes; + v->Pop(); + v->Push(attrs); + return SQ_OK; + } + else if(_class(*o)->GetAttributes(key,attrs)) { + v->Pop(); + v->Push(attrs); + return SQ_OK; + } + return sq_throwerror(v,_SC("wrong index")); +} + +SQRESULT sq_getmemberhandle(HSQUIRRELVM v,SQInteger idx,HSQMEMBERHANDLE *handle) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_CLASS,o); + SQObjectPtr &key = stack_get(v,-1); + SQTable *m = _class(*o)->_members; + SQObjectPtr val; + if(m->Get(key,val)) { + handle->_static = _isfield(val) ? SQFalse : SQTrue; + handle->_index = _member_idx(val); + v->Pop(); + return SQ_OK; + } + return sq_throwerror(v,_SC("wrong index")); +} + +SQRESULT _getmemberbyhandle(HSQUIRRELVM v,SQObjectPtr &self,HSQMEMBERHANDLE *handle,SQObjectPtr *&val) +{ + switch(type(self)) { + case OT_INSTANCE: { + SQInstance *i = _instance(self); + if(handle->_static) { + SQClass *c = i->_class; + val = &c->_methods[handle->_index].val; + } + else { + val = &i->_values[handle->_index]; + + } + } + break; + case OT_CLASS: { + SQClass *c = _class(self); + if(handle->_static) { + val = &c->_methods[handle->_index].val; + } + else { + val = &c->_defaultvalues[handle->_index].val; + } + } + break; + default: + return sq_throwerror(v,_SC("wrong type(expected class or instance)")); + } + return SQ_OK; +} + +SQRESULT sq_getbyhandle(HSQUIRRELVM v,SQInteger idx,HSQMEMBERHANDLE *handle) +{ + SQObjectPtr &self = stack_get(v,idx); + SQObjectPtr *val = NULL; + if(SQ_FAILED(_getmemberbyhandle(v,self,handle,val))) { + return SQ_ERROR; + } + v->Push(_realval(*val)); + return SQ_OK; +} + +SQRESULT sq_setbyhandle(HSQUIRRELVM v,SQInteger idx,HSQMEMBERHANDLE *handle) +{ + SQObjectPtr &self = stack_get(v,idx); + SQObjectPtr &newval = stack_get(v,-1); + SQObjectPtr *val = NULL; + if(SQ_FAILED(_getmemberbyhandle(v,self,handle,val))) { + return SQ_ERROR; + } + *val = newval; + v->Pop(); + return SQ_OK; +} + +SQRESULT sq_getbase(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_CLASS,o); + if(_class(*o)->_base) + v->Push(SQObjectPtr(_class(*o)->_base)); + else + v->PushNull(); + return SQ_OK; +} + +SQRESULT sq_getclass(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_INSTANCE,o); + v->Push(SQObjectPtr(_instance(*o)->_class)); + return SQ_OK; +} + +SQRESULT sq_createinstance(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_CLASS,o); + v->Push(_class(*o)->CreateInstance()); + return SQ_OK; +} + +void sq_weakref(HSQUIRRELVM v,SQInteger idx) +{ + SQObject &o=stack_get(v,idx); + if(ISREFCOUNTED(type(o))) { + v->Push(_refcounted(o)->GetWeakRef(type(o))); + return; + } + v->Push(o); +} + +SQRESULT sq_getweakrefval(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &o = stack_get(v,idx); + if(type(o) != OT_WEAKREF) { + return sq_throwerror(v,_SC("the object must be a weakref")); + } + v->Push(_weakref(o)->_obj); + return SQ_OK; +} + +SQRESULT sq_getdefaultdelegate(HSQUIRRELVM v,SQObjectType t) +{ + SQSharedState *ss = _ss(v); + switch(t) { + case OT_TABLE: v->Push(ss->_table_default_delegate); break; + case OT_ARRAY: v->Push(ss->_array_default_delegate); break; + case OT_STRING: v->Push(ss->_string_default_delegate); break; + case OT_INTEGER: case OT_FLOAT: v->Push(ss->_number_default_delegate); break; + case OT_GENERATOR: v->Push(ss->_generator_default_delegate); break; + case OT_CLOSURE: case OT_NATIVECLOSURE: v->Push(ss->_closure_default_delegate); break; + case OT_THREAD: v->Push(ss->_thread_default_delegate); break; + case OT_CLASS: v->Push(ss->_class_default_delegate); break; + case OT_INSTANCE: v->Push(ss->_instance_default_delegate); break; + case OT_WEAKREF: v->Push(ss->_weakref_default_delegate); break; + default: return sq_throwerror(v,_SC("the type doesn't have a default delegate")); + } + return SQ_OK; +} + +SQRESULT sq_next(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr o=stack_get(v,idx),&refpos = stack_get(v,-1),realkey,val; + if(type(o) == OT_GENERATOR) { + return sq_throwerror(v,_SC("cannot iterate a generator")); + } + int faketojump; + if(!v->FOREACH_OP(o,realkey,val,refpos,0,666,faketojump)) + return SQ_ERROR; + if(faketojump != 666) { + v->Push(realkey); + v->Push(val); + return SQ_OK; + } + return SQ_ERROR; +} + +struct BufState{ + const SQChar *buf; + SQInteger ptr; + SQInteger size; +}; + +SQInteger buf_lexfeed(SQUserPointer file) +{ + BufState *buf=(BufState*)file; + if(buf->size<(buf->ptr+1)) + return 0; + return buf->buf[buf->ptr++]; +} + +SQRESULT sq_compilebuffer(HSQUIRRELVM v,const SQChar *s,SQInteger size,const SQChar *sourcename,SQBool raiseerror) { + BufState buf; + buf.buf = s; + buf.size = size; + buf.ptr = 0; + return sq_compile(v, buf_lexfeed, &buf, sourcename, raiseerror); +} + +void sq_move(HSQUIRRELVM dest,HSQUIRRELVM src,SQInteger idx) +{ + dest->Push(stack_get(src,idx)); +} + +void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc,SQPRINTFUNCTION errfunc) +{ + _ss(v)->_printfunc = printfunc; + _ss(v)->_errorfunc = errfunc; +} + +SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v) +{ + return _ss(v)->_printfunc; +} + +SQPRINTFUNCTION sq_geterrorfunc(HSQUIRRELVM v) +{ + return _ss(v)->_errorfunc; +} + +void *sq_malloc(SQUnsignedInteger size) +{ + return SQ_MALLOC(size); +} + +void *sq_realloc(void* p,SQUnsignedInteger oldsize,SQUnsignedInteger newsize) +{ + return SQ_REALLOC(p,oldsize,newsize); +} + +void sq_free(void *p,SQUnsignedInteger size) +{ + SQ_FREE(p,size); +} diff --git a/squirrel_3_0_1_stable/squirrel/sqarray.h b/squirrel_3_0_1_stable/squirrel/sqarray.h index c3a57abcc..e9b746657 100644 --- a/squirrel_3_0_1_stable/squirrel/sqarray.h +++ b/squirrel_3_0_1_stable/squirrel/sqarray.h @@ -1,94 +1,94 @@ -/* see copyright notice in squirrel.h */
-#ifndef _SQARRAY_H_
-#define _SQARRAY_H_
-
-struct SQArray : public CHAINABLE_OBJ
-{
-private:
- SQArray(SQSharedState *ss,SQInteger nsize){_values.resize(nsize); INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);}
- ~SQArray()
- {
- REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);
- }
-public:
- static SQArray* Create(SQSharedState *ss,SQInteger nInitialSize){
- SQArray *newarray=(SQArray*)SQ_MALLOC(sizeof(SQArray));
- new (newarray) SQArray(ss,nInitialSize);
- return newarray;
- }
-#ifndef NO_GARBAGE_COLLECTOR
- void Mark(SQCollectable **chain);
- SQObjectType GetType() {return OT_ARRAY;}
-#endif
- void Finalize(){
- _values.resize(0);
- }
- bool Get(const SQInteger nidx,SQObjectPtr &val)
- {
- if(nidx>=0 && nidx<(SQInteger)_values.size()){
- SQObjectPtr &o = _values[nidx];
- val = _realval(o);
- return true;
- }
- else return false;
- }
- bool Set(const SQInteger nidx,const SQObjectPtr &val)
- {
- if(nidx>=0 && nidx<(SQInteger)_values.size()){
- _values[nidx]=val;
- return true;
- }
- else return false;
- }
- SQInteger Next(const SQObjectPtr &refpos,SQObjectPtr &outkey,SQObjectPtr &outval)
- {
- SQUnsignedInteger idx=TranslateIndex(refpos);
- while(idx<_values.size()){
- //first found
- outkey=(SQInteger)idx;
- SQObjectPtr &o = _values[idx];
- outval = _realval(o);
- //return idx for the next iteration
- return ++idx;
- }
- //nothing to iterate anymore
- return -1;
- }
- SQArray *Clone(){SQArray *anew=Create(_opt_ss(this),0); anew->_values.copy(_values); return anew; }
- SQInteger Size() const {return _values.size();}
- void Resize(SQInteger size)
- {
- SQObjectPtr _null;
- Resize(size,_null);
- }
- void Resize(SQInteger size,SQObjectPtr &fill) { _values.resize(size,fill); ShrinkIfNeeded(); }
- void Reserve(SQInteger size) { _values.reserve(size); }
- void Append(const SQObject &o){_values.push_back(o);}
- void Extend(const SQArray *a);
- SQObjectPtr &Top(){return _values.top();}
- void Pop(){_values.pop_back(); ShrinkIfNeeded(); }
- bool Insert(SQInteger idx,const SQObject &val){
- if(idx < 0 || idx > (SQInteger)_values.size())
- return false;
- _values.insert(idx,val);
- return true;
- }
- void ShrinkIfNeeded() {
- if(_values.size() <= _values.capacity()>>2) //shrink the array
- _values.shrinktofit();
- }
- bool Remove(SQInteger idx){
- if(idx < 0 || idx >= (SQInteger)_values.size())
- return false;
- _values.remove(idx);
- ShrinkIfNeeded();
- return true;
- }
- void Release()
- {
- sq_delete(this,SQArray);
- }
-
- SQObjectPtrVec _values;
-};
-#endif //_SQARRAY_H_
+/* see copyright notice in squirrel.h */ +#ifndef _SQARRAY_H_ +#define _SQARRAY_H_ + +struct SQArray : public CHAINABLE_OBJ +{ +private: + SQArray(SQSharedState *ss,SQInteger nsize){_values.resize(nsize); INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);} + ~SQArray() + { + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); + } +public: + static SQArray* Create(SQSharedState *ss,SQInteger nInitialSize){ + SQArray *newarray=(SQArray*)SQ_MALLOC(sizeof(SQArray)); + new (newarray) SQArray(ss,nInitialSize); + return newarray; + } +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + SQObjectType GetType() {return OT_ARRAY;} +#endif + void Finalize(){ + _values.resize(0); + } + bool Get(const SQInteger nidx,SQObjectPtr &val) + { + if(nidx>=0 && nidx<(SQInteger)_values.size()){ + SQObjectPtr &o = _values[nidx]; + val = _realval(o); + return true; + } + else return false; + } + bool Set(const SQInteger nidx,const SQObjectPtr &val) + { + if(nidx>=0 && nidx<(SQInteger)_values.size()){ + _values[nidx]=val; + return true; + } + else return false; + } + SQInteger Next(const SQObjectPtr &refpos,SQObjectPtr &outkey,SQObjectPtr &outval) + { + SQUnsignedInteger idx=TranslateIndex(refpos); + while(idx<_values.size()){ + //first found + outkey=(SQInteger)idx; + SQObjectPtr &o = _values[idx]; + outval = _realval(o); + //return idx for the next iteration + return ++idx; + } + //nothing to iterate anymore + return -1; + } + SQArray *Clone(){SQArray *anew=Create(_opt_ss(this),0); anew->_values.copy(_values); return anew; } + SQInteger Size() const {return _values.size();} + void Resize(SQInteger size) + { + SQObjectPtr _null; + Resize(size,_null); + } + void Resize(SQInteger size,SQObjectPtr &fill) { _values.resize(size,fill); ShrinkIfNeeded(); } + void Reserve(SQInteger size) { _values.reserve(size); } + void Append(const SQObject &o){_values.push_back(o);} + void Extend(const SQArray *a); + SQObjectPtr &Top(){return _values.top();} + void Pop(){_values.pop_back(); ShrinkIfNeeded(); } + bool Insert(SQInteger idx,const SQObject &val){ + if(idx < 0 || idx > (SQInteger)_values.size()) + return false; + _values.insert(idx,val); + return true; + } + void ShrinkIfNeeded() { + if(_values.size() <= _values.capacity()>>2) //shrink the array + _values.shrinktofit(); + } + bool Remove(SQInteger idx){ + if(idx < 0 || idx >= (SQInteger)_values.size()) + return false; + _values.remove(idx); + ShrinkIfNeeded(); + return true; + } + void Release() + { + sq_delete(this,SQArray); + } + + SQObjectPtrVec _values; +}; +#endif //_SQARRAY_H_ diff --git a/squirrel_3_0_1_stable/squirrel/sqbaselib.cpp b/squirrel_3_0_1_stable/squirrel/sqbaselib.cpp index 1e9ae1445..c11c4d9bd 100644 --- a/squirrel_3_0_1_stable/squirrel/sqbaselib.cpp +++ b/squirrel_3_0_1_stable/squirrel/sqbaselib.cpp @@ -1,1110 +1,1110 @@ -/*
- see copyright notice in squirrel.h
-*/
-#include "sqpcheader.h"
-#include "sqvm.h"
-#include "sqstring.h"
-#include "sqtable.h"
-#include "sqarray.h"
-#include "sqfuncproto.h"
-#include "sqclosure.h"
-#include "sqclass.h"
-#include <stdlib.h>
-#include <stdarg.h>
-#include <ctype.h>
-
-bool str2num(const SQChar *s,SQObjectPtr &res)
-{
- SQChar *end;
- if(scstrstr(s,_SC("."))){
- SQFloat r = SQFloat(scstrtod(s,&end));
- if(s == end) return false;
- res = r;
- return true;
- }
- else{
- SQInteger r = SQInteger(scstrtol(s,&end,10));
- if(s == end) return false;
- res = r;
- return true;
- }
-}
-
-static SQInteger base_dummy(HSQUIRRELVM v)
-{
- return 0;
-}
-
-#ifndef NO_GARBAGE_COLLECTOR
-static SQInteger base_collectgarbage(HSQUIRRELVM v)
-{
- sq_pushinteger(v, sq_collectgarbage(v));
- return 1;
-}
-static SQInteger base_resurectureachable(HSQUIRRELVM v)
-{
- sq_resurrectunreachable(v);
- return 1;
-}
-#endif
-
-static SQInteger base_getroottable(HSQUIRRELVM v)
-{
- v->Push(v->_roottable);
- return 1;
-}
-
-static SQInteger base_getconsttable(HSQUIRRELVM v)
-{
- v->Push(_ss(v)->_consts);
- return 1;
-}
-
-
-static SQInteger base_setroottable(HSQUIRRELVM v)
-{
- SQObjectPtr o = v->_roottable;
- if(SQ_FAILED(sq_setroottable(v))) return SQ_ERROR;
- v->Push(o);
- return 1;
-}
-
-static SQInteger base_setconsttable(HSQUIRRELVM v)
-{
- SQObjectPtr o = _ss(v)->_consts;
- if(SQ_FAILED(sq_setconsttable(v))) return SQ_ERROR;
- v->Push(o);
- return 1;
-}
-
-static SQInteger base_seterrorhandler(HSQUIRRELVM v)
-{
- sq_seterrorhandler(v);
- return 0;
-}
-
-static SQInteger base_setdebughook(HSQUIRRELVM v)
-{
- sq_setdebughook(v);
- return 0;
-}
-
-static SQInteger base_enabledebuginfo(HSQUIRRELVM v)
-{
- SQObjectPtr &o=stack_get(v,2);
-
- sq_enabledebuginfo(v,SQVM::IsFalse(o)?SQFalse:SQTrue);
- return 0;
-}
-
-static SQInteger __getcallstackinfos(HSQUIRRELVM v,SQInteger level)
-{
- SQStackInfos si;
- SQInteger seq = 0;
- const SQChar *name = NULL;
-
- if (SQ_SUCCEEDED(sq_stackinfos(v, level, &si)))
- {
- const SQChar *fn = _SC("unknown");
- const SQChar *src = _SC("unknown");
- if(si.funcname)fn = si.funcname;
- if(si.source)src = si.source;
- sq_newtable(v);
- sq_pushstring(v, _SC("func"), -1);
- sq_pushstring(v, fn, -1);
- sq_newslot(v, -3, SQFalse);
- sq_pushstring(v, _SC("src"), -1);
- sq_pushstring(v, src, -1);
- sq_newslot(v, -3, SQFalse);
- sq_pushstring(v, _SC("line"), -1);
- sq_pushinteger(v, si.line);
- sq_newslot(v, -3, SQFalse);
- sq_pushstring(v, _SC("locals"), -1);
- sq_newtable(v);
- seq=0;
- while ((name = sq_getlocal(v, level, seq))) {
- sq_pushstring(v, name, -1);
- sq_push(v, -2);
- sq_newslot(v, -4, SQFalse);
- sq_pop(v, 1);
- seq++;
- }
- sq_newslot(v, -3, SQFalse);
- return 1;
- }
-
- return 0;
-}
-static SQInteger base_getstackinfos(HSQUIRRELVM v)
-{
- SQInteger level;
- sq_getinteger(v, -1, &level);
- return __getcallstackinfos(v,level);
-}
-
-static SQInteger base_assert(HSQUIRRELVM v)
-{
- if(SQVM::IsFalse(stack_get(v,2))){
- return sq_throwerror(v,_SC("assertion failed"));
- }
- return 0;
-}
-
-static SQInteger get_slice_params(HSQUIRRELVM v,SQInteger &sidx,SQInteger &eidx,SQObjectPtr &o)
-{
- SQInteger top = sq_gettop(v);
- sidx=0;
- eidx=0;
- o=stack_get(v,1);
- SQObjectPtr &start=stack_get(v,2);
- if(type(start)!=OT_NULL && sq_isnumeric(start)){
- sidx=tointeger(start);
- }
- if(top>2){
- SQObjectPtr &end=stack_get(v,3);
- if(sq_isnumeric(end)){
- eidx=tointeger(end);
- }
- }
- else {
- eidx = sq_getsize(v,1);
- }
- return 1;
-}
-
-static SQInteger base_print(HSQUIRRELVM v)
-{
- const SQChar *str;
- sq_tostring(v,2);
- sq_getstring(v,-1,&str);
- if(_ss(v)->_printfunc) _ss(v)->_printfunc(v,_SC("%s"),str);
- return 0;
-}
-
-static SQInteger base_error(HSQUIRRELVM v)
-{
- const SQChar *str;
- sq_tostring(v,2);
- sq_getstring(v,-1,&str);
- if(_ss(v)->_errorfunc) _ss(v)->_errorfunc(v,_SC("%s"),str);
- return 0;
-}
-
-static SQInteger base_compilestring(HSQUIRRELVM v)
-{
- SQInteger nargs=sq_gettop(v);
- const SQChar *src=NULL,*name=_SC("unnamedbuffer");
- SQInteger size;
- sq_getstring(v,2,&src);
- size=sq_getsize(v,2);
- if(nargs>2){
- sq_getstring(v,3,&name);
- }
- if(SQ_SUCCEEDED(sq_compilebuffer(v,src,size,name,SQFalse)))
- return 1;
- else
- return SQ_ERROR;
-}
-
-static SQInteger base_newthread(HSQUIRRELVM v)
-{
- SQObjectPtr &func = stack_get(v,2);
- SQInteger stksize = (_closure(func)->_function->_stacksize << 1) +2;
- HSQUIRRELVM newv = sq_newthread(v, (stksize < MIN_STACK_OVERHEAD + 2)? MIN_STACK_OVERHEAD + 2 : stksize);
- sq_move(newv,v,-2);
- return 1;
-}
-
-static SQInteger base_suspend(HSQUIRRELVM v)
-{
- return sq_suspendvm(v);
-}
-
-static SQInteger base_array(HSQUIRRELVM v)
-{
- SQArray *a;
- SQObject &size = stack_get(v,2);
- if(sq_gettop(v) > 2) {
- a = SQArray::Create(_ss(v),0);
- a->Resize(tointeger(size),stack_get(v,3));
- }
- else {
- a = SQArray::Create(_ss(v),tointeger(size));
- }
- v->Push(a);
- return 1;
-}
-
-static SQInteger base_type(HSQUIRRELVM v)
-{
- SQObjectPtr &o = stack_get(v,2);
- v->Push(SQString::Create(_ss(v),GetTypeName(o),-1));
- return 1;
-}
-
-static SQInteger base_callee(HSQUIRRELVM v)
-{
- if(v->_callsstacksize > 1)
- {
- v->Push(v->_callsstack[v->_callsstacksize - 2]._closure);
- return 1;
- }
- return sq_throwerror(v,_SC("no closure in the calls stack"));
-}
-
-static SQRegFunction base_funcs[]={
- //generic
- {_SC("seterrorhandler"),base_seterrorhandler,2, NULL},
- {_SC("setdebughook"),base_setdebughook,2, NULL},
- {_SC("enabledebuginfo"),base_enabledebuginfo,2, NULL},
- {_SC("getstackinfos"),base_getstackinfos,2, _SC(".n")},
- {_SC("getroottable"),base_getroottable,1, NULL},
- {_SC("setroottable"),base_setroottable,2, NULL},
- {_SC("getconsttable"),base_getconsttable,1, NULL},
- {_SC("setconsttable"),base_setconsttable,2, NULL},
- {_SC("assert"),base_assert,2, NULL},
- {_SC("print"),base_print,2, NULL},
- {_SC("error"),base_error,2, NULL},
- {_SC("compilestring"),base_compilestring,-2, _SC(".ss")},
- {_SC("newthread"),base_newthread,2, _SC(".c")},
- {_SC("suspend"),base_suspend,-1, NULL},
- {_SC("array"),base_array,-2, _SC(".n")},
- {_SC("type"),base_type,2, NULL},
- {_SC("callee"),base_callee,0,NULL},
- {_SC("dummy"),base_dummy,0,NULL},
-#ifndef NO_GARBAGE_COLLECTOR
- {_SC("collectgarbage"),base_collectgarbage,0, NULL},
- {_SC("resurrectunreachable"),base_resurectureachable,0, NULL},
-#endif
- {0,0}
-};
-
-void sq_base_register(HSQUIRRELVM v)
-{
- SQInteger i=0;
- sq_pushroottable(v);
- while(base_funcs[i].name!=0) {
- sq_pushstring(v,base_funcs[i].name,-1);
- sq_newclosure(v,base_funcs[i].f,0);
- sq_setnativeclosurename(v,-1,base_funcs[i].name);
- sq_setparamscheck(v,base_funcs[i].nparamscheck,base_funcs[i].typemask);
- sq_newslot(v,-3, SQFalse);
- i++;
- }
-
- sq_pushstring(v,_SC("_versionnumber_"),-1);
- sq_pushinteger(v,SQUIRREL_VERSION_NUMBER);
- sq_newslot(v,-3, SQFalse);
- sq_pushstring(v,_SC("_version_"),-1);
- sq_pushstring(v,SQUIRREL_VERSION,-1);
- sq_newslot(v,-3, SQFalse);
- sq_pushstring(v,_SC("_charsize_"),-1);
- sq_pushinteger(v,sizeof(SQChar));
- sq_newslot(v,-3, SQFalse);
- sq_pushstring(v,_SC("_intsize_"),-1);
- sq_pushinteger(v,sizeof(SQInteger));
- sq_newslot(v,-3, SQFalse);
- sq_pushstring(v,_SC("_floatsize_"),-1);
- sq_pushinteger(v,sizeof(SQFloat));
- sq_newslot(v,-3, SQFalse);
- sq_pop(v,1);
-}
-
-static SQInteger default_delegate_len(HSQUIRRELVM v)
-{
- v->Push(SQInteger(sq_getsize(v,1)));
- return 1;
-}
-
-static SQInteger default_delegate_tofloat(HSQUIRRELVM v)
-{
- SQObjectPtr &o=stack_get(v,1);
- switch(type(o)){
- case OT_STRING:{
- SQObjectPtr res;
- if(str2num(_stringval(o),res)){
- v->Push(SQObjectPtr(tofloat(res)));
- break;
- }}
- return sq_throwerror(v, _SC("cannot convert the string"));
- break;
- case OT_INTEGER:case OT_FLOAT:
- v->Push(SQObjectPtr(tofloat(o)));
- break;
- case OT_BOOL:
- v->Push(SQObjectPtr((SQFloat)(_integer(o)?1:0)));
- break;
- default:
- v->PushNull();
- break;
- }
- return 1;
-}
-
-static SQInteger default_delegate_tointeger(HSQUIRRELVM v)
-{
- SQObjectPtr &o=stack_get(v,1);
- switch(type(o)){
- case OT_STRING:{
- SQObjectPtr res;
- if(str2num(_stringval(o),res)){
- v->Push(SQObjectPtr(tointeger(res)));
- break;
- }}
- return sq_throwerror(v, _SC("cannot convert the string"));
- break;
- case OT_INTEGER:case OT_FLOAT:
- v->Push(SQObjectPtr(tointeger(o)));
- break;
- case OT_BOOL:
- v->Push(SQObjectPtr(_integer(o)?(SQInteger)1:(SQInteger)0));
- break;
- default:
- v->PushNull();
- break;
- }
- return 1;
-}
-
-static SQInteger default_delegate_tostring(HSQUIRRELVM v)
-{
- sq_tostring(v,1);
- return 1;
-}
-
-static SQInteger obj_delegate_weakref(HSQUIRRELVM v)
-{
- sq_weakref(v,1);
- return 1;
-}
-
-static SQInteger obj_clear(HSQUIRRELVM v)
-{
- return sq_clear(v,-1);
-}
-
-
-static SQInteger number_delegate_tochar(HSQUIRRELVM v)
-{
- SQObject &o=stack_get(v,1);
- SQChar c = (SQChar)tointeger(o);
- v->Push(SQString::Create(_ss(v),(const SQChar *)&c,1));
- return 1;
-}
-
-
-
-/////////////////////////////////////////////////////////////////
-//TABLE DEFAULT DELEGATE
-
-static SQInteger table_rawdelete(HSQUIRRELVM v)
-{
- if(SQ_FAILED(sq_rawdeleteslot(v,1,SQTrue)))
- return SQ_ERROR;
- return 1;
-}
-
-
-static SQInteger container_rawexists(HSQUIRRELVM v)
-{
- if(SQ_SUCCEEDED(sq_rawget(v,-2))) {
- sq_pushbool(v,SQTrue);
- return 1;
- }
- sq_pushbool(v,SQFalse);
- return 1;
-}
-
-static SQInteger container_rawset(HSQUIRRELVM v)
-{
- return sq_rawset(v,-3);
-}
-
-
-static SQInteger container_rawget(HSQUIRRELVM v)
-{
- return SQ_SUCCEEDED(sq_rawget(v,-2))?1:SQ_ERROR;
-}
-
-static SQInteger table_setdelegate(HSQUIRRELVM v)
-{
- if(SQ_FAILED(sq_setdelegate(v,-2)))
- return SQ_ERROR;
- sq_push(v,-1); // -1 because sq_setdelegate pops 1
- return 1;
-}
-
-static SQInteger table_getdelegate(HSQUIRRELVM v)
-{
- return SQ_SUCCEEDED(sq_getdelegate(v,-1))?1:SQ_ERROR;
-}
-
-SQRegFunction SQSharedState::_table_default_delegate_funcz[]={
- {_SC("len"),default_delegate_len,1, _SC("t")},
- {_SC("rawget"),container_rawget,2, _SC("t")},
- {_SC("rawset"),container_rawset,3, _SC("t")},
- {_SC("rawdelete"),table_rawdelete,2, _SC("t")},
- {_SC("rawin"),container_rawexists,2, _SC("t")},
- {_SC("weakref"),obj_delegate_weakref,1, NULL },
- {_SC("tostring"),default_delegate_tostring,1, _SC(".")},
- {_SC("clear"),obj_clear,1, _SC(".")},
- {_SC("setdelegate"),table_setdelegate,2, _SC(".t|o")},
- {_SC("getdelegate"),table_getdelegate,1, _SC(".")},
- {0,0}
-};
-
-//ARRAY DEFAULT DELEGATE///////////////////////////////////////
-
-static SQInteger array_append(HSQUIRRELVM v)
-{
- return sq_arrayappend(v,-2);
-}
-
-static SQInteger array_extend(HSQUIRRELVM v)
-{
- _array(stack_get(v,1))->Extend(_array(stack_get(v,2)));
- return 0;
-}
-
-static SQInteger array_reverse(HSQUIRRELVM v)
-{
- return sq_arrayreverse(v,-1);
-}
-
-static SQInteger array_pop(HSQUIRRELVM v)
-{
- return SQ_SUCCEEDED(sq_arraypop(v,1,SQTrue))?1:SQ_ERROR;
-}
-
-static SQInteger array_top(HSQUIRRELVM v)
-{
- SQObject &o=stack_get(v,1);
- if(_array(o)->Size()>0){
- v->Push(_array(o)->Top());
- return 1;
- }
- else return sq_throwerror(v,_SC("top() on a empty array"));
-}
-
-static SQInteger array_insert(HSQUIRRELVM v)
-{
- SQObject &o=stack_get(v,1);
- SQObject &idx=stack_get(v,2);
- SQObject &val=stack_get(v,3);
- if(!_array(o)->Insert(tointeger(idx),val))
- return sq_throwerror(v,_SC("index out of range"));
- return 0;
-}
-
-static SQInteger array_remove(HSQUIRRELVM v)
-{
- SQObject &o = stack_get(v, 1);
- SQObject &idx = stack_get(v, 2);
- if(!sq_isnumeric(idx)) return sq_throwerror(v, _SC("wrong type"));
- SQObjectPtr val;
- if(_array(o)->Get(tointeger(idx), val)) {
- _array(o)->Remove(tointeger(idx));
- v->Push(val);
- return 1;
- }
- return sq_throwerror(v, _SC("idx out of range"));
-}
-
-static SQInteger array_resize(HSQUIRRELVM v)
-{
- SQObject &o = stack_get(v, 1);
- SQObject &nsize = stack_get(v, 2);
- SQObjectPtr fill;
- if(sq_isnumeric(nsize)) {
- if(sq_gettop(v) > 2)
- fill = stack_get(v, 3);
- _array(o)->Resize(tointeger(nsize),fill);
- return 0;
- }
- return sq_throwerror(v, _SC("size must be a number"));
-}
-
-static SQInteger __map_array(SQArray *dest,SQArray *src,HSQUIRRELVM v) {
- SQObjectPtr temp;
- SQInteger size = src->Size();
- for(SQInteger n = 0; n < size; n++) {
- src->Get(n,temp);
- v->Push(src);
- v->Push(temp);
- if(SQ_FAILED(sq_call(v,2,SQTrue,SQFalse))) {
- return SQ_ERROR;
- }
- dest->Set(n,v->GetUp(-1));
- v->Pop();
- }
- return 0;
-}
-
-static SQInteger array_map(HSQUIRRELVM v)
-{
- SQObject &o = stack_get(v,1);
- SQInteger size = _array(o)->Size();
- SQObjectPtr ret = SQArray::Create(_ss(v),size);
- if(SQ_FAILED(__map_array(_array(ret),_array(o),v)))
- return SQ_ERROR;
- v->Push(ret);
- return 1;
-}
-
-static SQInteger array_apply(HSQUIRRELVM v)
-{
- SQObject &o = stack_get(v,1);
- if(SQ_FAILED(__map_array(_array(o),_array(o),v)))
- return SQ_ERROR;
- return 0;
-}
-
-static SQInteger array_reduce(HSQUIRRELVM v)
-{
- SQObject &o = stack_get(v,1);
- SQArray *a = _array(o);
- SQInteger size = a->Size();
- if(size == 0) {
- return 0;
- }
- SQObjectPtr res;
- a->Get(0,res);
- if(size > 1) {
- SQObjectPtr other;
- for(SQInteger n = 1; n < size; n++) {
- a->Get(n,other);
- v->Push(o);
- v->Push(res);
- v->Push(other);
- if(SQ_FAILED(sq_call(v,3,SQTrue,SQFalse))) {
- return SQ_ERROR;
- }
- res = v->GetUp(-1);
- v->Pop();
- }
- }
- v->Push(res);
- return 1;
-}
-
-static SQInteger array_filter(HSQUIRRELVM v)
-{
- SQObject &o = stack_get(v,1);
- SQArray *a = _array(o);
- SQObjectPtr ret = SQArray::Create(_ss(v),0);
- SQInteger size = a->Size();
- SQObjectPtr val;
- for(SQInteger n = 0; n < size; n++) {
- a->Get(n,val);
- v->Push(o);
- v->Push(n);
- v->Push(val);
- if(SQ_FAILED(sq_call(v,3,SQTrue,SQFalse))) {
- return SQ_ERROR;
- }
- if(!SQVM::IsFalse(v->GetUp(-1))) {
- _array(ret)->Append(val);
- }
- v->Pop();
- }
- v->Push(ret);
- return 1;
-}
-
-static SQInteger array_find(HSQUIRRELVM v)
-{
- SQObject &o = stack_get(v,1);
- SQObjectPtr &val = stack_get(v,2);
- SQArray *a = _array(o);
- SQInteger size = a->Size();
- SQObjectPtr temp;
- for(SQInteger n = 0; n < size; n++) {
- bool res = false;
- a->Get(n,temp);
- if(SQVM::IsEqual(temp,val,res) && res) {
- v->Push(n);
- return 1;
- }
- }
- return 0;
-}
-
-//QSORT ala Sedgewick
-bool _qsort_compare(HSQUIRRELVM v,SQObjectPtr &arr,SQObjectPtr &a,SQObjectPtr &b,SQInteger func,SQInteger &ret)
-{
- if(func < 0) {
- if(!v->ObjCmp(a,b,ret)) return false;
- }
- else {
- SQInteger top = sq_gettop(v);
- sq_push(v, func);
- sq_pushroottable(v);
- v->Push(a);
- v->Push(b);
- if(SQ_FAILED(sq_call(v, 3, SQTrue, SQFalse))) {
- if(!sq_isstring( v->_lasterror))
- v->Raise_Error(_SC("compare func failed"));
- return false;
- }
- sq_getinteger(v, -1, &ret);
- sq_settop(v, top);
- return true;
- }
- return true;
-}
-//QSORT ala Sedgewick
-bool _qsort(HSQUIRRELVM v,SQObjectPtr &arr, SQInteger l, SQInteger r,SQInteger func)
-{
- SQInteger i, j;
- SQArray *a=_array(arr);
- SQObjectPtr pivot,t;
- if( l < r ){
- pivot = a->_values[l];
- i = l; j = r+1;
- while(1){
- SQInteger ret;
- do {
- ++i;
- if(i > r) break;
- if(!_qsort_compare(v,arr,a->_values[i],pivot,func,ret))
- return false;
- } while( ret <= 0);
- do {
- --j;
- if ( j < 0 ) {
- v->Raise_Error( _SC("Invalid qsort, probably compare function defect") );
- return false;
- }
- if(!_qsort_compare(v,arr,a->_values[j],pivot,func,ret))
- return false;
- }
- while( ret > 0 );
- if( i >= j ) break;
- t = a->_values[i]; a->_values[i] = a->_values[j]; a->_values[j] = t;
- }
- t = a->_values[l]; a->_values[l] = a->_values[j]; a->_values[j] = t;
- if(!_qsort( v, arr, l, j-1,func)) return false;
- if(!_qsort( v, arr, j+1, r,func)) return false;
- }
- return true;
-}
-
-static SQInteger array_sort(HSQUIRRELVM v)
-{
- SQInteger func = -1;
- SQObjectPtr &o = stack_get(v,1);
- //SQObject &funcobj = stack_get(v,2);
- if(_array(o)->Size() > 1) {
- if(sq_gettop(v) == 2 /*&& type(funcobj) == OT_CLOSURE || type(funcobj) == OT_NATIVECLOSURE*/) func = 2;
- if(!_qsort(v, o, 0, _array(o)->Size()-1, func))
- return SQ_ERROR;
-
- }
- return 0;
-}
-static SQInteger array_slice(HSQUIRRELVM v)
-{
- SQInteger sidx,eidx;
- SQObjectPtr o;
- if(get_slice_params(v,sidx,eidx,o)==-1)return -1;
- SQInteger alen = _array(o)->Size();
- if(sidx < 0)sidx = alen + sidx;
- if(eidx < 0)eidx = alen + eidx;
- if(eidx < sidx)return sq_throwerror(v,_SC("wrong indexes"));
- if(eidx > alen)return sq_throwerror(v,_SC("slice out of range"));
- SQArray *arr=SQArray::Create(_ss(v),eidx-sidx);
- SQObjectPtr t;
- SQInteger count=0;
- for(SQInteger i=sidx;i<eidx;i++){
- _array(o)->Get(i,t);
- arr->Set(count++,t);
- }
- v->Push(arr);
- return 1;
-
-}
-
-SQRegFunction SQSharedState::_array_default_delegate_funcz[]={
- {_SC("len"),default_delegate_len,1, _SC("a")},
- {_SC("append"),array_append,2, _SC("a")},
- {_SC("extend"),array_extend,2, _SC("aa")},
- {_SC("push"),array_append,2, _SC("a")},
- {_SC("pop"),array_pop,1, _SC("a")},
- {_SC("top"),array_top,1, _SC("a")},
- {_SC("insert"),array_insert,3, _SC("an")},
- {_SC("remove"),array_remove,2, _SC("an")},
- {_SC("resize"),array_resize,-2, _SC("an")},
- {_SC("reverse"),array_reverse,1, _SC("a")},
- {_SC("sort"),array_sort,-1, _SC("ac")},
- {_SC("slice"),array_slice,-1, _SC("ann")},
- {_SC("weakref"),obj_delegate_weakref,1, NULL },
- {_SC("tostring"),default_delegate_tostring,1, _SC(".")},
- {_SC("clear"),obj_clear,1, _SC(".")},
- {_SC("map"),array_map,2, _SC("ac")},
- {_SC("apply"),array_apply,2, _SC("ac")},
- {_SC("reduce"),array_reduce,2, _SC("ac")},
- {_SC("filter"),array_filter,2, _SC("ac")},
- {_SC("find"),array_find,2, _SC("a.")},
- {0,0}
-};
-
-//STRING DEFAULT DELEGATE//////////////////////////
-static SQInteger string_slice(HSQUIRRELVM v)
-{
- SQInteger sidx,eidx;
- SQObjectPtr o;
- if(SQ_FAILED(get_slice_params(v,sidx,eidx,o)))return -1;
- SQInteger slen = _string(o)->_len;
- if(sidx < 0)sidx = slen + sidx;
- if(eidx < 0)eidx = slen + eidx;
- if(eidx < sidx) return sq_throwerror(v,_SC("wrong indexes"));
- if(eidx > slen) return sq_throwerror(v,_SC("slice out of range"));
- v->Push(SQString::Create(_ss(v),&_stringval(o)[sidx],eidx-sidx));
- return 1;
-}
-
-static SQInteger string_find(HSQUIRRELVM v)
-{
- SQInteger top,start_idx=0;
- const SQChar *str,*substr,*ret;
- if(((top=sq_gettop(v))>1) && SQ_SUCCEEDED(sq_getstring(v,1,&str)) && SQ_SUCCEEDED(sq_getstring(v,2,&substr))){
- if(top>2)sq_getinteger(v,3,&start_idx);
- if((sq_getsize(v,1)>start_idx) && (start_idx>=0)){
- ret=scstrstr(&str[start_idx],substr);
- if(ret){
- sq_pushinteger(v,(SQInteger)(ret-str));
- return 1;
- }
- }
- return 0;
- }
- return sq_throwerror(v,_SC("invalid param"));
-}
-
-#define STRING_TOFUNCZ(func) static SQInteger string_##func(HSQUIRRELVM v) \
-{ \
- SQObject str=stack_get(v,1); \
- SQInteger len=_string(str)->_len; \
- const SQChar *sThis=_stringval(str); \
- SQChar *sNew=(_ss(v)->GetScratchPad(rsl(len))); \
- for(SQInteger i=0;i<len;i++) sNew[i]=func(sThis[i]); \
- v->Push(SQString::Create(_ss(v),sNew,len)); \
- return 1; \
-}
-
-
-STRING_TOFUNCZ(tolower)
-STRING_TOFUNCZ(toupper)
-
-SQRegFunction SQSharedState::_string_default_delegate_funcz[]={
- {_SC("len"),default_delegate_len,1, _SC("s")},
- {_SC("tointeger"),default_delegate_tointeger,1, _SC("s")},
- {_SC("tofloat"),default_delegate_tofloat,1, _SC("s")},
- {_SC("tostring"),default_delegate_tostring,1, _SC(".")},
- {_SC("slice"),string_slice,-1, _SC(" s n n")},
- {_SC("find"),string_find,-2, _SC("s s n ")},
- {_SC("tolower"),string_tolower,1, _SC("s")},
- {_SC("toupper"),string_toupper,1, _SC("s")},
- {_SC("weakref"),obj_delegate_weakref,1, NULL },
- {0,0}
-};
-
-//INTEGER DEFAULT DELEGATE//////////////////////////
-SQRegFunction SQSharedState::_number_default_delegate_funcz[]={
- {_SC("tointeger"),default_delegate_tointeger,1, _SC("n|b")},
- {_SC("tofloat"),default_delegate_tofloat,1, _SC("n|b")},
- {_SC("tostring"),default_delegate_tostring,1, _SC(".")},
- {_SC("tochar"),number_delegate_tochar,1, _SC("n|b")},
- {_SC("weakref"),obj_delegate_weakref,1, NULL },
- {0,0}
-};
-
-//CLOSURE DEFAULT DELEGATE//////////////////////////
-static SQInteger closure_pcall(HSQUIRRELVM v)
-{
- return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue,SQFalse))?1:SQ_ERROR;
-}
-
-static SQInteger closure_call(HSQUIRRELVM v)
-{
- return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue,SQTrue))?1:SQ_ERROR;
-}
-
-static SQInteger _closure_acall(HSQUIRRELVM v,SQBool raiseerror)
-{
- SQArray *aparams=_array(stack_get(v,2));
- SQInteger nparams=aparams->Size();
- v->Push(stack_get(v,1));
- for(SQInteger i=0;i<nparams;i++)v->Push(aparams->_values[i]);
- return SQ_SUCCEEDED(sq_call(v,nparams,SQTrue,raiseerror))?1:SQ_ERROR;
-}
-
-static SQInteger closure_acall(HSQUIRRELVM v)
-{
- return _closure_acall(v,SQTrue);
-}
-
-static SQInteger closure_pacall(HSQUIRRELVM v)
-{
- return _closure_acall(v,SQFalse);
-}
-
-static SQInteger closure_bindenv(HSQUIRRELVM v)
-{
- if(SQ_FAILED(sq_bindenv(v,1)))
- return SQ_ERROR;
- return 1;
-}
-
-static SQInteger closure_getinfos(HSQUIRRELVM v) {
- SQObject o = stack_get(v,1);
- SQTable *res = SQTable::Create(_ss(v),4);
- if(type(o) == OT_CLOSURE) {
- SQFunctionProto *f = _closure(o)->_function;
- SQInteger nparams = f->_nparameters + (f->_varparams?1:0);
- SQObjectPtr params = SQArray::Create(_ss(v),nparams);
- for(SQInteger n = 0; n<f->_nparameters; n++) {
- _array(params)->Set((SQInteger)n,f->_parameters[n]);
- }
- if(f->_varparams) {
- _array(params)->Set(nparams-1,SQString::Create(_ss(v),_SC("..."),-1));
- }
- res->NewSlot(SQString::Create(_ss(v),_SC("native"),-1),false);
- res->NewSlot(SQString::Create(_ss(v),_SC("name"),-1),f->_name);
- res->NewSlot(SQString::Create(_ss(v),_SC("src"),-1),f->_sourcename);
- res->NewSlot(SQString::Create(_ss(v),_SC("parameters"),-1),params);
- res->NewSlot(SQString::Create(_ss(v),_SC("varargs"),-1),f->_varparams);
- }
- else { //OT_NATIVECLOSURE
- SQNativeClosure *nc = _nativeclosure(o);
- res->NewSlot(SQString::Create(_ss(v),_SC("native"),-1),true);
- res->NewSlot(SQString::Create(_ss(v),_SC("name"),-1),nc->_name);
- res->NewSlot(SQString::Create(_ss(v),_SC("paramscheck"),-1),nc->_nparamscheck);
- SQObjectPtr typecheck;
- if(nc->_typecheck.size() > 0) {
- typecheck =
- SQArray::Create(_ss(v), nc->_typecheck.size());
- for(SQUnsignedInteger n = 0; n<nc->_typecheck.size(); n++) {
- _array(typecheck)->Set((SQInteger)n,nc->_typecheck[n]);
- }
- }
- res->NewSlot(SQString::Create(_ss(v),_SC("typecheck"),-1),typecheck);
- }
- v->Push(res);
- return 1;
-}
-
-
-SQRegFunction SQSharedState::_closure_default_delegate_funcz[]={
- {_SC("call"),closure_call,-1, _SC("c")},
- {_SC("pcall"),closure_pcall,-1, _SC("c")},
- {_SC("acall"),closure_acall,2, _SC("ca")},
- {_SC("pacall"),closure_pacall,2, _SC("ca")},
- {_SC("weakref"),obj_delegate_weakref,1, NULL },
- {_SC("tostring"),default_delegate_tostring,1, _SC(".")},
- {_SC("bindenv"),closure_bindenv,2, _SC("c x|y|t")},
- {_SC("getinfos"),closure_getinfos,1, _SC("c")},
- {0,0}
-};
-
-//GENERATOR DEFAULT DELEGATE
-static SQInteger generator_getstatus(HSQUIRRELVM v)
-{
- SQObject &o=stack_get(v,1);
- switch(_generator(o)->_state){
- case SQGenerator::eSuspended:v->Push(SQString::Create(_ss(v),_SC("suspended")));break;
- case SQGenerator::eRunning:v->Push(SQString::Create(_ss(v),_SC("running")));break;
- case SQGenerator::eDead:v->Push(SQString::Create(_ss(v),_SC("dead")));break;
- }
- return 1;
-}
-
-SQRegFunction SQSharedState::_generator_default_delegate_funcz[]={
- {_SC("getstatus"),generator_getstatus,1, _SC("g")},
- {_SC("weakref"),obj_delegate_weakref,1, NULL },
- {_SC("tostring"),default_delegate_tostring,1, _SC(".")},
- {0,0}
-};
-
-//THREAD DEFAULT DELEGATE
-static SQInteger thread_call(HSQUIRRELVM v)
-{
- SQObjectPtr o = stack_get(v,1);
- if(type(o) == OT_THREAD) {
- SQInteger nparams = sq_gettop(v);
- _thread(o)->Push(_thread(o)->_roottable);
- for(SQInteger i = 2; i<(nparams+1); i++)
- sq_move(_thread(o),v,i);
- if(SQ_SUCCEEDED(sq_call(_thread(o),nparams,SQTrue,SQFalse))) {
- sq_move(v,_thread(o),-1);
- sq_pop(_thread(o),1);
- return 1;
- }
- v->_lasterror = _thread(o)->_lasterror;
- return SQ_ERROR;
- }
- return sq_throwerror(v,_SC("wrong parameter"));
-}
-
-static SQInteger thread_wakeup(HSQUIRRELVM v)
-{
- SQObjectPtr o = stack_get(v,1);
- if(type(o) == OT_THREAD) {
- SQVM *thread = _thread(o);
- SQInteger state = sq_getvmstate(thread);
- if(state != SQ_VMSTATE_SUSPENDED) {
- switch(state) {
- case SQ_VMSTATE_IDLE:
- return sq_throwerror(v,_SC("cannot wakeup a idle thread"));
- break;
- case SQ_VMSTATE_RUNNING:
- return sq_throwerror(v,_SC("cannot wakeup a running thread"));
- break;
- }
- }
-
- SQInteger wakeupret = sq_gettop(v)>1?1:0;
- if(wakeupret) {
- sq_move(thread,v,2);
- }
- if(SQ_SUCCEEDED(sq_wakeupvm(thread,wakeupret,SQTrue,SQTrue,SQFalse))) {
- sq_move(v,thread,-1);
- sq_pop(thread,1); //pop retval
- if(sq_getvmstate(thread) == SQ_VMSTATE_IDLE) {
- sq_settop(thread,1); //pop roottable
- }
- return 1;
- }
- sq_settop(thread,1);
- v->_lasterror = thread->_lasterror;
- return SQ_ERROR;
- }
- return sq_throwerror(v,_SC("wrong parameter"));
-}
-
-static SQInteger thread_getstatus(HSQUIRRELVM v)
-{
- SQObjectPtr &o = stack_get(v,1);
- switch(sq_getvmstate(_thread(o))) {
- case SQ_VMSTATE_IDLE:
- sq_pushstring(v,_SC("idle"),-1);
- break;
- case SQ_VMSTATE_RUNNING:
- sq_pushstring(v,_SC("running"),-1);
- break;
- case SQ_VMSTATE_SUSPENDED:
- sq_pushstring(v,_SC("suspended"),-1);
- break;
- default:
- return sq_throwerror(v,_SC("internal VM error"));
- }
- return 1;
-}
-
-static SQInteger thread_getstackinfos(HSQUIRRELVM v)
-{
- SQObjectPtr o = stack_get(v,1);
- if(type(o) == OT_THREAD) {
- SQVM *thread = _thread(o);
- SQInteger threadtop = sq_gettop(thread);
- SQInteger level;
- sq_getinteger(v,-1,&level);
- SQRESULT res = __getcallstackinfos(thread,level);
- if(SQ_FAILED(res))
- {
- sq_settop(thread,threadtop);
- if(type(thread->_lasterror) == OT_STRING) {
- sq_throwerror(v,_stringval(thread->_lasterror));
- }
- else {
- sq_throwerror(v,_SC("unknown error"));
- }
- }
- if(res > 0) {
- //some result
- sq_move(v,thread,-1);
- sq_settop(thread,threadtop);
- return 1;
- }
- //no result
- sq_settop(thread,threadtop);
- return 0;
-
- }
- return sq_throwerror(v,_SC("wrong parameter"));
-}
-
-SQRegFunction SQSharedState::_thread_default_delegate_funcz[] = {
- {_SC("call"), thread_call, -1, _SC("v")},
- {_SC("wakeup"), thread_wakeup, -1, _SC("v")},
- {_SC("getstatus"), thread_getstatus, 1, _SC("v")},
- {_SC("weakref"),obj_delegate_weakref,1, NULL },
- {_SC("getstackinfos"),thread_getstackinfos,2, _SC("vn")},
- {_SC("tostring"),default_delegate_tostring,1, _SC(".")},
- {0,0},
-};
-
-static SQInteger class_getattributes(HSQUIRRELVM v)
-{
- return SQ_SUCCEEDED(sq_getattributes(v,-2))?1:SQ_ERROR;
-}
-
-static SQInteger class_setattributes(HSQUIRRELVM v)
-{
- return SQ_SUCCEEDED(sq_setattributes(v,-3))?1:SQ_ERROR;
-}
-
-static SQInteger class_instance(HSQUIRRELVM v)
-{
- return SQ_SUCCEEDED(sq_createinstance(v,-1))?1:SQ_ERROR;
-}
-
-static SQInteger class_getbase(HSQUIRRELVM v)
-{
- return SQ_SUCCEEDED(sq_getbase(v,-1))?1:SQ_ERROR;
-}
-
-SQRegFunction SQSharedState::_class_default_delegate_funcz[] = {
- {_SC("getattributes"), class_getattributes, 2, _SC("y.")},
- {_SC("setattributes"), class_setattributes, 3, _SC("y..")},
- {_SC("rawget"),container_rawget,2, _SC("y")},
- {_SC("rawset"),container_rawset,3, _SC("y")},
- {_SC("rawin"),container_rawexists,2, _SC("y")},
- {_SC("weakref"),obj_delegate_weakref,1, NULL },
- {_SC("tostring"),default_delegate_tostring,1, _SC(".")},
- {_SC("instance"),class_instance,1, _SC("y")},
- {_SC("getbase"),class_getbase,1, _SC("y")},
- {0,0}
-};
-
-static SQInteger instance_getclass(HSQUIRRELVM v)
-{
- if(SQ_SUCCEEDED(sq_getclass(v,1)))
- return 1;
- return SQ_ERROR;
-}
-
-SQRegFunction SQSharedState::_instance_default_delegate_funcz[] = {
- {_SC("getclass"), instance_getclass, 1, _SC("x")},
- {_SC("rawget"),container_rawget,2, _SC("x")},
- {_SC("rawset"),container_rawset,3, _SC("x")},
- {_SC("rawin"),container_rawexists,2, _SC("x")},
- {_SC("weakref"),obj_delegate_weakref,1, NULL },
- {_SC("tostring"),default_delegate_tostring,1, _SC(".")},
- {0,0}
-};
-
-static SQInteger weakref_ref(HSQUIRRELVM v)
-{
- if(SQ_FAILED(sq_getweakrefval(v,1)))
- return SQ_ERROR;
- return 1;
-}
-
-SQRegFunction SQSharedState::_weakref_default_delegate_funcz[] = {
- {_SC("ref"),weakref_ref,1, _SC("r")},
- {_SC("weakref"),obj_delegate_weakref,1, NULL },
- {_SC("tostring"),default_delegate_tostring,1, _SC(".")},
- {0,0}
-};
-
+/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include "sqvm.h" +#include "sqstring.h" +#include "sqtable.h" +#include "sqarray.h" +#include "sqfuncproto.h" +#include "sqclosure.h" +#include "sqclass.h" +#include <stdlib.h> +#include <stdarg.h> +#include <ctype.h> + +bool str2num(const SQChar *s,SQObjectPtr &res) +{ + SQChar *end; + if(scstrstr(s,_SC("."))){ + SQFloat r = SQFloat(scstrtod(s,&end)); + if(s == end) return false; + res = r; + return true; + } + else{ + SQInteger r = SQInteger(scstrtol(s,&end,10)); + if(s == end) return false; + res = r; + return true; + } +} + +static SQInteger base_dummy(HSQUIRRELVM v) +{ + return 0; +} + +#ifndef NO_GARBAGE_COLLECTOR +static SQInteger base_collectgarbage(HSQUIRRELVM v) +{ + sq_pushinteger(v, sq_collectgarbage(v)); + return 1; +} +static SQInteger base_resurectureachable(HSQUIRRELVM v) +{ + sq_resurrectunreachable(v); + return 1; +} +#endif + +static SQInteger base_getroottable(HSQUIRRELVM v) +{ + v->Push(v->_roottable); + return 1; +} + +static SQInteger base_getconsttable(HSQUIRRELVM v) +{ + v->Push(_ss(v)->_consts); + return 1; +} + + +static SQInteger base_setroottable(HSQUIRRELVM v) +{ + SQObjectPtr o = v->_roottable; + if(SQ_FAILED(sq_setroottable(v))) return SQ_ERROR; + v->Push(o); + return 1; +} + +static SQInteger base_setconsttable(HSQUIRRELVM v) +{ + SQObjectPtr o = _ss(v)->_consts; + if(SQ_FAILED(sq_setconsttable(v))) return SQ_ERROR; + v->Push(o); + return 1; +} + +static SQInteger base_seterrorhandler(HSQUIRRELVM v) +{ + sq_seterrorhandler(v); + return 0; +} + +static SQInteger base_setdebughook(HSQUIRRELVM v) +{ + sq_setdebughook(v); + return 0; +} + +static SQInteger base_enabledebuginfo(HSQUIRRELVM v) +{ + SQObjectPtr &o=stack_get(v,2); + + sq_enabledebuginfo(v,SQVM::IsFalse(o)?SQFalse:SQTrue); + return 0; +} + +static SQInteger __getcallstackinfos(HSQUIRRELVM v,SQInteger level) +{ + SQStackInfos si; + SQInteger seq = 0; + const SQChar *name = NULL; + + if (SQ_SUCCEEDED(sq_stackinfos(v, level, &si))) + { + const SQChar *fn = _SC("unknown"); + const SQChar *src = _SC("unknown"); + if(si.funcname)fn = si.funcname; + if(si.source)src = si.source; + sq_newtable(v); + sq_pushstring(v, _SC("func"), -1); + sq_pushstring(v, fn, -1); + sq_newslot(v, -3, SQFalse); + sq_pushstring(v, _SC("src"), -1); + sq_pushstring(v, src, -1); + sq_newslot(v, -3, SQFalse); + sq_pushstring(v, _SC("line"), -1); + sq_pushinteger(v, si.line); + sq_newslot(v, -3, SQFalse); + sq_pushstring(v, _SC("locals"), -1); + sq_newtable(v); + seq=0; + while ((name = sq_getlocal(v, level, seq))) { + sq_pushstring(v, name, -1); + sq_push(v, -2); + sq_newslot(v, -4, SQFalse); + sq_pop(v, 1); + seq++; + } + sq_newslot(v, -3, SQFalse); + return 1; + } + + return 0; +} +static SQInteger base_getstackinfos(HSQUIRRELVM v) +{ + SQInteger level; + sq_getinteger(v, -1, &level); + return __getcallstackinfos(v,level); +} + +static SQInteger base_assert(HSQUIRRELVM v) +{ + if(SQVM::IsFalse(stack_get(v,2))){ + return sq_throwerror(v,_SC("assertion failed")); + } + return 0; +} + +static SQInteger get_slice_params(HSQUIRRELVM v,SQInteger &sidx,SQInteger &eidx,SQObjectPtr &o) +{ + SQInteger top = sq_gettop(v); + sidx=0; + eidx=0; + o=stack_get(v,1); + SQObjectPtr &start=stack_get(v,2); + if(type(start)!=OT_NULL && sq_isnumeric(start)){ + sidx=tointeger(start); + } + if(top>2){ + SQObjectPtr &end=stack_get(v,3); + if(sq_isnumeric(end)){ + eidx=tointeger(end); + } + } + else { + eidx = sq_getsize(v,1); + } + return 1; +} + +static SQInteger base_print(HSQUIRRELVM v) +{ + const SQChar *str; + sq_tostring(v,2); + sq_getstring(v,-1,&str); + if(_ss(v)->_printfunc) _ss(v)->_printfunc(v,_SC("%s"),str); + return 0; +} + +static SQInteger base_error(HSQUIRRELVM v) +{ + const SQChar *str; + sq_tostring(v,2); + sq_getstring(v,-1,&str); + if(_ss(v)->_errorfunc) _ss(v)->_errorfunc(v,_SC("%s"),str); + return 0; +} + +static SQInteger base_compilestring(HSQUIRRELVM v) +{ + SQInteger nargs=sq_gettop(v); + const SQChar *src=NULL,*name=_SC("unnamedbuffer"); + SQInteger size; + sq_getstring(v,2,&src); + size=sq_getsize(v,2); + if(nargs>2){ + sq_getstring(v,3,&name); + } + if(SQ_SUCCEEDED(sq_compilebuffer(v,src,size,name,SQFalse))) + return 1; + else + return SQ_ERROR; +} + +static SQInteger base_newthread(HSQUIRRELVM v) +{ + SQObjectPtr &func = stack_get(v,2); + SQInteger stksize = (_closure(func)->_function->_stacksize << 1) +2; + HSQUIRRELVM newv = sq_newthread(v, (stksize < MIN_STACK_OVERHEAD + 2)? MIN_STACK_OVERHEAD + 2 : stksize); + sq_move(newv,v,-2); + return 1; +} + +static SQInteger base_suspend(HSQUIRRELVM v) +{ + return sq_suspendvm(v); +} + +static SQInteger base_array(HSQUIRRELVM v) +{ + SQArray *a; + SQObject &size = stack_get(v,2); + if(sq_gettop(v) > 2) { + a = SQArray::Create(_ss(v),0); + a->Resize(tointeger(size),stack_get(v,3)); + } + else { + a = SQArray::Create(_ss(v),tointeger(size)); + } + v->Push(a); + return 1; +} + +static SQInteger base_type(HSQUIRRELVM v) +{ + SQObjectPtr &o = stack_get(v,2); + v->Push(SQString::Create(_ss(v),GetTypeName(o),-1)); + return 1; +} + +static SQInteger base_callee(HSQUIRRELVM v) +{ + if(v->_callsstacksize > 1) + { + v->Push(v->_callsstack[v->_callsstacksize - 2]._closure); + return 1; + } + return sq_throwerror(v,_SC("no closure in the calls stack")); +} + +static SQRegFunction base_funcs[]={ + //generic + {_SC("seterrorhandler"),base_seterrorhandler,2, NULL}, + {_SC("setdebughook"),base_setdebughook,2, NULL}, + {_SC("enabledebuginfo"),base_enabledebuginfo,2, NULL}, + {_SC("getstackinfos"),base_getstackinfos,2, _SC(".n")}, + {_SC("getroottable"),base_getroottable,1, NULL}, + {_SC("setroottable"),base_setroottable,2, NULL}, + {_SC("getconsttable"),base_getconsttable,1, NULL}, + {_SC("setconsttable"),base_setconsttable,2, NULL}, + {_SC("assert"),base_assert,2, NULL}, + {_SC("print"),base_print,2, NULL}, + {_SC("error"),base_error,2, NULL}, + {_SC("compilestring"),base_compilestring,-2, _SC(".ss")}, + {_SC("newthread"),base_newthread,2, _SC(".c")}, + {_SC("suspend"),base_suspend,-1, NULL}, + {_SC("array"),base_array,-2, _SC(".n")}, + {_SC("type"),base_type,2, NULL}, + {_SC("callee"),base_callee,0,NULL}, + {_SC("dummy"),base_dummy,0,NULL}, +#ifndef NO_GARBAGE_COLLECTOR + {_SC("collectgarbage"),base_collectgarbage,0, NULL}, + {_SC("resurrectunreachable"),base_resurectureachable,0, NULL}, +#endif + {0,0} +}; + +void sq_base_register(HSQUIRRELVM v) +{ + SQInteger i=0; + sq_pushroottable(v); + while(base_funcs[i].name!=0) { + sq_pushstring(v,base_funcs[i].name,-1); + sq_newclosure(v,base_funcs[i].f,0); + sq_setnativeclosurename(v,-1,base_funcs[i].name); + sq_setparamscheck(v,base_funcs[i].nparamscheck,base_funcs[i].typemask); + sq_newslot(v,-3, SQFalse); + i++; + } + + sq_pushstring(v,_SC("_versionnumber_"),-1); + sq_pushinteger(v,SQUIRREL_VERSION_NUMBER); + sq_newslot(v,-3, SQFalse); + sq_pushstring(v,_SC("_version_"),-1); + sq_pushstring(v,SQUIRREL_VERSION,-1); + sq_newslot(v,-3, SQFalse); + sq_pushstring(v,_SC("_charsize_"),-1); + sq_pushinteger(v,sizeof(SQChar)); + sq_newslot(v,-3, SQFalse); + sq_pushstring(v,_SC("_intsize_"),-1); + sq_pushinteger(v,sizeof(SQInteger)); + sq_newslot(v,-3, SQFalse); + sq_pushstring(v,_SC("_floatsize_"),-1); + sq_pushinteger(v,sizeof(SQFloat)); + sq_newslot(v,-3, SQFalse); + sq_pop(v,1); +} + +static SQInteger default_delegate_len(HSQUIRRELVM v) +{ + v->Push(SQInteger(sq_getsize(v,1))); + return 1; +} + +static SQInteger default_delegate_tofloat(HSQUIRRELVM v) +{ + SQObjectPtr &o=stack_get(v,1); + switch(type(o)){ + case OT_STRING:{ + SQObjectPtr res; + if(str2num(_stringval(o),res)){ + v->Push(SQObjectPtr(tofloat(res))); + break; + }} + return sq_throwerror(v, _SC("cannot convert the string")); + break; + case OT_INTEGER:case OT_FLOAT: + v->Push(SQObjectPtr(tofloat(o))); + break; + case OT_BOOL: + v->Push(SQObjectPtr((SQFloat)(_integer(o)?1:0))); + break; + default: + v->PushNull(); + break; + } + return 1; +} + +static SQInteger default_delegate_tointeger(HSQUIRRELVM v) +{ + SQObjectPtr &o=stack_get(v,1); + switch(type(o)){ + case OT_STRING:{ + SQObjectPtr res; + if(str2num(_stringval(o),res)){ + v->Push(SQObjectPtr(tointeger(res))); + break; + }} + return sq_throwerror(v, _SC("cannot convert the string")); + break; + case OT_INTEGER:case OT_FLOAT: + v->Push(SQObjectPtr(tointeger(o))); + break; + case OT_BOOL: + v->Push(SQObjectPtr(_integer(o)?(SQInteger)1:(SQInteger)0)); + break; + default: + v->PushNull(); + break; + } + return 1; +} + +static SQInteger default_delegate_tostring(HSQUIRRELVM v) +{ + sq_tostring(v,1); + return 1; +} + +static SQInteger obj_delegate_weakref(HSQUIRRELVM v) +{ + sq_weakref(v,1); + return 1; +} + +static SQInteger obj_clear(HSQUIRRELVM v) +{ + return sq_clear(v,-1); +} + + +static SQInteger number_delegate_tochar(HSQUIRRELVM v) +{ + SQObject &o=stack_get(v,1); + SQChar c = (SQChar)tointeger(o); + v->Push(SQString::Create(_ss(v),(const SQChar *)&c,1)); + return 1; +} + + + +///////////////////////////////////////////////////////////////// +//TABLE DEFAULT DELEGATE + +static SQInteger table_rawdelete(HSQUIRRELVM v) +{ + if(SQ_FAILED(sq_rawdeleteslot(v,1,SQTrue))) + return SQ_ERROR; + return 1; +} + + +static SQInteger container_rawexists(HSQUIRRELVM v) +{ + if(SQ_SUCCEEDED(sq_rawget(v,-2))) { + sq_pushbool(v,SQTrue); + return 1; + } + sq_pushbool(v,SQFalse); + return 1; +} + +static SQInteger container_rawset(HSQUIRRELVM v) +{ + return sq_rawset(v,-3); +} + + +static SQInteger container_rawget(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_rawget(v,-2))?1:SQ_ERROR; +} + +static SQInteger table_setdelegate(HSQUIRRELVM v) +{ + if(SQ_FAILED(sq_setdelegate(v,-2))) + return SQ_ERROR; + sq_push(v,-1); // -1 because sq_setdelegate pops 1 + return 1; +} + +static SQInteger table_getdelegate(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_getdelegate(v,-1))?1:SQ_ERROR; +} + +SQRegFunction SQSharedState::_table_default_delegate_funcz[]={ + {_SC("len"),default_delegate_len,1, _SC("t")}, + {_SC("rawget"),container_rawget,2, _SC("t")}, + {_SC("rawset"),container_rawset,3, _SC("t")}, + {_SC("rawdelete"),table_rawdelete,2, _SC("t")}, + {_SC("rawin"),container_rawexists,2, _SC("t")}, + {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, + {_SC("clear"),obj_clear,1, _SC(".")}, + {_SC("setdelegate"),table_setdelegate,2, _SC(".t|o")}, + {_SC("getdelegate"),table_getdelegate,1, _SC(".")}, + {0,0} +}; + +//ARRAY DEFAULT DELEGATE/////////////////////////////////////// + +static SQInteger array_append(HSQUIRRELVM v) +{ + return sq_arrayappend(v,-2); +} + +static SQInteger array_extend(HSQUIRRELVM v) +{ + _array(stack_get(v,1))->Extend(_array(stack_get(v,2))); + return 0; +} + +static SQInteger array_reverse(HSQUIRRELVM v) +{ + return sq_arrayreverse(v,-1); +} + +static SQInteger array_pop(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_arraypop(v,1,SQTrue))?1:SQ_ERROR; +} + +static SQInteger array_top(HSQUIRRELVM v) +{ + SQObject &o=stack_get(v,1); + if(_array(o)->Size()>0){ + v->Push(_array(o)->Top()); + return 1; + } + else return sq_throwerror(v,_SC("top() on a empty array")); +} + +static SQInteger array_insert(HSQUIRRELVM v) +{ + SQObject &o=stack_get(v,1); + SQObject &idx=stack_get(v,2); + SQObject &val=stack_get(v,3); + if(!_array(o)->Insert(tointeger(idx),val)) + return sq_throwerror(v,_SC("index out of range")); + return 0; +} + +static SQInteger array_remove(HSQUIRRELVM v) +{ + SQObject &o = stack_get(v, 1); + SQObject &idx = stack_get(v, 2); + if(!sq_isnumeric(idx)) return sq_throwerror(v, _SC("wrong type")); + SQObjectPtr val; + if(_array(o)->Get(tointeger(idx), val)) { + _array(o)->Remove(tointeger(idx)); + v->Push(val); + return 1; + } + return sq_throwerror(v, _SC("idx out of range")); +} + +static SQInteger array_resize(HSQUIRRELVM v) +{ + SQObject &o = stack_get(v, 1); + SQObject &nsize = stack_get(v, 2); + SQObjectPtr fill; + if(sq_isnumeric(nsize)) { + if(sq_gettop(v) > 2) + fill = stack_get(v, 3); + _array(o)->Resize(tointeger(nsize),fill); + return 0; + } + return sq_throwerror(v, _SC("size must be a number")); +} + +static SQInteger __map_array(SQArray *dest,SQArray *src,HSQUIRRELVM v) { + SQObjectPtr temp; + SQInteger size = src->Size(); + for(SQInteger n = 0; n < size; n++) { + src->Get(n,temp); + v->Push(src); + v->Push(temp); + if(SQ_FAILED(sq_call(v,2,SQTrue,SQFalse))) { + return SQ_ERROR; + } + dest->Set(n,v->GetUp(-1)); + v->Pop(); + } + return 0; +} + +static SQInteger array_map(HSQUIRRELVM v) +{ + SQObject &o = stack_get(v,1); + SQInteger size = _array(o)->Size(); + SQObjectPtr ret = SQArray::Create(_ss(v),size); + if(SQ_FAILED(__map_array(_array(ret),_array(o),v))) + return SQ_ERROR; + v->Push(ret); + return 1; +} + +static SQInteger array_apply(HSQUIRRELVM v) +{ + SQObject &o = stack_get(v,1); + if(SQ_FAILED(__map_array(_array(o),_array(o),v))) + return SQ_ERROR; + return 0; +} + +static SQInteger array_reduce(HSQUIRRELVM v) +{ + SQObject &o = stack_get(v,1); + SQArray *a = _array(o); + SQInteger size = a->Size(); + if(size == 0) { + return 0; + } + SQObjectPtr res; + a->Get(0,res); + if(size > 1) { + SQObjectPtr other; + for(SQInteger n = 1; n < size; n++) { + a->Get(n,other); + v->Push(o); + v->Push(res); + v->Push(other); + if(SQ_FAILED(sq_call(v,3,SQTrue,SQFalse))) { + return SQ_ERROR; + } + res = v->GetUp(-1); + v->Pop(); + } + } + v->Push(res); + return 1; +} + +static SQInteger array_filter(HSQUIRRELVM v) +{ + SQObject &o = stack_get(v,1); + SQArray *a = _array(o); + SQObjectPtr ret = SQArray::Create(_ss(v),0); + SQInteger size = a->Size(); + SQObjectPtr val; + for(SQInteger n = 0; n < size; n++) { + a->Get(n,val); + v->Push(o); + v->Push(n); + v->Push(val); + if(SQ_FAILED(sq_call(v,3,SQTrue,SQFalse))) { + return SQ_ERROR; + } + if(!SQVM::IsFalse(v->GetUp(-1))) { + _array(ret)->Append(val); + } + v->Pop(); + } + v->Push(ret); + return 1; +} + +static SQInteger array_find(HSQUIRRELVM v) +{ + SQObject &o = stack_get(v,1); + SQObjectPtr &val = stack_get(v,2); + SQArray *a = _array(o); + SQInteger size = a->Size(); + SQObjectPtr temp; + for(SQInteger n = 0; n < size; n++) { + bool res = false; + a->Get(n,temp); + if(SQVM::IsEqual(temp,val,res) && res) { + v->Push(n); + return 1; + } + } + return 0; +} + +//QSORT ala Sedgewick +bool _qsort_compare(HSQUIRRELVM v,SQObjectPtr &arr,SQObjectPtr &a,SQObjectPtr &b,SQInteger func,SQInteger &ret) +{ + if(func < 0) { + if(!v->ObjCmp(a,b,ret)) return false; + } + else { + SQInteger top = sq_gettop(v); + sq_push(v, func); + sq_pushroottable(v); + v->Push(a); + v->Push(b); + if(SQ_FAILED(sq_call(v, 3, SQTrue, SQFalse))) { + if(!sq_isstring( v->_lasterror)) + v->Raise_Error(_SC("compare func failed")); + return false; + } + sq_getinteger(v, -1, &ret); + sq_settop(v, top); + return true; + } + return true; +} +//QSORT ala Sedgewick +bool _qsort(HSQUIRRELVM v,SQObjectPtr &arr, SQInteger l, SQInteger r,SQInteger func) +{ + SQInteger i, j; + SQArray *a=_array(arr); + SQObjectPtr pivot,t; + if( l < r ){ + pivot = a->_values[l]; + i = l; j = r+1; + while(1){ + SQInteger ret; + do { + ++i; + if(i > r) break; + if(!_qsort_compare(v,arr,a->_values[i],pivot,func,ret)) + return false; + } while( ret <= 0); + do { + --j; + if ( j < 0 ) { + v->Raise_Error( _SC("Invalid qsort, probably compare function defect") ); + return false; + } + if(!_qsort_compare(v,arr,a->_values[j],pivot,func,ret)) + return false; + } + while( ret > 0 ); + if( i >= j ) break; + t = a->_values[i]; a->_values[i] = a->_values[j]; a->_values[j] = t; + } + t = a->_values[l]; a->_values[l] = a->_values[j]; a->_values[j] = t; + if(!_qsort( v, arr, l, j-1,func)) return false; + if(!_qsort( v, arr, j+1, r,func)) return false; + } + return true; +} + +static SQInteger array_sort(HSQUIRRELVM v) +{ + SQInteger func = -1; + SQObjectPtr &o = stack_get(v,1); + //SQObject &funcobj = stack_get(v,2); + if(_array(o)->Size() > 1) { + if(sq_gettop(v) == 2 /*&& type(funcobj) == OT_CLOSURE || type(funcobj) == OT_NATIVECLOSURE*/) func = 2; + if(!_qsort(v, o, 0, _array(o)->Size()-1, func)) + return SQ_ERROR; + + } + return 0; +} +static SQInteger array_slice(HSQUIRRELVM v) +{ + SQInteger sidx,eidx; + SQObjectPtr o; + if(get_slice_params(v,sidx,eidx,o)==-1)return -1; + SQInteger alen = _array(o)->Size(); + if(sidx < 0)sidx = alen + sidx; + if(eidx < 0)eidx = alen + eidx; + if(eidx < sidx)return sq_throwerror(v,_SC("wrong indexes")); + if(eidx > alen)return sq_throwerror(v,_SC("slice out of range")); + SQArray *arr=SQArray::Create(_ss(v),eidx-sidx); + SQObjectPtr t; + SQInteger count=0; + for(SQInteger i=sidx;i<eidx;i++){ + _array(o)->Get(i,t); + arr->Set(count++,t); + } + v->Push(arr); + return 1; + +} + +SQRegFunction SQSharedState::_array_default_delegate_funcz[]={ + {_SC("len"),default_delegate_len,1, _SC("a")}, + {_SC("append"),array_append,2, _SC("a")}, + {_SC("extend"),array_extend,2, _SC("aa")}, + {_SC("push"),array_append,2, _SC("a")}, + {_SC("pop"),array_pop,1, _SC("a")}, + {_SC("top"),array_top,1, _SC("a")}, + {_SC("insert"),array_insert,3, _SC("an")}, + {_SC("remove"),array_remove,2, _SC("an")}, + {_SC("resize"),array_resize,-2, _SC("an")}, + {_SC("reverse"),array_reverse,1, _SC("a")}, + {_SC("sort"),array_sort,-1, _SC("ac")}, + {_SC("slice"),array_slice,-1, _SC("ann")}, + {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, + {_SC("clear"),obj_clear,1, _SC(".")}, + {_SC("map"),array_map,2, _SC("ac")}, + {_SC("apply"),array_apply,2, _SC("ac")}, + {_SC("reduce"),array_reduce,2, _SC("ac")}, + {_SC("filter"),array_filter,2, _SC("ac")}, + {_SC("find"),array_find,2, _SC("a.")}, + {0,0} +}; + +//STRING DEFAULT DELEGATE////////////////////////// +static SQInteger string_slice(HSQUIRRELVM v) +{ + SQInteger sidx,eidx; + SQObjectPtr o; + if(SQ_FAILED(get_slice_params(v,sidx,eidx,o)))return -1; + SQInteger slen = _string(o)->_len; + if(sidx < 0)sidx = slen + sidx; + if(eidx < 0)eidx = slen + eidx; + if(eidx < sidx) return sq_throwerror(v,_SC("wrong indexes")); + if(eidx > slen) return sq_throwerror(v,_SC("slice out of range")); + v->Push(SQString::Create(_ss(v),&_stringval(o)[sidx],eidx-sidx)); + return 1; +} + +static SQInteger string_find(HSQUIRRELVM v) +{ + SQInteger top,start_idx=0; + const SQChar *str,*substr,*ret; + if(((top=sq_gettop(v))>1) && SQ_SUCCEEDED(sq_getstring(v,1,&str)) && SQ_SUCCEEDED(sq_getstring(v,2,&substr))){ + if(top>2)sq_getinteger(v,3,&start_idx); + if((sq_getsize(v,1)>start_idx) && (start_idx>=0)){ + ret=scstrstr(&str[start_idx],substr); + if(ret){ + sq_pushinteger(v,(SQInteger)(ret-str)); + return 1; + } + } + return 0; + } + return sq_throwerror(v,_SC("invalid param")); +} + +#define STRING_TOFUNCZ(func) static SQInteger string_##func(HSQUIRRELVM v) \ +{ \ + SQObject str=stack_get(v,1); \ + SQInteger len=_string(str)->_len; \ + const SQChar *sThis=_stringval(str); \ + SQChar *sNew=(_ss(v)->GetScratchPad(rsl(len))); \ + for(SQInteger i=0;i<len;i++) sNew[i]=func(sThis[i]); \ + v->Push(SQString::Create(_ss(v),sNew,len)); \ + return 1; \ +} + + +STRING_TOFUNCZ(tolower) +STRING_TOFUNCZ(toupper) + +SQRegFunction SQSharedState::_string_default_delegate_funcz[]={ + {_SC("len"),default_delegate_len,1, _SC("s")}, + {_SC("tointeger"),default_delegate_tointeger,1, _SC("s")}, + {_SC("tofloat"),default_delegate_tofloat,1, _SC("s")}, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, + {_SC("slice"),string_slice,-1, _SC(" s n n")}, + {_SC("find"),string_find,-2, _SC("s s n ")}, + {_SC("tolower"),string_tolower,1, _SC("s")}, + {_SC("toupper"),string_toupper,1, _SC("s")}, + {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {0,0} +}; + +//INTEGER DEFAULT DELEGATE////////////////////////// +SQRegFunction SQSharedState::_number_default_delegate_funcz[]={ + {_SC("tointeger"),default_delegate_tointeger,1, _SC("n|b")}, + {_SC("tofloat"),default_delegate_tofloat,1, _SC("n|b")}, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, + {_SC("tochar"),number_delegate_tochar,1, _SC("n|b")}, + {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {0,0} +}; + +//CLOSURE DEFAULT DELEGATE////////////////////////// +static SQInteger closure_pcall(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue,SQFalse))?1:SQ_ERROR; +} + +static SQInteger closure_call(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue,SQTrue))?1:SQ_ERROR; +} + +static SQInteger _closure_acall(HSQUIRRELVM v,SQBool raiseerror) +{ + SQArray *aparams=_array(stack_get(v,2)); + SQInteger nparams=aparams->Size(); + v->Push(stack_get(v,1)); + for(SQInteger i=0;i<nparams;i++)v->Push(aparams->_values[i]); + return SQ_SUCCEEDED(sq_call(v,nparams,SQTrue,raiseerror))?1:SQ_ERROR; +} + +static SQInteger closure_acall(HSQUIRRELVM v) +{ + return _closure_acall(v,SQTrue); +} + +static SQInteger closure_pacall(HSQUIRRELVM v) +{ + return _closure_acall(v,SQFalse); +} + +static SQInteger closure_bindenv(HSQUIRRELVM v) +{ + if(SQ_FAILED(sq_bindenv(v,1))) + return SQ_ERROR; + return 1; +} + +static SQInteger closure_getinfos(HSQUIRRELVM v) { + SQObject o = stack_get(v,1); + SQTable *res = SQTable::Create(_ss(v),4); + if(type(o) == OT_CLOSURE) { + SQFunctionProto *f = _closure(o)->_function; + SQInteger nparams = f->_nparameters + (f->_varparams?1:0); + SQObjectPtr params = SQArray::Create(_ss(v),nparams); + for(SQInteger n = 0; n<f->_nparameters; n++) { + _array(params)->Set((SQInteger)n,f->_parameters[n]); + } + if(f->_varparams) { + _array(params)->Set(nparams-1,SQString::Create(_ss(v),_SC("..."),-1)); + } + res->NewSlot(SQString::Create(_ss(v),_SC("native"),-1),false); + res->NewSlot(SQString::Create(_ss(v),_SC("name"),-1),f->_name); + res->NewSlot(SQString::Create(_ss(v),_SC("src"),-1),f->_sourcename); + res->NewSlot(SQString::Create(_ss(v),_SC("parameters"),-1),params); + res->NewSlot(SQString::Create(_ss(v),_SC("varargs"),-1),f->_varparams); + } + else { //OT_NATIVECLOSURE + SQNativeClosure *nc = _nativeclosure(o); + res->NewSlot(SQString::Create(_ss(v),_SC("native"),-1),true); + res->NewSlot(SQString::Create(_ss(v),_SC("name"),-1),nc->_name); + res->NewSlot(SQString::Create(_ss(v),_SC("paramscheck"),-1),nc->_nparamscheck); + SQObjectPtr typecheck; + if(nc->_typecheck.size() > 0) { + typecheck = + SQArray::Create(_ss(v), nc->_typecheck.size()); + for(SQUnsignedInteger n = 0; n<nc->_typecheck.size(); n++) { + _array(typecheck)->Set((SQInteger)n,nc->_typecheck[n]); + } + } + res->NewSlot(SQString::Create(_ss(v),_SC("typecheck"),-1),typecheck); + } + v->Push(res); + return 1; +} + + +SQRegFunction SQSharedState::_closure_default_delegate_funcz[]={ + {_SC("call"),closure_call,-1, _SC("c")}, + {_SC("pcall"),closure_pcall,-1, _SC("c")}, + {_SC("acall"),closure_acall,2, _SC("ca")}, + {_SC("pacall"),closure_pacall,2, _SC("ca")}, + {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, + {_SC("bindenv"),closure_bindenv,2, _SC("c x|y|t")}, + {_SC("getinfos"),closure_getinfos,1, _SC("c")}, + {0,0} +}; + +//GENERATOR DEFAULT DELEGATE +static SQInteger generator_getstatus(HSQUIRRELVM v) +{ + SQObject &o=stack_get(v,1); + switch(_generator(o)->_state){ + case SQGenerator::eSuspended:v->Push(SQString::Create(_ss(v),_SC("suspended")));break; + case SQGenerator::eRunning:v->Push(SQString::Create(_ss(v),_SC("running")));break; + case SQGenerator::eDead:v->Push(SQString::Create(_ss(v),_SC("dead")));break; + } + return 1; +} + +SQRegFunction SQSharedState::_generator_default_delegate_funcz[]={ + {_SC("getstatus"),generator_getstatus,1, _SC("g")}, + {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, + {0,0} +}; + +//THREAD DEFAULT DELEGATE +static SQInteger thread_call(HSQUIRRELVM v) +{ + SQObjectPtr o = stack_get(v,1); + if(type(o) == OT_THREAD) { + SQInteger nparams = sq_gettop(v); + _thread(o)->Push(_thread(o)->_roottable); + for(SQInteger i = 2; i<(nparams+1); i++) + sq_move(_thread(o),v,i); + if(SQ_SUCCEEDED(sq_call(_thread(o),nparams,SQTrue,SQFalse))) { + sq_move(v,_thread(o),-1); + sq_pop(_thread(o),1); + return 1; + } + v->_lasterror = _thread(o)->_lasterror; + return SQ_ERROR; + } + return sq_throwerror(v,_SC("wrong parameter")); +} + +static SQInteger thread_wakeup(HSQUIRRELVM v) +{ + SQObjectPtr o = stack_get(v,1); + if(type(o) == OT_THREAD) { + SQVM *thread = _thread(o); + SQInteger state = sq_getvmstate(thread); + if(state != SQ_VMSTATE_SUSPENDED) { + switch(state) { + case SQ_VMSTATE_IDLE: + return sq_throwerror(v,_SC("cannot wakeup a idle thread")); + break; + case SQ_VMSTATE_RUNNING: + return sq_throwerror(v,_SC("cannot wakeup a running thread")); + break; + } + } + + SQInteger wakeupret = sq_gettop(v)>1?1:0; + if(wakeupret) { + sq_move(thread,v,2); + } + if(SQ_SUCCEEDED(sq_wakeupvm(thread,wakeupret,SQTrue,SQTrue,SQFalse))) { + sq_move(v,thread,-1); + sq_pop(thread,1); //pop retval + if(sq_getvmstate(thread) == SQ_VMSTATE_IDLE) { + sq_settop(thread,1); //pop roottable + } + return 1; + } + sq_settop(thread,1); + v->_lasterror = thread->_lasterror; + return SQ_ERROR; + } + return sq_throwerror(v,_SC("wrong parameter")); +} + +static SQInteger thread_getstatus(HSQUIRRELVM v) +{ + SQObjectPtr &o = stack_get(v,1); + switch(sq_getvmstate(_thread(o))) { + case SQ_VMSTATE_IDLE: + sq_pushstring(v,_SC("idle"),-1); + break; + case SQ_VMSTATE_RUNNING: + sq_pushstring(v,_SC("running"),-1); + break; + case SQ_VMSTATE_SUSPENDED: + sq_pushstring(v,_SC("suspended"),-1); + break; + default: + return sq_throwerror(v,_SC("internal VM error")); + } + return 1; +} + +static SQInteger thread_getstackinfos(HSQUIRRELVM v) +{ + SQObjectPtr o = stack_get(v,1); + if(type(o) == OT_THREAD) { + SQVM *thread = _thread(o); + SQInteger threadtop = sq_gettop(thread); + SQInteger level; + sq_getinteger(v,-1,&level); + SQRESULT res = __getcallstackinfos(thread,level); + if(SQ_FAILED(res)) + { + sq_settop(thread,threadtop); + if(type(thread->_lasterror) == OT_STRING) { + sq_throwerror(v,_stringval(thread->_lasterror)); + } + else { + sq_throwerror(v,_SC("unknown error")); + } + } + if(res > 0) { + //some result + sq_move(v,thread,-1); + sq_settop(thread,threadtop); + return 1; + } + //no result + sq_settop(thread,threadtop); + return 0; + + } + return sq_throwerror(v,_SC("wrong parameter")); +} + +SQRegFunction SQSharedState::_thread_default_delegate_funcz[] = { + {_SC("call"), thread_call, -1, _SC("v")}, + {_SC("wakeup"), thread_wakeup, -1, _SC("v")}, + {_SC("getstatus"), thread_getstatus, 1, _SC("v")}, + {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {_SC("getstackinfos"),thread_getstackinfos,2, _SC("vn")}, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, + {0,0}, +}; + +static SQInteger class_getattributes(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_getattributes(v,-2))?1:SQ_ERROR; +} + +static SQInteger class_setattributes(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_setattributes(v,-3))?1:SQ_ERROR; +} + +static SQInteger class_instance(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_createinstance(v,-1))?1:SQ_ERROR; +} + +static SQInteger class_getbase(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_getbase(v,-1))?1:SQ_ERROR; +} + +SQRegFunction SQSharedState::_class_default_delegate_funcz[] = { + {_SC("getattributes"), class_getattributes, 2, _SC("y.")}, + {_SC("setattributes"), class_setattributes, 3, _SC("y..")}, + {_SC("rawget"),container_rawget,2, _SC("y")}, + {_SC("rawset"),container_rawset,3, _SC("y")}, + {_SC("rawin"),container_rawexists,2, _SC("y")}, + {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, + {_SC("instance"),class_instance,1, _SC("y")}, + {_SC("getbase"),class_getbase,1, _SC("y")}, + {0,0} +}; + +static SQInteger instance_getclass(HSQUIRRELVM v) +{ + if(SQ_SUCCEEDED(sq_getclass(v,1))) + return 1; + return SQ_ERROR; +} + +SQRegFunction SQSharedState::_instance_default_delegate_funcz[] = { + {_SC("getclass"), instance_getclass, 1, _SC("x")}, + {_SC("rawget"),container_rawget,2, _SC("x")}, + {_SC("rawset"),container_rawset,3, _SC("x")}, + {_SC("rawin"),container_rawexists,2, _SC("x")}, + {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, + {0,0} +}; + +static SQInteger weakref_ref(HSQUIRRELVM v) +{ + if(SQ_FAILED(sq_getweakrefval(v,1))) + return SQ_ERROR; + return 1; +} + +SQRegFunction SQSharedState::_weakref_default_delegate_funcz[] = { + {_SC("ref"),weakref_ref,1, _SC("r")}, + {_SC("weakref"),obj_delegate_weakref,1, NULL }, + {_SC("tostring"),default_delegate_tostring,1, _SC(".")}, + {0,0} +}; + diff --git a/squirrel_3_0_1_stable/squirrel/sqclass.cpp b/squirrel_3_0_1_stable/squirrel/sqclass.cpp index 1f26cc92f..dcee77d70 100644 --- a/squirrel_3_0_1_stable/squirrel/sqclass.cpp +++ b/squirrel_3_0_1_stable/squirrel/sqclass.cpp @@ -1,213 +1,213 @@ -/*
- see copyright notice in squirrel.h
-*/
-#include "sqpcheader.h"
-#include "sqvm.h"
-#include "sqtable.h"
-#include "sqclass.h"
-#include "sqfuncproto.h"
-#include "sqclosure.h"
-
-
-
-SQClass::SQClass(SQSharedState *ss,SQClass *base)
-{
- _base = base;
- _typetag = 0;
- _hook = NULL;
- _udsize = 0;
- _locked = false;
- _constructoridx = -1;
- if(_base) {
- _constructoridx = _base->_constructoridx;
- _udsize = _base->_udsize;
- _defaultvalues.copy(base->_defaultvalues);
- _methods.copy(base->_methods);
- _COPY_VECTOR(_metamethods,base->_metamethods,MT_LAST);
- __ObjAddRef(_base);
- }
- _members = base?base->_members->Clone() : SQTable::Create(ss,0);
- __ObjAddRef(_members);
-
- INIT_CHAIN();
- ADD_TO_CHAIN(&_sharedstate->_gc_chain, this);
-}
-
-void SQClass::Finalize() {
- _attributes.Null();
- _defaultvalues.resize(0);
- _methods.resize(0);
- _NULL_SQOBJECT_VECTOR(_metamethods,MT_LAST);
- __ObjRelease(_members);
- if(_base) {
- __ObjRelease(_base);
- }
-}
-
-SQClass::~SQClass()
-{
- REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this);
- Finalize();
-}
-
-bool SQClass::NewSlot(SQSharedState *ss,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic)
-{
- SQObjectPtr temp;
- bool belongs_to_static_table = type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE || bstatic;
- if(_locked && !belongs_to_static_table)
- return false; //the class already has an instance so cannot be modified
- if(_members->Get(key,temp) && _isfield(temp)) //overrides the default value
- {
- _defaultvalues[_member_idx(temp)].val = val;
- return true;
- }
- if(belongs_to_static_table) {
- SQInteger mmidx;
- if((type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE) &&
- (mmidx = ss->GetMetaMethodIdxByName(key)) != -1) {
- _metamethods[mmidx] = val;
- }
- else {
- SQObjectPtr theval = val;
- if(_base && type(val) == OT_CLOSURE) {
- theval = _closure(val)->Clone();
- _closure(theval)->_base = _base;
- __ObjAddRef(_base); //ref for the closure
- }
- if(type(temp) == OT_NULL) {
- bool isconstructor;
- SQVM::IsEqual(ss->_constructoridx, key, isconstructor);
- if(isconstructor) {
- _constructoridx = (SQInteger)_methods.size();
- }
- SQClassMember m;
- m.val = theval;
- _members->NewSlot(key,SQObjectPtr(_make_method_idx(_methods.size())));
- _methods.push_back(m);
- }
- else {
- _methods[_member_idx(temp)].val = theval;
- }
- }
- return true;
- }
- SQClassMember m;
- m.val = val;
- _members->NewSlot(key,SQObjectPtr(_make_field_idx(_defaultvalues.size())));
- _defaultvalues.push_back(m);
- return true;
-}
-
-SQInstance *SQClass::CreateInstance()
-{
- if(!_locked) Lock();
- return SQInstance::Create(_opt_ss(this),this);
-}
-
-SQInteger SQClass::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval)
-{
- SQObjectPtr oval;
- SQInteger idx = _members->Next(false,refpos,outkey,oval);
- if(idx != -1) {
- if(_ismethod(oval)) {
- outval = _methods[_member_idx(oval)].val;
- }
- else {
- SQObjectPtr &o = _defaultvalues[_member_idx(oval)].val;
- outval = _realval(o);
- }
- }
- return idx;
-}
-
-bool SQClass::SetAttributes(const SQObjectPtr &key,const SQObjectPtr &val)
-{
- SQObjectPtr idx;
- if(_members->Get(key,idx)) {
- if(_isfield(idx))
- _defaultvalues[_member_idx(idx)].attrs = val;
- else
- _methods[_member_idx(idx)].attrs = val;
- return true;
- }
- return false;
-}
-
-bool SQClass::GetAttributes(const SQObjectPtr &key,SQObjectPtr &outval)
-{
- SQObjectPtr idx;
- if(_members->Get(key,idx)) {
- outval = (_isfield(idx)?_defaultvalues[_member_idx(idx)].attrs:_methods[_member_idx(idx)].attrs);
- return true;
- }
- return false;
-}
-
-///////////////////////////////////////////////////////////////////////
-void SQInstance::Init(SQSharedState *ss)
-{
- _userpointer = NULL;
- _hook = NULL;
- __ObjAddRef(_class);
- _delegate = _class->_members;
- INIT_CHAIN();
- ADD_TO_CHAIN(&_sharedstate->_gc_chain, this);
-}
-
-SQInstance::SQInstance(SQSharedState *ss, SQClass *c, SQInteger memsize)
-{
- _memsize = memsize;
- _class = c;
- SQUnsignedInteger nvalues = _class->_defaultvalues.size();
- for(SQUnsignedInteger n = 0; n < nvalues; n++) {
- new (&_values[n]) SQObjectPtr(_class->_defaultvalues[n].val);
- }
- Init(ss);
-}
-
-SQInstance::SQInstance(SQSharedState *ss, SQInstance *i, SQInteger memsize)
-{
- _memsize = memsize;
- _class = i->_class;
- SQUnsignedInteger nvalues = _class->_defaultvalues.size();
- for(SQUnsignedInteger n = 0; n < nvalues; n++) {
- new (&_values[n]) SQObjectPtr(i->_values[n]);
- }
- Init(ss);
-}
-
-void SQInstance::Finalize()
-{
- SQUnsignedInteger nvalues = _class->_defaultvalues.size();
- __ObjRelease(_class);
- _NULL_SQOBJECT_VECTOR(_values,nvalues);
- //for(SQUnsignedInteger i = 0; i < nvalues; i++) {
-// _values[i].Null();
-// }
-}
-
-SQInstance::~SQInstance()
-{
- REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this);
- if(_class){ Finalize(); } //if _class is null it was already finalized by the GC
-}
-
-bool SQInstance::GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res)
-{
- if(type(_class->_metamethods[mm]) != OT_NULL) {
- res = _class->_metamethods[mm];
- return true;
- }
- return false;
-}
-
-bool SQInstance::InstanceOf(SQClass *trg)
-{
- SQClass *parent = _class;
- while(parent != NULL) {
- if(parent == trg)
- return true;
- parent = parent->_base;
- }
- return false;
-}
+/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include "sqvm.h" +#include "sqtable.h" +#include "sqclass.h" +#include "sqfuncproto.h" +#include "sqclosure.h" + + + +SQClass::SQClass(SQSharedState *ss,SQClass *base) +{ + _base = base; + _typetag = 0; + _hook = NULL; + _udsize = 0; + _locked = false; + _constructoridx = -1; + if(_base) { + _constructoridx = _base->_constructoridx; + _udsize = _base->_udsize; + _defaultvalues.copy(base->_defaultvalues); + _methods.copy(base->_methods); + _COPY_VECTOR(_metamethods,base->_metamethods,MT_LAST); + __ObjAddRef(_base); + } + _members = base?base->_members->Clone() : SQTable::Create(ss,0); + __ObjAddRef(_members); + + INIT_CHAIN(); + ADD_TO_CHAIN(&_sharedstate->_gc_chain, this); +} + +void SQClass::Finalize() { + _attributes.Null(); + _defaultvalues.resize(0); + _methods.resize(0); + _NULL_SQOBJECT_VECTOR(_metamethods,MT_LAST); + __ObjRelease(_members); + if(_base) { + __ObjRelease(_base); + } +} + +SQClass::~SQClass() +{ + REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); + Finalize(); +} + +bool SQClass::NewSlot(SQSharedState *ss,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic) +{ + SQObjectPtr temp; + bool belongs_to_static_table = type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE || bstatic; + if(_locked && !belongs_to_static_table) + return false; //the class already has an instance so cannot be modified + if(_members->Get(key,temp) && _isfield(temp)) //overrides the default value + { + _defaultvalues[_member_idx(temp)].val = val; + return true; + } + if(belongs_to_static_table) { + SQInteger mmidx; + if((type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE) && + (mmidx = ss->GetMetaMethodIdxByName(key)) != -1) { + _metamethods[mmidx] = val; + } + else { + SQObjectPtr theval = val; + if(_base && type(val) == OT_CLOSURE) { + theval = _closure(val)->Clone(); + _closure(theval)->_base = _base; + __ObjAddRef(_base); //ref for the closure + } + if(type(temp) == OT_NULL) { + bool isconstructor; + SQVM::IsEqual(ss->_constructoridx, key, isconstructor); + if(isconstructor) { + _constructoridx = (SQInteger)_methods.size(); + } + SQClassMember m; + m.val = theval; + _members->NewSlot(key,SQObjectPtr(_make_method_idx(_methods.size()))); + _methods.push_back(m); + } + else { + _methods[_member_idx(temp)].val = theval; + } + } + return true; + } + SQClassMember m; + m.val = val; + _members->NewSlot(key,SQObjectPtr(_make_field_idx(_defaultvalues.size()))); + _defaultvalues.push_back(m); + return true; +} + +SQInstance *SQClass::CreateInstance() +{ + if(!_locked) Lock(); + return SQInstance::Create(_opt_ss(this),this); +} + +SQInteger SQClass::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval) +{ + SQObjectPtr oval; + SQInteger idx = _members->Next(false,refpos,outkey,oval); + if(idx != -1) { + if(_ismethod(oval)) { + outval = _methods[_member_idx(oval)].val; + } + else { + SQObjectPtr &o = _defaultvalues[_member_idx(oval)].val; + outval = _realval(o); + } + } + return idx; +} + +bool SQClass::SetAttributes(const SQObjectPtr &key,const SQObjectPtr &val) +{ + SQObjectPtr idx; + if(_members->Get(key,idx)) { + if(_isfield(idx)) + _defaultvalues[_member_idx(idx)].attrs = val; + else + _methods[_member_idx(idx)].attrs = val; + return true; + } + return false; +} + +bool SQClass::GetAttributes(const SQObjectPtr &key,SQObjectPtr &outval) +{ + SQObjectPtr idx; + if(_members->Get(key,idx)) { + outval = (_isfield(idx)?_defaultvalues[_member_idx(idx)].attrs:_methods[_member_idx(idx)].attrs); + return true; + } + return false; +} + +/////////////////////////////////////////////////////////////////////// +void SQInstance::Init(SQSharedState *ss) +{ + _userpointer = NULL; + _hook = NULL; + __ObjAddRef(_class); + _delegate = _class->_members; + INIT_CHAIN(); + ADD_TO_CHAIN(&_sharedstate->_gc_chain, this); +} + +SQInstance::SQInstance(SQSharedState *ss, SQClass *c, SQInteger memsize) +{ + _memsize = memsize; + _class = c; + SQUnsignedInteger nvalues = _class->_defaultvalues.size(); + for(SQUnsignedInteger n = 0; n < nvalues; n++) { + new (&_values[n]) SQObjectPtr(_class->_defaultvalues[n].val); + } + Init(ss); +} + +SQInstance::SQInstance(SQSharedState *ss, SQInstance *i, SQInteger memsize) +{ + _memsize = memsize; + _class = i->_class; + SQUnsignedInteger nvalues = _class->_defaultvalues.size(); + for(SQUnsignedInteger n = 0; n < nvalues; n++) { + new (&_values[n]) SQObjectPtr(i->_values[n]); + } + Init(ss); +} + +void SQInstance::Finalize() +{ + SQUnsignedInteger nvalues = _class->_defaultvalues.size(); + __ObjRelease(_class); + _NULL_SQOBJECT_VECTOR(_values,nvalues); + //for(SQUnsignedInteger i = 0; i < nvalues; i++) { +// _values[i].Null(); +// } +} + +SQInstance::~SQInstance() +{ + REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); + if(_class){ Finalize(); } //if _class is null it was already finalized by the GC +} + +bool SQInstance::GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res) +{ + if(type(_class->_metamethods[mm]) != OT_NULL) { + res = _class->_metamethods[mm]; + return true; + } + return false; +} + +bool SQInstance::InstanceOf(SQClass *trg) +{ + SQClass *parent = _class; + while(parent != NULL) { + if(parent == trg) + return true; + parent = parent->_base; + } + return false; +} diff --git a/squirrel_3_0_1_stable/squirrel/sqclass.h b/squirrel_3_0_1_stable/squirrel/sqclass.h index 996a3df70..5c1fe2d20 100644 --- a/squirrel_3_0_1_stable/squirrel/sqclass.h +++ b/squirrel_3_0_1_stable/squirrel/sqclass.h @@ -1,158 +1,158 @@ -/* see copyright notice in squirrel.h */
-#ifndef _SQCLASS_H_
-#define _SQCLASS_H_
-
-struct SQInstance;
-
-struct SQClassMember {
- SQObjectPtr val;
- SQObjectPtr attrs;
-};
-
-typedef sqvector<SQClassMember> SQClassMemberVec;
-
-#define MEMBER_TYPE_METHOD 0x01000000
-#define MEMBER_TYPE_FIELD 0x02000000
-
-#define _ismethod(o) (_integer(o)&MEMBER_TYPE_METHOD)
-#define _isfield(o) (_integer(o)&MEMBER_TYPE_FIELD)
-#define _make_method_idx(i) ((SQInteger)(MEMBER_TYPE_METHOD|i))
-#define _make_field_idx(i) ((SQInteger)(MEMBER_TYPE_FIELD|i))
-#define _member_type(o) (_integer(o)&0xFF000000)
-#define _member_idx(o) (_integer(o)&0x00FFFFFF)
-
-struct SQClass : public CHAINABLE_OBJ
-{
- SQClass(SQSharedState *ss,SQClass *base);
-public:
- static SQClass* Create(SQSharedState *ss,SQClass *base) {
- SQClass *newclass = (SQClass *)SQ_MALLOC(sizeof(SQClass));
- new (newclass) SQClass(ss, base);
- return newclass;
- }
- ~SQClass();
- bool NewSlot(SQSharedState *ss, const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic);
- bool Get(const SQObjectPtr &key,SQObjectPtr &val) {
- if(_members->Get(key,val)) {
- if(_isfield(val)) {
- SQObjectPtr &o = _defaultvalues[_member_idx(val)].val;
- val = _realval(o);
- }
- else {
- val = _methods[_member_idx(val)].val;
- }
- return true;
- }
- return false;
- }
- bool GetConstructor(SQObjectPtr &ctor)
- {
- if(_constructoridx != -1) {
- ctor = _methods[_constructoridx].val;
- return true;
- }
- return false;
- }
- bool SetAttributes(const SQObjectPtr &key,const SQObjectPtr &val);
- bool GetAttributes(const SQObjectPtr &key,SQObjectPtr &outval);
- void Lock() { _locked = true; if(_base) _base->Lock(); }
- void Release() {
- if (_hook) { _hook(_typetag,0);}
- sq_delete(this, SQClass);
- }
- void Finalize();
-#ifndef NO_GARBAGE_COLLECTOR
- void Mark(SQCollectable ** );
- SQObjectType GetType() {return OT_CLASS;}
-#endif
- SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval);
- SQInstance *CreateInstance();
- SQTable *_members;
- SQClass *_base;
- SQClassMemberVec _defaultvalues;
- SQClassMemberVec _methods;
- SQObjectPtr _metamethods[MT_LAST];
- SQObjectPtr _attributes;
- SQUserPointer _typetag;
- SQRELEASEHOOK _hook;
- bool _locked;
- SQInteger _constructoridx;
- SQInteger _udsize;
-};
-
-#define calcinstancesize(_theclass_) \
- (_theclass_->_udsize + sq_aligning(sizeof(SQInstance) + (sizeof(SQObjectPtr)*(_theclass_->_defaultvalues.size()>0?_theclass_->_defaultvalues.size()-1:0))))
-
-struct SQInstance : public SQDelegable
-{
- void Init(SQSharedState *ss);
- SQInstance(SQSharedState *ss, SQClass *c, SQInteger memsize);
- SQInstance(SQSharedState *ss, SQInstance *c, SQInteger memsize);
-public:
- static SQInstance* Create(SQSharedState *ss,SQClass *theclass) {
-
- SQInteger size = calcinstancesize(theclass);
- SQInstance *newinst = (SQInstance *)SQ_MALLOC(size);
- new (newinst) SQInstance(ss, theclass,size);
- if(theclass->_udsize) {
- newinst->_userpointer = ((unsigned char *)newinst) + (size - theclass->_udsize);
- }
- return newinst;
- }
- SQInstance *Clone(SQSharedState *ss)
- {
- SQInteger size = calcinstancesize(_class);
- SQInstance *newinst = (SQInstance *)SQ_MALLOC(size);
- new (newinst) SQInstance(ss, this,size);
- if(_class->_udsize) {
- newinst->_userpointer = ((unsigned char *)newinst) + (size - _class->_udsize);
- }
- return newinst;
- }
- ~SQInstance();
- bool Get(const SQObjectPtr &key,SQObjectPtr &val) {
- if(_class->_members->Get(key,val)) {
- if(_isfield(val)) {
- SQObjectPtr &o = _values[_member_idx(val)];
- val = _realval(o);
- }
- else {
- val = _class->_methods[_member_idx(val)].val;
- }
- return true;
- }
- return false;
- }
- bool Set(const SQObjectPtr &key,const SQObjectPtr &val) {
- SQObjectPtr idx;
- if(_class->_members->Get(key,idx) && _isfield(idx)) {
- _values[_member_idx(idx)] = val;
- return true;
- }
- return false;
- }
- void Release() {
- _uiRef++;
- if (_hook) { _hook(_userpointer,0);}
- _uiRef--;
- if(_uiRef > 0) return;
- SQInteger size = _memsize;
- this->~SQInstance();
- SQ_FREE(this, size);
- }
- void Finalize();
-#ifndef NO_GARBAGE_COLLECTOR
- void Mark(SQCollectable ** );
- SQObjectType GetType() {return OT_INSTANCE;}
-#endif
- bool InstanceOf(SQClass *trg);
- bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res);
-
- SQClass *_class;
- SQUserPointer _userpointer;
- SQRELEASEHOOK _hook;
- SQInteger _memsize;
- SQObjectPtr _values[1];
-};
-
-#endif //_SQCLASS_H_
+/* see copyright notice in squirrel.h */ +#ifndef _SQCLASS_H_ +#define _SQCLASS_H_ + +struct SQInstance; + +struct SQClassMember { + SQObjectPtr val; + SQObjectPtr attrs; +}; + +typedef sqvector<SQClassMember> SQClassMemberVec; + +#define MEMBER_TYPE_METHOD 0x01000000 +#define MEMBER_TYPE_FIELD 0x02000000 + +#define _ismethod(o) (_integer(o)&MEMBER_TYPE_METHOD) +#define _isfield(o) (_integer(o)&MEMBER_TYPE_FIELD) +#define _make_method_idx(i) ((SQInteger)(MEMBER_TYPE_METHOD|i)) +#define _make_field_idx(i) ((SQInteger)(MEMBER_TYPE_FIELD|i)) +#define _member_type(o) (_integer(o)&0xFF000000) +#define _member_idx(o) (_integer(o)&0x00FFFFFF) + +struct SQClass : public CHAINABLE_OBJ +{ + SQClass(SQSharedState *ss,SQClass *base); +public: + static SQClass* Create(SQSharedState *ss,SQClass *base) { + SQClass *newclass = (SQClass *)SQ_MALLOC(sizeof(SQClass)); + new (newclass) SQClass(ss, base); + return newclass; + } + ~SQClass(); + bool NewSlot(SQSharedState *ss, const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic); + bool Get(const SQObjectPtr &key,SQObjectPtr &val) { + if(_members->Get(key,val)) { + if(_isfield(val)) { + SQObjectPtr &o = _defaultvalues[_member_idx(val)].val; + val = _realval(o); + } + else { + val = _methods[_member_idx(val)].val; + } + return true; + } + return false; + } + bool GetConstructor(SQObjectPtr &ctor) + { + if(_constructoridx != -1) { + ctor = _methods[_constructoridx].val; + return true; + } + return false; + } + bool SetAttributes(const SQObjectPtr &key,const SQObjectPtr &val); + bool GetAttributes(const SQObjectPtr &key,SQObjectPtr &outval); + void Lock() { _locked = true; if(_base) _base->Lock(); } + void Release() { + if (_hook) { _hook(_typetag,0);} + sq_delete(this, SQClass); + } + void Finalize(); +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable ** ); + SQObjectType GetType() {return OT_CLASS;} +#endif + SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval); + SQInstance *CreateInstance(); + SQTable *_members; + SQClass *_base; + SQClassMemberVec _defaultvalues; + SQClassMemberVec _methods; + SQObjectPtr _metamethods[MT_LAST]; + SQObjectPtr _attributes; + SQUserPointer _typetag; + SQRELEASEHOOK _hook; + bool _locked; + SQInteger _constructoridx; + SQInteger _udsize; +}; + +#define calcinstancesize(_theclass_) \ + (_theclass_->_udsize + sq_aligning(sizeof(SQInstance) + (sizeof(SQObjectPtr)*(_theclass_->_defaultvalues.size()>0?_theclass_->_defaultvalues.size()-1:0)))) + +struct SQInstance : public SQDelegable +{ + void Init(SQSharedState *ss); + SQInstance(SQSharedState *ss, SQClass *c, SQInteger memsize); + SQInstance(SQSharedState *ss, SQInstance *c, SQInteger memsize); +public: + static SQInstance* Create(SQSharedState *ss,SQClass *theclass) { + + SQInteger size = calcinstancesize(theclass); + SQInstance *newinst = (SQInstance *)SQ_MALLOC(size); + new (newinst) SQInstance(ss, theclass,size); + if(theclass->_udsize) { + newinst->_userpointer = ((unsigned char *)newinst) + (size - theclass->_udsize); + } + return newinst; + } + SQInstance *Clone(SQSharedState *ss) + { + SQInteger size = calcinstancesize(_class); + SQInstance *newinst = (SQInstance *)SQ_MALLOC(size); + new (newinst) SQInstance(ss, this,size); + if(_class->_udsize) { + newinst->_userpointer = ((unsigned char *)newinst) + (size - _class->_udsize); + } + return newinst; + } + ~SQInstance(); + bool Get(const SQObjectPtr &key,SQObjectPtr &val) { + if(_class->_members->Get(key,val)) { + if(_isfield(val)) { + SQObjectPtr &o = _values[_member_idx(val)]; + val = _realval(o); + } + else { + val = _class->_methods[_member_idx(val)].val; + } + return true; + } + return false; + } + bool Set(const SQObjectPtr &key,const SQObjectPtr &val) { + SQObjectPtr idx; + if(_class->_members->Get(key,idx) && _isfield(idx)) { + _values[_member_idx(idx)] = val; + return true; + } + return false; + } + void Release() { + _uiRef++; + if (_hook) { _hook(_userpointer,0);} + _uiRef--; + if(_uiRef > 0) return; + SQInteger size = _memsize; + this->~SQInstance(); + SQ_FREE(this, size); + } + void Finalize(); +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable ** ); + SQObjectType GetType() {return OT_INSTANCE;} +#endif + bool InstanceOf(SQClass *trg); + bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res); + + SQClass *_class; + SQUserPointer _userpointer; + SQRELEASEHOOK _hook; + SQInteger _memsize; + SQObjectPtr _values[1]; +}; + +#endif //_SQCLASS_H_ diff --git a/squirrel_3_0_1_stable/squirrel/sqclosure.h b/squirrel_3_0_1_stable/squirrel/sqclosure.h index 07b3efcfe..353eb5041 100644 --- a/squirrel_3_0_1_stable/squirrel/sqclosure.h +++ b/squirrel_3_0_1_stable/squirrel/sqclosure.h @@ -1,193 +1,193 @@ -/* see copyright notice in squirrel.h */
-#ifndef _SQCLOSURE_H_
-#define _SQCLOSURE_H_
-
-
-#define _CALC_CLOSURE_SIZE(func) (sizeof(SQClosure) + (func->_noutervalues*sizeof(SQObjectPtr)) + (func->_ndefaultparams*sizeof(SQObjectPtr)))
-
-struct SQFunctionProto;
-struct SQClass;
-struct SQClosure : public CHAINABLE_OBJ
-{
-private:
- SQClosure(SQSharedState *ss,SQFunctionProto *func){_function = func; __ObjAddRef(_function); _base = NULL; INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); _env = NULL;}
-public:
- static SQClosure *Create(SQSharedState *ss,SQFunctionProto *func){
- SQInteger size = _CALC_CLOSURE_SIZE(func);
- SQClosure *nc=(SQClosure*)SQ_MALLOC(size);
- new (nc) SQClosure(ss,func);
- nc->_outervalues = (SQObjectPtr *)(nc + 1);
- nc->_defaultparams = &nc->_outervalues[func->_noutervalues];
- _CONSTRUCT_VECTOR(SQObjectPtr,func->_noutervalues,nc->_outervalues);
- _CONSTRUCT_VECTOR(SQObjectPtr,func->_ndefaultparams,nc->_defaultparams);
- return nc;
- }
- void Release(){
- SQFunctionProto *f = _function;
- SQInteger size = _CALC_CLOSURE_SIZE(f);
- _DESTRUCT_VECTOR(SQObjectPtr,f->_noutervalues,_outervalues);
- _DESTRUCT_VECTOR(SQObjectPtr,f->_ndefaultparams,_defaultparams);
- __ObjRelease(_function);
- this->~SQClosure();
- sq_vm_free(this,size);
- }
-
- SQClosure *Clone()
- {
- SQFunctionProto *f = _function;
- SQClosure * ret = SQClosure::Create(_opt_ss(this),f);
- ret->_env = _env;
- if(ret->_env) __ObjAddRef(ret->_env);
- _COPY_VECTOR(ret->_outervalues,_outervalues,f->_noutervalues);
- _COPY_VECTOR(ret->_defaultparams,_defaultparams,f->_ndefaultparams);
- return ret;
- }
- ~SQClosure();
-
- bool Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write);
- static bool Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret);
-#ifndef NO_GARBAGE_COLLECTOR
- void Mark(SQCollectable **chain);
- void Finalize(){
- SQFunctionProto *f = _function;
- _NULL_SQOBJECT_VECTOR(_outervalues,f->_noutervalues);
- _NULL_SQOBJECT_VECTOR(_defaultparams,f->_ndefaultparams);
- }
- SQObjectType GetType() {return OT_CLOSURE;}
-#endif
- SQWeakRef *_env;
- SQClass *_base;
- SQFunctionProto *_function;
- SQObjectPtr *_outervalues;
- SQObjectPtr *_defaultparams;
-};
-
-//////////////////////////////////////////////
-struct SQOuter : public CHAINABLE_OBJ
-{
-
-private:
- SQOuter(SQSharedState *ss, SQObjectPtr *outer){_valptr = outer; _next = NULL; INIT_CHAIN(); ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); }
-
-public:
- static SQOuter *Create(SQSharedState *ss, SQObjectPtr *outer)
- {
- SQOuter *nc = (SQOuter*)SQ_MALLOC(sizeof(SQOuter));
- new (nc) SQOuter(ss, outer);
- return nc;
- }
- ~SQOuter() { REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); }
-
- void Release()
- {
- this->~SQOuter();
- sq_vm_free(this,sizeof(SQOuter));
- }
-
-#ifndef NO_GARBAGE_COLLECTOR
- void Mark(SQCollectable **chain);
- void Finalize() { _value.Null(); }
- SQObjectType GetType() {return OT_OUTER;}
-#endif
-
- SQObjectPtr *_valptr; /* pointer to value on stack, or _value below */
- SQInteger _idx; /* idx in stack array, for relocation */
- SQObjectPtr _value; /* value of outer after stack frame is closed */
- SQOuter *_next; /* pointer to next outer when frame is open */
-};
-
-//////////////////////////////////////////////
-struct SQGenerator : public CHAINABLE_OBJ
-{
- enum SQGeneratorState{eRunning,eSuspended,eDead};
-private:
- SQGenerator(SQSharedState *ss,SQClosure *closure){_closure=closure;_state=eRunning;_ci._generator=NULL;INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);}
-public:
- static SQGenerator *Create(SQSharedState *ss,SQClosure *closure){
- SQGenerator *nc=(SQGenerator*)SQ_MALLOC(sizeof(SQGenerator));
- new (nc) SQGenerator(ss,closure);
- return nc;
- }
- ~SQGenerator()
- {
- REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);
- }
- void Kill(){
- _state=eDead;
- _stack.resize(0);
- _closure.Null();}
- void Release(){
- sq_delete(this,SQGenerator);
- }
-
- bool Yield(SQVM *v,SQInteger target);
- bool Resume(SQVM *v,SQObjectPtr &dest);
-#ifndef NO_GARBAGE_COLLECTOR
- void Mark(SQCollectable **chain);
- void Finalize(){_stack.resize(0);_closure.Null();}
- SQObjectType GetType() {return OT_GENERATOR;}
-#endif
- SQObjectPtr _closure;
- SQObjectPtrVec _stack;
- SQVM::CallInfo _ci;
- ExceptionsTraps _etraps;
- SQGeneratorState _state;
-};
-
-#define _CALC_NATVIVECLOSURE_SIZE(noutervalues) (sizeof(SQNativeClosure) + (noutervalues*sizeof(SQObjectPtr)))
-
-struct SQNativeClosure : public CHAINABLE_OBJ
-{
-private:
- SQNativeClosure(SQSharedState *ss,SQFUNCTION func){_function=func;INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); _env = NULL;}
-public:
- static SQNativeClosure *Create(SQSharedState *ss,SQFUNCTION func,SQInteger nouters)
- {
- SQInteger size = _CALC_NATVIVECLOSURE_SIZE(nouters);
- SQNativeClosure *nc=(SQNativeClosure*)SQ_MALLOC(size);
- new (nc) SQNativeClosure(ss,func);
- nc->_outervalues = (SQObjectPtr *)(nc + 1);
- nc->_noutervalues = nouters;
- _CONSTRUCT_VECTOR(SQObjectPtr,nc->_noutervalues,nc->_outervalues);
- return nc;
- }
- SQNativeClosure *Clone()
- {
- SQNativeClosure * ret = SQNativeClosure::Create(_opt_ss(this),_function,_noutervalues);
- ret->_env = _env;
- if(ret->_env) __ObjAddRef(ret->_env);
- ret->_name = _name;
- _COPY_VECTOR(ret->_outervalues,_outervalues,_noutervalues);
- ret->_typecheck.copy(_typecheck);
- ret->_nparamscheck = _nparamscheck;
- return ret;
- }
- ~SQNativeClosure()
- {
- __ObjRelease(_env);
- REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);
- }
- void Release(){
- SQInteger size = _CALC_NATVIVECLOSURE_SIZE(_noutervalues);
- _DESTRUCT_VECTOR(SQObjectPtr,_noutervalues,_outervalues);
- this->~SQNativeClosure();
- sq_free(this,size);
- }
-
-#ifndef NO_GARBAGE_COLLECTOR
- void Mark(SQCollectable **chain);
- void Finalize() { _NULL_SQOBJECT_VECTOR(_outervalues,_noutervalues); }
- SQObjectType GetType() {return OT_NATIVECLOSURE;}
-#endif
- SQInteger _nparamscheck;
- SQIntVec _typecheck;
- SQObjectPtr *_outervalues;
- SQUnsignedInteger _noutervalues;
- SQWeakRef *_env;
- SQFUNCTION _function;
- SQObjectPtr _name;
-};
-
-
-
-#endif //_SQCLOSURE_H_
+/* see copyright notice in squirrel.h */ +#ifndef _SQCLOSURE_H_ +#define _SQCLOSURE_H_ + + +#define _CALC_CLOSURE_SIZE(func) (sizeof(SQClosure) + (func->_noutervalues*sizeof(SQObjectPtr)) + (func->_ndefaultparams*sizeof(SQObjectPtr))) + +struct SQFunctionProto; +struct SQClass; +struct SQClosure : public CHAINABLE_OBJ +{ +private: + SQClosure(SQSharedState *ss,SQFunctionProto *func){_function = func; __ObjAddRef(_function); _base = NULL; INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); _env = NULL;} +public: + static SQClosure *Create(SQSharedState *ss,SQFunctionProto *func){ + SQInteger size = _CALC_CLOSURE_SIZE(func); + SQClosure *nc=(SQClosure*)SQ_MALLOC(size); + new (nc) SQClosure(ss,func); + nc->_outervalues = (SQObjectPtr *)(nc + 1); + nc->_defaultparams = &nc->_outervalues[func->_noutervalues]; + _CONSTRUCT_VECTOR(SQObjectPtr,func->_noutervalues,nc->_outervalues); + _CONSTRUCT_VECTOR(SQObjectPtr,func->_ndefaultparams,nc->_defaultparams); + return nc; + } + void Release(){ + SQFunctionProto *f = _function; + SQInteger size = _CALC_CLOSURE_SIZE(f); + _DESTRUCT_VECTOR(SQObjectPtr,f->_noutervalues,_outervalues); + _DESTRUCT_VECTOR(SQObjectPtr,f->_ndefaultparams,_defaultparams); + __ObjRelease(_function); + this->~SQClosure(); + sq_vm_free(this,size); + } + + SQClosure *Clone() + { + SQFunctionProto *f = _function; + SQClosure * ret = SQClosure::Create(_opt_ss(this),f); + ret->_env = _env; + if(ret->_env) __ObjAddRef(ret->_env); + _COPY_VECTOR(ret->_outervalues,_outervalues,f->_noutervalues); + _COPY_VECTOR(ret->_defaultparams,_defaultparams,f->_ndefaultparams); + return ret; + } + ~SQClosure(); + + bool Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write); + static bool Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret); +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + void Finalize(){ + SQFunctionProto *f = _function; + _NULL_SQOBJECT_VECTOR(_outervalues,f->_noutervalues); + _NULL_SQOBJECT_VECTOR(_defaultparams,f->_ndefaultparams); + } + SQObjectType GetType() {return OT_CLOSURE;} +#endif + SQWeakRef *_env; + SQClass *_base; + SQFunctionProto *_function; + SQObjectPtr *_outervalues; + SQObjectPtr *_defaultparams; +}; + +////////////////////////////////////////////// +struct SQOuter : public CHAINABLE_OBJ +{ + +private: + SQOuter(SQSharedState *ss, SQObjectPtr *outer){_valptr = outer; _next = NULL; INIT_CHAIN(); ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); } + +public: + static SQOuter *Create(SQSharedState *ss, SQObjectPtr *outer) + { + SQOuter *nc = (SQOuter*)SQ_MALLOC(sizeof(SQOuter)); + new (nc) SQOuter(ss, outer); + return nc; + } + ~SQOuter() { REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); } + + void Release() + { + this->~SQOuter(); + sq_vm_free(this,sizeof(SQOuter)); + } + +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + void Finalize() { _value.Null(); } + SQObjectType GetType() {return OT_OUTER;} +#endif + + SQObjectPtr *_valptr; /* pointer to value on stack, or _value below */ + SQInteger _idx; /* idx in stack array, for relocation */ + SQObjectPtr _value; /* value of outer after stack frame is closed */ + SQOuter *_next; /* pointer to next outer when frame is open */ +}; + +////////////////////////////////////////////// +struct SQGenerator : public CHAINABLE_OBJ +{ + enum SQGeneratorState{eRunning,eSuspended,eDead}; +private: + SQGenerator(SQSharedState *ss,SQClosure *closure){_closure=closure;_state=eRunning;_ci._generator=NULL;INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);} +public: + static SQGenerator *Create(SQSharedState *ss,SQClosure *closure){ + SQGenerator *nc=(SQGenerator*)SQ_MALLOC(sizeof(SQGenerator)); + new (nc) SQGenerator(ss,closure); + return nc; + } + ~SQGenerator() + { + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); + } + void Kill(){ + _state=eDead; + _stack.resize(0); + _closure.Null();} + void Release(){ + sq_delete(this,SQGenerator); + } + + bool Yield(SQVM *v,SQInteger target); + bool Resume(SQVM *v,SQObjectPtr &dest); +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + void Finalize(){_stack.resize(0);_closure.Null();} + SQObjectType GetType() {return OT_GENERATOR;} +#endif + SQObjectPtr _closure; + SQObjectPtrVec _stack; + SQVM::CallInfo _ci; + ExceptionsTraps _etraps; + SQGeneratorState _state; +}; + +#define _CALC_NATVIVECLOSURE_SIZE(noutervalues) (sizeof(SQNativeClosure) + (noutervalues*sizeof(SQObjectPtr))) + +struct SQNativeClosure : public CHAINABLE_OBJ +{ +private: + SQNativeClosure(SQSharedState *ss,SQFUNCTION func){_function=func;INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); _env = NULL;} +public: + static SQNativeClosure *Create(SQSharedState *ss,SQFUNCTION func,SQInteger nouters) + { + SQInteger size = _CALC_NATVIVECLOSURE_SIZE(nouters); + SQNativeClosure *nc=(SQNativeClosure*)SQ_MALLOC(size); + new (nc) SQNativeClosure(ss,func); + nc->_outervalues = (SQObjectPtr *)(nc + 1); + nc->_noutervalues = nouters; + _CONSTRUCT_VECTOR(SQObjectPtr,nc->_noutervalues,nc->_outervalues); + return nc; + } + SQNativeClosure *Clone() + { + SQNativeClosure * ret = SQNativeClosure::Create(_opt_ss(this),_function,_noutervalues); + ret->_env = _env; + if(ret->_env) __ObjAddRef(ret->_env); + ret->_name = _name; + _COPY_VECTOR(ret->_outervalues,_outervalues,_noutervalues); + ret->_typecheck.copy(_typecheck); + ret->_nparamscheck = _nparamscheck; + return ret; + } + ~SQNativeClosure() + { + __ObjRelease(_env); + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); + } + void Release(){ + SQInteger size = _CALC_NATVIVECLOSURE_SIZE(_noutervalues); + _DESTRUCT_VECTOR(SQObjectPtr,_noutervalues,_outervalues); + this->~SQNativeClosure(); + sq_free(this,size); + } + +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + void Finalize() { _NULL_SQOBJECT_VECTOR(_outervalues,_noutervalues); } + SQObjectType GetType() {return OT_NATIVECLOSURE;} +#endif + SQInteger _nparamscheck; + SQIntVec _typecheck; + SQObjectPtr *_outervalues; + SQUnsignedInteger _noutervalues; + SQWeakRef *_env; + SQFUNCTION _function; + SQObjectPtr _name; +}; + + + +#endif //_SQCLOSURE_H_ diff --git a/squirrel_3_0_1_stable/squirrel/sqcompiler.cpp b/squirrel_3_0_1_stable/squirrel/sqcompiler.cpp index e8c1496c9..d2f161642 100644 --- a/squirrel_3_0_1_stable/squirrel/sqcompiler.cpp +++ b/squirrel_3_0_1_stable/squirrel/sqcompiler.cpp @@ -1,1504 +1,1504 @@ -/*
- see copyright notice in squirrel.h
-*/
-#include "sqpcheader.h"
-#ifndef NO_COMPILER
-#include <stdarg.h>
-#include <setjmp.h>
-#include "sqopcodes.h"
-#include "sqstring.h"
-#include "sqfuncproto.h"
-#include "sqcompiler.h"
-#include "sqfuncstate.h"
-#include "sqlexer.h"
-#include "sqvm.h"
-#include "sqtable.h"
-
-#define EXPR 1
-#define OBJECT 2
-#define BASE 3
-#define LOCAL 4
-#define OUTER 5
-
-struct SQExpState {
- SQInteger etype; /* expr. type; one of EXPR, OBJECT, BASE, OUTER or LOCAL */
- SQInteger epos; /* expr. location on stack; -1 for OBJECT and BASE */
- bool donot_get; /* signal not to deref the next value */
-};
-
-struct SQScope {
- SQInteger outers;
- SQInteger stacksize;
-};
-
-#define BEGIN_SCOPE() SQScope __oldscope__ = _scope; \
- _scope.outers = _fs->_outers; \
- _scope.stacksize = _fs->GetStackSize();
-
-#define RESOLVE_OUTERS() if(_fs->GetStackSize() != _scope.stacksize) { \
- if(_fs->CountOuters(_scope.stacksize)) { \
- _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \
- } \
- }
-
-#define END_SCOPE_NO_CLOSE() { if(_fs->GetStackSize() != _scope.stacksize) { \
- _fs->SetStackSize(_scope.stacksize); \
- } \
- _scope = __oldscope__; \
- }
-
-#define END_SCOPE() { SQInteger oldouters = _fs->_outers;\
- if(_fs->GetStackSize() != _scope.stacksize) { \
- _fs->SetStackSize(_scope.stacksize); \
- if(oldouters != _fs->_outers) { \
- _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \
- } \
- } \
- _scope = __oldscope__; \
- }
-
-#define BEGIN_BREAKBLE_BLOCK() SQInteger __nbreaks__=_fs->_unresolvedbreaks.size(); \
- SQInteger __ncontinues__=_fs->_unresolvedcontinues.size(); \
- _fs->_breaktargets.push_back(0);_fs->_continuetargets.push_back(0);
-
-#define END_BREAKBLE_BLOCK(continue_target) {__nbreaks__=_fs->_unresolvedbreaks.size()-__nbreaks__; \
- __ncontinues__=_fs->_unresolvedcontinues.size()-__ncontinues__; \
- if(__ncontinues__>0)ResolveContinues(_fs,__ncontinues__,continue_target); \
- if(__nbreaks__>0)ResolveBreaks(_fs,__nbreaks__); \
- _fs->_breaktargets.pop_back();_fs->_continuetargets.pop_back();}
-
-class SQCompiler
-{
-public:
- SQCompiler(SQVM *v, SQLEXREADFUNC rg, SQUserPointer up, const SQChar* sourcename, bool raiseerror, bool lineinfo)
- {
- _vm=v;
- _lex.Init(_ss(v), rg, up,ThrowError,this);
- _sourcename = SQString::Create(_ss(v), sourcename);
- _lineinfo = lineinfo;_raiseerror = raiseerror;
- _scope.outers = 0;
- _scope.stacksize = 0;
- compilererror = NULL;
- }
- static void ThrowError(void *ud, const SQChar *s) {
- SQCompiler *c = (SQCompiler *)ud;
- c->Error(s);
- }
- void Error(const SQChar *s, ...)
- {
- static SQChar temp[256];
- va_list vl;
- va_start(vl, s);
- scvsprintf(temp, s, vl);
- va_end(vl);
- compilererror = temp;
- longjmp(_errorjmp,1);
- }
- void Lex(){ _token = _lex.Lex();}
- SQObject Expect(SQInteger tok)
- {
-
- if(_token != tok) {
- if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER) {
- //do nothing
- }
- else {
- const SQChar *etypename;
- if(tok > 255) {
- switch(tok)
- {
- case TK_IDENTIFIER:
- etypename = _SC("IDENTIFIER");
- break;
- case TK_STRING_LITERAL:
- etypename = _SC("STRING_LITERAL");
- break;
- case TK_INTEGER:
- etypename = _SC("INTEGER");
- break;
- case TK_FLOAT:
- etypename = _SC("FLOAT");
- break;
- default:
- etypename = _lex.Tok2Str(tok);
- }
- Error(_SC("expected '%s'"), etypename);
- }
- Error(_SC("expected '%c'"), tok);
- }
- }
- SQObjectPtr ret;
- switch(tok)
- {
- case TK_IDENTIFIER:
- ret = _fs->CreateString(_lex._svalue);
- break;
- case TK_STRING_LITERAL:
- ret = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
- break;
- case TK_INTEGER:
- ret = SQObjectPtr(_lex._nvalue);
- break;
- case TK_FLOAT:
- ret = SQObjectPtr(_lex._fvalue);
- break;
- }
- Lex();
- return ret;
- }
- bool IsEndOfStatement() { return ((_lex._prevtoken == _SC('\n')) || (_token == SQUIRREL_EOB) || (_token == _SC('}')) || (_token == _SC(';'))); }
- void OptionalSemicolon()
- {
- if(_token == _SC(';')) { Lex(); return; }
- if(!IsEndOfStatement()) {
- Error(_SC("end of statement expected (; or lf)"));
- }
- }
- void MoveIfCurrentTargetIsLocal() {
- SQInteger trg = _fs->TopTarget();
- if(_fs->IsLocal(trg)) {
- trg = _fs->PopTarget(); //no pops the target and move it
- _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), trg);
- }
- }
- bool Compile(SQObjectPtr &o)
- {
- _debugline = 1;
- _debugop = 0;
-
- SQFuncState funcstate(_ss(_vm), NULL,ThrowError,this);
- funcstate._name = SQString::Create(_ss(_vm), _SC("main"));
- _fs = &funcstate;
- _fs->AddParameter(_fs->CreateString(_SC("this")));
- _fs->AddParameter(_fs->CreateString(_SC("vargv")));
- _fs->_varparams = true;
- _fs->_sourcename = _sourcename;
- SQInteger stacksize = _fs->GetStackSize();
- if(setjmp(_errorjmp) == 0) {
- Lex();
- while(_token > 0){
- Statement();
- if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();
- }
- _fs->SetStackSize(stacksize);
- _fs->AddLineInfos(_lex._currentline, _lineinfo, true);
- _fs->AddInstruction(_OP_RETURN, 0xFF);
- _fs->SetStackSize(0);
- o =_fs->BuildProto();
-#ifdef _DEBUG_DUMP
- _fs->Dump(_funcproto(o));
-#endif
- }
- else {
- if(_raiseerror && _ss(_vm)->_compilererrorhandler) {
- _ss(_vm)->_compilererrorhandler(_vm, compilererror, type(_sourcename) == OT_STRING?_stringval(_sourcename):_SC("unknown"),
- _lex._currentline, _lex._currentcolumn);
- }
- _vm->_lasterror = SQString::Create(_ss(_vm), compilererror, -1);
- return false;
- }
- return true;
- }
- void Statements()
- {
- while(_token != _SC('}') && _token != TK_DEFAULT && _token != TK_CASE) {
- Statement();
- if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();
- }
- }
- void Statement(bool closeframe = true)
- {
- _fs->AddLineInfos(_lex._currentline, _lineinfo);
- switch(_token){
- case _SC(';'): Lex(); break;
- case TK_IF: IfStatement(); break;
- case TK_WHILE: WhileStatement(); break;
- case TK_DO: DoWhileStatement(); break;
- case TK_FOR: ForStatement(); break;
- case TK_FOREACH: ForEachStatement(); break;
- case TK_SWITCH: SwitchStatement(); break;
- case TK_LOCAL: LocalDeclStatement(); break;
- case TK_RETURN:
- case TK_YIELD: {
- SQOpcode op;
- if(_token == TK_RETURN) {
- op = _OP_RETURN;
- }
- else {
- op = _OP_YIELD;
- _fs->_bgenerator = true;
- }
- Lex();
- if(!IsEndOfStatement()) {
- SQInteger retexp = _fs->GetCurrentPos()+1;
- CommaExpr();
- if(op == _OP_RETURN && _fs->_traps > 0)
- _fs->AddInstruction(_OP_POPTRAP, _fs->_traps, 0);
- _fs->_returnexp = retexp;
- _fs->AddInstruction(op, 1, _fs->PopTarget(),_fs->GetStackSize());
- }
- else{
- if(op == _OP_RETURN && _fs->_traps > 0)
- _fs->AddInstruction(_OP_POPTRAP, _fs->_traps ,0);
- _fs->_returnexp = -1;
- _fs->AddInstruction(op, 0xFF,0,_fs->GetStackSize());
- }
- break;}
- case TK_BREAK:
- if(_fs->_breaktargets.size() <= 0)Error(_SC("'break' has to be in a loop block"));
- if(_fs->_breaktargets.top() > 0){
- _fs->AddInstruction(_OP_POPTRAP, _fs->_breaktargets.top(), 0);
- }
- RESOLVE_OUTERS();
- _fs->AddInstruction(_OP_JMP, 0, -1234);
- _fs->_unresolvedbreaks.push_back(_fs->GetCurrentPos());
- Lex();
- break;
- case TK_CONTINUE:
- if(_fs->_continuetargets.size() <= 0)Error(_SC("'continue' has to be in a loop block"));
- if(_fs->_continuetargets.top() > 0) {
- _fs->AddInstruction(_OP_POPTRAP, _fs->_continuetargets.top(), 0);
- }
- RESOLVE_OUTERS();
- _fs->AddInstruction(_OP_JMP, 0, -1234);
- _fs->_unresolvedcontinues.push_back(_fs->GetCurrentPos());
- Lex();
- break;
- case TK_FUNCTION:
- FunctionStatement();
- break;
- case TK_CLASS:
- ClassStatement();
- break;
- case TK_ENUM:
- EnumStatement();
- break;
- case _SC('{'):{
- BEGIN_SCOPE();
- Lex();
- Statements();
- Expect(_SC('}'));
- if(closeframe) {
- END_SCOPE();
- }
- else {
- END_SCOPE_NO_CLOSE();
- }
- }
- break;
- case TK_TRY:
- TryCatchStatement();
- break;
- case TK_THROW:
- Lex();
- CommaExpr();
- _fs->AddInstruction(_OP_THROW, _fs->PopTarget());
- break;
- case TK_CONST:
- {
- Lex();
- SQObject id = Expect(TK_IDENTIFIER);
- Expect('=');
- SQObject val = ExpectScalar();
- OptionalSemicolon();
- SQTable *enums = _table(_ss(_vm)->_consts);
- SQObjectPtr strongid = id;
- enums->NewSlot(strongid,SQObjectPtr(val));
- strongid.Null();
- }
- break;
- default:
- CommaExpr();
- _fs->DiscardTarget();
- //_fs->PopTarget();
- break;
- }
- _fs->SnoozeOpt();
- }
- void EmitDerefOp(SQOpcode op)
- {
- SQInteger val = _fs->PopTarget();
- SQInteger key = _fs->PopTarget();
- SQInteger src = _fs->PopTarget();
- _fs->AddInstruction(op,_fs->PushTarget(),src,key,val);
- }
- void Emit2ArgsOP(SQOpcode op, SQInteger p3 = 0)
- {
- SQInteger p2 = _fs->PopTarget(); //src in OP_GET
- SQInteger p1 = _fs->PopTarget(); //key in OP_GET
- _fs->AddInstruction(op,_fs->PushTarget(), p1, p2, p3);
- }
- void EmitCompoundArith(SQInteger tok, SQInteger etype, SQInteger pos)
- {
- /* Generate code depending on the expression type */
- switch(etype) {
- case LOCAL:{
- SQInteger p2 = _fs->PopTarget(); //src in OP_GET
- SQInteger p1 = _fs->PopTarget(); //key in OP_GET
- _fs->PushTarget(p1);
- //EmitCompArithLocal(tok, p1, p1, p2);
- _fs->AddInstruction(ChooseArithOpByToken(tok),p1, p2, p1, 0);
- }
- break;
- case OBJECT:
- case BASE:
- {
- SQInteger val = _fs->PopTarget();
- SQInteger key = _fs->PopTarget();
- SQInteger src = _fs->PopTarget();
- /* _OP_COMPARITH mixes dest obj and source val in the arg1 */
- _fs->AddInstruction(_OP_COMPARITH, _fs->PushTarget(), (src<<16)|val, key, ChooseCompArithCharByToken(tok));
- }
- break;
- case OUTER:
- {
- SQInteger val = _fs->TopTarget();
- SQInteger tmp = _fs->PushTarget();
- _fs->AddInstruction(_OP_GETOUTER, tmp, pos);
- _fs->AddInstruction(ChooseArithOpByToken(tok), tmp, val, tmp, 0);
- _fs->AddInstruction(_OP_SETOUTER, tmp, pos, tmp);
- }
- break;
- }
- }
- void CommaExpr()
- {
- for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr());
- }
- void Expression()
- {
- SQExpState es = _es;
- _es.etype = EXPR;
- _es.epos = -1;
- _es.donot_get = false;
- LogicalOrExp();
- switch(_token) {
- case _SC('='):
- case TK_NEWSLOT:
- case TK_MINUSEQ:
- case TK_PLUSEQ:
- case TK_MULEQ:
- case TK_DIVEQ:
- case TK_MODEQ:{
- SQInteger op = _token;
- SQInteger ds = _es.etype;
- SQInteger pos = _es.epos;
- if(ds == EXPR) Error(_SC("can't assign expression"));
- Lex(); Expression();
-
- switch(op){
- case TK_NEWSLOT:
- if(ds == OBJECT || ds == BASE)
- EmitDerefOp(_OP_NEWSLOT);
- else //if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local
- Error(_SC("can't 'create' a local slot"));
- break;
- case _SC('='): //ASSIGN
- switch(ds) {
- case LOCAL:
- {
- SQInteger src = _fs->PopTarget();
- SQInteger dst = _fs->TopTarget();
- _fs->AddInstruction(_OP_MOVE, dst, src);
- }
- break;
- case OBJECT:
- case BASE:
- EmitDerefOp(_OP_SET);
- break;
- case OUTER:
- {
- SQInteger src = _fs->PopTarget();
- SQInteger dst = _fs->PushTarget();
- _fs->AddInstruction(_OP_SETOUTER, dst, pos, src);
- }
- }
- break;
- case TK_MINUSEQ:
- case TK_PLUSEQ:
- case TK_MULEQ:
- case TK_DIVEQ:
- case TK_MODEQ:
- EmitCompoundArith(op, ds, pos);
- break;
- }
- }
- break;
- case _SC('?'): {
- Lex();
- _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
- SQInteger jzpos = _fs->GetCurrentPos();
- SQInteger trg = _fs->PushTarget();
- Expression();
- SQInteger first_exp = _fs->PopTarget();
- if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
- SQInteger endfirstexp = _fs->GetCurrentPos();
- _fs->AddInstruction(_OP_JMP, 0, 0);
- Expect(_SC(':'));
- SQInteger jmppos = _fs->GetCurrentPos();
- Expression();
- SQInteger second_exp = _fs->PopTarget();
- if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
- _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
- _fs->SetIntructionParam(jzpos, 1, endfirstexp - jzpos + 1);
- _fs->SnoozeOpt();
- }
- break;
- }
- _es = es;
- }
- template<typename T> void BIN_EXP(SQOpcode op, T f,SQInteger op3 = 0)
- {
- Lex(); (this->*f)();
- SQInteger op1 = _fs->PopTarget();SQInteger op2 = _fs->PopTarget();
- _fs->AddInstruction(op, _fs->PushTarget(), op1, op2, op3);
- }
- void LogicalOrExp()
- {
- LogicalAndExp();
- for(;;) if(_token == TK_OR) {
- SQInteger first_exp = _fs->PopTarget();
- SQInteger trg = _fs->PushTarget();
- _fs->AddInstruction(_OP_OR, trg, 0, first_exp, 0);
- SQInteger jpos = _fs->GetCurrentPos();
- if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
- Lex(); LogicalOrExp();
- _fs->SnoozeOpt();
- SQInteger second_exp = _fs->PopTarget();
- if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
- _fs->SnoozeOpt();
- _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
- break;
- }else return;
- }
- void LogicalAndExp()
- {
- BitwiseOrExp();
- for(;;) switch(_token) {
- case TK_AND: {
- SQInteger first_exp = _fs->PopTarget();
- SQInteger trg = _fs->PushTarget();
- _fs->AddInstruction(_OP_AND, trg, 0, first_exp, 0);
- SQInteger jpos = _fs->GetCurrentPos();
- if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp);
- Lex(); LogicalAndExp();
- _fs->SnoozeOpt();
- SQInteger second_exp = _fs->PopTarget();
- if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp);
- _fs->SnoozeOpt();
- _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos));
- break;
- }
- case TK_IN: BIN_EXP(_OP_EXISTS, &SQCompiler::BitwiseOrExp); break;
- case TK_INSTANCEOF: BIN_EXP(_OP_INSTANCEOF, &SQCompiler::BitwiseOrExp); break;
- default:
- return;
- }
- }
- void BitwiseOrExp()
- {
- BitwiseXorExp();
- for(;;) if(_token == _SC('|'))
- {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseXorExp,BW_OR);
- }else return;
- }
- void BitwiseXorExp()
- {
- BitwiseAndExp();
- for(;;) if(_token == _SC('^'))
- {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseAndExp,BW_XOR);
- }else return;
- }
- void BitwiseAndExp()
- {
- EqExp();
- for(;;) if(_token == _SC('&'))
- {BIN_EXP(_OP_BITW, &SQCompiler::EqExp,BW_AND);
- }else return;
- }
- void EqExp()
- {
- CompExp();
- for(;;) switch(_token) {
- case TK_EQ: BIN_EXP(_OP_EQ, &SQCompiler::CompExp); break;
- case TK_NE: BIN_EXP(_OP_NE, &SQCompiler::CompExp); break;
- case TK_3WAYSCMP: BIN_EXP(_OP_CMP, &SQCompiler::CompExp,CMP_3W); break;
- default: return;
- }
- }
- void CompExp()
- {
- ShiftExp();
- for(;;) switch(_token) {
- case _SC('>'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_G); break;
- case _SC('<'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_L); break;
- case TK_GE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_GE); break;
- case TK_LE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_LE); break;
- default: return;
- }
- }
- void ShiftExp()
- {
- PlusExp();
- for(;;) switch(_token) {
- case TK_USHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_USHIFTR); break;
- case TK_SHIFTL: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTL); break;
- case TK_SHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTR); break;
- default: return;
- }
- }
- SQOpcode ChooseArithOpByToken(SQInteger tok)
- {
- switch(tok) {
- case TK_PLUSEQ: case '+': return _OP_ADD;
- case TK_MINUSEQ: case '-': return _OP_SUB;
- case TK_MULEQ: case '*': return _OP_MUL;
- case TK_DIVEQ: case '/': return _OP_DIV;
- case TK_MODEQ: case '%': return _OP_MOD;
- default: assert(0);
- }
- return _OP_ADD;
- }
- SQInteger ChooseCompArithCharByToken(SQInteger tok)
- {
- SQInteger oper;
- switch(tok){
- case TK_MINUSEQ: oper = '-'; break;
- case TK_PLUSEQ: oper = '+'; break;
- case TK_MULEQ: oper = '*'; break;
- case TK_DIVEQ: oper = '/'; break;
- case TK_MODEQ: oper = '%'; break;
- default: oper = 0; //shut up compiler
- assert(0); break;
- };
- return oper;
- }
- void PlusExp()
- {
- MultExp();
- for(;;) switch(_token) {
- case _SC('+'): case _SC('-'):
- BIN_EXP(ChooseArithOpByToken(_token), &SQCompiler::MultExp); break;
- default: return;
- }
- }
-
- void MultExp()
- {
- PrefixedExpr();
- for(;;) switch(_token) {
- case _SC('*'): case _SC('/'): case _SC('%'):
- BIN_EXP(ChooseArithOpByToken(_token), &SQCompiler::PrefixedExpr); break;
- default: return;
- }
- }
- //if 'pos' != -1 the previous variable is a local variable
- void PrefixedExpr()
- {
- SQInteger pos = Factor();
- for(;;) {
- switch(_token) {
- case _SC('.'):
- pos = -1;
- Lex();
-
- _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));
- if(_es.etype==BASE) {
- Emit2ArgsOP(_OP_GET);
- pos = _fs->TopTarget();
- _es.etype = EXPR;
- _es.epos = pos;
- }
- else {
- if(NeedGet()) {
- Emit2ArgsOP(_OP_GET);
- }
- _es.etype = OBJECT;
- }
- break;
- case _SC('['):
- if(_lex._prevtoken == _SC('\n')) Error(_SC("cannot brake deref/or comma needed after [exp]=exp slot declaration"));
- Lex(); Expression(); Expect(_SC(']'));
- pos = -1;
- if(_es.etype==BASE) {
- Emit2ArgsOP(_OP_GET);
- pos = _fs->TopTarget();
- _es.etype = EXPR;
- _es.epos = pos;
- }
- else {
- if(NeedGet()) {
- Emit2ArgsOP(_OP_GET);
- }
- _es.etype = OBJECT;
- }
- break;
- case TK_MINUSMINUS:
- case TK_PLUSPLUS:
- {
- if(IsEndOfStatement()) return;
- SQInteger diff = (_token==TK_MINUSMINUS) ? -1 : 1;
- Lex();
- switch(_es.etype)
- {
- case EXPR: Error(_SC("can't '++' or '--' an expression")); break;
- case OBJECT:
- case BASE:
- Emit2ArgsOP(_OP_PINC, diff);
- break;
- case LOCAL: {
- SQInteger src = _fs->PopTarget();
- _fs->AddInstruction(_OP_PINCL, _fs->PushTarget(), src, 0, diff);
- }
- break;
- case OUTER: {
- SQInteger tmp1 = _fs->PushTarget();
- SQInteger tmp2 = _fs->PushTarget();
- _fs->AddInstruction(_OP_GETOUTER, tmp2, _es.epos);
- _fs->AddInstruction(_OP_PINCL, tmp1, tmp2, 0, diff);
- _fs->AddInstruction(_OP_SETOUTER, tmp2, _es.epos, tmp2);
- _fs->PopTarget();
- }
- }
- }
- return;
- break;
- case _SC('('):
- switch(_es.etype) {
- case OBJECT: {
- SQInteger key = _fs->PopTarget(); /* location of the key */
- SQInteger table = _fs->PopTarget(); /* location of the object */
- SQInteger closure = _fs->PushTarget(); /* location for the closure */
- SQInteger ttarget = _fs->PushTarget(); /* location for 'this' pointer */
- _fs->AddInstruction(_OP_PREPCALL, closure, key, table, ttarget);
- }
- break;
- case BASE:
- //Emit2ArgsOP(_OP_GET);
- _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
- break;
- case OUTER:
- _fs->AddInstruction(_OP_GETOUTER, _fs->PushTarget(), _es.epos);
- _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
- break;
- default:
- _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0);
- }
- _es.etype = EXPR;
- Lex();
- FunctionCallArgs();
- break;
- default: return;
- }
- }
- }
- SQInteger Factor()
- {
- _es.etype = EXPR;
- switch(_token)
- {
- case TK_STRING_LITERAL:
- _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1)));
- Lex();
- break;
- case TK_BASE:
- Lex();
- _fs->AddInstruction(_OP_GETBASE, _fs->PushTarget());
- _es.etype = BASE;
- _es.epos = _fs->TopTarget();
- return (_es.epos);
- break;
- case TK_IDENTIFIER:
- case TK_CONSTRUCTOR:
- case TK_THIS:{
- SQObject id;
- SQObject constant;
-
- switch(_token) {
- case TK_IDENTIFIER: id = _fs->CreateString(_lex._svalue); break;
- case TK_THIS: id = _fs->CreateString(_SC("this")); break;
- case TK_CONSTRUCTOR: id = _fs->CreateString(_SC("constructor")); break;
- }
-
- SQInteger pos = -1;
- Lex();
- if((pos = _fs->GetLocalVariable(id)) != -1) {
- /* Handle a local variable (includes 'this') */
- _fs->PushTarget(pos);
- _es.etype = LOCAL;
- _es.epos = pos;
- }
-
- else if((pos = _fs->GetOuterVariable(id)) != -1) {
- /* Handle a free var */
- if(NeedGet()) {
- _es.epos = _fs->PushTarget();
- _fs->AddInstruction(_OP_GETOUTER, _es.epos, pos);
- /* _es.etype = EXPR; already default value */
- }
- else {
- _es.etype = OUTER;
- _es.epos = pos;
- }
- }
-
- else if(_fs->IsConstant(id, constant)) {
- /* Handle named constant */
- SQObjectPtr constval;
- SQObject constid;
- if(type(constant) == OT_TABLE) {
- Expect('.');
- constid = Expect(TK_IDENTIFIER);
- if(!_table(constant)->Get(constid, constval)) {
- constval.Null();
- Error(_SC("invalid constant [%s.%s]"), _stringval(id), _stringval(constid));
- }
- }
- else {
- constval = constant;
- }
- _es.epos = _fs->PushTarget();
-
- /* generate direct or literal function depending on size */
- SQObjectType ctype = type(constval);
- switch(ctype) {
- case OT_INTEGER: EmitLoadConstInt(_integer(constval),_es.epos); break;
- case OT_FLOAT: EmitLoadConstFloat(_float(constval),_es.epos); break;
- default: _fs->AddInstruction(_OP_LOAD,_es.epos,_fs->GetConstant(constval)); break;
- }
- _es.etype = EXPR;
- }
- else {
- /* Handle a non-local variable, aka a field. Push the 'this' pointer on
- * the virtual stack (always found in offset 0, so no instruction needs to
- * be generated), and push the key next. Generate an _OP_LOAD instruction
- * for the latter. If we are not using the variable as a dref expr, generate
- * the _OP_GET instruction.
- */
- _fs->PushTarget(0);
- _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
- if(NeedGet()) {
- Emit2ArgsOP(_OP_GET);
- }
- _es.etype = OBJECT;
- }
- return _es.epos;
- }
- break;
- case TK_DOUBLE_COLON: // "::"
- _fs->AddInstruction(_OP_LOADROOT, _fs->PushTarget());
- _es.etype = OBJECT;
- _token = _SC('.'); /* hack: drop into PrefixExpr, case '.'*/
- _es.epos = -1;
- return _es.epos;
- break;
- case TK_NULL:
- _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);
- Lex();
- break;
- case TK_INTEGER: EmitLoadConstInt(_lex._nvalue,-1); Lex(); break;
- case TK_FLOAT: EmitLoadConstFloat(_lex._fvalue,-1); Lex(); break;
- case TK_TRUE: case TK_FALSE:
- _fs->AddInstruction(_OP_LOADBOOL, _fs->PushTarget(),_token == TK_TRUE?1:0);
- Lex();
- break;
- case _SC('['): {
- _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,0,NOT_ARRAY);
- SQInteger apos = _fs->GetCurrentPos(),key = 0;
- Lex();
- while(_token != _SC(']')) {
- Expression();
- if(_token == _SC(',')) Lex();
- SQInteger val = _fs->PopTarget();
- SQInteger array = _fs->TopTarget();
- _fs->AddInstruction(_OP_APPENDARRAY, array, val, AAT_STACK);
- key++;
- }
- _fs->SetIntructionParam(apos, 1, key);
- Lex();
- }
- break;
- case _SC('{'):
- _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE);
- Lex();ParseTableOrClass(_SC(','),_SC('}'));
- break;
- case TK_FUNCTION: FunctionExp(_token);break;
- case _SC('@'): FunctionExp(_token,true);break;
- case TK_CLASS: Lex(); ClassExp();break;
- case _SC('-'):
- Lex();
- switch(_token) {
- case TK_INTEGER: EmitLoadConstInt(-_lex._nvalue,-1); Lex(); break;
- case TK_FLOAT: EmitLoadConstFloat(-_lex._fvalue,-1); Lex(); break;
- default: UnaryOP(_OP_NEG);
- }
- break;
- case _SC('!'): Lex(); UnaryOP(_OP_NOT); break;
- case _SC('~'):
- Lex();
- if(_token == TK_INTEGER) { EmitLoadConstInt(~_lex._nvalue,-1); Lex(); break; }
- UnaryOP(_OP_BWNOT);
- break;
- case TK_TYPEOF : Lex() ;UnaryOP(_OP_TYPEOF); break;
- case TK_RESUME : Lex(); UnaryOP(_OP_RESUME); break;
- case TK_CLONE : Lex(); UnaryOP(_OP_CLONE); break;
- case TK_MINUSMINUS :
- case TK_PLUSPLUS :PrefixIncDec(_token); break;
- case TK_DELETE : DeleteExpr(); break;
- case _SC('('): Lex(); CommaExpr(); Expect(_SC(')'));
- break;
- default: Error(_SC("expression expected"));
- }
- return -1;
- }
- void EmitLoadConstInt(SQInteger value,SQInteger target)
- {
- if(target < 0) {
- target = _fs->PushTarget();
- }
- if((value & (~((SQInteger)0xFFFFFFFF))) == 0) { //does it fit in 32 bits?
- _fs->AddInstruction(_OP_LOADINT, target,value);
- }
- else {
- _fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value));
- }
- }
- void EmitLoadConstFloat(SQFloat value,SQInteger target)
- {
- if(target < 0) {
- target = _fs->PushTarget();
- }
- if(sizeof(SQFloat) == sizeof(SQInt32)) {
- _fs->AddInstruction(_OP_LOADFLOAT, target,*((SQInt32 *)&value));
- }
- else {
- _fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value));
- }
- }
- void UnaryOP(SQOpcode op)
- {
- PrefixedExpr();
- SQInteger src = _fs->PopTarget();
- _fs->AddInstruction(op, _fs->PushTarget(), src);
- }
- bool NeedGet()
- {
- switch(_token) {
- case _SC('='): case _SC('('): case TK_NEWSLOT: case TK_MODEQ: case TK_MULEQ:
- case TK_DIVEQ: case TK_MINUSEQ: case TK_PLUSEQ: case TK_PLUSPLUS: case TK_MINUSMINUS:
- return false;
- }
- return (!_es.donot_get || ( _es.donot_get && (_token == _SC('.') || _token == _SC('['))));
- }
- void FunctionCallArgs()
- {
- SQInteger nargs = 1;//this
- while(_token != _SC(')')) {
- Expression();
- MoveIfCurrentTargetIsLocal();
- nargs++;
- if(_token == _SC(',')){
- Lex();
- if(_token == ')') Error(_SC("expression expected, found ')'"));
- }
- }
- Lex();
- for(SQInteger i = 0; i < (nargs - 1); i++) _fs->PopTarget();
- SQInteger stackbase = _fs->PopTarget();
- SQInteger closure = _fs->PopTarget();
- _fs->AddInstruction(_OP_CALL, _fs->PushTarget(), closure, stackbase, nargs);
- }
- void ParseTableOrClass(SQInteger separator,SQInteger terminator)
- {
- SQInteger tpos = _fs->GetCurrentPos(),nkeys = 0;
- while(_token != terminator) {
- bool hasattrs = false;
- bool isstatic = false;
- //check if is an attribute
- if(separator == ';') {
- if(_token == TK_ATTR_OPEN) {
- _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE); Lex();
- ParseTableOrClass(',',TK_ATTR_CLOSE);
- hasattrs = true;
- }
- if(_token == TK_STATIC) {
- isstatic = true;
- Lex();
- }
- }
- switch(_token) {
- case TK_FUNCTION:
- case TK_CONSTRUCTOR:{
- SQInteger tk = _token;
- Lex();
- SQObject id = tk == TK_FUNCTION ? Expect(TK_IDENTIFIER) : _fs->CreateString(_SC("constructor"));
- Expect(_SC('('));
- _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
- CreateFunction(id);
- _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
- }
- break;
- case _SC('['):
- Lex(); CommaExpr(); Expect(_SC(']'));
- Expect(_SC('=')); Expression();
- break;
- case TK_STRING_LITERAL: //JSON
- if(separator == ',') { //only works for tables
- _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_STRING_LITERAL)));
- Expect(_SC(':')); Expression();
- break;
- }
- default :
- _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER)));
- Expect(_SC('=')); Expression();
- }
- if(_token == separator) Lex();//optional comma/semicolon
- nkeys++;
- SQInteger val = _fs->PopTarget();
- SQInteger key = _fs->PopTarget();
- SQInteger attrs = hasattrs ? _fs->PopTarget():-1;
- assert((hasattrs && (attrs == key-1)) || !hasattrs);
- unsigned char flags = (hasattrs?NEW_SLOT_ATTRIBUTES_FLAG:0)|(isstatic?NEW_SLOT_STATIC_FLAG:0);
- SQInteger table = _fs->TopTarget(); //<<BECAUSE OF THIS NO COMMON EMIT FUNC IS POSSIBLE
- if(separator == _SC(',')) { //hack recognizes a table from the separator
- _fs->AddInstruction(_OP_NEWSLOT, 0xFF, table, key, val);
- }
- else {
- _fs->AddInstruction(_OP_NEWSLOTA, flags, table, key, val); //this for classes only as it invokes _newmember
- }
- }
- if(separator == _SC(',')) //hack recognizes a table from the separator
- _fs->SetIntructionParam(tpos, 1, nkeys);
- Lex();
- }
- void LocalDeclStatement()
- {
- SQObject varname;
- Lex();
- if( _token == TK_FUNCTION) {
- Lex();
- varname = Expect(TK_IDENTIFIER);
- Expect(_SC('('));
- CreateFunction(varname,false);
- _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
- _fs->PopTarget();
- _fs->PushLocalVariable(varname);
- return;
- }
-
- do {
- varname = Expect(TK_IDENTIFIER);
- if(_token == _SC('=')) {
- Lex(); Expression();
- SQInteger src = _fs->PopTarget();
- SQInteger dest = _fs->PushTarget();
- if(dest != src) _fs->AddInstruction(_OP_MOVE, dest, src);
- }
- else{
- _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1);
- }
- _fs->PopTarget();
- _fs->PushLocalVariable(varname);
- if(_token == _SC(',')) Lex(); else break;
- } while(1);
- }
- void IfStatement()
- {
- SQInteger jmppos;
- bool haselse = false;
- Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
- _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
- SQInteger jnepos = _fs->GetCurrentPos();
- BEGIN_SCOPE();
-
- Statement();
- //
- if(_token != _SC('}') && _token != TK_ELSE) OptionalSemicolon();
-
- END_SCOPE();
- SQInteger endifblock = _fs->GetCurrentPos();
- if(_token == TK_ELSE){
- haselse = true;
- BEGIN_SCOPE();
- _fs->AddInstruction(_OP_JMP);
- jmppos = _fs->GetCurrentPos();
- Lex();
- Statement(); OptionalSemicolon();
- END_SCOPE();
- _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
- }
- _fs->SetIntructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0));
- }
- void WhileStatement()
- {
- SQInteger jzpos, jmppos;
- jmppos = _fs->GetCurrentPos();
- Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
-
- BEGIN_BREAKBLE_BLOCK();
- _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
- jzpos = _fs->GetCurrentPos();
- BEGIN_SCOPE();
-
- Statement();
-
- END_SCOPE();
- _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);
- _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
-
- END_BREAKBLE_BLOCK(jmppos);
- }
- void DoWhileStatement()
- {
- Lex();
- SQInteger jmptrg = _fs->GetCurrentPos();
- BEGIN_BREAKBLE_BLOCK()
- BEGIN_SCOPE();
- Statement();
- END_SCOPE();
- Expect(TK_WHILE);
- SQInteger continuetrg = _fs->GetCurrentPos();
- Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
- _fs->AddInstruction(_OP_JZ, _fs->PopTarget(), 1);
- _fs->AddInstruction(_OP_JMP, 0, jmptrg - _fs->GetCurrentPos() - 1);
- END_BREAKBLE_BLOCK(continuetrg);
- }
- void ForStatement()
- {
- Lex();
- BEGIN_SCOPE();
- Expect(_SC('('));
- if(_token == TK_LOCAL) LocalDeclStatement();
- else if(_token != _SC(';')){
- CommaExpr();
- _fs->PopTarget();
- }
- Expect(_SC(';'));
- _fs->SnoozeOpt();
- SQInteger jmppos = _fs->GetCurrentPos();
- SQInteger jzpos = -1;
- if(_token != _SC(';')) { CommaExpr(); _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); jzpos = _fs->GetCurrentPos(); }
- Expect(_SC(';'));
- _fs->SnoozeOpt();
- SQInteger expstart = _fs->GetCurrentPos() + 1;
- if(_token != _SC(')')) {
- CommaExpr();
- _fs->PopTarget();
- }
- Expect(_SC(')'));
- _fs->SnoozeOpt();
- SQInteger expend = _fs->GetCurrentPos();
- SQInteger expsize = (expend - expstart) + 1;
- SQInstructionVec exp;
- if(expsize > 0) {
- for(SQInteger i = 0; i < expsize; i++)
- exp.push_back(_fs->GetInstruction(expstart + i));
- _fs->PopInstructions(expsize);
- }
- BEGIN_BREAKBLE_BLOCK()
- Statement();
- SQInteger continuetrg = _fs->GetCurrentPos();
- if(expsize > 0) {
- for(SQInteger i = 0; i < expsize; i++)
- _fs->AddInstruction(exp[i]);
- }
- _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1, 0);
- if(jzpos> 0) _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos);
- END_SCOPE();
-
- END_BREAKBLE_BLOCK(continuetrg);
- }
- void ForEachStatement()
- {
- SQObject idxname, valname;
- Lex(); Expect(_SC('(')); valname = Expect(TK_IDENTIFIER);
- if(_token == _SC(',')) {
- idxname = valname;
- Lex(); valname = Expect(TK_IDENTIFIER);
- }
- else{
- idxname = _fs->CreateString(_SC("@INDEX@"));
- }
- Expect(TK_IN);
-
- //save the stack size
- BEGIN_SCOPE();
- //put the table in the stack(evaluate the table expression)
- Expression(); Expect(_SC(')'));
- SQInteger container = _fs->TopTarget();
- //push the index local var
- SQInteger indexpos = _fs->PushLocalVariable(idxname);
- _fs->AddInstruction(_OP_LOADNULLS, indexpos,1);
- //push the value local var
- SQInteger valuepos = _fs->PushLocalVariable(valname);
- _fs->AddInstruction(_OP_LOADNULLS, valuepos,1);
- //push reference index
- SQInteger itrpos = _fs->PushLocalVariable(_fs->CreateString(_SC("@ITERATOR@"))); //use invalid id to make it inaccessible
- _fs->AddInstruction(_OP_LOADNULLS, itrpos,1);
- SQInteger jmppos = _fs->GetCurrentPos();
- _fs->AddInstruction(_OP_FOREACH, container, 0, indexpos);
- SQInteger foreachpos = _fs->GetCurrentPos();
- _fs->AddInstruction(_OP_POSTFOREACH, container, 0, indexpos);
- //generate the statement code
- BEGIN_BREAKBLE_BLOCK()
- Statement();
- _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1);
- _fs->SetIntructionParam(foreachpos, 1, _fs->GetCurrentPos() - foreachpos);
- _fs->SetIntructionParam(foreachpos + 1, 1, _fs->GetCurrentPos() - foreachpos);
- END_BREAKBLE_BLOCK(foreachpos - 1);
- //restore the local variable stack(remove index,val and ref idx)
- END_SCOPE();
- }
- void SwitchStatement()
- {
- Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
- Expect(_SC('{'));
- SQInteger expr = _fs->TopTarget();
- bool bfirst = true;
- SQInteger tonextcondjmp = -1;
- SQInteger skipcondjmp = -1;
- SQInteger __nbreaks__ = _fs->_unresolvedbreaks.size();
- _fs->_breaktargets.push_back(0);
- while(_token == TK_CASE) {
- if(!bfirst) {
- _fs->AddInstruction(_OP_JMP, 0, 0);
- skipcondjmp = _fs->GetCurrentPos();
- _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
- }
- //condition
- Lex(); Expression(); Expect(_SC(':'));
- SQInteger trg = _fs->PopTarget();
- _fs->AddInstruction(_OP_EQ, trg, trg, expr);
- _fs->AddInstruction(_OP_JZ, trg, 0);
- //end condition
- if(skipcondjmp != -1) {
- _fs->SetIntructionParam(skipcondjmp, 1, (_fs->GetCurrentPos() - skipcondjmp));
- }
- tonextcondjmp = _fs->GetCurrentPos();
- BEGIN_SCOPE();
- Statements();
- END_SCOPE();
- bfirst = false;
- }
- if(tonextcondjmp != -1)
- _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp);
- if(_token == TK_DEFAULT) {
- Lex(); Expect(_SC(':'));
- BEGIN_SCOPE();
- Statements();
- END_SCOPE();
- }
- Expect(_SC('}'));
- _fs->PopTarget();
- __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__;
- if(__nbreaks__ > 0)ResolveBreaks(_fs, __nbreaks__);
- _fs->_breaktargets.pop_back();
- }
- void FunctionStatement()
- {
- SQObject id;
- Lex(); id = Expect(TK_IDENTIFIER);
- _fs->PushTarget(0);
- _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
- if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
-
- while(_token == TK_DOUBLE_COLON) {
- Lex();
- id = Expect(TK_IDENTIFIER);
- _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id));
- if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET);
- }
- Expect(_SC('('));
- CreateFunction(id);
- _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0);
- EmitDerefOp(_OP_NEWSLOT);
- _fs->PopTarget();
- }
- void ClassStatement()
- {
- SQExpState es;
- Lex();
- es = _es;
- _es.donot_get = true;
- PrefixedExpr();
- if(_es.etype == EXPR) {
- Error(_SC("invalid class name"));
- }
- else if(_es.etype == OBJECT || _es.etype == BASE) {
- ClassExp();
- EmitDerefOp(_OP_NEWSLOT);
- _fs->PopTarget();
- }
- else {
- Error(_SC("cannot create a class in a local with the syntax(class <local>)"));
- }
- _es = es;
- }
- SQObject ExpectScalar()
- {
- SQObject val;
- val._type = OT_NULL; val._unVal.nInteger = 0; //shut up GCC 4.x
- switch(_token) {
- case TK_INTEGER:
- val._type = OT_INTEGER;
- val._unVal.nInteger = _lex._nvalue;
- break;
- case TK_FLOAT:
- val._type = OT_FLOAT;
- val._unVal.fFloat = _lex._fvalue;
- break;
- case TK_STRING_LITERAL:
- val = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1);
- break;
- case '-':
- Lex();
- switch(_token)
- {
- case TK_INTEGER:
- val._type = OT_INTEGER;
- val._unVal.nInteger = -_lex._nvalue;
- break;
- case TK_FLOAT:
- val._type = OT_FLOAT;
- val._unVal.fFloat = -_lex._fvalue;
- break;
- default:
- Error(_SC("scalar expected : integer,float"));
- }
- break;
- default:
- Error(_SC("scalar expected : integer,float or string"));
- }
- Lex();
- return val;
- }
- void EnumStatement()
- {
- Lex();
- SQObject id = Expect(TK_IDENTIFIER);
- Expect(_SC('{'));
-
- SQObject table = _fs->CreateTable();
- SQInteger nval = 0;
- while(_token != _SC('}')) {
- SQObject key = Expect(TK_IDENTIFIER);
- SQObject val;
- if(_token == _SC('=')) {
- Lex();
- val = ExpectScalar();
- }
- else {
- val._type = OT_INTEGER;
- val._unVal.nInteger = nval++;
- }
- _table(table)->NewSlot(SQObjectPtr(key),SQObjectPtr(val));
- if(_token == ',') Lex();
- }
- SQTable *enums = _table(_ss(_vm)->_consts);
- SQObjectPtr strongid = id;
- enums->NewSlot(SQObjectPtr(strongid),SQObjectPtr(table));
- strongid.Null();
- Lex();
- }
- void TryCatchStatement()
- {
- SQObject exid;
- Lex();
- _fs->AddInstruction(_OP_PUSHTRAP,0,0);
- _fs->_traps++;
- if(_fs->_breaktargets.size()) _fs->_breaktargets.top()++;
- if(_fs->_continuetargets.size()) _fs->_continuetargets.top()++;
- SQInteger trappos = _fs->GetCurrentPos();
- {
- BEGIN_SCOPE();
- Statement();
- END_SCOPE();
- }
- _fs->_traps--;
- _fs->AddInstruction(_OP_POPTRAP, 1, 0);
- if(_fs->_breaktargets.size()) _fs->_breaktargets.top()--;
- if(_fs->_continuetargets.size()) _fs->_continuetargets.top()--;
- _fs->AddInstruction(_OP_JMP, 0, 0);
- SQInteger jmppos = _fs->GetCurrentPos();
- _fs->SetIntructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos));
- Expect(TK_CATCH); Expect(_SC('(')); exid = Expect(TK_IDENTIFIER); Expect(_SC(')'));
- {
- BEGIN_SCOPE();
- SQInteger ex_target = _fs->PushLocalVariable(exid);
- _fs->SetIntructionParam(trappos, 0, ex_target);
- Statement();
- _fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0);
- END_SCOPE();
- }
- }
- void FunctionExp(SQInteger ftype,bool lambda = false)
- {
- Lex(); Expect(_SC('('));
- SQObjectPtr dummy;
- CreateFunction(dummy,lambda);
- _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, ftype == TK_FUNCTION?0:1);
- }
- void ClassExp()
- {
- SQInteger base = -1;
- SQInteger attrs = -1;
- if(_token == TK_EXTENDS) {
- Lex(); Expression();
- base = _fs->TopTarget();
- }
- if(_token == TK_ATTR_OPEN) {
- Lex();
- _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE);
- ParseTableOrClass(_SC(','),TK_ATTR_CLOSE);
- attrs = _fs->TopTarget();
- }
- Expect(_SC('{'));
- if(attrs != -1) _fs->PopTarget();
- if(base != -1) _fs->PopTarget();
- _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(), base, attrs,NOT_CLASS);
- ParseTableOrClass(_SC(';'),_SC('}'));
- }
- void DeleteExpr()
- {
- SQExpState es;
- Lex();
- es = _es;
- _es.donot_get = true;
- PrefixedExpr();
- if(_es.etype==EXPR) Error(_SC("can't delete an expression"));
- if(_es.etype==OBJECT || _es.etype==BASE) {
- Emit2ArgsOP(_OP_DELETE);
- }
- else {
- Error(_SC("cannot delete an (outer) local"));
- }
- _es = es;
- }
- void PrefixIncDec(SQInteger token)
- {
- SQExpState es;
- SQInteger diff = (token==TK_MINUSMINUS) ? -1 : 1;
- Lex();
- es = _es;
- _es.donot_get = true;
- PrefixedExpr();
- if(_es.etype==EXPR) {
- Error(_SC("can't '++' or '--' an expression"));
- }
- else if(_es.etype==OBJECT || _es.etype==BASE) {
- Emit2ArgsOP(_OP_INC, diff);
- }
- else if(_es.etype==LOCAL) {
- SQInteger src = _fs->TopTarget();
- _fs->AddInstruction(_OP_INCL, src, src, 0, diff);
-
- }
- else if(_es.etype==OUTER) {
- SQInteger tmp = _fs->PushTarget();
- _fs->AddInstruction(_OP_GETOUTER, tmp, _es.epos);
- _fs->AddInstruction(_OP_INCL, tmp, tmp, 0, diff);
- _fs->AddInstruction(_OP_SETOUTER, tmp, _es.epos, tmp);
- }
- _es = es;
- }
- void CreateFunction(SQObject &name,bool lambda = false)
- {
- SQFuncState *funcstate = _fs->PushChildState(_ss(_vm));
- funcstate->_name = name;
- SQObject paramname;
- funcstate->AddParameter(_fs->CreateString(_SC("this")));
- funcstate->_sourcename = _sourcename;
- SQInteger defparams = 0;
- while(_token!=_SC(')')) {
- if(_token == TK_VARPARAMS) {
- if(defparams > 0) Error(_SC("function with default parameters cannot have variable number of parameters"));
- funcstate->AddParameter(_fs->CreateString(_SC("vargv")));
- funcstate->_varparams = true;
- Lex();
- if(_token != _SC(')')) Error(_SC("expected ')'"));
- break;
- }
- else {
- paramname = Expect(TK_IDENTIFIER);
- funcstate->AddParameter(paramname);
- if(_token == _SC('=')) {
- Lex();
- Expression();
- funcstate->AddDefaultParam(_fs->TopTarget());
- defparams++;
- }
- else {
- if(defparams > 0) Error(_SC("expected '='"));
- }
- if(_token == _SC(',')) Lex();
- else if(_token != _SC(')')) Error(_SC("expected ')' or ','"));
- }
- }
- Expect(_SC(')'));
- for(SQInteger n = 0; n < defparams; n++) {
- _fs->PopTarget();
- }
-
- SQFuncState *currchunk = _fs;
- _fs = funcstate;
- if(lambda) {
- Expression();
- _fs->AddInstruction(_OP_RETURN, 1, _fs->PopTarget());}
- else {
- Statement(false);
- }
- funcstate->AddLineInfos(_lex._prevtoken == _SC('\n')?_lex._lasttokenline:_lex._currentline, _lineinfo, true);
- funcstate->AddInstruction(_OP_RETURN, -1);
- funcstate->SetStackSize(0);
-
- SQFunctionProto *func = funcstate->BuildProto();
-#ifdef _DEBUG_DUMP
- funcstate->Dump(func);
-#endif
- _fs = currchunk;
- _fs->_functions.push_back(func);
- _fs->PopChildState();
- }
- void ResolveBreaks(SQFuncState *funcstate, SQInteger ntoresolve)
- {
- while(ntoresolve > 0) {
- SQInteger pos = funcstate->_unresolvedbreaks.back();
- funcstate->_unresolvedbreaks.pop_back();
- //set the jmp instruction
- funcstate->SetIntructionParams(pos, 0, funcstate->GetCurrentPos() - pos, 0);
- ntoresolve--;
- }
- }
- void ResolveContinues(SQFuncState *funcstate, SQInteger ntoresolve, SQInteger targetpos)
- {
- while(ntoresolve > 0) {
- SQInteger pos = funcstate->_unresolvedcontinues.back();
- funcstate->_unresolvedcontinues.pop_back();
- //set the jmp instruction
- funcstate->SetIntructionParams(pos, 0, targetpos - pos, 0);
- ntoresolve--;
- }
- }
-private:
- SQInteger _token;
- SQFuncState *_fs;
- SQObjectPtr _sourcename;
- SQLexer _lex;
- bool _lineinfo;
- bool _raiseerror;
- SQInteger _debugline;
- SQInteger _debugop;
- SQExpState _es;
- SQScope _scope;
- SQChar *compilererror;
- jmp_buf _errorjmp;
- SQVM *_vm;
-};
-
-bool Compile(SQVM *vm,SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo)
-{
- SQCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo);
- return p.Compile(out);
-}
-
-#endif
+/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#ifndef NO_COMPILER +#include <stdarg.h> +#include <setjmp.h> +#include "sqopcodes.h" +#include "sqstring.h" +#include "sqfuncproto.h" +#include "sqcompiler.h" +#include "sqfuncstate.h" +#include "sqlexer.h" +#include "sqvm.h" +#include "sqtable.h" + +#define EXPR 1 +#define OBJECT 2 +#define BASE 3 +#define LOCAL 4 +#define OUTER 5 + +struct SQExpState { + SQInteger etype; /* expr. type; one of EXPR, OBJECT, BASE, OUTER or LOCAL */ + SQInteger epos; /* expr. location on stack; -1 for OBJECT and BASE */ + bool donot_get; /* signal not to deref the next value */ +}; + +struct SQScope { + SQInteger outers; + SQInteger stacksize; +}; + +#define BEGIN_SCOPE() SQScope __oldscope__ = _scope; \ + _scope.outers = _fs->_outers; \ + _scope.stacksize = _fs->GetStackSize(); + +#define RESOLVE_OUTERS() if(_fs->GetStackSize() != _scope.stacksize) { \ + if(_fs->CountOuters(_scope.stacksize)) { \ + _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \ + } \ + } + +#define END_SCOPE_NO_CLOSE() { if(_fs->GetStackSize() != _scope.stacksize) { \ + _fs->SetStackSize(_scope.stacksize); \ + } \ + _scope = __oldscope__; \ + } + +#define END_SCOPE() { SQInteger oldouters = _fs->_outers;\ + if(_fs->GetStackSize() != _scope.stacksize) { \ + _fs->SetStackSize(_scope.stacksize); \ + if(oldouters != _fs->_outers) { \ + _fs->AddInstruction(_OP_CLOSE,0,_scope.stacksize); \ + } \ + } \ + _scope = __oldscope__; \ + } + +#define BEGIN_BREAKBLE_BLOCK() SQInteger __nbreaks__=_fs->_unresolvedbreaks.size(); \ + SQInteger __ncontinues__=_fs->_unresolvedcontinues.size(); \ + _fs->_breaktargets.push_back(0);_fs->_continuetargets.push_back(0); + +#define END_BREAKBLE_BLOCK(continue_target) {__nbreaks__=_fs->_unresolvedbreaks.size()-__nbreaks__; \ + __ncontinues__=_fs->_unresolvedcontinues.size()-__ncontinues__; \ + if(__ncontinues__>0)ResolveContinues(_fs,__ncontinues__,continue_target); \ + if(__nbreaks__>0)ResolveBreaks(_fs,__nbreaks__); \ + _fs->_breaktargets.pop_back();_fs->_continuetargets.pop_back();} + +class SQCompiler +{ +public: + SQCompiler(SQVM *v, SQLEXREADFUNC rg, SQUserPointer up, const SQChar* sourcename, bool raiseerror, bool lineinfo) + { + _vm=v; + _lex.Init(_ss(v), rg, up,ThrowError,this); + _sourcename = SQString::Create(_ss(v), sourcename); + _lineinfo = lineinfo;_raiseerror = raiseerror; + _scope.outers = 0; + _scope.stacksize = 0; + compilererror = NULL; + } + static void ThrowError(void *ud, const SQChar *s) { + SQCompiler *c = (SQCompiler *)ud; + c->Error(s); + } + void Error(const SQChar *s, ...) + { + static SQChar temp[256]; + va_list vl; + va_start(vl, s); + scvsprintf(temp, s, vl); + va_end(vl); + compilererror = temp; + longjmp(_errorjmp,1); + } + void Lex(){ _token = _lex.Lex();} + SQObject Expect(SQInteger tok) + { + + if(_token != tok) { + if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER) { + //do nothing + } + else { + const SQChar *etypename; + if(tok > 255) { + switch(tok) + { + case TK_IDENTIFIER: + etypename = _SC("IDENTIFIER"); + break; + case TK_STRING_LITERAL: + etypename = _SC("STRING_LITERAL"); + break; + case TK_INTEGER: + etypename = _SC("INTEGER"); + break; + case TK_FLOAT: + etypename = _SC("FLOAT"); + break; + default: + etypename = _lex.Tok2Str(tok); + } + Error(_SC("expected '%s'"), etypename); + } + Error(_SC("expected '%c'"), tok); + } + } + SQObjectPtr ret; + switch(tok) + { + case TK_IDENTIFIER: + ret = _fs->CreateString(_lex._svalue); + break; + case TK_STRING_LITERAL: + ret = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1); + break; + case TK_INTEGER: + ret = SQObjectPtr(_lex._nvalue); + break; + case TK_FLOAT: + ret = SQObjectPtr(_lex._fvalue); + break; + } + Lex(); + return ret; + } + bool IsEndOfStatement() { return ((_lex._prevtoken == _SC('\n')) || (_token == SQUIRREL_EOB) || (_token == _SC('}')) || (_token == _SC(';'))); } + void OptionalSemicolon() + { + if(_token == _SC(';')) { Lex(); return; } + if(!IsEndOfStatement()) { + Error(_SC("end of statement expected (; or lf)")); + } + } + void MoveIfCurrentTargetIsLocal() { + SQInteger trg = _fs->TopTarget(); + if(_fs->IsLocal(trg)) { + trg = _fs->PopTarget(); //no pops the target and move it + _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), trg); + } + } + bool Compile(SQObjectPtr &o) + { + _debugline = 1; + _debugop = 0; + + SQFuncState funcstate(_ss(_vm), NULL,ThrowError,this); + funcstate._name = SQString::Create(_ss(_vm), _SC("main")); + _fs = &funcstate; + _fs->AddParameter(_fs->CreateString(_SC("this"))); + _fs->AddParameter(_fs->CreateString(_SC("vargv"))); + _fs->_varparams = true; + _fs->_sourcename = _sourcename; + SQInteger stacksize = _fs->GetStackSize(); + if(setjmp(_errorjmp) == 0) { + Lex(); + while(_token > 0){ + Statement(); + if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon(); + } + _fs->SetStackSize(stacksize); + _fs->AddLineInfos(_lex._currentline, _lineinfo, true); + _fs->AddInstruction(_OP_RETURN, 0xFF); + _fs->SetStackSize(0); + o =_fs->BuildProto(); +#ifdef _DEBUG_DUMP + _fs->Dump(_funcproto(o)); +#endif + } + else { + if(_raiseerror && _ss(_vm)->_compilererrorhandler) { + _ss(_vm)->_compilererrorhandler(_vm, compilererror, type(_sourcename) == OT_STRING?_stringval(_sourcename):_SC("unknown"), + _lex._currentline, _lex._currentcolumn); + } + _vm->_lasterror = SQString::Create(_ss(_vm), compilererror, -1); + return false; + } + return true; + } + void Statements() + { + while(_token != _SC('}') && _token != TK_DEFAULT && _token != TK_CASE) { + Statement(); + if(_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon(); + } + } + void Statement(bool closeframe = true) + { + _fs->AddLineInfos(_lex._currentline, _lineinfo); + switch(_token){ + case _SC(';'): Lex(); break; + case TK_IF: IfStatement(); break; + case TK_WHILE: WhileStatement(); break; + case TK_DO: DoWhileStatement(); break; + case TK_FOR: ForStatement(); break; + case TK_FOREACH: ForEachStatement(); break; + case TK_SWITCH: SwitchStatement(); break; + case TK_LOCAL: LocalDeclStatement(); break; + case TK_RETURN: + case TK_YIELD: { + SQOpcode op; + if(_token == TK_RETURN) { + op = _OP_RETURN; + } + else { + op = _OP_YIELD; + _fs->_bgenerator = true; + } + Lex(); + if(!IsEndOfStatement()) { + SQInteger retexp = _fs->GetCurrentPos()+1; + CommaExpr(); + if(op == _OP_RETURN && _fs->_traps > 0) + _fs->AddInstruction(_OP_POPTRAP, _fs->_traps, 0); + _fs->_returnexp = retexp; + _fs->AddInstruction(op, 1, _fs->PopTarget(),_fs->GetStackSize()); + } + else{ + if(op == _OP_RETURN && _fs->_traps > 0) + _fs->AddInstruction(_OP_POPTRAP, _fs->_traps ,0); + _fs->_returnexp = -1; + _fs->AddInstruction(op, 0xFF,0,_fs->GetStackSize()); + } + break;} + case TK_BREAK: + if(_fs->_breaktargets.size() <= 0)Error(_SC("'break' has to be in a loop block")); + if(_fs->_breaktargets.top() > 0){ + _fs->AddInstruction(_OP_POPTRAP, _fs->_breaktargets.top(), 0); + } + RESOLVE_OUTERS(); + _fs->AddInstruction(_OP_JMP, 0, -1234); + _fs->_unresolvedbreaks.push_back(_fs->GetCurrentPos()); + Lex(); + break; + case TK_CONTINUE: + if(_fs->_continuetargets.size() <= 0)Error(_SC("'continue' has to be in a loop block")); + if(_fs->_continuetargets.top() > 0) { + _fs->AddInstruction(_OP_POPTRAP, _fs->_continuetargets.top(), 0); + } + RESOLVE_OUTERS(); + _fs->AddInstruction(_OP_JMP, 0, -1234); + _fs->_unresolvedcontinues.push_back(_fs->GetCurrentPos()); + Lex(); + break; + case TK_FUNCTION: + FunctionStatement(); + break; + case TK_CLASS: + ClassStatement(); + break; + case TK_ENUM: + EnumStatement(); + break; + case _SC('{'):{ + BEGIN_SCOPE(); + Lex(); + Statements(); + Expect(_SC('}')); + if(closeframe) { + END_SCOPE(); + } + else { + END_SCOPE_NO_CLOSE(); + } + } + break; + case TK_TRY: + TryCatchStatement(); + break; + case TK_THROW: + Lex(); + CommaExpr(); + _fs->AddInstruction(_OP_THROW, _fs->PopTarget()); + break; + case TK_CONST: + { + Lex(); + SQObject id = Expect(TK_IDENTIFIER); + Expect('='); + SQObject val = ExpectScalar(); + OptionalSemicolon(); + SQTable *enums = _table(_ss(_vm)->_consts); + SQObjectPtr strongid = id; + enums->NewSlot(strongid,SQObjectPtr(val)); + strongid.Null(); + } + break; + default: + CommaExpr(); + _fs->DiscardTarget(); + //_fs->PopTarget(); + break; + } + _fs->SnoozeOpt(); + } + void EmitDerefOp(SQOpcode op) + { + SQInteger val = _fs->PopTarget(); + SQInteger key = _fs->PopTarget(); + SQInteger src = _fs->PopTarget(); + _fs->AddInstruction(op,_fs->PushTarget(),src,key,val); + } + void Emit2ArgsOP(SQOpcode op, SQInteger p3 = 0) + { + SQInteger p2 = _fs->PopTarget(); //src in OP_GET + SQInteger p1 = _fs->PopTarget(); //key in OP_GET + _fs->AddInstruction(op,_fs->PushTarget(), p1, p2, p3); + } + void EmitCompoundArith(SQInteger tok, SQInteger etype, SQInteger pos) + { + /* Generate code depending on the expression type */ + switch(etype) { + case LOCAL:{ + SQInteger p2 = _fs->PopTarget(); //src in OP_GET + SQInteger p1 = _fs->PopTarget(); //key in OP_GET + _fs->PushTarget(p1); + //EmitCompArithLocal(tok, p1, p1, p2); + _fs->AddInstruction(ChooseArithOpByToken(tok),p1, p2, p1, 0); + } + break; + case OBJECT: + case BASE: + { + SQInteger val = _fs->PopTarget(); + SQInteger key = _fs->PopTarget(); + SQInteger src = _fs->PopTarget(); + /* _OP_COMPARITH mixes dest obj and source val in the arg1 */ + _fs->AddInstruction(_OP_COMPARITH, _fs->PushTarget(), (src<<16)|val, key, ChooseCompArithCharByToken(tok)); + } + break; + case OUTER: + { + SQInteger val = _fs->TopTarget(); + SQInteger tmp = _fs->PushTarget(); + _fs->AddInstruction(_OP_GETOUTER, tmp, pos); + _fs->AddInstruction(ChooseArithOpByToken(tok), tmp, val, tmp, 0); + _fs->AddInstruction(_OP_SETOUTER, tmp, pos, tmp); + } + break; + } + } + void CommaExpr() + { + for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr()); + } + void Expression() + { + SQExpState es = _es; + _es.etype = EXPR; + _es.epos = -1; + _es.donot_get = false; + LogicalOrExp(); + switch(_token) { + case _SC('='): + case TK_NEWSLOT: + case TK_MINUSEQ: + case TK_PLUSEQ: + case TK_MULEQ: + case TK_DIVEQ: + case TK_MODEQ:{ + SQInteger op = _token; + SQInteger ds = _es.etype; + SQInteger pos = _es.epos; + if(ds == EXPR) Error(_SC("can't assign expression")); + Lex(); Expression(); + + switch(op){ + case TK_NEWSLOT: + if(ds == OBJECT || ds == BASE) + EmitDerefOp(_OP_NEWSLOT); + else //if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local + Error(_SC("can't 'create' a local slot")); + break; + case _SC('='): //ASSIGN + switch(ds) { + case LOCAL: + { + SQInteger src = _fs->PopTarget(); + SQInteger dst = _fs->TopTarget(); + _fs->AddInstruction(_OP_MOVE, dst, src); + } + break; + case OBJECT: + case BASE: + EmitDerefOp(_OP_SET); + break; + case OUTER: + { + SQInteger src = _fs->PopTarget(); + SQInteger dst = _fs->PushTarget(); + _fs->AddInstruction(_OP_SETOUTER, dst, pos, src); + } + } + break; + case TK_MINUSEQ: + case TK_PLUSEQ: + case TK_MULEQ: + case TK_DIVEQ: + case TK_MODEQ: + EmitCompoundArith(op, ds, pos); + break; + } + } + break; + case _SC('?'): { + Lex(); + _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); + SQInteger jzpos = _fs->GetCurrentPos(); + SQInteger trg = _fs->PushTarget(); + Expression(); + SQInteger first_exp = _fs->PopTarget(); + if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp); + SQInteger endfirstexp = _fs->GetCurrentPos(); + _fs->AddInstruction(_OP_JMP, 0, 0); + Expect(_SC(':')); + SQInteger jmppos = _fs->GetCurrentPos(); + Expression(); + SQInteger second_exp = _fs->PopTarget(); + if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp); + _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos); + _fs->SetIntructionParam(jzpos, 1, endfirstexp - jzpos + 1); + _fs->SnoozeOpt(); + } + break; + } + _es = es; + } + template<typename T> void BIN_EXP(SQOpcode op, T f,SQInteger op3 = 0) + { + Lex(); (this->*f)(); + SQInteger op1 = _fs->PopTarget();SQInteger op2 = _fs->PopTarget(); + _fs->AddInstruction(op, _fs->PushTarget(), op1, op2, op3); + } + void LogicalOrExp() + { + LogicalAndExp(); + for(;;) if(_token == TK_OR) { + SQInteger first_exp = _fs->PopTarget(); + SQInteger trg = _fs->PushTarget(); + _fs->AddInstruction(_OP_OR, trg, 0, first_exp, 0); + SQInteger jpos = _fs->GetCurrentPos(); + if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp); + Lex(); LogicalOrExp(); + _fs->SnoozeOpt(); + SQInteger second_exp = _fs->PopTarget(); + if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp); + _fs->SnoozeOpt(); + _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos)); + break; + }else return; + } + void LogicalAndExp() + { + BitwiseOrExp(); + for(;;) switch(_token) { + case TK_AND: { + SQInteger first_exp = _fs->PopTarget(); + SQInteger trg = _fs->PushTarget(); + _fs->AddInstruction(_OP_AND, trg, 0, first_exp, 0); + SQInteger jpos = _fs->GetCurrentPos(); + if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp); + Lex(); LogicalAndExp(); + _fs->SnoozeOpt(); + SQInteger second_exp = _fs->PopTarget(); + if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp); + _fs->SnoozeOpt(); + _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos)); + break; + } + case TK_IN: BIN_EXP(_OP_EXISTS, &SQCompiler::BitwiseOrExp); break; + case TK_INSTANCEOF: BIN_EXP(_OP_INSTANCEOF, &SQCompiler::BitwiseOrExp); break; + default: + return; + } + } + void BitwiseOrExp() + { + BitwiseXorExp(); + for(;;) if(_token == _SC('|')) + {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseXorExp,BW_OR); + }else return; + } + void BitwiseXorExp() + { + BitwiseAndExp(); + for(;;) if(_token == _SC('^')) + {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseAndExp,BW_XOR); + }else return; + } + void BitwiseAndExp() + { + EqExp(); + for(;;) if(_token == _SC('&')) + {BIN_EXP(_OP_BITW, &SQCompiler::EqExp,BW_AND); + }else return; + } + void EqExp() + { + CompExp(); + for(;;) switch(_token) { + case TK_EQ: BIN_EXP(_OP_EQ, &SQCompiler::CompExp); break; + case TK_NE: BIN_EXP(_OP_NE, &SQCompiler::CompExp); break; + case TK_3WAYSCMP: BIN_EXP(_OP_CMP, &SQCompiler::CompExp,CMP_3W); break; + default: return; + } + } + void CompExp() + { + ShiftExp(); + for(;;) switch(_token) { + case _SC('>'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_G); break; + case _SC('<'): BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_L); break; + case TK_GE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_GE); break; + case TK_LE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_LE); break; + default: return; + } + } + void ShiftExp() + { + PlusExp(); + for(;;) switch(_token) { + case TK_USHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_USHIFTR); break; + case TK_SHIFTL: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTL); break; + case TK_SHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTR); break; + default: return; + } + } + SQOpcode ChooseArithOpByToken(SQInteger tok) + { + switch(tok) { + case TK_PLUSEQ: case '+': return _OP_ADD; + case TK_MINUSEQ: case '-': return _OP_SUB; + case TK_MULEQ: case '*': return _OP_MUL; + case TK_DIVEQ: case '/': return _OP_DIV; + case TK_MODEQ: case '%': return _OP_MOD; + default: assert(0); + } + return _OP_ADD; + } + SQInteger ChooseCompArithCharByToken(SQInteger tok) + { + SQInteger oper; + switch(tok){ + case TK_MINUSEQ: oper = '-'; break; + case TK_PLUSEQ: oper = '+'; break; + case TK_MULEQ: oper = '*'; break; + case TK_DIVEQ: oper = '/'; break; + case TK_MODEQ: oper = '%'; break; + default: oper = 0; //shut up compiler + assert(0); break; + }; + return oper; + } + void PlusExp() + { + MultExp(); + for(;;) switch(_token) { + case _SC('+'): case _SC('-'): + BIN_EXP(ChooseArithOpByToken(_token), &SQCompiler::MultExp); break; + default: return; + } + } + + void MultExp() + { + PrefixedExpr(); + for(;;) switch(_token) { + case _SC('*'): case _SC('/'): case _SC('%'): + BIN_EXP(ChooseArithOpByToken(_token), &SQCompiler::PrefixedExpr); break; + default: return; + } + } + //if 'pos' != -1 the previous variable is a local variable + void PrefixedExpr() + { + SQInteger pos = Factor(); + for(;;) { + switch(_token) { + case _SC('.'): + pos = -1; + Lex(); + + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER))); + if(_es.etype==BASE) { + Emit2ArgsOP(_OP_GET); + pos = _fs->TopTarget(); + _es.etype = EXPR; + _es.epos = pos; + } + else { + if(NeedGet()) { + Emit2ArgsOP(_OP_GET); + } + _es.etype = OBJECT; + } + break; + case _SC('['): + if(_lex._prevtoken == _SC('\n')) Error(_SC("cannot brake deref/or comma needed after [exp]=exp slot declaration")); + Lex(); Expression(); Expect(_SC(']')); + pos = -1; + if(_es.etype==BASE) { + Emit2ArgsOP(_OP_GET); + pos = _fs->TopTarget(); + _es.etype = EXPR; + _es.epos = pos; + } + else { + if(NeedGet()) { + Emit2ArgsOP(_OP_GET); + } + _es.etype = OBJECT; + } + break; + case TK_MINUSMINUS: + case TK_PLUSPLUS: + { + if(IsEndOfStatement()) return; + SQInteger diff = (_token==TK_MINUSMINUS) ? -1 : 1; + Lex(); + switch(_es.etype) + { + case EXPR: Error(_SC("can't '++' or '--' an expression")); break; + case OBJECT: + case BASE: + Emit2ArgsOP(_OP_PINC, diff); + break; + case LOCAL: { + SQInteger src = _fs->PopTarget(); + _fs->AddInstruction(_OP_PINCL, _fs->PushTarget(), src, 0, diff); + } + break; + case OUTER: { + SQInteger tmp1 = _fs->PushTarget(); + SQInteger tmp2 = _fs->PushTarget(); + _fs->AddInstruction(_OP_GETOUTER, tmp2, _es.epos); + _fs->AddInstruction(_OP_PINCL, tmp1, tmp2, 0, diff); + _fs->AddInstruction(_OP_SETOUTER, tmp2, _es.epos, tmp2); + _fs->PopTarget(); + } + } + } + return; + break; + case _SC('('): + switch(_es.etype) { + case OBJECT: { + SQInteger key = _fs->PopTarget(); /* location of the key */ + SQInteger table = _fs->PopTarget(); /* location of the object */ + SQInteger closure = _fs->PushTarget(); /* location for the closure */ + SQInteger ttarget = _fs->PushTarget(); /* location for 'this' pointer */ + _fs->AddInstruction(_OP_PREPCALL, closure, key, table, ttarget); + } + break; + case BASE: + //Emit2ArgsOP(_OP_GET); + _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0); + break; + case OUTER: + _fs->AddInstruction(_OP_GETOUTER, _fs->PushTarget(), _es.epos); + _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0); + break; + default: + _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0); + } + _es.etype = EXPR; + Lex(); + FunctionCallArgs(); + break; + default: return; + } + } + } + SQInteger Factor() + { + _es.etype = EXPR; + switch(_token) + { + case TK_STRING_LITERAL: + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1))); + Lex(); + break; + case TK_BASE: + Lex(); + _fs->AddInstruction(_OP_GETBASE, _fs->PushTarget()); + _es.etype = BASE; + _es.epos = _fs->TopTarget(); + return (_es.epos); + break; + case TK_IDENTIFIER: + case TK_CONSTRUCTOR: + case TK_THIS:{ + SQObject id; + SQObject constant; + + switch(_token) { + case TK_IDENTIFIER: id = _fs->CreateString(_lex._svalue); break; + case TK_THIS: id = _fs->CreateString(_SC("this")); break; + case TK_CONSTRUCTOR: id = _fs->CreateString(_SC("constructor")); break; + } + + SQInteger pos = -1; + Lex(); + if((pos = _fs->GetLocalVariable(id)) != -1) { + /* Handle a local variable (includes 'this') */ + _fs->PushTarget(pos); + _es.etype = LOCAL; + _es.epos = pos; + } + + else if((pos = _fs->GetOuterVariable(id)) != -1) { + /* Handle a free var */ + if(NeedGet()) { + _es.epos = _fs->PushTarget(); + _fs->AddInstruction(_OP_GETOUTER, _es.epos, pos); + /* _es.etype = EXPR; already default value */ + } + else { + _es.etype = OUTER; + _es.epos = pos; + } + } + + else if(_fs->IsConstant(id, constant)) { + /* Handle named constant */ + SQObjectPtr constval; + SQObject constid; + if(type(constant) == OT_TABLE) { + Expect('.'); + constid = Expect(TK_IDENTIFIER); + if(!_table(constant)->Get(constid, constval)) { + constval.Null(); + Error(_SC("invalid constant [%s.%s]"), _stringval(id), _stringval(constid)); + } + } + else { + constval = constant; + } + _es.epos = _fs->PushTarget(); + + /* generate direct or literal function depending on size */ + SQObjectType ctype = type(constval); + switch(ctype) { + case OT_INTEGER: EmitLoadConstInt(_integer(constval),_es.epos); break; + case OT_FLOAT: EmitLoadConstFloat(_float(constval),_es.epos); break; + default: _fs->AddInstruction(_OP_LOAD,_es.epos,_fs->GetConstant(constval)); break; + } + _es.etype = EXPR; + } + else { + /* Handle a non-local variable, aka a field. Push the 'this' pointer on + * the virtual stack (always found in offset 0, so no instruction needs to + * be generated), and push the key next. Generate an _OP_LOAD instruction + * for the latter. If we are not using the variable as a dref expr, generate + * the _OP_GET instruction. + */ + _fs->PushTarget(0); + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); + if(NeedGet()) { + Emit2ArgsOP(_OP_GET); + } + _es.etype = OBJECT; + } + return _es.epos; + } + break; + case TK_DOUBLE_COLON: // "::" + _fs->AddInstruction(_OP_LOADROOT, _fs->PushTarget()); + _es.etype = OBJECT; + _token = _SC('.'); /* hack: drop into PrefixExpr, case '.'*/ + _es.epos = -1; + return _es.epos; + break; + case TK_NULL: + _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1); + Lex(); + break; + case TK_INTEGER: EmitLoadConstInt(_lex._nvalue,-1); Lex(); break; + case TK_FLOAT: EmitLoadConstFloat(_lex._fvalue,-1); Lex(); break; + case TK_TRUE: case TK_FALSE: + _fs->AddInstruction(_OP_LOADBOOL, _fs->PushTarget(),_token == TK_TRUE?1:0); + Lex(); + break; + case _SC('['): { + _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,0,NOT_ARRAY); + SQInteger apos = _fs->GetCurrentPos(),key = 0; + Lex(); + while(_token != _SC(']')) { + Expression(); + if(_token == _SC(',')) Lex(); + SQInteger val = _fs->PopTarget(); + SQInteger array = _fs->TopTarget(); + _fs->AddInstruction(_OP_APPENDARRAY, array, val, AAT_STACK); + key++; + } + _fs->SetIntructionParam(apos, 1, key); + Lex(); + } + break; + case _SC('{'): + _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE); + Lex();ParseTableOrClass(_SC(','),_SC('}')); + break; + case TK_FUNCTION: FunctionExp(_token);break; + case _SC('@'): FunctionExp(_token,true);break; + case TK_CLASS: Lex(); ClassExp();break; + case _SC('-'): + Lex(); + switch(_token) { + case TK_INTEGER: EmitLoadConstInt(-_lex._nvalue,-1); Lex(); break; + case TK_FLOAT: EmitLoadConstFloat(-_lex._fvalue,-1); Lex(); break; + default: UnaryOP(_OP_NEG); + } + break; + case _SC('!'): Lex(); UnaryOP(_OP_NOT); break; + case _SC('~'): + Lex(); + if(_token == TK_INTEGER) { EmitLoadConstInt(~_lex._nvalue,-1); Lex(); break; } + UnaryOP(_OP_BWNOT); + break; + case TK_TYPEOF : Lex() ;UnaryOP(_OP_TYPEOF); break; + case TK_RESUME : Lex(); UnaryOP(_OP_RESUME); break; + case TK_CLONE : Lex(); UnaryOP(_OP_CLONE); break; + case TK_MINUSMINUS : + case TK_PLUSPLUS :PrefixIncDec(_token); break; + case TK_DELETE : DeleteExpr(); break; + case _SC('('): Lex(); CommaExpr(); Expect(_SC(')')); + break; + default: Error(_SC("expression expected")); + } + return -1; + } + void EmitLoadConstInt(SQInteger value,SQInteger target) + { + if(target < 0) { + target = _fs->PushTarget(); + } + if((value & (~((SQInteger)0xFFFFFFFF))) == 0) { //does it fit in 32 bits? + _fs->AddInstruction(_OP_LOADINT, target,value); + } + else { + _fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value)); + } + } + void EmitLoadConstFloat(SQFloat value,SQInteger target) + { + if(target < 0) { + target = _fs->PushTarget(); + } + if(sizeof(SQFloat) == sizeof(SQInt32)) { + _fs->AddInstruction(_OP_LOADFLOAT, target,*((SQInt32 *)&value)); + } + else { + _fs->AddInstruction(_OP_LOAD, target, _fs->GetNumericConstant(value)); + } + } + void UnaryOP(SQOpcode op) + { + PrefixedExpr(); + SQInteger src = _fs->PopTarget(); + _fs->AddInstruction(op, _fs->PushTarget(), src); + } + bool NeedGet() + { + switch(_token) { + case _SC('='): case _SC('('): case TK_NEWSLOT: case TK_MODEQ: case TK_MULEQ: + case TK_DIVEQ: case TK_MINUSEQ: case TK_PLUSEQ: case TK_PLUSPLUS: case TK_MINUSMINUS: + return false; + } + return (!_es.donot_get || ( _es.donot_get && (_token == _SC('.') || _token == _SC('[')))); + } + void FunctionCallArgs() + { + SQInteger nargs = 1;//this + while(_token != _SC(')')) { + Expression(); + MoveIfCurrentTargetIsLocal(); + nargs++; + if(_token == _SC(',')){ + Lex(); + if(_token == ')') Error(_SC("expression expected, found ')'")); + } + } + Lex(); + for(SQInteger i = 0; i < (nargs - 1); i++) _fs->PopTarget(); + SQInteger stackbase = _fs->PopTarget(); + SQInteger closure = _fs->PopTarget(); + _fs->AddInstruction(_OP_CALL, _fs->PushTarget(), closure, stackbase, nargs); + } + void ParseTableOrClass(SQInteger separator,SQInteger terminator) + { + SQInteger tpos = _fs->GetCurrentPos(),nkeys = 0; + while(_token != terminator) { + bool hasattrs = false; + bool isstatic = false; + //check if is an attribute + if(separator == ';') { + if(_token == TK_ATTR_OPEN) { + _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE); Lex(); + ParseTableOrClass(',',TK_ATTR_CLOSE); + hasattrs = true; + } + if(_token == TK_STATIC) { + isstatic = true; + Lex(); + } + } + switch(_token) { + case TK_FUNCTION: + case TK_CONSTRUCTOR:{ + SQInteger tk = _token; + Lex(); + SQObject id = tk == TK_FUNCTION ? Expect(TK_IDENTIFIER) : _fs->CreateString(_SC("constructor")); + Expect(_SC('(')); + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); + CreateFunction(id); + _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0); + } + break; + case _SC('['): + Lex(); CommaExpr(); Expect(_SC(']')); + Expect(_SC('=')); Expression(); + break; + case TK_STRING_LITERAL: //JSON + if(separator == ',') { //only works for tables + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_STRING_LITERAL))); + Expect(_SC(':')); Expression(); + break; + } + default : + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER))); + Expect(_SC('=')); Expression(); + } + if(_token == separator) Lex();//optional comma/semicolon + nkeys++; + SQInteger val = _fs->PopTarget(); + SQInteger key = _fs->PopTarget(); + SQInteger attrs = hasattrs ? _fs->PopTarget():-1; + assert((hasattrs && (attrs == key-1)) || !hasattrs); + unsigned char flags = (hasattrs?NEW_SLOT_ATTRIBUTES_FLAG:0)|(isstatic?NEW_SLOT_STATIC_FLAG:0); + SQInteger table = _fs->TopTarget(); //<<BECAUSE OF THIS NO COMMON EMIT FUNC IS POSSIBLE + if(separator == _SC(',')) { //hack recognizes a table from the separator + _fs->AddInstruction(_OP_NEWSLOT, 0xFF, table, key, val); + } + else { + _fs->AddInstruction(_OP_NEWSLOTA, flags, table, key, val); //this for classes only as it invokes _newmember + } + } + if(separator == _SC(',')) //hack recognizes a table from the separator + _fs->SetIntructionParam(tpos, 1, nkeys); + Lex(); + } + void LocalDeclStatement() + { + SQObject varname; + Lex(); + if( _token == TK_FUNCTION) { + Lex(); + varname = Expect(TK_IDENTIFIER); + Expect(_SC('(')); + CreateFunction(varname,false); + _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0); + _fs->PopTarget(); + _fs->PushLocalVariable(varname); + return; + } + + do { + varname = Expect(TK_IDENTIFIER); + if(_token == _SC('=')) { + Lex(); Expression(); + SQInteger src = _fs->PopTarget(); + SQInteger dest = _fs->PushTarget(); + if(dest != src) _fs->AddInstruction(_OP_MOVE, dest, src); + } + else{ + _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1); + } + _fs->PopTarget(); + _fs->PushLocalVariable(varname); + if(_token == _SC(',')) Lex(); else break; + } while(1); + } + void IfStatement() + { + SQInteger jmppos; + bool haselse = false; + Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')')); + _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); + SQInteger jnepos = _fs->GetCurrentPos(); + BEGIN_SCOPE(); + + Statement(); + // + if(_token != _SC('}') && _token != TK_ELSE) OptionalSemicolon(); + + END_SCOPE(); + SQInteger endifblock = _fs->GetCurrentPos(); + if(_token == TK_ELSE){ + haselse = true; + BEGIN_SCOPE(); + _fs->AddInstruction(_OP_JMP); + jmppos = _fs->GetCurrentPos(); + Lex(); + Statement(); OptionalSemicolon(); + END_SCOPE(); + _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos); + } + _fs->SetIntructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0)); + } + void WhileStatement() + { + SQInteger jzpos, jmppos; + jmppos = _fs->GetCurrentPos(); + Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')')); + + BEGIN_BREAKBLE_BLOCK(); + _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); + jzpos = _fs->GetCurrentPos(); + BEGIN_SCOPE(); + + Statement(); + + END_SCOPE(); + _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1); + _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos); + + END_BREAKBLE_BLOCK(jmppos); + } + void DoWhileStatement() + { + Lex(); + SQInteger jmptrg = _fs->GetCurrentPos(); + BEGIN_BREAKBLE_BLOCK() + BEGIN_SCOPE(); + Statement(); + END_SCOPE(); + Expect(TK_WHILE); + SQInteger continuetrg = _fs->GetCurrentPos(); + Expect(_SC('(')); CommaExpr(); Expect(_SC(')')); + _fs->AddInstruction(_OP_JZ, _fs->PopTarget(), 1); + _fs->AddInstruction(_OP_JMP, 0, jmptrg - _fs->GetCurrentPos() - 1); + END_BREAKBLE_BLOCK(continuetrg); + } + void ForStatement() + { + Lex(); + BEGIN_SCOPE(); + Expect(_SC('(')); + if(_token == TK_LOCAL) LocalDeclStatement(); + else if(_token != _SC(';')){ + CommaExpr(); + _fs->PopTarget(); + } + Expect(_SC(';')); + _fs->SnoozeOpt(); + SQInteger jmppos = _fs->GetCurrentPos(); + SQInteger jzpos = -1; + if(_token != _SC(';')) { CommaExpr(); _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); jzpos = _fs->GetCurrentPos(); } + Expect(_SC(';')); + _fs->SnoozeOpt(); + SQInteger expstart = _fs->GetCurrentPos() + 1; + if(_token != _SC(')')) { + CommaExpr(); + _fs->PopTarget(); + } + Expect(_SC(')')); + _fs->SnoozeOpt(); + SQInteger expend = _fs->GetCurrentPos(); + SQInteger expsize = (expend - expstart) + 1; + SQInstructionVec exp; + if(expsize > 0) { + for(SQInteger i = 0; i < expsize; i++) + exp.push_back(_fs->GetInstruction(expstart + i)); + _fs->PopInstructions(expsize); + } + BEGIN_BREAKBLE_BLOCK() + Statement(); + SQInteger continuetrg = _fs->GetCurrentPos(); + if(expsize > 0) { + for(SQInteger i = 0; i < expsize; i++) + _fs->AddInstruction(exp[i]); + } + _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1, 0); + if(jzpos> 0) _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos); + END_SCOPE(); + + END_BREAKBLE_BLOCK(continuetrg); + } + void ForEachStatement() + { + SQObject idxname, valname; + Lex(); Expect(_SC('(')); valname = Expect(TK_IDENTIFIER); + if(_token == _SC(',')) { + idxname = valname; + Lex(); valname = Expect(TK_IDENTIFIER); + } + else{ + idxname = _fs->CreateString(_SC("@INDEX@")); + } + Expect(TK_IN); + + //save the stack size + BEGIN_SCOPE(); + //put the table in the stack(evaluate the table expression) + Expression(); Expect(_SC(')')); + SQInteger container = _fs->TopTarget(); + //push the index local var + SQInteger indexpos = _fs->PushLocalVariable(idxname); + _fs->AddInstruction(_OP_LOADNULLS, indexpos,1); + //push the value local var + SQInteger valuepos = _fs->PushLocalVariable(valname); + _fs->AddInstruction(_OP_LOADNULLS, valuepos,1); + //push reference index + SQInteger itrpos = _fs->PushLocalVariable(_fs->CreateString(_SC("@ITERATOR@"))); //use invalid id to make it inaccessible + _fs->AddInstruction(_OP_LOADNULLS, itrpos,1); + SQInteger jmppos = _fs->GetCurrentPos(); + _fs->AddInstruction(_OP_FOREACH, container, 0, indexpos); + SQInteger foreachpos = _fs->GetCurrentPos(); + _fs->AddInstruction(_OP_POSTFOREACH, container, 0, indexpos); + //generate the statement code + BEGIN_BREAKBLE_BLOCK() + Statement(); + _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1); + _fs->SetIntructionParam(foreachpos, 1, _fs->GetCurrentPos() - foreachpos); + _fs->SetIntructionParam(foreachpos + 1, 1, _fs->GetCurrentPos() - foreachpos); + END_BREAKBLE_BLOCK(foreachpos - 1); + //restore the local variable stack(remove index,val and ref idx) + END_SCOPE(); + } + void SwitchStatement() + { + Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')')); + Expect(_SC('{')); + SQInteger expr = _fs->TopTarget(); + bool bfirst = true; + SQInteger tonextcondjmp = -1; + SQInteger skipcondjmp = -1; + SQInteger __nbreaks__ = _fs->_unresolvedbreaks.size(); + _fs->_breaktargets.push_back(0); + while(_token == TK_CASE) { + if(!bfirst) { + _fs->AddInstruction(_OP_JMP, 0, 0); + skipcondjmp = _fs->GetCurrentPos(); + _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp); + } + //condition + Lex(); Expression(); Expect(_SC(':')); + SQInteger trg = _fs->PopTarget(); + _fs->AddInstruction(_OP_EQ, trg, trg, expr); + _fs->AddInstruction(_OP_JZ, trg, 0); + //end condition + if(skipcondjmp != -1) { + _fs->SetIntructionParam(skipcondjmp, 1, (_fs->GetCurrentPos() - skipcondjmp)); + } + tonextcondjmp = _fs->GetCurrentPos(); + BEGIN_SCOPE(); + Statements(); + END_SCOPE(); + bfirst = false; + } + if(tonextcondjmp != -1) + _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp); + if(_token == TK_DEFAULT) { + Lex(); Expect(_SC(':')); + BEGIN_SCOPE(); + Statements(); + END_SCOPE(); + } + Expect(_SC('}')); + _fs->PopTarget(); + __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__; + if(__nbreaks__ > 0)ResolveBreaks(_fs, __nbreaks__); + _fs->_breaktargets.pop_back(); + } + void FunctionStatement() + { + SQObject id; + Lex(); id = Expect(TK_IDENTIFIER); + _fs->PushTarget(0); + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); + if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET); + + while(_token == TK_DOUBLE_COLON) { + Lex(); + id = Expect(TK_IDENTIFIER); + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); + if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET); + } + Expect(_SC('(')); + CreateFunction(id); + _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0); + EmitDerefOp(_OP_NEWSLOT); + _fs->PopTarget(); + } + void ClassStatement() + { + SQExpState es; + Lex(); + es = _es; + _es.donot_get = true; + PrefixedExpr(); + if(_es.etype == EXPR) { + Error(_SC("invalid class name")); + } + else if(_es.etype == OBJECT || _es.etype == BASE) { + ClassExp(); + EmitDerefOp(_OP_NEWSLOT); + _fs->PopTarget(); + } + else { + Error(_SC("cannot create a class in a local with the syntax(class <local>)")); + } + _es = es; + } + SQObject ExpectScalar() + { + SQObject val; + val._type = OT_NULL; val._unVal.nInteger = 0; //shut up GCC 4.x + switch(_token) { + case TK_INTEGER: + val._type = OT_INTEGER; + val._unVal.nInteger = _lex._nvalue; + break; + case TK_FLOAT: + val._type = OT_FLOAT; + val._unVal.fFloat = _lex._fvalue; + break; + case TK_STRING_LITERAL: + val = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1); + break; + case '-': + Lex(); + switch(_token) + { + case TK_INTEGER: + val._type = OT_INTEGER; + val._unVal.nInteger = -_lex._nvalue; + break; + case TK_FLOAT: + val._type = OT_FLOAT; + val._unVal.fFloat = -_lex._fvalue; + break; + default: + Error(_SC("scalar expected : integer,float")); + } + break; + default: + Error(_SC("scalar expected : integer,float or string")); + } + Lex(); + return val; + } + void EnumStatement() + { + Lex(); + SQObject id = Expect(TK_IDENTIFIER); + Expect(_SC('{')); + + SQObject table = _fs->CreateTable(); + SQInteger nval = 0; + while(_token != _SC('}')) { + SQObject key = Expect(TK_IDENTIFIER); + SQObject val; + if(_token == _SC('=')) { + Lex(); + val = ExpectScalar(); + } + else { + val._type = OT_INTEGER; + val._unVal.nInteger = nval++; + } + _table(table)->NewSlot(SQObjectPtr(key),SQObjectPtr(val)); + if(_token == ',') Lex(); + } + SQTable *enums = _table(_ss(_vm)->_consts); + SQObjectPtr strongid = id; + enums->NewSlot(SQObjectPtr(strongid),SQObjectPtr(table)); + strongid.Null(); + Lex(); + } + void TryCatchStatement() + { + SQObject exid; + Lex(); + _fs->AddInstruction(_OP_PUSHTRAP,0,0); + _fs->_traps++; + if(_fs->_breaktargets.size()) _fs->_breaktargets.top()++; + if(_fs->_continuetargets.size()) _fs->_continuetargets.top()++; + SQInteger trappos = _fs->GetCurrentPos(); + { + BEGIN_SCOPE(); + Statement(); + END_SCOPE(); + } + _fs->_traps--; + _fs->AddInstruction(_OP_POPTRAP, 1, 0); + if(_fs->_breaktargets.size()) _fs->_breaktargets.top()--; + if(_fs->_continuetargets.size()) _fs->_continuetargets.top()--; + _fs->AddInstruction(_OP_JMP, 0, 0); + SQInteger jmppos = _fs->GetCurrentPos(); + _fs->SetIntructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos)); + Expect(TK_CATCH); Expect(_SC('(')); exid = Expect(TK_IDENTIFIER); Expect(_SC(')')); + { + BEGIN_SCOPE(); + SQInteger ex_target = _fs->PushLocalVariable(exid); + _fs->SetIntructionParam(trappos, 0, ex_target); + Statement(); + _fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0); + END_SCOPE(); + } + } + void FunctionExp(SQInteger ftype,bool lambda = false) + { + Lex(); Expect(_SC('(')); + SQObjectPtr dummy; + CreateFunction(dummy,lambda); + _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, ftype == TK_FUNCTION?0:1); + } + void ClassExp() + { + SQInteger base = -1; + SQInteger attrs = -1; + if(_token == TK_EXTENDS) { + Lex(); Expression(); + base = _fs->TopTarget(); + } + if(_token == TK_ATTR_OPEN) { + Lex(); + _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(),0,NOT_TABLE); + ParseTableOrClass(_SC(','),TK_ATTR_CLOSE); + attrs = _fs->TopTarget(); + } + Expect(_SC('{')); + if(attrs != -1) _fs->PopTarget(); + if(base != -1) _fs->PopTarget(); + _fs->AddInstruction(_OP_NEWOBJ, _fs->PushTarget(), base, attrs,NOT_CLASS); + ParseTableOrClass(_SC(';'),_SC('}')); + } + void DeleteExpr() + { + SQExpState es; + Lex(); + es = _es; + _es.donot_get = true; + PrefixedExpr(); + if(_es.etype==EXPR) Error(_SC("can't delete an expression")); + if(_es.etype==OBJECT || _es.etype==BASE) { + Emit2ArgsOP(_OP_DELETE); + } + else { + Error(_SC("cannot delete an (outer) local")); + } + _es = es; + } + void PrefixIncDec(SQInteger token) + { + SQExpState es; + SQInteger diff = (token==TK_MINUSMINUS) ? -1 : 1; + Lex(); + es = _es; + _es.donot_get = true; + PrefixedExpr(); + if(_es.etype==EXPR) { + Error(_SC("can't '++' or '--' an expression")); + } + else if(_es.etype==OBJECT || _es.etype==BASE) { + Emit2ArgsOP(_OP_INC, diff); + } + else if(_es.etype==LOCAL) { + SQInteger src = _fs->TopTarget(); + _fs->AddInstruction(_OP_INCL, src, src, 0, diff); + + } + else if(_es.etype==OUTER) { + SQInteger tmp = _fs->PushTarget(); + _fs->AddInstruction(_OP_GETOUTER, tmp, _es.epos); + _fs->AddInstruction(_OP_INCL, tmp, tmp, 0, diff); + _fs->AddInstruction(_OP_SETOUTER, tmp, _es.epos, tmp); + } + _es = es; + } + void CreateFunction(SQObject &name,bool lambda = false) + { + SQFuncState *funcstate = _fs->PushChildState(_ss(_vm)); + funcstate->_name = name; + SQObject paramname; + funcstate->AddParameter(_fs->CreateString(_SC("this"))); + funcstate->_sourcename = _sourcename; + SQInteger defparams = 0; + while(_token!=_SC(')')) { + if(_token == TK_VARPARAMS) { + if(defparams > 0) Error(_SC("function with default parameters cannot have variable number of parameters")); + funcstate->AddParameter(_fs->CreateString(_SC("vargv"))); + funcstate->_varparams = true; + Lex(); + if(_token != _SC(')')) Error(_SC("expected ')'")); + break; + } + else { + paramname = Expect(TK_IDENTIFIER); + funcstate->AddParameter(paramname); + if(_token == _SC('=')) { + Lex(); + Expression(); + funcstate->AddDefaultParam(_fs->TopTarget()); + defparams++; + } + else { + if(defparams > 0) Error(_SC("expected '='")); + } + if(_token == _SC(',')) Lex(); + else if(_token != _SC(')')) Error(_SC("expected ')' or ','")); + } + } + Expect(_SC(')')); + for(SQInteger n = 0; n < defparams; n++) { + _fs->PopTarget(); + } + + SQFuncState *currchunk = _fs; + _fs = funcstate; + if(lambda) { + Expression(); + _fs->AddInstruction(_OP_RETURN, 1, _fs->PopTarget());} + else { + Statement(false); + } + funcstate->AddLineInfos(_lex._prevtoken == _SC('\n')?_lex._lasttokenline:_lex._currentline, _lineinfo, true); + funcstate->AddInstruction(_OP_RETURN, -1); + funcstate->SetStackSize(0); + + SQFunctionProto *func = funcstate->BuildProto(); +#ifdef _DEBUG_DUMP + funcstate->Dump(func); +#endif + _fs = currchunk; + _fs->_functions.push_back(func); + _fs->PopChildState(); + } + void ResolveBreaks(SQFuncState *funcstate, SQInteger ntoresolve) + { + while(ntoresolve > 0) { + SQInteger pos = funcstate->_unresolvedbreaks.back(); + funcstate->_unresolvedbreaks.pop_back(); + //set the jmp instruction + funcstate->SetIntructionParams(pos, 0, funcstate->GetCurrentPos() - pos, 0); + ntoresolve--; + } + } + void ResolveContinues(SQFuncState *funcstate, SQInteger ntoresolve, SQInteger targetpos) + { + while(ntoresolve > 0) { + SQInteger pos = funcstate->_unresolvedcontinues.back(); + funcstate->_unresolvedcontinues.pop_back(); + //set the jmp instruction + funcstate->SetIntructionParams(pos, 0, targetpos - pos, 0); + ntoresolve--; + } + } +private: + SQInteger _token; + SQFuncState *_fs; + SQObjectPtr _sourcename; + SQLexer _lex; + bool _lineinfo; + bool _raiseerror; + SQInteger _debugline; + SQInteger _debugop; + SQExpState _es; + SQScope _scope; + SQChar *compilererror; + jmp_buf _errorjmp; + SQVM *_vm; +}; + +bool Compile(SQVM *vm,SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo) +{ + SQCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo); + return p.Compile(out); +} + +#endif diff --git a/squirrel_3_0_1_stable/squirrel/sqcompiler.h b/squirrel_3_0_1_stable/squirrel/sqcompiler.h index fcfd46a99..de5983b46 100644 --- a/squirrel_3_0_1_stable/squirrel/sqcompiler.h +++ b/squirrel_3_0_1_stable/squirrel/sqcompiler.h @@ -1,77 +1,77 @@ -/* see copyright notice in squirrel.h */
-#ifndef _SQCOMPILER_H_
-#define _SQCOMPILER_H_
-
-struct SQVM;
-
-#define TK_IDENTIFIER 258
-#define TK_STRING_LITERAL 259
-#define TK_INTEGER 260
-#define TK_FLOAT 261
-#define TK_BASE 262
-#define TK_DELETE 263
-#define TK_EQ 264
-#define TK_NE 265
-#define TK_LE 266
-#define TK_GE 267
-#define TK_SWITCH 268
-#define TK_ARROW 269
-#define TK_AND 270
-#define TK_OR 271
-#define TK_IF 272
-#define TK_ELSE 273
-#define TK_WHILE 274
-#define TK_BREAK 275
-#define TK_FOR 276
-#define TK_DO 277
-#define TK_NULL 278
-#define TK_FOREACH 279
-#define TK_IN 280
-#define TK_NEWSLOT 281
-#define TK_MODULO 282
-#define TK_LOCAL 283
-#define TK_CLONE 284
-#define TK_FUNCTION 285
-#define TK_RETURN 286
-#define TK_TYPEOF 287
-#define TK_UMINUS 288
-#define TK_PLUSEQ 289
-#define TK_MINUSEQ 290
-#define TK_CONTINUE 291
-#define TK_YIELD 292
-#define TK_TRY 293
-#define TK_CATCH 294
-#define TK_THROW 295
-#define TK_SHIFTL 296
-#define TK_SHIFTR 297
-#define TK_RESUME 298
-#define TK_DOUBLE_COLON 299
-#define TK_CASE 300
-#define TK_DEFAULT 301
-#define TK_THIS 302
-#define TK_PLUSPLUS 303
-#define TK_MINUSMINUS 304
-#define TK_3WAYSCMP 305
-#define TK_USHIFTR 306
-#define TK_CLASS 307
-#define TK_EXTENDS 308
-#define TK_CONSTRUCTOR 310
-#define TK_INSTANCEOF 311
-#define TK_VARPARAMS 312
-//#define TK_VARGC 313
-//#define TK_VARGV 314
-#define TK_TRUE 315
-#define TK_FALSE 316
-#define TK_MULEQ 317
-#define TK_DIVEQ 318
-#define TK_MODEQ 319
-#define TK_ATTR_OPEN 320
-#define TK_ATTR_CLOSE 321
-#define TK_STATIC 322
-#define TK_ENUM 323
-#define TK_CONST 324
-
-
-typedef void(*CompilerErrorFunc)(void *ud, const SQChar *s);
-bool Compile(SQVM *vm, SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo);
-#endif //_SQCOMPILER_H_
+/* see copyright notice in squirrel.h */ +#ifndef _SQCOMPILER_H_ +#define _SQCOMPILER_H_ + +struct SQVM; + +#define TK_IDENTIFIER 258 +#define TK_STRING_LITERAL 259 +#define TK_INTEGER 260 +#define TK_FLOAT 261 +#define TK_BASE 262 +#define TK_DELETE 263 +#define TK_EQ 264 +#define TK_NE 265 +#define TK_LE 266 +#define TK_GE 267 +#define TK_SWITCH 268 +#define TK_ARROW 269 +#define TK_AND 270 +#define TK_OR 271 +#define TK_IF 272 +#define TK_ELSE 273 +#define TK_WHILE 274 +#define TK_BREAK 275 +#define TK_FOR 276 +#define TK_DO 277 +#define TK_NULL 278 +#define TK_FOREACH 279 +#define TK_IN 280 +#define TK_NEWSLOT 281 +#define TK_MODULO 282 +#define TK_LOCAL 283 +#define TK_CLONE 284 +#define TK_FUNCTION 285 +#define TK_RETURN 286 +#define TK_TYPEOF 287 +#define TK_UMINUS 288 +#define TK_PLUSEQ 289 +#define TK_MINUSEQ 290 +#define TK_CONTINUE 291 +#define TK_YIELD 292 +#define TK_TRY 293 +#define TK_CATCH 294 +#define TK_THROW 295 +#define TK_SHIFTL 296 +#define TK_SHIFTR 297 +#define TK_RESUME 298 +#define TK_DOUBLE_COLON 299 +#define TK_CASE 300 +#define TK_DEFAULT 301 +#define TK_THIS 302 +#define TK_PLUSPLUS 303 +#define TK_MINUSMINUS 304 +#define TK_3WAYSCMP 305 +#define TK_USHIFTR 306 +#define TK_CLASS 307 +#define TK_EXTENDS 308 +#define TK_CONSTRUCTOR 310 +#define TK_INSTANCEOF 311 +#define TK_VARPARAMS 312 +//#define TK_VARGC 313 +//#define TK_VARGV 314 +#define TK_TRUE 315 +#define TK_FALSE 316 +#define TK_MULEQ 317 +#define TK_DIVEQ 318 +#define TK_MODEQ 319 +#define TK_ATTR_OPEN 320 +#define TK_ATTR_CLOSE 321 +#define TK_STATIC 322 +#define TK_ENUM 323 +#define TK_CONST 324 + + +typedef void(*CompilerErrorFunc)(void *ud, const SQChar *s); +bool Compile(SQVM *vm, SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo); +#endif //_SQCOMPILER_H_ diff --git a/squirrel_3_0_1_stable/squirrel/sqdebug.cpp b/squirrel_3_0_1_stable/squirrel/sqdebug.cpp index 3cb7b71cd..01d0261d2 100644 --- a/squirrel_3_0_1_stable/squirrel/sqdebug.cpp +++ b/squirrel_3_0_1_stable/squirrel/sqdebug.cpp @@ -1,116 +1,116 @@ -/*
- see copyright notice in squirrel.h
-*/
-#include "sqpcheader.h"
-#include <stdarg.h>
-#include "sqvm.h"
-#include "sqfuncproto.h"
-#include "sqclosure.h"
-#include "sqstring.h"
-
-SQRESULT sq_getfunctioninfo(HSQUIRRELVM v,SQInteger level,SQFunctionInfo *fi)
-{
- SQInteger cssize = v->_callsstacksize;
- if (cssize > level) {
- SQVM::CallInfo &ci = v->_callsstack[cssize-level-1];
- if(sq_isclosure(ci._closure)) {
- SQClosure *c = _closure(ci._closure);
- SQFunctionProto *proto = c->_function;
- fi->funcid = proto;
- fi->name = type(proto->_name) == OT_STRING?_stringval(proto->_name):_SC("unknown");
- fi->source = type(proto->_name) == OT_STRING?_stringval(proto->_sourcename):_SC("unknown");
- return SQ_OK;
- }
- }
- return sq_throwerror(v,_SC("the object is not a closure"));
-}
-
-SQRESULT sq_stackinfos(HSQUIRRELVM v, SQInteger level, SQStackInfos *si)
-{
- SQInteger cssize = v->_callsstacksize;
- if (cssize > level) {
- memset(si, 0, sizeof(SQStackInfos));
- SQVM::CallInfo &ci = v->_callsstack[cssize-level-1];
- switch (type(ci._closure)) {
- case OT_CLOSURE:{
- SQFunctionProto *func = _closure(ci._closure)->_function;
- if (type(func->_name) == OT_STRING)
- si->funcname = _stringval(func->_name);
- if (type(func->_sourcename) == OT_STRING)
- si->source = _stringval(func->_sourcename);
- si->line = func->GetLine(ci._ip);
- }
- break;
- case OT_NATIVECLOSURE:
- si->source = _SC("NATIVE");
- si->funcname = _SC("unknown");
- if(type(_nativeclosure(ci._closure)->_name) == OT_STRING)
- si->funcname = _stringval(_nativeclosure(ci._closure)->_name);
- si->line = -1;
- break;
- default: break; //shutup compiler
- }
- return SQ_OK;
- }
- return SQ_ERROR;
-}
-
-void SQVM::Raise_Error(const SQChar *s, ...)
-{
- va_list vl;
- va_start(vl, s);
- scvsprintf(_sp(rsl((SQInteger)scstrlen(s)+(NUMBER_MAX_CHAR*2))), s, vl);
- va_end(vl);
- _lasterror = SQString::Create(_ss(this),_spval,-1);
-}
-
-void SQVM::Raise_Error(const SQObjectPtr &desc)
-{
- _lasterror = desc;
-}
-
-SQString *SQVM::PrintObjVal(const SQObjectPtr &o)
-{
- switch(type(o)) {
- case OT_STRING: return _string(o);
- case OT_INTEGER:
- scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)), _PRINT_INT_FMT, _integer(o));
- return SQString::Create(_ss(this), _spval);
- break;
- case OT_FLOAT:
- scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)), _SC("%.14g"), _float(o));
- return SQString::Create(_ss(this), _spval);
- break;
- default:
- return SQString::Create(_ss(this), GetTypeName(o));
- }
-}
-
-void SQVM::Raise_IdxError(const SQObjectPtr &o)
-{
- SQObjectPtr oval = PrintObjVal(o);
- Raise_Error(_SC("the index '%.50s' does not exist"), _stringval(oval));
-}
-
-void SQVM::Raise_CompareError(const SQObject &o1, const SQObject &o2)
-{
- SQObjectPtr oval1 = PrintObjVal(o1), oval2 = PrintObjVal(o2);
- Raise_Error(_SC("comparsion between '%.50s' and '%.50s'"), _stringval(oval1), _stringval(oval2));
-}
-
-
-void SQVM::Raise_ParamTypeError(SQInteger nparam,SQInteger typemask,SQInteger type)
-{
- SQObjectPtr exptypes = SQString::Create(_ss(this), _SC(""), -1);
- SQInteger found = 0;
- for(SQInteger i=0; i<16; i++)
- {
- SQInteger mask = 0x00000001 << i;
- if(typemask & (mask)) {
- if(found>0) StringCat(exptypes,SQString::Create(_ss(this), _SC("|"), -1), exptypes);
- found ++;
- StringCat(exptypes,SQString::Create(_ss(this), IdType2Name((SQObjectType)mask), -1), exptypes);
- }
- }
- Raise_Error(_SC("parameter %d has an invalid type '%s' ; expected: '%s'"), nparam, IdType2Name((SQObjectType)type), _stringval(exptypes));
-}
+/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include <stdarg.h> +#include "sqvm.h" +#include "sqfuncproto.h" +#include "sqclosure.h" +#include "sqstring.h" + +SQRESULT sq_getfunctioninfo(HSQUIRRELVM v,SQInteger level,SQFunctionInfo *fi) +{ + SQInteger cssize = v->_callsstacksize; + if (cssize > level) { + SQVM::CallInfo &ci = v->_callsstack[cssize-level-1]; + if(sq_isclosure(ci._closure)) { + SQClosure *c = _closure(ci._closure); + SQFunctionProto *proto = c->_function; + fi->funcid = proto; + fi->name = type(proto->_name) == OT_STRING?_stringval(proto->_name):_SC("unknown"); + fi->source = type(proto->_name) == OT_STRING?_stringval(proto->_sourcename):_SC("unknown"); + return SQ_OK; + } + } + return sq_throwerror(v,_SC("the object is not a closure")); +} + +SQRESULT sq_stackinfos(HSQUIRRELVM v, SQInteger level, SQStackInfos *si) +{ + SQInteger cssize = v->_callsstacksize; + if (cssize > level) { + memset(si, 0, sizeof(SQStackInfos)); + SQVM::CallInfo &ci = v->_callsstack[cssize-level-1]; + switch (type(ci._closure)) { + case OT_CLOSURE:{ + SQFunctionProto *func = _closure(ci._closure)->_function; + if (type(func->_name) == OT_STRING) + si->funcname = _stringval(func->_name); + if (type(func->_sourcename) == OT_STRING) + si->source = _stringval(func->_sourcename); + si->line = func->GetLine(ci._ip); + } + break; + case OT_NATIVECLOSURE: + si->source = _SC("NATIVE"); + si->funcname = _SC("unknown"); + if(type(_nativeclosure(ci._closure)->_name) == OT_STRING) + si->funcname = _stringval(_nativeclosure(ci._closure)->_name); + si->line = -1; + break; + default: break; //shutup compiler + } + return SQ_OK; + } + return SQ_ERROR; +} + +void SQVM::Raise_Error(const SQChar *s, ...) +{ + va_list vl; + va_start(vl, s); + scvsprintf(_sp(rsl((SQInteger)scstrlen(s)+(NUMBER_MAX_CHAR*2))), s, vl); + va_end(vl); + _lasterror = SQString::Create(_ss(this),_spval,-1); +} + +void SQVM::Raise_Error(const SQObjectPtr &desc) +{ + _lasterror = desc; +} + +SQString *SQVM::PrintObjVal(const SQObjectPtr &o) +{ + switch(type(o)) { + case OT_STRING: return _string(o); + case OT_INTEGER: + scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)), _PRINT_INT_FMT, _integer(o)); + return SQString::Create(_ss(this), _spval); + break; + case OT_FLOAT: + scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)), _SC("%.14g"), _float(o)); + return SQString::Create(_ss(this), _spval); + break; + default: + return SQString::Create(_ss(this), GetTypeName(o)); + } +} + +void SQVM::Raise_IdxError(const SQObjectPtr &o) +{ + SQObjectPtr oval = PrintObjVal(o); + Raise_Error(_SC("the index '%.50s' does not exist"), _stringval(oval)); +} + +void SQVM::Raise_CompareError(const SQObject &o1, const SQObject &o2) +{ + SQObjectPtr oval1 = PrintObjVal(o1), oval2 = PrintObjVal(o2); + Raise_Error(_SC("comparsion between '%.50s' and '%.50s'"), _stringval(oval1), _stringval(oval2)); +} + + +void SQVM::Raise_ParamTypeError(SQInteger nparam,SQInteger typemask,SQInteger type) +{ + SQObjectPtr exptypes = SQString::Create(_ss(this), _SC(""), -1); + SQInteger found = 0; + for(SQInteger i=0; i<16; i++) + { + SQInteger mask = 0x00000001 << i; + if(typemask & (mask)) { + if(found>0) StringCat(exptypes,SQString::Create(_ss(this), _SC("|"), -1), exptypes); + found ++; + StringCat(exptypes,SQString::Create(_ss(this), IdType2Name((SQObjectType)mask), -1), exptypes); + } + } + Raise_Error(_SC("parameter %d has an invalid type '%s' ; expected: '%s'"), nparam, IdType2Name((SQObjectType)type), _stringval(exptypes)); +} diff --git a/squirrel_3_0_1_stable/squirrel/sqfuncproto.h b/squirrel_3_0_1_stable/squirrel/sqfuncproto.h index cd48aa6df..e6e9529ec 100644 --- a/squirrel_3_0_1_stable/squirrel/sqfuncproto.h +++ b/squirrel_3_0_1_stable/squirrel/sqfuncproto.h @@ -1,154 +1,154 @@ -/* see copyright notice in squirrel.h */
-#ifndef _SQFUNCTION_H_
-#define _SQFUNCTION_H_
-
-#include "sqopcodes.h"
-
-enum SQOuterType {
- otLOCAL = 0,
- otOUTER = 1
-};
-
-struct SQOuterVar
-{
-
- SQOuterVar(){}
- SQOuterVar(const SQObjectPtr &name,const SQObjectPtr &src,SQOuterType t)
- {
- _name = name;
- _src=src;
- _type=t;
- }
- SQOuterVar(const SQOuterVar &ov)
- {
- _type=ov._type;
- _src=ov._src;
- _name=ov._name;
- }
- SQOuterType _type;
- SQObjectPtr _name;
- SQObjectPtr _src;
-};
-
-struct SQLocalVarInfo
-{
- SQLocalVarInfo():_start_op(0),_end_op(0),_pos(0){}
- SQLocalVarInfo(const SQLocalVarInfo &lvi)
- {
- _name=lvi._name;
- _start_op=lvi._start_op;
- _end_op=lvi._end_op;
- _pos=lvi._pos;
- }
- SQObjectPtr _name;
- SQUnsignedInteger _start_op;
- SQUnsignedInteger _end_op;
- SQUnsignedInteger _pos;
-};
-
-struct SQLineInfo { SQInteger _line;SQInteger _op; };
-
-typedef sqvector<SQOuterVar> SQOuterVarVec;
-typedef sqvector<SQLocalVarInfo> SQLocalVarInfoVec;
-typedef sqvector<SQLineInfo> SQLineInfoVec;
-
-#define _FUNC_SIZE(ni,nl,nparams,nfuncs,nouters,nlineinf,localinf,defparams) (sizeof(SQFunctionProto) \
- +((ni-1)*sizeof(SQInstruction))+(nl*sizeof(SQObjectPtr)) \
- +(nparams*sizeof(SQObjectPtr))+(nfuncs*sizeof(SQObjectPtr)) \
- +(nouters*sizeof(SQOuterVar))+(nlineinf*sizeof(SQLineInfo)) \
- +(localinf*sizeof(SQLocalVarInfo))+(defparams*sizeof(SQInteger)))
-
-
-struct SQFunctionProto : public CHAINABLE_OBJ
-{
-private:
- SQFunctionProto(SQSharedState *ss);
- ~SQFunctionProto();
-
-public:
- static SQFunctionProto *Create(SQSharedState *ss,SQInteger ninstructions,
- SQInteger nliterals,SQInteger nparameters,
- SQInteger nfunctions,SQInteger noutervalues,
- SQInteger nlineinfos,SQInteger nlocalvarinfos,SQInteger ndefaultparams)
- {
- SQFunctionProto *f;
- //I compact the whole class and members in a single memory allocation
- f = (SQFunctionProto *)sq_vm_malloc(_FUNC_SIZE(ninstructions,nliterals,nparameters,nfunctions,noutervalues,nlineinfos,nlocalvarinfos,ndefaultparams));
- new (f) SQFunctionProto(ss);
- f->_ninstructions = ninstructions;
- f->_literals = (SQObjectPtr*)&f->_instructions[ninstructions];
- f->_nliterals = nliterals;
- f->_parameters = (SQObjectPtr*)&f->_literals[nliterals];
- f->_nparameters = nparameters;
- f->_functions = (SQObjectPtr*)&f->_parameters[nparameters];
- f->_nfunctions = nfunctions;
- f->_outervalues = (SQOuterVar*)&f->_functions[nfunctions];
- f->_noutervalues = noutervalues;
- f->_lineinfos = (SQLineInfo *)&f->_outervalues[noutervalues];
- f->_nlineinfos = nlineinfos;
- f->_localvarinfos = (SQLocalVarInfo *)&f->_lineinfos[nlineinfos];
- f->_nlocalvarinfos = nlocalvarinfos;
- f->_defaultparams = (SQInteger *)&f->_localvarinfos[nlocalvarinfos];
- f->_ndefaultparams = ndefaultparams;
-
- _CONSTRUCT_VECTOR(SQObjectPtr,f->_nliterals,f->_literals);
- _CONSTRUCT_VECTOR(SQObjectPtr,f->_nparameters,f->_parameters);
- _CONSTRUCT_VECTOR(SQObjectPtr,f->_nfunctions,f->_functions);
- _CONSTRUCT_VECTOR(SQOuterVar,f->_noutervalues,f->_outervalues);
- //_CONSTRUCT_VECTOR(SQLineInfo,f->_nlineinfos,f->_lineinfos); //not required are 2 integers
- _CONSTRUCT_VECTOR(SQLocalVarInfo,f->_nlocalvarinfos,f->_localvarinfos);
- return f;
- }
- void Release(){
- _DESTRUCT_VECTOR(SQObjectPtr,_nliterals,_literals);
- _DESTRUCT_VECTOR(SQObjectPtr,_nparameters,_parameters);
- _DESTRUCT_VECTOR(SQObjectPtr,_nfunctions,_functions);
- _DESTRUCT_VECTOR(SQOuterVar,_noutervalues,_outervalues);
- //_DESTRUCT_VECTOR(SQLineInfo,_nlineinfos,_lineinfos); //not required are 2 integers
- _DESTRUCT_VECTOR(SQLocalVarInfo,_nlocalvarinfos,_localvarinfos);
- SQInteger size = _FUNC_SIZE(_ninstructions,_nliterals,_nparameters,_nfunctions,_noutervalues,_nlineinfos,_nlocalvarinfos,_ndefaultparams);
- this->~SQFunctionProto();
- sq_vm_free(this,size);
- }
-
- const SQChar* GetLocal(SQVM *v,SQUnsignedInteger stackbase,SQUnsignedInteger nseq,SQUnsignedInteger nop);
- SQInteger GetLine(SQInstruction *curr);
- bool Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write);
- static bool Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret);
-#ifndef NO_GARBAGE_COLLECTOR
- void Mark(SQCollectable **chain);
- void Finalize(){ _NULL_SQOBJECT_VECTOR(_literals,_nliterals); }
- SQObjectType GetType() {return OT_FUNCPROTO;}
-#endif
- SQObjectPtr _sourcename;
- SQObjectPtr _name;
- SQInteger _stacksize;
- bool _bgenerator;
- SQInteger _varparams;
-
- SQInteger _nlocalvarinfos;
- SQLocalVarInfo *_localvarinfos;
-
- SQInteger _nlineinfos;
- SQLineInfo *_lineinfos;
-
- SQInteger _nliterals;
- SQObjectPtr *_literals;
-
- SQInteger _nparameters;
- SQObjectPtr *_parameters;
-
- SQInteger _nfunctions;
- SQObjectPtr *_functions;
-
- SQInteger _noutervalues;
- SQOuterVar *_outervalues;
-
- SQInteger _ndefaultparams;
- SQInteger *_defaultparams;
-
- SQInteger _ninstructions;
- SQInstruction _instructions[1];
-};
-
-#endif //_SQFUNCTION_H_
+/* see copyright notice in squirrel.h */ +#ifndef _SQFUNCTION_H_ +#define _SQFUNCTION_H_ + +#include "sqopcodes.h" + +enum SQOuterType { + otLOCAL = 0, + otOUTER = 1 +}; + +struct SQOuterVar +{ + + SQOuterVar(){} + SQOuterVar(const SQObjectPtr &name,const SQObjectPtr &src,SQOuterType t) + { + _name = name; + _src=src; + _type=t; + } + SQOuterVar(const SQOuterVar &ov) + { + _type=ov._type; + _src=ov._src; + _name=ov._name; + } + SQOuterType _type; + SQObjectPtr _name; + SQObjectPtr _src; +}; + +struct SQLocalVarInfo +{ + SQLocalVarInfo():_start_op(0),_end_op(0),_pos(0){} + SQLocalVarInfo(const SQLocalVarInfo &lvi) + { + _name=lvi._name; + _start_op=lvi._start_op; + _end_op=lvi._end_op; + _pos=lvi._pos; + } + SQObjectPtr _name; + SQUnsignedInteger _start_op; + SQUnsignedInteger _end_op; + SQUnsignedInteger _pos; +}; + +struct SQLineInfo { SQInteger _line;SQInteger _op; }; + +typedef sqvector<SQOuterVar> SQOuterVarVec; +typedef sqvector<SQLocalVarInfo> SQLocalVarInfoVec; +typedef sqvector<SQLineInfo> SQLineInfoVec; + +#define _FUNC_SIZE(ni,nl,nparams,nfuncs,nouters,nlineinf,localinf,defparams) (sizeof(SQFunctionProto) \ + +((ni-1)*sizeof(SQInstruction))+(nl*sizeof(SQObjectPtr)) \ + +(nparams*sizeof(SQObjectPtr))+(nfuncs*sizeof(SQObjectPtr)) \ + +(nouters*sizeof(SQOuterVar))+(nlineinf*sizeof(SQLineInfo)) \ + +(localinf*sizeof(SQLocalVarInfo))+(defparams*sizeof(SQInteger))) + + +struct SQFunctionProto : public CHAINABLE_OBJ +{ +private: + SQFunctionProto(SQSharedState *ss); + ~SQFunctionProto(); + +public: + static SQFunctionProto *Create(SQSharedState *ss,SQInteger ninstructions, + SQInteger nliterals,SQInteger nparameters, + SQInteger nfunctions,SQInteger noutervalues, + SQInteger nlineinfos,SQInteger nlocalvarinfos,SQInteger ndefaultparams) + { + SQFunctionProto *f; + //I compact the whole class and members in a single memory allocation + f = (SQFunctionProto *)sq_vm_malloc(_FUNC_SIZE(ninstructions,nliterals,nparameters,nfunctions,noutervalues,nlineinfos,nlocalvarinfos,ndefaultparams)); + new (f) SQFunctionProto(ss); + f->_ninstructions = ninstructions; + f->_literals = (SQObjectPtr*)&f->_instructions[ninstructions]; + f->_nliterals = nliterals; + f->_parameters = (SQObjectPtr*)&f->_literals[nliterals]; + f->_nparameters = nparameters; + f->_functions = (SQObjectPtr*)&f->_parameters[nparameters]; + f->_nfunctions = nfunctions; + f->_outervalues = (SQOuterVar*)&f->_functions[nfunctions]; + f->_noutervalues = noutervalues; + f->_lineinfos = (SQLineInfo *)&f->_outervalues[noutervalues]; + f->_nlineinfos = nlineinfos; + f->_localvarinfos = (SQLocalVarInfo *)&f->_lineinfos[nlineinfos]; + f->_nlocalvarinfos = nlocalvarinfos; + f->_defaultparams = (SQInteger *)&f->_localvarinfos[nlocalvarinfos]; + f->_ndefaultparams = ndefaultparams; + + _CONSTRUCT_VECTOR(SQObjectPtr,f->_nliterals,f->_literals); + _CONSTRUCT_VECTOR(SQObjectPtr,f->_nparameters,f->_parameters); + _CONSTRUCT_VECTOR(SQObjectPtr,f->_nfunctions,f->_functions); + _CONSTRUCT_VECTOR(SQOuterVar,f->_noutervalues,f->_outervalues); + //_CONSTRUCT_VECTOR(SQLineInfo,f->_nlineinfos,f->_lineinfos); //not required are 2 integers + _CONSTRUCT_VECTOR(SQLocalVarInfo,f->_nlocalvarinfos,f->_localvarinfos); + return f; + } + void Release(){ + _DESTRUCT_VECTOR(SQObjectPtr,_nliterals,_literals); + _DESTRUCT_VECTOR(SQObjectPtr,_nparameters,_parameters); + _DESTRUCT_VECTOR(SQObjectPtr,_nfunctions,_functions); + _DESTRUCT_VECTOR(SQOuterVar,_noutervalues,_outervalues); + //_DESTRUCT_VECTOR(SQLineInfo,_nlineinfos,_lineinfos); //not required are 2 integers + _DESTRUCT_VECTOR(SQLocalVarInfo,_nlocalvarinfos,_localvarinfos); + SQInteger size = _FUNC_SIZE(_ninstructions,_nliterals,_nparameters,_nfunctions,_noutervalues,_nlineinfos,_nlocalvarinfos,_ndefaultparams); + this->~SQFunctionProto(); + sq_vm_free(this,size); + } + + const SQChar* GetLocal(SQVM *v,SQUnsignedInteger stackbase,SQUnsignedInteger nseq,SQUnsignedInteger nop); + SQInteger GetLine(SQInstruction *curr); + bool Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write); + static bool Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret); +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + void Finalize(){ _NULL_SQOBJECT_VECTOR(_literals,_nliterals); } + SQObjectType GetType() {return OT_FUNCPROTO;} +#endif + SQObjectPtr _sourcename; + SQObjectPtr _name; + SQInteger _stacksize; + bool _bgenerator; + SQInteger _varparams; + + SQInteger _nlocalvarinfos; + SQLocalVarInfo *_localvarinfos; + + SQInteger _nlineinfos; + SQLineInfo *_lineinfos; + + SQInteger _nliterals; + SQObjectPtr *_literals; + + SQInteger _nparameters; + SQObjectPtr *_parameters; + + SQInteger _nfunctions; + SQObjectPtr *_functions; + + SQInteger _noutervalues; + SQOuterVar *_outervalues; + + SQInteger _ndefaultparams; + SQInteger *_defaultparams; + + SQInteger _ninstructions; + SQInstruction _instructions[1]; +}; + +#endif //_SQFUNCTION_H_ diff --git a/squirrel_3_0_1_stable/squirrel/sqfuncstate.cpp b/squirrel_3_0_1_stable/squirrel/sqfuncstate.cpp index 9e236c7e7..81ec7e31c 100644 --- a/squirrel_3_0_1_stable/squirrel/sqfuncstate.cpp +++ b/squirrel_3_0_1_stable/squirrel/sqfuncstate.cpp @@ -1,652 +1,652 @@ -/*
- see copyright notice in squirrel.h
-*/
-#include "sqpcheader.h"
-#ifndef NO_COMPILER
-#include "sqcompiler.h"
-#include "sqstring.h"
-#include "sqfuncproto.h"
-#include "sqtable.h"
-#include "sqopcodes.h"
-#include "sqfuncstate.h"
-
-#ifdef _DEBUG_DUMP
-SQInstructionDesc g_InstrDesc[]={
- {_SC("_OP_LINE")},
- {_SC("_OP_LOAD")},
- {_SC("_OP_LOADINT")},
- {_SC("_OP_LOADFLOAT")},
- {_SC("_OP_DLOAD")},
- {_SC("_OP_TAILCALL")},
- {_SC("_OP_CALL")},
- {_SC("_OP_PREPCALL")},
- {_SC("_OP_PREPCALLK")},
- {_SC("_OP_GETK")},
- {_SC("_OP_MOVE")},
- {_SC("_OP_NEWSLOT")},
- {_SC("_OP_DELETE")},
- {_SC("_OP_SET")},
- {_SC("_OP_GET")},
- {_SC("_OP_EQ")},
- {_SC("_OP_NE")},
- {_SC("_OP_ADD")},
- {_SC("_OP_SUB")},
- {_SC("_OP_MUL")},
- {_SC("_OP_DIV")},
- {_SC("_OP_MOD")},
- {_SC("_OP_BITW")},
- {_SC("_OP_RETURN")},
- {_SC("_OP_LOADNULLS")},
- {_SC("_OP_LOADROOT")},
- {_SC("_OP_LOADBOOL")},
- {_SC("_OP_DMOVE")},
- {_SC("_OP_JMP")},
- {_SC("_OP_JCMP")},
- {_SC("_OP_JZ")},
- {_SC("_OP_SETOUTER")},
- {_SC("_OP_GETOUTER")},
- {_SC("_OP_NEWOBJ")},
- {_SC("_OP_APPENDARRAY")},
- {_SC("_OP_COMPARITH")},
- {_SC("_OP_INC")},
- {_SC("_OP_INCL")},
- {_SC("_OP_PINC")},
- {_SC("_OP_PINCL")},
- {_SC("_OP_CMP")},
- {_SC("_OP_EXISTS")},
- {_SC("_OP_INSTANCEOF")},
- {_SC("_OP_AND")},
- {_SC("_OP_OR")},
- {_SC("_OP_NEG")},
- {_SC("_OP_NOT")},
- {_SC("_OP_BWNOT")},
- {_SC("_OP_CLOSURE")},
- {_SC("_OP_YIELD")},
- {_SC("_OP_RESUME")},
- {_SC("_OP_FOREACH")},
- {_SC("_OP_POSTFOREACH")},
- {_SC("_OP_CLONE")},
- {_SC("_OP_TYPEOF")},
- {_SC("_OP_PUSHTRAP")},
- {_SC("_OP_POPTRAP")},
- {_SC("_OP_THROW")},
- {_SC("_OP_NEWSLOTA")},
- {_SC("_OP_GETBASE")},
- {_SC("_OP_CLOSE")},
- {_SC("_OP_JCMP")}
-};
-#endif
-void DumpLiteral(SQObjectPtr &o)
-{
- switch(type(o)){
- case OT_STRING: scprintf(_SC("\"%s\""),_stringval(o));break;
- case OT_FLOAT: scprintf(_SC("{%f}"),_float(o));break;
- case OT_INTEGER: scprintf(_SC("{") _PRINT_INT_FMT _SC("}"),_integer(o));break;
- case OT_BOOL: scprintf(_SC("%s"),_integer(o)?_SC("true"):_SC("false"));break;
- default: scprintf(_SC("(%s %p)"),GetTypeName(o),(void*)_rawval(o));break; break; //shut up compiler
- }
-}
-
-SQFuncState::SQFuncState(SQSharedState *ss,SQFuncState *parent,CompilerErrorFunc efunc,void *ed)
-{
- _nliterals = 0;
- _literals = SQTable::Create(ss,0);
- _strings = SQTable::Create(ss,0);
- _sharedstate = ss;
- _lastline = 0;
- _optimization = true;
- _parent = parent;
- _stacksize = 0;
- _traps = 0;
- _returnexp = 0;
- _varparams = false;
- _errfunc = efunc;
- _errtarget = ed;
- _bgenerator = false;
- _outers = 0;
- _ss = ss;
-
-}
-
-void SQFuncState::Error(const SQChar *err)
-{
- _errfunc(_errtarget,err);
-}
-
-#ifdef _DEBUG_DUMP
-void SQFuncState::Dump(SQFunctionProto *func)
-{
- SQUnsignedInteger n=0,i;
- SQInteger si;
- scprintf(_SC("SQInstruction sizeof %d\n"),sizeof(SQInstruction));
- scprintf(_SC("SQObject sizeof %d\n"),sizeof(SQObject));
- scprintf(_SC("--------------------------------------------------------------------\n"));
- scprintf(_SC("*****FUNCTION [%s]\n"),type(func->_name)==OT_STRING?_stringval(func->_name):_SC("unknown"));
- scprintf(_SC("-----LITERALS\n"));
- SQObjectPtr refidx,key,val;
- SQInteger idx;
- SQObjectPtrVec templiterals;
- templiterals.resize(_nliterals);
- while((idx=_table(_literals)->Next(false,refidx,key,val))!=-1) {
- refidx=idx;
- templiterals[_integer(val)]=key;
- }
- for(i=0;i<templiterals.size();i++){
- scprintf(_SC("[%d] "),n);
- DumpLiteral(templiterals[i]);
- scprintf(_SC("\n"));
- n++;
- }
- scprintf(_SC("-----PARAMS\n"));
- if(_varparams)
- scprintf(_SC("<<VARPARAMS>>\n"));
- n=0;
- for(i=0;i<_parameters.size();i++){
- scprintf(_SC("[%d] "),n);
- DumpLiteral(_parameters[i]);
- scprintf(_SC("\n"));
- n++;
- }
- scprintf(_SC("-----LOCALS\n"));
- for(si=0;si<func->_nlocalvarinfos;si++){
- SQLocalVarInfo lvi=func->_localvarinfos[si];
- scprintf(_SC("[%d] %s \t%d %d\n"),lvi._pos,_stringval(lvi._name),lvi._start_op,lvi._end_op);
- n++;
- }
- scprintf(_SC("-----LINE INFO\n"));
- for(i=0;i<_lineinfos.size();i++){
- SQLineInfo li=_lineinfos[i];
- scprintf(_SC("op [%d] line [%d] \n"),li._op,li._line);
- n++;
- }
- scprintf(_SC("-----dump\n"));
- n=0;
- for(i=0;i<_instructions.size();i++){
- SQInstruction &inst=_instructions[i];
- if(inst.op==_OP_LOAD || inst.op==_OP_DLOAD || inst.op==_OP_PREPCALLK || inst.op==_OP_GETK ){
-
- SQInteger lidx = inst._arg1;
- scprintf(_SC("[%03d] %15s %d "),n,g_InstrDesc[inst.op].name,inst._arg0);
- if(lidx >= 0xFFFFFFFF)
- scprintf(_SC("null"));
- else {
- SQInteger refidx;
- SQObjectPtr val,key,refo;
- while(((refidx=_table(_literals)->Next(false,refo,key,val))!= -1) && (_integer(val) != lidx)) {
- refo = refidx;
- }
- DumpLiteral(key);
- }
- if(inst.op != _OP_DLOAD) {
- scprintf(_SC(" %d %d \n"),inst._arg2,inst._arg3);
- }
- else {
- scprintf(_SC(" %d "),inst._arg2);
- lidx = inst._arg3;
- if(lidx >= 0xFFFFFFFF)
- scprintf(_SC("null"));
- else {
- SQInteger refidx;
- SQObjectPtr val,key,refo;
- while(((refidx=_table(_literals)->Next(false,refo,key,val))!= -1) && (_integer(val) != lidx)) {
- refo = refidx;
- }
- DumpLiteral(key);
- scprintf(_SC("\n"));
- }
- }
- }
- else if(inst.op==_OP_LOADFLOAT) {
- scprintf(_SC("[%03d] %15s %d %f %d %d\n"),n,g_InstrDesc[inst.op].name,inst._arg0,*((SQFloat*)&inst._arg1),inst._arg2,inst._arg3);
- }
- /* else if(inst.op==_OP_ARITH){
- scprintf(_SC("[%03d] %15s %d %d %d %c\n"),n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3);
- }*/
- else {
- scprintf(_SC("[%03d] %15s %d %d %d %d\n"),n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3);
- }
- n++;
- }
- scprintf(_SC("-----\n"));
- scprintf(_SC("stack size[%d]\n"),func->_stacksize);
- scprintf(_SC("--------------------------------------------------------------------\n\n"));
-}
-#endif
-
-SQInteger SQFuncState::GetNumericConstant(const SQInteger cons)
-{
- return GetConstant(SQObjectPtr(cons));
-}
-
-SQInteger SQFuncState::GetNumericConstant(const SQFloat cons)
-{
- return GetConstant(SQObjectPtr(cons));
-}
-
-SQInteger SQFuncState::GetConstant(const SQObject &cons)
-{
- SQObjectPtr val;
- if(!_table(_literals)->Get(cons,val))
- {
- val = _nliterals;
- _table(_literals)->NewSlot(cons,val);
- _nliterals++;
- if(_nliterals > MAX_LITERALS) {
- val.Null();
- Error(_SC("internal compiler error: too many literals"));
- }
- }
- return _integer(val);
-}
-
-void SQFuncState::SetIntructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2,SQInteger arg3)
-{
- _instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&arg0);
- _instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&arg1);
- _instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&arg2);
- _instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&arg3);
-}
-
-void SQFuncState::SetIntructionParam(SQInteger pos,SQInteger arg,SQInteger val)
-{
- switch(arg){
- case 0:_instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&val);break;
- case 1:case 4:_instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&val);break;
- case 2:_instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&val);break;
- case 3:_instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&val);break;
- };
-}
-
-SQInteger SQFuncState::AllocStackPos()
-{
- SQInteger npos=_vlocals.size();
- _vlocals.push_back(SQLocalVarInfo());
- if(_vlocals.size()>((SQUnsignedInteger)_stacksize)) {
- if(_stacksize>MAX_FUNC_STACKSIZE) Error(_SC("internal compiler error: too many locals"));
- _stacksize=_vlocals.size();
- }
- return npos;
-}
-
-SQInteger SQFuncState::PushTarget(SQInteger n)
-{
- if(n!=-1){
- _targetstack.push_back(n);
- return n;
- }
- n=AllocStackPos();
- _targetstack.push_back(n);
- return n;
-}
-
-SQInteger SQFuncState::GetUpTarget(SQInteger n){
- return _targetstack[((_targetstack.size()-1)-n)];
-}
-
-SQInteger SQFuncState::TopTarget(){
- return _targetstack.back();
-}
-SQInteger SQFuncState::PopTarget()
-{
- SQInteger npos=_targetstack.back();
- SQLocalVarInfo &t=_vlocals[_targetstack.back()];
- if(type(t._name)==OT_NULL){
- _vlocals.pop_back();
- }
- _targetstack.pop_back();
- return npos;
-}
-
-SQInteger SQFuncState::GetStackSize()
-{
- return _vlocals.size();
-}
-
-SQInteger SQFuncState::CountOuters(SQInteger stacksize)
-{
- SQInteger outers = 0;
- SQInteger k = _vlocals.size() - 1;
- while(k >= stacksize) {
- SQLocalVarInfo &lvi = _vlocals[k];
- k--;
- if(lvi._end_op == UINT_MINUS_ONE) { //this means is an outer
- outers++;
- }
- }
- return outers;
-}
-
-void SQFuncState::SetStackSize(SQInteger n)
-{
- SQInteger size=_vlocals.size();
- while(size>n){
- size--;
- SQLocalVarInfo lvi = _vlocals.back();
- if(type(lvi._name)!=OT_NULL){
- if(lvi._end_op == UINT_MINUS_ONE) { //this means is an outer
- _outers--;
- }
- lvi._end_op = GetCurrentPos();
- _localvarinfos.push_back(lvi);
- }
- _vlocals.pop_back();
- }
-}
-
-bool SQFuncState::IsConstant(const SQObject &name,SQObject &e)
-{
- SQObjectPtr val;
- if(_table(_sharedstate->_consts)->Get(name,val)) {
- e = val;
- return true;
- }
- return false;
-}
-
-bool SQFuncState::IsLocal(SQUnsignedInteger stkpos)
-{
- if(stkpos>=_vlocals.size())return false;
- else if(type(_vlocals[stkpos]._name)!=OT_NULL)return true;
- return false;
-}
-
-SQInteger SQFuncState::PushLocalVariable(const SQObject &name)
-{
- SQInteger pos=_vlocals.size();
- SQLocalVarInfo lvi;
- lvi._name=name;
- lvi._start_op=GetCurrentPos()+1;
- lvi._pos=_vlocals.size();
- _vlocals.push_back(lvi);
- if(_vlocals.size()>((SQUnsignedInteger)_stacksize))_stacksize=_vlocals.size();
- return pos;
-}
-
-
-
-SQInteger SQFuncState::GetLocalVariable(const SQObject &name)
-{
- SQInteger locals=_vlocals.size();
- while(locals>=1){
- SQLocalVarInfo &lvi = _vlocals[locals-1];
- if(type(lvi._name)==OT_STRING && _string(lvi._name)==_string(name)){
- return locals-1;
- }
- locals--;
- }
- return -1;
-}
-
-void SQFuncState::MarkLocalAsOuter(SQInteger pos)
-{
- SQLocalVarInfo &lvi = _vlocals[pos];
- lvi._end_op = UINT_MINUS_ONE;
- _outers++;
-}
-
-SQInteger SQFuncState::GetOuterVariable(const SQObject &name)
-{
- SQInteger outers = _outervalues.size();
- for(SQInteger i = 0; i<outers; i++) {
- if(_string(_outervalues[i]._name) == _string(name))
- return i;
- }
- SQInteger pos=-1;
- if(_parent) {
- pos = _parent->GetLocalVariable(name);
- if(pos == -1) {
- pos = _parent->GetOuterVariable(name);
- if(pos != -1) {
- _outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otOUTER)); //local
- return _outervalues.size() - 1;
- }
- }
- else {
- _parent->MarkLocalAsOuter(pos);
- _outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otLOCAL)); //local
- return _outervalues.size() - 1;
-
-
- }
- }
- return -1;
-}
-
-void SQFuncState::AddParameter(const SQObject &name)
-{
- PushLocalVariable(name);
- _parameters.push_back(name);
-}
-
-void SQFuncState::AddLineInfos(SQInteger line,bool lineop,bool force)
-{
- if(_lastline!=line || force){
- SQLineInfo li;
- li._line=line;li._op=(GetCurrentPos()+1);
- if(lineop)AddInstruction(_OP_LINE,0,line);
- if(_lastline!=line) {
- _lineinfos.push_back(li);
- }
- _lastline=line;
- }
-}
-
-void SQFuncState::DiscardTarget()
-{
- SQInteger discardedtarget = PopTarget();
- SQInteger size = _instructions.size();
- if(size > 0 && _optimization){
- SQInstruction &pi = _instructions[size-1];//previous instruction
- switch(pi.op) {
- case _OP_SET:case _OP_NEWSLOT:case _OP_SETOUTER:case _OP_CALL:
- if(pi._arg0 == discardedtarget) {
- pi._arg0 = 0xFF;
- }
- }
- }
-}
-
-void SQFuncState::AddInstruction(SQInstruction &i)
-{
- SQInteger size = _instructions.size();
- if(size > 0 && _optimization){ //simple optimizer
- SQInstruction &pi = _instructions[size-1];//previous instruction
- switch(i.op) {
- case _OP_JZ:
- if( pi.op == _OP_CMP && pi._arg1 < 0xFF) {
- pi.op = _OP_JCMP;
- pi._arg0 = (unsigned char)pi._arg1;
- pi._arg1 = i._arg1;
- return;
- }
- case _OP_SET:
- case _OP_NEWSLOT:
- if(i._arg0 == i._arg3) {
- i._arg0 = 0xFF;
- }
- break;
- case _OP_SETOUTER:
- if(i._arg0 == i._arg2) {
- i._arg0 = 0xFF;
- }
- break;
- case _OP_RETURN:
- if( _parent && i._arg0 != MAX_FUNC_STACKSIZE && pi.op == _OP_CALL && _returnexp < size-1) {
- pi.op = _OP_TAILCALL;
- } else if(pi.op == _OP_CLOSE){
- pi = i;
- return;
- }
- break;
- case _OP_GET:
- if( pi.op == _OP_LOAD && pi._arg0 == i._arg2 && (!IsLocal(pi._arg0))){
- pi._arg1 = pi._arg1;
- pi._arg2 = (unsigned char)i._arg1;
- pi.op = _OP_GETK;
- pi._arg0 = i._arg0;
-
- return;
- }
- break;
- case _OP_PREPCALL:
- if( pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){
- pi.op = _OP_PREPCALLK;
- pi._arg0 = i._arg0;
- pi._arg1 = pi._arg1;
- pi._arg2 = i._arg2;
- pi._arg3 = i._arg3;
- return;
- }
- break;
- case _OP_APPENDARRAY: {
- SQInteger aat = -1;
- switch(pi.op) {
- case _OP_LOAD: aat = AAT_LITERAL; break;
- case _OP_LOADINT: aat = AAT_INT; break;
- case _OP_LOADBOOL: aat = AAT_BOOL; break;
- case _OP_LOADFLOAT: aat = AAT_FLOAT; break;
- default: break;
- }
- if(aat != -1 && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){
- pi.op = _OP_APPENDARRAY;
- pi._arg0 = i._arg0;
- pi._arg1 = pi._arg1;
- pi._arg2 = (unsigned char)aat;
- pi._arg3 = MAX_FUNC_STACKSIZE;
- return;
- }
- }
- break;
- case _OP_MOVE:
- switch(pi.op) {
- case _OP_GET: case _OP_ADD: case _OP_SUB: case _OP_MUL: case _OP_DIV: case _OP_MOD: case _OP_BITW:
- case _OP_LOADINT: case _OP_LOADFLOAT: case _OP_LOADBOOL: case _OP_LOAD:
-
- if(pi._arg0 == i._arg1)
- {
- pi._arg0 = i._arg0;
- _optimization = false;
- //_result_elimination = false;
- return;
- }
- }
-
- if(pi.op == _OP_MOVE)
- {
- pi.op = _OP_DMOVE;
- pi._arg2 = i._arg0;
- pi._arg3 = (unsigned char)i._arg1;
- return;
- }
- break;
- case _OP_LOAD:
- if(pi.op == _OP_LOAD && i._arg1 < 256) {
- pi.op = _OP_DLOAD;
- pi._arg2 = i._arg0;
- pi._arg3 = (unsigned char)i._arg1;
- return;
- }
- break;
- case _OP_EQ:case _OP_NE:
- if(pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0) ))
- {
- pi.op = i.op;
- pi._arg0 = i._arg0;
- pi._arg1 = pi._arg1;
- pi._arg2 = i._arg2;
- pi._arg3 = MAX_FUNC_STACKSIZE;
- return;
- }
- break;
- case _OP_LOADNULLS:
- if((pi.op == _OP_LOADNULLS && pi._arg0+pi._arg1 == i._arg0)) {
-
- pi._arg1 = pi._arg1 + 1;
- pi.op = _OP_LOADNULLS;
- return;
- }
- break;
- case _OP_LINE:
- if(pi.op == _OP_LINE) {
- _instructions.pop_back();
- _lineinfos.pop_back();
- }
- break;
- }
- }
- _optimization = true;
- _instructions.push_back(i);
-}
-
-SQObject SQFuncState::CreateString(const SQChar *s,SQInteger len)
-{
- SQObjectPtr ns(SQString::Create(_sharedstate,s,len));
- _table(_strings)->NewSlot(ns,(SQInteger)1);
- return ns;
-}
-
-SQObject SQFuncState::CreateTable()
-{
- SQObjectPtr nt(SQTable::Create(_sharedstate,0));
- _table(_strings)->NewSlot(nt,(SQInteger)1);
- return nt;
-}
-
-SQFunctionProto *SQFuncState::BuildProto()
-{
-
- SQFunctionProto *f=SQFunctionProto::Create(_ss,_instructions.size(),
- _nliterals,_parameters.size(),_functions.size(),_outervalues.size(),
- _lineinfos.size(),_localvarinfos.size(),_defaultparams.size());
-
- SQObjectPtr refidx,key,val;
- SQInteger idx;
-
- f->_stacksize = _stacksize;
- f->_sourcename = _sourcename;
- f->_bgenerator = _bgenerator;
- f->_name = _name;
-
- while((idx=_table(_literals)->Next(false,refidx,key,val))!=-1) {
- f->_literals[_integer(val)]=key;
- refidx=idx;
- }
-
- for(SQUnsignedInteger nf = 0; nf < _functions.size(); nf++) f->_functions[nf] = _functions[nf];
- for(SQUnsignedInteger np = 0; np < _parameters.size(); np++) f->_parameters[np] = _parameters[np];
- for(SQUnsignedInteger no = 0; no < _outervalues.size(); no++) f->_outervalues[no] = _outervalues[no];
- for(SQUnsignedInteger nl = 0; nl < _localvarinfos.size(); nl++) f->_localvarinfos[nl] = _localvarinfos[nl];
- for(SQUnsignedInteger ni = 0; ni < _lineinfos.size(); ni++) f->_lineinfos[ni] = _lineinfos[ni];
- for(SQUnsignedInteger nd = 0; nd < _defaultparams.size(); nd++) f->_defaultparams[nd] = _defaultparams[nd];
-
- memcpy(f->_instructions,&_instructions[0],_instructions.size()*sizeof(SQInstruction));
-
- f->_varparams = _varparams;
-
- return f;
-}
-
-SQFuncState *SQFuncState::PushChildState(SQSharedState *ss)
-{
- SQFuncState *child = (SQFuncState *)sq_malloc(sizeof(SQFuncState));
- new (child) SQFuncState(ss,this,_errfunc,_errtarget);
- _childstates.push_back(child);
- return child;
-}
-
-void SQFuncState::PopChildState()
-{
- SQFuncState *child = _childstates.back();
- sq_delete(child,SQFuncState);
- _childstates.pop_back();
-}
-
-SQFuncState::~SQFuncState()
-{
- while(_childstates.size() > 0)
- {
- PopChildState();
- }
-}
-
-#endif
+/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#ifndef NO_COMPILER +#include "sqcompiler.h" +#include "sqstring.h" +#include "sqfuncproto.h" +#include "sqtable.h" +#include "sqopcodes.h" +#include "sqfuncstate.h" + +#ifdef _DEBUG_DUMP +SQInstructionDesc g_InstrDesc[]={ + {_SC("_OP_LINE")}, + {_SC("_OP_LOAD")}, + {_SC("_OP_LOADINT")}, + {_SC("_OP_LOADFLOAT")}, + {_SC("_OP_DLOAD")}, + {_SC("_OP_TAILCALL")}, + {_SC("_OP_CALL")}, + {_SC("_OP_PREPCALL")}, + {_SC("_OP_PREPCALLK")}, + {_SC("_OP_GETK")}, + {_SC("_OP_MOVE")}, + {_SC("_OP_NEWSLOT")}, + {_SC("_OP_DELETE")}, + {_SC("_OP_SET")}, + {_SC("_OP_GET")}, + {_SC("_OP_EQ")}, + {_SC("_OP_NE")}, + {_SC("_OP_ADD")}, + {_SC("_OP_SUB")}, + {_SC("_OP_MUL")}, + {_SC("_OP_DIV")}, + {_SC("_OP_MOD")}, + {_SC("_OP_BITW")}, + {_SC("_OP_RETURN")}, + {_SC("_OP_LOADNULLS")}, + {_SC("_OP_LOADROOT")}, + {_SC("_OP_LOADBOOL")}, + {_SC("_OP_DMOVE")}, + {_SC("_OP_JMP")}, + {_SC("_OP_JCMP")}, + {_SC("_OP_JZ")}, + {_SC("_OP_SETOUTER")}, + {_SC("_OP_GETOUTER")}, + {_SC("_OP_NEWOBJ")}, + {_SC("_OP_APPENDARRAY")}, + {_SC("_OP_COMPARITH")}, + {_SC("_OP_INC")}, + {_SC("_OP_INCL")}, + {_SC("_OP_PINC")}, + {_SC("_OP_PINCL")}, + {_SC("_OP_CMP")}, + {_SC("_OP_EXISTS")}, + {_SC("_OP_INSTANCEOF")}, + {_SC("_OP_AND")}, + {_SC("_OP_OR")}, + {_SC("_OP_NEG")}, + {_SC("_OP_NOT")}, + {_SC("_OP_BWNOT")}, + {_SC("_OP_CLOSURE")}, + {_SC("_OP_YIELD")}, + {_SC("_OP_RESUME")}, + {_SC("_OP_FOREACH")}, + {_SC("_OP_POSTFOREACH")}, + {_SC("_OP_CLONE")}, + {_SC("_OP_TYPEOF")}, + {_SC("_OP_PUSHTRAP")}, + {_SC("_OP_POPTRAP")}, + {_SC("_OP_THROW")}, + {_SC("_OP_NEWSLOTA")}, + {_SC("_OP_GETBASE")}, + {_SC("_OP_CLOSE")}, + {_SC("_OP_JCMP")} +}; +#endif +void DumpLiteral(SQObjectPtr &o) +{ + switch(type(o)){ + case OT_STRING: scprintf(_SC("\"%s\""),_stringval(o));break; + case OT_FLOAT: scprintf(_SC("{%f}"),_float(o));break; + case OT_INTEGER: scprintf(_SC("{") _PRINT_INT_FMT _SC("}"),_integer(o));break; + case OT_BOOL: scprintf(_SC("%s"),_integer(o)?_SC("true"):_SC("false"));break; + default: scprintf(_SC("(%s %p)"),GetTypeName(o),(void*)_rawval(o));break; break; //shut up compiler + } +} + +SQFuncState::SQFuncState(SQSharedState *ss,SQFuncState *parent,CompilerErrorFunc efunc,void *ed) +{ + _nliterals = 0; + _literals = SQTable::Create(ss,0); + _strings = SQTable::Create(ss,0); + _sharedstate = ss; + _lastline = 0; + _optimization = true; + _parent = parent; + _stacksize = 0; + _traps = 0; + _returnexp = 0; + _varparams = false; + _errfunc = efunc; + _errtarget = ed; + _bgenerator = false; + _outers = 0; + _ss = ss; + +} + +void SQFuncState::Error(const SQChar *err) +{ + _errfunc(_errtarget,err); +} + +#ifdef _DEBUG_DUMP +void SQFuncState::Dump(SQFunctionProto *func) +{ + SQUnsignedInteger n=0,i; + SQInteger si; + scprintf(_SC("SQInstruction sizeof %d\n"),sizeof(SQInstruction)); + scprintf(_SC("SQObject sizeof %d\n"),sizeof(SQObject)); + scprintf(_SC("--------------------------------------------------------------------\n")); + scprintf(_SC("*****FUNCTION [%s]\n"),type(func->_name)==OT_STRING?_stringval(func->_name):_SC("unknown")); + scprintf(_SC("-----LITERALS\n")); + SQObjectPtr refidx,key,val; + SQInteger idx; + SQObjectPtrVec templiterals; + templiterals.resize(_nliterals); + while((idx=_table(_literals)->Next(false,refidx,key,val))!=-1) { + refidx=idx; + templiterals[_integer(val)]=key; + } + for(i=0;i<templiterals.size();i++){ + scprintf(_SC("[%d] "),n); + DumpLiteral(templiterals[i]); + scprintf(_SC("\n")); + n++; + } + scprintf(_SC("-----PARAMS\n")); + if(_varparams) + scprintf(_SC("<<VARPARAMS>>\n")); + n=0; + for(i=0;i<_parameters.size();i++){ + scprintf(_SC("[%d] "),n); + DumpLiteral(_parameters[i]); + scprintf(_SC("\n")); + n++; + } + scprintf(_SC("-----LOCALS\n")); + for(si=0;si<func->_nlocalvarinfos;si++){ + SQLocalVarInfo lvi=func->_localvarinfos[si]; + scprintf(_SC("[%d] %s \t%d %d\n"),lvi._pos,_stringval(lvi._name),lvi._start_op,lvi._end_op); + n++; + } + scprintf(_SC("-----LINE INFO\n")); + for(i=0;i<_lineinfos.size();i++){ + SQLineInfo li=_lineinfos[i]; + scprintf(_SC("op [%d] line [%d] \n"),li._op,li._line); + n++; + } + scprintf(_SC("-----dump\n")); + n=0; + for(i=0;i<_instructions.size();i++){ + SQInstruction &inst=_instructions[i]; + if(inst.op==_OP_LOAD || inst.op==_OP_DLOAD || inst.op==_OP_PREPCALLK || inst.op==_OP_GETK ){ + + SQInteger lidx = inst._arg1; + scprintf(_SC("[%03d] %15s %d "),n,g_InstrDesc[inst.op].name,inst._arg0); + if(lidx >= 0xFFFFFFFF) + scprintf(_SC("null")); + else { + SQInteger refidx; + SQObjectPtr val,key,refo; + while(((refidx=_table(_literals)->Next(false,refo,key,val))!= -1) && (_integer(val) != lidx)) { + refo = refidx; + } + DumpLiteral(key); + } + if(inst.op != _OP_DLOAD) { + scprintf(_SC(" %d %d \n"),inst._arg2,inst._arg3); + } + else { + scprintf(_SC(" %d "),inst._arg2); + lidx = inst._arg3; + if(lidx >= 0xFFFFFFFF) + scprintf(_SC("null")); + else { + SQInteger refidx; + SQObjectPtr val,key,refo; + while(((refidx=_table(_literals)->Next(false,refo,key,val))!= -1) && (_integer(val) != lidx)) { + refo = refidx; + } + DumpLiteral(key); + scprintf(_SC("\n")); + } + } + } + else if(inst.op==_OP_LOADFLOAT) { + scprintf(_SC("[%03d] %15s %d %f %d %d\n"),n,g_InstrDesc[inst.op].name,inst._arg0,*((SQFloat*)&inst._arg1),inst._arg2,inst._arg3); + } + /* else if(inst.op==_OP_ARITH){ + scprintf(_SC("[%03d] %15s %d %d %d %c\n"),n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3); + }*/ + else { + scprintf(_SC("[%03d] %15s %d %d %d %d\n"),n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3); + } + n++; + } + scprintf(_SC("-----\n")); + scprintf(_SC("stack size[%d]\n"),func->_stacksize); + scprintf(_SC("--------------------------------------------------------------------\n\n")); +} +#endif + +SQInteger SQFuncState::GetNumericConstant(const SQInteger cons) +{ + return GetConstant(SQObjectPtr(cons)); +} + +SQInteger SQFuncState::GetNumericConstant(const SQFloat cons) +{ + return GetConstant(SQObjectPtr(cons)); +} + +SQInteger SQFuncState::GetConstant(const SQObject &cons) +{ + SQObjectPtr val; + if(!_table(_literals)->Get(cons,val)) + { + val = _nliterals; + _table(_literals)->NewSlot(cons,val); + _nliterals++; + if(_nliterals > MAX_LITERALS) { + val.Null(); + Error(_SC("internal compiler error: too many literals")); + } + } + return _integer(val); +} + +void SQFuncState::SetIntructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2,SQInteger arg3) +{ + _instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&arg0); + _instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&arg1); + _instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&arg2); + _instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&arg3); +} + +void SQFuncState::SetIntructionParam(SQInteger pos,SQInteger arg,SQInteger val) +{ + switch(arg){ + case 0:_instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&val);break; + case 1:case 4:_instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&val);break; + case 2:_instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&val);break; + case 3:_instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&val);break; + }; +} + +SQInteger SQFuncState::AllocStackPos() +{ + SQInteger npos=_vlocals.size(); + _vlocals.push_back(SQLocalVarInfo()); + if(_vlocals.size()>((SQUnsignedInteger)_stacksize)) { + if(_stacksize>MAX_FUNC_STACKSIZE) Error(_SC("internal compiler error: too many locals")); + _stacksize=_vlocals.size(); + } + return npos; +} + +SQInteger SQFuncState::PushTarget(SQInteger n) +{ + if(n!=-1){ + _targetstack.push_back(n); + return n; + } + n=AllocStackPos(); + _targetstack.push_back(n); + return n; +} + +SQInteger SQFuncState::GetUpTarget(SQInteger n){ + return _targetstack[((_targetstack.size()-1)-n)]; +} + +SQInteger SQFuncState::TopTarget(){ + return _targetstack.back(); +} +SQInteger SQFuncState::PopTarget() +{ + SQInteger npos=_targetstack.back(); + SQLocalVarInfo &t=_vlocals[_targetstack.back()]; + if(type(t._name)==OT_NULL){ + _vlocals.pop_back(); + } + _targetstack.pop_back(); + return npos; +} + +SQInteger SQFuncState::GetStackSize() +{ + return _vlocals.size(); +} + +SQInteger SQFuncState::CountOuters(SQInteger stacksize) +{ + SQInteger outers = 0; + SQInteger k = _vlocals.size() - 1; + while(k >= stacksize) { + SQLocalVarInfo &lvi = _vlocals[k]; + k--; + if(lvi._end_op == UINT_MINUS_ONE) { //this means is an outer + outers++; + } + } + return outers; +} + +void SQFuncState::SetStackSize(SQInteger n) +{ + SQInteger size=_vlocals.size(); + while(size>n){ + size--; + SQLocalVarInfo lvi = _vlocals.back(); + if(type(lvi._name)!=OT_NULL){ + if(lvi._end_op == UINT_MINUS_ONE) { //this means is an outer + _outers--; + } + lvi._end_op = GetCurrentPos(); + _localvarinfos.push_back(lvi); + } + _vlocals.pop_back(); + } +} + +bool SQFuncState::IsConstant(const SQObject &name,SQObject &e) +{ + SQObjectPtr val; + if(_table(_sharedstate->_consts)->Get(name,val)) { + e = val; + return true; + } + return false; +} + +bool SQFuncState::IsLocal(SQUnsignedInteger stkpos) +{ + if(stkpos>=_vlocals.size())return false; + else if(type(_vlocals[stkpos]._name)!=OT_NULL)return true; + return false; +} + +SQInteger SQFuncState::PushLocalVariable(const SQObject &name) +{ + SQInteger pos=_vlocals.size(); + SQLocalVarInfo lvi; + lvi._name=name; + lvi._start_op=GetCurrentPos()+1; + lvi._pos=_vlocals.size(); + _vlocals.push_back(lvi); + if(_vlocals.size()>((SQUnsignedInteger)_stacksize))_stacksize=_vlocals.size(); + return pos; +} + + + +SQInteger SQFuncState::GetLocalVariable(const SQObject &name) +{ + SQInteger locals=_vlocals.size(); + while(locals>=1){ + SQLocalVarInfo &lvi = _vlocals[locals-1]; + if(type(lvi._name)==OT_STRING && _string(lvi._name)==_string(name)){ + return locals-1; + } + locals--; + } + return -1; +} + +void SQFuncState::MarkLocalAsOuter(SQInteger pos) +{ + SQLocalVarInfo &lvi = _vlocals[pos]; + lvi._end_op = UINT_MINUS_ONE; + _outers++; +} + +SQInteger SQFuncState::GetOuterVariable(const SQObject &name) +{ + SQInteger outers = _outervalues.size(); + for(SQInteger i = 0; i<outers; i++) { + if(_string(_outervalues[i]._name) == _string(name)) + return i; + } + SQInteger pos=-1; + if(_parent) { + pos = _parent->GetLocalVariable(name); + if(pos == -1) { + pos = _parent->GetOuterVariable(name); + if(pos != -1) { + _outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otOUTER)); //local + return _outervalues.size() - 1; + } + } + else { + _parent->MarkLocalAsOuter(pos); + _outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otLOCAL)); //local + return _outervalues.size() - 1; + + + } + } + return -1; +} + +void SQFuncState::AddParameter(const SQObject &name) +{ + PushLocalVariable(name); + _parameters.push_back(name); +} + +void SQFuncState::AddLineInfos(SQInteger line,bool lineop,bool force) +{ + if(_lastline!=line || force){ + SQLineInfo li; + li._line=line;li._op=(GetCurrentPos()+1); + if(lineop)AddInstruction(_OP_LINE,0,line); + if(_lastline!=line) { + _lineinfos.push_back(li); + } + _lastline=line; + } +} + +void SQFuncState::DiscardTarget() +{ + SQInteger discardedtarget = PopTarget(); + SQInteger size = _instructions.size(); + if(size > 0 && _optimization){ + SQInstruction &pi = _instructions[size-1];//previous instruction + switch(pi.op) { + case _OP_SET:case _OP_NEWSLOT:case _OP_SETOUTER:case _OP_CALL: + if(pi._arg0 == discardedtarget) { + pi._arg0 = 0xFF; + } + } + } +} + +void SQFuncState::AddInstruction(SQInstruction &i) +{ + SQInteger size = _instructions.size(); + if(size > 0 && _optimization){ //simple optimizer + SQInstruction &pi = _instructions[size-1];//previous instruction + switch(i.op) { + case _OP_JZ: + if( pi.op == _OP_CMP && pi._arg1 < 0xFF) { + pi.op = _OP_JCMP; + pi._arg0 = (unsigned char)pi._arg1; + pi._arg1 = i._arg1; + return; + } + case _OP_SET: + case _OP_NEWSLOT: + if(i._arg0 == i._arg3) { + i._arg0 = 0xFF; + } + break; + case _OP_SETOUTER: + if(i._arg0 == i._arg2) { + i._arg0 = 0xFF; + } + break; + case _OP_RETURN: + if( _parent && i._arg0 != MAX_FUNC_STACKSIZE && pi.op == _OP_CALL && _returnexp < size-1) { + pi.op = _OP_TAILCALL; + } else if(pi.op == _OP_CLOSE){ + pi = i; + return; + } + break; + case _OP_GET: + if( pi.op == _OP_LOAD && pi._arg0 == i._arg2 && (!IsLocal(pi._arg0))){ + pi._arg1 = pi._arg1; + pi._arg2 = (unsigned char)i._arg1; + pi.op = _OP_GETK; + pi._arg0 = i._arg0; + + return; + } + break; + case _OP_PREPCALL: + if( pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){ + pi.op = _OP_PREPCALLK; + pi._arg0 = i._arg0; + pi._arg1 = pi._arg1; + pi._arg2 = i._arg2; + pi._arg3 = i._arg3; + return; + } + break; + case _OP_APPENDARRAY: { + SQInteger aat = -1; + switch(pi.op) { + case _OP_LOAD: aat = AAT_LITERAL; break; + case _OP_LOADINT: aat = AAT_INT; break; + case _OP_LOADBOOL: aat = AAT_BOOL; break; + case _OP_LOADFLOAT: aat = AAT_FLOAT; break; + default: break; + } + if(aat != -1 && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){ + pi.op = _OP_APPENDARRAY; + pi._arg0 = i._arg0; + pi._arg1 = pi._arg1; + pi._arg2 = (unsigned char)aat; + pi._arg3 = MAX_FUNC_STACKSIZE; + return; + } + } + break; + case _OP_MOVE: + switch(pi.op) { + case _OP_GET: case _OP_ADD: case _OP_SUB: case _OP_MUL: case _OP_DIV: case _OP_MOD: case _OP_BITW: + case _OP_LOADINT: case _OP_LOADFLOAT: case _OP_LOADBOOL: case _OP_LOAD: + + if(pi._arg0 == i._arg1) + { + pi._arg0 = i._arg0; + _optimization = false; + //_result_elimination = false; + return; + } + } + + if(pi.op == _OP_MOVE) + { + pi.op = _OP_DMOVE; + pi._arg2 = i._arg0; + pi._arg3 = (unsigned char)i._arg1; + return; + } + break; + case _OP_LOAD: + if(pi.op == _OP_LOAD && i._arg1 < 256) { + pi.op = _OP_DLOAD; + pi._arg2 = i._arg0; + pi._arg3 = (unsigned char)i._arg1; + return; + } + break; + case _OP_EQ:case _OP_NE: + if(pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0) )) + { + pi.op = i.op; + pi._arg0 = i._arg0; + pi._arg1 = pi._arg1; + pi._arg2 = i._arg2; + pi._arg3 = MAX_FUNC_STACKSIZE; + return; + } + break; + case _OP_LOADNULLS: + if((pi.op == _OP_LOADNULLS && pi._arg0+pi._arg1 == i._arg0)) { + + pi._arg1 = pi._arg1 + 1; + pi.op = _OP_LOADNULLS; + return; + } + break; + case _OP_LINE: + if(pi.op == _OP_LINE) { + _instructions.pop_back(); + _lineinfos.pop_back(); + } + break; + } + } + _optimization = true; + _instructions.push_back(i); +} + +SQObject SQFuncState::CreateString(const SQChar *s,SQInteger len) +{ + SQObjectPtr ns(SQString::Create(_sharedstate,s,len)); + _table(_strings)->NewSlot(ns,(SQInteger)1); + return ns; +} + +SQObject SQFuncState::CreateTable() +{ + SQObjectPtr nt(SQTable::Create(_sharedstate,0)); + _table(_strings)->NewSlot(nt,(SQInteger)1); + return nt; +} + +SQFunctionProto *SQFuncState::BuildProto() +{ + + SQFunctionProto *f=SQFunctionProto::Create(_ss,_instructions.size(), + _nliterals,_parameters.size(),_functions.size(),_outervalues.size(), + _lineinfos.size(),_localvarinfos.size(),_defaultparams.size()); + + SQObjectPtr refidx,key,val; + SQInteger idx; + + f->_stacksize = _stacksize; + f->_sourcename = _sourcename; + f->_bgenerator = _bgenerator; + f->_name = _name; + + while((idx=_table(_literals)->Next(false,refidx,key,val))!=-1) { + f->_literals[_integer(val)]=key; + refidx=idx; + } + + for(SQUnsignedInteger nf = 0; nf < _functions.size(); nf++) f->_functions[nf] = _functions[nf]; + for(SQUnsignedInteger np = 0; np < _parameters.size(); np++) f->_parameters[np] = _parameters[np]; + for(SQUnsignedInteger no = 0; no < _outervalues.size(); no++) f->_outervalues[no] = _outervalues[no]; + for(SQUnsignedInteger nl = 0; nl < _localvarinfos.size(); nl++) f->_localvarinfos[nl] = _localvarinfos[nl]; + for(SQUnsignedInteger ni = 0; ni < _lineinfos.size(); ni++) f->_lineinfos[ni] = _lineinfos[ni]; + for(SQUnsignedInteger nd = 0; nd < _defaultparams.size(); nd++) f->_defaultparams[nd] = _defaultparams[nd]; + + memcpy(f->_instructions,&_instructions[0],_instructions.size()*sizeof(SQInstruction)); + + f->_varparams = _varparams; + + return f; +} + +SQFuncState *SQFuncState::PushChildState(SQSharedState *ss) +{ + SQFuncState *child = (SQFuncState *)sq_malloc(sizeof(SQFuncState)); + new (child) SQFuncState(ss,this,_errfunc,_errtarget); + _childstates.push_back(child); + return child; +} + +void SQFuncState::PopChildState() +{ + SQFuncState *child = _childstates.back(); + sq_delete(child,SQFuncState); + _childstates.pop_back(); +} + +SQFuncState::~SQFuncState() +{ + while(_childstates.size() > 0) + { + PopChildState(); + } +} + +#endif diff --git a/squirrel_3_0_1_stable/squirrel/sqfuncstate.h b/squirrel_3_0_1_stable/squirrel/sqfuncstate.h index 1da13212a..2ae220087 100644 --- a/squirrel_3_0_1_stable/squirrel/sqfuncstate.h +++ b/squirrel_3_0_1_stable/squirrel/sqfuncstate.h @@ -1,91 +1,91 @@ -/* see copyright notice in squirrel.h */
-#ifndef _SQFUNCSTATE_H_
-#define _SQFUNCSTATE_H_
-///////////////////////////////////
-#include "squtils.h"
-
-struct SQFuncState
-{
- SQFuncState(SQSharedState *ss,SQFuncState *parent,CompilerErrorFunc efunc,void *ed);
- ~SQFuncState();
-#ifdef _DEBUG_DUMP
- void Dump(SQFunctionProto *func);
-#endif
- void Error(const SQChar *err);
- SQFuncState *PushChildState(SQSharedState *ss);
- void PopChildState();
- void AddInstruction(SQOpcode _op,SQInteger arg0=0,SQInteger arg1=0,SQInteger arg2=0,SQInteger arg3=0){SQInstruction i(_op,arg0,arg1,arg2,arg3);AddInstruction(i);}
- void AddInstruction(SQInstruction &i);
- void SetIntructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2=0,SQInteger arg3=0);
- void SetIntructionParam(SQInteger pos,SQInteger arg,SQInteger val);
- SQInstruction &GetInstruction(SQInteger pos){return _instructions[pos];}
- void PopInstructions(SQInteger size){for(SQInteger i=0;i<size;i++)_instructions.pop_back();}
- void SetStackSize(SQInteger n);
- SQInteger CountOuters(SQInteger stacksize);
- void SnoozeOpt(){_optimization=false;}
- void AddDefaultParam(SQInteger trg) { _defaultparams.push_back(trg); }
- SQInteger GetDefaultParamCount() { return _defaultparams.size(); }
- SQInteger GetCurrentPos(){return _instructions.size()-1;}
- SQInteger GetNumericConstant(const SQInteger cons);
- SQInteger GetNumericConstant(const SQFloat cons);
- SQInteger PushLocalVariable(const SQObject &name);
- void AddParameter(const SQObject &name);
- //void AddOuterValue(const SQObject &name);
- SQInteger GetLocalVariable(const SQObject &name);
- void MarkLocalAsOuter(SQInteger pos);
- SQInteger GetOuterVariable(const SQObject &name);
- SQInteger GenerateCode();
- SQInteger GetStackSize();
- SQInteger CalcStackFrameSize();
- void AddLineInfos(SQInteger line,bool lineop,bool force=false);
- SQFunctionProto *BuildProto();
- SQInteger AllocStackPos();
- SQInteger PushTarget(SQInteger n=-1);
- SQInteger PopTarget();
- SQInteger TopTarget();
- SQInteger GetUpTarget(SQInteger n);
- void DiscardTarget();
- bool IsLocal(SQUnsignedInteger stkpos);
- SQObject CreateString(const SQChar *s,SQInteger len = -1);
- SQObject CreateTable();
- bool IsConstant(const SQObject &name,SQObject &e);
- SQInteger _returnexp;
- SQLocalVarInfoVec _vlocals;
- SQIntVec _targetstack;
- SQInteger _stacksize;
- bool _varparams;
- bool _bgenerator;
- SQIntVec _unresolvedbreaks;
- SQIntVec _unresolvedcontinues;
- SQObjectPtrVec _functions;
- SQObjectPtrVec _parameters;
- SQOuterVarVec _outervalues;
- SQInstructionVec _instructions;
- SQLocalVarInfoVec _localvarinfos;
- SQObjectPtr _literals;
- SQObjectPtr _strings;
- SQObjectPtr _name;
- SQObjectPtr _sourcename;
- SQInteger _nliterals;
- SQLineInfoVec _lineinfos;
- SQFuncState *_parent;
- SQIntVec _scope_blocks;
- SQIntVec _breaktargets;
- SQIntVec _continuetargets;
- SQIntVec _defaultparams;
- SQInteger _lastline;
- SQInteger _traps; //contains number of nested exception traps
- SQInteger _outers;
- bool _optimization;
- SQSharedState *_sharedstate;
- sqvector<SQFuncState*> _childstates;
- SQInteger GetConstant(const SQObject &cons);
-private:
- CompilerErrorFunc _errfunc;
- void *_errtarget;
- SQSharedState *_ss;
-};
-
-
-#endif //_SQFUNCSTATE_H_
-
+/* see copyright notice in squirrel.h */ +#ifndef _SQFUNCSTATE_H_ +#define _SQFUNCSTATE_H_ +/////////////////////////////////// +#include "squtils.h" + +struct SQFuncState +{ + SQFuncState(SQSharedState *ss,SQFuncState *parent,CompilerErrorFunc efunc,void *ed); + ~SQFuncState(); +#ifdef _DEBUG_DUMP + void Dump(SQFunctionProto *func); +#endif + void Error(const SQChar *err); + SQFuncState *PushChildState(SQSharedState *ss); + void PopChildState(); + void AddInstruction(SQOpcode _op,SQInteger arg0=0,SQInteger arg1=0,SQInteger arg2=0,SQInteger arg3=0){SQInstruction i(_op,arg0,arg1,arg2,arg3);AddInstruction(i);} + void AddInstruction(SQInstruction &i); + void SetIntructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2=0,SQInteger arg3=0); + void SetIntructionParam(SQInteger pos,SQInteger arg,SQInteger val); + SQInstruction &GetInstruction(SQInteger pos){return _instructions[pos];} + void PopInstructions(SQInteger size){for(SQInteger i=0;i<size;i++)_instructions.pop_back();} + void SetStackSize(SQInteger n); + SQInteger CountOuters(SQInteger stacksize); + void SnoozeOpt(){_optimization=false;} + void AddDefaultParam(SQInteger trg) { _defaultparams.push_back(trg); } + SQInteger GetDefaultParamCount() { return _defaultparams.size(); } + SQInteger GetCurrentPos(){return _instructions.size()-1;} + SQInteger GetNumericConstant(const SQInteger cons); + SQInteger GetNumericConstant(const SQFloat cons); + SQInteger PushLocalVariable(const SQObject &name); + void AddParameter(const SQObject &name); + //void AddOuterValue(const SQObject &name); + SQInteger GetLocalVariable(const SQObject &name); + void MarkLocalAsOuter(SQInteger pos); + SQInteger GetOuterVariable(const SQObject &name); + SQInteger GenerateCode(); + SQInteger GetStackSize(); + SQInteger CalcStackFrameSize(); + void AddLineInfos(SQInteger line,bool lineop,bool force=false); + SQFunctionProto *BuildProto(); + SQInteger AllocStackPos(); + SQInteger PushTarget(SQInteger n=-1); + SQInteger PopTarget(); + SQInteger TopTarget(); + SQInteger GetUpTarget(SQInteger n); + void DiscardTarget(); + bool IsLocal(SQUnsignedInteger stkpos); + SQObject CreateString(const SQChar *s,SQInteger len = -1); + SQObject CreateTable(); + bool IsConstant(const SQObject &name,SQObject &e); + SQInteger _returnexp; + SQLocalVarInfoVec _vlocals; + SQIntVec _targetstack; + SQInteger _stacksize; + bool _varparams; + bool _bgenerator; + SQIntVec _unresolvedbreaks; + SQIntVec _unresolvedcontinues; + SQObjectPtrVec _functions; + SQObjectPtrVec _parameters; + SQOuterVarVec _outervalues; + SQInstructionVec _instructions; + SQLocalVarInfoVec _localvarinfos; + SQObjectPtr _literals; + SQObjectPtr _strings; + SQObjectPtr _name; + SQObjectPtr _sourcename; + SQInteger _nliterals; + SQLineInfoVec _lineinfos; + SQFuncState *_parent; + SQIntVec _scope_blocks; + SQIntVec _breaktargets; + SQIntVec _continuetargets; + SQIntVec _defaultparams; + SQInteger _lastline; + SQInteger _traps; //contains number of nested exception traps + SQInteger _outers; + bool _optimization; + SQSharedState *_sharedstate; + sqvector<SQFuncState*> _childstates; + SQInteger GetConstant(const SQObject &cons); +private: + CompilerErrorFunc _errfunc; + void *_errtarget; + SQSharedState *_ss; +}; + + +#endif //_SQFUNCSTATE_H_ + diff --git a/squirrel_3_0_1_stable/squirrel/sqlexer.cpp b/squirrel_3_0_1_stable/squirrel/sqlexer.cpp index ab17ba619..ec1704b71 100644 --- a/squirrel_3_0_1_stable/squirrel/sqlexer.cpp +++ b/squirrel_3_0_1_stable/squirrel/sqlexer.cpp @@ -1,489 +1,489 @@ -/*
- see copyright notice in squirrel.h
-*/
-#include "sqpcheader.h"
-#include <ctype.h>
-#include <stdlib.h>
-#include "sqtable.h"
-#include "sqstring.h"
-#include "sqcompiler.h"
-#include "sqlexer.h"
-
-#define CUR_CHAR (_currdata)
-#define RETURN_TOKEN(t) { _prevtoken = _curtoken; _curtoken = t; return t;}
-#define IS_EOB() (CUR_CHAR <= SQUIRREL_EOB)
-#define NEXT() {Next();_currentcolumn++;}
-#define INIT_TEMP_STRING() { _longstr.resize(0);}
-#define APPEND_CHAR(c) { _longstr.push_back(c);}
-#define TERMINATE_BUFFER() {_longstr.push_back(_SC('\0'));}
-#define ADD_KEYWORD(key,id) _keywords->NewSlot( SQString::Create(ss, _SC(#key)) ,SQInteger(id))
-
-SQLexer::SQLexer(){}
-SQLexer::~SQLexer()
-{
- _keywords->Release();
-}
-
-void SQLexer::Init(SQSharedState *ss, SQLEXREADFUNC rg, SQUserPointer up,CompilerErrorFunc efunc,void *ed)
-{
- _errfunc = efunc;
- _errtarget = ed;
- _sharedstate = ss;
- _keywords = SQTable::Create(ss, 26);
- ADD_KEYWORD(while, TK_WHILE);
- ADD_KEYWORD(do, TK_DO);
- ADD_KEYWORD(if, TK_IF);
- ADD_KEYWORD(else, TK_ELSE);
- ADD_KEYWORD(break, TK_BREAK);
- ADD_KEYWORD(continue, TK_CONTINUE);
- ADD_KEYWORD(return, TK_RETURN);
- ADD_KEYWORD(null, TK_NULL);
- ADD_KEYWORD(function, TK_FUNCTION);
- ADD_KEYWORD(local, TK_LOCAL);
- ADD_KEYWORD(for, TK_FOR);
- ADD_KEYWORD(foreach, TK_FOREACH);
- ADD_KEYWORD(in, TK_IN);
- ADD_KEYWORD(typeof, TK_TYPEOF);
- ADD_KEYWORD(base, TK_BASE);
- ADD_KEYWORD(delete, TK_DELETE);
- ADD_KEYWORD(try, TK_TRY);
- ADD_KEYWORD(catch, TK_CATCH);
- ADD_KEYWORD(throw, TK_THROW);
- ADD_KEYWORD(clone, TK_CLONE);
- ADD_KEYWORD(yield, TK_YIELD);
- ADD_KEYWORD(resume, TK_RESUME);
- ADD_KEYWORD(switch, TK_SWITCH);
- ADD_KEYWORD(case, TK_CASE);
- ADD_KEYWORD(default, TK_DEFAULT);
- ADD_KEYWORD(this, TK_THIS);
- ADD_KEYWORD(class,TK_CLASS);
- ADD_KEYWORD(extends,TK_EXTENDS);
- ADD_KEYWORD(constructor,TK_CONSTRUCTOR);
- ADD_KEYWORD(instanceof,TK_INSTANCEOF);
- ADD_KEYWORD(true,TK_TRUE);
- ADD_KEYWORD(false,TK_FALSE);
- ADD_KEYWORD(static,TK_STATIC);
- ADD_KEYWORD(enum,TK_ENUM);
- ADD_KEYWORD(const,TK_CONST);
-
- _readf = rg;
- _up = up;
- _lasttokenline = _currentline = 1;
- _currentcolumn = 0;
- _prevtoken = -1;
- _reached_eof = SQFalse;
- Next();
-}
-
-void SQLexer::Error(const SQChar *err)
-{
- _errfunc(_errtarget,err);
-}
-
-void SQLexer::Next()
-{
- SQInteger t = _readf(_up);
- if(t > MAX_CHAR) Error(_SC("Invalid character"));
- if(t != 0) {
- _currdata = (LexChar)t;
- return;
- }
- _currdata = SQUIRREL_EOB;
- _reached_eof = SQTrue;
-}
-
-const SQChar *SQLexer::Tok2Str(SQInteger tok)
-{
- SQObjectPtr itr, key, val;
- SQInteger nitr;
- while((nitr = _keywords->Next(false,itr, key, val)) != -1) {
- itr = (SQInteger)nitr;
- if(((SQInteger)_integer(val)) == tok)
- return _stringval(key);
- }
- return NULL;
-}
-
-void SQLexer::LexBlockComment()
-{
- bool done = false;
- while(!done) {
- switch(CUR_CHAR) {
- case _SC('*'): { NEXT(); if(CUR_CHAR == _SC('/')) { done = true; NEXT(); }}; continue;
- case _SC('\n'): _currentline++; NEXT(); continue;
- case SQUIRREL_EOB: Error(_SC("missing \"*/\" in comment"));
- default: NEXT();
- }
- }
-}
-void SQLexer::LexLineComment()
-{
- do { NEXT(); } while (CUR_CHAR != _SC('\n') && (!IS_EOB()));
-}
-
-SQInteger SQLexer::Lex()
-{
- _lasttokenline = _currentline;
- while(CUR_CHAR != SQUIRREL_EOB) {
- switch(CUR_CHAR){
- case _SC('\t'): case _SC('\r'): case _SC(' '): NEXT(); continue;
- case _SC('\n'):
- _currentline++;
- _prevtoken=_curtoken;
- _curtoken=_SC('\n');
- NEXT();
- _currentcolumn=1;
- continue;
- case _SC('#'): LexLineComment(); continue;
- case _SC('/'):
- NEXT();
- switch(CUR_CHAR){
- case _SC('*'):
- NEXT();
- LexBlockComment();
- continue;
- case _SC('/'):
- LexLineComment();
- continue;
- case _SC('='):
- NEXT();
- RETURN_TOKEN(TK_DIVEQ);
- continue;
- case _SC('>'):
- NEXT();
- RETURN_TOKEN(TK_ATTR_CLOSE);
- continue;
- default:
- RETURN_TOKEN('/');
- }
- case _SC('='):
- NEXT();
- if (CUR_CHAR != _SC('=')){ RETURN_TOKEN('=') }
- else { NEXT(); RETURN_TOKEN(TK_EQ); }
- case _SC('<'):
- NEXT();
- switch(CUR_CHAR) {
- case _SC('='):
- NEXT();
- if(CUR_CHAR == _SC('>')) {
- NEXT();
- RETURN_TOKEN(TK_3WAYSCMP);
- }
- RETURN_TOKEN(TK_LE)
- break;
- case _SC('-'): NEXT(); RETURN_TOKEN(TK_NEWSLOT); break;
- case _SC('<'): NEXT(); RETURN_TOKEN(TK_SHIFTL); break;
- case _SC('/'): NEXT(); RETURN_TOKEN(TK_ATTR_OPEN); break;
- }
- RETURN_TOKEN('<');
- case _SC('>'):
- NEXT();
- if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_GE);}
- else if(CUR_CHAR == _SC('>')){
- NEXT();
- if(CUR_CHAR == _SC('>')){
- NEXT();
- RETURN_TOKEN(TK_USHIFTR);
- }
- RETURN_TOKEN(TK_SHIFTR);
- }
- else { RETURN_TOKEN('>') }
- case _SC('!'):
- NEXT();
- if (CUR_CHAR != _SC('=')){ RETURN_TOKEN('!')}
- else { NEXT(); RETURN_TOKEN(TK_NE); }
- case _SC('@'): {
- SQInteger stype;
- NEXT();
- if(CUR_CHAR != _SC('"')) {
- RETURN_TOKEN('@');
- }
- if((stype=ReadString('"',true))!=-1) {
- RETURN_TOKEN(stype);
- }
- Error(_SC("error parsing the string"));
- }
- case _SC('"'):
- case _SC('\''): {
- SQInteger stype;
- if((stype=ReadString(CUR_CHAR,false))!=-1){
- RETURN_TOKEN(stype);
- }
- Error(_SC("error parsing the string"));
- }
- case _SC('{'): case _SC('}'): case _SC('('): case _SC(')'): case _SC('['): case _SC(']'):
- case _SC(';'): case _SC(','): case _SC('?'): case _SC('^'): case _SC('~'):
- {SQInteger ret = CUR_CHAR;
- NEXT(); RETURN_TOKEN(ret); }
- case _SC('.'):
- NEXT();
- if (CUR_CHAR != _SC('.')){ RETURN_TOKEN('.') }
- NEXT();
- if (CUR_CHAR != _SC('.')){ Error(_SC("invalid token '..'")); }
- NEXT();
- RETURN_TOKEN(TK_VARPARAMS);
- case _SC('&'):
- NEXT();
- if (CUR_CHAR != _SC('&')){ RETURN_TOKEN('&') }
- else { NEXT(); RETURN_TOKEN(TK_AND); }
- case _SC('|'):
- NEXT();
- if (CUR_CHAR != _SC('|')){ RETURN_TOKEN('|') }
- else { NEXT(); RETURN_TOKEN(TK_OR); }
- case _SC(':'):
- NEXT();
- if (CUR_CHAR != _SC(':')){ RETURN_TOKEN(':') }
- else { NEXT(); RETURN_TOKEN(TK_DOUBLE_COLON); }
- case _SC('*'):
- NEXT();
- if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MULEQ);}
- else RETURN_TOKEN('*');
- case _SC('%'):
- NEXT();
- if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MODEQ);}
- else RETURN_TOKEN('%');
- case _SC('-'):
- NEXT();
- if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MINUSEQ);}
- else if (CUR_CHAR == _SC('-')){ NEXT(); RETURN_TOKEN(TK_MINUSMINUS);}
- else RETURN_TOKEN('-');
- case _SC('+'):
- NEXT();
- if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_PLUSEQ);}
- else if (CUR_CHAR == _SC('+')){ NEXT(); RETURN_TOKEN(TK_PLUSPLUS);}
- else RETURN_TOKEN('+');
- case SQUIRREL_EOB:
- return 0;
- default:{
- if (scisdigit(CUR_CHAR)) {
- SQInteger ret = ReadNumber();
- RETURN_TOKEN(ret);
- }
- else if (scisalpha(CUR_CHAR) || CUR_CHAR == _SC('_')) {
- SQInteger t = ReadID();
- RETURN_TOKEN(t);
- }
- else {
- SQInteger c = CUR_CHAR;
- if (sciscntrl((int)c)) Error(_SC("unexpected character(control)"));
- NEXT();
- RETURN_TOKEN(c);
- }
- RETURN_TOKEN(0);
- }
- }
- }
- return 0;
-}
-
-SQInteger SQLexer::GetIDType(SQChar *s)
-{
- SQObjectPtr t;
- if(_keywords->Get(SQString::Create(_sharedstate, s), t)) {
- return SQInteger(_integer(t));
- }
- return TK_IDENTIFIER;
-}
-
-
-SQInteger SQLexer::ReadString(SQInteger ndelim,bool verbatim)
-{
- INIT_TEMP_STRING();
- NEXT();
- if(IS_EOB()) return -1;
- for(;;) {
- while(CUR_CHAR != ndelim) {
- switch(CUR_CHAR) {
- case SQUIRREL_EOB:
- Error(_SC("unfinished string"));
- return -1;
- case _SC('\n'):
- if(!verbatim) Error(_SC("newline in a constant"));
- APPEND_CHAR(CUR_CHAR); NEXT();
- _currentline++;
- break;
- case _SC('\\'):
- if(verbatim) {
- APPEND_CHAR('\\'); NEXT();
- }
- else {
- NEXT();
- switch(CUR_CHAR) {
- case _SC('x'): NEXT(); {
- if(!isxdigit(CUR_CHAR)) Error(_SC("hexadecimal number expected"));
- const SQInteger maxdigits = 4;
- SQChar temp[maxdigits+1];
- SQInteger n = 0;
- while(isxdigit(CUR_CHAR) && n < maxdigits) {
- temp[n] = CUR_CHAR;
- n++;
- NEXT();
- }
- temp[n] = 0;
- SQChar *sTemp;
- APPEND_CHAR((SQChar)scstrtoul(temp,&sTemp,16));
- }
- break;
- case _SC('t'): APPEND_CHAR(_SC('\t')); NEXT(); break;
- case _SC('a'): APPEND_CHAR(_SC('\a')); NEXT(); break;
- case _SC('b'): APPEND_CHAR(_SC('\b')); NEXT(); break;
- case _SC('n'): APPEND_CHAR(_SC('\n')); NEXT(); break;
- case _SC('r'): APPEND_CHAR(_SC('\r')); NEXT(); break;
- case _SC('v'): APPEND_CHAR(_SC('\v')); NEXT(); break;
- case _SC('f'): APPEND_CHAR(_SC('\f')); NEXT(); break;
- case _SC('0'): APPEND_CHAR(_SC('\0')); NEXT(); break;
- case _SC('\\'): APPEND_CHAR(_SC('\\')); NEXT(); break;
- case _SC('"'): APPEND_CHAR(_SC('"')); NEXT(); break;
- case _SC('\''): APPEND_CHAR(_SC('\'')); NEXT(); break;
- default:
- Error(_SC("unrecognised escaper char"));
- break;
- }
- }
- break;
- default:
- APPEND_CHAR(CUR_CHAR);
- NEXT();
- }
- }
- NEXT();
- if(verbatim && CUR_CHAR == '"') { //double quotation
- APPEND_CHAR(CUR_CHAR);
- NEXT();
- }
- else {
- break;
- }
- }
- TERMINATE_BUFFER();
- SQInteger len = _longstr.size()-1;
- if(ndelim == _SC('\'')) {
- if(len == 0) Error(_SC("empty constant"));
- if(len > 1) Error(_SC("constant too long"));
- _nvalue = _longstr[0];
- return TK_INTEGER;
- }
- _svalue = &_longstr[0];
- return TK_STRING_LITERAL;
-}
-
-void LexHexadecimal(const SQChar *s,SQUnsignedInteger *res)
-{
- *res = 0;
- while(*s != 0)
- {
- if(scisdigit(*s)) *res = (*res)*16+((*s++)-'0');
- else if(scisxdigit(*s)) *res = (*res)*16+(toupper(*s++)-'A'+10);
- else { assert(0); }
- }
-}
-
-void LexInteger(const SQChar *s,SQUnsignedInteger *res)
-{
- *res = 0;
- while(*s != 0)
- {
- *res = (*res)*10+((*s++)-'0');
- }
-}
-
-SQInteger scisodigit(SQInteger c) { return c >= _SC('0') && c <= _SC('7'); }
-
-void LexOctal(const SQChar *s,SQUnsignedInteger *res)
-{
- *res = 0;
- while(*s != 0)
- {
- if(scisodigit(*s)) *res = (*res)*8+((*s++)-'0');
- else { assert(0); }
- }
-}
-
-SQInteger isexponent(SQInteger c) { return c == 'e' || c=='E'; }
-
-
-#define MAX_HEX_DIGITS (sizeof(SQInteger)*2)
-SQInteger SQLexer::ReadNumber()
-{
-#define TINT 1
-#define TFLOAT 2
-#define THEX 3
-#define TSCIENTIFIC 4
-#define TOCTAL 5
- SQInteger type = TINT, firstchar = CUR_CHAR;
- SQChar *sTemp;
- INIT_TEMP_STRING();
- NEXT();
- if(firstchar == _SC('0') && (toupper(CUR_CHAR) == _SC('X') || scisodigit(CUR_CHAR)) ) {
- if(scisodigit(CUR_CHAR)) {
- type = TOCTAL;
- while(scisodigit(CUR_CHAR)) {
- APPEND_CHAR(CUR_CHAR);
- NEXT();
- }
- if(scisdigit(CUR_CHAR)) Error(_SC("invalid octal number"));
- }
- else {
- NEXT();
- type = THEX;
- while(isxdigit(CUR_CHAR)) {
- APPEND_CHAR(CUR_CHAR);
- NEXT();
- }
- if(_longstr.size() > MAX_HEX_DIGITS) Error(_SC("too many digits for an Hex number"));
- }
- }
- else {
- APPEND_CHAR((int)firstchar);
- while (CUR_CHAR == _SC('.') || scisdigit(CUR_CHAR) || isexponent(CUR_CHAR)) {
- if(CUR_CHAR == _SC('.')) type = TFLOAT;
- if(isexponent(CUR_CHAR)) {
- if(type != TFLOAT) Error(_SC("invalid numeric format"));
- type = TSCIENTIFIC;
- APPEND_CHAR(CUR_CHAR);
- NEXT();
- if(CUR_CHAR == '+' || CUR_CHAR == '-'){
- APPEND_CHAR(CUR_CHAR);
- NEXT();
- }
- if(!scisdigit(CUR_CHAR)) Error(_SC("exponent expected"));
- }
-
- APPEND_CHAR(CUR_CHAR);
- NEXT();
- }
- }
- TERMINATE_BUFFER();
- switch(type) {
- case TSCIENTIFIC:
- case TFLOAT:
- _fvalue = (SQFloat)scstrtod(&_longstr[0],&sTemp);
- return TK_FLOAT;
- case TINT:
- LexInteger(&_longstr[0],(SQUnsignedInteger *)&_nvalue);
- return TK_INTEGER;
- case THEX:
- LexHexadecimal(&_longstr[0],(SQUnsignedInteger *)&_nvalue);
- return TK_INTEGER;
- case TOCTAL:
- LexOctal(&_longstr[0],(SQUnsignedInteger *)&_nvalue);
- return TK_INTEGER;
- }
- return 0;
-}
-
-SQInteger SQLexer::ReadID()
-{
- SQInteger res;
- INIT_TEMP_STRING();
- do {
- APPEND_CHAR(CUR_CHAR);
- NEXT();
- } while(scisalnum(CUR_CHAR) || CUR_CHAR == _SC('_'));
- TERMINATE_BUFFER();
- res = GetIDType(&_longstr[0]);
- if(res == TK_IDENTIFIER || res == TK_CONSTRUCTOR) {
- _svalue = &_longstr[0];
- }
- return res;
-}
+/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include <ctype.h> +#include <stdlib.h> +#include "sqtable.h" +#include "sqstring.h" +#include "sqcompiler.h" +#include "sqlexer.h" + +#define CUR_CHAR (_currdata) +#define RETURN_TOKEN(t) { _prevtoken = _curtoken; _curtoken = t; return t;} +#define IS_EOB() (CUR_CHAR <= SQUIRREL_EOB) +#define NEXT() {Next();_currentcolumn++;} +#define INIT_TEMP_STRING() { _longstr.resize(0);} +#define APPEND_CHAR(c) { _longstr.push_back(c);} +#define TERMINATE_BUFFER() {_longstr.push_back(_SC('\0'));} +#define ADD_KEYWORD(key,id) _keywords->NewSlot( SQString::Create(ss, _SC(#key)) ,SQInteger(id)) + +SQLexer::SQLexer(){} +SQLexer::~SQLexer() +{ + _keywords->Release(); +} + +void SQLexer::Init(SQSharedState *ss, SQLEXREADFUNC rg, SQUserPointer up,CompilerErrorFunc efunc,void *ed) +{ + _errfunc = efunc; + _errtarget = ed; + _sharedstate = ss; + _keywords = SQTable::Create(ss, 26); + ADD_KEYWORD(while, TK_WHILE); + ADD_KEYWORD(do, TK_DO); + ADD_KEYWORD(if, TK_IF); + ADD_KEYWORD(else, TK_ELSE); + ADD_KEYWORD(break, TK_BREAK); + ADD_KEYWORD(continue, TK_CONTINUE); + ADD_KEYWORD(return, TK_RETURN); + ADD_KEYWORD(null, TK_NULL); + ADD_KEYWORD(function, TK_FUNCTION); + ADD_KEYWORD(local, TK_LOCAL); + ADD_KEYWORD(for, TK_FOR); + ADD_KEYWORD(foreach, TK_FOREACH); + ADD_KEYWORD(in, TK_IN); + ADD_KEYWORD(typeof, TK_TYPEOF); + ADD_KEYWORD(base, TK_BASE); + ADD_KEYWORD(delete, TK_DELETE); + ADD_KEYWORD(try, TK_TRY); + ADD_KEYWORD(catch, TK_CATCH); + ADD_KEYWORD(throw, TK_THROW); + ADD_KEYWORD(clone, TK_CLONE); + ADD_KEYWORD(yield, TK_YIELD); + ADD_KEYWORD(resume, TK_RESUME); + ADD_KEYWORD(switch, TK_SWITCH); + ADD_KEYWORD(case, TK_CASE); + ADD_KEYWORD(default, TK_DEFAULT); + ADD_KEYWORD(this, TK_THIS); + ADD_KEYWORD(class,TK_CLASS); + ADD_KEYWORD(extends,TK_EXTENDS); + ADD_KEYWORD(constructor,TK_CONSTRUCTOR); + ADD_KEYWORD(instanceof,TK_INSTANCEOF); + ADD_KEYWORD(true,TK_TRUE); + ADD_KEYWORD(false,TK_FALSE); + ADD_KEYWORD(static,TK_STATIC); + ADD_KEYWORD(enum,TK_ENUM); + ADD_KEYWORD(const,TK_CONST); + + _readf = rg; + _up = up; + _lasttokenline = _currentline = 1; + _currentcolumn = 0; + _prevtoken = -1; + _reached_eof = SQFalse; + Next(); +} + +void SQLexer::Error(const SQChar *err) +{ + _errfunc(_errtarget,err); +} + +void SQLexer::Next() +{ + SQInteger t = _readf(_up); + if(t > MAX_CHAR) Error(_SC("Invalid character")); + if(t != 0) { + _currdata = (LexChar)t; + return; + } + _currdata = SQUIRREL_EOB; + _reached_eof = SQTrue; +} + +const SQChar *SQLexer::Tok2Str(SQInteger tok) +{ + SQObjectPtr itr, key, val; + SQInteger nitr; + while((nitr = _keywords->Next(false,itr, key, val)) != -1) { + itr = (SQInteger)nitr; + if(((SQInteger)_integer(val)) == tok) + return _stringval(key); + } + return NULL; +} + +void SQLexer::LexBlockComment() +{ + bool done = false; + while(!done) { + switch(CUR_CHAR) { + case _SC('*'): { NEXT(); if(CUR_CHAR == _SC('/')) { done = true; NEXT(); }}; continue; + case _SC('\n'): _currentline++; NEXT(); continue; + case SQUIRREL_EOB: Error(_SC("missing \"*/\" in comment")); + default: NEXT(); + } + } +} +void SQLexer::LexLineComment() +{ + do { NEXT(); } while (CUR_CHAR != _SC('\n') && (!IS_EOB())); +} + +SQInteger SQLexer::Lex() +{ + _lasttokenline = _currentline; + while(CUR_CHAR != SQUIRREL_EOB) { + switch(CUR_CHAR){ + case _SC('\t'): case _SC('\r'): case _SC(' '): NEXT(); continue; + case _SC('\n'): + _currentline++; + _prevtoken=_curtoken; + _curtoken=_SC('\n'); + NEXT(); + _currentcolumn=1; + continue; + case _SC('#'): LexLineComment(); continue; + case _SC('/'): + NEXT(); + switch(CUR_CHAR){ + case _SC('*'): + NEXT(); + LexBlockComment(); + continue; + case _SC('/'): + LexLineComment(); + continue; + case _SC('='): + NEXT(); + RETURN_TOKEN(TK_DIVEQ); + continue; + case _SC('>'): + NEXT(); + RETURN_TOKEN(TK_ATTR_CLOSE); + continue; + default: + RETURN_TOKEN('/'); + } + case _SC('='): + NEXT(); + if (CUR_CHAR != _SC('=')){ RETURN_TOKEN('=') } + else { NEXT(); RETURN_TOKEN(TK_EQ); } + case _SC('<'): + NEXT(); + switch(CUR_CHAR) { + case _SC('='): + NEXT(); + if(CUR_CHAR == _SC('>')) { + NEXT(); + RETURN_TOKEN(TK_3WAYSCMP); + } + RETURN_TOKEN(TK_LE) + break; + case _SC('-'): NEXT(); RETURN_TOKEN(TK_NEWSLOT); break; + case _SC('<'): NEXT(); RETURN_TOKEN(TK_SHIFTL); break; + case _SC('/'): NEXT(); RETURN_TOKEN(TK_ATTR_OPEN); break; + } + RETURN_TOKEN('<'); + case _SC('>'): + NEXT(); + if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_GE);} + else if(CUR_CHAR == _SC('>')){ + NEXT(); + if(CUR_CHAR == _SC('>')){ + NEXT(); + RETURN_TOKEN(TK_USHIFTR); + } + RETURN_TOKEN(TK_SHIFTR); + } + else { RETURN_TOKEN('>') } + case _SC('!'): + NEXT(); + if (CUR_CHAR != _SC('=')){ RETURN_TOKEN('!')} + else { NEXT(); RETURN_TOKEN(TK_NE); } + case _SC('@'): { + SQInteger stype; + NEXT(); + if(CUR_CHAR != _SC('"')) { + RETURN_TOKEN('@'); + } + if((stype=ReadString('"',true))!=-1) { + RETURN_TOKEN(stype); + } + Error(_SC("error parsing the string")); + } + case _SC('"'): + case _SC('\''): { + SQInteger stype; + if((stype=ReadString(CUR_CHAR,false))!=-1){ + RETURN_TOKEN(stype); + } + Error(_SC("error parsing the string")); + } + case _SC('{'): case _SC('}'): case _SC('('): case _SC(')'): case _SC('['): case _SC(']'): + case _SC(';'): case _SC(','): case _SC('?'): case _SC('^'): case _SC('~'): + {SQInteger ret = CUR_CHAR; + NEXT(); RETURN_TOKEN(ret); } + case _SC('.'): + NEXT(); + if (CUR_CHAR != _SC('.')){ RETURN_TOKEN('.') } + NEXT(); + if (CUR_CHAR != _SC('.')){ Error(_SC("invalid token '..'")); } + NEXT(); + RETURN_TOKEN(TK_VARPARAMS); + case _SC('&'): + NEXT(); + if (CUR_CHAR != _SC('&')){ RETURN_TOKEN('&') } + else { NEXT(); RETURN_TOKEN(TK_AND); } + case _SC('|'): + NEXT(); + if (CUR_CHAR != _SC('|')){ RETURN_TOKEN('|') } + else { NEXT(); RETURN_TOKEN(TK_OR); } + case _SC(':'): + NEXT(); + if (CUR_CHAR != _SC(':')){ RETURN_TOKEN(':') } + else { NEXT(); RETURN_TOKEN(TK_DOUBLE_COLON); } + case _SC('*'): + NEXT(); + if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MULEQ);} + else RETURN_TOKEN('*'); + case _SC('%'): + NEXT(); + if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MODEQ);} + else RETURN_TOKEN('%'); + case _SC('-'): + NEXT(); + if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_MINUSEQ);} + else if (CUR_CHAR == _SC('-')){ NEXT(); RETURN_TOKEN(TK_MINUSMINUS);} + else RETURN_TOKEN('-'); + case _SC('+'): + NEXT(); + if (CUR_CHAR == _SC('=')){ NEXT(); RETURN_TOKEN(TK_PLUSEQ);} + else if (CUR_CHAR == _SC('+')){ NEXT(); RETURN_TOKEN(TK_PLUSPLUS);} + else RETURN_TOKEN('+'); + case SQUIRREL_EOB: + return 0; + default:{ + if (scisdigit(CUR_CHAR)) { + SQInteger ret = ReadNumber(); + RETURN_TOKEN(ret); + } + else if (scisalpha(CUR_CHAR) || CUR_CHAR == _SC('_')) { + SQInteger t = ReadID(); + RETURN_TOKEN(t); + } + else { + SQInteger c = CUR_CHAR; + if (sciscntrl((int)c)) Error(_SC("unexpected character(control)")); + NEXT(); + RETURN_TOKEN(c); + } + RETURN_TOKEN(0); + } + } + } + return 0; +} + +SQInteger SQLexer::GetIDType(SQChar *s) +{ + SQObjectPtr t; + if(_keywords->Get(SQString::Create(_sharedstate, s), t)) { + return SQInteger(_integer(t)); + } + return TK_IDENTIFIER; +} + + +SQInteger SQLexer::ReadString(SQInteger ndelim,bool verbatim) +{ + INIT_TEMP_STRING(); + NEXT(); + if(IS_EOB()) return -1; + for(;;) { + while(CUR_CHAR != ndelim) { + switch(CUR_CHAR) { + case SQUIRREL_EOB: + Error(_SC("unfinished string")); + return -1; + case _SC('\n'): + if(!verbatim) Error(_SC("newline in a constant")); + APPEND_CHAR(CUR_CHAR); NEXT(); + _currentline++; + break; + case _SC('\\'): + if(verbatim) { + APPEND_CHAR('\\'); NEXT(); + } + else { + NEXT(); + switch(CUR_CHAR) { + case _SC('x'): NEXT(); { + if(!isxdigit(CUR_CHAR)) Error(_SC("hexadecimal number expected")); + const SQInteger maxdigits = 4; + SQChar temp[maxdigits+1]; + SQInteger n = 0; + while(isxdigit(CUR_CHAR) && n < maxdigits) { + temp[n] = CUR_CHAR; + n++; + NEXT(); + } + temp[n] = 0; + SQChar *sTemp; + APPEND_CHAR((SQChar)scstrtoul(temp,&sTemp,16)); + } + break; + case _SC('t'): APPEND_CHAR(_SC('\t')); NEXT(); break; + case _SC('a'): APPEND_CHAR(_SC('\a')); NEXT(); break; + case _SC('b'): APPEND_CHAR(_SC('\b')); NEXT(); break; + case _SC('n'): APPEND_CHAR(_SC('\n')); NEXT(); break; + case _SC('r'): APPEND_CHAR(_SC('\r')); NEXT(); break; + case _SC('v'): APPEND_CHAR(_SC('\v')); NEXT(); break; + case _SC('f'): APPEND_CHAR(_SC('\f')); NEXT(); break; + case _SC('0'): APPEND_CHAR(_SC('\0')); NEXT(); break; + case _SC('\\'): APPEND_CHAR(_SC('\\')); NEXT(); break; + case _SC('"'): APPEND_CHAR(_SC('"')); NEXT(); break; + case _SC('\''): APPEND_CHAR(_SC('\'')); NEXT(); break; + default: + Error(_SC("unrecognised escaper char")); + break; + } + } + break; + default: + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + } + NEXT(); + if(verbatim && CUR_CHAR == '"') { //double quotation + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + else { + break; + } + } + TERMINATE_BUFFER(); + SQInteger len = _longstr.size()-1; + if(ndelim == _SC('\'')) { + if(len == 0) Error(_SC("empty constant")); + if(len > 1) Error(_SC("constant too long")); + _nvalue = _longstr[0]; + return TK_INTEGER; + } + _svalue = &_longstr[0]; + return TK_STRING_LITERAL; +} + +void LexHexadecimal(const SQChar *s,SQUnsignedInteger *res) +{ + *res = 0; + while(*s != 0) + { + if(scisdigit(*s)) *res = (*res)*16+((*s++)-'0'); + else if(scisxdigit(*s)) *res = (*res)*16+(toupper(*s++)-'A'+10); + else { assert(0); } + } +} + +void LexInteger(const SQChar *s,SQUnsignedInteger *res) +{ + *res = 0; + while(*s != 0) + { + *res = (*res)*10+((*s++)-'0'); + } +} + +SQInteger scisodigit(SQInteger c) { return c >= _SC('0') && c <= _SC('7'); } + +void LexOctal(const SQChar *s,SQUnsignedInteger *res) +{ + *res = 0; + while(*s != 0) + { + if(scisodigit(*s)) *res = (*res)*8+((*s++)-'0'); + else { assert(0); } + } +} + +SQInteger isexponent(SQInteger c) { return c == 'e' || c=='E'; } + + +#define MAX_HEX_DIGITS (sizeof(SQInteger)*2) +SQInteger SQLexer::ReadNumber() +{ +#define TINT 1 +#define TFLOAT 2 +#define THEX 3 +#define TSCIENTIFIC 4 +#define TOCTAL 5 + SQInteger type = TINT, firstchar = CUR_CHAR; + SQChar *sTemp; + INIT_TEMP_STRING(); + NEXT(); + if(firstchar == _SC('0') && (toupper(CUR_CHAR) == _SC('X') || scisodigit(CUR_CHAR)) ) { + if(scisodigit(CUR_CHAR)) { + type = TOCTAL; + while(scisodigit(CUR_CHAR)) { + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + if(scisdigit(CUR_CHAR)) Error(_SC("invalid octal number")); + } + else { + NEXT(); + type = THEX; + while(isxdigit(CUR_CHAR)) { + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + if(_longstr.size() > MAX_HEX_DIGITS) Error(_SC("too many digits for an Hex number")); + } + } + else { + APPEND_CHAR((int)firstchar); + while (CUR_CHAR == _SC('.') || scisdigit(CUR_CHAR) || isexponent(CUR_CHAR)) { + if(CUR_CHAR == _SC('.')) type = TFLOAT; + if(isexponent(CUR_CHAR)) { + if(type != TFLOAT) Error(_SC("invalid numeric format")); + type = TSCIENTIFIC; + APPEND_CHAR(CUR_CHAR); + NEXT(); + if(CUR_CHAR == '+' || CUR_CHAR == '-'){ + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + if(!scisdigit(CUR_CHAR)) Error(_SC("exponent expected")); + } + + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + } + TERMINATE_BUFFER(); + switch(type) { + case TSCIENTIFIC: + case TFLOAT: + _fvalue = (SQFloat)scstrtod(&_longstr[0],&sTemp); + return TK_FLOAT; + case TINT: + LexInteger(&_longstr[0],(SQUnsignedInteger *)&_nvalue); + return TK_INTEGER; + case THEX: + LexHexadecimal(&_longstr[0],(SQUnsignedInteger *)&_nvalue); + return TK_INTEGER; + case TOCTAL: + LexOctal(&_longstr[0],(SQUnsignedInteger *)&_nvalue); + return TK_INTEGER; + } + return 0; +} + +SQInteger SQLexer::ReadID() +{ + SQInteger res; + INIT_TEMP_STRING(); + do { + APPEND_CHAR(CUR_CHAR); + NEXT(); + } while(scisalnum(CUR_CHAR) || CUR_CHAR == _SC('_')); + TERMINATE_BUFFER(); + res = GetIDType(&_longstr[0]); + if(res == TK_IDENTIFIER || res == TK_CONSTRUCTOR) { + _svalue = &_longstr[0]; + } + return res; +} diff --git a/squirrel_3_0_1_stable/squirrel/sqlexer.h b/squirrel_3_0_1_stable/squirrel/sqlexer.h index d3283c6f7..49fadd90a 100644 --- a/squirrel_3_0_1_stable/squirrel/sqlexer.h +++ b/squirrel_3_0_1_stable/squirrel/sqlexer.h @@ -1,47 +1,47 @@ -/* see copyright notice in squirrel.h */
-#ifndef _SQLEXER_H_
-#define _SQLEXER_H_
-
-#ifdef SQUNICODE
-typedef SQChar LexChar;
-#else
-typedef unsigned char LexChar;
-#endif
-
-struct SQLexer
-{
- SQLexer();
- ~SQLexer();
- void Init(SQSharedState *ss,SQLEXREADFUNC rg,SQUserPointer up,CompilerErrorFunc efunc,void *ed);
- void Error(const SQChar *err);
- SQInteger Lex();
- const SQChar *Tok2Str(SQInteger tok);
-private:
- SQInteger GetIDType(SQChar *s);
- SQInteger ReadString(SQInteger ndelim,bool verbatim);
- SQInteger ReadNumber();
- void LexBlockComment();
- void LexLineComment();
- SQInteger ReadID();
- void Next();
- SQInteger _curtoken;
- SQTable *_keywords;
- SQBool _reached_eof;
-public:
- SQInteger _prevtoken;
- SQInteger _currentline;
- SQInteger _lasttokenline;
- SQInteger _currentcolumn;
- const SQChar *_svalue;
- SQInteger _nvalue;
- SQFloat _fvalue;
- SQLEXREADFUNC _readf;
- SQUserPointer _up;
- LexChar _currdata;
- SQSharedState *_sharedstate;
- sqvector<SQChar> _longstr;
- CompilerErrorFunc _errfunc;
- void *_errtarget;
-};
-
-#endif
+/* see copyright notice in squirrel.h */ +#ifndef _SQLEXER_H_ +#define _SQLEXER_H_ + +#ifdef SQUNICODE +typedef SQChar LexChar; +#else +typedef unsigned char LexChar; +#endif + +struct SQLexer +{ + SQLexer(); + ~SQLexer(); + void Init(SQSharedState *ss,SQLEXREADFUNC rg,SQUserPointer up,CompilerErrorFunc efunc,void *ed); + void Error(const SQChar *err); + SQInteger Lex(); + const SQChar *Tok2Str(SQInteger tok); +private: + SQInteger GetIDType(SQChar *s); + SQInteger ReadString(SQInteger ndelim,bool verbatim); + SQInteger ReadNumber(); + void LexBlockComment(); + void LexLineComment(); + SQInteger ReadID(); + void Next(); + SQInteger _curtoken; + SQTable *_keywords; + SQBool _reached_eof; +public: + SQInteger _prevtoken; + SQInteger _currentline; + SQInteger _lasttokenline; + SQInteger _currentcolumn; + const SQChar *_svalue; + SQInteger _nvalue; + SQFloat _fvalue; + SQLEXREADFUNC _readf; + SQUserPointer _up; + LexChar _currdata; + SQSharedState *_sharedstate; + sqvector<SQChar> _longstr; + CompilerErrorFunc _errfunc; + void *_errtarget; +}; + +#endif diff --git a/squirrel_3_0_1_stable/squirrel/sqmem.cpp b/squirrel_3_0_1_stable/squirrel/sqmem.cpp index 520f7eb76..6faf8165a 100644 --- a/squirrel_3_0_1_stable/squirrel/sqmem.cpp +++ b/squirrel_3_0_1_stable/squirrel/sqmem.cpp @@ -1,9 +1,9 @@ -/*
- see copyright notice in squirrel.h
-*/
-#include "sqpcheader.h"
-void *sq_vm_malloc(SQUnsignedInteger size){ return malloc(size); }
-
-void *sq_vm_realloc(void *p, SQUnsignedInteger oldsize, SQUnsignedInteger size){ return realloc(p, size); }
-
-void sq_vm_free(void *p, SQUnsignedInteger size){ free(p); }
+/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +void *sq_vm_malloc(SQUnsignedInteger size){ return malloc(size); } + +void *sq_vm_realloc(void *p, SQUnsignedInteger oldsize, SQUnsignedInteger size){ return realloc(p, size); } + +void sq_vm_free(void *p, SQUnsignedInteger size){ free(p); } diff --git a/squirrel_3_0_1_stable/squirrel/sqobject.cpp b/squirrel_3_0_1_stable/squirrel/sqobject.cpp index 418a6d656..e32cd72b9 100644 --- a/squirrel_3_0_1_stable/squirrel/sqobject.cpp +++ b/squirrel_3_0_1_stable/squirrel/sqobject.cpp @@ -1,655 +1,655 @@ -/*
- see copyright notice in squirrel.h
-*/
-#include "sqpcheader.h"
-#include "sqvm.h"
-#include "sqstring.h"
-#include "sqarray.h"
-#include "sqtable.h"
-#include "squserdata.h"
-#include "sqfuncproto.h"
-#include "sqclass.h"
-#include "sqclosure.h"
-
-
-const SQChar *IdType2Name(SQObjectType type)
-{
- switch(_RAW_TYPE(type))
- {
- case _RT_NULL:return _SC("null");
- case _RT_INTEGER:return _SC("integer");
- case _RT_FLOAT:return _SC("float");
- case _RT_BOOL:return _SC("bool");
- case _RT_STRING:return _SC("string");
- case _RT_TABLE:return _SC("table");
- case _RT_ARRAY:return _SC("array");
- case _RT_GENERATOR:return _SC("generator");
- case _RT_CLOSURE:
- case _RT_NATIVECLOSURE:
- return _SC("function");
- case _RT_USERDATA:
- case _RT_USERPOINTER:
- return _SC("userdata");
- case _RT_THREAD: return _SC("thread");
- case _RT_FUNCPROTO: return _SC("function");
- case _RT_CLASS: return _SC("class");
- case _RT_INSTANCE: return _SC("instance");
- case _RT_WEAKREF: return _SC("weakref");
- case _RT_OUTER: return _SC("outer");
- default:
- return NULL;
- }
-}
-
-const SQChar *GetTypeName(const SQObjectPtr &obj1)
-{
- return IdType2Name(type(obj1));
-}
-
-SQString *SQString::Create(SQSharedState *ss,const SQChar *s,SQInteger len)
-{
- SQString *str=ADD_STRING(ss,s,len);
- return str;
-}
-
-void SQString::Release()
-{
- REMOVE_STRING(_sharedstate,this);
-}
-
-SQInteger SQString::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval)
-{
- SQInteger idx = (SQInteger)TranslateIndex(refpos);
- while(idx < _len){
- outkey = (SQInteger)idx;
- outval = SQInteger(_val[idx]);
- //return idx for the next iteration
- return ++idx;
- }
- //nothing to iterate anymore
- return -1;
-}
-
-SQUnsignedInteger TranslateIndex(const SQObjectPtr &idx)
-{
- switch(type(idx)){
- case OT_NULL:
- return 0;
- case OT_INTEGER:
- return (SQUnsignedInteger)_integer(idx);
- default: assert(0); break;
- }
- return 0;
-}
-
-SQWeakRef *SQRefCounted::GetWeakRef(SQObjectType type)
-{
- if(!_weakref) {
- sq_new(_weakref,SQWeakRef);
- _weakref->_obj._type = type;
- _weakref->_obj._unVal.pRefCounted = this;
- }
- return _weakref;
-}
-
-SQRefCounted::~SQRefCounted()
-{
- if(_weakref) {
- _weakref->_obj._type = OT_NULL;
- _weakref->_obj._unVal.pRefCounted = NULL;
- }
-}
-
-void SQWeakRef::Release() {
- if(ISREFCOUNTED(_obj._type)) {
- _obj._unVal.pRefCounted->_weakref = NULL;
- }
- sq_delete(this,SQWeakRef);
-}
-
-bool SQDelegable::GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res) {
- if(_delegate) {
- return _delegate->Get((*_ss(v)->_metamethods)[mm],res);
- }
- return false;
-}
-
-bool SQDelegable::SetDelegate(SQTable *mt)
-{
- SQTable *temp = mt;
- if(temp == this) return false;
- while (temp) {
- if (temp->_delegate == this) return false; //cycle detected
- temp = temp->_delegate;
- }
- if (mt) __ObjAddRef(mt);
- __ObjRelease(_delegate);
- _delegate = mt;
- return true;
-}
-
-bool SQGenerator::Yield(SQVM *v,SQInteger target)
-{
- if(_state==eSuspended) { v->Raise_Error(_SC("internal vm error, yielding dead generator")); return false;}
- if(_state==eDead) { v->Raise_Error(_SC("internal vm error, yielding a dead generator")); return false; }
- SQInteger size = v->_top-v->_stackbase;
-
- _stack.resize(size);
- SQObject _this = v->_stack[v->_stackbase];
- _stack._vals[0] = ISREFCOUNTED(type(_this)) ? SQObjectPtr(_refcounted(_this)->GetWeakRef(type(_this))) : _this;
- for(SQInteger n =1; n<target; n++) {
- _stack._vals[n] = v->_stack[v->_stackbase+n];
- }
- for(SQInteger j =0; j < size; j++)
- {
- v->_stack[v->_stackbase+j].Null();
- }
-
- _ci = *v->ci;
- _ci._generator=NULL;
- for(SQInteger i=0;i<_ci._etraps;i++) {
- _etraps.push_back(v->_etraps.top());
- v->_etraps.pop_back();
- }
- _state=eSuspended;
- return true;
-}
-
-bool SQGenerator::Resume(SQVM *v,SQObjectPtr &dest)
-{
- if(_state==eDead){ v->Raise_Error(_SC("resuming dead generator")); return false; }
- if(_state==eRunning){ v->Raise_Error(_SC("resuming active generator")); return false; }
- SQInteger size = _stack.size();
- SQInteger target = &dest - &(v->_stack._vals[v->_stackbase]);
- assert(target>=0 && target<=255);
- if(!v->EnterFrame(v->_top, v->_top + size, false))
- return false;
- v->ci->_generator = this;
- v->ci->_target = (SQInt32)target;
- v->ci->_closure = _ci._closure;
- v->ci->_ip = _ci._ip;
- v->ci->_literals = _ci._literals;
- v->ci->_ncalls = _ci._ncalls;
- v->ci->_etraps = _ci._etraps;
- v->ci->_root = _ci._root;
-
-
- for(SQInteger i=0;i<_ci._etraps;i++) {
- v->_etraps.push_back(_etraps.top());
- _etraps.pop_back();
- }
- SQObject _this = _stack._vals[0];
- v->_stack[v->_stackbase] = type(_this) == OT_WEAKREF ? _weakref(_this)->_obj : _this;
-
- for(SQInteger n = 1; n<size; n++) {
- v->_stack[v->_stackbase+n] = _stack._vals[n];
- _stack._vals[n].Null();
- }
-
- _state=eRunning;
- if (v->_debughook)
- v->CallDebugHook(_SC('c'));
-
- return true;
-}
-
-void SQArray::Extend(const SQArray *a){
- SQInteger xlen;
- if((xlen=a->Size()))
- for(SQInteger i=0;i<xlen;i++)
- Append(a->_values[i]);
-}
-
-const SQChar* SQFunctionProto::GetLocal(SQVM *vm,SQUnsignedInteger stackbase,SQUnsignedInteger nseq,SQUnsignedInteger nop)
-{
- SQUnsignedInteger nvars=_nlocalvarinfos;
- const SQChar *res=NULL;
- if(nvars>=nseq){
- for(SQUnsignedInteger i=0;i<nvars;i++){
- if(_localvarinfos[i]._start_op<=nop && _localvarinfos[i]._end_op>=nop)
- {
- if(nseq==0){
- vm->Push(vm->_stack[stackbase+_localvarinfos[i]._pos]);
- res=_stringval(_localvarinfos[i]._name);
- break;
- }
- nseq--;
- }
- }
- }
- return res;
-}
-
-
-SQInteger SQFunctionProto::GetLine(SQInstruction *curr)
-{
- SQInteger op = (SQInteger)(curr-_instructions);
- SQInteger line=_lineinfos[0]._line;
- SQInteger low = 0;
- SQInteger high = _nlineinfos - 1;
- SQInteger mid = 0;
- while(low <= high)
- {
- mid = low + ((high - low) >> 1);
- SQInteger curop = _lineinfos[mid]._op;
- if(curop > op)
- {
- high = mid - 1;
- }
- else if(curop < op) {
- if(mid < (_nlineinfos - 1)
- && _lineinfos[mid + 1]._op >= op) {
- break;
- }
- low = mid + 1;
- }
- else { //equal
- break;
- }
- }
-
- line = _lineinfos[mid]._line;
- return line;
-}
-
-SQClosure::~SQClosure()
-{
- __ObjRelease(_env);
- __ObjRelease(_base);
- REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);
-}
-
-#define _CHECK_IO(exp) { if(!exp)return false; }
-bool SafeWrite(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,SQUserPointer dest,SQInteger size)
-{
- if(write(up,dest,size) != size) {
- v->Raise_Error(_SC("io error (write function failure)"));
- return false;
- }
- return true;
-}
-
-bool SafeRead(HSQUIRRELVM v,SQWRITEFUNC read,SQUserPointer up,SQUserPointer dest,SQInteger size)
-{
- if(size && read(up,dest,size) != size) {
- v->Raise_Error(_SC("io error, read function failure, the origin stream could be corrupted/trucated"));
- return false;
- }
- return true;
-}
-
-bool WriteTag(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,SQUnsignedInteger32 tag)
-{
- return SafeWrite(v,write,up,&tag,sizeof(tag));
-}
-
-bool CheckTag(HSQUIRRELVM v,SQWRITEFUNC read,SQUserPointer up,SQUnsignedInteger32 tag)
-{
- SQUnsignedInteger32 t;
- _CHECK_IO(SafeRead(v,read,up,&t,sizeof(t)));
- if(t != tag){
- v->Raise_Error(_SC("invalid or corrupted closure stream"));
- return false;
- }
- return true;
-}
-
-bool WriteObject(HSQUIRRELVM v,SQUserPointer up,SQWRITEFUNC write,SQObjectPtr &o)
-{
- SQUnsignedInteger32 _type = (SQUnsignedInteger32)type(o);
- _CHECK_IO(SafeWrite(v,write,up,&_type,sizeof(_type)));
- switch(type(o)){
- case OT_STRING:
- _CHECK_IO(SafeWrite(v,write,up,&_string(o)->_len,sizeof(SQInteger)));
- _CHECK_IO(SafeWrite(v,write,up,_stringval(o),rsl(_string(o)->_len)));
- break;
- case OT_INTEGER:
- _CHECK_IO(SafeWrite(v,write,up,&_integer(o),sizeof(SQInteger)));break;
- case OT_FLOAT:
- _CHECK_IO(SafeWrite(v,write,up,&_float(o),sizeof(SQFloat)));break;
- case OT_NULL:
- break;
- default:
- v->Raise_Error(_SC("cannot serialize a %s"),GetTypeName(o));
- return false;
- }
- return true;
-}
-
-bool ReadObject(HSQUIRRELVM v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &o)
-{
- SQUnsignedInteger32 _type;
- _CHECK_IO(SafeRead(v,read,up,&_type,sizeof(_type)));
- SQObjectType t = (SQObjectType)_type;
- switch(t){
- case OT_STRING:{
- SQInteger len;
- _CHECK_IO(SafeRead(v,read,up,&len,sizeof(SQInteger)));
- _CHECK_IO(SafeRead(v,read,up,_ss(v)->GetScratchPad(rsl(len)),rsl(len)));
- o=SQString::Create(_ss(v),_ss(v)->GetScratchPad(-1),len);
- }
- break;
- case OT_INTEGER:{
- SQInteger i;
- _CHECK_IO(SafeRead(v,read,up,&i,sizeof(SQInteger))); o = i; break;
- }
- case OT_FLOAT:{
- SQFloat f;
- _CHECK_IO(SafeRead(v,read,up,&f,sizeof(SQFloat))); o = f; break;
- }
- case OT_NULL:
- o.Null();
- break;
- default:
- v->Raise_Error(_SC("cannot serialize a %s"),IdType2Name(t));
- return false;
- }
- return true;
-}
-
-bool SQClosure::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write)
-{
- _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_HEAD));
- _CHECK_IO(WriteTag(v,write,up,sizeof(SQChar)));
- _CHECK_IO(WriteTag(v,write,up,sizeof(SQInteger)));
- _CHECK_IO(WriteTag(v,write,up,sizeof(SQFloat)));
- _CHECK_IO(_function->Save(v,up,write));
- _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_TAIL));
- return true;
-}
-
-bool SQClosure::Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret)
-{
- _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_HEAD));
- _CHECK_IO(CheckTag(v,read,up,sizeof(SQChar)));
- _CHECK_IO(CheckTag(v,read,up,sizeof(SQInteger)));
- _CHECK_IO(CheckTag(v,read,up,sizeof(SQFloat)));
- SQObjectPtr func;
- _CHECK_IO(SQFunctionProto::Load(v,up,read,func));
- _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_TAIL));
- ret = SQClosure::Create(_ss(v),_funcproto(func));
- return true;
-}
-
-SQFunctionProto::SQFunctionProto(SQSharedState *ss)
-{
- _stacksize=0;
- _bgenerator=false;
- INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);
-}
-
-SQFunctionProto::~SQFunctionProto()
-{
- REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);
-}
-
-bool SQFunctionProto::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write)
-{
- SQInteger i,nliterals = _nliterals,nparameters = _nparameters;
- SQInteger noutervalues = _noutervalues,nlocalvarinfos = _nlocalvarinfos;
- SQInteger nlineinfos=_nlineinfos,ninstructions = _ninstructions,nfunctions=_nfunctions;
- SQInteger ndefaultparams = _ndefaultparams;
- _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));
- _CHECK_IO(WriteObject(v,up,write,_sourcename));
- _CHECK_IO(WriteObject(v,up,write,_name));
- _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));
- _CHECK_IO(SafeWrite(v,write,up,&nliterals,sizeof(nliterals)));
- _CHECK_IO(SafeWrite(v,write,up,&nparameters,sizeof(nparameters)));
- _CHECK_IO(SafeWrite(v,write,up,&noutervalues,sizeof(noutervalues)));
- _CHECK_IO(SafeWrite(v,write,up,&nlocalvarinfos,sizeof(nlocalvarinfos)));
- _CHECK_IO(SafeWrite(v,write,up,&nlineinfos,sizeof(nlineinfos)));
- _CHECK_IO(SafeWrite(v,write,up,&ndefaultparams,sizeof(ndefaultparams)));
- _CHECK_IO(SafeWrite(v,write,up,&ninstructions,sizeof(ninstructions)));
- _CHECK_IO(SafeWrite(v,write,up,&nfunctions,sizeof(nfunctions)));
- _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));
- for(i=0;i<nliterals;i++){
- _CHECK_IO(WriteObject(v,up,write,_literals[i]));
- }
-
- _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));
- for(i=0;i<nparameters;i++){
- _CHECK_IO(WriteObject(v,up,write,_parameters[i]));
- }
-
- _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));
- for(i=0;i<noutervalues;i++){
- _CHECK_IO(SafeWrite(v,write,up,&_outervalues[i]._type,sizeof(SQUnsignedInteger)));
- _CHECK_IO(WriteObject(v,up,write,_outervalues[i]._src));
- _CHECK_IO(WriteObject(v,up,write,_outervalues[i]._name));
- }
-
- _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));
- for(i=0;i<nlocalvarinfos;i++){
- SQLocalVarInfo &lvi=_localvarinfos[i];
- _CHECK_IO(WriteObject(v,up,write,lvi._name));
- _CHECK_IO(SafeWrite(v,write,up,&lvi._pos,sizeof(SQUnsignedInteger)));
- _CHECK_IO(SafeWrite(v,write,up,&lvi._start_op,sizeof(SQUnsignedInteger)));
- _CHECK_IO(SafeWrite(v,write,up,&lvi._end_op,sizeof(SQUnsignedInteger)));
- }
-
- _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));
- _CHECK_IO(SafeWrite(v,write,up,_lineinfos,sizeof(SQLineInfo)*nlineinfos));
-
- _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));
- _CHECK_IO(SafeWrite(v,write,up,_defaultparams,sizeof(SQInteger)*ndefaultparams));
-
- _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));
- _CHECK_IO(SafeWrite(v,write,up,_instructions,sizeof(SQInstruction)*ninstructions));
-
- _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART));
- for(i=0;i<nfunctions;i++){
- _CHECK_IO(_funcproto(_functions[i])->Save(v,up,write));
- }
- _CHECK_IO(SafeWrite(v,write,up,&_stacksize,sizeof(_stacksize)));
- _CHECK_IO(SafeWrite(v,write,up,&_bgenerator,sizeof(_bgenerator)));
- _CHECK_IO(SafeWrite(v,write,up,&_varparams,sizeof(_varparams)));
- return true;
-}
-
-bool SQFunctionProto::Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret)
-{
- SQInteger i, nliterals,nparameters;
- SQInteger noutervalues ,nlocalvarinfos ;
- SQInteger nlineinfos,ninstructions ,nfunctions,ndefaultparams ;
- SQObjectPtr sourcename, name;
- SQObjectPtr o;
- _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));
- _CHECK_IO(ReadObject(v, up, read, sourcename));
- _CHECK_IO(ReadObject(v, up, read, name));
-
- _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));
- _CHECK_IO(SafeRead(v,read,up, &nliterals, sizeof(nliterals)));
- _CHECK_IO(SafeRead(v,read,up, &nparameters, sizeof(nparameters)));
- _CHECK_IO(SafeRead(v,read,up, &noutervalues, sizeof(noutervalues)));
- _CHECK_IO(SafeRead(v,read,up, &nlocalvarinfos, sizeof(nlocalvarinfos)));
- _CHECK_IO(SafeRead(v,read,up, &nlineinfos, sizeof(nlineinfos)));
- _CHECK_IO(SafeRead(v,read,up, &ndefaultparams, sizeof(ndefaultparams)));
- _CHECK_IO(SafeRead(v,read,up, &ninstructions, sizeof(ninstructions)));
- _CHECK_IO(SafeRead(v,read,up, &nfunctions, sizeof(nfunctions)));
-
-
- SQFunctionProto *f = SQFunctionProto::Create(_opt_ss(v),ninstructions,nliterals,nparameters,
- nfunctions,noutervalues,nlineinfos,nlocalvarinfos,ndefaultparams);
- SQObjectPtr proto = f; //gets a ref in case of failure
- f->_sourcename = sourcename;
- f->_name = name;
-
- _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));
-
- for(i = 0;i < nliterals; i++){
- _CHECK_IO(ReadObject(v, up, read, o));
- f->_literals[i] = o;
- }
- _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));
-
- for(i = 0; i < nparameters; i++){
- _CHECK_IO(ReadObject(v, up, read, o));
- f->_parameters[i] = o;
- }
- _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));
-
- for(i = 0; i < noutervalues; i++){
- SQUnsignedInteger type;
- SQObjectPtr name;
- _CHECK_IO(SafeRead(v,read,up, &type, sizeof(SQUnsignedInteger)));
- _CHECK_IO(ReadObject(v, up, read, o));
- _CHECK_IO(ReadObject(v, up, read, name));
- f->_outervalues[i] = SQOuterVar(name,o, (SQOuterType)type);
- }
- _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));
-
- for(i = 0; i < nlocalvarinfos; i++){
- SQLocalVarInfo lvi;
- _CHECK_IO(ReadObject(v, up, read, lvi._name));
- _CHECK_IO(SafeRead(v,read,up, &lvi._pos, sizeof(SQUnsignedInteger)));
- _CHECK_IO(SafeRead(v,read,up, &lvi._start_op, sizeof(SQUnsignedInteger)));
- _CHECK_IO(SafeRead(v,read,up, &lvi._end_op, sizeof(SQUnsignedInteger)));
- f->_localvarinfos[i] = lvi;
- }
- _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));
- _CHECK_IO(SafeRead(v,read,up, f->_lineinfos, sizeof(SQLineInfo)*nlineinfos));
-
- _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));
- _CHECK_IO(SafeRead(v,read,up, f->_defaultparams, sizeof(SQInteger)*ndefaultparams));
-
- _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));
- _CHECK_IO(SafeRead(v,read,up, f->_instructions, sizeof(SQInstruction)*ninstructions));
-
- _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART));
- for(i = 0; i < nfunctions; i++){
- _CHECK_IO(_funcproto(o)->Load(v, up, read, o));
- f->_functions[i] = o;
- }
- _CHECK_IO(SafeRead(v,read,up, &f->_stacksize, sizeof(f->_stacksize)));
- _CHECK_IO(SafeRead(v,read,up, &f->_bgenerator, sizeof(f->_bgenerator)));
- _CHECK_IO(SafeRead(v,read,up, &f->_varparams, sizeof(f->_varparams)));
-
- ret = f;
- return true;
-}
-
-#ifndef NO_GARBAGE_COLLECTOR
-
-#define START_MARK() if(!(_uiRef&MARK_FLAG)){ \
- _uiRef|=MARK_FLAG;
-
-#define END_MARK() RemoveFromChain(&_sharedstate->_gc_chain, this); \
- AddToChain(chain, this); }
-
-void SQVM::Mark(SQCollectable **chain)
-{
- START_MARK()
- SQSharedState::MarkObject(_lasterror,chain);
- SQSharedState::MarkObject(_errorhandler,chain);
- SQSharedState::MarkObject(_debughook_closure,chain);
- SQSharedState::MarkObject(_roottable, chain);
- SQSharedState::MarkObject(temp_reg, chain);
- for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain);
- for(SQInteger k = 0; k < _callsstacksize; k++) SQSharedState::MarkObject(_callsstack[k]._closure, chain);
- END_MARK()
-}
-
-void SQArray::Mark(SQCollectable **chain)
-{
- START_MARK()
- SQInteger len = _values.size();
- for(SQInteger i = 0;i < len; i++) SQSharedState::MarkObject(_values[i], chain);
- END_MARK()
-}
-void SQTable::Mark(SQCollectable **chain)
-{
- START_MARK()
- if(_delegate) _delegate->Mark(chain);
- SQInteger len = _numofnodes;
- for(SQInteger i = 0; i < len; i++){
- SQSharedState::MarkObject(_nodes[i].key, chain);
- SQSharedState::MarkObject(_nodes[i].val, chain);
- }
- END_MARK()
-}
-
-void SQClass::Mark(SQCollectable **chain)
-{
- START_MARK()
- _members->Mark(chain);
- if(_base) _base->Mark(chain);
- SQSharedState::MarkObject(_attributes, chain);
- for(SQUnsignedInteger i =0; i< _defaultvalues.size(); i++) {
- SQSharedState::MarkObject(_defaultvalues[i].val, chain);
- SQSharedState::MarkObject(_defaultvalues[i].attrs, chain);
- }
- for(SQUnsignedInteger j =0; j< _methods.size(); j++) {
- SQSharedState::MarkObject(_methods[j].val, chain);
- SQSharedState::MarkObject(_methods[j].attrs, chain);
- }
- for(SQUnsignedInteger k =0; k< MT_LAST; k++) {
- SQSharedState::MarkObject(_metamethods[k], chain);
- }
- END_MARK()
-}
-
-void SQInstance::Mark(SQCollectable **chain)
-{
- START_MARK()
- _class->Mark(chain);
- SQUnsignedInteger nvalues = _class->_defaultvalues.size();
- for(SQUnsignedInteger i =0; i< nvalues; i++) {
- SQSharedState::MarkObject(_values[i], chain);
- }
- END_MARK()
-}
-
-void SQGenerator::Mark(SQCollectable **chain)
-{
- START_MARK()
- for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain);
- SQSharedState::MarkObject(_closure, chain);
- END_MARK()
-}
-
-void SQFunctionProto::Mark(SQCollectable **chain)
-{
- START_MARK()
- for(SQInteger i = 0; i < _nliterals; i++) SQSharedState::MarkObject(_literals[i], chain);
- for(SQInteger k = 0; k < _nfunctions; k++) SQSharedState::MarkObject(_functions[k], chain);
- END_MARK()
-}
-
-void SQClosure::Mark(SQCollectable **chain)
-{
- START_MARK()
- if(_base) _base->Mark(chain);
- SQFunctionProto *fp = _function;
- fp->Mark(chain);
- for(SQInteger i = 0; i < fp->_noutervalues; i++) SQSharedState::MarkObject(_outervalues[i], chain);
- for(SQInteger k = 0; k < fp->_ndefaultparams; k++) SQSharedState::MarkObject(_defaultparams[k], chain);
- END_MARK()
-}
-
-void SQNativeClosure::Mark(SQCollectable **chain)
-{
- START_MARK()
- for(SQUnsignedInteger i = 0; i < _noutervalues; i++) SQSharedState::MarkObject(_outervalues[i], chain);
- END_MARK()
-}
-
-void SQOuter::Mark(SQCollectable **chain)
-{
- START_MARK()
- /* If the valptr points to a closed value, that value is alive */
- if(_valptr == &_value) {
- SQSharedState::MarkObject(_value, chain);
- }
- END_MARK()
-}
-
-void SQUserData::Mark(SQCollectable **chain){
- START_MARK()
- if(_delegate) _delegate->Mark(chain);
- END_MARK()
-}
-
-void SQCollectable::UnMark() { _uiRef&=~MARK_FLAG; }
-
-#endif
-
+/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include "sqvm.h" +#include "sqstring.h" +#include "sqarray.h" +#include "sqtable.h" +#include "squserdata.h" +#include "sqfuncproto.h" +#include "sqclass.h" +#include "sqclosure.h" + + +const SQChar *IdType2Name(SQObjectType type) +{ + switch(_RAW_TYPE(type)) + { + case _RT_NULL:return _SC("null"); + case _RT_INTEGER:return _SC("integer"); + case _RT_FLOAT:return _SC("float"); + case _RT_BOOL:return _SC("bool"); + case _RT_STRING:return _SC("string"); + case _RT_TABLE:return _SC("table"); + case _RT_ARRAY:return _SC("array"); + case _RT_GENERATOR:return _SC("generator"); + case _RT_CLOSURE: + case _RT_NATIVECLOSURE: + return _SC("function"); + case _RT_USERDATA: + case _RT_USERPOINTER: + return _SC("userdata"); + case _RT_THREAD: return _SC("thread"); + case _RT_FUNCPROTO: return _SC("function"); + case _RT_CLASS: return _SC("class"); + case _RT_INSTANCE: return _SC("instance"); + case _RT_WEAKREF: return _SC("weakref"); + case _RT_OUTER: return _SC("outer"); + default: + return NULL; + } +} + +const SQChar *GetTypeName(const SQObjectPtr &obj1) +{ + return IdType2Name(type(obj1)); +} + +SQString *SQString::Create(SQSharedState *ss,const SQChar *s,SQInteger len) +{ + SQString *str=ADD_STRING(ss,s,len); + return str; +} + +void SQString::Release() +{ + REMOVE_STRING(_sharedstate,this); +} + +SQInteger SQString::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval) +{ + SQInteger idx = (SQInteger)TranslateIndex(refpos); + while(idx < _len){ + outkey = (SQInteger)idx; + outval = SQInteger(_val[idx]); + //return idx for the next iteration + return ++idx; + } + //nothing to iterate anymore + return -1; +} + +SQUnsignedInteger TranslateIndex(const SQObjectPtr &idx) +{ + switch(type(idx)){ + case OT_NULL: + return 0; + case OT_INTEGER: + return (SQUnsignedInteger)_integer(idx); + default: assert(0); break; + } + return 0; +} + +SQWeakRef *SQRefCounted::GetWeakRef(SQObjectType type) +{ + if(!_weakref) { + sq_new(_weakref,SQWeakRef); + _weakref->_obj._type = type; + _weakref->_obj._unVal.pRefCounted = this; + } + return _weakref; +} + +SQRefCounted::~SQRefCounted() +{ + if(_weakref) { + _weakref->_obj._type = OT_NULL; + _weakref->_obj._unVal.pRefCounted = NULL; + } +} + +void SQWeakRef::Release() { + if(ISREFCOUNTED(_obj._type)) { + _obj._unVal.pRefCounted->_weakref = NULL; + } + sq_delete(this,SQWeakRef); +} + +bool SQDelegable::GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res) { + if(_delegate) { + return _delegate->Get((*_ss(v)->_metamethods)[mm],res); + } + return false; +} + +bool SQDelegable::SetDelegate(SQTable *mt) +{ + SQTable *temp = mt; + if(temp == this) return false; + while (temp) { + if (temp->_delegate == this) return false; //cycle detected + temp = temp->_delegate; + } + if (mt) __ObjAddRef(mt); + __ObjRelease(_delegate); + _delegate = mt; + return true; +} + +bool SQGenerator::Yield(SQVM *v,SQInteger target) +{ + if(_state==eSuspended) { v->Raise_Error(_SC("internal vm error, yielding dead generator")); return false;} + if(_state==eDead) { v->Raise_Error(_SC("internal vm error, yielding a dead generator")); return false; } + SQInteger size = v->_top-v->_stackbase; + + _stack.resize(size); + SQObject _this = v->_stack[v->_stackbase]; + _stack._vals[0] = ISREFCOUNTED(type(_this)) ? SQObjectPtr(_refcounted(_this)->GetWeakRef(type(_this))) : _this; + for(SQInteger n =1; n<target; n++) { + _stack._vals[n] = v->_stack[v->_stackbase+n]; + } + for(SQInteger j =0; j < size; j++) + { + v->_stack[v->_stackbase+j].Null(); + } + + _ci = *v->ci; + _ci._generator=NULL; + for(SQInteger i=0;i<_ci._etraps;i++) { + _etraps.push_back(v->_etraps.top()); + v->_etraps.pop_back(); + } + _state=eSuspended; + return true; +} + +bool SQGenerator::Resume(SQVM *v,SQObjectPtr &dest) +{ + if(_state==eDead){ v->Raise_Error(_SC("resuming dead generator")); return false; } + if(_state==eRunning){ v->Raise_Error(_SC("resuming active generator")); return false; } + SQInteger size = _stack.size(); + SQInteger target = &dest - &(v->_stack._vals[v->_stackbase]); + assert(target>=0 && target<=255); + if(!v->EnterFrame(v->_top, v->_top + size, false)) + return false; + v->ci->_generator = this; + v->ci->_target = (SQInt32)target; + v->ci->_closure = _ci._closure; + v->ci->_ip = _ci._ip; + v->ci->_literals = _ci._literals; + v->ci->_ncalls = _ci._ncalls; + v->ci->_etraps = _ci._etraps; + v->ci->_root = _ci._root; + + + for(SQInteger i=0;i<_ci._etraps;i++) { + v->_etraps.push_back(_etraps.top()); + _etraps.pop_back(); + } + SQObject _this = _stack._vals[0]; + v->_stack[v->_stackbase] = type(_this) == OT_WEAKREF ? _weakref(_this)->_obj : _this; + + for(SQInteger n = 1; n<size; n++) { + v->_stack[v->_stackbase+n] = _stack._vals[n]; + _stack._vals[n].Null(); + } + + _state=eRunning; + if (v->_debughook) + v->CallDebugHook(_SC('c')); + + return true; +} + +void SQArray::Extend(const SQArray *a){ + SQInteger xlen; + if((xlen=a->Size())) + for(SQInteger i=0;i<xlen;i++) + Append(a->_values[i]); +} + +const SQChar* SQFunctionProto::GetLocal(SQVM *vm,SQUnsignedInteger stackbase,SQUnsignedInteger nseq,SQUnsignedInteger nop) +{ + SQUnsignedInteger nvars=_nlocalvarinfos; + const SQChar *res=NULL; + if(nvars>=nseq){ + for(SQUnsignedInteger i=0;i<nvars;i++){ + if(_localvarinfos[i]._start_op<=nop && _localvarinfos[i]._end_op>=nop) + { + if(nseq==0){ + vm->Push(vm->_stack[stackbase+_localvarinfos[i]._pos]); + res=_stringval(_localvarinfos[i]._name); + break; + } + nseq--; + } + } + } + return res; +} + + +SQInteger SQFunctionProto::GetLine(SQInstruction *curr) +{ + SQInteger op = (SQInteger)(curr-_instructions); + SQInteger line=_lineinfos[0]._line; + SQInteger low = 0; + SQInteger high = _nlineinfos - 1; + SQInteger mid = 0; + while(low <= high) + { + mid = low + ((high - low) >> 1); + SQInteger curop = _lineinfos[mid]._op; + if(curop > op) + { + high = mid - 1; + } + else if(curop < op) { + if(mid < (_nlineinfos - 1) + && _lineinfos[mid + 1]._op >= op) { + break; + } + low = mid + 1; + } + else { //equal + break; + } + } + + line = _lineinfos[mid]._line; + return line; +} + +SQClosure::~SQClosure() +{ + __ObjRelease(_env); + __ObjRelease(_base); + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); +} + +#define _CHECK_IO(exp) { if(!exp)return false; } +bool SafeWrite(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,SQUserPointer dest,SQInteger size) +{ + if(write(up,dest,size) != size) { + v->Raise_Error(_SC("io error (write function failure)")); + return false; + } + return true; +} + +bool SafeRead(HSQUIRRELVM v,SQWRITEFUNC read,SQUserPointer up,SQUserPointer dest,SQInteger size) +{ + if(size && read(up,dest,size) != size) { + v->Raise_Error(_SC("io error, read function failure, the origin stream could be corrupted/trucated")); + return false; + } + return true; +} + +bool WriteTag(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,SQUnsignedInteger32 tag) +{ + return SafeWrite(v,write,up,&tag,sizeof(tag)); +} + +bool CheckTag(HSQUIRRELVM v,SQWRITEFUNC read,SQUserPointer up,SQUnsignedInteger32 tag) +{ + SQUnsignedInteger32 t; + _CHECK_IO(SafeRead(v,read,up,&t,sizeof(t))); + if(t != tag){ + v->Raise_Error(_SC("invalid or corrupted closure stream")); + return false; + } + return true; +} + +bool WriteObject(HSQUIRRELVM v,SQUserPointer up,SQWRITEFUNC write,SQObjectPtr &o) +{ + SQUnsignedInteger32 _type = (SQUnsignedInteger32)type(o); + _CHECK_IO(SafeWrite(v,write,up,&_type,sizeof(_type))); + switch(type(o)){ + case OT_STRING: + _CHECK_IO(SafeWrite(v,write,up,&_string(o)->_len,sizeof(SQInteger))); + _CHECK_IO(SafeWrite(v,write,up,_stringval(o),rsl(_string(o)->_len))); + break; + case OT_INTEGER: + _CHECK_IO(SafeWrite(v,write,up,&_integer(o),sizeof(SQInteger)));break; + case OT_FLOAT: + _CHECK_IO(SafeWrite(v,write,up,&_float(o),sizeof(SQFloat)));break; + case OT_NULL: + break; + default: + v->Raise_Error(_SC("cannot serialize a %s"),GetTypeName(o)); + return false; + } + return true; +} + +bool ReadObject(HSQUIRRELVM v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &o) +{ + SQUnsignedInteger32 _type; + _CHECK_IO(SafeRead(v,read,up,&_type,sizeof(_type))); + SQObjectType t = (SQObjectType)_type; + switch(t){ + case OT_STRING:{ + SQInteger len; + _CHECK_IO(SafeRead(v,read,up,&len,sizeof(SQInteger))); + _CHECK_IO(SafeRead(v,read,up,_ss(v)->GetScratchPad(rsl(len)),rsl(len))); + o=SQString::Create(_ss(v),_ss(v)->GetScratchPad(-1),len); + } + break; + case OT_INTEGER:{ + SQInteger i; + _CHECK_IO(SafeRead(v,read,up,&i,sizeof(SQInteger))); o = i; break; + } + case OT_FLOAT:{ + SQFloat f; + _CHECK_IO(SafeRead(v,read,up,&f,sizeof(SQFloat))); o = f; break; + } + case OT_NULL: + o.Null(); + break; + default: + v->Raise_Error(_SC("cannot serialize a %s"),IdType2Name(t)); + return false; + } + return true; +} + +bool SQClosure::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write) +{ + _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_HEAD)); + _CHECK_IO(WriteTag(v,write,up,sizeof(SQChar))); + _CHECK_IO(WriteTag(v,write,up,sizeof(SQInteger))); + _CHECK_IO(WriteTag(v,write,up,sizeof(SQFloat))); + _CHECK_IO(_function->Save(v,up,write)); + _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_TAIL)); + return true; +} + +bool SQClosure::Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret) +{ + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_HEAD)); + _CHECK_IO(CheckTag(v,read,up,sizeof(SQChar))); + _CHECK_IO(CheckTag(v,read,up,sizeof(SQInteger))); + _CHECK_IO(CheckTag(v,read,up,sizeof(SQFloat))); + SQObjectPtr func; + _CHECK_IO(SQFunctionProto::Load(v,up,read,func)); + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_TAIL)); + ret = SQClosure::Create(_ss(v),_funcproto(func)); + return true; +} + +SQFunctionProto::SQFunctionProto(SQSharedState *ss) +{ + _stacksize=0; + _bgenerator=false; + INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); +} + +SQFunctionProto::~SQFunctionProto() +{ + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); +} + +bool SQFunctionProto::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write) +{ + SQInteger i,nliterals = _nliterals,nparameters = _nparameters; + SQInteger noutervalues = _noutervalues,nlocalvarinfos = _nlocalvarinfos; + SQInteger nlineinfos=_nlineinfos,ninstructions = _ninstructions,nfunctions=_nfunctions; + SQInteger ndefaultparams = _ndefaultparams; + _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(WriteObject(v,up,write,_sourcename)); + _CHECK_IO(WriteObject(v,up,write,_name)); + _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeWrite(v,write,up,&nliterals,sizeof(nliterals))); + _CHECK_IO(SafeWrite(v,write,up,&nparameters,sizeof(nparameters))); + _CHECK_IO(SafeWrite(v,write,up,&noutervalues,sizeof(noutervalues))); + _CHECK_IO(SafeWrite(v,write,up,&nlocalvarinfos,sizeof(nlocalvarinfos))); + _CHECK_IO(SafeWrite(v,write,up,&nlineinfos,sizeof(nlineinfos))); + _CHECK_IO(SafeWrite(v,write,up,&ndefaultparams,sizeof(ndefaultparams))); + _CHECK_IO(SafeWrite(v,write,up,&ninstructions,sizeof(ninstructions))); + _CHECK_IO(SafeWrite(v,write,up,&nfunctions,sizeof(nfunctions))); + _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART)); + for(i=0;i<nliterals;i++){ + _CHECK_IO(WriteObject(v,up,write,_literals[i])); + } + + _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART)); + for(i=0;i<nparameters;i++){ + _CHECK_IO(WriteObject(v,up,write,_parameters[i])); + } + + _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART)); + for(i=0;i<noutervalues;i++){ + _CHECK_IO(SafeWrite(v,write,up,&_outervalues[i]._type,sizeof(SQUnsignedInteger))); + _CHECK_IO(WriteObject(v,up,write,_outervalues[i]._src)); + _CHECK_IO(WriteObject(v,up,write,_outervalues[i]._name)); + } + + _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART)); + for(i=0;i<nlocalvarinfos;i++){ + SQLocalVarInfo &lvi=_localvarinfos[i]; + _CHECK_IO(WriteObject(v,up,write,lvi._name)); + _CHECK_IO(SafeWrite(v,write,up,&lvi._pos,sizeof(SQUnsignedInteger))); + _CHECK_IO(SafeWrite(v,write,up,&lvi._start_op,sizeof(SQUnsignedInteger))); + _CHECK_IO(SafeWrite(v,write,up,&lvi._end_op,sizeof(SQUnsignedInteger))); + } + + _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeWrite(v,write,up,_lineinfos,sizeof(SQLineInfo)*nlineinfos)); + + _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeWrite(v,write,up,_defaultparams,sizeof(SQInteger)*ndefaultparams)); + + _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeWrite(v,write,up,_instructions,sizeof(SQInstruction)*ninstructions)); + + _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART)); + for(i=0;i<nfunctions;i++){ + _CHECK_IO(_funcproto(_functions[i])->Save(v,up,write)); + } + _CHECK_IO(SafeWrite(v,write,up,&_stacksize,sizeof(_stacksize))); + _CHECK_IO(SafeWrite(v,write,up,&_bgenerator,sizeof(_bgenerator))); + _CHECK_IO(SafeWrite(v,write,up,&_varparams,sizeof(_varparams))); + return true; +} + +bool SQFunctionProto::Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret) +{ + SQInteger i, nliterals,nparameters; + SQInteger noutervalues ,nlocalvarinfos ; + SQInteger nlineinfos,ninstructions ,nfunctions,ndefaultparams ; + SQObjectPtr sourcename, name; + SQObjectPtr o; + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(ReadObject(v, up, read, sourcename)); + _CHECK_IO(ReadObject(v, up, read, name)); + + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up, &nliterals, sizeof(nliterals))); + _CHECK_IO(SafeRead(v,read,up, &nparameters, sizeof(nparameters))); + _CHECK_IO(SafeRead(v,read,up, &noutervalues, sizeof(noutervalues))); + _CHECK_IO(SafeRead(v,read,up, &nlocalvarinfos, sizeof(nlocalvarinfos))); + _CHECK_IO(SafeRead(v,read,up, &nlineinfos, sizeof(nlineinfos))); + _CHECK_IO(SafeRead(v,read,up, &ndefaultparams, sizeof(ndefaultparams))); + _CHECK_IO(SafeRead(v,read,up, &ninstructions, sizeof(ninstructions))); + _CHECK_IO(SafeRead(v,read,up, &nfunctions, sizeof(nfunctions))); + + + SQFunctionProto *f = SQFunctionProto::Create(_opt_ss(v),ninstructions,nliterals,nparameters, + nfunctions,noutervalues,nlineinfos,nlocalvarinfos,ndefaultparams); + SQObjectPtr proto = f; //gets a ref in case of failure + f->_sourcename = sourcename; + f->_name = name; + + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + + for(i = 0;i < nliterals; i++){ + _CHECK_IO(ReadObject(v, up, read, o)); + f->_literals[i] = o; + } + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + + for(i = 0; i < nparameters; i++){ + _CHECK_IO(ReadObject(v, up, read, o)); + f->_parameters[i] = o; + } + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + + for(i = 0; i < noutervalues; i++){ + SQUnsignedInteger type; + SQObjectPtr name; + _CHECK_IO(SafeRead(v,read,up, &type, sizeof(SQUnsignedInteger))); + _CHECK_IO(ReadObject(v, up, read, o)); + _CHECK_IO(ReadObject(v, up, read, name)); + f->_outervalues[i] = SQOuterVar(name,o, (SQOuterType)type); + } + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + + for(i = 0; i < nlocalvarinfos; i++){ + SQLocalVarInfo lvi; + _CHECK_IO(ReadObject(v, up, read, lvi._name)); + _CHECK_IO(SafeRead(v,read,up, &lvi._pos, sizeof(SQUnsignedInteger))); + _CHECK_IO(SafeRead(v,read,up, &lvi._start_op, sizeof(SQUnsignedInteger))); + _CHECK_IO(SafeRead(v,read,up, &lvi._end_op, sizeof(SQUnsignedInteger))); + f->_localvarinfos[i] = lvi; + } + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up, f->_lineinfos, sizeof(SQLineInfo)*nlineinfos)); + + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up, f->_defaultparams, sizeof(SQInteger)*ndefaultparams)); + + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up, f->_instructions, sizeof(SQInstruction)*ninstructions)); + + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + for(i = 0; i < nfunctions; i++){ + _CHECK_IO(_funcproto(o)->Load(v, up, read, o)); + f->_functions[i] = o; + } + _CHECK_IO(SafeRead(v,read,up, &f->_stacksize, sizeof(f->_stacksize))); + _CHECK_IO(SafeRead(v,read,up, &f->_bgenerator, sizeof(f->_bgenerator))); + _CHECK_IO(SafeRead(v,read,up, &f->_varparams, sizeof(f->_varparams))); + + ret = f; + return true; +} + +#ifndef NO_GARBAGE_COLLECTOR + +#define START_MARK() if(!(_uiRef&MARK_FLAG)){ \ + _uiRef|=MARK_FLAG; + +#define END_MARK() RemoveFromChain(&_sharedstate->_gc_chain, this); \ + AddToChain(chain, this); } + +void SQVM::Mark(SQCollectable **chain) +{ + START_MARK() + SQSharedState::MarkObject(_lasterror,chain); + SQSharedState::MarkObject(_errorhandler,chain); + SQSharedState::MarkObject(_debughook_closure,chain); + SQSharedState::MarkObject(_roottable, chain); + SQSharedState::MarkObject(temp_reg, chain); + for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain); + for(SQInteger k = 0; k < _callsstacksize; k++) SQSharedState::MarkObject(_callsstack[k]._closure, chain); + END_MARK() +} + +void SQArray::Mark(SQCollectable **chain) +{ + START_MARK() + SQInteger len = _values.size(); + for(SQInteger i = 0;i < len; i++) SQSharedState::MarkObject(_values[i], chain); + END_MARK() +} +void SQTable::Mark(SQCollectable **chain) +{ + START_MARK() + if(_delegate) _delegate->Mark(chain); + SQInteger len = _numofnodes; + for(SQInteger i = 0; i < len; i++){ + SQSharedState::MarkObject(_nodes[i].key, chain); + SQSharedState::MarkObject(_nodes[i].val, chain); + } + END_MARK() +} + +void SQClass::Mark(SQCollectable **chain) +{ + START_MARK() + _members->Mark(chain); + if(_base) _base->Mark(chain); + SQSharedState::MarkObject(_attributes, chain); + for(SQUnsignedInteger i =0; i< _defaultvalues.size(); i++) { + SQSharedState::MarkObject(_defaultvalues[i].val, chain); + SQSharedState::MarkObject(_defaultvalues[i].attrs, chain); + } + for(SQUnsignedInteger j =0; j< _methods.size(); j++) { + SQSharedState::MarkObject(_methods[j].val, chain); + SQSharedState::MarkObject(_methods[j].attrs, chain); + } + for(SQUnsignedInteger k =0; k< MT_LAST; k++) { + SQSharedState::MarkObject(_metamethods[k], chain); + } + END_MARK() +} + +void SQInstance::Mark(SQCollectable **chain) +{ + START_MARK() + _class->Mark(chain); + SQUnsignedInteger nvalues = _class->_defaultvalues.size(); + for(SQUnsignedInteger i =0; i< nvalues; i++) { + SQSharedState::MarkObject(_values[i], chain); + } + END_MARK() +} + +void SQGenerator::Mark(SQCollectable **chain) +{ + START_MARK() + for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain); + SQSharedState::MarkObject(_closure, chain); + END_MARK() +} + +void SQFunctionProto::Mark(SQCollectable **chain) +{ + START_MARK() + for(SQInteger i = 0; i < _nliterals; i++) SQSharedState::MarkObject(_literals[i], chain); + for(SQInteger k = 0; k < _nfunctions; k++) SQSharedState::MarkObject(_functions[k], chain); + END_MARK() +} + +void SQClosure::Mark(SQCollectable **chain) +{ + START_MARK() + if(_base) _base->Mark(chain); + SQFunctionProto *fp = _function; + fp->Mark(chain); + for(SQInteger i = 0; i < fp->_noutervalues; i++) SQSharedState::MarkObject(_outervalues[i], chain); + for(SQInteger k = 0; k < fp->_ndefaultparams; k++) SQSharedState::MarkObject(_defaultparams[k], chain); + END_MARK() +} + +void SQNativeClosure::Mark(SQCollectable **chain) +{ + START_MARK() + for(SQUnsignedInteger i = 0; i < _noutervalues; i++) SQSharedState::MarkObject(_outervalues[i], chain); + END_MARK() +} + +void SQOuter::Mark(SQCollectable **chain) +{ + START_MARK() + /* If the valptr points to a closed value, that value is alive */ + if(_valptr == &_value) { + SQSharedState::MarkObject(_value, chain); + } + END_MARK() +} + +void SQUserData::Mark(SQCollectable **chain){ + START_MARK() + if(_delegate) _delegate->Mark(chain); + END_MARK() +} + +void SQCollectable::UnMark() { _uiRef&=~MARK_FLAG; } + +#endif + diff --git a/squirrel_3_0_1_stable/squirrel/sqobject.h b/squirrel_3_0_1_stable/squirrel/sqobject.h index a7d1e1ed3..2b85e24c3 100644 --- a/squirrel_3_0_1_stable/squirrel/sqobject.h +++ b/squirrel_3_0_1_stable/squirrel/sqobject.h @@ -1,354 +1,354 @@ -/* see copyright notice in squirrel.h */
-#ifndef _SQOBJECT_H_
-#define _SQOBJECT_H_
-
-#include "squtils.h"
-
-#ifdef _SQ64
-#define UINT_MINUS_ONE (0xFFFFFFFFFFFFFFFF)
-#else
-#define UINT_MINUS_ONE (0xFFFFFFFF)
-#endif
-
-#define SQ_CLOSURESTREAM_HEAD (('S'<<24)|('Q'<<16)|('I'<<8)|('R'))
-#define SQ_CLOSURESTREAM_PART (('P'<<24)|('A'<<16)|('R'<<8)|('T'))
-#define SQ_CLOSURESTREAM_TAIL (('T'<<24)|('A'<<16)|('I'<<8)|('L'))
-
-struct SQSharedState;
-
-enum SQMetaMethod{
- MT_ADD=0,
- MT_SUB=1,
- MT_MUL=2,
- MT_DIV=3,
- MT_UNM=4,
- MT_MODULO=5,
- MT_SET=6,
- MT_GET=7,
- MT_TYPEOF=8,
- MT_NEXTI=9,
- MT_CMP=10,
- MT_CALL=11,
- MT_CLONED=12,
- MT_NEWSLOT=13,
- MT_DELSLOT=14,
- MT_TOSTRING=15,
- MT_NEWMEMBER=16,
- MT_INHERITED=17,
- MT_LAST = 18
-};
-
-#define MM_ADD _SC("_add")
-#define MM_SUB _SC("_sub")
-#define MM_MUL _SC("_mul")
-#define MM_DIV _SC("_div")
-#define MM_UNM _SC("_unm")
-#define MM_MODULO _SC("_modulo")
-#define MM_SET _SC("_set")
-#define MM_GET _SC("_get")
-#define MM_TYPEOF _SC("_typeof")
-#define MM_NEXTI _SC("_nexti")
-#define MM_CMP _SC("_cmp")
-#define MM_CALL _SC("_call")
-#define MM_CLONED _SC("_cloned")
-#define MM_NEWSLOT _SC("_newslot")
-#define MM_DELSLOT _SC("_delslot")
-#define MM_TOSTRING _SC("_tostring")
-#define MM_NEWMEMBER _SC("_newmember")
-#define MM_INHERITED _SC("_inherited")
-
-
-#define _CONSTRUCT_VECTOR(type,size,ptr) { \
- for(SQInteger n = 0; n < ((SQInteger)size); n++) { \
- new (&ptr[n]) type(); \
- } \
-}
-
-#define _DESTRUCT_VECTOR(type,size,ptr) { \
- for(SQInteger nl = 0; nl < ((SQInteger)size); nl++) { \
- ptr[nl].~type(); \
- } \
-}
-
-#define _COPY_VECTOR(dest,src,size) { \
- for(SQInteger _n_ = 0; _n_ < ((SQInteger)size); _n_++) { \
- dest[_n_] = src[_n_]; \
- } \
-}
-
-#define _NULL_SQOBJECT_VECTOR(vec,size) { \
- for(SQInteger _n_ = 0; _n_ < ((SQInteger)size); _n_++) { \
- vec[_n_].Null(); \
- } \
-}
-
-#define MINPOWER2 4
-
-struct SQRefCounted
-{
- SQUnsignedInteger _uiRef;
- struct SQWeakRef *_weakref;
- SQRefCounted() { _uiRef = 0; _weakref = NULL; }
- virtual ~SQRefCounted();
- SQWeakRef *GetWeakRef(SQObjectType type);
- virtual void Release()=0;
-
-};
-
-struct SQWeakRef : SQRefCounted
-{
- void Release();
- SQObject _obj;
-};
-
-#define _realval(o) (type((o)) != OT_WEAKREF?(SQObject)o:_weakref(o)->_obj)
-
-struct SQObjectPtr;
-
-#define __AddRef(type,unval) if(ISREFCOUNTED(type)) \
- { \
- unval.pRefCounted->_uiRef++; \
- }
-
-#define __Release(type,unval) if(ISREFCOUNTED(type) && ((--unval.pRefCounted->_uiRef)==0)) \
- { \
- unval.pRefCounted->Release(); \
- }
-
-#define __ObjRelease(obj) { \
- if((obj)) { \
- (obj)->_uiRef--; \
- if((obj)->_uiRef == 0) \
- (obj)->Release(); \
- (obj) = NULL; \
- } \
-}
-
-#define __ObjAddRef(obj) { \
- (obj)->_uiRef++; \
-}
-
-#define type(obj) ((obj)._type)
-#define is_delegable(t) (type(t)&SQOBJECT_DELEGABLE)
-#define raw_type(obj) _RAW_TYPE((obj)._type)
-
-#define _integer(obj) ((obj)._unVal.nInteger)
-#define _float(obj) ((obj)._unVal.fFloat)
-#define _string(obj) ((obj)._unVal.pString)
-#define _table(obj) ((obj)._unVal.pTable)
-#define _array(obj) ((obj)._unVal.pArray)
-#define _closure(obj) ((obj)._unVal.pClosure)
-#define _generator(obj) ((obj)._unVal.pGenerator)
-#define _nativeclosure(obj) ((obj)._unVal.pNativeClosure)
-#define _userdata(obj) ((obj)._unVal.pUserData)
-#define _userpointer(obj) ((obj)._unVal.pUserPointer)
-#define _thread(obj) ((obj)._unVal.pThread)
-#define _funcproto(obj) ((obj)._unVal.pFunctionProto)
-#define _class(obj) ((obj)._unVal.pClass)
-#define _instance(obj) ((obj)._unVal.pInstance)
-#define _delegable(obj) ((SQDelegable *)(obj)._unVal.pDelegable)
-#define _weakref(obj) ((obj)._unVal.pWeakRef)
-#define _outer(obj) ((obj)._unVal.pOuter)
-#define _refcounted(obj) ((obj)._unVal.pRefCounted)
-#define _rawval(obj) ((obj)._unVal.raw)
-
-#define _stringval(obj) (obj)._unVal.pString->_val
-#define _userdataval(obj) ((SQUserPointer)sq_aligning((obj)._unVal.pUserData + 1))
-
-#define tofloat(num) ((type(num)==OT_INTEGER)?(SQFloat)_integer(num):_float(num))
-#define tointeger(num) ((type(num)==OT_FLOAT)?(SQInteger)_float(num):_integer(num))
-/////////////////////////////////////////////////////////////////////////////////////
-/////////////////////////////////////////////////////////////////////////////////////
-#if defined(SQUSEDOUBLE) && !defined(_SQ64) || !defined(SQUSEDOUBLE) && defined(_SQ64)
-#define SQ_REFOBJECT_INIT() SQ_OBJECT_RAWINIT()
-#else
-#define SQ_REFOBJECT_INIT()
-#endif
-
-#define _REF_TYPE_DECL(type,_class,sym) \
- SQObjectPtr(_class * x) \
- { \
- SQ_OBJECT_RAWINIT() \
- _type=type; \
- _unVal.sym = x; \
- assert(_unVal.pTable); \
- _unVal.pRefCounted->_uiRef++; \
- } \
- inline SQObjectPtr& operator=(_class *x) \
- { \
- SQObjectType tOldType; \
- SQObjectValue unOldVal; \
- tOldType=_type; \
- unOldVal=_unVal; \
- _type = type; \
- SQ_REFOBJECT_INIT() \
- _unVal.sym = x; \
- _unVal.pRefCounted->_uiRef++; \
- __Release(tOldType,unOldVal); \
- return *this; \
- }
-
-#define _SCALAR_TYPE_DECL(type,_class,sym) \
- SQObjectPtr(_class x) \
- { \
- SQ_OBJECT_RAWINIT() \
- _type=type; \
- _unVal.sym = x; \
- } \
- inline SQObjectPtr& operator=(_class x) \
- { \
- __Release(_type,_unVal); \
- _type = type; \
- SQ_OBJECT_RAWINIT() \
- _unVal.sym = x; \
- return *this; \
- }
-struct SQObjectPtr : public SQObject
-{
- SQObjectPtr()
- {
- SQ_OBJECT_RAWINIT()
- _type=OT_NULL;
- _unVal.pUserPointer=NULL;
- }
- SQObjectPtr(const SQObjectPtr &o)
- {
- //SQ_OBJECT_RAWINIT()
- _type=o._type;
- _unVal=o._unVal;
- __AddRef(_type,_unVal);
- }
- SQObjectPtr(const SQObject &o)
- {
- //SQ_OBJECT_RAWINIT()
- _type=o._type;
- _unVal=o._unVal;
- __AddRef(_type,_unVal);
- }
- _REF_TYPE_DECL(OT_TABLE,SQTable,pTable)
- _REF_TYPE_DECL(OT_CLASS,SQClass,pClass)
- _REF_TYPE_DECL(OT_INSTANCE,SQInstance,pInstance)
- _REF_TYPE_DECL(OT_ARRAY,SQArray,pArray)
- _REF_TYPE_DECL(OT_CLOSURE,SQClosure,pClosure)
- _REF_TYPE_DECL(OT_NATIVECLOSURE,SQNativeClosure,pNativeClosure)
- _REF_TYPE_DECL(OT_OUTER,SQOuter,pOuter)
- _REF_TYPE_DECL(OT_GENERATOR,SQGenerator,pGenerator)
- _REF_TYPE_DECL(OT_STRING,SQString,pString)
- _REF_TYPE_DECL(OT_USERDATA,SQUserData,pUserData)
- _REF_TYPE_DECL(OT_WEAKREF,SQWeakRef,pWeakRef)
- _REF_TYPE_DECL(OT_THREAD,SQVM,pThread)
- _REF_TYPE_DECL(OT_FUNCPROTO,SQFunctionProto,pFunctionProto)
-
- _SCALAR_TYPE_DECL(OT_INTEGER,SQInteger,nInteger)
- _SCALAR_TYPE_DECL(OT_FLOAT,SQFloat,fFloat)
- _SCALAR_TYPE_DECL(OT_USERPOINTER,SQUserPointer,pUserPointer)
-
- SQObjectPtr(bool bBool)
- {
- SQ_OBJECT_RAWINIT()
- _type = OT_BOOL;
- _unVal.nInteger = bBool?1:0;
- }
- inline SQObjectPtr& operator=(bool b)
- {
- __Release(_type,_unVal);
- SQ_OBJECT_RAWINIT()
- _type = OT_BOOL;
- _unVal.nInteger = b?1:0;
- return *this;
- }
-
- ~SQObjectPtr()
- {
- __Release(_type,_unVal);
- }
-
- inline SQObjectPtr& operator=(const SQObjectPtr& obj)
- {
- SQObjectType tOldType;
- SQObjectValue unOldVal;
- tOldType=_type;
- unOldVal=_unVal;
- _unVal = obj._unVal;
- _type = obj._type;
- __AddRef(_type,_unVal);
- __Release(tOldType,unOldVal);
- return *this;
- }
- inline SQObjectPtr& operator=(const SQObject& obj)
- {
- SQObjectType tOldType;
- SQObjectValue unOldVal;
- tOldType=_type;
- unOldVal=_unVal;
- _unVal = obj._unVal;
- _type = obj._type;
- __AddRef(_type,_unVal);
- __Release(tOldType,unOldVal);
- return *this;
- }
- inline void Null()
- {
- __Release(_type ,_unVal);
- _type = OT_NULL;
- _unVal.raw = NULL;
- }
- private:
- SQObjectPtr(const SQChar *){} //safety
-};
-
-
-inline void _Swap(SQObject &a,SQObject &b)
-{
- SQObjectType tOldType = a._type;
- SQObjectValue unOldVal = a._unVal;
- a._type = b._type;
- a._unVal = b._unVal;
- b._type = tOldType;
- b._unVal = unOldVal;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////
-#ifndef NO_GARBAGE_COLLECTOR
-#define MARK_FLAG 0x80000000
-struct SQCollectable : public SQRefCounted {
- SQCollectable *_next;
- SQCollectable *_prev;
- SQSharedState *_sharedstate;
- virtual SQObjectType GetType()=0;
- virtual void Release()=0;
- virtual void Mark(SQCollectable **chain)=0;
- void UnMark();
- virtual void Finalize()=0;
- static void AddToChain(SQCollectable **chain,SQCollectable *c);
- static void RemoveFromChain(SQCollectable **chain,SQCollectable *c);
-};
-
-
-#define ADD_TO_CHAIN(chain,obj) AddToChain(chain,obj)
-#define REMOVE_FROM_CHAIN(chain,obj) {if(!(_uiRef&MARK_FLAG))RemoveFromChain(chain,obj);}
-#define CHAINABLE_OBJ SQCollectable
-#define INIT_CHAIN() {_next=NULL;_prev=NULL;_sharedstate=ss;}
-#else
-
-#define ADD_TO_CHAIN(chain,obj) ((void)0)
-#define REMOVE_FROM_CHAIN(chain,obj) ((void)0)
-#define CHAINABLE_OBJ SQRefCounted
-#define INIT_CHAIN() ((void)0)
-#endif
-
-struct SQDelegable : public CHAINABLE_OBJ {
- bool SetDelegate(SQTable *m);
- virtual bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res);
- SQTable *_delegate;
-};
-
-SQUnsignedInteger TranslateIndex(const SQObjectPtr &idx);
-typedef sqvector<SQObjectPtr> SQObjectPtrVec;
-typedef sqvector<SQInteger> SQIntVec;
-const SQChar *GetTypeName(const SQObjectPtr &obj1);
-const SQChar *IdType2Name(SQObjectType type);
-
-
-
-#endif //_SQOBJECT_H_
+/* see copyright notice in squirrel.h */ +#ifndef _SQOBJECT_H_ +#define _SQOBJECT_H_ + +#include "squtils.h" + +#ifdef _SQ64 +#define UINT_MINUS_ONE (0xFFFFFFFFFFFFFFFF) +#else +#define UINT_MINUS_ONE (0xFFFFFFFF) +#endif + +#define SQ_CLOSURESTREAM_HEAD (('S'<<24)|('Q'<<16)|('I'<<8)|('R')) +#define SQ_CLOSURESTREAM_PART (('P'<<24)|('A'<<16)|('R'<<8)|('T')) +#define SQ_CLOSURESTREAM_TAIL (('T'<<24)|('A'<<16)|('I'<<8)|('L')) + +struct SQSharedState; + +enum SQMetaMethod{ + MT_ADD=0, + MT_SUB=1, + MT_MUL=2, + MT_DIV=3, + MT_UNM=4, + MT_MODULO=5, + MT_SET=6, + MT_GET=7, + MT_TYPEOF=8, + MT_NEXTI=9, + MT_CMP=10, + MT_CALL=11, + MT_CLONED=12, + MT_NEWSLOT=13, + MT_DELSLOT=14, + MT_TOSTRING=15, + MT_NEWMEMBER=16, + MT_INHERITED=17, + MT_LAST = 18 +}; + +#define MM_ADD _SC("_add") +#define MM_SUB _SC("_sub") +#define MM_MUL _SC("_mul") +#define MM_DIV _SC("_div") +#define MM_UNM _SC("_unm") +#define MM_MODULO _SC("_modulo") +#define MM_SET _SC("_set") +#define MM_GET _SC("_get") +#define MM_TYPEOF _SC("_typeof") +#define MM_NEXTI _SC("_nexti") +#define MM_CMP _SC("_cmp") +#define MM_CALL _SC("_call") +#define MM_CLONED _SC("_cloned") +#define MM_NEWSLOT _SC("_newslot") +#define MM_DELSLOT _SC("_delslot") +#define MM_TOSTRING _SC("_tostring") +#define MM_NEWMEMBER _SC("_newmember") +#define MM_INHERITED _SC("_inherited") + + +#define _CONSTRUCT_VECTOR(type,size,ptr) { \ + for(SQInteger n = 0; n < ((SQInteger)size); n++) { \ + new (&ptr[n]) type(); \ + } \ +} + +#define _DESTRUCT_VECTOR(type,size,ptr) { \ + for(SQInteger nl = 0; nl < ((SQInteger)size); nl++) { \ + ptr[nl].~type(); \ + } \ +} + +#define _COPY_VECTOR(dest,src,size) { \ + for(SQInteger _n_ = 0; _n_ < ((SQInteger)size); _n_++) { \ + dest[_n_] = src[_n_]; \ + } \ +} + +#define _NULL_SQOBJECT_VECTOR(vec,size) { \ + for(SQInteger _n_ = 0; _n_ < ((SQInteger)size); _n_++) { \ + vec[_n_].Null(); \ + } \ +} + +#define MINPOWER2 4 + +struct SQRefCounted +{ + SQUnsignedInteger _uiRef; + struct SQWeakRef *_weakref; + SQRefCounted() { _uiRef = 0; _weakref = NULL; } + virtual ~SQRefCounted(); + SQWeakRef *GetWeakRef(SQObjectType type); + virtual void Release()=0; + +}; + +struct SQWeakRef : SQRefCounted +{ + void Release(); + SQObject _obj; +}; + +#define _realval(o) (type((o)) != OT_WEAKREF?(SQObject)o:_weakref(o)->_obj) + +struct SQObjectPtr; + +#define __AddRef(type,unval) if(ISREFCOUNTED(type)) \ + { \ + unval.pRefCounted->_uiRef++; \ + } + +#define __Release(type,unval) if(ISREFCOUNTED(type) && ((--unval.pRefCounted->_uiRef)==0)) \ + { \ + unval.pRefCounted->Release(); \ + } + +#define __ObjRelease(obj) { \ + if((obj)) { \ + (obj)->_uiRef--; \ + if((obj)->_uiRef == 0) \ + (obj)->Release(); \ + (obj) = NULL; \ + } \ +} + +#define __ObjAddRef(obj) { \ + (obj)->_uiRef++; \ +} + +#define type(obj) ((obj)._type) +#define is_delegable(t) (type(t)&SQOBJECT_DELEGABLE) +#define raw_type(obj) _RAW_TYPE((obj)._type) + +#define _integer(obj) ((obj)._unVal.nInteger) +#define _float(obj) ((obj)._unVal.fFloat) +#define _string(obj) ((obj)._unVal.pString) +#define _table(obj) ((obj)._unVal.pTable) +#define _array(obj) ((obj)._unVal.pArray) +#define _closure(obj) ((obj)._unVal.pClosure) +#define _generator(obj) ((obj)._unVal.pGenerator) +#define _nativeclosure(obj) ((obj)._unVal.pNativeClosure) +#define _userdata(obj) ((obj)._unVal.pUserData) +#define _userpointer(obj) ((obj)._unVal.pUserPointer) +#define _thread(obj) ((obj)._unVal.pThread) +#define _funcproto(obj) ((obj)._unVal.pFunctionProto) +#define _class(obj) ((obj)._unVal.pClass) +#define _instance(obj) ((obj)._unVal.pInstance) +#define _delegable(obj) ((SQDelegable *)(obj)._unVal.pDelegable) +#define _weakref(obj) ((obj)._unVal.pWeakRef) +#define _outer(obj) ((obj)._unVal.pOuter) +#define _refcounted(obj) ((obj)._unVal.pRefCounted) +#define _rawval(obj) ((obj)._unVal.raw) + +#define _stringval(obj) (obj)._unVal.pString->_val +#define _userdataval(obj) ((SQUserPointer)sq_aligning((obj)._unVal.pUserData + 1)) + +#define tofloat(num) ((type(num)==OT_INTEGER)?(SQFloat)_integer(num):_float(num)) +#define tointeger(num) ((type(num)==OT_FLOAT)?(SQInteger)_float(num):_integer(num)) +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +#if defined(SQUSEDOUBLE) && !defined(_SQ64) || !defined(SQUSEDOUBLE) && defined(_SQ64) +#define SQ_REFOBJECT_INIT() SQ_OBJECT_RAWINIT() +#else +#define SQ_REFOBJECT_INIT() +#endif + +#define _REF_TYPE_DECL(type,_class,sym) \ + SQObjectPtr(_class * x) \ + { \ + SQ_OBJECT_RAWINIT() \ + _type=type; \ + _unVal.sym = x; \ + assert(_unVal.pTable); \ + _unVal.pRefCounted->_uiRef++; \ + } \ + inline SQObjectPtr& operator=(_class *x) \ + { \ + SQObjectType tOldType; \ + SQObjectValue unOldVal; \ + tOldType=_type; \ + unOldVal=_unVal; \ + _type = type; \ + SQ_REFOBJECT_INIT() \ + _unVal.sym = x; \ + _unVal.pRefCounted->_uiRef++; \ + __Release(tOldType,unOldVal); \ + return *this; \ + } + +#define _SCALAR_TYPE_DECL(type,_class,sym) \ + SQObjectPtr(_class x) \ + { \ + SQ_OBJECT_RAWINIT() \ + _type=type; \ + _unVal.sym = x; \ + } \ + inline SQObjectPtr& operator=(_class x) \ + { \ + __Release(_type,_unVal); \ + _type = type; \ + SQ_OBJECT_RAWINIT() \ + _unVal.sym = x; \ + return *this; \ + } +struct SQObjectPtr : public SQObject +{ + SQObjectPtr() + { + SQ_OBJECT_RAWINIT() + _type=OT_NULL; + _unVal.pUserPointer=NULL; + } + SQObjectPtr(const SQObjectPtr &o) + { + //SQ_OBJECT_RAWINIT() + _type=o._type; + _unVal=o._unVal; + __AddRef(_type,_unVal); + } + SQObjectPtr(const SQObject &o) + { + //SQ_OBJECT_RAWINIT() + _type=o._type; + _unVal=o._unVal; + __AddRef(_type,_unVal); + } + _REF_TYPE_DECL(OT_TABLE,SQTable,pTable) + _REF_TYPE_DECL(OT_CLASS,SQClass,pClass) + _REF_TYPE_DECL(OT_INSTANCE,SQInstance,pInstance) + _REF_TYPE_DECL(OT_ARRAY,SQArray,pArray) + _REF_TYPE_DECL(OT_CLOSURE,SQClosure,pClosure) + _REF_TYPE_DECL(OT_NATIVECLOSURE,SQNativeClosure,pNativeClosure) + _REF_TYPE_DECL(OT_OUTER,SQOuter,pOuter) + _REF_TYPE_DECL(OT_GENERATOR,SQGenerator,pGenerator) + _REF_TYPE_DECL(OT_STRING,SQString,pString) + _REF_TYPE_DECL(OT_USERDATA,SQUserData,pUserData) + _REF_TYPE_DECL(OT_WEAKREF,SQWeakRef,pWeakRef) + _REF_TYPE_DECL(OT_THREAD,SQVM,pThread) + _REF_TYPE_DECL(OT_FUNCPROTO,SQFunctionProto,pFunctionProto) + + _SCALAR_TYPE_DECL(OT_INTEGER,SQInteger,nInteger) + _SCALAR_TYPE_DECL(OT_FLOAT,SQFloat,fFloat) + _SCALAR_TYPE_DECL(OT_USERPOINTER,SQUserPointer,pUserPointer) + + SQObjectPtr(bool bBool) + { + SQ_OBJECT_RAWINIT() + _type = OT_BOOL; + _unVal.nInteger = bBool?1:0; + } + inline SQObjectPtr& operator=(bool b) + { + __Release(_type,_unVal); + SQ_OBJECT_RAWINIT() + _type = OT_BOOL; + _unVal.nInteger = b?1:0; + return *this; + } + + ~SQObjectPtr() + { + __Release(_type,_unVal); + } + + inline SQObjectPtr& operator=(const SQObjectPtr& obj) + { + SQObjectType tOldType; + SQObjectValue unOldVal; + tOldType=_type; + unOldVal=_unVal; + _unVal = obj._unVal; + _type = obj._type; + __AddRef(_type,_unVal); + __Release(tOldType,unOldVal); + return *this; + } + inline SQObjectPtr& operator=(const SQObject& obj) + { + SQObjectType tOldType; + SQObjectValue unOldVal; + tOldType=_type; + unOldVal=_unVal; + _unVal = obj._unVal; + _type = obj._type; + __AddRef(_type,_unVal); + __Release(tOldType,unOldVal); + return *this; + } + inline void Null() + { + __Release(_type ,_unVal); + _type = OT_NULL; + _unVal.raw = NULL; + } + private: + SQObjectPtr(const SQChar *){} //safety +}; + + +inline void _Swap(SQObject &a,SQObject &b) +{ + SQObjectType tOldType = a._type; + SQObjectValue unOldVal = a._unVal; + a._type = b._type; + a._unVal = b._unVal; + b._type = tOldType; + b._unVal = unOldVal; +} + +///////////////////////////////////////////////////////////////////////////////////// +#ifndef NO_GARBAGE_COLLECTOR +#define MARK_FLAG 0x80000000 +struct SQCollectable : public SQRefCounted { + SQCollectable *_next; + SQCollectable *_prev; + SQSharedState *_sharedstate; + virtual SQObjectType GetType()=0; + virtual void Release()=0; + virtual void Mark(SQCollectable **chain)=0; + void UnMark(); + virtual void Finalize()=0; + static void AddToChain(SQCollectable **chain,SQCollectable *c); + static void RemoveFromChain(SQCollectable **chain,SQCollectable *c); +}; + + +#define ADD_TO_CHAIN(chain,obj) AddToChain(chain,obj) +#define REMOVE_FROM_CHAIN(chain,obj) {if(!(_uiRef&MARK_FLAG))RemoveFromChain(chain,obj);} +#define CHAINABLE_OBJ SQCollectable +#define INIT_CHAIN() {_next=NULL;_prev=NULL;_sharedstate=ss;} +#else + +#define ADD_TO_CHAIN(chain,obj) ((void)0) +#define REMOVE_FROM_CHAIN(chain,obj) ((void)0) +#define CHAINABLE_OBJ SQRefCounted +#define INIT_CHAIN() ((void)0) +#endif + +struct SQDelegable : public CHAINABLE_OBJ { + bool SetDelegate(SQTable *m); + virtual bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res); + SQTable *_delegate; +}; + +SQUnsignedInteger TranslateIndex(const SQObjectPtr &idx); +typedef sqvector<SQObjectPtr> SQObjectPtrVec; +typedef sqvector<SQInteger> SQIntVec; +const SQChar *GetTypeName(const SQObjectPtr &obj1); +const SQChar *IdType2Name(SQObjectType type); + + + +#endif //_SQOBJECT_H_ diff --git a/squirrel_3_0_1_stable/squirrel/sqopcodes.h b/squirrel_3_0_1_stable/squirrel/sqopcodes.h index 4d179812f..f5f5697c9 100644 --- a/squirrel_3_0_1_stable/squirrel/sqopcodes.h +++ b/squirrel_3_0_1_stable/squirrel/sqopcodes.h @@ -1,132 +1,132 @@ -/* see copyright notice in squirrel.h */
-#ifndef _SQOPCODES_H_
-#define _SQOPCODES_H_
-
-#define MAX_FUNC_STACKSIZE 0xFF
-#define MAX_LITERALS ((SQInteger)0x7FFFFFFF)
-
-enum BitWiseOP {
- BW_AND = 0,
- BW_OR = 2,
- BW_XOR = 3,
- BW_SHIFTL = 4,
- BW_SHIFTR = 5,
- BW_USHIFTR = 6
-};
-
-enum CmpOP {
- CMP_G = 0,
- CMP_GE = 2,
- CMP_L = 3,
- CMP_LE = 4,
- CMP_3W = 5
-};
-
-enum NewObjectType {
- NOT_TABLE = 0,
- NOT_ARRAY = 1,
- NOT_CLASS = 2
-};
-
-enum AppendArrayType {
- AAT_STACK = 0,
- AAT_LITERAL = 1,
- AAT_INT = 2,
- AAT_FLOAT = 3,
- AAT_BOOL = 4
-};
-
-enum SQOpcode
-{
- _OP_LINE= 0x00,
- _OP_LOAD= 0x01,
- _OP_LOADINT= 0x02,
- _OP_LOADFLOAT= 0x03,
- _OP_DLOAD= 0x04,
- _OP_TAILCALL= 0x05,
- _OP_CALL= 0x06,
- _OP_PREPCALL= 0x07,
- _OP_PREPCALLK= 0x08,
- _OP_GETK= 0x09,
- _OP_MOVE= 0x0A,
- _OP_NEWSLOT= 0x0B,
- _OP_DELETE= 0x0C,
- _OP_SET= 0x0D,
- _OP_GET= 0x0E,
- _OP_EQ= 0x0F,
- _OP_NE= 0x10,
- _OP_ADD= 0x11,
- _OP_SUB= 0x12,
- _OP_MUL= 0x13,
- _OP_DIV= 0x14,
- _OP_MOD= 0x15,
- _OP_BITW= 0x16,
- _OP_RETURN= 0x17,
- _OP_LOADNULLS= 0x18,
- _OP_LOADROOT= 0x19,
- _OP_LOADBOOL= 0x1A,
- _OP_DMOVE= 0x1B,
- _OP_JMP= 0x1C,
- //_OP_JNZ= 0x1D,
- _OP_JCMP= 0x1D,
- _OP_JZ= 0x1E,
- _OP_SETOUTER= 0x1F,
- _OP_GETOUTER= 0x20,
- _OP_NEWOBJ= 0x21,
- _OP_APPENDARRAY= 0x22,
- _OP_COMPARITH= 0x23,
- _OP_INC= 0x24,
- _OP_INCL= 0x25,
- _OP_PINC= 0x26,
- _OP_PINCL= 0x27,
- _OP_CMP= 0x28,
- _OP_EXISTS= 0x29,
- _OP_INSTANCEOF= 0x2A,
- _OP_AND= 0x2B,
- _OP_OR= 0x2C,
- _OP_NEG= 0x2D,
- _OP_NOT= 0x2E,
- _OP_BWNOT= 0x2F,
- _OP_CLOSURE= 0x30,
- _OP_YIELD= 0x31,
- _OP_RESUME= 0x32,
- _OP_FOREACH= 0x33,
- _OP_POSTFOREACH= 0x34,
- _OP_CLONE= 0x35,
- _OP_TYPEOF= 0x36,
- _OP_PUSHTRAP= 0x37,
- _OP_POPTRAP= 0x38,
- _OP_THROW= 0x39,
- _OP_NEWSLOTA= 0x3A,
- _OP_GETBASE= 0x3B,
- _OP_CLOSE= 0x3C,
-};
-
-struct SQInstructionDesc {
- const SQChar *name;
-};
-
-struct SQInstruction
-{
- SQInstruction(){};
- SQInstruction(SQOpcode _op,SQInteger a0=0,SQInteger a1=0,SQInteger a2=0,SQInteger a3=0)
- { op = _op;
- _arg0 = (unsigned char)a0;_arg1 = (SQInt32)a1;
- _arg2 = (unsigned char)a2;_arg3 = (unsigned char)a3;
- }
-
-
- SQInt32 _arg1;
- unsigned char op;
- unsigned char _arg0;
- unsigned char _arg2;
- unsigned char _arg3;
-};
-
-#include "squtils.h"
-typedef sqvector<SQInstruction> SQInstructionVec;
-
-#define NEW_SLOT_ATTRIBUTES_FLAG 0x01
-#define NEW_SLOT_STATIC_FLAG 0x02
-
-#endif // _SQOPCODES_H_
+/* see copyright notice in squirrel.h */ +#ifndef _SQOPCODES_H_ +#define _SQOPCODES_H_ + +#define MAX_FUNC_STACKSIZE 0xFF +#define MAX_LITERALS ((SQInteger)0x7FFFFFFF) + +enum BitWiseOP { + BW_AND = 0, + BW_OR = 2, + BW_XOR = 3, + BW_SHIFTL = 4, + BW_SHIFTR = 5, + BW_USHIFTR = 6 +}; + +enum CmpOP { + CMP_G = 0, + CMP_GE = 2, + CMP_L = 3, + CMP_LE = 4, + CMP_3W = 5 +}; + +enum NewObjectType { + NOT_TABLE = 0, + NOT_ARRAY = 1, + NOT_CLASS = 2 +}; + +enum AppendArrayType { + AAT_STACK = 0, + AAT_LITERAL = 1, + AAT_INT = 2, + AAT_FLOAT = 3, + AAT_BOOL = 4 +}; + +enum SQOpcode +{ + _OP_LINE= 0x00, + _OP_LOAD= 0x01, + _OP_LOADINT= 0x02, + _OP_LOADFLOAT= 0x03, + _OP_DLOAD= 0x04, + _OP_TAILCALL= 0x05, + _OP_CALL= 0x06, + _OP_PREPCALL= 0x07, + _OP_PREPCALLK= 0x08, + _OP_GETK= 0x09, + _OP_MOVE= 0x0A, + _OP_NEWSLOT= 0x0B, + _OP_DELETE= 0x0C, + _OP_SET= 0x0D, + _OP_GET= 0x0E, + _OP_EQ= 0x0F, + _OP_NE= 0x10, + _OP_ADD= 0x11, + _OP_SUB= 0x12, + _OP_MUL= 0x13, + _OP_DIV= 0x14, + _OP_MOD= 0x15, + _OP_BITW= 0x16, + _OP_RETURN= 0x17, + _OP_LOADNULLS= 0x18, + _OP_LOADROOT= 0x19, + _OP_LOADBOOL= 0x1A, + _OP_DMOVE= 0x1B, + _OP_JMP= 0x1C, + //_OP_JNZ= 0x1D, + _OP_JCMP= 0x1D, + _OP_JZ= 0x1E, + _OP_SETOUTER= 0x1F, + _OP_GETOUTER= 0x20, + _OP_NEWOBJ= 0x21, + _OP_APPENDARRAY= 0x22, + _OP_COMPARITH= 0x23, + _OP_INC= 0x24, + _OP_INCL= 0x25, + _OP_PINC= 0x26, + _OP_PINCL= 0x27, + _OP_CMP= 0x28, + _OP_EXISTS= 0x29, + _OP_INSTANCEOF= 0x2A, + _OP_AND= 0x2B, + _OP_OR= 0x2C, + _OP_NEG= 0x2D, + _OP_NOT= 0x2E, + _OP_BWNOT= 0x2F, + _OP_CLOSURE= 0x30, + _OP_YIELD= 0x31, + _OP_RESUME= 0x32, + _OP_FOREACH= 0x33, + _OP_POSTFOREACH= 0x34, + _OP_CLONE= 0x35, + _OP_TYPEOF= 0x36, + _OP_PUSHTRAP= 0x37, + _OP_POPTRAP= 0x38, + _OP_THROW= 0x39, + _OP_NEWSLOTA= 0x3A, + _OP_GETBASE= 0x3B, + _OP_CLOSE= 0x3C, +}; + +struct SQInstructionDesc { + const SQChar *name; +}; + +struct SQInstruction +{ + SQInstruction(){}; + SQInstruction(SQOpcode _op,SQInteger a0=0,SQInteger a1=0,SQInteger a2=0,SQInteger a3=0) + { op = _op; + _arg0 = (unsigned char)a0;_arg1 = (SQInt32)a1; + _arg2 = (unsigned char)a2;_arg3 = (unsigned char)a3; + } + + + SQInt32 _arg1; + unsigned char op; + unsigned char _arg0; + unsigned char _arg2; + unsigned char _arg3; +}; + +#include "squtils.h" +typedef sqvector<SQInstruction> SQInstructionVec; + +#define NEW_SLOT_ATTRIBUTES_FLAG 0x01 +#define NEW_SLOT_STATIC_FLAG 0x02 + +#endif // _SQOPCODES_H_ diff --git a/squirrel_3_0_1_stable/squirrel/sqpcheader.h b/squirrel_3_0_1_stable/squirrel/sqpcheader.h index f0e5cf2df..a3fb037e4 100644 --- a/squirrel_3_0_1_stable/squirrel/sqpcheader.h +++ b/squirrel_3_0_1_stable/squirrel/sqpcheader.h @@ -1,19 +1,19 @@ -/* see copyright notice in squirrel.h */
-#ifndef _SQPCHEADER_H_
-#define _SQPCHEADER_H_
-
-#if defined(_MSC_VER) && defined(_DEBUG)
-#include <crtdbg.h>
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <new>
-//squirrel stuff
-#include <squirrel.h>
-#include "sqobject.h"
-#include "sqstate.h"
-
-#endif //_SQPCHEADER_H_
+/* see copyright notice in squirrel.h */ +#ifndef _SQPCHEADER_H_ +#define _SQPCHEADER_H_ + +#if defined(_MSC_VER) && defined(_DEBUG) +#include <crtdbg.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <new> +//squirrel stuff +#include <squirrel.h> +#include "sqobject.h" +#include "sqstate.h" + +#endif //_SQPCHEADER_H_ diff --git a/squirrel_3_0_1_stable/squirrel/sqstate.cpp b/squirrel_3_0_1_stable/squirrel/sqstate.cpp index 0bee40661..8e77900f3 100644 --- a/squirrel_3_0_1_stable/squirrel/sqstate.cpp +++ b/squirrel_3_0_1_stable/squirrel/sqstate.cpp @@ -1,648 +1,648 @@ -/*
- see copyright notice in squirrel.h
-*/
-#include "sqpcheader.h"
-#include "sqopcodes.h"
-#include "sqvm.h"
-#include "sqfuncproto.h"
-#include "sqclosure.h"
-#include "sqstring.h"
-#include "sqtable.h"
-#include "sqarray.h"
-#include "squserdata.h"
-#include "sqclass.h"
-
-//SQObjectPtr _null_;
-//SQObjectPtr _true_(true);
-//SQObjectPtr _false_(false);
-//SQObjectPtr _one_((SQInteger)1);
-//SQObjectPtr _minusone_((SQInteger)-1);
-
-SQSharedState::SQSharedState()
-{
- _compilererrorhandler = NULL;
- _printfunc = NULL;
- _errorfunc = NULL;
- _debuginfo = false;
- _notifyallexceptions = false;
-}
-
-#define newsysstring(s) { \
- _systemstrings->push_back(SQString::Create(this,s)); \
- }
-
-#define newmetamethod(s) { \
- _metamethods->push_back(SQString::Create(this,s)); \
- _table(_metamethodsmap)->NewSlot(_metamethods->back(),(SQInteger)(_metamethods->size()-1)); \
- }
-
-bool CompileTypemask(SQIntVec &res,const SQChar *typemask)
-{
- SQInteger i = 0;
-
- SQInteger mask = 0;
- while(typemask[i] != 0) {
-
- switch(typemask[i]){
- case 'o': mask |= _RT_NULL; break;
- case 'i': mask |= _RT_INTEGER; break;
- case 'f': mask |= _RT_FLOAT; break;
- case 'n': mask |= (_RT_FLOAT | _RT_INTEGER); break;
- case 's': mask |= _RT_STRING; break;
- case 't': mask |= _RT_TABLE; break;
- case 'a': mask |= _RT_ARRAY; break;
- case 'u': mask |= _RT_USERDATA; break;
- case 'c': mask |= (_RT_CLOSURE | _RT_NATIVECLOSURE); break;
- case 'b': mask |= _RT_BOOL; break;
- case 'g': mask |= _RT_GENERATOR; break;
- case 'p': mask |= _RT_USERPOINTER; break;
- case 'v': mask |= _RT_THREAD; break;
- case 'x': mask |= _RT_INSTANCE; break;
- case 'y': mask |= _RT_CLASS; break;
- case 'r': mask |= _RT_WEAKREF; break;
- case '.': mask = -1; res.push_back(mask); i++; mask = 0; continue;
- case ' ': i++; continue; //ignores spaces
- default:
- return false;
- }
- i++;
- if(typemask[i] == '|') {
- i++;
- if(typemask[i] == 0)
- return false;
- continue;
- }
- res.push_back(mask);
- mask = 0;
-
- }
- return true;
-}
-
-SQTable *CreateDefaultDelegate(SQSharedState *ss,SQRegFunction *funcz)
-{
- SQInteger i=0;
- SQTable *t=SQTable::Create(ss,0);
- while(funcz[i].name!=0){
- SQNativeClosure *nc = SQNativeClosure::Create(ss,funcz[i].f,0);
- nc->_nparamscheck = funcz[i].nparamscheck;
- nc->_name = SQString::Create(ss,funcz[i].name);
- if(funcz[i].typemask && !CompileTypemask(nc->_typecheck,funcz[i].typemask))
- return NULL;
- t->NewSlot(SQString::Create(ss,funcz[i].name),nc);
- i++;
- }
- return t;
-}
-
-void SQSharedState::Init()
-{
- _scratchpad=NULL;
- _scratchpadsize=0;
-#ifndef NO_GARBAGE_COLLECTOR
- _gc_chain=NULL;
-#endif
- _stringtable = (SQStringTable*)SQ_MALLOC(sizeof(SQStringTable));
- new (_stringtable) SQStringTable(this);
- sq_new(_metamethods,SQObjectPtrVec);
- sq_new(_systemstrings,SQObjectPtrVec);
- sq_new(_types,SQObjectPtrVec);
- _metamethodsmap = SQTable::Create(this,MT_LAST-1);
- //adding type strings to avoid memory trashing
- //types names
- newsysstring(_SC("null"));
- newsysstring(_SC("table"));
- newsysstring(_SC("array"));
- newsysstring(_SC("closure"));
- newsysstring(_SC("string"));
- newsysstring(_SC("userdata"));
- newsysstring(_SC("integer"));
- newsysstring(_SC("float"));
- newsysstring(_SC("userpointer"));
- newsysstring(_SC("function"));
- newsysstring(_SC("generator"));
- newsysstring(_SC("thread"));
- newsysstring(_SC("class"));
- newsysstring(_SC("instance"));
- newsysstring(_SC("bool"));
- //meta methods
- newmetamethod(MM_ADD);
- newmetamethod(MM_SUB);
- newmetamethod(MM_MUL);
- newmetamethod(MM_DIV);
- newmetamethod(MM_UNM);
- newmetamethod(MM_MODULO);
- newmetamethod(MM_SET);
- newmetamethod(MM_GET);
- newmetamethod(MM_TYPEOF);
- newmetamethod(MM_NEXTI);
- newmetamethod(MM_CMP);
- newmetamethod(MM_CALL);
- newmetamethod(MM_CLONED);
- newmetamethod(MM_NEWSLOT);
- newmetamethod(MM_DELSLOT);
- newmetamethod(MM_TOSTRING);
- newmetamethod(MM_NEWMEMBER);
- newmetamethod(MM_INHERITED);
-
- _constructoridx = SQString::Create(this,_SC("constructor"));
- _registry = SQTable::Create(this,0);
- _consts = SQTable::Create(this,0);
- _table_default_delegate = CreateDefaultDelegate(this,_table_default_delegate_funcz);
- _array_default_delegate = CreateDefaultDelegate(this,_array_default_delegate_funcz);
- _string_default_delegate = CreateDefaultDelegate(this,_string_default_delegate_funcz);
- _number_default_delegate = CreateDefaultDelegate(this,_number_default_delegate_funcz);
- _closure_default_delegate = CreateDefaultDelegate(this,_closure_default_delegate_funcz);
- _generator_default_delegate = CreateDefaultDelegate(this,_generator_default_delegate_funcz);
- _thread_default_delegate = CreateDefaultDelegate(this,_thread_default_delegate_funcz);
- _class_default_delegate = CreateDefaultDelegate(this,_class_default_delegate_funcz);
- _instance_default_delegate = CreateDefaultDelegate(this,_instance_default_delegate_funcz);
- _weakref_default_delegate = CreateDefaultDelegate(this,_weakref_default_delegate_funcz);
-
-}
-
-SQSharedState::~SQSharedState()
-{
- _constructoridx.Null();
- _table(_registry)->Finalize();
- _table(_consts)->Finalize();
- _table(_metamethodsmap)->Finalize();
- _registry.Null();
- _consts.Null();
- _metamethodsmap.Null();
- while(!_systemstrings->empty()) {
- _systemstrings->back().Null();
- _systemstrings->pop_back();
- }
- _thread(_root_vm)->Finalize();
- _root_vm.Null();
- _table_default_delegate.Null();
- _array_default_delegate.Null();
- _string_default_delegate.Null();
- _number_default_delegate.Null();
- _closure_default_delegate.Null();
- _generator_default_delegate.Null();
- _thread_default_delegate.Null();
- _class_default_delegate.Null();
- _instance_default_delegate.Null();
- _weakref_default_delegate.Null();
- _refs_table.Finalize();
-#ifndef NO_GARBAGE_COLLECTOR
- SQCollectable *t = _gc_chain;
- SQCollectable *nx = NULL;
- while(t) {
- t->_uiRef++;
- t->Finalize();
- nx = t->_next;
- if(--t->_uiRef == 0)
- t->Release();
- t=nx;
- }
- assert(_gc_chain==NULL); //just to proove a theory
- while(_gc_chain){
- _gc_chain->_uiRef++;
- _gc_chain->Release();
- }
-#endif
-
- sq_delete(_types,SQObjectPtrVec);
- sq_delete(_systemstrings,SQObjectPtrVec);
- sq_delete(_metamethods,SQObjectPtrVec);
- sq_delete(_stringtable,SQStringTable);
- if(_scratchpad)SQ_FREE(_scratchpad,_scratchpadsize);
-}
-
-
-SQInteger SQSharedState::GetMetaMethodIdxByName(const SQObjectPtr &name)
-{
- if(type(name) != OT_STRING)
- return -1;
- SQObjectPtr ret;
- if(_table(_metamethodsmap)->Get(name,ret)) {
- return _integer(ret);
- }
- return -1;
-}
-
-#ifndef NO_GARBAGE_COLLECTOR
-
-void SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain)
-{
- switch(type(o)){
- case OT_TABLE:_table(o)->Mark(chain);break;
- case OT_ARRAY:_array(o)->Mark(chain);break;
- case OT_USERDATA:_userdata(o)->Mark(chain);break;
- case OT_CLOSURE:_closure(o)->Mark(chain);break;
- case OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break;
- case OT_GENERATOR:_generator(o)->Mark(chain);break;
- case OT_THREAD:_thread(o)->Mark(chain);break;
- case OT_CLASS:_class(o)->Mark(chain);break;
- case OT_INSTANCE:_instance(o)->Mark(chain);break;
- case OT_OUTER:_outer(o)->Mark(chain);break;
- case OT_FUNCPROTO:_funcproto(o)->Mark(chain);break;
- default: break; //shutup compiler
- }
-}
-
-
-void SQSharedState::RunMark(SQVM *vm,SQCollectable **tchain)
-{
- SQVM *vms = _thread(_root_vm);
-
- vms->Mark(tchain);
-
- _refs_table.Mark(tchain);
- MarkObject(_registry,tchain);
- MarkObject(_consts,tchain);
- MarkObject(_metamethodsmap,tchain);
- MarkObject(_table_default_delegate,tchain);
- MarkObject(_array_default_delegate,tchain);
- MarkObject(_string_default_delegate,tchain);
- MarkObject(_number_default_delegate,tchain);
- MarkObject(_generator_default_delegate,tchain);
- MarkObject(_thread_default_delegate,tchain);
- MarkObject(_closure_default_delegate,tchain);
- MarkObject(_class_default_delegate,tchain);
- MarkObject(_instance_default_delegate,tchain);
- MarkObject(_weakref_default_delegate,tchain);
-
-}
-
-SQInteger SQSharedState::ResurrectUnreachable(SQVM *vm)
-{
- SQInteger n=0;
- SQCollectable *tchain=NULL;
-
- RunMark(vm,&tchain);
-
- SQCollectable *resurrected = _gc_chain;
- SQCollectable *t = resurrected;
- //SQCollectable *nx = NULL;
-
- _gc_chain = tchain;
-
- SQArray *ret = NULL;
- if(resurrected) {
- ret = SQArray::Create(this,0);
- SQCollectable *rlast = NULL;
- while(t) {
- rlast = t;
- SQObjectType type = t->GetType();
- if(type != OT_FUNCPROTO && type != OT_OUTER) {
- SQObject sqo;
- sqo._type = type;
- sqo._unVal.pRefCounted = t;
- ret->Append(sqo);
- }
- t = t->_next;
- n++;
- }
-
- assert(rlast->_next == NULL);
- rlast->_next = _gc_chain;
- if(_gc_chain)
- {
- _gc_chain->_prev = rlast;
- }
- _gc_chain = resurrected;
- }
-
- t = _gc_chain;
- while(t) {
- t->UnMark();
- t = t->_next;
- }
-
- if(ret) {
- SQObjectPtr temp = ret;
- vm->Push(temp);
- }
- else {
- vm->PushNull();
- }
- return n;
-}
-
-SQInteger SQSharedState::CollectGarbage(SQVM *vm)
-{
- SQInteger n=0;
- SQCollectable *tchain=NULL;
-
- RunMark(vm,&tchain);
-
- SQCollectable *t = _gc_chain;
- SQCollectable *nx = NULL;
- while(t) {
- t->_uiRef++;
- t->Finalize();
- nx = t->_next;
- if(--t->_uiRef == 0)
- t->Release();
- t = nx;
- n++;
- }
-
- t = tchain;
- while(t) {
- t->UnMark();
- t = t->_next;
- }
- _gc_chain = tchain;
-
- return n;
-}
-#endif
-
-#ifndef NO_GARBAGE_COLLECTOR
-void SQCollectable::AddToChain(SQCollectable **chain,SQCollectable *c)
-{
- c->_prev = NULL;
- c->_next = *chain;
- if(*chain) (*chain)->_prev = c;
- *chain = c;
-}
-
-void SQCollectable::RemoveFromChain(SQCollectable **chain,SQCollectable *c)
-{
- if(c->_prev) c->_prev->_next = c->_next;
- else *chain = c->_next;
- if(c->_next)
- c->_next->_prev = c->_prev;
- c->_next = NULL;
- c->_prev = NULL;
-}
-#endif
-
-SQChar* SQSharedState::GetScratchPad(SQInteger size)
-{
- SQInteger newsize;
- if(size>0) {
- if(_scratchpadsize < size) {
- newsize = size + (size>>1);
- _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize);
- _scratchpadsize = newsize;
-
- }else if(_scratchpadsize >= (size<<5)) {
- newsize = _scratchpadsize >> 1;
- _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize);
- _scratchpadsize = newsize;
- }
- }
- return _scratchpad;
-}
-
-RefTable::RefTable()
-{
- AllocNodes(4);
-}
-
-void RefTable::Finalize()
-{
- RefNode *nodes = _nodes;
- for(SQUnsignedInteger n = 0; n < _numofslots; n++) {
- nodes->obj.Null();
- nodes++;
- }
-}
-
-RefTable::~RefTable()
-{
- SQ_FREE(_buckets,(_numofslots * sizeof(RefNode *)) + (_numofslots * sizeof(RefNode)));
-}
-
-#ifndef NO_GARBAGE_COLLECTOR
-void RefTable::Mark(SQCollectable **chain)
-{
- RefNode *nodes = (RefNode *)_nodes;
- for(SQUnsignedInteger n = 0; n < _numofslots; n++) {
- if(type(nodes->obj) != OT_NULL) {
- SQSharedState::MarkObject(nodes->obj,chain);
- }
- nodes++;
- }
-}
-#endif
-
-void RefTable::AddRef(SQObject &obj)
-{
- SQHash mainpos;
- RefNode *prev;
- RefNode *ref = Get(obj,mainpos,&prev,true);
- ref->refs++;
-}
-
-SQUnsignedInteger RefTable::GetRefCount(SQObject &obj)
-{
- SQHash mainpos;
- RefNode *prev;
- RefNode *ref = Get(obj,mainpos,&prev,true);
- return ref->refs;
-}
-
-
-SQBool RefTable::Release(SQObject &obj)
-{
- SQHash mainpos;
- RefNode *prev;
- RefNode *ref = Get(obj,mainpos,&prev,false);
- if(ref) {
- if(--ref->refs == 0) {
- SQObjectPtr o = ref->obj;
- if(prev) {
- prev->next = ref->next;
- }
- else {
- _buckets[mainpos] = ref->next;
- }
- ref->next = _freelist;
- _freelist = ref;
- _slotused--;
- ref->obj.Null();
- //<<FIXME>>test for shrink?
- return SQTrue;
- }
- }
- else {
- assert(0);
- }
- return SQFalse;
-}
-
-void RefTable::Resize(SQUnsignedInteger size)
-{
- RefNode **oldbucks = _buckets;
- RefNode *t = _nodes;
- SQUnsignedInteger oldnumofslots = _numofslots;
- AllocNodes(size);
- //rehash
- SQUnsignedInteger nfound = 0;
- for(SQUnsignedInteger n = 0; n < oldnumofslots; n++) {
- if(type(t->obj) != OT_NULL) {
- //add back;
- assert(t->refs != 0);
- RefNode *nn = Add(::HashObj(t->obj)&(_numofslots-1),t->obj);
- nn->refs = t->refs;
- t->obj.Null();
- nfound++;
- }
- t++;
- }
- assert(nfound == oldnumofslots);
- SQ_FREE(oldbucks,(oldnumofslots * sizeof(RefNode *)) + (oldnumofslots * sizeof(RefNode)));
-}
-
-RefTable::RefNode *RefTable::Add(SQHash mainpos,SQObject &obj)
-{
- RefNode *t = _buckets[mainpos];
- RefNode *newnode = _freelist;
- newnode->obj = obj;
- _buckets[mainpos] = newnode;
- _freelist = _freelist->next;
- newnode->next = t;
- assert(newnode->refs == 0);
- _slotused++;
- return newnode;
-}
-
-RefTable::RefNode *RefTable::Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add)
-{
- RefNode *ref;
- mainpos = ::HashObj(obj)&(_numofslots-1);
- *prev = NULL;
- for (ref = _buckets[mainpos]; ref; ) {
- if(_rawval(ref->obj) == _rawval(obj) && type(ref->obj) == type(obj))
- break;
- *prev = ref;
- ref = ref->next;
- }
- if(ref == NULL && add) {
- if(_numofslots == _slotused) {
- assert(_freelist == 0);
- Resize(_numofslots*2);
- mainpos = ::HashObj(obj)&(_numofslots-1);
- }
- ref = Add(mainpos,obj);
- }
- return ref;
-}
-
-void RefTable::AllocNodes(SQUnsignedInteger size)
-{
- RefNode **bucks;
- RefNode *nodes;
- bucks = (RefNode **)SQ_MALLOC((size * sizeof(RefNode *)) + (size * sizeof(RefNode)));
- nodes = (RefNode *)&bucks[size];
- RefNode *temp = nodes;
- SQUnsignedInteger n;
- for(n = 0; n < size - 1; n++) {
- bucks[n] = NULL;
- temp->refs = 0;
- new (&temp->obj) SQObjectPtr;
- temp->next = temp+1;
- temp++;
- }
- bucks[n] = NULL;
- temp->refs = 0;
- new (&temp->obj) SQObjectPtr;
- temp->next = NULL;
- _freelist = nodes;
- _nodes = nodes;
- _buckets = bucks;
- _slotused = 0;
- _numofslots = size;
-}
-//////////////////////////////////////////////////////////////////////////
-//SQStringTable
-/*
-* The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.)
-* http://www.lua.org/copyright.html#4
-* http://www.lua.org/source/4.0.1/src_lstring.c.html
-*/
-
-SQStringTable::SQStringTable(SQSharedState *ss)
-{
- _sharedstate = ss;
- AllocNodes(4);
- _slotused = 0;
-}
-
-SQStringTable::~SQStringTable()
-{
- SQ_FREE(_strings,sizeof(SQString*)*_numofslots);
- _strings = NULL;
-}
-
-void SQStringTable::AllocNodes(SQInteger size)
-{
- _numofslots = size;
- _strings = (SQString**)SQ_MALLOC(sizeof(SQString*)*_numofslots);
- memset(_strings,0,sizeof(SQString*)*_numofslots);
-}
-
-SQString *SQStringTable::Add(const SQChar *news,SQInteger len)
-{
- if(len<0)
- len = (SQInteger)scstrlen(news);
- SQHash h = ::_hashstr(news,len)&(_numofslots-1);
- SQString *s;
- for (s = _strings[h]; s; s = s->_next){
- if(s->_len == len && (!memcmp(news,s->_val,rsl(len))))
- return s; //found
- }
-
- SQString *t=(SQString *)SQ_MALLOC(rsl(len)+sizeof(SQString));
- new (t) SQString;
- t->_sharedstate = _sharedstate;
- memcpy(t->_val,news,rsl(len));
- t->_val[len] = _SC('\0');
- t->_len = len;
- t->_hash = ::_hashstr(news,len);
- t->_next = _strings[h];
- _strings[h] = t;
- _slotused++;
- if (_slotused > _numofslots) /* too crowded? */
- Resize(_numofslots*2);
- return t;
-}
-
-void SQStringTable::Resize(SQInteger size)
-{
- SQInteger oldsize=_numofslots;
- SQString **oldtable=_strings;
- AllocNodes(size);
- for (SQInteger i=0; i<oldsize; i++){
- SQString *p = oldtable[i];
- while(p){
- SQString *next = p->_next;
- SQHash h = p->_hash&(_numofslots-1);
- p->_next = _strings[h];
- _strings[h] = p;
- p = next;
- }
- }
- SQ_FREE(oldtable,oldsize*sizeof(SQString*));
-}
-
-void SQStringTable::Remove(SQString *bs)
-{
- SQString *s;
- SQString *prev=NULL;
- SQHash h = bs->_hash&(_numofslots - 1);
-
- for (s = _strings[h]; s; ){
- if(s == bs){
- if(prev)
- prev->_next = s->_next;
- else
- _strings[h] = s->_next;
- _slotused--;
- SQInteger slen = s->_len;
- s->~SQString();
- SQ_FREE(s,sizeof(SQString) + rsl(slen));
- return;
- }
- prev = s;
- s = s->_next;
- }
- assert(0);//if this fail something is wrong
-}
+/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include "sqopcodes.h" +#include "sqvm.h" +#include "sqfuncproto.h" +#include "sqclosure.h" +#include "sqstring.h" +#include "sqtable.h" +#include "sqarray.h" +#include "squserdata.h" +#include "sqclass.h" + +//SQObjectPtr _null_; +//SQObjectPtr _true_(true); +//SQObjectPtr _false_(false); +//SQObjectPtr _one_((SQInteger)1); +//SQObjectPtr _minusone_((SQInteger)-1); + +SQSharedState::SQSharedState() +{ + _compilererrorhandler = NULL; + _printfunc = NULL; + _errorfunc = NULL; + _debuginfo = false; + _notifyallexceptions = false; +} + +#define newsysstring(s) { \ + _systemstrings->push_back(SQString::Create(this,s)); \ + } + +#define newmetamethod(s) { \ + _metamethods->push_back(SQString::Create(this,s)); \ + _table(_metamethodsmap)->NewSlot(_metamethods->back(),(SQInteger)(_metamethods->size()-1)); \ + } + +bool CompileTypemask(SQIntVec &res,const SQChar *typemask) +{ + SQInteger i = 0; + + SQInteger mask = 0; + while(typemask[i] != 0) { + + switch(typemask[i]){ + case 'o': mask |= _RT_NULL; break; + case 'i': mask |= _RT_INTEGER; break; + case 'f': mask |= _RT_FLOAT; break; + case 'n': mask |= (_RT_FLOAT | _RT_INTEGER); break; + case 's': mask |= _RT_STRING; break; + case 't': mask |= _RT_TABLE; break; + case 'a': mask |= _RT_ARRAY; break; + case 'u': mask |= _RT_USERDATA; break; + case 'c': mask |= (_RT_CLOSURE | _RT_NATIVECLOSURE); break; + case 'b': mask |= _RT_BOOL; break; + case 'g': mask |= _RT_GENERATOR; break; + case 'p': mask |= _RT_USERPOINTER; break; + case 'v': mask |= _RT_THREAD; break; + case 'x': mask |= _RT_INSTANCE; break; + case 'y': mask |= _RT_CLASS; break; + case 'r': mask |= _RT_WEAKREF; break; + case '.': mask = -1; res.push_back(mask); i++; mask = 0; continue; + case ' ': i++; continue; //ignores spaces + default: + return false; + } + i++; + if(typemask[i] == '|') { + i++; + if(typemask[i] == 0) + return false; + continue; + } + res.push_back(mask); + mask = 0; + + } + return true; +} + +SQTable *CreateDefaultDelegate(SQSharedState *ss,SQRegFunction *funcz) +{ + SQInteger i=0; + SQTable *t=SQTable::Create(ss,0); + while(funcz[i].name!=0){ + SQNativeClosure *nc = SQNativeClosure::Create(ss,funcz[i].f,0); + nc->_nparamscheck = funcz[i].nparamscheck; + nc->_name = SQString::Create(ss,funcz[i].name); + if(funcz[i].typemask && !CompileTypemask(nc->_typecheck,funcz[i].typemask)) + return NULL; + t->NewSlot(SQString::Create(ss,funcz[i].name),nc); + i++; + } + return t; +} + +void SQSharedState::Init() +{ + _scratchpad=NULL; + _scratchpadsize=0; +#ifndef NO_GARBAGE_COLLECTOR + _gc_chain=NULL; +#endif + _stringtable = (SQStringTable*)SQ_MALLOC(sizeof(SQStringTable)); + new (_stringtable) SQStringTable(this); + sq_new(_metamethods,SQObjectPtrVec); + sq_new(_systemstrings,SQObjectPtrVec); + sq_new(_types,SQObjectPtrVec); + _metamethodsmap = SQTable::Create(this,MT_LAST-1); + //adding type strings to avoid memory trashing + //types names + newsysstring(_SC("null")); + newsysstring(_SC("table")); + newsysstring(_SC("array")); + newsysstring(_SC("closure")); + newsysstring(_SC("string")); + newsysstring(_SC("userdata")); + newsysstring(_SC("integer")); + newsysstring(_SC("float")); + newsysstring(_SC("userpointer")); + newsysstring(_SC("function")); + newsysstring(_SC("generator")); + newsysstring(_SC("thread")); + newsysstring(_SC("class")); + newsysstring(_SC("instance")); + newsysstring(_SC("bool")); + //meta methods + newmetamethod(MM_ADD); + newmetamethod(MM_SUB); + newmetamethod(MM_MUL); + newmetamethod(MM_DIV); + newmetamethod(MM_UNM); + newmetamethod(MM_MODULO); + newmetamethod(MM_SET); + newmetamethod(MM_GET); + newmetamethod(MM_TYPEOF); + newmetamethod(MM_NEXTI); + newmetamethod(MM_CMP); + newmetamethod(MM_CALL); + newmetamethod(MM_CLONED); + newmetamethod(MM_NEWSLOT); + newmetamethod(MM_DELSLOT); + newmetamethod(MM_TOSTRING); + newmetamethod(MM_NEWMEMBER); + newmetamethod(MM_INHERITED); + + _constructoridx = SQString::Create(this,_SC("constructor")); + _registry = SQTable::Create(this,0); + _consts = SQTable::Create(this,0); + _table_default_delegate = CreateDefaultDelegate(this,_table_default_delegate_funcz); + _array_default_delegate = CreateDefaultDelegate(this,_array_default_delegate_funcz); + _string_default_delegate = CreateDefaultDelegate(this,_string_default_delegate_funcz); + _number_default_delegate = CreateDefaultDelegate(this,_number_default_delegate_funcz); + _closure_default_delegate = CreateDefaultDelegate(this,_closure_default_delegate_funcz); + _generator_default_delegate = CreateDefaultDelegate(this,_generator_default_delegate_funcz); + _thread_default_delegate = CreateDefaultDelegate(this,_thread_default_delegate_funcz); + _class_default_delegate = CreateDefaultDelegate(this,_class_default_delegate_funcz); + _instance_default_delegate = CreateDefaultDelegate(this,_instance_default_delegate_funcz); + _weakref_default_delegate = CreateDefaultDelegate(this,_weakref_default_delegate_funcz); + +} + +SQSharedState::~SQSharedState() +{ + _constructoridx.Null(); + _table(_registry)->Finalize(); + _table(_consts)->Finalize(); + _table(_metamethodsmap)->Finalize(); + _registry.Null(); + _consts.Null(); + _metamethodsmap.Null(); + while(!_systemstrings->empty()) { + _systemstrings->back().Null(); + _systemstrings->pop_back(); + } + _thread(_root_vm)->Finalize(); + _root_vm.Null(); + _table_default_delegate.Null(); + _array_default_delegate.Null(); + _string_default_delegate.Null(); + _number_default_delegate.Null(); + _closure_default_delegate.Null(); + _generator_default_delegate.Null(); + _thread_default_delegate.Null(); + _class_default_delegate.Null(); + _instance_default_delegate.Null(); + _weakref_default_delegate.Null(); + _refs_table.Finalize(); +#ifndef NO_GARBAGE_COLLECTOR + SQCollectable *t = _gc_chain; + SQCollectable *nx = NULL; + while(t) { + t->_uiRef++; + t->Finalize(); + nx = t->_next; + if(--t->_uiRef == 0) + t->Release(); + t=nx; + } + assert(_gc_chain==NULL); //just to proove a theory + while(_gc_chain){ + _gc_chain->_uiRef++; + _gc_chain->Release(); + } +#endif + + sq_delete(_types,SQObjectPtrVec); + sq_delete(_systemstrings,SQObjectPtrVec); + sq_delete(_metamethods,SQObjectPtrVec); + sq_delete(_stringtable,SQStringTable); + if(_scratchpad)SQ_FREE(_scratchpad,_scratchpadsize); +} + + +SQInteger SQSharedState::GetMetaMethodIdxByName(const SQObjectPtr &name) +{ + if(type(name) != OT_STRING) + return -1; + SQObjectPtr ret; + if(_table(_metamethodsmap)->Get(name,ret)) { + return _integer(ret); + } + return -1; +} + +#ifndef NO_GARBAGE_COLLECTOR + +void SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain) +{ + switch(type(o)){ + case OT_TABLE:_table(o)->Mark(chain);break; + case OT_ARRAY:_array(o)->Mark(chain);break; + case OT_USERDATA:_userdata(o)->Mark(chain);break; + case OT_CLOSURE:_closure(o)->Mark(chain);break; + case OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break; + case OT_GENERATOR:_generator(o)->Mark(chain);break; + case OT_THREAD:_thread(o)->Mark(chain);break; + case OT_CLASS:_class(o)->Mark(chain);break; + case OT_INSTANCE:_instance(o)->Mark(chain);break; + case OT_OUTER:_outer(o)->Mark(chain);break; + case OT_FUNCPROTO:_funcproto(o)->Mark(chain);break; + default: break; //shutup compiler + } +} + + +void SQSharedState::RunMark(SQVM *vm,SQCollectable **tchain) +{ + SQVM *vms = _thread(_root_vm); + + vms->Mark(tchain); + + _refs_table.Mark(tchain); + MarkObject(_registry,tchain); + MarkObject(_consts,tchain); + MarkObject(_metamethodsmap,tchain); + MarkObject(_table_default_delegate,tchain); + MarkObject(_array_default_delegate,tchain); + MarkObject(_string_default_delegate,tchain); + MarkObject(_number_default_delegate,tchain); + MarkObject(_generator_default_delegate,tchain); + MarkObject(_thread_default_delegate,tchain); + MarkObject(_closure_default_delegate,tchain); + MarkObject(_class_default_delegate,tchain); + MarkObject(_instance_default_delegate,tchain); + MarkObject(_weakref_default_delegate,tchain); + +} + +SQInteger SQSharedState::ResurrectUnreachable(SQVM *vm) +{ + SQInteger n=0; + SQCollectable *tchain=NULL; + + RunMark(vm,&tchain); + + SQCollectable *resurrected = _gc_chain; + SQCollectable *t = resurrected; + //SQCollectable *nx = NULL; + + _gc_chain = tchain; + + SQArray *ret = NULL; + if(resurrected) { + ret = SQArray::Create(this,0); + SQCollectable *rlast = NULL; + while(t) { + rlast = t; + SQObjectType type = t->GetType(); + if(type != OT_FUNCPROTO && type != OT_OUTER) { + SQObject sqo; + sqo._type = type; + sqo._unVal.pRefCounted = t; + ret->Append(sqo); + } + t = t->_next; + n++; + } + + assert(rlast->_next == NULL); + rlast->_next = _gc_chain; + if(_gc_chain) + { + _gc_chain->_prev = rlast; + } + _gc_chain = resurrected; + } + + t = _gc_chain; + while(t) { + t->UnMark(); + t = t->_next; + } + + if(ret) { + SQObjectPtr temp = ret; + vm->Push(temp); + } + else { + vm->PushNull(); + } + return n; +} + +SQInteger SQSharedState::CollectGarbage(SQVM *vm) +{ + SQInteger n=0; + SQCollectable *tchain=NULL; + + RunMark(vm,&tchain); + + SQCollectable *t = _gc_chain; + SQCollectable *nx = NULL; + while(t) { + t->_uiRef++; + t->Finalize(); + nx = t->_next; + if(--t->_uiRef == 0) + t->Release(); + t = nx; + n++; + } + + t = tchain; + while(t) { + t->UnMark(); + t = t->_next; + } + _gc_chain = tchain; + + return n; +} +#endif + +#ifndef NO_GARBAGE_COLLECTOR +void SQCollectable::AddToChain(SQCollectable **chain,SQCollectable *c) +{ + c->_prev = NULL; + c->_next = *chain; + if(*chain) (*chain)->_prev = c; + *chain = c; +} + +void SQCollectable::RemoveFromChain(SQCollectable **chain,SQCollectable *c) +{ + if(c->_prev) c->_prev->_next = c->_next; + else *chain = c->_next; + if(c->_next) + c->_next->_prev = c->_prev; + c->_next = NULL; + c->_prev = NULL; +} +#endif + +SQChar* SQSharedState::GetScratchPad(SQInteger size) +{ + SQInteger newsize; + if(size>0) { + if(_scratchpadsize < size) { + newsize = size + (size>>1); + _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize); + _scratchpadsize = newsize; + + }else if(_scratchpadsize >= (size<<5)) { + newsize = _scratchpadsize >> 1; + _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize); + _scratchpadsize = newsize; + } + } + return _scratchpad; +} + +RefTable::RefTable() +{ + AllocNodes(4); +} + +void RefTable::Finalize() +{ + RefNode *nodes = _nodes; + for(SQUnsignedInteger n = 0; n < _numofslots; n++) { + nodes->obj.Null(); + nodes++; + } +} + +RefTable::~RefTable() +{ + SQ_FREE(_buckets,(_numofslots * sizeof(RefNode *)) + (_numofslots * sizeof(RefNode))); +} + +#ifndef NO_GARBAGE_COLLECTOR +void RefTable::Mark(SQCollectable **chain) +{ + RefNode *nodes = (RefNode *)_nodes; + for(SQUnsignedInteger n = 0; n < _numofslots; n++) { + if(type(nodes->obj) != OT_NULL) { + SQSharedState::MarkObject(nodes->obj,chain); + } + nodes++; + } +} +#endif + +void RefTable::AddRef(SQObject &obj) +{ + SQHash mainpos; + RefNode *prev; + RefNode *ref = Get(obj,mainpos,&prev,true); + ref->refs++; +} + +SQUnsignedInteger RefTable::GetRefCount(SQObject &obj) +{ + SQHash mainpos; + RefNode *prev; + RefNode *ref = Get(obj,mainpos,&prev,true); + return ref->refs; +} + + +SQBool RefTable::Release(SQObject &obj) +{ + SQHash mainpos; + RefNode *prev; + RefNode *ref = Get(obj,mainpos,&prev,false); + if(ref) { + if(--ref->refs == 0) { + SQObjectPtr o = ref->obj; + if(prev) { + prev->next = ref->next; + } + else { + _buckets[mainpos] = ref->next; + } + ref->next = _freelist; + _freelist = ref; + _slotused--; + ref->obj.Null(); + //<<FIXME>>test for shrink? + return SQTrue; + } + } + else { + assert(0); + } + return SQFalse; +} + +void RefTable::Resize(SQUnsignedInteger size) +{ + RefNode **oldbucks = _buckets; + RefNode *t = _nodes; + SQUnsignedInteger oldnumofslots = _numofslots; + AllocNodes(size); + //rehash + SQUnsignedInteger nfound = 0; + for(SQUnsignedInteger n = 0; n < oldnumofslots; n++) { + if(type(t->obj) != OT_NULL) { + //add back; + assert(t->refs != 0); + RefNode *nn = Add(::HashObj(t->obj)&(_numofslots-1),t->obj); + nn->refs = t->refs; + t->obj.Null(); + nfound++; + } + t++; + } + assert(nfound == oldnumofslots); + SQ_FREE(oldbucks,(oldnumofslots * sizeof(RefNode *)) + (oldnumofslots * sizeof(RefNode))); +} + +RefTable::RefNode *RefTable::Add(SQHash mainpos,SQObject &obj) +{ + RefNode *t = _buckets[mainpos]; + RefNode *newnode = _freelist; + newnode->obj = obj; + _buckets[mainpos] = newnode; + _freelist = _freelist->next; + newnode->next = t; + assert(newnode->refs == 0); + _slotused++; + return newnode; +} + +RefTable::RefNode *RefTable::Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add) +{ + RefNode *ref; + mainpos = ::HashObj(obj)&(_numofslots-1); + *prev = NULL; + for (ref = _buckets[mainpos]; ref; ) { + if(_rawval(ref->obj) == _rawval(obj) && type(ref->obj) == type(obj)) + break; + *prev = ref; + ref = ref->next; + } + if(ref == NULL && add) { + if(_numofslots == _slotused) { + assert(_freelist == 0); + Resize(_numofslots*2); + mainpos = ::HashObj(obj)&(_numofslots-1); + } + ref = Add(mainpos,obj); + } + return ref; +} + +void RefTable::AllocNodes(SQUnsignedInteger size) +{ + RefNode **bucks; + RefNode *nodes; + bucks = (RefNode **)SQ_MALLOC((size * sizeof(RefNode *)) + (size * sizeof(RefNode))); + nodes = (RefNode *)&bucks[size]; + RefNode *temp = nodes; + SQUnsignedInteger n; + for(n = 0; n < size - 1; n++) { + bucks[n] = NULL; + temp->refs = 0; + new (&temp->obj) SQObjectPtr; + temp->next = temp+1; + temp++; + } + bucks[n] = NULL; + temp->refs = 0; + new (&temp->obj) SQObjectPtr; + temp->next = NULL; + _freelist = nodes; + _nodes = nodes; + _buckets = bucks; + _slotused = 0; + _numofslots = size; +} +////////////////////////////////////////////////////////////////////////// +//SQStringTable +/* +* The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.) +* http://www.lua.org/copyright.html#4 +* http://www.lua.org/source/4.0.1/src_lstring.c.html +*/ + +SQStringTable::SQStringTable(SQSharedState *ss) +{ + _sharedstate = ss; + AllocNodes(4); + _slotused = 0; +} + +SQStringTable::~SQStringTable() +{ + SQ_FREE(_strings,sizeof(SQString*)*_numofslots); + _strings = NULL; +} + +void SQStringTable::AllocNodes(SQInteger size) +{ + _numofslots = size; + _strings = (SQString**)SQ_MALLOC(sizeof(SQString*)*_numofslots); + memset(_strings,0,sizeof(SQString*)*_numofslots); +} + +SQString *SQStringTable::Add(const SQChar *news,SQInteger len) +{ + if(len<0) + len = (SQInteger)scstrlen(news); + SQHash h = ::_hashstr(news,len)&(_numofslots-1); + SQString *s; + for (s = _strings[h]; s; s = s->_next){ + if(s->_len == len && (!memcmp(news,s->_val,rsl(len)))) + return s; //found + } + + SQString *t=(SQString *)SQ_MALLOC(rsl(len)+sizeof(SQString)); + new (t) SQString; + t->_sharedstate = _sharedstate; + memcpy(t->_val,news,rsl(len)); + t->_val[len] = _SC('\0'); + t->_len = len; + t->_hash = ::_hashstr(news,len); + t->_next = _strings[h]; + _strings[h] = t; + _slotused++; + if (_slotused > _numofslots) /* too crowded? */ + Resize(_numofslots*2); + return t; +} + +void SQStringTable::Resize(SQInteger size) +{ + SQInteger oldsize=_numofslots; + SQString **oldtable=_strings; + AllocNodes(size); + for (SQInteger i=0; i<oldsize; i++){ + SQString *p = oldtable[i]; + while(p){ + SQString *next = p->_next; + SQHash h = p->_hash&(_numofslots-1); + p->_next = _strings[h]; + _strings[h] = p; + p = next; + } + } + SQ_FREE(oldtable,oldsize*sizeof(SQString*)); +} + +void SQStringTable::Remove(SQString *bs) +{ + SQString *s; + SQString *prev=NULL; + SQHash h = bs->_hash&(_numofslots - 1); + + for (s = _strings[h]; s; ){ + if(s == bs){ + if(prev) + prev->_next = s->_next; + else + _strings[h] = s->_next; + _slotused--; + SQInteger slen = s->_len; + s->~SQString(); + SQ_FREE(s,sizeof(SQString) + rsl(slen)); + return; + } + prev = s; + s = s->_next; + } + assert(0);//if this fail something is wrong +} diff --git a/squirrel_3_0_1_stable/squirrel/sqstate.h b/squirrel_3_0_1_stable/squirrel/sqstate.h index 3ed3307d7..ee652e786 100644 --- a/squirrel_3_0_1_stable/squirrel/sqstate.h +++ b/squirrel_3_0_1_stable/squirrel/sqstate.h @@ -1,144 +1,144 @@ -/* see copyright notice in squirrel.h */
-#ifndef _SQSTATE_H_
-#define _SQSTATE_H_
-
-#include "squtils.h"
-#include "sqobject.h"
-struct SQString;
-struct SQTable;
-//max number of character for a printed number
-#define NUMBER_MAX_CHAR 50
-
-struct SQStringTable
-{
- SQStringTable(SQSharedState*ss);
- ~SQStringTable();
- SQString *Add(const SQChar *,SQInteger len);
- void Remove(SQString *);
-private:
- void Resize(SQInteger size);
- void AllocNodes(SQInteger size);
- SQString **_strings;
- SQUnsignedInteger _numofslots;
- SQUnsignedInteger _slotused;
- SQSharedState *_sharedstate;
-};
-
-struct RefTable {
- struct RefNode {
- SQObjectPtr obj;
- SQUnsignedInteger refs;
- struct RefNode *next;
- };
- RefTable();
- ~RefTable();
- void AddRef(SQObject &obj);
- SQBool Release(SQObject &obj);
- SQUnsignedInteger GetRefCount(SQObject &obj);
-#ifndef NO_GARBAGE_COLLECTOR
- void Mark(SQCollectable **chain);
-#endif
- void Finalize();
-private:
- RefNode *Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add);
- RefNode *Add(SQHash mainpos,SQObject &obj);
- void Resize(SQUnsignedInteger size);
- void AllocNodes(SQUnsignedInteger size);
- SQUnsignedInteger _numofslots;
- SQUnsignedInteger _slotused;
- RefNode *_nodes;
- RefNode *_freelist;
- RefNode **_buckets;
-};
-
-#define ADD_STRING(ss,str,len) ss->_stringtable->Add(str,len)
-#define REMOVE_STRING(ss,bstr) ss->_stringtable->Remove(bstr)
-
-struct SQObjectPtr;
-
-struct SQSharedState
-{
- SQSharedState();
- ~SQSharedState();
- void Init();
-public:
- SQChar* GetScratchPad(SQInteger size);
- SQInteger GetMetaMethodIdxByName(const SQObjectPtr &name);
-#ifndef NO_GARBAGE_COLLECTOR
- SQInteger CollectGarbage(SQVM *vm);
- void RunMark(SQVM *vm,SQCollectable **tchain);
- SQInteger ResurrectUnreachable(SQVM *vm);
- static void MarkObject(SQObjectPtr &o,SQCollectable **chain);
-#endif
- SQObjectPtrVec *_metamethods;
- SQObjectPtr _metamethodsmap;
- SQObjectPtrVec *_systemstrings;
- SQObjectPtrVec *_types;
- SQStringTable *_stringtable;
- RefTable _refs_table;
- SQObjectPtr _registry;
- SQObjectPtr _consts;
- SQObjectPtr _constructoridx;
-#ifndef NO_GARBAGE_COLLECTOR
- SQCollectable *_gc_chain;
-#endif
- SQObjectPtr _root_vm;
- SQObjectPtr _table_default_delegate;
- static SQRegFunction _table_default_delegate_funcz[];
- SQObjectPtr _array_default_delegate;
- static SQRegFunction _array_default_delegate_funcz[];
- SQObjectPtr _string_default_delegate;
- static SQRegFunction _string_default_delegate_funcz[];
- SQObjectPtr _number_default_delegate;
- static SQRegFunction _number_default_delegate_funcz[];
- SQObjectPtr _generator_default_delegate;
- static SQRegFunction _generator_default_delegate_funcz[];
- SQObjectPtr _closure_default_delegate;
- static SQRegFunction _closure_default_delegate_funcz[];
- SQObjectPtr _thread_default_delegate;
- static SQRegFunction _thread_default_delegate_funcz[];
- SQObjectPtr _class_default_delegate;
- static SQRegFunction _class_default_delegate_funcz[];
- SQObjectPtr _instance_default_delegate;
- static SQRegFunction _instance_default_delegate_funcz[];
- SQObjectPtr _weakref_default_delegate;
- static SQRegFunction _weakref_default_delegate_funcz[];
-
- SQCOMPILERERROR _compilererrorhandler;
- SQPRINTFUNCTION _printfunc;
- SQPRINTFUNCTION _errorfunc;
- bool _debuginfo;
- bool _notifyallexceptions;
-private:
- SQChar *_scratchpad;
- SQInteger _scratchpadsize;
-};
-
-#define _sp(s) (_sharedstate->GetScratchPad(s))
-#define _spval (_sharedstate->GetScratchPad(-1))
-
-#define _table_ddel _table(_sharedstate->_table_default_delegate)
-#define _array_ddel _table(_sharedstate->_array_default_delegate)
-#define _string_ddel _table(_sharedstate->_string_default_delegate)
-#define _number_ddel _table(_sharedstate->_number_default_delegate)
-#define _generator_ddel _table(_sharedstate->_generator_default_delegate)
-#define _closure_ddel _table(_sharedstate->_closure_default_delegate)
-#define _thread_ddel _table(_sharedstate->_thread_default_delegate)
-#define _class_ddel _table(_sharedstate->_class_default_delegate)
-#define _instance_ddel _table(_sharedstate->_instance_default_delegate)
-#define _weakref_ddel _table(_sharedstate->_weakref_default_delegate)
-
-#ifdef SQUNICODE //rsl REAL STRING LEN
-#define rsl(l) ((l)<<1)
-#else
-#define rsl(l) (l)
-#endif
-
-//extern SQObjectPtr _null_;
-
-bool CompileTypemask(SQIntVec &res,const SQChar *typemask);
-
-void *sq_vm_malloc(SQUnsignedInteger size);
-void *sq_vm_realloc(void *p,SQUnsignedInteger oldsize,SQUnsignedInteger size);
-void sq_vm_free(void *p,SQUnsignedInteger size);
-#endif //_SQSTATE_H_
+/* see copyright notice in squirrel.h */ +#ifndef _SQSTATE_H_ +#define _SQSTATE_H_ + +#include "squtils.h" +#include "sqobject.h" +struct SQString; +struct SQTable; +//max number of character for a printed number +#define NUMBER_MAX_CHAR 50 + +struct SQStringTable +{ + SQStringTable(SQSharedState*ss); + ~SQStringTable(); + SQString *Add(const SQChar *,SQInteger len); + void Remove(SQString *); +private: + void Resize(SQInteger size); + void AllocNodes(SQInteger size); + SQString **_strings; + SQUnsignedInteger _numofslots; + SQUnsignedInteger _slotused; + SQSharedState *_sharedstate; +}; + +struct RefTable { + struct RefNode { + SQObjectPtr obj; + SQUnsignedInteger refs; + struct RefNode *next; + }; + RefTable(); + ~RefTable(); + void AddRef(SQObject &obj); + SQBool Release(SQObject &obj); + SQUnsignedInteger GetRefCount(SQObject &obj); +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); +#endif + void Finalize(); +private: + RefNode *Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add); + RefNode *Add(SQHash mainpos,SQObject &obj); + void Resize(SQUnsignedInteger size); + void AllocNodes(SQUnsignedInteger size); + SQUnsignedInteger _numofslots; + SQUnsignedInteger _slotused; + RefNode *_nodes; + RefNode *_freelist; + RefNode **_buckets; +}; + +#define ADD_STRING(ss,str,len) ss->_stringtable->Add(str,len) +#define REMOVE_STRING(ss,bstr) ss->_stringtable->Remove(bstr) + +struct SQObjectPtr; + +struct SQSharedState +{ + SQSharedState(); + ~SQSharedState(); + void Init(); +public: + SQChar* GetScratchPad(SQInteger size); + SQInteger GetMetaMethodIdxByName(const SQObjectPtr &name); +#ifndef NO_GARBAGE_COLLECTOR + SQInteger CollectGarbage(SQVM *vm); + void RunMark(SQVM *vm,SQCollectable **tchain); + SQInteger ResurrectUnreachable(SQVM *vm); + static void MarkObject(SQObjectPtr &o,SQCollectable **chain); +#endif + SQObjectPtrVec *_metamethods; + SQObjectPtr _metamethodsmap; + SQObjectPtrVec *_systemstrings; + SQObjectPtrVec *_types; + SQStringTable *_stringtable; + RefTable _refs_table; + SQObjectPtr _registry; + SQObjectPtr _consts; + SQObjectPtr _constructoridx; +#ifndef NO_GARBAGE_COLLECTOR + SQCollectable *_gc_chain; +#endif + SQObjectPtr _root_vm; + SQObjectPtr _table_default_delegate; + static SQRegFunction _table_default_delegate_funcz[]; + SQObjectPtr _array_default_delegate; + static SQRegFunction _array_default_delegate_funcz[]; + SQObjectPtr _string_default_delegate; + static SQRegFunction _string_default_delegate_funcz[]; + SQObjectPtr _number_default_delegate; + static SQRegFunction _number_default_delegate_funcz[]; + SQObjectPtr _generator_default_delegate; + static SQRegFunction _generator_default_delegate_funcz[]; + SQObjectPtr _closure_default_delegate; + static SQRegFunction _closure_default_delegate_funcz[]; + SQObjectPtr _thread_default_delegate; + static SQRegFunction _thread_default_delegate_funcz[]; + SQObjectPtr _class_default_delegate; + static SQRegFunction _class_default_delegate_funcz[]; + SQObjectPtr _instance_default_delegate; + static SQRegFunction _instance_default_delegate_funcz[]; + SQObjectPtr _weakref_default_delegate; + static SQRegFunction _weakref_default_delegate_funcz[]; + + SQCOMPILERERROR _compilererrorhandler; + SQPRINTFUNCTION _printfunc; + SQPRINTFUNCTION _errorfunc; + bool _debuginfo; + bool _notifyallexceptions; +private: + SQChar *_scratchpad; + SQInteger _scratchpadsize; +}; + +#define _sp(s) (_sharedstate->GetScratchPad(s)) +#define _spval (_sharedstate->GetScratchPad(-1)) + +#define _table_ddel _table(_sharedstate->_table_default_delegate) +#define _array_ddel _table(_sharedstate->_array_default_delegate) +#define _string_ddel _table(_sharedstate->_string_default_delegate) +#define _number_ddel _table(_sharedstate->_number_default_delegate) +#define _generator_ddel _table(_sharedstate->_generator_default_delegate) +#define _closure_ddel _table(_sharedstate->_closure_default_delegate) +#define _thread_ddel _table(_sharedstate->_thread_default_delegate) +#define _class_ddel _table(_sharedstate->_class_default_delegate) +#define _instance_ddel _table(_sharedstate->_instance_default_delegate) +#define _weakref_ddel _table(_sharedstate->_weakref_default_delegate) + +#ifdef SQUNICODE //rsl REAL STRING LEN +#define rsl(l) ((l)<<1) +#else +#define rsl(l) (l) +#endif + +//extern SQObjectPtr _null_; + +bool CompileTypemask(SQIntVec &res,const SQChar *typemask); + +void *sq_vm_malloc(SQUnsignedInteger size); +void *sq_vm_realloc(void *p,SQUnsignedInteger oldsize,SQUnsignedInteger size); +void sq_vm_free(void *p,SQUnsignedInteger size); +#endif //_SQSTATE_H_ diff --git a/squirrel_3_0_1_stable/squirrel/sqstring.h b/squirrel_3_0_1_stable/squirrel/sqstring.h index 235d19059..14f09e1b0 100644 --- a/squirrel_3_0_1_stable/squirrel/sqstring.h +++ b/squirrel_3_0_1_stable/squirrel/sqstring.h @@ -1,31 +1,31 @@ -/* see copyright notice in squirrel.h */
-#ifndef _SQSTRING_H_
-#define _SQSTRING_H_
-
-inline SQHash _hashstr (const SQChar *s, size_t l)
-{
- SQHash h = (SQHash)l; /* seed */
- size_t step = (l>>5)|1; /* if string is too long, don't hash all its chars */
- for (; l>=step; l-=step)
- h = h ^ ((h<<5)+(h>>2)+(unsigned short)*(s++));
- return h;
-}
-
-struct SQString : public SQRefCounted
-{
- SQString(){}
- ~SQString(){}
-public:
- static SQString *Create(SQSharedState *ss, const SQChar *, SQInteger len = -1 );
- SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval);
- void Release();
- SQSharedState *_sharedstate;
- SQString *_next; //chain for the string table
- SQInteger _len;
- SQHash _hash;
- SQChar _val[1];
-};
-
-
-
-#endif //_SQSTRING_H_
+/* see copyright notice in squirrel.h */ +#ifndef _SQSTRING_H_ +#define _SQSTRING_H_ + +inline SQHash _hashstr (const SQChar *s, size_t l) +{ + SQHash h = (SQHash)l; /* seed */ + size_t step = (l>>5)|1; /* if string is too long, don't hash all its chars */ + for (; l>=step; l-=step) + h = h ^ ((h<<5)+(h>>2)+(unsigned short)*(s++)); + return h; +} + +struct SQString : public SQRefCounted +{ + SQString(){} + ~SQString(){} +public: + static SQString *Create(SQSharedState *ss, const SQChar *, SQInteger len = -1 ); + SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval); + void Release(); + SQSharedState *_sharedstate; + SQString *_next; //chain for the string table + SQInteger _len; + SQHash _hash; + SQChar _val[1]; +}; + + + +#endif //_SQSTRING_H_ diff --git a/squirrel_3_0_1_stable/squirrel/sqtable.cpp b/squirrel_3_0_1_stable/squirrel/sqtable.cpp index fe3d5f2a1..bc43124a3 100644 --- a/squirrel_3_0_1_stable/squirrel/sqtable.cpp +++ b/squirrel_3_0_1_stable/squirrel/sqtable.cpp @@ -1,220 +1,220 @@ -/*
-see copyright notice in squirrel.h
-*/
-#include "sqpcheader.h"
-#include "sqvm.h"
-#include "sqtable.h"
-#include "sqfuncproto.h"
-#include "sqclosure.h"
-
-SQTable::SQTable(SQSharedState *ss,SQInteger nInitialSize)
-{
- SQInteger pow2size=MINPOWER2;
- while(nInitialSize>pow2size)pow2size=pow2size<<1;
- AllocNodes(pow2size);
- _usednodes = 0;
- _delegate = NULL;
- INIT_CHAIN();
- ADD_TO_CHAIN(&_sharedstate->_gc_chain,this);
-}
-
-void SQTable::Remove(const SQObjectPtr &key)
-{
-
- _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1));
- if (n) {
- n->val.Null();
- n->key.Null();
- _usednodes--;
- Rehash(false);
- }
-}
-
-void SQTable::AllocNodes(SQInteger nSize)
-{
- _HashNode *nodes=(_HashNode *)SQ_MALLOC(sizeof(_HashNode)*nSize);
- for(SQInteger i=0;i<nSize;i++){
- _HashNode &n = nodes[i];
- new (&n) _HashNode;
- n.next=NULL;
- }
- _numofnodes=nSize;
- _nodes=nodes;
- _firstfree=&_nodes[_numofnodes-1];
-}
-
-void SQTable::Rehash(bool force)
-{
- SQInteger oldsize=_numofnodes;
- //prevent problems with the integer division
- if(oldsize<4)oldsize=4;
- _HashNode *nold=_nodes;
- SQInteger nelems=CountUsed();
- if (nelems >= oldsize-oldsize/4) /* using more than 3/4? */
- AllocNodes(oldsize*2);
- else if (nelems <= oldsize/4 && /* less than 1/4? */
- oldsize > MINPOWER2)
- AllocNodes(oldsize/2);
- else if(force)
- AllocNodes(oldsize);
- else
- return;
- _usednodes = 0;
- for (SQInteger i=0; i<oldsize; i++) {
- _HashNode *old = nold+i;
- if (type(old->key) != OT_NULL)
- NewSlot(old->key,old->val);
- }
- for(SQInteger k=0;k<oldsize;k++)
- nold[k].~_HashNode();
- SQ_FREE(nold,oldsize*sizeof(_HashNode));
-}
-
-SQTable *SQTable::Clone()
-{
- SQTable *nt=Create(_opt_ss(this),_numofnodes);
-#ifdef _FAST_CLONE
- _HashNode *basesrc = _nodes;
- _HashNode *basedst = nt->_nodes;
- _HashNode *src = _nodes;
- _HashNode *dst = nt->_nodes;
- SQInteger n = 0;
- for(n = 0; n < _numofnodes; n++) {
- dst->key = src->key;
- dst->val = src->val;
- if(src->next) {
- assert(src->next > basesrc);
- dst->next = basedst + (src->next - basesrc);
- assert(dst != dst->next);
- }
- dst++;
- src++;
- }
- assert(_firstfree > basesrc);
- assert(_firstfree != NULL);
- nt->_firstfree = basedst + (_firstfree - basesrc);
-#else
- SQInteger ridx=0;
- SQObjectPtr key,val;
- while((ridx=Next(true,ridx,key,val))!=-1){
- nt->NewSlot(key,val);
- }
-#endif
- nt->SetDelegate(_delegate);
- return nt;
-}
-
-bool SQTable::Get(const SQObjectPtr &key,SQObjectPtr &val)
-{
- if(type(key) == OT_NULL)
- return false;
- _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1));
- if (n) {
- val = _realval(n->val);
- return true;
- }
- return false;
-}
-bool SQTable::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val)
-{
- assert(type(key) != OT_NULL);
- SQHash h = HashObj(key) & (_numofnodes - 1);
- _HashNode *n = _Get(key, h);
- if (n) {
- n->val = val;
- return false;
- }
- _HashNode *mp = &_nodes[h];
- n = mp;
-
-
- //key not found I'll insert it
- //main pos is not free
-
- if(type(mp->key) != OT_NULL) {
- n = _firstfree; /* get a free place */
- SQHash mph = HashObj(mp->key) & (_numofnodes - 1);
- _HashNode *othern; /* main position of colliding node */
-
- if (mp > n && (othern = &_nodes[mph]) != mp){
- /* yes; move colliding node into free position */
- while (othern->next != mp){
- assert(othern->next != NULL);
- othern = othern->next; /* find previous */
- }
- othern->next = n; /* redo the chain with `n' in place of `mp' */
- n->key = mp->key;
- n->val = mp->val;/* copy colliding node into free pos. (mp->next also goes) */
- n->next = mp->next;
- mp->key.Null();
- mp->val.Null();
- mp->next = NULL; /* now `mp' is free */
- }
- else{
- /* new node will go into free position */
- n->next = mp->next; /* chain new position */
- mp->next = n;
- mp = n;
- }
- }
- mp->key = key;
-
- for (;;) { /* correct `firstfree' */
- if (type(_firstfree->key) == OT_NULL && _firstfree->next == NULL) {
- mp->val = val;
- _usednodes++;
- return true; /* OK; table still has a free place */
- }
- else if (_firstfree == _nodes) break; /* cannot decrement from here */
- else (_firstfree)--;
- }
- Rehash(true);
- return NewSlot(key, val);
-}
-
-SQInteger SQTable::Next(bool getweakrefs,const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval)
-{
- SQInteger idx = (SQInteger)TranslateIndex(refpos);
- while (idx < _numofnodes) {
- if(type(_nodes[idx].key) != OT_NULL) {
- //first found
- _HashNode &n = _nodes[idx];
- outkey = n.key;
- outval = getweakrefs?(SQObject)n.val:_realval(n.val);
- //return idx for the next iteration
- return ++idx;
- }
- ++idx;
- }
- //nothing to iterate anymore
- return -1;
-}
-
-
-bool SQTable::Set(const SQObjectPtr &key, const SQObjectPtr &val)
-{
- _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1));
- if (n) {
- n->val = val;
- return true;
- }
- return false;
-}
-
-void SQTable::_ClearNodes()
-{
- for(SQInteger i = 0;i < _numofnodes; i++) { _HashNode &n = _nodes[i]; n.key.Null(); n.val.Null(); }
-}
-
-void SQTable::Finalize()
-{
- _ClearNodes();
- SetDelegate(NULL);
-}
-
-void SQTable::Clear()
-{
- _ClearNodes();
- _usednodes = 0;
- Rehash(true);
-}
+/* +see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include "sqvm.h" +#include "sqtable.h" +#include "sqfuncproto.h" +#include "sqclosure.h" + +SQTable::SQTable(SQSharedState *ss,SQInteger nInitialSize) +{ + SQInteger pow2size=MINPOWER2; + while(nInitialSize>pow2size)pow2size=pow2size<<1; + AllocNodes(pow2size); + _usednodes = 0; + _delegate = NULL; + INIT_CHAIN(); + ADD_TO_CHAIN(&_sharedstate->_gc_chain,this); +} + +void SQTable::Remove(const SQObjectPtr &key) +{ + + _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1)); + if (n) { + n->val.Null(); + n->key.Null(); + _usednodes--; + Rehash(false); + } +} + +void SQTable::AllocNodes(SQInteger nSize) +{ + _HashNode *nodes=(_HashNode *)SQ_MALLOC(sizeof(_HashNode)*nSize); + for(SQInteger i=0;i<nSize;i++){ + _HashNode &n = nodes[i]; + new (&n) _HashNode; + n.next=NULL; + } + _numofnodes=nSize; + _nodes=nodes; + _firstfree=&_nodes[_numofnodes-1]; +} + +void SQTable::Rehash(bool force) +{ + SQInteger oldsize=_numofnodes; + //prevent problems with the integer division + if(oldsize<4)oldsize=4; + _HashNode *nold=_nodes; + SQInteger nelems=CountUsed(); + if (nelems >= oldsize-oldsize/4) /* using more than 3/4? */ + AllocNodes(oldsize*2); + else if (nelems <= oldsize/4 && /* less than 1/4? */ + oldsize > MINPOWER2) + AllocNodes(oldsize/2); + else if(force) + AllocNodes(oldsize); + else + return; + _usednodes = 0; + for (SQInteger i=0; i<oldsize; i++) { + _HashNode *old = nold+i; + if (type(old->key) != OT_NULL) + NewSlot(old->key,old->val); + } + for(SQInteger k=0;k<oldsize;k++) + nold[k].~_HashNode(); + SQ_FREE(nold,oldsize*sizeof(_HashNode)); +} + +SQTable *SQTable::Clone() +{ + SQTable *nt=Create(_opt_ss(this),_numofnodes); +#ifdef _FAST_CLONE + _HashNode *basesrc = _nodes; + _HashNode *basedst = nt->_nodes; + _HashNode *src = _nodes; + _HashNode *dst = nt->_nodes; + SQInteger n = 0; + for(n = 0; n < _numofnodes; n++) { + dst->key = src->key; + dst->val = src->val; + if(src->next) { + assert(src->next > basesrc); + dst->next = basedst + (src->next - basesrc); + assert(dst != dst->next); + } + dst++; + src++; + } + assert(_firstfree > basesrc); + assert(_firstfree != NULL); + nt->_firstfree = basedst + (_firstfree - basesrc); +#else + SQInteger ridx=0; + SQObjectPtr key,val; + while((ridx=Next(true,ridx,key,val))!=-1){ + nt->NewSlot(key,val); + } +#endif + nt->SetDelegate(_delegate); + return nt; +} + +bool SQTable::Get(const SQObjectPtr &key,SQObjectPtr &val) +{ + if(type(key) == OT_NULL) + return false; + _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1)); + if (n) { + val = _realval(n->val); + return true; + } + return false; +} +bool SQTable::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val) +{ + assert(type(key) != OT_NULL); + SQHash h = HashObj(key) & (_numofnodes - 1); + _HashNode *n = _Get(key, h); + if (n) { + n->val = val; + return false; + } + _HashNode *mp = &_nodes[h]; + n = mp; + + + //key not found I'll insert it + //main pos is not free + + if(type(mp->key) != OT_NULL) { + n = _firstfree; /* get a free place */ + SQHash mph = HashObj(mp->key) & (_numofnodes - 1); + _HashNode *othern; /* main position of colliding node */ + + if (mp > n && (othern = &_nodes[mph]) != mp){ + /* yes; move colliding node into free position */ + while (othern->next != mp){ + assert(othern->next != NULL); + othern = othern->next; /* find previous */ + } + othern->next = n; /* redo the chain with `n' in place of `mp' */ + n->key = mp->key; + n->val = mp->val;/* copy colliding node into free pos. (mp->next also goes) */ + n->next = mp->next; + mp->key.Null(); + mp->val.Null(); + mp->next = NULL; /* now `mp' is free */ + } + else{ + /* new node will go into free position */ + n->next = mp->next; /* chain new position */ + mp->next = n; + mp = n; + } + } + mp->key = key; + + for (;;) { /* correct `firstfree' */ + if (type(_firstfree->key) == OT_NULL && _firstfree->next == NULL) { + mp->val = val; + _usednodes++; + return true; /* OK; table still has a free place */ + } + else if (_firstfree == _nodes) break; /* cannot decrement from here */ + else (_firstfree)--; + } + Rehash(true); + return NewSlot(key, val); +} + +SQInteger SQTable::Next(bool getweakrefs,const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval) +{ + SQInteger idx = (SQInteger)TranslateIndex(refpos); + while (idx < _numofnodes) { + if(type(_nodes[idx].key) != OT_NULL) { + //first found + _HashNode &n = _nodes[idx]; + outkey = n.key; + outval = getweakrefs?(SQObject)n.val:_realval(n.val); + //return idx for the next iteration + return ++idx; + } + ++idx; + } + //nothing to iterate anymore + return -1; +} + + +bool SQTable::Set(const SQObjectPtr &key, const SQObjectPtr &val) +{ + _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1)); + if (n) { + n->val = val; + return true; + } + return false; +} + +void SQTable::_ClearNodes() +{ + for(SQInteger i = 0;i < _numofnodes; i++) { _HashNode &n = _nodes[i]; n.key.Null(); n.val.Null(); } +} + +void SQTable::Finalize() +{ + _ClearNodes(); + SetDelegate(NULL); +} + +void SQTable::Clear() +{ + _ClearNodes(); + _usednodes = 0; + Rehash(true); +} diff --git a/squirrel_3_0_1_stable/squirrel/sqtable.h b/squirrel_3_0_1_stable/squirrel/sqtable.h index 2f6487023..b2ba0ba98 100644 --- a/squirrel_3_0_1_stable/squirrel/sqtable.h +++ b/squirrel_3_0_1_stable/squirrel/sqtable.h @@ -1,92 +1,92 @@ -/* see copyright notice in squirrel.h */
-#ifndef _SQTABLE_H_
-#define _SQTABLE_H_
-/*
-* The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.)
-* http://www.lua.org/copyright.html#4
-* http://www.lua.org/source/4.0.1/src_ltable.c.html
-*/
-
-#include "sqstring.h"
-
-
-#define hashptr(p) ((SQHash)(((SQInteger)p) >> 3))
-
-inline SQHash HashObj(const SQObjectPtr &key)
-{
- switch(type(key)) {
- case OT_STRING: return _string(key)->_hash;
- case OT_FLOAT: return (SQHash)((SQInteger)_float(key));
- case OT_BOOL: case OT_INTEGER: return (SQHash)((SQInteger)_integer(key));
- default: return hashptr(key._unVal.pRefCounted);
- }
-}
-
-struct SQTable : public SQDelegable
-{
-private:
- struct _HashNode
- {
- _HashNode() { next = NULL; }
- SQObjectPtr val;
- SQObjectPtr key;
- _HashNode *next;
- };
- _HashNode *_firstfree;
- _HashNode *_nodes;
- SQInteger _numofnodes;
- SQInteger _usednodes;
-
-///////////////////////////
- void AllocNodes(SQInteger nSize);
- void Rehash(bool force);
- SQTable(SQSharedState *ss, SQInteger nInitialSize);
- void _ClearNodes();
-public:
- static SQTable* Create(SQSharedState *ss,SQInteger nInitialSize)
- {
- SQTable *newtable = (SQTable*)SQ_MALLOC(sizeof(SQTable));
- new (newtable) SQTable(ss, nInitialSize);
- newtable->_delegate = NULL;
- return newtable;
- }
- void Finalize();
- SQTable *Clone();
- ~SQTable()
- {
- SetDelegate(NULL);
- REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this);
- for (SQInteger i = 0; i < _numofnodes; i++) _nodes[i].~_HashNode();
- SQ_FREE(_nodes, _numofnodes * sizeof(_HashNode));
- }
-#ifndef NO_GARBAGE_COLLECTOR
- void Mark(SQCollectable **chain);
- SQObjectType GetType() {return OT_TABLE;}
-#endif
- inline _HashNode *_Get(const SQObjectPtr &key,SQHash hash)
- {
- _HashNode *n = &_nodes[hash];
- do{
- if(_rawval(n->key) == _rawval(key) && type(n->key) == type(key)){
- return n;
- }
- }while((n = n->next));
- return NULL;
- }
- bool Get(const SQObjectPtr &key,SQObjectPtr &val);
- void Remove(const SQObjectPtr &key);
- bool Set(const SQObjectPtr &key, const SQObjectPtr &val);
- //returns true if a new slot has been created false if it was already present
- bool NewSlot(const SQObjectPtr &key,const SQObjectPtr &val);
- SQInteger Next(bool getweakrefs,const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval);
-
- SQInteger CountUsed(){ return _usednodes;}
- void Clear();
- void Release()
- {
- sq_delete(this, SQTable);
- }
-
-};
-
-#endif //_SQTABLE_H_
+/* see copyright notice in squirrel.h */ +#ifndef _SQTABLE_H_ +#define _SQTABLE_H_ +/* +* The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.) +* http://www.lua.org/copyright.html#4 +* http://www.lua.org/source/4.0.1/src_ltable.c.html +*/ + +#include "sqstring.h" + + +#define hashptr(p) ((SQHash)(((SQInteger)p) >> 3)) + +inline SQHash HashObj(const SQObjectPtr &key) +{ + switch(type(key)) { + case OT_STRING: return _string(key)->_hash; + case OT_FLOAT: return (SQHash)((SQInteger)_float(key)); + case OT_BOOL: case OT_INTEGER: return (SQHash)((SQInteger)_integer(key)); + default: return hashptr(key._unVal.pRefCounted); + } +} + +struct SQTable : public SQDelegable +{ +private: + struct _HashNode + { + _HashNode() { next = NULL; } + SQObjectPtr val; + SQObjectPtr key; + _HashNode *next; + }; + _HashNode *_firstfree; + _HashNode *_nodes; + SQInteger _numofnodes; + SQInteger _usednodes; + +/////////////////////////// + void AllocNodes(SQInteger nSize); + void Rehash(bool force); + SQTable(SQSharedState *ss, SQInteger nInitialSize); + void _ClearNodes(); +public: + static SQTable* Create(SQSharedState *ss,SQInteger nInitialSize) + { + SQTable *newtable = (SQTable*)SQ_MALLOC(sizeof(SQTable)); + new (newtable) SQTable(ss, nInitialSize); + newtable->_delegate = NULL; + return newtable; + } + void Finalize(); + SQTable *Clone(); + ~SQTable() + { + SetDelegate(NULL); + REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); + for (SQInteger i = 0; i < _numofnodes; i++) _nodes[i].~_HashNode(); + SQ_FREE(_nodes, _numofnodes * sizeof(_HashNode)); + } +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + SQObjectType GetType() {return OT_TABLE;} +#endif + inline _HashNode *_Get(const SQObjectPtr &key,SQHash hash) + { + _HashNode *n = &_nodes[hash]; + do{ + if(_rawval(n->key) == _rawval(key) && type(n->key) == type(key)){ + return n; + } + }while((n = n->next)); + return NULL; + } + bool Get(const SQObjectPtr &key,SQObjectPtr &val); + void Remove(const SQObjectPtr &key); + bool Set(const SQObjectPtr &key, const SQObjectPtr &val); + //returns true if a new slot has been created false if it was already present + bool NewSlot(const SQObjectPtr &key,const SQObjectPtr &val); + SQInteger Next(bool getweakrefs,const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval); + + SQInteger CountUsed(){ return _usednodes;} + void Clear(); + void Release() + { + sq_delete(this, SQTable); + } + +}; + +#endif //_SQTABLE_H_ diff --git a/squirrel_3_0_1_stable/squirrel/squserdata.h b/squirrel_3_0_1_stable/squirrel/squserdata.h index dea27ae78..2bf1b0709 100644 --- a/squirrel_3_0_1_stable/squirrel/squserdata.h +++ b/squirrel_3_0_1_stable/squirrel/squserdata.h @@ -1,40 +1,40 @@ -/* see copyright notice in squirrel.h */
-#ifndef _SQUSERDATA_H_
-#define _SQUSERDATA_H_
-
-struct SQUserData : SQDelegable
-{
- SQUserData(SQSharedState *ss){ _delegate = 0; _hook = NULL; INIT_CHAIN(); ADD_TO_CHAIN(&_ss(this)->_gc_chain, this); }
- ~SQUserData()
- {
- REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain, this);
- SetDelegate(NULL);
- }
- static SQUserData* Create(SQSharedState *ss, SQInteger size)
- {
- SQUserData* ud = (SQUserData*)SQ_MALLOC(sq_aligning(sizeof(SQUserData))+size);
- new (ud) SQUserData(ss);
- ud->_size = size;
- ud->_typetag = 0;
- return ud;
- }
-#ifndef NO_GARBAGE_COLLECTOR
- void Mark(SQCollectable **chain);
- void Finalize(){SetDelegate(NULL);}
- SQObjectType GetType(){ return OT_USERDATA;}
-#endif
- void Release() {
- if (_hook) _hook((SQUserPointer)sq_aligning(this + 1),_size);
- SQInteger tsize = _size;
- this->~SQUserData();
- SQ_FREE(this, sq_aligning(sizeof(SQUserData)) + tsize);
- }
-
-
- SQInteger _size;
- SQRELEASEHOOK _hook;
- SQUserPointer _typetag;
- //SQChar _val[1];
-};
-
-#endif //_SQUSERDATA_H_
+/* see copyright notice in squirrel.h */ +#ifndef _SQUSERDATA_H_ +#define _SQUSERDATA_H_ + +struct SQUserData : SQDelegable +{ + SQUserData(SQSharedState *ss){ _delegate = 0; _hook = NULL; INIT_CHAIN(); ADD_TO_CHAIN(&_ss(this)->_gc_chain, this); } + ~SQUserData() + { + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain, this); + SetDelegate(NULL); + } + static SQUserData* Create(SQSharedState *ss, SQInteger size) + { + SQUserData* ud = (SQUserData*)SQ_MALLOC(sq_aligning(sizeof(SQUserData))+size); + new (ud) SQUserData(ss); + ud->_size = size; + ud->_typetag = 0; + return ud; + } +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + void Finalize(){SetDelegate(NULL);} + SQObjectType GetType(){ return OT_USERDATA;} +#endif + void Release() { + if (_hook) _hook((SQUserPointer)sq_aligning(this + 1),_size); + SQInteger tsize = _size; + this->~SQUserData(); + SQ_FREE(this, sq_aligning(sizeof(SQUserData)) + tsize); + } + + + SQInteger _size; + SQRELEASEHOOK _hook; + SQUserPointer _typetag; + //SQChar _val[1]; +}; + +#endif //_SQUSERDATA_H_ diff --git a/squirrel_3_0_1_stable/squirrel/squtils.h b/squirrel_3_0_1_stable/squirrel/squtils.h index bff7d24bb..f3510beea 100644 --- a/squirrel_3_0_1_stable/squirrel/squtils.h +++ b/squirrel_3_0_1_stable/squirrel/squtils.h @@ -1,112 +1,112 @@ -/* see copyright notice in squirrel.h */
-#ifndef _SQUTILS_H_
-#define _SQUTILS_H_
-
-#define sq_new(__ptr,__type) {__ptr=(__type *)sq_vm_malloc(sizeof(__type));new (__ptr) __type;}
-#define sq_delete(__ptr,__type) {__ptr->~__type();sq_vm_free(__ptr,sizeof(__type));}
-#define SQ_MALLOC(__size) sq_vm_malloc((__size));
-#define SQ_FREE(__ptr,__size) sq_vm_free((__ptr),(__size));
-#define SQ_REALLOC(__ptr,__oldsize,__size) sq_vm_realloc((__ptr),(__oldsize),(__size));
-
-#define sq_aligning(v) (((size_t)(v) + (SQ_ALIGNMENT-1)) & (~(SQ_ALIGNMENT-1)))
-
-//sqvector mini vector class, supports objects by value
-template<typename T> class sqvector
-{
-public:
- sqvector()
- {
- _vals = NULL;
- _size = 0;
- _allocated = 0;
- }
- sqvector(const sqvector<T>& v)
- {
- copy(v);
- }
- void copy(const sqvector<T>& v)
- {
- if(_size) {
- resize(0); //destroys all previous stuff
- }
- //resize(v._size);
- if(v._size > _allocated) {
- _realloc(v._size);
- }
- for(SQUnsignedInteger i = 0; i < v._size; i++) {
- new ((void *)&_vals[i]) T(v._vals[i]);
- }
- _size = v._size;
- }
- ~sqvector()
- {
- if(_allocated) {
- for(SQUnsignedInteger i = 0; i < _size; i++)
- _vals[i].~T();
- SQ_FREE(_vals, (_allocated * sizeof(T)));
- }
- }
- void reserve(SQUnsignedInteger newsize) { _realloc(newsize); }
- void resize(SQUnsignedInteger newsize, const T& fill = T())
- {
- if(newsize > _allocated)
- _realloc(newsize);
- if(newsize > _size) {
- while(_size < newsize) {
- new ((void *)&_vals[_size]) T(fill);
- _size++;
- }
- }
- else{
- for(SQUnsignedInteger i = newsize; i < _size; i++) {
- _vals[i].~T();
- }
- _size = newsize;
- }
- }
- void shrinktofit() { if(_size > 4) { _realloc(_size); } }
- T& top() const { return _vals[_size - 1]; }
- inline SQUnsignedInteger size() const { return _size; }
- bool empty() const { return (_size <= 0); }
- inline T &push_back(const T& val = T())
- {
- if(_allocated <= _size)
- _realloc(_size * 2);
- return *(new ((void *)&_vals[_size++]) T(val));
- }
- inline void pop_back()
- {
- _size--; _vals[_size].~T();
- }
- void insert(SQUnsignedInteger idx, const T& val)
- {
- resize(_size + 1);
- for(SQUnsignedInteger i = _size - 1; i > idx; i--) {
- _vals[i] = _vals[i - 1];
- }
- _vals[idx] = val;
- }
- void remove(SQUnsignedInteger idx)
- {
- _vals[idx].~T();
- if(idx < (_size - 1)) {
- memcpy(&_vals[idx], &_vals[idx+1], sizeof(T) * (_size - idx - 1));
- }
- _size--;
- }
- SQUnsignedInteger capacity() { return _allocated; }
- inline T &back() const { return _vals[_size - 1]; }
- inline T& operator[](SQUnsignedInteger pos) const{ return _vals[pos]; }
- T* _vals;
-private:
- void _realloc(SQUnsignedInteger newsize)
- {
- newsize = (newsize > 0)?newsize:4;
- _vals = (T*)SQ_REALLOC(_vals, _allocated * sizeof(T), newsize * sizeof(T));
- _allocated = newsize;
- }
- SQUnsignedInteger _size;
- SQUnsignedInteger _allocated;
-};
-
-#endif //_SQUTILS_H_
+/* see copyright notice in squirrel.h */ +#ifndef _SQUTILS_H_ +#define _SQUTILS_H_ + +#define sq_new(__ptr,__type) {__ptr=(__type *)sq_vm_malloc(sizeof(__type));new (__ptr) __type;} +#define sq_delete(__ptr,__type) {__ptr->~__type();sq_vm_free(__ptr,sizeof(__type));} +#define SQ_MALLOC(__size) sq_vm_malloc((__size)); +#define SQ_FREE(__ptr,__size) sq_vm_free((__ptr),(__size)); +#define SQ_REALLOC(__ptr,__oldsize,__size) sq_vm_realloc((__ptr),(__oldsize),(__size)); + +#define sq_aligning(v) (((size_t)(v) + (SQ_ALIGNMENT-1)) & (~(SQ_ALIGNMENT-1))) + +//sqvector mini vector class, supports objects by value +template<typename T> class sqvector +{ +public: + sqvector() + { + _vals = NULL; + _size = 0; + _allocated = 0; + } + sqvector(const sqvector<T>& v) + { + copy(v); + } + void copy(const sqvector<T>& v) + { + if(_size) { + resize(0); //destroys all previous stuff + } + //resize(v._size); + if(v._size > _allocated) { + _realloc(v._size); + } + for(SQUnsignedInteger i = 0; i < v._size; i++) { + new ((void *)&_vals[i]) T(v._vals[i]); + } + _size = v._size; + } + ~sqvector() + { + if(_allocated) { + for(SQUnsignedInteger i = 0; i < _size; i++) + _vals[i].~T(); + SQ_FREE(_vals, (_allocated * sizeof(T))); + } + } + void reserve(SQUnsignedInteger newsize) { _realloc(newsize); } + void resize(SQUnsignedInteger newsize, const T& fill = T()) + { + if(newsize > _allocated) + _realloc(newsize); + if(newsize > _size) { + while(_size < newsize) { + new ((void *)&_vals[_size]) T(fill); + _size++; + } + } + else{ + for(SQUnsignedInteger i = newsize; i < _size; i++) { + _vals[i].~T(); + } + _size = newsize; + } + } + void shrinktofit() { if(_size > 4) { _realloc(_size); } } + T& top() const { return _vals[_size - 1]; } + inline SQUnsignedInteger size() const { return _size; } + bool empty() const { return (_size <= 0); } + inline T &push_back(const T& val = T()) + { + if(_allocated <= _size) + _realloc(_size * 2); + return *(new ((void *)&_vals[_size++]) T(val)); + } + inline void pop_back() + { + _size--; _vals[_size].~T(); + } + void insert(SQUnsignedInteger idx, const T& val) + { + resize(_size + 1); + for(SQUnsignedInteger i = _size - 1; i > idx; i--) { + _vals[i] = _vals[i - 1]; + } + _vals[idx] = val; + } + void remove(SQUnsignedInteger idx) + { + _vals[idx].~T(); + if(idx < (_size - 1)) { + memcpy(&_vals[idx], &_vals[idx+1], sizeof(T) * (_size - idx - 1)); + } + _size--; + } + SQUnsignedInteger capacity() { return _allocated; } + inline T &back() const { return _vals[_size - 1]; } + inline T& operator[](SQUnsignedInteger pos) const{ return _vals[pos]; } + T* _vals; +private: + void _realloc(SQUnsignedInteger newsize) + { + newsize = (newsize > 0)?newsize:4; + _vals = (T*)SQ_REALLOC(_vals, _allocated * sizeof(T), newsize * sizeof(T)); + _allocated = newsize; + } + SQUnsignedInteger _size; + SQUnsignedInteger _allocated; +}; + +#endif //_SQUTILS_H_ diff --git a/squirrel_3_0_1_stable/squirrel/sqvm.cpp b/squirrel_3_0_1_stable/squirrel/sqvm.cpp index bd8ebcc1a..b6ad21836 100644 --- a/squirrel_3_0_1_stable/squirrel/sqvm.cpp +++ b/squirrel_3_0_1_stable/squirrel/sqvm.cpp @@ -1,1714 +1,1714 @@ -/*
- see copyright notice in squirrel.h
-*/
-#include "sqpcheader.h"
-#include <math.h>
-#include <stdlib.h>
-#include "sqopcodes.h"
-#include "sqvm.h"
-#include "sqfuncproto.h"
-#include "sqclosure.h"
-#include "sqstring.h"
-#include "sqtable.h"
-#include "squserdata.h"
-#include "sqarray.h"
-#include "sqclass.h"
-
-#define TOP() (_stack._vals[_top-1])
-
-bool SQVM::BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2)
-{
- SQInteger res;
- if((type(o1)|type(o2)) == OT_INTEGER)
- {
- SQInteger i1 = _integer(o1), i2 = _integer(o2);
- switch(op) {
- case BW_AND: res = i1 & i2; break;
- case BW_OR: res = i1 | i2; break;
- case BW_XOR: res = i1 ^ i2; break;
- case BW_SHIFTL: res = i1 << i2; break;
- case BW_SHIFTR: res = i1 >> i2; break;
- case BW_USHIFTR:res = (SQInteger)(*((SQUnsignedInteger*)&i1) >> i2); break;
- default: { Raise_Error(_SC("internal vm error bitwise op failed")); return false; }
- }
- }
- else { Raise_Error(_SC("bitwise op between '%s' and '%s'"),GetTypeName(o1),GetTypeName(o2)); return false;}
- trg = res;
- return true;
-}
-
-#define _ARITH_(op,trg,o1,o2) \
-{ \
- SQInteger tmask = type(o1)|type(o2); \
- switch(tmask) { \
- case OT_INTEGER: trg = _integer(o1) op _integer(o2);break; \
- case (OT_FLOAT|OT_INTEGER): \
- case (OT_FLOAT): trg = tofloat(o1) op tofloat(o2); break;\
- default: _GUARD(ARITH_OP((#op)[0],trg,o1,o2)); break;\
- } \
-}
-
-#define _ARITH_NOZERO(op,trg,o1,o2,err) \
-{ \
- SQInteger tmask = type(o1)|type(o2); \
- switch(tmask) { \
- case OT_INTEGER: { SQInteger i2 = _integer(o2); if(i2 == 0) { Raise_Error(err); SQ_THROW(); } trg = _integer(o1) op i2; } break;\
- case (OT_FLOAT|OT_INTEGER): \
- case (OT_FLOAT): trg = tofloat(o1) op tofloat(o2); break;\
- default: _GUARD(ARITH_OP((#op)[0],trg,o1,o2)); break;\
- } \
-}
-
-bool SQVM::ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2)
-{
- SQInteger tmask = type(o1)|type(o2);
- switch(tmask) {
- case OT_INTEGER:{
- SQInteger res, i1 = _integer(o1), i2 = _integer(o2);
- switch(op) {
- case '+': res = i1 + i2; break;
- case '-': res = i1 - i2; break;
- case '/': if(i2 == 0) { Raise_Error(_SC("division by zero")); return false; }
- res = i1 / i2;
- break;
- case '*': res = i1 * i2; break;
- case '%': if(i2 == 0) { Raise_Error(_SC("modulo by zero")); return false; }
- res = i1 % i2;
- break;
- default: res = 0xDEADBEEF;
- }
- trg = res; }
- break;
- case (OT_FLOAT|OT_INTEGER):
- case (OT_FLOAT):{
- SQFloat res, f1 = tofloat(o1), f2 = tofloat(o2);
- switch(op) {
- case '+': res = f1 + f2; break;
- case '-': res = f1 - f2; break;
- case '/': res = f1 / f2; break;
- case '*': res = f1 * f2; break;
- case '%': res = SQFloat(fmod((double)f1,(double)f2)); break;
- default: res = 0x0f;
- }
- trg = res; }
- break;
- default:
- if(op == '+' && (tmask & _RT_STRING)){
- if(!StringCat(o1, o2, trg)) return false;
- }
- else if(!ArithMetaMethod(op,o1,o2,trg)) {
- return false;
- }
- }
- return true;
-}
-
-SQVM::SQVM(SQSharedState *ss)
-{
- _sharedstate=ss;
- _suspended = SQFalse;
- _suspended_target = -1;
- _suspended_root = SQFalse;
- _suspended_traps = -1;
- _foreignptr = NULL;
- _nnativecalls = 0;
- _nmetamethodscall = 0;
- _lasterror.Null();
- _errorhandler.Null();
- _debughook = false;
- _debughook_native = NULL;
- _debughook_closure.Null();
- _openouters = NULL;
- ci = NULL;
- INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);
-}
-
-void SQVM::Finalize()
-{
- if(_openouters) CloseOuters(&_stack._vals[0]);
- _roottable.Null();
- _lasterror.Null();
- _errorhandler.Null();
- _debughook = false;
- _debughook_native = NULL;
- _debughook_closure.Null();
- temp_reg.Null();
- _callstackdata.resize(0);
- SQInteger size=_stack.size();
- for(SQInteger i=0;i<size;i++)
- _stack[i].Null();
-}
-
-SQVM::~SQVM()
-{
- Finalize();
- REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);
-}
-
-bool SQVM::ArithMetaMethod(SQInteger op,const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &dest)
-{
- SQMetaMethod mm;
- switch(op){
- case _SC('+'): mm=MT_ADD; break;
- case _SC('-'): mm=MT_SUB; break;
- case _SC('/'): mm=MT_DIV; break;
- case _SC('*'): mm=MT_MUL; break;
- case _SC('%'): mm=MT_MODULO; break;
- default: mm = MT_ADD; assert(0); break; //shutup compiler
- }
- if(is_delegable(o1) && _delegable(o1)->_delegate) {
-
- SQObjectPtr closure;
- if(_delegable(o1)->GetMetaMethod(this, mm, closure)) {
- Push(o1);Push(o2);
- return CallMetaMethod(closure,mm,2,dest);
- }
- }
- Raise_Error(_SC("arith op %c on between '%s' and '%s'"),op,GetTypeName(o1),GetTypeName(o2));
- return false;
-}
-
-bool SQVM::NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o)
-{
-
- switch(type(o)) {
- case OT_INTEGER:
- trg = -_integer(o);
- return true;
- case OT_FLOAT:
- trg = -_float(o);
- return true;
- case OT_TABLE:
- case OT_USERDATA:
- case OT_INSTANCE:
- if(_delegable(o)->_delegate) {
- SQObjectPtr closure;
- if(_delegable(o)->GetMetaMethod(this, MT_UNM, closure)) {
- Push(o);
- if(!CallMetaMethod(closure, MT_UNM, 1, temp_reg)) return false;
- _Swap(trg,temp_reg);
- return true;
-
- }
- }
- default:break; //shutup compiler
- }
- Raise_Error(_SC("attempt to negate a %s"), GetTypeName(o));
- return false;
-}
-
-#define _RET_SUCCEED(exp) { result = (exp); return true; }
-bool SQVM::ObjCmp(const SQObjectPtr &o1,const SQObjectPtr &o2,SQInteger &result)
-{
- SQObjectType t1 = type(o1), t2 = type(o2);
- if(t1 == t2){
- if(_rawval(o1)==_rawval(o2))_RET_SUCCEED(0);
- SQObjectPtr res;
- switch(t1){
- case OT_STRING:
- _RET_SUCCEED(scstrcmp(_stringval(o1),_stringval(o2)));
- case OT_INTEGER:
- _RET_SUCCEED(_integer(o1)-_integer(o2));
- case OT_FLOAT:
- _RET_SUCCEED((_float(o1)<_float(o2))?-1:1);
- case OT_TABLE:
- case OT_USERDATA:
- case OT_INSTANCE:
- if(_delegable(o1)->_delegate) {
- SQObjectPtr closure;
- if(_delegable(o1)->GetMetaMethod(this, MT_CMP, closure)) {
- Push(o1);Push(o2);
- if(!CallMetaMethod(closure,MT_CMP,2,res)) return false;
- }
- break;
- }
- //continues through (no break needed)
- default:
- _RET_SUCCEED( _userpointer(o1) < _userpointer(o2)?-1:1 );
- }
- if(type(res)!=OT_INTEGER) { Raise_CompareError(o1,o2); return false; }
- _RET_SUCCEED(_integer(res));
-
- }
- else{
- if(sq_isnumeric(o1) && sq_isnumeric(o2)){
- if((t1==OT_INTEGER) && (t2==OT_FLOAT)) {
- if( _integer(o1)==_float(o2) ) { _RET_SUCCEED(0); }
- else if( _integer(o1)<_float(o2) ) { _RET_SUCCEED(-1); }
- _RET_SUCCEED(1);
- }
- else{
- if( _float(o1)==_integer(o2) ) { _RET_SUCCEED(0); }
- else if( _float(o1)<_integer(o2) ) { _RET_SUCCEED(-1); }
- _RET_SUCCEED(1);
- }
- }
- else if(t1==OT_NULL) {_RET_SUCCEED(-1);}
- else if(t2==OT_NULL) {_RET_SUCCEED(1);}
- else { Raise_CompareError(o1,o2); return false; }
-
- }
- assert(0);
- _RET_SUCCEED(0); //cannot happen
-}
-
-bool SQVM::CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res)
-{
- SQInteger r;
- if(ObjCmp(o1,o2,r)) {
- switch(op) {
- case CMP_G: res = (r > 0); return true;
- case CMP_GE: res = (r >= 0); return true;
- case CMP_L: res = (r < 0); return true;
- case CMP_LE: res = (r <= 0); return true;
- case CMP_3W: res = r; return true;
- }
- assert(0);
- }
- return false;
-}
-
-bool SQVM::ToString(const SQObjectPtr &o,SQObjectPtr &res)
-{
- switch(type(o)) {
- case OT_STRING:
- res = o;
- return true;
- case OT_FLOAT:
- scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)),_SC("%g"),_float(o));
- break;
- case OT_INTEGER:
- scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)),_PRINT_INT_FMT,_integer(o));
- break;
- case OT_BOOL:
- scsprintf(_sp(rsl(6)),_integer(o)?_SC("true"):_SC("false"));
- break;
- case OT_TABLE:
- case OT_USERDATA:
- case OT_INSTANCE:
- if(_delegable(o)->_delegate) {
- SQObjectPtr closure;
- if(_delegable(o)->GetMetaMethod(this, MT_TOSTRING, closure)) {
- Push(o);
- if(CallMetaMethod(closure,MT_TOSTRING,1,res)) {;
- if(type(res) == OT_STRING)
- return true;
- }
- else {
- return false;
- }
- }
- }
- default:
- scsprintf(_sp(rsl(sizeof(void*)+20)),_SC("(%s : 0x%p)"),GetTypeName(o),(void*)_rawval(o));
- }
- res = SQString::Create(_ss(this),_spval);
- return true;
-}
-
-
-bool SQVM::StringCat(const SQObjectPtr &str,const SQObjectPtr &obj,SQObjectPtr &dest)
-{
- SQObjectPtr a, b;
- if(!ToString(str, a)) return false;
- if(!ToString(obj, b)) return false;
- SQInteger l = _string(a)->_len , ol = _string(b)->_len;
- SQChar *s = _sp(rsl(l + ol + 1));
- memcpy(s, _stringval(a), rsl(l));
- memcpy(s + l, _stringval(b), rsl(ol));
- dest = SQString::Create(_ss(this), _spval, l + ol);
- return true;
-}
-
-bool SQVM::TypeOf(const SQObjectPtr &obj1,SQObjectPtr &dest)
-{
- if(is_delegable(obj1) && _delegable(obj1)->_delegate) {
- SQObjectPtr closure;
- if(_delegable(obj1)->GetMetaMethod(this, MT_TYPEOF, closure)) {
- Push(obj1);
- return CallMetaMethod(closure,MT_TYPEOF,1,dest);
- }
- }
- dest = SQString::Create(_ss(this),GetTypeName(obj1));
- return true;
-}
-
-bool SQVM::Init(SQVM *friendvm, SQInteger stacksize)
-{
- _stack.resize(stacksize);
- _alloccallsstacksize = 4;
- _callstackdata.resize(_alloccallsstacksize);
- _callsstacksize = 0;
- _callsstack = &_callstackdata[0];
- _stackbase = 0;
- _top = 0;
- if(!friendvm)
- _roottable = SQTable::Create(_ss(this), 0);
- else {
- _roottable = friendvm->_roottable;
- _errorhandler = friendvm->_errorhandler;
- _debughook = friendvm->_debughook;
- _debughook_native = friendvm->_debughook_native;
- _debughook_closure = friendvm->_debughook_closure;
- }
-
- sq_base_register(this);
- return true;
-}
-
-
-bool SQVM::StartCall(SQClosure *closure,SQInteger target,SQInteger args,SQInteger stackbase,bool tailcall)
-{
- SQFunctionProto *func = closure->_function;
-
- SQInteger paramssize = func->_nparameters;
- const SQInteger newtop = stackbase + func->_stacksize;
- SQInteger nargs = args;
- if(func->_varparams)
- {
- paramssize--;
- if (nargs < paramssize) {
- Raise_Error(_SC("wrong number of parameters"));
- return false;
- }
-
- //dumpstack(stackbase);
- SQInteger nvargs = nargs - paramssize;
- SQArray *arr = SQArray::Create(_ss(this),nvargs);
- SQInteger pbase = stackbase+paramssize;
- for(SQInteger n = 0; n < nvargs; n++) {
- arr->_values[n] = _stack._vals[pbase];
- _stack._vals[pbase].Null();
- pbase++;
-
- }
- _stack._vals[stackbase+paramssize] = arr;
- //dumpstack(stackbase);
- }
- else if (paramssize != nargs) {
- SQInteger ndef = func->_ndefaultparams;
- SQInteger diff;
- if(ndef && nargs < paramssize && (diff = paramssize - nargs) <= ndef) {
- for(SQInteger n = ndef - diff; n < ndef; n++) {
- _stack._vals[stackbase + (nargs++)] = closure->_defaultparams[n];
- }
- }
- else {
- Raise_Error(_SC("wrong number of parameters"));
- return false;
- }
- }
-
- if(closure->_env) {
- _stack._vals[stackbase] = closure->_env->_obj;
- }
-
- if(!EnterFrame(stackbase, newtop, tailcall)) return false;
-
- ci->_closure = closure;
- ci->_literals = func->_literals;
- ci->_ip = func->_instructions;
- ci->_target = (SQInt32)target;
-
- if (_debughook) {
- CallDebugHook(_SC('c'));
- }
-
- if (closure->_function->_bgenerator) {
- SQFunctionProto *f = closure->_function;
- SQGenerator *gen = SQGenerator::Create(_ss(this), closure);
- if(!gen->Yield(this,f->_stacksize))
- return false;
- SQObjectPtr temp;
- Return(1, target, temp);
- STK(target) = gen;
- }
-
-
- return true;
-}
-
-bool SQVM::Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval)
-{
- SQBool _isroot = ci->_root;
- SQInteger callerbase = _stackbase - ci->_prevstkbase;
-
- if (_debughook) {
- for(SQInteger i=0; i<ci->_ncalls; i++) {
- CallDebugHook(_SC('r'));
- }
- }
-
- SQObjectPtr *dest;
- if (_isroot) {
- dest = &(retval);
- } else if (ci->_target == -1) {
- dest = NULL;
- } else {
- dest = &_stack._vals[callerbase + ci->_target];
- }
- if (dest) {
- if(_arg0 != 0xFF) {
- *dest = _stack._vals[_stackbase+_arg1];
- }
- else {
- dest->Null();
- }
- //*dest = (_arg0 != 0xFF) ? _stack._vals[_stackbase+_arg1] : _null_;
- }
- LeaveFrame();
- return _isroot ? true : false;
-}
-
-#define _RET_ON_FAIL(exp) { if(!exp) return false; }
-
-bool SQVM::PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr)
-{
- SQObjectPtr trg;
- _RET_ON_FAIL(ARITH_OP( op , trg, a, incr));
- target = a;
- a = trg;
- return true;
-}
-
-bool SQVM::DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix,SQInteger selfidx)
-{
- SQObjectPtr tmp, tself = self, tkey = key;
- if (!Get(tself, tkey, tmp, false, selfidx)) { return false; }
- _RET_ON_FAIL(ARITH_OP( op , target, tmp, incr))
- if (!Set(tself, tkey, target,selfidx)) { return false; }
- if (postfix) target = tmp;
- return true;
-}
-
-#define arg0 (_i_._arg0)
-#define sarg0 ((SQInteger)*((signed char *)&_i_._arg0))
-#define arg1 (_i_._arg1)
-#define sarg1 (*((SQInt32 *)&_i_._arg1))
-#define arg2 (_i_._arg2)
-#define arg3 (_i_._arg3)
-#define sarg3 ((SQInteger)*((signed char *)&_i_._arg3))
-
-SQRESULT SQVM::Suspend()
-{
- if (_suspended)
- return sq_throwerror(this, _SC("cannot suspend an already suspended vm"));
- if (_nnativecalls!=2)
- return sq_throwerror(this, _SC("cannot suspend through native calls/metamethods"));
- return SQ_SUSPEND_FLAG;
-}
-
-
-#define _FINISH(howmuchtojump) {jump = howmuchtojump; return true; }
-bool SQVM::FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr
-&o3,SQObjectPtr &o4,SQInteger arg_2,int exitpos,int &jump)
-{
- SQInteger nrefidx;
- switch(type(o1)) {
- case OT_TABLE:
- if((nrefidx = _table(o1)->Next(false,o4, o2, o3)) == -1) _FINISH(exitpos);
- o4 = (SQInteger)nrefidx; _FINISH(1);
- case OT_ARRAY:
- if((nrefidx = _array(o1)->Next(o4, o2, o3)) == -1) _FINISH(exitpos);
- o4 = (SQInteger) nrefidx; _FINISH(1);
- case OT_STRING:
- if((nrefidx = _string(o1)->Next(o4, o2, o3)) == -1)_FINISH(exitpos);
- o4 = (SQInteger)nrefidx; _FINISH(1);
- case OT_CLASS:
- if((nrefidx = _class(o1)->Next(o4, o2, o3)) == -1)_FINISH(exitpos);
- o4 = (SQInteger)nrefidx; _FINISH(1);
- case OT_USERDATA:
- case OT_INSTANCE:
- if(_delegable(o1)->_delegate) {
- SQObjectPtr itr;
- SQObjectPtr closure;
- if(_delegable(o1)->GetMetaMethod(this, MT_NEXTI, closure)) {
- Push(o1);
- Push(o4);
- if(CallMetaMethod(closure, MT_NEXTI, 2, itr)) {
- o4 = o2 = itr;
- if(type(itr) == OT_NULL) _FINISH(exitpos);
- if(!Get(o1, itr, o3, false, DONT_FALL_BACK)) {
- Raise_Error(_SC("_nexti returned an invalid idx")); // cloud be changed
- return false;
- }
- _FINISH(1);
- }
- else {
- return false;
- }
- }
- Raise_Error(_SC("_nexti failed"));
- return false;
- }
- break;
- case OT_GENERATOR:
- if(_generator(o1)->_state == SQGenerator::eDead) _FINISH(exitpos);
- if(_generator(o1)->_state == SQGenerator::eSuspended) {
- SQInteger idx = 0;
- if(type(o4) == OT_INTEGER) {
- idx = _integer(o4) + 1;
- }
- o2 = idx;
- o4 = idx;
- _generator(o1)->Resume(this, o3);
- _FINISH(0);
- }
- default:
- Raise_Error(_SC("cannot iterate %s"), GetTypeName(o1));
- }
- return false; //cannot be hit(just to avoid warnings)
-}
-
-#define COND_LITERAL (arg3!=0?ci->_literals[arg1]:STK(arg1))
-
-#define SQ_THROW() { goto exception_trap; }
-
-#define _GUARD(exp) { if(!exp) { SQ_THROW();} }
-
-bool SQVM::CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func)
-{
- SQInteger nouters;
- SQClosure *closure = SQClosure::Create(_ss(this), func);
- if((nouters = func->_noutervalues)) {
- for(SQInteger i = 0; i<nouters; i++) {
- SQOuterVar &v = func->_outervalues[i];
- switch(v._type){
- case otLOCAL:
- FindOuter(closure->_outervalues[i], &STK(_integer(v._src)));
- break;
- case otOUTER:
- closure->_outervalues[i] = _closure(ci->_closure)->_outervalues[_integer(v._src)];
- break;
- }
- }
- }
- SQInteger ndefparams;
- if((ndefparams = func->_ndefaultparams)) {
- for(SQInteger i = 0; i < ndefparams; i++) {
- SQInteger spos = func->_defaultparams[i];
- closure->_defaultparams[i] = _stack._vals[_stackbase + spos];
- }
- }
- target = closure;
- return true;
-
-}
-
-
-bool SQVM::CLASS_OP(SQObjectPtr &target,SQInteger baseclass,SQInteger attributes)
-{
- SQClass *base = NULL;
- SQObjectPtr attrs;
- if(baseclass != -1) {
- if(type(_stack._vals[_stackbase+baseclass]) != OT_CLASS) { Raise_Error(_SC("trying to inherit from a %s"),GetTypeName(_stack._vals[_stackbase+baseclass])); return false; }
- base = _class(_stack._vals[_stackbase + baseclass]);
- }
- if(attributes != MAX_FUNC_STACKSIZE) {
- attrs = _stack._vals[_stackbase+attributes];
- }
- target = SQClass::Create(_ss(this),base);
- if(type(_class(target)->_metamethods[MT_INHERITED]) != OT_NULL) {
- int nparams = 2;
- SQObjectPtr ret;
- Push(target); Push(attrs);
- Call(_class(target)->_metamethods[MT_INHERITED],nparams,_top - nparams, ret, false);
- Pop(nparams);
- }
- _class(target)->_attributes = attrs;
- return true;
-}
-
-bool SQVM::IsEqual(const SQObjectPtr &o1,const SQObjectPtr &o2,bool &res)
-{
- if(type(o1) == type(o2)) {
- res = (_rawval(o1) == _rawval(o2));
- }
- else {
- if(sq_isnumeric(o1) && sq_isnumeric(o2)) {
- res = (tofloat(o1) == tofloat(o2));
- }
- else {
- res = false;
- }
- }
- return true;
-}
-
-bool SQVM::IsFalse(SQObjectPtr &o)
-{
- if(((type(o) & SQOBJECT_CANBEFALSE)
- && ( ((type(o) == OT_FLOAT) && (_float(o) == SQFloat(0.0))) ))
-#if !defined(SQUSEDOUBLE) || (defined(SQUSEDOUBLE) && defined(_SQ64))
- || (_integer(o) == 0) ) //OT_NULL|OT_INTEGER|OT_BOOL
-#else
- || (((type(o) != OT_FLOAT) && (_integer(o) == 0))) ) //OT_NULL|OT_INTEGER|OT_BOOL
-#endif
- {
- return true;
- }
- return false;
-}
-
-bool SQVM::Execute(SQObjectPtr &closure, SQInteger nargs, SQInteger stackbase,SQObjectPtr &outres, SQBool raiseerror,ExecutionType et)
-{
- if ((_nnativecalls + 1) > MAX_NATIVE_CALLS) { Raise_Error(_SC("Native stack overflow")); return false; }
- _nnativecalls++;
- AutoDec ad(&_nnativecalls);
- SQInteger traps = 0;
- CallInfo *prevci = ci;
-
- switch(et) {
- case ET_CALL: {
- temp_reg = closure;
- if(!StartCall(_closure(temp_reg), _top - nargs, nargs, stackbase, false)) {
- //call the handler if there are no calls in the stack, if not relies on the previous node
- if(ci == NULL) CallErrorHandler(_lasterror);
- return false;
- }
- if(ci == prevci) {
- outres = STK(_top-nargs);
- return true;
- }
- ci->_root = SQTrue;
- }
- break;
- case ET_RESUME_GENERATOR: _generator(closure)->Resume(this, outres); ci->_root = SQTrue; traps += ci->_etraps; break;
- case ET_RESUME_VM:
- case ET_RESUME_THROW_VM:
- traps = _suspended_traps;
- ci->_root = _suspended_root;
- _suspended = SQFalse;
- if(et == ET_RESUME_THROW_VM) { SQ_THROW(); }
- break;
- }
-
-exception_restore:
- //
- {
- for(;;)
- {
- const SQInstruction &_i_ = *ci->_ip++;
- //dumpstack(_stackbase);
- //scprintf("\n[%d] %s %d %d %d %d\n",ci->_ip-ci->_iv->_vals,g_InstrDesc[_i_.op].name,arg0,arg1,arg2,arg3);
- switch(_i_.op)
- {
- case _OP_LINE: if (_debughook) CallDebugHook(_SC('l'),arg1); continue;
- case _OP_LOAD: TARGET = ci->_literals[arg1]; continue;
- case _OP_LOADINT:
-#ifndef _SQ64
- TARGET = (SQInteger)arg1; continue;
-#else
- TARGET = (SQInteger)((SQUnsignedInteger32)arg1); continue;
-#endif
- case _OP_LOADFLOAT: TARGET = *((SQFloat *)&arg1); continue;
- case _OP_DLOAD: TARGET = ci->_literals[arg1]; STK(arg2) = ci->_literals[arg3];continue;
- case _OP_TAILCALL:{
- SQObjectPtr &t = STK(arg1);
- if (type(t) == OT_CLOSURE
- && (!_closure(t)->_function->_bgenerator)){
- SQObjectPtr clo = t;
- if(_openouters) CloseOuters(&(_stack._vals[_stackbase]));
- for (SQInteger i = 0; i < arg3; i++) STK(i) = STK(arg2 + i);
- _GUARD(StartCall(_closure(clo), ci->_target, arg3, _stackbase, true));
- continue;
- }
- }
- case _OP_CALL: {
- SQObjectPtr clo = STK(arg1);
- switch (type(clo)) {
- case OT_CLOSURE:
- _GUARD(StartCall(_closure(clo), sarg0, arg3, _stackbase+arg2, false));
- continue;
- case OT_NATIVECLOSURE: {
- bool suspend;
- _GUARD(CallNative(_nativeclosure(clo), arg3, _stackbase+arg2, clo,suspend));
- if(suspend){
- _suspended = SQTrue;
- _suspended_target = sarg0;
- _suspended_root = ci->_root;
- _suspended_traps = traps;
- outres = clo;
- return true;
- }
- if(sarg0 != -1) {
- STK(arg0) = clo;
- }
- }
- continue;
- case OT_CLASS:{
- SQObjectPtr inst;
- _GUARD(CreateClassInstance(_class(clo),inst,clo));
- if(sarg0 != -1) {
- STK(arg0) = inst;
- }
- SQInteger stkbase;
- switch(type(clo)) {
- case OT_CLOSURE:
- stkbase = _stackbase+arg2;
- _stack._vals[stkbase] = inst;
- _GUARD(StartCall(_closure(clo), -1, arg3, stkbase, false));
- break;
- case OT_NATIVECLOSURE:
- bool suspend;
- stkbase = _stackbase+arg2;
- _stack._vals[stkbase] = inst;
- _GUARD(CallNative(_nativeclosure(clo), arg3, stkbase, clo,suspend));
- break;
- default: break; //shutup GCC 4.x
- }
- }
- break;
- case OT_TABLE:
- case OT_USERDATA:
- case OT_INSTANCE:{
- SQObjectPtr closure;
- if(_delegable(clo)->_delegate && _delegable(clo)->GetMetaMethod(this,MT_CALL,closure)) {
- Push(clo);
- for (SQInteger i = 0; i < arg3; i++) Push(STK(arg2 + i));
- if(!CallMetaMethod(closure, MT_CALL, arg3+1, clo)) SQ_THROW();
- if(sarg0 != -1) {
- STK(arg0) = clo;
- }
- break;
- }
-
- //Raise_Error(_SC("attempt to call '%s'"), GetTypeName(clo));
- //SQ_THROW();
- }
- default:
- Raise_Error(_SC("attempt to call '%s'"), GetTypeName(clo));
- SQ_THROW();
- }
- }
- continue;
- case _OP_PREPCALL:
- case _OP_PREPCALLK: {
- SQObjectPtr &key = _i_.op == _OP_PREPCALLK?(ci->_literals)[arg1]:STK(arg1);
- SQObjectPtr &o = STK(arg2);
- if (!Get(o, key, temp_reg,false,arg2)) {
- SQ_THROW();
- }
- STK(arg3) = o;
- _Swap(TARGET,temp_reg);//TARGET = temp_reg;
- }
- continue;
- case _OP_GETK:
- if (!Get(STK(arg2), ci->_literals[arg1], temp_reg, false,arg2)) { SQ_THROW();}
- _Swap(TARGET,temp_reg);//TARGET = temp_reg;
- continue;
- case _OP_MOVE: TARGET = STK(arg1); continue;
- case _OP_NEWSLOT:
- _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3),false));
- if(arg0 != 0xFF) TARGET = STK(arg3);
- continue;
- case _OP_DELETE: _GUARD(DeleteSlot(STK(arg1), STK(arg2), TARGET)); continue;
- case _OP_SET:
- if (!Set(STK(arg1), STK(arg2), STK(arg3),arg1)) { SQ_THROW(); }
- if (arg0 != 0xFF) TARGET = STK(arg3);
- continue;
- case _OP_GET:
- if (!Get(STK(arg1), STK(arg2), temp_reg, false,arg1)) { SQ_THROW(); }
- _Swap(TARGET,temp_reg);//TARGET = temp_reg;
- continue;
- case _OP_EQ:{
- bool res;
- if(!IsEqual(STK(arg2),COND_LITERAL,res)) { SQ_THROW(); }
- TARGET = res?true:false;
- }continue;
- case _OP_NE:{
- bool res;
- if(!IsEqual(STK(arg2),COND_LITERAL,res)) { SQ_THROW(); }
- TARGET = (!res)?true:false;
- } continue;
- case _OP_ADD: _ARITH_(+,TARGET,STK(arg2),STK(arg1)); continue;
- case _OP_SUB: _ARITH_(-,TARGET,STK(arg2),STK(arg1)); continue;
- case _OP_MUL: _ARITH_(*,TARGET,STK(arg2),STK(arg1)); continue;
- case _OP_DIV: _ARITH_NOZERO(/,TARGET,STK(arg2),STK(arg1),_SC("division by zero")); continue;
- case _OP_MOD: ARITH_OP('%',TARGET,STK(arg2),STK(arg1)); continue;
- case _OP_BITW: _GUARD(BW_OP( arg3,TARGET,STK(arg2),STK(arg1))); continue;
- case _OP_RETURN:
- if((ci)->_generator) {
- (ci)->_generator->Kill();
- }
- if(Return(arg0, arg1, temp_reg)){
- assert(traps==0);
- //outres = temp_reg;
- _Swap(outres,temp_reg);
- return true;
- }
- continue;
- case _OP_LOADNULLS:{ for(SQInt32 n=0; n < arg1; n++) STK(arg0+n).Null(); }continue;
- case _OP_LOADROOT: TARGET = _roottable; continue;
- case _OP_LOADBOOL: TARGET = arg1?true:false; continue;
- case _OP_DMOVE: STK(arg0) = STK(arg1); STK(arg2) = STK(arg3); continue;
- case _OP_JMP: ci->_ip += (sarg1); continue;
- //case _OP_JNZ: if(!IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue;
- case _OP_JCMP:
- _GUARD(CMP_OP((CmpOP)arg3,STK(arg2),STK(arg0),temp_reg));
- if(IsFalse(temp_reg)) ci->_ip+=(sarg1);
- continue;
- case _OP_JZ: if(IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue;
- case _OP_GETOUTER: {
- SQClosure *cur_cls = _closure(ci->_closure);
- SQOuter *otr = _outer(cur_cls->_outervalues[arg1]);
- TARGET = *(otr->_valptr);
- }
- continue;
- case _OP_SETOUTER: {
- SQClosure *cur_cls = _closure(ci->_closure);
- SQOuter *otr = _outer(cur_cls->_outervalues[arg1]);
- *(otr->_valptr) = STK(arg2);
- if(arg0 != 0xFF) {
- TARGET = STK(arg2);
- }
- }
- continue;
- case _OP_NEWOBJ:
- switch(arg3) {
- case NOT_TABLE: TARGET = SQTable::Create(_ss(this), arg1); continue;
- case NOT_ARRAY: TARGET = SQArray::Create(_ss(this), 0); _array(TARGET)->Reserve(arg1); continue;
- case NOT_CLASS: _GUARD(CLASS_OP(TARGET,arg1,arg2)); continue;
- default: assert(0); continue;
- }
- case _OP_APPENDARRAY:
- {
- SQObject val;
- val._unVal.raw = 0;
- switch(arg2) {
- case AAT_STACK:
- val = STK(arg1); break;
- case AAT_LITERAL:
- val = ci->_literals[arg1]; break;
- case AAT_INT:
- val._type = OT_INTEGER;
-#ifndef _SQ64
- val._unVal.nInteger = (SQInteger)arg1;
-#else
- val._unVal.nInteger = (SQInteger)((SQUnsignedInteger32)arg1);
-#endif
- break;
- case AAT_FLOAT:
- val._type = OT_FLOAT;
- val._unVal.fFloat = *((SQFloat *)&arg1);
- break;
- case AAT_BOOL:
- val._type = OT_BOOL;
- val._unVal.nInteger = arg1;
- break;
- default: assert(0); break;
-
- }
- _array(STK(arg0))->Append(val); continue;
- }
- case _OP_COMPARITH: {
- SQInteger selfidx = (((SQUnsignedInteger)arg1&0xFFFF0000)>>16);
- _GUARD(DerefInc(arg3, TARGET, STK(selfidx), STK(arg2), STK(arg1&0x0000FFFF), false, selfidx));
- }
- continue;
- case _OP_INC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, false, arg1));} continue;
- case _OP_INCL: {
- SQObjectPtr &a = STK(arg1);
- if(type(a) == OT_INTEGER) {
- a._unVal.nInteger = _integer(a) + sarg3;
- }
- else {
- SQObjectPtr o(sarg3); //_GUARD(LOCAL_INC('+',TARGET, STK(arg1), o));
- _ARITH_(+,a,a,o);
- }
- } continue;
- case _OP_PINC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, true, arg1));} continue;
- case _OP_PINCL: {
- SQObjectPtr &a = STK(arg1);
- if(type(a) == OT_INTEGER) {
- TARGET = a;
- a._unVal.nInteger = _integer(a) + sarg3;
- }
- else {
- SQObjectPtr o(sarg3); _GUARD(PLOCAL_INC('+',TARGET, STK(arg1), o));
- }
-
- } continue;
- case _OP_CMP: _GUARD(CMP_OP((CmpOP)arg3,STK(arg2),STK(arg1),TARGET)) continue;
- case _OP_EXISTS: TARGET = Get(STK(arg1), STK(arg2), temp_reg, true,DONT_FALL_BACK)?true:false;continue;
- case _OP_INSTANCEOF:
- if(type(STK(arg1)) != OT_CLASS)
- {Raise_Error(_SC("cannot apply instanceof between a %s and a %s"),GetTypeName(STK(arg1)),GetTypeName(STK(arg2))); SQ_THROW();}
- TARGET = (type(STK(arg2)) == OT_INSTANCE) ? (_instance(STK(arg2))->InstanceOf(_class(STK(arg1)))?true:false) : false;
- continue;
- case _OP_AND:
- if(IsFalse(STK(arg2))) {
- TARGET = STK(arg2);
- ci->_ip += (sarg1);
- }
- continue;
- case _OP_OR:
- if(!IsFalse(STK(arg2))) {
- TARGET = STK(arg2);
- ci->_ip += (sarg1);
- }
- continue;
- case _OP_NEG: _GUARD(NEG_OP(TARGET,STK(arg1))); continue;
- case _OP_NOT: TARGET = IsFalse(STK(arg1)); continue;
- case _OP_BWNOT:
- if(type(STK(arg1)) == OT_INTEGER) {
- SQInteger t = _integer(STK(arg1));
- TARGET = SQInteger(~t);
- continue;
- }
- Raise_Error(_SC("attempt to perform a bitwise op on a %s"), GetTypeName(STK(arg1)));
- SQ_THROW();
- case _OP_CLOSURE: {
- SQClosure *c = ci->_closure._unVal.pClosure;
- SQFunctionProto *fp = c->_function;
- if(!CLOSURE_OP(TARGET,fp->_functions[arg1]._unVal.pFunctionProto)) { SQ_THROW(); }
- continue;
- }
- case _OP_YIELD:{
- if(ci->_generator) {
- if(sarg1 != MAX_FUNC_STACKSIZE) temp_reg = STK(arg1);
- _GUARD(ci->_generator->Yield(this,arg2));
- traps -= ci->_etraps;
- if(sarg1 != MAX_FUNC_STACKSIZE) _Swap(STK(arg1),temp_reg);//STK(arg1) = temp_reg;
- }
- else { Raise_Error(_SC("trying to yield a '%s',only genenerator can be yielded"), GetTypeName(ci->_generator)); SQ_THROW();}
- if(Return(arg0, arg1, temp_reg)){
- assert(traps == 0);
- outres = temp_reg;
- return true;
- }
-
- }
- continue;
- case _OP_RESUME:
- if(type(STK(arg1)) != OT_GENERATOR){ Raise_Error(_SC("trying to resume a '%s',only genenerator can be resumed"), GetTypeName(STK(arg1))); SQ_THROW();}
- _GUARD(_generator(STK(arg1))->Resume(this, TARGET));
- traps += ci->_etraps;
- continue;
- case _OP_FOREACH:{ int tojump;
- _GUARD(FOREACH_OP(STK(arg0),STK(arg2),STK(arg2+1),STK(arg2+2),arg2,sarg1,tojump));
- ci->_ip += tojump; }
- continue;
- case _OP_POSTFOREACH:
- assert(type(STK(arg0)) == OT_GENERATOR);
- if(_generator(STK(arg0))->_state == SQGenerator::eDead)
- ci->_ip += (sarg1 - 1);
- continue;
- case _OP_CLONE: _GUARD(Clone(STK(arg1), TARGET)); continue;
- case _OP_TYPEOF: _GUARD(TypeOf(STK(arg1), TARGET)) continue;
- case _OP_PUSHTRAP:{
- SQInstruction *_iv = _closure(ci->_closure)->_function->_instructions;
- _etraps.push_back(SQExceptionTrap(_top,_stackbase, &_iv[(ci->_ip-_iv)+arg1], arg0)); traps++;
- ci->_etraps++;
- }
- continue;
- case _OP_POPTRAP: {
- for(SQInteger i = 0; i < arg0; i++) {
- _etraps.pop_back(); traps--;
- ci->_etraps--;
- }
- }
- continue;
- case _OP_THROW: Raise_Error(TARGET); SQ_THROW(); continue;
- case _OP_NEWSLOTA: {
- bool bstatic = (arg0&NEW_SLOT_STATIC_FLAG)?true:false;
- if(type(STK(arg1)) == OT_CLASS) {
- if(type(_class(STK(arg1))->_metamethods[MT_NEWMEMBER]) != OT_NULL ) {
- Push(STK(arg1)); Push(STK(arg2)); Push(STK(arg3));
- Push((arg0&NEW_SLOT_ATTRIBUTES_FLAG) ? STK(arg2-1) : SQObjectPtr());
- Push(bstatic);
- int nparams = 5;
- if(Call(_class(STK(arg1))->_metamethods[MT_NEWMEMBER], nparams, _top - nparams, temp_reg,SQFalse)) {
- Pop(nparams);
- continue;
- }
- else {
- SQ_THROW();
- }
- }
- }
- _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3),bstatic));
- if((arg0&NEW_SLOT_ATTRIBUTES_FLAG)) {
- _class(STK(arg1))->SetAttributes(STK(arg2),STK(arg2-1));
- }
- }
- continue;
- case _OP_GETBASE:{
- SQClosure *clo = _closure(ci->_closure);
- if(clo->_base) {
- TARGET = clo->_base;
- }
- else {
- TARGET.Null();
- }
- continue;
- }
- case _OP_CLOSE:
- if(_openouters) CloseOuters(&(STK(arg1)));
- continue;
- }
-
- }
- }
-exception_trap:
- {
- SQObjectPtr currerror = _lasterror;
-// dumpstack(_stackbase);
-// SQInteger n = 0;
- SQInteger last_top = _top;
-
- if(_ss(this)->_notifyallexceptions || (!traps && raiseerror)) CallErrorHandler(currerror);
-
- while( ci ) {
- if(ci->_etraps > 0) {
- SQExceptionTrap &et = _etraps.top();
- ci->_ip = et._ip;
- _top = et._stacksize;
- _stackbase = et._stackbase;
- _stack._vals[_stackbase + et._extarget] = currerror;
- _etraps.pop_back(); traps--; ci->_etraps--;
- while(last_top >= _top) _stack._vals[last_top--].Null();
- goto exception_restore;
- }
- else if (_debughook) {
- //notify debugger of a "return"
- //even if it really an exception unwinding the stack
- for(SQInteger i = 0; i < ci->_ncalls; i++) {
- CallDebugHook(_SC('r'));
- }
- }
- if(ci->_generator) ci->_generator->Kill();
- bool mustbreak = ci && ci->_root;
- LeaveFrame();
- if(mustbreak) break;
- }
-
- _lasterror = currerror;
- return false;
- }
- assert(0);
-}
-
-bool SQVM::CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor)
-{
- inst = theclass->CreateInstance();
- if(!theclass->GetConstructor(constructor)) {
- constructor.Null();
- }
- return true;
-}
-
-void SQVM::CallErrorHandler(SQObjectPtr &error)
-{
- if(type(_errorhandler) != OT_NULL) {
- SQObjectPtr out;
- Push(_roottable); Push(error);
- Call(_errorhandler, 2, _top-2, out,SQFalse);
- Pop(2);
- }
-}
-
-
-void SQVM::CallDebugHook(SQInteger type,SQInteger forcedline)
-{
- _debughook = false;
- SQFunctionProto *func=_closure(ci->_closure)->_function;
- if(_debughook_native) {
- const SQChar *src = type(func->_sourcename) == OT_STRING?_stringval(func->_sourcename):NULL;
- const SQChar *fname = type(func->_name) == OT_STRING?_stringval(func->_name):NULL;
- SQInteger line = forcedline?forcedline:func->GetLine(ci->_ip);
- _debughook_native(this,type,src,line,fname);
- }
- else {
- SQObjectPtr temp_reg;
- SQInteger nparams=5;
- Push(_roottable); Push(type); Push(func->_sourcename); Push(forcedline?forcedline:func->GetLine(ci->_ip)); Push(func->_name);
- Call(_debughook_closure,nparams,_top-nparams,temp_reg,SQFalse);
- Pop(nparams);
- }
- _debughook = true;
-}
-
-bool SQVM::CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newbase, SQObjectPtr &retval, bool &suspend)
-{
- SQInteger nparamscheck = nclosure->_nparamscheck;
- SQInteger newtop = newbase + nargs + nclosure->_noutervalues;
-
- if (_nnativecalls + 1 > MAX_NATIVE_CALLS) {
- Raise_Error(_SC("Native stack overflow"));
- return false;
- }
-
- if(nparamscheck && (((nparamscheck > 0) && (nparamscheck != nargs)) ||
- ((nparamscheck < 0) && (nargs < (-nparamscheck)))))
- {
- Raise_Error(_SC("wrong number of parameters"));
- return false;
- }
-
- SQInteger tcs;
- SQIntVec &tc = nclosure->_typecheck;
- if((tcs = tc.size())) {
- for(SQInteger i = 0; i < nargs && i < tcs; i++) {
- if((tc._vals[i] != -1) && !(type(_stack._vals[newbase+i]) & tc._vals[i])) {
- Raise_ParamTypeError(i,tc._vals[i],type(_stack._vals[newbase+i]));
- return false;
- }
- }
- }
-
- if(!EnterFrame(newbase, newtop, false)) return false;
- ci->_closure = nclosure;
-
- SQInteger outers = nclosure->_noutervalues;
- for (SQInteger i = 0; i < outers; i++) {
- _stack._vals[newbase+nargs+i] = nclosure->_outervalues[i];
- }
- if(nclosure->_env) {
- _stack._vals[newbase] = nclosure->_env->_obj;
- }
-
- _nnativecalls++;
- SQInteger ret = (nclosure->_function)(this);
- _nnativecalls--;
-
- suspend = false;
- if (ret == SQ_SUSPEND_FLAG) {
- suspend = true;
- }
- else if (ret < 0) {
- LeaveFrame();
- Raise_Error(_lasterror);
- return false;
- }
- if(ret) {
- retval = _stack._vals[_top-1];
- }
- else {
- retval.Null();
- }
- //retval = ret ? _stack._vals[_top-1] : _null_;
- LeaveFrame();
- return true;
-}
-
-#define FALLBACK_OK 0
-#define FALLBACK_NO_MATCH 1
-#define FALLBACK_ERROR 2
-
-bool SQVM::Get(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw, SQInteger selfidx)
-{
- switch(type(self)){
- case OT_TABLE:
- if(_table(self)->Get(key,dest))return true;
- break;
- case OT_ARRAY:
- if(sq_isnumeric(key)) { if(_array(self)->Get(tointeger(key),dest)) { return true; } Raise_IdxError(key); return false; }
- break;
- case OT_INSTANCE:
- if(_instance(self)->Get(key,dest)) return true;
- break;
- case OT_CLASS:
- if(_class(self)->Get(key,dest)) return true;
- break;
- case OT_STRING:
- if(sq_isnumeric(key)){
- SQInteger n = tointeger(key);
- if(abs((int)n) < _string(self)->_len) {
- if(n < 0) n = _string(self)->_len - n;
- dest = SQInteger(_stringval(self)[n]);
- return true;
- }
- Raise_IdxError(key);
- return false;
- }
- break;
- default:break; //shut up compiler
- }
- if(!raw) {
- switch(FallBackGet(self,key,dest)) {
- case FALLBACK_OK: return true; //okie
- case FALLBACK_NO_MATCH: break; //keep falling back
- case FALLBACK_ERROR: return false; // the metamethod failed
- }
- if(InvokeDefaultDelegate(self,key,dest)) {
- return true;
- }
- }
-//#ifdef ROOT_FALLBACK
- if(selfidx == 0) {
- if(_table(_roottable)->Get(key,dest)) return true;
- }
-//#endif
- Raise_IdxError(key);
- return false;
-}
-
-bool SQVM::InvokeDefaultDelegate(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest)
-{
- SQTable *ddel = NULL;
- switch(type(self)) {
- case OT_CLASS: ddel = _class_ddel; break;
- case OT_TABLE: ddel = _table_ddel; break;
- case OT_ARRAY: ddel = _array_ddel; break;
- case OT_STRING: ddel = _string_ddel; break;
- case OT_INSTANCE: ddel = _instance_ddel; break;
- case OT_INTEGER:case OT_FLOAT:case OT_BOOL: ddel = _number_ddel; break;
- case OT_GENERATOR: ddel = _generator_ddel; break;
- case OT_CLOSURE: case OT_NATIVECLOSURE: ddel = _closure_ddel; break;
- case OT_THREAD: ddel = _thread_ddel; break;
- case OT_WEAKREF: ddel = _weakref_ddel; break;
- default: return false;
- }
- return ddel->Get(key,dest);
-}
-
-
-SQInteger SQVM::FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest)
-{
- switch(type(self)){
- case OT_TABLE:
- case OT_USERDATA:
- //delegation
- if(_delegable(self)->_delegate) {
- if(Get(SQObjectPtr(_delegable(self)->_delegate),key,dest,false,DONT_FALL_BACK)) return FALLBACK_OK;
- }
- else {
- return FALLBACK_NO_MATCH;
- }
- //go through
- case OT_INSTANCE: {
- SQObjectPtr closure;
- if(_delegable(self)->GetMetaMethod(this, MT_GET, closure)) {
- Push(self);Push(key);
- _nmetamethodscall++;
- AutoDec ad(&_nmetamethodscall);
- if(Call(closure, 2, _top - 2, dest, SQFalse)) {
- Pop(2);
- return FALLBACK_OK;
- }
- else {
- if(type(_lasterror) != OT_NULL) { //NULL means "clean failure" (not found)
- //error
- Pop(2);
- return FALLBACK_ERROR;
- }
- }
- }
- }
- break;
- default: break;//shutup GCC 4.x
- }
- // no metamethod or no fallback type
- return FALLBACK_NO_MATCH;
-}
-
-bool SQVM::Set(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,SQInteger selfidx)
-{
- switch(type(self)){
- case OT_TABLE:
- if(_table(self)->Set(key,val)) return true;
- break;
- case OT_INSTANCE:
- if(_instance(self)->Set(key,val)) return true;
- break;
- case OT_ARRAY:
- if(!sq_isnumeric(key)) { Raise_Error(_SC("indexing %s with %s"),GetTypeName(self),GetTypeName(key)); return false; }
- if(!_array(self)->Set(tointeger(key),val)) {
- Raise_IdxError(key);
- return false;
- }
- return true;
- default:
- Raise_Error(_SC("trying to set '%s'"),GetTypeName(self));
- return false;
- }
-
- switch(FallBackSet(self,key,val)) {
- case FALLBACK_OK: return true; //okie
- case FALLBACK_NO_MATCH: break; //keep falling back
- case FALLBACK_ERROR: return false; // the metamethod failed
- }
- if(selfidx == 0) {
- if(_table(_roottable)->Set(key,val))
- return true;
- }
- Raise_IdxError(key);
- return false;
-}
-
-SQInteger SQVM::FallBackSet(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val)
-{
- switch(type(self)) {
- case OT_TABLE:
- if(_table(self)->_delegate) {
- if(Set(_table(self)->_delegate,key,val,DONT_FALL_BACK)) return FALLBACK_OK;
- }
- //keps on going
- case OT_INSTANCE:
- case OT_USERDATA:{
- SQObjectPtr closure;
- SQObjectPtr t;
- if(_delegable(self)->GetMetaMethod(this, MT_SET, closure)) {
- Push(self);Push(key);Push(val);
- _nmetamethodscall++;
- AutoDec ad(&_nmetamethodscall);
- if(Call(closure, 3, _top - 3, t, SQFalse)) {
- Pop(3);
- return FALLBACK_OK;
- }
- else {
- if(type(_lasterror) != OT_NULL) { //NULL means "clean failure" (not found)
- //error
- Pop(3);
- return FALLBACK_ERROR;
- }
- }
- }
- }
- break;
- default: break;//shutup GCC 4.x
- }
- // no metamethod or no fallback type
- return FALLBACK_NO_MATCH;
-}
-
-bool SQVM::Clone(const SQObjectPtr &self,SQObjectPtr &target)
-{
- SQObjectPtr temp_reg;
- SQObjectPtr newobj;
- switch(type(self)){
- case OT_TABLE:
- newobj = _table(self)->Clone();
- goto cloned_mt;
- case OT_INSTANCE: {
- newobj = _instance(self)->Clone(_ss(this));
-cloned_mt:
- SQObjectPtr closure;
- if(_delegable(newobj)->_delegate && _delegable(newobj)->GetMetaMethod(this,MT_CLONED,closure)) {
- Push(newobj);
- Push(self);
- if(!CallMetaMethod(closure,MT_CLONED,2,temp_reg))
- return false;
- }
- }
- target = newobj;
- return true;
- case OT_ARRAY:
- target = _array(self)->Clone();
- return true;
- default:
- Raise_Error(_SC("cloning a %s"), GetTypeName(self));
- return false;
- }
-}
-
-bool SQVM::NewSlot(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic)
-{
- if(type(key) == OT_NULL) { Raise_Error(_SC("null cannot be used as index")); return false; }
- switch(type(self)) {
- case OT_TABLE: {
- bool rawcall = true;
- if(_table(self)->_delegate) {
- SQObjectPtr res;
- if(!_table(self)->Get(key,res)) {
- SQObjectPtr closure;
- if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_NEWSLOT,closure)) {
- Push(self);Push(key);Push(val);
- if(!CallMetaMethod(closure,MT_NEWSLOT,3,res)) {
- return false;
- }
- rawcall = false;
- }
- else {
- rawcall = true;
- }
- }
- }
- if(rawcall) _table(self)->NewSlot(key,val); //cannot fail
-
- break;}
- case OT_INSTANCE: {
- SQObjectPtr res;
- SQObjectPtr closure;
- if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_NEWSLOT,closure)) {
- Push(self);Push(key);Push(val);
- if(!CallMetaMethod(closure,MT_NEWSLOT,3,res)) {
- return false;
- }
- break;
- }
- Raise_Error(_SC("class instances do not support the new slot operator"));
- return false;
- break;}
- case OT_CLASS:
- if(!_class(self)->NewSlot(_ss(this),key,val,bstatic)) {
- if(_class(self)->_locked) {
- Raise_Error(_SC("trying to modify a class that has already been instantiated"));
- return false;
- }
- else {
- SQObjectPtr oval = PrintObjVal(key);
- Raise_Error(_SC("the property '%s' already exists"),_stringval(oval));
- return false;
- }
- }
- break;
- default:
- Raise_Error(_SC("indexing %s with %s"),GetTypeName(self),GetTypeName(key));
- return false;
- break;
- }
- return true;
-}
-
-
-
-bool SQVM::DeleteSlot(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &res)
-{
- switch(type(self)) {
- case OT_TABLE:
- case OT_INSTANCE:
- case OT_USERDATA: {
- SQObjectPtr t;
- //bool handled = false;
- SQObjectPtr closure;
- if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_DELSLOT,closure)) {
- Push(self);Push(key);
- return CallMetaMethod(closure,MT_DELSLOT,2,res);
- }
- else {
- if(type(self) == OT_TABLE) {
- if(_table(self)->Get(key,t)) {
- _table(self)->Remove(key);
- }
- else {
- Raise_IdxError((SQObject &)key);
- return false;
- }
- }
- else {
- Raise_Error(_SC("cannot delete a slot from %s"),GetTypeName(self));
- return false;
- }
- }
- res = t;
- }
- break;
- default:
- Raise_Error(_SC("attempt to delete a slot from a %s"),GetTypeName(self));
- return false;
- }
- return true;
-}
-
-bool SQVM::Call(SQObjectPtr &closure,SQInteger nparams,SQInteger stackbase,SQObjectPtr &outres,SQBool raiseerror)
-{
-#ifdef _DEBUG
-SQInteger prevstackbase = _stackbase;
-#endif
- switch(type(closure)) {
- case OT_CLOSURE:
- return Execute(closure, nparams, stackbase, outres, raiseerror);
- break;
- case OT_NATIVECLOSURE:{
- bool suspend;
- return CallNative(_nativeclosure(closure), nparams, stackbase, outres,suspend);
-
- }
- break;
- case OT_CLASS: {
- SQObjectPtr constr;
- SQObjectPtr temp;
- CreateClassInstance(_class(closure),outres,constr);
- if(type(constr) != OT_NULL) {
- _stack[stackbase] = outres;
- return Call(constr,nparams,stackbase,temp,raiseerror);
- }
- return true;
- }
- break;
- default:
- return false;
- }
-#ifdef _DEBUG
- if(!_suspended) {
- assert(_stackbase == prevstackbase);
- }
-#endif
- return true;
-}
-
-bool SQVM::CallMetaMethod(SQObjectPtr &closure,SQMetaMethod mm,SQInteger nparams,SQObjectPtr &outres)
-{
- //SQObjectPtr closure;
-
- _nmetamethodscall++;
- if(Call(closure, nparams, _top - nparams, outres, SQFalse)) {
- _nmetamethodscall--;
- Pop(nparams);
- return true;
- }
- _nmetamethodscall--;
- //}
- Pop(nparams);
- return false;
-}
-
-void SQVM::FindOuter(SQObjectPtr &target, SQObjectPtr *stackindex)
-{
- SQOuter **pp = &_openouters;
- SQOuter *p;
- SQOuter *otr;
-
- while ((p = *pp) != NULL && p->_valptr >= stackindex) {
- if (p->_valptr == stackindex) {
- target = SQObjectPtr(p);
- return;
- }
- pp = &p->_next;
- }
- otr = SQOuter::Create(_ss(this), stackindex);
- otr->_next = *pp;
- otr->_idx = (stackindex - _stack._vals);
- __ObjAddRef(otr);
- *pp = otr;
- target = SQObjectPtr(otr);
-}
-
-bool SQVM::EnterFrame(SQInteger newbase, SQInteger newtop, bool tailcall)
-{
- if( !tailcall ) {
- if( _callsstacksize == _alloccallsstacksize ) {
- GrowCallStack();
- }
- ci = &_callsstack[_callsstacksize++];
- ci->_prevstkbase = (SQInt32)(newbase - _stackbase);
- ci->_prevtop = (SQInt32)(_top - _stackbase);
- ci->_etraps = 0;
- ci->_ncalls = 1;
- ci->_generator = NULL;
- ci->_root = SQFalse;
- }
- else {
- ci->_ncalls++;
- }
-
- _stackbase = newbase;
- _top = newtop;
- if(newtop + MIN_STACK_OVERHEAD > (SQInteger)_stack.size()) {
- if(_nmetamethodscall) {
- Raise_Error(_SC("stack overflow, cannot resize stack while in a metamethod"));
- return false;
- }
- _stack.resize(_stack.size() + (MIN_STACK_OVERHEAD << 2));
- RelocateOuters();
- }
- return true;
-}
-
-void SQVM::LeaveFrame() {
- SQInteger last_top = _top;
- SQInteger last_stackbase = _stackbase;
- SQInteger css = --_callsstacksize;
-
- /* First clean out the call stack frame */
- ci->_closure.Null();
- _stackbase -= ci->_prevstkbase;
- _top = _stackbase + ci->_prevtop;
- ci = (css) ? &_callsstack[css-1] : NULL;
-
- if(_openouters) CloseOuters(&(_stack._vals[last_stackbase]));
- while (last_top >= _top) {
- _stack._vals[last_top--].Null();
- }
-}
-
-void SQVM::RelocateOuters()
-{
- SQOuter *p = _openouters;
- while (p) {
- p->_valptr = _stack._vals + p->_idx;
- p = p->_next;
- }
-}
-
-void SQVM::CloseOuters(SQObjectPtr *stackindex) {
- SQOuter *p;
- while ((p = _openouters) != NULL && p->_valptr >= stackindex) {
- p->_value = *(p->_valptr);
- p->_valptr = &p->_value;
- _openouters = p->_next;
- __ObjRelease(p);
- }
-}
-
-void SQVM::Remove(SQInteger n) {
- n = (n >= 0)?n + _stackbase - 1:_top + n;
- for(SQInteger i = n; i < _top; i++){
- _stack[i] = _stack[i+1];
- }
- _stack[_top].Null();
- _top--;
-}
-
-void SQVM::Pop() {
- _stack[--_top].Null();
-}
-
-void SQVM::Pop(SQInteger n) {
- for(SQInteger i = 0; i < n; i++){
- _stack[--_top].Null();
- }
-}
-
-void SQVM::PushNull() { _stack[_top++].Null(); }
-void SQVM::Push(const SQObjectPtr &o) { _stack[_top++] = o; }
-SQObjectPtr &SQVM::Top() { return _stack[_top-1]; }
-SQObjectPtr &SQVM::PopGet() { return _stack[--_top]; }
-SQObjectPtr &SQVM::GetUp(SQInteger n) { return _stack[_top+n]; }
-SQObjectPtr &SQVM::GetAt(SQInteger n) { return _stack[n]; }
-
-#ifdef _DEBUG_DUMP
-void SQVM::dumpstack(SQInteger stackbase,bool dumpall)
-{
- SQInteger size=dumpall?_stack.size():_top;
- SQInteger n=0;
- scprintf(_SC("\n>>>>stack dump<<<<\n"));
- CallInfo &ci=_callsstack[_callsstacksize-1];
- scprintf(_SC("IP: %p\n"),ci._ip);
- scprintf(_SC("prev stack base: %d\n"),ci._prevstkbase);
- scprintf(_SC("prev top: %d\n"),ci._prevtop);
- for(SQInteger i=0;i<size;i++){
- SQObjectPtr &obj=_stack[i];
- if(stackbase==i)scprintf(_SC(">"));else scprintf(_SC(" "));
- scprintf(_SC("[%d]:"),n);
- switch(type(obj)){
- case OT_FLOAT: scprintf(_SC("FLOAT %.3f"),_float(obj));break;
- case OT_INTEGER: scprintf(_SC("INTEGER %d"),_integer(obj));break;
- case OT_BOOL: scprintf(_SC("BOOL %s"),_integer(obj)?"true":"false");break;
- case OT_STRING: scprintf(_SC("STRING %s"),_stringval(obj));break;
- case OT_NULL: scprintf(_SC("NULL")); break;
- case OT_TABLE: scprintf(_SC("TABLE %p[%p]"),_table(obj),_table(obj)->_delegate);break;
- case OT_ARRAY: scprintf(_SC("ARRAY %p"),_array(obj));break;
- case OT_CLOSURE: scprintf(_SC("CLOSURE [%p]"),_closure(obj));break;
- case OT_NATIVECLOSURE: scprintf(_SC("NATIVECLOSURE"));break;
- case OT_USERDATA: scprintf(_SC("USERDATA %p[%p]"),_userdataval(obj),_userdata(obj)->_delegate);break;
- case OT_GENERATOR: scprintf(_SC("GENERATOR %p"),_generator(obj));break;
- case OT_THREAD: scprintf(_SC("THREAD [%p]"),_thread(obj));break;
- case OT_USERPOINTER: scprintf(_SC("USERPOINTER %p"),_userpointer(obj));break;
- case OT_CLASS: scprintf(_SC("CLASS %p"),_class(obj));break;
- case OT_INSTANCE: scprintf(_SC("INSTANCE %p"),_instance(obj));break;
- case OT_WEAKREF: scprintf(_SC("WEAKERF %p"),_weakref(obj));break;
- default:
- assert(0);
- break;
- };
- scprintf(_SC("\n"));
- ++n;
- }
-}
-
-
-
-#endif
+/* + see copyright notice in squirrel.h +*/ +#include "sqpcheader.h" +#include <math.h> +#include <stdlib.h> +#include "sqopcodes.h" +#include "sqvm.h" +#include "sqfuncproto.h" +#include "sqclosure.h" +#include "sqstring.h" +#include "sqtable.h" +#include "squserdata.h" +#include "sqarray.h" +#include "sqclass.h" + +#define TOP() (_stack._vals[_top-1]) + +bool SQVM::BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2) +{ + SQInteger res; + if((type(o1)|type(o2)) == OT_INTEGER) + { + SQInteger i1 = _integer(o1), i2 = _integer(o2); + switch(op) { + case BW_AND: res = i1 & i2; break; + case BW_OR: res = i1 | i2; break; + case BW_XOR: res = i1 ^ i2; break; + case BW_SHIFTL: res = i1 << i2; break; + case BW_SHIFTR: res = i1 >> i2; break; + case BW_USHIFTR:res = (SQInteger)(*((SQUnsignedInteger*)&i1) >> i2); break; + default: { Raise_Error(_SC("internal vm error bitwise op failed")); return false; } + } + } + else { Raise_Error(_SC("bitwise op between '%s' and '%s'"),GetTypeName(o1),GetTypeName(o2)); return false;} + trg = res; + return true; +} + +#define _ARITH_(op,trg,o1,o2) \ +{ \ + SQInteger tmask = type(o1)|type(o2); \ + switch(tmask) { \ + case OT_INTEGER: trg = _integer(o1) op _integer(o2);break; \ + case (OT_FLOAT|OT_INTEGER): \ + case (OT_FLOAT): trg = tofloat(o1) op tofloat(o2); break;\ + default: _GUARD(ARITH_OP((#op)[0],trg,o1,o2)); break;\ + } \ +} + +#define _ARITH_NOZERO(op,trg,o1,o2,err) \ +{ \ + SQInteger tmask = type(o1)|type(o2); \ + switch(tmask) { \ + case OT_INTEGER: { SQInteger i2 = _integer(o2); if(i2 == 0) { Raise_Error(err); SQ_THROW(); } trg = _integer(o1) op i2; } break;\ + case (OT_FLOAT|OT_INTEGER): \ + case (OT_FLOAT): trg = tofloat(o1) op tofloat(o2); break;\ + default: _GUARD(ARITH_OP((#op)[0],trg,o1,o2)); break;\ + } \ +} + +bool SQVM::ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2) +{ + SQInteger tmask = type(o1)|type(o2); + switch(tmask) { + case OT_INTEGER:{ + SQInteger res, i1 = _integer(o1), i2 = _integer(o2); + switch(op) { + case '+': res = i1 + i2; break; + case '-': res = i1 - i2; break; + case '/': if(i2 == 0) { Raise_Error(_SC("division by zero")); return false; } + res = i1 / i2; + break; + case '*': res = i1 * i2; break; + case '%': if(i2 == 0) { Raise_Error(_SC("modulo by zero")); return false; } + res = i1 % i2; + break; + default: res = 0xDEADBEEF; + } + trg = res; } + break; + case (OT_FLOAT|OT_INTEGER): + case (OT_FLOAT):{ + SQFloat res, f1 = tofloat(o1), f2 = tofloat(o2); + switch(op) { + case '+': res = f1 + f2; break; + case '-': res = f1 - f2; break; + case '/': res = f1 / f2; break; + case '*': res = f1 * f2; break; + case '%': res = SQFloat(fmod((double)f1,(double)f2)); break; + default: res = 0x0f; + } + trg = res; } + break; + default: + if(op == '+' && (tmask & _RT_STRING)){ + if(!StringCat(o1, o2, trg)) return false; + } + else if(!ArithMetaMethod(op,o1,o2,trg)) { + return false; + } + } + return true; +} + +SQVM::SQVM(SQSharedState *ss) +{ + _sharedstate=ss; + _suspended = SQFalse; + _suspended_target = -1; + _suspended_root = SQFalse; + _suspended_traps = -1; + _foreignptr = NULL; + _nnativecalls = 0; + _nmetamethodscall = 0; + _lasterror.Null(); + _errorhandler.Null(); + _debughook = false; + _debughook_native = NULL; + _debughook_closure.Null(); + _openouters = NULL; + ci = NULL; + INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); +} + +void SQVM::Finalize() +{ + if(_openouters) CloseOuters(&_stack._vals[0]); + _roottable.Null(); + _lasterror.Null(); + _errorhandler.Null(); + _debughook = false; + _debughook_native = NULL; + _debughook_closure.Null(); + temp_reg.Null(); + _callstackdata.resize(0); + SQInteger size=_stack.size(); + for(SQInteger i=0;i<size;i++) + _stack[i].Null(); +} + +SQVM::~SQVM() +{ + Finalize(); + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); +} + +bool SQVM::ArithMetaMethod(SQInteger op,const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &dest) +{ + SQMetaMethod mm; + switch(op){ + case _SC('+'): mm=MT_ADD; break; + case _SC('-'): mm=MT_SUB; break; + case _SC('/'): mm=MT_DIV; break; + case _SC('*'): mm=MT_MUL; break; + case _SC('%'): mm=MT_MODULO; break; + default: mm = MT_ADD; assert(0); break; //shutup compiler + } + if(is_delegable(o1) && _delegable(o1)->_delegate) { + + SQObjectPtr closure; + if(_delegable(o1)->GetMetaMethod(this, mm, closure)) { + Push(o1);Push(o2); + return CallMetaMethod(closure,mm,2,dest); + } + } + Raise_Error(_SC("arith op %c on between '%s' and '%s'"),op,GetTypeName(o1),GetTypeName(o2)); + return false; +} + +bool SQVM::NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o) +{ + + switch(type(o)) { + case OT_INTEGER: + trg = -_integer(o); + return true; + case OT_FLOAT: + trg = -_float(o); + return true; + case OT_TABLE: + case OT_USERDATA: + case OT_INSTANCE: + if(_delegable(o)->_delegate) { + SQObjectPtr closure; + if(_delegable(o)->GetMetaMethod(this, MT_UNM, closure)) { + Push(o); + if(!CallMetaMethod(closure, MT_UNM, 1, temp_reg)) return false; + _Swap(trg,temp_reg); + return true; + + } + } + default:break; //shutup compiler + } + Raise_Error(_SC("attempt to negate a %s"), GetTypeName(o)); + return false; +} + +#define _RET_SUCCEED(exp) { result = (exp); return true; } +bool SQVM::ObjCmp(const SQObjectPtr &o1,const SQObjectPtr &o2,SQInteger &result) +{ + SQObjectType t1 = type(o1), t2 = type(o2); + if(t1 == t2){ + if(_rawval(o1)==_rawval(o2))_RET_SUCCEED(0); + SQObjectPtr res; + switch(t1){ + case OT_STRING: + _RET_SUCCEED(scstrcmp(_stringval(o1),_stringval(o2))); + case OT_INTEGER: + _RET_SUCCEED(_integer(o1)-_integer(o2)); + case OT_FLOAT: + _RET_SUCCEED((_float(o1)<_float(o2))?-1:1); + case OT_TABLE: + case OT_USERDATA: + case OT_INSTANCE: + if(_delegable(o1)->_delegate) { + SQObjectPtr closure; + if(_delegable(o1)->GetMetaMethod(this, MT_CMP, closure)) { + Push(o1);Push(o2); + if(!CallMetaMethod(closure,MT_CMP,2,res)) return false; + } + break; + } + //continues through (no break needed) + default: + _RET_SUCCEED( _userpointer(o1) < _userpointer(o2)?-1:1 ); + } + if(type(res)!=OT_INTEGER) { Raise_CompareError(o1,o2); return false; } + _RET_SUCCEED(_integer(res)); + + } + else{ + if(sq_isnumeric(o1) && sq_isnumeric(o2)){ + if((t1==OT_INTEGER) && (t2==OT_FLOAT)) { + if( _integer(o1)==_float(o2) ) { _RET_SUCCEED(0); } + else if( _integer(o1)<_float(o2) ) { _RET_SUCCEED(-1); } + _RET_SUCCEED(1); + } + else{ + if( _float(o1)==_integer(o2) ) { _RET_SUCCEED(0); } + else if( _float(o1)<_integer(o2) ) { _RET_SUCCEED(-1); } + _RET_SUCCEED(1); + } + } + else if(t1==OT_NULL) {_RET_SUCCEED(-1);} + else if(t2==OT_NULL) {_RET_SUCCEED(1);} + else { Raise_CompareError(o1,o2); return false; } + + } + assert(0); + _RET_SUCCEED(0); //cannot happen +} + +bool SQVM::CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res) +{ + SQInteger r; + if(ObjCmp(o1,o2,r)) { + switch(op) { + case CMP_G: res = (r > 0); return true; + case CMP_GE: res = (r >= 0); return true; + case CMP_L: res = (r < 0); return true; + case CMP_LE: res = (r <= 0); return true; + case CMP_3W: res = r; return true; + } + assert(0); + } + return false; +} + +bool SQVM::ToString(const SQObjectPtr &o,SQObjectPtr &res) +{ + switch(type(o)) { + case OT_STRING: + res = o; + return true; + case OT_FLOAT: + scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)),_SC("%g"),_float(o)); + break; + case OT_INTEGER: + scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)),_PRINT_INT_FMT,_integer(o)); + break; + case OT_BOOL: + scsprintf(_sp(rsl(6)),_integer(o)?_SC("true"):_SC("false")); + break; + case OT_TABLE: + case OT_USERDATA: + case OT_INSTANCE: + if(_delegable(o)->_delegate) { + SQObjectPtr closure; + if(_delegable(o)->GetMetaMethod(this, MT_TOSTRING, closure)) { + Push(o); + if(CallMetaMethod(closure,MT_TOSTRING,1,res)) {; + if(type(res) == OT_STRING) + return true; + } + else { + return false; + } + } + } + default: + scsprintf(_sp(rsl(sizeof(void*)+20)),_SC("(%s : 0x%p)"),GetTypeName(o),(void*)_rawval(o)); + } + res = SQString::Create(_ss(this),_spval); + return true; +} + + +bool SQVM::StringCat(const SQObjectPtr &str,const SQObjectPtr &obj,SQObjectPtr &dest) +{ + SQObjectPtr a, b; + if(!ToString(str, a)) return false; + if(!ToString(obj, b)) return false; + SQInteger l = _string(a)->_len , ol = _string(b)->_len; + SQChar *s = _sp(rsl(l + ol + 1)); + memcpy(s, _stringval(a), rsl(l)); + memcpy(s + l, _stringval(b), rsl(ol)); + dest = SQString::Create(_ss(this), _spval, l + ol); + return true; +} + +bool SQVM::TypeOf(const SQObjectPtr &obj1,SQObjectPtr &dest) +{ + if(is_delegable(obj1) && _delegable(obj1)->_delegate) { + SQObjectPtr closure; + if(_delegable(obj1)->GetMetaMethod(this, MT_TYPEOF, closure)) { + Push(obj1); + return CallMetaMethod(closure,MT_TYPEOF,1,dest); + } + } + dest = SQString::Create(_ss(this),GetTypeName(obj1)); + return true; +} + +bool SQVM::Init(SQVM *friendvm, SQInteger stacksize) +{ + _stack.resize(stacksize); + _alloccallsstacksize = 4; + _callstackdata.resize(_alloccallsstacksize); + _callsstacksize = 0; + _callsstack = &_callstackdata[0]; + _stackbase = 0; + _top = 0; + if(!friendvm) + _roottable = SQTable::Create(_ss(this), 0); + else { + _roottable = friendvm->_roottable; + _errorhandler = friendvm->_errorhandler; + _debughook = friendvm->_debughook; + _debughook_native = friendvm->_debughook_native; + _debughook_closure = friendvm->_debughook_closure; + } + + sq_base_register(this); + return true; +} + + +bool SQVM::StartCall(SQClosure *closure,SQInteger target,SQInteger args,SQInteger stackbase,bool tailcall) +{ + SQFunctionProto *func = closure->_function; + + SQInteger paramssize = func->_nparameters; + const SQInteger newtop = stackbase + func->_stacksize; + SQInteger nargs = args; + if(func->_varparams) + { + paramssize--; + if (nargs < paramssize) { + Raise_Error(_SC("wrong number of parameters")); + return false; + } + + //dumpstack(stackbase); + SQInteger nvargs = nargs - paramssize; + SQArray *arr = SQArray::Create(_ss(this),nvargs); + SQInteger pbase = stackbase+paramssize; + for(SQInteger n = 0; n < nvargs; n++) { + arr->_values[n] = _stack._vals[pbase]; + _stack._vals[pbase].Null(); + pbase++; + + } + _stack._vals[stackbase+paramssize] = arr; + //dumpstack(stackbase); + } + else if (paramssize != nargs) { + SQInteger ndef = func->_ndefaultparams; + SQInteger diff; + if(ndef && nargs < paramssize && (diff = paramssize - nargs) <= ndef) { + for(SQInteger n = ndef - diff; n < ndef; n++) { + _stack._vals[stackbase + (nargs++)] = closure->_defaultparams[n]; + } + } + else { + Raise_Error(_SC("wrong number of parameters")); + return false; + } + } + + if(closure->_env) { + _stack._vals[stackbase] = closure->_env->_obj; + } + + if(!EnterFrame(stackbase, newtop, tailcall)) return false; + + ci->_closure = closure; + ci->_literals = func->_literals; + ci->_ip = func->_instructions; + ci->_target = (SQInt32)target; + + if (_debughook) { + CallDebugHook(_SC('c')); + } + + if (closure->_function->_bgenerator) { + SQFunctionProto *f = closure->_function; + SQGenerator *gen = SQGenerator::Create(_ss(this), closure); + if(!gen->Yield(this,f->_stacksize)) + return false; + SQObjectPtr temp; + Return(1, target, temp); + STK(target) = gen; + } + + + return true; +} + +bool SQVM::Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval) +{ + SQBool _isroot = ci->_root; + SQInteger callerbase = _stackbase - ci->_prevstkbase; + + if (_debughook) { + for(SQInteger i=0; i<ci->_ncalls; i++) { + CallDebugHook(_SC('r')); + } + } + + SQObjectPtr *dest; + if (_isroot) { + dest = &(retval); + } else if (ci->_target == -1) { + dest = NULL; + } else { + dest = &_stack._vals[callerbase + ci->_target]; + } + if (dest) { + if(_arg0 != 0xFF) { + *dest = _stack._vals[_stackbase+_arg1]; + } + else { + dest->Null(); + } + //*dest = (_arg0 != 0xFF) ? _stack._vals[_stackbase+_arg1] : _null_; + } + LeaveFrame(); + return _isroot ? true : false; +} + +#define _RET_ON_FAIL(exp) { if(!exp) return false; } + +bool SQVM::PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr) +{ + SQObjectPtr trg; + _RET_ON_FAIL(ARITH_OP( op , trg, a, incr)); + target = a; + a = trg; + return true; +} + +bool SQVM::DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix,SQInteger selfidx) +{ + SQObjectPtr tmp, tself = self, tkey = key; + if (!Get(tself, tkey, tmp, false, selfidx)) { return false; } + _RET_ON_FAIL(ARITH_OP( op , target, tmp, incr)) + if (!Set(tself, tkey, target,selfidx)) { return false; } + if (postfix) target = tmp; + return true; +} + +#define arg0 (_i_._arg0) +#define sarg0 ((SQInteger)*((signed char *)&_i_._arg0)) +#define arg1 (_i_._arg1) +#define sarg1 (*((SQInt32 *)&_i_._arg1)) +#define arg2 (_i_._arg2) +#define arg3 (_i_._arg3) +#define sarg3 ((SQInteger)*((signed char *)&_i_._arg3)) + +SQRESULT SQVM::Suspend() +{ + if (_suspended) + return sq_throwerror(this, _SC("cannot suspend an already suspended vm")); + if (_nnativecalls!=2) + return sq_throwerror(this, _SC("cannot suspend through native calls/metamethods")); + return SQ_SUSPEND_FLAG; +} + + +#define _FINISH(howmuchtojump) {jump = howmuchtojump; return true; } +bool SQVM::FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr +&o3,SQObjectPtr &o4,SQInteger arg_2,int exitpos,int &jump) +{ + SQInteger nrefidx; + switch(type(o1)) { + case OT_TABLE: + if((nrefidx = _table(o1)->Next(false,o4, o2, o3)) == -1) _FINISH(exitpos); + o4 = (SQInteger)nrefidx; _FINISH(1); + case OT_ARRAY: + if((nrefidx = _array(o1)->Next(o4, o2, o3)) == -1) _FINISH(exitpos); + o4 = (SQInteger) nrefidx; _FINISH(1); + case OT_STRING: + if((nrefidx = _string(o1)->Next(o4, o2, o3)) == -1)_FINISH(exitpos); + o4 = (SQInteger)nrefidx; _FINISH(1); + case OT_CLASS: + if((nrefidx = _class(o1)->Next(o4, o2, o3)) == -1)_FINISH(exitpos); + o4 = (SQInteger)nrefidx; _FINISH(1); + case OT_USERDATA: + case OT_INSTANCE: + if(_delegable(o1)->_delegate) { + SQObjectPtr itr; + SQObjectPtr closure; + if(_delegable(o1)->GetMetaMethod(this, MT_NEXTI, closure)) { + Push(o1); + Push(o4); + if(CallMetaMethod(closure, MT_NEXTI, 2, itr)) { + o4 = o2 = itr; + if(type(itr) == OT_NULL) _FINISH(exitpos); + if(!Get(o1, itr, o3, false, DONT_FALL_BACK)) { + Raise_Error(_SC("_nexti returned an invalid idx")); // cloud be changed + return false; + } + _FINISH(1); + } + else { + return false; + } + } + Raise_Error(_SC("_nexti failed")); + return false; + } + break; + case OT_GENERATOR: + if(_generator(o1)->_state == SQGenerator::eDead) _FINISH(exitpos); + if(_generator(o1)->_state == SQGenerator::eSuspended) { + SQInteger idx = 0; + if(type(o4) == OT_INTEGER) { + idx = _integer(o4) + 1; + } + o2 = idx; + o4 = idx; + _generator(o1)->Resume(this, o3); + _FINISH(0); + } + default: + Raise_Error(_SC("cannot iterate %s"), GetTypeName(o1)); + } + return false; //cannot be hit(just to avoid warnings) +} + +#define COND_LITERAL (arg3!=0?ci->_literals[arg1]:STK(arg1)) + +#define SQ_THROW() { goto exception_trap; } + +#define _GUARD(exp) { if(!exp) { SQ_THROW();} } + +bool SQVM::CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func) +{ + SQInteger nouters; + SQClosure *closure = SQClosure::Create(_ss(this), func); + if((nouters = func->_noutervalues)) { + for(SQInteger i = 0; i<nouters; i++) { + SQOuterVar &v = func->_outervalues[i]; + switch(v._type){ + case otLOCAL: + FindOuter(closure->_outervalues[i], &STK(_integer(v._src))); + break; + case otOUTER: + closure->_outervalues[i] = _closure(ci->_closure)->_outervalues[_integer(v._src)]; + break; + } + } + } + SQInteger ndefparams; + if((ndefparams = func->_ndefaultparams)) { + for(SQInteger i = 0; i < ndefparams; i++) { + SQInteger spos = func->_defaultparams[i]; + closure->_defaultparams[i] = _stack._vals[_stackbase + spos]; + } + } + target = closure; + return true; + +} + + +bool SQVM::CLASS_OP(SQObjectPtr &target,SQInteger baseclass,SQInteger attributes) +{ + SQClass *base = NULL; + SQObjectPtr attrs; + if(baseclass != -1) { + if(type(_stack._vals[_stackbase+baseclass]) != OT_CLASS) { Raise_Error(_SC("trying to inherit from a %s"),GetTypeName(_stack._vals[_stackbase+baseclass])); return false; } + base = _class(_stack._vals[_stackbase + baseclass]); + } + if(attributes != MAX_FUNC_STACKSIZE) { + attrs = _stack._vals[_stackbase+attributes]; + } + target = SQClass::Create(_ss(this),base); + if(type(_class(target)->_metamethods[MT_INHERITED]) != OT_NULL) { + int nparams = 2; + SQObjectPtr ret; + Push(target); Push(attrs); + Call(_class(target)->_metamethods[MT_INHERITED],nparams,_top - nparams, ret, false); + Pop(nparams); + } + _class(target)->_attributes = attrs; + return true; +} + +bool SQVM::IsEqual(const SQObjectPtr &o1,const SQObjectPtr &o2,bool &res) +{ + if(type(o1) == type(o2)) { + res = (_rawval(o1) == _rawval(o2)); + } + else { + if(sq_isnumeric(o1) && sq_isnumeric(o2)) { + res = (tofloat(o1) == tofloat(o2)); + } + else { + res = false; + } + } + return true; +} + +bool SQVM::IsFalse(SQObjectPtr &o) +{ + if(((type(o) & SQOBJECT_CANBEFALSE) + && ( ((type(o) == OT_FLOAT) && (_float(o) == SQFloat(0.0))) )) +#if !defined(SQUSEDOUBLE) || (defined(SQUSEDOUBLE) && defined(_SQ64)) + || (_integer(o) == 0) ) //OT_NULL|OT_INTEGER|OT_BOOL +#else + || (((type(o) != OT_FLOAT) && (_integer(o) == 0))) ) //OT_NULL|OT_INTEGER|OT_BOOL +#endif + { + return true; + } + return false; +} + +bool SQVM::Execute(SQObjectPtr &closure, SQInteger nargs, SQInteger stackbase,SQObjectPtr &outres, SQBool raiseerror,ExecutionType et) +{ + if ((_nnativecalls + 1) > MAX_NATIVE_CALLS) { Raise_Error(_SC("Native stack overflow")); return false; } + _nnativecalls++; + AutoDec ad(&_nnativecalls); + SQInteger traps = 0; + CallInfo *prevci = ci; + + switch(et) { + case ET_CALL: { + temp_reg = closure; + if(!StartCall(_closure(temp_reg), _top - nargs, nargs, stackbase, false)) { + //call the handler if there are no calls in the stack, if not relies on the previous node + if(ci == NULL) CallErrorHandler(_lasterror); + return false; + } + if(ci == prevci) { + outres = STK(_top-nargs); + return true; + } + ci->_root = SQTrue; + } + break; + case ET_RESUME_GENERATOR: _generator(closure)->Resume(this, outres); ci->_root = SQTrue; traps += ci->_etraps; break; + case ET_RESUME_VM: + case ET_RESUME_THROW_VM: + traps = _suspended_traps; + ci->_root = _suspended_root; + _suspended = SQFalse; + if(et == ET_RESUME_THROW_VM) { SQ_THROW(); } + break; + } + +exception_restore: + // + { + for(;;) + { + const SQInstruction &_i_ = *ci->_ip++; + //dumpstack(_stackbase); + //scprintf("\n[%d] %s %d %d %d %d\n",ci->_ip-ci->_iv->_vals,g_InstrDesc[_i_.op].name,arg0,arg1,arg2,arg3); + switch(_i_.op) + { + case _OP_LINE: if (_debughook) CallDebugHook(_SC('l'),arg1); continue; + case _OP_LOAD: TARGET = ci->_literals[arg1]; continue; + case _OP_LOADINT: +#ifndef _SQ64 + TARGET = (SQInteger)arg1; continue; +#else + TARGET = (SQInteger)((SQUnsignedInteger32)arg1); continue; +#endif + case _OP_LOADFLOAT: TARGET = *((SQFloat *)&arg1); continue; + case _OP_DLOAD: TARGET = ci->_literals[arg1]; STK(arg2) = ci->_literals[arg3];continue; + case _OP_TAILCALL:{ + SQObjectPtr &t = STK(arg1); + if (type(t) == OT_CLOSURE + && (!_closure(t)->_function->_bgenerator)){ + SQObjectPtr clo = t; + if(_openouters) CloseOuters(&(_stack._vals[_stackbase])); + for (SQInteger i = 0; i < arg3; i++) STK(i) = STK(arg2 + i); + _GUARD(StartCall(_closure(clo), ci->_target, arg3, _stackbase, true)); + continue; + } + } + case _OP_CALL: { + SQObjectPtr clo = STK(arg1); + switch (type(clo)) { + case OT_CLOSURE: + _GUARD(StartCall(_closure(clo), sarg0, arg3, _stackbase+arg2, false)); + continue; + case OT_NATIVECLOSURE: { + bool suspend; + _GUARD(CallNative(_nativeclosure(clo), arg3, _stackbase+arg2, clo,suspend)); + if(suspend){ + _suspended = SQTrue; + _suspended_target = sarg0; + _suspended_root = ci->_root; + _suspended_traps = traps; + outres = clo; + return true; + } + if(sarg0 != -1) { + STK(arg0) = clo; + } + } + continue; + case OT_CLASS:{ + SQObjectPtr inst; + _GUARD(CreateClassInstance(_class(clo),inst,clo)); + if(sarg0 != -1) { + STK(arg0) = inst; + } + SQInteger stkbase; + switch(type(clo)) { + case OT_CLOSURE: + stkbase = _stackbase+arg2; + _stack._vals[stkbase] = inst; + _GUARD(StartCall(_closure(clo), -1, arg3, stkbase, false)); + break; + case OT_NATIVECLOSURE: + bool suspend; + stkbase = _stackbase+arg2; + _stack._vals[stkbase] = inst; + _GUARD(CallNative(_nativeclosure(clo), arg3, stkbase, clo,suspend)); + break; + default: break; //shutup GCC 4.x + } + } + break; + case OT_TABLE: + case OT_USERDATA: + case OT_INSTANCE:{ + SQObjectPtr closure; + if(_delegable(clo)->_delegate && _delegable(clo)->GetMetaMethod(this,MT_CALL,closure)) { + Push(clo); + for (SQInteger i = 0; i < arg3; i++) Push(STK(arg2 + i)); + if(!CallMetaMethod(closure, MT_CALL, arg3+1, clo)) SQ_THROW(); + if(sarg0 != -1) { + STK(arg0) = clo; + } + break; + } + + //Raise_Error(_SC("attempt to call '%s'"), GetTypeName(clo)); + //SQ_THROW(); + } + default: + Raise_Error(_SC("attempt to call '%s'"), GetTypeName(clo)); + SQ_THROW(); + } + } + continue; + case _OP_PREPCALL: + case _OP_PREPCALLK: { + SQObjectPtr &key = _i_.op == _OP_PREPCALLK?(ci->_literals)[arg1]:STK(arg1); + SQObjectPtr &o = STK(arg2); + if (!Get(o, key, temp_reg,false,arg2)) { + SQ_THROW(); + } + STK(arg3) = o; + _Swap(TARGET,temp_reg);//TARGET = temp_reg; + } + continue; + case _OP_GETK: + if (!Get(STK(arg2), ci->_literals[arg1], temp_reg, false,arg2)) { SQ_THROW();} + _Swap(TARGET,temp_reg);//TARGET = temp_reg; + continue; + case _OP_MOVE: TARGET = STK(arg1); continue; + case _OP_NEWSLOT: + _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3),false)); + if(arg0 != 0xFF) TARGET = STK(arg3); + continue; + case _OP_DELETE: _GUARD(DeleteSlot(STK(arg1), STK(arg2), TARGET)); continue; + case _OP_SET: + if (!Set(STK(arg1), STK(arg2), STK(arg3),arg1)) { SQ_THROW(); } + if (arg0 != 0xFF) TARGET = STK(arg3); + continue; + case _OP_GET: + if (!Get(STK(arg1), STK(arg2), temp_reg, false,arg1)) { SQ_THROW(); } + _Swap(TARGET,temp_reg);//TARGET = temp_reg; + continue; + case _OP_EQ:{ + bool res; + if(!IsEqual(STK(arg2),COND_LITERAL,res)) { SQ_THROW(); } + TARGET = res?true:false; + }continue; + case _OP_NE:{ + bool res; + if(!IsEqual(STK(arg2),COND_LITERAL,res)) { SQ_THROW(); } + TARGET = (!res)?true:false; + } continue; + case _OP_ADD: _ARITH_(+,TARGET,STK(arg2),STK(arg1)); continue; + case _OP_SUB: _ARITH_(-,TARGET,STK(arg2),STK(arg1)); continue; + case _OP_MUL: _ARITH_(*,TARGET,STK(arg2),STK(arg1)); continue; + case _OP_DIV: _ARITH_NOZERO(/,TARGET,STK(arg2),STK(arg1),_SC("division by zero")); continue; + case _OP_MOD: ARITH_OP('%',TARGET,STK(arg2),STK(arg1)); continue; + case _OP_BITW: _GUARD(BW_OP( arg3,TARGET,STK(arg2),STK(arg1))); continue; + case _OP_RETURN: + if((ci)->_generator) { + (ci)->_generator->Kill(); + } + if(Return(arg0, arg1, temp_reg)){ + assert(traps==0); + //outres = temp_reg; + _Swap(outres,temp_reg); + return true; + } + continue; + case _OP_LOADNULLS:{ for(SQInt32 n=0; n < arg1; n++) STK(arg0+n).Null(); }continue; + case _OP_LOADROOT: TARGET = _roottable; continue; + case _OP_LOADBOOL: TARGET = arg1?true:false; continue; + case _OP_DMOVE: STK(arg0) = STK(arg1); STK(arg2) = STK(arg3); continue; + case _OP_JMP: ci->_ip += (sarg1); continue; + //case _OP_JNZ: if(!IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue; + case _OP_JCMP: + _GUARD(CMP_OP((CmpOP)arg3,STK(arg2),STK(arg0),temp_reg)); + if(IsFalse(temp_reg)) ci->_ip+=(sarg1); + continue; + case _OP_JZ: if(IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue; + case _OP_GETOUTER: { + SQClosure *cur_cls = _closure(ci->_closure); + SQOuter *otr = _outer(cur_cls->_outervalues[arg1]); + TARGET = *(otr->_valptr); + } + continue; + case _OP_SETOUTER: { + SQClosure *cur_cls = _closure(ci->_closure); + SQOuter *otr = _outer(cur_cls->_outervalues[arg1]); + *(otr->_valptr) = STK(arg2); + if(arg0 != 0xFF) { + TARGET = STK(arg2); + } + } + continue; + case _OP_NEWOBJ: + switch(arg3) { + case NOT_TABLE: TARGET = SQTable::Create(_ss(this), arg1); continue; + case NOT_ARRAY: TARGET = SQArray::Create(_ss(this), 0); _array(TARGET)->Reserve(arg1); continue; + case NOT_CLASS: _GUARD(CLASS_OP(TARGET,arg1,arg2)); continue; + default: assert(0); continue; + } + case _OP_APPENDARRAY: + { + SQObject val; + val._unVal.raw = 0; + switch(arg2) { + case AAT_STACK: + val = STK(arg1); break; + case AAT_LITERAL: + val = ci->_literals[arg1]; break; + case AAT_INT: + val._type = OT_INTEGER; +#ifndef _SQ64 + val._unVal.nInteger = (SQInteger)arg1; +#else + val._unVal.nInteger = (SQInteger)((SQUnsignedInteger32)arg1); +#endif + break; + case AAT_FLOAT: + val._type = OT_FLOAT; + val._unVal.fFloat = *((SQFloat *)&arg1); + break; + case AAT_BOOL: + val._type = OT_BOOL; + val._unVal.nInteger = arg1; + break; + default: assert(0); break; + + } + _array(STK(arg0))->Append(val); continue; + } + case _OP_COMPARITH: { + SQInteger selfidx = (((SQUnsignedInteger)arg1&0xFFFF0000)>>16); + _GUARD(DerefInc(arg3, TARGET, STK(selfidx), STK(arg2), STK(arg1&0x0000FFFF), false, selfidx)); + } + continue; + case _OP_INC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, false, arg1));} continue; + case _OP_INCL: { + SQObjectPtr &a = STK(arg1); + if(type(a) == OT_INTEGER) { + a._unVal.nInteger = _integer(a) + sarg3; + } + else { + SQObjectPtr o(sarg3); //_GUARD(LOCAL_INC('+',TARGET, STK(arg1), o)); + _ARITH_(+,a,a,o); + } + } continue; + case _OP_PINC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, true, arg1));} continue; + case _OP_PINCL: { + SQObjectPtr &a = STK(arg1); + if(type(a) == OT_INTEGER) { + TARGET = a; + a._unVal.nInteger = _integer(a) + sarg3; + } + else { + SQObjectPtr o(sarg3); _GUARD(PLOCAL_INC('+',TARGET, STK(arg1), o)); + } + + } continue; + case _OP_CMP: _GUARD(CMP_OP((CmpOP)arg3,STK(arg2),STK(arg1),TARGET)) continue; + case _OP_EXISTS: TARGET = Get(STK(arg1), STK(arg2), temp_reg, true,DONT_FALL_BACK)?true:false;continue; + case _OP_INSTANCEOF: + if(type(STK(arg1)) != OT_CLASS) + {Raise_Error(_SC("cannot apply instanceof between a %s and a %s"),GetTypeName(STK(arg1)),GetTypeName(STK(arg2))); SQ_THROW();} + TARGET = (type(STK(arg2)) == OT_INSTANCE) ? (_instance(STK(arg2))->InstanceOf(_class(STK(arg1)))?true:false) : false; + continue; + case _OP_AND: + if(IsFalse(STK(arg2))) { + TARGET = STK(arg2); + ci->_ip += (sarg1); + } + continue; + case _OP_OR: + if(!IsFalse(STK(arg2))) { + TARGET = STK(arg2); + ci->_ip += (sarg1); + } + continue; + case _OP_NEG: _GUARD(NEG_OP(TARGET,STK(arg1))); continue; + case _OP_NOT: TARGET = IsFalse(STK(arg1)); continue; + case _OP_BWNOT: + if(type(STK(arg1)) == OT_INTEGER) { + SQInteger t = _integer(STK(arg1)); + TARGET = SQInteger(~t); + continue; + } + Raise_Error(_SC("attempt to perform a bitwise op on a %s"), GetTypeName(STK(arg1))); + SQ_THROW(); + case _OP_CLOSURE: { + SQClosure *c = ci->_closure._unVal.pClosure; + SQFunctionProto *fp = c->_function; + if(!CLOSURE_OP(TARGET,fp->_functions[arg1]._unVal.pFunctionProto)) { SQ_THROW(); } + continue; + } + case _OP_YIELD:{ + if(ci->_generator) { + if(sarg1 != MAX_FUNC_STACKSIZE) temp_reg = STK(arg1); + _GUARD(ci->_generator->Yield(this,arg2)); + traps -= ci->_etraps; + if(sarg1 != MAX_FUNC_STACKSIZE) _Swap(STK(arg1),temp_reg);//STK(arg1) = temp_reg; + } + else { Raise_Error(_SC("trying to yield a '%s',only genenerator can be yielded"), GetTypeName(ci->_generator)); SQ_THROW();} + if(Return(arg0, arg1, temp_reg)){ + assert(traps == 0); + outres = temp_reg; + return true; + } + + } + continue; + case _OP_RESUME: + if(type(STK(arg1)) != OT_GENERATOR){ Raise_Error(_SC("trying to resume a '%s',only genenerator can be resumed"), GetTypeName(STK(arg1))); SQ_THROW();} + _GUARD(_generator(STK(arg1))->Resume(this, TARGET)); + traps += ci->_etraps; + continue; + case _OP_FOREACH:{ int tojump; + _GUARD(FOREACH_OP(STK(arg0),STK(arg2),STK(arg2+1),STK(arg2+2),arg2,sarg1,tojump)); + ci->_ip += tojump; } + continue; + case _OP_POSTFOREACH: + assert(type(STK(arg0)) == OT_GENERATOR); + if(_generator(STK(arg0))->_state == SQGenerator::eDead) + ci->_ip += (sarg1 - 1); + continue; + case _OP_CLONE: _GUARD(Clone(STK(arg1), TARGET)); continue; + case _OP_TYPEOF: _GUARD(TypeOf(STK(arg1), TARGET)) continue; + case _OP_PUSHTRAP:{ + SQInstruction *_iv = _closure(ci->_closure)->_function->_instructions; + _etraps.push_back(SQExceptionTrap(_top,_stackbase, &_iv[(ci->_ip-_iv)+arg1], arg0)); traps++; + ci->_etraps++; + } + continue; + case _OP_POPTRAP: { + for(SQInteger i = 0; i < arg0; i++) { + _etraps.pop_back(); traps--; + ci->_etraps--; + } + } + continue; + case _OP_THROW: Raise_Error(TARGET); SQ_THROW(); continue; + case _OP_NEWSLOTA: { + bool bstatic = (arg0&NEW_SLOT_STATIC_FLAG)?true:false; + if(type(STK(arg1)) == OT_CLASS) { + if(type(_class(STK(arg1))->_metamethods[MT_NEWMEMBER]) != OT_NULL ) { + Push(STK(arg1)); Push(STK(arg2)); Push(STK(arg3)); + Push((arg0&NEW_SLOT_ATTRIBUTES_FLAG) ? STK(arg2-1) : SQObjectPtr()); + Push(bstatic); + int nparams = 5; + if(Call(_class(STK(arg1))->_metamethods[MT_NEWMEMBER], nparams, _top - nparams, temp_reg,SQFalse)) { + Pop(nparams); + continue; + } + else { + SQ_THROW(); + } + } + } + _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3),bstatic)); + if((arg0&NEW_SLOT_ATTRIBUTES_FLAG)) { + _class(STK(arg1))->SetAttributes(STK(arg2),STK(arg2-1)); + } + } + continue; + case _OP_GETBASE:{ + SQClosure *clo = _closure(ci->_closure); + if(clo->_base) { + TARGET = clo->_base; + } + else { + TARGET.Null(); + } + continue; + } + case _OP_CLOSE: + if(_openouters) CloseOuters(&(STK(arg1))); + continue; + } + + } + } +exception_trap: + { + SQObjectPtr currerror = _lasterror; +// dumpstack(_stackbase); +// SQInteger n = 0; + SQInteger last_top = _top; + + if(_ss(this)->_notifyallexceptions || (!traps && raiseerror)) CallErrorHandler(currerror); + + while( ci ) { + if(ci->_etraps > 0) { + SQExceptionTrap &et = _etraps.top(); + ci->_ip = et._ip; + _top = et._stacksize; + _stackbase = et._stackbase; + _stack._vals[_stackbase + et._extarget] = currerror; + _etraps.pop_back(); traps--; ci->_etraps--; + while(last_top >= _top) _stack._vals[last_top--].Null(); + goto exception_restore; + } + else if (_debughook) { + //notify debugger of a "return" + //even if it really an exception unwinding the stack + for(SQInteger i = 0; i < ci->_ncalls; i++) { + CallDebugHook(_SC('r')); + } + } + if(ci->_generator) ci->_generator->Kill(); + bool mustbreak = ci && ci->_root; + LeaveFrame(); + if(mustbreak) break; + } + + _lasterror = currerror; + return false; + } + assert(0); +} + +bool SQVM::CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor) +{ + inst = theclass->CreateInstance(); + if(!theclass->GetConstructor(constructor)) { + constructor.Null(); + } + return true; +} + +void SQVM::CallErrorHandler(SQObjectPtr &error) +{ + if(type(_errorhandler) != OT_NULL) { + SQObjectPtr out; + Push(_roottable); Push(error); + Call(_errorhandler, 2, _top-2, out,SQFalse); + Pop(2); + } +} + + +void SQVM::CallDebugHook(SQInteger type,SQInteger forcedline) +{ + _debughook = false; + SQFunctionProto *func=_closure(ci->_closure)->_function; + if(_debughook_native) { + const SQChar *src = type(func->_sourcename) == OT_STRING?_stringval(func->_sourcename):NULL; + const SQChar *fname = type(func->_name) == OT_STRING?_stringval(func->_name):NULL; + SQInteger line = forcedline?forcedline:func->GetLine(ci->_ip); + _debughook_native(this,type,src,line,fname); + } + else { + SQObjectPtr temp_reg; + SQInteger nparams=5; + Push(_roottable); Push(type); Push(func->_sourcename); Push(forcedline?forcedline:func->GetLine(ci->_ip)); Push(func->_name); + Call(_debughook_closure,nparams,_top-nparams,temp_reg,SQFalse); + Pop(nparams); + } + _debughook = true; +} + +bool SQVM::CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newbase, SQObjectPtr &retval, bool &suspend) +{ + SQInteger nparamscheck = nclosure->_nparamscheck; + SQInteger newtop = newbase + nargs + nclosure->_noutervalues; + + if (_nnativecalls + 1 > MAX_NATIVE_CALLS) { + Raise_Error(_SC("Native stack overflow")); + return false; + } + + if(nparamscheck && (((nparamscheck > 0) && (nparamscheck != nargs)) || + ((nparamscheck < 0) && (nargs < (-nparamscheck))))) + { + Raise_Error(_SC("wrong number of parameters")); + return false; + } + + SQInteger tcs; + SQIntVec &tc = nclosure->_typecheck; + if((tcs = tc.size())) { + for(SQInteger i = 0; i < nargs && i < tcs; i++) { + if((tc._vals[i] != -1) && !(type(_stack._vals[newbase+i]) & tc._vals[i])) { + Raise_ParamTypeError(i,tc._vals[i],type(_stack._vals[newbase+i])); + return false; + } + } + } + + if(!EnterFrame(newbase, newtop, false)) return false; + ci->_closure = nclosure; + + SQInteger outers = nclosure->_noutervalues; + for (SQInteger i = 0; i < outers; i++) { + _stack._vals[newbase+nargs+i] = nclosure->_outervalues[i]; + } + if(nclosure->_env) { + _stack._vals[newbase] = nclosure->_env->_obj; + } + + _nnativecalls++; + SQInteger ret = (nclosure->_function)(this); + _nnativecalls--; + + suspend = false; + if (ret == SQ_SUSPEND_FLAG) { + suspend = true; + } + else if (ret < 0) { + LeaveFrame(); + Raise_Error(_lasterror); + return false; + } + if(ret) { + retval = _stack._vals[_top-1]; + } + else { + retval.Null(); + } + //retval = ret ? _stack._vals[_top-1] : _null_; + LeaveFrame(); + return true; +} + +#define FALLBACK_OK 0 +#define FALLBACK_NO_MATCH 1 +#define FALLBACK_ERROR 2 + +bool SQVM::Get(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw, SQInteger selfidx) +{ + switch(type(self)){ + case OT_TABLE: + if(_table(self)->Get(key,dest))return true; + break; + case OT_ARRAY: + if(sq_isnumeric(key)) { if(_array(self)->Get(tointeger(key),dest)) { return true; } Raise_IdxError(key); return false; } + break; + case OT_INSTANCE: + if(_instance(self)->Get(key,dest)) return true; + break; + case OT_CLASS: + if(_class(self)->Get(key,dest)) return true; + break; + case OT_STRING: + if(sq_isnumeric(key)){ + SQInteger n = tointeger(key); + if(abs((int)n) < _string(self)->_len) { + if(n < 0) n = _string(self)->_len - n; + dest = SQInteger(_stringval(self)[n]); + return true; + } + Raise_IdxError(key); + return false; + } + break; + default:break; //shut up compiler + } + if(!raw) { + switch(FallBackGet(self,key,dest)) { + case FALLBACK_OK: return true; //okie + case FALLBACK_NO_MATCH: break; //keep falling back + case FALLBACK_ERROR: return false; // the metamethod failed + } + if(InvokeDefaultDelegate(self,key,dest)) { + return true; + } + } +//#ifdef ROOT_FALLBACK + if(selfidx == 0) { + if(_table(_roottable)->Get(key,dest)) return true; + } +//#endif + Raise_IdxError(key); + return false; +} + +bool SQVM::InvokeDefaultDelegate(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest) +{ + SQTable *ddel = NULL; + switch(type(self)) { + case OT_CLASS: ddel = _class_ddel; break; + case OT_TABLE: ddel = _table_ddel; break; + case OT_ARRAY: ddel = _array_ddel; break; + case OT_STRING: ddel = _string_ddel; break; + case OT_INSTANCE: ddel = _instance_ddel; break; + case OT_INTEGER:case OT_FLOAT:case OT_BOOL: ddel = _number_ddel; break; + case OT_GENERATOR: ddel = _generator_ddel; break; + case OT_CLOSURE: case OT_NATIVECLOSURE: ddel = _closure_ddel; break; + case OT_THREAD: ddel = _thread_ddel; break; + case OT_WEAKREF: ddel = _weakref_ddel; break; + default: return false; + } + return ddel->Get(key,dest); +} + + +SQInteger SQVM::FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest) +{ + switch(type(self)){ + case OT_TABLE: + case OT_USERDATA: + //delegation + if(_delegable(self)->_delegate) { + if(Get(SQObjectPtr(_delegable(self)->_delegate),key,dest,false,DONT_FALL_BACK)) return FALLBACK_OK; + } + else { + return FALLBACK_NO_MATCH; + } + //go through + case OT_INSTANCE: { + SQObjectPtr closure; + if(_delegable(self)->GetMetaMethod(this, MT_GET, closure)) { + Push(self);Push(key); + _nmetamethodscall++; + AutoDec ad(&_nmetamethodscall); + if(Call(closure, 2, _top - 2, dest, SQFalse)) { + Pop(2); + return FALLBACK_OK; + } + else { + if(type(_lasterror) != OT_NULL) { //NULL means "clean failure" (not found) + //error + Pop(2); + return FALLBACK_ERROR; + } + } + } + } + break; + default: break;//shutup GCC 4.x + } + // no metamethod or no fallback type + return FALLBACK_NO_MATCH; +} + +bool SQVM::Set(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,SQInteger selfidx) +{ + switch(type(self)){ + case OT_TABLE: + if(_table(self)->Set(key,val)) return true; + break; + case OT_INSTANCE: + if(_instance(self)->Set(key,val)) return true; + break; + case OT_ARRAY: + if(!sq_isnumeric(key)) { Raise_Error(_SC("indexing %s with %s"),GetTypeName(self),GetTypeName(key)); return false; } + if(!_array(self)->Set(tointeger(key),val)) { + Raise_IdxError(key); + return false; + } + return true; + default: + Raise_Error(_SC("trying to set '%s'"),GetTypeName(self)); + return false; + } + + switch(FallBackSet(self,key,val)) { + case FALLBACK_OK: return true; //okie + case FALLBACK_NO_MATCH: break; //keep falling back + case FALLBACK_ERROR: return false; // the metamethod failed + } + if(selfidx == 0) { + if(_table(_roottable)->Set(key,val)) + return true; + } + Raise_IdxError(key); + return false; +} + +SQInteger SQVM::FallBackSet(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val) +{ + switch(type(self)) { + case OT_TABLE: + if(_table(self)->_delegate) { + if(Set(_table(self)->_delegate,key,val,DONT_FALL_BACK)) return FALLBACK_OK; + } + //keps on going + case OT_INSTANCE: + case OT_USERDATA:{ + SQObjectPtr closure; + SQObjectPtr t; + if(_delegable(self)->GetMetaMethod(this, MT_SET, closure)) { + Push(self);Push(key);Push(val); + _nmetamethodscall++; + AutoDec ad(&_nmetamethodscall); + if(Call(closure, 3, _top - 3, t, SQFalse)) { + Pop(3); + return FALLBACK_OK; + } + else { + if(type(_lasterror) != OT_NULL) { //NULL means "clean failure" (not found) + //error + Pop(3); + return FALLBACK_ERROR; + } + } + } + } + break; + default: break;//shutup GCC 4.x + } + // no metamethod or no fallback type + return FALLBACK_NO_MATCH; +} + +bool SQVM::Clone(const SQObjectPtr &self,SQObjectPtr &target) +{ + SQObjectPtr temp_reg; + SQObjectPtr newobj; + switch(type(self)){ + case OT_TABLE: + newobj = _table(self)->Clone(); + goto cloned_mt; + case OT_INSTANCE: { + newobj = _instance(self)->Clone(_ss(this)); +cloned_mt: + SQObjectPtr closure; + if(_delegable(newobj)->_delegate && _delegable(newobj)->GetMetaMethod(this,MT_CLONED,closure)) { + Push(newobj); + Push(self); + if(!CallMetaMethod(closure,MT_CLONED,2,temp_reg)) + return false; + } + } + target = newobj; + return true; + case OT_ARRAY: + target = _array(self)->Clone(); + return true; + default: + Raise_Error(_SC("cloning a %s"), GetTypeName(self)); + return false; + } +} + +bool SQVM::NewSlot(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic) +{ + if(type(key) == OT_NULL) { Raise_Error(_SC("null cannot be used as index")); return false; } + switch(type(self)) { + case OT_TABLE: { + bool rawcall = true; + if(_table(self)->_delegate) { + SQObjectPtr res; + if(!_table(self)->Get(key,res)) { + SQObjectPtr closure; + if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_NEWSLOT,closure)) { + Push(self);Push(key);Push(val); + if(!CallMetaMethod(closure,MT_NEWSLOT,3,res)) { + return false; + } + rawcall = false; + } + else { + rawcall = true; + } + } + } + if(rawcall) _table(self)->NewSlot(key,val); //cannot fail + + break;} + case OT_INSTANCE: { + SQObjectPtr res; + SQObjectPtr closure; + if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_NEWSLOT,closure)) { + Push(self);Push(key);Push(val); + if(!CallMetaMethod(closure,MT_NEWSLOT,3,res)) { + return false; + } + break; + } + Raise_Error(_SC("class instances do not support the new slot operator")); + return false; + break;} + case OT_CLASS: + if(!_class(self)->NewSlot(_ss(this),key,val,bstatic)) { + if(_class(self)->_locked) { + Raise_Error(_SC("trying to modify a class that has already been instantiated")); + return false; + } + else { + SQObjectPtr oval = PrintObjVal(key); + Raise_Error(_SC("the property '%s' already exists"),_stringval(oval)); + return false; + } + } + break; + default: + Raise_Error(_SC("indexing %s with %s"),GetTypeName(self),GetTypeName(key)); + return false; + break; + } + return true; +} + + + +bool SQVM::DeleteSlot(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &res) +{ + switch(type(self)) { + case OT_TABLE: + case OT_INSTANCE: + case OT_USERDATA: { + SQObjectPtr t; + //bool handled = false; + SQObjectPtr closure; + if(_delegable(self)->_delegate && _delegable(self)->GetMetaMethod(this,MT_DELSLOT,closure)) { + Push(self);Push(key); + return CallMetaMethod(closure,MT_DELSLOT,2,res); + } + else { + if(type(self) == OT_TABLE) { + if(_table(self)->Get(key,t)) { + _table(self)->Remove(key); + } + else { + Raise_IdxError((SQObject &)key); + return false; + } + } + else { + Raise_Error(_SC("cannot delete a slot from %s"),GetTypeName(self)); + return false; + } + } + res = t; + } + break; + default: + Raise_Error(_SC("attempt to delete a slot from a %s"),GetTypeName(self)); + return false; + } + return true; +} + +bool SQVM::Call(SQObjectPtr &closure,SQInteger nparams,SQInteger stackbase,SQObjectPtr &outres,SQBool raiseerror) +{ +#ifdef _DEBUG +SQInteger prevstackbase = _stackbase; +#endif + switch(type(closure)) { + case OT_CLOSURE: + return Execute(closure, nparams, stackbase, outres, raiseerror); + break; + case OT_NATIVECLOSURE:{ + bool suspend; + return CallNative(_nativeclosure(closure), nparams, stackbase, outres,suspend); + + } + break; + case OT_CLASS: { + SQObjectPtr constr; + SQObjectPtr temp; + CreateClassInstance(_class(closure),outres,constr); + if(type(constr) != OT_NULL) { + _stack[stackbase] = outres; + return Call(constr,nparams,stackbase,temp,raiseerror); + } + return true; + } + break; + default: + return false; + } +#ifdef _DEBUG + if(!_suspended) { + assert(_stackbase == prevstackbase); + } +#endif + return true; +} + +bool SQVM::CallMetaMethod(SQObjectPtr &closure,SQMetaMethod mm,SQInteger nparams,SQObjectPtr &outres) +{ + //SQObjectPtr closure; + + _nmetamethodscall++; + if(Call(closure, nparams, _top - nparams, outres, SQFalse)) { + _nmetamethodscall--; + Pop(nparams); + return true; + } + _nmetamethodscall--; + //} + Pop(nparams); + return false; +} + +void SQVM::FindOuter(SQObjectPtr &target, SQObjectPtr *stackindex) +{ + SQOuter **pp = &_openouters; + SQOuter *p; + SQOuter *otr; + + while ((p = *pp) != NULL && p->_valptr >= stackindex) { + if (p->_valptr == stackindex) { + target = SQObjectPtr(p); + return; + } + pp = &p->_next; + } + otr = SQOuter::Create(_ss(this), stackindex); + otr->_next = *pp; + otr->_idx = (stackindex - _stack._vals); + __ObjAddRef(otr); + *pp = otr; + target = SQObjectPtr(otr); +} + +bool SQVM::EnterFrame(SQInteger newbase, SQInteger newtop, bool tailcall) +{ + if( !tailcall ) { + if( _callsstacksize == _alloccallsstacksize ) { + GrowCallStack(); + } + ci = &_callsstack[_callsstacksize++]; + ci->_prevstkbase = (SQInt32)(newbase - _stackbase); + ci->_prevtop = (SQInt32)(_top - _stackbase); + ci->_etraps = 0; + ci->_ncalls = 1; + ci->_generator = NULL; + ci->_root = SQFalse; + } + else { + ci->_ncalls++; + } + + _stackbase = newbase; + _top = newtop; + if(newtop + MIN_STACK_OVERHEAD > (SQInteger)_stack.size()) { + if(_nmetamethodscall) { + Raise_Error(_SC("stack overflow, cannot resize stack while in a metamethod")); + return false; + } + _stack.resize(_stack.size() + (MIN_STACK_OVERHEAD << 2)); + RelocateOuters(); + } + return true; +} + +void SQVM::LeaveFrame() { + SQInteger last_top = _top; + SQInteger last_stackbase = _stackbase; + SQInteger css = --_callsstacksize; + + /* First clean out the call stack frame */ + ci->_closure.Null(); + _stackbase -= ci->_prevstkbase; + _top = _stackbase + ci->_prevtop; + ci = (css) ? &_callsstack[css-1] : NULL; + + if(_openouters) CloseOuters(&(_stack._vals[last_stackbase])); + while (last_top >= _top) { + _stack._vals[last_top--].Null(); + } +} + +void SQVM::RelocateOuters() +{ + SQOuter *p = _openouters; + while (p) { + p->_valptr = _stack._vals + p->_idx; + p = p->_next; + } +} + +void SQVM::CloseOuters(SQObjectPtr *stackindex) { + SQOuter *p; + while ((p = _openouters) != NULL && p->_valptr >= stackindex) { + p->_value = *(p->_valptr); + p->_valptr = &p->_value; + _openouters = p->_next; + __ObjRelease(p); + } +} + +void SQVM::Remove(SQInteger n) { + n = (n >= 0)?n + _stackbase - 1:_top + n; + for(SQInteger i = n; i < _top; i++){ + _stack[i] = _stack[i+1]; + } + _stack[_top].Null(); + _top--; +} + +void SQVM::Pop() { + _stack[--_top].Null(); +} + +void SQVM::Pop(SQInteger n) { + for(SQInteger i = 0; i < n; i++){ + _stack[--_top].Null(); + } +} + +void SQVM::PushNull() { _stack[_top++].Null(); } +void SQVM::Push(const SQObjectPtr &o) { _stack[_top++] = o; } +SQObjectPtr &SQVM::Top() { return _stack[_top-1]; } +SQObjectPtr &SQVM::PopGet() { return _stack[--_top]; } +SQObjectPtr &SQVM::GetUp(SQInteger n) { return _stack[_top+n]; } +SQObjectPtr &SQVM::GetAt(SQInteger n) { return _stack[n]; } + +#ifdef _DEBUG_DUMP +void SQVM::dumpstack(SQInteger stackbase,bool dumpall) +{ + SQInteger size=dumpall?_stack.size():_top; + SQInteger n=0; + scprintf(_SC("\n>>>>stack dump<<<<\n")); + CallInfo &ci=_callsstack[_callsstacksize-1]; + scprintf(_SC("IP: %p\n"),ci._ip); + scprintf(_SC("prev stack base: %d\n"),ci._prevstkbase); + scprintf(_SC("prev top: %d\n"),ci._prevtop); + for(SQInteger i=0;i<size;i++){ + SQObjectPtr &obj=_stack[i]; + if(stackbase==i)scprintf(_SC(">"));else scprintf(_SC(" ")); + scprintf(_SC("[%d]:"),n); + switch(type(obj)){ + case OT_FLOAT: scprintf(_SC("FLOAT %.3f"),_float(obj));break; + case OT_INTEGER: scprintf(_SC("INTEGER %d"),_integer(obj));break; + case OT_BOOL: scprintf(_SC("BOOL %s"),_integer(obj)?"true":"false");break; + case OT_STRING: scprintf(_SC("STRING %s"),_stringval(obj));break; + case OT_NULL: scprintf(_SC("NULL")); break; + case OT_TABLE: scprintf(_SC("TABLE %p[%p]"),_table(obj),_table(obj)->_delegate);break; + case OT_ARRAY: scprintf(_SC("ARRAY %p"),_array(obj));break; + case OT_CLOSURE: scprintf(_SC("CLOSURE [%p]"),_closure(obj));break; + case OT_NATIVECLOSURE: scprintf(_SC("NATIVECLOSURE"));break; + case OT_USERDATA: scprintf(_SC("USERDATA %p[%p]"),_userdataval(obj),_userdata(obj)->_delegate);break; + case OT_GENERATOR: scprintf(_SC("GENERATOR %p"),_generator(obj));break; + case OT_THREAD: scprintf(_SC("THREAD [%p]"),_thread(obj));break; + case OT_USERPOINTER: scprintf(_SC("USERPOINTER %p"),_userpointer(obj));break; + case OT_CLASS: scprintf(_SC("CLASS %p"),_class(obj));break; + case OT_INSTANCE: scprintf(_SC("INSTANCE %p"),_instance(obj));break; + case OT_WEAKREF: scprintf(_SC("WEAKERF %p"),_weakref(obj));break; + default: + assert(0); + break; + }; + scprintf(_SC("\n")); + ++n; + } +} + + + +#endif diff --git a/squirrel_3_0_1_stable/squirrel/sqvm.h b/squirrel_3_0_1_stable/squirrel/sqvm.h index 397dcd9c1..a21be543d 100644 --- a/squirrel_3_0_1_stable/squirrel/sqvm.h +++ b/squirrel_3_0_1_stable/squirrel/sqvm.h @@ -1,208 +1,208 @@ -/* see copyright notice in squirrel.h */
-#ifndef _SQVM_H_
-#define _SQVM_H_
-
-#include "sqopcodes.h"
-#include "sqobject.h"
-#define MAX_NATIVE_CALLS 100
-#define MIN_STACK_OVERHEAD 15
-
-#define SQ_SUSPEND_FLAG -666
-#define DONT_FALL_BACK 666
-//base lib
-void sq_base_register(HSQUIRRELVM v);
-
-struct SQExceptionTrap{
- SQExceptionTrap() {}
- SQExceptionTrap(SQInteger ss, SQInteger stackbase,SQInstruction *ip, SQInteger ex_target){ _stacksize = ss; _stackbase = stackbase; _ip = ip; _extarget = ex_target;}
- SQExceptionTrap(const SQExceptionTrap &et) { (*this) = et; }
- SQInteger _stackbase;
- SQInteger _stacksize;
- SQInstruction *_ip;
- SQInteger _extarget;
-};
-
-#define _INLINE
-
-#define STK(a) _stack._vals[_stackbase+(a)]
-#define TARGET _stack._vals[_stackbase+arg0]
-
-typedef sqvector<SQExceptionTrap> ExceptionsTraps;
-
-struct SQVM : public CHAINABLE_OBJ
-{
- struct CallInfo{
- //CallInfo() { _generator = NULL;}
- SQInstruction *_ip;
- SQObjectPtr *_literals;
- SQObjectPtr _closure;
- SQGenerator *_generator;
- SQInt32 _etraps;
- SQInt32 _prevstkbase;
- SQInt32 _prevtop;
- SQInt32 _target;
- SQInt32 _ncalls;
- SQBool _root;
- };
-
-typedef sqvector<CallInfo> CallInfoVec;
-public:
- void DebugHookProxy(SQInteger type, const SQChar * sourcename, SQInteger line, const SQChar * funcname);
- static void _DebugHookProxy(HSQUIRRELVM v, SQInteger type, const SQChar * sourcename, SQInteger line, const SQChar * funcname);
- enum ExecutionType { ET_CALL, ET_RESUME_GENERATOR, ET_RESUME_VM,ET_RESUME_THROW_VM };
- SQVM(SQSharedState *ss);
- ~SQVM();
- bool Init(SQVM *friendvm, SQInteger stacksize);
- bool Execute(SQObjectPtr &func, SQInteger nargs, SQInteger stackbase, SQObjectPtr &outres, SQBool raiseerror, ExecutionType et = ET_CALL);
- //starts a native call return when the NATIVE closure returns
- bool CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newbase, SQObjectPtr &retval,bool &suspend);
- //starts a SQUIRREL call in the same "Execution loop"
- bool StartCall(SQClosure *closure, SQInteger target, SQInteger nargs, SQInteger stackbase, bool tailcall);
- bool CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor);
- //call a generic closure pure SQUIRREL or NATIVE
- bool Call(SQObjectPtr &closure, SQInteger nparams, SQInteger stackbase, SQObjectPtr &outres,SQBool raiseerror);
- SQRESULT Suspend();
-
- void CallDebugHook(SQInteger type,SQInteger forcedline=0);
- void CallErrorHandler(SQObjectPtr &e);
- bool Get(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &dest, bool raw, SQInteger selfidx);
- SQInteger FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest);
- bool InvokeDefaultDelegate(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest);
- bool Set(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val, SQInteger selfidx);
- SQInteger FallBackSet(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val);
- bool NewSlot(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val,bool bstatic);
- bool DeleteSlot(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &res);
- bool Clone(const SQObjectPtr &self, SQObjectPtr &target);
- bool ObjCmp(const SQObjectPtr &o1, const SQObjectPtr &o2,SQInteger &res);
- bool StringCat(const SQObjectPtr &str, const SQObjectPtr &obj, SQObjectPtr &dest);
- static bool IsEqual(const SQObjectPtr &o1,const SQObjectPtr &o2,bool &res);
- bool ToString(const SQObjectPtr &o,SQObjectPtr &res);
- SQString *PrintObjVal(const SQObjectPtr &o);
-
-
- void Raise_Error(const SQChar *s, ...);
- void Raise_Error(const SQObjectPtr &desc);
- void Raise_IdxError(const SQObjectPtr &o);
- void Raise_CompareError(const SQObject &o1, const SQObject &o2);
- void Raise_ParamTypeError(SQInteger nparam,SQInteger typemask,SQInteger type);
-
- void FindOuter(SQObjectPtr &target, SQObjectPtr *stackindex);
- void RelocateOuters();
- void CloseOuters(SQObjectPtr *stackindex);
-
- bool TypeOf(const SQObjectPtr &obj1, SQObjectPtr &dest);
- bool CallMetaMethod(SQObjectPtr &closure, SQMetaMethod mm, SQInteger nparams, SQObjectPtr &outres);
- bool ArithMetaMethod(SQInteger op, const SQObjectPtr &o1, const SQObjectPtr &o2, SQObjectPtr &dest);
- bool Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval);
- //new stuff
- _INLINE bool ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2);
- _INLINE bool BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2);
- _INLINE bool NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o1);
- _INLINE bool CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res);
- bool CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func);
- bool CLASS_OP(SQObjectPtr &target,SQInteger base,SQInteger attrs);
- //return true if the loop is finished
- bool FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr &o3,SQObjectPtr &o4,SQInteger arg_2,int exitpos,int &jump);
- //_INLINE bool LOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr);
- _INLINE bool PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr);
- _INLINE bool DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix,SQInteger arg0);
-#ifdef _DEBUG_DUMP
- void dumpstack(SQInteger stackbase=-1, bool dumpall = false);
-#endif
-
-#ifndef NO_GARBAGE_COLLECTOR
- void Mark(SQCollectable **chain);
- SQObjectType GetType() {return OT_THREAD;}
-#endif
- void Finalize();
- void GrowCallStack() {
- SQInteger newsize = _alloccallsstacksize*2;
- _callstackdata.resize(newsize);
- _callsstack = &_callstackdata[0];
- _alloccallsstacksize = newsize;
- }
- bool EnterFrame(SQInteger newbase, SQInteger newtop, bool tailcall);
- void LeaveFrame();
- void Release(){ sq_delete(this,SQVM); }
-////////////////////////////////////////////////////////////////////////////
- //stack functions for the api
- void Remove(SQInteger n);
-
- static bool IsFalse(SQObjectPtr &o);
-
- void Pop();
- void Pop(SQInteger n);
- void Push(const SQObjectPtr &o);
- void PushNull();
- SQObjectPtr &Top();
- SQObjectPtr &PopGet();
- SQObjectPtr &GetUp(SQInteger n);
- SQObjectPtr &GetAt(SQInteger n);
-
- SQObjectPtrVec _stack;
-
- SQInteger _top;
- SQInteger _stackbase;
- SQOuter *_openouters;
- SQObjectPtr _roottable;
- SQObjectPtr _lasterror;
- SQObjectPtr _errorhandler;
-
- bool _debughook;
- SQDEBUGHOOK _debughook_native;
- SQObjectPtr _debughook_closure;
-
- SQObjectPtr temp_reg;
-
-
- CallInfo* _callsstack;
- SQInteger _callsstacksize;
- SQInteger _alloccallsstacksize;
- sqvector<CallInfo> _callstackdata;
-
- ExceptionsTraps _etraps;
- CallInfo *ci;
- void *_foreignptr;
- //VMs sharing the same state
- SQSharedState *_sharedstate;
- SQInteger _nnativecalls;
- SQInteger _nmetamethodscall;
- //suspend infos
- SQBool _suspended;
- SQBool _suspended_root;
- SQInteger _suspended_target;
- SQInteger _suspended_traps;
-};
-
-struct AutoDec{
- AutoDec(SQInteger *n) { _n = n; }
- ~AutoDec() { (*_n)--; }
- SQInteger *_n;
-};
-
-inline SQObjectPtr &stack_get(HSQUIRRELVM v,SQInteger idx){return ((idx>=0)?(v->GetAt(idx+v->_stackbase-1)):(v->GetUp(idx)));}
-
-#define _ss(_vm_) (_vm_)->_sharedstate
-
-#ifndef NO_GARBAGE_COLLECTOR
-#define _opt_ss(_vm_) (_vm_)->_sharedstate
-#else
-#define _opt_ss(_vm_) NULL
-#endif
-
-#define PUSH_CALLINFO(v,nci){ \
- SQInteger css = v->_callsstacksize; \
- if(css == v->_alloccallsstacksize) { \
- v->GrowCallStack(); \
- } \
- v->ci = &v->_callsstack[css]; \
- *(v->ci) = nci; \
- v->_callsstacksize++; \
-}
-
-#define POP_CALLINFO(v){ \
- SQInteger css = --v->_callsstacksize; \
- v->ci->_closure.Null(); \
- v->ci = css?&v->_callsstack[css-1]:NULL; \
-}
-#endif //_SQVM_H_
+/* see copyright notice in squirrel.h */ +#ifndef _SQVM_H_ +#define _SQVM_H_ + +#include "sqopcodes.h" +#include "sqobject.h" +#define MAX_NATIVE_CALLS 100 +#define MIN_STACK_OVERHEAD 15 + +#define SQ_SUSPEND_FLAG -666 +#define DONT_FALL_BACK 666 +//base lib +void sq_base_register(HSQUIRRELVM v); + +struct SQExceptionTrap{ + SQExceptionTrap() {} + SQExceptionTrap(SQInteger ss, SQInteger stackbase,SQInstruction *ip, SQInteger ex_target){ _stacksize = ss; _stackbase = stackbase; _ip = ip; _extarget = ex_target;} + SQExceptionTrap(const SQExceptionTrap &et) { (*this) = et; } + SQInteger _stackbase; + SQInteger _stacksize; + SQInstruction *_ip; + SQInteger _extarget; +}; + +#define _INLINE + +#define STK(a) _stack._vals[_stackbase+(a)] +#define TARGET _stack._vals[_stackbase+arg0] + +typedef sqvector<SQExceptionTrap> ExceptionsTraps; + +struct SQVM : public CHAINABLE_OBJ +{ + struct CallInfo{ + //CallInfo() { _generator = NULL;} + SQInstruction *_ip; + SQObjectPtr *_literals; + SQObjectPtr _closure; + SQGenerator *_generator; + SQInt32 _etraps; + SQInt32 _prevstkbase; + SQInt32 _prevtop; + SQInt32 _target; + SQInt32 _ncalls; + SQBool _root; + }; + +typedef sqvector<CallInfo> CallInfoVec; +public: + void DebugHookProxy(SQInteger type, const SQChar * sourcename, SQInteger line, const SQChar * funcname); + static void _DebugHookProxy(HSQUIRRELVM v, SQInteger type, const SQChar * sourcename, SQInteger line, const SQChar * funcname); + enum ExecutionType { ET_CALL, ET_RESUME_GENERATOR, ET_RESUME_VM,ET_RESUME_THROW_VM }; + SQVM(SQSharedState *ss); + ~SQVM(); + bool Init(SQVM *friendvm, SQInteger stacksize); + bool Execute(SQObjectPtr &func, SQInteger nargs, SQInteger stackbase, SQObjectPtr &outres, SQBool raiseerror, ExecutionType et = ET_CALL); + //starts a native call return when the NATIVE closure returns + bool CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newbase, SQObjectPtr &retval,bool &suspend); + //starts a SQUIRREL call in the same "Execution loop" + bool StartCall(SQClosure *closure, SQInteger target, SQInteger nargs, SQInteger stackbase, bool tailcall); + bool CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor); + //call a generic closure pure SQUIRREL or NATIVE + bool Call(SQObjectPtr &closure, SQInteger nparams, SQInteger stackbase, SQObjectPtr &outres,SQBool raiseerror); + SQRESULT Suspend(); + + void CallDebugHook(SQInteger type,SQInteger forcedline=0); + void CallErrorHandler(SQObjectPtr &e); + bool Get(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &dest, bool raw, SQInteger selfidx); + SQInteger FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest); + bool InvokeDefaultDelegate(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest); + bool Set(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val, SQInteger selfidx); + SQInteger FallBackSet(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val); + bool NewSlot(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val,bool bstatic); + bool DeleteSlot(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &res); + bool Clone(const SQObjectPtr &self, SQObjectPtr &target); + bool ObjCmp(const SQObjectPtr &o1, const SQObjectPtr &o2,SQInteger &res); + bool StringCat(const SQObjectPtr &str, const SQObjectPtr &obj, SQObjectPtr &dest); + static bool IsEqual(const SQObjectPtr &o1,const SQObjectPtr &o2,bool &res); + bool ToString(const SQObjectPtr &o,SQObjectPtr &res); + SQString *PrintObjVal(const SQObjectPtr &o); + + + void Raise_Error(const SQChar *s, ...); + void Raise_Error(const SQObjectPtr &desc); + void Raise_IdxError(const SQObjectPtr &o); + void Raise_CompareError(const SQObject &o1, const SQObject &o2); + void Raise_ParamTypeError(SQInteger nparam,SQInteger typemask,SQInteger type); + + void FindOuter(SQObjectPtr &target, SQObjectPtr *stackindex); + void RelocateOuters(); + void CloseOuters(SQObjectPtr *stackindex); + + bool TypeOf(const SQObjectPtr &obj1, SQObjectPtr &dest); + bool CallMetaMethod(SQObjectPtr &closure, SQMetaMethod mm, SQInteger nparams, SQObjectPtr &outres); + bool ArithMetaMethod(SQInteger op, const SQObjectPtr &o1, const SQObjectPtr &o2, SQObjectPtr &dest); + bool Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval); + //new stuff + _INLINE bool ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2); + _INLINE bool BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2); + _INLINE bool NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o1); + _INLINE bool CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res); + bool CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func); + bool CLASS_OP(SQObjectPtr &target,SQInteger base,SQInteger attrs); + //return true if the loop is finished + bool FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr &o3,SQObjectPtr &o4,SQInteger arg_2,int exitpos,int &jump); + //_INLINE bool LOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr); + _INLINE bool PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr); + _INLINE bool DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix,SQInteger arg0); +#ifdef _DEBUG_DUMP + void dumpstack(SQInteger stackbase=-1, bool dumpall = false); +#endif + +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + SQObjectType GetType() {return OT_THREAD;} +#endif + void Finalize(); + void GrowCallStack() { + SQInteger newsize = _alloccallsstacksize*2; + _callstackdata.resize(newsize); + _callsstack = &_callstackdata[0]; + _alloccallsstacksize = newsize; + } + bool EnterFrame(SQInteger newbase, SQInteger newtop, bool tailcall); + void LeaveFrame(); + void Release(){ sq_delete(this,SQVM); } +//////////////////////////////////////////////////////////////////////////// + //stack functions for the api + void Remove(SQInteger n); + + static bool IsFalse(SQObjectPtr &o); + + void Pop(); + void Pop(SQInteger n); + void Push(const SQObjectPtr &o); + void PushNull(); + SQObjectPtr &Top(); + SQObjectPtr &PopGet(); + SQObjectPtr &GetUp(SQInteger n); + SQObjectPtr &GetAt(SQInteger n); + + SQObjectPtrVec _stack; + + SQInteger _top; + SQInteger _stackbase; + SQOuter *_openouters; + SQObjectPtr _roottable; + SQObjectPtr _lasterror; + SQObjectPtr _errorhandler; + + bool _debughook; + SQDEBUGHOOK _debughook_native; + SQObjectPtr _debughook_closure; + + SQObjectPtr temp_reg; + + + CallInfo* _callsstack; + SQInteger _callsstacksize; + SQInteger _alloccallsstacksize; + sqvector<CallInfo> _callstackdata; + + ExceptionsTraps _etraps; + CallInfo *ci; + void *_foreignptr; + //VMs sharing the same state + SQSharedState *_sharedstate; + SQInteger _nnativecalls; + SQInteger _nmetamethodscall; + //suspend infos + SQBool _suspended; + SQBool _suspended_root; + SQInteger _suspended_target; + SQInteger _suspended_traps; +}; + +struct AutoDec{ + AutoDec(SQInteger *n) { _n = n; } + ~AutoDec() { (*_n)--; } + SQInteger *_n; +}; + +inline SQObjectPtr &stack_get(HSQUIRRELVM v,SQInteger idx){return ((idx>=0)?(v->GetAt(idx+v->_stackbase-1)):(v->GetUp(idx)));} + +#define _ss(_vm_) (_vm_)->_sharedstate + +#ifndef NO_GARBAGE_COLLECTOR +#define _opt_ss(_vm_) (_vm_)->_sharedstate +#else +#define _opt_ss(_vm_) NULL +#endif + +#define PUSH_CALLINFO(v,nci){ \ + SQInteger css = v->_callsstacksize; \ + if(css == v->_alloccallsstacksize) { \ + v->GrowCallStack(); \ + } \ + v->ci = &v->_callsstack[css]; \ + *(v->ci) = nci; \ + v->_callsstacksize++; \ +} + +#define POP_CALLINFO(v){ \ + SQInteger css = --v->_callsstacksize; \ + v->ci->_closure.Null(); \ + v->ci = css?&v->_callsstack[css-1]:NULL; \ +} +#endif //_SQVM_H_ |