- More work on scripting interface
[supertux.git] / src / squirrel / squirrel / sqapi.cpp
1 /*\r
2         see copyright notice in squirrel.h\r
3 */\r
4 #include "sqpcheader.h"\r
5 #include "sqvm.h"\r
6 #include "sqstring.h"\r
7 #include "sqtable.h"\r
8 #include "sqarray.h"\r
9 #include "sqfuncproto.h"\r
10 #include "sqclosure.h"\r
11 #include "squserdata.h"\r
12 #include "sqfuncstate.h"\r
13 #include "sqcompiler.h"\r
14 #include "sqclass.h"\r
15 \r
16 bool sq_aux_gettypedarg(HSQUIRRELVM v,int idx,SQObjectType type,SQObjectPtr **o)\r
17 {\r
18         *o = &stack_get(v,idx);\r
19         if(type(**o) != type){\r
20                 SQObjectPtr oval = v->PrintObjVal(**o);\r
21                 v->Raise_Error(_SC("wrong argument type, expected '%s' got '%.50s'"),IdType2Name(type),_stringval(oval));\r
22                 return false;\r
23         }\r
24         return true;\r
25 }\r
26 \r
27 #define _GETSAFE_OBJ(v,idx,type,o) { if(!sq_aux_gettypedarg(v,idx,type,&o)) return SQ_ERROR; }\r
28 \r
29 #define sq_aux_paramscheck(v,count) \\r
30 { \\r
31         if(sq_gettop(v) < count){ v->Raise_Error(_SC("not enough params in the stack")); return SQ_ERROR; }\\r
32 }               \r
33 \r
34 int sq_aux_throwobject(HSQUIRRELVM v,SQObjectPtr &e)\r
35 {\r
36         v->_lasterror = e;\r
37         return SQ_ERROR;\r
38 }\r
39 \r
40 int sq_aux_invalidtype(HSQUIRRELVM v,SQObjectType type)\r
41 {\r
42         scsprintf(_ss(v)->GetScratchPad(100), _SC("unexpected type %s"), IdType2Name(type));\r
43         return sq_throwerror(v, _ss(v)->GetScratchPad(-1));\r
44 }\r
45 \r
46 HSQUIRRELVM sq_open(int initialstacksize)\r
47 {\r
48         SQSharedState *ss;\r
49         SQVM *v;\r
50         sq_new(ss, SQSharedState);\r
51         ss->Init();\r
52         v = (SQVM *)SQ_MALLOC(sizeof(SQVM));\r
53         new (v) SQVM(ss);\r
54         ss->_root_vm = v;\r
55         if(v->Init(NULL, initialstacksize)) {\r
56                 return v;\r
57         } else {\r
58                 sq_delete(v, SQVM);\r
59                 return NULL;\r
60         }\r
61         return v;\r
62 }\r
63 \r
64 HSQUIRRELVM sq_newthread(HSQUIRRELVM friendvm, int initialstacksize)\r
65 {\r
66         SQSharedState *ss;\r
67         SQVM *v;\r
68         ss=_ss(friendvm);\r
69         \r
70         v= (SQVM *)SQ_MALLOC(sizeof(SQVM));\r
71         new (v) SQVM(ss);\r
72         \r
73         if(v->Init(friendvm, initialstacksize)) {\r
74                 friendvm->Push(v);\r
75                 return v;\r
76         } else {\r
77                 sq_delete(v, SQVM);\r
78                 return NULL;\r
79         }\r
80 }\r
81 \r
82 int sq_getvmstate(HSQUIRRELVM v)\r
83 {\r
84         if(v->_suspended)\r
85                 return SQ_VMSTATE_SUSPENDED;\r
86         else { \r
87                 if(v->_callsstack.size() != 0) return SQ_VMSTATE_RUNNING;\r
88                 else return SQ_VMSTATE_IDLE;\r
89         }\r
90 }\r
91 \r
92 void sq_seterrorhandler(HSQUIRRELVM v)\r
93 {\r
94         SQObject o = stack_get(v, -1);\r
95         if(sq_isclosure(o) || sq_isnativeclosure(o) || sq_isnull(o)) {\r
96                 v->_errorhandler = o;\r
97                 v->Pop();\r
98         }\r
99 }\r
100 \r
101 void sq_setdebughook(HSQUIRRELVM v)\r
102 {\r
103         SQObject o = stack_get(v,-1);\r
104         if(sq_isclosure(o) || sq_isnativeclosure(o) || sq_isnull(o)) {\r
105                 v->_debughook = o;\r
106                 v->Pop();\r
107         }\r
108 }\r
109 \r
110 void sq_close(HSQUIRRELVM v)\r
111 {\r
112         SQSharedState *ss = _ss(v);\r
113         _thread(ss->_root_vm)->Finalize();\r
114         sq_delete(ss, SQSharedState);\r
115 }\r
116 \r
117 SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,const SQChar *sourcename,SQBool raiseerror)\r
118 {\r
119         SQObjectPtr o;\r
120         if(Compile(v, read, p, sourcename, o, raiseerror?true:false, _ss(v)->_debuginfo)) {\r
121                 v->Push(SQClosure::Create(_ss(v), _funcproto(o)));\r
122                 return SQ_OK;\r
123         }\r
124         return SQ_ERROR;\r
125 }\r
126 \r
127 void sq_enabledebuginfo(HSQUIRRELVM v, SQBool debuginfo)\r
128 {\r
129         _ss(v)->_debuginfo = debuginfo?true:false;\r
130 }\r
131 \r
132 void sq_addref(HSQUIRRELVM v,HSQOBJECT *po)\r
133 {\r
134         SQObjectPtr refs;\r
135         if(!ISREFCOUNTED(type(*po))) return;\r
136         if(_table(_ss(v)->_refs_table)->Get(*po, refs)) {\r
137                 refs = _integer(refs) + 1;\r
138         }\r
139         else{\r
140                 refs = 1;\r
141         }\r
142         _table(_ss(v)->_refs_table)->NewSlot(*po, refs);\r
143 }\r
144 \r
145 SQBool sq_release(HSQUIRRELVM v,HSQOBJECT *po)\r
146 {\r
147         SQObjectPtr refs;\r
148         if(!ISREFCOUNTED(type(*po))) return SQTrue;\r
149         if(_table(_ss(v)->_refs_table)->Get(*po, refs)) {\r
150                 int n = _integer(refs) - 1;\r
151                 if(n <= 0) {\r
152                         _table(_ss(v)->_refs_table)->Remove(*po);\r
153                         sq_resetobject(po);\r
154                 }\r
155                 else {\r
156                         refs = n;_table(_ss(v)->_refs_table)->Set(*po, refs);\r
157                         return SQFalse;\r
158                 }\r
159         }\r
160         return SQTrue;\r
161 }\r
162 \r
163 const SQChar *sq_objtostring(HSQOBJECT *o) \r
164 {\r
165         if(sq_type(*o) == OT_STRING) {\r
166                 return o->_unVal.pString->_val;\r
167         }\r
168         return NULL;\r
169 }\r
170 \r
171 SQInteger sq_objtointeger(HSQOBJECT *o) \r
172 {\r
173         if(sq_isnumeric(*o)) {\r
174                 return tointeger(*o);\r
175         }\r
176         return 0;\r
177 }\r
178 \r
179 SQFloat sq_objtofloat(HSQOBJECT *o) \r
180 {\r
181         if(sq_isnumeric(*o)) {\r
182                 return tofloat(*o);\r
183         }\r
184         return 0;\r
185 }\r
186 \r
187 void sq_pushnull(HSQUIRRELVM v)\r
188 {\r
189         v->Push(_null_);\r
190 }\r
191 \r
192 void sq_pushstring(HSQUIRRELVM v,const SQChar *s,int len)\r
193 {\r
194         if(s)\r
195                 v->Push(SQObjectPtr(SQString::Create(_ss(v), s, len)));\r
196         else v->Push(_null_);\r
197 }\r
198 \r
199 void sq_pushinteger(HSQUIRRELVM v,SQInteger n)\r
200 {\r
201         v->Push(n);\r
202 }\r
203 \r
204 void sq_pushbool(HSQUIRRELVM v,SQBool b)\r
205 {\r
206         v->Push(b?true:false);\r
207 }\r
208 \r
209 void sq_pushfloat(HSQUIRRELVM v,SQFloat n)\r
210 {\r
211         v->Push(n);\r
212 }\r
213 \r
214 void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p)\r
215 {\r
216         v->Push(p);\r
217 }\r
218 \r
219 SQUserPointer sq_newuserdata(HSQUIRRELVM v,unsigned int size)\r
220 {\r
221         SQUserData *ud = SQUserData::Create(_ss(v), size);\r
222         v->Push(ud);\r
223         return ud->_val;\r
224 }\r
225 \r
226 void sq_newtable(HSQUIRRELVM v)\r
227 {\r
228         v->Push(SQTable::Create(_ss(v), 0));    \r
229 }\r
230 \r
231 void sq_newarray(HSQUIRRELVM v,int size)\r
232 {\r
233         v->Push(SQArray::Create(_ss(v), size)); \r
234 }\r
235 \r
236 SQRESULT sq_newclass(HSQUIRRELVM v,SQBool hasbase)\r
237 {\r
238         SQClass *baseclass = NULL;\r
239         if(hasbase) {\r
240                 SQObjectPtr &base = stack_get(v,-1);\r
241                 if(type(base) != OT_CLASS)\r
242                         return sq_throwerror(v,_SC("invalid base type"));\r
243                 baseclass = _class(base);\r
244         }\r
245         SQClass *newclass = SQClass::Create(_ss(v), baseclass);\r
246         if(baseclass) v->Pop();\r
247         v->Push(newclass);      \r
248         return SQ_OK;\r
249 }\r
250 \r
251 int sq_instanceof(HSQUIRRELVM v)\r
252 {\r
253         SQObjectPtr &inst = stack_get(v,-1);\r
254         SQObjectPtr &cl = stack_get(v,-2);\r
255         if(type(inst) != OT_INSTANCE || type(cl) != OT_CLASS)\r
256                 return sq_throwerror(v,_SC("invalid param type"));\r
257         return _instance(inst)->InstanceOf(_class(cl))?1:0;\r
258 }\r
259 \r
260 SQRESULT sq_arrayappend(HSQUIRRELVM v,int idx)\r
261 {\r
262         sq_aux_paramscheck(v,2);\r
263         SQObjectPtr *arr;\r
264         _GETSAFE_OBJ(v, idx, OT_ARRAY,arr);\r
265         _array(*arr)->Append(v->GetUp(-1));\r
266         v->Pop(1);\r
267         return SQ_OK;\r
268 }\r
269 \r
270 SQRESULT sq_arraypop(HSQUIRRELVM v,int idx,SQBool pushval)\r
271 {\r
272         sq_aux_paramscheck(v, 1);\r
273         SQObjectPtr *arr;\r
274         _GETSAFE_OBJ(v, idx, OT_ARRAY,arr);\r
275         if(_array(*arr)->Size() > 0) {\r
276         if(pushval != 0){ v->Push(_array(*arr)->Top()); }\r
277                 _array(*arr)->Pop();\r
278                 return SQ_OK;\r
279         }\r
280         return sq_throwerror(v, _SC("empty array"));\r
281 }\r
282 \r
283 SQRESULT sq_arrayresize(HSQUIRRELVM v,int idx,int newsize)\r
284 {\r
285         sq_aux_paramscheck(v,1);\r
286         SQObjectPtr *arr;\r
287         _GETSAFE_OBJ(v, idx, OT_ARRAY,arr);\r
288         if(_array(*arr)->Size() > 0) {\r
289                 _array(*arr)->Resize(newsize);\r
290                 return SQ_OK;\r
291         }\r
292         return sq_throwerror(v, _SC("empty array"));\r
293 }\r
294 \r
295 SQRESULT sq_arrayreverse(HSQUIRRELVM v,int idx)\r
296 {\r
297         sq_aux_paramscheck(v, 1);\r
298         SQObjectPtr *o;\r
299         _GETSAFE_OBJ(v, idx, OT_ARRAY,o);\r
300         SQArray *arr = _array(*o);\r
301         if(arr->Size() > 0) {\r
302                 SQObjectPtr t;\r
303                 int size = arr->Size();\r
304                 int n = size >> 1; size -= 1;\r
305                 for(int i = 0; i < n; i++) {\r
306                         t = arr->_values[i];\r
307                         arr->_values[i] = arr->_values[size-i];\r
308                         arr->_values[size-i] = t;\r
309                 }\r
310                 return SQ_OK;\r
311         }\r
312         return sq_throwerror(v, _SC("empty array"));\r
313 }\r
314 \r
315 void sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,unsigned int nfreevars)\r
316 {\r
317         SQNativeClosure *nc = SQNativeClosure::Create(_ss(v), func);\r
318         nc->_nparamscheck = 0;\r
319         for(unsigned int i = 0; i < nfreevars; i++) {\r
320                 nc->_outervalues.push_back(v->Top());\r
321                 v->Pop();\r
322         }\r
323         v->Push(SQObjectPtr(nc));       \r
324 }\r
325 \r
326 SQRESULT sq_getclosureinfo(HSQUIRRELVM v,int idx,unsigned int *nparams,unsigned int *nfreevars)\r
327 {\r
328         SQObject o = stack_get(v, idx);\r
329         if(sq_isclosure(o)) {\r
330                 SQClosure *c = _closure(o);\r
331                 SQFunctionProto *proto = _funcproto(c->_function);\r
332                 *nparams = (unsigned int)proto->_parameters.size();\r
333         *nfreevars = (unsigned int)c->_outervalues.size();\r
334                 return SQ_OK;\r
335         }\r
336         return sq_throwerror(v,_SC("the object is not a closure"));\r
337 }\r
338 \r
339 SQRESULT sq_setnativeclosurename(HSQUIRRELVM v,int idx,const SQChar *name)\r
340 {\r
341         SQObject o = stack_get(v, idx);\r
342         if(sq_isnativeclosure(o)) {\r
343                 SQNativeClosure *nc = _nativeclosure(o);\r
344                 nc->_name = SQString::Create(_ss(v),name);\r
345                 return SQ_OK;\r
346         }\r
347         return sq_throwerror(v,_SC("the object is not a nativeclosure"));\r
348 }\r
349 \r
350 SQRESULT sq_setparamscheck(HSQUIRRELVM v,int nparamscheck,const SQChar *typemask)\r
351 {\r
352         SQObject o = stack_get(v, -1);\r
353         if(!sq_isnativeclosure(o))\r
354                 return sq_throwerror(v, _SC("native closure expected"));\r
355         SQNativeClosure *nc = _nativeclosure(o);\r
356         nc->_nparamscheck = nparamscheck;\r
357         if(typemask) {\r
358                 SQIntVec res;\r
359                 if(!CompileTypemask(res, typemask))\r
360                         return sq_throwerror(v, _SC("invalid typemask"));\r
361                 nc->_typecheck.copy(res);\r
362         }\r
363         else {\r
364                 nc->_typecheck.resize(0);\r
365         }\r
366         return SQ_OK;\r
367 }\r
368 \r
369 void sq_pushroottable(HSQUIRRELVM v)\r
370 {\r
371         v->Push(v->_roottable);\r
372 }\r
373 \r
374 void sq_pushregistrytable(HSQUIRRELVM v)\r
375 {\r
376         v->Push(_ss(v)->_registry);\r
377 }\r
378 \r
379 SQRESULT sq_setroottable(HSQUIRRELVM v)\r
380 {\r
381         SQObject o = stack_get(v, -1);\r
382         if(sq_istable(o) || sq_isnull(o)) {\r
383                 v->_roottable = o;\r
384                 v->Pop();\r
385                 return SQ_OK;\r
386         }\r
387         return sq_throwerror(v, _SC("ivalid type"));\r
388 }\r
389 \r
390 void sq_setforeignptr(HSQUIRRELVM v,SQUserPointer p)\r
391 {\r
392         v->_foreignptr = p;\r
393 }\r
394 \r
395 SQUserPointer sq_getforeignptr(HSQUIRRELVM v)\r
396 {\r
397         return v->_foreignptr;\r
398 }\r
399 \r
400 void sq_push(HSQUIRRELVM v,int idx)\r
401 {\r
402         v->Push(stack_get(v, idx));\r
403 }\r
404 \r
405 SQObjectType sq_gettype(HSQUIRRELVM v,int idx)\r
406 {\r
407         return type(stack_get(v, idx));\r
408 }\r
409 \r
410 SQRESULT sq_getinteger(HSQUIRRELVM v,int idx,SQInteger *i)\r
411 {\r
412         SQObjectPtr &o = stack_get(v, idx);\r
413         if(sq_isnumeric(o)) {\r
414                 *i = tointeger(o);\r
415                 return SQ_OK;\r
416         }\r
417         return SQ_ERROR;\r
418 }\r
419 \r
420 SQRESULT sq_getfloat(HSQUIRRELVM v,int idx,SQFloat *f)\r
421 {\r
422         SQObjectPtr &o = stack_get(v, idx);\r
423         if(sq_isnumeric(o)) {\r
424                 *f = tofloat(o);\r
425                 return SQ_OK;\r
426         }\r
427         return SQ_ERROR;\r
428 }\r
429 \r
430 SQRESULT sq_getbool(HSQUIRRELVM v,int idx,SQBool *b)\r
431 {\r
432         SQObjectPtr &o = stack_get(v, idx);\r
433         if(sq_isbool(o)) {\r
434                 *b = _integer(o);\r
435                 return SQ_OK;\r
436         }\r
437         return SQ_ERROR;\r
438 }\r
439 \r
440 SQRESULT sq_getstring(HSQUIRRELVM v,int idx,const SQChar **c)\r
441 {\r
442         SQObjectPtr *o = NULL;\r
443         _GETSAFE_OBJ(v, idx, OT_STRING,o);\r
444         *c = _stringval(*o);\r
445         return SQ_OK;\r
446 }\r
447 \r
448 SQRESULT sq_getthread(HSQUIRRELVM v,int idx,HSQUIRRELVM *thread)\r
449 {\r
450         SQObjectPtr *o = NULL;\r
451         _GETSAFE_OBJ(v, idx, OT_THREAD,o);\r
452         *thread = _thread(*o);\r
453         return SQ_OK;\r
454 }\r
455 \r
456 SQRESULT sq_clone(HSQUIRRELVM v,int idx)\r
457 {\r
458         SQObjectPtr &o = stack_get(v,idx);\r
459         v->Push(_null_);\r
460         if(!v->Clone(o, stack_get(v, -1))){\r
461                 v->Pop();\r
462                 return sq_aux_invalidtype(v, type(o));\r
463         }\r
464         return SQ_OK;\r
465 }\r
466 \r
467 SQInteger sq_getsize(HSQUIRRELVM v, int idx)\r
468 {\r
469         SQObjectPtr &o = stack_get(v, idx);\r
470         SQObjectType type = type(o);\r
471         switch(type) {\r
472         case OT_STRING:         return _string(o)->_len;\r
473         case OT_TABLE:          return _table(o)->CountUsed();\r
474         case OT_ARRAY:          return _array(o)->Size();\r
475         case OT_USERDATA:       return _userdata(o)->_size;\r
476         default:\r
477                 return sq_aux_invalidtype(v, type);\r
478         }\r
479 }\r
480 \r
481 SQRESULT sq_getuserdata(HSQUIRRELVM v,int idx,SQUserPointer *p,unsigned int *typetag)\r
482 {\r
483         SQObjectPtr *o = NULL;\r
484         _GETSAFE_OBJ(v, idx, OT_USERDATA,o);\r
485         (*p) = _userdataval(*o);\r
486         if(typetag) *typetag = _userdata(*o)->_typetag;\r
487         return SQ_OK;\r
488 }\r
489 \r
490 SQRESULT sq_settypetag(HSQUIRRELVM v,int idx,unsigned int typetag)\r
491 {\r
492         SQObjectPtr &o = stack_get(v,idx);\r
493         switch(type(o)) {\r
494                 case OT_USERDATA:       _userdata(o)->_typetag = typetag;       break;\r
495                 case OT_CLASS:          _class(o)->_typetag = typetag;          break;\r
496                 default:                        return sq_throwerror(v,_SC("invalid object type"));\r
497         }\r
498         return SQ_OK;\r
499 }\r
500 \r
501 SQRESULT sq_gettypetag(HSQUIRRELVM v,int idx,unsigned int *typetag)\r
502 {\r
503         SQObjectPtr &o = stack_get(v,idx);\r
504         switch(type(o)) {\r
505                 case OT_USERDATA:       *typetag = _userdata(o)->_typetag;      break;\r
506                 case OT_CLASS:          *typetag = _class(o)->_typetag;         break;\r
507                 default:                        return sq_throwerror(v,_SC("invalid object type"));\r
508         }\r
509         return SQ_OK;\r
510 }\r
511 \r
512 SQRESULT sq_getuserpointer(HSQUIRRELVM v, int idx, SQUserPointer *p)\r
513 {\r
514         SQObjectPtr *o = NULL;\r
515         _GETSAFE_OBJ(v, idx, OT_USERPOINTER,o);\r
516         (*p) = _userpointer(*o);\r
517         return SQ_OK;\r
518 }\r
519 \r
520 SQRESULT sq_setinstanceup(HSQUIRRELVM v, int idx, SQUserPointer p)\r
521 {\r
522         SQObjectPtr &o = stack_get(v,idx);\r
523         if(type(o) != OT_INSTANCE) return sq_throwerror(v,_SC("the object is not a class instance"));\r
524         _instance(o)->_userpointer = p;\r
525         return SQ_OK;\r
526 }\r
527 \r
528 SQRESULT sq_getinstanceup(HSQUIRRELVM v, int idx, SQUserPointer *p,unsigned int typetag)\r
529 {\r
530         SQObjectPtr &o = stack_get(v,idx);\r
531         if(type(o) != OT_INSTANCE) return sq_throwerror(v,_SC("the object is not a class instance"));\r
532         (*p) = _instance(o)->_userpointer;\r
533         if(typetag != 0) {\r
534                 SQClass *cl = _instance(o)->_class;\r
535                 do{\r
536                         if(cl->_typetag == typetag)\r
537                                 return SQ_OK;\r
538                         cl = cl->_base;\r
539                 }while(cl != NULL);\r
540                 return sq_throwerror(v,_SC("invalid type tag"));\r
541         }\r
542         return SQ_OK;\r
543 }\r
544 \r
545 int sq_gettop(HSQUIRRELVM v)\r
546 {\r
547         return (v->_top) - v->_stackbase;\r
548 }\r
549 \r
550 void sq_settop(HSQUIRRELVM v, int newtop)\r
551 {\r
552         int top = sq_gettop(v);\r
553         if(top > newtop)\r
554                 sq_pop(v, top - newtop);\r
555         else\r
556                 while(top < newtop) sq_pushnull(v);\r
557 }\r
558 \r
559 void sq_pop(HSQUIRRELVM v, int nelemstopop)\r
560 {\r
561         assert(v->_top >= nelemstopop);\r
562         v->Pop(nelemstopop);\r
563 }\r
564 \r
565 void sq_remove(HSQUIRRELVM v, int idx)\r
566 {\r
567         v->Remove(idx);\r
568 }\r
569 \r
570 int sq_cmp(HSQUIRRELVM v)\r
571 {\r
572         int res;\r
573         v->ObjCmp(stack_get(v, -1), stack_get(v, -2),res);\r
574         return res;\r
575 }\r
576 \r
577 SQRESULT sq_createslot(HSQUIRRELVM v, int idx)\r
578 {\r
579         sq_aux_paramscheck(v, 3);\r
580         SQObjectPtr &self = stack_get(v, idx);\r
581         if(type(self) == OT_TABLE || type(self) == OT_CLASS) {\r
582                 SQObjectPtr &key = v->GetUp(-2);\r
583                 if(type(key) == OT_NULL) return sq_throwerror(v, _SC("null is not a valid key"));\r
584                 v->NewSlot(self, key, v->GetUp(-1));\r
585                 v->Pop(2);\r
586         }\r
587         return SQ_OK;\r
588 }\r
589 \r
590 SQRESULT sq_deleteslot(HSQUIRRELVM v,int idx,SQBool pushval)\r
591 {\r
592         sq_aux_paramscheck(v, 2);\r
593         SQObjectPtr *self;\r
594         _GETSAFE_OBJ(v, idx, OT_TABLE,self);\r
595         SQObjectPtr &key = v->GetUp(-1);\r
596         if(type(key) == OT_NULL) return sq_throwerror(v, _SC("null is not a valid key"));\r
597         SQObjectPtr res;\r
598         if(!v->DeleteSlot(*self, key, res)){\r
599                 return SQ_ERROR;\r
600         }\r
601         if(pushval)     v->GetUp(-1) = res;\r
602         else v->Pop(1);\r
603         return SQ_OK;\r
604 }\r
605 \r
606 SQRESULT sq_set(HSQUIRRELVM v,int idx)\r
607 {\r
608         SQObjectPtr &self = stack_get(v, idx);\r
609         if(v->Set(self, v->GetUp(-2), v->GetUp(-1),false)) {\r
610                 v->Pop(2);\r
611                 return SQ_OK;\r
612         }\r
613         v->Raise_IdxError(v->GetUp(-2));return SQ_ERROR;\r
614 }\r
615 \r
616 SQRESULT sq_rawset(HSQUIRRELVM v,int idx)\r
617 {\r
618         SQObjectPtr &self = stack_get(v, idx);\r
619         if(type(v->GetUp(-2)) == OT_NULL) return sq_throwerror(v, _SC("null key"));\r
620         switch(type(self)) {\r
621         case OT_TABLE:\r
622                 _table(self)->NewSlot(v->GetUp(-2), v->GetUp(-1));\r
623                 v->Pop(2);\r
624                 return SQ_OK;\r
625         break;\r
626         case OT_CLASS:\r
627                 _class(self)->NewSlot(v->GetUp(-2), v->GetUp(-1));\r
628                 v->Pop(2);\r
629                 return SQ_OK;\r
630         break;\r
631         case OT_INSTANCE:\r
632                 if(_instance(self)->Set(v->GetUp(-2), v->GetUp(-1))) {\r
633                         v->Pop(2);\r
634                         return SQ_OK;\r
635                 }\r
636         break;\r
637         case OT_ARRAY:\r
638                 if(v->Set(self, v->GetUp(-2), v->GetUp(-1),false)) {\r
639                         v->Pop(2);\r
640                         return SQ_OK;\r
641                 }\r
642         break;\r
643         default:\r
644                 v->Pop(2);\r
645                 return sq_throwerror(v, _SC("rawset works only on arrays,tables,calsses and instances"));\r
646         }\r
647         v->Raise_IdxError(v->GetUp(-2));return SQ_ERROR;\r
648 }\r
649 \r
650 SQRESULT sq_setdelegate(HSQUIRRELVM v,int idx)\r
651 {\r
652         SQObjectPtr &self = stack_get(v, idx);\r
653         SQObjectPtr &mt = v->GetUp(-1);\r
654         SQObjectType type = type(self);\r
655         switch(type) {\r
656         case OT_TABLE:\r
657                 if(type(mt) == OT_TABLE) {\r
658                         if(!_table(self)->SetDelegate(_table(mt))) return sq_throwerror(v, _SC("delagate cycle")); v->Pop();}\r
659                 else if(type(mt)==OT_NULL) {\r
660                         _table(self)->SetDelegate(NULL); v->Pop(); }\r
661                 else return sq_aux_invalidtype(v,type);\r
662                 break;\r
663         case OT_USERDATA:\r
664                 if(type(mt)==OT_TABLE) {\r
665                         _userdata(self)->SetDelegate(_table(mt)); v->Pop(); }\r
666                 else if(type(mt)==OT_NULL) {\r
667                         _userdata(self)->SetDelegate(NULL); v->Pop(); }\r
668                 else return sq_aux_invalidtype(v, type);\r
669                 break;\r
670         default:\r
671                         return sq_aux_invalidtype(v, type);\r
672                 break;\r
673         }\r
674         return SQ_OK;\r
675 }\r
676 \r
677 SQRESULT sq_rawdeleteslot(HSQUIRRELVM v,int idx,SQBool pushval)\r
678 {\r
679         sq_aux_paramscheck(v, 2);\r
680         SQObjectPtr *self;\r
681         _GETSAFE_OBJ(v, idx, OT_TABLE,self);\r
682         SQObjectPtr &key = v->GetUp(-1);\r
683         SQObjectPtr t;\r
684         if(_table(*self)->Get(key,t)) {\r
685                 _table(*self)->Remove(key);\r
686         }\r
687         if(pushval != 0)\r
688                 if(pushval)     v->GetUp(-1) = t;\r
689         else\r
690                 v->Pop(1);\r
691         return SQ_OK;\r
692 }\r
693 \r
694 SQRESULT sq_getdelegate(HSQUIRRELVM v,int idx)\r
695 {\r
696         SQObjectPtr &self=stack_get(v,idx);\r
697         switch(type(self)){\r
698         case OT_TABLE:\r
699                 if(!_table(self)->_delegate)break;\r
700                 v->Push(SQObjectPtr(_table(self)->_delegate));\r
701                 return SQ_OK;\r
702                 break;\r
703         case OT_USERDATA:\r
704                 if(!_userdata(self)->_delegate)break;\r
705                 v->Push(SQObjectPtr(_userdata(self)->_delegate));\r
706                 return SQ_OK;\r
707                 break;\r
708         }\r
709         return sq_throwerror(v,_SC("wrong type"));\r
710 }\r
711 \r
712 SQRESULT sq_get(HSQUIRRELVM v,int idx)\r
713 {\r
714         SQObjectPtr &self=stack_get(v,idx);\r
715         if(v->Get(self,v->GetUp(-1),v->GetUp(-1),false,false))\r
716                 return SQ_OK;\r
717         v->Pop(1);\r
718         return sq_throwerror(v,_SC("the index doesn't exist"));\r
719 }\r
720 \r
721 SQRESULT sq_rawget(HSQUIRRELVM v,int idx)\r
722 {\r
723         SQObjectPtr &self=stack_get(v,idx);\r
724         switch(type(self)) {\r
725         case OT_TABLE:\r
726                 if(_table(self)->Get(v->GetUp(-1),v->GetUp(-1)))\r
727                         return SQ_OK;\r
728                 break;\r
729         case OT_CLASS:\r
730                 if(_class(self)->Get(v->GetUp(-1),v->GetUp(-1)))\r
731                         return SQ_OK;\r
732                 break;\r
733         case OT_INSTANCE:\r
734                 if(_instance(self)->Get(v->GetUp(-1),v->GetUp(-1)))\r
735                         return SQ_OK;\r
736                 break;\r
737         case OT_ARRAY:\r
738                 if(v->Get(self,v->GetUp(-1),v->GetUp(-1),false,false))\r
739                         return SQ_OK;\r
740                 break;\r
741         default:\r
742                 v->Pop(1);\r
743                 return sq_throwerror(v,_SC("rawget works only on arrays and tables"));\r
744         }       \r
745         v->Pop(1);\r
746         return sq_throwerror(v,_SC("the index doesn't exist"));\r
747 }\r
748 \r
749 SQRESULT sq_getstackobj(HSQUIRRELVM v,int idx,HSQOBJECT *po)\r
750 {\r
751         *po=stack_get(v,idx);\r
752         return SQ_OK;\r
753 }\r
754 \r
755 const SQChar *sq_getlocal(HSQUIRRELVM v,unsigned int level,unsigned int idx)\r
756 {\r
757         unsigned int cstksize=v->_callsstack.size();\r
758         unsigned int lvl=(cstksize-level)-1;\r
759         int stackbase=v->_stackbase;\r
760         if(lvl<cstksize){\r
761                 for(unsigned int i=0;i<level;i++){\r
762                         SQVM::CallInfo &ci=v->_callsstack[(cstksize-i)-1];\r
763                         stackbase-=ci._prevstkbase;\r
764                 }\r
765                 SQVM::CallInfo &ci=v->_callsstack[lvl];\r
766                 if(type(ci._closure)!=OT_CLOSURE)\r
767                         return NULL;\r
768                 SQClosure *c=_closure(ci._closure);\r
769                 SQFunctionProto *func=_funcproto(c->_function);\r
770                 return func->GetLocal(v,stackbase,idx,(ci._ip-func->_instructions._vals)-1);\r
771         }\r
772         return NULL;\r
773 }\r
774 \r
775 void sq_pushobject(HSQUIRRELVM v,HSQOBJECT obj)\r
776 {\r
777         v->Push(SQObjectPtr(obj));\r
778 }\r
779 \r
780 void sq_resetobject(HSQOBJECT *po)\r
781 {\r
782         po->_unVal.pUserPointer=NULL;po->_type=OT_NULL;\r
783 }\r
784 \r
785 SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err)\r
786 {\r
787         v->_lasterror=SQString::Create(_ss(v),err);\r
788         return -1;\r
789 }\r
790 \r
791 void sq_reseterror(HSQUIRRELVM v)\r
792 {\r
793         v->_lasterror = _null_;\r
794 }\r
795 \r
796 void sq_getlasterror(HSQUIRRELVM v)\r
797 {\r
798         v->Push(v->_lasterror);\r
799 }\r
800 \r
801 void sq_reservestack(HSQUIRRELVM v,int nsize)\r
802 {\r
803         if (((unsigned int)v->_top + nsize) > v->_stack.size()) {\r
804                 v->_stack.resize(v->_stack.size() + ((v->_top + nsize) - v->_stack.size()));\r
805         }\r
806 }\r
807 \r
808 SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval)\r
809 {\r
810         if(type(v->GetUp(-1))==OT_GENERATOR){\r
811                 v->Push(_null_); //retval\r
812                 if(!v->Execute(v->GetUp(-2),v->_top,0,v->_top,v->GetUp(-1),SQVM::ET_RESUME_GENERATOR))\r
813                 {v->Raise_Error(v->_lasterror); return SQ_ERROR;}\r
814                 if(!retval)\r
815                         v->Pop();\r
816                 return SQ_OK;\r
817         }\r
818         return sq_throwerror(v,_SC("only generators can be resumed"));\r
819 }\r
820 \r
821 SQRESULT sq_call(HSQUIRRELVM v,int params,SQBool retval)\r
822 {\r
823         SQObjectPtr res;\r
824         if(v->Call(v->GetUp(-(params+1)),params,v->_top-params,res)){\r
825                 v->Pop(params);//pop closure and args\r
826                 if(retval){\r
827                         v->Push(res); return SQ_OK;\r
828                 }\r
829                 return SQ_OK;\r
830         }\r
831         else {\r
832                 v->Pop(params);\r
833                 return SQ_ERROR;\r
834         }\r
835         if(!v->_suspended)\r
836                 v->Pop(params);\r
837         return sq_throwerror(v,_SC("call failed"));\r
838 }\r
839 \r
840 SQRESULT sq_suspendvm(HSQUIRRELVM v)\r
841 {\r
842         return v->Suspend();\r
843 }\r
844 \r
845 SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool wakeupret,SQBool retval)\r
846 {\r
847         SQObjectPtr ret;\r
848         if(!v->_suspended)\r
849                 return sq_throwerror(v,_SC("cannot resume a vm that is not running any code"));\r
850         if(wakeupret) {\r
851                 v->GetAt(v->_stackbase+v->_suspended_target)=v->GetUp(-1); //retval\r
852                 v->Pop();\r
853         } else v->GetAt(v->_stackbase+v->_suspended_target)=_null_;\r
854         if(!v->Execute(_null_,v->_top,-1,-1,ret,SQVM::ET_RESUME_VM))\r
855                 return SQ_ERROR;\r
856         if(sq_getvmstate(v) == SQ_VMSTATE_IDLE) {\r
857                 while (v->_top > 1) v->_stack[--v->_top] = _null_;\r
858         }\r
859         if(retval)\r
860                 v->Push(ret);\r
861         return SQ_OK;\r
862 }\r
863 \r
864 void sq_setreleasehook(HSQUIRRELVM v,int idx,SQRELEASEHOOK hook)\r
865 {\r
866         if(sq_gettop(v) >= 1){\r
867                 SQObjectPtr &ud=stack_get(v,idx);\r
868                 switch( type(ud) ) {\r
869                 case OT_USERDATA:\r
870                         _userdata(ud)->_hook = hook;\r
871                         break;\r
872                 case OT_INSTANCE:\r
873                         _instance(ud)->_hook = hook;\r
874                         break;\r
875                 }\r
876         }\r
877 }\r
878 \r
879 void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f)\r
880 {\r
881         _ss(v)->_compilererrorhandler = f;\r
882 }\r
883 \r
884 SQRESULT sq_writeclosure(HSQUIRRELVM v,SQWRITEFUNC w,SQUserPointer up)\r
885 {\r
886         SQObjectPtr *o = NULL;\r
887         _GETSAFE_OBJ(v, -1, OT_CLOSURE,o);\r
888         SQClosure *c=_closure(*o);\r
889         unsigned short tag = SQ_BYTECODE_STREAM_TAG;\r
890         if(w(up,&tag,2) != 2)\r
891                 return sq_throwerror(v,_SC("io error"));\r
892         if(!_closure(*o)->Save(v,up,w))\r
893                 return SQ_ERROR;\r
894         return SQ_OK;\r
895 }\r
896 \r
897 SQRESULT sq_readclosure(HSQUIRRELVM v,SQREADFUNC r,SQUserPointer up)\r
898 {\r
899         SQObjectPtr func=SQFunctionProto::Create();\r
900         SQObjectPtr closure=SQClosure::Create(_ss(v),_funcproto(func));\r
901         unsigned short tag;\r
902         if(r(up,&tag,2) != 2)\r
903                 return sq_throwerror(v,_SC("io error"));\r
904         if(tag != SQ_BYTECODE_STREAM_TAG)\r
905                 return sq_throwerror(v,_SC("invalid stream"));\r
906         if(!_closure(closure)->Load(v,up,r))\r
907                 return SQ_ERROR;\r
908         v->Push(closure);\r
909         return SQ_OK;\r
910 }\r
911 \r
912 SQChar *sq_getscratchpad(HSQUIRRELVM v,int minsize)\r
913 {\r
914         return _ss(v)->GetScratchPad(minsize);\r
915 }\r
916 \r
917 int sq_collectgarbage(HSQUIRRELVM v)\r
918 {\r
919 #ifndef NO_GARBAGE_COLLECTOR\r
920         return _ss(v)->CollectGarbage(v);\r
921 #else\r
922         return -1;\r
923 #endif\r
924 }\r
925 \r
926 SQRESULT sq_setfreevariable(HSQUIRRELVM v,int idx,unsigned int nval)\r
927 {\r
928         SQObjectPtr &self=stack_get(v,idx);\r
929         switch(type(self))\r
930         {\r
931         case OT_CLOSURE:\r
932                 if(_closure(self)->_outervalues.size()>nval){\r
933                         _closure(self)->_outervalues[nval]=stack_get(v,-1);\r
934                 }\r
935                 else return sq_throwerror(v,_SC("invalid free var index"));\r
936                 break;\r
937         case OT_NATIVECLOSURE:\r
938                 if(_nativeclosure(self)->_outervalues.size()>nval){\r
939                         _nativeclosure(self)->_outervalues[nval]=stack_get(v,-1);\r
940                 }\r
941                 else return sq_throwerror(v,_SC("invalid free var index"));\r
942                 break;\r
943         default:\r
944                 return sq_aux_invalidtype(v,type(self));\r
945         }\r
946         v->Pop(1);\r
947         return SQ_OK;\r
948 }\r
949 \r
950 SQRESULT sq_setattributes(HSQUIRRELVM v,int idx)\r
951 {\r
952         SQObjectPtr *o = NULL;\r
953         _GETSAFE_OBJ(v, idx, OT_CLASS,o);\r
954         SQObjectPtr &key = stack_get(v,-2);\r
955         SQObjectPtr &val = stack_get(v,-1);\r
956         SQObjectPtr attrs;\r
957         if(type(key) == OT_NULL) {\r
958                 attrs = _class(*o)->_attributes;\r
959                 _class(*o)->_attributes = val;\r
960                 v->Pop(2);\r
961                 v->Push(attrs);\r
962                 return SQ_OK;\r
963         }else if(_class(*o)->GetAttributes(key,attrs)) {\r
964                 _class(*o)->SetAttributes(key,val);\r
965                 v->Pop(2);\r
966                 v->Push(attrs);\r
967                 return SQ_OK;\r
968         }\r
969         return sq_throwerror(v,_SC("wrong index"));\r
970 }\r
971 \r
972 SQRESULT sq_getattributes(HSQUIRRELVM v,int idx)\r
973 {\r
974         SQObjectPtr *o = NULL;\r
975         _GETSAFE_OBJ(v, idx, OT_CLASS,o);\r
976         SQObjectPtr &key = stack_get(v,-1);\r
977         SQObjectPtr attrs;\r
978         if(type(key) == OT_NULL) {\r
979                 attrs = _class(*o)->_attributes;\r
980                 v->Pop();\r
981                 v->Push(attrs);\r
982                 return SQ_OK;\r
983         }\r
984         else if(_class(*o)->GetAttributes(key,attrs)) {\r
985                 v->Pop();\r
986                 v->Push(attrs);\r
987                 return SQ_OK;\r
988         }\r
989         return sq_throwerror(v,_SC("wrong index"));\r
990 }\r
991 \r
992 SQRESULT sq_getclass(HSQUIRRELVM v,int idx)\r
993 {\r
994         SQObjectPtr *o = NULL;\r
995         _GETSAFE_OBJ(v, idx, OT_INSTANCE,o);\r
996         v->Push(SQObjectPtr(_instance(*o)->_class));\r
997         return SQ_OK;\r
998 }\r
999 \r
1000 SQRESULT sq_createinstance(HSQUIRRELVM v,int idx)\r
1001 {\r
1002         SQObjectPtr *o = NULL;\r
1003         _GETSAFE_OBJ(v, idx, OT_CLASS,o);\r
1004         v->Push(_class(*o)->CreateInstance());\r
1005         return SQ_OK;\r
1006 }\r
1007 \r
1008 SQRESULT sq_next(HSQUIRRELVM v,int idx)\r
1009 {\r
1010         SQObjectPtr o=stack_get(v,idx),&refpos = stack_get(v,-1),realkey,val;\r
1011         if(type(o) == OT_GENERATOR) {\r
1012                 return sq_throwerror(v,_SC("cannot iterate a generator"));\r
1013         }\r
1014         bool finished;\r
1015         if(!v->FOREACH_OP(o,realkey,val,refpos,0,finished))\r
1016                 return SQ_ERROR;\r
1017         if(!finished) {\r
1018                 v->Push(realkey);\r
1019                 v->Push(val);\r
1020                 return SQ_OK;\r
1021         }\r
1022         return SQ_ERROR;\r
1023 }\r
1024 \r
1025 struct BufState{\r
1026         const SQChar *buf;\r
1027         int ptr;\r
1028         int size;\r
1029 };\r
1030 \r
1031 SQInteger buf_lexfeed(SQUserPointer file)\r
1032 {\r
1033         BufState *buf=(BufState*)file;\r
1034         if(buf->size<(buf->ptr+1))\r
1035                 return 0;\r
1036         return buf->buf[buf->ptr++];\r
1037 }\r
1038 \r
1039 SQRESULT sq_compilebuffer(HSQUIRRELVM v,const SQChar *s,int size,const SQChar *sourcename,SQBool raiseerror) {\r
1040         BufState buf;\r
1041         buf.buf = s;\r
1042         buf.size = size;\r
1043         buf.ptr = 0;\r
1044         return sq_compile(v, buf_lexfeed, &buf, sourcename, raiseerror);\r
1045 }\r
1046 \r
1047 void sq_move(HSQUIRRELVM dest,HSQUIRRELVM src,int idx)\r
1048 {\r
1049         dest->Push(stack_get(src,idx));\r
1050 }\r
1051 \r
1052 void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc)\r
1053 {\r
1054         _ss(v)->_printfunc = printfunc;\r
1055 }\r
1056 \r
1057 SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v)\r
1058 {\r
1059         return _ss(v)->_printfunc;\r
1060 }\r
1061 \r
1062 void *sq_malloc(unsigned int size)\r
1063 {\r
1064         return SQ_MALLOC(size);\r
1065 }\r
1066 \r
1067 void *sq_realloc(void* p,unsigned int oldsize,unsigned int newsize)\r
1068 {\r
1069         return SQ_REALLOC(p,oldsize,newsize);\r
1070 }\r
1071 void sq_free(void *p,unsigned int size)\r
1072 {\r
1073         SQ_FREE(p,size);\r
1074 }\r