rafactor(vm): end instruction impl
This commit is contained in:
@@ -208,6 +208,14 @@ pub enum ICError {
|
||||
BadGeneratedValueParse(String, String),
|
||||
#[error("IC with id {0} is not sloted into a circuit holder")]
|
||||
NoCircuitHolder(ObjectID),
|
||||
#[error("object {0} is not slot writeable")]
|
||||
NotSlotWriteable(ObjectID),
|
||||
#[error("object {0} does not use reagents ")]
|
||||
NotReagentReadable(ObjectID),
|
||||
#[error("{0} is not a valid number of sleep seconds")]
|
||||
SleepDurationError(f64),
|
||||
#[error("{0} can not be added to {1} ")]
|
||||
SleepAddtionError(time::Duration, time::OffsetDateTime),
|
||||
}
|
||||
|
||||
impl ICError {
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
use core::f64;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
ops::Deref,
|
||||
string::ToString,
|
||||
};
|
||||
use std::{
|
||||
collections::{BTreeMap, HashSet},
|
||||
fmt::Display,
|
||||
@@ -18,22 +13,9 @@ use time::format_description;
|
||||
use crate::{
|
||||
errors::{ICError, LineError},
|
||||
grammar,
|
||||
vm::{
|
||||
enums::{
|
||||
basic_enums::Class as SlotClass,
|
||||
script_enums::{LogicSlotType, LogicType},
|
||||
},
|
||||
instructions::{
|
||||
enums::InstructionOp,
|
||||
operands::{DeviceSpec, Operand, RegisterSpec},
|
||||
Instruction,
|
||||
},
|
||||
VM,
|
||||
},
|
||||
vm::instructions::{enums::InstructionOp, Instruction},
|
||||
};
|
||||
|
||||
use serde_with::serde_as;
|
||||
|
||||
pub mod instructions;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
@@ -42,8 +24,9 @@ pub enum ICState {
|
||||
Running,
|
||||
Yield,
|
||||
Sleep(time::OffsetDateTime, f64),
|
||||
HasCaughtFire,
|
||||
Error(LineError),
|
||||
HasCaughtFire,
|
||||
Ended,
|
||||
}
|
||||
|
||||
impl Display for ICState {
|
||||
@@ -51,7 +34,7 @@ impl Display for ICState {
|
||||
let out = match self {
|
||||
ICState::Start => "Not Run".to_owned(),
|
||||
ICState::Running => "Running".to_owned(),
|
||||
ICState::Yield => "Ic has yielded, Resume on next tick".to_owned(),
|
||||
ICState::Yield => "IC has yielded, Resume on next tick".to_owned(),
|
||||
ICState::Sleep(then, sleep_for) => {
|
||||
let format = format_description::parse("[hour]:[minute]:[second]").unwrap();
|
||||
let resume = *then + time::Duration::new(*sleep_for as i64, 0);
|
||||
@@ -62,88 +45,12 @@ impl Display for ICState {
|
||||
}
|
||||
ICState::Error(err) => format!("{err}"),
|
||||
ICState::HasCaughtFire => "IC has caught fire! this is not a joke!".to_owned(),
|
||||
ICState::Ended => "Program has reached the end of exacution".to_owned(),
|
||||
};
|
||||
write!(f, "{out}")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct IC {
|
||||
pub device: u32,
|
||||
pub id: u32,
|
||||
pub registers: RefCell<[f64; 18]>,
|
||||
/// Instruction Pointer
|
||||
pub ip: Cell<u32>,
|
||||
/// Instruction Count since last yield
|
||||
pub ic: Cell<u16>,
|
||||
pub stack: RefCell<[f64; 512]>,
|
||||
pub aliases: RefCell<BTreeMap<String, Operand>>,
|
||||
pub defines: RefCell<BTreeMap<String, f64>>,
|
||||
pub pins: RefCell<[Option<u32>; 6]>,
|
||||
pub code: RefCell<String>,
|
||||
pub program: RefCell<Program>,
|
||||
pub state: RefCell<ICState>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct FrozenIC {
|
||||
pub device: u32,
|
||||
pub id: u32,
|
||||
pub registers: [f64; 18],
|
||||
/// Instruction Pointer
|
||||
pub ip: u32,
|
||||
/// Instruction Count since last yield
|
||||
pub ic: u16,
|
||||
#[serde_as(as = "[_; 512]")]
|
||||
pub stack: [f64; 512],
|
||||
pub aliases: BTreeMap<String, Operand>,
|
||||
pub defines: BTreeMap<String, f64>,
|
||||
pub pins: [Option<u32>; 6],
|
||||
pub state: ICState,
|
||||
pub code: String,
|
||||
}
|
||||
|
||||
impl<T> From<T> for FrozenIC
|
||||
where
|
||||
T: Deref<Target = IC>,
|
||||
{
|
||||
fn from(ic: T) -> Self {
|
||||
FrozenIC {
|
||||
device: ic.device,
|
||||
id: ic.id,
|
||||
registers: *ic.registers.borrow(),
|
||||
ip: ic.ip.get(),
|
||||
ic: ic.ic.get(),
|
||||
stack: *ic.stack.borrow(),
|
||||
aliases: ic.aliases.borrow().clone(),
|
||||
defines: ic.defines.borrow().clone(),
|
||||
pins: *ic.pins.borrow(),
|
||||
state: ic.state.borrow().clone(),
|
||||
code: ic.code.borrow().clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FrozenIC> for IC {
|
||||
fn from(value: FrozenIC) -> Self {
|
||||
IC {
|
||||
device: value.device,
|
||||
id: value.id,
|
||||
registers: RefCell::new(value.registers),
|
||||
ip: Cell::new(value.ip),
|
||||
ic: Cell::new(value.ic),
|
||||
stack: RefCell::new(value.stack),
|
||||
aliases: RefCell::new(value.aliases),
|
||||
defines: RefCell::new(value.defines),
|
||||
pins: RefCell::new(value.pins),
|
||||
state: RefCell::new(value.state),
|
||||
code: RefCell::new(value.code.clone()),
|
||||
program: RefCell::new(Program::from_code_with_invalid(&value.code)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Program {
|
||||
pub instructions: Vec<Instruction>,
|
||||
@@ -166,6 +73,10 @@ impl Program {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.instructions.len()
|
||||
}
|
||||
|
||||
pub fn try_from_code(code: &str) -> Result<Self, ICError> {
|
||||
let parse_tree = grammar::parse(code)?;
|
||||
let mut labels_set = HashSet::new();
|
||||
@@ -255,570 +166,6 @@ impl Program {
|
||||
}
|
||||
}
|
||||
|
||||
impl IC {
|
||||
pub fn new(id: u32, device: u32) -> Self {
|
||||
IC {
|
||||
device,
|
||||
id,
|
||||
ip: Cell::new(0),
|
||||
ic: Cell::new(0),
|
||||
registers: RefCell::new([0.0; 18]),
|
||||
stack: RefCell::new([0.0; 512]),
|
||||
pins: RefCell::new([None; 6]),
|
||||
program: RefCell::new(Program::new()),
|
||||
code: RefCell::new(String::new()),
|
||||
aliases: RefCell::new(BTreeMap::new()),
|
||||
defines: RefCell::new(BTreeMap::new()),
|
||||
state: RefCell::new(ICState::Start),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset(&self) {
|
||||
self.ip.replace(0);
|
||||
self.ic.replace(0);
|
||||
self.registers.replace([0.0; 18]);
|
||||
self.stack.replace([0.0; 512]);
|
||||
self.aliases.replace(BTreeMap::new());
|
||||
self.defines.replace(BTreeMap::new());
|
||||
self.state.replace(ICState::Start);
|
||||
}
|
||||
|
||||
/// Set program code if it's valid
|
||||
pub fn set_code(&self, code: &str) -> Result<(), ICError> {
|
||||
let prog = Program::try_from_code(code)?;
|
||||
self.program.replace(prog);
|
||||
self.code.replace(code.to_string());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set program code and translate invalid lines to Nop, collecting errors
|
||||
pub fn set_code_invalid(&mut self, code: &str) {
|
||||
let prog = Program::from_code_with_invalid(code);
|
||||
self.program.replace(prog);
|
||||
self.code.replace(code.to_string());
|
||||
}
|
||||
|
||||
pub fn get_real_target(&self, indirection: u32, target: u32) -> Result<f64, ICError> {
|
||||
let mut i = indirection;
|
||||
let mut t = target as f64;
|
||||
while i > 0 {
|
||||
if let Some(new_t) = self.registers.borrow().get(t as usize) {
|
||||
t = *new_t;
|
||||
} else {
|
||||
return Err(ICError::RegisterIndexOutOfRange(t));
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
Ok(t)
|
||||
}
|
||||
|
||||
pub fn get_register(&self, indirection: u32, target: u32) -> Result<f64, ICError> {
|
||||
let t = self.get_real_target(indirection, target)?;
|
||||
self.registers
|
||||
.borrow()
|
||||
.get(t as usize)
|
||||
.ok_or(ICError::RegisterIndexOutOfRange(t))
|
||||
.copied()
|
||||
}
|
||||
|
||||
/// sets a register thorough, recursing through provided indirection, returns value previously
|
||||
pub fn set_register(&self, indirection: u32, target: u32, val: f64) -> Result<f64, ICError> {
|
||||
let t = self.get_real_target(indirection, target)?;
|
||||
let mut registers = self.registers.borrow_mut();
|
||||
let old_val = registers
|
||||
.get(t as usize)
|
||||
.ok_or(ICError::RegisterIndexOutOfRange(t))
|
||||
.copied()?;
|
||||
registers[t as usize] = val;
|
||||
Ok(old_val)
|
||||
}
|
||||
|
||||
/// save ip to 'ra' or register 18
|
||||
fn al(&self) {
|
||||
self.registers.borrow_mut()[17] = self.ip() as f64 + 1.0;
|
||||
}
|
||||
|
||||
pub fn push(&self, val: f64) -> Result<f64, ICError> {
|
||||
let mut registers = self.registers.borrow_mut();
|
||||
let mut stack = self.stack.borrow_mut();
|
||||
let sp = (registers[16].round()) as i32;
|
||||
if sp < 0 {
|
||||
Err(ICError::StackUnderflow)
|
||||
} else if sp >= 512 {
|
||||
Err(ICError::StackOverflow)
|
||||
} else {
|
||||
let last = stack[sp as usize];
|
||||
stack[sp as usize] = val;
|
||||
registers[16] += 1.0;
|
||||
Ok(last)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pop(&self) -> Result<f64, ICError> {
|
||||
let mut registers = self.registers.borrow_mut();
|
||||
registers[16] -= 1.0;
|
||||
let sp = (registers[16].round()) as i32;
|
||||
if sp < 0 {
|
||||
Err(ICError::StackUnderflow)
|
||||
} else if sp >= 512 {
|
||||
Err(ICError::StackOverflow)
|
||||
} else {
|
||||
let last = self.stack.borrow()[sp as usize];
|
||||
Ok(last)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn poke(&self, address: f64, val: f64) -> Result<f64, ICError> {
|
||||
let sp = address.round() as i32;
|
||||
if !(0..512).contains(&sp) {
|
||||
Err(ICError::StackIndexOutOfRange(address))
|
||||
} else {
|
||||
let mut stack = self.stack.borrow_mut();
|
||||
let last = stack[sp as usize];
|
||||
stack[sp as usize] = val;
|
||||
Ok(last)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn peek(&self) -> Result<f64, ICError> {
|
||||
let sp = (self.registers.borrow()[16] - 1.0).round() as i32;
|
||||
if sp < 0 {
|
||||
Err(ICError::StackUnderflow)
|
||||
} else if sp >= 512 {
|
||||
Err(ICError::StackOverflow)
|
||||
} else {
|
||||
let last = self.stack.borrow()[sp as usize];
|
||||
Ok(last)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn peek_addr(&self, addr: f64) -> Result<f64, ICError> {
|
||||
let sp = (addr) as i32;
|
||||
if sp < 0 {
|
||||
Err(ICError::StackUnderflow)
|
||||
} else if sp >= 512 {
|
||||
Err(ICError::StackOverflow)
|
||||
} else {
|
||||
let last = self.stack.borrow()[sp as usize];
|
||||
Ok(last)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn propagate_line_number(&self, vm: &VM) {
|
||||
if let Some(device) = vm.devices.get(&self.device) {
|
||||
let mut device_ref = device.borrow_mut();
|
||||
let _ = device_ref.set_field(LogicType::LineNumber, self.ip.get() as f64, vm, true);
|
||||
if let Some(slot) = device_ref
|
||||
.slots
|
||||
.iter_mut()
|
||||
.find(|slot| slot.typ == SlotClass::ProgrammableChip)
|
||||
{
|
||||
let _ = slot.set_field(LogicSlotType::LineNumber, self.ip.get() as f64, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// processes one line of the contained program
|
||||
pub fn step(&self, vm: &VM, advance_ip_on_err: bool) -> Result<bool, LineError> {
|
||||
// TODO: handle sleep
|
||||
self.state.replace(ICState::Running);
|
||||
let line = self.ip();
|
||||
let result = self.internal_step(vm, advance_ip_on_err);
|
||||
if let Err(error) = result {
|
||||
let error = LineError { error, line };
|
||||
self.state.replace(ICState::Error(error.clone()));
|
||||
Err(error)
|
||||
} else {
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ip(&self) -> u32 {
|
||||
self.ip.get()
|
||||
}
|
||||
|
||||
pub fn set_ip(&self, val: u32) {
|
||||
self.ip.replace(val);
|
||||
}
|
||||
|
||||
fn internal_step(&self, vm: &VM, advance_ip_on_err: bool) -> Result<(), ICError> {
|
||||
use ICError::*;
|
||||
|
||||
let mut next_ip = self.ip() + 1;
|
||||
// XXX: This closure should be replaced with a try block
|
||||
// https://github.com/rust-lang/rust/issues/31436
|
||||
let mut process_op = |this: &Self| -> Result<(), ICError> {
|
||||
use InstructionOp::*;
|
||||
|
||||
// force the program borrow to drop
|
||||
let line = {
|
||||
let prog = this.program.borrow();
|
||||
prog.get_line(this.ip())?.clone()
|
||||
};
|
||||
let operands = &line.operands;
|
||||
let inst = line.instruction;
|
||||
match inst {
|
||||
Nop => Ok(()),
|
||||
Hcf => Ok(()), // TODO
|
||||
Clr => Ok(()), // TODO
|
||||
Clrd => Ok(()), // TODO
|
||||
Label => Ok(()), // NOP
|
||||
|
||||
S => match &operands[..] {
|
||||
[dev, lt, val] => {
|
||||
let (Some(device_id), connection) = dev.as_device(this, inst, 1)? else {
|
||||
return Err(DeviceNotSet);
|
||||
};
|
||||
let lt = lt.as_logic_type(this, inst, 2)?;
|
||||
if CHANNEL_LOGIC_TYPES.contains(<) {
|
||||
let channel = lt.as_channel().unwrap();
|
||||
let Some(connection) = connection else {
|
||||
return Err(MissingConnectionSpecifier);
|
||||
};
|
||||
let network_id = vm
|
||||
.get_device_same_network(this.device, device_id)
|
||||
.map(|device| device.borrow().get_network_id(connection))
|
||||
.unwrap_or(Err(UnknownDeviceID(device_id as f64)))?;
|
||||
let val = val.as_value(this, inst, 3)?;
|
||||
vm.set_network_channel(network_id, channel, val)?;
|
||||
return Ok(());
|
||||
}
|
||||
let device = vm.get_device_same_network(this.device, device_id);
|
||||
match device {
|
||||
Some(device) => {
|
||||
let val = val.as_value(this, inst, 1)?;
|
||||
device.borrow_mut().set_field(lt, val, vm, false)?;
|
||||
vm.set_modified(device_id);
|
||||
Ok(())
|
||||
}
|
||||
None => Err(UnknownDeviceID(device_id as f64)),
|
||||
}
|
||||
}
|
||||
oprs => Err(ICError::mismatch_operands(oprs.len(), 3)),
|
||||
},
|
||||
Sd => match &operands[..] {
|
||||
[dev, lt, val] => {
|
||||
let device_id = dev.as_value(this, inst, 1)?;
|
||||
if device_id >= u16::MAX as f64 || device_id < u16::MIN as f64 {
|
||||
return Err(DeviceIndexOutOfRange(device_id));
|
||||
}
|
||||
let device = vm.get_device_same_network(this.device, device_id as u32);
|
||||
match device {
|
||||
Some(device) => {
|
||||
let lt = lt.as_logic_type(this, inst, 2)?;
|
||||
let val = val.as_value(this, inst, 3)?;
|
||||
device.borrow_mut().set_field(lt, val, vm, false)?;
|
||||
vm.set_modified(device_id as u32);
|
||||
Ok(())
|
||||
}
|
||||
None => Err(UnknownDeviceID(device_id)),
|
||||
}
|
||||
}
|
||||
oprs => Err(ICError::mismatch_operands(oprs.len(), 3)),
|
||||
},
|
||||
Ss => match &operands[..] {
|
||||
[dev, index, slt, val] => {
|
||||
let (Some(device_id), _connection) = dev.as_device(this, inst, 1)? else {
|
||||
return Err(DeviceNotSet);
|
||||
};
|
||||
let device = vm.get_device_same_network(this.device, device_id);
|
||||
match device {
|
||||
Some(device) => {
|
||||
let index = index.as_value(this, inst, 2)?;
|
||||
let slt = slt.as_slot_logic_type(this, inst, 3)?;
|
||||
let val = val.as_value(this, inst, 4)?;
|
||||
device
|
||||
.borrow_mut()
|
||||
.set_slot_field(index, slt, val, vm, false)?;
|
||||
vm.set_modified(device_id);
|
||||
Ok(())
|
||||
}
|
||||
None => Err(UnknownDeviceID(device_id as f64)),
|
||||
}
|
||||
}
|
||||
oprs => Err(ICError::mismatch_operands(oprs.len(), 4)),
|
||||
},
|
||||
Sb => match &operands[..] {
|
||||
[prefab, lt, val] => {
|
||||
let prefab = prefab.as_value(this, inst, 1)?;
|
||||
let lt = lt.as_logic_type(this, inst, 2)?;
|
||||
let val = val.as_value(this, inst, 3)?;
|
||||
vm.set_batch_device_field(this.device, prefab, lt, val, false)?;
|
||||
Ok(())
|
||||
}
|
||||
oprs => Err(ICError::mismatch_operands(oprs.len(), 3)),
|
||||
},
|
||||
Sbs => match &operands[..] {
|
||||
[prefab, index, slt, val] => {
|
||||
let prefab = prefab.as_value(this, inst, 1)?;
|
||||
let index = index.as_value(this, inst, 2)?;
|
||||
let slt = slt.as_slot_logic_type(this, inst, 3)?;
|
||||
let val = val.as_value(this, inst, 4)?;
|
||||
vm.set_batch_device_slot_field(
|
||||
this.device,
|
||||
prefab,
|
||||
index,
|
||||
slt,
|
||||
val,
|
||||
false,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
oprs => Err(ICError::mismatch_operands(oprs.len(), 4)),
|
||||
},
|
||||
Sbn => match &operands[..] {
|
||||
[prefab, name, lt, val] => {
|
||||
let prefab = prefab.as_value(this, inst, 1)?;
|
||||
let name = name.as_value(this, inst, 2)?;
|
||||
let lt = lt.as_logic_type(this, inst, 3)?;
|
||||
let val = val.as_value(this, inst, 4)?;
|
||||
vm.set_batch_name_device_field(this.device, prefab, name, lt, val, false)?;
|
||||
Ok(())
|
||||
}
|
||||
oprs => Err(ICError::mismatch_operands(oprs.len(), 4)),
|
||||
},
|
||||
|
||||
L => match &operands[..] {
|
||||
[reg, dev, lt] => {
|
||||
let RegisterSpec {
|
||||
indirection,
|
||||
target,
|
||||
} = reg.as_register(this, inst, 1)?;
|
||||
let (Some(device_id), connection) = dev.as_device(this, inst, 2)? else {
|
||||
return Err(DeviceNotSet);
|
||||
};
|
||||
let lt = lt.as_logic_type(this, inst, 3)?;
|
||||
if CHANNEL_LOGIC_TYPES.contains(<) {
|
||||
let channel = lt.as_channel().unwrap();
|
||||
let Some(connection) = connection else {
|
||||
return Err(MissingConnectionSpecifier);
|
||||
};
|
||||
let network_id = vm
|
||||
.get_device_same_network(this.device, device_id)
|
||||
.map(|device| device.borrow().get_network_id(connection))
|
||||
.unwrap_or(Err(UnknownDeviceID(device_id as f64)))?;
|
||||
let val = vm.get_network_channel(network_id, channel)?;
|
||||
this.set_register(indirection, target, val)?;
|
||||
return Ok(());
|
||||
}
|
||||
if lt == LogicType::LineNumber && this.device == device_id {
|
||||
// HACK: we can't use device.get_field as that will try to reborrow our
|
||||
// ic which will panic
|
||||
this.set_register(indirection, target, this.ip() as f64)?;
|
||||
Ok(())
|
||||
} else {
|
||||
let device = vm.get_device_same_network(this.device, device_id);
|
||||
match device {
|
||||
Some(device) => {
|
||||
let val = device.borrow().get_field(lt, vm)?;
|
||||
this.set_register(indirection, target, val)?;
|
||||
Ok(())
|
||||
}
|
||||
None => Err(UnknownDeviceID(device_id as f64)),
|
||||
}
|
||||
}
|
||||
}
|
||||
oprs => Err(ICError::mismatch_operands(oprs.len(), 3)),
|
||||
},
|
||||
Ld => match &operands[..] {
|
||||
[reg, dev, lt] => {
|
||||
let RegisterSpec {
|
||||
indirection,
|
||||
target,
|
||||
} = reg.as_register(this, inst, 1)?;
|
||||
let device_id = dev.as_value(this, inst, 2)?;
|
||||
if device_id >= u16::MAX as f64 || device_id < u16::MIN as f64 {
|
||||
return Err(DeviceIndexOutOfRange(device_id));
|
||||
}
|
||||
let lt = lt.as_logic_type(this, inst, 3)?;
|
||||
if lt == LogicType::LineNumber && this.device == device_id as u32 {
|
||||
// HACK: we can't use device.get_field as that will try to reborrow our
|
||||
// ic which will panic
|
||||
this.set_register(indirection, target, this.ip() as f64)?;
|
||||
Ok(())
|
||||
} else {
|
||||
let device = vm.get_device_same_network(this.device, device_id as u32);
|
||||
match device {
|
||||
Some(device) => {
|
||||
let val = device.borrow().get_field(lt, vm)?;
|
||||
this.set_register(indirection, target, val)?;
|
||||
Ok(())
|
||||
}
|
||||
None => Err(UnknownDeviceID(device_id)),
|
||||
}
|
||||
}
|
||||
}
|
||||
oprs => Err(ICError::mismatch_operands(oprs.len(), 3)),
|
||||
},
|
||||
Ls => match &operands[..] {
|
||||
[reg, dev, index, slt] => {
|
||||
let RegisterSpec {
|
||||
indirection,
|
||||
target,
|
||||
} = reg.as_register(this, inst, 1)?;
|
||||
let (Some(device_id), _connection) = dev.as_device(this, inst, 2)? else {
|
||||
return Err(DeviceNotSet);
|
||||
};
|
||||
let slt = slt.as_slot_logic_type(this, inst, 4)?;
|
||||
if slt == LogicSlotType::LineNumber && this.device == device_id {
|
||||
// HACK: we can't use device.get_slot_field as that will try to reborrow our
|
||||
// ic which will panic
|
||||
this.set_register(indirection, target, this.ip() as f64)?;
|
||||
Ok(())
|
||||
} else {
|
||||
let device = vm.get_device_same_network(this.device, device_id);
|
||||
match device {
|
||||
Some(device) => {
|
||||
let index = index.as_value(this, inst, 3)?;
|
||||
let val = device.borrow().get_slot_field(index, slt, vm)?;
|
||||
this.set_register(indirection, target, val)?;
|
||||
Ok(())
|
||||
}
|
||||
None => Err(UnknownDeviceID(device_id as f64)),
|
||||
}
|
||||
}
|
||||
}
|
||||
oprs => Err(ICError::mismatch_operands(oprs.len(), 4)),
|
||||
},
|
||||
Lr => match &operands[..] {
|
||||
[reg, dev, rm, name] => {
|
||||
let RegisterSpec {
|
||||
indirection,
|
||||
target,
|
||||
} = reg.as_register(this, inst, 1)?;
|
||||
let (Some(device_id), _connection) = dev.as_device(this, inst, 2)? else {
|
||||
return Err(DeviceNotSet);
|
||||
};
|
||||
let device = vm.get_device_same_network(this.device, device_id);
|
||||
match device {
|
||||
Some(device) => {
|
||||
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)?;
|
||||
Ok(())
|
||||
}
|
||||
None => Err(UnknownDeviceID(device_id as f64)),
|
||||
}
|
||||
}
|
||||
oprs => Err(ICError::mismatch_operands(oprs.len(), 4)),
|
||||
},
|
||||
Lb => match &operands[..] {
|
||||
[reg, prefab, lt, bm] => {
|
||||
let RegisterSpec {
|
||||
indirection,
|
||||
target,
|
||||
} = 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 = 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(())
|
||||
}
|
||||
oprs => Err(ICError::mismatch_operands(oprs.len(), 4)),
|
||||
},
|
||||
Lbn => match &operands[..] {
|
||||
[reg, prefab, name, lt, bm] => {
|
||||
let RegisterSpec {
|
||||
indirection,
|
||||
target,
|
||||
} = reg.as_register(this, inst, 1)?;
|
||||
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 = 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)?;
|
||||
Ok(())
|
||||
}
|
||||
oprs => Err(ICError::mismatch_operands(oprs.len(), 5)),
|
||||
},
|
||||
Lbns => match &operands[..] {
|
||||
[reg, prefab, name, index, slt, bm] => {
|
||||
let RegisterSpec {
|
||||
indirection,
|
||||
target,
|
||||
} = reg.as_register(this, inst, 1)?;
|
||||
let prefab = prefab.as_value(this, inst, 2)?;
|
||||
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 = bm.as_batch_mode(this, inst, 6)?;
|
||||
let val = vm.get_batch_name_device_slot_field(
|
||||
this.device,
|
||||
prefab,
|
||||
name,
|
||||
index,
|
||||
slt,
|
||||
bm,
|
||||
)?;
|
||||
this.set_register(indirection, target, val)?;
|
||||
Ok(())
|
||||
}
|
||||
oprs => Err(ICError::mismatch_operands(oprs.len(), 6)),
|
||||
},
|
||||
Lbs => match &operands[..] {
|
||||
[reg, prefab, index, slt, bm] => {
|
||||
let RegisterSpec {
|
||||
indirection,
|
||||
target,
|
||||
} = reg.as_register(this, inst, 1)?;
|
||||
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 = 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)?;
|
||||
Ok(())
|
||||
}
|
||||
oprs => Err(ICError::mismatch_operands(oprs.len(), 5)),
|
||||
},
|
||||
}
|
||||
};
|
||||
let result = process_op(self);
|
||||
if result.is_ok() || advance_ip_on_err {
|
||||
self.ic.set(self.ic.get() + 1);
|
||||
self.set_ip(next_ip);
|
||||
self.propagate_line_number(vm);
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
const CHANNEL_LOGIC_TYPES: [LogicType; 8] = [
|
||||
LogicType::Channel0,
|
||||
LogicType::Channel1,
|
||||
LogicType::Channel2,
|
||||
LogicType::Channel3,
|
||||
LogicType::Channel4,
|
||||
LogicType::Channel5,
|
||||
LogicType::Channel6,
|
||||
LogicType::Channel7,
|
||||
];
|
||||
|
||||
trait LogicTypeExt {
|
||||
fn as_channel(&self) -> Option<usize>;
|
||||
}
|
||||
impl LogicTypeExt for LogicType {
|
||||
fn as_channel(&self) -> Option<usize> {
|
||||
match self {
|
||||
LogicType::Channel0 => Some(0),
|
||||
LogicType::Channel1 => Some(1),
|
||||
LogicType::Channel2 => Some(2),
|
||||
LogicType::Channel3 => Some(3),
|
||||
LogicType::Channel4 => Some(4),
|
||||
LogicType::Channel5 => Some(5),
|
||||
LogicType::Channel6 => Some(6),
|
||||
LogicType::Channel7 => Some(7),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn f64_to_i64(f: f64, signed: bool) -> i64 {
|
||||
let mut num: i64 = (f % (1i64 << 53) as f64) as i64;
|
||||
if !signed {
|
||||
@@ -838,7 +185,7 @@ pub fn i64_to_f64(i: i64) -> f64 {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::errors::VMError;
|
||||
use crate::{errors::VMError, vm::VM};
|
||||
|
||||
use super::*;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::{
|
||||
errors::ICError,
|
||||
interpreter::{i64_to_f64, ICState},
|
||||
vm::{
|
||||
enums::script_enums::LogicReagentMode,
|
||||
instructions::{
|
||||
operands::{InstOperand, RegisterSpec},
|
||||
traits::*,
|
||||
@@ -1967,15 +1968,14 @@ impl<T: IC10Marker> GetInstruction for T {
|
||||
} = r.as_register(self)?;
|
||||
let address = address.as_value(self)?;
|
||||
let (device, connection) = d.as_device(self)?;
|
||||
let Some(logicable) = self
|
||||
let logicable = self
|
||||
.get_circuit_holder()
|
||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||
.get_logicable_from_index(device, connection) else {
|
||||
return Err(ICError::DeviceNotSet);
|
||||
};
|
||||
let Some(memory) = logicable.as_memory_readable() else {
|
||||
return Err(MemoryError::NotReadable.into());
|
||||
};
|
||||
.get_logicable_from_index(device, connection)
|
||||
.ok_or(ICError::DeviceNotSet)?;
|
||||
let memory = logicable
|
||||
.as_memory_readable()
|
||||
.ok_or(MemoryError::NotReadable)?;
|
||||
self.set_register(indirection, target, memory.get_memory(address as i32)?)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -1995,15 +1995,14 @@ impl<T: IC10Marker> GetdInstruction for T {
|
||||
} = r.as_register(self)?;
|
||||
let id = id.as_value(self)?;
|
||||
let address = address.as_value(self)?;
|
||||
let Some(logicable) = self
|
||||
let logicable = self
|
||||
.get_circuit_holder()
|
||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||
.get_logicable_from_id(id as ObjectID, None) else {
|
||||
return Err(ICError::UnknownDeviceId(id));
|
||||
};
|
||||
let Some(memory) = logicable.as_memory_readable() else {
|
||||
return Err(MemoryError::NotReadable.into());
|
||||
};
|
||||
.get_logicable_from_id(id as ObjectID, None)
|
||||
.ok_or(ICError::DeviceNotSet)?;
|
||||
let memory = logicable
|
||||
.as_memory_readable()
|
||||
.ok_or(MemoryError::NotReadable)?;
|
||||
self.set_register(indirection, target, memory.get_memory(address as i32)?)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -2020,15 +2019,14 @@ impl<T: IC10Marker> PutInstruction for T {
|
||||
let (device, connection) = d.as_device(self)?;
|
||||
let address = address.as_value(self)?;
|
||||
let value = value.as_value(self)?;
|
||||
let Some(logicable) = self
|
||||
let logicable = self
|
||||
.get_circuit_holder()
|
||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||
.get_logicable_from_index_mut(device, connection) else {
|
||||
return Err(ICError::DeviceNotSet);
|
||||
};
|
||||
let Some(memory) = logicable.as_memory_writable() else {
|
||||
return Err(MemoryError::NotWriteable.into());
|
||||
};
|
||||
.get_logicable_from_index_mut(device, connection)
|
||||
.ok_or(ICError::DeviceNotSet)?;
|
||||
let memory = logicable
|
||||
.as_memory_writable()
|
||||
.ok_or(MemoryError::NotWriteable)?;
|
||||
memory.set_memory(address as i32, value)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -2045,15 +2043,14 @@ impl<T: IC10Marker> PutdInstruction for T {
|
||||
let id = id.as_value(self)?;
|
||||
let address = address.as_value(self)?;
|
||||
let value = value.as_value(self)?;
|
||||
let Some(logicable) = self
|
||||
let logicable = self
|
||||
.get_circuit_holder()
|
||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||
.get_logicable_from_id_mut(id as ObjectID, None) else {
|
||||
return Err(ICError::DeviceNotSet);
|
||||
};
|
||||
let Some(memory) = logicable.as_memory_writable() else {
|
||||
return Err(MemoryError::NotWriteable.into());
|
||||
};
|
||||
.get_logicable_from_id_mut(id as ObjectID, None)
|
||||
.ok_or(ICError::DeviceNotSet)?;
|
||||
let memory = logicable
|
||||
.as_memory_writable()
|
||||
.ok_or(MemoryError::NotWriteable)?;
|
||||
memory.set_memory(address as i32, value)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -2061,202 +2058,463 @@ impl<T: IC10Marker> PutdInstruction for T {
|
||||
|
||||
impl<T: IC10Marker> ClrInstruction for T {
|
||||
/// clr d?
|
||||
fn execute_inner(&mut self, d: &InstOperand) -> Result<(), ICError> {
|
||||
fn execute_inner(&mut self, d: &InstOperand) -> Result<(), ICError> {
|
||||
let (device, connection) = d.as_device(self)?;
|
||||
let Some(logicable) = self
|
||||
let logicable = self
|
||||
.get_circuit_holder()
|
||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||
.get_logicable_from_index_mut(device, connection) else {
|
||||
return Err(ICError::DeviceNotSet);
|
||||
};
|
||||
let Some(memory) = logicable.as_memory_writable() else {
|
||||
return Err(MemoryError::NotWriteable.into());
|
||||
};
|
||||
.get_logicable_from_index_mut(device, connection)
|
||||
.ok_or(ICError::DeviceNotSet)?;
|
||||
let memory = logicable
|
||||
.as_memory_writable()
|
||||
.ok_or(MemoryError::NotWriteable)?;
|
||||
memory.clear_memory()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl<T: IC10Marker> ClrdInstruction for T {
|
||||
/// clrd id(r?|num)
|
||||
fn execute_inner(&mut self, id: &InstOperand) -> Result<(), ICError> {
|
||||
fn execute_inner(&mut self, id: &InstOperand) -> Result<(), ICError> {
|
||||
let id = id.as_value(self)?;
|
||||
let Some(logicable) = self
|
||||
let logicable = self
|
||||
.get_circuit_holder()
|
||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||
.get_logicable_from_id_mut(id as ObjectID, None) else {
|
||||
return Err(ICError::DeviceNotSet);
|
||||
};
|
||||
let Some(memory) = logicable.as_memory_writable() else {
|
||||
return Err(MemoryError::NotWriteable.into());
|
||||
};
|
||||
.get_logicable_from_id_mut(id as ObjectID, None)
|
||||
.ok_or(ICError::DeviceNotSet)?;
|
||||
let memory = logicable
|
||||
.as_memory_writable()
|
||||
.ok_or(MemoryError::NotWriteable)?;
|
||||
memory.clear_memory()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// impl<T: IC10Marker> HcfInstruction for T {
|
||||
// /// hcf
|
||||
// fn execute_inner(&mut self, vm: &VM) -> Result<(), ICError>;
|
||||
// }
|
||||
// impl<T: IC10Marker> LInstruction for T {
|
||||
// /// l r? d? logicType
|
||||
// fn execute_inner(
|
||||
// &mut self,
|
||||
//
|
||||
// r: &InstOperand,
|
||||
// d: &InstOperand,
|
||||
// logic_type: &InstOperand,
|
||||
// ) -> Result<(), ICError>;
|
||||
// }
|
||||
// impl<T: IC10Marker> LabelInstruction for T {
|
||||
// /// label d? str
|
||||
// fn execute_inner(&mut self, d: &InstOperand, str: &InstOperand) -> Result<(), ICError>;
|
||||
// }
|
||||
// impl<T: IC10Marker> LbInstruction for T {
|
||||
// /// lb r? deviceHash logicType batchMode
|
||||
// fn execute_inner(
|
||||
// &mut self,
|
||||
//
|
||||
// r: &InstOperand,
|
||||
// device_hash: &InstOperand,
|
||||
// logic_type: &InstOperand,
|
||||
// batch_mode: &InstOperand,
|
||||
// ) -> Result<(), ICError>;
|
||||
// }
|
||||
// impl<T: IC10Marker> LbnInstruction for T {
|
||||
// /// lbn r? deviceHash nameHash logicType batchMode
|
||||
// fn execute_inner(
|
||||
// &mut self,
|
||||
//
|
||||
// r: &InstOperand,
|
||||
// device_hash: &InstOperand,
|
||||
// name_hash: &InstOperand,
|
||||
// logic_type: &InstOperand,
|
||||
// batch_mode: &InstOperand,
|
||||
// ) -> Result<(), ICError>;
|
||||
// }
|
||||
// impl<T: IC10Marker> LbnsInstruction for T {
|
||||
// /// lbns r? deviceHash nameHash slotIndex logicSlotType batchMode
|
||||
// fn execute_inner(
|
||||
// &mut self,
|
||||
//
|
||||
// r: &InstOperand,
|
||||
// device_hash: &InstOperand,
|
||||
// name_hash: &InstOperand,
|
||||
// slot_index: &InstOperand,
|
||||
// logic_slot_type: &InstOperand,
|
||||
// batch_mode: &InstOperand,
|
||||
// ) -> Result<(), ICError>;
|
||||
// }
|
||||
// impl<T: IC10Marker> LbsInstruction for T {
|
||||
// /// lbs r? deviceHash slotIndex logicSlotType batchMode
|
||||
// fn execute_inner(
|
||||
// &mut self,
|
||||
//
|
||||
// r: &InstOperand,
|
||||
// device_hash: &InstOperand,
|
||||
// slot_index: &InstOperand,
|
||||
// logic_slot_type: &InstOperand,
|
||||
// batch_mode: &InstOperand,
|
||||
// ) -> Result<(), ICError>;
|
||||
// }
|
||||
// impl<T: IC10Marker> LdInstruction for T {
|
||||
// /// ld r? id(r?|num) logicType
|
||||
// fn execute_inner(
|
||||
// &mut self,
|
||||
//
|
||||
// r: &InstOperand,
|
||||
// id: &InstOperand,
|
||||
// logic_type: &InstOperand,
|
||||
// ) -> Result<(), ICError>;
|
||||
// }
|
||||
// impl<T: IC10Marker> LogInstruction for T {
|
||||
// /// log r? a(r?|num)
|
||||
// fn execute_inner(&mut self, r: &InstOperand, a: &InstOperand) -> Result<(), ICError>;
|
||||
// }
|
||||
// impl<T: IC10Marker> LrInstruction for T {
|
||||
// /// lr r? d? reagentMode int
|
||||
// fn execute_inner(
|
||||
// &mut self,
|
||||
//
|
||||
// r: &InstOperand,
|
||||
// d: &InstOperand,
|
||||
// reagent_mode: &InstOperand,
|
||||
// int: &InstOperand,
|
||||
// ) -> Result<(), ICError>;
|
||||
// }
|
||||
// impl<T: IC10Marker> LsInstruction for T {
|
||||
// /// ls r? d? slotIndex logicSlotType
|
||||
// fn execute_inner(
|
||||
// &mut self,
|
||||
//
|
||||
// r: &InstOperand,
|
||||
// d: &InstOperand,
|
||||
// slot_index: &InstOperand,
|
||||
// logic_slot_type: &InstOperand,
|
||||
// ) -> Result<(), ICError>;
|
||||
// }
|
||||
// impl<T: IC10Marker> SInstruction for T {
|
||||
// /// s d? logicType r?
|
||||
// fn execute_inner(
|
||||
// &mut self,
|
||||
//
|
||||
// d: &InstOperand,
|
||||
// logic_type: &InstOperand,
|
||||
// r: &InstOperand,
|
||||
// ) -> Result<(), ICError>;
|
||||
// }
|
||||
// impl<T: IC10Marker> SbInstruction for T {
|
||||
// /// sb deviceHash logicType r?
|
||||
// fn execute_inner(
|
||||
// &mut self,
|
||||
//
|
||||
// device_hash: &InstOperand,
|
||||
// logic_type: &InstOperand,
|
||||
// r: &InstOperand,
|
||||
// ) -> Result<(), ICError>;
|
||||
// }
|
||||
// impl<T: IC10Marker> SbnInstruction for T {
|
||||
// /// sbn deviceHash nameHash logicType r?
|
||||
// fn execute_inner(
|
||||
// &mut self,
|
||||
//
|
||||
// device_hash: &InstOperand,
|
||||
// name_hash: &InstOperand,
|
||||
// logic_type: &InstOperand,
|
||||
// r: &InstOperand,
|
||||
// ) -> Result<(), ICError>;
|
||||
// }
|
||||
// impl<T: IC10Marker> SbsInstruction for T {
|
||||
// /// sbs deviceHash slotIndex logicSlotType r?
|
||||
// fn execute_inner(
|
||||
// &mut self,
|
||||
//
|
||||
// device_hash: &InstOperand,
|
||||
// slot_index: &InstOperand,
|
||||
// logic_slot_type: &InstOperand,
|
||||
// r: &InstOperand,
|
||||
// ) -> Result<(), ICError>;
|
||||
// }
|
||||
// impl<T: IC10Marker> SdInstruction for T {
|
||||
// /// sd id(r?|num) logicType r?
|
||||
// fn execute_inner(
|
||||
// &mut self,
|
||||
//
|
||||
// id: &InstOperand,
|
||||
// logic_type: &InstOperand,
|
||||
// r: &InstOperand,
|
||||
// ) -> Result<(), ICError>;
|
||||
// }
|
||||
// impl<T: IC10Marker> SsInstruction for T {
|
||||
// /// ss d? slotIndex logicSlotType r?
|
||||
// fn execute_inner(
|
||||
// &mut self,
|
||||
//
|
||||
// d: &InstOperand,
|
||||
// slot_index: &InstOperand,
|
||||
// logic_slot_type: &InstOperand,
|
||||
// r: &InstOperand,
|
||||
// ) -> Result<(), ICError>;
|
||||
// }
|
||||
//
|
||||
impl<T: IC10Marker> SInstruction for T {
|
||||
/// s d? logicType r?
|
||||
fn execute_inner(
|
||||
&mut self,
|
||||
d: &InstOperand,
|
||||
logic_type: &InstOperand,
|
||||
r: &InstOperand,
|
||||
) -> Result<(), ICError> {
|
||||
let (device, connection) = d.as_device(self)?;
|
||||
let logic_type = logic_type.as_logic_type(self)?;
|
||||
let val = r.as_value(self)?;
|
||||
let logicable = self
|
||||
.get_circuit_holder()
|
||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||
.get_logicable_from_index_mut(device, connection)
|
||||
.ok_or(ICError::DeviceNotSet)?;
|
||||
logicable.set_logic(logic_type, val, false)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IC10Marker> SdInstruction for T {
|
||||
/// sd id(r?|num) logicType r?
|
||||
fn execute_inner(
|
||||
&mut self,
|
||||
id: &InstOperand,
|
||||
logic_type: &InstOperand,
|
||||
r: &InstOperand,
|
||||
) -> Result<(), ICError> {
|
||||
let id = id.as_value(self)?;
|
||||
let logic_type = logic_type.as_logic_type(self)?;
|
||||
let val = r.as_value(self)?;
|
||||
let logicable = self
|
||||
.get_circuit_holder()
|
||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||
.get_logicable_from_id_mut(id as ObjectID, None)
|
||||
.ok_or(ICError::DeviceNotSet)?;
|
||||
logicable.set_logic(logic_type, val, false)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IC10Marker> SsInstruction for T {
|
||||
/// ss d? slotIndex logicSlotType r?
|
||||
fn execute_inner(
|
||||
&mut self,
|
||||
d: &InstOperand,
|
||||
slot_index: &InstOperand,
|
||||
logic_slot_type: &InstOperand,
|
||||
r: &InstOperand,
|
||||
) -> Result<(), ICError> {
|
||||
let (device, connection) = d.as_device(self)?;
|
||||
let slot_index = slot_index.as_value(self)?;
|
||||
let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?;
|
||||
let val = r.as_value(self)?;
|
||||
let logicable = self
|
||||
.get_circuit_holder()
|
||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||
.get_logicable_from_index_mut(device, connection)
|
||||
.ok_or(ICError::DeviceNotSet)?;
|
||||
let device = logicable
|
||||
.as_mut_device()
|
||||
.ok_or(ICError::NotSlotWriteable(logicable.get_id()))?;
|
||||
device.set_slot_logic(logic_slot_type, slot_index, val, false)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IC10Marker> SbInstruction for T {
|
||||
/// sb deviceHash logicType r?
|
||||
fn execute_inner(
|
||||
&mut self,
|
||||
|
||||
device_hash: &InstOperand,
|
||||
logic_type: &InstOperand,
|
||||
r: &InstOperand,
|
||||
) -> Result<(), ICError> {
|
||||
let prefab = device_hash.as_value(self)?;
|
||||
let logic_type = logic_type.as_logic_type(self)?;
|
||||
let val = r.as_value(self)?;
|
||||
self.get_vm()
|
||||
.set_batch_device_field(self.get_id(), prefab, logic_type, val, false)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IC10Marker> SbsInstruction for T {
|
||||
/// sbs deviceHash slotIndex logicSlotType r?
|
||||
fn execute_inner(
|
||||
&mut self,
|
||||
|
||||
device_hash: &InstOperand,
|
||||
slot_index: &InstOperand,
|
||||
logic_slot_type: &InstOperand,
|
||||
r: &InstOperand,
|
||||
) -> Result<(), ICError> {
|
||||
let prefab = device_hash.as_value(self)?;
|
||||
let slot_index = slot_index.as_value(self)?;
|
||||
let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?;
|
||||
let val = r.as_value(self)?;
|
||||
self.get_vm().set_batch_device_slot_field(
|
||||
self.get_id(),
|
||||
prefab,
|
||||
slot_index,
|
||||
logic_slot_type,
|
||||
val,
|
||||
false,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IC10Marker> SbnInstruction for T {
|
||||
/// sbn deviceHash nameHash logicType r?
|
||||
fn execute_inner(
|
||||
&mut self,
|
||||
|
||||
device_hash: &InstOperand,
|
||||
name_hash: &InstOperand,
|
||||
logic_type: &InstOperand,
|
||||
r: &InstOperand,
|
||||
) -> Result<(), ICError> {
|
||||
let prefab = device_hash.as_value(self)?;
|
||||
let name = name_hash.as_value(self)?;
|
||||
let logic_type = logic_type.as_logic_type(self)?;
|
||||
let val = r.as_value(self)?;
|
||||
self.get_vm().set_batch_name_device_field(
|
||||
self.get_id(),
|
||||
prefab,
|
||||
name,
|
||||
logic_type,
|
||||
val,
|
||||
false,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IC10Marker> LInstruction for T {
|
||||
/// l r? d? logicType
|
||||
fn execute_inner(
|
||||
&mut self,
|
||||
|
||||
r: &InstOperand,
|
||||
d: &InstOperand,
|
||||
logic_type: &InstOperand,
|
||||
) -> Result<(), ICError> {
|
||||
let RegisterSpec {
|
||||
indirection,
|
||||
target,
|
||||
} = r.as_register(self)?;
|
||||
let (device, connection) = d.as_device(self)?;
|
||||
let logic_type = logic_type.as_logic_type(self)?;
|
||||
let logicable = self
|
||||
.get_circuit_holder()
|
||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||
.get_logicable_from_index(device, connection)
|
||||
.ok_or(ICError::DeviceNotSet)?;
|
||||
self.set_register(indirection, target, logicable.get_logic(logic_type)?)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IC10Marker> LdInstruction for T {
|
||||
/// ld r? id(r?|num) logicType
|
||||
fn execute_inner(
|
||||
&mut self,
|
||||
r: &InstOperand,
|
||||
id: &InstOperand,
|
||||
logic_type: &InstOperand,
|
||||
) -> Result<(), ICError> {
|
||||
let RegisterSpec {
|
||||
indirection,
|
||||
target,
|
||||
} = r.as_register(self)?;
|
||||
let id = id.as_value(self)?;
|
||||
let logic_type = logic_type.as_logic_type(self)?;
|
||||
let logicable = self
|
||||
.get_circuit_holder()
|
||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||
.get_logicable_from_id(id as ObjectID, None)
|
||||
.ok_or(ICError::DeviceNotSet)?;
|
||||
self.set_register(indirection, target, logicable.get_logic(logic_type)?)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IC10Marker> LsInstruction for T {
|
||||
/// ls r? d? slotIndex logicSlotType
|
||||
fn execute_inner(
|
||||
&mut self,
|
||||
r: &InstOperand,
|
||||
d: &InstOperand,
|
||||
slot_index: &InstOperand,
|
||||
logic_slot_type: &InstOperand,
|
||||
) -> Result<(), ICError> {
|
||||
let RegisterSpec {
|
||||
indirection,
|
||||
target,
|
||||
} = r.as_register(self)?;
|
||||
let (device, connection) = d.as_device(self)?;
|
||||
let slot_index = slot_index.as_value(self)?;
|
||||
let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?;
|
||||
let logicable = self
|
||||
.get_circuit_holder()
|
||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||
.get_logicable_from_index(device, connection)
|
||||
.ok_or(ICError::DeviceNotSet)?;
|
||||
self.set_register(
|
||||
indirection,
|
||||
target,
|
||||
logicable.get_slot_logic(logic_slot_type, slot_index)?,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IC10Marker> LrInstruction for T {
|
||||
/// lr r? d? reagentMode int
|
||||
fn execute_inner(
|
||||
&mut self,
|
||||
r: &InstOperand,
|
||||
d: &InstOperand,
|
||||
reagent_mode: &InstOperand,
|
||||
int: &InstOperand,
|
||||
) -> Result<(), ICError> {
|
||||
let RegisterSpec {
|
||||
indirection,
|
||||
target,
|
||||
} = r.as_register(self)?;
|
||||
let (device, connection) = d.as_device(self)?;
|
||||
let reagent_mode = reagent_mode.as_reagent_mode(self)?;
|
||||
let int = int.as_value(self)?;
|
||||
let logicable = self
|
||||
.get_circuit_holder()
|
||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||
.get_logicable_from_index(device, connection)
|
||||
.ok_or(ICError::DeviceNotSet)?;
|
||||
|
||||
let result = match reagent_mode {
|
||||
LogicReagentMode::Contents => {
|
||||
let device = logicable
|
||||
.as_device()
|
||||
.ok_or(ICError::NotReagentReadable(logicable.get_id()))?;
|
||||
device
|
||||
.get_reagents()
|
||||
.iter()
|
||||
.find(|(hash, _)| *hash as f64 == int)
|
||||
.map(|(_, quantity)| *quantity)
|
||||
.unwrap_or(0.0)
|
||||
}
|
||||
LogicReagentMode::TotalContents => {
|
||||
let device = logicable
|
||||
.as_device()
|
||||
.ok_or(ICError::NotReagentReadable(logicable.get_id()))?;
|
||||
device
|
||||
.get_reagents()
|
||||
.iter()
|
||||
.map(|(_, quantity)| quantity)
|
||||
.sum()
|
||||
}
|
||||
LogicReagentMode::Required => {
|
||||
let reagent_interface = logicable
|
||||
.as_reagent_interface()
|
||||
.ok_or(ICError::NotReagentReadable(logicable.get_id()))?;
|
||||
reagent_interface
|
||||
.get_current_required()
|
||||
.iter()
|
||||
.find(|(hash, _)| *hash as f64 == int)
|
||||
.map(|(_, quantity)| *quantity)
|
||||
.unwrap_or(0.0)
|
||||
}
|
||||
LogicReagentMode::Recipe => {
|
||||
let reagent_interface = logicable
|
||||
.as_reagent_interface()
|
||||
.ok_or(ICError::NotReagentReadable(logicable.get_id()))?;
|
||||
reagent_interface
|
||||
.get_current_recipie()
|
||||
.iter()
|
||||
.find(|(hash, _)| *hash as f64 == int)
|
||||
.map(|(_, quantity)| *quantity)
|
||||
.unwrap_or(0.0)
|
||||
}
|
||||
};
|
||||
|
||||
self.set_register(indirection, target, result)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IC10Marker> LbInstruction for T {
|
||||
/// lb r? deviceHash logicType batchMode
|
||||
fn execute_inner(
|
||||
&mut self,
|
||||
r: &InstOperand,
|
||||
device_hash: &InstOperand,
|
||||
logic_type: &InstOperand,
|
||||
batch_mode: &InstOperand,
|
||||
) -> Result<(), ICError> {
|
||||
let RegisterSpec {
|
||||
indirection,
|
||||
target,
|
||||
} = r.as_register(self)?;
|
||||
|
||||
let prefab = device_hash.as_value(self)?;
|
||||
let logic_type = logic_type.as_logic_type(self)?;
|
||||
let batch_mode = batch_mode.as_batch_mode(self)?;
|
||||
let val =
|
||||
self.get_vm()
|
||||
.get_batch_device_field(self.get_id(), prefab, logic_type, batch_mode)?;
|
||||
self.set_register(indirection, target, val)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IC10Marker> LbnInstruction for T {
|
||||
/// lbn r? deviceHash nameHash logicType batchMode
|
||||
fn execute_inner(
|
||||
&mut self,
|
||||
|
||||
r: &InstOperand,
|
||||
device_hash: &InstOperand,
|
||||
name_hash: &InstOperand,
|
||||
logic_type: &InstOperand,
|
||||
batch_mode: &InstOperand,
|
||||
) -> Result<(), ICError> {
|
||||
let RegisterSpec {
|
||||
indirection,
|
||||
target,
|
||||
} = r.as_register(self)?;
|
||||
let prefab = device_hash.as_value(self)?;
|
||||
let name = name_hash.as_value(self)?;
|
||||
let logic_type = logic_type.as_logic_type(self)?;
|
||||
let batch_mode = batch_mode.as_batch_mode(self)?;
|
||||
let val = self.get_vm().get_batch_name_device_field(
|
||||
self.get_id(),
|
||||
prefab,
|
||||
name,
|
||||
logic_type,
|
||||
batch_mode,
|
||||
)?;
|
||||
self.set_register(indirection, target, val)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IC10Marker> LbnsInstruction for T {
|
||||
/// lbns r? deviceHash nameHash slotIndex logicSlotType batchMode
|
||||
fn execute_inner(
|
||||
&mut self,
|
||||
|
||||
r: &InstOperand,
|
||||
device_hash: &InstOperand,
|
||||
name_hash: &InstOperand,
|
||||
slot_index: &InstOperand,
|
||||
logic_slot_type: &InstOperand,
|
||||
batch_mode: &InstOperand,
|
||||
) -> Result<(), ICError> {
|
||||
let RegisterSpec {
|
||||
indirection,
|
||||
target,
|
||||
} = r.as_register(self)?;
|
||||
let prefab = device_hash.as_value(self)?;
|
||||
let name = name_hash.as_value(self)?;
|
||||
let slot_index = slot_index.as_value(self)?;
|
||||
let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?;
|
||||
let batch_mode = batch_mode.as_batch_mode(self)?;
|
||||
let val = self.get_vm().get_batch_name_device_slot_field(
|
||||
self.get_id(),
|
||||
prefab,
|
||||
name,
|
||||
slot_index,
|
||||
logic_slot_type,
|
||||
batch_mode,
|
||||
)?;
|
||||
self.set_register(indirection, target, val)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IC10Marker> LbsInstruction for T {
|
||||
/// lbs r? deviceHash slotIndex logicSlotType batchMode
|
||||
fn execute_inner(
|
||||
&mut self,
|
||||
|
||||
r: &InstOperand,
|
||||
device_hash: &InstOperand,
|
||||
slot_index: &InstOperand,
|
||||
logic_slot_type: &InstOperand,
|
||||
batch_mode: &InstOperand,
|
||||
) -> Result<(), ICError> {
|
||||
let RegisterSpec {
|
||||
indirection,
|
||||
target,
|
||||
} = r.as_register(self)?;
|
||||
let prefab = device_hash.as_value(self)?;
|
||||
let slot_index = slot_index.as_value(self)?;
|
||||
let logic_slot_type = logic_slot_type.as_slot_logic_type(self)?;
|
||||
let batch_mode = batch_mode.as_batch_mode(self)?;
|
||||
let val = self.get_vm().get_batch_device_slot_field(
|
||||
self.get_id(),
|
||||
prefab,
|
||||
slot_index,
|
||||
logic_slot_type,
|
||||
batch_mode,
|
||||
)?;
|
||||
self.set_register(indirection, target, val)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IC10Marker> HcfInstruction for T {
|
||||
/// hcf
|
||||
fn execute_inner(&mut self) -> Result<(), ICError> {
|
||||
self.get_circuit_holder()
|
||||
.ok_or(ICError::NoCircuitHolder(self.get_id()))?
|
||||
.hault_and_catch_fire();
|
||||
self.set_state(ICState::HasCaughtFire);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IC10Marker> LabelInstruction for T {
|
||||
/// label d? str
|
||||
fn execute_inner(&mut self, d: &InstOperand, str: &InstOperand) -> Result<(), ICError> {
|
||||
// No op, handled by program compilation, should never be called?
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,7 +265,7 @@ impl VM {
|
||||
.ok_or(VMError::NotProgrammable(id))?;
|
||||
self.operation_modified.borrow_mut().clear();
|
||||
self.set_modified(id);
|
||||
programmable.step(self, advance_ip_on_err)?;
|
||||
programmable.step(advance_ip_on_err)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -286,7 +286,7 @@ impl VM {
|
||||
self.operation_modified.borrow_mut().clear();
|
||||
self.set_modified(id);
|
||||
for _i in 0..128 {
|
||||
if let Err(err) = programmable.step(self, ignore_errors) {
|
||||
if let Err(err) = programmable.step( ignore_errors) {
|
||||
if !ignore_errors {
|
||||
return Err(err.into());
|
||||
}
|
||||
@@ -629,7 +629,7 @@ impl VM {
|
||||
.borrow_mut()
|
||||
.as_mut_device()
|
||||
.expect("batch iter yielded non device")
|
||||
.set_slot_logic(typ, index, val, self, write_readonly)
|
||||
.set_slot_logic(typ, index, val, write_readonly)
|
||||
.map_err(Into::into)
|
||||
})
|
||||
.try_collect()
|
||||
@@ -718,7 +718,7 @@ impl VM {
|
||||
.borrow()
|
||||
.as_device()
|
||||
.expect("batch iter yielded non device")
|
||||
.get_slot_logic(typ, index, self)
|
||||
.get_slot_logic(typ, index)
|
||||
.map_err(Into::into)
|
||||
})
|
||||
.filter_ok(|val| !val.is_nan())
|
||||
@@ -741,7 +741,7 @@ impl VM {
|
||||
.borrow()
|
||||
.as_device()
|
||||
.expect("batch iter yielded non device")
|
||||
.get_slot_logic(typ, index, self)
|
||||
.get_slot_logic(typ, index)
|
||||
.map_err(Into::into)
|
||||
})
|
||||
.filter_ok(|val| !val.is_nan())
|
||||
|
||||
@@ -1,18 +1,12 @@
|
||||
use crate::{
|
||||
errors::{ICError, LineError},
|
||||
grammar,
|
||||
interpreter::{ICState, instructions::IC10Marker},
|
||||
errors::ICError,
|
||||
interpreter::{instructions::IC10Marker, ICState, Program},
|
||||
vm::{
|
||||
enums::{
|
||||
basic_enums::{Class as SlotClass, GasType, SortingClass},
|
||||
script_enums::{LogicSlotType, LogicType},
|
||||
},
|
||||
instructions::{
|
||||
enums::InstructionOp,
|
||||
operands::{DeviceSpec, Operand, RegisterSpec},
|
||||
traits::*,
|
||||
Instruction,
|
||||
},
|
||||
instructions::{operands::Operand, Instruction},
|
||||
object::{
|
||||
errors::{LogicError, MemoryError},
|
||||
macros::ObjectInterface,
|
||||
@@ -22,124 +16,8 @@ use crate::{
|
||||
VM,
|
||||
},
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use macro_rules_attribute::derive;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::{
|
||||
collections::{BTreeMap, HashSet},
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Program {
|
||||
pub instructions: Vec<Instruction>,
|
||||
pub errors: Vec<ICError>,
|
||||
pub labels: BTreeMap<String, u32>,
|
||||
}
|
||||
|
||||
impl Default for Program {
|
||||
fn default() -> Self {
|
||||
Program::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Program {
|
||||
pub fn new() -> Self {
|
||||
Program {
|
||||
instructions: Vec::new(),
|
||||
errors: Vec::new(),
|
||||
labels: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_from_code(code: &str) -> Result<Self, ICError> {
|
||||
let parse_tree = grammar::parse(code)?;
|
||||
let mut labels_set = HashSet::new();
|
||||
let mut labels = BTreeMap::new();
|
||||
let errors = Vec::new();
|
||||
let instructions = parse_tree
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(line_number, line)| match line.code {
|
||||
None => Ok(Instruction {
|
||||
instruction: InstructionOp::Nop,
|
||||
operands: vec![],
|
||||
}),
|
||||
Some(code) => match code {
|
||||
grammar::Code::Label(label) => {
|
||||
if labels_set.contains(&label.id.name) {
|
||||
Err(ICError::DuplicateLabel(label.id.name))
|
||||
} else {
|
||||
labels_set.insert(label.id.name.clone());
|
||||
labels.insert(label.id.name, line_number as u32);
|
||||
Ok(Instruction {
|
||||
instruction: InstructionOp::Nop,
|
||||
operands: vec![],
|
||||
})
|
||||
}
|
||||
}
|
||||
grammar::Code::Instruction(instruction) => Ok(instruction),
|
||||
grammar::Code::Invalid(err) => Err(err.into()),
|
||||
},
|
||||
})
|
||||
.try_collect()?;
|
||||
Ok(Program {
|
||||
instructions,
|
||||
errors,
|
||||
labels,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_code_with_invalid(code: &str) -> Self {
|
||||
let parse_tree = grammar::parse_with_invalid(code);
|
||||
let mut labels_set = HashSet::new();
|
||||
let mut labels = BTreeMap::new();
|
||||
let mut errors = Vec::new();
|
||||
let instructions = parse_tree
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(line_number, line)| match line.code {
|
||||
None => Instruction {
|
||||
instruction: InstructionOp::Nop,
|
||||
operands: vec![],
|
||||
},
|
||||
Some(code) => match code {
|
||||
grammar::Code::Label(label) => {
|
||||
if labels_set.contains(&label.id.name) {
|
||||
errors.push(ICError::DuplicateLabel(label.id.name));
|
||||
} else {
|
||||
labels_set.insert(label.id.name.clone());
|
||||
labels.insert(label.id.name, line_number as u32);
|
||||
}
|
||||
Instruction {
|
||||
instruction: InstructionOp::Nop,
|
||||
operands: vec![],
|
||||
}
|
||||
}
|
||||
grammar::Code::Instruction(instruction) => instruction,
|
||||
grammar::Code::Invalid(err) => {
|
||||
errors.push(err.into());
|
||||
Instruction {
|
||||
instruction: InstructionOp::Nop,
|
||||
operands: vec![],
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
.collect_vec();
|
||||
Program {
|
||||
instructions,
|
||||
errors,
|
||||
labels,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_line(&self, line: usize) -> Result<&Instruction, ICError> {
|
||||
self.instructions
|
||||
.get(line)
|
||||
.ok_or(ICError::InstructionPointerOutOfRange(line))
|
||||
}
|
||||
}
|
||||
use std::{collections::BTreeMap, rc::Rc};
|
||||
|
||||
static RETURN_ADDRESS_INDEX: usize = 17;
|
||||
static STACK_POINTER_INDEX: usize = 16;
|
||||
@@ -219,6 +97,7 @@ impl Storage for ItemIntegratedCircuit10 {
|
||||
&mut []
|
||||
}
|
||||
}
|
||||
|
||||
impl Logicable for ItemIntegratedCircuit10 {
|
||||
fn prefab_hash(&self) -> i32 {
|
||||
self.get_prefab().hash
|
||||
@@ -487,3 +366,46 @@ impl IntegratedCircuit for ItemIntegratedCircuit10 {
|
||||
}
|
||||
|
||||
impl IC10Marker for ItemIntegratedCircuit10 {}
|
||||
|
||||
impl Programmable for ItemIntegratedCircuit10 {
|
||||
fn step(&mut self, advance_ip_on_err: bool) -> Result<(), crate::errors::ICError> {
|
||||
if matches!(&self.state, ICState::HasCaughtFire | ICState::Error(_)) {
|
||||
return Ok(());
|
||||
}
|
||||
if let ICState::Sleep(then, sleep_for) = &self.state {
|
||||
if let Some(duration) = time::Duration::checked_seconds_f64(*sleep_for) {
|
||||
if let Some(sleep_till) = then.checked_add(duration) {
|
||||
if sleep_till
|
||||
<= time::OffsetDateTime::now_local()
|
||||
.unwrap_or_else(|_| time::OffsetDateTime::now_utc())
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
// else sleep duration ended, continue
|
||||
} else {
|
||||
return Err(ICError::SleepAddtionError(duration, *then));
|
||||
}
|
||||
} else {
|
||||
return Err(ICError::SleepDurationError(*sleep_for));
|
||||
}
|
||||
}
|
||||
if self.ip >= self.program.len() || self.program.len() == 0 {
|
||||
self.state = ICState::Ended;
|
||||
return Ok(());
|
||||
}
|
||||
self.next_ip = self.ip + 1;
|
||||
self.state = ICState::Running;
|
||||
let line = self.program.get_line(self.ip)?;
|
||||
let operands = &line.operands;
|
||||
let instruction = line.instruction;
|
||||
instruction.execute(self, operands)?;
|
||||
self.ip = self.next_ip;
|
||||
if self.ip >= self.program.len() {
|
||||
self.state = ICState::Ended;
|
||||
}
|
||||
self.get_circuit_holder()
|
||||
.ok_or(ICError::NoCircuitHolder(self.id))?
|
||||
.set_logic(LogicType::LineNumber, self.ip as f64, true)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +104,7 @@ tag_object_traits! {
|
||||
fn get_batch(&self) -> Vec<LogicableRef>;
|
||||
fn get_batch_mut(&self) -> Vec<LogicableRefMut>;
|
||||
fn get_ic(&self) -> Option<ObjectID>;
|
||||
fn hault_and_catch_fire(&mut self);
|
||||
}
|
||||
|
||||
pub trait Item {
|
||||
@@ -148,8 +149,6 @@ tag_object_traits! {
|
||||
}
|
||||
|
||||
pub trait Programmable: ICInstructable {
|
||||
fn get_source_code(&self) -> String;
|
||||
fn set_source_code(&self, code: String);
|
||||
fn step(&mut self, advance_ip_on_err: bool) -> Result<(), crate::errors::ICError>;
|
||||
}
|
||||
|
||||
@@ -182,8 +181,23 @@ tag_object_traits! {
|
||||
fn has_on_off_state(&self) -> bool;
|
||||
fn has_open_state(&self) -> bool;
|
||||
fn has_reagents(&self) -> bool;
|
||||
/// return vector of (reagent_hash, quantity) pairs
|
||||
fn get_reagents(&self) -> Vec<(i32, f64)>;
|
||||
/// overwrite present reagents
|
||||
fn set_reagents(&mut self, reagents: &[(i32, f64)]);
|
||||
/// adds the reagents to contents
|
||||
fn add_reagents(&mut self, reagents: &[(i32, f64)]);
|
||||
}
|
||||
|
||||
pub trait ReagentInterface: Device {
|
||||
/// reagents required by current recipe
|
||||
fn get_current_recipie(&self) -> Vec<(i32, f64)>;
|
||||
/// reagents required to complete current recipe
|
||||
fn get_current_required(&self) -> Vec<(i32, f64)>;
|
||||
}
|
||||
|
||||
pub trait Fabricator: ReagentInterface {}
|
||||
|
||||
pub trait WirelessTransmit: Logicable {}
|
||||
|
||||
pub trait WirelessReceive: Logicable {}
|
||||
|
||||
Reference in New Issue
Block a user