jsrepr.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. #include "jsi.h"
  2. #include "utf.h"
  3. static void reprvalue(js_State *J, js_Buffer **sb);
  4. static void reprnum(js_State *J, js_Buffer **sb, double n)
  5. {
  6. char buf[40];
  7. if (n == 0 && signbit(n))
  8. js_puts(J, sb, "-0");
  9. else
  10. js_puts(J, sb, jsV_numbertostring(J, buf, n));
  11. }
  12. static void reprstr(js_State *J, js_Buffer **sb, const char *s)
  13. {
  14. static const char *HEX = "0123456789ABCDEF";
  15. int i, n;
  16. Rune c;
  17. js_putc(J, sb, '"');
  18. while (*s) {
  19. n = chartorune(&c, s);
  20. switch (c) {
  21. case '"': js_puts(J, sb, "\\\""); break;
  22. case '\\': js_puts(J, sb, "\\\\"); break;
  23. case '\b': js_puts(J, sb, "\\b"); break;
  24. case '\f': js_puts(J, sb, "\\f"); break;
  25. case '\n': js_puts(J, sb, "\\n"); break;
  26. case '\r': js_puts(J, sb, "\\r"); break;
  27. case '\t': js_puts(J, sb, "\\t"); break;
  28. default:
  29. if (c < ' ') {
  30. js_putc(J, sb, '\\');
  31. js_putc(J, sb, 'x');
  32. js_putc(J, sb, HEX[(c>>4)&15]);
  33. js_putc(J, sb, HEX[c&15]);
  34. } else if (c < 128) {
  35. js_putc(J, sb, c);
  36. } else if (c < 0x10000) {
  37. js_putc(J, sb, '\\');
  38. js_putc(J, sb, 'u');
  39. js_putc(J, sb, HEX[(c>>12)&15]);
  40. js_putc(J, sb, HEX[(c>>8)&15]);
  41. js_putc(J, sb, HEX[(c>>4)&15]);
  42. js_putc(J, sb, HEX[c&15]);
  43. } else {
  44. for (i = 0; i < n; ++i)
  45. js_putc(J, sb, s[i]);
  46. }
  47. break;
  48. }
  49. s += n;
  50. }
  51. js_putc(J, sb, '"');
  52. }
  53. #ifndef isalpha
  54. #define isalpha(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
  55. #endif
  56. #ifndef isdigit
  57. #define isdigit(c) (c >= '0' && c <= '9')
  58. #endif
  59. static void reprident(js_State *J, js_Buffer **sb, const char *name)
  60. {
  61. const char *p = name;
  62. if (isdigit(*p))
  63. while (isdigit(*p))
  64. ++p;
  65. else if (isalpha(*p) || *p == '_')
  66. while (isdigit(*p) || isalpha(*p) || *p == '_')
  67. ++p;
  68. if (p > name && *p == 0)
  69. js_puts(J, sb, name);
  70. else
  71. reprstr(J, sb, name);
  72. }
  73. static void reprobject(js_State *J, js_Buffer **sb)
  74. {
  75. const char *key;
  76. int i, n;
  77. n = js_gettop(J) - 1;
  78. for (i = 0; i < n; ++i) {
  79. if (js_isobject(J, i)) {
  80. if (js_toobject(J, i) == js_toobject(J, -1)) {
  81. js_puts(J, sb, "{}");
  82. return;
  83. }
  84. }
  85. }
  86. n = 0;
  87. js_putc(J, sb, '{');
  88. js_pushiterator(J, -1, 1);
  89. while ((key = js_nextiterator(J, -1))) {
  90. if (n++ > 0)
  91. js_puts(J, sb, ", ");
  92. reprident(J, sb, key);
  93. js_puts(J, sb, ": ");
  94. js_getproperty(J, -2, key);
  95. reprvalue(J, sb);
  96. js_pop(J, 1);
  97. }
  98. js_pop(J, 1);
  99. js_putc(J, sb, '}');
  100. }
  101. static void reprarray(js_State *J, js_Buffer **sb)
  102. {
  103. int n, i;
  104. n = js_gettop(J) - 1;
  105. for (i = 0; i < n; ++i) {
  106. if (js_isobject(J, i)) {
  107. if (js_toobject(J, i) == js_toobject(J, -1)) {
  108. js_puts(J, sb, "[]");
  109. return;
  110. }
  111. }
  112. }
  113. js_putc(J, sb, '[');
  114. n = js_getlength(J, -1);
  115. for (i = 0; i < n; ++i) {
  116. if (i > 0)
  117. js_puts(J, sb, ", ");
  118. if (js_hasindex(J, -1, i)) {
  119. reprvalue(J, sb);
  120. js_pop(J, 1);
  121. }
  122. }
  123. js_putc(J, sb, ']');
  124. }
  125. static void reprfun(js_State *J, js_Buffer **sb, js_Function *fun)
  126. {
  127. int i;
  128. js_puts(J, sb, "function ");
  129. js_puts(J, sb, fun->name);
  130. js_putc(J, sb, '(');
  131. for (i = 0; i < fun->numparams; ++i) {
  132. if (i > 0)
  133. js_puts(J, sb, ", ");
  134. js_puts(J, sb, fun->vartab[i]);
  135. }
  136. js_puts(J, sb, ") { [byte code] }");
  137. }
  138. static void reprvalue(js_State *J, js_Buffer **sb)
  139. {
  140. if (js_isundefined(J, -1))
  141. js_puts(J, sb, "undefined");
  142. else if (js_isnull(J, -1))
  143. js_puts(J, sb, "null");
  144. else if (js_isboolean(J, -1))
  145. js_puts(J, sb, js_toboolean(J, -1) ? "true" : "false");
  146. else if (js_isnumber(J, -1))
  147. reprnum(J, sb, js_tonumber(J, -1));
  148. else if (js_isstring(J, -1))
  149. reprstr(J, sb, js_tostring(J, -1));
  150. else if (js_isobject(J, -1)) {
  151. js_Object *obj = js_toobject(J, -1);
  152. switch (obj->type) {
  153. default:
  154. reprobject(J, sb);
  155. break;
  156. case JS_CARRAY:
  157. reprarray(J, sb);
  158. break;
  159. case JS_CFUNCTION:
  160. case JS_CSCRIPT:
  161. reprfun(J, sb, obj->u.f.function);
  162. break;
  163. case JS_CCFUNCTION:
  164. js_puts(J, sb, "function ");
  165. js_puts(J, sb, obj->u.c.name);
  166. js_puts(J, sb, "() { [native code] }");
  167. break;
  168. case JS_CBOOLEAN:
  169. js_puts(J, sb, "(new Boolean(");
  170. js_puts(J, sb, obj->u.boolean ? "true" : "false");
  171. js_puts(J, sb, "))");
  172. break;
  173. case JS_CNUMBER:
  174. js_puts(J, sb, "(new Number(");
  175. reprnum(J, sb, obj->u.number);
  176. js_puts(J, sb, "))");
  177. break;
  178. case JS_CSTRING:
  179. js_puts(J, sb, "(new String(");
  180. reprstr(J, sb, obj->u.s.string);
  181. js_puts(J, sb, "))");
  182. break;
  183. case JS_CREGEXP:
  184. js_putc(J, sb, '/');
  185. js_puts(J, sb, obj->u.r.source);
  186. js_putc(J, sb, '/');
  187. if (obj->u.r.flags & JS_REGEXP_G) js_putc(J, sb, 'g');
  188. if (obj->u.r.flags & JS_REGEXP_I) js_putc(J, sb, 'i');
  189. if (obj->u.r.flags & JS_REGEXP_M) js_putc(J, sb, 'm');
  190. break;
  191. case JS_CDATE:
  192. {
  193. char buf[40];
  194. js_puts(J, sb, "(new Date(");
  195. js_puts(J, sb, jsV_numbertostring(J, buf, obj->u.number));
  196. js_puts(J, sb, "))");
  197. }
  198. break;
  199. case JS_CERROR:
  200. js_puts(J, sb, "(new ");
  201. js_getproperty(J, -1, "name");
  202. js_puts(J, sb, js_tostring(J, -1));
  203. js_pop(J, 1);
  204. js_putc(J, sb, '(');
  205. if (js_hasproperty(J, -1, "message")) {
  206. reprvalue(J, sb);
  207. js_pop(J, 1);
  208. }
  209. js_puts(J, sb, "))");
  210. break;
  211. case JS_CMATH:
  212. js_puts(J, sb, "Math");
  213. break;
  214. case JS_CJSON:
  215. js_puts(J, sb, "JSON");
  216. break;
  217. case JS_CITERATOR:
  218. js_puts(J, sb, "[iterator ");
  219. break;
  220. case JS_CUSERDATA:
  221. js_puts(J, sb, "[userdata ");
  222. js_puts(J, sb, obj->u.user.tag);
  223. js_putc(J, sb, ']');
  224. break;
  225. }
  226. }
  227. }
  228. void js_repr(js_State *J, int idx)
  229. {
  230. js_Buffer *sb = NULL;
  231. int savebot;
  232. if (js_try(J)) {
  233. js_free(J, sb);
  234. js_throw(J);
  235. }
  236. js_copy(J, idx);
  237. savebot = J->bot;
  238. J->bot = J->top - 1;
  239. reprvalue(J, &sb);
  240. J->bot = savebot;
  241. js_pop(J, 1);
  242. js_putc(J, &sb, 0);
  243. js_pushstring(J, sb ? sb->s : "undefined");
  244. js_endtry(J);
  245. js_free(J, sb);
  246. }
  247. const char *js_torepr(js_State *J, int idx)
  248. {
  249. js_repr(J, idx);
  250. js_replace(J, idx < 0 ? idx-1 : idx);
  251. return js_tostring(J, idx);
  252. }
  253. const char *js_tryrepr(js_State *J, int idx, const char *error)
  254. {
  255. const char *s;
  256. if (js_try(J)) {
  257. js_pop(J, 1);
  258. return error;
  259. }
  260. s = js_torepr(J, idx);
  261. js_endtry(J);
  262. return s;
  263. }