diff --git a/ic10emu/src/grammar.rs b/ic10emu/src/grammar.rs index a0d5568..2ee8dca 100644 --- a/ic10emu/src/grammar.rs +++ b/ic10emu/src/grammar.rs @@ -347,11 +347,13 @@ pub enum Operand { RegisterSpec(RegisterSpec), DeviceSpec(DeviceSpec), Number(Number), - LogicType(LogicType), - SlotLogicType(SlotLogicType), - LogicOrSlotLogicType(LogicType, SlotLogicType), - BatchMode(BatchMode), - ReagentMode(ReagentMode), + Type { + logic_type: Option, + slot_logic_type: Option, + batch_mode: Option, + reagent_mode: Option, + identifier: Identifier, + }, Identifier(Identifier), } @@ -368,27 +370,25 @@ impl Operand { target, }) => ic.get_register(indirection, target), Operand::Number(num) => Ok(num.value()), - Operand::LogicType(lt) => lt - .get_str("value") - .map(|val| val.parse::().unwrap() as f64) - .ok_or(interpreter::ICError::TypeValueNotKnown), - Operand::SlotLogicType(slt) => slt - .get_str("value") - .map(|val| val.parse::().unwrap() as f64) - .ok_or(interpreter::ICError::TypeValueNotKnown), - // default to using LogicType when converting to value - Operand::LogicOrSlotLogicType(lt, _) => lt - .get_str("value") - .map(|val| val.parse::().unwrap() as f64) - .ok_or(interpreter::ICError::TypeValueNotKnown), - Operand::BatchMode(bm) => bm - .get_str("value") - .map(|val| val.parse::().unwrap() as f64) - .ok_or(interpreter::ICError::TypeValueNotKnown), - Operand::ReagentMode(rm) => rm - .get_str("value") - .map(|val| val.parse::().unwrap() as f64) - .ok_or(interpreter::ICError::TypeValueNotKnown), + Operand::Type { + logic_type, + slot_logic_type, + batch_mode, + reagent_mode, + identifier: _, + } => { + if let Some(lt) = logic_type { + Ok(lt.get_str("value").unwrap().parse::().unwrap() as f64) + } else if let Some(slt) = slot_logic_type { + Ok(slt.get_str("value").unwrap().parse::().unwrap() as f64) + } else if let Some(bm) = batch_mode { + Ok(bm.get_str("value").unwrap().parse::().unwrap() as f64) + } else if let Some(rm) = reagent_mode { + Ok(rm.get_str("value").unwrap().parse::().unwrap() as f64) + } else { + Err(interpreter::ICError::TypeValueNotKnown) + } + } Operand::Identifier(id) => { Err(interpreter::ICError::UnknownIdentifier(id.name.to_string())) } @@ -502,8 +502,10 @@ impl Operand { index: u32, ) -> Result { match &self { - Operand::LogicType(lt) => Ok(*lt), - Operand::LogicOrSlotLogicType(lt, _slt) => Ok(*lt), + Operand::Type { + logic_type: Some(lt), + .. + } => Ok(*lt), _ => LogicType::try_from(self.as_value(ic, inst, index)?), } } @@ -515,15 +517,47 @@ impl Operand { index: u32, ) -> Result { match &self { - Operand::SlotLogicType(slt) => Ok(*slt), - Operand::LogicOrSlotLogicType(_lt, slt) => Ok(*slt), + Operand::Type { + slot_logic_type: Some(slt), + .. + } => Ok(*slt), _ => SlotLogicType::try_from(self.as_value(ic, inst, index)?), } } + pub fn as_batch_mode( + &self, + ic: &interpreter::IC, + inst: InstructionOp, + index: u32, + ) -> Result { + match &self { + Operand::Type { + batch_mode: Some(bm), + .. + } => Ok(*bm), + _ => BatchMode::try_from(self.as_value(ic, inst, index)?), + } + } + + pub fn as_reagent_mode( + &self, + ic: &interpreter::IC, + inst: InstructionOp, + index: u32, + ) -> Result { + match &self { + Operand::Type { + reagent_mode: Some(rm), + .. + } => Ok(*rm), + _ => ReagentMode::try_from(self.as_value(ic, inst, index)?), + } + } + pub fn translate_alias(&self, ic: &interpreter::IC) -> Self { match &self { - Operand::Identifier(id) => { + Operand::Identifier(id) | Operand::Type { identifier: id, .. } => { if let Some(alias) = ic.aliases.borrow().get(&id.name) { alias.clone() } else if let Some(define) = ic.defines.borrow().get(&id.name) { @@ -798,24 +832,23 @@ impl FromStr for Operand { Ok(Operand::Number(Number::Enum( val.get_str("value").unwrap().parse().unwrap(), ))) - } else if let Ok(lt) = LogicType::from_str(s) { - if let Ok(slt) = SlotLogicType::from_str(s) { - Ok(Operand::LogicOrSlotLogicType(lt, slt)) - } else { - Ok(Operand::LogicType(lt)) - } - } else if let Ok(slt) = SlotLogicType::from_str(s) { - if let Ok(lt) = LogicType::from_str(s) { - Ok(Operand::LogicOrSlotLogicType(lt, slt)) - } else { - Ok(Operand::SlotLogicType(slt)) - } - } else if let Ok(bm) = BatchMode::from_str(s) { - Ok(Operand::BatchMode(bm)) - } else if let Ok(rm) = ReagentMode::from_str(s) { - Ok(Operand::ReagentMode(rm)) } else { - Ok(Operand::Identifier(s.parse::()?)) + let lt = LogicType::from_str(s).ok(); + let slt = SlotLogicType::from_str(s).ok(); + let bm = BatchMode::from_str(s).ok(); + let rm = ReagentMode::from_str(s).ok(); + let identifier = Identifier::from_str(s)?; + if lt.is_some() || slt.is_some() || bm.is_some() || rm.is_some() { + Ok(Operand::Type { + logic_type: lt, + slot_logic_type: slt, + batch_mode: bm, + reagent_mode: rm, + identifier, + }) + } else { + Ok(Operand::Identifier(identifier)) + } } } } @@ -895,11 +928,7 @@ impl Display for Operand { Display::fmt(&number.value(), f) } }, - Operand::LogicType(logic) => Display::fmt(logic, f), - Operand::SlotLogicType(slot_logic) => Display::fmt(slot_logic, f), - Operand::LogicOrSlotLogicType(logic, _) => Display::fmt(logic, f), - Operand::BatchMode(batch_mode) => Display::fmt(batch_mode, f), - Operand::ReagentMode(reagent_mode) => Display::fmt(reagent_mode, f), + Operand::Type { identifier, .. } => Display::fmt(&identifier, f), Operand::Identifier(ident) => Display::fmt(&ident, f), } } @@ -1036,7 +1065,15 @@ mod tests { device: Device::Numbered(0), connection: None, }), - Operand::LogicType(LogicType::Setting), + Operand::Type { + logic_type: Some(LogicType::Setting), + slot_logic_type: None, + batch_mode: None, + reagent_mode: None, + identifier: Identifier { + name: "Setting".to_owned(), + }, + }, Operand::Number(Number::Float(0.0)), ], },),), @@ -1159,7 +1196,15 @@ mod tests { device: Device::Numbered(0), connection: None }), - Operand::LogicOrSlotLogicType(LogicType::On, SlotLogicType::On), + Operand::Type { + logic_type: Some(LogicType::On), + slot_logic_type: Some(SlotLogicType::On), + batch_mode: None, + reagent_mode: None, + identifier: Identifier { + name: "On".to_owned(), + }, + }, Operand::Number(Number::Float(1.0)) ] })), @@ -1232,7 +1277,15 @@ mod tests { }, connection: None, }), - Operand::LogicType(LogicType::RatioWater), + Operand::Type { + logic_type: Some(LogicType::RatioWater), + slot_logic_type: None, + batch_mode: None, + reagent_mode: None, + identifier: Identifier { + name: "RatioWater".to_owned(), + }, + }, ], },),), comment: None, diff --git a/ic10emu/src/interpreter.rs b/ic10emu/src/interpreter.rs index 81bc0ec..475be8c 100644 --- a/ic10emu/src/interpreter.rs +++ b/ic10emu/src/interpreter.rs @@ -2458,7 +2458,7 @@ impl IC { let device = vm.get_device_same_network(this.device, device_id); match device { Some(device) => { - let rm = ReagentMode::try_from(rm.as_value(this, inst, 3)?)?; + let rm = rm.as_reagent_mode(this, inst, 3)?; let name = name.as_value(this, inst, 4)?; let val = device.borrow().get_reagent(&rm, name); this.set_register(indirection, target, val)?; @@ -2477,7 +2477,7 @@ impl IC { } = reg.as_register(this, inst, 1)?; let prefab = prefab.as_value(this, inst, 2)?; let lt = lt.as_logic_type(this, inst, 3)?; - let bm = BatchMode::try_from(bm.as_value(this, inst, 4)?)?; + let bm = bm.as_batch_mode(this, inst, 4)?; let val = vm.get_batch_device_field(this.device, prefab, lt, bm)?; this.set_register(indirection, target, val)?; Ok(()) @@ -2493,7 +2493,7 @@ impl IC { let prefab = prefab.as_value(this, inst, 2)?; let name = name.as_value(this, inst, 3)?; let lt = lt.as_logic_type(this, inst, 4)?; - let bm = BatchMode::try_from(bm.as_value(this, inst, 5)?)?; + let bm = bm.as_batch_mode(this, inst, 5)?; let val = vm.get_batch_name_device_field(this.device, prefab, name, lt, bm)?; this.set_register(indirection, target, val)?; @@ -2511,7 +2511,7 @@ impl IC { let name = name.as_value(this, inst, 3)?; let index = index.as_value(this, inst, 4)?; let slt = slt.as_slot_logic_type(this, inst, 5)?; - let bm = BatchMode::try_from(bm.as_value(this, inst, 6)?)?; + let bm = bm.as_batch_mode(this, inst, 6)?; let val = vm.get_batch_name_device_slot_field( this.device, prefab, @@ -2534,7 +2534,7 @@ impl IC { let prefab = prefab.as_value(this, inst, 2)?; let index = index.as_value(this, inst, 3)?; let slt = slt.as_slot_logic_type(this, inst, 4)?; - let bm = BatchMode::try_from(bm.as_value(this, inst, 5)?)?; + let bm = bm.as_batch_mode(this, inst, 5)?; let val = vm.get_batch_device_slot_field(this.device, prefab, index, slt, bm)?; this.set_register(indirection, target, val)?; @@ -2620,15 +2620,15 @@ mod tests { vm.set_code( ic, r#"lb r0 HASH("ItemActiveVent") On Sum - #lb r1 HASH("ItemActiveVent") On Maximum + lb r1 HASH("ItemActiveVent") On Maximum lb r2 HASH("ItemActiveVent") On Minimum"#, )?; vm.step_ic(ic, false)?; let r0 = ic_chip.get_register(0, 0).unwrap(); assert_eq!(r0, 0.0); vm.step_ic(ic, false)?; - // let r1 = ic_chip.get_register(0, 1).unwrap(); - // assert_eq!(r1, f64::NEG_INFINITY); + let r1 = ic_chip.get_register(0, 1).unwrap(); + assert_eq!(r1, f64::NEG_INFINITY); vm.step_ic(ic, false)?; let r2 = ic_chip.get_register(0, 2).unwrap(); assert_eq!(r2, f64::INFINITY);