1use derive_generic_visitor::*;
6use macros::{EnumAsGetters, EnumIsA, EnumToGetters};
7use serde_state::{DeserializeState, SerializeState};
8use std::mem;
9use std::sync::atomic::{AtomicUsize, Ordering};
10
11use crate::ast::*;
12
13generate_index_type!(StatementId);
15generate_index_type!(BlockId);
17
18pub type ExprBody = GExprBody<Block>;
19
20#[derive(Debug, Eq, Clone, SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
22#[serde_state(state_implements = DedupSerializerState)] pub struct Block {
24 pub span: Span,
25 #[cfg_attr(feature = "charon_on_charon", charon::rename("block_id"))]
28 pub id: BlockId,
29 pub statements: Vec<Statement>,
30}
31
32#[derive(Debug, Eq, Clone, SerializeState, DeserializeState, Drive, DriveMut, DriveTwo)]
34pub struct Statement {
35 pub span: Span,
36 #[cfg_attr(feature = "charon_on_charon", charon::rename("statement_id"))]
39 pub id: StatementId,
40 pub kind: StatementKind,
41 pub comments_before: Vec<String>,
44}
45
46#[derive(
47 Debug,
48 PartialEq,
49 Eq,
50 Clone,
51 EnumIsA,
52 EnumToGetters,
53 EnumAsGetters,
54 SerializeState,
55 DeserializeState,
56 Drive,
57 DriveMut,
58 DriveTwo,
59)]
60pub enum StatementKind {
61 Assign(Place, Rvalue),
64 SetDiscriminant(Place, VariantId),
66 StorageLive(LocalId),
71 StorageDead(LocalId),
76 PlaceMention(Place),
80 Borrowck(BorrowckStatement),
82 Drop {
88 place: Place,
89 fn_ptr: FnPtr,
91 kind: DropKind,
92 on_unwind: Block,
93 },
94 Assert {
95 assert: Assert,
96 on_failure: AbortKind,
97 on_unwind: Block,
98 },
99 InlineAsm {
101 asm: String,
102 targets: Vec<Block>,
103 on_unwind: Block,
104 },
105 Call {
106 call: Call,
107 on_unwind: Block,
108 },
109 Abort(AbortKind),
112 Return,
113 UnwindResume,
115 Break(usize),
121 Continue(usize),
127 Nop,
129 Switch {
130 data: SwitchData,
131 branches: IndexVec<BranchId, Block>,
132 },
133 Loop(Block),
134 Error(String),
135}
136
137impl PartialEq for Statement {
139 fn eq(&self, other: &Self) -> bool {
140 self.span == other.span
141 && self.kind == other.kind
142 && self.comments_before == other.comments_before
143 }
144}
145
146impl PartialEq for Block {
148 fn eq(&self, other: &Self) -> bool {
149 self.span == other.span && self.statements == other.statements
150 }
151}
152
153impl Block {
154 pub fn new(span: Span, statements: Vec<Statement>) -> Self {
155 Block {
156 span,
157 id: BlockId::fresh(),
158 statements,
159 }
160 }
161
162 pub fn new_abort(span: Span, kind: AbortKind) -> Self {
163 Statement::new(span, StatementKind::Abort(kind)).into_block()
164 }
165
166 pub fn new_unreachable(span: Span) -> Self {
167 Self::new_abort(span, AbortKind::UndefinedBehavior)
168 }
169
170 pub fn from_seq(seq: Vec<Statement>) -> Option<Self> {
171 if seq.is_empty() {
172 None
173 } else {
174 let span = seq
175 .iter()
176 .map(|st| st.span)
177 .reduce(|a, b| meta::combine_span(&a, &b))
178 .unwrap();
179 Some(Block::new(span, seq))
180 }
181 }
182
183 pub fn merge(mut self, mut other: Self) -> Self {
184 self.span = meta::combine_span(&self.span, &other.span);
185 self.statements.append(&mut other.statements);
186 self
187 }
188
189 pub fn then(mut self, r: Statement) -> Self {
190 self.span = meta::combine_span(&self.span, &r.span);
191 self.statements.push(r);
192 self
193 }
194
195 pub fn then_opt(self, other: Option<Statement>) -> Self {
196 if let Some(other) = other {
197 self.then(other)
198 } else {
199 self
200 }
201 }
202
203 pub fn visit_statements<F: FnMut(&mut Statement)>(&mut self, f: F) {
205 self.visit_helper(|_| {}, f);
206 }
207
208 pub fn transform_sequences<F: FnMut(&mut [Statement]) -> Vec<Statement>>(&mut self, mut f: F) {
217 self.visit_blocks_bwd(|blk: &mut Block| {
218 let mut final_len = blk.statements.len();
219 let mut to_insert = vec![];
220 for i in (0..blk.statements.len()).rev() {
221 let new_to_insert = f(&mut blk.statements[i..]);
222 final_len += new_to_insert.len();
223 to_insert.push((i, new_to_insert));
224 }
225 if !to_insert.is_empty() {
226 to_insert.sort_by_key(|(i, _)| *i);
227 to_insert.reverse();
229 let old_statements =
231 mem::replace(&mut blk.statements, Vec::with_capacity(final_len));
232 for (i, stmt) in old_statements.into_iter().enumerate() {
233 while let Some((j, _)) = to_insert.last()
234 && *j == i
235 {
236 let (_, mut stmts) = to_insert.pop().unwrap();
237 blk.statements.append(&mut stmts);
238 }
239 blk.statements.push(stmt);
240 }
241 }
242 })
243 }
244
245 pub fn visit_blocks_bwd<F: FnMut(&mut Block)>(&mut self, f: F) {
247 self.visit_helper(f, |_| {});
248 }
249
250 fn visit_helper<F: FnMut(&mut Block), G: FnMut(&mut Statement)>(
252 &mut self,
253 exit_blk: F,
254 enter_stmt: G,
255 ) {
256 #[derive(Visitor)]
257 pub struct BlockVisitor<F: FnMut(&mut Block), G: FnMut(&mut Statement)> {
258 exit_blk: F,
259 enter_stmt: G,
260 }
261
262 impl<F: FnMut(&mut Block), G: FnMut(&mut Statement)> VisitBodyMut for BlockVisitor<F, G> {
263 fn exit_llbc_block(&mut self, x: &mut Block) {
264 (self.exit_blk)(x)
265 }
266 fn enter_llbc_statement(&mut self, x: &mut Statement) {
267 (self.enter_stmt)(x)
268 }
269 }
270 BlockVisitor {
271 exit_blk,
272 enter_stmt,
273 }
274 .visit_by_val_infallible(self);
275 }
276}
277
278impl BlockId {
279 pub fn fresh() -> BlockId {
280 static COUNTER: AtomicUsize = AtomicUsize::new(0);
281 let id = COUNTER.fetch_add(1, Ordering::Relaxed);
282 BlockId::new(id)
283 }
284}
285
286impl Statement {
287 pub fn new(span: Span, kind: StatementKind) -> Self {
288 Statement {
289 span,
290 id: StatementId::fresh(),
291 kind,
292 comments_before: vec![],
293 }
294 }
295
296 pub fn into_box(self) -> Box<Self> {
297 Box::new(self)
298 }
299
300 pub fn into_block(self) -> Block {
301 Block::new(self.span, vec![self])
302 }
303}
304
305impl StatementId {
306 pub fn fresh() -> StatementId {
307 static COUNTER: AtomicUsize = AtomicUsize::new(0);
308 let id = COUNTER.fetch_add(1, Ordering::Relaxed);
309 StatementId::new(id)
310 }
311}