wininet: Access request object directly in WININET_SetAuthorization.
[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 } 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}
100 };
101
102 static int lex_error(parser_ctx_t *ctx, HRESULT hres)
103 {
104     ctx->hres = hres;
105     ctx->lexer_error = TRUE;
106     return -1;
107 }
108
109 /* ECMA-262 3rd Edition    7.6 */
110 static BOOL is_identifier_char(WCHAR c)
111 {
112     return isalnumW(c) || c == '$' || c == '_' || c == '\\';
113 }
114
115 static int check_keyword(parser_ctx_t *ctx, const WCHAR *word, const WCHAR **lval)
116 {
117     const WCHAR *p1 = ctx->ptr;
118     const WCHAR *p2 = word;
119
120     while(p1 < ctx->end && *p2) {
121         if(*p1 != *p2)
122             return *p1 - *p2;
123         p1++;
124         p2++;
125     }
126
127     if(*p2 || (p1 < ctx->end && is_identifier_char(*p1)))
128         return 1;
129
130     if(lval)
131         *lval = ctx->ptr;
132     ctx->ptr = p1;
133     return 0;
134 }
135
136 /* ECMA-262 3rd Edition    7.3 */
137 static BOOL is_endline(WCHAR c)
138 {
139     return c == '\n' || c == '\r' || c == 0x2028 || c == 0x2029;
140 }
141
142 static int hex_to_int(WCHAR c)
143 {
144     if('0' <= c && c <= '9')
145         return c-'0';
146
147     if('a' <= c && c <= 'f')
148         return c-'a'+10;
149
150     if('A' <= c && c <= 'F')
151         return c-'A'+10;
152
153     return -1;
154 }
155
156 static int check_keywords(parser_ctx_t *ctx, const WCHAR **lval)
157 {
158     int min = 0, max = sizeof(keywords)/sizeof(keywords[0])-1, r, i;
159
160     while(min <= max) {
161         i = (min+max)/2;
162
163         r = check_keyword(ctx, keywords[i].word, lval);
164         if(!r)
165             return keywords[i].token;
166
167         if(r > 0)
168             min = i+1;
169         else
170             max = i-1;
171     }
172
173     return 0;
174 }
175
176 static void skip_spaces(parser_ctx_t *ctx)
177 {
178     while(ctx->ptr < ctx->end && isspaceW(*ctx->ptr)) {
179         if(is_endline(*ctx->ptr++))
180             ctx->nl = TRUE;
181     }
182 }
183
184 static BOOL skip_html_comment(parser_ctx_t *ctx)
185 {
186     const WCHAR html_commentW[] = {'<','!','-','-',0};
187
188     if(!ctx->is_html || ctx->ptr+3 >= ctx->end ||
189         memcmp(ctx->ptr, html_commentW, sizeof(WCHAR)*4))
190         return FALSE;
191
192     ctx->nl = TRUE;
193     while(ctx->ptr < ctx->end && !is_endline(*ctx->ptr++));
194
195     return TRUE;
196 }
197
198 static BOOL skip_comment(parser_ctx_t *ctx)
199 {
200     if(ctx->ptr+1 >= ctx->end)
201         return FALSE;
202
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;
207         }
208
209         return FALSE;
210     }
211
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++;
219
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;
225         }
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;
236     }
237
238     return TRUE;
239 }
240
241 static BOOL unescape(WCHAR *str)
242 {
243     WCHAR *pd, *p, c;
244     int i;
245
246     pd = p = str;
247     while(*p) {
248         if(*p != '\\') {
249             *pd++ = *p++;
250             continue;
251         }
252
253         p++;
254
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;
281
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;
292
293             i = hex_to_int(*++p);
294             if(i == -1)
295                 return FALSE;
296             c += i << 8;
297
298             i = hex_to_int(*++p);
299             if(i == -1)
300                 return FALSE;
301             c += i << 4;
302
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');
315                 }
316                 p--;
317             }
318             else
319                 c = *p;
320         }
321
322         *pd++ = c;
323         p++;
324     }
325
326     *pd = 0;
327     return TRUE;
328 }
329
330 static int parse_identifier(parser_ctx_t *ctx, const WCHAR **ret)
331 {
332     const WCHAR *ptr = ctx->ptr++;
333     WCHAR *wstr;
334     int len;
335
336     while(ctx->ptr < ctx->end && is_identifier_char(*ctx->ptr))
337         ctx->ptr++;
338
339     len = ctx->ptr-ptr;
340
341     *ret = wstr = parser_alloc(ctx, (len+1)*sizeof(WCHAR));
342     memcpy(wstr, ptr, len*sizeof(WCHAR));
343     wstr[len] = 0;
344
345     /* FIXME: unescape */
346     return tIdentifier;
347 }
348
349 static int parse_string_literal(parser_ctx_t *ctx, const WCHAR **ret, WCHAR endch)
350 {
351     const WCHAR *ptr = ++ctx->ptr;
352     WCHAR *wstr;
353     int len;
354
355     while(ctx->ptr < ctx->end && *ctx->ptr != endch) {
356         if(*ctx->ptr++ == '\\')
357             ctx->ptr++;
358     }
359
360     if(ctx->ptr == ctx->end)
361         return lex_error(ctx, JS_E_UNTERMINATED_STRING);
362
363     len = ctx->ptr-ptr;
364
365     *ret = wstr = parser_alloc(ctx, (len+1)*sizeof(WCHAR));
366     memcpy(wstr, ptr, len*sizeof(WCHAR));
367     wstr[len] = 0;
368
369     ctx->ptr++;
370
371     if(!unescape(wstr)) {
372         WARN("unescape failed\n");
373         return lex_error(ctx, E_FAIL);
374     }
375
376     return tStringLiteral;
377 }
378
379 static literal_t *new_int_literal(parser_ctx_t *ctx, LONG l)
380 {
381     literal_t *ret = parser_alloc(ctx, sizeof(literal_t));
382
383     ret->type = LT_INT;
384     ret->u.lval = l;
385
386     return ret;
387 }
388
389 static literal_t *new_double_literal(parser_ctx_t *ctx, DOUBLE d)
390 {
391     literal_t *ret = parser_alloc(ctx, sizeof(literal_t));
392
393     ret->type = LT_DOUBLE;
394     ret->u.dval = d;
395     return ret;
396 }
397
398 literal_t *new_boolean_literal(parser_ctx_t *ctx, VARIANT_BOOL bval)
399 {
400     literal_t *ret = parser_alloc(ctx, sizeof(literal_t));
401
402     ret->type = LT_BOOL;
403     ret->u.bval = bval;
404
405     return ret;
406 }
407
408 static int parse_double_literal(parser_ctx_t *ctx, LONG int_part, literal_t **literal)
409 {
410     LONGLONG d, hlp;
411     int exp = 0;
412
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;
417     }
418
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;
425         }
426         else
427             d = hlp;
428     }
429     while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr)) {
430         exp++;
431         ctx->ptr++;
432     }
433
434     if(*ctx->ptr == '.') ctx->ptr++;
435
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;
440
441         d = hlp;
442         exp--;
443     }
444     while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr))
445         ctx->ptr++;
446
447     if(ctx->ptr < ctx->end && (*ctx->ptr == 'e' || *ctx->ptr == 'E')) {
448         int sign = 1, e = 0;
449
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);
460             }
461         }
462
463         if(ctx->ptr == ctx->end) {
464             WARN("unexpected end of file\n");
465             return lex_error(ctx, E_FAIL);
466         }
467
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;
471         }
472         e *= sign;
473
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;
477     }
478
479     *literal = new_double_literal(ctx, exp>=0 ? d*pow(10, exp) : d/pow(10, -exp));
480     return tNumericLiteral;
481 }
482
483 static int parse_numeric_literal(parser_ctx_t *ctx, literal_t **literal)
484 {
485     LONG l, d;
486
487     l = *ctx->ptr++ - '0';
488     if(ctx->ptr == ctx->end) {
489         *literal = new_int_literal(ctx, l);
490         return tNumericLiteral;
491     }
492
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;
498             }
499
500             while(ctx->ptr < ctx->end && (d = hex_to_int(*ctx->ptr)) != -1) {
501                 l = l*16 + d;
502                 ctx->ptr++;
503             }
504
505             if(ctx->ptr < ctx->end && is_identifier_char(*ctx->ptr)) {
506                 WARN("unexpected identifier char\n");
507                 return lex_error(ctx, E_FAIL);
508             }
509
510             *literal = new_int_literal(ctx, l);
511             return tNumericLiteral;
512         }
513
514         if(isdigitW(*ctx->ptr) || is_identifier_char(*ctx->ptr)) {
515             WARN("wrong char after zero\n");
516             return lex_error(ctx, E_FAIL);
517         }
518
519         *literal = new_int_literal(ctx, 0);
520     }
521
522     while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr))
523     {
524         d = l*10 + *(ctx->ptr)-'0';
525
526         /* Check for integer overflow */
527         if (l > INT_MAX/10 || d < 0)
528             return parse_double_literal(ctx, l, literal);
529
530         l = d;
531         ctx->ptr++;
532     }
533
534     if(ctx->ptr < ctx->end) {
535         if(*ctx->ptr == '.' || *ctx->ptr == 'e' || *ctx->ptr == 'E')
536             return parse_double_literal(ctx, l, literal);
537
538         if(is_identifier_char(*ctx->ptr)) {
539             WARN("unexpected identifier char\n");
540             return lex_error(ctx, E_FAIL);
541         }
542     }
543
544     *literal = new_int_literal(ctx, l);
545     return tNumericLiteral;
546 }
547
548 static int next_token(parser_ctx_t *ctx, void *lval)
549 {
550     do {
551         skip_spaces(ctx);
552         if(ctx->ptr == ctx->end)
553             return tEOF;
554     }while(skip_comment(ctx) || skip_html_comment(ctx));
555
556     if(isalphaW(*ctx->ptr)) {
557         int ret = check_keywords(ctx, lval);
558         if(ret)
559             return ret;
560
561         return parse_identifier(ctx, lval);
562     }
563
564     if(isdigitW(*ctx->ptr))
565         return parse_numeric_literal(ctx, lval);
566
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++;
579
580     case '}':
581         *(const WCHAR**)lval = ctx->ptr++;
582         return '}';
583
584     case '.':
585         if(++ctx->ptr < ctx->end && isdigitW(*ctx->ptr))
586             return parse_double_literal(ctx, 0, lval);
587         return '.';
588
589     case '<':
590         if(++ctx->ptr == ctx->end) {
591             *(int*)lval = EXPR_LESS;
592             return tRelOper;
593         }
594
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;
605             }
606             *(int*)lval = EXPR_LSHIFT;
607             return tShiftOper;
608         default: /* < */
609             *(int*)lval = EXPR_LESS;
610             return tRelOper;
611         }
612
613     case '>':
614         if(++ctx->ptr == ctx->end) { /* > */
615             *(int*)lval = EXPR_GREATER;
616             return tRelOper;
617         }
618
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;
630                 }
631                 if(*ctx->ptr == '>') {  /* >>> */
632                     if(++ctx->ptr < ctx->end && *ctx->ptr == '=') {  /* >>>= */
633                         ctx->ptr++;
634                         *(int*)lval = EXPR_ASSIGNRRSHIFT;
635                         return tAssignOper;
636                     }
637                     *(int*)lval = EXPR_RRSHIFT;
638                     return tRelOper;
639                 }
640             }
641             *(int*)lval = EXPR_RSHIFT;
642             return tShiftOper;
643         default:
644             *(int*)lval = EXPR_GREATER;
645             return tRelOper;
646         }
647
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;
659             }
660         }
661         return '+';
662
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;
672                 }
673                 return tDEC;
674             case '=':  /* -= */
675                 ctx->ptr++;
676                 *(int*)lval = EXPR_ASSIGNSUB;
677                 return tAssignOper;
678             }
679         }
680         return '-';
681
682     case '*':
683         if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* *= */
684             ctx->ptr++;
685             *(int*)lval = EXPR_ASSIGNMUL;
686             return tAssignOper;
687         }
688         return '*';
689
690     case '%':
691         if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* %= */
692             ctx->ptr++;
693             *(int*)lval = EXPR_ASSIGNMOD;
694             return tAssignOper;
695         }
696         return '%';
697
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;
708             }
709         }
710         return '&';
711
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;
722             }
723         }
724         return '|';
725
726     case '^':
727         if(++ctx->ptr < ctx->end && *ctx->ptr == '=') {  /* ^= */
728             ctx->ptr++;
729             *(int*)lval = EXPR_ASSIGNXOR;
730             return tAssignOper;
731         }
732         return '^';
733
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;
740             }
741             *(int*)lval = EXPR_NOTEQ;
742             return tEqOper;
743         }
744         return '!';
745
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;
752             }
753             *(int*)lval = EXPR_EQ;
754             return tEqOper;
755         }
756         return '=';
757
758     case '/':
759         if(++ctx->ptr < ctx->end) {
760             if(*ctx->ptr == '=') {  /* /= */
761                 ctx->ptr++;
762                 *(int*)lval = EXPR_ASSIGNDIV;
763                 return kDIVEQ;
764             }
765         }
766         return '/';
767
768     case '\"':
769     case '\'':
770         return parse_string_literal(ctx, lval, *ctx->ptr);
771
772     case '_':
773     case '$':
774         return parse_identifier(ctx, lval);
775
776     case '@':
777         return '@';
778     }
779
780     WARN("unexpected char '%c' %d\n", *ctx->ptr, *ctx->ptr);
781     return 0;
782 }
783
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];
793 };
794
795 void release_cc(cc_ctx_t *cc)
796 {
797     cc_var_t *iter, *next;
798
799     for(iter = cc->vars; iter; iter = next) {
800         next = iter->next;
801         heap_free(iter);
802     }
803
804     heap_free(cc);
805 }
806
807 static BOOL add_cc_var(cc_ctx_t *cc, const WCHAR *name, cc_var_t *v)
808 {
809     cc_var_t *new_v;
810     unsigned len;
811
812     len = strlenW(name);
813
814     new_v = heap_alloc(sizeof(cc_var_t) + (len+1)*sizeof(WCHAR));
815     if(!new_v)
816         return FALSE;
817
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;
824 }
825
826 static cc_var_t *find_cc_var(cc_ctx_t *cc, const WCHAR *name, unsigned name_len)
827 {
828     cc_var_t *iter;
829
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;
833     }
834
835     return NULL;
836 }
837
838 static int init_cc(parser_ctx_t *ctx)
839 {
840     cc_ctx_t *cc;
841     cc_var_t v;
842
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};
850
851     if(ctx->script->cc)
852         return 0;
853
854     cc = heap_alloc(sizeof(cc_ctx_t));
855     if(!cc)
856         return lex_error(ctx, E_OUTOFMEMORY);
857
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);
866     }
867
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);
873     }
874
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);
879     }
880
881     ctx->script->cc = cc;
882     return 0;
883 }
884
885 static int cc_token(parser_ctx_t *ctx, void *lval)
886 {
887     unsigned id_len = 0;
888     cc_var_t *var;
889
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};
894
895     ctx->ptr++;
896
897     if(!check_keyword(ctx, cc_onW, NULL))
898         return init_cc(ctx);
899
900     if(!check_keyword(ctx, setW, NULL)) {
901         FIXME("@set not implemented\n");
902         return lex_error(ctx, E_NOTIMPL);
903     }
904
905     if(!check_keyword(ctx, ifW, NULL)) {
906         FIXME("@if not implemented\n");
907         return lex_error(ctx, E_NOTIMPL);
908     }
909
910     if(!check_keyword(ctx, elifW, NULL)) {
911         FIXME("@elif not implemented\n");
912         return lex_error(ctx, E_NOTIMPL);
913     }
914
915     if(!check_keyword(ctx, elseW, NULL)) {
916         FIXME("@else not implemented\n");
917         return lex_error(ctx, E_NOTIMPL);
918     }
919
920     if(!check_keyword(ctx, endW, NULL)) {
921         FIXME("@end not implemented\n");
922         return lex_error(ctx, E_NOTIMPL);
923     }
924
925     if(!ctx->script->cc)
926         return lex_error(ctx, JS_E_DISABLED_CC);
927
928     while(ctx->ptr+id_len < ctx->end && is_identifier_char(ctx->ptr[id_len]))
929         id_len++;
930     if(!id_len)
931         return '@';
932
933     TRACE("var %s\n", debugstr_wn(ctx->ptr, id_len));
934
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;
940     }
941
942     *(literal_t**)lval = new_boolean_literal(ctx, var->u.b);
943     return tBooleanLiteral;
944 }
945
946 int parser_lex(void *lval, parser_ctx_t *ctx)
947 {
948     int ret;
949
950     ctx->nl = ctx->ptr == ctx->begin;
951
952     do {
953         ret = next_token(ctx, lval);
954     } while(ret == '@' && !(ret = cc_token(ctx, lval)));
955
956     return ret;
957 }
958
959 literal_t *parse_regexp(parser_ctx_t *ctx)
960 {
961     const WCHAR *re, *flags_ptr;
962     BOOL in_class = FALSE;
963     DWORD re_len, flags;
964     literal_t *ret;
965     HRESULT hres;
966
967     TRACE("\n");
968
969     while(*--ctx->ptr != '/');
970
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;
985
986             if(*ctx->ptr == '[')
987                 in_class = TRUE;
988         }
989         ctx->ptr++;
990     }
991
992     if(ctx->ptr == ctx->end || *ctx->ptr != '/') {
993         WARN("pre-parsing failed\n");
994         return NULL;
995     }
996
997     re_len = ctx->ptr-re;
998
999     flags_ptr = ++ctx->ptr;
1000     while(ctx->ptr < ctx->end && isalnumW(*ctx->ptr))
1001         ctx->ptr++;
1002
1003     hres = parse_regexp_flags(flags_ptr, ctx->ptr-flags_ptr, &flags);
1004     if(FAILED(hres))
1005         return NULL;
1006
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;
1013 }