diff --git a/examples/code.ram b/examples/code.ram index 985848e..c45f73b 100644 --- a/examples/code.ram +++ b/examples/code.ram @@ -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 diff --git a/src/interpreter.rs b/src/interpreter.rs index 063063b..7af6ab3 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -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; @@ -11,6 +8,8 @@ use thiserror::Error; #[derive(Debug, PartialEq, Eq)] pub struct RamMachine { code: RamCode, + // TODO: Change to Vec>, because it should'nt be assumed that each value is 0 by + // default tape: Vec, pointer: usize, input: Vec, @@ -21,12 +20,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), @@ -36,14 +33,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.")] @@ -52,7 +41,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), } @@ -66,7 +55,7 @@ impl RamMachine { pub fn new(code: RamCode, input: Vec) -> Self { RamMachine { code, - tape: vec![0, 0, 0, 0, 0, 0], + tape: vec![0], pointer: 0, input_pointer: 0, input, @@ -88,41 +77,6 @@ impl RamMachine { // todo!() // } - fn access_cell(&self, cell: &CellAddress) -> Result { - self.tape - .get(*cell) - .ok_or(CellAccessError::NotExistentCell(*cell)) - .copied() - } - - fn access(&self, operand: &Operand) -> Result { - 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 { match self .code @@ -141,14 +95,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 @@ -166,55 +112,80 @@ impl RamMachine { RunState::Halted } + fn get(&self, operand: &Operand) -> Result { + 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 { 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 { diff --git a/src/main.rs b/src/main.rs index c8d55e6..b64a816 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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(()) } diff --git a/src/parser/operand.rs b/src/parser/operand.rs index 4d215e4..01c7ba4 100644 --- a/src/parser/operand.rs +++ b/src/parser/operand.rs @@ -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 { + 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")