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