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    AssertVariant,
21    BinaryOperation,
22    Block,
23    CoreConstant,
24    CoreFunction,
25    DefinitionPlace,
26    Expression,
27    FromStrRadix as _,
28    Function,
29    IntegerType,
30    Literal,
31    LiteralVariant,
32    Statement,
33    Type,
34    UnaryOperation,
35    Variant,
36};
37use leo_errors::{InterpreterHalt, Result};
38use leo_span::{Span, Symbol, sym};
39
40use snarkvm::prelude::{
41    Closure as SvmClosure,
42    Double as _,
43    Finalize as SvmFinalize,
44    Function as SvmFunctionParam,
45    Inverse as _,
46    Pow as _,
47    ProgramID,
48    Square as _,
49    SquareRoot as _,
50    TestnetV0,
51};
52
53use indexmap::{IndexMap, IndexSet};
54use rand_chacha::{ChaCha20Rng, rand_core::SeedableRng};
55use std::{cmp::Ordering, collections::HashMap, fmt, mem, str::FromStr as _};
56
57pub type Closure = SvmClosure<TestnetV0>;
58pub type Finalize = SvmFinalize<TestnetV0>;
59pub type SvmFunction = SvmFunctionParam<TestnetV0>;
60
61/// Names associated to values in a function being executed.
62#[derive(Clone, Debug)]
63pub struct FunctionContext {
64    program: Symbol,
65    pub caller: SvmAddress,
66    names: HashMap<Symbol, Value>,
67    accumulated_futures: Future,
68    is_async: bool,
69}
70
71/// A stack of contexts, building with the function call stack.
72#[derive(Clone, Debug, Default)]
73pub struct ContextStack {
74    contexts: Vec<FunctionContext>,
75    current_len: usize,
76}
77
78impl ContextStack {
79    fn len(&self) -> usize {
80        self.current_len
81    }
82
83    fn push(&mut self, program: Symbol, caller: SvmAddress, is_async: bool) {
84        if self.current_len == self.contexts.len() {
85            self.contexts.push(FunctionContext {
86                program,
87                caller,
88                names: HashMap::new(),
89                accumulated_futures: Default::default(),
90                is_async,
91            });
92        }
93        self.contexts[self.current_len].accumulated_futures.0.clear();
94        self.contexts[self.current_len].names.clear();
95        self.contexts[self.current_len].caller = caller;
96        self.contexts[self.current_len].program = program;
97        self.contexts[self.current_len].is_async = is_async;
98        self.current_len += 1;
99    }
100
101    pub fn pop(&mut self) {
102        // We never actually pop the underlying Vec
103        // so we can reuse the storage of the hash
104        // tables.
105        assert!(self.len() > 0);
106        self.current_len -= 1;
107        self.contexts[self.current_len].names.clear();
108    }
109
110    /// Get the future accumulated by awaiting futures in the current function call.
111    ///
112    /// If the current code being interpreted is not in an async function, this
113    /// will of course be empty.
114    fn get_future(&mut self) -> Future {
115        assert!(self.len() > 0);
116        mem::take(&mut self.contexts[self.current_len - 1].accumulated_futures)
117    }
118
119    fn set(&mut self, symbol: Symbol, value: Value) {
120        assert!(self.current_len > 0);
121        self.last_mut().unwrap().names.insert(symbol, value);
122    }
123
124    pub fn add_future(&mut self, future: Future) {
125        assert!(self.current_len > 0);
126        self.contexts[self.current_len - 1].accumulated_futures.0.extend(future.0);
127    }
128
129    /// Are we currently in an async function?
130    fn is_async(&self) -> bool {
131        assert!(self.current_len > 0);
132        self.last().unwrap().is_async
133    }
134
135    pub fn current_program(&self) -> Option<Symbol> {
136        self.last().map(|c| c.program)
137    }
138
139    pub fn last(&self) -> Option<&FunctionContext> {
140        self.len().checked_sub(1).and_then(|i| self.contexts.get(i))
141    }
142
143    fn last_mut(&mut self) -> Option<&mut FunctionContext> {
144        self.len().checked_sub(1).and_then(|i| self.contexts.get_mut(i))
145    }
146}
147
148#[derive(Clone, Debug)]
149pub enum AleoContext {
150    Closure(Closure),
151    Function(SvmFunction),
152    Finalize(Finalize),
153}
154
155/// A Leo construct to be evauated.
156#[derive(Clone, Debug)]
157pub enum Element {
158    /// A Leo statement.
159    Statement(Statement),
160
161    /// A Leo expression.
162    Expression(Expression),
163
164    /// A Leo block.
165    ///
166    /// We have a separate variant for Leo blocks for two reasons:
167    /// 1. In a ConditionalExpression, the `then` block is stored
168    ///    as just a Block with no statement, and
169    /// 2. We need to remember if a Block came from a function body,
170    ///    so that if such a block ends, we know to push a `Unit` to
171    ///    the values stack.
172    Block {
173        block: Block,
174        function_body: bool,
175    },
176
177    AleoExecution {
178        context: Box<AleoContext>,
179        registers: IndexMap<u64, Value>,
180        instruction_index: usize,
181    },
182
183    DelayedCall(GlobalId),
184}
185
186impl Element {
187    pub fn span(&self) -> Span {
188        use Element::*;
189        match self {
190            Statement(statement) => statement.span(),
191            Expression(expression) => expression.span(),
192            Block { block, .. } => block.span(),
193            AleoExecution { .. } | DelayedCall(..) => Default::default(),
194        }
195    }
196}
197
198/// A frame of execution, keeping track of the Element next to
199/// be executed and the number of steps we've done so far.
200#[derive(Clone, Debug)]
201pub struct Frame {
202    pub step: usize,
203    pub element: Element,
204    pub user_initiated: bool,
205}
206
207/// Global values - such as mappings, functions, etc -
208/// are identified by program and name.
209#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
210pub struct GlobalId {
211    pub program: Symbol,
212    pub name: Symbol,
213}
214
215impl fmt::Display for GlobalId {
216    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217        write!(f, "{}.aleo/{}", self.program, self.name)
218    }
219}
220
221#[derive(Clone, Debug)]
222pub enum FunctionVariant {
223    Leo(Function),
224    AleoClosure(Closure),
225    AleoFunction(SvmFunction),
226}
227
228/// Tracks the current execution state - a cursor into the running program.
229#[derive(Clone, Debug)]
230pub struct Cursor {
231    /// Stack of execution frames, with the one currently to be executed on top.
232    pub frames: Vec<Frame>,
233
234    /// Stack of values from evaluated expressions.
235    ///
236    /// Each time an expression completes evaluation, a value is pushed here.
237    pub values: Vec<Value>,
238
239    /// All functions (or transitions or inlines) in any program being interpreted.
240    pub functions: HashMap<GlobalId, FunctionVariant>,
241
242    /// Consts are stored here.
243    pub globals: HashMap<GlobalId, Value>,
244
245    pub user_values: HashMap<Symbol, Value>,
246
247    pub mappings: HashMap<GlobalId, HashMap<Value, Value>>,
248
249    /// For each struct type, we only need to remember the names of its members, in order.
250    pub structs: HashMap<GlobalId, IndexSet<Symbol>>,
251
252    pub futures: Vec<Future>,
253
254    pub contexts: ContextStack,
255
256    pub signer: SvmAddress,
257
258    pub rng: ChaCha20Rng,
259
260    pub block_height: u32,
261
262    pub really_async: bool,
263
264    pub program: Option<Symbol>,
265}
266
267impl CoreFunctionHelper for Cursor {
268    fn pop_value_impl(&mut self) -> Option<Value> {
269        self.values.pop()
270    }
271
272    fn set_block_height(&mut self, height: u32) {
273        self.block_height = height;
274    }
275
276    fn lookup_mapping(&self, program: Option<Symbol>, name: Symbol) -> Option<&HashMap<Value, Value>> {
277        Cursor::lookup_mapping(self, program, name)
278    }
279
280    fn lookup_mapping_mut(&mut self, program: Option<Symbol>, name: Symbol) -> Option<&mut HashMap<Value, Value>> {
281        Cursor::lookup_mapping_mut(self, program, name)
282    }
283
284    fn rng(&mut self) -> Option<&mut ChaCha20Rng> {
285        Some(&mut self.rng)
286    }
287}
288
289impl Cursor {
290    /// `really_async` indicates we should really delay execution of async function calls until the user runs them.
291    pub fn new(really_async: bool, signer: SvmAddress, block_height: u32) -> Self {
292        Cursor {
293            frames: Default::default(),
294            values: Default::default(),
295            functions: Default::default(),
296            globals: Default::default(),
297            user_values: Default::default(),
298            mappings: Default::default(),
299            structs: Default::default(),
300            contexts: Default::default(),
301            futures: Default::default(),
302            rng: ChaCha20Rng::from_entropy(),
303            signer,
304            block_height,
305            really_async,
306            program: None,
307        }
308    }
309
310    pub fn set_program(&mut self, program: &str) {
311        let p = program.strip_suffix(".aleo").unwrap_or(program);
312        self.program = Some(Symbol::intern(p));
313    }
314
315    pub fn current_program(&self) -> Option<Symbol> {
316        self.contexts.current_program().or(self.program)
317    }
318
319    pub fn increment_step(&mut self) {
320        let Some(Frame { step, .. }) = self.frames.last_mut() else {
321            panic!("frame expected");
322        };
323        *step += 1;
324    }
325
326    fn new_caller(&self) -> SvmAddress {
327        if let Some(function_context) = self.contexts.last() {
328            let program_id = ProgramID::<TestnetV0>::from_str(&format!("{}.aleo", function_context.program))
329                .expect("should be able to create ProgramID");
330            program_id.to_address().expect("should be able to convert to address")
331        } else {
332            self.signer
333        }
334    }
335
336    fn pop_value(&mut self) -> Result<Value> {
337        match self.values.pop() {
338            Some(v) => Ok(v),
339            None => {
340                Err(InterpreterHalt::new("value expected - this may be a bug in the Leo interpreter".to_string())
341                    .into())
342            }
343        }
344    }
345
346    fn lookup(&self, name: Symbol) -> Option<Value> {
347        if let Some(context) = self.contexts.last() {
348            let option_value =
349                context.names.get(&name).or_else(|| self.globals.get(&GlobalId { program: context.program, name }));
350            if option_value.is_some() {
351                return option_value.cloned();
352            }
353        };
354
355        self.user_values.get(&name).cloned()
356    }
357
358    pub fn lookup_mapping(&self, program: Option<Symbol>, name: Symbol) -> Option<&HashMap<Value, Value>> {
359        let Some(program) = program.or_else(|| self.current_program()) else {
360            panic!("no program for mapping lookup");
361        };
362        self.mappings.get(&GlobalId { program, name })
363    }
364
365    pub fn lookup_mapping_mut(&mut self, program: Option<Symbol>, name: Symbol) -> Option<&mut HashMap<Value, Value>> {
366        let Some(program) = program.or_else(|| self.current_program()) else {
367            panic!("no program for mapping lookup");
368        };
369        self.mappings.get_mut(&GlobalId { program, name })
370    }
371
372    fn lookup_function(&self, program: Symbol, name: Symbol) -> Option<FunctionVariant> {
373        self.functions.get(&GlobalId { program, name }).cloned()
374    }
375
376    fn set_variable(&mut self, symbol: Symbol, value: Value) {
377        if self.contexts.len() > 0 {
378            self.contexts.set(symbol, value);
379        } else {
380            self.user_values.insert(symbol, value);
381        }
382    }
383
384    /// Execute the whole step of the current Element.
385    ///
386    /// That is, perform a step, and then finish all statements and expressions that have been pushed,
387    /// until we're ready for the next step of the current Element (if there is one).
388    pub fn whole_step(&mut self) -> Result<StepResult> {
389        let frames_len = self.frames.len();
390        let initial_result = self.step()?;
391        if !initial_result.finished {
392            while self.frames.len() > frames_len {
393                self.step()?;
394            }
395        }
396        Ok(initial_result)
397    }
398
399    /// Step `over` the current Element.
400    ///
401    /// That is, continue executing until the current Element is finished.
402    pub fn over(&mut self) -> Result<StepResult> {
403        let frames_len = self.frames.len();
404        loop {
405            match self.frames.len().cmp(&frames_len) {
406                Ordering::Greater => {
407                    self.step()?;
408                }
409                Ordering::Equal => {
410                    let result = self.step()?;
411                    if result.finished {
412                        return Ok(result);
413                    }
414                }
415                Ordering::Less => {
416                    // This can happen if, for instance, a `return` was encountered,
417                    // which means we exited the function we were evaluating and the
418                    // frame stack was truncated.
419                    return Ok(StepResult { finished: true, value: None });
420                }
421            }
422        }
423    }
424
425    pub fn step_block(&mut self, block: &Block, function_body: bool, step: usize) -> bool {
426        let len = self.frames.len();
427
428        let done = match step {
429            0 => {
430                for statement in block.statements.iter().rev() {
431                    self.frames.push(Frame {
432                        element: Element::Statement(statement.clone()),
433                        step: 0,
434                        user_initiated: false,
435                    });
436                }
437                false
438            }
439            1 if function_body => {
440                self.values.push(Value::Unit);
441                self.contexts.pop();
442                true
443            }
444            1 => true,
445            _ => unreachable!(),
446        };
447
448        if done {
449            assert_eq!(len, self.frames.len());
450            self.frames.pop();
451        } else {
452            self.frames[len - 1].step += 1;
453        }
454
455        done
456    }
457
458    fn step_statement(&mut self, statement: &Statement, step: usize) -> Result<bool> {
459        let len = self.frames.len();
460
461        let mut push = |expression: &Expression| {
462            self.frames.push(Frame { element: Element::Expression(expression.clone()), step: 0, user_initiated: false })
463        };
464
465        let done = match statement {
466            Statement::Assert(assert) if step == 0 => {
467                match &assert.variant {
468                    AssertVariant::Assert(x) => push(x),
469                    AssertVariant::AssertEq(x, y) | AssertVariant::AssertNeq(x, y) => {
470                        push(y);
471                        push(x);
472                    }
473                };
474                false
475            }
476            Statement::Assert(assert) if step == 1 => {
477                match &assert.variant {
478                    AssertVariant::Assert(..) => {
479                        let value = self.pop_value()?;
480                        match value {
481                            Value::Bool(true) => {}
482                            Value::Bool(false) => halt!(assert.span(), "assert failure"),
483                            _ => tc_fail!(),
484                        }
485                    }
486                    AssertVariant::AssertEq(..) | AssertVariant::AssertNeq(..) => {
487                        let x = self.pop_value()?;
488                        let y = self.pop_value()?;
489                        let b =
490                            if matches!(assert.variant, AssertVariant::AssertEq(..)) { x.eq(&y)? } else { x.neq(&y)? };
491                        if !b {
492                            halt!(assert.span(), "assert failure");
493                        }
494                    }
495                };
496                true
497            }
498            Statement::Assign(assign) if step == 0 => {
499                push(&assign.value);
500                false
501            }
502            Statement::Assign(assign) if step == 1 => {
503                let value = self.values.pop().unwrap();
504                match &assign.place {
505                    Expression::Identifier(name) => self.set_variable(name.name, value),
506                    Expression::TupleAccess(tuple_access) => {
507                        let Expression::Identifier(identifier) = tuple_access.tuple else {
508                            halt!(assign.span(), "tuple assignments must refer to identifiers.");
509                        };
510                        let mut current_tuple = self.lookup(identifier.name).expect_tc(identifier.span())?;
511                        let Value::Tuple(tuple) = &mut current_tuple else {
512                            halt!(tuple_access.span(), "Type error: this must be a tuple.");
513                        };
514                        tuple[tuple_access.index.value()] = value;
515                        self.set_variable(identifier.name, current_tuple);
516                    }
517                    _ => halt!(assign.span(), "Invalid assignment place."),
518                }
519                true
520            }
521            Statement::Block(block) => return Ok(self.step_block(block, false, step)),
522            Statement::Conditional(conditional) if step == 0 => {
523                push(&conditional.condition);
524                false
525            }
526            Statement::Conditional(conditional) if step == 1 => {
527                match self.pop_value()? {
528                    Value::Bool(true) => self.frames.push(Frame {
529                        step: 0,
530                        element: Element::Block { block: conditional.then.clone(), function_body: false },
531                        user_initiated: false,
532                    }),
533                    Value::Bool(false) => {
534                        if let Some(otherwise) = conditional.otherwise.as_ref() {
535                            self.frames.push(Frame {
536                                step: 0,
537                                element: Element::Statement(Statement::clone(otherwise)),
538                                user_initiated: false,
539                            })
540                        }
541                    }
542                    _ => tc_fail!(),
543                };
544                false
545            }
546            Statement::Conditional(_) if step == 2 => true,
547            Statement::Const(const_) if step == 0 => {
548                push(&const_.value);
549                false
550            }
551            Statement::Const(const_) if step == 1 => {
552                let value = self.pop_value()?;
553                self.set_variable(const_.place.name, value);
554                true
555            }
556            Statement::Definition(definition) if step == 0 => {
557                push(&definition.value);
558                false
559            }
560            Statement::Definition(definition) if step == 1 => {
561                let value = self.pop_value()?;
562                match &definition.place {
563                    DefinitionPlace::Single(id) => self.set_variable(id.name, value),
564                    DefinitionPlace::Multiple(ids) => {
565                        let Value::Tuple(rhs) = value else {
566                            tc_fail!();
567                        };
568                        for (id, val) in ids.iter().zip(rhs.into_iter()) {
569                            self.set_variable(id.name, val);
570                        }
571                    }
572                }
573                true
574            }
575            Statement::Expression(expression) if step == 0 => {
576                push(&expression.expression);
577                false
578            }
579            Statement::Expression(_) if step == 1 => {
580                self.values.pop();
581                true
582            }
583            Statement::Iteration(iteration) if step == 0 => {
584                assert!(!iteration.inclusive);
585                push(&iteration.stop);
586                push(&iteration.start);
587                false
588            }
589            Statement::Iteration(iteration) => {
590                // Currently there actually isn't a syntax in Leo for inclusive ranges.
591                let stop = self.pop_value()?;
592                let start = self.pop_value()?;
593                if start.eq(&stop)? {
594                    true
595                } else {
596                    let new_start = start.inc_wrapping();
597                    self.set_variable(iteration.variable.name, start);
598                    self.frames.push(Frame {
599                        step: 0,
600                        element: Element::Block { block: iteration.block.clone(), function_body: false },
601                        user_initiated: false,
602                    });
603                    self.values.push(new_start);
604                    self.values.push(stop);
605                    false
606                }
607            }
608            Statement::Return(return_) if step == 0 => {
609                push(&return_.expression);
610                false
611            }
612            Statement::Return(_) if step == 1 => loop {
613                let last_frame = self.frames.last().expect("a frame should be present");
614                match last_frame.element {
615                    Element::Expression(Expression::Call(_)) | Element::DelayedCall(_) => {
616                        if self.contexts.is_async() {
617                            // Get rid of the Unit we previously pushed, and replace it with a Future.
618                            self.values.pop();
619                            self.values.push(Value::Future(self.contexts.get_future()));
620                        }
621                        self.contexts.pop();
622                        return Ok(true);
623                    }
624                    _ => {
625                        self.frames.pop();
626                    }
627                }
628            },
629            _ => unreachable!(),
630        };
631
632        if done {
633            assert_eq!(len, self.frames.len());
634            self.frames.pop();
635        } else {
636            self.frames[len - 1].step += 1;
637        }
638
639        Ok(done)
640    }
641
642    fn step_expression(&mut self, expression: &Expression, step: usize) -> Result<bool> {
643        let len = self.frames.len();
644
645        macro_rules! push {
646            () => {
647                |expression: &Expression| {
648                    self.frames.push(Frame {
649                        element: Element::Expression(expression.clone()),
650                        step: 0,
651                        user_initiated: false,
652                    })
653                }
654            };
655        }
656
657        if let Some(value) = match expression {
658            Expression::ArrayAccess(array) if step == 0 => {
659                push!()(&array.index);
660                push!()(&array.array);
661                None
662            }
663            Expression::ArrayAccess(array) if step == 1 => {
664                let span = array.span();
665                let array = self.pop_value()?;
666                let index = self.pop_value()?;
667
668                let index_usize: usize = match index {
669                    Value::U8(x) => x.into(),
670                    Value::U16(x) => x.into(),
671                    Value::U32(x) => x.try_into().expect_tc(span)?,
672                    Value::U64(x) => x.try_into().expect_tc(span)?,
673                    Value::U128(x) => x.try_into().expect_tc(span)?,
674                    Value::I8(x) => x.try_into().expect_tc(span)?,
675                    Value::I16(x) => x.try_into().expect_tc(span)?,
676                    Value::I32(x) => x.try_into().expect_tc(span)?,
677                    Value::I64(x) => x.try_into().expect_tc(span)?,
678                    Value::I128(x) => x.try_into().expect_tc(span)?,
679                    _ => halt!(expression.span(), "invalid array index {index}"),
680                };
681                let Value::Array(vec_array) = array else { tc_fail!() };
682                Some(vec_array.get(index_usize).expect_tc(span)?.clone())
683            }
684            Expression::MemberAccess(access) => match &access.inner {
685                Expression::Identifier(identifier) if identifier.name == sym::SelfLower => match access.name.name {
686                    sym::signer => Some(Value::Address(self.signer)),
687                    sym::caller => {
688                        if let Some(function_context) = self.contexts.last() {
689                            Some(Value::Address(function_context.caller))
690                        } else {
691                            Some(Value::Address(self.signer))
692                        }
693                    }
694                    _ => halt!(access.span(), "unknown member of self"),
695                },
696                Expression::Identifier(identifier) if identifier.name == sym::block => match access.name.name {
697                    sym::height => Some(Value::U32(self.block_height)),
698                    _ => halt!(access.span(), "unknown member of block"),
699                },
700
701                // Otherwise, we just have a normal struct member access.
702                _ if step == 0 => {
703                    push!()(&access.inner);
704                    None
705                }
706                _ if step == 1 => {
707                    let Some(Value::Struct(struct_)) = self.values.pop() else {
708                        tc_fail!();
709                    };
710                    let value = struct_.contents.get(&access.name.name).cloned();
711                    if value.is_none() {
712                        tc_fail!();
713                    }
714                    value
715                }
716                _ => unreachable!("we've actually covered all possible patterns above"),
717            },
718            Expression::TupleAccess(tuple_access) if step == 0 => {
719                push!()(&tuple_access.tuple);
720                None
721            }
722            Expression::TupleAccess(tuple_access) if step == 1 => {
723                let Some(value) = self.values.pop() else { tc_fail!() };
724                let Value::Tuple(tuple) = value else {
725                    halt!(tuple_access.span(), "Type error");
726                };
727                if let Some(result) = tuple.get(tuple_access.index.value()) {
728                    Some(result.clone())
729                } else {
730                    halt!(tuple_access.span(), "Tuple index out of range");
731                }
732            }
733            Expression::Array(array) if step == 0 => {
734                array.elements.iter().rev().for_each(push!());
735                None
736            }
737            Expression::Array(array) if step == 1 => {
738                let len = self.values.len();
739                let array_values = self.values.drain(len - array.elements.len()..).collect();
740                Some(Value::Array(array_values))
741            }
742            Expression::AssociatedConstant(constant) if step == 0 => {
743                let Type::Identifier(type_ident) = constant.ty else {
744                    tc_fail!();
745                };
746                let Some(core_constant) = CoreConstant::from_symbols(type_ident.name, constant.name.name) else {
747                    halt!(constant.span(), "Unknown constant {constant}");
748                };
749                match core_constant {
750                    CoreConstant::GroupGenerator => Some(Value::generator()),
751                }
752            }
753            Expression::AssociatedFunction(function) if step == 0 => {
754                let Some(core_function) = CoreFunction::from_symbols(function.variant.name, function.name.name) else {
755                    halt!(function.span(), "Unkown core function {function}");
756                };
757
758                // We want to push expressions for each of the arguments... except for mappings,
759                // because we don't look them up as Values.
760                match core_function {
761                    CoreFunction::MappingGet | CoreFunction::MappingRemove | CoreFunction::MappingContains => {
762                        push!()(&function.arguments[1]);
763                    }
764                    CoreFunction::MappingGetOrUse | CoreFunction::MappingSet => {
765                        push!()(&function.arguments[2]);
766                        push!()(&function.arguments[1]);
767                    }
768                    CoreFunction::CheatCodePrintMapping => {
769                        // Do nothing, as we don't need to evaluate the mapping.
770                    }
771                    _ => function.arguments.iter().rev().for_each(push!()),
772                }
773                None
774            }
775            Expression::AssociatedFunction(function) if step == 1 => {
776                let Some(core_function) = CoreFunction::from_symbols(function.variant.name, function.name.name) else {
777                    halt!(function.span(), "Unkown core function {function}");
778                };
779
780                let span = function.span();
781
782                if let CoreFunction::FutureAwait = core_function {
783                    let value = self.pop_value()?;
784                    let Value::Future(future) = value else {
785                        halt!(span, "Invalid value for await: {value}");
786                    };
787                    for async_execution in future.0 {
788                        self.values.extend(async_execution.arguments.into_iter());
789                        self.frames.push(Frame {
790                            step: 0,
791                            element: Element::DelayedCall(async_execution.function),
792                            user_initiated: false,
793                        });
794                    }
795                    // For an await, we have one extra step - first we must evaluate the delayed call.
796                    None
797                } else {
798                    let value = crate::evaluate_core_function(self, core_function.clone(), &function.arguments, span)?;
799                    assert!(value.is_some());
800                    value
801                }
802            }
803            Expression::AssociatedFunction(function) if step == 2 => {
804                let Some(core_function) = CoreFunction::from_symbols(function.variant.name, function.name.name) else {
805                    halt!(function.span(), "Unkown core function {function}");
806                };
807                assert!(core_function == CoreFunction::FutureAwait);
808                Some(Value::Unit)
809            }
810            Expression::Binary(binary) if step == 0 => {
811                push!()(&binary.right);
812                push!()(&binary.left);
813                None
814            }
815            Expression::Binary(binary) if step == 1 => {
816                let rhs = self.pop_value()?;
817                let lhs = self.pop_value()?;
818                Some(evaluate_binary(binary.span, binary.op, &lhs, &rhs)?)
819            }
820            Expression::Call(call) if step == 0 => {
821                call.arguments.iter().rev().for_each(push!());
822                None
823            }
824            Expression::Call(call) if step == 1 => {
825                let len = self.values.len();
826                let (program, name) = match &call.function {
827                    Expression::Identifier(id) => {
828                        let maybe_program = call.program.or_else(|| self.current_program());
829                        if let Some(program) = maybe_program {
830                            (program, id.name)
831                        } else {
832                            halt!(call.span, "No current program");
833                        }
834                    }
835                    Expression::Locator(locator) => (locator.program.name.name, locator.name),
836                    _ => tc_fail!(),
837                };
838                // It's a bit cheesy to collect the arguments into a Vec first, but it's the easiest way
839                // to handle lifetimes here.
840                let arguments: Vec<Value> = self.values.drain(len - call.arguments.len()..).collect();
841                self.do_call(
842                    program,
843                    name,
844                    arguments.into_iter(),
845                    false, // finalize
846                    call.span(),
847                )?;
848                None
849            }
850            Expression::Call(_call) if step == 2 => Some(self.pop_value()?),
851            Expression::Cast(cast) if step == 0 => {
852                push!()(&cast.expression);
853                None
854            }
855            Expression::Cast(cast) if step == 1 => {
856                let span = cast.span();
857                let arg = self.pop_value()?;
858                match arg.cast(&cast.type_) {
859                    Some(value) => Some(value),
860                    None => return Err(InterpreterHalt::new_spanned("cast failure".to_string(), span).into()),
861                }
862            }
863            Expression::Err(_) => todo!(),
864            Expression::Identifier(identifier) if step == 0 => {
865                Some(self.lookup(identifier.name).expect_tc(identifier.span())?)
866            }
867            Expression::Literal(literal) if step == 0 => Some(literal_to_value(literal)?),
868            Expression::Locator(_locator) => todo!(),
869            Expression::Struct(struct_) if step == 0 => {
870                struct_.members.iter().flat_map(|init| init.expression.as_ref()).for_each(push!());
871                None
872            }
873            Expression::Struct(struct_) if step == 1 => {
874                // Collect all the key/value pairs into a HashMap.
875                let mut contents_tmp = HashMap::with_capacity(struct_.members.len());
876                for initializer in struct_.members.iter() {
877                    let name = initializer.identifier.name;
878                    let value = if initializer.expression.is_some() {
879                        self.pop_value()?
880                    } else {
881                        self.lookup(name).expect_tc(struct_.span())?
882                    };
883                    contents_tmp.insert(name, value);
884                }
885
886                // And now put them into an IndexMap in the correct order.
887                let program = self.current_program().expect("there should be a current program");
888                let id = GlobalId { program, name: struct_.name.name };
889                let struct_type = self.structs.get(&id).expect_tc(struct_.span())?;
890                let contents = struct_type
891                    .iter()
892                    .map(|sym| (*sym, contents_tmp.remove(sym).expect("we just inserted this")))
893                    .collect();
894
895                Some(Value::Struct(StructContents { name: struct_.name.name, contents }))
896            }
897            Expression::Ternary(ternary) if step == 0 => {
898                push!()(&ternary.condition);
899                None
900            }
901            Expression::Ternary(ternary) if step == 1 => {
902                let condition = self.pop_value()?;
903                match condition {
904                    Value::Bool(true) => push!()(&ternary.if_true),
905                    Value::Bool(false) => push!()(&ternary.if_false),
906                    _ => halt!(ternary.span(), "Invalid type for ternary expression {ternary}"),
907                }
908                None
909            }
910            Expression::Ternary(_) if step == 2 => Some(self.pop_value()?),
911            Expression::Tuple(tuple) if step == 0 => {
912                tuple.elements.iter().rev().for_each(push!());
913                None
914            }
915            Expression::Tuple(tuple) if step == 1 => {
916                let len = self.values.len();
917                let tuple_values = self.values.drain(len - tuple.elements.len()..).collect();
918                Some(Value::Tuple(tuple_values))
919            }
920            Expression::Unary(unary) if step == 0 => {
921                push!()(&unary.receiver);
922                None
923            }
924            Expression::Unary(unary) if step == 1 => {
925                let value = self.pop_value()?;
926                Some(evaluate_unary(unary.span, unary.op, &value)?)
927            }
928            Expression::Unit(_) if step == 0 => Some(Value::Unit),
929            x => unreachable!("Unexpected expression {x}"),
930        } {
931            assert_eq!(self.frames.len(), len);
932            self.frames.pop();
933            self.values.push(value);
934            Ok(true)
935        } else {
936            self.frames[len - 1].step += 1;
937            Ok(false)
938        }
939    }
940
941    /// Execute one step of the current element.
942    ///
943    /// Many Leo constructs require multiple steps. For instance, when executing a conditional,
944    /// the first step will push the condition expression to the stack. Once that has executed
945    /// and we've returned to the conditional, we push the `then` or `otherwise` block to the
946    /// stack. Once that has executed and we've returned to the conditional, the final step
947    /// does nothing.
948    pub fn step(&mut self) -> Result<StepResult> {
949        if self.frames.is_empty() {
950            return Err(InterpreterHalt::new("no execution frames available".into()).into());
951        }
952
953        let Frame { element, step, user_initiated } = self.frames.last().expect("there should be a frame").clone();
954        match element {
955            Element::Block { block, function_body } => {
956                let finished = self.step_block(&block, function_body, step);
957                Ok(StepResult { finished, value: None })
958            }
959            Element::Statement(statement) => {
960                let finished = self.step_statement(&statement, step)?;
961                Ok(StepResult { finished, value: None })
962            }
963            Element::Expression(expression) => {
964                let finished = self.step_expression(&expression, step)?;
965                let value = match (finished, user_initiated) {
966                    (false, _) => None,
967                    (true, false) => self.values.last().cloned(),
968                    (true, true) => self.values.pop(),
969                };
970                let maybe_future = if let Some(Value::Tuple(vals)) = &value { vals.last() } else { value.as_ref() };
971
972                if let Some(Value::Future(future)) = &maybe_future {
973                    if user_initiated && !future.0.is_empty() {
974                        self.futures.push(future.clone());
975                    }
976                }
977                Ok(StepResult { finished, value })
978            }
979            Element::AleoExecution { .. } => {
980                self.step_aleo()?;
981                Ok(StepResult { finished: true, value: None })
982            }
983            Element::DelayedCall(gid) if step == 0 => {
984                match self.lookup_function(gid.program, gid.name).expect("function should exist") {
985                    FunctionVariant::Leo(function) => {
986                        assert!(function.variant == Variant::AsyncFunction);
987                        let len = self.values.len();
988                        let values: Vec<Value> = self.values.drain(len - function.input.len()..).collect();
989                        self.contexts.push(
990                            gid.program,
991                            self.signer,
992                            true, // is_async
993                        );
994                        let param_names = function.input.iter().map(|input| input.identifier.name);
995                        for (name, value) in param_names.zip(values) {
996                            self.set_variable(name, value);
997                        }
998                        self.frames.last_mut().unwrap().step = 1;
999                        self.frames.push(Frame {
1000                            step: 0,
1001                            element: Element::Block { block: function.block.clone(), function_body: true },
1002                            user_initiated: false,
1003                        });
1004                        Ok(StepResult { finished: false, value: None })
1005                    }
1006                    FunctionVariant::AleoFunction(function) => {
1007                        let Some(finalize_f) = function.finalize_logic() else {
1008                            panic!("must have finalize logic for a delayed call");
1009                        };
1010                        let len = self.values.len();
1011                        let values_iter = self.values.drain(len - finalize_f.inputs().len()..);
1012                        self.contexts.push(
1013                            gid.program,
1014                            self.signer,
1015                            true, // is_async
1016                        );
1017                        self.frames.last_mut().unwrap().step = 1;
1018                        self.frames.push(Frame {
1019                            step: 0,
1020                            element: Element::AleoExecution {
1021                                context: AleoContext::Finalize(finalize_f.clone()).into(),
1022                                registers: values_iter.enumerate().map(|(i, v)| (i as u64, v)).collect(),
1023                                instruction_index: 0,
1024                            },
1025                            user_initiated: false,
1026                        });
1027                        Ok(StepResult { finished: false, value: None })
1028                    }
1029                    FunctionVariant::AleoClosure(..) => panic!("A call to a closure can't be delayed"),
1030                }
1031            }
1032            Element::DelayedCall(_gid) => {
1033                assert_eq!(step, 1);
1034                let value = self.values.pop();
1035                self.frames.pop();
1036                Ok(StepResult { finished: true, value })
1037            }
1038        }
1039    }
1040
1041    pub fn do_call(
1042        &mut self,
1043        function_program: Symbol,
1044        function_name: Symbol,
1045        arguments: impl Iterator<Item = Value>,
1046        finalize: bool,
1047        span: Span,
1048    ) -> Result<()> {
1049        let Some(function_variant) = self.lookup_function(function_program, function_name) else {
1050            halt!(span, "unknown function {function_program}.aleo/{function_name}");
1051        };
1052        match function_variant {
1053            FunctionVariant::Leo(function) => {
1054                let caller = if matches!(function.variant, Variant::Transition | Variant::AsyncTransition) {
1055                    self.new_caller()
1056                } else {
1057                    self.signer
1058                };
1059                if self.really_async && function.variant == Variant::AsyncFunction {
1060                    // Don't actually run the call now.
1061                    let async_ex = AsyncExecution {
1062                        function: GlobalId { name: function_name, program: function_program },
1063                        arguments: arguments.collect(),
1064                    };
1065                    self.values.push(Value::Future(Future(vec![async_ex])));
1066                } else {
1067                    let is_async = function.variant == Variant::AsyncFunction;
1068                    self.contexts.push(function_program, caller, is_async);
1069                    let param_names = function.input.iter().map(|input| input.identifier.name);
1070                    for (name, value) in param_names.zip(arguments) {
1071                        self.set_variable(name, value);
1072                    }
1073                    self.frames.push(Frame {
1074                        step: 0,
1075                        element: Element::Block { block: function.block.clone(), function_body: true },
1076                        user_initiated: false,
1077                    });
1078                }
1079            }
1080            FunctionVariant::AleoClosure(closure) => {
1081                self.contexts.push(function_program, self.signer, false);
1082                let context = AleoContext::Closure(closure);
1083                self.frames.push(Frame {
1084                    step: 0,
1085                    element: Element::AleoExecution {
1086                        context: context.into(),
1087                        registers: arguments.enumerate().map(|(i, v)| (i as u64, v)).collect(),
1088                        instruction_index: 0,
1089                    },
1090                    user_initiated: false,
1091                });
1092            }
1093            FunctionVariant::AleoFunction(function) => {
1094                let caller = self.new_caller();
1095                self.contexts.push(function_program, caller, false);
1096                let context = if finalize {
1097                    let Some(finalize_f) = function.finalize_logic() else {
1098                        panic!("finalize call with no finalize logic");
1099                    };
1100                    AleoContext::Finalize(finalize_f.clone())
1101                } else {
1102                    AleoContext::Function(function)
1103                };
1104                self.frames.push(Frame {
1105                    step: 0,
1106                    element: Element::AleoExecution {
1107                        context: context.into(),
1108                        registers: arguments.enumerate().map(|(i, v)| (i as u64, v)).collect(),
1109                        instruction_index: 0,
1110                    },
1111                    user_initiated: false,
1112                });
1113            }
1114        }
1115
1116        Ok(())
1117    }
1118}
1119
1120#[derive(Clone, Debug)]
1121pub struct StepResult {
1122    /// Has this element completely finished running?
1123    pub finished: bool,
1124
1125    /// If the element was an expression, here's its value.
1126    pub value: Option<Value>,
1127}
1128
1129/// Evaluate a binary operation.
1130pub fn evaluate_binary(span: Span, op: BinaryOperation, lhs: &Value, rhs: &Value) -> Result<Value> {
1131    let value = match op {
1132        BinaryOperation::Add => {
1133            let Some(value) = (match (lhs, rhs) {
1134                (Value::U8(x), Value::U8(y)) => x.checked_add(*y).map(Value::U8),
1135                (Value::U16(x), Value::U16(y)) => x.checked_add(*y).map(Value::U16),
1136                (Value::U32(x), Value::U32(y)) => x.checked_add(*y).map(Value::U32),
1137                (Value::U64(x), Value::U64(y)) => x.checked_add(*y).map(Value::U64),
1138                (Value::U128(x), Value::U128(y)) => x.checked_add(*y).map(Value::U128),
1139                (Value::I8(x), Value::I8(y)) => x.checked_add(*y).map(Value::I8),
1140                (Value::I16(x), Value::I16(y)) => x.checked_add(*y).map(Value::I16),
1141                (Value::I32(x), Value::I32(y)) => x.checked_add(*y).map(Value::I32),
1142                (Value::I64(x), Value::I64(y)) => x.checked_add(*y).map(Value::I64),
1143                (Value::I128(x), Value::I128(y)) => x.checked_add(*y).map(Value::I128),
1144                (Value::Group(x), Value::Group(y)) => Some(Value::Group(*x + *y)),
1145                (Value::Field(x), Value::Field(y)) => Some(Value::Field(*x + *y)),
1146                (Value::Scalar(x), Value::Scalar(y)) => Some(Value::Scalar(*x + *y)),
1147                _ => halt!(span, "Type error"),
1148            }) else {
1149                halt!(span, "add overflow");
1150            };
1151            value
1152        }
1153        BinaryOperation::AddWrapped => match (lhs, rhs) {
1154            (Value::U8(x), Value::U8(y)) => Value::U8(x.wrapping_add(*y)),
1155            (Value::U16(x), Value::U16(y)) => Value::U16(x.wrapping_add(*y)),
1156            (Value::U32(x), Value::U32(y)) => Value::U32(x.wrapping_add(*y)),
1157            (Value::U64(x), Value::U64(y)) => Value::U64(x.wrapping_add(*y)),
1158            (Value::U128(x), Value::U128(y)) => Value::U128(x.wrapping_add(*y)),
1159            (Value::I8(x), Value::I8(y)) => Value::I8(x.wrapping_add(*y)),
1160            (Value::I16(x), Value::I16(y)) => Value::I16(x.wrapping_add(*y)),
1161            (Value::I32(x), Value::I32(y)) => Value::I32(x.wrapping_add(*y)),
1162            (Value::I64(x), Value::I64(y)) => Value::I64(x.wrapping_add(*y)),
1163            (Value::I128(x), Value::I128(y)) => Value::I128(x.wrapping_add(*y)),
1164            _ => halt!(span, "Type error"),
1165        },
1166        BinaryOperation::And => match (lhs, rhs) {
1167            (Value::Bool(x), Value::Bool(y)) => Value::Bool(*x && *y),
1168            _ => halt!(span, "Type error"),
1169        },
1170        BinaryOperation::BitwiseAnd => match (lhs, rhs) {
1171            (Value::Bool(x), Value::Bool(y)) => Value::Bool(x & y),
1172            (Value::U8(x), Value::U8(y)) => Value::U8(x & y),
1173            (Value::U16(x), Value::U16(y)) => Value::U16(x & y),
1174            (Value::U32(x), Value::U32(y)) => Value::U32(x & y),
1175            (Value::U64(x), Value::U64(y)) => Value::U64(x & y),
1176            (Value::U128(x), Value::U128(y)) => Value::U128(x & y),
1177            (Value::I8(x), Value::I8(y)) => Value::I8(x & y),
1178            (Value::I16(x), Value::I16(y)) => Value::I16(x & y),
1179            (Value::I32(x), Value::I32(y)) => Value::I32(x & y),
1180            (Value::I64(x), Value::I64(y)) => Value::I64(x & y),
1181            (Value::I128(x), Value::I128(y)) => Value::I128(x & y),
1182            _ => halt!(span, "Type error"),
1183        },
1184        BinaryOperation::Div => {
1185            let Some(value) = (match (lhs, rhs) {
1186                (Value::U8(x), Value::U8(y)) => x.checked_div(*y).map(Value::U8),
1187                (Value::U16(x), Value::U16(y)) => x.checked_div(*y).map(Value::U16),
1188                (Value::U32(x), Value::U32(y)) => x.checked_div(*y).map(Value::U32),
1189                (Value::U64(x), Value::U64(y)) => x.checked_div(*y).map(Value::U64),
1190                (Value::U128(x), Value::U128(y)) => x.checked_div(*y).map(Value::U128),
1191                (Value::I8(x), Value::I8(y)) => x.checked_div(*y).map(Value::I8),
1192                (Value::I16(x), Value::I16(y)) => x.checked_div(*y).map(Value::I16),
1193                (Value::I32(x), Value::I32(y)) => x.checked_div(*y).map(Value::I32),
1194                (Value::I64(x), Value::I64(y)) => x.checked_div(*y).map(Value::I64),
1195                (Value::I128(x), Value::I128(y)) => x.checked_div(*y).map(Value::I128),
1196                (Value::Field(x), Value::Field(y)) => y.inverse().map(|y| Value::Field(*x * y)).ok(),
1197                _ => halt!(span, "Type error"),
1198            }) else {
1199                halt!(span, "div overflow");
1200            };
1201            value
1202        }
1203        BinaryOperation::DivWrapped => match (lhs, rhs) {
1204            (Value::U8(_), Value::U8(0))
1205            | (Value::U16(_), Value::U16(0))
1206            | (Value::U32(_), Value::U32(0))
1207            | (Value::U64(_), Value::U64(0))
1208            | (Value::U128(_), Value::U128(0))
1209            | (Value::I8(_), Value::I8(0))
1210            | (Value::I16(_), Value::I16(0))
1211            | (Value::I32(_), Value::I32(0))
1212            | (Value::I64(_), Value::I64(0))
1213            | (Value::I128(_), Value::I128(0)) => halt!(span, "divide by 0"),
1214            (Value::U8(x), Value::U8(y)) => Value::U8(x.wrapping_div(*y)),
1215            (Value::U16(x), Value::U16(y)) => Value::U16(x.wrapping_div(*y)),
1216            (Value::U32(x), Value::U32(y)) => Value::U32(x.wrapping_div(*y)),
1217            (Value::U64(x), Value::U64(y)) => Value::U64(x.wrapping_div(*y)),
1218            (Value::U128(x), Value::U128(y)) => Value::U128(x.wrapping_div(*y)),
1219            (Value::I8(x), Value::I8(y)) => Value::I8(x.wrapping_div(*y)),
1220            (Value::I16(x), Value::I16(y)) => Value::I16(x.wrapping_div(*y)),
1221            (Value::I32(x), Value::I32(y)) => Value::I32(x.wrapping_div(*y)),
1222            (Value::I64(x), Value::I64(y)) => Value::I64(x.wrapping_div(*y)),
1223            (Value::I128(x), Value::I128(y)) => Value::I128(x.wrapping_div(*y)),
1224            _ => halt!(span, "Type error"),
1225        },
1226        BinaryOperation::Eq => Value::Bool(lhs.eq(rhs)?),
1227        BinaryOperation::Gte => Value::Bool(lhs.gte(rhs)?),
1228        BinaryOperation::Gt => Value::Bool(lhs.gt(rhs)?),
1229        BinaryOperation::Lte => Value::Bool(lhs.lte(rhs)?),
1230        BinaryOperation::Lt => Value::Bool(lhs.lt(rhs)?),
1231        BinaryOperation::Mod => {
1232            let Some(value) = (match (lhs, rhs) {
1233                (Value::U8(x), Value::U8(y)) => x.checked_rem(*y).map(Value::U8),
1234                (Value::U16(x), Value::U16(y)) => x.checked_rem(*y).map(Value::U16),
1235                (Value::U32(x), Value::U32(y)) => x.checked_rem(*y).map(Value::U32),
1236                (Value::U64(x), Value::U64(y)) => x.checked_rem(*y).map(Value::U64),
1237                (Value::U128(x), Value::U128(y)) => x.checked_rem(*y).map(Value::U128),
1238                (Value::I8(x), Value::I8(y)) => x.checked_rem(*y).map(Value::I8),
1239                (Value::I16(x), Value::I16(y)) => x.checked_rem(*y).map(Value::I16),
1240                (Value::I32(x), Value::I32(y)) => x.checked_rem(*y).map(Value::I32),
1241                (Value::I64(x), Value::I64(y)) => x.checked_rem(*y).map(Value::I64),
1242                (Value::I128(x), Value::I128(y)) => x.checked_rem(*y).map(Value::I128),
1243                _ => halt!(span, "Type error"),
1244            }) else {
1245                halt!(span, "mod overflow");
1246            };
1247            value
1248        }
1249        BinaryOperation::Mul => {
1250            let Some(value) = (match (lhs, rhs) {
1251                (Value::U8(x), Value::U8(y)) => x.checked_mul(*y).map(Value::U8),
1252                (Value::U16(x), Value::U16(y)) => x.checked_mul(*y).map(Value::U16),
1253                (Value::U32(x), Value::U32(y)) => x.checked_mul(*y).map(Value::U32),
1254                (Value::U64(x), Value::U64(y)) => x.checked_mul(*y).map(Value::U64),
1255                (Value::U128(x), Value::U128(y)) => x.checked_mul(*y).map(Value::U128),
1256                (Value::I8(x), Value::I8(y)) => x.checked_mul(*y).map(Value::I8),
1257                (Value::I16(x), Value::I16(y)) => x.checked_mul(*y).map(Value::I16),
1258                (Value::I32(x), Value::I32(y)) => x.checked_mul(*y).map(Value::I32),
1259                (Value::I64(x), Value::I64(y)) => x.checked_mul(*y).map(Value::I64),
1260                (Value::I128(x), Value::I128(y)) => x.checked_mul(*y).map(Value::I128),
1261                (Value::Field(x), Value::Field(y)) => Some(Value::Field(*x * *y)),
1262                (Value::Group(x), Value::Scalar(y)) => Some(Value::Group(*x * *y)),
1263                (Value::Scalar(x), Value::Group(y)) => Some(Value::Group(*x * *y)),
1264                _ => halt!(span, "Type error"),
1265            }) else {
1266                halt!(span, "mul overflow");
1267            };
1268            value
1269        }
1270        BinaryOperation::MulWrapped => match (lhs, rhs) {
1271            (Value::U8(x), Value::U8(y)) => Value::U8(x.wrapping_mul(*y)),
1272            (Value::U16(x), Value::U16(y)) => Value::U16(x.wrapping_mul(*y)),
1273            (Value::U32(x), Value::U32(y)) => Value::U32(x.wrapping_mul(*y)),
1274            (Value::U64(x), Value::U64(y)) => Value::U64(x.wrapping_mul(*y)),
1275            (Value::U128(x), Value::U128(y)) => Value::U128(x.wrapping_mul(*y)),
1276            (Value::I8(x), Value::I8(y)) => Value::I8(x.wrapping_mul(*y)),
1277            (Value::I16(x), Value::I16(y)) => Value::I16(x.wrapping_mul(*y)),
1278            (Value::I32(x), Value::I32(y)) => Value::I32(x.wrapping_mul(*y)),
1279            (Value::I64(x), Value::I64(y)) => Value::I64(x.wrapping_mul(*y)),
1280            (Value::I128(x), Value::I128(y)) => Value::I128(x.wrapping_mul(*y)),
1281            _ => halt!(span, "Type error"),
1282        },
1283
1284        BinaryOperation::Nand => match (lhs, rhs) {
1285            (Value::Bool(x), Value::Bool(y)) => Value::Bool(!(x & y)),
1286            _ => halt!(span, "Type error"),
1287        },
1288        BinaryOperation::Neq => Value::Bool(lhs.neq(rhs)?),
1289        BinaryOperation::Nor => match (lhs, rhs) {
1290            (Value::Bool(x), Value::Bool(y)) => Value::Bool(!(x | y)),
1291            _ => halt!(span, "Type error"),
1292        },
1293        BinaryOperation::Or => match (lhs, rhs) {
1294            (Value::Bool(x), Value::Bool(y)) => Value::Bool(x | y),
1295            _ => halt!(span, "Type error"),
1296        },
1297        BinaryOperation::BitwiseOr => match (lhs, rhs) {
1298            (Value::Bool(x), Value::Bool(y)) => Value::Bool(x | y),
1299            (Value::U8(x), Value::U8(y)) => Value::U8(x | y),
1300            (Value::U16(x), Value::U16(y)) => Value::U16(x | y),
1301            (Value::U32(x), Value::U32(y)) => Value::U32(x | y),
1302            (Value::U64(x), Value::U64(y)) => Value::U64(x | y),
1303            (Value::U128(x), Value::U128(y)) => Value::U128(x | y),
1304            (Value::I8(x), Value::I8(y)) => Value::I8(x | y),
1305            (Value::I16(x), Value::I16(y)) => Value::I16(x | y),
1306            (Value::I32(x), Value::I32(y)) => Value::I32(x | y),
1307            (Value::I64(x), Value::I64(y)) => Value::I64(x | y),
1308            (Value::I128(x), Value::I128(y)) => Value::I128(x | y),
1309            _ => halt!(span, "Type error"),
1310        },
1311        BinaryOperation::Pow => {
1312            if let (Value::Field(x), Value::Field(y)) = (&lhs, &rhs) {
1313                Value::Field(x.pow(y))
1314            } else {
1315                let rhs: u32 = match rhs {
1316                    Value::U8(y) => (*y).into(),
1317                    Value::U16(y) => (*y).into(),
1318                    Value::U32(y) => *y,
1319                    _ => tc_fail!(),
1320                };
1321
1322                let Some(value) = (match lhs {
1323                    Value::U8(x) => x.checked_pow(rhs).map(Value::U8),
1324                    Value::U16(x) => x.checked_pow(rhs).map(Value::U16),
1325                    Value::U32(x) => x.checked_pow(rhs).map(Value::U32),
1326                    Value::U64(x) => x.checked_pow(rhs).map(Value::U64),
1327                    Value::U128(x) => x.checked_pow(rhs).map(Value::U128),
1328                    Value::I8(x) => x.checked_pow(rhs).map(Value::I8),
1329                    Value::I16(x) => x.checked_pow(rhs).map(Value::I16),
1330                    Value::I32(x) => x.checked_pow(rhs).map(Value::I32),
1331                    Value::I64(x) => x.checked_pow(rhs).map(Value::I64),
1332                    Value::I128(x) => x.checked_pow(rhs).map(Value::I128),
1333                    _ => halt!(span, "Type error"),
1334                }) else {
1335                    halt!(span, "pow overflow");
1336                };
1337                value
1338            }
1339        }
1340        BinaryOperation::PowWrapped => {
1341            let rhs: u32 = match rhs {
1342                Value::U8(y) => (*y).into(),
1343                Value::U16(y) => (*y).into(),
1344                Value::U32(y) => *y,
1345                _ => halt!(span, "Type error"),
1346            };
1347
1348            match lhs {
1349                Value::U8(x) => Value::U8(x.wrapping_pow(rhs)),
1350                Value::U16(x) => Value::U16(x.wrapping_pow(rhs)),
1351                Value::U32(x) => Value::U32(x.wrapping_pow(rhs)),
1352                Value::U64(x) => Value::U64(x.wrapping_pow(rhs)),
1353                Value::U128(x) => Value::U128(x.wrapping_pow(rhs)),
1354                Value::I8(x) => Value::I8(x.wrapping_pow(rhs)),
1355                Value::I16(x) => Value::I16(x.wrapping_pow(rhs)),
1356                Value::I32(x) => Value::I32(x.wrapping_pow(rhs)),
1357                Value::I64(x) => Value::I64(x.wrapping_pow(rhs)),
1358                Value::I128(x) => Value::I128(x.wrapping_pow(rhs)),
1359                _ => halt!(span, "Type error"),
1360            }
1361        }
1362        BinaryOperation::Rem => {
1363            let Some(value) = (match (lhs, rhs) {
1364                (Value::U8(x), Value::U8(y)) => x.checked_rem(*y).map(Value::U8),
1365                (Value::U16(x), Value::U16(y)) => x.checked_rem(*y).map(Value::U16),
1366                (Value::U32(x), Value::U32(y)) => x.checked_rem(*y).map(Value::U32),
1367                (Value::U64(x), Value::U64(y)) => x.checked_rem(*y).map(Value::U64),
1368                (Value::U128(x), Value::U128(y)) => x.checked_rem(*y).map(Value::U128),
1369                (Value::I8(x), Value::I8(y)) => x.checked_rem(*y).map(Value::I8),
1370                (Value::I16(x), Value::I16(y)) => x.checked_rem(*y).map(Value::I16),
1371                (Value::I32(x), Value::I32(y)) => x.checked_rem(*y).map(Value::I32),
1372                (Value::I64(x), Value::I64(y)) => x.checked_rem(*y).map(Value::I64),
1373                (Value::I128(x), Value::I128(y)) => x.checked_rem(*y).map(Value::I128),
1374                _ => halt!(span, "Type error"),
1375            }) else {
1376                halt!(span, "rem error");
1377            };
1378            value
1379        }
1380        BinaryOperation::RemWrapped => match (lhs, rhs) {
1381            (Value::U8(_), Value::U8(0))
1382            | (Value::U16(_), Value::U16(0))
1383            | (Value::U32(_), Value::U32(0))
1384            | (Value::U64(_), Value::U64(0))
1385            | (Value::U128(_), Value::U128(0))
1386            | (Value::I8(_), Value::I8(0))
1387            | (Value::I16(_), Value::I16(0))
1388            | (Value::I32(_), Value::I32(0))
1389            | (Value::I64(_), Value::I64(0))
1390            | (Value::I128(_), Value::I128(0)) => halt!(span, "rem by 0"),
1391            (Value::U8(x), Value::U8(y)) => Value::U8(x.wrapping_rem(*y)),
1392            (Value::U16(x), Value::U16(y)) => Value::U16(x.wrapping_rem(*y)),
1393            (Value::U32(x), Value::U32(y)) => Value::U32(x.wrapping_rem(*y)),
1394            (Value::U64(x), Value::U64(y)) => Value::U64(x.wrapping_rem(*y)),
1395            (Value::U128(x), Value::U128(y)) => Value::U128(x.wrapping_rem(*y)),
1396            (Value::I8(x), Value::I8(y)) => Value::I8(x.wrapping_rem(*y)),
1397            (Value::I16(x), Value::I16(y)) => Value::I16(x.wrapping_rem(*y)),
1398            (Value::I32(x), Value::I32(y)) => Value::I32(x.wrapping_rem(*y)),
1399            (Value::I64(x), Value::I64(y)) => Value::I64(x.wrapping_rem(*y)),
1400            (Value::I128(x), Value::I128(y)) => Value::I128(x.wrapping_rem(*y)),
1401            _ => halt!(span, "Type error"),
1402        },
1403        BinaryOperation::Shl => {
1404            let rhs: u32 = match rhs {
1405                Value::U8(y) => (*y).into(),
1406                Value::U16(y) => (*y).into(),
1407                Value::U32(y) => *y,
1408                _ => halt!(span, "Type error"),
1409            };
1410            match lhs {
1411                Value::U8(_) | Value::I8(_) if rhs >= 8 => halt!(span, "shl overflow"),
1412                Value::U16(_) | Value::I16(_) if rhs >= 16 => halt!(span, "shl overflow"),
1413                Value::U32(_) | Value::I32(_) if rhs >= 32 => halt!(span, "shl overflow"),
1414                Value::U64(_) | Value::I64(_) if rhs >= 64 => halt!(span, "shl overflow"),
1415                Value::U128(_) | Value::I128(_) if rhs >= 128 => halt!(span, "shl overflow"),
1416                _ => {}
1417            }
1418
1419            // Aleo's shl halts if set bits are shifted out.
1420            let shifted = lhs.simple_shl(rhs);
1421            let reshifted = shifted.simple_shr(rhs);
1422            if lhs.eq(&reshifted)? {
1423                shifted
1424            } else {
1425                halt!(span, "shl overflow");
1426            }
1427        }
1428
1429        BinaryOperation::ShlWrapped => {
1430            let rhs: u32 = match rhs {
1431                Value::U8(y) => (*y).into(),
1432                Value::U16(y) => (*y).into(),
1433                Value::U32(y) => *y,
1434                _ => halt!(span, "Type error"),
1435            };
1436            match lhs {
1437                Value::U8(x) => Value::U8(x.wrapping_shl(rhs)),
1438                Value::U16(x) => Value::U16(x.wrapping_shl(rhs)),
1439                Value::U32(x) => Value::U32(x.wrapping_shl(rhs)),
1440                Value::U64(x) => Value::U64(x.wrapping_shl(rhs)),
1441                Value::U128(x) => Value::U128(x.wrapping_shl(rhs)),
1442                Value::I8(x) => Value::I8(x.wrapping_shl(rhs)),
1443                Value::I16(x) => Value::I16(x.wrapping_shl(rhs)),
1444                Value::I32(x) => Value::I32(x.wrapping_shl(rhs)),
1445                Value::I64(x) => Value::I64(x.wrapping_shl(rhs)),
1446                Value::I128(x) => Value::I128(x.wrapping_shl(rhs)),
1447                _ => halt!(span, "Type error"),
1448            }
1449        }
1450
1451        BinaryOperation::Shr => {
1452            let rhs: u32 = match rhs {
1453                Value::U8(y) => (*y).into(),
1454                Value::U16(y) => (*y).into(),
1455                Value::U32(y) => *y,
1456                _ => halt!(span, "Type error"),
1457            };
1458
1459            match lhs {
1460                Value::U8(_) | Value::I8(_) if rhs >= 8 => halt!(span, "shr overflow"),
1461                Value::U16(_) | Value::I16(_) if rhs >= 16 => halt!(span, "shr overflow"),
1462                Value::U32(_) | Value::I32(_) if rhs >= 32 => halt!(span, "shr overflow"),
1463                Value::U64(_) | Value::I64(_) if rhs >= 64 => halt!(span, "shr overflow"),
1464                Value::U128(_) | Value::I128(_) if rhs >= 128 => halt!(span, "shr overflow"),
1465                _ => {}
1466            }
1467
1468            lhs.simple_shr(rhs)
1469        }
1470
1471        BinaryOperation::ShrWrapped => {
1472            let rhs: u32 = match rhs {
1473                Value::U8(y) => (*y).into(),
1474                Value::U16(y) => (*y).into(),
1475                Value::U32(y) => *y,
1476                _ => halt!(span, "Type error"),
1477            };
1478
1479            match lhs {
1480                Value::U8(x) => Value::U8(x.wrapping_shr(rhs)),
1481                Value::U16(x) => Value::U16(x.wrapping_shr(rhs)),
1482                Value::U32(x) => Value::U32(x.wrapping_shr(rhs)),
1483                Value::U64(x) => Value::U64(x.wrapping_shr(rhs)),
1484                Value::U128(x) => Value::U128(x.wrapping_shr(rhs)),
1485                Value::I8(x) => Value::I8(x.wrapping_shr(rhs)),
1486                Value::I16(x) => Value::I16(x.wrapping_shr(rhs)),
1487                Value::I32(x) => Value::I32(x.wrapping_shr(rhs)),
1488                Value::I64(x) => Value::I64(x.wrapping_shr(rhs)),
1489                Value::I128(x) => Value::I128(x.wrapping_shr(rhs)),
1490                _ => halt!(span, "Type error"),
1491            }
1492        }
1493
1494        BinaryOperation::Sub => {
1495            let Some(value) = (match (lhs, rhs) {
1496                (Value::U8(x), Value::U8(y)) => x.checked_sub(*y).map(Value::U8),
1497                (Value::U16(x), Value::U16(y)) => x.checked_sub(*y).map(Value::U16),
1498                (Value::U32(x), Value::U32(y)) => x.checked_sub(*y).map(Value::U32),
1499                (Value::U64(x), Value::U64(y)) => x.checked_sub(*y).map(Value::U64),
1500                (Value::U128(x), Value::U128(y)) => x.checked_sub(*y).map(Value::U128),
1501                (Value::I8(x), Value::I8(y)) => x.checked_sub(*y).map(Value::I8),
1502                (Value::I16(x), Value::I16(y)) => x.checked_sub(*y).map(Value::I16),
1503                (Value::I32(x), Value::I32(y)) => x.checked_sub(*y).map(Value::I32),
1504                (Value::I64(x), Value::I64(y)) => x.checked_sub(*y).map(Value::I64),
1505                (Value::I128(x), Value::I128(y)) => x.checked_sub(*y).map(Value::I128),
1506                (Value::Group(x), Value::Group(y)) => Some(Value::Group(*x - *y)),
1507                (Value::Field(x), Value::Field(y)) => Some(Value::Field(*x - *y)),
1508                _ => halt!(span, "Type error"),
1509            }) else {
1510                halt!(span, "sub overflow");
1511            };
1512            value
1513        }
1514
1515        BinaryOperation::SubWrapped => match (lhs, rhs) {
1516            (Value::U8(x), Value::U8(y)) => Value::U8(x.wrapping_sub(*y)),
1517            (Value::U16(x), Value::U16(y)) => Value::U16(x.wrapping_sub(*y)),
1518            (Value::U32(x), Value::U32(y)) => Value::U32(x.wrapping_sub(*y)),
1519            (Value::U64(x), Value::U64(y)) => Value::U64(x.wrapping_sub(*y)),
1520            (Value::U128(x), Value::U128(y)) => Value::U128(x.wrapping_sub(*y)),
1521            (Value::I8(x), Value::I8(y)) => Value::I8(x.wrapping_sub(*y)),
1522            (Value::I16(x), Value::I16(y)) => Value::I16(x.wrapping_sub(*y)),
1523            (Value::I32(x), Value::I32(y)) => Value::I32(x.wrapping_sub(*y)),
1524            (Value::I64(x), Value::I64(y)) => Value::I64(x.wrapping_sub(*y)),
1525            (Value::I128(x), Value::I128(y)) => Value::I128(x.wrapping_sub(*y)),
1526            _ => halt!(span, "Type error"),
1527        },
1528
1529        BinaryOperation::Xor => match (lhs, rhs) {
1530            (Value::Bool(x), Value::Bool(y)) => Value::Bool(*x ^ *y),
1531            (Value::U8(x), Value::U8(y)) => Value::U8(*x ^ *y),
1532            (Value::U16(x), Value::U16(y)) => Value::U16(*x ^ *y),
1533            (Value::U32(x), Value::U32(y)) => Value::U32(*x ^ *y),
1534            (Value::U64(x), Value::U64(y)) => Value::U64(*x ^ *y),
1535            (Value::U128(x), Value::U128(y)) => Value::U128(*x ^ *y),
1536            (Value::I8(x), Value::I8(y)) => Value::I8(*x ^ *y),
1537            (Value::I16(x), Value::I16(y)) => Value::I16(*x ^ *y),
1538            (Value::I32(x), Value::I32(y)) => Value::I32(*x ^ *y),
1539            (Value::I64(x), Value::I64(y)) => Value::I64(*x ^ *y),
1540            (Value::I128(x), Value::I128(y)) => Value::I128(*x ^ *y),
1541            _ => halt!(span, "Type error"),
1542        },
1543    };
1544    Ok(value)
1545}
1546
1547/// Evaluate a unary operation.
1548pub fn evaluate_unary(span: Span, op: UnaryOperation, value: &Value) -> Result<Value> {
1549    let value_result = match op {
1550        UnaryOperation::Abs => match value {
1551            Value::I8(x) => {
1552                if *x == i8::MIN {
1553                    halt!(span, "abs overflow");
1554                } else {
1555                    Value::I8(x.abs())
1556                }
1557            }
1558            Value::I16(x) => {
1559                if *x == i16::MIN {
1560                    halt!(span, "abs overflow");
1561                } else {
1562                    Value::I16(x.abs())
1563                }
1564            }
1565            Value::I32(x) => {
1566                if *x == i32::MIN {
1567                    halt!(span, "abs overflow");
1568                } else {
1569                    Value::I32(x.abs())
1570                }
1571            }
1572            Value::I64(x) => {
1573                if *x == i64::MIN {
1574                    halt!(span, "abs overflow");
1575                } else {
1576                    Value::I64(x.abs())
1577                }
1578            }
1579            Value::I128(x) => {
1580                if *x == i128::MIN {
1581                    halt!(span, "abs overflow");
1582                } else {
1583                    Value::I128(x.abs())
1584                }
1585            }
1586            _ => halt!(span, "Type error"),
1587        },
1588        UnaryOperation::AbsWrapped => match value {
1589            Value::I8(x) => Value::I8(x.unsigned_abs() as i8),
1590            Value::I16(x) => Value::I16(x.unsigned_abs() as i16),
1591            Value::I32(x) => Value::I32(x.unsigned_abs() as i32),
1592            Value::I64(x) => Value::I64(x.unsigned_abs() as i64),
1593            Value::I128(x) => Value::I128(x.unsigned_abs() as i128),
1594            _ => halt!(span, "Type error"),
1595        },
1596        UnaryOperation::Double => match value {
1597            Value::Field(x) => Value::Field(x.double()),
1598            Value::Group(x) => Value::Group(x.double()),
1599            _ => halt!(span, "Type error"),
1600        },
1601        UnaryOperation::Inverse => match value {
1602            Value::Field(x) => {
1603                let Ok(y) = x.inverse() else {
1604                    halt!(span, "attempt to invert 0field");
1605                };
1606                Value::Field(y)
1607            }
1608            _ => halt!(span, "Can only invert fields"),
1609        },
1610        UnaryOperation::Negate => match value {
1611            Value::I8(x) => match x.checked_neg() {
1612                None => halt!(span, "negation overflow"),
1613                Some(y) => Value::I8(y),
1614            },
1615            Value::I16(x) => match x.checked_neg() {
1616                None => halt!(span, "negation overflow"),
1617                Some(y) => Value::I16(y),
1618            },
1619            Value::I32(x) => match x.checked_neg() {
1620                None => halt!(span, "negation overflow"),
1621                Some(y) => Value::I32(y),
1622            },
1623            Value::I64(x) => match x.checked_neg() {
1624                None => halt!(span, "negation overflow"),
1625                Some(y) => Value::I64(y),
1626            },
1627            Value::I128(x) => match x.checked_neg() {
1628                None => halt!(span, "negation overflow"),
1629                Some(y) => Value::I128(y),
1630            },
1631            Value::Group(x) => Value::Group(-*x),
1632            Value::Field(x) => Value::Field(-*x),
1633            _ => halt!(span, "Type error"),
1634        },
1635        UnaryOperation::Not => match value {
1636            Value::Bool(x) => Value::Bool(!x),
1637            Value::U8(x) => Value::U8(!x),
1638            Value::U16(x) => Value::U16(!x),
1639            Value::U32(x) => Value::U32(!x),
1640            Value::U64(x) => Value::U64(!x),
1641            Value::U128(x) => Value::U128(!x),
1642            Value::I8(x) => Value::I8(!x),
1643            Value::I16(x) => Value::I16(!x),
1644            Value::I32(x) => Value::I32(!x),
1645            Value::I64(x) => Value::I64(!x),
1646            Value::I128(x) => Value::I128(!x),
1647            _ => halt!(span, "Type error"),
1648        },
1649        UnaryOperation::Square => match value {
1650            Value::Field(x) => Value::Field(x.square()),
1651            _ => halt!(span, "Can only square fields"),
1652        },
1653        UnaryOperation::SquareRoot => match value {
1654            Value::Field(x) => {
1655                let Ok(y) = x.square_root() else {
1656                    halt!(span, "square root failure");
1657                };
1658                Value::Field(y)
1659            }
1660            _ => halt!(span, "Can only apply square_root to fields"),
1661        },
1662        UnaryOperation::ToXCoordinate => match value {
1663            Value::Group(x) => Value::Field(x.to_x_coordinate()),
1664            _ => tc_fail!(),
1665        },
1666        UnaryOperation::ToYCoordinate => match value {
1667            Value::Group(x) => Value::Field(x.to_y_coordinate()),
1668            _ => tc_fail!(),
1669        },
1670    };
1671
1672    Ok(value_result)
1673}
1674
1675pub fn literal_to_value(literal: &Literal) -> Result<Value> {
1676    // SnarkVM will not parse fields, groups, or scalars with
1677    // leading zeros, so we strip them out.
1678    fn prepare_snarkvm_string(s: &str, suffix: &str) -> String {
1679        // If there's a `-`, separate it from the rest of the string.
1680        let (neg, rest) = s.strip_prefix("-").map(|rest| ("-", rest)).unwrap_or(("", s));
1681        // Remove leading zeros.
1682        let mut rest = rest.trim_start_matches('0');
1683        if rest.is_empty() {
1684            rest = "0";
1685        }
1686        format!("{neg}{rest}{suffix}")
1687    }
1688
1689    let value = match &literal.variant {
1690        LiteralVariant::Boolean(b) => Value::Bool(*b),
1691        LiteralVariant::Integer(IntegerType::U8, s, ..) => {
1692            let s = s.replace("_", "");
1693            Value::U8(u8::from_str_by_radix(&s).expect("Parsing guarantees this works."))
1694        }
1695        LiteralVariant::Integer(IntegerType::U16, s, ..) => {
1696            let s = s.replace("_", "");
1697            Value::U16(u16::from_str_by_radix(&s).expect("Parsing guarantees this works."))
1698        }
1699        LiteralVariant::Integer(IntegerType::U32, s, ..) => {
1700            let s = s.replace("_", "");
1701            Value::U32(u32::from_str_by_radix(&s).expect("Parsing guarantees this works."))
1702        }
1703        LiteralVariant::Integer(IntegerType::U64, s, ..) => {
1704            let s = s.replace("_", "");
1705            Value::U64(u64::from_str_by_radix(&s).expect("Parsing guarantees this works."))
1706        }
1707        LiteralVariant::Integer(IntegerType::U128, s, ..) => {
1708            let s = s.replace("_", "");
1709            Value::U128(u128::from_str_by_radix(&s).expect("Parsing guarantees this works."))
1710        }
1711        LiteralVariant::Integer(IntegerType::I8, s, ..) => {
1712            let s = s.replace("_", "");
1713            Value::I8(i8::from_str_by_radix(&s).expect("Parsing guarantees this works."))
1714        }
1715        LiteralVariant::Integer(IntegerType::I16, s, ..) => {
1716            let s = s.replace("_", "");
1717            Value::I16(i16::from_str_by_radix(&s).expect("Parsing guarantees this works."))
1718        }
1719        LiteralVariant::Integer(IntegerType::I32, s, ..) => {
1720            let s = s.replace("_", "");
1721            Value::I32(i32::from_str_by_radix(&s).expect("Parsing guarantees this works."))
1722        }
1723        LiteralVariant::Integer(IntegerType::I64, s, ..) => {
1724            let s = s.replace("_", "");
1725            Value::I64(i64::from_str_by_radix(&s).expect("Parsing guarantees this works."))
1726        }
1727        LiteralVariant::Integer(IntegerType::I128, s, ..) => {
1728            let s = s.replace("_", "");
1729            Value::I128(i128::from_str_by_radix(&s).expect("Parsing guarantees this works."))
1730        }
1731        LiteralVariant::Field(s) => Value::Field(prepare_snarkvm_string(s, "field").parse().expect_tc(literal.span())?),
1732        LiteralVariant::Group(s) => Value::Group(prepare_snarkvm_string(s, "group").parse().expect_tc(literal.span())?),
1733        LiteralVariant::Address(s) => {
1734            if s.ends_with(".aleo") {
1735                let program_id = ProgramID::from_str(s)?;
1736                Value::Address(program_id.to_address()?)
1737            } else {
1738                Value::Address(s.parse().expect_tc(literal.span())?)
1739            }
1740        }
1741        LiteralVariant::Scalar(s) => {
1742            Value::Scalar(prepare_snarkvm_string(s, "scalar").parse().expect_tc(literal.span())?)
1743        }
1744        LiteralVariant::String(..) => tc_fail!(),
1745    };
1746
1747    Ok(value)
1748}