wined3d: Pass a wined3d_device_context to wined3d_cs_emit_blt_sub_resource().
[wine/zf.git] / dlls / jscript / lex.c
blobefed1038a95a09533c41085f530b1159bbe91415
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"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}
73 static int lex_error(parser_ctx_t *ctx, HRESULT hres)
75 ctx->hres = hres;
76 ctx->lexer_error = TRUE;
77 return -1;
80 /* ECMA-262 3rd Edition 7.6 */
81 BOOL is_identifier_char(WCHAR c)
83 return iswalnum(c) || c == '$' || c == '_' || c == '\\';
86 static BOOL is_identifier_first_char(WCHAR c)
88 return iswalpha(c) || c == '$' || c == '_' || c == '\\';
91 static int check_keyword(parser_ctx_t *ctx, const WCHAR *word, const WCHAR **lval)
93 const WCHAR *p1 = ctx->ptr;
94 const WCHAR *p2 = word;
96 while(p1 < ctx->end && *p2) {
97 if(*p1 != *p2)
98 return *p1 - *p2;
99 p1++;
100 p2++;
103 if(*p2 || (p1 < ctx->end && is_identifier_char(*p1)))
104 return 1;
106 if(lval)
107 *lval = word;
108 ctx->ptr = p1;
109 return 0;
112 /* ECMA-262 3rd Edition 7.3 */
113 static BOOL is_endline(WCHAR c)
115 return c == '\n' || c == '\r' || c == 0x2028 || c == 0x2029;
118 static int hex_to_int(WCHAR c)
120 if('0' <= c && c <= '9')
121 return c-'0';
123 if('a' <= c && c <= 'f')
124 return c-'a'+10;
126 if('A' <= c && c <= 'F')
127 return c-'A'+10;
129 return -1;
132 static int check_keywords(parser_ctx_t *ctx, const WCHAR **lval)
134 int min = 0, max = ARRAY_SIZE(keywords)-1, r, i;
136 while(min <= max) {
137 i = (min+max)/2;
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;
147 ctx->implicit_nl_semicolon = keywords[i].no_nl;
148 return keywords[i].token;
151 if(r > 0)
152 min = i+1;
153 else
154 max = i-1;
157 return 0;
160 static BOOL skip_html_comment(parser_ctx_t *ctx)
162 if(!ctx->is_html || ctx->ptr+3 >= ctx->end ||
163 memcmp(ctx->ptr, L"<!--", sizeof(WCHAR)*4))
164 return FALSE;
166 ctx->nl = TRUE;
167 while(ctx->ptr < ctx->end && !is_endline(*ctx->ptr++));
169 return TRUE;
172 static BOOL skip_comment(parser_ctx_t *ctx)
174 if(ctx->ptr+1 >= ctx->end)
175 return FALSE;
177 if(*ctx->ptr != '/') {
178 if(*ctx->ptr == '@' && ctx->ptr+2 < ctx->end && ctx->ptr[1] == '*' && ctx->ptr[2] == '/') {
179 ctx->ptr += 3;
180 return TRUE;
183 return FALSE;
186 switch(ctx->ptr[1]) {
187 case '*':
188 ctx->ptr += 2;
189 if(ctx->ptr+2 < ctx->end && *ctx->ptr == '@' && is_identifier_char(ctx->ptr[1]))
190 return FALSE;
191 while(ctx->ptr+1 < ctx->end && (ctx->ptr[0] != '*' || ctx->ptr[1] != '/'))
192 ctx->ptr++;
194 if(ctx->ptr[0] == '*' && ctx->ptr[1] == '/') {
195 ctx->ptr += 2;
196 }else {
197 WARN("unexpected end of file (missing end of comment)\n");
198 ctx->ptr = ctx->end;
200 break;
201 case '/':
202 ctx->ptr += 2;
203 if(ctx->ptr+2 < ctx->end && *ctx->ptr == '@' && is_identifier_char(ctx->ptr[1]))
204 return FALSE;
205 while(ctx->ptr < ctx->end && !is_endline(*ctx->ptr))
206 ctx->ptr++;
207 break;
208 default:
209 return FALSE;
212 return TRUE;
215 static BOOL skip_spaces(parser_ctx_t *ctx)
217 while(ctx->ptr < ctx->end && (iswspace(*ctx->ptr) || *ctx->ptr == 0xFEFF /* UTF16 BOM */)) {
218 if(is_endline(*ctx->ptr++))
219 ctx->nl = TRUE;
222 return ctx->ptr != ctx->end;
225 BOOL unescape(WCHAR *str, size_t *len)
227 WCHAR *pd, *p, c, *end = str + *len;
228 int i;
230 pd = p = str;
231 while(p < end) {
232 if(*p != '\\') {
233 *pd++ = *p++;
234 continue;
237 if(++p == end)
238 return FALSE;
240 switch(*p) {
241 case '\'':
242 case '\"':
243 case '\\':
244 c = *p;
245 break;
246 case 'b':
247 c = '\b';
248 break;
249 case 't':
250 c = '\t';
251 break;
252 case 'n':
253 c = '\n';
254 break;
255 case 'f':
256 c = '\f';
257 break;
258 case 'r':
259 c = '\r';
260 break;
261 case 'x':
262 if(p + 2 >= end)
263 return FALSE;
264 i = hex_to_int(*++p);
265 if(i == -1)
266 return FALSE;
267 c = i << 4;
269 i = hex_to_int(*++p);
270 if(i == -1)
271 return FALSE;
272 c += i;
273 break;
274 case 'u':
275 if(p + 4 >= end)
276 return FALSE;
277 i = hex_to_int(*++p);
278 if(i == -1)
279 return FALSE;
280 c = i << 12;
282 i = hex_to_int(*++p);
283 if(i == -1)
284 return FALSE;
285 c += i << 8;
287 i = hex_to_int(*++p);
288 if(i == -1)
289 return FALSE;
290 c += i << 4;
292 i = hex_to_int(*++p);
293 if(i == -1)
294 return FALSE;
295 c += i;
296 break;
297 default:
298 if(is_digit(*p)) {
299 c = *p++ - '0';
300 if(p < end && is_digit(*p)) {
301 c = c*8 + (*p++ - '0');
302 if(p < end && is_digit(*p))
303 c = c*8 + (*p++ - '0');
305 p--;
307 else
308 c = *p;
311 *pd++ = c;
312 p++;
315 *len = pd - str;
316 return TRUE;
319 static int parse_identifier(parser_ctx_t *ctx, const WCHAR **ret)
321 const WCHAR *ptr = ctx->ptr++;
322 WCHAR *wstr;
323 int len;
325 while(ctx->ptr < ctx->end && is_identifier_char(*ctx->ptr))
326 ctx->ptr++;
328 len = ctx->ptr-ptr;
330 *ret = wstr = parser_alloc(ctx, (len+1)*sizeof(WCHAR));
331 memcpy(wstr, ptr, len*sizeof(WCHAR));
332 wstr[len] = 0;
334 /* FIXME: unescape */
335 return tIdentifier;
338 static int parse_string_literal(parser_ctx_t *ctx, jsstr_t **ret, WCHAR endch)
340 const WCHAR *ptr = ++ctx->ptr, *ret_str = ptr;
341 BOOL needs_unescape = FALSE;
342 WCHAR *unescape_str;
343 size_t len;
345 while(ctx->ptr < ctx->end && *ctx->ptr != endch) {
346 if(*ctx->ptr++ == '\\') {
347 ctx->ptr++;
348 needs_unescape = TRUE;
352 if(ctx->ptr == ctx->end)
353 return lex_error(ctx, JS_E_UNTERMINATED_STRING);
355 len = ctx->ptr - ptr;
356 ctx->ptr++;
358 if(needs_unescape) {
359 ret_str = unescape_str = parser_alloc(ctx, len * sizeof(WCHAR));
360 if(!unescape_str)
361 return lex_error(ctx, E_OUTOFMEMORY);
362 memcpy(unescape_str, ptr, len * sizeof(WCHAR));
363 if(!unescape(unescape_str, &len)) {
364 WARN("unescape failed\n");
365 return lex_error(ctx, E_FAIL);
369 if(!(*ret = compiler_alloc_string_len(ctx->compiler, ret_str, len)))
370 return lex_error(ctx, E_OUTOFMEMORY);
372 /* FIXME: leaking string */
373 return tStringLiteral;
376 static literal_t *new_double_literal(parser_ctx_t *ctx, DOUBLE d)
378 literal_t *ret = parser_alloc(ctx, sizeof(literal_t));
380 ret->type = LT_DOUBLE;
381 ret->u.dval = d;
382 return ret;
385 literal_t *new_boolean_literal(parser_ctx_t *ctx, BOOL bval)
387 literal_t *ret = parser_alloc(ctx, sizeof(literal_t));
389 ret->type = LT_BOOL;
390 ret->u.bval = bval;
392 return ret;
395 HRESULT parse_decimal(const WCHAR **iter, const WCHAR *end, double *ret)
397 const WCHAR *ptr = *iter;
398 LONGLONG d = 0, hlp;
399 int exp = 0;
401 while(ptr < end && is_digit(*ptr)) {
402 hlp = d*10 + *(ptr++) - '0';
403 if(d>MAXLONGLONG/10 || hlp<0) {
404 exp++;
405 break;
407 else
408 d = hlp;
410 while(ptr < end && is_digit(*ptr)) {
411 exp++;
412 ptr++;
415 if(*ptr == '.') {
416 ptr++;
418 while(ptr < end && is_digit(*ptr)) {
419 hlp = d*10 + *(ptr++) - '0';
420 if(d>MAXLONGLONG/10 || hlp<0)
421 break;
423 d = hlp;
424 exp--;
426 while(ptr < end && is_digit(*ptr))
427 ptr++;
430 if(ptr < end && (*ptr == 'e' || *ptr == 'E')) {
431 int sign = 1, e = 0;
433 if(++ptr < end) {
434 if(*ptr == '+') {
435 ptr++;
436 }else if(*ptr == '-') {
437 sign = -1;
438 ptr++;
439 }else if(!is_digit(*ptr)) {
440 WARN("Expected exponent part\n");
441 return E_FAIL;
445 if(ptr == end) {
446 WARN("unexpected end of file\n");
447 return E_FAIL;
450 while(ptr < end && is_digit(*ptr)) {
451 if(e > INT_MAX/10 || (e = e*10 + *ptr++ - '0')<0)
452 e = INT_MAX;
454 e *= sign;
456 if(exp<0 && e<0 && e+exp>0) exp = INT_MIN;
457 else if(exp>0 && e>0 && e+exp<0) exp = INT_MAX;
458 else exp += e;
461 if(is_identifier_char(*ptr)) {
462 WARN("wrong char after zero\n");
463 return JS_E_MISSING_SEMICOLON;
466 *ret = exp>=0 ? d*pow(10, exp) : d/pow(10, -exp);
467 *iter = ptr;
468 return S_OK;
471 static BOOL parse_numeric_literal(parser_ctx_t *ctx, double *ret)
473 HRESULT hres;
475 if(*ctx->ptr == '0') {
476 ctx->ptr++;
478 if(*ctx->ptr == 'x' || *ctx->ptr == 'X') {
479 double r = 0;
480 int d;
481 if(++ctx->ptr == ctx->end) {
482 ERR("unexpected end of file\n");
483 return FALSE;
486 while(ctx->ptr < ctx->end && (d = hex_to_int(*ctx->ptr)) != -1) {
487 r = r*16 + d;
488 ctx->ptr++;
491 if(ctx->ptr < ctx->end && is_identifier_char(*ctx->ptr)) {
492 WARN("unexpected identifier char\n");
493 lex_error(ctx, JS_E_MISSING_SEMICOLON);
494 return FALSE;
497 *ret = r;
498 return TRUE;
501 if(is_digit(*ctx->ptr)) {
502 unsigned base = 8;
503 const WCHAR *ptr;
504 double val = 0;
506 for(ptr = ctx->ptr; ptr < ctx->end && is_digit(*ptr); ptr++) {
507 if(*ptr > '7') {
508 base = 10;
509 break;
513 do {
514 val = val*base + *ctx->ptr-'0';
515 }while(++ctx->ptr < ctx->end && is_digit(*ctx->ptr));
517 /* FIXME: Do we need it here? */
518 if(ctx->ptr < ctx->end && (is_identifier_char(*ctx->ptr) || *ctx->ptr == '.')) {
519 WARN("wrong char after octal literal: '%c'\n", *ctx->ptr);
520 lex_error(ctx, JS_E_MISSING_SEMICOLON);
521 return FALSE;
524 *ret = val;
525 return TRUE;
528 if(is_identifier_char(*ctx->ptr)) {
529 WARN("wrong char after zero\n");
530 lex_error(ctx, JS_E_MISSING_SEMICOLON);
531 return FALSE;
535 hres = parse_decimal(&ctx->ptr, ctx->end, ret);
536 if(FAILED(hres)) {
537 lex_error(ctx, hres);
538 return FALSE;
541 return TRUE;
544 static int next_token(parser_ctx_t *ctx, unsigned *loc, void *lval)
546 do {
547 if(!skip_spaces(ctx)) {
548 *loc = ctx->ptr - ctx->begin;
549 return 0;
551 }while(skip_comment(ctx) || skip_html_comment(ctx));
552 *loc = ctx->ptr - ctx->begin;
554 if(ctx->implicit_nl_semicolon) {
555 if(ctx->nl)
556 return ';';
557 ctx->implicit_nl_semicolon = FALSE;
560 if(iswalpha(*ctx->ptr)) {
561 int ret = check_keywords(ctx, lval);
562 if(ret)
563 return ret;
565 return parse_identifier(ctx, lval);
568 if(is_digit(*ctx->ptr)) {
569 double n;
571 if(!parse_numeric_literal(ctx, &n))
572 return -1;
574 *(literal_t**)lval = new_double_literal(ctx, n);
575 return tNumericLiteral;
578 switch(*ctx->ptr) {
579 case '{':
580 case '}':
581 case '(':
582 case ')':
583 case '[':
584 case ']':
585 case ';':
586 case ',':
587 case '~':
588 case '?':
589 return *ctx->ptr++;
591 case '.':
592 if(ctx->ptr+1 < ctx->end && is_digit(ctx->ptr[1])) {
593 double n;
594 HRESULT hres;
595 hres = parse_decimal(&ctx->ptr, ctx->end, &n);
596 if(FAILED(hres)) {
597 lex_error(ctx, hres);
598 return -1;
600 *(literal_t**)lval = new_double_literal(ctx, n);
601 return tNumericLiteral;
603 ctx->ptr++;
604 return '.';
606 case '<':
607 if(++ctx->ptr == ctx->end) {
608 *(int*)lval = EXPR_LESS;
609 return tRelOper;
612 switch(*ctx->ptr) {
613 case '=': /* <= */
614 ctx->ptr++;
615 *(int*)lval = EXPR_LESSEQ;
616 return tRelOper;
617 case '<': /* << */
618 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* <<= */
619 ctx->ptr++;
620 *(int*)lval = EXPR_ASSIGNLSHIFT;
621 return tAssignOper;
623 *(int*)lval = EXPR_LSHIFT;
624 return tShiftOper;
625 default: /* < */
626 *(int*)lval = EXPR_LESS;
627 return tRelOper;
630 case '>':
631 if(++ctx->ptr == ctx->end) { /* > */
632 *(int*)lval = EXPR_GREATER;
633 return tRelOper;
636 switch(*ctx->ptr) {
637 case '=': /* >= */
638 ctx->ptr++;
639 *(int*)lval = EXPR_GREATEREQ;
640 return tRelOper;
641 case '>': /* >> */
642 if(++ctx->ptr < ctx->end) {
643 if(*ctx->ptr == '=') { /* >>= */
644 ctx->ptr++;
645 *(int*)lval = EXPR_ASSIGNRSHIFT;
646 return tAssignOper;
648 if(*ctx->ptr == '>') { /* >>> */
649 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* >>>= */
650 ctx->ptr++;
651 *(int*)lval = EXPR_ASSIGNRRSHIFT;
652 return tAssignOper;
654 *(int*)lval = EXPR_RRSHIFT;
655 return tRelOper;
658 *(int*)lval = EXPR_RSHIFT;
659 return tShiftOper;
660 default:
661 *(int*)lval = EXPR_GREATER;
662 return tRelOper;
665 case '+':
666 ctx->ptr++;
667 if(ctx->ptr < ctx->end) {
668 switch(*ctx->ptr) {
669 case '+': /* ++ */
670 ctx->ptr++;
671 return tINC;
672 case '=': /* += */
673 ctx->ptr++;
674 *(int*)lval = EXPR_ASSIGNADD;
675 return tAssignOper;
678 return '+';
680 case '-':
681 ctx->ptr++;
682 if(ctx->ptr < ctx->end) {
683 switch(*ctx->ptr) {
684 case '-': /* -- or --> */
685 ctx->ptr++;
686 if(ctx->is_html && ctx->nl && ctx->ptr < ctx->end && *ctx->ptr == '>') {
687 ctx->ptr++;
688 return tHTMLCOMMENT;
690 return tDEC;
691 case '=': /* -= */
692 ctx->ptr++;
693 *(int*)lval = EXPR_ASSIGNSUB;
694 return tAssignOper;
697 return '-';
699 case '*':
700 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* *= */
701 ctx->ptr++;
702 *(int*)lval = EXPR_ASSIGNMUL;
703 return tAssignOper;
705 return '*';
707 case '%':
708 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* %= */
709 ctx->ptr++;
710 *(int*)lval = EXPR_ASSIGNMOD;
711 return tAssignOper;
713 return '%';
715 case '&':
716 if(++ctx->ptr < ctx->end) {
717 switch(*ctx->ptr) {
718 case '=': /* &= */
719 ctx->ptr++;
720 *(int*)lval = EXPR_ASSIGNAND;
721 return tAssignOper;
722 case '&': /* && */
723 ctx->ptr++;
724 return tANDAND;
727 return '&';
729 case '|':
730 if(++ctx->ptr < ctx->end) {
731 switch(*ctx->ptr) {
732 case '=': /* |= */
733 ctx->ptr++;
734 *(int*)lval = EXPR_ASSIGNOR;
735 return tAssignOper;
736 case '|': /* || */
737 ctx->ptr++;
738 return tOROR;
741 return '|';
743 case '^':
744 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* ^= */
745 ctx->ptr++;
746 *(int*)lval = EXPR_ASSIGNXOR;
747 return tAssignOper;
749 return '^';
751 case '!':
752 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* != */
753 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* !== */
754 ctx->ptr++;
755 *(int*)lval = EXPR_NOTEQEQ;
756 return tEqOper;
758 *(int*)lval = EXPR_NOTEQ;
759 return tEqOper;
761 return '!';
763 case '=':
764 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* == */
765 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* === */
766 ctx->ptr++;
767 *(int*)lval = EXPR_EQEQ;
768 return tEqOper;
770 *(int*)lval = EXPR_EQ;
771 return tEqOper;
773 return '=';
775 case '/':
776 if(++ctx->ptr < ctx->end) {
777 if(*ctx->ptr == '=') { /* /= */
778 ctx->ptr++;
779 *(int*)lval = EXPR_ASSIGNDIV;
780 return kDIVEQ;
783 return '/';
785 case ':':
786 if(++ctx->ptr < ctx->end && *ctx->ptr == ':') {
787 ctx->ptr++;
788 return kDCOL;
790 return ':';
792 case '\"':
793 case '\'':
794 return parse_string_literal(ctx, lval, *ctx->ptr);
796 case '_':
797 case '$':
798 return parse_identifier(ctx, lval);
800 case '@':
801 return '@';
804 WARN("unexpected char '%c' %d\n", *ctx->ptr, *ctx->ptr);
805 return 0;
808 struct _cc_var_t {
809 ccval_t val;
810 struct _cc_var_t *next;
811 unsigned name_len;
812 WCHAR name[0];
815 void release_cc(cc_ctx_t *cc)
817 cc_var_t *iter, *next;
819 for(iter = cc->vars; iter; iter = next) {
820 next = iter->next;
821 heap_free(iter);
824 heap_free(cc);
827 static BOOL new_cc_var(cc_ctx_t *cc, const WCHAR *name, int len, ccval_t v)
829 cc_var_t *new_v;
831 if(len == -1)
832 len = lstrlenW(name);
834 new_v = heap_alloc(sizeof(cc_var_t) + (len+1)*sizeof(WCHAR));
835 if(!new_v)
836 return FALSE;
838 new_v->val = v;
839 memcpy(new_v->name, name, (len+1)*sizeof(WCHAR));
840 new_v->name_len = len;
841 new_v->next = cc->vars;
842 cc->vars = new_v;
843 return TRUE;
846 static cc_var_t *find_cc_var(cc_ctx_t *cc, const WCHAR *name, unsigned name_len)
848 cc_var_t *iter;
850 for(iter = cc->vars; iter; iter = iter->next) {
851 if(iter->name_len == name_len && !memcmp(iter->name, name, name_len*sizeof(WCHAR)))
852 return iter;
855 return NULL;
858 static BOOL init_cc(parser_ctx_t *ctx)
860 cc_ctx_t *cc;
862 if(ctx->script->cc)
863 return TRUE;
865 cc = heap_alloc(sizeof(cc_ctx_t));
866 if(!cc) {
867 lex_error(ctx, E_OUTOFMEMORY);
868 return FALSE;
871 cc->vars = NULL;
873 if(!new_cc_var(cc, L"_jscript", -1, ccval_bool(TRUE))
874 || !new_cc_var(cc, sizeof(void*) == 8 ? L"_win64" : L"_win32", -1, ccval_bool(TRUE))
875 || !new_cc_var(cc, sizeof(void*) == 8 ? L"_amd64" : L"_x86", -1, ccval_bool(TRUE))
876 || !new_cc_var(cc, L"_jscript_version", -1, ccval_num(JSCRIPT_MAJOR_VERSION + (DOUBLE)JSCRIPT_MINOR_VERSION/10.0))
877 || !new_cc_var(cc, L"_jscript_build", -1, ccval_num(JSCRIPT_BUILD_VERSION))) {
878 release_cc(cc);
879 lex_error(ctx, E_OUTOFMEMORY);
880 return FALSE;
883 ctx->script->cc = cc;
884 return TRUE;
887 static BOOL parse_cc_identifier(parser_ctx_t *ctx, const WCHAR **ret, unsigned *ret_len)
889 if(*ctx->ptr != '@') {
890 lex_error(ctx, JS_E_EXPECTED_AT);
891 return FALSE;
894 if(!is_identifier_first_char(*++ctx->ptr)) {
895 lex_error(ctx, JS_E_EXPECTED_IDENTIFIER);
896 return FALSE;
899 *ret = ctx->ptr;
900 while(++ctx->ptr < ctx->end && is_identifier_char(*ctx->ptr));
901 *ret_len = ctx->ptr - *ret;
902 return TRUE;
905 int try_parse_ccval(parser_ctx_t *ctx, ccval_t *r)
907 if(!skip_spaces(ctx))
908 return -1;
910 if(is_digit(*ctx->ptr)) {
911 double n;
913 if(!parse_numeric_literal(ctx, &n))
914 return -1;
916 *r = ccval_num(n);
917 return 1;
920 if(*ctx->ptr == '@') {
921 const WCHAR *ident;
922 unsigned ident_len;
923 cc_var_t *cc_var;
925 if(!parse_cc_identifier(ctx, &ident, &ident_len))
926 return -1;
928 cc_var = find_cc_var(ctx->script->cc, ident, ident_len);
929 *r = cc_var ? cc_var->val : ccval_num(NAN);
930 return 1;
933 if(!check_keyword(ctx, L"true", NULL)) {
934 *r = ccval_bool(TRUE);
935 return 1;
938 if(!check_keyword(ctx, L"false", NULL)) {
939 *r = ccval_bool(FALSE);
940 return 1;
943 return 0;
946 static int skip_code(parser_ctx_t *ctx, BOOL exec_else)
948 int if_depth = 1;
949 const WCHAR *ptr;
951 while(1) {
952 ptr = wcschr(ctx->ptr, '@');
953 if(!ptr) {
954 WARN("No @end\n");
955 return lex_error(ctx, JS_E_EXPECTED_CCEND);
957 ctx->ptr = ptr+1;
959 if(!check_keyword(ctx, L"end", NULL)) {
960 if(--if_depth)
961 continue;
962 return 0;
965 if(exec_else && !check_keyword(ctx, L"elif", NULL)) {
966 if(if_depth > 1)
967 continue;
969 if(!skip_spaces(ctx) || *ctx->ptr != '(')
970 return lex_error(ctx, JS_E_MISSING_LBRACKET);
972 if(!parse_cc_expr(ctx))
973 return -1;
975 if(!get_ccbool(ctx->ccval))
976 continue; /* skip block of code */
978 /* continue parsing */
979 ctx->cc_if_depth++;
980 return 0;
983 if(exec_else && !check_keyword(ctx, L"else", NULL)) {
984 if(if_depth > 1)
985 continue;
987 /* parse else block */
988 ctx->cc_if_depth++;
989 return 0;
992 if(!check_keyword(ctx, L"if", NULL)) {
993 if_depth++;
994 continue;
997 ctx->ptr++;
1001 static int cc_token(parser_ctx_t *ctx, void *lval)
1003 unsigned id_len = 0;
1004 cc_var_t *var;
1006 ctx->ptr++;
1008 if(!check_keyword(ctx, L"cc_on", NULL))
1009 return init_cc(ctx) ? 0 : -1;
1011 if(!check_keyword(ctx, L"set", NULL)) {
1012 const WCHAR *ident;
1013 unsigned ident_len;
1014 cc_var_t *var;
1016 if(!init_cc(ctx))
1017 return -1;
1019 if(!skip_spaces(ctx))
1020 return lex_error(ctx, JS_E_EXPECTED_AT);
1022 if(!parse_cc_identifier(ctx, &ident, &ident_len))
1023 return -1;
1025 if(!skip_spaces(ctx) || *ctx->ptr != '=')
1026 return lex_error(ctx, JS_E_EXPECTED_ASSIGN);
1027 ctx->ptr++;
1029 if(!parse_cc_expr(ctx)) {
1030 WARN("parsing CC expression failed\n");
1031 return -1;
1034 var = find_cc_var(ctx->script->cc, ident, ident_len);
1035 if(var) {
1036 var->val = ctx->ccval;
1037 }else {
1038 if(!new_cc_var(ctx->script->cc, ident, ident_len, ctx->ccval))
1039 return lex_error(ctx, E_OUTOFMEMORY);
1042 return 0;
1045 if(!check_keyword(ctx, L"if", NULL)) {
1046 if(!init_cc(ctx))
1047 return -1;
1049 if(!skip_spaces(ctx) || *ctx->ptr != '(')
1050 return lex_error(ctx, JS_E_MISSING_LBRACKET);
1052 if(!parse_cc_expr(ctx))
1053 return -1;
1055 if(get_ccbool(ctx->ccval)) {
1056 /* continue parsing block inside if */
1057 ctx->cc_if_depth++;
1058 return 0;
1061 return skip_code(ctx, TRUE);
1064 if(!check_keyword(ctx, L"elif", NULL) || !check_keyword(ctx, L"else", NULL)) {
1065 if(!ctx->cc_if_depth)
1066 return lex_error(ctx, JS_E_SYNTAX);
1068 return skip_code(ctx, FALSE);
1071 if(!check_keyword(ctx, L"end", NULL)) {
1072 if(!ctx->cc_if_depth)
1073 return lex_error(ctx, JS_E_SYNTAX);
1075 ctx->cc_if_depth--;
1076 return 0;
1079 if(!ctx->script->cc)
1080 return lex_error(ctx, JS_E_DISABLED_CC);
1082 while(ctx->ptr+id_len < ctx->end && is_identifier_char(ctx->ptr[id_len]))
1083 id_len++;
1084 if(!id_len)
1085 return '@';
1087 TRACE("var %s\n", debugstr_wn(ctx->ptr, id_len));
1089 var = find_cc_var(ctx->script->cc, ctx->ptr, id_len);
1090 ctx->ptr += id_len;
1091 if(!var || var->val.is_num) {
1092 *(literal_t**)lval = new_double_literal(ctx, var ? var->val.u.n : NAN);
1093 return tNumericLiteral;
1096 *(literal_t**)lval = new_boolean_literal(ctx, var->val.u.b);
1097 return tBooleanLiteral;
1100 int parser_lex(void *lval, unsigned *loc, parser_ctx_t *ctx)
1102 int ret;
1104 ctx->nl = ctx->ptr == ctx->begin;
1106 do {
1107 ret = next_token(ctx, loc, lval);
1108 } while(ret == '@' && !(ret = cc_token(ctx, lval)));
1110 return ret;
1113 literal_t *parse_regexp(parser_ctx_t *ctx)
1115 const WCHAR *re, *flags_ptr;
1116 BOOL in_class = FALSE;
1117 DWORD re_len, flags;
1118 literal_t *ret;
1120 TRACE("\n");
1122 while(*--ctx->ptr != '/');
1124 /* Simple regexp pre-parser; '/' if used in char class does not terminate regexp literal */
1125 re = ++ctx->ptr;
1126 while(ctx->ptr < ctx->end) {
1127 if(*ctx->ptr == '\\') {
1128 if(++ctx->ptr == ctx->end)
1129 break;
1130 }else if(in_class) {
1131 if(*ctx->ptr == '\n')
1132 break;
1133 if(*ctx->ptr == ']')
1134 in_class = FALSE;
1135 }else {
1136 if(*ctx->ptr == '/')
1137 break;
1139 if(*ctx->ptr == '[')
1140 in_class = TRUE;
1142 ctx->ptr++;
1145 if(ctx->ptr == ctx->end || *ctx->ptr != '/') {
1146 WARN("pre-parsing failed\n");
1147 ctx->hres = JS_E_SYNTAX;
1148 return NULL;
1151 re_len = ctx->ptr-re;
1153 flags_ptr = ++ctx->ptr;
1154 while(ctx->ptr < ctx->end && iswalnum(*ctx->ptr))
1155 ctx->ptr++;
1157 ctx->hres = parse_regexp_flags(flags_ptr, ctx->ptr-flags_ptr, &flags);
1158 if(FAILED(ctx->hres))
1159 return NULL;
1161 ret = parser_alloc(ctx, sizeof(literal_t));
1162 ret->type = LT_REGEXP;
1163 ret->u.regexp.str = compiler_alloc_string_len(ctx->compiler, re, re_len);
1164 ret->u.regexp.flags = flags;
1165 return ret;