xref: /reactos/dll/win32/jscript/lex.c (revision 3e2d6582)
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