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"
|
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",
|
||||||
|
@ -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"
|
||||||
|
@ -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())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
options: InstructionOptions,
|
||||||
|
a: u16,
|
||||||
|
b: u16,
|
||||||
|
c: u16,
|
||||||
|
}
|
||||||
|
|
||||||
impl Instruction {
|
impl Instruction {
|
||||||
pub fn new(operation: Operation) -> Instruction {
|
|
||||||
Instruction(operation as u64)
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
||||||
|
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 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;
|
||||||
|
@ -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