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