13af6ab5fSopenharmony_ci/*
23af6ab5fSopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
33af6ab5fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
43af6ab5fSopenharmony_ci * you may not use this file except in compliance with the License.
53af6ab5fSopenharmony_ci * You may obtain a copy of the License at
63af6ab5fSopenharmony_ci *
73af6ab5fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
83af6ab5fSopenharmony_ci *
93af6ab5fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
103af6ab5fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
113af6ab5fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
123af6ab5fSopenharmony_ci * See the License for the specific language governing permissions and
133af6ab5fSopenharmony_ci * limitations under the License.
143af6ab5fSopenharmony_ci */
153af6ab5fSopenharmony_ci
163af6ab5fSopenharmony_ci#include "iterators.h"
173af6ab5fSopenharmony_ci
183af6ab5fSopenharmony_ci#include <compiler/core/pandagen.h>
193af6ab5fSopenharmony_ci#include <compiler/base/catchTable.h>
203af6ab5fSopenharmony_ci#include <compiler/function/functionBuilder.h>
213af6ab5fSopenharmony_ci
223af6ab5fSopenharmony_cinamespace panda::es2panda::compiler {
233af6ab5fSopenharmony_ci
243af6ab5fSopenharmony_ci// Iterator
253af6ab5fSopenharmony_ci
263af6ab5fSopenharmony_ciIterator::Iterator(PandaGen *pg, const ir::AstNode *node, IteratorType type)
273af6ab5fSopenharmony_ci    : pg_(pg), node_(node), closed_(pg->AllocReg()), method_(pg->AllocReg()), iterator_(pg->AllocReg()),
283af6ab5fSopenharmony_ci      nextResult_(pg->AllocReg()), type_(type)
293af6ab5fSopenharmony_ci{
303af6ab5fSopenharmony_ci    if (type_ == IteratorType::ASYNC) {
313af6ab5fSopenharmony_ci        pg_->GetAsyncIterator(node);
323af6ab5fSopenharmony_ci    } else {
333af6ab5fSopenharmony_ci        pg_->GetIterator(node);
343af6ab5fSopenharmony_ci    }
353af6ab5fSopenharmony_ci
363af6ab5fSopenharmony_ci    pg_->StoreAccumulator(node, iterator_);
373af6ab5fSopenharmony_ci    pg_->LoadObjByName(node_, iterator_, "next");
383af6ab5fSopenharmony_ci    pg_->StoreAccumulator(node_, method_);
393af6ab5fSopenharmony_ci    pg_->StoreConst(node_, closed_, Constant::JS_FALSE);
403af6ab5fSopenharmony_ci}
413af6ab5fSopenharmony_ci
423af6ab5fSopenharmony_civoid Iterator::GetMethod(util::StringView name) const
433af6ab5fSopenharmony_ci{
443af6ab5fSopenharmony_ci    pg_->LoadObjByName(node_, iterator_, name);
453af6ab5fSopenharmony_ci    pg_->StoreAccumulator(node_, method_);
463af6ab5fSopenharmony_ci}
473af6ab5fSopenharmony_ci
483af6ab5fSopenharmony_civoid Iterator::CallMethodWithValue() const
493af6ab5fSopenharmony_ci{
503af6ab5fSopenharmony_ci    pg_->CallThis(node_, method_, 2);
513af6ab5fSopenharmony_ci}
523af6ab5fSopenharmony_ci
533af6ab5fSopenharmony_civoid Iterator::CallMethod() const
543af6ab5fSopenharmony_ci{
553af6ab5fSopenharmony_ci    pg_->CallThis(node_, method_, 1);
563af6ab5fSopenharmony_ci}
573af6ab5fSopenharmony_ci
583af6ab5fSopenharmony_civoid Iterator::Next() const
593af6ab5fSopenharmony_ci{
603af6ab5fSopenharmony_ci    CallMethod();
613af6ab5fSopenharmony_ci
623af6ab5fSopenharmony_ci    if (type_ == IteratorType::ASYNC) {
633af6ab5fSopenharmony_ci        pg_->FuncBuilder()->Await(node_);
643af6ab5fSopenharmony_ci    }
653af6ab5fSopenharmony_ci
663af6ab5fSopenharmony_ci    pg_->StoreAccumulator(node_, nextResult_);
673af6ab5fSopenharmony_ci    pg_->ThrowIfNotObject(node_, nextResult_);
683af6ab5fSopenharmony_ci}
693af6ab5fSopenharmony_ci
703af6ab5fSopenharmony_civoid Iterator::Complete() const
713af6ab5fSopenharmony_ci{
723af6ab5fSopenharmony_ci    pg_->LoadObjByName(node_, nextResult_, "done");
733af6ab5fSopenharmony_ci}
743af6ab5fSopenharmony_ci
753af6ab5fSopenharmony_civoid Iterator::Value() const
763af6ab5fSopenharmony_ci{
773af6ab5fSopenharmony_ci    pg_->LoadObjByName(node_, nextResult_, "value");
783af6ab5fSopenharmony_ci}
793af6ab5fSopenharmony_ci
803af6ab5fSopenharmony_civoid Iterator::Close(bool abruptCompletion) const
813af6ab5fSopenharmony_ci{
823af6ab5fSopenharmony_ci    RegScope rs(pg_);
833af6ab5fSopenharmony_ci    VReg completion = pg_->AllocReg();
843af6ab5fSopenharmony_ci    VReg innerResult = pg_->AllocReg();
853af6ab5fSopenharmony_ci    VReg innerException = pg_->AllocReg();
863af6ab5fSopenharmony_ci    Label *noReturn = pg_->AllocLabel();
873af6ab5fSopenharmony_ci
883af6ab5fSopenharmony_ci    pg_->StoreAccumulator(node_, completion);
893af6ab5fSopenharmony_ci    pg_->LoadAccumulator(node_, closed_);
903af6ab5fSopenharmony_ci    pg_->BranchIfTrue(node_, noReturn);
913af6ab5fSopenharmony_ci
923af6ab5fSopenharmony_ci    pg_->StoreConst(node_, closed_, Constant::JS_TRUE);
933af6ab5fSopenharmony_ci    pg_->StoreConst(node_, innerResult, Constant::JS_UNDEFINED);
943af6ab5fSopenharmony_ci    pg_->StoreConst(node_, innerException, Constant::JS_HOLE);
953af6ab5fSopenharmony_ci
963af6ab5fSopenharmony_ci    TryContext tryCtx(pg_);
973af6ab5fSopenharmony_ci    const auto &labelSet = tryCtx.LabelSet();
983af6ab5fSopenharmony_ci
993af6ab5fSopenharmony_ci    pg_->SetLabel(node_, labelSet.TryBegin());
1003af6ab5fSopenharmony_ci
1013af6ab5fSopenharmony_ci    // 4. Let innerResult be GetMethod(iterator, "return").
1023af6ab5fSopenharmony_ci    GetMethod("return");
1033af6ab5fSopenharmony_ci
1043af6ab5fSopenharmony_ci    // 5. If innerResult.[[Type]] is normal, then
1053af6ab5fSopenharmony_ci    {
1063af6ab5fSopenharmony_ci        // a. Let return be innerResult.[[Value]].
1073af6ab5fSopenharmony_ci        // b. If return is undefined, return Completion(completion).
1083af6ab5fSopenharmony_ci        pg_->BranchIfUndefined(node_, noReturn);
1093af6ab5fSopenharmony_ci        // c. Set innerResult to Call(return, iterator).
1103af6ab5fSopenharmony_ci        CallMethod();
1113af6ab5fSopenharmony_ci        if (type_ == IteratorType::ASYNC) {
1123af6ab5fSopenharmony_ci            // d. If innerResult.[[Type]] is normal, set innerResult to Await(innerResult.[[Value]]).
1133af6ab5fSopenharmony_ci            pg_->FuncBuilder()->Await(node_);
1143af6ab5fSopenharmony_ci        }
1153af6ab5fSopenharmony_ci        pg_->StoreAccumulator(node_, innerResult);
1163af6ab5fSopenharmony_ci    }
1173af6ab5fSopenharmony_ci
1183af6ab5fSopenharmony_ci    pg_->SetLabel(node_, labelSet.TryEnd());
1193af6ab5fSopenharmony_ci    pg_->Branch(node_, labelSet.CatchEnd());
1203af6ab5fSopenharmony_ci
1213af6ab5fSopenharmony_ci    pg_->SetLabel(node_, labelSet.CatchBegin());
1223af6ab5fSopenharmony_ci    pg_->StoreAccumulator(node_, innerException);
1233af6ab5fSopenharmony_ci    pg_->SetLabel(node_, labelSet.CatchEnd());
1243af6ab5fSopenharmony_ci
1253af6ab5fSopenharmony_ci    // 6. If completion.[[Type]] is throw, return Completion(completion).
1263af6ab5fSopenharmony_ci    if (abruptCompletion) {
1273af6ab5fSopenharmony_ci        pg_->LoadAccumulator(node_, completion);
1283af6ab5fSopenharmony_ci        pg_->EmitThrow(node_);
1293af6ab5fSopenharmony_ci    } else {
1303af6ab5fSopenharmony_ci        // 7. If innerResult.[[Type]] is throw, return Completion(innerResult).
1313af6ab5fSopenharmony_ci        pg_->LoadAccumulator(node_, innerException);
1323af6ab5fSopenharmony_ci        pg_->EmitRethrow(node_);
1333af6ab5fSopenharmony_ci    }
1343af6ab5fSopenharmony_ci
1353af6ab5fSopenharmony_ci    // 8. If Type(innerResult.[[Value]]) is not Object, throw a TypeError exception.
1363af6ab5fSopenharmony_ci    pg_->LoadAccumulator(node_, innerResult);
1373af6ab5fSopenharmony_ci    pg_->ThrowIfNotObject(node_, innerResult);
1383af6ab5fSopenharmony_ci
1393af6ab5fSopenharmony_ci    pg_->SetLabel(node_, noReturn);
1403af6ab5fSopenharmony_ci    pg_->LoadAccumulator(node_, completion);
1413af6ab5fSopenharmony_ci    if (abruptCompletion) {
1423af6ab5fSopenharmony_ci        pg_->EmitThrow(node_);
1433af6ab5fSopenharmony_ci    }
1443af6ab5fSopenharmony_ci}
1453af6ab5fSopenharmony_ci
1463af6ab5fSopenharmony_ciDestructuringIterator::DestructuringIterator(PandaGen *pg, const ir::AstNode *node)
1473af6ab5fSopenharmony_ci    : Iterator(pg, node, IteratorType::SYNC), done_(pg->AllocReg()), result_(pg->AllocReg())
1483af6ab5fSopenharmony_ci{
1493af6ab5fSopenharmony_ci    pg_->StoreConst(node, done_, Constant::JS_FALSE);
1503af6ab5fSopenharmony_ci    pg_->StoreConst(node, result_, Constant::JS_UNDEFINED);
1513af6ab5fSopenharmony_ci}
1523af6ab5fSopenharmony_ci
1533af6ab5fSopenharmony_civoid DestructuringIterator::Step(Label *doneTarget) const
1543af6ab5fSopenharmony_ci{
1553af6ab5fSopenharmony_ci    TryContext tryCtx(pg_);
1563af6ab5fSopenharmony_ci    const auto &labelSet = tryCtx.LabelSet();
1573af6ab5fSopenharmony_ci    Label *normalClose = pg_->AllocLabel();
1583af6ab5fSopenharmony_ci    Label *noClose = pg_->AllocLabel();
1593af6ab5fSopenharmony_ci
1603af6ab5fSopenharmony_ci    pg_->SetLabel(node_, labelSet.TryBegin());
1613af6ab5fSopenharmony_ci    JumpIfDone(noClose);
1623af6ab5fSopenharmony_ci    Next();
1633af6ab5fSopenharmony_ci    Complete();
1643af6ab5fSopenharmony_ci    pg_->StoreAccumulator(node_, done_);
1653af6ab5fSopenharmony_ci    pg_->BranchIfFalse(node_, normalClose);
1663af6ab5fSopenharmony_ci    pg_->StoreConst(node_, done_, Constant::JS_TRUE);
1673af6ab5fSopenharmony_ci    pg_->LoadConst(node_, Constant::JS_UNDEFINED);
1683af6ab5fSopenharmony_ci    pg_->Branch(node_, noClose);
1693af6ab5fSopenharmony_ci
1703af6ab5fSopenharmony_ci    pg_->SetLabel(node_, normalClose);
1713af6ab5fSopenharmony_ci    Value();
1723af6ab5fSopenharmony_ci    pg_->StoreAccumulator(node_, result_);
1733af6ab5fSopenharmony_ci    pg_->Branch(node_, labelSet.CatchEnd());
1743af6ab5fSopenharmony_ci    pg_->SetLabel(node_, noClose);
1753af6ab5fSopenharmony_ci    OnIterDone(doneTarget);
1763af6ab5fSopenharmony_ci
1773af6ab5fSopenharmony_ci    pg_->SetLabel(node_, labelSet.TryEnd());
1783af6ab5fSopenharmony_ci    pg_->Branch(node_, labelSet.CatchEnd());
1793af6ab5fSopenharmony_ci
1803af6ab5fSopenharmony_ci    pg_->SetLabel(node_, labelSet.CatchBegin());
1813af6ab5fSopenharmony_ci    pg_->StoreAccumulator(node_, result_);
1823af6ab5fSopenharmony_ci    pg_->StoreConst(node_, done_, Constant::JS_TRUE);
1833af6ab5fSopenharmony_ci    pg_->LoadAccumulator(node_, result_);
1843af6ab5fSopenharmony_ci    pg_->EmitThrow(node_);
1853af6ab5fSopenharmony_ci    pg_->SetLabel(node_, labelSet.CatchEnd());
1863af6ab5fSopenharmony_ci}
1873af6ab5fSopenharmony_ci
1883af6ab5fSopenharmony_civoid DestructuringIterator::OnIterDone([[maybe_unused]] Label *doneTarget) const
1893af6ab5fSopenharmony_ci{
1903af6ab5fSopenharmony_ci    pg_->LoadConst(node_, Constant::JS_UNDEFINED);
1913af6ab5fSopenharmony_ci}
1923af6ab5fSopenharmony_ci
1933af6ab5fSopenharmony_civoid DestructuringRestIterator::OnIterDone([[maybe_unused]] Label *doneTarget) const
1943af6ab5fSopenharmony_ci{
1953af6ab5fSopenharmony_ci    pg_->Branch(node_, doneTarget);
1963af6ab5fSopenharmony_ci}
1973af6ab5fSopenharmony_ci
1983af6ab5fSopenharmony_civoid DestructuringIterator::JumpIfDone(Label *noClose) const
1993af6ab5fSopenharmony_ci{
2003af6ab5fSopenharmony_ci    pg_->LoadAccumulator(node_, done_);
2013af6ab5fSopenharmony_ci    pg_->BranchIfTrue(node_, noClose);
2023af6ab5fSopenharmony_ci}
2033af6ab5fSopenharmony_ci
2043af6ab5fSopenharmony_ci}  // namespace panda::es2panda::compiler
205