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 part of dart2js; | 5 part of dart2js; |
6 | 6 |
7 /** | 7 /** |
8 * [CompilerTask] for loading libraries and setting up the import/export scopes. | 8 * [CompilerTask] for loading libraries and setting up the import/export scopes. |
| 9 * |
| 10 * The library loader uses four different kinds of URIs in different parts of |
| 11 * the loading process. |
| 12 * |
| 13 * ## User URI ## |
| 14 * |
| 15 * A 'user URI' is a URI provided by the user in code and as the main entry URI |
| 16 * at the command line. These generally come in 3 versions: |
| 17 * |
| 18 * * A relative URI such as 'foo.dart', '../bar.dart', and 'baz/boz.dart'. |
| 19 * |
| 20 * * A dart URI such as 'dart:core' and 'dart:_js_helper'. |
| 21 * |
| 22 * * A package URI such as 'package:foo.dart' and 'package:bar/baz.dart'. |
| 23 * |
| 24 * A user URI can also be absolute, like 'file:///foo.dart' or |
| 25 * 'http://example.com/bar.dart', but such URIs cannot necessarily be used for |
| 26 * locating source files, since the scheme must be supported by the input |
| 27 * provider. The standard input provider for dart2js only supports the 'file' |
| 28 * scheme. |
| 29 * |
| 30 * ## Resolved URI ## |
| 31 * |
| 32 * A 'resolved URI' is a (user) URI that has been resolved to an absolute URI |
| 33 * based on the readable URI (see below) from which it was loaded. A URI with an |
| 34 * explicit scheme (such as 'dart:', 'package:' or 'file:') is already resolved. |
| 35 * A relative URI like for instance '../foo/bar.dart' is translated into an |
| 36 * resolved URI in one of three ways: |
| 37 * |
| 38 * * If provided as the main entry URI at the command line, the URI is resolved |
| 39 * relative to the current working directory, say |
| 40 * 'file:///current/working/dir/', and the resolved URI is therefore |
| 41 * 'file:///current/working/foo/bar.dart'. |
| 42 * |
| 43 * * If the relative URI is provided in an import, export or part tag, and the |
| 44 * readable URI of the enclosing compilation unit is a file URI, |
| 45 * 'file://some/path/baz.dart', then the resolved URI is |
| 46 * 'file://some/foo/bar.dart'. |
| 47 * |
| 48 * * If the relative URI is provided in an import, export or part tag, and the |
| 49 * readable URI of the enclosing compilation unit is a package URI, |
| 50 * 'package:some/path/baz.dart', then the resolved URI is |
| 51 * 'package:some/foo/bar.dart'. |
| 52 * |
| 53 * The resolved URI thus preserves the scheme through resolution: A readable |
| 54 * file URI results in an resolved file URI and a readable package URI results |
| 55 * in an resolved package URI. Note that since a dart URI is not a readable URI, |
| 56 * import, export or part tags within platform libraries are not interpreted as |
| 57 * dart URIs but instead relative to the library source file location. |
| 58 * |
| 59 * The resolved URI of a library is also used as the canonical URI |
| 60 * ([LibraryElement.canonicalUri]) by which we identify which libraries are |
| 61 * identical. This means that libraries loaded through the 'package' scheme will |
| 62 * resolve to the same library when loaded from within using relative URIs (see |
| 63 * for instance the test 'standalone/package/package1_test.dart'). But loading a |
| 64 * platform library using a relative URI will _not_ result in the same library |
| 65 * as when loaded through the dart URI. |
| 66 * |
| 67 * ## Readable URI ## |
| 68 * |
| 69 * A 'readable URI' is an absolute URI whose scheme is either 'package' or |
| 70 * something supported by the input provider, normally 'file'. Dart URIs such as |
| 71 * 'dart:core' and 'dart:_js_helper' are not readable themselves but are instead |
| 72 * resolved into a readable URI using the library root URI provided from the |
| 73 * command line and the list of platform libraries found in |
| 74 * 'sdk/lib/_internal/libraries.dart'. This is done through the |
| 75 * [Compiler.translateResolvedUri] method which checks whether a library by that |
| 76 * name exists and in case of internal libraries whether access is granted. |
| 77 * |
| 78 * ## Resource URI ## |
| 79 * |
| 80 * A 'resource URI' is an absolute URI with a scheme supported by the input |
| 81 * provider. For the standard implementation this means a URI with the 'file' |
| 82 * scheme. Readable URIs are converted into resource URIs as part of the |
| 83 * [Compiler.readScript] method. In the standard implementation the package URIs |
| 84 * are converted to file URIs using the package root URI provided on the |
| 85 * command line as base. If the package root URI is |
| 86 * 'file:///current/working/dir/' then the package URI 'package:foo/bar.dart' |
| 87 * will be resolved to the resource URI |
| 88 * 'file:///current/working/dir/foo/bar.dart'. |
| 89 * |
| 90 * The distinction between readable URI and resource URI is necessary to ensure |
| 91 * that these imports |
| 92 * |
| 93 * import 'package:foo.dart' as a; |
| 94 * import 'packages/foo.dart' as b; |
| 95 * |
| 96 * do _not_ resolve to the same library when the package root URI happens to |
| 97 * point to the 'packages' folder. |
| 98 * |
9 */ | 99 */ |
10 abstract class LibraryLoader extends CompilerTask { | 100 abstract class LibraryLoader extends CompilerTask { |
11 LibraryLoader(Compiler compiler) : super(compiler); | 101 LibraryLoader(Compiler compiler) : super(compiler); |
12 | 102 |
13 /** | 103 /** |
14 * Loads the library located at [uri] and returns its [LibraryElement]. | 104 * Loads the library specified by the [resolvedUri] and returns its |
| 105 * [LibraryElement]. |
15 * | 106 * |
16 * If the library is not already loaded, the method creates the | 107 * If the library is not already loaded, the method creates the |
17 * [LibraryElement] for the library and computes the import/export scope, | 108 * [LibraryElement] for the library and computes the import/export scope, |
18 * loading and computing the import/export scopes of all required libraries in | 109 * loading and computing the import/export scopes of all required libraries in |
19 * the process. The method handles cyclic dependency between libraries. | 110 * the process. The method handles cyclic dependency between libraries. |
20 * | 111 * |
21 * This is the main entry point for [LibraryLoader]. | 112 * This is the main entry point for [LibraryLoader]. |
22 */ | 113 */ |
23 LibraryElement loadLibrary(Uri uri, Node node, Uri canonicalUri); | 114 // TODO(johnniwinther): Remove [canonicalUri] together with |
| 115 // [Compiler.scanBuiltinLibrary]. |
| 116 LibraryElement loadLibrary(Uri resolvedUri, Node node, Uri canonicalUri); |
24 | 117 |
25 // TODO(johnniwinther): Remove this when patches don't need special parsing. | 118 // TODO(johnniwinther): Remove this when patches don't need special parsing. |
26 void registerLibraryFromTag(LibraryDependencyHandler handler, | 119 void registerLibraryFromTag(LibraryDependencyHandler handler, |
27 LibraryElement library, | 120 LibraryElement library, |
28 LibraryDependency tag); | 121 LibraryDependency tag); |
29 | 122 |
30 /** | 123 /** |
31 * Adds the elements in the export scope of [importedLibrary] to the import | 124 * Adds the elements in the export scope of [importedLibrary] to the import |
32 * scope of [importingLibrary]. | 125 * scope of [importingLibrary]. |
33 */ | 126 */ |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
126 */ | 219 */ |
127 class LibraryLoaderTask extends LibraryLoader { | 220 class LibraryLoaderTask extends LibraryLoader { |
128 LibraryLoaderTask(Compiler compiler) : super(compiler); | 221 LibraryLoaderTask(Compiler compiler) : super(compiler); |
129 String get name => 'LibraryLoader'; | 222 String get name => 'LibraryLoader'; |
130 | 223 |
131 final Map<String, LibraryElement> libraryNames = | 224 final Map<String, LibraryElement> libraryNames = |
132 new LinkedHashMap<String, LibraryElement>(); | 225 new LinkedHashMap<String, LibraryElement>(); |
133 | 226 |
134 LibraryDependencyHandler currentHandler; | 227 LibraryDependencyHandler currentHandler; |
135 | 228 |
136 LibraryElement loadLibrary(Uri uri, Node node, Uri canonicalUri) { | 229 LibraryElement loadLibrary(Uri resolvedUri, Node node, Uri canonicalUri) { |
137 return measure(() { | 230 return measure(() { |
138 assert(currentHandler == null); | 231 assert(currentHandler == null); |
139 currentHandler = new LibraryDependencyHandler(compiler); | 232 currentHandler = new LibraryDependencyHandler(compiler); |
140 LibraryElement library = | 233 LibraryElement library = |
141 createLibrary(currentHandler, uri, node, canonicalUri); | 234 createLibrary(currentHandler, null, resolvedUri, node, canonicalUri); |
142 currentHandler.computeExports(); | 235 currentHandler.computeExports(); |
143 currentHandler = null; | 236 currentHandler = null; |
144 return library; | 237 return library; |
145 }); | 238 }); |
146 } | 239 } |
147 | 240 |
148 /** | 241 /** |
149 * Processes the library tags in [library]. | 242 * Processes the library tags in [library]. |
150 * | 243 * |
151 * The imported/exported libraries are loaded and processed recursively but | 244 * The imported/exported libraries are loaded and processed recursively but |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
186 tagState = checkTag(TagState.LIBRARY, tag); | 279 tagState = checkTag(TagState.LIBRARY, tag); |
187 if (library.libraryTag != null) { | 280 if (library.libraryTag != null) { |
188 compiler.cancel("duplicated library declaration", node: tag); | 281 compiler.cancel("duplicated library declaration", node: tag); |
189 } else { | 282 } else { |
190 library.libraryTag = tag; | 283 library.libraryTag = tag; |
191 } | 284 } |
192 checkDuplicatedLibraryName(library); | 285 checkDuplicatedLibraryName(library); |
193 } else if (tag.isPart) { | 286 } else if (tag.isPart) { |
194 Part part = tag; | 287 Part part = tag; |
195 StringNode uri = part.uri; | 288 StringNode uri = part.uri; |
196 Uri resolved = base.resolve(uri.dartString.slowToString()); | 289 Uri resolvedUri = base.resolve(uri.dartString.slowToString()); |
197 tagState = checkTag(TagState.SOURCE, part); | 290 tagState = checkTag(TagState.SOURCE, part); |
198 scanPart(part, resolved, library); | 291 scanPart(part, resolvedUri, library); |
199 } else { | 292 } else { |
200 compiler.internalError("Unhandled library tag.", node: tag); | 293 compiler.internalError("Unhandled library tag.", node: tag); |
201 } | 294 } |
202 } | 295 } |
203 | 296 |
204 // Apply patch, if any. | 297 // Apply patch, if any. |
205 if (library.uri.scheme == 'dart') { | 298 if (library.isPlatformLibrary) { |
206 patchDartLibrary(handler, library, library.uri.path); | 299 patchDartLibrary(handler, library, library.canonicalUri.path); |
207 } | 300 } |
208 | 301 |
209 // Import dart:core if not already imported. | 302 // Import dart:core if not already imported. |
210 if (!importsDartCore && !isDartCore(library.uri)) { | 303 if (!importsDartCore && !isDartCore(library.canonicalUri)) { |
211 handler.registerDependency(library, null, loadCoreLibrary(handler)); | 304 handler.registerDependency(library, null, loadCoreLibrary(handler)); |
212 } | 305 } |
213 | 306 |
214 for (LibraryDependency tag in libraryDependencies.toLink()) { | 307 for (LibraryDependency tag in libraryDependencies.toLink()) { |
215 registerLibraryFromTag(handler, library, tag); | 308 registerLibraryFromTag(handler, library, tag); |
216 } | 309 } |
217 } | 310 } |
218 | 311 |
219 void checkDuplicatedLibraryName(LibraryElement library) { | 312 void checkDuplicatedLibraryName(LibraryElement library) { |
220 LibraryName tag = library.libraryTag; | 313 LibraryName tag = library.libraryTag; |
(...skipping 17 matching lines...) Expand all Loading... |
238 } | 331 } |
239 | 332 |
240 bool isDartCore(Uri uri) => uri.scheme == "dart" && uri.path == "core"; | 333 bool isDartCore(Uri uri) => uri.scheme == "dart" && uri.path == "core"; |
241 | 334 |
242 /** | 335 /** |
243 * Lazily loads and returns the [LibraryElement] for the dart:core library. | 336 * Lazily loads and returns the [LibraryElement] for the dart:core library. |
244 */ | 337 */ |
245 LibraryElement loadCoreLibrary(LibraryDependencyHandler handler) { | 338 LibraryElement loadCoreLibrary(LibraryDependencyHandler handler) { |
246 if (compiler.coreLibrary == null) { | 339 if (compiler.coreLibrary == null) { |
247 Uri coreUri = new Uri.fromComponents(scheme: 'dart', path: 'core'); | 340 Uri coreUri = new Uri.fromComponents(scheme: 'dart', path: 'core'); |
248 compiler.coreLibrary = createLibrary(handler, coreUri, null, coreUri); | 341 compiler.coreLibrary |
| 342 = createLibrary(handler, null, coreUri, null, coreUri); |
249 } | 343 } |
250 return compiler.coreLibrary; | 344 return compiler.coreLibrary; |
251 } | 345 } |
252 | 346 |
253 void patchDartLibrary(LibraryDependencyHandler handler, | 347 void patchDartLibrary(LibraryDependencyHandler handler, |
254 LibraryElement library, String dartLibraryPath) { | 348 LibraryElement library, String dartLibraryPath) { |
255 if (library.isPatched) return; | 349 if (library.isPatched) return; |
256 Uri patchUri = compiler.resolvePatchUri(dartLibraryPath); | 350 Uri patchUri = compiler.resolvePatchUri(dartLibraryPath); |
257 if (patchUri != null) { | 351 if (patchUri != null) { |
258 compiler.patchParser.patchLibrary(handler, patchUri, library); | 352 compiler.patchParser.patchLibrary(handler, patchUri, library); |
259 } | 353 } |
260 } | 354 } |
261 | 355 |
262 /** | 356 /** |
263 * Handle a part tag in the scope of [library]. The [path] given is used as | 357 * Handle a part tag in the scope of [library]. The [resolvedUri] given is |
264 * is, any URI resolution should be done beforehand. | 358 * used as is, any URI resolution should be done beforehand. |
265 */ | 359 */ |
266 void scanPart(Part part, Uri path, LibraryElement library) { | 360 void scanPart(Part part, Uri resolvedUri, LibraryElement library) { |
267 if (!path.isAbsolute()) throw new ArgumentError(path); | 361 if (!resolvedUri.isAbsolute()) throw new ArgumentError(resolvedUri); |
268 Script sourceScript = compiler.readScript(path, part); | 362 Uri readableUri = compiler.translateResolvedUri(library, resolvedUri, part); |
| 363 Script sourceScript = compiler.readScript(readableUri, part); |
269 CompilationUnitElement unit = | 364 CompilationUnitElement unit = |
270 new CompilationUnitElementX(sourceScript, library); | 365 new CompilationUnitElementX(sourceScript, library); |
271 compiler.withCurrentElement(unit, () { | 366 compiler.withCurrentElement(unit, () { |
272 compiler.scanner.scan(unit); | 367 compiler.scanner.scan(unit); |
273 if (unit.partTag == null) { | 368 if (unit.partTag == null) { |
274 bool wasDiagnosticEmitted = false; | 369 bool wasDiagnosticEmitted = false; |
275 compiler.withCurrentElement(library, () { | 370 compiler.withCurrentElement(library, () { |
276 wasDiagnosticEmitted = | 371 wasDiagnosticEmitted = |
277 compiler.onDeprecatedFeature(part, 'missing part-of tag'); | 372 compiler.onDeprecatedFeature(part, 'missing part-of tag'); |
278 }); | 373 }); |
279 if (wasDiagnosticEmitted) { | 374 if (wasDiagnosticEmitted) { |
280 compiler.reportMessage( | 375 compiler.reportMessage( |
281 compiler.spanFromElement(unit), | 376 compiler.spanFromElement(unit), |
282 MessageKind.MISSING_PART_OF_TAG.error([]), | 377 MessageKind.MISSING_PART_OF_TAG.error([]), |
283 api.Diagnostic.INFO); | 378 api.Diagnostic.INFO); |
284 } | 379 } |
285 } | 380 } |
286 }); | 381 }); |
287 } | 382 } |
288 | 383 |
289 /** | 384 /** |
290 * Handle an import/export tag by loading the referenced library and | 385 * Handle an import/export tag by loading the referenced library and |
291 * registering its dependency in [handler] for the computation of the import/ | 386 * registering its dependency in [handler] for the computation of the import/ |
292 * export scope. | 387 * export scope. |
293 */ | 388 */ |
294 void registerLibraryFromTag(LibraryDependencyHandler handler, | 389 void registerLibraryFromTag(LibraryDependencyHandler handler, |
295 LibraryElement library, | 390 LibraryElement library, |
296 LibraryDependency tag) { | 391 LibraryDependency tag) { |
297 Uri base = library.entryCompilationUnit.script.uri; | 392 Uri base = library.entryCompilationUnit.script.uri; |
298 Uri resolved = base.resolve(tag.uri.dartString.slowToString()); | 393 Uri resolvedUri = base.resolve(tag.uri.dartString.slowToString()); |
299 LibraryElement loadedLibrary = | 394 LibraryElement loadedLibrary = |
300 createLibrary(handler, resolved, tag.uri, resolved); | 395 createLibrary(handler, library, resolvedUri, tag.uri, resolvedUri); |
301 handler.registerDependency(library, tag, loadedLibrary); | 396 handler.registerDependency(library, tag, loadedLibrary); |
302 | 397 |
303 if (!loadedLibrary.hasLibraryName()) { | 398 if (!loadedLibrary.hasLibraryName()) { |
304 compiler.withCurrentElement(library, () { | 399 compiler.withCurrentElement(library, () { |
305 compiler.reportError(tag == null ? null : tag.uri, | 400 compiler.reportError(tag == null ? null : tag.uri, |
306 'no library name found in ${loadedLibrary.uri}'); | 401 'no library name found in ${loadedLibrary.canonicalUri}'); |
307 }); | 402 }); |
308 } | 403 } |
309 } | 404 } |
310 | 405 |
311 /** | 406 /** |
312 * Create (or reuse) a library element for the library located at [uri]. | 407 * Create (or reuse) a library element for the library specified by the |
| 408 * [resolvedUri]. |
| 409 * |
313 * If a new library is created, the [handler] is notified. | 410 * If a new library is created, the [handler] is notified. |
314 */ | 411 */ |
| 412 // TODO(johnniwinther): Remove [canonicalUri] and make [resolvedUri] the |
| 413 // canonical uri when [Compiler.scanBuiltinLibrary] is removed. |
315 LibraryElement createLibrary(LibraryDependencyHandler handler, | 414 LibraryElement createLibrary(LibraryDependencyHandler handler, |
316 Uri uri, Node node, Uri canonicalUri) { | 415 LibraryElement importingLibrary, |
| 416 Uri resolvedUri, Node node, Uri canonicalUri) { |
317 bool newLibrary = false; | 417 bool newLibrary = false; |
| 418 Uri readableUri = |
| 419 compiler.translateResolvedUri(importingLibrary, resolvedUri, node); |
| 420 if (readableUri == null) return null; |
318 LibraryElement createLibrary() { | 421 LibraryElement createLibrary() { |
319 newLibrary = true; | 422 newLibrary = true; |
320 Script script = compiler.readScript(uri, node); | 423 Script script = compiler.readScript(readableUri, node); |
321 LibraryElement element = new LibraryElementX(script, canonicalUri); | 424 LibraryElement element = new LibraryElementX(script, canonicalUri); |
322 handler.registerNewLibrary(element); | 425 handler.registerNewLibrary(element); |
323 native.maybeEnableNative(compiler, element, uri); | 426 native.maybeEnableNative(compiler, element); |
324 return element; | 427 return element; |
325 } | 428 } |
326 LibraryElement library; | 429 LibraryElement library; |
327 if (canonicalUri == null) { | 430 if (canonicalUri == null) { |
328 library = createLibrary(); | 431 library = createLibrary(); |
329 } else { | 432 } else { |
330 library = compiler.libraries.putIfAbsent(canonicalUri.toString(), | 433 library = compiler.libraries.putIfAbsent(canonicalUri.toString(), |
331 createLibrary); | 434 createLibrary); |
332 } | 435 } |
333 if (newLibrary) { | 436 if (newLibrary) { |
334 compiler.withCurrentElement(library, () { | 437 compiler.withCurrentElement(library, () { |
335 compiler.scanner.scanLibrary(library); | 438 compiler.scanner.scanLibrary(library); |
336 processLibraryTags(handler, library); | 439 processLibraryTags(handler, library); |
337 handler.registerLibraryExports(library); | 440 handler.registerLibraryExports(library); |
338 compiler.onLibraryScanned(library, uri); | 441 compiler.onLibraryScanned(library, resolvedUri); |
339 }); | 442 }); |
340 } | 443 } |
341 return library; | 444 return library; |
342 } | 445 } |
343 | 446 |
344 // TODO(johnniwinther): Remove this method when 'js_helper' is handled by | 447 // TODO(johnniwinther): Remove this method when 'js_helper' is handled by |
345 // [LibraryLoaderTask]. | 448 // [LibraryLoaderTask]. |
346 void importLibrary(LibraryElement importingLibrary, | 449 void importLibrary(LibraryElement importingLibrary, |
347 LibraryElement importedLibrary, | 450 LibraryElement importedLibrary, |
348 Import tag) { | 451 Import tag) { |
(...skipping 376 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
725 } | 828 } |
726 | 829 |
727 /** | 830 /** |
728 * Registers all top-level entities of [library] as starting point for the | 831 * Registers all top-level entities of [library] as starting point for the |
729 * fixed-point computation of the import/export scopes. | 832 * fixed-point computation of the import/export scopes. |
730 */ | 833 */ |
731 void registerLibraryExports(LibraryElement library) { | 834 void registerLibraryExports(LibraryElement library) { |
732 nodeMap[library].registerInitialExports(); | 835 nodeMap[library].registerInitialExports(); |
733 } | 836 } |
734 } | 837 } |
OLD | NEW |