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