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

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

Powered by Google App Engine
This is Rietveld 408576698