mindustry logic execution, map- and schematic- parsing and rendering
basic, inaccurate, Display impl for executor
bendn 2023-09-29
parent 8842b7f · commit 6ce3a99
-rw-r--r--lemu/rustfmt.toml1
-rw-r--r--lemu/src/executor/builder.rs35
-rw-r--r--lemu/src/executor/mod.rs83
-rw-r--r--lemu/src/instructions/draw.rs101
-rw-r--r--lemu/src/instructions/io.rs28
-rw-r--r--lemu/src/instructions/mod.rs162
-rw-r--r--lemu/src/memory.rs25
-rw-r--r--lemu/src/parser/mod.rs60
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));