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