Sync with trunk r63174.
[reactos.git] / 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>MAXLONGLONG/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>MAXLONGLONG/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 if(is_identifier_char(*ctx->ptr)) {
447 WARN("wrong char after zero\n");
448 return lex_error(ctx, JS_E_MISSING_SEMICOLON);
449 }
450
451 *literal = new_double_literal(ctx, exp>=0 ? d*pow(10, exp) : d/pow(10, -exp));
452 return tNumericLiteral;
453 }
454
455 static int parse_numeric_literal(parser_ctx_t *ctx, literal_t **literal)
456 {
457 LONG l, d;
458
459 l = *ctx->ptr++ - '0';
460 if(!l) {
461 if(*ctx->ptr == 'x' || *ctx->ptr == 'X') {
462 if(++ctx->ptr == ctx->end) {
463 ERR("unexpected end of file\n");
464 return 0;
465 }
466
467 while(ctx->ptr < ctx->end && (d = hex_to_int(*ctx->ptr)) != -1) {
468 l = l*16 + d;
469 ctx->ptr++;
470 }
471
472 if(ctx->ptr < ctx->end && is_identifier_char(*ctx->ptr)) {
473 WARN("unexpected identifier char\n");
474 return lex_error(ctx, JS_E_MISSING_SEMICOLON);
475 }
476
477 *literal = new_double_literal(ctx, l);
478 return tNumericLiteral;
479 }
480
481 if(isdigitW(*ctx->ptr)) {
482 unsigned base = 8;
483 const WCHAR *ptr;
484 double val = 0;
485
486 for(ptr = ctx->ptr; ptr < ctx->end && isdigitW(*ptr); ptr++) {
487 if(*ptr > '7') {
488 base = 10;
489 break;
490 }
491 }
492
493 do {
494 val = val*base + *ctx->ptr-'0';
495 }while(++ctx->ptr < ctx->end && isdigitW(*ctx->ptr));
496
497 /* FIXME: Do we need it here? */
498 if(ctx->ptr < ctx->end && (is_identifier_char(*ctx->ptr) || *ctx->ptr == '.')) {
499 WARN("wrong char after octal literal: '%c'\n", *ctx->ptr);
500 return lex_error(ctx, JS_E_MISSING_SEMICOLON);
501 }
502
503 *literal = new_double_literal(ctx, val);
504 return tNumericLiteral;
505 }
506
507 if(is_identifier_char(*ctx->ptr)) {
508 WARN("wrong char after zero\n");
509 return lex_error(ctx, JS_E_MISSING_SEMICOLON);
510 }
511 }
512
513 return parse_double_literal(ctx, l, literal);
514 }
515
516 static int next_token(parser_ctx_t *ctx, void *lval)
517 {
518 do {
519 while(ctx->ptr < ctx->end && isspaceW(*ctx->ptr)) {
520 if(is_endline(*ctx->ptr++))
521 ctx->nl = TRUE;
522 }
523 if(ctx->ptr == ctx->end)
524 return tEOF;
525 }while(skip_comment(ctx) || skip_html_comment(ctx));
526
527 if(ctx->implicit_nl_semicolon) {
528 if(ctx->nl)
529 return ';';
530 ctx->implicit_nl_semicolon = FALSE;
531 }
532
533 if(isalphaW(*ctx->ptr)) {
534 int ret = check_keywords(ctx, lval);
535 if(ret)
536 return ret;
537
538 return parse_identifier(ctx, lval);
539 }
540
541 if(isdigitW(*ctx->ptr))
542 return parse_numeric_literal(ctx, lval);
543
544 switch(*ctx->ptr) {
545 case '{':
546 case '(':
547 case ')':
548 case '[':
549 case ']':
550 case ';':
551 case ',':
552 case '~':
553 case '?':
554 case ':':
555 return *ctx->ptr++;
556
557 case '}':
558 *(const WCHAR**)lval = ctx->ptr++;
559 return '}';
560
561 case '.':
562 if(++ctx->ptr < ctx->end && isdigitW(*ctx->ptr))
563 return parse_double_literal(ctx, 0, lval);
564 return '.';
565
566 case '<':
567 if(++ctx->ptr == ctx->end) {
568 *(int*)lval = EXPR_LESS;
569 return tRelOper;
570 }
571
572 switch(*ctx->ptr) {
573 case '=': /* <= */
574 ctx->ptr++;
575 *(int*)lval = EXPR_LESSEQ;
576 return tRelOper;
577 case '<': /* << */
578 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* <<= */
579 ctx->ptr++;
580 *(int*)lval = EXPR_ASSIGNLSHIFT;
581 return tAssignOper;
582 }
583 *(int*)lval = EXPR_LSHIFT;
584 return tShiftOper;
585 default: /* < */
586 *(int*)lval = EXPR_LESS;
587 return tRelOper;
588 }
589
590 case '>':
591 if(++ctx->ptr == ctx->end) { /* > */
592 *(int*)lval = EXPR_GREATER;
593 return tRelOper;
594 }
595
596 switch(*ctx->ptr) {
597 case '=': /* >= */
598 ctx->ptr++;
599 *(int*)lval = EXPR_GREATEREQ;
600 return tRelOper;
601 case '>': /* >> */
602 if(++ctx->ptr < ctx->end) {
603 if(*ctx->ptr == '=') { /* >>= */
604 ctx->ptr++;
605 *(int*)lval = EXPR_ASSIGNRSHIFT;
606 return tAssignOper;
607 }
608 if(*ctx->ptr == '>') { /* >>> */
609 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* >>>= */
610 ctx->ptr++;
611 *(int*)lval = EXPR_ASSIGNRRSHIFT;
612 return tAssignOper;
613 }
614 *(int*)lval = EXPR_RRSHIFT;
615 return tRelOper;
616 }
617 }
618 *(int*)lval = EXPR_RSHIFT;
619 return tShiftOper;
620 default:
621 *(int*)lval = EXPR_GREATER;
622 return tRelOper;
623 }
624
625 case '+':
626 ctx->ptr++;
627 if(ctx->ptr < ctx->end) {
628 switch(*ctx->ptr) {
629 case '+': /* ++ */
630 ctx->ptr++;
631 return tINC;
632 case '=': /* += */
633 ctx->ptr++;
634 *(int*)lval = EXPR_ASSIGNADD;
635 return tAssignOper;
636 }
637 }
638 return '+';
639
640 case '-':
641 ctx->ptr++;
642 if(ctx->ptr < ctx->end) {
643 switch(*ctx->ptr) {
644 case '-': /* -- or --> */
645 ctx->ptr++;
646 if(ctx->is_html && ctx->nl && ctx->ptr < ctx->end && *ctx->ptr == '>') {
647 ctx->ptr++;
648 return tHTMLCOMMENT;
649 }
650 return tDEC;
651 case '=': /* -= */
652 ctx->ptr++;
653 *(int*)lval = EXPR_ASSIGNSUB;
654 return tAssignOper;
655 }
656 }
657 return '-';
658
659 case '*':
660 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* *= */
661 ctx->ptr++;
662 *(int*)lval = EXPR_ASSIGNMUL;
663 return tAssignOper;
664 }
665 return '*';
666
667 case '%':
668 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* %= */
669 ctx->ptr++;
670 *(int*)lval = EXPR_ASSIGNMOD;
671 return tAssignOper;
672 }
673 return '%';
674
675 case '&':
676 if(++ctx->ptr < ctx->end) {
677 switch(*ctx->ptr) {
678 case '=': /* &= */
679 ctx->ptr++;
680 *(int*)lval = EXPR_ASSIGNAND;
681 return tAssignOper;
682 case '&': /* && */
683 ctx->ptr++;
684 return tANDAND;
685 }
686 }
687 return '&';
688
689 case '|':
690 if(++ctx->ptr < ctx->end) {
691 switch(*ctx->ptr) {
692 case '=': /* |= */
693 ctx->ptr++;
694 *(int*)lval = EXPR_ASSIGNOR;
695 return tAssignOper;
696 case '|': /* || */
697 ctx->ptr++;
698 return tOROR;
699 }
700 }
701 return '|';
702
703 case '^':
704 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* ^= */
705 ctx->ptr++;
706 *(int*)lval = EXPR_ASSIGNXOR;
707 return tAssignOper;
708 }
709 return '^';
710
711 case '!':
712 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* != */
713 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* !== */
714 ctx->ptr++;
715 *(int*)lval = EXPR_NOTEQEQ;
716 return tEqOper;
717 }
718 *(int*)lval = EXPR_NOTEQ;
719 return tEqOper;
720 }
721 return '!';
722
723 case '=':
724 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* == */
725 if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* === */
726 ctx->ptr++;
727 *(int*)lval = EXPR_EQEQ;
728 return tEqOper;
729 }
730 *(int*)lval = EXPR_EQ;
731 return tEqOper;
732 }
733 return '=';
734
735 case '/':
736 if(++ctx->ptr < ctx->end) {
737 if(*ctx->ptr == '=') { /* /= */
738 ctx->ptr++;
739 *(int*)lval = EXPR_ASSIGNDIV;
740 return kDIVEQ;
741 }
742 }
743 return '/';
744
745 case '\"':
746 case '\'':
747 return parse_string_literal(ctx, lval, *ctx->ptr);
748
749 case '_':
750 case '$':
751 return parse_identifier(ctx, lval);
752
753 case '@':
754 return '@';
755 }
756
757 WARN("unexpected char '%c' %d\n", *ctx->ptr, *ctx->ptr);
758 return 0;
759 }
760
761 struct _cc_var_t {
762 BOOL is_num;
763 union {
764 BOOL b;
765 DOUBLE n;
766 } u;
767 struct _cc_var_t *next;
768 unsigned name_len;
769 WCHAR name[0];
770 };
771
772 void release_cc(cc_ctx_t *cc)
773 {
774 cc_var_t *iter, *next;
775
776 for(iter = cc->vars; iter; iter = next) {
777 next = iter->next;
778 heap_free(iter);
779 }
780
781 heap_free(cc);
782 }
783
784 static BOOL add_cc_var(cc_ctx_t *cc, const WCHAR *name, cc_var_t *v)
785 {
786 cc_var_t *new_v;
787 unsigned len;
788
789 len = strlenW(name);
790
791 new_v = heap_alloc(sizeof(cc_var_t) + (len+1)*sizeof(WCHAR));
792 if(!new_v)
793 return FALSE;
794
795 memcpy(new_v, v, sizeof(*v));
796 memcpy(new_v->name, name, (len+1)*sizeof(WCHAR));
797 new_v->name_len = len;
798 new_v->next = cc->vars;
799 cc->vars = new_v;
800 return TRUE;
801 }
802
803 static cc_var_t *find_cc_var(cc_ctx_t *cc, const WCHAR *name, unsigned name_len)
804 {
805 cc_var_t *iter;
806
807 for(iter = cc->vars; iter; iter = iter->next) {
808 if(iter->name_len == name_len && !memcmp(iter->name, name, name_len*sizeof(WCHAR)))
809 return iter;
810 }
811
812 return NULL;
813 }
814
815 static int init_cc(parser_ctx_t *ctx)
816 {
817 cc_ctx_t *cc;
818 cc_var_t v;
819
820 static const WCHAR _win32W[] = {'_','w','i','n','3','2',0};
821 static const WCHAR _win64W[] = {'_','w','i','n','6','4',0};
822 static const WCHAR _x86W[] = {'_','x','8','6',0};
823 static const WCHAR _amd64W[] = {'_','a','m','d','6','4',0};
824 static const WCHAR _jscriptW[] = {'_','j','s','c','r','i','p','t',0};
825 static const WCHAR _jscript_buildW[] = {'_','j','s','c','r','i','p','t','_','b','u','i','l','d',0};
826 static const WCHAR _jscript_versionW[] = {'_','j','s','c','r','i','p','t','_','v','e','r','s','i','o','n',0};
827
828 if(ctx->script->cc)
829 return 0;
830
831 cc = heap_alloc(sizeof(cc_ctx_t));
832 if(!cc)
833 return lex_error(ctx, E_OUTOFMEMORY);
834
835 cc->vars = NULL;
836 v.is_num = FALSE;
837 v.u.b = TRUE;
838 if(!add_cc_var(cc, _jscriptW, &v)
839 || !add_cc_var(cc, sizeof(void*) == 8 ? _win64W : _win32W, &v)
840 || !add_cc_var(cc, sizeof(void*) == 8 ? _amd64W : _x86W, &v)) {
841 release_cc(cc);
842 return lex_error(ctx, E_OUTOFMEMORY);
843 }
844
845 v.is_num = TRUE;
846 v.u.n = JSCRIPT_BUILD_VERSION;
847 if(!add_cc_var(cc, _jscript_buildW, &v)) {
848 release_cc(cc);
849 return lex_error(ctx, E_OUTOFMEMORY);
850 }
851
852 v.u.n = JSCRIPT_MAJOR_VERSION + (DOUBLE)JSCRIPT_MINOR_VERSION/10.0;
853 if(!add_cc_var(cc, _jscript_versionW, &v)) {
854 release_cc(cc);
855 return lex_error(ctx, E_OUTOFMEMORY);
856 }
857
858 ctx->script->cc = cc;
859 return 0;
860 }
861
862 static int cc_token(parser_ctx_t *ctx, void *lval)
863 {
864 unsigned id_len = 0;
865 cc_var_t *var;
866
867 static const WCHAR cc_onW[] = {'c','c','_','o','n',0};
868 static const WCHAR setW[] = {'s','e','t',0};
869 static const WCHAR elifW[] = {'e','l','i','f',0};
870 static const WCHAR endW[] = {'e','n','d',0};
871
872 ctx->ptr++;
873
874 if(!check_keyword(ctx, cc_onW, NULL))
875 return init_cc(ctx);
876
877 if(!check_keyword(ctx, setW, NULL)) {
878 FIXME("@set not implemented\n");
879 return lex_error(ctx, E_NOTIMPL);
880 }
881
882 if(!check_keyword(ctx, ifW, NULL)) {
883 FIXME("@if not implemented\n");
884 return lex_error(ctx, E_NOTIMPL);
885 }
886
887 if(!check_keyword(ctx, elifW, NULL)) {
888 FIXME("@elif not implemented\n");
889 return lex_error(ctx, E_NOTIMPL);
890 }
891
892 if(!check_keyword(ctx, elseW, NULL)) {
893 FIXME("@else not implemented\n");
894 return lex_error(ctx, E_NOTIMPL);
895 }
896
897 if(!check_keyword(ctx, endW, NULL)) {
898 FIXME("@end not implemented\n");
899 return lex_error(ctx, E_NOTIMPL);
900 }
901
902 if(!ctx->script->cc)
903 return lex_error(ctx, JS_E_DISABLED_CC);
904
905 while(ctx->ptr+id_len < ctx->end && is_identifier_char(ctx->ptr[id_len]))
906 id_len++;
907 if(!id_len)
908 return '@';
909
910 TRACE("var %s\n", debugstr_wn(ctx->ptr, id_len));
911
912 var = find_cc_var(ctx->script->cc, ctx->ptr, id_len);
913 ctx->ptr += id_len;
914 if(!var || var->is_num) {
915 *(literal_t**)lval = new_double_literal(ctx, var ? var->u.n : NAN);
916 return tNumericLiteral;
917 }
918
919 *(literal_t**)lval = new_boolean_literal(ctx, var->u.b);
920 return tBooleanLiteral;
921 }
922
923 int parser_lex(void *lval, parser_ctx_t *ctx)
924 {
925 int ret;
926
927 ctx->nl = ctx->ptr == ctx->begin;
928
929 do {
930 ret = next_token(ctx, lval);
931 } while(ret == '@' && !(ret = cc_token(ctx, lval)));
932
933 return ret;
934 }
935
936 literal_t *parse_regexp(parser_ctx_t *ctx)
937 {
938 const WCHAR *re, *flags_ptr;
939 BOOL in_class = FALSE;
940 DWORD re_len, flags;
941 literal_t *ret;
942 HRESULT hres;
943
944 TRACE("\n");
945
946 while(*--ctx->ptr != '/');
947
948 /* Simple regexp pre-parser; '/' if used in char class does not terminate regexp literal */
949 re = ++ctx->ptr;
950 while(ctx->ptr < ctx->end) {
951 if(*ctx->ptr == '\\') {
952 if(++ctx->ptr == ctx->end)
953 break;
954 }else if(in_class) {
955 if(*ctx->ptr == '\n')
956 break;
957 if(*ctx->ptr == ']')
958 in_class = FALSE;
959 }else {
960 if(*ctx->ptr == '/')
961 break;
962
963 if(*ctx->ptr == '[')
964 in_class = TRUE;
965 }
966 ctx->ptr++;
967 }
968
969 if(ctx->ptr == ctx->end || *ctx->ptr != '/') {
970 WARN("pre-parsing failed\n");
971 return NULL;
972 }
973
974 re_len = ctx->ptr-re;
975
976 flags_ptr = ++ctx->ptr;
977 while(ctx->ptr < ctx->end && isalnumW(*ctx->ptr))
978 ctx->ptr++;
979
980 hres = parse_regexp_flags(flags_ptr, ctx->ptr-flags_ptr, &flags);
981 if(FAILED(hres))
982 return NULL;
983
984 ret = parser_alloc(ctx, sizeof(literal_t));
985 ret->type = LT_REGEXP;
986 ret->u.regexp.str = re;
987 ret->u.regexp.str_len = re_len;
988 ret->u.regexp.flags = flags;
989 return ret;
990 }