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