/ console / program / src / data / plaintext / parse.rs
parse.rs
  1  // Copyright (c) 2025-2026 ACDC Network
  2  // This file is part of the alphavm library.
  3  //
  4  // Alpha Chain | Delta Chain Protocol
  5  // International Monetary Graphite.
  6  //
  7  // Derived from Aleo (https://aleo.org) and ProvableHQ (https://provable.com).
  8  // They built world-class ZK infrastructure. We installed the EASY button.
  9  // Their cryptography: elegant. Our modifications: bureaucracy-compatible.
 10  // Original brilliance: theirs. Robert's Rules: ours. Bugs: definitely ours.
 11  //
 12  // Original Aleo/ProvableHQ code subject to Apache 2.0 https://www.apache.org/licenses/LICENSE-2.0
 13  // All modifications and new work: CC0 1.0 Universal Public Domain Dedication.
 14  // No rights reserved. No permission required. No warranty. No refunds.
 15  //
 16  // https://creativecommons.org/publicdomain/zero/1.0/
 17  // SPDX-License-Identifier: CC0-1.0
 18  
 19  use super::*;
 20  
 21  impl<N: Network> Parser for Plaintext<N> {
 22      /// Parses a string into a plaintext value.
 23      #[inline]
 24      fn parse(string: &str) -> ParserResult<'_, Self> {
 25          // Parse the string into a plaintext value.
 26          Self::parse_internal(string, 0)
 27      }
 28  }
 29  
 30  impl<N: Network> Plaintext<N> {
 31      /// Parses a sanitized pair: `identifier: plaintext`.
 32      fn parse_pair(string: &str, depth: usize) -> ParserResult<'_, (Identifier<N>, Self)> {
 33          // Parse the whitespace and comments from the string.
 34          let (string, _) = Sanitizer::parse(string)?;
 35          // Parse the identifier from the string.
 36          let (string, identifier) = Identifier::parse(string)?;
 37          // Parse the whitespace from the string.
 38          let (string, _) = Sanitizer::parse_whitespaces(string)?;
 39          // Parse the ":" from the string.
 40          let (string, _) = tag(":")(string)?;
 41          // Parse the plaintext from the string.
 42          let (string, plaintext) = Self::parse_internal(string, depth + 1)?;
 43          // Parse the whitespace from the string.
 44          let (string, _) = Sanitizer::parse_whitespaces(string)?;
 45          // Return the identifier and plaintext.
 46          Ok((string, (identifier, plaintext)))
 47      }
 48  
 49      /// Parses a plaintext as a struct: `{ identifier_0: plaintext_0, ..., identifier_n: plaintext_n }`.
 50      fn parse_struct(string: &str, depth: usize) -> ParserResult<'_, Self> {
 51          // Parse the whitespace and comments from the string.
 52          let (string, _) = Sanitizer::parse(string)?;
 53          // Parse the "{" from the string.
 54          let (string, _) = tag("{")(string)?;
 55          // Parse the members.
 56          let (string, members) =
 57              map_res(separated_list1(tag(","), |input| Self::parse_pair(input, depth)), |members: Vec<_>| {
 58                  // Ensure the members has no duplicate names.
 59                  if has_duplicates(members.iter().map(|(name, ..)| name)) {
 60                      return Err(error("Duplicate member in struct"));
 61                  }
 62                  // Ensure the number of structs is within the maximum limit.
 63                  match members.len() <= N::MAX_STRUCT_ENTRIES {
 64                      true => Ok(members),
 65                      false => Err(error(format!("Found a plaintext that exceeds size ({})", members.len()))),
 66                  }
 67              })(string)?;
 68          // Parse the whitespace and comments from the string.
 69          let (string, _) = Sanitizer::parse(string)?;
 70          // Parse the '}' from the string.
 71          let (string, _) = tag("}")(string)?;
 72          // Output the plaintext.
 73          Ok((string, Self::Struct(IndexMap::from_iter(members), Default::default())))
 74      }
 75  
 76      /// Parses a plaintext as an array: `[plaintext_0, ..., plaintext_n]`.
 77      fn parse_array(string: &str, depth: usize) -> ParserResult<'_, Self> {
 78          // Parse the whitespace and comments from the string.
 79          let (string, _) = Sanitizer::parse(string)?;
 80          // Parse the "[" from the string.
 81          let (string, _) = tag("[")(string)?;
 82          // Parse the members.
 83          let (string, members) = separated_list1(tag(","), |input| Self::parse_internal(input, depth + 1))(string)?;
 84          // Parse the whitespace and comments from the string.
 85          let (string, _) = Sanitizer::parse(string)?;
 86          // Parse the ']' from the string.
 87          let (string, _) = tag("]")(string)?;
 88          // Output the plaintext.
 89          Ok((string, Self::Array(members, Default::default())))
 90      }
 91  
 92      /// Parses a string into a plaintext value, while tracking the depth of the data.
 93      fn parse_internal(string: &str, depth: usize) -> ParserResult<'_, Self> {
 94          // Ensure that the depth is within the maximum limit.
 95          if depth > N::MAX_DATA_DEPTH {
 96              return map_res(take(0usize), |_| {
 97                  Err(error(format!("Found a plaintext that exceeds maximum data depth ({})", N::MAX_DATA_DEPTH)))
 98              })(string);
 99          }
