Chromium Code Reviews| 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 |
|
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 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 (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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |