Skip to content

Commit

Permalink
Update: parse ternary, binary, and unary logic (#58)
Browse files Browse the repository at this point in the history
* feat: parse binary logic

* feat: parse unary logic

* chore: remove support for deprecated OR command

* fix: include write memory accesses for logic commands

* chore: rename op -> operator for consistency

* chore: rename LogicOperator -> BinaryOperator to disambiguate future Ternary type

* feat: support ternary logic instructions (#60)

* chore: rename ternary-related identifiers for usage clarity

* chore: fix typo

* chore: additional leftover renaming from ternary to comparison

* chore: add tested instruction to assert message
  • Loading branch information
nilslice authored Jun 7, 2022
1 parent faec656 commit 4fb17a9
Show file tree
Hide file tree
Showing 8 changed files with 517 additions and 44 deletions.
130 changes: 127 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,
}
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 ComparisonOperand {
LiteralInteger(i64),
LiteralReal(f64),
MemoryReference(MemoryReference),
}

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

#[derive(Clone, Debug, PartialEq)]
pub enum ComparisonOperator {
Equal,
GreaterThanOrEqual,
GreaterThan,
LessThanOrEqual,
LessThan,
}

impl fmt::Display for ComparisonOperator {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self {
ComparisonOperator::Equal => write!(f, "EQ"),
ComparisonOperator::GreaterThanOrEqual => write!(f, "GE"),
ComparisonOperator::GreaterThan => write!(f, "GT"),
ComparisonOperator::LessThanOrEqual => write!(f, "LE"),
ComparisonOperator::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 Comparison {
pub operator: ComparisonOperator,
pub operands: (MemoryReference, MemoryReference, ComparisonOperand),
}

#[derive(Clone, Debug, PartialEq)]
pub struct BinaryLogic {
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),
Comparison(Comparison),
BinaryLogic(BinaryLogic),
UnaryLogic(UnaryLogic),
Halt,
Label(Label),
Move(Move),
Expand Down Expand Up @@ -480,6 +585,9 @@ impl From<&Instruction> for InstructionRole {
| Instruction::ShiftPhase(_)
| Instruction::SwapPhases(_) => InstructionRole::RFControl,
Instruction::Arithmetic(_)
| Instruction::Comparison(_)
| 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 @@ -759,7 +867,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 @@ -806,6 +914,19 @@ impl fmt::Display for Instruction {
write!(f, "JUMP-WHEN @{} {}", target, condition)
}
Instruction::Label(Label(label)) => write!(f, "LABEL @{}", label),
Instruction::Comparison(Comparison { operator, operands }) => {
write!(
f,
"{} {} {} {}",
operator, operands.0, operands.1, operands.2
)
}
Instruction::BinaryLogic(BinaryLogic { operator, operands }) => {
write!(f, "{} {} {}", operator, operands.0, operands.1)
}
Instruction::UnaryLogic(UnaryLogic { operator, operand }) => {
write!(f, "{} {}", operator, operand)
}
}
}
}
Expand Down Expand Up @@ -1003,6 +1124,9 @@ impl Instruction {
| Instruction::Pragma(_)
| Instruction::WaveformDefinition(_)
| Instruction::Arithmetic(_)
| Instruction::BinaryLogic(_)
| Instruction::UnaryLogic(_)
| Instruction::Comparison(_)
| Instruction::Halt
| Instruction::Label(_)
| Instruction::Move(_)
Expand Down
62 changes: 57 additions & 5 deletions src/parser/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ use nom::{
};

use crate::instruction::{
Arithmetic, ArithmeticOperand, ArithmeticOperator, Calibration, Capture, CircuitDefinition,
Declaration, Delay, Exchange, Fence, FrameDefinition, Instruction, Jump, JumpUnless, JumpWhen,
Label, Load, MeasureCalibrationDefinition, Measurement, Move, Pragma, Pulse, Qubit, RawCapture,
Reset, SetFrequency, SetPhase, SetScale, ShiftFrequency, ShiftPhase, Store, Waveform,
WaveformDefinition,
Arithmetic, ArithmeticOperand, ArithmeticOperator, BinaryLogic, BinaryOperator, Calibration,
Capture, CircuitDefinition, Comparison, ComparisonOperator, Declaration, Delay, Exchange,
Fence, FrameDefinition, Instruction, Jump, JumpUnless, JumpWhen, Label, Load,
MeasureCalibrationDefinition, Measurement, Move, Pragma, Pulse, Qubit, RawCapture, Reset,
SetFrequency, SetPhase, SetScale, ShiftFrequency, ShiftPhase, Store, 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 comparison instruction of the form `addr addr ( addr | number )`.
/// Called using the comparison operator itself (such as `EQ`) which should be previously parsed.
pub fn parse_comparison(
operator: ComparisonOperator,
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_comparison_operand(input)?;

Ok((
input,
Instruction::Comparison(Comparison {
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),
}),
))
}

/// 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
65 changes: 57 additions & 8 deletions src/parser/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ use crate::{
expected_token,
expression::Expression,
instruction::{
ArithmeticOperand, AttributeValue, FrameIdentifier, GateModifier, MemoryReference, Qubit,
ScalarType, Vector, WaveformInvocation,
ArithmeticOperand, AttributeValue, BinaryOperand, ComparisonOperand, FrameIdentifier,
GateModifier, MemoryReference, Qubit, ScalarType, Vector, WaveformInvocation,
},
parser::lexer::Operator,
token,
Expand All @@ -39,7 +39,8 @@ use super::{
ParserInput, ParserResult,
};

/// Parse the operand of an arithmetic instruction, which may be a literal integer, literal real number, or memory reference.
/// Parse the operand of an arithmetic instruction, which may be a literal integer, literal real
/// number, or memory reference.
pub fn parse_arithmetic_operand<'a>(input: ParserInput<'a>) -> ParserResult<'a, ArithmeticOperand> {
alt((
map(
Expand All @@ -64,9 +65,55 @@ 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 comparison instruction, which may be a literal integer, literal real
/// number, or memory reference.
pub fn parse_comparison_operand<'a>(input: ParserInput<'a>) -> ParserResult<'a, ComparisonOperand> {
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
};
ComparisonOperand::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
};
ComparisonOperand::LiteralInteger(sign * (v as i64))
},
),
map(parse_memory_reference, ComparisonOperand::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 Expand Up @@ -108,7 +155,8 @@ pub fn parse_gate_modifier<'a>(input: ParserInput<'a>) -> ParserResult<'a, GateM
))
}

/// Parse a reference to a memory location, such as `ro[5]`, with optional brackets (i.e, `ro` allowed).
/// Parse a reference to a memory location, such as `ro[5]`, with optional brackets
/// (i.e, `ro` allowed).
pub fn parse_memory_reference<'a>(input: ParserInput<'a>) -> ParserResult<'a, MemoryReference> {
let (input, name) = token!(Identifier(v))(input)?;
let (input, index) = opt(delimited(
Expand All @@ -120,7 +168,8 @@ pub fn parse_memory_reference<'a>(input: ParserInput<'a>) -> ParserResult<'a, Me
Ok((input, MemoryReference { name, index }))
}

/// Parse a reference to a memory location, such as `ro[5]` requiring the brackets (i.e, `ro` disallowed).
/// Parse a reference to a memory location, such as `ro[5]` requiring the brackets
/// (i.e, `ro` disallowed).
pub fn parse_memory_reference_with_brackets<'a>(
input: ParserInput<'a>,
) -> ParserResult<'a, MemoryReference> {
Expand Down
Loading

0 comments on commit 4fb17a9

Please sign in to comment.