Implement %IteratorPrototype% [ @@dispose ] and %AsyncIteratorPrototype% [ @@asyncDispose ]

Signed-off-by: Seonghyun Kim <sh8281.kim@samsung.com>
This commit is contained in:
Seonghyun Kim 2025-08-20 15:47:00 +09:00 committed by Patrick Kim
commit c3fadf767b
5 changed files with 81 additions and 12 deletions

View file

@ -23,6 +23,7 @@
#include "runtime/VMInstance.h"
#include "runtime/NativeFunctionObject.h"
#include "runtime/ArrayObject.h"
#include "runtime/PromiseObject.h"
namespace Escargot {
@ -220,6 +221,75 @@ static Value builtinIteratorMap(ExecutionState& state, Value thisValue, size_t a
return result;
}
static Value builtinIteratorDispose(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
// Let O be the this value.
const Value& O = thisValue;
// Let return be ? GetMethod(O, "return").
Value returnValue = Object::getMethod(state, O, state.context()->staticStrings().stringReturn);
// If return is not undefined, then
if (!returnValue.isUndefined()) {
// Perform ? Call(return, O, « »).
Object::call(state, returnValue, O, 0, nullptr);
}
// Return NormalCompletion(empty).
return Value();
}
static Value builtinIteratorAsyncDispose(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
// Let O be the this value.
const Value& O = thisValue;
// Let promiseCapability be ! NewPromiseCapability(%Promise%).
auto promiseCapability = PromiseObject::newPromiseCapability(state, state.context()->globalObject()->promise());
// Let return be Completion(GetMethod(O, "return")).
Value returnValue;
try {
returnValue = Object::getMethod(state, O, state.context()->staticStrings().stringReturn);
} catch (const Value& error) {
// IfAbruptRejectPromise(return, promiseCapability).
Value arg = error;
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &arg);
return promiseCapability.m_promise;
}
// If return is undefined, then
if (returnValue.isUndefined()) {
// Perform ! Call(promiseCapability.[[Resolve]], undefined, « undefined »).
Object::call(state, promiseCapability.m_resolveFunction, Value(), 1, &returnValue);
} else {
// Else,
// Let result be Completion(Call(return, O, « undefined »)).
Value result;
try {
Value argv;
result = Object::call(state, returnValue, Value(), 1, &argv);
} catch (const Value& error) {
// IfAbruptRejectPromise(result, promiseCapability).
Value arg = error;
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &arg);
return promiseCapability.m_promise;
}
// Let resultWrapper be Completion(PromiseResolve(%Promise%, result)).
Value resultWrapper;
try {
resultWrapper = PromiseObject::promiseResolve(state, state.context()->globalObject()->promise(), result);
} catch (const Value& error) {
// IfAbruptRejectPromise(resultWrapper, promiseCapability).
Value arg = error;
Object::call(state, promiseCapability.m_rejectFunction, Value(), 1, &arg);
return promiseCapability.m_promise;
}
// Let unwrap be a new Abstract Closure that performs the following steps when called:
// i. Return undefined.
// Let onFulfilled be CreateBuiltinFunction(unwrap, 1, "", « »).
Value onFulfilled = new NativeFunctionObject(state, NativeFunctionInfo(AtomicString(), [](ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget) -> Value { return Value(); }, 1, NativeFunctionInfo::Strict));
// Perform PerformPromiseThen(resultWrapper, onFulfilled, undefined, promiseCapability).
promiseCapability.m_promise->asPromiseObject()->then(state, onFulfilled, Value());
}
// Return promiseCapability.[[Promise]].
return promiseCapability.m_promise;
}
static std::pair<Value, bool> iteratorFilterClosure(ExecutionState& state, IteratorHelperObject* obj, void* data)
{
// Let closure be a new Abstract Closure with no parameters that captures iterated and predicate and performs the following steps when called:
@ -906,6 +976,9 @@ void GlobalObject::installIterator(ExecutionState& state)
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->symbolAsyncIterator, builtinSpeciesGetter, 0, NativeFunctionInfo::Strict)),
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_asyncIteratorPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().asyncDispose),
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->symbolAsyncDispose, builtinIteratorAsyncDispose, 0, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_iteratorPrototype = new PrototypeObject(state);
m_iteratorPrototype->setGlobalIntrinsicObject(state, true);
// https://www.ecma-international.org/ecma-262/10.0/index.html#sec-%iteratorprototype%-@@iterator
@ -915,6 +988,9 @@ void GlobalObject::installIterator(ExecutionState& state)
m_iteratorPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(state.context()->vmInstance()->globalSymbols().toStringTag)),
ObjectPropertyDescriptor(Value(strings->Iterator.string()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_iteratorPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().dispose),
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(strings->symbolDispose, builtinIteratorDispose, 0, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
m_genericIteratorPrototype = new PrototypeObject(state, m_iteratorPrototype);
m_genericIteratorPrototype->setGlobalIntrinsicObject(state, true);

View file

@ -118,6 +118,8 @@ void StaticStrings::initStaticStrings()
INIT_STATIC_STRING(symbolSplit, "[Symbol.split]");
INIT_STATIC_STRING(symbolAsyncIterator, "[Symbol.asyncIterator]");
INIT_STATIC_STRING(symbolIterator, "[Symbol.iterator]");
INIT_STATIC_STRING(symbolDispose, "[Symbol.dispose]");
INIT_STATIC_STRING(symbolAsyncDispose, "[Symbol.asyncDispose]");
#if defined(ENABLE_WASM)
INIT_STATIC_STRING(getExports, "get exports");

View file

@ -1091,6 +1091,8 @@ public:
AtomicString symbolReplace;
AtomicString symbolSearch;
AtomicString symbolSplit;
AtomicString symbolDispose;
AtomicString symbolAsyncDispose;
#if defined(ENABLE_WASM)
AtomicString getExports;

@ -1 +1 @@
Subproject commit 40a372e4d26cea0fec929c83c23f25b0840ad9fe
Subproject commit 29486d5dcc33fb323eeb6dbef0712feba19f03cf

View file

@ -81,11 +81,6 @@
<test id="built-ins/AsyncDisposableStack/undefined-newtarget-throws"><reason>TODO</reason></test>
<test id="built-ins/AsyncGeneratorPrototype/return/return-state-completed-broken-promise"><reason>TODO</reason></test>
<test id="built-ins/AsyncGeneratorPrototype/return/return-suspendedStart-broken-promise"><reason>TODO</reason></test>
<test id="built-ins/AsyncIteratorPrototype/Symbol.asyncDispose/is-function"><reason>TODO</reason></test>
<test id="built-ins/AsyncIteratorPrototype/Symbol.asyncDispose/length"><reason>TODO</reason></test>
<test id="built-ins/AsyncIteratorPrototype/Symbol.asyncDispose/name"><reason>TODO</reason></test>
<test id="built-ins/AsyncIteratorPrototype/Symbol.asyncDispose/prop-desc"><reason>TODO</reason></test>
<test id="built-ins/AsyncIteratorPrototype/Symbol.asyncDispose/return-val"><reason>TODO</reason></test>
<test id="built-ins/DataView/custom-proto-access-resizes-buffer-invalid-by-length"><reason>TODO</reason></test>
<test id="built-ins/DataView/custom-proto-access-resizes-buffer-invalid-by-offset"><reason>TODO</reason></test>
<test id="built-ins/DataView/custom-proto-access-resizes-buffer-valid-by-offset"><reason>TODO</reason></test>
@ -137,12 +132,6 @@
<test id="built-ins/Iterator/concat/throws-typeerror-when-generator-is-running-return"><reason>TODO</reason></test>
<test id="built-ins/Iterator/concat/throws-typeerror-when-iterator-not-an-object"><reason>TODO</reason></test>
<test id="built-ins/Iterator/concat/zero-arguments"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/Symbol.dispose/invokes-return"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/Symbol.dispose/is-function"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/Symbol.dispose/length"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/Symbol.dispose/name"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/Symbol.dispose/prop-desc"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/Symbol.dispose/return-val"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/Symbol.toStringTag/prop-desc"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/Symbol.toStringTag/weird-setter"><reason>TODO</reason></test>
<test id="built-ins/Iterator/prototype/constructor/prop-desc"><reason>TODO</reason></test>