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

View File

@ -29,11 +29,11 @@ pub fn optimize_test_with_explicit_booleans(compiler: &mut Compiler) {
if matches!(
compiler.get_last_operations(),
Some([
Operation::Equal | Operation::Less | Operation::LessEqual,
Operation::Test,
Operation::Jump,
Operation::LoadBoolean,
Operation::LoadBoolean,
Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL,
Operation::TEST,
Operation::JUMP,
Operation::LOAD_BOOLEAN,
Operation::LOAD_BOOLEAN,
])
) {
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!(
compiler.get_last_operations(),
Some([
Operation::Test,
Operation::Jump,
Operation::LoadBoolean | Operation::LoadConstant,
Operation::LoadBoolean | Operation::LoadConstant,
Operation::TEST,
Operation::JUMP,
Operation::LOAD_BOOLEAN | Operation::LOAD_CONSTANT,
Operation::LOAD_BOOLEAN | Operation::LOAD_CONSTANT,
])
) {
return;

View File

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

View File

@ -16,7 +16,7 @@ impl From<&Instruction> for Close {
impl From<Close> for Instruction {
fn from(close: Close) -> Self {
let operation = Operation::Close;
let operation = Operation::CLOSE;
let (a, b, c) = (0, close.from, close.to);
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 {
fn from(divide: Divide) -> Self {
let operation = Operation::Divide;
let operation = Operation::DIVIDE;
let a = divide.destination;
let (b, b_is_constant) = divide.left.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 {
fn from(equal: Equal) -> Self {
let operation = Operation::Equal;
let operation = Operation::EQUAL;
let a = equal.destination;
let (b, b_is_constant) = equal.left.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 {
fn from(get_local: GetLocal) -> Self {
let operation = Operation::GetLocal;
let operation = Operation::GET_LOCAL;
let a = get_local.destination;
let b = get_local.local_index;

View File

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

View File

@ -24,7 +24,7 @@ impl From<&Instruction> for Less {
impl From<Less> for Instruction {
fn from(less: Less) -> Self {
let operation = Operation::Less;
let operation = Operation::LESS;
let a = less.destination;
let (b, b_is_constant) = less.left.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 {
fn from(less_equal: LessEqual) -> Self {
let operation = Operation::LessEqual;
let operation = Operation::LESS_EQUAL;
let a = less_equal.destination;
let (b, b_options) = less_equal.left.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 {
fn from(load_boolean: LoadBoolean) -> Self {
let operation = Operation::LoadBoolean;
let operation = Operation::LOAD_BOOLEAN;
let a = load_boolean.destination;
let b = load_boolean.value 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 {
fn from(load_constant: LoadConstant) -> Self {
let operation = Operation::LoadConstant;
let operation = Operation::LOAD_CONSTANT;
let a = load_constant.destination;
let b = load_constant.constant_index;
let c = load_constant.jump_next as u8;

View File

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

View File

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

View File

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

View File

@ -21,7 +21,7 @@ impl From<&Instruction> for Modulo {
impl From<Modulo> for Instruction {
fn from(modulo: Modulo) -> Self {
let operation = Operation::Modulo;
let operation = Operation::MODULO;
let a = modulo.destination;
let (b, b_is_constant) = modulo.left.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 {
fn from(r#move: Move) -> Self {
let operation = Operation::Move;
let operation = Operation::MOVE;
let b = r#move.from;
let c = r#move.to;

View File

@ -21,7 +21,7 @@ impl From<&Instruction> for Multiply {
impl From<Multiply> for Instruction {
fn from(multiply: Multiply) -> Self {
let operation = Operation::Multiply;
let operation = Operation::MULTIPLY;
let a = multiply.destination;
let (b, b_options) = multiply.left.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 {
fn from(negate: Negate) -> Self {
let operation = Operation::Negate;
let operation = Operation::NEGATE;
let a = negate.destination;
let (b, b_is_constant) = negate.argument.as_index_and_constant_flag();
let c = 0;

View File

@ -19,7 +19,7 @@ impl From<&Instruction> for Not {
impl From<Not> for Instruction {
fn from(not: Not) -> Self {
let operation = Operation::Not;
let operation = Operation::NOT;
let a = not.destination;
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};
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.
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
#[repr(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,
}
pub struct Operation(pub u8);
impl From<u8> for Operation {
fn from(byte: u8) -> Self {
match byte {
MOVE_BYTE => Self::Move,
CLOSE_BYTE => Self::Close,
LOAD_BOOLEAN_BYTE => Self::LoadBoolean,
LOAD_CONSTANT_BYTE => Self::LoadConstant,
LOAD_LIST_BYTE => Self::LoadList,
LOAD_SELF_BYTE => Self::LoadSelf,
GET_LOCAL_BYTE => Self::GetLocal,
SET_LOCAL_BYTE => Self::SetLocal,
ADD_BYTE => Self::Add,
SUBTRACT_BYTE => Self::Subtract,
MULTIPLY_BYTE => Self::Multiply,
DIVIDE_BYTE => Self::Divide,
MODULO_BYTE => Self::Modulo,
TEST_BYTE => Self::Test,
TEST_SET_BYTE => Self::TestSet,
EQUAL_BYTE => Self::Equal,
LESS_BYTE => Self::Less,
LESS_EQUAL_BYTE => Self::LessEqual,
NEGATE_BYTE => Self::Negate,
NOT_BYTE => Self::Not,
CALL_BYTE => Self::Call,
CALL_NATIVE_BYTE => Self::CallNative,
JUMP_BYTE => Self::Jump,
RETURN_BYTE => Self::Return,
_ => {
if cfg!(debug_assertions) {
panic!("Invalid operation byte: {}", byte)
} else {
Self::Return
}
}
}
}
impl Operation {
pub const MOVE: Operation = Operation(0);
pub const CLOSE: Operation = Operation(1);
pub const LOAD_BOOLEAN: Operation = Operation(2);
pub const LOAD_CONSTANT: Operation = Operation(3);
pub const LOAD_LIST: Operation = Operation(4);
pub const LOAD_SELF: Operation = Operation(5);
pub const GET_LOCAL: Operation = Operation(6);
pub const SET_LOCAL: Operation = Operation(7);
pub const ADD: Operation = Operation(8);
pub const SUBTRACT: Operation = Operation(9);
pub const MULTIPLY: Operation = Operation(10);
pub const DIVIDE: Operation = Operation(11);
pub const MODULO: Operation = Operation(12);
pub const TEST: Operation = Operation(13);
pub const TEST_SET: Operation = Operation(14);
pub const EQUAL: Operation = Operation(15);
pub const LESS: Operation = Operation(16);
pub const LESS_EQUAL: Operation = Operation(17);
pub const NEGATE: Operation = Operation(18);
pub const NOT: Operation = Operation(19);
pub const CALL: Operation = Operation(20);
pub const CALL_NATIVE: Operation = Operation(21);
pub const JUMP: Operation = Operation(22);
pub const RETURN: Operation = Operation(23);
}
impl Operation {
pub fn name(self) -> &'static str {
match self {
Self::Move => "MOVE",
Self::Close => "CLOSE",
Self::LoadBoolean => "LOAD_BOOLEAN",
Self::LoadConstant => "LOAD_CONSTANT",
Self::LoadList => "LOAD_LIST",
Self::LoadSelf => "LOAD_SELF",
Self::GetLocal => "GET_LOCAL",
Self::SetLocal => "SET_LOCAL",
Self::Add => "ADD",
Self::Subtract => "SUBTRACT",
Self::Multiply => "MULTIPLY",
Self::Divide => "DIVIDE",
Self::Modulo => "MODULO",
Self::Test => "TEST",
Self::TestSet => "TEST_SET",
Self::Equal => "EQUAL",
Self::Less => "LESS",
Self::LessEqual => "LESS_EQUAL",
Self::Negate => "NEGATE",
Self::Not => "NOT",
Self::Call => "CALL",
Self::CallNative => "CALL_NATIVE",
Self::Jump => "JUMP",
Self::Return => "RETURN",
Self::MOVE => "MOVE",
Self::CLOSE => "CLOSE",
Self::LOAD_BOOLEAN => "LOAD_BOOLEAN",
Self::LOAD_CONSTANT => "LOAD_CONSTANT",
Self::LOAD_LIST => "LOAD_LIST",
Self::LOAD_SELF => "LOAD_SELF",
Self::GET_LOCAL => "GET_LOCAL",
Self::SET_LOCAL => "SET_LOCAL",
Self::ADD => "ADD",
Self::SUBTRACT => "SUBTRACT",
Self::MULTIPLY => "MULTIPLY",
Self::DIVIDE => "DIVIDE",
Self::MODULO => "MODULO",
Self::TEST => "TEST",
Self::TEST_SET => "TEST_SET",
Self::EQUAL => "EQUAL",
Self::LESS => "LESS",
Self::LESS_EQUAL => "LESS_EQUAL",
Self::NEGATE => "NEGATE",
Self::NOT => "NOT",
Self::CALL => "CALL",
Self::CALL_NATIVE => "CALL_NATIVE",
Self::JUMP => "JUMP",
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 {
@ -139,54 +82,3 @@ impl Display for Operation {
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 {
fn from(r#return: Return) -> Self {
let operation = Operation::Return;
let operation = Operation::RETURN;
let b = r#return.should_return_value as u8;
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 {
fn from(set_local: SetLocal) -> Self {
let operation = Operation::SetLocal;
let operation = Operation::SET_LOCAL;
let b = set_local.register_index;
let c = set_local.local_index;

View File

@ -21,7 +21,7 @@ impl From<&Instruction> for Subtract {
impl From<Subtract> for Instruction {
fn from(subtract: Subtract) -> Self {
let operation = Operation::Subtract;
let operation = Operation::SUBTRACT;
let a = subtract.destination;
let (b, b_is_constant) = subtract.left.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 {
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 c = test.test_value as u8;

View File

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

View File

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