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 { call: _, target } => vec![*target],
70            RawTerminator::Abort(..) | RawTerminator::Return => {
71                vec![]
72            }
73        }
74    }
75
76    /// See [body_transform_operands]
77    pub fn transform_operands<F: FnMut(&Span, &mut Vec<Statement>, &mut Operand)>(
78        &mut self,
79        mut f: F,
80    ) {
81        // Explore the operands in the statements
82        for mut st in mem::take(&mut self.statements) {
83            st.content
84                .dyn_visit_in_body_mut(|op: &mut Operand| f(&st.span, &mut self.statements, op));
85            // Add the statement to the vector of statements
86            self.statements.push(st)
87        }
88
89        // Explore the terminator
90        self.terminator
91            .content
92            .dyn_visit_in_body_mut(|op: &mut Operand| {
93                f(&self.terminator.span, &mut self.statements, op)
94            });
95    }
96
97    /// Apply a transformer to all the statements.
98    ///
99    /// The transformer should:
100    /// - mutate the current statement in place
101    /// - return the sequence of statements to introduce before the current statement
102    pub fn transform<F: FnMut(&mut Statement) -> Vec<Statement>>(&mut self, mut f: F) {
103        self.transform_sequences_bwd(|slice| {
104            let new_statements = f(&mut slice[0]);
105            if new_statements.is_empty() {
106                vec![]
107            } else {
108                vec![(0, new_statements)]
109            }
110        });
111    }
112
113    /// Helper, see `transform_sequences_fwd` and `transform_sequences_bwd`.
114    fn transform_sequences<F>(&mut self, mut f: F, forward: bool)
115    where
116        F: FnMut(&mut [Statement]) -> Vec<(usize, Vec<Statement>)>,
117    {
118        let mut to_insert = vec![];
119        let mut final_len = self.statements.len();
120        if forward {
121            for i in 0..self.statements.len() {
122                let new_to_insert = f(&mut self.statements[i..]);
123                to_insert.extend(new_to_insert.into_iter().map(|(j, stmts)| {
124                    final_len += stmts.len();
125                    (i + j, stmts)
126                }));
127            }
128        } else {
129            for i in (0..self.statements.len()).rev() {
130                let new_to_insert = f(&mut self.statements[i..]);
131                to_insert.extend(new_to_insert.into_iter().map(|(j, stmts)| {
132                    final_len += stmts.len();
133                    (i + j, stmts)
134                }));
135            }
136        }
137        if !to_insert.is_empty() {
138            to_insert.sort_by_key(|(i, _)| *i);
139            // Make it so the first element is always at the end so we can pop it.
140            to_insert.reverse();
141            // Construct the merged list of statements.
142            let old_statements = mem::replace(&mut self.statements, Vec::with_capacity(final_len));
143            for (i, stmt) in old_statements.into_iter().enumerate() {
144                while let Some((j, _)) = to_insert.last()
145                    && *j == i
146                {
147                    let (_, mut stmts) = to_insert.pop().unwrap();
148                    self.statements.append(&mut stmts);
149                }
150                self.statements.push(stmt);
151            }
152        }
153    }
154
155    /// Apply a transformer to all the statements.
156    ///
157    /// The transformer should:
158    /// - mutate the current statements in place
159    /// - return a list of `(i, statements)` where `statements` will be inserted before index `i`.
160    pub fn transform_sequences_fwd<F>(&mut self, f: F)
161    where
162        F: FnMut(&mut [Statement]) -> Vec<(usize, Vec<Statement>)>,
163    {
164        self.transform_sequences(f, true);
165    }
166
167    /// Apply a transformer to all the statements.
168    ///
169    /// The transformer should:
170    /// - mutate the current statements in place
171    /// - return a list of `(i, statements)` where `statements` will be inserted before index `i`.
172    pub fn transform_sequences_bwd<F>(&mut self, f: F)
173    where
174        F: FnMut(&mut [Statement]) -> Vec<(usize, Vec<Statement>)>,
175    {
176        self.transform_sequences(f, false);
177    }
178}
179
180impl ExprBody {
181    pub fn transform_sequences_fwd<F>(&mut self, mut f: F)
182    where
183        F: FnMut(&mut Locals, &mut [Statement]) -> Vec<(usize, Vec<Statement>)>,
184    {
185        for block in &mut self.body {
186            block.transform_sequences_fwd(|seq| f(&mut self.locals, seq));
187        }
188    }
189
190    pub fn transform_sequences_bwd<F>(&mut self, mut f: F)
191    where
192        F: FnMut(&mut Locals, &mut [Statement]) -> Vec<(usize, Vec<Statement>)>,
193    {
194        for block in &mut self.body {
195            block.transform_sequences_bwd(|seq| f(&mut self.locals, seq));
196        }
197    }
198
199    /// Apply a function to all the statements, in a bottom-up manner.
200    pub fn visit_statements<F: FnMut(&mut Statement)>(&mut self, mut f: F) {
201        for block in self.body.iter_mut().rev() {
202            for st in block.statements.iter_mut().rev() {
203                f(st);
204            }
205        }
206    }
207}