qasm/src/grammar.lalrpop

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,
};