1
0

Experiment wih more optimizations

This commit is contained in:
Jeff 2024-12-11 09:26:38 -05:00
parent 395f0af213
commit 1777ad298b
29 changed files with 239 additions and 323 deletions

View File

@ -301,7 +301,7 @@ impl<'src> Compiler<'src> {
} }
fn get_last_operations<const COUNT: usize>(&self) -> Option<[Operation; COUNT]> { fn get_last_operations<const COUNT: usize>(&self) -> Option<[Operation; COUNT]> {
let mut n_operations = [Operation::Return; COUNT]; let mut n_operations = [Operation::RETURN; COUNT];
for (nth, operation) in n_operations.iter_mut().rev().zip( for (nth, operation) in n_operations.iter_mut().rev().zip(
self.instructions self.instructions
@ -338,14 +338,14 @@ impl<'src> Compiler<'src> {
let operation = instruction.operation(); let operation = instruction.operation();
if let Operation::LoadList = operation { if let Operation::LOAD_LIST = operation {
let LoadList { start_register, .. } = LoadList::from(instruction); let LoadList { start_register, .. } = LoadList::from(instruction);
let item_type = self.get_register_type(start_register)?; let item_type = self.get_register_type(start_register)?;
return Ok(Type::List(Box::new(item_type))); return Ok(Type::List(Box::new(item_type)));
} }
if let Operation::LoadSelf = operation { if let Operation::LOAD_SELF = operation {
return Ok(Type::SelfChunk); return Ok(Type::SelfChunk);
} }
@ -612,28 +612,28 @@ impl<'src> Compiler<'src> {
instruction: &Instruction, instruction: &Instruction,
) -> Result<(Argument, bool), CompileError> { ) -> Result<(Argument, bool), CompileError> {
let (argument, push_back) = match instruction.operation() { let (argument, push_back) = match instruction.operation() {
Operation::LoadConstant => (Argument::Constant(instruction.b_field()), false), Operation::LOAD_CONSTANT => (Argument::Constant(instruction.b_field()), false),
Operation::GetLocal => { Operation::GET_LOCAL => {
let local_index = instruction.b_field(); let local_index = instruction.b_field();
let (local, _) = self.get_local(local_index)?; let (local, _) = self.get_local(local_index)?;
(Argument::Register(local.register_index), false) (Argument::Register(local.register_index), false)
} }
Operation::LoadBoolean Operation::LOAD_BOOLEAN
| Operation::LoadList | Operation::LOAD_LIST
| Operation::LoadSelf | Operation::LOAD_SELF
| Operation::Add | Operation::ADD
| Operation::Subtract | Operation::SUBTRACT
| Operation::Multiply | Operation::MULTIPLY
| Operation::Divide | Operation::DIVIDE
| Operation::Modulo | Operation::MODULO
| Operation::Equal | Operation::EQUAL
| Operation::Less | Operation::LESS
| Operation::LessEqual | Operation::LESS_EQUAL
| Operation::Negate | Operation::NEGATE
| Operation::Not | Operation::NOT
| Operation::Call => (Argument::Register(instruction.a_field()), true), | Operation::CALL => (Argument::Register(instruction.a_field()), true),
Operation::CallNative => { Operation::CALL_NATIVE => {
let function = NativeFunction::from(instruction.b_field()); let function = NativeFunction::from(instruction.b_field());
if function.returns_value() { if function.returns_value() {
@ -665,7 +665,7 @@ impl<'src> Compiler<'src> {
position: self.previous_position, position: self.previous_position,
})?; })?;
let (left, push_back_left) = self.handle_binary_argument(&left_instruction)?; let (left, push_back_left) = self.handle_binary_argument(&left_instruction)?;
let left_is_mutable_local = if let Operation::GetLocal = left_instruction.operation() { let left_is_mutable_local = if let Operation::GET_LOCAL = left_instruction.operation() {
let GetLocal { local_index, .. } = GetLocal::from(&left_instruction); let GetLocal { local_index, .. } = GetLocal::from(&left_instruction);
self.locals self.locals
@ -812,7 +812,7 @@ impl<'src> Compiler<'src> {
} }
fn parse_comparison_binary(&mut self) -> Result<(), CompileError> { fn parse_comparison_binary(&mut self) -> Result<(), CompileError> {
if let Some([Operation::Equal | Operation::Less | Operation::LessEqual, _, _]) = if let Some([Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL, _, _]) =
self.get_last_operations() self.get_last_operations()
{ {
return Err(CompileError::CannotChainComparison { return Err(CompileError::CannotChainComparison {
@ -886,7 +886,7 @@ impl<'src> Compiler<'src> {
fn parse_logical_binary(&mut self) -> Result<(), CompileError> { fn parse_logical_binary(&mut self) -> Result<(), CompileError> {
let is_logic_chain = matches!( let is_logic_chain = matches!(
self.get_last_operations(), self.get_last_operations(),
Some([Operation::Test, Operation::Jump, _]) Some([Operation::TEST, Operation::JUMP, _])
); );
let (mut left_instruction, left_type, left_position) = self.pop_last_instruction()?; let (mut left_instruction, left_type, left_position) = self.pop_last_instruction()?;
@ -1204,7 +1204,7 @@ impl<'src> Compiler<'src> {
match else_block_distance { match else_block_distance {
0 => {} 0 => {}
1 => { 1 => {
if let Some([Operation::LoadBoolean | Operation::LoadConstant]) = if let Some([Operation::LOAD_BOOLEAN | Operation::LOAD_CONSTANT]) =
self.get_last_operations() self.get_last_operations()
{ {
let (mut loader, _, _) = self.instructions.last_mut().unwrap(); let (mut loader, _, _) = self.instructions.last_mut().unwrap();
@ -1291,10 +1291,10 @@ impl<'src> Compiler<'src> {
if matches!( if matches!(
self.get_last_operations(), self.get_last_operations(),
Some([ Some([
Operation::Equal | Operation::Less | Operation::LessEqual, Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL,
Operation::Jump, Operation::JUMP,
Operation::LoadBoolean, Operation::LOAD_BOOLEAN,
Operation::LoadBoolean, Operation::LOAD_BOOLEAN,
],) ],)
) { ) {
self.instructions.pop(); self.instructions.pop();

View File

@ -29,11 +29,11 @@ pub fn optimize_test_with_explicit_booleans(compiler: &mut Compiler) {
if matches!( if matches!(
compiler.get_last_operations(), compiler.get_last_operations(),
Some([ Some([
Operation::Equal | Operation::Less | Operation::LessEqual, Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL,
Operation::Test, Operation::TEST,
Operation::Jump, Operation::JUMP,
Operation::LoadBoolean, Operation::LOAD_BOOLEAN,
Operation::LoadBoolean, Operation::LOAD_BOOLEAN,
]) ])
) { ) {
log::debug!("Removing redundant test, jump and boolean loaders after comparison"); log::debug!("Removing redundant test, jump and boolean loaders after comparison");
@ -70,10 +70,10 @@ pub fn optimize_test_with_loader_arguments(compiler: &mut Compiler) {
if !matches!( if !matches!(
compiler.get_last_operations(), compiler.get_last_operations(),
Some([ Some([
Operation::Test, Operation::TEST,
Operation::Jump, Operation::JUMP,
Operation::LoadBoolean | Operation::LoadConstant, Operation::LOAD_BOOLEAN | Operation::LOAD_CONSTANT,
Operation::LoadBoolean | Operation::LoadConstant, Operation::LOAD_BOOLEAN | Operation::LOAD_CONSTANT,
]) ])
) { ) {
return; return;

View File

@ -21,7 +21,7 @@ impl From<&Instruction> for Add {
impl From<Add> for Instruction { impl From<Add> for Instruction {
fn from(add: Add) -> Self { fn from(add: Add) -> Self {
let operation = Operation::Add; let operation = Operation::ADD;
let a = add.destination; let a = add.destination;
let (b, b_is_constant) = add.left.as_index_and_constant_flag(); let (b, b_is_constant) = add.left.as_index_and_constant_flag();
let (c, c_is_constant) = add.right.as_index_and_constant_flag(); let (c, c_is_constant) = add.right.as_index_and_constant_flag();

View File

@ -26,6 +26,6 @@ impl From<Call> for Instruction {
let (b, b_is_constant) = call.function.as_index_and_constant_flag(); let (b, b_is_constant) = call.function.as_index_and_constant_flag();
let c = call.argument_count; let c = call.argument_count;
Instruction::new(Operation::Call, a, b, c, b_is_constant, false, false) Instruction::new(Operation::CALL, a, b, c, b_is_constant, false, false)
} }
} }

View File

@ -21,7 +21,7 @@ impl From<&Instruction> for CallNative {
impl From<CallNative> for Instruction { impl From<CallNative> for Instruction {
fn from(call_native: CallNative) -> Self { fn from(call_native: CallNative) -> Self {
let operation = Operation::CallNative; let operation = Operation::CALL_NATIVE;
let a = call_native.destination; let a = call_native.destination;
let b = call_native.function as u8; let b = call_native.function as u8;
let c = call_native.argument_count; let c = call_native.argument_count;

View File

@ -16,7 +16,7 @@ impl From<&Instruction> for Close {
impl From<Close> for Instruction { impl From<Close> for Instruction {
fn from(close: Close) -> Self { fn from(close: Close) -> Self {
let operation = Operation::Close; let operation = Operation::CLOSE;
let (a, b, c) = (0, close.from, close.to); let (a, b, c) = (0, close.from, close.to);
Instruction::new(operation, a, b, c, false, false, false) Instruction::new(operation, a, b, c, false, false, false)

View File

@ -21,7 +21,7 @@ impl From<&Instruction> for Divide {
impl From<Divide> for Instruction { impl From<Divide> for Instruction {
fn from(divide: Divide) -> Self { fn from(divide: Divide) -> Self {
let operation = Operation::Divide; let operation = Operation::DIVIDE;
let a = divide.destination; let a = divide.destination;
let (b, b_is_constant) = divide.left.as_index_and_constant_flag(); let (b, b_is_constant) = divide.left.as_index_and_constant_flag();
let (c, c_is_constant) = divide.right.as_index_and_constant_flag(); let (c, c_is_constant) = divide.right.as_index_and_constant_flag();

View File

@ -24,7 +24,7 @@ impl From<&Instruction> for Equal {
impl From<Equal> for Instruction { impl From<Equal> for Instruction {
fn from(equal: Equal) -> Self { fn from(equal: Equal) -> Self {
let operation = Operation::Equal; let operation = Operation::EQUAL;
let a = equal.destination; let a = equal.destination;
let (b, b_is_constant) = equal.left.as_index_and_constant_flag(); let (b, b_is_constant) = equal.left.as_index_and_constant_flag();
let (c, c_is_constant) = equal.right.as_index_and_constant_flag(); let (c, c_is_constant) = equal.right.as_index_and_constant_flag();

View File

@ -19,7 +19,7 @@ impl From<&Instruction> for GetLocal {
impl From<GetLocal> for Instruction { impl From<GetLocal> for Instruction {
fn from(get_local: GetLocal) -> Self { fn from(get_local: GetLocal) -> Self {
let operation = Operation::GetLocal; let operation = Operation::GET_LOCAL;
let a = get_local.destination; let a = get_local.destination;
let b = get_local.local_index; let b = get_local.local_index;

View File

@ -16,7 +16,7 @@ impl From<&Instruction> for Jump {
impl From<Jump> for Instruction { impl From<Jump> for Instruction {
fn from(jump: Jump) -> Self { fn from(jump: Jump) -> Self {
let operation = Operation::Jump; let operation = Operation::JUMP;
let b = jump.offset; let b = jump.offset;
let c = jump.is_positive as u8; let c = jump.is_positive as u8;

View File

@ -24,7 +24,7 @@ impl From<&Instruction> for Less {
impl From<Less> for Instruction { impl From<Less> for Instruction {
fn from(less: Less) -> Self { fn from(less: Less) -> Self {
let operation = Operation::Less; let operation = Operation::LESS;
let a = less.destination; let a = less.destination;
let (b, b_is_constant) = less.left.as_index_and_constant_flag(); let (b, b_is_constant) = less.left.as_index_and_constant_flag();
let (c, c_is_constant) = less.right.as_index_and_constant_flag(); let (c, c_is_constant) = less.right.as_index_and_constant_flag();

View File

@ -24,7 +24,7 @@ impl From<&Instruction> for LessEqual {
impl From<LessEqual> for Instruction { impl From<LessEqual> for Instruction {
fn from(less_equal: LessEqual) -> Self { fn from(less_equal: LessEqual) -> Self {
let operation = Operation::LessEqual; let operation = Operation::LESS_EQUAL;
let a = less_equal.destination; let a = less_equal.destination;
let (b, b_options) = less_equal.left.as_index_and_constant_flag(); let (b, b_options) = less_equal.left.as_index_and_constant_flag();
let (c, c_options) = less_equal.right.as_index_and_constant_flag(); let (c, c_options) = less_equal.right.as_index_and_constant_flag();

View File

@ -22,7 +22,7 @@ impl From<&Instruction> for LoadBoolean {
impl From<LoadBoolean> for Instruction { impl From<LoadBoolean> for Instruction {
fn from(load_boolean: LoadBoolean) -> Self { fn from(load_boolean: LoadBoolean) -> Self {
let operation = Operation::LoadBoolean; let operation = Operation::LOAD_BOOLEAN;
let a = load_boolean.destination; let a = load_boolean.destination;
let b = load_boolean.value as u8; let b = load_boolean.value as u8;
let c = load_boolean.jump_next as u8; let c = load_boolean.jump_next as u8;

View File

@ -22,7 +22,7 @@ impl From<&Instruction> for LoadConstant {
impl From<LoadConstant> for Instruction { impl From<LoadConstant> for Instruction {
fn from(load_constant: LoadConstant) -> Self { fn from(load_constant: LoadConstant) -> Self {
let operation = Operation::LoadConstant; let operation = Operation::LOAD_CONSTANT;
let a = load_constant.destination; let a = load_constant.destination;
let b = load_constant.constant_index; let b = load_constant.constant_index;
let c = load_constant.jump_next as u8; let c = load_constant.jump_next as u8;

View File

@ -19,7 +19,7 @@ impl From<&Instruction> for LoadList {
impl From<LoadList> for Instruction { impl From<LoadList> for Instruction {
fn from(load_list: LoadList) -> Self { fn from(load_list: LoadList) -> Self {
let operation = Operation::LoadList; let operation = Operation::LOAD_LIST;
let a = load_list.destination; let a = load_list.destination;
let b = load_list.start_register; let b = load_list.start_register;

View File

@ -14,7 +14,7 @@ impl From<&Instruction> for LoadSelf {
impl From<LoadSelf> for Instruction { impl From<LoadSelf> for Instruction {
fn from(load_self: LoadSelf) -> Self { fn from(load_self: LoadSelf) -> Self {
let operation = Operation::LoadSelf; let operation = Operation::LOAD_SELF;
let a = load_self.destination; let a = load_self.destination;
Instruction::new(operation, a, 0, 0, false, false, false) Instruction::new(operation, a, 0, 0, false, false, false)

View File

@ -172,7 +172,7 @@ impl Instruction {
c_is_constant: bool, c_is_constant: bool,
d: bool, d: bool,
) -> Instruction { ) -> Instruction {
let bits = operation as u32 let bits = operation.0 as u32
| ((b_is_constant as u32) << 5) | ((b_is_constant as u32) << 5)
| ((c_is_constant as u32) << 6) | ((c_is_constant as u32) << 6)
| ((d as u32) << 7) | ((d as u32) << 7)
@ -186,7 +186,7 @@ impl Instruction {
pub fn operation(&self) -> Operation { pub fn operation(&self) -> Operation {
let operation_bits = self.0 & 0b0001_1111; let operation_bits = self.0 & 0b0001_1111;
Operation::from(operation_bits as u8) Operation(operation_bits as u8)
} }
pub fn b_is_constant(&self) -> bool { pub fn b_is_constant(&self) -> bool {
@ -425,40 +425,40 @@ impl Instruction {
pub fn is_math(&self) -> bool { pub fn is_math(&self) -> bool {
matches!( matches!(
self.operation(), self.operation(),
Operation::Add Operation::ADD
| Operation::Subtract | Operation::SUBTRACT
| Operation::Multiply | Operation::MULTIPLY
| Operation::Divide | Operation::DIVIDE
| Operation::Modulo | Operation::MODULO
) )
} }
pub fn is_comparison(&self) -> bool { pub fn is_comparison(&self) -> bool {
matches!( matches!(
self.operation(), self.operation(),
Operation::Equal | Operation::Less | Operation::LessEqual Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL
) )
} }
pub fn as_argument(&self) -> Option<Argument> { pub fn as_argument(&self) -> Option<Argument> {
match self.operation() { match self.operation() {
Operation::LoadConstant => Some(Argument::Constant(self.b_field())), Operation::LOAD_CONSTANT => Some(Argument::Constant(self.b_field())),
Operation::LoadBoolean Operation::LOAD_BOOLEAN
| Operation::LoadList | Operation::LOAD_LIST
| Operation::LoadSelf | Operation::LOAD_SELF
| Operation::GetLocal | Operation::GET_LOCAL
| Operation::Add | Operation::ADD
| Operation::Subtract | Operation::SUBTRACT
| Operation::Multiply | Operation::MULTIPLY
| Operation::Divide | Operation::DIVIDE
| Operation::Modulo | Operation::MODULO
| Operation::Equal | Operation::EQUAL
| Operation::Less | Operation::LESS
| Operation::LessEqual | Operation::LESS_EQUAL
| Operation::Negate | Operation::NEGATE
| Operation::Not | Operation::NOT
| Operation::Call => Some(Argument::Register(self.a_field())), | Operation::CALL => Some(Argument::Register(self.a_field())),
Operation::CallNative => { Operation::CALL_NATIVE => {
let function = NativeFunction::from(self.b_field()); let function = NativeFunction::from(self.b_field());
if function.returns_value() { if function.returns_value() {
@ -496,50 +496,51 @@ impl Instruction {
pub fn yields_value(&self) -> bool { pub fn yields_value(&self) -> bool {
match self.operation() { match self.operation() {
Operation::LoadBoolean Operation::LOAD_BOOLEAN
| Operation::LoadConstant | Operation::LOAD_CONSTANT
| Operation::LoadList | Operation::LOAD_LIST
| Operation::LoadSelf | Operation::LOAD_SELF
| Operation::GetLocal | Operation::GET_LOCAL
| Operation::Add | Operation::ADD
| Operation::Subtract | Operation::SUBTRACT
| Operation::Multiply | Operation::MULTIPLY
| Operation::Divide | Operation::DIVIDE
| Operation::Modulo | Operation::MODULO
| Operation::Negate | Operation::NEGATE
| Operation::Not | Operation::NOT
| Operation::Equal | Operation::EQUAL
| Operation::Less | Operation::LESS
| Operation::LessEqual | Operation::LESS_EQUAL
| Operation::Call => true, | Operation::CALL => true,
Operation::CallNative => { Operation::CALL_NATIVE => {
let function = NativeFunction::from(self.b_field()); let function = NativeFunction::from(self.b_field());
function.returns_value() function.returns_value()
} }
Operation::Move Operation::MOVE
| Operation::Close | Operation::CLOSE
| Operation::SetLocal | Operation::SET_LOCAL
| Operation::Test | Operation::TEST
| Operation::TestSet | Operation::TEST_SET
| Operation::Jump | Operation::JUMP
| Operation::Return => false, | Operation::RETURN => false,
_ => Operation::panic_from_unknown_code(self.operation().0),
} }
} }
pub fn disassembly_info(&self) -> String { pub fn disassembly_info(&self) -> String {
match self.operation() { match self.operation() {
Operation::Move => { Operation::MOVE => {
let Move { from, to } = Move::from(self); let Move { from, to } = Move::from(self);
format!("R{to} = R{from}") format!("R{to} = R{from}")
} }
Operation::Close => { Operation::CLOSE => {
let Close { from, to } = Close::from(self); let Close { from, to } = Close::from(self);
format!("R{from}..R{to}") format!("R{from}..R{to}")
} }
Operation::LoadBoolean => { Operation::LOAD_BOOLEAN => {
let LoadBoolean { let LoadBoolean {
destination, destination,
value, value,
@ -552,7 +553,7 @@ impl Instruction {
format!("R{destination} = {value}") format!("R{destination} = {value}")
} }
} }
Operation::LoadConstant => { Operation::LOAD_CONSTANT => {
let LoadConstant { let LoadConstant {
destination, destination,
constant_index, constant_index,
@ -565,7 +566,7 @@ impl Instruction {
format!("R{destination} = C{constant_index}") format!("R{destination} = C{constant_index}")
} }
} }
Operation::LoadList => { Operation::LOAD_LIST => {
let LoadList { let LoadList {
destination, destination,
start_register, start_register,
@ -574,12 +575,12 @@ impl Instruction {
format!("R{destination} = [R{start_register}..=R{end_register}]",) format!("R{destination} = [R{start_register}..=R{end_register}]",)
} }
Operation::LoadSelf => { Operation::LOAD_SELF => {
let LoadSelf { destination } = LoadSelf::from(self); let LoadSelf { destination } = LoadSelf::from(self);
format!("R{destination} = self") format!("R{destination} = self")
} }
Operation::GetLocal => { Operation::GET_LOCAL => {
let GetLocal { let GetLocal {
destination, destination,
local_index, local_index,
@ -587,7 +588,7 @@ impl Instruction {
format!("R{destination} = L{local_index}") format!("R{destination} = L{local_index}")
} }
Operation::SetLocal => { Operation::SET_LOCAL => {
let SetLocal { let SetLocal {
register_index, register_index,
local_index, local_index,
@ -595,7 +596,7 @@ impl Instruction {
format!("L{local_index} = R{register_index}") format!("L{local_index} = R{register_index}")
} }
Operation::Add => { Operation::ADD => {
let Add { let Add {
destination, destination,
left, left,
@ -604,7 +605,7 @@ impl Instruction {
format!("R{destination} = {left} + {right}") format!("R{destination} = {left} + {right}")
} }
Operation::Subtract => { Operation::SUBTRACT => {
let Subtract { let Subtract {
destination, destination,
left, left,
@ -613,7 +614,7 @@ impl Instruction {
format!("R{destination} = {left} - {right}") format!("R{destination} = {left} - {right}")
} }
Operation::Multiply => { Operation::MULTIPLY => {
let Multiply { let Multiply {
destination, destination,
left, left,
@ -622,7 +623,7 @@ impl Instruction {
format!("R{destination} = {left} * {right}") format!("R{destination} = {left} * {right}")
} }
Operation::Divide => { Operation::DIVIDE => {
let Divide { let Divide {
destination, destination,
left, left,
@ -631,7 +632,7 @@ impl Instruction {
format!("R{destination} = {left} / {right}") format!("R{destination} = {left} / {right}")
} }
Operation::Modulo => { Operation::MODULO => {
let Modulo { let Modulo {
destination, destination,
left, left,
@ -640,7 +641,7 @@ impl Instruction {
format!("R{destination} = {left} % {right}") format!("R{destination} = {left} % {right}")
} }
Operation::Test => { Operation::TEST => {
let Test { let Test {
argument, argument,
test_value: value, test_value: value,
@ -649,7 +650,7 @@ impl Instruction {
format!("if {bang}{argument} {{ JUMP +1 }}",) format!("if {bang}{argument} {{ JUMP +1 }}",)
} }
Operation::TestSet => { Operation::TEST_SET => {
let TestSet { let TestSet {
destination, destination,
argument, argument,
@ -659,7 +660,7 @@ impl Instruction {
format!("if {bang}{argument} {{ JUMP +1 }} else {{ R{destination} = {argument} }}") format!("if {bang}{argument} {{ JUMP +1 }} else {{ R{destination} = {argument} }}")
} }
Operation::Equal => { Operation::EQUAL => {
let Equal { let Equal {
destination, destination,
value, value,
@ -670,7 +671,7 @@ impl Instruction {
format!("R{destination} = {left} {comparison_symbol} {right}") format!("R{destination} = {left} {comparison_symbol} {right}")
} }
Operation::Less => { Operation::LESS => {
let Less { let Less {
destination, destination,
value, value,
@ -681,7 +682,7 @@ impl Instruction {
format!("R{destination} = {left} {comparison_symbol} {right}") format!("R{destination} = {left} {comparison_symbol} {right}")
} }
Operation::LessEqual => { Operation::LESS_EQUAL => {
let LessEqual { let LessEqual {
destination, destination,
value, value,
@ -692,7 +693,7 @@ impl Instruction {
format!("R{destination} = {left} {comparison_symbol} {right}") format!("R{destination} = {left} {comparison_symbol} {right}")
} }
Operation::Negate => { Operation::NEGATE => {
let Negate { let Negate {
destination, destination,
argument, argument,
@ -700,7 +701,7 @@ impl Instruction {
format!("R{destination} = -{argument}") format!("R{destination} = -{argument}")
} }
Operation::Not => { Operation::NOT => {
let Not { let Not {
destination, destination,
argument, argument,
@ -708,7 +709,7 @@ impl Instruction {
format!("R{destination} = !{argument}") format!("R{destination} = !{argument}")
} }
Operation::Jump => { Operation::JUMP => {
let Jump { let Jump {
offset, offset,
is_positive, is_positive,
@ -720,7 +721,7 @@ impl Instruction {
format!("JUMP -{offset}") format!("JUMP -{offset}")
} }
} }
Operation::Call => { Operation::CALL => {
let Call { let Call {
destination, destination,
function, function,
@ -737,7 +738,7 @@ impl Instruction {
} }
} }
} }
Operation::CallNative => { Operation::CALL_NATIVE => {
let CallNative { let CallNative {
destination, destination,
function, function,
@ -763,7 +764,7 @@ impl Instruction {
info_string info_string
} }
Operation::Return => { Operation::RETURN => {
let Return { let Return {
should_return_value, should_return_value,
} = Return::from(self); } = Return::from(self);

View File

@ -21,7 +21,7 @@ impl From<&Instruction> for Modulo {
impl From<Modulo> for Instruction { impl From<Modulo> for Instruction {
fn from(modulo: Modulo) -> Self { fn from(modulo: Modulo) -> Self {
let operation = Operation::Modulo; let operation = Operation::MODULO;
let a = modulo.destination; let a = modulo.destination;
let (b, b_is_constant) = modulo.left.as_index_and_constant_flag(); let (b, b_is_constant) = modulo.left.as_index_and_constant_flag();
let (c, c_is_constant) = modulo.right.as_index_and_constant_flag(); let (c, c_is_constant) = modulo.right.as_index_and_constant_flag();

View File

@ -16,7 +16,7 @@ impl From<&Instruction> for Move {
impl From<Move> for Instruction { impl From<Move> for Instruction {
fn from(r#move: Move) -> Self { fn from(r#move: Move) -> Self {
let operation = Operation::Move; let operation = Operation::MOVE;
let b = r#move.from; let b = r#move.from;
let c = r#move.to; let c = r#move.to;

View File

@ -21,7 +21,7 @@ impl From<&Instruction> for Multiply {
impl From<Multiply> for Instruction { impl From<Multiply> for Instruction {
fn from(multiply: Multiply) -> Self { fn from(multiply: Multiply) -> Self {
let operation = Operation::Multiply; let operation = Operation::MULTIPLY;
let a = multiply.destination; let a = multiply.destination;
let (b, b_options) = multiply.left.as_index_and_constant_flag(); let (b, b_options) = multiply.left.as_index_and_constant_flag();
let (c, c_options) = multiply.right.as_index_and_constant_flag(); let (c, c_options) = multiply.right.as_index_and_constant_flag();

View File

@ -19,7 +19,7 @@ impl From<&Instruction> for Negate {
impl From<Negate> for Instruction { impl From<Negate> for Instruction {
fn from(negate: Negate) -> Self { fn from(negate: Negate) -> Self {
let operation = Operation::Negate; let operation = Operation::NEGATE;
let a = negate.destination; let a = negate.destination;
let (b, b_is_constant) = negate.argument.as_index_and_constant_flag(); let (b, b_is_constant) = negate.argument.as_index_and_constant_flag();
let c = 0; let c = 0;

View File

@ -19,7 +19,7 @@ impl From<&Instruction> for Not {
impl From<Not> for Instruction { impl From<Not> for Instruction {
fn from(not: Not) -> Self { fn from(not: Not) -> Self {
let operation = Operation::Not; let operation = Operation::NOT;
let a = not.destination; let a = not.destination;
let (b, b_is_constant) = not.argument.as_index_and_constant_flag(); let (b, b_is_constant) = not.argument.as_index_and_constant_flag();

View File

@ -4,128 +4,71 @@ use std::fmt::{self, Debug, Display, Formatter};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
pub const MOVE_BYTE: u8 = 0;
pub const CLOSE_BYTE: u8 = 1;
pub const LOAD_BOOLEAN_BYTE: u8 = 2;
pub const LOAD_CONSTANT_BYTE: u8 = 3;
pub const LOAD_LIST_BYTE: u8 = 4;
pub const LOAD_SELF_BYTE: u8 = 5;
pub const GET_LOCAL_BYTE: u8 = 6;
pub const SET_LOCAL_BYTE: u8 = 7;
pub const ADD_BYTE: u8 = 8;
pub const SUBTRACT_BYTE: u8 = 9;
pub const MULTIPLY_BYTE: u8 = 10;
pub const DIVIDE_BYTE: u8 = 11;
pub const MODULO_BYTE: u8 = 12;
pub const TEST_BYTE: u8 = 13;
pub const TEST_SET_BYTE: u8 = 14;
pub const EQUAL_BYTE: u8 = 15;
pub const LESS_BYTE: u8 = 16;
pub const LESS_EQUAL_BYTE: u8 = 17;
pub const NEGATE_BYTE: u8 = 18;
pub const NOT_BYTE: u8 = 19;
pub const CALL_BYTE: u8 = 20;
pub const CALL_NATIVE_BYTE: u8 = 21;
pub const JUMP_BYTE: u8 = 22;
pub const RETURN_BYTE: u8 = 23;
/// Part of an [Instruction][crate::Instruction] that is encoded as a single byte. /// Part of an [Instruction][crate::Instruction] that is encoded as a single byte.
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
#[repr(u8)] pub struct Operation(pub u8);
pub enum Operation {
Move = MOVE_BYTE,
Close = CLOSE_BYTE,
LoadBoolean = LOAD_BOOLEAN_BYTE,
LoadConstant = LOAD_CONSTANT_BYTE,
LoadList = LOAD_LIST_BYTE,
LoadSelf = LOAD_SELF_BYTE,
GetLocal = GET_LOCAL_BYTE,
SetLocal = SET_LOCAL_BYTE,
Add = ADD_BYTE,
Subtract = SUBTRACT_BYTE,
Multiply = MULTIPLY_BYTE,
Divide = DIVIDE_BYTE,
Modulo = MODULO_BYTE,
Test = TEST_BYTE,
TestSet = TEST_SET_BYTE,
Equal = EQUAL_BYTE,
Less = LESS_BYTE,
LessEqual = LESS_EQUAL_BYTE,
Negate = NEGATE_BYTE,
Not = NOT_BYTE,
Call = CALL_BYTE,
CallNative = CALL_NATIVE_BYTE,
Jump = JUMP_BYTE,
Return = RETURN_BYTE,
}
impl From<u8> for Operation { impl Operation {
fn from(byte: u8) -> Self { pub const MOVE: Operation = Operation(0);
match byte { pub const CLOSE: Operation = Operation(1);
MOVE_BYTE => Self::Move, pub const LOAD_BOOLEAN: Operation = Operation(2);
CLOSE_BYTE => Self::Close, pub const LOAD_CONSTANT: Operation = Operation(3);
LOAD_BOOLEAN_BYTE => Self::LoadBoolean, pub const LOAD_LIST: Operation = Operation(4);
LOAD_CONSTANT_BYTE => Self::LoadConstant, pub const LOAD_SELF: Operation = Operation(5);
LOAD_LIST_BYTE => Self::LoadList, pub const GET_LOCAL: Operation = Operation(6);
LOAD_SELF_BYTE => Self::LoadSelf, pub const SET_LOCAL: Operation = Operation(7);
GET_LOCAL_BYTE => Self::GetLocal, pub const ADD: Operation = Operation(8);
SET_LOCAL_BYTE => Self::SetLocal, pub const SUBTRACT: Operation = Operation(9);
ADD_BYTE => Self::Add, pub const MULTIPLY: Operation = Operation(10);
SUBTRACT_BYTE => Self::Subtract, pub const DIVIDE: Operation = Operation(11);
MULTIPLY_BYTE => Self::Multiply, pub const MODULO: Operation = Operation(12);
DIVIDE_BYTE => Self::Divide, pub const TEST: Operation = Operation(13);
MODULO_BYTE => Self::Modulo, pub const TEST_SET: Operation = Operation(14);
TEST_BYTE => Self::Test, pub const EQUAL: Operation = Operation(15);
TEST_SET_BYTE => Self::TestSet, pub const LESS: Operation = Operation(16);
EQUAL_BYTE => Self::Equal, pub const LESS_EQUAL: Operation = Operation(17);
LESS_BYTE => Self::Less, pub const NEGATE: Operation = Operation(18);
LESS_EQUAL_BYTE => Self::LessEqual, pub const NOT: Operation = Operation(19);
NEGATE_BYTE => Self::Negate, pub const CALL: Operation = Operation(20);
NOT_BYTE => Self::Not, pub const CALL_NATIVE: Operation = Operation(21);
CALL_BYTE => Self::Call, pub const JUMP: Operation = Operation(22);
CALL_NATIVE_BYTE => Self::CallNative, pub const RETURN: Operation = Operation(23);
JUMP_BYTE => Self::Jump,
RETURN_BYTE => Self::Return,
_ => {
if cfg!(debug_assertions) {
panic!("Invalid operation byte: {}", byte)
} else {
Self::Return
}
}
}
}
} }
impl Operation { impl Operation {
pub fn name(self) -> &'static str { pub fn name(self) -> &'static str {
match self { match self {
Self::Move => "MOVE", Self::MOVE => "MOVE",
Self::Close => "CLOSE", Self::CLOSE => "CLOSE",
Self::LoadBoolean => "LOAD_BOOLEAN", Self::LOAD_BOOLEAN => "LOAD_BOOLEAN",
Self::LoadConstant => "LOAD_CONSTANT", Self::LOAD_CONSTANT => "LOAD_CONSTANT",
Self::LoadList => "LOAD_LIST", Self::LOAD_LIST => "LOAD_LIST",
Self::LoadSelf => "LOAD_SELF", Self::LOAD_SELF => "LOAD_SELF",
Self::GetLocal => "GET_LOCAL", Self::GET_LOCAL => "GET_LOCAL",
Self::SetLocal => "SET_LOCAL", Self::SET_LOCAL => "SET_LOCAL",
Self::Add => "ADD", Self::ADD => "ADD",
Self::Subtract => "SUBTRACT", Self::SUBTRACT => "SUBTRACT",
Self::Multiply => "MULTIPLY", Self::MULTIPLY => "MULTIPLY",
Self::Divide => "DIVIDE", Self::DIVIDE => "DIVIDE",
Self::Modulo => "MODULO", Self::MODULO => "MODULO",
Self::Test => "TEST", Self::TEST => "TEST",
Self::TestSet => "TEST_SET", Self::TEST_SET => "TEST_SET",
Self::Equal => "EQUAL", Self::EQUAL => "EQUAL",
Self::Less => "LESS", Self::LESS => "LESS",
Self::LessEqual => "LESS_EQUAL", Self::LESS_EQUAL => "LESS_EQUAL",
Self::Negate => "NEGATE", Self::NEGATE => "NEGATE",
Self::Not => "NOT", Self::NOT => "NOT",
Self::Call => "CALL", Self::CALL => "CALL",
Self::CallNative => "CALL_NATIVE", Self::CALL_NATIVE => "CALL_NATIVE",
Self::Jump => "JUMP", Self::JUMP => "JUMP",
Self::Return => "RETURN", Self::RETURN => "RETURN",
_ => Self::panic_from_unknown_code(self.0),
} }
} }
pub fn panic_from_unknown_code(code: u8) -> ! {
panic!("Unknown operation code: {code}");
}
} }
impl Debug for Operation { impl Debug for Operation {
@ -139,54 +82,3 @@ impl Display for Operation {
write!(f, "{}", self.name()) write!(f, "{}", self.name())
} }
} }
#[cfg(test)]
mod tests {
use super::*;
const ALL_OPERATIONS: [Operation; 24] = [
Operation::Move,
Operation::Close,
Operation::LoadBoolean,
Operation::LoadConstant,
Operation::LoadList,
Operation::LoadSelf,
Operation::GetLocal,
Operation::SetLocal,
Operation::Add,
Operation::Subtract,
Operation::Multiply,
Operation::Divide,
Operation::Modulo,
Operation::Test,
Operation::TestSet,
Operation::Equal,
Operation::Less,
Operation::LessEqual,
Operation::Negate,
Operation::Not,
Operation::Call,
Operation::CallNative,
Operation::Jump,
Operation::Return,
];
#[test]
fn operations_are_unique() {
for (i, operation) in ALL_OPERATIONS.into_iter().enumerate() {
assert_eq!(i, operation as usize);
}
}
#[test]
fn operation_uses_five_bits() {
for operation in ALL_OPERATIONS {
assert_eq!(operation as u8 & 0b1110_0000, 0);
}
}
#[test]
fn operation_is_one_byte() {
assert_eq!(size_of::<Operation>(), 1);
}
}

View File

@ -16,7 +16,7 @@ impl From<&Instruction> for Return {
impl From<Return> for Instruction { impl From<Return> for Instruction {
fn from(r#return: Return) -> Self { fn from(r#return: Return) -> Self {
let operation = Operation::Return; let operation = Operation::RETURN;
let b = r#return.should_return_value as u8; let b = r#return.should_return_value as u8;
Instruction::new(operation, 0, b, 0, false, false, false) Instruction::new(operation, 0, b, 0, false, false, false)

View File

@ -19,7 +19,7 @@ impl From<&Instruction> for SetLocal {
impl From<SetLocal> for Instruction { impl From<SetLocal> for Instruction {
fn from(set_local: SetLocal) -> Self { fn from(set_local: SetLocal) -> Self {
let operation = Operation::SetLocal; let operation = Operation::SET_LOCAL;
let b = set_local.register_index; let b = set_local.register_index;
let c = set_local.local_index; let c = set_local.local_index;

View File

@ -21,7 +21,7 @@ impl From<&Instruction> for Subtract {
impl From<Subtract> for Instruction { impl From<Subtract> for Instruction {
fn from(subtract: Subtract) -> Self { fn from(subtract: Subtract) -> Self {
let operation = Operation::Subtract; let operation = Operation::SUBTRACT;
let a = subtract.destination; let a = subtract.destination;
let (b, b_is_constant) = subtract.left.as_index_and_constant_flag(); let (b, b_is_constant) = subtract.left.as_index_and_constant_flag();
let (c, c_is_constant) = subtract.right.as_index_and_constant_flag(); let (c, c_is_constant) = subtract.right.as_index_and_constant_flag();

View File

@ -19,7 +19,7 @@ impl From<&Instruction> for Test {
impl From<Test> for Instruction { impl From<Test> for Instruction {
fn from(test: Test) -> Self { fn from(test: Test) -> Self {
let operation = Operation::Test; let operation = Operation::TEST;
let (b, b_is_constant) = test.argument.as_index_and_constant_flag(); let (b, b_is_constant) = test.argument.as_index_and_constant_flag();
let c = test.test_value as u8; let c = test.test_value as u8;

View File

@ -22,7 +22,7 @@ impl From<&Instruction> for TestSet {
impl From<TestSet> for Instruction { impl From<TestSet> for Instruction {
fn from(test_set: TestSet) -> Self { fn from(test_set: TestSet) -> Self {
let operation = Operation::Test; let operation = Operation::TEST;
let a = test_set.destination; let a = test_set.destination;
let (b, b_is_constant) = test_set.argument.as_index_and_constant_flag(); let (b, b_is_constant) = test_set.argument.as_index_and_constant_flag();
let c = test_set.test_value as u8; let c = test_set.test_value as u8;

View File

@ -90,6 +90,7 @@ impl<'a> Vm<'a> {
position position
} }
#[allow(clippy::needless_lifetimes)]
fn r#move<'b, 'c>( fn r#move<'b, 'c>(
vm: &'b mut Vm<'c>, vm: &'b mut Vm<'c>,
instruction_data: InstructionData, instruction_data: InstructionData,
@ -108,6 +109,7 @@ impl<'a> Vm<'a> {
Ok(()) Ok(())
} }
#[allow(clippy::needless_lifetimes)]
fn close<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) -> Result<(), VmError> { fn close<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) -> Result<(), VmError> {
let InstructionData { b, c, .. } = instruction_data; let InstructionData { b, c, .. } = instruction_data;
@ -124,6 +126,7 @@ impl<'a> Vm<'a> {
Ok(()) Ok(())
} }
#[allow(clippy::needless_lifetimes)]
fn load_boolean<'b, 'c>( fn load_boolean<'b, 'c>(
vm: &'b mut Vm<'c>, vm: &'b mut Vm<'c>,
instruction_data: InstructionData, instruction_data: InstructionData,
@ -141,6 +144,7 @@ impl<'a> Vm<'a> {
Ok(()) Ok(())
} }
#[allow(clippy::needless_lifetimes)]
fn load_constant<'b, 'c>( fn load_constant<'b, 'c>(
vm: &'b mut Vm<'c>, vm: &'b mut Vm<'c>,
instruction_data: InstructionData, instruction_data: InstructionData,
@ -157,6 +161,7 @@ impl<'a> Vm<'a> {
Ok(()) Ok(())
} }
#[allow(clippy::needless_lifetimes)]
fn load_list<'b, 'c>( fn load_list<'b, 'c>(
vm: &'b mut Vm<'c>, vm: &'b mut Vm<'c>,
instruction_data: InstructionData, instruction_data: InstructionData,
@ -181,6 +186,7 @@ impl<'a> Vm<'a> {
vm.set_register(a, register) vm.set_register(a, register)
} }
#[allow(clippy::needless_lifetimes)]
fn load_self<'b, 'c>( fn load_self<'b, 'c>(
vm: &'b mut Vm<'c>, vm: &'b mut Vm<'c>,
instruction_data: InstructionData, instruction_data: InstructionData,
@ -191,6 +197,7 @@ impl<'a> Vm<'a> {
vm.set_register(a, register) vm.set_register(a, register)
} }
#[allow(clippy::needless_lifetimes)]
fn get_local<'b, 'c>( fn get_local<'b, 'c>(
vm: &'b mut Vm<'c>, vm: &'b mut Vm<'c>,
instruction_data: InstructionData, instruction_data: InstructionData,
@ -202,6 +209,7 @@ impl<'a> Vm<'a> {
vm.set_register(a, register) vm.set_register(a, register)
} }
#[allow(clippy::needless_lifetimes)]
fn set_local<'b, 'c>( fn set_local<'b, 'c>(
vm: &'b mut Vm<'c>, vm: &'b mut Vm<'c>,
instruction_data: InstructionData, instruction_data: InstructionData,
@ -213,6 +221,7 @@ impl<'a> Vm<'a> {
vm.set_register(local_register_index, register) vm.set_register(local_register_index, register)
} }
#[allow(clippy::needless_lifetimes)]
fn add<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) -> Result<(), VmError> { fn add<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) -> Result<(), VmError> {
let InstructionData { let InstructionData {
a, a,
@ -239,6 +248,7 @@ impl<'a> Vm<'a> {
vm.set_register(a, register) vm.set_register(a, register)
} }
#[allow(clippy::needless_lifetimes)]
fn subtract<'b, 'c>( fn subtract<'b, 'c>(
vm: &'b mut Vm<'c>, vm: &'b mut Vm<'c>,
instruction_data: InstructionData, instruction_data: InstructionData,
@ -268,6 +278,7 @@ impl<'a> Vm<'a> {
vm.set_register(a, register) vm.set_register(a, register)
} }
#[allow(clippy::needless_lifetimes)]
fn multiply<'b, 'c>( fn multiply<'b, 'c>(
vm: &'b mut Vm<'c>, vm: &'b mut Vm<'c>,
instruction_data: InstructionData, instruction_data: InstructionData,
@ -297,6 +308,7 @@ impl<'a> Vm<'a> {
vm.set_register(a, register) vm.set_register(a, register)
} }
#[allow(clippy::needless_lifetimes)]
fn divide<'b, 'c>( fn divide<'b, 'c>(
vm: &'b mut Vm<'c>, vm: &'b mut Vm<'c>,
instruction_data: InstructionData, instruction_data: InstructionData,
@ -326,6 +338,7 @@ impl<'a> Vm<'a> {
vm.set_register(a, register) vm.set_register(a, register)
} }
#[allow(clippy::needless_lifetimes)]
fn modulo<'b, 'c>( fn modulo<'b, 'c>(
vm: &'b mut Vm<'c>, vm: &'b mut Vm<'c>,
instruction_data: InstructionData, instruction_data: InstructionData,
@ -355,6 +368,7 @@ impl<'a> Vm<'a> {
vm.set_register(a, register) vm.set_register(a, register)
} }
#[allow(clippy::needless_lifetimes)]
fn test<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) -> Result<(), VmError> { fn test<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) -> Result<(), VmError> {
let InstructionData { let InstructionData {
b, b,
@ -380,6 +394,7 @@ impl<'a> Vm<'a> {
Ok(()) Ok(())
} }
#[allow(clippy::needless_lifetimes)]
fn test_set<'b, 'c>( fn test_set<'b, 'c>(
vm: &'b mut Vm<'c>, vm: &'b mut Vm<'c>,
instruction_data: InstructionData, instruction_data: InstructionData,
@ -418,6 +433,7 @@ impl<'a> Vm<'a> {
Ok(()) Ok(())
} }
#[allow(clippy::needless_lifetimes)]
fn equal<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) -> Result<(), VmError> { fn equal<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) -> Result<(), VmError> {
let InstructionData { let InstructionData {
a, a,
@ -448,6 +464,7 @@ impl<'a> Vm<'a> {
vm.set_register(a, register) vm.set_register(a, register)
} }
#[allow(clippy::needless_lifetimes)]
fn less<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) -> Result<(), VmError> { fn less<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) -> Result<(), VmError> {
let InstructionData { let InstructionData {
a, a,
@ -478,6 +495,7 @@ impl<'a> Vm<'a> {
vm.set_register(a, register) vm.set_register(a, register)
} }
#[allow(clippy::needless_lifetimes)]
fn less_equal<'b, 'c>( fn less_equal<'b, 'c>(
vm: &'b mut Vm<'c>, vm: &'b mut Vm<'c>,
instruction_data: InstructionData, instruction_data: InstructionData,
@ -513,6 +531,7 @@ impl<'a> Vm<'a> {
vm.set_register(a, register) vm.set_register(a, register)
} }
#[allow(clippy::needless_lifetimes)]
fn negate<'b, 'c>( fn negate<'b, 'c>(
vm: &'b mut Vm<'c>, vm: &'b mut Vm<'c>,
instruction_data: InstructionData, instruction_data: InstructionData,
@ -533,6 +552,7 @@ impl<'a> Vm<'a> {
vm.set_register(a, register) vm.set_register(a, register)
} }
#[allow(clippy::needless_lifetimes)]
fn not<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) -> Result<(), VmError> { fn not<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) -> Result<(), VmError> {
let InstructionData { let InstructionData {
a, a,
@ -550,6 +570,7 @@ impl<'a> Vm<'a> {
vm.set_register(a, register) vm.set_register(a, register)
} }
#[allow(clippy::needless_lifetimes)]
fn jump<'b, 'c>(vm: &mut Vm<'c>, instruction_data: InstructionData) -> Result<(), VmError> { fn jump<'b, 'c>(vm: &mut Vm<'c>, instruction_data: InstructionData) -> Result<(), VmError> {
let InstructionData { b, c, .. } = instruction_data; let InstructionData { b, c, .. } = instruction_data;
let is_positive = c != 0; let is_positive = c != 0;
@ -559,6 +580,7 @@ impl<'a> Vm<'a> {
Ok(()) Ok(())
} }
#[allow(clippy::needless_lifetimes)]
fn call<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) -> Result<(), VmError> { fn call<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) -> Result<(), VmError> {
let InstructionData { let InstructionData {
a, a,
@ -609,6 +631,7 @@ impl<'a> Vm<'a> {
Ok(()) Ok(())
} }
#[allow(clippy::needless_lifetimes)]
fn call_native<'b, 'c>( fn call_native<'b, 'c>(
vm: &'b mut Vm<'c>, vm: &'b mut Vm<'c>,
instruction_data: InstructionData, instruction_data: InstructionData,
@ -665,7 +688,7 @@ impl<'a> Vm<'a> {
instruction.disassembly_info() instruction.disassembly_info()
); );
if let Operation::Return = operation { if let Operation::RETURN = operation {
let should_return_value = instruction_data.b != 0; let should_return_value = instruction_data.b != 0;
if !should_return_value { if !should_return_value {
@ -684,7 +707,7 @@ impl<'a> Vm<'a> {
}) })
}; };
} else { } else {
let runner = RUNNERS[operation as usize]; let runner = RUNNERS[operation.0 as usize];
runner(self, instruction_data).unwrap(); runner(self, instruction_data).unwrap();
} }
@ -1045,35 +1068,35 @@ mod tests {
use super::*; use super::*;
const ALL_OPERATIONS: [(Operation, Runner); 23] = [ const ALL_OPERATIONS: [(Operation, Runner); 23] = [
(Operation::Move, Vm::r#move), (Operation::MOVE, Vm::r#move),
(Operation::Close, Vm::close), (Operation::CLOSE, Vm::close),
(Operation::LoadBoolean, Vm::load_boolean), (Operation::LOAD_BOOLEAN, Vm::load_boolean),
(Operation::LoadConstant, Vm::load_constant), (Operation::LOAD_CONSTANT, Vm::load_constant),
(Operation::LoadList, Vm::load_list), (Operation::LOAD_LIST, Vm::load_list),
(Operation::LoadSelf, Vm::load_self), (Operation::LOAD_SELF, Vm::load_self),
(Operation::GetLocal, Vm::get_local), (Operation::GET_LOCAL, Vm::get_local),
(Operation::SetLocal, Vm::set_local), (Operation::SET_LOCAL, Vm::set_local),
(Operation::Add, Vm::add), (Operation::ADD, Vm::add),
(Operation::Subtract, Vm::subtract), (Operation::SUBTRACT, Vm::subtract),
(Operation::Multiply, Vm::multiply), (Operation::MULTIPLY, Vm::multiply),
(Operation::Divide, Vm::divide), (Operation::DIVIDE, Vm::divide),
(Operation::Modulo, Vm::modulo), (Operation::MODULO, Vm::modulo),
(Operation::Test, Vm::test), (Operation::TEST, Vm::test),
(Operation::TestSet, Vm::test_set), (Operation::TEST_SET, Vm::test_set),
(Operation::Equal, Vm::equal), (Operation::EQUAL, Vm::equal),
(Operation::Less, Vm::less), (Operation::LESS, Vm::less),
(Operation::LessEqual, Vm::less_equal), (Operation::LESS_EQUAL, Vm::less_equal),
(Operation::Negate, Vm::negate), (Operation::NEGATE, Vm::negate),
(Operation::Not, Vm::not), (Operation::NOT, Vm::not),
(Operation::Call, Vm::call), (Operation::CALL, Vm::call),
(Operation::CallNative, Vm::call_native), (Operation::CALL_NATIVE, Vm::call_native),
(Operation::Jump, Vm::jump), (Operation::JUMP, Vm::jump),
]; ];
#[test] #[test]
fn operations_map_to_the_correct_runner() { fn operations_map_to_the_correct_runner() {
for (operation, expected_runner) in ALL_OPERATIONS { for (operation, expected_runner) in ALL_OPERATIONS {
let actual_runner = RUNNERS[operation as usize]; let actual_runner = RUNNERS[operation.0 as usize];
assert_eq!( assert_eq!(
expected_runner, actual_runner, expected_runner, actual_runner,