1use super::*;
18
19use leo_ast::{
20 ArrayAccess,
21 ArrayExpression,
22 AssociatedConstantExpression,
23 AssociatedFunctionExpression,
24 AsyncExpression,
25 BinaryExpression,
26 BinaryOperation,
27 CallExpression,
28 CastExpression,
29 CoreFunction,
30 ErrExpression,
31 Expression,
32 Literal,
33 LiteralVariant,
34 Location,
35 LocatorExpression,
36 MemberAccess,
37 NetworkName,
38 Node,
39 Path,
40 ProgramId,
41 RepeatExpression,
42 StructExpression,
43 TernaryExpression,
44 TupleExpression,
45 Type,
46 UnaryExpression,
47 UnaryOperation,
48 UnitExpression,
49 Variant,
50};
51use leo_span::sym;
52use snarkvm::{
53 prelude::{CanaryV0, MainnetV0, TestnetV0},
54 synthesizer::program::{CommitVariant, DeserializeVariant, SerializeVariant},
55};
56
57use anyhow::bail;
58use std::{borrow::Borrow, fmt::Write as _};
59
60impl CodeGeneratingVisitor<'_> {
62 pub fn visit_expression(&mut self, input: &Expression) -> (String, String) {
63 match input {
64 Expression::Array(expr) => self.visit_array(expr),
65 Expression::ArrayAccess(expr) => self.visit_array_access(expr),
66 Expression::AssociatedConstant(expr) => self.visit_associated_constant(expr),
67 Expression::AssociatedFunction(expr) => self.visit_associated_function(expr),
68 Expression::Async(expr) => self.visit_async(expr),
69 Expression::Binary(expr) => self.visit_binary(expr),
70 Expression::Call(expr) => self.visit_call(expr),
71 Expression::Cast(expr) => self.visit_cast(expr),
72 Expression::Struct(expr) => self.visit_struct_init(expr),
73 Expression::Err(expr) => self.visit_err(expr),
74 Expression::Path(expr) => self.visit_path(expr),
75 Expression::Literal(expr) => self.visit_value(expr),
76 Expression::Locator(expr) => self.visit_locator(expr),
77 Expression::MemberAccess(expr) => self.visit_member_access(expr),
78 Expression::Repeat(expr) => self.visit_repeat(expr),
79 Expression::Ternary(expr) => self.visit_ternary(expr),
80 Expression::Tuple(expr) => self.visit_tuple(expr),
81 Expression::TupleAccess(_) => panic!("Tuple accesses should not appear in the AST at this point."),
82 Expression::Unary(expr) => self.visit_unary(expr),
83 Expression::Unit(expr) => self.visit_unit(expr),
84 }
85 }
86
87 fn visit_path(&mut self, input: &Path) -> (String, String) {
88 let var_name = input.identifier().name;
91 (
92 self.variable_mapping.get(&var_name).or_else(|| self.global_mapping.get(&var_name)).unwrap().clone(),
93 String::new(),
94 )
95 }
96
97 fn visit_err(&mut self, _input: &ErrExpression) -> (String, String) {
98 panic!("`ErrExpression`s should not be in the AST at this phase of compilation.")
99 }
100
101 fn visit_value(&mut self, input: &Literal) -> (String, String) {
102 let literal = if let LiteralVariant::Unsuffixed(value) = &input.variant {
104 match self.state.type_table.get(&input.id) {
107 Some(Type::Integer(int_ty)) => Literal {
108 variant: LiteralVariant::Integer(int_ty, value.clone()),
109 id: self.state.node_builder.next_id(),
110 span: input.span,
111 },
112 Some(Type::Field) => Literal {
113 variant: LiteralVariant::Field(value.clone()),
114 id: self.state.node_builder.next_id(),
115 span: input.span,
116 },
117 Some(Type::Group) => Literal {
118 variant: LiteralVariant::Group(value.clone()),
119 id: self.state.node_builder.next_id(),
120 span: input.span,
121 },
122 Some(Type::Scalar) => Literal {
123 variant: LiteralVariant::Scalar(value.clone()),
124 id: self.state.node_builder.next_id(),
125 span: input.span,
126 },
127 _ => panic!(
128 "Unexpected type for unsuffixed integer literal. This should have been caught by the type checker"
129 ),
130 }
131 } else {
132 input.clone()
133 };
134 (format!("{}", literal.display_decimal()), String::new())
135 }
136
137 fn visit_locator(&mut self, input: &LocatorExpression) -> (String, String) {
138 if input.program.name.name == self.program_id.expect("Locators only appear within programs.").name.name {
139 (format!("{}", input.name), String::new())
141 } else {
142 (format!("{input}"), String::new())
143 }
144 }
145
146 fn visit_binary(&mut self, input: &BinaryExpression) -> (String, String) {
147 let (left_operand, left_instructions) = self.visit_expression(&input.left);
148 let (right_operand, right_instructions) = self.visit_expression(&input.right);
149
150 let opcode = match input.op {
151 BinaryOperation::Add => String::from("add"),
152 BinaryOperation::AddWrapped => String::from("add.w"),
153 BinaryOperation::And => String::from("and"),
154 BinaryOperation::BitwiseAnd => String::from("and"),
155 BinaryOperation::Div => String::from("div"),
156 BinaryOperation::DivWrapped => String::from("div.w"),
157 BinaryOperation::Eq => String::from("is.eq"),
158 BinaryOperation::Gte => String::from("gte"),
159 BinaryOperation::Gt => String::from("gt"),
160 BinaryOperation::Lte => String::from("lte"),
161 BinaryOperation::Lt => String::from("lt"),
162 BinaryOperation::Mod => String::from("mod"),
163 BinaryOperation::Mul => String::from("mul"),
164 BinaryOperation::MulWrapped => String::from("mul.w"),
165 BinaryOperation::Nand => String::from("nand"),
166 BinaryOperation::Neq => String::from("is.neq"),
167 BinaryOperation::Nor => String::from("nor"),
168 BinaryOperation::Or => String::from("or"),
169 BinaryOperation::BitwiseOr => String::from("or"),
170 BinaryOperation::Pow => String::from("pow"),
171 BinaryOperation::PowWrapped => String::from("pow.w"),
172 BinaryOperation::Rem => String::from("rem"),
173 BinaryOperation::RemWrapped => String::from("rem.w"),
174 BinaryOperation::Shl => String::from("shl"),
175 BinaryOperation::ShlWrapped => String::from("shl.w"),
176 BinaryOperation::Shr => String::from("shr"),
177 BinaryOperation::ShrWrapped => String::from("shr.w"),
178 BinaryOperation::Sub => String::from("sub"),
179 BinaryOperation::SubWrapped => String::from("sub.w"),
180 BinaryOperation::Xor => String::from("xor"),
181 };
182
183 let destination_register = self.next_register();
184 let binary_instruction = format!(" {opcode} {left_operand} {right_operand} into {destination_register};\n",);
185
186 let mut instructions = left_instructions;
188 instructions.push_str(&right_instructions);
189 instructions.push_str(&binary_instruction);
190
191 (destination_register, instructions)
192 }
193
194 fn visit_cast(&mut self, input: &CastExpression) -> (String, String) {
195 let (expression_operand, mut instructions) = self.visit_expression(&input.expression);
196
197 let destination_register = self.next_register();
199
200 let cast_instruction = format!(
201 " cast {expression_operand} into {destination_register} as {};\n",
202 Self::visit_type(&input.type_)
203 );
204
205 instructions.push_str(&cast_instruction);
207
208 (destination_register, instructions)
209 }
210
211 fn visit_array(&mut self, input: &ArrayExpression) -> (String, String) {
212 let mut expression_operands = String::new();
213 let mut instructions = String::new();
214 for (operand, operand_instructions) in input.elements.iter().map(|expr| self.visit_expression(expr)) {
215 let space = if expression_operands.is_empty() { "" } else { " " };
216 write!(&mut expression_operands, "{space}{operand}").unwrap();
217 instructions.push_str(&operand_instructions);
218 }
219
220 let destination_register = self.next_register();
222
223 let Some(array_type @ Type::Array(..)) = self.state.type_table.get(&input.id) else {
225 panic!("All types should be known at this phase of compilation");
226 };
227 let array_type: String = Self::visit_type(&array_type);
228
229 let array_instruction =
230 format!(" cast {expression_operands} into {destination_register} as {array_type};\n");
231
232 instructions.push_str(&array_instruction);
234
235 (destination_register, instructions)
236 }
237
238 fn visit_unary(&mut self, input: &UnaryExpression) -> (String, String) {
239 let (expression_operand, expression_instructions) = self.visit_expression(&input.receiver);
240
241 let (opcode, suffix) = match input.op {
243 UnaryOperation::Abs => ("abs", ""),
244 UnaryOperation::AbsWrapped => ("abs.w", ""),
245 UnaryOperation::Double => ("double", ""),
246 UnaryOperation::Inverse => ("inv", ""),
247 UnaryOperation::Not => ("not", ""),
248 UnaryOperation::Negate => ("neg", ""),
249 UnaryOperation::Square => ("square", ""),
250 UnaryOperation::SquareRoot => ("sqrt", ""),
251 UnaryOperation::ToXCoordinate => ("cast", " as group.x"),
252 UnaryOperation::ToYCoordinate => ("cast", " as group.y"),
253 };
254
255 let destination_register = self.next_register();
256 let unary_instruction = format!(" {opcode} {expression_operand} into {destination_register}{suffix};\n");
257
258 let mut instructions = expression_instructions;
260 instructions.push_str(&unary_instruction);
261
262 (destination_register, instructions)
263 }
264
265 fn visit_ternary(&mut self, input: &TernaryExpression) -> (String, String) {
266 let (condition_operand, condition_instructions) = self.visit_expression(&input.condition);
267 let (if_true_operand, if_true_instructions) = self.visit_expression(&input.if_true);
268 let (if_false_operand, if_false_instructions) = self.visit_expression(&input.if_false);
269
270 let destination_register = self.next_register();
271 let ternary_instruction = format!(
272 " ternary {condition_operand} {if_true_operand} {if_false_operand} into {destination_register};\n",
273 );
274
275 let mut instructions = condition_instructions;
277 instructions.push_str(&if_true_instructions);
278 instructions.push_str(&if_false_instructions);
279 instructions.push_str(&ternary_instruction);
280
281 (destination_register, instructions)
282 }
283
284 fn visit_struct_init(&mut self, input: &StructExpression) -> (String, String) {
285 let name = if let Some((is_record, type_)) = self.composite_mapping.get(&input.path.absolute_path()) {
287 if *is_record {
288 let [record_name] = &input.path.absolute_path()[..] else {
290 panic!("Absolute paths to records can only have a single segment at this stage.")
291 };
292 format!("{record_name}.{type_}")
293 } else {
294 Self::legalize_path(&input.path.absolute_path()).expect("path format cannot be legalized at this point")
296 }
297 } else {
298 panic!("All composite types should be known at this phase of compilation")
299 };
300
301 let mut instructions = String::new();
303 let mut struct_init_instruction = String::from(" cast ");
304
305 for member in input.members.iter() {
307 let operand = if let Some(expr) = member.expression.as_ref() {
308 let (variable_operand, variable_instructions) = self.visit_expression(expr);
310 instructions.push_str(&variable_instructions);
311
312 variable_operand
313 } else {
314 let (ident_operand, ident_instructions) =
316 self.visit_path(&Path::from(member.identifier).into_absolute());
317 instructions.push_str(&ident_instructions);
318
319 ident_operand
320 };
321
322 write!(struct_init_instruction, "{operand} ").expect("failed to write to string");
324 }
325
326 let destination_register = self.next_register();
328 writeln!(struct_init_instruction, "into {destination_register} as {name};",)
329 .expect("failed to write to string");
330
331 instructions.push_str(&struct_init_instruction);
332
333 (destination_register, instructions)
334 }
335
336 fn visit_array_access(&mut self, input: &ArrayAccess) -> (String, String) {
337 let (array_operand, _) = self.visit_expression(&input.array);
338
339 assert!(
340 matches!(self.state.type_table.get(&input.index.id()), Some(Type::Integer(_))),
341 "unexpected type for for array index. This should have been caught by the type checker."
342 );
343
344 let index_operand = match &input.index {
345 Expression::Literal(Literal {
346 variant: LiteralVariant::Integer(_, s) | LiteralVariant::Unsuffixed(s),
347 ..
348 }) => format!("{s}u32"),
349 _ => panic!("Array indices must be integer literals"),
350 };
351
352 (format!("{array_operand}[{index_operand}]"), String::new())
353 }
354
355 fn visit_member_access(&mut self, input: &MemberAccess) -> (String, String) {
356 if let Expression::Path(path) = input.inner.borrow()
358 && matches!(path.try_absolute_path().as_deref(), Some([sym::SelfLower]))
359 {
360 let program_id = self.program_id.expect("Program ID should be set before traversing the program");
362
363 match input.name.name {
364 sym::address | sym::id => {
366 return (program_id.to_string(), String::new());
367 }
368 name @ (sym::checksum | sym::edition | sym::program_owner) => {
370 return (name.to_string(), String::new());
371 }
372 _ => {} }
374 }
375
376 let (inner_expr, _) = self.visit_expression(&input.inner);
377 let member_access = format!("{}.{}", inner_expr, input.name);
378
379 (member_access, String::new())
380 }
381
382 fn visit_repeat(&mut self, input: &RepeatExpression) -> (String, String) {
383 let (operand, mut operand_instructions) = self.visit_expression(&input.expr);
384 let count = input.count.as_u32().expect("repeat count should be known at this point");
385
386 let expression_operands = std::iter::repeat_n(operand, count as usize).collect::<Vec<_>>().join(" ");
387
388 let destination_register = self.next_register();
390
391 let Some(array_type @ Type::Array(..)) = self.state.type_table.get(&input.id) else {
393 panic!("All types should be known at this phase of compilation");
394 };
395 let array_type: String = Self::visit_type(&array_type);
396
397 let array_instruction =
398 format!(" cast {expression_operands} into {destination_register} as {array_type};\n");
399
400 operand_instructions.push_str(&array_instruction);
402
403 (destination_register, operand_instructions)
404 }
405
406 fn visit_associated_constant(&mut self, input: &AssociatedConstantExpression) -> (String, String) {
408 (format!("{input}"), String::new())
409 }
410
411 fn visit_associated_function(&mut self, input: &AssociatedFunctionExpression) -> (String, String) {
413 let mut instructions = String::new();
414
415 let arguments = input
417 .arguments
418 .iter()
419 .map(|argument| {
420 let (arg_string, arg_instructions) = self.visit_expression(argument);
421 instructions.push_str(&arg_instructions);
422 arg_string
423 })
424 .collect::<Vec<_>>();
425
426 let generate_program_core = |program: &str, name: &str| {
428 let program_id = ProgramId::from_str_with_network(&program.replace("\"", ""), self.state.network)
430 .expect("Type checking guarantees that the program name is valid");
431 let operand = match program_id.to_string()
433 == self.program_id.expect("The program ID is set before traversing the program").to_string()
434 {
435 true => name.to_string(),
436 false => format!("{program_id}/{name}"),
437 };
438 (operand, String::new())
439 };
440
441 let (destination, instruction) = match CoreFunction::try_from(input).ok() {
443 Some(CoreFunction::Commit(variant, ref type_)) => {
444 let mut instruction = format!(" {}", CommitVariant::opcode(variant as u8));
445 let destination_register = self.next_register();
446 writeln!(instruction, " {} {} into {destination_register} as {type_};", arguments[0], arguments[1])
448 .expect("failed to write to string");
449 (destination_register, instruction)
450 }
451 Some(CoreFunction::Hash(variant, ref type_)) => {
452 let mut instruction = format!(" {}", variant.opcode());
453 let destination_register = self.next_register();
454 let type_ = match self.state.network {
455 NetworkName::TestnetV0 => {
456 type_.to_snarkvm::<TestnetV0>().expect("TYC guarantees that the type is valid").to_string()
457 }
458 NetworkName::CanaryV0 => {
459 type_.to_snarkvm::<CanaryV0>().expect("TYC guarantees that the type is valid").to_string()
460 }
461 NetworkName::MainnetV0 => {
462 type_.to_snarkvm::<MainnetV0>().expect("TYC guarantees that the type is valid").to_string()
463 }
464 };
465 writeln!(instruction, " {} into {destination_register} as {type_};", arguments[0])
467 .expect("failed to write to string");
468 (destination_register, instruction)
469 }
470 Some(CoreFunction::Get) => {
471 let mut instruction = " get".to_string();
472 let destination_register = self.next_register();
473 writeln!(instruction, " {}[{}] into {destination_register};", arguments[0], arguments[1])
475 .expect("failed to write to string");
476 (destination_register, instruction)
477 }
478 Some(CoreFunction::MappingGetOrUse) => {
479 let mut instruction = " get.or_use".to_string();
480 let destination_register = self.next_register();
481 writeln!(
483 instruction,
484 " {}[{}] {} into {destination_register};",
485 arguments[0], arguments[1], arguments[2]
486 )
487 .expect("failed to write to string");
488 (destination_register, instruction)
489 }
490 Some(CoreFunction::Set) => {
491 let mut instruction = " set".to_string();
492 writeln!(instruction, " {} into {}[{}];", arguments[2], arguments[0], arguments[1])
494 .expect("failed to write to string");
495 (String::new(), instruction)
496 }
497 Some(CoreFunction::MappingRemove) => {
498 let mut instruction = " remove".to_string();
499 writeln!(instruction, " {}[{}];", arguments[0], arguments[1]).expect("failed to write to string");
501 (String::new(), instruction)
502 }
503 Some(CoreFunction::MappingContains) => {
504 let mut instruction = " contains".to_string();
505 let destination_register = self.next_register();
506 writeln!(instruction, " {}[{}] into {destination_register};", arguments[0], arguments[1])
508 .expect("failed to write to string");
509 (destination_register, instruction)
510 }
511 Some(CoreFunction::GroupToXCoordinate) => {
512 let mut instruction = " cast".to_string();
513 let destination_register = self.next_register();
514 writeln!(instruction, " {} into {destination_register} as group.x;", arguments[0],)
516 .expect("failed to write to string");
517 (destination_register, instruction)
518 }
519 Some(CoreFunction::GroupToYCoordinate) => {
520 let mut instruction = " cast".to_string();
521 let destination_register = self.next_register();
522 writeln!(instruction, " {} into {destination_register} as group.y;", arguments[0],)
524 .expect("failed to write to string");
525 (destination_register, instruction)
526 }
527 Some(CoreFunction::ChaChaRand(type_)) => {
528 let destination_register = self.next_register();
530 let instruction = format!(" rand.chacha into {destination_register} as {type_};\n");
532
533 (destination_register, instruction)
534 }
535 Some(CoreFunction::SignatureVerify) => {
536 let mut instruction = " sign.verify".to_string();
537 let destination_register = self.next_register();
538 writeln!(
540 instruction,
541 " {} {} {} into {destination_register};",
542 arguments[0], arguments[1], arguments[2]
543 )
544 .expect("failed to write to string");
545 (destination_register, instruction)
546 }
547 Some(CoreFunction::ECDSAVerify(variant)) => {
548 let mut instruction = format!(" {}", variant.opcode());
549 let destination_register = self.next_register();
550 writeln!(
552 instruction,
553 " {} {} {} into {destination_register};",
554 arguments[0], arguments[1], arguments[2]
555 )
556 .expect("failed to write to string");
557 (destination_register, instruction)
558 }
559 Some(CoreFunction::FutureAwait) => {
560 let mut instruction = " await".to_string();
561 writeln!(instruction, " {};", arguments[0]).expect("failed to write to string");
562 (String::new(), instruction)
563 }
564 Some(CoreFunction::ProgramChecksum) => generate_program_core(&arguments[0], "checksum"),
565 Some(CoreFunction::ProgramEdition) => generate_program_core(&arguments[0], "edition"),
566 Some(CoreFunction::ProgramOwner) => generate_program_core(&arguments[0], "program_owner"),
567 Some(CoreFunction::CheatCodePrintMapping)
568 | Some(CoreFunction::CheatCodeSetBlockHeight)
569 | Some(CoreFunction::CheatCodeSetSigner) => {
570 (String::new(), String::new())
571 }
573 Some(CoreFunction::Serialize(variant)) => {
574 let Some(input_type) = self.state.type_table.get(&input.arguments[0].id()) else {
576 panic!("All types should be known at this phase of compilation");
577 };
578 let (is_raw, variant) = match variant {
580 SerializeVariant::ToBits => (false, "bits"),
581 SerializeVariant::ToBitsRaw => (true, "bits.raw"),
582 };
583 let size_in_bits = match self.state.network {
585 NetworkName::TestnetV0 => {
586 input_type.size_in_bits::<TestnetV0, _>(is_raw, |_| bail!("structs are not supported"))
587 }
588 NetworkName::MainnetV0 => {
589 input_type.size_in_bits::<MainnetV0, _>(is_raw, |_| bail!("structs are not supported"))
590 }
591 NetworkName::CanaryV0 => {
592 input_type.size_in_bits::<CanaryV0, _>(is_raw, |_| bail!("structs are not supported"))
593 }
594 }
595 .expect("TYC guarantees that all types have a valid size in bits");
596
597 let output_array_type = format!("[boolean; {size_in_bits}u32]");
599 let destination_register = self.next_register();
601 let instruction = format!(
603 " serialize.{variant} {} ({}) into {destination_register} ({output_array_type});\n",
604 arguments[0],
605 Self::visit_type(&input_type)
606 );
607
608 (destination_register, instruction)
609 }
610 Some(CoreFunction::Deserialize(variant, output_type)) => {
611 let variant = match variant {
613 DeserializeVariant::FromBits => "bits",
614 DeserializeVariant::FromBitsRaw => "bits.raw",
615 };
616 let Some(input_type) = self.state.type_table.get(&input.arguments[0].id()) else {
618 panic!("All types should be known at this phase of compilation");
619 };
620 let destination_register = self.next_register();
622 let instruction = format!(
624 " deserialize.{variant} {} ({}) into {destination_register} ({});\n",
625 arguments[0],
626 Self::visit_type(&input_type),
627 Self::visit_type(&output_type)
628 );
629
630 (destination_register, instruction)
631 }
632 Some(CoreFunction::OptionalUnwrap) | Some(CoreFunction::OptionalUnwrapOr) => {
633 panic!("`Optional` core functions should have been lowered before code generation")
634 }
635 Some(CoreFunction::VectorPush)
636 | Some(CoreFunction::VectorPop)
637 | Some(CoreFunction::VectorLen)
638 | Some(CoreFunction::VectorClear)
639 | Some(CoreFunction::VectorSwapRemove) => {
640 panic!("`Vector` core functions should have been lowered before code generation")
641 }
642 None => {
643 panic!("All core functions should be known at this phase of compilation")
644 }
645 };
646 instructions.push_str(&instruction);
648
649 (destination, instructions)
650 }
651
652 fn visit_async(&mut self, _input: &AsyncExpression) -> (String, String) {
653 panic!("`AsyncExpression`s should not be in the AST at this phase of compilation.")
654 }
655
656 fn visit_call(&mut self, input: &CallExpression) -> (String, String) {
657 let caller_program = self.program_id.expect("Calls only appear within programs.").name.name;
658 let callee_program = input.program.unwrap_or(caller_program);
659 let func_symbol = self
660 .state
661 .symbol_table
662 .lookup_function(&Location::new(callee_program, input.function.absolute_path().to_vec()))
663 .expect("Type checking guarantees functions exist");
664
665 let mut call_instruction = if caller_program != callee_program {
667 assert!(
669 self.program.stubs.get(&callee_program).is_some(),
670 "Type checking guarantees that imported and stub programs are present."
671 );
672 format!(" call {}.aleo/{}", callee_program, input.function)
673 } else if func_symbol.function.variant.is_async() {
674 format!(" async {}", self.current_function.unwrap().identifier)
675 } else {
676 format!(" call {}", input.function)
677 };
678
679 let mut instructions = String::new();
680
681 for argument in input.arguments.iter() {
682 let (argument, argument_instructions) = self.visit_expression(argument);
683 write!(call_instruction, " {argument}").expect("failed to write to string");
684 instructions.push_str(&argument_instructions);
685 }
686
687 let mut destinations = Vec::new();
689
690 match func_symbol.function.output_type.clone() {
692 Type::Unit => {} Type::Tuple(tuple) => match tuple.length() {
694 0 | 1 => panic!("Parsing guarantees that a tuple type has at least two elements"),
695 len => {
696 for _ in 0..len {
697 destinations.push(self.next_register());
698 }
699 }
700 },
701 _ => {
702 destinations.push(self.next_register());
703 }
704 }
705
706 if func_symbol.function.variant == Variant::AsyncFunction {
708 destinations.push(self.next_register());
709 }
710
711 let output_operands = destinations.join(" ");
713
714 if !destinations.is_empty() {
716 write!(call_instruction, " into").expect("failed to write to string");
717 for destination in &destinations {
718 write!(call_instruction, " {destination}").expect("failed to write to string");
719 }
720 }
721
722 writeln!(call_instruction, ";").expect("failed to write to string");
724
725 instructions.push_str(&call_instruction);
727
728 (output_operands, instructions)
730 }
731
732 fn visit_tuple(&mut self, input: &TupleExpression) -> (String, String) {
733 let mut tuple_elements = Vec::with_capacity(input.elements.len());
736 let mut instructions = String::new();
737
738 for element in input.elements.iter() {
740 let (element, element_instructions) = self.visit_expression(element);
741 tuple_elements.push(element);
742 instructions.push_str(&element_instructions);
743 }
744
745 (tuple_elements.join(" "), instructions)
747 }
748
749 fn visit_unit(&mut self, _input: &UnitExpression) -> (String, String) {
750 panic!("`UnitExpression`s should not be visited during code generation.")
751 }
752
753 pub fn clone_register(&mut self, register: &str, typ: &Type) -> (String, String) {
754 let new_reg = self.next_register();
755 match typ {
756 Type::Address
757 | Type::Boolean
758 | Type::Field
759 | Type::Group
760 | Type::Scalar
761 | Type::Signature
762 | Type::Integer(_) => {
763 let instruction = format!(" cast {register} into {new_reg} as {typ};\n");
765 (new_reg, instruction)
766 }
767
768 Type::Array(array_type) => {
769 let mut instruction = " cast ".to_string();
771 for i in 0..array_type.length.as_u32().expect("length should be known at this point") as usize {
772 write!(&mut instruction, "{register}[{i}u32] ").unwrap();
773 }
774 writeln!(&mut instruction, "into {new_reg} as {};", Self::visit_type(typ)).unwrap();
775 (new_reg, instruction)
776 }
777
778 Type::Composite(comp_ty) => {
779 let program = comp_ty.program.unwrap_or(self.program_id.unwrap().name.name);
781 let location = Location::new(program, comp_ty.path.absolute_path().to_vec());
782 let comp = self
783 .state
784 .symbol_table
785 .lookup_record(&location)
786 .or_else(|| self.state.symbol_table.lookup_struct(&comp_ty.path.absolute_path()))
787 .unwrap();
788 let mut instruction = " cast ".to_string();
789 for member in &comp.members {
790 write!(&mut instruction, "{register}.{} ", member.identifier.name).unwrap();
791 }
792 writeln!(
793 &mut instruction,
794 "into {new_reg} as {};",
795 self.visit_type_with_visibility(typ, leo_ast::Mode::None)
797 )
798 .unwrap();
799 (new_reg, instruction)
800 }
801
802 Type::Optional(_) => panic!("All optional types should have been lowered by now."),
803
804 Type::Vector(_) => panic!("All vector types should have been lowered by now."),
805
806 Type::Mapping(..)
807 | Type::Future(..)
808 | Type::Tuple(..)
809 | Type::Identifier(..)
810 | Type::String
811 | Type::Unit
812 | Type::Numeric
813 | Type::Err => panic!("Objects of type {typ} cannot be cloned."),
814 }
815 }
816}