Skip to content

Commit

Permalink
feat: 🎸 Make all values in tape None by default
Browse files Browse the repository at this point in the history
  • Loading branch information
kamack38 committed Jan 24, 2024
1 parent a835c4c commit 59bb24f
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 41 deletions.
58 changes: 33 additions & 25 deletions src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,24 @@ use thiserror::Error;
#[derive(Debug, PartialEq, Eq)]
pub struct RamMachine {
code: RamCode,
// TODO: Change to Vec<Option<i32>>, because it should'nt be assumed that each value is 0 by
// default
tape: Vec<i32>,
tape: Vec<Option<i32>>,
pointer: usize,
input: Vec<i32>,
input_pointer: usize,
output: Vec<i32>,
}

#[derive(Error, Debug, PartialEq, Eq)]
#[error("Buffer could not be accessed, because its value was never set.")]
pub struct BufferError;

#[derive(Error, Debug, PartialEq, Eq)]
pub enum RamMachineError {
#[error(transparent)]
ExpandError(#[from] ExpandError),
#[error(transparent)]
BufferError(#[from] BufferError),
#[error(transparent)]
InputAccessError(#[from] InputAccessError),
#[error(transparent)]
JumpError(#[from] JumpError),
Expand Down Expand Up @@ -55,7 +59,7 @@ impl RamMachine {
pub fn new(code: RamCode, input: Vec<i32>) -> Self {
RamMachine {
code,
tape: vec![0],
tape: vec![None],
pointer: 0,
input_pointer: 0,
input,
Expand Down Expand Up @@ -119,19 +123,20 @@ impl RamMachine {
fn set(&mut self, cell_operand: &CellOperand, value: i32) -> Result<(), ExpandError> {
let index = cell_operand.expand(&self.tape)?;
if self.tape.len() < index + 1 {
self.tape.resize(index + 1, 0);
self.tape.resize(index + 1, None);
}
*self.tape.get_mut(index).expect("Tape was just resized") = value;
*self.tape.get_mut(index).expect("Tape was just resized") = Some(value);
Ok(())
}

fn buffer(&self) -> &i32 {
fn buffer(&self) -> Result<&i32, BufferError> {
self.tape
.first()
.expect("Tape was initialized with length 1")
.and_then(|val| val.as_ref())
.ok_or(BufferError)
}

fn buffer_mut(&mut self) -> &mut i32 {
fn buffer_mut(&mut self) -> &mut Option<i32> {
self.tape
.get_mut(0)
.expect("Tape was initialized with length 1")
Expand All @@ -141,32 +146,35 @@ impl RamMachine {
use Instruction::*;
match instruction {
Load(o) => {
*self.buffer_mut() = self.get(o)?;
*self.buffer_mut() = Some(self.get(o)?);
Ok(self.advance_pointer())
}
Store(o) => {
self.set(o, *self.buffer())?;
self.set(o, *self.buffer()?)?;
Ok(self.advance_pointer())
}
Add(o) => {
*self.buffer_mut() = self
.buffer()
.checked_add(self.get(o)?)
.ok_or(RamMachineError::AdditionFailed(self.get(o)?))?;
*self.buffer_mut() = Some(
self.buffer()?
.checked_add(self.get(o)?)
.ok_or(RamMachineError::AdditionFailed(self.get(o)?))?,
);
Ok(self.advance_pointer())
}
Mult(o) => {
*self.buffer_mut() = self
.buffer()
.checked_mul(self.get(o)?)
.ok_or(RamMachineError::MultiplicationFailed(self.get(o)?))?;
*self.buffer_mut() = Some(
self.buffer()?
.checked_mul(self.get(o)?)
.ok_or(RamMachineError::MultiplicationFailed(self.get(o)?))?,
);
Ok(self.advance_pointer())
}
Div(o) => {
*self.buffer_mut() = self
.buffer()
.checked_div(self.get(o)?)
.ok_or(RamMachineError::DivisionFailed(self.get(o)?))?;
*self.buffer_mut() = Some(
self.buffer()?
.checked_div(self.get(o)?)
.ok_or(RamMachineError::DivisionFailed(self.get(o)?))?,
);
Ok(self.advance_pointer())
}
Read(o) => {
Expand All @@ -180,14 +188,14 @@ impl RamMachine {
}
Jump(s) => Ok(self.jump_to(s)?),
Jgtz(s) => {
if *self.buffer() > 0 {
if *self.buffer()? > 0 {
self.jump_to(s)?;
return Ok(RunState::Running);
}
Ok(self.advance_pointer())
}
Jzero(s) => {
if *self.buffer() == 0 {
if *self.buffer()? == 0 {
self.jump_to(s)?;
Ok(RunState::Running)
} else {
Expand Down
42 changes: 26 additions & 16 deletions src/parser/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,47 +35,57 @@ pub enum ExpandError {
}

impl Operand {
pub fn expand<'a>(&'a self, tape: &'a [i32]) -> Result<&'a i32, ExpandError> {
pub fn expand<'a>(&'a self, tape: &'a [Option<i32>]) -> Result<&'a i32, ExpandError> {
use Operand::*;
match self {
Number(v) => Ok(v),
ValueInCell(cell) => tape.get(*cell).ok_or(ExpandError::NotExistentCell(*cell)),
ValueInCell(cell) => Ok(tape
.get(*cell)
.and_then(|val| val.as_ref())
.ok_or(ExpandError::NotExistentCell(*cell))?),
ValueOfValueInCell(cell) => tape
.get(
CellAddress::try_from(
*tape.get(*cell).ok_or(ExpandError::NotExistentCell(*cell))?,
tape.get(*cell)
.ok_or(ExpandError::NotExistentCell(*cell))?
.ok_or(ExpandError::NotExistentCell(*cell))?,
)
.map_err(|_| {
ExpandError::ConvertError(
*tape.get(*cell).expect("Would've failed before"),
tape.get(*cell).expect("Would've failed before").unwrap(),
*cell,
)
})?,
)
.and_then(|val| val.as_ref())
.ok_or_else(|| {
ExpandError::NotExistentCell(
CellAddress::try_from(*tape.get(*cell).expect("Would've failed before"))
.expect("Would've failed before"),
CellAddress::try_from(
tape.get(*cell).expect("Would've failed before").unwrap(),
)
.expect("Would've failed before"),
)
}),
}
}
}

impl CellOperand {
pub fn expand(&self, tape: &[i32]) -> Result<CellAddress, ExpandError> {
pub fn expand(&self, tape: &[Option<i32>]) -> Result<CellAddress, ExpandError> {
use CellOperand::*;
match self {
AddressOfCell(cell) => Ok(*cell),
AddressOfCellInCell(cell) => {
CellAddress::try_from(*tape.get(*cell).ok_or(ExpandError::NotExistentCell(*cell))?)
.map_err(|_| {
ExpandError::ConvertError(
*tape.get(*cell).expect("Didn't fail previously"),
*cell,
)
})
}
AddressOfCellInCell(cell) => CellAddress::try_from(
tape.get(*cell)
.ok_or(ExpandError::NotExistentCell(*cell))?
.ok_or(ExpandError::NotExistentCell(*cell))?,
)
.map_err(|_| {
ExpandError::ConvertError(
tape.get(*cell).expect("Didn't fail previously").unwrap(),
*cell,
)
}),
}
}
}
Expand Down

0 comments on commit 59bb24f

Please sign in to comment.