1use crate::meta::Span;
3use crate::ullbc_ast::*;
4use std::mem;
5
6impl SwitchTargets {
7 pub fn get_targets(&self) -> Vec<BlockId> {
8 match self {
9 SwitchTargets::If(then_tgt, else_tgt) => {
10 vec![*then_tgt, *else_tgt]
11 }
12 SwitchTargets::SwitchInt(_, targets, otherwise) => {
13 let mut all_targets = vec![];
14 for (_, target) in targets {
15 all_targets.push(*target);
16 }
17 all_targets.push(*otherwise);
18 all_targets
19 }
20 }
21 }
22}
23
24impl Statement {
25 pub fn new(span: Span, kind: StatementKind) -> Self {
26 Statement {
27 span,
28 kind,
29 comments_before: vec![],
30 }
31 }
32}
33
34impl Terminator {
35 pub fn new(span: Span, kind: TerminatorKind) -> Self {
36 Terminator {
37 span,
38 kind,
39 comments_before: vec![],
40 }
41 }
42 pub fn goto(span: Span, target: BlockId) -> Self {
43 Self::new(span, TerminatorKind::Goto { target })
44 }
45
46 pub fn into_block(self) -> BlockData {
47 BlockData {
48 statements: vec![],
49 terminator: self,
50 }
51 }
52}
53
54impl BlockData {
55 pub fn new_goto(span: Span, target: BlockId) -> Self {
57 BlockData {
58 statements: vec![],
59 terminator: Terminator::goto(span, target),
60 }
61 }
62
63 pub fn targets(&self) -> Vec<BlockId> {
64 match &self.terminator.kind {
65 TerminatorKind::Goto { target } => {
66 vec![*target]
67 }
68 TerminatorKind::Switch { targets, .. } => targets.get_targets(),
69 TerminatorKind::Call {
70 call: _,
71 target,
72 on_unwind,
73 } => vec![*target, *on_unwind],
74 TerminatorKind::Abort(..) | TerminatorKind::Return | TerminatorKind::UnwindResume => {
75 vec![]
76 }
77 }
78 }
79
80 pub fn transform_operands<F: FnMut(&Span, &mut Vec<Statement>, &mut Operand)>(
82 &mut self,
83 mut f: F,
84 ) {
85 for mut st in mem::take(&mut self.statements) {
87 st.kind
88 .dyn_visit_in_body_mut(|op: &mut Operand| f(&st.span, &mut self.statements, op));
89 self.statements.push(st)
91 }
92
93 self.terminator
95 .kind
96 .dyn_visit_in_body_mut(|op: &mut Operand| {
97 f(&self.terminator.span, &mut self.statements, op)
98 });
99 }
100
101 pub fn transform<F: FnMut(&mut Statement) -> Vec<Statement>>(&mut self, mut f: F) {
107 self.transform_sequences_bwd(|slice| {
108 let new_statements = f(&mut slice[0]);
109 if new_statements.is_empty() {
110 vec![]
111 } else {
112 vec![(0, new_statements)]
113 }
114 });
115 }
116
117 fn transform_sequences<F>(&mut self, mut f: F, forward: bool)
119 where
120 F: FnMut(&mut [Statement]) -> Vec<(usize, Vec<Statement>)>,
121 {
122 let mut to_insert = vec![];
123 let mut final_len = self.statements.len();
124 if forward {
125 for i in 0..self.statements.len() {
126 let new_to_insert = f(&mut self.statements[i..]);
127 to_insert.extend(new_to_insert.into_iter().map(|(j, stmts)| {
128 final_len += stmts.len();
129 (i + j, stmts)
130 }));
131 }
132 } else {
133 for i in (0..self.statements.len()).rev() {
134 let new_to_insert = f(&mut self.statements[i..]);
135 to_insert.extend(new_to_insert.into_iter().map(|(j, stmts)| {
136 final_len += stmts.len();
137 (i + j, stmts)
138 }));
139 }
140 }
141 if !to_insert.is_empty() {
142 to_insert.sort_by_key(|(i, _)| *i);
143 to_insert.reverse();
145 let old_statements = mem::replace(&mut self.statements, Vec::with_capacity(final_len));
147 for (i, stmt) in old_statements.into_iter().enumerate() {
148 while let Some((j, _)) = to_insert.last()
149 && *j == i
150 {
151 let (_, mut stmts) = to_insert.pop().unwrap();
152 self.statements.append(&mut stmts);
153 }
154 self.statements.push(stmt);
155 }
156 }
157 }
158
159 pub fn transform_sequences_fwd<F>(&mut self, f: F)
165 where
166 F: FnMut(&mut [Statement]) -> Vec<(usize, Vec<Statement>)>,
167 {
168 self.transform_sequences(f, true);
169 }
170
171 pub fn transform_sequences_bwd<F>(&mut self, f: F)
177 where
178 F: FnMut(&mut [Statement]) -> Vec<(usize, Vec<Statement>)>,
179 {
180 self.transform_sequences(f, false);
181 }
182}
183
184impl ExprBody {
185 pub fn transform_sequences_fwd<F>(&mut self, mut f: F)
186 where
187 F: FnMut(&mut Locals, &mut [Statement]) -> Vec<(usize, Vec<Statement>)>,
188 {
189 for block in &mut self.body {
190 block.transform_sequences_fwd(|seq| f(&mut self.locals, seq));
191 }
192 }
193
194 pub fn transform_sequences_bwd<F>(&mut self, mut f: F)
195 where
196 F: FnMut(&mut Locals, &mut [Statement]) -> Vec<(usize, Vec<Statement>)>,
197 {
198 for block in &mut self.body {
199 block.transform_sequences_bwd(|seq| f(&mut self.locals, seq));
200 }
201 }
202
203 pub fn visit_statements<F: FnMut(&mut Statement)>(&mut self, mut f: F) {
205 for block in self.body.iter_mut().rev() {
206 for st in block.statements.iter_mut().rev() {
207 f(st);
208 }
209 }
210 }
211}
212
213pub struct BodyBuilder {
215 pub span: Span,
217 pub body: ExprBody,
219 pub current_block: BlockId,
221 pub unwind_block: Option<BlockId>,
223}
224
225fn mk_block(span: Span, term: TerminatorKind) -> BlockData {
226 BlockData {
227 statements: vec![],
228 terminator: Terminator::new(span, term),
229 }
230}
231
232impl BodyBuilder {
233 pub fn new(span: Span, arg_count: usize) -> Self {
234 let mut body: ExprBody = GExprBody {
235 span,
236 locals: Locals::new(arg_count),
237 comments: vec![],
238 body: Vector::new(),
239 };
240 let current_block = body.body.push(BlockData {
241 statements: Default::default(),
242 terminator: Terminator::new(span, TerminatorKind::Return),
243 });
244 Self {
245 span,
246 body,
247 current_block,
248 unwind_block: None,
249 }
250 }
251
252 pub fn build(self) -> ExprBody {
254 self.body
255 }
256
257 pub fn new_var(&mut self, name: Option<String>, ty: Ty) -> Place {
260 let place = self.body.locals.new_var(name, ty);
261 let local_id = place.as_local().unwrap();
262 if !self.body.locals.is_return_or_arg(local_id) {
263 self.push_statement(StatementKind::StorageLive(local_id));
264 }
265 place
266 }
267
268 fn current_block(&mut self) -> &mut BlockData {
270 &mut self.body.body[self.current_block]
271 }
272
273 pub fn push_statement(&mut self, kind: StatementKind) {
274 let st = Statement::new(self.span, kind);
275 self.current_block().statements.push(st);
276 }
277
278 fn unwind_block(&mut self) -> BlockId {
279 *self.unwind_block.get_or_insert_with(|| {
280 self.body
281 .body
282 .push(mk_block(self.span, TerminatorKind::UnwindResume))
283 })
284 }
285
286 pub fn call(&mut self, call: Call) {
287 let next_block = self
288 .body
289 .body
290 .push(mk_block(self.span, TerminatorKind::Return));
291 let term = TerminatorKind::Call {
292 target: next_block,
293 call,
294 on_unwind: self.unwind_block(),
295 };
296 self.current_block().terminator.kind = term;
297 self.current_block = next_block;
298 }
299}