qasmsim/grammar/ast.rs
1//! Contain the data structures for creating OPENQASM ASTs. The module is
2//! **unstable**.
3//!
4//! # Notes
5//!
6//! Although OPENQASM 2.0 is stable enough, this module is not. Providing better
7//! errors would require an extensive use of the `Span` structure beyond
8//! statements, and adding new features to the language would require the
9//! modification os certain layouts.
10
11#[cfg(feature = "serde")]
12use serde::{Deserialize, Serialize};
13
14use crate::grammar::lexer::Location;
15
16/// Represent a OPENQASM program. A valid program contains a version string
17/// and a list of instructions.
18///
19/// # Examples
20///
21/// The AST corresponding to the following program:
22///
23/// ```qasm
24/// OPENQASM 2.0;
25/// qreg q[1];
26/// U(pi/2, 0, pi) q[0];
27/// ```
28///
29/// Can be built programmatically with:
30///
31/// ```
32/// use qasmsim::grammar::ast::{
33/// OpenQasmProgram,
34/// Span,
35/// Statement,
36/// QuantumOperation,
37/// UnitaryOperation,
38/// OpCode,
39/// Expression,
40/// Argument
41/// };
42/// use qasmsim::grammar::lexer::Location;
43///
44/// let program = OpenQasmProgram {
45/// version: "2.0".to_string(),
46/// program: vec![
47/// Span {
48/// boundaries: (Location(14), Location(24)),
49/// node: Box::new(
50/// Statement::QRegDecl(
51/// "q".to_string(),
52/// 1
53/// )
54/// )
55/// },
56/// Span {
57/// boundaries: (Location(25), Location(45)),
58/// node: Box::new(
59/// Statement::QuantumOperation(
60/// QuantumOperation::Unitary(
61/// UnitaryOperation(
62/// "U".to_string(),
63/// vec![
64/// Expression::Op(
65/// OpCode::Div,
66/// Box::new(Expression::Pi),
67/// Box::new(Expression::Int(2))
68/// ),
69/// Expression::Int(0),
70/// Expression::Pi
71/// ],
72/// vec![
73/// Argument::Item("q".to_string(), 0)
74/// ]
75/// )
76/// )
77/// )
78/// )
79/// }
80/// ]
81/// };
82/// ```
83#[derive(Debug, Clone, PartialEq)]
84#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
85pub struct OpenQasmProgram {
86 /// The version of the language as in `X.Y`. Current supported version is
87 /// `2.0`.
88 pub version: String,
89 /// List of statements conforming the program body.
90 pub program: Vec<Span<Statement>>,
91}
92
93/// Represent a OPENQASM library. OPENQASM libraries can contain gate
94/// declarations only.
95///
96/// # Examples
97///
98/// The AST corresponding to the following library:
99///
100/// ```qasm
101/// gate h q {
102/// U(pi/2, 0, pi) q[0];
103/// }
104/// ```
105///
106/// Can be built programmatically with:
107///
108/// ```
109/// use qasmsim::grammar::ast::{
110/// OpenQasmLibrary,
111/// Statement,
112/// GateOperation,
113/// UnitaryOperation,
114/// OpCode,
115/// Expression,
116/// Argument
117/// };
118/// use qasmsim::grammar::lexer::Location;
119///
120/// let library = OpenQasmLibrary {
121/// definitions: vec![
122/// Statement::GateDecl {
123/// signature: (
124/// "h".to_string(),
125/// vec![],
126/// vec!["q".to_string()],
127/// vec![
128/// GateOperation::Unitary(
129/// UnitaryOperation(
130/// "U".to_string(),
131/// vec![
132/// Expression::Op(
133/// OpCode::Div,
134/// Box::new(Expression::Pi),
135/// Box::new(Expression::Int(2))
136/// ),
137/// Expression::Int(0),
138/// Expression::Pi
139/// ],
140/// vec![
141/// Argument::Item("q".to_string(), 0)
142/// ]
143/// )
144/// )
145/// ]
146/// ),
147/// docstring: None
148/// }
149/// ]
150/// };
151#[derive(Debug, Clone, PartialEq)]
152#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
153pub struct OpenQasmLibrary {
154 /// List of gate declarations. Although the type allows for the contruction
155 /// of a library with arbitrary statements, this would not constitute a
156 /// valid OPENQASM library and the linker would panic at runtime.
157 pub definitions: Vec<Statement>,
158}
159
160// TODO: This should not be part of the grammar. It is a directive for
161// the optimizer or compiler.
162
163/// A pragma for a potential gate optimizer to prevent the combination of the
164/// gates at both sides of the barrier. The barrier takes a list of registers
165/// or qubits arguments.
166///
167/// # Examples
168///
169/// The AST corresponding to the `barrier` of the following program:
170///
171/// ```qasm
172/// barrier q;
173/// ```
174///
175/// Corresponds to:
176///
177/// ```
178/// use qasmsim::grammar::ast::{BarrierPragma, Argument};
179///
180/// let barrier = BarrierPragma(vec![Argument::Id("q".to_string())]);
181/// ```
182///
183/// A `BarrierPragma` cannot compound a valid [`OpenQasmProgram`]. It needs
184/// to be enclosed in a [`Statement`].
185///
186/// [`OpenQasmProgram`]: ./struct.OpenQasmProgram.html
187/// [`Statement`]: ./enum.Statement.html
188#[derive(Debug, Clone, PartialEq, Eq, Hash)]
189#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
190pub struct BarrierPragma(pub Vec<Argument>);
191
192/// Each of the statements you can find in a OPENQASM program.
193///
194/// OPENQASM programs are made exclusively of list of statements. The statements
195/// can be wrappers for more complex structures and take parameters representing
196/// these structures.
197///
198/// # Examples
199///
200/// The following OPENQASM code:
201///
202/// ```qasm
203/// barrier q;
204/// ```
205///
206/// Is represented, as statement, like:
207///
208/// ```
209/// use qasmsim::grammar::ast::{Statement, BarrierPragma, Argument};
210///
211/// let barrier_stmt = Statement::Barrier(
212/// BarrierPragma(vec![Argument::Id("q".to_string())])
213/// );
214/// ```
215///
216/// Enclose a statement inside a [span] and aggregate them in a list to form
217/// a valid [`OpenQasmProgram`].
218///
219/// [span]: ./struct.Span.html
220/// [`OpenQasmProgram`]: ./struct.OpenQasmProgram.html
221#[non_exhaustive]
222#[derive(Debug, Clone, PartialEq)]
223#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
224pub enum Statement {
225 /// Quantum register declaration with name and size.
226 QRegDecl(String, usize),
227 /// Classical register declaration with name and size.
228 CRegDecl(String, usize),
229 /// Quantum gate declaration with signature and docstring, if any.
230 GateDecl {
231 /// The signature includes the name, list of formal real parameters,
232 /// list of formal quantum registers, and a list of [`GateOperation`]
233 /// representing the body of the gate.
234 signature: (String, Vec<String>, Vec<String>, Vec<GateOperation>),
235 /// A string representing documentation related to the gate.
236 docstring: Option<String>,
237 },
238 /// Include statement for linking with gate libraries.
239 Include(String),
240 /// A wrapper for the barrier pragma.
241 Barrier(BarrierPragma),
242 /// Opaque gate declaration with signature and docstring, if any.
243 OpaqueGateDecl {
244 /// The signature inlcudes the name and formal lists of real parameters
245 /// and quantum registers. Opaque declarations have no body.
246 signature: (String, Vec<String>, Vec<String>),
247 /// A string representing documentation related to the gate.
248 docstring: Option<String>,
249 },
250 /// A wrapper for a quantum operation.
251 QuantumOperation(QuantumOperation),
252 /// A wrapper for making a quantum operation to simulate just if certain
253 /// equality condition holds. The wrapper takes the left-side of the
254 /// comparison, the right side, and the operation to perform.
255 Conditional(Argument, u64, QuantumOperation),
256}
257
258/// Relates a node with the fragment of source code where the node appears.
259///
260/// # Examples
261///
262/// Consider the following program:
263///
264/// ```qasm
265/// OPENQASM 2.0;
266/// qreg q[10];
267/// ```
268///
269/// The span for the second line statement is as follows:
270///
271/// ```
272/// use qasmsim::grammar::ast::{Span, Statement};
273/// use qasmsim::grammar::lexer::Location;
274///
275/// let barrier_span = Span {
276/// boundaries: (Location(14), Location(25)),
277/// node: Box::new(
278/// Statement::QRegDecl(
279/// "q".to_string(),
280/// 1
281/// )
282/// )
283/// };
284/// ```
285///
286/// Boundaries run from characters 14 to 25 corresponding to the starting-0
287/// character index of the source code.
288///
289/// Right, now, only statements are tied to spans making impossible to
290/// accurately localize inner AST nodes.
291#[derive(Debug, Clone, PartialEq)]
292#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
293pub struct Span<S> {
294 /// Pair of source locations where the AST node can be found.
295 pub boundaries: (Location, Location),
296 /// Boxed AST node.
297 pub node: Box<S>,
298}
299
300/// Any of the statements that can appear inside a gate definition.
301///
302/// # Examples
303///
304/// See [`OpenQasmLibrary`] for a complete example.
305///
306/// A gate in OPENQASM is always reversible so gates can only be compound of
307/// barriers (which are no-op actually) and other gate invocations.
308///
309/// [`OpenQasmLibrary`]: ./struct.OpenQasmLibrary.html
310#[non_exhaustive]
311#[derive(Debug, Clone, PartialEq)]
312#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
313pub enum GateOperation {
314 /// A gate invocation.
315 Unitary(UnitaryOperation),
316 /// A barrier pragma.
317 Barrier(BarrierPragma),
318}
319
320/// Any of the operations that actuates over quantum registers.
321///
322/// # Examples
323///
324/// See [`OpenQasmProgram`] for a complete examples.
325///
326/// [`OpenQasmProgram`]: ./struct.OpenQasmProgram.html
327#[non_exhaustive]
328#[derive(Debug, Clone, PartialEq)]
329#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
330pub enum QuantumOperation {
331 /// A gate invocation.
332 Unitary(UnitaryOperation),
333 /// A measurement on a quantum register to a classical register.
334 Measure(Argument, Argument),
335 /// A reset operation on a quantum register.
336 Reset(Argument),
337}
338
339/// A gate "invocation".
340///
341/// The name comes after the fact that all quantum gates are [unitary]
342/// operators. Calling a gate consists on applying it on some quantum
343/// registers.
344///
345/// # Examples
346///
347/// See [`OpenQasmProgram`] for a complete example.
348///
349/// [`OpenQasmProgram`]: ./struct.OpenQasmProgram.html
350/// [unitary]: https://en.wikipedia.org/wiki/Unitary_operator
351#[derive(Debug, Clone, PartialEq)]
352#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
353pub struct UnitaryOperation(pub String, pub Vec<Expression>, pub Vec<Argument>);
354
355/// Any of the operators that can appear in an expression.
356///
357/// # Examples
358///
359/// Notice the different `Expression` instances in the [`OpenQasmLibrary`]
360/// example.
361///
362/// [`OpenQasmLibrary`]: ./struct.OpenQasmLibrary.html
363#[non_exhaustive]
364#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
365#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
366pub enum OpCode {
367 /// Code for the addition operator `+`.
368 Add,
369 /// Code for the substraction operator `-`.
370 Sub,
371 /// Code for the multiplication operator `*`.
372 Mul,
373 /// Code for the division operator `/`.
374 Div,
375 /// Code for the power operator `^`.
376 Pow,
377}
378
379/// Any of the functions that can appear in an expression.
380#[non_exhaustive]
381#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
382#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
383pub enum FuncCode {
384 /// Function sinus `sin`.
385 Sin,
386 /// Function cosinus `cos`.
387 Cos,
388 /// Function tangent `tan`.
389 Tan,
390 /// Function exponential `exp`.
391 Exp,
392 /// Function natural logarithm `ln`.
393 Ln,
394 /// Function square root `sqrt`.
395 Sqrt,
396}
397
398/// Any of the subexpressions that can appear inside a expression.
399///
400/// # Examples
401///
402/// See [`OpenQasmLibrary`] for an example.
403///
404/// [`OpenQasmLibrary`]: ./struct.OpenQasmLibrary.html
405#[non_exhaustive]
406#[derive(Debug, Clone, PartialEq)]
407#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
408pub enum Expression {
409 /// The pi constant `pi`.
410 Pi,
411 /// A valid OPENQASM identifier.
412 Id(String),
413 /// A real number.
414 Real(f64),
415 /// An integer number.
416 Int(u64),
417 /// A binary operation.
418 Op(OpCode, Box<Expression>, Box<Expression>),
419 /// A call to a function.
420 Function(FuncCode, Box<Expression>),
421 /// A negation of an expression.
422 Minus(Box<Expression>),
423}
424
425/// A reference to a register or register component.
426///
427/// # Examples
428///
429/// Look at these barrier statements:
430///
431/// ```qasm
432/// barrier q;
433/// barrier q[0];
434/// ```
435///
436/// They differ on the quantum register argument and can be built with:
437///
438/// ```
439/// use qasmsim::grammar::ast::{BarrierPragma, Argument};
440///
441/// let on_the_whole_register = BarrierPragma(
442/// vec![Argument::Id("q".to_string())]
443/// );
444/// let on_the_first_qubit = BarrierPragma(
445/// vec![Argument::Item("q".to_string(), 0)]
446/// );
447/// ```
448#[non_exhaustive]
449#[derive(Debug, Clone, PartialEq, Eq, Hash)]
450#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
451pub enum Argument {
452 /// An entire register like `q`.
453 Id(String),
454 /// One of the bits/qubits of a register `q[0]`.
455 Item(String, usize),
456}