snarkvm_synthesizer_program/logic/command/
branch.rs1use crate::{Opcode, Operand};
17use console::{network::prelude::*, program::Identifier};
18
19pub type BranchEq<N> = Branch<N, { Variant::BranchEq as u8 }>;
21pub type BranchNeq<N> = Branch<N, { Variant::BranchNeq as u8 }>;
23
24enum Variant {
25 BranchEq,
26 BranchNeq,
27}
28
29#[derive(Clone, PartialEq, Eq, Hash)]
31pub struct Branch<N: Network, const VARIANT: u8> {
32 operands: [Operand<N>; 2],
34 position: Identifier<N>,
36}
37
38impl<N: Network, const VARIANT: u8> Branch<N, VARIANT> {
39 #[inline]
41 pub const fn opcode() -> Opcode {
42 match VARIANT {
43 0 => Opcode::Command("branch.eq"),
44 1 => Opcode::Command("branch.neq"),
45 _ => panic!("Invalid 'branch' instruction opcode"),
46 }
47 }
48
49 #[inline]
51 pub const fn operands(&self) -> &[Operand<N>] {
52 &self.operands
53 }
54
55 #[inline]
57 pub const fn first(&self) -> &Operand<N> {
58 &self.operands[0]
59 }
60
61 #[inline]
63 pub const fn second(&self) -> &Operand<N> {
64 &self.operands[1]
65 }
66
67 #[inline]
69 pub const fn position(&self) -> &Identifier<N> {
70 &self.position
71 }
72
73 #[inline]
75 pub fn contains_external_struct(&self) -> bool {
76 false
77 }
78}
79
80impl<N: Network, const VARIANT: u8> Parser for Branch<N, VARIANT> {
81 #[inline]
83 fn parse(string: &str) -> ParserResult<Self> {
84 let (string, _) = Sanitizer::parse(string)?;
86 let (string, _) = tag(*Self::opcode())(string)?;
88 let (string, _) = Sanitizer::parse_whitespaces(string)?;
90
91 let (string, first) = Operand::parse(string)?;
93 let (string, _) = Sanitizer::parse_whitespaces(string)?;
95
96 let (string, second) = Operand::parse(string)?;
98 let (string, _) = Sanitizer::parse_whitespaces(string)?;
100
101 let (string, _) = tag("to")(string)?;
103 let (string, _) = Sanitizer::parse_whitespaces(string)?;
105 let (string, position) = Identifier::parse(string)?;
107
108 let (string, _) = Sanitizer::parse_whitespaces(string)?;
110 let (string, _) = tag(";")(string)?;
112
113 Ok((string, Self { operands: [first, second], position }))
114 }
115}
116
117impl<N: Network, const VARIANT: u8> FromStr for Branch<N, VARIANT> {
118 type Err = Error;
119
120 #[inline]
122 fn from_str(string: &str) -> Result<Self> {
123 match Self::parse(string) {
124 Ok((remainder, object)) => {
125 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
127 Ok(object)
129 }
130 Err(error) => bail!("Failed to parse string. {error}"),
131 }
132 }
133}
134
135impl<N: Network, const VARIANT: u8> Debug for Branch<N, VARIANT> {
136 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
138 Display::fmt(self, f)
139 }
140}
141
142impl<N: Network, const VARIANT: u8> Display for Branch<N, VARIANT> {
143 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
145 write!(f, "{} {} {} to {};", Self::opcode(), self.first(), self.second(), self.position)
147 }
148}
149
150impl<N: Network, const VARIANT: u8> FromBytes for Branch<N, VARIANT> {
151 fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
153 let first = Operand::read_le(&mut reader)?;
155 let second = Operand::read_le(&mut reader)?;
157 let position = Identifier::read_le(&mut reader)?;
159
160 Ok(Self { operands: [first, second], position })
162 }
163}
164
165impl<N: Network, const VARIANT: u8> ToBytes for Branch<N, VARIANT> {
166 fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
168 self.first().write_le(&mut writer)?;
170 self.second().write_le(&mut writer)?;
172 self.position.write_le(&mut writer)
174 }
175}
176
177#[cfg(test)]
178mod tests {
179 use super::*;
180 use console::{
181 network::MainnetV0,
182 program::{Identifier, Register},
183 };
184
185 type CurrentNetwork = MainnetV0;
186
187 #[test]
188 fn test_parse() {
189 let (string, branch) = BranchEq::<CurrentNetwork>::parse("branch.eq r0 r1 to exit;").unwrap();
190 assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'");
191 assert_eq!(branch.first(), &Operand::Register(Register::Locator(0)), "The first operand is incorrect");
192 assert_eq!(branch.second(), &Operand::Register(Register::Locator(1)), "The second operand is incorrect");
193 assert_eq!(branch.position, Identifier::from_str("exit").unwrap(), "The position is incorrect");
194
195 let (string, branch) = BranchNeq::<CurrentNetwork>::parse("branch.neq r3 r4 to start;").unwrap();
196 assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'");
197 assert_eq!(branch.first(), &Operand::Register(Register::Locator(3)), "The first operand is incorrect");
198 assert_eq!(branch.second(), &Operand::Register(Register::Locator(4)), "The second operand is incorrect");
199 assert_eq!(branch.position, Identifier::from_str("start").unwrap(), "The position is incorrect");
200 }
201}