Skip to content

Commit

Permalink
refactor: 💡 Refactor interpreter and add automatic tape resize
Browse files Browse the repository at this point in the history
  • Loading branch information
kamack38 committed Jan 22, 2024
1 parent 76be794 commit 8a86e53
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 85 deletions.
13 changes: 6 additions & 7 deletions examples/code.ram
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
#read 1 #idk
read 2
load 2
mult 2
store 3
#div 3
#load 1
read 1
load 1
mult 1
write 0
div =2
store 2
write 2
123 changes: 46 additions & 77 deletions src/interpreter.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
use std::num::TryFromIntError;

use crate::parser::{
instruction::Instruction,
operand::CellAddress,
operand::{CellOperand, Operand},
operand::{CellOperand, ExpandError, Operand},
ram_code::RamCode,
};
use thiserror::Error;
Expand All @@ -21,12 +18,10 @@ pub struct RamMachine {
#[derive(Error, Debug, PartialEq, Eq)]
pub enum RamMachineError {
#[error(transparent)]
CellAccessError(#[from] CellAccessError),
ExpandError(#[from] ExpandError),
#[error(transparent)]
InputAccessError(#[from] InputAccessError),
#[error(transparent)]
ConvertError(#[from] TryFromIntError),
#[error(transparent)]
JumpError(#[from] JumpError),
#[error("Addition of `{0}` failed.")]
AdditionFailed(i32),
Expand All @@ -36,14 +31,6 @@ pub enum RamMachineError {
DivisionFailed(i32),
}

#[derive(Error, Debug, PartialEq, Eq)]
pub enum CellAccessError {
#[error("Cell {0} does not exist or its value wasn't set.")]
NotExistentCell(usize),
#[error(transparent)]
ConvertError(#[from] TryFromIntError),
}

#[derive(Error, Debug, PartialEq, Eq)]
pub enum InputAccessError {
#[error("Input at index `{0}` not found.")]
Expand All @@ -52,7 +39,7 @@ pub enum InputAccessError {

#[derive(Error, Debug, PartialEq, Eq)]
pub enum JumpError {
#[error("")]
#[error("Label `{0}` could not be found in Ram code.")]
LabelNotFound(String),
}

Expand All @@ -66,7 +53,7 @@ impl RamMachine {
pub fn new(code: RamCode, input: Vec<i32>) -> Self {
RamMachine {
code,
tape: vec![0, 0, 0, 0, 0, 0],
tape: vec![0],
pointer: 0,
input_pointer: 0,
input,
Expand All @@ -88,41 +75,6 @@ impl RamMachine {
// todo!()
// }

fn access_cell(&self, cell: &CellAddress) -> Result<i32, CellAccessError> {
self.tape
.get(*cell)
.ok_or(CellAccessError::NotExistentCell(*cell))
.copied()
}

fn access(&self, operand: &Operand) -> Result<i32, CellAccessError> {
use Operand::*;
match operand {
Number(v) => Ok(*v),
ValueInCell(cell) => Ok(self.access_cell(cell)?),
ValueOfValueInCell(cell) => {
Ok(self.access_cell(&usize::try_from(self.access_cell(cell)?)?)?)
}
}
}

fn get_cell(&mut self, cell_operand: &CellOperand) -> Result<&mut i32, CellAccessError> {
use CellOperand::*;
match cell_operand {
AddressOfCell(cell) => self
.tape
.get_mut(*cell)
.ok_or(CellAccessError::NotExistentCell(*cell)),
AddressOfCellInCell(cell) => {
let real_cell = self
.tape
.get(*cell)
.ok_or(CellAccessError::NotExistentCell(*cell))?;
self.get_cell(&CellOperand::AddressOfCell(usize::try_from(*real_cell)?))
}
}
}

fn jump_to(&mut self, label: &str) -> Result<RunState, JumpError> {
match self
.code
Expand All @@ -141,14 +93,6 @@ impl RamMachine {
}
}

fn buffer_value(&self) -> i32 {
self.tape[0]
}

fn buffer(&mut self) -> &mut i32 {
self.tape.get_mut(0).unwrap()
}

fn get_input(&mut self) -> Result<&i32, InputAccessError> {
let input = self
.input
Expand All @@ -166,55 +110,80 @@ impl RamMachine {
RunState::Halted
}

fn get(&self, operand: &Operand) -> Result<i32, ExpandError> {
Ok(*operand.expand(&self.tape)?)
}

fn set(&mut self, cell_operand: &CellOperand, value: i32) -> Result<(), ExpandError> {
let index = cell_operand.expand(&self.tape)?;
self.tape.resize(index + 1, 0);
*self.tape.get_mut(index).expect("Tape was just resized") = value;
Ok(())
}

fn buffer(&self) -> &i32 {
self.tape
.first()
.expect("Tape was initialized with length 1")
}

fn buffer_mut(&mut self) -> &mut i32 {
self.tape
.get_mut(0)
.expect("Tape was initialized with length 1")
}

pub fn execute(&mut self, instruction: &Instruction) -> Result<RunState, RamMachineError> {
use Instruction::*;
match instruction {
Load(o) => {
self.tape[0] = self.access(o)?;
*self.buffer_mut() = self.get(o)?;
Ok(self.advance_pointer())
}
Store(o) => {
*self.get_cell(o)? = self.buffer_value();
self.set(o, *self.buffer())?;
Ok(self.advance_pointer())
}
Add(o) => {
*self.buffer() = self.tape[0]
.checked_add(self.access(o)?)
.ok_or(RamMachineError::AdditionFailed(self.access(o)?))?;
*self.buffer_mut() = self
.buffer()
.checked_add(self.get(o)?)
.ok_or(RamMachineError::AdditionFailed(self.get(o)?))?;
Ok(self.advance_pointer())
}
Mult(o) => {
*self.buffer() = self
.buffer_value()
.checked_mul(self.access(o)?)
.ok_or(RamMachineError::MultiplicationFailed(self.access(o)?))?;
*self.buffer_mut() = self
.buffer()
.checked_mul(self.get(o)?)
.ok_or(RamMachineError::MultiplicationFailed(self.get(o)?))?;
Ok(self.advance_pointer())
}
Div(o) => {
*self.buffer() = self
.buffer_value()
.checked_div(self.access(o)?)
.ok_or(RamMachineError::DivisionFailed(self.access(o)?))?;
*self.buffer_mut() = self
.buffer()
.checked_div(self.get(o)?)
.ok_or(RamMachineError::DivisionFailed(self.get(o)?))?;
Ok(self.advance_pointer())
}
Read(o) => {
*self.get_cell(o)? = *self.get_input()?;
let input = *self.get_input()?;
self.set(o, input)?;
Ok(self.advance_pointer())
}
Write(o) => {
self.output.push(self.access(o)?);
self.output.push(self.get(o)?);
Ok(self.advance_pointer())
}
Jump(s) => Ok(self.jump_to(s)?),
Jgtz(s) => {
if self.tape[0] > 0 {
if *self.buffer() > 0 {
self.jump_to(s)?;
return Ok(RunState::Running);
}
Ok(self.advance_pointer())
}
Jzero(s) => {
if self.tape[0] == 0 {
if *self.buffer() == 0 {
self.jump_to(s)?;
Ok(RunState::Running)
} else {
Expand Down
5 changes: 4 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ fn main() -> Result<(), RuntimeError> {
let interpreter = RamMachine::new(code, input);
match interpreter.run() {
Ok(v) => println!("{:?}", v),
Err(e) => println!("{}", e),
Err(e) => {
println!("{}", e);
exit(1);
}
}
Ok(())
}
50 changes: 50 additions & 0 deletions src/parser/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,56 @@ pub enum CellOperand {
AddressOfCellInCell(CellAddress),
}

#[derive(Error, Debug, PartialEq, Eq)]
pub enum ExpandError {
#[error("Cell {0} does not exist or its value wasn't set.")]
NotExistentCell(usize),
#[error("Value `{0}` in cell `{1}` could not be converted to a tape index.")]
ConvertError(i32, usize),
// #[error("Tried reading from cell with address `{0}`, which wasn't set.")]
// ValueNotSet(usize),
}

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

impl CellOperand {
pub fn expand(&self, tape: &[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))?)
.or(Err(ExpandError::ConvertError(
*tape.get(*cell).expect("Didn't fail previously"),
*cell,
)))
}
}
}
}

macro_rules! parse {
($e:expr) => {
$e.parse().expect("Already checked if can be parsed")
Expand Down

0 comments on commit 8a86e53

Please sign in to comment.