Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update: parse ternary, binary, and unary logic #58

Merged
merged 13 commits into from
Jun 7, 2022
Merged
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "quil-rs"
description = "Rust tooling for Quil (Quantum Instruction Language)"
version ="0.8.7"
version = "0.8.7"
edition = "2018"
license = "Apache-2.0"
repository = "https://github.com/rigetti/quil-rust"
Expand Down
127 changes: 124 additions & 3 deletions src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,90 @@ impl fmt::Display for ArithmeticOperator {
}
}

#[derive(Clone, Debug, PartialEq)]
pub enum BinaryOperand {
LiteralInteger(i64),
MemoryReference(MemoryReference),
}

impl fmt::Display for BinaryOperand {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self {
BinaryOperand::LiteralInteger(value) => write!(f, "{}", value),
BinaryOperand::MemoryReference(value) => write!(f, "{}", value),
}
}
}

#[derive(Clone, Debug, PartialEq)]
pub enum BinaryOperator {
And,
Ior,
Xor,
}
nilslice marked this conversation as resolved.
Show resolved Hide resolved
impl fmt::Display for BinaryOperator {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self {
BinaryOperator::And => write!(f, "AND"),
BinaryOperator::Ior => write!(f, "IOR"),
BinaryOperator::Xor => write!(f, "XOR"),
}
}
}

#[derive(Clone, Debug, PartialEq)]
pub enum UnaryOperator {
Neg,
Not,
}

impl fmt::Display for UnaryOperator {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self {
UnaryOperator::Neg => write!(f, "NEG"),
UnaryOperator::Not => write!(f, "NOT"),
}
}
}

#[derive(Clone, Debug, PartialEq)]
pub enum TernaryOperand {
LiteralInteger(i64),
LiteralReal(f64),
MemoryReference(MemoryReference),
}

impl fmt::Display for TernaryOperand {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self {
TernaryOperand::LiteralInteger(value) => write!(f, "{}", value),
TernaryOperand::LiteralReal(value) => write!(f, "{}", value),
TernaryOperand::MemoryReference(value) => write!(f, "{}", value),
}
}
}

#[derive(Clone, Debug, PartialEq)]
pub enum TernaryOperator {
nilslice marked this conversation as resolved.
Show resolved Hide resolved
Equal,
GreaterThanOrEqual,
GreaterThan,
LessThanOrEqual,
LessThan,
}
nilslice marked this conversation as resolved.
Show resolved Hide resolved

impl fmt::Display for TernaryOperator {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self {
TernaryOperator::Equal => write!(f, "EQ"),
TernaryOperator::GreaterThanOrEqual => write!(f, "GE"),
TernaryOperator::GreaterThan => write!(f, "GT"),
TernaryOperator::LessThanOrEqual => write!(f, "LE"),
TernaryOperator::LessThan => write!(f, "LT"),
}
}
}

