Line data Source code
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:
22 74923 : explicit ModuleDescriptor(Zone* zone)
23 : : module_requests_(zone),
24 : special_exports_(zone),
25 : namespace_imports_(zone),
26 : regular_exports_(zone),
27 74923 : 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?
102 : 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 28508 : 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;
124 : 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.
141 : const ModuleRequestMap& module_requests() const { return module_requests_; }
142 :
143 : // 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.
149 : const RegularImportMap& regular_imports() const { return regular_imports_; }
150 :
151 : // Star exports and explicitly indirect 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.
158 : const RegularExportMap& regular_exports() const { return regular_exports_; }
159 :
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 46006 : regular_exports_.insert(std::make_pair(entry->local_name, entry));
166 : }
167 :
168 : void AddSpecialExport(const Entry* entry, Zone* zone) {
169 : DCHECK_NULL(entry->local_name);
170 : DCHECK_LE(0, entry->module_request);
171 380 : special_exports_.push_back(entry);
172 : }
173 :
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 9270 : 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 :
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 545 : 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 :
231 2874 : int AddModuleRequest(const AstRawString* specifier,
232 : Scanner::Location specifier_loc) {
233 : DCHECK_NOT_NULL(specifier);
234 2874 : 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 5748 : specifier_loc.beg_pos)))
239 : .first;
240 2874 : return it->second.index;
241 : }
242 : };
243 :
244 : } // namespace internal
245 : } // namespace v8
246 :
247 : #endif // V8_AST_MODULES_H_
|