5 #include "duk_internal.h"
7 #ifdef DUK_USE_REGEXP_SUPPORT
9 DUK_LOCAL
void duk__get_this_regexp(duk_context
*ctx
) {
13 h
= duk_require_hobject_with_class(ctx
, -1, DUK_HOBJECT_CLASS_REGEXP
);
14 DUK_ASSERT(h
!= NULL
);
16 duk_insert(ctx
, 0); /* prepend regexp to valstack 0 index */
19 /* XXX: much to improve (code size) */
20 DUK_INTERNAL duk_ret_t
duk_bi_regexp_constructor(duk_context
*ctx
) {
21 duk_hthread
*thr
= (duk_hthread
*) ctx
;
22 duk_hobject
*h_pattern
;
24 DUK_ASSERT_TOP(ctx
, 2);
25 h_pattern
= duk_get_hobject(ctx
, 0);
27 if (!duk_is_constructor_call(ctx
) &&
29 DUK_HOBJECT_GET_CLASS_NUMBER(h_pattern
) == DUK_HOBJECT_CLASS_REGEXP
&&
30 duk_is_undefined(ctx
, 1)) {
31 /* Called as a function, pattern has [[Class]] "RegExp" and
32 * flags is undefined -> return object as is.
38 /* Else functionality is identical for function call and constructor
42 if (h_pattern
!= NULL
&&
43 DUK_HOBJECT_GET_CLASS_NUMBER(h_pattern
) == DUK_HOBJECT_CLASS_REGEXP
) {
44 if (duk_is_undefined(ctx
, 1)) {
45 duk_bool_t flag_g
, flag_i
, flag_m
;
46 duk_get_prop_stridx(ctx
, 0, DUK_STRIDX_SOURCE
);
47 flag_g
= duk_get_prop_stridx_boolean(ctx
, 0, DUK_STRIDX_GLOBAL
, NULL
);
48 flag_i
= duk_get_prop_stridx_boolean(ctx
, 0, DUK_STRIDX_IGNORE_CASE
, NULL
);
49 flag_m
= duk_get_prop_stridx_boolean(ctx
, 0, DUK_STRIDX_MULTILINE
, NULL
);
51 duk_push_sprintf(ctx
, "%s%s%s",
52 (const char *) (flag_g
? "g" : ""),
53 (const char *) (flag_i
? "i" : ""),
54 (const char *) (flag_m
? "m" : ""));
56 /* [ ... pattern flags ] */
58 return DUK_RET_TYPE_ERROR
;
61 if (duk_is_undefined(ctx
, 0)) {
62 duk_push_string(ctx
, "");
65 duk_to_string(ctx
, -1);
67 if (duk_is_undefined(ctx
, 1)) {
68 duk_push_string(ctx
, "");
71 duk_to_string(ctx
, -1);
74 /* [ ... pattern flags ] */
77 DUK_DDD(DUK_DDDPRINT("RegExp constructor/function call, pattern=%!T, flags=%!T",
78 (duk_tval
*) duk_get_tval(ctx
, -2), (duk_tval
*) duk_get_tval(ctx
, -1)));
80 /* [ ... pattern flags ] */
82 duk_regexp_compile(thr
);
84 /* [ ... bytecode escaped_source ] */
86 duk_regexp_create_instance(thr
);
93 DUK_INTERNAL duk_ret_t
duk_bi_regexp_prototype_exec(duk_context
*ctx
) {
94 duk__get_this_regexp(ctx
);
96 /* [ regexp input ] */
98 duk_regexp_match((duk_hthread
*) ctx
);
105 DUK_INTERNAL duk_ret_t
duk_bi_regexp_prototype_test(duk_context
*ctx
) {
106 duk__get_this_regexp(ctx
);
108 /* [ regexp input ] */
110 /* result object is created and discarded; wasteful but saves code space */
111 duk_regexp_match((duk_hthread
*) ctx
);
115 duk_push_boolean(ctx
, (duk_is_null(ctx
, -1) ? 0 : 1));
120 DUK_INTERNAL duk_ret_t
duk_bi_regexp_prototype_to_string(duk_context
*ctx
) {
122 duk_small_int_t re_flags
;
125 /* A little tricky string approach to provide the flags string.
126 * This depends on the specific flag values in duk_regexp.h,
127 * which needs to be asserted for. In practice this doesn't
128 * produce more compact code than the easier approach in use.
131 const char *flag_strings
= "gim\0gi\0gm\0g\0";
132 duk_uint8_t flag_offsets
[8] = {
133 (duk_uint8_t
) 3, /* flags: "" */
134 (duk_uint8_t
) 10, /* flags: "g" */
135 (duk_uint8_t
) 5, /* flags: "i" */
136 (duk_uint8_t
) 4, /* flags: "gi" */
137 (duk_uint8_t
) 2, /* flags: "m" */
138 (duk_uint8_t
) 7, /* flags: "gm" */
139 (duk_uint8_t
) 1, /* flags: "im" */
140 (duk_uint8_t
) 0, /* flags: "gim" */
142 DUK_ASSERT(DUK_RE_FLAG_GLOBAL
== 1);
143 DUK_ASSERT(DUK_RE_FLAG_IGNORE_CASE
== 2);
144 DUK_ASSERT(DUK_RE_FLAG_MULTILINE
== 4);
147 duk__get_this_regexp(ctx
);
151 duk_get_prop_stridx(ctx
, 0, DUK_STRIDX_SOURCE
);
152 duk_get_prop_stridx(ctx
, 0, DUK_STRIDX_INT_BYTECODE
);
153 h_bc
= duk_get_hstring(ctx
, -1);
154 DUK_ASSERT(h_bc
!= NULL
);
155 DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(h_bc
) >= 1);
156 DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h_bc
) >= 1);
157 DUK_ASSERT(DUK_HSTRING_GET_DATA(h_bc
)[0] < 0x80);
158 re_flags
= (duk_small_int_t
) DUK_HSTRING_GET_DATA(h_bc
)[0];
160 /* [ regexp source bytecode ] */
163 /* This is a cleaner approach and also produces smaller code than
164 * the other alternative. Use duk_require_string() for format
165 * safety (although the source property should always exist).
167 duk_push_sprintf(ctx
, "/%s/%s%s%s",
168 (const char *) duk_require_string(ctx
, -2), /* require to be safe */
169 (re_flags
& DUK_RE_FLAG_GLOBAL
) ? "g" : "",
170 (re_flags
& DUK_RE_FLAG_IGNORE_CASE
) ? "i" : "",
171 (re_flags
& DUK_RE_FLAG_MULTILINE
) ? "m" : "");
173 /* This should not be necessary because no-one should tamper with the
174 * regexp bytecode, but is prudent to avoid potential segfaults if that
175 * were to happen for some reason.
178 DUK_ASSERT(re_flags
>= 0 && re_flags
<= 7); /* three flags */
179 duk_push_sprintf(ctx
, "/%s/%s",
180 (const char *) duk_require_string(ctx
, -2),
181 (const char *) (flag_strings
+ flag_offsets
[re_flags
]));
187 #else /* DUK_USE_REGEXP_SUPPORT */
189 DUK_INTERNAL duk_ret_t
duk_bi_regexp_constructor(duk_context
*ctx
) {
191 return DUK_RET_UNSUPPORTED_ERROR
;
194 DUK_INTERNAL duk_ret_t
duk_bi_regexp_prototype_exec(duk_context
*ctx
) {
196 return DUK_RET_UNSUPPORTED_ERROR
;
199 DUK_INTERNAL duk_ret_t
duk_bi_regexp_prototype_test(duk_context
*ctx
) {
201 return DUK_RET_UNSUPPORTED_ERROR
;
204 DUK_INTERNAL duk_ret_t
duk_bi_regexp_prototype_to_string(duk_context
*ctx
) {
206 return DUK_RET_UNSUPPORTED_ERROR
;
209 #endif /* DUK_USE_REGEXP_SUPPORT */