leo_passes/loop_unrolling/
duplicate.rs

1// Copyright (C) 2019-2025 Provable Inc.
2// This file is part of the Leo library.
3
4// The Leo library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The Leo library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
16
17use leo_ast::{Block, ExpressionReconstructor, Statement, StatementReconstructor, *};
18
19use crate::SymbolTable;
20
21/// Duplicate this block, recursively giving new `NodeID`s into scopes, and duplicating the new scopes
22/// in the `SymbolTable`.
23pub fn duplicate(block: Block, symbol_table: &mut SymbolTable, node_builder: &NodeBuilder) -> Block {
24    Duplicator { symbol_table, node_builder }.reconstruct_block(block).0
25}
26
27struct Duplicator<'a> {
28    symbol_table: &'a mut SymbolTable,
29    node_builder: &'a NodeBuilder,
30}
31
32impl Duplicator<'_> {
33    fn in_scope_duped<T>(&mut self, new_id: NodeID, old_id: NodeID, func: impl FnOnce(&mut Self) -> T) -> T {
34        self.symbol_table.enter_scope_duped(new_id, old_id);
35        let result = func(self);
36        self.symbol_table.enter_parent();
37        result
38    }
39}
40
41impl TypeReconstructor for Duplicator<'_> {}
42
43impl ExpressionReconstructor for Duplicator<'_> {
44    type AdditionalOutput = ();
45}
46
47impl StatementReconstructor for Duplicator<'_> {
48    fn reconstruct_statement(&mut self, input: Statement) -> (Statement, Self::AdditionalOutput) {
49        match input {
50            Statement::Block(stmt) => {
51                let (stmt, output) = self.reconstruct_block(stmt);
52                (stmt.into(), output)
53            }
54            Statement::Conditional(stmt) => self.reconstruct_conditional(stmt),
55            Statement::Iteration(stmt) => self.reconstruct_iteration(*stmt),
56            stmt => (stmt, Default::default()),
57        }
58    }
59
60    fn reconstruct_block(&mut self, mut input: Block) -> (Block, Self::AdditionalOutput) {
61        let next_id = self.node_builder.next_id();
62        self.in_scope_duped(next_id, input.id(), |slf| {
63            input.id = next_id;
64            input.statements = input.statements.into_iter().map(|stmt| slf.reconstruct_statement(stmt).0).collect();
65            (input, Default::default())
66        })
67    }
68
69    fn reconstruct_conditional(&mut self, mut input: ConditionalStatement) -> (Statement, Self::AdditionalOutput) {
70        input.then = self.reconstruct_block(input.then).0;
71        if let Some(mut otherwise) = input.otherwise {
72            *otherwise = self.reconstruct_statement(*otherwise).0;
73            input.otherwise = Some(otherwise);
74        }
75
76        (input.into(), Default::default())
77    }
78
79    fn reconstruct_iteration(&mut self, mut input: IterationStatement) -> (Statement, Self::AdditionalOutput) {
80        let next_id = self.node_builder.next_id();
81        self.in_scope_duped(next_id, input.id(), |slf| {
82            input.id = next_id;
83            input.block = slf.reconstruct_block(input.block).0;
84            (input.into(), Default::default())
85        })
86    }
87}