• 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_(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