quil_rs/instruction/
declaration.rs

1use std::str::FromStr;
2
3use nom_locate::LocatedSpan;
4
5#[cfg(feature = "stubs")]
6use pyo3_stub_gen::derive::{gen_stub_pyclass, gen_stub_pyclass_enum};
7
8use crate::{
9    parser::{common::parse_memory_reference, lex, ParseError},
10    pickleable_new,
11    program::{disallow_leftover, SyntaxError},
12    quil::Quil,
13};
14
15use super::ArithmeticOperand;
16
17#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
18#[cfg_attr(feature = "stubs", gen_stub_pyclass_enum)]
19#[cfg_attr(
20    feature = "python",
21    pyo3::pyclass(
22        module = "quil.instructions",
23        eq,
24        frozen,
25        hash,
26        rename_all = "SCREAMING_SNAKE_CASE"
27    )
28)]
29pub enum ScalarType {
30    Bit,
31    Integer,
32    Octet,
33    Real,
34}
35
36impl Quil for ScalarType {
37    fn write(
38        &self,
39        f: &mut impl std::fmt::Write,
40        _fall_back_to_debug: bool,
41    ) -> crate::quil::ToQuilResult<()> {
42        use ScalarType::*;
43        write!(
44            f,
45            "{}",
46            match self {
47                Bit => "BIT",
48                Integer => "INTEGER",
49                Octet => "OCTET",
50                Real => "REAL",
51            }
52        )
53        .map_err(Into::into)
54    }
55}
56
57#[derive(Clone, Debug, Hash, PartialEq, Eq)]
58#[cfg_attr(feature = "stubs", gen_stub_pyclass)]
59#[cfg_attr(
60    feature = "python",
61    pyo3::pyclass(module = "quil.instructions", eq, frozen, hash, get_all, subclass)
62)]
63pub struct Vector {
64    pub data_type: ScalarType,
65    pub length: u64,
66}
67
68pickleable_new! {
69    impl Vector {
70        pub fn new(data_type: ScalarType, length: u64);
71    }
72}
73
74impl Quil for Vector {
75    fn write(
76        &self,
77        f: &mut impl std::fmt::Write,
78        fall_back_to_debug: bool,
79    ) -> crate::quil::ToQuilResult<()> {
80        self.data_type.write(f, fall_back_to_debug)?;
81        write!(f, "[{}]", self.length).map_err(Into::into)
82    }
83}
84
85#[derive(Clone, Debug, PartialEq, Eq, Hash)]
86#[cfg_attr(feature = "stubs", gen_stub_pyclass)]
87#[cfg_attr(
88    feature = "python",
89    pyo3::pyclass(module = "quil.instructions", eq, frozen, hash, subclass)
90)]
91pub struct Sharing {
92    pub name: String,
93    pub offsets: Vec<Offset>,
94}
95
96pickleable_new! {
97    impl Sharing {
98        pub fn new(name: String, offsets: Vec<Offset>);
99    }
100}
101
102#[derive(Clone, Debug, PartialEq, Eq, Hash)]
103#[cfg_attr(feature = "stubs", gen_stub_pyclass)]
104#[cfg_attr(
105    feature = "python",
106    pyo3::pyclass(module = "quil.instructions", eq, frozen, hash, subclass)
107)]
108pub struct Offset {
109    pub offset: u64,
110    pub data_type: ScalarType,
111}
112
113pickleable_new! {
114    impl Offset {
115        pub fn new(offset: u64, data_type: ScalarType);
116    }
117}
118
119impl Quil for Offset {
120    fn write(
121        &self,
122        f: &mut impl std::fmt::Write,
123        fall_back_to_debug: bool,
124    ) -> crate::quil::ToQuilResult<()> {
125        write!(f, "{} ", self.offset)?;
126        self.data_type.write(f, fall_back_to_debug)
127    }
128}
129
130#[derive(Clone, Debug, PartialEq, Eq, Hash)]
131#[cfg_attr(feature = "stubs", gen_stub_pyclass)]
132#[cfg_attr(
133    feature = "python",
134    pyo3::pyclass(module = "quil.instructions", eq, frozen, hash, get_all, subclass)
135)]
136pub struct Declaration {
137    pub name: String,
138    pub size: Vector,
139    pub sharing: Option<Sharing>,
140}
141
142pickleable_new! {
143    impl Declaration {
144        pub fn new(name: String, size: Vector, sharing: Option<Sharing>);
145    }
146}
147
148impl Quil for Declaration {
149    fn write(
150        &self,
151        f: &mut impl std::fmt::Write,
152        fall_back_to_debug: bool,
153    ) -> crate::quil::ToQuilResult<()> {
154        write!(f, "DECLARE {} ", self.name)?;
155        self.size.write(f, fall_back_to_debug)?;
156        if let Some(shared) = &self.sharing {
157            write!(f, " SHARING {}", shared.name)?;
158            if !shared.offsets.is_empty() {
159                write!(f, " OFFSET")?;
160                for offset in shared.offsets.iter() {
161                    write!(f, " ")?;
162                    offset.write(f, fall_back_to_debug)?;
163                }
164            }
165        }
166        Ok(())
167    }
168}
169
170#[cfg(test)]
171mod test_declaration {
172    use super::{Declaration, Offset, ScalarType, Sharing, Vector};
173    use crate::quil::Quil;
174    use insta::assert_snapshot;
175    use rstest::rstest;
176
177    #[rstest]
178    #[case(
179        "Basic Declaration",
180        Declaration{
181            name: "ro".to_string(),
182            size: Vector{data_type: ScalarType::Bit, length: 1},
183            sharing: None,
184
185        }
186    )]
187    #[case(
188        "Shared Declaration",
189        Declaration{
190            name: "ro".to_string(),
191            size: Vector{data_type: ScalarType::Integer, length: 2},
192            sharing: Some(Sharing{name: "foo".to_string(), offsets: vec![]})
193        }
194    )]
195    #[case(
196        "Shared Declaration with Offsets",
197        Declaration{
198            name: "ro".to_string(),
199            size: Vector{data_type: ScalarType::Real, length: 3},
200            sharing: Some(Sharing{
201                name: "bar".to_string(),
202                offsets: vec![
203                    Offset{offset: 4, data_type: ScalarType::Bit},
204                    Offset{offset: 5, data_type: ScalarType::Bit}
205                ]})
206        }
207    )]
208    fn test_display(#[case] description: &str, #[case] declaration: Declaration) {
209        insta::with_settings!({
210            snapshot_suffix => description,
211        }, {
212            assert_snapshot!(declaration.to_quil_or_debug())
213        })
214    }
215}
216
217#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
218#[cfg_attr(feature = "stubs", gen_stub_pyclass)]
219#[cfg_attr(
220    feature = "python",
221    pyo3::pyclass(module = "quil.instructions", get_all, eq, frozen, hash, subclass)
222)]
223pub struct MemoryReference {
224    pub name: String,
225    pub index: u64,
226}
227
228pickleable_new! {
229    impl MemoryReference {
230        pub fn new(name: String, index: u64);
231    }
232}
233
234impl Quil for MemoryReference {
235    fn write(
236        &self,
237        f: &mut impl std::fmt::Write,
238        _fall_back_to_debug: bool,
239    ) -> crate::quil::ToQuilResult<()> {
240        write!(f, "{}[{}]", self.name, self.index).map_err(Into::into)
241    }
242}
243
244impl std::fmt::Display for MemoryReference {
245    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
246        write!(f, "{}[{}]", self.name, self.index)
247    }
248}
249
250impl FromStr for MemoryReference {
251    type Err = SyntaxError<Self>;
252
253    fn from_str(s: &str) -> Result<Self, Self::Err> {
254        let input = LocatedSpan::new(s);
255        let tokens = lex(input)?;
256        disallow_leftover(
257            parse_memory_reference(&tokens).map_err(ParseError::from_nom_internal_err),
258        )
259    }
260}
261
262#[derive(Clone, Debug, PartialEq, Eq, Hash)]
263#[cfg_attr(feature = "stubs", gen_stub_pyclass)]
264#[cfg_attr(
265    feature = "python",
266    pyo3::pyclass(module = "quil.instructions", eq, frozen, hash, get_all, subclass)
267)]
268pub struct Load {
269    pub destination: MemoryReference,
270    pub source: String,
271    pub offset: MemoryReference,
272}
273
274pickleable_new! {
275    impl Load {
276        pub fn new(destination: MemoryReference, source: String, offset: MemoryReference);
277    }
278}
279
280impl Quil for Load {
281    fn write(
282        &self,
283        f: &mut impl std::fmt::Write,
284        fall_back_to_debug: bool,
285    ) -> crate::quil::ToQuilResult<()> {
286        write!(f, "LOAD ")?;
287        self.destination.write(f, fall_back_to_debug)?;
288        write!(f, " {} ", self.source)?;
289        self.offset.write(f, fall_back_to_debug)?;
290        Ok(())
291    }
292}
293
294#[derive(Clone, Debug, PartialEq, Hash)]
295#[cfg_attr(feature = "stubs", gen_stub_pyclass)]
296#[cfg_attr(
297    feature = "python",
298    pyo3::pyclass(module = "quil.instructions", eq, frozen, hash, get_all, subclass)
299)]
300pub struct Store {
301    pub destination: String,
302    pub offset: MemoryReference,
303    pub source: ArithmeticOperand,
304}
305
306pickleable_new! {
307    impl Store {
308        pub fn new(destination: String, offset: MemoryReference, source: ArithmeticOperand);
309    }
310}
311
312impl Quil for Store {
313    fn write(
314        &self,
315        f: &mut impl std::fmt::Write,
316        fall_back_to_debug: bool,
317    ) -> crate::quil::ToQuilResult<()> {
318        write!(f, "STORE {} ", self.destination)?;
319        self.offset.write(f, fall_back_to_debug)?;
320        write!(f, " ")?;
321        self.source.write(f, fall_back_to_debug)?;
322        Ok(())
323    }
324}