2 * Copyright 2008 Jacek Caban for CodeWeavers
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.
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.
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
29 #include "parser.tab.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(jscript
);
41 {L
"break", kBREAK
, TRUE
},
44 {L
"continue", kCONTINUE
, TRUE
},
45 {L
"default", kDEFAULT
},
50 {L
"finally", kFINALLY
},
52 {L
"function", kFUNCTION
},
53 {L
"get", kGET
, FALSE
, SCRIPTLANGUAGEVERSION_ES5
},
56 {L
"instanceof", kINSTANCEOF
},
59 {L
"return", kRETURN
, TRUE
},
60 {L
"set", kSET
, FALSE
, SCRIPTLANGUAGEVERSION_ES5
},
73 static int lex_error(parser_ctx_t
*ctx
, HRESULT hres
)
76 ctx
->lexer_error
= TRUE
;
80 /* ECMA-262 3rd Edition 7.6 */
81 BOOL
is_identifier_char(WCHAR c
)
83 return iswalnum(c
) || c
== '$' || c
== '_' || c
== '\\';
86 static BOOL
is_identifier_first_char(WCHAR c
)
88 return iswalpha(c
) || c
== '$' || c
== '_' || c
== '\\';
91 static int check_keyword(parser_ctx_t
*ctx
, const WCHAR
*word
, const WCHAR
**lval
)
93 const WCHAR
*p1
= ctx
->ptr
;
94 const WCHAR
*p2
= word
;
96 while(p1
< ctx
->end
&& *p2
) {
103 if(*p2
|| (p1
< ctx
->end
&& is_identifier_char(*p1
)))
112 /* ECMA-262 3rd Edition 7.3 */
113 static BOOL
is_endline(WCHAR c
)
115 return c
== '\n' || c
== '\r' || c
== 0x2028 || c
== 0x2029;
118 static int hex_to_int(WCHAR c
)
120 if('0' <= c
&& c
<= '9')
123 if('a' <= c
&& c
<= 'f')
126 if('A' <= c
&& c
<= 'F')
132 static int check_keywords(parser_ctx_t
*ctx
, const WCHAR
**lval
)
134 int min
= 0, max
= ARRAY_SIZE(keywords
)-1, r
, i
;
139 r
= check_keyword(ctx
, keywords
[i
].word
, lval
);
141 if(ctx
->script
->version
< keywords
[i
].min_version
) {
142 TRACE("ignoring keyword %s in incompatible mode\n",
143 debugstr_w(keywords
[i
].word
));
144 ctx
->ptr
-= lstrlenW(keywords
[i
].word
);
147 ctx
->implicit_nl_semicolon
= keywords
[i
].no_nl
;
148 return keywords
[i
].token
;
160 static BOOL
skip_html_comment(parser_ctx_t
*ctx
)
162 if(!ctx
->is_html
|| ctx
->ptr
+3 >= ctx
->end
||
163 memcmp(ctx
->ptr
, L
"<!--", sizeof(WCHAR
)*4))
167 while(ctx
->ptr
< ctx
->end
&& !is_endline(*ctx
->ptr
++));
172 static BOOL
skip_comment(parser_ctx_t
*ctx
)
174 if(ctx
->ptr
+1 >= ctx
->end
)
177 if(*ctx
->ptr
!= '/') {
178 if(*ctx
->ptr
== '@' && ctx
->ptr
+2 < ctx
->end
&& ctx
->ptr
[1] == '*' && ctx
->ptr
[2] == '/') {
186 switch(ctx
->ptr
[1]) {
189 if(ctx
->ptr
+2 < ctx
->end
&& *ctx
->ptr
== '@' && is_identifier_char(ctx
->ptr
[1]))
191 while(ctx
->ptr
+1 < ctx
->end
&& (ctx
->ptr
[0] != '*' || ctx
->ptr
[1] != '/'))
194 if(ctx
->ptr
[0] == '*' && ctx
->ptr
[1] == '/') {
197 WARN("unexpected end of file (missing end of comment)\n");
203 if(ctx
->ptr
+2 < ctx
->end
&& *ctx
->ptr
== '@' && is_identifier_char(ctx
->ptr
[1]))
205 while(ctx
->ptr
< ctx
->end
&& !is_endline(*ctx
->ptr
))
215 static BOOL
skip_spaces(parser_ctx_t
*ctx
)
217 while(ctx
->ptr
< ctx
->end
&& (iswspace(*ctx
->ptr
) || *ctx
->ptr
== 0xFEFF /* UTF16 BOM */)) {
218 if(is_endline(*ctx
->ptr
++))
222 return ctx
->ptr
!= ctx
->end
;
225 BOOL
unescape(WCHAR
*str
, size_t *len
)
227 WCHAR
*pd
, *p
, c
, *end
= str
+ *len
;
264 i
= hex_to_int(*++p
);
269 i
= hex_to_int(*++p
);
277 i
= hex_to_int(*++p
);
282 i
= hex_to_int(*++p
);
287 i
= hex_to_int(*++p
);
292 i
= hex_to_int(*++p
);
300 if(p
< end
&& is_digit(*p
)) {
301 c
= c
*8 + (*p
++ - '0');
302 if(p
< end
&& is_digit(*p
))
303 c
= c
*8 + (*p
++ - '0');
319 static int parse_identifier(parser_ctx_t
*ctx
, const WCHAR
**ret
)
321 const WCHAR
*ptr
= ctx
->ptr
++;
325 while(ctx
->ptr
< ctx
->end
&& is_identifier_char(*ctx
->ptr
))
330 *ret
= wstr
= parser_alloc(ctx
, (len
+1)*sizeof(WCHAR
));
331 memcpy(wstr
, ptr
, len
*sizeof(WCHAR
));
334 /* FIXME: unescape */
338 static int parse_string_literal(parser_ctx_t
*ctx
, jsstr_t
**ret
, WCHAR endch
)
340 const WCHAR
*ptr
= ++ctx
->ptr
, *ret_str
= ptr
;
341 BOOL needs_unescape
= FALSE
;
345 while(ctx
->ptr
< ctx
->end
&& *ctx
->ptr
!= endch
) {
346 if(*ctx
->ptr
++ == '\\') {
348 needs_unescape
= TRUE
;
352 if(ctx
->ptr
== ctx
->end
)
353 return lex_error(ctx
, JS_E_UNTERMINATED_STRING
);
355 len
= ctx
->ptr
- ptr
;
359 ret_str
= unescape_str
= parser_alloc(ctx
, len
* sizeof(WCHAR
));
361 return lex_error(ctx
, E_OUTOFMEMORY
);
362 memcpy(unescape_str
, ptr
, len
* sizeof(WCHAR
));
363 if(!unescape(unescape_str
, &len
)) {
364 WARN("unescape failed\n");
365 return lex_error(ctx
, E_FAIL
);
369 if(!(*ret
= compiler_alloc_string_len(ctx
->compiler
, ret_str
, len
)))
370 return lex_error(ctx
, E_OUTOFMEMORY
);
372 /* FIXME: leaking string */
373 return tStringLiteral
;
376 static literal_t
*new_double_literal(parser_ctx_t
*ctx
, DOUBLE d
)
378 literal_t
*ret
= parser_alloc(ctx
, sizeof(literal_t
));
380 ret
->type
= LT_DOUBLE
;
385 literal_t
*new_boolean_literal(parser_ctx_t
*ctx
, BOOL bval
)
387 literal_t
*ret
= parser_alloc(ctx
, sizeof(literal_t
));
395 HRESULT
parse_decimal(const WCHAR
**iter
, const WCHAR
*end
, double *ret
)
397 const WCHAR
*ptr
= *iter
;
401 while(ptr
< end
&& is_digit(*ptr
)) {
402 hlp
= d
*10 + *(ptr
++) - '0';
403 if(d
>MAXLONGLONG
/10 || hlp
<0) {
410 while(ptr
< end
&& is_digit(*ptr
)) {
418 while(ptr
< end
&& is_digit(*ptr
)) {
419 hlp
= d
*10 + *(ptr
++) - '0';
420 if(d
>MAXLONGLONG
/10 || hlp
<0)
426 while(ptr
< end
&& is_digit(*ptr
))
430 if(ptr
< end
&& (*ptr
== 'e' || *ptr
== 'E')) {
436 }else if(*ptr
== '-') {
439 }else if(!is_digit(*ptr
)) {
440 WARN("Expected exponent part\n");
446 WARN("unexpected end of file\n");
450 while(ptr
< end
&& is_digit(*ptr
)) {
451 if(e
> INT_MAX
/10 || (e
= e
*10 + *ptr
++ - '0')<0)
456 if(exp
<0 && e
<0 && e
+exp
>0) exp
= INT_MIN
;
457 else if(exp
>0 && e
>0 && e
+exp
<0) exp
= INT_MAX
;
461 if(is_identifier_char(*ptr
)) {
462 WARN("wrong char after zero\n");
463 return JS_E_MISSING_SEMICOLON
;
466 *ret
= exp
>=0 ? d
*pow(10, exp
) : d
/pow(10, -exp
);
471 static BOOL
parse_numeric_literal(parser_ctx_t
*ctx
, double *ret
)
475 if(*ctx
->ptr
== '0') {
478 if(*ctx
->ptr
== 'x' || *ctx
->ptr
== 'X') {
481 if(++ctx
->ptr
== ctx
->end
) {
482 ERR("unexpected end of file\n");
486 while(ctx
->ptr
< ctx
->end
&& (d
= hex_to_int(*ctx
->ptr
)) != -1) {
491 if(ctx
->ptr
< ctx
->end
&& is_identifier_char(*ctx
->ptr
)) {
492 WARN("unexpected identifier char\n");
493 lex_error(ctx
, JS_E_MISSING_SEMICOLON
);
501 if(is_digit(*ctx
->ptr
)) {
506 for(ptr
= ctx
->ptr
; ptr
< ctx
->end
&& is_digit(*ptr
); ptr
++) {
514 val
= val
*base
+ *ctx
->ptr
-'0';
515 }while(++ctx
->ptr
< ctx
->end
&& is_digit(*ctx
->ptr
));
517 /* FIXME: Do we need it here? */
518 if(ctx
->ptr
< ctx
->end
&& (is_identifier_char(*ctx
->ptr
) || *ctx
->ptr
== '.')) {
519 WARN("wrong char after octal literal: '%c'\n", *ctx
->ptr
);
520 lex_error(ctx
, JS_E_MISSING_SEMICOLON
);
528 if(is_identifier_char(*ctx
->ptr
)) {
529 WARN("wrong char after zero\n");
530 lex_error(ctx
, JS_E_MISSING_SEMICOLON
);
535 hres
= parse_decimal(&ctx
->ptr
, ctx
->end
, ret
);
537 lex_error(ctx
, hres
);
544 static int next_token(parser_ctx_t
*ctx
, unsigned *loc
, void *lval
)
547 if(!skip_spaces(ctx
)) {
548 *loc
= ctx
->ptr
- ctx
->begin
;
551 }while(skip_comment(ctx
) || skip_html_comment(ctx
));
552 *loc
= ctx
->ptr
- ctx
->begin
;
554 if(ctx
->implicit_nl_semicolon
) {
557 ctx
->implicit_nl_semicolon
= FALSE
;
560 if(iswalpha(*ctx
->ptr
)) {
561 int ret
= check_keywords(ctx
, lval
);
565 return parse_identifier(ctx
, lval
);
568 if(is_digit(*ctx
->ptr
)) {
571 if(!parse_numeric_literal(ctx
, &n
))
574 *(literal_t
**)lval
= new_double_literal(ctx
, n
);
575 return tNumericLiteral
;
592 if(ctx
->ptr
+1 < ctx
->end
&& is_digit(ctx
->ptr
[1])) {
595 hres
= parse_decimal(&ctx
->ptr
, ctx
->end
, &n
);
597 lex_error(ctx
, hres
);
600 *(literal_t
**)lval
= new_double_literal(ctx
, n
);
601 return tNumericLiteral
;
607 if(++ctx
->ptr
== ctx
->end
) {
608 *(int*)lval
= EXPR_LESS
;
615 *(int*)lval
= EXPR_LESSEQ
;
618 if(++ctx
->ptr
< ctx
->end
&& *ctx
->ptr
== '=') { /* <<= */
620 *(int*)lval
= EXPR_ASSIGNLSHIFT
;
623 *(int*)lval
= EXPR_LSHIFT
;
626 *(int*)lval
= EXPR_LESS
;
631 if(++ctx
->ptr
== ctx
->end
) { /* > */
632 *(int*)lval
= EXPR_GREATER
;
639 *(int*)lval
= EXPR_GREATEREQ
;
642 if(++ctx
->ptr
< ctx
->end
) {
643 if(*ctx
->ptr
== '=') { /* >>= */
645 *(int*)lval
= EXPR_ASSIGNRSHIFT
;
648 if(*ctx
->ptr
== '>') { /* >>> */
649 if(++ctx
->ptr
< ctx
->end
&& *ctx
->ptr
== '=') { /* >>>= */
651 *(int*)lval
= EXPR_ASSIGNRRSHIFT
;
654 *(int*)lval
= EXPR_RRSHIFT
;
658 *(int*)lval
= EXPR_RSHIFT
;
661 *(int*)lval
= EXPR_GREATER
;
667 if(ctx
->ptr
< ctx
->end
) {
674 *(int*)lval
= EXPR_ASSIGNADD
;
682 if(ctx
->ptr
< ctx
->end
) {
684 case '-': /* -- or --> */
686 if(ctx
->is_html
&& ctx
->nl
&& ctx
->ptr
< ctx
->end
&& *ctx
->ptr
== '>') {
693 *(int*)lval
= EXPR_ASSIGNSUB
;
700 if(++ctx
->ptr
< ctx
->end
&& *ctx
->ptr
== '=') { /* *= */
702 *(int*)lval
= EXPR_ASSIGNMUL
;
708 if(++ctx
->ptr
< ctx
->end
&& *ctx
->ptr
== '=') { /* %= */
710 *(int*)lval
= EXPR_ASSIGNMOD
;
716 if(++ctx
->ptr
< ctx
->end
) {
720 *(int*)lval
= EXPR_ASSIGNAND
;
730 if(++ctx
->ptr
< ctx
->end
) {
734 *(int*)lval
= EXPR_ASSIGNOR
;
744 if(++ctx
->ptr
< ctx
->end
&& *ctx
->ptr
== '=') { /* ^= */
746 *(int*)lval
= EXPR_ASSIGNXOR
;
752 if(++ctx
->ptr
< ctx
->end
&& *ctx
->ptr
== '=') { /* != */
753 if(++ctx
->ptr
< ctx
->end
&& *ctx
->ptr
== '=') { /* !== */
755 *(int*)lval
= EXPR_NOTEQEQ
;
758 *(int*)lval
= EXPR_NOTEQ
;
764 if(++ctx
->ptr
< ctx
->end
&& *ctx
->ptr
== '=') { /* == */
765 if(++ctx
->ptr
< ctx
->end
&& *ctx
->ptr
== '=') { /* === */
767 *(int*)lval
= EXPR_EQEQ
;
770 *(int*)lval
= EXPR_EQ
;
776 if(++ctx
->ptr
< ctx
->end
) {
777 if(*ctx
->ptr
== '=') { /* /= */
779 *(int*)lval
= EXPR_ASSIGNDIV
;
786 if(++ctx
->ptr
< ctx
->end
&& *ctx
->ptr
== ':') {
794 return parse_string_literal(ctx
, lval
, *ctx
->ptr
);
798 return parse_identifier(ctx
, lval
);
804 WARN("unexpected char '%c' %d\n", *ctx
->ptr
, *ctx
->ptr
);
810 struct _cc_var_t
*next
;
815 void release_cc(cc_ctx_t
*cc
)
817 cc_var_t
*iter
, *next
;
819 for(iter
= cc
->vars
; iter
; iter
= next
) {
827 static BOOL
new_cc_var(cc_ctx_t
*cc
, const WCHAR
*name
, int len
, ccval_t v
)
832 len
= lstrlenW(name
);
834 new_v
= heap_alloc(sizeof(cc_var_t
) + (len
+1)*sizeof(WCHAR
));
839 memcpy(new_v
->name
, name
, (len
+1)*sizeof(WCHAR
));
840 new_v
->name_len
= len
;
841 new_v
->next
= cc
->vars
;
846 static cc_var_t
*find_cc_var(cc_ctx_t
*cc
, const WCHAR
*name
, unsigned name_len
)
850 for(iter
= cc
->vars
; iter
; iter
= iter
->next
) {
851 if(iter
->name_len
== name_len
&& !memcmp(iter
->name
, name
, name_len
*sizeof(WCHAR
)))
858 static BOOL
init_cc(parser_ctx_t
*ctx
)
865 cc
= heap_alloc(sizeof(cc_ctx_t
));
867 lex_error(ctx
, E_OUTOFMEMORY
);
873 if(!new_cc_var(cc
, L
"_jscript", -1, ccval_bool(TRUE
))
874 || !new_cc_var(cc
, sizeof(void*) == 8 ? L
"_win64" : L
"_win32", -1, ccval_bool(TRUE
))
875 || !new_cc_var(cc
, sizeof(void*) == 8 ? L
"_amd64" : L
"_x86", -1, ccval_bool(TRUE
))
876 || !new_cc_var(cc
, L
"_jscript_version", -1, ccval_num(JSCRIPT_MAJOR_VERSION
+ (DOUBLE
)JSCRIPT_MINOR_VERSION
/10.0))
877 || !new_cc_var(cc
, L
"_jscript_build", -1, ccval_num(JSCRIPT_BUILD_VERSION
))) {
879 lex_error(ctx
, E_OUTOFMEMORY
);
883 ctx
->script
->cc
= cc
;
887 static BOOL
parse_cc_identifier(parser_ctx_t
*ctx
, const WCHAR
**ret
, unsigned *ret_len
)
889 if(*ctx
->ptr
!= '@') {
890 lex_error(ctx
, JS_E_EXPECTED_AT
);
894 if(!is_identifier_first_char(*++ctx
->ptr
)) {
895 lex_error(ctx
, JS_E_EXPECTED_IDENTIFIER
);
900 while(++ctx
->ptr
< ctx
->end
&& is_identifier_char(*ctx
->ptr
));
901 *ret_len
= ctx
->ptr
- *ret
;
905 int try_parse_ccval(parser_ctx_t
*ctx
, ccval_t
*r
)
907 if(!skip_spaces(ctx
))
910 if(is_digit(*ctx
->ptr
)) {
913 if(!parse_numeric_literal(ctx
, &n
))
920 if(*ctx
->ptr
== '@') {
925 if(!parse_cc_identifier(ctx
, &ident
, &ident_len
))
928 cc_var
= find_cc_var(ctx
->script
->cc
, ident
, ident_len
);
929 *r
= cc_var
? cc_var
->val
: ccval_num(NAN
);
933 if(!check_keyword(ctx
, L
"true", NULL
)) {
934 *r
= ccval_bool(TRUE
);
938 if(!check_keyword(ctx
, L
"false", NULL
)) {
939 *r
= ccval_bool(FALSE
);
946 static int skip_code(parser_ctx_t
*ctx
, BOOL exec_else
)
952 ptr
= wcschr(ctx
->ptr
, '@');
955 return lex_error(ctx
, JS_E_EXPECTED_CCEND
);
959 if(!check_keyword(ctx
, L
"end", NULL
)) {
965 if(exec_else
&& !check_keyword(ctx
, L
"elif", NULL
)) {
969 if(!skip_spaces(ctx
) || *ctx
->ptr
!= '(')
970 return lex_error(ctx
, JS_E_MISSING_LBRACKET
);
972 if(!parse_cc_expr(ctx
))
975 if(!get_ccbool(ctx
->ccval
))
976 continue; /* skip block of code */
978 /* continue parsing */
983 if(exec_else
&& !check_keyword(ctx
, L
"else", NULL
)) {
987 /* parse else block */
992 if(!check_keyword(ctx
, L
"if", NULL
)) {
1001 static int cc_token(parser_ctx_t
*ctx
, void *lval
)
1003 unsigned id_len
= 0;
1008 if(!check_keyword(ctx
, L
"cc_on", NULL
))
1009 return init_cc(ctx
) ? 0 : -1;
1011 if(!check_keyword(ctx
, L
"set", NULL
)) {
1019 if(!skip_spaces(ctx
))
1020 return lex_error(ctx
, JS_E_EXPECTED_AT
);
1022 if(!parse_cc_identifier(ctx
, &ident
, &ident_len
))
1025 if(!skip_spaces(ctx
) || *ctx
->ptr
!= '=')
1026 return lex_error(ctx
, JS_E_EXPECTED_ASSIGN
);
1029 if(!parse_cc_expr(ctx
)) {
1030 WARN("parsing CC expression failed\n");
1034 var
= find_cc_var(ctx
->script
->cc
, ident
, ident_len
);
1036 var
->val
= ctx
->ccval
;
1038 if(!new_cc_var(ctx
->script
->cc
, ident
, ident_len
, ctx
->ccval
))
1039 return lex_error(ctx
, E_OUTOFMEMORY
);
1045 if(!check_keyword(ctx
, L
"if", NULL
)) {
1049 if(!skip_spaces(ctx
) || *ctx
->ptr
!= '(')
1050 return lex_error(ctx
, JS_E_MISSING_LBRACKET
);
1052 if(!parse_cc_expr(ctx
))
1055 if(get_ccbool(ctx
->ccval
)) {
1056 /* continue parsing block inside if */
1061 return skip_code(ctx
, TRUE
);
1064 if(!check_keyword(ctx
, L
"elif", NULL
) || !check_keyword(ctx
, L
"else", NULL
)) {
1065 if(!ctx
->cc_if_depth
)
1066 return lex_error(ctx
, JS_E_SYNTAX
);
1068 return skip_code(ctx
, FALSE
);
1071 if(!check_keyword(ctx
, L
"end", NULL
)) {
1072 if(!ctx
->cc_if_depth
)
1073 return lex_error(ctx
, JS_E_SYNTAX
);
1079 if(!ctx
->script
->cc
)
1080 return lex_error(ctx
, JS_E_DISABLED_CC
);
1082 while(ctx
->ptr
+id_len
< ctx
->end
&& is_identifier_char(ctx
->ptr
[id_len
]))
1087 TRACE("var %s\n", debugstr_wn(ctx
->ptr
, id_len
));
1089 var
= find_cc_var(ctx
->script
->cc
, ctx
->ptr
, id_len
);
1091 if(!var
|| var
->val
.is_num
) {
1092 *(literal_t
**)lval
= new_double_literal(ctx
, var
? var
->val
.u
.n
: NAN
);
1093 return tNumericLiteral
;
1096 *(literal_t
**)lval
= new_boolean_literal(ctx
, var
->val
.u
.b
);
1097 return tBooleanLiteral
;
1100 int parser_lex(void *lval
, unsigned *loc
, parser_ctx_t
*ctx
)
1104 ctx
->nl
= ctx
->ptr
== ctx
->begin
;
1107 ret
= next_token(ctx
, loc
, lval
);
1108 } while(ret
== '@' && !(ret
= cc_token(ctx
, lval
)));
1113 literal_t
*parse_regexp(parser_ctx_t
*ctx
)
1115 const WCHAR
*re
, *flags_ptr
;
1116 BOOL in_class
= FALSE
;
1117 DWORD re_len
, flags
;
1122 while(*--ctx
->ptr
!= '/');
1124 /* Simple regexp pre-parser; '/' if used in char class does not terminate regexp literal */
1126 while(ctx
->ptr
< ctx
->end
) {
1127 if(*ctx
->ptr
== '\\') {
1128 if(++ctx
->ptr
== ctx
->end
)
1130 }else if(in_class
) {
1131 if(*ctx
->ptr
== '\n')
1133 if(*ctx
->ptr
== ']')
1136 if(*ctx
->ptr
== '/')
1139 if(*ctx
->ptr
== '[')
1145 if(ctx
->ptr
== ctx
->end
|| *ctx
->ptr
!= '/') {
1146 WARN("pre-parsing failed\n");
1147 ctx
->hres
= JS_E_SYNTAX
;
1151 re_len
= ctx
->ptr
-re
;
1153 flags_ptr
= ++ctx
->ptr
;
1154 while(ctx
->ptr
< ctx
->end
&& iswalnum(*ctx
->ptr
))
1157 ctx
->hres
= parse_regexp_flags(flags_ptr
, ctx
->ptr
-flags_ptr
, &flags
);
1158 if(FAILED(ctx
->hres
))
1161 ret
= parser_alloc(ctx
, sizeof(literal_t
));
1162 ret
->type
= LT_REGEXP
;
1163 ret
->u
.regexp
.str
= compiler_alloc_string_len(ctx
->compiler
, re
, re_len
);
1164 ret
->u
.regexp
.flags
= flags
;