parse.rs
1 // Copyright (c) 2019-2025 Alpha-Delta Network Inc. 2 // This file is part of the deltavm 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 ClosureCore<N> { 19 /// Parses a string into a closure. 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 'closure' 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 closure 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) = many1(Input::parse)(string)?; 37 // Parse the instructions from the string. 38 let (string, instructions) = many1(Instruction::parse)(string)?; 39 // Parse the outputs from the string. 40 let (string, outputs) = many0(Output::parse)(string)?; 41 42 map_res(take(0usize), move |_| { 43 // Initialize a new closure. 44 let mut closure = Self::new(name); 45 inputs.iter().cloned().try_for_each(|input| closure.add_input(input))?; 46 instructions.iter().cloned().try_for_each(|instruction| closure.add_instruction(instruction))?; 47 outputs.iter().cloned().try_for_each(|output| closure.add_output(output))?; 48 Ok::<_, Error>(closure) 49 })(string) 50 } 51 } 52 53 impl<N: Network> FromStr for ClosureCore<N> { 54 type Err = Error; 55 56 /// Returns a closure from a string literal. 57 fn from_str(string: &str) -> Result<Self> { 58 match Self::parse(string) { 59 Ok((remainder, object)) => { 60 // Ensure the remainder is empty. 61 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\""); 62 // Return the object. 63 Ok(object) 64 } 65 Err(error) => bail!("Failed to parse string. {error}"), 66 } 67 } 68 } 69 70 impl<N: Network> Debug for ClosureCore<N> { 71 /// Prints the closure as a string. 72 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 73 Display::fmt(self, f) 74 } 75 } 76 77 impl<N: Network> Display for ClosureCore<N> { 78 /// Prints the closure as a string. 79 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 80 // Write the closure to a string. 81 write!(f, "{} {}:", Self::type_name(), self.name)?; 82 self.inputs.iter().try_for_each(|input| write!(f, "\n {input}"))?; 83 self.instructions.iter().try_for_each(|instruction| write!(f, "\n {instruction}"))?; 84 self.outputs.iter().try_for_each(|output| write!(f, "\n {output}")) 85 } 86 } 87 88 #[cfg(test)] 89 mod tests { 90 use super::*; 91 use crate::Closure; 92 use console::network::MainnetV0; 93 94 type CurrentNetwork = MainnetV0; 95 96 #[test] 97 fn test_closure_parse() { 98 let closure = Closure::<CurrentNetwork>::parse( 99 r" 100 closure foo: 101 input r0 as field; 102 input r1 as field; 103 add r0 r1 into r2; 104 output r2 as field;", 105 ) 106 .unwrap() 107 .1; 108 assert_eq!("foo", closure.name().to_string()); 109 assert_eq!(2, closure.inputs().len()); 110 assert_eq!(1, closure.instructions().len()); 111 assert_eq!(1, closure.outputs().len()); 112 } 113 114 #[test] 115 fn test_closure_parse_cast() { 116 let closure = Closure::<CurrentNetwork>::parse( 117 r" 118 closure foo: 119 input r0 as token.record; 120 cast r0.owner r0.token_amount into r1 as data; 121 output r1 as data;", 122 ) 123 .unwrap() 124 .1; 125 assert_eq!("foo", closure.name().to_string()); 126 assert_eq!(1, closure.inputs().len()); 127 assert_eq!(1, closure.instructions().len()); 128 assert_eq!(1, closure.outputs().len()); 129 } 130 131 #[test] 132 fn test_closure_display() { 133 let expected = r"closure foo: 134 input r0 as field; 135 input r1 as field; 136 add r0 r1 into r2; 137 output r2 as field;"; 138 let closure = Closure::<CurrentNetwork>::parse(expected).unwrap().1; 139 assert_eq!(expected, format!("{closure}"),); 140 } 141 142 #[test] 143 fn test_closure_parse_output_function() { 144 let result = Closure::<CurrentNetwork>::parse( 145 r" 146 closure foo: 147 input r0 as token.record; 148 cast r0.owner r0.token_amount into r1 as token.record; 149 output r1 as token.record;", 150 ); 151 152 assert!(result.is_err()); 153 } 154 }