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 : 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?
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 21893 : cell_index(0) {}
109 :
110 : Handle<ModuleInfoEntry> Serialize(Isolate* isolate) const;
111 : };
112 :
113 : enum CellIndexKind { kInvalid, kExport, kImport };
114 : static CellIndexKind GetCellIndexKind(int cell_index);
115 :
116 : struct ModuleRequest {
117 : int index;
118 : int position;
119 : ModuleRequest(int index, int position) : index(index), position(position) {}
120 : };
121 :
122 : // Custom content-based comparer for the below maps, to keep them stable
123 : // across parses.
124 : struct V8_EXPORT_PRIVATE AstRawStringComparer {
125 : bool operator()(const AstRawString* lhs, const AstRawString* rhs) const;
126 : };
127 :
128 : typedef ZoneMap<const AstRawString*, ModuleRequest, AstRawStringComparer>
129 : ModuleRequestMap;
130 : typedef ZoneMultimap<const AstRawString*, Entry*, AstRawStringComparer>
131 : RegularExportMap;
132 : typedef ZoneMap<const AstRawString*, Entry*, AstRawStringComparer>
133 : RegularImportMap;
134 :
135 : // Module requests.
136 : const ModuleRequestMap& module_requests() const { return module_requests_; }
137 :
138 : // Namespace imports.
139 : const ZoneVector<const Entry*>& namespace_imports() const {
140 : return namespace_imports_;
141 : }
142 :
143 : // All the remaining imports, indexed by local name.
144 : const RegularImportMap& regular_imports() const { return regular_imports_; }
145 :
146 : // Star exports and explicitly indirect exports.
147 : const ZoneVector<const Entry*>& special_exports() const {
148 : return special_exports_;
149 : }
150 :
151 : // All the remaining exports, indexed by local name.
152 : // After canonicalization (see Validate), these are exactly the local exports.
153 : const RegularExportMap& regular_exports() const { return regular_exports_; }
154 :
155 : void AddRegularExport(Entry* entry) {
156 : DCHECK_NOT_NULL(entry->export_name);
157 : DCHECK_NOT_NULL(entry->local_name);
158 : DCHECK_NULL(entry->import_name);
159 : DCHECK_LT(entry->module_request, 0);
160 38308 : regular_exports_.insert(std::make_pair(entry->local_name, entry));
161 : }
162 :
163 : void AddSpecialExport(const Entry* entry, Zone* zone) {
164 : DCHECK_NULL(entry->local_name);
165 : DCHECK_LE(0, entry->module_request);
166 380 : special_exports_.push_back(entry);
167 : }
168 :
169 : void AddRegularImport(Entry* entry) {
170 : DCHECK_NOT_NULL(entry->import_name);
171 : DCHECK_NOT_NULL(entry->local_name);
172 : DCHECK_NULL(entry->export_name);
173 : DCHECK_LE(0, entry->module_request);
174 4308 : regular_imports_.insert(std::make_pair(entry->local_name, entry));
175 : // We don't care if there's already an entry for this local name, as in that
176 : // case we will report an error when declaring the variable.
177 : }
178 :
179 : void AddNamespaceImport(const Entry* entry, Zone* zone) {
180 : DCHECK_NULL(entry->import_name);
181 : DCHECK_NULL(entry->export_name);
182 : DCHECK_NOT_NULL(entry->local_name);
183 : DCHECK_LE(0, entry->module_request);
184 260 : namespace_imports_.push_back(entry);
185 : }
186 :
187 : Handle<FixedArray> SerializeRegularExports(Isolate* isolate,
188 : Zone* zone) const;
189 :
190 : private:
191 : ModuleRequestMap module_requests_;
192 : ZoneVector<const Entry*> special_exports_;
193 : ZoneVector<const Entry*> namespace_imports_;
194 : RegularExportMap regular_exports_;
195 : RegularImportMap regular_imports_;
196 :
197 : // If there are multiple export entries with the same export name, return the
198 : // last of them (in source order). Otherwise return nullptr.
199 : const Entry* FindDuplicateExport(Zone* zone) const;
200 :
201 : // Find any implicitly indirect exports and make them explicit.
202 : //
203 : // An explicitly indirect export is an export entry arising from an export
204 : // statement of the following form:
205 : // export {a as c} from "X";
206 : // An implicitly indirect export corresponds to
207 : // export {b as c};
208 : // in the presence of an import statement of the form
209 : // import {a as b} from "X";
210 : // This function finds such implicitly indirect export entries and rewrites
211 : // them by filling in the import name and module request, as well as nulling
212 : // out the local name. Effectively, it turns
213 : // import {a as b} from "X"; export {b as c};
214 : // into:
215 : // import {a as b} from "X"; export {a as c} from "X";
216 : // (The import entry is never deleted.)
217 : void MakeIndirectExportsExplicit(Zone* zone);
218 :
219 : // Assign a cell_index of -1,-2,... to regular imports.
220 : // Assign a cell_index of +1,+2,... to regular (local) exports.
221 : // Assign a cell_index of 0 to anything else.
222 : void AssignCellIndices();
223 :
224 : int AddModuleRequest(const AstRawString* specifier,
225 : Scanner::Location specifier_loc) {
226 : DCHECK_NOT_NULL(specifier);
227 2884 : int module_requests_count = static_cast<int>(module_requests_.size());
228 : auto it = module_requests_
229 5768 : .insert(std::make_pair(specifier,
230 : ModuleRequest(module_requests_count,
231 : specifier_loc.beg_pos)))
232 : .first;
233 2739 : return it->second.index;
234 : }
235 : };
236 :
237 : } // namespace internal
238 : } // namespace v8
239 :
240 : #endif // V8_AST_MODULES_H_
|