mindustry logic execution, map- and schematic- parsing and rendering
| -rw-r--r-- | lemu/src/code.rs | 18 | ||||
| -rw-r--r-- | lemu/src/debug/info.rs | 77 | ||||
| -rw-r--r-- | lemu/src/debug/mod.rs | 2 | ||||
| -rw-r--r-- | lemu/src/debug/printable.rs | 7 | ||||
| -rw-r--r-- | lemu/src/executor/builder.rs | 11 | ||||
| -rw-r--r-- | lemu/src/executor/mod.rs | 27 | ||||
| -rw-r--r-- | lemu/src/instructions/cop.rs | 21 | ||||
| -rw-r--r-- | lemu/src/instructions/draw.rs | 146 | ||||
| -rw-r--r-- | lemu/src/instructions/io.rs | 37 | ||||
| -rw-r--r-- | lemu/src/instructions/mod.rs | 148 | ||||
| -rw-r--r-- | lemu/src/instructions/mop.rs | 36 | ||||
| -rw-r--r-- | lemu/src/instructions/mop2.rs | 73 | ||||
| -rw-r--r-- | lemu/src/lib.rs | 5 | ||||
| -rw-r--r-- | lemu/src/memory.rs | 43 | ||||
| -rw-r--r-- | lemu/src/parser/mod.rs | 24 |
15 files changed, 439 insertions, 236 deletions
diff --git a/lemu/src/code.rs b/lemu/src/code.rs index bf9f58e..b57cb55 100644 --- a/lemu/src/code.rs +++ b/lemu/src/code.rs @@ -1,3 +1,5 @@ +use crate::debug::{info::DebugInfo, printable::Printable}; + use super::{ instructions::{DrawInstr, Instr}, lexer::Token, @@ -11,11 +13,11 @@ pub enum PInstr<'s> { Comment(&'s str), } -impl std::fmt::Display for PInstr<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl Printable for PInstr<'_> { + fn print(&self, info: &DebugInfo<'_>, f: &mut impl std::fmt::Write) -> std::fmt::Result { match self { - Self::Instr(i) => write!(f, "{i}"), - Self::Draw(i) => write!(f, "{i}"), + Self::Instr(i) => i.print(info, f), + Self::Draw(i) => i.print(info, f), Self::Code(c) => { let mut toks = c.iter(); if let Some(t) = toks.next() { @@ -31,16 +33,18 @@ impl std::fmt::Display for PInstr<'_> { } } -impl std::fmt::Display for Code<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl Printable for Code<'_> { + fn print(&self, info: &DebugInfo<'_>, f: &mut impl std::fmt::Write) -> std::fmt::Result { for instr in &*self.0 { - writeln!(f, "{instr}")?; + instr.print(info, f)?; + writeln!(f)?; } Ok(()) } } #[repr(transparent)] +#[derive(Debug)] pub struct Code<'s>(Box<[PInstr<'s>]>); // Pin requires diff --git a/lemu/src/debug/info.rs b/lemu/src/debug/info.rs new file mode 100644 index 0000000..6f370ba --- /dev/null +++ b/lemu/src/debug/info.rs @@ -0,0 +1,77 @@ +use std::ops::Range; + +use crate::{ + executor::Instruction, + memory::{LAddress, LVar}, +}; + +pub struct DebugInfo<'s> { + variables: Box<[Option<VarInfo<'s>>; 255]>, + /// maps "start" to 0 + pub labels: Vec<(&'s str, Instruction)>, +} + +impl<'s> Default for DebugInfo<'s> { + fn default() -> Self { + Self { + variables: Box::new([const { None }; 255]), + labels: vec![], + } + } +} + +impl<'s> DebugInfo<'s> { + pub fn label(&self, of: Instruction) -> Option<&'s str> { + self.labels.iter().find(|(_, i)| *i == of).map(|&(x, _)| x) + } +} + +impl<'s> std::ops::Index<LAddress> for DebugInfo<'s> { + type Output = VarData<'s>; + + fn index(&self, index: LAddress) -> &Self::Output { + &self.variables[index.address as usize] + .as_ref() + .unwrap() + .data + } +} + +impl<'s> DebugInfo<'s> { + pub fn set_var(&mut self, at: u8, name: &'s str, span: Range<usize>) { + self.variables[at as usize] = Some(VarInfo { + data: VarData::Variable(name), + span, + }); + } + + pub fn set_const(&mut self, at: u8, var: impl Into<LVar<'s>>, span: Range<usize>) { + self.variables[at as usize] = Some(VarInfo { + data: VarData::Constant(var.into()), + span, + }); + } +} + +#[derive(Clone)] +struct VarInfo<'s> { + pub data: VarData<'s>, + #[allow(dead_code)] + pub span: Range<usize>, +} + +#[derive(Clone)] +pub enum VarData<'s> { + Variable(&'s str), + // not necessary, but convenient. + Constant(LVar<'s>), +} + +impl std::fmt::Display for VarData<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + VarData::Variable(name) => f.write_str(name), + VarData::Constant(c) => write!(f, "{c}"), + } + } +} diff --git a/lemu/src/debug/mod.rs b/lemu/src/debug/mod.rs new file mode 100644 index 0000000..ef22b45 --- /dev/null +++ b/lemu/src/debug/mod.rs @@ -0,0 +1,2 @@ +pub mod info; +pub mod printable; diff --git a/lemu/src/debug/printable.rs b/lemu/src/debug/printable.rs new file mode 100644 index 0000000..243da57 --- /dev/null +++ b/lemu/src/debug/printable.rs @@ -0,0 +1,7 @@ +use std::fmt::{Debug, Result, Write}; + +use super::info::DebugInfo; + +pub trait Printable: Debug { + fn print(&self, info: &DebugInfo<'_>, f: &mut impl Write) -> Result; +} diff --git a/lemu/src/executor/builder.rs b/lemu/src/executor/builder.rs index 7ed4177..3f83159 100644 --- a/lemu/src/executor/builder.rs +++ b/lemu/src/executor/builder.rs @@ -1,5 +1,5 @@ use fimg::Image; -use std::{collections::VecDeque, io::Write as Wr, pin::Pin}; +use std::{collections::VecDeque, io::Write as Wr}; use super::{ Display, Drawing, Executor, ExecutorContext, Instruction, Limit, Memory, PInstr, UPInstr, @@ -7,6 +7,7 @@ use super::{ }; use crate::{ code::Code, + debug::info::DebugInfo, instructions::{DrawInstr, Instr}, lexer::Token, memory::LRegistry, @@ -22,6 +23,7 @@ pub struct ExecutorBuilderInternal<'v, W: Wr> { iteration_limit: Limit, instruction_limit: Limit, pub(crate) mem: LRegistry<'v>, + pub(crate) debug_info: DebugInfo<'v>, } impl<'s, W: Wr> ExecutorBuilderInternal<'s, W> { @@ -35,6 +37,7 @@ impl<'s, W: Wr> ExecutorBuilderInternal<'s, W> { iteration_limit: Limit::limited(1), instruction_limit: Limit::Unlimited, mem: LRegistry::default(), + debug_info: DebugInfo::default(), } } @@ -108,7 +111,7 @@ impl<'s, W: Wr> ExecutorBuilderInternal<'s, W> { core::ptr::slice_from_raw_parts_mut(ptr.cast::<[f64; N]>(), len / N); unsafe { Box::from_raw(ptr) } } - let program = Pin::new(Code::new( + let program = Code::new( self.program .into_iter() .map(|v| match v { @@ -119,13 +122,14 @@ impl<'s, W: Wr> ExecutorBuilderInternal<'s, W> { UPInstr::Code(c) => PInstr::Code(c), }) .collect::<Box<[PInstr]>>(), - )); + ); let Self { instruction_limit, iteration_limit, displays, output, banks, + debug_info, cells, mem, .. @@ -146,6 +150,7 @@ impl<'s, W: Wr> ExecutorBuilderInternal<'s, W> { output, }, instructions_ran: 0, + debug_info, program, } } diff --git a/lemu/src/executor/mod.rs b/lemu/src/executor/mod.rs index 4b50cf6..94b9c57 100644 --- a/lemu/src/executor/mod.rs +++ b/lemu/src/executor/mod.rs @@ -1,5 +1,7 @@ mod builder; +use crate::debug::{info::DebugInfo, printable::Printable}; + use super::{ code::{Code, PInstr}, instructions::{DrawInstr, DrawInstruction, Flow, Instr, LInstruction}, @@ -8,7 +10,7 @@ use super::{ }; pub use builder::ExecutorBuilderInternal; use fimg::Image; -use std::{collections::VecDeque, io::Write, num::NonZeroUsize, pin::Pin}; +use std::{collections::VecDeque, io::Write, num::NonZeroUsize}; #[derive(Debug, Copy, Clone, Default)] pub struct Display(pub usize); @@ -53,7 +55,7 @@ impl std::fmt::Display for Memory { pub const BANK_SIZE: usize = 512; pub const CELL_SIZE: usize = 64; -#[derive(Copy, Clone)] +#[derive(Copy, Clone, PartialEq, Eq)] pub struct Instruction(usize); impl Instruction { @@ -107,10 +109,17 @@ pub struct Executor<'varnames, W: Write> { /// a `Stop` instruction will break the loop. pub iteration_limit: Limit, pub(crate) inner: ExecutorContext<'varnames, W>, - /// gets pointed to by drawbuf - pub(crate) program: Pin<Code<'varnames>>, + /// 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)] @@ -128,7 +137,7 @@ pub struct Drawing { pub buffer: VecDeque<*const DrawInstr>, } -impl<'v> Drawing { +impl Drawing { fn buffer(&mut self, i: &DrawInstr) { self.buffer.push_back(i); } @@ -237,7 +246,13 @@ 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); + /* + 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(); + println!("exec '{instr}' ({mem})"); + */ i.run(&mut self.inner) } PInstr::Draw(i) => { diff --git a/lemu/src/instructions/cop.rs b/lemu/src/instructions/cop.rs index 250a0f1..0079bfa 100644 --- a/lemu/src/instructions/cop.rs +++ b/lemu/src/instructions/cop.rs @@ -29,15 +29,12 @@ op!(gt >); op!(le <=); op!(ge >=); -impl ConditionOp { - pub const fn get_fn(self) -> for<'f> fn(&LVar<'f>, &LVar<'f>) -> bool { - match self { - Self::Equal | Self::StrictEqual => eq, - Self::NotEqual => ne, - Self::LessThan => lt, - Self::GreaterThan => gt, - Self::LessThanEq => le, - Self::GreaterThanEq => ge, - } - } -} +super::op_impl!(ConditionOp, ptr type = for<'f> fn(&LVar<'f>, &LVar<'f>) -> bool { + Equal => eq, + StrictEqual => eq, + NotEqual => ne, + LessThan => lt, + GreaterThan => gt, + LessThanEq => le, + GreaterThanEq => ge, +}); diff --git a/lemu/src/instructions/draw.rs b/lemu/src/instructions/draw.rs index 82f97da..bc22d4c 100644 --- a/lemu/src/instructions/draw.rs +++ b/lemu/src/instructions/draw.rs @@ -1,21 +1,22 @@ use super::{get_num, Flow, LInstruction}; use crate::{ + debug::{info::DebugInfo, printable::Printable}, executor::{Display, DisplayState, ExecutorContext}, memory::{LAddress, LRegistry, LVar}, }; use enum_dispatch::enum_dispatch; use fimg::Image; -use std::fmt::{self, Display as Disp, Formatter}; +use std::fmt; pub const INSTRS: &[&str] = &[ "clear", "color", "col", "stroke", "line", "rect", "lineRect", "triangle", "poly", "linePoly", ]; #[enum_dispatch] -pub trait DrawInstruction: Disp { - fn draw<'v>( +pub trait DrawInstruction: Printable { + fn draw( &self, - mem: &mut LRegistry<'v>, + mem: &mut LRegistry<'_>, image: &mut Image<&mut [u8], 4>, state: &mut DisplayState, ); @@ -35,18 +36,18 @@ pub enum DrawInstr { LinePoly(LinePoly), } -impl Disp for DrawInstr { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl Printable for DrawInstr { + fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result { match self { - Self::Line(i) => write!(f, "{i}"), - Self::RectBordered(i) => write!(f, "{i}"), - Self::RectFilled(i) => write!(f, "{i}"), - Self::Triangle(i) => write!(f, "{i}"), - Self::Clear(i) => write!(f, "{i}"), - Self::SetColor(i) => write!(f, "{i}"), - Self::SetStroke(i) => write!(f, "{i}"), - Self::Poly(i) => write!(f, "{i}"), - Self::LinePoly(i) => write!(f, "{i}"), + Self::Line(i) => i.print(info, f), + Self::RectBordered(i) => i.print(info, f), + Self::RectFilled(i) => i.print(info, f), + Self::Triangle(i) => i.print(info, f), + Self::Clear(i) => i.print(info, f), + Self::SetColor(i) => i.print(info, f), + Self::SetStroke(i) => i.print(info, f), + Self::Poly(i) => i.print(info, f), + Self::LinePoly(i) => i.print(info, f), } } } @@ -60,9 +61,9 @@ pub struct Clear { } impl DrawInstruction for Clear { - fn draw<'v>( + fn draw( &self, - mem: &mut LRegistry<'v>, + mem: &mut LRegistry<'_>, image: &mut Image<&mut [u8], 4>, _: &mut DisplayState, ) { @@ -81,9 +82,13 @@ impl DrawInstruction for Clear { } } -impl Disp for Clear { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "draw clear {} {} {}", self.r, self.g, self.b) +impl Printable for Clear { + fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result { + write!( + f, + "draw clear {} {} {}", + info[self.r], info[self.g], info[self.b] + ) } } @@ -96,9 +101,9 @@ pub struct SetColor { pub a: LAddress, } impl DrawInstruction for SetColor { - fn draw<'v>( + fn draw( &self, - mem: &mut LRegistry<'v>, + mem: &mut LRegistry<'_>, _: &mut Image<&mut [u8], 4>, state: &mut DisplayState, ) { @@ -114,9 +119,13 @@ impl DrawInstruction 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) +impl Printable for SetColor { + fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result { + write!( + f, + "draw color {} {} {} {}", + info[self.r], info[self.g], info[self.b], info[self.a] + ) } } @@ -126,9 +135,9 @@ pub struct SetStroke { pub size: LAddress, } impl DrawInstruction for SetStroke { - fn draw<'v>( + fn draw( &self, - mem: &mut LRegistry<'v>, + mem: &mut LRegistry<'_>, _: &mut Image<&mut [u8], 4>, state: &mut DisplayState, ) { @@ -138,9 +147,9 @@ impl DrawInstruction for SetStroke { } } -impl Disp for SetStroke { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "draw stroke {}", self.size) +impl Printable for SetStroke { + fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result { + write!(f, "draw stroke {}", info[self.size]) } } @@ -168,9 +177,9 @@ pub struct Line { } impl DrawInstruction for Line { - fn draw<'v>( + fn draw( &self, - mem: &mut LRegistry<'v>, + mem: &mut LRegistry<'_>, image: &mut Image<&mut [u8], 4>, state: &mut DisplayState, ) { @@ -180,12 +189,12 @@ impl DrawInstruction for Line { } } -impl Disp for Line { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl Printable for Line { + fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result { write!( f, "draw line {} {} {} {}", - self.point_a.0, self.point_a.1, self.point_b.0, self.point_b.1 + info[self.point_a.0], info[self.point_a.1], info[self.point_b.0], info[self.point_b.1] ) } } @@ -199,9 +208,9 @@ pub struct RectFilled { } impl DrawInstruction for RectFilled { - fn draw<'v>( + fn draw( &self, - mem: &mut LRegistry<'v>, + mem: &mut LRegistry<'_>, image: &mut Image<&mut [u8], 4>, state: &mut DisplayState, ) { @@ -212,12 +221,12 @@ impl DrawInstruction for RectFilled { } } -impl Disp for RectFilled { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl Printable for RectFilled { + fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result { write!( f, "draw rect {} {} {} {}", - self.position.0, self.position.1, self.width, self.height + info[self.position.0], info[self.position.1], info[self.width], info[self.height] ) } } @@ -230,20 +239,20 @@ pub struct RectBordered { pub height: LAddress, } -impl Disp for RectBordered { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl Printable for RectBordered { + fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result { write!( f, "draw lineRect {} {} {} {}", - self.position.0, self.position.1, self.width, self.height + info[self.position.0], info[self.position.1], info[self.width], info[self.height] ) } } impl DrawInstruction for RectBordered { - fn draw<'v>( + fn draw( &self, - mem: &mut LRegistry<'v>, + mem: &mut LRegistry<'_>, image: &mut Image<&mut [u8], 4>, state: &mut DisplayState, ) { @@ -260,9 +269,9 @@ pub struct Triangle { pub points: (Point, Point, Point), } impl DrawInstruction for Triangle { - fn draw<'v>( + fn draw( &self, - mem: &mut LRegistry<'v>, + mem: &mut LRegistry<'_>, i: &mut Image<&mut [u8], 4>, state: &mut DisplayState, ) { @@ -275,17 +284,17 @@ impl DrawInstruction for Triangle { i.tri::<f32>(a, b, c, state.col()); } } -impl Disp for Triangle { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl Printable for Triangle { + fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result { write!( f, "draw triangle {} {} {} {} {} {}", - self.points.0.0, - self.points.0.1, - self.points.1.0, - self.points.1.1, - self.points.2.0, - self.points.2.1 + info[self.points.0.0], + info[self.points.0.1], + info[self.points.1.0], + info[self.points.1.1], + info[self.points.2.0], + info[self.points.2.1] ) } } @@ -300,9 +309,9 @@ pub struct Poly { } impl DrawInstruction for Poly { - fn draw<'v>( + fn draw( &self, - mem: &mut LRegistry<'v>, + mem: &mut LRegistry<'_>, image: &mut Image<&mut [u8], 4>, state: &mut DisplayState, ) { @@ -325,12 +334,12 @@ impl DrawInstruction for Poly { } } -impl Disp for Poly { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl Printable for Poly { + fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result { write!( f, "draw poly {} {} {} {} {}", - self.pos.0, self.pos.1, self.sides, self.radius, self.rot + info[self.pos.0], info[self.pos.1], info[self.sides], info[self.radius], info[self.rot], ) } } @@ -345,9 +354,9 @@ pub struct LinePoly { } impl DrawInstruction for LinePoly { - fn draw<'v>( + fn draw( &self, - mem: &mut LRegistry<'v>, + mem: &mut LRegistry<'_>, image: &mut Image<&mut [u8], 4>, state: &mut DisplayState, ) { @@ -371,12 +380,12 @@ impl DrawInstruction for LinePoly { } } -impl Disp for LinePoly { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl Printable for LinePoly { + fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result { write!( f, "draw linePoly {} {} {} {} {}", - self.pos.0, self.pos.1, self.sides, self.radius, self.rot + info[self.pos.0], info[self.pos.1], info[self.sides], info[self.radius], info[self.rot], ) } } @@ -393,9 +402,8 @@ impl LInstruction for Flush { } } -impl Disp for Flush { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let d = self.display; - write!(f, "drawflush {d}") +impl Printable for Flush { + fn print(&self, _: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result { + write!(f, "drawflush {}", self.display) } } diff --git a/lemu/src/instructions/io.rs b/lemu/src/instructions/io.rs index d919f5e..22d1b52 100644 --- a/lemu/src/instructions/io.rs +++ b/lemu/src/instructions/io.rs @@ -1,12 +1,10 @@ use super::{get_num, Flow, LInstruction}; use crate::{ + debug::{info::DebugInfo, printable::Printable}, executor::{ExecutorContext, Memory}, memory::{LAddress, LVar}, }; -use std::{ - fmt::{self, Display, Formatter}, - io::Write as Wr, -}; +use std::{fmt, io::Write as Wr}; #[derive(Debug, Copy, Clone)] @@ -17,7 +15,7 @@ pub struct Read { } impl LInstruction for Read { - fn run<'v, W: Wr>(&self, exec: &mut ExecutorContext<'v, W>) -> Flow { + fn run<W: Wr>(&self, exec: &mut ExecutorContext<'_, W>) -> Flow { let i = get_num!(exec.get(self.index)).round() as usize; if let Some(&n) = exec.mem(self.container).get(i) { *exec.get_mut(self.output) = LVar::from(n); @@ -26,9 +24,13 @@ impl LInstruction for Read { } } -impl Display for Read { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "read {} {} {}", self.output, self.container, self.index) +impl Printable for Read { + fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result { + write!( + f, + "read {} {} {}", + info[self.output], self.container, info[self.index] + ) } } @@ -41,7 +43,7 @@ pub struct Write { } impl LInstruction for Write { - fn run<'v, W: Wr>(&self, exec: &mut ExecutorContext<'v, W>) -> Flow { + fn run<W: Wr>(&self, exec: &mut ExecutorContext<'_, 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) { @@ -52,9 +54,13 @@ impl LInstruction for Write { } } -impl Display for Write { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "write {} {} {}", self.set, self.container, self.index) +impl Printable for Write { + fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result { + write!( + f, + "write {} {} {}", + info[self.set], self.container, info[self.index] + ) } } @@ -76,8 +82,9 @@ impl LInstruction for Print { Flow::Continue } } -impl Display for Print { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "print {}", self.val) +// haha +impl Printable for Print { + fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result { + write!(f, "print {}", info[self.val]) } } diff --git a/lemu/src/instructions/mod.rs b/lemu/src/instructions/mod.rs index e684a64..f4d6565 100644 --- a/lemu/src/instructions/mod.rs +++ b/lemu/src/instructions/mod.rs @@ -23,10 +23,9 @@ pub use draw::{DrawInstr, DrawInstruction}; use enum_dispatch::enum_dispatch; pub use mop::MathOp1; pub use mop2::MathOp2; -use std::{ - fmt::{self, Display, Formatter}, - io::Write, -}; +use std::{fmt, io::Write}; + +use crate::debug::{info::DebugInfo, printable::Printable}; use super::{ executor::{ExecutorContext, Instruction}, @@ -87,8 +86,8 @@ pub enum Flow { } #[enum_dispatch] -pub trait LInstruction: Display { - fn run<'v, W: Write>(&self, exec: &mut ExecutorContext<'v, W>) -> Flow; +pub trait LInstruction: Printable { + fn run<W: Write>(&self, exec: &mut ExecutorContext<'_, W>) -> Flow; } #[derive(Debug, Copy, Clone)] @@ -107,21 +106,22 @@ pub enum Instr { Stop(Stop), End(End), } -impl Display for Instr { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + +impl Printable for Instr { + fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result { match self { - Self::Op2(i) => write!(f, "{i}"), - Self::Jump(i) => write!(f, "{i}"), - Self::AlwaysJump(i) => write!(f, "{i}"), - Self::Set(i) => write!(f, "{i}"), - Self::Op1(i) => write!(f, "{i}"), - Self::Read(i) => write!(f, "{i}"), - Self::Write(i) => write!(f, "{i}"), - Self::DrawFlush(i) => write!(f, "{i}"), - Self::DynJump(i) => write!(f, "{i}"), - Self::Print(i) => write!(f, "{i}"), - Self::Stop(i) => write!(f, "{i}"), - Self::End(i) => write!(f, "{i}"), + Self::Op2(i) => i.print(info, f), + Self::Jump(i) => i.print(info, f), + Self::AlwaysJump(i) => i.print(info, f), + Self::Set(i) => i.print(info, f), + Self::Op1(i) => i.print(info, f), + Self::Read(i) => i.print(info, f), + Self::Write(i) => i.print(info, f), + Self::DrawFlush(i) => i.print(info, f), + Self::DynJump(i) => i.print(info, f), + Self::Print(i) => i.print(info, f), + Self::Stop(i) => i.print(info, f), + Self::End(i) => i.print(info, f), } } } @@ -132,15 +132,15 @@ pub struct Set { pub(crate) to: LAddress, } impl LInstruction for Set { - fn run<'v, W: Write>(&self, exec: &mut ExecutorContext<'v, W>) -> Flow { - exec.set(self.from, self.to.clone()); + fn run<W: Write>(&self, exec: &mut ExecutorContext<'_, W>) -> Flow { + exec.set(self.from, self.to); Flow::Continue } } -impl Display for Set { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "set {} {}", self.from, self.to) +impl Printable for Set { + fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result { + write!(f, "set {} {}", info[self.from], info[self.to]) } } @@ -163,6 +163,12 @@ macro_rules! op_enum { } } + impl std::fmt::Display for $name { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + write!(f, "{}", Token::from(*self)) + } + } + impl<'a> From<$name> for Token<'a> { fn from(value: $name) -> Self { match value { @@ -174,6 +180,30 @@ macro_rules! op_enum { } use op_enum; +// not part of op_enum due to rem +macro_rules! op_impl { + ($name:ident, ptr type = $ptr:ty { $($own:ident => $fn:ident,)+ }) => { + impl $name { + pub const fn get_fn(self) -> $ptr { + match self { + $(Self::$own => $fn,)+ + } + } + } + + impl TryFrom<$ptr> for $name { + type Error = (); + fn try_from(f:$ptr) -> Result<Self, ()> { + match f { + $(f if f == $fn => Ok(Self::$own),)+ + _ => Err(()), + } + } + } + } +} +use op_impl; + macro_rules! get_num { ($x:expr) => { match $x { @@ -190,7 +220,7 @@ pub struct Op1 { x: LAddress, out: LAddress, } -impl<'v> Op1 { +impl Op1 { pub(crate) const fn new(op: MathOp1, x: LAddress, out: LAddress) -> Self { Self { op: op.get_fn(), @@ -201,17 +231,17 @@ impl<'v> Op1 { } impl LInstruction for Op1 { - fn run<'s, W: Write>(&self, exec: &mut ExecutorContext<'s, W>) -> Flow { + fn run<W: Write>(&self, exec: &mut ExecutorContext<'_, W>) -> Flow { let x = (self.op)(exec.get(self.x)); *exec.get_mut(self.out) = LVar::Num(x); Flow::Continue } } -impl Display for Op1 { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let Self { x, out, .. } = self; - write!(f, "op .. {out} {x}") +impl Printable for Op1 { + fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result { + let op = mop::MathOp1::try_from(self.op).unwrap(); + write!(f, "op {op} {} {}", info[self.out], info[self.x]) } } @@ -235,17 +265,21 @@ impl Op2 { impl LInstruction for Op2 { #[inline] - fn run<'v, W: Write>(&self, exec: &mut ExecutorContext<'v, W>) -> Flow { + fn run<W: Write>(&self, exec: &mut ExecutorContext<'_, 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 { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let Self { a, b, out, .. } = self; - write!(f, "op .. {out} {a} {b}") +impl Printable for Op2 { + fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result { + let op = mop2::MathOp2::try_from(self.op).unwrap(); + write!( + f, + "op {op} {} {} {}", + info[self.out], info[self.a], info[self.b] + ) } } @@ -261,8 +295,8 @@ impl LInstruction for End { } } -impl Display for End { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl Printable for End { + fn print(&self, _: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result { write!(f, "end") } } @@ -278,9 +312,14 @@ impl LInstruction for AlwaysJump { } } -impl Display for AlwaysJump { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "jump {} always", self.to.get()) +impl Printable for AlwaysJump { + fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result { + write!(f, "jump ")?; + match info.label(self.to) { + Some(l) => f.write_str(l)?, + None => write!(f, "{}", self.to.get())?, + } + write!(f, " always") } } @@ -303,7 +342,7 @@ impl Jump { } impl LInstruction for Jump { - fn run<'v, W: Write>(&self, exec: &mut ExecutorContext<'v, W>) -> Flow { + fn run<W: Write>(&self, exec: &mut ExecutorContext<'_, W>) -> Flow { if (self.op)(exec.get(self.a), exec.get(self.b)) { exec.jump(self.to); Flow::Stay @@ -313,10 +352,15 @@ impl LInstruction for Jump { } } -impl Display for Jump { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let Self { to, a, b, .. } = self; - write!(f, "jump .. {} {a} {b}", to.get()) +impl Printable for Jump { + fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result { + let op = ConditionOp::try_from(self.op).unwrap(); + write!(f, "jump {op} ")?; + match info.label(self.to) { + Some(l) => f.write_str(l)?, + None => write!(f, "{}", self.to.get())?, + }; + write!(f, " {} {}", info[self.a], info[self.b]) } } @@ -327,7 +371,7 @@ pub struct DynJump { } impl LInstruction for DynJump { - fn run<'v, W: Write>(&self, exec: &mut ExecutorContext<'v, W>) -> Flow { + fn run<W: Write>(&self, exec: &mut ExecutorContext<'_, W>) -> Flow { if let &LVar::Num(n) = exec.get(self.to) { let i = n.round() as usize; if i < self.proglen { @@ -340,9 +384,9 @@ impl LInstruction for DynJump { } } -impl Display for DynJump { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "set @counter {}", self.to) +impl Printable for DynJump { + fn print(&self, info: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result { + write!(f, "set @counter {}", info[self.to]) } } @@ -354,8 +398,8 @@ impl LInstruction for Stop { } } -impl Display for Stop { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +impl Printable for Stop { + fn print(&self, _: &DebugInfo<'_>, f: &mut impl fmt::Write) -> fmt::Result { write!(f, "stop") } } diff --git a/lemu/src/instructions/mop.rs b/lemu/src/instructions/mop.rs index eb315eb..a008c45 100644 --- a/lemu/src/instructions/mop.rs +++ b/lemu/src/instructions/mop.rs @@ -51,23 +51,19 @@ num!(acos f64::acos); num!(atan f64::atan); num!(log10 f64::log10); -impl MathOp1 { - pub const fn get_fn(self) -> for<'f> fn(&LVar<'f>) -> f64 { - match self { - Self::Floor => floor, - Self::Not => not, - Self::Log => log, - Self::Abs => abs, - Self::Rand => rand, - Self::Ceil => ceil, - Self::Sqrt => sqrt, - Self::Sin => sin, - Self::Cos => cos, - Self::Tan => tan, - Self::ASin => asin, - Self::ACos => acos, - Self::ATan => atan, - Self::Log10 => log10, - } - } -} +super::op_impl!(MathOp1, ptr type = for<'v> fn(&LVar<'v>) -> f64 { + Floor => floor, + Not => not, + Log => log, + Abs => abs, + Rand => rand, + Ceil => ceil, + Sqrt => sqrt, + Sin => sin, + Cos => cos, + Tan => tan, + ASin => asin, + ACos => acos, + ATan => atan, + Log10 => log10, +}); diff --git a/lemu/src/instructions/mop2.rs b/lemu/src/instructions/mop2.rs index 9fb208f..6051794 100644 --- a/lemu/src/instructions/mop2.rs +++ b/lemu/src/instructions/mop2.rs @@ -62,7 +62,8 @@ macro_rules! nofun { nofun!(eq | a, b | a == b); nofun!(ne | a, b | a != b); num!(and | a, b | a != 0.0 && b != 0.0); -op!(add+); +#[rustfmt::skip] +op!(add +); op!(sub -); op!(mul *); bop!(idiv /); @@ -99,35 +100,41 @@ num!(angle |a: f64, b: f64| { x }); -impl MathOp2 { - pub const fn get_fn(self) -> for<'f> fn(&LVar<'f>, &LVar<'f>) -> f64 { - match self { - // we kind of interpret strings as numbers so yeah - Self::Equal | Self::StrictEqual => eq, - Self::NotEqual => ne, - Self::And => and, - Self::Add => add, - Self::Sub => sub, - Self::Mul => mul, - Self::IDiv => idiv, - Self::LessThan => lt, - Self::LessThanEq => le, - Self::GreaterThan => gt, - Self::GreaterThanEq => ge, - Self::Div => div, - Self::Mod => rem, - Self::Pow => pow, - Self::ShiftLeft => shl, - Self::ShiftRight => shr, - Self::BitOr => or, - Self::BitAnd => band, - Self::ExclusiveOr => xor, - Self::Max => max, - Self::Min => min, - Self::AngleDiff => angle_diff, - Self::Len => len, - Self::Noise => noise, - Self::Angle => angle, - } - } -} +super::op_impl!(MathOp2, ptr type = for<'f> fn(&LVar<'f>, &LVar<'f>) -> f64 { + Equal => eq, + StrictEqual => eq, + NotEqual => ne, + And => and, + Add => add, + Sub => sub, + Mul => mul, + IDiv => idiv, + LessThan => lt, + LessThanEq => le, + GreaterThan => gt, + GreaterThanEq => ge, + Div => div, + Mod => rem, + Pow => pow, + ShiftLeft => shl, + ShiftRight => shr, + BitOr => or, + BitAnd => band, + ExclusiveOr => xor, + Max => max, + Min => min, + AngleDiff => angle_diff, + Len => len, + Noise => noise, + Angle => angle, +}); + +// // no macro cuz funky rem +// impl MathOp2 { +// pub const fn get_fn(self) -> for<'f> fn(&LVar<'f>, &LVar<'f>) -> f64 { +// match self { +// // we kind of interpret strings as numbers so yeah + +// } +// } +// } diff --git a/lemu/src/lib.rs b/lemu/src/lib.rs index d4c0f71..64cd653 100644 --- a/lemu/src/lib.rs +++ b/lemu/src/lib.rs @@ -1,6 +1,8 @@ //! crate for [MLOG](https://mindustrygame.github.io/wiki/logic/0-introduction/#what-is-mindustry-logic) emulation. #![feature(let_chains, inline_const)] -#![allow(clippy::redundant_closure_call)] +#![allow(clippy::redundant_closure_call, incomplete_features)] +// yeah so like well you see i kinda well kinda have to yes but sorta +#![allow(clippy::fn_address_comparisons)] #![warn( clippy::multiple_unsafe_ops_per_block, clippy::missing_const_for_fn, @@ -12,6 +14,7 @@ missing_docs )] pub(crate) mod code; +mod debug; mod executor; mod instructions; mod lexer; diff --git a/lemu/src/memory.rs b/lemu/src/memory.rs index b71e44e..ddb0e8a 100644 --- a/lemu/src/memory.rs +++ b/lemu/src/memory.rs @@ -1,4 +1,6 @@ use beef::lean::Cow; + +use crate::debug::{info::VarData, printable::Printable}; #[derive(Clone, Debug)] pub enum LVar<'string> { Num(f64), @@ -50,16 +52,10 @@ impl std::fmt::Debug for LAddress { } } -impl std::fmt::Display for LAddress { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:x}", self.address) - } -} - impl std::fmt::Display for LVar<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::Num(n) => write!(f, "{n}"), + Self::Num(n) => write!(f, "{n:.4}"), // yeeeeahhhh Self::String(s) => write!(f, r#""{s}""#), } } @@ -130,15 +126,42 @@ impl std::fmt::Display for LRegistry<'_> { if let Some((i, v)) = iter.next() { write!(f, "{i}: {v}")?; } - while let Some((i, v)) = iter.next() { + for (i, v) in iter { write!(f, ", {i}: {v}")?; } write!(f, "]") } } -impl<'s> LRegistry<'s> { - pub fn get<'a>(&'a self, a: LAddress) -> &LVar { +impl LRegistry<'_> { + pub fn get(&self, a: LAddress) -> &LVar { &self[a] } } + +impl Printable for LRegistry<'_> { + fn print( + &self, + info: &crate::debug::info::DebugInfo<'_>, + f: &mut impl std::fmt::Write, + ) -> std::fmt::Result { + write!(f, "R[")?; + let mut iter = self + .0 + .iter() + .zip(0..u8::MAX) + .filter(|&(v, _)| v != &LVar::null()) + .map(|(v, i)| (&info[LAddress::addr(i)], v)) + .filter_map(|(d, v)| match d { + VarData::Variable(d) => Some((*d, v)), + VarData::Constant(_) => None, + }); + if let Some((i, v)) = iter.next() { + write!(f, "{i}: {v}")?; + } + for (i, v) in iter { + write!(f, ", {i}: {v}")?; + } + write!(f, "]") + } +} diff --git a/lemu/src/parser/mod.rs b/lemu/src/parser/mod.rs index 5a90334..5b667cb 100644 --- a/lemu/src/parser/mod.rs +++ b/lemu/src/parser/mod.rs @@ -97,15 +97,22 @@ pub fn parse<'source, W: Wr>( let mut used = 0u8; let mut mem: [Option<&str>; 255] = [None; 255]; // maps &str to usize macro_rules! push { + // push a ident ($var:expr) => {{ - mem[used as usize] = Some($var); + let v = $var; + executor.debug_info.set_var(used, v, tokens.span()); + mem[used as usize] = Some(v); 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); + let v = $var; + executor + .debug_info + .set_const(used, v.clone(), tokens.span()); + executor.mem[LAddress::addr(used)] = LVar::from(v); used = used .checked_add(1) .ok_or(Error::TooManyVariables(tokens.span()))?; @@ -127,8 +134,6 @@ pub fn parse<'source, W: Wr>( }}; } - // maps "start" to 0 - let mut labels = Vec::new(); let mut unfinished_jumps = Vec::new(); macro_rules! tok { () => { @@ -242,9 +247,10 @@ pub fn parse<'source, W: Wr>( // # omg Token::Comment(c) => executor.program.push(UPInstr::Comment(c)), // label: - Token::Ident(v) if v.ends_with(':') => { - labels.push((&v[..v.len() - 1], executor.next())) - } + Token::Ident(v) if v.ends_with(':') => executor + .debug_info + .labels + .push((&v[..v.len() - 1], executor.next())), // print "5" Token::Print => { let val = take_var!(tok!()?)?; @@ -784,7 +790,9 @@ pub fn parse<'source, W: Wr>( } for (j, (label, s), i) in unfinished_jumps { - let to = labels + let to = executor + .debug_info + .labels .iter() .find(|(v, _)| v == &label) .ok_or_else(|| Error::LabelNotFound(label, s))? |