1 /*
2 * Copyright (c) 2023 - 2025 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 "compiler/lowering/ets/topLevelStmts/globalDeclTransformer.h"
17
18 namespace ark::es2panda::compiler {
19
FilterDeclarations(ArenaVector<ir::Statement * > & stmts)20 void GlobalDeclTransformer::FilterDeclarations(ArenaVector<ir::Statement *> &stmts)
21 {
22 const auto isDeclCb = [&types = typeDecl_](const ir::AstNode *node) {
23 return types.count(node->Type()) == 0U || (node->IsExportNamedDeclaration());
24 };
25 stmts.erase(std::remove_if(stmts.begin(), stmts.end(), isDeclCb), stmts.end());
26 }
27
TransformStatements(const ArenaVector<ir::Statement * > & stmts)28 GlobalDeclTransformer::ResultT GlobalDeclTransformer::TransformStatements(const ArenaVector<ir::Statement *> &stmts)
29 {
30 result_.classProperties.clear();
31 result_.immediateInit.clear();
32 result_.initializerBlocks.clear();
33 for (auto stmt : stmts) {
34 stmt->Accept(this);
35 }
36 return std::move(result_);
37 }
38
VisitFunctionDeclaration(ir::FunctionDeclaration * funcDecl)39 void GlobalDeclTransformer::VisitFunctionDeclaration(ir::FunctionDeclaration *funcDecl)
40 {
41 auto *funcExpr = util::NodeAllocator::ForceSetParent<ir::FunctionExpression>(allocator_, funcDecl->Function());
42 ES2PANDA_ASSERT(funcExpr != nullptr);
43 funcDecl->Function()->SetStart(funcDecl->Function()->Id()->Start());
44 funcExpr->SetRange(funcDecl->Function()->Range());
45 ir::MethodDefinitionKind methodKind;
46 if (funcDecl->Function()->HasReceiver()) {
47 if (funcDecl->Function()->IsGetter()) {
48 methodKind = ir::MethodDefinitionKind::EXTENSION_GET;
49 } else if (funcDecl->Function()->IsSetter()) {
50 methodKind = ir::MethodDefinitionKind::EXTENSION_SET;
51 } else {
52 methodKind = ir::MethodDefinitionKind::EXTENSION_METHOD;
53 }
54 } else {
55 methodKind = ir::MethodDefinitionKind::METHOD;
56 }
57
58 auto *method = util::NodeAllocator::ForceSetParent<ir::MethodDefinition>(
59 allocator_, methodKind, funcDecl->Function()->Id()->Clone(allocator_, nullptr), funcExpr,
60 funcDecl->Function()->Modifiers(), allocator_, false);
61 method->SetRange(funcDecl->Range());
62 method->Function()->SetAnnotations(std::move(funcDecl->Annotations()));
63
64 if (funcDecl->Function()->HasExportAlias()) {
65 method->AddAstNodeFlags(ir::AstNodeFlags::HAS_EXPORT_ALIAS);
66 }
67
68 result_.classProperties.emplace_back(method);
69 }
70
VisitVariableDeclaration(ir::VariableDeclaration * varDecl)71 void GlobalDeclTransformer::VisitVariableDeclaration(ir::VariableDeclaration *varDecl)
72 {
73 for (auto declarator : varDecl->Declarators()) {
74 auto id = declarator->Id()->AsIdentifier();
75 auto typeAnn = id->TypeAnnotation();
76 id->SetTsTypeAnnotation(nullptr);
77 auto modifiers = varDecl->Modifiers() | declarator->Modifiers();
78 bool needInitializeInStaticBlock = (declarator->Init() == nullptr) &&
79 (modifiers & ir::ModifierFlags::CONST) != 0 &&
80 currentModule_->AsETSModule()->Program()->IsPackage();
81 auto *field = util::NodeAllocator::ForceSetParent<ir::ClassProperty>(
82 allocator_, id->Clone(allocator_, nullptr), declarator->Init(), typeAnn, modifiers, allocator_, false);
83 field->SetInitInStaticBlock(needInitializeInStaticBlock);
84 field->SetRange(declarator->Range());
85
86 if (!varDecl->Annotations().empty()) {
87 ArenaVector<ir::AnnotationUsage *> propAnnotations(allocator_->Adapter());
88 for (auto *annotationUsage : varDecl->Annotations()) {
89 ES2PANDA_ASSERT(annotationUsage != nullptr);
90 propAnnotations.push_back(annotationUsage->Clone(allocator_, field)->AsAnnotationUsage());
91 }
92 field->SetAnnotations(std::move(propAnnotations));
93 }
94
95 if (varDecl->HasExportAlias() || declarator->HasExportAlias()) {
96 field->AddAstNodeFlags(ir::AstNodeFlags::HAS_EXPORT_ALIAS);
97 }
98
99 result_.classProperties.emplace_back(field);
100 if (auto stmt = InitTopLevelProperty(field); stmt != nullptr) {
101 result_.immediateInit.emplace_back(stmt);
102 }
103 }
104 }
105
IsFinalBlockOfTryStatement(ir::AstNode const * node)106 static bool IsFinalBlockOfTryStatement(ir::AstNode const *node)
107 {
108 if (!node->IsBlockStatement() || node->Parent() == nullptr) {
109 return false;
110 }
111
112 auto parent = node->Parent();
113 return parent->IsTryStatement() && (parent->AsTryStatement()->FinallyBlock() == node);
114 }
115
116 // Note: Extract the expressions from ClassStaticBlock to Initializer block.
VisitClassStaticBlock(ir::ClassStaticBlock * classStaticBlock)117 void GlobalDeclTransformer::VisitClassStaticBlock(ir::ClassStaticBlock *classStaticBlock)
118 {
119 auto containUnhandledThrow = [&](ir::AstNode *ast) {
120 if (!ast->IsThrowStatement()) {
121 return;
122 }
123
124 auto const *parent = ast->Parent();
125 while (parent != nullptr) {
126 if (parent->IsTryStatement() && !parent->AsTryStatement()->CatchClauses().empty()) {
127 return;
128 }
129
130 if (parent->IsCatchClause() || IsFinalBlockOfTryStatement(parent)) {
131 break;
132 }
133 parent = parent->Parent();
134 }
135 parser_->LogError(diagnostic::UNHANDLED_THROW_IN_INITIALIZER, {}, ast->Start());
136 };
137
138 auto *staticBlock = classStaticBlock->Function();
139 ES2PANDA_ASSERT((staticBlock->Flags() & ir::ScriptFunctionFlags::STATIC_BLOCK) != 0);
140 classStaticBlock->IterateRecursivelyPostorder(containUnhandledThrow);
141 auto &initStatements = staticBlock->Body()->AsBlockStatement()->Statements();
142 ArenaVector<ir::Statement *> initializerBlock(allocator_->Adapter());
143 initializerBlock.insert(initializerBlock.begin(), initStatements.begin(), initStatements.end());
144 result_.initializerBlocks.emplace_back(std::move(initializerBlock));
145 ++initializerBlockCount_;
146 }
147
RefIdent(const util::StringView & name)148 ir::Identifier *GlobalDeclTransformer::RefIdent(const util::StringView &name)
149 {
150 auto *const callee = util::NodeAllocator::Alloc<ir::Identifier>(allocator_, name, allocator_);
151 return callee;
152 }
153
InitTopLevelProperty(ir::ClassProperty * classProperty)154 ir::ExpressionStatement *GlobalDeclTransformer::InitTopLevelProperty(ir::ClassProperty *classProperty)
155 {
156 const auto initializer = classProperty->Value();
157 if (classProperty->IsConst() || initializer == nullptr) {
158 classProperty->SetStart(classProperty->Id()->Start());
159 return nullptr;
160 }
161
162 auto const ident = RefIdent(classProperty->Id()->Name());
163 ident->SetRange(classProperty->Id()->Range());
164
165 initializer->SetParent(nullptr);
166 auto *assignmentExpression = util::NodeAllocator::Alloc<ir::AssignmentExpression>(
167 allocator_, ident, initializer, lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
168 ES2PANDA_ASSERT(assignmentExpression != nullptr);
169 assignmentExpression->SetRange({ident->Start(), initializer->End()});
170 assignmentExpression->SetTsType(initializer->TsType());
171
172 auto expressionStatement = util::NodeAllocator::Alloc<ir::ExpressionStatement>(allocator_, assignmentExpression);
173 expressionStatement->SetRange(classProperty->Range());
174
175 classProperty->SetRange({ident->Start(), initializer->End()});
176
177 if (classProperty->TypeAnnotation() != nullptr) {
178 classProperty->SetValue(nullptr);
179 } else {
180 // Code will be ignored, but checker is going to deduce the type.
181 classProperty->SetValue(initializer->Clone(allocator_, classProperty)->AsExpression());
182 }
183 return expressionStatement;
184 }
185
HandleNode(ir::AstNode * node)186 void GlobalDeclTransformer::HandleNode(ir::AstNode *node)
187 {
188 ES2PANDA_ASSERT(node->IsStatement());
189 if (typeDecl_.count(node->Type()) == 0U) {
190 ES2PANDA_ASSERT(!propertiesDecl_.count(node->Type()));
191 result_.immediateInit.emplace_back(node->AsStatement());
192 }
193 }
194
195 } // namespace ark::es2panda::compiler
196