312 lines
10 KiB
Plaintext
312 lines
10 KiB
Plaintext
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,
|
|
};
|