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}