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