1 #include "jsi.h"
2 #include "jsparse.h"
3 #include "jscompile.h"
4 #include "jsvalue.h"
5 
6 #include "utf.h"
7 
8 #include <assert.h>
9 
10 static const char *astname[] = {
11 #include "astnames.h"
12 NULL
13 };
14 
15 static const char *opname[] = {
16 #include "opnames.h"
17 NULL
18 };
19 
20 static int minify = 0;
21 
jsP_aststring(enum js_AstType type)22 const char *jsP_aststring(enum js_AstType type)
23 {
24 	if (type < nelem(astname)-1)
25 		return astname[type];
26 	return "<unknown>";
27 }
28 
jsC_opcodestring(enum js_OpCode opcode)29 const char *jsC_opcodestring(enum js_OpCode opcode)
30 {
31 	if (opcode < nelem(opname)-1)
32 		return opname[opcode];
33 	return "<unknown>";
34 }
35 
prec(enum js_AstType type)36 static int prec(enum js_AstType type)
37 {
38 	switch (type) {
39 	case AST_IDENTIFIER:
40 	case EXP_IDENTIFIER:
41 	case EXP_NUMBER:
42 	case EXP_STRING:
43 	case EXP_REGEXP:
44 	case EXP_UNDEF:
45 	case EXP_NULL:
46 	case EXP_TRUE:
47 	case EXP_FALSE:
48 	case EXP_THIS:
49 	case EXP_ARRAY:
50 	case EXP_OBJECT:
51 		return 170;
52 
53 	case EXP_FUN:
54 	case EXP_INDEX:
55 	case EXP_MEMBER:
56 	case EXP_CALL:
57 	case EXP_NEW:
58 		return 160;
59 
60 	case EXP_POSTINC:
61 	case EXP_POSTDEC:
62 		return 150;
63 
64 	case EXP_DELETE:
65 	case EXP_VOID:
66 	case EXP_TYPEOF:
67 	case EXP_PREINC:
68 	case EXP_PREDEC:
69 	case EXP_POS:
70 	case EXP_NEG:
71 	case EXP_BITNOT:
72 	case EXP_LOGNOT:
73 		return 140;
74 
75 	case EXP_MOD:
76 	case EXP_DIV:
77 	case EXP_MUL:
78 		return 130;
79 
80 	case EXP_SUB:
81 	case EXP_ADD:
82 		return 120;
83 
84 	case EXP_USHR:
85 	case EXP_SHR:
86 	case EXP_SHL:
87 		return 110;
88 
89 	case EXP_IN:
90 	case EXP_INSTANCEOF:
91 	case EXP_GE:
92 	case EXP_LE:
93 	case EXP_GT:
94 	case EXP_LT:
95 		return 100;
96 
97 	case EXP_STRICTNE:
98 	case EXP_STRICTEQ:
99 	case EXP_NE:
100 	case EXP_EQ:
101 		return 90;
102 
103 	case EXP_BITAND: return 80;
104 	case EXP_BITXOR: return 70;
105 	case EXP_BITOR: return 60;
106 	case EXP_LOGAND: return 50;
107 	case EXP_LOGOR: return 40;
108 
109 	case EXP_COND:
110 		return 30;
111 
112 	case EXP_ASS:
113 	case EXP_ASS_MUL:
114 	case EXP_ASS_DIV:
115 	case EXP_ASS_MOD:
116 	case EXP_ASS_ADD:
117 	case EXP_ASS_SUB:
118 	case EXP_ASS_SHL:
119 	case EXP_ASS_SHR:
120 	case EXP_ASS_USHR:
121 	case EXP_ASS_BITAND:
122 	case EXP_ASS_BITXOR:
123 	case EXP_ASS_BITOR:
124 		return 20;
125 
126 #define COMMA 15
127 
128 	case EXP_COMMA:
129 		return 10;
130 
131 	default:
132 		return 0;
133 	}
134 }
135 
pc(int c)136 static void pc(int c)
137 {
138 	putchar(c);
139 }
140 
ps(const char * s)141 static void ps(const char *s)
142 {
143 	fputs(s, stdout);
144 }
145 
pn(int n)146 static void pn(int n)
147 {
148 	printf("%d", n);
149 }
150 
in(int d)151 static void in(int d)
152 {
153 	if (minify < 1)
154 		while (d-- > 0)
155 			putchar('\t');
156 }
157 
nl(void)158 static void nl(void)
159 {
160 	if (minify < 2)
161 		putchar('\n');
162 }
163 
sp(void)164 static void sp(void)
165 {
166 	if (minify < 1)
167 		putchar(' ');
168 }
169 
comma(void)170 static void comma(void)
171 {
172 	putchar(',');
173 	sp();
174 }
175 
176 /* Pretty-printed Javascript syntax */
177 
178 static void pstmlist(int d, js_Ast *list);
179 static void pexpi(int d, int i, js_Ast *exp);
180 static void pstm(int d, js_Ast *stm);
181 static void slist(int d, js_Ast *list);
182 static void sblock(int d, js_Ast *list);
183 
pargs(int d,js_Ast * list)184 static void pargs(int d, js_Ast *list)
185 {
186 	while (list) {
187 		assert(list->type == AST_LIST);
188 		pexpi(d, COMMA, list->a);
189 		list = list->b;
190 		if (list)
191 			comma();
192 	}
193 }
194 
parray(int d,js_Ast * list)195 static void parray(int d, js_Ast *list)
196 {
197 	pc('[');
198 	while (list) {
199 		assert(list->type == AST_LIST);
200 		pexpi(d, COMMA, list->a);
201 		list = list->b;
202 		if (list)
203 			comma();
204 	}
205 	pc(']');
206 }
207 
pobject(int d,js_Ast * list)208 static void pobject(int d, js_Ast *list)
209 {
210 	pc('{');
211 	if (list) {
212 		nl();
213 		in(d+1);
214 	}
215 	while (list) {
216 		js_Ast *kv = list->a;
217 		assert(list->type == AST_LIST);
218 		switch (kv->type) {
219 		default: break;
220 		case EXP_PROP_VAL:
221 			pexpi(d+1, COMMA, kv->a);
222 			pc(':'); sp();
223 			pexpi(d+1, COMMA, kv->b);
224 			break;
225 		case EXP_PROP_GET:
226 			ps("get ");
227 			pexpi(d+1, COMMA, kv->a);
228 			ps("()"); sp(); pc('{'); nl();
229 			pstmlist(d+1, kv->c);
230 			in(d+1); pc('}');
231 			break;
232 		case EXP_PROP_SET:
233 			ps("set ");
234 			pexpi(d+1, COMMA, kv->a);
235 			pc('(');
236 			pargs(d+1, kv->b);
237 			pc(')'); sp(); pc('{'); nl();
238 			pstmlist(d+1, kv->c);
239 			in(d+1); pc('}');
240 			break;
241 		}
242 		list = list->b;
243 		if (list) {
244 			pc(',');
245 			nl();
246 			in(d+1);
247 		} else {
248 			nl();
249 			in(d);
250 		}
251 	}
252 	pc('}');
253 }
254 
pstr(const char * s)255 static void pstr(const char *s)
256 {
257 	static const char *HEX = "0123456789ABCDEF";
258 	Rune c;
259 	pc(minify ? '\'' : '"');
260 	while (*s) {
261 		s += chartorune(&c, s);
262 		switch (c) {
263 		case '\'': ps("\\'"); break;
264 		case '"': ps("\\\""); break;
265 		case '\\': ps("\\\\"); break;
266 		case '\b': ps("\\b"); break;
267 		case '\f': ps("\\f"); break;
268 		case '\n': ps("\\n"); break;
269 		case '\r': ps("\\r"); break;
270 		case '\t': ps("\\t"); break;
271 		default:
272 			if (c < ' ' || c > 127) {
273 				ps("\\u");
274 				pc(HEX[(c>>12)&15]);
275 				pc(HEX[(c>>8)&15]);
276 				pc(HEX[(c>>4)&15]);
277 				pc(HEX[c&15]);
278 			} else {
279 				pc(c); break;
280 			}
281 		}
282 	}
283 	pc(minify ? '\'' : '"');
284 }
285 
pregexp(const char * prog,int flags)286 static void pregexp(const char *prog, int flags)
287 {
288 	pc('/');
289 	while (*prog) {
290 		if (*prog == '/')
291 			pc('\\');
292 		pc(*prog);
293 		++prog;
294 	}
295 	pc('/');
296 	if (flags & JS_REGEXP_G) pc('g');
297 	if (flags & JS_REGEXP_I) pc('i');
298 	if (flags & JS_REGEXP_M) pc('m');
299 }
300 
pbin(int d,int p,js_Ast * exp,const char * op)301 static void pbin(int d, int p, js_Ast *exp, const char *op)
302 {
303 	pexpi(d, p, exp->a);
304 	sp();
305 	ps(op);
306 	sp();
307 	pexpi(d, p, exp->b);
308 }
309 
puna(int d,int p,js_Ast * exp,const char * pre,const char * suf)310 static void puna(int d, int p, js_Ast *exp, const char *pre, const char *suf)
311 {
312 	ps(pre);
313 	pexpi(d, p, exp->a);
314 	ps(suf);
315 }
316 
pexpi(int d,int p,js_Ast * exp)317 static void pexpi(int d, int p, js_Ast *exp)
318 {
319 	int tp, paren;
320 
321 	if (!exp) return;
322 
323 	tp = prec(exp->type);
324 	paren = 0;
325 	if (tp < p) {
326 		pc('(');
327 		paren = 1;
328 	}
329 	p = tp;
330 
331 	switch (exp->type) {
332 	case AST_IDENTIFIER: ps(exp->string); break;
333 	case EXP_IDENTIFIER: ps(exp->string); break;
334 	case EXP_NUMBER: printf("%.9g", exp->number); break;
335 	case EXP_STRING: pstr(exp->string); break;
336 	case EXP_REGEXP: pregexp(exp->string, exp->number); break;
337 
338 	case EXP_UNDEF: break;
339 	case EXP_NULL: ps("null"); break;
340 	case EXP_TRUE: ps("true"); break;
341 	case EXP_FALSE: ps("false"); break;
342 	case EXP_THIS: ps("this"); break;
343 
344 	case EXP_OBJECT: pobject(d, exp->a); break;
345 	case EXP_ARRAY: parray(d, exp->a); break;
346 
347 	case EXP_DELETE: puna(d, p, exp, "delete ", ""); break;
348 	case EXP_VOID: puna(d, p, exp, "void ", ""); break;
349 	case EXP_TYPEOF: puna(d, p, exp, "typeof ", ""); break;
350 	case EXP_PREINC: puna(d, p, exp, "++", ""); break;
351 	case EXP_PREDEC: puna(d, p, exp, "--", ""); break;
352 	case EXP_POSTINC: puna(d, p, exp, "", "++"); break;
353 	case EXP_POSTDEC: puna(d, p, exp, "", "--"); break;
354 	case EXP_POS: puna(d, p, exp, "+", ""); break;
355 	case EXP_NEG: puna(d, p, exp, "-", ""); break;
356 	case EXP_BITNOT: puna(d, p, exp, "~", ""); break;
357 	case EXP_LOGNOT: puna(d, p, exp, "!", ""); break;
358 
359 	case EXP_LOGOR: pbin(d, p, exp, "||"); break;
360 	case EXP_LOGAND: pbin(d, p, exp, "&&"); break;
361 	case EXP_BITOR: pbin(d, p, exp, "|"); break;
362 	case EXP_BITXOR: pbin(d, p, exp, "^"); break;
363 	case EXP_BITAND: pbin(d, p, exp, "&"); break;
364 	case EXP_EQ: pbin(d, p, exp, "=="); break;
365 	case EXP_NE: pbin(d, p, exp, "!="); break;
366 	case EXP_STRICTEQ: pbin(d, p, exp, "==="); break;
367 	case EXP_STRICTNE: pbin(d, p, exp, "!=="); break;
368 	case EXP_LT: pbin(d, p, exp, "<"); break;
369 	case EXP_GT: pbin(d, p, exp, ">"); break;
370 	case EXP_LE: pbin(d, p, exp, "<="); break;
371 	case EXP_GE: pbin(d, p, exp, ">="); break;
372 	case EXP_IN: pbin(d, p, exp, "in"); break;
373 	case EXP_SHL: pbin(d, p, exp, "<<"); break;
374 	case EXP_SHR: pbin(d, p, exp, ">>"); break;
375 	case EXP_USHR: pbin(d, p, exp, ">>>"); break;
376 	case EXP_ADD: pbin(d, p, exp, "+"); break;
377 	case EXP_SUB: pbin(d, p, exp, "-"); break;
378 	case EXP_MUL: pbin(d, p, exp, "*"); break;
379 	case EXP_DIV: pbin(d, p, exp, "/"); break;
380 	case EXP_MOD: pbin(d, p, exp, "%"); break;
381 	case EXP_ASS: pbin(d, p, exp, "="); break;
382 	case EXP_ASS_MUL: pbin(d, p, exp, "*="); break;
383 	case EXP_ASS_DIV: pbin(d, p, exp, "/="); break;
384 	case EXP_ASS_MOD: pbin(d, p, exp, "%="); break;
385 	case EXP_ASS_ADD: pbin(d, p, exp, "+="); break;
386 	case EXP_ASS_SUB: pbin(d, p, exp, "-="); break;
387 	case EXP_ASS_SHL: pbin(d, p, exp, "<<="); break;
388 	case EXP_ASS_SHR: pbin(d, p, exp, ">>="); break;
389 	case EXP_ASS_USHR: pbin(d, p, exp, ">>>="); break;
390 	case EXP_ASS_BITAND: pbin(d, p, exp, "&="); break;
391 	case EXP_ASS_BITXOR: pbin(d, p, exp, "^="); break;
392 	case EXP_ASS_BITOR: pbin(d, p, exp, "|="); break;
393 
394 	case EXP_INSTANCEOF:
395 		pexpi(d, p, exp->a);
396 		ps(" instanceof ");
397 		pexpi(d, p, exp->b);
398 		break;
399 
400 	case EXP_COMMA:
401 		pexpi(d, p, exp->a);
402 		pc(','); sp();
403 		pexpi(d, p, exp->b);
404 		break;
405 
406 	case EXP_COND:
407 		pexpi(d, p, exp->a);
408 		sp(); pc('?'); sp();
409 		pexpi(d, p, exp->b);
410 		sp(); pc(':'); sp();
411 		pexpi(d, p, exp->c);
412 		break;
413 
414 	case EXP_INDEX:
415 		pexpi(d, p, exp->a);
416 		pc('[');
417 		pexpi(d, 0, exp->b);
418 		pc(']');
419 		break;
420 
421 	case EXP_MEMBER:
422 		pexpi(d, p, exp->a);
423 		pc('.');
424 		pexpi(d, 0, exp->b);
425 		break;
426 
427 	case EXP_CALL:
428 		pexpi(d, p, exp->a);
429 		pc('(');
430 		pargs(d, exp->b);
431 		pc(')');
432 		break;
433 
434 	case EXP_NEW:
435 		ps("new ");
436 		pexpi(d, p, exp->a);
437 		pc('(');
438 		pargs(d, exp->b);
439 		pc(')');
440 		break;
441 
442 	case EXP_FUN:
443 		if (p == 0) pc('(');
444 		ps("function ");
445 		pexpi(d, 0, exp->a);
446 		pc('(');
447 		pargs(d, exp->b);
448 		pc(')'); sp(); pc('{'); nl();
449 		pstmlist(d, exp->c);
450 		in(d); pc('}');
451 		if (p == 0) pc(')');
452 		break;
453 
454 	default:
455 		ps("<UNKNOWN>");
456 		break;
457 	}
458 
459 	if (paren) pc(')');
460 }
461 
pexp(int d,js_Ast * exp)462 static void pexp(int d, js_Ast *exp)
463 {
464 	pexpi(d, 0, exp);
465 }
466 
pvar(int d,js_Ast * var)467 static void pvar(int d, js_Ast *var)
468 {
469 	assert(var->type == EXP_VAR);
470 	pexp(d, var->a);
471 	if (var->b) {
472 		sp(); pc('='); sp();
473 		pexp(d, var->b);
474 	}
475 }
476 
pvarlist(int d,js_Ast * list)477 static void pvarlist(int d, js_Ast *list)
478 {
479 	while (list) {
480 		assert(list->type == AST_LIST);
481 		pvar(d, list->a);
482 		list = list->b;
483 		if (list)
484 			comma();
485 	}
486 }
487 
pblock(int d,js_Ast * block)488 static void pblock(int d, js_Ast *block)
489 {
490 	assert(block->type == STM_BLOCK);
491 	pc('{'); nl();
492 	pstmlist(d, block->a);
493 	in(d); pc('}');
494 }
495 
pstmh(int d,js_Ast * stm)496 static void pstmh(int d, js_Ast *stm)
497 {
498 	if (stm->type == STM_BLOCK) {
499 		sp();
500 		pblock(d, stm);
501 	} else {
502 		nl();
503 		pstm(d+1, stm);
504 	}
505 }
506 
pcaselist(int d,js_Ast * list)507 static void pcaselist(int d, js_Ast *list)
508 {
509 	while (list) {
510 		js_Ast *stm = list->a;
511 		if (stm->type == STM_CASE) {
512 			in(d); ps("case "); pexp(d, stm->a); pc(':'); nl();
513 			pstmlist(d, stm->b);
514 		}
515 		if (stm->type == STM_DEFAULT) {
516 			in(d); ps("default:"); nl();
517 			pstmlist(d, stm->a);
518 		}
519 		list = list->b;
520 	}
521 }
522 
pstm(int d,js_Ast * stm)523 static void pstm(int d, js_Ast *stm)
524 {
525 	if (stm->type == STM_BLOCK) {
526 		pblock(d, stm);
527 		return;
528 	}
529 
530 	in(d);
531 
532 	switch (stm->type) {
533 	case AST_FUNDEC:
534 		ps("function ");
535 		pexp(d, stm->a);
536 		pc('(');
537 		pargs(d, stm->b);
538 		pc(')'); sp(); pc('{'); nl();
539 		pstmlist(d, stm->c);
540 		in(d); pc('}');
541 		break;
542 
543 	case STM_EMPTY:
544 		pc(';');
545 		break;
546 
547 	case STM_VAR:
548 		ps("var ");
549 		pvarlist(d, stm->a);
550 		pc(';');
551 		break;
552 
553 	case STM_IF:
554 		ps("if"); sp(); pc('('); pexp(d, stm->a); pc(')');
555 		pstmh(d, stm->b);
556 		if (stm->c) {
557 			nl(); in(d); ps("else");
558 			pstmh(d, stm->c);
559 		}
560 		break;
561 
562 	case STM_DO:
563 		ps("do");
564 		pstmh(d, stm->a);
565 		nl();
566 		in(d); ps("while"); sp(); pc('('); pexp(d, stm->b); pc(')'); pc(';');
567 		break;
568 
569 	case STM_WHILE:
570 		ps("while"); sp(); pc('('); pexp(d, stm->a); pc(')');
571 		pstmh(d, stm->b);
572 		break;
573 
574 	case STM_FOR:
575 		ps("for"); sp(); pc('(');
576 		pexp(d, stm->a); pc(';'); sp();
577 		pexp(d, stm->b); pc(';'); sp();
578 		pexp(d, stm->c); pc(')');
579 		pstmh(d, stm->d);
580 		break;
581 	case STM_FOR_VAR:
582 		ps("for"); sp(); ps("(var ");
583 		pvarlist(d, stm->a); pc(';'); sp();
584 		pexp(d, stm->b); pc(';'); sp();
585 		pexp(d, stm->c); pc(')');
586 		pstmh(d, stm->d);
587 		break;
588 	case STM_FOR_IN:
589 		ps("for"); sp(); pc('(');
590 		pexp(d, stm->a); ps(" in ");
591 		pexp(d, stm->b); pc(')');
592 		pstmh(d, stm->c);
593 		break;
594 	case STM_FOR_IN_VAR:
595 		ps("for"); sp(); ps("(var ");
596 		pvarlist(d, stm->a); ps(" in ");
597 		pexp(d, stm->b); pc(')');
598 		pstmh(d, stm->c);
599 		break;
600 
601 	case STM_CONTINUE:
602 		ps("continue");
603 		if (stm->a) {
604 			pc(' '); pexp(d, stm->a);
605 		}
606 		pc(';');
607 		break;
608 
609 	case STM_BREAK:
610 		ps("break");
611 		if (stm->a) {
612 			pc(' '); pexp(d, stm->a);
613 		}
614 		pc(';');
615 		break;
616 
617 	case STM_RETURN:
618 		ps("return");
619 		if (stm->a) {
620 			pc(' '); pexp(d, stm->a);
621 		}
622 		pc(';');
623 		break;
624 
625 	case STM_WITH:
626 		ps("with"); sp(); pc('('); pexp(d, stm->a); pc(')');
627 		pstmh(d, stm->b);
628 		break;
629 
630 	case STM_SWITCH:
631 		ps("switch"); sp(); pc('(');
632 		pexp(d, stm->a);
633 		pc(')'); sp(); pc('{'); nl();
634 		pcaselist(d, stm->b);
635 		in(d); pc('}');
636 		break;
637 
638 	case STM_THROW:
639 		ps("throw "); pexp(d, stm->a); pc(';');
640 		break;
641 
642 	case STM_TRY:
643 		ps("try");
644 		if (minify && stm->a->type != STM_BLOCK)
645 			pc(' ');
646 		pstmh(d, stm->a);
647 		if (stm->b && stm->c) {
648 			nl(); in(d); ps("catch"); sp(); pc('('); pexp(d, stm->b); pc(')');
649 			pstmh(d, stm->c);
650 		}
651 		if (stm->d) {
652 			nl(); in(d); ps("finally");
653 			pstmh(d, stm->d);
654 		}
655 		break;
656 
657 	case STM_LABEL:
658 		pexp(d, stm->a); pc(':'); sp(); pstm(d, stm->b);
659 		break;
660 
661 	case STM_DEBUGGER:
662 		ps("debugger");
663 		pc(';');
664 		break;
665 
666 	default:
667 		pexp(d, stm);
668 		pc(';');
669 	}
670 }
671 
pstmlist(int d,js_Ast * list)672 static void pstmlist(int d, js_Ast *list)
673 {
674 	while (list) {
675 		assert(list->type == AST_LIST);
676 		pstm(d+1, list->a);
677 		nl();
678 		list = list->b;
679 	}
680 }
681 
jsP_dumpsyntax(js_State * J,js_Ast * prog,int dominify)682 void jsP_dumpsyntax(js_State *J, js_Ast *prog, int dominify)
683 {
684 	minify = dominify;
685 	if (prog->type == AST_LIST)
686 		pstmlist(-1, prog);
687 	else {
688 		pstm(0, prog);
689 		nl();
690 	}
691 	if (minify > 1)
692 		putchar('\n');
693 }
694 
695 /* S-expression list representation */
696 
snode(int d,js_Ast * node)697 static void snode(int d, js_Ast *node)
698 {
699 	void (*afun)(int,js_Ast*) = snode;
700 	void (*bfun)(int,js_Ast*) = snode;
701 	void (*cfun)(int,js_Ast*) = snode;
702 	void (*dfun)(int,js_Ast*) = snode;
703 
704 	if (!node) {
705 		return;
706 	}
707 
708 	if (node->type == AST_LIST) {
709 		slist(d, node);
710 		return;
711 	}
712 
713 	pc('(');
714 	ps(astname[node->type]);
715 	pc(':');
716 	pn(node->line);
717 	switch (node->type) {
718 	default: break;
719 	case AST_IDENTIFIER: pc(' '); ps(node->string); break;
720 	case EXP_IDENTIFIER: pc(' '); ps(node->string); break;
721 	case EXP_STRING: pc(' '); pstr(node->string); break;
722 	case EXP_REGEXP: pc(' '); pregexp(node->string, node->number); break;
723 	case EXP_NUMBER: printf(" %.9g", node->number); break;
724 	case STM_BLOCK: afun = sblock; break;
725 	case AST_FUNDEC: case EXP_FUN: cfun = sblock; break;
726 	case EXP_PROP_GET: cfun = sblock; break;
727 	case EXP_PROP_SET: cfun = sblock; break;
728 	case STM_SWITCH: bfun = sblock; break;
729 	case STM_CASE: bfun = sblock; break;
730 	case STM_DEFAULT: afun = sblock; break;
731 	}
732 	if (node->a) { pc(' '); afun(d, node->a); }
733 	if (node->b) { pc(' '); bfun(d, node->b); }
734 	if (node->c) { pc(' '); cfun(d, node->c); }
735 	if (node->d) { pc(' '); dfun(d, node->d); }
736 	pc(')');
737 }
738 
slist(int d,js_Ast * list)739 static void slist(int d, js_Ast *list)
740 {
741 	pc('[');
742 	while (list) {
743 		assert(list->type == AST_LIST);
744 		snode(d, list->a);
745 		list = list->b;
746 		if (list)
747 			pc(' ');
748 	}
749 	pc(']');
750 }
751 
sblock(int d,js_Ast * list)752 static void sblock(int d, js_Ast *list)
753 {
754 	ps("[\n");
755 	in(d+1);
756 	while (list) {
757 		assert(list->type == AST_LIST);
758 		snode(d+1, list->a);
759 		list = list->b;
760 		if (list) {
761 			nl();
762 			in(d+1);
763 		}
764 	}
765 	nl(); in(d); pc(']');
766 }
767 
jsP_dumplist(js_State * J,js_Ast * prog)768 void jsP_dumplist(js_State *J, js_Ast *prog)
769 {
770 	minify = 0;
771 	if (prog->type == AST_LIST)
772 		sblock(0, prog);
773 	else
774 		snode(0, prog);
775 	nl();
776 }
777 
778 /* Compiled code */
779 
jsC_dumpfunction(js_State * J,js_Function * F)780 void jsC_dumpfunction(js_State *J, js_Function *F)
781 {
782 	js_Instruction *p = F->code;
783 	js_Instruction *end = F->code + F->codelen;
784 	char *s;
785 	double n;
786 	int i;
787 
788 	minify = 0;
789 
790 	printf("%s(%d)\n", F->name, F->numparams);
791 	if (F->strict) printf("\tstrict\n");
792 	if (F->lightweight) printf("\tlightweight\n");
793 	if (F->arguments) printf("\targuments\n");
794 	printf("\tsource %s:%d\n", F->filename, F->line);
795 	for (i = 0; i < F->funlen; ++i)
796 		printf("\tfunction %d %s\n", i, F->funtab[i]->name);
797 	for (i = 0; i < F->varlen; ++i)
798 		printf("\tlocal %d %s\n", i + 1, F->vartab[i]);
799 
800 	printf("{\n");
801 	while (p < end) {
802 		int ln = *p++;
803 		int c = *p++;
804 
805 		printf("%5d(%3d): ", (int)(p - F->code) - 2, ln);
806 		ps(opname[c]);
807 
808 		switch (c) {
809 		case OP_INTEGER:
810 			printf(" %ld", (long)((*p++) - 32768));
811 			break;
812 		case OP_NUMBER:
813 			memcpy(&n, p, sizeof(n));
814 			p += sizeof(n) / sizeof(*p);
815 			printf(" %.9g", n);
816 			break;
817 		case OP_STRING:
818 			memcpy(&s, p, sizeof(s));
819 			p += sizeof(s) / sizeof(*p);
820 			pc(' ');
821 			pstr(s);
822 			break;
823 		case OP_NEWREGEXP:
824 			pc(' ');
825 			memcpy(&s, p, sizeof(s));
826 			p += sizeof(s) / sizeof(*p);
827 			pregexp(s, *p++);
828 			break;
829 
830 		case OP_GETVAR:
831 		case OP_HASVAR:
832 		case OP_SETVAR:
833 		case OP_DELVAR:
834 		case OP_GETPROP_S:
835 		case OP_SETPROP_S:
836 		case OP_DELPROP_S:
837 		case OP_CATCH:
838 			memcpy(&s, p, sizeof(s));
839 			p += sizeof(s) / sizeof(*p);
840 			pc(' ');
841 			ps(s);
842 			break;
843 
844 		case OP_GETLOCAL:
845 		case OP_SETLOCAL:
846 		case OP_DELLOCAL:
847 			printf(" %s", F->vartab[*p++ - 1]);
848 			break;
849 
850 		case OP_CLOSURE:
851 		case OP_CALL:
852 		case OP_NEW:
853 		case OP_JUMP:
854 		case OP_JTRUE:
855 		case OP_JFALSE:
856 		case OP_JCASE:
857 		case OP_TRY:
858 			printf(" %ld", (long)*p++);
859 			break;
860 		}
861 
862 		nl();
863 	}
864 	printf("}\n");
865 
866 	for (i = 0; i < F->funlen; ++i) {
867 		if (F->funtab[i] != F) {
868 			printf("function %d ", i);
869 			jsC_dumpfunction(J, F->funtab[i]);
870 		}
871 	}
872 }
873 
874 /* Runtime values */
875 
js_dumpvalue(js_State * J,js_Value v)876 void js_dumpvalue(js_State *J, js_Value v)
877 {
878 	minify = 0;
879 	switch (v.type) {
880 	case JS_TUNDEFINED: printf("undefined"); break;
881 	case JS_TNULL: printf("null"); break;
882 	case JS_TBOOLEAN: printf(v.u.boolean ? "true" : "false"); break;
883 	case JS_TNUMBER: printf("%.9g", v.u.number); break;
884 	case JS_TSHRSTR: printf("'%s'", v.u.shrstr); break;
885 	case JS_TLITSTR: printf("'%s'", v.u.litstr); break;
886 	case JS_TMEMSTR: printf("'%s'", v.u.memstr->p); break;
887 	case JS_TOBJECT:
888 		if (v.u.object == J->G) {
889 			printf("[Global]");
890 			break;
891 		}
892 		switch (v.u.object->type) {
893 		case JS_COBJECT: printf("[Object %p]", (void*)v.u.object); break;
894 		case JS_CARRAY: printf("[Array %p]", (void*)v.u.object); break;
895 		case JS_CFUNCTION:
896 			printf("[Function %p, %s, %s:%d]",
897 				(void*)v.u.object,
898 				v.u.object->u.f.function->name,
899 				v.u.object->u.f.function->filename,
900 				v.u.object->u.f.function->line);
901 			break;
902 		case JS_CSCRIPT: printf("[Script %s]", v.u.object->u.f.function->filename); break;
903 		case JS_CCFUNCTION: printf("[CFunction %s]", v.u.object->u.c.name); break;
904 		case JS_CBOOLEAN: printf("[Boolean %d]", v.u.object->u.boolean); break;
905 		case JS_CNUMBER: printf("[Number %g]", v.u.object->u.number); break;
906 		case JS_CSTRING: printf("[String'%s']", v.u.object->u.s.string); break;
907 		case JS_CERROR: printf("[Error]"); break;
908 		case JS_CARGUMENTS: printf("[Arguments %p]", (void*)v.u.object); break;
909 		case JS_CITERATOR: printf("[Iterator %p]", (void*)v.u.object); break;
910 		case JS_CUSERDATA:
911 			printf("[Userdata %s %p]", v.u.object->u.user.tag, v.u.object->u.user.data);
912 			break;
913 		default: printf("[Object %p]", (void*)v.u.object); break;
914 		}
915 		break;
916 	}
917 }
918 
js_dumpproperty(js_State * J,js_Property * node)919 static void js_dumpproperty(js_State *J, js_Property *node)
920 {
921 	minify = 0;
922 	if (node->left->level)
923 		js_dumpproperty(J, node->left);
924 	printf("\t%s: ", node->name);
925 	js_dumpvalue(J, node->value);
926 	printf(",\n");
927 	if (node->right->level)
928 		js_dumpproperty(J, node->right);
929 }
930 
js_dumpobject(js_State * J,js_Object * obj)931 void js_dumpobject(js_State *J, js_Object *obj)
932 {
933 	minify = 0;
934 	printf("{\n");
935 	if (obj->properties->level)
936 		js_dumpproperty(J, obj->properties);
937 	printf("}\n");
938 }
939