[JSCRIPT]
[reactos.git] / reactos / dll / win32 / jscript / lex.c
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 #include "jscript.h"
20
21 #include "parser.tab.h"
22
23 #define LONGLONG_MAX (((LONGLONG)0x7fffffff<<32)|0xffffffff)
24
25 static const WCHAR breakW[] = {'b','r','e','a','k',0};
26 static const WCHAR caseW[] = {'c','a','s','e',0};
27 static const WCHAR catchW[] = {'c','a','t','c','h',0};
28 static const WCHAR continueW[] = {'c','o','n','t','i','n','u','e',0};
29 static const WCHAR defaultW[] = {'d','e','f','a','u','l','t',0};
30 static const WCHAR deleteW[] = {'d','e','l','e','t','e',0};
31 static const WCHAR doW[] = {'d','o',0};
32 static const WCHAR elseW[] = {'e','l','s','e',0};
33 static const WCHAR falseW[] = {'f','a','l','s','e',0};
34 static const WCHAR finallyW[] = {'f','i','n','a','l','l','y',0};
35 static const WCHAR forW[] = {'f','o','r',0};
36 static const WCHAR functionW[] = {'f','u','n','c','t','i','o','n',0};
37 static const WCHAR ifW[] = {'i','f',0};
38 static const WCHAR inW[] = {'i','n',0};
39 static const WCHAR instanceofW[] = {'i','n','s','t','a','n','c','e','o','f',0};
40 static const WCHAR newW[] = {'n','e','w',0};
41 static const WCHAR nullW[] = {'n','u','l','l',0};
42 static const WCHAR returnW[] = {'r','e','t','u','r','n',0};
43 static const WCHAR switchW[] = {'s','w','i','t','c','h',0};
44 static const WCHAR thisW[] = {'t','h','i','s',0};
45 static const WCHAR throwW[] = {'t','h','r','o','w',0};
46 static const WCHAR trueW[] = {'t','r','u','e',0};
47 static const WCHAR tryW[] = {'t','r','y',0};
48 static const WCHAR typeofW[] = {'t','y','p','e','o','f',0};
49 static const WCHAR varW[] = {'v','a','r',0};
50 static const WCHAR voidW[] = {'v','o','i','d',0};
51 static const WCHAR whileW[] = {'w','h','i','l','e',0};
52 static const WCHAR withW[] = {'w','i','t','h',0};
53
54 static const struct {
55 const WCHAR *word;
56 int token;
57 BOOL no_nl;
58 } keywords[] = {
59 {breakW, kBREAK, TRUE},
60 {caseW, kCASE},
61 {catchW, kCATCH},
62 {continueW, kCONTINUE, TRUE},
63 {defaultW, kDEFAULT},
64 {deleteW, kDELETE},
65 {doW, kDO},
66 {elseW, kELSE},
67 {falseW, kFALSE},
68 {finallyW, kFINALLY},
69 {forW, kFOR},
70 {functionW, kFUNCTION},
71 {ifW, kIF},
72 {inW, kIN},
73 {instanceofW, kINSTANCEOF},
74 {newW, kNEW},
75 {nullW, kNULL},
76 {returnW, kRETURN, TRUE},
77 {switchW, kSWITCH},
78 {thisW, kTHIS},
79 {throwW, kTHROW},
80 {trueW, kTRUE},
81 {tryW, kTRY},
82 {typeofW, kTYPEOF},
83 {varW, kVAR},
84 {voidW, kVOID},
85 {whileW, kWHILE},
86 {withW, kWITH}
87 };
88
89 static int lex_error(parser_ctx_t *ctx, HRESULT hres)
90 {
91 ctx->hres = hres;
92 ctx->lexer_error = TRUE;
93 return -1;
94 }
95
96 /* ECMA-262 3rd Edition 7.6 */
97 static BOOL is_identifier_char(WCHAR c)
98 {
99 return isalnumW(c) || c == '$' || c == '_' || c == '\\';
100 }
101
102 static int check_keyword(parser_ctx_t *ctx, const WCHAR *word, const WCHAR **lval)
103 {
104 const WCHAR *p1 = ctx->ptr;
105 const WCHAR *p2 = word;
106
107 while(p1 < ctx->end && *p2) {
108 if(*p1 != *p2)
109 return *p1 - *p2;
110 p1++;
111 p2++;
112 }
113
114 if(*p2 || (p1 < ctx->end && is_identifier_char(*p1)))
115 return 1;
116
117 if(lval)
118 *lval = ctx->ptr;
119 ctx->ptr = p1;
120 return 0;
121 }
122
123 /* ECMA-262 3rd Edition 7.3 */
124 static BOOL is_endline(WCHAR c)
125 {
126 return c == '\n' || c == '\r' || c == 0x2028 || c == 0x2029;
127 }
128
129 static int hex_to_int(WCHAR c)
130 {
131 if('0' <= c && c <= '9')
132 return c-'0';
133
134 if('a' <= c && c <= 'f')
135 return c-'a'+10;
136
137 if('A' <= c && c <= 'F')
138 return c-'A'+10;
139
140 return -1;
141 }
142
143 static int check_keywords(parser_ctx_t *ctx, const WCHAR **lval)
144 {
145 int min = 0, max = sizeof(keywords)/sizeof(keywords[0])-1, r, i;
146
147 while(min <= max) {
148 i = (min+max)/2;
149
150 r = check_keyword(ctx, keywords[i].word, lval);
151 if(!r) {
152 ctx->implicit_nl_semicolon = keywords[i].no_nl;
153 return keywords[i].token;
154 }
155
156 if(r > 0)
157 min = i+1;
158 else
159 max = i-1;
160 }
161
162 return 0;
163 }
164
165 static BOOL skip_html_comment(parser_ctx_t *ctx)
166 {
167 const WCHAR html_commentW[] = {'<','!','-','-',0};
168
169 if(!ctx->is_html || ctx->ptr+3 >= ctx->end ||
170 memcmp(ctx->ptr, html_commentW, sizeof(WCHAR)*4))
171 return FALSE;
172
173 ctx->nl = TRUE;
174 while(ctx->ptr < ctx->end && !is_endline(*ctx->ptr++));
175
176 return TRUE;
177 }
178
179 static BOOL skip_comment(parser_ctx_t *ctx)
180 {
181 if(ctx->ptr+1 >= ctx->end)
182 return FALSE;
183
184 if(*ctx->ptr != '/') {
185 if(*ctx->ptr == '@' && ctx->ptr+2 < ctx->end && ctx->ptr[1] == '*' && ctx->ptr[2] == '/') {
186 ctx->ptr += 3;
187 return TRUE;
188 }
189
190 return FALSE;
191 }
192
193 switch(ctx->ptr[1]) {
194 case '*':
195 ctx->ptr += 2;
196 if(ctx->ptr+2 < ctx->end && *ctx->ptr == '@' && is_identifier_char(ctx->ptr[1]))
197 return FALSE;
198 while(ctx->ptr+1 < ctx->end && (ctx->ptr[0] != '*' || ctx->ptr[1] != '/'))
199 ctx->ptr++;
200
201 if(ctx->ptr[0] == '*' && ctx->ptr[1] == '/') {
202 ctx->ptr += 2;
203 }else {
204 WARN("unexpected end of file (missing end of comment)\n");
205 ctx->ptr = ctx->end;
206 }
207 break;
208 case '/':
209 ctx->ptr += 2;
210 if(ctx->ptr+2 < ctx->end && *ctx->ptr == '@' && is_identifier_char(ctx->ptr[1]))
211 return FALSE;
212 while(ctx->ptr < ctx->end && !is_endline(*ctx->ptr))
213 ctx->ptr++;
214 break;
215 default:
216 return FALSE;
217 }
218
219 return TRUE;
220 }
221
222 static BOOL unescape(WCHAR *str)
223 {
224 WCHAR *pd, *p, c;
225 int i;
226
227 pd = p = str;
228 while(*p) {
229 if(*p != '\\') {
230 *pd++ = *p++;
231 continue;
232 }
233
234 p++;
235
236 switch(*p) {
237 case '\'':
238 case '\"':
239 case '\\':
240 c = *p;
241 break;
242 case 'b':
243 c = '\b';
244 break;
245 case 't':
246 c = '\t';
247 break;
248 case 'n':
249 c = '\n';
250 break;
251 case 'f':
252 c = '\f';
253 break;
254 case 'r':
255 c = '\r';
256 break;
257 case 'x':
258 i = hex_to_int(*++p);
259 if(i == -1)
260 return FALSE;
261 c = i << 4;
262
263 i = hex_to_int(*++p);
264 if(i == -1)
265 return FALSE;
266 c += i;
267 break;
268 case 'u':
269 i = hex_to_int(*++p);
270 if(i == -1)
271 return FALSE;
272 c = i << 12;
273
274 i = hex_to_int(*++p);
275 if(i == -1)
276 return FALSE;
277 c += i << 8;
278
279 i = hex_to_int(*++p);
280 if(i == -1)
281 return FALSE;
282 c += i << 4;
283
284 i = hex_to_int(*++p);
285 if(i == -1)
286 return FALSE;
287 c += i;
288 break;
289 default:
290 if(isdigitW(*p)) {
291 c = *p++ - '0';
292 if(isdigitW(*p)) {
293 c = c*8 + (*p++ - '0');
294 if(isdigitW(*p))
295 c = c*8 + (*p++ - '0');
296 }
297 p--;
298 }
299 else
300 c = *p;
301 }
302
303 *pd++ = c;
304 p++;
305 }
306
307 *pd = 0;
308 return TRUE;
309 }
310
311 static int parse_identifier(parser_ctx_t *ctx, const WCHAR **ret)
312 {
313 const WCHAR *ptr = ctx->ptr++;
314 WCHAR *wstr;
315 int len;
316
317 while(ctx->ptr < ctx->end && is_identifier_char(*ctx->ptr))
318 ctx->ptr++;
319
320 len = ctx->ptr-ptr;
321
322 *ret = wstr = parser_alloc(ctx, (len+1)*sizeof(WCHAR));
323 memcpy(wstr, ptr, len*sizeof(WCHAR));
324 wstr[len] = 0;
325
326 /* FIXME: unescape */
327 return tIdentifier;
328 }
329
330 static int parse_string_literal(parser_ctx_t *ctx, const WCHAR **ret, WCHAR endch)
331 {
332 const WCHAR *ptr = ++ctx->ptr;
333 WCHAR *wstr;
334 int len;
335
336 while(ctx->ptr < ctx->end && *ctx->ptr != endch) {
337 if(*ctx->ptr++ == '\\')
338 ctx->ptr++;
339 }
340
341 if(ctx->ptr == ctx->end)
342 return lex_error(ctx, JS_E_UNTERMINATED_STRING);
343
344 len = ctx->ptr-ptr;
345
346 *ret = wstr = parser_alloc(ctx, (len+1)*sizeof(WCHAR));
347 memcpy(wstr, ptr, len*sizeof(WCHAR));
348 wstr[len] = 0;
349
350 ctx->ptr++;
351
352 if(!unescape(wstr)) {
353 WARN("unescape failed\n");
354 return lex_error(ctx, E_FAIL);
355 }
356
357 return tStringLiteral;
358 }
359
360 static literal_t *new_double_literal(parser_ctx_t *ctx, DOUBLE d)
361 {
362 literal_t *ret = parser_alloc(ctx, sizeof(literal_t));
363
364 ret->type = LT_DOUBLE;
365 ret->u.dval = d;
366 return ret;
367 }
368
369 literal_t *new_boolean_literal(parser_ctx_t *ctx, BOOL bval)
370 {
371 literal_t *ret = parser_alloc(ctx, sizeof(literal_t));
372
373 ret->type = LT_BOOL;
374 ret->u.bval = bval;
375
376 return ret;
377 }
378
379 static int parse_double_literal(parser_ctx_t *ctx, LONG int_part, literal_t **literal)
380 {
381 LONGLONG d, hlp;
382 int exp = 0;
383
384 d = int_part;
385 while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr)) {
386 hlp = d*10 + *(ctx->ptr++) - '0';
387 if(d>LONGLONG_MAX/10 || hlp<0) {
388 exp++;
389 break;
390 }
391 else
392 d = hlp;
393 }
394 while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr)) {
395 exp++;
396 ctx->ptr++;
397 }
398
399 if(*ctx->ptr == '.') {
400 ctx->ptr++;
401
402 while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr)) {
403 hlp = d*10 + *(ctx->ptr++) - '0';
404 if(d>LONGLONG_MAX/10 || hlp<0)
405 break;
406
407 d = hlp;
408 exp--;
409 }
410 while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr))
411 ctx->ptr++;
412 }
413
414 if(ctx->ptr < ctx->end && (*ctx->ptr == 'e' || *ctx->ptr == 'E')) {
415 int sign = 1, e = 0;
416
417 ctx->ptr++;
418 if(ctx->ptr < ctx->end) {
419 if(*ctx->ptr == '+') {
420 ctx->ptr++;
421 }else if(*ctx->ptr == '-') {
422 sign = -1;
423 ctx->ptr++;
424 }else if(!isdigitW(*ctx->ptr)) {
425 WARN("Expected exponent part\n");
426 return lex_error(ctx, E_FAIL);
427 }
428 }
429
430 if(ctx->ptr == ctx->end) {
431 WARN("unexpected end of file\n");
432 return lex_error(ctx, E_FAIL);
433 }
434
435 while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr)) {
436 if(e > INT_MAX/10 || (e = e*10 + *ctx->ptr++ - '0')<0)
437 e = INT_MAX;
438 }
439 e *= sign;
440
441 if(exp<0 && e<0 && e+exp>0) exp = INT_MIN;
442 else if(exp>0 && e>0 && e+exp<0) exp = INT_MAX;
443 else exp += e;
444 }
445
446 *literal = new_double_literal(ctx, exp>=0 ? d*pow(10, exp) : d/pow(10, -exp));
447 return tNumericLiteral;
448 }
449
450 static int parse_numeric_literal(parser_ctx_t *ctx, literal_t **literal)
451 {
452 LONG l, d;
453
454 l = *ctx->ptr++ - '0';
455 if(!l) {
456 if(*ctx->ptr == 'x' || *ctx->ptr == 'X') {
457 if(++ctx->ptr == ctx->end) {
458 ERR("unexpected end of file\n");
459 return 0;
460 }
461
462 while(ctx->ptr < ctx->end && (d = hex_to_int(*ctx->ptr)) != -1) {
463 l = l*16 + d;
464 ctx->ptr++;
465 }
466
467 if(ctx->ptr < ctx->end && is_identifier_char(*ctx->ptr)) {
468 WARN("unexpected identifier char\n");
469 return lex_error(ctx, E_FAIL);
470 }
471
472 *literal = new_double_literal(ctx, l);
473 return tNumericLiteral;
474 }
475
476 if(is_identifier_char(*ctx->ptr)) {
477 WARN("wrong char after zero\n");
478 return lex_error(ctx, E_FAIL);
479 }
480
481 if(isdigitW(*ctx->ptr)) {
482 FIXME("octal literals not implemented\n");
483 return lex_error(ctx, E_NOTIMPL);
484 }
485 }
486
487 return parse_double_literal(ctx, l, literal);
488 }
489
490 static int next_token(parser_ctx_t *ctx, void *lval)
491 {
492 do {
493 while(ctx->ptr < ctx->end && isspaceW(*ctx->ptr)) {
494 if(is_endline(*ctx->ptr++))
495 ctx->nl = TRUE;
496 }
497 if(ctx->ptr == ctx->end)
498 return tEOF;
499 }while(skip_comment(ctx) || skip_html_comment(ctx));
500
501 if(ctx->implicit_nl_semicolon) {
502 if(ctx->nl)
503 return ';';
504 ctx->implicit_nl_semicolon = FALSE;
505 }
506
507 if(isalphaW(*ctx->ptr)) {
508 int ret = check_keywords(ctx, lval);
509 if(ret)
510 return ret;
511
512 return parse_identifier(ctx, lval);
513 }
514
515 if(isdigitW(*ctx->ptr))
516 return parse_numeric_literal(ctx, lval);
517
518 switch(*ctx->ptr) {
519 case '{':
520 case '(':
521 case ')':
522 case '[':
523 case ']':
524 case ';':
525 case ',':
526 case '~':
527 case '?':
528 case ':':
529 return *ctx->ptr++;
530
531 case '}':
532 *(const WCHAR**)lval = ctx->ptr++;
533 return '}';
534
535 case '.':
536 if(++ctx->ptr < ctx->end && isdigitW(*ctx->ptr))
537 return parse_double_literal(ctx, 0, lval);
538 return '.';
539
540 case '<':
541 if(++ctx->ptr == ctx->end) {
542 *(int*)lval = EXPR_LESS;
543 return tRelOper;
544 }
545
546 switch(*ctx->ptr) {
547 case '=': /* <= */
548 ctx->ptr++;
549 *(int*)lval = EXPR_LESSEQ;
550 return tRelOper;
551 case '<': /* << */
552 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* <<= */
553 ctx->ptr++;
554 *(int*)lval = EXPR_ASSIGNLSHIFT;
555 return tAssignOper;
556 }
557 *(int*)lval = EXPR_LSHIFT;
558 return tShiftOper;
559 default: /* < */
560 *(int*)lval = EXPR_LESS;
561 return tRelOper;
562 }
563
564 case '>':
565 if(++ctx->ptr == ctx->end) { /* > */
566 *(int*)lval = EXPR_GREATER;
567 return tRelOper;
568 }
569
570 switch(*ctx->ptr) {
571 case '=': /* >= */
572 ctx->ptr++;
573 *(int*)lval = EXPR_GREATEREQ;
574 return tRelOper;
575 case '>': /* >> */
576 if(++ctx->ptr < ctx->end) {
577 if(*ctx->ptr == '=') { /* >>= */
578 ctx->ptr++;
579 *(int*)lval = EXPR_ASSIGNRSHIFT;
580 return tAssignOper;
581 }
582 if(*ctx->ptr == '>') { /* >>> */
583 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* >>>= */
584 ctx->ptr++;
585 *(int*)lval = EXPR_ASSIGNRRSHIFT;
586 return tAssignOper;
587 }
588 *(int*)lval = EXPR_RRSHIFT;
589 return tRelOper;
590 }
591 }
592 *(int*)lval = EXPR_RSHIFT;
593 return tShiftOper;
594 default:
595 *(int*)lval = EXPR_GREATER;
596 return tRelOper;
597 }
598
599 case '+':
600 ctx->ptr++;
601 if(ctx->ptr < ctx->end) {
602 switch(*ctx->ptr) {
603 case '+': /* ++ */
604 ctx->ptr++;
605 return tINC;
606 case '=': /* += */
607 ctx->ptr++;
608 *(int*)lval = EXPR_ASSIGNADD;
609 return tAssignOper;
610 }
611 }
612 return '+';
613
614 case '-':
615 ctx->ptr++;
616 if(ctx->ptr < ctx->end) {
617 switch(*ctx->ptr) {
618 case '-': /* -- or --> */
619 ctx->ptr++;
620 if(ctx->is_html && ctx->nl && ctx->ptr < ctx->end && *ctx->ptr == '>') {
621 ctx->ptr++;
622 return tHTMLCOMMENT;
623 }
624 return tDEC;
625 case '=': /* -= */
626 ctx->ptr++;
627 *(int*)lval = EXPR_ASSIGNSUB;
628 return tAssignOper;
629 }
630 }
631 return '-';
632
633 case '*':
634 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* *= */
635 ctx->ptr++;
636 *(int*)lval = EXPR_ASSIGNMUL;
637 return tAssignOper;
638 }
639 return '*';
640
641 case '%':
642 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* %= */
643 ctx->ptr++;
644 *(int*)lval = EXPR_ASSIGNMOD;
645 return tAssignOper;
646 }
647 return '%';
648
649 case '&':
650 if(++ctx->ptr < ctx->end) {
651 switch(*ctx->ptr) {
652 case '=': /* &= */
653 ctx->ptr++;
654 *(int*)lval = EXPR_ASSIGNAND;
655 return tAssignOper;
656 case '&': /* && */
657 ctx->ptr++;
658 return tANDAND;
659 }
660 }
661 return '&';
662
663 case '|':
664 if(++ctx->ptr < ctx->end) {
665 switch(*ctx->ptr) {
666 case '=': /* |= */
667 ctx->ptr++;
668 *(int*)lval = EXPR_ASSIGNOR;
669 return tAssignOper;
670 case '|': /* || */
671 ctx->ptr++;
672 return tOROR;
673 }
674 }
675 return '|';
676
677 case '^':
678 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* ^= */
679 ctx->ptr++;
680 *(int*)lval = EXPR_ASSIGNXOR;
681 return tAssignOper;
682 }
683 return '^';
684
685 case '!':
686 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* != */
687 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* !== */
688 ctx->ptr++;
689 *(int*)lval = EXPR_NOTEQEQ;
690 return tEqOper;
691 }
692 *(int*)lval = EXPR_NOTEQ;
693 return tEqOper;
694 }
695 return '!';
696
697 case '=':
698 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* == */
699 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* === */
700 ctx->ptr++;
701 *(int*)lval = EXPR_EQEQ;
702 return tEqOper;
703 }
704 *(int*)lval = EXPR_EQ;
705 return tEqOper;
706 }
707 return '=';
708
709 case '/':
710 if(++ctx->ptr < ctx->end) {
711 if(*ctx->ptr == '=') { /* /= */
712 ctx->ptr++;
713 *(int*)lval = EXPR_ASSIGNDIV;
714 return kDIVEQ;
715 }
716 }
717 return '/';
718
719 case '\"':
720 case '\'':
721 return parse_string_literal(ctx, lval, *ctx->ptr);
722
723 case '_':
724 case '$':
725 return parse_identifier(ctx, lval);
726
727 case '@':
728 return '@';
729 }
730
731 WARN("unexpected char '%c' %d\n", *ctx->ptr, *ctx->ptr);
732 return 0;
733 }
734
735 struct _cc_var_t {
736 BOOL is_num;
737 union {
738 BOOL b;
739 DOUBLE n;
740 } u;
741 struct _cc_var_t *next;
742 unsigned name_len;
743 WCHAR name[0];
744 };
745
746 void release_cc(cc_ctx_t *cc)
747 {
748 cc_var_t *iter, *next;
749
750 for(iter = cc->vars; iter; iter = next) {
751 next = iter->next;
752 heap_free(iter);
753 }
754
755 heap_free(cc);
756 }
757
758 static BOOL add_cc_var(cc_ctx_t *cc, const WCHAR *name, cc_var_t *v)
759 {
760 cc_var_t *new_v;
761 unsigned len;
762
763 len = strlenW(name);
764
765 new_v = heap_alloc(sizeof(cc_var_t) + (len+1)*sizeof(WCHAR));
766 if(!new_v)
767 return FALSE;
768
769 memcpy(new_v, v, sizeof(*v));
770 memcpy(new_v->name, name, (len+1)*sizeof(WCHAR));
771 new_v->name_len = len;
772 new_v->next = cc->vars;
773 cc->vars = new_v;
774 return TRUE;
775 }
776
777 static cc_var_t *find_cc_var(cc_ctx_t *cc, const WCHAR *name, unsigned name_len)
778 {
779 cc_var_t *iter;
780
781 for(iter = cc->vars; iter; iter = iter->next) {
782 if(iter->name_len == name_len && !memcmp(iter->name, name, name_len*sizeof(WCHAR)))
783 return iter;
784 }
785
786 return NULL;
787 }
788
789 static int init_cc(parser_ctx_t *ctx)
790 {
791 cc_ctx_t *cc;
792 cc_var_t v;
793
794 static const WCHAR _win32W[] = {'_','w','i','n','3','2',0};
795 static const WCHAR _win64W[] = {'_','w','i','n','6','4',0};
796 static const WCHAR _x86W[] = {'_','x','8','6',0};
797 static const WCHAR _amd64W[] = {'_','a','m','d','6','4',0};
798 static const WCHAR _jscriptW[] = {'_','j','s','c','r','i','p','t',0};
799 static const WCHAR _jscript_buildW[] = {'_','j','s','c','r','i','p','t','_','b','u','i','l','d',0};
800 static const WCHAR _jscript_versionW[] = {'_','j','s','c','r','i','p','t','_','v','e','r','s','i','o','n',0};
801
802 if(ctx->script->cc)
803 return 0;
804
805 cc = heap_alloc(sizeof(cc_ctx_t));
806 if(!cc)
807 return lex_error(ctx, E_OUTOFMEMORY);
808
809 cc->vars = NULL;
810 v.is_num = FALSE;
811 v.u.b = TRUE;
812 if(!add_cc_var(cc, _jscriptW, &v)
813 || !add_cc_var(cc, sizeof(void*) == 8 ? _win64W : _win32W, &v)
814 || !add_cc_var(cc, sizeof(void*) == 8 ? _amd64W : _x86W, &v)) {
815 release_cc(cc);
816 return lex_error(ctx, E_OUTOFMEMORY);
817 }
818
819 v.is_num = TRUE;
820 v.u.n = JSCRIPT_BUILD_VERSION;
821 if(!add_cc_var(cc, _jscript_buildW, &v)) {
822 release_cc(cc);
823 return lex_error(ctx, E_OUTOFMEMORY);
824 }
825
826 v.u.n = JSCRIPT_MAJOR_VERSION + (DOUBLE)JSCRIPT_MINOR_VERSION/10.0;
827 if(!add_cc_var(cc, _jscript_versionW, &v)) {
828 release_cc(cc);
829 return lex_error(ctx, E_OUTOFMEMORY);
830 }
831
832 ctx->script->cc = cc;
833 return 0;
834 }
835
836 static int cc_token(parser_ctx_t *ctx, void *lval)
837 {
838 unsigned id_len = 0;
839 cc_var_t *var;
840
841 static const WCHAR cc_onW[] = {'c','c','_','o','n',0};
842 static const WCHAR setW[] = {'s','e','t',0};
843 static const WCHAR elifW[] = {'e','l','i','f',0};
844 static const WCHAR endW[] = {'e','n','d',0};
845
846 ctx->ptr++;
847
848 if(!check_keyword(ctx, cc_onW, NULL))
849 return init_cc(ctx);
850
851 if(!check_keyword(ctx, setW, NULL)) {
852 FIXME("@set not implemented\n");
853 return lex_error(ctx, E_NOTIMPL);
854 }
855
856 if(!check_keyword(ctx, ifW, NULL)) {
857 FIXME("@if not implemented\n");
858 return lex_error(ctx, E_NOTIMPL);
859 }
860
861 if(!check_keyword(ctx, elifW, NULL)) {
862 FIXME("@elif not implemented\n");
863 return lex_error(ctx, E_NOTIMPL);
864 }
865
866 if(!check_keyword(ctx, elseW, NULL)) {
867 FIXME("@else not implemented\n");
868 return lex_error(ctx, E_NOTIMPL);
869 }
870
871 if(!check_keyword(ctx, endW, NULL)) {
872 FIXME("@end not implemented\n");
873 return lex_error(ctx, E_NOTIMPL);
874 }
875
876 if(!ctx->script->cc)
877 return lex_error(ctx, JS_E_DISABLED_CC);
878
879 while(ctx->ptr+id_len < ctx->end && is_identifier_char(ctx->ptr[id_len]))
880 id_len++;
881 if(!id_len)
882 return '@';
883
884 TRACE("var %s\n", debugstr_wn(ctx->ptr, id_len));
885
886 var = find_cc_var(ctx->script->cc, ctx->ptr, id_len);
887 ctx->ptr += id_len;
888 if(!var || var->is_num) {
889 *(literal_t**)lval = new_double_literal(ctx, var ? var->u.n : NAN);
890 return tNumericLiteral;
891 }
892
893 *(literal_t**)lval = new_boolean_literal(ctx, var->u.b);
894 return tBooleanLiteral;
895 }
896
897 int parser_lex(void *lval, parser_ctx_t *ctx)
898 {
899 int ret;
900
901 ctx->nl = ctx->ptr == ctx->begin;
902
903 do {
904 ret = next_token(ctx, lval);
905 } while(ret == '@' && !(ret = cc_token(ctx, lval)));
906
907 return ret;
908 }
909
910 literal_t *parse_regexp(parser_ctx_t *ctx)
911 {
912 const WCHAR *re, *flags_ptr;
913 BOOL in_class = FALSE;
914 DWORD re_len, flags;
915 literal_t *ret;
916 HRESULT hres;
917
918 TRACE("\n");
919
920 while(*--ctx->ptr != '/');
921
922 /* Simple regexp pre-parser; '/' if used in char class does not terminate regexp literal */
923 re = ++ctx->ptr;
924 while(ctx->ptr < ctx->end) {
925 if(*ctx->ptr == '\\') {
926 if(++ctx->ptr == ctx->end)
927 break;
928 }else if(in_class) {
929 if(*ctx->ptr == '\n')
930 break;
931 if(*ctx->ptr == ']')
932 in_class = FALSE;
933 }else {
934 if(*ctx->ptr == '/')
935 break;
936
937 if(*ctx->ptr == '[')
938 in_class = TRUE;
939 }
940 ctx->ptr++;
941 }
942
943 if(ctx->ptr == ctx->end || *ctx->ptr != '/') {
944 WARN("pre-parsing failed\n");
945 return NULL;
946 }
947
948 re_len = ctx->ptr-re;
949
950 flags_ptr = ++ctx->ptr;
951 while(ctx->ptr < ctx->end && isalnumW(*ctx->ptr))
952 ctx->ptr++;
953
954 hres = parse_regexp_flags(flags_ptr, ctx->ptr-flags_ptr, &flags);
955 if(FAILED(hres))
956 return NULL;
957
958 ret = parser_alloc(ctx, sizeof(literal_t));
959 ret->type = LT_REGEXP;
960 ret->u.regexp.str = re;
961 ret->u.regexp.str_len = re_len;
962 ret->u.regexp.flags = flags;
963 return ret;
964 }