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