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 library leg_apiimpl; | 5 library leg_apiimpl; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:convert'; | 8 import 'dart:convert'; |
9 | 9 |
10 import 'package:package_config/packages.dart'; | 10 import 'package:package_config/packages.dart'; |
11 import 'package:package_config/packages_file.dart' as pkgs; | 11 import 'package:package_config/packages_file.dart' as pkgs; |
12 import 'package:package_config/src/packages_impl.dart' show | 12 import 'package:package_config/src/packages_impl.dart' show |
13 MapPackages, | 13 MapPackages, |
14 NonFilePackagesDirectoryPackages; | 14 NonFilePackagesDirectoryPackages; |
15 import 'package:package_config/src/util.dart' show | 15 import 'package:package_config/src/util.dart' show |
16 checkValidPackageUri; | 16 checkValidPackageUri; |
17 import 'package:sdk_library_metadata/libraries.dart' as library_info; | |
18 | 17 |
19 import '../compiler_new.dart' as api; | 18 import '../compiler_new.dart' as api; |
20 import 'commandline_options.dart'; | 19 import 'commandline_options.dart'; |
21 import 'common.dart'; | 20 import 'common.dart'; |
22 import 'common/tasks.dart' show | 21 import 'common/tasks.dart' show |
23 GenericTask; | 22 GenericTask; |
24 import 'compiler.dart'; | 23 import 'compiler.dart'; |
25 import 'diagnostics/diagnostic_listener.dart' show | 24 import 'diagnostics/diagnostic_listener.dart' show |
26 DiagnosticOptions; | 25 DiagnosticOptions; |
27 import 'diagnostics/messages.dart' show | 26 import 'diagnostics/messages.dart' show |
28 Message; | 27 Message; |
29 import 'elements/elements.dart' as elements; | 28 import 'elements/elements.dart' as elements; |
30 import 'io/source_file.dart'; | 29 import 'io/source_file.dart'; |
| 30 import 'platform_configuration.dart' as platform_configuration; |
31 import 'script.dart'; | 31 import 'script.dart'; |
32 | 32 |
33 const bool forceIncrementalSupport = | 33 const bool forceIncrementalSupport = |
34 const bool.fromEnvironment('DART2JS_EXPERIMENTAL_INCREMENTAL_SUPPORT'); | 34 const bool.fromEnvironment('DART2JS_EXPERIMENTAL_INCREMENTAL_SUPPORT'); |
35 | 35 |
| 36 /// Locations of the platform descriptor files relative to the library root. |
| 37 const String _clientPlatform = "lib/dart_client.platform"; |
| 38 const String _serverPlatform = "lib/dart_server.platform"; |
| 39 const String _sharedPlatform = "lib/dart_shared.platform"; |
| 40 const String _dart2dartPlatform = "lib/dart2dart.platform"; |
| 41 |
36 /// Implements the [Compiler] using a [api.CompilerInput] for supplying the | 42 /// Implements the [Compiler] using a [api.CompilerInput] for supplying the |
37 /// sources. | 43 /// sources. |
38 class CompilerImpl extends Compiler { | 44 class CompilerImpl extends Compiler { |
39 api.CompilerInput provider; | 45 api.CompilerInput provider; |
40 api.CompilerDiagnostics handler; | 46 api.CompilerDiagnostics handler; |
41 final Uri libraryRoot; | 47 final Uri platformConfigUri; |
42 final Uri packageConfig; | 48 final Uri packageConfig; |
43 final Uri packageRoot; | 49 final Uri packageRoot; |
44 final api.PackagesDiscoveryProvider packagesDiscoveryProvider; | 50 final api.PackagesDiscoveryProvider packagesDiscoveryProvider; |
45 Packages packages; | 51 Packages packages; |
46 List<String> options; | 52 List<String> options; |
47 Map<String, dynamic> environment; | 53 Map<String, dynamic> environment; |
48 bool mockableLibraryUsed = false; | 54 bool mockableLibraryUsed = false; |
49 final Set<library_info.Category> allowedLibraryCategories; | 55 |
| 56 /// A mapping of the dart: library-names to their location. |
| 57 /// |
| 58 /// Initialized in [setupSdk]. |
| 59 Map<String, Uri> sdkLibraries; |
50 | 60 |
51 GenericTask userHandlerTask; | 61 GenericTask userHandlerTask; |
52 GenericTask userProviderTask; | 62 GenericTask userProviderTask; |
53 GenericTask userPackagesDiscoveryTask; | 63 GenericTask userPackagesDiscoveryTask; |
54 | 64 |
| 65 Uri get libraryRoot => platformConfigUri.resolve("."); |
| 66 |
55 CompilerImpl(this.provider, | 67 CompilerImpl(this.provider, |
56 api.CompilerOutput outputProvider, | 68 api.CompilerOutput outputProvider, |
57 this.handler, | 69 this.handler, |
58 this.libraryRoot, | 70 Uri libraryRoot, |
59 this.packageRoot, | 71 this.packageRoot, |
60 List<String> options, | 72 List<String> options, |
61 this.environment, | 73 this.environment, |
62 [this.packageConfig, | 74 [this.packageConfig, |
63 this.packagesDiscoveryProvider]) | 75 this.packagesDiscoveryProvider]) |
64 : this.options = options, | 76 : this.options = options, |
65 this.allowedLibraryCategories = getAllowedLibraryCategories(options), | 77 this.platformConfigUri = resolvePlatformConfig(libraryRoot, options), |
66 super( | 78 super( |
67 outputProvider: outputProvider, | 79 outputProvider: outputProvider, |
68 enableTypeAssertions: hasOption(options, Flags.enableCheckedMode), | 80 enableTypeAssertions: hasOption(options, Flags.enableCheckedMode), |
69 enableUserAssertions: hasOption(options, Flags.enableCheckedMode), | 81 enableUserAssertions: hasOption(options, Flags.enableCheckedMode), |
70 trustTypeAnnotations: | 82 trustTypeAnnotations: |
71 hasOption(options, Flags.trustTypeAnnotations), | 83 hasOption(options, Flags.trustTypeAnnotations), |
72 trustPrimitives: | 84 trustPrimitives: |
73 hasOption(options, Flags.trustPrimitives), | 85 hasOption(options, Flags.trustPrimitives), |
74 enableMinification: hasOption(options, Flags.minify), | 86 enableMinification: hasOption(options, Flags.minify), |
75 useFrequencyNamer: | 87 useFrequencyNamer: |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
168 // CSV: Comma separated values. | 180 // CSV: Comma separated values. |
169 static List<String> extractCsvOption(List<String> options, String prefix) { | 181 static List<String> extractCsvOption(List<String> options, String prefix) { |
170 for (String option in options) { | 182 for (String option in options) { |
171 if (option.startsWith(prefix)) { | 183 if (option.startsWith(prefix)) { |
172 return option.substring(prefix.length).split(','); | 184 return option.substring(prefix.length).split(','); |
173 } | 185 } |
174 } | 186 } |
175 return const <String>[]; | 187 return const <String>[]; |
176 } | 188 } |
177 | 189 |
178 static Set<library_info.Category> getAllowedLibraryCategories( | 190 static Uri resolvePlatformConfig(Uri libraryRoot, |
179 List<String> options) { | 191 List<String> options) { |
180 Iterable<library_info.Category> categories = | 192 String platformConfigPath = |
181 extractCsvOption(options, '--categories=') | 193 extractStringOption(options, "--platform-config=", null); |
182 .map(library_info.parseCategory) | 194 if (platformConfigPath != null) { |
183 .where((x) => x != null); | 195 return libraryRoot.resolve(platformConfigPath); |
184 if (categories.isEmpty) { | 196 } else if (hasOption(options, '--output-type=dart')) { |
185 return new Set.from([library_info.Category.client]); | 197 return libraryRoot.resolve(_dart2dartPlatform); |
| 198 } else { |
| 199 Iterable<String> categories = extractCsvOption(options, '--categories='); |
| 200 if (categories.length == 0) { |
| 201 return libraryRoot.resolve(_clientPlatform); |
| 202 } |
| 203 assert(categories.length <= 2); |
| 204 if (categories.contains("Client")) { |
| 205 if (categories.contains("Server")) { |
| 206 return libraryRoot.resolve(_sharedPlatform); |
| 207 } |
| 208 return libraryRoot.resolve(_clientPlatform); |
| 209 } |
| 210 assert(categories.contains("Server")); |
| 211 return libraryRoot.resolve(_serverPlatform); |
186 } | 212 } |
187 return new Set.from(categories); | |
188 } | 213 } |
189 | 214 |
190 static bool hasOption(List<String> options, String option) { | 215 static bool hasOption(List<String> options, String option) { |
191 return options.indexOf(option) >= 0; | 216 return options.indexOf(option) >= 0; |
192 } | 217 } |
193 | 218 |
194 String lookupPatchPath(String dartLibraryName) { | |
195 library_info.LibraryInfo info = lookupLibraryInfo(dartLibraryName); | |
196 if (info == null) return null; | |
197 if (!info.isDart2jsLibrary) return null; | |
198 String path = info.dart2jsPatchPath; | |
199 if (path == null) return null; | |
200 return "lib/$path"; | |
201 } | |
202 | |
203 void log(message) { | 219 void log(message) { |
204 callUserHandler( | 220 callUserHandler( |
205 null, null, null, null, message, api.Diagnostic.VERBOSE_INFO); | 221 null, null, null, null, message, api.Diagnostic.VERBOSE_INFO); |
206 } | 222 } |
207 | 223 |
208 /// See [Compiler.translateResolvedUri]. | 224 /// See [Compiler.translateResolvedUri]. |
209 Uri translateResolvedUri(elements.LibraryElement importingLibrary, | 225 Uri translateResolvedUri(elements.LibraryElement importingLibrary, |
210 Uri resolvedUri, Spannable spannable) { | 226 Uri resolvedUri, Spannable spannable) { |
211 if (resolvedUri.scheme == 'dart') { | 227 if (resolvedUri.scheme == 'dart') { |
212 return translateDartUri(importingLibrary, resolvedUri, spannable); | 228 return translateDartUri(importingLibrary, resolvedUri, spannable); |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
297 * See [LibraryLoader] for terminology on URIs. | 313 * See [LibraryLoader] for terminology on URIs. |
298 */ | 314 */ |
299 Uri translateUri(Spannable node, Uri readableUri) { | 315 Uri translateUri(Spannable node, Uri readableUri) { |
300 switch (readableUri.scheme) { | 316 switch (readableUri.scheme) { |
301 case 'package': return translatePackageUri(node, readableUri); | 317 case 'package': return translatePackageUri(node, readableUri); |
302 default: return readableUri; | 318 default: return readableUri; |
303 } | 319 } |
304 } | 320 } |
305 | 321 |
306 /// Translates "resolvedUri" with scheme "dart" to a [uri] resolved relative | 322 /// Translates "resolvedUri" with scheme "dart" to a [uri] resolved relative |
307 /// to [libraryRoot] according to the information in [library_info.libraries]. | 323 /// to [platformConfigUri] according to the information in the file at |
| 324 /// [platformConfigUri]. |
308 /// | 325 /// |
309 /// Returns null and emits an error if the library could not be found or | 326 /// Returns null and emits an error if the library could not be found or |
310 /// imported into [importingLibrary]. | 327 /// imported into [importingLibrary]. |
311 /// | 328 /// |
312 /// If [importingLibrary] is a platform or patch library all dart2js libraries | 329 /// Internal libraries (whose name starts with '_') can be only resolved if |
313 /// can be resolved. Otherwise only libraries with categories in | 330 /// [importingLibrary] is a platform or patch library. |
314 /// [allowedLibraryCategories] can be resolved. | |
315 Uri translateDartUri(elements.LibraryElement importingLibrary, | 331 Uri translateDartUri(elements.LibraryElement importingLibrary, |
316 Uri resolvedUri, Spannable spannable) { | 332 Uri resolvedUri, Spannable spannable) { |
317 | 333 |
318 library_info.LibraryInfo libraryInfo = lookupLibraryInfo(resolvedUri.path); | 334 Uri location = lookupLibraryUri(resolvedUri.path); |
319 | 335 |
320 bool allowInternalLibraryAccess = false; | 336 if (location == null) { |
321 if (importingLibrary != null) { | 337 reporter.reportErrorMessage( |
322 if (importingLibrary.isPlatformLibrary || importingLibrary.isPatch) { | 338 spannable, |
323 allowInternalLibraryAccess = true; | 339 MessageKind.LIBRARY_NOT_FOUND, |
324 } else if (importingLibrary.canonicalUri.path.contains( | 340 {'resolvedUri': resolvedUri}); |
325 'sdk/tests/compiler/dart2js_native')) { | 341 return null; |
326 allowInternalLibraryAccess = true; | 342 } |
| 343 |
| 344 if (resolvedUri.path.startsWith('_') ) { |
| 345 bool allowInternalLibraryAccess = importingLibrary != null && |
| 346 (importingLibrary.isPlatformLibrary || |
| 347 importingLibrary.isPatch || |
| 348 importingLibrary.canonicalUri.path |
| 349 .contains('sdk/tests/compiler/dart2js_native')); |
| 350 |
| 351 if (!allowInternalLibraryAccess) { |
| 352 if (importingLibrary != null) { |
| 353 reporter.reportErrorMessage( |
| 354 spannable, |
| 355 MessageKind.INTERNAL_LIBRARY_FROM, |
| 356 {'resolvedUri': resolvedUri, |
| 357 'importingUri': importingLibrary.canonicalUri}); |
| 358 } else { |
| 359 reporter.reportErrorMessage( |
| 360 spannable, |
| 361 MessageKind.INTERNAL_LIBRARY, |
| 362 {'resolvedUri': resolvedUri}); |
| 363 registerDisallowedLibraryUse(resolvedUri); |
| 364 } |
| 365 return null; |
327 } | 366 } |
328 } | 367 } |
329 | 368 |
330 String computePath() { | 369 if (location.scheme == "unsupported") { |
331 if (libraryInfo == null) { | 370 reporter.reportErrorMessage( |
332 return null; | 371 spannable, |
333 } else if (!libraryInfo.isDart2jsLibrary) { | 372 MessageKind.LIBRARY_NOT_SUPPORTED, |
334 return null; | 373 {'resolvedUri': resolvedUri}); |
335 } else { | 374 registerDisallowedLibraryUse(resolvedUri); |
336 if (libraryInfo.isInternal && | |
337 !allowInternalLibraryAccess) { | |
338 if (importingLibrary != null) { | |
339 reporter.reportErrorMessage( | |
340 spannable, | |
341 MessageKind.INTERNAL_LIBRARY_FROM, | |
342 {'resolvedUri': resolvedUri, | |
343 'importingUri': importingLibrary.canonicalUri}); | |
344 } else { | |
345 reporter.reportErrorMessage( | |
346 spannable, | |
347 MessageKind.INTERNAL_LIBRARY, | |
348 {'resolvedUri': resolvedUri}); | |
349 registerDisallowedLibraryUse(resolvedUri); | |
350 } | |
351 return null; | |
352 } else if (!allowInternalLibraryAccess && | |
353 !allowedLibraryCategories.any(libraryInfo.categories.contains)) { | |
354 registerDisallowedLibraryUse(resolvedUri); | |
355 // TODO(sigurdm): Currently we allow the sdk libraries to import | |
356 // libraries from any category. We might want to revisit this. | |
357 return null; | |
358 } else { | |
359 return (libraryInfo.dart2jsPath != null) | |
360 ? libraryInfo.dart2jsPath | |
361 : libraryInfo.path; | |
362 } | |
363 } | |
364 } | |
365 | |
366 String path = computePath(); | |
367 | |
368 if (path == null) { | |
369 if (libraryInfo == null) { | |
370 reporter.reportErrorMessage( | |
371 spannable, | |
372 MessageKind.LIBRARY_NOT_FOUND, | |
373 {'resolvedUri': resolvedUri}); | |
374 } else { | |
375 reporter.reportErrorMessage( | |
376 spannable, | |
377 MessageKind.LIBRARY_NOT_SUPPORTED, | |
378 {'resolvedUri': resolvedUri}); | |
379 } | |
380 // TODO(johnniwinther): Support signaling the error through the returned | |
381 // value. | |
382 return null; | 375 return null; |
383 } | 376 } |
384 | 377 |
385 if (resolvedUri.path == 'html' || | 378 if (resolvedUri.path == 'html' || |
386 resolvedUri.path == 'io') { | 379 resolvedUri.path == 'io') { |
387 // TODO(ahe): Get rid of mockableLibraryUsed when test.dart | 380 // TODO(ahe): Get rid of mockableLibraryUsed when test.dart |
388 // supports this use case better. | 381 // supports this use case better. |
389 mockableLibraryUsed = true; | 382 mockableLibraryUsed = true; |
390 } | 383 } |
391 return libraryRoot.resolve("lib/$path"); | 384 return location; |
392 } | |
393 | |
394 Uri resolvePatchUri(String dartLibraryPath) { | |
395 String patchPath = lookupPatchPath(dartLibraryPath); | |
396 if (patchPath == null) return null; | |
397 return libraryRoot.resolve(patchPath); | |
398 } | 385 } |
399 | 386 |
400 Uri translatePackageUri(Spannable node, Uri uri) { | 387 Uri translatePackageUri(Spannable node, Uri uri) { |
401 try { | 388 try { |
402 checkValidPackageUri(uri); | 389 checkValidPackageUri(uri); |
403 } on ArgumentError catch (e) { | 390 } on ArgumentError catch (e) { |
404 reporter.reportErrorMessage( | 391 reporter.reportErrorMessage( |
405 node, | 392 node, |
406 MessageKind.INVALID_PACKAGE_URI, | 393 MessageKind.INVALID_PACKAGE_URI, |
407 {'uri': uri, 'exception': e.message}); | 394 {'uri': uri, 'exception': e.message}); |
408 return null; | 395 return null; |
409 } | 396 } |
410 return packages.resolve(uri, | 397 return packages.resolve(uri, |
411 notFound: (Uri notFound) { | 398 notFound: (Uri notFound) { |
412 reporter.reportErrorMessage( | 399 reporter.reportErrorMessage( |
413 node, | 400 node, |
414 MessageKind.LIBRARY_NOT_FOUND, | 401 MessageKind.LIBRARY_NOT_FOUND, |
415 {'resolvedUri': uri}); | 402 {'resolvedUri': uri}); |
416 return null; | 403 return null; |
417 }); | 404 }); |
418 } | 405 } |
419 | 406 |
420 Future<elements.LibraryElement> analyzeUri( | 407 Future<elements.LibraryElement> analyzeUri( |
421 Uri uri, | 408 Uri uri, |
422 {bool skipLibraryWithPartOfTag: true}) { | 409 {bool skipLibraryWithPartOfTag: true}) { |
| 410 List<Future> setupFutures = new List<Future>(); |
| 411 if (sdkLibraries == null) { |
| 412 setupFutures.add(setupSdk()); |
| 413 } |
423 if (packages == null) { | 414 if (packages == null) { |
424 return setupPackages(uri).then((_) => super.analyzeUri(uri)); | 415 setupFutures.add(setupPackages(uri)); |
425 } | 416 } |
426 return super.analyzeUri( | 417 return Future.wait(setupFutures).then((_) => super.analyzeUri(uri)); |
427 uri, skipLibraryWithPartOfTag: skipLibraryWithPartOfTag); | |
428 } | 418 } |
429 | 419 |
430 Future setupPackages(Uri uri) { | 420 Future setupPackages(Uri uri) { |
431 if (packageRoot != null) { | 421 if (packageRoot != null) { |
432 // Use "non-file" packages because the file version requires a [Directory] | 422 // Use "non-file" packages because the file version requires a [Directory] |
433 // and we can't depend on 'dart:io' classes. | 423 // and we can't depend on 'dart:io' classes. |
434 packages = new NonFilePackagesDirectoryPackages(packageRoot); | 424 packages = new NonFilePackagesDirectoryPackages(packageRoot); |
435 } else if (packageConfig != null) { | 425 } else if (packageConfig != null) { |
436 return callUserProvider(packageConfig).then((packageConfigContents) { | 426 return callUserProvider(packageConfig).then((packageConfigContents) { |
437 if (packageConfigContents is String) { | 427 if (packageConfigContents is String) { |
(...skipping 20 matching lines...) Expand all Loading... |
458 packages = Packages.noPackages; | 448 packages = Packages.noPackages; |
459 } else { | 449 } else { |
460 return callUserPackagesDiscovery(uri).then((p) { | 450 return callUserPackagesDiscovery(uri).then((p) { |
461 packages = p; | 451 packages = p; |
462 }); | 452 }); |
463 } | 453 } |
464 } | 454 } |
465 return new Future.value(); | 455 return new Future.value(); |
466 } | 456 } |
467 | 457 |
| 458 Future<Null> setupSdk() { |
| 459 if (sdkLibraries == null) { |
| 460 return platform_configuration.load(platformConfigUri, provider) |
| 461 .then((Map<String, Uri> mapping) { |
| 462 sdkLibraries = mapping; |
| 463 }); |
| 464 } else { |
| 465 // The incremental compiler sets up the sdk before run. |
| 466 // Therefore this will be called a second time. |
| 467 return new Future.value(null); |
| 468 } |
| 469 } |
| 470 |
468 Future<bool> run(Uri uri) { | 471 Future<bool> run(Uri uri) { |
469 log('Allowed library categories: $allowedLibraryCategories'); | 472 log('Using platform configuration at ${platformConfigUri}'); |
470 | 473 |
471 return setupPackages(uri).then((_) { | 474 return Future.wait([setupSdk(), setupPackages(uri)]).then((_) { |
| 475 assert(sdkLibraries != null); |
472 assert(packages != null); | 476 assert(packages != null); |
473 | 477 |
474 return super.run(uri).then((bool success) { | 478 return super.run(uri).then((bool success) { |
475 int cumulated = 0; | 479 int cumulated = 0; |
476 for (final task in tasks) { | 480 for (final task in tasks) { |
477 int elapsed = task.timing; | 481 int elapsed = task.timing; |
478 if (elapsed != 0) { | 482 if (elapsed != 0) { |
479 cumulated += elapsed; | 483 cumulated += elapsed; |
480 log('${task.name} took ${elapsed}msec'); | 484 log('${task.name} took ${elapsed}msec'); |
481 for (String subtask in task.subtasks) { | 485 for (String subtask in task.subtasks) { |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
552 Future<Packages> callUserPackagesDiscovery(Uri uri) { | 556 Future<Packages> callUserPackagesDiscovery(Uri uri) { |
553 try { | 557 try { |
554 return userPackagesDiscoveryTask.measure( | 558 return userPackagesDiscoveryTask.measure( |
555 () => packagesDiscoveryProvider(uri)); | 559 () => packagesDiscoveryProvider(uri)); |
556 } catch (ex, s) { | 560 } catch (ex, s) { |
557 diagnoseCrashInUserCode('Uncaught exception in package discovery', ex, s); | 561 diagnoseCrashInUserCode('Uncaught exception in package discovery', ex, s); |
558 rethrow; | 562 rethrow; |
559 } | 563 } |
560 } | 564 } |
561 | 565 |
562 | |
563 fromEnvironment(String name) => environment[name]; | 566 fromEnvironment(String name) => environment[name]; |
564 | 567 |
565 library_info.LibraryInfo lookupLibraryInfo(String libraryName) { | 568 Uri lookupLibraryUri(String libraryName) { |
566 return library_info.libraries[libraryName]; | 569 assert(invariant(NO_LOCATION_SPANNABLE, |
| 570 sdkLibraries != null, message: "setupSdk() has not been run")); |
| 571 return sdkLibraries[libraryName]; |
| 572 } |
| 573 |
| 574 Uri resolvePatchUri(String libraryName) { |
| 575 return backend.resolvePatchUri(libraryName, platformConfigUri); |
567 } | 576 } |
568 } | 577 } |
OLD | NEW |