leo_interpreter/
cursor.rs

1// Copyright (C) 2019-2025 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 super::*;
18
19use leo_ast::{
20    ArrayType,
21    AssertVariant,
22    AsyncExpression,
23    BinaryOperation,
24    Block,
25    CoreConstant,
26    CoreFunction,
27    DefinitionPlace,
28    Expression,
29    Function,
30    NodeID,
31    Statement,
32    StructVariableInitializer,
33    Type,
34    UnaryOperation,
35    Variant,
36    interpreter_value::{
37        AsyncExecution,
38        CoreFunctionHelper,
39        GlobalId,
40        Value,
41        evaluate_binary,
42        evaluate_core_function,
43        evaluate_unary,
44        literal_to_value,
45    },
46};
47use leo_errors::{InterpreterHalt, Result};
48use leo_span::{Span, Symbol, sym};
49
50use snarkvm::prelude::{
51    Closure as SvmClosure,
52    Finalize as SvmFinalize,
53    Function as SvmFunctionParam,
54    ProgramID,
55    TestnetV0,
56};
57
58use indexmap::IndexMap;
59use itertools::Itertools;
60use rand_chacha::{ChaCha20Rng, rand_core::SeedableRng};
61use std::{cmp::Ordering, collections::HashMap, mem, str::FromStr as _};
62
63pub type Closure = SvmClosure<TestnetV0>;
64pub type Finalize = SvmFinalize<TestnetV0>;
65pub type SvmFunction = SvmFunctionParam<TestnetV0>;
66
67/// Names associated to values in a function being executed.
68#[derive(Clone, Debug)]
69pub struct FunctionContext {
70    path: Vec<Symbol>,
71    program: Symbol,
72    pub caller: Value,
73    names: HashMap<Vec<Symbol>, Value>,
74    accumulated_futures: Vec<AsyncExecution>,
75    is_async: bool,
76}
77
78/// A stack of contexts, building with the function call stack.
79#[derive(Clone, Debug, Default)]
80pub struct ContextStack {
81    contexts: Vec<FunctionContext>,
82    current_len: usize,
83}
84
85impl ContextStack {
86    fn len(&self) -> usize {
87        self.current_len
88    }
89
90    fn push(
91        &mut self,
92        path: &[Symbol],
93        program: Symbol,
94        caller: Value,
95        is_async: bool,
96        names: HashMap<Vec<Symbol>, Value>, // a map of variable names that are already known
97    ) {
98        if self.current_len == self.contexts.len() {
99            self.contexts.push(FunctionContext {
100                path: path.to_vec(),
101                program,
102                caller: caller.clone(),
103                names: HashMap::new(),
104                accumulated_futures: Default::default(),
105                is_async,
106            });
107        }
108
109        self.contexts[self.current_len].path = path.to_vec();
110        self.contexts[self.current_len].program = program;
111        self.contexts[self.current_len].caller = caller;
112        self.contexts[self.current_len].names = names;
113        self.contexts[self.current_len].accumulated_futures.clear();
114        self.contexts[self.current_len].is_async = is_async;
115        self.current_len += 1;
116    }
117
118    pub fn pop(&mut self) {
119        // We never actually pop the underlying Vec
120        // so we can reuse the storage of the hash
121        // tables.
122        assert!(self.len() > 0);
123        self.current_len -= 1;
124        self.contexts[self.current_len].names.clear();
125    }
126
127    /// Get the future accumulated by awaiting futures in the current function call.
128    ///
129    /// If the current code being interpreted is not in an async function, this
130    /// will of course be empty.
131    fn get_future(&mut self) -> Vec<AsyncExecution> {
132        assert!(self.len() > 0);
133        mem::take(&mut self.contexts[self.current_len - 1].accumulated_futures)
134    }
135
136    fn set(&mut self, path: &[Symbol], value: Value) {
137        assert!(self.current_len > 0);
138        self.last_mut().unwrap().names.insert(path.to_vec(), value);
139    }
140
141    pub fn add_future(&mut self, future: Vec<AsyncExecution>) {
142        assert!(self.current_len > 0);
143        self.contexts[self.current_len - 1].accumulated_futures.extend(future);
144    }
145
146    /// Are we currently in an async function?
147    fn is_async(&self) -> bool {
148        assert!(self.current_len > 0);
149        self.last().unwrap().is_async
150    }
151
152    pub fn current_program(&self) -> Option<Symbol> {
153        self.last().map(|c| c.program)
154    }
155
156    pub fn last(&self) -> Option<&FunctionContext> {
157        self.len().checked_sub(1).and_then(|i| self.contexts.get(i))
158    }
159
160    fn last_mut(&mut self) -> Option<&mut FunctionContext> {
161        self.len().checked_sub(1).and_then(|i| self.contexts.get_mut(i))
162    }
163}
164
165#[derive(Clone, Debug)]
166pub enum AleoContext {
167    Closure(Closure),
168    Function(SvmFunction),
169    Finalize(Finalize),
170}
171
172/// A Leo construct to be evauated.
173#[derive(Clone, Debug)]
174pub enum Element {
175    /// A Leo statement.
176    Statement(Statement),
177
178    /// A Leo expression. The optional type is an optional "expected type" for the expression. It helps when trying to
179    /// resolve an unsuffixed literal.
180    Expression(Expression, Option<Type>),
181
182    /// A Leo block.
183    ///
184    /// We have a separate variant for Leo blocks for two reasons:
185    /// 1. In a ConditionalExpression, the `then` block is stored
186    ///    as just a Block with no statement, and
187    /// 2. We need to remember if a Block came from a function body,
188    ///    so that if such a block ends, we know to push a `Unit` to
189    ///    the values stack.
190    Block {
191        block: Block,
192        function_body: bool,
193    },
194
195    AleoExecution {
196        context: Box<AleoContext>,
197        registers: IndexMap<u64, Value>,
198        instruction_index: usize,
199    },
200
201    DelayedCall(GlobalId),
202    DelayedAsyncBlock {
203        program: Symbol,
204        block: NodeID,
205        names: HashMap<Vec<Symbol>, Value>,
206    },
207}
208
209impl Element {
210    pub fn span(&self) -> Span {
211        use Element::*;
212        match self {
213            Statement(statement) => statement.span(),
214            Expression(expression, _) => expression.span(),
215            Block { block, .. } => block.span(),
216            AleoExecution { .. } | DelayedCall(..) | DelayedAsyncBlock { .. } => Default::default(),
217        }
218    }
219}
220
221/// A frame of execution, keeping track of the Element next to
222/// be executed and the number of steps we've done so far.
223#[derive(Clone, Debug)]
224pub struct Frame {
225    pub step: usize,
226    pub element: Element,
227    pub user_initiated: bool,
228}
229
230#[derive(Clone, Debug)]
231pub enum FunctionVariant {
232    Leo(Function),
233    AleoClosure(Closure),
234    AleoFunction(SvmFunction),
235}
236
237/// Tracks the current execution state - a cursor into the running program.
238#[derive(Clone, Debug)]
239pub struct Cursor {
240    /// Stack of execution frames, with the one currently to be executed on top.
241    pub frames: Vec<Frame>,
242
243    /// Stack of values from evaluated expressions.
244    ///
245    /// Each time an expression completes evaluation, a value is pushed here.
246    pub values: Vec<Value>,
247
248    /// All functions (or transitions or inlines) in any program being interpreted.
249    pub functions: HashMap<GlobalId, FunctionVariant>,
250
251    /// All the async blocks encountered. We identify them by their `NodeID`.
252    pub async_blocks: HashMap<NodeID, Block>,
253
254    /// Consts are stored here.
255    pub globals: HashMap<GlobalId, Value>,
256
257    pub user_values: HashMap<Vec<Symbol>, Value>,
258
259    pub mappings: HashMap<GlobalId, HashMap<Value, Value>>,
260
261    /// For each struct type, we only need to remember the names of its members, in order.
262    pub structs: HashMap<Vec<Symbol>, IndexMap<Symbol, Type>>,
263
264    /// For each record type, we index by program name and path, and remember its members
265    /// except `owner`.
266    pub records: HashMap<(Symbol, Vec<Symbol>), IndexMap<Symbol, Type>>,
267
268    pub futures: Vec<AsyncExecution>,
269
270    pub contexts: ContextStack,
271
272    pub signer: Value,
273
274    pub rng: ChaCha20Rng,
275
276    pub block_height: u32,
277
278    pub really_async: bool,
279
280    pub program: Option<Symbol>,
281}
282
283impl CoreFunctionHelper for Cursor {
284    fn pop_value_impl(&mut self) -> Option<Value> {
285        self.values.pop()
286    }
287
288    fn set_block_height(&mut self, height: u32) {
289        self.block_height = height;
290    }
291
292    fn lookup_mapping(&self, program: Option<Symbol>, name: Symbol) -> Option<&HashMap<Value, Value>> {
293        Cursor::lookup_mapping(self, program, name)
294    }
295
296    fn lookup_mapping_mut(&mut self, program: Option<Symbol>, name: Symbol) -> Option<&mut HashMap<Value, Value>> {
297        Cursor::lookup_mapping_mut(self, program, name)
298    }
299
300    fn rng(&mut self) -> Option<&mut ChaCha20Rng> {
301        Some(&mut self.rng)
302    }
303}
304
305impl Cursor {
306    /// `really_async` indicates we should really delay execution of async function calls until the user runs them.
307    pub fn new(really_async: bool, signer: Value, block_height: u32) -> Self {
308        Cursor {
309            frames: Default::default(),
310            values: Default::default(),
311            functions: Default::default(),
312            async_blocks: Default::default(),
313            globals: Default::default(),
314            user_values: Default::default(),
315            mappings: Default::default(),
316            structs: Default::default(),
317            records: Default::default(),
318            contexts: Default::default(),
319            futures: Default::default(),
320            rng: ChaCha20Rng::from_entropy(),
321            signer,
322            block_height,
323            really_async,
324            program: None,
325        }
326    }
327
328    fn set_place(
329        new_value: Value,
330        this_value: &mut Value,
331        places: &mut dyn Iterator<Item = &Expression>,
332        indices: &mut dyn Iterator<Item = Value>,
333    ) -> Result<()> {
334        match places.next() {
335            None => *this_value = new_value,
336            Some(Expression::ArrayAccess(_access)) => {
337                let index = indices.next().unwrap();
338                let index = index.as_u32().unwrap() as usize;
339
340                let mut index_value = this_value.array_index(index).expect("Type");
341                Self::set_place(new_value, &mut index_value, places, indices)?;
342
343                if this_value.array_index_set(index, index_value).is_none() {
344                    halt_no_span!("Invalid array assignment");
345                }
346            }
347            Some(Expression::TupleAccess(access)) => {
348                let index = access.index.value();
349                let mut index_value = this_value.tuple_index(index).expect("Type");
350                Self::set_place(new_value, &mut index_value, places, indices)?;
351                if this_value.tuple_index_set(index, index_value).is_none() {
352                    halt_no_span!("Invalid tuple assignment");
353                }
354            }
355            Some(Expression::MemberAccess(access)) => {
356                let mut access_value = this_value.member_access(access.name.name).expect("Type");
357                Self::set_place(new_value, &mut access_value, places, indices)?;
358                if this_value.member_set(access.name.name, access_value).is_none() {
359                    halt_no_span!("Invalid member set");
360                }
361            }
362            Some(Expression::Path(_path)) => {
363                Self::set_place(new_value, this_value, places, indices)?;
364            }
365            Some(place) => halt_no_span!("Invalid place for assignment: {place}"),
366        }
367
368        Ok(())
369    }
370
371    pub fn assign(&mut self, value: Value, place: &Expression, indices: &mut dyn Iterator<Item = Value>) -> Result<()> {
372        let mut places = vec![place];
373        let indices: Vec<Value> = indices.collect();
374
375        let path: &Path;
376
377        loop {
378            match places.last().unwrap() {
379                Expression::ArrayAccess(access) => places.push(&access.array),
380                Expression::TupleAccess(access) => places.push(&access.tuple),
381                Expression::MemberAccess(access) => places.push(&access.inner),
382                Expression::Path(path_) => {
383                    path = path_;
384                    break;
385                }
386                place @ (Expression::AssociatedConstant(..)
387                | Expression::AssociatedFunction(..)
388                | Expression::Async(..)
389                | Expression::Array(..)
390                | Expression::Binary(..)
391                | Expression::Call(..)
392                | Expression::Cast(..)
393                | Expression::Err(..)
394                | Expression::Literal(..)
395                | Expression::Locator(..)
396                | Expression::Repeat(..)
397                | Expression::Struct(..)
398                | Expression::Ternary(..)
399                | Expression::Tuple(..)
400                | Expression::Unary(..)
401                | Expression::Unit(..)) => halt_no_span!("Invalid place for assignment: {place}"),
402            }
403        }
404
405        let full_name = self.to_absolute_path(&path.as_symbols());
406
407        let mut leo_value = self.lookup(&full_name).unwrap_or(Value::make_unit());
408
409        // Do an ad hoc evaluation of the lhs of the assignment to determine its type.
410        let mut temp_value = leo_value.clone();
411        let mut indices_iter = indices.iter();
412
413        for place in places.iter().rev() {
414            match place {
415                Expression::ArrayAccess(_access) => {
416                    let next_index = indices_iter.next().unwrap();
417                    temp_value = temp_value.array_index(next_index.as_u32().unwrap() as usize).unwrap();
418                }
419                Expression::TupleAccess(access) => {
420                    temp_value = temp_value.tuple_index(access.index.value()).unwrap();
421                }
422                Expression::MemberAccess(access) => {
423                    temp_value = temp_value.member_access(access.name.name).unwrap();
424                }
425                Expression::Path(_path) =>
426                    // temp_value is already set to leo_value
427                    {}
428                _ => panic!("Can't happen."),
429            }
430        }
431
432        let ty = temp_value.get_numeric_type();
433        let value = value.resolve_if_unsuffixed(&ty, place.span())?;
434
435        Self::set_place(value, &mut leo_value, &mut places.into_iter().rev(), &mut indices.into_iter())?;
436        self.set_variable(&full_name, leo_value);
437        Ok(())
438    }
439
440    pub fn set_program(&mut self, program: &str) {
441        let p = program.strip_suffix(".aleo").unwrap_or(program);
442        self.program = Some(Symbol::intern(p));
443    }
444
445    pub fn current_program(&self) -> Option<Symbol> {
446        self.contexts.current_program().or(self.program)
447    }
448
449    pub fn increment_step(&mut self) {
450        let Some(Frame { step, .. }) = self.frames.last_mut() else {
451            panic!("frame expected");
452        };
453        *step += 1;
454    }
455
456    fn new_caller(&self) -> Value {
457        if let Some(function_context) = self.contexts.last() {
458            let program_id = ProgramID::<TestnetV0>::from_str(&format!("{}.aleo", function_context.program))
459                .expect("should be able to create ProgramID");
460            program_id.to_address().expect("should be able to convert to address").into()
461        } else {
462            self.signer.clone()
463        }
464    }
465
466    fn pop_value(&mut self) -> Result<Value> {
467        match self.values.pop() {
468            Some(v) => Ok(v),
469            None => {
470                Err(InterpreterHalt::new("value expected - this may be a bug in the Leo interpreter".to_string())
471                    .into())
472            }
473        }
474    }
475
476    fn lookup(&self, name: &[Symbol]) -> Option<Value> {
477        if let Some(context) = self.contexts.last() {
478            let option_value = context
479                .names
480                .get(name)
481                .or_else(|| self.globals.get(&GlobalId { program: context.program, path: name.to_vec() }));
482            if option_value.is_some() {
483                return option_value.cloned();
484            }
485        };
486
487        self.user_values.get(name).cloned()
488    }
489
490    pub fn lookup_mapping(&self, program: Option<Symbol>, name: Symbol) -> Option<&HashMap<Value, Value>> {
491        let Some(program) = program.or_else(|| self.current_program()) else {
492            panic!("no program for mapping lookup");
493        };
494        // mappings can only show up in the top level program scope
495        self.mappings.get(&GlobalId { program, path: vec![name] })
496    }
497
498    pub fn lookup_mapping_mut(&mut self, program: Option<Symbol>, name: Symbol) -> Option<&mut HashMap<Value, Value>> {
499        let Some(program) = program.or_else(|| self.current_program()) else {
500            panic!("no program for mapping lookup");
501        };
502        // mappings can only show up in the top level program scope
503        self.mappings.get_mut(&GlobalId { program, path: vec![name] })
504    }
505
506    fn lookup_function(&self, program: Symbol, name: &[Symbol]) -> Option<FunctionVariant> {
507        self.functions.get(&GlobalId { program, path: name.to_vec() }).cloned()
508    }
509
510    fn set_variable(&mut self, path: &[Symbol], value: Value) {
511        if self.contexts.len() > 0 {
512            self.contexts.set(path, value);
513        } else {
514            self.user_values.insert(path.to_vec(), value);
515        }
516    }
517
518    /// Execute the whole step of the current Element.
519    ///
520    /// That is, perform a step, and then finish all statements and expressions that have been pushed,
521    /// until we're ready for the next step of the current Element (if there is one).
522    pub fn whole_step(&mut self) -> Result<StepResult> {
523        let frames_len = self.frames.len();
524        let initial_result = self.step()?;
525        if !initial_result.finished {
526            while self.frames.len() > frames_len {
527                self.step()?;
528            }
529        }
530        Ok(initial_result)
531    }
532
533    /// Step `over` the current Element.
534    ///
535    /// That is, continue executing until the current Element is finished.
536    pub fn over(&mut self) -> Result<StepResult> {
537        let frames_len = self.frames.len();
538        loop {
539            match self.frames.len().cmp(&frames_len) {
540                Ordering::Greater => {
541                    self.step()?;
542                }
543                Ordering::Equal => {
544                    let result = self.step()?;
545                    if result.finished {
546                        return Ok(result);
547                    }
548                }
549                Ordering::Less => {
550                    // This can happen if, for instance, a `return` was encountered,
551                    // which means we exited the function we were evaluating and the
552                    // frame stack was truncated.
553                    return Ok(StepResult { finished: true, value: None });
554                }
555            }
556        }
557    }
558
559    pub fn step_block(&mut self, block: &Block, function_body: bool, step: usize) -> bool {
560        let len = self.frames.len();
561
562        let done = match step {
563            0 => {
564                for statement in block.statements.iter().rev() {
565                    self.frames.push(Frame {
566                        element: Element::Statement(statement.clone()),
567                        step: 0,
568                        user_initiated: false,
569                    });
570                }
571                false
572            }
573            1 if function_body => {
574                self.values.push(Value::make_unit());
575                self.contexts.pop();
576                true
577            }
578            1 => true,
579            _ => unreachable!(),
580        };
581
582        if done {
583            assert_eq!(len, self.frames.len());
584            self.frames.pop();
585        } else {
586            self.frames[len - 1].step += 1;
587        }
588
589        done
590    }
591
592    /// Returns the full absolute path by prefixing `name` with the current module path.
593    /// If no context is available, returns `name` as-is.
594    fn to_absolute_path(&self, name: &[Symbol]) -> Vec<Symbol> {
595        if let Some(context) = self.contexts.last() {
596            let mut full_name = context.path.clone();
597            full_name.pop(); // This pops the function name, keeping only the module prefix 
598            full_name.extend(name);
599            full_name
600        } else {
601            name.to_vec()
602        }
603    }
604
605    fn step_statement(&mut self, statement: &Statement, step: usize) -> Result<bool> {
606        let len = self.frames.len();
607        // Push a new expression frame with an optional expected type for the expression
608        let mut push = |expression: &Expression, ty: &Option<Type>| {
609            self.frames.push(Frame {
610                element: Element::Expression(expression.clone(), ty.clone()),
611                step: 0,
612                user_initiated: false,
613            })
614        };
615
616        let done = match statement {
617            Statement::Assert(assert) if step == 0 => {
618                match &assert.variant {
619                    AssertVariant::Assert(x) => push(x, &Some(Type::Boolean)),
620                    AssertVariant::AssertEq(x, y) | AssertVariant::AssertNeq(x, y) => {
621                        push(y, &None);
622                        push(x, &None);
623                    }
624                };
625                false
626            }
627            Statement::Assert(assert) if step == 1 => {
628                match &assert.variant {
629                    AssertVariant::Assert(..) => {
630                        let value = self.pop_value()?;
631                        match value.try_into() {
632                            Ok(true) => {}
633                            Ok(false) => halt!(assert.span(), "assert failure"),
634                            _ => tc_fail!(),
635                        }
636                    }
637                    AssertVariant::AssertEq(..) => {
638                        let x = self.pop_value()?;
639                        let y = self.pop_value()?;
640                        if !x.eq(&y)? {
641                            halt!(assert.span(), "assert failure: {} != {}", y, x);
642                        }
643                    }
644
645                    AssertVariant::AssertNeq(..) => {
646                        let x = self.pop_value()?;
647                        let y = self.pop_value()?;
648                        if x.eq(&y)? {
649                            halt!(assert.span(), "assert failure: {} == {}", y, x);
650                        }
651                    }
652                };
653                true
654            }
655            Statement::Assign(assign) if step == 0 => {
656                // Step 0: push the expression frame and any array index expression frames.
657                push(&assign.value, &None);
658                let mut place = &assign.place;
659                loop {
660                    match place {
661                        leo_ast::Expression::ArrayAccess(access) => {
662                            push(&access.index, &None);
663                            place = &access.array;
664                        }
665                        leo_ast::Expression::Path(..) => break,
666                        leo_ast::Expression::MemberAccess(access) => {
667                            place = &access.inner;
668                        }
669                        leo_ast::Expression::TupleAccess(access) => {
670                            place = &access.tuple;
671                        }
672                        _ => panic!("Can't happen"),
673                    }
674                }
675                false
676            }
677            Statement::Assign(assign) if step == 1 => {
678                // Step 1: set the variable (or place).
679                let mut index_count = 0;
680                let mut place = &assign.place;
681                loop {
682                    match place {
683                        leo_ast::Expression::ArrayAccess(access) => {
684                            index_count += 1;
685                            place = &access.array;
686                        }
687                        leo_ast::Expression::Path(..) => break,
688                        leo_ast::Expression::MemberAccess(access) => {
689                            place = &access.inner;
690                        }
691                        leo_ast::Expression::TupleAccess(access) => {
692                            place = &access.tuple;
693                        }
694                        _ => panic!("Can't happen"),
695                    }
696                }
697
698                // Get the value.
699                let value = self.pop_value()?;
700                let len = self.values.len();
701
702                // Get the indices.
703                let indices: Vec<Value> = self.values.drain(len - index_count..len).collect();
704
705                self.assign(value, &assign.place, &mut indices.into_iter())?;
706
707                true
708            }
709            Statement::Block(block) => return Ok(self.step_block(block, false, step)),
710            Statement::Conditional(conditional) if step == 0 => {
711                push(&conditional.condition, &Some(Type::Boolean));
712                false
713            }
714            Statement::Conditional(conditional) if step == 1 => {
715                match self.pop_value()?.try_into() {
716                    Ok(true) => self.frames.push(Frame {
717                        step: 0,
718                        element: Element::Block { block: conditional.then.clone(), function_body: false },
719                        user_initiated: false,
720                    }),
721                    Ok(false) => {
722                        if let Some(otherwise) = conditional.otherwise.as_ref() {
723                            self.frames.push(Frame {
724                                step: 0,
725                                element: Element::Statement(Statement::clone(otherwise)),
726                                user_initiated: false,
727                            })
728                        }
729                    }
730                    _ => tc_fail!(),
731                };
732                false
733            }
734            Statement::Conditional(_) if step == 2 => true,
735            Statement::Const(const_) if step == 0 => {
736                push(&const_.value, &Some(const_.type_.clone()));
737                false
738            }
739            Statement::Const(const_) if step == 1 => {
740                let value = self.pop_value()?;
741                self.set_variable(&self.to_absolute_path(&[const_.place.name]), value);
742                true
743            }
744            Statement::Definition(definition) if step == 0 => {
745                push(&definition.value, &definition.type_);
746                false
747            }
748            Statement::Definition(definition) if step == 1 => {
749                let value = self.pop_value()?;
750                match &definition.place {
751                    DefinitionPlace::Single(id) => self.set_variable(&self.to_absolute_path(&[id.name]), value),
752                    DefinitionPlace::Multiple(ids) => {
753                        for (i, id) in ids.iter().enumerate() {
754                            self.set_variable(
755                                &self.to_absolute_path(&[id.name]),
756                                value.tuple_index(i).expect("Place for definition should be a tuple."),
757                            );
758                        }
759                    }
760                }
761                true
762            }
763            Statement::Expression(expression) if step == 0 => {
764                push(&expression.expression, &None);
765                false
766            }
767            Statement::Expression(_) if step == 1 => {
768                self.values.pop();
769                true
770            }
771            Statement::Iteration(iteration) if step == 0 => {
772                assert!(!iteration.inclusive);
773                push(&iteration.stop, &iteration.type_.clone());
774                push(&iteration.start, &iteration.type_.clone());
775                false
776            }
777            Statement::Iteration(iteration) => {
778                // Currently there actually isn't a syntax in Leo for inclusive ranges.
779                let stop = self.pop_value()?;
780                let start = self.pop_value()?;
781                if start.eq(&stop)? {
782                    true
783                } else {
784                    let new_start = start.inc_wrapping().expect_tc(iteration.span())?;
785                    self.set_variable(&self.to_absolute_path(&[iteration.variable.name]), start);
786                    self.frames.push(Frame {
787                        step: 0,
788                        element: Element::Block { block: iteration.block.clone(), function_body: false },
789                        user_initiated: false,
790                    });
791                    self.values.push(new_start);
792                    self.values.push(stop);
793                    false
794                }
795            }
796            Statement::Return(return_) if step == 0 => {
797                // We really only need to care about the type of the output for Leo functions. Aleo functions and
798                // closures don't have to worry about unsuffixed literals
799                let output_type = self.contexts.last().and_then(|ctx| {
800                    self.lookup_function(ctx.program, &ctx.path).and_then(|variant| match variant {
801                        FunctionVariant::Leo(function) => Some(function.output_type.clone()),
802                        _ => None,
803                    })
804                });
805
806                self.frames.push(Frame {
807                    element: Element::Expression(return_.expression.clone(), output_type),
808                    step: 0,
809                    user_initiated: false,
810                });
811
812                false
813            }
814            Statement::Return(_) if step == 1 => loop {
815                let last_frame = self.frames.last().expect("a frame should be present");
816                match last_frame.element {
817                    Element::Expression(Expression::Call(_), _) | Element::DelayedCall(_) => {
818                        if self.contexts.is_async() {
819                            // Get rid of the Unit we previously pushed, and replace it with a Future.
820                            self.values.pop();
821                            self.values.push(self.contexts.get_future().into());
822                        }
823                        self.contexts.pop();
824                        return Ok(true);
825                    }
826                    _ => {
827                        self.frames.pop();
828                    }
829                }
830            },
831            _ => unreachable!(),
832        };
833
834        if done {
835            assert_eq!(len, self.frames.len());
836            self.frames.pop();
837        } else {
838            self.frames[len - 1].step += 1;
839        }
840
841        Ok(done)
842    }
843
844    fn step_expression(&mut self, expression: &Expression, expected_ty: &Option<Type>, step: usize) -> Result<bool> {
845        let len = self.frames.len();
846
847        macro_rules! push {
848            () => {
849                |expression: &Expression, expected_ty: &Option<Type>| {
850                    self.frames.push(Frame {
851                        element: Element::Expression(expression.clone(), expected_ty.clone()),
852                        step: 0,
853                        user_initiated: false,
854                    })
855                }
856            };
857        }
858
859        if let Some(value) = match expression {
860            Expression::ArrayAccess(array) if step == 0 => {
861                push!()(&array.index, &None);
862                push!()(&array.array, &None);
863                None
864            }
865            Expression::ArrayAccess(array_expr) if step == 1 => {
866                let span = array_expr.span();
867                let index = self.pop_value()?;
868                let array = self.pop_value()?;
869
870                // Local helper function to convert a Value into usize
871                fn to_usize(value: &Value, span: Span) -> Result<usize> {
872                    let value = value.resolve_if_unsuffixed(&Some(Type::Integer(leo_ast::IntegerType::U32)), span)?;
873                    Ok(value.as_u32().expect_tc(span)? as usize)
874                }
875
876                let index_usize = to_usize(&index, span)?;
877
878                Some(array.array_index(index_usize).expect_tc(span)?)
879            }
880
881            Expression::Async(AsyncExpression { block, .. }) if step == 0 => {
882                // Keep track of the async block, but nothing else to do at this point
883                self.async_blocks.insert(block.id, block.clone());
884                None
885            }
886            Expression::Async(AsyncExpression { block, .. }) if step == 1 => {
887                // Keep track of this block as a `Future` containing an `AsyncExecution` but nothing else to do here.
888                // The block actually executes when an `await` is called on its future.
889                if let Some(context) = self.contexts.last() {
890                    let async_ex = AsyncExecution::AsyncBlock {
891                        containing_function: GlobalId { program: context.program, path: context.path.clone() },
892                        block: block.id,
893                        names: context.names.clone().into_iter().collect(),
894                    };
895                    self.values.push(vec![async_ex].into());
896                }
897                None
898            }
899            Expression::Async(_) if step == 2 => Some(self.pop_value()?),
900
901            Expression::MemberAccess(access) => match &access.inner {
902                Expression::Path(path) if *path.as_symbols() == vec![sym::SelfLower] => match access.name.name {
903                    sym::signer => Some(self.signer.clone()),
904                    sym::caller => {
905                        if let Some(function_context) = self.contexts.last() {
906                            Some(function_context.caller.clone())
907                        } else {
908                            Some(self.signer.clone())
909                        }
910                    }
911                    _ => halt!(access.span(), "unknown member of self"),
912                },
913                Expression::Path(path) if *path.as_symbols() == vec![sym::block] => match access.name.name {
914                    sym::height => Some(self.block_height.into()),
915                    _ => halt!(access.span(), "unknown member of block"),
916                },
917
918                // Otherwise, we just have a normal struct member access.
919                _ if step == 0 => {
920                    push!()(&access.inner, &None);
921                    None
922                }
923                _ if step == 1 => {
924                    let struct_ = self.values.pop().expect_tc(access.span())?;
925                    let value = struct_.member_access(access.name.name).expect_tc(access.span())?;
926                    Some(value)
927                }
928                _ => unreachable!("we've actually covered all possible patterns above"),
929            },
930            Expression::TupleAccess(tuple_access) if step == 0 => {
931                push!()(&tuple_access.tuple, &None);
932                None
933            }
934            Expression::TupleAccess(tuple_access) if step == 1 => {
935                let Some(value) = self.values.pop() else { tc_fail!() };
936                if let Some(result) = value.tuple_index(tuple_access.index.value()) {
937                    Some(result)
938                } else {
939                    halt!(tuple_access.span(), "Tuple index out of range");
940                }
941            }
942            Expression::Array(array) if step == 0 => {
943                let element_type = expected_ty.clone().and_then(|ty| match ty {
944                    Type::Array(ArrayType { element_type, .. }) => Some(*element_type),
945                    _ => None,
946                });
947
948                array.elements.iter().rev().for_each(|array| push!()(array, &element_type));
949                None
950            }
951            Expression::Array(array) if step == 1 => {
952                let len = self.values.len();
953                let array_values = self.values.drain(len - array.elements.len()..);
954                Some(Value::make_array(array_values))
955            }
956            Expression::Repeat(repeat) if step == 0 => {
957                let element_type = expected_ty.clone().and_then(|ty| match ty {
958                    Type::Array(ArrayType { element_type, .. }) => Some(*element_type),
959                    _ => None,
960                });
961
962                push!()(&repeat.count, &None);
963                push!()(&repeat.expr, &element_type);
964                None
965            }
966            Expression::Repeat(repeat) if step == 1 => {
967                let count = self.pop_value()?;
968                let expr = self.pop_value()?;
969                let count_resolved = count
970                    .resolve_if_unsuffixed(&Some(Type::Integer(leo_ast::IntegerType::U32)), repeat.count.span())?;
971                Some(Value::make_array(std::iter::repeat_n(
972                    expr,
973                    count_resolved.as_u32().expect_tc(repeat.span())? as usize,
974                )))
975            }
976            Expression::AssociatedConstant(constant) if step == 0 => {
977                let Type::Identifier(type_ident) = constant.ty else {
978                    tc_fail!();
979                };
980                let Some(core_constant) = CoreConstant::from_symbols(type_ident.name, constant.name.name) else {
981                    halt!(constant.span(), "Unknown constant {constant}");
982                };
983                match core_constant {
984                    CoreConstant::GroupGenerator => Some(Value::generator()),
985                }
986            }
987            Expression::AssociatedFunction(function) if step == 0 => {
988                let Some(core_function) = CoreFunction::from_symbols(function.variant.name, function.name.name) else {
989                    halt!(function.span(), "Unkown core function {function}");
990                };
991
992                // We want to push expressions for each of the arguments... except for mappings,
993                // because we don't look them up as Values.
994                match core_function {
995                    CoreFunction::MappingGet | CoreFunction::MappingRemove | CoreFunction::MappingContains => {
996                        push!()(&function.arguments[1], &None);
997                    }
998                    CoreFunction::MappingGetOrUse | CoreFunction::MappingSet => {
999                        push!()(&function.arguments[2], &None);
1000                        push!()(&function.arguments[1], &None);
1001                    }
1002                    CoreFunction::CheatCodePrintMapping => {
1003                        // Do nothing, as we don't need to evaluate the mapping.
1004                    }
1005                    _ => function.arguments.iter().rev().for_each(|arg| push!()(arg, &None)),
1006                }
1007                None
1008            }
1009            Expression::AssociatedFunction(function) if step == 1 => {
1010                let Some(core_function) = CoreFunction::from_symbols(function.variant.name, function.name.name) else {
1011                    halt!(function.span(), "Unkown core function {function}");
1012                };
1013
1014                let span = function.span();
1015
1016                if let CoreFunction::FutureAwait = core_function {
1017                    let value = self.pop_value()?;
1018                    let Some(asyncs) = value.as_future() else {
1019                        halt!(span, "Invalid value for await: {value}");
1020                    };
1021                    for async_execution in asyncs {
1022                        match async_execution {
1023                            AsyncExecution::AsyncFunctionCall { function, arguments } => {
1024                                self.values.extend(arguments.iter().cloned());
1025                                self.frames.push(Frame {
1026                                    step: 0,
1027                                    element: Element::DelayedCall(function.clone()),
1028                                    user_initiated: false,
1029                                });
1030                            }
1031                            AsyncExecution::AsyncBlock { containing_function, block, names, .. } => {
1032                                self.frames.push(Frame {
1033                                    step: 0,
1034                                    element: Element::DelayedAsyncBlock {
1035                                        program: containing_function.program,
1036                                        block: *block,
1037                                        // Keep track of all the known variables up to this point.
1038                                        // These are available to use inside the block when we actually execute it.
1039                                        names: names.clone().into_iter().collect(),
1040                                    },
1041                                    user_initiated: false,
1042                                });
1043                            }
1044                        }
1045                    }
1046                    // For an await, we have one extra step - first we must evaluate the delayed call.
1047                    None
1048                } else {
1049                    let value = evaluate_core_function(self, core_function.clone(), &function.arguments, span)?;
1050                    assert!(value.is_some());
1051                    value
1052                }
1053            }
1054            Expression::AssociatedFunction(function) if step == 2 => {
1055                let Some(core_function) = CoreFunction::from_symbols(function.variant.name, function.name.name) else {
1056                    halt!(function.span(), "Unkown core function {function}");
1057                };
1058                assert!(core_function == CoreFunction::FutureAwait);
1059                Some(Value::make_unit())
1060            }
1061            Expression::Binary(binary) if step == 0 => {
1062                use BinaryOperation::*;
1063
1064                // Determine the expected types for the right and left operands based on the operation
1065                let (right_ty, left_ty) = match binary.op {
1066                    // Multiplications that return a `Group` can take `Scalar * Group` or `Group * Scalar`.
1067                    // No way to know at this stage.
1068                    Mul if matches!(expected_ty, Some(Type::Group)) => (None, None),
1069
1070                    // Boolean operations don't require expected type propagation
1071                    And | Or | Nand | Nor | Eq | Neq | Lt | Gt | Lte | Gte => (None, None),
1072
1073                    // Exponentiation (Pow) may require specific typing if expected to be a Field
1074                    Pow => {
1075                        let right_ty = if matches!(expected_ty, Some(Type::Field)) {
1076                            Some(Type::Field) // Enforce Field type on exponent if expected
1077                        } else {
1078                            None // Otherwise, don't constrain the exponent
1079                        };
1080                        (right_ty, expected_ty.clone()) // Pass the expected type to the base
1081                    }
1082
1083                    // Bitwise shifts and wrapped exponentiation:
1084                    // Typically only the left operand should conform to the expected type
1085                    Shl | ShlWrapped | Shr | ShrWrapped | PowWrapped => (None, expected_ty.clone()),
1086
1087                    // Default case: propagate expected type to both operands
1088                    _ => (expected_ty.clone(), expected_ty.clone()),
1089                };
1090
1091                // Push operands onto the stack for evaluation in right-to-left order
1092                push!()(&binary.right, &right_ty);
1093                push!()(&binary.left, &left_ty);
1094
1095                None
1096            }
1097            Expression::Binary(binary) if step == 1 => {
1098                let rhs = self.pop_value()?;
1099                let lhs = self.pop_value()?;
1100                Some(evaluate_binary(binary.span, binary.op, &lhs, &rhs, expected_ty)?)
1101            }
1102
1103            Expression::Call(call) if step == 0 => {
1104                // Resolve the function's program and name
1105                let (function_program, function_path) = {
1106                    let maybe_program = call.program.or_else(|| self.current_program());
1107                    if let Some(program) = maybe_program {
1108                        (program, self.to_absolute_path(&call.function.as_symbols()))
1109                    } else {
1110                        halt!(call.span, "No current program");
1111                    }
1112                };
1113
1114                // Look up the function variant (Leo, AleoClosure, or AleoFunction)
1115                let Some(function_variant) = self.lookup_function(function_program, &function_path) else {
1116                    halt!(call.span, "unknown function {function_program}.aleo/{}", function_path.iter().format("::"));
1117                };
1118
1119                // Extract const parameter and input types based on the function variant
1120                let (const_param_types, input_types) = match function_variant {
1121                    FunctionVariant::Leo(function) => (
1122                        function.const_parameters.iter().map(|p| p.type_.clone()).collect::<Vec<_>>(),
1123                        function.input.iter().map(|p| p.type_.clone()).collect::<Vec<_>>(),
1124                    ),
1125                    FunctionVariant::AleoClosure(closure) => {
1126                        let function = leo_ast::FunctionStub::from_closure(&closure, function_program);
1127                        (vec![], function.input.iter().map(|p| p.type_.clone()).collect::<Vec<_>>())
1128                    }
1129                    FunctionVariant::AleoFunction(svm_function) => {
1130                        let function = leo_ast::FunctionStub::from_function_core(&svm_function, function_program);
1131                        (vec![], function.input.iter().map(|p| p.type_.clone()).collect::<Vec<_>>())
1132                    }
1133                };
1134
1135                // Push arguments (in reverse order) with corresponding input types
1136                call.arguments
1137                    .iter()
1138                    .rev()
1139                    .zip(input_types.iter().rev())
1140                    .for_each(|(arg, ty)| push!()(arg, &Some(ty.clone())));
1141
1142                // Push const arguments (in reverse order) with corresponding const param types
1143                call.const_arguments
1144                    .iter()
1145                    .rev()
1146                    .zip(const_param_types.iter().rev())
1147                    .for_each(|(arg, ty)| push!()(arg, &Some(ty.clone())));
1148
1149                None
1150            }
1151
1152            Expression::Call(call) if step == 1 => {
1153                let len = self.values.len();
1154                let (program, path) = {
1155                    let maybe_program = call.program.or_else(|| self.current_program());
1156                    if let Some(program) = maybe_program {
1157                        (program, call.function.as_symbols())
1158                    } else {
1159                        halt!(call.span, "No current program");
1160                    }
1161                };
1162                // It's a bit cheesy to collect the arguments into a Vec first, but it's the easiest way
1163                // to handle lifetimes here.
1164                let arguments: Vec<Value> =
1165                    self.values.drain(len - call.arguments.len() - call.const_arguments.len()..).collect();
1166                self.do_call(
1167                    program,
1168                    &self.to_absolute_path(&path),
1169                    arguments.into_iter(),
1170                    false, // finalize
1171                    call.span(),
1172                )?;
1173                None
1174            }
1175            Expression::Call(_call) if step == 2 => Some(self.pop_value()?),
1176            Expression::Cast(cast) if step == 0 => {
1177                push!()(&cast.expression, &None);
1178                None
1179            }
1180            Expression::Cast(cast) if step == 1 => {
1181                let span = cast.span();
1182                let arg = self.pop_value()?;
1183                match arg.cast(&cast.type_) {
1184                    Some(value) => Some(value),
1185                    None => return Err(InterpreterHalt::new_spanned("cast failure".to_string(), span).into()),
1186                }
1187            }
1188            Expression::Err(_) => todo!(),
1189            Expression::Path(path) if step == 0 => {
1190                Some(self.lookup(&self.to_absolute_path(&path.as_symbols())).expect_tc(path.span())?)
1191            }
1192            Expression::Literal(literal) if step == 0 => Some(literal_to_value(literal, expected_ty)?),
1193            Expression::Locator(_locator) => todo!(),
1194            Expression::Struct(struct_) if step == 0 => {
1195                let members =
1196                    self.structs.get(&self.to_absolute_path(&struct_.path.as_symbols())).expect_tc(struct_.span())?;
1197                for StructVariableInitializer { identifier: field_init_name, expression: init, .. } in &struct_.members
1198                {
1199                    let Some(type_) = members.get(&field_init_name.name) else { tc_fail!() };
1200                    push!()(
1201                        init.as_ref().unwrap_or(&Expression::Path(Path::from(*field_init_name))),
1202                        &Some(type_.clone()),
1203                    )
1204                }
1205
1206                None
1207            }
1208            Expression::Struct(struct_) if step == 1 => {
1209                // Collect all the key/value pairs into a HashMap.
1210                let mut contents_tmp = HashMap::with_capacity(struct_.members.len());
1211                for initializer in struct_.members.iter() {
1212                    let name = initializer.identifier.name;
1213                    let value = self.pop_value()?;
1214                    contents_tmp.insert(name, value);
1215                }
1216
1217                // And now put them into an IndexMap in the correct order.
1218                let members =
1219                    self.structs.get(&self.to_absolute_path(&struct_.path.as_symbols())).expect_tc(struct_.span())?;
1220                let contents = members.iter().map(|(identifier, _)| {
1221                    (*identifier, contents_tmp.remove(identifier).expect("we just inserted this"))
1222                });
1223
1224                // TODO: this only works for structs defined in the top level module.. must figure
1225                // something out for structs defined in modules
1226                Some(Value::make_struct(contents, self.current_program().unwrap(), struct_.path.as_symbols()))
1227            }
1228            Expression::Ternary(ternary) if step == 0 => {
1229                push!()(&ternary.condition, &None);
1230                None
1231            }
1232            Expression::Ternary(ternary) if step == 1 => {
1233                let condition = self.pop_value()?;
1234                match condition.try_into() {
1235                    Ok(true) => push!()(&ternary.if_true, &None),
1236                    Ok(false) => push!()(&ternary.if_false, &None),
1237                    _ => halt!(ternary.span(), "Invalid type for ternary expression {ternary}"),
1238                }
1239                None
1240            }
1241            Expression::Ternary(_) if step == 2 => Some(self.pop_value()?),
1242            Expression::Tuple(tuple) if step == 0 => {
1243                tuple.elements.iter().rev().for_each(|t| push!()(t, &None));
1244                None
1245            }
1246            Expression::Tuple(tuple) if step == 1 => {
1247                let len = self.values.len();
1248                let tuple_values = self.values.drain(len - tuple.elements.len()..);
1249                Some(Value::make_tuple(tuple_values))
1250            }
1251            Expression::Unary(unary) if step == 0 => {
1252                use UnaryOperation::*;
1253
1254                // Determine the expected type based on the unary operation
1255                let ty = match unary.op {
1256                    Inverse | Square | SquareRoot => Some(Type::Field), // These ops require Field operands
1257                    ToXCoordinate | ToYCoordinate => Some(Type::Group), // These ops apply to Group elements
1258                    _ => expected_ty.clone(),                           // Fallback to the externally expected type
1259                };
1260
1261                // Push the receiver expression with the computed type
1262                push!()(&unary.receiver, &ty);
1263
1264                None
1265            }
1266            Expression::Unary(unary) if step == 1 => {
1267                let value = self.pop_value()?;
1268                Some(evaluate_unary(unary.span, unary.op, &value, expected_ty)?)
1269            }
1270            Expression::Unit(_) if step == 0 => Some(Value::make_unit()),
1271            x => unreachable!("Unexpected expression {x}"),
1272        } {
1273            assert_eq!(self.frames.len(), len);
1274            self.frames.pop();
1275            self.values.push(value);
1276            Ok(true)
1277        } else {
1278            self.frames[len - 1].step += 1;
1279            Ok(false)
1280        }
1281    }
1282
1283    /// Execute one step of the current element.
1284    ///
1285    /// Many Leo constructs require multiple steps. For instance, when executing a conditional,
1286    /// the first step will push the condition expression to the stack. Once that has executed
1287    /// and we've returned to the conditional, we push the `then` or `otherwise` block to the
1288    /// stack. Once that has executed and we've returned to the conditional, the final step
1289    /// does nothing.
1290    pub fn step(&mut self) -> Result<StepResult> {
1291        if self.frames.is_empty() {
1292            return Err(InterpreterHalt::new("no execution frames available".into()).into());
1293        }
1294
1295        let Frame { element, step, user_initiated } = self.frames.last().expect("there should be a frame").clone();
1296        match element {
1297            Element::Block { block, function_body } => {
1298                let finished = self.step_block(&block, function_body, step);
1299                Ok(StepResult { finished, value: None })
1300            }
1301            Element::Statement(statement) => {
1302                let finished = self.step_statement(&statement, step)?;
1303                Ok(StepResult { finished, value: None })
1304            }
1305            Element::Expression(expression, expected_ty) => {
1306                let finished = self.step_expression(&expression, &expected_ty, step)?;
1307                let value = match (finished, user_initiated) {
1308                    (false, _) => None,
1309                    (true, false) => self.values.last().cloned(),
1310                    (true, true) => self.values.pop(),
1311                };
1312
1313                let maybe_future = if let Some(len) = value.as_ref().and_then(|val| val.tuple_len()) {
1314                    value.as_ref().unwrap().tuple_index(len - 1)
1315                } else {
1316                    value.clone()
1317                };
1318
1319                if let Some(asyncs) = maybe_future.as_ref().and_then(|fut| fut.as_future()) {
1320                    self.futures.extend(asyncs.iter().cloned());
1321                }
1322
1323                Ok(StepResult { finished, value })
1324            }
1325            Element::AleoExecution { .. } => {
1326                self.step_aleo()?;
1327                Ok(StepResult { finished: true, value: None })
1328            }
1329            Element::DelayedCall(gid) if step == 0 => {
1330                match self.lookup_function(gid.program, &gid.path).expect("function should exist") {
1331                    FunctionVariant::Leo(function) => {
1332                        assert!(function.variant == Variant::AsyncFunction);
1333                        let len = self.values.len();
1334                        let values: Vec<Value> = self.values.drain(len - function.input.len()..).collect();
1335                        self.contexts.push(
1336                            &gid.path,
1337                            gid.program,
1338                            self.signer.clone(),
1339                            true, // is_async
1340                            HashMap::new(),
1341                        );
1342                        let param_names = function.input.iter().map(|input| input.identifier.name);
1343                        for (name, value) in param_names.zip(values) {
1344                            self.set_variable(&self.to_absolute_path(&[name]), value);
1345                        }
1346                        self.frames.last_mut().unwrap().step = 1;
1347                        self.frames.push(Frame {
1348                            step: 0,
1349                            element: Element::Block { block: function.block.clone(), function_body: true },
1350                            user_initiated: false,
1351                        });
1352                        Ok(StepResult { finished: false, value: None })
1353                    }
1354                    FunctionVariant::AleoFunction(function) => {
1355                        let Some(finalize_f) = function.finalize_logic() else {
1356                            panic!("must have finalize logic for a delayed call");
1357                        };
1358                        let len = self.values.len();
1359                        let values_iter = self.values.drain(len - finalize_f.inputs().len()..);
1360                        self.contexts.push(
1361                            &gid.path,
1362                            gid.program,
1363                            self.signer.clone(),
1364                            true, // is_async
1365                            HashMap::new(),
1366                        );
1367                        self.frames.last_mut().unwrap().step = 1;
1368                        self.frames.push(Frame {
1369                            step: 0,
1370                            element: Element::AleoExecution {
1371                                context: AleoContext::Finalize(finalize_f.clone()).into(),
1372                                registers: values_iter.enumerate().map(|(i, v)| (i as u64, v)).collect(),
1373                                instruction_index: 0,
1374                            },
1375                            user_initiated: false,
1376                        });
1377                        Ok(StepResult { finished: false, value: None })
1378                    }
1379                    FunctionVariant::AleoClosure(..) => panic!("A call to a closure can't be delayed"),
1380                }
1381            }
1382            Element::DelayedCall(_gid) => {
1383                assert_eq!(step, 1);
1384                let value = self.values.pop();
1385                self.frames.pop();
1386                Ok(StepResult { finished: true, value })
1387            }
1388            Element::DelayedAsyncBlock { program, block, names } if step == 0 => {
1389                self.contexts.push(
1390                    &[Symbol::intern("")],
1391                    program,
1392                    self.signer.clone(),
1393                    true,
1394                    names.clone().into_iter().collect(), // Set the known names to the previously preserved `names`.
1395                );
1396                self.frames.last_mut().unwrap().step = 1;
1397                self.frames.push(Frame {
1398                    step: 0,
1399                    element: Element::Block {
1400                        block: self.async_blocks.get(&block).unwrap().clone(),
1401                        function_body: true,
1402                    },
1403                    user_initiated: false,
1404                });
1405                Ok(StepResult { finished: false, value: None })
1406            }
1407            Element::DelayedAsyncBlock { .. } => {
1408                assert_eq!(step, 1);
1409                let value = self.values.pop();
1410                self.frames.pop();
1411                Ok(StepResult { finished: true, value })
1412            }
1413        }
1414    }
1415
1416    pub fn do_call(
1417        &mut self,
1418        function_program: Symbol,
1419        function_path: &[Symbol],
1420        arguments: impl Iterator<Item = Value>,
1421        finalize: bool,
1422        span: Span,
1423    ) -> Result<()> {
1424        let Some(function_variant) = self.lookup_function(function_program, function_path) else {
1425            halt!(span, "unknown function {function_program}.aleo/{}", function_path.iter().format("::"));
1426        };
1427        match function_variant {
1428            FunctionVariant::Leo(function) => {
1429                let caller = if matches!(function.variant, Variant::Transition | Variant::AsyncTransition) {
1430                    self.new_caller()
1431                } else {
1432                    self.signer.clone()
1433                };
1434                if self.really_async && function.variant == Variant::AsyncFunction {
1435                    // Don't actually run the call now.
1436                    let async_ex = AsyncExecution::AsyncFunctionCall {
1437                        function: GlobalId { path: function_path.to_vec(), program: function_program },
1438                        arguments: arguments.collect(),
1439                    };
1440                    self.values.push(vec![async_ex].into());
1441                } else {
1442                    let is_async = function.variant == Variant::AsyncFunction;
1443                    self.contexts.push(function_path, function_program, caller, is_async, HashMap::new());
1444                    // Treat const generic parameters as regular inputs
1445                    let param_names = function
1446                        .const_parameters
1447                        .iter()
1448                        .map(|param| param.identifier.name)
1449                        .chain(function.input.iter().map(|input| input.identifier.name));
1450                    for (name, value) in param_names.zip(arguments) {
1451                        self.set_variable(&self.to_absolute_path(&[name]), value);
1452                    }
1453                    self.frames.push(Frame {
1454                        step: 0,
1455                        element: Element::Block { block: function.block.clone(), function_body: true },
1456                        user_initiated: false,
1457                    });
1458                }
1459            }
1460            FunctionVariant::AleoClosure(closure) => {
1461                self.contexts.push(function_path, function_program, self.signer.clone(), false, HashMap::new());
1462                let context = AleoContext::Closure(closure);
1463                self.frames.push(Frame {
1464                    step: 0,
1465                    element: Element::AleoExecution {
1466                        context: context.into(),
1467                        registers: arguments.enumerate().map(|(i, v)| (i as u64, v)).collect(),
1468                        instruction_index: 0,
1469                    },
1470                    user_initiated: false,
1471                });
1472            }
1473            FunctionVariant::AleoFunction(function) => {
1474                let caller = self.new_caller();
1475                self.contexts.push(function_path, function_program, caller, false, HashMap::new());
1476                let context = if finalize {
1477                    let Some(finalize_f) = function.finalize_logic() else {
1478                        panic!("finalize call with no finalize logic");
1479                    };
1480                    AleoContext::Finalize(finalize_f.clone())
1481                } else {
1482                    AleoContext::Function(function)
1483                };
1484                self.frames.push(Frame {
1485                    step: 0,
1486                    element: Element::AleoExecution {
1487                        context: context.into(),
1488                        registers: arguments.enumerate().map(|(i, v)| (i as u64, v)).collect(),
1489                        instruction_index: 0,
1490                    },
1491                    user_initiated: false,
1492                });
1493            }
1494        }
1495
1496        Ok(())
1497    }
1498}
1499
1500#[derive(Clone, Debug)]
1501pub struct StepResult {
1502    /// Has this element completely finished running?
1503    pub finished: bool,
1504
1505    /// If the element was an expression, here's its value.
1506    pub value: Option<Value>,
1507}