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
10static const char *astname[] = {
11#include "astnames.h"
12NULL
13};
14
15static const char *opname[] = {
16#include "opnames.h"
17NULL
18};
19
20static int minify = 0;
21
22const char *jsP_aststring(enum js_AstType type)
23{
24 if (type < nelem(astname)-1)
25 return astname[type];
26 return "<unknown>";
27}
28
29const char *jsC_opcodestring(enum js_OpCode opcode)
30{
31 if (opcode < nelem(opname)-1)
32 return opname[opcode];
33 return "<unknown>";
34}
35
36static 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
136static void pc(int c)
137{
138 putchar(c);
139}
140
141static void ps(const char *s)
142{
143 fputs(s, stdout);
144}
145
146static void pn(int n)
147{
148 printf("%d", n);
149}
150
151static void in(int d)
152{
153 if (minify < 1)
154 while (d-- > 0)
155 putchar('\t');
156}
157
158static void nl(void)
159{
160 if (minify < 2)
161 putchar('\n');
162}
163
164static void sp(void)
165{
166 if (minify < 1)
167 putchar(' ');
168}
169
170static void comma(void)
171{
172 putchar(',');
173 sp();
174}
175
176/* Pretty-printed Javascript syntax */
177
178static void pstmlist(int d, js_Ast *list);
179static void pexpi(int d, int i, js_Ast *exp);
180static void pstm(int d, js_Ast *stm);
181static void slist(int d, js_Ast *list);
182static void sblock(int d, js_Ast *list);
183
184static 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
195static 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
208static 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
255static 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
286static 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
296static 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
305static 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
312static 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
457static void pexp(int d, js_Ast *exp)
458{
459 pexpi(d, 0, exp);
460}
461
462static 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
472static 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
483static 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
491static 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
502static 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
518static 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
667static 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
677void 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
692static 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
734static 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
747static 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
763void 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
775void 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(" %d", (*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(" %d", *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
861void 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_CCFUNCTION: printf("[CFunction %s]", v.u.object->u.c.name); break;
889 case JS_CBOOLEAN: printf("[Boolean %d]", v.u.object->u.boolean); break;
890 case JS_CNUMBER: printf("[Number %g]", v.u.object->u.number); break;
891 case JS_CSTRING: printf("[String'%s']", v.u.object->u.s.string); break;
892 case JS_CERROR: printf("[Error]"); break;
893 case JS_CARGUMENTS: printf("[Arguments %p]", (void*)v.u.object); break;
894 case JS_CITERATOR: printf("[Iterator %p]", (void*)v.u.object); break;
895 case JS_CUSERDATA:
896 printf("[Userdata %s %p]", v.u.object->u.user.tag, v.u.object->u.user.data);
897 break;
898 default: printf("[Object %p]", (void*)v.u.object); break;
899 }
900 break;
901 }
902}
903
904static void js_dumpproperty(js_State *J, js_Property *node)
905{
906 minify = 0;
907 if (node->left->level)
908 js_dumpproperty(J, node->left);
909 printf("\t%s: ", node->name);
910 js_dumpvalue(J, node->value);
911 printf(",\n");
912 if (node->right->level)
913 js_dumpproperty(J, node->right);
914}
915
916void js_dumpobject(js_State *J, js_Object *obj)
917{
918 minify = 0;
919 printf("{\n");
920 if (obj->properties->level)
921 js_dumpproperty(J, obj->properties);
922 printf("}\n");
923}
924