#[derive(Clone, Debug, PartialEq)]
pub enum AttributeValue {
String(String),
Expand Down Expand Up @@ -364,6 +448,24 @@ pub struct Arithmetic {
pub source: ArithmeticOperand,
}

#[derive(Clone, Debug, PartialEq)]
pub struct TernaryLogic {
pub operator: TernaryOperator,
pub operands: (MemoryReference, MemoryReference, TernaryOperand),
}

#[derive(Clone, Debug, PartialEq)]
pub struct BinaryLogic {
nilslice marked this conversation as resolved.
Show resolved Hide resolved
pub operator: BinaryOperator,
pub operands: (MemoryReference, BinaryOperand),
}

#[derive(Clone, Debug, PartialEq)]
pub struct UnaryLogic {
pub operator: UnaryOperator,
pub operand: MemoryReference,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Label(pub String);

Expand Down Expand Up @@ -435,6 +537,9 @@ pub enum Instruction {
SwapPhases(SwapPhases),
WaveformDefinition(WaveformDefinition),
Arithmetic(Arithmetic),
TernaryLogic(TernaryLogic),
BinaryLogic(BinaryLogic),
UnaryLogic(UnaryLogic),
Halt,
Label(Label),
Move(Move),
Expand Down Expand Up @@ -481,6 +586,9 @@ impl From<&Instruction> for InstructionRole {
| Instruction::ShiftPhase(_)
| Instruction::SwapPhases(_) => InstructionRole::RFControl,
Instruction::Arithmetic(_)
| Instruction::TernaryLogic(_)
| Instruction::BinaryLogic(_)
| Instruction::UnaryLogic(_)
| Instruction::Move(_)
| Instruction::Exchange(_)
| Instruction::Load(_)
Expand Down Expand Up @@ -593,7 +701,7 @@ impl fmt::Display for Instruction {
.collect::<Vec<String>>()
.join(", ");
if !parameter_str.is_empty() {
parameter_str = format!("({})", parameter_str)
parameter_str = format!("({})", parameter_str);
}
write!(f, "DEFCIRCUIT {}{}", name, parameter_str)?;
for qubit_variable in qubit_variables {
Expand Down Expand Up @@ -734,7 +842,7 @@ impl fmt::Display for Instruction {
waveform,
}) => {
if !blocking {
write!(f, "NONBLOCKING ")?;
write!(f, "NONBLOCKING ")?
}
write!(f, "PULSE {} {}", frame, waveform)
}
Expand All @@ -754,7 +862,7 @@ impl fmt::Display for Instruction {
memory_reference,
}) => {
if !blocking {
write!(f, "NONBLOCKING ")?;
write!(f, "NONBLOCKING ")?
}
write!(f, "RAW-CAPTURE {} {} {}", frame, duration, memory_reference)
}
Expand Down Expand Up @@ -801,6 +909,19 @@ impl fmt::Display for Instruction {
write!(f, "JUMP-WHEN @{} {}", target, condition)
}
Instruction::Label(Label(label)) => write!(f, "LABEL @{}", label),
Instruction::TernaryLogic(TernaryLogic { operator, operands }) => {
write!(
f,
"{} {} {} {}",
operator, operands.0, operands.1, operands.2
)
}
Instruction::BinaryLogic(BinaryLogic { operator, operands }) => {
write!(f, "{} {} {}", operator, operands.0, operands.1)
}
nilslice marked this conversation as resolved.
Show resolved Hide resolved
Instruction::UnaryLogic(UnaryLogic { operator, operand }) => {
write!(f, "{} {}", operator, operand)
}
}
}
}
Expand Down
60 changes: 56 additions & 4 deletions src/parser/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ use nom::{
};

use crate::instruction::{
Arithmetic, ArithmeticOperand, ArithmeticOperator, Calibration, Capture, CircuitDefinition,
Declaration, Delay, Exchange, Fence, FrameDefinition, Instruction, Jump, JumpUnless, JumpWhen,
Label, Load, Measurement, Move, Pragma, Pulse, RawCapture, Reset, SetFrequency, SetPhase,
SetScale, ShiftFrequency, ShiftPhase, Store, Waveform, WaveformDefinition,
Arithmetic, ArithmeticOperand, ArithmeticOperator, BinaryLogic, BinaryOperator, Calibration,
Capture, CircuitDefinition, Declaration, Delay, Exchange, Fence, FrameDefinition, Instruction,
Jump, JumpUnless, JumpWhen, Label, Load, Measurement, Move, Pragma, Pulse, RawCapture, Reset,
SetFrequency, SetPhase, SetScale, ShiftFrequency, ShiftPhase, Store, TernaryLogic,
TernaryOperator, UnaryLogic, UnaryOperator, Waveform, WaveformDefinition,
};
use crate::parser::common::parse_variable_qubit;
use crate::parser::instruction::parse_block;
Expand Down Expand Up @@ -57,6 +58,57 @@ pub fn parse_arithmetic(
))
}

/// Parse a logical ternary instruction of the form `addr addr ( addr | number )`.
/// Called using the logical operator itself (such as `EQ`) which should be previously parsed.
pub fn parse_logical_ternary(
operator: TernaryOperator,
input: ParserInput,
) -> ParserResult<Instruction> {
let (input, destination) = common::parse_memory_reference(input)?;
let (input, left) = common::parse_memory_reference(input)?;
let (input, right) = common::parse_ternary_logic_operand(input)?;

Ok((
input,
Instruction::TernaryLogic(TernaryLogic {
operator,
operands: (destination, left, right),
}),
))
}

