Restart instruction refactor
This commit is contained in:
parent
78c9b65531
commit
1fa958fd0b
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -85,6 +85,15 @@ version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.16.0"
|
||||
@ -189,6 +198,7 @@ name = "dust-lang"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"annotate-snippets",
|
||||
"bitflags",
|
||||
"colored",
|
||||
"env_logger",
|
||||
"getrandom",
|
||||
|
@ -22,6 +22,7 @@ smallvec = { version = "1.13.2", features = ["serde"] }
|
||||
smartstring = { version = "1.0.1", features = [
|
||||
"serde",
|
||||
], default-features = false }
|
||||
bitflags = { version = "2.6.0", features = ["serde"] }
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = "0.11.5"
|
||||
|
@ -8,11 +8,7 @@ pub struct Add {
|
||||
|
||||
impl From<&Instruction> for Add {
|
||||
fn from(instruction: &Instruction) -> Self {
|
||||
let destination = if instruction.a_is_local() {
|
||||
Destination::Local(instruction.a())
|
||||
} else {
|
||||
Destination::Register(instruction.a())
|
||||
};
|
||||
let destination = instruction.a_as_destination();
|
||||
let (left, right) = instruction.b_and_c_as_arguments();
|
||||
|
||||
Add {
|
||||
@ -25,19 +21,16 @@ impl From<&Instruction> for Add {
|
||||
|
||||
impl From<Add> for Instruction {
|
||||
fn from(add: Add) -> Self {
|
||||
let (a, a_is_local) = match add.destination {
|
||||
Destination::Local(local) => (local, true),
|
||||
Destination::Register(register) => (register, false),
|
||||
};
|
||||
let (a, a_options) = add.destination.as_index_and_a_options();
|
||||
let (b, b_options) = add.left.as_index_and_b_options();
|
||||
let (c, c_options) = add.right.as_index_and_c_options();
|
||||
|
||||
*Instruction::new(Operation::Add)
|
||||
.set_a(a)
|
||||
.set_a_is_local(a_is_local)
|
||||
.set_b(add.left.index())
|
||||
.set_b_is_constant(add.left.is_constant())
|
||||
.set_b_is_local(add.left.is_local())
|
||||
.set_c(add.right.index())
|
||||
.set_c_is_constant(add.right.is_constant())
|
||||
.set_c_is_local(add.right.is_local())
|
||||
Instruction {
|
||||
operation: Operation::ADD,
|
||||
options: a_options | b_options | c_options,
|
||||
a,
|
||||
b,
|
||||
c,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,33 +8,25 @@ pub struct Call {
|
||||
|
||||
impl From<&Instruction> for Call {
|
||||
fn from(instruction: &Instruction) -> Self {
|
||||
let destination = if instruction.a_is_local() {
|
||||
Destination::Local(instruction.a())
|
||||
} else {
|
||||
Destination::Register(instruction.a())
|
||||
};
|
||||
|
||||
Call {
|
||||
destination,
|
||||
destination: instruction.a_as_destination(),
|
||||
function: instruction.b_as_argument(),
|
||||
argument_count: instruction.c(),
|
||||
argument_count: instruction.c,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Call> for Instruction {
|
||||
fn from(call: Call) -> Self {
|
||||
let (a, a_is_local) = match call.destination {
|
||||
Destination::Local(local) => (local, true),
|
||||
Destination::Register(register) => (register, false),
|
||||
};
|
||||
let (a, a_options) = call.destination.as_index_and_a_options();
|
||||
let (b, b_options) = call.function.as_index_and_b_options();
|
||||
|
||||
*Instruction::new(Operation::Call)
|
||||
.set_a(a)
|
||||
.set_a_is_local(a_is_local)
|
||||
.set_b(call.function.index())
|
||||
.set_b_is_constant(call.function.is_constant())
|
||||
.set_b_is_local(call.function.is_local())
|
||||
.set_c(call.argument_count)
|
||||
Instruction {
|
||||
operation: Operation::CALL,
|
||||
options: a_options | b_options,
|
||||
a,
|
||||
b,
|
||||
c: call.argument_count,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,6 +71,8 @@ mod r#move;
|
||||
mod multiply;
|
||||
mod negate;
|
||||
mod not;
|
||||
mod operation;
|
||||
mod options;
|
||||
mod r#return;
|
||||
mod set_local;
|
||||
mod subtract;
|
||||
@ -98,6 +100,8 @@ pub use modulo::Modulo;
|
||||
pub use multiply::Multiply;
|
||||
pub use negate::Negate;
|
||||
pub use not::Not;
|
||||
pub use operation::Operation;
|
||||
pub use options::InstructionOptions;
|
||||
pub use r#move::Move;
|
||||
pub use r#return::Return;
|
||||
pub use set_local::SetLocal;
|
||||
@ -107,19 +111,21 @@ pub use test_set::TestSet;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{NativeFunction, Operation};
|
||||
use crate::NativeFunction;
|
||||
|
||||
/// An operation and its arguments for the Dust virtual machine.
|
||||
///
|
||||
/// See the [module-level documentation](index.html) for more information.
|
||||
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||
pub struct Instruction(u64);
|
||||
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct Instruction {
|
||||
operation: Operation,
|
||||
options: InstructionOptions,
|
||||
a: u16,
|
||||
b: u16,
|
||||
c: u16,
|
||||
}
|
||||
|
||||
impl Instruction {
|
||||
pub fn new(operation: Operation) -> Instruction {
|
||||
Instruction(operation as u64)
|
||||
}
|
||||
|
||||
pub fn r#move(from: u16, to: u16) -> Instruction {
|
||||
Instruction::from(Move { from, to })
|
||||
}
|
||||
@ -296,215 +302,115 @@ impl Instruction {
|
||||
}
|
||||
|
||||
pub fn destination_as_argument(&self) -> Option<Argument> {
|
||||
match self.operation() {
|
||||
Operation::LoadConstant => Some(Argument::Constant(self.b())),
|
||||
Operation::GetLocal => Some(Argument::Local(self.b())),
|
||||
Operation::LoadBoolean
|
||||
| Operation::LoadList
|
||||
| Operation::LoadSelf
|
||||
| Operation::Add
|
||||
| Operation::Subtract
|
||||
| Operation::Multiply
|
||||
| Operation::Divide
|
||||
| Operation::Modulo
|
||||
| Operation::Negate
|
||||
| Operation::Not
|
||||
| Operation::Call
|
||||
| Operation::CallNative => Some(Argument::Register(self.a())),
|
||||
match self.operation {
|
||||
Operation::LOAD_CONSTANT => Some(Argument::Constant(self.b)),
|
||||
Operation::GET_LOCAL => Some(Argument::Local(self.b)),
|
||||
Operation::LOAD_BOOLEAN
|
||||
| Operation::LOAD_LIST
|
||||
| Operation::LOAD_SELF
|
||||
| Operation::ADD
|
||||
| Operation::SUBTRACT
|
||||
| Operation::MULTIPLY
|
||||
| Operation::DIVIDE
|
||||
| Operation::MODULO
|
||||
| Operation::NEGATE
|
||||
| Operation::NOT
|
||||
| Operation::CALL
|
||||
| Operation::CALL_NATIVE => Some(Argument::Register(self.a)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn b_as_argument(&self) -> Argument {
|
||||
if self.b_is_constant() {
|
||||
Argument::Constant(self.b())
|
||||
} else if self.b_is_local() {
|
||||
Argument::Local(self.b())
|
||||
pub fn a_as_destination(&self) -> Destination {
|
||||
if self.options.a_is_local() {
|
||||
Destination::Local(self.a)
|
||||
} 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) {
|
||||
let left = if self.b_is_constant() {
|
||||
Argument::Constant(self.b())
|
||||
} else if self.b_is_local() {
|
||||
Argument::Local(self.b())
|
||||
let left = 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())
|
||||
Argument::Register(self.b)
|
||||
};
|
||||
let right = if self.c_is_constant() {
|
||||
Argument::Constant(self.c())
|
||||
} else if self.c_is_local() {
|
||||
Argument::Local(self.c())
|
||||
let right = if self.options.c_is_constant() {
|
||||
Argument::Constant(self.c)
|
||||
} else if self.options.c_is_local() {
|
||||
Argument::Local(self.c)
|
||||
} else {
|
||||
Argument::Register(self.c())
|
||||
Argument::Register(self.c)
|
||||
};
|
||||
|
||||
(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 {
|
||||
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::Call => true,
|
||||
Operation::Move
|
||||
| Operation::Close
|
||||
| Operation::DefineLocal
|
||||
| Operation::SetLocal
|
||||
| Operation::Equal
|
||||
| Operation::Less
|
||||
| Operation::LessEqual
|
||||
| Operation::Test
|
||||
| Operation::TestSet
|
||||
| Operation::Jump
|
||||
| Operation::Return => false,
|
||||
Operation::CallNative => {
|
||||
let function = NativeFunction::from(self.b());
|
||||
match self.operation {
|
||||
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::CALL => true,
|
||||
Operation::MOVE
|
||||
| Operation::CLOSE
|
||||
| Operation::SET_LOCAL
|
||||
| Operation::EQUAL
|
||||
| Operation::LESS
|
||||
| Operation::LESS_EQUAL
|
||||
| Operation::TEST
|
||||
| Operation::TEST_SET
|
||||
| Operation::JUMP
|
||||
| Operation::RETURN => false,
|
||||
Operation::CALL_NATIVE => {
|
||||
let function = NativeFunction::from(self.b);
|
||||
|
||||
function.returns_value()
|
||||
}
|
||||
_ => {
|
||||
if cfg!(debug_assertions) {
|
||||
panic!("Unknown operation {}", self.operation);
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn disassembly_info(&self) -> String {
|
||||
match self.operation() {
|
||||
Operation::Move => {
|
||||
match self.operation {
|
||||
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,
|
||||
@ -517,7 +423,7 @@ impl Instruction {
|
||||
format!("{destination} = {value}")
|
||||
}
|
||||
}
|
||||
Operation::LoadConstant => {
|
||||
Operation::LOAD_CONSTANT => {
|
||||
let LoadConstant {
|
||||
destination,
|
||||
constant_index,
|
||||
@ -530,7 +436,7 @@ impl Instruction {
|
||||
format!("{destination} = C{constant_index}")
|
||||
}
|
||||
}
|
||||
Operation::LoadList => {
|
||||
Operation::LOAD_LIST => {
|
||||
let LoadList {
|
||||
destination,
|
||||
start_register,
|
||||
@ -539,25 +445,12 @@ impl Instruction {
|
||||
|
||||
format!("{destination} = [R{start_register}..=R{end_register}]",)
|
||||
}
|
||||
Operation::LoadSelf => {
|
||||
Operation::LOAD_SELF => {
|
||||
let LoadSelf { destination } = LoadSelf::from(self);
|
||||
|
||||
format!("{destination} = self")
|
||||
}
|
||||
Operation::DefineLocal => {
|
||||
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 => {
|
||||
Operation::GET_LOCAL => {
|
||||
let GetLocal {
|
||||
destination,
|
||||
local_index,
|
||||
@ -565,7 +458,7 @@ impl Instruction {
|
||||
|
||||
format!("{destination} = L{local_index}")
|
||||
}
|
||||
Operation::SetLocal => {
|
||||
Operation::SET_LOCAL => {
|
||||
let SetLocal {
|
||||
register,
|
||||
local_index,
|
||||
@ -573,7 +466,7 @@ impl Instruction {
|
||||
|
||||
format!("L{local_index} = R{register}")
|
||||
}
|
||||
Operation::Add => {
|
||||
Operation::ADD => {
|
||||
let Add {
|
||||
destination,
|
||||
left,
|
||||
@ -582,7 +475,7 @@ impl Instruction {
|
||||
|
||||
format!("{destination} = {left} + {right}")
|
||||
}
|
||||
Operation::Subtract => {
|
||||
Operation::SUBTRACT => {
|
||||
let Subtract {
|
||||
destination,
|
||||
left,
|
||||
@ -591,7 +484,7 @@ impl Instruction {
|
||||
|
||||
format!("{destination} = {left} - {right}")
|
||||
}
|
||||
Operation::Multiply => {
|
||||
Operation::MULTIPLY => {
|
||||
let Multiply {
|
||||
destination,
|
||||
left,
|
||||
@ -600,7 +493,7 @@ impl Instruction {
|
||||
|
||||
format!("{destination} = {left} * {right}")
|
||||
}
|
||||
Operation::Divide => {
|
||||
Operation::DIVIDE => {
|
||||
let Divide {
|
||||
destination,
|
||||
left,
|
||||
@ -609,7 +502,7 @@ impl Instruction {
|
||||
|
||||
format!("{destination} = {left} / {right}")
|
||||
}
|
||||
Operation::Modulo => {
|
||||
Operation::MODULO => {
|
||||
let Modulo {
|
||||
destination,
|
||||
left,
|
||||
@ -618,7 +511,7 @@ impl Instruction {
|
||||
|
||||
format!("{destination} = {left} % {right}")
|
||||
}
|
||||
Operation::Test => {
|
||||
Operation::TEST => {
|
||||
let Test {
|
||||
argument,
|
||||
test_value: value,
|
||||
@ -627,7 +520,7 @@ impl Instruction {
|
||||
|
||||
format!("if {bang}{argument} {{ JUMP +1 }}",)
|
||||
}
|
||||
Operation::TestSet => {
|
||||
Operation::TEST_SET => {
|
||||
let TestSet {
|
||||
destination,
|
||||
argument,
|
||||
@ -637,25 +530,25 @@ impl Instruction {
|
||||
|
||||
format!("if {bang}{argument} {{ JUMP +1 }} else {{ {destination} = {argument} }}")
|
||||
}
|
||||
Operation::Equal => {
|
||||
Operation::EQUAL => {
|
||||
let Equal { value, left, right } = Equal::from(self);
|
||||
let comparison_symbol = if value { "==" } else { "!=" };
|
||||
|
||||
format!("if {left} {comparison_symbol} {right} {{ JUMP +1 }}")
|
||||
}
|
||||
Operation::Less => {
|
||||
Operation::LESS => {
|
||||
let Less { value, left, right } = Less::from(self);
|
||||
let comparison_symbol = if value { "<" } else { ">=" };
|
||||
|
||||
format!("if {left} {comparison_symbol} {right} {{ JUMP +1 }}")
|
||||
}
|
||||
Operation::LessEqual => {
|
||||
Operation::LESS_EQUAL => {
|
||||
let LessEqual { value, left, right } = LessEqual::from(self);
|
||||
let comparison_symbol = if value { "<=" } else { ">" };
|
||||
|
||||
format!("if {left} {comparison_symbol} {right} {{ JUMP +1 }}")
|
||||
}
|
||||
Operation::Negate => {
|
||||
Operation::NEGATE => {
|
||||
let Negate {
|
||||
destination,
|
||||
argument,
|
||||
@ -663,7 +556,7 @@ impl Instruction {
|
||||
|
||||
format!("{destination} = -{argument}")
|
||||
}
|
||||
Operation::Not => {
|
||||
Operation::NOT => {
|
||||
let Not {
|
||||
destination,
|
||||
argument,
|
||||
@ -671,7 +564,7 @@ impl Instruction {
|
||||
|
||||
format!("{destination} = !{argument}")
|
||||
}
|
||||
Operation::Jump => {
|
||||
Operation::JUMP => {
|
||||
let Jump {
|
||||
offset,
|
||||
is_positive,
|
||||
@ -683,7 +576,7 @@ impl Instruction {
|
||||
format!("JUMP -{offset}")
|
||||
}
|
||||
}
|
||||
Operation::Call => {
|
||||
Operation::CALL => {
|
||||
let Call {
|
||||
destination,
|
||||
function,
|
||||
@ -694,7 +587,7 @@ impl Instruction {
|
||||
|
||||
format!("{destination} = {function}(R{arguments_start}..R{arguments_end})")
|
||||
}
|
||||
Operation::CallNative => {
|
||||
Operation::CALL_NATIVE => {
|
||||
let CallNative {
|
||||
destination,
|
||||
function,
|
||||
@ -709,7 +602,7 @@ impl Instruction {
|
||||
format!("{function}(R{arguments_start}..R{arguments_end})")
|
||||
}
|
||||
}
|
||||
Operation::Return => {
|
||||
Operation::RETURN => {
|
||||
let Return {
|
||||
should_return_value,
|
||||
} = Return::from(self);
|
||||
@ -720,19 +613,20 @@ impl Instruction {
|
||||
"".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 {
|
||||
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 {
|
||||
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 {
|
||||
@ -795,6 +696,22 @@ impl Argument {
|
||||
pub fn is_register(&self) -> bool {
|
||||
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 {
|
||||
|
83
dust-lang/src/instruction/operation.rs
Normal file
83
dust-lang/src/instruction/operation.rs
Normal 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())
|
||||
}
|
||||
}
|
43
dust-lang/src/instruction/options.rs
Normal file
43
dust-lang/src/instruction/options.rs
Normal 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)
|
||||
}
|
||||
}
|
@ -35,7 +35,6 @@ pub mod dust_error;
|
||||
pub mod instruction;
|
||||
pub mod lexer;
|
||||
pub mod native_function;
|
||||
pub mod operation;
|
||||
pub mod optimize;
|
||||
pub mod scope;
|
||||
pub mod token;
|
||||
@ -47,10 +46,9 @@ pub use crate::chunk::{Chunk, Local};
|
||||
pub use crate::compiler::{compile, CompileError, Compiler};
|
||||
pub use crate::disassembler::Disassembler;
|
||||
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::native_function::{NativeFunction, NativeFunctionError};
|
||||
pub use crate::operation::Operation;
|
||||
pub use crate::optimize::{optimize_control_flow, optimize_set_local};
|
||||
pub use crate::r#type::{EnumType, FunctionType, StructType, Type, TypeConflict};
|
||||
pub use crate::scope::Scope;
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user