snarkvm_synthesizer_program/logic/instruction/operand/
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> Parser for Operand<N> {
19    /// Parses a string into a operand.
20    #[inline]
21    fn parse(string: &str) -> ParserResult<Self> {
22        // Parse to determine the operand (order matters).
23        alt((
24            // Parse special operands before literals, registers, and program IDs.
25            // This ensures correctness in the case where a special operand is a prefix of, or could be parsed as, a literal, register, or program ID.
26            map(tag("group::GEN"), |_| Self::Literal(Literal::Group(Group::generator()))),
27            map(tag("self.signer"), |_| Self::Signer),
28            map(tag("self.caller"), |_| Self::Caller),
29            map(tag("block.height"), |_| Self::BlockHeight),
30            map(tag("network.id"), |_| Self::NetworkID),
31            // Note that `Operand::ProgramID`s must be parsed before `Operand::Literal`s, since a program ID can be implicitly parsed as a literal address.
32            // This ensures that the string representation of a program uses the `Operand::ProgramID` variant.
33            map(ProgramID::parse, |program_id| Self::ProgramID(program_id)),
34            map(Literal::parse, |literal| Self::Literal(literal)),
35            map(Register::parse, |register| Self::Register(register)),
36        ))(string)
37    }
38}
39
40impl<N: Network> FromStr for Operand<N> {
41    type Err = Error;
42
43    /// Parses a string into an operand.
44    #[inline]
45    fn from_str(string: &str) -> Result<Self> {
46        match Self::parse(string) {
47            Ok((remainder, object)) => {
48                // Ensure the remainder is empty.
49                ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
50                // Return the object.
51                Ok(object)
52            }
53            Err(error) => bail!("Failed to parse string. {error}"),
54        }
55    }
56}
57
58impl<N: Network> Debug for Operand<N> {
59    /// Prints the operand as a string.
60    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
61        Display::fmt(self, f)
62    }
63}
64
65impl<N: Network> Display for Operand<N> {
66    /// Prints the operand as a string.
67    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
68        match self {
69            // Prints the literal, i.e. 10field.private
70            Self::Literal(literal) => Display::fmt(literal, f),
71            // Prints the register, i.e. r0 or r0.owner
72            Self::Register(register) => Display::fmt(register, f),
73            // Prints the program ID, i.e. howard.aleo
74            Self::ProgramID(program_id) => Display::fmt(program_id, f),
75            // Prints the identifier for the signer, i.e. self.signer
76            Self::Signer => write!(f, "self.signer"),
77            // Prints the identifier for the caller, i.e. self.caller
78            Self::Caller => write!(f, "self.caller"),
79            // Prints the identifier for the block height, i.e. block.height
80            Self::BlockHeight => write!(f, "block.height"),
81            // Prints the identifier for the network ID, i.e. network.id
82            Self::NetworkID => write!(f, "network.id"),
83        }
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90    use console::network::MainnetV0;
91
92    type CurrentNetwork = MainnetV0;
93
94    #[test]
95    fn test_operand_parse() -> Result<()> {
96        let operand = Operand::<CurrentNetwork>::parse("1field").unwrap().1;
97        assert_eq!(Operand::Literal(Literal::from_str("1field")?), operand);
98
99        let operand = Operand::<CurrentNetwork>::parse("r0").unwrap().1;
100        assert_eq!(Operand::Register(Register::from_str("r0")?), operand);
101
102        let operand = Operand::<CurrentNetwork>::parse("r0.owner").unwrap().1;
103        assert_eq!(Operand::Register(Register::from_str("r0.owner")?), operand);
104
105        let operand = Operand::<CurrentNetwork>::parse("howard.aleo").unwrap().1;
106        assert_eq!(Operand::ProgramID(ProgramID::from_str("howard.aleo")?), operand);
107
108        let operand = Operand::<CurrentNetwork>::parse("self.signer").unwrap().1;
109        assert_eq!(Operand::Signer, operand);
110
111        let operand = Operand::<CurrentNetwork>::parse("self.caller").unwrap().1;
112        assert_eq!(Operand::Caller, operand);
113
114        let operand = Operand::<CurrentNetwork>::parse("block.height").unwrap().1;
115        assert_eq!(Operand::BlockHeight, operand);
116
117        let operand = Operand::<CurrentNetwork>::parse("network.id").unwrap().1;
118        assert_eq!(Operand::NetworkID, operand);
119
120        let operand = Operand::<CurrentNetwork>::parse("group::GEN").unwrap().1;
121        assert_eq!(Operand::Literal(Literal::Group(Group::generator())), operand);
122
123        // Sanity check a failure case.
124        let (remainder, operand) = Operand::<CurrentNetwork>::parse("1field.private").unwrap();
125        assert_eq!(Operand::Literal(Literal::from_str("1field")?), operand);
126        assert_eq!(".private", remainder);
127
128        Ok(())
129    }
130
131    #[test]
132    fn test_operand_display() {
133        let operand = Operand::<CurrentNetwork>::parse("1field").unwrap().1;
134        assert_eq!(format!("{operand}"), "1field");
135
136        let operand = Operand::<CurrentNetwork>::parse("r0").unwrap().1;
137        assert_eq!(format!("{operand}"), "r0");
138
139        let operand = Operand::<CurrentNetwork>::parse("r0.owner").unwrap().1;
140        assert_eq!(format!("{operand}"), "r0.owner");
141
142        let operand = Operand::<CurrentNetwork>::parse("howard.aleo").unwrap().1;
143        assert_eq!(format!("{operand}"), "howard.aleo");
144
145        let operand = Operand::<CurrentNetwork>::parse("self.signer").unwrap().1;
146        assert_eq!(format!("{operand}"), "self.signer");
147
148        let operand = Operand::<CurrentNetwork>::parse("self.caller").unwrap().1;
149        assert_eq!(format!("{operand}"), "self.caller");
150
151        let operand = Operand::<CurrentNetwork>::parse("group::GEN").unwrap().1;
152        assert_eq!(
153            format!("{operand}"),
154            "1540945439182663264862696551825005342995406165131907382295858612069623286213group"
155        );
156    }
157
158    #[test]
159    fn test_operand_from_str_fails() -> Result<()> {
160        assert!(Operand::<CurrentNetwork>::from_str("1field.private").is_err());
161        Ok(())
162    }
163}