jsstate.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. #include "jsi.h"
  2. #include <assert.h>
  3. #include <errno.h>
  4. static int js_ptry(js_State *J) {
  5. if (J->trytop == JS_TRYLIMIT) {
  6. J->stack[J->top].t.type = JS_TLITSTR;
  7. J->stack[J->top].u.litstr = "exception stack overflow";
  8. ++J->top;
  9. return 1;
  10. }
  11. return 0;
  12. }
  13. static void *js_defaultalloc(void *actx, void *ptr, int size)
  14. {
  15. if (size == 0) {
  16. free(ptr);
  17. return NULL;
  18. }
  19. return realloc(ptr, (size_t)size);
  20. }
  21. static void js_defaultreport(js_State *J, const char *message)
  22. {
  23. fputs(message, stderr);
  24. fputc('\n', stderr);
  25. }
  26. static void js_defaultpanic(js_State *J)
  27. {
  28. js_report(J, "uncaught exception");
  29. /* return to javascript to abort */
  30. }
  31. int js_ploadstring(js_State *J, const char *filename, const char *source)
  32. {
  33. if (js_ptry(J))
  34. return 1;
  35. if (js_try(J))
  36. return 1;
  37. js_loadstring(J, filename, source);
  38. js_endtry(J);
  39. return 0;
  40. }
  41. int js_ploadfile(js_State *J, const char *filename)
  42. {
  43. if (js_ptry(J))
  44. return 1;
  45. if (js_try(J))
  46. return 1;
  47. js_loadfile(J, filename);
  48. js_endtry(J);
  49. return 0;
  50. }
  51. const char *js_trystring(js_State *J, int idx, const char *error)
  52. {
  53. const char *s;
  54. if (js_ptry(J)) {
  55. js_pop(J, 1);
  56. return error;
  57. }
  58. if (js_try(J)) {
  59. js_pop(J, 1);
  60. return error;
  61. }
  62. s = js_tostring(J, idx);
  63. js_endtry(J);
  64. return s;
  65. }
  66. double js_trynumber(js_State *J, int idx, double error)
  67. {
  68. double v;
  69. if (js_ptry(J)) {
  70. js_pop(J, 1);
  71. return error;
  72. }
  73. if (js_try(J)) {
  74. js_pop(J, 1);
  75. return error;
  76. }
  77. v = js_tonumber(J, idx);
  78. js_endtry(J);
  79. return v;
  80. }
  81. int js_tryinteger(js_State *J, int idx, int error)
  82. {
  83. int v;
  84. if (js_ptry(J)) {
  85. js_pop(J, 1);
  86. return error;
  87. }
  88. if (js_try(J)) {
  89. js_pop(J, 1);
  90. return error;
  91. }
  92. v = js_tointeger(J, idx);
  93. js_endtry(J);
  94. return v;
  95. }
  96. int js_tryboolean(js_State *J, int idx, int error)
  97. {
  98. int v;
  99. if (js_ptry(J)) {
  100. js_pop(J, 1);
  101. return error;
  102. }
  103. if (js_try(J)) {
  104. js_pop(J, 1);
  105. return error;
  106. }
  107. v = js_toboolean(J, idx);
  108. js_endtry(J);
  109. return v;
  110. }
  111. static void js_loadstringx(js_State *J, const char *filename, const char *source, int iseval)
  112. {
  113. js_Ast *P;
  114. js_Function *F;
  115. if (js_try(J)) {
  116. jsP_freeparse(J);
  117. js_throw(J);
  118. }
  119. P = jsP_parse(J, filename, source);
  120. F = jsC_compilescript(J, P, iseval ? J->strict : J->default_strict);
  121. jsP_freeparse(J);
  122. js_newscript(J, F, iseval ? (J->strict ? J->E : NULL) : J->GE);
  123. js_endtry(J);
  124. }
  125. void js_loadeval(js_State *J, const char *filename, const char *source)
  126. {
  127. js_loadstringx(J, filename, source, 1);
  128. }
  129. void js_loadstring(js_State *J, const char *filename, const char *source)
  130. {
  131. js_loadstringx(J, filename, source, 0);
  132. }
  133. void js_loadfile(js_State *J, const char *filename)
  134. {
  135. FILE *f;
  136. char *s, *p;
  137. int n, t;
  138. f = fopen(filename, "rb");
  139. if (!f) {
  140. js_error(J, "cannot open file '%s': %s", filename, strerror(errno));
  141. }
  142. if (fseek(f, 0, SEEK_END) < 0) {
  143. fclose(f);
  144. js_error(J, "cannot seek in file '%s': %s", filename, strerror(errno));
  145. }
  146. n = ftell(f);
  147. if (n < 0) {
  148. fclose(f);
  149. js_error(J, "cannot tell in file '%s': %s", filename, strerror(errno));
  150. }
  151. if (fseek(f, 0, SEEK_SET) < 0) {
  152. fclose(f);
  153. js_error(J, "cannot seek in file '%s': %s", filename, strerror(errno));
  154. }
  155. if (js_try(J)) {
  156. fclose(f);
  157. js_throw(J);
  158. }
  159. s = js_malloc(J, n + 1); /* add space for string terminator */
  160. js_endtry(J);
  161. t = fread(s, 1, (size_t)n, f);
  162. if (t != n) {
  163. js_free(J, s);
  164. fclose(f);
  165. js_error(J, "cannot read data from file '%s': %s", filename, strerror(errno));
  166. }
  167. s[n] = 0; /* zero-terminate string containing file data */
  168. if (js_try(J)) {
  169. js_free(J, s);
  170. fclose(f);
  171. js_throw(J);
  172. }
  173. /* skip first line if it starts with "#!" */
  174. p = s;
  175. if (p[0] == '#' && p[1] == '!') {
  176. p += 2;
  177. while (*p && *p != '\n')
  178. ++p;
  179. }
  180. js_loadstring(J, filename, p);
  181. js_free(J, s);
  182. fclose(f);
  183. js_endtry(J);
  184. }
  185. int js_dostring(js_State *J, const char *source)
  186. {
  187. if (js_ptry(J)) {
  188. js_report(J, "exception stack overflow");
  189. js_pop(J, 1);
  190. return 1;
  191. }
  192. if (js_try(J)) {
  193. js_report(J, js_trystring(J, -1, "Error"));
  194. js_pop(J, 1);
  195. return 1;
  196. }
  197. js_loadstring(J, "[string]", source);
  198. js_pushundefined(J);
  199. js_call(J, 0);
  200. js_pop(J, 1);
  201. js_endtry(J);
  202. return 0;
  203. }
  204. int js_dofile(js_State *J, const char *filename)
  205. {
  206. if (js_ptry(J)) {
  207. js_report(J, "exception stack overflow");
  208. js_pop(J, 1);
  209. return 1;
  210. }
  211. if (js_try(J)) {
  212. js_report(J, js_trystring(J, -1, "Error"));
  213. js_pop(J, 1);
  214. return 1;
  215. }
  216. js_loadfile(J, filename);
  217. js_pushundefined(J);
  218. js_call(J, 0);
  219. js_pop(J, 1);
  220. js_endtry(J);
  221. return 0;
  222. }
  223. js_Panic js_atpanic(js_State *J, js_Panic panic)
  224. {
  225. js_Panic old = J->panic;
  226. J->panic = panic;
  227. return old;
  228. }
  229. void js_report(js_State *J, const char *message)
  230. {
  231. if (J->report)
  232. J->report(J, message);
  233. }
  234. void js_setreport(js_State *J, js_Report report)
  235. {
  236. J->report = report;
  237. }
  238. void js_setcontext(js_State *J, void *uctx)
  239. {
  240. J->uctx = uctx;
  241. }
  242. void *js_getcontext(js_State *J)
  243. {
  244. return J->uctx;
  245. }
  246. js_State *js_newstate(js_Alloc alloc, void *actx, int flags)
  247. {
  248. js_State *J;
  249. assert(sizeof(js_Value) == 16);
  250. assert(soffsetof(js_Value, t.type) == 15);
  251. if (!alloc)
  252. alloc = js_defaultalloc;
  253. J = alloc(actx, NULL, sizeof *J);
  254. if (!J)
  255. return NULL;
  256. memset(J, 0, sizeof(*J));
  257. J->actx = actx;
  258. J->alloc = alloc;
  259. if (flags & JS_STRICT)
  260. J->strict = J->default_strict = 1;
  261. J->trace[0].name = "-top-";
  262. J->trace[0].file = "native";
  263. J->trace[0].line = 0;
  264. J->report = js_defaultreport;
  265. J->panic = js_defaultpanic;
  266. J->stack = alloc(actx, NULL, JS_STACKSIZE * sizeof *J->stack);
  267. if (!J->stack) {
  268. alloc(actx, J, 0);
  269. return NULL;
  270. }
  271. J->gcmark = 1;
  272. J->nextref = 0;
  273. J->gcthresh = 0; /* reaches stability within ~ 2-5 GC cycles */
  274. if (js_try(J)) {
  275. js_freestate(J);
  276. return NULL;
  277. }
  278. J->R = jsV_newobject(J, JS_COBJECT, NULL);
  279. J->G = jsV_newobject(J, JS_COBJECT, NULL);
  280. J->E = jsR_newenvironment(J, J->G, NULL);
  281. J->GE = J->E;
  282. jsB_init(J);
  283. js_endtry(J);
  284. return J;
  285. }