1 /* 2 * Copyright 2008 Jacek Caban for CodeWeavers 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 20 #include <limits.h> 21 #include <math.h> 22 23 #include "jscript.h" 24 #include "activscp.h" 25 #include "objsafe.h" 26 #include "engine.h" 27 #include "parser.h" 28 29 #include "parser.tab.h" 30 31 #include "wine/debug.h" 32 33 WINE_DEFAULT_DEBUG_CHANNEL(jscript); 34 35 static const struct { 36 const WCHAR *word; 37 int token; 38 BOOL no_nl; 39 unsigned min_version; 40 } keywords[] = { 41 {L"break", kBREAK, TRUE}, 42 {L"case", kCASE}, 43 {L"catch", kCATCH}, 44 {L"continue", kCONTINUE, TRUE}, 45 {L"default", kDEFAULT}, 46 {L"delete", kDELETE}, 47 {L"do", kDO}, 48 {L"else", kELSE}, 49 {L"false", kFALSE}, 50 {L"finally", kFINALLY}, 51 {L"for", kFOR}, 52 {L"function", kFUNCTION}, 53 {L"get", kGET, FALSE, SCRIPTLANGUAGEVERSION_ES5}, 54 {L"if", kIF}, 55 {L"in", kIN}, 56 {L"instanceof", kINSTANCEOF}, 57 {L"new", kNEW}, 58 {L"null", kNULL}, 59 {L"return", kRETURN, TRUE}, 60 {L"set", kSET, FALSE, SCRIPTLANGUAGEVERSION_ES5}, 61 {L"switch", kSWITCH}, 62 {L"this", kTHIS}, 63 {L"throw", kTHROW}, 64 {L"true", kTRUE}, 65 {L"try", kTRY}, 66 {L"typeof", kTYPEOF}, 67 {L"var", kVAR}, 68 {L"void", kVOID}, 69 {L"while", kWHILE}, 70 {L"with", kWITH} 71 }; 72 73 static int lex_error(parser_ctx_t *ctx, HRESULT hres) 74 { 75 ctx->hres = hres; 76 ctx->lexer_error = TRUE; 77 return -1; 78 } 79 80 /* ECMA-262 3rd Edition 7.6 */ 81 BOOL is_identifier_char(WCHAR c) 82 { 83 return iswalnum(c) || c == '$' || c == '_' || c == '\\'; 84 } 85 86 static BOOL is_identifier_first_char(WCHAR c) 87 { 88 return iswalpha(c) || c == '$' || c == '_' || c == '\\'; 89 } 90 91 static int check_keyword(parser_ctx_t *ctx, const WCHAR *word, const WCHAR **lval) 92 { 93 const WCHAR *p1 = ctx->ptr; 94 const WCHAR *p2 = word; 95 96 while(p1 < ctx->end && *p2) { 97 if(*p1 != *p2) 98 return *p1 - *p2; 99 p1++; 100 p2++; 101 } 102 103 if(*p2 || (p1 < ctx->end && is_identifier_char(*p1))) 104 return 1; 105 106 if(lval) 107 *lval = word; 108 ctx->ptr = p1; 109 return 0; 110 } 111 112 /* ECMA-262 3rd Edition 7.3 */ 113 static BOOL is_endline(WCHAR c) 114 { 115 return c == '\n' || c == '\r' || c == 0x2028 || c == 0x2029; 116 } 117 118 static int hex_to_int(WCHAR c) 119 { 120 if('0' <= c && c <= '9') 121 return c-'0'; 122 123 if('a' <= c && c <= 'f') 124 return c-'a'+10; 125 126 if('A' <= c && c <= 'F') 127 return c-'A'+10; 128 129 return -1; 130 } 131 132 static int check_keywords(parser_ctx_t *ctx, const WCHAR **lval) 133 { 134 int min = 0, max = ARRAY_SIZE(keywords)-1, r, i; 135 136 while(min <= max) { 137 i = (min+max)/2; 138 139 r = check_keyword(ctx, keywords[i].word, lval); 140 if(!r) { 141 if(ctx->script->version < keywords[i].min_version) { 142 TRACE("ignoring keyword %s in incompatible mode\n", 143 debugstr_w(keywords[i].word)); 144 ctx->ptr -= lstrlenW(keywords[i].word); 145 return 0; 146 } 147 ctx->implicit_nl_semicolon = keywords[i].no_nl; 148 return keywords[i].token; 149 } 150 151 if(r > 0) 152 min = i+1; 153 else 154 max = i-1; 155 } 156 157 return 0; 158 } 159 160 static BOOL skip_html_comment(parser_ctx_t *ctx) 161 { 162 const WCHAR html_commentW[] = {'<','!','-','-',0}; 163 164 if(!ctx->is_html || ctx->ptr+3 >= ctx->end || 165 memcmp(ctx->ptr, html_commentW, sizeof(WCHAR)*4)) 166 return FALSE; 167 168 ctx->nl = TRUE; 169 while(ctx->ptr < ctx->end && !is_endline(*ctx->ptr++)); 170 171 return TRUE; 172 } 173 174 static BOOL skip_comment(parser_ctx_t *ctx) 175 { 176 if(ctx->ptr+1 >= ctx->end) 177 return FALSE; 178 179 if(*ctx->ptr != '/') { 180 if(*ctx->ptr == '@' && ctx->ptr+2 < ctx->end && ctx->ptr[1] == '*' && ctx->ptr[2] == '/') { 181 ctx->ptr += 3; 182 return TRUE; 183 } 184 185 return FALSE; 186 } 187 188 switch(ctx->ptr[1]) { 189 case '*': 190 ctx->ptr += 2; 191 if(ctx->ptr+2 < ctx->end && *ctx->ptr == '@' && is_identifier_char(ctx->ptr[1])) 192 return FALSE; 193 while(ctx->ptr+1 < ctx->end && (ctx->ptr[0] != '*' || ctx->ptr[1] != '/')) 194 ctx->ptr++; 195 196 if(ctx->ptr[0] == '*' && ctx->ptr[1] == '/') { 197 ctx->ptr += 2; 198 }else { 199 WARN("unexpected end of file (missing end of comment)\n"); 200 ctx->ptr = ctx->end; 201 } 202 break; 203 case '/': 204 ctx->ptr += 2; 205 if(ctx->ptr+2 < ctx->end && *ctx->ptr == '@' && is_identifier_char(ctx->ptr[1])) 206 return FALSE; 207 while(ctx->ptr < ctx->end && !is_endline(*ctx->ptr)) 208 ctx->ptr++; 209 break; 210 default: 211 return FALSE; 212 } 213 214 return TRUE; 215 } 216 217 static BOOL skip_spaces(parser_ctx_t *ctx) 218 { 219 while(ctx->ptr < ctx->end && (iswspace(*ctx->ptr) || *ctx->ptr == 0xFEFF /* UTF16 BOM */)) { 220 if(is_endline(*ctx->ptr++)) 221 ctx->nl = TRUE; 222 } 223 224 return ctx->ptr != ctx->end; 225 } 226 227 BOOL unescape(WCHAR *str, size_t *len) 228 { 229 WCHAR *pd, *p, c, *end = str + *len; 230 int i; 231 232 pd = p = str; 233 while(p < end) { 234 if(*p != '\\') { 235 *pd++ = *p++; 236 continue; 237 } 238 239 if(++p == end) 240 return FALSE; 241 242 switch(*p) { 243 case '\'': 244 case '\"': 245 case '\\': 246 c = *p; 247 break; 248 case 'b': 249 c = '\b'; 250 break; 251 case 't': 252 c = '\t'; 253 break; 254 case 'n': 255 c = '\n'; 256 break; 257 case 'f': 258 c = '\f'; 259 break; 260 case 'r': 261 c = '\r'; 262 break; 263 case 'x': 264 if(p + 2 >= end) 265 return FALSE; 266 i = hex_to_int(*++p); 267 if(i == -1) 268 return FALSE; 269 c = i << 4; 270 271 i = hex_to_int(*++p); 272 if(i == -1) 273 return FALSE; 274 c += i; 275 break; 276 case 'u': 277 if(p + 4 >= end) 278 return FALSE; 279 i = hex_to_int(*++p); 280 if(i == -1) 281 return FALSE; 282 c = i << 12; 283 284 i = hex_to_int(*++p); 285 if(i == -1) 286 return FALSE; 287 c += i << 8; 288 289 i = hex_to_int(*++p); 290 if(i == -1) 291 return FALSE; 292 c += i << 4; 293 294 i = hex_to_int(*++p); 295 if(i == -1) 296 return FALSE; 297 c += i; 298 break; 299 default: 300 if(iswdigit(*p)) { 301 c = *p++ - '0'; 302 if(p < end && iswdigit(*p)) { 303 c = c*8 + (*p++ - '0'); 304 if(p < end && iswdigit(*p)) 305 c = c*8 + (*p++ - '0'); 306 } 307 p--; 308 } 309 else 310 c = *p; 311 } 312 313 *pd++ = c; 314 p++; 315 } 316 317 *len = pd - str; 318 return TRUE; 319 } 320 321 static int parse_identifier(parser_ctx_t *ctx, const WCHAR **ret) 322 { 323 const WCHAR *ptr = ctx->ptr++; 324 WCHAR *wstr; 325 int len; 326 327 while(ctx->ptr < ctx->end && is_identifier_char(*ctx->ptr)) 328 ctx->ptr++; 329 330 len = ctx->ptr-ptr; 331 332 *ret = wstr = parser_alloc(ctx, (len+1)*sizeof(WCHAR)); 333 memcpy(wstr, ptr, len*sizeof(WCHAR)); 334 wstr[len] = 0; 335 336 /* FIXME: unescape */ 337 return tIdentifier; 338 } 339 340 static int parse_string_literal(parser_ctx_t *ctx, jsstr_t **ret, WCHAR endch) 341 { 342 const WCHAR *ptr = ++ctx->ptr, *ret_str = ptr; 343 BOOL needs_unescape = FALSE; 344 WCHAR *unescape_str; 345 size_t len; 346 347 while(ctx->ptr < ctx->end && *ctx->ptr != endch) { 348 if(*ctx->ptr++ == '\\') { 349 ctx->ptr++; 350 needs_unescape = TRUE; 351 } 352 } 353 354 if(ctx->ptr == ctx->end) 355 return lex_error(ctx, JS_E_UNTERMINATED_STRING); 356 357 len = ctx->ptr - ptr; 358 ctx->ptr++; 359 360 if(needs_unescape) { 361 ret_str = unescape_str = parser_alloc(ctx, len * sizeof(WCHAR)); 362 if(!unescape_str) 363 return lex_error(ctx, E_OUTOFMEMORY); 364 memcpy(unescape_str, ptr, len * sizeof(WCHAR)); 365 if(!unescape(unescape_str, &len)) { 366 WARN("unescape failed\n"); 367 return lex_error(ctx, E_FAIL); 368 } 369 } 370 371 if(!(*ret = compiler_alloc_string_len(ctx->compiler, ret_str, len))) 372 return lex_error(ctx, E_OUTOFMEMORY); 373 374 /* FIXME: leaking string */ 375 return tStringLiteral; 376 } 377 378 static literal_t *new_double_literal(parser_ctx_t *ctx, DOUBLE d) 379 { 380 literal_t *ret = parser_alloc(ctx, sizeof(literal_t)); 381 382 ret->type = LT_DOUBLE; 383 ret->u.dval = d; 384 return ret; 385 } 386 387 literal_t *new_boolean_literal(parser_ctx_t *ctx, BOOL bval) 388 { 389 literal_t *ret = parser_alloc(ctx, sizeof(literal_t)); 390 391 ret->type = LT_BOOL; 392 ret->u.bval = bval; 393 394 return ret; 395 } 396 397 HRESULT parse_decimal(const WCHAR **iter, const WCHAR *end, double *ret) 398 { 399 const WCHAR *ptr = *iter; 400 LONGLONG d = 0, hlp; 401 int exp = 0; 402 403 while(ptr < end && iswdigit(*ptr)) { 404 hlp = d*10 + *(ptr++) - '0'; 405 if(d>MAXLONGLONG/10 || hlp<0) { 406 exp++; 407 break; 408 } 409 else 410 d = hlp; 411 } 412 while(ptr < end && iswdigit(*ptr)) { 413 exp++; 414 ptr++; 415 } 416 417 if(*ptr == '.') { 418 ptr++; 419 420 while(ptr < end && iswdigit(*ptr)) { 421 hlp = d*10 + *(ptr++) - '0'; 422 if(d>MAXLONGLONG/10 || hlp<0) 423 break; 424 425 d = hlp; 426 exp--; 427 } 428 while(ptr < end && iswdigit(*ptr)) 429 ptr++; 430 } 431 432 if(ptr < end && (*ptr == 'e' || *ptr == 'E')) { 433 int sign = 1, e = 0; 434 435 if(++ptr < end) { 436 if(*ptr == '+') { 437 ptr++; 438 }else if(*ptr == '-') { 439 sign = -1; 440 ptr++; 441 }else if(!iswdigit(*ptr)) { 442 WARN("Expected exponent part\n"); 443 return E_FAIL; 444 } 445 } 446 447 if(ptr == end) { 448 WARN("unexpected end of file\n"); 449 return E_FAIL; 450 } 451 452 while(ptr < end && iswdigit(*ptr)) { 453 if(e > INT_MAX/10 || (e = e*10 + *ptr++ - '0')<0) 454 e = INT_MAX; 455 } 456 e *= sign; 457 458 if(exp<0 && e<0 && e+exp>0) exp = INT_MIN; 459 else if(exp>0 && e>0 && e+exp<0) exp = INT_MAX; 460 else exp += e; 461 } 462 463 if(is_identifier_char(*ptr)) { 464 WARN("wrong char after zero\n"); 465 return JS_E_MISSING_SEMICOLON; 466 } 467 468 *ret = exp>=0 ? d*pow(10, exp) : d/pow(10, -exp); 469 *iter = ptr; 470 return S_OK; 471 } 472 473 static BOOL parse_numeric_literal(parser_ctx_t *ctx, double *ret) 474 { 475 HRESULT hres; 476 477 if(*ctx->ptr == '0') { 478 ctx->ptr++; 479 480 if(*ctx->ptr == 'x' || *ctx->ptr == 'X') { 481 double r = 0; 482 int d; 483 if(++ctx->ptr == ctx->end) { 484 ERR("unexpected end of file\n"); 485 return FALSE; 486 } 487 488 while(ctx->ptr < ctx->end && (d = hex_to_int(*ctx->ptr)) != -1) { 489 r = r*16 + d; 490 ctx->ptr++; 491 } 492 493 if(ctx->ptr < ctx->end && is_identifier_char(*ctx->ptr)) { 494 WARN("unexpected identifier char\n"); 495 lex_error(ctx, JS_E_MISSING_SEMICOLON); 496 return FALSE; 497 } 498 499 *ret = r; 500 return TRUE; 501 } 502 503 if(iswdigit(*ctx->ptr)) { 504 unsigned base = 8; 505 const WCHAR *ptr; 506 double val = 0; 507 508 for(ptr = ctx->ptr; ptr < ctx->end && iswdigit(*ptr); ptr++) { 509 if(*ptr > '7') { 510 base = 10; 511 break; 512 } 513 } 514 515 do { 516 val = val*base + *ctx->ptr-'0'; 517 }while(++ctx->ptr < ctx->end && iswdigit(*ctx->ptr)); 518 519 /* FIXME: Do we need it here? */ 520 if(ctx->ptr < ctx->end && (is_identifier_char(*ctx->ptr) || *ctx->ptr == '.')) { 521 WARN("wrong char after octal literal: '%c'\n", *ctx->ptr); 522 lex_error(ctx, JS_E_MISSING_SEMICOLON); 523 return FALSE; 524 } 525 526 *ret = val; 527 return TRUE; 528 } 529 530 if(is_identifier_char(*ctx->ptr)) { 531 WARN("wrong char after zero\n"); 532 lex_error(ctx, JS_E_MISSING_SEMICOLON); 533 return FALSE; 534 } 535 } 536 537 hres = parse_decimal(&ctx->ptr, ctx->end, ret); 538 if(FAILED(hres)) { 539 lex_error(ctx, hres); 540 return FALSE; 541 } 542 543 return TRUE; 544 } 545 546 static int next_token(parser_ctx_t *ctx, void *lval) 547 { 548 do { 549 if(!skip_spaces(ctx)) 550 return tEOF; 551 }while(skip_comment(ctx) || skip_html_comment(ctx)); 552 553 if(ctx->implicit_nl_semicolon) { 554 if(ctx->nl) 555 return ';'; 556 ctx->implicit_nl_semicolon = FALSE; 557 } 558 559 if(iswalpha(*ctx->ptr)) { 560 int ret = check_keywords(ctx, lval); 561 if(ret) 562 return ret; 563 564 return parse_identifier(ctx, lval); 565 } 566 567 if(iswdigit(*ctx->ptr)) { 568 double n; 569 570 if(!parse_numeric_literal(ctx, &n)) 571 return -1; 572 573 *(literal_t**)lval = new_double_literal(ctx, n); 574 return tNumericLiteral; 575 } 576 577 switch(*ctx->ptr) { 578 case '{': 579 case '(': 580 case ')': 581 case '[': 582 case ']': 583 case ';': 584 case ',': 585 case '~': 586 case '?': 587 return *ctx->ptr++; 588 589 case '}': 590 *(const WCHAR**)lval = ctx->ptr++; 591 return '}'; 592 593 case '.': 594 if(ctx->ptr+1 < ctx->end && iswdigit(ctx->ptr[1])) { 595 double n; 596 HRESULT hres; 597 hres = parse_decimal(&ctx->ptr, ctx->end, &n); 598 if(FAILED(hres)) { 599 lex_error(ctx, hres); 600 return -1; 601 } 602 *(literal_t**)lval = new_double_literal(ctx, n); 603 return tNumericLiteral; 604 } 605 ctx->ptr++; 606 return '.'; 607 608 case '<': 609 if(++ctx->ptr == ctx->end) { 610 *(int*)lval = EXPR_LESS; 611 return tRelOper; 612 } 613 614 switch(*ctx->ptr) { 615 case '=': /* <= */ 616 ctx->ptr++; 617 *(int*)lval = EXPR_LESSEQ; 618 return tRelOper; 619 case '<': /* << */ 620 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* <<= */ 621 ctx->ptr++; 622 *(int*)lval = EXPR_ASSIGNLSHIFT; 623 return tAssignOper; 624 } 625 *(int*)lval = EXPR_LSHIFT; 626 return tShiftOper; 627 default: /* < */ 628 *(int*)lval = EXPR_LESS; 629 return tRelOper; 630 } 631 632 case '>': 633 if(++ctx->ptr == ctx->end) { /* > */ 634 *(int*)lval = EXPR_GREATER; 635 return tRelOper; 636 } 637 638 switch(*ctx->ptr) { 639 case '=': /* >= */ 640 ctx->ptr++; 641 *(int*)lval = EXPR_GREATEREQ; 642 return tRelOper; 643 case '>': /* >> */ 644 if(++ctx->ptr < ctx->end) { 645 if(*ctx->ptr == '=') { /* >>= */ 646 ctx->ptr++; 647 *(int*)lval = EXPR_ASSIGNRSHIFT; 648 return tAssignOper; 649 } 650 if(*ctx->ptr == '>') { /* >>> */ 651 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* >>>= */ 652 ctx->ptr++; 653 *(int*)lval = EXPR_ASSIGNRRSHIFT; 654 return tAssignOper; 655 } 656 *(int*)lval = EXPR_RRSHIFT; 657 return tRelOper; 658 } 659 } 660 *(int*)lval = EXPR_RSHIFT; 661 return tShiftOper; 662 default: 663 *(int*)lval = EXPR_GREATER; 664 return tRelOper; 665 } 666 667 case '+': 668 ctx->ptr++; 669 if(ctx->ptr < ctx->end) { 670 switch(*ctx->ptr) { 671 case '+': /* ++ */ 672 ctx->ptr++; 673 return tINC; 674 case '=': /* += */ 675 ctx->ptr++; 676 *(int*)lval = EXPR_ASSIGNADD; 677 return tAssignOper; 678 } 679 } 680 return '+'; 681 682 case '-': 683 ctx->ptr++; 684 if(ctx->ptr < ctx->end) { 685 switch(*ctx->ptr) { 686 case '-': /* -- or --> */ 687 ctx->ptr++; 688 if(ctx->is_html && ctx->nl && ctx->ptr < ctx->end && *ctx->ptr == '>') { 689 ctx->ptr++; 690 return tHTMLCOMMENT; 691 } 692 return tDEC; 693 case '=': /* -= */ 694 ctx->ptr++; 695 *(int*)lval = EXPR_ASSIGNSUB; 696 return tAssignOper; 697 } 698 } 699 return '-'; 700 701 case '*': 702 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* *= */ 703 ctx->ptr++; 704 *(int*)lval = EXPR_ASSIGNMUL; 705 return tAssignOper; 706 } 707 return '*'; 708 709 case '%': 710 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* %= */ 711 ctx->ptr++; 712 *(int*)lval = EXPR_ASSIGNMOD; 713 return tAssignOper; 714 } 715 return '%'; 716 717 case '&': 718 if(++ctx->ptr < ctx->end) { 719 switch(*ctx->ptr) { 720 case '=': /* &= */ 721 ctx->ptr++; 722 *(int*)lval = EXPR_ASSIGNAND; 723 return tAssignOper; 724 case '&': /* && */ 725 ctx->ptr++; 726 return tANDAND; 727 } 728 } 729 return '&'; 730 731 case '|': 732 if(++ctx->ptr < ctx->end) { 733 switch(*ctx->ptr) { 734 case '=': /* |= */ 735 ctx->ptr++; 736 *(int*)lval = EXPR_ASSIGNOR; 737 return tAssignOper; 738 case '|': /* || */ 739 ctx->ptr++; 740 return tOROR; 741 } 742 } 743 return '|'; 744 745 case '^': 746 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* ^= */ 747 ctx->ptr++; 748 *(int*)lval = EXPR_ASSIGNXOR; 749 return tAssignOper; 750 } 751 return '^'; 752 753 case '!': 754 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* != */ 755 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* !== */ 756 ctx->ptr++; 757 *(int*)lval = EXPR_NOTEQEQ; 758 return tEqOper; 759 } 760 *(int*)lval = EXPR_NOTEQ; 761 return tEqOper; 762 } 763 return '!'; 764 765 case '=': 766 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* == */ 767 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* === */ 768 ctx->ptr++; 769 *(int*)lval = EXPR_EQEQ; 770 return tEqOper; 771 } 772 *(int*)lval = EXPR_EQ; 773 return tEqOper; 774 } 775 return '='; 776 777 case '/': 778 if(++ctx->ptr < ctx->end) { 779 if(*ctx->ptr == '=') { /* /= */ 780 ctx->ptr++; 781 *(int*)lval = EXPR_ASSIGNDIV; 782 return kDIVEQ; 783 } 784 } 785 return '/'; 786 787 case ':': 788 if(++ctx->ptr < ctx->end && *ctx->ptr == ':') { 789 ctx->ptr++; 790 return kDCOL; 791 } 792 return ':'; 793 794 case '\"': 795 case '\'': 796 return parse_string_literal(ctx, lval, *ctx->ptr); 797 798 case '_': 799 case '$': 800 return parse_identifier(ctx, lval); 801 802 case '@': 803 return '@'; 804 } 805 806 WARN("unexpected char '%c' %d\n", *ctx->ptr, *ctx->ptr); 807 return 0; 808 } 809 810 struct _cc_var_t { 811 ccval_t val; 812 struct _cc_var_t *next; 813 unsigned name_len; 814 WCHAR name[0]; 815 }; 816 817 void release_cc(cc_ctx_t *cc) 818 { 819 cc_var_t *iter, *next; 820 821 for(iter = cc->vars; iter; iter = next) { 822 next = iter->next; 823 heap_free(iter); 824 } 825 826 heap_free(cc); 827 } 828 829 static BOOL new_cc_var(cc_ctx_t *cc, const WCHAR *name, int len, ccval_t v) 830 { 831 cc_var_t *new_v; 832 833 if(len == -1) 834 len = lstrlenW(name); 835 836 new_v = heap_alloc(sizeof(cc_var_t) + (len+1)*sizeof(WCHAR)); 837 if(!new_v) 838 return FALSE; 839 840 new_v->val = v; 841 memcpy(new_v->name, name, (len+1)*sizeof(WCHAR)); 842 new_v->name_len = len; 843 new_v->next = cc->vars; 844 cc->vars = new_v; 845 return TRUE; 846 } 847 848 static cc_var_t *find_cc_var(cc_ctx_t *cc, const WCHAR *name, unsigned name_len) 849 { 850 cc_var_t *iter; 851 852 for(iter = cc->vars; iter; iter = iter->next) { 853 if(iter->name_len == name_len && !memcmp(iter->name, name, name_len*sizeof(WCHAR))) 854 return iter; 855 } 856 857 return NULL; 858 } 859 860 static BOOL init_cc(parser_ctx_t *ctx) 861 { 862 cc_ctx_t *cc; 863 864 if(ctx->script->cc) 865 return TRUE; 866 867 cc = heap_alloc(sizeof(cc_ctx_t)); 868 if(!cc) { 869 lex_error(ctx, E_OUTOFMEMORY); 870 return FALSE; 871 } 872 873 cc->vars = NULL; 874 875 if(!new_cc_var(cc, L"_jscript", -1, ccval_bool(TRUE)) 876 || !new_cc_var(cc, sizeof(void*) == 8 ? L"_win64" : L"_win32", -1, ccval_bool(TRUE)) 877 || !new_cc_var(cc, sizeof(void*) == 8 ? L"_amd64" : L"_x86", -1, ccval_bool(TRUE)) 878 || !new_cc_var(cc, L"_jscript_version", -1, ccval_num(JSCRIPT_MAJOR_VERSION + (DOUBLE)JSCRIPT_MINOR_VERSION/10.0)) 879 || !new_cc_var(cc, L"_jscript_build", -1, ccval_num(JSCRIPT_BUILD_VERSION))) { 880 release_cc(cc); 881 lex_error(ctx, E_OUTOFMEMORY); 882 return FALSE; 883 } 884 885 ctx->script->cc = cc; 886 return TRUE; 887 } 888 889 static BOOL parse_cc_identifier(parser_ctx_t *ctx, const WCHAR **ret, unsigned *ret_len) 890 { 891 if(*ctx->ptr != '@') { 892 lex_error(ctx, JS_E_EXPECTED_AT); 893 return FALSE; 894 } 895 896 if(!is_identifier_first_char(*++ctx->ptr)) { 897 lex_error(ctx, JS_E_EXPECTED_IDENTIFIER); 898 return FALSE; 899 } 900 901 *ret = ctx->ptr; 902 while(++ctx->ptr < ctx->end && is_identifier_char(*ctx->ptr)); 903 *ret_len = ctx->ptr - *ret; 904 return TRUE; 905 } 906 907 int try_parse_ccval(parser_ctx_t *ctx, ccval_t *r) 908 { 909 if(!skip_spaces(ctx)) 910 return -1; 911 912 if(iswdigit(*ctx->ptr)) { 913 double n; 914 915 if(!parse_numeric_literal(ctx, &n)) 916 return -1; 917 918 *r = ccval_num(n); 919 return 1; 920 } 921 922 if(*ctx->ptr == '@') { 923 const WCHAR *ident; 924 unsigned ident_len; 925 cc_var_t *cc_var; 926 927 if(!parse_cc_identifier(ctx, &ident, &ident_len)) 928 return -1; 929 930 cc_var = find_cc_var(ctx->script->cc, ident, ident_len); 931 *r = cc_var ? cc_var->val : ccval_num(NAN); 932 return 1; 933 } 934 935 if(!check_keyword(ctx, L"true", NULL)) { 936 *r = ccval_bool(TRUE); 937 return 1; 938 } 939 940 if(!check_keyword(ctx, L"false", NULL)) { 941 *r = ccval_bool(FALSE); 942 return 1; 943 } 944 945 return 0; 946 } 947 948 static int skip_code(parser_ctx_t *ctx, BOOL exec_else) 949 { 950 int if_depth = 1; 951 const WCHAR *ptr; 952 953 while(1) { 954 ptr = wcschr(ctx->ptr, '@'); 955 if(!ptr) { 956 WARN("No @end\n"); 957 return lex_error(ctx, JS_E_EXPECTED_CCEND); 958 } 959 ctx->ptr = ptr+1; 960 961 if(!check_keyword(ctx, L"end", NULL)) { 962 if(--if_depth) 963 continue; 964 return 0; 965 } 966 967 if(exec_else && !check_keyword(ctx, L"elif", NULL)) { 968 if(if_depth > 1) 969 continue; 970 971 if(!skip_spaces(ctx) || *ctx->ptr != '(') 972 return lex_error(ctx, JS_E_MISSING_LBRACKET); 973 974 if(!parse_cc_expr(ctx)) 975 return -1; 976 977 if(!get_ccbool(ctx->ccval)) 978 continue; /* skip block of code */ 979 980 /* continue parsing */ 981 ctx->cc_if_depth++; 982 return 0; 983 } 984 985 if(exec_else && !check_keyword(ctx, L"else", NULL)) { 986 if(if_depth > 1) 987 continue; 988 989 /* parse else block */ 990 ctx->cc_if_depth++; 991 return 0; 992 } 993 994 if(!check_keyword(ctx, L"if", NULL)) { 995 if_depth++; 996 continue; 997 } 998 999 ctx->ptr++; 1000 } 1001 } 1002 1003 static int cc_token(parser_ctx_t *ctx, void *lval) 1004 { 1005 unsigned id_len = 0; 1006 cc_var_t *var; 1007 1008 ctx->ptr++; 1009 1010 if(!check_keyword(ctx, L"cc_on", NULL)) 1011 return init_cc(ctx) ? 0 : -1; 1012 1013 if(!check_keyword(ctx, L"set", NULL)) { 1014 const WCHAR *ident; 1015 unsigned ident_len; 1016 cc_var_t *var; 1017 1018 if(!init_cc(ctx)) 1019 return -1; 1020 1021 if(!skip_spaces(ctx)) 1022 return lex_error(ctx, JS_E_EXPECTED_AT); 1023 1024 if(!parse_cc_identifier(ctx, &ident, &ident_len)) 1025 return -1; 1026 1027 if(!skip_spaces(ctx) || *ctx->ptr != '=') 1028 return lex_error(ctx, JS_E_EXPECTED_ASSIGN); 1029 ctx->ptr++; 1030 1031 if(!parse_cc_expr(ctx)) { 1032 WARN("parsing CC expression failed\n"); 1033 return -1; 1034 } 1035 1036 var = find_cc_var(ctx->script->cc, ident, ident_len); 1037 if(var) { 1038 var->val = ctx->ccval; 1039 }else { 1040 if(!new_cc_var(ctx->script->cc, ident, ident_len, ctx->ccval)) 1041 return lex_error(ctx, E_OUTOFMEMORY); 1042 } 1043 1044 return 0; 1045 } 1046 1047 if(!check_keyword(ctx, L"if", NULL)) { 1048 if(!init_cc(ctx)) 1049 return -1; 1050 1051 if(!skip_spaces(ctx) || *ctx->ptr != '(') 1052 return lex_error(ctx, JS_E_MISSING_LBRACKET); 1053 1054 if(!parse_cc_expr(ctx)) 1055 return -1; 1056 1057 if(get_ccbool(ctx->ccval)) { 1058 /* continue parsing block inside if */ 1059 ctx->cc_if_depth++; 1060 return 0; 1061 } 1062 1063 return skip_code(ctx, TRUE); 1064 } 1065 1066 if(!check_keyword(ctx, L"elif", NULL) || !check_keyword(ctx, L"else", NULL)) { 1067 if(!ctx->cc_if_depth) 1068 return lex_error(ctx, JS_E_SYNTAX); 1069 1070 return skip_code(ctx, FALSE); 1071 } 1072 1073 if(!check_keyword(ctx, L"end", NULL)) { 1074 if(!ctx->cc_if_depth) 1075 return lex_error(ctx, JS_E_SYNTAX); 1076 1077 ctx->cc_if_depth--; 1078 return 0; 1079 } 1080 1081 if(!ctx->script->cc) 1082 return lex_error(ctx, JS_E_DISABLED_CC); 1083 1084 while(ctx->ptr+id_len < ctx->end && is_identifier_char(ctx->ptr[id_len])) 1085 id_len++; 1086 if(!id_len) 1087 return '@'; 1088 1089 TRACE("var %s\n", debugstr_wn(ctx->ptr, id_len)); 1090 1091 var = find_cc_var(ctx->script->cc, ctx->ptr, id_len); 1092 ctx->ptr += id_len; 1093 if(!var || var->val.is_num) { 1094 *(literal_t**)lval = new_double_literal(ctx, var ? var->val.u.n : NAN); 1095 return tNumericLiteral; 1096 } 1097 1098 *(literal_t**)lval = new_boolean_literal(ctx, var->val.u.b); 1099 return tBooleanLiteral; 1100 } 1101 1102 int parser_lex(void *lval, parser_ctx_t *ctx) 1103 { 1104 int ret; 1105 1106 ctx->nl = ctx->ptr == ctx->begin; 1107 1108 do { 1109 ret = next_token(ctx, lval); 1110 } while(ret == '@' && !(ret = cc_token(ctx, lval))); 1111 1112 return ret; 1113 } 1114 1115 literal_t *parse_regexp(parser_ctx_t *ctx) 1116 { 1117 const WCHAR *re, *flags_ptr; 1118 BOOL in_class = FALSE; 1119 DWORD re_len, flags; 1120 literal_t *ret; 1121 HRESULT hres; 1122 1123 TRACE("\n"); 1124 1125 while(*--ctx->ptr != '/'); 1126 1127 /* Simple regexp pre-parser; '/' if used in char class does not terminate regexp literal */ 1128 re = ++ctx->ptr; 1129 while(ctx->ptr < ctx->end) { 1130 if(*ctx->ptr == '\\') { 1131 if(++ctx->ptr == ctx->end) 1132 break; 1133 }else if(in_class) { 1134 if(*ctx->ptr == '\n') 1135 break; 1136 if(*ctx->ptr == ']') 1137 in_class = FALSE; 1138 }else { 1139 if(*ctx->ptr == '/') 1140 break; 1141 1142 if(*ctx->ptr == '[') 1143 in_class = TRUE; 1144 } 1145 ctx->ptr++; 1146 } 1147 1148 if(ctx->ptr == ctx->end || *ctx->ptr != '/') { 1149 WARN("pre-parsing failed\n"); 1150 return NULL; 1151 } 1152 1153 re_len = ctx->ptr-re; 1154 1155 flags_ptr = ++ctx->ptr; 1156 while(ctx->ptr < ctx->end && iswalnum(*ctx->ptr)) 1157 ctx->ptr++; 1158 1159 hres = parse_regexp_flags(flags_ptr, ctx->ptr-flags_ptr, &flags); 1160 if(FAILED(hres)) 1161 return NULL; 1162 1163 ret = parser_alloc(ctx, sizeof(literal_t)); 1164 ret->type = LT_REGEXP; 1165 ret->u.regexp.str = compiler_alloc_string_len(ctx->compiler, re, re_len); 1166 ret->u.regexp.flags = flags; 1167 return ret; 1168 } 1169