| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 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 | 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 source_file_provider; | 5 library source_file_provider; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:io'; | 8 import 'dart:io'; |
| 9 import 'dart:math' as math; | 9 import 'dart:math' as math; |
| 10 import 'dart:typed_data'; | 10 import 'dart:typed_data'; |
| 11 | 11 |
| 12 import '../compiler.dart' as api show Diagnostic; | 12 import '../compiler.dart' as api show Diagnostic; |
| 13 import '../compiler_new.dart' as api; | 13 import '../compiler_new.dart' as api; |
| 14 import '../compiler_new.dart'; | 14 import '../compiler_new.dart'; |
| 15 import 'colors.dart' as colors; | 15 import 'colors.dart' as colors; |
| 16 import 'dart2js.dart' show AbortLeg; | 16 import 'dart2js.dart' show AbortLeg; |
| 17 import 'filenames.dart'; | 17 import 'filenames.dart'; |
| 18 import 'io/source_file.dart'; | 18 import 'io/source_file.dart'; |
| 19 import 'util/uri_extras.dart'; | 19 import 'util/uri_extras.dart'; |
| 20 | 20 |
| 21 abstract class SourceFileProvider implements CompilerInput { | 21 abstract class SourceFileProvider implements CompilerInput { |
| 22 bool isWindows = (Platform.operatingSystem == 'windows'); | 22 bool isWindows = (Platform.operatingSystem == 'windows'); |
| 23 Uri cwd = currentDirectory; | 23 Uri cwd = currentDirectory; |
| 24 Map<Uri, SourceFile> sourceFiles = <Uri, SourceFile>{}; | 24 Map<Uri, api.Input> sourceFiles = <Uri, api.Input>{}; |
| 25 int dartCharactersRead = 0; | 25 int dartCharactersRead = 0; |
| 26 | 26 |
| 27 Future<List<int>> readUtf8BytesFromUri(Uri resourceUri) { | 27 Future<api.Input> readBytesFromUri(Uri resourceUri, api.InputKind inputKind) { |
| 28 if (resourceUri.scheme == 'file') { | 28 if (resourceUri.scheme == 'file') { |
| 29 return _readFromFile(resourceUri); | 29 return _readFromFile(resourceUri, inputKind); |
| 30 } else if (resourceUri.scheme == 'http' || resourceUri.scheme == 'https') { | 30 } else if (resourceUri.scheme == 'http' || resourceUri.scheme == 'https') { |
| 31 return _readFromHttp(resourceUri); | 31 return _readFromHttp(resourceUri, inputKind); |
| 32 } else { | 32 } else { |
| 33 throw new ArgumentError("Unknown scheme in uri '$resourceUri'"); | 33 throw new ArgumentError("Unknown scheme in uri '$resourceUri'"); |
| 34 } | 34 } |
| 35 } | 35 } |
| 36 | 36 |
| 37 Future<List<int>> _readFromFile(Uri resourceUri) { | 37 Future<api.Input> _readFromFile(Uri resourceUri, api.InputKind inputKind) { |
| 38 assert(resourceUri.scheme == 'file'); | 38 assert(resourceUri.scheme == 'file'); |
| 39 List<int> source; | 39 List<int> source; |
| 40 try { | 40 try { |
| 41 source = readAll(resourceUri.toFilePath()); | 41 source = readAll(resourceUri.toFilePath(), |
| 42 zeroTerminated: inputKind == api.InputKind.utf8); |
| 42 } on FileSystemException catch (ex) { | 43 } on FileSystemException catch (ex) { |
| 43 String message = ex.osError?.message; | 44 String message = ex.osError?.message; |
| 44 String detail = message != null ? ' ($message)' : ''; | 45 String detail = message != null ? ' ($message)' : ''; |
| 45 return new Future.error( | 46 return new Future.error( |
| 46 "Error reading '${relativizeUri(resourceUri)}' $detail"); | 47 "Error reading '${relativizeUri(resourceUri)}' $detail"); |
| 47 } | 48 } |
| 48 dartCharactersRead += source.length; | 49 dartCharactersRead += source.length; |
| 49 sourceFiles[resourceUri] = new CachingUtf8BytesSourceFile( | 50 api.Input input; |
| 50 resourceUri, relativizeUri(resourceUri), source); | 51 switch (inputKind) { |
| 51 return new Future.value(source); | 52 case api.InputKind.utf8: |
| 53 input = new CachingUtf8BytesSourceFile( |
| 54 resourceUri, relativizeUri(resourceUri), source); |
| 55 break; |
| 56 case api.InputKind.binary: |
| 57 input = new Binary(resourceUri, source); |
| 58 break; |
| 59 } |
| 60 sourceFiles[resourceUri] = input; |
| 61 return new Future.value(input); |
| 52 } | 62 } |
| 53 | 63 |
| 54 Future<List<int>> _readFromHttp(Uri resourceUri) { | 64 Future<api.Input> _readFromHttp(Uri resourceUri, api.InputKind inputKind) { |
| 55 assert(resourceUri.scheme == 'http'); | 65 assert(resourceUri.scheme == 'http'); |
| 56 HttpClient client = new HttpClient(); | 66 HttpClient client = new HttpClient(); |
| 57 return client | 67 return client |
| 58 .getUrl(resourceUri) | 68 .getUrl(resourceUri) |
| 59 .then((HttpClientRequest request) => request.close()) | 69 .then((HttpClientRequest request) => request.close()) |
| 60 .then((HttpClientResponse response) { | 70 .then((HttpClientResponse response) { |
| 61 if (response.statusCode != HttpStatus.OK) { | 71 if (response.statusCode != HttpStatus.OK) { |
| 62 String msg = 'Failure getting $resourceUri: ' | 72 String msg = 'Failure getting $resourceUri: ' |
| 63 '${response.statusCode} ${response.reasonPhrase}'; | 73 '${response.statusCode} ${response.reasonPhrase}'; |
| 64 throw msg; | 74 throw msg; |
| 65 } | 75 } |
| 66 return response.toList(); | 76 return response.toList(); |
| 67 }).then((List<List<int>> splitContent) { | 77 }).then((List<List<int>> splitContent) { |
| 68 int totalLength = splitContent.fold(0, (int old, List list) { | 78 int totalLength = splitContent.fold(0, (int old, List list) { |
| 69 return old + list.length; | 79 return old + list.length; |
| 70 }); | 80 }); |
| 71 Uint8List result = new Uint8List(totalLength); | 81 Uint8List result = new Uint8List(totalLength); |
| 72 int offset = 0; | 82 int offset = 0; |
| 73 for (List<int> contentPart in splitContent) { | 83 for (List<int> contentPart in splitContent) { |
| 74 result.setRange(offset, offset + contentPart.length, contentPart); | 84 result.setRange(offset, offset + contentPart.length, contentPart); |
| 75 offset += contentPart.length; | 85 offset += contentPart.length; |
| 76 } | 86 } |
| 77 dartCharactersRead += totalLength; | 87 dartCharactersRead += totalLength; |
| 78 sourceFiles[resourceUri] = new CachingUtf8BytesSourceFile( | 88 api.Input input; |
| 79 resourceUri, resourceUri.toString(), result); | 89 switch (inputKind) { |
| 80 return result; | 90 case api.InputKind.utf8: |
| 91 input = new CachingUtf8BytesSourceFile( |
| 92 resourceUri, resourceUri.toString(), result); |
| 93 break; |
| 94 case api.InputKind.binary: |
| 95 input = new Binary(resourceUri, result); |
| 96 break; |
| 97 } |
| 98 sourceFiles[resourceUri] = input; |
| 99 return input; |
| 81 }); | 100 }); |
| 82 } | 101 } |
| 83 | 102 |
| 84 // TODO(johnniwinther): Remove this when no longer needed for the old compiler | 103 // TODO(johnniwinther): Remove this when no longer needed for the old compiler |
| 85 // API. | 104 // API. |
| 86 Future /* <List<int> | String> */ call(Uri resourceUri) { | 105 Future /* <List<int> | String> */ call(Uri resourceUri) { |
| 87 throw "unimplemented"; | 106 throw "unimplemented"; |
| 88 } | 107 } |
| 89 | 108 |
| 90 relativizeUri(Uri uri) => relativize(cwd, uri, isWindows); | 109 relativizeUri(Uri uri) => relativize(cwd, uri, isWindows); |
| 91 | 110 |
| 92 SourceFile getSourceFile(Uri resourceUri) { | 111 SourceFile getSourceFile(Uri resourceUri) { |
| 93 return sourceFiles[resourceUri]; | 112 return sourceFiles[resourceUri]; |
| 94 } | 113 } |
| 95 } | 114 } |
| 96 | 115 |
| 97 List<int> readAll(String filename) { | 116 List<int> readAll(String filename, {bool zeroTerminated: true}) { |
| 98 var file = (new File(filename)).openSync(); | 117 RandomAccessFile file = (new File(filename)).openSync(); |
| 99 var length = file.lengthSync(); | 118 int length = file.lengthSync(); |
| 100 // +1 to have a 0 terminated list, see [Scanner]. | 119 int bufferLength = length; |
| 101 var buffer = new Uint8List(length + 1); | 120 if (zeroTerminated) { |
| 121 // +1 to have a 0 terminated list, see [Scanner]. |
| 122 bufferLength++; |
| 123 } |
| 124 var buffer = new Uint8List(bufferLength); |
| 102 file.readIntoSync(buffer, 0, length); | 125 file.readIntoSync(buffer, 0, length); |
| 103 file.closeSync(); | 126 file.closeSync(); |
| 104 return buffer; | 127 return buffer; |
| 105 } | 128 } |
| 106 | 129 |
| 107 class CompilerSourceFileProvider extends SourceFileProvider { | 130 class CompilerSourceFileProvider extends SourceFileProvider { |
| 108 // TODO(johnniwinther): Remove this when no longer needed for the old compiler | 131 // TODO(johnniwinther): Remove this when no longer needed for the old compiler |
| 109 // API. | 132 // API. |
| 110 Future<List<int>> call(Uri resourceUri) => readFromUri(resourceUri); | 133 Future<List<int>> call(Uri resourceUri) => readFromUri(resourceUri); |
| 111 | 134 |
| 112 @override | 135 @override |
| 113 Future readFromUri(Uri uri) => readUtf8BytesFromUri(uri); | 136 Future readFromUri(Uri uri, {InputKind inputKind: InputKind.utf8}) => |
| 137 readBytesFromUri(uri, inputKind); |
| 114 } | 138 } |
| 115 | 139 |
| 116 class FormattingDiagnosticHandler implements CompilerDiagnostics { | 140 class FormattingDiagnosticHandler implements CompilerDiagnostics { |
| 117 final SourceFileProvider provider; | 141 final SourceFileProvider provider; |
| 118 bool showWarnings = true; | 142 bool showWarnings = true; |
| 119 bool showHints = true; | 143 bool showHints = true; |
| 120 bool verbose = false; | 144 bool verbose = false; |
| 121 bool isAborting = false; | 145 bool isAborting = false; |
| 122 bool enableColors = false; | 146 bool enableColors = false; |
| 123 bool throwOnError = false; | 147 bool throwOnError = false; |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 198 color = colors.green; | 222 color = colors.green; |
| 199 } else { | 223 } else { |
| 200 throw 'Unknown kind: $kind (${kind.ordinal})'; | 224 throw 'Unknown kind: $kind (${kind.ordinal})'; |
| 201 } | 225 } |
| 202 if (!enableColors) { | 226 if (!enableColors) { |
| 203 color = (x) => x; | 227 color = (x) => x; |
| 204 } | 228 } |
| 205 if (uri == null) { | 229 if (uri == null) { |
| 206 print('${color(message)}'); | 230 print('${color(message)}'); |
| 207 } else { | 231 } else { |
| 208 SourceFile file = provider.sourceFiles[uri]; | 232 api.Input file = provider.sourceFiles[uri]; |
| 209 // TODO(johnniwinther): Remove the '.dill' hack; add support for binary | 233 if (file is SourceFile) { |
| 210 // files to avoid crashes on trying to decode .dill binaries as utf8. | |
| 211 if (file != null && !file.filename.endsWith('.dill')) { | |
| 212 print(file.getLocationMessage(color(message), begin, end, | 234 print(file.getLocationMessage(color(message), begin, end, |
| 213 colorize: color)); | 235 colorize: color)); |
| 214 } else { | 236 } else { |
| 215 String position = end - begin > 0 ? '@$begin+${end - begin}' : ''; | 237 String position = end - begin > 0 ? '@$begin+${end - begin}' : ''; |
| 216 print('${provider.relativizeUri(uri)}$position:\n' | 238 print('${provider.relativizeUri(uri)}$position:\n' |
| 217 '${color(message)}'); | 239 '${color(message)}'); |
| 218 } | 240 } |
| 219 } | 241 } |
| 220 if (fatal && ++fatalCount >= throwOnErrorCount && throwOnError) { | 242 if (fatal && ++fatalCount >= throwOnErrorCount && throwOnError) { |
| 221 isAborting = true; | 243 isAborting = true; |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 400 /// `/bazel-root/a/b.dart` which will likely fail. | 422 /// `/bazel-root/a/b.dart` which will likely fail. |
| 401 class BazelInputProvider extends SourceFileProvider { | 423 class BazelInputProvider extends SourceFileProvider { |
| 402 final List<Uri> dirs; | 424 final List<Uri> dirs; |
| 403 | 425 |
| 404 BazelInputProvider(List<String> searchPaths) | 426 BazelInputProvider(List<String> searchPaths) |
| 405 : dirs = searchPaths.map(_resolve).toList(); | 427 : dirs = searchPaths.map(_resolve).toList(); |
| 406 | 428 |
| 407 static _resolve(String path) => currentDirectory.resolve(path); | 429 static _resolve(String path) => currentDirectory.resolve(path); |
| 408 | 430 |
| 409 @override | 431 @override |
| 410 Future readFromUri(Uri uri) async { | 432 Future<api.Input> readFromUri(Uri uri, |
| 433 {InputKind inputKind: InputKind.utf8}) async { |
| 411 var resolvedUri = uri; | 434 var resolvedUri = uri; |
| 412 var path = uri.path; | 435 var path = uri.path; |
| 413 if (path.startsWith('/bazel-root')) { | 436 if (path.startsWith('/bazel-root')) { |
| 414 path = path.substring('/bazel-root/'.length); | 437 path = path.substring('/bazel-root/'.length); |
| 415 for (var dir in dirs) { | 438 for (var dir in dirs) { |
| 416 var file = dir.resolve(path); | 439 var file = dir.resolve(path); |
| 417 if (await new File.fromUri(file).exists()) { | 440 if (await new File.fromUri(file).exists()) { |
| 418 resolvedUri = file; | 441 resolvedUri = file; |
| 419 break; | 442 break; |
| 420 } | 443 } |
| 421 } | 444 } |
| 422 } | 445 } |
| 423 List<int> result = await readUtf8BytesFromUri(resolvedUri); | 446 api.Input result = await readBytesFromUri(resolvedUri, inputKind); |
| 424 sourceFiles[uri] = sourceFiles[resolvedUri]; | 447 sourceFiles[uri] = sourceFiles[resolvedUri]; |
| 425 return result; | 448 return result; |
| 426 } | 449 } |
| 427 } | 450 } |
| OLD | NEW |