feat: add conditional jumps
This commit is contained in:
parent
b410e7a5b8
commit
6557e172e7
|
@ -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 */
|
||||
|
|
|
@ -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())?,
|
||||
|
|
|
@ -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 => {
|
||||
|
|
Loading…
Reference in a new issue