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
lex_error(parser_ctx_t * ctx,HRESULT hres)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 */
is_identifier_char(WCHAR c)81 BOOL is_identifier_char(WCHAR c)
82 {
83 return iswalnum(c) || c == '$' || c == '_' || c == '\\';
84 }
85
is_identifier_first_char(WCHAR c)86 static BOOL is_identifier_first_char(WCHAR c)
87 {
88 return iswalpha(c) || c == '$' || c == '_' || c == '\\';
89 }
90
check_keyword(parser_ctx_t * ctx,const WCHAR * word,const WCHAR ** lval)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 */
is_endline(WCHAR c)113 static BOOL is_endline(WCHAR c)
114 {
115 return c == '\n' || c == '\r' || c == 0x2028 || c == 0x2029;
116 }
117
hex_to_int(WCHAR c)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
check_keywords(parser_ctx_t * ctx,const WCHAR ** lval)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
skip_html_comment(parser_ctx_t * ctx)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
skip_comment(parser_ctx_t * ctx)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
skip_spaces(parser_ctx_t * ctx)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
unescape(WCHAR * str,size_t * len)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
parse_identifier(parser_ctx_t * ctx,const WCHAR ** ret)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
parse_string_literal(parser_ctx_t * ctx,jsstr_t ** ret,WCHAR endch)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
new_double_literal(parser_ctx_t * ctx,DOUBLE d)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
new_boolean_literal(parser_ctx_t * ctx,BOOL bval)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
parse_decimal(const WCHAR ** iter,const WCHAR * end,double * ret)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
parse_numeric_literal(parser_ctx_t * ctx,double * ret)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
next_token(parser_ctx_t * ctx,void * lval)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
release_cc(cc_ctx_t * cc)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
new_cc_var(cc_ctx_t * cc,const WCHAR * name,int len,ccval_t v)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
find_cc_var(cc_ctx_t * cc,const WCHAR * name,unsigned name_len)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
init_cc(parser_ctx_t * ctx)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
parse_cc_identifier(parser_ctx_t * ctx,const WCHAR ** ret,unsigned * ret_len)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
try_parse_ccval(parser_ctx_t * ctx,ccval_t * r)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
skip_code(parser_ctx_t * ctx,BOOL exec_else)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
cc_token(parser_ctx_t * ctx,void * lval)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
parser_lex(void * lval,parser_ctx_t * ctx)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
parse_regexp(parser_ctx_t * ctx)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