1/* Copyright JS Foundation and other contributors, http://js.foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "ecma-alloc.h"
17#include "ecma-builtins.h"
18#include "ecma-conversion.h"
19#include "ecma-exceptions.h"
20#include "ecma-gc.h"
21#include "ecma-helpers.h"
22#include "jcontext.h"
23#include "ecma-objects.h"
24#include "ecma-regexp-object.h"
25#include "ecma-try-catch-macro.h"
26
27#if ENABLED (JERRY_BUILTIN_REGEXP)
28
29#define ECMA_BUILTINS_INTERNAL
30#include "ecma-builtins-internal.h"
31
32#define BUILTIN_INC_HEADER_NAME "ecma-builtin-regexp.inc.h"
33#define BUILTIN_UNDERSCORED_ID regexp
34#include "ecma-builtin-internal-routines-template.inc.h"
35
36/** \addtogroup ecma ECMA
37 * @{
38 *
39 * \addtogroup ecmabuiltins
40 * @{
41 *
42 * \addtogroup regexp ECMA RegExp object built-in
43 * @{
44 */
45
46static ecma_value_t
47ecma_builtin_regexp_dispatch_helper (const ecma_value_t *arguments_list_p, /**< arguments list */
48                                     ecma_length_t arguments_list_len) /**< number of arguments */
49{
50  ecma_value_t pattern_value = ECMA_VALUE_UNDEFINED;
51  ecma_value_t flags_value = ECMA_VALUE_UNDEFINED;
52#if ENABLED (JERRY_ES2015)
53  bool create_regexp_from_bc = false;
54  bool free_arguments = false;
55  ecma_object_t *new_target_p = JERRY_CONTEXT (current_new_target);
56#else /* !ENABLED (JERRY_ES2015) */
57  ecma_object_t *new_target_p = NULL;
58#endif /* ENABLED (JERRY_ES2015) */
59
60  if (arguments_list_len > 0)
61  {
62    /* pattern string or RegExp object */
63    pattern_value = arguments_list_p[0];
64
65    if (arguments_list_len > 1)
66    {
67      flags_value = arguments_list_p[1];
68    }
69  }
70
71#if ENABLED (JERRY_ES2015)
72  ecma_value_t regexp_value = ecma_op_is_regexp (pattern_value);
73
74  if (ECMA_IS_VALUE_ERROR (regexp_value))
75  {
76    return regexp_value;
77  }
78
79  bool pattern_is_regexp = regexp_value == ECMA_VALUE_TRUE;
80  re_compiled_code_t *bc_p = NULL;
81
82  if (new_target_p == NULL)
83  {
84    new_target_p = ecma_builtin_get (ECMA_BUILTIN_ID_REGEXP);
85
86    if (pattern_is_regexp && ecma_is_value_undefined (flags_value))
87    {
88      ecma_object_t *pattern_obj_p = ecma_get_object_from_value (pattern_value);
89
90      ecma_value_t pattern_constructor = ecma_op_object_get_by_magic_id (pattern_obj_p, LIT_MAGIC_STRING_CONSTRUCTOR);
91
92      if (ECMA_IS_VALUE_ERROR (pattern_constructor))
93      {
94        return pattern_constructor;
95      }
96
97      bool is_same = ecma_op_same_value (ecma_make_object_value (new_target_p), pattern_constructor);
98      ecma_free_value (pattern_constructor);
99
100      if (is_same)
101      {
102        return ecma_copy_value (pattern_value);
103      }
104    }
105  }
106
107  if (ecma_object_is_regexp_object (pattern_value))
108  {
109    ecma_extended_object_t *pattern_obj_p = (ecma_extended_object_t *) ecma_get_object_from_value (pattern_value);
110    bc_p = ECMA_GET_INTERNAL_VALUE_POINTER (re_compiled_code_t,
111                                            pattern_obj_p->u.class_prop.u.value);
112
113    create_regexp_from_bc = ecma_is_value_undefined (flags_value);
114
115    if (!create_regexp_from_bc)
116    {
117      pattern_value = bc_p->source;
118    }
119  }
120  else if (pattern_is_regexp)
121  {
122    ecma_object_t *pattern_obj_p = ecma_get_object_from_value (pattern_value);
123
124    pattern_value = ecma_op_object_get_by_magic_id (pattern_obj_p, LIT_MAGIC_STRING_SOURCE);
125
126    if (ECMA_IS_VALUE_ERROR (pattern_value))
127    {
128      return pattern_value;
129    }
130
131    if (ecma_is_value_undefined (flags_value))
132    {
133      flags_value = ecma_op_object_get_by_magic_id (pattern_obj_p, LIT_MAGIC_STRING_FLAGS);
134
135      if (ECMA_IS_VALUE_ERROR (flags_value))
136      {
137        ecma_free_value (pattern_value);
138        return flags_value;
139      }
140    }
141    else
142    {
143      flags_value = ecma_copy_value (flags_value);
144    }
145
146    free_arguments = true;
147  }
148#else /* !ENABLED (JERRY_ES2015) */
149  if (ecma_object_is_regexp_object (pattern_value))
150  {
151    if (ecma_is_value_undefined (flags_value))
152    {
153      return ecma_copy_value (pattern_value);
154    }
155
156    return ecma_raise_type_error (ECMA_ERR_MSG ("Invalid argument of RegExp call."));
157  }
158#endif /* ENABLED (JERRY_ES2015) */
159
160  ecma_value_t ret_value = ECMA_VALUE_ERROR;
161  ecma_object_t *new_target_obj_p = ecma_op_regexp_alloc (new_target_p);
162
163  if (JERRY_LIKELY (new_target_obj_p != NULL))
164  {
165#if ENABLED (JERRY_ES2015)
166    if (create_regexp_from_bc)
167    {
168      ret_value = ecma_op_create_regexp_from_bytecode (new_target_obj_p, bc_p);
169      JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (ret_value));
170    }
171    else
172#endif /* ENABLED (JERRY_ES2015) */
173    {
174      ret_value = ecma_op_create_regexp_from_pattern (new_target_obj_p, pattern_value, flags_value);
175
176      if (ECMA_IS_VALUE_ERROR (ret_value))
177      {
178        ecma_deref_object (new_target_obj_p);
179      }
180    }
181  }
182
183#if ENABLED (JERRY_ES2015)
184  if (free_arguments)
185  {
186    ecma_free_value (pattern_value);
187    ecma_free_value (flags_value);
188  }
189#endif /* ENABLED (JERRY_ES2015) */
190
191  return ret_value;
192} /* ecma_builtin_regexp_dispatch_helper */
193
194/**
195 * Handle calling [[Call]] of built-in RegExp object
196 *
197 * @return ecma value
198 *         Returned value must be freed with ecma_free_value.
199 */
200ecma_value_t
201ecma_builtin_regexp_dispatch_call (const ecma_value_t *arguments_list_p, /**< arguments list */
202                                   ecma_length_t arguments_list_len) /**< number of arguments */
203{
204  return ecma_builtin_regexp_dispatch_helper (arguments_list_p,
205                                              arguments_list_len);
206} /* ecma_builtin_regexp_dispatch_call */
207
208/**
209 * Handle calling [[Construct]] of built-in RegExp object
210 *
211 * @return ecma value
212 *         Returned value must be freed with ecma_free_value.
213 */
214ecma_value_t
215ecma_builtin_regexp_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */
216                                        ecma_length_t arguments_list_len) /**< number of arguments */
217{
218  return ecma_builtin_regexp_dispatch_helper (arguments_list_p,
219                                              arguments_list_len);
220} /* ecma_builtin_regexp_dispatch_construct */
221
222#if ENABLED (JERRY_ES2015)
223/**
224 * 21.2.4.2 get RegExp [ @@species ] accessor
225 *
226 * @return ecma_value
227 *         returned value must be freed with ecma_free_value
228 */
229ecma_value_t
230ecma_builtin_regexp_species_get (ecma_value_t this_value) /**< This Value */
231{
232  return ecma_copy_value (this_value);
233} /* ecma_builtin_regexp_species_get */
234#endif /* ENABLED (JERRY_ES2015) */
235
236/**
237 * @}
238 * @}
239 * @}
240 */
241
242#endif /* ENABLED (JERRY_BUILTIN_REGEXP) */
243