1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_AST_MODULES_H_ 6 #define V8_AST_MODULES_H_ 7 8 #include "src/parsing/scanner.h" // Only for Scanner::Location. 9 #include "src/zone/zone-containers.h" 10 11 namespace v8 { 12 namespace internal { 13 14 15 class AstRawString; 16 class SourceTextModuleInfo; 17 class SourceTextModuleInfoEntry; 18 class PendingCompilationErrorHandler; 19 20 class SourceTextModuleDescriptor : public ZoneObject { 21 public: SourceTextModuleDescriptor(Zone * zone)22 explicit SourceTextModuleDescriptor(Zone* zone) 23 : module_requests_(zone), 24 special_exports_(zone), 25 namespace_imports_(zone), 26 regular_exports_(zone), 27 regular_imports_(zone) {} 28 29 // The following Add* methods are high-level convenience functions for use by 30 // the parser. 31 32 // import x from "foo.js"; 33 // import {x} from "foo.js"; 34 // import {x as y} from "foo.js"; 35 void AddImport(const AstRawString* import_name, 36 const AstRawString* local_name, 37 const AstRawString* module_request, 38 const Scanner::Location loc, 39 const Scanner::Location specifier_loc, Zone* zone); 40 41 // import * as x from "foo.js"; 42 void AddStarImport(const AstRawString* local_name, 43 const AstRawString* module_request, 44 const Scanner::Location loc, 45 const Scanner::Location specifier_loc, Zone* zone); 46 47 // import "foo.js"; 48 // import {} from "foo.js"; 49 // export {} from "foo.js"; (sic!) 50 void AddEmptyImport(const AstRawString* module_request, 51 const Scanner::Location specifier_loc); 52 53 // export {x}; 54 // export {x as y}; 55 // export VariableStatement 56 // export Declaration 57 // export default ... 58 void AddExport( 59 const AstRawString* local_name, const AstRawString* export_name, 60 const Scanner::Location loc, Zone* zone); 61 62 // export {x} from "foo.js"; 63 // export {x as y} from "foo.js"; 64 void AddExport(const AstRawString* export_name, 65 const AstRawString* import_name, 66 const AstRawString* module_request, 67 const Scanner::Location loc, 68 const Scanner::Location specifier_loc, Zone* zone); 69 70 // export * from "foo.js"; 71 void AddStarExport(const AstRawString* module_request, 72 const Scanner::Location loc, 73 const Scanner::Location specifier_loc, Zone* zone); 74 75 // Check if module is well-formed and report error if not. 76 // Also canonicalize indirect exports. 77 bool Validate(ModuleScope* module_scope, 78 PendingCompilationErrorHandler* error_handler, Zone* zone); 79 80 struct Entry : public ZoneObject { 81 Scanner::Location location; 82 const AstRawString* export_name; 83 const AstRawString* local_name; 84 const AstRawString* import_name; 85 86 // The module_request value records the order in which modules are 87 // requested. It also functions as an index into the SourceTextModuleInfo's 88 // array of module specifiers and into the Module's array of requested 89 // modules. A negative value means no module request. 90 int module_request; 91 92 // Import/export entries that are associated with a MODULE-allocated 93 // variable (i.e. regular_imports and regular_exports after Validate) use 94 // the cell_index value to encode the location of their cell. During 95 // variable allocation, this will be be copied into the variable's index 96 // field. 97 // Entries that are not associated with a MODULE-allocated variable have 98 // GetCellIndexKind(cell_index) == kInvalid. 99 int cell_index; 100 101 // TODO(neis): Remove local_name component? EntryEntry102 explicit Entry(Scanner::Location loc) 103 : location(loc), 104 export_name(nullptr), 105 local_name(nullptr), 106 import_name(nullptr), 107 module_request(-1), 108 cell_index(0) {} 109 110 template <typename LocalIsolate> 111 Handle<SourceTextModuleInfoEntry> Serialize(LocalIsolate* isolate) const; 112 }; 113 114 enum CellIndexKind { kInvalid, kExport, kImport }; 115 static CellIndexKind GetCellIndexKind(int cell_index); 116 117 struct ModuleRequest { 118 int index; 119 int position; ModuleRequestModuleRequest120 ModuleRequest(int index, int position) : index(index), position(position) {} 121 }; 122 123 // Custom content-based comparer for the below maps, to keep them stable 124 // across parses. 125 struct V8_EXPORT_PRIVATE AstRawStringComparer { 126 bool operator()(const AstRawString* lhs, const AstRawString* rhs) const; 127 }; 128 129 using ModuleRequestMap = 130 ZoneMap<const AstRawString*, ModuleRequest, AstRawStringComparer>; 131 using RegularExportMap = 132 ZoneMultimap<const AstRawString*, Entry*, AstRawStringComparer>; 133 using RegularImportMap = 134 ZoneMap<const AstRawString*, Entry*, AstRawStringComparer>; 135 136 // Module requests. module_requests()137 const ModuleRequestMap& module_requests() const { return module_requests_; } 138 139 // Namespace imports. namespace_imports()140 const ZoneVector<const Entry*>& namespace_imports() const { 141 return namespace_imports_; 142 } 143 144 // All the remaining imports, indexed by local name. regular_imports()145 const RegularImportMap& regular_imports() const { return regular_imports_; } 146 147 // Star exports and explicitly indirect exports. special_exports()148 const ZoneVector<const Entry*>& special_exports() const { 149 return special_exports_; 150 } 151 152 // All the remaining exports, indexed by local name. 153 // After canonicalization (see Validate), these are exactly the local exports. regular_exports()154 const RegularExportMap& regular_exports() const { return regular_exports_; } 155 AddRegularExport(Entry * entry)156 void AddRegularExport(Entry* entry) { 157 DCHECK_NOT_NULL(entry->export_name); 158 DCHECK_NOT_NULL(entry->local_name); 159 DCHECK_NULL(entry->import_name); 160 DCHECK_LT(entry->module_request, 0); 161 regular_exports_.insert(std::make_pair(entry->local_name, entry)); 162 } 163 AddSpecialExport(const Entry * entry,Zone * zone)164 void AddSpecialExport(const Entry* entry, Zone* zone) { 165 DCHECK_NULL(entry->local_name); 166 DCHECK_LE(0, entry->module_request); 167 special_exports_.push_back(entry); 168 } 169 AddRegularImport(Entry * entry)170 void AddRegularImport(Entry* entry) { 171 DCHECK_NOT_NULL(entry->import_name); 172 DCHECK_NOT_NULL(entry->local_name); 173 DCHECK_NULL(entry->export_name); 174 DCHECK_LE(0, entry->module_request); 175 regular_imports_.insert(std::make_pair(entry->local_name, entry)); 176 // We don't care if there's already an entry for this local name, as in that 177 // case we will report an error when declaring the variable. 178 } 179 AddNamespaceImport(const Entry * entry,Zone * zone)180 void AddNamespaceImport(const Entry* entry, Zone* zone) { 181 DCHECK_NULL(entry->import_name); 182 DCHECK_NULL(entry->export_name); 183 DCHECK_NOT_NULL(entry->local_name); 184 DCHECK_LE(0, entry->module_request); 185 namespace_imports_.push_back(entry); 186 } 187 188 template <typename LocalIsolate> 189 Handle<FixedArray> SerializeRegularExports(LocalIsolate* isolate, 190 Zone* zone) const; 191 192 private: 193 ModuleRequestMap module_requests_; 194 ZoneVector<const Entry*> special_exports_; 195 ZoneVector<const Entry*> namespace_imports_; 196 RegularExportMap regular_exports_; 197 RegularImportMap regular_imports_; 198 199 // If there are multiple export entries with the same export name, return the 200 // last of them (in source order). Otherwise return nullptr. 201 const Entry* FindDuplicateExport(Zone* zone) const; 202 203 // Find any implicitly indirect exports and make them explicit. 204 // 205 // An explicitly indirect export is an export entry arising from an export 206 // statement of the following form: 207 // export {a as c} from "X"; 208 // An implicitly indirect export corresponds to 209 // export {b as c}; 210 // in the presence of an import statement of the form 211 // import {a as b} from "X"; 212 // This function finds such implicitly indirect export entries and rewrites 213 // them by filling in the import name and module request, as well as nulling 214 // out the local name. Effectively, it turns 215 // import {a as b} from "X"; export {b as c}; 216 // into: 217 // import {a as b} from "X"; export {a as c} from "X"; 218 // (The import entry is never deleted.) 219 void MakeIndirectExportsExplicit(Zone* zone); 220 221 // Assign a cell_index of -1,-2,... to regular imports. 222 // Assign a cell_index of +1,+2,... to regular (local) exports. 223 // Assign a cell_index of 0 to anything else. 224 void AssignCellIndices(); 225 AddModuleRequest(const AstRawString * specifier,Scanner::Location specifier_loc)226 int AddModuleRequest(const AstRawString* specifier, 227 Scanner::Location specifier_loc) { 228 DCHECK_NOT_NULL(specifier); 229 int module_requests_count = static_cast<int>(module_requests_.size()); 230 auto it = module_requests_ 231 .insert(std::make_pair(specifier, 232 ModuleRequest(module_requests_count, 233 specifier_loc.beg_pos))) 234 .first; 235 return it->second.index; 236 } 237 }; 238 239 } // namespace internal 240 } // namespace v8 241 242 #endif // V8_AST_MODULES_H_ 243