• 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 "ecma-alloc.h"
17 #include "ecma-array-object.h"
18 #include "ecma-iterator-object.h"
19 #include "ecma-builtin-helpers.h"
20 #include "ecma-builtins.h"
21 #include "ecma-exceptions.h"
22 #include "ecma-gc.h"
23 #include "ecma-globals.h"
24 #include "ecma-helpers.h"
25 #include "ecma-number-arithmetic.h"
26 #include "ecma-objects.h"
27 #include "ecma-objects-general.h"
28 #include "ecma-function-object.h"
29 #include "jcontext.h"
30 
31 /** \addtogroup ecma ECMA
32  * @{
33  *
34  * \addtogroup ecmaiteratorobject ECMA iterator object related routines
35  * @{
36  */
37 
38 #if ENABLED (JERRY_ES2015)
39 
40 /**
41  * Implementation of 'CreateArrayFromList' specialized for iterators
42  *
43  * See also:
44  *          ECMA-262 v6, 7.3.16.
45  *
46  * Note:
47  *      Returned value must be freed with ecma_free_value.
48  *
49  * @return new array object
50  */
51 ecma_value_t
ecma_create_array_from_iter_element(ecma_value_t value,ecma_value_t index_value)52 ecma_create_array_from_iter_element (ecma_value_t value, /**< value */
53                                      ecma_value_t index_value) /**< iterator index */
54 {
55   /* 2. */
56   ecma_value_t new_array = ecma_op_create_array_object (NULL, 0, false);
57   JERRY_ASSERT (!ECMA_IS_VALUE_ERROR (new_array));
58   ecma_object_t *new_array_p = ecma_get_object_from_value (new_array);
59 
60   /* 3 - 4. */
61   for (uint32_t index = 0; index < 2; index++)
62   {
63     ecma_string_t *index_string_p = ecma_new_ecma_string_from_uint32 (index);
64 
65     /* 4.a */
66     ecma_value_t completion = ecma_builtin_helper_def_prop (new_array_p,
67                                                             index_string_p,
68                                                             (index == 0) ? index_value : value,
69                                                             ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE);
70 
71     /* 4.b */
72     JERRY_ASSERT (ecma_is_value_true (completion));
73 
74     ecma_deref_ecma_string (index_string_p);
75   }
76 
77   /* 5. */
78   return new_array;
79 } /* ecma_create_array_from_iter_element */
80 
81 /**
82  * CreateIterResultObject operation
83  *
84  * See also:
85  *          ECMA-262 v6, 7.4.7.
86  *
87  * Note:
88  *      Returned value must be freed with ecma_free_value.
89  *
90  * @return iterator result object
91  */
92 ecma_value_t
ecma_create_iter_result_object(ecma_value_t value,ecma_value_t done)93 ecma_create_iter_result_object (ecma_value_t value, /**< value */
94                                 ecma_value_t done) /**< ECMA_VALUE_{TRUE,FALSE} based
95                                                     *   on the iterator index */
96 {
97   /* 1. */
98   JERRY_ASSERT (ecma_is_value_boolean (done));
99 
100   /* 2. */
101   ecma_object_t *object_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE),
102                                                 0,
103                                                 ECMA_OBJECT_TYPE_GENERAL);
104 
105   /* 3. */
106   ecma_property_value_t *prop_value_p;
107   prop_value_p = ecma_create_named_data_property (object_p,
108                                                   ecma_get_magic_string (LIT_MAGIC_STRING_VALUE),
109                                                   ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
110                                                   NULL);
111 
112   prop_value_p->value = ecma_copy_value_if_not_object (value);
113 
114   /* 4. */
115   prop_value_p = ecma_create_named_data_property (object_p,
116                                                   ecma_get_magic_string (LIT_MAGIC_STRING_DONE),
117                                                   ECMA_PROPERTY_CONFIGURABLE_ENUMERABLE_WRITABLE,
118                                                   NULL);
119   prop_value_p->value = done;
120 
121   /* 5. */
122   return ecma_make_object_value (object_p);
123 } /* ecma_create_iter_result_object */
124 
125 /**
126  * General iterator object creation operation.
127  *
128  * See also: ECMA-262 v6, 21.1.5.1, 22.1.5.1, 23.1.5.1
129  *
130  * Note:
131  *      Returned value must be freed with ecma_free_value.
132  *
133  * @return iterator object
134  */
135 ecma_value_t
ecma_op_create_iterator_object(ecma_value_t iterated_value,ecma_object_t * prototype_obj_p,uint8_t iterator_type,uint8_t extra_info)136 ecma_op_create_iterator_object (ecma_value_t iterated_value, /**< value from create iterator */
137                                 ecma_object_t *prototype_obj_p, /**< prototype object */
138                                 uint8_t iterator_type, /**< iterator type, see ecma_pseudo_array_type_t */
139                                 uint8_t extra_info) /**< extra information */
140 {
141   /* 1. */
142   JERRY_ASSERT (iterator_type >= ECMA_PSEUDO_ARRAY_ITERATOR && iterator_type <= ECMA_PSEUDO_ARRAY__MAX);
143 
144   /* 2. */
145   ecma_object_t *object_p = ecma_create_object (prototype_obj_p,
146                                                 sizeof (ecma_extended_object_t),
147                                                 ECMA_OBJECT_TYPE_PSEUDO_ARRAY);
148 
149   ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p;
150   ext_obj_p->u.pseudo_array.type = iterator_type;
151 
152   /* 3. */
153   ext_obj_p->u.pseudo_array.u2.iterated_value = iterated_value;
154   /* 4. */
155   ext_obj_p->u.pseudo_array.u1.iterator_index = 0;
156   /* 5. */
157   ext_obj_p->u.pseudo_array.extra_info = extra_info;
158 
159   /* 6. */
160   return ecma_make_object_value (object_p);
161 } /* ecma_op_create_iterator_object */
162 
163 /**
164  * GetIterator operation
165  *
166  * See also: ECMA-262 v6, 7.4.1
167  *
168  * Note:
169  *      Returned value must be freed with ecma_free_value.
170  *
171  * @return iterator object - if success
172  *         raised error - otherwise
173  */
174 ecma_value_t
ecma_op_get_iterator(ecma_value_t value,ecma_value_t method)175 ecma_op_get_iterator (ecma_value_t value, /**< value to get iterator from */
176                       ecma_value_t method) /**< provided method argument */
177 {
178   /* 1. */
179   if (ECMA_IS_VALUE_ERROR (value))
180   {
181     return value;
182   }
183 
184   /* 2. */
185   bool has_method = !ecma_is_value_empty (method);
186 
187   if (!has_method)
188   {
189     /* 2.a */
190     method = ecma_op_get_method_by_symbol_id (value, LIT_GLOBAL_SYMBOL_ITERATOR);
191 
192     /* 2.b */
193     if (ECMA_IS_VALUE_ERROR (method))
194     {
195       return method;
196     }
197   }
198 
199   /* 3. */
200   if (!ecma_is_value_object (method) || !ecma_op_is_callable (method))
201   {
202     ecma_free_value (method);
203     return ecma_raise_type_error (ECMA_ERR_MSG ("object is not iterable"));
204   }
205 
206   ecma_object_t *method_obj_p = ecma_get_object_from_value (method);
207   ecma_value_t iterator = ecma_op_function_call (method_obj_p, value, NULL, 0);
208 
209   if (!has_method)
210   {
211     ecma_deref_object (method_obj_p);
212   }
213 
214   /* 4. */
215   if (ECMA_IS_VALUE_ERROR (iterator))
216   {
217     return iterator;
218   }
219 
220   /* 5. */
221   if (!ecma_is_value_object (iterator))
222   {
223     ecma_free_value (iterator);
224     return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator is not an object."));
225   }
226 
227   /* 6. */
228   return iterator;
229 } /* ecma_op_get_iterator */
230 
231 /**
232  * IteratorNext operation
233  *
234  * See also: ECMA-262 v6, 7.4.2
235  *
236  * Note:
237  *      Returned value must be freed with ecma_free_value.
238  *
239  * @return iterator result object - if success
240  *         raised error - otherwise
241  */
242 static ecma_value_t
ecma_op_iterator_next(ecma_value_t iterator,ecma_value_t value)243 ecma_op_iterator_next (ecma_value_t iterator, /**< iterator value */
244                        ecma_value_t value) /**< the routines's value argument */
245 {
246   JERRY_ASSERT (ecma_is_value_object (iterator));
247 
248   /* 1 - 2. */
249   ecma_object_t *obj_p = ecma_get_object_from_value (iterator);
250 
251   ecma_value_t func_next = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_NEXT);
252 
253   if (ECMA_IS_VALUE_ERROR (func_next))
254   {
255     return func_next;
256   }
257 
258   if (!ecma_is_value_object (func_next) || !ecma_op_is_callable (func_next))
259   {
260     ecma_free_value (func_next);
261     return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator next() is not callable."));
262   }
263 
264   ecma_object_t *next_obj_p = ecma_get_object_from_value (func_next);
265 
266   bool has_value = !ecma_is_value_empty (value);
267 
268   ecma_value_t result;
269   if (has_value)
270   {
271     result = ecma_op_function_call (next_obj_p, iterator, &value, 1);
272   }
273   else
274   {
275     result = ecma_op_function_call (next_obj_p, iterator, NULL, 0);
276   }
277 
278   ecma_free_value (func_next);
279 
280   /* 5. */
281   return result;
282 } /* ecma_op_iterator_next */
283 
284 /**
285  * IteratorReturn operation
286  *
287  * See also: ECMA-262 v6, 14.4.14 (last part)
288  *
289  * Note:
290  *      Returned value must be freed with ecma_free_value.
291  *
292  * @return iterator result object - if success
293  *         raised error - otherwise
294  */
295 static ecma_value_t
ecma_op_iterator_return(ecma_value_t iterator,ecma_value_t value)296 ecma_op_iterator_return (ecma_value_t iterator, /**< iterator value */
297                          ecma_value_t value) /**< the routines's value argument */
298 {
299   JERRY_ASSERT (ecma_is_value_object (iterator));
300 
301   ecma_object_t *obj_p = ecma_get_object_from_value (iterator);
302   ecma_value_t func_return = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_RETURN);
303 
304   if (ECMA_IS_VALUE_ERROR (func_return))
305   {
306     return func_return;
307   }
308 
309   if (func_return == ECMA_VALUE_UNDEFINED)
310   {
311     return ecma_create_iter_result_object (value, true);
312   }
313 
314   if (!ecma_is_value_object (func_return) || !ecma_op_is_callable (func_return))
315   {
316     ecma_free_value (func_return);
317     return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator return() is not callable."));
318   }
319 
320   ecma_object_t *return_obj_p = ecma_get_object_from_value (func_return);
321 
322   ecma_value_t result = ecma_op_function_call (return_obj_p, iterator, &value, 1);
323   ecma_free_value (func_return);
324 
325   return result;
326 } /* ecma_op_iterator_return */
327 
328 /**
329  * IteratorThrow operation
330  *
331  * See also: ECMA-262 v6, 14.4.14 (last part)
332  *
333  * Note:
334  *      Returned value must be freed with ecma_free_value.
335  *
336  * @return iterator result object - if success
337  *         raised error - otherwise
338  */
339 static ecma_value_t
ecma_op_iterator_throw(ecma_value_t iterator,ecma_value_t value)340 ecma_op_iterator_throw (ecma_value_t iterator, /**< iterator value */
341                         ecma_value_t value) /**< the routines's value argument */
342 {
343   JERRY_ASSERT (ecma_is_value_object (iterator));
344 
345   ecma_object_t *obj_p = ecma_get_object_from_value (iterator);
346   ecma_value_t func_throw = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_THROW);
347 
348   if (ECMA_IS_VALUE_ERROR (func_throw))
349   {
350     return func_throw;
351   }
352 
353   if (func_throw == ECMA_VALUE_UNDEFINED)
354   {
355     ecma_value_t result = ecma_op_iterator_close (iterator);
356 
357     if (ECMA_IS_VALUE_ERROR (result))
358     {
359       return result;
360     }
361 
362     ecma_free_value (result);
363     return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator throw() is not available."));
364   }
365 
366   if (!ecma_is_value_object (func_throw) || !ecma_op_is_callable (func_throw))
367   {
368     ecma_free_value (func_throw);
369     return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator throw() is not callable."));
370   }
371 
372   ecma_object_t *return_obj_p = ecma_get_object_from_value (func_throw);
373 
374   ecma_value_t result = ecma_op_function_call (return_obj_p, iterator, &value, 1);
375   ecma_free_value (func_throw);
376 
377   return result;
378 } /* ecma_op_iterator_throw */
379 
380 /**
381  * IteratorValue operation
382  *
383  * See also: ECMA-262 v6, 7.4.4
384  *
385  * Note:
386  *      Returned value must be freed with ecma_free_value.
387  *
388  * @return value of the iterator result object
389  */
390 ecma_value_t
ecma_op_iterator_value(ecma_value_t iter_result)391 ecma_op_iterator_value (ecma_value_t iter_result) /**< iterator value */
392 {
393   /* 1. */
394   JERRY_ASSERT (ecma_is_value_object (iter_result));
395 
396   /* 2. */
397   ecma_object_t *obj_p = ecma_get_object_from_value (iter_result);
398   return ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_VALUE);
399 } /* ecma_op_iterator_value */
400 
401 /**
402  * IteratorClose operation
403  *
404  * See also: ECMA-262 v6, 7.4.6
405  *
406  * @return ECMA_VALUE_EMPTY - if "return" is succesfully invoked,
407  *                            and the operation is called with normal completion
408  *         ECMA_VALUE_ERROR - otherwise
409  */
410 ecma_value_t
ecma_op_iterator_close(ecma_value_t iterator)411 ecma_op_iterator_close (ecma_value_t iterator) /**< iterator value */
412 {
413   /* 1. */
414   JERRY_ASSERT (ecma_is_value_object (iterator));
415 
416   /* 2. */
417   ecma_value_t completion = ECMA_VALUE_EMPTY;
418 
419   if (jcontext_has_pending_exception ())
420   {
421     completion = jcontext_take_exception ();
422   }
423 
424   /* 3. */
425   ecma_value_t return_method = ecma_op_get_method_by_magic_id (iterator, LIT_MAGIC_STRING_RETURN);
426 
427   /* 4. */
428   if (ECMA_IS_VALUE_ERROR (return_method))
429   {
430     ecma_free_value (completion);
431     return return_method;
432   }
433 
434   /* 5. */
435   if (ecma_is_value_undefined (return_method))
436   {
437     if (ecma_is_value_empty (completion))
438     {
439       return ECMA_VALUE_UNDEFINED;
440     }
441 
442     jcontext_raise_exception (completion);
443     return ECMA_VALUE_ERROR;
444   }
445 
446   /* 6. */
447   ecma_object_t *return_obj_p = ecma_get_object_from_value (return_method);
448   ecma_value_t inner_result = ecma_op_function_call (return_obj_p, iterator, NULL, 0);
449   ecma_deref_object (return_obj_p);
450 
451   /* 7. */
452   if (!ecma_is_value_empty (completion))
453   {
454     if (ECMA_IS_VALUE_ERROR (inner_result))
455     {
456       jcontext_release_exception ();
457     }
458     else
459     {
460       ecma_free_value (inner_result);
461     }
462 
463     jcontext_raise_exception (completion);
464     return ECMA_VALUE_ERROR;
465   }
466 
467   /* 8. */
468   if (ECMA_IS_VALUE_ERROR (inner_result))
469   {
470     ecma_free_value (completion);
471     return inner_result;
472   }
473 
474   /* 9. */
475   bool is_object = ecma_is_value_object (inner_result);
476   ecma_free_value (inner_result);
477 
478   if (!is_object)
479   {
480     ecma_free_value (completion);
481     return ecma_raise_type_error (ECMA_ERR_MSG ("method 'return' is not callable."));
482   }
483 
484   /* 10. */
485   if (ecma_is_value_empty (completion))
486   {
487     return ECMA_VALUE_UNDEFINED;
488   }
489 
490   jcontext_raise_exception (completion);
491   return ECMA_VALUE_ERROR;
492 } /* ecma_op_iterator_close */
493 
494 /**
495  * IteratorStep operation
496  *
497  * See also: ECMA-262 v6, 7.4.5
498  *
499  * Note:
500  *      Returned value must be freed with ecma_free_value.
501  *
502  * @return iterator object or ECMA_VALUE_FALSE - if success
503  *         raised error - otherwise
504  */
505 ecma_value_t
ecma_op_iterator_step(ecma_value_t iterator)506 ecma_op_iterator_step (ecma_value_t iterator) /**< iterator value */
507 {
508   /* 1. */
509   ecma_value_t result = ecma_op_iterator_next (iterator, ECMA_VALUE_EMPTY);
510 
511   /* 2. */
512   if (ECMA_IS_VALUE_ERROR (result))
513   {
514     return result;
515   }
516 
517   if (!ecma_is_value_object (result))
518   {
519     ecma_free_value (result);
520     return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator result is not an object."));
521   }
522 
523   /* 3. */
524   ecma_object_t *obj_p = ecma_get_object_from_value (result);
525   ecma_value_t done = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_DONE);
526 
527   /* 4. */
528   if (ECMA_IS_VALUE_ERROR (done))
529   {
530     ecma_free_value (result);
531     return done;
532   }
533 
534   bool is_done = ecma_op_to_boolean (done);
535   ecma_free_value (done);
536 
537   /* 5. */
538   if (is_done)
539   {
540     ecma_free_value (result);
541     return ECMA_VALUE_FALSE;
542   }
543 
544   /* 6. */
545   return result;
546 } /* ecma_op_iterator_step */
547 
548 /**
549  * Perform a command specified by the command argument
550  *
551  * Note:
552  *      Returned value must be freed with ecma_free_value.
553  *
554  * @return iterator object - if success
555  *         raised error - otherwise
556  */
557 ecma_value_t
ecma_op_iterator_do(ecma_iterator_command_type_t command,ecma_value_t iterator,ecma_value_t value,bool * done_p)558 ecma_op_iterator_do (ecma_iterator_command_type_t command, /**< command to be executed */
559                      ecma_value_t iterator, /**< iterator object */
560                      ecma_value_t value, /**< the routines's value argument */
561                      bool *done_p) /**< it contains the logical value of the done property */
562 {
563   ecma_value_t result;
564 
565   if (command == ECMA_ITERATOR_NEXT)
566   {
567     result = ecma_op_iterator_next (iterator, value);
568   }
569   else if (command == ECMA_ITERATOR_RETURN)
570   {
571     result = ecma_op_iterator_return (iterator, value);
572   }
573   else
574   {
575     JERRY_ASSERT (command == ECMA_ITERATOR_THROW);
576     result = ecma_op_iterator_throw (iterator, value);
577   }
578 
579   if (ECMA_IS_VALUE_ERROR (result))
580   {
581     return result;
582   }
583 
584   if (!ecma_is_value_object (result))
585   {
586     ecma_free_value (result);
587     return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator result is not an object."));
588   }
589 
590   ecma_object_t *obj_p = ecma_get_object_from_value (result);
591   ecma_value_t done = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_DONE);
592 
593   if (ECMA_IS_VALUE_ERROR (done))
594   {
595     ecma_free_value (result);
596     return done;
597   }
598 
599   *done_p = ecma_op_to_boolean (done);
600   ecma_free_value (done);
601 
602   return result;
603 } /* ecma_op_iterator_do */
604 
605 #endif /* ENABLED (JERRY_ES2015) */
606 
607 /**
608  * @}
609  * @}
610  */
611