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

Side by Side Diff: pkg/front_end/lib/src/dependency_walker.dart

Issue 2554973002: Move dependency walker logic to front end. (Closed)
Patch Set: Created 4 years 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
OLDNEW
(Empty)
1
2 /**
3 * Instances of [Node] represent nodes in a dependency graph. The
4 * type parameter, [NodeType], is the derived type (this affords some
5 * extra type safety by making it difficult to accidentally construct
6 * bridges between unrelated dependency graphs).
7 */
8 abstract class Node<NodeType> {
9 /**
10 * Index used by Tarjan's strongly connected components algorithm.
11 * Zero means the node has not been visited yet; a nonzero value
12 * counts the order in which the node was visited.
13 */
14 int _index = 0;
15
16 /**
17 * Low link used by Tarjan's strongly connected components
18 * algorithm. This represents the smallest [_index] of all the nodes
19 * in the strongly connected component to which this node belongs.
20 */
21 int _lowLink = 0;
22
23 List<NodeType> _dependencies;
24
25 /**
26 * Retrieve the dependencies of this node.
27 */
28 List<NodeType> get dependencies => _dependencies ??= computeDependencies();
29
30 /**
31 * Indicates whether this node has been evaluated yet.
32 */
33 bool get isEvaluated;
34
35 /**
36 * Compute the dependencies of this node.
37 */
38 List<NodeType> computeDependencies();
39 }
40
41 /**
42 * An instance of [DependencyWalker] contains the core algorithms for
43 * walking a dependency graph and evaluating nodes in a safe order.
44 */
45 abstract class DependencyWalker<NodeType extends Node<NodeType>> {
46 /**
47 * Called by [walk] to evaluate a single non-cyclical node, after
48 * all that node's dependencies have been evaluated.
49 */
50 void evaluate(NodeType v);
51
52 /**
53 * Called by [walk] to evaluate a strongly connected component
54 * containing one or more nodes. All dependencies of the strongly
55 * connected component have been evaluated.
56 */
57 void evaluateScc(List<NodeType> scc);
58
59 /**
60 * Walk the dependency graph starting at [startingPoint], finding
61 * strongly connected components and evaluating them in a safe order
62 * by calling [evaluate] and [evaluateScc].
63 *
64 * This is an implementation of Tarjan's strongly connected
65 * components algorithm
66 * (https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_alg orithm).
67 */
68 void walk(NodeType startingPoint) {
69 // TODO(paulberry): consider rewriting in a non-recursive way so
70 // that long dependency chains don't cause stack overflow.
71
72 // TODO(paulberry): in the event that an exception occurs during
73 // the walk, restore the state of the [Node] data structures so
74 // that further evaluation will be safe.
75
76 // The index which will be assigned to the next node that is
77 // freshly visited.
78 int index = 1;
79
80 // Stack of nodes which have been seen so far and whose strongly
81 // connected component is still being determined. Nodes are only
82 // popped off the stack when they are evaluated, so sometimes the
83 // stack contains nodes that were visited after the current node.
84 List<NodeType> stack = <NodeType>[];
85
86 void strongConnect(NodeType node) {
87 bool hasTrivialCycle = false;
88
89 // Assign the current node an index and add it to the stack. We
90 // haven't seen any of its dependencies yet, so set its lowLink
91 // to its index, indicating that so far it is the only node in
92 // its strongly connected component.
93 node._index = node._lowLink = index++;
94 stack.add(node);
95
96 // Consider the node's dependencies one at a time.
97 for (NodeType dependency in node.dependencies) {
98 // If the dependency has already been evaluated, it can't be
99 // part of this node's strongly connected component, so we can
100 // skip it.
101 if (dependency.isEvaluated) {
102 continue;
103 }
104 if (identical(node, dependency)) {
105 // If a node includes itself as a dependency, there is no need to
106 // explore the dependency further.
107 hasTrivialCycle = true;
108 } else if (dependency._index == 0) {
109 // The dependency hasn't been seen yet, so recurse on it.
110 strongConnect(dependency);
111 // If the dependency's lowLink refers to a node that was
112 // visited before the current node, that means that the
113 // current node, the dependency, and the node referred to by
114 // the dependency's lowLink are all part of the same
115 // strongly connected component, so we need to update the
116 // current node's lowLink accordingly.
117 if (dependency._lowLink < node._lowLink) {
118 node._lowLink = dependency._lowLink;
119 }
120 } else {
121 // The dependency has already been seen, so it is part of
122 // the current node's strongly connected component. If it
123 // was visited earlier than the current node's lowLink, then
124 // it is a new addition to the current node's strongly
125 // connected component, so we need to update the current
126 // node's lowLink accordingly.
127 if (dependency._index < node._lowLink) {
128 node._lowLink = dependency._index;
129 }
130 }
131 }
132
133 // If the current node's lowLink is the same as its index, then
134 // we have finished visiting a strongly connected component, so
135 // pop the stack and evaluate it before moving on.
136 if (node._lowLink == node._index) {
137 // The strongly connected component has only one node. If there is a
138 // cycle, it's a trivial one.
139 if (identical(stack.last, node)) {
140 stack.removeLast();
141 if (hasTrivialCycle) {
142 evaluateScc(<NodeType>[node]);
143 } else {
144 evaluate(node);
145 }
146 } else {
147 // There are multiple nodes in the strongly connected
148 // component.
149 List<NodeType> scc = <NodeType>[];
150 while (true) {
151 NodeType otherNode = stack.removeLast();
152 scc.add(otherNode);
153 if (identical(otherNode, node)) {
154 break;
155 }
156 }
157 evaluateScc(scc);
158 }
159 }
160 }
161
162 // Kick off the algorithm starting with the starting point.
163 strongConnect(startingPoint);
164 }
165 }
OLDNEW
« no previous file with comments | « pkg/analyzer/lib/src/summary/link.dart ('k') | pkg/front_end/test/src/dependency_walker_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698