Skip to main content

nanvm_lib/vm/any/
get_iterator.rs

1use crate::vm::{Any, IVm, IteratorRecord, Unpacked, error};
2
3impl<A: IVm> Any<A> {
4    /// ECMAScript's `GetIterator(self, sync)`
5    /// (<https://tc39.es/ecma262/#sec-getiterator>), restricted to the values
6    /// a FunctionalScript module can build: an array's elements, or a
7    /// string's code points, each a string. Every other value — `null`,
8    /// `undefined`, a boolean, a number, a `bigint`, an object, a function —
9    /// is not iterable, and the `TypeError` is raised here, before any
10    /// element. No object is iterable: a module cannot spell
11    /// `Symbol.iterator`.
12    ///
13    /// The one protocol behind array spread, call spread and array
14    /// destructuring. Not `Array::concat`, which keeps a non-array item
15    /// whole: `[...'ab']` is `['a', 'b']`, not `['ab']`, and `[...{}]`
16    /// throws.
17    pub fn get_iterator(self) -> Result<IteratorRecord<A>, Any<A>> {
18        match self.into() {
19            Unpacked::Array(array) => Ok(IteratorRecord::Array(array.into_iter())),
20            Unpacked::String(string) => Ok(IteratorRecord::String { string, next: 0 }),
21            _ => Err(error::not_iterable()),
22        }
23    }
24}
25
26#[cfg(test)]
27mod tests {
28    use crate::{
29        naive::Naive,
30        vm::{
31            Any, IVm, Nullish, ToAny, ToArray, ToObject, error,
32            unstable::{bigint_any, f64_any},
33        },
34    };
35
36    type A = Naive;
37
38    /// Every value that is not an array or a string throws, an empty object
39    /// included: `[...1]`, `[...null]`, `[...{}]`.
40    #[test]
41    fn not_iterable() {
42        let values: [Any<A>; 8] = [
43            Nullish::Null.to_any(),
44            Any::undefined(),
45            true.to_any(),
46            f64_any(0x3ff0_0000_0000_0000),
47            bigint_any(1),
48            [].to_object().to_any(),
49            [("0".into(), 1.0.to_any())].to_object().to_any(),
50            A::static_function(|_, _| Ok(Any::undefined()), 0, [].to_array(), None).to_any(),
51        ];
52        for v in values {
53            assert_eq!(v.get_iterator().err(), Some(error::not_iterable()));
54        }
55    }
56
57    #[test]
58    fn iterable() {
59        let empty: Any<A> = "".into();
60        assert!(empty.get_iterator().is_ok());
61        let array: Any<A> = [].to_array().to_any();
62        assert!(array.get_iterator().is_ok());
63    }
64}