snarkvm_synthesizer_program/logic/command/
position.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 crate::Opcode;
17use console::{network::prelude::*, program::Identifier};
18
19/// A position command, e.g. `position exit`.
20/// Indicates a position to which the program can branch to.
21#[derive(Clone, PartialEq, Eq, Hash)]
22pub struct Position<N: Network> {
23    /// The name to reference when branching to this position.
24    name: Identifier<N>,
25}
26
27impl<N: Network> Position<N> {
28    /// Returns the opcode.
29    #[inline]
30    pub const fn opcode() -> Opcode {
31        Opcode::Command("position")
32    }
33
34    /// Returns the name.
35    #[inline]
36    pub fn name(&self) -> &Identifier<N> {
37        &self.name
38    }
39}
40
41impl<N: Network> Position<N> {
42    /// Finalizes the command.
43    /// Note that `Position` is a no-op.
44    #[inline]
45    pub fn finalize(&self) -> Result<()> {
46        Ok(())
47    }
48}
49
50impl<N: Network> Parser for Position<N> {
51    /// Parses a string into a command.
52    #[inline]
53    fn parse(string: &str) -> ParserResult<Self> {
54        // Parse the whitespace and comments from the string.
55        let (string, _) = Sanitizer::parse(string)?;
56        // Parse the opcode from the string.
57        let (string, _) = tag(*Self::opcode())(string)?;
58        // Parse the whitespace from the string.
59        let (string, _) = Sanitizer::parse_whitespaces(string)?;
60
61        // Parse the name from the string.
62        let (string, name) = Identifier::parse(string)?;
63
64        // Parse the whitespace from the string.
65        let (string, _) = Sanitizer::parse_whitespaces(string)?;
66        // Parse the ";" from the string.
67        let (string, _) = tag(";")(string)?;
68
69        Ok((string, Self { name }))
70    }
71}
72
73impl<N: Network> FromStr for Position<N> {
74    type Err = Error;
75
76    /// Parses a string into the command.
77    #[inline]
78    fn from_str(string: &str) -> Result<Self> {
79        match Self::parse(string) {
80            Ok((remainder, object)) => {
81                // Ensure the remainder is empty.
82                ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
83                // Return the object.
84                Ok(object)
85            }
86            Err(error) => bail!("Failed to parse string. {error}"),
87        }
88    }
89}
90
91impl<N: Network> Debug for Position<N> {
92    /// Prints the command as a string.
93    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
94        Display::fmt(self, f)
95    }
96}
97
98impl<N: Network> Display for Position<N> {
99    /// Prints the command to a string.
100    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
101        // Print the command.
102        write!(f, "{} ", Self::opcode())?;
103        // Print the name.
104        write!(f, "{};", self.name)
105    }
106}
107
108impl<N: Network> FromBytes for Position<N> {
109    /// Reads the command from a buffer.
110    fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
111        // Read the name.
112        let name = Identifier::read_le(&mut reader)?;
113        // Return the command.
114        Ok(Self { name })
115    }
116}
117
118impl<N: Network> ToBytes for Position<N> {
119    /// Writes the command to a buffer.
120    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
121        // Write the name.
122        self.name.write_le(&mut writer)
123    }
124}
125
126#[cfg(test)]
127mod tests {
128    use super::*;
129    use console::network::MainnetV0;
130
131    type CurrentNetwork = MainnetV0;
132
133    #[test]
134    fn test_parse() {
135        let (string, position) = Position::<CurrentNetwork>::parse("position exit;").unwrap();
136        assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'");
137        assert_eq!(position.name, Identifier::from_str("exit").unwrap());
138    }
139}