leo_passes/processing_async/program.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 super::ProcessingAsyncVisitor;
18use leo_ast::{
19 AstReconstructor,
20 ConstParameter,
21 Function,
22 Input,
23 Node,
24 Output,
25 ProgramReconstructor,
26 ProgramScope,
27 Statement,
28};
29
30impl ProgramReconstructor for ProcessingAsyncVisitor<'_> {
31 /// Reconstructs a `ProgramScope` by rewriting all contained elements:
32 /// - Updates the current program context.
33 /// - Reconstructs all functions using `reconstruct_function`.
34 /// - Reconstructs structs, mappings, and constants.
35 /// - Inserts reconstructed functions, including any newly created async functions,
36 /// placing transitions before other functions.
37 ///
38 /// This prepares the scope for further analysis or compilation, ensuring all
39 /// components have gone through transformation.
40 fn reconstruct_program_scope(&mut self, input: ProgramScope) -> ProgramScope {
41 // Set the current program context
42 self.current_program = input.program_id.name.name;
43
44 // Reconstruct all functions and store them temporarily. This process also populates
45 // `new_async_functions`.
46 let mut reconstructed_functions: Vec<_> =
47 input.functions.iter().map(|(name, func)| (*name, self.reconstruct_function(func.clone()))).collect();
48
49 // Now append all newly created `async` functions. This ensures transition functions still show up before all other functions.
50 reconstructed_functions.append(&mut self.new_async_functions);
51
52 ProgramScope {
53 program_id: input.program_id,
54 structs: input.structs.into_iter().map(|(id, def)| (id, self.reconstruct_struct(def))).collect(),
55 mappings: input.mappings.into_iter().map(|(id, mapping)| (id, self.reconstruct_mapping(mapping))).collect(),
56 storage_variables: input
57 .storage_variables
58 .into_iter()
59 .map(|(id, storage_variable)| (id, self.reconstruct_storage_variable(storage_variable)))
60 .collect(),
61 functions: reconstructed_functions,
62 constructor: input.constructor,
63 consts: input
64 .consts
65 .into_iter()
66 .map(|(id, stmt)| match self.reconstruct_const(stmt) {
67 (Statement::Const(decl), _) => (id, decl),
68 _ => panic!("`reconstruct_const` must return `Statement::Const`"),
69 })
70 .collect(),
71 span: input.span,
72 }
73 }
74
75 fn reconstruct_function(&mut self, input: Function) -> Function {
76 self.current_function = input.name();
77
78 // Enter the scope of the function for correct symbols lookup later
79 self.in_scope(input.id(), |slf| Function {
80 annotations: input.annotations,
81 variant: input.variant,
82 identifier: input.identifier,
83 const_parameters: input
84 .const_parameters
85 .iter()
86 .map(|param| ConstParameter { type_: slf.reconstruct_type(param.type_.clone()).0, ..param.clone() })
87 .collect(),
88 input: input
89 .input
90 .iter()
91 .map(|input| Input { type_: slf.reconstruct_type(input.type_.clone()).0, ..input.clone() })
92 .collect(),
93 output: input
94 .output
95 .iter()
96 .map(|output| Output { type_: slf.reconstruct_type(output.type_.clone()).0, ..output.clone() })
97 .collect(),
98 output_type: slf.reconstruct_type(input.output_type).0,
99 block: slf.reconstruct_block(input.block).0,
100 span: input.span,
101 id: input.id,
102 })
103 }
104}