Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/mujs/jsparse.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 #include "jsi.h" | |
| 2 | |
| 3 #define LIST(h) jsP_newnode(J, AST_LIST, 0, h, 0, 0, 0) | |
| 4 | |
| 5 #define EXP0(x) jsP_newnode(J, EXP_ ## x, line, 0, 0, 0, 0) | |
| 6 #define EXP1(x,a) jsP_newnode(J, EXP_ ## x, line, a, 0, 0, 0) | |
| 7 #define EXP2(x,a,b) jsP_newnode(J, EXP_ ## x, line, a, b, 0, 0) | |
| 8 #define EXP3(x,a,b,c) jsP_newnode(J, EXP_ ## x, line, a, b, c, 0) | |
| 9 | |
| 10 #define STM0(x) jsP_newnode(J, STM_ ## x, line, 0, 0, 0, 0) | |
| 11 #define STM1(x,a) jsP_newnode(J, STM_ ## x, line, a, 0, 0, 0) | |
| 12 #define STM2(x,a,b) jsP_newnode(J, STM_ ## x, line, a, b, 0, 0) | |
| 13 #define STM3(x,a,b,c) jsP_newnode(J, STM_ ## x, line, a, b, c, 0) | |
| 14 #define STM4(x,a,b,c,d) jsP_newnode(J, STM_ ## x, line, a, b, c, d) | |
| 15 | |
| 16 static js_Ast *expression(js_State *J, int notin); | |
| 17 static js_Ast *assignment(js_State *J, int notin); | |
| 18 static js_Ast *memberexp(js_State *J); | |
| 19 static js_Ast *statement(js_State *J); | |
| 20 static js_Ast *funbody(js_State *J); | |
| 21 | |
| 22 JS_NORETURN static void jsP_error(js_State *J, const char *fmt, ...) JS_PRINTFLIKE(2,3); | |
| 23 | |
| 24 #define INCREC() if (++J->astdepth > JS_ASTLIMIT) jsP_error(J, "too much recursion") | |
| 25 #define DECREC() --J->astdepth | |
| 26 #define SAVEREC() int SAVE=J->astdepth | |
| 27 #define POPREC() J->astdepth=SAVE | |
| 28 | |
| 29 static void jsP_error(js_State *J, const char *fmt, ...) | |
| 30 { | |
| 31 va_list ap; | |
| 32 char buf[512]; | |
| 33 char msgbuf[256]; | |
| 34 | |
| 35 va_start(ap, fmt); | |
| 36 vsnprintf(msgbuf, 256, fmt, ap); | |
| 37 va_end(ap); | |
| 38 | |
| 39 snprintf(buf, 256, "%s:%d: ", J->filename, J->lexline); | |
| 40 strcat(buf, msgbuf); | |
| 41 | |
| 42 js_newsyntaxerror(J, buf); | |
| 43 js_throw(J); | |
| 44 } | |
| 45 | |
| 46 static void jsP_warning(js_State *J, const char *fmt, ...) | |
| 47 { | |
| 48 va_list ap; | |
| 49 char buf[512]; | |
| 50 char msg[256]; | |
| 51 | |
| 52 va_start(ap, fmt); | |
| 53 vsnprintf(msg, sizeof msg, fmt, ap); | |
| 54 va_end(ap); | |
| 55 | |
| 56 snprintf(buf, sizeof buf, "%s:%d: warning: %s", J->filename, J->lexline, msg); | |
| 57 js_report(J, buf); | |
| 58 } | |
| 59 | |
| 60 static js_Ast *jsP_newnode(js_State *J, enum js_AstType type, int line, js_Ast *a, js_Ast *b, js_Ast *c, js_Ast *d) | |
| 61 { | |
| 62 js_Ast *node = js_malloc(J, sizeof *node); | |
| 63 | |
| 64 node->type = type; | |
| 65 node->line = line; | |
| 66 node->a = a; | |
| 67 node->b = b; | |
| 68 node->c = c; | |
| 69 node->d = d; | |
| 70 node->number = 0; | |
| 71 node->string = NULL; | |
| 72 node->jumps = NULL; | |
| 73 node->casejump = 0; | |
| 74 | |
| 75 node->parent = NULL; | |
| 76 if (a) a->parent = node; | |
| 77 if (b) b->parent = node; | |
| 78 if (c) c->parent = node; | |
| 79 if (d) d->parent = node; | |
| 80 | |
| 81 node->gcnext = J->gcast; | |
| 82 J->gcast = node; | |
| 83 | |
| 84 return node; | |
| 85 } | |
| 86 | |
| 87 static js_Ast *jsP_list(js_Ast *head) | |
| 88 { | |
| 89 /* set parent pointers in list nodes */ | |
| 90 js_Ast *prev = head, *node = head->b; | |
| 91 while (node) { | |
| 92 node->parent = prev; | |
| 93 prev = node; | |
| 94 node = node->b; | |
| 95 } | |
| 96 return head; | |
| 97 } | |
| 98 | |
| 99 static js_Ast *jsP_newstrnode(js_State *J, enum js_AstType type, const char *s) | |
| 100 { | |
| 101 js_Ast *node = jsP_newnode(J, type, J->lexline, 0, 0, 0, 0); | |
| 102 node->string = s; | |
| 103 return node; | |
| 104 } | |
| 105 | |
| 106 static js_Ast *jsP_newnumnode(js_State *J, enum js_AstType type, double n) | |
| 107 { | |
| 108 js_Ast *node = jsP_newnode(J, type, J->lexline, 0, 0, 0, 0); | |
| 109 node->number = n; | |
| 110 return node; | |
| 111 } | |
| 112 | |
| 113 static void jsP_freejumps(js_State *J, js_JumpList *node) | |
| 114 { | |
| 115 while (node) { | |
| 116 js_JumpList *next = node->next; | |
| 117 js_free(J, node); | |
| 118 node = next; | |
| 119 } | |
| 120 } | |
| 121 | |
| 122 void jsP_freeparse(js_State *J) | |
| 123 { | |
| 124 js_Ast *node = J->gcast; | |
| 125 while (node) { | |
| 126 js_Ast *next = node->gcnext; | |
| 127 jsP_freejumps(J, node->jumps); | |
| 128 js_free(J, node); | |
| 129 node = next; | |
| 130 } | |
| 131 J->gcast = NULL; | |
| 132 } | |
| 133 | |
| 134 /* Lookahead */ | |
| 135 | |
| 136 static void jsP_next(js_State *J) | |
| 137 { | |
| 138 J->lookahead = jsY_lex(J); | |
| 139 } | |
| 140 | |
| 141 #define jsP_accept(J,x) (J->lookahead == x ? (jsP_next(J), 1) : 0) | |
| 142 | |
| 143 #define jsP_expect(J,x) if (!jsP_accept(J, x)) jsP_error(J, "unexpected token: %s (expected %s)", jsY_tokenstring(J->lookahead), jsY_tokenstring(x)) | |
| 144 | |
| 145 static void semicolon(js_State *J) | |
| 146 { | |
| 147 if (J->lookahead == ';') { | |
| 148 jsP_next(J); | |
| 149 return; | |
| 150 } | |
| 151 if (J->newline || J->lookahead == '}' || J->lookahead == 0) | |
| 152 return; | |
| 153 jsP_error(J, "unexpected token: %s (expected ';')", jsY_tokenstring(J->lookahead)); | |
| 154 } | |
| 155 | |
| 156 /* Literals */ | |
| 157 | |
| 158 static js_Ast *identifier(js_State *J) | |
| 159 { | |
| 160 js_Ast *a; | |
| 161 if (J->lookahead == TK_IDENTIFIER) { | |
| 162 a = jsP_newstrnode(J, AST_IDENTIFIER, J->text); | |
| 163 jsP_next(J); | |
| 164 return a; | |
| 165 } | |
| 166 jsP_error(J, "unexpected token: %s (expected identifier)", jsY_tokenstring(J->lookahead)); | |
| 167 } | |
| 168 | |
| 169 static js_Ast *identifieropt(js_State *J) | |
| 170 { | |
| 171 if (J->lookahead == TK_IDENTIFIER) | |
| 172 return identifier(J); | |
| 173 return NULL; | |
| 174 } | |
| 175 | |
| 176 static js_Ast *identifiername(js_State *J) | |
| 177 { | |
| 178 if (J->lookahead == TK_IDENTIFIER || J->lookahead >= TK_BREAK) { | |
| 179 js_Ast *a = jsP_newstrnode(J, AST_IDENTIFIER, J->text); | |
| 180 jsP_next(J); | |
| 181 return a; | |
| 182 } | |
| 183 jsP_error(J, "unexpected token: %s (expected identifier or keyword)", jsY_tokenstring(J->lookahead)); | |
| 184 } | |
| 185 | |
| 186 static js_Ast *arrayelement(js_State *J) | |
| 187 { | |
| 188 int line = J->lexline; | |
| 189 if (J->lookahead == ',') | |
| 190 return EXP0(ELISION); | |
| 191 return assignment(J, 0); | |
| 192 } | |
| 193 | |
| 194 static js_Ast *arrayliteral(js_State *J) | |
| 195 { | |
| 196 js_Ast *head, *tail; | |
| 197 if (J->lookahead == ']') | |
| 198 return NULL; | |
| 199 head = tail = LIST(arrayelement(J)); | |
| 200 while (jsP_accept(J, ',')) { | |
| 201 if (J->lookahead != ']') | |
| 202 tail = tail->b = LIST(arrayelement(J)); | |
| 203 } | |
| 204 return jsP_list(head); | |
| 205 } | |
| 206 | |
| 207 static js_Ast *propname(js_State *J) | |
| 208 { | |
| 209 js_Ast *name; | |
| 210 if (J->lookahead == TK_NUMBER) { | |
| 211 name = jsP_newnumnode(J, EXP_NUMBER, J->number); | |
| 212 jsP_next(J); | |
| 213 } else if (J->lookahead == TK_STRING) { | |
| 214 name = jsP_newstrnode(J, EXP_STRING, J->text); | |
| 215 jsP_next(J); | |
| 216 } else { | |
| 217 name = identifiername(J); | |
| 218 } | |
| 219 return name; | |
| 220 } | |
| 221 | |
| 222 static js_Ast *propassign(js_State *J) | |
| 223 { | |
| 224 js_Ast *name, *value, *arg, *body; | |
| 225 int line = J->lexline; | |
| 226 | |
| 227 name = propname(J); | |
| 228 | |
| 229 if (J->lookahead != ':' && name->type == AST_IDENTIFIER) { | |
| 230 if (!strcmp(name->string, "get")) { | |
| 231 name = propname(J); | |
| 232 jsP_expect(J, '('); | |
| 233 jsP_expect(J, ')'); | |
| 234 body = funbody(J); | |
| 235 return EXP3(PROP_GET, name, NULL, body); | |
| 236 } | |
| 237 if (!strcmp(name->string, "set")) { | |
| 238 name = propname(J); | |
| 239 jsP_expect(J, '('); | |
| 240 arg = identifier(J); | |
| 241 jsP_expect(J, ')'); | |
| 242 body = funbody(J); | |
| 243 return EXP3(PROP_SET, name, LIST(arg), body); | |
| 244 } | |
| 245 } | |
| 246 | |
| 247 jsP_expect(J, ':'); | |
| 248 value = assignment(J, 0); | |
| 249 return EXP2(PROP_VAL, name, value); | |
| 250 } | |
| 251 | |
| 252 static js_Ast *objectliteral(js_State *J) | |
| 253 { | |
| 254 js_Ast *head, *tail; | |
| 255 if (J->lookahead == '}') | |
| 256 return NULL; | |
| 257 head = tail = LIST(propassign(J)); | |
| 258 while (jsP_accept(J, ',')) { | |
| 259 if (J->lookahead == '}') | |
| 260 break; | |
| 261 tail = tail->b = LIST(propassign(J)); | |
| 262 } | |
| 263 return jsP_list(head); | |
| 264 } | |
| 265 | |
| 266 /* Functions */ | |
| 267 | |
| 268 static js_Ast *parameters(js_State *J) | |
| 269 { | |
| 270 js_Ast *head, *tail; | |
| 271 if (J->lookahead == ')') | |
| 272 return NULL; | |
| 273 head = tail = LIST(identifier(J)); | |
| 274 while (jsP_accept(J, ',')) { | |
| 275 tail = tail->b = LIST(identifier(J)); | |
| 276 } | |
| 277 return jsP_list(head); | |
| 278 } | |
| 279 | |
| 280 static js_Ast *fundec(js_State *J, int line) | |
| 281 { | |
| 282 js_Ast *a, *b, *c; | |
| 283 a = identifier(J); | |
| 284 jsP_expect(J, '('); | |
| 285 b = parameters(J); | |
| 286 jsP_expect(J, ')'); | |
| 287 c = funbody(J); | |
| 288 return jsP_newnode(J, AST_FUNDEC, line, a, b, c, 0); | |
| 289 } | |
| 290 | |
| 291 static js_Ast *funstm(js_State *J, int line) | |
| 292 { | |
| 293 js_Ast *a, *b, *c; | |
| 294 a = identifier(J); | |
| 295 jsP_expect(J, '('); | |
| 296 b = parameters(J); | |
| 297 jsP_expect(J, ')'); | |
| 298 c = funbody(J); | |
| 299 /* rewrite function statement as "var X = function X() {}" */ | |
| 300 return STM1(VAR, LIST(EXP2(VAR, a, EXP3(FUN, a, b, c)))); | |
| 301 } | |
| 302 | |
| 303 static js_Ast *funexp(js_State *J, int line) | |
| 304 { | |
| 305 js_Ast *a, *b, *c; | |
| 306 a = identifieropt(J); | |
| 307 jsP_expect(J, '('); | |
| 308 b = parameters(J); | |
| 309 jsP_expect(J, ')'); | |
| 310 c = funbody(J); | |
| 311 return EXP3(FUN, a, b, c); | |
| 312 } | |
| 313 | |
| 314 /* Expressions */ | |
| 315 | |
| 316 static js_Ast *primary(js_State *J) | |
| 317 { | |
| 318 js_Ast *a; | |
| 319 int line = J->lexline; | |
| 320 | |
| 321 if (J->lookahead == TK_IDENTIFIER) { | |
| 322 a = jsP_newstrnode(J, EXP_IDENTIFIER, J->text); | |
| 323 jsP_next(J); | |
| 324 return a; | |
| 325 } | |
| 326 if (J->lookahead == TK_STRING) { | |
| 327 a = jsP_newstrnode(J, EXP_STRING, J->text); | |
| 328 jsP_next(J); | |
| 329 return a; | |
| 330 } | |
| 331 if (J->lookahead == TK_REGEXP) { | |
| 332 a = jsP_newstrnode(J, EXP_REGEXP, J->text); | |
| 333 a->number = J->number; | |
| 334 jsP_next(J); | |
| 335 return a; | |
| 336 } | |
| 337 if (J->lookahead == TK_NUMBER) { | |
| 338 a = jsP_newnumnode(J, EXP_NUMBER, J->number); | |
| 339 jsP_next(J); | |
| 340 return a; | |
| 341 } | |
| 342 | |
| 343 if (jsP_accept(J, TK_THIS)) return EXP0(THIS); | |
| 344 if (jsP_accept(J, TK_NULL)) return EXP0(NULL); | |
| 345 if (jsP_accept(J, TK_TRUE)) return EXP0(TRUE); | |
| 346 if (jsP_accept(J, TK_FALSE)) return EXP0(FALSE); | |
| 347 if (jsP_accept(J, '{')) { | |
| 348 a = EXP1(OBJECT, objectliteral(J)); | |
| 349 jsP_expect(J, '}'); | |
| 350 return a; | |
| 351 } | |
| 352 if (jsP_accept(J, '[')) { | |
| 353 a = EXP1(ARRAY, arrayliteral(J)); | |
| 354 jsP_expect(J, ']'); | |
| 355 return a; | |
| 356 } | |
| 357 if (jsP_accept(J, '(')) { | |
| 358 a = expression(J, 0); | |
| 359 jsP_expect(J, ')'); | |
| 360 return a; | |
| 361 } | |
| 362 | |
| 363 jsP_error(J, "unexpected token in expression: %s", jsY_tokenstring(J->lookahead)); | |
| 364 } | |
| 365 | |
| 366 static js_Ast *arguments(js_State *J) | |
| 367 { | |
| 368 js_Ast *head, *tail; | |
| 369 if (J->lookahead == ')') | |
| 370 return NULL; | |
| 371 head = tail = LIST(assignment(J, 0)); | |
| 372 while (jsP_accept(J, ',')) { | |
| 373 tail = tail->b = LIST(assignment(J, 0)); | |
| 374 } | |
| 375 return jsP_list(head); | |
| 376 } | |
| 377 | |
| 378 static js_Ast *newexp(js_State *J) | |
| 379 { | |
| 380 js_Ast *a, *b; | |
| 381 int line = J->lexline; | |
| 382 | |
| 383 if (jsP_accept(J, TK_NEW)) { | |
| 384 a = memberexp(J); | |
| 385 if (jsP_accept(J, '(')) { | |
| 386 b = arguments(J); | |
| 387 jsP_expect(J, ')'); | |
| 388 return EXP2(NEW, a, b); | |
| 389 } | |
| 390 return EXP1(NEW, a); | |
| 391 } | |
| 392 | |
| 393 if (jsP_accept(J, TK_FUNCTION)) | |
| 394 return funexp(J, line); | |
| 395 | |
| 396 return primary(J); | |
| 397 } | |
| 398 | |
| 399 static js_Ast *memberexp(js_State *J) | |
| 400 { | |
| 401 js_Ast *a = newexp(J); | |
| 402 int line; | |
| 403 SAVEREC(); | |
| 404 loop: | |
| 405 INCREC(); | |
| 406 line = J->lexline; | |
| 407 if (jsP_accept(J, '.')) { a = EXP2(MEMBER, a, identifiername(J)); goto loop; } | |
| 408 if (jsP_accept(J, '[')) { a = EXP2(INDEX, a, expression(J, 0)); jsP_expect(J, ']'); goto loop; } | |
| 409 POPREC(); | |
| 410 return a; | |
| 411 } | |
| 412 | |
| 413 static js_Ast *callexp(js_State *J) | |
| 414 { | |
| 415 js_Ast *a = newexp(J); | |
| 416 int line; | |
| 417 SAVEREC(); | |
| 418 loop: | |
| 419 INCREC(); | |
| 420 line = J->lexline; | |
| 421 if (jsP_accept(J, '.')) { a = EXP2(MEMBER, a, identifiername(J)); goto loop; } | |
| 422 if (jsP_accept(J, '[')) { a = EXP2(INDEX, a, expression(J, 0)); jsP_expect(J, ']'); goto loop; } | |
| 423 if (jsP_accept(J, '(')) { a = EXP2(CALL, a, arguments(J)); jsP_expect(J, ')'); goto loop; } | |
| 424 POPREC(); | |
| 425 return a; | |
| 426 } | |
| 427 | |
| 428 static js_Ast *postfix(js_State *J) | |
| 429 { | |
| 430 js_Ast *a = callexp(J); | |
| 431 int line = J->lexline; | |
| 432 if (!J->newline && jsP_accept(J, TK_INC)) return EXP1(POSTINC, a); | |
| 433 if (!J->newline && jsP_accept(J, TK_DEC)) return EXP1(POSTDEC, a); | |
| 434 return a; | |
| 435 } | |
| 436 | |
| 437 static js_Ast *unary(js_State *J) | |
| 438 { | |
| 439 js_Ast *a; | |
| 440 int line = J->lexline; | |
| 441 INCREC(); | |
| 442 if (jsP_accept(J, TK_DELETE)) a = EXP1(DELETE, unary(J)); | |
| 443 else if (jsP_accept(J, TK_VOID)) a = EXP1(VOID, unary(J)); | |
| 444 else if (jsP_accept(J, TK_TYPEOF)) a = EXP1(TYPEOF, unary(J)); | |
| 445 else if (jsP_accept(J, TK_INC)) a = EXP1(PREINC, unary(J)); | |
| 446 else if (jsP_accept(J, TK_DEC)) a = EXP1(PREDEC, unary(J)); | |
| 447 else if (jsP_accept(J, '+')) a = EXP1(POS, unary(J)); | |
| 448 else if (jsP_accept(J, '-')) a = EXP1(NEG, unary(J)); | |
| 449 else if (jsP_accept(J, '~')) a = EXP1(BITNOT, unary(J)); | |
| 450 else if (jsP_accept(J, '!')) a = EXP1(LOGNOT, unary(J)); | |
| 451 else a = postfix(J); | |
| 452 DECREC(); | |
| 453 return a; | |
| 454 } | |
| 455 | |
| 456 static js_Ast *multiplicative(js_State *J) | |
| 457 { | |
| 458 js_Ast *a = unary(J); | |
| 459 int line; | |
| 460 SAVEREC(); | |
| 461 loop: | |
| 462 INCREC(); | |
| 463 line = J->lexline; | |
| 464 if (jsP_accept(J, '*')) { a = EXP2(MUL, a, unary(J)); goto loop; } | |
| 465 if (jsP_accept(J, '/')) { a = EXP2(DIV, a, unary(J)); goto loop; } | |
| 466 if (jsP_accept(J, '%')) { a = EXP2(MOD, a, unary(J)); goto loop; } | |
| 467 POPREC(); | |
| 468 return a; | |
| 469 } | |
| 470 | |
| 471 static js_Ast *additive(js_State *J) | |
| 472 { | |
| 473 js_Ast *a = multiplicative(J); | |
| 474 int line; | |
| 475 SAVEREC(); | |
| 476 loop: | |
| 477 INCREC(); | |
| 478 line = J->lexline; | |
| 479 if (jsP_accept(J, '+')) { a = EXP2(ADD, a, multiplicative(J)); goto loop; } | |
| 480 if (jsP_accept(J, '-')) { a = EXP2(SUB, a, multiplicative(J)); goto loop; } | |
| 481 POPREC(); | |
| 482 return a; | |
| 483 } | |
| 484 | |
| 485 static js_Ast *shift(js_State *J) | |
| 486 { | |
| 487 js_Ast *a = additive(J); | |
| 488 int line; | |
| 489 SAVEREC(); | |
| 490 loop: | |
| 491 INCREC(); | |
| 492 line = J->lexline; | |
| 493 if (jsP_accept(J, TK_SHL)) { a = EXP2(SHL, a, additive(J)); goto loop; } | |
| 494 if (jsP_accept(J, TK_SHR)) { a = EXP2(SHR, a, additive(J)); goto loop; } | |
| 495 if (jsP_accept(J, TK_USHR)) { a = EXP2(USHR, a, additive(J)); goto loop; } | |
| 496 POPREC(); | |
| 497 return a; | |
| 498 } | |
| 499 | |
| 500 static js_Ast *relational(js_State *J, int notin) | |
| 501 { | |
| 502 js_Ast *a = shift(J); | |
| 503 int line; | |
| 504 SAVEREC(); | |
| 505 loop: | |
| 506 INCREC(); | |
| 507 line = J->lexline; | |
| 508 if (jsP_accept(J, '<')) { a = EXP2(LT, a, shift(J)); goto loop; } | |
| 509 if (jsP_accept(J, '>')) { a = EXP2(GT, a, shift(J)); goto loop; } | |
| 510 if (jsP_accept(J, TK_LE)) { a = EXP2(LE, a, shift(J)); goto loop; } | |
| 511 if (jsP_accept(J, TK_GE)) { a = EXP2(GE, a, shift(J)); goto loop; } | |
| 512 if (jsP_accept(J, TK_INSTANCEOF)) { a = EXP2(INSTANCEOF, a, shift(J)); goto loop; } | |
| 513 if (!notin && jsP_accept(J, TK_IN)) { a = EXP2(IN, a, shift(J)); goto loop; } | |
| 514 POPREC(); | |
| 515 return a; | |
| 516 } | |
| 517 | |
| 518 static js_Ast *equality(js_State *J, int notin) | |
| 519 { | |
| 520 js_Ast *a = relational(J, notin); | |
| 521 int line; | |
| 522 SAVEREC(); | |
| 523 loop: | |
| 524 INCREC(); | |
| 525 line = J->lexline; | |
| 526 if (jsP_accept(J, TK_EQ)) { a = EXP2(EQ, a, relational(J, notin)); goto loop; } | |
| 527 if (jsP_accept(J, TK_NE)) { a = EXP2(NE, a, relational(J, notin)); goto loop; } | |
| 528 if (jsP_accept(J, TK_STRICTEQ)) { a = EXP2(STRICTEQ, a, relational(J, notin)); goto loop; } | |
| 529 if (jsP_accept(J, TK_STRICTNE)) { a = EXP2(STRICTNE, a, relational(J, notin)); goto loop; } | |
| 530 POPREC(); | |
| 531 return a; | |
| 532 } | |
| 533 | |
| 534 static js_Ast *bitand(js_State *J, int notin) | |
| 535 { | |
| 536 js_Ast *a = equality(J, notin); | |
| 537 SAVEREC(); | |
| 538 int line = J->lexline; | |
| 539 while (jsP_accept(J, '&')) { | |
| 540 INCREC(); | |
| 541 a = EXP2(BITAND, a, equality(J, notin)); | |
| 542 line = J->lexline; | |
| 543 } | |
| 544 POPREC(); | |
| 545 return a; | |
| 546 } | |
| 547 | |
| 548 static js_Ast *bitxor(js_State *J, int notin) | |
| 549 { | |
| 550 js_Ast *a = bitand(J, notin); | |
| 551 SAVEREC(); | |
| 552 int line = J->lexline; | |
| 553 while (jsP_accept(J, '^')) { | |
| 554 INCREC(); | |
| 555 a = EXP2(BITXOR, a, bitand(J, notin)); | |
| 556 line = J->lexline; | |
| 557 } | |
| 558 POPREC(); | |
| 559 return a; | |
| 560 } | |
| 561 | |
| 562 static js_Ast *bitor(js_State *J, int notin) | |
| 563 { | |
| 564 js_Ast *a = bitxor(J, notin); | |
| 565 SAVEREC(); | |
| 566 int line = J->lexline; | |
| 567 while (jsP_accept(J, '|')) { | |
| 568 INCREC(); | |
| 569 a = EXP2(BITOR, a, bitxor(J, notin)); | |
| 570 line = J->lexline; | |
| 571 } | |
| 572 POPREC(); | |
| 573 return a; | |
| 574 } | |
| 575 | |
| 576 static js_Ast *logand(js_State *J, int notin) | |
| 577 { | |
| 578 js_Ast *a = bitor(J, notin); | |
| 579 int line = J->lexline; | |
| 580 if (jsP_accept(J, TK_AND)) { | |
| 581 INCREC(); | |
| 582 a = EXP2(LOGAND, a, logand(J, notin)); | |
| 583 DECREC(); | |
| 584 } | |
| 585 return a; | |
| 586 } | |
| 587 | |
| 588 static js_Ast *logor(js_State *J, int notin) | |
| 589 { | |
| 590 js_Ast *a = logand(J, notin); | |
| 591 int line = J->lexline; | |
| 592 if (jsP_accept(J, TK_OR)) { | |
| 593 INCREC(); | |
| 594 a = EXP2(LOGOR, a, logor(J, notin)); | |
| 595 DECREC(); | |
| 596 } | |
| 597 return a; | |
| 598 } | |
| 599 | |
| 600 static js_Ast *conditional(js_State *J, int notin) | |
| 601 { | |
| 602 js_Ast *a = logor(J, notin); | |
| 603 int line = J->lexline; | |
| 604 if (jsP_accept(J, '?')) { | |
| 605 js_Ast *b, *c; | |
| 606 INCREC(); | |
| 607 b = assignment(J, 0); | |
| 608 jsP_expect(J, ':'); | |
| 609 c = assignment(J, notin); | |
| 610 DECREC(); | |
| 611 return EXP3(COND, a, b, c); | |
| 612 } | |
| 613 return a; | |
| 614 } | |
| 615 | |
| 616 static js_Ast *assignment(js_State *J, int notin) | |
| 617 { | |
| 618 js_Ast *a = conditional(J, notin); | |
| 619 int line = J->lexline; | |
| 620 INCREC(); | |
| 621 if (jsP_accept(J, '=')) a = EXP2(ASS, a, assignment(J, notin)); | |
| 622 else if (jsP_accept(J, TK_MUL_ASS)) a = EXP2(ASS_MUL, a, assignment(J, notin)); | |
| 623 else if (jsP_accept(J, TK_DIV_ASS)) a = EXP2(ASS_DIV, a, assignment(J, notin)); | |
| 624 else if (jsP_accept(J, TK_MOD_ASS)) a = EXP2(ASS_MOD, a, assignment(J, notin)); | |
| 625 else if (jsP_accept(J, TK_ADD_ASS)) a = EXP2(ASS_ADD, a, assignment(J, notin)); | |
| 626 else if (jsP_accept(J, TK_SUB_ASS)) a = EXP2(ASS_SUB, a, assignment(J, notin)); | |
| 627 else if (jsP_accept(J, TK_SHL_ASS)) a = EXP2(ASS_SHL, a, assignment(J, notin)); | |
| 628 else if (jsP_accept(J, TK_SHR_ASS)) a = EXP2(ASS_SHR, a, assignment(J, notin)); | |
| 629 else if (jsP_accept(J, TK_USHR_ASS)) a = EXP2(ASS_USHR, a, assignment(J, notin)); | |
| 630 else if (jsP_accept(J, TK_AND_ASS)) a = EXP2(ASS_BITAND, a, assignment(J, notin)); | |
| 631 else if (jsP_accept(J, TK_XOR_ASS)) a = EXP2(ASS_BITXOR, a, assignment(J, notin)); | |
| 632 else if (jsP_accept(J, TK_OR_ASS)) a = EXP2(ASS_BITOR, a, assignment(J, notin)); | |
| 633 DECREC(); | |
| 634 return a; | |
| 635 } | |
| 636 | |
| 637 static js_Ast *expression(js_State *J, int notin) | |
| 638 { | |
| 639 js_Ast *a = assignment(J, notin); | |
| 640 SAVEREC(); | |
| 641 int line = J->lexline; | |
| 642 while (jsP_accept(J, ',')) { | |
| 643 INCREC(); | |
| 644 a = EXP2(COMMA, a, assignment(J, notin)); | |
| 645 line = J->lexline; | |
| 646 } | |
| 647 POPREC(); | |
| 648 return a; | |
| 649 } | |
| 650 | |
| 651 /* Statements */ | |
| 652 | |
| 653 static js_Ast *vardec(js_State *J, int notin) | |
| 654 { | |
| 655 js_Ast *a = identifier(J); | |
| 656 int line = J->lexline; | |
| 657 if (jsP_accept(J, '=')) | |
| 658 return EXP2(VAR, a, assignment(J, notin)); | |
| 659 return EXP1(VAR, a); | |
| 660 } | |
| 661 | |
| 662 static js_Ast *vardeclist(js_State *J, int notin) | |
| 663 { | |
| 664 js_Ast *head, *tail; | |
| 665 head = tail = LIST(vardec(J, notin)); | |
| 666 while (jsP_accept(J, ',')) | |
| 667 tail = tail->b = LIST(vardec(J, notin)); | |
| 668 return jsP_list(head); | |
| 669 } | |
| 670 | |
| 671 static js_Ast *statementlist(js_State *J) | |
| 672 { | |
| 673 js_Ast *head, *tail; | |
| 674 if (J->lookahead == '}' || J->lookahead == TK_CASE || J->lookahead == TK_DEFAULT) | |
| 675 return NULL; | |
| 676 head = tail = LIST(statement(J)); | |
| 677 while (J->lookahead != '}' && J->lookahead != TK_CASE && J->lookahead != TK_DEFAULT) | |
| 678 tail = tail->b = LIST(statement(J)); | |
| 679 return jsP_list(head); | |
| 680 } | |
| 681 | |
| 682 static js_Ast *caseclause(js_State *J) | |
| 683 { | |
| 684 js_Ast *a, *b; | |
| 685 int line = J->lexline; | |
| 686 | |
| 687 if (jsP_accept(J, TK_CASE)) { | |
| 688 a = expression(J, 0); | |
| 689 jsP_expect(J, ':'); | |
| 690 b = statementlist(J); | |
| 691 return STM2(CASE, a, b); | |
| 692 } | |
| 693 | |
| 694 if (jsP_accept(J, TK_DEFAULT)) { | |
| 695 jsP_expect(J, ':'); | |
| 696 a = statementlist(J); | |
| 697 return STM1(DEFAULT, a); | |
| 698 } | |
| 699 | |
| 700 jsP_error(J, "unexpected token in switch: %s (expected 'case' or 'default')", jsY_tokenstring(J->lookahead)); | |
| 701 } | |
| 702 | |
| 703 static js_Ast *caselist(js_State *J) | |
| 704 { | |
| 705 js_Ast *head, *tail; | |
| 706 if (J->lookahead == '}') | |
| 707 return NULL; | |
| 708 head = tail = LIST(caseclause(J)); | |
| 709 while (J->lookahead != '}') | |
| 710 tail = tail->b = LIST(caseclause(J)); | |
| 711 return jsP_list(head); | |
| 712 } | |
| 713 | |
| 714 static js_Ast *block(js_State *J) | |
| 715 { | |
| 716 js_Ast *a; | |
| 717 int line = J->lexline; | |
| 718 jsP_expect(J, '{'); | |
| 719 a = statementlist(J); | |
| 720 jsP_expect(J, '}'); | |
| 721 return STM1(BLOCK, a); | |
| 722 } | |
| 723 | |
| 724 static js_Ast *forexpression(js_State *J, int end) | |
| 725 { | |
| 726 js_Ast *a = NULL; | |
| 727 if (J->lookahead != end) | |
| 728 a = expression(J, 0); | |
| 729 jsP_expect(J, end); | |
| 730 return a; | |
| 731 } | |
| 732 | |
| 733 static js_Ast *forstatement(js_State *J, int line) | |
| 734 { | |
| 735 js_Ast *a, *b, *c, *d; | |
| 736 jsP_expect(J, '('); | |
| 737 if (jsP_accept(J, TK_VAR)) { | |
| 738 a = vardeclist(J, 1); | |
| 739 if (jsP_accept(J, ';')) { | |
| 740 b = forexpression(J, ';'); | |
| 741 c = forexpression(J, ')'); | |
| 742 d = statement(J); | |
| 743 return STM4(FOR_VAR, a, b, c, d); | |
| 744 } | |
| 745 if (jsP_accept(J, TK_IN)) { | |
| 746 b = expression(J, 0); | |
| 747 jsP_expect(J, ')'); | |
| 748 c = statement(J); | |
| 749 return STM3(FOR_IN_VAR, a, b, c); | |
| 750 } | |
| 751 jsP_error(J, "unexpected token in for-var-statement: %s", jsY_tokenstring(J->lookahead)); | |
| 752 } | |
| 753 | |
| 754 if (J->lookahead != ';') | |
| 755 a = expression(J, 1); | |
| 756 else | |
| 757 a = NULL; | |
| 758 if (jsP_accept(J, ';')) { | |
| 759 b = forexpression(J, ';'); | |
| 760 c = forexpression(J, ')'); | |
| 761 d = statement(J); | |
| 762 return STM4(FOR, a, b, c, d); | |
| 763 } | |
| 764 if (jsP_accept(J, TK_IN)) { | |
| 765 b = expression(J, 0); | |
| 766 jsP_expect(J, ')'); | |
| 767 c = statement(J); | |
| 768 return STM3(FOR_IN, a, b, c); | |
| 769 } | |
| 770 jsP_error(J, "unexpected token in for-statement: %s", jsY_tokenstring(J->lookahead)); | |
| 771 } | |
| 772 | |
| 773 static js_Ast *statement(js_State *J) | |
| 774 { | |
| 775 js_Ast *a, *b, *c, *d; | |
| 776 js_Ast *stm; | |
| 777 int line = J->lexline; | |
| 778 | |
| 779 INCREC(); | |
| 780 | |
| 781 if (J->lookahead == '{') { | |
| 782 stm = block(J); | |
| 783 } | |
| 784 | |
| 785 else if (jsP_accept(J, TK_VAR)) { | |
| 786 a = vardeclist(J, 0); | |
| 787 semicolon(J); | |
| 788 stm = STM1(VAR, a); | |
| 789 } | |
| 790 | |
| 791 /* empty statement */ | |
| 792 else if (jsP_accept(J, ';')) { | |
| 793 stm = STM0(EMPTY); | |
| 794 } | |
| 795 | |
| 796 else if (jsP_accept(J, TK_IF)) { | |
| 797 jsP_expect(J, '('); | |
| 798 a = expression(J, 0); | |
| 799 jsP_expect(J, ')'); | |
| 800 b = statement(J); | |
| 801 if (jsP_accept(J, TK_ELSE)) | |
| 802 c = statement(J); | |
| 803 else | |
| 804 c = NULL; | |
| 805 stm = STM3(IF, a, b, c); | |
| 806 } | |
| 807 | |
| 808 else if (jsP_accept(J, TK_DO)) { | |
| 809 a = statement(J); | |
| 810 jsP_expect(J, TK_WHILE); | |
| 811 jsP_expect(J, '('); | |
| 812 b = expression(J, 0); | |
| 813 jsP_expect(J, ')'); | |
| 814 semicolon(J); | |
| 815 stm = STM2(DO, a, b); | |
| 816 } | |
| 817 | |
| 818 else if (jsP_accept(J, TK_WHILE)) { | |
| 819 jsP_expect(J, '('); | |
| 820 a = expression(J, 0); | |
| 821 jsP_expect(J, ')'); | |
| 822 b = statement(J); | |
| 823 stm = STM2(WHILE, a, b); | |
| 824 } | |
| 825 | |
| 826 else if (jsP_accept(J, TK_FOR)) { | |
| 827 stm = forstatement(J, line); | |
| 828 } | |
| 829 | |
| 830 else if (jsP_accept(J, TK_CONTINUE)) { | |
| 831 a = identifieropt(J); | |
| 832 semicolon(J); | |
| 833 stm = STM1(CONTINUE, a); | |
| 834 } | |
| 835 | |
| 836 else if (jsP_accept(J, TK_BREAK)) { | |
| 837 a = identifieropt(J); | |
| 838 semicolon(J); | |
| 839 stm = STM1(BREAK, a); | |
| 840 } | |
| 841 | |
| 842 else if (jsP_accept(J, TK_RETURN)) { | |
| 843 if (J->lookahead != ';' && J->lookahead != '}' && J->lookahead != 0) | |
| 844 a = expression(J, 0); | |
| 845 else | |
| 846 a = NULL; | |
| 847 semicolon(J); | |
| 848 stm = STM1(RETURN, a); | |
| 849 } | |
| 850 | |
| 851 else if (jsP_accept(J, TK_WITH)) { | |
| 852 jsP_expect(J, '('); | |
| 853 a = expression(J, 0); | |
| 854 jsP_expect(J, ')'); | |
| 855 b = statement(J); | |
| 856 stm = STM2(WITH, a, b); | |
| 857 } | |
| 858 | |
| 859 else if (jsP_accept(J, TK_SWITCH)) { | |
| 860 jsP_expect(J, '('); | |
| 861 a = expression(J, 0); | |
| 862 jsP_expect(J, ')'); | |
| 863 jsP_expect(J, '{'); | |
| 864 b = caselist(J); | |
| 865 jsP_expect(J, '}'); | |
| 866 stm = STM2(SWITCH, a, b); | |
| 867 } | |
| 868 | |
| 869 else if (jsP_accept(J, TK_THROW)) { | |
| 870 a = expression(J, 0); | |
| 871 semicolon(J); | |
| 872 stm = STM1(THROW, a); | |
| 873 } | |
| 874 | |
| 875 else if (jsP_accept(J, TK_TRY)) { | |
| 876 a = block(J); | |
| 877 b = c = d = NULL; | |
| 878 if (jsP_accept(J, TK_CATCH)) { | |
| 879 jsP_expect(J, '('); | |
| 880 b = identifier(J); | |
| 881 jsP_expect(J, ')'); | |
| 882 c = block(J); | |
| 883 } | |
| 884 if (jsP_accept(J, TK_FINALLY)) { | |
| 885 d = block(J); | |
| 886 } | |
| 887 if (!b && !d) | |
| 888 jsP_error(J, "unexpected token in try: %s (expected 'catch' or 'finally')", jsY_tokenstring(J->lookahead)); | |
| 889 stm = STM4(TRY, a, b, c, d); | |
| 890 } | |
| 891 | |
| 892 else if (jsP_accept(J, TK_DEBUGGER)) { | |
| 893 semicolon(J); | |
| 894 stm = STM0(DEBUGGER); | |
| 895 } | |
| 896 | |
| 897 else if (jsP_accept(J, TK_FUNCTION)) { | |
| 898 jsP_warning(J, "function statements are not standard"); | |
| 899 stm = funstm(J, line); | |
| 900 } | |
| 901 | |
| 902 /* labelled statement or expression statement */ | |
| 903 else if (J->lookahead == TK_IDENTIFIER) { | |
| 904 a = expression(J, 0); | |
| 905 if (a->type == EXP_IDENTIFIER && jsP_accept(J, ':')) { | |
| 906 a->type = AST_IDENTIFIER; | |
| 907 b = statement(J); | |
| 908 stm = STM2(LABEL, a, b); | |
| 909 } else { | |
| 910 semicolon(J); | |
| 911 stm = a; | |
| 912 } | |
| 913 } | |
| 914 | |
| 915 /* expression statement */ | |
| 916 else { | |
| 917 stm = expression(J, 0); | |
| 918 semicolon(J); | |
| 919 } | |
| 920 | |
| 921 DECREC(); | |
| 922 return stm; | |
| 923 } | |
| 924 | |
| 925 /* Program */ | |
| 926 | |
| 927 static js_Ast *scriptelement(js_State *J) | |
| 928 { | |
| 929 int line = J->lexline; | |
| 930 if (jsP_accept(J, TK_FUNCTION)) | |
| 931 return fundec(J, line); | |
| 932 return statement(J); | |
| 933 } | |
| 934 | |
| 935 static js_Ast *script(js_State *J, int terminator) | |
| 936 { | |
| 937 js_Ast *head, *tail; | |
| 938 if (J->lookahead == terminator) | |
| 939 return NULL; | |
| 940 head = tail = LIST(scriptelement(J)); | |
| 941 while (J->lookahead != terminator) | |
| 942 tail = tail->b = LIST(scriptelement(J)); | |
| 943 return jsP_list(head); | |
| 944 } | |
| 945 | |
| 946 static js_Ast *funbody(js_State *J) | |
| 947 { | |
| 948 js_Ast *a; | |
| 949 jsP_expect(J, '{'); | |
| 950 a = script(J, '}'); | |
| 951 jsP_expect(J, '}'); | |
| 952 return a; | |
| 953 } | |
| 954 | |
| 955 /* Constant folding */ | |
| 956 | |
| 957 static int toint32(double d) | |
| 958 { | |
| 959 double two32 = 4294967296.0; | |
| 960 double two31 = 2147483648.0; | |
| 961 | |
| 962 if (!isfinite(d) || d == 0) | |
| 963 return 0; | |
| 964 | |
| 965 d = fmod(d, two32); | |
| 966 d = d >= 0 ? floor(d) : ceil(d) + two32; | |
| 967 if (d >= two31) | |
| 968 return d - two32; | |
| 969 else | |
| 970 return d; | |
| 971 } | |
| 972 | |
| 973 static unsigned int touint32(double d) | |
| 974 { | |
| 975 return (unsigned int)toint32(d); | |
| 976 } | |
| 977 | |
| 978 static int jsP_setnumnode(js_Ast *node, double x) | |
| 979 { | |
| 980 node->type = EXP_NUMBER; | |
| 981 node->number = x; | |
| 982 node->a = node->b = node->c = node->d = NULL; | |
| 983 return 1; | |
| 984 } | |
| 985 | |
| 986 static int jsP_foldconst(js_Ast *node) | |
| 987 { | |
| 988 double x, y; | |
| 989 int a, b; | |
| 990 | |
| 991 if (node->type == AST_LIST) { | |
| 992 while (node) { | |
| 993 jsP_foldconst(node->a); | |
| 994 node = node->b; | |
| 995 } | |
| 996 return 0; | |
| 997 } | |
| 998 | |
| 999 if (node->type == EXP_NUMBER) | |
| 1000 return 1; | |
| 1001 | |
| 1002 a = node->a ? jsP_foldconst(node->a) : 0; | |
| 1003 b = node->b ? jsP_foldconst(node->b) : 0; | |
| 1004 if (node->c) jsP_foldconst(node->c); | |
| 1005 if (node->d) jsP_foldconst(node->d); | |
| 1006 | |
| 1007 if (a) { | |
| 1008 x = node->a->number; | |
| 1009 switch (node->type) { | |
| 1010 default: break; | |
| 1011 case EXP_NEG: return jsP_setnumnode(node, -x); | |
| 1012 case EXP_POS: return jsP_setnumnode(node, x); | |
| 1013 case EXP_BITNOT: return jsP_setnumnode(node, ~toint32(x)); | |
| 1014 } | |
| 1015 | |
| 1016 if (b) { | |
| 1017 y = node->b->number; | |
| 1018 switch (node->type) { | |
| 1019 default: break; | |
| 1020 case EXP_MUL: return jsP_setnumnode(node, x * y); | |
| 1021 case EXP_DIV: return jsP_setnumnode(node, x / y); | |
| 1022 case EXP_MOD: return jsP_setnumnode(node, fmod(x, y)); | |
| 1023 case EXP_ADD: return jsP_setnumnode(node, x + y); | |
| 1024 case EXP_SUB: return jsP_setnumnode(node, x - y); | |
| 1025 case EXP_SHL: return jsP_setnumnode(node, toint32(x) << (touint32(y) & 0x1F)); | |
| 1026 case EXP_SHR: return jsP_setnumnode(node, toint32(x) >> (touint32(y) & 0x1F)); | |
| 1027 case EXP_USHR: return jsP_setnumnode(node, touint32(x) >> (touint32(y) & 0x1F)); | |
| 1028 case EXP_BITAND: return jsP_setnumnode(node, toint32(x) & toint32(y)); | |
| 1029 case EXP_BITXOR: return jsP_setnumnode(node, toint32(x) ^ toint32(y)); | |
| 1030 case EXP_BITOR: return jsP_setnumnode(node, toint32(x) | toint32(y)); | |
| 1031 } | |
| 1032 } | |
| 1033 } | |
| 1034 | |
| 1035 return 0; | |
| 1036 } | |
| 1037 | |
| 1038 /* Main entry point */ | |
| 1039 | |
| 1040 js_Ast *jsP_parse(js_State *J, const char *filename, const char *source) | |
| 1041 { | |
| 1042 js_Ast *p; | |
| 1043 | |
| 1044 jsY_initlex(J, filename, source); | |
| 1045 jsP_next(J); | |
| 1046 J->astdepth = 0; | |
| 1047 p = script(J, 0); | |
| 1048 if (p) | |
| 1049 jsP_foldconst(p); | |
| 1050 | |
| 1051 return p; | |
| 1052 } | |
| 1053 | |
| 1054 js_Ast *jsP_parsefunction(js_State *J, const char *filename, const char *params, const char *body) | |
| 1055 { | |
| 1056 js_Ast *p = NULL; | |
| 1057 int line = 0; | |
| 1058 if (params) { | |
| 1059 jsY_initlex(J, filename, params); | |
| 1060 jsP_next(J); | |
| 1061 J->astdepth = 0; | |
| 1062 p = parameters(J); | |
| 1063 } | |
| 1064 return EXP3(FUN, NULL, p, jsP_parse(J, filename, body)); | |
| 1065 } |
