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