/// Parse a logical binary instruction of the form `addr ( addr | INT )`.
/// Called using the logical operator itself (such as `AND`) which should be previously parsed.
pub fn parse_logical_binary(
operator: BinaryOperator,
input: ParserInput,
) -> ParserResult<Instruction> {
let (input, left) = common::parse_memory_reference(input)?;
let (input, right) = common::parse_binary_logic_operand(input)?;

Ok((
input,
Instruction::BinaryLogic(BinaryLogic {
operator,
operands: (left, right),
}),
))
}

nilslice marked this conversation as resolved.
Show resolved Hide resolved
/// Parse a logical unary instruction of the form `addr`.
/// Called using the logical operator itself (such as `NOT`) which should be previously parsed.
pub fn parse_logical_unary(
operator: UnaryOperator,
input: ParserInput,
) -> ParserResult<Instruction> {
let (input, operand) = common::parse_memory_reference(input)?;

Ok((
input,
Instruction::UnaryLogic(UnaryLogic { operator, operand }),
))
}

/// Parse the contents of a `DECLARE` instruction.
pub fn parse_declare<'a>(input: ParserInput<'a>) -> ParserResult<'a, Instruction> {
let (input, name) = token!(Identifier(v))(input)?;
Expand Down
55 changes: 50 additions & 5 deletions src/parser/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ use crate::{
expected_token,
expression::Expression,
instruction::{
ArithmeticOperand, AttributeValue, FrameIdentifier, GateModifier, MemoryReference, Qubit,
ScalarType, Vector, WaveformInvocation,
ArithmeticOperand, AttributeValue, BinaryOperand, FrameIdentifier, GateModifier,
MemoryReference, Qubit, ScalarType, TernaryOperand, Vector, WaveformInvocation,
},
parser::lexer::Operator,
token,
Expand Down Expand Up @@ -65,9 +65,54 @@ pub fn parse_arithmetic_operand<'a>(input: ParserInput<'a>) -> ParserResult<'a,
ArithmeticOperand::LiteralInteger(sign * (v as i64))
},
),
map(parse_memory_reference, |f| {
ArithmeticOperand::MemoryReference(f)
}),
map(parse_memory_reference, ArithmeticOperand::MemoryReference),
))(input)
}

/// Parse the operand of a ternary instruction, which may be a literal integer, literal real number, or memory reference.
pub fn parse_ternary_logic_operand<'a>(input: ParserInput<'a>) -> ParserResult<'a, TernaryOperand> {
alt((
map(
tuple((opt(token!(Operator(o))), token!(Float(v)))),
|(op, v)| {
let sign = match op {
None => 1f64,
Some(Operator::Minus) => -1f64,
_ => panic!("Implement this error"), // TODO
};
TernaryOperand::LiteralReal(sign * v)
},
),
map(
tuple((opt(token!(Operator(o))), token!(Integer(v)))),
|(op, v)| {
let sign = match op {
None => 1,
Some(Operator::Minus) => -1,
_ => panic!("Implement this error"), // TODO
};
TernaryOperand::LiteralInteger(sign * (v as i64))
},
),
map(parse_memory_reference, TernaryOperand::MemoryReference),
))(input)
}

/// Parse the operand of a binary logic instruction, which may be a literal integer or memory reference.
pub fn parse_binary_logic_operand<'a>(input: ParserInput<'a>) -> ParserResult<'a, BinaryOperand> {
alt((
map(
tuple((opt(token!(Operator(o))), token!(Integer(v)))),
|(op, v)| {
let sign = match op {
None => 1,
Some(Operator::Minus) => -1,
_ => panic!("Implement this error"), // TODO
};
BinaryOperand::LiteralInteger(sign * (v as i64))
},
),
map(parse_memory_reference, BinaryOperand::MemoryReference),
))(input)
}

Expand Down
Loading