leo_passes/code_generation/
program.rs1use super::CodeGeneratingVisitor;
18
19use leo_ast::{Composite, Function, Location, Mapping, Member, Mode, Program, ProgramScope, Type, Variant};
20use leo_span::{Symbol, sym};
21
22use indexmap::IndexMap;
23use std::fmt::Write as _;
24
25const EXPECT_STR: &str = "Failed to write code";
26
27impl<'a> CodeGeneratingVisitor<'a> {
28 pub fn visit_program(&mut self, input: &'a Program) -> String {
29 let mut program_string = String::new();
31
32 input.stubs.iter().for_each(|(program_name, _)| {
34 writeln!(program_string, "import {}.aleo;", program_name).expect(EXPECT_STR);
35 });
36
37 let program_scope: &ProgramScope = input.program_scopes.values().next().unwrap();
40
41 self.program_id = Some(program_scope.program_id);
42
43 writeln!(program_string, "program {};", program_scope.program_id).expect(EXPECT_STR);
45
46 let order = self.state.struct_graph.post_order().unwrap();
49
50 let this_program = self.program_id.unwrap().name.name;
51
52 let lookup = |name: Symbol| {
53 self.state
54 .symbol_table
55 .lookup_struct(name)
56 .or_else(|| self.state.symbol_table.lookup_record(Location::new(this_program, name)))
57 };
58
59 for name in order.into_iter() {
61 if let Some(struct_) = lookup(name) {
62 program_string.push_str(&self.visit_struct_or_record(struct_));
63 }
64 }
65
66 for (_symbol, mapping) in program_scope.mappings.iter() {
68 program_string.push_str(&self.visit_mapping(mapping));
69 }
70
71 for (_symbol, function) in program_scope.functions.iter() {
75 if function.variant != Variant::AsyncFunction {
76 let mut function_string = self.visit_function(function);
77
78 if function.variant == Variant::AsyncTransition {
80 self.finalize_caller = Some(function.identifier.name);
82 let finalize = &self
84 .state
85 .symbol_table
86 .lookup_function(Location::new(self.program_id.unwrap().name.name, function.identifier.name))
87 .unwrap()
88 .clone()
89 .finalizer
90 .unwrap();
91 function_string.push_str(&self.visit_function_with(
93 &program_scope.functions.iter().find(|(name, _f)| name == &finalize.location.name).unwrap().1,
94 &finalize.future_inputs,
95 ));
96 }
97
98 program_string.push_str(&function_string);
99 }
100 }
101
102 program_string
103 }
104
105 fn visit_struct_or_record(&mut self, struct_: &'a Composite) -> String {
106 if struct_.is_record { self.visit_record(struct_) } else { self.visit_struct(struct_) }
107 }
108
109 fn visit_struct(&mut self, struct_: &'a Composite) -> String {
110 self.composite_mapping.insert(struct_.identifier.name, (false, String::from("private"))); let mut output_string = format!("\nstruct {}:\n", struct_.identifier); for var in struct_.members.iter() {
117 writeln!(output_string, " {} as {};", var.identifier, Self::visit_type(&var.type_),).expect(EXPECT_STR);
118 }
119
120 output_string
121 }
122
123 fn visit_record(&mut self, record: &'a Composite) -> String {
124 self.composite_mapping.insert(record.identifier.name, (true, "record".into()));
126
127 let mut output_string = format!("\nrecord {}:\n", record.identifier); let mut members = Vec::with_capacity(record.members.len());
130 let mut member_map: IndexMap<Symbol, Member> =
131 record.members.clone().into_iter().map(|member| (member.identifier.name, member)).collect();
132
133 members.push(member_map.shift_remove(&sym::owner).unwrap());
136
137 members.extend(member_map.into_iter().map(|(_, member)| member));
139
140 for var in members.iter() {
142 let mode = match var.mode {
143 Mode::Constant => "constant",
144 Mode::Public => "public",
145 Mode::None | Mode::Private => "private",
146 };
147 writeln!(
148 output_string,
149 " {} as {}.{mode};", var.identifier,
151 Self::visit_type(&var.type_)
152 )
153 .expect(EXPECT_STR);
154 }
155
156 output_string
157 }
158
159 fn visit_function_with(&mut self, function: &'a Function, futures: &[Location]) -> String {
160 self.next_register = 0;
162 self.variable_mapping = IndexMap::new();
163 self.variant = Some(function.variant);
164 self.variable_mapping.insert(sym::SelfLower, "self".to_string());
166 self.variable_mapping.insert(sym::block, "block".to_string());
167 self.variable_mapping.insert(sym::network, "network".to_string());
168 self.current_function = Some(function);
169
170 let mut function_string = match function.variant {
175 Variant::Transition | Variant::AsyncTransition => format!("\nfunction {}:\n", function.identifier),
176 Variant::Function => format!("\nclosure {}:\n", function.identifier),
177 Variant::AsyncFunction => format!("\nfinalize {}:\n", self.finalize_caller.unwrap()),
178 Variant::Inline => return String::new(),
179 Variant::Script => panic!("script should not appear in native code"),
180 };
181
182 let mut futures = futures.iter();
183
184 self.internal_record_inputs.clear();
185
186 for input in function.input.iter() {
188 let register_string = self.next_register();
189
190 if let Type::Composite(comp) = &input.type_ {
192 let program = comp.program.unwrap_or(self.program_id.unwrap().name.name);
193 if let Some(record) = self.state.symbol_table.lookup_record(Location::new(program, comp.id.name)) {
194 if record.external.is_none() || record.external == self.program_id.map(|id| id.name.name) {
195 self.internal_record_inputs.insert(register_string.clone());
196 }
197 }
198 }
199
200 let type_string = {
201 self.variable_mapping.insert(input.identifier.name, register_string.clone());
202 let visibility = match (self.variant.unwrap(), input.mode) {
204 (Variant::AsyncTransition, Mode::None) | (Variant::Transition, Mode::None) => Mode::Private,
205 (Variant::AsyncFunction, Mode::None) => Mode::Public,
206 _ => input.mode,
207 };
208 if matches!(input.type_, Type::Future(_)) {
210 let location = *futures
211 .next()
212 .expect("Type checking guarantees we have future locations for each future input");
213 format!("{}.aleo/{}.future", location.program, location.name)
214 } else {
215 self.visit_type_with_visibility(&input.type_, visibility)
216 }
217 };
218
219 writeln!(function_string, " input {register_string} as {type_string};",).expect(EXPECT_STR);
220 }
221
222 let block_string = self.visit_block(&function.block);
224 if matches!(self.variant.unwrap(), Variant::Function | Variant::AsyncFunction)
225 && block_string.lines().all(|line| line.starts_with(" output "))
226 {
227 function_string.push_str(" assert.eq true true;\n");
230 }
231
232 function_string.push_str(&block_string);
233
234 function_string
235 }
236
237 fn visit_function(&mut self, function: &'a Function) -> String {
238 self.visit_function_with(function, &[])
239 }
240
241 fn visit_mapping(&mut self, mapping: &'a Mapping) -> String {
242 let mut mapping_string = format!("\nmapping {}:\n", mapping.identifier);
244
245 let create_type = |type_: &Type| {
247 match type_ {
248 Type::Mapping(_) | Type::Tuple(_) => panic!("Mappings cannot contain mappings or tuples."),
249 Type::Identifier(identifier) => {
250 let (is_record, _) = self.composite_mapping.get(&identifier.name).unwrap();
253 assert!(!is_record, "Type checking guarantees that mappings cannot contain records.");
254 self.visit_type_with_visibility(type_, Mode::Public)
255 }
256 type_ => self.visit_type_with_visibility(type_, Mode::Public),
257 }
258 };
259
260 writeln!(mapping_string, " key as {};", create_type(&mapping.key_type)).expect(EXPECT_STR);
262
263 writeln!(mapping_string, " value as {};", create_type(&mapping.value_type)).expect(EXPECT_STR);
265
266 self.global_mapping.insert(mapping.identifier.name, mapping.identifier.to_string());
268
269 mapping_string
270 }
271}