| OLD | NEW |
| 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, 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 import 'dart:async'; | 5 import 'dart:async'; |
| 6 import 'dart:typed_data'; | 6 import 'dart:typed_data'; |
| 7 | 7 |
| 8 import 'package:crypto/crypto.dart'; | 8 import 'package:crypto/crypto.dart'; |
| 9 import 'package:front_end/file_system.dart'; | 9 import 'package:front_end/file_system.dart'; |
| 10 import 'package:front_end/src/base/api_signature.dart'; | 10 import 'package:front_end/src/base/api_signature.dart'; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 37 | 37 |
| 38 /// The absolute URI of the file. | 38 /// The absolute URI of the file. |
| 39 final Uri uri; | 39 final Uri uri; |
| 40 | 40 |
| 41 /// The resolved URI of the file in the file system. | 41 /// The resolved URI of the file in the file system. |
| 42 final Uri fileUri; | 42 final Uri fileUri; |
| 43 | 43 |
| 44 bool _exists; | 44 bool _exists; |
| 45 List<int> _content; | 45 List<int> _content; |
| 46 List<int> _contentHash; | 46 List<int> _contentHash; |
| 47 bool _hasMixinApplication; |
| 47 List<int> _apiSignature; | 48 List<int> _apiSignature; |
| 48 | 49 |
| 49 List<NamespaceExport> _exports; | 50 List<NamespaceExport> _exports; |
| 50 List<FileState> _importedLibraries; | 51 List<FileState> _importedLibraries; |
| 51 List<FileState> _exportedLibraries; | 52 List<FileState> _exportedLibraries; |
| 52 List<FileState> _partFiles; | 53 List<FileState> _partFiles; |
| 53 | 54 |
| 54 Set<FileState> _directReferencedFiles = new Set<FileState>(); | 55 Set<FileState> _directReferencedFiles = new Set<FileState>(); |
| 55 List<FileState> _directReferencedLibraries = <FileState>[]; | 56 List<FileState> _directReferencedLibraries = <FileState>[]; |
| 56 | 57 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 78 | 79 |
| 79 /// The list of the libraries exported by this library. | 80 /// The list of the libraries exported by this library. |
| 80 List<FileState> get exportedLibraries => _exportedLibraries; | 81 List<FileState> get exportedLibraries => _exportedLibraries; |
| 81 | 82 |
| 82 /// The list of the exported files with combinators. | 83 /// The list of the exported files with combinators. |
| 83 List<NamespaceExport> get exports => _exports; | 84 List<NamespaceExport> get exports => _exports; |
| 84 | 85 |
| 85 @override | 86 @override |
| 86 int get hashCode => uri.hashCode; | 87 int get hashCode => uri.hashCode; |
| 87 | 88 |
| 89 /// Whether the file has a mixin application. |
| 90 bool get hasMixinApplication => _hasMixinApplication; |
| 91 |
| 92 /// Whether a unit of the library has a mixin application. |
| 93 bool get hasMixinApplicationLibrary { |
| 94 return _hasMixinApplication || |
| 95 _partFiles.any((part) => part._hasMixinApplication); |
| 96 } |
| 97 |
| 88 /// The list of the libraries imported by this library. | 98 /// The list of the libraries imported by this library. |
| 89 List<FileState> get importedLibraries => _importedLibraries; | 99 List<FileState> get importedLibraries => _importedLibraries; |
| 90 | 100 |
| 91 /// The list of files this library file references as parts. | 101 /// The list of files this library file references as parts. |
| 92 List<FileState> get partFiles => _partFiles; | 102 List<FileState> get partFiles => _partFiles; |
| 93 | 103 |
| 94 /// Return topologically sorted cycles of dependencies for this library. | 104 /// Return topologically sorted cycles of dependencies for this library. |
| 95 List<LibraryCycle> get topologicalOrder { | 105 List<LibraryCycle> get topologicalOrder { |
| 96 var libraryWalker = new _LibraryWalker(); | 106 var libraryWalker = new _LibraryWalker(); |
| 97 libraryWalker.walk(libraryWalker.getNode(this)); | 107 libraryWalker.walk(libraryWalker.getNode(this)); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 131 _content = new Uint8List(0); | 141 _content = new Uint8List(0); |
| 132 _exists = false; | 142 _exists = false; |
| 133 } | 143 } |
| 134 | 144 |
| 135 // Compute the content hash. | 145 // Compute the content hash. |
| 136 _contentHash = md5.convert(_content).bytes; | 146 _contentHash = md5.convert(_content).bytes; |
| 137 | 147 |
| 138 // Scan the content. | 148 // Scan the content. |
| 139 ScannerResult scanResult = _scan(); | 149 ScannerResult scanResult = _scan(); |
| 140 | 150 |
| 141 // Compute the API signature. | 151 // Compute syntactic properties. |
| 142 _apiSignature = _computeApiSignature(scanResult.tokens); | 152 _computeSyntacticProperties(scanResult.tokens); |
| 143 | 153 |
| 144 // Parse directives. | 154 // Parse directives. |
| 145 var listener = new _DirectiveListenerWithNative(); | 155 var listener = new _DirectiveListenerWithNative(); |
| 146 new TopLevelParser(listener).parseUnit(scanResult.tokens); | 156 new TopLevelParser(listener).parseUnit(scanResult.tokens); |
| 147 | 157 |
| 148 // Build the graph. | 158 // Build the graph. |
| 149 _importedLibraries = <FileState>[]; | 159 _importedLibraries = <FileState>[]; |
| 150 _exportedLibraries = <FileState>[]; | 160 _exportedLibraries = <FileState>[]; |
| 151 _partFiles = <FileState>[]; | 161 _partFiles = <FileState>[]; |
| 152 _exports = <NamespaceExport>[]; | 162 _exports = <NamespaceExport>[]; |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 203 if (uri.toString() != 'dart:core') return; | 213 if (uri.toString() != 'dart:core') return; |
| 204 for (String uri in new VmTarget(null).extraRequiredLibraries) { | 214 for (String uri in new VmTarget(null).extraRequiredLibraries) { |
| 205 FileState file = await _getFileForRelativeUri(uri); | 215 FileState file = await _getFileForRelativeUri(uri); |
| 206 // TODO(scheglov) add error handling | 216 // TODO(scheglov) add error handling |
| 207 if (file != null) { | 217 if (file != null) { |
| 208 _importedLibraries.add(file); | 218 _importedLibraries.add(file); |
| 209 } | 219 } |
| 210 } | 220 } |
| 211 } | 221 } |
| 212 | 222 |
| 213 /// Compute and return the API signature of the file. | 223 /// Compute syntactic properties of the file: [_apiSignature] and [_hasMixinAp
plication]. |
| 214 /// | 224 /// |
| 215 /// The signature is based on non-comment tokens of the file outside | 225 /// The signature is based on non-comment tokens of the file outside |
| 216 /// of function bodies. | 226 /// of function bodies. |
| 217 List<int> _computeApiSignature(Token token) { | 227 void _computeSyntacticProperties(Token token) { |
| 218 var parser = new _BodySkippingParser(); | 228 var parser = new _BodySkippingParser(); |
| 219 parser.parseUnit(token); | 229 parser.parseUnit(token); |
| 220 | 230 |
| 231 _hasMixinApplication = parser.hasMixin; |
| 232 |
| 221 ApiSignature apiSignature = new ApiSignature(); | 233 ApiSignature apiSignature = new ApiSignature(); |
| 222 apiSignature.addBytes(_fsState._salt); | 234 apiSignature.addBytes(_fsState._salt); |
| 223 | 235 |
| 224 // Iterate over tokens and skip bodies. | 236 // Iterate over tokens and skip bodies. |
| 225 Iterator<_BodyRange> bodyIterator = parser.bodyRanges.iterator; | 237 Iterator<_BodyRange> bodyIterator = parser.bodyRanges.iterator; |
| 226 bodyIterator.moveNext(); | 238 bodyIterator.moveNext(); |
| 227 for (; token.kind != EOF_TOKEN; token = token.next) { | 239 for (; token.kind != EOF_TOKEN; token = token.next) { |
| 228 // Move to the body range that ends after the token. | 240 // Move to the body range that ends after the token. |
| 229 while (bodyIterator.current != null && | 241 while (bodyIterator.current != null && |
| 230 bodyIterator.current.last < token.charOffset) { | 242 bodyIterator.current.last < token.charOffset) { |
| 231 bodyIterator.moveNext(); | 243 bodyIterator.moveNext(); |
| 232 } | 244 } |
| 233 // If the current body range starts before or at the token, skip it. | 245 // If the current body range starts before or at the token, skip it. |
| 234 if (bodyIterator.current != null && | 246 if (bodyIterator.current != null && |
| 235 bodyIterator.current.first <= token.charOffset) { | 247 bodyIterator.current.first <= token.charOffset) { |
| 236 continue; | 248 continue; |
| 237 } | 249 } |
| 238 // The token is outside of a function body, add it. | 250 // The token is outside of a function body, add it. |
| 239 apiSignature.addString(token.lexeme); | 251 apiSignature.addString(token.lexeme); |
| 240 } | 252 } |
| 241 | 253 |
| 242 return apiSignature.toByteList(); | 254 // Store the API signature. |
| 255 _apiSignature = apiSignature.toByteList(); |
| 243 } | 256 } |
| 244 | 257 |
| 245 /// Exclude all `native 'xyz';` token sequences. | 258 /// Exclude all `native 'xyz';` token sequences. |
| 246 void _excludeNativeClauses(Token token) { | 259 void _excludeNativeClauses(Token token) { |
| 247 for (; token.kind != EOF_TOKEN; token = token.next) { | 260 for (; token.kind != EOF_TOKEN; token = token.next) { |
| 248 if (optional('native', token) && | 261 if (optional('native', token) && |
| 249 token.next.kind == STRING_TOKEN && | 262 token.next.kind == STRING_TOKEN && |
| 250 optional(';', token.next.next)) { | 263 optional(';', token.next.next)) { |
| 251 token.previous.next = token.next.next; | 264 token.previous.next = token.next.next; |
| 252 } | 265 } |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 432 final int last; | 445 final int last; |
| 433 | 446 |
| 434 _BodyRange(this.first, this.last); | 447 _BodyRange(this.first, this.last); |
| 435 | 448 |
| 436 @override | 449 @override |
| 437 String toString() => '[$first, $last]'; | 450 String toString() => '[$first, $last]'; |
| 438 } | 451 } |
| 439 | 452 |
| 440 /// The [Parser] that skips function bodies and remembers their token ranges. | 453 /// The [Parser] that skips function bodies and remembers their token ranges. |
| 441 class _BodySkippingParser extends Parser { | 454 class _BodySkippingParser extends Parser { |
| 455 bool hasMixin = false; |
| 442 final List<_BodyRange> bodyRanges = []; | 456 final List<_BodyRange> bodyRanges = []; |
| 443 | 457 |
| 444 _BodySkippingParser() : super(new Listener()); | 458 _BodySkippingParser() : super(new Listener()); |
| 445 | 459 |
| 446 @override | 460 @override |
| 447 Token parseFunctionBody(Token token, bool isExpression, bool allowAbstract) { | 461 Token parseFunctionBody(Token token, bool isExpression, bool allowAbstract) { |
| 448 if (identical('{', token.lexeme)) { | 462 if (identical('{', token.lexeme)) { |
| 449 Token close = skipBlock(token); | 463 Token close = skipBlock(token); |
| 450 bodyRanges.add(new _BodyRange(token.charOffset, close.charOffset)); | 464 bodyRanges.add(new _BodyRange(token.charOffset, close.charOffset)); |
| 451 return close; | 465 return close; |
| 452 } | 466 } |
| 453 return super.parseFunctionBody(token, isExpression, allowAbstract); | 467 return super.parseFunctionBody(token, isExpression, allowAbstract); |
| 454 } | 468 } |
| 469 |
| 470 Token parseMixinApplication(Token token) { |
| 471 hasMixin = true; |
| 472 return super.parseMixinApplication(token); |
| 473 } |
| 455 } | 474 } |
| 456 | 475 |
| 457 /// [DirectiveListener] that skips native clauses. | 476 /// [DirectiveListener] that skips native clauses. |
| 458 class _DirectiveListenerWithNative extends DirectiveListener { | 477 class _DirectiveListenerWithNative extends DirectiveListener { |
| 459 @override | 478 @override |
| 460 Token handleNativeClause(Token token) => skipNativeClause(token); | 479 Token handleNativeClause(Token token) => skipNativeClause(token); |
| 461 } | 480 } |
| 462 | 481 |
| 463 /// [FileSystemState] based implementation of [FileSystem]. | 482 /// [FileSystemState] based implementation of [FileSystem]. |
| 464 /// It provides a consistent view on the known file system state. | 483 /// It provides a consistent view on the known file system state. |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 543 node.isEvaluated = true; | 562 node.isEvaluated = true; |
| 544 cycle.libraries.add(node.file); | 563 cycle.libraries.add(node.file); |
| 545 } | 564 } |
| 546 topologicallySortedCycles.add(cycle); | 565 topologicallySortedCycles.add(cycle); |
| 547 } | 566 } |
| 548 | 567 |
| 549 _LibraryNode getNode(FileState file) { | 568 _LibraryNode getNode(FileState file) { |
| 550 return nodesOfFiles.putIfAbsent(file, () => new _LibraryNode(this, file)); | 569 return nodesOfFiles.putIfAbsent(file, () => new _LibraryNode(this, file)); |
| 551 } | 570 } |
| 552 } | 571 } |
| OLD | NEW |