snarkvm_console_program/data/future/
parse.rs

1// Copyright 2024 Aleo Network Foundation
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> Parser for Future<N> {
19    /// Parses a string into a future value.
20    #[inline]
21    fn parse(string: &str) -> ParserResult<Self> {
22        /// Parses an array of future arguments: `[arg_0, ..., arg_1]`.
23        fn parse_arguments<N: Network>(string: &str) -> ParserResult<Vec<Argument<N>>> {
24            // Parse the whitespace and comments from the string.
25            let (string, _) = Sanitizer::parse(string)?;
26            // Parse the "[" from the string.
27            let (string, _) = tag("[")(string)?;
28            // Parse the whitespace from the string.
29            let (string, _) = Sanitizer::parse(string)?;
30            // Parse the members.
31            let (string, arguments) = separated_list0(
32                pair(pair(Sanitizer::parse_whitespaces, tag(",")), Sanitizer::parse),
33                alt((map(Future::parse, Argument::Future), map(Plaintext::parse, Argument::Plaintext))),
34            )(string)?;
35            // Parse the whitespace and comments from the string.
36            let (string, _) = Sanitizer::parse(string)?;
37            // Parse the ']' from the string.
38            let (string, _) = tag("]")(string)?;
39            // Output the plaintext.
40            Ok((string, arguments))
41        }
42
43        // Parse the whitespace and comments from the string.
44        let (string, _) = Sanitizer::parse(string)?;
45        // Parse the "{" from the string.
46        let (string, _) = tag("{")(string)?;
47
48        // Parse the whitespace and comments from the string.
49        let (string, _) = Sanitizer::parse(string)?;
50        // Parse the "program_id" from the string.
51        let (string, _) = tag("program_id")(string)?;
52        // Parse the whitespace from the string.
53        let (string, _) = Sanitizer::parse_whitespaces(string)?;
54        // Parse the ":" from the string.
55        let (string, _) = tag(":")(string)?;
56        // Parse the whitespace from the string.
57        let (string, _) = Sanitizer::parse_whitespaces(string)?;
58        // Parse the program ID from the string.
59        let (string, program_id) = ProgramID::parse(string)?;
60        // Parse the whitespace from the string.
61        let (string, _) = Sanitizer::parse_whitespaces(string)?;
62        // Parse the "," from the string.
63        let (string, _) = tag(",")(string)?;
64
65        // Parse the whitespace and comments from the string.
66        let (string, _) = Sanitizer::parse(string)?;
67        // Parse the "function_name" from the string.
68        let (string, _) = tag("function_name")(string)?;
69        // Parse the whitespace from the string.
70        let (string, _) = Sanitizer::parse_whitespaces(string)?;
71        // Parse the ":" from the string.
72        let (string, _) = tag(":")(string)?;
73        // Parse the whitespace from the string.
74        let (string, _) = Sanitizer::parse_whitespaces(string)?;
75        // Parse the function name from the string.
76        let (string, function_name) = Identifier::parse(string)?;
77        // Parse the whitespace from the string.
78        let (string, _) = Sanitizer::parse_whitespaces(string)?;
79        // Parse the "," from the string.
80        let (string, _) = tag(",")(string)?;
81
82        // Parse the whitespace and comments from the string.
83        let (string, _) = Sanitizer::parse(string)?;
84        // Parse the "arguments" from the string.
85        let (string, _) = tag("arguments")(string)?;
86        // Parse the whitespace from the string.
87        let (string, _) = Sanitizer::parse_whitespaces(string)?;
88        // Parse the ":" from the string.
89        let (string, _) = tag(":")(string)?;
90        // Parse the whitespace from the string.
91        let (string, _) = Sanitizer::parse_whitespaces(string)?;
92        // Parse the arguments from the string.
93        let (string, arguments) = parse_arguments(string)?;
94
95        // Parse the whitespace and comments from the string.
96        let (string, _) = Sanitizer::parse(string)?;
97        // Parse the "}" from the string.
98        let (string, _) = tag("}")(string)?;
99
100        Ok((string, Self::new(program_id, function_name, arguments)))
101    }
102}
103
104impl<N: Network> FromStr for Future<N> {
105    type Err = Error;
106
107    /// Returns a future from a string literal.
108    fn from_str(string: &str) -> Result<Self> {
109        match Self::parse(string) {
110            Ok((remainder, object)) => {
111                // Ensure the remainder is empty.
112                ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
113                // Return the object.
114                Ok(object)
115            }
116            Err(error) => bail!("Failed to parse string. {error}"),
117        }
118    }
119}
120
121impl<N: Network> Debug for Future<N> {
122    /// Prints the future as a string.
123    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
124        Display::fmt(self, f)
125    }
126}
127
128impl<N: Network> Display for Future<N> {
129    /// Prints the future as a string.
130    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
131        self.fmt_internal(f, 0)
132    }
133}
134
135impl<N: Network> Future<N> {
136    /// Prints the future with the given indentation depth.
137    fn fmt_internal(&self, f: &mut Formatter, depth: usize) -> fmt::Result {
138        /// The number of spaces to indent.
139        const INDENT: usize = 2;
140
141        // Print the opening brace.
142        write!(f, "{{")?;
143
144        // Print the program ID.
145        write!(
146            f,
147            "\n{:indent$}program_id: {program_id},",
148            "",
149            indent = (depth + 1) * INDENT,
150            program_id = self.program_id()
151        )?;
152        // Print the function name.
153        write!(
154            f,
155            "\n{:indent$}function_name: {function_name},",
156            "",
157            indent = (depth + 1) * INDENT,
158            function_name = self.function_name()
159        )?;
160        // Print the arguments.
161        // If the arguments are empty, print an empty array.
162        if self.arguments.is_empty() {
163            write!(f, "\n{:indent$}arguments: []", "", indent = (depth + 1) * INDENT)?;
164        } else {
165            write!(f, "\n{:indent$}arguments: [", "", indent = (depth + 1) * INDENT)?;
166            self.arguments.iter().enumerate().try_for_each(|(i, argument)| {
167                match argument {
168                    Argument::Plaintext(plaintext) => match i == self.arguments.len() - 1 {
169                        true => {
170                            // Print the last argument without a comma.
171                            write!(
172                                f,
173                                "\n{:indent$}{plaintext}",
174                                "",
175                                indent = (depth + 2) * INDENT,
176                                plaintext = plaintext
177                            )
178                        }
179                        // Print the argument with a comma.
180                        false => {
181                            write!(
182                                f,
183                                "\n{:indent$}{plaintext},",
184                                "",
185                                indent = (depth + 2) * INDENT,
186                                plaintext = plaintext
187                            )
188                        }
189                    },
190                    Argument::Future(future) => {
191                        // Print a newline.
192                        write!(f, "\n{:indent$}", "", indent = (depth + 2) * INDENT)?;
193                        // Print the argument.
194                        future.fmt_internal(f, depth + 2)?;
195                        // Print the closing brace.
196                        match i == self.arguments.len() - 1 {
197                            // Print the last member without a comma.
198                            true => write!(f, "\n{:indent$}", "", indent = (depth + 1) * INDENT),
199                            // Print the member with a comma.
200                            false => write!(f, ","),
201                        }
202                    }
203                }
204            })?;
205            // Print the closing bracket.
206            write!(f, "\n{:indent$}]", "", indent = (depth + 1) * INDENT)?;
207        }
208
209        // Print the closing brace.
210        write!(f, "\n{:indent$}}}", "", indent = depth * INDENT)
211    }
212}
213
214#[cfg(test)]
215mod tests {
216    use super::*;
217    use snarkvm_console_network::MainnetV0;
218
219    type CurrentNetwork = MainnetV0;
220
221    #[test]
222    fn test_parse_future() -> Result<()> {
223        // No argument case.
224        let expected = r"{
225  program_id: credits.aleo,
226  function_name: transfer,
227  arguments: []
228}";
229        let (remainder, candidate) =
230            Future::<CurrentNetwork>::parse("{ program_id: credits.aleo, function_name: transfer, arguments: [] }")?;
231        assert!(remainder.is_empty());
232        assert_eq!(expected, candidate.to_string());
233        assert_eq!("", remainder);
234
235        // Literal arguments.
236        let expected = r"{
237  program_id: credits.aleo,
238  function_name: transfer_public_to_private,
239  arguments: [
240    aleo1g8qul5a44vk22u9uuvaewdcjw4v6xg8wx0llru39nnjn7eu08yrscxe4e2,
241    100000000u64
242  ]
243}";
244        let (remainder, candidate) = Future::<CurrentNetwork>::parse(
245            "{ program_id: credits.aleo, function_name: transfer_public_to_private, arguments: [ aleo1g8qul5a44vk22u9uuvaewdcjw4v6xg8wx0llru39nnjn7eu08yrscxe4e2, 100000000u64 ] }",
246        )?;
247        assert!(remainder.is_empty());
248        assert_eq!(expected, candidate.to_string());
249        assert_eq!("", remainder);
250
251        Ok(())
252    }
253}