push
This commit is contained in:
commit
dcf80a5974
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
/target/
|
||||||
|
/Cargo.lock
|
||||||
|
/test.qASM
|
||||||
|
/mem.bin
|
19
Cargo.toml
Normal file
19
Cargo.toml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
[package]
|
||||||
|
name = "q_asm"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bitvec = "1.0.1"
|
||||||
|
clap = { version = "4.2.7", features = ["derive"] }
|
||||||
|
codespan-reporting = "0.11.1"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
nalgebra = "0.32.2"
|
||||||
|
num-traits = "0.2.15"
|
||||||
|
rand = "0.8.5"
|
||||||
|
lalrpop-util = { version = "0.20.0", features = ["lexer"] }
|
||||||
|
|
||||||
|
[build_dependencies]
|
||||||
|
lalrpop = { version = "0.20.0", features = ["lexer"] }
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 zkdream
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
127
README.md
Normal file
127
README.md
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
```
|
||||||
|
qbits n
|
||||||
|
cbits n
|
||||||
|
qregs n
|
||||||
|
cregs n
|
||||||
|
mem n
|
||||||
|
|
||||||
|
<code>
|
||||||
|
```
|
||||||
|
|
||||||
|
The order of the headers is important and should not be changed. The `qbits` header specifies the number of
|
||||||
|
qubits in each quantum register. The `cbits` header specifies the number of classical bits in each classical
|
||||||
|
register. The `qregs` header specifies the number of quantum registers. The `cregs` header specifies the number
|
||||||
|
of classical registers. The `n` after each header is any integer number. Operands/arguments for all
|
||||||
|
instructions are delimited by spaces and not commas.
|
||||||
|
|
||||||
|
Code execution should always end at a `hlt` instruction. If the emulator reaches the end of code but does not
|
||||||
|
encounter a `hlt` instruction, it will end with a "PC out of bounds" error.
|
||||||
|
|
||||||
|
## Quantum Instructions
|
||||||
|
The general format for quantum instructions are:
|
||||||
|
```
|
||||||
|
op qn <other arguments>
|
||||||
|
```
|
||||||
|
Where `op` is the name/opcode, `qn` specifies a specific qubit `n` of the currently selected quantum register.
|
||||||
|
`<other arguments>` can include more qubits as arguments, or in the case of some instructions, a rotation expressed
|
||||||
|
as a rational multiple of pi, in the format `[n]pi[/n]`, where `n` can be any integer number, and items
|
||||||
|
in `[]` are optional. Quantum registers can be selected via the `qsel` instruction, which has the general format
|
||||||
|
`qsel qrn` where `n` is any non-negative number.
|
||||||
|
|
||||||
|
List of currently implemented quantum instructions:
|
||||||
|
|
||||||
|
| Quantum Gate | Instruction name | Syntax example | Explanation |
|
||||||
|
| ------------------- | ---------------- | ------------------- | ----------- |
|
||||||
|
| Hadamard | h | `h q0` | Applies a Hadamard to qubit 0 |
|
||||||
|
| CNOT | cnot | `cnot q0 q1` | Applies a CNOT to qubit 1 with qubit 0 being the control |
|
||||||
|
| CCNOT/Toffoli | ccnot | `ccnot q0 q1 q2` | Applies a Toffoli to qubit 2 with qubit 0 and qubit 1 being the controls |
|
||||||
|
| Pauli X | x | `x q0` | Applies a Pauli X to qubit 0 |
|
||||||
|
| Pauli Y | y | `y q0` | Applies a Pauli Y to qubit 0 |
|
||||||
|
| Pauli Z | z | `z q0` | Applies a Pauli Z to qubit 0 |
|
||||||
|
| Rx | rx | `rx q0 pi/3` | Rotates the statevector of qubit 0 by pi/3 radians along X axis on bloch sphere |
|
||||||
|
| Ry | ry | `ry q0 pi` | Rotates the statevector of qubit 0 by pi radians along Y axis on bloch sphere |
|
||||||
|
| Rz | rz | `rz q0 pi/4` | Rotates the statevector of qubit 0 by pi/4 radians along Z axis on bloch sphere |
|
||||||
|
| U gate | u | `u q0 pi pi/3 pi/6` | Rotates the statevector of qubit 0 by the 3 Euler angles pi, pi/3, pi/6 |
|
||||||
|
| S gate | s | `s q0` | Applies an S gate to qubit 0 |
|
||||||
|
| T gate | t | `t q0` | Applies a T gate to qubit 0 |
|
||||||
|
| S-dagger | sdg | `sdg q0` | Applies a S-dagger or the inverse of S gate to qubit 0 |
|
||||||
|
| T-dagger | tdg | `tdg q0` | Applies a T-dagger or the inverse of T gate to qubit 0 |
|
||||||
|
| Phase gate | p | `p q0 pi/3` | Applies a relative phase of pi/3 radians to qubit 0 |
|
||||||
|
| Controlled Hadamard | ch | `ch q0 q1` | Applies a controlled Hadamard to qubit 1 with qubit 0 being the control |
|
||||||
|
| Controlled Pauli Y | cy | `cy q0 q1` | Applies a controlled Pauli Y to qubit 1 with qubit 0 being the control |
|
||||||
|
| Controlled Pauli Z | cz | `cz q0 q1` | Applies a controlled Pauli Z to qubit 1 with qubit 0 being the control |
|
||||||
|
| Controlled Phase | cp | `cp q0 q1 pi/2` | Applies a controlled Phase gate to qubit 1 of pi/2 radians with qubit 0 being the control |
|
||||||
|
| Swap | swap | `swap q0 q1` | Swaps the state of qubits 0 and 1 |
|
||||||
|
| Square Root NOT | sqrtx | `sqrtx q0 ` | Applies a sqrt(NOT)/sqrt(X) to qubit 0 |
|
||||||
|
| Square Root Swap | sqrtswp | `sqrtswp q0 q1` | Applies a sqrt(Swap) to qubits 0 and 1, halfway swapping their state |
|
||||||
|
| Controlled Swap | cswap | `cswap q0 q1 q2` | Swaps the state of qubits 1 and 2 with qubit 0 being the control |
|
||||||
|
| Measure | m | `m q0 cr1 c3` | Measures the state of qubit 0 into 3rd bit of classical register 1 |
|
||||||
|
|
||||||
|
*Note: Remove any measurement operations before running the emulator with `--print-state` (or `-p`) as the emulator does not ignore them currently when run with that flag set*
|
||||||
|
|
||||||
|
## Classical Instructions
|
||||||
|
General format for classical instructions are:
|
||||||
|
```
|
||||||
|
op <operands>
|
||||||
|
```
|
||||||
|
Where `op` is the name/opcode, operands may include `crn`, which specifies a specific classical register `n`, or
|
||||||
|
an immediate literal value (for now non-negative due to not implemented in parser yet) Other than these differences,
|
||||||
|
they behave basically the same as any other assembly language instructions.
|
||||||
|
|
||||||
|
List of currently implemented classical instructions:
|
||||||
|
|
||||||
|
*Note: The value of a register refers to the value stored in the register. The value of an immediate is the immediate number itself.*
|
||||||
|
|
||||||
|
*Note 2: An operand can either be a register or immediate unless a restriction is specified.*
|
||||||
|
|
||||||
|
| Instruction name | Description |
|
||||||
|
| ---------------- | ----------- |
|
||||||
|
| add | op1 = op2 + op3. op1 is always a register. |
|
||||||
|
| sub | op1 = op2 - op3. op1 is always a register. |
|
||||||
|
| mult | op1 = op2 * op3. op1 is always a register. All values are treated unsigned. |
|
||||||
|
| umult | op1 = (op2 * op3) >> (cbits/2). op1 is always a register. All values are treated unsigned. |
|
||||||
|
| div | op1 = op2 / op3. op1 is always a register. Performs integer division. All values are treated unsigned. |
|
||||||
|
| smult | op1 = op2 * op3. op1 is always a register. All values are treated signed. |
|
||||||
|
| sumult | op1 = (op2 * op3) >> (cbits/2). op1 is always a register. All values are treated signed. |
|
||||||
|
| sdiv | op1 = op2 / op3. op1 is always a register. Performs integer division. All values are treated signed. |
|
||||||
|
| not | op1 = ~op2. op1 is always a register. |
|
||||||
|
| and | op1 = op2 & op3. op1 is always a register. |
|
||||||
|
| or | op1 = op2 \| op3. op1 is always a register. |
|
||||||
|
| xor | op1 = op2 ^ op3. op1 is always a register. |
|
||||||
|
| nand | op1 = ~(op2 & op3). op1 is always a register. |
|
||||||
|
| nor | op1 = ~(op2 \| op3). op1 is always a register. |
|
||||||
|
| xnor | op1 = ~(op2 ^ op3). op1 is always a register. |
|
||||||
|
|
||||||
|
## Misc. Instructions
|
||||||
|
These instructions are here because.
|
||||||
|
|
||||||
|
| Instruction name | Description |
|
||||||
|
| ---------------- | ----------- |
|
||||||
|
| qsel | Selects a quantum register so that proceeding quantum instructions act on that qreg. |
|
||||||
|
| cmp | Updates flags based on comparing values in op1 and op2. op1 is always a register. |
|
||||||
|
| jmp | Unconditionally jump to a label. |
|
||||||
|
| jeq | Jump to label if comparison resulted in EQ flag set. |
|
||||||
|
| jne | Jump to label if comparsion did not result in EQ flag set. |
|
||||||
|
| jg | Jump to label if comparison resulted in GREATER flag set. |
|
||||||
|
| jge | Jump to label if comparison resulted in GREATER or EQ flag set. |
|
||||||
|
| jl | Jump to label if comparison resulted in LESSER flag set. |
|
||||||
|
| jle | Jump to label if comparison resulted in LESSER or EQ flag set. |
|
||||||
|
| hlt | Halt the program. |
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
This program simulates the $\ket{\Phi^+}$ bell state:
|
||||||
|
```
|
||||||
|
qbits 2
|
||||||
|
cbits 2
|
||||||
|
qregs 1
|
||||||
|
cregs 1
|
||||||
|
|
||||||
|
qsel qr0
|
||||||
|
h q0
|
||||||
|
cnot q0 q1
|
||||||
|
|
||||||
|
m q0 cr0 c0
|
||||||
|
m q1 cr0 c1
|
||||||
|
|
||||||
|
hlt
|
||||||
|
```
|
634
src/ast.rs
Normal file
634
src/ast.rs
Normal file
|
@ -0,0 +1,634 @@
|
||||||
|
use std::{collections::HashMap, fmt::Display, ops::Range};
|
||||||
|
|
||||||
|
use lalrpop_util::{lalrpop_mod, ParseError};
|
||||||
|
lalrpop_mod!(grammar);
|
||||||
|
|
||||||
|
use codespan_reporting::diagnostic::{Diagnostic, Label};
|
||||||
|
|
||||||
|
type CGateInfo = (usize, Vec<(String, IdentType)>, Vec<ResolvedInst>);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Program {
|
||||||
|
// (qbits, cbits, qregs, cregs, mem_size)
|
||||||
|
pub headers: (usize, usize, usize, usize, usize),
|
||||||
|
pub custom_gates: HashMap<String, CGateInfo>,
|
||||||
|
pub instructions: Vec<ResolvedInst>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct SourceSpan {
|
||||||
|
pub file: usize,
|
||||||
|
pub span: Range<usize>,
|
||||||
|
}
|
||||||
|
impl SourceSpan {
|
||||||
|
pub fn new(file: usize, span: Range<usize>) -> Self {
|
||||||
|
Self { file, span }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ParseResult<'a> = Result<Program, ResolveError>;
|
||||||
|
|
||||||
|
pub fn parse(code: &str, file: usize) -> (ParseResult, Vec<Diagnostic<usize>>) {
|
||||||
|
let mut errs = Vec::new();
|
||||||
|
let ast = grammar::ProgramParser::new().parse(file, &mut errs, code);
|
||||||
|
let mut diags = Vec::new();
|
||||||
|
|
||||||
|
for err in errs {
|
||||||
|
let diag = Diagnostic::error();
|
||||||
|
match err {
|
||||||
|
ParseError::InvalidToken { location } => diags.push(
|
||||||
|
diag.with_message("Invalid token")
|
||||||
|
.with_labels(vec![Label::primary(file, location..location)]),
|
||||||
|
),
|
||||||
|
|
||||||
|
ParseError::UnrecognizedEof { location, .. } => diags.push(
|
||||||
|
diag.with_message("Unexpected EOF")
|
||||||
|
.with_labels(vec![Label::primary(file, location..location)]),
|
||||||
|
),
|
||||||
|
|
||||||
|
ParseError::UnrecognizedToken { token, expected } => diags.push(
|
||||||
|
diag.with_message("Unrecognized token")
|
||||||
|
.with_labels(vec![Label::primary(file, token.0..token.2)])
|
||||||
|
.with_notes(expected),
|
||||||
|
),
|
||||||
|
|
||||||
|
ParseError::ExtraToken { token } => diags.push(
|
||||||
|
diag.with_message("Extra token found")
|
||||||
|
.with_labels(vec![Label::primary(file, token.0..token.2)]),
|
||||||
|
),
|
||||||
|
|
||||||
|
ParseError::User { .. } => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(ast) = ast {
|
||||||
|
(ast, diags)
|
||||||
|
} else {
|
||||||
|
let mut diag = Diagnostic::error();
|
||||||
|
let err = ast.unwrap_err();
|
||||||
|
match err {
|
||||||
|
ParseError::InvalidToken { location } => {
|
||||||
|
diag = diag
|
||||||
|
.with_message("Invalid token")
|
||||||
|
.with_labels(vec![Label::primary(file, location..location)])
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseError::UnrecognizedEof { location, .. } => {
|
||||||
|
diag = diag
|
||||||
|
.with_message("Unexpected EOF")
|
||||||
|
.with_labels(vec![Label::primary(file, location..location)])
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseError::UnrecognizedToken { token, .. } => {
|
||||||
|
diag = diag
|
||||||
|
.with_message("Unrecognized token")
|
||||||
|
.with_labels(vec![Label::primary(file, token.0..token.2)])
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseError::ExtraToken { token } => {
|
||||||
|
diag = diag
|
||||||
|
.with_message("Extra token found")
|
||||||
|
.with_labels(vec![Label::primary(file, token.0..token.2)])
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseError::User { .. } => todo!(),
|
||||||
|
}
|
||||||
|
|
||||||
|
(Err(ResolveError::ParseError(diag)), diags)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resolve_ast(
|
||||||
|
headers: (usize, usize, usize, usize, usize),
|
||||||
|
ast: Vec<Inst>,
|
||||||
|
) -> Result<Program, ResolveError> {
|
||||||
|
let mut label_map = HashMap::new();
|
||||||
|
let mut custom_gates = HashMap::new();
|
||||||
|
let mut resolved_insts: Vec<ResolvedInst> = Vec::new();
|
||||||
|
|
||||||
|
// Get all labels from the AST
|
||||||
|
let mut i = 0usize;
|
||||||
|
for inst in &ast {
|
||||||
|
if let Inst::Label(name) = inst {
|
||||||
|
label_map.insert(name, i);
|
||||||
|
} else {
|
||||||
|
i += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update all instructions with the label map
|
||||||
|
for inst in &ast {
|
||||||
|
match inst {
|
||||||
|
Inst::Label(_) => {}
|
||||||
|
|
||||||
|
Inst::Jmp(name, s) => {
|
||||||
|
if let Some(offset) = label_map.get(name) {
|
||||||
|
resolved_insts.push(ResolvedInst::Jmp(*offset, s.clone()))
|
||||||
|
} else {
|
||||||
|
return Err(ResolveError::UndefinedLabel(name.clone(), s.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Inst::Jeq(name, s) => {
|
||||||
|
if let Some(offset) = label_map.get(name) {
|
||||||
|
resolved_insts.push(ResolvedInst::Jeq(*offset, s.clone()))
|
||||||
|
} else {
|
||||||
|
return Err(ResolveError::UndefinedLabel(name.clone(), s.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Inst::Jne(name, s) => {
|
||||||
|
if let Some(offset) = label_map.get(name) {
|
||||||
|
resolved_insts.push(ResolvedInst::Jne(*offset, s.clone()))
|
||||||
|
} else {
|
||||||
|
return Err(ResolveError::UndefinedLabel(name.clone(), s.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Inst::Jg(name, s) => {
|
||||||
|
if let Some(offset) = label_map.get(name) {
|
||||||
|
resolved_insts.push(ResolvedInst::Jg(*offset, s.clone()))
|
||||||
|
} else {
|
||||||
|
return Err(ResolveError::UndefinedLabel(name.clone(), s.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Inst::Jge(name, s) => {
|
||||||
|
if let Some(offset) = label_map.get(name) {
|
||||||
|
resolved_insts.push(ResolvedInst::Jge(*offset, s.clone()))
|
||||||
|
} else {
|
||||||
|
return Err(ResolveError::UndefinedLabel(name.clone(), s.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Inst::Jl(name, s) => {
|
||||||
|
if let Some(offset) = label_map.get(name) {
|
||||||
|
resolved_insts.push(ResolvedInst::Jle(*offset, s.clone()))
|
||||||
|
} else {
|
||||||
|
return Err(ResolveError::UndefinedLabel(name.clone(), s.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom instruction stuff
|
||||||
|
Inst::CustomGateDef(name, qbits, args, body) => {
|
||||||
|
let body = resolve_ast(headers, body.clone())?.instructions;
|
||||||
|
custom_gates.insert(name.clone(), (*qbits, args.clone(), body));
|
||||||
|
}
|
||||||
|
Inst::Custom(name, qbits, args, s) => {
|
||||||
|
if let Some(gate) = custom_gates.get(name) {
|
||||||
|
let gate_qbits = gate.0;
|
||||||
|
let gate_args = &gate.1;
|
||||||
|
let diag = Diagnostic::error();
|
||||||
|
|
||||||
|
if qbits.len() != gate_qbits {
|
||||||
|
return Err(ResolveError::CustomGateError(
|
||||||
|
diag.with_message("Given qubits to gate don't match gate definition")
|
||||||
|
.with_labels(vec![Label::primary(s.file, s.span.clone())])
|
||||||
|
.with_notes(vec![format!(
|
||||||
|
"Note: Gate expects {} qubits, but {} were given",
|
||||||
|
gate_qbits,
|
||||||
|
qbits.len()
|
||||||
|
)]),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if args.iter().map(|x| x.get_type()).collect::<Vec<_>>()
|
||||||
|
!= gate_args.iter().map(|x| x.1).collect::<Vec<_>>()
|
||||||
|
{
|
||||||
|
return Err(ResolveError::CustomGateError(
|
||||||
|
diag.with_message("Given args to gate don't match gate definition")
|
||||||
|
.with_labels(vec![Label::primary(s.file, s.span.clone())])
|
||||||
|
.with_notes(vec![format!(
|
||||||
|
"Note: Gate expects arg types {}, but given arg types were {}",
|
||||||
|
format_vec(gate_args.iter().map(|x| x.1).collect()),
|
||||||
|
format_vec(args.iter().map(|x| x.get_type()).collect()),
|
||||||
|
)]),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
resolved_insts.push(inst.into())
|
||||||
|
} else {
|
||||||
|
return Err(ResolveError::UndefinedGate(name.clone(), s.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Inst::Err => {}
|
||||||
|
|
||||||
|
_ => resolved_insts.push(inst.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Program {
|
||||||
|
headers,
|
||||||
|
custom_gates,
|
||||||
|
instructions: resolved_insts,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_vec<T: Display>(vec: Vec<T>) -> String {
|
||||||
|
let mut s = String::from("[");
|
||||||
|
for e in vec {
|
||||||
|
s += format!("{}, ", e).as_str()
|
||||||
|
}
|
||||||
|
s.pop();
|
||||||
|
s.pop();
|
||||||
|
s += "]";
|
||||||
|
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Inst {
|
||||||
|
// Quantum Instructions
|
||||||
|
Qsel(usize, SourceSpan),
|
||||||
|
Id(usize, SourceSpan),
|
||||||
|
Hadamard(usize, SourceSpan),
|
||||||
|
Cnot(usize, usize, SourceSpan),
|
||||||
|
Ccnot(usize, usize, usize, SourceSpan),
|
||||||
|
X(usize, SourceSpan),
|
||||||
|
Y(usize, SourceSpan),
|
||||||
|
Z(usize, SourceSpan),
|
||||||
|
Rx(usize, Rotation, SourceSpan),
|
||||||
|
Ry(usize, Rotation, SourceSpan),
|
||||||
|
Rz(usize, Rotation, SourceSpan),
|
||||||
|
U(usize, Rotation, Rotation, Rotation, SourceSpan),
|
||||||
|
S(usize, SourceSpan),
|
||||||
|
T(usize, SourceSpan),
|
||||||
|
Sdg(usize, SourceSpan),
|
||||||
|
Tdg(usize, SourceSpan),
|
||||||
|
Phase(usize, Rotation, SourceSpan),
|
||||||
|
Ch(usize, usize, SourceSpan),
|
||||||
|
Cy(usize, usize, SourceSpan),
|
||||||
|
Cz(usize, usize, SourceSpan),
|
||||||
|
CPhase(usize, usize, Rotation, SourceSpan),
|
||||||
|
Swap(usize, usize, SourceSpan),
|
||||||
|
SqrtX(usize, SourceSpan),
|
||||||
|
SqrtSwap(usize, usize, SourceSpan),
|
||||||
|
CSwap(usize, usize, usize, SourceSpan),
|
||||||
|
Measure(usize, usize, usize, SourceSpan),
|
||||||
|
|
||||||
|
// Custom gate stuff
|
||||||
|
// (name, qbits, args, body)
|
||||||
|
CustomGateDef(String, usize, Vec<(String, IdentType)>, Vec<Inst>),
|
||||||
|
Custom(String, Vec<usize>, Vec<IdentVal>, SourceSpan),
|
||||||
|
|
||||||
|
// Classical Instructions
|
||||||
|
Mov(Operand, Operand, SourceSpan),
|
||||||
|
Add(Operand, Operand, Operand, SourceSpan),
|
||||||
|
Sub(Operand, Operand, Operand, SourceSpan),
|
||||||
|
Mul(Operand, Operand, Operand, SourceSpan),
|
||||||
|
UMul(Operand, Operand, Operand, SourceSpan),
|
||||||
|
Div(Operand, Operand, Operand, SourceSpan),
|
||||||
|
SMul(Operand, Operand, Operand, SourceSpan),
|
||||||
|
SUMul(Operand, Operand, Operand, SourceSpan),
|
||||||
|
SDiv(Operand, Operand, Operand, SourceSpan),
|
||||||
|
Not(Operand, Operand, SourceSpan),
|
||||||
|
And(Operand, Operand, Operand, SourceSpan),
|
||||||
|
Or(Operand, Operand, Operand, SourceSpan),
|
||||||
|
Xor(Operand, Operand, Operand, SourceSpan),
|
||||||
|
Nand(Operand, Operand, Operand, SourceSpan),
|
||||||
|
Nor(Operand, Operand, Operand, SourceSpan),
|
||||||
|
Xnor(Operand, Operand, Operand, SourceSpan),
|
||||||
|
|
||||||
|
// Misc
|
||||||
|
Cmp(Operand, Operand, SourceSpan),
|
||||||
|
Jmp(String, SourceSpan),
|
||||||
|
Jeq(String, SourceSpan),
|
||||||
|
Jne(String, SourceSpan),
|
||||||
|
Jg(String, SourceSpan),
|
||||||
|
Jge(String, SourceSpan),
|
||||||
|
Jl(String, SourceSpan),
|
||||||
|
Jle(String, SourceSpan),
|
||||||
|
Hlt,
|
||||||
|
|
||||||
|
Label(String),
|
||||||
|
|
||||||
|
Err,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum ResolvedInst {
|
||||||
|
// Quantum Instructions
|
||||||
|
Qsel(usize, SourceSpan),
|
||||||
|
Id(usize, SourceSpan),
|
||||||
|
Hadamard(usize, SourceSpan),
|
||||||
|
Cnot(usize, usize, SourceSpan),
|
||||||
|
Ccnot(usize, usize, usize, SourceSpan),
|
||||||
|
X(usize, SourceSpan),
|
||||||
|
Y(usize, SourceSpan),
|
||||||
|
Z(usize, SourceSpan),
|
||||||
|
Rx(usize, Rotation, SourceSpan),
|
||||||
|
Ry(usize, Rotation, SourceSpan),
|
||||||
|
Rz(usize, Rotation, SourceSpan),
|
||||||
|
U(usize, Rotation, Rotation, Rotation, SourceSpan),
|
||||||
|
S(usize, SourceSpan),
|
||||||
|
T(usize, SourceSpan),
|
||||||
|
Sdg(usize, SourceSpan),
|
||||||
|
Tdg(usize, SourceSpan),
|
||||||
|
Phase(usize, Rotation, SourceSpan),
|
||||||
|
Ch(usize, usize, SourceSpan),
|
||||||
|
Cy(usize, usize, SourceSpan),
|
||||||
|
Cz(usize, usize, SourceSpan),
|
||||||
|
CPhase(usize, usize, Rotation, SourceSpan),
|
||||||
|
Swap(usize, usize, SourceSpan),
|
||||||
|
SqrtX(usize, SourceSpan),
|
||||||
|
SqrtSwap(usize, usize, SourceSpan),
|
||||||
|
CSwap(usize, usize, usize, SourceSpan),
|
||||||
|
Measure(usize, usize, usize, SourceSpan),
|
||||||
|
|
||||||
|
// Custom gate stuff
|
||||||
|
Custom(String, Vec<usize>, Vec<IdentVal>, SourceSpan),
|
||||||
|
|
||||||
|
// Classical Instructions
|
||||||
|
Mov(Operand, Operand, SourceSpan),
|
||||||
|
Add(Operand, Operand, Operand, SourceSpan),
|
||||||
|
Sub(Operand, Operand, Operand, SourceSpan),
|
||||||
|
Mul(Operand, Operand, Operand, SourceSpan),
|
||||||
|
UMul(Operand, Operand, Operand, SourceSpan),
|
||||||
|
Div(Operand, Operand, Operand, SourceSpan),
|
||||||
|
SMul(Operand, Operand, Operand, SourceSpan),
|
||||||
|
SUMul(Operand, Operand, Operand, SourceSpan),
|
||||||
|
SDiv(Operand, Operand, Operand, SourceSpan),
|
||||||
|
Not(Operand, Operand, SourceSpan),
|
||||||
|
And(Operand, Operand, Operand, SourceSpan),
|
||||||
|
Or(Operand, Operand, Operand, SourceSpan),
|
||||||
|
Xor(Operand, Operand, Operand, SourceSpan),
|
||||||
|
Nand(Operand, Operand, Operand, SourceSpan),
|
||||||
|
Nor(Operand, Operand, Operand, SourceSpan),
|
||||||
|
Xnor(Operand, Operand, Operand, SourceSpan),
|
||||||
|
|
||||||
|
// Misc
|
||||||
|
Cmp(Operand, Operand, SourceSpan),
|
||||||
|
Jmp(usize, SourceSpan),
|
||||||
|
Jeq(usize, SourceSpan),
|
||||||
|
Jne(usize, SourceSpan),
|
||||||
|
Jg(usize, SourceSpan),
|
||||||
|
Jge(usize, SourceSpan),
|
||||||
|
Jl(usize, SourceSpan),
|
||||||
|
Jle(usize, SourceSpan),
|
||||||
|
|
||||||
|
Hlt,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&Inst> for ResolvedInst {
|
||||||
|
// The most painful damn function ever to write
|
||||||
|
fn from(value: &Inst) -> Self {
|
||||||
|
match value {
|
||||||
|
// Quantum instructions
|
||||||
|
Inst::Qsel(q, s) => Self::Qsel(*q, s.clone()),
|
||||||
|
Inst::Id(q, s) => Self::Id(*q, s.clone()),
|
||||||
|
Inst::Hadamard(q, s) => Self::Hadamard(*q, s.clone()),
|
||||||
|
Inst::Cnot(q1, q2, s) => Self::Cnot(*q1, *q2, s.clone()),
|
||||||
|
Inst::Ccnot(q1, q2, q3, s) => Self::Ccnot(*q1, *q2, *q3, s.clone()),
|
||||||
|
Inst::X(q, s) => Self::X(*q, s.clone()),
|
||||||
|
Inst::Y(q, s) => Self::Y(*q, s.clone()),
|
||||||
|
Inst::Z(q, s) => Self::Z(*q, s.clone()),
|
||||||
|
Inst::Rx(q, r, s) => Self::Rx(*q, r.clone(), s.clone()),
|
||||||
|
Inst::Ry(q, r, s) => Self::Ry(*q, r.clone(), s.clone()),
|
||||||
|
Inst::Rz(q, r, s) => Self::Rz(*q, r.clone(), s.clone()),
|
||||||
|
Inst::U(q, r1, r2, r3, s) => Self::U(*q, r1.clone(), r2.clone(), r3.clone(), s.clone()),
|
||||||
|
Inst::S(q, s) => Self::S(*q, s.clone()),
|
||||||
|
Inst::T(q, s) => Self::T(*q, s.clone()),
|
||||||
|
Inst::Sdg(q, s) => Self::Sdg(*q, s.clone()),
|
||||||
|
Inst::Tdg(q, s) => Self::Tdg(*q, s.clone()),
|
||||||
|
Inst::Phase(q, r, s) => Self::Phase(*q, r.clone(), s.clone()),
|
||||||
|
Inst::Ch(q1, q2, s) => Self::Ch(*q1, *q2, s.clone()),
|
||||||
|
Inst::Cy(q1, q2, s) => Self::Cy(*q1, *q2, s.clone()),
|
||||||
|
Inst::Cz(q1, q2, s) => Self::Cz(*q1, *q2, s.clone()),
|
||||||
|
Inst::CPhase(q1, q2, r, s) => Self::CPhase(*q1, *q2, r.clone(), s.clone()),
|
||||||
|
Inst::Swap(q1, q2, s) => Self::Swap(*q1, *q2, s.clone()),
|
||||||
|
Inst::SqrtX(q, s) => Self::SqrtX(*q, s.clone()),
|
||||||
|
Inst::SqrtSwap(q1, q2, s) => Self::SqrtSwap(*q1, *q2, s.clone()),
|
||||||
|
Inst::CSwap(q1, q2, q3, s) => Self::CSwap(*q1, *q2, *q3, s.clone()),
|
||||||
|
Inst::Measure(q, cr, cb, s) => Self::Measure(*q, *cr, *cb, s.clone()),
|
||||||
|
|
||||||
|
// Custom gate stuff
|
||||||
|
Inst::Custom(name, qbits, args, s) => {
|
||||||
|
Self::Custom(name.clone(), qbits.clone(), args.clone(), s.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Classical Instructions
|
||||||
|
Inst::Mov(cr1, val, s) => Self::Mov(cr1.clone(), val.clone(), s.clone()),
|
||||||
|
Inst::Add(cr1, cr2, cr3, s) => {
|
||||||
|
Self::Add(cr1.clone(), cr2.clone(), cr3.clone(), s.clone())
|
||||||
|
}
|
||||||
|
Inst::Sub(cr1, cr2, cr3, s) => {
|
||||||
|
Self::Sub(cr1.clone(), cr2.clone(), cr3.clone(), s.clone())
|
||||||
|
}
|
||||||
|
Inst::Mul(cr1, cr2, cr3, s) => {
|
||||||
|
Self::Mul(cr1.clone(), cr2.clone(), cr3.clone(), s.clone())
|
||||||
|
}
|
||||||
|
Inst::UMul(cr1, cr2, cr3, s) => {
|
||||||
|
Self::UMul(cr1.clone(), cr2.clone(), cr3.clone(), s.clone())
|
||||||
|
}
|
||||||
|
Inst::Div(cr1, cr2, cr3, s) => {
|
||||||
|
Self::Div(cr1.clone(), cr2.clone(), cr3.clone(), s.clone())
|
||||||
|
}
|
||||||
|
Inst::SMul(cr1, cr2, cr3, s) => {
|
||||||
|
Self::SMul(cr1.clone(), cr2.clone(), cr3.clone(), s.clone())
|
||||||
|
}
|
||||||
|
Inst::SUMul(cr1, cr2, cr3, s) => {
|
||||||
|
Self::SUMul(cr1.clone(), cr2.clone(), cr3.clone(), s.clone())
|
||||||
|
}
|
||||||
|
Inst::SDiv(cr1, cr2, cr3, s) => {
|
||||||
|
Self::SDiv(cr1.clone(), cr2.clone(), cr3.clone(), s.clone())
|
||||||
|
}
|
||||||
|
Inst::Not(cr1, cr2, s) => Self::Not(cr1.clone(), cr2.clone(), s.clone()),
|
||||||
|
Inst::And(cr1, cr2, cr3, s) => {
|
||||||
|
Self::And(cr1.clone(), cr2.clone(), cr3.clone(), s.clone())
|
||||||
|
}
|
||||||
|
Inst::Or(cr1, cr2, cr3, s) => {
|
||||||
|
Self::Or(cr1.clone(), cr2.clone(), cr3.clone(), s.clone())
|
||||||
|
}
|
||||||
|
Inst::Xor(cr1, cr2, cr3, s) => {
|
||||||
|
Self::Xor(cr1.clone(), cr2.clone(), cr3.clone(), s.clone())
|
||||||
|
}
|
||||||
|
Inst::Nand(cr1, cr2, cr3, s) => {
|
||||||
|
Self::Nand(cr1.clone(), cr2.clone(), cr3.clone(), s.clone())
|
||||||
|
}
|
||||||
|
Inst::Nor(cr1, cr2, cr3, s) => {
|
||||||
|
Self::Nor(cr1.clone(), cr2.clone(), cr3.clone(), s.clone())
|
||||||
|
}
|
||||||
|
Inst::Xnor(cr1, cr2, cr3, s) => {
|
||||||
|
Self::Xnor(cr1.clone(), cr2.clone(), cr3.clone(), s.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Misc
|
||||||
|
Inst::Cmp(cr1, val, s) => Self::Cmp(cr1.clone(), val.clone(), s.clone()),
|
||||||
|
Inst::Hlt => Self::Hlt,
|
||||||
|
|
||||||
|
_ => unreachable!(), /* Atleast hopefully unreachable if I didn't mess up stuff */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ResolvedInst {
|
||||||
|
pub fn get_span(&self) -> &SourceSpan {
|
||||||
|
match self {
|
||||||
|
Self::Qsel(_, s) => s,
|
||||||
|
Self::Id(_, s) => s,
|
||||||
|
Self::Hadamard(_, s) => s,
|
||||||
|
Self::Cnot(_, _, s) => s,
|
||||||
|
Self::Ccnot(_, _, _, s) => s,
|
||||||
|
Self::X(_, s) => s,
|
||||||
|
Self::Y(_, s) => s,
|
||||||
|
Self::Z(_, s) => s,
|
||||||
|
Self::Rx(_, _, s) => s,
|
||||||
|
Self::Ry(_, _, s) => s,
|
||||||
|
Self::Rz(_, _, s) => s,
|
||||||
|
Self::U(_, _, _, _, s) => s,
|
||||||
|
Self::S(_, s) => s,
|
||||||
|
Self::T(_, s) => s,
|
||||||
|
Self::Sdg(_, s) => s,
|
||||||
|
Self::Tdg(_, s) => s,
|
||||||
|
Self::Phase(_, _, s) => s,
|
||||||
|
Self::Ch(_, _, s) => s,
|
||||||
|
Self::Cy(_, _, s) => s,
|
||||||
|
Self::Cz(_, _, s) => s,
|
||||||
|
Self::CPhase(_, _, _, s) => s,
|
||||||
|
Self::Swap(_, _, s) => s,
|
||||||
|
Self::SqrtX(_, s) => s,
|
||||||
|
Self::SqrtSwap(_, _, s) => s,
|
||||||
|
Self::CSwap(_, _, _, s) => s,
|
||||||
|
Self::Measure(_, _, _, s) => s,
|
||||||
|
|
||||||
|
// Custom gate stuff
|
||||||
|
Self::Custom(_, _, _, s) => s,
|
||||||
|
|
||||||
|
// Classical Instructions
|
||||||
|
Self::Mov(_, _, s) => s,
|
||||||
|
Self::Add(_, _, _, s) => s,
|
||||||
|
Self::Sub(_, _, _, s) => s,
|
||||||
|
Self::Mul(_, _, _, s) => s,
|
||||||
|
Self::UMul(_, _, _, s) => s,
|
||||||
|
Self::Div(_, _, _, s) => s,
|
||||||
|
Self::SMul(_, _, _, s) => s,
|
||||||
|
Self::SUMul(_, _, _, s) => s,
|
||||||
|
Self::SDiv(_, _, _, s) => s,
|
||||||
|
Self::Not(_, _, s) => s,
|
||||||
|
Self::And(_, _, _, s) => s,
|
||||||
|
Self::Or(_, _, _, s) => s,
|
||||||
|
Self::Xor(_, _, _, s) => s,
|
||||||
|
Self::Nand(_, _, _, s) => s,
|
||||||
|
Self::Nor(_, _, _, s) => s,
|
||||||
|
Self::Xnor(_, _, _, s) => s,
|
||||||
|
|
||||||
|
// Misc
|
||||||
|
Self::Cmp(_, _, s) => s,
|
||||||
|
Self::Jmp(_, s) => s,
|
||||||
|
Self::Jeq(_, s) => s,
|
||||||
|
Self::Jne(_, s) => s,
|
||||||
|
Self::Jg(_, s) => s,
|
||||||
|
Self::Jge(_, s) => s,
|
||||||
|
Self::Jl(_, s) => s,
|
||||||
|
Self::Jle(_, s) => s,
|
||||||
|
|
||||||
|
Self::Hlt => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum Operand {
|
||||||
|
Imm(i64),
|
||||||
|
Reg(usize),
|
||||||
|
Addr(MemAddr),
|
||||||
|
Ident(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum IdentVal {
|
||||||
|
Rot(Rot),
|
||||||
|
|
||||||
|
Imm(i64),
|
||||||
|
Reg(usize),
|
||||||
|
Addr(MemAddr),
|
||||||
|
}
|
||||||
|
impl IdentVal {
|
||||||
|
pub fn get_type(&self) -> IdentType {
|
||||||
|
match self {
|
||||||
|
Self::Rot(_) => IdentType::Rot,
|
||||||
|
Self::Imm(_) => IdentType::Imm,
|
||||||
|
Self::Reg(_) => IdentType::Reg,
|
||||||
|
Self::Addr(_) => IdentType::MemAddr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_rot(&self) -> Option<Rot> {
|
||||||
|
match self {
|
||||||
|
Self::Rot(rot) => Some(*rot),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<&IdentVal> for Operand {
|
||||||
|
fn from(value: &IdentVal) -> Self {
|
||||||
|
match value {
|
||||||
|
IdentVal::Imm(imm) => Self::Imm(*imm),
|
||||||
|
IdentVal::Reg(reg) => Self::Reg(*reg),
|
||||||
|
IdentVal::Addr(addr) => Self::Addr(*addr),
|
||||||
|
|
||||||
|
IdentVal::Rot(_) => unreachable!(), // hopefully...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum IdentType {
|
||||||
|
Rot,
|
||||||
|
|
||||||
|
Imm,
|
||||||
|
Reg,
|
||||||
|
MemAddr,
|
||||||
|
}
|
||||||
|
impl Display for IdentType {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Rot => write!(f, "Rot"),
|
||||||
|
Self::Imm => write!(f, "Imm"),
|
||||||
|
Self::Reg => write!(f, "Reg"),
|
||||||
|
Self::MemAddr => write!(f, "Addr"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum MemAddr {
|
||||||
|
Address(usize),
|
||||||
|
// (reg, align, offset) = reg * align + offset
|
||||||
|
Indirect(usize, usize, usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct Rot(pub i64, pub u64);
|
||||||
|
impl Rot {
|
||||||
|
pub fn get_angle(&self) -> f64 {
|
||||||
|
(self.0 as f64) * std::f64::consts::PI / (self.1 as f64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum Rotation {
|
||||||
|
Rot(Rot),
|
||||||
|
Ident(String),
|
||||||
|
}
|
||||||
|
impl Rotation {
|
||||||
|
pub fn get_rot(&self, args: &HashMap<String, IdentVal>) -> Option<Rot> {
|
||||||
|
match self {
|
||||||
|
Self::Rot(rot) => Some(*rot),
|
||||||
|
Self::Ident(ident) => {
|
||||||
|
if let Some(rot) = args.get(ident) {
|
||||||
|
rot.get_rot()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum ResolveError {
|
||||||
|
UndefinedLabel(String, SourceSpan),
|
||||||
|
ParseError(Diagnostic<usize>),
|
||||||
|
UndefinedGate(String, SourceSpan),
|
||||||
|
CustomGateError(Diagnostic<usize>),
|
||||||
|
}
|
1480
src/emulator.rs
Normal file
1480
src/emulator.rs
Normal file
File diff suppressed because it is too large
Load diff
311
src/grammar.lalrpop
Normal file
311
src/grammar.lalrpop
Normal file
|
@ -0,0 +1,311 @@
|
||||||
|
use crate::ast::*;
|
||||||
|
|
||||||
|
use lalrpop_util::ParseError;
|
||||||
|
|
||||||
|
grammar<'err>(file: usize, errors: &'err mut Vec<ParseError<usize, Token<'input>, &'static str>>);
|
||||||
|
|
||||||
|
match {
|
||||||
|
"qbits",
|
||||||
|
"cbits",
|
||||||
|
"qregs",
|
||||||
|
"cregs",
|
||||||
|
"mem",
|
||||||
|
r"q[0-9]+" => QBIT,
|
||||||
|
r"qr[0-9]+" => QREG,
|
||||||
|
r"cr[0-9]+" => CREG,
|
||||||
|
r"c[0-9]+" => CBIT,
|
||||||
|
"gate",
|
||||||
|
"Rot",
|
||||||
|
"Imm",
|
||||||
|
"Reg",
|
||||||
|
"Addr",
|
||||||
|
r"[0-9]+" => NUM,
|
||||||
|
":",
|
||||||
|
"pi",
|
||||||
|
"/",
|
||||||
|
"[",
|
||||||
|
"]",
|
||||||
|
"(",
|
||||||
|
")",
|
||||||
|
"{",
|
||||||
|
"}",
|
||||||
|
"+",
|
||||||
|
"*",
|
||||||
|
"=",
|
||||||
|
";",
|
||||||
|
r"#.*" => {},
|
||||||
|
r"\n+" => NEWLINE,
|
||||||
|
r" +" => SPACE,
|
||||||
|
"-",
|
||||||
|
|
||||||
|
// Instructions
|
||||||
|
// Quantum instructions
|
||||||
|
"h",
|
||||||
|
"cnot",
|
||||||
|
"ccnot",
|
||||||
|
"x",
|
||||||
|
"y",
|
||||||
|
"z",
|
||||||
|
"rx",
|
||||||
|
"ry",
|
||||||
|
"rz",
|
||||||
|
"u",
|
||||||
|
"s",
|
||||||
|
"t",
|
||||||
|
"sdg",
|
||||||
|
"tdg",
|
||||||
|
"p",
|
||||||
|
"ch",
|
||||||
|
"cy",
|
||||||
|
"cz",
|
||||||
|
"cp",
|
||||||
|
"swap",
|
||||||
|
"sqrtx",
|
||||||
|
"sqrtswp",
|
||||||
|
"cswap",
|
||||||
|
|
||||||
|
// Classical instructions
|
||||||
|
"mov",
|
||||||
|
"add",
|
||||||
|
"sub",
|
||||||
|
"mult",
|
||||||
|
"umult",
|
||||||
|
"div",
|
||||||
|
"smult",
|
||||||
|
"sumult",
|
||||||
|
"sdiv",
|
||||||
|
"not",
|
||||||
|
"and",
|
||||||
|
"or",
|
||||||
|
"xor",
|
||||||
|
"nand",
|
||||||
|
"nor",
|
||||||
|
"xnor",
|
||||||
|
|
||||||
|
// Misc instructions
|
||||||
|
"qsel",
|
||||||
|
"m",
|
||||||
|
"cmp",
|
||||||
|
"jmp",
|
||||||
|
"jeq",
|
||||||
|
"jne",
|
||||||
|
"jg",
|
||||||
|
"jge",
|
||||||
|
"jl",
|
||||||
|
"jle",
|
||||||
|
"hlt",
|
||||||
|
} else {
|
||||||
|
r"[a-zA-Z_][a-zA-Z0-9_]*" => IDENT,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub Program: Result<Program, ResolveError> = {
|
||||||
|
<h: Headers> <i: Instructions> => resolve_ast(h, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
Headers: (usize, usize, usize, usize, usize) = {
|
||||||
|
"qbits" SPACE <qbits: Num> NEWLINE
|
||||||
|
"cbits" SPACE <cbits: Num> NEWLINE
|
||||||
|
"qregs" SPACE <qregs: Num> NEWLINE
|
||||||
|
"cregs" SPACE <cregs: Num> NEWLINE
|
||||||
|
"mem" SPACE <mem: Num> NEWLINE
|
||||||
|
=> (qbits, cbits, qregs, cregs, mem)
|
||||||
|
}
|
||||||
|
|
||||||
|
Instructions: Vec<Inst> = {
|
||||||
|
(SPACE? <Instruction> NEWLINE)*
|
||||||
|
}
|
||||||
|
|
||||||
|
Instruction: Inst = {
|
||||||
|
// Quantum instructions
|
||||||
|
<l: @L> "h" SPACE <q:Qbit> <r: @R> => Inst::Hadamard(q, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "cnot" SPACE <q0:Qbit> SPACE <q1:Qbit> <r: @R> => Inst::Cnot(q0, q1, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "ccnot" SPACE <q0:Qbit> SPACE <q1:Qbit> SPACE <q2:Qbit> <r: @R> => Inst::Ccnot(q0, q1, q2, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "x" SPACE <q:Qbit> <r: @R> => Inst::X(q, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "y" SPACE <q:Qbit> <r: @R> => Inst::Y(q, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "z" SPACE <q:Qbit> <r: @R> => Inst::Z(q, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "rx" SPACE <q:Qbit> SPACE <rot:Rot> <r: @R> => Inst::Rx(q, rot, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "ry" SPACE <q:Qbit> SPACE <rot:Rot> <r: @R> => Inst::Ry(q, rot, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "rz" SPACE <q:Qbit> SPACE <rot:Rot> <r: @R> => Inst::Rz(q, rot, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "u" SPACE <q:Qbit> SPACE <r0:Rot> SPACE <r1:Rot> SPACE <r2:Rot> <r: @R> => Inst::U(q, r0, r1, r2, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "s" SPACE <q:Qbit> <r: @R> => Inst::S(q, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "t" SPACE <q:Qbit> <r: @R> => Inst::T(q, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "sdg" SPACE <q:Qbit> <r: @R> => Inst::Sdg(q, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "tdg" SPACE <q:Qbit> <r: @R> => Inst::Tdg(q, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "p" SPACE <q:Qbit> SPACE <rot:Rot> <r: @R> => Inst::Phase(q, rot, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "ch" SPACE <q0:Qbit> SPACE <q1:Qbit> <r: @R> => Inst::Ch(q0, q1, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "cy" SPACE <q0:Qbit> SPACE <q1:Qbit> <r: @R> => Inst::Cy(q0, q1, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "cz" SPACE <q0:Qbit> SPACE <q1:Qbit> <r: @R> => Inst::Cz(q0, q1, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "cp" SPACE <q0:Qbit> SPACE <q1:Qbit> SPACE <rot:Rot> <r:@R> => Inst::CPhase(q0, q1, rot, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "swap" <q0:Qbit> SPACE <q1:Qbit> <r: @R> => Inst::Swap(q0, q1, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "sqrtx" <q:Qbit> <r: @R> => Inst::SqrtX(q, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "sqrtswp" <q0:Qbit> SPACE <q1:Qbit> <r: @R> => Inst::SqrtSwap(q0, q1, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "cswap" SPACE <q0:Qbit> SPACE <q1:Qbit> SPACE <q2:Qbit> <r: @R> => Inst::CSwap(q0, q1, q2, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "m" SPACE <q:Qbit> SPACE <cr:Creg> SPACE <c:Cbit> <r: @R> => Inst::Measure(q, cr, c, SourceSpan::new(file, l..r)),
|
||||||
|
|
||||||
|
// Custom gates stuff
|
||||||
|
"gate" SPACE <name:Ident> SPACE? "(" SPACE? "qbits" SPACE? "=" SPACE? <qbits:Num> SPACE? ")" SPACE?
|
||||||
|
<args:("(" SPACE? <Ident> SPACE? ":" SPACE? <IdentType> SPACE? ")" SPACE?)*>
|
||||||
|
"{" NEWLINE <body:Instructions> "}" => Inst::CustomGateDef(name, qbits, args, body),
|
||||||
|
|
||||||
|
<l: @L> <name:Ident> SPACE <mut qbits:(<Qbit> SPACE)*> <e1:Qbit?> <args:(";" SPACE <(<CGateArg> SPACE)*> <CGateArg?>)?> <r:@R> => {
|
||||||
|
let mut other_args;
|
||||||
|
let e2;
|
||||||
|
if let Some(args) = args {
|
||||||
|
other_args = args.0;
|
||||||
|
e2 = args.1;
|
||||||
|
} else {
|
||||||
|
other_args = Vec::new();
|
||||||
|
e2 = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Inst::Custom(
|
||||||
|
name,
|
||||||
|
match e1 {
|
||||||
|
None => qbits,
|
||||||
|
Some(e) => {
|
||||||
|
qbits.push(e);
|
||||||
|
qbits
|
||||||
|
}
|
||||||
|
},
|
||||||
|
match e2 {
|
||||||
|
None => other_args,
|
||||||
|
Some(e) => {
|
||||||
|
other_args.push(e);
|
||||||
|
other_args
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SourceSpan::new(file, l..r),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|
||||||
|
// Classical instructions
|
||||||
|
<l: @L> "mov" SPACE <r1:SrcOp> SPACE <r2:AnyOp> <r: @R> => Inst::Mov(r1, r2, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "add" SPACE <r1:SrcOp> SPACE <r2:AnyOp> SPACE <r3:AnyOp> <r: @R> => Inst::Add(
|
||||||
|
r1, r2, r3,
|
||||||
|
SourceSpan::new(file, l..r),
|
||||||
|
),
|
||||||
|
<l: @L> "sub" SPACE <r1:SrcOp> SPACE <r2:AnyOp> SPACE <r3:AnyOp> <r: @R> => Inst::Sub(
|
||||||
|
r1, r2, r3,
|
||||||
|
SourceSpan::new(file, l..r),
|
||||||
|
),
|
||||||
|
<l: @L> "mult" SPACE <r1:SrcOp> SPACE <r2:AnyOp> SPACE <r3:AnyOp> <r: @R> => Inst::Mul(
|
||||||
|
r1, r2, r3,
|
||||||
|
SourceSpan::new(file, l..r),
|
||||||
|
),
|
||||||
|
<l: @L> "umult" SPACE <r1:SrcOp> SPACE <r2:AnyOp> SPACE <r3:AnyOp> <r: @R> => Inst::UMul(
|
||||||
|
r1, r2, r3,
|
||||||
|
SourceSpan::new(file, l..r),
|
||||||
|
),
|
||||||
|
<l: @L> "div" SPACE <r1:SrcOp> SPACE <r2:AnyOp> SPACE <r3:AnyOp> <r: @R> => Inst::Div(
|
||||||
|
r1, r2, r3,
|
||||||
|
SourceSpan::new(file, l..r),
|
||||||
|
),
|
||||||
|
<l: @L> "smult" SPACE <r1:SrcOp> SPACE <r2:AnyOp> SPACE <r3:AnyOp> <r: @R> => Inst::SMul(
|
||||||
|
r1, r2, r3,
|
||||||
|
SourceSpan::new(file, l..r),
|
||||||
|
),
|
||||||
|
<l: @L> "sumult" SPACE <r1:SrcOp> SPACE <r2:AnyOp> SPACE <r3:AnyOp> <r: @R> => Inst::SUMul(
|
||||||
|
r1, r2, r3,
|
||||||
|
SourceSpan::new(file, l..r),
|
||||||
|
),
|
||||||
|
<l: @L> "sdiv" SPACE <r1:SrcOp> SPACE <r2:AnyOp> SPACE <r3:AnyOp> <r: @R> => Inst::SDiv(
|
||||||
|
r1, r2, r3,
|
||||||
|
SourceSpan::new(file, l..r),
|
||||||
|
),
|
||||||
|
<l: @L> "not" SPACE <r1:SrcOp> SPACE <r2:AnyOp> <r: @R> => Inst::Not(r1, r2, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "and" SPACE <r1:SrcOp> SPACE <r2:AnyOp> SPACE <r3:AnyOp> <r: @R> => Inst::And(
|
||||||
|
r1, r2, r3,
|
||||||
|
SourceSpan::new(file, l..r),
|
||||||
|
),
|
||||||
|
<l: @L> "or" SPACE <r1:SrcOp> SPACE <r2:AnyOp> SPACE <r3:AnyOp> <r: @R> => Inst::Or(
|
||||||
|
r1, r2, r3,
|
||||||
|
SourceSpan::new(file, l..r),
|
||||||
|
),
|
||||||
|
<l: @L> "xor" SPACE <r1:SrcOp> SPACE <r2:AnyOp> SPACE <r3:AnyOp> <r: @R> => Inst::Xor(
|
||||||
|
r1, r2, r3,
|
||||||
|
SourceSpan::new(file, l..r),
|
||||||
|
),
|
||||||
|
<l: @L> "nand" SPACE <r1:SrcOp> SPACE <r2:AnyOp> SPACE <r3:AnyOp> <r: @R> => Inst::Nand(
|
||||||
|
r1, r2, r3,
|
||||||
|
SourceSpan::new(file, l..r),
|
||||||
|
),
|
||||||
|
<l: @L> "nor" SPACE <r1:SrcOp> SPACE <r2:AnyOp> SPACE <r3:AnyOp> <r: @R> => Inst::Nor(
|
||||||
|
r1, r2, r3,
|
||||||
|
SourceSpan::new(file, l..r),
|
||||||
|
),
|
||||||
|
<l: @L> "xnor" SPACE <r1:SrcOp> SPACE <r2:AnyOp> SPACE <r3:AnyOp> <r: @R> => Inst::Xnor(
|
||||||
|
r1, r2, r3,
|
||||||
|
SourceSpan::new(file, l..r),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Misc instructions
|
||||||
|
<l: @L> "qsel" SPACE <qr:Qreg> <r: @R> => Inst::Qsel(qr, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "cmp" SPACE <r1:SrcOp> SPACE <r2:AnyOp> <r: @R> => Inst::Cmp(r1, r2, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "jmp" SPACE <lbl:Label> <r: @R> => Inst::Jmp(lbl, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "jeq" SPACE <lbl:Label> <r: @R> => Inst::Jeq(lbl, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "jne" SPACE <lbl:Label> <r: @R> => Inst::Jne(lbl, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "jg" SPACE <lbl:Label> <r: @R> => Inst::Jg(lbl, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "jge" SPACE <lbl:Label> <r: @R> => Inst::Jge(lbl, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "jl" SPACE <lbl:Label> <r: @R> => Inst::Jl(lbl, SourceSpan::new(file, l..r)),
|
||||||
|
<l: @L> "jle" SPACE <lbl:Label> <r: @R> => Inst::Jle(lbl, SourceSpan::new(file, l..r)),
|
||||||
|
"hlt" => Inst::Hlt,
|
||||||
|
|
||||||
|
<Label> ":" => Inst::Label(<>),
|
||||||
|
|
||||||
|
! => {
|
||||||
|
errors.push(<>.error);
|
||||||
|
Inst::Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Num: usize = NUM => <>.parse().unwrap();
|
||||||
|
Imm: isize = "-"? NUM => ((<>).0.unwrap_or("").to_string() + (<>).1).parse::<isize>().unwrap();
|
||||||
|
|
||||||
|
Label: String = IDENT => String::from(<>);
|
||||||
|
Ident: String = IDENT => String::from(<>);
|
||||||
|
|
||||||
|
Qbit: usize = QBIT => <>[1..].parse().unwrap();
|
||||||
|
Qreg: usize = QREG => <>[2..].parse().unwrap();
|
||||||
|
_Rot: Rot = <sgn:"-"?> <num:Num?> "pi" <den:("/" <Num>)?> => {
|
||||||
|
let sign = if sgn.is_some() { -1 } else { 1 };
|
||||||
|
let num = if let Some(num) = num { num as i64 } else { 1 };
|
||||||
|
let den = if let Some(den) = den { den as u64 } else { 1 };
|
||||||
|
Rot(sign * num, den)
|
||||||
|
};
|
||||||
|
Rot: Rotation = _Rot => Rotation::Rot(<>);
|
||||||
|
Creg: usize = CREG => <>[2..].parse().unwrap();
|
||||||
|
Cbit: usize = CBIT => <>[1..].parse().unwrap();
|
||||||
|
Mem: MemAddr = {
|
||||||
|
"[" SPACE? <Creg> SPACE? "]" => MemAddr::Indirect(<>, 1, 0),
|
||||||
|
"[" SPACE? <Num> SPACE? "]" => MemAddr::Address(<>),
|
||||||
|
"[" SPACE? <reg: Creg> SPACE? "+" SPACE? <offset: Num> SPACE? "]" => MemAddr::Indirect(reg, 1, offset),
|
||||||
|
"[" SPACE? <reg: Creg> SPACE? "*" SPACE? <align: Num> SPACE? "+" SPACE? <offset: Num> SPACE? "]" => MemAddr::Indirect(reg, align, offset),
|
||||||
|
};
|
||||||
|
SrcOp: Operand = {
|
||||||
|
Creg => Operand::Reg(<>),
|
||||||
|
Mem => Operand::Addr(<>),
|
||||||
|
|
||||||
|
Ident => Operand::Ident(<>),
|
||||||
|
};
|
||||||
|
AnyOp: Operand = {
|
||||||
|
Imm => Operand::Imm(<> as i64),
|
||||||
|
Creg => Operand::Reg(<>),
|
||||||
|
Mem => Operand::Addr(<>),
|
||||||
|
|
||||||
|
Ident => Operand::Ident(<>),
|
||||||
|
};
|
||||||
|
|
||||||
|
CGateArg: IdentVal = {
|
||||||
|
_Rot => IdentVal::Rot(<>),
|
||||||
|
|
||||||
|
Imm => IdentVal::Imm(<> as i64),
|
||||||
|
Creg => IdentVal::Reg(<>),
|
||||||
|
Mem => IdentVal::Addr(<>)
|
||||||
|
};
|
||||||
|
IdentType: IdentType = {
|
||||||
|
"Rot" => IdentType::Rot,
|
||||||
|
|
||||||
|
"Imm" => IdentType::Imm,
|
||||||
|
"Reg" => IdentType::Reg,
|
||||||
|
"Addr" => IdentType::MemAddr,
|
||||||
|
};
|
0
src/lib.rs
Normal file
0
src/lib.rs
Normal file
188
src/main.rs
Normal file
188
src/main.rs
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
use std::{
|
||||||
|
fs,
|
||||||
|
io::{Read, Write},
|
||||||
|
};
|
||||||
|
|
||||||
|
use clap::{ArgAction, Parser};
|
||||||
|
|
||||||
|
use codespan_reporting::{
|
||||||
|
diagnostic::{Diagnostic, Label},
|
||||||
|
files::SimpleFiles,
|
||||||
|
term::{
|
||||||
|
self,
|
||||||
|
termcolor::{ColorChoice, StandardStream},
|
||||||
|
Config,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub mod ast;
|
||||||
|
pub mod emulator;
|
||||||
|
|
||||||
|
use ast::*;
|
||||||
|
use emulator::Emulator;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args = Args::parse();
|
||||||
|
let mut f = fs::File::open(&args.input_file).unwrap();
|
||||||
|
let mut contents = String::new();
|
||||||
|
f.read_to_string(&mut contents).unwrap();
|
||||||
|
|
||||||
|
let mut files = SimpleFiles::new();
|
||||||
|
files.add(&args.input_file, &contents);
|
||||||
|
let writer = StandardStream::stderr(ColorChoice::Always);
|
||||||
|
let config = Config::default();
|
||||||
|
|
||||||
|
let (prog, diags) = ast::parse(&contents, 0);
|
||||||
|
|
||||||
|
for diag in &diags {
|
||||||
|
term::emit(&mut writer.lock(), &config, &files, diag).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !diags.is_empty() {
|
||||||
|
std::process::exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(prog) = prog {
|
||||||
|
let mut emulator = Emulator::new(&prog);
|
||||||
|
let mut results = vec![vec![0u64; 1 << prog.headers.1]; prog.headers.3];
|
||||||
|
|
||||||
|
if args.print_emu_state {
|
||||||
|
let res = emulator.run();
|
||||||
|
if let Err(diag) = res {
|
||||||
|
term::emit(&mut writer.lock(), &config, &files, &diag).unwrap();
|
||||||
|
std::process::exit(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("{}", emulator);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if args.classical {
|
||||||
|
let res = emulator.run();
|
||||||
|
if let Err(diag) = res {
|
||||||
|
term::emit(&mut writer.lock(), &config, &files, &diag).unwrap();
|
||||||
|
std::process::exit(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Registers data:");
|
||||||
|
print!("Reg:");
|
||||||
|
for i in 0..prog.headers.3 {
|
||||||
|
print!("\tcr{}", i)
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
print!("Data:");
|
||||||
|
let data = emulator.get_cregs_state();
|
||||||
|
for reg in data {
|
||||||
|
print!("\t{:01$b}", reg.get_val().0, prog.headers.1)
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
|
||||||
|
let mut mem_file = fs::File::options()
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.truncate(true)
|
||||||
|
.open("mem.bin")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mem = emulator.get_mem_state();
|
||||||
|
for chunk in mem.chunks(16) {
|
||||||
|
for data in chunk {
|
||||||
|
write!(mem_file, "{:01$b} ", data.get_val().0, prog.headers.1).unwrap()
|
||||||
|
}
|
||||||
|
writeln!(mem_file).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for _ in 0..args.shots {
|
||||||
|
let res = emulator.run();
|
||||||
|
if let Err(diag) = res {
|
||||||
|
term::emit(&mut writer.lock(), &config, &files, &diag).unwrap();
|
||||||
|
std::process::exit(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
let cregs = emulator.get_cregs_state();
|
||||||
|
for (creg, res) in cregs.iter().zip(results.iter_mut()) {
|
||||||
|
let val1 = creg.get_val().0;
|
||||||
|
res[val1 as usize] += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
emulator.reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("creg statistics:");
|
||||||
|
for (i, result) in results.iter().enumerate() {
|
||||||
|
println!("creg {} stat:", i);
|
||||||
|
let sum = result.iter().sum::<u64>() as f64;
|
||||||
|
for (j, res) in result.iter().enumerate() {
|
||||||
|
println!(
|
||||||
|
"[STATE {:01$b}] freq: {2};\tprob: {3:.5}",
|
||||||
|
j,
|
||||||
|
prog.headers.1,
|
||||||
|
res,
|
||||||
|
(*res as f64) / sum
|
||||||
|
)
|
||||||
|
}
|
||||||
|
println!("-------------------")
|
||||||
|
}
|
||||||
|
} else if let Err(e) = prog {
|
||||||
|
let diag = Diagnostic::error();
|
||||||
|
match e {
|
||||||
|
ResolveError::UndefinedLabel(name, s) => term::emit(
|
||||||
|
&mut writer.lock(),
|
||||||
|
&config,
|
||||||
|
&files,
|
||||||
|
&diag
|
||||||
|
.with_message(format!("Reference to undefined label \"{}\"", name))
|
||||||
|
.with_labels(vec![Label::primary(s.file, s.span)]),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
|
||||||
|
ResolveError::ParseError(diag) => {
|
||||||
|
term::emit(&mut writer.lock(), &config, &files, &diag).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
ResolveError::UndefinedGate(name, s) => term::emit(
|
||||||
|
&mut writer.lock(),
|
||||||
|
&config,
|
||||||
|
&files,
|
||||||
|
&diag
|
||||||
|
.with_message(format!("Usage of undefined gate \"{}\"", name))
|
||||||
|
.with_labels(vec![Label::primary(s.file, s.span)]),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
|
||||||
|
ResolveError::CustomGateError(diag) => {
|
||||||
|
term::emit(&mut writer.lock(), &config, &files, &diag).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::process::exit(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Args {
|
||||||
|
/// The input .qASM file
|
||||||
|
input_file: String,
|
||||||
|
|
||||||
|
/// Number of times to run the program for statistics information
|
||||||
|
#[clap(short = 's', long = "shots", default_value_t = 1024)]
|
||||||
|
shots: u64,
|
||||||
|
|
||||||
|
/// Print the statevectors of the quantum registers and terminate the program
|
||||||
|
#[clap(short = 'p', long = "print-state", default_value_t = false, action = ArgAction::SetTrue)]
|
||||||
|
print_emu_state: bool,
|
||||||
|
|
||||||
|
#[clap(short = 'c', long = "classical", default_value_t = false, action = ArgAction::SetTrue)]
|
||||||
|
classical: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _escaped(c: char) -> String {
|
||||||
|
match c {
|
||||||
|
'\n' => String::from("\\n"),
|
||||||
|
'\r' => String::from("\\r"),
|
||||||
|
_ => c.to_string(),
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue