value.rs
   1  // Copyright (C) 2019-2025 ADnet Contributors
   2  // This file is part of the ADL library.
   3  
   4  // The ADL 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 ADL 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 ADL library. If not, see <https://www.gnu.org/licenses/>.
  16  
  17  use std::{
  18      collections::BTreeMap,
  19      fmt,
  20      hash::{Hash, Hasher},
  21      str::FromStr,
  22  };
  23  
  24  use itertools::Itertools as _;
  25  
  26  use crate::Location;
  27  
  28  use 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  };
  43  pub(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  
  52  use adl_errors::Result;
  53  use adl_span::{Span, Symbol};
  54  
  55  use crate::{Expression, IntegerType, NodeBuilder, Type};
  56  
  57  pub(crate) type CurrentNetwork = TestnetV0;
  58  
  59  pub(crate) type SvmValue = SvmValueParam<CurrentNetwork>;
  60  pub(crate) type ProgramID = ProgramIDParam<CurrentNetwork>;
  61  pub(crate) type SvmPlaintext = Plaintext<CurrentNetwork>;
  62  pub(crate) type SvmLiteral = SvmLiteralParam<CurrentNetwork>;
  63  pub(crate) type SvmIdentifier = SvmIdentifierParam<CurrentNetwork>;
  64  pub(crate) type Group = SvmGroup<CurrentNetwork>;
  65  pub(crate) type Field = SvmField<CurrentNetwork>;
  66  pub(crate) type Scalar = SvmScalar<CurrentNetwork>;
  67  pub(crate) type Address = SvmAddress<CurrentNetwork>;
  68  pub(crate) type Boolean = SvmBoolean<CurrentNetwork>;
  69  pub(crate) type Future = FutureParam<CurrentNetwork>;
  70  pub(crate) type Signature = SvmSignature<CurrentNetwork>;
  71  
  72  #[derive(Clone, Debug, Eq, PartialEq)]
  73  pub struct CompositeContents {
  74      pub path: Vec<Symbol>,
  75  }
  76  
  77  #[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
  78  pub struct Value {
  79      pub id: Option<Location>,
  80      pub(crate) contents: ValueVariants,
  81  }
  82  
  83  #[derive(Clone, Default, Debug, Eq, PartialEq)]
  84  // SnarkVM's Value is large, but that's okay.
  85  #[allow(clippy::large_enum_variant)]
  86  pub(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)]
  97  pub enum AsyncExecution {
  98      AsyncFunctionCall {
  99          function: Location,
 100          arguments: Vec<Value>,
 101      },
 102      AsyncBlock {
 103          containing_function: Location, // The function that contains the async block.
 104          block: crate::NodeID,
 105          names: BTreeMap<Vec<Symbol>, Value>, // Use a `BTreeMap` here because `HashMap` does not implement `Hash`.
 106      },
 107  }
 108  
 109  impl 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  
 124  fn hash_plaintext<H>(pt: &SvmPlaintext, state: &mut H)
 125  where
 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              // The correctness of this hash depends on the members being
 137              // in the same order for each type.
 138              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  
 151  impl 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                      // NOTE - we don't actually hash the data or owner. Thus this is
 178                      // a terrible hash function with many collisions.
 179                      // This shouldn't matter as the only place where we hash this is in
 180                      // keys for mappings, which cannot be records.
 181                  }
 182                  SvmValueParam::Future(future) => {
 183                      5u8.hash(state);
 184                      future.program_id().hash(state);
 185                      future.function_name().hash(state);
 186                      // Ditto - we don't hash the arguments.
 187                  }
 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  
 200  impl From<ValueVariants> for Value {
 201      fn from(contents: ValueVariants) -> Self {
 202          Value { id: None, contents }
 203      }
 204  }
 205  
 206  pub trait TryAsRef<T>
 207  where
 208      T: ?Sized,
 209  {
 210      fn try_as_ref(&self) -> Option<&T>;
 211  }
 212  
 213  macro_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  
 263  impl_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  
 277  macro_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  
 302  impl_from_literal! {
 303      Field; Group; Scalar; Address;
 304  }
 305  
 306  impl 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  
 320  impl From<Future> for Value {
 321      fn from(value: Future) -> Self {
 322          SvmValueParam::Future(value).into()
 323      }
 324  }
 325  
 326  impl 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  
 335  impl From<SvmLiteral> for Value {
 336      fn from(x: SvmLiteral) -> Self {
 337          ValueVariants::Svm(SvmValueParam::Plaintext(Plaintext::Literal(x, Default::default()))).into()
 338      }
 339  }
 340  
 341  impl 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  
 349  impl 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  
 357  impl 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  
 363  impl From<SvmPlaintext> for Value {
 364      fn from(x: SvmPlaintext) -> Self {
 365          ValueVariants::Svm(SvmValueParam::Plaintext(x)).into()
 366      }
 367  }
 368  
 369  impl From<SvmValue> for Value {
 370      fn from(x: SvmValue) -> Self {
 371          ValueVariants::Svm(x).into()
 372      }
 373  }
 374  
 375  impl From<Vec<AsyncExecution>> for Value {
 376      fn from(x: Vec<AsyncExecution>) -> Self {
 377          ValueVariants::Future(x).into()
 378      }
 379  }
 380  
 381  impl 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  
 389  impl 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  
 412  impl 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      /// Return the group generator.
 555      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}.alpha")).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          // Find the owner, storing the other contents for later.
 748          let mut non_owners = Vec::new();
 749          // let mut non_owners: Vec<(SvmIdentifier, SvmPlaintext)> = Vec::new();
 750          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(), // Just an arbitrary nonce.
 772                  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      /// Gets the type of a `Value` but only if it is an integer, a field, a group, or a scalar.
 800      /// Return `None` otherwise. These are the only types that an unsuffixed literal can have.
 801      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(value) => Literal::string(value.clone(), span, id).into(),
 868          };
 869  
 870          Some(expression)
 871      }
 872  }
 873  
 874  #[allow(clippy::type_complexity)]
 875  fn 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, CompositeExpression, CompositeFieldInitializer, Identifier, IntegerType, Literal};
 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                  // Strip off the `field` suffix.
 895                  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                  // Strip off the `group` suffix.
 901                  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                  // Strip off the `scalar` suffix.
 907                  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              CompositeExpression {
 930                  span,
 931                  id,
 932                  path: composite_type.path.clone(),
 933                  // If we were able to construct a Value, the const arguments must have already been resolved
 934                  // and inserted appropriately.
 935                  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(CompositeFieldInitializer {
 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  
 977  impl FromStr for Value {
 978      type Err = ();
 979  
 980      fn from_str(s: &str) -> Result<Self, Self::Err> {
 981          // Either it's a unit.
 982          if s == "()" {
 983              return Ok(Value::make_unit());
 984          }
 985  
 986          // Or it's a tuple.
 987          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          // Or it's an unsuffixed numeric literal.
1001          if s.chars().all(|c| c == '_' || c.is_ascii_digit()) {
1002              return Ok(ValueVariants::Unsuffixed(s.to_string()).into());
1003          }
1004  
1005          // Or it's a snarkvm value.
1006          let value: SvmValue = s.parse().map_err(|_| ())?;
1007          Ok(value.into())
1008      }
1009  }