feat(bytecode): swap should be able to swap the top item with any other in 2^16 range
reason: this is easy to implement as a fast operation in the interpreter, and reduces the need for a separate "temporary" stack.
This commit is contained in:
parent
b1ea85cf3e
commit
e65cfa9f91
|
@ -36,8 +36,9 @@ pub enum Instr<'a> {
|
|||
/// duplicates the top-$0 stack value, pushing it to the top of the stack
|
||||
Dup(u16),
|
||||
|
||||
/// swaps the 2 top-most stack values
|
||||
Swap,
|
||||
/// swaps the top stack value with the top-1-$0 stack value
|
||||
/// (`Swap(0)` swaps the two top-most stack values)
|
||||
Swap(u16),
|
||||
|
||||
/// basic atom operations
|
||||
ABuild,
|
||||
|
@ -60,7 +61,7 @@ impl Instr<'_> {
|
|||
Instr::Push(_) => OpType::Push,
|
||||
Instr::Pop(_) => OpType::Pop,
|
||||
Instr::Dup(_) => OpType::Dup,
|
||||
Instr::Swap => OpType::Swap,
|
||||
Instr::Swap(_) => OpType::Swap,
|
||||
Instr::ABuild => OpType::ABuild,
|
||||
Instr::ADecon => OpType::ADecon,
|
||||
Instr::DoMath2(_) => OpType::DoMath2,
|
||||
|
@ -112,10 +113,10 @@ impl<'a> crate::Parse<'a> for Instr<'a> {
|
|||
OpType::Push => Ok(Value::parse(inp).map(|(inp, val)| (inp, Instr::Push(val)))?),
|
||||
OpType::Pop => u16::parse(inp).map(|(inp, val)| (inp, Instr::Pop(val))),
|
||||
OpType::Dup => u16::parse(inp).map(|(inp, val)| (inp, Instr::Dup(val))),
|
||||
OpType::Swap => u16::parse(inp).map(|(inp, val)| (inp, Instr::Swap(val))),
|
||||
OpType::DoMath2 => MathBinOp::parse(inp).map(|(inp, val)| (inp, Instr::DoMath2(val))),
|
||||
OpType::Label => Ok((inp, Instr::Label)),
|
||||
OpType::Return => Ok((inp, Instr::Return)),
|
||||
OpType::Swap => Ok((inp, Instr::Swap)),
|
||||
OpType::ABuild => Ok((inp, Instr::ABuild)),
|
||||
OpType::ADecon => Ok((inp, Instr::ADecon)),
|
||||
}
|
||||
|
@ -139,8 +140,9 @@ impl Instr<'_> {
|
|||
Instr::Push(val) => val.write_to(writer)?,
|
||||
Instr::Pop(val) => writer.write_all(&val.to_be_bytes())?,
|
||||
Instr::Dup(val) => writer.write_all(&val.to_be_bytes())?,
|
||||
Instr::Swap(val) => writer.write_all(&val.to_be_bytes())?,
|
||||
Instr::DoMath2(val) => writer.write_all(&val.int_value().to_be_bytes())?,
|
||||
Instr::Label | Instr::Return | Instr::Swap | Instr::ABuild | Instr::ADecon => {}
|
||||
Instr::Label | Instr::Return | Instr::ABuild | Instr::ADecon => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -260,14 +260,15 @@ impl Process {
|
|||
};
|
||||
self.stack.push(x);
|
||||
}
|
||||
Instr::Swap => {
|
||||
Instr::Swap(delta) => {
|
||||
let ssl = self.stack.len();
|
||||
if ssl < 2 {
|
||||
tracing::error!("swap on empty stack @ {}", previptr);
|
||||
break;
|
||||
}
|
||||
let x = &mut self.stack[ssl - 2..ssl];
|
||||
let (y, z) = x.split_at_mut(1);
|
||||
let (y, z) = match ssl.checked_sub(usize::from(delta) + 2) {
|
||||
None => {
|
||||
tracing::error!("swap on too small stack @ {}", previptr);
|
||||
break;
|
||||
}
|
||||
Some(ltrg) => self.stack[ltrg..].split_at_mut(1),
|
||||
};
|
||||
core::mem::swap(&mut y[0], &mut z[0]);
|
||||
}
|
||||
Instr::ABuild => {
|
||||
|
|
Loading…
Reference in a new issue