Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(136)

Side by Side Diff: pkg/front_end/lib/src/incremental/file_state.dart

Issue 2879783002: Compute topologically sorted library cycles. (Closed)
Patch Set: Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | pkg/front_end/lib/src/incremental_kernel_generator_impl.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | pkg/front_end/lib/src/incremental_kernel_generator_impl.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698