• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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