Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(197)

Unified Diff: lib/src/compiler/compiler.dart

Issue 1879373004: Implement modular compilation (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/src/compiler/command.dart ('k') | lib/src/compiler/element_helpers.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/src/compiler/compiler.dart
diff --git a/lib/src/compiler/compiler.dart b/lib/src/compiler/compiler.dart
new file mode 100644
index 0000000000000000000000000000000000000000..31fb4999b5caeaf1c9078b60e956191f8fa83893
--- /dev/null
+++ b/lib/src/compiler/compiler.dart
@@ -0,0 +1,269 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:args/args.dart' show ArgParser, ArgResults;
+import 'package:analyzer/analyzer.dart'
+ show AnalysisError, CompilationUnit, ErrorSeverity;
+import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
+import 'package:analyzer/src/generated/java_engine.dart' show AnalysisException;
+import 'package:analyzer/src/generated/source_io.dart' show Source, SourceKind;
+import 'package:func/func.dart' show Func1;
+import 'package:path/path.dart' as path;
+
+import '../analyzer/context.dart'
+ show AnalyzerOptions, createAnalysisContextWithSources;
+import 'extension_types.dart' show ExtensionTypeSet;
+import 'code_generator.dart' show CodeGenerator;
+import 'error_helpers.dart' show errorSeverity, formatError, sortErrors;
+
+/// Compiles a set of Dart files into a single JavaScript module.
+///
+/// For a single [BuildUnit] definition, this will produce a [JSModuleFile].
+/// Those objects are record types that record the data consumed and produced
+/// for a single compile.
+///
+/// This class exists to cache global state associated with a single in-memory
+/// AnalysisContext, such as information about extension types in the Dart SDK.
+/// It can be used once to produce a single module, or reused to save warm-up
+/// time. (Currently there is no warm up, but there may be in the future.)
+///
+/// The SDK source code is assumed to be immutable for the life of this class.
+///
+/// For all other files, it is up to the [AnalysisContext] to decide whether or
+/// not any caching is performed. By default an analysis context will assume
+/// sources are immutable for the life of the context, and cache information
+/// about them.
+class ModuleCompiler {
+ final AnalysisContext context;
+ final _extensionTypes = new ExtensionTypeSet();
+
+ ModuleCompiler.withContext(this.context);
+
+ ModuleCompiler(AnalyzerOptions analyzerOptions)
+ : this.withContext(createAnalysisContextWithSources(analyzerOptions));
+
+ /// Compiles a single Dart build unit into a JavaScript module.
+ ///
+ /// *Warning* - this may require resolving the entire world.
+ /// If that is not desired, the analysis context must be pre-configured using
+ /// summaries before calling this method.
+ JSModuleFile compile(BuildUnit unit, CompilerOptions options) {
+ var trees = <CompilationUnit>[];
+ var errors = <AnalysisError>[];
+
+ for (var sourcePath in unit.sources) {
+ String sourceUri = sourcePath;
+ if (path.isRelative(sourcePath)) {
+ sourceUri = path.absolute(sourceUri);
+ }
+ sourceUri = path.toUri(sourceUri).toString();
+ Source source = context.sourceFactory.forUri(sourceUri);
+ if (source == null) {
+ throw new AnalysisException('could not create a source for $sourcePath.'
+ ' The file name is in the wrong format or was not found.');
+ }
+
+ // Ignore parts. They need to be handled in the context of their library.
+ if (context.getKindOf(source) == SourceKind.PART) {
+ continue;
+ }
+
+ var resolvedTree = context.resolveCompilationUnit2(source, source);
+ trees.add(resolvedTree);
+ errors.addAll(context.computeErrors(source));
+
+ var library = resolvedTree.element.library;
+ for (var part in library.parts) {
+ trees.add(context.resolveCompilationUnit(part.source, library));
+ errors.addAll(context.computeErrors(part.source));
+ }
+ }
+
+ sortErrors(context, errors);
+ var messages = <String>[];
+ for (var e in errors) {
+ var m = formatError(context, e);
+ if (m != null) messages.add(m);
+ }
+
+ if (!options.unsafeForceCompile &&
+ errors.any((e) => errorSeverity(context, e) == ErrorSeverity.ERROR)) {
+ return new JSModuleFile.invalid(unit.name, messages);
+ }
+
+ var codeGenerator = new CodeGenerator(context, options, _extensionTypes);
+ return codeGenerator.compile(unit, trees, messages);
+ }
+}
+
+enum ModuleFormat { es6, legacy, node }
+
+ModuleFormat parseModuleFormat(String s) => {
+ 'es6': ModuleFormat.es6,
+ 'node': ModuleFormat.node,
+ 'legacy': ModuleFormat.legacy
+ }[s];
+
+class CompilerOptions {
+ /// Whether to emit the source mapping file.
+ ///
+ /// This supports debugging the original source code instead of the generated
+ /// code.
+ final bool sourceMap;
+
+ /// If [sourceMap] is emitted, this will emit a `sourceMappingUrl` comment
+ /// into the output JavaScript module.
+ final bool sourceMapComment;
+
+ /// Whether to emit a summary file containing API signatures.
+ ///
+ /// This is required for a modular build process.
+ final bool summarizeApi;
+
+ /// Whether to force compilation of code with static errors.
+ final bool unsafeForceCompile;
+
+ /// Whether to emit Closure Compiler-friendly code.
+ final bool closure;
+
+ /// Enable ES6 destructuring of named parameters. Off by default.
+ ///
+ /// Older V8 versions do not accept default values with destructuring in
+ /// arrow functions yet (e.g. `({a} = {}) => 1`) but happily accepts them
+ /// with regular functions (e.g. `function({a} = {}) { return 1 }`).
+ ///
+ /// Supporting the syntax:
+ /// * Chrome Canary (51)
+ /// * Firefox
+ ///
+ /// Not yet supporting:
+ /// * Atom (1.5.4)
+ /// * Electron (0.36.3)
+ // TODO(ochafik): Simplify this code when our target platforms catch up.
+ final bool destructureNamedParams;
+
+ /// Which module format to support.
+ /// Currently 'es6' and 'legacy' are supported.
+ final ModuleFormat moduleFormat;
+
+ const CompilerOptions(
+ {this.sourceMap: true,
+ this.sourceMapComment: true,
+ this.summarizeApi: true,
+ this.unsafeForceCompile: false,
+ this.closure: false,
+ this.destructureNamedParams: false,
+ this.moduleFormat: ModuleFormat.legacy});
+
+ CompilerOptions.fromArguments(ArgResults args)
+ : sourceMap = args['source-map'],
+ sourceMapComment = args['source-map-comment'],
+ summarizeApi = args['summarize'],
+ unsafeForceCompile = args['unsafe-force-compile'],
+ closure = args['closure-experimental'],
+ destructureNamedParams = args['destructure-named-params'],
+ moduleFormat = parseModuleFormat(args['modules']);
+
+ static ArgParser addArguments(ArgParser parser) => parser
+ ..addFlag('summarize', help: 'emit an API summary file', defaultsTo: true)
+ ..addFlag('source-map', help: 'emit source mapping', defaultsTo: true)
+ ..addFlag('source-map-comment',
+ help: 'adds a sourceMappingURL comment to the end of the JS,\n'
+ 'disable if using X-SourceMap header',
+ defaultsTo: true)
+ ..addOption('modules',
+ help: 'module pattern to emit',
+ allowed: ['es6', 'legacy', 'node'],
+ allowedHelp: {
+ 'es6': 'es6 modules',
+ 'legacy': 'a custom format used by dartdevc, similar to AMD',
+ 'node': 'node.js modules (https://nodejs.org/api/modules.html)'
+ },
+ defaultsTo: 'legacy')
+ ..addFlag('closure-experimental',
+ help: 'emit Closure Compiler-friendly code (experimental)',
+ defaultsTo: false)
+ ..addFlag('destructure-named-params',
+ help: 'Destructure named parameters', defaultsTo: false)
+ ..addFlag('unsafe-force-compile',
+ help: 'Compile code even if it has errors. ಠ_ಠ\n'
+ 'This has undefined behavior!',
+ defaultsTo: false);
+}
+
+/// A unit of Dart code that can be built into a single JavaScript module.
+class BuildUnit {
+ /// The name of this module.
+ final String name;
+
+ /// The list of sources in this module.
+ ///
+ /// The set of Dart files can be arbitrarily large, but it must contain
+ /// complete libraries including all of their parts, as well as all libraries
+ /// that are part of a library cycle.
+ final List<String> sources;
+
+ /// Given an imported library URI, this will determine to what Dart/JS module
+ /// it belongs to.
+ // TODO(jmesserly): we should replace this with another way of tracking
+ // build units.
+ final Func1<Source, String> libraryToModule;
+
+ BuildUnit(this.name, this.sources, this.libraryToModule);
+}
+
+/// The output of Dart->JS compilation.
+///
+/// This contains the file contents of the JS module, as well as a list of
+/// Dart libraries that are contained in this module.
+class JSModuleFile {
+ /// The name of this module.
+ final String name;
+
+ /// The list of messages (errors and warnings)
+ final List<String> errors;
+
+ /// The JavaScript code for this module.
+ ///
+ /// If a [sourceMap] is available, this will include the `sourceMappingURL`
+ /// comment at end of the file.
+ final String code;
+
+ /// The JSON of the source map, if generated, otherwise `null`.
+ ///
+ /// The source paths will initially be absolute paths. They can be adjusted
+ /// using [placeSourceMap].
+ final Map sourceMap;
+
+ /// The binary contents of the API summary file, including APIs from each of
+ /// the [libraries] in this module.
+ final List<int> summaryBytes;
+
+ JSModuleFile(
+ this.name, this.errors, this.code, this.sourceMap, this.summaryBytes);
+
+ JSModuleFile.invalid(this.name, this.errors)
+ : code = null,
+ sourceMap = null,
+ summaryBytes = null;
+
+ /// True if this library was successfully compiled.
+ bool get isValid => code != null;
+
+ /// Adjusts the source paths in [sourceMap] to be relative to [sourceMapPath],
+ /// and returns the new map.
+ ///
+ /// See also [writeSourceMap].
+ Map placeSourceMap(String sourceMapPath) {
+ var dir = path.dirname(sourceMapPath);
+
+ var map = new Map.from(this.sourceMap);
+ List list = new List.from(map['sources']);
+ map['sources'] = list;
+ for (int i = 0; i < list.length; i++) {
+ list[i] = path.relative(list[i], from: dir);
+ }
+ return map;
+ }
+}
« no previous file with comments | « lib/src/compiler/command.dart ('k') | lib/src/compiler/element_helpers.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698