Skip to content

Commit b74e9cd

Browse files
committed
Implement RegExp.prototype.compile()
JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai.u-szeged@partner.samsung.com
1 parent 4ee30cb commit b74e9cd

File tree

8 files changed

+341
-58
lines changed

8 files changed

+341
-58
lines changed

jerry-core/ecma/builtin-objects/ecma-builtin-regexp-prototype.cpp

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,173 @@
4545
* @{
4646
*/
4747

48+
#ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_ANNEXB_BUILTIN
49+
50+
/**
51+
* The RegExp.prototype object's 'compile' routine
52+
*
53+
* See also:
54+
* ECMA-262 v5, B.2.5.1
55+
*
56+
* @return completion value
57+
* Returned value must be freed with ecma_free_completion_value.
58+
*/
59+
static ecma_completion_value_t
60+
ecma_builtin_regexp_prototype_compile (ecma_value_t this_arg, /**< this argument */
61+
ecma_value_t pattern_arg, /**< pattern or RegExp object */
62+
ecma_value_t flags_arg) /**< flags */
63+
{
64+
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
65+
ecma_object_t *this_obj_p = ecma_get_object_from_value (this_arg);
66+
67+
if (ecma_object_get_class_name (this_obj_p) != LIT_MAGIC_STRING_REGEXP_UL)
68+
{
69+
/* Compile can only be called on RegExp objects. */
70+
ret_value = ecma_make_throw_obj_completion_value (ecma_new_standard_error (ECMA_ERROR_TYPE));
71+
}
72+
else
73+
{
74+
ecma_string_t *pattern_string_p = NULL;
75+
uint8_t flags = 0;
76+
77+
if (ecma_is_value_object (pattern_arg)
78+
&& ecma_object_get_class_name (ecma_get_object_from_value (pattern_arg)) == LIT_MAGIC_STRING_REGEXP_UL)
79+
{
80+
if (!ecma_is_value_undefined (flags_arg))
81+
{
82+
ret_value = ecma_raise_type_error ("Invalid argument of RegExp compile.");
83+
}
84+
else
85+
{
86+
/* Compile from existing RegExp pbject. */
87+
ecma_object_t *target_p = ecma_get_object_from_value (pattern_arg);
88+
89+
/* Get source. */
90+
ecma_string_t *magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_SOURCE);
91+
ecma_property_t *prop_p = ecma_get_named_data_property (target_p, magic_string_p);
92+
pattern_string_p = ecma_get_string_from_value (ecma_get_named_data_property_value (prop_p));
93+
ecma_deref_ecma_string (magic_string_p);
94+
95+
/* Get flags. */
96+
magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_GLOBAL);
97+
prop_p = ecma_get_named_data_property (target_p, magic_string_p);
98+
99+
if (ecma_is_value_true (ecma_get_named_data_property_value (prop_p)))
100+
{
101+
flags |= RE_FLAG_GLOBAL;
102+
}
103+
104+
ecma_deref_ecma_string (magic_string_p);
105+
magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_IGNORECASE_UL);
106+
prop_p = ecma_get_named_data_property (target_p, magic_string_p);
107+
108+
if (ecma_is_value_true (ecma_get_named_data_property_value (prop_p)))
109+
{
110+
flags |= RE_FLAG_IGNORE_CASE;
111+
}
112+
113+
ecma_deref_ecma_string (magic_string_p);
114+
magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_MULTILINE);
115+
prop_p = ecma_get_named_data_property (target_p, magic_string_p);
116+
117+
if (ecma_is_value_true (ecma_get_named_data_property_value (prop_p)))
118+
{
119+
flags |= RE_FLAG_MULTILINE;
120+
}
121+
122+
ecma_deref_ecma_string (magic_string_p);
123+
124+
/* Get bytecode property. */
125+
ecma_property_t *bc_prop_p = ecma_get_internal_property (this_obj_p,
126+
ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE);
127+
re_bytecode_t *old_bc_p = ECMA_GET_NON_NULL_POINTER (re_bytecode_t,
128+
bc_prop_p->u.internal_property.value);
129+
130+
FIXME ("We currently have to re-compile the bytecode, because we can't copy it without knowing its length.")
131+
re_bytecode_t *new_bc_p = NULL;
132+
ecma_completion_value_t bc_comp = re_compile_bytecode (&new_bc_p, pattern_string_p, flags);
133+
/* Should always succeed, since we're compiling from a source that has been compiled previously. */
134+
JERRY_ASSERT (ecma_is_completion_value_empty (bc_comp));
135+
136+
mem_heap_free_block (old_bc_p);
137+
ECMA_SET_POINTER (bc_prop_p->u.internal_property.value, new_bc_p);
138+
139+
re_initialize_props (this_obj_p, pattern_string_p, flags);
140+
141+
ret_value = ecma_make_normal_completion_value (ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED));
142+
}
143+
}
144+
else
145+
{
146+
/* Get source string. */
147+
if (!ecma_is_value_undefined (pattern_arg))
148+
{
149+
ECMA_TRY_CATCH (regexp_str_value,
150+
ecma_op_to_string (pattern_arg),
151+
ret_value);
152+
153+
if (ecma_string_get_length (ecma_get_string_from_value (regexp_str_value)) == 0)
154+
{
155+
pattern_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_EMPTY_NON_CAPTURE_GROUP);
156+
}
157+
else
158+
{
159+
pattern_string_p = ecma_copy_or_ref_ecma_string (ecma_get_string_from_value (regexp_str_value));
160+
}
161+
162+
ECMA_FINALIZE (regexp_str_value);
163+
}
164+
else
165+
{
166+
pattern_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_EMPTY_NON_CAPTURE_GROUP);
167+
}
168+
169+
/* Parse flags. */
170+
if (ecma_is_completion_value_empty (ret_value) && !ecma_is_value_undefined (flags_arg))
171+
{
172+
ECMA_TRY_CATCH (flags_str_value,
173+
ecma_op_to_string (flags_arg),
174+
ret_value);
175+
176+
ECMA_TRY_CATCH (flags_dummy,
177+
re_parse_regexp_flags (ecma_get_string_from_value (flags_str_value), &flags),
178+
ret_value);
179+
ECMA_FINALIZE (flags_dummy);
180+
ECMA_FINALIZE (flags_str_value);
181+
}
182+
183+
if (ecma_is_completion_value_empty (ret_value))
184+
{
185+
ecma_property_t *bc_prop_p = ecma_get_internal_property (this_obj_p,
186+
ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE);
187+
re_bytecode_t *old_bc_p = ECMA_GET_NON_NULL_POINTER (re_bytecode_t,
188+
bc_prop_p->u.internal_property.value);
189+
190+
/* Try to compile bytecode from new source. */
191+
re_bytecode_t *new_bc_p = NULL;
192+
ECMA_TRY_CATCH (bc_dummy, re_compile_bytecode (&new_bc_p, pattern_string_p, flags), ret_value);
193+
194+
/* Replace old bytecode with new one. */
195+
mem_heap_free_block (old_bc_p);
196+
ECMA_SET_POINTER (bc_prop_p->u.internal_property.value, new_bc_p);
197+
re_initialize_props (this_obj_p, pattern_string_p, flags);
198+
ret_value = ecma_make_normal_completion_value (ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED));
199+
200+
ECMA_FINALIZE (bc_dummy);
201+
}
202+
203+
if (pattern_string_p != NULL)
204+
{
205+
ecma_deref_ecma_string (pattern_string_p);
206+
}
207+
}
208+
}
209+
210+
return ret_value;
211+
} /* ecma_builtin_regexp_prototype_compile */
212+
213+
#endif /* !CONFIG_ECMA_COMPACT_PROFILE_DISABLE_ANNEXB_BUILTIN */
214+
48215
/**
49216
* The RegExp.prototype object's 'exec' routine
50217
*

jerry-core/ecma/builtin-objects/ecma-builtin-regexp-prototype.inc.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ NUMBER_VALUE (LIT_MAGIC_STRING_LASTINDEX_UL,
8686
ECMA_PROPERTY_NOT_ENUMERABLE,
8787
ECMA_PROPERTY_NOT_CONFIGURABLE)
8888

89+
#ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_ANNEXB_BUILTIN
90+
ROUTINE (LIT_MAGIC_STRING_COMPILE, ecma_builtin_regexp_prototype_compile, 2, 1)
91+
#endif
8992
ROUTINE (LIT_MAGIC_STRING_EXEC, ecma_builtin_regexp_prototype_exec, 1, 1)
9093
ROUTINE (LIT_MAGIC_STRING_TEST, ecma_builtin_regexp_prototype_test, 1, 1)
9194
ROUTINE (LIT_MAGIC_STRING_TO_STRING_UL, ecma_builtin_regexp_prototype_to_string, 0, 0)

jerry-core/ecma/operations/ecma-regexp-object.cpp

Lines changed: 102 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
* @return completion value
6363
* Returned value must be freed with ecma_free_completion_value
6464
*/
65-
static ecma_completion_value_t
65+
ecma_completion_value_t
6666
re_parse_regexp_flags (ecma_string_t *flags_str_p, /**< Input string with flags */
6767
uint8_t *flags_p) /**< Output: parsed flag bits */
6868
{
@@ -119,6 +119,101 @@ re_parse_regexp_flags (ecma_string_t *flags_str_p, /**< Input string with flags
119119
return ret_value;
120120
} /* re_parse_regexp_flags */
121121

122+
/*
123+
* Initializes the source, global, ignoreCase, multiline, and lastIndex properties of RegExp instance.
124+
*/
125+
void
126+
re_initialize_props (ecma_object_t *re_obj_p, /**< RegExp obejct */
127+
ecma_string_t *source_p, /**< source string */
128+
uint8_t flags) /**< flags */
129+
{
130+
/* Set source property. ECMA-262 v5, 15.10.7.1 */
131+
ecma_string_t *magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_SOURCE);
132+
ecma_property_t *prop_p = ecma_find_named_property (re_obj_p, magic_string_p);
133+
134+
if (prop_p == NULL)
135+
{
136+
prop_p = ecma_create_named_data_property (re_obj_p,
137+
magic_string_p,
138+
false, false, false);
139+
}
140+
141+
ecma_deref_ecma_string (magic_string_p);
142+
JERRY_ASSERT (prop_p->type == ECMA_PROPERTY_NAMEDDATA);
143+
ecma_named_data_property_assign_value (re_obj_p,
144+
prop_p,
145+
ecma_make_string_value (source_p));
146+
147+
ecma_simple_value_t prop_value;
148+
149+
/* Set global property. ECMA-262 v5, 15.10.7.2 */
150+
magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_GLOBAL);
151+
prop_p = ecma_find_named_property (re_obj_p, magic_string_p);
152+
153+
if (prop_p == NULL)
154+
{
155+
prop_p = ecma_create_named_data_property (re_obj_p,
156+
magic_string_p,
157+
false, false, false);
158+
}
159+
160+
ecma_deref_ecma_string (magic_string_p);
161+
prop_value = flags & RE_FLAG_GLOBAL ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE;
162+
JERRY_ASSERT (prop_p->type == ECMA_PROPERTY_NAMEDDATA);
163+
ecma_set_named_data_property_value (prop_p, ecma_make_simple_value (prop_value));
164+
165+
/* Set ignoreCase property. ECMA-262 v5, 15.10.7.3 */
166+
magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_IGNORECASE_UL);
167+
prop_p = ecma_find_named_property (re_obj_p, magic_string_p);
168+
169+
if (prop_p == NULL)
170+
{
171+
prop_p = ecma_create_named_data_property (re_obj_p,
172+
magic_string_p,
173+
false, false, false);
174+
}
175+
176+
ecma_deref_ecma_string (magic_string_p);
177+
prop_value = flags & RE_FLAG_IGNORE_CASE ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE;
178+
JERRY_ASSERT (prop_p->type == ECMA_PROPERTY_NAMEDDATA);
179+
ecma_set_named_data_property_value (prop_p, ecma_make_simple_value (prop_value));
180+
181+
/* Set multiline property. ECMA-262 v5, 15.10.7.4 */
182+
magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_MULTILINE);
183+
prop_p = ecma_find_named_property (re_obj_p, magic_string_p);
184+
185+
if (prop_p == NULL)
186+
{
187+
prop_p = ecma_create_named_data_property (re_obj_p,
188+
magic_string_p,
189+
false, false, false);
190+
}
191+
192+
ecma_deref_ecma_string (magic_string_p);
193+
prop_value = flags & RE_FLAG_MULTILINE ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE;
194+
JERRY_ASSERT (prop_p->type == ECMA_PROPERTY_NAMEDDATA);
195+
ecma_set_named_data_property_value (prop_p, ecma_make_simple_value (prop_value));
196+
197+
/* Set lastIndex property. ECMA-262 v5, 15.10.7.5 */
198+
magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL);
199+
prop_p = ecma_find_named_property (re_obj_p, magic_string_p);
200+
201+
if (prop_p == NULL)
202+
{
203+
prop_p = ecma_create_named_data_property (re_obj_p,
204+
magic_string_p,
205+
true, false, false);
206+
}
207+
208+
ecma_deref_ecma_string (magic_string_p);
209+
210+
ecma_number_t *lastindex_num_p = ecma_alloc_number ();
211+
*lastindex_num_p = ECMA_NUMBER_ZERO;
212+
JERRY_ASSERT (prop_p->type == ECMA_PROPERTY_NAMEDDATA);
213+
ecma_named_data_property_assign_value (re_obj_p, prop_p, ecma_make_number_value (lastindex_num_p));
214+
ecma_dealloc_number (lastindex_num_p);
215+
} /* re_initialize_props */
216+
122217
/**
123218
* RegExp object creation operation.
124219
*
@@ -155,64 +250,19 @@ ecma_op_create_regexp_object (ecma_string_t *pattern_p, /**< input pattern */
155250
ecma_property_t *class_prop_p = ecma_create_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_CLASS);
156251
class_prop_p->u.internal_property.value = LIT_MAGIC_STRING_REGEXP_UL;
157252

