mindustry logic execution, map- and schematic- parsing and rendering
optimize size of instructions
| -rw-r--r-- | lemu/src/code.rs | 4 | ||||
| -rw-r--r-- | lemu/src/executor/builder.rs | 14 | ||||
| -rw-r--r-- | lemu/src/executor/mod.rs | 34 | ||||
| -rw-r--r-- | lemu/src/instructions/draw.rs | 247 | ||||
| -rw-r--r-- | lemu/src/instructions/io.rs | 53 | ||||
| -rw-r--r-- | lemu/src/instructions/mod.rs | 203 | ||||
| -rw-r--r-- | lemu/src/lib.rs | 4 | ||||
| -rw-r--r-- | lemu/src/memory.rs | 113 | ||||
| -rw-r--r-- | lemu/src/parser/error.rs | 72 | ||||
| -rw-r--r-- | lemu/src/parser/mod.rs | 119 |
10 files changed, 457 insertions, 406 deletions
diff --git a/lemu/src/code.rs b/lemu/src/code.rs index 9132279..bf9f58e 100644 --- a/lemu/src/code.rs +++ b/lemu/src/code.rs @@ -5,8 +5,8 @@ use super::{ #[derive(Debug)] pub enum PInstr<'s> { - Instr(Instr<'s>), - Draw(DrawInstr<'s>), + Instr(Instr), + Draw(DrawInstr), Code(Box<[Token<'s>]>), Comment(&'s str), } diff --git a/lemu/src/executor/builder.rs b/lemu/src/executor/builder.rs index eae3fb2..7ed4177 100644 --- a/lemu/src/executor/builder.rs +++ b/lemu/src/executor/builder.rs @@ -21,7 +21,7 @@ pub struct ExecutorBuilderInternal<'v, W: Wr> { cells: Vec<f64>, iteration_limit: Limit, instruction_limit: Limit, - mem: usize, + pub(crate) mem: LRegistry<'v>, } impl<'s, W: Wr> ExecutorBuilderInternal<'s, W> { @@ -34,7 +34,7 @@ impl<'s, W: Wr> ExecutorBuilderInternal<'s, W> { cells: vec![], iteration_limit: Limit::limited(1), instruction_limit: Limit::Unlimited, - mem: 0, + mem: LRegistry::default(), } } @@ -81,15 +81,11 @@ impl<'s, W: Wr> ExecutorBuilderInternal<'s, W> { Instruction(self.program.len() - 1) } - pub(crate) fn mem(&mut self, size: usize) { - self.mem = size; - } - - pub(crate) fn add(&mut self, i: impl Into<Instr<'s>>) { + pub(crate) fn add(&mut self, i: impl Into<Instr>) { self.program.push(UPInstr::Instr(i.into())); } - pub(crate) fn draw(&mut self, i: impl Into<DrawInstr<'s>>) { + pub(crate) fn draw(&mut self, i: impl Into<DrawInstr>) { self.program.push(UPInstr::Draw(i.into())); } @@ -140,7 +136,7 @@ impl<'s, W: Wr> ExecutorBuilderInternal<'s, W> { inner: ExecutorContext { cells: cst::<CELL_SIZE>(cells), banks: cst::<BANK_SIZE>(banks), - memory: LRegistry::new(mem), + memory: mem, counter: 0, iterations: 0, display: Drawing { diff --git a/lemu/src/executor/mod.rs b/lemu/src/executor/mod.rs index 746ca7a..4b50cf6 100644 --- a/lemu/src/executor/mod.rs +++ b/lemu/src/executor/mod.rs @@ -113,33 +113,34 @@ pub struct Executor<'varnames, W: Write> { pub instructions_ran: usize, } +#[derive(Debug)] pub enum UPInstr<'s> { - Instr(Instr<'s>), - Draw(DrawInstr<'s>), + Instr(Instr), + Draw(DrawInstr), UnfinishedJump, Code(Box<[Token<'s>]>), Comment(&'s str), } -pub struct Drawing<'v> { +pub struct Drawing { pub displays: Box<[fimg::Image<Vec<u8>, 4>]>, /// points to `Executor.program` - pub buffer: VecDeque<*const DrawInstr<'v>>, + pub buffer: VecDeque<*const DrawInstr>, } -impl<'v> Drawing<'v> { - fn buffer(&mut self, i: &DrawInstr<'v>) { +impl<'v> Drawing { + fn buffer(&mut self, i: &DrawInstr) { self.buffer.push_back(i); } } -pub struct ExecutorContext<'varnames, W: Write> { +pub struct ExecutorContext<'strings, W: Write> { // maximum of 128 elements, so can use ~60KB pub cells: Box<[[f64; CELL_SIZE]]>, // screw world cells // maximum of 127 elements, so can use ~500KB pub banks: Box<[[f64; BANK_SIZE]]>, - pub memory: LRegistry<'varnames>, + pub memory: LRegistry<'strings>, pub counter: usize, - pub display: Drawing<'varnames>, + pub display: Drawing, pub output: Option<W>, /// Counter for the number of iterations we have run so far. pub iterations: usize, @@ -185,20 +186,20 @@ impl<'s, W: Write> ExecutorContext<'s, W> { } } - pub fn set(&mut self, a: &LAddress<'s>, b: LAddress<'s>) -> bool { - self.memory.set(a, b) + pub fn set(&mut self, a: LAddress, b: LAddress) { + self.memory[a] = self.memory[b].clone(); } - pub fn get_mut(&mut self, a: &LAddress<'s>) -> Option<&mut LVar<'s>> { - self.memory.get_mut(a) + pub fn get_mut(&mut self, a: LAddress) -> &mut LVar<'s> { + &mut self.memory[a] } pub fn jump(&mut self, Instruction(n): Instruction) { self.counter = n; } - pub fn get<'a>(&'a self, a: &'a LAddress<'s>) -> &LVar<'s> { - self.memory.get(a) + pub fn get<'a>(&'a self, a: LAddress) -> &LVar<'s> { + &self.memory[a] } } @@ -236,7 +237,7 @@ impl<'s, W: Write> Executor<'s, W> { // SAFETY: yee match unsafe { self.program.get_unchecked(self.inner.counter) } { PInstr::Instr(i) => { - // println!("run {i:?} ({:?})", self.inner.memory); + // println!("run {i:?} ({})", self.inner.memory); i.run(&mut self.inner) } PInstr::Draw(i) => { @@ -266,7 +267,6 @@ impl<'s, W: Write> Executor<'s, W> { if self.inner.counter >= self.program.len() { self.inner.counter = 0; self.inner.iterations += 1; - self.inner.memory.clear(); } } } diff --git a/lemu/src/instructions/draw.rs b/lemu/src/instructions/draw.rs index fc93d8f..04b168c 100644 --- a/lemu/src/instructions/draw.rs +++ b/lemu/src/instructions/draw.rs @@ -12,8 +12,8 @@ pub const INSTRS: &[&str] = &[ ]; #[enum_dispatch] -pub trait DrawInstruction<'v>: Disp { - fn draw( +pub trait DrawInstruction: Disp { + fn draw<'v>( &self, mem: &mut LRegistry<'v>, image: &mut Image<&mut [u8], 4>, @@ -21,21 +21,21 @@ pub trait DrawInstruction<'v>: Disp { ); } -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] #[enum_dispatch(DrawInstruction)] -pub enum DrawInstr<'v> { - Line(Line<'v>), - RectBordered(RectBordered<'v>), - RectFilled(RectFilled<'v>), - Triangle(Triangle<'v>), - Clear(Clear<'v>), - SetColor(SetColor<'v>), - SetStroke(SetStroke<'v>), - Poly(Poly<'v>), - LinePoly(LinePoly<'v>), -} - -impl Disp for DrawInstr<'_> { +pub enum DrawInstr { + Line(Line), + RectBordered(RectBordered), + RectFilled(RectFilled), + Triangle(Triangle), + Clear(Clear), + SetColor(SetColor), + SetStroke(SetStroke), + Poly(Poly), + LinePoly(LinePoly), +} + +impl Disp for DrawInstr { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { Self::Line(i) => write!(f, "{i}"), @@ -51,18 +51,24 @@ impl Disp for DrawInstr<'_> { } } -#[derive(Debug)] -pub struct Clear<'v> { - pub r: LAddress<'v>, - pub g: LAddress<'v>, - pub b: LAddress<'v>, +#[derive(Debug, Copy, Clone)] + +pub struct Clear { + pub r: LAddress, + pub g: LAddress, + pub b: LAddress, } -impl<'v> DrawInstruction<'v> for Clear<'v> { - fn draw(&self, mem: &mut LRegistry<'v>, image: &mut Image<&mut [u8], 4>, _: &mut DisplayState) { +impl DrawInstruction for Clear { + fn draw<'v>( + &self, + mem: &mut LRegistry<'v>, + image: &mut Image<&mut [u8], 4>, + _: &mut DisplayState, + ) { macro_rules! u8 { ($v:ident) => { - match mem.get(&self.$v) { + match mem.get(self.$v) { LVar::Num(n) => n.round() as u8, _ => return, } @@ -75,24 +81,30 @@ impl<'v> DrawInstruction<'v> for Clear<'v> { } } -impl Disp for Clear<'_> { +impl Disp for Clear { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "draw clear {} {} {}", self.r, self.g, self.b) } } -#[derive(Debug)] -pub struct SetColor<'v> { - pub r: LAddress<'v>, - pub g: LAddress<'v>, - pub b: LAddress<'v>, - pub a: LAddress<'v>, -} -impl<'v> DrawInstruction<'v> for SetColor<'v> { - fn draw(&self, mem: &mut LRegistry<'v>, _: &mut Image<&mut [u8], 4>, state: &mut DisplayState) { +#[derive(Debug, Copy, Clone)] + +pub struct SetColor { + pub r: LAddress, + pub g: LAddress, + pub b: LAddress, + pub a: LAddress, +} +impl DrawInstruction for SetColor { + fn draw<'v>( + &self, + mem: &mut LRegistry<'v>, + _: &mut Image<&mut [u8], 4>, + state: &mut DisplayState, + ) { macro_rules! u8 { ($v:ident) => { - match mem.get(&self.$v) { + match mem.get(self.$v) { LVar::Num(n) => n.round() as u8, _ => return, } @@ -102,36 +114,42 @@ impl<'v> DrawInstruction<'v> for SetColor<'v> { } } -impl Disp for SetColor<'_> { +impl Disp for SetColor { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "draw color {} {} {} {}", self.r, self.g, self.b, self.a) } } -#[derive(Debug)] -pub struct SetStroke<'v> { - pub size: LAddress<'v>, +#[derive(Debug, Copy, Clone)] + +pub struct SetStroke { + pub size: LAddress, } -impl<'v> DrawInstruction<'v> for SetStroke<'v> { - fn draw(&self, mem: &mut LRegistry<'v>, _: &mut Image<&mut [u8], 4>, state: &mut DisplayState) { - if let &LVar::Num(n) = mem.get(&self.size) { +impl DrawInstruction for SetStroke { + fn draw<'v>( + &self, + mem: &mut LRegistry<'v>, + _: &mut Image<&mut [u8], 4>, + state: &mut DisplayState, + ) { + if let &LVar::Num(n) = mem.get(self.size) { state.stroke = n; } } } -impl Disp for SetStroke<'_> { +impl Disp for SetStroke { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "draw stroke {}", self.size) } } -pub type Point<'v> = (LAddress<'v>, LAddress<'v>); +pub type Point = (LAddress, LAddress); #[rustfmt::skip] macro_rules! point { ($mem:ident@$point:expr) => {{ - let &LVar::Num(a) = $mem.get(&$point.0) else { return; }; - let &LVar::Num(b) = $mem.get(&$point.1) else { return; }; + let &LVar::Num(a) = $mem.get($point.0) else { return }; + let &LVar::Num(b) = $mem.get($point.1) else { return }; (a,b) }} } @@ -142,14 +160,15 @@ macro_rules! map { ($fn(a), $fn(b)) }}; } -#[derive(Debug)] -pub struct Line<'v> { - pub point_a: Point<'v>, - pub point_b: Point<'v>, +#[derive(Debug, Copy, Clone)] + +pub struct Line { + pub point_a: Point, + pub point_b: Point, } -impl<'v> DrawInstruction<'v> for Line<'v> { - fn draw( +impl DrawInstruction for Line { + fn draw<'v>( &self, mem: &mut LRegistry<'v>, image: &mut Image<&mut [u8], 4>, @@ -161,7 +180,7 @@ impl<'v> DrawInstruction<'v> for Line<'v> { } } -impl Disp for Line<'_> { +impl Disp for Line { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!( f, @@ -171,28 +190,29 @@ impl Disp for Line<'_> { } } -#[derive(Debug)] -pub struct RectFilled<'v> { - pub position: Point<'v>, - pub width: LAddress<'v>, - pub height: LAddress<'v>, +#[derive(Debug, Copy, Clone)] + +pub struct RectFilled { + pub position: Point, + pub width: LAddress, + pub height: LAddress, } -impl<'v> DrawInstruction<'v> for RectFilled<'v> { - fn draw( +impl DrawInstruction for RectFilled { + fn draw<'v>( &self, mem: &mut LRegistry<'v>, image: &mut Image<&mut [u8], 4>, state: &mut DisplayState, ) { let pos = map!(point!([email protected]), |n| n as u32); - let width = get_num!(mem.get(&self.width)) as u32; - let height = get_num!(mem.get(&self.height)) as u32; + let width = get_num!(mem.get(self.width)) as u32; + let height = get_num!(mem.get(self.height)) as u32; image.filled_box(pos, width, height, state.col()); } } -impl Disp for RectFilled<'_> { +impl Disp for RectFilled { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!( f, @@ -202,14 +222,15 @@ impl Disp for RectFilled<'_> { } } -#[derive(Debug)] -pub struct RectBordered<'v> { - pub position: Point<'v>, - pub width: LAddress<'v>, - pub height: LAddress<'v>, +#[derive(Debug, Copy, Clone)] + +pub struct RectBordered { + pub position: Point, + pub width: LAddress, + pub height: LAddress, } -impl Disp for RectBordered<'_> { +impl Disp for RectBordered { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!( f, @@ -219,26 +240,32 @@ impl Disp for RectBordered<'_> { } } -impl<'v> DrawInstruction<'v> for RectBordered<'v> { - fn draw( +impl DrawInstruction for RectBordered { + fn draw<'v>( &self, mem: &mut LRegistry<'v>, image: &mut Image<&mut [u8], 4>, state: &mut DisplayState, ) { let pos = map!(point!([email protected]), |n| n as u32); - let width = get_num!(mem.get(&self.width)) as u32; - let height = get_num!(mem.get(&self.height)) as u32; + let width = get_num!(mem.get(self.width)) as u32; + let height = get_num!(mem.get(self.height)) as u32; image.stroked_box(pos, width, height, state.stroke.round() as u32, state.col()); } } -#[derive(Debug)] -pub struct Triangle<'v> { - pub points: (Point<'v>, Point<'v>, Point<'v>), +#[derive(Debug, Copy, Clone)] + +pub struct Triangle { + pub points: (Point, Point, Point), } -impl<'v> DrawInstruction<'v> for Triangle<'v> { - fn draw(&self, mem: &mut LRegistry<'v>, i: &mut Image<&mut [u8], 4>, state: &mut DisplayState) { +impl DrawInstruction for Triangle { + fn draw<'v>( + &self, + mem: &mut LRegistry<'v>, + i: &mut Image<&mut [u8], 4>, + state: &mut DisplayState, + ) { let to32 = |n| n as f32; let (a, b, c) = ( map!(point!([email protected]), to32), @@ -248,7 +275,7 @@ impl<'v> DrawInstruction<'v> for Triangle<'v> { i.tri(a, b, c, state.col()); } } -impl Disp for Triangle<'_> { +impl Disp for Triangle { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!( f, @@ -263,41 +290,42 @@ impl Disp for Triangle<'_> { } } -#[derive(Debug)] -pub struct Poly<'v> { - pub(crate) pos: Point<'v>, - pub(crate) sides: LAddress<'v>, - pub(crate) radius: LAddress<'v>, - pub(crate) rot: LAddress<'v>, +#[derive(Debug, Copy, Clone)] + +pub struct Poly { + pub(crate) pos: Point, + pub(crate) sides: LAddress, + pub(crate) radius: LAddress, + pub(crate) rot: LAddress, } -impl<'v> DrawInstruction<'v> for Poly<'v> { - fn draw( +impl DrawInstruction for Poly { + fn draw<'v>( &self, mem: &mut LRegistry<'v>, image: &mut Image<&mut [u8], 4>, state: &mut DisplayState, ) { - let sides = get_num!(mem.get(&self.sides)).round() as usize; + let sides = get_num!(mem.get(self.sides)).round() as usize; if sides < 90 { image.poly( map!(point!([email protected]), |n| n as f32), sides, - get_num!(mem.get(&self.radius)) as f32, - get_num!(mem.get(&self.rot)) as f32, + get_num!(mem.get(self.radius)) as f32, + get_num!(mem.get(self.rot)) as f32, state.col(), ); } else { image.circle( map!(point!([email protected]), |n: f64| n.round() as i32), - get_num!(mem.get(&self.radius)).round() as i32, + get_num!(mem.get(self.radius)).round() as i32, state.col(), ); } } } -impl Disp for Poly<'_> { +impl Disp for Poly { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!( f, @@ -307,42 +335,43 @@ impl Disp for Poly<'_> { } } -#[derive(Debug)] -pub struct LinePoly<'v> { - pub(crate) pos: Point<'v>, - pub(crate) sides: LAddress<'v>, - pub(crate) radius: LAddress<'v>, - pub(crate) rot: LAddress<'v>, +#[derive(Debug, Copy, Clone)] + +pub struct LinePoly { + pub(crate) pos: Point, + pub(crate) sides: LAddress, + pub(crate) radius: LAddress, + pub(crate) rot: LAddress, } -impl<'v> DrawInstruction<'v> for LinePoly<'v> { - fn draw( +impl DrawInstruction for LinePoly { + fn draw<'v>( &self, mem: &mut LRegistry<'v>, image: &mut Image<&mut [u8], 4>, state: &mut DisplayState, ) { - let sides = get_num!(mem.get(&self.sides)).round() as usize; + let sides = get_num!(mem.get(self.sides)).round() as usize; if sides < 90 { image.border_poly( map!(point!([email protected]), |n| n as f32), sides, - get_num!(mem.get(&self.radius)) as f32, - get_num!(mem.get(&self.rot)) as f32, + get_num!(mem.get(self.radius)) as f32, + get_num!(mem.get(self.rot)) as f32, state.stroke as f32, state.col(), ); } else { image.border_circle( map!(point!([email protected]), |n: f64| n.round() as i32), - get_num!(mem.get(&self.radius)).round() as i32, + get_num!(mem.get(self.radius)).round() as i32, state.col(), ); } } } -impl Disp for LinePoly<'_> { +impl Disp for LinePoly { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!( f, @@ -352,11 +381,12 @@ impl Disp for LinePoly<'_> { } } -#[derive(Debug, Default)] +#[derive(Debug, Copy, Clone, Default)] + pub struct Flush { pub(crate) display: Display, } -impl LInstruction<'_> for Flush { +impl LInstruction for Flush { fn run<W: std::io::Write>(&self, exec: &mut ExecutorContext<'_, W>) -> Flow { exec.flush(self.display); Flow::Continue @@ -365,6 +395,7 @@ impl LInstruction<'_> for Flush { impl Disp for Flush { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "drawflush {}", self.display) + let d = self.display; + write!(f, "drawflush {d}") } } diff --git a/lemu/src/instructions/io.rs b/lemu/src/instructions/io.rs index 6e8e325..d919f5e 100644 --- a/lemu/src/instructions/io.rs +++ b/lemu/src/instructions/io.rs @@ -8,42 +8,42 @@ use std::{ io::Write as Wr, }; -#[derive(Debug)] -pub struct Read<'v> { - pub(crate) index: LAddress<'v>, - pub(crate) output: LAddress<'v>, +#[derive(Debug, Copy, Clone)] + +pub struct Read { + pub(crate) index: LAddress, + pub(crate) output: LAddress, pub(crate) container: Memory, } -impl<'v> LInstruction<'v> for Read<'v> { - fn run<W: Wr>(&self, exec: &mut ExecutorContext<'v, W>) -> Flow { - let i = get_num!(exec.get(&self.index)).round() as usize; +impl LInstruction for Read { + fn run<'v, W: Wr>(&self, exec: &mut ExecutorContext<'v, W>) -> Flow { + 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); - } + *exec.get_mut(self.output) = LVar::from(n); }; Flow::Continue } } -impl Display for Read<'_> { +impl Display for Read { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "read {} {} {}", self.output, self.container, self.index) } } -#[derive(Debug)] -pub struct Write<'v> { - pub(crate) index: LAddress<'v>, - pub(crate) set: LAddress<'v>, +#[derive(Debug, Copy, Clone)] + +pub struct Write { + pub(crate) index: LAddress, + pub(crate) set: LAddress, pub(crate) container: Memory, } -impl<'v> LInstruction<'v> for Write<'v> { - fn run<W: Wr>(&self, exec: &mut ExecutorContext<'v, W>) -> Flow { - let i = get_num!(exec.get(&self.index)).round() as usize; - if let &LVar::Num(b) = exec.get(&self.set) { +impl LInstruction for Write { + fn run<'v, W: Wr>(&self, exec: &mut ExecutorContext<'v, W>) -> Flow { + 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; } @@ -52,19 +52,20 @@ impl<'v> LInstruction<'v> for Write<'v> { } } -impl Display for Write<'_> { +impl Display for Write { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "write {} {} {}", self.set, self.container, self.index) } } -#[derive(Debug)] -pub struct Print<'v> { - pub(crate) val: LAddress<'v>, +#[derive(Debug, Copy, Clone)] + +pub struct Print { + pub(crate) val: LAddress, } -impl LInstruction<'_> for Print<'_> { +impl LInstruction for Print { fn run<W: Wr>(&self, exec: &mut ExecutorContext<'_, W>) -> Flow { - let v = exec.get(&self.val).clone(); + let v = exec.get(self.val).clone(); if let Some(o) = &mut exec.output { match v { LVar::Num(n) => write!(o, "{n}"), @@ -75,7 +76,7 @@ impl LInstruction<'_> for Print<'_> { Flow::Continue } } -impl Display for Print<'_> { +impl Display for Print { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "print {}", self.val) } diff --git a/lemu/src/instructions/mod.rs b/lemu/src/instructions/mod.rs index 7bc2c57..39507a9 100644 --- a/lemu/src/instructions/mod.rs +++ b/lemu/src/instructions/mod.rs @@ -30,7 +30,6 @@ use std::{ use super::{ executor::{ExecutorContext, Instruction}, - lexer::Token, memory::{LAddress, LVar}, }; @@ -88,27 +87,27 @@ pub enum Flow { } #[enum_dispatch] -pub trait LInstruction<'v>: Display { - fn run<W: Write>(&self, exec: &mut ExecutorContext<'v, W>) -> Flow; +pub trait LInstruction: Display { + fn run<'v, W: Write>(&self, exec: &mut ExecutorContext<'v, W>) -> Flow; } -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] #[enum_dispatch(LInstruction)] -pub enum Instr<'v> { - Op2(Op2<'v>), - Jump(Jump<'v>), - AlwaysJump(AlwaysJump<'v>), - Set(Set<'v>), - Op1(Op1<'v>), - Read(io::Read<'v>), - Write(io::Write<'v>), +pub enum Instr { + Op2(Op2), + Jump(Jump), + AlwaysJump(AlwaysJump), + Set(Set), + Op1(Op1), + Read(io::Read), + Write(io::Write), DrawFlush(draw::Flush), - DynJump(DynJump<'v>), - Print(io::Print<'v>), + DynJump(DynJump), + Print(io::Print), Stop(Stop), End(End), } -impl Display for Instr<'_> { +impl Display for Instr { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { Self::Op2(i) => write!(f, "{i}"), @@ -127,19 +126,19 @@ impl Display for Instr<'_> { } } -#[derive(Debug)] -pub struct Set<'v> { - pub(crate) from: LAddress<'v>, - pub(crate) to: LAddress<'v>, +#[derive(Debug, Copy, Clone)] +pub struct Set { + pub(crate) from: LAddress, + pub(crate) to: LAddress, } -impl<'v> LInstruction<'v> for Set<'v> { - fn run<W: Write>(&self, exec: &mut ExecutorContext<'v, W>) -> Flow { - exec.set(&self.from, self.to.clone()); +impl LInstruction for Set { + fn run<'v, W: Write>(&self, exec: &mut ExecutorContext<'v, W>) -> Flow { + exec.set(self.from, self.to.clone()); Flow::Continue } } -impl Display for Set<'_> { +impl Display for Set { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "set {} {}", self.from, self.to) } @@ -185,17 +184,15 @@ macro_rules! get_num { } use get_num; -#[derive(Debug)] -pub struct Op1<'v> { - op_id: MathOp1, - op: fn(&LVar<'v>) -> f64, - x: LAddress<'v>, - out: LAddress<'v>, +#[derive(Debug, Copy, Clone)] +pub struct Op1 { + op: for<'v> fn(&LVar<'v>) -> f64, + x: LAddress, + out: LAddress, } -impl<'v> Op1<'v> { - pub(crate) const fn new(op: MathOp1, x: LAddress<'v>, out: LAddress<'v>) -> Self { +impl<'v> Op1 { + pub(crate) const fn new(op: MathOp1, x: LAddress, out: LAddress) -> Self { Self { - op_id: op, op: op.get_fn(), x, out, @@ -203,40 +200,31 @@ impl<'v> Op1<'v> { } } -impl<'s> LInstruction<'s> for Op1<'s> { - fn run<W: Write>(&self, exec: &mut ExecutorContext<'s, W>) -> Flow { - let x = (self.op)(exec.get(&self.x)); - if let Some(y) = exec.get_mut(&self.out) { - *y = LVar::Num(x); - } +impl LInstruction for Op1 { + fn run<'s, W: Write>(&self, exec: &mut ExecutorContext<'s, W>) -> Flow { + let x = (self.op)(exec.get(self.x)); + *exec.get_mut(self.out) = LVar::Num(x); Flow::Continue } } -impl Display for Op1<'_> { +impl Display for Op1 { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let Self { op_id, x, out, .. } = self; - write!(f, "op {} {out} {x}", Token::from(*op_id)) + let Self { x, out, .. } = self; + write!(f, "op .. {out} {x}") } } -#[derive(Debug)] -pub struct Op2<'v> { - op_id: MathOp2, - op: fn(&LVar<'v>, &LVar<'v>) -> f64, - a: LAddress<'v>, - b: LAddress<'v>, - out: LAddress<'v>, +#[derive(Debug, Copy, Clone)] +pub struct Op2 { + op: for<'v> fn(&LVar<'v>, &LVar<'v>) -> f64, + a: LAddress, + b: LAddress, + out: LAddress, } -impl<'v> Op2<'v> { - pub(crate) const fn new( - op: MathOp2, - a: LAddress<'v>, - b: LAddress<'v>, - out: LAddress<'v>, - ) -> Self { +impl Op2 { + pub(crate) const fn new(op: MathOp2, a: LAddress, b: LAddress, out: LAddress) -> Self { Self { - op_id: op, op: op.get_fn(), a, b, @@ -245,31 +233,26 @@ impl<'v> Op2<'v> { } } -impl<'v> LInstruction<'v> for Op2<'v> { - fn run<W: Write>(&self, exec: &mut ExecutorContext<'v, W>) -> Flow { - let x = (self.op)(exec.get(&self.a), exec.get(&self.b)); - if let Some(y) = exec.get_mut(&self.out) { - *y = LVar::from(x); - } +impl LInstruction for Op2 { + fn run<'v, W: Write>(&self, exec: &mut ExecutorContext<'v, W>) -> Flow { + let x = (self.op)(exec.get(self.a), exec.get(self.b)); + exec.memory[self.out] = LVar::Num(x); Flow::Continue } } -impl Display for Op2<'_> { +impl Display for Op2 { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let Self { - op_id, a, b, out, .. - } = self; - write!(f, "op {} {out} {a} {b}", Token::from(*op_id)) + let Self { a, b, out, .. } = self; + write!(f, "op .. {out} {a} {b}") } } -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] pub struct End {} -impl LInstruction<'_> for End { +impl LInstruction for End { fn run<W: Write>(&self, exec: &mut ExecutorContext<'_, W>) -> Flow { - exec.memory.clear(); exec.iterations += 1; // SAFETY: if we exist, 0 exists. unsafe { exec.jump(Instruction::new(0)) }; @@ -283,48 +266,34 @@ impl Display for End { } } -#[derive(Debug)] -pub struct AlwaysJump<'s> { +#[derive(Debug, Copy, Clone)] +pub struct AlwaysJump { pub(crate) to: Instruction, - pub(crate) label: Option<&'s str>, } -impl LInstruction<'_> for AlwaysJump<'_> { +impl LInstruction for AlwaysJump { fn run<W: Write>(&self, exec: &mut ExecutorContext<'_, W>) -> Flow { exec.jump(self.to); Flow::Stay } } -impl Display for AlwaysJump<'_> { +impl Display for AlwaysJump { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self.label { - None => write!(f, "jump {} always", self.to.get()), - Some(l) => write!(f, "jump {l} always"), - } + write!(f, "jump {} always", self.to.get()) } } -#[derive(Debug)] -pub struct Jump<'v> { - label: Option<&'v str>, - op_id: ConditionOp, - op: fn(&LVar<'v>, &LVar<'v>) -> bool, +#[derive(Debug, Copy, Clone)] +pub struct Jump { + op: for<'v> fn(&LVar<'v>, &LVar<'v>) -> bool, pub(crate) to: Instruction, - a: LAddress<'v>, - b: LAddress<'v>, + a: LAddress, + b: LAddress, } -impl<'v> Jump<'v> { - pub fn new( - op: ConditionOp, - to: Instruction, - a: LAddress<'v>, - b: LAddress<'v>, - label: Option<&'v str>, - ) -> Self { +impl Jump { + pub fn new(op: ConditionOp, to: Instruction, a: LAddress, b: LAddress) -> Self { Self { - op_id: op, op: op.get_fn(), - label, to, a, b, @@ -332,9 +301,9 @@ impl<'v> Jump<'v> { } } -impl<'v> LInstruction<'v> for Jump<'v> { - fn run<W: Write>(&self, exec: &mut ExecutorContext<'v, W>) -> Flow { - if (self.op)(exec.get(&self.a), exec.get(&self.b)) { +impl LInstruction for Jump { + fn run<'v, W: Write>(&self, exec: &mut ExecutorContext<'v, W>) -> Flow { + if (self.op)(exec.get(self.a), exec.get(self.b)) { exec.jump(self.to); Flow::Stay } else { @@ -343,34 +312,22 @@ impl<'v> LInstruction<'v> for Jump<'v> { } } -impl Display for Jump<'_> { +impl Display for Jump { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let Self { - op_id, - label, - to, - a, - b, - .. - } = self; - write!(f, "jump ")?; - match label { - Some(v) => write!(f, "{v} "), - None => write!(f, "{} ", to.get()), - }?; - write!(f, "{} {a} {b}", Token::from(*op_id)) + let Self { to, a, b, .. } = self; + write!(f, "jump .. {} {a} {b}", to.get()) } } -#[derive(Debug)] -pub struct DynJump<'v> { - pub to: LAddress<'v>, +#[derive(Debug, Copy, Clone)] +pub struct DynJump { + pub to: LAddress, pub proglen: usize, } -impl<'v> LInstruction<'v> for DynJump<'v> { - fn run<W: Write>(&self, exec: &mut ExecutorContext<'v, W>) -> Flow { - if let &LVar::Num(n) = exec.get(&self.to) { +impl LInstruction for DynJump { + fn run<'v, W: Write>(&self, exec: &mut ExecutorContext<'v, W>) -> Flow { + if let &LVar::Num(n) = exec.get(self.to) { let i = n.round() as usize; if i < self.proglen { // SAFETY: just checked bounds @@ -382,15 +339,15 @@ impl<'v> LInstruction<'v> for DynJump<'v> { } } -impl Display for DynJump<'_> { +impl Display for DynJump { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "set @counter {}", self.to) } } -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] pub struct Stop {} -impl LInstruction<'_> for Stop { +impl LInstruction for Stop { fn run<W: Write>(&self, _: &mut ExecutorContext<'_, W>) -> Flow { Flow::Exit } diff --git a/lemu/src/lib.rs b/lemu/src/lib.rs index ba643aa..d4c0f71 100644 --- a/lemu/src/lib.rs +++ b/lemu/src/lib.rs @@ -1,5 +1,5 @@ //! crate for [MLOG](https://mindustrygame.github.io/wiki/logic/0-introduction/#what-is-mindustry-logic) emulation. -#![feature(let_chains, trace_macros)] +#![feature(let_chains, inline_const)] #![allow(clippy::redundant_closure_call)] #![warn( clippy::multiple_unsafe_ops_per_block, @@ -177,6 +177,6 @@ mod test { test!(run fib.mlog; output = b"12586269025"); test!(run primes.mlog; output = b"2 | 3 | 5 | 7 | 11 | 13 | 17 | 19 | 23 | 29 | 31 | 37 | 41 | 43 | 47 | 53 | 59 | 61 | 67 | 71 | 73 | 79 | 83 | 89 | 97 | 101 | 103 | 107 | 109 | 113 | 127 | 131 | 137 | 139 | 149 | 151 | 157 | 163 | 167 | 173 | 179 | 181 | 191 | 193 | 197 | 199 | 211 | 223 | 227 | 229 | 233 | 239 | 241 | 251 | 257 | 263 | 269 | 271 | 277 | 281 | 283 | 293 | 307 | 311 | 313 | 317 | 331 | 337 | 347 | 349 | 353 | 359 | 367 | 373 | 379 | 383 | 389 | 397 | 401 | 409 | 419 | 421 | 431 | 433 | 439 | 443 | 449 | 457 | 461 | 463 | 467 | 479 | 487 | 491 | 499 | 503 | 509 | "); test!(run numbers.mlog; output = b"121212"); - test!(run celliterate.mlog 500 times; cell[0][0] = 500.0); + test!(run celliterate.mlog 5 times; cell[0][0] = 5.0); test!(run hello.mlog; output = b"hello world"); } diff --git a/lemu/src/memory.rs b/lemu/src/memory.rs index 052314f..b71e44e 100644 --- a/lemu/src/memory.rs +++ b/lemu/src/memory.rs @@ -15,6 +15,12 @@ impl PartialEq for LVar<'_> { } } +impl Default for LVar<'static> { + fn default() -> Self { + Self::Num(0.0) + } +} + impl LVar<'_> { // get null pub const fn null() -> LVar<'static> { @@ -22,22 +28,14 @@ impl LVar<'_> { } } -#[derive(Clone)] -pub enum LAddress<'str> { - Const(LVar<'str>), - Address(usize, &'str str, Priv), +#[derive(Clone, Copy)] +pub struct LAddress { + pub address: u8, } -impl<'v> LAddress<'v> { - /// # Safety - /// - /// you must make sure that addr is in bounds of the memory. - pub(crate) const unsafe fn addr(addr: usize, name: &'v str) -> Self { - LAddress::Address(addr, name, Priv { _priv: () }) - } - - pub(crate) fn cnst(c: impl Into<LVar<'v>>) -> Self { - Self::Const(c.into()) +impl LAddress { + pub(crate) const fn addr(address: u8) -> Self { + LAddress { address } } } @@ -46,21 +44,15 @@ pub struct Priv { _priv: (), } -impl std::fmt::Debug for LAddress<'_> { +impl std::fmt::Debug for LAddress { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Const(c) => write!(f, "{c}"), - Self::Address(n, name, ..) => write!(f, "{name}@0x{n:x}"), - } + write!(f, "{:x}", self.address) } } -impl std::fmt::Display for LAddress<'_> { +impl std::fmt::Display for LAddress { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Const(c) => write!(f, "{c}"), - Self::Address(_, n, ..) => write!(f, "{n}"), - } + write!(f, "{:x}", self.address) } } @@ -104,54 +96,49 @@ impl<'s> From<Cow<'s, str>> for LVar<'s> { } /// cleared every loop -#[derive(Default, Debug)] -pub struct LRegistry<'str>(Box<[LVar<'str>]>); +#[derive(Debug)] +pub struct LRegistry<'str>(pub [LVar<'str>; 255]); -impl<'s> LRegistry<'s> { - pub fn new(size: usize) -> Self { - Self(vec![LVar::null(); size].into_boxed_slice()) +impl<'s> std::ops::Index<LAddress> for LRegistry<'s> { + type Output = LVar<'s>; + + fn index(&self, index: LAddress) -> &Self::Output { + &self.0[index.address as usize] } +} - pub fn clear(&mut self) { - for var in &mut *self.0 { - *var = LVar::null(); - } +impl<'s> std::ops::IndexMut<LAddress> for LRegistry<'s> { + fn index_mut(&mut self, index: LAddress) -> &mut Self::Output { + &mut self.0[index.address as usize] } +} - pub fn get<'a>(&'a self, a: &'a LAddress<'s>) -> &LVar<'s> { - match a { - // SAFETY: addr constructor requires bounds - LAddress::Address(n, ..) => unsafe { self.0.get_unchecked(*n) }, - LAddress::Const(n) => n, - } +impl<'s> Default for LRegistry<'s> { + fn default() -> Self { + Self([const { LVar::null() }; 255]) } +} - pub fn set(&mut self, a: &LAddress<'s>, b: LAddress<'s>) -> bool { - match a { - LAddress::Const(_) => false, - LAddress::Address(v, ..) => { - match b { - LAddress::Const(n) => { - // SAFETY: v comes from Address, therefore safe - *unsafe { self.0.get_unchecked_mut(*v) } = n; - } - LAddress::Address(n, ..) => { - // SAFETY: n comes from Address, therefore safe - let b = unsafe { self.0.get_unchecked(n).clone() }; - // SAFETY: v comes from Addr, therefore safe - *unsafe { self.0.get_unchecked_mut(*v) } = b; - } - }; - true - } +impl std::fmt::Display for LRegistry<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "R[")?; + let mut iter = self + .0 + .iter() + .enumerate() + .filter(|&(_, v)| v != &LVar::null()); + if let Some((i, v)) = iter.next() { + write!(f, "{i}: {v}")?; + } + while let Some((i, v)) = iter.next() { + write!(f, ", {i}: {v}")?; } + write!(f, "]") } +} - pub fn get_mut(&mut self, a: &LAddress<'s>) -> Option<&mut LVar<'s>> { - match a { - LAddress::Const(_) => None, - // SAFETY: addr constructor requires bounds - LAddress::Address(n, ..) => Some(unsafe { self.0.get_unchecked_mut(*n) }), - } +impl<'s> LRegistry<'s> { + pub fn get<'a>(&'a self, a: LAddress) -> &LVar { + &self[a] } } diff --git a/lemu/src/parser/error.rs b/lemu/src/parser/error.rs index b9ffb66..658f236 100644 --- a/lemu/src/parser/error.rs +++ b/lemu/src/parser/error.rs @@ -144,6 +144,9 @@ pub enum Error<'s> { /// .display(); /// ``` NoDisplay(usize, Span), + /// We have a limit of [`u8::MAX`] variables. + #[error("too many variables")] + TooManyVariables(Span), } impl Error<'_> { @@ -172,11 +175,14 @@ impl Error<'_> { write!(out, ", {}", op).unwrap(); } out.write_char('}').unwrap(); - if let Some((mat,score)) = rust_fuzzy_search::fuzzy_search_best_n($op, $ops, 1).first() && *score > 0.5 { + if let Some((mat, score)) = + rust_fuzzy_search::fuzzy_search_best_n($op, $ops, 1).first() + && *score > 0.5 + { e.note(cmt!("{help}: you may have meant {bold_green}{mat}{reset}")); } out - }} + }}; } match self { Self::UnexpectedEof => { @@ -220,7 +226,12 @@ impl Error<'_> { Self::ExpectedOp(t, s) => { msg!("{error}: expected operator") .label((s, cmt!("this was supposed to be a {bold_blue}operator{reset} (eg. {magenta}equal{reset})"))); - if let Some(i) = tokstr!(*t) && let Some((mat,score)) = rust_fuzzy_search::fuzzy_search_best_n(i, crate::instructions::OPS, 1).first() && *score > 0.5 { + if let Some(i) = tokstr!(*t) + && let Some((mat, score)) = + rust_fuzzy_search::fuzzy_search_best_n(i, crate::instructions::OPS, 1) + .first() + && *score > 0.5 + { e.note(cmt!("{help}: maybe you meant {bold_green}{mat}{reset}")); } } @@ -236,9 +247,53 @@ impl Error<'_> { Self::ExpectedInstr(t, s) => { msg!("{error}: expected instruction") .label((s, cmt!("this was supposed to be a {bold_blue}instruction{reset} (eg. {magenta}print{reset})"))); - if let Some(i) = tokstr!(*t) && let Some((mat,score)) = rust_fuzzy_search::fuzzy_search_best_n(i, &[ - "getlink", "read", "write", "set", "op", "end", "drawflush", "draw", "print", "packcolor", "jump", "stop", "printflush", "control", "radar", "sensor", "wait", "lookup", "packcolor", "ubind", "ucontrol", "uradar", "ulocate", "getblock", "setblock", "spawn", "status", "spawnwave", "setrule", "cutscene", "explosion", "setrate", "fetch", "getflag", "setflag", "setprop", "effect" - ], 1).first() && *score > 0.5 { + if let Some(i) = tokstr!(*t) + && let Some((mat, score)) = rust_fuzzy_search::fuzzy_search_best_n( + i, + &[ + "getlink", + "read", + "write", + "set", + "op", + "end", + "drawflush", + "draw", + "print", + "packcolor", + "jump", + "stop", + "printflush", + "control", + "radar", + "sensor", + "wait", + "lookup", + "packcolor", + "ubind", + "ucontrol", + "uradar", + "ulocate", + "getblock", + "setblock", + "spawn", + "status", + "spawnwave", + "setrule", + "cutscene", + "explosion", + "setrate", + "fetch", + "getflag", + "setflag", + "setprop", + "effect", + ], + 1, + ) + .first() + && *score > 0.5 + { e.note(cmt!("{help}: maybe you meant {mat}")); } } @@ -376,6 +431,11 @@ impl Error<'_> { msg!("{error}: {bold_red}index{reset} {} out of bounds", index) .label((s, cmt!("memory has only {magenta}{size}{reset} elements"))); } + Self::TooManyVariables(s) => { + msg!("{error}: {bold_red}too many variables{reset}. ") + .label((s, cmt!("we only have 255 variable slots"))) + .note(cmt!("consider not using variables")); + } }; e } diff --git a/lemu/src/parser/mod.rs b/lemu/src/parser/mod.rs index 1091a82..077b35e 100644 --- a/lemu/src/parser/mod.rs +++ b/lemu/src/parser/mod.rs @@ -81,10 +81,10 @@ macro_rules! tokstr { use tokstr; #[derive(Debug)] -enum UJump<'v> { +enum UJump { Sometimes { - a: LAddress<'v>, - b: LAddress<'v>, + a: LAddress, + b: LAddress, op: ConditionOp, }, Always, @@ -94,7 +94,39 @@ pub fn parse<'source, W: Wr>( mut tokens: Lexer<'source>, executor: &mut ExecutorBuilderInternal<'source, W>, ) -> Result<(), Error<'source>> { - let mut mem = Vec::new(); // maps &str to usize + let mut used = 0u8; + let mut mem: [Option<&str>; 255] = [None; 255]; // maps &str to usize + macro_rules! push { + ($var:expr) => {{ + mem[used as usize] = Some($var); + used = used + .checked_add(1) + .ok_or(Error::TooManyVariables(tokens.span()))?; + Ok(LAddress::addr(used - 1)) + }}; + (const $var:expr) => {{ + executor.mem[LAddress::addr(used)] = LVar::from($var); + used = used + .checked_add(1) + .ok_or(Error::TooManyVariables(tokens.span()))?; + Ok(LAddress::addr(used - 1)) + }}; + } + macro_rules! addr { + ($val:expr) => {{ + let val = $val; + match mem + .iter() + .zip(0..used) + .find(|(&v, _)| v == Some(val)) + .map(|(_, i)| i) + { + Some(n) => Ok(LAddress::addr(n)), + None => push!(val), + } + }}; + } + // maps "start" to 0 let mut labels = Vec::new(); let mut unfinished_jumps = Vec::new(); @@ -113,7 +145,7 @@ pub fn parse<'source, W: Wr>( return Err(Error::$e($($stuff,)+ tokens.span())) }; } - #[rustfmt::skip] + #[rustfmt::skip] macro_rules! nextline { () => { while let Some(tok) = tokens.next() && tok != Token::Newline { } @@ -161,25 +193,6 @@ pub fn parse<'source, W: Wr>( } }}; } - macro_rules! addr { - ($n:expr) => {{ - let n = $n; - match mem - .iter() - .enumerate() - .find(|(_, &v)| v == n) - .map(|(i, _)| i) - { - // SAFETY: we tell it the size is mem.len(); i comes from mem, this is fine - Some(i) => unsafe { LAddress::addr(i, n) }, - None => { - mem.push(n); - // SAFETY: see above - unsafe { LAddress::addr(mem.len() - 1, n) } - } - } - }}; - } macro_rules! take_ident { ($tok:expr) => {{ let tok = $tok; @@ -190,11 +203,11 @@ pub fn parse<'source, W: Wr>( ($tok:expr) => {{ let tok = $tok; if let Some(i) = tokstr!(tok) { - Ok(addr!(i)) + addr!(i) } else { match tok { - Token::Num(n) => Ok(LAddress::cnst(n)), - Token::String(s) => Ok(LAddress::cnst(s)), + Token::Num(n) => push!(const n), + Token::String(s) => push!(const s), t => Err(err!(ExpectedVar(t))), } } @@ -204,10 +217,10 @@ pub fn parse<'source, W: Wr>( ($tok:expr) => {{ let tok = $tok; if let Some(i) = tokstr!(tok) { - Ok(addr!(i)) + addr!(i) } else { match tok { - Token::Num(n) => Ok(LAddress::cnst(n)), + Token::Num(n) => push!(const n), t => Err(err!(ExpectedNum(t))), } } @@ -233,7 +246,7 @@ pub fn parse<'source, W: Wr>( let to = take_numvar!(tok!()?)?; executor.add(DynJump { to, proglen: 0 }); } else { - let from = addr!(take_ident!(from)?); + let from = addr!(take_ident!(from)?)?; let to = take_var!(tok!()?)?; executor.add(Set { from, to }); } @@ -268,12 +281,12 @@ pub fn parse<'source, W: Wr>( let to = unsafe { Instruction::new(n) }; let op = tok!()?; if op == Token::Always { - executor.add(AlwaysJump { to, label: None }); + executor.add(AlwaysJump { to }); } else { let op = op.try_into().map_err(|op| err!(ExpectedOp(op)))?; let a = take_var!(tok!()?)?; let b = take_var!(tok!()?)?; - executor.add(Jump::new(op, to, a, b, None)); + executor.add(Jump::new(op, to, a, b)); } } else { yeet!(ExpectedJump(tok)); @@ -301,7 +314,9 @@ pub fn parse<'source, W: Wr>( let set = take_numvar!(tok!()?)?; let container = take_memory!(); let index = take_numvar!(tok!()?)?; - if let LAddress::Const(LVar::Num(v)) = index && !container.fits(v.round() as usize) { + if let LVar::Num(v) = executor.mem[index] + && !container.fits(v.round() as usize) + { yeet!(IndexOutOfBounds(v.round() as usize, container.size())); } executor.add(Write { @@ -315,7 +330,9 @@ pub fn parse<'source, W: Wr>( let output = take_var!(tok!()?)?; let container = take_memory!(); let index = take_numvar!(tok!()?)?; - if let LAddress::Const(LVar::Num(v)) = index && !container.fits(v.round() as usize) { + if let LVar::Num(v) = executor.mem[index] + && !container.fits(v.round() as usize) + { yeet!(IndexOutOfBounds(v.round() as usize, container.size())); } executor.add(Read { @@ -352,12 +369,13 @@ pub fn parse<'source, W: Wr>( let g = col & 0x00ff_0000 >> 16; let b = col & 0x0000_ff00 >> 8; let a = col & 0x0000_00ff; - executor.draw(SetColor { - r: LAddress::cnst(r), - g: LAddress::cnst(g), - b: LAddress::cnst(b), - a: LAddress::cnst(a), - }); + let i = SetColor { + r: push!(const r)?, + g: push!(const g)?, + b: push!(const b)?, + a: push!(const a)?, + }; + executor.draw(i); } "stroke" => { let size = take_numvar!(tok!()?)?; @@ -416,7 +434,9 @@ pub fn parse<'source, W: Wr>( } Token::DrawFlush => { let t = tok!(); - if let Ok(t) = t && t != Token::Newline { + if let Ok(t) = t + && t != Token::Newline + { let screen = take_ident!(t.clone())?; let mut out = String::new(); for ch in screen.chars() { @@ -433,7 +453,9 @@ pub fn parse<'source, W: Wr>( yeet!(InvalidDisplayType(screen)); } let n_span = tokens.span().start + screen.len()..tokens.span().end; - let screen_n = out.parse::<usize>().map_err(|_| Error::ExpectedInt(t, n_span.clone()))?; + let screen_n = out + .parse::<usize>() + .map_err(|_| Error::ExpectedInt(t, n_span.clone()))?; let display = executor .display(screen_n) .map_err(|n| Error::NoDisplay(n, n_span))?; @@ -733,7 +755,9 @@ pub fn parse<'source, W: Wr>( "effect" => { let mut v = Vec::with_capacity(6); v.push(Token::Ident("effect")); - while let Some(tok) = tokens.next() && tok != Token::Newline { + while let Some(tok) = tokens.next() + && tok != Token::Newline + { v.push(tok); } executor.code(v.into_boxed_slice()); @@ -755,11 +779,8 @@ pub fn parse<'source, W: Wr>( .ok_or_else(|| Error::LabelNotFound(label, s))? .1; executor.program[i.get()] = UPInstr::Instr(match j { - UJump::Always => Instr::from(AlwaysJump { - to, - label: Some(label), - }), - UJump::Sometimes { a, b, op } => Instr::from(Jump::new(op, to, a, b, Some(label))), + UJump::Always => Instr::from(AlwaysJump { to }), + UJump::Sometimes { a, b, op } => Instr::from(Jump::new(op, to, a, b)), }); } @@ -783,7 +804,5 @@ pub fn parse<'source, W: Wr>( } } - executor.mem(mem.len()); - Ok(()) } |