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 ModuleInfo; 17 class ModuleInfoEntry; 18 class PendingCompilationErrorHandler; 19 20 class ModuleDescriptor : public ZoneObject { 21 public: ModuleDescriptor(Zone * zone)22 explicit ModuleDescriptor(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 ModuleInfo's array of 88 // module specifiers and into the Module's array of requested modules. A 89 // 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 // (De-)serialization support. 111 // Note that the location value is not preserved as it's only needed by the 112 // parser. (A Deserialize'd entry has an invalid location.) 113 Handle<ModuleInfoEntry> Serialize(Isolate* isolate) const; 114 static Entry* Deserialize(Isolate* isolate, AstValueFactory* avfactory, 115 Handle<ModuleInfoEntry> entry); 116 }; 117 118 enum CellIndexKind { kInvalid, kExport, kImport }; 119 static CellIndexKind GetCellIndexKind(int cell_index); 120 121 struct ModuleRequest { 122 int index; 123 int position; ModuleRequestModuleRequest124 ModuleRequest(int index, int position) : index(index), position(position) {} 125 }; 126 127 // Custom content-based comparer for the below maps, to keep them stable 128 // across parses. 129 struct AstRawStringComparer { 130 bool operator()(const AstRawString* lhs, const AstRawString* rhs) const; 131 }; 132 133 typedef ZoneMap<const AstRawString*, ModuleRequest, AstRawStringComparer> 134 ModuleRequestMap; 135 typedef ZoneMultimap<const AstRawString*, Entry*, AstRawStringComparer> 136 RegularExportMap; 137 typedef ZoneMap<const AstRawString*, Entry*, AstRawStringComparer> 138 RegularImportMap; 139 140 // Module requests. module_requests()141 const ModuleRequestMap& module_requests() const { return module_requests_; } 142 143 // Namespace imports. namespace_imports()144 const ZoneVector<const Entry*>& namespace_imports() const { 145 return namespace_imports_; 146 } 147 148 // All the remaining imports, indexed by local name. regular_imports()149 const RegularImportMap& regular_imports() const { return regular_imports_; } 150 151 // Star exports and explicitly indirect exports. special_exports()152 const ZoneVector<const Entry*>& special_exports() const { 153 return special_exports_; 154 } 155 156 // All the remaining exports, indexed by local name. 157 // After canonicalization (see Validate), these are exactly the local exports. regular_exports()158 const RegularExportMap& regular_exports() const { return regular_exports_; } 159 AddRegularExport(Entry * entry)160 void AddRegularExport(Entry* entry) { 161 DCHECK_NOT_NULL(entry->export_name); 162 DCHECK_NOT_NULL(entry->local_name); 163 DCHECK_NULL(entry->import_name); 164 DCHECK_LT(entry->module_request, 0); 165 regular_exports_.insert(std::make_pair(entry->local_name, entry)); 166 } 167 AddSpecialExport(const Entry * entry,Zone * zone)168 void AddSpecialExport(const Entry* entry, Zone* zone) { 169 DCHECK_NULL(entry->local_name); 170 DCHECK_LE(0, entry->module_request); 171 special_exports_.push_back(entry); 172 } 173 AddRegularImport(Entry * entry)174 void AddRegularImport(Entry* entry) { 175 DCHECK_NOT_NULL(entry->import_name); 176 DCHECK_NOT_NULL(entry->local_name); 177 DCHECK_NULL(entry->export_name); 178 DCHECK_LE(0, entry->module_request); 179 regular_imports_.insert(std::make_pair(entry->local_name, entry)); 180 // We don't care if there's already an entry for this local name, as in that 181 // case we will report an error when declaring the variable. 182 } 183 AddNamespaceImport(const Entry * entry,Zone * zone)184 void AddNamespaceImport(const Entry* entry, Zone* zone) { 185 DCHECK_NULL(entry->import_name); 186 DCHECK_NULL(entry->export_name); 187 DCHECK_NOT_NULL(entry->local_name); 188 DCHECK_LE(0, entry->module_request); 189 namespace_imports_.push_back(entry); 190 } 191 192 Handle<FixedArray> SerializeRegularExports(Isolate* isolate, 193 Zone* zone) const; 194 void DeserializeRegularExports(Isolate* isolate, AstValueFactory* avfactory, 195 Handle<ModuleInfo> module_info); 196 197 private: 198 ModuleRequestMap module_requests_; 199 ZoneVector<const Entry*> special_exports_; 200 ZoneVector<const Entry*> namespace_imports_; 201 RegularExportMap regular_exports_; 202 RegularImportMap regular_imports_; 203 204 // If there are multiple export entries with the same export name, return the 205 // last of them (in source order). Otherwise return nullptr. 206 const Entry* FindDuplicateExport(Zone* zone) const; 207 208 // Find any implicitly indirect exports and make them explicit. 209 // 210 // An explicitly indirect export is an export entry arising from an export 211 // statement of the following form: 212 // export {a as c} from "X"; 213 // An implicitly indirect export corresponds to 214 // export {b as c}; 215 // in the presence of an import statement of the form 216 // import {a as b} from "X"; 217 // This function finds such implicitly indirect export entries and rewrites 218 // them by filling in the import name and module request, as well as nulling 219 // out the local name. Effectively, it turns 220 // import {a as b} from "X"; export {b as c}; 221 // into: 222 // import {a as b} from "X"; export {a as c} from "X"; 223 // (The import entry is never deleted.) 224 void MakeIndirectExportsExplicit(Zone* zone); 225 226 // Assign a cell_index of -1,-2,... to regular imports. 227 // Assign a cell_index of +1,+2,... to regular (local) exports. 228 // Assign a cell_index of 0 to anything else. 229 void AssignCellIndices(); 230 AddModuleRequest(const AstRawString * specifier,Scanner::Location specifier_loc)231 int AddModuleRequest(const AstRawString* specifier, 232 Scanner::Location specifier_loc) { 233 DCHECK_NOT_NULL(specifier); 234 int module_requests_count = static_cast<int>(module_requests_.size()); 235 auto it = module_requests_ 236 .insert(std::make_pair(specifier, 237 ModuleRequest(module_requests_count, 238 specifier_loc.beg_pos))) 239 .first; 240 return it->second.index; 241 } 242 }; 243 244 } // namespace internal 245 } // namespace v8 246 247 #endif // V8_AST_MODULES_H_ 248