rafactor(vm): end instruction impl

This commit is contained in:
Rachel Powers
2024-05-15 16:43:37 -07:00
parent 0c5e2b29a8
commit e928813c0e
6 changed files with 555 additions and 1006 deletions

View File

@@ -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 {

View File

@@ -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(&lt) {
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(&lt) {
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::*;

View File

@@ -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(())
}
}

View File

@@ -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())

View File

@@ -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(())
}
}

View File

@@ -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 {}