1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/builtins/builtins_async_from_sync_iterator.h"
17 #include "ecmascript/builtins/builtins_promise.h"
18 #include "ecmascript/builtins/builtins_promise_handler.h"
19 #include "ecmascript/base/builtins_base.h"
20 #include "ecmascript/ecma_vm.h"
21 #include "ecmascript/global_env.h"
22 #include "ecmascript/js_tagged_value.h"
23 #include "ecmascript/js_async_from_sync_iterator.h"
24 #include "ecmascript/object_factory.h"
25 #include "ecmascript/js_iterator.h"
26 #include "ecmascript/js_promise.h"
27 #include "ecmascript/js_function.h"
28
29 namespace panda::ecmascript::builtins {
30
Next(EcmaRuntimeCallInfo * argv)31 JSTaggedValue BuiltinsAsyncFromSyncIterator::Next(EcmaRuntimeCallInfo *argv)
32 {
33 JSThread *thread = argv->GetThread();
34 [[maybe_unused]] EcmaHandleScope scope(thread);
35 auto vm = thread->GetEcmaVM();
36 JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
37 // 1.Let O be the this value.
38 JSHandle<JSTaggedValue> thisValue = GetThis(argv);
39 // 2.Assert: Type(O) is Object and O has a [[SyncIteratorRecord]] internal slot.
40 if (!thisValue->IsAsyncFromSyncIterator()) {
41 THROW_TYPE_ERROR_AND_RETURN(thread, "is not AsyncFromSyncIterator", JSTaggedValue::Exception());
42 }
43 // 3.Let promiseCapability be ! NewPromiseCapability(%Promise%).
44 JSHandle<PromiseCapability> pcap =
45 JSPromise::NewPromiseCapability(thread, JSHandle<JSTaggedValue>::Cast(env->GetPromiseFunction()));
46 // 4.Let syncIteratorRecord be O.[[SyncIteratorRecord]].
47 JSHandle<JSAsyncFromSyncIterator> asyncIterator(thisValue);
48 JSHandle<AsyncIteratorRecord> syncIteratorRecord(thread, asyncIterator->GetSyncIteratorRecord());
49 // 5.If value is present, then
50 // a.Let result be IteratorNext(syncIteratorRecord, value).
51 // 6.Else,
52 // a.Let result be IteratorNext(syncIteratorRecord).
53 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
54 JSHandle<JSTaggedValue> result;
55 if (value->IsNull()) {
56 result = JSIterator::IteratorNext(thread, syncIteratorRecord);
57 } else {
58 result = JSIterator::IteratorNext(thread, syncIteratorRecord, value);
59 }
60 // 7.IfAbruptRejectPromise(result, promiseCapability).
61 RETURN_REJECT_PROMISE_IF_ABRUPT(thread, result, pcap);
62 // 8.Return ! AsyncFromSyncIteratorContinuation(result, promiseCapability).
63 return JSAsyncFromSyncIterator::AsyncFromSyncIteratorContinuation(thread, result, pcap);
64 }
65
Throw(EcmaRuntimeCallInfo * argv)66 JSTaggedValue BuiltinsAsyncFromSyncIterator::Throw(EcmaRuntimeCallInfo *argv)
67 {
68 JSThread *thread = argv->GetThread();
69 [[maybe_unused]] EcmaHandleScope scope(thread);
70 auto vm = thread->GetEcmaVM();
71 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
72 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
73 // 1.Let O be the this value.
74 JSHandle<JSTaggedValue> input(BuiltinsBase::GetThis(argv));
75 JSHandle<JSAsyncFromSyncIterator> asyncIterator(input);
76 // 3.Let promiseCapability be ! NewPromiseCapability(%Promise%).
77 JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
78 JSHandle<PromiseCapability> pcap =
79 JSPromise::NewPromiseCapability(thread, JSHandle<JSTaggedValue>::Cast(env->GetPromiseFunction()));
80 // 4.Let syncIterator be O.[[SyncIteratorRecord]].[[Iterator]].
81 JSHandle<AsyncIteratorRecord> syncIteratorRecord(thread, asyncIterator->GetSyncIteratorRecord());
82 JSHandle<JSTaggedValue> syncIterator(thread, syncIteratorRecord->GetIterator());
83 // 5.Let return be GetMethod(syncIterator, "throw").
84 JSHandle<JSTaggedValue> throwString = thread->GlobalConstants()->GetHandledThrowString();
85 JSHandle<JSTaggedValue> throwResult = JSObject::GetMethod(thread, syncIterator, throwString);
86 JSHandle<JSTaggedValue> value = base::BuiltinsBase::GetCallArg(argv, 0);
87 JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
88 // 7.If throw is undefined, then
89 if (throwResult->IsUndefined()) {
90 JSHandle<JSObject> iterResult = JSIterator::CreateIterResultObject(thread, value, true);
91 JSHandle<JSTaggedValue> resolve(thread, pcap->GetResolve());
92 EcmaRuntimeCallInfo *info =
93 EcmaInterpreter::NewRuntimeCallInfo(thread, resolve, undefined, undefined, 1);
94 info->SetCallArg(iterResult.GetTaggedValue());
95 return pcap->GetPromise();
96 }
97 JSTaggedValue ret;
98 // 8.If value is present, then
99 if (value->IsNull()) {
100 EcmaRuntimeCallInfo *callInfo =
101 EcmaInterpreter::NewRuntimeCallInfo(thread, throwResult, syncIterator, undefined, 0);
102 ret = JSFunction::Call(callInfo);
103 } else {
104 EcmaRuntimeCallInfo *callInfo =
105 EcmaInterpreter::NewRuntimeCallInfo(thread, throwResult, syncIterator, undefined, 1);
106 callInfo->SetCallArg(value.GetTaggedValue());
107 ret = JSFunction::Call(callInfo);
108 }
109 JSHandle<JSTaggedValue> result(thread, ret);
110 // 11.If Type(result) is not Object, then
111 if (!result->IsECMAObject()) {
112 // a.Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
113 JSHandle<JSObject> resolutionError =
114 factory->GetJSError(ErrorType::TYPE_ERROR, "AsyncFromSyncIteratorPrototype.throw: is not Object.");
115 JSHandle<JSTaggedValue> reject(thread, pcap->GetReject());
116 EcmaRuntimeCallInfo *info =
117 EcmaInterpreter::NewRuntimeCallInfo(thread, reject, undefined, undefined, 1);
118 info->SetCallArg(resolutionError.GetTaggedValue());
119 JSFunction::Call(info);
120
121 // b.Return promiseCapability.[[Promise]].
122 JSHandle<JSObject> promise(thread, pcap->GetPromise());
123 return promise.GetTaggedValue();
124 }
125 // 12.Return ! AsyncFromSyncIteratorContinuation(result, promiseCapability).
126 return JSAsyncFromSyncIterator::AsyncFromSyncIteratorContinuation(thread, result, pcap);
127 }
128
Return(EcmaRuntimeCallInfo * argv)129 JSTaggedValue BuiltinsAsyncFromSyncIterator::Return(EcmaRuntimeCallInfo *argv)
130 {
131 JSThread *thread = argv->GetThread();
132 [[maybe_unused]] EcmaHandleScope scope(thread);
133 auto vm = thread->GetEcmaVM();
134 const GlobalEnvConstants *globalConst = thread->GlobalConstants();
135 ObjectFactory *factory = vm->GetFactory();
136 // 1.Let O be the this value.
137 JSHandle<JSTaggedValue> thisValue = GetThis(argv);
138 if (!thisValue->IsAsyncFromSyncIterator()) {
139 THROW_TYPE_ERROR_AND_RETURN(thread, "is not AsyncFromSyncIterator", JSTaggedValue::Exception());
140 }
141
142 // 3.Let promiseCapability be ! NewPromiseCapability(%Promise%).
143 JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
144 JSHandle<PromiseCapability> pcap =
145 JSPromise::NewPromiseCapability(thread, JSHandle<JSTaggedValue>::Cast(env->GetPromiseFunction()));
146 // 4.Let syncIterator be O.[[SyncIteratorRecord]].[[Iterator]].
147 JSHandle<JSAsyncFromSyncIterator> asyncIterator(thisValue);
148 JSHandle<AsyncIteratorRecord> syncIteratorRecord(thread, asyncIterator->GetSyncIteratorRecord());
149 JSHandle<JSTaggedValue> syncIterator(thread, syncIteratorRecord->GetIterator());
150 // 5.Let return be GetMethod(syncIterator, "return").
151 JSHandle<JSTaggedValue> returnString = globalConst->GetHandledReturnString();
152 JSHandle<JSTaggedValue> returnResult = JSObject::GetMethod(thread, syncIterator, returnString);
153 JSHandle<JSTaggedValue> value = base::BuiltinsBase::GetCallArg(argv, 0);
154 JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
155 // 7.If return is undefined, then
156 if (returnResult->IsUndefined()) {
157 JSHandle<JSObject> iterResult = JSIterator::CreateIterResultObject(thread, value, true);
158 JSHandle<JSTaggedValue> its = JSHandle<JSTaggedValue>::Cast(iterResult);
159 JSHandle<JSTaggedValue> resolve(thread, pcap->GetResolve());
160 EcmaRuntimeCallInfo *info =
161 EcmaInterpreter::NewRuntimeCallInfo(thread, resolve, undefined, undefined, 1);
162 info->SetCallArg(its.GetTaggedValue());
163 JSHandle<JSObject> promise(thread, pcap->GetPromise());
164 return promise.GetTaggedValue();
165 }
166 JSTaggedValue ret;
167 // 8.If value is present, then
168 if (value->IsNull()) {
169 EcmaRuntimeCallInfo *callInfo =
170 EcmaInterpreter::NewRuntimeCallInfo(thread, returnResult, syncIterator, undefined, 0);
171 ret = JSFunction::Call(callInfo);
172 } else {
173 EcmaRuntimeCallInfo *callInfo =
174 EcmaInterpreter::NewRuntimeCallInfo(thread, returnResult, syncIterator, undefined, 1);
175 callInfo->SetCallArg(value.GetTaggedValue());
176 ret = JSFunction::Call(callInfo);
177 }
178 JSHandle<JSTaggedValue> result(thread, ret);
179 // 11.If Type(result) is not Object, then
180 if (!result->IsECMAObject()) {
181 // a.Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
182 JSHandle<JSObject> resolutionError =
183 factory->GetJSError(ErrorType::TYPE_ERROR, "AsyncFromSyncIteratorPrototype.return: is not Object.");
184 JSHandle<JSTaggedValue> rstErr = JSHandle<JSTaggedValue>::Cast(resolutionError);
185 JSHandle<JSTaggedValue> reject(thread, pcap->GetReject());
186 EcmaRuntimeCallInfo *info =
187 EcmaInterpreter::NewRuntimeCallInfo(thread, reject, undefined, undefined, 1);
188 info->SetCallArg(rstErr.GetTaggedValue());
189 JSFunction::Call(info);
190
191 // b.Return promiseCapability.[[Promise]].
192 JSHandle<JSObject> promise(thread, pcap->GetPromise());
193 return promise.GetTaggedValue();
194 }
195 // 12.Return ! AsyncFromSyncIteratorContinuation(result, promiseCapability).
196 return JSAsyncFromSyncIterator::AsyncFromSyncIteratorContinuation(thread, result, pcap);
197 }
198 } // namespace panda::ecmascript::builtins
199