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

Side by Side 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 unified diff | 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 »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
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.
4
5 import 'package:args/args.dart' show ArgParser, ArgResults;
6 import 'package:analyzer/analyzer.dart'
7 show AnalysisError, CompilationUnit, ErrorSeverity;
8 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
9 import 'package:analyzer/src/generated/java_engine.dart' show AnalysisException;
10 import 'package:analyzer/src/generated/source_io.dart' show Source, SourceKind;
11 import 'package:func/func.dart' show Func1;
12 import 'package:path/path.dart' as path;
13
14 import '../analyzer/context.dart'
15 show AnalyzerOptions, createAnalysisContextWithSources;
16 import 'extension_types.dart' show ExtensionTypeSet;
17 import 'code_generator.dart' show CodeGenerator;
18 import 'error_helpers.dart' show errorSeverity, formatError, sortErrors;
19
20 /// Compiles a set of Dart files into a single JavaScript module.
21 ///
22 /// For a single [BuildUnit] definition, this will produce a [JSModuleFile].
23 /// Those objects are record types that record the data consumed and produced
24 /// for a single compile.
25 ///
26 /// This class exists to cache global state associated with a single in-memory
27 /// AnalysisContext, such as information about extension types in the Dart SDK.
28 /// It can be used once to produce a single module, or reused to save warm-up
29 /// time. (Currently there is no warm up, but there may be in the future.)
30 ///
31 /// The SDK source code is assumed to be immutable for the life of this class.
32 ///
33 /// For all other files, it is up to the [AnalysisContext] to decide whether or
34 /// not any caching is performed. By default an analysis context will assume
35 /// sources are immutable for the life of the context, and cache information
36 /// about them.
37 class ModuleCompiler {
38 final AnalysisContext context;
39 final _extensionTypes = new ExtensionTypeSet();
40
41 ModuleCompiler.withContext(this.context);
42
43 ModuleCompiler(AnalyzerOptions analyzerOptions)
44 : this.withContext(createAnalysisContextWithSources(analyzerOptions));
45
46 /// Compiles a single Dart build unit into a JavaScript module.
47 ///
48 /// *Warning* - this may require resolving the entire world.
49 /// If that is not desired, the analysis context must be pre-configured using
50 /// summaries before calling this method.
51 JSModuleFile compile(BuildUnit unit, CompilerOptions options) {
52 var trees = <CompilationUnit>[];
53 var errors = <AnalysisError>[];
54
55 for (var sourcePath in unit.sources) {
56 String sourceUri = sourcePath;
57 if (path.isRelative(sourcePath)) {
58 sourceUri = path.absolute(sourceUri);
59 }
60 sourceUri = path.toUri(sourceUri).toString();
61 Source source = context.sourceFactory.forUri(sourceUri);
62 if (source == null) {
63 throw new AnalysisException('could not create a source for $sourcePath.'
64 ' The file name is in the wrong format or was not found.');
65 }
66
67 // Ignore parts. They need to be handled in the context of their library.
68 if (context.getKindOf(source) == SourceKind.PART) {
69 continue;
70 }
71
72 var resolvedTree = context.resolveCompilationUnit2(source, source);
73 trees.add(resolvedTree);
74 errors.addAll(context.computeErrors(source));
75
76 var library = resolvedTree.element.library;
77 for (var part in library.parts) {
78 trees.add(context.resolveCompilationUnit(part.source, library));
79 errors.addAll(context.computeErrors(part.source));
80 }
81 }
82
83 sortErrors(context, errors);
84 var messages = <String>[];
85 for (var e in errors) {
86 var m = formatError(context, e);
87 if (m != null) messages.add(m);
88 }
89
90 if (!options.unsafeForceCompile &&
91 errors.any((e) => errorSeverity(context, e) == ErrorSeverity.ERROR)) {
92 return new JSModuleFile.invalid(unit.name, messages);
93 }
94
95 var codeGenerator = new CodeGenerator(context, options, _extensionTypes);
96 return codeGenerator.compile(unit, trees, messages);
97 }
98 }
99
100 enum ModuleFormat { es6, legacy, node }
101
102 ModuleFormat parseModuleFormat(String s) => {
103 'es6': ModuleFormat.es6,
104 'node': ModuleFormat.node,
105 'legacy': ModuleFormat.legacy
106 }[s];
107
108 class CompilerOptions {
109 /// Whether to emit the source mapping file.
110 ///
111 /// This supports debugging the original source code instead of the generated
112 /// code.
113 final bool sourceMap;
114
115 /// If [sourceMap] is emitted, this will emit a `sourceMappingUrl` comment
116 /// into the output JavaScript module.
117 final bool sourceMapComment;
118
119 /// Whether to emit a summary file containing API signatures.
120 ///
121 /// This is required for a modular build process.
122 final bool summarizeApi;
123
124 /// Whether to force compilation of code with static errors.
125 final bool unsafeForceCompile;
126
127 /// Whether to emit Closure Compiler-friendly code.
128 final bool closure;
129
130 /// Enable ES6 destructuring of named parameters. Off by default.
131 ///
132 /// Older V8 versions do not accept default values with destructuring in
133 /// arrow functions yet (e.g. `({a} = {}) => 1`) but happily accepts them
134 /// with regular functions (e.g. `function({a} = {}) { return 1 }`).
135 ///
136 /// Supporting the syntax:
137 /// * Chrome Canary (51)
138 /// * Firefox
139 ///
140 /// Not yet supporting:
141 /// * Atom (1.5.4)
142 /// * Electron (0.36.3)
143 // TODO(ochafik): Simplify this code when our target platforms catch up.
144 final bool destructureNamedParams;
145
146 /// Which module format to support.
147 /// Currently 'es6' and 'legacy' are supported.
148 final ModuleFormat moduleFormat;
149
150 const CompilerOptions(
151 {this.sourceMap: true,
152 this.sourceMapComment: true,
153 this.summarizeApi: true,
154 this.unsafeForceCompile: false,
155 this.closure: false,
156 this.destructureNamedParams: false,
157 this.moduleFormat: ModuleFormat.legacy});
158
159 CompilerOptions.fromArguments(ArgResults args)
160 : sourceMap = args['source-map'],
161 sourceMapComment = args['source-map-comment'],
162 summarizeApi = args['summarize'],
163 unsafeForceCompile = args['unsafe-force-compile'],
164 closure = args['closure-experimental'],
165 destructureNamedParams = args['destructure-named-params'],
166 moduleFormat = parseModuleFormat(args['modules']);
167
168 static ArgParser addArguments(ArgParser parser) => parser
169 ..addFlag('summarize', help: 'emit an API summary file', defaultsTo: true)
170 ..addFlag('source-map', help: 'emit source mapping', defaultsTo: true)
171 ..addFlag('source-map-comment',
172 help: 'adds a sourceMappingURL comment to the end of the JS,\n'
173 'disable if using X-SourceMap header',
174 defaultsTo: true)
175 ..addOption('modules',
176 help: 'module pattern to emit',
177 allowed: ['es6', 'legacy', 'node'],
178 allowedHelp: {
179 'es6': 'es6 modules',
180 'legacy': 'a custom format used by dartdevc, similar to AMD',
181 'node': 'node.js modules (https://nodejs.org/api/modules.html)'
182 },
183 defaultsTo: 'legacy')
184 ..addFlag('closure-experimental',
185 help: 'emit Closure Compiler-friendly code (experimental)',
186 defaultsTo: false)
187 ..addFlag('destructure-named-params',
188 help: 'Destructure named parameters', defaultsTo: false)
189 ..addFlag('unsafe-force-compile',
190 help: 'Compile code even if it has errors. ಠ_ಠ\n'
191 'This has undefined behavior!',
192 defaultsTo: false);
193 }
194
195 /// A unit of Dart code that can be built into a single JavaScript module.
196 class BuildUnit {
197 /// The name of this module.
198 final String name;
199
200 /// The list of sources in this module.
201 ///
202 /// The set of Dart files can be arbitrarily large, but it must contain
203 /// complete libraries including all of their parts, as well as all libraries
204 /// that are part of a library cycle.
205 final List<String> sources;
206
207 /// Given an imported library URI, this will determine to what Dart/JS module
208 /// it belongs to.
209 // TODO(jmesserly): we should replace this with another way of tracking
210 // build units.
211 final Func1<Source, String> libraryToModule;
212
213 BuildUnit(this.name, this.sources, this.libraryToModule);
214 }
215
216 /// The output of Dart->JS compilation.
217 ///
218 /// This contains the file contents of the JS module, as well as a list of
219 /// Dart libraries that are contained in this module.
220 class JSModuleFile {
221 /// The name of this module.
222 final String name;
223
224 /// The list of messages (errors and warnings)
225 final List<String> errors;
226
227 /// The JavaScript code for this module.
228 ///
229 /// If a [sourceMap] is available, this will include the `sourceMappingURL`
230 /// comment at end of the file.
231 final String code;
232
233 /// The JSON of the source map, if generated, otherwise `null`.
234 ///
235 /// The source paths will initially be absolute paths. They can be adjusted
236 /// using [placeSourceMap].
237 final Map sourceMap;
238
239 /// The binary contents of the API summary file, including APIs from each of
240 /// the [libraries] in this module.
241 final List<int> summaryBytes;
242
243 JSModuleFile(
244 this.name, this.errors, this.code, this.sourceMap, this.summaryBytes);
245
246 JSModuleFile.invalid(this.name, this.errors)
247 : code = null,
248 sourceMap = null,
249 summaryBytes = null;
250
251 /// True if this library was successfully compiled.
252 bool get isValid => code != null;
253
254 /// Adjusts the source paths in [sourceMap] to be relative to [sourceMapPath],
255 /// and returns the new map.
256 ///
257 /// See also [writeSourceMap].
258 Map placeSourceMap(String sourceMapPath) {
259 var dir = path.dirname(sourceMapPath);
260
261 var map = new Map.from(this.sourceMap);
262 List list = new List.from(map['sources']);
263 map['sources'] = list;
264 for (int i = 0; i < list.length; i++) {
265 list[i] = path.relative(list[i], from: dir);
266 }
267 return map;
268 }
269 }
OLDNEW
« 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