1use crate::{CompilerState, Pass};
36
37use leo_ast::{
38 AleoProgram,
39 AstVisitor,
40 Composite,
41 ConstDeclaration,
42 Function,
43 FunctionStub,
44 Interface,
45 Library,
46 Location,
47 Mapping,
48 MappingType,
49 Module,
50 OptionalType,
51 ProgramScope,
52 ProgramVisitor,
53 StorageVariable,
54 Type,
55};
56use leo_errors::Result;
57use leo_span::Symbol;
58
59pub struct GlobalItemsCollection;
63
64impl Pass for GlobalItemsCollection {
65 type Input = ();
66 type Output = ();
67
68 const NAME: &'static str = "GlobalItemsCollection";
69
70 fn do_pass(_input: Self::Input, state: &mut CompilerState) -> Result<Self::Output> {
71 let ast = std::mem::take(&mut state.ast);
72 let mut visitor = GlobalItemsCollectionVisitor { state, program_name: Symbol::intern(""), module: vec![] };
73
74 ast.visit(
75 |program| visitor.visit_program(program),
76 |library| {
77 let _ = library;
79 },
80 );
81
82 visitor.state.handler.last_err()?;
83 visitor.state.ast = ast;
84 Ok(())
85 }
86}
87
88struct GlobalItemsCollectionVisitor<'a> {
89 state: &'a mut CompilerState,
91 program_name: Symbol,
93 module: Vec<Symbol>,
95}
96
97impl GlobalItemsCollectionVisitor<'_> {
98 pub fn in_module_scope<T>(&mut self, module: &[Symbol], func: impl FnOnce(&mut Self) -> T) -> T {
100 let parent_module = self.module.clone();
101 self.module = module.to_vec();
102 let result = func(self);
103 self.module = parent_module;
104 result
105 }
106}
107
108impl AstVisitor for GlobalItemsCollectionVisitor<'_> {
109 type AdditionalInput = ();
110 type Output = ();
111
112 fn visit_const(&mut self, input: &ConstDeclaration) {
113 let const_path: Vec<Symbol> = self.module.iter().cloned().chain(std::iter::once(input.place.name)).collect();
115 self.state.symbol_table.set_global_type(&Location::new(self.program_name, const_path), input.type_.clone());
116 }
117}
118
119impl ProgramVisitor for GlobalItemsCollectionVisitor<'_> {
120 fn visit_program_scope(&mut self, input: &ProgramScope) {
121 self.program_name = input.program_id.as_symbol();
123
124 input.consts.iter().for_each(|(_, c)| self.visit_const(c));
126 input.composites.iter().for_each(|(_, c)| self.visit_composite(c));
127 input.mappings.iter().for_each(|(_, c)| self.visit_mapping(c));
128 input.storage_variables.iter().for_each(|(_, c)| self.visit_storage_variable(c));
129 input.functions.iter().for_each(|(_, c)| self.visit_function(c));
130 input.interfaces.iter().for_each(|(_, c)| self.visit_interface(c));
131 if let Some(c) = input.constructor.as_ref() {
132 self.visit_constructor(c);
133 }
134 }
135
136 fn visit_module(&mut self, input: &Module) {
137 self.program_name = input.program_name;
138 self.in_module_scope(&input.path.clone(), |slf| {
139 input.composites.iter().for_each(|(_, c)| slf.visit_composite(c));
140 input.functions.iter().for_each(|(_, c)| slf.visit_function(c));
141 input.consts.iter().for_each(|(_, c)| slf.visit_const(c));
142 input.interfaces.iter().for_each(|(_, c)| slf.visit_interface(c));
143 })
144 }
145
146 fn visit_composite(&mut self, input: &Composite) {
147 let full_name = self.module.iter().cloned().chain(std::iter::once(input.name())).collect::<Vec<Symbol>>();
148
149 if input.is_record {
150 if let Err(err) =
153 self.state.symbol_table.insert_record(Location::new(self.program_name, full_name), input.clone())
154 {
155 self.state.handler.emit_err(err);
156 }
157 } else if let Err(err) =
158 self.state.symbol_table.insert_struct(Location::new(self.program_name, full_name.clone()), input.clone())
159 {
160 self.state.handler.emit_err(err);
161 }
162 }
163
164 fn visit_mapping(&mut self, input: &Mapping) {
165 self.state.symbol_table.set_global_type(
167 &Location::new(self.program_name, vec![input.identifier.name]),
168 Type::Mapping(MappingType {
169 key: Box::new(input.key_type.clone()),
170 value: Box::new(input.value_type.clone()),
171 }),
172 );
173 }
174
175 fn visit_storage_variable(&mut self, input: &StorageVariable) {
176 let type_ = match input.type_ {
180 Type::Vector(_) => input.type_.clone(),
181 _ => Type::Optional(OptionalType { inner: Box::new(input.type_.clone()) }),
182 };
183
184 self.state.symbol_table.set_global_type(&Location::new(self.program_name, vec![input.identifier.name]), type_);
185 }
186
187 fn visit_function(&mut self, input: &Function) {
188 let full_name = self.module.iter().cloned().chain(std::iter::once(input.name())).collect::<Vec<Symbol>>();
189 let loc = Location::new(self.program_name, full_name);
190 if let Err(err) = self.state.symbol_table.insert_function(loc, input.clone()) {
191 self.state.handler.emit_err(err);
192 }
193 }
194
195 fn visit_interface(&mut self, input: &Interface) {
196 let full_name = self.module.iter().cloned().chain(std::iter::once(input.name())).collect::<Vec<Symbol>>();
197 if let Err(err) =
198 self.state.symbol_table.insert_interface(Location::new(self.program_name, full_name), input.clone())
199 {
200 self.state.handler.emit_err(err);
201 }
202 }
203
204 fn visit_library(&mut self, input: &Library) {
205 self.program_name = input.name;
206
207 input.interfaces.iter().for_each(|(_, i)| self.visit_interface(i));
208 input.structs.iter().for_each(|(_, s)| self.visit_composite(s));
209 input.consts.iter().for_each(|(_, c)| self.visit_const(c));
210 input.functions.iter().for_each(|(_, f)| self.visit_function(f));
211 input.modules.values().for_each(|m| {
212 self.visit_module(m);
213 });
214 }
215
216 fn visit_aleo_program(&mut self, input: &AleoProgram) {
217 self.program_name = input.stub_id.as_symbol();
218
219 input.functions.iter().for_each(|(_, c)| self.visit_function_stub(c));
220 input.composites.iter().for_each(|(_, c)| self.visit_composite_stub(c));
221 input.mappings.iter().for_each(|(_, c)| self.visit_mapping(c));
222 }
223
224 fn visit_function_stub(&mut self, input: &FunctionStub) {
225 let location = Location::new(self.program_name, vec![input.name()]);
227 if let Err(err) = self.state.symbol_table.insert_function(location.clone(), Function::from(input.clone())) {
229 self.state.handler.emit_err(err);
230 }
231
232 if input.has_final_output() {
237 let name = Symbol::intern(&format!("finalize/{}", input.name()));
239 if let Err(err) = self.state.symbol_table.attach_finalizer(
240 location,
241 Location::new(self.program_name, vec![name]),
242 Vec::new(),
243 Vec::new(),
244 ) {
245 self.state.handler.emit_err(err);
246 }
247 }
248 }
249
250 fn visit_composite_stub(&mut self, input: &Composite) {
251 if input.is_record {
252 if let Err(err) = self
253 .state
254 .symbol_table
255 .insert_record(Location::new(self.program_name, vec![input.name()]), input.clone())
256 {
257 self.state.handler.emit_err(err);
258 }
259 } else if let Err(err) =
260 self.state.symbol_table.insert_struct(Location::new(self.program_name, vec![input.name()]), input.clone())
261 {
262 self.state.handler.emit_err(err);
263 }
264 }
265}