wineandroid: Use the user driver interface to create host desktops.
[wine.git] / dlls / jscript / lex.c
blob3bb2040803defe6b2c5a3a06c61770cb5fc73a6c
1 /*
2 * Copyright 2008 Jacek Caban for CodeWeavers
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.
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.
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
20 #include <limits.h>
21 #include <math.h>
23 #include "jscript.h"
24 #include "activscp.h"
25 #include "objsafe.h"
26 #include "engine.h"
27 #include "parser.h"
29 #include "parser.tab.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
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"const", kCONST},
45 {L"continue", kCONTINUE, TRUE},
46 {L"default", kDEFAULT},
47 {L"delete", kDELETE},
48 {L"do", kDO},
49 {L"else", kELSE},
50 {L"false", kFALSE},
51 {L"finally", kFINALLY},
52 {L"for", kFOR},
53 {L"function", kFUNCTION},
54 {L"get", kGET, FALSE, SCRIPTLANGUAGEVERSION_ES5},
55 {L"if", kIF},
56 {L"in", kIN},
57 {L"instanceof", kINSTANCEOF},
58 {L"let", kLET, FALSE, SCRIPTLANGUAGEVERSION_ES5},
59 {L"new", kNEW},
60 {L"null", kNULL},
61 {L"return", kRETURN, TRUE},
62 {L"set", kSET, FALSE, SCRIPTLANGUAGEVERSION_ES5},
63 {L"switch", kSWITCH},
64 {L"this", kTHIS},
65 {L"throw", kTHROW},
66 {L"true", kTRUE},
67 {L"try", kTRY},
68 {L"typeof", kTYPEOF},
69 {L"var", kVAR},
70 {L"void", kVOID},
71 {L"while", kWHILE},
72 {L"with", kWITH}
75 static int lex_error(parser_ctx_t *ctx, HRESULT hres)
77 ctx->hres = hres;
78 ctx->lexer_error = TRUE;
79 return -1;
82 /* ECMA-262 3rd Edition 7.6 */
83 BOOL is_identifier_char(WCHAR c)
85 return iswalnum(c) || c == '$' || c == '_' || c == '\\';
88 static BOOL is_identifier_first_char(WCHAR c)
90 return iswalpha(c) || c == '$' || c == '_' || c == '\\';
93 static int check_keyword(parser_ctx_t *ctx, const WCHAR *word, const WCHAR **lval)
95 const WCHAR *p1 = ctx->ptr;
96 const WCHAR *p2 = word;
98 while(p1 < ctx->end && *p2) {
99 if(*p1 != *p2)
100 return *p1 - *p2;
101 p1++;
102 p2++;
105 if(*p2 || (p1 < ctx->end && is_identifier_char(*p1)))
106 return 1;
108 if(lval)
109 *lval = word;
110 ctx->ptr = p1;
111 return 0;
114 /* ECMA-262 3rd Edition 7.3 */
115 static BOOL is_endline(WCHAR c)
117 return c == '\n' || c == '\r' || c == 0x2028 || c == 0x2029;
120 static int hex_to_int(WCHAR c)
122 if('0' <= c && c <= '9')
123 return c-'0';
125 if('a' <= c && c <= 'f')
126 return c-'a'+10;
128 if('A' <= c && c <= 'F')
129 return c-'A'+10;
131 return -1;
134 static int check_keywords(parser_ctx_t *ctx, const WCHAR **lval)
136 int min = 0, max = ARRAY_SIZE(keywords)-1, r, i;
138 while(min <= max) {
139 i = (min+max)/2;
141 r = check_keyword(ctx, keywords[i].word, lval);
142 if(!r) {
143 if(ctx->script->version < keywords[i].min_version) {
144 TRACE("ignoring keyword %s in incompatible mode\n",
145 debugstr_w(keywords[i].word));
146 ctx->ptr -= lstrlenW(keywords[i].word);
147 return 0;
149 ctx->implicit_nl_semicolon = keywords[i].no_nl;
150 return keywords[i].token;
153 if(r > 0)
154 min = i+1;
155 else
156 max = i-1;
159 return 0;
162 static BOOL skip_html_comment(parser_ctx_t *ctx)
164 if(!ctx->is_html || ctx->ptr+3 >= ctx->end ||
165 memcmp(ctx->ptr, L"<!--", sizeof(WCHAR)*4))
166 return FALSE;
168 ctx->nl = TRUE;
169 while(ctx->ptr < ctx->end && !is_endline(*ctx->ptr++));
171 return TRUE;
174 static BOOL skip_comment(parser_ctx_t *ctx)
176 if(ctx->ptr+1 >= ctx->end)
177 return FALSE;
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;
185 return FALSE;
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++;
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;
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;
214 return TRUE;
217 static BOOL skip_spaces(parser_ctx_t *ctx)
219 while(ctx->ptr < ctx->end && (iswspace(*ctx->ptr) || *ctx->ptr == 0xFEFF /* UTF16 BOM */)) {
220 if(is_endline(*ctx->ptr++))
221 ctx->nl = TRUE;
224 return ctx->ptr != ctx->end;
227 BOOL unescape(WCHAR *str, size_t *len)
229 WCHAR *pd, *p, c, *end = str + *len;
230 int i;
232 pd = p = str;
233 while(p < end) {
234 if(*p != '\\') {
235 *pd++ = *p++;
236 continue;
239 if(++p == end)
240 return FALSE;
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;
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;
284 i = hex_to_int(*++p);
285 if(i == -1)
286 return FALSE;
287 c += i << 8;
289 i = hex_to_int(*++p);
290 if(i == -1)
291 return FALSE;
292 c += i << 4;
294 i = hex_to_int(*++p);
295 if(i == -1)
296 return FALSE;
297 c += i;
298 break;
299 default:
300 if(is_digit(*p)) {
301 c = *p++ - '0';
302 if(p < end && is_digit(*p)) {
303 c = c*8 + (*p++ - '0');
304 if(p < end && is_digit(*p))
305 c = c*8 + (*p++ - '0');
307 p--;
309 else
310 c = *p;
313 *pd++ = c;
314 p++;
317 *len = pd - str;
318 return TRUE;
321 static int parse_identifier(parser_ctx_t *ctx, const WCHAR **ret)
323 const WCHAR *ptr = ctx->ptr++;
324 WCHAR *wstr;
325 int len;
327 while(ctx->ptr < ctx->end && is_identifier_char(*ctx->ptr))
328 ctx->ptr++;
330 len = ctx->ptr-ptr;
332 *ret = wstr = parser_alloc(ctx, (len+1)*sizeof(WCHAR));
333 memcpy(wstr, ptr, len*sizeof(WCHAR));
334 wstr[len] = 0;
336 /* FIXME: unescape */
337 return tIdentifier;
340 static int parse_string_literal(parser_ctx_t *ctx, jsstr_t **ret, WCHAR endch)
342 const WCHAR *ptr = ++ctx->ptr, *ret_str = ptr;
343 BOOL needs_unescape = FALSE;
344 WCHAR *unescape_str;
345 size_t len;
347 while(ctx->ptr < ctx->end && *ctx->ptr != endch) {
348 if(*ctx->ptr++ == '\\') {
349 ctx->ptr++;
350 needs_unescape = TRUE;
354 if(ctx->ptr == ctx->end)
355 return lex_error(ctx, JS_E_UNTERMINATED_STRING);
357 len = ctx->ptr - ptr;
358 ctx->ptr++;
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);
371 if(!(*ret = compiler_alloc_string_len(ctx->compiler, ret_str, len)))
372 return lex_error(ctx, E_OUTOFMEMORY);
374 /* FIXME: leaking string */
375 return tStringLiteral;
378 static literal_t *new_double_literal(parser_ctx_t *ctx, DOUBLE d)
380 literal_t *ret = parser_alloc(ctx, sizeof(literal_t));
382 ret->type = LT_DOUBLE;
383 ret->u.dval = d;
384 return ret;
387 literal_t *new_boolean_literal(parser_ctx_t *ctx, BOOL bval)
389 literal_t *ret = parser_alloc(ctx, sizeof(literal_t));
391 ret->type = LT_BOOL;
392 ret->u.bval = bval;
394 return ret;
397 HRESULT parse_decimal(const WCHAR **iter, const WCHAR *end, double *ret)
399 const WCHAR *ptr = *iter;
400 LONGLONG d = 0, hlp;
401 int exp = 0;
403 while(ptr < end && is_digit(*ptr)) {
404 hlp = d*10 + *(ptr++) - '0';
405 if(d>MAXLONGLONG/10 || hlp<0) {
406 exp++;
407 break;
409 else
410 d = hlp;
412 while(ptr < end && is_digit(*ptr)) {
413 exp++;
414 ptr++;
417 if(*ptr == '.') {
418 ptr++;
420 while(ptr < end && is_digit(*ptr)) {
421 hlp = d*10 + *(ptr++) - '0';
422 if(d>MAXLONGLONG/10 || hlp<0)
423 break;
425 d = hlp;
426 exp--;
428 while(ptr < end && is_digit(*ptr))
429 ptr++;
432 if(ptr < end && (*ptr == 'e' || *ptr == 'E')) {
433 int sign = 1, e = 0;
435 if(++ptr < end) {
436 if(*ptr == '+') {
437 ptr++;
438 }else if(*ptr == '-') {
439 sign = -1;
440 ptr++;
441 }else if(!is_digit(*ptr)) {
442 WARN("Expected exponent part\n");
443 return E_FAIL;
447 if(ptr == end) {
448 WARN("unexpected end of file\n");
449 return E_FAIL;
452 while(ptr < end && is_digit(*ptr)) {
453 if(e > INT_MAX/10 || (e = e*10 + *ptr++ - '0')<0)
454 e = INT_MAX;
456 e *= sign;
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;
463 if(is_identifier_char(*ptr)) {
464 WARN("wrong char after zero\n");
465 return JS_E_MISSING_SEMICOLON;
468 *ret = exp>=0 ? d*pow(10, exp) : d/pow(10, -exp);
469 *iter = ptr;
470 return S_OK;
473 static BOOL parse_numeric_literal(parser_ctx_t *ctx, double *ret)
475 HRESULT hres;
477 if(*ctx->ptr == '0') {
478 ctx->ptr++;
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;
488 while(ctx->ptr < ctx->end && (d = hex_to_int(*ctx->ptr)) != -1) {
489 r = r*16 + d;
490 ctx->ptr++;
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;
499 *ret = r;
500 return TRUE;
503 if(is_digit(*ctx->ptr)) {
504 unsigned base = 8;
505 const WCHAR *ptr;
506 double val = 0;
508 for(ptr = ctx->ptr; ptr < ctx->end && is_digit(*ptr); ptr++) {
509 if(*ptr > '7') {
510 base = 10;
511 break;
515 do {
516 val = val*base + *ctx->ptr-'0';
517 }while(++ctx->ptr < ctx->end && is_digit(*ctx->ptr));
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;
526 *ret = val;
527 return TRUE;
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;
537 hres = parse_decimal(&ctx->ptr, ctx->end, ret);
538 if(FAILED(hres)) {
539 lex_error(ctx, hres);
540 return FALSE;
543 return TRUE;
546 static int next_token(parser_ctx_t *ctx, unsigned *loc, void *lval)
548 do {
549 if(!skip_spaces(ctx)) {
550 *loc = ctx->ptr - ctx->begin;
551 return 0;
553 }while(skip_comment(ctx) || skip_html_comment(ctx));
554 *loc = ctx->ptr - ctx->begin;
556 if(ctx->implicit_nl_semicolon) {
557 if(ctx->nl)
558 return ';';
559 ctx->implicit_nl_semicolon = FALSE;
562 if(iswalpha(*ctx->ptr)) {
563 int ret = check_keywords(ctx, lval);
564 if(ret)
565 return ret;
567 return parse_identifier(ctx, lval);
570 if(is_digit(*ctx->ptr)) {
571 double n;
573 if(!parse_numeric_literal(ctx, &n))
574 return -1;
576 *(literal_t**)lval = new_double_literal(ctx, n);
577 return tNumericLiteral;
580 switch(*ctx->ptr) {
581 case '{':
582 case '}':
583 case '(':
584 case ')':
585 case '[':
586 case ']':
587 case ';':
588 case ',':
589 case '~':
590 case '?':
591 return *ctx->ptr++;
593 case '.':
594 if(ctx->ptr+1 < ctx->end && is_digit(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;
602 *(literal_t**)lval = new_double_literal(ctx, n);
603 return tNumericLiteral;
605 ctx->ptr++;
606 return '.';
608 case '<':
609 if(++ctx->ptr == ctx->end) {
610 *(int*)lval = EXPR_LESS;
611 return tRelOper;
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;
625 *(int*)lval = EXPR_LSHIFT;
626 return tShiftOper;
627 default: /* < */
628 *(int*)lval = EXPR_LESS;
629 return tRelOper;
632 case '>':
633 if(++ctx->ptr == ctx->end) { /* > */
634 *(int*)lval = EXPR_GREATER;
635 return tRelOper;
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;
650 if(*ctx->ptr == '>') { /* >>> */
651 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* >>>= */
652 ctx->ptr++;
653 *(int*)lval = EXPR_ASSIGNRRSHIFT;
654 return tAssignOper;
656 *(int*)lval = EXPR_RRSHIFT;
657 return tRelOper;
660 *(int*)lval = EXPR_RSHIFT;
661 return tShiftOper;
662 default:
663 *(int*)lval = EXPR_GREATER;
664 return tRelOper;
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;
680 return '+';
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;
692 return tDEC;
693 case '=': /* -= */
694 ctx->ptr++;
695 *(int*)lval = EXPR_ASSIGNSUB;
696 return tAssignOper;
699 return '-';
701 case '*':
702 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* *= */
703 ctx->ptr++;
704 *(int*)lval = EXPR_ASSIGNMUL;
705 return tAssignOper;
707 return '*';
709 case '%':
710 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* %= */
711 ctx->ptr++;
712 *(int*)lval = EXPR_ASSIGNMOD;
713 return tAssignOper;
715 return '%';
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;
729 return '&';
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;
743 return '|';
745 case '^':
746 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* ^= */
747 ctx->ptr++;
748 *(int*)lval = EXPR_ASSIGNXOR;
749 return tAssignOper;
751 return '^';
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;
760 *(int*)lval = EXPR_NOTEQ;
761 return tEqOper;
763 return '!';
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;
772 *(int*)lval = EXPR_EQ;
773 return tEqOper;
775 return '=';
777 case '/':
778 if(++ctx->ptr < ctx->end) {
779 if(*ctx->ptr == '=') { /* /= */
780 ctx->ptr++;
781 *(int*)lval = EXPR_ASSIGNDIV;
782 return kDIVEQ;
785 return '/';
787 case ':':
788 if(++ctx->ptr < ctx->end && *ctx->ptr == ':') {
789 ctx->ptr++;
790 return kDCOL;
792 return ':';
794 case '\"':
795 case '\'':
796 return parse_string_literal(ctx, lval, *ctx->ptr);
798 case '_':
799 case '$':
800 return parse_identifier(ctx, lval);
802 case '@':
803 return '@';
806 WARN("unexpected char '%c' %d\n", *ctx->ptr, *ctx->ptr);
807 return 0;
810 struct _cc_var_t {
811 ccval_t val;
812 struct _cc_var_t *next;
813 unsigned name_len;
814 WCHAR name[0];
817 void release_cc(cc_ctx_t *cc)
819 cc_var_t *iter, *next;
821 for(iter = cc->vars; iter; iter = next) {
822 next = iter->next;
823 free(iter);
826 free(cc);
829 static BOOL new_cc_var(cc_ctx_t *cc, const WCHAR *name, int len, ccval_t v)
831 cc_var_t *new_v;
833 if(len == -1)
834 len = lstrlenW(name);
836 new_v = malloc(sizeof(cc_var_t) + (len+1)*sizeof(WCHAR));
837 if(!new_v)
838 return FALSE;
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;
848 static cc_var_t *find_cc_var(cc_ctx_t *cc, const WCHAR *name, unsigned name_len)
850 cc_var_t *iter;
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;
857 return NULL;
860 static BOOL init_cc(parser_ctx_t *ctx)
862 cc_ctx_t *cc;
864 if(ctx->script->cc)
865 return TRUE;
867 cc = malloc(sizeof(cc_ctx_t));
868 if(!cc) {
869 lex_error(ctx, E_OUTOFMEMORY);
870 return FALSE;
873 cc->vars = NULL;
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;
885 ctx->script->cc = cc;
886 return TRUE;
889 static BOOL parse_cc_identifier(parser_ctx_t *ctx, const WCHAR **ret, unsigned *ret_len)
891 if(*ctx->ptr != '@') {
892 lex_error(ctx, JS_E_EXPECTED_AT);
893 return FALSE;
896 if(!is_identifier_first_char(*++ctx->ptr)) {
897 lex_error(ctx, JS_E_EXPECTED_IDENTIFIER);
898 return FALSE;
901 *ret = ctx->ptr;
902 while(++ctx->ptr < ctx->end && is_identifier_char(*ctx->ptr));
903 *ret_len = ctx->ptr - *ret;
904 return TRUE;
907 int try_parse_ccval(parser_ctx_t *ctx, ccval_t *r)
909 if(!skip_spaces(ctx))
910 return -1;
912 if(is_digit(*ctx->ptr)) {
913 double n;
915 if(!parse_numeric_literal(ctx, &n))
916 return -1;
918 *r = ccval_num(n);
919 return 1;
922 if(*ctx->ptr == '@') {
923 const WCHAR *ident;
924 unsigned ident_len;
925 cc_var_t *cc_var;
927 if(!parse_cc_identifier(ctx, &ident, &ident_len))
928 return -1;
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;
935 if(!check_keyword(ctx, L"true", NULL)) {
936 *r = ccval_bool(TRUE);
937 return 1;
940 if(!check_keyword(ctx, L"false", NULL)) {
941 *r = ccval_bool(FALSE);
942 return 1;
945 return 0;
948 static int skip_code(parser_ctx_t *ctx, BOOL exec_else)
950 int if_depth = 1;
951 const WCHAR *ptr;
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);
959 ctx->ptr = ptr+1;
961 if(!check_keyword(ctx, L"end", NULL)) {
962 if(--if_depth)
963 continue;
964 return 0;
967 if(exec_else && !check_keyword(ctx, L"elif", NULL)) {
968 if(if_depth > 1)
969 continue;
971 if(!skip_spaces(ctx) || *ctx->ptr != '(')
972 return lex_error(ctx, JS_E_MISSING_LBRACKET);
974 if(!parse_cc_expr(ctx))
975 return -1;
977 if(!get_ccbool(ctx->ccval))
978 continue; /* skip block of code */
980 /* continue parsing */
981 ctx->cc_if_depth++;
982 return 0;
985 if(exec_else && !check_keyword(ctx, L"else", NULL)) {
986 if(if_depth > 1)
987 continue;
989 /* parse else block */
990 ctx->cc_if_depth++;
991 return 0;
994 if(!check_keyword(ctx, L"if", NULL)) {
995 if_depth++;
996 continue;
999 ctx->ptr++;
1003 static int cc_token(parser_ctx_t *ctx, void *lval)
1005 unsigned id_len = 0;
1006 cc_var_t *var;
1008 ctx->ptr++;
1010 if(!check_keyword(ctx, L"cc_on", NULL))
1011 return init_cc(ctx) ? 0 : -1;
1013 if(!check_keyword(ctx, L"set", NULL)) {
1014 const WCHAR *ident;
1015 unsigned ident_len;
1016 cc_var_t *var;
1018 if(!init_cc(ctx))
1019 return -1;
1021 if(!skip_spaces(ctx))
1022 return lex_error(ctx, JS_E_EXPECTED_AT);
1024 if(!parse_cc_identifier(ctx, &ident, &ident_len))
1025 return -1;
1027 if(!skip_spaces(ctx) || *ctx->ptr != '=')
1028 return lex_error(ctx, JS_E_EXPECTED_ASSIGN);
1029 ctx->ptr++;
1031 if(!parse_cc_expr(ctx)) {
1032 WARN("parsing CC expression failed\n");
1033 return -1;
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);
1044 return 0;
1047 if(!check_keyword(ctx, L"if", NULL)) {
1048 if(!init_cc(ctx))
1049 return -1;
1051 if(!skip_spaces(ctx) || *ctx->ptr != '(')
1052 return lex_error(ctx, JS_E_MISSING_LBRACKET);
1054 if(!parse_cc_expr(ctx))
1055 return -1;
1057 if(get_ccbool(ctx->ccval)) {
1058 /* continue parsing block inside if */
1059 ctx->cc_if_depth++;
1060 return 0;
1063 return skip_code(ctx, TRUE);
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);
1070 return skip_code(ctx, FALSE);
1073 if(!check_keyword(ctx, L"end", NULL)) {
1074 if(!ctx->cc_if_depth)
1075 return lex_error(ctx, JS_E_SYNTAX);
1077 ctx->cc_if_depth--;
1078 return 0;
1081 if(!ctx->script->cc)
1082 return lex_error(ctx, JS_E_DISABLED_CC);
1084 while(ctx->ptr+id_len < ctx->end && is_identifier_char(ctx->ptr[id_len]))
1085 id_len++;
1086 if(!id_len)
1087 return '@';
1089 TRACE("var %s\n", debugstr_wn(ctx->ptr, id_len));
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;
1098 *(literal_t**)lval = new_boolean_literal(ctx, var->val.u.b);
1099 return tBooleanLiteral;
1102 int parser_lex(void *lval, unsigned *loc, parser_ctx_t *ctx)
1104 int ret;
1106 ctx->nl = ctx->ptr == ctx->begin;
1108 do {
1109 ret = next_token(ctx, loc, lval);
1110 } while(ret == '@' && !(ret = cc_token(ctx, lval)));
1112 return ret;
1115 literal_t *parse_regexp(parser_ctx_t *ctx)
1117 const WCHAR *re, *flags_ptr;
1118 BOOL in_class = FALSE;
1119 DWORD re_len, flags;
1120 literal_t *ret;
1122 TRACE("\n");
1124 while(*--ctx->ptr != '/');
1126 /* Simple regexp pre-parser; '/' if used in char class does not terminate regexp literal */
1127 re = ++ctx->ptr;
1128 while(ctx->ptr < ctx->end) {
1129 if(*ctx->ptr == '\\') {
1130 if(++ctx->ptr == ctx->end)
1131 break;
1132 }else if(in_class) {
1133 if(*ctx->ptr == '\n')
1134 break;
1135 if(*ctx->ptr == ']')
1136 in_class = FALSE;
1137 }else {
1138 if(*ctx->ptr == '/')
1139 break;
1141 if(*ctx->ptr == '[')
1142 in_class = TRUE;
1144 ctx->ptr++;
1147 if(ctx->ptr == ctx->end || *ctx->ptr != '/') {
1148 WARN("pre-parsing failed\n");
1149 ctx->hres = JS_E_SYNTAX;
1150 return NULL;
1153 re_len = ctx->ptr-re;
1155 flags_ptr = ++ctx->ptr;
1156 while(ctx->ptr < ctx->end && iswalnum(*ctx->ptr))
1157 ctx->ptr++;
1159 ctx->hres = parse_regexp_flags(flags_ptr, ctx->ptr-flags_ptr, &flags);
1160 if(FAILED(ctx->hres))
1161 return NULL;
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;