use std::str::FromStr;
use crate::grammar::{ast, lexer::{Location, Tok, LexicalError}};
grammar;
pub OpenQasmProgram: ast::OpenQasmProgram = {
"OPENQASM" <version:Version> ";" <program:ProgramBody> => ast::OpenQasmProgram{<>}
};
pub OpenQasmLibrary: ast::OpenQasmLibrary = {
<definitions:GateDefinitionList> => ast::OpenQasmLibrary{<>}
}
pub ProgramBody: Vec<ast::Span<ast::Statement>> = {
<left:@L> <statement:Statement> <right:@R> => {
vec![ast::Span {
boundaries: (left, right),
node: Box::new(statement)
}]
},
<program:ProgramBody> <left:@L> <statement:Statement> <right:@R> => {
let mut program = program;
program.push(ast::Span {
boundaries: (left, right),
node: Box::new(statement)
});
program
}
};
pub Statement: ast::Statement = {
RegisterDeclaration,
GateDefinition,
Include,
Barrier => ast::Statement::Barrier(<>),
If,
QuantumOperation => ast::Statement::QuantumOperation(<>)
};
GateDefinition: ast::Statement = {
<docstr:docstring?> <decl:GateDeclaration> "{" "}" =>
ast::Statement::GateDecl {
signature: (decl.0, decl.1, decl.2, vec![]),
docstring: docstr,
},
<docstr:docstring?> <decl:GateDeclaration> "{" <ops:GateOperationList> "}" =>
ast::Statement::GateDecl {
signature: (decl.0, decl.1, decl.2, ops),
docstring: docstr,
},
<docstr:docstring?> "opaque" <decl:GateDeclaration> ";" =>
ast::Statement::OpaqueGateDecl {
signature: (decl.0, decl.1, decl.2),
docstring: docstr,
},
};
Include: ast::Statement = {
"include" <s:string> ";" => ast::Statement::Include(s)
}
If: ast::Statement = {
"if" "(" <r:Id> "==" <t:Int> ")" <op:QuantumOperation> =>
ast::Statement::Conditional(ast::Argument::Id(r), t, op)
}
GateDefinitionList: Vec<ast::Statement> = {
GateDefinition => vec![<>],
<definitions:GateDefinitionList> <d:GateDefinition> => {
let mut definitions = definitions;
definitions.push(d);
definitions
}
}
RegisterDeclaration: ast::Statement = {
"qreg" <Id> "[" <Size> "]" ";" => ast::Statement::QRegDecl(<>),
"creg" <Id> "[" <Size> "]" ";" => ast::Statement::CRegDecl(<>)
}
QuantumOperation: ast::QuantumOperation = {
"measure" <Argument> "->" <Argument> ";" =>
ast::QuantumOperation::Measure(<>),
"reset" <Argument> ";" => ast::QuantumOperation::Reset(<>),
UnitaryOperation => ast::QuantumOperation::Unitary(<>)
}
GateDeclaration: (String, Vec<String>, Vec<String>) = {
"gate" <id:Id> <args:IdList> => (id, vec![], args),
"gate" <id:Id> "(" ")" <args:IdList> => (id, vec![], args),
"gate" <Id> "(" <IdList> ")" <IdList> => (<>)
}
GateOperationList: Vec<ast::GateOperation> = {
GateOperation => vec![<>],
<list:GateOperationList> <op:GateOperation> => {
let mut list = list; list.push(op); list
}
}
GateOperation: ast::GateOperation = {
Barrier => ast::GateOperation::Barrier(<>),
UnitaryOperation => ast::GateOperation::Unitary(<>)
}
Barrier: ast::BarrierPragma = {
"barrier" <ArgumentList> ";" => ast::BarrierPragma(<>),
}
UnitaryOperation: ast::UnitaryOperation = {
"U" "(" <theta:Expr> "," <phi:Expr> "," <lambda:Expr> ")" <target:Argument> ";" =>
ast::UnitaryOperation("U".to_owned(), vec![theta, phi, lambda], vec![target]),
"CX" <Argument> "," <Argument> ";" =>
ast::UnitaryOperation("CX".to_owned(), vec![], vec![<>]),
GateExpansion => ast::UnitaryOperation(<>.0, <>.1, <>.2)
};
GateExpansion: (String, Vec<ast::Expression>, Vec<ast::Argument>) = {
<id:Id> <args:ArgumentList> ";" => (id, vec![], args),
<id:Id> "(" ")" <args:ArgumentList> ";" => (id, vec![], args),
<Id> "(" <ExpressionList> ")" <ArgumentList> ";" => (<>)
};
ExpressionList = List<Expr>;
pub Expr: ast::Expression = {
<l:Expr> <op:ExprOp> <r:Factor> => ast::Expression::Op(op, Box::new(l), Box::new(r)),
Factor
}
ExprOp: ast::OpCode = {
"+" => ast::OpCode::Add,
"-" => ast::OpCode::Sub
}
Factor: ast::Expression = {
<l:Factor> <op:FactorOp> <r:Base> => ast::Expression::Op(op, Box::new(l), Box::new(r)),
Base
}
FactorOp: ast::OpCode = {
"*" => ast::OpCode::Mul,
"/" => ast::OpCode::Div
}
Base: ast::Expression = {
<l:Base> <op:BaseOp> <r:Term> => ast::Expression::Op(op, Box::new(l), Box::new(r)),
Term
}
BaseOp: ast::OpCode = {
"^" => ast::OpCode::Pow
}
Term: ast::Expression = {
"-" <Term> => ast::Expression::Minus(Box::new(<>)),
"pi" => ast::Expression::Pi,
<f:Func> "(" <e:Expr> ")" => ast::Expression::Function(f, Box::new(e)),
Id => ast::Expression::Id(<>),
Real => ast::Expression::Real(<>),
"(" <Expr> ")"
};
Func: ast::FuncCode = {
"sin" => ast::FuncCode::Sin,
"cos" => ast::FuncCode::Cos,
"tan" => ast::FuncCode::Tan,
"exp" => ast::FuncCode::Exp,
"ln" => ast::FuncCode::Ln,
"sqrt" => ast::FuncCode::Sqrt
}
ArgumentList = List<Argument>;
Argument: ast::Argument = {
Id => ast::Argument::Id(<>),
<Id> "[" <Size> "]" => ast::Argument::Item(<>)
};
IdList = List<Id>;
Id: String = <s:id> => s;
Size: usize = <v:int> => usize::from_str(&v).unwrap();
Int: u64 = <v:int> => u64::from_str(&v).unwrap();
Real: f64 = {
<v:real> => f64::from_str(&v).unwrap(),
<v:int> => f64::from_str(&v).unwrap()
}
Version: String = <s:version> => s;
List<T>: Vec<T> = {
T => vec![<>],
<list:List<T>> "," <item:T> => { let mut list = list; list.push(item); list }
}
extern {
type Location = Location;
type Error = LexicalError<Location>;
enum Tok {
"+" => Tok::Add,
"-" => Tok::Minus,
"*" => Tok::Mult,
"/" => Tok::Div,
"^" => Tok::Pow,
"[" => Tok::LBracket,
"]" => Tok::RBracket,
"{" => Tok::LBrace,
"}" => Tok::RBrace,
"(" => Tok::LParent,
")" => Tok::RParent,
";" => Tok::Semi,
"," => Tok::Comma,
"->" => Tok::Arrow,
"==" => Tok::Equal,
"sin" => Tok::Sin,
"cos" => Tok::Cos,
"tan" => Tok::Tan,
"exp" => Tok::Exp,
"ln" => Tok::Ln,
"sqrt" => Tok::Sqrt,
"pi" => Tok::ConstPi,
"U" => Tok::U,
"CX" => Tok::CX,
"opaque" => Tok::Opaque,
"gate" => Tok::Gate,
"include" => Tok::Include,
"qreg" => Tok::QReg,
"creg" => Tok::CReg,
"measure" => Tok::Measure,
"reset" => Tok::Reset,
"barrier" => Tok::Barrier,
"if" => Tok::If,
"OPENQASM" => Tok::QASMHeader,
version => Tok::Version { repr: <String> },
id => Tok::Id { repr: <String> },
int => Tok::Int { repr: <String> },
real => Tok::Real { repr: <String> },
string => Tok::Str { repr: <String> },
docstring => Tok::DocStr { repr: <String> },
}
}