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