Mercurial > hgrepos > Python2 > PyMuPDF
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 } |
