1/* 2 * Copyright (c) 2024 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 "evaluate/helpers.h" 17#include "evaluate/irCheckHelper.h" 18#include "compiler/lowering/util.h" 19#include "compiler/lowering/scopesInit/scopesInitPhase.h" 20#include "checker/ETSchecker.h" 21 22namespace ark::es2panda::evaluate { 23 24IrCheckHelper::IrCheckHelper(checker::ETSChecker *checker, varbinder::ETSBinder *varBinder) 25 : checker_(checker), varBinder_(varBinder), recursiveDecls_(checker->Allocator()->Adapter()) 26{ 27 ASSERT(checker_); 28 ASSERT(varBinder_); 29} 30 31bool IrCheckHelper::CheckNewNode(ir::AstNode *node, varbinder::Scope *scope, ir::AstNode *parentClass, 32 parser::Program *program) 33{ 34 ASSERT(node); 35 36 if (program == nullptr) { 37 program = varBinder_->Program(); 38 } 39 if (scope == nullptr) { 40 scope = checker_->Scope(); 41 } 42 43 recursiveDecls_.emplace_back(program, scope, parentClass, node); 44 45 if (isRecursive_) { 46 return false; 47 } 48 isRecursive_ = true; 49 50 if (isPrecheckPassed_) { 51 HandleCustomNodes(); 52 CheckDecls(); 53 } 54 55 isRecursive_ = false; 56 57 return true; 58} 59 60void IrCheckHelper::PreCheck() 61{ 62 HandleCustomNodes(); 63 CheckDecls(); 64 65 isPrecheckPassed_ = true; 66} 67 68void IrCheckHelper::CheckDecls() 69{ 70 // All dependent user-classes must be created at this point, so we can run checker. 71 while (!recursiveDecls_.empty()) { 72 auto [program, scope, parent, node] = recursiveDecls_.front(); 73 recursiveDecls_.pop_front(); 74 helpers::DoScopedAction(checker_, varBinder_, program, scope, parent, [this, node = node, scope = scope]() { 75 varBinder_->ResolveReferencesForScope(node, scope); 76 node->Check(checker_); 77 }); 78 } 79} 80 81void IrCheckHelper::HandleCustomNodes() 82{ 83 auto iter = recursiveDecls_.begin(); 84 while (iter != recursiveDecls_.end()) { 85 // Can trigger `ETSBinder::BuildClassDefinition`, 86 // which can eventually call debug-info plugin to create another class. 87 // Hence we delay `ETSChecker::Check` until all required classes are built and initialized in varbinder. 88 auto [program, scope, parent, node] = *iter; 89 helpers::DoScopedAction(checker_, varBinder_, program, scope, parent, 90 [varBinder = varBinder_, node = node]() { varBinder->HandleCustomNodes(node); }); 91 ++iter; 92 } 93} 94 95void IrCheckHelper::CheckGlobalEntity(parser::Program *program, ir::AstNode *node, bool mustCheck) 96{ 97 ASSERT(program); 98 99 auto *globalClass = program->GlobalClass(); 100 auto *globalClassScope = program->GlobalClassScope(); 101 102 helpers::DoScopedAction(checker_, varBinder_, program, globalClassScope, globalClass, 103 [this, globalClassScope, node]() { 104 compiler::InitScopesPhaseETS::RunExternalNode(node, varBinder_); 105 varBinder_->ResolveReferencesForScope(node, globalClassScope); 106 }); 107 if (mustCheck) { 108 CheckNewNode(node, globalClassScope, globalClass, program); 109 } 110} 111 112void IrCheckHelper::CheckLocalEntity(ir::AstNode *node) 113{ 114 compiler::InitScopesPhaseETS::RunExternalNode(node, varBinder_); 115 CheckNewNode(node, nullptr, nullptr, nullptr); 116} 117 118} // namespace ark::es2panda::evaluate 119