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::Checksum` and `Operand::Edition` must be parsed before `Operand::ProgramID`s, since an edition or checksum may be prefixed with a program ID.
32            map(pair(opt(terminated(ProgramID::parse, tag("/"))), tag("checksum")), |(program_id, _)| {
33                Self::Checksum(program_id)
34            }),
35            map(pair(opt(terminated(ProgramID::parse, tag("/"))), tag("edition")), |(program_id, _)| {
36                Self::Edition(program_id)
37            }),
38            // Note that `Operand::ProgramOwner` must be parsed before `Operand::ProgramID`s, since an owner may be prefixed with a program ID.
39            map(pair(opt(terminated(ProgramID::parse, tag("/"))), tag("program_owner")), |(program_id, _)| {
40                Self::ProgramOwner(program_id)
41            }),
42            // Note that `Operand::ProgramID`s must be parsed before `Operand::Literal`s, since a program ID can be implicitly parsed as a literal address.
43            // This ensures that the string representation of a program uses the `Operand::ProgramID` variant.
44            map(ProgramID::parse, |program_id| Self::ProgramID(program_id)),
45            map(Literal::parse, |literal| Self::Literal(literal)),
46            map(Register::parse, |register| Self::Register(register)),
47        ))(string)
48    }
49}
50
51impl<N: Network> FromStr for Operand<N> {
52    type Err = Error;
53
54    /// Parses a string into an operand.
55    #[inline]
56    fn from_str(string: &str) -> Result<Self> {
57        match Self::parse(string) {
58            Ok((remainder, object)) => {
59                // Ensure the remainder is empty.
60                ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
61                // Return the object.
62                Ok(object)
63            }
64            Err(error) => bail!("Failed to parse string. {error}"),
65        }
66    }
67}
68
69impl<N: Network> Debug for Operand<N> {
70    /// Prints the operand as a string.
71    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
72        Display::fmt(self, f)
73    }
74}
75
76impl<N: Network> Display for Operand<N> {
77    /// Prints the operand as a string.
78    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
79        match self {
80            // Prints the literal, i.e. 10field.private
81            Self::Literal(literal) => Display::fmt(literal, f),
82            // Prints the register, i.e. r0 or r0.owner
83            Self::Register(register) => Display::fmt(register, f),
84            // Prints the program ID, i.e. howard.aleo
85            Self::ProgramID(program_id) => Display::fmt(program_id, f),
86            // Prints the identifier for the signer, i.e. self.signer
87            Self::Signer => write!(f, "self.signer"),
88            // Prints the identifier for the caller, i.e. self.caller
89            Self::Caller => write!(f, "self.caller"),
90            // Prints the identifier for the block height, i.e. block.height
91            Self::BlockHeight => write!(f, "block.height"),
92            // Prints the identifier for the network ID, i.e. network.id
93            Self::NetworkID => write!(f, "network.id"),
94            // Prints the optional program ID with the checksum keyword, i.e. `checksum` or `token.aleo/checksum`
95            Self::Checksum(program_id) => match program_id {
96                Some(program_id) => write!(f, "{program_id}/checksum"),
97                None => write!(f, "checksum"),
98            },
99            // Prints the optional program ID with the edition keyword, i.e. `edition` or  `token.aleo/edition`
100            Self::Edition(program_id) => match program_id {
101                Some(program_id) => write!(f, "{program_id}/edition"),
102                None => write!(f, "edition"),
103            },
104            // Prints the optional program ID with the program owner keyword, i.e. `program_owner` or `token.aleo/program_owner`
105            Self::ProgramOwner(program_id) => match program_id {
106                Some(program_id) => write!(f, "{program_id}/program_owner"),
107                None => write!(f, "program_owner"),
108            },
109        }
110    }
111}
112
113#[cfg(test)]
114mod tests {
115    use super::*;
116    use console::network::MainnetV0;
117
118    type CurrentNetwork = MainnetV0;
119
120    #[test]
121    fn test_operand_parse() -> Result<()> {
122        let operand = Operand::<CurrentNetwork>::parse("1field").unwrap().1;
123        assert_eq!(Operand::Literal(Literal::from_str("1field")?), operand);
124
125        let operand = Operand::<CurrentNetwork>::parse("r0").unwrap().1;
126        assert_eq!(Operand::Register(Register::from_str("r0")?), operand);
127
128        let operand = Operand::<CurrentNetwork>::parse("r0.owner").unwrap().1;
129        assert_eq!(Operand::Register(Register::from_str("r0.owner")?), operand);
130
131        let operand = Operand::<CurrentNetwork>::parse("howard.aleo").unwrap().1;
132        assert_eq!(Operand::ProgramID(ProgramID::from_str("howard.aleo")?), operand);
133
134        let operand = Operand::<CurrentNetwork>::parse("self.signer").unwrap().1;
135        assert_eq!(Operand::Signer, operand);
136
137        let operand = Operand::<CurrentNetwork>::parse("self.caller").unwrap().1;
138        assert_eq!(Operand::Caller, operand);
139
140        let operand = Operand::<CurrentNetwork>::parse("block.height").unwrap().1;
141        assert_eq!(Operand::BlockHeight, operand);
142
143        let operand = Operand::<CurrentNetwork>::parse("network.id").unwrap().1;
144        assert_eq!(Operand::NetworkID, operand);
145
146        let operand = Operand::<CurrentNetwork>::parse("group::GEN").unwrap().1;
147        assert_eq!(Operand::Literal(Literal::Group(Group::generator())), operand);
148
149        let operand = Operand::<CurrentNetwork>::parse("checksum").unwrap().1;
150        assert_eq!(Operand::Checksum(None), operand);
151
152        let operand = Operand::<CurrentNetwork>::parse("token.aleo/checksum").unwrap().1;
153        assert_eq!(Operand::Checksum(Some(ProgramID::from_str("token.aleo")?)), operand);
154
155        let operand = Operand::<CurrentNetwork>::parse("edition").unwrap().1;
156        assert_eq!(Operand::Edition(None), operand);
157
158        let operand = Operand::<CurrentNetwork>::parse("token.aleo/edition").unwrap().1;
159        assert_eq!(Operand::Edition(Some(ProgramID::from_str("token.aleo")?)), operand);
160
161        let operand = Operand::<CurrentNetwork>::parse("program_owner").unwrap().1;
162        assert_eq!(Operand::ProgramOwner(None), operand);
163
164        let operand = Operand::<CurrentNetwork>::parse("token.aleo/program_owner").unwrap().1;
165        assert_eq!(Operand::ProgramOwner(Some(ProgramID::from_str("token.aleo")?)), operand);
166
167        // Sanity check a failure case.
168        let (remainder, operand) = Operand::<CurrentNetwork>::parse("1field.private").unwrap();
169        assert_eq!(Operand::Literal(Literal::from_str("1field")?), operand);
170        assert_eq!(".private", remainder);
171
172        Ok(())
173    }
174
175    #[test]
176    fn test_operand_display() {
177        let operand = Operand::<CurrentNetwork>::parse("1field").unwrap().1;
178        assert_eq!(format!("{operand}"), "1field");
179
180        let operand = Operand::<CurrentNetwork>::parse("r0").unwrap().1;
181        assert_eq!(format!("{operand}"), "r0");
182
183        let operand = Operand::<CurrentNetwork>::parse("r0.owner").unwrap().1;
184        assert_eq!(format!("{operand}"), "r0.owner");
185
186        let operand = Operand::<CurrentNetwork>::parse("howard.aleo").unwrap().1;
187        assert_eq!(format!("{operand}"), "howard.aleo");
188
189        let operand = Operand::<CurrentNetwork>::parse("self.signer").unwrap().1;
190        assert_eq!(format!("{operand}"), "self.signer");
191
192        let operand = Operand::<CurrentNetwork>::parse("self.caller").unwrap().1;
193        assert_eq!(format!("{operand}"), "self.caller");
194
195        let operand = Operand::<CurrentNetwork>::parse("checksum").unwrap().1;
196        assert_eq!(format!("{operand}"), "checksum");
197
198        let operand = Operand::<CurrentNetwork>::parse("foo.aleo/checksum").unwrap().1;
199        assert_eq!(format!("{operand}"), "foo.aleo/checksum");
200
201        let operand = Operand::<CurrentNetwork>::parse("edition").unwrap().1;
202        assert_eq!(format!("{operand}"), "edition");
203
204        let operand = Operand::<CurrentNetwork>::parse("foo.aleo/edition").unwrap().1;
205        assert_eq!(format!("{operand}"), "foo.aleo/edition");
206
207        let operand = Operand::<CurrentNetwork>::parse("program_owner").unwrap().1;
208        assert_eq!(format!("{operand}"), "program_owner");
209
210        let operand = Operand::<CurrentNetwork>::parse("foo.aleo/program_owner").unwrap().1;
211        assert_eq!(format!("{operand}"), "foo.aleo/program_owner");
212
213        let operand = Operand::<CurrentNetwork>::parse("group::GEN").unwrap().1;
214        assert_eq!(
215            format!("{operand}"),
216            "1540945439182663264862696551825005342995406165131907382295858612069623286213group"
217        );
218    }
219
220    #[test]
221    fn test_operand_from_str_fails() -> Result<()> {
222        assert!(Operand::<CurrentNetwork>::from_str("1field.private").is_err());
223        Ok(())
224    }
225}