1 /*
2 * Copyright (c) 2023 - 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 "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 ||
24 (node->IsExportNamedDeclaration() && !node->AsExportNamedDeclaration()->Specifiers().empty());
25 };
26 stmts.erase(std::remove_if(stmts.begin(), stmts.end(), isDeclCb), stmts.end());
27 }
28
TransformStatements(const ArenaVector<ir::Statement * > & stmts,bool addInitializer)29 GlobalDeclTransformer::ResultT GlobalDeclTransformer::TransformStatements(const ArenaVector<ir::Statement *> &stmts,
30 bool addInitializer)
31 {
32 addInitializer_ = addInitializer;
33 result_.classProperties.clear();
34 result_.initStatements.clear();
35 for (auto stmt : stmts) {
36 stmt->Accept(this);
37 }
38 return std::move(result_);
39 }
40
VisitFunctionDeclaration(ir::FunctionDeclaration * funcDecl)41 void GlobalDeclTransformer::VisitFunctionDeclaration(ir::FunctionDeclaration *funcDecl)
42 {
43 auto *funcExpr = util::NodeAllocator::ForceSetParent<ir::FunctionExpression>(allocator_, funcDecl->Function());
44 funcDecl->Function()->SetStart(funcDecl->Function()->Id()->End());
45 funcExpr->SetRange(funcDecl->Function()->Range());
46 ir::MethodDefinitionKind methodKind;
47 if (funcDecl->Function()->IsExtensionMethod()) {
48 methodKind = ir::MethodDefinitionKind::EXTENSION_METHOD;
49 } else {
50 methodKind = ir::MethodDefinitionKind::METHOD;
51 }
52 auto *method = util::NodeAllocator::ForceSetParent<ir::MethodDefinition>(
53 allocator_, methodKind, funcDecl->Function()->Id()->Clone(allocator_, nullptr), funcExpr,
54 funcDecl->Function()->Modifiers(), allocator_, false);
55 method->SetRange(funcDecl->Range());
56
57 if (funcDecl->Function()->IsExported() && funcDecl->Function()->HasExportAlias()) {
58 method->AddAstNodeFlags(ir::AstNodeFlags::HAS_EXPORT_ALIAS);
59 }
60
61 result_.classProperties.emplace_back(method);
62 }
63
VisitVariableDeclaration(ir::VariableDeclaration * varDecl)64 void GlobalDeclTransformer::VisitVariableDeclaration(ir::VariableDeclaration *varDecl)
65 {
66 for (auto declarator : varDecl->Declarators()) {
67 auto id = declarator->Id()->AsIdentifier();
68 auto typeAnn = id->TypeAnnotation();
69 id->SetTsTypeAnnotation(nullptr);
70 auto *field = util::NodeAllocator::ForceSetParent<ir::ClassProperty>(allocator_, id->Clone(allocator_, nullptr),
71 declarator->Init(), typeAnn,
72 varDecl->Modifiers(), allocator_, false);
73 field->SetRange(declarator->Range());
74
75 if (varDecl->IsExported() && varDecl->HasExportAlias()) {
76 field->AddAstNodeFlags(ir::AstNodeFlags::HAS_EXPORT_ALIAS);
77 }
78
79 result_.classProperties.emplace_back(field);
80 if (auto stmt = InitTopLevelProperty(field); stmt != nullptr) {
81 result_.initStatements.emplace_back(stmt);
82 }
83 }
84 }
85
RefIdent(const util::StringView & name)86 ir::Identifier *GlobalDeclTransformer::RefIdent(const util::StringView &name)
87 {
88 auto *const callee = util::NodeAllocator::Alloc<ir::Identifier>(allocator_, name, allocator_);
89 callee->SetReference();
90 return callee;
91 }
92
InitTopLevelProperty(ir::ClassProperty * classProperty)93 ir::ExpressionStatement *GlobalDeclTransformer::InitTopLevelProperty(ir::ClassProperty *classProperty)
94 {
95 ir::ExpressionStatement *initStmt = nullptr;
96 const auto initializer = classProperty->Value();
97 if (addInitializer_ && !classProperty->IsConst() && initializer != nullptr) {
98 auto *ident = RefIdent(classProperty->Id()->Name());
99 ident->SetRange(classProperty->Id()->Range());
100
101 initializer->SetParent(nullptr);
102 auto *assignmentExpression = util::NodeAllocator::Alloc<ir::AssignmentExpression>(
103 allocator_, ident, initializer, lexer::TokenType::PUNCTUATOR_SUBSTITUTION);
104 assignmentExpression->SetRange({ident->Start(), initializer->End()});
105 assignmentExpression->SetTsType(initializer->TsType());
106
107 auto expressionStatement =
108 util::NodeAllocator::Alloc<ir::ExpressionStatement>(allocator_, assignmentExpression);
109 expressionStatement->SetRange(classProperty->Range());
110
111 classProperty->SetRange({ident->Start(), initializer->End()});
112
113 if (classProperty->TypeAnnotation() != nullptr) {
114 classProperty->SetValue(nullptr);
115 } else {
116 // Code will be ignored, but checker is going to deduce the type.
117 classProperty->SetValue(initializer->Clone(allocator_, classProperty)->AsExpression());
118 }
119 initStmt = expressionStatement;
120 } else {
121 classProperty->SetStart(classProperty->Id()->Start());
122 }
123 return initStmt;
124 }
125
HandleNode(ir::AstNode * node)126 void GlobalDeclTransformer::HandleNode(ir::AstNode *node)
127 {
128 ASSERT(node->IsStatement());
129 if (typeDecl_.count(node->Type()) == 0U) {
130 ASSERT(!propertiesDecl_.count(node->Type()));
131 result_.initStatements.emplace_back(node->AsStatement());
132 }
133 }
134
135 } // namespace ark::es2panda::compiler
136