Skip to main content

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)]
223#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
224pub struct MemoryReference {
225    #[cfg_attr(
226        test,
227        proptest(strategy = "crate::expression::proptest_helpers::arb_name()")
228    )]
229    pub name: String,
230    pub index: u64,
231}
232
233pickleable_new! {
234    impl MemoryReference {
235        pub fn new(name: String, index: u64);
236    }
237}
238
239impl Quil for MemoryReference {
240    fn write(
241        &self,
242        f: &mut impl std::fmt::Write,
243        _fall_back_to_debug: bool,
244    ) -> crate::quil::ToQuilResult<()> {
245        write!(f, "{}[{}]", self.name, self.index).map_err(Into::into)
246    }
247}
248
249impl std::fmt::Display for MemoryReference {
250    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
251        write!(f, "{}[{}]", self.name, self.index)
252    }
253}
254
255impl FromStr for MemoryReference {
256    type Err = SyntaxError<Self>;
257
258    fn from_str(s: &str) -> Result<Self, Self::Err> {
259        let input = LocatedSpan::new(s);
260        let tokens = lex(input)?;
261        disallow_leftover(
262            parse_memory_reference(&tokens).map_err(ParseError::from_nom_internal_err),
263        )
264    }
265}
266
267#[derive(Clone, Debug, PartialEq, Eq, Hash)]
268#[cfg_attr(feature = "stubs", gen_stub_pyclass)]
269#[cfg_attr(
270    feature = "python",
271    pyo3::pyclass(module = "quil.instructions", eq, frozen, hash, get_all, subclass)
272)]
273pub struct Load {
274    pub destination: MemoryReference,
275    pub source: String,
276    pub offset: MemoryReference,
277}
278
279pickleable_new! {
280    impl Load {
281        pub fn new(destination: MemoryReference, source: String, offset: MemoryReference);
282    }
283}
284
285impl Quil for Load {
286    fn write(
287        &self,
288        f: &mut impl std::fmt::Write,
289        fall_back_to_debug: bool,
290    ) -> crate::quil::ToQuilResult<()> {
291        write!(f, "LOAD ")?;
292        self.destination.write(f, fall_back_to_debug)?;
293        write!(f, " {} ", self.source)?;
294        self.offset.write(f, fall_back_to_debug)?;
295        Ok(())
296    }
297}
298
299#[derive(Clone, Debug, PartialEq, Hash)]
300#[cfg_attr(feature = "stubs", gen_stub_pyclass)]
301#[cfg_attr(
302    feature = "python",
303    pyo3::pyclass(module = "quil.instructions", eq, frozen, hash, get_all, subclass)
304)]
305pub struct Store {
306    pub destination: String,
307    pub offset: MemoryReference,
308    pub source: ArithmeticOperand,
309}
310
311pickleable_new! {
312    impl Store {
313        pub fn new(destination: String, offset: MemoryReference, source: ArithmeticOperand);
314    }
315}
316
317impl Quil for Store {
318    fn write(
319        &self,
320        f: &mut impl std::fmt::Write,
321        fall_back_to_debug: bool,
322    ) -> crate::quil::ToQuilResult<()> {
323        write!(f, "STORE {} ", self.destination)?;
324        self.offset.write(f, fall_back_to_debug)?;
325        write!(f, " ")?;
326        self.source.write(f, fall_back_to_debug)?;
327        Ok(())
328    }
329}