• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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