| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |