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 }