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