Reference OpenQASM AST in Python - contains the reference abstract syntax tree (AST) for representing OpenQASM 3 programs, tools to parse text into this AST, and tools to manipulate the AST
npx @tessl/cli install tessl/pypi-openqasm3@1.0.0A comprehensive Python library that provides the reference abstract syntax tree (AST) for representing OpenQASM 3 programs, tools to parse text into this AST, and tools to manipulate the AST. This package enables developers to build OpenQASM 3 compiler passes, quantum circuit analyzers, and other quantum language processing tools in Python.
pip install openqasm3 (AST, visitors, code generation only)pip install openqasm3[parser] (includes text-to-AST parsing)import openqasm3Common imports for working with AST nodes:
from openqasm3 import astFor parsing (requires [parser] extra):
from openqasm3 import parse
# or
import openqasm3
program = openqasm3.parse(qasm_source)For AST manipulation:
from openqasm3 import visitorFor code generation:
from openqasm3 import dump, dumpsimport openqasm3
from openqasm3 import ast
# Parse OpenQASM 3 source code into AST (requires [parser] extra)
qasm_source = '''
OPENQASM 3.0;
qubit[2] q;
h q[0];
cx q[0], q[1];
'''
program = openqasm3.parse(qasm_source)
print(f"Program has {len(program.statements)} statements")
# Create AST nodes programmatically
qubit_decl = ast.QubitDeclaration(
qubit=ast.Identifier("q"),
size=ast.IntegerLiteral(2)
)
# Convert AST back to OpenQASM 3 text
qasm_text = openqasm3.dumps(program)
print(qasm_text)
# Walk and analyze AST using visitor pattern
class GateCounter(openqasm3.visitor.QASMVisitor):
def __init__(self):
self.gate_count = 0
def visit_QuantumGate(self, node):
self.gate_count += 1
self.generic_visit(node)
counter = GateCounter()
counter.visit(program)
print(f"Found {counter.gate_count} quantum gates")The OpenQASM 3 Python reference follows a layered architecture:
This design enables maximum reusability across quantum compiler toolchains, development environments, and language processing applications.
Complete abstract syntax tree representing all OpenQASM 3 language constructs including quantum gates, classical code, control flow, type system, and calibration blocks.
# Base classes
@dataclass
class QASMNode:
span: Optional[Span] = field(init=False, default=None, compare=False)
@dataclass
class Statement(QASMNode):
annotations: List[Annotation] = field(init=False, default_factory=list)
class Expression(QASMNode):
pass
class ClassicalType(QASMNode):
pass
# Program structure
@dataclass
class Program(QASMNode):
statements: List[Union[Statement, Pragma]]
version: Optional[str] = None
# Key statement types
@dataclass
class QubitDeclaration(Statement):
qubit: Identifier
size: Optional[Expression] = None
@dataclass
class QuantumGateDefinition(Statement):
name: Identifier
arguments: List[Identifier]
qubits: List[Identifier]
body: List[QuantumStatement]
@dataclass
class ClassicalDeclaration(Statement):
type: ClassicalType
identifier: Identifier
init_expression: Optional[Union[Expression, QuantumMeasurement]] = None
@dataclass
class SubroutineDefinition(Statement):
name: Identifier
arguments: List[Union[ClassicalArgument, QuantumArgument]]
body: List[Statement]
return_type: Optional[ClassicalType] = NoneParse OpenQASM 3 source code into the reference AST with full language support and error reporting. Requires the [parser] extra installation.
def parse(input_: str, *, permissive: bool = False) -> ast.Program:
"""
Parse a complete OpenQASM 3 program from text into the reference AST.
Args:
input_: A string containing a complete OpenQASM 3 program
permissive: If True, enables ANTLR error recovery for partial parsing
If False (default), raises exceptions on syntax errors
Returns:
A complete ast.Program node representing the parsed program
Raises:
QASM3ParsingError: When the program cannot be correctly parsed
ImportError: If the [parser] extra is not installed
"""Visitor and transformer patterns for systematic AST traversal, analysis, and modification with optional context support.
class QASMVisitor(Generic[T]):
def visit(self, node: QASMNode, context: Optional[T] = None):
"""Visit a node and dispatch to the appropriate visitor method"""
def generic_visit(self, node: QASMNode, context: Optional[T] = None):
"""Called if no explicit visitor function exists for a node"""
class QASMTransformer(QASMVisitor[T]):
def generic_visit(self, node: QASMNode, context: Optional[T] = None) -> QASMNode:
"""Visit and potentially modify nodes and their children"""Convert AST nodes back to valid OpenQASM 3 text with configurable formatting and complete language support.
def dump(node: ast.QASMNode, file: io.TextIOBase, **kwargs) -> None:
"""Write textual OpenQASM 3 code representing an AST node to an open stream"""
def dumps(node: ast.QASMNode, **kwargs) -> str:
"""Get a string representation of OpenQASM 3 code from an AST node"""
class Printer(QASMVisitor[PrinterState]):
def __init__(self, stream: io.TextIOBase, indent: str = " ",
chain_else_if: bool = True, old_measurement: bool = False):
"""Initialize the printer with formatting options"""
def visit(self, node: ast.QASMNode, context: Optional[PrinterState] = None) -> None:
"""Main entry point for visiting nodes and generating code"""Expression precedence handling, specification version metadata, and other utility functions for working with OpenQASM 3 ASTs.
# Specification metadata
supported_versions: List[str] # ["3.0", "3.1"]
# Expression precedence
def precedence(node_type: type) -> int:
"""
Get the precedence level for an expression node type.
Higher numbers indicate higher precedence (tighter binding).
"""# Core enums
class AccessControl(Enum):
readonly = "readonly"
mutable = "mutable"
class TimeUnit(Enum):
dt = "dt"
ns = "ns"
us = "us"
ms = "ms"
s = "s"
class BinaryOperator(Enum):
# Comparison operators
GT = ">"
LT = "<"
GTE = ">="
LTE = "<="
EQ = "=="
NE = "!="
# Logical operators
LOGICAL_AND = "&&"
LOGICAL_OR = "||"
# Bitwise operators
BITWISE_OR = "|"
BITWISE_XOR = "^"
BITWISE_AND = "&"
LSHIFT = "<<"
RSHIFT = ">>"
# Arithmetic operators
PLUS = "+"
MINUS = "-"
TIMES = "*"
DIVIDE = "/"
MODULO = "%"
POWER = "**"
class UnaryOperator(Enum):
BITWISE_NOT = "~"
LOGICAL_NOT = "!"
MINUS = "-"
class AssignmentOperator(Enum):
EQUALS = "="
PLUS_EQUALS = "+="
MINUS_EQUALS = "-="
TIMES_EQUALS = "*="
DIVIDE_EQUALS = "/="
BITWISE_AND_EQUALS = "&="
BITWISE_OR_EQUALS = "|="
BITWISE_NOT_EQUALS = "~="
BITWISE_XOR_EQUALS = "^="
LSHIFT_EQUALS = "<<="
RSHIFT_EQUALS = ">>="
MODULO_EQUALS = "%="
POWER_EQUALS = "**="
class GateModifierName(Enum):
inv = "inv"
pow = "pow"
ctrl = "ctrl"
negctrl = "negctrl"
class IOKeyword(Enum):
input = "input"
output = "output"
# Location information
@dataclass
class Span:
start_line: int
start_column: int
end_line: int
end_column: int
# Type aliases
IndexElement = Union[DiscreteSet, List[Union[Expression, RangeDefinition]]]