/** * The RegExp.prototype object's 'exec' routine * * See also: * ECMA-262 v5, 15.10.6.2 * * @return array object containing the results - if the matched * null - otherwise * * May raise error, so returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_builtin_regexp_prototype_exec (ecma_value_t this_arg, /**< this argument */ ecma_value_t arg) /**< routine's argument */ { ecma_value_t ret_value = ecma_make_simple_value (ECMA_SIMPLE_VALUE_EMPTY); if (!ecma_is_value_object (this_arg) || ecma_object_get_class_name (ecma_get_object_from_value (this_arg)) != LIT_MAGIC_STRING_REGEXP_UL) { ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Incomplete RegExp type")); } else { ECMA_TRY_CATCH (obj_this, ecma_op_to_object (this_arg), ret_value); ECMA_TRY_CATCH (input_str_value, ecma_op_to_string (arg), ret_value); ecma_property_t *bytecode_prop_p; ecma_object_t *obj_p = ecma_get_object_from_value (obj_this); bytecode_prop_p = ecma_get_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE); void *bytecode_p = ECMA_GET_INTERNAL_VALUE_POINTER (void, ecma_get_internal_property_value (bytecode_prop_p)); if (bytecode_p == NULL) { /* Missing bytecode means empty RegExp: '/(?:)/', so always return empty string. */ ecma_string_t *capture_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); ecma_value_t arguments_list[1]; arguments_list[0] = ecma_make_string_value (capture_str_p); ret_value = ecma_op_create_array_object (arguments_list, 1, false); ecma_deref_ecma_string (capture_str_p); re_set_result_array_properties (ecma_get_object_from_value (ret_value), ecma_get_string_from_value (input_str_value), 1, 0); } else { ret_value = ecma_regexp_exec_helper (obj_this, input_str_value, false); } ECMA_FINALIZE (input_str_value); ECMA_FINALIZE (obj_this); } return ret_value; } /* ecma_builtin_regexp_prototype_exec */
/** * RegExp helper function to start the recursive matching algorithm * and create the result Array object * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t ecma_regexp_exec_helper (ecma_value_t regexp_value, /**< RegExp object */ ecma_value_t input_string, /**< input string */ bool ignore_global) /**< ignore global flag */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); JERRY_ASSERT (ecma_is_value_object (regexp_value)); JERRY_ASSERT (ecma_is_value_string (input_string)); ecma_object_t *regexp_object_p = ecma_get_object_from_value (regexp_value); JERRY_ASSERT (ecma_object_get_class_name (regexp_object_p) == LIT_MAGIC_STRING_REGEXP_UL); ecma_property_t *bytecode_prop_p = ecma_get_internal_property (regexp_object_p, ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE); re_bytecode_t *bc_p = ECMA_GET_POINTER (re_bytecode_t, bytecode_prop_p->u.internal_property.value); ecma_string_t *input_string_p = ecma_get_string_from_value (input_string); lit_utf8_size_t input_string_size = ecma_string_get_size (input_string_p); MEM_DEFINE_LOCAL_ARRAY (input_utf8_buffer_p, input_string_size, lit_utf8_byte_t); ecma_string_to_utf8_string (input_string_p, input_utf8_buffer_p, (ssize_t) input_string_size); lit_utf8_iterator_t iterator = lit_utf8_iterator_create (input_utf8_buffer_p, input_string_size); re_matcher_ctx_t re_ctx; re_ctx.input_start_p = iterator.buf_p; re_ctx.input_end_p = iterator.buf_p + iterator.buf_size; /* 1. Read bytecode header and init regexp matcher context. */ re_ctx.flags = (uint8_t) re_get_value (&bc_p); if (ignore_global) { re_ctx.flags &= (uint8_t) ~RE_FLAG_GLOBAL; } JERRY_DDLOG ("Exec with flags [global: %d, ignoreCase: %d, multiline: %d]\n", re_ctx.flags & RE_FLAG_GLOBAL, re_ctx.flags & RE_FLAG_IGNORE_CASE, re_ctx.flags & RE_FLAG_MULTILINE); re_ctx.num_of_captures = re_get_value (&bc_p); JERRY_ASSERT (re_ctx.num_of_captures % 2 == 0); re_ctx.num_of_non_captures = re_get_value (&bc_p); /* We create an invalid iterator, that will be used to identify unused result values. */ lit_utf8_iterator_t unused_iter = lit_utf8_iterator_create (NULL, 0); unused_iter.buf_p = (lit_utf8_byte_t *) 1; MEM_DEFINE_LOCAL_ARRAY (saved_p, re_ctx.num_of_captures + re_ctx.num_of_non_captures, lit_utf8_iterator_t); for (uint32_t i = 0; i < re_ctx.num_of_captures + re_ctx.num_of_non_captures; i++) { saved_p[i] = unused_iter; } re_ctx.saved_p = saved_p; uint32_t num_of_iter_length = (re_ctx.num_of_captures / 2) + (re_ctx.num_of_non_captures - 1); MEM_DEFINE_LOCAL_ARRAY (num_of_iter_p, num_of_iter_length, uint32_t); for (uint32_t i = 0; i < num_of_iter_length; i++) { num_of_iter_p[i] = 0u; } bool is_match = false; re_ctx.num_of_iterations_p = num_of_iter_p; int32_t index = 0; ecma_length_t input_str_len = lit_utf8_string_length (iterator.buf_p, iterator.buf_size); if (iterator.buf_p && (re_ctx.flags & RE_FLAG_GLOBAL)) { ecma_string_t *magic_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL); ecma_property_t *lastindex_prop_p = ecma_op_object_get_property (regexp_object_p, magic_str_p); ECMA_OP_TO_NUMBER_TRY_CATCH (lastindex_num, lastindex_prop_p->u.named_data_property.value, ret_value) index = ecma_number_to_int32 (lastindex_num); JERRY_ASSERT (iterator.buf_pos.offset == 0 && !iterator.buf_pos.is_non_bmp_middle); if (!lit_utf8_iterator_is_eos (&iterator) && index <= (int32_t) input_str_len && index > 0) { lit_utf8_iterator_advance (&iterator, (ecma_length_t) index); } ECMA_OP_TO_NUMBER_FINALIZE (lastindex_num); ecma_deref_ecma_string (magic_str_p); } /* 2. Try to match */ lit_utf8_iterator_t sub_iter = lit_utf8_iterator_create (NULL, 0); while (ecma_is_completion_value_empty (ret_value)) { if (index < 0 || index > (int32_t) input_str_len) { if (re_ctx.flags & RE_FLAG_GLOBAL) { ecma_string_t *magic_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL); ecma_number_t *lastindex_num_p = ecma_alloc_number (); *lastindex_num_p = ECMA_NUMBER_ZERO; ecma_op_object_put (regexp_object_p, magic_str_p, ecma_make_number_value (lastindex_num_p), true); ecma_dealloc_number (lastindex_num_p); ecma_deref_ecma_string (magic_str_p); } is_match = false; break; } else { ECMA_TRY_CATCH (match_value, re_match_regexp (&re_ctx, bc_p, iterator, &sub_iter), ret_value); if (ecma_is_value_true (match_value)) { is_match = true; break; } if (!lit_utf8_iterator_is_eos (&iterator)) { lit_utf8_iterator_advance (&iterator, 1); } index++; ECMA_FINALIZE (match_value); } } if (iterator.buf_p && (re_ctx.flags & RE_FLAG_GLOBAL)) { ecma_string_t *magic_str_p = ecma_get_magic_string (LIT_MAGIC_STRING_LASTINDEX_UL); ecma_number_t *lastindex_num_p = ecma_alloc_number (); *lastindex_num_p = sub_iter.buf_pos.offset; ecma_op_object_put (regexp_object_p, magic_str_p, ecma_make_number_value (lastindex_num_p), true); ecma_dealloc_number (lastindex_num_p); ecma_deref_ecma_string (magic_str_p); } /* 3. Fill the result array or return with 'undefiend' */ if (ecma_is_completion_value_empty (ret_value)) { if (is_match) { ecma_completion_value_t result_array = ecma_op_create_array_object (0, 0, false); ecma_object_t *result_array_obj_p = ecma_get_object_from_completion_value (result_array); ecma_string_t *input_str_p = ecma_new_ecma_string_from_utf8 (iterator.buf_p, iterator.buf_size); re_set_result_array_properties (result_array_obj_p, input_str_p, re_ctx.num_of_captures / 2, index); ecma_deref_ecma_string (input_str_p); for (uint32_t i = 0; i < re_ctx.num_of_captures; i += 2) { ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (i / 2); /* Note: 'iter_p->buf_p == NULL' means the input is empty string */ if ((re_ctx.saved_p[i].buf_p != unused_iter.buf_p && re_ctx.saved_p[i + 1].buf_p != unused_iter.buf_p) && re_ctx.saved_p[i + 1].buf_pos.offset >= re_ctx.saved_p[i].buf_pos.offset) { ecma_length_t capture_str_len; capture_str_len = (ecma_length_t) re_ctx.saved_p[i + 1].buf_pos.offset - re_ctx.saved_p[i].buf_pos.offset; ecma_string_t *capture_str_p; if (capture_str_len > 0) { const lit_utf8_byte_t *utf8_str_p = re_ctx.saved_p[i].buf_p + re_ctx.saved_p[i].buf_pos.offset; capture_str_p = ecma_new_ecma_string_from_utf8 (utf8_str_p, capture_str_len); } else { capture_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); } ecma_op_object_put (result_array_obj_p, index_str_p, ecma_make_string_value (capture_str_p), true); ecma_deref_ecma_string (capture_str_p); } else { ecma_op_object_put (result_array_obj_p, index_str_p, ecma_make_simple_value (ECMA_SIMPLE_VALUE_UNDEFINED), true); } ecma_deref_ecma_string (index_str_p); } ret_value = result_array; } else { ret_value = ecma_make_normal_completion_value (ecma_make_simple_value (ECMA_SIMPLE_VALUE_NULL)); } } MEM_FINALIZE_LOCAL_ARRAY (num_of_iter_p); MEM_FINALIZE_LOCAL_ARRAY (saved_p); MEM_FINALIZE_LOCAL_ARRAY (input_utf8_buffer_p); return ret_value; } /* ecma_regexp_exec_helper */
/** * The RegExp.prototype object's 'exec' routine * * See also: * ECMA-262 v5, 15.10.6.2 * * @return completion value * Returned value must be freed with ecma_free_completion_value. */ static ecma_completion_value_t ecma_builtin_regexp_prototype_exec (ecma_value_t this_arg, /**< this argument */ ecma_value_t arg) /**< routine's argument */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); if (!ecma_is_value_object (this_arg) || ecma_object_get_class_name (ecma_get_object_from_value (this_arg)) != LIT_MAGIC_STRING_REGEXP_UL) { ret_value = ecma_raise_type_error ("Incomplete RegExp type"); } else { ECMA_TRY_CATCH (obj_this, ecma_op_to_object (this_arg), ret_value); ECMA_TRY_CATCH (input_str_value, ecma_op_to_string (arg), ret_value); ecma_property_t *bytecode_prop_p; ecma_object_t *obj_p = ecma_get_object_from_completion_value (obj_this); bytecode_prop_p = ecma_get_internal_property (obj_p, ECMA_INTERNAL_PROPERTY_REGEXP_BYTECODE); void *bytecode_p = ECMA_GET_POINTER (void, bytecode_prop_p->u.internal_property.value); if (bytecode_p == NULL) { /* Missing bytecode means empty RegExp: '/(?:)/', so always return empty string. */ ecma_completion_value_t result_array = ecma_op_create_array_object (0, 0, false); ecma_object_t *result_array_obj_p = ecma_get_object_from_completion_value (result_array); ecma_string_t *input_str_p = ecma_get_string_from_value (input_str_value); re_set_result_array_properties (result_array_obj_p, input_str_p, 1, 0); ecma_string_t *index_str_p = ecma_new_ecma_string_from_uint32 (0); ecma_string_t *capture_str_p = ecma_get_magic_string (LIT_MAGIC_STRING__EMPTY); ECMA_TRY_CATCH (put_res_value, ecma_op_object_put (result_array_obj_p, index_str_p, ecma_make_string_value (capture_str_p), true), ret_value); ret_value = result_array; ECMA_FINALIZE (put_res_value) ecma_deref_ecma_string (capture_str_p); ecma_deref_ecma_string (index_str_p); } else { ret_value = ecma_regexp_exec_helper (obj_this, input_str_value, false); } ECMA_FINALIZE (input_str_value); ECMA_FINALIZE (obj_this); } return ret_value; } /* ecma_builtin_regexp_prototype_exec */