1/** 2 * Copyright (c) 2021 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 "forOfStatement.h" 17 18#include <binder/binder.h> 19#include <binder/scope.h> 20#include <compiler/base/catchTable.h> 21#include <compiler/base/iterators.h> 22#include <compiler/base/lreference.h> 23#include <compiler/core/labelTarget.h> 24#include <compiler/core/pandagen.h> 25#include <typescript/checker.h> 26#include <ir/astDump.h> 27#include <ir/expression.h> 28 29namespace panda::es2panda::ir { 30 31void ForOfStatement::Iterate(const NodeTraverser &cb) const 32{ 33 cb(left_); 34 cb(right_); 35 cb(body_); 36} 37 38void ForOfStatement::Dump(ir::AstDumper *dumper) const 39{ 40 dumper->Add({{"type", "ForOfStatement"}, {"await", isAwait_}, {"left", left_}, {"right", right_}, {"body", body_}}); 41} 42 43void ForOfStatement::Compile(compiler::PandaGen *pg) const 44{ 45 compiler::LocalRegScope regScope(pg, scope_); 46 47 if (scope_->NeedLexEnv()) { 48 pg->NewLexEnv(this, scope_->LexicalSlots()); 49 } 50 51 { 52 compiler::TryContext iterInitTryCtx(pg); 53 const auto &labelSet = iterInitTryCtx.LabelSet(); 54 pg->SetLabel(right_, labelSet.TryBegin()); 55 right_->Compile(pg); 56 pg->SetLabel(right_, labelSet.TryEnd()); 57 pg->Branch(right_, labelSet.CatchEnd()); 58 59 pg->SetLabel(right_, labelSet.CatchBegin()); 60 compiler::VReg exception = pg->AllocReg(); 61 pg->StoreAccumulator(right_, exception); 62 if (scope_->NeedLexEnv()) { 63 pg->PopLexEnv(this); 64 } 65 pg->LoadAccumulator(right_, exception); 66 pg->EmitThrow(right_); 67 pg->SetLabel(right_, labelSet.CatchEnd()); 68 } 69 70 if (scope_->NeedLexEnv()) { 71 pg->PopLexEnv(this); 72 } 73 74 compiler::LabelTarget labelTarget(pg); 75 auto iterator_type = isAwait_ ? compiler::IteratorType::ASYNC : compiler::IteratorType::SYNC; 76 compiler::Iterator iterator(pg, this, iterator_type); 77 78 pg->SetLabel(this, labelTarget.ContinueTarget()); 79 80 iterator.Next(); 81 iterator.Complete(); 82 pg->BranchIfTrue(this, labelTarget.BreakTarget()); 83 84 compiler::VReg value = pg->AllocReg(); 85 iterator.Value(); 86 pg->StoreAccumulator(this, value); 87 88 auto lref = compiler::LReference::CreateLRef(pg, left_, false); 89 { 90 compiler::IteratorContext forOfCtx(pg, iterator, labelTarget); 91 compiler::LoopEnvScope envScope(pg, scope_, {}); 92 pg->LoadAccumulator(this, value); 93 lref.SetValue(); 94 95 body_->Compile(pg); 96 } 97 98 pg->Branch(this, labelTarget.ContinueTarget()); 99 pg->SetLabel(this, labelTarget.BreakTarget()); 100} 101 102checker::Type *ForOfStatement::Check([[maybe_unused]] checker::Checker *checker) const 103{ 104 return nullptr; 105} 106 107void ForOfStatement::UpdateSelf(const NodeUpdater &cb, binder::Binder *binder) 108{ 109 auto *loopScope = Scope(); 110 auto loopCtx = binder::LexicalScope<binder::LoopScope>::Enter(binder, loopScope); 111 left_ = std::get<ir::AstNode *>(cb(left_)); 112 right_ = std::get<ir::AstNode *>(cb(right_))->AsExpression(); 113 114 body_ = UpdateChildStatement(cb, binder, body_); 115} 116 117} // namespace panda::es2panda::ir 118