mindustry logic execution, map- and schematic- parsing and rendering
Diffstat (limited to 'lemu/src/executor/mod.rs')
| -rw-r--r-- | lemu/src/executor/mod.rs | 320 |
1 files changed, 0 insertions, 320 deletions
diff --git a/lemu/src/executor/mod.rs b/lemu/src/executor/mod.rs deleted file mode 100644 index 0989bc0..0000000 --- a/lemu/src/executor/mod.rs +++ /dev/null @@ -1,320 +0,0 @@ -mod builder; -const COUNTER: LAddress = unsafe { LAddress::addr(0) }; -use crate::{ - debug::{info::DebugInfo, printable::Printable}, - instructions::draw::Drawn, -}; - -use super::{ - code::{Code, PInstr}, - instructions::{DrawInstr, Flow, Frozen, Instr, LInstruction}, - lexer::Token, - memory::{LAddress, LRegistry, LVar}, -}; -pub use builder::ExecutorBuilderInternal; -use fimg::Image; -use std::{collections::VecDeque, io::Write, num::NonZeroUsize}; - -#[derive(Debug, Copy, Clone, Default)] -pub struct Display(pub usize); - -impl std::fmt::Display for Display { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "display{}", self.0 + 1) - } -} - -#[derive(Debug, Copy, Clone)] -pub enum Memory { - Cell(u8), - Bank(u8), -} - -impl Memory { - pub(crate) const fn fits(self, i: usize) -> bool { - match self { - Self::Bank(_) => i < BANK_SIZE, - Self::Cell(_) => i < CELL_SIZE, - } - } - - pub(crate) const fn size(&self) -> usize { - match self { - Self::Bank(_) => BANK_SIZE, - Self::Cell(_) => CELL_SIZE, - } - } -} - -impl std::fmt::Display for Memory { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Bank(n) => write!(f, "bank{}", n + 1), - Self::Cell(n) => write!(f, "cell{}", n + 1), - } - } -} - -pub const BANK_SIZE: usize = 512; -pub const CELL_SIZE: usize = 64; - -#[derive(Copy, Clone, PartialEq, Eq)] -pub struct Instruction(usize); - -impl Instruction { - /// # Safety - /// verify n is valid. - pub const unsafe fn new(n: usize) -> Self { - Self(n) - } - - pub const fn get(self) -> usize { - self.0 - } -} - -impl std::fmt::Debug for Instruction { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Instruction#{}", self.0) - } -} - -#[derive(Debug, Copy, Clone)] -pub enum Limit { - /// limited to n - Limited(NonZeroUsize), - /// unlimited - Unlimited, -} - -impl Limit { - /// panics if n != 0 - pub fn limited(n: usize) -> Self { - Self::Limited(n.try_into().expect("nonzero")) - } -} - -impl Limit { - pub(crate) const fn reached(self, n: usize) -> bool { - match self { - Self::Limited(v) => v.get() <= n, - Self::Unlimited => false, - } - } -} - -/// One time use logic executor. -pub struct Executor<'varnames, W: Write> { - /// if limited, will run n instructions before exiting. - pub instruction_limit: Limit, - /// if limtited, will loop(go from a end to the start) n times before exiting - /// both unlimited does not mean this function will never return; - /// a `Stop` instruction will break the loop. - pub iteration_limit: Limit, - pub(crate) inner: ExecutorContext<'varnames, W>, - /// gets pointed to by drawbuf (pls no move) - pub(crate) program: Code<'varnames>, - /// Counter for the number of instructions we have run so far. - pub instructions_ran: usize, - debug_info: DebugInfo<'varnames>, -} - -impl<W: Write> std::fmt::Display for Executor<'_, W> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.program.print(&self.debug_info, f) - } -} - -#[derive(Debug)] -pub enum UPInstr<'s> { - Instr(Instr), - Draw(DrawInstr), - UnfinishedJump, - Code(Box<[Token<'s>]>), - Comment(&'s str), -} - -pub struct Drawing { - pub displays: Box<[(fimg::Image<Vec<u8>, 4>, DisplayState)]>, - pub buffer: VecDeque<Drawn>, -} - -impl Drawing { - fn buffer(&mut self, i: Drawn) { - self.buffer.push_back(i); - } -} -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<'strings>, - pub display: Drawing, - pub output: Option<W>, - /// Counter for the number of iterations we have run so far. - pub iterations: usize, -} - -/// State of a display. -#[derive(Debug)] -pub struct DisplayState { - /// Color to draw - pub color: (u8, u8, u8, u8), - /// Stroke to draw - pub stroke: f64, -} - -impl DisplayState { - pub const fn col(&self) -> [u8; 4] { - [self.color.0, self.color.1, self.color.2, self.color.3] - } -} - -impl Default for DisplayState { - fn default() -> Self { - Self { - color: Default::default(), - stroke: 5.0, - } - } -} - -impl<'s, W: Write> ExecutorContext<'s, W> { - pub fn flush(&mut self, to: Display) { - let (img, state) = &mut self.display.displays[to.0]; - while let Some(d) = self.display.buffer.pop_front() { - use crate::instructions::draw::Apply; - #[cfg(feature = "debug")] - comat::cprintln!("{d:blue}"); - d.apply(img.as_mut(), state); - } - } - - pub fn mem(&mut self, m: Memory) -> &mut [f64] { - match m { - Memory::Bank(m) => &mut self.banks[m as usize], - Memory::Cell(m) => &mut self.cells[m as usize], - } - } - - pub fn set(&mut self, a: LAddress, b: LAddress) { - self.memory[a] = self.memory[b].clone(); - } - - 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 as f64; - } - - pub fn counter(&mut self) -> &mut f64 { - unsafe { - self.memory - .0 - .get_unchecked_mut(0) - .num_mut() - .unwrap_unchecked() - } - } - - pub fn get<'a>(&'a self, a: LAddress) -> &LVar<'s> { - &self.memory[a] - } -} - -/// Returned by the [`output`](Executor::output).function. -pub struct Output<W: Write> { - /// Everything created by a `print` instruction. - pub output: Option<W>, - /// Logic displays that were drawn with `draw` instructions. - pub displays: Box<[(Image<Vec<u8>, 4>, DisplayState)]>, - /// Memory banks, written to with the `write`/`read` instructions - pub cells: Box<[[f64; CELL_SIZE]]>, - /// Memory cells, written to with the `write`/`read` instructions - pub banks: Box<[[f64; BANK_SIZE]]>, -} - -impl<'s, W: Write> Executor<'s, W> { - /// Consume this executor, returning all output. - pub fn output(mut self) -> Output<W> { - for (display, _) in &mut *self.inner.display.displays { - // TODO make the instructions draw flipped-ly - display.flip_v(); - } - Output { - output: self.inner.output, - displays: self.inner.display.displays, - cells: self.inner.cells, - banks: self.inner.banks, - } - } - - /// # Safety - /// - /// `counter` *must* be in bounds. - unsafe fn run_current(&mut self) -> Flow { - // SAFETY: yee - let c = self.inner.counter(); - let i = unsafe { self.program.get_unchecked(*c as usize) }; - *c += 1.0; - match i { - PInstr::Instr(i) => { - #[cfg(feature = "debug")] - { - let mut instr = String::new(); - i.print(&self.debug_info, &mut instr).unwrap(); - let mut mem = String::new(); - self.inner.memory.print(&self.debug_info, &mut mem).unwrap(); - comat::cprintln!( - "{black}{:0<2} | {green}{instr} {black}({mem}){reset}", - self.inner.counter(), - ); - } - - i.run(&mut self.inner) - } - PInstr::Draw(i) => { - if let Some(i) = i.freeze(&self.inner.memory) { - #[cfg(feature = "debug")] - { - let mut mem = String::new(); - self.inner.memory.print(&self.debug_info, &mut mem).unwrap(); - comat::cprintln!( - "{black}{:0<2} | {magenta}{i} {black}({mem}){reset}", - self.inner.counter() - ); - } - self.inner.display.buffer(i) - } - Flow::Continue - } - _ => Flow::Continue, - } - } - - /// Begin code execution. - pub fn run(&mut self) { - while !self.instruction_limit.reached(self.instructions_ran) - && !self.iteration_limit.reached(self.inner.iterations) - { - // SAFETY: we have a check - match unsafe { self.run_current() } { - Flow::Continue => {} - Flow::Exit => break, - Flow::Stay => { - self.instructions_ran += 1; - continue; - } - }; - self.instructions_ran += 1; - let c = self.inner.counter(); - if *c as usize >= self.program.len() { - *c = 0.0; - self.inner.iterations += 1; - } - } - } -} |