json.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. #include "jsi.h"
  2. #include "utf.h"
  3. int js_isnumberobject(js_State *J, int idx)
  4. {
  5. return js_isobject(J, idx) && js_toobject(J, idx)->type == JS_CNUMBER;
  6. }
  7. int js_isstringobject(js_State *J, int idx)
  8. {
  9. return js_isobject(J, idx) && js_toobject(J, idx)->type == JS_CSTRING;
  10. }
  11. int js_isbooleanobject(js_State *J, int idx)
  12. {
  13. return js_isobject(J, idx) && js_toobject(J, idx)->type == JS_CBOOLEAN;
  14. }
  15. int js_isdateobject(js_State *J, int idx)
  16. {
  17. return js_isobject(J, idx) && js_toobject(J, idx)->type == JS_CDATE;
  18. }
  19. static void jsonnext(js_State *J)
  20. {
  21. J->lookahead = jsY_lexjson(J);
  22. }
  23. static int jsonaccept(js_State *J, int t)
  24. {
  25. if (J->lookahead == t) {
  26. jsonnext(J);
  27. return 1;
  28. }
  29. return 0;
  30. }
  31. static void jsonexpect(js_State *J, int t)
  32. {
  33. if (!jsonaccept(J, t))
  34. js_syntaxerror(J, "JSON: unexpected token: %s (expected %s)",
  35. jsY_tokenstring(J->lookahead), jsY_tokenstring(t));
  36. }
  37. static void jsonvalue(js_State *J)
  38. {
  39. int i;
  40. const char *name;
  41. switch (J->lookahead) {
  42. case TK_STRING:
  43. js_pushstring(J, J->text);
  44. jsonnext(J);
  45. break;
  46. case TK_NUMBER:
  47. js_pushnumber(J, J->number);
  48. jsonnext(J);
  49. break;
  50. case '{':
  51. js_newobject(J);
  52. jsonnext(J);
  53. if (jsonaccept(J, '}'))
  54. return;
  55. do {
  56. if (J->lookahead != TK_STRING)
  57. js_syntaxerror(J, "JSON: unexpected token: %s (expected string)", jsY_tokenstring(J->lookahead));
  58. name = J->text;
  59. jsonnext(J);
  60. jsonexpect(J, ':');
  61. jsonvalue(J);
  62. js_setproperty(J, -2, name);
  63. } while (jsonaccept(J, ','));
  64. jsonexpect(J, '}');
  65. break;
  66. case '[':
  67. js_newarray(J);
  68. jsonnext(J);
  69. i = 0;
  70. if (jsonaccept(J, ']'))
  71. return;
  72. do {
  73. jsonvalue(J);
  74. js_setindex(J, -2, i++);
  75. } while (jsonaccept(J, ','));
  76. jsonexpect(J, ']');
  77. break;
  78. case TK_TRUE:
  79. js_pushboolean(J, 1);
  80. jsonnext(J);
  81. break;
  82. case TK_FALSE:
  83. js_pushboolean(J, 0);
  84. jsonnext(J);
  85. break;
  86. case TK_NULL:
  87. js_pushnull(J);
  88. jsonnext(J);
  89. break;
  90. default:
  91. js_syntaxerror(J, "JSON: unexpected token: %s", jsY_tokenstring(J->lookahead));
  92. }
  93. }
  94. static void jsonrevive(js_State *J, const char *name)
  95. {
  96. const char *key;
  97. char buf[32];
  98. /* revive is in 2 */
  99. /* holder is in -1 */
  100. js_getproperty(J, -1, name); /* get value from holder */
  101. if (js_isobject(J, -1)) {
  102. if (js_isarray(J, -1)) {
  103. int i = 0;
  104. int n = js_getlength(J, -1);
  105. for (i = 0; i < n; ++i) {
  106. jsonrevive(J, js_itoa(buf, i));
  107. if (js_isundefined(J, -1)) {
  108. js_pop(J, 1);
  109. js_delproperty(J, -1, buf);
  110. } else {
  111. js_setproperty(J, -2, buf);
  112. }
  113. }
  114. } else {
  115. js_pushiterator(J, -1, 1);
  116. while ((key = js_nextiterator(J, -1))) {
  117. js_rot2(J);
  118. jsonrevive(J, key);
  119. if (js_isundefined(J, -1)) {
  120. js_pop(J, 1);
  121. js_delproperty(J, -1, key);
  122. } else {
  123. js_setproperty(J, -2, key);
  124. }
  125. js_rot2(J);
  126. }
  127. js_pop(J, 1);
  128. }
  129. }
  130. js_copy(J, 2); /* reviver function */
  131. js_copy(J, -3); /* holder as this */
  132. js_pushstring(J, name); /* name */
  133. js_copy(J, -4); /* value */
  134. js_call(J, 2);
  135. js_rot2pop1(J); /* pop old value, leave new value on stack */
  136. }
  137. static void JSON_parse(js_State *J)
  138. {
  139. const char *source = js_tostring(J, 1);
  140. jsY_initlex(J, "JSON", source);
  141. jsonnext(J);
  142. if (js_iscallable(J, 2)) {
  143. js_newobject(J);
  144. jsonvalue(J);
  145. js_defproperty(J, -2, "", 0);
  146. jsonrevive(J, "");
  147. } else {
  148. jsonvalue(J);
  149. }
  150. }
  151. static void fmtnum(js_State *J, js_Buffer **sb, double n)
  152. {
  153. if (isnan(n)) js_puts(J, sb, "null");
  154. else if (isinf(n)) js_puts(J, sb, "null");
  155. else if (n == 0) js_puts(J, sb, "0");
  156. else {
  157. char buf[40];
  158. js_puts(J, sb, jsV_numbertostring(J, buf, n));
  159. }
  160. }
  161. static void fmtstr(js_State *J, js_Buffer **sb, const char *s)
  162. {
  163. static const char *HEX = "0123456789abcdef";
  164. int i, n;
  165. Rune c;
  166. js_putc(J, sb, '"');
  167. while (*s) {
  168. n = chartorune(&c, s);
  169. switch (c) {
  170. case '"': js_puts(J, sb, "\\\""); break;
  171. case '\\': js_puts(J, sb, "\\\\"); break;
  172. case '\b': js_puts(J, sb, "\\b"); break;
  173. case '\f': js_puts(J, sb, "\\f"); break;
  174. case '\n': js_puts(J, sb, "\\n"); break;
  175. case '\r': js_puts(J, sb, "\\r"); break;
  176. case '\t': js_puts(J, sb, "\\t"); break;
  177. default:
  178. if (c < ' ' || (c >= 0xd800 && c <= 0xdfff)) {
  179. js_putc(J, sb, '\\');
  180. js_putc(J, sb, 'u');
  181. js_putc(J, sb, HEX[(c>>12)&15]);
  182. js_putc(J, sb, HEX[(c>>8)&15]);
  183. js_putc(J, sb, HEX[(c>>4)&15]);
  184. js_putc(J, sb, HEX[c&15]);
  185. } else if (c < 128) {
  186. js_putc(J, sb, c);
  187. } else {
  188. for (i = 0; i < n; ++i)
  189. js_putc(J, sb, s[i]);
  190. }
  191. break;
  192. }
  193. s += n;
  194. }
  195. js_putc(J, sb, '"');
  196. }
  197. static void fmtindent(js_State *J, js_Buffer **sb, const char *gap, int level)
  198. {
  199. js_putc(J, sb, '\n');
  200. while (level--)
  201. js_puts(J, sb, gap);
  202. }
  203. static int fmtvalue(js_State *J, js_Buffer **sb, const char *key, const char *gap, int level);
  204. static int filterprop(js_State *J, const char *key)
  205. {
  206. int i, n, found;
  207. /* replacer/property-list is in stack slot 2 */
  208. if (js_isarray(J, 2)) {
  209. found = 0;
  210. n = js_getlength(J, 2);
  211. for (i = 0; i < n && !found; ++i) {
  212. js_getindex(J, 2, i);
  213. if (js_isstring(J, -1) || js_isnumber(J, -1) ||
  214. js_isstringobject(J, -1) || js_isnumberobject(J, -1))
  215. found = !strcmp(key, js_tostring(J, -1));
  216. js_pop(J, 1);
  217. }
  218. return found;
  219. }
  220. return 1;
  221. }
  222. static void fmtobject(js_State *J, js_Buffer **sb, js_Object *obj, const char *gap, int level)
  223. {
  224. const char *key;
  225. int save;
  226. int i, n;
  227. n = js_gettop(J) - 1;
  228. for (i = 4; i < n; ++i)
  229. if (js_isobject(J, i))
  230. if (js_toobject(J, i) == js_toobject(J, -1))
  231. js_typeerror(J, "cyclic object value");
  232. n = 0;
  233. js_putc(J, sb, '{');
  234. js_pushiterator(J, -1, 1);
  235. while ((key = js_nextiterator(J, -1))) {
  236. if (filterprop(J, key)) {
  237. save = (*sb)->n;
  238. if (n) js_putc(J, sb, ',');
  239. if (gap) fmtindent(J, sb, gap, level + 1);
  240. fmtstr(J, sb, key);
  241. js_putc(J, sb, ':');
  242. if (gap)
  243. js_putc(J, sb, ' ');
  244. js_rot2(J);
  245. if (!fmtvalue(J, sb, key, gap, level + 1))
  246. (*sb)->n = save;
  247. else
  248. ++n;
  249. js_rot2(J);
  250. }
  251. }
  252. js_pop(J, 1);
  253. if (gap && n) fmtindent(J, sb, gap, level);
  254. js_putc(J, sb, '}');
  255. }
  256. static void fmtarray(js_State *J, js_Buffer **sb, const char *gap, int level)
  257. {
  258. int n, i;
  259. char buf[32];
  260. n = js_gettop(J) - 1;
  261. for (i = 4; i < n; ++i)
  262. if (js_isobject(J, i))
  263. if (js_toobject(J, i) == js_toobject(J, -1))
  264. js_typeerror(J, "cyclic object value");
  265. js_putc(J, sb, '[');
  266. n = js_getlength(J, -1);
  267. for (i = 0; i < n; ++i) {
  268. if (i) js_putc(J, sb, ',');
  269. if (gap) fmtindent(J, sb, gap, level + 1);
  270. if (!fmtvalue(J, sb, js_itoa(buf, i), gap, level + 1))
  271. js_puts(J, sb, "null");
  272. }
  273. if (gap && n) fmtindent(J, sb, gap, level);
  274. js_putc(J, sb, ']');
  275. }
  276. static int fmtvalue(js_State *J, js_Buffer **sb, const char *key, const char *gap, int level)
  277. {
  278. /* replacer/property-list is in 2 */
  279. /* holder is in -1 */
  280. js_getproperty(J, -1, key);
  281. if (js_isobject(J, -1)) {
  282. if (js_hasproperty(J, -1, "toJSON")) {
  283. if (js_iscallable(J, -1)) {
  284. js_copy(J, -2);
  285. js_pushstring(J, key);
  286. js_call(J, 1);
  287. js_rot2pop1(J);
  288. } else {
  289. js_pop(J, 1);
  290. }
  291. }
  292. }
  293. if (js_iscallable(J, 2)) {
  294. js_copy(J, 2); /* replacer function */
  295. js_copy(J, -3); /* holder as this */
  296. js_pushstring(J, key); /* name */
  297. js_copy(J, -4); /* old value */
  298. js_call(J, 2);
  299. js_rot2pop1(J); /* pop old value, leave new value on stack */
  300. }
  301. if (js_isobject(J, -1) && !js_iscallable(J, -1)) {
  302. js_Object *obj = js_toobject(J, -1);
  303. switch (obj->type) {
  304. case JS_CNUMBER: fmtnum(J, sb, obj->u.number); break;
  305. case JS_CSTRING: fmtstr(J, sb, obj->u.s.string); break;
  306. case JS_CBOOLEAN: js_puts(J, sb, obj->u.boolean ? "true" : "false"); break;
  307. case JS_CARRAY: fmtarray(J, sb, gap, level); break;
  308. default: fmtobject(J, sb, obj, gap, level); break;
  309. }
  310. }
  311. else if (js_isboolean(J, -1))
  312. js_puts(J, sb, js_toboolean(J, -1) ? "true" : "false");
  313. else if (js_isnumber(J, -1))
  314. fmtnum(J, sb, js_tonumber(J, -1));
  315. else if (js_isstring(J, -1))
  316. fmtstr(J, sb, js_tostring(J, -1));
  317. else if (js_isnull(J, -1))
  318. js_puts(J, sb, "null");
  319. else {
  320. js_pop(J, 1);
  321. return 0;
  322. }
  323. js_pop(J, 1);
  324. return 1;
  325. }
  326. static void JSON_stringify(js_State *J)
  327. {
  328. js_Buffer *sb = NULL;
  329. char buf[12];
  330. /* NOTE: volatile to silence GCC warning about longjmp clobbering a variable */
  331. const char * volatile gap;
  332. const char *s;
  333. int n;
  334. gap = NULL;
  335. if (js_isnumber(J, 3) || js_isnumberobject(J, 3)) {
  336. n = js_tointeger(J, 3);
  337. if (n < 0) n = 0;
  338. if (n > 10) n = 10;
  339. memset(buf, ' ', n);
  340. buf[n] = 0;
  341. if (n > 0) gap = buf;
  342. } else if (js_isstring(J, 3) || js_isstringobject(J, 3)) {
  343. s = js_tostring(J, 3);
  344. n = strlen(s);
  345. if (n > 10) n = 10;
  346. memcpy(buf, s, n);
  347. buf[n] = 0;
  348. if (n > 0) gap = buf;
  349. }
  350. if (js_try(J)) {
  351. js_free(J, sb);
  352. js_throw(J);
  353. }
  354. js_newobject(J); /* wrapper */
  355. js_copy(J, 1);
  356. js_defproperty(J, -2, "", 0);
  357. if (!fmtvalue(J, &sb, "", gap, 0)) {
  358. js_pushundefined(J);
  359. } else {
  360. js_putc(J, &sb, 0);
  361. js_pushstring(J, sb ? sb->s : "");
  362. js_rot2pop1(J);
  363. }
  364. js_endtry(J);
  365. js_free(J, sb);
  366. }
  367. void jsB_initjson(js_State *J)
  368. {
  369. js_pushobject(J, jsV_newobject(J, JS_CJSON, J->Object_prototype));
  370. {
  371. jsB_propf(J, "JSON.parse", JSON_parse, 2);
  372. jsB_propf(J, "JSON.stringify", JSON_stringify, 3);
  373. }
  374. js_defglobal(J, "JSON", JS_DONTENUM);
  375. }