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