implement Display for Instruction

This commit is contained in:
Dan Johnson
2024-04-04 12:50:13 -07:00
parent cee8ddf8fc
commit ff8b039f38

View File

@@ -290,6 +290,17 @@ impl FromStr for Instruction {
}
}
impl Display for Instruction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let i = self.instruction.to_string().to_lowercase();
write!(f, "{}", i)?;
for operand in &self.operands {
write!(f, " {}", operand)?;
}
Ok(())
}
}
fn get_operand_tokens<'a>(
s: &'a str,
tokens_iter: SplitConsecutiveWithIndices<'a>,
@@ -767,6 +778,84 @@ impl FromStr for Operand {
}
}
impl Display for Operand {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Operand::RegisterSpec(RegisterSpec {
indirection,
target,
}) => {
for _ in 0..*indirection {
write!(f, "r")?;
}
match target {
17 => write!(f, "ra"),
16 => write!(f, "sp"),
_ => write!(f, "r{}", target),
}
}
Operand::DeviceSpec(DeviceSpec { device, connection }) => {
match device {
Device::Db => write!(f, "db"),
Device::Numbered(number) => write!(f, "d{}", number),
Device::Indirect {
indirection,
target,
} => {
write!(f, "d")?;
for _ in 0..=*indirection {
write!(f, "r")?;
}
write!(f, "{}", target)
}
}?;
if let Some(connection) = connection {
write!(f, ":{connection}")?;
}
Ok(())
}
Operand::Number(number) => match number {
Number::Float(_) => Display::fmt(&number.value(), f),
Number::Hexadecimal(n) => {
// FIXME: precision loss here, maybe we should track the source i64?
write!(f, "${:x}", *n as i64)
}
Number::Binary(n) => {
// FIXME: precision loss here, maybe we should track the source i64?
write!(f, "%{:b}", *n as i64)
}
Number::Constant(c) => {
dbg!(c);
let (name, _) = CONSTANTS_LOOKUP
.entries()
.find(|(_, &value)| {
*c == value
|| (c.is_nan() && value.is_nan())
|| (c.is_infinite()
&& value.is_infinite()
&& c.is_sign_positive() == value.is_sign_positive())
})
.expect("constant should be in lookup table");
Display::fmt(name, f)
}
Number::String(s) => {
write!(f, r#"HASH("{s}")"#)
}
Number::Enum(_) => {
// TODO: handle better
Display::fmt(&number.value(), f)
}
},
Operand::LogicType(logic) => Display::fmt(logic, f),
Operand::SlotLogicType(slot_logic) => Display::fmt(slot_logic, f),
Operand::BatchMode(batch_mode) => Display::fmt(batch_mode, f),
Operand::ReagentMode(reagent_mode) => Display::fmt(reagent_mode, f),
Operand::Identifier(ident) => Display::fmt(&ident, f),
}
}
}
#[derive(PartialEq, Eq, Debug)]
pub struct Label {
pub id: Identifier,
@@ -840,6 +929,12 @@ impl FromStr for Identifier {
}
}
impl Display for Identifier {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Display::fmt(&self.name, f)
}
}
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub enum Number {
Float(f64),
@@ -1164,4 +1259,40 @@ mod tests {
],
);
}
#[test]
fn test_operand_display() {
#[track_caller]
fn test_roundtrip(s: &str) {
let o: Operand = s.parse().expect("test string should parse with FromStr");
assert_eq!(o.to_string(), s);
}
test_roundtrip("r0");
test_roundtrip("r15");
test_roundtrip("rr4");
test_roundtrip("rrrr4");
test_roundtrip("ra");
test_roundtrip("rra");
test_roundtrip("sp");
test_roundtrip("rsp");
test_roundtrip("Identifier");
test_roundtrip("db");
test_roundtrip("d0");
test_roundtrip("drr0");
test_roundtrip("d0:1");
test_roundtrip("42");
test_roundtrip("1.2345");
test_roundtrip("-1.2345");
test_roundtrip(&LogicType::Pressure.to_string());
test_roundtrip(&SlotLogicType::Occupied.to_string());
test_roundtrip(&BatchMode::Average.to_string());
test_roundtrip(&ReagentMode::Recipe.to_string());
test_roundtrip("pi");
test_roundtrip("pinf");
test_roundtrip("ninf");
test_roundtrip("nan");
test_roundtrip(r#"HASH("StructureFurnace")"#);
test_roundtrip("$abcd");
test_roundtrip("%1001");
}
}