1 /**
2 * Copyright (c) 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/exportAnonymousConst.h"
17 #include "compiler/lowering/util.h"
18 #include "macros.h"
19
20 namespace ark::es2panda::compiler {
21
CreateAnonymousVariableDecl(public_lib::Context * ctx,ir::ExportNamedDeclaration * exportDecl)22 static ir::AstNode *CreateAnonymousVariableDecl(public_lib::Context *ctx, ir::ExportNamedDeclaration *exportDecl)
23 {
24 [[maybe_unused]] const size_t exportDefaultMaxSize = 1;
25 auto *parser = ctx->parser->AsETSParser();
26 auto *allocator = ctx->allocator;
27
28 auto *anonymousIdentifier =
29 allocator->New<ir::Identifier>(exportDecl->Specifiers().front()->Exported()->Name(), allocator);
30 ES2PANDA_ASSERT(exportDecl->Specifiers().size() == exportDefaultMaxSize);
31 auto *anonymousConstant = parser->CreateFormattedExpression(
32 "const @@I1 = @@E2;", anonymousIdentifier, exportDecl->Specifiers().front()->GetConstantExpression());
33
34 auto *anonymousVariableDecl = anonymousConstant->AsBlockExpression()->Statements().front()->AsVariableDeclaration();
35 anonymousVariableDecl->AddModifier(ir::ModifierFlags::CONST | ir::ModifierFlags::STATIC |
36 ir::ModifierFlags::PUBLIC);
37
38 return anonymousVariableDecl;
39 }
40
HandleAnonymousConst(public_lib::Context * const ctx,parser::Program * const program)41 static void HandleAnonymousConst(public_lib::Context *const ctx, parser::Program *const program)
42 {
43 /* The Single Export Directive can directly export anonymous constant variables
44 * export default new A()
45 * ----- After Parser -----
46 * export default genName
47 * ----- perform the following conversion this phase -----
48 * const genName = new A()
49 * export default genName
50 */
51 auto isExportAnonymousConst = [](ir::AstNode *ast) {
52 if (!ast->IsExportNamedDeclaration()) {
53 return false;
54 }
55 return std::any_of(
56 ast->AsExportNamedDeclaration()->Specifiers().begin(), ast->AsExportNamedDeclaration()->Specifiers().end(),
57 [](auto *specific) { return specific->IsDefault() && specific->GetConstantExpression() != nullptr; });
58 };
59 auto module = program->Ast();
60 auto iterator = std::find_if(module->Statements().begin(), module->Statements().end(), isExportAnonymousConst);
61 if (iterator == module->Statements().end()) {
62 return;
63 }
64
65 auto *anonymousVariableDecl =
66 CreateAnonymousVariableDecl(ctx, (*iterator)->AsExportNamedDeclaration())->AsStatement();
67 module->Statements().insert(iterator, anonymousVariableDecl);
68 }
69
HandleExportDefaultInExportNamedDecl(public_lib::Context * const ctx,parser::Program * const program)70 static void HandleExportDefaultInExportNamedDecl(public_lib::Context *const ctx, parser::Program *const program)
71 {
72 /* Create a separate ExportNamedDeclaration for export default and add the Export_default flag
73 * export {new A() as default,B as B, C as C}
74 * ----- perform the following conversion this phase -----
75 * export default new A()
76 * export {B as B, C as C}
77 */
78 auto exportNamedDeclarationhasDefault = [](ir::AstNode *ast) {
79 if (!ast->IsExportNamedDeclaration()) {
80 return false;
81 }
82 return std::any_of(ast->AsExportNamedDeclaration()->Specifiers().begin(),
83 ast->AsExportNamedDeclaration()->Specifiers().end(),
84 [](auto *specific) { return specific->IsDefault(); });
85 };
86
87 auto module = program->Ast();
88 auto iterator =
89 std::find_if(module->Statements().begin(), module->Statements().end(), exportNamedDeclarationhasDefault);
90 if (iterator == module->Statements().end()) {
91 return;
92 }
93
94 auto *allocator = ctx->allocator;
95 auto *exportNamedDeclaration = (*iterator)->AsExportNamedDeclaration();
96 auto oldSpecifiers = exportNamedDeclaration->Specifiers();
97 ArenaVector<ir::ExportSpecifier *> newSpecifiers(allocator->Adapter());
98 ArenaVector<ir::ExportNamedDeclaration *> exportDefaulNamedDeclarations(allocator->Adapter());
99
100 for (auto *specifier : oldSpecifiers) {
101 if (specifier->IsDefault()) {
102 ArenaVector<ir::ExportSpecifier *> exports(allocator->Adapter());
103 exports.emplace_back(specifier);
104 auto *exportDefaulNamedDecl = allocator->New<ir::ExportNamedDeclaration>(
105 allocator, static_cast<ir::StringLiteral *>(nullptr), std::move(exports));
106 ES2PANDA_ASSERT(exportDefaulNamedDecl);
107 exportDefaulNamedDecl->AddModifier(ir::ModifierFlags::DEFAULT_EXPORT);
108 exportDefaulNamedDeclarations.push_back(exportDefaulNamedDecl);
109 continue;
110 }
111 newSpecifiers.push_back(specifier);
112 }
113
114 module->Statements().insert(iterator, exportDefaulNamedDeclarations.front());
115 exportNamedDeclaration->ReplaceSpecifiers(newSpecifiers);
116 exportNamedDeclaration->ClearModifier(ir::ModifierFlags::DEFAULT_EXPORT);
117 }
118
Perform(public_lib::Context * const ctx,parser::Program * const program)119 bool ExportAnonymousConstPhase::Perform(public_lib::Context *const ctx, parser::Program *const program)
120 {
121 for (auto &[_, ext_programs] : program->ExternalSources()) {
122 (void)_;
123 for (auto *extProg : ext_programs) {
124 Perform(ctx, extProg);
125 }
126 }
127
128 HandleExportDefaultInExportNamedDecl(ctx, program);
129 HandleAnonymousConst(ctx, program);
130 return true;
131 }
132
133 } // namespace ark::es2panda::compiler
134