comparison mupdf-source/thirdparty/mujs/pp.c @ 2:b50eed0cc0ef upstream

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