quil_rs/instruction/
declaration.rs

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