user32/tests: Fix the listbox delete test on NT4.
[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 static const WCHAR breakW[] = {'b','r','e','a','k',0};
35 static const WCHAR caseW[] = {'c','a','s','e',0};
36 static const WCHAR catchW[] = {'c','a','t','c','h',0};
37 static const WCHAR continueW[] = {'c','o','n','t','i','n','u','e',0};
38 static const WCHAR defaultW[] = {'d','e','f','a','u','l','t',0};
39 static const WCHAR deleteW[] = {'d','e','l','e','t','e',0};
40 static const WCHAR doW[] = {'d','o',0};
41 static const WCHAR elseW[] = {'e','l','s','e',0};
42 static const WCHAR falseW[] = {'f','a','l','s','e',0};
43 static const WCHAR finallyW[] = {'f','i','n','a','l','l','y',0};
44 static const WCHAR forW[] = {'f','o','r',0};
45 static const WCHAR functionW[] = {'f','u','n','c','t','i','o','n',0};
46 static const WCHAR ifW[] = {'i','f',0};
47 static const WCHAR inW[] = {'i','n',0};
48 static const WCHAR instanceofW[] = {'i','n','s','t','a','n','c','e','o','f',0};
49 static const WCHAR newW[] = {'n','e','w',0};
50 static const WCHAR nullW[] = {'n','u','l','l',0};
51 static const WCHAR returnW[] = {'r','e','t','u','r','n',0};
52 static const WCHAR switchW[] = {'s','w','i','t','c','h',0};
53 static const WCHAR thisW[] = {'t','h','i','s',0};
54 static const WCHAR throwW[] = {'t','h','r','o','w',0};
55 static const WCHAR trueW[] = {'t','r','u','e',0};
56 static const WCHAR tryW[] = {'t','r','y',0};
57 static const WCHAR typeofW[] = {'t','y','p','e','o','f',0};
58 static const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};
59 static const WCHAR varW[] = {'v','a','r',0};
60 static const WCHAR voidW[] = {'v','o','i','d',0};
61 static const WCHAR whileW[] = {'w','h','i','l','e',0};
62 static const WCHAR withW[] = {'w','i','t','h',0};
63
64 static const struct {
65     const WCHAR *word;
66     int token;
67 } keywords[] = {
68     {breakW,       kBREAK},
69     {caseW,        kCASE},
70     {catchW,       kCATCH},
71     {continueW,    kCONTINUE},
72     {defaultW,     kDEFAULT},
73     {deleteW,      kDELETE},
74     {doW,          kDO},
75     {elseW,        kELSE},
76     {falseW,       kFALSE},
77     {finallyW,     kFINALLY},
78     {forW,         kFOR},
79     {functionW,    kFUNCTION},
80     {ifW,          kIF},
81     {inW,          kIN},
82     {instanceofW,  kINSTANCEOF},
83     {newW,         kNEW},
84     {nullW,        kNULL},
85     {returnW,      kRETURN},
86     {switchW,      kSWITCH},
87     {thisW,        kTHIS},
88     {throwW,       kTHROW},
89     {trueW,        kTRUE},
90     {tryW,         kTRY},
91     {typeofW,      kTYPEOF},
92     {undefinedW,   kUNDEFINED},
93     {varW,         kVAR},
94     {voidW,        kVOID},
95     {whileW,       kWHILE},
96     {withW,        kWITH}
97 };
98
99 static int lex_error(parser_ctx_t *ctx, HRESULT hres)
100 {
101     ctx->hres = hres;
102     return -1;
103 }
104
105 static int check_keyword(parser_ctx_t *ctx, const WCHAR *word, const WCHAR **lval)
106 {
107     const WCHAR *p1 = ctx->ptr;
108     const WCHAR *p2 = word;
109
110     while(p1 < ctx->end && *p2) {
111         if(*p1 != *p2)
112             return *p1 - *p2;
113         p1++;
114         p2++;
115     }
116
117     if(*p2 || (p1 < ctx->end && isalnumW(*p1)))
118         return 1;
119
120     *lval = ctx->ptr;
121     ctx->ptr = p1;
122     return 0;
123 }
124
125 /* ECMA-262 3rd Edition    7.3 */
126 static BOOL is_endline(WCHAR c)
127 {
128     return c == '\n' || c == '\r' || c == 0x2028 || c == 0x2029;
129 }
130
131 static BOOL is_identifier_char(WCHAR c)
132 {
133     return isalnumW(c) || c == '$' || c == '_' || c == '\\';
134 }
135
136 static int hex_to_int(WCHAR c)
137 {
138     if('0' <= c && c <= '9')
139         return c-'0';
140
141     if('a' <= c && c <= 'f')
142         return c-'a'+10;
143
144     if('A' <= c && c <= 'F')
145         return c-'A'+10;
146
147     return -1;
148 }
149
150 static int check_keywords(parser_ctx_t *ctx, const WCHAR **lval)
151 {
152     int min = 0, max = sizeof(keywords)/sizeof(keywords[0])-1, r, i;
153
154     while(min <= max) {
155         i = (min+max)/2;
156
157         r = check_keyword(ctx, keywords[i].word, lval);
158         if(!r)
159             return keywords[i].token;
160
161         if(r > 0)
162             min = i+1;
163         else
164             max = i-1;
165     }
166
167     return 0;
168 }
169
170 static void skip_spaces(parser_ctx_t *ctx)
171 {
172     while(ctx->ptr < ctx->end && isspaceW(*ctx->ptr)) {
173         if(is_endline(*ctx->ptr++))
174             ctx->nl = TRUE;
175     }
176 }
177
178 static BOOL skip_html_comment(parser_ctx_t *ctx)
179 {
180     const WCHAR html_commentW[] = {'<','!','-','-',0};
181
182     if(!ctx->is_html || ctx->ptr+3 >= ctx->end ||
183         memcmp(ctx->ptr, html_commentW, sizeof(WCHAR)*4))
184         return FALSE;
185
186     ctx->nl = TRUE;
187     while(ctx->ptr < ctx->end && !is_endline(*ctx->ptr++));
188
189     return TRUE;
190 }
191
192 static BOOL skip_comment(parser_ctx_t *ctx)
193 {
194     if(ctx->ptr+1 >= ctx->end || *ctx->ptr != '/')
195         return FALSE;
196
197     switch(ctx->ptr[1]) {
198     case '*':
199         ctx->ptr += 2;
200         while(ctx->ptr+1 < ctx->end && (ctx->ptr[0] != '*' || ctx->ptr[1] != '/'))
201             ctx->ptr++;
202
203         if(ctx->ptr[0] == '*' && ctx->ptr[1] == '/') {
204             ctx->ptr += 2;
205         }else {
206             WARN("unexpected end of file (missing end of comment)\n");
207             ctx->ptr = ctx->end;
208         }
209         break;
210     case '/':
211         ctx->ptr += 2;
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         c = 0;
236
237         switch(*p) {
238         case '\'':
239         case '\"':
240         case '\\':
241             c = *p;
242             break;
243         case 'b':
244             c = '\b';
245             break;
246         case 't':
247             c = '\t';
248             break;
249         case 'n':
250             c = '\n';
251             break;
252         case 'v':
253             c = '\v';
254             break;
255         case 'f':
256             c = '\f';
257             break;
258         case 'r':
259             c = '\r';
260             break;
261         case 'x':
262             i = hex_to_int(*++p);
263             if(i == -1)
264                 return FALSE;
265             c = i << 4;
266
267             i = hex_to_int(*++p);
268             if(i == -1)
269                 return FALSE;
270             c += i;
271             break;
272         case 'u':
273             i = hex_to_int(*++p);
274             if(i == -1)
275                 return FALSE;
276             c = i << 12;
277
278             i = hex_to_int(*++p);
279             if(i == -1)
280                 return FALSE;
281             c += i << 8;
282
283             i = hex_to_int(*++p);
284             if(i == -1)
285                 return FALSE;
286             c += 1 << 4;
287
288             i = hex_to_int(*++p);
289             if(i == -1)
290                 return FALSE;
291             c += i;
292             break;
293         default:
294             if(isdigitW(*p)) {
295                 c = *p++ - '0';
296                 while(isdigitW(*p))
297                     c = c*10 + (*p++ - '0');
298                 *pd++ = c;
299                 continue;
300             }
301
302             c = *p;
303         }
304
305         *pd++ = c;
306         p++;
307     }
308
309     *pd = 0;
310     return TRUE;
311 }
312
313 static int parse_identifier(parser_ctx_t *ctx, const WCHAR **ret)
314 {
315     const WCHAR *ptr = ctx->ptr++;
316     WCHAR *wstr;
317     int len;
318
319     while(ctx->ptr < ctx->end && is_identifier_char(*ctx->ptr))
320         ctx->ptr++;
321
322     len = ctx->ptr-ptr;
323
324     *ret = wstr = parser_alloc(ctx, (len+1)*sizeof(WCHAR));
325     memcpy(wstr, ptr, (len+1)*sizeof(WCHAR));
326     wstr[len] = 0;
327
328     /* FIXME: unescape */
329     return tIdentifier;
330 }
331
332 static int parse_string_literal(parser_ctx_t *ctx, const WCHAR **ret, WCHAR endch)
333 {
334     const WCHAR *ptr = ++ctx->ptr;
335     WCHAR *wstr;
336     int len;
337
338     while(ctx->ptr < ctx->end && *ctx->ptr != endch) {
339         if(*ctx->ptr++ == '\\')
340             ctx->ptr++;
341     }
342
343     if(ctx->ptr == ctx->end) {
344         WARN("unexpected end of file\n");
345         return lex_error(ctx, E_FAIL);
346     }
347
348     len = ctx->ptr-ptr;
349
350     *ret = wstr = parser_alloc(ctx, (len+1)*sizeof(WCHAR));
351     memcpy(wstr, ptr, (len+1)*sizeof(WCHAR));
352     wstr[len] = 0;
353
354     ctx->ptr++;
355
356     if(!unescape(wstr)) {
357         WARN("unescape failed\n");
358         return lex_error(ctx, E_FAIL);
359     }
360
361     return tStringLiteral;
362 }
363
364 static literal_t *alloc_int_literal(parser_ctx_t *ctx, LONG l)
365 {
366     literal_t *ret = parser_alloc(ctx, sizeof(literal_t));
367
368     ret->vt = VT_I4;
369     ret->u.lval = l;
370
371     return ret;
372 }
373
374 static int parse_double_literal(parser_ctx_t *ctx, LONG int_part, literal_t **literal)
375 {
376     double d, tmp = 1.0;
377
378     if(ctx->ptr == ctx->end || (!isdigitW(*ctx->ptr) &&
379         *ctx->ptr!='.' && *ctx->ptr!='e' && *ctx->ptr!='E')) {
380         ERR("Illegal character\n");
381         return 0;
382     }
383
384     d = int_part;
385     while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr))
386         d = d*10 + *(ctx->ptr++) - '0';
387
388     if(*ctx->ptr == '.') ctx->ptr++;
389
390     while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr))
391         d += (tmp /= 10.0)*(*ctx->ptr++ - '0');
392
393     if(ctx->ptr < ctx->end && (*ctx->ptr == 'e' || *ctx->ptr == 'E')) {
394         int sign = 1, e = 0;
395
396         ctx->ptr++;
397         if(ctx->ptr < ctx->end) {
398             if(*ctx->ptr == '+') {
399                 ctx->ptr++;
400             }else if(*ctx->ptr == '-') {
401                 sign = -1;
402                 ctx->ptr++;
403             }else if(!isdigitW(*ctx->ptr)) {
404                 WARN("Expected exponent part\n");
405                 return lex_error(ctx, E_FAIL);
406             }
407         }
408
409         if(ctx->ptr == ctx->end) {
410             WARN("unexpected end of file\n");
411             return lex_error(ctx, E_FAIL);
412         }
413
414         while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr))
415             e = e*10 + *ctx->ptr++ - '0';
416         e *= sign;
417
418         d *= pow(10, e);
419     }
420
421     *literal = parser_alloc(ctx, sizeof(literal_t));
422     (*literal)->vt = VT_R8;
423     (*literal)->u.dval = d;
424
425     return tNumericLiteral;
426 }
427
428 static int parse_numeric_literal(parser_ctx_t *ctx, literal_t **literal)
429 {
430     LONG l, d;
431
432     l = *ctx->ptr++ - '0';
433     if(ctx->ptr == ctx->end) {
434         *literal = alloc_int_literal(ctx, l);
435         return tNumericLiteral;
436     }
437
438     if(!l) {
439         if(*ctx->ptr == 'x' || *ctx->ptr == 'X') {
440             if(++ctx->ptr == ctx->end) {
441                 ERR("unexpexted end of file\n");
442                 return 0;
443             }
444
445             while(ctx->ptr < ctx->end && (d = hex_to_int(*ctx->ptr)) != -1) {
446                 l = l*16 + d;
447                 ctx->ptr++;
448             }
449
450             if(ctx->ptr < ctx->end && is_identifier_char(*ctx->ptr)) {
451                 WARN("unexpected identifier char\n");
452                 return lex_error(ctx, E_FAIL);
453             }
454
455             *literal = alloc_int_literal(ctx, l);
456             return tNumericLiteral;
457         }
458
459         if(isdigitW(*ctx->ptr) || is_identifier_char(*ctx->ptr)) {
460             WARN("wrong char after zero\n");
461             return lex_error(ctx, E_FAIL);
462         }
463
464         *literal = alloc_int_literal(ctx, 0);
465     }
466
467     while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr))
468     {
469         d = l*10 + *(ctx->ptr)-'0';
470
471         /* Check for integer overflow */
472         if (l > INT_MAX/10 || d < 0)
473             return parse_double_literal(ctx, l, literal);
474
475         l = d;
476         ctx->ptr++;
477     }
478
479     if(ctx->ptr < ctx->end) {
480         if(*ctx->ptr == '.' || *ctx->ptr == 'e' || *ctx->ptr == 'E')
481             return parse_double_literal(ctx, l, literal);
482
483         if(is_identifier_char(*ctx->ptr)) {
484             WARN("unexpected identifier char\n");
485             return lex_error(ctx, E_FAIL);
486         }
487     }
488
489     *literal = alloc_int_literal(ctx, l);
490     return tNumericLiteral;
491 }
492
493 int parser_lex(void *lval, parser_ctx_t *ctx)
494 {
495     int ret;
496
497     ctx->nl = ctx->ptr == ctx->begin;
498
499     do {
500         skip_spaces(ctx);
501         if(ctx->ptr == ctx->end)
502             return 0;
503     }while(skip_comment(ctx) || skip_html_comment(ctx));
504
505     if(isalphaW(*ctx->ptr)) {
506         ret = check_keywords(ctx, lval);
507         if(ret)
508             return ret;
509
510         return parse_identifier(ctx, lval);
511     }
512
513     if(isdigitW(*ctx->ptr))
514         return parse_numeric_literal(ctx, lval);
515
516     switch(*ctx->ptr) {
517     case '{':
518     case '(':
519     case ')':
520     case '[':
521     case ']':
522     case ';':
523     case ',':
524     case '~':
525     case '?':
526     case ':':
527         return *ctx->ptr++;
528
529     case '}':
530         *(const WCHAR**)lval = ctx->ptr++;
531         return '}';
532
533     case '.':
534         if(++ctx->ptr < ctx->end && isdigitW(*ctx->ptr))
535             return parse_double_literal(ctx, 0, lval);
536         return '.';
537
538     case '<':
539         if(++ctx->ptr == ctx->end) {
540             *(int*)lval = EXPR_LESS;
541             return tRelOper;
542         }
543
544         switch(*ctx->ptr) {
545         case '=':  /* <= */
546             ctx->ptr++;
547             *(int*)lval = EXPR_LESSEQ;
548             return tRelOper;
549         case '<':  /* << */
550             if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* <<= */
551                 ctx->ptr++;
552                 *(int*)lval = EXPR_ASSIGNLSHIFT;
553                 return tAssignOper;
554             }
555             *(int*)lval = EXPR_LSHIFT;
556             return tShiftOper;
557         default: /* < */
558             *(int*)lval = EXPR_LESS;
559             return tRelOper;
560         }
561
562     case '>':
563         if(++ctx->ptr == ctx->end) { /* > */
564             *(int*)lval = EXPR_GREATER;
565             return tRelOper;
566         }
567
568         switch(*ctx->ptr) {
569         case '=':  /* >= */
570             ctx->ptr++;
571             *(int*)lval = EXPR_GREATEREQ;
572             return tRelOper;
573         case '>':  /* >> */
574             if(++ctx->ptr < ctx->end) {
575                 if(*ctx->ptr == '=') {  /* >>= */
576                     ctx->ptr++;
577                     *(int*)lval = EXPR_ASSIGNRSHIFT;
578                     return tAssignOper;
579                 }
580                 if(*ctx->ptr == '>') {  /* >>> */
581                     if(++ctx->ptr < ctx->end && *ctx->ptr == '=') {  /* >>>= */
582                         ctx->ptr++;
583                         *(int*)lval = EXPR_ASSIGNRRSHIFT;
584                         return tAssignOper;
585                     }
586                     *(int*)lval = EXPR_RRSHIFT;
587                     return tRelOper;
588                 }
589             }
590             *(int*)lval = EXPR_RSHIFT;
591             return tShiftOper;
592         default:
593             *(int*)lval = EXPR_GREATER;
594             return tRelOper;
595         }
596
597     case '+':
598         ctx->ptr++;
599         if(ctx->ptr < ctx->end) {
600             switch(*ctx->ptr) {
601             case '+':  /* ++ */
602                 ctx->ptr++;
603                 return tINC;
604             case '=':  /* += */
605                 ctx->ptr++;
606                 *(int*)lval = EXPR_ASSIGNADD;
607                 return tAssignOper;
608             }
609         }
610         return '+';
611
612     case '-':
613         ctx->ptr++;
614         if(ctx->ptr < ctx->end) {
615             switch(*ctx->ptr) {
616             case '-':  /* -- or --> */
617                 ctx->ptr++;
618                 if(ctx->is_html && ctx->nl && ctx->ptr < ctx->end && *ctx->ptr == '>') {
619                     ctx->ptr++;
620                     return tHTMLCOMMENT;
621                 }
622                 return tDEC;
623             case '=':  /* -= */
624                 ctx->ptr++;
625                 *(int*)lval = EXPR_ASSIGNSUB;
626                 return tAssignOper;
627             }
628         }
629         return '-';
630
631     case '*':
632         if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* *= */
633             ctx->ptr++;
634             *(int*)lval = EXPR_ASSIGNMUL;
635             return tAssignOper;
636         }
637         return '*';
638
639     case '%':
640         if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* %= */
641             ctx->ptr++;
642             *(int*)lval = EXPR_ASSIGNMOD;
643             return tAssignOper;
644         }
645         return '%';
646
647     case '&':
648         if(++ctx->ptr < ctx->end) {
649             switch(*ctx->ptr) {
650             case '=':  /* &= */
651                 ctx->ptr++;
652                 *(int*)lval = EXPR_ASSIGNAND;
653                 return tAssignOper;
654             case '&':  /* && */
655                 ctx->ptr++;
656                 return tANDAND;
657             }
658         }
659         return '&';
660
661     case '|':
662         if(++ctx->ptr < ctx->end) {
663             switch(*ctx->ptr) {
664             case '=':  /* |= */
665                 ctx->ptr++;
666                 *(int*)lval = EXPR_ASSIGNOR;
667                 return tAssignOper;
668             case '|':  /* || */
669                 ctx->ptr++;
670                 return tOROR;
671             }
672         }
673         return '|';
674
675     case '^':
676         if(++ctx->ptr < ctx->end && *ctx->ptr == '=') {  /* ^= */
677             ctx->ptr++;
678             *(int*)lval = EXPR_ASSIGNXOR;
679             return tAssignOper;
680         }
681         return '^';
682
683     case '!':
684         if(++ctx->ptr < ctx->end && *ctx->ptr == '=') {  /* != */
685             if(++ctx->ptr < ctx->end && *ctx->ptr == '=') {  /* !== */
686                 ctx->ptr++;
687                 *(int*)lval = EXPR_NOTEQEQ;
688                 return tEqOper;
689             }
690             *(int*)lval = EXPR_NOTEQ;
691             return tEqOper;
692         }
693         return '!';
694
695     case '=':
696         if(++ctx->ptr < ctx->end && *ctx->ptr == '=') {  /* == */
697             if(++ctx->ptr < ctx->end && *ctx->ptr == '=') {  /* === */
698                 ctx->ptr++;
699                 *(int*)lval = EXPR_EQEQ;
700                 return tEqOper;
701             }
702             *(int*)lval = EXPR_EQ;
703             return tEqOper;
704         }
705         return '=';
706
707     case '/':
708         if(++ctx->ptr < ctx->end) {
709             if(*ctx->ptr == '=') {  /* /= */
710                 ctx->ptr++;
711                 *(int*)lval = EXPR_ASSIGNDIV;
712                 return tAssignOper;
713             }
714         }
715         return '/';
716
717     case '\"':
718     case '\'':
719         return parse_string_literal(ctx, lval, *ctx->ptr);
720
721     case '_':
722     case '$':
723         return parse_identifier(ctx, lval);
724     }
725
726     WARN("unexpected char '%c' %d\n", *ctx->ptr, *ctx->ptr);
727     return 0;
728 }
729
730 static void add_object_literal(parser_ctx_t *ctx, DispatchEx *obj)
731 {
732     obj_literal_t *literal = parser_alloc(ctx, sizeof(obj_literal_t));
733
734     literal->obj = obj;
735     literal->next = ctx->obj_literals;
736     ctx->obj_literals = literal;
737 }
738
739 literal_t *parse_regexp(parser_ctx_t *ctx)
740 {
741     const WCHAR *re, *flags;
742     DispatchEx *regexp;
743     literal_t *ret;
744     DWORD re_len;
745     HRESULT hres;
746
747     TRACE("\n");
748
749     re = ctx->ptr;
750     while(ctx->ptr < ctx->end && *ctx->ptr != '/') {
751         if(*ctx->ptr++ == '\\' && ctx->ptr < ctx->end)
752             ctx->ptr++;
753     }
754
755     if(ctx->ptr == ctx->end) {
756         WARN("unexpected end of file\n");
757         return NULL;
758     }
759
760     re_len = ctx->ptr-re;
761
762     flags = ++ctx->ptr;
763     while(ctx->ptr < ctx->end && isalnumW(*ctx->ptr))
764         ctx->ptr++;
765
766     hres = create_regexp_str(ctx->script, re, re_len, flags, ctx->ptr-flags, &regexp);
767     if(FAILED(hres))
768         return NULL;
769
770     add_object_literal(ctx, regexp);
771
772     ret = parser_alloc(ctx, sizeof(literal_t));
773     ret->vt = VT_DISPATCH;
774     ret->u.disp = (IDispatch*)_IDispatchEx_(regexp);
775     return ret;
776 }