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