158-
/* Set source property. ECMA-262 v5, 15.10.7.1 */
159-
ecma_string_t *magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_SOURCE);
160-
ecma_property_t *source_prop_p = ecma_create_named_data_property (obj_p,
161-
magic_string_p,
162-
false, false, false);
163-
ecma_deref_ecma_string (magic_string_p);
164-
ecma_set_named_data_property_value (source_prop_p,
165-
ecma_make_string_value (ecma_copy_or_ref_ecma_string (pattern_p)));
166-
167-
ecma_simple_value_t prop_value;
168-
169-
/* Set global property. ECMA-262 v5, 15.10.7.2*/
170-
magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_GLOBAL);
171-
ecma_property_t *global_prop_p = ecma_create_named_data_property (obj_p,
172-
magic_string_p,
173-
false, false, false);
174-
ecma_deref_ecma_string (magic_string_p);
175-
prop_value = flags & RE_FLAG_GLOBAL ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE;
176-
ecma_set_named_data_property_value (global_prop_p, ecma_make_simple_value (prop_value));
177-
178-
/* Set ignoreCase property. ECMA-262 v5, 15.10.7.3*/
179-
magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_IGNORECASE_UL);
180-
ecma_property_t *ignorecase_prop_p = ecma_create_named_data_property (obj_p,
181-
magic_string_p,
182-
false, false, false);
183-
ecma_deref_ecma_string (magic_string_p);
184-
prop_value = flags & RE_FLAG_IGNORE_CASE ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE;
185-
ecma_set_named_data_property_value (ignorecase_prop_p, ecma_make_simple_value (prop_value));
186-
187-
188-
/* Set multiline property. ECMA-262 v5, 15.10.7.4*/
189-
magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_MULTILINE);
190-
ecma_property_t *multiline_prop_p = ecma_create_named_data_property (obj_p,
191-
magic_string_p,
192-
false, false, false);
193-
ecma_deref_ecma_string (magic_string_p);
194-
prop_value = flags & RE_FLAG_MULTILINE ? ECMA_SIMPLE_VALUE_TRUE : ECMA_SIMPLE_VALUE_FALSE;
195-
ecma_set_named_data_property_value (multiline_prop_p, ecma_make_simple_value (prop_value));
196-
197-
/* Set lastIndex property. ECMA-262 v5, 15.10.7.5*/
198-
magic_string_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL);
199-
ecma_property_t *lastindex_prop_p = ecma_create_named_data_property (obj_p,
200-
magic_string_p,
201-
true, false, false);
202-
ecma_deref_ecma_string (magic_string_p);
203-
204-
ecma_number_t *lastindex_num_p = ecma_alloc_number ();
205-
*lastindex_num_p = ECMA_NUMBER_ZERO;
206-
ecma_named_data_property_assign_value (obj_p, lastindex_prop_p, ecma_make_number_value (lastindex_num_p));
207-
ecma_dealloc_number (lastindex_num_p);
253+
re_initialize_props (obj_p, pattern_p, flags);
208254

