snarkvm_synthesizer_program/finalize/
parse.rs

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