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