Index: pkg/front_end/lib/src/base/processed_options.dart |
diff --git a/pkg/front_end/lib/src/base/processed_options.dart b/pkg/front_end/lib/src/base/processed_options.dart |
index b2e93ab6008cb4553aec0ad17fb6d3d515a3733e..a42d2b54caa8c554bb705ee450a79a3a61a8ab64 100644 |
--- a/pkg/front_end/lib/src/base/processed_options.dart |
+++ b/pkg/front_end/lib/src/base/processed_options.dart |
@@ -4,27 +4,17 @@ |
import 'dart:async'; |
-import 'package:front_end/compilation_error.dart'; |
import 'package:front_end/compiler_options.dart'; |
import 'package:front_end/file_system.dart'; |
-import 'package:front_end/src/base/performace_logger.dart'; |
-import 'package:front_end/src/fasta/ticker.dart'; |
import 'package:front_end/src/fasta/translate_uri.dart'; |
+import 'package:front_end/src/base/performace_logger.dart'; |
import 'package:front_end/src/incremental/byte_store.dart'; |
-import 'package:kernel/kernel.dart' |
- show Program, loadProgramFromBytes, CanonicalName; |
-import 'package:kernel/target/targets.dart'; |
-import 'package:kernel/target/vm_fasta.dart'; |
+import 'package:front_end/src/simple_error.dart'; |
import 'package:package_config/packages_file.dart' as package_config; |
-import 'package:source_span/source_span.dart' show SourceSpan; |
+import 'package:kernel/kernel.dart' show Program, loadProgramFromBytes; |
-/// All options needed for the front end implementation. |
-/// |
-/// This includes: all of [CompilerOptions] in a form useful to the |
-/// implementation, default values for options that were not provided, |
-/// and information derived from how the compiler was invoked (like the |
-/// entry-points given to the compiler and whether a modular or whole-program |
-/// API was used). |
+/// Wrapper around [CompilerOptions] which exposes the options in a form useful |
+/// to the front end implementation. |
/// |
/// The intent is that the front end should immediately wrap any incoming |
/// [CompilerOptions] object in this class before doing further processing, and |
@@ -44,58 +34,19 @@ class ProcessedOptions { |
TranslateUri _uriTranslator; |
/// The SDK summary, or `null` if it has not been read yet. |
- /// |
- /// A summary, also referred to as "outline" internally, is a [Program] where |
- /// all method bodies are left out. In essence, it contains just API |
- /// signatures and constants. When strong-mode is enabled, the summary already |
- /// includes inferred types. |
Program _sdkSummaryProgram; |
/// The summary for each uri in `options.inputSummaries`. |
- /// |
- /// A summary, also referred to as "outline" internally, is a [Program] where |
- /// all method bodies are left out. In essence, it contains just API |
- /// signatures and constants. When strong-mode is enabled, the summary already |
- /// includes inferred types. |
List<Program> _inputSummariesPrograms; |
- /// Other programs that are meant to be linked and compiled with the input |
- /// sources. |
- List<Program> _linkedDependencies; |
- |
/// The location of the SDK, or `null` if the location hasn't been determined |
/// yet. |
Uri _sdkRoot; |
- Uri get sdkRoot => _sdkRoot ??= _normalizeSdkRoot(); |
- |
- Uri _sdkSummary; |
- Uri get sdkSummary => _sdkSummary ??= _computeSdkSummaryUri(); |
- Ticker ticker; |
- |
- bool get verbose => _raw.verbose; |
- |
- bool get verify => _raw.verify; |
- |
- bool get debugDump => _raw.debugDump; |
- |
- /// Like [CompilerOptions.chaseDependencies] but with the appropriate default |
- /// value filled in. |
- bool get chaseDependencies => _raw.chaseDependencies ?? !_modularApi; |
- |
- /// Whether the compiler was invoked with a modular API. |
- /// |
- /// Used to determine the default behavior for [chaseDependencies]. |
- final bool _modularApi; |
- |
- /// The entry-points provided to the compiler. |
- final List<Uri> inputs; |
+ Uri get sdkRoot => _sdkRoot ??= _normalizeSdkRoot(); |
/// Initializes a [ProcessedOptions] object wrapping the given [rawOptions]. |
- ProcessedOptions(CompilerOptions rawOptions, |
- [this._modularApi = false, this.inputs = const []]) |
- : this._raw = rawOptions, |
- ticker = new Ticker(isVerbose: rawOptions.verbose); |
+ ProcessedOptions(CompilerOptions rawOptions) : this._raw = rawOptions; |
/// The logger to report compilation progress. |
PerformanceLog get logger { |
@@ -107,40 +58,28 @@ class ProcessedOptions { |
return _raw.byteStore; |
} |
- // TODO(sigmund): delete. We should use messages with error codes directly |
- // instead. |
- void reportError(String message) { |
- _raw.onError(new _CompilationError(message)); |
- } |
- |
/// Runs various validations checks on the input options. For instance, |
/// if an option is a path to a file, it checks that the file exists. |
Future<bool> validateOptions() async { |
- for (var source in inputs) { |
- if (source.scheme == 'file' && |
- !await fileSystem.entityForUri(source).exists()) { |
- reportError("Entry-point file not found: $source"); |
- return false; |
- } |
- } |
+ var fs = _raw.fileSystem; |
+ var root = _raw.sdkRoot; |
- if (_raw.sdkRoot != null && |
- !await fileSystem.entityForUri(sdkRoot).exists()) { |
- reportError("SDK root directory not found: ${sdkRoot}"); |
+ bool _report(String msg) { |
+ _raw.onError(new SimpleError(msg)); |
return false; |
} |
- var summary = sdkSummary; |
- if (summary != null && !await fileSystem.entityForUri(summary).exists()) { |
- reportError("SDK summary not found: ${summary}"); |
- return false; |
+ if (root != null && !await fs.entityForUri(root).exists()) { |
+ return _report("SDK root directory not found: ${_raw.sdkRoot}"); |
} |
- if (compileSdk && summary != null) { |
- reportError( |
- "The compileSdk and sdkSummary options are mutually exclusive"); |
- return false; |
+ var summary = _raw.sdkSummary; |
+ if (summary != null && !await fs.entityForUri(summary).exists()) { |
+ return _report("SDK summary not found: ${_raw.sdkSummary}"); |
} |
+ |
+ // TODO(sigmund): add checks for options that are meant to be disjoint (like |
+ // sdkRoot and sdkSummary). |
return true; |
} |
@@ -148,67 +87,43 @@ class ProcessedOptions { |
/// whole-program. |
bool get compileSdk => _raw.compileSdk; |
- FileSystem _fileSystem; |
- |
/// Get the [FileSystem] which should be used by the front end to access |
/// files. |
/// |
/// If the client supplied roots using [CompilerOptions.multiRoots], the |
/// returned [FileSystem] will automatically perform the appropriate mapping. |
- FileSystem get fileSystem => _fileSystem ??= _createFileSystem(); |
+ FileSystem get fileSystem { |
+ // TODO(paulberry): support multiRoots. |
+ assert(_raw.multiRoots.isEmpty); |
+ return _raw.fileSystem; |
+ } |
/// Whether to interpret Dart sources in strong-mode. |
bool get strongMode => _raw.strongMode; |
- Target _target; |
- Target get target => _target ??= |
- _raw.target ?? new VmFastaTarget(new TargetFlags(strongMode: strongMode)); |
- |
- /// Get an outline program that summarizes the SDK, if any. |
- // TODO(sigmund): move, this doesn't feel like an "option". |
- Future<Program> loadSdkSummary(CanonicalName nameRoot) async { |
+ /// Get an outline program that summarizes the SDK. |
+ Future<Program> get sdkSummaryProgram async { |
if (_sdkSummaryProgram == null) { |
- if (sdkSummary == null) return null; |
- var bytes = await fileSystem.entityForUri(sdkSummary).readAsBytes(); |
- _sdkSummaryProgram = loadProgram(bytes, nameRoot); |
+ if (_raw.sdkSummary == null) return null; |
+ _sdkSummaryProgram = await _loadProgram(_raw.sdkSummary); |
} |
return _sdkSummaryProgram; |
} |
/// Get the summary programs for each of the underlying `inputSummaries` |
/// provided via [CompilerOptions]. |
- // TODO(sigmund): move, this doesn't feel like an "option". |
- Future<List<Program>> loadInputSummaries(CanonicalName nameRoot) async { |
+ Future<List<Program>> get inputSummariesPrograms async { |
if (_inputSummariesPrograms == null) { |
var uris = _raw.inputSummaries; |
if (uris == null || uris.isEmpty) return const <Program>[]; |
- // TODO(sigmund): throttle # of concurrent opreations. |
- var allBytes = await Future |
- .wait(uris.map((uri) => fileSystem.entityForUri(uri).readAsBytes())); |
- _inputSummariesPrograms = |
- allBytes.map((bytes) => loadProgram(bytes, nameRoot)).toList(); |
+ _inputSummariesPrograms = await Future.wait(uris.map(_loadProgram)); |
} |
return _inputSummariesPrograms; |
} |
- /// Load each of the [CompilerOptions.linkedDependencies] programs. |
- // TODO(sigmund): move, this doesn't feel like an "option". |
- Future<List<Program>> loadLinkDependencies(CanonicalName nameRoot) async { |
- if (_linkedDependencies == null) { |
- var uris = _raw.linkedDependencies; |
- if (uris == null || uris.isEmpty) return const <Program>[]; |
- // TODO(sigmund): throttle # of concurrent opreations. |
- var allBytes = await Future |
- .wait(uris.map((uri) => fileSystem.entityForUri(uri).readAsBytes())); |
- _linkedDependencies = |
- allBytes.map((bytes) => loadProgram(bytes, nameRoot)).toList(); |
- } |
- return _linkedDependencies; |
- } |
- |
- /// Helper to load a .dill file from [uri] using the existing [nameRoot]. |
- Program loadProgram(List<int> bytes, CanonicalName nameRoot) { |
- return loadProgramFromBytes(bytes, new Program(nameRoot: nameRoot)); |
+ Future<Program> _loadProgram(Uri uri) async { |
+ var bytes = await fileSystem.entityForUri(uri).readAsBytes(); |
+ return loadProgramFromBytes(bytes)..unbindCanonicalNames(); |
} |
/// Get the [TranslateUri] which resolves "package:" and "dart:" URIs. |
@@ -220,19 +135,13 @@ class ProcessedOptions { |
await _getPackages(); |
// TODO(scheglov) Load SDK libraries from whatever format we decide. |
// TODO(scheglov) Remove the field "_raw.dartLibraries". |
- var libraries = _raw.dartLibraries ?? await _parseLibraries(); |
- _uriTranslator = |
- new TranslateUri(_packages, libraries, const <String, List<Uri>>{}); |
- ticker.logMs("Read packages file"); |
+ _uriTranslator = new TranslateUri( |
+ _packages, _raw.dartLibraries, const <String, List<Uri>>{}); |
+ _uriTranslator.dartLibraries.addAll(_raw.dartLibraries); |
} |
return _uriTranslator; |
} |
- Future<Map<String, Uri>> _parseLibraries() async { |
- Uri librariesJson = _raw.sdkRoot?.resolve("lib/libraries.json"); |
- return await computeLibraries(fileSystem, librariesJson); |
- } |
- |
/// Get the package map which maps package names to URIs. |
/// |
/// This is an asynchronous getter since file system operations may be |
@@ -240,8 +149,7 @@ class ProcessedOptions { |
Future<Map<String, Uri>> _getPackages() async { |
if (_packages == null) { |
if (_raw.packagesFileUri == null) { |
- // TODO(sigmund,paulberry): implement |
- throw new UnimplementedError('search for .packages'); |
+ throw new UnimplementedError(); // TODO(paulberry): search for .packages |
} else if (_raw.packagesFileUri.path.isEmpty) { |
_packages = {}; |
} else { |
@@ -254,6 +162,9 @@ class ProcessedOptions { |
} |
/// Get the location of the SDK. |
+ /// |
+ /// This is an asynchronous getter since file system operations may be |
+ /// required to locate the SDK. |
Uri _normalizeSdkRoot() { |
// If an SDK summary location was provided, the SDK itself should not be |
// needed. |
@@ -261,89 +172,12 @@ class ProcessedOptions { |
if (_raw.sdkRoot == null) { |
// TODO(paulberry): implement the algorithm for finding the SDK |
// automagically. |
- throw new UnimplementedError('infer the default sdk location'); |
+ throw new UnimplementedError(); |
} |
var root = _raw.sdkRoot; |
if (!root.path.endsWith('/')) { |
- root = root.replace(path: root.path + '/'); |
+ root = root.replace(path: _sdkRoot.path + '/'); |
} |
return root; |
} |
- |
- /// Get or infer the location of the SDK summary. |
- Uri _computeSdkSummaryUri() { |
- if (_raw.sdkSummary != null) return _raw.sdkSummary; |
- |
- // Infer based on the sdkRoot, but only when `compileSdk` is false, |
- // otherwise the default intent was to compile the sdk from sources and not |
- // to load an sdk summary file. |
- if (_raw.compileSdk) return null; |
- return sdkRoot.resolve('outline.dill'); |
- } |
- |
- /// Create a [FileSystem] specific to the current options. |
- /// |
- /// If [chaseDependencies] is false, the resulting file system will be |
- /// hermetic. |
- FileSystem _createFileSystem() { |
- var result = _raw.fileSystem; |
- if (!chaseDependencies) { |
- var allInputs = inputs.toSet(); |
- allInputs.addAll(_raw.inputSummaries); |
- allInputs.addAll(_raw.linkedDependencies); |
- |
- if (sdkSummary != null) allInputs.add(sdkSummary); |
- |
- if (_raw.sdkRoot != null) { |
- // TODO(sigmund): refine this, we should be more explicit about when |
- // sdkRoot and libraries.json are allowed to be used. |
- allInputs.add(sdkRoot); |
- allInputs.add(sdkRoot.resolve("lib/libraries.json")); |
- } |
- |
- /// Note: Searching the file-system for the package-config is not |
- /// supported in hermetic builds. |
- if (_raw.packagesFileUri != null) allInputs.add(_raw.packagesFileUri); |
- result = new HermeticFileSystem(allInputs, result); |
- } |
- // TODO(paulberry): support multiRoots. |
- assert(_raw.multiRoots.isEmpty); |
- return result; |
- } |
-} |
- |
-/// A [FileSystem] that only allows access to files that have been explicitly |
-/// whitelisted. |
-class HermeticFileSystem implements FileSystem { |
- final Set<Uri> includedFiles; |
- final FileSystem _realFileSystem; |
- |
- HermeticFileSystem(this.includedFiles, this._realFileSystem); |
- |
- FileSystemEntity entityForUri(Uri uri) { |
- if (includedFiles.contains(uri)) return _realFileSystem.entityForUri(uri); |
- throw new HermeticAccessException(uri); |
- } |
-} |
- |
-class HermeticAccessException extends FileSystemException { |
- HermeticAccessException(Uri uri) |
- : super( |
- uri, |
- 'Invalid access to $uri: ' |
- 'the file is accessed in a modular hermetic build, ' |
- 'but it was not explicitly listed as an input.'); |
- |
- @override |
- String toString() => message; |
-} |
- |
-/// An error that only contains a message and no error location. |
-class _CompilationError implements CompilationError { |
- String get correction => null; |
- SourceSpan get span => null; |
- final String message; |
- _CompilationError(this.message); |
- |
- String toString() => message; |
} |