/* * Copyright (c) 2021-2022 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 "iterators.h" #include #include #include namespace panda::es2panda::compiler { // Iterator Iterator::Iterator(PandaGen *pg, const ir::AstNode *node, IteratorType type) : pg_(pg), node_(node), closed_(pg->AllocReg()), method_(pg->AllocReg()), iterator_(pg->AllocReg()), nextResult_(pg->AllocReg()), type_(type) { if (type_ == IteratorType::ASYNC) { pg_->GetAsyncIterator(node); } else { pg_->GetIterator(node); } pg_->StoreAccumulator(node, iterator_); pg_->LoadObjByName(node_, iterator_, "next"); pg_->StoreAccumulator(node_, method_); pg_->StoreConst(node_, closed_, Constant::JS_FALSE); } void Iterator::GetMethod(util::StringView name) const { pg_->LoadObjByName(node_, iterator_, name); pg_->StoreAccumulator(node_, method_); } void Iterator::CallMethodWithValue() const { pg_->CallThis(node_, method_, 2); } void Iterator::CallMethod() const { pg_->CallThis(node_, method_, 1); } void Iterator::Next() const { CallMethod(); if (type_ == IteratorType::ASYNC) { pg_->FuncBuilder()->Await(node_); } pg_->StoreAccumulator(node_, nextResult_); pg_->ThrowIfNotObject(node_, nextResult_); } void Iterator::Complete() const { pg_->LoadObjByName(node_, nextResult_, "done"); } void Iterator::Value() const { pg_->LoadObjByName(node_, nextResult_, "value"); } void Iterator::Close(bool abruptCompletion) const { RegScope rs(pg_); VReg completion = pg_->AllocReg(); VReg innerResult = pg_->AllocReg(); VReg innerException = pg_->AllocReg(); Label *noReturn = pg_->AllocLabel(); pg_->StoreAccumulator(node_, completion); pg_->LoadAccumulator(node_, closed_); pg_->BranchIfTrue(node_, noReturn); pg_->StoreConst(node_, closed_, Constant::JS_TRUE); pg_->StoreConst(node_, innerResult, Constant::JS_UNDEFINED); pg_->StoreConst(node_, innerException, Constant::JS_HOLE); TryContext tryCtx(pg_); const auto &labelSet = tryCtx.LabelSet(); pg_->SetLabel(node_, labelSet.TryBegin()); // 4. Let innerResult be GetMethod(iterator, "return"). GetMethod("return"); // 5. If innerResult.[[Type]] is normal, then { // a. Let return be innerResult.[[Value]]. // b. If return is undefined, return Completion(completion). pg_->BranchIfUndefined(node_, noReturn); // c. Set innerResult to Call(return, iterator). CallMethod(); if (type_ == IteratorType::ASYNC) { // d. If innerResult.[[Type]] is normal, set innerResult to Await(innerResult.[[Value]]). pg_->FuncBuilder()->Await(node_); } pg_->StoreAccumulator(node_, innerResult); } pg_->SetLabel(node_, labelSet.TryEnd()); pg_->Branch(node_, labelSet.CatchEnd()); pg_->SetLabel(node_, labelSet.CatchBegin()); pg_->StoreAccumulator(node_, innerException); pg_->SetLabel(node_, labelSet.CatchEnd()); // 6. If completion.[[Type]] is throw, return Completion(completion). if (abruptCompletion) { pg_->LoadAccumulator(node_, completion); pg_->EmitThrow(node_); } else { // 7. If innerResult.[[Type]] is throw, return Completion(innerResult). pg_->LoadAccumulator(node_, innerException); pg_->EmitRethrow(node_); } // 8. If Type(innerResult.[[Value]]) is not Object, throw a TypeError exception. pg_->LoadAccumulator(node_, innerResult); pg_->ThrowIfNotObject(node_, innerResult); pg_->SetLabel(node_, noReturn); pg_->LoadAccumulator(node_, completion); if (abruptCompletion) { pg_->EmitThrow(node_); } } DestructuringIterator::DestructuringIterator(PandaGen *pg, const ir::AstNode *node) : Iterator(pg, node, IteratorType::SYNC), done_(pg->AllocReg()), result_(pg->AllocReg()) { pg_->StoreConst(node, done_, Constant::JS_FALSE); pg_->StoreConst(node, result_, Constant::JS_UNDEFINED); } void DestructuringIterator::Step(Label *doneTarget) const { TryContext tryCtx(pg_); const auto &labelSet = tryCtx.LabelSet(); Label *normalClose = pg_->AllocLabel(); Label *noClose = pg_->AllocLabel(); pg_->SetLabel(node_, labelSet.TryBegin()); JumpIfDone(noClose); Next(); Complete(); pg_->StoreAccumulator(node_, done_); pg_->BranchIfFalse(node_, normalClose); pg_->StoreConst(node_, done_, Constant::JS_TRUE); pg_->LoadConst(node_, Constant::JS_UNDEFINED); pg_->Branch(node_, noClose); pg_->SetLabel(node_, normalClose); Value(); pg_->StoreAccumulator(node_, result_); pg_->Branch(node_, labelSet.CatchEnd()); pg_->SetLabel(node_, noClose); OnIterDone(doneTarget); pg_->SetLabel(node_, labelSet.TryEnd()); pg_->Branch(node_, labelSet.CatchEnd()); pg_->SetLabel(node_, labelSet.CatchBegin()); pg_->StoreAccumulator(node_, result_); pg_->StoreConst(node_, done_, Constant::JS_TRUE); pg_->LoadAccumulator(node_, result_); pg_->EmitThrow(node_); pg_->SetLabel(node_, labelSet.CatchEnd()); } void DestructuringIterator::OnIterDone([[maybe_unused]] Label *doneTarget) const { pg_->LoadConst(node_, Constant::JS_UNDEFINED); } void DestructuringRestIterator::OnIterDone([[maybe_unused]] Label *doneTarget) const { pg_->Branch(node_, doneTarget); } void DestructuringIterator::JumpIfDone(Label *noClose) const { pg_->LoadAccumulator(node_, done_); pg_->BranchIfTrue(node_, noClose); } } // namespace panda::es2panda::compiler