| 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 |