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:
Alain Zscheile 2022-09-25 15:05:01 +02:00
parent b1ea85cf3e
commit e65cfa9f91
2 changed files with 15 additions and 12 deletions

View file

@ -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(())
}

View file

@ -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 => {