modules.h revision c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7a
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/pending-compilation-error-handler.h"
10#include "src/zone/zone-containers.h"
11
12namespace v8 {
13namespace internal {
14
15
16class AstRawString;
17class ModuleInfo;
18class ModuleInfoEntry;
19
20class ModuleDescriptor : public ZoneObject {
21 public:
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?
98    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.
118  const ZoneMap<const AstRawString*, int>& module_requests() const {
119    return module_requests_;
120  }
121
122  // 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.
128  const ZoneMap<const AstRawString*, Entry*>& regular_imports() const {
129    return regular_imports_;
130  }
131
132  // Star exports and explicitly indirect 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.
139  const ZoneMultimap<const AstRawString*, Entry*>& regular_exports() const {
140    return regular_exports_;
141  }
142
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
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
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
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
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