mindustry logic execution, map- and schematic- parsing and rendering
Diffstat (limited to 'lemu/src/parser/mod.rs')
| -rw-r--r-- | lemu/src/parser/mod.rs | 119 |
1 files changed, 69 insertions, 50 deletions
diff --git a/lemu/src/parser/mod.rs b/lemu/src/parser/mod.rs index 1091a82..077b35e 100644 --- a/lemu/src/parser/mod.rs +++ b/lemu/src/parser/mod.rs @@ -81,10 +81,10 @@ macro_rules! tokstr { use tokstr; #[derive(Debug)] -enum UJump<'v> { +enum UJump { Sometimes { - a: LAddress<'v>, - b: LAddress<'v>, + a: LAddress, + b: LAddress, op: ConditionOp, }, Always, @@ -94,7 +94,39 @@ pub fn parse<'source, W: Wr>( mut tokens: Lexer<'source>, executor: &mut ExecutorBuilderInternal<'source, W>, ) -> Result<(), Error<'source>> { - let mut mem = Vec::new(); // maps &str to usize + let mut used = 0u8; + let mut mem: [Option<&str>; 255] = [None; 255]; // maps &str to usize + macro_rules! push { + ($var:expr) => {{ + mem[used as usize] = Some($var); + 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); + used = used + .checked_add(1) + .ok_or(Error::TooManyVariables(tokens.span()))?; + Ok(LAddress::addr(used - 1)) + }}; + } + macro_rules! addr { + ($val:expr) => {{ + let val = $val; + match mem + .iter() + .zip(0..used) + .find(|(&v, _)| v == Some(val)) + .map(|(_, i)| i) + { + Some(n) => Ok(LAddress::addr(n)), + None => push!(val), + } + }}; + } + // maps "start" to 0 let mut labels = Vec::new(); let mut unfinished_jumps = Vec::new(); @@ -113,7 +145,7 @@ pub fn parse<'source, W: Wr>( return Err(Error::$e($($stuff,)+ tokens.span())) }; } - #[rustfmt::skip] + #[rustfmt::skip] macro_rules! nextline { () => { while let Some(tok) = tokens.next() && tok != Token::Newline { } @@ -161,25 +193,6 @@ pub fn parse<'source, W: Wr>( } }}; } - macro_rules! addr { - ($n:expr) => {{ - let n = $n; - match mem - .iter() - .enumerate() - .find(|(_, &v)| v == n) - .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, n) }, - None => { - mem.push(n); - // SAFETY: see above - unsafe { LAddress::addr(mem.len() - 1, n) } - } - } - }}; - } macro_rules! take_ident { ($tok:expr) => {{ let tok = $tok; @@ -190,11 +203,11 @@ pub fn parse<'source, W: Wr>( ($tok:expr) => {{ let tok = $tok; if let Some(i) = tokstr!(tok) { - Ok(addr!(i)) + addr!(i) } else { match tok { - Token::Num(n) => Ok(LAddress::cnst(n)), - Token::String(s) => Ok(LAddress::cnst(s)), + Token::Num(n) => push!(const n), + Token::String(s) => push!(const s), t => Err(err!(ExpectedVar(t))), } } @@ -204,10 +217,10 @@ pub fn parse<'source, W: Wr>( ($tok:expr) => {{ let tok = $tok; if let Some(i) = tokstr!(tok) { - Ok(addr!(i)) + addr!(i) } else { match tok { - Token::Num(n) => Ok(LAddress::cnst(n)), + Token::Num(n) => push!(const n), t => Err(err!(ExpectedNum(t))), } } @@ -233,7 +246,7 @@ pub fn parse<'source, W: Wr>( let to = take_numvar!(tok!()?)?; executor.add(DynJump { to, proglen: 0 }); } else { - let from = addr!(take_ident!(from)?); + let from = addr!(take_ident!(from)?)?; let to = take_var!(tok!()?)?; executor.add(Set { from, to }); } @@ -268,12 +281,12 @@ pub fn parse<'source, W: Wr>( let to = unsafe { Instruction::new(n) }; let op = tok!()?; if op == Token::Always { - executor.add(AlwaysJump { to, label: None }); + executor.add(AlwaysJump { to }); } 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, None)); + executor.add(Jump::new(op, to, a, b)); } } else { yeet!(ExpectedJump(tok)); @@ -301,7 +314,9 @@ pub fn parse<'source, W: Wr>( let set = take_numvar!(tok!()?)?; let container = take_memory!(); let index = take_numvar!(tok!()?)?; - if let LAddress::Const(LVar::Num(v)) = index && !container.fits(v.round() as usize) { + if let LVar::Num(v) = executor.mem[index] + && !container.fits(v.round() as usize) + { yeet!(IndexOutOfBounds(v.round() as usize, container.size())); } executor.add(Write { @@ -315,7 +330,9 @@ pub fn parse<'source, W: Wr>( let output = take_var!(tok!()?)?; let container = take_memory!(); let index = take_numvar!(tok!()?)?; - if let LAddress::Const(LVar::Num(v)) = index && !container.fits(v.round() as usize) { + if let LVar::Num(v) = executor.mem[index] + && !container.fits(v.round() as usize) + { yeet!(IndexOutOfBounds(v.round() as usize, container.size())); } executor.add(Read { @@ -352,12 +369,13 @@ pub fn parse<'source, W: Wr>( 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), - }); + let i = SetColor { + r: push!(const r)?, + g: push!(const g)?, + b: push!(const b)?, + a: push!(const a)?, + }; + executor.draw(i); } "stroke" => { let size = take_numvar!(tok!()?)?; @@ -416,7 +434,9 @@ pub fn parse<'source, W: Wr>( } Token::DrawFlush => { let t = tok!(); - if let Ok(t) = t && t != Token::Newline { + if let Ok(t) = t + && t != Token::Newline + { let screen = take_ident!(t.clone())?; let mut out = String::new(); for ch in screen.chars() { @@ -433,7 +453,9 @@ pub fn parse<'source, W: Wr>( yeet!(InvalidDisplayType(screen)); } let n_span = tokens.span().start + screen.len()..tokens.span().end; - let screen_n = out.parse::<usize>().map_err(|_| Error::ExpectedInt(t, n_span.clone()))?; + let screen_n = out + .parse::<usize>() + .map_err(|_| Error::ExpectedInt(t, n_span.clone()))?; let display = executor .display(screen_n) .map_err(|n| Error::NoDisplay(n, n_span))?; @@ -733,7 +755,9 @@ pub fn parse<'source, W: Wr>( "effect" => { let mut v = Vec::with_capacity(6); v.push(Token::Ident("effect")); - while let Some(tok) = tokens.next() && tok != Token::Newline { + while let Some(tok) = tokens.next() + && tok != Token::Newline + { v.push(tok); } executor.code(v.into_boxed_slice()); @@ -755,11 +779,8 @@ pub fn parse<'source, W: Wr>( .ok_or_else(|| Error::LabelNotFound(label, s))? .1; executor.program[i.get()] = UPInstr::Instr(match j { - UJump::Always => Instr::from(AlwaysJump { - to, - label: Some(label), - }), - UJump::Sometimes { a, b, op } => Instr::from(Jump::new(op, to, a, b, Some(label))), + UJump::Always => Instr::from(AlwaysJump { to }), + UJump::Sometimes { a, b, op } => Instr::from(Jump::new(op, to, a, b)), }); } @@ -783,7 +804,5 @@ pub fn parse<'source, W: Wr>( } } - executor.mem(mem.len()); - Ok(()) } |