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