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 "lit-strings.h"
17 #include "ecma-alloc.h"
18 #include "ecma-builtins.h"
19 #include "ecma-conversion.h"
20 #include "ecma-exceptions.h"
21 #include "ecma-gc.h"
22 #include "ecma-globals.h"
23 #include "ecma-helpers.h"
24 #include "ecma-objects.h"
25 #include "ecma-string-object.h"
26 #if ENABLED (JERRY_ES2015)
27 #include "ecma-symbol-object.h"
28 #endif /* ENABLED (JERRY_ES2015) */
29 #include "ecma-try-catch-macro.h"
30 #include "jrt.h"
31
32 #if ENABLED (JERRY_BUILTIN_STRING)
33
34 #define ECMA_BUILTINS_INTERNAL
35 #include "ecma-builtins-internal.h"
36
37 #define BUILTIN_INC_HEADER_NAME "ecma-builtin-string.inc.h"
38 #define BUILTIN_UNDERSCORED_ID string
39 #include "ecma-builtin-internal-routines-template.inc.h"
40
41 /** \addtogroup ecma ECMA
42 * @{
43 *
44 * \addtogroup ecmabuiltins
45 * @{
46 *
47 * \addtogroup string ECMA String object built-in
48 * @{
49 */
50
51 /**
52 * The String object's 'fromCharCode' routine
53 *
54 * See also:
55 * ECMA-262 v5, 15.5.3.2
56 *
57 * @return ecma value
58 * Returned value must be freed with ecma_free_value.
59 */
60 static ecma_value_t
ecma_builtin_string_object_from_char_code(ecma_value_t this_arg,const ecma_value_t args[],ecma_length_t args_number)61 ecma_builtin_string_object_from_char_code (ecma_value_t this_arg, /**< 'this' argument */
62 const ecma_value_t args[], /**< arguments list */
63 ecma_length_t args_number) /**< number of arguments */
64 {
65 JERRY_UNUSED (this_arg);
66
67 if (args_number == 0)
68 {
69 return ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY);
70 }
71
72 ecma_value_t ret_value = ECMA_VALUE_EMPTY;
73 ecma_string_t *ret_string_p = NULL;
74 lit_utf8_size_t utf8_buf_size = args_number * LIT_CESU8_MAX_BYTES_IN_CODE_UNIT;
75
76 JMEM_DEFINE_LOCAL_ARRAY (utf8_buf_p,
77 utf8_buf_size,
78 lit_utf8_byte_t);
79
80 lit_utf8_size_t utf8_buf_used = 0;
81
82 for (ecma_length_t arg_index = 0;
83 arg_index < args_number && ecma_is_value_empty (ret_value);
84 arg_index++)
85 {
86 ECMA_OP_TO_NUMBER_TRY_CATCH (arg_num, args[arg_index], ret_value);
87
88 uint32_t uint32_char_code = ecma_number_to_uint32 (arg_num);
89 ecma_char_t code_unit = (uint16_t) uint32_char_code;
90
91 JERRY_ASSERT (utf8_buf_used <= utf8_buf_size - LIT_UTF8_MAX_BYTES_IN_CODE_UNIT);
92 utf8_buf_used += lit_code_unit_to_utf8 (code_unit, utf8_buf_p + utf8_buf_used);
93 JERRY_ASSERT (utf8_buf_used <= utf8_buf_size);
94
95 ECMA_OP_TO_NUMBER_FINALIZE (arg_num);
96 }
97
98 if (ecma_is_value_empty (ret_value))
99 {
100 ret_string_p = ecma_new_ecma_string_from_utf8 (utf8_buf_p, utf8_buf_used);
101 }
102
103 JMEM_FINALIZE_LOCAL_ARRAY (utf8_buf_p);
104
105 if (ecma_is_value_empty (ret_value))
106 {
107 ret_value = ecma_make_string_value (ret_string_p);
108 }
109
110 return ret_value;
111 } /* ecma_builtin_string_object_from_char_code */
112
113 #if ENABLED (JERRY_ES2015)
114
115 /**
116 * The String object's 'raw' routine
117 *
118 * See also:
119 * ECMA-262 v6, 21.1.2.4
120 *
121 * @return ecma value
122 * Returned value must be freed with ecma_free_value.
123 */
124 static ecma_value_t
ecma_builtin_string_object_raw(ecma_value_t this_arg,const ecma_value_t args[],ecma_length_t args_number)125 ecma_builtin_string_object_raw (ecma_value_t this_arg, /**< 'this' argument */
126 const ecma_value_t args[], /**< arguments list */
127 ecma_length_t args_number) /**< number of arguments */
128 {
129 JERRY_UNUSED (this_arg);
130
131 /* 1 - 2. */
132 const ecma_value_t *substitutions;
133 ecma_length_t number_of_substitutions;
134
135 if (args_number > 1)
136 {
137 substitutions = args + 1;
138 number_of_substitutions = args_number - 1;
139 }
140 else
141 {
142 substitutions = NULL;
143 number_of_substitutions = 0;
144 }
145
146 /* 3. */
147 ecma_value_t template = args_number > 0 ? args[0] : ECMA_VALUE_UNDEFINED;
148
149 ecma_value_t cooked = ecma_op_to_object (template);
150
151 /* 4. */
152 if (ECMA_IS_VALUE_ERROR (cooked))
153 {
154 return cooked;
155 }
156
157 ecma_object_t *cooked_obj_p = ecma_get_object_from_value (cooked);
158
159 /* 5. */
160 ecma_value_t raw = ecma_op_object_get_by_magic_id (cooked_obj_p, LIT_MAGIC_STRING_RAW);
161
162 ecma_deref_object (cooked_obj_p);
163
164 if (ECMA_IS_VALUE_ERROR (raw))
165 {
166 return raw;
167 }
168
169 ecma_value_t raw_obj = ecma_op_to_object (raw);
170
171 /* 6. */
172 if (ECMA_IS_VALUE_ERROR (raw_obj))
173 {
174 ecma_free_value (raw);
175 return raw_obj;
176 }
177
178 ecma_object_t *raw_obj_p = ecma_get_object_from_value (raw_obj);
179
180 ecma_value_t ret_value = ECMA_VALUE_ERROR;
181
182 /* 7 - 8. */
183 uint32_t literal_segments;
184 if (ECMA_IS_VALUE_ERROR (ecma_op_object_get_length (raw_obj_p, &literal_segments)))
185 {
186 goto cleanup;
187 }
188
189 /* 9. */
190 if (literal_segments == 0)
191 {
192 ret_value = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY);
193 goto cleanup;
194 }
195
196 /* 10. */
197 ecma_stringbuilder_t builder = ecma_stringbuilder_create ();
198
199 /* 11. */
200 uint32_t next_index = 0;
201
202 /* 12. */
203 while (true)
204 {
205 /* 12.a,b */
206 ecma_value_t next_seg = ecma_op_object_get_by_uint32_index (raw_obj_p, next_index);
207
208 if (ECMA_IS_VALUE_ERROR (next_seg))
209 {
210 goto builder_cleanup;
211 }
212
213 ecma_string_t *next_seg_srt_p = ecma_op_to_string (next_seg);
214
215 /* 12.c */
216 if (JERRY_UNLIKELY (next_seg_srt_p == NULL))
217 {
218 ecma_free_value (next_seg);
219 goto builder_cleanup;
220 }
221
222 /* 12.d */
223 ecma_stringbuilder_append (&builder, next_seg_srt_p);
224
225 ecma_deref_ecma_string (next_seg_srt_p);
226 ecma_free_value (next_seg);
227
228 /* 12.e */
229 if (next_index + 1 == literal_segments)
230 {
231 ret_value = ecma_make_string_value (ecma_stringbuilder_finalize (&builder));
232 goto cleanup;
233 }
234
235 /* 12.f-g */
236 if (next_index >= number_of_substitutions)
237 {
238 next_index++;
239 continue;
240 }
241
242 /* 12.h */
243 ecma_string_t *next_sub_p = ecma_op_to_string (substitutions[next_index]);
244
245 /* 12.i */
246 if (JERRY_UNLIKELY (next_sub_p == NULL))
247 {
248 goto builder_cleanup;
249 }
250
251 /* 12.j */
252 ecma_stringbuilder_append (&builder, next_sub_p);
253 ecma_deref_ecma_string (next_sub_p);
254
255 /* 12.k */
256 next_index++;
257 }
258
259 builder_cleanup:
260 ecma_stringbuilder_destroy (&builder);
261
262 cleanup:
263 ecma_deref_object (raw_obj_p);
264 ecma_free_value (raw);
265
266 return ret_value;
267 } /* ecma_builtin_string_object_raw */
268
269 /**
270 * The String object's 'fromCodePoint' routine
271 *
272 * See also:
273 * ECMA-262 v6, 21.1.2.2
274 *
275 * @return ecma value
276 * Returned value must be freed with ecma_free_value.
277 */
278 static ecma_value_t
ecma_builtin_string_object_from_code_point(ecma_value_t this_arg,const ecma_value_t args[],ecma_length_t args_number)279 ecma_builtin_string_object_from_code_point (ecma_value_t this_arg, /**< 'this' argument */
280 const ecma_value_t args[], /**< arguments list */
281 ecma_length_t args_number) /**< number of arguments */
282 {
283 JERRY_UNUSED (this_arg);
284
285 if (args_number == 0)
286 {
287 return ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY);
288 }
289
290 ecma_stringbuilder_t builder = ecma_stringbuilder_create ();
291
292 for (ecma_length_t index = 0; index < args_number; index++)
293 {
294 ecma_value_t to_number_value = ecma_op_to_number (args[index]);
295
296 if (ECMA_IS_VALUE_ERROR (to_number_value))
297 {
298 ecma_stringbuilder_destroy (&builder);
299 return to_number_value;
300 }
301
302 ecma_number_t to_number_num = ecma_get_number_from_value (to_number_value);
303 ecma_free_value (to_number_value);
304
305 ecma_number_t to_int_num;
306 ecma_value_t to_int_value = ecma_op_to_integer (to_number_value, &to_int_num);
307
308 if (ECMA_IS_VALUE_ERROR (to_int_value))
309 {
310 ecma_stringbuilder_destroy (&builder);
311 return to_int_value;
312 }
313
314 if (to_number_num != to_int_num || to_int_num < 0 || to_int_num > LIT_UNICODE_CODE_POINT_MAX)
315 {
316 ecma_stringbuilder_destroy (&builder);
317 return ecma_raise_range_error (ECMA_ERR_MSG ("Error: Invalid code point"));
318 }
319
320 lit_code_point_t code_point = (uint32_t) to_int_num;
321
322 ecma_char_t converted_cp[2];
323 uint8_t encoded_size = lit_utf16_encode_code_point (code_point, converted_cp);
324
325 for (uint8_t i = 0; i < encoded_size; i++)
326 {
327 ecma_stringbuilder_append_char (&builder, converted_cp[i]);
328 }
329 }
330
331 ecma_string_t *ret_str_p = ecma_stringbuilder_finalize (&builder);
332
333 return ecma_make_string_value (ret_str_p);
334 } /* ecma_builtin_string_object_from_code_point */
335
336 #endif /* ENABLED (JERRY_ES2015) */
337
338 /**
339 * Handle calling [[Call]] of built-in String object
340 *
341 * See also:
342 * ECMA-262 v6, 21.1.1.1
343 *
344 * @return ecma value
345 */
346 ecma_value_t
ecma_builtin_string_dispatch_call(const ecma_value_t * arguments_list_p,ecma_length_t arguments_list_len)347 ecma_builtin_string_dispatch_call (const ecma_value_t *arguments_list_p, /**< arguments list */
348 ecma_length_t arguments_list_len) /**< number of arguments */
349 {
350 JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
351
352 ecma_value_t ret_value = ECMA_VALUE_EMPTY;
353
354 /* 1. */
355 if (arguments_list_len == 0)
356 {
357 ret_value = ecma_make_magic_string_value (LIT_MAGIC_STRING__EMPTY);
358 }
359 #if ENABLED (JERRY_ES2015)
360 /* 2.a */
361 else if (ecma_is_value_symbol (arguments_list_p[0]))
362 {
363 ret_value = ecma_get_symbol_descriptive_string (arguments_list_p[0]);
364 }
365 #endif /* ENABLED (JERRY_ES2015) */
366 /* 2.b */
367 else
368 {
369 ecma_string_t *str_p = ecma_op_to_string (arguments_list_p[0]);
370 if (JERRY_UNLIKELY (str_p == NULL))
371 {
372 return ECMA_VALUE_ERROR;
373 }
374
375 ret_value = ecma_make_string_value (str_p);
376 }
377
378 return ret_value;
379 } /* ecma_builtin_string_dispatch_call */
380
381 /**
382 * Handle calling [[Construct]] of built-in String object
383 *
384 * @return ecma value
385 */
386 ecma_value_t
ecma_builtin_string_dispatch_construct(const ecma_value_t * arguments_list_p,ecma_length_t arguments_list_len)387 ecma_builtin_string_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */
388 ecma_length_t arguments_list_len) /**< number of arguments */
389 {
390 JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL);
391
392 return ecma_op_create_string_object (arguments_list_p, arguments_list_len);
393 } /* ecma_builtin_string_dispatch_construct */
394
395 /**
396 * @}
397 * @}
398 * @}
399 */
400
401 #endif /* ENABLED (JERRY_BUILTIN_STRING) */
402