parse.rs
1 // Copyright (c) 2019-2025 Alpha-Delta Network Inc. 2 // This file is part of the alphavm library. 3 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at: 7 8 // http://www.apache.org/licenses/LICENSE-2.0 9 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 use super::*; 17 18 impl<N: Network> Parser for Entry<N, Plaintext<N>> { 19 /// Parses a string into the entry. 20 #[inline] 21 fn parse(string: &str) -> ParserResult<Self> { 22 /// A helper enum encoding the visibility. 23 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 24 enum Mode { 25 Constant, 26 Public, 27 Private, 28 } 29 30 /// Parses a sanitized pair: `identifier: entry`, while tracking the depth of the data. 31 fn parse_pair<N: Network>(string: &str, depth: usize) -> ParserResult<(Identifier<N>, Plaintext<N>, Mode)> { 32 // Parse the whitespace and comments from the string. 33 let (string, _) = Sanitizer::parse(string)?; 34 // Parse the identifier from the string. 35 let (string, identifier) = Identifier::parse(string)?; 36 // Parse the whitespace from the string. 37 let (string, _) = Sanitizer::parse_whitespaces(string)?; 38 // Parse the ":" from the string. 39 let (string, _) = tag(":")(string)?; 40 // Parse the whitespace from the string. 41 let (string, _) = Sanitizer::parse_whitespaces(string)?; 42 // Parse the plaintext and visibility from the string. 43 let (string, (plaintext, mode)) = alt(( 44 // Parse a literal. 45 |input| parse_literal(input, depth), 46 // Parse a struct. 47 |input| parse_struct(input, depth), 48 // Parse an array. 49 |input| parse_array(input, depth), 50 ))(string)?; 51 // Parse the whitespace from the string. 52 let (string, _) = Sanitizer::parse_whitespaces(string)?; 53 // Return the identifier, plaintext, and visibility. 54 Ok((string, (identifier, plaintext, mode))) 55 } 56 57 /// Parses an entry as a literal: `literal.visibility`, while tracking the depth of the data. 58 fn parse_literal<N: Network>(string: &str, depth: usize) -> ParserResult<(Plaintext<N>, Mode)> { 59 // Ensure that the depth is within the maximum limit. 60 if depth > N::MAX_DATA_DEPTH { 61 return map_res(take(0usize), |_| { 62 Err(error(format!("Found an entry future that exceeds maximum data depth ({})", N::MAX_DATA_DEPTH))) 63 })(string); 64 } 65 alt(( 66 map(pair(Literal::parse, tag(".constant")), |(literal, _)| (Plaintext::from(literal), Mode::Constant)), 67 map(pair(Literal::parse, tag(".public")), |(literal, _)| (Plaintext::from(literal), Mode::Public)), 68 map(pair(Literal::parse, tag(".private")), |(literal, _)| (Plaintext::from(literal), Mode::Private)), 69 ))(string) 70 } 71 72 /// Parses an entry as a struct: `{ identifier_0: plaintext_0.visibility, ..., identifier_n: plaintext_n.visibility }`, while tracking the depth of the data. 73 /// Observe the `visibility` is the same for all members of the plaintext value. 74 fn parse_struct<N: Network>(string: &str, depth: usize) -> ParserResult<(Plaintext<N>, Mode)> { 75 // Ensure that the depth is within the maximum limit. 76 if depth > N::MAX_DATA_DEPTH { 77 return map_res(take(0usize), |_| { 78 Err(error(format!("Found an entry that exceeds maximum data depth ({})", N::MAX_DATA_DEPTH))) 79 })(string); 80 } 81 // Parse the whitespace and comments from the string. 82 let (string, _) = Sanitizer::parse(string)?; 83 // Parse the "{" from the string. 84 let (string, _) = tag("{")(string)?; 85 // Parse the whitespace from the string. 86 let (string, _) = Sanitizer::parse_whitespaces(string)?; 87 // Parse the members. 88 let (string, (members, mode)) = 89 map_res(separated_list1(tag(","), |input| parse_pair(input, depth + 1)), |members: Vec<_>| { 90 // Ensure the members has no duplicate names. 91 if has_duplicates(members.iter().map(|(name, ..)| name)) { 92 return Err(error("Duplicate member in struct")); 93 } 94 // Ensure the members all have the same visibility. 95 let mode = members.iter().map(|(_, _, mode)| mode).dedup().collect::<Vec<_>>(); 96 let mode = match mode.len() == 1 { 97 true => *mode[0], 98 false => return Err(error("Members of struct in entry have different visibilities")), 99 }; 100 // Ensure the number of structs is within the maximum limit. 101 match members.len() <= N::MAX_STRUCT_ENTRIES { 102 // Return the members and the visibility. 103 true => Ok((members.into_iter().map(|(i, p, _)| (i, p)).collect::<Vec<_>>(), mode)), 104 false => Err(error(format!("Found a struct that exceeds size ({})", members.len()))), 105 } 106 })(string)?; 107 // Parse the whitespace and comments from the string. 108 let (string, _) = Sanitizer::parse(string)?; 109 // Parse the '}' from the string. 110 let (string, _) = tag("}")(string)?; 111 // Output the plaintext and visibility. 112 Ok((string, (Plaintext::Struct(IndexMap::from_iter(members), Default::default()), mode))) 113 } 114 115 /// Parses an entry as an array: `[plaintext_0.visibility, ..., plaintext_n.visibility]`, while tracking the depth of the data. 116 /// Observe the `visibility` is the same for all members of the plaintext value. 117 fn parse_array<N: Network>(string: &str, depth: usize) -> ParserResult<(Plaintext<N>, Mode)> { 118 // Ensure that the depth is within the maximum limit. 119 if depth > N::MAX_DATA_DEPTH { 120 return map_res(take(0usize), |_| { 121 Err(error(format!("Found an entry future that exceeds maximum data depth ({})", N::MAX_DATA_DEPTH))) 122 })(string); 123 } 124 // Parse the whitespace and comments from the string. 125 let (string, _) = Sanitizer::parse(string)?; 126 // Parse the "[" from the string. 127 let (string, _) = tag("[")(string)?; 128 // Parse the whitespace from the string. 129 let (string, _) = Sanitizer::parse_whitespaces(string)?; 130 // Parse the members. 131 let (string, (elements, mode)) = map_res( 132 separated_list1( 133 pair(Sanitizer::parse_whitespaces, pair(tag(","), Sanitizer::parse_whitespaces)), 134 alt(( 135 |input| parse_literal(input, depth + 1), 136 |input| parse_struct(input, depth + 1), 137 |input| parse_array(input, depth + 1), 138 )), 139 ), 140 |members: Vec<(Plaintext<N>, Mode)>| { 141 // Ensure the members all have the same visibility. 142 let mode = members.iter().map(|(_, mode)| mode).dedup().collect::<Vec<_>>(); 143 let mode = match mode.len() == 1 { 144 true => *mode[0], 145 false => return Err(error("Members of an array have different visibilities")), 146 }; 147 // Ensure the number of array elements is within the maximum limit. 148 match members.len() <= N::MAX_ARRAY_ELEMENTS { 149 // Return the members and the visibility. 150 true => Ok((members.into_iter().map(|(p, _)| p).collect::<Vec<_>>(), mode)), 151 false => Err(error(format!("Found an array that exceeds size ({})", members.len()))), 152 } 153 }, 154 )(string)?; 155 // Parse the whitespace and comments from the string. 156 let (string, _) = Sanitizer::parse(string)?; 157 // Parse the ']' from the string. 158 let (string, _) = tag("]")(string)?; 159 // Output the plaintext and visibility. 160 Ok((string, (Plaintext::Array(elements, Default::default()), mode))) 161 } 162 163 // Parse the whitespace from the string. 164 let (string, _) = Sanitizer::parse_whitespaces(string)?; 165 // Parse to determine the entry (order matters). 166 let (string, (plaintext, mode)) = alt(( 167 // Parse a literal. 168 |input| parse_literal(input, 0), 169 // Parse a struct. 170 |input| parse_struct(input, 0), 171 // Parse an array. 172 |input| parse_array(input, 0), 173 ))(string)?; 174 175 // Return the entry. 176 match mode { 177 Mode::Constant => Ok((string, Entry::Constant(plaintext))), 178 Mode::Public => Ok((string, Entry::Public(plaintext))), 179 Mode::Private => Ok((string, Entry::Private(plaintext))), 180 } 181 } 182 } 183 184 impl<N: Network> FromStr for Entry<N, Plaintext<N>> { 185 type Err = Error; 186 187 /// Returns the entry from a string literal. 188 fn from_str(string: &str) -> Result<Self> { 189 match Self::parse(string) { 190 Ok((remainder, object)) => { 191 // Ensure the remainder is empty. 192 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\""); 193 // Return the object. 194 Ok(object) 195 } 196 Err(error) => bail!("Failed to parse string. {error}"), 197 } 198 } 199 } 200 201 impl<N: Network> Debug for Entry<N, Plaintext<N>> { 202 /// Prints the entry as a string. 203 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 204 Display::fmt(self, f) 205 } 206 } 207 208 impl<N: Network> Display for Entry<N, Plaintext<N>> { 209 /// Prints the entry as a string. 210 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 211 self.fmt_internal(f, 0) 212 } 213 } 214 215 impl<N: Network> Entry<N, Plaintext<N>> { 216 /// Prints the entry with the given indentation depth. 217 pub(in crate::data::record) fn fmt_internal(&self, f: &mut Formatter, depth: usize) -> fmt::Result { 218 /// The number of spaces to indent. 219 const INDENT: usize = 2; 220 221 let (plaintext, visibility) = match self { 222 Self::Constant(constant) => (constant, "constant"), 223 Self::Public(public) => (public, "public"), 224 Self::Private(private) => (private, "private"), 225 }; 226 227 match plaintext { 228 // Prints the literal, i.e. 10field.public 229 Plaintext::Literal(literal, ..) => { 230 write!(f, "{:indent$}{literal}.{visibility}", "", indent = depth * INDENT) 231 } 232 // Prints the struct, i.e. { first: 10i64.private, second: 198u64.private } 233 Plaintext::Struct(struct_, ..) => { 234 // Print the opening brace. 235 write!(f, "{{")?; 236 // Print the members. 237 struct_.iter().enumerate().try_for_each(|(i, (name, plaintext))| { 238 match plaintext { 239 #[rustfmt::skip] 240 Plaintext::Literal(literal, ..) => match i == struct_.len() - 1 { 241 true => { 242 // Print the last member without a comma. 243 write!(f, "\n{:indent$}{name}: {literal}.{visibility}", "", indent = (depth + 1) * INDENT)?; 244 // Print the closing brace. 245 write!(f, "\n{:indent$}}}", "", indent = depth * INDENT) 246 } 247 // Print the member with a comma. 248 false => write!(f, "\n{:indent$}{name}: {literal}.{visibility},", "", indent = (depth + 1) * INDENT), 249 }, 250 Plaintext::Struct(..) | Plaintext::Array(..) => { 251 // Print the member name. 252 write!(f, "\n{:indent$}{name}: ", "", indent = (depth + 1) * INDENT)?; 253 // Print the member. 254 match self { 255 Self::Constant(..) => Self::Constant(plaintext.clone()).fmt_internal(f, depth + 1)?, 256 Self::Public(..) => Self::Public(plaintext.clone()).fmt_internal(f, depth + 1)?, 257 Self::Private(..) => Self::Private(plaintext.clone()).fmt_internal(f, depth + 1)?, 258 } 259 // Print the closing brace. 260 match i == struct_.len() - 1 { 261 // If this inner struct is the last member of the outer struct, print the closing brace of the outer struct. 262 true => write!(f, "\n{:indent$}}}", "", indent = depth * INDENT), 263 // Otherwise, print a comma after the inner struct, because the outer struct has more members after this one. 264 false => write!(f, ","), 265 } 266 }, 267 } 268 }) 269 } 270 // Prints the array, i.e. [ 10u64.public, 198u64.private ] 271 Plaintext::Array(array, ..) => { 272 // Print the opening bracket. 273 write!(f, "[")?; 274 // Print the members. 275 array.iter().enumerate().try_for_each(|(i, plaintext)| { 276 match plaintext { 277 #[rustfmt::skip] 278 Plaintext::Literal(literal, ..) => match i == array.len() - 1 { 279 true => { 280 // Print the last member without a comma. 281 write!(f, "\n{:indent$}{literal}.{visibility}", "", indent = (depth + 1) * INDENT)?; 282 // Print the closing brace. 283 write!(f, "\n{:indent$}]", "", indent = depth * INDENT) 284 } 285 // Print the member with a comma. 286 false => write!(f, "\n{:indent$}{literal}.{visibility},", "", indent = (depth + 1) * INDENT), 287 }, 288 Plaintext::Struct(..) | Plaintext::Array(..) => { 289 // Print a new line. 290 write!(f, "\n{:indent$}", "", indent = (depth + 1) * INDENT)?; 291 // Print the member. 292 match self { 293 Self::Constant(..) => Self::Constant(plaintext.clone()).fmt_internal(f, depth + 1)?, 294 Self::Public(..) => Self::Public(plaintext.clone()).fmt_internal(f, depth + 1)?, 295 Self::Private(..) => Self::Private(plaintext.clone()).fmt_internal(f, depth + 1)?, 296 } 297 // Print the closing brace. 298 match i == array.len() - 1 { 299 // If this inner struct is the last member of the outer struct, print the closing bracket of the outer vector. 300 true => write!(f, "\n{:indent$}]", "", indent = depth * INDENT), 301 // Otherwise, print a comma after the inner struct, because the outer vector has more members after this one. 302 false => write!(f, ","), 303 } 304 }, 305 } 306 }) 307 } 308 } 309 } 310 } 311 312 #[cfg(test)] 313 mod tests { 314 use super::*; 315 use alphavm_console_network::MainnetV0; 316 317 type CurrentNetwork = MainnetV0; 318 319 #[test] 320 fn test_parse() -> Result<()> { 321 // Sanity check. 322 let expected = r"{ 323 foo: 5u8.private 324 }"; 325 let (remainder, candidate) = Entry::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse("{ foo: 5u8.private }")?; 326 assert_eq!(expected, candidate.to_string()); 327 assert_eq!("", remainder); 328 329 let expected = r"{ 330 foo: 5u8.public, 331 bar: { 332 baz: 10field.public, 333 qux: { 334 quux: { 335 corge: { 336 grault: { 337 garply: { 338 waldo: { 339 fred: { 340 plugh: { 341 xyzzy: { 342 thud: true.public 343 } 344 } 345 } 346 } 347 } 348 } 349 } 350 } 351 } 352 } 353 }"; 354 let (remainder, candidate) = Entry::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse( 355 "{ foo: 5u8.public, bar: { baz: 10field.public, qux: {quux:{corge :{grault: {garply:{waldo:{fred:{plugh:{xyzzy: { thud: true.public}} }}} }}}}}}", 356 )?; 357 println!("\nExpected: {expected}\n\nFound: {candidate}\n"); 358 assert_eq!(expected, candidate.to_string()); 359 assert_eq!("", remainder); 360 361 // Test an array of literals. 362 let expected = r"[ 363 5u8.private, 364 10u8.private, 365 15u8.private 366 ]"; 367 let (remainder, candidate) = 368 Entry::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse("[ 5u8.private, 10u8.private, 15u8.private ]")?; 369 assert_eq!(expected, candidate.to_string()); 370 assert_eq!("", remainder); 371 372 // Test an array of structs. 373 let expected = r"[ 374 { 375 foo: 5u8.public 376 }, 377 { 378 bar: 10u8.public 379 }, 380 { 381 baz: 15u8.public 382 } 383 ]"; 384 let (remainder, candidate) = Entry::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse( 385 "[ { foo: 5u8.public }, { bar: 10u8.public }, { baz: 15u8.public } ]", 386 )?; 387 assert_eq!(expected, candidate.to_string()); 388 assert_eq!("", remainder); 389 390 // Test a struct with arrays. 391 let expected = r"{ 392 foo: [ 393 5u8.public, 394 10u8.public, 395 15u8.public 396 ], 397 bar: [ 398 { 399 foo: 5u8.public 400 }, 401 { 402 bar: 10u8.public 403 }, 404 { 405 baz: 15u8.public 406 } 407 ] 408 }"; 409 let (remainder, candidate) = Entry::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse( 410 "{ foo: [ 5u8.public, 10u8.public, 15u8.public ], bar: [ { foo: 5u8.public }, { bar: 10u8.public }, { baz: 15u8.public } ] }", 411 )?; 412 assert_eq!(expected, candidate.to_string()); 413 assert_eq!("", remainder); 414 415 Ok(()) 416 } 417 418 // A helper function to get the depth of the plaintext. 419 fn get_depth(plaintext: &Plaintext<CurrentNetwork>) -> usize { 420 match plaintext { 421 Plaintext::Literal(_, _) => 0, 422 Plaintext::Struct(members, _) => members.values().map(get_depth).max().unwrap_or(0) + 1, 423 Plaintext::Array(elements, _) => elements.iter().map(get_depth).max().unwrap_or(0) + 1, 424 } 425 } 426 427 #[test] 428 fn test_deeply_nested_entry() { 429 // Creates a string representation of a nested array Entry with the given depth and root. 430 fn create_nested_array(depth: usize, root: impl Display) -> String { 431 // Define the prefix and suffix based on the depth. 432 let prefix = if depth == 0 { "".to_string() } else { "[".repeat(depth) }; 433 let suffix = if depth == 0 { "".to_string() } else { "]".repeat(depth) }; 434 // Format the string with the prefix, root, and suffix. 435 format!("{prefix}{root}{suffix}") 436 } 437 438 // Creates a string representation of a nested struct Entry with the given depth and root. 439 fn create_nested_struct(depth: usize, root: impl Display) -> String { 440 // Define the prefix and suffix based on the depth. 441 let prefix = if depth == 0 { "".to_string() } else { "{inner:".repeat(depth) }; 442 let suffix = if depth == 0 { "".to_string() } else { "}".repeat(depth) }; 443 // Format the string with the prefix, root, and suffix. 444 format!("{prefix}{root}{suffix}") 445 } 446 447 // Creates a string representation of a nested Entry with alternating structs and arrays with the given depth and root. 448 fn create_alternated_nested(depth: usize, root: impl Display) -> String { 449 let prefix = (0..depth).map(|i| if i % 2 == 0 { "[" } else { "{inner:" }).collect::<String>(); 450 let suffix = (0..depth).map(|i| if i % 2 == 0 { "]" } else { "}" }).rev().collect::<String>(); 451 format!("{prefix}{root}{suffix}") 452 } 453 454 // A helper function to run the test. 455 fn run_test(expected_depth: usize, input: String, expected_error: bool) { 456 println!("Testing input: {input} with expected error: {expected_error}"); 457 // Parse the input string. 458 let result = Entry::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse(&input); 459 // Check if the result is an error. 460 match expected_error { 461 true => { 462 assert!(result.is_err()); 463 return; 464 } 465 false => assert!(result.is_ok()), 466 }; 467 // Unwrap the result. 468 let (remainder, candidate) = result.unwrap(); 469 // Check if the remainder is empty. 470 assert!(remainder.is_empty()); 471 // Check if the candidate is equal to the input, with whitespace removed. 472 assert_eq!(input, candidate.to_string().replace("\n", "").replace(" ", "")); 473 // Check if the candidate is equal to the expected depth. 474 match candidate { 475 Entry::Constant(plaintext) => { 476 assert_eq!(get_depth(&plaintext), expected_depth); 477 } 478 Entry::Public(plaintext) => { 479 assert_eq!(get_depth(&plaintext), expected_depth); 480 } 481 Entry::Private(plaintext) => { 482 assert_eq!(get_depth(&plaintext), expected_depth); 483 } 484 } 485 } 486 487 // Initialize a sequence of depths to check. 488 let mut depths = (0usize..100).collect_vec(); 489 depths.extend((100..1000).step_by(100)); 490 depths.extend((1000..10000).step_by(1000)); 491 depths.extend((10000..100000).step_by(10000)); 492 493 // Test deeply nested arrays with different literal types. 494 for i in depths.iter().copied() { 495 run_test(i, create_nested_array(i, "false.constant"), i > CurrentNetwork::MAX_DATA_DEPTH); 496 run_test(i, create_nested_array(i, "1u8.public"), i > CurrentNetwork::MAX_DATA_DEPTH); 497 run_test(i, create_nested_array(i, "0u128.private"), i > CurrentNetwork::MAX_DATA_DEPTH); 498 run_test(i, create_nested_array(i, "10field.constant"), i > CurrentNetwork::MAX_DATA_DEPTH); 499 } 500 501 // Test deeply nested structs with different literal types. 502 for i in depths.iter().copied() { 503 run_test(i, create_nested_struct(i, "false.public"), i > CurrentNetwork::MAX_DATA_DEPTH); 504 run_test(i, create_nested_struct(i, "1u8.private"), i > CurrentNetwork::MAX_DATA_DEPTH); 505 run_test(i, create_nested_struct(i, "0u128.constant"), i > CurrentNetwork::MAX_DATA_DEPTH); 506 run_test(i, create_nested_struct(i, "10field.public"), i > CurrentNetwork::MAX_DATA_DEPTH); 507 } 508 509 // Test alternating nested arrays and structs. 510 for i in depths.iter().copied() { 511 run_test(i, create_alternated_nested(i, "false.private"), i > CurrentNetwork::MAX_DATA_DEPTH); 512 run_test(i, create_alternated_nested(i, "1u8.constant"), i > CurrentNetwork::MAX_DATA_DEPTH); 513 run_test(i, create_alternated_nested(i, "0u128.public"), i > CurrentNetwork::MAX_DATA_DEPTH); 514 run_test(i, create_alternated_nested(i, "10field.private"), i > CurrentNetwork::MAX_DATA_DEPTH); 515 } 516 } 517 }