1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 15:27:35 +00:00

LibJS: Implement Iterator.prototype.toArray

This commit is contained in:
Timothy Flynn 2023-06-25 13:49:46 -04:00 committed by Andreas Kling
parent acc05480e8
commit 35380b2aef
4 changed files with 94 additions and 0 deletions

View file

@ -512,6 +512,7 @@ namespace JS {
P(timeZone) \ P(timeZone) \
P(timeZoneName) \ P(timeZoneName) \
P(timeZones) \ P(timeZones) \
P(toArray) \
P(toDateString) \ P(toDateString) \
P(toExponential) \ P(toExponential) \
P(toFixed) \ P(toFixed) \

View file

@ -6,6 +6,7 @@
#include <AK/Function.h> #include <AK/Function.h>
#include <LibJS/Runtime/AbstractOperations.h> #include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Array.h>
#include <LibJS/Runtime/FunctionObject.h> #include <LibJS/Runtime/FunctionObject.h>
#include <LibJS/Runtime/GlobalObject.h> #include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/IteratorHelper.h> #include <LibJS/Runtime/IteratorHelper.h>
@ -36,6 +37,7 @@ ThrowCompletionOr<void> IteratorPrototype::initialize(Realm& realm)
define_native_function(realm, vm.names.drop, drop, 1, attr); define_native_function(realm, vm.names.drop, drop, 1, attr);
define_native_function(realm, vm.names.flatMap, flat_map, 1, attr); define_native_function(realm, vm.names.flatMap, flat_map, 1, attr);
define_native_function(realm, vm.names.reduce, reduce, 1, attr); define_native_function(realm, vm.names.reduce, reduce, 1, attr);
define_native_function(realm, vm.names.toArray, to_array, 0, attr);
return {}; return {};
} }
@ -516,4 +518,36 @@ JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::reduce)
} }
} }
// 3.1.3.8 Iterator.prototype.toArray ( ), https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.toarray
JS_DEFINE_NATIVE_FUNCTION(IteratorPrototype::to_array)
{
auto& realm = *vm.current_realm();
// 1. Let O be the this value.
// 2. If O is not an Object, throw a TypeError exception.
auto object = TRY(this_object(vm));
// 3. Let iterated be ? GetIteratorDirect(O).
auto iterated = TRY(get_iterator_direct(vm, object));
// 4. Let items be a new empty List.
Vector<Value> items;
// 5. Repeat,
while (true) {
// a. Let next be ? IteratorStep(iterated).
auto next = TRY(iterator_step(vm, iterated));
// b. If next is false, return CreateArrayFromList(items).
if (!next)
return Array::create_from(realm, items);
// c. Let value be ? IteratorValue(next).
auto value = TRY(iterator_value(vm, *next));
// d. Append value to items.
TRY_OR_THROW_OOM(vm, items.try_append(value));
}
}
} }

View file

@ -28,6 +28,7 @@ private:
JS_DECLARE_NATIVE_FUNCTION(drop); JS_DECLARE_NATIVE_FUNCTION(drop);
JS_DECLARE_NATIVE_FUNCTION(flat_map); JS_DECLARE_NATIVE_FUNCTION(flat_map);
JS_DECLARE_NATIVE_FUNCTION(reduce); JS_DECLARE_NATIVE_FUNCTION(reduce);
JS_DECLARE_NATIVE_FUNCTION(to_array);
}; };
} }

View file

@ -0,0 +1,58 @@
describe("errors", () => {
test("iterator's next method throws", () => {
function TestError() {}
class TestIterator extends Iterator {
next() {
throw new TestError();
}
}
expect(() => {
new TestIterator().toArray();
}).toThrow(TestError);
});
test("value returned by iterator's next method throws", () => {
function TestError() {}
class TestIterator extends Iterator {
next() {
return {
done: false,
get value() {
throw new TestError();
},
};
}
}
expect(() => {
new TestIterator().toArray();
}).toThrow(TestError);
});
});
describe("normal behavior", () => {
test("length is 0", () => {
expect(Iterator.prototype.toArray).toHaveLength(0);
});
test("empty list", () => {
function* generator() {}
const result = generator().toArray();
expect(result).toEqual([]);
});
test("non-empty list", () => {
function* generator() {
yield 1;
yield 2;
yield 3;
}
const result = generator().toArray();
expect(result).toEqual([1, 2, 3]);
});
});