mindustry logic execution, map- and schematic- parsing and rendering
get 4294901760 more variables
bendn 2023-11-12
parent 078d8ee · commit 3bd1750
-rw-r--r--lemu/src/debug/info.rs27
-rw-r--r--lemu/src/executor/builder.rs8
-rw-r--r--lemu/src/memory.rs32
-rw-r--r--lemu/src/parser/error.rs4
-rw-r--r--lemu/src/parser/mod.rs38
5 files changed, 53 insertions, 56 deletions
diff --git a/lemu/src/debug/info.rs b/lemu/src/debug/info.rs
index 5b38f81..e23f23b 100644
--- a/lemu/src/debug/info.rs
+++ b/lemu/src/debug/info.rs
@@ -6,7 +6,7 @@ use crate::{
};
pub struct DebugInfo<'s> {
- variables: Box<[Option<VarInfo<'s>>; 65536]>,
+ pub variables: Box<[VarInfo<'s>]>,
/// maps "start" to 0
pub labels: Vec<(&'s str, Instruction)>,
}
@@ -14,7 +14,7 @@ pub struct DebugInfo<'s> {
impl<'s> Default for DebugInfo<'s> {
fn default() -> Self {
Self {
- variables: vec![None; 65536].try_into().unwrap(),
+ variables: vec![].into(),
labels: vec![],
}
}
@@ -30,31 +30,12 @@ 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: u16, 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: u16, var: impl Into<LVar<'s>>, span: Range<usize>) {
- self.variables[at as usize] = Some(VarInfo {
- data: VarData::Constant(var.into()),
- span,
- });
+ &self.variables[index.address as usize].data
}
}
#[derive(Clone, Debug)]
-struct VarInfo<'s> {
+pub struct VarInfo<'s> {
pub data: VarData<'s>,
#[allow(dead_code)]
pub span: Range<usize>,
diff --git a/lemu/src/executor/builder.rs b/lemu/src/executor/builder.rs
index ae78996..936a3b6 100644
--- a/lemu/src/executor/builder.rs
+++ b/lemu/src/executor/builder.rs
@@ -10,7 +10,7 @@ use crate::{
debug::info::DebugInfo,
instructions::{DrawInstr, Instr},
lexer::Token,
- memory::LRegistry,
+ memory::{LRegistry, LVar},
};
/// for internal use by [parser](crate::parser) only
@@ -22,7 +22,7 @@ pub struct ExecutorBuilderInternal<'v, W: Wr> {
cells: Vec<f64>,
iteration_limit: Limit,
instruction_limit: Limit,
- pub(crate) mem: LRegistry<'v>,
+ pub(crate) mem: Vec<LVar<'v>>,
pub(crate) debug_info: DebugInfo<'v>,
}
@@ -39,7 +39,7 @@ impl<'s, W: Wr> ExecutorBuilderInternal<'s, W> {
cells: vec![],
iteration_limit: Limit::limited(1),
instruction_limit: Limit::Unlimited,
- mem: LRegistry::default(),
+ mem: Vec::with_capacity(64),
debug_info: DebugInfo::default(),
}
}
@@ -143,7 +143,7 @@ impl<'s, W: Wr> ExecutorBuilderInternal<'s, W> {
inner: ExecutorContext {
cells: cst::<CELL_SIZE>(cells),
banks: cst::<BANK_SIZE>(banks),
- memory: mem,
+ memory: LRegistry(mem.into()),
counter: 0,
iterations: 0,
display: Drawing {
diff --git a/lemu/src/memory.rs b/lemu/src/memory.rs
index 133fe8e..ff99dc8 100644
--- a/lemu/src/memory.rs
+++ b/lemu/src/memory.rs
@@ -39,11 +39,14 @@ impl LVar<'_> {
#[derive(Clone, Copy)]
pub struct LAddress {
- pub address: u16,
+ pub address: u32,
}
impl LAddress {
- pub(crate) const fn addr(address: u16) -> Self {
+ /// # Safety
+ ///
+ /// ensure that address is valid
+ pub(crate) const unsafe fn addr(address: u32) -> Self {
LAddress { address }
}
}
@@ -98,27 +101,27 @@ impl<'s> From<Cow<'s, str>> for LVar<'s> {
}
}
-/// whats a megabyte among friends
#[derive(Debug)]
-pub struct LRegistry<'str>(pub Box<[LVar<'str>; 65536]>);
+pub struct LRegistry<'str>(pub Box<[LVar<'str>]>);
impl<'s> std::ops::Index<LAddress> for LRegistry<'s> {
type Output = LVar<'s>;
fn index(&self, index: LAddress) -> &Self::Output {
- &self.0[index.address as usize]
+ debug_assert!((index.address as usize) < self.0.len());
+ // SAFETY: LAddress promises to be in our bounds.
+ // lreg has no constructors, so unless you keep one around, grab a laddr, and use it on the old lreg,
+ // this is safeish.
+ // lreg is private to the outside world, so its ok
+ unsafe { self.0.get_unchecked(index.address as usize) }
}
}
impl<'s> std::ops::IndexMut<LAddress> for LRegistry<'s> {
fn index_mut(&mut self, index: LAddress) -> &mut Self::Output {
- &mut self.0[index.address as usize]
- }
-}
-
-impl<'s> Default for LRegistry<'s> {
- fn default() -> Self {
- Self(vec![LVar::null(); 65536].try_into().unwrap())
+ debug_assert!((index.address as usize) < self.0.len());
+ // SAFETY: see above
+ unsafe { self.0.get_unchecked_mut(index.address as usize) }
}
}
@@ -156,9 +159,10 @@ impl Printable for LRegistry<'_> {
let mut iter = self
.0
.iter()
- .zip(0..u16::MAX)
+ .zip(0..self.0.len() as u32)
.filter(|&(v, _)| v != &LVar::null())
- .map(|(v, i)| (&info[LAddress::addr(i)], v))
+ // SAFETY: the address comes from me
+ .map(|(v, i)| (&info[unsafe { LAddress::addr(i) }], v))
.filter_map(|(d, v)| match d {
VarData::Variable(d) => Some((*d, v)),
VarData::Constant(_) => None,
diff --git a/lemu/src/parser/error.rs b/lemu/src/parser/error.rs
index 41a0296..c2b053b 100644
--- a/lemu/src/parser/error.rs
+++ b/lemu/src/parser/error.rs
@@ -144,7 +144,7 @@ pub enum Error<'s> {
/// .display();
/// ```
NoDisplay(usize, Span),
- /// We have a limit of [`u16::MAX`] variables.
+ /// We have a limit of [`u32::MAX`] variables.
#[error("too many variables")]
TooManyVariables(Span),
}
@@ -433,7 +433,7 @@ impl Error<'_> {
}
Self::TooManyVariables(s) => {
msg!("{error}: {bold_red}too many variables{reset}. ")
- .label((s, cmt!("we only have 255 variable slots")))
+ .label((s, cmt!("we only have 65536 variable slots")))
.note(cmt!("consider not using variables"));
}
};
diff --git a/lemu/src/parser/mod.rs b/lemu/src/parser/mod.rs
index 6a5b601..cfc0fc8 100644
--- a/lemu/src/parser/mod.rs
+++ b/lemu/src/parser/mod.rs
@@ -4,6 +4,7 @@ mod error;
pub use error::Error;
use super::{
+ debug::info::{VarData, VarInfo},
executor::{ExecutorBuilderInternal, Instruction, UPInstr},
instructions::{
draw::{
@@ -94,29 +95,37 @@ pub fn parse<'source, W: Wr>(
mut tokens: Lexer<'source>,
executor: &mut ExecutorBuilderInternal<'source, W>,
) -> Result<(), Error<'source>> {
- let mut used = 0u16;
- let mut mem: Box<[Option<&str>; 65536]> = vec![None; 65536].try_into().unwrap(); // maps &str to usize
+ let mut used = 0u32;
+ let mut mem: Vec<Option<&str>> = Vec::with_capacity(64); // maps &str to usize
+ let mut dbg_info: Vec<VarInfo> = Vec::with_capacity(64);
macro_rules! push {
// push a ident
($var:expr) => {{
let v = $var;
- executor.debug_info.set_var(used, v, tokens.span());
- mem[used as usize] = Some(v);
+ dbg_info.push(VarInfo {
+ data: VarData::Variable(v),
+ span: tokens.span(),
+ });
+ executor.mem.push(LVar::null());
+ mem.push(Some(v));
used = used
.checked_add(1)
.ok_or(Error::TooManyVariables(tokens.span()))?;
- Ok(LAddress::addr(used - 1))
+ // SAFETY: just initialized executor.mem
+ unsafe { Ok(LAddress::addr(used - 1)) }
}};
(const $var:expr) => {{
let v = $var;
- executor
- .debug_info
- .set_const(used, v.clone(), tokens.span());
- executor.mem[LAddress::addr(used)] = LVar::from(v);
+ dbg_info.push(VarInfo {
+ data: VarData::Constant(v.clone().into()),
+ span: tokens.span(),
+ });
+ executor.mem.push(LVar::from(v));
+ mem.push(None);
used = used
.checked_add(1)
.ok_or(Error::TooManyVariables(tokens.span()))?;
- Ok(LAddress::addr(used - 1))
+ unsafe { Ok(LAddress::addr(used - 1)) }
}};
}
macro_rules! addr {
@@ -128,7 +137,7 @@ pub fn parse<'source, W: Wr>(
.find(|(&v, _)| v == Some(val))
.map(|(_, i)| i)
{
- Some(n) => Ok(LAddress::addr(n)),
+ Some(n) => unsafe { Ok(LAddress::addr(n)) },
None => push!(val),
}
}};
@@ -331,7 +340,8 @@ pub fn parse<'source, W: Wr>(
let set = take_numvar!(tok!()?)?;
let container = take_memory!();
let index = take_numvar!(tok!()?)?;
- if let LVar::Num(v) = executor.mem[index]
+ // this is the parser so i wont bother getting unchecked
+ if let LVar::Num(v) = executor.mem[index.address as usize]
&& !container.fits(v.round() as usize)
{
yeet!(IndexOutOfBounds(v.round() as usize, container.size()));
@@ -347,7 +357,7 @@ pub fn parse<'source, W: Wr>(
let output = take_var!(tok!()?)?;
let container = take_memory!();
let index = take_numvar!(tok!()?)?;
- if let LVar::Num(v) = executor.mem[index]
+ if let LVar::Num(v) = executor.mem[index.address as usize]
&& !container.fits(v.round() as usize)
{
yeet!(IndexOutOfBounds(v.round() as usize, container.size()));
@@ -823,5 +833,7 @@ pub fn parse<'source, W: Wr>(
}
}
+ executor.debug_info.variables = dbg_info.into();
+
Ok(())
}