1use super::*;
18
19use leo_ast::{
20 ArrayAccess,
21 ArrayExpression,
22 AssociatedConstantExpression,
23 AssociatedFunctionExpression,
24 BinaryExpression,
25 BinaryOperation,
26 CallExpression,
27 CastExpression,
28 CoreFunction,
29 Expression,
30 IntegerType,
31 Literal,
32 LiteralVariant,
33 Location,
34 LocatorExpression,
35 MemberAccess,
36 NetworkName,
37 Node,
38 Path,
39 ProgramId,
40 RepeatExpression,
41 StructExpression,
42 TernaryExpression,
43 TupleExpression,
44 Type,
45 UnaryExpression,
46 UnaryOperation,
47 Variant,
48};
49use leo_span::sym;
50use snarkvm::{
51 prelude::{CanaryV0, MainnetV0, TestnetV0},
52 synthesizer::program::SerializeVariant,
53};
54
55use anyhow::bail;
56use std::borrow::Borrow;
57
58impl CodeGeneratingVisitor<'_> {
60 pub fn visit_expression(&mut self, input: &Expression) -> (Option<AleoExpr>, Vec<AleoStmt>) {
61 let is_empty_type = self.state.type_table.get(&input.id()).map(|ty| ty.is_empty()).unwrap_or(false);
62 let is_pure = input.is_pure();
63
64 if is_empty_type && is_pure {
65 return (None, vec![]);
67 }
68
69 let some_expr = |(expr, stmts): (AleoExpr, Vec<AleoStmt>)| (Some(expr), stmts);
70
71 match input {
72 Expression::ArrayAccess(expr) => (Some(self.visit_array_access(expr)), vec![]),
73 Expression::AssociatedConstant(expr) => (Some(self.visit_associated_constant(expr)), vec![]),
74 Expression::MemberAccess(expr) => (Some(self.visit_member_access(expr)), vec![]),
75 Expression::Path(expr) => (Some(self.visit_path(expr)), vec![]),
76 Expression::Literal(expr) => (Some(self.visit_value(expr)), vec![]),
77 Expression::Locator(expr) => (Some(self.visit_locator(expr)), vec![]),
78
79 Expression::Array(expr) => some_expr(self.visit_array(expr)),
80 Expression::Binary(expr) => some_expr(self.visit_binary(expr)),
81 Expression::Call(expr) => some_expr(self.visit_call(expr)),
82 Expression::Cast(expr) => some_expr(self.visit_cast(expr)),
83 Expression::Struct(expr) => some_expr(self.visit_struct_init(expr)),
84 Expression::Repeat(expr) => some_expr(self.visit_repeat(expr)),
85 Expression::Ternary(expr) => some_expr(self.visit_ternary(expr)),
86 Expression::Tuple(expr) => some_expr(self.visit_tuple(expr)),
87 Expression::Unary(expr) => some_expr(self.visit_unary(expr)),
88
89 Expression::AssociatedFunction(expr) => self.visit_associated_function(expr),
90
91 Expression::Async(..) => {
92 panic!("`AsyncExpression`s should not be in the AST at this phase of compilation.")
93 }
94 Expression::Err(..) => panic!("`ErrExpression`s should not be in the AST at this phase of compilation."),
95 Expression::TupleAccess(..) => panic!("Tuple accesses should not appear in the AST at this point."),
96 Expression::Unit(..) => panic!("`UnitExpression`s should not be visited during code generation."),
97 }
98 }
99
100 fn visit_path(&mut self, input: &Path) -> AleoExpr {
101 let var_name = input.identifier().name;
104 self.variable_mapping.get(&var_name).or_else(|| self.global_mapping.get(&var_name)).unwrap().clone()
105 }
106
107 fn visit_value(&mut self, input: &Literal) -> AleoExpr {
108 let literal = if let LiteralVariant::Unsuffixed(value) = &input.variant {
110 match self.state.type_table.get(&input.id) {
113 Some(Type::Integer(int_ty)) => Literal {
114 variant: LiteralVariant::Integer(int_ty, value.clone()),
115 id: self.state.node_builder.next_id(),
116 span: input.span,
117 },
118 Some(Type::Field) => Literal {
119 variant: LiteralVariant::Field(value.clone()),
120 id: self.state.node_builder.next_id(),
121 span: input.span,
122 },
123 Some(Type::Group) => Literal {
124 variant: LiteralVariant::Group(value.clone()),
125 id: self.state.node_builder.next_id(),
126 span: input.span,
127 },
128 Some(Type::Scalar) => Literal {
129 variant: LiteralVariant::Scalar(value.clone()),
130 id: self.state.node_builder.next_id(),
131 span: input.span,
132 },
133 _ => panic!(
134 "Unexpected type for unsuffixed integer literal. This should have been caught by the type checker"
135 ),
136 }
137 } else {
138 input.clone()
139 };
140 AleoExpr::Literal(literal)
141 }
142
143 fn visit_locator(&mut self, input: &LocatorExpression) -> AleoExpr {
144 if input.program.name.name == self.program_id.expect("Locators only appear within programs.").name.name {
145 AleoExpr::RawName(input.name.to_string())
147 } else {
148 AleoExpr::RawName(input.to_string())
149 }
150 }
151
152 fn visit_binary(&mut self, input: &BinaryExpression) -> (AleoExpr, Vec<AleoStmt>) {
153 let (left, left_instructions) = self.visit_expression(&input.left);
154 let (right, right_instructions) = self.visit_expression(&input.right);
155 let left = left.expect("Trying to operate on an empty expression");
156 let right = right.expect("Trying to operate on an empty expression");
157
158 let dest_reg = self.next_register();
159
160 let binary_instruction = match input.op {
161 BinaryOperation::Add => AleoStmt::Add(left, right, dest_reg.clone()),
162 BinaryOperation::AddWrapped => AleoStmt::AddWrapped(left, right, dest_reg.clone()),
163 BinaryOperation::And | BinaryOperation::BitwiseAnd => AleoStmt::And(left, right, dest_reg.clone()),
164 BinaryOperation::Div => AleoStmt::Div(left, right, dest_reg.clone()),
165 BinaryOperation::DivWrapped => AleoStmt::DivWrapped(left, right, dest_reg.clone()),
166 BinaryOperation::Eq => AleoStmt::Eq(left, right, dest_reg.clone()),
167 BinaryOperation::Gte => AleoStmt::Gte(left, right, dest_reg.clone()),
168 BinaryOperation::Gt => AleoStmt::Gt(left, right, dest_reg.clone()),
169 BinaryOperation::Lte => AleoStmt::Lte(left, right, dest_reg.clone()),
170 BinaryOperation::Lt => AleoStmt::Lt(left, right, dest_reg.clone()),
171 BinaryOperation::Mod => AleoStmt::Mod(left, right, dest_reg.clone()),
172 BinaryOperation::Mul => AleoStmt::Mul(left, right, dest_reg.clone()),
173 BinaryOperation::MulWrapped => AleoStmt::MulWrapped(left, right, dest_reg.clone()),
174 BinaryOperation::Nand => AleoStmt::Nand(left, right, dest_reg.clone()),
175 BinaryOperation::Neq => AleoStmt::Neq(left, right, dest_reg.clone()),
176 BinaryOperation::Nor => AleoStmt::Nor(left, right, dest_reg.clone()),
177 BinaryOperation::Or | BinaryOperation::BitwiseOr => AleoStmt::Or(left, right, dest_reg.clone()),
178 BinaryOperation::Pow => AleoStmt::Pow(left, right, dest_reg.clone()),
179 BinaryOperation::PowWrapped => AleoStmt::PowWrapped(left, right, dest_reg.clone()),
180 BinaryOperation::Rem => AleoStmt::Rem(left, right, dest_reg.clone()),
181 BinaryOperation::RemWrapped => AleoStmt::RemWrapped(left, right, dest_reg.clone()),
182 BinaryOperation::Shl => AleoStmt::Shl(left, right, dest_reg.clone()),
183 BinaryOperation::ShlWrapped => AleoStmt::ShlWrapped(left, right, dest_reg.clone()),
184 BinaryOperation::Shr => AleoStmt::Shr(left, right, dest_reg.clone()),
185 BinaryOperation::ShrWrapped => AleoStmt::ShrWrapped(left, right, dest_reg.clone()),
186 BinaryOperation::Sub => AleoStmt::Sub(left, right, dest_reg.clone()),
187 BinaryOperation::SubWrapped => AleoStmt::SubWrapped(left, right, dest_reg.clone()),
188 BinaryOperation::Xor => AleoStmt::Xor(left, right, dest_reg.clone()),
189 };
190
191 let mut instructions = left_instructions;
193 instructions.extend(right_instructions);
194 instructions.push(binary_instruction);
195
196 (AleoExpr::Reg(dest_reg), instructions)
197 }
198
199 fn visit_cast(&mut self, input: &CastExpression) -> (AleoExpr, Vec<AleoStmt>) {
200 let (operand, mut instructions) = self.visit_expression(&input.expression);
201 let operand = operand.expect("Trying to cast an empty expression");
202
203 let dest_reg = self.next_register();
205
206 let cast_instruction = AleoStmt::Cast(operand, dest_reg.clone(), Self::visit_type(&input.type_));
207
208 instructions.push(cast_instruction);
210
211 (AleoExpr::Reg(dest_reg), instructions)
212 }
213
214 fn visit_array(&mut self, input: &ArrayExpression) -> (AleoExpr, Vec<AleoStmt>) {
215 let mut instructions = vec![];
216 let operands = input
217 .elements
218 .iter()
219 .map(|expr| self.visit_expression(expr))
220 .filter_map(|(operand, operand_instructions)| {
221 instructions.extend(operand_instructions);
222 operand
223 })
224 .collect();
225
226 let destination_register = self.next_register();
228
229 let Some(array_type @ Type::Array(..)) = self.state.type_table.get(&input.id) else {
231 panic!("All types should be known at this phase of compilation");
232 };
233 let array_type: AleoType = Self::visit_type(&array_type);
234
235 let array_instruction = AleoStmt::Cast(AleoExpr::Tuple(operands), destination_register.clone(), array_type);
236
237 instructions.push(array_instruction);
239
240 (AleoExpr::Reg(destination_register), instructions)
241 }
242
243 fn visit_unary(&mut self, input: &UnaryExpression) -> (AleoExpr, Vec<AleoStmt>) {
244 let (operand, stmts) = self.visit_expression(&input.receiver);
245 let operand = operand.expect("Trying to operate on an empty value");
246
247 let dest_reg = self.next_register();
248
249 let unary_instruction = match input.op {
251 UnaryOperation::Abs => AleoStmt::Abs(operand, dest_reg.clone()),
252 UnaryOperation::AbsWrapped => AleoStmt::AbsW(operand, dest_reg.clone()),
253 UnaryOperation::Double => AleoStmt::Double(operand, dest_reg.clone()),
254 UnaryOperation::Inverse => AleoStmt::Inv(operand, dest_reg.clone()),
255 UnaryOperation::Not => AleoStmt::Not(operand, dest_reg.clone()),
256 UnaryOperation::Negate => AleoStmt::Neg(operand, dest_reg.clone()),
257 UnaryOperation::Square => AleoStmt::Square(operand, dest_reg.clone()),
258 UnaryOperation::SquareRoot => AleoStmt::Sqrt(operand, dest_reg.clone()),
259 UnaryOperation::ToXCoordinate => AleoStmt::Cast(operand, dest_reg.clone(), AleoType::GroupX),
260 UnaryOperation::ToYCoordinate => AleoStmt::Cast(operand, dest_reg.clone(), AleoType::GroupY),
261 };
262
263 let mut instructions = stmts;
265 instructions.push(unary_instruction);
266
267 (AleoExpr::Reg(dest_reg), instructions)
268 }
269
270 fn visit_ternary(&mut self, input: &TernaryExpression) -> (AleoExpr, Vec<AleoStmt>) {
271 let (cond, cond_stmts) = self.visit_expression(&input.condition);
272 let (if_true, if_true_stmts) = self.visit_expression(&input.if_true);
273 let (if_false, if_false_stmts) = self.visit_expression(&input.if_false);
274 let cond = cond.expect("Trying to build a ternary with an empty expression.");
275 let if_true = if_true.expect("Trying to build a ternary with an empty expression.");
276 let if_false = if_false.expect("Trying to build a ternary with an empty expression.");
277
278 let dest_reg = self.next_register();
279 let ternary_instruction = AleoStmt::Ternary(cond, if_true, if_false, dest_reg.clone());
280
281 let mut stmts = cond_stmts;
283 stmts.extend(if_true_stmts);
284 stmts.extend(if_false_stmts);
285 stmts.push(ternary_instruction);
286
287 (AleoExpr::Reg(dest_reg), stmts)
288 }
289
290 fn visit_struct_init(&mut self, input: &StructExpression) -> (AleoExpr, Vec<AleoStmt>) {
291 let struct_type = if let Some(is_record) = self.composite_mapping.get(&input.path.absolute_path()) {
293 if *is_record {
294 let [record_name] = &input.path.absolute_path()[..] else {
296 panic!("Absolute paths to records can only have a single segment at this stage.")
297 };
298 AleoType::Record { name: record_name.to_string(), program: None }
299 } else {
300 AleoType::Ident {
302 name: Self::legalize_path(&input.path.absolute_path())
303 .expect("path format cannot be legalized at this point"),
304 }
305 }
306 } else {
307 panic!("All composite types should be known at this phase of compilation")
308 };
309
310 let mut instructions = vec![];
312
313 let operands: Vec<AleoExpr> = input
315 .members
316 .iter()
317 .filter_map(|member| {
318 if let Some(expr) = member.expression.as_ref() {
319 let (variable_operand, variable_instructions) = self.visit_expression(expr);
321 instructions.extend(variable_instructions);
322
323 variable_operand
324 } else {
325 Some(self.visit_path(&Path::from(member.identifier).into_absolute()))
326 }
327 })
328 .collect();
329
330 let dest_reg = self.next_register();
332
333 let struct_init_instruction = AleoStmt::Cast(AleoExpr::Tuple(operands), dest_reg.clone(), struct_type);
334
335 instructions.push(struct_init_instruction);
336
337 (AleoExpr::Reg(dest_reg), instructions)
338 }
339
340 fn visit_array_access(&mut self, input: &ArrayAccess) -> AleoExpr {
341 let (array_operand, _) = self.visit_expression(&input.array);
342 let array_operand = array_operand.expect("Trying to access an element of an empty expression.");
343
344 assert!(
345 matches!(self.state.type_table.get(&input.index.id()), Some(Type::Integer(_))),
346 "unexpected type for for array index. This should have been caught by the type checker."
347 );
348
349 let index_operand = match &input.index {
350 Expression::Literal(Literal {
351 variant: LiteralVariant::Integer(_, s) | LiteralVariant::Unsuffixed(s),
352 ..
353 }) => AleoExpr::U32(s.parse().unwrap()),
354 _ => panic!("Array indices must be integer literals"),
355 };
356
357 AleoExpr::ArrayAccess(Box::new(array_operand), Box::new(index_operand))
358 }
359
360 fn visit_member_access(&mut self, input: &MemberAccess) -> AleoExpr {
361 if let Expression::Path(path) = input.inner.borrow()
363 && matches!(path.try_absolute_path().as_deref(), Some([sym::SelfLower]))
364 {
365 let program_id = self.program_id.expect("Program ID should be set before traversing the program");
367
368 match input.name.name {
369 sym::address | sym::id => {
371 return AleoExpr::RawName(program_id.to_string());
372 }
373 name @ (sym::checksum | sym::edition | sym::program_owner) => {
375 return AleoExpr::RawName(name.to_string());
376 }
377 _ => {} }
379 }
380
381 let (inner_expr, _) = self.visit_expression(&input.inner);
382 let inner_expr = inner_expr.expect("Trying to access a member of an empty expression.");
383
384 AleoExpr::MemberAccess(Box::new(inner_expr), input.name.to_string())
385 }
386
387 fn visit_repeat(&mut self, input: &RepeatExpression) -> (AleoExpr, Vec<AleoStmt>) {
388 let (operand, mut operand_instructions) = self.visit_expression(&input.expr);
389 let operand = operand.expect("Trying to repeat an empty expression");
390
391 let count = input.count.as_u32().expect("repeat count should be known at this point");
392
393 let expression_operands = std::iter::repeat_n(operand, count as usize).collect::<Vec<_>>();
394
395 let dest_reg = self.next_register();
397
398 let Some(array_type @ Type::Array(..)) = self.state.type_table.get(&input.id) else {
400 panic!("All types should be known at this phase of compilation");
401 };
402 let array_type = Self::visit_type(&array_type);
403
404 let array_instruction = AleoStmt::Cast(AleoExpr::Tuple(expression_operands), dest_reg.clone(), array_type);
405
406 operand_instructions.push(array_instruction);
408
409 (AleoExpr::Reg(dest_reg), operand_instructions)
410 }
411
412 fn visit_associated_constant(&mut self, input: &AssociatedConstantExpression) -> AleoExpr {
414 AleoExpr::RawName(format!("{input}"))
415 }
416
417 fn visit_associated_function(&mut self, input: &AssociatedFunctionExpression) -> (Option<AleoExpr>, Vec<AleoStmt>) {
419 let mut instructions = vec![];
420
421 let arguments = input
423 .arguments
424 .iter()
425 .filter_map(|argument| {
426 let (arg_string, arg_instructions) = self.visit_expression(argument);
427 instructions.extend(arg_instructions);
428 arg_string
429 })
430 .collect::<Vec<_>>();
431
432 let generate_program_core = |program: &str, name: &str| {
434 let program_id = ProgramId::from_str_with_network(&program.replace("\"", ""), self.state.network)
436 .expect("Type checking guarantees that the program name is valid");
437 match program_id.to_string()
439 == self.program_id.expect("The program ID is set before traversing the program").to_string()
440 {
441 true => name.to_string(),
442 false => format!("{program_id}/{name}"),
443 }
444 };
445
446 let (destination, instruction) = match CoreFunction::try_from(input).ok() {
448 Some(CoreFunction::Commit(variant, ref type_)) => {
449 let type_ = AleoType::from(*type_);
450 let dest_reg = self.next_register();
451 let instruction =
452 AleoStmt::Commit(variant, arguments[0].clone(), arguments[1].clone(), dest_reg.clone(), type_);
453 (Some(AleoExpr::Reg(dest_reg)), vec![instruction])
454 }
455 Some(CoreFunction::Hash(variant, ref type_)) => {
456 let dest_reg = self.next_register();
457 let type_ = match self.state.network {
458 NetworkName::TestnetV0 => {
459 AleoType::from(type_.to_snarkvm::<TestnetV0>().expect("TYC guarantees that the type is valid"))
460 }
461 NetworkName::CanaryV0 => {
462 AleoType::from(type_.to_snarkvm::<CanaryV0>().expect("TYC guarantees that the type is valid"))
463 }
464 NetworkName::MainnetV0 => {
465 AleoType::from(type_.to_snarkvm::<MainnetV0>().expect("TYC guarantees that the type is valid"))
466 }
467 };
468 let instruction = AleoStmt::Hash(variant, arguments[0].clone(), dest_reg.clone(), type_);
469 (Some(AleoExpr::Reg(dest_reg)), vec![instruction])
470 }
471 Some(CoreFunction::Get) => {
472 let dest_reg = self.next_register();
473 let instruction = AleoStmt::Get(arguments[0].clone(), arguments[1].clone(), dest_reg.clone());
474 (Some(AleoExpr::Reg(dest_reg)), vec![instruction])
475 }
476 Some(CoreFunction::MappingGetOrUse) => {
477 let dest_reg = self.next_register();
478 let instruction = AleoStmt::GetOrUse(
479 arguments[0].clone(),
480 arguments[1].clone(),
481 arguments[2].clone(),
482 dest_reg.clone(),
483 );
484 (Some(AleoExpr::Reg(dest_reg)), vec![instruction])
485 }
486 Some(CoreFunction::Set) => {
487 let instruction = AleoStmt::Set(arguments[2].clone(), arguments[0].clone(), arguments[1].clone());
488 (None, vec![instruction])
489 }
490 Some(CoreFunction::MappingRemove) => {
491 let instruction = AleoStmt::Remove(arguments[0].clone(), arguments[1].clone());
492 (None, vec![instruction])
493 }
494 Some(CoreFunction::MappingContains) => {
495 let dest_reg = self.next_register();
496 let instruction = AleoStmt::Contains(arguments[0].clone(), arguments[1].clone(), dest_reg.clone());
497 (Some(AleoExpr::Reg(dest_reg)), vec![instruction])
498 }
499 Some(CoreFunction::GroupToXCoordinate) => {
500 let dest_reg = self.next_register();
501 let instruction = AleoStmt::Cast(arguments[0].clone(), dest_reg.clone(), AleoType::GroupX);
502 (Some(AleoExpr::Reg(dest_reg)), vec![instruction])
503 }
504 Some(CoreFunction::GroupToYCoordinate) => {
505 let dest_reg = self.next_register();
506 let instruction = AleoStmt::Cast(arguments[0].clone(), dest_reg.clone(), AleoType::GroupY);
507 (Some(AleoExpr::Reg(dest_reg)), vec![instruction])
508 }
509 Some(CoreFunction::ChaChaRand(type_)) => {
510 let dest_reg = self.next_register();
511 let instruction = AleoStmt::RandChacha(dest_reg.clone(), type_.into());
512 (Some(AleoExpr::Reg(dest_reg)), vec![instruction])
513 }
514 Some(CoreFunction::SignatureVerify) => {
515 let dest_reg = self.next_register();
516 let instruction = AleoStmt::SignVerify(
517 arguments[0].clone(),
518 arguments[1].clone(),
519 arguments[2].clone(),
520 dest_reg.clone(),
521 );
522 (Some(AleoExpr::Reg(dest_reg)), vec![instruction])
523 }
524 Some(CoreFunction::ECDSAVerify(variant)) => {
525 let dest_reg = self.next_register();
526 let instruction = AleoStmt::EcdsaVerify(
527 variant,
528 arguments[0].clone(),
529 arguments[1].clone(),
530 arguments[2].clone(),
531 dest_reg.clone(),
532 );
533 (Some(AleoExpr::Reg(dest_reg)), vec![instruction])
534 }
535 Some(CoreFunction::FutureAwait) => {
536 let instruction = AleoStmt::Await(arguments[0].clone());
537 (None, vec![instruction])
538 }
539 Some(CoreFunction::ProgramChecksum) => {
540 (Some(AleoExpr::RawName(generate_program_core(&arguments[0].to_string(), "checksum"))), vec![])
541 }
542 Some(CoreFunction::ProgramEdition) => {
543 (Some(AleoExpr::RawName(generate_program_core(&arguments[0].to_string(), "edition"))), vec![])
544 }
545 Some(CoreFunction::ProgramOwner) => {
546 (Some(AleoExpr::RawName(generate_program_core(&arguments[0].to_string(), "program_owner"))), vec![])
547 }
548 Some(CoreFunction::CheatCodePrintMapping)
549 | Some(CoreFunction::CheatCodeSetBlockHeight)
550 | Some(CoreFunction::CheatCodeSetBlockTimestamp)
551 | Some(CoreFunction::CheatCodeSetSigner) => {
552 (None, vec![])
553 }
555 Some(CoreFunction::Serialize(variant)) => {
556 let Some(input_type) = self.state.type_table.get(&input.arguments[0].id()) else {
558 panic!("All types should be known at this phase of compilation");
559 };
560 let is_raw = matches!(variant, SerializeVariant::ToBitsRaw);
562 let size_in_bits = match self.state.network {
564 NetworkName::TestnetV0 => {
565 input_type.size_in_bits::<TestnetV0, _>(is_raw, |_| bail!("structs are not supported"))
566 }
567 NetworkName::MainnetV0 => {
568 input_type.size_in_bits::<MainnetV0, _>(is_raw, |_| bail!("structs are not supported"))
569 }
570 NetworkName::CanaryV0 => {
571 input_type.size_in_bits::<CanaryV0, _>(is_raw, |_| bail!("structs are not supported"))
572 }
573 }
574 .expect("TYC guarantees that all types have a valid size in bits");
575
576 let dest_reg = self.next_register();
577 let output_type = AleoType::Array { inner: Box::new(AleoType::Boolean), len: size_in_bits as u32 };
578 let input_type = Self::visit_type(&input_type);
579 let instruction =
580 AleoStmt::Serialize(variant, arguments[0].clone(), input_type, dest_reg.clone(), output_type);
581
582 (Some(AleoExpr::Reg(dest_reg)), vec![instruction])
583 }
584 Some(CoreFunction::Deserialize(variant, output_type)) => {
585 let Some(input_type) = self.state.type_table.get(&input.arguments[0].id()) else {
587 panic!("All types should be known at this phase of compilation");
588 };
589
590 let dest_reg = self.next_register();
591 let input_type = Self::visit_type(&input_type);
592 let output_type = Self::visit_type(&output_type);
593 let instruction =
594 AleoStmt::Deserialize(variant, arguments[0].clone(), input_type, dest_reg.clone(), output_type);
595
596 (Some(AleoExpr::Reg(dest_reg)), vec![instruction])
597 }
598 Some(CoreFunction::OptionalUnwrap) | Some(CoreFunction::OptionalUnwrapOr) => {
599 panic!("`Optional` core functions should have been lowered before code generation")
600 }
601 Some(CoreFunction::VectorPush)
602 | Some(CoreFunction::VectorPop)
603 | Some(CoreFunction::VectorLen)
604 | Some(CoreFunction::VectorClear)
605 | Some(CoreFunction::VectorSwapRemove) => {
606 panic!("`Vector` core functions should have been lowered before code generation")
607 }
608 None => {
609 panic!("All core functions should be known at this phase of compilation")
610 }
611 };
612 instructions.extend(instruction);
614
615 (destination, instructions)
616 }
617
618 fn visit_call(&mut self, input: &CallExpression) -> (AleoExpr, Vec<AleoStmt>) {
619 let caller_program = self.program_id.expect("Calls only appear within programs.").name.name;
620 let callee_program = input.program.unwrap_or(caller_program);
621 let func_symbol = self
622 .state
623 .symbol_table
624 .lookup_function(&Location::new(callee_program, input.function.absolute_path().to_vec()))
625 .expect("Type checking guarantees functions exist");
626
627 let mut instructions = vec![];
628
629 let arguments = input
630 .arguments
631 .iter()
632 .filter_map(|argument| {
633 let (argument, argument_instructions) = self.visit_expression(argument);
634 instructions.extend(argument_instructions);
635 argument
636 })
637 .collect();
638
639 let mut destinations = Vec::new();
641
642 match func_symbol.function.output_type.clone() {
644 t if t.is_empty() => {} Type::Tuple(tuple) => match tuple.length() {
646 0 | 1 => panic!("Parsing guarantees that a tuple type has at least two elements"),
647 len => {
648 for _ in 0..len {
649 destinations.push(self.next_register());
650 }
651 }
652 },
653 _ => {
654 destinations.push(self.next_register());
655 }
656 }
657
658 if func_symbol.function.variant == Variant::AsyncFunction {
660 destinations.push(self.next_register());
661 }
662
663 let call_instruction = if caller_program != callee_program {
665 assert!(
667 self.program.stubs.get(&callee_program).is_some(),
668 "Type checking guarantees that imported and stub programs are present."
669 );
670
671 AleoStmt::Call(format!("{}.aleo/{}", callee_program, input.function), arguments, destinations.clone())
672 } else if func_symbol.function.variant.is_async() {
673 AleoStmt::Async(self.current_function.unwrap().identifier.to_string(), arguments, destinations.clone())
674 } else {
675 AleoStmt::Call(input.function.to_string(), arguments, destinations.clone())
676 };
677
678 instructions.push(call_instruction);
680
681 (AleoExpr::Tuple(destinations.into_iter().map(AleoExpr::Reg).collect()), instructions)
683 }
684
685 fn visit_tuple(&mut self, input: &TupleExpression) -> (AleoExpr, Vec<AleoStmt>) {
686 let mut instructions = vec![];
687
688 let tuple_elements = input
690 .elements
691 .iter()
692 .filter_map(|element| {
693 let (element, element_instructions) = self.visit_expression(element);
694 instructions.extend(element_instructions);
695 element
696 })
697 .collect();
698
699 (AleoExpr::Tuple(tuple_elements), instructions)
701 }
702
703 pub fn clone_register(&mut self, register: &AleoExpr, typ: &Type) -> (AleoExpr, Vec<AleoStmt>) {
704 let new_reg = self.next_register();
705 match typ {
706 Type::Address => {
707 let ins = AleoStmt::Cast(register.clone(), new_reg.clone(), AleoType::Address);
708 ((AleoExpr::Reg(new_reg)), vec![ins])
709 }
710 Type::Boolean => {
711 let ins = AleoStmt::Cast(register.clone(), new_reg.clone(), AleoType::Boolean);
712 ((AleoExpr::Reg(new_reg)), vec![ins])
713 }
714 Type::Field => {
715 let ins = AleoStmt::Cast(register.clone(), new_reg.clone(), AleoType::Field);
716 ((AleoExpr::Reg(new_reg)), vec![ins])
717 }
718 Type::Group => {
719 let ins = AleoStmt::Cast(register.clone(), new_reg.clone(), AleoType::Group);
720 ((AleoExpr::Reg(new_reg)), vec![ins])
721 }
722 Type::Scalar => {
723 let ins = AleoStmt::Cast(register.clone(), new_reg.clone(), AleoType::Scalar);
724 ((AleoExpr::Reg(new_reg)), vec![ins])
725 }
726 Type::Signature => {
727 let ins = AleoStmt::Cast(register.clone(), new_reg.clone(), AleoType::Signature);
728 ((AleoExpr::Reg(new_reg)), vec![ins])
729 }
730 Type::Integer(int) => {
731 let ins = AleoStmt::Cast(register.clone(), new_reg.clone(), match int {
732 IntegerType::U8 => AleoType::U8,
733 IntegerType::U16 => AleoType::U16,
734 IntegerType::U32 => AleoType::U32,
735 IntegerType::U64 => AleoType::U64,
736 IntegerType::U128 => AleoType::U128,
737 IntegerType::I8 => AleoType::I8,
738 IntegerType::I16 => AleoType::I16,
739 IntegerType::I32 => AleoType::I32,
740 IntegerType::I64 => AleoType::I64,
741 IntegerType::I128 => AleoType::I128,
742 });
743 ((AleoExpr::Reg(new_reg)), vec![ins])
744 }
745
746 Type::Array(array_type) => {
747 let elems = (0..array_type.length.as_u32().expect("length should be known at this point"))
749 .map(|i| AleoExpr::ArrayAccess(Box::new(register.clone()), Box::new(AleoExpr::U32(i))))
750 .collect::<Vec<_>>();
751
752 let ins = AleoStmt::Cast(AleoExpr::Tuple(elems), new_reg.clone(), Self::visit_type(typ));
753 ((AleoExpr::Reg(new_reg)), vec![ins])
754 }
755
756 Type::Composite(comp_ty) => {
757 let program = comp_ty.program.unwrap_or(self.program_id.unwrap().name.name);
759 let location = Location::new(program, comp_ty.path.absolute_path().to_vec());
760 let comp = self
761 .state
762 .symbol_table
763 .lookup_record(&location)
764 .or_else(|| self.state.symbol_table.lookup_struct(&comp_ty.path.absolute_path()))
765 .unwrap();
766 let elems = comp
767 .members
768 .iter()
769 .map(|member| {
770 AleoExpr::MemberAccess(Box::new(register.clone()), member.identifier.name.to_string())
771 })
772 .collect();
773 let instruction = AleoStmt::Cast(
774 AleoExpr::Tuple(elems),
775 new_reg.clone(),
776 self.visit_type_with_visibility(typ, None).0,
777 );
778 ((AleoExpr::Reg(new_reg)), vec![instruction])
779 }
780
781 Type::Optional(_) => panic!("All optional types should have been lowered by now."),
782
783 Type::Vector(_) => panic!("All vector types should have been lowered by now."),
784
785 Type::Mapping(..)
786 | Type::Future(..)
787 | Type::Tuple(..)
788 | Type::Identifier(..)
789 | Type::String
790 | Type::Unit
791 | Type::Numeric
792 | Type::Err => panic!("Objects of type {typ} cannot be cloned."),
793 }
794 }
795}