1use derive_generic_visitor::*;
3use std::mem;
4use std::sync::atomic::{AtomicUsize, Ordering};
5
6use crate::llbc_ast::*;
7use crate::meta;
8use crate::meta::Span;
9
10pub fn combine_switch_targets_span(targets: &Switch) -> Span {
12 match targets {
13 Switch::If(_, st1, st2) => meta::combine_span(&st1.span, &st2.span),
14 Switch::SwitchInt(_, _, branches, otherwise) => {
15 let branches = branches.iter().map(|b| &b.1.span);
16 let mbranches = meta::combine_span_iter(branches);
17 meta::combine_span(&mbranches, &otherwise.span)
18 }
19 Switch::Match(_, branches, otherwise) => {
20 let branches = branches.iter().map(|b| &b.1.span);
21 let mbranches = meta::combine_span_iter(branches);
22 if let Some(otherwise) = otherwise {
23 meta::combine_span(&mbranches, &otherwise.span)
24 } else {
25 mbranches
26 }
27 }
28 }
29}
30
31impl Switch {
32 pub fn iter_targets(&self) -> impl Iterator<Item = &Block> {
33 use itertools::Either;
34 match self {
35 Switch::If(_, exp1, exp2) => Either::Left([exp1, exp2].into_iter()),
36 Switch::SwitchInt(_, _, targets, otherwise) => Either::Right(Either::Left(
37 targets.iter().map(|(_, tgt)| tgt).chain([otherwise]),
38 )),
39 Switch::Match(_, targets, otherwise) => Either::Right(Either::Right(
40 targets.iter().map(|(_, tgt)| tgt).chain(otherwise.as_ref()),
41 )),
42 }
43 }
44
45 pub fn iter_targets_mut(&mut self) -> impl Iterator<Item = &mut Block> {
46 use itertools::Either;
47 match self {
48 Switch::If(_, exp1, exp2) => Either::Left([exp1, exp2].into_iter()),
49 Switch::SwitchInt(_, _, targets, otherwise) => Either::Right(Either::Left(
50 targets.iter_mut().map(|(_, tgt)| tgt).chain([otherwise]),
51 )),
52 Switch::Match(_, targets, otherwise) => Either::Right(Either::Right(
53 targets
54 .iter_mut()
55 .map(|(_, tgt)| tgt)
56 .chain(otherwise.as_mut()),
57 )),
58 }
59 }
60}
61
62impl StatementId {
63 pub fn fresh() -> StatementId {
64 static COUNTER: AtomicUsize = AtomicUsize::new(0);
65 let id = COUNTER.fetch_add(1, Ordering::Relaxed);
66 StatementId::new(id)
67 }
68}
69
70impl BlockId {
71 pub fn fresh() -> BlockId {
72 static COUNTER: AtomicUsize = AtomicUsize::new(0);
73 let id = COUNTER.fetch_add(1, Ordering::Relaxed);
74 BlockId::new(id)
75 }
76}
77
78impl Statement {
79 pub fn new(span: Span, kind: StatementKind) -> Self {
80 Statement {
81 span,
82 id: StatementId::fresh(),
83 kind,
84 comments_before: vec![],
85 }
86 }
87
88 pub fn into_box(self) -> Box<Self> {
89 Box::new(self)
90 }
91
92 pub fn into_block(self) -> Block {
93 Block::new(self.span, vec![self])
94 }
95}
96
97impl Block {
98 pub fn new(span: Span, statements: Vec<Statement>) -> Self {
99 Block {
100 span,
101 id: BlockId::fresh(),
102 statements,
103 }
104 }
105
106 pub fn new_abort(span: Span, kind: AbortKind) -> Self {
107 Statement::new(span, StatementKind::Abort(kind)).into_block()
108 }
109
110 pub fn new_unreachable(span: Span) -> Self {
111 Self::new_abort(span, AbortKind::UndefinedBehavior)
112 }
113
114 pub fn from_seq(seq: Vec<Statement>) -> Option<Self> {
115 if seq.is_empty() {
116 None
117 } else {
118 let span = seq
119 .iter()
120 .map(|st| st.span)
121 .reduce(|a, b| meta::combine_span(&a, &b))
122 .unwrap();
123 Some(Block::new(span, seq))
124 }
125 }
126
127 pub fn merge(mut self, mut other: Self) -> Self {
128 self.span = meta::combine_span(&self.span, &other.span);
129 self.statements.append(&mut other.statements);
130 self
131 }
132
133 pub fn then(mut self, r: Statement) -> Self {
134 self.span = meta::combine_span(&self.span, &r.span);
135 self.statements.push(r);
136 self
137 }
138
139 pub fn then_opt(self, other: Option<Statement>) -> Self {
140 if let Some(other) = other {
141 self.then(other)
142 } else {
143 self
144 }
145 }
146
147 pub fn visit_statements<F: FnMut(&mut Statement)>(&mut self, f: F) {
149 let _ = BlockVisitor::new(|_| {}, f).visit(self);
150 }
151
152 pub fn transform_sequences<F: FnMut(&mut [Statement]) -> Vec<Statement>>(&mut self, mut f: F) {
161 self.visit_blocks_bwd(|blk: &mut Block| {
162 let mut final_len = blk.statements.len();
163 let mut to_insert = vec![];
164 for i in (0..blk.statements.len()).rev() {
165 let new_to_insert = f(&mut blk.statements[i..]);
166 final_len += new_to_insert.len();
167 to_insert.push((i, new_to_insert));
168 }
169 if !to_insert.is_empty() {
170 to_insert.sort_by_key(|(i, _)| *i);
171 to_insert.reverse();
173 let old_statements =
175 mem::replace(&mut blk.statements, Vec::with_capacity(final_len));
176 for (i, stmt) in old_statements.into_iter().enumerate() {
177 while let Some((j, _)) = to_insert.last()
178 && *j == i
179 {
180 let (_, mut stmts) = to_insert.pop().unwrap();
181 blk.statements.append(&mut stmts);
182 }
183 blk.statements.push(stmt);
184 }
185 }
186 })
187 }
188
189 pub fn visit_blocks_bwd<F: FnMut(&mut Block)>(&mut self, f: F) {
191 let _ = BlockVisitor::new(f, |_| {}).visit(self);
192 }
193}
194
195#[derive(Visitor)]
197pub struct BlockVisitor<F: FnMut(&mut Block), G: FnMut(&mut Statement)> {
198 exit_blk: F,
199 enter_stmt: G,
200}
201
202impl<F: FnMut(&mut Block), G: FnMut(&mut Statement)> BlockVisitor<F, G> {
203 pub fn new(exit_blk: F, enter_stmt: G) -> Self {
204 Self {
205 exit_blk,
206 enter_stmt,
207 }
208 }
209}
210
211impl<F: FnMut(&mut Block), G: FnMut(&mut Statement)> VisitBodyMut for BlockVisitor<F, G> {
212 fn exit_llbc_block(&mut self, x: &mut Block) {
213 (self.exit_blk)(x)
214 }
215 fn enter_llbc_statement(&mut self, x: &mut Statement) {
216 (self.enter_stmt)(x)
217 }
218}