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 Future<N> { 19 /// Parses a string into a future value. 20 #[inline] 21 fn parse(string: &str) -> ParserResult<Self> { 22 // Parse the future from the string. 23 Self::parse_internal(string, 0) 24 } 25 } 26 27 impl<N: Network> Future<N> { 28 /// Parses an array of future arguments: `[arg_0, ..., arg_1]`, while tracking the depth of the data. 29 fn parse_arguments(string: &str, depth: usize) -> ParserResult<Vec<Argument<N>>> { 30 // Parse the whitespace and comments from the string. 31 let (string, _) = Sanitizer::parse(string)?; 32 // Parse the "[" from the string. 33 let (string, _) = tag("[")(string)?; 34 // Parse the whitespace from the string. 35 let (string, _) = Sanitizer::parse(string)?; 36 // Parse the members. 37 let (string, arguments) = separated_list0( 38 pair(pair(Sanitizer::parse_whitespaces, tag(",")), Sanitizer::parse), 39 alt(( 40 map(|input| Self::parse_internal(input, depth + 1), Argument::Future), 41 map(Plaintext::parse, Argument::Plaintext), 42 )), 43 )(string)?; 44 // Parse the whitespace and comments from the string. 45 let (string, _) = Sanitizer::parse(string)?; 46 // Parse the ']' from the string. 47 let (string, _) = tag("]")(string)?; 48 // Output the plaintext. 49 Ok((string, arguments)) 50 } 51 52 /// Parses a string into a future value, while tracking the depth of the data. 53 #[inline] 54 fn parse_internal(string: &str, depth: usize) -> ParserResult<Self> { 55 // Ensure that the depth is within the maximum limit. 56 // Note: `N::MAX_DATA_DEPTH` is an upper bound on the number of nested futures. 57 // The true maximum is defined by `Transaction::<N>::MAX_TRANSITIONS`, however, that object is not accessible in this crate. 58 // In practice, `MAX_DATA_DEPTH` is 32, while `MAX_TRANSITIONS` is 31. 59 if depth > N::MAX_DATA_DEPTH { 60 return map_res(take(0usize), |_| { 61 Err(error(format!("Found a future that exceeds maximum data depth ({})", N::MAX_DATA_DEPTH))) 62 })(string); 63 } 64 // Parse the whitespace and comments from the string. 65 let (string, _) = Sanitizer::parse(string)?; 66 // Parse the "{" from the string. 67 let (string, _) = tag("{")(string)?; 68 69 // Parse the whitespace and comments from the string. 70 let (string, _) = Sanitizer::parse(string)?; 71 // Parse the "program_id" from the string. 72 let (string, _) = tag("program_id")(string)?; 73 // Parse the whitespace from the string. 74 let (string, _) = Sanitizer::parse_whitespaces(string)?; 75 // Parse the ":" from the string. 76 let (string, _) = tag(":")(string)?; 77 // Parse the whitespace from the string. 78 let (string, _) = Sanitizer::parse_whitespaces(string)?; 79 // Parse the program ID from the string. 80 let (string, program_id) = ProgramID::parse(string)?; 81 // Parse the whitespace from the string. 82 let (string, _) = Sanitizer::parse_whitespaces(string)?; 83 // Parse the "," from the string. 84 let (string, _) = tag(",")(string)?; 85 86 // Parse the whitespace and comments from the string. 87 let (string, _) = Sanitizer::parse(string)?; 88 // Parse the "function_name" from the string. 89 let (string, _) = tag("function_name")(string)?; 90 // Parse the whitespace from the string. 91 let (string, _) = Sanitizer::parse_whitespaces(string)?; 92 // Parse the ":" from the string. 93 let (string, _) = tag(":")(string)?; 94 // Parse the whitespace from the string. 95 let (string, _) = Sanitizer::parse_whitespaces(string)?; 96 // Parse the function name from the string. 97 let (string, function_name) = Identifier::parse(string)?; 98 // Parse the whitespace from the string. 99 let (string, _) = Sanitizer::parse_whitespaces(string)?; 100 // Parse the "," from the string. 101 let (string, _) = tag(",")(string)?; 102 103 // Parse the whitespace and comments from the string. 104 let (string, _) = Sanitizer::parse(string)?; 105 // Parse the "arguments" from the string. 106 let (string, _) = tag("arguments")(string)?; 107 // Parse the whitespace from the string. 108 let (string, _) = Sanitizer::parse_whitespaces(string)?; 109 // Parse the ":" from the string. 110 let (string, _) = tag(":")(string)?; 111 // Parse the whitespace from the string. 112 let (string, _) = Sanitizer::parse_whitespaces(string)?; 113 // Parse the arguments from the string. 114 let (string, arguments) = Self::parse_arguments(string, depth)?; 115 116 // Parse the whitespace and comments from the string. 117 let (string, _) = Sanitizer::parse(string)?; 118 // Parse the "}" from the string. 119 let (string, _) = tag("}")(string)?; 120 121 Ok((string, Self::new(program_id, function_name, arguments))) 122 } 123 } 124 125 impl<N: Network> FromStr for Future<N> { 126 type Err = Error; 127 128 /// Returns a future from a string literal. 129 fn from_str(string: &str) -> Result<Self> { 130 match Self::parse(string) { 131 Ok((remainder, object)) => { 132 // Ensure the remainder is empty. 133 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\""); 134 // Return the object. 135 Ok(object) 136 } 137 Err(error) => bail!("Failed to parse string. {error}"), 138 } 139 } 140 } 141 142 impl<N: Network> Debug for Future<N> { 143 /// Prints the future as a string. 144 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 145 Display::fmt(self, f) 146 } 147 } 148 149 impl<N: Network> Display for Future<N> { 150 /// Prints the future as a string. 151 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 152 self.fmt_internal(f, 0) 153 } 154 } 155 156 impl<N: Network> Future<N> { 157 /// Prints the future with the given indentation depth. 158 fn fmt_internal(&self, f: &mut Formatter, depth: usize) -> fmt::Result { 159 /// The number of spaces to indent. 160 const INDENT: usize = 2; 161 162 // Print the opening brace. 163 write!(f, "{{")?; 164 165 // Print the program ID. 166 write!( 167 f, 168 "\n{:indent$}program_id: {program_id},", 169 "", 170 indent = (depth + 1) * INDENT, 171 program_id = self.program_id() 172 )?; 173 // Print the function name. 174 write!( 175 f, 176 "\n{:indent$}function_name: {function_name},", 177 "", 178 indent = (depth + 1) * INDENT, 179 function_name = self.function_name() 180 )?; 181 // Print the arguments. 182 // If the arguments are empty, print an empty array. 183 if self.arguments.is_empty() { 184 write!(f, "\n{:indent$}arguments: []", "", indent = (depth + 1) * INDENT)?; 185 } else { 186 write!(f, "\n{:indent$}arguments: [", "", indent = (depth + 1) * INDENT)?; 187 self.arguments.iter().enumerate().try_for_each(|(i, argument)| { 188 match argument { 189 Argument::Plaintext(plaintext) => match i == self.arguments.len() - 1 { 190 true => { 191 // Print the last argument without a comma. 192 write!( 193 f, 194 "\n{:indent$}{plaintext}", 195 "", 196 indent = (depth + 2) * INDENT, 197 plaintext = plaintext 198 ) 199 } 200 // Print the argument with a comma. 201 false => { 202 write!( 203 f, 204 "\n{:indent$}{plaintext},", 205 "", 206 indent = (depth + 2) * INDENT, 207 plaintext = plaintext 208 ) 209 } 210 }, 211 Argument::Future(future) => { 212 // Print a newline. 213 write!(f, "\n{:indent$}", "", indent = (depth + 2) * INDENT)?; 214 // Print the argument. 215 future.fmt_internal(f, depth + 2)?; 216 // Print the closing brace. 217 match i == self.arguments.len() - 1 { 218 // Print the last member without a comma. 219 true => write!(f, "\n{:indent$}", "", indent = (depth + 1) * INDENT), 220 // Print the member with a comma. 221 false => write!(f, ","), 222 } 223 } 224 } 225 })?; 226 // Print the closing bracket. 227 write!(f, "\n{:indent$}]", "", indent = (depth + 1) * INDENT)?; 228 } 229 230 // Print the closing brace. 231 write!(f, "\n{:indent$}}}", "", indent = depth * INDENT) 232 } 233 } 234 235 #[cfg(test)] 236 mod tests { 237 use super::*; 238 use alphavm_console_network::MainnetV0; 239 240 type CurrentNetwork = MainnetV0; 241 242 #[test] 243 fn test_parse_future() -> Result<()> { 244 // No argument case. 245 let expected = r"{ 246 program_id: credits.alpha, 247 function_name: transfer, 248 arguments: [] 249 }"; 250 let (remainder, candidate) = 251 Future::<CurrentNetwork>::parse("{ program_id: credits.alpha, function_name: transfer, arguments: [] }")?; 252 assert!(remainder.is_empty()); 253 assert_eq!(expected, candidate.to_string()); 254 assert_eq!("", remainder); 255 256 // Literal arguments. 257 let expected = r"{ 258 program_id: credits.alpha, 259 function_name: transfer_public_to_private, 260 arguments: [ 261 ax150w2lvhdzychwvzu54ys5zas7tm5s0ycdyw563pms83g9u0vucgqe5fs5w, 262 100000000u64 263 ] 264 }"; 265 let (remainder, candidate) = Future::<CurrentNetwork>::parse( 266 "{ program_id: credits.alpha, function_name: transfer_public_to_private, arguments: [ ax150w2lvhdzychwvzu54ys5zas7tm5s0ycdyw563pms83g9u0vucgqe5fs5w, 100000000u64 ] }", 267 )?; 268 assert!(remainder.is_empty()); 269 assert_eq!(expected, candidate.to_string()); 270 assert_eq!("", remainder); 271 272 Ok(()) 273 } 274 275 #[test] 276 fn test_deeply_nested_future() { 277 // A helper function to iteratively create a deeply nested future. 278 fn create_nested_future(depth: usize) -> String { 279 // Define the base case. 280 let root = r"{ 281 program_id: foo.alpha, 282 function_name: bar, 283 arguments: [] 284 }"; 285 // Define the prefix and suffix for the nested future. 286 let prefix = r"{ 287 program_id: foo.alpha, 288 function_name: bar, 289 arguments: [" 290 .repeat(depth); 291 let suffix = r"]}".repeat(depth); 292 // Concatenate the prefix, root, and suffix to create the nested future. 293 format!("{prefix}{root}{suffix}") 294 } 295 296 // A helper function to test the parsing of a deeply nested future. 297 fn run_test(depth: usize, expected_error: bool) { 298 // Create the nested future string. 299 let nested_future_string = create_nested_future(depth); 300 // Parse the nested future. 301 let result = Future::<CurrentNetwork>::parse(&nested_future_string); 302 // Check if the result is an error. 303 match expected_error { 304 true => { 305 assert!(result.is_err()); 306 return; 307 } 308 false => assert!(result.is_ok()), 309 }; 310 // Unwrap the result. 311 let (remainder, candidate) = result.unwrap(); 312 // Ensure the remainder is empty. 313 assert!( 314 remainder.is_empty(), 315 "Failed to parse deeply nested future. Found invalid character in: \"{remainder}\"" 316 ); 317 // Strip the expected string of whitespace. 318 let expected = nested_future_string.replace("\n", "").replace(" ", "").replace("\t", ""); 319 // Strip the candidate string of whitespace. 320 let candidate_str = candidate.to_string().replace("\n", "").replace(" ", "").replace("\t", ""); 321 // Ensure the expected and candidate strings are equal. 322 assert_eq!(expected, candidate_str, "Expected: {expected}, Candidate: {candidate_str}"); 323 } 324 325 // Initialize a set of depths to test. 326 let mut depths = (0usize..100).collect_vec(); 327 depths.extend((100..1000).step_by(100)); 328 depths.extend((1000..10000).step_by(1000)); 329 depths.extend((10000..100000).step_by(10000)); 330 331 // For each depth, test the parsing of a deeply nested future. 332 for depth in depths { 333 run_test(depth, depth > CurrentNetwork::MAX_DATA_DEPTH); 334 } 335 } 336 }