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 dart2js; | 5 library dart2js; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:collection' show Queue, LinkedHashMap; | 8 import 'dart:collection' show Queue, LinkedHashMap; |
9 import 'dart:io'; | 9 import 'dart:io'; |
10 import 'dart:uri'; | 10 import 'dart:uri'; |
11 import 'dart:utf'; | 11 import 'dart:utf'; |
12 | 12 |
13 import '../compiler.dart' as api; | 13 import '../compiler.dart' as api; |
14 import 'colors.dart' as colors; | |
15 import 'source_file.dart'; | 14 import 'source_file.dart'; |
| 15 import 'source_file_provider.dart'; |
16 import 'filenames.dart'; | 16 import 'filenames.dart'; |
17 import 'util/uri_extras.dart'; | 17 import 'util/uri_extras.dart'; |
18 | 18 |
19 const String LIBRARY_ROOT = '../../../../..'; | 19 const String LIBRARY_ROOT = '../../../../..'; |
20 const String OUTPUT_LANGUAGE_DART = 'Dart'; | 20 const String OUTPUT_LANGUAGE_DART = 'Dart'; |
21 | 21 |
22 typedef void HandleOption(String option); | 22 typedef void HandleOption(String option); |
23 | 23 |
24 class OptionHandler { | 24 class OptionHandler { |
25 String pattern; | 25 String pattern; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
63 continue OUTER; | 63 continue OUTER; |
64 } | 64 } |
65 } | 65 } |
66 throw 'Internal error: "$argument" did not match'; | 66 throw 'Internal error: "$argument" did not match'; |
67 } | 67 } |
68 } | 68 } |
69 | 69 |
70 void compile(List<String> argv) { | 70 void compile(List<String> argv) { |
71 bool isWindows = (Platform.operatingSystem == 'windows'); | 71 bool isWindows = (Platform.operatingSystem == 'windows'); |
72 Uri cwd = getCurrentDirectory(); | 72 Uri cwd = getCurrentDirectory(); |
73 bool throwOnError = false; | |
74 bool showWarnings = true; | |
75 bool verbose = false; | |
76 Uri libraryRoot = cwd; | 73 Uri libraryRoot = cwd; |
77 Uri out = cwd.resolve('out.js'); | 74 Uri out = cwd.resolve('out.js'); |
78 Uri sourceMapOut = cwd.resolve('out.js.map'); | 75 Uri sourceMapOut = cwd.resolve('out.js.map'); |
79 Uri packageRoot = null; | 76 Uri packageRoot = null; |
80 List<String> options = new List<String>(); | 77 List<String> options = new List<String>(); |
81 bool explicitOut = false; | 78 bool explicitOut = false; |
82 bool wantHelp = false; | 79 bool wantHelp = false; |
83 bool enableColors = false; | |
84 String outputLanguage = 'JavaScript'; | 80 String outputLanguage = 'JavaScript'; |
85 bool stripArgumentSet = false; | 81 bool stripArgumentSet = false; |
| 82 SourceFileProvider inputProvider = new SourceFileProvider(); |
| 83 FormattingDiagnosticHandler diagnosticHandler = |
| 84 new FormattingDiagnosticHandler(inputProvider); |
86 | 85 |
87 passThrough(String argument) => options.add(argument); | 86 passThrough(String argument) => options.add(argument); |
88 | 87 |
89 setLibraryRoot(String argument) { | 88 setLibraryRoot(String argument) { |
90 libraryRoot = cwd.resolve(extractPath(argument)); | 89 libraryRoot = cwd.resolve(extractPath(argument)); |
91 } | 90 } |
92 | 91 |
93 setPackageRoot(String argument) { | 92 setPackageRoot(String argument) { |
94 packageRoot = cwd.resolve(extractPath(argument)); | 93 packageRoot = cwd.resolve(extractPath(argument)); |
95 } | 94 } |
(...skipping 24 matching lines...) Expand all Loading... |
120 setStrip(String argument) { | 119 setStrip(String argument) { |
121 stripArgumentSet = true; | 120 stripArgumentSet = true; |
122 passThrough(argument); | 121 passThrough(argument); |
123 } | 122 } |
124 | 123 |
125 handleShortOptions(String argument) { | 124 handleShortOptions(String argument) { |
126 var shortOptions = argument.substring(1).splitChars(); | 125 var shortOptions = argument.substring(1).splitChars(); |
127 for (var shortOption in shortOptions) { | 126 for (var shortOption in shortOptions) { |
128 switch (shortOption) { | 127 switch (shortOption) { |
129 case 'v': | 128 case 'v': |
130 verbose = true; | 129 diagnosticHandler.verbose = true; |
131 break; | 130 break; |
132 case 'h': | 131 case 'h': |
133 case '?': | 132 case '?': |
134 wantHelp = true; | 133 wantHelp = true; |
135 break; | 134 break; |
136 case 'c': | 135 case 'c': |
137 passThrough('--enable-checked-mode'); | 136 passThrough('--enable-checked-mode'); |
138 break; | 137 break; |
139 default: | 138 default: |
140 throw 'Internal error: "$shortOption" did not match'; | 139 throw 'Internal error: "$shortOption" did not match'; |
141 } | 140 } |
142 } | 141 } |
143 } | 142 } |
144 | 143 |
145 List<String> arguments = <String>[]; | 144 List<String> arguments = <String>[]; |
146 List<OptionHandler> handlers = <OptionHandler>[ | 145 List<OptionHandler> handlers = <OptionHandler>[ |
147 new OptionHandler('-[chv?]+', handleShortOptions), | 146 new OptionHandler('-[chv?]+', handleShortOptions), |
148 new OptionHandler('--throw-on-error', (_) => throwOnError = true), | 147 new OptionHandler('--throw-on-error', |
149 new OptionHandler('--suppress-warnings', (_) => showWarnings = false), | 148 (_) => diagnosticHandler.throwOnError = true), |
| 149 new OptionHandler('--suppress-warnings', |
| 150 (_) => diagnosticHandler.showWarnings = false), |
150 new OptionHandler('--output-type=dart|--output-type=js', setOutputType), | 151 new OptionHandler('--output-type=dart|--output-type=js', setOutputType), |
151 new OptionHandler('--verbose', (_) => verbose = true), | 152 new OptionHandler('--verbose', (_) => diagnosticHandler.verbose = true), |
152 new OptionHandler('--library-root=.+', setLibraryRoot), | 153 new OptionHandler('--library-root=.+', setLibraryRoot), |
153 new OptionHandler('--out=.+|-o.+', setOutput), | 154 new OptionHandler('--out=.+|-o.+', setOutput), |
154 new OptionHandler('--allow-mock-compilation', passThrough), | 155 new OptionHandler('--allow-mock-compilation', passThrough), |
155 new OptionHandler('--minify', passThrough), | 156 new OptionHandler('--minify', passThrough), |
156 new OptionHandler('--force-strip=.*', setStrip), | 157 new OptionHandler('--force-strip=.*', setStrip), |
157 // TODO(ahe): Remove the --no-colors option. | 158 // TODO(ahe): Remove the --no-colors option. |
158 new OptionHandler('--disable-diagnostic-colors', | 159 new OptionHandler('--disable-diagnostic-colors', |
159 (_) => enableColors = false), | 160 (_) => diagnosticHandler.enableColors = false), |
160 new OptionHandler('--enable-diagnostic-colors', (_) => enableColors = true), | 161 new OptionHandler('--enable-diagnostic-colors', |
| 162 (_) => diagnosticHandler.enableColors = true), |
161 new OptionHandler('--enable[_-]checked[_-]mode|--checked', | 163 new OptionHandler('--enable[_-]checked[_-]mode|--checked', |
162 (_) => passThrough('--enable-checked-mode')), | 164 (_) => passThrough('--enable-checked-mode')), |
163 new OptionHandler('--enable-concrete-type-inference', | 165 new OptionHandler('--enable-concrete-type-inference', |
164 (_) => passThrough('--enable-concrete-type-inference')), | 166 (_) => passThrough('--enable-concrete-type-inference')), |
165 new OptionHandler(r'--help|/\?|/h', (_) => wantHelp = true), | 167 new OptionHandler(r'--help|/\?|/h', (_) => wantHelp = true), |
166 new OptionHandler('--package-root=.+|-p.+', setPackageRoot), | 168 new OptionHandler('--package-root=.+|-p.+', setPackageRoot), |
167 new OptionHandler('--disallow-unsafe-eval', passThrough), | 169 new OptionHandler('--disallow-unsafe-eval', passThrough), |
168 new OptionHandler('--analyze-all', passThrough), | 170 new OptionHandler('--analyze-all', passThrough), |
169 new OptionHandler('--disable-native-live-type-analysis', passThrough), | 171 new OptionHandler('--disable-native-live-type-analysis', passThrough), |
170 new OptionHandler('--enable-native-live-type-analysis', passThrough), | 172 new OptionHandler('--enable-native-live-type-analysis', passThrough), |
171 new OptionHandler('--reject-deprecated-language-features', passThrough), | 173 new OptionHandler('--reject-deprecated-language-features', passThrough), |
172 new OptionHandler('--report-sdk-use-of-deprecated-language-features', | 174 new OptionHandler('--report-sdk-use-of-deprecated-language-features', |
173 passThrough), | 175 passThrough), |
174 | 176 |
175 // The following two options must come last. | 177 // The following two options must come last. |
176 new OptionHandler('-.*', (String argument) { | 178 new OptionHandler('-.*', (String argument) { |
177 helpAndFail('Error: Unknown option "$argument".'); | 179 helpAndFail('Error: Unknown option "$argument".'); |
178 }), | 180 }), |
179 new OptionHandler('.*', (String argument) { | 181 new OptionHandler('.*', (String argument) { |
180 arguments.add(nativeToUriPath(argument)); | 182 arguments.add(nativeToUriPath(argument)); |
181 }) | 183 }) |
182 ]; | 184 ]; |
183 | 185 |
184 parseCommandLine(handlers, argv); | 186 parseCommandLine(handlers, argv); |
185 if (wantHelp) helpAndExit(verbose); | 187 if (wantHelp) helpAndExit(diagnosticHandler.verbose); |
186 | 188 |
187 if (outputLanguage != OUTPUT_LANGUAGE_DART && stripArgumentSet) { | 189 if (outputLanguage != OUTPUT_LANGUAGE_DART && stripArgumentSet) { |
188 helpAndFail('Error: --force-strip may only be used with ' | 190 helpAndFail('Error: --force-strip may only be used with ' |
189 '--output-type=dart'); | 191 '--output-type=dart'); |
190 } | 192 } |
191 if (arguments.isEmpty) { | 193 if (arguments.isEmpty) { |
192 helpAndFail('Error: No Dart file specified.'); | 194 helpAndFail('Error: No Dart file specified.'); |
193 } | 195 } |
194 if (arguments.length > 1) { | 196 if (arguments.length > 1) { |
195 var extra = arguments.getRange(1, arguments.length - 1); | 197 var extra = arguments.getRange(1, arguments.length - 1); |
196 helpAndFail('Error: Extra arguments: ${Strings.join(extra, " ")}'); | 198 helpAndFail('Error: Extra arguments: ${Strings.join(extra, " ")}'); |
197 } | 199 } |
198 | 200 |
199 Map<String, SourceFile> sourceFiles = <String, SourceFile>{}; | |
200 int dartBytesRead = 0; | |
201 | |
202 Future<String> provider(Uri uri) { | |
203 if (uri.scheme != 'file') { | |
204 throw new ArgumentError(uri); | |
205 } | |
206 String source; | |
207 try { | |
208 source = readAll(uriPathToNative(uri.path)); | |
209 } on FileIOException catch (ex) { | |
210 throw 'Error: Cannot read "${relativize(cwd, uri, isWindows)}" ' | |
211 '(${ex.osError}).'; | |
212 } | |
213 dartBytesRead += source.length; | |
214 sourceFiles[uri.toString()] = | |
215 new SourceFile(relativize(cwd, uri, isWindows), source); | |
216 return new Future.immediate(source); | |
217 } | |
218 | |
219 void info(var message, [api.Diagnostic kind = api.Diagnostic.VERBOSE_INFO]) { | |
220 if (!verbose && identical(kind, api.Diagnostic.VERBOSE_INFO)) return; | |
221 if (enableColors) { | |
222 print('${colors.green("info:")} $message'); | |
223 } else { | |
224 print('info: $message'); | |
225 } | |
226 } | |
227 | |
228 bool isAborting = false; | |
229 | |
230 final int FATAL = api.Diagnostic.CRASH.ordinal | api.Diagnostic.ERROR.ordinal; | |
231 final int INFO = | |
232 api.Diagnostic.INFO.ordinal | api.Diagnostic.VERBOSE_INFO.ordinal; | |
233 | |
234 void handler(Uri uri, int begin, int end, String message, | 201 void handler(Uri uri, int begin, int end, String message, |
235 api.Diagnostic kind) { | 202 api.Diagnostic kind) { |
236 if (identical(kind.name, 'source map')) { | 203 if (identical(kind.name, 'source map')) { |
237 // TODO(podivilov): We should find a better way to return source maps from | 204 // TODO(podivilov): We should find a better way to return source maps from |
238 // emitter. Using diagnostic handler for that purpose is a temporary hack. | 205 // emitter. Using diagnostic handler for that purpose is a temporary hack. |
239 writeString(sourceMapOut, message); | 206 writeString(sourceMapOut, message); |
240 return; | 207 return; |
241 } | 208 } |
242 | 209 diagnosticHandler.diagnosticHandler(uri, begin, end, message, kind); |
243 if (isAborting) return; | |
244 isAborting = identical(kind, api.Diagnostic.CRASH); | |
245 bool fatal = (kind.ordinal & FATAL) != 0; | |
246 bool isInfo = (kind.ordinal & INFO) != 0; | |
247 if (isInfo && uri == null && !identical(kind, api.Diagnostic.INFO)) { | |
248 info(message, kind); | |
249 return; | |
250 } | |
251 var color; | |
252 if (!enableColors) { | |
253 color = (x) => x; | |
254 } else if (identical(kind, api.Diagnostic.ERROR)) { | |
255 color = colors.red; | |
256 } else if (identical(kind, api.Diagnostic.WARNING)) { | |
257 color = colors.magenta; | |
258 } else if (identical(kind, api.Diagnostic.LINT)) { | |
259 color = colors.magenta; | |
260 } else if (identical(kind, api.Diagnostic.CRASH)) { | |
261 color = colors.red; | |
262 } else if (identical(kind, api.Diagnostic.INFO)) { | |
263 color = colors.green; | |
264 } else { | |
265 throw 'Unknown kind: $kind (${kind.ordinal})'; | |
266 } | |
267 if (uri == null) { | |
268 assert(fatal); | |
269 print(color(message)); | |
270 } else if (fatal || showWarnings) { | |
271 SourceFile file = sourceFiles[uri.toString()]; | |
272 if (file == null) { | |
273 throw '$uri: file is null'; | |
274 } | |
275 print(file.getLocationMessage(color(message), begin, end, true, color)); | |
276 } | |
277 if (fatal && throwOnError) { | |
278 isAborting = true; | |
279 throw new AbortLeg(message); | |
280 } | |
281 } | 210 } |
282 | 211 |
283 Uri uri = cwd.resolve(arguments[0]); | 212 Uri uri = cwd.resolve(arguments[0]); |
284 if (packageRoot == null) { | 213 if (packageRoot == null) { |
285 packageRoot = uri.resolve('./packages/'); | 214 packageRoot = uri.resolve('./packages/'); |
286 } | 215 } |
287 | 216 |
288 info('package root is $packageRoot'); | 217 diagnosticHandler.info('package root is $packageRoot'); |
289 | 218 |
290 // TODO(ahe): We expect the future to be complete and call value | 219 // TODO(ahe): We expect the future to be complete and call value |
291 // directly. In effect, we don't support truly asynchronous API. | 220 // directly. In effect, we don't support truly asynchronous API. |
292 String code = deprecatedFutureValue( | 221 String code = deprecatedFutureValue( |
293 api.compile(uri, libraryRoot, packageRoot, provider, handler, options)); | 222 api.compile(uri, libraryRoot, packageRoot, |
| 223 inputProvider.readStringFromUri, |
| 224 handler, |
| 225 options)); |
294 if (code == null) { | 226 if (code == null) { |
295 fail('Error: Compilation failed.'); | 227 fail('Error: Compilation failed.'); |
296 } | 228 } |
297 String sourceMapFileName = | 229 String sourceMapFileName = |
298 sourceMapOut.path.substring(sourceMapOut.path.lastIndexOf('/') + 1); | 230 sourceMapOut.path.substring(sourceMapOut.path.lastIndexOf('/') + 1); |
299 code = '$code\n//@ sourceMappingURL=${sourceMapFileName}'; | 231 code = '$code\n//@ sourceMappingURL=${sourceMapFileName}'; |
300 writeString(out, code); | 232 writeString(out, code); |
301 writeString(new Uri.fromString('$out.deps'), getDepsOutput(sourceFiles)); | 233 writeString(new Uri.fromString('$out.deps'), |
| 234 getDepsOutput(inputProvider.sourceFiles)); |
| 235 int dartBytesRead = inputProvider.dartBytesRead; |
302 int bytesWritten = code.length; | 236 int bytesWritten = code.length; |
303 info('compiled $dartBytesRead bytes Dart -> $bytesWritten bytes ' | 237 diagnosticHandler.info( |
304 '$outputLanguage in ${relativize(cwd, out, isWindows)}'); | 238 'compiled $dartBytesRead bytes Dart -> $bytesWritten bytes ' |
| 239 '$outputLanguage in ${relativize(cwd, out, isWindows)}'); |
305 if (!explicitOut) { | 240 if (!explicitOut) { |
306 String input = uriPathToNative(arguments[0]); | 241 String input = uriPathToNative(arguments[0]); |
307 String output = relativize(cwd, out, isWindows); | 242 String output = relativize(cwd, out, isWindows); |
308 print('Dart file $input compiled to $outputLanguage: $output'); | 243 print('Dart file $input compiled to $outputLanguage: $output'); |
309 } | 244 } |
310 } | 245 } |
311 | 246 |
312 class AbortLeg { | 247 class AbortLeg { |
313 final message; | 248 final message; |
314 AbortLeg(this.message); | 249 AbortLeg(this.message); |
315 toString() => 'Aborted due to --throw-on-error: $message'; | 250 toString() => 'Aborted due to --throw-on-error: $message'; |
316 } | 251 } |
317 | 252 |
318 void writeString(Uri uri, String text) { | 253 void writeString(Uri uri, String text) { |
319 if (uri.scheme != 'file') { | 254 if (uri.scheme != 'file') { |
320 fail('Error: Unhandled scheme ${uri.scheme}.'); | 255 fail('Error: Unhandled scheme ${uri.scheme}.'); |
321 } | 256 } |
322 var file = new File(uriPathToNative(uri.path)).openSync(FileMode.WRITE); | 257 var file = new File(uriPathToNative(uri.path)).openSync(FileMode.WRITE); |
323 file.writeStringSync(text); | 258 file.writeStringSync(text); |
324 file.closeSync(); | 259 file.closeSync(); |
325 } | 260 } |
326 | 261 |
327 String readAll(String filename) { | |
328 var file = (new File(filename)).openSync(FileMode.READ); | |
329 var length = file.lengthSync(); | |
330 var buffer = new List<int>.fixedLength(length); | |
331 var bytes = file.readListSync(buffer, 0, length); | |
332 file.closeSync(); | |
333 return new String.fromCharCodes(new Utf8Decoder(buffer).decodeRest()); | |
334 } | |
335 | |
336 void fail(String message) { | 262 void fail(String message) { |
337 print(message); | 263 print(message); |
338 exit(1); | 264 exit(1); |
339 } | 265 } |
340 | 266 |
341 void compilerMain(Options options) { | 267 void compilerMain(Options options) { |
342 var root = uriPathToNative("/$LIBRARY_ROOT"); | 268 var root = uriPathToNative("/$LIBRARY_ROOT"); |
343 List<String> argv = ['--library-root=${options.script}$root']; | 269 List<String> argv = ['--library-root=${options.script}$root']; |
344 argv.addAll(options.arguments); | 270 argv.addAll(options.arguments); |
345 compile(argv); | 271 compile(argv); |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
467 } catch (ignored) { | 393 } catch (ignored) { |
468 print('Internal error: error while printing exception'); | 394 print('Internal error: error while printing exception'); |
469 } | 395 } |
470 try { | 396 try { |
471 print(trace); | 397 print(trace); |
472 } finally { | 398 } finally { |
473 exit(253); // 253 is recognized as a crash by our test scripts. | 399 exit(253); // 253 is recognized as a crash by our test scripts. |
474 } | 400 } |
475 } | 401 } |
476 } | 402 } |
OLD | NEW |