Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(472)

Side by Side Diff: lib/compiler/implementation/library_loader.dart

Issue 10990060: Added support for exports and re-exports. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Updated cf. comments. Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « lib/compiler/implementation/leg.dart ('k') | lib/compiler/implementation/patch_parser.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 class ScannerTask extends CompilerTask { 5 /**
6 ScannerTask(Compiler compiler) : super(compiler); 6 * [CompilerTask] for loading libraries and setting up the import/export scopes.
7 String get name => 'Scanner'; 7 */
8 abstract class LibraryLoader extends CompilerTask {
9 LibraryLoader(Compiler compiler) : super(compiler);
10
11 /**
12 * Loads the library located at [uri] and returns its [LibraryElement].
13 *
14 * If the library is not already loaded, the method creates the
15 * [LibraryElement] for the library and computes the import/export scope,
16 * loading and computing the import/export scopes of all required libraries in
17 * the process. The method handles cyclic dependency between libraries.
18 *
19 * This is the main entry point for [LibraryLoader].
20 */
21 abstract LibraryElement loadLibrary(Uri uri, Node node, Uri canonicalUri);
22
23 // TODO(johnniwinther): Remove this when patches don't need special parsing.
24 abstract void registerLibraryFromTag(LibraryDependencyHandler handler,
25 LibraryElement library,
26 LibraryDependency tag);
27
28 /**
29 * Adds the elements in the export scope of [importedLibrary] to the import
30 * scope of [importingLibrary].
31 */
32 // TODO(johnniwinther): Move handling of 'js_helper' to the library loader
33 // to remove this method from the [LibraryLoader] interface.
34 abstract void importLibrary(LibraryElement importingLibrary,
35 LibraryElement importedLibrary,
36 Import tag);
37 }
38
39 /**
40 * Implementation class for [LibraryLoader]. The distinction between
41 * [LibraryLoader] and [LibraryLoaderTask] is made to hide internal members from
42 * the [LibraryLoader] interface.
43 */
44 class LibraryLoaderTask extends LibraryLoader {
45 LibraryLoaderTask(Compiler compiler) : super(compiler);
46 String get name => 'LibraryLoader';
8 47
9 final Map<String, LibraryElement> libraryNames = 48 final Map<String, LibraryElement> libraryNames =
10 new Map<String, LibraryElement>(); 49 new Map<String, LibraryElement>();
11 50
12 void scanLibrary(LibraryElement library) { 51 LibraryDependencyHandler currentHandler;
13 var compilationUnit = library.entryCompilationUnit;
14 compiler.log("scanning library ${compilationUnit.script.name}");
15 scan(compilationUnit);
16 processLibraryTags(library);
17 }
18 52
19 void scan(CompilationUnitElement compilationUnit) { 53 LibraryElement loadLibrary(Uri uri, Node node, Uri canonicalUri) {
20 measure(() { 54 return measure(() {
21 scanElements(compilationUnit); 55 assert(currentHandler == null);
56 currentHandler = new LibraryDependencyHandler(compiler);
57 LibraryElement library =
58 createLibrary(currentHandler, uri, node, canonicalUri);
59 currentHandler.computeExports();
60 currentHandler = null;
61 return library;
22 }); 62 });
23 } 63 }
24 64
25 void processLibraryTags(LibraryElement library) { 65 /**
66 * Processes the library tags in [library].
67 *
68 * The imported/exported libraries are loaded and processed recursively but
69 * the import/export scopes are not set up.
70 */
71 void processLibraryTags(LibraryDependencyHandler handler,
72 LibraryElement library) {
26 int tagState = TagState.NO_TAG_SEEN; 73 int tagState = TagState.NO_TAG_SEEN;
27 74
28 /** 75 /**
29 * If [value] is less than [tagState] complain and return 76 * If [value] is less than [tagState] complain and return
30 * [tagState]. Otherwise return the new value for [tagState] 77 * [tagState]. Otherwise return the new value for [tagState]
31 * (transition function for state machine). 78 * (transition function for state machine).
32 */ 79 */
33 int checkTag(int value, LibraryTag tag) { 80 int checkTag(int value, LibraryTag tag) {
34 if (tagState > value) { 81 if (tagState > value) {
35 compiler.reportError(tag, 'out of order'); 82 compiler.reportError(tag, 'out of order');
36 return tagState; 83 return tagState;
37 } 84 }
38 return TagState.NEXT[value]; 85 return TagState.NEXT[value];
39 } 86 }
40 87
41 LinkBuilder<Import> imports = new LinkBuilder<Import>(); 88 bool importsDartCore = false;
89 var libraryDependencies = new LinkBuilder<LibraryDependency>();
42 Uri base = library.entryCompilationUnit.script.uri; 90 Uri base = library.entryCompilationUnit.script.uri;
43 for (LibraryTag tag in library.tags.reverse()) { 91 for (LibraryTag tag in library.tags.reverse()) {
44 if (tag.isImport) { 92 if (tag.isImport) {
45 tagState = checkTag(TagState.IMPORT, tag); 93 tagState = checkTag(TagState.IMPORT_OR_EXPORT, tag);
46 if (tag.combinators != null) { 94 if (tag.combinators != null) {
47 compiler.unimplemented('combinators', node: tag.combinators); 95 compiler.unimplemented('combinators', node: tag.combinators);
48 } 96 }
49 // It is not safe to import other libraries at this point as 97 if (tag.uri.dartString.slowToString() == 'dart:core') {
50 // another library could then observe the current library 98 importsDartCore = true;
51 // before it fully declares all the members that are sourced 99 }
52 // in. 100 libraryDependencies.addLast(tag);
53 imports.addLast(tag); 101 } else if (tag.isExport) {
102 tagState = checkTag(TagState.IMPORT_OR_EXPORT, tag);
103 libraryDependencies.addLast(tag);
54 } else if (tag.isLibraryName) { 104 } else if (tag.isLibraryName) {
55 tagState = checkTag(TagState.LIBRARY, tag); 105 tagState = checkTag(TagState.LIBRARY, tag);
56 if (library.libraryTag !== null) { 106 if (library.libraryTag !== null) {
57 compiler.cancel("duplicated library declaration", node: tag); 107 compiler.cancel("duplicated library declaration", node: tag);
58 } else { 108 } else {
59 library.libraryTag = tag; 109 library.libraryTag = tag;
60 } 110 }
61 checkDuplicatedLibraryName(library); 111 checkDuplicatedLibraryName(library);
62 } else if (tag.isPart) { 112 } else if (tag.isPart) {
63 StringNode uri = tag.uri; 113 StringNode uri = tag.uri;
64 Uri resolved = base.resolve(uri.dartString.slowToString()); 114 Uri resolved = base.resolve(uri.dartString.slowToString());
65 tagState = checkTag(TagState.SOURCE, tag); 115 tagState = checkTag(TagState.SOURCE, tag);
66 loadPart(tag, resolved, library); 116 scanPart(tag, resolved, library);
67 } else { 117 } else {
68 compiler.internalError("Unhandled library tag.", node: tag); 118 compiler.internalError("Unhandled library tag.", node: tag);
69 } 119 }
70 } 120 }
71 121
72 // Apply patch, if any. 122 // Apply patch, if any.
73 if (library.uri.scheme == 'dart') { 123 if (library.uri.scheme == 'dart') {
74 compiler.patchDartLibrary(library, library.uri.path); 124 patchDartLibrary(handler, library, library.uri.path);
75 } 125 }
76 126
77 // Now that we have processed all the source tags, it is safe to 127 // Import dart:core if not already imported.
78 // start loading other libraries. 128 if (!importsDartCore && !isDartCore(library.uri)) {
79 129 handler.registerDependency(library, null, loadCoreLibrary(handler));
80 if (library.uri.scheme != 'dart' || library.uri.path != 'core') {
81 compiler.importCoreLibrary(library);
82 } 130 }
83 131
84 for (Import tag in imports.toLink()) { 132 for (LibraryDependency tag in libraryDependencies.toLink()) {
85 importLibraryFromTag(tag, library.entryCompilationUnit); 133 registerLibraryFromTag(handler, library, tag);
86 } 134 }
87 } 135 }
88 136
89 void checkDuplicatedLibraryName(LibraryElement library) { 137 void checkDuplicatedLibraryName(LibraryElement library) {
90 LibraryTag tag = library.libraryTag; 138 LibraryName tag = library.libraryTag;
91 if (tag != null) { 139 if (tag != null) {
92 String name = library.getLibraryOrScriptName(); 140 String name = library.getLibraryOrScriptName();
93 LibraryElement existing = 141 LibraryElement existing =
94 libraryNames.putIfAbsent(name, () => library); 142 libraryNames.putIfAbsent(name, () => library);
95 if (existing !== library) { 143 if (existing !== library) {
96 Uri uri = library.entryCompilationUnit.script.uri; 144 Uri uri = library.entryCompilationUnit.script.uri;
97 compiler.reportMessage( 145 compiler.reportMessage(
98 compiler.spanFromNode(tag.name, uri), 146 compiler.spanFromNode(tag.name, uri),
99 MessageKind.DUPLICATED_LIBRARY_NAME.error([name]), 147 MessageKind.DUPLICATED_LIBRARY_NAME.error([name]),
100 api_s.Diagnostic.WARNING); 148 api.Diagnostic.WARNING);
101 Uri existingUri = existing.entryCompilationUnit.script.uri; 149 Uri existingUri = existing.entryCompilationUnit.script.uri;
102 compiler.reportMessage( 150 compiler.reportMessage(
103 compiler.spanFromNode(existing.libraryTag.name, existingUri), 151 compiler.spanFromNode(existing.libraryTag.name, existingUri),
104 MessageKind.DUPLICATED_LIBRARY_NAME.error([name]), 152 MessageKind.DUPLICATED_LIBRARY_NAME.error([name]),
105 api_s.Diagnostic.WARNING); 153 api.Diagnostic.WARNING);
106 } 154 }
107 } 155 }
108 } 156 }
109 157
158 bool isDartCore(Uri uri) => uri.scheme == "dart" && uri.path == "core";
159
160 /**
161 * Lazily loads and returns the [LibraryElement] for the dart:core library.
162 */
163 LibraryElement loadCoreLibrary(LibraryDependencyHandler handler) {
164 if (compiler.coreLibrary === null) {
165 Uri coreUri = new Uri.fromComponents(scheme: 'dart', path: 'core');
166 compiler.coreLibrary = createLibrary(handler, coreUri, null, coreUri);
167 }
168 return compiler.coreLibrary;
169 }
170
171 void patchDartLibrary(LibraryDependencyHandler handler,
172 LibraryElement library, String dartLibraryPath) {
173 if (library.isPatched) return;
174 Uri patchUri = compiler.resolvePatchUri(dartLibraryPath);
175 if (patchUri !== null) {
176 compiler.patchParser.patchLibrary(handler, patchUri, library);
177 }
178 }
179
110 /** 180 /**
111 * Handle a part tag in the scope of [library]. The [path] given is used as 181 * Handle a part tag in the scope of [library]. The [path] given is used as
112 * is, any resolution should be done beforehand. 182 * is, any URI resolution should be done beforehand.
113 */ 183 */
114 void loadPart(Part part, Uri path, LibraryElement library) { 184 void scanPart(Part part, Uri path, LibraryElement library) {
115 Script sourceScript = compiler.readScript(path, part.uri); 185 if (!path.isAbsolute()) throw new ArgumentError(path);
186 Script sourceScript = compiler.readScript(path, part);
116 CompilationUnitElement unit = 187 CompilationUnitElement unit =
117 new CompilationUnitElement(sourceScript, library); 188 new CompilationUnitElement(sourceScript, library);
118 compiler.withCurrentElement(unit, () => compiler.scanner.scan(unit)); 189 compiler.withCurrentElement(unit, () => compiler.scanner.scan(unit));
119 } 190 }
120 191
121 /** 192 /**
122 * Handle an import script tag by importing the referenced library into the 193 * Handle an import/export tag by loading the referenced library and
123 * current library. 194 * registering its dependency in [handler] for the computation of the import/
124 * Returns the resolved library [Uri]. 195 * export scope.
125 */ 196 */
126 Uri importLibraryFromTag(Import tag, 197 void registerLibraryFromTag(LibraryDependencyHandler handler,
127 CompilationUnitElement compilationUnit) { 198 LibraryElement library,
128 Uri base = compilationUnit.script.uri; 199 LibraryDependency tag) {
200 Uri base = library.entryCompilationUnit.script.uri;
129 Uri resolved = base.resolve(tag.uri.dartString.slowToString()); 201 Uri resolved = base.resolve(tag.uri.dartString.slowToString());
130 LibraryElement importedLibrary = loadLibrary(resolved, tag.uri, resolved); 202 LibraryElement loadedLibrary =
131 importLibrary(compilationUnit.getLibrary(), 203 createLibrary(handler, resolved, tag.uri, resolved);
132 importedLibrary, 204 handler.registerDependency(library, tag, loadedLibrary);
133 tag, 205
134 compilationUnit); 206 if (!loadedLibrary.hasLibraryName()) {
135 return resolved; 207 compiler.withCurrentElement(library, () {
208 compiler.reportError(tag === null ? null : tag.uri,
209 'no library name found in ${loadedLibrary.uri}');
210 });
211 }
136 } 212 }
137 213
138 void scanElements(CompilationUnitElement compilationUnit) { 214 /**
139 Script script = compilationUnit.script; 215 * Create (or reuse) a library element for the library located at [uri].
140 Token tokens = new StringScanner(script.text).tokenize(); 216 * If a new library is created, the [handler] is notified.
141 compiler.dietParser.dietParse(compilationUnit, tokens); 217 */
142 } 218 LibraryElement createLibrary(LibraryDependencyHandler handler,
143 219 Uri uri, Node node, Uri canonicalUri) {
144 LibraryElement loadLibrary(Uri uri, Node node, Uri canonicalUri) {
145 bool newLibrary = false; 220 bool newLibrary = false;
146 LibraryElement createLibrary() { 221 LibraryElement createLibrary() {
147 newLibrary = true; 222 newLibrary = true;
148 Script script = compiler.readScript(uri, node); 223 Script script = compiler.readScript(uri, node);
149 LibraryElement element = new LibraryElement(script, canonicalUri); 224 LibraryElement element = new LibraryElement(script, canonicalUri);
225 handler.registerNewLibrary(element);
150 native.maybeEnableNative(compiler, element, uri); 226 native.maybeEnableNative(compiler, element, uri);
151 return element; 227 return element;
152 } 228 }
153 LibraryElement library; 229 LibraryElement library;
154 if (canonicalUri === null) { 230 if (canonicalUri === null) {
155 library = createLibrary(); 231 library = createLibrary();
156 } else { 232 } else {
157 library = compiler.libraries.putIfAbsent(canonicalUri.toString(), 233 library = compiler.libraries.putIfAbsent(canonicalUri.toString(),
158 createLibrary); 234 createLibrary);
159 } 235 }
160 if (newLibrary) { 236 if (newLibrary) {
161 compiler.withCurrentElement(library, () { 237 compiler.withCurrentElement(library, () {
162 scanLibrary(library); 238 compiler.scanner.scanLibrary(library);
163 compiler.onLibraryLoaded(library, uri); 239 processLibraryTags(handler, library);
240 handler.registerLibraryExports(library);
241 compiler.onLibraryScanned(library, uri);
164 }); 242 });
165 } 243 }
166 return library; 244 return library;
167 } 245 }
168 246
169 void importLibrary(LibraryElement library, LibraryElement imported, 247 // TODO(johnniwinther): Remove this method when 'js_helper' is handled by
170 Import tag, [CompilationUnitElement compilationUnit]) { 248 // [LibraryLoaderTask].
171 if (!imported.hasLibraryName()) { 249 void importLibrary(LibraryElement importingLibrary,
172 compiler.withCurrentElement(library, () { 250 LibraryElement importedLibrary,
173 compiler.reportError(tag === null ? null : tag.uri, 251 Import tag) {
174 'no #library tag found in ${imported.uri}'); 252 new ImportLink(tag, importedLibrary).importLibrary(compiler,
175 }); 253 importingLibrary);
176 } 254 }
177 if (tag !== null && tag.prefix !== null) { 255 }
178 SourceString prefix = tag.prefix.source; 256
179 Element e = library.find(prefix);
180 if (e === null) {
181 if (compilationUnit === null) {
182 compilationUnit = library.entryCompilationUnit;
183 }
184 e = new PrefixElement(prefix, compilationUnit, tag.getBeginToken());
185 library.addToScope(e, compiler);
186 }
187 if (e.kind !== ElementKind.PREFIX) {
188 compiler.withCurrentElement(e, () {
189 compiler.reportWarning(new Identifier(e.position()),
190 'duplicated definition');
191 });
192 compiler.reportError(tag.prefix, 'duplicate defintion');
193 }
194 PrefixElement prefixElement = e;
195 imported.forEachExport((Element element) {
196 Element existing =
197 prefixElement.imported.putIfAbsent(element.name, () => element);
198 if (existing !== element) {
199 compiler.withCurrentElement(existing, () {
200 compiler.reportWarning(new Identifier(existing.position()),
201 'duplicated import');
202 });
203 compiler.withCurrentElement(element, () {
204 compiler.reportError(new Identifier(element.position()),
205 'duplicated import');
206 });
207 }
208 });
209 } else {
210 imported.forEachExport((Element element) {
211 compiler.withCurrentElement(element, () {
212 library.addImport(element, compiler);
213 });
214 });
215 }
216 }
217 }
218
219 class DietParserTask extends CompilerTask {
220 DietParserTask(Compiler compiler) : super(compiler);
221 final String name = 'Diet Parser';
222
223 dietParse(CompilationUnitElement compilationUnit, Token tokens) {
224 measure(() {
225 Function idGenerator = compiler.getNextFreeClassId;
226 ElementListener listener =
227 new ElementListener(compiler, compilationUnit, idGenerator);
228 PartialParser parser = new PartialParser(listener);
229 parser.parseUnit(tokens);
230 });
231 }
232 }
233 257
234 /** 258 /**
235 * The fields of this class models a state machine for checking script 259 * The fields of this class models a state machine for checking script
236 * tags come in the correct order. 260 * tags come in the correct order.
237 */ 261 */
238 class TagState { 262 class TagState {
239 static const int NO_TAG_SEEN = 0; 263 static const int NO_TAG_SEEN = 0;
240 static const int LIBRARY = 1; 264 static const int LIBRARY = 1;
241 static const int IMPORT = 2; 265 static const int IMPORT_OR_EXPORT = 2;
242 static const int SOURCE = 3; 266 static const int SOURCE = 3;
243 static const int RESOURCE = 4; 267 static const int RESOURCE = 4;
244 268
245 /** Next state. */ 269 /** Next state. */
246 static const List<int> NEXT = 270 static const List<int> NEXT =
247 const <int>[NO_TAG_SEEN, 271 const <int>[NO_TAG_SEEN,
248 IMPORT, // Only one library tag is allowed. 272 IMPORT_OR_EXPORT, // Only one library tag is allowed.
249 IMPORT, 273 IMPORT_OR_EXPORT,
250 SOURCE, 274 SOURCE,
251 RESOURCE]; 275 RESOURCE];
252 } 276 }
277
278 /**
279 * An [import] tag and the [importedLibrary] imported through [import].
280 */
281 class ImportLink {
282 final Import import;
283 final LibraryElement importedLibrary;
284
285 ImportLink(this.import, this.importedLibrary);
286
287 /**
288 * Imports the library into the [importingLibrary].
289 */
290 void importLibrary(Compiler compiler, LibraryElement importingLibrary) {
291 assert(invariant(importingLibrary,
292 importedLibrary.exportsHandled,
293 message: 'Exports not handled on $importedLibrary'));
294 if (import !== null && import.prefix !== null) {
295 SourceString prefix = import.prefix.source;
296 Element e = importingLibrary.find(prefix);
297 if (e === null) {
298 e = new PrefixElement(prefix, importingLibrary.entryCompilationUnit,
299 import.getBeginToken());
300 importingLibrary.addToScope(e, compiler);
301 }
302 if (e.kind !== ElementKind.PREFIX) {
303 compiler.withCurrentElement(e, () {
304 compiler.reportWarning(new Identifier(e.position()),
305 'duplicated definition');
306 });
307 compiler.reportError(import.prefix, 'duplicate definition');
308 }
309 PrefixElement prefixElement = e;
310 importedLibrary.forEachExport((Element element) {
311 // TODO(johnniwinther): Handle show and hide combinators.
312 // TODO(johnniwinther): Clean-up like [checkDuplicateLibraryName].
313 Element existing =
314 prefixElement.imported.putIfAbsent(element.name, () => element);
315 if (existing !== element) {
316 compiler.withCurrentElement(existing, () {
317 compiler.reportWarning(new Identifier(existing.position()),
318 'duplicated import');
319 });
320 compiler.withCurrentElement(element, () {
321 compiler.reportError(new Identifier(element.position()),
322 'duplicated import');
323 });
324 }
325 });
326 } else {
327 importedLibrary.forEachExport((Element element) {
328 compiler.withCurrentElement(element, () {
329 // TODO(johnniwinther): Handle show and hide combinators.
330 importingLibrary.addImport(element, compiler);
331 });
332 });
333 }
334 }
335 }
336
337 /**
338 * A node in the library dependency graph.
339 *
340 * This class is used to collect the library dependencies expressed through
341 * import and export tags, and as the work-list entry in computations of library
342 * exports performed in [LibraryDependencyHandler.computeExports].
343 */
344 class LibraryDependencyNode {
345 final LibraryElement library;
346
347 /**
348 * A linked list of the import tags that import [library] mapped to the
349 * corresponding libraries. This is used to propagate exports into imports
350 * after the export scopes have been computed.
351 */
352 Link<ImportLink> imports = const EmptyLink<ImportLink>();
353
354 /**
355 * The export tags that export [library] mapped to the nodes for the libraries
356 * that declared each export tag. This is used to propagete exports during the
357 * computation of export scopes.
358 */
359 Map<Export, LibraryDependencyNode> dependencyMap =
360 new Map<Export, LibraryDependencyNode>();
361
362 /**
363 * The export scope for [library] which is gradually computed by the work-list
364 * computation in [LibraryDependencyHandler.computeExports].
365 */
366 Map<SourceString, Element> exportScope = new Map<SourceString, Element>();
367
368 /**
369 * The set of exported elements that need to be propageted to dependent
370 * libraries as part of the work-list computation performed in
371 * [LibraryDependencyHandler.computeExports].
372 */
373 Set<Element> pendingExportSet = new Set<Element>();
374
375 LibraryDependencyNode(LibraryElement this.library);
376
377 /**
378 * Registers that the library of this node imports [importLibrary] through the
379 * [import] tag.
380 */
381 void registerImportDependency(Import import,
382 LibraryElement importedLibrary) {
383 imports = imports.prepend(new ImportLink(import, importedLibrary));
384 }
385
386 /**
387 * Registers that the library of this node is exported by
388 * [exportingLibraryNode] through the [export] tag.
389 */
390 void registerExportDependency(Export export,
391 LibraryDependencyNode exportingLibraryNode) {
392 dependencyMap[export] = exportingLibraryNode;
393 }
394
395 /**
396 * Registers all non-private locally declared members of the library of this
397 * node to be exported. This forms the basis for the work-list computation of
398 * the export scopes performed in [LibraryDependencyHandler.computeExports].
399 */
400 void registerInitialExports() {
401 pendingExportSet.addAll(
402 library.localScope.getValues().filter((Element element) {
403 // At this point [localScope] only contains members so we don't need
404 // to check for foreign or prefix elements.
405 return !element.name.isPrivate();
406 }));
407 }
408
409 /**
410 * Registers the compute export scope with the node library.
411 */
412 void registerExports() {
413 library.setExports(exportScope.getValues());
414 }
415
416 /**
417 * Registers the imports of the node library.
418 */
419 void registerImports(Compiler compiler) {
420 for (ImportLink link in imports) {
421 link.importLibrary(compiler, library);
422 }
423 }
424
425 /**
426 * Copies and clears pending export set for this node.
427 */
428 List<Element> pullPendingExports() {
429 List<Element> pendingExports = new List.from(pendingExportSet);
430 pendingExportSet.clear();
431 return pendingExports;
432 }
433
434 /**
435 * Adds [element] to the export scope for this node. If the [element] name
436 * is a duplicate, an error element is inserted into the exscope.
437 */
438 Element addElementToExportScope(Compiler compiler, Element element) {
439 SourceString name = element.name;
440 Element existingElement = exportScope[name];
441 if (existingElement !== null) {
442 if (existingElement.getLibrary() != library) {
443 // Declared elements hide exported elements.
444 element = exportScope[name] = new ErroneousElement(
445 MessageKind.DUPLICATE_EXPORT, [name], name, library);
446 }
447 } else {
448 exportScope[name] = element;
449 }
450 return element;
451 }
452
453 /**
454 * Propagates the exported [element] to all library nodes that depend upon
455 * this node. If the propagation updated any pending exports, [:true:] is
456 * returned.
457 */
458 bool propagateElement(Element element) {
459 bool change = false;
460 dependencyMap.forEach((Export export, LibraryDependencyNode exportNode) {
461 if (exportNode.addElementToPendingExports(export, element)) {
462 change = true;
463 }
464 });
465 return change;
466 }
467
468 /**
469 * Adds [element] to the pending exports of this node and returns [:true:] if
470 * the pending export set was modified. The combinators of [export] are used
471 * to filter the element.
472 */
473 bool addElementToPendingExports(Export export, Element element) {
474 // TODO(johnniwinther): Use [export] to handle show and hide combinators.
475 if (exportScope[element.name] !== element) {
476 if (!pendingExportSet.contains(element)) {
477 pendingExportSet.add(element);
478 return true;
479 }
480 }
481 return false;
482 }
483 }
484
485 /**
486 * Helper class used for computing the possibly cyclic import/export scopes of
487 * a set of libraries.
488 *
489 * This class is used by [ScannerTask.loadLibrary] to collect all newly loaded
490 * libraries and to compute their import/export scopes through a fixed-point
491 * algorithm.
492 */
493 class LibraryDependencyHandler {
494 final Compiler compiler;
495
496 /**
497 * Newly loaded libraries and their corresponding node in the library
498 * dependency graph. Libraries that have already been fully loaded are not
499 * part of the dependency graph of this handler since their export scopes have
500 * already been computed.
501 */
502 Map<LibraryElement,LibraryDependencyNode> nodeMap =
503 new Map<LibraryElement,LibraryDependencyNode>();
504
505 LibraryDependencyHandler(Compiler this.compiler);
506
507 /**
508 * Performs a fixed-point computation on the export scopes of all registered
509 * libraries and creates the import/export of the libraries based on the
510 * fixed-point.
511 */
512 void computeExports() {
513 bool changed = true;
514 while (changed) {
515 changed = false;
516 nodeMap.forEach((_, LibraryDependencyNode node) {
517 var pendingExports = node.pullPendingExports();
518 pendingExports.forEach((Element element) {
519 element = node.addElementToExportScope(compiler, element);
520 if (node.propagateElement(element)) {
521 changed = true;
522 }
523 });
524 });
525 }
526
527 // Setup export scopes. These have to be set before computing the import
528 // scopes to avoid accessing uncomputed export scopes during handling of
529 // imports.
530 nodeMap.forEach((LibraryElement library, LibraryDependencyNode node) {
531 node.registerExports();
532 });
533
534 // Setup import scopes.
535 nodeMap.forEach((LibraryElement library, LibraryDependencyNode node) {
536 node.registerImports(compiler);
537 });
538 }
539
540 /**
541 * Registers that [library] depends on [loadedLibrary] through [tag].
542 */
543 void registerDependency(LibraryElement library,
544 LibraryDependency tag,
545 LibraryElement loadedLibrary) {
546 if (tag is Export) {
547 // [loadedLibrary] is exported by [library].
548 if (loadedLibrary.exportsHandled) {
549 // Export scope already computed on [loadedLibrary].
550 return;
551 }
552 LibraryDependencyNode exportedNode = nodeMap[loadedLibrary];
553 LibraryDependencyNode exportingNode = nodeMap[library];
554 assert(invariant(loadedLibrary, exportedNode != null,
555 message: "$loadedLibrary has not been registered"));
556 assert(invariant(library, exportingNode != null,
557 message: "$library has not been registered"));
558 exportedNode.registerExportDependency(tag, exportingNode);
559 } else if (tag == null || tag is Import) {
560 // [loadedLibrary] is imported by [library].
561 LibraryDependencyNode importingNode = nodeMap[library];
562 assert(invariant(library, importingNode != null,
563 message: "$library has not been registered"));
564 importingNode.registerImportDependency(tag, loadedLibrary);
565 }
566 }
567
568 /**
569 * Registers [library] for the processing of its import/export scope.
570 */
571 void registerNewLibrary(LibraryElement library) {
572 nodeMap[library] = new LibraryDependencyNode(library);
573 }
574
575 /**
576 * Registers all top-level entities of [library] as starting point for the
577 * fixed-point computation of the import/export scopes.
578 */
579 void registerLibraryExports(LibraryElement library) {
580 nodeMap[library].registerInitialExports();
581 }
582 }
OLDNEW
« no previous file with comments | « lib/compiler/implementation/leg.dart ('k') | lib/compiler/implementation/patch_parser.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698