| 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 | 17 |
| 18 import '../compiler_new.dart' as api; | 18 import '../compiler_new.dart' as api; |
| 19 import 'commandline_options.dart'; | 19 import 'commandline_options.dart'; |
| 20 import 'common.dart'; | 20 import 'common.dart'; |
| 21 import 'common/tasks.dart' show | 21 import 'common/tasks.dart' show |
| 22 GenericTask; | 22 GenericTask; |
| 23 import 'compiler.dart'; | 23 import 'compiler.dart'; |
| 24 import 'diagnostics/diagnostic_listener.dart' show | 24 import 'diagnostics/diagnostic_listener.dart' show |
| 25 DiagnosticOptions; | 25 DiagnosticOptions; |
| 26 import 'diagnostics/messages.dart' show | 26 import 'diagnostics/messages.dart' show |
| 27 Message; | 27 Message; |
| 28 import 'elements/elements.dart' as elements; | 28 import 'elements/elements.dart' as elements; |
| 29 import 'environment.dart'; |
| 29 import 'io/source_file.dart'; | 30 import 'io/source_file.dart'; |
| 30 import 'platform_configuration.dart' as platform_configuration; | 31 import 'platform_configuration.dart' as platform_configuration; |
| 31 import 'script.dart'; | 32 import 'script.dart'; |
| 32 | 33 |
| 33 /// For every 'dart:' library, a corresponding environment variable is set | |
| 34 /// to "true". The environment variable's name is the concatenation of | |
| 35 /// this prefix and the name (without the 'dart:'. | |
| 36 /// | |
| 37 /// For example 'dart:html' has the environment variable 'dart.library.html' set | |
| 38 /// to "true". | |
| 39 const String dartLibraryEnvironmentPrefix = 'dart.library.'; | |
| 40 | |
| 41 | 34 |
| 42 /// Implements the [Compiler] using a [api.CompilerInput] for supplying the | 35 /// Implements the [Compiler] using a [api.CompilerInput] for supplying the |
| 43 /// sources. | 36 /// sources. |
| 44 class CompilerImpl extends Compiler { | 37 class CompilerImpl extends Compiler { |
| 45 api.CompilerInput provider; | 38 api.CompilerInput provider; |
| 46 api.CompilerDiagnostics handler; | 39 api.CompilerDiagnostics handler; |
| 47 Packages packages; | 40 Packages packages; |
| 48 bool mockableLibraryUsed = false; | 41 bool mockableLibraryUsed = false; |
| 49 | 42 |
| 50 /// A mapping of the dart: library-names to their location. | 43 /// A mapping of the dart: library-names to their location. |
| 51 /// | 44 /// |
| 52 /// Initialized in [setupSdk]. | 45 /// Initialized in [setupSdk]. |
| 53 Map<String, Uri> sdkLibraries; | 46 Map<String, Uri> sdkLibraries; |
| 54 | 47 |
| 55 GenericTask userHandlerTask; | 48 GenericTask userHandlerTask; |
| 56 GenericTask userProviderTask; | 49 GenericTask userProviderTask; |
| 57 GenericTask userPackagesDiscoveryTask; | 50 GenericTask userPackagesDiscoveryTask; |
| 58 | 51 |
| 59 Uri get libraryRoot => options.platformConfigUri.resolve("."); | 52 Uri get libraryRoot => options.platformConfigUri.resolve("."); |
| 60 | 53 |
| 61 CompilerImpl(this.provider, api.CompilerOutput outputProvider, | 54 CompilerImpl(this.provider, api.CompilerOutput outputProvider, |
| 62 this.handler, api.CompilerOptions options) | 55 this.handler, api.CompilerOptions options) |
| 63 : super(options: options, outputProvider: outputProvider) { | 56 : super(options: options, outputProvider: outputProvider, |
| 57 environment: new _Environment(options.environment)) { |
| 58 _Environment env = environment; |
| 59 env.compiler = this; |
| 64 tasks.addAll([ | 60 tasks.addAll([ |
| 65 userHandlerTask = new GenericTask('Diagnostic handler', this), | 61 userHandlerTask = new GenericTask('Diagnostic handler', this), |
| 66 userProviderTask = new GenericTask('Input provider', this), | 62 userProviderTask = new GenericTask('Input provider', this), |
| 67 userPackagesDiscoveryTask = | 63 userPackagesDiscoveryTask = |
| 68 new GenericTask('Package discovery', this), | 64 new GenericTask('Package discovery', this), |
| 69 ]); | 65 ]); |
| 70 } | 66 } |
| 71 | 67 |
| 72 | 68 |
| 73 void log(message) { | 69 void log(message) { |
| 74 callUserHandler( | 70 callUserHandler( |
| 75 null, null, null, null, message, api.Diagnostic.VERBOSE_INFO); | 71 null, null, null, null, message, api.Diagnostic.VERBOSE_INFO); |
| 76 } | 72 } |
| 77 | 73 |
| 78 /// See [Compiler.translateResolvedUri]. | 74 /// See [Compiler.translateResolvedUri]. |
| 79 Uri translateResolvedUri(elements.LibraryElement importingLibrary, | 75 Uri translateResolvedUri(elements.LibraryElement importingLibrary, |
| 80 Uri resolvedUri, Spannable spannable) { | 76 Uri resolvedUri, Spannable spannable) { |
| 81 if (resolvedUri.scheme == 'dart') { | 77 if (resolvedUri.scheme == 'dart') { |
| 82 return translateDartUri(importingLibrary, resolvedUri, spannable); | 78 return translateDartUri(importingLibrary, resolvedUri, spannable); |
| 83 } | 79 } |
| 84 return resolvedUri; | 80 return resolvedUri; |
| 85 } | 81 } |
| 86 | 82 |
| 87 /** | 83 /** |
| 88 * Reads the script designated by [readableUri]. | 84 * Reads the script designated by [readableUri]. |
| 89 */ | 85 */ |
| 90 Future<Script> readScript(Spannable node, Uri readableUri) { | 86 Future<Script> readScript(Uri readableUri, [Spannable node]) { |
| 91 if (!readableUri.isAbsolute) { | 87 if (!readableUri.isAbsolute) { |
| 92 if (node == null) node = NO_LOCATION_SPANNABLE; | 88 if (node == null) node = NO_LOCATION_SPANNABLE; |
| 93 reporter.internalError(node, | 89 reporter.internalError(node, |
| 94 'Relative uri $readableUri provided to readScript(Uri).'); | 90 'Relative uri $readableUri provided to readScript(Uri).'); |
| 95 } | 91 } |
| 96 | 92 |
| 97 // We need to store the current element since we are reporting read errors | 93 // We need to store the current element since we are reporting read errors |
| 98 // asynchronously and therefore need to restore the current element for | 94 // asynchronously and therefore need to restore the current element for |
| 99 // [node] to be valid. | 95 // [node] to be valid. |
| 100 elements.Element element = currentElement; | 96 elements.Element element = currentElement; |
| 101 void reportReadError(exception) { | 97 void reportReadError(exception) { |
| 102 if (element == null || node == null) { | 98 if (element == null || node == null) { |
| 103 reporter.reportErrorMessage( | 99 reporter.reportErrorMessage( |
| 104 new SourceSpan(readableUri, 0, 0), | 100 new SourceSpan(readableUri, 0, 0), |
| 105 MessageKind.READ_SELF_ERROR, | 101 MessageKind.READ_SELF_ERROR, |
| 106 {'uri': readableUri, 'exception': exception}); | 102 {'uri': readableUri, 'exception': exception}); |
| 107 } else { | 103 } else { |
| 108 reporter.withCurrentElement(element, () { | 104 reporter.withCurrentElement(element, () { |
| 109 reporter.reportErrorMessage( | 105 reporter.reportErrorMessage( |
| 110 node, | 106 node, |
| 111 MessageKind.READ_SCRIPT_ERROR, | 107 MessageKind.READ_SCRIPT_ERROR, |
| 112 {'uri': readableUri, 'exception': exception}); | 108 {'uri': readableUri, 'exception': exception}); |
| 113 }); | 109 }); |
| 114 } | 110 } |
| 115 } | 111 } |
| 116 | 112 |
| 117 Uri resourceUri = translateUri(node, readableUri); | 113 Uri resourceUri = translateUri(node, readableUri); |
| 118 if (resourceUri == null) return synthesizeScript(node, readableUri); | 114 if (resourceUri == null) return _synthesizeScript(readableUri); |
| 119 if (resourceUri.scheme == 'dart-ext') { | 115 if (resourceUri.scheme == 'dart-ext') { |
| 120 if (!options.allowNativeExtensions) { | 116 if (!options.allowNativeExtensions) { |
| 121 reporter.withCurrentElement(element, () { | 117 reporter.withCurrentElement(element, () { |
| 122 reporter.reportErrorMessage( | 118 reporter.reportErrorMessage( |
| 123 node, MessageKind.DART_EXT_NOT_SUPPORTED); | 119 node, MessageKind.DART_EXT_NOT_SUPPORTED); |
| 124 }); | 120 }); |
| 125 } | 121 } |
| 126 return synthesizeScript(node, readableUri); | 122 return _synthesizeScript(readableUri); |
| 127 } | 123 } |
| 128 | 124 |
| 129 // TODO(johnniwinther): Wrap the result from [provider] in a specialized | 125 // TODO(johnniwinther): Wrap the result from [provider] in a specialized |
| 130 // [Future] to ensure that we never execute an asynchronous action without | 126 // [Future] to ensure that we never execute an asynchronous action without |
| 131 // setting up the current element of the compiler. | 127 // setting up the current element of the compiler. |
| 132 return new Future.sync(() => callUserProvider(resourceUri)).then((data) { | 128 return new Future.sync(() => callUserProvider(resourceUri)).then((data) { |
| 133 SourceFile sourceFile; | 129 SourceFile sourceFile; |
| 134 if (data is List<int>) { | 130 if (data is List<int>) { |
| 135 sourceFile = new Utf8BytesSourceFile(resourceUri, data); | 131 sourceFile = new Utf8BytesSourceFile(resourceUri, data); |
| 136 } else if (data is String) { | 132 } else if (data is String) { |
| 137 sourceFile = new StringSourceFile.fromUri(resourceUri, data); | 133 sourceFile = new StringSourceFile.fromUri(resourceUri, data); |
| 138 } else { | 134 } else { |
| 139 String message = "Expected a 'String' or a 'List<int>' from the input " | 135 String message = "Expected a 'String' or a 'List<int>' from the input " |
| 140 "provider, but got: ${Error.safeToString(data)}."; | 136 "provider, but got: ${Error.safeToString(data)}."; |
| 141 reportReadError(message); | 137 reportReadError(message); |
| 142 } | 138 } |
| 143 // We use [readableUri] as the URI for the script since need to preserve | 139 // We use [readableUri] as the URI for the script since need to preserve |
| 144 // the scheme in the script because [Script.uri] is used for resolving | 140 // the scheme in the script because [Script.uri] is used for resolving |
| 145 // relative URIs mentioned in the script. See the comment on | 141 // relative URIs mentioned in the script. See the comment on |
| 146 // [LibraryLoader] for more details. | 142 // [LibraryLoader] for more details. |
| 147 return new Script(readableUri, resourceUri, sourceFile); | 143 return new Script(readableUri, resourceUri, sourceFile); |
| 148 }).catchError((error) { | 144 }).catchError((error) { |
| 149 reportReadError(error); | 145 reportReadError(error); |
| 150 return synthesizeScript(node, readableUri); | 146 return _synthesizeScript(readableUri); |
| 151 }); | 147 }); |
| 152 } | 148 } |
| 153 | 149 |
| 154 Future<Script> synthesizeScript(Spannable node, Uri readableUri) { | 150 Future<Script> _synthesizeScript(Uri readableUri) { |
| 155 return new Future.value( | 151 return new Future.value(new Script.synthetic(readableUri)); |
| 156 new Script( | |
| 157 readableUri, readableUri, | |
| 158 new StringSourceFile.fromUri( | |
| 159 readableUri, | |
| 160 "// Synthetic source file generated for '$readableUri'."), | |
| 161 isSynthesized: true)); | |
| 162 } | 152 } |
| 163 | 153 |
| 164 /** | 154 /** |
| 165 * Translates a readable URI into a resource URI. | 155 * Translates a readable URI into a resource URI. |
| 166 * | 156 * |
| 167 * See [LibraryLoader] for terminology on URIs. | 157 * See [LibraryLoader] for terminology on URIs. |
| 168 */ | 158 */ |
| 169 Uri translateUri(Spannable node, Uri readableUri) { | 159 Uri translateUri(Spannable node, Uri uri) => |
| 170 switch (readableUri.scheme) { | 160 uri.scheme == 'package' ? translatePackageUri(node, uri) : uri; |
| 171 case 'package': return translatePackageUri(node, readableUri); | |
| 172 default: return readableUri; | |
| 173 } | |
| 174 } | |
| 175 | 161 |
| 176 /// Translates "resolvedUri" with scheme "dart" to a [uri] resolved relative | 162 /// Translates "resolvedUri" with scheme "dart" to a [uri] resolved relative |
| 177 /// to `options.platformConfigUri` according to the information in the file at | 163 /// to `options.platformConfigUri` according to the information in the file at |
| 178 /// `options.platformConfigUri`. | 164 /// `options.platformConfigUri`. |
| 179 /// | 165 /// |
| 180 /// Returns null and emits an error if the library could not be found or | 166 /// Returns null and emits an error if the library could not be found or |
| 181 /// imported into [importingLibrary]. | 167 /// imported into [importingLibrary]. |
| 182 /// | 168 /// |
| 183 /// Internal libraries (whose name starts with '_') can be only resolved if | 169 /// Internal libraries (whose name starts with '_') can be only resolved if |
| 184 /// [importingLibrary] is a platform or patch library. | 170 /// [importingLibrary] is a platform or patch library. |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 373 callUserHandler( | 359 callUserHandler( |
| 374 message, span.uri, span.begin, span.end, '$message', kind); | 360 message, span.uri, span.begin, span.end, '$message', kind); |
| 375 } | 361 } |
| 376 } | 362 } |
| 377 | 363 |
| 378 bool get isMockCompilation => | 364 bool get isMockCompilation => |
| 379 mockableLibraryUsed && options.allowMockCompilation; | 365 mockableLibraryUsed && options.allowMockCompilation; |
| 380 | 366 |
| 381 void callUserHandler(Message message, Uri uri, int begin, int end, | 367 void callUserHandler(Message message, Uri uri, int begin, int end, |
| 382 String text, api.Diagnostic kind) { | 368 String text, api.Diagnostic kind) { |
| 383 try { | 369 userHandlerTask.measure(() { |
| 384 userHandlerTask.measure(() { | 370 handler.report(message, uri, begin, end, text, kind); |
| 385 handler.report(message, uri, begin, end, text, kind); | 371 }); |
| 386 }); | |
| 387 } catch (ex, s) { | |
| 388 diagnoseCrashInUserCode( | |
| 389 'Uncaught exception in diagnostic handler', ex, s); | |
| 390 rethrow; | |
| 391 } | |
| 392 } | 372 } |
| 393 | 373 |
| 394 Future callUserProvider(Uri uri) { | 374 Future callUserProvider(Uri uri) { |
| 395 try { | 375 return userProviderTask.measure(() => provider.readFromUri(uri)); |
| 396 return userProviderTask.measure(() => provider.readFromUri(uri)); | |
| 397 } catch (ex, s) { | |
| 398 diagnoseCrashInUserCode('Uncaught exception in input provider', ex, s); | |
| 399 rethrow; | |
| 400 } | |
| 401 } | 376 } |
| 402 | 377 |
| 403 Future<Packages> callUserPackagesDiscovery(Uri uri) { | 378 Future<Packages> callUserPackagesDiscovery(Uri uri) { |
| 404 try { | 379 return userPackagesDiscoveryTask.measure( |
| 405 return userPackagesDiscoveryTask.measure( | 380 () => options.packagesDiscoveryProvider(uri)); |
| 406 () => options.packagesDiscoveryProvider(uri)); | |
| 407 } catch (ex, s) { | |
| 408 diagnoseCrashInUserCode('Uncaught exception in package discovery', ex, s); | |
| 409 rethrow; | |
| 410 } | |
| 411 } | |
| 412 | |
| 413 fromEnvironment(String name) { | |
| 414 assert(invariant(NO_LOCATION_SPANNABLE, | |
| 415 sdkLibraries != null, message: "setupSdk() has not been run")); | |
| 416 | |
| 417 var result = options.environment[name]; | |
| 418 if (result != null || options.environment.containsKey(name)) return result; | |
| 419 if (!name.startsWith(dartLibraryEnvironmentPrefix)) return null; | |
| 420 | |
| 421 String libraryName = name.substring(dartLibraryEnvironmentPrefix.length); | |
| 422 | |
| 423 // Private libraries are not exposed to the users. | |
| 424 if (libraryName.startsWith("_")) return null; | |
| 425 | |
| 426 if (sdkLibraries.containsKey(libraryName)) { | |
| 427 // Dart2js always "supports" importing 'dart:mirrors' but will abort | |
| 428 // the compilation at a later point if the backend doesn't support | |
| 429 // mirrors. In this case 'mirrors' should not be in the environment. | |
| 430 if (libraryName == 'mirrors') { | |
| 431 return backend.supportsReflection ? "true" : null; | |
| 432 } | |
| 433 return "true"; | |
| 434 } | |
| 435 return null; | |
| 436 } | 381 } |
| 437 | 382 |
| 438 Uri lookupLibraryUri(String libraryName) { | 383 Uri lookupLibraryUri(String libraryName) { |
| 439 assert(invariant(NO_LOCATION_SPANNABLE, | 384 assert(invariant(NO_LOCATION_SPANNABLE, |
| 440 sdkLibraries != null, message: "setupSdk() has not been run")); | 385 sdkLibraries != null, message: "setupSdk() has not been run")); |
| 441 return sdkLibraries[libraryName]; | 386 return sdkLibraries[libraryName]; |
| 442 } | 387 } |
| 443 | 388 |
| 444 Uri resolvePatchUri(String libraryName) { | 389 Uri resolvePatchUri(String libraryName) { |
| 445 return backend.resolvePatchUri(libraryName, options.platformConfigUri); | 390 return backend.resolvePatchUri(libraryName, options.platformConfigUri); |
| 446 } | 391 } |
| 447 } | 392 } |
| 393 |
| 394 class _Environment implements Environment { |
| 395 final Map<String, String> definitions; |
| 396 |
| 397 // TODO(sigmund): break the circularity here: Compiler needs an environment to |
| 398 // intialize the library loader, but the environment here needs to know about |
| 399 // how the sdk is set up and about whether the backend supports mirrors. |
| 400 CompilerImpl compiler; |
| 401 |
| 402 _Environment(this.definitions); |
| 403 |
| 404 String valueOf(String name) { |
| 405 assert(invariant(NO_LOCATION_SPANNABLE, |
| 406 compiler.sdkLibraries != null, message: "setupSdk() has not been run")); |
| 407 |
| 408 var result = definitions[name]; |
| 409 if (result != null || definitions.containsKey(name)) return result; |
| 410 if (!name.startsWith(_dartLibraryEnvironmentPrefix)) return null; |
| 411 |
| 412 String libraryName = name.substring(_dartLibraryEnvironmentPrefix.length); |
| 413 |
| 414 // Private libraries are not exposed to the users. |
| 415 if (libraryName.startsWith("_")) return null; |
| 416 |
| 417 if (compiler.sdkLibraries.containsKey(libraryName)) { |
| 418 // Dart2js always "supports" importing 'dart:mirrors' but will abort |
| 419 // the compilation at a later point if the backend doesn't support |
| 420 // mirrors. In this case 'mirrors' should not be in the environment. |
| 421 if (libraryName == 'mirrors') { |
| 422 return compiler.backend.supportsReflection ? "true" : null; |
| 423 } |
| 424 return "true"; |
| 425 } |
| 426 return null; |
| 427 } |
| 428 } |
| 429 |
| 430 /// For every 'dart:' library, a corresponding environment variable is set |
| 431 /// to "true". The environment variable's name is the concatenation of |
| 432 /// this prefix and the name (without the 'dart:'. |
| 433 /// |
| 434 /// For example 'dart:html' has the environment variable 'dart.library.html' set |
| 435 /// to "true". |
| 436 const String _dartLibraryEnvironmentPrefix = 'dart.library.'; |
| OLD | NEW |