Skip to main content

leo_passes/code_generation/
mod.rs

1// Copyright (C) 2019-2026 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 crate::{Bytecode, CompiledPrograms, Pass};
18
19use itertools::Itertools;
20use leo_ast::{Ast, Mode, ProgramId};
21use leo_errors::Result;
22
23use std::fmt::Display;
24
25mod expression;
26
27mod program;
28
29mod statement;
30
31mod type_;
32
33mod visitor;
34use snarkvm::{
35    prelude::{ArrayType, LiteralType, Network, PlaintextType},
36    synthesizer::program::{
37        CommitVariant,
38        DeserializeVariant,
39        ECDSAVerifyVariant,
40        HashVariant,
41        SerializeVariant,
42        SnarkVerifyVariant,
43    },
44};
45use visitor::*;
46
47/// The structured output of code generation, before serialization.
48#[derive(Default)]
49pub struct GeneratedPrograms {
50    pub primary: Option<AleoProgram>,
51    pub imports: Vec<(String, AleoProgram)>,
52}
53
54impl GeneratedPrograms {
55    /// Serializes all programs to bytecode strings.
56    pub fn into_compiled(self) -> CompiledPrograms {
57        let primary_bytecode = self.primary.map(|p| p.to_string()).unwrap_or_default();
58        let import_bytecodes = self
59            .imports
60            .into_iter()
61            .map(|(name, program)| Bytecode { program_name: name, bytecode: program.to_string() })
62            .collect();
63        CompiledPrograms { primary_bytecode, import_bytecodes }
64    }
65
66    /// Returns mutable references to all statement lists across all functions/closures/finalizes/constructors.
67    pub fn for_each_statement_list(&mut self, mut f: impl FnMut(&mut Vec<AleoStmt>, usize)) {
68        for (_, program) in &mut self.imports {
69            program.for_each_statement_list(&mut f);
70        }
71        if let Some(primary) = &mut self.primary {
72            primary.for_each_statement_list(&mut f);
73        }
74    }
75}
76
77pub struct CodeGenerating;
78
79impl Pass for CodeGenerating {
80    type Input = ();
81    type Output = GeneratedPrograms;
82
83    const NAME: &str = "CodeGenerating";
84
85    fn do_pass(_input: Self::Input, state: &mut crate::CompilerState) -> Result<Self::Output> {
86        let mut visitor = CodeGeneratingVisitor {
87            state,
88            next_register: 0,
89            current_function: None,
90            variable_mapping: Default::default(),
91            composite_mapping: Default::default(),
92            global_mapping: Default::default(),
93            variant: None,
94            program: match &state.ast {
95                Ast::Program(p) => p,
96                Ast::Library(_) => {
97                    return Ok(Default::default()); // no-op for libraries
98                }
99            },
100            program_id: None,
101            finalize_caller: None,
102            next_label: 0,
103            conditional_depth: 0,
104            internal_record_inputs: Default::default(),
105        };
106
107        Ok(visitor.visit_package())
108    }
109}
110
111#[derive(Debug)]
112pub struct AleoProgram {
113    imports: Vec<String>,
114    program_id: ProgramId,
115    data_types: Vec<AleoDatatype>, // order matters
116    mappings: Vec<AleoMapping>,
117    functions: Vec<AleoFunctional>,
118    constructor: Option<AleoConstructor>,
119}
120
121impl AleoProgram {
122    /// Calls `f` for each statement list in the program (closures, functions, finalizes, constructor).
123    /// The second argument to `f` is the number of input registers for that function.
124    pub fn for_each_statement_list(&mut self, f: &mut impl FnMut(&mut Vec<AleoStmt>, usize)) {
125        for functional in &mut self.functions {
126            match functional {
127                AleoFunctional::Closure(c) => {
128                    f(&mut c.statements, c.inputs.len());
129                }
130                AleoFunctional::Function(fun) => {
131                    f(&mut fun.statements, fun.inputs.len());
132                    if let Some(fin) = &mut fun.finalize {
133                        f(&mut fin.statements, fin.inputs.len());
134                    }
135                }
136                AleoFunctional::Finalize(fin) => {
137                    f(&mut fin.statements, fin.inputs.len());
138                }
139                AleoFunctional::View(v) => {
140                    f(&mut v.statements, v.inputs.len());
141                }
142            }
143        }
144        if let Some(constructor) = &mut self.constructor {
145            f(&mut constructor.statements, 0);
146        }
147    }
148}
149
150impl Display for AleoProgram {
151    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
152        self.imports
153            .iter()
154            .map(|program_name| format!("import {program_name};"))
155            .chain(std::iter::once(format!("program {};\n", self.program_id)))
156            .chain(self.data_types.iter().map(ToString::to_string))
157            .chain(self.mappings.iter().map(ToString::to_string))
158            .chain(self.functions.iter().map(ToString::to_string))
159            .chain(self.constructor.iter().map(ToString::to_string))
160            .join("\n")
161            .fmt(f)
162    }
163}
164
165#[derive(Debug)]
166pub enum AleoDatatype {
167    Struct(AleoStruct),
168    Record(AleoRecord),
169}
170
171impl Display for AleoDatatype {
172    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
173        match self {
174            Self::Struct(s) => s.fmt(f),
175            Self::Record(r) => r.fmt(f),
176        }
177    }
178}
179
180#[derive(Debug)]
181pub struct AleoStruct {
182    name: String,
183    fields: Vec<(String, AleoType)>,
184}
185impl Display for AleoStruct {
186    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
187        writeln!(f, "struct {}:", self.name)?;
188        for (id, ty) in self.fields.iter() {
189            writeln!(f, "    {id} as {ty};")?;
190        }
191        Ok(())
192    }
193}
194
195#[derive(Debug)]
196pub struct AleoRecord {
197    name: String,
198    fields: Vec<(String, AleoType, AleoVisibility)>,
199}
200impl Display for AleoRecord {
201    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
202        writeln!(f, "record {}:", self.name)?;
203        for (id, ty, mode) in self.fields.iter() {
204            writeln!(f, "    {id} as {ty}.{mode};")?;
205        }
206        Ok(())
207    }
208}
209
210#[derive(Clone, Debug, PartialEq)]
211pub enum AleoVisibility {
212    Constant,
213    Public,
214    Private,
215}
216impl AleoVisibility {
217    fn maybe_from(mode: Mode) -> Option<Self> {
218        match mode {
219            Mode::None => None,
220            Mode::Constant => Some(Self::Constant),
221            Mode::Private => Some(Self::Private),
222            Mode::Public => Some(Self::Public),
223        }
224    }
225}
226
227impl Display for AleoVisibility {
228    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
229        write!(f, "{}", match self {
230            Self::Constant => "constant",
231            Self::Public => "public",
232            Self::Private => "private",
233        })
234    }
235}
236
237#[derive(Debug)]
238pub struct AleoMapping {
239    name: String,
240    key_type: AleoType,
241    key_visibility: Option<AleoVisibility>,
242    value_type: AleoType,
243    value_visibility: Option<AleoVisibility>,
244}
245impl Display for AleoMapping {
246    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
247        writeln!(f, "mapping {}:", self.name)?;
248        if let Some(key_viz) = &self.key_visibility {
249            writeln!(f, "    key as {}.{};", self.key_type, key_viz)?;
250        } else {
251            writeln!(f, "    key as {};", self.key_type)?;
252        }
253        if let Some(value_viz) = &self.value_visibility {
254            writeln!(f, "    value as {}.{};", self.value_type, value_viz)?;
255        } else {
256            writeln!(f, "    value as {};", self.value_type)?;
257        }
258        Ok(())
259    }
260}
261
262#[derive(Debug)]
263pub struct AleoClosure {
264    name: String,
265    inputs: Vec<AleoInput>,
266    statements: Vec<AleoStmt>,
267}
268impl Display for AleoClosure {
269    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
270        writeln!(f, "closure {}:", self.name)?;
271        for input in &self.inputs {
272            write!(f, "{}", input)?;
273        }
274        for stm in &self.statements {
275            write!(f, "{}", stm)?;
276        }
277        Ok(())
278    }
279}
280
281#[derive(Debug)]
282pub enum AleoFunctional {
283    Closure(AleoClosure),
284    Function(AleoFunction),
285    Finalize(AleoFinalize),
286    View(AleoView),
287}
288impl AleoFunctional {
289    pub fn as_closure(self) -> AleoClosure {
290        if let Self::Closure(c) = self { c } else { panic!("this is not a closure") }
291    }
292
293    pub fn as_function(self) -> AleoFunction {
294        if let Self::Function(c) = self { c } else { panic!("this is not a function") }
295    }
296
297    pub fn as_function_ref_mut(&mut self) -> &mut AleoFunction {
298        if let Self::Function(c) = self { c } else { panic!("this is not a function") }
299    }
300
301    pub fn as_finalize(self) -> AleoFinalize {
302        if let Self::Finalize(c) = self { c } else { panic!("this is not a finalize") }
303    }
304}
305impl Display for AleoFunctional {
306    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
307        match self {
308            Self::Closure(c) => c.fmt(f),
309            Self::Function(fun) => fun.fmt(f),
310            Self::Finalize(fin) => fin.fmt(f),
311            Self::View(v) => v.fmt(f),
312        }
313    }
314}
315
316/// An Aleo `view` block — a read-only entry point introduced in V15.
317/// Bytecode shape:
318///
319/// ```aleo
320/// view <name>:
321///     input r0 as <type>.public;
322///     ...
323///     output r1 as <type>.public;
324/// ```
325#[derive(Debug)]
326pub struct AleoView {
327    name: String,
328    inputs: Vec<AleoInput>,
329    statements: Vec<AleoStmt>,
330}
331impl Display for AleoView {
332    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
333        writeln!(f, "view {}:", self.name)?;
334        for input in &self.inputs {
335            write!(f, "{}", input)?;
336        }
337        for stm in &self.statements {
338            write!(f, "{}", stm)?;
339        }
340        Ok(())
341    }
342}
343
344#[derive(Debug)]
345pub struct AleoFunction {
346    name: String,
347    inputs: Vec<AleoInput>,
348    statements: Vec<AleoStmt>,
349    finalize: Option<AleoFinalize>,
350}
351impl Display for AleoFunction {
352    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
353        writeln!(f, "function {}:", self.name)?;
354        for input in &self.inputs {
355            write!(f, "{}", input)?;
356        }
357        for stm in &self.statements {
358            write!(f, "{}", stm)?;
359        }
360        if let Some(finalize) = &self.finalize {
361            write!(f, "\n{}", finalize)?;
362        }
363        Ok(())
364    }
365}
366
367#[derive(Debug)]
368pub struct AleoFinalize {
369    caller_name: String,
370    inputs: Vec<AleoInput>,
371    statements: Vec<AleoStmt>,
372}
373impl Display for AleoFinalize {
374    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
375        writeln!(f, "finalize {}:", self.caller_name)?;
376        for input in &self.inputs {
377            write!(f, "{}", input)?;
378        }
379        for stm in &self.statements {
380            write!(f, "{}", stm)?;
381        }
382        Ok(())
383    }
384}
385
386#[derive(Debug)]
387pub struct AleoInput {
388    register: AleoReg,
389    type_: AleoType,
390    visibility: Option<AleoVisibility>,
391}
392impl Display for AleoInput {
393    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
394        if let Some(visibility) = &self.visibility {
395            writeln!(f, "    input {} as {}.{};", self.register, self.type_, visibility)
396        } else {
397            writeln!(f, "    input {} as {};", self.register, self.type_)
398        }
399    }
400}
401
402#[derive(Debug)]
403pub struct AleoConstructor {
404    statements: Vec<AleoStmt>,
405}
406impl Display for AleoConstructor {
407    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
408        writeln!(f, "constructor:")?;
409        for stm in &self.statements {
410            write!(f, "{}", stm)?;
411        }
412        Ok(())
413    }
414}
415
416#[derive(Hash, Eq, PartialEq, Clone, Debug)]
417pub enum AleoExpr {
418    Reg(AleoReg),
419    Tuple(Vec<AleoExpr>),
420    ArrayAccess(Box<AleoExpr>, Box<AleoExpr>),
421    MemberAccess(Box<AleoExpr>, String),
422    RawName(String),
423    // Literals
424    Address(String),
425    Identifier(String),
426    Bool(bool),
427    Field(String),
428    Group(String),
429    Signature(String),
430    Scalar(String),
431    String(String),
432    U8(u8),
433    U16(u16),
434    U32(u32),
435    U64(u64),
436    U128(u128),
437    I8(i8),
438    I16(i16),
439    I32(i32),
440    I64(i64),
441    I128(i128),
442}
443impl Display for AleoExpr {
444    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
445        match self {
446            Self::Reg(reg) => write!(f, "{reg}"),
447            Self::Tuple(regs) => write!(f, "{}", regs.iter().map(|reg| reg.to_string()).join(" ")),
448            Self::ArrayAccess(array, index) => write!(f, "{array}[{index}]"),
449            Self::MemberAccess(comp, member) => write!(f, "{comp}.{member}"),
450            Self::RawName(n) => write!(f, "{n}"),
451            // Literals
452            Self::Identifier(val) => write!(f, "'{val}'"),
453            Self::Address(val) => write!(f, "{val}"),
454            Self::Bool(val) => write!(f, "{val}"),
455            Self::Field(val) => write!(f, "{val}field"),
456            Self::Group(val) => write!(f, "{val}group"),
457            Self::U8(val) => write!(f, "{val}u8"),
458            Self::U16(val) => write!(f, "{val}u16"),
459            Self::U32(val) => write!(f, "{val}u32"),
460            Self::U64(val) => write!(f, "{val}u64"),
461            Self::U128(val) => write!(f, "{val}u128"),
462            Self::I8(val) => write!(f, "{val}i8"),
463            Self::I16(val) => write!(f, "{val}i16"),
464            Self::I32(val) => write!(f, "{val}i32"),
465            Self::I64(val) => write!(f, "{val}i64"),
466            Self::I128(val) => write!(f, "{val}i128"),
467            Self::Scalar(val) => write!(f, "{val}scalar"),
468            Self::Signature(val) => write!(f, "{val}"),
469            Self::String(val) => write!(f, "\"{val}\""),
470        }
471    }
472}
473
474#[derive(Clone, Debug, PartialEq)]
475pub enum AleoStmt {
476    Output(AleoExpr, AleoType, Option<AleoVisibility>),
477    AssertEq(AleoExpr, AleoExpr),
478    AssertNeq(AleoExpr, AleoExpr),
479    Cast(AleoExpr, AleoReg, AleoType),
480    Abs(AleoExpr, AleoReg),
481    AbsW(AleoExpr, AleoReg),
482    Double(AleoExpr, AleoReg),
483    Inv(AleoExpr, AleoReg),
484    Not(AleoExpr, AleoReg),
485    Neg(AleoExpr, AleoReg),
486    Square(AleoExpr, AleoReg),
487    Sqrt(AleoExpr, AleoReg),
488    Ternary(AleoExpr, AleoExpr, AleoExpr, AleoReg),
489    Commit(CommitVariant, AleoExpr, AleoExpr, AleoReg, AleoType),
490    Hash(HashVariant, AleoExpr, AleoReg, AleoType),
491    Get(AleoExpr, AleoExpr, AleoReg),
492    GetOrUse(AleoExpr, AleoExpr, AleoExpr, AleoReg),
493    Set(AleoExpr, AleoExpr, AleoExpr),
494    Remove(AleoExpr, AleoExpr),
495    Contains(AleoExpr, AleoExpr, AleoReg),
496    RandChacha(AleoReg, AleoType),
497    SignVerify(AleoExpr, AleoExpr, AleoExpr, AleoReg),
498    EcdsaVerify(ECDSAVerifyVariant, AleoExpr, AleoExpr, AleoExpr, AleoReg),
499    SnarkVerify(SnarkVerifyVariant, AleoExpr, AleoExpr, AleoExpr, AleoExpr, AleoReg),
500    Await(AleoExpr),
501    Serialize(SerializeVariant, AleoExpr, AleoType, AleoReg, AleoType),
502    Deserialize(DeserializeVariant, AleoExpr, AleoType, AleoReg, AleoType),
503    Call(String, Vec<AleoExpr>, Vec<AleoReg>),
504    CallDynamic(
505        AleoExpr,
506        AleoExpr,
507        AleoExpr,
508        Vec<AleoExpr>,
509        Vec<(AleoType, Option<AleoVisibility>)>,
510        Vec<AleoReg>,
511        Vec<(AleoType, Option<AleoVisibility>)>,
512    ),
513    GetRecordDynamic(AleoExpr, String, AleoReg, AleoType),
514    /// `contains.dynamic {prog} {net} {mapping}[{key}] into {dest};`
515    ContainsDynamic(AleoExpr, AleoExpr, AleoExpr, AleoExpr, AleoReg),
516    /// `get.dynamic {prog} {net} {mapping}[{key}] into {dest} as {type};`
517    GetDynamic(AleoExpr, AleoExpr, AleoExpr, AleoExpr, AleoReg, AleoType),
518    /// `get.or_use.dynamic {prog} {net} {mapping}[{key}] {default} into {dest} as {type};`
519    GetOrUseDynamic(AleoExpr, AleoExpr, AleoExpr, AleoExpr, AleoExpr, AleoReg, AleoType),
520    Async(String, Vec<AleoExpr>, Vec<AleoReg>),
521    BranchEq(AleoExpr, AleoExpr, String),
522    Position(String),
523    Add(AleoExpr, AleoExpr, AleoReg),
524    AddWrapped(AleoExpr, AleoExpr, AleoReg),
525    And(AleoExpr, AleoExpr, AleoReg),
526    Div(AleoExpr, AleoExpr, AleoReg),
527    DivWrapped(AleoExpr, AleoExpr, AleoReg),
528    Eq(AleoExpr, AleoExpr, AleoReg),
529    Gte(AleoExpr, AleoExpr, AleoReg),
530    Gt(AleoExpr, AleoExpr, AleoReg),
531    Lte(AleoExpr, AleoExpr, AleoReg),
532    Lt(AleoExpr, AleoExpr, AleoReg),
533    Mod(AleoExpr, AleoExpr, AleoReg),
534    Mul(AleoExpr, AleoExpr, AleoReg),
535    MulWrapped(AleoExpr, AleoExpr, AleoReg),
536    Nand(AleoExpr, AleoExpr, AleoReg),
537    Neq(AleoExpr, AleoExpr, AleoReg),
538    Nor(AleoExpr, AleoExpr, AleoReg),
539    Or(AleoExpr, AleoExpr, AleoReg),
540    Pow(AleoExpr, AleoExpr, AleoReg),
541    PowWrapped(AleoExpr, AleoExpr, AleoReg),
542    Rem(AleoExpr, AleoExpr, AleoReg),
543    RemWrapped(AleoExpr, AleoExpr, AleoReg),
544    Shl(AleoExpr, AleoExpr, AleoReg),
545    ShlWrapped(AleoExpr, AleoExpr, AleoReg),
546    Shr(AleoExpr, AleoExpr, AleoReg),
547    ShrWrapped(AleoExpr, AleoExpr, AleoReg),
548    Sub(AleoExpr, AleoExpr, AleoReg),
549    SubWrapped(AleoExpr, AleoExpr, AleoReg),
550    Xor(AleoExpr, AleoExpr, AleoReg),
551}
552impl Display for AleoStmt {
553    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
554        match self {
555            Self::Output(arg, type_, viz) => {
556                if let Some(viz) = &viz {
557                    writeln!(f, "    output {} as {}.{};", arg, type_, viz)
558                } else {
559                    writeln!(f, "    output {} as {};", arg, type_)
560                }
561            }
562            Self::AssertEq(left, right) => writeln!(f, "    assert.eq {left} {right};"),
563            Self::AssertNeq(left, right) => writeln!(f, "    assert.neq {left} {right};"),
564            Self::Cast(operands, dest, type_) => {
565                writeln!(f, "    cast {operands} into {dest} as {type_};")
566            }
567            Self::GetRecordDynamic(src, field, dest, type_) => {
568                writeln!(f, "    get.record.dynamic {src}.{field} into {dest} as {type_};")
569            }
570            Self::Abs(op, dest) => writeln!(f, "    abs {op} into {dest};"),
571            Self::AbsW(op, dest) => writeln!(f, "    abs.w {op} into {dest};"),
572            Self::Double(op, dest) => writeln!(f, "    double {op} into {dest};"),
573            Self::Inv(op, dest) => writeln!(f, "    inv {op} into {dest};"),
574            Self::Not(op, dest) => writeln!(f, "    not {op} into {dest};"),
575            Self::Neg(op, dest) => writeln!(f, "    neg {op} into {dest};"),
576            Self::Square(op, dest) => writeln!(f, "    square {op} into {dest};"),
577            Self::Sqrt(op, dest) => writeln!(f, "    sqrt {op} into {dest};"),
578            Self::Ternary(cond, if_true, if_false, dest) => {
579                writeln!(f, "    ternary {cond} {if_true} {if_false} into {dest};")
580            }
581            Self::Commit(variant, arg0, arg1, dest, type_) => {
582                writeln!(f, "    {} {arg0} {arg1} into {dest} as {type_};", CommitVariant::opcode(*variant as u8))
583            }
584            Self::Hash(variant, arg0, dest, type_) => {
585                writeln!(f, "    {} {arg0} into {dest} as {type_};", variant.opcode())
586            }
587            Self::Get(mapping, key, dest) => writeln!(f, "    get {mapping}[{key}] into {dest};"),
588            Self::GetOrUse(mapping, key, default, dest) => {
589                writeln!(f, "    get.or_use {mapping}[{key}] {default} into {dest};")
590            }
591            Self::Set(value, mapping, key) => writeln!(f, "    set {value} into {mapping}[{key}];"),
592            Self::Remove(mapping, key) => writeln!(f, "    remove {mapping}[{key}];"),
593            Self::Contains(mapping, key, dest) => writeln!(f, "    contains {mapping}[{key}] into {dest};"),
594            Self::RandChacha(dest, type_) => writeln!(f, "    rand.chacha into {dest} as {type_};"),
595            Self::SignVerify(arg0, arg1, arg2, dest) => {
596                writeln!(f, "    sign.verify {arg0} {arg1} {arg2} into {dest};")
597            }
598            Self::EcdsaVerify(variant, arg0, arg1, arg2, dest) => {
599                writeln!(f, "    {} {arg0} {arg1} {arg2} into {dest};", variant.opcode())
600            }
601            Self::SnarkVerify(variant, arg0, arg1, arg2, arg3, dest) => {
602                writeln!(f, "    {} {arg0} {arg1} {arg2} {arg3} into {dest};", variant.opcode())
603            }
604            Self::Await(exp) => writeln!(f, "    await {exp};"),
605            Self::Serialize(variant, input, input_ty, dest, dest_ty) => {
606                writeln!(
607                    f,
608                    "    {} {input} ({input_ty}) into {dest} ({dest_ty});",
609                    SerializeVariant::opcode(variant.clone() as u8),
610                )
611            }
612            Self::Deserialize(variant, input, input_ty, dest, dest_ty) => {
613                writeln!(
614                    f,
615                    "    {} {input} ({input_ty}) into {dest} ({dest_ty});",
616                    DeserializeVariant::opcode(variant.clone() as u8),
617                )
618            }
619            Self::Call(id, inputs, dests) => {
620                write!(f, "    call {id}")?;
621                if !inputs.is_empty() {
622                    write!(f, " {}", inputs.iter().map(|input| input.to_string()).join(" "))?;
623                }
624                if !dests.is_empty() {
625                    write!(f, " into {}", dests.iter().map(|input| input.to_string()).join(" "))?;
626                }
627                writeln!(f, ";")
628            }
629            Self::CallDynamic(prog, net, fun, inputs, input_types, outputs, output_types) => {
630                write!(f, "    call.dynamic {prog} {net} {fun}")?;
631                if !inputs.is_empty() {
632                    write!(f, " with {}", inputs.iter().map(|i| i.to_string()).join(" "))?;
633                }
634                if !input_types.is_empty() {
635                    write!(
636                        f,
637                        " (as {})",
638                        input_types
639                            .iter()
640                            .map(|(ty, viz)| { if let Some(v) = viz { format!("{ty}.{v}") } else { format!("{ty}") } })
641                            .join(" ")
642                    )?;
643                }
644                if !outputs.is_empty() {
645                    write!(f, " into {}", outputs.iter().map(|o| o.to_string()).join(" "))?;
646                }
647                if !output_types.is_empty() {
648                    write!(
649                        f,
650                        " (as {})",
651                        output_types
652                            .iter()
653                            .map(|(ty, viz)| { if let Some(v) = viz { format!("{ty}.{v}") } else { format!("{ty}") } })
654                            .join(" ")
655                    )?;
656                }
657                writeln!(f, ";")
658            }
659            Self::ContainsDynamic(prog, net, mapping, key, dest) => {
660                writeln!(f, "    contains.dynamic {prog} {net} {mapping}[{key}] into {dest};")
661            }
662            Self::GetDynamic(prog, net, mapping, key, dest, ty) => {
663                writeln!(f, "    get.dynamic {prog} {net} {mapping}[{key}] into {dest} as {ty};")
664            }
665            Self::GetOrUseDynamic(prog, net, mapping, key, default, dest, ty) => {
666                writeln!(f, "    get.or_use.dynamic {prog} {net} {mapping}[{key}] {default} into {dest} as {ty};")
667            }
668            Self::Async(id, inputs, dests) => {
669                write!(f, "    async {id}")?;
670                if !inputs.is_empty() {
671                    write!(f, " {}", inputs.iter().map(|input| input.to_string()).join(" "))?;
672                }
673                if !dests.is_empty() {
674                    write!(f, " into {}", dests.iter().map(|input| input.to_string()).join(" "))?;
675                }
676                writeln!(f, ";")
677            }
678            Self::BranchEq(arg0, arg1, label) => {
679                writeln!(f, "    branch.eq {arg0} {arg1} to {label};")
680            }
681            Self::Position(label) => writeln!(f, "    position {label};"),
682            Self::Add(arg0, arg1, dest) => writeln!(f, "    add {arg0} {arg1} into {dest};"),
683            Self::AddWrapped(arg0, arg1, dest) => writeln!(f, "    add.w {arg0} {arg1} into {dest};"),
684            Self::And(arg0, arg1, dest) => writeln!(f, "    and {arg0} {arg1} into {dest};"),
685            Self::Div(arg0, arg1, dest) => writeln!(f, "    div {arg0} {arg1} into {dest};"),
686            Self::DivWrapped(arg0, arg1, dest) => writeln!(f, "    div.w {arg0} {arg1} into {dest};"),
687            Self::Eq(arg0, arg1, dest) => writeln!(f, "    is.eq {arg0} {arg1} into {dest};"),
688            Self::Gte(arg0, arg1, dest) => writeln!(f, "    gte {arg0} {arg1} into {dest};"),
689            Self::Gt(arg0, arg1, dest) => writeln!(f, "    gt {arg0} {arg1} into {dest};"),
690            Self::Lte(arg0, arg1, dest) => writeln!(f, "    lte {arg0} {arg1} into {dest};"),
691            Self::Lt(arg0, arg1, dest) => writeln!(f, "    lt {arg0} {arg1} into {dest};"),
692            Self::Mod(arg0, arg1, dest) => writeln!(f, "    mod {arg0} {arg1} into {dest};"),
693            Self::Mul(arg0, arg1, dest) => writeln!(f, "    mul {arg0} {arg1} into {dest};"),
694            Self::MulWrapped(arg0, arg1, dest) => writeln!(f, "    mul.w {arg0} {arg1} into {dest};"),
695            Self::Nand(arg0, arg1, dest) => writeln!(f, "    nand {arg0} {arg1} into {dest};"),
696            Self::Neq(arg0, arg1, dest) => writeln!(f, "    is.neq {arg0} {arg1} into {dest};"),
697            Self::Nor(arg0, arg1, dest) => writeln!(f, "    nor {arg0} {arg1} into {dest};"),
698            Self::Or(arg0, arg1, dest) => writeln!(f, "    or {arg0} {arg1} into {dest};"),
699            Self::Pow(arg0, arg1, dest) => writeln!(f, "    pow {arg0} {arg1} into {dest};"),
700            Self::PowWrapped(arg0, arg1, dest) => writeln!(f, "    pow.w {arg0} {arg1} into {dest};"),
701            Self::Rem(arg0, arg1, dest) => writeln!(f, "    rem {arg0} {arg1} into {dest};"),
702            Self::RemWrapped(arg0, arg1, dest) => writeln!(f, "    rem.w {arg0} {arg1} into {dest};"),
703            Self::Shl(arg0, arg1, dest) => writeln!(f, "    shl {arg0} {arg1} into {dest};"),
704            Self::ShlWrapped(arg0, arg1, dest) => writeln!(f, "    shl.w {arg0} {arg1} into {dest};"),
705            Self::Shr(arg0, arg1, dest) => writeln!(f, "    shr {arg0} {arg1} into {dest};"),
706            Self::ShrWrapped(arg0, arg1, dest) => writeln!(f, "    shr.w {arg0} {arg1} into {dest};"),
707            Self::Sub(arg0, arg1, dest) => writeln!(f, "    sub {arg0} {arg1} into {dest};"),
708            Self::SubWrapped(arg0, arg1, dest) => writeln!(f, "    sub.w {arg0} {arg1} into {dest};"),
709            Self::Xor(arg0, arg1, dest) => writeln!(f, "    xor {arg0} {arg1} into {dest};"),
710        }
711    }
712}
713
714#[derive(Clone, Debug, PartialEq)]
715pub enum AleoType {
716    Future { name: String, program: String },
717    Record { name: String, program: Option<String> },
718    Ident { name: String },
719    Location { program: String, name: String },
720    Array { inner: Box<AleoType>, len: u32 },
721    GroupX,
722    GroupY,
723    Address,
724    Identifier,
725    DynamicRecord,
726    DynamicFuture,
727    Boolean,
728    Field,
729    Group,
730    I8,
731    I16,
732    I32,
733    I64,
734    I128,
735    U8,
736    U16,
737    U32,
738    U64,
739    U128,
740    Scalar,
741    Signature,
742    String,
743}
744impl Display for AleoType {
745    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
746        match self {
747            Self::Future { name, program } => write!(f, "{program}/{name}.future"),
748            Self::Record { name, program: Some(program_name) } => write!(f, "{program_name}/{name}.record"),
749            Self::Record { name, program: None } => write!(f, "{name}.record"),
750            Self::GroupX => write!(f, "group.x"),
751            Self::GroupY => write!(f, "group.y"),
752            Self::Ident { name } => write!(f, "{name}"),
753            Self::Location { program, name } => write!(f, "{program}/{name}"),
754            Self::Identifier => write!(f, "identifier"),
755            Self::DynamicRecord => write!(f, "dynamic.record"),
756            Self::DynamicFuture => write!(f, "dynamic.future"),
757            Self::Address => write!(f, "address"),
758            Self::Boolean => write!(f, "boolean"),
759            Self::Field => write!(f, "field"),
760            Self::Group => write!(f, "group"),
761            Self::I8 => write!(f, "i8"),
762            Self::I16 => write!(f, "i16"),
763            Self::I32 => write!(f, "i32"),
764            Self::I64 => write!(f, "i64"),
765            Self::I128 => write!(f, "i128"),
766            Self::U8 => write!(f, "u8"),
767            Self::U16 => write!(f, "u16"),
768            Self::U32 => write!(f, "u32"),
769            Self::U64 => write!(f, "u64"),
770            Self::U128 => write!(f, "u128"),
771            Self::Scalar => write!(f, "scalar"),
772            Self::Signature => write!(f, "signature"),
773            Self::String => write!(f, "string"),
774            Self::Array { inner, len } => write!(f, "[{inner}; {len}u32]"),
775        }
776    }
777}
778impl<N: Network> From<PlaintextType<N>> for AleoType {
779    fn from(value: PlaintextType<N>) -> Self {
780        match value {
781            PlaintextType::Literal(lit) => lit.into(),
782            PlaintextType::Struct(id) => Self::Ident { name: id.to_string() },
783            PlaintextType::ExternalStruct(loc) => {
784                Self::Location { program: loc.program_id().to_string(), name: loc.name().to_string() }
785            }
786            PlaintextType::Array(arr) => arr.into(),
787        }
788    }
789}
790impl From<LiteralType> for AleoType {
791    fn from(value: LiteralType) -> Self {
792        match value {
793            LiteralType::Identifier => Self::Identifier,
794            LiteralType::Address => Self::Address,
795            LiteralType::Boolean => Self::Boolean,
796            LiteralType::Field => Self::Field,
797            LiteralType::Group => Self::Group,
798            LiteralType::I8 => Self::I8,
799            LiteralType::I16 => Self::I16,
800            LiteralType::I32 => Self::I32,
801            LiteralType::I64 => Self::I64,
802            LiteralType::I128 => Self::I128,
803            LiteralType::U8 => Self::U8,
804            LiteralType::U16 => Self::U16,
805            LiteralType::U32 => Self::U32,
806            LiteralType::U64 => Self::U64,
807            LiteralType::U128 => Self::U128,
808            LiteralType::Scalar => Self::Scalar,
809            LiteralType::Signature => Self::Signature,
810            LiteralType::String => Self::String,
811        }
812    }
813}
814impl<N: Network> From<ArrayType<N>> for AleoType {
815    fn from(value: ArrayType<N>) -> Self {
816        Self::Array { len: **value.length(), inner: Box::new(AleoType::from(value.next_element_type().clone())) }
817    }
818}
819
820#[derive(Hash, Eq, PartialEq, Clone, Debug)]
821pub enum AleoReg {
822    Self_,
823    Block,
824    Network,
825    R(u64),
826}
827impl Display for AleoReg {
828    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
829        match self {
830            Self::Self_ => write!(f, "self"),
831            Self::Block => write!(f, "block"),
832            Self::Network => write!(f, "network"),
833            Self::R(n) => write!(f, "r{n}"),
834        }
835    }
836}