* Copyright (c) 2023-2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/builtins/builtins_async_from_sync_iterator.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_async_from_sync_iterator.h"
#include "ecmascript/interpreter/interpreter.h"
#include "ecmascript/js_iterator.h"
#include "ecmascript/js_promise.h"
namespace panda::ecmascript::builtins {
JSTaggedValue BuiltinsAsyncFromSyncIterator::Next(EcmaRuntimeCallInfo *argv)
{
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, AsyncFromSyncIterator, Next);
[[maybe_unused]] EcmaHandleScope scope(thread);
auto vm = thread->GetEcmaVM();
JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
JSHandle<JSTaggedValue> thisValue = GetThis(argv);
if (!thisValue->IsAsyncFromSyncIterator()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "is not AsyncFromSyncIterator", JSTaggedValue::Exception());
}
JSHandle<PromiseCapability> pcap =
JSPromise::NewPromiseCapability(thread, JSHandle<JSTaggedValue>::Cast(env->GetPromiseFunction()));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSAsyncFromSyncIterator> asyncIterator(thisValue);
JSHandle<AsyncIteratorRecord> syncIteratorRecord(thread, asyncIterator->GetSyncIteratorRecord(thread));
JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> result;
if (value->IsNull()) {
result = JSIterator::IteratorNext(thread, syncIteratorRecord);
} else {
result = JSIterator::IteratorNext(thread, syncIteratorRecord, value);
}
RETURN_REJECT_PROMISE_IF_ABRUPT(thread, result, pcap);
return JSAsyncFromSyncIterator::AsyncFromSyncIteratorContinuation(thread, result, pcap);
}
JSTaggedValue BuiltinsAsyncFromSyncIterator::Throw(EcmaRuntimeCallInfo *argv)
{
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, AsyncFromSyncIterator, Throw);
[[maybe_unused]] EcmaHandleScope scope(thread);
auto vm = thread->GetEcmaVM();
const GlobalEnvConstants *globalConstant = thread->GlobalConstants();
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSTaggedValue> input(BuiltinsBase::GetThis(argv));
JSHandle<JSAsyncFromSyncIterator> asyncIterator(input);
JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
JSHandle<PromiseCapability> pcap =
JSPromise::NewPromiseCapability(thread, JSHandle<JSTaggedValue>::Cast(env->GetPromiseFunction()));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<AsyncIteratorRecord> syncIteratorRecord(thread, asyncIterator->GetSyncIteratorRecord(thread));
JSHandle<JSTaggedValue> syncIterator(thread, syncIteratorRecord->GetIterator(thread));
JSHandle<JSTaggedValue> throwString = globalConstant->GetHandledThrowString();
JSHandle<JSTaggedValue> throwResult = JSObject::GetMethod(thread, syncIterator, throwString);
RETURN_REJECT_PROMISE_IF_ABRUPT(thread, throwString, pcap);
JSHandle<JSTaggedValue> value = base::BuiltinsBase::GetCallArg(argv, 0);
JSHandle<JSTaggedValue> undefinedValue = globalConstant->GetHandledUndefined();
if (throwResult->IsUndefined()) {
JSHandle<JSObject> iterResult = JSIterator::CreateIterResultObject(thread, value, true);
JSHandle<JSTaggedValue> reject(thread, pcap->GetReject(thread));
EcmaRuntimeCallInfo *info =
EcmaInterpreter::NewRuntimeCallInfo(thread, reject, undefinedValue, undefinedValue, 1);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
info->SetCallArg(iterResult.GetTaggedValue());
return pcap->GetPromise(thread);
}
JSTaggedValue ret;
if (value->IsNull()) {
EcmaRuntimeCallInfo *callInfo =
EcmaInterpreter::NewRuntimeCallInfo(thread, throwResult, syncIterator, undefinedValue, 0);
ret = JSFunction::Call(callInfo);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
} else {
EcmaRuntimeCallInfo *callInfo =
EcmaInterpreter::NewRuntimeCallInfo(thread, throwResult, syncIterator, undefinedValue, 1);
RETURN_REJECT_PROMISE_IF_ABRUPT(thread, throwResult, pcap);
callInfo->SetCallArg(value.GetTaggedValue());
ret = JSFunction::Call(callInfo);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
}
JSHandle<JSTaggedValue> result(thread, ret);
if (!result->IsECMAObject()) {
JSHandle<JSObject> resolutionError =
factory->GetJSError(ErrorType::TYPE_ERROR,
"AsyncFromSyncIteratorPrototype.throw: is not Object.", StackCheck::NO);
JSHandle<JSTaggedValue> reject(thread, pcap->GetReject(thread));
EcmaRuntimeCallInfo *info =
EcmaInterpreter::NewRuntimeCallInfo(thread, reject, undefinedValue, undefinedValue, 1);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
info->SetCallArg(resolutionError.GetTaggedValue());
JSFunction::Call(info);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSObject> promise(thread, pcap->GetPromise(thread));
return promise.GetTaggedValue();
}
return JSAsyncFromSyncIterator::AsyncFromSyncIteratorContinuation(thread, result, pcap);
}
JSTaggedValue BuiltinsAsyncFromSyncIterator::Return(EcmaRuntimeCallInfo *argv)
{
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, AsyncFromSyncIterator, Return);
[[maybe_unused]] EcmaHandleScope scope(thread);
auto vm = thread->GetEcmaVM();
const GlobalEnvConstants *globalConstant = thread->GlobalConstants();
ObjectFactory *factory = vm->GetFactory();
JSHandle<JSTaggedValue> thisValue = GetThis(argv);
if (!thisValue->IsAsyncFromSyncIterator()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "is not AsyncFromSyncIterator", JSTaggedValue::Exception());
}
JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
JSHandle<PromiseCapability> pcap =
JSPromise::NewPromiseCapability(thread, JSHandle<JSTaggedValue>::Cast(env->GetPromiseFunction()));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSAsyncFromSyncIterator> asyncIterator(thisValue);
JSHandle<AsyncIteratorRecord> syncIteratorRecord(thread, asyncIterator->GetSyncIteratorRecord(thread));
JSHandle<JSTaggedValue> syncIterator(thread, syncIteratorRecord->GetIterator(thread));
JSHandle<JSTaggedValue> returnString = globalConstant->GetHandledReturnString();
JSHandle<JSTaggedValue> returnResult = JSObject::GetMethod(thread, syncIterator, returnString);
RETURN_REJECT_PROMISE_IF_ABRUPT(thread, returnResult, pcap);
JSHandle<JSTaggedValue> value = base::BuiltinsBase::GetCallArg(argv, 0);
JSHandle<JSTaggedValue> undefinedValue = globalConstant->GetHandledUndefined();
if (returnResult->IsUndefined()) {
JSHandle<JSObject> iterResult = JSIterator::CreateIterResultObject(thread, value, true);
JSHandle<JSTaggedValue> its = JSHandle<JSTaggedValue>::Cast(iterResult);
JSHandle<JSTaggedValue> resolve(thread, pcap->GetResolve(thread));
EcmaRuntimeCallInfo *info =
EcmaInterpreter::NewRuntimeCallInfo(thread, resolve, undefinedValue, undefinedValue, 1);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
info->SetCallArg(its.GetTaggedValue());
JSHandle<JSObject> promise(thread, pcap->GetPromise(thread));
return promise.GetTaggedValue();
}
JSTaggedValue ret;
if (value->IsNull()) {
EcmaRuntimeCallInfo *callInfo =
EcmaInterpreter::NewRuntimeCallInfo(thread, returnResult, syncIterator, undefinedValue, 0);
ret = JSFunction::Call(callInfo);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
} else {
EcmaRuntimeCallInfo *callInfo =
EcmaInterpreter::NewRuntimeCallInfo(thread, returnResult, syncIterator, undefinedValue, 1);
RETURN_REJECT_PROMISE_IF_ABRUPT(thread, returnResult, pcap);
callInfo->SetCallArg(value.GetTaggedValue());
ret = JSFunction::Call(callInfo);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
}
JSHandle<JSTaggedValue> result(thread, ret);
if (!result->IsECMAObject()) {
JSHandle<JSObject> resolutionError = factory->GetJSError(ErrorType::TYPE_ERROR,
"AsyncFromSyncIteratorPrototype.return: is not Object.", StackCheck::NO);
JSHandle<JSTaggedValue> rstErr = JSHandle<JSTaggedValue>::Cast(resolutionError);
JSHandle<JSTaggedValue> reject(thread, pcap->GetReject(thread));
EcmaRuntimeCallInfo *info =
EcmaInterpreter::NewRuntimeCallInfo(thread, reject, undefinedValue, undefinedValue, 1);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
info->SetCallArg(rstErr.GetTaggedValue());
JSFunction::Call(info);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSObject> promise(thread, pcap->GetPromise(thread));
return promise.GetTaggedValue();
}
return JSAsyncFromSyncIterator::AsyncFromSyncIteratorContinuation(thread, result, pcap);
}
}