leo_ast/interpreter_value/
value.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 std::{
18    collections::BTreeMap,
19    fmt,
20    hash::{Hash, Hasher},
21    str::FromStr,
22};
23
24use itertools::Itertools as _;
25
26use snarkvm::prelude::{
27    Access,
28    Address as SvmAddress,
29    Argument,
30    Boolean as SvmBoolean,
31    Entry,
32    Field as SvmField,
33    Future as FutureParam,
34    Group as SvmGroup,
35    LiteralType,
36    Owner,
37    ProgramID as ProgramIDParam,
38    Record,
39    Scalar as SvmScalar,
40};
41pub(crate) use snarkvm::prelude::{
42    Identifier as SvmIdentifierParam,
43    Literal as SvmLiteralParam,
44    Plaintext,
45    TestnetV0,
46    Value as SvmValueParam,
47};
48
49use leo_errors::Result;
50use leo_span::{Span, Symbol};
51
52use crate::{Expression, IntegerType, NodeBuilder, Type};
53
54pub(crate) type CurrentNetwork = TestnetV0;
55
56pub(crate) type SvmValue = SvmValueParam<CurrentNetwork>;
57pub(crate) type ProgramID = ProgramIDParam<CurrentNetwork>;
58pub(crate) type SvmPlaintext = Plaintext<CurrentNetwork>;
59pub(crate) type SvmLiteral = SvmLiteralParam<CurrentNetwork>;
60pub(crate) type SvmIdentifier = SvmIdentifierParam<CurrentNetwork>;
61pub(crate) type Group = SvmGroup<CurrentNetwork>;
62pub(crate) type Field = SvmField<CurrentNetwork>;
63pub(crate) type Scalar = SvmScalar<CurrentNetwork>;
64pub(crate) type Address = SvmAddress<CurrentNetwork>;
65pub(crate) type Boolean = SvmBoolean<CurrentNetwork>;
66pub(crate) type Future = FutureParam<CurrentNetwork>;
67
68/// Global values - such as mappings, functions, etc -
69/// are identified by program and name.
70#[derive(Clone, Debug, Hash, Eq, PartialEq)]
71pub struct GlobalId {
72    pub program: Symbol,
73    pub path: Vec<Symbol>,
74}
75
76#[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
77pub struct Value {
78    pub id: Option<GlobalId>,
79    pub(crate) contents: ValueVariants,
80}
81
82#[derive(Clone, Default, Debug, Eq, PartialEq)]
83// SnarkVM's Value is large, but that's okay.
84#[allow(clippy::large_enum_variant)]
85pub(crate) enum ValueVariants {
86    #[default]
87    Unit,
88    Svm(SvmValue),
89    Tuple(Vec<Value>),
90    Unsuffixed(String),
91    Future(Vec<AsyncExecution>),
92}
93
94#[derive(Clone, Debug, Eq, PartialEq, Hash)]
95pub enum AsyncExecution {
96    AsyncFunctionCall {
97        function: GlobalId,
98        arguments: Vec<Value>,
99    },
100    AsyncBlock {
101        containing_function: GlobalId, // The function that contains the async block.
102        block: crate::NodeID,
103        names: BTreeMap<Vec<Symbol>, Value>, // Use a `BTreeMap` here because `HashMap` does not implement `Hash`.
104    },
105}
106
107impl fmt::Display for AsyncExecution {
108    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109        write!(f, " async call to ")?;
110
111        match self {
112            AsyncExecution::AsyncFunctionCall { function, .. } => {
113                write!(f, "{function}")
114            }
115            AsyncExecution::AsyncBlock { containing_function, .. } => {
116                write!(f, "{containing_function}/<async block>")
117            }
118        }
119    }
120}
121
122fn hash_plaintext<H>(pt: &SvmPlaintext, state: &mut H)
123where
124    H: Hasher,
125{
126    match pt {
127        Plaintext::Literal(literal, ..) => {
128            6u8.hash(state);
129            literal.hash(state);
130        }
131        Plaintext::Struct(index_map, ..) => {
132            7u8.hash(state);
133            index_map.len().hash(state);
134            // The correctness of this hash depends on the members being
135            // in the same order for each type.
136            index_map.iter().for_each(|(key, value)| {
137                key.hash(state);
138                hash_plaintext(value, state);
139            });
140        }
141        Plaintext::Array(vec, ..) => {
142            8u8.hash(state);
143            vec.len().hash(state);
144            vec.iter().for_each(|pt0| hash_plaintext(pt0, state));
145        }
146    }
147}
148
149impl Hash for ValueVariants {
150    fn hash<H>(&self, state: &mut H)
151    where
152        H: Hasher,
153    {
154        use ValueVariants::*;
155
156        match self {
157            Unit => 0u8.hash(state),
158            Tuple(vec) => {
159                1u8.hash(state);
160                vec.len().hash(state);
161            }
162            Unsuffixed(s) => {
163                2u8.hash(state);
164                s.hash(state);
165            }
166            Future(async_executions) => {
167                3u8.hash(state);
168                async_executions.hash(state);
169            }
170            Svm(value) => match value {
171                SvmValueParam::Record(record) => {
172                    4u8.hash(state);
173                    (**record.version()).hash(state);
174                    record.nonce().hash(state);
175                    // NOTE - we don't actually hash the data or owner. Thus this is
176                    // a terrible hash function with many collisions.
177                    // This shouldn't matter as the only place where we hash this is in
178                    // keys for mappings, which cannot be records.
179                }
180                SvmValueParam::Future(future) => {
181                    5u8.hash(state);
182                    future.program_id().hash(state);
183                    future.function_name().hash(state);
184                    // Ditto - we don't hash the arguments.
185                }
186                SvmValueParam::Plaintext(plaintext) => {
187                    hash_plaintext(plaintext, state);
188                }
189            },
190        }
191    }
192}
193
194impl From<ValueVariants> for Value {
195    fn from(contents: ValueVariants) -> Self {
196        Value { id: None, contents }
197    }
198}
199
200impl fmt::Display for GlobalId {
201    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
202        write!(f, "{}.aleo/{}", self.program, self.path.iter().format("::"))
203    }
204}
205
206pub trait TryAsRef<T>
207where
208    T: ?Sized,
209{
210    fn try_as_ref(&self) -> Option<&T>;
211}
212
213macro_rules! impl_from_integer {
214    ($($int_type: ident $variant: ident);* $(;)?) => {
215        $(
216            impl From<$int_type> for Value {
217                fn from(value: $int_type) -> Self {
218                    ValueVariants::Svm(
219                        SvmValueParam::Plaintext(
220                            Plaintext::Literal(
221                                snarkvm::prelude::$variant::new(value).into(),
222                                Default::default(),
223                            )
224                        )
225                    ).into()
226                }
227            }
228
229            impl From<snarkvm::prelude::$variant<CurrentNetwork>> for Value {
230                fn from(x: snarkvm::prelude::$variant<CurrentNetwork>) -> Self {
231                    ValueVariants::Svm(SvmValueParam::Plaintext(
232                        Plaintext::Literal(
233                            SvmLiteralParam::$variant(x),
234                            Default::default()
235                        )
236                    )).into()
237                }
238            }
239
240            impl TryFrom<Value> for $int_type {
241                type Error = ();
242
243                fn try_from(value: Value) -> Result<$int_type, Self::Error> {
244                    match value.contents {
245                        ValueVariants::Svm(SvmValueParam::Plaintext(Plaintext::Literal(SvmLiteralParam::$variant(x), _))) => Ok(*x),
246                        _ => Err(()),
247                    }
248                }
249            }
250
251            impl TryAsRef<$int_type> for Value {
252                fn try_as_ref(&self) -> Option<&$int_type> {
253                    match &self.contents {
254                        ValueVariants::Svm(SvmValueParam::Plaintext(Plaintext::Literal(SvmLiteralParam::$variant(x), _))) => Some(&*x),
255                        _ => None,
256                    }
257                }
258            }
259        )*
260    };
261}
262
263impl_from_integer! {
264    u8 U8;
265    u16 U16;
266    u32 U32;
267    u64 U64;
268    u128 U128;
269    i8 I8;
270    i16 I16;
271    i32 I32;
272    i64 I64;
273    i128 I128;
274    bool Boolean;
275}
276
277macro_rules! impl_from_literal {
278    ($($type_: ident);* $(;)?) => {
279        $(
280            impl From<snarkvm::prelude::$type_<CurrentNetwork>> for Value {
281                fn from(x: snarkvm::prelude::$type_<CurrentNetwork>) -> Self {
282                    let literal: SvmLiteral = x.into();
283                    ValueVariants::Svm(SvmValueParam::Plaintext(Plaintext::Literal(literal, Default::default()))).into()
284                }
285            }
286
287            impl TryFrom<Value> for snarkvm::prelude::$type_<CurrentNetwork> {
288                type Error = ();
289
290                fn try_from(x: Value) -> Result<Self, Self::Error> {
291                    if let ValueVariants::Svm(SvmValueParam::Plaintext(Plaintext::Literal(SvmLiteralParam::$type_(val), ..))) = x.contents {
292                        Ok(val)
293                    } else {
294                        Err(())
295                    }
296                }
297            }
298        )*
299    };
300}
301
302impl_from_literal! {
303    Field; Group; Scalar; Address;
304}
305
306impl From<Future> for Value {
307    fn from(value: Future) -> Self {
308        SvmValueParam::Future(value).into()
309    }
310}
311
312impl TryAsRef<SvmLiteral> for Value {
313    fn try_as_ref(&self) -> Option<&SvmLiteral> {
314        match &self.contents {
315            ValueVariants::Svm(SvmValueParam::Plaintext(Plaintext::Literal(literal, ..))) => Some(literal),
316            _ => None,
317        }
318    }
319}
320
321impl From<SvmLiteral> for Value {
322    fn from(x: SvmLiteral) -> Self {
323        ValueVariants::Svm(SvmValueParam::Plaintext(Plaintext::Literal(x, Default::default()))).into()
324    }
325}
326
327impl TryFrom<Value> for SvmValue {
328    type Error = ();
329
330    fn try_from(value: Value) -> Result<Self, Self::Error> {
331        if let ValueVariants::Svm(x) = value.contents { Ok(x) } else { Err(()) }
332    }
333}
334
335impl TryFrom<Value> for SvmPlaintext {
336    type Error = ();
337
338    fn try_from(value: Value) -> Result<Self, Self::Error> {
339        if let ValueVariants::Svm(SvmValueParam::Plaintext(x)) = value.contents { Ok(x) } else { Err(()) }
340    }
341}
342
343impl TryAsRef<SvmPlaintext> for Value {
344    fn try_as_ref(&self) -> Option<&SvmPlaintext> {
345        if let ValueVariants::Svm(SvmValueParam::Plaintext(x)) = &self.contents { Some(x) } else { None }
346    }
347}
348
349impl From<SvmPlaintext> for Value {
350    fn from(x: SvmPlaintext) -> Self {
351        ValueVariants::Svm(SvmValueParam::Plaintext(x)).into()
352    }
353}
354
355impl From<SvmValue> for Value {
356    fn from(x: SvmValue) -> Self {
357        ValueVariants::Svm(x).into()
358    }
359}
360
361impl From<Vec<AsyncExecution>> for Value {
362    fn from(x: Vec<AsyncExecution>) -> Self {
363        ValueVariants::Future(x).into()
364    }
365}
366
367impl fmt::Display for Value {
368    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
369        match &self.contents {
370            ValueVariants::Unit => "()".fmt(f),
371            ValueVariants::Svm(SvmValueParam::Plaintext(Plaintext::Struct(struct_, ..))) => {
372                if let Some(id) = &self.id {
373                    write!(f, "{id} ")?
374                }
375                let mut debug_map = f.debug_map();
376                for (key, value) in struct_ {
377                    debug_map.entry(key, value);
378                }
379                debug_map.finish()
380            }
381            ValueVariants::Svm(value) => value.fmt(f),
382            ValueVariants::Tuple(vec) => write!(f, "({})", vec.iter().format(", ")),
383            ValueVariants::Unsuffixed(s) => s.fmt(f),
384            ValueVariants::Future(_async_executions) => "Future".fmt(f),
385        }
386    }
387}
388
389impl Value {
390    pub fn lt(&self, rhs: &Self) -> Option<bool> {
391        use SvmLiteralParam::*;
392
393        let literal0: &SvmLiteral = self.try_as_ref()?;
394        let literal1: &SvmLiteral = rhs.try_as_ref()?;
395
396        let value = match (literal0, literal1) {
397            (I8(val0), I8(val1)) => val0 < val1,
398            (I16(val0), I16(val1)) => val0 < val1,
399            (I32(val0), I32(val1)) => val0 < val1,
400            (I64(val0), I64(val1)) => val0 < val1,
401            (I128(val0), I128(val1)) => val0 < val1,
402            (U8(val0), U8(val1)) => val0 < val1,
403            (U16(val0), U16(val1)) => val0 < val1,
404            (U32(val0), U32(val1)) => val0 < val1,
405            (U64(val0), U64(val1)) => val0 < val1,
406            (U128(val0), U128(val1)) => val0 < val1,
407            (Field(val0), Field(val1)) => val0 < val1,
408            _ => return None,
409        };
410
411        Some(value)
412    }
413
414    pub fn lte(&self, rhs: &Self) -> Option<bool> {
415        use SvmLiteralParam::*;
416
417        let literal0: &SvmLiteral = self.try_as_ref()?;
418        let literal1: &SvmLiteral = rhs.try_as_ref()?;
419
420        let value = match (literal0, literal1) {
421            (I8(val0), I8(val1)) => val0 <= val1,
422            (I16(val0), I16(val1)) => val0 <= val1,
423            (I32(val0), I32(val1)) => val0 <= val1,
424            (I64(val0), I64(val1)) => val0 <= val1,
425            (I128(val0), I128(val1)) => val0 <= val1,
426            (U8(val0), U8(val1)) => val0 <= val1,
427            (U16(val0), U16(val1)) => val0 <= val1,
428            (U32(val0), U32(val1)) => val0 <= val1,
429            (U64(val0), U64(val1)) => val0 <= val1,
430            (U128(val0), U128(val1)) => val0 <= val1,
431            (Field(val0), Field(val1)) => val0 <= val1,
432            _ => return None,
433        };
434
435        Some(value)
436    }
437
438    pub fn gt(&self, rhs: &Self) -> Option<bool> {
439        rhs.lt(self)
440    }
441
442    pub fn gte(&self, rhs: &Self) -> Option<bool> {
443        rhs.lte(self)
444    }
445
446    pub fn inc_wrapping(&self) -> Option<Self> {
447        let literal: &SvmLiteral = self.try_as_ref()?;
448
449        let value = match literal {
450            SvmLiteralParam::U8(x) => x.wrapping_add(1).into(),
451            SvmLiteralParam::U16(x) => x.wrapping_add(1).into(),
452            SvmLiteralParam::U32(x) => x.wrapping_add(1).into(),
453            SvmLiteralParam::U64(x) => x.wrapping_add(1).into(),
454            SvmLiteralParam::U128(x) => x.wrapping_add(1).into(),
455            SvmLiteralParam::I8(x) => x.wrapping_add(1).into(),
456            SvmLiteralParam::I16(x) => x.wrapping_add(1).into(),
457            SvmLiteralParam::I32(x) => x.wrapping_add(1).into(),
458            SvmLiteralParam::I64(x) => x.wrapping_add(1).into(),
459            SvmLiteralParam::I128(x) => x.wrapping_add(1).into(),
460            _ => return None,
461        };
462        Some(value)
463    }
464
465    pub fn add(&self, i: usize) -> Option<Self> {
466        let literal: &SvmLiteral = self.try_as_ref()?;
467
468        macro_rules! sum {
469            ($ty: ident, $int: ident) => {{
470                let rhs: $ty = i.try_into().ok()?;
471                (**$int + rhs).into()
472            }};
473        }
474
475        let value = match literal {
476            SvmLiteralParam::I8(int) => sum!(i8, int),
477            SvmLiteralParam::I16(int) => sum!(i16, int),
478            SvmLiteralParam::I32(int) => sum!(i32, int),
479            SvmLiteralParam::I64(int) => sum!(i64, int),
480            SvmLiteralParam::I128(int) => sum!(i128, int),
481            SvmLiteralParam::U8(int) => sum!(u8, int),
482            SvmLiteralParam::U16(int) => sum!(u16, int),
483            SvmLiteralParam::U32(int) => sum!(u32, int),
484            SvmLiteralParam::U64(int) => sum!(u64, int),
485            SvmLiteralParam::U128(int) => sum!(u128, int),
486            SvmLiteralParam::Address(..)
487            | SvmLiteralParam::Boolean(..)
488            | SvmLiteralParam::Field(..)
489            | SvmLiteralParam::Group(..)
490            | SvmLiteralParam::Scalar(..)
491            | SvmLiteralParam::Signature(..)
492            | SvmLiteralParam::String(..) => return None,
493        };
494        Some(value)
495    }
496
497    pub fn cast(&self, ty: &Type) -> Option<Self> {
498        let literal_ty = match ty {
499            Type::Address => LiteralType::Address,
500            Type::Boolean => LiteralType::Boolean,
501            Type::Field => LiteralType::Field,
502            Type::Group => LiteralType::Group,
503            Type::Integer(IntegerType::U8) => LiteralType::U8,
504            Type::Integer(IntegerType::U16) => LiteralType::U16,
505            Type::Integer(IntegerType::U32) => LiteralType::U32,
506            Type::Integer(IntegerType::U64) => LiteralType::U64,
507            Type::Integer(IntegerType::U128) => LiteralType::U128,
508            Type::Integer(IntegerType::I8) => LiteralType::I8,
509            Type::Integer(IntegerType::I16) => LiteralType::I16,
510            Type::Integer(IntegerType::I32) => LiteralType::I32,
511            Type::Integer(IntegerType::I64) => LiteralType::I64,
512            Type::Integer(IntegerType::I128) => LiteralType::I128,
513            Type::Scalar => LiteralType::Scalar,
514            Type::Signature => LiteralType::Signature,
515            Type::String => LiteralType::String,
516            _ => return None,
517        };
518
519        let literal: &SvmLiteral = self.try_as_ref()?;
520
521        Some(literal.cast(literal_ty).ok()?.into())
522    }
523
524    pub fn cast_lossy(&self, ty: &LiteralType) -> Option<Self> {
525        let ValueVariants::Svm(SvmValueParam::Plaintext(Plaintext::Literal(literal, ..))) = &self.contents else {
526            return None;
527        };
528        literal.cast_lossy(*ty).ok().map(|lit| lit.into())
529    }
530
531    /// Return the group generator.
532    pub fn generator() -> Self {
533        Group::generator().into()
534    }
535
536    pub fn as_u32(&self) -> Option<u32> {
537        let literal = self.try_as_ref()?;
538        let value = match literal {
539            SvmLiteralParam::U8(x) => **x as u32,
540            SvmLiteralParam::U16(x) => **x as u32,
541            SvmLiteralParam::U32(x) => **x,
542            SvmLiteralParam::U64(x) => (**x).try_into().ok()?,
543            SvmLiteralParam::U128(x) => (**x).try_into().ok()?,
544            SvmLiteralParam::I8(x) => (**x).try_into().ok()?,
545            SvmLiteralParam::I16(x) => (**x).try_into().ok()?,
546            SvmLiteralParam::I32(x) => (**x).try_into().ok()?,
547            SvmLiteralParam::I64(x) => (**x).try_into().ok()?,
548            SvmLiteralParam::I128(x) => (**x).try_into().ok()?,
549            _ => return None,
550        };
551        Some(value)
552    }
553
554    pub fn as_i128(&self) -> Option<i128> {
555        let literal = self.try_as_ref()?;
556        let value = match literal {
557            SvmLiteralParam::U8(x) => **x as i128,
558            SvmLiteralParam::U16(x) => **x as i128,
559            SvmLiteralParam::U32(x) => **x as i128,
560            SvmLiteralParam::U64(x) => **x as i128,
561            SvmLiteralParam::U128(x) => (**x).try_into().ok()?,
562            SvmLiteralParam::I8(x) => **x as i128,
563            SvmLiteralParam::I16(x) => **x as i128,
564            SvmLiteralParam::I32(x) => **x as i128,
565            SvmLiteralParam::I64(x) => **x as i128,
566            SvmLiteralParam::I128(x) => **x,
567            _ => return None,
568        };
569        Some(value)
570    }
571
572    pub fn array_index(&self, i: usize) -> Option<Self> {
573        let plaintext: &SvmPlaintext = self.try_as_ref()?;
574        let Plaintext::Array(array, ..) = plaintext else {
575            return None;
576        };
577
578        Some(array[i].clone().into())
579    }
580
581    pub fn array_index_set(&mut self, i: usize, value: Self) -> Option<()> {
582        let plaintext_rhs: SvmPlaintext = value.try_into().ok()?;
583
584        let ValueVariants::Svm(SvmValue::Plaintext(Plaintext::Array(arr, once_cell))) = &mut self.contents else {
585            return None;
586        };
587        *once_cell = Default::default();
588
589        *arr.get_mut(i)? = plaintext_rhs;
590
591        Some(())
592    }
593
594    pub fn tuple_len(&self) -> Option<usize> {
595        let ValueVariants::Tuple(tuple) = &self.contents else {
596            return None;
597        };
598
599        Some(tuple.len())
600    }
601
602    pub fn tuple_index(&self, i: usize) -> Option<Self> {
603        let ValueVariants::Tuple(tuple) = &self.contents else {
604            return None;
605        };
606
607        Some(tuple[i].clone())
608    }
609
610    pub fn tuple_index_set(&mut self, i: usize, value: Self) -> Option<()> {
611        let ValueVariants::Tuple(tuple) = &mut self.contents else {
612            return None;
613        };
614
615        *tuple.get_mut(i)? = value;
616
617        Some(())
618    }
619
620    pub fn as_future(&self) -> Option<&[AsyncExecution]> {
621        if let ValueVariants::Future(asyncs) = &self.contents { Some(asyncs) } else { None }
622    }
623
624    pub fn accesses(&self, accesses: impl IntoIterator<Item = Access<CurrentNetwork>>) -> Option<Value> {
625        self.accesses_impl(&mut accesses.into_iter())
626    }
627
628    fn accesses_impl(&self, accesses: &mut dyn Iterator<Item = Access<CurrentNetwork>>) -> Option<Value> {
629        let ValueVariants::Svm(SvmValueParam::Plaintext(current)) = &self.contents else {
630            return None;
631        };
632
633        let mut current = current;
634
635        for access in accesses {
636            current = match (access, current) {
637                (Access::Member(identifier), Plaintext::Struct(struct_, ..)) => struct_.get(&identifier)?,
638                (Access::Index(integer), Plaintext::Array(array, ..)) => array.get(*integer as usize)?,
639                _ => return None,
640            };
641        }
642
643        Some(current.clone().into())
644    }
645
646    pub fn member_access(&self, member: Symbol) -> Option<Self> {
647        match &self.contents {
648            ValueVariants::Svm(SvmValueParam::Plaintext(Plaintext::Struct(map, ..))) => {
649                let identifier: SvmIdentifier =
650                    member.to_string().parse().expect("Member name should be valid identifier");
651                Some(map.get(&identifier)?.clone().into())
652            }
653            _ => None,
654        }
655    }
656
657    pub fn member_set(&mut self, member: Symbol, value: Value) -> Option<()> {
658        let plaintext: SvmPlaintext = value.try_into().ok()?;
659        match &mut self.contents {
660            ValueVariants::Svm(SvmValueParam::Plaintext(Plaintext::Struct(map, once_cell))) => {
661                *once_cell = Default::default();
662                let identifier: SvmIdentifier = member.to_string().parse().ok()?;
663                *map.get_mut(&identifier)? = plaintext;
664                Some(())
665            }
666
667            _ => None,
668        }
669    }
670
671    pub fn make_future(
672        program_name: Symbol,
673        function: Symbol,
674        arguments: impl IntoIterator<Item = Value>,
675    ) -> Option<Value> {
676        Self::make_future_impl(program_name, function, &mut arguments.into_iter())
677    }
678
679    fn make_future_impl(
680        program_name: Symbol,
681        function: Symbol,
682        arguments: &mut dyn Iterator<Item = Value>,
683    ) -> Option<Value> {
684        let program = ProgramID::try_from(format!("{program_name}.aleo")).ok()?;
685
686        let function_identifier: SvmIdentifier = function.to_string().parse().ok()?;
687
688        let arguments_vec = arguments
689            .map(|value| match value.contents {
690                ValueVariants::Svm(SvmValueParam::Plaintext(plaintext)) => Some(Argument::Plaintext(plaintext)),
691                ValueVariants::Svm(SvmValueParam::Future(future)) => Some(Argument::Future(future)),
692                _ => None,
693            })
694            .collect::<Option<Vec<_>>>()?;
695
696        Some(Future::new(program, function_identifier, arguments_vec).into())
697    }
698
699    pub fn make_unit() -> Self {
700        Value { id: None, contents: ValueVariants::Unit }
701    }
702
703    pub fn make_struct(contents: impl Iterator<Item = (Symbol, Value)>, program: Symbol, path: Vec<Symbol>) -> Self {
704        let id = Some(GlobalId { program, path });
705
706        let contents = Plaintext::Struct(
707            contents
708                .map(|(symbol, value)| {
709                    let identifier =
710                        symbol.to_string().parse().expect("Invalid identifiers shouldn't have been allowed.");
711                    let plaintext = value.try_into().expect("Invalid struct members shouldn't have been allowed.");
712                    (identifier, plaintext)
713                })
714                .collect(),
715            Default::default(),
716        );
717
718        Value { id, contents: ValueVariants::Svm(contents.into()) }
719    }
720
721    pub fn make_record(contents: impl Iterator<Item = (Symbol, Value)>, program: Symbol, path: Vec<Symbol>) -> Self {
722        let id = Some(GlobalId { program, path });
723
724        // Find the owner, storing the other contents for later.
725        let mut non_owners = Vec::new();
726        // let mut non_owners: Vec<(SvmIdentifier, SvmPlaintext)> = Vec::new();
727        let symbol_owner = Symbol::intern("owner");
728        let mut opt_owner_value = None;
729        for (symbol, value) in contents {
730            if symbol == symbol_owner {
731                let owner: Address = value.try_into().expect("Owner should be an address.");
732                opt_owner_value = Some(owner);
733            } else {
734                let identifier: SvmIdentifier = symbol.to_string().parse().expect("Can't parse identifier.");
735                let plaintext: SvmPlaintext = value.try_into().expect("Record member not plaintext.");
736                non_owners.push((identifier, Entry::Public(plaintext)));
737            }
738        }
739
740        let Some(owner_value) = opt_owner_value else {
741            panic!("No owner in record.");
742        };
743
744        let contents = SvmValueParam::Record(
745            Record::<CurrentNetwork, SvmPlaintext>::from_plaintext(
746                Owner::Public(owner_value),
747                non_owners.into_iter().collect(),
748                Group::generator(), // Just an arbitrary nonce.
749                snarkvm::prelude::U8::new(1u8),
750            )
751            .expect("Failed to make record."),
752        );
753
754        Value { id, contents: ValueVariants::Svm(contents) }
755    }
756
757    pub fn make_array(contents: impl Iterator<Item = Value>) -> Self {
758        let vec = contents
759            .map(|value| {
760                let plaintext: SvmPlaintext =
761                    value.try_into().expect("Invalid array members shouldn't have been allowed.");
762                plaintext
763            })
764            .collect();
765        SvmPlaintext::Array(vec, Default::default()).into()
766    }
767
768    pub fn make_tuple(contents: impl IntoIterator<Item = Value>) -> Self {
769        ValueVariants::Tuple(contents.into_iter().collect()).into()
770    }
771
772    /// Gets the type of a `Value` but only if it is an integer, a field, a group, or a scalar.
773    /// Return `None` otherwise. These are the only types that an unsuffixed literal can have.
774    pub fn get_numeric_type(&self) -> Option<Type> {
775        use IntegerType::*;
776        use Type::*;
777        let ValueVariants::Svm(SvmValueParam::Plaintext(Plaintext::Literal(literal, ..))) = &self.contents else {
778            return None;
779        };
780        match literal {
781            SvmLiteralParam::U8(_) => Some(Integer(U8)),
782            SvmLiteralParam::U16(_) => Some(Integer(U16)),
783            SvmLiteralParam::U32(_) => Some(Integer(U32)),
784            SvmLiteralParam::U64(_) => Some(Integer(U64)),
785            SvmLiteralParam::U128(_) => Some(Integer(U128)),
786            SvmLiteralParam::I8(_) => Some(Integer(I8)),
787            SvmLiteralParam::I16(_) => Some(Integer(I16)),
788            SvmLiteralParam::I32(_) => Some(Integer(I32)),
789            SvmLiteralParam::I64(_) => Some(Integer(I64)),
790            SvmLiteralParam::I128(_) => Some(Integer(I128)),
791            SvmLiteralParam::Field(_) => Some(Field),
792            SvmLiteralParam::Group(_) => Some(Group),
793            SvmLiteralParam::Scalar(_) => Some(Scalar),
794            _ => None,
795        }
796    }
797
798    #[allow(clippy::type_complexity)]
799    pub fn to_expression(
800        &self,
801        span: Span,
802        node_builder: &NodeBuilder,
803        ty: &Type,
804        struct_lookup: &dyn Fn(&[Symbol]) -> Vec<(Symbol, Type)>,
805    ) -> Option<Expression> {
806        use crate::{Literal, TupleExpression, UnitExpression};
807
808        let id = node_builder.next_id();
809        let expression = match &self.contents {
810            ValueVariants::Unit => UnitExpression { span, id }.into(),
811            ValueVariants::Tuple(vec) => {
812                let Type::Tuple(tuple_type) = ty else {
813                    return None;
814                };
815
816                if vec.len() != tuple_type.elements().len() {
817                    return None;
818                }
819
820                TupleExpression {
821                    span,
822                    id,
823                    elements: vec
824                        .iter()
825                        .zip(tuple_type.elements())
826                        .map(|(val, ty)| val.to_expression(span, node_builder, ty, struct_lookup))
827                        .collect::<Option<Vec<_>>>()?,
828                }
829                .into()
830            }
831            ValueVariants::Unsuffixed(s) => Literal::unsuffixed(s.clone(), span, id).into(),
832            ValueVariants::Svm(value) => match value {
833                SvmValueParam::Plaintext(plaintext) => {
834                    plaintext_to_expression(plaintext, span, node_builder, ty, &struct_lookup)?
835                }
836                SvmValueParam::Record(..) => return None,
837                SvmValueParam::Future(..) => return None,
838            },
839
840            ValueVariants::Future(..) => return None,
841        };
842
843        Some(expression)
844    }
845}
846
847#[allow(clippy::type_complexity)]
848fn plaintext_to_expression(
849    plaintext: &SvmPlaintext,
850    span: Span,
851    node_builder: &NodeBuilder,
852    ty: &Type,
853    struct_lookup: &dyn Fn(&[Symbol]) -> Vec<(Symbol, Type)>,
854) -> Option<Expression> {
855    use crate::{ArrayExpression, Identifier, IntegerType, Literal, StructExpression, StructVariableInitializer};
856
857    let id = node_builder.next_id();
858
859    let expression = match plaintext {
860        Plaintext::Literal(literal, ..) => match literal {
861            SvmLiteralParam::Address(address) => {
862                Literal::address(address.to_string(), span, node_builder.next_id()).into()
863            }
864            SvmLiteralParam::Boolean(boolean) => Literal::boolean(**boolean, span, node_builder.next_id()).into(),
865            SvmLiteralParam::Field(field) => {
866                let mut s = field.to_string();
867                // Strip off the `field` suffix.
868                s.truncate(s.len() - 5);
869                Literal::field(s, span, id).into()
870            }
871            SvmLiteralParam::Group(group) => {
872                let mut s = group.to_string();
873                // Strip off the `group` suffix.
874                s.truncate(s.len() - 5);
875                Literal::group(s, span, id).into()
876            }
877            SvmLiteralParam::Scalar(scalar) => {
878                let mut s = scalar.to_string();
879                // Strip off the `scalar` suffix.
880                s.truncate(s.len() - 6);
881                Literal::scalar(s, span, id).into()
882            }
883            SvmLiteralParam::I8(int) => Literal::integer(IntegerType::I8, (**int).to_string(), span, id).into(),
884            SvmLiteralParam::I16(int) => Literal::integer(IntegerType::I16, (**int).to_string(), span, id).into(),
885            SvmLiteralParam::I32(int) => Literal::integer(IntegerType::I32, (**int).to_string(), span, id).into(),
886            SvmLiteralParam::I64(int) => Literal::integer(IntegerType::I64, (**int).to_string(), span, id).into(),
887            SvmLiteralParam::I128(int) => Literal::integer(IntegerType::I128, (**int).to_string(), span, id).into(),
888            SvmLiteralParam::U8(int) => Literal::integer(IntegerType::U8, (**int).to_string(), span, id).into(),
889            SvmLiteralParam::U16(int) => Literal::integer(IntegerType::U16, (**int).to_string(), span, id).into(),
890            SvmLiteralParam::U32(int) => Literal::integer(IntegerType::U32, (**int).to_string(), span, id).into(),
891            SvmLiteralParam::U64(int) => Literal::integer(IntegerType::U64, (**int).to_string(), span, id).into(),
892            SvmLiteralParam::U128(int) => Literal::integer(IntegerType::U128, (**int).to_string(), span, id).into(),
893            SvmLiteralParam::Signature(..) => todo!(),
894            SvmLiteralParam::String(..) => return None,
895        },
896        Plaintext::Struct(index_map, ..) => {
897            let Type::Composite(composite_type) = ty else {
898                return None;
899            };
900            let symbols = composite_type.path.as_symbols();
901            let iter_members = struct_lookup(&symbols);
902            StructExpression {
903                span,
904                id,
905                path: composite_type.path.clone(),
906                // If we were able to construct a Value, the const arguments must have already been resolved
907                // and inserted appropriately.
908                const_arguments: Vec::new(),
909                members: iter_members
910                    .into_iter()
911                    .map(|(sym, ty)| {
912                        let svm_identifier: snarkvm::prelude::Identifier<CurrentNetwork> =
913                            sym.to_string().parse().ok()?;
914                        Some(StructVariableInitializer {
915                            span,
916                            id: node_builder.next_id(),
917                            identifier: Identifier::new(sym, node_builder.next_id()),
918                            expression: Some(plaintext_to_expression(
919                                index_map.get(&svm_identifier)?,
920                                span,
921                                node_builder,
922                                &ty,
923                                &struct_lookup,
924                            )?),
925                        })
926                    })
927                    .collect::<Option<Vec<_>>>()?,
928            }
929            .into()
930        }
931        Plaintext::Array(vec, ..) => {
932            let Type::Array(array_ty) = ty else {
933                return None;
934            };
935            ArrayExpression {
936                span,
937                id,
938                elements: vec
939                    .iter()
940                    .map(|pt| plaintext_to_expression(pt, span, node_builder, &array_ty.element_type, &struct_lookup))
941                    .collect::<Option<Vec<_>>>()?,
942            }
943            .into()
944        }
945    };
946
947    Some(expression)
948}
949
950impl FromStr for Value {
951    type Err = ();
952
953    fn from_str(s: &str) -> Result<Self, Self::Err> {
954        // Either it's a unit.
955        if s == "()" {
956            return Ok(Value::make_unit());
957        }
958
959        // Or it's a tuple.
960        if let Some(s) = s.strip_prefix("(") {
961            if let Some(s) = s.strip_suffix(")") {
962                let mut results = Vec::new();
963                for item in s.split(',') {
964                    let item = item.trim();
965                    let value: Value = item.parse().map_err(|_| ())?;
966                    results.push(value);
967                }
968
969                return Ok(Value::make_tuple(results));
970            }
971        }
972
973        // Or it's an unsuffixed numeric literal.
974        if s.chars().all(|c| c == '_' || c.is_ascii_digit()) {
975            return Ok(ValueVariants::Unsuffixed(s.to_string()).into());
976        }
977
978        // Or it's a snarkvm value.
979        let value: SvmValue = s.parse().map_err(|_| ())?;
980        Ok(value.into())
981    }
982}