# Apache V2 usage with no significant modifications
# Source: https://github.com/openqasm/openqasm/blob/429781bb9c95ef15944861f306ac6b9e4ff0abf0/source/openqasm/openqasm3/ast.py
# License: https://github.com/openqasm/openqasm/blob/main/LICENSE
"""
========================================
Abstract Syntax Tree (``openqasm3.ast``)
========================================
.. currentmodule:: openqasm3.ast
The reference abstract syntax tree (AST) for OpenQASM 3 programs.
"""
from __future__ import annotations
from dataclasses import dataclass, field
from enum import Enum
from typing import List, Optional, Union
__all__ = [
"AccessControl",
"AliasStatement",
"AngleType",
"Annotation",
"ArrayLiteral",
"ArrayReferenceType",
"ArrayType",
"AssignmentOperator",
"BinaryExpression",
"BinaryOperator",
"BitType",
"BitstringLiteral",
"BoolType",
"BooleanLiteral",
"Box",
"BranchingStatement",
"BreakStatement",
"CalibrationDefinition",
"CalibrationGrammarDeclaration",
"Cast",
"ClassicalArgument",
"ClassicalAssignment",
"ClassicalDeclaration",
"ClassicalType",
"ComplexType",
"Concatenation",
"ConstantDeclaration",
"ContinueStatement",
"DelayInstruction",
"DiscreteSet",
"DurationLiteral",
"DurationOf",
"DurationType",
"EndStatement",
"Expression",
"ExpressionStatement",
"ExternDeclaration",
"FloatLiteral",
"FloatType",
"ForInLoop",
"FunctionCall",
"GateModifierName",
"IODeclaration",
"IOKeyword",
"Identifier",
"Include",
"IndexExpression",
"IndexedIdentifier",
"IntType",
"IntegerLiteral",
"Pragma",
"Program",
"QASMNode",
"QuantumArgument",
"QuantumBarrier",
"QuantumGate",
"QuantumGateDefinition",
"QuantumGateModifier",
"QuantumMeasurement",
"QuantumMeasurementStatement",
"QuantumPhase",
"QuantumReset",
"QuantumStatement",
"QubitDeclaration",
"RangeDefinition",
"ReturnStatement",
"SizeOf",
"Span",
"Statement",
"StretchType",
"SubroutineDefinition",
"TimeUnit",
"UintType",
"UnaryExpression",
"UnaryOperator",
"WhileLoop",
]
from sympy import Expr
AccessControl = Enum("AccessControl", "const mutable")
AssignmentOperator = Enum("AssignmentOperator", "= += -= *= /= &= |= ~= ^= <<= >>= %= **=")
BinaryOperator = Enum("BinaryOperator", "> < >= <= == != && || | ^ & << >> + - * / % **")
GateModifierName = Enum("GateModifier", "inv pow ctrl negctrl")
IOKeyword = Enum("IOKeyword", "input output")
TimeUnit = Enum("TimeUnit", "dt ns us ms s")
UnaryOperator = Enum("UnaryOperator", "~ ! -")
[docs]
@dataclass
class Span:
"""
Start and end line/column in the source file
We use the Antlr convention. The starting line number is 1 and starting column number is 0.
"""
start_line: int
start_column: int
end_line: int
end_column: int
[docs]
@dataclass
class QASMNode:
"""Base class for all OpenQASM 3 nodes"""
span: Optional[Span] = field(init=False, default=None, compare=False)
"""
The span(location) of the node in the source code.
Because not all the nodes are generated from source, the span is optional.
To make it easier to write unit test, we exclude span from the generated __eq__().
"""
[docs]
@dataclass
class Program(QASMNode):
"""
An entire OpenQASM 3 program represented by a list of top level statements
"""
statements: List[Statement]
version: Optional[str] = None
[docs]
@dataclass
class Annotation(QASMNode):
"""An annotation applied to a statment."""
keyword: str
command: Optional[str] = None
[docs]
@dataclass
class Statement(QASMNode):
"""A statement: anything that can appear on its own line"""
annotations: List[Annotation] = field(init=False, default_factory=list)
[docs]
@dataclass
class Include(Statement):
"""
An include statement
"""
filename: str
[docs]
@dataclass
class ExpressionStatement(Statement):
"""A statement that contains a single expression"""
expression: Expression
# Note that QubitDeclaration is not a valid QuantumStatement, because qubits
# can only be declared in global scopes, not in gates.
[docs]
@dataclass
class QubitDeclaration(Statement):
"""
Global qubit declaration
Example::
qubit q;
qubit[4] q;
q // <- qubit
4 // <- size
"""
qubit: Identifier
size: Optional[Expression] = None
[docs]
@dataclass
class QuantumGateDefinition(Statement):
"""
Define a new quantum gate
Example::
gate cx c, t {
ctrl @ unitary(pi, 0, pi) c, t;
}
"""
name: Identifier
arguments: List[Identifier]
qubits: List[Identifier]
body: List[QuantumStatement]
[docs]
class QuantumStatement(Statement):
"""Statements that may appear inside a gate declaration"""
[docs]
@dataclass
class ExternDeclaration(Statement):
"""
A extern declaration
Example::
extern get_pauli(int[prec]) -> bit[2 * n];
get_pauli // <- name
int[prec] // <- classical type
bit[2 * n] // <- return type
"""
name: Identifier
arguments: List[ExternArgument]
return_type: Optional[ExternArgument] = None
[docs]
class Expression(QASMNode):
"""An expression: anything that returns a value"""
[docs]
@dataclass
class Identifier(Expression):
"""
An identifier
Example::
q1
"""
name: str
[docs]
@dataclass
class UnaryExpression(Expression):
"""
A unary expression
Example::
~b
!bool
-i
"""
op: UnaryOperator
expression: Expression
[docs]
@dataclass
class BinaryExpression(Expression):
"""
A binary expression
Example::
q1 || q2
"""
op: BinaryOperator
lhs: Expression
rhs: Expression
[docs]
@dataclass
class IntegerLiteral(Expression):
"""
An integer literal
Example::
1
"""
value: int
[docs]
@dataclass
class FloatLiteral(Expression):
"""
An real number literal
Example::
1.1
"""
value: float
[docs]
@dataclass
class BooleanLiteral(Expression):
"""
A boolean expression
Example::
true
false
"""
value: bool
[docs]
@dataclass
class BitstringLiteral(Expression):
"""A literal bitstring value. The ``value`` is the numerical value of the
bitstring, and the ``width`` is the number of digits given."""
value: int
width: int
[docs]
@dataclass
class DurationLiteral(Expression):
"""
A duration literal
Example::
1.0ns
"""
value: float
unit: TimeUnit
[docs]
@dataclass
class ArrayLiteral(Expression):
"""Array literal, used to initialise declared arrays.
For example::
array[uint[8], 2] row = {1, 2};
array[uint[8], 2, 2] my_array = {{1, 2}, {3, 4}};
array[uint[8], 2, 2] my_array = {row, row};
"""
values: List[Expression]
[docs]
@dataclass
class FunctionCall(Expression):
"""
A function call expression
Example::
foo(1)
foo // <- name
"""
name: Identifier
arguments: List[Expression]
[docs]
@dataclass
class Cast(Expression):
"""
A cast call expression
Example::
counts += int[1](b);
"""
type: ClassicalType
argument: Expression
[docs]
@dataclass
class DiscreteSet(QASMNode):
"""
A set of discrete values. This can be used for the values in a ``for``
loop, or to index certain values out of a register::
for i in {1, 2, 3} {}
let alias = qubits[{2, 3, 4}];
"""
values: List[Expression]
[docs]
@dataclass
class RangeDefinition(QASMNode):
"""
Range definition.
Example::
1:2
1:1:10
:
"""
start: Optional[Expression]
end: Optional[Expression]
step: Optional[Expression]
IndexElement = Union[DiscreteSet, List[Union[Expression, RangeDefinition]]]
[docs]
@dataclass
class IndexExpression(Expression):
"""
An index expression.
Example::
q[1]
"""
collection: Expression
index: IndexElement
[docs]
@dataclass
class IndexedIdentifier(QASMNode):
"""An indentifier with index operators, such that it can be used as an
lvalue. The list of indices is subsequent index brackets, so in::
a[{1, 2, 3}][0:1, 0:1]
the list of indices will have two elements. The first will be a
:class:`.DiscreteSet`, and the second will be a list of two
:class:`.RangeDefinition`\\ s.
"""
name: Identifier
indices: List[IndexElement]
[docs]
@dataclass
class Concatenation(Expression):
"""
Concatenation of two registers, for example::
a ++ b
a[2:3] ++ a[0:1]
"""
lhs: Expression
rhs: Expression
[docs]
@dataclass
class QuantumGate(QuantumStatement):
"""
Invoking a quantum gate
Example::
cx[dur] 0, 1;
or
ctrl @ p(λ) a, b;
ctrl @ // <- quantumGateModifier
p // <- quantumGateName
λ // <- argument
a, b // <- qubit
"""
modifiers: List[QuantumGateModifier]
name: Identifier
arguments: List[Expression]
qubits: List[Union[IndexedIdentifier, Identifier]]
duration: Optional[Expression] = None
[docs]
@dataclass
class QuantumGateModifier(QASMNode):
"""
A quantum gate modifier
Attributes:
modifier: 'inv', 'pow', or 'ctrl'
expression: only pow modifier has expression.
Example::
inv @
pow(1/2)
ctrl
"""
modifier: GateModifierName
argument: Optional[Expression] = None
[docs]
@dataclass
class QuantumPhase(QuantumStatement):
"""
A quantum phase instruction
Example::
ctrl @ gphase(λ) a;
ctrl @ // <- quantumGateModifier
λ // <- argument
a // <- qubit
"""
modifiers: List[QuantumGateModifier]
argument: Expression
qubits: List[Union[IndexedIdentifier, Identifier]]
# Not a full expression because it can only be used in limited contexts.
[docs]
@dataclass
class QuantumMeasurement(QASMNode):
"""
A quantum measurement instruction
Example::
measure q;
"""
qubit: Union[IndexedIdentifier, Identifier]
# Note that this is not a QuantumStatement because it involves access to
# classical bits.
[docs]
@dataclass
class QuantumMeasurementStatement(Statement):
"""Stand-alone statement of a quantum measurement, potentially assigning the
result to a classical variable. This is not the only statement that
`measure` can appear in (it can also be in classical declaration statements
and returns)."""
measure: QuantumMeasurement
target: Optional[Union[IndexedIdentifier, Identifier]]
[docs]
@dataclass
class QuantumBarrier(QuantumStatement):
"""
A quantum barrier instruction
Example::
barrier q;
"""
qubits: List[Expression]
[docs]
@dataclass
class QuantumReset(QuantumStatement):
"""
A reset instruction.
Example::
reset q;
"""
qubits: Union[IndexedIdentifier, Identifier]
[docs]
@dataclass
class ClassicalArgument(QASMNode):
"""
Classical argument for a gate or subroutine declaration
"""
type: ClassicalType
name: Identifier
access: Optional[AccessControl] = None
@dataclass
class ExternArgument(QASMNode):
"""Classical argument for an extern declaration."""
type: ClassicalType
access: Optional[AccessControl] = None
[docs]
@dataclass
class ClassicalDeclaration(Statement):
"""
Classical variable declaration
Example::
bit c;
"""
type: ClassicalType
identifier: Identifier
init_expression: Optional[Union[Expression, QuantumMeasurement]] = None
[docs]
@dataclass
class IODeclaration(Statement):
"""
Input/output variable declaration
Exampe::
input angle[16] theta;
output bit select;
"""
io_identifier: IOKeyword
type: ClassicalType
identifier: Identifier
[docs]
@dataclass
class ConstantDeclaration(Statement):
"""
Constant declaration
Example::
const int[16] n = 10;
"""
type: ClassicalType
identifier: Identifier
init_expression: Expression
[docs]
class ClassicalType(QASMNode):
"""
Base class for classical type
"""
[docs]
@dataclass
class IntType(ClassicalType):
"""
Node representing a classical ``int`` (signed integer) type, with an
optional precision.
Example:
int[8]
int[16]
"""
size: Optional[Expression] = None
[docs]
@dataclass
class UintType(ClassicalType):
"""
Node representing a classical ``uint`` (unsigned integer) type, with an
optional precision.
Example:
uint[8]
uint[16]
"""
size: Optional[Expression] = None
[docs]
@dataclass
class FloatType(ClassicalType):
"""
Node representing the classical ``float`` type, with the particular IEEE-754
floating-point size optionally specified.
Example:
float[16]
float[64]
"""
size: Optional[Expression] = None
[docs]
@dataclass
class ComplexType(ClassicalType):
"""
Complex ClassicalType. Its real and imaginary parts are based on other classical types.
Example::
complex[float]
complex[float[32]]
"""
base_type: Optional[FloatType]
[docs]
@dataclass
class AngleType(ClassicalType):
"""
Node representing the classical ``angle`` type, with an optional precision.
Example::
angle[8]
angle[16]
"""
size: Optional[Expression] = None
[docs]
@dataclass
class BitType(ClassicalType):
"""
Node representing the classical ``bit`` type, with an optional size.
Example::
bit[8]
creg[8]
"""
size: Optional[Expression] = None
[docs]
class BoolType(ClassicalType):
"""
Leaf node representing the Boolean classical type.
"""
[docs]
@dataclass
class ArrayType(ClassicalType):
"""Type of arrays that include allocation of the storage.
This is generally any array declared as a standard statement, but not
arrays declared by being arguments to subroutines.
"""
base_type: Union[IntType, UintType, FloatType, AngleType, BitType, BoolType, ComplexType]
dimensions: List[Expression]
[docs]
@dataclass
class ArrayReferenceType(ClassicalType):
"""Type of arrays that are a reference to an array with allocated storage.
This is generally any array declared as a subroutine argument. The
dimensions can be either a list of expressions (one for each dimension), or
a single expression, which is the number of dimensions.
For example::
// `a` will have dimensions `[IntegerLiteral(2)]` (with a list), because
// it is a 1D array, with a length of 2.
def f(const array[uint[8], 2] a) {}
// `b` will have dimension `IntegerLiteral(3)` (no list), because it is
// a 3D array, but we don't know the lengths of its dimensions.
def f(const array[uint[8], #dim=3] b) {}
"""
base_type: Union[IntType, UintType, FloatType, AngleType, BitType, BoolType, ComplexType]
dimensions: Union[Expression, List[Expression]]
[docs]
class DurationType(ClassicalType):
"""
Leaf node representing the ``duration`` type.
"""
[docs]
class StretchType(ClassicalType):
"""
Leaf node representing the ``stretch`` type.
"""
[docs]
@dataclass
class CalibrationGrammarDeclaration(Statement):
"""
Calibration grammar declaration
Example::
defcalgrammar "openpulse";
"""
name: str
[docs]
@dataclass
class CalibrationDefinition(Statement):
"""
Calibration definition
Example::
defcal rz(angle[20] theta) q {
shift_phase drive(q), -theta;
}
"""
name: Identifier
arguments: List[ClassicalArgument]
qubits: List[Identifier]
return_type: Optional[ClassicalType]
body: str
[docs]
@dataclass
class SubroutineDefinition(Statement):
"""
Subroutine definition
Example::
def measure(qubit q) -> bit {
s q;
h q;
return measure q;
}
"""
name: Identifier
arguments: List[Union[ClassicalArgument, QuantumArgument]]
body: List[Statement]
return_type: Optional[ClassicalType] = None
[docs]
@dataclass
class QuantumArgument(QASMNode):
"""
Quantum argument for a subroutine declaration
"""
name: Identifier
size: Optional[Expression] = None
[docs]
@dataclass
class ReturnStatement(Statement):
"""
Classical or quantum return statement
Example::
return measure q;
return a + b
"""
expression: Optional[Union[Expression, QuantumMeasurement]] = None
[docs]
class BreakStatement(Statement):
"""
Break statement
Example::
break;
"""
[docs]
class ContinueStatement(Statement):
"""
Continue statement
Example::
continue;
"""
[docs]
class EndStatement(Statement):
"""
End statement
Example::
end;
"""
[docs]
@dataclass
class BranchingStatement(Statement):
"""
Branch (``if``) statement
Example::
if (temp == 1) {
ry(-pi / 2) scratch[0];
} else continue;
"""
condition: Expression
if_block: List[Statement]
else_block: List[Statement]
[docs]
@dataclass
class WhileLoop(Statement):
"""
While loop
Example::
while(~success) {
reset magic;
ry(pi / 4) magic;
success = distill(magic, scratch);
}
"""
while_condition: Expression
block: List[Statement]
[docs]
@dataclass
class ForInLoop(Statement):
"""
For in loop
Example::
for i in [0: 2] {
majority a[i], b[i + 1], a[i + 1];
}
"""
type: ClassicalType
identifier: Identifier
set_declaration: Union[RangeDefinition, DiscreteSet, Identifier]
block: List[Statement]
[docs]
@dataclass
class DelayInstruction(QuantumStatement):
"""
Delay instruction
Example::
delay[start_stretch] $0;
"""
duration: Expression
qubits: List[Union[IndexedIdentifier, Identifier]]
[docs]
@dataclass
class Box(QuantumStatement):
"""
Timing box
Example::
box [maxdur] {
delay[start_stretch] $0;
x $0;
}
"""
duration: Optional[Expression]
body: List[QuantumStatement]
[docs]
@dataclass
class DurationOf(Expression):
"""
Duration Of
Example::
durationof({x $0;})
"""
target: List[Statement]
[docs]
@dataclass
class SizeOf(Expression):
"""``sizeof`` an array's dimensions."""
target: Expression
index: Optional[Expression] = None
[docs]
@dataclass
class AliasStatement(Statement):
"""
Alias statement
Example::
let a = qubits[0];
"""
target: Identifier
value: Union[Identifier, Concatenation]
[docs]
@dataclass
class ClassicalAssignment(Statement):
"""
Classical assignment
Example::
a[0] = 1;
"""
lvalue: Union[Identifier, IndexedIdentifier]
op: AssignmentOperator
rvalue: Expression
[docs]
@dataclass
class Pragma(QASMNode):
"""
Pragma
Example::
#pragma val1 val2 val3
"""
command: str
@dataclass
class SymbolLiteral(Expression):
"""
A symbol literal for parametric interpretation
Example::
Symbol("theta")
"""
value: Expr