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