• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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