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_(1, zone), 25 namespace_imports_(1, 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( 36 const AstRawString* import_name, const AstRawString* local_name, 37 const AstRawString* module_request, const Scanner::Location loc, 38 Zone* zone); 39 40 // import * as x from "foo.js"; 41 void AddStarImport( 42 const AstRawString* local_name, const AstRawString* module_request, 43 const Scanner::Location loc, Zone* zone); 44 45 // import "foo.js"; 46 // import {} from "foo.js"; 47 // export {} from "foo.js"; (sic!) 48 void AddEmptyImport(const AstRawString* module_request); 49 50 // export {x}; 51 // export {x as y}; 52 // export VariableStatement 53 // export Declaration 54 // export default ... 55 void AddExport( 56 const AstRawString* local_name, const AstRawString* export_name, 57 const Scanner::Location loc, Zone* zone); 58 59 // export {x} from "foo.js"; 60 // export {x as y} from "foo.js"; 61 void AddExport( 62 const AstRawString* export_name, const AstRawString* import_name, 63 const AstRawString* module_request, const Scanner::Location loc, 64 Zone* zone); 65 66 // export * from "foo.js"; 67 void AddStarExport( 68 const AstRawString* module_request, const Scanner::Location loc, 69 Zone* zone); 70 71 // Check if module is well-formed and report error if not. 72 // Also canonicalize indirect exports. 73 bool Validate(ModuleScope* module_scope, 74 PendingCompilationErrorHandler* error_handler, Zone* zone); 75 76 struct Entry : public ZoneObject { 77 Scanner::Location location; 78 const AstRawString* export_name; 79 const AstRawString* local_name; 80 const AstRawString* import_name; 81 82 // The module_request value records the order in which modules are 83 // requested. It also functions as an index into the ModuleInfo's array of 84 // module specifiers and into the Module's array of requested modules. A 85 // negative value means no module request. 86 int module_request; 87 88 // Import/export entries that are associated with a MODULE-allocated 89 // variable (i.e. regular_imports and regular_exports after Validate) use 90 // the cell_index value to encode the location of their cell. During 91 // variable allocation, this will be be copied into the variable's index 92 // field. 93 // Entries that are not associated with a MODULE-allocated variable have 94 // GetCellIndexKind(cell_index) == kInvalid. 95 int cell_index; 96 97 // TODO(neis): Remove local_name component? EntryEntry98 explicit Entry(Scanner::Location loc) 99 : location(loc), 100 export_name(nullptr), 101 local_name(nullptr), 102 import_name(nullptr), 103 module_request(-1), 104 cell_index(0) {} 105 106 // (De-)serialization support. 107 // Note that the location value is not preserved as it's only needed by the 108 // parser. (A Deserialize'd entry has an invalid location.) 109 Handle<ModuleInfoEntry> Serialize(Isolate* isolate) const; 110 static Entry* Deserialize(Isolate* isolate, AstValueFactory* avfactory, 111 Handle<ModuleInfoEntry> entry); 112 }; 113 114 enum CellIndexKind { kInvalid, kExport, kImport }; 115 static CellIndexKind GetCellIndexKind(int cell_index); 116 117 // Module requests. module_requests()118 const ZoneMap<const AstRawString*, int>& module_requests() const { 119 return module_requests_; 120 } 121 122 // Namespace imports. namespace_imports()123 const ZoneList<const Entry*>& namespace_imports() const { 124 return namespace_imports_; 125 } 126 127 // All the remaining imports, indexed by local name. regular_imports()128 const ZoneMap<const AstRawString*, Entry*>& regular_imports() const { 129 return regular_imports_; 130 } 131 132 // Star exports and explicitly indirect exports. special_exports()133 const ZoneList<const Entry*>& special_exports() const { 134 return special_exports_; 135 } 136 137 // All the remaining exports, indexed by local name. 138 // After canonicalization (see Validate), these are exactly the local exports. regular_exports()139 const ZoneMultimap<const AstRawString*, Entry*>& regular_exports() const { 140 return regular_exports_; 141 } 142 AddRegularExport(Entry * entry)143 void AddRegularExport(Entry* entry) { 144 DCHECK_NOT_NULL(entry->export_name); 145 DCHECK_NOT_NULL(entry->local_name); 146 DCHECK_NULL(entry->import_name); 147 DCHECK_LT(entry->module_request, 0); 148 regular_exports_.insert(std::make_pair(entry->local_name, entry)); 149 } 150 AddSpecialExport(const Entry * entry,Zone * zone)151 void AddSpecialExport(const Entry* entry, Zone* zone) { 152 DCHECK_NULL(entry->local_name); 153 DCHECK_LE(0, entry->module_request); 154 special_exports_.Add(entry, zone); 155 } 156 AddRegularImport(Entry * entry)157 void AddRegularImport(Entry* entry) { 158 DCHECK_NOT_NULL(entry->import_name); 159 DCHECK_NOT_NULL(entry->local_name); 160 DCHECK_NULL(entry->export_name); 161 DCHECK_LE(0, entry->module_request); 162 regular_imports_.insert(std::make_pair(entry->local_name, entry)); 163 // We don't care if there's already an entry for this local name, as in that 164 // case we will report an error when declaring the variable. 165 } 166 AddNamespaceImport(const Entry * entry,Zone * zone)167 void AddNamespaceImport(const Entry* entry, Zone* zone) { 168 DCHECK_NULL(entry->import_name); 169 DCHECK_NULL(entry->export_name); 170 DCHECK_NOT_NULL(entry->local_name); 171 DCHECK_LE(0, entry->module_request); 172 namespace_imports_.Add(entry, zone); 173 } 174 175 Handle<FixedArray> SerializeRegularExports(Isolate* isolate, 176 Zone* zone) const; 177 void DeserializeRegularExports(Isolate* isolate, AstValueFactory* avfactory, 178 Handle<ModuleInfo> module_info); 179 180 private: 181 // TODO(neis): Use STL datastructure instead of ZoneList? 182 ZoneMap<const AstRawString*, int> module_requests_; 183 ZoneList<const Entry*> special_exports_; 184 ZoneList<const Entry*> namespace_imports_; 185 ZoneMultimap<const AstRawString*, Entry*> regular_exports_; 186 ZoneMap<const AstRawString*, Entry*> regular_imports_; 187 188 // If there are multiple export entries with the same export name, return the 189 // last of them (in source order). Otherwise return nullptr. 190 const Entry* FindDuplicateExport(Zone* zone) const; 191 192 // Find any implicitly indirect exports and make them explicit. 193 // 194 // An explicitly indirect export is an export entry arising from an export 195 // statement of the following form: 196 // export {a as c} from "X"; 197 // An implicitly indirect export corresponds to 198 // export {b as c}; 199 // in the presence of an import statement of the form 200 // import {a as b} from "X"; 201 // This function finds such implicitly indirect export entries and rewrites 202 // them by filling in the import name and module request, as well as nulling 203 // out the local name. Effectively, it turns 204 // import {a as b} from "X"; export {b as c}; 205 // into: 206 // import {a as b} from "X"; export {a as c} from "X"; 207 // (The import entry is never deleted.) 208 void MakeIndirectExportsExplicit(Zone* zone); 209 210 // Assign a cell_index of -1,-2,... to regular imports. 211 // Assign a cell_index of +1,+2,... to regular (local) exports. 212 // Assign a cell_index of 0 to anything else. 213 void AssignCellIndices(); 214 AddModuleRequest(const AstRawString * specifier)215 int AddModuleRequest(const AstRawString* specifier) { 216 DCHECK_NOT_NULL(specifier); 217 auto it = module_requests_ 218 .insert(std::make_pair(specifier, module_requests_.size())) 219 .first; 220 return it->second; 221 } 222 }; 223 224 } // namespace internal 225 } // namespace v8 226 227 #endif // V8_AST_MODULES_H_ 228