qasmsim 1.2.0

A QASM interpreter and quantum simulator in Rust
Documentation
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> },
    }
}