jscript: Added missing port.h include to lex.c.
[wine/wine-gecko.git] / dlls / jscript / lex.c
blob06d0b89c7d4128a1f175af24dd43d9163bd070d3
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
19 #include "config.h"
20 #include "wine/port.h"
22 #include <limits.h>
24 #include "jscript.h"
25 #include "activscp.h"
26 #include "objsafe.h"
27 #include "engine.h"
29 #include "parser.tab.h"
31 #include "wine/debug.h"
32 #include "wine/unicode.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
36 #define LONGLONG_MAX (((LONGLONG)0x7fffffff<<32)|0xffffffff)
38 static const WCHAR breakW[] = {'b','r','e','a','k',0};
39 static const WCHAR caseW[] = {'c','a','s','e',0};
40 static const WCHAR catchW[] = {'c','a','t','c','h',0};
41 static const WCHAR continueW[] = {'c','o','n','t','i','n','u','e',0};
42 static const WCHAR defaultW[] = {'d','e','f','a','u','l','t',0};
43 static const WCHAR deleteW[] = {'d','e','l','e','t','e',0};
44 static const WCHAR doW[] = {'d','o',0};
45 static const WCHAR elseW[] = {'e','l','s','e',0};
46 static const WCHAR falseW[] = {'f','a','l','s','e',0};
47 static const WCHAR finallyW[] = {'f','i','n','a','l','l','y',0};
48 static const WCHAR forW[] = {'f','o','r',0};
49 static const WCHAR functionW[] = {'f','u','n','c','t','i','o','n',0};
50 static const WCHAR ifW[] = {'i','f',0};
51 static const WCHAR inW[] = {'i','n',0};
52 static const WCHAR instanceofW[] = {'i','n','s','t','a','n','c','e','o','f',0};
53 static const WCHAR newW[] = {'n','e','w',0};
54 static const WCHAR nullW[] = {'n','u','l','l',0};
55 static const WCHAR returnW[] = {'r','e','t','u','r','n',0};
56 static const WCHAR switchW[] = {'s','w','i','t','c','h',0};
57 static const WCHAR thisW[] = {'t','h','i','s',0};
58 static const WCHAR throwW[] = {'t','h','r','o','w',0};
59 static const WCHAR trueW[] = {'t','r','u','e',0};
60 static const WCHAR tryW[] = {'t','r','y',0};
61 static const WCHAR typeofW[] = {'t','y','p','e','o','f',0};
62 static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};
63 static const WCHAR varW[] = {'v','a','r',0};
64 static const WCHAR voidW[] = {'v','o','i','d',0};
65 static const WCHAR whileW[] = {'w','h','i','l','e',0};
66 static const WCHAR withW[] = {'w','i','t','h',0};
68 static const struct {
69 const WCHAR *word;
70 int token;
71 } keywords[] = {
72 {breakW, kBREAK},
73 {caseW, kCASE},
74 {catchW, kCATCH},
75 {continueW, kCONTINUE},
76 {defaultW, kDEFAULT},
77 {deleteW, kDELETE},
78 {doW, kDO},
79 {elseW, kELSE},
80 {falseW, kFALSE},
81 {finallyW, kFINALLY},
82 {forW, kFOR},
83 {functionW, kFUNCTION},
84 {ifW, kIF},
85 {inW, kIN},
86 {instanceofW, kINSTANCEOF},
87 {newW, kNEW},
88 {nullW, kNULL},
89 {returnW, kRETURN},
90 {switchW, kSWITCH},
91 {thisW, kTHIS},
92 {throwW, kTHROW},
93 {trueW, kTRUE},
94 {tryW, kTRY},
95 {typeofW, kTYPEOF},
96 {varW, kVAR},
97 {voidW, kVOID},
98 {whileW, kWHILE},
99 {withW, kWITH}
102 static int lex_error(parser_ctx_t *ctx, HRESULT hres)
104 ctx->hres = hres;
105 ctx->lexer_error = TRUE;
106 return -1;
109 /* ECMA-262 3rd Edition 7.6 */
110 static BOOL is_identifier_char(WCHAR c)
112 return isalnumW(c) || c == '$' || c == '_' || c == '\\';
115 static int check_keyword(parser_ctx_t *ctx, const WCHAR *word, const WCHAR **lval)
117 const WCHAR *p1 = ctx->ptr;
118 const WCHAR *p2 = word;
120 while(p1 < ctx->end && *p2) {
121 if(*p1 != *p2)
122 return *p1 - *p2;
123 p1++;
124 p2++;
127 if(*p2 || (p1 < ctx->end && is_identifier_char(*p1)))
128 return 1;
130 if(lval)
131 *lval = ctx->ptr;
132 ctx->ptr = p1;
133 return 0;
136 /* ECMA-262 3rd Edition 7.3 */
137 static BOOL is_endline(WCHAR c)
139 return c == '\n' || c == '\r' || c == 0x2028 || c == 0x2029;
142 static int hex_to_int(WCHAR c)
144 if('0' <= c && c <= '9')
145 return c-'0';
147 if('a' <= c && c <= 'f')
148 return c-'a'+10;
150 if('A' <= c && c <= 'F')
151 return c-'A'+10;
153 return -1;
156 static int check_keywords(parser_ctx_t *ctx, const WCHAR **lval)
158 int min = 0, max = sizeof(keywords)/sizeof(keywords[0])-1, r, i;
160 while(min <= max) {
161 i = (min+max)/2;
163 r = check_keyword(ctx, keywords[i].word, lval);
164 if(!r)
165 return keywords[i].token;
167 if(r > 0)
168 min = i+1;
169 else
170 max = i-1;
173 return 0;
176 static void skip_spaces(parser_ctx_t *ctx)
178 while(ctx->ptr < ctx->end && isspaceW(*ctx->ptr)) {
179 if(is_endline(*ctx->ptr++))
180 ctx->nl = TRUE;
184 static BOOL skip_html_comment(parser_ctx_t *ctx)
186 const WCHAR html_commentW[] = {'<','!','-','-',0};
188 if(!ctx->is_html || ctx->ptr+3 >= ctx->end ||
189 memcmp(ctx->ptr, html_commentW, sizeof(WCHAR)*4))
190 return FALSE;
192 ctx->nl = TRUE;
193 while(ctx->ptr < ctx->end && !is_endline(*ctx->ptr++));
195 return TRUE;
198 static BOOL skip_comment(parser_ctx_t *ctx)
200 if(ctx->ptr+1 >= ctx->end)
201 return FALSE;
203 if(*ctx->ptr != '/') {
204 if(*ctx->ptr == '@' && ctx->ptr+2 < ctx->end && ctx->ptr[1] == '*' && ctx->ptr[2] == '/') {
205 ctx->ptr += 3;
206 return TRUE;
209 return FALSE;
212 switch(ctx->ptr[1]) {
213 case '*':
214 ctx->ptr += 2;
215 if(ctx->ptr+2 < ctx->end && *ctx->ptr == '@' && is_identifier_char(ctx->ptr[1]))
216 return FALSE;
217 while(ctx->ptr+1 < ctx->end && (ctx->ptr[0] != '*' || ctx->ptr[1] != '/'))
218 ctx->ptr++;
220 if(ctx->ptr[0] == '*' && ctx->ptr[1] == '/') {
221 ctx->ptr += 2;
222 }else {
223 WARN("unexpected end of file (missing end of comment)\n");
224 ctx->ptr = ctx->end;
226 break;
227 case '/':
228 ctx->ptr += 2;
229 if(ctx->ptr+2 < ctx->end && *ctx->ptr == '@' && is_identifier_char(ctx->ptr[1]))
230 return FALSE;
231 while(ctx->ptr < ctx->end && !is_endline(*ctx->ptr))
232 ctx->ptr++;
233 break;
234 default:
235 return FALSE;
238 return TRUE;
241 static BOOL unescape(WCHAR *str)
243 WCHAR *pd, *p, c;
244 int i;
246 pd = p = str;
247 while(*p) {
248 if(*p != '\\') {
249 *pd++ = *p++;
250 continue;
253 p++;
255 switch(*p) {
256 case '\'':
257 case '\"':
258 case '\\':
259 c = *p;
260 break;
261 case 'b':
262 c = '\b';
263 break;
264 case 't':
265 c = '\t';
266 break;
267 case 'n':
268 c = '\n';
269 break;
270 case 'f':
271 c = '\f';
272 break;
273 case 'r':
274 c = '\r';
275 break;
276 case 'x':
277 i = hex_to_int(*++p);
278 if(i == -1)
279 return FALSE;
280 c = i << 4;
282 i = hex_to_int(*++p);
283 if(i == -1)
284 return FALSE;
285 c += i;
286 break;
287 case 'u':
288 i = hex_to_int(*++p);
289 if(i == -1)
290 return FALSE;
291 c = i << 12;
293 i = hex_to_int(*++p);
294 if(i == -1)
295 return FALSE;
296 c += i << 8;
298 i = hex_to_int(*++p);
299 if(i == -1)
300 return FALSE;
301 c += i << 4;
303 i = hex_to_int(*++p);
304 if(i == -1)
305 return FALSE;
306 c += i;
307 break;
308 default:
309 if(isdigitW(*p)) {
310 c = *p++ - '0';
311 if(isdigitW(*p)) {
312 c = c*8 + (*p++ - '0');
313 if(isdigitW(*p))
314 c = c*8 + (*p++ - '0');
316 p--;
318 else
319 c = *p;
322 *pd++ = c;
323 p++;
326 *pd = 0;
327 return TRUE;
330 static int parse_identifier(parser_ctx_t *ctx, const WCHAR **ret)
332 const WCHAR *ptr = ctx->ptr++;
333 WCHAR *wstr;
334 int len;
336 while(ctx->ptr < ctx->end && is_identifier_char(*ctx->ptr))
337 ctx->ptr++;
339 len = ctx->ptr-ptr;
341 *ret = wstr = parser_alloc(ctx, (len+1)*sizeof(WCHAR));
342 memcpy(wstr, ptr, len*sizeof(WCHAR));
343 wstr[len] = 0;
345 /* FIXME: unescape */
346 return tIdentifier;
349 static int parse_string_literal(parser_ctx_t *ctx, const WCHAR **ret, WCHAR endch)
351 const WCHAR *ptr = ++ctx->ptr;
352 WCHAR *wstr;
353 int len;
355 while(ctx->ptr < ctx->end && *ctx->ptr != endch) {
356 if(*ctx->ptr++ == '\\')
357 ctx->ptr++;
360 if(ctx->ptr == ctx->end)
361 return lex_error(ctx, JS_E_UNTERMINATED_STRING);
363 len = ctx->ptr-ptr;
365 *ret = wstr = parser_alloc(ctx, (len+1)*sizeof(WCHAR));
366 memcpy(wstr, ptr, len*sizeof(WCHAR));
367 wstr[len] = 0;
369 ctx->ptr++;
371 if(!unescape(wstr)) {
372 WARN("unescape failed\n");
373 return lex_error(ctx, E_FAIL);
376 return tStringLiteral;
379 static literal_t *new_int_literal(parser_ctx_t *ctx, LONG l)
381 literal_t *ret = parser_alloc(ctx, sizeof(literal_t));
383 ret->type = LT_INT;
384 ret->u.lval = l;
386 return ret;
389 static literal_t *new_double_literal(parser_ctx_t *ctx, DOUBLE d)
391 literal_t *ret = parser_alloc(ctx, sizeof(literal_t));
393 ret->type = LT_DOUBLE;
394 ret->u.dval = d;
395 return ret;
398 literal_t *new_boolean_literal(parser_ctx_t *ctx, VARIANT_BOOL bval)
400 literal_t *ret = parser_alloc(ctx, sizeof(literal_t));
402 ret->type = LT_BOOL;
403 ret->u.bval = bval;
405 return ret;
408 static int parse_double_literal(parser_ctx_t *ctx, LONG int_part, literal_t **literal)
410 LONGLONG d, hlp;
411 int exp = 0;
413 if(ctx->ptr == ctx->end || (!isdigitW(*ctx->ptr) &&
414 *ctx->ptr!='.' && *ctx->ptr!='e' && *ctx->ptr!='E')) {
415 ERR("Illegal character\n");
416 return 0;
419 d = int_part;
420 while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr)) {
421 hlp = d*10 + *(ctx->ptr++) - '0';
422 if(d>LONGLONG_MAX/10 || hlp<0) {
423 exp++;
424 break;
426 else
427 d = hlp;
429 while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr)) {
430 exp++;
431 ctx->ptr++;
434 if(*ctx->ptr == '.') ctx->ptr++;
436 while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr)) {
437 hlp = d*10 + *(ctx->ptr++) - '0';
438 if(d>LONGLONG_MAX/10 || hlp<0)
439 break;
441 d = hlp;
442 exp--;
444 while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr))
445 ctx->ptr++;
447 if(ctx->ptr < ctx->end && (*ctx->ptr == 'e' || *ctx->ptr == 'E')) {
448 int sign = 1, e = 0;
450 ctx->ptr++;
451 if(ctx->ptr < ctx->end) {
452 if(*ctx->ptr == '+') {
453 ctx->ptr++;
454 }else if(*ctx->ptr == '-') {
455 sign = -1;
456 ctx->ptr++;
457 }else if(!isdigitW(*ctx->ptr)) {
458 WARN("Expected exponent part\n");
459 return lex_error(ctx, E_FAIL);
463 if(ctx->ptr == ctx->end) {
464 WARN("unexpected end of file\n");
465 return lex_error(ctx, E_FAIL);
468 while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr)) {
469 if(e > INT_MAX/10 || (e = e*10 + *ctx->ptr++ - '0')<0)
470 e = INT_MAX;
472 e *= sign;
474 if(exp<0 && e<0 && e+exp>0) exp = INT_MIN;
475 else if(exp>0 && e>0 && e+exp<0) exp = INT_MAX;
476 else exp += e;
479 *literal = new_double_literal(ctx, exp>=0 ? d*pow(10, exp) : d/pow(10, -exp));
480 return tNumericLiteral;
483 static int parse_numeric_literal(parser_ctx_t *ctx, literal_t **literal)
485 LONG l, d;
487 l = *ctx->ptr++ - '0';
488 if(ctx->ptr == ctx->end) {
489 *literal = new_int_literal(ctx, l);
490 return tNumericLiteral;
493 if(!l) {
494 if(*ctx->ptr == 'x' || *ctx->ptr == 'X') {
495 if(++ctx->ptr == ctx->end) {
496 ERR("unexpected end of file\n");
497 return 0;
500 while(ctx->ptr < ctx->end && (d = hex_to_int(*ctx->ptr)) != -1) {
501 l = l*16 + d;
502 ctx->ptr++;
505 if(ctx->ptr < ctx->end && is_identifier_char(*ctx->ptr)) {
506 WARN("unexpected identifier char\n");
507 return lex_error(ctx, E_FAIL);
510 *literal = new_int_literal(ctx, l);
511 return tNumericLiteral;
514 if(isdigitW(*ctx->ptr) || is_identifier_char(*ctx->ptr)) {
515 WARN("wrong char after zero\n");
516 return lex_error(ctx, E_FAIL);
519 *literal = new_int_literal(ctx, 0);
522 while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr))
524 d = l*10 + *(ctx->ptr)-'0';
526 /* Check for integer overflow */
527 if (l > INT_MAX/10 || d < 0)
528 return parse_double_literal(ctx, l, literal);
530 l = d;
531 ctx->ptr++;
534 if(ctx->ptr < ctx->end) {
535 if(*ctx->ptr == '.' || *ctx->ptr == 'e' || *ctx->ptr == 'E')
536 return parse_double_literal(ctx, l, literal);
538 if(is_identifier_char(*ctx->ptr)) {
539 WARN("unexpected identifier char\n");
540 return lex_error(ctx, E_FAIL);
544 *literal = new_int_literal(ctx, l);
545 return tNumericLiteral;
548 static int next_token(parser_ctx_t *ctx, void *lval)
550 do {
551 skip_spaces(ctx);
552 if(ctx->ptr == ctx->end)
553 return tEOF;
554 }while(skip_comment(ctx) || skip_html_comment(ctx));
556 if(isalphaW(*ctx->ptr)) {
557 int ret = check_keywords(ctx, lval);
558 if(ret)
559 return ret;
561 return parse_identifier(ctx, lval);
564 if(isdigitW(*ctx->ptr))
565 return parse_numeric_literal(ctx, lval);
567 switch(*ctx->ptr) {
568 case '{':
569 case '(':
570 case ')':
571 case '[':
572 case ']':
573 case ';':
574 case ',':
575 case '~':
576 case '?':
577 case ':':
578 return *ctx->ptr++;
580 case '}':
581 *(const WCHAR**)lval = ctx->ptr++;
582 return '}';
584 case '.':
585 if(++ctx->ptr < ctx->end && isdigitW(*ctx->ptr))
586 return parse_double_literal(ctx, 0, lval);
587 return '.';
589 case '<':
590 if(++ctx->ptr == ctx->end) {
591 *(int*)lval = EXPR_LESS;
592 return tRelOper;
595 switch(*ctx->ptr) {
596 case '=': /* <= */
597 ctx->ptr++;
598 *(int*)lval = EXPR_LESSEQ;
599 return tRelOper;
600 case '<': /* << */
601 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* <<= */
602 ctx->ptr++;
603 *(int*)lval = EXPR_ASSIGNLSHIFT;
604 return tAssignOper;
606 *(int*)lval = EXPR_LSHIFT;
607 return tShiftOper;
608 default: /* < */
609 *(int*)lval = EXPR_LESS;
610 return tRelOper;
613 case '>':
614 if(++ctx->ptr == ctx->end) { /* > */
615 *(int*)lval = EXPR_GREATER;
616 return tRelOper;
619 switch(*ctx->ptr) {
620 case '=': /* >= */
621 ctx->ptr++;
622 *(int*)lval = EXPR_GREATEREQ;
623 return tRelOper;
624 case '>': /* >> */
625 if(++ctx->ptr < ctx->end) {
626 if(*ctx->ptr == '=') { /* >>= */
627 ctx->ptr++;
628 *(int*)lval = EXPR_ASSIGNRSHIFT;
629 return tAssignOper;
631 if(*ctx->ptr == '>') { /* >>> */
632 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* >>>= */
633 ctx->ptr++;
634 *(int*)lval = EXPR_ASSIGNRRSHIFT;
635 return tAssignOper;
637 *(int*)lval = EXPR_RRSHIFT;
638 return tRelOper;
641 *(int*)lval = EXPR_RSHIFT;
642 return tShiftOper;
643 default:
644 *(int*)lval = EXPR_GREATER;
645 return tRelOper;
648 case '+':
649 ctx->ptr++;
650 if(ctx->ptr < ctx->end) {
651 switch(*ctx->ptr) {
652 case '+': /* ++ */
653 ctx->ptr++;
654 return tINC;
655 case '=': /* += */
656 ctx->ptr++;
657 *(int*)lval = EXPR_ASSIGNADD;
658 return tAssignOper;
661 return '+';
663 case '-':
664 ctx->ptr++;
665 if(ctx->ptr < ctx->end) {
666 switch(*ctx->ptr) {
667 case '-': /* -- or --> */
668 ctx->ptr++;
669 if(ctx->is_html && ctx->nl && ctx->ptr < ctx->end && *ctx->ptr == '>') {
670 ctx->ptr++;
671 return tHTMLCOMMENT;
673 return tDEC;
674 case '=': /* -= */
675 ctx->ptr++;
676 *(int*)lval = EXPR_ASSIGNSUB;
677 return tAssignOper;
680 return '-';
682 case '*':
683 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* *= */
684 ctx->ptr++;
685 *(int*)lval = EXPR_ASSIGNMUL;
686 return tAssignOper;
688 return '*';
690 case '%':
691 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* %= */
692 ctx->ptr++;
693 *(int*)lval = EXPR_ASSIGNMOD;
694 return tAssignOper;
696 return '%';
698 case '&':
699 if(++ctx->ptr < ctx->end) {
700 switch(*ctx->ptr) {
701 case '=': /* &= */
702 ctx->ptr++;
703 *(int*)lval = EXPR_ASSIGNAND;
704 return tAssignOper;
705 case '&': /* && */
706 ctx->ptr++;
707 return tANDAND;
710 return '&';
712 case '|':
713 if(++ctx->ptr < ctx->end) {
714 switch(*ctx->ptr) {
715 case '=': /* |= */
716 ctx->ptr++;
717 *(int*)lval = EXPR_ASSIGNOR;
718 return tAssignOper;
719 case '|': /* || */
720 ctx->ptr++;
721 return tOROR;
724 return '|';
726 case '^':
727 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* ^= */
728 ctx->ptr++;
729 *(int*)lval = EXPR_ASSIGNXOR;
730 return tAssignOper;
732 return '^';
734 case '!':
735 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* != */
736 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* !== */
737 ctx->ptr++;
738 *(int*)lval = EXPR_NOTEQEQ;
739 return tEqOper;
741 *(int*)lval = EXPR_NOTEQ;
742 return tEqOper;
744 return '!';
746 case '=':
747 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* == */
748 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* === */
749 ctx->ptr++;
750 *(int*)lval = EXPR_EQEQ;
751 return tEqOper;
753 *(int*)lval = EXPR_EQ;
754 return tEqOper;
756 return '=';
758 case '/':
759 if(++ctx->ptr < ctx->end) {
760 if(*ctx->ptr == '=') { /* /= */
761 ctx->ptr++;
762 *(int*)lval = EXPR_ASSIGNDIV;
763 return kDIVEQ;
766 return '/';
768 case '\"':
769 case '\'':
770 return parse_string_literal(ctx, lval, *ctx->ptr);
772 case '_':
773 case '$':
774 return parse_identifier(ctx, lval);
776 case '@':
777 return '@';
780 WARN("unexpected char '%c' %d\n", *ctx->ptr, *ctx->ptr);
781 return 0;
784 struct _cc_var_t {
785 BOOL is_num;
786 union {
787 VARIANT_BOOL b;
788 DOUBLE n;
789 } u;
790 struct _cc_var_t *next;
791 unsigned name_len;
792 WCHAR name[0];
795 void release_cc(cc_ctx_t *cc)
797 cc_var_t *iter, *next;
799 for(iter = cc->vars; iter; iter = next) {
800 next = iter->next;
801 heap_free(iter);
804 heap_free(cc);
807 static BOOL add_cc_var(cc_ctx_t *cc, const WCHAR *name, cc_var_t *v)
809 cc_var_t *new_v;
810 unsigned len;
812 len = strlenW(name);
814 new_v = heap_alloc(sizeof(cc_var_t) + (len+1)*sizeof(WCHAR));
815 if(!new_v)
816 return FALSE;
818 memcpy(new_v, v, sizeof(*v));
819 memcpy(new_v->name, name, (len+1)*sizeof(WCHAR));
820 new_v->name_len = len;
821 new_v->next = cc->vars;
822 cc->vars = new_v;
823 return TRUE;
826 static cc_var_t *find_cc_var(cc_ctx_t *cc, const WCHAR *name, unsigned name_len)
828 cc_var_t *iter;
830 for(iter = cc->vars; iter; iter = iter->next) {
831 if(iter->name_len == name_len && !memcmp(iter->name, name, name_len*sizeof(WCHAR)))
832 return iter;
835 return NULL;
838 static int init_cc(parser_ctx_t *ctx)
840 cc_ctx_t *cc;
841 cc_var_t v;
843 static const WCHAR _win32W[] = {'_','w','i','n','3','2',0};
844 static const WCHAR _win64W[] = {'_','w','i','n','6','4',0};
845 static const WCHAR _x86W[] = {'_','x','8','6',0};
846 static const WCHAR _amd64W[] = {'_','a','m','d','6','4',0};
847 static const WCHAR _jscriptW[] = {'_','j','s','c','r','i','p','t',0};
848 static const WCHAR _jscript_buildW[] = {'_','j','s','c','r','i','p','t','_','b','u','i','l','d',0};
849 static const WCHAR _jscript_versionW[] = {'_','j','s','c','r','i','p','t','_','v','e','r','s','i','o','n',0};
851 if(ctx->script->cc)
852 return 0;
854 cc = heap_alloc(sizeof(cc_ctx_t));
855 if(!cc)
856 return lex_error(ctx, E_OUTOFMEMORY);
858 cc->vars = NULL;
859 v.is_num = FALSE;
860 v.u.b = VARIANT_TRUE;
861 if(!add_cc_var(cc, _jscriptW, &v)
862 || !add_cc_var(cc, sizeof(void*) == 8 ? _win64W : _win32W, &v)
863 || !add_cc_var(cc, sizeof(void*) == 8 ? _amd64W : _x86W, &v)) {
864 release_cc(cc);
865 return lex_error(ctx, E_OUTOFMEMORY);
868 v.is_num = TRUE;
869 v.u.n = JSCRIPT_BUILD_VERSION;
870 if(!add_cc_var(cc, _jscript_buildW, &v)) {
871 release_cc(cc);
872 return lex_error(ctx, E_OUTOFMEMORY);
875 v.u.n = JSCRIPT_MAJOR_VERSION + (DOUBLE)JSCRIPT_MINOR_VERSION/10.0;
876 if(!add_cc_var(cc, _jscript_versionW, &v)) {
877 release_cc(cc);
878 return lex_error(ctx, E_OUTOFMEMORY);
881 ctx->script->cc = cc;
882 return 0;
885 static int cc_token(parser_ctx_t *ctx, void *lval)
887 unsigned id_len = 0;
888 cc_var_t *var;
890 static const WCHAR cc_onW[] = {'c','c','_','o','n',0};
891 static const WCHAR setW[] = {'s','e','t',0};
892 static const WCHAR elifW[] = {'e','l','i','f',0};
893 static const WCHAR endW[] = {'e','n','d',0};
895 ctx->ptr++;
897 if(!check_keyword(ctx, cc_onW, NULL))
898 return init_cc(ctx);
900 if(!check_keyword(ctx, setW, NULL)) {
901 FIXME("@set not implemented\n");
902 return lex_error(ctx, E_NOTIMPL);
905 if(!check_keyword(ctx, ifW, NULL)) {
906 FIXME("@if not implemented\n");
907 return lex_error(ctx, E_NOTIMPL);
910 if(!check_keyword(ctx, elifW, NULL)) {
911 FIXME("@elif not implemented\n");
912 return lex_error(ctx, E_NOTIMPL);
915 if(!check_keyword(ctx, elseW, NULL)) {
916 FIXME("@else not implemented\n");
917 return lex_error(ctx, E_NOTIMPL);
920 if(!check_keyword(ctx, endW, NULL)) {
921 FIXME("@end not implemented\n");
922 return lex_error(ctx, E_NOTIMPL);
925 if(!ctx->script->cc)
926 return lex_error(ctx, JS_E_DISABLED_CC);
928 while(ctx->ptr+id_len < ctx->end && is_identifier_char(ctx->ptr[id_len]))
929 id_len++;
930 if(!id_len)
931 return '@';
933 TRACE("var %s\n", debugstr_wn(ctx->ptr, id_len));
935 var = find_cc_var(ctx->script->cc, ctx->ptr, id_len);
936 ctx->ptr += id_len;
937 if(!var || var->is_num) {
938 *(literal_t**)lval = new_double_literal(ctx, var ? var->u.n : NAN);
939 return tNumericLiteral;
942 *(literal_t**)lval = new_boolean_literal(ctx, var->u.b);
943 return tBooleanLiteral;
946 int parser_lex(void *lval, parser_ctx_t *ctx)
948 int ret;
950 ctx->nl = ctx->ptr == ctx->begin;
952 do {
953 ret = next_token(ctx, lval);
954 } while(ret == '@' && !(ret = cc_token(ctx, lval)));
956 return ret;
959 literal_t *parse_regexp(parser_ctx_t *ctx)
961 const WCHAR *re, *flags_ptr;
962 BOOL in_class = FALSE;
963 DWORD re_len, flags;
964 literal_t *ret;
965 HRESULT hres;
967 TRACE("\n");
969 while(*--ctx->ptr != '/');
971 /* Simple regexp pre-parser; '/' if used in char class does not terminate regexp literal */
972 re = ++ctx->ptr;
973 while(ctx->ptr < ctx->end) {
974 if(*ctx->ptr == '\\') {
975 if(++ctx->ptr == ctx->end)
976 break;
977 }else if(in_class) {
978 if(*ctx->ptr == '\n')
979 break;
980 if(*ctx->ptr == ']')
981 in_class = FALSE;
982 }else {
983 if(*ctx->ptr == '/')
984 break;
986 if(*ctx->ptr == '[')
987 in_class = TRUE;
989 ctx->ptr++;
992 if(ctx->ptr == ctx->end || *ctx->ptr != '/') {
993 WARN("pre-parsing failed\n");
994 return NULL;
997 re_len = ctx->ptr-re;
999 flags_ptr = ++ctx->ptr;
1000 while(ctx->ptr < ctx->end && isalnumW(*ctx->ptr))
1001 ctx->ptr++;
1003 hres = parse_regexp_flags(flags_ptr, ctx->ptr-flags_ptr, &flags);
1004 if(FAILED(hres))
1005 return NULL;
1007 ret = parser_alloc(ctx, sizeof(literal_t));
1008 ret->type = LT_REGEXP;
1009 ret->u.regexp.str = re;
1010 ret->u.regexp.str_len = re_len;
1011 ret->u.regexp.flags = flags;
1012 return ret;