squirrel update
[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 "sqcompiler.h"\r
13 #include "sqfuncstate.h"\r
14 #include "sqclass.h"\r
15 \r
16 bool sq_aux_gettypedarg(HSQUIRRELVM v,SQInteger 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 SQInteger 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 SQInteger 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(SQInteger 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, SQInteger 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 SQInteger 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                 SQInteger 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 _stringval(*o);\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 SQBool sq_objtobool(HSQOBJECT *o) \r
188 {\r
189         if(sq_isbool(*o)) {\r
190                 return _integer(*o);\r
191         }\r
192         return SQFalse;\r
193 }\r
194 \r
195 void sq_pushnull(HSQUIRRELVM v)\r
196 {\r
197         v->Push(_null_);\r
198 }\r
199 \r
200 void sq_pushstring(HSQUIRRELVM v,const SQChar *s,SQInteger len)\r
201 {\r
202         if(s)\r
203                 v->Push(SQObjectPtr(SQString::Create(_ss(v), s, len)));\r
204         else v->Push(_null_);\r
205 }\r
206 \r
207 void sq_pushinteger(HSQUIRRELVM v,SQInteger n)\r
208 {\r
209         v->Push(n);\r
210 }\r
211 \r
212 void sq_pushbool(HSQUIRRELVM v,SQBool b)\r
213 {\r
214         v->Push(b?true:false);\r
215 }\r
216 \r
217 void sq_pushfloat(HSQUIRRELVM v,SQFloat n)\r
218 {\r
219         v->Push(n);\r
220 }\r
221 \r
222 void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p)\r
223 {\r
224         v->Push(p);\r
225 }\r
226 \r
227 SQUserPointer sq_newuserdata(HSQUIRRELVM v,SQUnsignedInteger size)\r
228 {\r
229         SQUserData *ud = SQUserData::Create(_ss(v), size);\r
230         v->Push(ud);\r
231         return ud->_val;\r
232 }\r
233 \r
234 void sq_newtable(HSQUIRRELVM v)\r
235 {\r
236         v->Push(SQTable::Create(_ss(v), 0));    \r
237 }\r
238 \r
239 void sq_newarray(HSQUIRRELVM v,SQInteger size)\r
240 {\r
241         v->Push(SQArray::Create(_ss(v), size)); \r
242 }\r
243 \r
244 SQRESULT sq_newclass(HSQUIRRELVM v,SQBool hasbase)\r
245 {\r
246         SQClass *baseclass = NULL;\r
247         if(hasbase) {\r
248                 SQObjectPtr &base = stack_get(v,-1);\r
249                 if(type(base) != OT_CLASS)\r
250                         return sq_throwerror(v,_SC("invalid base type"));\r
251                 baseclass = _class(base);\r
252         }\r
253         SQClass *newclass = SQClass::Create(_ss(v), baseclass);\r
254         if(baseclass) v->Pop();\r
255         v->Push(newclass);      \r
256         return SQ_OK;\r
257 }\r
258 \r
259 SQInteger sq_instanceof(HSQUIRRELVM v)\r
260 {\r
261         SQObjectPtr &inst = stack_get(v,-1);\r
262         SQObjectPtr &cl = stack_get(v,-2);\r
263         if(type(inst) != OT_INSTANCE || type(cl) != OT_CLASS)\r
264                 return sq_throwerror(v,_SC("invalid param type"));\r
265         return _instance(inst)->InstanceOf(_class(cl))?1:0;\r
266 }\r
267 \r
268 SQRESULT sq_arrayappend(HSQUIRRELVM v,SQInteger idx)\r
269 {\r
270         sq_aux_paramscheck(v,2);\r
271         SQObjectPtr *arr;\r
272         _GETSAFE_OBJ(v, idx, OT_ARRAY,arr);\r
273         _array(*arr)->Append(v->GetUp(-1));\r
274         v->Pop(1);\r
275         return SQ_OK;\r
276 }\r
277 \r
278 SQRESULT sq_arraypop(HSQUIRRELVM v,SQInteger idx,SQBool pushval)\r
279 {\r
280         sq_aux_paramscheck(v, 1);\r
281         SQObjectPtr *arr;\r
282         _GETSAFE_OBJ(v, idx, OT_ARRAY,arr);\r
283         if(_array(*arr)->Size() > 0) {\r
284         if(pushval != 0){ v->Push(_array(*arr)->Top()); }\r
285                 _array(*arr)->Pop();\r
286                 return SQ_OK;\r
287         }\r
288         return sq_throwerror(v, _SC("empty array"));\r
289 }\r
290 \r
291 SQRESULT sq_arrayresize(HSQUIRRELVM v,SQInteger idx,SQInteger newsize)\r
292 {\r
293         sq_aux_paramscheck(v,1);\r
294         SQObjectPtr *arr;\r
295         _GETSAFE_OBJ(v, idx, OT_ARRAY,arr);\r
296         if(_array(*arr)->Size() > 0) {\r
297                 _array(*arr)->Resize(newsize);\r
298                 return SQ_OK;\r
299         }\r
300         return SQ_OK;\r
301 }\r
302 \r
303 SQRESULT sq_arrayreverse(HSQUIRRELVM v,SQInteger idx)\r
304 {\r
305         sq_aux_paramscheck(v, 1);\r
306         SQObjectPtr *o;\r
307         _GETSAFE_OBJ(v, idx, OT_ARRAY,o);\r
308         SQArray *arr = _array(*o);\r
309         if(arr->Size() > 0) {\r
310                 SQObjectPtr t;\r
311                 SQInteger size = arr->Size();\r
312                 SQInteger n = size >> 1; size -= 1;\r
313                 for(SQInteger i = 0; i < n; i++) {\r
314                         t = arr->_values[i];\r
315                         arr->_values[i] = arr->_values[size-i];\r
316                         arr->_values[size-i] = t;\r
317                 }\r
318                 return SQ_OK;\r
319         }\r
320         return SQ_OK;\r
321 }\r
322 \r
323 void sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,SQUnsignedInteger nfreevars)\r
324 {\r
325         SQNativeClosure *nc = SQNativeClosure::Create(_ss(v), func);\r
326         nc->_nparamscheck = 0;\r
327         for(SQUnsignedInteger i = 0; i < nfreevars; i++) {\r
328                 nc->_outervalues.push_back(v->Top());\r
329                 v->Pop();\r
330         }\r
331         v->Push(SQObjectPtr(nc));       \r
332 }\r
333 \r
334 SQRESULT sq_getclosureinfo(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger *nparams,SQUnsignedInteger *nfreevars)\r
335 {\r
336         SQObject o = stack_get(v, idx);\r
337         if(sq_isclosure(o)) {\r
338                 SQClosure *c = _closure(o);\r
339                 SQFunctionProto *proto = _funcproto(c->_function);\r
340                 *nparams = (SQUnsignedInteger)proto->_parameters.size();\r
341         *nfreevars = (SQUnsignedInteger)c->_outervalues.size();\r
342                 return SQ_OK;\r
343         }\r
344         return sq_throwerror(v,_SC("the object is not a closure"));\r
345 }\r
346 \r
347 SQRESULT sq_setnativeclosurename(HSQUIRRELVM v,SQInteger idx,const SQChar *name)\r
348 {\r
349         SQObject o = stack_get(v, idx);\r
350         if(sq_isnativeclosure(o)) {\r
351                 SQNativeClosure *nc = _nativeclosure(o);\r
352                 nc->_name = SQString::Create(_ss(v),name);\r
353                 return SQ_OK;\r
354         }\r
355         return sq_throwerror(v,_SC("the object is not a nativeclosure"));\r
356 }\r
357 \r
358 SQRESULT sq_setparamscheck(HSQUIRRELVM v,SQInteger nparamscheck,const SQChar *typemask)\r
359 {\r
360         SQObject o = stack_get(v, -1);\r
361         if(!sq_isnativeclosure(o))\r
362                 return sq_throwerror(v, _SC("native closure expected"));\r
363         SQNativeClosure *nc = _nativeclosure(o);\r
364         nc->_nparamscheck = nparamscheck;\r
365         if(typemask) {\r
366                 SQIntVec res;\r
367                 if(!CompileTypemask(res, typemask))\r
368                         return sq_throwerror(v, _SC("invalid typemask"));\r
369                 nc->_typecheck.copy(res);\r
370         }\r
371         else {\r
372                 nc->_typecheck.resize(0);\r
373         }\r
374         if(nparamscheck == SQ_MATCHTYPEMASKSTRING) {\r
375                 nc->_nparamscheck = nc->_typecheck.size();\r
376         }\r
377         return SQ_OK;\r
378 }\r
379 \r
380 void sq_pushroottable(HSQUIRRELVM v)\r
381 {\r
382         v->Push(v->_roottable);\r
383 }\r
384 \r
385 void sq_pushregistrytable(HSQUIRRELVM v)\r
386 {\r
387         v->Push(_ss(v)->_registry);\r
388 }\r
389 \r
390 SQRESULT sq_setroottable(HSQUIRRELVM v)\r
391 {\r
392         SQObject o = stack_get(v, -1);\r
393         if(sq_istable(o) || sq_isnull(o)) {\r
394                 v->_roottable = o;\r
395                 v->Pop();\r
396                 return SQ_OK;\r
397         }\r
398         return sq_throwerror(v, _SC("ivalid type"));\r
399 }\r
400 \r
401 void sq_setforeignptr(HSQUIRRELVM v,SQUserPointer p)\r
402 {\r
403         v->_foreignptr = p;\r
404 }\r
405 \r
406 SQUserPointer sq_getforeignptr(HSQUIRRELVM v)\r
407 {\r
408         return v->_foreignptr;\r
409 }\r
410 \r
411 void sq_push(HSQUIRRELVM v,SQInteger idx)\r
412 {\r
413         v->Push(stack_get(v, idx));\r
414 }\r
415 \r
416 SQObjectType sq_gettype(HSQUIRRELVM v,SQInteger idx)\r
417 {\r
418         return type(stack_get(v, idx));\r
419 }\r
420 \r
421 void sq_tostring(HSQUIRRELVM v,SQInteger idx)\r
422 {\r
423         SQObjectPtr &o = stack_get(v, idx);\r
424         SQObjectPtr res;\r
425         v->ToString(o,res);\r
426         v->Push(res);\r
427 }\r
428 \r
429 SQRESULT sq_getinteger(HSQUIRRELVM v,SQInteger idx,SQInteger *i)\r
430 {\r
431         SQObjectPtr &o = stack_get(v, idx);\r
432         if(sq_isnumeric(o)) {\r
433                 *i = tointeger(o);\r
434                 return SQ_OK;\r
435         }\r
436         return SQ_ERROR;\r
437 }\r
438 \r
439 SQRESULT sq_getfloat(HSQUIRRELVM v,SQInteger idx,SQFloat *f)\r
440 {\r
441         SQObjectPtr &o = stack_get(v, idx);\r
442         if(sq_isnumeric(o)) {\r
443                 *f = tofloat(o);\r
444                 return SQ_OK;\r
445         }\r
446         return SQ_ERROR;\r
447 }\r
448 \r
449 SQRESULT sq_getbool(HSQUIRRELVM v,SQInteger idx,SQBool *b)\r
450 {\r
451         SQObjectPtr &o = stack_get(v, idx);\r
452         if(sq_isbool(o)) {\r
453                 *b = _integer(o);\r
454                 return SQ_OK;\r
455         }\r
456         return SQ_ERROR;\r
457 }\r
458 \r
459 SQRESULT sq_getstring(HSQUIRRELVM v,SQInteger idx,const SQChar **c)\r
460 {\r
461         SQObjectPtr *o = NULL;\r
462         _GETSAFE_OBJ(v, idx, OT_STRING,o);\r
463         *c = _stringval(*o);\r
464         return SQ_OK;\r
465 }\r
466 \r
467 SQRESULT sq_getthread(HSQUIRRELVM v,SQInteger idx,HSQUIRRELVM *thread)\r
468 {\r
469         SQObjectPtr *o = NULL;\r
470         _GETSAFE_OBJ(v, idx, OT_THREAD,o);\r
471         *thread = _thread(*o);\r
472         return SQ_OK;\r
473 }\r
474 \r
475 SQRESULT sq_clone(HSQUIRRELVM v,SQInteger idx)\r
476 {\r
477         SQObjectPtr &o = stack_get(v,idx);\r
478         v->Push(_null_);\r
479         if(!v->Clone(o, stack_get(v, -1))){\r
480                 v->Pop();\r
481                 return sq_aux_invalidtype(v, type(o));\r
482         }\r
483         return SQ_OK;\r
484 }\r
485 \r
486 SQInteger sq_getsize(HSQUIRRELVM v, SQInteger idx)\r
487 {\r
488         SQObjectPtr &o = stack_get(v, idx);\r
489         SQObjectType type = type(o);\r
490         switch(type) {\r
491         case OT_STRING:         return _string(o)->_len;\r
492         case OT_TABLE:          return _table(o)->CountUsed();\r
493         case OT_ARRAY:          return _array(o)->Size();\r
494         case OT_USERDATA:       return _userdata(o)->_size;\r
495         default:\r
496                 return sq_aux_invalidtype(v, type);\r
497         }\r
498 }\r
499 \r
500 SQRESULT sq_getuserdata(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p,SQUserPointer *typetag)\r
501 {\r
502         SQObjectPtr *o = NULL;\r
503         _GETSAFE_OBJ(v, idx, OT_USERDATA,o);\r
504         (*p) = _userdataval(*o);\r
505         if(typetag) *typetag = _userdata(*o)->_typetag;\r
506         return SQ_OK;\r
507 }\r
508 \r
509 SQRESULT sq_settypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer typetag)\r
510 {\r
511         SQObjectPtr &o = stack_get(v,idx);\r
512         switch(type(o)) {\r
513                 case OT_USERDATA:       _userdata(o)->_typetag = typetag;       break;\r
514                 case OT_CLASS:          _class(o)->_typetag = typetag;          break;\r
515                 default:                        return sq_throwerror(v,_SC("invalid object type"));\r
516         }\r
517         return SQ_OK;\r
518 }\r
519 \r
520 SQRESULT sq_getobjtypetag(HSQOBJECT *o,SQUserPointer * typetag)\r
521 {\r
522   switch(type(*o)) {\r
523     case OT_INSTANCE: *typetag = _instance(*o)->_class->_typetag; break;\r
524     case OT_USERDATA: *typetag = _userdata(*o)->_typetag; break;\r
525     case OT_CLASS:    *typetag = _class(*o)->_typetag; break;\r
526     default: return SQ_ERROR;\r
527   }\r
528   return SQ_OK;\r
529 }\r
530 \r
531 SQRESULT sq_gettypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer *typetag)\r
532 {\r
533         SQObjectPtr &o = stack_get(v,idx);\r
534         if(SQ_FAILED(sq_getobjtypetag(&o,typetag)))\r
535                 return sq_throwerror(v,_SC("invalid object type"));\r
536         return SQ_OK;\r
537 }\r
538 \r
539 SQRESULT sq_getuserpointer(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p)\r
540 {\r
541         SQObjectPtr *o = NULL;\r
542         _GETSAFE_OBJ(v, idx, OT_USERPOINTER,o);\r
543         (*p) = _userpointer(*o);\r
544         return SQ_OK;\r
545 }\r
546 \r
547 SQRESULT sq_setinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer p)\r
548 {\r
549         SQObjectPtr &o = stack_get(v,idx);\r
550         if(type(o) != OT_INSTANCE) return sq_throwerror(v,_SC("the object is not a class instance"));\r
551         _instance(o)->_userpointer = p;\r
552         return SQ_OK;\r
553 }\r
554 \r
555 SQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p,SQUserPointer typetag)\r
556 {\r
557         SQObjectPtr &o = stack_get(v,idx);\r
558         if(type(o) != OT_INSTANCE) return sq_throwerror(v,_SC("the object is not a class instance"));\r
559         (*p) = _instance(o)->_userpointer;\r
560         if(typetag != 0) {\r
561                 SQClass *cl = _instance(o)->_class;\r
562                 do{\r
563                         if(cl->_typetag == typetag)\r
564                                 return SQ_OK;\r
565                         cl = cl->_base;\r
566                 }while(cl != NULL);\r
567                 return sq_throwerror(v,_SC("invalid type tag"));\r
568         }\r
569         return SQ_OK;\r
570 }\r
571 \r
572 SQInteger sq_gettop(HSQUIRRELVM v)\r
573 {\r
574         return (v->_top) - v->_stackbase;\r
575 }\r
576 \r
577 void sq_settop(HSQUIRRELVM v, SQInteger newtop)\r
578 {\r
579         SQInteger top = sq_gettop(v);\r
580         if(top > newtop)\r
581                 sq_pop(v, top - newtop);\r
582         else\r
583                 while(top < newtop) sq_pushnull(v);\r
584 }\r
585 \r
586 void sq_pop(HSQUIRRELVM v, SQInteger nelemstopop)\r
587 {\r
588         assert(v->_top >= nelemstopop);\r
589         v->Pop(nelemstopop);\r
590 }\r
591 \r
592 void sq_poptop(HSQUIRRELVM v)\r
593 {\r
594         assert(v->_top >= 1);\r
595     v->Pop();\r
596 }\r
597 \r
598 \r
599 void sq_remove(HSQUIRRELVM v, SQInteger idx)\r
600 {\r
601         v->Remove(idx);\r
602 }\r
603 \r
604 SQInteger sq_cmp(HSQUIRRELVM v)\r
605 {\r
606         SQInteger res;\r
607         v->ObjCmp(stack_get(v, -1), stack_get(v, -2),res);\r
608         return res;\r
609 }\r
610 \r
611 SQRESULT sq_createslot(HSQUIRRELVM v, SQInteger idx)\r
612 {\r
613         sq_aux_paramscheck(v, 3);\r
614         SQObjectPtr &self = stack_get(v, idx);\r
615         if(type(self) == OT_TABLE || type(self) == OT_CLASS) {\r
616                 SQObjectPtr &key = v->GetUp(-2);\r
617                 if(type(key) == OT_NULL) return sq_throwerror(v, _SC("null is not a valid key"));\r
618                 v->NewSlot(self, key, v->GetUp(-1));\r
619                 v->Pop(2);\r
620         }\r
621         return SQ_OK;\r
622 }\r
623 \r
624 SQRESULT sq_deleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval)\r
625 {\r
626         sq_aux_paramscheck(v, 2);\r
627         SQObjectPtr *self;\r
628         _GETSAFE_OBJ(v, idx, OT_TABLE,self);\r
629         SQObjectPtr &key = v->GetUp(-1);\r
630         if(type(key) == OT_NULL) return sq_throwerror(v, _SC("null is not a valid key"));\r
631         SQObjectPtr res;\r
632         if(!v->DeleteSlot(*self, key, res)){\r
633                 return SQ_ERROR;\r
634         }\r
635         if(pushval)     v->GetUp(-1) = res;\r
636         else v->Pop(1);\r
637         return SQ_OK;\r
638 }\r
639 \r
640 SQRESULT sq_set(HSQUIRRELVM v,SQInteger idx)\r
641 {\r
642         SQObjectPtr &self = stack_get(v, idx);\r
643         if(v->Set(self, v->GetUp(-2), v->GetUp(-1),false)) {\r
644                 v->Pop(2);\r
645                 return SQ_OK;\r
646         }\r
647         v->Raise_IdxError(v->GetUp(-2));return SQ_ERROR;\r
648 }\r
649 \r
650 SQRESULT sq_rawset(HSQUIRRELVM v,SQInteger idx)\r
651 {\r
652         SQObjectPtr &self = stack_get(v, idx);\r
653         if(type(v->GetUp(-2)) == OT_NULL) return sq_throwerror(v, _SC("null key"));\r
654         switch(type(self)) {\r
655         case OT_TABLE:\r
656                 _table(self)->NewSlot(v->GetUp(-2), v->GetUp(-1));\r
657                 v->Pop(2);\r
658                 return SQ_OK;\r
659         break;\r
660         case OT_CLASS:\r
661                 _class(self)->NewSlot(v->GetUp(-2), v->GetUp(-1));\r
662                 v->Pop(2);\r
663                 return SQ_OK;\r
664         break;\r
665         case OT_INSTANCE:\r
666                 if(_instance(self)->Set(v->GetUp(-2), v->GetUp(-1))) {\r
667                         v->Pop(2);\r
668                         return SQ_OK;\r
669                 }\r
670         break;\r
671         case OT_ARRAY:\r
672                 if(v->Set(self, v->GetUp(-2), v->GetUp(-1),false)) {\r
673                         v->Pop(2);\r
674                         return SQ_OK;\r
675                 }\r
676         break;\r
677         default:\r
678                 v->Pop(2);\r
679                 return sq_throwerror(v, _SC("rawset works only on array/table/calsse and instance"));\r
680         }\r
681         v->Raise_IdxError(v->GetUp(-2));return SQ_ERROR;\r
682 }\r
683 \r
684 SQRESULT sq_setdelegate(HSQUIRRELVM v,SQInteger idx)\r
685 {\r
686         SQObjectPtr &self = stack_get(v, idx);\r
687         SQObjectPtr &mt = v->GetUp(-1);\r
688         SQObjectType type = type(self);\r
689         switch(type) {\r
690         case OT_TABLE:\r
691                 if(type(mt) == OT_TABLE) {\r
692                         if(!_table(self)->SetDelegate(_table(mt))) return sq_throwerror(v, _SC("delagate cycle")); v->Pop();}\r
693                 else if(type(mt)==OT_NULL) {\r
694                         _table(self)->SetDelegate(NULL); v->Pop(); }\r
695                 else return sq_aux_invalidtype(v,type);\r
696                 break;\r
697         case OT_USERDATA:\r
698                 if(type(mt)==OT_TABLE) {\r
699                         _userdata(self)->SetDelegate(_table(mt)); v->Pop(); }\r
700                 else if(type(mt)==OT_NULL) {\r
701                         _userdata(self)->SetDelegate(NULL); v->Pop(); }\r
702                 else return sq_aux_invalidtype(v, type);\r
703                 break;\r
704         default:\r
705                         return sq_aux_invalidtype(v, type);\r
706                 break;\r
707         }\r
708         return SQ_OK;\r
709 }\r
710 \r
711 SQRESULT sq_rawdeleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval)\r
712 {\r
713         sq_aux_paramscheck(v, 2);\r
714         SQObjectPtr *self;\r
715         _GETSAFE_OBJ(v, idx, OT_TABLE,self);\r
716         SQObjectPtr &key = v->GetUp(-1);\r
717         SQObjectPtr t;\r
718         if(_table(*self)->Get(key,t)) {\r
719                 _table(*self)->Remove(key);\r
720         }\r
721         if(pushval != 0)\r
722                 if(pushval)     v->GetUp(-1) = t;\r
723         else\r
724                 v->Pop(1);\r
725         return SQ_OK;\r
726 }\r
727 \r
728 SQRESULT sq_getdelegate(HSQUIRRELVM v,SQInteger idx)\r
729 {\r
730         SQObjectPtr &self=stack_get(v,idx);\r
731         switch(type(self)){\r
732         case OT_TABLE:\r
733                 if(!_table(self)->_delegate)break;\r
734                 v->Push(SQObjectPtr(_table(self)->_delegate));\r
735                 return SQ_OK;\r
736                 break;\r
737         case OT_USERDATA:\r
738                 if(!_userdata(self)->_delegate)break;\r
739                 v->Push(SQObjectPtr(_userdata(self)->_delegate));\r
740                 return SQ_OK;\r
741                 break;\r
742         }\r
743         return sq_throwerror(v,_SC("wrong type"));\r
744 }\r
745 \r
746 SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx)\r
747 {\r
748         SQObjectPtr &self=stack_get(v,idx);\r
749         if(v->Get(self,v->GetUp(-1),v->GetUp(-1),false,false))\r
750                 return SQ_OK;\r
751         v->Pop(1);\r
752         return sq_throwerror(v,_SC("the index doesn't exist"));\r
753 }\r
754 \r
755 SQRESULT sq_rawget(HSQUIRRELVM v,SQInteger idx)\r
756 {\r
757         SQObjectPtr &self=stack_get(v,idx);\r
758         switch(type(self)) {\r
759         case OT_TABLE:\r
760                 if(_table(self)->Get(v->GetUp(-1),v->GetUp(-1)))\r
761                         return SQ_OK;\r
762                 break;\r
763         case OT_CLASS:\r
764                 if(_class(self)->Get(v->GetUp(-1),v->GetUp(-1)))\r
765                         return SQ_OK;\r
766                 break;\r
767         case OT_INSTANCE:\r
768                 if(_instance(self)->Get(v->GetUp(-1),v->GetUp(-1)))\r
769                         return SQ_OK;\r
770                 break;\r
771         case OT_ARRAY:\r
772                 if(v->Get(self,v->GetUp(-1),v->GetUp(-1),false,false))\r
773                         return SQ_OK;\r
774                 break;\r
775         default:\r
776                 v->Pop(1);\r
777                 return sq_throwerror(v,_SC("rawget works only on array/table/instance and class"));\r
778         }       \r
779         v->Pop(1);\r
780         return sq_throwerror(v,_SC("the index doesn't exist"));\r
781 }\r
782 \r
783 SQRESULT sq_getstackobj(HSQUIRRELVM v,SQInteger idx,HSQOBJECT *po)\r
784 {\r
785         *po=stack_get(v,idx);\r
786         return SQ_OK;\r
787 }\r
788 \r
789 const SQChar *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger idx)\r
790 {\r
791         SQUnsignedInteger cstksize=v->_callsstack.size();\r
792         SQUnsignedInteger lvl=(cstksize-level)-1;\r
793         SQInteger stackbase=v->_stackbase;\r
794         if(lvl<cstksize){\r
795                 for(SQUnsignedInteger i=0;i<level;i++){\r
796                         SQVM::CallInfo &ci=v->_callsstack[(cstksize-i)-1];\r
797                         stackbase-=ci._prevstkbase;\r
798                 }\r
799                 SQVM::CallInfo &ci=v->_callsstack[lvl];\r
800                 if(type(ci._closure)!=OT_CLOSURE)\r
801                         return NULL;\r
802                 SQClosure *c=_closure(ci._closure);\r
803                 SQFunctionProto *func=_funcproto(c->_function);\r
804                 return func->GetLocal(v,stackbase,idx,(ci._ip-func->_instructions._vals)-1);\r
805         }\r
806         return NULL;\r
807 }\r
808 \r
809 void sq_pushobject(HSQUIRRELVM v,HSQOBJECT obj)\r
810 {\r
811         v->Push(SQObjectPtr(obj));\r
812 }\r
813 \r
814 void sq_resetobject(HSQOBJECT *po)\r
815 {\r
816         po->_unVal.pUserPointer=NULL;po->_type=OT_NULL;\r
817 }\r
818 \r
819 SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err)\r
820 {\r
821         v->_lasterror=SQString::Create(_ss(v),err);\r
822         return -1;\r
823 }\r
824 \r
825 void sq_reseterror(HSQUIRRELVM v)\r
826 {\r
827         v->_lasterror = _null_;\r
828 }\r
829 \r
830 void sq_getlasterror(HSQUIRRELVM v)\r
831 {\r
832         v->Push(v->_lasterror);\r
833 }\r
834 \r
835 void sq_reservestack(HSQUIRRELVM v,SQInteger nsize)\r
836 {\r
837         if (((SQUnsignedInteger)v->_top + nsize) > v->_stack.size()) {\r
838                 v->_stack.resize(v->_stack.size() + ((v->_top + nsize) - v->_stack.size()));\r
839         }\r
840 }\r
841 \r
842 SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval)\r
843 {\r
844         if(type(v->GetUp(-1))==OT_GENERATOR){\r
845                 v->Push(_null_); //retval\r
846                 if(!v->Execute(v->GetUp(-2),v->_top,0,v->_top,v->GetUp(-1),SQVM::ET_RESUME_GENERATOR))\r
847                 {v->Raise_Error(v->_lasterror); return SQ_ERROR;}\r
848                 if(!retval)\r
849                         v->Pop();\r
850                 return SQ_OK;\r
851         }\r
852         return sq_throwerror(v,_SC("only generators can be resumed"));\r
853 }\r
854 \r
855 SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval)\r
856 {\r
857         SQObjectPtr res;\r
858         if(v->Call(v->GetUp(-(params+1)),params,v->_top-params,res)){\r
859                 v->Pop(params);//pop closure and args\r
860                 if(retval){\r
861                         v->Push(res); return SQ_OK;\r
862                 }\r
863                 return SQ_OK;\r
864         }\r
865         else {\r
866                 v->Pop(params);\r
867                 return SQ_ERROR;\r
868         }\r
869         if(!v->_suspended)\r
870                 v->Pop(params);\r
871         return sq_throwerror(v,_SC("call failed"));\r
872 }\r
873 \r
874 SQRESULT sq_suspendvm(HSQUIRRELVM v)\r
875 {\r
876         return v->Suspend();\r
877 }\r
878 \r
879 SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool wakeupret,SQBool retval)\r
880 {\r
881         SQObjectPtr ret;\r
882         if(!v->_suspended)\r
883                 return sq_throwerror(v,_SC("cannot resume a vm that is not running any code"));\r
884         if(wakeupret) {\r
885                 v->GetAt(v->_stackbase+v->_suspended_target)=v->GetUp(-1); //retval\r
886                 v->Pop();\r
887         } else v->GetAt(v->_stackbase+v->_suspended_target)=_null_;\r
888         if(!v->Execute(_null_,v->_top,-1,-1,ret,SQVM::ET_RESUME_VM))\r
889                 return SQ_ERROR;\r
890         if(sq_getvmstate(v) == SQ_VMSTATE_IDLE) {\r
891                 while (v->_top > 1) v->_stack[--v->_top] = _null_;\r
892         }\r
893         if(retval)\r
894                 v->Push(ret);\r
895         return SQ_OK;\r
896 }\r
897 \r
898 void sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook)\r
899 {\r
900         if(sq_gettop(v) >= 1){\r
901                 SQObjectPtr &ud=stack_get(v,idx);\r
902                 switch( type(ud) ) {\r
903                 case OT_USERDATA:\r
904                         _userdata(ud)->_hook = hook;\r
905                         break;\r
906                 case OT_INSTANCE:\r
907                         _instance(ud)->_hook = hook;\r
908                         break;\r
909                 }\r
910         }\r
911 }\r
912 \r
913 void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f)\r
914 {\r
915         _ss(v)->_compilererrorhandler = f;\r
916 }\r
917 \r
918 SQRESULT sq_writeclosure(HSQUIRRELVM v,SQWRITEFUNC w,SQUserPointer up)\r
919 {\r
920         SQObjectPtr *o = NULL;\r
921         _GETSAFE_OBJ(v, -1, OT_CLOSURE,o);\r
922         SQClosure *c=_closure(*o);\r
923         unsigned short tag = SQ_BYTECODE_STREAM_TAG;\r
924         if(w(up,&tag,2) != 2)\r
925                 return sq_throwerror(v,_SC("io error"));\r
926         if(!_closure(*o)->Save(v,up,w))\r
927                 return SQ_ERROR;\r
928         return SQ_OK;\r
929 }\r
930 \r
931 SQRESULT sq_readclosure(HSQUIRRELVM v,SQREADFUNC r,SQUserPointer up)\r
932 {\r
933         SQObjectPtr func=SQFunctionProto::Create();\r
934         SQObjectPtr closure=SQClosure::Create(_ss(v),_funcproto(func));\r
935         unsigned short tag;\r
936         if(r(up,&tag,2) != 2)\r
937                 return sq_throwerror(v,_SC("io error"));\r
938         if(tag != SQ_BYTECODE_STREAM_TAG)\r
939                 return sq_throwerror(v,_SC("invalid stream"));\r
940         if(!_closure(closure)->Load(v,up,r))\r
941                 return SQ_ERROR;\r
942         v->Push(closure);\r
943         return SQ_OK;\r
944 }\r
945 \r
946 SQChar *sq_getscratchpad(HSQUIRRELVM v,SQInteger minsize)\r
947 {\r
948         return _ss(v)->GetScratchPad(minsize);\r
949 }\r
950 \r
951 SQInteger sq_collectgarbage(HSQUIRRELVM v)\r
952 {\r
953 #ifndef NO_GARBAGE_COLLECTOR\r
954         return _ss(v)->CollectGarbage(v);\r
955 #else\r
956         return -1;\r
957 #endif\r
958 }\r
959 \r
960 const SQChar *sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval)\r
961 {\r
962         SQObjectPtr &self = stack_get(v,idx);\r
963         const SQChar *name = NULL;\r
964         if(type(self) == OT_CLOSURE) {\r
965                 if(_closure(self)->_outervalues.size()>nval) {\r
966                         v->Push(_closure(self)->_outervalues[nval]);\r
967                         SQFunctionProto *fp = _funcproto(_closure(self)->_function);\r
968                         SQOuterVar &ov = fp->_outervalues[nval];\r
969                         name = _stringval(ov._name);\r
970                 }\r
971         }\r
972         return name;\r
973 }\r
974 \r
975 SQRESULT sq_setfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval)\r
976 {\r
977         SQObjectPtr &self=stack_get(v,idx);\r
978         switch(type(self))\r
979         {\r
980         case OT_CLOSURE:\r
981                 if(_closure(self)->_outervalues.size()>nval){\r
982                         _closure(self)->_outervalues[nval]=stack_get(v,-1);\r
983                 }\r
984                 else return sq_throwerror(v,_SC("invalid free var index"));\r
985                 break;\r
986         case OT_NATIVECLOSURE:\r
987                 if(_nativeclosure(self)->_outervalues.size()>nval){\r
988                         _nativeclosure(self)->_outervalues[nval]=stack_get(v,-1);\r
989                 }\r
990                 else return sq_throwerror(v,_SC("invalid free var index"));\r
991                 break;\r
992         default:\r
993                 return sq_aux_invalidtype(v,type(self));\r
994         }\r
995         v->Pop(1);\r
996         return SQ_OK;\r
997 }\r
998 \r
999 SQRESULT sq_setattributes(HSQUIRRELVM v,SQInteger idx)\r
1000 {\r
1001         SQObjectPtr *o = NULL;\r
1002         _GETSAFE_OBJ(v, idx, OT_CLASS,o);\r
1003         SQObjectPtr &key = stack_get(v,-2);\r
1004         SQObjectPtr &val = stack_get(v,-1);\r
1005         SQObjectPtr attrs;\r
1006         if(type(key) == OT_NULL) {\r
1007                 attrs = _class(*o)->_attributes;\r
1008                 _class(*o)->_attributes = val;\r
1009                 v->Pop(2);\r
1010                 v->Push(attrs);\r
1011                 return SQ_OK;\r
1012         }else if(_class(*o)->GetAttributes(key,attrs)) {\r
1013                 _class(*o)->SetAttributes(key,val);\r
1014                 v->Pop(2);\r
1015                 v->Push(attrs);\r
1016                 return SQ_OK;\r
1017         }\r
1018         return sq_throwerror(v,_SC("wrong index"));\r
1019 }\r
1020 \r
1021 SQRESULT sq_getattributes(HSQUIRRELVM v,SQInteger idx)\r
1022 {\r
1023         SQObjectPtr *o = NULL;\r
1024         _GETSAFE_OBJ(v, idx, OT_CLASS,o);\r
1025         SQObjectPtr &key = stack_get(v,-1);\r
1026         SQObjectPtr attrs;\r
1027         if(type(key) == OT_NULL) {\r
1028                 attrs = _class(*o)->_attributes;\r
1029                 v->Pop();\r
1030                 v->Push(attrs);\r
1031                 return SQ_OK;\r
1032         }\r
1033         else if(_class(*o)->GetAttributes(key,attrs)) {\r
1034                 v->Pop();\r
1035                 v->Push(attrs);\r
1036                 return SQ_OK;\r
1037         }\r
1038         return sq_throwerror(v,_SC("wrong index"));\r
1039 }\r
1040 \r
1041 SQRESULT sq_getclass(HSQUIRRELVM v,SQInteger idx)\r
1042 {\r
1043         SQObjectPtr *o = NULL;\r
1044         _GETSAFE_OBJ(v, idx, OT_INSTANCE,o);\r
1045         v->Push(SQObjectPtr(_instance(*o)->_class));\r
1046         return SQ_OK;\r
1047 }\r
1048 \r
1049 SQRESULT sq_createinstance(HSQUIRRELVM v,SQInteger idx)\r
1050 {\r
1051         SQObjectPtr *o = NULL;\r
1052         _GETSAFE_OBJ(v, idx, OT_CLASS,o);\r
1053         v->Push(_class(*o)->CreateInstance());\r
1054         return SQ_OK;\r
1055 }\r
1056 \r
1057 void sq_weakref(HSQUIRRELVM v,SQInteger idx)\r
1058 {\r
1059         SQObject &o=stack_get(v,idx);\r
1060         if(ISREFCOUNTED(type(o))) {\r
1061                 v->Push(_refcounted(o)->GetWeakRef(type(o)));\r
1062                 return;\r
1063         }\r
1064         v->Push(o);\r
1065 }\r
1066 \r
1067 SQRESULT sq_getweakrefval(HSQUIRRELVM v,SQInteger idx)\r
1068 {\r
1069         SQObjectPtr &o = stack_get(v,idx);\r
1070         if(type(o) != OT_WEAKREF) {\r
1071                 return sq_throwerror(v,_SC("the object must be a weakref"));\r
1072         }\r
1073         v->Push(_weakref(o)->_obj);\r
1074         return SQ_OK;\r
1075 }\r
1076 \r
1077 SQRESULT sq_next(HSQUIRRELVM v,SQInteger idx)\r
1078 {\r
1079         SQObjectPtr o=stack_get(v,idx),&refpos = stack_get(v,-1),realkey,val;\r
1080         if(type(o) == OT_GENERATOR) {\r
1081                 return sq_throwerror(v,_SC("cannot iterate a generator"));\r
1082         }\r
1083         bool finished;\r
1084         if(!v->FOREACH_OP(o,realkey,val,refpos,0,finished))\r
1085                 return SQ_ERROR;\r
1086         if(!finished) {\r
1087                 v->Push(realkey);\r
1088                 v->Push(val);\r
1089                 return SQ_OK;\r
1090         }\r
1091         return SQ_ERROR;\r
1092 }\r
1093 \r
1094 struct BufState{\r
1095         const SQChar *buf;\r
1096         SQInteger ptr;\r
1097         SQInteger size;\r
1098 };\r
1099 \r
1100 SQInteger buf_lexfeed(SQUserPointer file)\r
1101 {\r
1102         BufState *buf=(BufState*)file;\r
1103         if(buf->size<(buf->ptr+1))\r
1104                 return 0;\r
1105         return buf->buf[buf->ptr++];\r
1106 }\r
1107 \r
1108 SQRESULT sq_compilebuffer(HSQUIRRELVM v,const SQChar *s,SQInteger size,const SQChar *sourcename,SQBool raiseerror) {\r
1109         BufState buf;\r
1110         buf.buf = s;\r
1111         buf.size = size;\r
1112         buf.ptr = 0;\r
1113         return sq_compile(v, buf_lexfeed, &buf, sourcename, raiseerror);\r
1114 }\r
1115 \r
1116 void sq_move(HSQUIRRELVM dest,HSQUIRRELVM src,SQInteger idx)\r
1117 {\r
1118         dest->Push(stack_get(src,idx));\r
1119 }\r
1120 \r
1121 void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc)\r
1122 {\r
1123         _ss(v)->_printfunc = printfunc;\r
1124 }\r
1125 \r
1126 SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v)\r
1127 {\r
1128         return _ss(v)->_printfunc;\r
1129 }\r
1130 \r
1131 void *sq_malloc(SQUnsignedInteger size)\r
1132 {\r
1133         return SQ_MALLOC(size);\r
1134 }\r
1135 \r
1136 void *sq_realloc(void* p,SQUnsignedInteger oldsize,SQUnsignedInteger newsize)\r
1137 {\r
1138         return SQ_REALLOC(p,oldsize,newsize);\r
1139 }\r
1140 void sq_free(void *p,SQUnsignedInteger size)\r
1141 {\r
1142         SQ_FREE(p,size);\r
1143 }\r