Back to home page

Enduro/X

 
 

    


0001 /*

0002     see copyright notice in pscript.h

0003 */
0004 #include "pspcheader.h"
0005 #include "psvm.h"
0006 #include "psstring.h"
0007 #include "pstable.h"
0008 #include "psarray.h"
0009 #include "psfuncproto.h"
0010 #include "psclosure.h"
0011 #include "psuserdata.h"
0012 #include "pscompiler.h"
0013 #include "psfuncstate.h"
0014 #include "psclass.h"
0015 
0016 static bool ps_aux_gettypedarg(HPSCRIPTVM v,PSInteger idx,PSObjectType type,PSObjectPtr **o)
0017 {
0018     *o = &stack_get(v,idx);
0019     if(type(**o) != type){
0020         PSObjectPtr oval = v->PrintObjVal(**o);
0021         v->Raise_Error(_SC("wrong argument type, expected '%s' got '%.50s'"),IdType2Name(type),_stringval(oval));
0022         return false;
0023     }
0024     return true;
0025 }
0026 
0027 #define _GETSAFE_OBJ(v,idx,type,o) { if(!ps_aux_gettypedarg(v,idx,type,&o)) return PS_ERROR; }
0028 
0029 #define ps_aux_paramscheck(v,count) \
0030 { \
0031     if(ps_gettop(v) < count){ v->Raise_Error(_SC("not enough params in the stack")); return PS_ERROR; }\
0032 }
0033 
0034 
0035 PSInteger ps_aux_invalidtype(HPSCRIPTVM v,PSObjectType type)
0036 {
0037     PSUnsignedInteger buf_size = 100 *sizeof(PSChar);
0038     scsprintf(_ss(v)->GetScratchPad(buf_size), buf_size, _SC("unexpected type %s"), IdType2Name(type));
0039     return ps_throwerror(v, _ss(v)->GetScratchPad(-1));
0040 }
0041 
0042 HPSCRIPTVM ps_open(PSInteger initialstacksize)
0043 {
0044     PSSharedState *ss;
0045     PSVM *v;
0046     ps_new(ss, PSSharedState);
0047     ss->Init();
0048     v = (PSVM *)PS_MALLOC(sizeof(PSVM));
0049     new (v) PSVM(ss);
0050     ss->_root_vm = v;
0051     if(v->Init(NULL, initialstacksize)) {
0052         return v;
0053     } else {
0054         ps_delete(v, PSVM);
0055         return NULL;
0056     }
0057     return v;
0058 }
0059 
0060 HPSCRIPTVM ps_newthread(HPSCRIPTVM friendvm, PSInteger initialstacksize)
0061 {
0062     PSSharedState *ss;
0063     PSVM *v;
0064     ss=_ss(friendvm);
0065 
0066     v= (PSVM *)PS_MALLOC(sizeof(PSVM));
0067     new (v) PSVM(ss);
0068 
0069     if(v->Init(friendvm, initialstacksize)) {
0070         friendvm->Push(v);
0071         return v;
0072     } else {
0073         ps_delete(v, PSVM);
0074         return NULL;
0075     }
0076 }
0077 
0078 PSInteger ps_getvmstate(HPSCRIPTVM v)
0079 {
0080     if(v->_suspended)
0081         return PS_VMSTATE_SUSPENDED;
0082     else {
0083         if(v->_callsstacksize != 0) return PS_VMSTATE_RUNNING;
0084         else return PS_VMSTATE_IDLE;
0085     }
0086 }
0087 
0088 void ps_seterrorhandler(HPSCRIPTVM v)
0089 {
0090     PSObject o = stack_get(v, -1);
0091     if(ps_isclosure(o) || ps_isnativeclosure(o) || ps_isnull(o)) {
0092         v->_errorhandler = o;
0093         v->Pop();
0094     }
0095 }
0096 
0097 void ps_setnativedebughook(HPSCRIPTVM v,PSDEBUGHOOK hook)
0098 {
0099     v->_debughook_native = hook;
0100     v->_debughook_closure.Null();
0101     v->_debughook = hook?true:false;
0102 }
0103 
0104 void ps_setdebughook(HPSCRIPTVM v)
0105 {
0106     PSObject o = stack_get(v,-1);
0107     if(ps_isclosure(o) || ps_isnativeclosure(o) || ps_isnull(o)) {
0108         v->_debughook_closure = o;
0109         v->_debughook_native = NULL;
0110         v->_debughook = !ps_isnull(o);
0111         v->Pop();
0112     }
0113 }
0114 
0115 void ps_close(HPSCRIPTVM v)
0116 {
0117     PSSharedState *ss = _ss(v);
0118     _thread(ss->_root_vm)->Finalize();
0119     ps_delete(ss, PSSharedState);
0120 }
0121 
0122 PSInteger ps_getversion()
0123 {
0124     return PSCRIPT_VERSION_NUMBER;
0125 }
0126 
0127 PSRESULT ps_compile(HPSCRIPTVM v,PSLEXREADFUNC read,PSUserPointer p,const PSChar *sourcename,PSBool raiseerror)
0128 {
0129     PSObjectPtr o;
0130 #ifndef NO_COMPILER
0131     if(Compile(v, read, p, sourcename, o, raiseerror?true:false, _ss(v)->_debuginfo)) {
0132         v->Push(PSClosure::Create(_ss(v), _funcproto(o), _table(v->_roottable)->GetWeakRef(OT_TABLE)));
0133         return PS_OK;
0134     }
0135     return PS_ERROR;
0136 #else
0137     return ps_throwerror(v,_SC("this is a no compiler build"));
0138 #endif
0139 }
0140 
0141 void ps_enabledebuginfo(HPSCRIPTVM v, PSBool enable)
0142 {
0143     _ss(v)->_debuginfo = enable?true:false;
0144 }
0145 
0146 void ps_notifyallexceptions(HPSCRIPTVM v, PSBool enable)
0147 {
0148     _ss(v)->_notifyallexceptions = enable?true:false;
0149 }
0150 
0151 void ps_addref(HPSCRIPTVM v,HPSOBJECT *po)
0152 {
0153     if(!ISREFCOUNTED(type(*po))) return;
0154 #ifdef NO_GARBAGE_COLLECTOR
0155     __AddRef(po->_type,po->_unVal);
0156 #else
0157     _ss(v)->_refs_table.AddRef(*po);
0158 #endif
0159 }
0160 
0161 PSUnsignedInteger ps_getrefcount(HPSCRIPTVM v,HPSOBJECT *po)
0162 {
0163     if(!ISREFCOUNTED(type(*po))) return 0;
0164 #ifdef NO_GARBAGE_COLLECTOR
0165    return po->_unVal.pRefCounted->_uiRef;
0166 #else
0167    return _ss(v)->_refs_table.GetRefCount(*po);
0168 #endif
0169 }
0170 
0171 PSBool ps_release(HPSCRIPTVM v,HPSOBJECT *po)
0172 {
0173     if(!ISREFCOUNTED(type(*po))) return PSTrue;
0174 #ifdef NO_GARBAGE_COLLECTOR
0175     bool ret = (po->_unVal.pRefCounted->_uiRef <= 1) ? PSTrue : PSFalse;
0176     __Release(po->_type,po->_unVal);
0177     return ret; //the ret val doesn't work(and cannot be fixed)

0178 #else
0179     return _ss(v)->_refs_table.Release(*po);
0180 #endif
0181 }
0182 
0183 PSUnsignedInteger ps_getvmrefcount(HPSCRIPTVM PS_UNUSED_ARG(v), const HPSOBJECT *po)
0184 {
0185     if (!ISREFCOUNTED(type(*po))) return 0;
0186     return po->_unVal.pRefCounted->_uiRef;
0187 }
0188 
0189 const PSChar *ps_objtostring(const HPSOBJECT *o)
0190 {
0191     if(ps_type(*o) == OT_STRING) {
0192         return _stringval(*o);
0193     }
0194     return NULL;
0195 }
0196 
0197 PSInteger ps_objtointeger(const HPSOBJECT *o)
0198 {
0199     if(ps_isnumeric(*o)) {
0200         return tointeger(*o);
0201     }
0202     return 0;
0203 }
0204 
0205 PSFloat ps_objtofloat(const HPSOBJECT *o)
0206 {
0207     if(ps_isnumeric(*o)) {
0208         return tofloat(*o);
0209     }
0210     return 0;
0211 }
0212 
0213 PSBool ps_objtobool(const HPSOBJECT *o)
0214 {
0215     if(ps_isbool(*o)) {
0216         return _integer(*o);
0217     }
0218     return PSFalse;
0219 }
0220 
0221 PSUserPointer ps_objtouserpointer(const HPSOBJECT *o)
0222 {
0223     if(ps_isuserpointer(*o)) {
0224         return _userpointer(*o);
0225     }
0226     return 0;
0227 }
0228 
0229 void ps_pushnull(HPSCRIPTVM v)
0230 {
0231     v->PushNull();
0232 }
0233 
0234 void ps_pushstring(HPSCRIPTVM v,const PSChar *s,PSInteger len)
0235 {
0236     if(s)
0237         v->Push(PSObjectPtr(PSString::Create(_ss(v), s, len)));
0238     else v->PushNull();
0239 }
0240 
0241 void ps_pushinteger(HPSCRIPTVM v,PSInteger n)
0242 {
0243     v->Push(n);
0244 }
0245 
0246 void ps_pushbool(HPSCRIPTVM v,PSBool b)
0247 {
0248     v->Push(b?true:false);
0249 }
0250 
0251 void ps_pushfloat(HPSCRIPTVM v,PSFloat n)
0252 {
0253     v->Push(n);
0254 }
0255 
0256 void ps_pushuserpointer(HPSCRIPTVM v,PSUserPointer p)
0257 {
0258     v->Push(p);
0259 }
0260 
0261 void ps_pushthread(HPSCRIPTVM v, HPSCRIPTVM thread)
0262 {
0263     v->Push(thread);
0264 }
0265 
0266 PSUserPointer ps_newuserdata(HPSCRIPTVM v,PSUnsignedInteger size)
0267 {
0268     PSUserData *ud = PSUserData::Create(_ss(v), size + PS_ALIGNMENT);
0269     v->Push(ud);
0270     return (PSUserPointer)ps_aligning(ud + 1);
0271 }
0272 
0273 void ps_newtable(HPSCRIPTVM v)
0274 {
0275     v->Push(PSTable::Create(_ss(v), 0));
0276 }
0277 
0278 void ps_newtableex(HPSCRIPTVM v,PSInteger initialcapacity)
0279 {
0280     v->Push(PSTable::Create(_ss(v), initialcapacity));
0281 }
0282 
0283 void ps_newarray(HPSCRIPTVM v,PSInteger size)
0284 {
0285     v->Push(PSArray::Create(_ss(v), size));
0286 }
0287 
0288 PSRESULT ps_newclass(HPSCRIPTVM v,PSBool hasbase)
0289 {
0290     PSClass *baseclass = NULL;
0291     if(hasbase) {
0292         PSObjectPtr &base = stack_get(v,-1);
0293         if(type(base) != OT_CLASS)
0294             return ps_throwerror(v,_SC("invalid base type"));
0295         baseclass = _class(base);
0296     }
0297     PSClass *newclass = PSClass::Create(_ss(v), baseclass);
0298     if(baseclass) v->Pop();
0299     v->Push(newclass);
0300     return PS_OK;
0301 }
0302 
0303 PSBool ps_instanceof(HPSCRIPTVM v)
0304 {
0305     PSObjectPtr &inst = stack_get(v,-1);
0306     PSObjectPtr &cl = stack_get(v,-2);
0307     if(type(inst) != OT_INSTANCE || type(cl) != OT_CLASS)
0308         return ps_throwerror(v,_SC("invalid param type"));
0309     return _instance(inst)->InstanceOf(_class(cl))?PSTrue:PSFalse;
0310 }
0311 
0312 PSRESULT ps_arrayappend(HPSCRIPTVM v,PSInteger idx)
0313 {
0314     ps_aux_paramscheck(v,2);
0315     PSObjectPtr *arr;
0316     _GETSAFE_OBJ(v, idx, OT_ARRAY,arr);
0317     _array(*arr)->Append(v->GetUp(-1));
0318     v->Pop();
0319     return PS_OK;
0320 }
0321 
0322 PSRESULT ps_arraypop(HPSCRIPTVM v,PSInteger idx,PSBool pushval)
0323 {
0324     ps_aux_paramscheck(v, 1);
0325     PSObjectPtr *arr;
0326     _GETSAFE_OBJ(v, idx, OT_ARRAY,arr);
0327     if(_array(*arr)->Size() > 0) {
0328         if(pushval != 0){ v->Push(_array(*arr)->Top()); }
0329         _array(*arr)->Pop();
0330         return PS_OK;
0331     }
0332     return ps_throwerror(v, _SC("empty array"));
0333 }
0334 
0335 PSRESULT ps_arrayresize(HPSCRIPTVM v,PSInteger idx,PSInteger newsize)
0336 {
0337     ps_aux_paramscheck(v,1);
0338     PSObjectPtr *arr;
0339     _GETSAFE_OBJ(v, idx, OT_ARRAY,arr);
0340     if(newsize >= 0) {
0341         _array(*arr)->Resize(newsize);
0342         return PS_OK;
0343     }
0344     return ps_throwerror(v,_SC("negative size"));
0345 }
0346 
0347 
0348 PSRESULT ps_arrayreverse(HPSCRIPTVM v,PSInteger idx)
0349 {
0350     ps_aux_paramscheck(v, 1);
0351     PSObjectPtr *o;
0352     _GETSAFE_OBJ(v, idx, OT_ARRAY,o);
0353     PSArray *arr = _array(*o);
0354     if(arr->Size() > 0) {
0355         PSObjectPtr t;
0356         PSInteger size = arr->Size();
0357         PSInteger n = size >> 1; size -= 1;
0358         for(PSInteger i = 0; i < n; i++) {
0359             t = arr->_values[i];
0360             arr->_values[i] = arr->_values[size-i];
0361             arr->_values[size-i] = t;
0362         }
0363         return PS_OK;
0364     }
0365     return PS_OK;
0366 }
0367 
0368 PSRESULT ps_arrayremove(HPSCRIPTVM v,PSInteger idx,PSInteger itemidx)
0369 {
0370     ps_aux_paramscheck(v, 1);
0371     PSObjectPtr *arr;
0372     _GETSAFE_OBJ(v, idx, OT_ARRAY,arr);
0373     return _array(*arr)->Remove(itemidx) ? PS_OK : ps_throwerror(v,_SC("index out of range"));
0374 }
0375 
0376 PSRESULT ps_arrayinsert(HPSCRIPTVM v,PSInteger idx,PSInteger destpos)
0377 {
0378     ps_aux_paramscheck(v, 1);
0379     PSObjectPtr *arr;
0380     _GETSAFE_OBJ(v, idx, OT_ARRAY,arr);
0381     PSRESULT ret = _array(*arr)->Insert(destpos, v->GetUp(-1)) ? PS_OK : ps_throwerror(v,_SC("index out of range"));
0382     v->Pop();
0383     return ret;
0384 }
0385 
0386 void ps_newclosure(HPSCRIPTVM v,PSFUNCTION func,PSUnsignedInteger nfreevars)
0387 {
0388     PSNativeClosure *nc = PSNativeClosure::Create(_ss(v), func,nfreevars);
0389     nc->_nparamscheck = 0;
0390     for(PSUnsignedInteger i = 0; i < nfreevars; i++) {
0391         nc->_outervalues[i] = v->Top();
0392         v->Pop();
0393     }
0394     v->Push(PSObjectPtr(nc));
0395 }
0396 
0397 PSRESULT ps_getclosureinfo(HPSCRIPTVM v,PSInteger idx,PSUnsignedInteger *nparams,PSUnsignedInteger *nfreevars)
0398 {
0399     PSObject o = stack_get(v, idx);
0400     if(type(o) == OT_CLOSURE) {
0401         PSClosure *c = _closure(o);
0402         PSFunctionProto *proto = c->_function;
0403         *nparams = (PSUnsignedInteger)proto->_nparameters;
0404         *nfreevars = (PSUnsignedInteger)proto->_noutervalues;
0405         return PS_OK;
0406     }
0407     else if(type(o) == OT_NATIVECLOSURE)
0408     {
0409         PSNativeClosure *c = _nativeclosure(o);
0410         *nparams = (PSUnsignedInteger)c->_nparamscheck;
0411         *nfreevars = c->_noutervalues;
0412         return PS_OK;
0413     }
0414     return ps_throwerror(v,_SC("the object is not a closure"));
0415 }
0416 
0417 PSRESULT ps_setnativeclosurename(HPSCRIPTVM v,PSInteger idx,const PSChar *name)
0418 {
0419     PSObject o = stack_get(v, idx);
0420     if(ps_isnativeclosure(o)) {
0421         PSNativeClosure *nc = _nativeclosure(o);
0422         nc->_name = PSString::Create(_ss(v),name);
0423         return PS_OK;
0424     }
0425     return ps_throwerror(v,_SC("the object is not a nativeclosure"));
0426 }
0427 
0428 PSRESULT ps_setparamscheck(HPSCRIPTVM v,PSInteger nparamscheck,const PSChar *typemask)
0429 {
0430     PSObject o = stack_get(v, -1);
0431     if(!ps_isnativeclosure(o))
0432         return ps_throwerror(v, _SC("native closure expected"));
0433     PSNativeClosure *nc = _nativeclosure(o);
0434     nc->_nparamscheck = nparamscheck;
0435     if(typemask) {
0436         PSIntVec res;
0437         if(!CompileTypemask(res, typemask))
0438             return ps_throwerror(v, _SC("invalid typemask"));
0439         nc->_typecheck.copy(res);
0440     }
0441     else {
0442         nc->_typecheck.resize(0);
0443     }
0444     if(nparamscheck == PS_MATCHTYPEMASKSTRING) {
0445         nc->_nparamscheck = nc->_typecheck.size();
0446     }
0447     return PS_OK;
0448 }
0449 
0450 PSRESULT ps_bindenv(HPSCRIPTVM v,PSInteger idx)
0451 {
0452     PSObjectPtr &o = stack_get(v,idx);
0453     if(!ps_isnativeclosure(o) &&
0454         !ps_isclosure(o))
0455         return ps_throwerror(v,_SC("the target is not a closure"));
0456     PSObjectPtr &env = stack_get(v,-1);
0457     if(!ps_istable(env) &&
0458         !ps_isarray(env) &&
0459         !ps_isclass(env) &&
0460         !ps_isinstance(env))
0461         return ps_throwerror(v,_SC("invalid environment"));
0462     PSWeakRef *w = _refcounted(env)->GetWeakRef(type(env));
0463     PSObjectPtr ret;
0464     if(ps_isclosure(o)) {
0465         PSClosure *c = _closure(o)->Clone();
0466         __ObjRelease(c->_env);
0467         c->_env = w;
0468         __ObjAddRef(c->_env);
0469         if(_closure(o)->_base) {
0470             c->_base = _closure(o)->_base;
0471             __ObjAddRef(c->_base);
0472         }
0473         ret = c;
0474     }
0475     else { //then must be a native closure

0476         PSNativeClosure *c = _nativeclosure(o)->Clone();
0477         __ObjRelease(c->_env);
0478         c->_env = w;
0479         __ObjAddRef(c->_env);
0480         ret = c;
0481     }
0482     v->Pop();
0483     v->Push(ret);
0484     return PS_OK;
0485 }
0486 
0487 PSRESULT ps_getclosurename(HPSCRIPTVM v,PSInteger idx)
0488 {
0489     PSObjectPtr &o = stack_get(v,idx);
0490     if(!ps_isnativeclosure(o) &&
0491         !ps_isclosure(o))
0492         return ps_throwerror(v,_SC("the target is not a closure"));
0493     if(ps_isnativeclosure(o))
0494     {
0495         v->Push(_nativeclosure(o)->_name);
0496     }
0497     else { //closure

0498         v->Push(_closure(o)->_function->_name);
0499     }
0500     return PS_OK;
0501 }
0502 
0503 PSRESULT ps_setclosureroot(HPSCRIPTVM v,PSInteger idx)
0504 {
0505     PSObjectPtr &c = stack_get(v,idx);
0506     PSObject o = stack_get(v, -1);
0507     if(!ps_isclosure(c)) return ps_throwerror(v, _SC("closure expected"));
0508     if(ps_istable(o)) {
0509         _closure(c)->SetRoot(_table(o)->GetWeakRef(OT_TABLE));
0510         v->Pop();
0511         return PS_OK;
0512     }
0513     return ps_throwerror(v, _SC("ivalid type"));
0514 }
0515 
0516 PSRESULT ps_getclosureroot(HPSCRIPTVM v,PSInteger idx)
0517 {
0518     PSObjectPtr &c = stack_get(v,idx);
0519     if(!ps_isclosure(c)) return ps_throwerror(v, _SC("closure expected"));
0520     v->Push(_closure(c)->_root->_obj);
0521     return PS_OK;
0522 }
0523 
0524 PSRESULT ps_clear(HPSCRIPTVM v,PSInteger idx)
0525 {
0526     PSObject &o=stack_get(v,idx);
0527     switch(type(o)) {
0528         case OT_TABLE: _table(o)->Clear();  break;
0529         case OT_ARRAY: _array(o)->Resize(0); break;
0530         default:
0531             return ps_throwerror(v, _SC("clear only works on table and array"));
0532         break;
0533 
0534     }
0535     return PS_OK;
0536 }
0537 
0538 void ps_pushroottable(HPSCRIPTVM v)
0539 {
0540     v->Push(v->_roottable);
0541 }
0542 
0543 void ps_pushregistrytable(HPSCRIPTVM v)
0544 {
0545     v->Push(_ss(v)->_registry);
0546 }
0547 
0548 void ps_pushconsttable(HPSCRIPTVM v)
0549 {
0550     v->Push(_ss(v)->_consts);
0551 }
0552 
0553 PSRESULT ps_setroottable(HPSCRIPTVM v)
0554 {
0555     PSObject o = stack_get(v, -1);
0556     if(ps_istable(o) || ps_isnull(o)) {
0557         v->_roottable = o;
0558         v->Pop();
0559         return PS_OK;
0560     }
0561     return ps_throwerror(v, _SC("ivalid type"));
0562 }
0563 
0564 PSRESULT ps_setconsttable(HPSCRIPTVM v)
0565 {
0566     PSObject o = stack_get(v, -1);
0567     if(ps_istable(o)) {
0568         _ss(v)->_consts = o;
0569         v->Pop();
0570         return PS_OK;
0571     }
0572     return ps_throwerror(v, _SC("ivalid type, expected table"));
0573 }
0574 
0575 void ps_setforeignptr(HPSCRIPTVM v,PSUserPointer p)
0576 {
0577     v->_foreignptr = p;
0578 }
0579 
0580 PSUserPointer ps_getforeignptr(HPSCRIPTVM v)
0581 {
0582     return v->_foreignptr;
0583 }
0584 
0585 void ps_setsharedforeignptr(HPSCRIPTVM v,PSUserPointer p)
0586 {
0587     _ss(v)->_foreignptr = p;
0588 }
0589 
0590 PSUserPointer ps_getsharedforeignptr(HPSCRIPTVM v)
0591 {
0592     return _ss(v)->_foreignptr;
0593 }
0594 
0595 void ps_setvmreleasehook(HPSCRIPTVM v,PSRELEASEHOOK hook)
0596 {
0597     v->_releasehook = hook;
0598 }
0599 
0600 PSRELEASEHOOK ps_getvmreleasehook(HPSCRIPTVM v)
0601 {
0602     return v->_releasehook;
0603 }
0604 
0605 void ps_setsharedreleasehook(HPSCRIPTVM v,PSRELEASEHOOK hook)
0606 {
0607     _ss(v)->_releasehook = hook;
0608 }
0609 
0610 PSRELEASEHOOK ps_getsharedreleasehook(HPSCRIPTVM v)
0611 {
0612     return _ss(v)->_releasehook;
0613 }
0614 
0615 void ps_push(HPSCRIPTVM v,PSInteger idx)
0616 {
0617     v->Push(stack_get(v, idx));
0618 }
0619 
0620 PSObjectType ps_gettype(HPSCRIPTVM v,PSInteger idx)
0621 {
0622     return type(stack_get(v, idx));
0623 }
0624 
0625 PSRESULT ps_typeof(HPSCRIPTVM v,PSInteger idx)
0626 {
0627     PSObjectPtr &o = stack_get(v, idx);
0628     PSObjectPtr res;
0629     if(!v->TypeOf(o,res)) {
0630         return PS_ERROR;
0631     }
0632     v->Push(res);
0633     return PS_OK;
0634 }
0635 
0636 PSRESULT ps_tostring(HPSCRIPTVM v,PSInteger idx)
0637 {
0638     PSObjectPtr &o = stack_get(v, idx);
0639     PSObjectPtr res;
0640     if(!v->ToString(o,res)) {
0641         return PS_ERROR;
0642     }
0643     v->Push(res);
0644     return PS_OK;
0645 }
0646 
0647 void ps_tobool(HPSCRIPTVM v, PSInteger idx, PSBool *b)
0648 {
0649     PSObjectPtr &o = stack_get(v, idx);
0650     *b = PSVM::IsFalse(o)?PSFalse:PSTrue;
0651 }
0652 
0653 PSRESULT ps_getinteger(HPSCRIPTVM v,PSInteger idx,PSInteger *i)
0654 {
0655     PSObjectPtr &o = stack_get(v, idx);
0656     if(ps_isnumeric(o)) {
0657         *i = tointeger(o);
0658         return PS_OK;
0659     }
0660     return PS_ERROR;
0661 }
0662 
0663 PSRESULT ps_getfloat(HPSCRIPTVM v,PSInteger idx,PSFloat *f)
0664 {
0665     PSObjectPtr &o = stack_get(v, idx);
0666     if(ps_isnumeric(o)) {
0667         *f = tofloat(o);
0668         return PS_OK;
0669     }
0670     return PS_ERROR;
0671 }
0672 
0673 PSRESULT ps_getbool(HPSCRIPTVM v,PSInteger idx,PSBool *b)
0674 {
0675     PSObjectPtr &o = stack_get(v, idx);
0676     if(ps_isbool(o)) {
0677         *b = _integer(o);
0678         return PS_OK;
0679     }
0680     return PS_ERROR;
0681 }
0682 
0683 PSRESULT ps_getstring(HPSCRIPTVM v,PSInteger idx,const PSChar **c)
0684 {
0685     PSObjectPtr *o = NULL;
0686     _GETSAFE_OBJ(v, idx, OT_STRING,o);
0687     *c = _stringval(*o);
0688     return PS_OK;
0689 }
0690 
0691 PSRESULT ps_getthread(HPSCRIPTVM v,PSInteger idx,HPSCRIPTVM *thread)
0692 {
0693     PSObjectPtr *o = NULL;
0694     _GETSAFE_OBJ(v, idx, OT_THREAD,o);
0695     *thread = _thread(*o);
0696     return PS_OK;
0697 }
0698 
0699 PSRESULT ps_clone(HPSCRIPTVM v,PSInteger idx)
0700 {
0701     PSObjectPtr &o = stack_get(v,idx);
0702     v->PushNull();
0703     if(!v->Clone(o, stack_get(v, -1))){
0704         v->Pop();
0705         return PS_ERROR;
0706     }
0707     return PS_OK;
0708 }
0709 
0710 PSInteger ps_getsize(HPSCRIPTVM v, PSInteger idx)
0711 {
0712     PSObjectPtr &o = stack_get(v, idx);
0713     PSObjectType type = type(o);
0714     switch(type) {
0715     case OT_STRING:     return _string(o)->_len;
0716     case OT_TABLE:      return _table(o)->CountUsed();
0717     case OT_ARRAY:      return _array(o)->Size();
0718     case OT_USERDATA:   return _userdata(o)->_size;
0719     case OT_INSTANCE:   return _instance(o)->_class->_udsize;
0720     case OT_CLASS:      return _class(o)->_udsize;
0721     default:
0722         return ps_aux_invalidtype(v, type);
0723     }
0724 }
0725 
0726 PSHash ps_gethash(HPSCRIPTVM v, PSInteger idx)
0727 {
0728     PSObjectPtr &o = stack_get(v, idx);
0729     return HashObj(o);
0730 }
0731 
0732 PSRESULT ps_getuserdata(HPSCRIPTVM v,PSInteger idx,PSUserPointer *p,PSUserPointer *typetag)
0733 {
0734     PSObjectPtr *o = NULL;
0735     _GETSAFE_OBJ(v, idx, OT_USERDATA,o);
0736     (*p) = _userdataval(*o);
0737     if(typetag) *typetag = _userdata(*o)->_typetag;
0738     return PS_OK;
0739 }
0740 
0741 PSRESULT ps_settypetag(HPSCRIPTVM v,PSInteger idx,PSUserPointer typetag)
0742 {
0743     PSObjectPtr &o = stack_get(v,idx);
0744     switch(type(o)) {
0745         case OT_USERDATA:   _userdata(o)->_typetag = typetag;   break;
0746         case OT_CLASS:      _class(o)->_typetag = typetag;      break;
0747         default:            return ps_throwerror(v,_SC("invalid object type"));
0748     }
0749     return PS_OK;
0750 }
0751 
0752 PSRESULT ps_getobjtypetag(const HPSOBJECT *o,PSUserPointer * typetag)
0753 {
0754   switch(type(*o)) {
0755     case OT_INSTANCE: *typetag = _instance(*o)->_class->_typetag; break;
0756     case OT_USERDATA: *typetag = _userdata(*o)->_typetag; break;
0757     case OT_CLASS:    *typetag = _class(*o)->_typetag; break;
0758     default: return PS_ERROR;
0759   }
0760   return PS_OK;
0761 }
0762 
0763 PSRESULT ps_gettypetag(HPSCRIPTVM v,PSInteger idx,PSUserPointer *typetag)
0764 {
0765     PSObjectPtr &o = stack_get(v,idx);
0766     if(PS_FAILED(ps_getobjtypetag(&o,typetag)))
0767         return ps_throwerror(v,_SC("invalid object type"));
0768     return PS_OK;
0769 }
0770 
0771 PSRESULT ps_getuserpointer(HPSCRIPTVM v, PSInteger idx, PSUserPointer *p)
0772 {
0773     PSObjectPtr *o = NULL;
0774     _GETSAFE_OBJ(v, idx, OT_USERPOINTER,o);
0775     (*p) = _userpointer(*o);
0776     return PS_OK;
0777 }
0778 
0779 PSRESULT ps_setinstanceup(HPSCRIPTVM v, PSInteger idx, PSUserPointer p)
0780 {
0781     PSObjectPtr &o = stack_get(v,idx);
0782     if(type(o) != OT_INSTANCE) return ps_throwerror(v,_SC("the object is not a class instance"));
0783     _instance(o)->_userpointer = p;
0784     return PS_OK;
0785 }
0786 
0787 PSRESULT ps_setclassudsize(HPSCRIPTVM v, PSInteger idx, PSInteger udsize)
0788 {
0789     PSObjectPtr &o = stack_get(v,idx);
0790     if(type(o) != OT_CLASS) return ps_throwerror(v,_SC("the object is not a class"));
0791     if(_class(o)->_locked) return ps_throwerror(v,_SC("the class is locked"));
0792     _class(o)->_udsize = udsize;
0793     return PS_OK;
0794 }
0795 
0796 
0797 PSRESULT ps_getinstanceup(HPSCRIPTVM v, PSInteger idx, PSUserPointer *p,PSUserPointer typetag)
0798 {
0799     PSObjectPtr &o = stack_get(v,idx);
0800     if(type(o) != OT_INSTANCE) return ps_throwerror(v,_SC("the object is not a class instance"));
0801     (*p) = _instance(o)->_userpointer;
0802     if(typetag != 0) {
0803         PSClass *cl = _instance(o)->_class;
0804         do{
0805             if(cl->_typetag == typetag)
0806                 return PS_OK;
0807             cl = cl->_base;
0808         }while(cl != NULL);
0809         return ps_throwerror(v,_SC("invalid type tag"));
0810     }
0811     return PS_OK;
0812 }
0813 
0814 PSInteger ps_gettop(HPSCRIPTVM v)
0815 {
0816     return (v->_top) - v->_stackbase;
0817 }
0818 
0819 void ps_settop(HPSCRIPTVM v, PSInteger newtop)
0820 {
0821     PSInteger top = ps_gettop(v);
0822     if(top > newtop)
0823         ps_pop(v, top - newtop);
0824     else
0825         while(top++ < newtop) ps_pushnull(v);
0826 }
0827 
0828 void ps_pop(HPSCRIPTVM v, PSInteger nelemstopop)
0829 {
0830     assert(v->_top >= nelemstopop);
0831     v->Pop(nelemstopop);
0832 }
0833 
0834 void ps_poptop(HPSCRIPTVM v)
0835 {
0836     assert(v->_top >= 1);
0837     v->Pop();
0838 }
0839 
0840 
0841 void ps_remove(HPSCRIPTVM v, PSInteger idx)
0842 {
0843     v->Remove(idx);
0844 }
0845 
0846 PSInteger ps_cmp(HPSCRIPTVM v)
0847 {
0848     PSInteger res;
0849     v->ObjCmp(stack_get(v, -1), stack_get(v, -2),res);
0850     return res;
0851 }
0852 
0853 PSRESULT ps_newslot(HPSCRIPTVM v, PSInteger idx, PSBool bstatic)
0854 {
0855     ps_aux_paramscheck(v, 3);
0856     PSObjectPtr &self = stack_get(v, idx);
0857     if(type(self) == OT_TABLE || type(self) == OT_CLASS) {
0858         PSObjectPtr &key = v->GetUp(-2);
0859         if(type(key) == OT_NULL) return ps_throwerror(v, _SC("null is not a valid key"));
0860         v->NewSlot(self, key, v->GetUp(-1),bstatic?true:false);
0861         v->Pop(2);
0862     }
0863     return PS_OK;
0864 }
0865 
0866 PSRESULT ps_deleteslot(HPSCRIPTVM v,PSInteger idx,PSBool pushval)
0867 {
0868     ps_aux_paramscheck(v, 2);
0869     PSObjectPtr *self;
0870     _GETSAFE_OBJ(v, idx, OT_TABLE,self);
0871     PSObjectPtr &key = v->GetUp(-1);
0872     if(type(key) == OT_NULL) return ps_throwerror(v, _SC("null is not a valid key"));
0873     PSObjectPtr res;
0874     if(!v->DeleteSlot(*self, key, res)){
0875         v->Pop();
0876         return PS_ERROR;
0877     }
0878     if(pushval) v->GetUp(-1) = res;
0879     else v->Pop();
0880     return PS_OK;
0881 }
0882 
0883 PSRESULT ps_set(HPSCRIPTVM v,PSInteger idx)
0884 {
0885     PSObjectPtr &self = stack_get(v, idx);
0886     if(v->Set(self, v->GetUp(-2), v->GetUp(-1),DONT_FALL_BACK)) {
0887         v->Pop(2);
0888         return PS_OK;
0889     }
0890     return PS_ERROR;
0891 }
0892 
0893 PSRESULT ps_rawset(HPSCRIPTVM v,PSInteger idx)
0894 {
0895     PSObjectPtr &self = stack_get(v, idx);
0896     PSObjectPtr &key = v->GetUp(-2);
0897     if(type(key) == OT_NULL) {
0898         v->Pop(2);
0899         return ps_throwerror(v, _SC("null key"));
0900     }
0901     switch(type(self)) {
0902     case OT_TABLE:
0903         _table(self)->NewSlot(key, v->GetUp(-1));
0904         v->Pop(2);
0905         return PS_OK;
0906     break;
0907     case OT_CLASS:
0908         _class(self)->NewSlot(_ss(v), key, v->GetUp(-1),false);
0909         v->Pop(2);
0910         return PS_OK;
0911     break;
0912     case OT_INSTANCE:
0913         if(_instance(self)->Set(key, v->GetUp(-1))) {
0914             v->Pop(2);
0915             return PS_OK;
0916         }
0917     break;
0918     case OT_ARRAY:
0919         if(v->Set(self, key, v->GetUp(-1),false)) {
0920             v->Pop(2);
0921             return PS_OK;
0922         }
0923     break;
0924     default:
0925         v->Pop(2);
0926         return ps_throwerror(v, _SC("rawset works only on array/table/class and instance"));
0927     }
0928     v->Raise_IdxError(v->GetUp(-2));return PS_ERROR;
0929 }
0930 
0931 PSRESULT ps_newmember(HPSCRIPTVM v,PSInteger idx,PSBool bstatic)
0932 {
0933     PSObjectPtr &self = stack_get(v, idx);
0934     if(type(self) != OT_CLASS) return ps_throwerror(v, _SC("new member only works with classes"));
0935     PSObjectPtr &key = v->GetUp(-3);
0936     if(type(key) == OT_NULL) return ps_throwerror(v, _SC("null key"));
0937     if(!v->NewSlotA(self,key,v->GetUp(-2),v->GetUp(-1),bstatic?true:false,false))
0938         return PS_ERROR;
0939     return PS_OK;
0940 }
0941 
0942 PSRESULT ps_rawnewmember(HPSCRIPTVM v,PSInteger idx,PSBool bstatic)
0943 {
0944     PSObjectPtr &self = stack_get(v, idx);
0945     if(type(self) != OT_CLASS) return ps_throwerror(v, _SC("new member only works with classes"));
0946     PSObjectPtr &key = v->GetUp(-3);
0947     if(type(key) == OT_NULL) return ps_throwerror(v, _SC("null key"));
0948     if(!v->NewSlotA(self,key,v->GetUp(-2),v->GetUp(-1),bstatic?true:false,true))
0949         return PS_ERROR;
0950     return PS_OK;
0951 }
0952 
0953 PSRESULT ps_setdelegate(HPSCRIPTVM v,PSInteger idx)
0954 {
0955     PSObjectPtr &self = stack_get(v, idx);
0956     PSObjectPtr &mt = v->GetUp(-1);
0957     PSObjectType type = type(self);
0958     switch(type) {
0959     case OT_TABLE:
0960         if(type(mt) == OT_TABLE) {
0961             if(!_table(self)->SetDelegate(_table(mt))) return ps_throwerror(v, _SC("delagate cycle")); v->Pop();}
0962         else if(type(mt)==OT_NULL) {
0963             _table(self)->SetDelegate(NULL); v->Pop(); }
0964         else return ps_aux_invalidtype(v,type);
0965         break;
0966     case OT_USERDATA:
0967         if(type(mt)==OT_TABLE) {
0968             _userdata(self)->SetDelegate(_table(mt)); v->Pop(); }
0969         else if(type(mt)==OT_NULL) {
0970             _userdata(self)->SetDelegate(NULL); v->Pop(); }
0971         else return ps_aux_invalidtype(v, type);
0972         break;
0973     default:
0974             return ps_aux_invalidtype(v, type);
0975         break;
0976     }
0977     return PS_OK;
0978 }
0979 
0980 PSRESULT ps_rawdeleteslot(HPSCRIPTVM v,PSInteger idx,PSBool pushval)
0981 {
0982     ps_aux_paramscheck(v, 2);
0983     PSObjectPtr *self;
0984     _GETSAFE_OBJ(v, idx, OT_TABLE,self);
0985     PSObjectPtr &key = v->GetUp(-1);
0986     PSObjectPtr t;
0987     if(_table(*self)->Get(key,t)) {
0988         _table(*self)->Remove(key);
0989     }
0990     if(pushval != 0)
0991         v->GetUp(-1) = t;
0992     else
0993         v->Pop();
0994     return PS_OK;
0995 }
0996 
0997 PSRESULT ps_getdelegate(HPSCRIPTVM v,PSInteger idx)
0998 {
0999     PSObjectPtr &self=stack_get(v,idx);
1000     switch(type(self)){
1001     case OT_TABLE:
1002     case OT_USERDATA:
1003         if(!_delegable(self)->_delegate){
1004             v->PushNull();
1005             break;
1006         }
1007         v->Push(PSObjectPtr(_delegable(self)->_delegate));
1008         break;
1009     default: return ps_throwerror(v,_SC("wrong type")); break;
1010     }
1011     return PS_OK;
1012 
1013 }
1014 
1015 PSRESULT ps_get(HPSCRIPTVM v,PSInteger idx)
1016 {
1017     PSObjectPtr &self=stack_get(v,idx);
1018     PSObjectPtr &obj = v->GetUp(-1);
1019     if(v->Get(self,obj,obj,false,DONT_FALL_BACK))
1020         return PS_OK;
1021     v->Pop();
1022     return PS_ERROR;
1023 }
1024 
1025 PSRESULT ps_rawget(HPSCRIPTVM v,PSInteger idx)
1026 {
1027     PSObjectPtr &self=stack_get(v,idx);
1028     PSObjectPtr &obj = v->GetUp(-1);
1029     switch(type(self)) {
1030     case OT_TABLE:
1031         if(_table(self)->Get(obj,obj))
1032             return PS_OK;
1033         break;
1034     case OT_CLASS:
1035         if(_class(self)->Get(obj,obj))
1036             return PS_OK;
1037         break;
1038     case OT_INSTANCE:
1039         if(_instance(self)->Get(obj,obj))
1040             return PS_OK;
1041         break;
1042     case OT_ARRAY:{
1043         if(ps_isnumeric(obj)){
1044             if(_array(self)->Get(tointeger(obj),obj)) {
1045                 return PS_OK;
1046             }
1047         }
1048         else {
1049             v->Pop();
1050             return ps_throwerror(v,_SC("invalid index type for an array"));
1051         }
1052                   }
1053         break;
1054     default:
1055         v->Pop();
1056         return ps_throwerror(v,_SC("rawget works only on array/table/instance and class"));
1057     }
1058     v->Pop();
1059     return ps_throwerror(v,_SC("the index doesn't exist"));
1060 }
1061 
1062 PSRESULT ps_getstackobj(HPSCRIPTVM v,PSInteger idx,HPSOBJECT *po)
1063 {
1064     *po=stack_get(v,idx);
1065     return PS_OK;
1066 }
1067 
1068 const PSChar *ps_getlocal(HPSCRIPTVM v,PSUnsignedInteger level,PSUnsignedInteger idx)
1069 {
1070     PSUnsignedInteger cstksize=v->_callsstacksize;
1071     PSUnsignedInteger lvl=(cstksize-level)-1;
1072     PSInteger stackbase=v->_stackbase;
1073     if(lvl<cstksize){
1074         for(PSUnsignedInteger i=0;i<level;i++){
1075             PSVM::CallInfo &ci=v->_callsstack[(cstksize-i)-1];
1076             stackbase-=ci._prevstkbase;
1077         }
1078         PSVM::CallInfo &ci=v->_callsstack[lvl];
1079         if(type(ci._closure)!=OT_CLOSURE)
1080             return NULL;
1081         PSClosure *c=_closure(ci._closure);
1082         PSFunctionProto *func=c->_function;
1083         if(func->_noutervalues > (PSInteger)idx) {
1084             v->Push(*_outer(c->_outervalues[idx])->_valptr);
1085             return _stringval(func->_outervalues[idx]._name);
1086         }
1087         idx -= func->_noutervalues;
1088         return func->GetLocal(v,stackbase,idx,(PSInteger)(ci._ip-func->_instructions)-1);
1089     }
1090     return NULL;
1091 }
1092 
1093 void ps_pushobject(HPSCRIPTVM v,HPSOBJECT obj)
1094 {
1095     v->Push(PSObjectPtr(obj));
1096 }
1097 
1098 void ps_resetobject(HPSOBJECT *po)
1099 {
1100     po->_unVal.pUserPointer=NULL;po->_type=OT_NULL;
1101 }
1102 
1103 PSRESULT ps_throwerror(HPSCRIPTVM v,const PSChar *err)
1104 {
1105     v->_lasterror=PSString::Create(_ss(v),err);
1106     return PS_ERROR;
1107 }
1108 
1109 PSRESULT ps_throwobject(HPSCRIPTVM v)
1110 {
1111     v->_lasterror = v->GetUp(-1);
1112     v->Pop();
1113     return PS_ERROR;
1114 }
1115 
1116 
1117 void ps_reseterror(HPSCRIPTVM v)
1118 {
1119     v->_lasterror.Null();
1120 }
1121 
1122 void ps_getlasterror(HPSCRIPTVM v)
1123 {
1124     v->Push(v->_lasterror);
1125 }
1126 
1127 PSRESULT ps_reservestack(HPSCRIPTVM v,PSInteger nsize)
1128 {
1129     if (((PSUnsignedInteger)v->_top + nsize) > v->_stack.size()) {
1130         if(v->_nmetamethodscall) {
1131             return ps_throwerror(v,_SC("cannot resize stack while in  a metamethod"));
1132         }
1133         v->_stack.resize(v->_stack.size() + ((v->_top + nsize) - v->_stack.size()));
1134     }
1135     return PS_OK;
1136 }
1137 
1138 PSRESULT ps_resume(HPSCRIPTVM v,PSBool retval,PSBool raiseerror)
1139 {
1140     if (type(v->GetUp(-1)) == OT_GENERATOR)
1141     {
1142         v->PushNull(); //retval

1143         if (!v->Execute(v->GetUp(-2), 0, v->_top, v->GetUp(-1), raiseerror, PSVM::ET_RESUME_GENERATOR))
1144         {v->Raise_Error(v->_lasterror); return PS_ERROR;}
1145         if(!retval)
1146             v->Pop();
1147         return PS_OK;
1148     }
1149     return ps_throwerror(v,_SC("only generators can be resumed"));
1150 }
1151 
1152 PSRESULT ps_call(HPSCRIPTVM v,PSInteger params,PSBool retval,PSBool raiseerror)
1153 {
1154     PSObjectPtr res;
1155     if(v->Call(v->GetUp(-(params+1)),params,v->_top-params,res,raiseerror?true:false)){
1156 
1157         if(!v->_suspended) {
1158             v->Pop(params);//pop closure and args

1159         }
1160         if(retval){
1161             v->Push(res); return PS_OK;
1162         }
1163         return PS_OK;
1164     }
1165     else {
1166         v->Pop(params);
1167         return PS_ERROR;
1168     }
1169     if(!v->_suspended)
1170         v->Pop(params);
1171     return ps_throwerror(v,_SC("call failed"));
1172 }
1173 
1174 PSRESULT ps_suspendvm(HPSCRIPTVM v)
1175 {
1176     return v->Suspend();
1177 }
1178 
1179 PSRESULT ps_wakeupvm(HPSCRIPTVM v,PSBool wakeupret,PSBool retval,PSBool raiseerror,PSBool throwerror)
1180 {
1181     PSObjectPtr ret;
1182     if(!v->_suspended)
1183         return ps_throwerror(v,_SC("cannot resume a vm that is not running any code"));
1184     PSInteger target = v->_suspended_target;
1185     if(wakeupret) {
1186         if(target != -1) {
1187             v->GetAt(v->_stackbase+v->_suspended_target)=v->GetUp(-1); //retval

1188         }
1189         v->Pop();
1190     } else if(target != -1) { v->GetAt(v->_stackbase+v->_suspended_target).Null(); }
1191     PSObjectPtr dummy;
1192     if(!v->Execute(dummy,-1,-1,ret,raiseerror,throwerror?PSVM::ET_RESUME_THROW_VM : PSVM::ET_RESUME_VM)) {
1193         return PS_ERROR;
1194     }
1195     if(retval)
1196         v->Push(ret);
1197     return PS_OK;
1198 }
1199 
1200 void ps_setreleasehook(HPSCRIPTVM v,PSInteger idx,PSRELEASEHOOK hook)
1201 {
1202     if(ps_gettop(v) >= 1){
1203         PSObjectPtr &ud=stack_get(v,idx);
1204         switch( type(ud) ) {
1205         case OT_USERDATA:   _userdata(ud)->_hook = hook;    break;
1206         case OT_INSTANCE:   _instance(ud)->_hook = hook;    break;
1207         case OT_CLASS:      _class(ud)->_hook = hook;       break;
1208         default: break; //shutup compiler

1209         }
1210     }
1211 }
1212 
1213 PSRELEASEHOOK ps_getreleasehook(HPSCRIPTVM v,PSInteger idx)
1214 {
1215     if(ps_gettop(v) >= 1){
1216         PSObjectPtr &ud=stack_get(v,idx);
1217         switch( type(ud) ) {
1218         case OT_USERDATA:   return _userdata(ud)->_hook;    break;
1219         case OT_INSTANCE:   return _instance(ud)->_hook;    break;
1220         case OT_CLASS:      return _class(ud)->_hook;       break;
1221         default: break; //shutup compiler

1222         }
1223     }
1224     return NULL;
1225 }
1226 
1227 void ps_setcompilererrorhandler(HPSCRIPTVM v,PSCOMPILERERROR f)
1228 {
1229     _ss(v)->_compilererrorhandler = f;
1230 }
1231 
1232 PSRESULT ps_writeclosure(HPSCRIPTVM v,PSWRITEFUNC w,PSUserPointer up)
1233 {
1234     PSObjectPtr *o = NULL;
1235     _GETSAFE_OBJ(v, -1, OT_CLOSURE,o);
1236     unsigned short tag = PS_BYTECODE_STREAM_TAG;
1237     if(_closure(*o)->_function->_noutervalues)
1238         return ps_throwerror(v,_SC("a closure with free valiables bound it cannot be serialized"));
1239     if(w(up,&tag,2) != 2)
1240         return ps_throwerror(v,_SC("io error"));
1241     if(!_closure(*o)->Save(v,up,w))
1242         return PS_ERROR;
1243     return PS_OK;
1244 }
1245 
1246 PSRESULT ps_readclosure(HPSCRIPTVM v,PSREADFUNC r,PSUserPointer up)
1247 {
1248     PSObjectPtr closure;
1249 
1250     unsigned short tag;
1251     if(r(up,&tag,2) != 2)
1252         return ps_throwerror(v,_SC("io error"));
1253     if(tag != PS_BYTECODE_STREAM_TAG)
1254         return ps_throwerror(v,_SC("invalid stream"));
1255     if(!PSClosure::Load(v,up,r,closure))
1256         return PS_ERROR;
1257     v->Push(closure);
1258     return PS_OK;
1259 }
1260 
1261 PSChar *ps_getscratchpad(HPSCRIPTVM v,PSInteger minsize)
1262 {
1263     return _ss(v)->GetScratchPad(minsize);
1264 }
1265 
1266 PSRESULT ps_resurrectunreachable(HPSCRIPTVM v)
1267 {
1268 #ifndef NO_GARBAGE_COLLECTOR
1269     _ss(v)->ResurrectUnreachable(v);
1270     return PS_OK;
1271 #else
1272     return ps_throwerror(v,_SC("ps_resurrectunreachable requires a garbage collector build"));
1273 #endif
1274 }
1275 
1276 PSInteger ps_collectgarbage(HPSCRIPTVM v)
1277 {
1278 #ifndef NO_GARBAGE_COLLECTOR
1279     return _ss(v)->CollectGarbage(v);
1280 #else
1281     return -1;
1282 #endif
1283 }
1284 
1285 PSRESULT ps_getcallee(HPSCRIPTVM v)
1286 {
1287     if(v->_callsstacksize > 1)
1288     {
1289         v->Push(v->_callsstack[v->_callsstacksize - 2]._closure);
1290         return PS_OK;
1291     }
1292     return ps_throwerror(v,_SC("no closure in the calls stack"));
1293 }
1294 
1295 const PSChar *ps_getfreevariable(HPSCRIPTVM v,PSInteger idx,PSUnsignedInteger nval)
1296 {
1297     PSObjectPtr &self=stack_get(v,idx);
1298     const PSChar *name = NULL;
1299     switch(type(self))
1300     {
1301     case OT_CLOSURE:{
1302         PSClosure *clo = _closure(self);
1303         PSFunctionProto *fp = clo->_function;
1304         if(((PSUnsignedInteger)fp->_noutervalues) > nval) {
1305             v->Push(*(_outer(clo->_outervalues[nval])->_valptr));
1306             PSOuterVar &ov = fp->_outervalues[nval];
1307             name = _stringval(ov._name);
1308         }
1309                     }
1310         break;
1311     case OT_NATIVECLOSURE:{
1312         PSNativeClosure *clo = _nativeclosure(self);
1313         if(clo->_noutervalues > nval) {
1314             v->Push(clo->_outervalues[nval]);
1315             name = _SC("@NATIVE");
1316         }
1317                           }
1318         break;
1319     default: break; //shutup compiler

1320     }
1321     return name;
1322 }
1323 
1324 PSRESULT ps_setfreevariable(HPSCRIPTVM v,PSInteger idx,PSUnsignedInteger nval)
1325 {
1326     PSObjectPtr &self=stack_get(v,idx);
1327     switch(type(self))
1328     {
1329     case OT_CLOSURE:{
1330         PSFunctionProto *fp = _closure(self)->_function;
1331         if(((PSUnsignedInteger)fp->_noutervalues) > nval){
1332             *(_outer(_closure(self)->_outervalues[nval])->_valptr) = stack_get(v,-1);
1333         }
1334         else return ps_throwerror(v,_SC("invalid free var index"));
1335                     }
1336         break;
1337     case OT_NATIVECLOSURE:
1338         if(_nativeclosure(self)->_noutervalues > nval){
1339             _nativeclosure(self)->_outervalues[nval] = stack_get(v,-1);
1340         }
1341         else return ps_throwerror(v,_SC("invalid free var index"));
1342         break;
1343     default:
1344         return ps_aux_invalidtype(v,type(self));
1345     }
1346     v->Pop();
1347     return PS_OK;
1348 }
1349 
1350 PSRESULT ps_setattributes(HPSCRIPTVM v,PSInteger idx)
1351 {
1352     PSObjectPtr *o = NULL;
1353     _GETSAFE_OBJ(v, idx, OT_CLASS,o);
1354     PSObjectPtr &key = stack_get(v,-2);
1355     PSObjectPtr &val = stack_get(v,-1);
1356     PSObjectPtr attrs;
1357     if(type(key) == OT_NULL) {
1358         attrs = _class(*o)->_attributes;
1359         _class(*o)->_attributes = val;
1360         v->Pop(2);
1361         v->Push(attrs);
1362         return PS_OK;
1363     }else if(_class(*o)->GetAttributes(key,attrs)) {
1364         _class(*o)->SetAttributes(key,val);
1365         v->Pop(2);
1366         v->Push(attrs);
1367         return PS_OK;
1368     }
1369     return ps_throwerror(v,_SC("wrong index"));
1370 }
1371 
1372 PSRESULT ps_getattributes(HPSCRIPTVM v,PSInteger idx)
1373 {
1374     PSObjectPtr *o = NULL;
1375     _GETSAFE_OBJ(v, idx, OT_CLASS,o);
1376     PSObjectPtr &key = stack_get(v,-1);
1377     PSObjectPtr attrs;
1378     if(type(key) == OT_NULL) {
1379         attrs = _class(*o)->_attributes;
1380         v->Pop();
1381         v->Push(attrs);
1382         return PS_OK;
1383     }
1384     else if(_class(*o)->GetAttributes(key,attrs)) {
1385         v->Pop();
1386         v->Push(attrs);
1387         return PS_OK;
1388     }
1389     return ps_throwerror(v,_SC("wrong index"));
1390 }
1391 
1392 PSRESULT ps_getmemberhandle(HPSCRIPTVM v,PSInteger idx,HPSMEMBERHANDLE *handle)
1393 {
1394     PSObjectPtr *o = NULL;
1395     _GETSAFE_OBJ(v, idx, OT_CLASS,o);
1396     PSObjectPtr &key = stack_get(v,-1);
1397     PSTable *m = _class(*o)->_members;
1398     PSObjectPtr val;
1399     if(m->Get(key,val)) {
1400         handle->_static = _isfield(val) ? PSFalse : PSTrue;
1401         handle->_index = _member_idx(val);
1402         v->Pop();
1403         return PS_OK;
1404     }
1405     return ps_throwerror(v,_SC("wrong index"));
1406 }
1407 
1408 PSRESULT _getmemberbyhandle(HPSCRIPTVM v,PSObjectPtr &self,const HPSMEMBERHANDLE *handle,PSObjectPtr *&val)
1409 {
1410     switch(type(self)) {
1411         case OT_INSTANCE: {
1412                 PSInstance *i = _instance(self);
1413                 if(handle->_static) {
1414                     PSClass *c = i->_class;
1415                     val = &c->_methods[handle->_index].val;
1416                 }
1417                 else {
1418                     val = &i->_values[handle->_index];
1419 
1420                 }
1421             }
1422             break;
1423         case OT_CLASS: {
1424                 PSClass *c = _class(self);
1425                 if(handle->_static) {
1426                     val = &c->_methods[handle->_index].val;
1427                 }
1428                 else {
1429                     val = &c->_defaultvalues[handle->_index].val;
1430                 }
1431             }
1432             break;
1433         default:
1434             return ps_throwerror(v,_SC("wrong type(expected class or instance)"));
1435     }
1436     return PS_OK;
1437 }
1438 
1439 PSRESULT ps_getbyhandle(HPSCRIPTVM v,PSInteger idx,const HPSMEMBERHANDLE *handle)
1440 {
1441     PSObjectPtr &self = stack_get(v,idx);
1442     PSObjectPtr *val = NULL;
1443     if(PS_FAILED(_getmemberbyhandle(v,self,handle,val))) {
1444         return PS_ERROR;
1445     }
1446     v->Push(_realval(*val));
1447     return PS_OK;
1448 }
1449 
1450 PSRESULT ps_setbyhandle(HPSCRIPTVM v,PSInteger idx,const HPSMEMBERHANDLE *handle)
1451 {
1452     PSObjectPtr &self = stack_get(v,idx);
1453     PSObjectPtr &newval = stack_get(v,-1);
1454     PSObjectPtr *val = NULL;
1455     if(PS_FAILED(_getmemberbyhandle(v,self,handle,val))) {
1456         return PS_ERROR;
1457     }
1458     *val = newval;
1459     v->Pop();
1460     return PS_OK;
1461 }
1462 
1463 PSRESULT ps_getbase(HPSCRIPTVM v,PSInteger idx)
1464 {
1465     PSObjectPtr *o = NULL;
1466     _GETSAFE_OBJ(v, idx, OT_CLASS,o);
1467     if(_class(*o)->_base)
1468         v->Push(PSObjectPtr(_class(*o)->_base));
1469     else
1470         v->PushNull();
1471     return PS_OK;
1472 }
1473 
1474 PSRESULT ps_getclass(HPSCRIPTVM v,PSInteger idx)
1475 {
1476     PSObjectPtr *o = NULL;
1477     _GETSAFE_OBJ(v, idx, OT_INSTANCE,o);
1478     v->Push(PSObjectPtr(_instance(*o)->_class));
1479     return PS_OK;
1480 }
1481 
1482 PSRESULT ps_createinstance(HPSCRIPTVM v,PSInteger idx)
1483 {
1484     PSObjectPtr *o = NULL;
1485     _GETSAFE_OBJ(v, idx, OT_CLASS,o);
1486     v->Push(_class(*o)->CreateInstance());
1487     return PS_OK;
1488 }
1489 
1490 void ps_weakref(HPSCRIPTVM v,PSInteger idx)
1491 {
1492     PSObject &o=stack_get(v,idx);
1493     if(ISREFCOUNTED(type(o))) {
1494         v->Push(_refcounted(o)->GetWeakRef(type(o)));
1495         return;
1496     }
1497     v->Push(o);
1498 }
1499 
1500 PSRESULT ps_getweakrefval(HPSCRIPTVM v,PSInteger idx)
1501 {
1502     PSObjectPtr &o = stack_get(v,idx);
1503     if(type(o) != OT_WEAKREF) {
1504         return ps_throwerror(v,_SC("the object must be a weakref"));
1505     }
1506     v->Push(_weakref(o)->_obj);
1507     return PS_OK;
1508 }
1509 
1510 PSRESULT ps_getdefaultdelegate(HPSCRIPTVM v,PSObjectType t)
1511 {
1512     PSSharedState *ss = _ss(v);
1513     switch(t) {
1514     case OT_TABLE: v->Push(ss->_table_default_delegate); break;
1515     case OT_ARRAY: v->Push(ss->_array_default_delegate); break;
1516     case OT_STRING: v->Push(ss->_string_default_delegate); break;
1517     case OT_INTEGER: case OT_FLOAT: v->Push(ss->_number_default_delegate); break;
1518     case OT_GENERATOR: v->Push(ss->_generator_default_delegate); break;
1519     case OT_CLOSURE: case OT_NATIVECLOSURE: v->Push(ss->_closure_default_delegate); break;
1520     case OT_THREAD: v->Push(ss->_thread_default_delegate); break;
1521     case OT_CLASS: v->Push(ss->_class_default_delegate); break;
1522     case OT_INSTANCE: v->Push(ss->_instance_default_delegate); break;
1523     case OT_WEAKREF: v->Push(ss->_weakref_default_delegate); break;
1524     default: return ps_throwerror(v,_SC("the type doesn't have a default delegate"));
1525     }
1526     return PS_OK;
1527 }
1528 
1529 PSRESULT ps_next(HPSCRIPTVM v,PSInteger idx)
1530 {
1531     PSObjectPtr o=stack_get(v,idx),&refpos = stack_get(v,-1),realkey,val;
1532     if(type(o) == OT_GENERATOR) {
1533         return ps_throwerror(v,_SC("cannot iterate a generator"));
1534     }
1535     int faketojump;
1536     if(!v->FOREACH_OP(o,realkey,val,refpos,0,666,faketojump))
1537         return PS_ERROR;
1538     if(faketojump != 666) {
1539         v->Push(realkey);
1540         v->Push(val);
1541         return PS_OK;
1542     }
1543     return PS_ERROR;
1544 }
1545 
1546 struct BufState{
1547     const PSChar *buf;
1548     PSInteger ptr;
1549     PSInteger size;
1550 };
1551 
1552 PSInteger buf_lexfeed(PSUserPointer file)
1553 {
1554     BufState *buf=(BufState*)file;
1555     if(buf->size<(buf->ptr+1))
1556         return 0;
1557     return buf->buf[buf->ptr++];
1558 }
1559 
1560 PSRESULT ps_compilebuffer(HPSCRIPTVM v,const PSChar *s,PSInteger size,const PSChar *sourcename,PSBool raiseerror) {
1561     BufState buf;
1562     buf.buf = s;
1563     buf.size = size;
1564     buf.ptr = 0;
1565     return ps_compile(v, buf_lexfeed, &buf, sourcename, raiseerror);
1566 }
1567 
1568 void ps_move(HPSCRIPTVM dest,HPSCRIPTVM src,PSInteger idx)
1569 {
1570     dest->Push(stack_get(src,idx));
1571 }
1572 
1573 void ps_setprintfunc(HPSCRIPTVM v, PSPRINTFUNCTION printfunc,PSPRINTFUNCTION errfunc)
1574 {
1575     _ss(v)->_printfunc = printfunc;
1576     _ss(v)->_errorfunc = errfunc;
1577 }
1578 
1579 PSPRINTFUNCTION ps_getprintfunc(HPSCRIPTVM v)
1580 {
1581     return _ss(v)->_printfunc;
1582 }
1583 
1584 PSPRINTFUNCTION ps_geterrorfunc(HPSCRIPTVM v)
1585 {
1586     return _ss(v)->_errorfunc;
1587 }
1588 
1589 void *ps_malloc(PSUnsignedInteger size)
1590 {
1591     return PS_MALLOC(size);
1592 }
1593 
1594 void *ps_realloc(void* p,PSUnsignedInteger oldsize,PSUnsignedInteger newsize)
1595 {
1596     return PS_REALLOC(p,oldsize,newsize);
1597 }
1598 
1599 void ps_free(void *p,PSUnsignedInteger size)
1600 {
1601     PS_FREE(p,size);
1602 }