• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/importExportDecls.h"
17 #include "ir/ets/etsReExportDeclaration.h"
18 #include "util/importPathManager.h"
19 
20 namespace ark::es2panda::compiler {
21 
ParseDefaultSources()22 void ImportExportDecls::ParseDefaultSources()
23 {
24     auto imports = parser_->ParseDefaultSources(DEFAULT_IMPORT_SOURCE_FILE, defaultImportSource_);
25     varbinder_->SetDefaultImports(std::move(imports));
26 }
27 
HandleGlobalStmts(const ArenaVector<parser::Program * > & programs)28 void ImportExportDecls::HandleGlobalStmts(const ArenaVector<parser::Program *> &programs)
29 {
30     VerifySingleExportDefault(programs);
31     VerifyTypeExports(programs);
32     for (const auto &program : programs) {
33         fieldMap_.clear();
34         exportNameMap_.clear();
35         exportedTypes_.clear();
36         for (auto stmt : program->Ast()->Statements()) {
37             stmt->Accept(this);
38             if (stmt->IsExportNamedDeclaration()) {
39                 PopulateAliasMap(stmt->AsExportNamedDeclaration(), program->SourceFilePath());
40             }
41         }
42         for (auto const &[exportName, startLoc] : exportNameMap_) {
43             const bool isType = exportedTypes_.find(exportName) != exportedTypes_.end();
44             util::StringView originalName = varbinder_->FindNameInAliasMap(program->SourceFilePath(), exportName);
45 
46             ASSERT(!originalName.Empty());
47 
48             if (fieldMap_.find(originalName) == fieldMap_.end() && !isType) {
49                 util::ErrorHandler::ThrowSyntaxError(
50                     varbinder_->Program(), "Cannot find name '" + originalName.Mutf8() + "' to export", startLoc);
51             }
52             if (!isType) {
53                 HandleSelectiveExportWithAlias(originalName, exportName, startLoc);
54             }
55         }
56     }
57 }
58 
PopulateAliasMap(const ir::ExportNamedDeclaration * decl,const util::StringView & path)59 void ImportExportDecls::PopulateAliasMap(const ir::ExportNamedDeclaration *decl, const util::StringView &path)
60 {
61     for (auto spec : decl->Specifiers()) {
62         if (!varbinder_->AddSelectiveExportAlias(path, spec->Local()->Name(), spec->Exported()->Name())) {
63             util::ErrorHandler::ThrowSyntaxError(varbinder_->Program(),
64                                                  "The given name '" + spec->Local()->Name().Mutf8() +
65                                                      "' is already used in another export",
66                                                  spec->Start());
67         }
68     }
69 }
70 
HandleSelectiveExportWithAlias(util::StringView originalFieldName,util::StringView exportName,lexer::SourcePosition startLoc)71 void ImportExportDecls::HandleSelectiveExportWithAlias(util::StringView originalFieldName, util::StringView exportName,
72                                                        lexer::SourcePosition startLoc)
73 {
74     ir::AstNode *field = fieldMap_.find(originalFieldName)->second;
75     if ((field->Modifiers() & ir::ModifierFlags::EXPORTED) != 0) {
76         // Note (oeotvos) Needs to be discussed, whether we would like to allow exporting the same program
77         // element using its original name and also an alias, like: export {test_func, test_func as foo}.
78         util::ErrorHandler::ThrowSyntaxError(
79             varbinder_->Program(), "Cannot export '" + originalFieldName.Mutf8() + "', it was already exported",
80             startLoc);
81     }
82 
83     field->AddModifier(ir::ModifierFlags::EXPORT);
84 
85     if (exportName != originalFieldName) {
86         if (auto declItem = fieldMap_.find(exportName); declItem != fieldMap_.end()) {
87             // Checking for the alias might be unnecessary, because explicit exports cannot
88             // have an alias yet.
89             if (((declItem->second->Modifiers() & ir::ModifierFlags::EXPORTED) != 0) &&
90                 !declItem->second->HasExportAlias()) {
91                 util::ErrorHandler::ThrowSyntaxError(
92                     varbinder_->Program(),
93                     "The given name '" + exportName.Mutf8() + "' is already used in another export", startLoc);
94             }
95         }
96         field->AddAstNodeFlags(ir::AstNodeFlags::HAS_EXPORT_ALIAS);
97     }
98 }
99 
VisitFunctionDeclaration(ir::FunctionDeclaration * funcDecl)100 void ImportExportDecls::VisitFunctionDeclaration(ir::FunctionDeclaration *funcDecl)
101 {
102     fieldMap_.emplace(funcDecl->Function()->Id()->Name(), funcDecl->Function());
103 }
104 
VisitVariableDeclaration(ir::VariableDeclaration * varDecl)105 void ImportExportDecls::VisitVariableDeclaration(ir::VariableDeclaration *varDecl)
106 {
107     for (const auto &decl : varDecl->Declarators()) {
108         fieldMap_.emplace(decl->Id()->AsIdentifier()->Name(), varDecl);
109     }
110 }
111 
VisitClassDeclaration(ir::ClassDeclaration * classDecl)112 void ImportExportDecls::VisitClassDeclaration(ir::ClassDeclaration *classDecl)
113 {
114     fieldMap_.emplace(classDecl->Definition()->Ident()->Name(), classDecl);
115 }
116 
VisitTSTypeAliasDeclaration(ir::TSTypeAliasDeclaration * typeAliasDecl)117 void ImportExportDecls::VisitTSTypeAliasDeclaration(ir::TSTypeAliasDeclaration *typeAliasDecl)
118 {
119     fieldMap_.emplace(typeAliasDecl->Id()->Name(), typeAliasDecl);
120 }
121 
VisitTSInterfaceDeclaration(ir::TSInterfaceDeclaration * interfaceDecl)122 void ImportExportDecls::VisitTSInterfaceDeclaration(ir::TSInterfaceDeclaration *interfaceDecl)
123 {
124     fieldMap_.emplace(interfaceDecl->Id()->Name(), interfaceDecl);
125 }
126 
VisitExportNamedDeclaration(ir::ExportNamedDeclaration * exportDecl)127 void ImportExportDecls::VisitExportNamedDeclaration(ir::ExportNamedDeclaration *exportDecl)
128 {
129     for (auto spec : exportDecl->Specifiers()) {
130         auto local = spec->Local();
131         if (exportDecl->IsExportedType()) {
132             exportedTypes_.insert(local->Name());
133         }
134         if (!exportNameMap_.emplace(local->Name(), local->Start()).second) {
135             util::ErrorHandler::ThrowSyntaxError(
136                 varbinder_->Program(),
137                 "The given name '" + local->Name().Mutf8() + "' is already used in another export", local->Start());
138         }
139     }
140 }
141 
HandleSimpleType(std::set<util::StringView> & exportedTypes,std::set<util::StringView> & exportedStatements,ir::Statement * stmt,util::StringView name,parser::Program * program,lexer::SourcePosition pos)142 void ImportExportDecls::HandleSimpleType(std::set<util::StringView> &exportedTypes,
143                                          std::set<util::StringView> &exportedStatements, ir::Statement *stmt,
144                                          util::StringView name, parser::Program *program, lexer::SourcePosition pos)
145 {
146     if (stmt->IsExported()) {
147         exportedStatements.insert(name);
148     }
149 
150     if (!stmt->IsExportedType()) {
151         return;
152     }
153 
154     if (exportedStatements.find(name) != exportedStatements.end()) {
155         util::ErrorHandler::ThrowSyntaxError(
156             program, "Name '" + name.Mutf8() + "' cannot be exported and type exported at the same time.", pos);
157     }
158 
159     if (exportedTypes.find(name) != exportedTypes.end()) {
160         util::ErrorHandler::ThrowSyntaxError(program, "Cannot export the same '" + name.Mutf8() + "' type twice.", pos);
161     } else {
162         exportedTypes.insert(name);
163     }
164 }
165 
VerifyTypeExports(const ArenaVector<parser::Program * > & programs)166 void ImportExportDecls::VerifyTypeExports(const ArenaVector<parser::Program *> &programs)
167 {
168     std::set<util::StringView> exportedTypes;
169     std::set<util::StringView> exportedStatements;
170     std::map<util::StringView, ir::AstNode *> typesMap;
171 
172     for (const auto &program : programs) {
173         for (auto stmt : program->Ast()->Statements()) {
174             VerifyType(stmt, program, exportedTypes, exportedStatements, typesMap);
175         }
176     }
177 }
178 
VerifyType(ir::Statement * stmt,parser::Program * program,std::set<util::StringView> & exportedTypes,std::set<util::StringView> & exportedStatements,std::map<util::StringView,ir::AstNode * > & typesMap)179 void ImportExportDecls::VerifyType(ir::Statement *stmt, parser::Program *program,
180                                    std::set<util::StringView> &exportedTypes,
181                                    std::set<util::StringView> &exportedStatements,
182                                    std::map<util::StringView, ir::AstNode *> &typesMap)
183 {
184     if (stmt->IsClassDeclaration()) {
185         typesMap.insert({stmt->AsClassDeclaration()->Definition()->Ident()->Name(), stmt});
186         return HandleSimpleType(exportedTypes, exportedStatements, stmt,
187                                 stmt->AsClassDeclaration()->Definition()->Ident()->Name(), program, stmt->Start());
188     }
189 
190     if (stmt->IsTSInterfaceDeclaration()) {
191         typesMap.insert({stmt->AsTSInterfaceDeclaration()->Id()->Name(), stmt});
192         return HandleSimpleType(exportedTypes, exportedStatements, stmt, stmt->AsTSInterfaceDeclaration()->Id()->Name(),
193                                 program, stmt->Start());
194     }
195 
196     if (stmt->IsTSTypeAliasDeclaration()) {
197         typesMap.insert({stmt->AsTSTypeAliasDeclaration()->Id()->Name(), stmt});
198         return HandleSimpleType(exportedTypes, exportedStatements, stmt, stmt->AsTSTypeAliasDeclaration()->Id()->Name(),
199                                 program, stmt->Start());
200     }
201 
202     if (!stmt->IsExportedType()) {
203         return;
204     }
205 
206     if (!stmt->IsExportNamedDeclaration()) {
207         util::ErrorHandler::ThrowSyntaxError(program, "Can only type export class or interface!", stmt->Start());
208     }
209 
210     for (auto spec : stmt->AsExportNamedDeclaration()->Specifiers()) {
211         util::StringView name = spec->Local()->Name();
212         util::StringView nameFind = spec->Exported()->Name();
213 
214         auto element = typesMap.find(nameFind);
215         if (element == typesMap.end()) {
216             util::ErrorHandler::ThrowSyntaxError(program, "Can only type export class or interface!",
217                                                  spec->Local()->Start());
218         }
219         if (!element->second->IsExportedType()) {
220             element->second->AddModifier(ir::ModifierFlags::EXPORT_TYPE);
221         }
222         HandleSimpleType(exportedTypes, exportedStatements, stmt, name, program, spec->Local()->Start());
223         if (!name.Is(nameFind.Mutf8())) {
224             element->second->AddAstNodeFlags(ir::AstNodeFlags::HAS_EXPORT_ALIAS);
225             HandleSimpleType(exportedTypes, exportedStatements, stmt, nameFind, program, spec->Local()->Start());
226         }
227     }
228 }
229 
VerifySingleExportDefault(const ArenaVector<parser::Program * > & programs)230 void ImportExportDecls::VerifySingleExportDefault(const ArenaVector<parser::Program *> &programs)
231 {
232     bool metDefaultExport = false;
233     auto verifyDefault = [&metDefaultExport](ir::Statement *stmt, parser::Program *program) {
234         if ((stmt->Modifiers() & ir::ModifierFlags::DEFAULT_EXPORT) == 0) {
235             return;
236         }
237         if (metDefaultExport) {
238             util::ErrorHandler::ThrowSyntaxError(program, "Only one default export is allowed in a module",
239                                                  stmt->Start());
240         }
241         metDefaultExport = true;
242     };
243     for (const auto &program : programs) {
244         for (auto stmt : program->Ast()->Statements()) {
245             verifyDefault(stmt, program);
246         }
247         metDefaultExport = false;
248     }
249 }
250 
251 }  // namespace ark::es2panda::compiler
252