sq_slave_vm.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. /*
  2. ** Rings: Multiple Lua States
  3. ** $Id: rings.c,v 1.24 2008/06/30 17:52:31 carregal Exp $
  4. ** See Copyright Notice in license.html
  5. */
  6. #include <string.h>
  7. #include <stdio.h>
  8. #include "squirrel.h"
  9. #include <sqstdblob.h>
  10. #include <sqstdsystem.h>
  11. #include <sqstdio.h>
  12. #include <sqstdmath.h>
  13. #include <sqstdstring.h>
  14. /*
  15. ** Copies values from State src to State dst.
  16. */
  17. static SQRESULT copy_values_between_vms (HSQUIRRELVM dst, HSQUIRRELVM src, int argc, int argIdx)
  18. {
  19. SQRESULT _rc_;
  20. sq_reservestack(dst, argc + 20);
  21. argc += argIdx; //we will work with argc args starting at argIdx
  22. for (; argIdx < argc; argIdx++)
  23. {
  24. switch (sq_gettype(src, argIdx))
  25. {
  26. case OT_INTEGER:
  27. SQ_GET_INTEGER(src, argIdx, vint);
  28. sq_pushinteger(dst, vint);
  29. break;
  30. case OT_FLOAT:
  31. SQ_GET_FLOAT(src, argIdx, vfloat);
  32. sq_pushfloat (dst, vfloat);
  33. break;
  34. case OT_BOOL:
  35. SQ_GET_BOOL(src, argIdx, vbool);
  36. sq_pushbool (dst, vbool);
  37. break;
  38. case OT_STRING:
  39. {
  40. SQ_GET_STRING(src, argIdx, vstr)
  41. sq_pushstring (dst, vstr, vstr_size);
  42. }
  43. break;
  44. case OT_ARRAY:
  45. {
  46. SQInteger size = sq_getsize(src, argIdx);
  47. sq_newarray(dst, size);
  48. for(SQInteger i=0; i<size; ++i)
  49. {
  50. sq_pushinteger(src, i);
  51. sq_get(src, -2);
  52. sq_pushinteger(dst, i);
  53. if(copy_values_between_vms(dst, src, 1, sq_gettop(src)) != SQ_OK) return SQ_ERROR;
  54. sq_poptop(src);
  55. sq_set(dst, -3);
  56. }
  57. }
  58. break;
  59. case OT_TABLE:
  60. {
  61. sq_newtable(dst);
  62. sq_pushnull(src);
  63. while(sq_next(src, -2) == SQ_OK)
  64. {
  65. SQInteger src_top = sq_gettop(src);
  66. if(copy_values_between_vms(dst, src, 1, src_top-1) != SQ_OK
  67. || copy_values_between_vms(dst, src, 1, src_top) != SQ_OK) return SQ_ERROR;
  68. sq_newslot(dst, -3, SQFalse);
  69. sq_pop(src, 2);
  70. }
  71. sq_pop(src,1);
  72. }
  73. break;
  74. case OT_USERPOINTER:
  75. {
  76. SQUserPointer ptr;
  77. sq_getuserpointer(src, argIdx, &ptr);
  78. sq_pushuserpointer(dst, ptr);
  79. }
  80. break;
  81. case OT_NULL:
  82. sq_pushnull(dst);
  83. break;
  84. default:
  85. return SQ_ERROR;
  86. }
  87. }
  88. return SQ_OK;
  89. }
  90. static const SQChar sq_slave_vm_TAG[] = _SC("SlaveVM");
  91. static SQRESULT get_slave_vm_instance(HSQUIRRELVM v, SQInteger idx, HSQUIRRELVM *vm)
  92. {
  93. if(sq_getinstanceup(v, idx, (SQUserPointer*)vm, (void*)sq_slave_vm_TAG) != SQ_OK) return SQ_ERROR;
  94. if(!vm) return sq_throwerror(v, _SC("slave vm already closed"));
  95. return SQ_OK;
  96. }
  97. #define GET_sq_slave_vm_INSTANCE(v, idx) \
  98. HSQUIRRELVM self=NULL; if(get_slave_vm_instance(v, idx, &self) != SQ_OK) return SQ_ERROR;
  99. static SQRESULT sq_slave_vm__tostring (HSQUIRRELVM v)
  100. {
  101. GET_sq_slave_vm_INSTANCE(v, 1);
  102. sq_pushfstring (v, _SC("Squirrel vm (%p)"), self);
  103. return 1;
  104. }
  105. static SQRESULT sq_slave_vm_release_hook(SQUserPointer p, SQInteger size, HSQUIRRELVM v)
  106. {
  107. HSQUIRRELVM self = (HSQUIRRELVM)p;
  108. if(self) sq_close(self);
  109. return 0;
  110. }
  111. /*
  112. ** Creates a new SQuirrel vm.
  113. */
  114. static SQRESULT sq_slave_vm_constructor (HSQUIRRELVM v)
  115. {
  116. SQ_FUNC_VARS(v);
  117. SQ_OPT_INTEGER(v, 2, stack_size, 1024);
  118. SQ_OPT_BOOL(v, 3, with_libraries, false);
  119. HSQUIRRELVM self = sq_open(stack_size);
  120. /* Initialize environment */
  121. sq_setprintfunc(self,sq_getprintfunc(v),sq_geterrorfunc(v));
  122. if(with_libraries)
  123. {
  124. /* load base libraries */
  125. sq_pushroottable(self);
  126. sqstd_register_bloblib(self);
  127. sqstd_register_iolib(self);
  128. sqstd_register_systemlib(self);
  129. sqstd_register_mathlib(self);
  130. sqstd_register_stringlib(self);
  131. sq_poptop(self); //remove root table
  132. }
  133. sq_setinstanceup(v, 1, self);
  134. sq_setreleasehook(v, 1, sq_slave_vm_release_hook);
  135. return 1;
  136. }
  137. static SQRESULT sq_slave_vm_close(HSQUIRRELVM v)
  138. {
  139. GET_sq_slave_vm_INSTANCE(v, 1);
  140. sq_close(self);
  141. sq_setinstanceup(v, 1, 0); //next calls will fail with "vm is closed"
  142. return 0;
  143. }
  144. static SQRESULT sq_slave_vm_call(HSQUIRRELVM v)
  145. {
  146. SQ_FUNC_VARS_NO_TOP(v);
  147. GET_sq_slave_vm_INSTANCE(v, 1);
  148. SQ_GET_BOOL(v, 2, has_ret_val);
  149. SQ_GET_STRING(v, 3, func_name);
  150. SQInteger top = sq_gettop(self);
  151. SQRESULT result = SQ_ERROR;
  152. sq_pushroottable(self);
  153. sq_pushstring(self, func_name, func_name_size);
  154. if(sq_get(self, -2) == SQ_OK)
  155. {
  156. switch(sq_gettype(self, -1))
  157. {
  158. case OT_CLOSURE:
  159. case OT_NATIVECLOSURE:
  160. case OT_CLASS:
  161. {
  162. sq_pushroottable(self);
  163. int argc = sq_gettop(v) - 3;
  164. if(argc && copy_values_between_vms(self, v, argc, 4) != SQ_OK)
  165. {
  166. sq_throwerror(v, sq_getlasterror_str(self));
  167. goto cleanup;
  168. }
  169. if(sq_call(self, argc+1, has_ret_val, SQFalse) != SQ_OK)
  170. {
  171. sq_throwerror(v, sq_getlasterror_str(self));
  172. goto cleanup;
  173. }
  174. if(has_ret_val)
  175. {
  176. if(copy_values_between_vms(v, self, 1, sq_gettop(self)) == SQ_OK) result = 1;
  177. }
  178. else result = SQ_OK;
  179. }
  180. }
  181. }
  182. else
  183. {
  184. sq_throwerror(v, sq_getlasterror_str(self));
  185. }
  186. cleanup:
  187. sq_settop(self, top);
  188. return result;
  189. }
  190. static SQRESULT sq_slave_vm_set(HSQUIRRELVM v)
  191. {
  192. GET_sq_slave_vm_INSTANCE(v, 1);
  193. SQInteger top = sq_gettop(self);
  194. SQRESULT result;
  195. sq_pushroottable(self);
  196. if(copy_values_between_vms(self, v, 1, 2) == SQ_OK
  197. && copy_values_between_vms(self, v, 1, 3) == SQ_OK)
  198. {
  199. result = sq_newslot(self, -3, SQFalse);
  200. if(result == SQ_ERROR) sq_throwerror(v, sq_getlasterror_str(self));
  201. }
  202. else result = SQ_ERROR;
  203. sq_settop(self, top);
  204. return result;
  205. }
  206. static SQRESULT sq_slave_vm_get(HSQUIRRELVM v)
  207. {
  208. GET_sq_slave_vm_INSTANCE(v, 1);
  209. SQInteger top = sq_gettop(self);
  210. SQRESULT result = SQ_ERROR;
  211. sq_pushroottable(self);
  212. if(copy_values_between_vms(self, v, 1, 2) == SQ_OK)
  213. {
  214. if(sq_get(self, -2) == SQ_OK
  215. && copy_values_between_vms(v, self, 1, sq_gettop(self)) == SQ_OK)
  216. {
  217. result = 1;
  218. }
  219. else
  220. {
  221. if(sq_gettop(v) == 3) result = 1; //we have a default value
  222. else sq_throwerror(v, sq_getlasterror_str(self));
  223. }
  224. }
  225. sq_settop(self, top);
  226. return result;
  227. }
  228. static SQRESULT sq_slave_vm_dofile(HSQUIRRELVM v)
  229. {
  230. SQ_FUNC_VARS(v);
  231. GET_sq_slave_vm_INSTANCE(v, 1);
  232. SQ_GET_STRING(v, 2, file_name);
  233. SQ_OPT_BOOL(v, 3, retval, false);
  234. SQ_OPT_BOOL(v, 4, printerror, false);
  235. SQ_OPT_BOOL(v, 5, show_warnings, false);
  236. SQInteger top = sq_gettop(self);
  237. SQRESULT result = SQ_ERROR;
  238. sq_pushroottable(self); //important always push the root table, because sqstd_dofile will try to do a sq_push(v, -2)
  239. if(sqstd_dofile(self, file_name, retval, printerror, show_warnings) >= 0)
  240. {
  241. if(retval)
  242. {
  243. if(copy_values_between_vms(v, self, 1, sq_gettop(self)) == SQ_OK) result = 1;
  244. }
  245. else result = SQ_OK;
  246. }
  247. else sq_throwerror(v, sq_getlasterror_str(self));
  248. sq_settop(self, top);
  249. return result;
  250. }
  251. static SQRESULT sq_slave_vm_loadfile(HSQUIRRELVM v)
  252. {
  253. SQ_FUNC_VARS(v);
  254. GET_sq_slave_vm_INSTANCE(v, 1);
  255. SQ_GET_STRING(v, 2, func_name);
  256. SQ_GET_STRING(v, 3, file_name);
  257. SQ_OPT_BOOL(v, 4, printerror, false);
  258. SQ_OPT_BOOL(v, 5, show_warnings, false);
  259. SQInteger top = sq_gettop(self);
  260. SQRESULT result = SQ_ERROR;
  261. sq_pushroottable(self);
  262. sq_pushstring(self, func_name, func_name_size);
  263. if(sqstd_loadfile(self, file_name, printerror, show_warnings) >= 0)
  264. {
  265. result = sq_newslot(self, -3, SQFalse);
  266. }
  267. sq_settop(self, top);
  268. return result;
  269. }
  270. static SQRESULT sq_slave_vm_compilestring(HSQUIRRELVM v)
  271. {
  272. SQ_FUNC_VARS(v);
  273. GET_sq_slave_vm_INSTANCE(v, 1);
  274. SQ_GET_STRING(v, 2, func_name);
  275. SQ_GET_STRING(v, 3, str_script);
  276. SQ_OPT_BOOL(v, 4, printerror, false);
  277. SQ_OPT_BOOL(v, 5, show_warnings, false);
  278. SQInteger top = sq_gettop(self);
  279. SQRESULT result = SQ_ERROR;
  280. sq_pushroottable(self);
  281. sq_pushstring(self, func_name, func_name_size);
  282. if(sq_compilebuffer(self, str_script, str_script_size, func_name, printerror, show_warnings) >= 0)
  283. {
  284. result = sq_newslot(self, -3, SQFalse);
  285. }
  286. else
  287. {
  288. const SQChar *last_error = sq_getlasterror_str(self);
  289. if(last_error) {
  290. SQInteger line, column;
  291. sq_getlasterror_line_col(self, &line, &column);
  292. result = sq_throwerror(v, _SC("compilestring %s %d:%d: %s"), func_name, line, column, last_error);
  293. }
  294. }
  295. sq_settop(self, top);
  296. return result;
  297. }
  298. #ifdef __cplusplus
  299. extern "C" {
  300. #endif
  301. SQRESULT sqext_register_sq_slave_vm(HSQUIRRELVM v)
  302. {
  303. const SQChar get_set_validation_mask[] = _SC("x s|n|p s|n|b|a|t|p|o");
  304. sq_pushstring(v,sq_slave_vm_TAG, -1);
  305. sq_newclass(v, SQFalse);
  306. sq_settypetag(v,-1,(void*)sq_slave_vm_TAG);
  307. sq_insertfunc(v, _SC("constructor"), sq_slave_vm_constructor, -1, _SC("xib"), SQFalse);
  308. sq_insertfunc(v, _SC("_tostring"), sq_slave_vm__tostring, 1, _SC("x"), SQFalse);
  309. sq_insertfunc(v, _SC("close"), sq_slave_vm_close, 1, _SC("x"), SQFalse);
  310. sq_insertfunc(v, _SC("set"), sq_slave_vm_set, 3, get_set_validation_mask, SQFalse);
  311. sq_insertfunc(v, _SC("_set"), sq_slave_vm_set, 3, get_set_validation_mask, SQFalse);
  312. sq_insertfunc(v, _SC("get"), sq_slave_vm_get, -2, get_set_validation_mask, SQFalse);
  313. sq_insertfunc(v, _SC("_get"), sq_slave_vm_get, -2, get_set_validation_mask, SQFalse);
  314. sq_insertfunc(v, _SC("dofile"), sq_slave_vm_dofile, -2, _SC("xsbbb"), SQFalse);
  315. sq_insertfunc(v, _SC("loadfile"), sq_slave_vm_loadfile, -3, _SC("xssbb"), SQFalse);
  316. sq_insertfunc(v, _SC("compilestring"), sq_slave_vm_compilestring, -3, _SC("xssbb"), SQFalse);
  317. sq_insertfunc(v, _SC("call"), sq_slave_vm_call, -3, _SC("xbs"), SQFalse);
  318. sq_newslot(v,-3,SQTrue); //push sq_slave_vm class
  319. return 0;
  320. }
  321. #ifdef __cplusplus
  322. }
  323. #endif