1use petgraph::graph::NodeIndex;
2
3use super::control_data::*;
4use super::control_flow::*;
5
6pub trait UniquePassenger<E> {
7 fn start(&mut self, id: NodeIndex) -> Result<(), E>;
8 fn end(&mut self, id: NodeIndex) -> Result<(), E>;
9 fn loop_head(
10 &mut self,
11 id: NodeIndex,
12 ld: &mut LoopData,
13 expr: &mut ExprData,
14 ) -> Result<(), E>;
15 fn loop_foot(&mut self, id: NodeIndex, ld: &mut LoopData) -> Result<(), E>;
16 fn cont(&mut self, id: NodeIndex, ld: &mut LoopData) -> Result<(), E>;
17 fn br(&mut self, id: NodeIndex, ld: &mut LoopData) -> Result<(), E>;
18 fn enter_scope(&mut self, id: NodeIndex) -> Result<(), E>;
19 fn exit_scope(&mut self, id: NodeIndex) -> Result<(), E>;
20 fn local_var_decl(
21 &mut self,
22 id: NodeIndex,
23 decl: &mut LocalVarDeclData,
24 ) -> Result<(), E>;
25 fn assignment(
26 &mut self,
27 id: NodeIndex,
28 assign: &mut AssignmentData,
29 ) -> Result<(), E>;
30 fn expr(&mut self, id: NodeIndex, expr: &mut ExprData) -> Result<(), E>;
31 fn ret(&mut self, id: NodeIndex, rdata: &mut ReturnData) -> Result<(), E>;
32
33 fn loop_start_true_path(&mut self, id: NodeIndex) -> Result<(), E>;
34 fn loop_end_true_path(&mut self, id: NodeIndex) -> Result<(), E>;
35
36 fn branch_split(
37 &mut self,
38 id: NodeIndex,
39 b: &mut BranchingData,
40 e: &mut ExprData,
41 ) -> Result<(), E>;
42 fn branch_merge(
43 &mut self,
44 id: NodeIndex,
45 b: &mut BranchingData,
46 ) -> Result<(), E>;
47 fn branch_start_true_path(&mut self, id: NodeIndex) -> Result<(), E>;
48 fn branch_start_false_path(&mut self, id: NodeIndex) -> Result<(), E>;
49 fn branch_end_true_path(
50 &mut self,
51 id: NodeIndex,
52 b: &mut BranchingData,
53 ) -> Result<(), E>;
54 fn branch_end_false_path(
55 &mut self,
56 id: NodeIndex,
57 b: &mut BranchingData,
58 ) -> Result<(), E>;
59}
60
61pub fn traverse<E>(
62 graph: &mut CFG,
63 passenger: &mut dyn UniquePassenger<E>,
64) -> Result<(), E> {
65 let mut current = Some(graph.start());
66 let node_count = graph.graph().node_count();
67
68 for _ in 0..node_count {
70 match current {
71 Some(to_visit) => current = visit_node(graph, to_visit, passenger)?,
72 None => break,
73 }
74 }
75
76 if current.is_some() {
77 panic!("Graph traversal error. Node::End should have returned None. If Node::End was reached, this panic should not be triggered.")
78 }
79
80 Ok(())
81}
82
83fn visit_node<E>(
84 graph: &mut CFG,
85 current: NodeIndex,
86 passenger: &mut dyn UniquePassenger<E>,
87) -> Result<Option<NodeIndex>, E> {
88 let node_count = graph.graph().node_count();
89 match graph.node_weight_mut(current) {
90 Node::End => {
91 passenger.end(current)?;
92 Ok(None)
93 }
94
95 Node::Start => {
96 passenger.start(current)?;
97 Ok(Some(graph.next(current)))
98 }
99
100 Node::BranchSplit(ref mut branch_data, ref mut expr_data) => {
101 passenger.branch_split(current, branch_data, expr_data)?;
102
103 let (true_path, false_path) = graph.after_conditional(current);
104
105 passenger.branch_start_true_path(true_path)?;
106
107 let mut merge = None;
108
109 let mut current_node = true_path;
111 for _ in 0..node_count {
112 match graph.node_weight_mut(current_node) {
113 Node::BranchMerge(ref mut branch_data) => {
114 passenger
115 .branch_end_true_path(current_node, branch_data)?;
116 merge = Some(current_node);
117 break;
118 }
119
120 _ => (),
121 }
122
123 match visit_node(graph, current_node, passenger)? {
124 Some(next) => current_node = next,
125 None => break,
126 }
127 }
128
129 if merge.is_none() {
130 panic!("Traversed entire graph and did not find Condition::BranchMerge");
131 }
132
133 passenger.branch_start_false_path(false_path)?;
134
135 let mut current_node = false_path;
137 let mut merge = None;
138 for _ in 0..node_count {
139 match graph.node_weight_mut(current_node) {
140 Node::BranchMerge(ref mut branch_data) => {
141 passenger
142 .branch_end_false_path(current_node, branch_data)?;
143 passenger.branch_merge(current_node, branch_data)?;
144 merge = Some(current_node);
145 break;
146 }
147
148 _ => (),
149 }
150
151 match visit_node(graph, current_node, passenger)? {
152 Some(next) => current_node = next,
153 None => panic!(),
154 }
155 }
156
157 if merge.is_none() {
158 panic!("Traversed entire graph and did not find Condition::BranchMerge");
159 }
160
161 Ok(Some(graph.next(merge.unwrap())))
162 }
163
164 Node::BranchMerge(ref mut _branch_data) => {
165 unreachable!();
166 }
167
168 Node::LoopHead(ref mut branch_data, ref mut expr_data) => {
169 passenger.loop_head(current, branch_data, expr_data)?;
170 let (true_path, false_path) = graph.after_conditional(current);
171 passenger.loop_start_true_path(true_path)?;
172
173 let mut current_node = true_path;
174 let mut found_foot = false;
175 for _ in 0..node_count {
176 match graph.node_weight_mut(current_node) {
177 Node::LoopFoot(ref mut loop_data) => {
178 passenger.loop_end_true_path(current_node)?;
179 passenger.loop_foot(current_node, loop_data)?;
180 found_foot = true;
181 break;
182 }
183
184 _ => (),
185 }
186
187 match visit_node(graph, current_node, passenger)? {
188 Some(next) => current_node = next,
189 None => return Ok(None),
190 }
191 }
192
193 if found_foot == false {
194 panic!(
195 "Traversed the rest of the graph but did not find a Node::LoopFoot."
196 );
197 }
198
199 match graph.node_weight_mut(false_path) {
200 Node::LoopFoot(_) => (),
201 ref mut n @ _ => println!("Loop condition should be connected to Node::LoopFoot along the false path. Found {:?}.", n),
202 }
203
204 Ok(Some(graph.after_loop_foot(false_path)))
205 }
206
207 Node::LoopFoot(ref mut _data) => {
208 unreachable!();
209 }
210
211 Node::Continue(ref mut data) => {
212 passenger.cont(current, data)?;
213 Ok(Some(graph.after_continue(current)))
214 }
215
216 Node::Break(ref mut data) => {
217 passenger.br(current, data)?;
218 Ok(Some(graph.after_break(current)))
219 }
220
221 Node::EnterScope => {
222 passenger.enter_scope(current)?;
223 Ok(Some(graph.next(current)))
224 }
225
226 Node::ExitScope => {
227 passenger.exit_scope(current)?;
228 Ok(Some(graph.next(current)))
229 }
230
231 Node::Block(ref mut basic_block) => {
232 for n in basic_block.graph_mut() {
233 match *n {
234 BlockNode::LocalVarDecl(ref mut decl) => {
235 passenger.local_var_decl(current, decl)?;
236 }
237
238 BlockNode::Assignment(ref mut assign) => {
239 passenger.assignment(current, assign)?;
240 }
241
242 BlockNode::Expr(ref mut expr) => {
243 passenger.expr(current, expr)?;
244 }
245 }
246 }
247
248 Ok(Some(graph.next(current)))
249 }
250
251 Node::Return(ref mut rdata) => {
252 passenger.ret(current, rdata)?;
253 Ok(Some(graph.after_return(current)))
254 }
255 }
256}