209255
/* Set bytecode internal property. */
210256
ecma_property_t *bytecode_prop_p;
211257
bytecode_prop_p = ecma_create_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE);
212258

213259
/* Compile bytecode. */
214-
ECMA_TRY_CATCH (empty, re_compile_bytecode (bytecode_prop_p, pattern_p, flags), ret_value);
260+
re_bytecode_t *bc_p = NULL;
261+
ECMA_TRY_CATCH (empty, re_compile_bytecode (&bc_p, pattern_p, flags), ret_value);
262+
263+
ECMA_SET_POINTER (bytecode_prop_p->u.internal_property.value, bc_p);
215264
ret_value = ecma_make_normal_completion_value (ecma_make_object_value (obj_p));
265+
216266
ECMA_FINALIZE (empty);
217267

218268
if (ecma_is_completion_value_throw (ret_value))

jerry-core/ecma/operations/ecma-regexp-object.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,14 @@ re_set_result_array_properties (ecma_object_t *array_obj_p,
6565
uint32_t num_of_elements,
6666
int32_t index);
6767

68+
extern ecma_completion_value_t
69+
re_parse_regexp_flags (ecma_string_t *flags_str_p, uint8_t *flags_p);
70+
71+
extern void
72+
re_initialize_props (ecma_object_t *re_obj_p,
73+
ecma_string_t *source_p,
74+
uint8_t flags);
75+
6876
/**
6977
* @}
7078
* @}

jerry-core/lit/lit-magic-strings.inc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_INVALID_DATE_UL, "Invalid Date")
211211
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_APPLY, "apply")
212212
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CALL, "call")
213213
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_BIND, "bind")
214+
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_COMPILE, "compile")
214215
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_EXEC, "exec")
215216
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_TEST, "test")
216217
LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_NAME, "name")

0 commit comments

Comments
 (0)