branch.rs
1 // Copyright (c) 2025 ADnet Contributors 2 // This file is part of the AlphaVM 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 16 use crate::{Opcode, Operand}; 17 use console::{network::prelude::*, program::Identifier}; 18 19 /// Jumps to `position`, if `first` equals `second`. 20 pub type BranchEq<N> = Branch<N, { Variant::BranchEq as u8 }>; 21 /// Jumps to `position`, if `first` does **not** equal `second`. 22 pub type BranchNeq<N> = Branch<N, { Variant::BranchNeq as u8 }>; 23 24 enum Variant { 25 BranchEq, 26 BranchNeq, 27 } 28 29 /// Compares `first` and `second` and jumps to `position`, if the condition is met. 30 #[derive(Clone, PartialEq, Eq, Hash)] 31 pub struct Branch<N: Network, const VARIANT: u8> { 32 /// The operands. 33 operands: [Operand<N>; 2], 34 /// The position. 35 position: Identifier<N>, 36 } 37 38 impl<N: Network, const VARIANT: u8> Branch<N, VARIANT> { 39 /// Returns the opcode. 40 #[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 /// Returns the operands. 50 #[inline] 51 pub const fn operands(&self) -> &[Operand<N>] { 52 &self.operands 53 } 54 55 /// Returns the first operand. 56 #[inline] 57 pub const fn first(&self) -> &Operand<N> { 58 &self.operands[0] 59 } 60 61 /// Returns the second operand. 62 #[inline] 63 pub const fn second(&self) -> &Operand<N> { 64 &self.operands[1] 65 } 66 67 /// Returns the position. 68 #[inline] 69 pub const fn position(&self) -> &Identifier<N> { 70 &self.position 71 } 72 } 73 74 impl<N: Network, const VARIANT: u8> Parser for Branch<N, VARIANT> { 75 /// Parses a string into an command. 76 #[inline] 77 fn parse(string: &str) -> ParserResult<Self> { 78 // Parse the whitespace and comments from the string. 79 let (string, _) = Sanitizer::parse(string)?; 80 // Parse the opcode from the string. 81 let (string, _) = tag(*Self::opcode())(string)?; 82 // Parse the whitespace from the string. 83 let (string, _) = Sanitizer::parse_whitespaces(string)?; 84 85 // Parse the first operand from the string. 86 let (string, first) = Operand::parse(string)?; 87 // Parse the whitespace from the string. 88 let (string, _) = Sanitizer::parse_whitespaces(string)?; 89 90 // Parse the second operand from the string. 91 let (string, second) = Operand::parse(string)?; 92 // Parse the whitespace from the string. 93 let (string, _) = Sanitizer::parse_whitespaces(string)?; 94 95 // Parse the "to" from the string. 96 let (string, _) = tag("to")(string)?; 97 // Parse the whitespace from the string. 98 let (string, _) = Sanitizer::parse_whitespaces(string)?; 99 // Parse the position from the string. 100 let (string, position) = Identifier::parse(string)?; 101 102 // Parse the whitespace from the string. 103 let (string, _) = Sanitizer::parse_whitespaces(string)?; 104 // Parse the ";" from the string. 105 let (string, _) = tag(";")(string)?; 106 107 Ok((string, Self { operands: [first, second], position })) 108 } 109 } 110 111 impl<N: Network, const VARIANT: u8> FromStr for Branch<N, VARIANT> { 112 type Err = Error; 113 114 /// Parses a string into a command. 115 #[inline] 116 fn from_str(string: &str) -> Result<Self> { 117 match Self::parse(string) { 118 Ok((remainder, object)) => { 119 // Ensure the remainder is empty. 120 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\""); 121 // Return the object. 122 Ok(object) 123 } 124 Err(error) => bail!("Failed to parse string. {error}"), 125 } 126 } 127 } 128 129 impl<N: Network, const VARIANT: u8> Debug for Branch<N, VARIANT> { 130 /// Prints the command as a string. 131 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 132 Display::fmt(self, f) 133 } 134 } 135 136 impl<N: Network, const VARIANT: u8> Display for Branch<N, VARIANT> { 137 /// Prints the command to a string. 138 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 139 // Print the command. 140 write!(f, "{} {} {} to {};", Self::opcode(), self.first(), self.second(), self.position) 141 } 142 } 143 144 impl<N: Network, const VARIANT: u8> FromBytes for Branch<N, VARIANT> { 145 /// Reads the command from a buffer. 146 fn read_le<R: Read>(mut reader: R) -> IoResult<Self> { 147 // Read the first operand. 148 let first = Operand::read_le(&mut reader)?; 149 // Read the second operand. 150 let second = Operand::read_le(&mut reader)?; 151 // Read the position. 152 let position = Identifier::read_le(&mut reader)?; 153 154 // Return the command. 155 Ok(Self { operands: [first, second], position }) 156 } 157 } 158 159 impl<N: Network, const VARIANT: u8> ToBytes for Branch<N, VARIANT> { 160 /// Writes the command to a buffer. 161 fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> { 162 // Write the first operand. 163 self.first().write_le(&mut writer)?; 164 // Write the second operand. 165 self.second().write_le(&mut writer)?; 166 // Write the position. 167 self.position.write_le(&mut writer) 168 } 169 } 170 171 #[cfg(test)] 172 mod tests { 173 use super::*; 174 use console::{ 175 network::MainnetV0, 176 program::{Identifier, Register}, 177 }; 178 179 type CurrentNetwork = MainnetV0; 180 181 #[test] 182 fn test_parse() { 183 let (string, branch) = BranchEq::<CurrentNetwork>::parse("branch.eq r0 r1 to exit;").unwrap(); 184 assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'"); 185 assert_eq!(branch.first(), &Operand::Register(Register::Locator(0)), "The first operand is incorrect"); 186 assert_eq!(branch.second(), &Operand::Register(Register::Locator(1)), "The second operand is incorrect"); 187 assert_eq!(branch.position, Identifier::from_str("exit").unwrap(), "The position is incorrect"); 188 189 let (string, branch) = BranchNeq::<CurrentNetwork>::parse("branch.neq r3 r4 to start;").unwrap(); 190 assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'"); 191 assert_eq!(branch.first(), &Operand::Register(Register::Locator(3)), "The first operand is incorrect"); 192 assert_eq!(branch.second(), &Operand::Register(Register::Locator(4)), "The second operand is incorrect"); 193 assert_eq!(branch.position, Identifier::from_str("start").unwrap(), "The position is incorrect"); 194 } 195 }