• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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