1
0

Restart instruction refactor

This commit is contained in:
Jeff 2024-12-08 06:04:01 -05:00
parent 78c9b65531
commit 1fa958fd0b
9 changed files with 301 additions and 376 deletions

10
Cargo.lock generated
View File

@ -85,6 +85,15 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "bitflags"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.16.0" version = "3.16.0"
@ -189,6 +198,7 @@ name = "dust-lang"
version = "0.5.0" version = "0.5.0"
dependencies = [ dependencies = [
"annotate-snippets", "annotate-snippets",
"bitflags",
"colored", "colored",
"env_logger", "env_logger",
"getrandom", "getrandom",

View File

@ -22,6 +22,7 @@ smallvec = { version = "1.13.2", features = ["serde"] }
smartstring = { version = "1.0.1", features = [ smartstring = { version = "1.0.1", features = [
"serde", "serde",
], default-features = false } ], default-features = false }
bitflags = { version = "2.6.0", features = ["serde"] }
[dev-dependencies] [dev-dependencies]
env_logger = "0.11.5" env_logger = "0.11.5"

View File

@ -8,11 +8,7 @@ pub struct Add {
impl From<&Instruction> for Add { impl From<&Instruction> for Add {
fn from(instruction: &Instruction) -> Self { fn from(instruction: &Instruction) -> Self {
let destination = if instruction.a_is_local() { let destination = instruction.a_as_destination();
Destination::Local(instruction.a())
} else {
Destination::Register(instruction.a())
};
let (left, right) = instruction.b_and_c_as_arguments(); let (left, right) = instruction.b_and_c_as_arguments();
Add { Add {
@ -25,19 +21,16 @@ 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 (a, a_is_local) = match add.destination { let (a, a_options) = add.destination.as_index_and_a_options();
Destination::Local(local) => (local, true), let (b, b_options) = add.left.as_index_and_b_options();
Destination::Register(register) => (register, false), let (c, c_options) = add.right.as_index_and_c_options();
};
*Instruction::new(Operation::Add) Instruction {
.set_a(a) operation: Operation::ADD,
.set_a_is_local(a_is_local) options: a_options | b_options | c_options,
.set_b(add.left.index()) a,
.set_b_is_constant(add.left.is_constant()) b,
.set_b_is_local(add.left.is_local()) c,
.set_c(add.right.index()) }
.set_c_is_constant(add.right.is_constant())
.set_c_is_local(add.right.is_local())
} }
} }

View File

@ -8,33 +8,25 @@ pub struct Call {
impl From<&Instruction> for Call { impl From<&Instruction> for Call {
fn from(instruction: &Instruction) -> Self { fn from(instruction: &Instruction) -> Self {
let destination = if instruction.a_is_local() {
Destination::Local(instruction.a())
} else {
Destination::Register(instruction.a())
};
Call { Call {
destination, destination: instruction.a_as_destination(),
function: instruction.b_as_argument(), function: instruction.b_as_argument(),
argument_count: instruction.c(), argument_count: instruction.c,
} }
} }
} }
impl From<Call> for Instruction { impl From<Call> for Instruction {
fn from(call: Call) -> Self { fn from(call: Call) -> Self {
let (a, a_is_local) = match call.destination { let (a, a_options) = call.destination.as_index_and_a_options();
Destination::Local(local) => (local, true), let (b, b_options) = call.function.as_index_and_b_options();
Destination::Register(register) => (register, false),
};
*Instruction::new(Operation::Call) Instruction {
.set_a(a) operation: Operation::CALL,
.set_a_is_local(a_is_local) options: a_options | b_options,
.set_b(call.function.index()) a,
.set_b_is_constant(call.function.is_constant()) b,
.set_b_is_local(call.function.is_local()) c: call.argument_count,
.set_c(call.argument_count) }
} }
} }

View File

@ -71,6 +71,8 @@ mod r#move;
mod multiply; mod multiply;
mod negate; mod negate;
mod not; mod not;
mod operation;
mod options;
mod r#return; mod r#return;
mod set_local; mod set_local;
mod subtract; mod subtract;
@ -98,6 +100,8 @@ pub use modulo::Modulo;
pub use multiply::Multiply; pub use multiply::Multiply;
pub use negate::Negate; pub use negate::Negate;
pub use not::Not; pub use not::Not;
pub use operation::Operation;
pub use options::InstructionOptions;
pub use r#move::Move; pub use r#move::Move;
pub use r#return::Return; pub use r#return::Return;
pub use set_local::SetLocal; pub use set_local::SetLocal;
@ -107,19 +111,21 @@ pub use test_set::TestSet;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{NativeFunction, Operation}; use crate::NativeFunction;
/// An operation and its arguments for the Dust virtual machine. /// An operation and its arguments for the Dust virtual machine.
/// ///
/// See the [module-level documentation](index.html) for more information. /// See the [module-level documentation](index.html) for more information.
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)] #[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Instruction(u64); pub struct Instruction {
operation: Operation,
impl Instruction { options: InstructionOptions,
pub fn new(operation: Operation) -> Instruction { a: u16,
Instruction(operation as u64) b: u16,
c: u16,
} }
impl Instruction {
pub fn r#move(from: u16, to: u16) -> Instruction { pub fn r#move(from: u16, to: u16) -> Instruction {
Instruction::from(Move { from, to }) Instruction::from(Move { from, to })
} }
@ -296,215 +302,115 @@ impl Instruction {
} }
pub fn destination_as_argument(&self) -> Option<Argument> { pub fn destination_as_argument(&self) -> Option<Argument> {
match self.operation() { match self.operation {
Operation::LoadConstant => Some(Argument::Constant(self.b())), Operation::LOAD_CONSTANT => Some(Argument::Constant(self.b)),
Operation::GetLocal => Some(Argument::Local(self.b())), Operation::GET_LOCAL => Some(Argument::Local(self.b)),
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::Negate | Operation::NEGATE
| Operation::Not | Operation::NOT
| Operation::Call | Operation::CALL
| Operation::CallNative => Some(Argument::Register(self.a())), | Operation::CALL_NATIVE => Some(Argument::Register(self.a)),
_ => None, _ => None,
} }
} }
pub fn b_as_argument(&self) -> Argument { pub fn a_as_destination(&self) -> Destination {
if self.b_is_constant() { if self.options.a_is_local() {
Argument::Constant(self.b()) Destination::Local(self.a)
} else if self.b_is_local() {
Argument::Local(self.b())
} else { } else {
Argument::Register(self.b()) Destination::Register(self.a)
}
}
pub fn b_as_argument(&self) -> Argument {
if self.options.b_is_constant() {
Argument::Constant(self.b)
} else if self.options.b_is_local() {
Argument::Local(self.b)
} else {
Argument::Register(self.b)
} }
} }
pub fn b_and_c_as_arguments(&self) -> (Argument, Argument) { pub fn b_and_c_as_arguments(&self) -> (Argument, Argument) {
let left = if self.b_is_constant() { let left = if self.options.b_is_constant() {
Argument::Constant(self.b()) Argument::Constant(self.b)
} else if self.b_is_local() { } else if self.options.b_is_local() {
Argument::Local(self.b()) Argument::Local(self.b)
} else { } else {
Argument::Register(self.b()) Argument::Register(self.b)
}; };
let right = if self.c_is_constant() { let right = if self.options.c_is_constant() {
Argument::Constant(self.c()) Argument::Constant(self.c)
} else if self.c_is_local() { } else if self.options.c_is_local() {
Argument::Local(self.c()) Argument::Local(self.c)
} else { } else {
Argument::Register(self.c()) Argument::Register(self.c)
}; };
(left, right) (left, right)
} }
pub fn operation(&self) -> Operation {
Operation::from((self.0 & 0b11111111) as u8)
}
pub fn set_b_is_constant(&mut self, boolean: bool) -> &mut Self {
self.0 = (self.0 & !(1 << 9)) | ((boolean as u64) << 9);
self
}
pub fn set_c_is_constant(&mut self, boolean: bool) -> &mut Self {
self.0 = (self.0 & !(1 << 10)) | ((boolean as u64) << 10);
self
}
pub fn set_a_is_local(&mut self, boolean: bool) -> &mut Self {
self.0 = (self.0 & !(1 << 11)) | ((boolean as u64) << 11);
self
}
pub fn set_b_is_local(&mut self, boolean: bool) -> &mut Self {
self.0 = (self.0 & !(1 << 12)) | ((boolean as u64) << 12);
self
}
pub fn set_c_is_local(&mut self, boolean: bool) -> &mut Self {
self.0 = (self.0 & !(1 << 13)) | ((boolean as u64) << 13);
self
}
pub fn a(&self) -> u16 {
((self.0 >> 16) & 0b1111111111111111) as u16
}
pub fn a_as_boolean(&self) -> bool {
self.a() != 0
}
pub fn set_a(&mut self, a: u16) -> &mut Self {
self.0 = (self.0 & !(0b1111111111111111 << 16)) | ((a as u64) << 16);
self
}
pub fn set_a_to_boolean(&mut self, boolean: bool) -> &mut Self {
self.0 = (self.0 & !(0b1111111111111111 << 16)) | ((boolean as u64) << 16);
self
}
pub fn b(&self) -> u16 {
((self.0 >> 32) & 0b1111111111111111) as u16
}
pub fn b_as_boolean(&self) -> bool {
self.b() != 0
}
pub fn set_b(&mut self, b: u16) -> &mut Self {
self.0 = (self.0 & !(0b1111111111111111 << 32)) | ((b as u64) << 32);
self
}
pub fn set_b_to_boolean(&mut self, boolean: bool) -> &mut Self {
self.0 = (self.0 & !(0b1111111111111111 << 32)) | ((boolean as u64) << 32);
self
}
pub fn c(&self) -> u16 {
((self.0 >> 48) & 0b1111111111111111) as u16
}
pub fn c_as_boolean(&self) -> bool {
self.c() != 0
}
pub fn set_c(&mut self, c: u16) -> &mut Self {
self.0 = (self.0 & !(0b1111111111111111 << 48)) | ((c as u64) << 48);
self
}
pub fn set_c_to_boolean(&mut self, boolean: bool) -> &mut Self {
self.0 = (self.0 & !(0b1111111111111111 << 48)) | ((boolean as u64) << 48);
self
}
pub fn b_is_constant(&self) -> bool {
(self.0 >> 9) & 1 == 1
}
pub fn c_is_constant(&self) -> bool {
(self.0 >> 10) & 1 == 1
}
pub fn a_is_local(&self) -> bool {
(self.0 >> 11) & 1 == 1
}
pub fn b_is_local(&self) -> bool {
(self.0 >> 12) & 1 == 1
}
pub fn c_is_local(&self) -> bool {
(self.0 >> 13) & 1 == 1
}
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::Call => true, | Operation::CALL => true,
Operation::Move Operation::MOVE
| Operation::Close | Operation::CLOSE
| Operation::DefineLocal | Operation::SET_LOCAL
| Operation::SetLocal | Operation::EQUAL
| Operation::Equal | Operation::LESS
| Operation::Less | Operation::LESS_EQUAL
| Operation::LessEqual | Operation::TEST
| Operation::Test | Operation::TEST_SET
| Operation::TestSet | Operation::JUMP
| Operation::Jump | Operation::RETURN => false,
| Operation::Return => false, Operation::CALL_NATIVE => {
Operation::CallNative => { let function = NativeFunction::from(self.b);
let function = NativeFunction::from(self.b());
function.returns_value() function.returns_value()
} }
_ => {
if cfg!(debug_assertions) {
panic!("Unknown operation {}", self.operation);
} else {
false
}
}
} }
} }
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,
@ -517,7 +423,7 @@ impl Instruction {
format!("{destination} = {value}") format!("{destination} = {value}")
} }
} }
Operation::LoadConstant => { Operation::LOAD_CONSTANT => {
let LoadConstant { let LoadConstant {
destination, destination,
constant_index, constant_index,
@ -530,7 +436,7 @@ impl Instruction {
format!("{destination} = C{constant_index}") format!("{destination} = C{constant_index}")
} }
} }
Operation::LoadList => { Operation::LOAD_LIST => {
let LoadList { let LoadList {
destination, destination,
start_register, start_register,
@ -539,25 +445,12 @@ impl Instruction {
format!("{destination} = [R{start_register}..=R{end_register}]",) format!("{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!("{destination} = self") format!("{destination} = self")
} }
Operation::DefineLocal => { Operation::GET_LOCAL => {
let DefineLocal {
register,
local_index,
is_mutable,
} = DefineLocal::from(self);
if is_mutable {
format!("mut L{local_index} = R{register}")
} else {
format!("L{local_index} = R{register}")
}
}
Operation::GetLocal => {
let GetLocal { let GetLocal {
destination, destination,
local_index, local_index,
@ -565,7 +458,7 @@ impl Instruction {
format!("{destination} = L{local_index}") format!("{destination} = L{local_index}")
} }
Operation::SetLocal => { Operation::SET_LOCAL => {
let SetLocal { let SetLocal {
register, register,
local_index, local_index,
@ -573,7 +466,7 @@ impl Instruction {
format!("L{local_index} = R{register}") format!("L{local_index} = R{register}")
} }
Operation::Add => { Operation::ADD => {
let Add { let Add {
destination, destination,
left, left,
@ -582,7 +475,7 @@ impl Instruction {
format!("{destination} = {left} + {right}") format!("{destination} = {left} + {right}")
} }
Operation::Subtract => { Operation::SUBTRACT => {
let Subtract { let Subtract {
destination, destination,
left, left,
@ -591,7 +484,7 @@ impl Instruction {
format!("{destination} = {left} - {right}") format!("{destination} = {left} - {right}")
} }
Operation::Multiply => { Operation::MULTIPLY => {
let Multiply { let Multiply {
destination, destination,
left, left,
@ -600,7 +493,7 @@ impl Instruction {
format!("{destination} = {left} * {right}") format!("{destination} = {left} * {right}")
} }
Operation::Divide => { Operation::DIVIDE => {
let Divide { let Divide {
destination, destination,
left, left,
@ -609,7 +502,7 @@ impl Instruction {
format!("{destination} = {left} / {right}") format!("{destination} = {left} / {right}")
} }
Operation::Modulo => { Operation::MODULO => {
let Modulo { let Modulo {
destination, destination,
left, left,
@ -618,7 +511,7 @@ impl Instruction {
format!("{destination} = {left} % {right}") format!("{destination} = {left} % {right}")
} }
Operation::Test => { Operation::TEST => {
let Test { let Test {
argument, argument,
test_value: value, test_value: value,
@ -627,7 +520,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,
@ -637,25 +530,25 @@ impl Instruction {
format!("if {bang}{argument} {{ JUMP +1 }} else {{ {destination} = {argument} }}") format!("if {bang}{argument} {{ JUMP +1 }} else {{ {destination} = {argument} }}")
} }
Operation::Equal => { Operation::EQUAL => {
let Equal { value, left, right } = Equal::from(self); let Equal { value, left, right } = Equal::from(self);
let comparison_symbol = if value { "==" } else { "!=" }; let comparison_symbol = if value { "==" } else { "!=" };
format!("if {left} {comparison_symbol} {right} {{ JUMP +1 }}") format!("if {left} {comparison_symbol} {right} {{ JUMP +1 }}")
} }
Operation::Less => { Operation::LESS => {
let Less { value, left, right } = Less::from(self); let Less { value, left, right } = Less::from(self);
let comparison_symbol = if value { "<" } else { ">=" }; let comparison_symbol = if value { "<" } else { ">=" };
format!("if {left} {comparison_symbol} {right} {{ JUMP +1 }}") format!("if {left} {comparison_symbol} {right} {{ JUMP +1 }}")
} }
Operation::LessEqual => { Operation::LESS_EQUAL => {
let LessEqual { value, left, right } = LessEqual::from(self); let LessEqual { value, left, right } = LessEqual::from(self);
let comparison_symbol = if value { "<=" } else { ">" }; let comparison_symbol = if value { "<=" } else { ">" };
format!("if {left} {comparison_symbol} {right} {{ JUMP +1 }}") format!("if {left} {comparison_symbol} {right} {{ JUMP +1 }}")
} }
Operation::Negate => { Operation::NEGATE => {
let Negate { let Negate {
destination, destination,
argument, argument,
@ -663,7 +556,7 @@ impl Instruction {
format!("{destination} = -{argument}") format!("{destination} = -{argument}")
} }
Operation::Not => { Operation::NOT => {
let Not { let Not {
destination, destination,
argument, argument,
@ -671,7 +564,7 @@ impl Instruction {
format!("{destination} = !{argument}") format!("{destination} = !{argument}")
} }
Operation::Jump => { Operation::JUMP => {
let Jump { let Jump {
offset, offset,
is_positive, is_positive,
@ -683,7 +576,7 @@ impl Instruction {
format!("JUMP -{offset}") format!("JUMP -{offset}")
} }
} }
Operation::Call => { Operation::CALL => {
let Call { let Call {
destination, destination,
function, function,
@ -694,7 +587,7 @@ impl Instruction {
format!("{destination} = {function}(R{arguments_start}..R{arguments_end})") format!("{destination} = {function}(R{arguments_start}..R{arguments_end})")
} }
Operation::CallNative => { Operation::CALL_NATIVE => {
let CallNative { let CallNative {
destination, destination,
function, function,
@ -709,7 +602,7 @@ impl Instruction {
format!("{function}(R{arguments_start}..R{arguments_end})") format!("{function}(R{arguments_start}..R{arguments_end})")
} }
} }
Operation::Return => { Operation::RETURN => {
let Return { let Return {
should_return_value, should_return_value,
} = Return::from(self); } = Return::from(self);
@ -720,19 +613,20 @@ impl Instruction {
"".to_string() "".to_string()
} }
} }
_ => {
if cfg!(debug_assertions) {
panic!("Unknown operation {}", self.operation);
} else {
"RETURN".to_string()
} }
} }
} }
impl From<&Instruction> for u64 {
fn from(instruction: &Instruction) -> Self {
instruction.0
} }
} }
impl Debug for Instruction { impl Debug for Instruction {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{} {}", self.operation(), self.disassembly_info()) write!(f, "{} {}", self.operation, self.disassembly_info())
} }
} }
@ -757,6 +651,13 @@ impl Destination {
pub fn is_register(&self) -> bool { pub fn is_register(&self) -> bool {
matches!(self, Destination::Register(_)) matches!(self, Destination::Register(_))
} }
pub fn as_index_and_a_options(&self) -> (u16, InstructionOptions) {
match self {
Destination::Local(index) => (*index, InstructionOptions::A_IS_LOCAL),
Destination::Register(index) => (*index, InstructionOptions::empty()),
}
}
} }
impl Display for Destination { impl Display for Destination {
@ -795,6 +696,22 @@ impl Argument {
pub fn is_register(&self) -> bool { pub fn is_register(&self) -> bool {
matches!(self, Argument::Register(_)) matches!(self, Argument::Register(_))
} }
pub fn as_index_and_b_options(&self) -> (u16, InstructionOptions) {
match self {
Argument::Constant(index) => (*index, InstructionOptions::B_IS_CONSTANT),
Argument::Local(index) => (*index, InstructionOptions::B_IS_LOCAL),
Argument::Register(index) => (*index, InstructionOptions::empty()),
}
}
pub fn as_index_and_c_options(&self) -> (u16, InstructionOptions) {
match self {
Argument::Constant(index) => (*index, InstructionOptions::C_IS_CONSTANT),
Argument::Local(index) => (*index, InstructionOptions::C_IS_LOCAL),
Argument::Register(index) => (*index, InstructionOptions::empty()),
}
}
} }
impl Display for Argument { impl Display for Argument {

View File

@ -0,0 +1,83 @@
//! Part of an [Instruction][crate::Instruction] that is encoded as a single byte.
use std::fmt::{self, Debug, Display, Formatter};
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Operation(u8);
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);
pub fn name(self) -> &'static str {
match self {
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",
_ => {
if cfg!(debug_assertions) {
panic!("Unknown operation code {}", self.0);
} else {
"RETURN"
}
}
}
}
}
impl Debug for Operation {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "Operation({})", self.name())
}
}
impl Display for Operation {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}", self.name())
}
}

View File

@ -0,0 +1,43 @@
use bitflags::bitflags;
use serde::{Deserialize, Serialize};
bitflags! {
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct InstructionOptions: u8 {
const A_IS_LOCAL = 0b00000001;
const B_IS_CONSTANT = 0b00000010;
const B_IS_LOCAL = 0b00000100;
const C_IS_CONSTANT = 0b00001000;
const C_IS_LOCAL = 0b00010000;
const D_FIELD = 0b00100000;
}
}
impl InstructionOptions {
pub fn a_is_local(self) -> bool {
self.contains(Self::A_IS_LOCAL)
}
pub fn b_is_constant(self) -> bool {
self.contains(Self::B_IS_CONSTANT)
}
pub fn b_is_local(self) -> bool {
self.contains(Self::B_IS_LOCAL)
}
pub fn c_is_constant(self) -> bool {
self.contains(Self::C_IS_CONSTANT)
}
pub fn c_is_local(self) -> bool {
self.contains(Self::C_IS_LOCAL)
}
pub fn d(self) -> bool {
self.contains(Self::D_FIELD)
}
}

View File

@ -35,7 +35,6 @@ pub mod dust_error;
pub mod instruction; pub mod instruction;
pub mod lexer; pub mod lexer;
pub mod native_function; pub mod native_function;
pub mod operation;
pub mod optimize; pub mod optimize;
pub mod scope; pub mod scope;
pub mod token; pub mod token;
@ -47,10 +46,9 @@ pub use crate::chunk::{Chunk, Local};
pub use crate::compiler::{compile, CompileError, Compiler}; pub use crate::compiler::{compile, CompileError, Compiler};
pub use crate::disassembler::Disassembler; pub use crate::disassembler::Disassembler;
pub use crate::dust_error::{AnnotatedError, DustError}; pub use crate::dust_error::{AnnotatedError, DustError};
pub use crate::instruction::{Argument, Destination, Instruction}; pub use crate::instruction::{Argument, Destination, Instruction, Operation};
pub use crate::lexer::{lex, LexError, Lexer}; pub use crate::lexer::{lex, LexError, Lexer};
pub use crate::native_function::{NativeFunction, NativeFunctionError}; pub use crate::native_function::{NativeFunction, NativeFunctionError};
pub use crate::operation::Operation;
pub use crate::optimize::{optimize_control_flow, optimize_set_local}; pub use crate::optimize::{optimize_control_flow, optimize_set_local};
pub use crate::r#type::{EnumType, FunctionType, StructType, Type, TypeConflict}; pub use crate::r#type::{EnumType, FunctionType, StructType, Type, TypeConflict};
pub use crate::scope::Scope; pub use crate::scope::Scope;

View File

@ -1,112 +0,0 @@
//! Part of an [Instruction][crate::Instruction] that is encoded as a single byte.
use std::fmt::{self, Display, Formatter};
macro_rules! define_operation {
($(($name:ident, $byte:literal, $str:expr)),*) => {
/// Part of an [Instruction][crate::Instruction] that is encoded as a single byte.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Operation {
$(
$name = $byte as isize,
)*
}
impl From<u8> for Operation {
fn from(byte: u8) -> Self {
match byte {
$(
$byte => Operation::$name,
)*
_ => {
if cfg!(test) {
panic!("Invalid operation byte: {}", byte)
} else {
Operation::Return
}
}
}
}
}
impl From<Operation> for u8 {
fn from(operation: Operation) -> Self {
match operation {
$(
Operation::$name => $byte,
)*
}
}
}
impl Display for Operation {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
$(
Operation::$name => write!(f, "{}", $str),
)*
}
}
}
}
}
define_operation! {
(Move, 0, "MOVE"),
(Close, 1, "CLOSE"),
(LoadBoolean, 2, "LOAD_BOOLEAN"),
(LoadConstant, 3, "LOAD_CONSTANT"),
(LoadList, 4, "LOAD_LIST"),
(LoadSelf, 5, "LOAD_SELF"),
(DefineLocal, 6, "DEFINE_LOCAL"),
(GetLocal, 7, "GET_LOCAL"),
(SetLocal, 8, "SET_LOCAL"),
(Add, 9, "ADD"),
(Subtract, 10, "SUBTRACT"),
(Multiply, 11, "MULTIPLY"),
(Divide, 12, "DIVIDE"),
(Modulo, 13, "MODULO"),
(Test, 14, "TEST"),
(TestSet, 15, "TEST_SET"),
(Equal, 16, "EQUAL"),
(Less, 17, "LESS"),
(LessEqual, 18, "LESS_EQUAL"),
(Negate, 19, "NEGATE"),
(Not, 20, "NOT"),
(Call, 21, "CALL"),
(CallNative, 22, "CALL_NATIVE"),
(Jump, 23, "JUMP"),
(Return, 24, "RETURN")
}
impl Operation {
pub fn is_math(&self) -> bool {
matches!(
self,
Operation::Add
| Operation::Subtract
| Operation::Multiply
| Operation::Divide
| Operation::Modulo
)
}
pub fn is_comparison(&self) -> bool {
matches!(
self,
Operation::Equal | Operation::Less | Operation::LessEqual
)
}
pub fn is_test(&self) -> bool {
matches!(self, Operation::Test | Operation::TestSet)
}
}