mindustry logic execution, map- and schematic- parsing and rendering
dynamic indexes
| -rw-r--r-- | lemu/Cargo.toml | 2 | ||||
| -rw-r--r-- | lemu/src/executor/mod.rs | 14 | ||||
| -rw-r--r-- | lemu/src/instructions/io.rs | 27 | ||||
| -rw-r--r-- | lemu/src/instructions/mod.rs | 2 | ||||
| -rw-r--r-- | lemu/src/parser.rs | 41 |
5 files changed, 60 insertions, 26 deletions
diff --git a/lemu/Cargo.toml b/lemu/Cargo.toml index 49d88bd..7c643d5 100644 --- a/lemu/Cargo.toml +++ b/lemu/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lemu" -version = "0.2.3" +version = "0.2.4" edition = "2021" description = "M-LOG runner" authors = ["bend-n <[email protected]>"] diff --git a/lemu/src/executor/mod.rs b/lemu/src/executor/mod.rs index a3cce26..991c09f 100644 --- a/lemu/src/executor/mod.rs +++ b/lemu/src/executor/mod.rs @@ -13,11 +13,19 @@ pub struct Display(pub usize); // negative means bank, positive means cell pub struct Memory(pub(crate) i8); impl Memory { - pub(crate) fn limit(self, i: usize) -> usize { + pub(crate) fn fits(self, i: usize) -> bool { if self.0 < 0 { - i.min(BANK_SIZE) + i < BANK_SIZE } else { - i.min(CELL_SIZE) + i < CELL_SIZE + } + } + + pub(crate) fn size(self) -> usize { + if self.0 < 0 { + BANK_SIZE + } else { + CELL_SIZE } } } diff --git a/lemu/src/instructions/io.rs b/lemu/src/instructions/io.rs index 75b9c0e..8b1eed5 100644 --- a/lemu/src/instructions/io.rs +++ b/lemu/src/instructions/io.rs @@ -1,4 +1,4 @@ -use super::{Flow, LInstruction}; +use super::{get_num, Flow, LInstruction}; use crate::{ executor::{ExecutorContext, Memory}, memory::{LAddress, LVar}, @@ -7,37 +7,38 @@ use std::io::Write as Wr; #[derive(Debug)] pub struct Read<'v> { - // index guranteed to never be out of bounds - pub(crate) index: usize, + pub(crate) index: LAddress<'v>, pub(crate) output: LAddress<'v>, pub(crate) container: Memory, } impl<'v> LInstruction<'v> for Read<'v> { fn run<W: Wr>(&self, exec: &mut ExecutorContext<'v, W>) -> Flow { - let to = exec.mem(self.container)[self.index]; - let Some(out) = exec.get_mut(&self.output) else { - return Flow::Continue; + let i = get_num!(exec.get(&self.index)).round() as usize; + if let Some(&n) = exec.mem(self.container).get(i) { + if let Some(out) = exec.get_mut(&self.output) { + *out = LVar::from(n); + } }; - *out = LVar::from(to); Flow::Continue } } #[derive(Debug)] pub struct Write<'v> { - // index guranteed to never be out of bounds - pub(crate) index: usize, + pub(crate) index: LAddress<'v>, pub(crate) set: LAddress<'v>, pub(crate) container: Memory, } impl<'v> LInstruction<'v> for Write<'v> { fn run<W: Wr>(&self, exec: &mut ExecutorContext<'v, W>) -> Flow { - let &LVar::Num(n) = exec.get(&self.set) else { - return Flow::Continue; - }; - exec.mem(self.container)[self.index] = n; + let i = get_num!(exec.get(&self.index)).round() as usize; + if let &LVar::Num(b) = exec.get(&self.set) { + if let Some(a) = exec.mem(self.container).get_mut(i) { + *a = b; + } + } Flow::Continue } } diff --git a/lemu/src/instructions/mod.rs b/lemu/src/instructions/mod.rs index 8dbae7e..a6bd3ba 100644 --- a/lemu/src/instructions/mod.rs +++ b/lemu/src/instructions/mod.rs @@ -90,7 +90,9 @@ pub const OPS: &[&str] = &[ ]; #[must_use = "to change control flow"] +#[derive(Default)] pub enum Flow { + #[default] Continue, Stay, Exit, diff --git a/lemu/src/parser.rs b/lemu/src/parser.rs index 9fd08e1..b524bce 100644 --- a/lemu/src/parser.rs +++ b/lemu/src/parser.rs @@ -13,7 +13,7 @@ use super::{ AlwaysJump, ConditionOp, DynJump, End, Instr, Jump, MathOp1, MathOp2, Op1, Op2, Set, Stop, }, lexer::{Lexer, Token}, - memory::LAddress, + memory::{LAddress, LVar}, }; /// Errors returned when parsing fails. @@ -49,14 +49,17 @@ pub enum Error<'s> { /// jump label always /// ``` /// (typo: lable not label) - #[error("unable to find label {0:?}")] + #[error("unable to find label {0}")] LabelNotFound(&'s str, Span), /// Occurs from eg `jump 4910294029 always` #[error("unable to jump to instruction {0:?}")] InvalidJump(Instruction, Span), /// Occurs from eg `read bank9223372036854775807 5` (only `126` banks can exist) - #[error("cannot get cell>{0:?}")] + #[error("cannot get cell>{0}")] MemoryTooFar(usize, Span), + /// Occurs from eg `read bank1 512` + #[error("index {0} out of bounds ({1} max)")] + IndexOutOfBounds(usize, usize, Span), /// Occurs from `read register1` #[error("unknown memory type {0:?}, expected (cell)|(bank)")] InvalidMemoryType(&'s str, Span), @@ -217,11 +220,11 @@ impl Error<'_> { )); } Self::ExpectedVar(_, s) => { - msg!("{error}: expected a variable") + msg!("{error}: expected variable") .label(err!(s, "this was supposed to be a variable")); } Self::ExpectedIdent(_, s) => { - msg!("{error}: expected a identifier") + msg!("{error}: expected identifier") .label(err!(s, "this was supposed to be a identifier")); } Self::ExpectedJump(t, s) => { @@ -298,6 +301,10 @@ impl Error<'_> { Self::NoDisplay(disp, s) => { msg!("{error}: no display allocated").label(err!(s, "display#{disp} has not been created")).note(format!("{note}: it is impossible for me to dynamically allocate displays, as 'display1' could be large or small")); } + Self::IndexOutOfBounds(index, size, s) => { + msg!("{error}: index {index} out of bounds") + .label(err!(s, "memory has only {size} elements")); + } }; e } @@ -327,12 +334,12 @@ pub fn parse<'source, W: Wr>( }; } macro_rules! err { - ($e:ident($($stuff:expr)+)) => { + ($e:ident($($stuff:expr),+)) => { Error::$e($($stuff,)+ tokens.span()) } } macro_rules! yeet { - ($e:ident($($stuff:expr)+)) => { + ($e:ident($($stuff:expr),+)) => { return Err(Error::$e($($stuff,)+ tokens.span())) }; } @@ -499,7 +506,15 @@ pub fn parse<'source, W: Wr>( Token::Write => { let set = take_numvar!(tok!()?)?; let container = take_memory!(); - let index = container.limit(take_int!(tok!()?)?); + let index = take_numvar!(tok!()?)?; + match index { + LAddress::Const(LVar::Num(v)) => { + if !container.fits(v.round() as usize) { + yeet!(IndexOutOfBounds(v.round() as usize, container.size())); + } + } + _ => {} + } executor.add(Write { index, @@ -511,7 +526,15 @@ pub fn parse<'source, W: Wr>( Token::Read => { let output = take_var!(tok!()?)?; let container = take_memory!(); - let index = container.limit(take_int!(tok!()?)?); + let index = take_numvar!(tok!()?)?; + match index { + LAddress::Const(LVar::Num(v)) => { + if !container.fits(v.round() as usize) { + yeet!(IndexOutOfBounds(v.round() as usize, container.size())); + } + } + _ => {} + } executor.add(Read { index, output, |