100          // Parse the whitespace and comments from the string.
101          let (string, _) = Sanitizer::parse(string)?;
102          // Parse the struct or array from the string.
103          // Parse to determine the plaintext (order matters).
104          alt((
105              // Parse a plaintext literal.
106              map(Literal::parse, |literal| Self::Literal(literal, Default::default())),
107              // Parse a plaintext struct.
108              |input| Self::parse_struct(input, depth),
109              // Parse a plaintext array.
110              |input| Self::parse_array(input, depth),
111          ))(string)
112      }
113  }
114  
115  impl<N: Network> FromStr for Plaintext<N> {
116      type Err = Error;
117  
118      /// Returns a plaintext from a string literal.
119      fn from_str(string: &str) -> Result<Self> {
120          match Self::parse(string) {
121              Ok((remainder, object)) => {
122                  // Ensure the remainder is empty.
123                  ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
124                  // Return the object.
125                  Ok(object)
126              }
127              Err(error) => bail!("Failed to parse string. {error}"),
128          }
129      }
130  }
131  
132  impl<N: Network> Debug for Plaintext<N> {
133      /// Prints the plaintext as a string.
134      fn fmt(&self, f: &mut Formatter) -> fmt::Result {
135          Display::fmt(self, f)
136      }
137  }
138  
139  impl<N: Network> Display for Plaintext<N> {
140      /// Prints the plaintext as a string.
141      fn fmt(&self, f: &mut Formatter) -> fmt::Result {
142          self.fmt_internal(f, 0)
143      }
144  }
145  
146  impl<N: Network> Plaintext<N> {
147      /// Prints the plaintext with the given indentation depth.
148      fn fmt_internal(&self, f: &mut Formatter, depth: usize) -> fmt::Result {
149          /// The number of spaces to indent.
150          const INDENT: usize = 2;
151  
152          match self {
153              // Prints the literal, i.e. 10field
154              Self::Literal(literal, ..) => write!(f, "{:indent$}{literal}", "", indent = depth * INDENT),
155              // Prints the struct, i.e. { first: 10i64, second: 198u64 }
156              Self::Struct(struct_, ..) => {
157                  // Print the opening brace.
158                  write!(f, "{{")?;
159                  // Print the members.
160                  struct_.iter().enumerate().try_for_each(|(i, (name, plaintext))| {
161                      match plaintext {
162                          Self::Literal(literal, ..) => match i == struct_.len() - 1 {
163                              true => {
164                                  // Print the last member without a comma.
165                                  write!(f, "\n{:indent$}{name}: {literal}", "", indent = (depth + 1) * INDENT)?;
166                                  // Print the closing brace.
167                                  write!(f, "\n{:indent$}}}", "", indent = depth * INDENT)
168                              }
169                              // Print the member with a comma.
170                              false => write!(f, "\n{:indent$}{name}: {literal},", "", indent = (depth + 1) * INDENT),
171                          },
172                          Self::Struct(..) | Self::Array(..) => {
173                              // Print the member name.
174                              write!(f, "\n{:indent$}{name}: ", "", indent = (depth + 1) * INDENT)?;
175                              // Print the member.
176                              plaintext.fmt_internal(f, depth + 1)?;
177                              // Print the closing brace.
178                              match i == struct_.len() - 1 {
179                                  // Print the last member without a comma.
180                                  true => write!(f, "\n{:indent$}}}", "", indent = depth * INDENT),
181                                  // Print the member with a comma.
182                                  false => write!(f, ","),
183                              }
184                          }
185                      }
186                  })
187              }
188              // Prints the array, i.e. [ 10u64, 198u64 ]
189              Self::Array(array, ..) => {
190                  // Print the opening bracket.
191                  write!(f, "[")?;
192                  // Print the members.
193                  array.iter().enumerate().try_for_each(|(i, plaintext)| {
194                      match plaintext {
195                          Self::Literal(literal, ..) => match i == array.len() - 1 {
196                              true => {
197                                  // Print the last member without a comma.
198                                  write!(f, "\n{:indent$}{literal}", "", indent = (depth + 1) * INDENT)?;
199                                  // Print the closing bracket.
200                                  write!(f, "\n{:indent$}]", "", indent = depth * INDENT)
201                              }
202                              // Print the member with a comma.
203                              false => write!(f, "\n{:indent$}{literal},", "", indent = (depth + 1) * INDENT),
204                          },
205                          Self::Struct(..) | Self::Array(..) => {
206                              // Print a newline.
207                              write!(f, "\n{:indent$}", "", indent = (depth + 1) * INDENT)?;
208                              // Print the member.
209                              plaintext.fmt_internal(f, depth + 1)?;
210                              // Print the closing brace.
211                              match i == array.len() - 1 {
212                                  // Print the last member without a comma.
213                                  true => write!(f, "\n{:indent$}]", "", indent = depth * INDENT),
214                                  // Print the member with a comma.
215                                  false => write!(f, ","),
216                              }
217                          }
218                      }
219                  })
220              }
221          }
222      }
223  }
224  
225  #[cfg(test)]
226  mod tests {
227      use super::*;
228      use alphavm_console_network::MainnetV0;
229  
230      type CurrentNetwork = MainnetV0;
231  
232      #[test]
233      fn test_parse_literal() -> Result<()> {
234          // Sanity check.
235          let (remainder, candidate) = Plaintext::<CurrentNetwork>::parse("5u8")?;
236          assert_eq!("5u8", candidate.to_string());
237          assert_eq!("", remainder);
238  
239          Ok(())
240      }
241  
242      #[test]
243      fn test_parse_struct() -> Result<()> {
244          // Sanity check.
245          let expected = r"{
246    foo: 5u8
247  }";
248          let (remainder, candidate) = Plaintext::<CurrentNetwork>::parse("{ foo: 5u8 }")?;
249          assert_eq!(expected, candidate.to_string());
250          assert_eq!("", remainder);
251  
252          let expected = r"{
253    foo: 5u8,
254    bar: {
255      baz: 10field,
256      qux: {
257        quux: {
258          corge: {
259            grault: {
260              garply: {
261                waldo: {
262                  fred: {
263                    plugh: {
264                      xyzzy: {
265                        thud: true
266                      }
267                    }
268                  }
269                }
270              }
271            }
272          }
273        }
274      }
275    }
276  }";
277          let (remainder, candidate) = Plaintext::<CurrentNetwork>::parse(
278              "{ foo: 5u8, bar: { baz: 10field, qux: {quux:{corge :{grault:  {garply:{waldo:{fred:{plugh:{xyzzy: { thud: true}} }}}  }}}}}}",
279          )?;
280          println!("\nExpected: {expected}\n\nFound: {candidate}\n");
281          assert_eq!(expected, candidate.to_string());
282          assert_eq!("", remainder);
283  
284          Ok(())
285      }
286  
287      #[test]
288      fn test_parse_fails() {
289          // Must be non-empty.
290          assert!(Plaintext::<CurrentNetwork>::parse("").is_err());
291          assert!(Plaintext::<CurrentNetwork>::parse("{}").is_err());
292  
293          // Invalid characters.
294          assert!(Plaintext::<CurrentNetwork>::parse("_").is_err());
295          assert!(Plaintext::<CurrentNetwork>::parse("__").is_err());
296          assert!(Plaintext::<CurrentNetwork>::parse("___").is_err());
297          assert!(Plaintext::<CurrentNetwork>::parse("-").is_err());
298          assert!(Plaintext::<CurrentNetwork>::parse("--").is_err());
299          assert!(Plaintext::<CurrentNetwork>::parse("---").is_err());
300          assert!(Plaintext::<CurrentNetwork>::parse("*").is_err());
301          assert!(Plaintext::<CurrentNetwork>::parse("**").is_err());
302          assert!(Plaintext::<CurrentNetwork>::parse("***").is_err());
303  
304          // Must not start with a number.
305          assert!(Plaintext::<CurrentNetwork>::parse("1").is_err());
306          assert!(Plaintext::<CurrentNetwork>::parse("2").is_err());
307          assert!(Plaintext::<CurrentNetwork>::parse("3").is_err());
308          assert!(Plaintext::<CurrentNetwork>::parse("1foo").is_err());
309          assert!(Plaintext::<CurrentNetwork>::parse("12").is_err());
310          assert!(Plaintext::<CurrentNetwork>::parse("111").is_err());
311  
312          // Must fit within the data capacity of a base field element.
313          let plaintext =
314              Plaintext::<CurrentNetwork>::parse("foo_bar_baz_qux_quux_quuz_corge_grault_garply_waldo_fred_plugh_xyzzy");
315          assert!(plaintext.is_err());
316      }
317  
318      #[test]
319      fn test_nested_structs1() {
320          let expected = r"{
321    r1: {
322      c1: 1u8,
323      c2: 2u8,
324      c3: 1u8
325    },
326    r2: {
327      c1: 2u8,
328      c2: 2u8,
329      c3: 1u8
330    },
331    r3: {
332      c1: 1u8,
333      c2: 2u8,
334      c3: 1u8
335    }
336  }";
337  
338          let (remainder, candidate) = Plaintext::<CurrentNetwork>::parse(expected).unwrap();
339          println!("\nExpected: {expected}\n\nFound: {candidate}\n");
340          assert_eq!(expected, candidate.to_string());
341          assert_eq!("", remainder);
342      }
343  
344      #[test]
345      fn test_nested_structs2() {
346          let expected = r"{
347    foo: {
348      bar: {
349        baz: 1u8
350      },
351      qux: {
352        quux: 2u8
353      }
354    }
355  }";
356  
357          let (remainder, candidate) = Plaintext::<CurrentNetwork>::parse(expected).unwrap();
358          println!("\nExpected: {expected}\n\nFound: {candidate}\n");
359          assert_eq!(expected, candidate.to_string());
360          assert_eq!("", remainder);
361      }
362  
363      #[test]
364      fn test_nested_structs3() {
365          let expected = r"{
366    c: {
367      a: 0u8,
368      b: 1u8
369    },
370    d: {
371      a: 0u8,
372      b: 1u8
373    }
374  }";
375  
376          let (remainder, candidate) = Plaintext::<CurrentNetwork>::parse(expected).unwrap();
377          println!("\nExpected: {expected}\n\nFound: {candidate}\n");
378          assert_eq!(expected, candidate.to_string());
379          assert_eq!("", remainder);
380      }
381  
382      #[test]
383      fn test_array() {
384          // Test an array of literals.
385          let expected = r"[
386    1u8,
387    2u8,
388    3u8
389  ]";
390          let (remainder, candidate) = Plaintext::<CurrentNetwork>::parse(expected).unwrap();
391          println!("\nExpected: {expected}\n\nFound: {candidate}\n");
392          assert_eq!(expected, candidate.to_string());
393          assert_eq!("", remainder);
394  
395          // Test an array of structs.
396          let expected = r"[
397    {
398      foo: 1u8,
399      bar: 2u8
400    },
401    {
402      foo: 3u8,
403      bar: 4u8
404    },
405    {
406      foo: 5u8,
407      bar: 6u8
408    }
409  ]";
410          let (remainder, candidate) = Plaintext::<CurrentNetwork>::parse(expected).unwrap();
411          println!("\nExpected: {expected}\n\nFound: {candidate}\n");
412          assert_eq!(expected, candidate.to_string());
413          assert_eq!("", remainder);
414      }
415  
416      #[test]
417      fn test_struct_with_arrays() {
418          let expected = r"{
419    foo: [
420      1u8,
421      2u8,
422      3u8
423    ],
424    bar: [
425      4u8,
426      5u8,
427      6u8
428    ]
429  }";
430          let (remainder, candidate) = Plaintext::<CurrentNetwork>::parse(expected).unwrap();
431          println!("\nExpected: {expected}\n\nFound: {candidate}\n");
432          assert_eq!(expected, candidate.to_string());
433          assert_eq!("", remainder);
434      }
435  
436      #[test]
437      fn test_struct_with_array_of_structs() {
438          let expected = r"{
439    foo: [
440      {
441        foo: 1u8,
442        bar: 2u8
443      },
444      {
445        foo: 3u8,
446        bar: 4u8
447      },
448      {
449        foo: 5u8,
450        bar: 6u8
451      }
452    ],
453    bar: [
454      {
455        foo: [
456          1u8,
457          2u8,
458          3u8
459        ],
460        bar: [
461          4u8,
462          5u8,
463          6u8
464        ]
465      },
466      {
467        foo: [
468          7u8,
469          8u8,
470          9u8
471        ],
472        bar: [
473          10u8,
474          11u8,
475          12u8
476        ]
477      },
478      {
479        foo: [
480          13u8,
481          14u8,
482          15u8
483        ],
484        bar: [
485          16u8,
486          17u8,
487          18u8
488        ]
489      }
490    ]
491  }";
492          let (remainder, candidate) = Plaintext::<CurrentNetwork>::parse(expected).unwrap();
493          println!("\nExpected: {expected}\n\nFound: {candidate}\n");
494          assert_eq!(expected, candidate.to_string());
495          assert_eq!("", remainder);
496      }
497  
498      // A helper function to get the depth of the plaintext.
499      fn get_depth(plaintext: &Plaintext<CurrentNetwork>) -> usize {
500          match plaintext {
501              Plaintext::Literal(_, _) => 0,
502              Plaintext::Struct(members, _) => members.values().map(get_depth).max().unwrap_or(0) + 1,
503              Plaintext::Array(elements, _) => elements.iter().map(get_depth).max().unwrap_or(0) + 1,
504          }
505      }
506  
507      #[test]
508      fn test_deeply_nested_plaintext() {
509          // Creates a string representation of a nested Plaintext array with the given depth and root.
510          fn create_nested_array(depth: usize, root: impl Display) -> String {
511              // Define the prefix and suffix based on the depth.
512              let prefix = if depth == 0 { "".to_string() } else { "[".repeat(depth) };
513              let suffix = if depth == 0 { "".to_string() } else { "]".repeat(depth) };
514              // Format the string with the prefix, root, and suffix.
515              format!("{prefix}{root}{suffix}")
516          }
517  
518          // Creates a string representation of a nested Plaintext struct with the given depth and root.
519          fn create_nested_struct(depth: usize, root: impl Display) -> String {
520              // Define the prefix and suffix based on the depth.
521              let prefix = if depth == 0 { "".to_string() } else { "{inner:".repeat(depth) };
522              let suffix = if depth == 0 { "".to_string() } else { "}".repeat(depth) };
523              // Format the string with the prefix, root, and suffix.
524              format!("{prefix}{root}{suffix}")
525          }
526  
527          // Creates a string representation of a nested Plaintext object with alternating structs and arrays with the given depth and root.
528          fn create_alternated_nested(depth: usize, root: impl Display) -> String {
529              let prefix = (0..depth).map(|i| if i % 2 == 0 { "[" } else { "{inner:" }).collect::<String>();
530              let suffix = (0..depth).map(|i| if i % 2 == 0 { "]" } else { "}" }).rev().collect::<String>();
531              format!("{prefix}{root}{suffix}")
532          }
533  
534          // A helper function to run the test.
535          fn run_test(expected_depth: usize, input: String, expected_error: bool) {
536              // Parse the input string.
537              let result = Plaintext::<CurrentNetwork>::parse(&input);
538              // Check if the result is an error.
539              match expected_error {
540                  true => {
541                      assert!(result.is_err());
542                      return;
543                  }
544                  false => assert!(result.is_ok()),
545              };
546              // Unwrap the result.
547              let (remainder, candidate) = result.unwrap();
548              // Check if the remainder is empty.
549              assert!(remainder.is_empty());
550              // Check if the candidate is equal to the input, with whitespace removed.
551              assert_eq!(input, candidate.to_string().replace("\n", "").replace(" ", ""));
552              // Check if the candidate is equal to the expected depth.
553              assert_eq!(get_depth(&candidate), expected_depth);
554          }
555  
556          // Initialize a sequence of depths to check.
557          let mut depths = (0usize..100).collect_vec();
558          depths.extend((100..1000).step_by(100));
559          depths.extend((1000..10000).step_by(1000));
560          depths.extend((10000..100000).step_by(10000));
561  
562          // Test deeply nested arrays with different literal types.
563          for i in depths.iter().copied() {
564              run_test(i, create_nested_array(i, "false"), i > CurrentNetwork::MAX_DATA_DEPTH);
565              run_test(i, create_nested_array(i, "1u8"), i > CurrentNetwork::MAX_DATA_DEPTH);
566              run_test(i, create_nested_array(i, "0u128"), i > CurrentNetwork::MAX_DATA_DEPTH);
567              run_test(i, create_nested_array(i, "10field"), i > CurrentNetwork::MAX_DATA_DEPTH);
568          }
569  
570          // Test deeply nested structs with different literal types.
571          for i in depths.iter().copied() {
572              run_test(i, create_nested_struct(i, "false"), i > CurrentNetwork::MAX_DATA_DEPTH);
573              run_test(i, create_nested_struct(i, "1u8"), i > CurrentNetwork::MAX_DATA_DEPTH);
574              run_test(i, create_nested_struct(i, "0u128"), i > CurrentNetwork::MAX_DATA_DEPTH);
575              run_test(i, create_nested_struct(i, "10field"), i > CurrentNetwork::MAX_DATA_DEPTH);
576          }
577  
578          // Test alternating nested arrays and structs.
579          for i in depths.iter().copied() {
580              run_test(i, create_alternated_nested(i, "false"), i > CurrentNetwork::MAX_DATA_DEPTH);
581              run_test(i, create_alternated_nested(i, "1u8"), i > CurrentNetwork::MAX_DATA_DEPTH);
582              run_test(i, create_alternated_nested(i, "0u128"), i > CurrentNetwork::MAX_DATA_DEPTH);
583              run_test(i, create_alternated_nested(i, "10field"), i > CurrentNetwork::MAX_DATA_DEPTH);
584          }
585      }
586  }