mindustry logic execution, map- and schematic- parsing and rendering
basic, inaccurate, Display impl for executor
| -rw-r--r-- | lemu/rustfmt.toml | 1 | ||||
| -rw-r--r-- | lemu/src/executor/builder.rs | 35 | ||||
| -rw-r--r-- | lemu/src/executor/mod.rs | 83 | ||||
| -rw-r--r-- | lemu/src/instructions/draw.rs | 101 | ||||
| -rw-r--r-- | lemu/src/instructions/io.rs | 28 | ||||
| -rw-r--r-- | lemu/src/instructions/mod.rs | 162 | ||||
| -rw-r--r-- | lemu/src/memory.rs | 25 | ||||
| -rw-r--r-- | lemu/src/parser/mod.rs | 60 |
8 files changed, 380 insertions, 115 deletions
diff --git a/lemu/rustfmt.toml b/lemu/rustfmt.toml new file mode 100644 index 0000000..d4d3d50 --- /dev/null +++ b/lemu/rustfmt.toml @@ -0,0 +1 @@ +version = "Two"
\ No newline at end of file diff --git a/lemu/src/executor/builder.rs b/lemu/src/executor/builder.rs index 9df29ab..4d35a36 100644 --- a/lemu/src/executor/builder.rs +++ b/lemu/src/executor/builder.rs @@ -60,7 +60,7 @@ impl<'s, W: Wr> ExecutorBuilderInternal<'s, W> { if n * BANK_SIZE > self.banks.len() { self.banks.resize(n * BANK_SIZE, 0.0); } - Memory(-(((self.banks.len() - BANK_SIZE) / BANK_SIZE) as i8) - 1) + Memory::Bank(((self.banks.len() - BANK_SIZE) / BANK_SIZE) as u8) } pub(crate) fn cell(&mut self, n: usize) -> Memory { @@ -68,7 +68,7 @@ impl<'s, W: Wr> ExecutorBuilderInternal<'s, W> { if n * CELL_SIZE > self.cells.len() { self.cells.resize(n * CELL_SIZE, 0.0); } - Memory(((self.cells.len() - CELL_SIZE) / CELL_SIZE) as i8) + Memory::Cell(((self.cells.len() - CELL_SIZE) / CELL_SIZE) as u8) } pub(crate) fn next(&self) -> Instruction { @@ -95,10 +95,6 @@ impl<'s, W: Wr> ExecutorBuilderInternal<'s, W> { self.program.len() > i } - pub(crate) fn noop(&mut self) { - self.program.push(UPInstr::NoOp); - } - pub(crate) fn display(&mut self, n: usize) -> Result<Display, usize> { self.displays .get(n.checked_sub(1).ok_or(n)?) @@ -114,15 +110,27 @@ 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( + self.program + .into_iter() + .map(|v| match v { + UPInstr::Instr(i) => PInstr::Instr(i), + UPInstr::Draw(i) => PInstr::Draw(i), + UPInstr::Comment(c) => PInstr::Comment(c), + UPInstr::UnfinishedJump => panic!("all jumps should have finished"), + UPInstr::Code(c) => PInstr::Code(c), + }) + .collect::<Box<[PInstr]>>(), + ); let Self { instruction_limit, iteration_limit, - program, displays, output, banks, cells, mem, + .. } = self; Executor { instruction_limit, @@ -139,19 +147,8 @@ impl<'s, W: Wr> ExecutorBuilderInternal<'s, W> { }, output, }, - program: Pin::new( - program - .into_iter() - .map(|v| match v { - UPInstr::Instr(i) => PInstr::Instr(i), - UPInstr::Draw(i) => PInstr::Draw(i), - UPInstr::NoOp => PInstr::NoOp, - UPInstr::UnfinishedJump => panic!("all jumps should have finished"), - UPInstr::Code(c) => PInstr::Code(c), - }) - .collect::<Box<[PInstr]>>(), - ), instructions_ran: 0, + program, } } } diff --git a/lemu/src/executor/mod.rs b/lemu/src/executor/mod.rs index d1df0af..db9b7f9 100644 --- a/lemu/src/executor/mod.rs +++ b/lemu/src/executor/mod.rs @@ -11,26 +11,44 @@ use std::{collections::VecDeque, io::Write, num::NonZeroUsize, pin::Pin}; #[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)] -// negative means bank, positive means cell -pub struct Memory(pub(crate) i8); +pub enum Memory { + Cell(u8), + Bank(u8), +} + impl Memory { pub(crate) const fn fits(self, i: usize) -> bool { - if self.0 < 0 { - i < BANK_SIZE - } else { - i < CELL_SIZE + match self { + Self::Bank(_) => i < BANK_SIZE, + Self::Cell(_) => i < CELL_SIZE, } } - pub(crate) fn size(self) -> usize { - if self.0 < 0 { - BANK_SIZE - } else { - CELL_SIZE + pub(crate) 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; @@ -60,9 +78,28 @@ pub enum PInstr<'s> { Instr(Instr<'s>), Draw(DrawInstr<'s>), Code(Box<[Token<'s>]>), - NoOp, + Comment(&'s str), } +impl std::fmt::Display for PInstr<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Instr(i) => write!(f, "{i}"), + Self::Draw(i) => write!(f, "{i}"), + Self::Code(c) => { + let mut toks = c.iter(); + if let Some(t) = toks.next() { + write!(f, "{t}")?; + } + for token in toks { + write!(f, " {token}")?; + } + Ok(()) + } + Self::Comment(c) => write!(f, "{c}"), + } + } +} #[derive(Debug, Copy, Clone)] pub enum Limit { /// limited to n @@ -107,7 +144,7 @@ pub enum UPInstr<'s> { Draw(DrawInstr<'s>), UnfinishedJump, Code(Box<[Token<'s>]>), - NoOp, + Comment(&'s str), } pub struct Drawing<'v> { @@ -154,6 +191,15 @@ impl Default for DisplayState { } } +impl<W: Write> std::fmt::Display for Executor<'_, W> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for instr in &*self.program { + writeln!(f, "{instr}")?; + } + Ok(()) + } +} + impl<'s, W: Write> ExecutorContext<'s, W> { pub fn flush(&mut self, to: Display) { let mut state = DisplayState::default(); @@ -167,13 +213,10 @@ impl<'s, W: Write> ExecutorContext<'s, W> { } } - pub fn mem(&mut self, Memory(m): Memory) -> &mut [f64] { - if m < 0 { - let m = (m + 1).unsigned_abs() as usize; - &mut self.banks[m] - } else { - let m = m as usize; - &mut self.cells[m] + 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.banks[m as usize], } } diff --git a/lemu/src/instructions/draw.rs b/lemu/src/instructions/draw.rs index 365b422..2dff764 100644 --- a/lemu/src/instructions/draw.rs +++ b/lemu/src/instructions/draw.rs @@ -5,13 +5,14 @@ use crate::{ }; use enum_dispatch::enum_dispatch; use fimg::Image; +use std::fmt::{self, Display as Disp, Formatter}; pub const INSTRS: &[&str] = &[ "clear", "color", "col", "stroke", "line", "rect", "lineRect", "triangle", ]; #[enum_dispatch] -pub trait DrawInstruction<'v> { +pub trait DrawInstruction<'v>: Disp { fn draw( &self, mem: &mut LRegistry<'v>, @@ -28,10 +29,22 @@ pub enum DrawInstr<'v> { DrawRectFilled(RectFilled<'v>), DrawTriangle(Triangle<'v>), Clear(Clear<'v>), - SetColorDyn(SetColorDyn<'v>), - SetColorConst(SetColorConst), + SetColor(SetColor<'v>), SetStroke(SetStroke<'v>), } +impl Disp for DrawInstr<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + Self::DrawLine(i) => write!(f, "{i}"), + Self::DrawRectBordered(i) => write!(f, "{i}"), + Self::DrawRectFilled(i) => write!(f, "{i}"), + Self::DrawTriangle(i) => write!(f, "{i}"), + Self::Clear(i) => write!(f, "{i}"), + Self::SetColor(i) => write!(f, "{i}"), + Self::SetStroke(i) => write!(f, "{i}"), + } + } +} #[derive(Debug)] pub struct Clear<'v> { @@ -58,14 +71,20 @@ impl<'v> DrawInstruction<'v> for Clear<'v> { } } +impl Disp for Clear<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "draw clear {} {} {} {}", self.r, self.g, self.b, self.a) + } +} + #[derive(Debug)] -pub struct SetColorDyn<'v> { +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 SetColorDyn<'v> { +impl<'v> DrawInstruction<'v> for SetColor<'v> { fn draw(&self, mem: &mut LRegistry<'v>, _: &mut Image<&mut [u8], 4>, state: &mut DisplayState) { macro_rules! u8 { ($v:ident) => { @@ -79,16 +98,9 @@ impl<'v> DrawInstruction<'v> for SetColorDyn<'v> { } } -#[derive(Debug)] -pub struct SetColorConst { - pub r: u8, - pub g: u8, - pub b: u8, - pub a: u8, -} -impl DrawInstruction<'_> for SetColorConst { - fn draw(&self, _: &mut LRegistry<'_>, _: &mut Image<&mut [u8], 4>, state: &mut DisplayState) { - state.color = (self.r, self.g, self.b, self.a); +impl Disp for SetColor<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "draw color {} {} {} {}", self.r, self.g, self.b, self.a) } } @@ -104,6 +116,12 @@ impl<'v> DrawInstruction<'v> for SetStroke<'v> { } } +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>); #[rustfmt::skip] macro_rules! point { @@ -125,8 +143,8 @@ pub struct Line<'v> { pub point_a: Point<'v>, pub point_b: Point<'v>, } + impl<'v> DrawInstruction<'v> for Line<'v> { - #[allow(unused_variables)] fn draw( &self, mem: &mut LRegistry<'v>, @@ -140,12 +158,23 @@ impl<'v> DrawInstruction<'v> for Line<'v> { } } +impl Disp for Line<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!( + f, + "draw line {} {} {} {}", + self.point_a.0, self.point_a.1, self.point_b.0, self.point_b.1 + ) + } +} + #[derive(Debug)] pub struct RectFilled<'v> { pub position: Point<'v>, pub width: LAddress<'v>, pub height: LAddress<'v>, } + impl<'v> DrawInstruction<'v> for RectFilled<'v> { fn draw( &self, @@ -160,6 +189,16 @@ impl<'v> DrawInstruction<'v> for RectFilled<'v> { } } +impl Disp for RectFilled<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!( + f, + "draw rect {} {} {} {}", + self.position.0, self.position.1, self.width, self.height + ) + } +} + #[derive(Debug)] pub struct RectBordered<'v> { pub position: Point<'v>, @@ -167,6 +206,16 @@ pub struct RectBordered<'v> { pub height: LAddress<'v>, } +impl Disp for RectBordered<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!( + f, + "draw lineRect {} {} {} {}", + self.position.0, self.position.1, self.width, self.height + ) + } +} + impl<'v> DrawInstruction<'v> for RectBordered<'v> { fn draw( &self, @@ -197,6 +246,20 @@ impl<'v> DrawInstruction<'v> for Triangle<'v> { i.tri(a, b, c, state.col()); } } +impl Disp for Triangle<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> 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 + ) + } +} #[derive(Debug, Default)] pub struct Flush { @@ -208,3 +271,9 @@ impl LInstruction<'_> for Flush { Flow::Continue } } + +impl Disp for Flush { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "drawflush {}", self.display) + } +} diff --git a/lemu/src/instructions/io.rs b/lemu/src/instructions/io.rs index 8b1eed5..6e8e325 100644 --- a/lemu/src/instructions/io.rs +++ b/lemu/src/instructions/io.rs @@ -3,7 +3,10 @@ use crate::{ executor::{ExecutorContext, Memory}, memory::{LAddress, LVar}, }; -use std::io::Write as Wr; +use std::{ + fmt::{self, Display, Formatter}, + io::Write as Wr, +}; #[derive(Debug)] pub struct Read<'v> { @@ -24,6 +27,12 @@ impl<'v> LInstruction<'v> for Read<'v> { } } +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>, @@ -43,6 +52,12 @@ impl<'v> LInstruction<'v> for Write<'v> { } } +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>, @@ -51,8 +66,17 @@ impl LInstruction<'_> for Print<'_> { fn run<W: Wr>(&self, exec: &mut ExecutorContext<'_, W>) -> Flow { let v = exec.get(&self.val).clone(); if let Some(o) = &mut exec.output { - write!(o, "{v}").unwrap(); + match v { + LVar::Num(n) => write!(o, "{n}"), + LVar::String(s) => write!(o, r#"{s}"#), + } + .unwrap(); } Flow::Continue } } +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 70888a6..7bc2c57 100644 --- a/lemu/src/instructions/mod.rs +++ b/lemu/src/instructions/mod.rs @@ -23,10 +23,14 @@ pub use draw::{DrawInstr, DrawInstruction}; use enum_dispatch::enum_dispatch; pub use mop::MathOp1; pub use mop2::MathOp2; -use std::io::Write; +use std::{ + fmt::{self, Display, Formatter}, + io::Write, +}; use super::{ executor::{ExecutorContext, Instruction}, + lexer::Token, memory::{LAddress, LVar}, }; @@ -84,7 +88,7 @@ pub enum Flow { } #[enum_dispatch] -pub trait LInstruction<'v> { +pub trait LInstruction<'v>: Display { fn run<W: Write>(&self, exec: &mut ExecutorContext<'v, W>) -> Flow; } @@ -93,7 +97,7 @@ pub trait LInstruction<'v> { pub enum Instr<'v> { Op2(Op2<'v>), Jump(Jump<'v>), - AlwaysJump(AlwaysJump), + AlwaysJump(AlwaysJump<'v>), Set(Set<'v>), Op1(Op1<'v>), Read(io::Read<'v>), @@ -104,6 +108,24 @@ pub enum Instr<'v> { Stop(Stop), End(End), } +impl Display for Instr<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> 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}"), + } + } +} #[derive(Debug)] pub struct Set<'v> { @@ -117,6 +139,12 @@ impl<'v> LInstruction<'v> for Set<'v> { } } +impl Display for Set<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "set {} {}", self.from, self.to) + } +} + macro_rules! op_enum { ($v:vis enum $name:ident { $($variant:ident),+ $(,)? @@ -135,6 +163,14 @@ macro_rules! op_enum { } } } + + impl<'a> From<$name> for Token<'a> { + fn from(value: $name) -> Self { + match value { + $($name::$variant => Self::$variant,)+ + } + } + } } } use op_enum; @@ -151,13 +187,15 @@ use get_num; #[derive(Debug)] pub struct Op1<'v> { - pub(crate) op: fn(&LVar<'v>) -> f64, - pub(crate) x: LAddress<'v>, - pub(crate) out: LAddress<'v>, + op_id: MathOp1, + op: fn(&LVar<'v>) -> f64, + x: LAddress<'v>, + out: LAddress<'v>, } impl<'v> Op1<'v> { pub(crate) const fn new(op: MathOp1, x: LAddress<'v>, out: LAddress<'v>) -> Self { Self { + op_id: op, op: op.get_fn(), x, out, @@ -175,12 +213,20 @@ impl<'s> LInstruction<'s> for Op1<'s> { } } +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)) + } +} + #[derive(Debug)] pub struct Op2<'v> { - pub(crate) op: fn(&LVar<'v>, &LVar<'v>) -> f64, - pub(crate) a: LAddress<'v>, - pub(crate) b: LAddress<'v>, - pub(crate) out: LAddress<'v>, + op_id: MathOp2, + op: fn(&LVar<'v>, &LVar<'v>) -> f64, + a: LAddress<'v>, + b: LAddress<'v>, + out: LAddress<'v>, } impl<'v> Op2<'v> { pub(crate) const fn new( @@ -190,6 +236,7 @@ impl<'v> Op2<'v> { out: LAddress<'v>, ) -> Self { Self { + op_id: op, op: op.get_fn(), a, b, @@ -208,6 +255,15 @@ impl<'v> LInstruction<'v> for Op2<'v> { } } +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)) + } +} + #[derive(Debug)] pub struct End {} @@ -221,28 +277,54 @@ impl LInstruction<'_> for End { } } +impl Display for End { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "end") + } +} + #[derive(Debug)] -pub struct AlwaysJump { +pub struct AlwaysJump<'s> { 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<'_> { + 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"), + } + } +} + #[derive(Debug)] pub struct Jump<'v> { - pub(crate) op: fn(&LVar<'v>, &LVar<'v>) -> bool, + label: Option<&'v str>, + op_id: ConditionOp, + op: fn(&LVar<'v>, &LVar<'v>) -> bool, pub(crate) to: Instruction, - pub(crate) a: LAddress<'v>, - pub(crate) b: LAddress<'v>, + a: LAddress<'v>, + b: LAddress<'v>, } impl<'v> Jump<'v> { - pub fn new(op: ConditionOp, to: Instruction, a: LAddress<'v>, b: LAddress<'v>) -> Self { + pub fn new( + op: ConditionOp, + to: Instruction, + a: LAddress<'v>, + b: LAddress<'v>, + label: Option<&'v str>, + ) -> Self { Self { + op_id: op, op: op.get_fn(), + label, to, a, b, @@ -250,6 +332,36 @@ 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)) { + exec.jump(self.to); + Flow::Stay + } else { + Flow::Continue + } + } +} + +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)) + } +} + #[derive(Debug)] pub struct DynJump<'v> { pub to: LAddress<'v>, @@ -270,15 +382,9 @@ impl<'v> LInstruction<'v> for DynJump<'v> { } } -impl<'v> LInstruction<'v> for Jump<'v> { - #[allow(unused_variables)] - fn run<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 { - Flow::Continue - } +impl Display for DynJump<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "set @counter {}", self.to) } } @@ -289,3 +395,9 @@ impl LInstruction<'_> for Stop { Flow::Exit } } + +impl Display for Stop { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "stop") + } +} diff --git a/lemu/src/memory.rs b/lemu/src/memory.rs index 63d5db9..052314f 100644 --- a/lemu/src/memory.rs +++ b/lemu/src/memory.rs @@ -25,15 +25,15 @@ impl LVar<'_> { #[derive(Clone)] pub enum LAddress<'str> { Const(LVar<'str>), - Address(usize, Priv), + Address(usize, &'str str, Priv), } 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) -> Self { - LAddress::Address(addr, Priv { _priv: () }) + 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 { @@ -50,7 +50,16 @@ 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, ..) => write!(f, "0x{n:x}"), + Self::Address(n, name, ..) => write!(f, "{name}@0x{n:x}"), + } + } +} + +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}"), } } } @@ -59,7 +68,7 @@ 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::String(s) => write!(f, r#"{s}"#), + Self::String(s) => write!(f, r#""{s}""#), } } } @@ -76,6 +85,12 @@ impl From<bool> for LVar<'_> { } } +impl From<usize> for LVar<'_> { + fn from(value: usize) -> Self { + Self::Num(value as f64) + } +} + impl<'s> From<&'s str> for LVar<'s> { fn from(value: &'s str) -> Self { Self::String(value.into()) diff --git a/lemu/src/parser/mod.rs b/lemu/src/parser/mod.rs index a6a7aae..8d4e9ab 100644 --- a/lemu/src/parser/mod.rs +++ b/lemu/src/parser/mod.rs @@ -6,10 +6,7 @@ pub use error::Error; use super::{ executor::{ExecutorBuilderInternal, Instruction, UPInstr}, instructions::{ - draw::{ - Clear, Flush, Line, RectBordered, RectFilled, SetColorConst, SetColorDyn, SetStroke, - Triangle, - }, + draw::{Clear, Flush, Line, RectBordered, RectFilled, SetColor, SetStroke, Triangle}, io::{Print, Read, Write}, AlwaysJump, ConditionOp, DynJump, End, Instr, Jump, MathOp1, MathOp2, Op1, Op2, Set, Stop, }, @@ -95,7 +92,7 @@ pub fn parse<'source, W: Wr>( executor: &mut ExecutorBuilderInternal<'source, W>, ) -> Result<(), Error<'source>> { let mut mem = Vec::new(); // maps &str to usize - // maps "start" to 0 + // maps "start" to 0 let mut labels = Vec::new(); let mut unfinished_jumps = Vec::new(); macro_rules! tok { @@ -152,7 +149,7 @@ pub fn parse<'source, W: Wr>( return Err(Error::InvalidMemoryType( container, tokens.span().start..tokens.span().end - out.len(), - )) + )); } } }}; @@ -167,11 +164,11 @@ pub fn parse<'source, W: Wr>( .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) }, + Some(i) => unsafe { LAddress::addr(i, n) }, None => { mem.push(n); // SAFETY: see above - unsafe { LAddress::addr(mem.len() - 1) } + unsafe { LAddress::addr(mem.len() - 1, n) } } } }}; @@ -212,12 +209,10 @@ pub fn parse<'source, W: Wr>( while let Some(token) = tokens.next() { match token { // # omg - Token::Comment(_) => { - executor.noop(); - } + 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())); + labels.push((&v[..v.len() - 1], executor.next())) } // print "5" Token::Print => { @@ -266,12 +261,12 @@ pub fn parse<'source, W: Wr>( let to = unsafe { Instruction::new(n) }; let op = tok!()?; if op == Token::Always { - executor.add(AlwaysJump { to }); + executor.add(AlwaysJump { to, label: None }); } 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)); + executor.add(Jump::new(op, to, a, b, None)); } } else { yeet!(ExpectedJump(tok)); @@ -338,15 +333,20 @@ pub fn parse<'source, W: Wr>( } "color" => { let (r, g, b, a) = four! { take_numvar!(tok!()?)? }; - executor.draw(SetColorDyn { r, g, b, a }); + executor.draw(SetColor { r, g, b, a }); } "col" => { let col = take_int!(tok!()?)?; - let r = (col & 0xff00_0000 >> 24) as u8; - let g = (col & 0x00ff_0000 >> 16) as u8; - let b = (col & 0x0000_ff00 >> 8) as u8; - let a = (col & 0x0000_00ff) as u8; - executor.draw(SetColorConst { r, g, b, a }); + let r = col & 0xff00_0000 >> 24; + 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), + }); } "stroke" => { let size = take_numvar!(tok!()?)?; @@ -565,7 +565,7 @@ pub fn parse<'source, W: Wr>( "packcolor" => instr! { (4) => all!(num!()) }, "ubind" => instr! { (1) => |b| { let t = tok!()?; - if matches!(t, Token::String(_) | Token::Null) { + if tokstr!(t).is_some() || matches!(t, Token::Null) { b[0] = t; } else { yeet!(ExpectedString(t)); @@ -706,22 +706,26 @@ pub fn parse<'source, W: Wr>( nextline!(); } - for (j, (l, s), i) in unfinished_jumps { + for (j, (label, s), i) in unfinished_jumps { let to = labels .iter() - .find(|(v, _)| v == &l) - .ok_or_else(|| Error::LabelNotFound(l, s))? + .find(|(v, _)| v == &label) + .ok_or_else(|| Error::LabelNotFound(label, s))? .1; executor.program[i.get()] = UPInstr::Instr(match j { - UJump::Always => Instr::from(AlwaysJump { to }), - UJump::Sometimes { a, b, op } => Instr::from(Jump::new(op, to, a, b)), + UJump::Always => Instr::from(AlwaysJump { + to, + label: Some(label), + }), + UJump::Sometimes { a, b, op } => Instr::from(Jump::new(op, to, a, b, Some(label))), }); } // check jump validity for i in &executor.program { - if let UPInstr::Instr(Instr::Jump(Jump { to, .. }) | Instr::AlwaysJump(AlwaysJump { to })) = - i + if let UPInstr::Instr( + Instr::Jump(Jump { to, .. }) | Instr::AlwaysJump(AlwaysJump { to, .. }), + ) = i { if !executor.valid(*to) { yeet!(InvalidJump(*to)); |