| 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 |  | 
|---|
| 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 |  | 
|---|
| 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 |  | 
|---|
| 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 |  | 
|---|
| 136 | static void pc(int c) | 
|---|
| 137 | { | 
|---|
| 138 | putchar(c); | 
|---|
| 139 | } | 
|---|
| 140 |  | 
|---|
| 141 | static void ps(const char *s) | 
|---|
| 142 | { | 
|---|
| 143 | fputs(s, stdout); | 
|---|
| 144 | } | 
|---|
| 145 |  | 
|---|
| 146 | static void pn(int n) | 
|---|
| 147 | { | 
|---|
| 148 | printf( "%d", n); | 
|---|
| 149 | } | 
|---|
| 150 |  | 
|---|
| 151 | static void in(int d) | 
|---|
| 152 | { | 
|---|
| 153 | if (minify < 1) | 
|---|
| 154 | while (d-- > 0) | 
|---|
| 155 | putchar('\t'); | 
|---|
| 156 | } | 
|---|
| 157 |  | 
|---|
| 158 | static void nl(void) | 
|---|
| 159 | { | 
|---|
| 160 | if (minify < 2) | 
|---|
| 161 | putchar('\n'); | 
|---|
| 162 | } | 
|---|
| 163 |  | 
|---|
| 164 | static void sp(void) | 
|---|
| 165 | { | 
|---|
| 166 | if (minify < 1) | 
|---|
| 167 | putchar(' '); | 
|---|
| 168 | } | 
|---|
| 169 |  | 
|---|
| 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 |  | 
|---|
| 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 |  | 
|---|
| 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 |  | 
|---|
| 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 |  | 
|---|
| 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 |  | 
|---|
| 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 |  | 
|---|
| 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 |  | 
|---|
| 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 |  | 
|---|
| 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 |  | 
|---|
| 457 | static void pexp(int d, js_Ast *exp) | 
|---|
| 458 | { | 
|---|
| 459 | pexpi(d, 0, exp); | 
|---|
| 460 | } | 
|---|
| 461 |  | 
|---|
| 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 |  | 
|---|
| 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 |  | 
|---|
| 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 |  | 
|---|
| 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 |  | 
|---|
| 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 |  | 
|---|
| 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 |  | 
|---|
| 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 |  | 
|---|
| 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 |  | 
|---|
| 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 |  | 
|---|
| 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 |  | 
|---|
| 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 |  | 
|---|
| 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 |  | 
|---|
| 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( " %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 |  | 
|---|
| 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_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 |  | 
|---|
| 904 | static 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 |  | 
|---|
| 916 | void 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 |  | 
|---|