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