qasmfmt
qasmfmt is a fast formatter for OpenQASM 3.0 quantum circuit files, written in Rust.
Features
- Fast formatting powered by Rust
- Available as both Rust and Python package
- CLI and library interfaces
- stdin/stdout support for pipeline usage
- Configuration file support (
qasmfmt.toml) - Directory recursive processing
Installation
Using pip (recommended)
pip install qasmfmt
Using Cargo
cargo install qasmfmt
From source
git clone https://github.com/orangekame3/qasmfmt
cd qasmfmt
cargo install --path .
Usage
CLI
qasmfmt [OPTIONS] [PATH]...
Modes (mutually exclusive)
| Option | Description |
|---|---|
-w, --write | Write formatted output back to files (in-place) |
--check | Check if files are formatted (exit 1 if not) |
--diff | Show unified diff of formatting changes (exit 1 if diff exists) |
Options
| Option | Description |
|---|---|
-i, --indent <N> | Indentation size in spaces (default: 4) |
--max-width <N> | Maximum line width (default: 100) |
--stdin-filename <PATH> | Virtual filename for stdin input |
--config <PATH> | Path to configuration file |
--no-config | Disable automatic configuration file discovery |
-V, --version | Print version |
-h, --help | Print help |
Examples
# Format file (print to stdout)
qasmfmt input.qasm
# Format file in-place
qasmfmt -w input.qasm
# Check if file is formatted (for CI)
qasmfmt --check input.qasm
# Show diff
qasmfmt --diff input.qasm
# Format from stdin
echo 'OPENQASM 3.0;qubit[2]q;' | qasmfmt
echo 'OPENQASM 3.0;qubit[2]q;' | qasmfmt -
# Format from stdin with virtual filename
echo 'OPENQASM 3.0;qubit[2]q;' | qasmfmt --stdin-filename circuit.qasm -
# Custom indent size
qasmfmt -i 2 input.qasm
# Format all .qasm files in a directory (recursive)
qasmfmt -w ./circuits/
# Check all .qasm files in a directory
qasmfmt --check ./src/
# Use specific config file
qasmfmt --config ./qasmfmt.toml input.qasm
# Disable config file auto-discovery
qasmfmt --no-config input.qasm
Configuration File
qasmfmt automatically searches for qasmfmt.toml from the input file’s directory upward.
# qasmfmt.toml
indent_size = 2
max_width = 80
indent_style = "spaces" # or "tabs"
trailing_newline = true
CLI options override configuration file settings.
Python Library
import qasmfmt
# Format string
source = "OPENQASM 3.0;qubit[2]q;h q[0];"
formatted = qasmfmt.format_str(source)
print(formatted)
# OPENQASM 3.0;
# qubit[2] q;
# h q[0];
# Format with options
formatted = qasmfmt.format_str(source, indent_size=2, max_width=80)
# Format file
formatted = qasmfmt.format_file("circuit.qasm")
# Check if file is formatted
is_formatted = qasmfmt.check_file("circuit.qasm")
Rust Library
use qasmfmt::{format, format_with_config, FormatConfig};
fn main() {
let source = "OPENQASM 3.0;qubit[2]q;";
// Format with default config
let formatted = format(source).unwrap();
// Format with custom config
let config = FormatConfig {
indent_size: 2,
..Default::default()
};
let formatted = format_with_config(source, config).unwrap();
}
Example
Before:
OPENQASM 3.0;include"stdgates.inc";qubit[2]q;bit[2]c;h q[0];cx q[0],q[1];c=measure q;
After:
OPENQASM 3.0;
include "stdgates.inc";
qubit[2] q;
bit[2] c;
h q[0];
cx q[0], q[1];
c = measure q;
Exit Codes
| Code | Description |
|---|---|
| 0 | Success |
| 1 | Error or formatting differences found (--check, --diff) |
| 2 | Usage error (e.g., mutually exclusive options, stdin with --write) |
CI Integration
GitHub Actions
- name: Check OpenQASM formatting
run: |
pip install qasmfmt
qasmfmt --check .
pre-commit
# .pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: qasmfmt
name: qasmfmt
entry: qasmfmt --check
language: python
additional_dependencies: [qasmfmt]
files: \.qasm$
License
MIT License
Installation
From crates.io (Recommended)
cargo install qasmfmt
From Source
git clone https://github.com/orangekame3/qasmfmt
cd qasmfmt
cargo install --path .
Python
pip install qasmfmt
npm
npm install qasmfmt
Verify Installation
qasmfmt --version
Getting Started
Basic Usage
Format a file (in-place):
qasmfmt input.qasm
Format multiple files:
qasmfmt *.qasm
Format from stdin:
cat input.qasm | qasmfmt
Check Mode
Check if files are already formatted (useful for CI):
qasmfmt --check input.qasm
Exit codes:
0: File is formatted1: File needs formatting2: Error (parse error, file not found, etc.)
Show Diff
Preview changes without modifying files:
qasmfmt --diff input.qasm
CLI Reference
Synopsis
qasmfmt [OPTIONS] [FILES...]
Options
| Option | Short | Description |
|---|---|---|
--check | Check if files are formatted (exit 1 if not) | |
--diff | Show diff instead of writing | |
--help | -h | Print help |
--version | -V | Print version |
Behavior
- Default: Format files in-place
- No files given: Read from stdin, write to stdout
- With
--check: Exit with 1 if files would be reformatted - With
--diff: Show diff, do not modify files
Examples
# Format files in place
qasmfmt input.qasm
qasmfmt src/*.qasm
# Check if formatted (for CI)
qasmfmt --check input.qasm
# Show diff
qasmfmt --diff input.qasm
# Format from stdin
cat input.qasm | qasmfmt
echo "OPENQASM 3.0;qubit q;" | qasmfmt
# Format all QASM files recursively
find . -name "*.qasm" | xargs qasmfmt
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Would reformat (with --check) |
| 2 | Error (parse error, IO error) |
Configuration
Configuration File
qasmfmt looks for qasmfmt.toml in the current directory.
# qasmfmt.toml
# Number of spaces per indentation level
indent_size = 2
# Maximum line width
max_width = 100
Options
| Option | Type | Default | Description |
|---|---|---|---|
indent_size | integer | 2 | Spaces per indent level |
max_width | integer | 100 | Maximum line width |
Formatting Rules
This document defines the formatting rules for qasmfmt. Rules are based on analysis of examples from the official OpenQASM repository.
1. Version Declaration
// Before
OPENQASM 3.0;
// After
OPENQASM 3.0;
- Single space between
OPENQASMand version number
2. Include Statement
// Before
include"stdgates.inc";
// After
include "stdgates.inc";
- Single space between
includeand file path
3. Declarations
3.1 Qubit Declaration
// Before
qubit[2]q;
qubitq;
// After
qubit[2] q;
qubit q;
- No space between type and
[ - Single space between
]and identifier - Single space between type and identifier (when no array)
3.2 Classical Bit Declaration
// Before
bit[4]c;
bit c=0;
// After
bit[4] c;
bit c = 0;
- Same rules as qubit declaration
- Spaces around
=for initialization
3.3 Constant/Variable Declaration
// Before
const int[32]n=3;
// After
const int[32] n = 3;
4. Gate Calls
4.1 Basic Gates
// Before
hq[0];
// After
h q[0];
- Single space between gate name and arguments
4.2 Multiple Arguments
// Before
cxq[0],q[1];
// After
cx q[0], q[1];
- Single space after comma
- No space before comma
4.3 Parameterized Gates
// Before
rz(pi/4)q[0];
cphase(pi/2)q[0],q[1];
// After
rz(pi / 4) q[0];
cphase(pi / 2) q[0], q[1];
- No space between gate name and
( - Spaces around operators inside parameters
- Single space between
)and arguments
5. Operators
5.1 Arithmetic Operators
// Before
pi/4+pi/8
// After
pi / 4 + pi / 8
- Spaces around
+,-,*,/
5.2 Comparison Operators
// Before
c==1
n!=0
// After
c == 1
n != 0
- Spaces around
==,!=,<,>,<=,>=
5.3 Logical Operators
// Before
a&&b
c||d
// After
a && b
c || d
5.4 Assignment Operator
// Before
c=measure q;
// After
c = measure q;
6. Control Flow
6.1 If Statement
// Before
if(c==1)x q;
if(c==1){x q;}
// After
if (c == 1) x q;
if (c == 1) { x q; }
- Single space between
ifand( - Single space between
)and statement/{
6.2 If-Else Statement
if (c == 1) {
x q;
} else {
z q;
}
- Single space between
}andelse - Single space between
elseand{
6.3 While Statement
// Before
while(flags!=0){...}
// After
while (flags != 0) {
...
}
6.4 For Statement
for int i in [0:n] {
...
}
7. Gate Definition
// Before
gate mygate(theta)q{rz(theta)q;h q;}
// After
gate mygate(theta) q {
rz(theta) q;
h q;
}
- Single space between
gateand gate name - Single space between
)and qubit arguments - Single space between arguments and
{ - Body indented by 2 spaces
}on its own line
8. Subroutine Definition (def)
// Before
def myfunc(qubit q)->bit{bit b;measure q->b;return b;}
// After
def myfunc(qubit q) -> bit {
bit b;
measure q -> b;
return b;
}
- Spaces around
-> - Body indented by 2 spaces
9. Measure Statement
9.1 Assignment Form
// Before
c=measure q;
// After
c = measure q;
9.2 Arrow Form
// Before
measure q->c;
// After
measure q -> c;
- Spaces around
->
10. Barrier / Reset
barrier q;
reset q;
- Single space between keyword and arguments
11. Indentation
- Indent size: 2 spaces (default)
- Style: Spaces only (no tabs)
gate mygate q {
h q;
if (c == 1) {
x q;
}
}
12. Blank Lines
12.1 After Include
OPENQASM 3.0;
include "stdgates.inc";
qubit q;
- One blank line after include block
12.2 Around Gate/Def Definitions
qubit q;
gate mygate q {
h q;
}
h q;
- One blank line before and after gate/def definitions
12.3 Consecutive Blank Lines
- Multiple consecutive blank lines are collapsed to one
13. Trailing
13.1 Trailing Whitespace
- Trailing whitespace on each line is removed
13.2 Trailing Newline
- Single newline at end of file (default)
Rule Summary
| Category | Rule | Example |
|---|---|---|
| Spacing | After include | include "file"; |
| Spacing | Between type and identifier | qubit[2] q; |
| Spacing | Between gate and arguments | h q; |
| Spacing | After comma | cx q[0], q[1]; |
| Spacing | Around operators | a + b, c == 1 |
| Spacing | Before braces | { ... } |
| Spacing | After if/while | if (cond) |
| Indentation | Inside blocks | 2 spaces |
| Blank lines | After include | 1 line |
| Blank lines | Around gate/def | 1 line |
OpenQASM 3.0 Style Analysis
Analysis Date: January 2026
This document summarizes the analysis of examples from the official openqasm/openqasm repository.
Analyzed Files
- teleport.qasm
- qft.qasm
- rb.qasm
- gateteleport.qasm
- rus.qasm
- inverseqft1.qasm
Observed Style Patterns
1. Comments
// Line comment
/* Block comment */
2. OPENQASM Declaration
OPENQASM 3; // With semicolon, without dot
Sometimes omitted (some examples start with include)
3. Include Statement
include "stdgates.inc";
- Space between
includeand filename
4. Declarations
qubit[4] q;
bit[4] c;
const int[32] n = 3;
- No space between type and
[ - Space between
]and identifier
5. Gate Calls
h q[0];
cx q[0], q[1];
cphase(pi / 2) q[1], q[0];
rz(pi/4) a;
- Space between gate name and arguments
- Space after comma
- Inconsistent spacing inside parameters (
pi / 2andpi/4both appear)
6. Gate/Def Definitions
gate post q { }
def segment(qubit[2] anc, qubit psi) -> bit[2] {
bit[2] b;
reset anc;
...
return b;
}
- Space before braces
- Body indented by 2 spaces
7. If Statement
if(c0==1) z q[2];
if(c1==1) { x q[2]; }
if (r == 1) z q;
Inconsistent points:
if(vsif (- presence/absence of space- Spacing around
== - Braces for single statements
8. While Statement
while(int[2](flags) != 0) {
flags = segment(ancilla, input_qubit);
}
9. Measure
c0 = measure q[0]; // Assignment form
measure q -> c; // Arrow form
Both forms are used
10. Barrier
barrier q;
Inconsistent Points (to be unified by qasmfmt)
| Item | Official Examples | qasmfmt Policy |
|---|---|---|
if( vs if ( | Mixed | Unify to if ( |
Spacing around == | Mixed | Spaces on both sides of == |
| Spacing inside parameters | Mixed | Unify to pi / 2 |
| Braces for single statements | Mixed | Allow without braces |
Proposed qasmfmt Rules
Confirmed Rules (consistent in official examples)
✓ Space after include
✓ Space between type and identifier (qubit[2] q)
✓ Space between gate name and arguments (h q)
✓ Space after comma
✓ 2-space indent inside blocks
✓ Space before braces
Normalization Rules (qasmfmt will enforce)
→ Space after if ( and while (
→ Spaces around comparison operators (== != < >)
→ Spaces around arithmetic operators (+ - * /)
→ Spaces around assignment operator (=)
Configurable (future)
? Indentation: 2 or 4 spaces
? Maximum line width: 80 or 100
Architecture
Overview
qasmfmt uses a pipeline architecture inspired by rustfmt:
Source Code
↓
┌─────────────┐
│ Parser │ ← oq3_syntax
└─────────────┘
↓
┌─────────────┐
│ AST │
└─────────────┘
↓
┌─────────────┐
│ IR (Doc) │ ← Intermediate Representation
└─────────────┘
↓
┌─────────────┐
│ Printer │ ← Pretty Printer
└─────────────┘
↓
Formatted Code
Modules
| Module | Description |
|---|---|
config | Configuration handling |
error | Error types |
ir | Intermediate representation (Doc) |
printer | Pretty printer |
format | AST to IR conversion |
comment | Comment extraction |
IR (Doc)
The intermediate representation is based on Wadler’s “A prettier printer”:
#![allow(unused)]
fn main() {
enum Doc {
Nil,
Text(String),
Hardline,
Softline,
Concat(Vec<Doc>),
Indent(Box<Doc>),
Group(Box<Doc>),
}
}
Dependencies
oq3_syntax- OpenQASM 3.0 parserserde- Serializationthiserror- Error handling
Contributing
Development Setup
git clone https://github.com/orangekame3/qasmfmt
cd qasmfmt
cargo build
Running Tests
cargo test
Code Style
Format code before committing:
cargo fmt
cargo clippy
Pull Requests
- Fork the repository
- Create a feature branch
- Make changes
- Run tests
- Submit PR
Reporting Issues
Please include:
- qasmfmt version
- Input QASM code
- Expected output
- Actual output