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