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
22 namespace ark::es2panda::evaluate {
23
IrCheckHelper(checker::ETSChecker *checker, varbinder::ETSBinder *varBinder)24 IrCheckHelper::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
CheckNewNode(ir::AstNode *node, varbinder::Scope *scope, ir::AstNode *parentClass, parser::Program *program)31 bool 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
PreCheck()60 void IrCheckHelper::PreCheck()
61 {
62 HandleCustomNodes();
63 CheckDecls();
64
65 isPrecheckPassed_ = true;
66 }
67
CheckDecls()68 void 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
HandleCustomNodes()81 void 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
CheckGlobalEntity(parser::Program *program, ir::AstNode *node, bool mustCheck)95 void 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
CheckLocalEntity(ir::AstNode *node)112 void 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