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

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

Issue 11087073: Show and hide combinators supported. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Status updated. 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 | « no previous file | tests/co19/co19-dart2dart.status » ('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 /** 5 /**
6 * [CompilerTask] for loading libraries and setting up the import/export scopes. 6 * [CompilerTask] for loading libraries and setting up the import/export scopes.
7 */ 7 */
8 abstract class LibraryLoader extends CompilerTask { 8 abstract class LibraryLoader extends CompilerTask {
9 LibraryLoader(Compiler compiler) : super(compiler); 9 LibraryLoader(Compiler compiler) : super(compiler);
10 10
(...skipping 19 matching lines...) Expand all
30 * scope of [importingLibrary]. 30 * scope of [importingLibrary].
31 */ 31 */
32 // TODO(johnniwinther): Move handling of 'js_helper' to the library loader 32 // TODO(johnniwinther): Move handling of 'js_helper' to the library loader
33 // to remove this method from the [LibraryLoader] interface. 33 // to remove this method from the [LibraryLoader] interface.
34 abstract void importLibrary(LibraryElement importingLibrary, 34 abstract void importLibrary(LibraryElement importingLibrary,
35 LibraryElement importedLibrary, 35 LibraryElement importedLibrary,
36 Import tag); 36 Import tag);
37 } 37 }
38 38
39 /** 39 /**
40 * [CombinatorFilter] is a succinct representation of a list of combinators from
41 * a library dependency tag.
42 */
43 class CombinatorFilter {
44 const CombinatorFilter();
45
46 /**
47 * Returns [:true:] if [element] is excluded by this filter.
48 */
49 bool exclude(Element element) => false;
50
51 /**
52 * Creates a filter based on the combinators of [tag].
53 */
54 factory CombinatorFilter.fromTag(LibraryDependency tag) {
55 if (tag == null || tag.combinators == null) {
56 return const CombinatorFilter();
57 }
58
59 // If the list of combinators contain at least one [:show:] we can create
60 // a positive list of elements to include, otherwise we create a negative
61 // list of elements to exclude.
62 bool show = false;
63 Set<SourceString> nameSet;
64 for (Combinator combinator in tag.combinators) {
65 if (combinator.isShow) {
66 show = true;
67 var set = new Set<SourceString>();
68 for (Identifier identifier in combinator.identifiers) {
69 set.add(identifier.source);
70 }
71 if (nameSet == null) {
72 nameSet = set;
73 } else {
74 nameSet = nameSet.intersection(set);
75 }
76 }
77 }
78 if (nameSet == null) {
79 nameSet = new Set<SourceString>();
80 }
81 for (Combinator combinator in tag.combinators) {
82 if (combinator.isHide) {
83 for (Identifier identifier in combinator.identifiers) {
84 if (show) {
85 // We have a positive list => Remove hidden elements.
86 nameSet.remove(identifier.source);
87 } else {
88 // We have no positive list => Accumulate hidden elements.
89 nameSet.add(identifier.source);
90 }
91 }
92 }
93 }
94 return show ? new ShowFilter(nameSet) : new HideFilter(nameSet);
95 }
96 }
97
98 /**
99 * A list of combinators represented as a list of element names to include.
100 */
101 class ShowFilter extends CombinatorFilter {
102 final Set<SourceString> includedNames;
103
104 ShowFilter(this.includedNames);
105
106 bool exclude(Element element) => !includedNames.contains(element.name);
107 }
108
109 /**
110 * A list of combinators represented as a list of element names to exclude.
111 */
112 class HideFilter extends CombinatorFilter {
113 final Set<SourceString> excludedNames;
114
115 HideFilter(this.excludedNames);
116
117 bool exclude(Element element) => excludedNames.contains(element.name);
118 }
119
120 /**
40 * Implementation class for [LibraryLoader]. The distinction between 121 * Implementation class for [LibraryLoader]. The distinction between
41 * [LibraryLoader] and [LibraryLoaderTask] is made to hide internal members from 122 * [LibraryLoader] and [LibraryLoaderTask] is made to hide internal members from
42 * the [LibraryLoader] interface. 123 * the [LibraryLoader] interface.
43 */ 124 */
44 class LibraryLoaderTask extends LibraryLoader { 125 class LibraryLoaderTask extends LibraryLoader {
45 LibraryLoaderTask(Compiler compiler) : super(compiler); 126 LibraryLoaderTask(Compiler compiler) : super(compiler);
46 String get name => 'LibraryLoader'; 127 String get name => 'LibraryLoader';
47 128
48 final Map<String, LibraryElement> libraryNames = 129 final Map<String, LibraryElement> libraryNames =
49 new Map<String, LibraryElement>(); 130 new Map<String, LibraryElement>();
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 } 165 }
85 return TagState.NEXT[value]; 166 return TagState.NEXT[value];
86 } 167 }
87 168
88 bool importsDartCore = false; 169 bool importsDartCore = false;
89 var libraryDependencies = new LinkBuilder<LibraryDependency>(); 170 var libraryDependencies = new LinkBuilder<LibraryDependency>();
90 Uri base = library.entryCompilationUnit.script.uri; 171 Uri base = library.entryCompilationUnit.script.uri;
91 for (LibraryTag tag in library.tags.reverse()) { 172 for (LibraryTag tag in library.tags.reverse()) {
92 if (tag.isImport) { 173 if (tag.isImport) {
93 tagState = checkTag(TagState.IMPORT_OR_EXPORT, tag); 174 tagState = checkTag(TagState.IMPORT_OR_EXPORT, tag);
94 if (tag.combinators != null) {
95 compiler.unimplemented('combinators', node: tag.combinators);
96 }
97 if (tag.uri.dartString.slowToString() == 'dart:core') { 175 if (tag.uri.dartString.slowToString() == 'dart:core') {
98 importsDartCore = true; 176 importsDartCore = true;
99 } 177 }
100 libraryDependencies.addLast(tag); 178 libraryDependencies.addLast(tag);
101 } else if (tag.isExport) { 179 } else if (tag.isExport) {
102 tagState = checkTag(TagState.IMPORT_OR_EXPORT, tag); 180 tagState = checkTag(TagState.IMPORT_OR_EXPORT, tag);
103 libraryDependencies.addLast(tag); 181 libraryDependencies.addLast(tag);
104 } else if (tag.isLibraryName) { 182 } else if (tag.isLibraryName) {
105 tagState = checkTag(TagState.LIBRARY, tag); 183 tagState = checkTag(TagState.LIBRARY, tag);
106 if (library.libraryTag !== null) { 184 if (library.libraryTag !== null) {
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
284 362
285 ImportLink(this.import, this.importedLibrary); 363 ImportLink(this.import, this.importedLibrary);
286 364
287 /** 365 /**
288 * Imports the library into the [importingLibrary]. 366 * Imports the library into the [importingLibrary].
289 */ 367 */
290 void importLibrary(Compiler compiler, LibraryElement importingLibrary) { 368 void importLibrary(Compiler compiler, LibraryElement importingLibrary) {
291 assert(invariant(importingLibrary, 369 assert(invariant(importingLibrary,
292 importedLibrary.exportsHandled, 370 importedLibrary.exportsHandled,
293 message: 'Exports not handled on $importedLibrary')); 371 message: 'Exports not handled on $importedLibrary'));
372 var combinatorFilter = new CombinatorFilter.fromTag(import);
294 if (import !== null && import.prefix !== null) { 373 if (import !== null && import.prefix !== null) {
295 SourceString prefix = import.prefix.source; 374 SourceString prefix = import.prefix.source;
296 Element e = importingLibrary.find(prefix); 375 Element e = importingLibrary.find(prefix);
297 if (e === null) { 376 if (e === null) {
298 e = new PrefixElement(prefix, importingLibrary.entryCompilationUnit, 377 e = new PrefixElement(prefix, importingLibrary.entryCompilationUnit,
299 import.getBeginToken()); 378 import.getBeginToken());
300 importingLibrary.addToScope(e, compiler); 379 importingLibrary.addToScope(e, compiler);
301 } 380 }
302 if (e.kind !== ElementKind.PREFIX) { 381 if (e.kind !== ElementKind.PREFIX) {
303 compiler.withCurrentElement(e, () { 382 compiler.withCurrentElement(e, () {
304 compiler.reportWarning(new Identifier(e.position()), 383 compiler.reportWarning(new Identifier(e.position()),
305 'duplicated definition'); 384 'duplicated definition');
306 }); 385 });
307 compiler.reportError(import.prefix, 'duplicate definition'); 386 compiler.reportError(import.prefix, 'duplicate definition');
308 } 387 }
309 PrefixElement prefixElement = e; 388 PrefixElement prefixElement = e;
310 importedLibrary.forEachExport((Element element) { 389 importedLibrary.forEachExport((Element element) {
311 // TODO(johnniwinther): Handle show and hide combinators. 390 if (combinatorFilter.exclude(element)) return;
312 // TODO(johnniwinther): Clean-up like [checkDuplicateLibraryName]. 391 // TODO(johnniwinther): Clean-up like [checkDuplicateLibraryName].
313 Element existing = 392 Element existing =
314 prefixElement.imported.putIfAbsent(element.name, () => element); 393 prefixElement.imported.putIfAbsent(element.name, () => element);
315 if (existing !== element) { 394 if (existing !== element) {
316 compiler.withCurrentElement(existing, () { 395 compiler.withCurrentElement(existing, () {
317 compiler.reportWarning(new Identifier(existing.position()), 396 compiler.reportWarning(new Identifier(existing.position()),
318 'duplicated import'); 397 'duplicated import');
319 }); 398 });
320 compiler.withCurrentElement(element, () { 399 compiler.withCurrentElement(element, () {
321 compiler.reportError(new Identifier(element.position()), 400 compiler.reportError(new Identifier(element.position()),
322 'duplicated import'); 401 'duplicated import');
323 }); 402 });
324 } 403 }
325 }); 404 });
326 } else { 405 } else {
327 importedLibrary.forEachExport((Element element) { 406 importedLibrary.forEachExport((Element element) {
328 compiler.withCurrentElement(element, () { 407 compiler.withCurrentElement(element, () {
329 // TODO(johnniwinther): Handle show and hide combinators. 408 if (combinatorFilter.exclude(element)) return;
330 importingLibrary.addImport(element, compiler); 409 importingLibrary.addImport(element, compiler);
331 }); 410 });
332 }); 411 });
333 } 412 }
334 } 413 }
335 } 414 }
336 415
337 /** 416 /**
417 * The combinator filter computed from an export tag and the library dependency
418 * node for the library that declared the export tag. This represents an edge in
419 * the library dependency graph.
420 */
421 class ExportLink {
422 final CombinatorFilter combinatorFilter;
423 final LibraryDependencyNode exportNode;
424
425 ExportLink(Export export, LibraryDependencyNode this.exportNode)
426 : this.combinatorFilter = new CombinatorFilter.fromTag(export);
427
428 /**
429 * Exports [element] to the dependent library unless [element] is filtered by
430 * the export combinators. Returns [:true:] if the set pending exports of the
431 * dependent library was modified.
432 */
433 bool exportElement(Element element) {
434 if (combinatorFilter.exclude(element)) return false;
435 return exportNode.addElementToPendingExports(element);
436 }
437 }
438
439 /**
338 * A node in the library dependency graph. 440 * A node in the library dependency graph.
339 * 441 *
340 * This class is used to collect the library dependencies expressed through 442 * 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 443 * import and export tags, and as the work-list entry in computations of library
342 * exports performed in [LibraryDependencyHandler.computeExports]. 444 * exports performed in [LibraryDependencyHandler.computeExports].
343 */ 445 */
344 class LibraryDependencyNode { 446 class LibraryDependencyNode {
345 final LibraryElement library; 447 final LibraryElement library;
346 448
347 /** 449 /**
348 * A linked list of the import tags that import [library] mapped to the 450 * A linked list of the import tags that import [library] mapped to the
349 * corresponding libraries. This is used to propagate exports into imports 451 * corresponding libraries. This is used to propagate exports into imports
350 * after the export scopes have been computed. 452 * after the export scopes have been computed.
351 */ 453 */
352 Link<ImportLink> imports = const EmptyLink<ImportLink>(); 454 Link<ImportLink> imports = const EmptyLink<ImportLink>();
353 455
354 /** 456 /**
355 * The export tags that export [library] mapped to the nodes for the libraries 457 * A linked list of the export tags the dependent upon this node library.
356 * that declared each export tag. This is used to propagete exports during the 458 * This is used to propagate exports during the computation of export scopes.
357 * computation of export scopes.
358 */ 459 */
359 Map<Export, LibraryDependencyNode> dependencyMap = 460 Link<ExportLink> dependencies = const EmptyLink<ExportLink>();
360 new Map<Export, LibraryDependencyNode>();
361 461
362 /** 462 /**
363 * The export scope for [library] which is gradually computed by the work-list 463 * The export scope for [library] which is gradually computed by the work-list
364 * computation in [LibraryDependencyHandler.computeExports]. 464 * computation in [LibraryDependencyHandler.computeExports].
365 */ 465 */
366 Map<SourceString, Element> exportScope = new Map<SourceString, Element>(); 466 Map<SourceString, Element> exportScope = new Map<SourceString, Element>();
367 467
368 /** 468 /**
369 * The set of exported elements that need to be propageted to dependent 469 * The set of exported elements that need to be propageted to dependent
370 * libraries as part of the work-list computation performed in 470 * libraries as part of the work-list computation performed in
(...skipping 11 matching lines...) Expand all
382 LibraryElement importedLibrary) { 482 LibraryElement importedLibrary) {
383 imports = imports.prepend(new ImportLink(import, importedLibrary)); 483 imports = imports.prepend(new ImportLink(import, importedLibrary));
384 } 484 }
385 485
386 /** 486 /**
387 * Registers that the library of this node is exported by 487 * Registers that the library of this node is exported by
388 * [exportingLibraryNode] through the [export] tag. 488 * [exportingLibraryNode] through the [export] tag.
389 */ 489 */
390 void registerExportDependency(Export export, 490 void registerExportDependency(Export export,
391 LibraryDependencyNode exportingLibraryNode) { 491 LibraryDependencyNode exportingLibraryNode) {
392 dependencyMap[export] = exportingLibraryNode; 492 dependencies =
493 dependencies.prepend(new ExportLink(export, exportingLibraryNode));
393 } 494 }
394 495
395 /** 496 /**
396 * Registers all non-private locally declared members of the library of this 497 * 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 498 * node to be exported. This forms the basis for the work-list computation of
398 * the export scopes performed in [LibraryDependencyHandler.computeExports]. 499 * the export scopes performed in [LibraryDependencyHandler.computeExports].
399 */ 500 */
400 void registerInitialExports() { 501 void registerInitialExports() {
401 pendingExportSet.addAll( 502 pendingExportSet.addAll(
402 library.localScope.getValues().filter((Element element) { 503 library.localScope.getValues().filter((Element element) {
(...skipping 23 matching lines...) Expand all
426 * Copies and clears pending export set for this node. 527 * Copies and clears pending export set for this node.
427 */ 528 */
428 List<Element> pullPendingExports() { 529 List<Element> pullPendingExports() {
429 List<Element> pendingExports = new List.from(pendingExportSet); 530 List<Element> pendingExports = new List.from(pendingExportSet);
430 pendingExportSet.clear(); 531 pendingExportSet.clear();
431 return pendingExports; 532 return pendingExports;
432 } 533 }
433 534
434 /** 535 /**
435 * Adds [element] to the export scope for this node. If the [element] name 536 * 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. 537 * is a duplicate, an error element is inserted into the export scope.
437 */ 538 */
438 Element addElementToExportScope(Compiler compiler, Element element) { 539 Element addElementToExportScope(Compiler compiler, Element element) {
439 SourceString name = element.name; 540 SourceString name = element.name;
440 Element existingElement = exportScope[name]; 541 Element existingElement = exportScope[name];
441 if (existingElement !== null) { 542 if (existingElement !== null) {
442 if (existingElement.getLibrary() != library) { 543 if (existingElement.getLibrary() != library) {
443 // Declared elements hide exported elements. 544 // Declared elements hide exported elements.
444 element = exportScope[name] = new ErroneousElement( 545 element = exportScope[name] = new ErroneousElement(
445 MessageKind.DUPLICATE_EXPORT, [name], name, library); 546 MessageKind.DUPLICATE_EXPORT, [name], name, library);
446 } 547 }
447 } else { 548 } else {
448 exportScope[name] = element; 549 exportScope[name] = element;
449 } 550 }
450 return element; 551 return element;
451 } 552 }
452 553
453 /** 554 /**
454 * Propagates the exported [element] to all library nodes that depend upon 555 * Propagates the exported [element] to all library nodes that depend upon
455 * this node. If the propagation updated any pending exports, [:true:] is 556 * this node. If the propagation updated any pending exports, [:true:] is
456 * returned. 557 * returned.
457 */ 558 */
458 bool propagateElement(Element element) { 559 bool propagateElement(Element element) {
459 bool change = false; 560 bool change = false;
460 dependencyMap.forEach((Export export, LibraryDependencyNode exportNode) { 561 for (ExportLink link in dependencies) {
461 if (exportNode.addElementToPendingExports(export, element)) { 562 if (link.exportElement(element)) {
462 change = true; 563 change = true;
463 } 564 }
464 }); 565 }
465 return change; 566 return change;
466 } 567 }
467 568
468 /** 569 /**
469 * Adds [element] to the pending exports of this node and returns [:true:] if 570 * 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 571 * the pending export set was modified. The combinators of [export] are used
471 * to filter the element. 572 * to filter the element.
472 */ 573 */
473 bool addElementToPendingExports(Export export, Element element) { 574 bool addElementToPendingExports(Element element) {
474 // TODO(johnniwinther): Use [export] to handle show and hide combinators.
475 if (exportScope[element.name] !== element) { 575 if (exportScope[element.name] !== element) {
476 if (!pendingExportSet.contains(element)) { 576 if (!pendingExportSet.contains(element)) {
477 pendingExportSet.add(element); 577 pendingExportSet.add(element);
478 return true; 578 return true;
479 } 579 }
480 } 580 }
481 return false; 581 return false;
482 } 582 }
483 } 583 }
484 584
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
573 } 673 }
574 674
575 /** 675 /**
576 * Registers all top-level entities of [library] as starting point for the 676 * Registers all top-level entities of [library] as starting point for the
577 * fixed-point computation of the import/export scopes. 677 * fixed-point computation of the import/export scopes.
578 */ 678 */
579 void registerLibraryExports(LibraryElement library) { 679 void registerLibraryExports(LibraryElement library) {
580 nodeMap[library].registerInitialExports(); 680 nodeMap[library].registerInitialExports();
581 } 681 }
582 } 682 }
OLDNEW
« no previous file with comments | « no previous file | tests/co19/co19-dart2dart.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698