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 functions: reconstructed_functions,
57 constructor: input.constructor,
58 consts: input
59 .consts
60 .into_iter()
61 .map(|(id, stmt)| match self.reconstruct_const(stmt) {
62 (Statement::Const(decl), _) => (id, decl),
63 _ => panic!("`reconstruct_const` must return `Statement::Const`"),
64 })
65 .collect(),
66 span: input.span,
67 }
68 }
69
70 fn reconstruct_function(&mut self, input: Function) -> Function {
71 self.current_function = input.name();
72
73 // Enter the scope of the function for correct symbols lookup later
74 self.in_scope(input.id(), |slf| Function {
75 annotations: input.annotations,
76 variant: input.variant,
77 identifier: input.identifier,
78 const_parameters: input
79 .const_parameters
80 .iter()
81 .map(|param| ConstParameter { type_: slf.reconstruct_type(param.type_.clone()).0, ..param.clone() })
82 .collect(),
83 input: input
84 .input
85 .iter()
86 .map(|input| Input { type_: slf.reconstruct_type(input.type_.clone()).0, ..input.clone() })
87 .collect(),
88 output: input
89 .output
90 .iter()
91 .map(|output| Output { type_: slf.reconstruct_type(output.type_.clone()).0, ..output.clone() })
92 .collect(),
93 output_type: slf.reconstruct_type(input.output_type).0,
94 block: slf.reconstruct_block(input.block).0,
95 span: input.span,
96 id: input.id,
97 })
98 }
99}