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