parse.rs
1 // Copyright (c) 2025 ADnet Contributors 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 FunctionCore<N> { 19 /// Parses a string into a function. 20 #[inline] 21 fn parse(string: &str) -> ParserResult<Self> { 22 // Parse the whitespace and comments from the string. 23 let (string, _) = Sanitizer::parse(string)?; 24 // Parse the 'function' keyword from the string. 25 let (string, _) = tag(Self::type_name())(string)?; 26 // Parse the whitespace from the string. 27 let (string, _) = Sanitizer::parse_whitespaces(string)?; 28 // Parse the function name from the string. 29 let (string, name) = Identifier::<N>::parse(string)?; 30 // Parse the whitespace from the string. 31 let (string, _) = Sanitizer::parse_whitespaces(string)?; 32 // Parse the colon ':' keyword from the string. 33 let (string, _) = tag(":")(string)?; 34 35 // Parse the inputs from the string. 36 let (string, inputs) = many0(Input::parse)(string)?; 37 // Parse the instructions from the string. 38 let (string, instructions) = many0(Instruction::parse)(string)?; 39 // Parse the outputs from the string. 40 let (string, outputs) = many0(Output::parse)(string)?; 41 42 // Parse an optional finalize command from the string. 43 let (string, finalize) = opt(FinalizeCore::parse)(string)?; 44 45 map_res(take(0usize), move |_| { 46 // Initialize a new function. 47 let mut function = Self::new(name); 48 if let Err(error) = inputs.iter().cloned().try_for_each(|input| function.add_input(input)) { 49 eprintln!("{error}"); 50 return Err(error); 51 } 52 if let Err(error) = 53 instructions.iter().cloned().try_for_each(|instruction| function.add_instruction(instruction)) 54 { 55 eprintln!("{error}"); 56 return Err(error); 57 } 58 if let Err(error) = outputs.iter().cloned().try_for_each(|output| function.add_output(output)) { 59 eprintln!("{error}"); 60 return Err(error); 61 } 62 if let Some(finalize) = &finalize { 63 if let Err(error) = function.add_finalize(finalize.clone()) { 64 eprintln!("{error}"); 65 return Err(error); 66 } 67 } 68 Ok::<_, Error>(function) 69 })(string) 70 } 71 } 72 73 impl<N: Network> FromStr for FunctionCore<N> { 74 type Err = Error; 75 76 /// Returns a function from a string literal. 77 fn from_str(string: &str) -> Result<Self> { 78 match Self::parse(string) { 79 Ok((remainder, object)) => { 80 // Ensure the remainder is empty. 81 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\""); 82 // Return the object. 83 Ok(object) 84 } 85 Err(error) => bail!("Failed to parse string. {error}"), 86 } 87 } 88 } 89 90 impl<N: Network> Debug for FunctionCore<N> { 91 /// Prints the function as a string. 92 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 93 Display::fmt(self, f) 94 } 95 } 96 97 impl<N: Network> Display for FunctionCore<N> { 98 /// Prints the function as a string. 99 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 100 // Write the function to a string. 101 write!(f, "{} {}:", Self::type_name(), self.name)?; 102 self.inputs.iter().try_for_each(|input| write!(f, "\n {input}"))?; 103 self.instructions.iter().try_for_each(|instruction| write!(f, "\n {instruction}"))?; 104 self.outputs.iter().try_for_each(|output| write!(f, "\n {output}"))?; 105 106 // If finalize exists, write it out. 107 if let Some(finalize) = &self.finalize_logic { 108 write!(f, "\n\n")?; 109 write!(f, "{finalize}")?; 110 } 111 Ok(()) 112 } 113 } 114 115 #[cfg(test)] 116 mod tests { 117 use super::*; 118 use crate::Function; 119 use console::network::MainnetV0; 120 121 type CurrentNetwork = MainnetV0; 122 123 #[test] 124 fn test_function_parse() { 125 let function = Function::<CurrentNetwork>::parse( 126 r" 127 function foo: 128 input r0 as field.public; 129 input r1 as field.private; 130 add r0 r1 into r2; 131 output r2 as field.private;", 132 ) 133 .unwrap() 134 .1; 135 assert_eq!("foo", function.name().to_string()); 136 assert_eq!(2, function.inputs().len()); 137 assert_eq!(1, function.instructions().len()); 138 assert_eq!(1, function.outputs().len()); 139 140 // Function with 0 inputs. 141 let function = Function::<CurrentNetwork>::parse( 142 r" 143 function foo: 144 add 1u32 2u32 into r0; 145 output r0 as u32.private;", 146 ) 147 .unwrap() 148 .1; 149 assert_eq!("foo", function.name().to_string()); 150 assert_eq!(0, function.inputs().len()); 151 assert_eq!(1, function.instructions().len()); 152 assert_eq!(1, function.outputs().len()); 153 } 154 155 #[test] 156 fn test_function_parse_cast() { 157 let function = Function::<CurrentNetwork>::parse( 158 r" 159 function foo: 160 input r0 as token.record; 161 cast r0.owner r0.token_amount into r1 as token.record; 162 output r1 as token.record;", 163 ) 164 .unwrap() 165 .1; 166 assert_eq!("foo", function.name().to_string()); 167 assert_eq!(1, function.inputs().len()); 168 assert_eq!(1, function.instructions().len()); 169 assert_eq!(1, function.outputs().len()); 170 } 171 172 #[test] 173 fn test_function_parse_no_instruction_or_output() { 174 let function = Function::<CurrentNetwork>::parse( 175 r" 176 function foo: 177 input r0 as token.record;", 178 ) 179 .unwrap() 180 .1; 181 assert_eq!("foo", function.name().to_string()); 182 assert_eq!(1, function.inputs().len()); 183 assert_eq!(0, function.instructions().len()); 184 assert_eq!(0, function.outputs().len()); 185 } 186 187 #[test] 188 fn test_function_parse_finalize() { 189 let function = Function::<CurrentNetwork>::parse( 190 r" 191 function mint_public: 192 // Input the token receiver. 193 input r0 as address.public; 194 // Input the token amount. 195 input r1 as u64.public; 196 // Mint the tokens via an asynchronous call. 197 async mint_public r0 r1 into r2; 198 // Output the future. 199 output r2 as foo.alpha/mint_public.future; 200 201 // The finalize scope of `mint_public` increments the 202 // `account` of the token receiver by the specified amount. 203 finalize mint_public: 204 // Input the token receiver. 205 input r0 as address.public; 206 // Input the token amount. 207 input r1 as u64.public; 208 209 // Get `account[r0]` into `r2`, defaulting to 0u64 if the entry does not exist. 210 get.or_use account[r0] 0u64 into r2; 211 // Add `r1` to `r2`. If the operation overflows, `mint_public` is reverted. 212 add r2 r1 into r3; 213 // Set `r3` into `account[r0]`. 214 set r3 into account[r0]; 215 ", 216 ) 217 .unwrap() 218 .1; 219 assert_eq!("mint_public", function.name().to_string()); 220 assert_eq!(2, function.inputs().len()); 221 assert_eq!(1, function.instructions().len()); 222 assert_eq!(1, function.outputs().len()); 223 assert_eq!(2, function.finalize_logic().as_ref().unwrap().inputs().len()); 224 assert_eq!(3, function.finalize_logic().as_ref().unwrap().commands().len()); 225 226 let function = Function::<CurrentNetwork>::parse( 227 r" 228 function foo: 229 input r0 as token.record; 230 cast r0.owner r0.token_amount into r1 as token.record; 231 async foo r1.token_amount into r2; 232 output r2 as foo.alpha/foo.future; 233 234 finalize foo: 235 input r0 as u64.public; 236 add r0 r0 into r1; 237 ", 238 ) 239 .unwrap() 240 .1; 241 assert_eq!("foo", function.name().to_string()); 242 assert_eq!(1, function.inputs().len()); 243 assert_eq!(2, function.instructions().len()); 244 assert_eq!(1, function.outputs().len()); 245 assert_eq!(1, function.finalize_logic().as_ref().unwrap().inputs().len()); 246 assert_eq!(1, function.finalize_logic().as_ref().unwrap().commands().len()); 247 248 let function = Function::<CurrentNetwork>::parse( 249 r" 250 function compute: 251 input r0 as address.public; 252 input r1 as u64.public; 253 input r2 as u64.public; 254 add r1 r2 into r3; 255 async compute r0 r3 into r4; 256 output r4 as foo.alpha/compute.future; 257 258 finalize compute: 259 input r0 as address.public; 260 input r1 as u64.public; 261 get.or_use account[r0] 0u64 into r2; 262 add r2 r1 into r3; 263 set r3 into account[r0]; 264 ", 265 ) 266 .unwrap() 267 .1; 268 assert_eq!(3, function.inputs().len()); 269 assert_eq!(2, function.instructions().len()); 270 assert_eq!(1, function.outputs().len()); 271 assert_eq!(2, function.finalize_logic().as_ref().unwrap().inputs().len()); 272 assert_eq!(3, function.finalize_logic().as_ref().unwrap().commands().len()); 273 } 274 275 #[test] 276 fn test_function_display() { 277 let expected = r"function foo: 278 input r0 as field.public; 279 input r1 as field.private; 280 add r0 r1 into r2; 281 output r2 as field.private;"; 282 let function = Function::<CurrentNetwork>::parse(expected).unwrap().1; 283 assert_eq!(expected, format!("{function}"),); 284 } 285 }