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