Skip to main content

snarkvm_synthesizer_program/closure/output/
parse.rs

1// Copyright (c) 2019-2026 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> Parser for Output<N> {
19    /// Parses a string into an output statement.
20    /// The output statement is of the form `output {operand} as {register_type};`.
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 output 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 operand from the string.
30        let (string, operand) = Operand::parse(string)?;
31        // Parse the whitespace from the string.
32        let (string, _) = Sanitizer::parse_whitespaces(string)?;
33        // Parse the "as" from the string.
34        let (string, _) = tag("as")(string)?;
35        // Parse the whitespace from the string.
36        let (string, _) = Sanitizer::parse_whitespaces(string)?;
37        // Parse the register type from the string.
38        let (string, register_type) = RegisterType::parse(string)?;
39        // Parse the whitespace from the string.
40        let (string, _) = Sanitizer::parse_whitespaces(string)?;
41        // Parse the semicolon from the string.
42        let (string, _) = tag(";")(string)?;
43        // Return the output statement.
44        Ok((string, Self { operand, register_type }))
45    }
46}
47
48impl<N: Network> FromStr for Output<N> {
49    type Err = Error;
50
51    /// Parses a string into an output statement.
52    #[inline]
53    fn from_str(string: &str) -> Result<Self> {
54        match Self::parse(string) {
55            Ok((remainder, object)) => {
56                // Ensure the remainder is empty.
57                ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
58                // Return the object.
59                Ok(object)
60            }
61            Err(error) => bail!("Failed to parse string. {error}"),
62        }
63    }
64}
65
66impl<N: Network> Debug for Output<N> {
67    /// Prints the output as a string.
68    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
69        Display::fmt(self, f)
70    }
71}
72
73impl<N: Network> Display for Output<N> {
74    /// Prints the output statement as a string.
75    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
76        write!(
77            f,
78            "{type_} {operand} as {register_type};",
79            type_ = Self::type_name(),
80            operand = self.operand,
81            register_type = self.register_type
82        )
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89    use console::{
90        network::MainnetV0,
91        program::{Literal, Register, U8},
92    };
93
94    type CurrentNetwork = MainnetV0;
95
96    #[test]
97    fn test_output_parse() -> Result<()> {
98        // Register
99        let output = Output::<CurrentNetwork>::parse("output r0 as field;").unwrap().1;
100        assert_eq!(output.operand(), &Operand::Register(Register::<CurrentNetwork>::Locator(0)));
101        assert_eq!(output.register_type(), &RegisterType::<CurrentNetwork>::from_str("field")?);
102
103        let output = Output::<CurrentNetwork>::parse("output 0u8 as u8;").unwrap().1;
104        assert_eq!(output.operand(), &Operand::Literal(Literal::<CurrentNetwork>::U8(U8::new(0))));
105        assert_eq!(output.register_type(), &RegisterType::<CurrentNetwork>::from_str("u8")?);
106
107        // Struct
108        let output = Output::<CurrentNetwork>::parse("output r1 as signature;").unwrap().1;
109        assert_eq!(output.operand(), &Operand::Register(Register::<CurrentNetwork>::Locator(1)));
110        assert_eq!(output.register_type(), &RegisterType::<CurrentNetwork>::from_str("signature")?);
111
112        // Record
113        let output = Output::<CurrentNetwork>::parse("output r2 as token.record;").unwrap().1;
114        assert_eq!(output.operand(), &Operand::Register(Register::<CurrentNetwork>::Locator(2)));
115        assert_eq!(output.register_type(), &RegisterType::<CurrentNetwork>::from_str("token.record")?);
116
117        Ok(())
118    }
119
120    #[test]
121    fn test_output_display() {
122        // Register
123        let output = Output::<CurrentNetwork>::parse("output r0 as field;").unwrap().1;
124        assert_eq!(format!("{output}"), "output r0 as field;");
125
126        // Literal
127        let output = Output::<CurrentNetwork>::parse("output 0u8 as u8;").unwrap().1;
128        assert_eq!(format!("{output}"), "output 0u8 as u8;");
129
130        // Struct
131        let output = Output::<CurrentNetwork>::parse("output r1 as signature;").unwrap().1;
132        assert_eq!(format!("{output}"), "output r1 as signature;");
133
134        // Record
135        let output = Output::<CurrentNetwork>::parse("output r2 as token.record;").unwrap().1;
136        assert_eq!(format!("{output}"), "output r2 as token.record;");
137    }
138}