charon_lib/ast/
ullbc_ast_utils.rs

1//! Implementations for [crate::ullbc_ast]
2use 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, content: RawStatement) -> Self {
26        Statement {
27            span,
28            content,
29            comments_before: vec![],
30        }
31    }
32}
33
34impl Terminator {
35    pub fn new(span: Span, content: RawTerminator) -> Self {
36        Terminator {
37            span,
38            content,
39            comments_before: vec![],
40        }
41    }
42    pub fn goto(span: Span, target: BlockId) -> Self {
43        Self::new(span, RawTerminator::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    /// Build a block that's just a goto terminator.
56    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.content {
65            RawTerminator::Goto { target } => {
66                vec![*target]
67            }
68            RawTerminator::Switch { targets, .. } => targets.get_targets(),
69            RawTerminator::Call {
70                call: _,
71                target,
72                on_unwind,
73            } => vec![*target, *on_unwind],
74            RawTerminator::Abort(..) | RawTerminator::Return | RawTerminator::UnwindResume => {
75                vec![]
76            }
77        }
78    }
79
80    /// TODO: Write new documentation
81    pub fn transform_operands<F: FnMut(&Span, &mut Vec<Statement>, &mut Operand)>(
82        &mut self,
83        mut f: F,
84    ) {
85        // Explore the operands in the statements
86        for mut st in mem::take(&mut self.statements) {
87            st.content
88                .dyn_visit_in_body_mut(|op: &mut Operand| f(&st.span, &mut self.statements, op));
89            // Add the statement to the vector of statements
90            self.statements.push(st)
91        }
92
93        // Explore the terminator
94        self.terminator
95            .content
96            .dyn_visit_in_body_mut(|op: &mut Operand| {
97                f(&self.terminator.span, &mut self.statements, op)
98            });
99    }
100
101    /// Apply a transformer to all the statements.
102    ///
103    /// The transformer should:
104    /// - mutate the current statement in place
105    /// - return the sequence of statements to introduce before the current statement
106    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    /// Helper, see `transform_sequences_fwd` and `transform_sequences_bwd`.
118    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            // Make it so the first element is always at the end so we can pop it.
144            to_insert.reverse();
145            // Construct the merged list of statements.
146            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    /// Apply a transformer to all the statements.
160    ///
161    /// The transformer should:
162    /// - mutate the current statements in place
163    /// - return a list of `(i, statements)` where `statements` will be inserted before index `i`.
164    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    /// Apply a transformer to all the statements.
172    ///
173    /// The transformer should:
174    /// - mutate the current statements in place
175    /// - return a list of `(i, statements)` where `statements` will be inserted before index `i`.
176    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    /// Apply a function to all the statements, in a bottom-up manner.
204    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}