mindustry logic execution, map- and schematic- parsing and rendering
Diffstat (limited to 'lemu/src/parser/mod.rs')
-rw-r--r--lemu/src/parser/mod.rs856
1 files changed, 0 insertions, 856 deletions
diff --git a/lemu/src/parser/mod.rs b/lemu/src/parser/mod.rs
deleted file mode 100644
index 0764189..0000000
--- a/lemu/src/parser/mod.rs
+++ /dev/null
@@ -1,856 +0,0 @@
-use std::io::Write as Wr;
-
-mod error;
-pub use error::Error;
-
-#[rustfmt::skip]
-macro_rules! three { ($a:expr) => { ($a, $a, $a) }; }
-#[rustfmt::skip]
-macro_rules! four { ($a:expr) => { ($a, $a, $a, $a) }; }
-#[rustfmt::skip]
-macro_rules! five { ($a:expr) => { ($a, $a, $a, $a, $a) }; }
-#[rustfmt::skip]
-macro_rules! six { ($a:expr) => { ($a, $a, $a, $a, $a, $a) }; }
-
-use super::{
- debug::info::{VarData, VarInfo},
- executor::{ExecutorBuilderInternal, Instruction, UPInstr},
- instructions::{
- AlwaysJump, ConditionOp, DynJump, End, Instr, Jump, MathOp1, MathOp2, Op1, Op2, PackColor,
- Select, Set, Stop,
- draw::{
- Clear, Flush, Line, LinePoly, Poly, RectBordered, RectFilled, SetCol, SetColor,
- SetStroke, Triangle,
- },
- io::{Print, Read, Write},
- },
- lexer::{Lexer, Token},
- memory::{LAddress, LVar},
-};
-
-macro_rules! tokstr {
- ($tok:expr) => {
- match $tok {
- Token::Ident(i) => Some(i),
- Token::PackColor => Some("packcolor"),
- Token::Null => Some("null"),
- Token::Read => Some("read"),
- Token::Write => Some("write"),
- Token::Set => Some("set"),
- Token::Op => Some("op"),
- Token::End => Some("end"),
- Token::Draw => Some("draw"),
- Token::DrawFlush => Some("drawflush"),
- Token::Print => Some("print"),
- Token::Jump => Some("jump"),
- Token::Stop => Some("stop"),
- Token::Equal => Some("equal"),
- Token::NotEqual => Some("notEqual"),
- Token::LessThan => Some("lessThan"),
- Token::LessThanEq => Some("lessThanEq"),
- Token::GreaterThan => Some("greaterThan"),
- Token::GreaterThanEq => Some("greaterThanEq"),
- Token::StrictEqual => Some("strictEqual"),
- Token::Always => Some("always"),
- Token::Add => Some("add"),
- Token::Sub => Some("sub"),
- Token::Mul => Some("mul"),
- Token::Div => Some("div"),
- Token::IDiv => Some("idiv"),
- Token::Mod => Some("mod"),
- Token::Pow => Some("pow"),
- Token::And => Some("land"),
- Token::Not => Some("not"),
- Token::ShiftLeft => Some("shl"),
- Token::ShiftRight => Some("shr"),
- Token::BitOr => Some("or"),
- Token::BitAnd => Some("and"),
- Token::ExclusiveOr => Some("xor"),
- Token::Max => Some("max"),
- Token::Min => Some("min"),
- Token::Angle => Some("angle"),
- Token::AngleDiff => Some("angleDiff"),
- Token::Len => Some("len"),
- Token::Noise => Some("noise"),
- Token::Abs => Some("abs"),
- Token::Log => Some("log"),
- Token::Log10 => Some("log10"),
- Token::Floor => Some("floor"),
- Token::Ceil => Some("ceil"),
- Token::Sqrt => Some("sqrt"),
- Token::Rand => Some("rand"),
- Token::Sin => Some("sin"),
- Token::Cos => Some("cos"),
- Token::Tan => Some("tan"),
- Token::ASin => Some("asin"),
- Token::ACos => Some("acos"),
- Token::ATan => Some("atan"),
- _ => None,
- }
- };
-}
-use tokstr;
-
-#[derive(Debug)]
-enum UJump {
- Sometimes {
- a: LAddress,
- b: LAddress,
- op: ConditionOp,
- },
- Always,
-}
-
-pub fn parse<'source, W: Wr>(
- mut tokens: Lexer<'source>,
- executor: &mut ExecutorBuilderInternal<'source, W>,
-) -> Result<(), Error<'source>> {
- 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
- (const $var:expr) => {{
- let v = $var;
- 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()))?;
- unsafe { Ok(LAddress::addr(used - 1)) }
- }};
- ($var:expr) => {{
- let v = $var;
- 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()))?;
- // SAFETY: just initialized executor.mem
- unsafe { Ok(LAddress::addr(used - 1)) }
- }};
- }
- push!("@counter")?;
- macro_rules! addr {
- ($val:expr) => {{
- let val = $val;
- match mem
- .iter()
- .zip(0..used)
- .find(|&(&v, _)| v == Some(val))
- .map(|(_, i)| i)
- {
- Some(n) => unsafe { Ok(LAddress::addr(n)) },
- None => push!(val),
- }
- }};
- }
-
- let mut unfinished_jumps = Vec::new();
- macro_rules! tok {
- () => {
- tokens.next().ok_or(Error::UnexpectedEof)
- };
- }
- macro_rules! err {
- ($e:ident($($stuff:expr),+)) => {
- Error::$e($($stuff,)+ tokens.span())
- }
- }
- macro_rules! yeet {
- ($e:ident($($stuff:expr),+)) => {
- return Err(Error::$e($($stuff,)+ tokens.span()))
- };
- }
- #[rustfmt::skip]
- macro_rules! nextline {
- () => {
- while let Some(tok) = tokens.next() && tok != Token::Newline { }
- };
- }
- macro_rules! take_int {
- ($tok:expr) => {
- match $tok {
- Token::Num(n) if n.fract() == 0.0 && n >= 0.0 => Ok(n as usize),
- t => Err(err!(ExpectedInt(t))),
- }
- };
- }
- macro_rules! take_memory {
- () => {{
- let t = tok!()?;
- let container = take_ident!(t.clone())?;
- let mut out = String::new();
- for ch in container.chars() {
- if matches!(ch, '0'..='9') {
- out.push(ch);
- continue;
- }
- if out.len() != 0 {
- yeet!(InvalidMemoryType(container));
- }
- }
- let container = &container[..container.len() - out.len()];
- let n_span = tokens.span().start + container.len()..tokens.span().end;
- let cell_n = out
- .parse::<usize>()
- .map_err(|_| Error::ExpectedInt(t, n_span.clone()))?;
- if cell_n > 126 || cell_n == 0 {
- return Err(Error::MemoryTooFar(cell_n, n_span));
- }
- match container {
- "bank" => executor.bank(cell_n),
- "cell" => executor.cell(cell_n),
- _ => {
- return Err(Error::InvalidMemoryType(
- container,
- tokens.span().start..tokens.span().end - out.len(),
- ));
- }
- }
- }};
- }
- macro_rules! take_ident {
- ($tok:expr) => {{
- let tok = $tok;
- tokstr!(tok).ok_or(err!(ExpectedIdent(tok)))
- }};
- }
- macro_rules! take_var {
- ($tok:expr) => {{
- let tok = $tok;
- if let Some(i) = tokstr!(tok) {
- addr!(i)
- } else {
- match tok {
- Token::Num(n) => push!(const n),
- Token::String(s) => push!(const s),
- t => Err(err!(ExpectedVar(t))),
- }
- }
- }};
- }
- macro_rules! take_numvar {
- ($tok:expr) => {{
- let tok = $tok;
- if let Some(i) = tokstr!(tok) {
- addr!(i)
- } else {
- match tok {
- Token::Num(n) => push!(const n),
- t => Err(err!(ExpectedNum(t))),
- }
- }
- }};
- }
- macro_rules! num_or_255 {
- ($tok:expr) => {
- match $tok {
- Ok(t) => match take_numvar!(t) {
- Err(_) => push!(const 255),
- n => n,
- },
- Err(_) => push!(const 255),
- }
- }
- }
- while let Some(token) = tokens.next() {
- match token {
- // # omg
- Token::Comment(c) => executor.program.push(UPInstr::Comment(c)),
- // label:
- 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!()?)?;
- executor.add(Print { val });
- }
- // set x 4
- Token::Set => {
- let from = tok!()?;
- let from = addr!(take_ident!(from)?)?;
- let to = take_var!(tok!()?)?;
- executor.add(Set { from, to });
- }
- // stop
- Token::Stop => {
- executor.add(Stop {});
- }
- // jump start equal a b
- Token::Jump => {
- let tok = tok!()?;
- // label jump
- if let Some(i) = tokstr!(tok) {
- let span = tokens.span();
- let op = tok!()?;
- if op == Token::Always {
- executor.jmp();
- unfinished_jumps.push((UJump::Always, (i, span), executor.last()));
- } else {
- let op = op.try_into().map_err(|op| err!(ExpectedOp(op)))?;
- let a = take_var!(tok!()?)?;
- let b = take_var!(tok!()?)?;
- executor.jmp();
- unfinished_jumps.push((
- UJump::Sometimes { a, b, op },
- (i, span),
- executor.last(),
- ));
- }
- } else if let Ok(n) = take_int!(tok.clone()) {
- // SAFETY: we check at the end of the block that it is valid
- let to = unsafe { Instruction::new(n) };
- let op = tok!()?;
- if op == Token::Always {
- 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));
- }
- } else {
- yeet!(ExpectedJump(tok));
- };
- }
- // op add c 1 2
- Token::Op => {
- let op = tok!()?;
- if let Ok(op) = MathOp1::try_from(op.clone()) {
- // assigning to a var is useless but legal
- let out = take_numvar!(tok!()?)?;
- let x = take_numvar!(tok!()?)?;
- executor.add(Op1::new(op, x, out));
- } else if let Ok(op) = MathOp2::try_from(op.clone()) {
- let out = take_numvar!(tok!()?)?;
- let a = take_numvar!(tok!()?)?;
- let b = take_numvar!(tok!()?)?;
- executor.add(Op2::new(op, a, b, out));
- } else {
- yeet!(ExpectedOp(op));
- }
- }
- // write 5.0 bank1 4 (aka bank1[4] = 5.0)
- Token::Write => {
- let set = take_numvar!(tok!()?)?;
- let container = take_memory!();
- let index = take_numvar!(tok!()?)?;
- // 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()));
- }
- executor.add(Write {
- index,
- set,
- container,
- });
- }
- // read result cell1 4 (aka result = cell1[4])
- Token::Read => {
- let output = take_var!(tok!()?)?;
- let container = take_memory!();
- let index = take_numvar!(tok!()?)?;
- 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()));
- }
- executor.add(Read {
- index,
- output,
- container,
- });
- }
- Token::Draw => {
- let dty = tok!()?;
- let Token::Ident(instr) = dty else {
- yeet!(ExpectedIdent(dty));
- };
- match instr {
- "clear" => {
- let (r, g, b) = three! { num_or_255!(tok!())? };
- executor.draw(Clear { r, g, b });
- }
- "color" => {
- let (r, g, b, a) = four! { num_or_255!(tok!())? };
- executor.draw(SetColor { r, g, b, a });
- }
- "col" => {
- let col = take_numvar!(tok!()?)?;
- executor.draw(SetCol { col });
- }
- "stroke" => {
- let size = take_numvar!(tok!()?)?;
- executor.draw(SetStroke { size });
- }
- "line" => {
- let (x, y, x2, y2) = four! { take_numvar!(tok!()?)? };
- executor.draw(Line {
- point_a: (x, y),
- point_b: (x2, y2),
- });
- }
- "rect" => {
- let (x, y, width, height) = four! { take_numvar!(tok!()?)? };
- executor.draw(RectFilled {
- position: (x, y),
- width,
- height,
- });
- }
- "lineRect" => {
- let (x, y, width, height) = four! { take_numvar!(tok!()?)? };
- executor.draw(RectBordered {
- position: (x, y),
- width,
- height,
- });
- }
- "triangle" => {
- let (x, y, x2, y2, x3, y3) = six! { take_numvar!(tok!()?)? };
- executor.draw(Triangle {
- points: ((x, y), (x2, y2), (x3, y3)),
- });
- }
- "poly" => {
- let (x, y, sides, radius, rot) = five! { take_numvar!(tok!()?)? };
- executor.draw(Poly {
- pos: (x, y),
- sides,
- radius,
- rot,
- })
- }
- "linePoly" => {
- let (x, y, sides, radius, rot) = five! { take_numvar!(tok!()?)? };
- executor.draw(LinePoly {
- pos: (x, y),
- sides,
- radius,
- rot,
- })
- }
- // image is WONTFIX
- i => yeet!(UnsupportedImageOp(i)),
- }
- }
- Token::PackColor => {
- let out = take_numvar!(tok!()?)?;
- let (r, g, b, a) = four! { take_numvar!(tok!()?)? };
- executor.add(PackColor { out, r, g, b, a });
- }
- Token::DrawFlush => {
- let t = tok!();
- if let Ok(t) = t
- && t != Token::Newline
- {
- let screen = take_ident!(t.clone())?;
- let mut out = String::new();
- for ch in screen.chars() {
- if ch.is_ascii_digit() {
- out.push(ch);
- continue;
- }
- if !out.is_empty() {
- yeet!(InvalidDisplayType(screen));
- }
- }
- let screen = &screen[..screen.len() - out.len()];
- if screen != "display" {
- 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 display = executor
- .display(screen_n)
- .map_err(|n| Error::NoDisplay(n, n_span))?;
- executor.add(Flush { display });
- } else {
- executor.add(Flush::default())
- }
- }
- // end
- Token::End => {
- executor.add(End {});
- }
- Token::Select => {
- let to = addr!(take_ident!(tok!()?)?)?; // =
- // if
- let op: ConditionOp = tok!()?.try_into().map_err(|op| err!(ExpectedOp(op)))?;
-
- let x = take_var!(tok!()?)?;
- let y = take_var!(tok!()?)?;
-
- let a = take_var!(tok!()?)?; // then
- let b = take_var!(tok!()?)?; // else
-
- executor.add(Select {
- op: op.get_fn(),
- to,
- x,
- y,
- a,
- b,
- })
- }
- // starting newline, simply skip. continue, so as not to to trigger the nextline!()
- Token::Newline => continue,
- // unknown instruction
- Token::Ident(i) => {
- macro_rules! all {
- ($is:expr) => {
- |b| {
- for var in &mut *b {
- *var = $is;
- }
- Ok(())
- }
- };
- }
- macro_rules! take {
- (@ $b:ident $n:ident skip) => {
- $b[$n]=tok!()?;
-
- };
- (@ $b:ident $n:ident skip, $($rest:tt)*) => {
- $b[$n] = tok!()?;$n+=1; take!(@ $b $n $($rest)*);
- };
- (@ $b:ident $n:ident $v: expr) => {
- $b[$n] = $v;
- };
- (@ $b:ident $n:ident $v: expr, $($rest:tt)*) => {
- $b[$n] = $v;
- $n += 1;
- take!(@ $b $n $($rest)*);
- };
- [$($this:tt)*] => {
- |b| {
- let mut n = 0;
- take!(@ b n $($this)*);
- Ok(())
- }
- };
- }
- macro_rules! num {
- () => {{
- let tok = tok!()?;
- if let Some(i) = tokstr!(tok) {
- Token::Ident(i)
- } else {
- match tok {
- Token::Num(n) => Token::Num(n),
- t => yeet!(ExpectedNum(t)),
- }
- }
- }};
- }
- macro_rules! bool {
- () => {{
- let tok = tok!()?;
- if let Some(i) = tokstr!(tok) {
- Token::Ident(i)
- } else {
- match tok {
- Token::Num(n) => Token::Num(n),
- t => yeet!(ExpectedBool(t)),
- }
- }
- }};
- }
- macro_rules! ident {
- () => {
- take_ident!(tok!()?).map(|v| Token::Ident(v))?
- };
- }
- #[rustfmt::skip]
- macro_rules! build { () => { ident!() }}
- macro_rules! str {
- () => {
- match tok!()? {
- Token::String(s) => Token::String(s),
- t => yeet!(ExpectedString(t)),
- }
- };
- }
- macro_rules! var {
- () => {{
- let tok = tok!()?;
- if let Some(i) = tokstr!(tok) {
- Token::Ident(i)
- } else {
- match tok {
- Token::Num(n) => Token::Num(n),
- Token::String(s) => Token::String(s),
- t => yeet!(ExpectedVar(t)),
- }
- }
- }};
- }
- macro_rules! instr {
- (($argc:literal) => $block:expr) => {{
- let mut v: Box<[_; $argc + 1]> =
- Box::new(std::array::from_fn(|_| Token::Newline));
- v[0] = Token::Ident(i);
- const fn castor<
- 'source,
- F: FnMut(&mut [Token<'source>; $argc]) -> Result<(), Error<'source>>,
- >(
- f: F,
- ) -> F {
- f
- }
- castor($block)((&mut v[1..]).try_into().unwrap())?;
- executor.code(v as Box<[Token<'source>]>);
- nextline!();
- continue;
- }};
- }
- macro_rules! minstr {
- ($($sub:ident($argc:literal) => $block:expr)+ => $err:expr $(,)?) => {{
- let t = tok!()?;
- let idnt = take_ident!(t.clone())?;
- $(if idnt == stringify!($sub) {
- let mut v: Box<[_; $argc + 2]> = Box::new(std::array::from_fn(|_| Token::Newline));
- v[0]=Token::Ident(i);
- v[1]=Token::Ident(stringify!($sub));
- const fn castor<'source, F: FnMut(&mut [Token<'source>; $argc]) -> Result<(), Error<'source>>>(f: F) -> F { f }
- castor($block)((&mut v[2..]).try_into().unwrap())?;
- executor.code(v);
- nextline!();
- continue;
- })+
- return Err($err(idnt, t));
- }};
- }
- match i {
- "noop" => {
- // executor.program.push(UPInstr::Comment("a"));
- executor.add(crate::instructions::Noop {});
- }
- "printflush" => instr! {
- (1) => |b| {
- let t = tok!()?;
- if let Some(t) = tokstr!(t) {
- b[0] = Token::Ident(t);
- } else if t == Token::Null {
- b[0] = Token::Null;
- } else {
- b[0] = Token::Ident("message1");
- }
- Ok(())
- }
- },
- "getlink" => instr! { (2) => take![var!(), num!()] },
- "control" => minstr! {
- enabled(2) => take![build!(), bool!()]
- shoot(4) => take![build!(), num!(), num!(), bool!()]
- shootp(3) => take![build!(), str!(), bool!()]
- config(2) => take![build!(), tok!()?]
- color(4) => take![build!(), num!(), num!(), num!()]
- => |t, _| { err!(UnknownControlOp(t)) },
- },
- "radar" => {
- instr! { (7) => take![ident!(), ident!(), ident!(), ident!(), build!(), num!(), var!()] }
- }
- "sensor" => instr! { (3) => take![var!(), tok!()?, tok!()?] },
- "wait" => instr! { (1) => all!(num!()) },
- "lookup" => instr! { (3) => take![ident!(), var!(), num!()] },
- "packcolor" => instr! { (4) => all!(num!()) },
- "ubind" => instr! { (1) => |b| {
- let t = tok!()?;
- if tokstr!(t).is_some() || matches!(t, Token::Null) {
- b[0] = t;
- } else {
- yeet!(ExpectedString(t));
- };
- Ok(())
- } },
- "ucontrol" => minstr! {
- idle(0) => |_| Ok(())
- stop(0) => |_| Ok(())
- move(2) => all!(num!())
- approach(3) => all!(num!())
- boost(1) => all!(bool!())
- pathfind(2) => all!(num!())
- target(3) => take![num!(), num!(), bool!()]
- targetp(2) => take![str!(), bool!()]
- itemDrop(2) => take![build!(), num!()]
- itemTake(3) => take![build!(), str!(), num!()]
- payDrop(0) => |_| Ok(())
- payTake(1) => all!(bool!())
- payEnter(0) => |_| Ok(())
- mine(2) => all!(num!())
- flag(1) => all!(num!())
- build(5) => take![num!(), num!(), build!(), num!(), tok!()?]
- getBlock(4) => take![num!(), num!(), build!(), build!()]
- within(4) => take![num!(), num!(), num!(), var!()]
- => |t, _| { err!(UnknownUnitControlOp(t)) }
- },
- "uradar" => {
- instr! { (7) => take![ident!(), ident!(), ident!(), ident!(), build!(), num!(), var!()] }
- }
- "ulocate" => {
- minstr! {
- building(7) => take![build!(), bool!(), skip, num!(), num!(), bool!(), build!()]
- spawn(6) => take![skip, skip, skip, num!(), num!(), bool!()]
- damaged(7) => take![skip, skip, skip, num!(), num!(), var!(), var!()]
- ore(6) => take![skip, skip, tok!()?, num!(), num!(), bool!()]
- => |t, _| { err!(UnknownUnitLocateOp(t)) }
- }
- }
- "getblock" => minstr! {
- floor(3) => take![tok!()?, num!(), num!()]
- ore(3) => take![tok!()?, num!(), num!()]
- block(3) => take![tok!()?, num!(), num!()]
- building(3) => take![tok!()?, num!(), num!()]
- => |t, _| { err!(UnknownGetBlockOp(t)) }
- },
- "setblock" => minstr! {
- floor(3) => take![num!(), num!(), str!()]
- ore(3) => take![num!(), num!(), str!()]
- block(3) => take![num!(), num!(), str!(), str!(), num!()]
- => |t, _| { err!(UnknownSetBlockOp(t)) }
- },
- "spawn" => {
- instr! { (6) => take![str!(), num!(), num!(), num!(), str!(), var!()] }
- }
- "status" => minstr! {
- true(3) => take![ident!(), var!(), num!()]
- false(2) => take![ident!(), var!()]
- => |_, t| { err!(ExpectedBool(t)) }
- },
- "spawnwave" => instr! { (3) => take![num!(), num!(), bool!()] },
- "setrule" => {
- #[rustfmt::skip]
- macro_rules! rule { () => { take![num!(), str!()] }}
- minstr! {
- currentWaveTime(1) => all!(num!())
- waveTimer(1) => all!(num!())
- waves(1) => all!(num!())
- wave(1) => all!(num!())
- waveSpacing(1) => all!(num!())
- waveSending(1) => all!(num!())
- attackMode(1) => all!(num!())
- enemyCoreBuildRadius(1) => all!(num!())
- dropZoneRadius(1) => all!(num!())
- unitCap(1) => all!(num!())
- wave(1) => all!(num!())
- mapArea(4) => |b| {
- tok!()?;
- for var in &mut *b {
- *var = num!();
- }
- Ok(())
- }
- lighting(1) => all!(num!())
- ambientLight(1) => all!(num!())
- solarMultiplier(1) => all!(num!())
- buildSpeed(2) => rule!{}
- unitHealth(2) => rule!{}
- unitBuildSpeed(2) => rule!{}
- unitCost(2) => rule!{}
- unitDamage(2) => rule!{}
- blockHealth(2) => rule!{}
- blockDamage(2) => rule!{}
- rtsMinWeight(2) => rule!{}
- rtsMinSquad(2) => rule!{}
- => |t, _| { err!(UnknownRule(t)) }
- }
- }
- "cutscene" => minstr! {
- pan(3) => all!(num!())
- zoom(1) => all!(num!())
- stop(0) => |_| Ok(())
- => |t, _| { err!(UnknownCutscene(t)) }
- },
- "explosion" => {
- instr! { (8) => take![str!(), num!(), num!(), num!(), bool!(), bool!(), bool!()] }
- }
- "setrate" => instr! { (1) => all!(num!()) },
- "fetch" => minstr! {
- buildCount(4) => take![var!(), str!(), num!(), str!()] // useless 0
- unitCount(4) => take![var!(), str!()]
- playerCount(4) => take![var!(), str!()]
- coreCount(4) => take![var!(), str!()]
- unit(3) => take![var!(), str!(), num!()]
- player(3) => take![var!(), str!(), num!()]
- core(3) => take![var!(), str!(), num!()]
- build(3) => take![var!(), str!(), num!()]
- => |t, _| { err!(UnknownFetchOp(t)) }
- },
- "getflag" => instr! { (2) => take![bool!(), str!()] },
- "setflag" => instr! { (2) => take![str!(), bool!()] },
- "setprop" => instr! { (3) => take![str!(), var!(), tok!()?] },
- "effect" => {
- let mut v = Vec::with_capacity(6);
- v.push(Token::Ident("effect"));
- while let Some(tok) = tokens.next()
- && tok != Token::Newline
- {
- v.push(tok);
- }
- executor.code(v.into_boxed_slice());
- // we take the newline here
- continue;
- }
- t => yeet!(ExpectedInstr(Token::Ident(t))),
- }
- }
- t => yeet!(ExpectedInstr(t)),
- }
- nextline!();
- }
-
- for (j, (label, s), i) in unfinished_jumps {
- let to = executor
- .debug_info
- .labels
- .iter()
- .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)),
- });
- }
-
- // check jump validity
- for i in &executor.program {
- if let UPInstr::Instr(
- Instr::Jump(Jump { to, .. }) | Instr::AlwaysJump(AlwaysJump { to, .. }),
- ) = i
- {
- if !executor.valid(*to) {
- yeet!(InvalidJump(*to));
- }
- }
- }
-
- // set dynjumps
- let len = executor.program.len();
- for i in &mut executor.program {
- if let UPInstr::Instr(Instr::DynJump(DynJump { proglen, .. })) = i {
- *proglen = len;
- }
- }
-
- executor.debug_info.variables = dbg_info.into();
-
- Ok(())
-}