Revert "Update to SQUIRREL 3.0.4"
[supertux.git] / external / squirrel / squirrel / sqvm.cpp
1 /*\r
2         see copyright notice in squirrel.h\r
3 */\r
4 #include "sqpcheader.h"\r
5 #include <math.h>\r
6 #include <stdlib.h>\r
7 #include "sqopcodes.h"\r
8 #include "sqfuncproto.h"\r
9 #include "sqvm.h"\r
10 #include "sqclosure.h"\r
11 #include "sqstring.h"\r
12 #include "sqtable.h"\r
13 #include "squserdata.h"\r
14 #include "sqarray.h"\r
15 #include "sqclass.h"\r
16 \r
17 #define TOP() (_stack._vals[_top-1])\r
18 \r
19 #define CLEARSTACK(_last_top) { if((_last_top) >= _top) ClearStack(_last_top); }\r
20 void SQVM::ClearStack(SQInteger last_top)\r
21 {\r
22         SQObjectType tOldType;\r
23         SQObjectValue unOldVal;\r
24         while (last_top >= _top) {\r
25                 SQObjectPtr &o = _stack._vals[last_top--];\r
26                 tOldType = o._type;\r
27                 unOldVal = o._unVal;\r
28                 o._type = OT_NULL;\r
29                 o._unVal.pUserPointer = NULL;\r
30                 __Release(tOldType,unOldVal);\r
31         }\r
32 }\r
33 \r
34 bool SQVM::BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2)\r
35 {\r
36         SQInteger res;\r
37         SQInteger i1 = _integer(o1), i2 = _integer(o2);\r
38         if((type(o1)==OT_INTEGER) && (type(o2)==OT_INTEGER))\r
39         {\r
40                 switch(op) {\r
41                         case BW_AND:    res = i1 & i2; break;\r
42                         case BW_OR:             res = i1 | i2; break;\r
43                         case BW_XOR:    res = i1 ^ i2; break;\r
44                         case BW_SHIFTL: res = i1 << i2; break;\r
45                         case BW_SHIFTR: res = i1 >> i2; break;\r
46                         case BW_USHIFTR:res = (SQInteger)(*((SQUnsignedInteger*)&i1) >> i2); break;\r
47                         default: { Raise_Error(_SC("internal vm error bitwise op failed")); return false; }\r
48                 }\r
49         } \r
50         else { Raise_Error(_SC("bitwise op between '%s' and '%s'"),GetTypeName(o1),GetTypeName(o2)); return false;}\r
51         trg = res;\r
52         return true;\r
53 }\r
54 \r
55 bool SQVM::ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2)\r
56 {\r
57         if(sq_isnumeric(o1) && sq_isnumeric(o2)) {\r
58                         if((type(o1)==OT_INTEGER) && (type(o2)==OT_INTEGER)) {\r
59                                 SQInteger res, i1 = _integer(o1), i2 = _integer(o2);\r
60                                 switch(op) {\r
61                                 case '+': res = i1 + i2; break;\r
62                                 case '-': res = i1 - i2; break;\r
63                                 case '/': if(i2 == 0) { Raise_Error(_SC("division by zero")); return false; }\r
64                                         res = i1 / i2; \r
65                                         break;\r
66                                 case '*': res = i1 * i2; break;\r
67                                 case '%': if(i2 == 0) { Raise_Error(_SC("modulo by zero")); return false; }\r
68                                         res = i1 % i2; \r
69                                         break;\r
70                                 default: res = 0xDEADBEEF;\r
71                                 }\r
72                                 trg = res;\r
73                         }else{\r
74                                 SQFloat res, f1 = tofloat(o1), f2 = tofloat(o2);\r
75                                 switch(op) {\r
76                                 case '+': res = f1 + f2; break;\r
77                                 case '-': res = f1 - f2; break;\r
78                                 case '/': res = f1 / f2; break;\r
79                                 case '*': res = f1 * f2; break;\r
80                                 case '%': res = SQFloat(fmod((double)f1,(double)f2)); break;\r
81                                 default: res = 0x0f;\r
82                                 }\r
83                                 trg = res;\r
84                         }       \r
85                 } else {\r
86                         if(op == '+' && (type(o1) == OT_STRING || type(o2) == OT_STRING)){\r
87                                         if(!StringCat(o1, o2, trg)) return false;\r
88                         }\r
89                         else if(!ArithMetaMethod(op,o1,o2,trg)) { \r
90                                 Raise_Error(_SC("arith op %c on between '%s' and '%s'"),op,GetTypeName(o1),GetTypeName(o2)); return false; \r
91                         }\r
92                 }\r
93                 return true;\r
94 }\r
95 \r
96 SQVM::SQVM(SQSharedState *ss)\r
97 {\r
98         _sharedstate=ss;\r
99         _suspended = SQFalse;\r
100         _suspended_target=-1;\r
101         _suspended_root = SQFalse;\r
102         _suspended_traps=-1;\r
103         _foreignptr=NULL;\r
104         _nnativecalls=0;\r
105         _lasterror = _null_;\r
106         _errorhandler = _null_;\r
107         _debughook = _null_;\r
108         ci = NULL;\r
109         INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);\r
110 }\r
111 \r
112 void SQVM::Finalize()\r
113 {\r
114         _roottable = _null_;\r
115         _lasterror = _null_;\r
116         _errorhandler = _null_;\r
117         _debughook = _null_;\r
118         temp_reg = _null_;\r
119         _callstackdata.resize(0);\r
120         SQInteger size=_stack.size();\r
121         for(SQInteger i=0;i<size;i++)\r
122                 _stack[i]=_null_;\r
123 }\r
124 \r
125 SQVM::~SQVM()\r
126 {\r
127         Finalize();\r
128         //sq_free(_callsstack,_alloccallsstacksize*sizeof(CallInfo));\r
129         REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this);\r
130 }\r
131 \r
132 bool SQVM::ArithMetaMethod(SQInteger op,const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &dest)\r
133 {\r
134         SQMetaMethod mm;\r
135         switch(op){\r
136                 case _SC('+'): mm=MT_ADD; break;\r
137                 case _SC('-'): mm=MT_SUB; break;\r
138                 case _SC('/'): mm=MT_DIV; break;\r
139                 case _SC('*'): mm=MT_MUL; break;\r
140                 case _SC('%'): mm=MT_MODULO; break;\r
141                 default: mm = MT_ADD; assert(0); break; //shutup compiler\r
142         }\r
143         if(is_delegable(o1) && _delegable(o1)->_delegate) {\r
144                 Push(o1);Push(o2);\r
145                 return CallMetaMethod(_delegable(o1),mm,2,dest);\r
146         }\r
147         return false;\r
148 }\r
149 \r
150 bool SQVM::NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o)\r
151 {\r
152         \r
153         switch(type(o)) {\r
154         case OT_INTEGER:\r
155                 trg = -_integer(o);\r
156                 return true;\r
157         case OT_FLOAT:\r
158                 trg = -_float(o);\r
159                 return true;\r
160         case OT_TABLE:\r
161         case OT_USERDATA:\r
162         case OT_INSTANCE:\r
163                 if(_delegable(o)->_delegate) {\r
164                         Push(o);\r
165                         if(CallMetaMethod(_delegable(o), MT_UNM, 1, temp_reg)) {\r
166                                 trg = temp_reg;\r
167                                 return true;\r
168                         }\r
169                 }\r
170         default:break; //shutup compiler\r
171         }\r
172         Raise_Error(_SC("attempt to negate a %s"), GetTypeName(o));\r
173         return false;\r
174 }\r
175 \r
176 #define _RET_SUCCEED(exp) { result = (exp); return true; } \r
177 bool SQVM::ObjCmp(const SQObjectPtr &o1,const SQObjectPtr &o2,SQInteger &result)\r
178 {\r
179         if(type(o1)==type(o2)){\r
180                 if(_rawval(o1)==_rawval(o2))_RET_SUCCEED(0);\r
181                 SQObjectPtr res;\r
182                 switch(type(o1)){\r
183                 case OT_STRING:\r
184                         _RET_SUCCEED(scstrcmp(_stringval(o1),_stringval(o2)));\r
185                 case OT_INTEGER:\r
186                         _RET_SUCCEED(_integer(o1)-_integer(o2));\r
187                 case OT_FLOAT:\r
188                         _RET_SUCCEED((_float(o1)<_float(o2))?-1:1);\r
189                 case OT_TABLE:\r
190                 case OT_USERDATA:\r
191                 case OT_INSTANCE:\r
192                         if(_delegable(o1)->_delegate) {\r
193                                 Push(o1);Push(o2);\r
194                                 if(CallMetaMethod(_delegable(o1),MT_CMP,2,res)) break;\r
195                         }\r
196                         //continues through (no break needed)\r
197                 default: \r
198                         _RET_SUCCEED( _userpointer(o1) < _userpointer(o2)?-1:1 );\r
199                 }\r
200                 if(type(res)!=OT_INTEGER) { Raise_CompareError(o1,o2); return false; }\r
201                         _RET_SUCCEED(_integer(res));\r
202                 \r
203         }\r
204         else{\r
205                 if(sq_isnumeric(o1) && sq_isnumeric(o2)){\r
206                         if((type(o1)==OT_INTEGER) && (type(o2)==OT_FLOAT)) { \r
207                                 if( _integer(o1)==_float(o2) ) { _RET_SUCCEED(0); }\r
208                                 else if( _integer(o1)<_float(o2) ) { _RET_SUCCEED(-1); }\r
209                                 _RET_SUCCEED(1);\r
210                         }\r
211                         else{\r
212                                 if( _float(o1)==_integer(o2) ) { _RET_SUCCEED(0); }\r
213                                 else if( _float(o1)<_integer(o2) ) { _RET_SUCCEED(-1); }\r
214                                 _RET_SUCCEED(1);\r
215                         }\r
216                 }\r
217                 else if(type(o1)==OT_NULL) {_RET_SUCCEED(-1);}\r
218                 else if(type(o2)==OT_NULL) {_RET_SUCCEED(1);}\r
219                 else { Raise_CompareError(o1,o2); return false; }\r
220                 \r
221         }\r
222         assert(0);\r
223         _RET_SUCCEED(0); //cannot happen\r
224 }\r
225 \r
226 bool SQVM::CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res)\r
227 {\r
228         SQInteger r;\r
229         if(ObjCmp(o1,o2,r)) {\r
230                 switch(op) {\r
231                         case CMP_G: res = (r > 0)?_true_:_false_; return true;\r
232                         case CMP_GE: res = (r >= 0)?_true_:_false_; return true;\r
233                         case CMP_L: res = (r < 0)?_true_:_false_; return true;\r
234                         case CMP_LE: res = (r <= 0)?_true_:_false_; return true;\r
235                         \r
236                 }\r
237                 assert(0);\r
238         }\r
239         return false;\r
240 }\r
241 \r
242 void SQVM::ToString(const SQObjectPtr &o,SQObjectPtr &res)\r
243 {\r
244         switch(type(o)) {\r
245         case OT_STRING:\r
246                 res = o;\r
247                 return;\r
248         case OT_FLOAT:\r
249                 scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)),_SC("%g"),_float(o));\r
250                 break;\r
251         case OT_INTEGER:\r
252                 scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)),_SC("%d"),_integer(o));\r
253                 break;\r
254         case OT_BOOL:\r
255                 scsprintf(_sp(rsl(6)),_integer(o)?_SC("true"):_SC("false"));\r
256                 break;\r
257         case OT_TABLE:\r
258         case OT_USERDATA:\r
259         case OT_INSTANCE:\r
260                 if(_delegable(o)->_delegate) {\r
261                         Push(o);\r
262                         if(CallMetaMethod(_delegable(o),MT_TOSTRING,1,res)) {\r
263                                 if(type(res) == OT_STRING)\r
264                                         return;\r
265                                 //else keeps going to the default\r
266                         }\r
267                 }\r
268         default:\r
269                 scsprintf(_sp(rsl(sizeof(void*)+20)),_SC("(%s : 0x%p)"),GetTypeName(o),(void*)_rawval(o));\r
270         }\r
271         res = SQString::Create(_ss(this),_spval);\r
272 }\r
273 \r
274 \r
275 bool SQVM::StringCat(const SQObjectPtr &str,const SQObjectPtr &obj,SQObjectPtr &dest)\r
276 {\r
277         SQObjectPtr a, b;\r
278         ToString(str, a);\r
279         ToString(obj, b);\r
280         SQInteger l = _string(a)->_len , ol = _string(b)->_len;\r
281         SQChar *s = _sp(rsl(l + ol + 1));\r
282         memcpy(s, _stringval(a), rsl(l)); \r
283         memcpy(s + l, _stringval(b), rsl(ol));\r
284         dest = SQString::Create(_ss(this), _spval, l + ol);\r
285         return true;\r
286 }\r
287 \r
288 void SQVM::TypeOf(const SQObjectPtr &obj1,SQObjectPtr &dest)\r
289 {\r
290         if(is_delegable(obj1) && _delegable(obj1)->_delegate) {\r
291                 Push(obj1);\r
292                 if(CallMetaMethod(_delegable(obj1),MT_TYPEOF,1,dest))\r
293                         return;\r
294         }\r
295         dest = SQString::Create(_ss(this),GetTypeName(obj1));\r
296 }\r
297 \r
298 bool SQVM::Init(SQVM *friendvm, SQInteger stacksize)\r
299 {\r
300         _stack.resize(stacksize);\r
301         _alloccallsstacksize = 4;\r
302         _callstackdata.resize(_alloccallsstacksize);\r
303         _callsstacksize = 0;\r
304         _callsstack = &_callstackdata[0];\r
305         _stackbase = 0;\r
306         _top = 0;\r
307         if(!friendvm) \r
308                 _roottable = SQTable::Create(_ss(this), 0);\r
309         else {\r
310                 _roottable = friendvm->_roottable;\r
311                 _errorhandler = friendvm->_errorhandler;\r
312                 _debughook = friendvm->_debughook;\r
313         }\r
314         \r
315         sq_base_register(this);\r
316         return true;\r
317 }\r
318 \r
319 extern SQInstructionDesc g_InstrDesc[];\r
320 \r
321 bool SQVM::StartCall(SQClosure *closure,SQInteger target,SQInteger args,SQInteger stackbase,bool tailcall)\r
322 {\r
323         SQFunctionProto *func = _funcproto(closure->_function);\r
324         \r
325         const SQInteger paramssize = func->_nparameters;\r
326         const SQInteger newtop = stackbase + func->_stacksize;\r
327         SQInteger nargs = args;\r
328         if (paramssize != nargs) {\r
329                 SQInteger ndef = func->_ndefaultparams;\r
330                 SQInteger diff;\r
331                 if(ndef && nargs < paramssize && (diff = paramssize - nargs) <= ndef) {\r
332                         for(SQInteger n = ndef - diff; n < ndef; n++) {\r
333                                 _stack._vals[stackbase + (nargs++)] = closure->_defaultparams[n];\r
334                         }\r
335                 }\r
336                 else if(func->_varparams)\r
337                 {\r
338                         if (nargs < paramssize) {\r
339                                 Raise_Error(_SC("wrong number of parameters"));\r
340                                 return false;\r
341                         }\r
342                         for(SQInteger n = 0; n < nargs - paramssize; n++) {\r
343                                 _vargsstack.push_back(_stack._vals[stackbase+paramssize+n]);\r
344                                 _stack._vals[stackbase+paramssize+n] = _null_;\r
345                         }\r
346                 }\r
347                 else {\r
348                         Raise_Error(_SC("wrong number of parameters"));\r
349                         return false;\r
350                 }\r
351         }\r
352 \r
353         if(type(closure->_env) == OT_WEAKREF) {\r
354                 _stack._vals[stackbase] = _weakref(closure->_env)->_obj;\r
355         }\r
356 \r
357         if (!tailcall) {\r
358                 CallInfo lc;\r
359                 lc._generator = NULL;\r
360                 lc._etraps = 0;\r
361                 lc._prevstkbase = (SQInt32) ( stackbase - _stackbase );\r
362                 lc._target = (SQInt32) target;\r
363                 lc._prevtop = (SQInt32) (_top - _stackbase);\r
364                 lc._ncalls = 1;\r
365                 lc._root = SQFalse;\r
366                 PUSH_CALLINFO(this, lc);\r
367         }\r
368         else {\r
369                 ci->_ncalls++;\r
370         }\r
371         ci->_vargs.size = (SQInt32)(nargs - paramssize);\r
372         ci->_vargs.base = (SQInt32)(_vargsstack.size()-(ci->_vargs.size));\r
373         ci->_closure = closure;\r
374         ci->_literals = func->_literals;\r
375         ci->_ip = func->_instructions;\r
376         //grows the stack if needed\r
377         if (((SQUnsignedInteger)newtop + (func->_stacksize<<1)) > _stack.size()) {\r
378                 _stack.resize(_stack.size() + (func->_stacksize<<1));\r
379         }\r
380                 \r
381         _top = newtop;\r
382         _stackbase = stackbase;\r
383         if (type(_debughook) != OT_NULL && _rawval(_debughook) != _rawval(ci->_closure))\r
384                 CallDebugHook(_SC('c'));\r
385         return true;\r
386 }\r
387 \r
388 bool SQVM::Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval)\r
389 {\r
390         if (type(_debughook) != OT_NULL && _rawval(_debughook) != _rawval(ci->_closure))\r
391                 for(SQInteger i=0;i<ci->_ncalls;i++)\r
392                         CallDebugHook(_SC('r'));\r
393                         \r
394         SQBool broot = ci->_root;\r
395         SQInteger last_top = _top;\r
396         SQInteger target = ci->_target;\r
397         SQInteger oldstackbase = _stackbase;\r
398         _stackbase -= ci->_prevstkbase;\r
399         _top = _stackbase + ci->_prevtop;\r
400         if(ci->_vargs.size) PopVarArgs(ci->_vargs);\r
401         POP_CALLINFO(this);\r
402         if (broot) {\r
403                 if (_arg0 != MAX_FUNC_STACKSIZE) retval = _stack._vals[oldstackbase+_arg1];\r
404                 else retval = _null_;\r
405         }\r
406         else {\r
407                 if(target != -1) { //-1 is when a class contructor ret value has to be ignored\r
408                         if (_arg0 != MAX_FUNC_STACKSIZE)\r
409                                 STK(target) = _stack._vals[oldstackbase+_arg1];\r
410                         else\r
411                                 STK(target) = _null_;\r
412                 }\r
413         }\r
414 \r
415         CLEARSTACK(last_top);\r
416         assert(oldstackbase >= _stackbase); \r
417         return broot?true:false;\r
418 }\r
419 \r
420 #define _RET_ON_FAIL(exp) { if(!exp) return false; }\r
421 \r
422 bool SQVM::LOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr)\r
423 {\r
424         _RET_ON_FAIL(ARITH_OP( op , target, a, incr));\r
425         a = target;\r
426         return true;\r
427 }\r
428 \r
429 bool SQVM::PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr)\r
430 {\r
431         SQObjectPtr trg;\r
432         _RET_ON_FAIL(ARITH_OP( op , trg, a, incr));\r
433         target = a;\r
434         a = trg;\r
435         return true;\r
436 }\r
437 \r
438 bool SQVM::DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix)\r
439 {\r
440         SQObjectPtr tmp, tself = self, tkey = key;\r
441         if (!Get(tself, tkey, tmp, false, true)) { Raise_IdxError(tkey); return false; }\r
442         _RET_ON_FAIL(ARITH_OP( op , target, tmp, incr))\r
443         Set(tself, tkey, target,true);\r
444         if (postfix) target = tmp;\r
445         return true;\r
446 }\r
447 \r
448 #define arg0 (_i_._arg0)\r
449 #define arg1 (_i_._arg1)\r
450 #define sarg1 (*((SQInt32 *)&_i_._arg1))\r
451 #define arg2 (_i_._arg2)\r
452 #define arg3 (_i_._arg3)\r
453 #define sarg3 ((SQInteger)*((signed char *)&_i_._arg3))\r
454 \r
455 SQRESULT SQVM::Suspend()\r
456 {\r
457         if (_suspended)\r
458                 return sq_throwerror(this, _SC("cannot suspend an already suspended vm"));\r
459         if (_nnativecalls!=2)\r
460                 return sq_throwerror(this, _SC("cannot suspend through native calls/metamethods"));\r
461         return SQ_SUSPEND_FLAG;\r
462 }\r
463 \r
464 void SQVM::PopVarArgs(VarArgs &vargs)\r
465 {\r
466         for(SQInteger n = 0; n< vargs.size; n++)\r
467                 _vargsstack.pop_back();\r
468 }\r
469 \r
470 #define _FINISH(howmuchtojump) {jump = howmuchtojump; return true; }\r
471 bool SQVM::FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr \r
472 &o3,SQObjectPtr &o4,SQInteger arg_2,int exitpos,int &jump)\r
473 {\r
474         SQInteger nrefidx;\r
475         switch(type(o1)) {\r
476         case OT_TABLE:\r
477                 if((nrefidx = _table(o1)->Next(false,o4, o2, o3)) == -1) _FINISH(exitpos);\r
478                 o4 = (SQInteger)nrefidx; _FINISH(1);\r
479         case OT_ARRAY:\r
480                 if((nrefidx = _array(o1)->Next(o4, o2, o3)) == -1) _FINISH(exitpos);\r
481                 o4 = (SQInteger) nrefidx; _FINISH(1);\r
482         case OT_STRING:\r
483                 if((nrefidx = _string(o1)->Next(o4, o2, o3)) == -1)_FINISH(exitpos);\r
484                 o4 = (SQInteger)nrefidx; _FINISH(1);\r
485         case OT_CLASS:\r
486                 if((nrefidx = _class(o1)->Next(o4, o2, o3)) == -1)_FINISH(exitpos);\r
487                 o4 = (SQInteger)nrefidx; _FINISH(1);\r
488         case OT_USERDATA:\r
489         case OT_INSTANCE:\r
490                 if(_delegable(o1)->_delegate) {\r
491                         SQObjectPtr itr;\r
492                         Push(o1);\r
493                         Push(o4);\r
494                         if(CallMetaMethod(_delegable(o1), MT_NEXTI, 2, itr)){\r
495                                 o4 = o2 = itr;\r
496                                 if(type(itr) == OT_NULL) _FINISH(exitpos);\r
497                                 if(!Get(o1, itr, o3, false,false)) {\r
498                                         Raise_Error(_SC("_nexti returned an invalid idx"));\r
499                                         return false;\r
500                                 }\r
501                                 _FINISH(1);\r
502                         }\r
503                         Raise_Error(_SC("_nexti failed"));\r
504                         return false;\r
505                 }\r
506                 break;\r
507         case OT_GENERATOR:\r
508                 if(_generator(o1)->_state == SQGenerator::eDead) _FINISH(exitpos);\r
509                 if(_generator(o1)->_state == SQGenerator::eSuspended) {\r
510                         SQInteger idx = 0;\r
511                         if(type(o4) == OT_INTEGER) {\r
512                                 idx = _integer(o4) + 1;\r
513                         }\r
514                         o2 = idx;\r
515                         o4 = idx;\r
516                         _generator(o1)->Resume(this, arg_2+1);\r
517                         _FINISH(0);\r
518                 }\r
519         default: \r
520                 Raise_Error(_SC("cannot iterate %s"), GetTypeName(o1));\r
521         }\r
522         return false; //cannot be hit(just to avoid warnings)\r
523 }\r
524 \r
525 bool SQVM::DELEGATE_OP(SQObjectPtr &trg,SQObjectPtr &o1,SQObjectPtr &o2)\r
526 {\r
527         if(type(o1) != OT_TABLE) { Raise_Error(_SC("delegating a '%s'"), GetTypeName(o1)); return false; }\r
528         switch(type(o2)) {\r
529         case OT_TABLE:\r
530                 if(!_table(o1)->SetDelegate(_table(o2))){\r
531                         Raise_Error(_SC("delegate cycle detected"));\r
532                         return false;\r
533                 }\r
534                 break;\r
535         case OT_NULL:\r
536                 _table(o1)->SetDelegate(NULL);\r
537                 break;\r
538         default:\r
539                 Raise_Error(_SC("using '%s' as delegate"), GetTypeName(o2));\r
540                 return false;\r
541                 break;\r
542         }\r
543         trg = o1;\r
544         return true;\r
545 }\r
546 #define COND_LITERAL (arg3!=0?ci->_literals[arg1]:STK(arg1))\r
547 \r
548 #define _GUARD(exp) { if(!exp) { Raise_Error(_lasterror); SQ_THROW();} }\r
549 \r
550 #define SQ_THROW() { goto exception_trap; }\r
551 \r
552 bool SQVM::CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func)\r
553 {\r
554         SQInteger nouters;\r
555         SQClosure *closure = SQClosure::Create(_ss(this), func);\r
556         if((nouters = func->_noutervalues)) {\r
557                 closure->_outervalues.reserve(nouters);\r
558                 for(SQInteger i = 0; i<nouters; i++) {\r
559                         SQOuterVar &v = func->_outervalues[i];\r
560                         switch(v._type){\r
561                         case otSYMBOL:\r
562                                 closure->_outervalues.push_back(_null_);\r
563                                 if(!Get(_stack._vals[_stackbase]/*STK(0)*/, v._src, closure->_outervalues.top(), false,true))\r
564                                 {Raise_IdxError(v._src); return false; }\r
565                                 break;\r
566                         case otLOCAL:\r
567                                 closure->_outervalues.push_back(_stack._vals[_stackbase+_integer(v._src)]);\r
568                                 break;\r
569                         case otOUTER:\r
570                                 closure->_outervalues.push_back(_closure(ci->_closure)->_outervalues[_integer(v._src)]);\r
571                                 break;\r
572                         }\r
573                 }\r
574         }\r
575         SQInteger ndefparams;\r
576         if((ndefparams = func->_ndefaultparams)) {\r
577                 closure->_defaultparams.reserve(ndefparams);\r
578                 for(SQInteger i = 0; i < ndefparams; i++) {\r
579                         SQInteger spos = func->_defaultparams[i];\r
580                         closure->_defaultparams.push_back(_stack._vals[_stackbase + spos]);\r
581                 }\r
582         }\r
583         target = closure;\r
584         return true;\r
585 \r
586 }\r
587 \r
588 bool SQVM::GETVARGV_OP(SQObjectPtr &target,SQObjectPtr &index,CallInfo *ci)\r
589 {\r
590         if(ci->_vargs.size == 0) {\r
591                 Raise_Error(_SC("the function doesn't have var args"));\r
592                 return false;\r
593         }\r
594         if(!sq_isnumeric(index)){\r
595                 Raise_Error(_SC("indexing 'vargv' with %s"),GetTypeName(index));\r
596                 return false;\r
597         }\r
598         SQInteger idx = tointeger(index);\r
599         if(idx < 0 || idx >= ci->_vargs.size){ Raise_Error(_SC("vargv index out of range")); return false; }\r
600         target = _vargsstack[ci->_vargs.base+idx];\r
601         return true;\r
602 }\r
603 \r
604 bool SQVM::CLASS_OP(SQObjectPtr &target,SQInteger baseclass,SQInteger attributes)\r
605 {\r
606         SQClass *base = NULL;\r
607         SQObjectPtr attrs;\r
608         if(baseclass != -1) {\r
609                 if(type(_stack._vals[_stackbase+baseclass]) != OT_CLASS) { Raise_Error(_SC("trying to inherit from a %s"),GetTypeName(_stack._vals[_stackbase+baseclass])); return false; }\r
610                 base = _class(_stack._vals[_stackbase + baseclass]);\r
611         }\r
612         if(attributes != MAX_FUNC_STACKSIZE) {\r
613                 attrs = _stack._vals[_stackbase+attributes];\r
614         }\r
615         target = SQClass::Create(_ss(this),base);\r
616         if(type(_class(target)->_metamethods[MT_INHERITED]) != OT_NULL) {\r
617                 int nparams = 2;\r
618                 SQObjectPtr ret;\r
619                 Push(target); Push(attrs);\r
620                 Call(_class(target)->_metamethods[MT_INHERITED],nparams,_top - nparams, ret, false);\r
621                 Pop(nparams);\r
622         }\r
623         _class(target)->_attributes = attrs;\r
624         return true;\r
625 }\r
626 \r
627 \r
628 \r
629 bool SQVM::IsEqual(SQObjectPtr &o1,SQObjectPtr &o2,bool &res)\r
630 {\r
631         if(type(o1) == type(o2)) {\r
632                 res = ((_rawval(o1) == _rawval(o2)?true:false));\r
633         }\r
634         else {\r
635                 if(sq_isnumeric(o1) && sq_isnumeric(o2)) {\r
636                         SQInteger cmpres;\r
637                         if(!ObjCmp(o1, o2,cmpres)) return false;\r
638                         res = (cmpres == 0);\r
639                 }\r
640                 else {\r
641                         res = false;\r
642                 }\r
643         }\r
644         return true;\r
645 }\r
646 \r
647 bool SQVM::IsFalse(SQObjectPtr &o)\r
648 {\r
649         if((type(o) & SQOBJECT_CANBEFALSE) && ( (type(o) == OT_FLOAT) && (_float(o) == SQFloat(0.0)) )\r
650                 || (_integer(o) == 0) ) { //OT_NULL|OT_INTEGER|OT_BOOL\r
651                 return true;\r
652         }\r
653         return false;\r
654 }\r
655 \r
656 bool SQVM::GETPARENT_OP(SQObjectPtr &o,SQObjectPtr &target)\r
657 {\r
658         switch(type(o)) {\r
659                 case OT_TABLE: target = _table(o)->_delegate?SQObjectPtr(_table(o)->_delegate):_null_;\r
660                         break;\r
661                 case OT_CLASS: target = _class(o)->_base?_class(o)->_base:_null_;\r
662                         break;\r
663                 default:\r
664                         Raise_Error(_SC("the %s type doesn't have a parent slot"), GetTypeName(o));\r
665                         return false;\r
666         }\r
667         return true;\r
668 }\r
669 \r
670 bool SQVM::Execute(SQObjectPtr &closure, SQInteger target, SQInteger nargs, SQInteger stackbase,SQObjectPtr &outres, SQBool raiseerror,ExecutionType et)\r
671 {\r
672         if ((_nnativecalls + 1) > MAX_NATIVE_CALLS) { Raise_Error(_SC("Native stack overflow")); return false; }\r
673         _nnativecalls++;\r
674         AutoDec ad(&_nnativecalls);\r
675         SQInteger traps = 0;\r
676         //temp_reg vars for OP_CALL\r
677         SQInteger ct_target;\r
678         SQInteger ct_stackbase;\r
679         bool ct_tailcall; \r
680 \r
681         switch(et) {\r
682                 case ET_CALL: {\r
683                         SQInteger last_top = _top;\r
684                         temp_reg = closure;\r
685                         if(!StartCall(_closure(temp_reg), _top - nargs, nargs, stackbase, false)) { \r
686                                 //call the handler if there are no calls in the stack, if not relies on the previous node\r
687                                 if(ci == NULL) CallErrorHandler(_lasterror);\r
688                                 return false;\r
689                         }\r
690                         if (_funcproto(_closure(temp_reg)->_function)->_bgenerator) {\r
691                                 SQFunctionProto *f = _funcproto(_closure(temp_reg)->_function);\r
692                                 SQGenerator *gen = SQGenerator::Create(_ss(this), _closure(temp_reg));\r
693                                 _GUARD(gen->Yield(this));\r
694                                 Return(1, ci->_target, temp_reg);\r
695                                 outres = gen;\r
696                                 CLEARSTACK(last_top);\r
697                                 return true;\r
698                         }\r
699                         ci->_root = SQTrue;\r
700                                           }\r
701                         break;\r
702                 case ET_RESUME_GENERATOR: _generator(closure)->Resume(this, target); ci->_root = SQTrue; traps += ci->_etraps; break;\r
703                 case ET_RESUME_VM:\r
704                 case ET_RESUME_THROW_VM:\r
705                         traps = _suspended_traps;\r
706                         ci->_root = _suspended_root;\r
707                         ci->_vargs = _suspend_varargs;\r
708                         _suspended = SQFalse;\r
709                         if(et  == ET_RESUME_THROW_VM) { SQ_THROW(); }\r
710                         break;\r
711         }\r
712         \r
713 exception_restore:\r
714         //\r
715         {\r
716                 for(;;)\r
717                 {\r
718                         const SQInstruction &_i_ = *ci->_ip++;\r
719                         //dumpstack(_stackbase);\r
720                         //scprintf("\n[%d] %s %d %d %d %d\n",ci->_ip-ci->_iv->_vals,g_InstrDesc[_i_.op].name,arg0,arg1,arg2,arg3);\r
721                         switch(_i_.op)\r
722                         {\r
723                         case _OP_LINE:\r
724                                 if(type(_debughook) != OT_NULL && _rawval(_debughook) != _rawval(ci->_closure))\r
725                                         CallDebugHook(_SC('l'),arg1);\r
726                                 continue;\r
727                         case _OP_LOAD: TARGET = ci->_literals[arg1]; continue;\r
728                         case _OP_LOADINT: TARGET = (SQInteger)arg1; continue;\r
729                         case _OP_LOADFLOAT: TARGET = *((SQFloat *)&arg1); continue;\r
730                         case _OP_DLOAD: TARGET = ci->_literals[arg1]; STK(arg2) = ci->_literals[arg3];continue;\r
731                         case _OP_TAILCALL:\r
732                                 temp_reg = STK(arg1);\r
733                                 if (type(temp_reg) == OT_CLOSURE && !_funcproto(_closure(temp_reg)->_function)->_bgenerator){ \r
734                                         ct_tailcall = true;\r
735                                         if(ci->_vargs.size) PopVarArgs(ci->_vargs);\r
736                                         for (SQInteger i = 0; i < arg3; i++) STK(i) = STK(arg2 + i);\r
737                                         ct_target = ci->_target;\r
738                                         ct_stackbase = _stackbase;\r
739                                         goto common_call;\r
740                                 }\r
741                         case _OP_CALL: {\r
742                                         ct_tailcall = false;\r
743                                         ct_target = arg0;\r
744                                         temp_reg = STK(arg1);\r
745                                         ct_stackbase = _stackbase+arg2;\r
746 \r
747 common_call:\r
748                                         SQObjectPtr clo = temp_reg;\r
749                                         SQInteger last_top = _top;\r
750                                         switch (type(clo)) {\r
751                                         case OT_CLOSURE:{\r
752                                                 _GUARD(StartCall(_closure(clo), ct_target, arg3, ct_stackbase, ct_tailcall));\r
753                                                 if (_funcproto(_closure(clo)->_function)->_bgenerator) {\r
754                                                         SQGenerator *gen = SQGenerator::Create(_ss(this), _closure(clo));\r
755                                                         _GUARD(gen->Yield(this));\r
756                                                         Return(1, ct_target, clo);\r
757                                                         STK(ct_target) = gen;\r
758                                                         CLEARSTACK(last_top);\r
759                                                         continue;\r
760                                                 }\r
761                                                 }\r
762                                                 continue;\r
763                                         case OT_NATIVECLOSURE: {\r
764                                                 bool suspend;\r
765                                                 _GUARD(CallNative(_nativeclosure(clo), arg3, ct_stackbase, clo,suspend));\r
766                                                 if(suspend){\r
767                                                         _suspended = SQTrue;\r
768                                                         _suspended_target = ct_target;\r
769                                                         _suspended_root = ci->_root;\r
770                                                         _suspended_traps = traps;\r
771                                                         _suspend_varargs = ci->_vargs;\r
772                                                         outres = clo;\r
773                                                         return true;\r
774                                                 }\r
775                                                 if(ct_target != -1) { //skip return value for constructors\r
776                                                         STK(ct_target) = clo;\r
777                                                 }\r
778                                                                                    }\r
779                                                 continue;\r
780                                         case OT_CLASS:{\r
781                                                 SQObjectPtr inst;\r
782                                                 _GUARD(CreateClassInstance(_class(clo),inst,temp_reg));\r
783                                                 STK(ct_target) = inst;\r
784                                                 ct_target = -1; //fakes return value target so that is not overwritten by the constructor\r
785                                                 if(type(temp_reg) != OT_NULL) {\r
786                                                         _stack._vals[ct_stackbase] = inst;\r
787                                                         goto common_call; //hard core spaghetti code(reissues the OP_CALL to invoke the constructor)\r
788                                                 }\r
789                                                 }\r
790                                                 break;\r
791                                         case OT_TABLE:\r
792                                         case OT_USERDATA:\r
793                                         case OT_INSTANCE:\r
794                                                 {\r
795                                                 Push(clo);\r
796                                                 for (SQInteger i = 0; i < arg3; i++) Push(STK(arg2 + i));\r
797                                                 if (_delegable(clo) && CallMetaMethod(_delegable(clo), MT_CALL, arg3+1, clo)){\r
798                                                         STK(ct_target) = clo;\r
799                                                         break;\r
800                                                 }\r
801                                                 Raise_Error(_SC("attempt to call '%s'"), GetTypeName(clo));\r
802                                                 SQ_THROW();\r
803                                           }\r
804                                         default:\r
805                                                 Raise_Error(_SC("attempt to call '%s'"), GetTypeName(clo));\r
806                                                 SQ_THROW();\r
807                                         }\r
808                                 }\r
809                                   continue;\r
810                         case _OP_PREPCALL:\r
811                         case _OP_PREPCALLK:\r
812                                 {\r
813                                         SQObjectPtr &key = _i_.op == _OP_PREPCALLK?(ci->_literals)[arg1]:STK(arg1);\r
814                                         SQObjectPtr &o = STK(arg2);\r
815                                         if (!Get(o, key, temp_reg,false,true)) {\r
816                                                 if(type(o) == OT_CLASS) { //hack?\r
817                                                         if(_class_ddel->Get(key,temp_reg)) {\r
818                                                                 STK(arg3) = o;\r
819                                                                 TARGET = temp_reg;\r
820                                                                 continue;\r
821                                                         }\r
822                                                 }\r
823                                                 { Raise_IdxError(key); SQ_THROW();}\r
824                                         }\r
825 \r
826                                         STK(arg3) = type(o) == OT_CLASS?STK(0):o;\r
827                                         TARGET = temp_reg;\r
828                                 }\r
829                                 continue;\r
830                         case _OP_GETK:\r
831                                 if (!Get(STK(arg2), ci->_literals[arg1], temp_reg, false,true)) { Raise_IdxError(ci->_literals[arg1]); SQ_THROW();}\r
832                                 TARGET = temp_reg;\r
833                                 continue;\r
834                         case _OP_MOVE: TARGET = STK(arg1); continue;\r
835                         case _OP_NEWSLOT:\r
836                                 _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3),false));\r
837                                 if(arg0 != arg3) TARGET = STK(arg3);\r
838                                 continue;\r
839                         case _OP_DELETE: _GUARD(DeleteSlot(STK(arg1), STK(arg2), TARGET)); continue;\r
840                         case _OP_SET:\r
841                                 if (!Set(STK(arg1), STK(arg2), STK(arg3),true)) { Raise_IdxError(STK(arg2)); SQ_THROW(); }\r
842                                 if (arg0 != arg3) TARGET = STK(arg3);\r
843                                 continue;\r
844                         case _OP_GET:\r
845                                 if (!Get(STK(arg1), STK(arg2), temp_reg, false,true)) { Raise_IdxError(STK(arg2)); SQ_THROW(); }\r
846                                 TARGET = temp_reg;\r
847                                 continue;\r
848                         case _OP_EQ:{\r
849                                 bool res;\r
850                                 if(!IsEqual(STK(arg2),COND_LITERAL,res)) { SQ_THROW(); }\r
851                                 TARGET = res?_true_:_false_;\r
852                                 }continue;\r
853                         case _OP_NE:{ \r
854                                 bool res;\r
855                                 if(!IsEqual(STK(arg2),COND_LITERAL,res)) { SQ_THROW(); }\r
856                                 TARGET = (!res)?_true_:_false_;\r
857                                 } continue;\r
858                         case _OP_ARITH: _GUARD(ARITH_OP( arg3 , temp_reg, STK(arg2), STK(arg1))); TARGET = temp_reg; continue;\r
859                         case _OP_BITW:  _GUARD(BW_OP( arg3,TARGET,STK(arg2),STK(arg1))); continue;\r
860                         case _OP_RETURN:\r
861                                 if(ci->_generator) {\r
862                                         ci->_generator->Kill();\r
863                                 }\r
864                                 if(Return(arg0, arg1, temp_reg)){\r
865                                         assert(traps==0);\r
866                                         outres = temp_reg;\r
867                                         return true;\r
868                                 }\r
869                                 continue;\r
870                         case _OP_LOADNULLS:{ for(SQInt32 n=0; n < arg1; n++) STK(arg0+n) = _null_; }continue;\r
871                         case _OP_LOADROOTTABLE: TARGET = _roottable; continue;\r
872                         case _OP_LOADBOOL: TARGET = arg1?_true_:_false_; continue;\r
873                         case _OP_DMOVE: STK(arg0) = STK(arg1); STK(arg2) = STK(arg3); continue;\r
874                         case _OP_JMP: ci->_ip += (sarg1); continue;\r
875                         case _OP_JNZ: if(!IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue;\r
876                         case _OP_JZ: if(IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue;\r
877                         case _OP_LOADFREEVAR: TARGET = _closure(ci->_closure)->_outervalues[arg1]; continue;\r
878                         case _OP_VARGC: TARGET = SQInteger(ci->_vargs.size); continue;\r
879                         case _OP_GETVARGV: \r
880                                 if(!GETVARGV_OP(TARGET,STK(arg1),ci)) { SQ_THROW(); } \r
881                                 continue;\r
882                         case _OP_NEWTABLE: TARGET = SQTable::Create(_ss(this), arg1); continue;\r
883                         case _OP_NEWARRAY: TARGET = SQArray::Create(_ss(this), 0); _array(TARGET)->Reserve(arg1); continue;\r
884                         case _OP_APPENDARRAY: _array(STK(arg0))->Append(COND_LITERAL);  continue;\r
885                         case _OP_GETPARENT: _GUARD(GETPARENT_OP(STK(arg1),TARGET)); continue;\r
886                         case _OP_COMPARITH: _GUARD(DerefInc(arg3, TARGET, STK((((SQUnsignedInteger)arg1&0xFFFF0000)>>16)), STK(arg2), STK(arg1&0x0000FFFF), false)); continue;\r
887                         case _OP_COMPARITHL: _GUARD(LOCAL_INC(arg3, TARGET, STK(arg1), STK(arg2))); continue;\r
888                         case _OP_INC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, false));} continue;\r
889                         case _OP_INCL: {SQObjectPtr o(sarg3); _GUARD(LOCAL_INC('+',TARGET, STK(arg1), o));} continue;\r
890                         case _OP_PINC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, true));} continue;\r
891                         case _OP_PINCL: {SQObjectPtr o(sarg3); _GUARD(PLOCAL_INC('+',TARGET, STK(arg1), o));} continue;\r
892                         case _OP_CMP:   _GUARD(CMP_OP((CmpOP)arg3,STK(arg2),STK(arg1),TARGET))  continue;\r
893                         case _OP_EXISTS: TARGET = Get(STK(arg1), STK(arg2), temp_reg, true,false)?_true_:_false_;continue;\r
894                         case _OP_INSTANCEOF: \r
895                                 if(type(STK(arg1)) != OT_CLASS || type(STK(arg2)) != OT_INSTANCE)\r
896                                 {Raise_Error(_SC("cannot apply instanceof between a %s and a %s"),GetTypeName(STK(arg1)),GetTypeName(STK(arg2))); SQ_THROW();}\r
897                                 TARGET = _instance(STK(arg2))->InstanceOf(_class(STK(arg1)))?_true_:_false_;\r
898                                 continue;\r
899                         case _OP_AND: \r
900                                 if(IsFalse(STK(arg2))) {\r
901                                         TARGET = STK(arg2);\r
902                                         ci->_ip += (sarg1);\r
903                                 }\r
904                                 continue;\r
905                         case _OP_OR:\r
906                                 if(!IsFalse(STK(arg2))) {\r
907                                         TARGET = STK(arg2);\r
908                                         ci->_ip += (sarg1);\r
909                                 }\r
910                                 continue;\r
911                         case _OP_NEG: _GUARD(NEG_OP(TARGET,STK(arg1))); continue;\r
912                         case _OP_NOT: TARGET = (IsFalse(STK(arg1))?_true_:_false_); continue;\r
913                         case _OP_BWNOT:\r
914                                 if(type(STK(arg1)) == OT_INTEGER) {\r
915                                         SQInteger t = _integer(STK(arg1));\r
916                                         TARGET = SQInteger(~t);\r
917                                         continue;\r
918                                 }\r
919                                 Raise_Error(_SC("attempt to perform a bitwise op on a %s"), GetTypeName(STK(arg1)));\r
920                                 SQ_THROW();\r
921                         case _OP_CLOSURE: {\r
922                                 SQClosure *c = ci->_closure._unVal.pClosure;\r
923                                 SQFunctionProto *fp = c->_function._unVal.pFunctionProto;\r
924                                 if(!CLOSURE_OP(TARGET,fp->_functions[arg1]._unVal.pFunctionProto)) { SQ_THROW(); }\r
925                                 continue;\r
926                         }\r
927                         case _OP_YIELD:{\r
928                                 if(ci->_generator) {\r
929                                         if(sarg1 != MAX_FUNC_STACKSIZE) temp_reg = STK(arg1);\r
930                                         _GUARD(ci->_generator->Yield(this));\r
931                                         traps -= ci->_etraps;\r
932                                         if(sarg1 != MAX_FUNC_STACKSIZE) STK(arg1) = temp_reg;\r
933                                 }\r
934                                 else { Raise_Error(_SC("trying to yield a '%s',only genenerator can be yielded"), GetTypeName(ci->_generator)); SQ_THROW();}\r
935                                 if(Return(arg0, arg1, temp_reg)){\r
936                                         assert(traps == 0);\r
937                                         outres = temp_reg;\r
938                                         return true;\r
939                                 }\r
940                                         \r
941                                 }\r
942                                 continue;\r
943                         case _OP_RESUME:\r
944                                 if(type(STK(arg1)) != OT_GENERATOR){ Raise_Error(_SC("trying to resume a '%s',only genenerator can be resumed"), GetTypeName(STK(arg1))); SQ_THROW();}\r
945                                 _GUARD(_generator(STK(arg1))->Resume(this, arg0));\r
946                                 traps += ci->_etraps;\r
947                 continue;\r
948                         case _OP_FOREACH:{ int tojump;\r
949                                 _GUARD(FOREACH_OP(STK(arg0),STK(arg2),STK(arg2+1),STK(arg2+2),arg2,sarg1,tojump));\r
950                                 ci->_ip += tojump; }\r
951                                 continue;\r
952                         case _OP_POSTFOREACH:\r
953                                 assert(type(STK(arg0)) == OT_GENERATOR);\r
954                                 if(_generator(STK(arg0))->_state == SQGenerator::eDead) \r
955                                         ci->_ip += (sarg1 - 1);\r
956                                 continue;\r
957                         case _OP_DELEGATE: _GUARD(DELEGATE_OP(TARGET,STK(arg1),STK(arg2))); continue;\r
958                         case _OP_CLONE:\r
959                                 if(!Clone(STK(arg1), TARGET))\r
960                                 { Raise_Error(_SC("cloning a %s"), GetTypeName(STK(arg1))); SQ_THROW();}\r
961                                 continue;\r
962                         case _OP_TYPEOF: TypeOf(STK(arg1), TARGET); continue;\r
963                         case _OP_PUSHTRAP:{\r
964                                 SQInstruction *_iv = _funcproto(_closure(ci->_closure)->_function)->_instructions;\r
965                                 _etraps.push_back(SQExceptionTrap(_top,_stackbase, &_iv[(ci->_ip-_iv)+arg1], arg0)); traps++;\r
966                                 ci->_etraps++;\r
967                                                           }\r
968                                 continue;\r
969                         case _OP_POPTRAP: {\r
970                                 for(SQInteger i = 0; i < arg0; i++) {\r
971                                         _etraps.pop_back(); traps--;\r
972                                         ci->_etraps--;\r
973                                 }\r
974                                                           }\r
975                                 continue;\r
976                         case _OP_THROW: Raise_Error(TARGET); SQ_THROW(); continue;\r
977                         case _OP_CLASS: _GUARD(CLASS_OP(TARGET,arg1,arg2)); continue;\r
978                         case _OP_NEWSLOTA:\r
979                                 bool bstatic = (arg0&NEW_SLOT_STATIC_FLAG)?true:false;\r
980                                 if(type(STK(arg1)) == OT_CLASS) {\r
981                                         if(type(_class(STK(arg1))->_metamethods[MT_NEWMEMBER]) != OT_NULL ) {\r
982                                                 Push(STK(arg1)); Push(STK(arg2)); Push(STK(arg3));\r
983                                                 Push((arg0&NEW_SLOT_ATTRIBUTES_FLAG) ? STK(arg2-1) : _null_);\r
984                                                 Push(bstatic);\r
985                                                 int nparams = 5;\r
986                                                 if(Call(_class(STK(arg1))->_metamethods[MT_NEWMEMBER], nparams, _top - nparams, temp_reg,SQFalse)) {\r
987                                                         Pop(nparams);\r
988                                                         continue;\r
989                                                 }\r
990                                         }\r
991                                 }\r
992                                 _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3),bstatic));\r
993                                 if((arg0&NEW_SLOT_ATTRIBUTES_FLAG)) {\r
994                                         _class(STK(arg1))->SetAttributes(STK(arg2),STK(arg2-1));\r
995                                 }\r
996                                 continue;\r
997                         }\r
998                         \r
999                 }\r
1000         }\r
1001 exception_trap:\r
1002         {\r
1003                 SQObjectPtr currerror = _lasterror;\r
1004 //              dumpstack(_stackbase);\r
1005                 SQInteger n = 0;\r
1006                 SQInteger last_top = _top;\r
1007                 if(ci) {\r
1008                         if(_ss(this)->_notifyallexceptions) CallErrorHandler(currerror);\r
1009 \r
1010                         if(traps) {\r
1011                                 do {\r
1012                                         if(ci->_etraps > 0) {\r
1013                                                 SQExceptionTrap &et = _etraps.top();\r
1014                                                 ci->_ip = et._ip;\r
1015                                                 _top = et._stacksize;\r
1016                                                 _stackbase = et._stackbase;\r
1017                                                 _stack._vals[_stackbase+et._extarget] = currerror;\r
1018                                                 _etraps.pop_back(); traps--; ci->_etraps--;\r
1019                                                 CLEARSTACK(last_top);\r
1020                                                 goto exception_restore;\r
1021                                         }\r
1022                                         //if is a native closure\r
1023                                         if(type(ci->_closure) != OT_CLOSURE && n)\r
1024                                                 break;\r
1025                                         if(ci->_generator) ci->_generator->Kill();\r
1026                                         PopVarArgs(ci->_vargs);\r
1027                                         POP_CALLINFO(this);\r
1028                                         n++;\r
1029                                 } while(_callsstacksize);\r
1030                         }\r
1031                         else {\r
1032                                 //call the hook\r
1033                                 if(raiseerror && !_ss(this)->_notifyallexceptions)\r
1034                                         CallErrorHandler(currerror);\r
1035                         }\r
1036                         //remove call stack until a C function is found or the cstack is empty\r
1037                         if(ci) do {\r
1038                                 SQBool exitafterthisone = ci->_root;\r
1039                                 if(ci->_generator) ci->_generator->Kill();\r
1040                                 _stackbase -= ci->_prevstkbase;\r
1041                                 _top = _stackbase + ci->_prevtop;\r
1042                                 PopVarArgs(ci->_vargs);\r
1043                                 POP_CALLINFO(this);\r
1044                                 if( (ci && type(ci->_closure) != OT_CLOSURE) || exitafterthisone) break;\r
1045                         } while(_callsstacksize);\r
1046 \r
1047                         CLEARSTACK(last_top);\r
1048                 }\r
1049                 _lasterror = currerror;\r
1050                 return false;\r
1051         }\r
1052         assert(0);\r
1053 }\r
1054 \r
1055 bool SQVM::CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor)\r
1056 {\r
1057         inst = theclass->CreateInstance();\r
1058         if(!theclass->Get(_ss(this)->_constructoridx,constructor)) {\r
1059                 constructor = _null_;\r
1060         }\r
1061         return true;\r
1062 }\r
1063 \r
1064 void SQVM::CallErrorHandler(SQObjectPtr &error)\r
1065 {\r
1066         if(type(_errorhandler) != OT_NULL) {\r
1067                 SQObjectPtr out;\r
1068                 Push(_roottable); Push(error);\r
1069                 Call(_errorhandler, 2, _top-2, out,SQFalse);\r
1070                 Pop(2);\r
1071         }\r
1072 }\r
1073 \r
1074 void SQVM::CallDebugHook(SQInteger type,SQInteger forcedline)\r
1075 {\r
1076         SQObjectPtr temp_reg;\r
1077         SQInteger nparams=5;\r
1078         SQFunctionProto *func=_funcproto(_closure(ci->_closure)->_function);\r
1079         Push(_roottable); Push(type); Push(func->_sourcename); Push(forcedline?forcedline:func->GetLine(ci->_ip)); Push(func->_name);\r
1080         Call(_debughook,nparams,_top-nparams,temp_reg,SQFalse);\r
1081         Pop(nparams);\r
1082 }\r
1083 \r
1084 bool SQVM::CallNative(SQNativeClosure *nclosure,SQInteger nargs,SQInteger stackbase,SQObjectPtr &retval,bool &suspend)\r
1085 {\r
1086         if (_nnativecalls + 1 > MAX_NATIVE_CALLS) { Raise_Error(_SC("Native stack overflow")); return false; }\r
1087         SQInteger nparamscheck = nclosure->_nparamscheck;\r
1088         if(((nparamscheck > 0) && (nparamscheck != nargs))\r
1089                 || ((nparamscheck < 0) && (nargs < (-nparamscheck)))) {\r
1090                 Raise_Error(_SC("wrong number of parameters"));\r
1091                 return false;\r
1092                 }\r
1093 \r
1094         SQInteger tcs;\r
1095         if((tcs = nclosure->_typecheck.size())) {\r
1096                 for(SQInteger i = 0; i < nargs && i < tcs; i++)\r
1097                         if((nclosure->_typecheck._vals[i] != -1) && !(type(_stack._vals[stackbase+i]) & nclosure->_typecheck[i])) {\r
1098                 Raise_ParamTypeError(i,nclosure->_typecheck._vals[i],type(_stack._vals[stackbase+i]));\r
1099                                 return false;\r
1100                         }\r
1101         }\r
1102         _nnativecalls++;\r
1103         if ((_top + MIN_STACK_OVERHEAD) > (SQInteger)_stack.size()) {\r
1104                 _stack.resize(_stack.size() + (MIN_STACK_OVERHEAD<<1));\r
1105         }\r
1106         SQInteger oldtop = _top;\r
1107         SQInteger oldstackbase = _stackbase;\r
1108         _top = stackbase + nargs;\r
1109         CallInfo lci;\r
1110         lci._closure = nclosure;\r
1111         lci._generator = NULL;\r
1112         lci._etraps = 0;\r
1113         lci._prevstkbase = (SQInt32) (stackbase - _stackbase);\r
1114         lci._ncalls = 1;\r
1115         lci._prevtop = (SQInt32) (oldtop - oldstackbase);\r
1116         PUSH_CALLINFO(this, lci);\r
1117         _stackbase = stackbase;\r
1118         //push free variables\r
1119         SQInteger outers = nclosure->_outervalues.size();\r
1120         for (SQInteger i = 0; i < outers; i++) {\r
1121                 Push(nclosure->_outervalues[i]);\r
1122         }\r
1123 \r
1124         if(type(nclosure->_env) == OT_WEAKREF) {\r
1125                 _stack[stackbase] = _weakref(nclosure->_env)->_obj;\r
1126         }\r
1127 \r
1128         \r
1129         SQInteger ret = (nclosure->_function)(this);\r
1130         _nnativecalls--;\r
1131         suspend = false;\r
1132         if( ret == SQ_SUSPEND_FLAG) suspend = true;\r
1133         else if (ret < 0) { \r
1134                 _stackbase = oldstackbase;\r
1135                 _top = oldtop;\r
1136                 POP_CALLINFO(this);\r
1137                 Raise_Error(_lasterror);\r
1138                 return false;\r
1139         }\r
1140         \r
1141         if (ret != 0){ retval = TOP(); TOP().Null(); }\r
1142         else { retval = _null_; }\r
1143         _stackbase = oldstackbase;\r
1144         _top = oldtop;\r
1145         POP_CALLINFO(this);\r
1146         return true;\r
1147 }\r
1148 \r
1149 bool SQVM::Get(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw, bool fetchroot)\r
1150 {\r
1151         switch(type(self)){\r
1152         case OT_TABLE:\r
1153                 if(_table(self)->Get(key,dest))return true;\r
1154                 break;\r
1155         case OT_ARRAY:\r
1156                 if(sq_isnumeric(key)){\r
1157                         return _array(self)->Get(tointeger(key),dest);\r
1158                 }\r
1159                 break;\r
1160         case OT_INSTANCE:\r
1161                 if(_instance(self)->Get(key,dest)) return true;\r
1162                 break;\r
1163         default:break; //shut up compiler\r
1164         }\r
1165         if(FallBackGet(self,key,dest,raw)) return true;\r
1166 \r
1167         if(fetchroot) {\r
1168                 if(_rawval(STK(0)) == _rawval(self) &&\r
1169                         type(STK(0)) == type(self)) {\r
1170                                 return _table(_roottable)->Get(key,dest);\r
1171                 }\r
1172         }\r
1173         return false;\r
1174 }\r
1175 \r
1176 bool SQVM::FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw)\r
1177 {\r
1178         switch(type(self)){\r
1179         case OT_CLASS: \r
1180                 return _class(self)->Get(key,dest);\r
1181                 break;\r
1182         case OT_TABLE:\r
1183         case OT_USERDATA:\r
1184         //delegation\r
1185                 if(_delegable(self)->_delegate) {\r
1186                         if(Get(SQObjectPtr(_delegable(self)->_delegate),key,dest,raw,false))\r
1187                                 return true;    \r
1188                         if(raw)return false;\r
1189                         Push(self);Push(key);\r
1190                         if(CallMetaMethod(_delegable(self),MT_GET,2,dest))\r
1191                                 return true;\r
1192                 }\r
1193                 if(type(self) == OT_TABLE) {\r
1194                         if(raw) return false;\r
1195                         return _table_ddel->Get(key,dest);\r
1196                 }\r
1197                 return false;\r
1198                 break;\r
1199         case OT_ARRAY:\r
1200                 if(raw)return false;\r
1201                 return _array_ddel->Get(key,dest);\r
1202         case OT_STRING:\r
1203                 if(sq_isnumeric(key)){\r
1204                         SQInteger n=tointeger(key);\r
1205                         if(abs((int)n)<_string(self)->_len){\r
1206                                 if(n<0)n=_string(self)->_len-n;\r
1207                                 dest=SQInteger(_stringval(self)[n]);\r
1208                                 return true;\r
1209                         }\r
1210                         return false;\r
1211                 }\r
1212                 else {\r
1213                         if(raw)return false;\r
1214                         return _string_ddel->Get(key,dest);\r
1215                 }\r
1216                 break;\r
1217         case OT_INSTANCE:\r
1218                 if(raw)return false;\r
1219                 Push(self);Push(key);\r
1220                 if(!CallMetaMethod(_delegable(self),MT_GET,2,dest)) {\r
1221                         return _instance_ddel->Get(key,dest);\r
1222                 }\r
1223                 return true;\r
1224         case OT_INTEGER:case OT_FLOAT:case OT_BOOL: \r
1225                 if(raw)return false;\r
1226                 return _number_ddel->Get(key,dest);\r
1227         case OT_GENERATOR: \r
1228                 if(raw)return false;\r
1229                 return _generator_ddel->Get(key,dest);\r
1230         case OT_CLOSURE: case OT_NATIVECLOSURE: \r
1231                 if(raw)return false;\r
1232                 return _closure_ddel->Get(key,dest);\r
1233         case OT_THREAD:\r
1234                 if(raw)return false;\r
1235                 return  _thread_ddel->Get(key,dest);\r
1236         case OT_WEAKREF:\r
1237                 if(raw)return false;\r
1238                 return  _weakref_ddel->Get(key,dest);\r
1239         default:return false;\r
1240         }\r
1241         return false;\r
1242 }\r
1243 \r
1244 bool SQVM::Set(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,bool fetchroot)\r
1245 {\r
1246         switch(type(self)){\r
1247         case OT_TABLE:\r
1248                 if(_table(self)->Set(key,val))\r
1249                         return true;\r
1250                 if(_table(self)->_delegate) {\r
1251                         if(Set(_table(self)->_delegate,key,val,false)) {\r
1252                                 return true;\r
1253                         }\r
1254                 }\r
1255                 //keeps going\r
1256         case OT_USERDATA:\r
1257                 if(_delegable(self)->_delegate) {\r
1258                         SQObjectPtr t;\r
1259                         Push(self);Push(key);Push(val);\r
1260                         if(CallMetaMethod(_delegable(self),MT_SET,3,t)) return true;\r
1261                 }\r
1262                 break;\r
1263         case OT_INSTANCE:{\r
1264                 if(_instance(self)->Set(key,val))\r
1265                         return true;\r
1266                 SQObjectPtr t;\r
1267                 Push(self);Push(key);Push(val);\r
1268                 if(CallMetaMethod(_delegable(self),MT_SET,3,t)) return true;\r
1269                 }\r
1270                 break;\r
1271         case OT_ARRAY:\r
1272                 if(!sq_isnumeric(key)) {Raise_Error(_SC("indexing %s with %s"),GetTypeName(self),GetTypeName(key)); return false; }\r
1273                 return _array(self)->Set(tointeger(key),val);\r
1274         default:\r
1275                 Raise_Error(_SC("trying to set '%s'"),GetTypeName(self));\r
1276                 return false;\r
1277         }\r
1278         if(fetchroot) {\r
1279                 if(_rawval(STK(0)) == _rawval(self) &&\r
1280                         type(STK(0)) == type(self)) {\r
1281                                 return _table(_roottable)->Set(key,val);\r
1282                         }\r
1283         }\r
1284         return false;\r
1285 }\r
1286 \r
1287 bool SQVM::Clone(const SQObjectPtr &self,SQObjectPtr &target)\r
1288 {\r
1289         SQObjectPtr temp_reg;\r
1290         SQObjectPtr newobj;\r
1291         switch(type(self)){\r
1292         case OT_TABLE:\r
1293                 newobj = _table(self)->Clone();\r
1294                 goto cloned_mt;\r
1295         case OT_INSTANCE:\r
1296                 newobj = _instance(self)->Clone(_ss(this));\r
1297 cloned_mt:\r
1298                 if(_delegable(newobj)->_delegate){\r
1299                         Push(newobj);\r
1300                         Push(self);\r
1301                         CallMetaMethod(_delegable(newobj),MT_CLONED,2,temp_reg);\r
1302                 }\r
1303                 target = newobj;\r
1304                 return true;\r
1305         case OT_ARRAY: \r
1306                 target = _array(self)->Clone();\r
1307                 return true;\r
1308         default: return false;\r
1309         }\r
1310 }\r
1311 \r
1312 bool SQVM::NewSlot(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic)\r
1313 {\r
1314         if(type(key) == OT_NULL) { Raise_Error(_SC("null cannot be used as index")); return false; }\r
1315         switch(type(self)) {\r
1316         case OT_TABLE: {\r
1317                 bool rawcall = true;\r
1318                 if(_table(self)->_delegate) {\r
1319                         SQObjectPtr res;\r
1320                         if(!_table(self)->Get(key,res)) {\r
1321                                 Push(self);Push(key);Push(val);\r
1322                                 rawcall = !CallMetaMethod(_table(self),MT_NEWSLOT,3,res);\r
1323                         }\r
1324                 }\r
1325                 if(rawcall) _table(self)->NewSlot(key,val); //cannot fail\r
1326                 \r
1327                 break;}\r
1328         case OT_INSTANCE: {\r
1329                 SQObjectPtr res;\r
1330                 Push(self);Push(key);Push(val);\r
1331                 if(!CallMetaMethod(_instance(self),MT_NEWSLOT,3,res)) {\r
1332                         Raise_Error(_SC("class instances do not support the new slot operator"));\r
1333                         return false;\r
1334                 }\r
1335                 break;}\r
1336         case OT_CLASS: \r
1337                 if(!_class(self)->NewSlot(_ss(this),key,val,bstatic)) {\r
1338                         if(_class(self)->_locked) {\r
1339                                 Raise_Error(_SC("trying to modify a class that has already been instantiated"));\r
1340                                 return false;\r
1341                         }\r
1342                         else {\r
1343                                 SQObjectPtr oval = PrintObjVal(key);\r
1344                                 Raise_Error(_SC("the property '%s' already exists"),_stringval(oval));\r
1345                                 return false;\r
1346                         }\r
1347                 }\r
1348                 break;\r
1349         default:\r
1350                 Raise_Error(_SC("indexing %s with %s"),GetTypeName(self),GetTypeName(key));\r
1351                 return false;\r
1352                 break;\r
1353         }\r
1354         return true;\r
1355 }\r
1356 \r
1357 bool SQVM::DeleteSlot(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &res)\r
1358 {\r
1359         switch(type(self)) {\r
1360         case OT_TABLE:\r
1361         case OT_INSTANCE:\r
1362         case OT_USERDATA: {\r
1363                 SQObjectPtr t;\r
1364                 bool handled = false;\r
1365                 if(_delegable(self)->_delegate) {\r
1366                         Push(self);Push(key);\r
1367                         handled = CallMetaMethod(_delegable(self),MT_DELSLOT,2,t);\r
1368                 }\r
1369 \r
1370                 if(!handled) {\r
1371                         if(type(self) == OT_TABLE) {\r
1372                                 if(_table(self)->Get(key,t)) {\r
1373                                         _table(self)->Remove(key);\r
1374                                 }\r
1375                                 else {\r
1376                                         Raise_IdxError((SQObject &)key);\r
1377                                         return false;\r
1378                                 }\r
1379                         }\r
1380                         else {\r
1381                                 Raise_Error(_SC("cannot delete a slot from %s"),GetTypeName(self));\r
1382                                 return false;\r
1383                         }\r
1384                 }\r
1385                 res = t;\r
1386                                 }\r
1387                 break;\r
1388         default:\r
1389                 Raise_Error(_SC("attempt to delete a slot from a %s"),GetTypeName(self));\r
1390                 return false;\r
1391         }\r
1392         return true;\r
1393 }\r
1394 \r
1395 bool SQVM::Call(SQObjectPtr &closure,SQInteger nparams,SQInteger stackbase,SQObjectPtr &outres,SQBool raiseerror)\r
1396 {\r
1397 #ifdef _DEBUG\r
1398 SQInteger prevstackbase = _stackbase;\r
1399 #endif\r
1400         switch(type(closure)) {\r
1401         case OT_CLOSURE:\r
1402                 return Execute(closure, _top - nparams, nparams, stackbase,outres,raiseerror);\r
1403                 break;\r
1404         case OT_NATIVECLOSURE:{\r
1405                 bool suspend;\r
1406                 return CallNative(_nativeclosure(closure), nparams, stackbase, outres,suspend);\r
1407                 \r
1408                                                   }\r
1409                 break;\r
1410         case OT_CLASS: {\r
1411                 SQObjectPtr constr;\r
1412                 SQObjectPtr temp;\r
1413                 CreateClassInstance(_class(closure),outres,constr);\r
1414                 if(type(constr) != OT_NULL) {\r
1415                         _stack[stackbase] = outres;\r
1416                         return Call(constr,nparams,stackbase,temp,raiseerror);\r
1417                 }\r
1418                 return true;\r
1419                                    }\r
1420                 break;\r
1421         default:\r
1422                 return false;\r
1423         }\r
1424 #ifdef _DEBUG\r
1425         if(!_suspended) {\r
1426                 assert(_stackbase == prevstackbase);\r
1427         }\r
1428 #endif\r
1429         return true;\r
1430 }\r
1431 \r
1432 bool SQVM::CallMetaMethod(SQDelegable *del,SQMetaMethod mm,SQInteger nparams,SQObjectPtr &outres)\r
1433 {\r
1434         SQObjectPtr closure;\r
1435         if(del->GetMetaMethod(this, mm, closure)) {\r
1436                 if(Call(closure, nparams, _top - nparams, outres, SQFalse)) {\r
1437                         Pop(nparams);\r
1438                         return true;\r
1439                 }\r
1440         }\r
1441         Pop(nparams);\r
1442         return false;\r
1443 }\r
1444 \r
1445 void SQVM::Remove(SQInteger n) {\r
1446         n = (n >= 0)?n + _stackbase - 1:_top + n;\r
1447         for(SQInteger i = n; i < _top; i++){\r
1448                 _stack[i] = _stack[i+1];\r
1449         }\r
1450         _stack[_top] = _null_;\r
1451         _top--;\r
1452 }\r
1453 \r
1454 void SQVM::Pop() {\r
1455         _stack[--_top] = _null_;\r
1456 }\r
1457 \r
1458 void SQVM::Pop(SQInteger n) {\r
1459         for(SQInteger i = 0; i < n; i++){\r
1460                 _stack[--_top] = _null_;\r
1461         }\r
1462 }\r
1463 \r
1464 void SQVM::Push(const SQObjectPtr &o) { _stack[_top++] = o; }\r
1465 SQObjectPtr &SQVM::Top() { return _stack[_top-1]; }\r
1466 SQObjectPtr &SQVM::PopGet() { return _stack[--_top]; }\r
1467 SQObjectPtr &SQVM::GetUp(SQInteger n) { return _stack[_top+n]; }\r
1468 SQObjectPtr &SQVM::GetAt(SQInteger n) { return _stack[n]; }\r
1469 \r
1470 #ifdef _DEBUG_DUMP\r
1471 void SQVM::dumpstack(SQInteger stackbase,bool dumpall)\r
1472 {\r
1473         SQInteger size=dumpall?_stack.size():_top;\r
1474         SQInteger n=0;\r
1475         scprintf(_SC("\n>>>>stack dump<<<<\n"));\r
1476         CallInfo &ci=_callsstack[_callsstacksize-1];\r
1477         scprintf(_SC("IP: %p\n"),ci._ip);\r
1478         scprintf(_SC("prev stack base: %d\n"),ci._prevstkbase);\r
1479         scprintf(_SC("prev top: %d\n"),ci._prevtop);\r
1480         for(SQInteger i=0;i<size;i++){\r
1481                 SQObjectPtr &obj=_stack[i];     \r
1482                 if(stackbase==i)scprintf(_SC(">"));else scprintf(_SC(" "));\r
1483                 scprintf(_SC("[%d]:"),n);\r
1484                 switch(type(obj)){\r
1485                 case OT_FLOAT:                  scprintf(_SC("FLOAT %.3f"),_float(obj));break;\r
1486                 case OT_INTEGER:                scprintf(_SC("INTEGER %d"),_integer(obj));break;\r
1487                 case OT_BOOL:                   scprintf(_SC("BOOL %s"),_integer(obj)?"true":"false");break;\r
1488                 case OT_STRING:                 scprintf(_SC("STRING %s"),_stringval(obj));break;\r
1489                 case OT_NULL:                   scprintf(_SC("NULL"));  break;\r
1490                 case OT_TABLE:                  scprintf(_SC("TABLE %p[%p]"),_table(obj),_table(obj)->_delegate);break;\r
1491                 case OT_ARRAY:                  scprintf(_SC("ARRAY %p"),_array(obj));break;\r
1492                 case OT_CLOSURE:                scprintf(_SC("CLOSURE [%p]"),_closure(obj));break;\r
1493                 case OT_NATIVECLOSURE:  scprintf(_SC("NATIVECLOSURE"));break;\r
1494                 case OT_USERDATA:               scprintf(_SC("USERDATA %p[%p]"),_userdataval(obj),_userdata(obj)->_delegate);break;\r
1495                 case OT_GENERATOR:              scprintf(_SC("GENERATOR %p"),_generator(obj));break;\r
1496                 case OT_THREAD:                 scprintf(_SC("THREAD [%p]"),_thread(obj));break;\r
1497                 case OT_USERPOINTER:    scprintf(_SC("USERPOINTER %p"),_userpointer(obj));break;\r
1498                 case OT_CLASS:                  scprintf(_SC("CLASS %p"),_class(obj));break;\r
1499                 case OT_INSTANCE:               scprintf(_SC("INSTANCE %p"),_instance(obj));break;\r
1500                 case OT_WEAKREF:                scprintf(_SC("WEAKERF %p"),_weakref(obj));break;\r
1501                 default:\r
1502                         assert(0);\r
1503                         break;\r
1504                 };\r
1505                 scprintf(_SC("\n"));\r
1506                 ++n;\r
1507         }\r
1508 }\r
1509 \r
1510 \r
1511 \r
1512 #endif\r