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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/dart2js.dart

Issue 694353007: Move dart2js from sdk/lib/_internal/compiler to pkg/compiler (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2013, 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 library dart2js.cmdline;
6
7 import 'dart:async'
8 show Future, EventSink;
9 import 'dart:convert' show UTF8, LineSplitter;
10 import 'dart:io'
11 show exit, File, FileMode, Platform, RandomAccessFile, FileSystemException,
12 stdin, stderr;
13
14 import '../compiler.dart' as api;
15 import 'source_file.dart';
16 import 'source_file_provider.dart';
17 import 'filenames.dart';
18 import 'util/uri_extras.dart';
19 import 'util/util.dart' show stackTraceFilePrefix;
20 import 'util/command_line.dart';
21 import '../../libraries.dart';
22
23 const String LIBRARY_ROOT = '../../../../..';
24 const String OUTPUT_LANGUAGE_DART = 'Dart';
25
26 /**
27 * A string to identify the revision or build.
28 *
29 * This ID is displayed if the compiler crashes and in verbose mode, and is
30 * an aid in reproducing bug reports.
31 *
32 * The actual string is rewritten by a wrapper script when included in the sdk.
33 */
34 String BUILD_ID = null;
35
36 /**
37 * The data passed to the [HandleOption] callback is either a single
38 * string argument, or the arguments iterator for multiple arguments
39 * handlers.
40 */
41 typedef void HandleOption(data);
42
43 class OptionHandler {
44 final String pattern;
45 final HandleOption handle;
46 final bool multipleArguments;
47
48 OptionHandler(this.pattern, this.handle, {this.multipleArguments: false});
49 }
50
51 /**
52 * Extract the parameter of an option.
53 *
54 * For example, in ['--out=fisk.js'] and ['-ohest.js'], the parameters
55 * are ['fisk.js'] and ['hest.js'], respectively.
56 */
57 String extractParameter(String argument, {bool isOptionalArgument: false}) {
58 // m[0] is the entire match (which will be equal to argument). m[1]
59 // is something like "-o" or "--out=", and m[2] is the parameter.
60 Match m = new RegExp('^(-[a-z]|--.+=)(.*)').firstMatch(argument);
61 if (m == null) {
62 if (isOptionalArgument) return null;
63 helpAndFail('Unknown option "$argument".');
64 }
65 return m[2];
66 }
67
68 String extractPath(String argument) {
69 String path = nativeToUriPath(extractParameter(argument));
70 return path.endsWith("/") ? path : "$path/";
71 }
72
73 void parseCommandLine(List<OptionHandler> handlers, List<String> argv) {
74 // TODO(ahe): Use ../../args/args.dart for parsing options instead.
75 var patterns = <String>[];
76 for (OptionHandler handler in handlers) {
77 patterns.add(handler.pattern);
78 }
79 var pattern = new RegExp('^(${patterns.join(")\$|^(")})\$');
80
81 Iterator<String> arguments = argv.iterator;
82 OUTER: while (arguments.moveNext()) {
83 String argument = arguments.current;
84 Match match = pattern.firstMatch(argument);
85 assert(match.groupCount == handlers.length);
86 for (int i = 0; i < handlers.length; i++) {
87 if (match[i + 1] != null) {
88 OptionHandler handler = handlers[i];
89 if (handler.multipleArguments) {
90 handler.handle(arguments);
91 } else {
92 handler.handle(argument);
93 }
94 continue OUTER;
95 }
96 }
97 throw 'Internal error: "$argument" did not match';
98 }
99 }
100
101 FormattingDiagnosticHandler diagnosticHandler;
102
103 Future compile(List<String> argv) {
104 stackTraceFilePrefix = '$currentDirectory';
105 Uri libraryRoot = currentDirectory;
106 Uri out = currentDirectory.resolve('out.js');
107 Uri sourceMapOut = currentDirectory.resolve('out.js.map');
108 Uri packageRoot = null;
109 List<String> options = new List<String>();
110 bool explicitOut = false;
111 bool wantHelp = false;
112 bool wantVersion = false;
113 String outputLanguage = 'JavaScript';
114 bool stripArgumentSet = false;
115 bool analyzeOnly = false;
116 bool analyzeAll = false;
117 bool enableAsyncAwait = false;
118 bool trustTypeAnnotations = false;
119 bool checkedMode = false;
120 // List of provided options that imply that output is expected.
121 List<String> optionsImplyCompilation = <String>[];
122 bool hasDisallowUnsafeEval = false;
123 // TODO(johnniwinther): Measure time for reading files.
124 SourceFileProvider inputProvider = new CompilerSourceFileProvider();
125 diagnosticHandler = new FormattingDiagnosticHandler(inputProvider);
126 Map<String, dynamic> environment = new Map<String, dynamic>();
127
128 passThrough(String argument) => options.add(argument);
129
130 if (BUILD_ID != null) {
131 passThrough("--build-id=$BUILD_ID");
132 }
133
134 setLibraryRoot(String argument) {
135 libraryRoot = currentDirectory.resolve(extractPath(argument));
136 }
137
138 setPackageRoot(String argument) {
139 packageRoot = currentDirectory.resolve(extractPath(argument));
140 }
141
142 setOutput(Iterator<String> arguments) {
143 optionsImplyCompilation.add(arguments.current);
144 String path;
145 if (arguments.current == '-o') {
146 if (!arguments.moveNext()) {
147 helpAndFail('Error: Missing file after -o option.');
148 }
149 path = arguments.current;
150 } else {
151 path = extractParameter(arguments.current);
152 }
153 explicitOut = true;
154 out = currentDirectory.resolve(nativeToUriPath(path));
155 sourceMapOut = Uri.parse('$out.map');
156 }
157
158 setOutputType(String argument) {
159 optionsImplyCompilation.add(argument);
160 if (argument == '--output-type=dart' ||
161 argument == '--output-type=dart-multi') {
162 outputLanguage = OUTPUT_LANGUAGE_DART;
163 if (!explicitOut) {
164 out = currentDirectory.resolve('out.dart');
165 sourceMapOut = currentDirectory.resolve('out.dart.map');
166 }
167 }
168 passThrough(argument);
169 }
170
171 String getDepsOutput(Map<String, SourceFile> sourceFiles) {
172 var filenames = new List.from(sourceFiles.keys);
173 filenames.sort();
174 return filenames.join("\n");
175 }
176
177 setStrip(String argument) {
178 optionsImplyCompilation.add(argument);
179 stripArgumentSet = true;
180 passThrough(argument);
181 }
182
183 setAnalyzeOnly(String argument) {
184 analyzeOnly = true;
185 passThrough(argument);
186 }
187
188 setAnalyzeAll(String argument) {
189 analyzeAll = true;
190 passThrough(argument);
191 }
192
193 setEnableAsync(String argument) {
194 enableAsyncAwait = true;
195 passThrough(argument);
196 }
197
198 setVerbose(_) {
199 diagnosticHandler.verbose = true;
200 passThrough('--verbose');
201 }
202
203 implyCompilation(String argument) {
204 optionsImplyCompilation.add(argument);
205 passThrough(argument);
206 }
207
208 setTrustTypeAnnotations(String argument) {
209 trustTypeAnnotations = true;
210 implyCompilation(argument);
211 }
212
213 setCheckedMode(String argument) {
214 checkedMode = true;
215 passThrough(argument);
216 }
217
218 addInEnvironment(String argument) {
219 int eqIndex = argument.indexOf('=');
220 String name = argument.substring(2, eqIndex);
221 String value = argument.substring(eqIndex + 1);
222 environment[name] = value;
223 }
224
225 setCategories(String argument) {
226 List<String> categories = extractParameter(argument).split(',');
227 Set<String> allowedCategories =
228 LIBRARIES.values.map((x) => x.category).toSet();
229 allowedCategories.remove('Shared');
230 allowedCategories.remove('Internal');
231 List<String> allowedCategoriesList =
232 new List<String>.from(allowedCategories);
233 allowedCategoriesList.sort();
234 if (categories.contains('all')) {
235 categories = allowedCategoriesList;
236 } else {
237 String allowedCategoriesString = allowedCategoriesList.join(', ');
238 for (String category in categories) {
239 if (!allowedCategories.contains(category)) {
240 fail('Unsupported library category "$category", '
241 'supported categories are: $allowedCategoriesString');
242 }
243 }
244 }
245 passThrough('--categories=${categories.join(",")}');
246 }
247
248 void handleThrowOnError(String argument) {
249 diagnosticHandler.throwOnError = true;
250 String parameter = extractParameter(argument, isOptionalArgument: true);
251 if (parameter != null) {
252 diagnosticHandler.throwOnErrorCount = int.parse(parameter);
253 }
254 }
255
256 handleShortOptions(String argument) {
257 var shortOptions = argument.substring(1).split("");
258 for (var shortOption in shortOptions) {
259 switch (shortOption) {
260 case 'v':
261 setVerbose(null);
262 break;
263 case 'h':
264 case '?':
265 wantHelp = true;
266 break;
267 case 'c':
268 setCheckedMode('--enable-checked-mode');
269 break;
270 case 'm':
271 implyCompilation('--minify');
272 break;
273 default:
274 throw 'Internal error: "$shortOption" did not match';
275 }
276 }
277 }
278
279 List<String> arguments = <String>[];
280 List<OptionHandler> handlers = <OptionHandler>[
281 new OptionHandler('-[chvm?]+', handleShortOptions),
282 new OptionHandler('--throw-on-error(?:=[0-9]+)?', handleThrowOnError),
283 new OptionHandler('--suppress-warnings', (_) {
284 diagnosticHandler.showWarnings = false;
285 passThrough('--suppress-warnings');
286 }),
287 new OptionHandler('--suppress-hints',
288 (_) => diagnosticHandler.showHints = false),
289 new OptionHandler(
290 '--output-type=dart|--output-type=dart-multi|--output-type=js',
291 setOutputType),
292 new OptionHandler('--verbose', setVerbose),
293 new OptionHandler('--version', (_) => wantVersion = true),
294 new OptionHandler('--library-root=.+', setLibraryRoot),
295 new OptionHandler('--out=.+|-o.*', setOutput, multipleArguments: true),
296 new OptionHandler('--allow-mock-compilation', passThrough),
297 new OptionHandler('--minify|-m', implyCompilation),
298 new OptionHandler('--preserve-uris', passThrough),
299 new OptionHandler('--force-strip=.*', setStrip),
300 new OptionHandler('--disable-diagnostic-colors',
301 (_) => diagnosticHandler.enableColors = false),
302 new OptionHandler('--enable-diagnostic-colors',
303 (_) => diagnosticHandler.enableColors = true),
304 new OptionHandler('--enable[_-]checked[_-]mode|--checked',
305 (_) => setCheckedMode('--enable-checked-mode')),
306 new OptionHandler('--enable-concrete-type-inference',
307 (_) => implyCompilation(
308 '--enable-concrete-type-inference')),
309 new OptionHandler('--trust-type-annotations',
310 (_) => setTrustTypeAnnotations(
311 '--trust-type-annotations')),
312 new OptionHandler(r'--help|/\?|/h', (_) => wantHelp = true),
313 new OptionHandler('--package-root=.+|-p.+', setPackageRoot),
314 new OptionHandler('--analyze-all', setAnalyzeAll),
315 new OptionHandler('--analyze-only', setAnalyzeOnly),
316 new OptionHandler('--analyze-signatures-only', setAnalyzeOnly),
317 new OptionHandler('--disable-native-live-type-analysis', passThrough),
318 new OptionHandler('--categories=.*', setCategories),
319 new OptionHandler('--disable-type-inference', implyCompilation),
320 new OptionHandler('--terse', passThrough),
321 new OptionHandler('--dump-info', implyCompilation),
322 new OptionHandler('--disallow-unsafe-eval',
323 (_) => hasDisallowUnsafeEval = true),
324 new OptionHandler('--show-package-warnings', passThrough),
325 new OptionHandler('--csp', passThrough),
326 new OptionHandler('--enable-async', setEnableAsync),
327 new OptionHandler('-D.+=.*', addInEnvironment),
328
329 // The following two options must come last.
330 new OptionHandler('-.*', (String argument) {
331 helpAndFail("Unknown option '$argument'.");
332 }),
333 new OptionHandler('.*', (String argument) {
334 arguments.add(nativeToUriPath(argument));
335 })
336 ];
337
338 parseCommandLine(handlers, argv);
339 if (wantHelp || wantVersion) {
340 helpAndExit(wantHelp, wantVersion, diagnosticHandler.verbose);
341 }
342
343 if (hasDisallowUnsafeEval) {
344 String precompiledName =
345 relativize(currentDirectory,
346 RandomAccessFileOutputProvider.computePrecompiledUri(out),
347 Platform.isWindows);
348 helpAndFail("Option '--disallow-unsafe-eval' has been removed."
349 " Instead, the compiler generates a file named"
350 " '$precompiledName'.");
351 }
352
353 if (outputLanguage != OUTPUT_LANGUAGE_DART && stripArgumentSet) {
354 helpAndFail("Option '--force-strip' may only be used with "
355 "'--output-type=dart'.");
356 }
357 if (arguments.isEmpty) {
358 helpAndFail('No Dart file specified.');
359 }
360 if (arguments.length > 1) {
361 var extra = arguments.sublist(1);
362 helpAndFail('Extra arguments: ${extra.join(" ")}');
363 }
364
365 if (checkedMode && trustTypeAnnotations) {
366 helpAndFail("Option '--trust-type-annotations' may not be used in "
367 "checked mode.");
368 }
369
370 Uri uri = currentDirectory.resolve(arguments[0]);
371 if (packageRoot == null) {
372 packageRoot = uri.resolve('./packages/');
373 }
374
375 if ((analyzeOnly || analyzeAll) && !optionsImplyCompilation.isEmpty) {
376 if (!analyzeOnly) {
377 diagnosticHandler.info(
378 "Option '--analyze-all' implies '--analyze-only'.",
379 api.Diagnostic.INFO);
380 }
381 diagnosticHandler.info(
382 "Options $optionsImplyCompilation indicate that output is expected, "
383 "but compilation is turned off by the option '--analyze-only'.",
384 api.Diagnostic.INFO);
385 }
386 if (analyzeAll) analyzeOnly = true;
387 if (enableAsyncAwait && !analyzeOnly) {
388 helpAndFail("Option '--enable-async' is currently only supported in "
389 "combination with the '--analyze-only' option.");
390 }
391
392 diagnosticHandler.info('Package root is $packageRoot');
393
394 options.add('--out=$out');
395 options.add('--source-map=$sourceMapOut');
396
397 RandomAccessFileOutputProvider outputProvider =
398 new RandomAccessFileOutputProvider(
399 out, sourceMapOut, onInfo: diagnosticHandler.info, onFailure: fail);
400
401 compilationDone(String code) {
402 if (analyzeOnly) return;
403 if (code == null) {
404 fail('Compilation failed.');
405 }
406 writeString(Uri.parse('$out.deps'),
407 getDepsOutput(inputProvider.sourceFiles));
408 diagnosticHandler.info(
409 'Compiled ${inputProvider.dartCharactersRead} characters Dart '
410 '-> ${outputProvider.totalCharactersWritten} characters '
411 '$outputLanguage in '
412 '${relativize(currentDirectory, out, Platform.isWindows)}');
413 if (diagnosticHandler.verbose) {
414 String input = uriPathToNative(arguments[0]);
415 print('Dart file ($input) compiled to $outputLanguage.');
416 print('Wrote the following files:');
417 for (String filename in outputProvider.allOutputFiles) {
418 print(" $filename");
419 }
420 } else if (!explicitOut) {
421 String input = uriPathToNative(arguments[0]);
422 String output = relativize(currentDirectory, out, Platform.isWindows);
423 print('Dart file ($input) compiled to $outputLanguage: $output');
424 }
425 }
426
427 return compileFunc(uri, libraryRoot, packageRoot,
428 inputProvider, diagnosticHandler,
429 options, outputProvider, environment)
430 .then(compilationDone);
431 }
432
433 class AbortLeg {
434 final message;
435 AbortLeg(this.message);
436 toString() => 'Aborted due to --throw-on-error: $message';
437 }
438
439 void writeString(Uri uri, String text) {
440 if (uri.scheme != 'file') {
441 fail('Unhandled scheme ${uri.scheme}.');
442 }
443 var file = new File(uri.toFilePath()).openSync(mode: FileMode.WRITE);
444 file.writeStringSync(text);
445 file.closeSync();
446 }
447
448 void fail(String message) {
449 if (diagnosticHandler != null) {
450 diagnosticHandler.diagnosticHandler(
451 null, -1, -1, message, api.Diagnostic.ERROR);
452 } else {
453 print('Error: $message');
454 }
455 exitFunc(1);
456 }
457
458 Future compilerMain(List<String> arguments) {
459 var root = uriPathToNative("/$LIBRARY_ROOT");
460 arguments = <String>['--library-root=${Platform.script.toFilePath()}$root']
461 ..addAll(arguments);
462 return compile(arguments);
463 }
464
465 void help() {
466 // This message should be no longer than 20 lines. The default
467 // terminal size normally 80x24. Two lines are used for the prompts
468 // before and after running the compiler. Another two lines may be
469 // used to print an error message.
470 print('''
471 Usage: dart2js [options] dartfile
472
473 Compiles Dart to JavaScript.
474
475 Common options:
476 -o <file> Generate the output into <file>.
477 -c Insert runtime type checks and enable assertions (checked mode).
478 -m Generate minified output.
479 -h Display this message (add -v for information about all options).''') ;
480 }
481
482 void verboseHelp() {
483 print(r'''
484 Usage: dart2js [options] dartfile
485
486 Compiles Dart to JavaScript.
487
488 Supported options:
489 -o <file>, --out=<file>
490 Generate the output into <file>.
491
492 -c, --enable-checked-mode, --checked
493 Insert runtime type checks and enable assertions (checked mode).
494
495 -m, --minify
496 Generate minified output.
497
498 -h, /h, /?, --help
499 Display this message (add -v for information about all options).
500
501 -v, --verbose
502 Display verbose information.
503
504 -D<name>=<value>
505 Define an environment variable.
506
507 --version
508 Display version information.
509
510 -p<path>, --package-root=<path>
511 Where to find packages, that is, "package:..." imports.
512
513 --analyze-all
514 Analyze all code. Without this option, the compiler only analyzes
515 code that is reachable from [main]. This option implies --analyze-only.
516
517 --analyze-only
518 Analyze but do not generate code.
519
520 --analyze-signatures-only
521 Skip analysis of method bodies and field initializers. This option implies
522 --analyze-only.
523
524 --suppress-warnings
525 Do not display any warnings.
526
527 --suppress-hints
528 Do not display any hints.
529
530 --enable-diagnostic-colors
531 Add colors to diagnostic messages.
532
533 --terse
534 Emit diagnostics without suggestions for how to get rid of the diagnosed
535 problems.
536
537 --show-package-warnings
538 Show warnings and hints generated from packages.
539
540 --preserve-uris
541 Preserve the source URIs in the reflection data. Without this flag the
542 `uri` getter for `LibraryMirror`s is mangled in minified mode.
543
544 --csp
545 Disables dynamic generation of code in the generated output. This is
546 necessary to satisfy CSP restrictions (see http://www.w3.org/TR/CSP/).
547
548 The following options are only used for compiler development and may
549 be removed in a future version:
550
551 --output-type=dart
552 Output Dart code instead of JavaScript.
553
554 --throw-on-error
555 Throw an exception if a compile-time error is detected.
556
557 --library-root=<directory>
558 Where to find the Dart platform libraries.
559
560 --allow-mock-compilation
561 Do not generate a call to main if either of the following
562 libraries are used: dart:dom, dart:html dart:io.
563
564 --enable-concrete-type-inference
565 Enable experimental concrete type inference.
566
567 --disable-native-live-type-analysis
568 Disable the optimization that removes unused native types from dart:html
569 and related libraries.
570
571 --categories=<categories>
572 A comma separated list of allowed library categories. The default
573 is "Client". Possible categories can be seen by providing an
574 unsupported category, for example, --categories=help. To enable
575 all categories, use --categories=all.
576
577 --dump-info
578 Generates an out.info.json file with information about the generated code.
579 You can inspect the generated file with the viewer at:
580 https://dart-lang.github.io/dump-info-visualizer/
581
582 '''.trim());
583 }
584
585 void helpAndExit(bool wantHelp, bool wantVersion, bool verbose) {
586 if (wantVersion) {
587 var version = (BUILD_ID == null)
588 ? '<non-SDK build>'
589 : BUILD_ID;
590 print('Dart-to-JavaScript compiler (dart2js) version: $version');
591 }
592 if (wantHelp) {
593 if (verbose) {
594 verboseHelp();
595 } else {
596 help();
597 }
598 }
599 exitFunc(0);
600 }
601
602 void helpAndFail(String message) {
603 help();
604 print('');
605 fail(message);
606 }
607
608 void main(List<String> arguments) {
609 // Since the sdk/bin/dart2js script adds its own arguments in front of
610 // user-supplied arguments we search for '--batch' at the end of the list.
611 if (arguments.length > 0 && arguments.last == "--batch") {
612 batchMain(arguments.sublist(0, arguments.length - 1));
613 return;
614 }
615 internalMain(arguments);
616 }
617
618 var exitFunc = exit;
619 var compileFunc = api.compile;
620
621 Future internalMain(List<String> arguments) {
622 onError(exception, trace) {
623 try {
624 print('The compiler crashed: $exception');
625 } catch (ignored) {
626 print('The compiler crashed: error while printing exception');
627 }
628
629 try {
630 if (trace != null) {
631 print(trace);
632 }
633 } finally {
634 exitFunc(253); // 253 is recognized as a crash by our test scripts.
635 }
636 }
637
638 try {
639 return compilerMain(arguments).catchError(onError);
640 } catch (exception, trace) {
641 onError(exception, trace);
642 return new Future.value();
643 }
644 }
645
646 const _EXIT_SIGNAL = const Object();
647
648 void batchMain(List<String> batchArguments) {
649 int exitCode;
650 exitFunc = (errorCode) {
651 // Since we only throw another part of the compiler might intercept our
652 // exception and try to exit with a different code.
653 if (exitCode == 0) {
654 exitCode = errorCode;
655 }
656 throw _EXIT_SIGNAL;
657 };
658
659 var stream = stdin.transform(UTF8.decoder).transform(new LineSplitter());
660 var subscription;
661 subscription = stream.listen((line) {
662 new Future.sync(() {
663 subscription.pause();
664 exitCode = 0;
665 if (line == null) exit(0);
666 List<String> args = <String>[];
667 args.addAll(batchArguments);
668 args.addAll(splitLine(line, windows: Platform.isWindows));
669 return internalMain(args);
670 }).catchError((exception, trace) {
671 if (!identical(exception, _EXIT_SIGNAL)) {
672 exitCode = 253;
673 }
674 }).whenComplete(() {
675 // The testing framework waits for a status line on stdout and
676 // stderr before moving to the next test.
677 if (exitCode == 0){
678 print(">>> TEST OK");
679 } else if (exitCode == 253) {
680 print(">>> TEST CRASH");
681 } else {
682 print(">>> TEST FAIL");
683 }
684 stderr.writeln(">>> EOF STDERR");
685 subscription.resume();
686 });
687 });
688 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698