mindustry logic execution, map- and schematic- parsing and rendering
debug info
bendn 2023-11-10
parent 2c21b8b · commit 0fd5e9d
-rw-r--r--lemu/src/code.rs18
-rw-r--r--lemu/src/debug/info.rs77
-rw-r--r--lemu/src/debug/mod.rs2
-rw-r--r--lemu/src/debug/printable.rs7
-rw-r--r--lemu/src/executor/builder.rs11
-rw-r--r--lemu/src/executor/mod.rs27
-rw-r--r--lemu/src/instructions/cop.rs21
-rw-r--r--lemu/src/instructions/draw.rs146
-rw-r--r--lemu/src/instructions/io.rs37
-rw-r--r--lemu/src/instructions/mod.rs148
-rw-r--r--lemu/src/instructions/mop.rs36
-rw-r--r--lemu/src/instructions/mop2.rs73
-rw-r--r--lemu/src/lib.rs5
-rw-r--r--lemu/src/memory.rs43
-rw-r--r--lemu/src/parser/mod.rs24
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))?