Skip to content

Commit c1f72df

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 c1f72df

File tree

8 files changed

+345
-55
lines changed

8 files changed

+345
-55
lines changed

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

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

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

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

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

89+
ROUTINE (LIT_MAGIC_STRING_COMPILE, ecma_builtin_regexp_prototype_compile, NON_FIXED, 1)
8990
ROUTINE (LIT_MAGIC_STRING_EXEC, ecma_builtin_regexp_prototype_exec, 1, 1)
9091
ROUTINE (LIT_MAGIC_STRING_TEST, ecma_builtin_regexp_prototype_test, 1, 1)
9192
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: 104 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+
* Initialize properties of RegExp instance.
124+
*/
125+
void
126+
re_initialize_props (ecma_object_t *re_obj_p,
127+
ecma_string_t *source_p,
128+
uint8_t 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)
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)
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)
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)
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)
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,68 +250,25 @@ 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))
219269
{
270+
JERRY_ASSERT (bc_p != NULL);
271+
mem_heap_free_block (bc_p);
220272
ecma_deref_object (obj_p);
221273
}
222274

0 commit comments

Comments
 (0)