Skip to content

Commit 6242f09

Browse files
2Jaeheonclover2123
authored andcommitted
Implement Iterator.prototype.flatMap method
Signed-off-by: 2jaeheon <[email protected]>
1 parent 6d0874b commit 6242f09

File tree

2 files changed

+125
-38
lines changed

2 files changed

+125
-38
lines changed

src/builtins/BuiltinIterator.cpp

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,17 @@ struct IteratorData : public gc {
132132
{
133133
}
134134
};
135+
struct FlatMapIteratorData : public IteratorData {
136+
IteratorRecord* innerIterator;
137+
bool innerAlive;
138+
139+
FlatMapIteratorData(Value mapper)
140+
: IteratorData(mapper)
141+
, innerIterator(nullptr)
142+
, innerAlive(false)
143+
{
144+
}
145+
};
135146

136147
static std::pair<Value, bool> iteratorMapClosure(ExecutionState& state, IteratorHelperObject* obj, void* data)
137148
{
@@ -739,6 +750,117 @@ static Value builtinIteratorToArray(ExecutionState& state, Value thisValue, size
739750
}
740751
}
741752

753+
static std::pair<Value, bool> iteratorFlatMapClosure(ExecutionState& state, IteratorHelperObject* obj, void* data)
754+
{
755+
// Let closure be a new Abstract Closure with no parameters that captures iterated and mapper and performs the following steps when called:
756+
// a. Let counter be 0.
757+
// b. Repeat,
758+
// i. Let value be ? IteratorStepValue(iterated).
759+
// ii. If value is done, return ReturnCompletion(undefined).
760+
// iii. Let mapped be Completion(Call(mapper, undefined, « value, 𝔽(counter) »)).
761+
// iv. IfAbruptCloseIterator(mapped, iterated).
762+
// v. Let innerIterator be Completion(GetIteratorFlattenable(mapped, reject-primitives)).
763+
// vi. IfAbruptCloseIterator(innerIterator, iterated).
764+
// vii. Let innerAlive be true.
765+
// viii. Repeat, while innerAlive is true,
766+
// 1. Let innerValue be Completion(IteratorStepValue(innerIterator)).
767+
// 2. IfAbruptCloseIterator(innerValue, iterated).
768+
// 3. If innerValue is done, then
769+
// a. Set innerAlive to false.
770+
// 4. Else,
771+
// a. Let completion be Completion(Yield(innerValue)).
772+
// b. If completion is an abrupt completion, then
773+
// i. Let backupCompletion be Completion(IteratorClose(innerIterator, completion)).
774+
// ii. IfAbruptCloseIterator(backupCompletion, iterated).
775+
// iii. Return ? IteratorClose(iterated, completion).
776+
// ix. Set counter to counter + 1.
777+
IteratorRecord* iterated = obj->underlyingIterator();
778+
FlatMapIteratorData* closureData = reinterpret_cast<FlatMapIteratorData*>(data);
779+
Value mapper = closureData->callback;
780+
781+
while (true) {
782+
// while innerAlive is true, Let innerValue be Completion(IteratorStepValue(innerIterator)).
783+
if (closureData->innerAlive && closureData->innerIterator) {
784+
Optional<Value> innerValue;
785+
try {
786+
innerValue = IteratorObject::iteratorStepValue(state, closureData->innerIterator);
787+
} catch (const Value& e) {
788+
// IfAbruptCloseIterator(innerValue, iterated).
789+
IteratorObject::iteratorClose(state, obj->underlyingIterator(), e, true);
790+
}
791+
if (!innerValue) {
792+
// If innerValue is done, then Set innerAlive to false.
793+
closureData->innerAlive = false;
794+
closureData->innerIterator = nullptr;
795+
} else {
796+
// Else, Let completion be Completion(Yield(innerValue)).
797+
return std::make_pair(innerValue.value(), false);
798+
}
799+
}
800+
801+
// Let value be ? IteratorStepValue(iterated).
802+
auto value = IteratorObject::iteratorStepValue(state, iterated);
803+
// If value is done, return ReturnCompletion(undefined).
804+
if (!value) {
805+
iterated->m_done = true;
806+
return std::make_pair(Value(), true);
807+
}
808+
809+
// Let mapped be Completion(Call(mapper, undefined, « value, 𝔽(counter) »)).
810+
Value args[2] = { value.value(), Value(closureData->counter) };
811+
Value mapped;
812+
813+
try {
814+
mapped = Object::call(state, mapper, Value(), 2, args);
815+
} catch (const Value& e) {
816+
// IfAbruptCloseIterator(mapped, iterated).
817+
IteratorObject::iteratorClose(state, iterated, e, true);
818+
}
819+
820+
// Let innerIterator be Completion(GetIteratorFlattenable(mapped, reject-primitives)).
821+
IteratorRecord* innerIterator = nullptr;
822+
try {
823+
innerIterator = IteratorObject::getIteratorFlattenable(state, mapped, IteratorObject::PrimitiveHandling::RejectPrimitives);
824+
} catch (const Value& e) {
825+
IteratorObject::iteratorClose(state, iterated, e, true);
826+
}
827+
828+
// Let innerAlive be true.
829+
// Set counter to counter + 1.
830+
closureData->innerAlive = true;
831+
closureData->innerIterator = innerIterator;
832+
closureData->counter = StorePositiveNumberAsOddNumber(closureData->counter + 1);
833+
}
834+
}
835+
836+
static Value builtinIteratorFlatMap(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
837+
{
838+
// Let O be the this value.
839+
const Value& O = thisValue;
840+
841+
// If O is not an Object, throw a TypeError exception.
842+
if (!O.isObject()) {
843+
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "this value is not Object");
844+
}
845+
846+
// If IsCallable(mapper) is false, throw a TypeError exception.
847+
const Value& mapper = argv[0];
848+
if (!mapper.isCallable()) {
849+
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "mapper is not callable");
850+
}
851+
852+
// Set iterated to ? GetIteratorDirect(O).
853+
IteratorRecord* iterated = IteratorObject::getIteratorDirect(state, O.asObject());
854+
855+
// Let result be CreateIteratorFromClosure(closure, "Iterator Helper", %IteratorHelperPrototype%, « [[UnderlyingIterator]] »).
856+
// Set result.[[UnderlyingIterator]] to iterated.
857+
IteratorHelperObject* result = new IteratorHelperObject(state, iteratorFlatMapClosure, iterated, new FlatMapIteratorData(mapper));
858+
859+
// Return result.
860+
return result;
861+
}
862+
863+
742864
static Value builtinGenericIteratorNext(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
743865
{
744866
if (!thisValue.isObject() || !thisValue.asObject()->isGenericIteratorObject()) {
@@ -840,6 +962,9 @@ void GlobalObject::installIterator(ExecutionState& state)
840962
m_iteratorPrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->toArray),
841963
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->toArray, builtinIteratorToArray, 0, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
842964

965+
m_iteratorPrototype->directDefineOwnProperty(state, ObjectPropertyName(strings->flatMap),
966+
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->flatMap, builtinIteratorFlatMap, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
967+
843968
directDefineOwnProperty(state, ObjectPropertyName(strings->Iterator),
844969
ObjectPropertyDescriptor(m_iterator, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
845970
}

tools/test/test262/excludelist.orig.xml

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -254,45 +254,7 @@
254254
<test id="built-ins/Iterator/prototype/filter/argument-validation-failure-closes-underlying"><reason>TODO</reason></test>
255255
<test id="built-ins/Iterator/prototype/find/argument-validation-failure-closes-underlying"><reason>TODO</reason></test>
256256
<test id="built-ins/Iterator/prototype/flatMap/argument-validation-failure-closes-underlying"><reason>TODO</reason></test>
257-
<test id="built-ins/Iterator/prototype/flatMap/callable"><reason>TODO</reason></test>
258-
<test id="built-ins/Iterator/prototype/flatMap/exhaustion-does-not-call-return"><reason>TODO</reason></test>
259-
<test id="built-ins/Iterator/prototype/flatMap/flattens-iterable"><reason>TODO</reason></test>
260-
<test id="built-ins/Iterator/prototype/flatMap/flattens-iterator"><reason>TODO</reason></test>
261-
<test id="built-ins/Iterator/prototype/flatMap/flattens-only-depth-1"><reason>TODO</reason></test>
262-
<test id="built-ins/Iterator/prototype/flatMap/get-next-method-only-once"><reason>TODO</reason></test>
263-
<test id="built-ins/Iterator/prototype/flatMap/get-next-method-throws"><reason>TODO</reason></test>
264-
<test id="built-ins/Iterator/prototype/flatMap/get-return-method-throws"><reason>TODO</reason></test>
265-
<test id="built-ins/Iterator/prototype/flatMap/is-function"><reason>TODO</reason></test>
266-
<test id="built-ins/Iterator/prototype/flatMap/iterable-primitives-are-not-flattened"><reason>TODO</reason></test>
267-
<test id="built-ins/Iterator/prototype/flatMap/iterable-to-iterator-fallback"><reason>TODO</reason></test>
268-
<test id="built-ins/Iterator/prototype/flatMap/iterator-already-exhausted"><reason>TODO</reason></test>
269-
<test id="built-ins/Iterator/prototype/flatMap/iterator-return-method-throws"><reason>TODO</reason></test>
270-
<test id="built-ins/Iterator/prototype/flatMap/length"><reason>TODO</reason></test>
271-
<test id="built-ins/Iterator/prototype/flatMap/mapper-args"><reason>TODO</reason></test>
272-
<test id="built-ins/Iterator/prototype/flatMap/mapper-returns-closed-iterator"><reason>TODO</reason></test>
273-
<test id="built-ins/Iterator/prototype/flatMap/mapper-returns-non-object"><reason>TODO</reason></test>
274-
<test id="built-ins/Iterator/prototype/flatMap/mapper-this"><reason>TODO</reason></test>
275-
<test id="built-ins/Iterator/prototype/flatMap/mapper-throws"><reason>TODO</reason></test>
276-
<test id="built-ins/Iterator/prototype/flatMap/mapper-throws-then-closing-iterator-also-throws"><reason>TODO</reason></test>
277-
<test id="built-ins/Iterator/prototype/flatMap/name"><reason>TODO</reason></test>
278-
<test id="built-ins/Iterator/prototype/flatMap/next-method-returns-non-object"><reason>TODO</reason></test>
279-
<test id="built-ins/Iterator/prototype/flatMap/next-method-returns-throwing-done"><reason>TODO</reason></test>
280-
<test id="built-ins/Iterator/prototype/flatMap/next-method-returns-throwing-value"><reason>TODO</reason></test>
281-
<test id="built-ins/Iterator/prototype/flatMap/next-method-returns-throwing-value-done"><reason>TODO</reason></test>
282-
<test id="built-ins/Iterator/prototype/flatMap/next-method-throws"><reason>TODO</reason></test>
283-
<test id="built-ins/Iterator/prototype/flatMap/prop-desc"><reason>TODO</reason></test>
284-
<test id="built-ins/Iterator/prototype/flatMap/proto"><reason>TODO</reason></test>
285-
<test id="built-ins/Iterator/prototype/flatMap/result-is-iterator"><reason>TODO</reason></test>
286257
<test id="built-ins/Iterator/prototype/flatMap/return-is-forwarded-to-mapper-result"><reason>TODO</reason></test>
287-
<test id="built-ins/Iterator/prototype/flatMap/return-is-forwarded-to-underlying-iterator"><reason>TODO</reason></test>
288-
<test id="built-ins/Iterator/prototype/flatMap/return-is-not-forwarded-after-exhaustion"><reason>TODO</reason></test>
289-
<test id="built-ins/Iterator/prototype/flatMap/strings-are-not-flattened"><reason>TODO</reason></test>
290-
<test id="built-ins/Iterator/prototype/flatMap/this-non-callable-next"><reason>TODO</reason></test>
291-
<test id="built-ins/Iterator/prototype/flatMap/this-plain-iterator"><reason>TODO</reason></test>
292-
<test id="built-ins/Iterator/prototype/flatMap/throws-typeerror-when-generator-is-running"><reason>TODO</reason></test>
293-
<test id="built-ins/Iterator/prototype/flatMap/underlying-iterator-advanced-in-parallel"><reason>TODO</reason></test>
294-
<test id="built-ins/Iterator/prototype/flatMap/underlying-iterator-closed"><reason>TODO</reason></test>
295-
<test id="built-ins/Iterator/prototype/flatMap/underlying-iterator-closed-in-parallel"><reason>TODO</reason></test>
296258
<test id="built-ins/Iterator/prototype/forEach/argument-validation-failure-closes-underlying"><reason>TODO</reason></test>
297259
<test id="built-ins/Iterator/prototype/map/argument-validation-failure-closes-underlying"><reason>TODO</reason></test>
298260
<test id="built-ins/Iterator/prototype/reduce/argument-validation-failure-closes-underlying"><reason>TODO</reason></test>

0 commit comments

Comments
 (0)