diff --git a/crates/fogtix-bytecode/src/consts.rs b/crates/fogtix-bytecode/src/consts.rs index 14b84d6..740b0c0 100644 --- a/crates/fogtix-bytecode/src/consts.rs +++ b/crates/fogtix-bytecode/src/consts.rs @@ -24,6 +24,7 @@ pub enum OpType { CallRemote = 0x6372, /* cr */ CallLocal = 0x636c, /* cl */ Jump = 0x6a70, /* jp */ + JumpCond = 0x6a63, /* jc */ Return = 0x7274, /* rt */ Push = 0x7073, /* ps */ diff --git a/crates/fogtix-bytecode/src/instr.rs b/crates/fogtix-bytecode/src/instr.rs index d2ff843..7c2a22d 100644 --- a/crates/fogtix-bytecode/src/instr.rs +++ b/crates/fogtix-bytecode/src/instr.rs @@ -19,6 +19,10 @@ pub enum Instr<'a> { /// jumps to the destination $0 inside of the current module Jump(u64), + /// pops the top stack value and if it is non-zero, jumps to the specified destination + /// inside of the current module + JumpCond(u64), + /// pops the current call frame Return, @@ -50,6 +54,7 @@ impl Instr<'_> { Instr::CallRemote(_, _) => OpType::CallRemote, Instr::CallLocal(_) => OpType::CallLocal, Instr::Jump(_) => OpType::Jump, + Instr::JumpCond(_) => OpType::JumpCond, Instr::Return => OpType::Return, Instr::Push(_) => OpType::Push, Instr::Pop(_) => OpType::Pop, @@ -101,6 +106,7 @@ impl<'a> crate::Parse<'a> for Instr<'a> { } OpType::CallLocal => u64::parse(inp).map(|(inp, val)| (inp, Instr::CallLocal(val))), OpType::Jump => u64::parse(inp).map(|(inp, val)| (inp, Instr::Jump(val))), + OpType::JumpCond => u64::parse(inp).map(|(inp, val)| (inp, Instr::JumpCond(val))), OpType::Push => Ok(Value::parse(inp).map(|(inp, val)| (inp, Instr::Push(val)))?), OpType::Pop => u32::parse(inp).map(|(inp, val)| (inp, Instr::Pop(val))), OpType::OnAtom => AtomOp::parse(inp).map(|(inp, val)| (inp, Instr::OnAtom(val))), @@ -126,6 +132,7 @@ impl Instr<'_> { } Instr::CallLocal(val) => writer.write_all(&val.to_be_bytes())?, Instr::Jump(val) => writer.write_all(&val.to_be_bytes())?, + Instr::JumpCond(val) => writer.write_all(&val.to_be_bytes())?, Instr::Push(val) => val.write_to(writer)?, Instr::Pop(val) => writer.write_all(&val.to_be_bytes())?, Instr::DoMath2(val) => writer.write_all(&val.int_value().to_be_bytes())?, diff --git a/crates/fogtix-vm/src/main.rs b/crates/fogtix-vm/src/main.rs index bbe84b2..b310b6d 100644 --- a/crates/fogtix-vm/src/main.rs +++ b/crates/fogtix-vm/src/main.rs @@ -179,6 +179,44 @@ impl Process { break; } } + Instr::JumpCond(x) => { + let x: usize = match x.try_into() { + Ok(y) => y, + Err(_) => { + tracing::error!( + "jump to out-of-bounds address @ {} -> {}", + previptr, + x + ); + break; + } + }; + let doit = match self.stack.pop() { + None => { + tracing::error!( + "popped empty stack during condition jump eval @ {}", + previptr + ); + break; + } + Some(StackEntValue::Int(i)) => i != 0, + Some(StackEntValue::Atom(a)) => a != Atom(0, 0), + Some(z) => { + tracing::error!( + "encountered invalid condition value {:?} @ {}", + z, + previptr + ); + break; + } + }; + if doit { + self.instrp.1 = x; + if !self.verify_jumptarget(previptr, "jump-cond") { + break; + } + } + } Instr::Return => match self.callstack.pop() { Some(x) => self.instrp = x, None => {