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:front_end/file_system.dart'; | 8 import 'package:front_end/file_system.dart'; |
9 import 'package:front_end/src/dependency_walker.dart' as graph; | |
9 import 'package:front_end/src/fasta/parser/top_level_parser.dart'; | 10 import 'package:front_end/src/fasta/parser/top_level_parser.dart'; |
10 import 'package:front_end/src/fasta/scanner.dart'; | 11 import 'package:front_end/src/fasta/scanner.dart'; |
11 import 'package:front_end/src/fasta/source/directive_listener.dart'; | 12 import 'package:front_end/src/fasta/source/directive_listener.dart'; |
12 import 'package:front_end/src/fasta/translate_uri.dart'; | 13 import 'package:front_end/src/fasta/translate_uri.dart'; |
13 | 14 |
14 /// Information about a file being compiled, explicitly or implicitly. | 15 /// Information about a file being compiled, explicitly or implicitly. |
15 /// | 16 /// |
16 /// It provides a consistent view on its properties. | 17 /// It provides a consistent view on its properties. |
17 /// | 18 /// |
18 /// The properties are not guaranteed to represent the most recent state | 19 /// The properties are not guaranteed to represent the most recent state |
19 /// of the file system. To update the file to the most recent state, [refresh] | 20 /// of the file system. To update the file to the most recent state, [refresh] |
20 /// should be called. | 21 /// should be called. |
21 class FileState { | 22 class FileState { |
22 final FileSystemState _fsState; | 23 final FileSystemState _fsState; |
23 | 24 |
24 /// The resolved URI of the file in the file system. | 25 /// The resolved URI of the file in the file system. |
25 final Uri fileUri; | 26 final Uri fileUri; |
26 | 27 |
27 bool _exists; | 28 bool _exists; |
28 List<int> _content; | 29 List<int> _content; |
29 | 30 |
30 List<FileState> _importedFiles; | 31 List<FileState> _importedFiles; |
31 List<FileState> _exportedFiles; | 32 List<FileState> _exportedFiles; |
32 List<FileState> _partFiles; | 33 List<FileState> _partFiles; |
33 | 34 |
34 Set<FileState> _directReferencedFiles = new Set<FileState>(); | 35 List<FileState> _directReferencedLibraries = <FileState>[]; |
35 | 36 |
36 FileState._(this._fsState, this.fileUri); | 37 FileState._(this._fsState, this.fileUri); |
37 | 38 |
38 /// The content of the file. | 39 /// The content of the file. |
39 List<int> get content => _content; | 40 List<int> get content => _content; |
40 | 41 |
42 /// Libraries that this library file directly imports or exports. | |
43 List<FileState> get directReferencedLibraries => _directReferencedLibraries; | |
44 | |
41 /// Whether the file exists. | 45 /// Whether the file exists. |
42 bool get exists => _exists; | 46 bool get exists => _exists; |
43 | 47 |
48 /// The list of files this file exports. | |
Paul Berry
2017/05/12 14:30:43
Sould we rename this to exportedLibraries?
scheglov
2017/05/12 15:40:58
Done.
| |
49 List<FileState> get exportedFiles => _exportedFiles; | |
50 | |
44 @override | 51 @override |
45 int get hashCode => fileUri.hashCode; | 52 int get hashCode => fileUri.hashCode; |
46 | 53 |
47 /// Return the set of transitive files - the file itself and all of the | 54 /// The list of files this file imports. |
Paul Berry
2017/05/12 14:30:43
Similar question here
scheglov
2017/05/12 15:40:58
Done.
| |
48 /// directly or indirectly referenced files. | 55 List<FileState> get importedFiles => _importedFiles; |
49 Set<FileState> get transitiveFiles { | |
50 // TODO(scheglov) add caching. | |
51 var transitiveFiles = new Set<FileState>(); | |
52 | 56 |
53 void appendReferenced(FileState file) { | 57 /// The list of files this library file references as parts. |
54 if (transitiveFiles.add(file)) { | 58 List<FileState> get partFiles => _partFiles; |
55 file._directReferencedFiles.forEach(appendReferenced); | |
56 } | |
57 } | |
58 | 59 |
59 appendReferenced(this); | 60 /// Return topologically sorted cycles of dependencies for this library. |
60 return transitiveFiles; | 61 List<LibraryCycle> get topologicalOrder { |
62 var libraryWalker = new _LibraryWalker(); | |
63 libraryWalker.walk(libraryWalker.getNode(this)); | |
64 return libraryWalker.topologicallySortedCycles; | |
61 } | 65 } |
62 | 66 |
63 @override | 67 @override |
64 bool operator ==(Object other) { | 68 bool operator ==(Object other) { |
65 return other is FileState && other.fileUri == fileUri; | 69 return other is FileState && other.fileUri == fileUri; |
66 } | 70 } |
67 | 71 |
68 /// Read the file content and ensure that all of the file properties are | 72 /// Read the file content and ensure that all of the file properties are |
69 /// consistent with the read content, including all its dependencies. | 73 /// consistent with the read content, including all its dependencies. |
70 Future<Null> refresh() async { | 74 Future<Null> refresh() async { |
(...skipping 20 matching lines...) Expand all Loading... | |
91 for (String uri in listener.imports) { | 95 for (String uri in listener.imports) { |
92 await _addFileForRelativeUri(_importedFiles, uri); | 96 await _addFileForRelativeUri(_importedFiles, uri); |
93 } | 97 } |
94 for (String uri in listener.exports) { | 98 for (String uri in listener.exports) { |
95 await _addFileForRelativeUri(_exportedFiles, uri); | 99 await _addFileForRelativeUri(_exportedFiles, uri); |
96 } | 100 } |
97 for (String uri in listener.parts) { | 101 for (String uri in listener.parts) { |
98 await _addFileForRelativeUri(_partFiles, uri); | 102 await _addFileForRelativeUri(_partFiles, uri); |
99 } | 103 } |
100 | 104 |
101 // Compute referenced files. | 105 // Compute referenced libraries. |
102 _directReferencedFiles = new Set<FileState>() | 106 _directReferencedLibraries = (new Set<FileState>() |
103 ..addAll(_importedFiles) | 107 ..addAll(_importedFiles) |
104 ..addAll(_exportedFiles) | 108 ..addAll(_exportedFiles)) |
105 ..addAll(_partFiles); | 109 .toList(); |
110 } | |
111 | |
112 @override | |
113 String toString() { | |
114 if (fileUri.scheme == 'file') return fileUri.path; | |
115 return fileUri.toString(); | |
106 } | 116 } |
107 | 117 |
108 /// Add the [FileState] for the given [relativeUri] to the [files]. | 118 /// Add the [FileState] for the given [relativeUri] to the [files]. |
109 /// Do nothing if the URI cannot be parsed, cannot correspond any file, etc. | 119 /// Do nothing if the URI cannot be parsed, cannot correspond any file, etc. |
110 Future<Null> _addFileForRelativeUri( | 120 Future<Null> _addFileForRelativeUri( |
111 List<FileState> files, String relativeUri) async { | 121 List<FileState> files, String relativeUri) async { |
112 if (relativeUri.isEmpty) return; | 122 if (relativeUri.isEmpty) return; |
113 | 123 |
114 // Resolve the relative URI into absolute. | 124 // Resolve the relative URI into absolute. |
115 // The result is either: | 125 // The result is either: |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
171 file = new FileState._(this, fileUri); | 181 file = new FileState._(this, fileUri); |
172 _fileUriToFile[fileUri] = file; | 182 _fileUriToFile[fileUri] = file; |
173 | 183 |
174 // Build the sub-graph of the file. | 184 // Build the sub-graph of the file. |
175 await file.refresh(); | 185 await file.refresh(); |
176 } | 186 } |
177 return file; | 187 return file; |
178 } | 188 } |
179 } | 189 } |
180 | 190 |
191 /// List of libraries that reference each other, so form a cycle. | |
192 class LibraryCycle { | |
193 final List<FileState> libraries = <FileState>[]; | |
194 | |
195 @override | |
196 String toString() => '[' + libraries.join(', ') + ']'; | |
197 } | |
198 | |
181 /// [FileSystemState] based implementation of [FileSystem]. | 199 /// [FileSystemState] based implementation of [FileSystem]. |
182 /// It provides a consistent view on the known file system state. | 200 /// It provides a consistent view on the known file system state. |
183 class _FileSystemView implements FileSystem { | 201 class _FileSystemView implements FileSystem { |
184 final FileSystemState fsState; | 202 final FileSystemState fsState; |
185 | 203 |
186 _FileSystemView(this.fsState); | 204 _FileSystemView(this.fsState); |
187 | 205 |
188 @override | 206 @override |
189 FileSystemEntity entityForUri(Uri uri) { | 207 FileSystemEntity entityForUri(Uri uri) { |
190 FileState file = fsState._fileUriToFile[uri]; | 208 FileState file = fsState._fileUriToFile[uri]; |
(...skipping 28 matching lines...) Expand all Loading... | |
219 Future<String> readAsString() async => _shouldNotBeQueried(); | 237 Future<String> readAsString() async => _shouldNotBeQueried(); |
220 | 238 |
221 /// _FileSystemViewEntry is used by the incremental kernel generator to | 239 /// _FileSystemViewEntry is used by the incremental kernel generator to |
222 /// provide Fasta with a consistent, race condition free view of the files | 240 /// provide Fasta with a consistent, race condition free view of the files |
223 /// constituting the project. It should only need to be used for reading | 241 /// constituting the project. It should only need to be used for reading |
224 /// file contents. | 242 /// file contents. |
225 dynamic _shouldNotBeQueried() { | 243 dynamic _shouldNotBeQueried() { |
226 throw new StateError('The method should not be invoked.'); | 244 throw new StateError('The method should not be invoked.'); |
227 } | 245 } |
228 } | 246 } |
247 | |
248 /// Node in [_LibraryWalker]. | |
249 class _LibraryNode extends graph.Node<_LibraryNode> { | |
250 final _LibraryWalker walker; | |
251 final FileState file; | |
252 | |
253 @override | |
254 bool isEvaluated = false; | |
255 | |
256 _LibraryNode(this.walker, this.file); | |
257 | |
258 @override | |
259 List<_LibraryNode> computeDependencies() { | |
260 return file.directReferencedLibraries.map(walker.getNode).toList(); | |
261 } | |
262 } | |
263 | |
264 /// Helper that organizes dependencies of a library into topologically | |
265 /// sorted [LibraryCycle]s. | |
266 class _LibraryWalker extends graph.DependencyWalker<_LibraryNode> { | |
267 final nodesOfFiles = <FileState, _LibraryNode>{}; | |
268 final topologicallySortedCycles = <LibraryCycle>[]; | |
269 | |
270 @override | |
271 void evaluate(_LibraryNode v) { | |
272 evaluateScc([v]); | |
273 } | |
274 | |
275 @override | |
276 void evaluateScc(List<_LibraryNode> scc) { | |
277 var cycle = new LibraryCycle(); | |
278 for (var node in scc) { | |
279 node.isEvaluated = true; | |
280 cycle.libraries.add(node.file); | |
281 } | |
282 topologicallySortedCycles.add(cycle); | |
283 } | |
284 | |
285 _LibraryNode getNode(FileState file) { | |
286 return nodesOfFiles.putIfAbsent(file, () => new _LibraryNode(this, file)); | |
287 } | |
288 } | |
OLD | NEW |