From 0510e18060f48ff03536a799a7870ae2db100657 Mon Sep 17 00:00:00 2001 From: Jeff Date: Mon, 13 Jan 2025 06:01:38 -0500 Subject: [PATCH] Begin implementing typed 64-bit instructions --- dust-lang/src/chunk/constant_table.rs | 62 + dust-lang/src/chunk/disassembler.rs | 89 +- dust-lang/src/chunk/local.rs | 14 +- dust-lang/src/chunk/mod.rs | 12 +- dust-lang/src/compiler/mod.rs | 550 ++++++--- dust-lang/src/compiler/optimize.rs | 20 +- dust-lang/src/instruction/add.rs | 31 - dust-lang/src/instruction/add_byte.rs | 54 + dust-lang/src/instruction/add_char.rs | 54 + dust-lang/src/instruction/add_char_str.rs | 54 + dust-lang/src/instruction/add_float.rs | 54 + dust-lang/src/instruction/add_int.rs | 56 + dust-lang/src/instruction/add_str.rs | 54 + dust-lang/src/instruction/add_str_char.rs | 54 + dust-lang/src/instruction/call.rs | 26 +- dust-lang/src/instruction/call_native.rs | 21 +- dust-lang/src/instruction/close.rs | 27 +- dust-lang/src/instruction/divide.rs | 31 - dust-lang/src/instruction/divide_byte.rs | 54 + dust-lang/src/instruction/divide_float.rs | 54 + dust-lang/src/instruction/divide_int.rs | 54 + dust-lang/src/instruction/equal.rs | 27 - dust-lang/src/instruction/equal_bool.rs | 55 + dust-lang/src/instruction/equal_byte.rs | 55 + dust-lang/src/instruction/equal_char.rs | 55 + dust-lang/src/instruction/equal_char_str.rs | 55 + dust-lang/src/instruction/equal_float.rs | 55 + dust-lang/src/instruction/equal_int.rs | 55 + dust-lang/src/instruction/equal_str.rs | 55 + dust-lang/src/instruction/equal_str_char.rs | 55 + dust-lang/src/instruction/get_local.rs | 31 +- dust-lang/src/instruction/jump.rs | 16 +- dust-lang/src/instruction/less.rs | 27 - dust-lang/src/instruction/less_byte.rs | 55 + dust-lang/src/instruction/less_char.rs | 55 + dust-lang/src/instruction/less_equal.rs | 27 - dust-lang/src/instruction/less_equal_byte.rs | 55 + dust-lang/src/instruction/less_equal_char.rs | 55 + dust-lang/src/instruction/less_equal_float.rs | 55 + dust-lang/src/instruction/less_equal_int.rs | 55 + dust-lang/src/instruction/less_equal_str.rs | 55 + dust-lang/src/instruction/less_float.rs | 55 + dust-lang/src/instruction/less_int.rs | 55 + dust-lang/src/instruction/less_str.rs | 55 + dust-lang/src/instruction/load_boolean.rs | 39 +- dust-lang/src/instruction/load_constant.rs | 28 +- dust-lang/src/instruction/load_function.rs | 44 +- dust-lang/src/instruction/load_list.rs | 42 +- dust-lang/src/instruction/load_self.rs | 41 +- dust-lang/src/instruction/mod.rs | 1060 ++++++++++------- dust-lang/src/instruction/modulo.rs | 31 - dust-lang/src/instruction/modulo_byte.rs | 54 + dust-lang/src/instruction/modulo_float.rs | 54 + dust-lang/src/instruction/modulo_int.rs | 54 + dust-lang/src/instruction/multiply.rs | 31 - dust-lang/src/instruction/multiply_byte.rs | 54 + dust-lang/src/instruction/multiply_float.rs | 54 + dust-lang/src/instruction/multiply_int.rs | 54 + dust-lang/src/instruction/negate.rs | 29 - dust-lang/src/instruction/negate_float.rs | 48 + dust-lang/src/instruction/negate_int.rs | 48 + dust-lang/src/instruction/not.rs | 21 +- dust-lang/src/instruction/operation.rs | 186 ++- dust-lang/src/instruction/point.rs | 32 +- dust-lang/src/instruction/return.rs | 16 +- dust-lang/src/instruction/set_local.rs | 31 +- dust-lang/src/instruction/subtract.rs | 31 - dust-lang/src/instruction/subtract_byte.rs | 54 + dust-lang/src/instruction/subtract_float.rs | 54 + dust-lang/src/instruction/subtract_int.rs | 54 + dust-lang/src/instruction/test.rs | 23 +- dust-lang/src/instruction/test_set.rs | 24 +- dust-lang/src/instruction/type_code.rs | 10 - dust-lang/src/lib.rs | 10 +- dust-lang/src/native_function/assert.rs | 2 +- dust-lang/src/native_function/io.rs | 6 +- dust-lang/src/native_function/mod.rs | 8 +- dust-lang/src/native_function/random.rs | 2 +- dust-lang/src/native_function/string.rs | 2 +- dust-lang/src/native_function/thread.rs | 4 +- dust-lang/src/type.rs | 6 +- dust-lang/src/value/function.rs | 2 +- dust-lang/src/vm/function_call.rs | 4 +- dust-lang/src/vm/mod.rs | 8 +- dust-lang/src/vm/run_action.rs | 18 +- dust-lang/src/vm/thread.rs | 26 +- dust-lang/tests/basic.rs | 12 +- dust-lang/tests/comparison.rs | 12 +- dust-lang/tests/functions.rs | 8 +- dust-lang/tests/lists.rs | 8 +- dust-lang/tests/loops.rs | 4 +- dust-lang/tests/math/divide.rs | 6 +- dust-lang/tests/math/divide_assign.rs | 2 +- dust-lang/tests/math/modulo.rs | 4 +- dust-lang/tests/math/multiply.rs | 4 +- dust-lang/tests/math/multiply_assign.rs | 2 +- dust-lang/tests/math/subtract.rs | 8 +- dust-lang/tests/math/subtract_assign.rs | 2 +- dust-lang/tests/unary_operations.rs | 4 +- 99 files changed, 3918 insertions(+), 1100 deletions(-) create mode 100644 dust-lang/src/chunk/constant_table.rs delete mode 100644 dust-lang/src/instruction/add.rs create mode 100644 dust-lang/src/instruction/add_byte.rs create mode 100644 dust-lang/src/instruction/add_char.rs create mode 100644 dust-lang/src/instruction/add_char_str.rs create mode 100644 dust-lang/src/instruction/add_float.rs create mode 100644 dust-lang/src/instruction/add_int.rs create mode 100644 dust-lang/src/instruction/add_str.rs create mode 100644 dust-lang/src/instruction/add_str_char.rs delete mode 100644 dust-lang/src/instruction/divide.rs create mode 100644 dust-lang/src/instruction/divide_byte.rs create mode 100644 dust-lang/src/instruction/divide_float.rs create mode 100644 dust-lang/src/instruction/divide_int.rs delete mode 100644 dust-lang/src/instruction/equal.rs create mode 100644 dust-lang/src/instruction/equal_bool.rs create mode 100644 dust-lang/src/instruction/equal_byte.rs create mode 100644 dust-lang/src/instruction/equal_char.rs create mode 100644 dust-lang/src/instruction/equal_char_str.rs create mode 100644 dust-lang/src/instruction/equal_float.rs create mode 100644 dust-lang/src/instruction/equal_int.rs create mode 100644 dust-lang/src/instruction/equal_str.rs create mode 100644 dust-lang/src/instruction/equal_str_char.rs delete mode 100644 dust-lang/src/instruction/less.rs create mode 100644 dust-lang/src/instruction/less_byte.rs create mode 100644 dust-lang/src/instruction/less_char.rs delete mode 100644 dust-lang/src/instruction/less_equal.rs create mode 100644 dust-lang/src/instruction/less_equal_byte.rs create mode 100644 dust-lang/src/instruction/less_equal_char.rs create mode 100644 dust-lang/src/instruction/less_equal_float.rs create mode 100644 dust-lang/src/instruction/less_equal_int.rs create mode 100644 dust-lang/src/instruction/less_equal_str.rs create mode 100644 dust-lang/src/instruction/less_float.rs create mode 100644 dust-lang/src/instruction/less_int.rs create mode 100644 dust-lang/src/instruction/less_str.rs delete mode 100644 dust-lang/src/instruction/modulo.rs create mode 100644 dust-lang/src/instruction/modulo_byte.rs create mode 100644 dust-lang/src/instruction/modulo_float.rs create mode 100644 dust-lang/src/instruction/modulo_int.rs delete mode 100644 dust-lang/src/instruction/multiply.rs create mode 100644 dust-lang/src/instruction/multiply_byte.rs create mode 100644 dust-lang/src/instruction/multiply_float.rs create mode 100644 dust-lang/src/instruction/multiply_int.rs delete mode 100644 dust-lang/src/instruction/negate.rs create mode 100644 dust-lang/src/instruction/negate_float.rs create mode 100644 dust-lang/src/instruction/negate_int.rs delete mode 100644 dust-lang/src/instruction/subtract.rs create mode 100644 dust-lang/src/instruction/subtract_byte.rs create mode 100644 dust-lang/src/instruction/subtract_float.rs create mode 100644 dust-lang/src/instruction/subtract_int.rs delete mode 100644 dust-lang/src/instruction/type_code.rs diff --git a/dust-lang/src/chunk/constant_table.rs b/dust-lang/src/chunk/constant_table.rs new file mode 100644 index 0000000..4c0c1ed --- /dev/null +++ b/dust-lang/src/chunk/constant_table.rs @@ -0,0 +1,62 @@ +use serde::{Deserialize, Serialize}; + +use crate::DustString; + +#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] +pub struct ConstantTable { + pub r#true: bool, + pub r#false: bool, + pub bytes: Vec, + pub characters: Vec, + pub floats: Vec, + pub integers: Vec, + pub strings: Vec, +} + +impl ConstantTable { + pub fn new() -> Self { + Self { + r#true: false, + r#false: false, + bytes: Vec::new(), + characters: Vec::new(), + floats: Vec::new(), + integers: Vec::new(), + strings: Vec::new(), + } + } + + #[cfg(debug_assertions)] + pub fn with_data( + booleans: (bool, bool), + bytes: impl Into>, + characters: impl Into>, + floats: impl Into>, + integers: impl Into>, + strings: impl Into>, + ) -> Self { + Self { + r#true: booleans.0, + r#false: booleans.1, + bytes: bytes.into(), + characters: characters.into(), + floats: floats.into(), + integers: integers.into(), + strings: strings.into(), + } + } + + pub fn len(&self) -> usize { + (if self.r#true { 1 } else { 0 }) + + (if self.r#false { 1 } else { 0 }) + + self.bytes.len() + + self.characters.len() + + self.floats.len() + + self.integers.len() + + self.strings.len() + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } +} diff --git a/dust-lang/src/chunk/disassembler.rs b/dust-lang/src/chunk/disassembler.rs index ac0b62a..b9dd48c 100644 --- a/dust-lang/src/chunk/disassembler.rs +++ b/dust-lang/src/chunk/disassembler.rs @@ -43,7 +43,7 @@ use std::io::{self, Write}; use colored::{ColoredString, Colorize}; -use crate::{Chunk, Local}; +use crate::{Chunk, Local, Type}; const INSTRUCTION_COLUMNS: [(&str, usize); 4] = [("i", 5), ("POSITION", 12), ("OPERATION", 17), ("INFO", 24)]; @@ -322,6 +322,7 @@ impl<'a, W: Write> Disassembler<'a, W> { let identifier_display = self .chunk .constants + .strings .get(*identifier_index as usize) .map(|value| value.to_string()) .unwrap_or_else(|| "unknown".to_string()); @@ -352,8 +353,88 @@ impl<'a, W: Write> Disassembler<'a, W> { self.write_center_border(&column_name_line)?; self.write_center_border(CONSTANT_BORDERS[1])?; - for (index, value) in self.chunk.constants.iter().enumerate() { - let type_display = value.r#type().to_string(); + if self.chunk.constants.r#true { + let type_display = Type::Boolean.to_string(); + let value_display = "true"; + let constant_display = format!("│{:^5}│{:^26}│{:^26}│", 0, type_display, value_display); + + self.write_center_border(&constant_display)?; + } + + if self.chunk.constants.r#false { + let type_display = Type::Boolean.to_string(); + let value_display = "false"; + let constant_display = format!("│{:^5}│{:^26}│{:^26}│", 1, type_display, value_display); + + self.write_center_border(&constant_display)?; + } + + for (index, value) in self.chunk.constants.bytes.iter().enumerate() { + let type_display = Type::Byte.to_string(); + let value_display = { + let mut value_string = value.to_string(); + + if value_string.len() > 26 { + value_string = format!("{value_string:.23}..."); + } + + value_string + }; + let constant_display = format!("│{index:^5}│{type_display:^26}│{value_display:^26}│"); + + self.write_center_border(&constant_display)?; + } + + for (index, value) in self.chunk.constants.characters.iter().enumerate() { + let type_display = Type::Character.to_string(); + let value_display = { + let mut value_string = value.to_string(); + + if value_string.len() > 26 { + value_string = format!("{value_string:.23}..."); + } + + value_string + }; + let constant_display = format!("│{index:^5}│{type_display:^26}│{value_display:^26}│"); + + self.write_center_border(&constant_display)?; + } + + for (index, value) in self.chunk.constants.floats.iter().enumerate() { + let type_display = Type::Float.to_string(); + let value_display = { + let mut value_string = value.to_string(); + + if value_string.len() > 26 { + value_string = format!("{value_string:.23}..."); + } + + value_string + }; + let constant_display = format!("│{index:^5}│{type_display:^26}│{value_display:^26}│"); + + self.write_center_border(&constant_display)?; + } + + for (index, value) in self.chunk.constants.integers.iter().enumerate() { + let type_display = Type::Integer.to_string(); + let value_display = { + let mut value_string = value.to_string(); + + if value_string.len() > 26 { + value_string = format!("{value_string:.23}..."); + } + + value_string + }; + let constant_display = format!("│{index:^5}│{type_display:^26}│{value_display:^26}│"); + + self.write_center_border(&constant_display)?; + } + + for (index, value) in self.chunk.constants.strings.iter().enumerate() { + let type_display = Type::String.to_string(); let value_display = { let mut value_string = value.to_string(); @@ -374,7 +455,7 @@ impl<'a, W: Write> Disassembler<'a, W> { } pub fn write_prototype_section(&mut self) -> Result<(), io::Error> { - self.write_center_border_bold("Functions")?; + self.write_center_border_bold("Prototypes")?; for chunk in &self.chunk.prototypes { chunk diff --git a/dust-lang/src/chunk/local.rs b/dust-lang/src/chunk/local.rs index 67f9d68..30cf47b 100644 --- a/dust-lang/src/chunk/local.rs +++ b/dust-lang/src/chunk/local.rs @@ -1,15 +1,17 @@ +//! Scoped variable. + use serde::{Deserialize, Serialize}; use crate::Scope; -/// A scoped variable. +/// Scoped variable. #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct Local { - /// The index of the identifier in the constants table. - pub identifier_index: u8, + /// Index of the identifier in the constants list. + pub identifier_index: u16, - /// Stack index where the local's value is stored. - pub register_index: u8, + /// Index of the register where the variable's value is stored. + pub register_index: u16, /// Whether the local is mutable. pub is_mutable: bool, @@ -20,7 +22,7 @@ pub struct Local { impl Local { /// Creates a new Local instance. - pub fn new(identifier_index: u8, register_index: u8, is_mutable: bool, scope: Scope) -> Self { + pub fn new(identifier_index: u16, register_index: u16, is_mutable: bool, scope: Scope) -> Self { Self { identifier_index, register_index, diff --git a/dust-lang/src/chunk/mod.rs b/dust-lang/src/chunk/mod.rs index d9a7364..29f68b7 100644 --- a/dust-lang/src/chunk/mod.rs +++ b/dust-lang/src/chunk/mod.rs @@ -13,10 +13,12 @@ //! [`Chunk::with_data`] can be used to create a chunk for comparison to the compiler output. Do not //! try to run these chunks in a virtual machine. Due to their missing stack size and record index, //! they will cause a panic or undefined behavior. +mod constant_table; mod disassembler; mod local; mod scope; +pub use constant_table::ConstantTable; pub use disassembler::Disassembler; pub use local::Local; pub use scope::Scope; @@ -27,7 +29,7 @@ use std::sync::Arc; use serde::{Deserialize, Serialize}; -use crate::{DustString, Function, FunctionType, Instruction, Span, Value}; +use crate::{DustString, Function, FunctionType, Instruction, Span}; /// Representation of a Dust program or function. /// @@ -39,12 +41,12 @@ pub struct Chunk { pub(crate) instructions: Vec, pub(crate) positions: Vec, - pub(crate) constants: Vec, + pub(crate) constants: ConstantTable, pub(crate) locals: Vec, pub(crate) prototypes: Vec>, pub(crate) register_count: usize, - pub(crate) prototype_index: u8, + pub(crate) prototype_index: u16, } impl Chunk { @@ -54,7 +56,7 @@ impl Chunk { r#type: FunctionType, instructions: impl Into>, positions: impl Into>, - constants: impl Into>, + constants: ConstantTable, locals: impl Into>, prototypes: impl IntoIterator, ) -> Self { @@ -63,7 +65,7 @@ impl Chunk { r#type, instructions: instructions.into(), positions: positions.into(), - constants: constants.into(), + constants, locals: locals.into(), prototypes: prototypes.into_iter().map(Arc::new).collect(), register_count: 0, diff --git a/dust-lang/src/compiler/mod.rs b/dust-lang/src/compiler/mod.rs index 270fc81..cb007b1 100644 --- a/dust-lang/src/compiler/mod.rs +++ b/dust-lang/src/compiler/mod.rs @@ -33,9 +33,10 @@ use std::{mem::replace, sync::Arc}; use optimize::control_flow_register_consolidation; use crate::{ - Argument, Chunk, ConcreteValue, DustError, DustString, FunctionType, Instruction, Lexer, Local, - NativeFunction, Operation, Scope, Span, Token, TokenKind, Type, Value, - instruction::{CallNative, Close, GetLocal, Jump, LoadList, Negate, Not, Return, SetLocal}, + Chunk, ConcreteValue, DustError, DustString, FunctionType, Instruction, Lexer, Local, + NativeFunction, Operand, Operation, Scope, Span, Token, TokenKind, Type, Value, + chunk::ConstantTable, + instruction::{GetLocal, Jump, LoadList}, }; /// Compiles the input and returns a chunk. @@ -88,7 +89,7 @@ pub struct Compiler<'src> { /// Constants that have been compiled. These are assigned to the chunk when [`Compiler::finish`] /// is called. - constants: Vec, + constants: ConstantTable, /// Block-local variables and their types. The locals are assigned to the chunk when /// [`Compiler::finish`] is called. The types are discarded after compilation. @@ -104,7 +105,7 @@ pub struct Compiler<'src> { /// The first register index that the compiler should use. This is used to avoid reusing the /// registers that are used for the function's arguments. - minimum_register: u8, + minimum_register: u16, /// Index of the current block. This is used to determine the scope of locals and is incremented /// when a new block is entered. @@ -115,7 +116,7 @@ pub struct Compiler<'src> { /// Index of the Chunk in its parent's prototype list. This is set to 0 for the main chunk but /// that value is never read because the main chunk is not a callable function. - prototype_index: u8, + prototype_index: u16, /// Whether the chunk is the program's main chunk. This is used to prevent recursive calls to /// the main chunk. @@ -144,7 +145,7 @@ impl<'src> Compiler<'src> { return_type: Type::None, }, instructions: Vec::new(), - constants: Vec::new(), + constants: ConstantTable::new(), locals: Vec::new(), prototypes: Vec::new(), stack_size: 0, @@ -215,7 +216,7 @@ impl<'src> Compiler<'src> { r#type: self.r#type, instructions, positions, - constants: self.constants.to_vec(), + constants: self.constants, locals, prototypes: self.prototypes, register_count: self.stack_size, @@ -227,7 +228,7 @@ impl<'src> Compiler<'src> { matches!(self.current_token, Token::Eof) } - fn next_register(&self) -> u8 { + fn next_register(&self) -> u16 { self.instructions .iter() .rev() @@ -260,7 +261,7 @@ impl<'src> Compiler<'src> { Ok(()) } - fn get_local(&self, index: u8) -> Result<&(Local, Type), CompileError> { + fn get_local(&self, index: u16) -> Result<&(Local, Type), CompileError> { self.locals .get(index as usize) .ok_or(CompileError::UndeclaredVariable { @@ -269,22 +270,19 @@ impl<'src> Compiler<'src> { }) } - fn get_local_index(&self, identifier_text: &str) -> Result { + fn get_local_index(&self, identifier_text: &str) -> Result { self.locals .iter() .enumerate() .rev() .find_map(|(index, (local, _))| { - let constant = self.constants.get(local.identifier_index as usize)?; - let identifier = - if let Value::Concrete(ConcreteValue::String(identifier)) = constant { - identifier - } else { - return None; - }; + let identifier = self + .constants + .strings + .get(local.identifier_index as usize)?; if identifier == identifier_text { - Some(index as u8) + Some(index as u16) } else { None } @@ -298,16 +296,16 @@ impl<'src> Compiler<'src> { fn declare_local( &mut self, identifier: &str, - register_index: u8, + register_index: u16, r#type: Type, is_mutable: bool, scope: Scope, - ) -> (u8, u8) { + ) -> (u16, u16) { info!("Declaring local {identifier}"); - let identifier = Value::Concrete(ConcreteValue::string(identifier)); - let identifier_index = self.push_or_get_constant(identifier); - let local_index = self.locals.len() as u8; + let identifier = DustString::from(identifier); + let identifier_index = self.push_or_get_constant_string(identifier); + let local_index = self.locals.len() as u16; self.locals.push(( Local::new(identifier_index, register_index, is_mutable, scope), @@ -317,29 +315,107 @@ impl<'src> Compiler<'src> { (local_index, identifier_index) } - fn get_identifier(&self, local_index: u8) -> Option { + fn get_identifier(&self, local_index: u16) -> Option { self.locals .get(local_index as usize) .and_then(|(local, _)| { self.constants + .strings .get(local.identifier_index as usize) .map(|value| value.to_string()) }) } - fn push_or_get_constant(&mut self, value: Value) -> u8 { + fn push_or_get_constant_bool(&mut self, boolean: bool) -> u16 { + if boolean { + if self.constants.r#true { + 0 + } else { + self.constants.r#true = true; + + 0 + } + } else if self.constants.r#false { + 1 + } else { + self.constants.r#false = true; + + 1 + } + } + + fn push_or_get_constant_byte(&mut self, new_byte: u8) -> u16 { if let Some(index) = self .constants + .bytes .iter() - .position(|constant| constant == &value) + .position(|&byte| byte == new_byte) { - index as u8 + index as u16 } else { - let index = self.constants.len() as u8; + self.constants.bytes.push(new_byte); - self.constants.push(value); + (self.constants.bytes.len() - 1) as u16 + } + } - index + fn push_or_get_constant_character(&mut self, new_character: char) -> u16 { + if let Some(index) = self + .constants + .characters + .iter() + .position(|&character| character == new_character) + { + index as u16 + } else { + self.constants.characters.push(new_character); + + (self.constants.characters.len() - 1) as u16 + } + } + + fn push_or_get_constant_float(&mut self, new_float: f64) -> u16 { + if let Some(index) = self + .constants + .floats + .iter() + .position(|&float| float == new_float) + { + index as u16 + } else { + self.constants.floats.push(new_float); + + (self.constants.floats.len() - 1) as u16 + } + } + + fn push_or_get_constant_integer(&mut self, new_integer: i64) -> u16 { + if let Some(index) = self + .constants + .integers + .iter() + .position(|&integer| integer == new_integer) + { + index as u16 + } else { + self.constants.integers.push(new_integer); + + (self.constants.integers.len() - 1) as u16 + } + } + + fn push_or_get_constant_string(&mut self, new_string: DustString) -> u16 { + if let Some(index) = self + .constants + .strings + .iter() + .position(|string| *string == new_string) + { + index as u16 + } else { + self.constants.strings.push(new_string); + + (self.constants.strings.len() - 1) as u16 } } @@ -393,7 +469,7 @@ impl<'src> Compiler<'src> { .unwrap_or(Type::None) } - fn get_register_type(&self, register_index: u8) -> Result { + fn get_register_type(&self, register_index: u16) -> Result { if let Some((_, r#type)) = self .locals .iter() @@ -481,6 +557,14 @@ impl<'src> Compiler<'src> { Ok(()) } + fn emit_boolean_constant(&mut self, boolean: bool, position: Span) { + let constant_index = self.push_or_get_constant_bool(boolean); + let destination = self.next_register(); + let load_boolean = Instruction::load_constant(destination, constant_index, jump_next); + + self.emit_instruction(load_boolean, Type::Boolean, position); + } + fn parse_boolean(&mut self) -> Result<(), CompileError> { let position = self.current_position; @@ -651,15 +735,10 @@ impl<'src> Compiler<'src> { } let destination = self.next_register(); - let instruction = match operator.kind() { - TokenKind::Bang => Instruction::from(Not { - destination, - argument, - }), - TokenKind::Minus => Instruction::from(Negate { - destination, - argument, - }), + let instruction = match (operator, &previous_type) { + (Token::Bang, Type::Boolean) => Instruction::not(destination, argument), + (Token::Minus, Type::Float) => Instruction::negate_float(destination, argument), + (Token::Minus, Type::Integer) => Instruction::negate_int(destination, argument), _ => { return Err(CompileError::ExpectedTokenMultiple { expected: &[TokenKind::Bang, TokenKind::Minus], @@ -677,34 +756,62 @@ impl<'src> Compiler<'src> { fn handle_binary_argument( &mut self, instruction: &Instruction, - ) -> Result<(Argument, bool), CompileError> { + ) -> Result<(Operand, bool), CompileError> { let (argument, push_back) = match instruction.operation() { - Operation::LOAD_CONSTANT => (Argument::Constant(instruction.b_field()), false), + Operation::LOAD_CONSTANT => (Operand::Constant(instruction.b_field()), false), Operation::GET_LOCAL => { let local_index = instruction.b_field(); let (local, _) = self.get_local(local_index)?; - (Argument::Register(local.register_index), false) + (Operand::Register(local.register_index), false) } Operation::LOAD_BOOLEAN | Operation::LOAD_LIST | Operation::LOAD_SELF - | Operation::ADD - | Operation::SUBTRACT - | Operation::MULTIPLY - | Operation::DIVIDE - | Operation::MODULO - | Operation::EQUAL - | Operation::LESS - | Operation::LESS_EQUAL - | Operation::NEGATE + | Operation::ADD_BYTE + | Operation::ADD_CHAR + | Operation::ADD_CHAR_STR + | Operation::ADD_FLOAT + | Operation::ADD_INT + | Operation::ADD_STR + | Operation::ADD_STR_CHAR + | Operation::SUBTRACT_BYTE + | Operation::SUBTRACT_FLOAT + | Operation::SUBTRACT_INT + | Operation::MULTIPLY_BYTE + | Operation::MULTIPLY_FLOAT + | Operation::MULTIPLY_INT + | Operation::DIVIDE_BYTE + | Operation::DIVIDE_FLOAT + | Operation::DIVIDE_INT + | Operation::MODULO_BYTE + | Operation::MODULO_INT + | Operation::MODULO_FLOAT + | Operation::EQUAL_INT + | Operation::EQUAL_FLOAT + | Operation::EQUAL_CHAR + | Operation::EQUAL_STR + | Operation::EQUAL_BOOL + | Operation::EQUAL_BYTE + | Operation::LESS_INT + | Operation::LESS_FLOAT + | Operation::LESS_CHAR + | Operation::LESS_STR + | Operation::LESS_BYTE + | Operation::LESS_EQUAL_INT + | Operation::LESS_EQUAL_FLOAT + | Operation::LESS_EQUAL_CHAR + | Operation::LESS_EQUAL_STR + | Operation::LESS_EQUAL_BYTE + | Operation::NEGATE_INT + | Operation::NEGATE_FLOAT | Operation::NOT - | Operation::CALL => (Argument::Register(instruction.a_field()), true), + | Operation::CALL => (Operand::Register(instruction.a_field()), true), Operation::CALL_NATIVE => { let function = NativeFunction::from(instruction.b_field()); if function.returns_value() { - (Argument::Register(instruction.a_field()), true) + (Operand::Register(instruction.a_field()), true) } else { return Err(CompileError::ExpectedExpression { found: self.previous_token.to_owned(), @@ -786,7 +893,7 @@ impl<'src> Compiler<'src> { if push_back_right { self.instructions - .push((right_instruction, right_type, right_position)); + .push((right_instruction, right_type.clone(), right_position)); } let r#type = if is_assignment { @@ -798,18 +905,70 @@ impl<'src> Compiler<'src> { }; let destination = if is_assignment { match left { - Argument::Register(register) => register, - Argument::Constant(_) => self.next_register(), + Operand::Register(register) => register, + Operand::Constant(_) => self.next_register(), } } else { self.next_register() }; - let instruction = match operator { - Token::Plus | Token::PlusEqual => Instruction::add(destination, left, right), - Token::Minus | Token::MinusEqual => Instruction::subtract(destination, left, right), - Token::Star | Token::StarEqual => Instruction::multiply(destination, left, right), - Token::Slash | Token::SlashEqual => Instruction::divide(destination, left, right), - Token::Percent | Token::PercentEqual => Instruction::modulo(destination, left, right), + let instruction = match (operator, left_type, right_type) { + (Token::Plus, Type::Byte, Type::Byte) => { + Instruction::add_byte(destination, left, right) + } + (Token::Plus, Type::Character, Type::Character) => { + Instruction::add_char(destination, left, right) + } + (Token::Plus, Type::Character, Type::String) => { + Instruction::add_char_str(destination, left, right) + } + (Token::Plus, Type::Float, Type::Float) => { + Instruction::add_float(destination, left, right) + } + (Token::Plus, Type::Integer, Type::Integer) => { + Instruction::add_int(destination, left, right) + } + (Token::Plus, Type::String, Type::Character) => { + Instruction::add_str_char(destination, left, right) + } + (Token::Plus, Type::String, Type::String) => { + Instruction::add_str(destination, left, right) + } + (Token::Minus, Type::Byte, Type::Byte) => { + Instruction::subtract_byte(destination, left, right) + } + (Token::Minus, Type::Float, Type::Float) => { + Instruction::subtract_float(destination, left, right) + } + (Token::Minus, Type::Integer, Type::Integer) => { + Instruction::subtract_int(destination, left, right) + } + (Token::Star, Type::Byte, Type::Byte) => { + Instruction::multiply_byte(destination, left, right) + } + (Token::Star, Type::Float, Type::Float) => { + Instruction::multiply_float(destination, left, right) + } + (Token::Star, Type::Integer, Type::Integer) => { + Instruction::multiply_int(destination, left, right) + } + (Token::Slash, Type::Byte, Type::Byte) => { + Instruction::divide_byte(destination, left, right) + } + (Token::Slash, Type::Float, Type::Float) => { + Instruction::divide_float(destination, left, right) + } + (Token::Slash, Type::Integer, Type::Integer) => { + Instruction::divide_int(destination, left, right) + } + (Token::Percent, Type::Byte, Type::Byte) => { + Instruction::modulo_byte(destination, left, right) + } + (Token::Percent, Type::Integer, Type::Integer) => { + Instruction::modulo_int(destination, left, right) + } + (Token::Percent, Type::Float, Type::Float) => { + Instruction::modulo_float(destination, left, right) + } _ => { return Err(CompileError::ExpectedTokenMultiple { expected: &[ @@ -836,13 +995,9 @@ impl<'src> Compiler<'src> { } fn parse_comparison_binary(&mut self) -> Result<(), CompileError> { - if let Some( - [ - Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL, - _, - _, - ], - ) = self.get_last_operations() + if self + .get_last_operation() + .is_some_and(|operation| operation.is_comparison()) { return Err(CompileError::ComparisonChain { position: self.current_position, @@ -863,7 +1018,7 @@ impl<'src> Compiler<'src> { if push_back_left { self.instructions - .push((left_instruction, left_type, left_position)); + .push((left_instruction, left_type.clone(), left_position)); } self.advance()?; @@ -880,17 +1035,111 @@ impl<'src> Compiler<'src> { if push_back_right { self.instructions - .push((right_instruction, right_type, right_position)); + .push((right_instruction, right_type.clone(), right_position)); } let destination = self.next_register(); - let comparison = match operator { - Token::DoubleEqual => Instruction::equal(true, left, right), - Token::BangEqual => Instruction::equal(false, left, right), - Token::Less => Instruction::less(true, left, right), - Token::LessEqual => Instruction::less_equal(true, left, right), - Token::Greater => Instruction::less_equal(false, left, right), - Token::GreaterEqual => Instruction::less(false, left, right), + let comparison = match (operator, left_type, right_type) { + (Token::DoubleEqual, Type::Boolean, Type::Boolean) => { + Instruction::equal_bool(true, left, right) + } + (Token::DoubleEqual, Type::Byte, Type::Byte) => { + Instruction::equal_byte(true, left, right) + } + (Token::DoubleEqual, Type::Character, Type::Character) => { + Instruction::equal_char(true, left, right) + } + (Token::DoubleEqual, Type::Character, Type::String) => { + Instruction::equal_char_str(true, left, right) + } + (Token::DoubleEqual, Type::Float, Type::Float) => { + Instruction::equal_float(true, left, right) + } + (Token::DoubleEqual, Type::Integer, Type::Integer) => { + Instruction::equal_int(true, left, right) + } + (Token::DoubleEqual, Type::String, Type::String) => { + Instruction::equal_str(true, left, right) + } + (Token::DoubleEqual, Type::String, Type::Character) => { + Instruction::equal_str_char(true, left, right) + } + (Token::BangEqual, Type::Boolean, Type::Boolean) => { + Instruction::equal_bool(false, left, right) + } + (Token::BangEqual, Type::Byte, Type::Byte) => { + Instruction::equal_byte(false, left, right) + } + (Token::BangEqual, Type::Character, Type::Character) => { + Instruction::equal_char(false, left, right) + } + (Token::BangEqual, Type::Character, Type::String) => { + Instruction::equal_char_str(false, left, right) + } + (Token::BangEqual, Type::Float, Type::Float) => { + Instruction::equal_float(false, left, right) + } + (Token::BangEqual, Type::Integer, Type::Integer) => { + Instruction::equal_int(false, left, right) + } + (Token::BangEqual, Type::String, Type::String) => { + Instruction::equal_str(false, left, right) + } + (Token::BangEqual, Type::String, Type::Character) => { + Instruction::equal_str_char(false, left, right) + } + (Token::Less, Type::Byte, Type::Byte) => Instruction::less_byte(true, left, right), + (Token::Less, Type::Character, Type::Character) => { + Instruction::less_char(true, left, right) + } + (Token::Less, Type::Float, Type::Float) => Instruction::less_float(true, left, right), + (Token::Less, Type::Integer, Type::Integer) => Instruction::less_int(true, left, right), + (Token::Less, Type::String, Type::String) => Instruction::less_str(true, left, right), + (Token::GreaterEqual, Type::Byte, Type::Byte) => { + Instruction::less_byte(false, left, right) + } + (Token::GreaterEqual, Type::Character, Type::Character) => { + Instruction::less_char(false, left, right) + } + (Token::GreaterEqual, Type::Float, Type::Float) => { + Instruction::less_float(false, left, right) + } + (Token::GreaterEqual, Type::Integer, Type::Integer) => { + Instruction::less_int(false, left, right) + } + (Token::GreaterEqual, Type::String, Type::String) => { + Instruction::less_str(false, left, right) + } + (Token::LessEqual, Type::Byte, Type::Byte) => { + Instruction::less_equal_byte(true, left, right) + } + (Token::LessEqual, Type::Character, Type::Character) => { + Instruction::less_equal_char(true, left, right) + } + (Token::LessEqual, Type::Float, Type::Float) => { + Instruction::less_equal_float(true, left, right) + } + (Token::LessEqual, Type::Integer, Type::Integer) => { + Instruction::less_equal_int(true, left, right) + } + (Token::LessEqual, Type::String, Type::String) => { + Instruction::less_equal_str(true, left, right) + } + (Token::Greater, Type::Byte, Type::Byte) => { + Instruction::less_equal_byte(false, left, right) + } + (Token::Greater, Type::Character, Type::Character) => { + Instruction::less_equal_char(false, left, right) + } + (Token::Greater, Type::Float, Type::Float) => { + Instruction::less_equal_float(false, left, right) + } + (Token::Greater, Type::Integer, Type::Integer) => { + Instruction::less_equal_int(false, left, right) + } + (Token::Greater, Type::String, Type::String) => { + Instruction::less_equal_str(false, left, right) + } _ => { return Err(CompileError::ExpectedTokenMultiple { expected: &[ @@ -974,7 +1223,23 @@ impl<'src> Compiler<'src> { if !matches!( instructions[0].0.operation(), - Operation::TEST | Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL + Operation::TEST + | Operation::EQUAL_INT + | Operation::EQUAL_STR + | Operation::EQUAL_BOOL + | Operation::EQUAL_BYTE + | Operation::EQUAL_CHAR + | Operation::EQUAL_FLOAT + | Operation::LESS_INT + | Operation::LESS_STR + | Operation::LESS_BYTE + | Operation::LESS_CHAR + | Operation::LESS_FLOAT + | Operation::LESS_EQUAL_INT + | Operation::LESS_EQUAL_STR + | Operation::LESS_EQUAL_BYTE + | Operation::LESS_EQUAL_CHAR + | Operation::LESS_EQUAL_FLOAT ) || !matches!(instructions[1].0.operation(), Operation::JUMP) { continue; @@ -982,7 +1247,7 @@ impl<'src> Compiler<'src> { let old_jump = &mut instructions[1].0; let jump_index = instructions_length - group_index * 3 - 1; - let short_circuit_distance = (instructions_length - jump_index) as u8; + let short_circuit_distance = (instructions_length - jump_index) as u16; *old_jump = Instruction::jump(short_circuit_distance, true); } @@ -1009,7 +1274,7 @@ impl<'src> Compiler<'src> { return self.parse_call_native(native_function); } else if self.function_name.as_deref() == Some(identifier) && !self.is_main { let destination = self.next_register(); - let load_self = Instruction::load_self(destination); + let load_self = Instruction::load_self(destination, false); self.emit_instruction(load_self, Type::SelfFunction, start_position); @@ -1056,10 +1321,7 @@ impl<'src> Compiler<'src> { math_instruction.set_a_field(local_register_index); } else { let register = self.next_register() - 1; - let set_local = Instruction::from(SetLocal { - register_index: register, - local_index, - }); + let set_local = Instruction::set_local(register, local_index); self.emit_instruction(set_local, Type::None, start_position); } @@ -1134,10 +1396,7 @@ impl<'src> Compiler<'src> { } if expected_register < actual_register { - let close = Instruction::from(Close { - from: expected_register, - to: actual_register, - }); + let close = Instruction::close(expected_register, actual_register); self.emit_instruction(close, Type::None, self.current_position); } @@ -1147,10 +1406,7 @@ impl<'src> Compiler<'src> { let destination = self.next_register(); let end = self.previous_position.1; - let load_list = Instruction::from(LoadList { - destination, - start_register, - }); + let load_list = Instruction::load_list(destination, start_register, false); self.emit_instruction(load_list, Type::List(Box::new(item_type)), Span(start, end)); @@ -1164,7 +1420,22 @@ impl<'src> Compiler<'src> { if matches!( self.get_last_operations(), Some([ - Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL, + Operation::EQUAL_INT + | Operation::EQUAL_STR + | Operation::EQUAL_BOOL + | Operation::EQUAL_BYTE + | Operation::EQUAL_CHAR + | Operation::EQUAL_FLOAT + | Operation::LESS_INT + | Operation::LESS_STR + | Operation::LESS_BYTE + | Operation::LESS_CHAR + | Operation::LESS_FLOAT + | Operation::LESS_EQUAL_INT + | Operation::LESS_EQUAL_STR + | Operation::LESS_EQUAL_BYTE + | Operation::LESS_EQUAL_CHAR + | Operation::LESS_EQUAL_FLOAT, Operation::JUMP, Operation::LOAD_BOOLEAN, Operation::LOAD_BOOLEAN @@ -1194,7 +1465,7 @@ impl<'src> Compiler<'src> { } let if_block_end = self.instructions.len(); - let mut if_block_distance = (if_block_end - if_block_start) as u8; + let mut if_block_distance = (if_block_end - if_block_start) as u16; let if_block_type = self.get_last_instruction_type(); if let Token::Else = self.current_token { @@ -1216,7 +1487,7 @@ impl<'src> Compiler<'src> { } let else_block_end = self.instructions.len(); - let else_block_distance = (else_block_end - if_block_end) as u8; + let else_block_distance = (else_block_end - if_block_end) as u16; let else_block_type = self.get_last_instruction_type(); if let Err(conflict) = if_block_type.check(&else_block_type) { @@ -1234,13 +1505,10 @@ impl<'src> Compiler<'src> { { let (loader, _, _) = self.instructions.last_mut().unwrap(); - loader.set_c_field(true as u8); + loader.set_c_field(true as u16); } else { if_block_distance += 1; - let jump = Instruction::from(Jump { - offset: else_block_distance, - is_positive: true, - }); + let jump = Instruction::jump(else_block_distance, true); self.instructions .insert(if_block_end, (jump, Type::None, self.current_position)); @@ -1248,10 +1516,7 @@ impl<'src> Compiler<'src> { } 2.. => { if_block_distance += 1; - let jump = Instruction::from(Jump { - offset: else_block_distance, - is_positive: true, - }); + let jump = Instruction::jump(else_block_distance, true); self.instructions .insert(if_block_end, (jump, Type::None, self.current_position)); @@ -1270,14 +1535,29 @@ impl<'src> Compiler<'src> { fn parse_while(&mut self) -> Result<(), CompileError> { self.advance()?; - let expression_start = self.instructions.len() as u8; + let expression_start = self.instructions.len() as u16; self.parse_expression()?; if matches!( self.get_last_operations(), Some([ - Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL, + Operation::EQUAL_INT + | Operation::EQUAL_STR + | Operation::EQUAL_BOOL + | Operation::EQUAL_BYTE + | Operation::EQUAL_CHAR + | Operation::EQUAL_FLOAT + | Operation::LESS_INT + | Operation::LESS_STR + | Operation::LESS_BYTE + | Operation::LESS_CHAR + | Operation::LESS_FLOAT + | Operation::LESS_EQUAL_INT + | Operation::LESS_EQUAL_STR + | Operation::LESS_EQUAL_BYTE + | Operation::LESS_EQUAL_CHAR + | Operation::LESS_EQUAL_FLOAT, Operation::JUMP, Operation::LOAD_BOOLEAN, Operation::LOAD_BOOLEAN @@ -1297,21 +1577,15 @@ impl<'src> Compiler<'src> { self.parse_block()?; - let block_end = self.instructions.len() as u8; - let jump_distance = block_end - block_start as u8 + 1; - let jump = Instruction::from(Jump { - offset: jump_distance, - is_positive: true, - }); + let block_end = self.instructions.len() as u16; + let jump_distance = block_end - block_start as u16 + 1; + let jump = Instruction::jump(jump_distance, true); self.instructions .insert(block_start, (jump, Type::None, self.current_position)); let jump_back_distance = block_end - expression_start + 1; - let jump_back = Instruction::from(Jump { - offset: jump_back_distance, - is_positive: false, - }); + let jump_back = Instruction::jump(jump_back_distance, false); self.emit_instruction(jump_back, Type::None, self.current_position); @@ -1330,13 +1604,9 @@ impl<'src> Compiler<'src> { self.parse_expression()?; let actual_register = self.next_register() - 1; - let registers_to_close = actual_register - expected_register; - if registers_to_close > 0 { - let close = Instruction::from(Close { - from: expected_register, - to: actual_register, - }); + if expected_register < actual_register { + let close = Instruction::close(expected_register, actual_register); self.emit_instruction(close, Type::None, self.current_position); } @@ -1348,11 +1618,7 @@ impl<'src> Compiler<'src> { let destination = self.next_register(); let argument_count = destination - start_register; let return_type = function.r#type().return_type; - let call_native = Instruction::from(CallNative { - destination, - function, - argument_count, - }); + let call_native = Instruction::call_native(destination, function, argument_count); self.emit_instruction(call_native, return_type, Span(start, end)); @@ -1415,10 +1681,7 @@ impl<'src> Compiler<'src> { }; let end = self.current_position.1; let return_register = self.next_register() - 1; - let r#return = Instruction::from(Return { - should_return_value, - return_register, - }); + let r#return = Instruction::r#return(should_return_value, return_register); self.emit_instruction(r#return, Type::None, Span(start, end)); @@ -1433,7 +1696,7 @@ impl<'src> Compiler<'src> { let offset = offset as usize; if is_positive && offset + index == instruction_length - 1 { - *instruction = Instruction::jump((offset + 1) as u8, true); + *instruction = Instruction::jump((offset + 1) as u16, true); } } } @@ -1487,7 +1750,7 @@ impl<'src> Compiler<'src> { let offset = offset as usize; if is_positive && offset + index == instruction_length - 1 { - *instruction = Instruction::jump((offset + 1) as u8, true); + *instruction = Instruction::jump((offset + 1) as u16, true); } } } @@ -1567,9 +1830,9 @@ impl<'src> Compiler<'src> { }); }; - function_compiler.prototype_index = self.prototypes.len() as u8; + function_compiler.prototype_index = self.prototypes.len() as u16; - let mut value_parameters: Vec<(u8, Type)> = Vec::with_capacity(3); + let mut value_parameters: Vec<(u16, Type)> = Vec::with_capacity(3); while !function_compiler.allow(Token::RightParenthesis)? { let is_mutable = function_compiler.allow(Token::Mut)?; @@ -1657,7 +1920,7 @@ impl<'src> Compiler<'src> { ); } - let load_function = Instruction::load_function(destination, prototype_index); + let load_function = Instruction::load_function(destination, prototype_index, false); self.emit_instruction( load_function, @@ -1717,15 +1980,12 @@ impl<'src> Compiler<'src> { let registers_to_close = (actual_register - expected_register).saturating_sub(1); if registers_to_close > 0 { - let close = Instruction::from(Close { - from: expected_register, - to: actual_register, - }); + let close = Instruction::close(expected_register, actual_register); self.emit_instruction(close, Type::None, self.current_position); - } - argument_count += registers_to_close + 1; + argument_count += registers_to_close + 1; + } self.allow(Token::Comma)?; } diff --git a/dust-lang/src/compiler/optimize.rs b/dust-lang/src/compiler/optimize.rs index 83b529c..3d45bad 100644 --- a/dust-lang/src/compiler/optimize.rs +++ b/dust-lang/src/compiler/optimize.rs @@ -26,7 +26,7 @@ use crate::{Compiler, Instruction, Operation}; /// a `POINT` instruction to prevent the VM from encountering an empty register. /// /// The instructions must be in the following order: -/// - `EQUAL` | `LESS` | `LESS_EQUAL` | `TEST` +/// - `TEST` or any of the `EQUAL`, `LESS` or `LESS_EQUAL` instructions /// - `JUMP` /// - `LOAD_BOOLEAN` or `LOAD_CONSTANT` /// - `LOAD_BOOLEAN` or `LOAD_CONSTANT` @@ -37,7 +37,23 @@ pub fn control_flow_register_consolidation(compiler: &mut Compiler) { if !matches!( compiler.get_last_operations(), Some([ - Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL | Operation::TEST, + Operation::TEST + | Operation::EQUAL_INT + | Operation::EQUAL_STR + | Operation::EQUAL_BOOL + | Operation::EQUAL_BYTE + | Operation::EQUAL_CHAR + | Operation::EQUAL_FLOAT + | Operation::LESS_INT + | Operation::LESS_STR + | Operation::LESS_BYTE + | Operation::LESS_CHAR + | Operation::LESS_FLOAT + | Operation::LESS_EQUAL_INT + | Operation::LESS_EQUAL_STR + | Operation::LESS_EQUAL_BYTE + | Operation::LESS_EQUAL_CHAR + | Operation::LESS_EQUAL_FLOAT, Operation::JUMP, Operation::LOAD_BOOLEAN | Operation::LOAD_CONSTANT, Operation::LOAD_BOOLEAN | Operation::LOAD_CONSTANT, diff --git a/dust-lang/src/instruction/add.rs b/dust-lang/src/instruction/add.rs deleted file mode 100644 index d8648c2..0000000 --- a/dust-lang/src/instruction/add.rs +++ /dev/null @@ -1,31 +0,0 @@ -use crate::{Argument, Instruction, Operation}; - -pub struct Add { - pub destination: u8, - pub left: Argument, - pub right: Argument, -} - -impl From for Add { - fn from(instruction: Instruction) -> Self { - let destination = instruction.a_field(); - let (left, right) = instruction.b_and_c_as_arguments(); - - Add { - destination, - left, - right, - } - } -} - -impl From for Instruction { - fn from(add: Add) -> Self { - let operation = Operation::ADD; - let a = add.destination; - let (b, b_is_constant) = add.left.as_index_and_constant_flag(); - let (c, c_is_constant) = add.right.as_index_and_constant_flag(); - - Instruction::new(operation, a, b, c, b_is_constant, c_is_constant, false) - } -} diff --git a/dust-lang/src/instruction/add_byte.rs b/dust-lang/src/instruction/add_byte.rs new file mode 100644 index 0000000..764badd --- /dev/null +++ b/dust-lang/src/instruction/add_byte.rs @@ -0,0 +1,54 @@ +use std::fmt::Display; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct AddByte { + pub destination: u16, + pub left: Operand, + pub right: Operand, +} + +impl From for AddByte { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + AddByte { + destination, + left, + right, + } + } +} + +impl From for Instruction { + fn from(add_byte: AddByte) -> Self { + let operation = Operation::ADD_BYTE; + let a_field = add_byte.destination; + let (b_field, b_is_constant) = add_byte.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = add_byte.right.as_index_and_constant_flag(); + + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for AddByte { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let AddByte { + destination, + left, + right, + } = self; + + write!(f, "R{} = {} + {}", destination, left, right) + } +} diff --git a/dust-lang/src/instruction/add_char.rs b/dust-lang/src/instruction/add_char.rs new file mode 100644 index 0000000..f0260ea --- /dev/null +++ b/dust-lang/src/instruction/add_char.rs @@ -0,0 +1,54 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct AddChar { + pub destination: u16, + pub left: Operand, + pub right: Operand, +} + +impl From for AddChar { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + AddChar { + destination, + left, + right, + } + } +} + +impl From for Instruction { + fn from(add_char: AddChar) -> Self { + let operation = Operation::ADD_CHAR; + let a_field = add_char.destination; + let (b_field, b_is_constant) = add_char.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = add_char.right.as_index_and_constant_flag(); + + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for AddChar { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let AddChar { + destination, + left, + right, + } = self; + + write!(f, "R{} = {} + {}", destination, left, right) + } +} diff --git a/dust-lang/src/instruction/add_char_str.rs b/dust-lang/src/instruction/add_char_str.rs new file mode 100644 index 0000000..4ffe95e --- /dev/null +++ b/dust-lang/src/instruction/add_char_str.rs @@ -0,0 +1,54 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct AddCharStr { + pub destination: u16, + pub left: Operand, + pub right: Operand, +} + +impl From for AddCharStr { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + AddCharStr { + destination, + left, + right, + } + } +} + +impl From for Instruction { + fn from(add_char_str: AddCharStr) -> Self { + let operation = Operation::ADD_CHAR_STR; + let a_field = add_char_str.destination; + let (b_field, b_is_constant) = add_char_str.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = add_char_str.right.as_index_and_constant_flag(); + + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for AddCharStr { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let AddCharStr { + destination, + left, + right, + } = self; + + write!(f, "R{} = {} + {}", destination, left, right) + } +} diff --git a/dust-lang/src/instruction/add_float.rs b/dust-lang/src/instruction/add_float.rs new file mode 100644 index 0000000..a8292f6 --- /dev/null +++ b/dust-lang/src/instruction/add_float.rs @@ -0,0 +1,54 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct AddFloat { + pub destination: u16, + pub left: Operand, + pub right: Operand, +} + +impl From for AddFloat { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + AddFloat { + destination, + left, + right, + } + } +} + +impl From for Instruction { + fn from(add_float: AddFloat) -> Self { + let operation = Operation::ADD_FLOAT; + let a_field = add_float.destination; + let (b_field, b_is_constant) = add_float.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = add_float.right.as_index_and_constant_flag(); + + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for AddFloat { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let AddFloat { + destination, + left, + right, + } = self; + + write!(f, "R{} = {} + {}", destination, left, right) + } +} diff --git a/dust-lang/src/instruction/add_int.rs b/dust-lang/src/instruction/add_int.rs new file mode 100644 index 0000000..21f2bf7 --- /dev/null +++ b/dust-lang/src/instruction/add_int.rs @@ -0,0 +1,56 @@ +use std::fmt::{self, Display, Formatter}; + +use crate::{Instruction, Operand, Operation}; + +use super::InstructionBuilder; + +pub struct AddInt { + pub destination: u16, + pub left: Operand, + pub right: Operand, +} + +impl From for AddInt { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + AddInt { + destination, + left, + right, + } + } +} + +impl From for Instruction { + fn from(add_int: AddInt) -> Self { + let operation = Operation::ADD_INT; + let a_field = add_int.destination; + let (b_field, b_is_constant) = add_int.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = add_int.right.as_index_and_constant_flag(); + + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for AddInt { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let AddInt { + destination, + left, + right, + } = self; + + write!(f, "R{} = {} + {}", destination, left, right) + } +} diff --git a/dust-lang/src/instruction/add_str.rs b/dust-lang/src/instruction/add_str.rs new file mode 100644 index 0000000..a43a3c9 --- /dev/null +++ b/dust-lang/src/instruction/add_str.rs @@ -0,0 +1,54 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct AddStr { + pub destination: u16, + pub left: Operand, + pub right: Operand, +} + +impl From for AddStr { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + AddStr { + destination, + left, + right, + } + } +} + +impl From for Instruction { + fn from(add_str: AddStr) -> Self { + let operation = Operation::ADD_STR; + let a_field = add_str.destination; + let (b_field, b_is_constant) = add_str.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = add_str.right.as_index_and_constant_flag(); + + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for AddStr { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let AddStr { + destination, + left, + right, + } = self; + + write!(f, "R{} = {} + {}", destination, left, right) + } +} diff --git a/dust-lang/src/instruction/add_str_char.rs b/dust-lang/src/instruction/add_str_char.rs new file mode 100644 index 0000000..8638fd8 --- /dev/null +++ b/dust-lang/src/instruction/add_str_char.rs @@ -0,0 +1,54 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct AddStrChar { + pub destination: u16, + pub left: Operand, + pub right: Operand, +} + +impl From for AddStrChar { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + AddStrChar { + destination, + left, + right, + } + } +} + +impl From for Instruction { + fn from(add_str_char: AddStrChar) -> Self { + let operation = Operation::ADD_STR_CHAR; + let a_field = add_str_char.destination; + let (b_field, b_is_constant) = add_str_char.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = add_str_char.right.as_index_and_constant_flag(); + + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for AddStrChar { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let AddStrChar { + destination, + left, + right, + } = self; + + write!(f, "R{} = {} + {}", destination, left, right) + } +} diff --git a/dust-lang/src/instruction/call.rs b/dust-lang/src/instruction/call.rs index dff0679..571bbb8 100644 --- a/dust-lang/src/instruction/call.rs +++ b/dust-lang/src/instruction/call.rs @@ -1,9 +1,11 @@ use crate::{Instruction, Operation}; +use super::InstructionBuilder; + pub struct Call { - pub destination: u8, - pub function_register: u8, - pub argument_count: u8, + pub destination: u16, + pub function_register: u16, + pub argument_count: u16, pub is_recursive: bool, } @@ -25,11 +27,19 @@ impl From for Call { impl From for Instruction { fn from(call: Call) -> Self { - let a = call.destination; - let b = call.function_register; - let c = call.argument_count; - let d = call.is_recursive; + let a_field = call.destination; + let b_field = call.function_register; + let c_field = call.argument_count; + let d_field = call.is_recursive; - Instruction::new(Operation::CALL, a, b, c, false, false, d) + InstructionBuilder { + operation: Operation::CALL, + a_field, + b_field, + c_field, + d_field, + ..Default::default() + } + .build() } } diff --git a/dust-lang/src/instruction/call_native.rs b/dust-lang/src/instruction/call_native.rs index d44a637..c40733a 100644 --- a/dust-lang/src/instruction/call_native.rs +++ b/dust-lang/src/instruction/call_native.rs @@ -1,9 +1,11 @@ use crate::{Instruction, NativeFunction, Operation}; +use super::InstructionBuilder; + pub struct CallNative { - pub destination: u8, + pub destination: u16, pub function: NativeFunction, - pub argument_count: u8, + pub argument_count: u16, } impl From for CallNative { @@ -22,10 +24,17 @@ impl From for CallNative { impl From for Instruction { fn from(call_native: CallNative) -> Self { let operation = Operation::CALL_NATIVE; - let a = call_native.destination; - let b = call_native.function as u8; - let c = call_native.argument_count; + let a_field = call_native.destination; + let b_field = call_native.function as u16; + let c_field = call_native.argument_count; - Instruction::new(operation, a, b, c, false, false, false) + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + ..Default::default() + } + .build() } } diff --git a/dust-lang/src/instruction/close.rs b/dust-lang/src/instruction/close.rs index 304d88c..9174438 100644 --- a/dust-lang/src/instruction/close.rs +++ b/dust-lang/src/instruction/close.rs @@ -1,8 +1,12 @@ +use std::fmt::{self, Display, Formatter}; + use crate::{Instruction, Operation}; +use super::InstructionBuilder; + pub struct Close { - pub from: u8, - pub to: u8, + pub from: u16, + pub to: u16, } impl From for Close { @@ -17,8 +21,23 @@ impl From for Close { impl From for Instruction { fn from(close: Close) -> Self { let operation = Operation::CLOSE; - let (a, b, c) = (0, close.from, close.to); + let b_field = close.from; + let c_field = close.to; - Instruction::new(operation, a, b, c, false, false, false) + InstructionBuilder { + operation, + b_field, + c_field, + ..Default::default() + } + .build() + } +} + +impl Display for Close { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let Close { from, to } = self; + + write!(f, "{from}..={to}") } } diff --git a/dust-lang/src/instruction/divide.rs b/dust-lang/src/instruction/divide.rs deleted file mode 100644 index 55a3263..0000000 --- a/dust-lang/src/instruction/divide.rs +++ /dev/null @@ -1,31 +0,0 @@ -use crate::{Argument, Instruction, Operation}; - -pub struct Divide { - pub destination: u8, - pub left: Argument, - pub right: Argument, -} - -impl From for Divide { - fn from(instruction: Instruction) -> Self { - let destination = instruction.a_field(); - let (left, right) = instruction.b_and_c_as_arguments(); - - Divide { - destination, - left, - right, - } - } -} - -impl From for Instruction { - fn from(divide: Divide) -> Self { - let operation = Operation::DIVIDE; - let a = divide.destination; - let (b, b_is_constant) = divide.left.as_index_and_constant_flag(); - let (c, c_is_constant) = divide.right.as_index_and_constant_flag(); - - Instruction::new(operation, a, b, c, b_is_constant, c_is_constant, false) - } -} diff --git a/dust-lang/src/instruction/divide_byte.rs b/dust-lang/src/instruction/divide_byte.rs new file mode 100644 index 0000000..ce2a4c4 --- /dev/null +++ b/dust-lang/src/instruction/divide_byte.rs @@ -0,0 +1,54 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct DivideByte { + pub destination: u16, + pub left: Operand, + pub right: Operand, +} + +impl From for DivideByte { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + DivideByte { + destination, + left, + right, + } + } +} + +impl From for Instruction { + fn from(divide_byte: DivideByte) -> Self { + let operation = Operation::DIVIDE_BYTE; + let a_field = divide_byte.destination; + let (b_field, b_is_constant) = divide_byte.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = divide_byte.right.as_index_and_constant_flag(); + + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for DivideByte { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let DivideByte { + destination, + left, + right, + } = self; + + write!(f, "R{} = {} ÷ {}", destination, left, right) + } +} diff --git a/dust-lang/src/instruction/divide_float.rs b/dust-lang/src/instruction/divide_float.rs new file mode 100644 index 0000000..aaaef22 --- /dev/null +++ b/dust-lang/src/instruction/divide_float.rs @@ -0,0 +1,54 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct DivideFloat { + pub destination: u16, + pub left: Operand, + pub right: Operand, +} + +impl From for DivideFloat { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + DivideFloat { + destination, + left, + right, + } + } +} + +impl From for Instruction { + fn from(divide_float: DivideFloat) -> Self { + let operation = Operation::DIVIDE_FLOAT; + let a_field = divide_float.destination; + let (b_field, b_is_constant) = divide_float.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = divide_float.right.as_index_and_constant_flag(); + + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for DivideFloat { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let DivideFloat { + destination, + left, + right, + } = self; + + write!(f, "R{} = {} ÷ {}", destination, left, right) + } +} diff --git a/dust-lang/src/instruction/divide_int.rs b/dust-lang/src/instruction/divide_int.rs new file mode 100644 index 0000000..b52ced0 --- /dev/null +++ b/dust-lang/src/instruction/divide_int.rs @@ -0,0 +1,54 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct DivideInt { + pub destination: u16, + pub left: Operand, + pub right: Operand, +} + +impl From for DivideInt { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + DivideInt { + destination, + left, + right, + } + } +} + +impl From for Instruction { + fn from(divide_int: DivideInt) -> Self { + let operation = Operation::DIVIDE_INT; + let a_field = divide_int.destination; + let (b_field, b_is_constant) = divide_int.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = divide_int.right.as_index_and_constant_flag(); + + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for DivideInt { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let DivideInt { + destination, + left, + right, + } = self; + + write!(f, "R{} = {} ÷ {}", destination, left, right) + } +} diff --git a/dust-lang/src/instruction/equal.rs b/dust-lang/src/instruction/equal.rs deleted file mode 100644 index 3b42c2e..0000000 --- a/dust-lang/src/instruction/equal.rs +++ /dev/null @@ -1,27 +0,0 @@ -use crate::{Argument, Instruction, Operation}; - -pub struct Equal { - pub value: bool, - pub left: Argument, - pub right: Argument, -} - -impl From for Equal { - fn from(instruction: Instruction) -> Self { - let value = instruction.d_field(); - let (left, right) = instruction.b_and_c_as_arguments(); - - Equal { value, left, right } - } -} - -impl From for Instruction { - fn from(equal: Equal) -> Self { - let operation = Operation::EQUAL; - let (b, b_is_constant) = equal.left.as_index_and_constant_flag(); - let (c, c_is_constant) = equal.right.as_index_and_constant_flag(); - let d = equal.value; - - Instruction::new(operation, 0, b, c, b_is_constant, c_is_constant, d) - } -} diff --git a/dust-lang/src/instruction/equal_bool.rs b/dust-lang/src/instruction/equal_bool.rs new file mode 100644 index 0000000..03a0997 --- /dev/null +++ b/dust-lang/src/instruction/equal_bool.rs @@ -0,0 +1,55 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct EqualBool { + pub comparator: bool, + pub left: Operand, + pub right: Operand, +} + +impl From for EqualBool { + fn from(instruction: Instruction) -> Self { + let comparator = instruction.d_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + EqualBool { + comparator, + left, + right, + } + } +} + +impl From for Instruction { + fn from(equal_bool: EqualBool) -> Self { + let operation = Operation::EQUAL_BOOL; + let (b_field, b_is_constant) = equal_bool.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = equal_bool.right.as_index_and_constant_flag(); + let d_field = equal_bool.comparator; + + InstructionBuilder { + operation, + b_field, + c_field, + d_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for EqualBool { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let EqualBool { + comparator, + left, + right, + } = self; + let operator = if *comparator { "==" } else { "≠" }; + + write!(f, "if {left} {operator} {right} {{ JUMP +1 }}") + } +} diff --git a/dust-lang/src/instruction/equal_byte.rs b/dust-lang/src/instruction/equal_byte.rs new file mode 100644 index 0000000..3be0ddb --- /dev/null +++ b/dust-lang/src/instruction/equal_byte.rs @@ -0,0 +1,55 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct EqualByte { + pub comparator: bool, + pub left: Operand, + pub right: Operand, +} + +impl From for EqualByte { + fn from(instruction: Instruction) -> Self { + let comparator = instruction.d_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + EqualByte { + comparator, + left, + right, + } + } +} + +impl From for Instruction { + fn from(equal_byte: EqualByte) -> Self { + let operation = Operation::EQUAL_BYTE; + let (b_field, b_is_constant) = equal_byte.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = equal_byte.right.as_index_and_constant_flag(); + let d_field = equal_byte.comparator; + + InstructionBuilder { + operation, + b_field, + c_field, + d_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for EqualByte { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let EqualByte { + comparator, + left, + right, + } = self; + let operator = if *comparator { "==" } else { "≠" }; + + write!(f, "if {left} {operator} {right} {{ JUMP +1 }}") + } +} diff --git a/dust-lang/src/instruction/equal_char.rs b/dust-lang/src/instruction/equal_char.rs new file mode 100644 index 0000000..4e60a77 --- /dev/null +++ b/dust-lang/src/instruction/equal_char.rs @@ -0,0 +1,55 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct EqualChar { + pub comparator: bool, + pub left: Operand, + pub right: Operand, +} + +impl From for EqualChar { + fn from(instruction: Instruction) -> Self { + let comparator = instruction.d_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + EqualChar { + comparator, + left, + right, + } + } +} + +impl From for Instruction { + fn from(equal_char: EqualChar) -> Self { + let operation = Operation::EQUAL_CHAR; + let (b_field, b_is_constant) = equal_char.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = equal_char.right.as_index_and_constant_flag(); + let d_field = equal_char.comparator; + + InstructionBuilder { + operation, + b_field, + c_field, + d_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for EqualChar { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let EqualChar { + comparator, + left, + right, + } = self; + let operator = if *comparator { "==" } else { "≠" }; + + write!(f, "if {left} {operator} {right} {{ JUMP +1 }}") + } +} diff --git a/dust-lang/src/instruction/equal_char_str.rs b/dust-lang/src/instruction/equal_char_str.rs new file mode 100644 index 0000000..eb15ae4 --- /dev/null +++ b/dust-lang/src/instruction/equal_char_str.rs @@ -0,0 +1,55 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct EqualCharStr { + pub comparator: bool, + pub left: Operand, + pub right: Operand, +} + +impl From for EqualCharStr { + fn from(instruction: Instruction) -> Self { + let comparator = instruction.d_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + EqualCharStr { + comparator, + left, + right, + } + } +} + +impl From for Instruction { + fn from(equal_char_str: EqualCharStr) -> Self { + let operation = Operation::EQUAL_CHAR_STR; + let (b_field, b_is_constant) = equal_char_str.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = equal_char_str.right.as_index_and_constant_flag(); + let d_field = equal_char_str.comparator; + + InstructionBuilder { + operation, + b_field, + c_field, + d_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for EqualCharStr { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let EqualCharStr { + comparator, + left, + right, + } = self; + let operator = if *comparator { "==" } else { "≠" }; + + write!(f, "if {left} {operator} {right} {{ JUMP +1 }}") + } +} diff --git a/dust-lang/src/instruction/equal_float.rs b/dust-lang/src/instruction/equal_float.rs new file mode 100644 index 0000000..6149c2c --- /dev/null +++ b/dust-lang/src/instruction/equal_float.rs @@ -0,0 +1,55 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct EqualFloat { + pub comparator: bool, + pub left: Operand, + pub right: Operand, +} + +impl From for EqualFloat { + fn from(instruction: Instruction) -> Self { + let comparator = instruction.d_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + EqualFloat { + comparator, + left, + right, + } + } +} + +impl From for Instruction { + fn from(equal_float: EqualFloat) -> Self { + let operation = Operation::EQUAL_FLOAT; + let (b_field, b_is_constant) = equal_float.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = equal_float.right.as_index_and_constant_flag(); + let d_field = equal_float.comparator; + + InstructionBuilder { + operation, + b_field, + c_field, + d_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for EqualFloat { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let EqualFloat { + comparator, + left, + right, + } = self; + let operator = if *comparator { "==" } else { "≠" }; + + write!(f, "if {left} {operator} {right} {{ JUMP +1 }}") + } +} diff --git a/dust-lang/src/instruction/equal_int.rs b/dust-lang/src/instruction/equal_int.rs new file mode 100644 index 0000000..cebc38d --- /dev/null +++ b/dust-lang/src/instruction/equal_int.rs @@ -0,0 +1,55 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct EqualInt { + pub comparator: bool, + pub left: Operand, + pub right: Operand, +} + +impl From for EqualInt { + fn from(instruction: Instruction) -> Self { + let comparator = instruction.d_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + EqualInt { + comparator, + left, + right, + } + } +} + +impl From for Instruction { + fn from(equal_int: EqualInt) -> Self { + let operation = Operation::EQUAL_INT; + let (b_field, b_is_constant) = equal_int.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = equal_int.right.as_index_and_constant_flag(); + let d_field = equal_int.comparator; + + InstructionBuilder { + operation, + b_field, + c_field, + d_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for EqualInt { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let EqualInt { + comparator, + left, + right, + } = self; + let operator = if *comparator { "==" } else { "≠" }; + + write!(f, "if {left} {operator} {right} {{ JUMP +1 }}") + } +} diff --git a/dust-lang/src/instruction/equal_str.rs b/dust-lang/src/instruction/equal_str.rs new file mode 100644 index 0000000..f4cc0c4 --- /dev/null +++ b/dust-lang/src/instruction/equal_str.rs @@ -0,0 +1,55 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct EqualStr { + pub comparator: bool, + pub left: Operand, + pub right: Operand, +} + +impl From for EqualStr { + fn from(instruction: Instruction) -> Self { + let comparator = instruction.d_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + EqualStr { + comparator, + left, + right, + } + } +} + +impl From for Instruction { + fn from(equal_str: EqualStr) -> Self { + let operation = Operation::EQUAL_STR; + let (b_field, b_is_constant) = equal_str.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = equal_str.right.as_index_and_constant_flag(); + let d_field = equal_str.comparator; + + InstructionBuilder { + operation, + b_field, + c_field, + d_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for EqualStr { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let EqualStr { + comparator, + left, + right, + } = self; + let operator = if *comparator { "==" } else { "≠" }; + + write!(f, "if {left} {operator} {right} {{ JUMP +1 }}") + } +} diff --git a/dust-lang/src/instruction/equal_str_char.rs b/dust-lang/src/instruction/equal_str_char.rs new file mode 100644 index 0000000..ccd0dd4 --- /dev/null +++ b/dust-lang/src/instruction/equal_str_char.rs @@ -0,0 +1,55 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct EqualStrChar { + pub comparator: bool, + pub left: Operand, + pub right: Operand, +} + +impl From for EqualStrChar { + fn from(instruction: Instruction) -> Self { + let comparator = instruction.d_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + EqualStrChar { + comparator, + left, + right, + } + } +} + +impl From for Instruction { + fn from(equal_str_char: EqualStrChar) -> Self { + let operation = Operation::EQUAL_STR_CHAR; + let (b_field, b_is_constant) = equal_str_char.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = equal_str_char.right.as_index_and_constant_flag(); + let d_field = equal_str_char.comparator; + + InstructionBuilder { + operation, + b_field, + c_field, + d_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for EqualStrChar { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let EqualStrChar { + comparator, + left, + right, + } = self; + let operator = if *comparator { "==" } else { "≠" }; + + write!(f, "if {left} {operator} {right} {{ JUMP +1 }}") + } +} diff --git a/dust-lang/src/instruction/get_local.rs b/dust-lang/src/instruction/get_local.rs index ec8be9d..8aba567 100644 --- a/dust-lang/src/instruction/get_local.rs +++ b/dust-lang/src/instruction/get_local.rs @@ -1,8 +1,12 @@ +use std::fmt::{self, Display, Formatter}; + use crate::{Instruction, Operation}; +use super::InstructionBuilder; + pub struct GetLocal { - pub destination: u8, - pub local_index: u8, + pub destination: u16, + pub local_index: u16, } impl From for GetLocal { @@ -20,9 +24,26 @@ impl From for GetLocal { impl From for Instruction { fn from(get_local: GetLocal) -> Self { let operation = Operation::GET_LOCAL; - let a = get_local.destination; - let b = get_local.local_index; + let a_field = get_local.destination; + let b_field = get_local.local_index; - Instruction::new(operation, a, b, 0, false, false, false) + InstructionBuilder { + operation, + a_field, + b_field, + ..Default::default() + } + .build() + } +} + +impl Display for GetLocal { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let GetLocal { + destination, + local_index, + } = self; + + write!(f, "R{destination} = L{local_index}") } } diff --git a/dust-lang/src/instruction/jump.rs b/dust-lang/src/instruction/jump.rs index 8a4c150..cf55b7c 100644 --- a/dust-lang/src/instruction/jump.rs +++ b/dust-lang/src/instruction/jump.rs @@ -1,7 +1,9 @@ use crate::{Instruction, Operation}; +use super::InstructionBuilder; + pub struct Jump { - pub offset: u8, + pub offset: u16, pub is_positive: bool, } @@ -17,9 +19,15 @@ impl From for Jump { impl From for Instruction { fn from(jump: Jump) -> Self { let operation = Operation::JUMP; - let b = jump.offset; - let c = jump.is_positive as u8; + let b_field = jump.offset; + let c_field = jump.is_positive as u16; - Instruction::new(operation, 0, b, c, false, false, false) + InstructionBuilder { + operation, + b_field, + c_field, + ..Default::default() + } + .build() } } diff --git a/dust-lang/src/instruction/less.rs b/dust-lang/src/instruction/less.rs deleted file mode 100644 index f8a868e..0000000 --- a/dust-lang/src/instruction/less.rs +++ /dev/null @@ -1,27 +0,0 @@ -use crate::{Argument, Instruction, Operation}; - -pub struct Less { - pub value: bool, - pub left: Argument, - pub right: Argument, -} - -impl From for Less { - fn from(instruction: Instruction) -> Self { - let value = instruction.d_field(); - let (left, right) = instruction.b_and_c_as_arguments(); - - Less { value, left, right } - } -} - -impl From for Instruction { - fn from(less: Less) -> Self { - let operation = Operation::LESS; - let (b, b_is_constant) = less.left.as_index_and_constant_flag(); - let (c, c_is_constant) = less.right.as_index_and_constant_flag(); - let d = less.value; - - Instruction::new(operation, 0, b, c, b_is_constant, c_is_constant, d) - } -} diff --git a/dust-lang/src/instruction/less_byte.rs b/dust-lang/src/instruction/less_byte.rs new file mode 100644 index 0000000..7b657f0 --- /dev/null +++ b/dust-lang/src/instruction/less_byte.rs @@ -0,0 +1,55 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct LessByte { + pub comparator: bool, + pub left: Operand, + pub right: Operand, +} + +impl From for LessByte { + fn from(instruction: Instruction) -> Self { + let comparator = instruction.d_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + LessByte { + comparator, + left, + right, + } + } +} + +impl From for Instruction { + fn from(less_byte: LessByte) -> Self { + let operation = Operation::LESS_BYTE; + let (b_field, b_is_constant) = less_byte.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = less_byte.right.as_index_and_constant_flag(); + let d_field = less_byte.comparator; + + InstructionBuilder { + operation, + b_field, + c_field, + d_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for LessByte { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let LessByte { + comparator, + left, + right, + } = self; + let operator = if *comparator { "<" } else { "≥" }; + + write!(f, "if {left} {operator} {right} {{ JUMP +1 }}") + } +} diff --git a/dust-lang/src/instruction/less_char.rs b/dust-lang/src/instruction/less_char.rs new file mode 100644 index 0000000..0f26ccf --- /dev/null +++ b/dust-lang/src/instruction/less_char.rs @@ -0,0 +1,55 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct LessChar { + pub comparator: bool, + pub left: Operand, + pub right: Operand, +} + +impl From for LessChar { + fn from(instruction: Instruction) -> Self { + let comparator = instruction.d_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + LessChar { + comparator, + left, + right, + } + } +} + +impl From for Instruction { + fn from(less_char: LessChar) -> Self { + let operation = Operation::LESS_CHAR; + let (b_field, b_is_constant) = less_char.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = less_char.right.as_index_and_constant_flag(); + let d_field = less_char.comparator; + + InstructionBuilder { + operation, + b_field, + c_field, + d_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for LessChar { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let LessChar { + comparator, + left, + right, + } = self; + let operator = if *comparator { "<" } else { "≥" }; + + write!(f, "if {left} {operator} {right} {{ JUMP +1 }}") + } +} diff --git a/dust-lang/src/instruction/less_equal.rs b/dust-lang/src/instruction/less_equal.rs deleted file mode 100644 index 6707804..0000000 --- a/dust-lang/src/instruction/less_equal.rs +++ /dev/null @@ -1,27 +0,0 @@ -use crate::{Argument, Instruction, Operation}; - -pub struct LessEqual { - pub value: bool, - pub left: Argument, - pub right: Argument, -} - -impl From for LessEqual { - fn from(instruction: Instruction) -> Self { - let value = instruction.d_field(); - let (left, right) = instruction.b_and_c_as_arguments(); - - LessEqual { value, left, right } - } -} - -impl From for Instruction { - fn from(less_equal: LessEqual) -> Self { - let operation = Operation::LESS_EQUAL; - let (b, b_options) = less_equal.left.as_index_and_constant_flag(); - let (c, c_options) = less_equal.right.as_index_and_constant_flag(); - let d = less_equal.value; - - Instruction::new(operation, 0, b, c, b_options, c_options, d) - } -} diff --git a/dust-lang/src/instruction/less_equal_byte.rs b/dust-lang/src/instruction/less_equal_byte.rs new file mode 100644 index 0000000..08b1cac --- /dev/null +++ b/dust-lang/src/instruction/less_equal_byte.rs @@ -0,0 +1,55 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct LessEqualByte { + pub comparator: bool, + pub left: Operand, + pub right: Operand, +} + +impl From for LessEqualByte { + fn from(instruction: Instruction) -> Self { + let comparator = instruction.d_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + LessEqualByte { + comparator, + left, + right, + } + } +} + +impl From for Instruction { + fn from(less_equal_byte: LessEqualByte) -> Self { + let operation = Operation::LESS_EQUAL_BYTE; + let (b_field, b_is_constant) = less_equal_byte.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = less_equal_byte.right.as_index_and_constant_flag(); + let d_field = less_equal_byte.comparator; + + InstructionBuilder { + operation, + b_field, + c_field, + d_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for LessEqualByte { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let LessEqualByte { + comparator, + left, + right, + } = self; + let operator = if *comparator { "≤" } else { ">" }; + + write!(f, "if {left} {operator} {right} {{ JUMP +1 }}") + } +} diff --git a/dust-lang/src/instruction/less_equal_char.rs b/dust-lang/src/instruction/less_equal_char.rs new file mode 100644 index 0000000..bd0777e --- /dev/null +++ b/dust-lang/src/instruction/less_equal_char.rs @@ -0,0 +1,55 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct LessEqualChar { + pub comparator: bool, + pub left: Operand, + pub right: Operand, +} + +impl From for LessEqualChar { + fn from(instruction: Instruction) -> Self { + let comparator = instruction.d_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + LessEqualChar { + comparator, + left, + right, + } + } +} + +impl From for Instruction { + fn from(less_equal_char: LessEqualChar) -> Self { + let operation = Operation::LESS_EQUAL_CHAR; + let (b_field, b_is_constant) = less_equal_char.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = less_equal_char.right.as_index_and_constant_flag(); + let d_field = less_equal_char.comparator; + + InstructionBuilder { + operation, + b_field, + c_field, + d_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for LessEqualChar { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let LessEqualChar { + comparator, + left, + right, + } = self; + let operator = if *comparator { "≤" } else { ">" }; + + write!(f, "if {left} {operator} {right} {{ JUMP +1 }}") + } +} diff --git a/dust-lang/src/instruction/less_equal_float.rs b/dust-lang/src/instruction/less_equal_float.rs new file mode 100644 index 0000000..f552f0b --- /dev/null +++ b/dust-lang/src/instruction/less_equal_float.rs @@ -0,0 +1,55 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct LessEqualFloat { + pub comparator: bool, + pub left: Operand, + pub right: Operand, +} + +impl From for LessEqualFloat { + fn from(instruction: Instruction) -> Self { + let comparator = instruction.d_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + LessEqualFloat { + comparator, + left, + right, + } + } +} + +impl From for Instruction { + fn from(less_equal_float: LessEqualFloat) -> Self { + let operation = Operation::LESS_EQUAL_FLOAT; + let (b_field, b_is_constant) = less_equal_float.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = less_equal_float.right.as_index_and_constant_flag(); + let d_field = less_equal_float.comparator; + + InstructionBuilder { + operation, + b_field, + c_field, + d_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for LessEqualFloat { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let LessEqualFloat { + comparator, + left, + right, + } = self; + let operator = if *comparator { "≤" } else { ">" }; + + write!(f, "if {left} {operator} {right} {{ JUMP +1 }}") + } +} diff --git a/dust-lang/src/instruction/less_equal_int.rs b/dust-lang/src/instruction/less_equal_int.rs new file mode 100644 index 0000000..ede40c8 --- /dev/null +++ b/dust-lang/src/instruction/less_equal_int.rs @@ -0,0 +1,55 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct LessEqualInt { + pub comparator: bool, + pub left: Operand, + pub right: Operand, +} + +impl From for LessEqualInt { + fn from(instruction: Instruction) -> Self { + let comparator = instruction.d_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + LessEqualInt { + comparator, + left, + right, + } + } +} + +impl From for Instruction { + fn from(less_equal_int: LessEqualInt) -> Self { + let operation = Operation::LESS_EQUAL_INT; + let (b_field, b_is_constant) = less_equal_int.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = less_equal_int.right.as_index_and_constant_flag(); + let d_field = less_equal_int.comparator; + + InstructionBuilder { + operation, + b_field, + c_field, + d_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for LessEqualInt { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let LessEqualInt { + comparator, + left, + right, + } = self; + let operator = if *comparator { "≤" } else { ">" }; + + write!(f, "if {left} {operator} {right} {{ JUMP +1 }}") + } +} diff --git a/dust-lang/src/instruction/less_equal_str.rs b/dust-lang/src/instruction/less_equal_str.rs new file mode 100644 index 0000000..4b8ae2b --- /dev/null +++ b/dust-lang/src/instruction/less_equal_str.rs @@ -0,0 +1,55 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct LessEqualStr { + pub comparator: bool, + pub left: Operand, + pub right: Operand, +} + +impl From for LessEqualStr { + fn from(instruction: Instruction) -> Self { + let comparator = instruction.d_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + LessEqualStr { + comparator, + left, + right, + } + } +} + +impl From for Instruction { + fn from(less_equal_str: LessEqualStr) -> Self { + let operation = Operation::LESS_EQUAL_STR; + let (b_field, b_is_constant) = less_equal_str.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = less_equal_str.right.as_index_and_constant_flag(); + let d_field = less_equal_str.comparator; + + InstructionBuilder { + operation, + b_field, + c_field, + d_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for LessEqualStr { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let LessEqualStr { + comparator, + left, + right, + } = self; + let operator = if *comparator { "≤" } else { ">" }; + + write!(f, "if {left} {operator} {right} {{ JUMP +1 }}") + } +} diff --git a/dust-lang/src/instruction/less_float.rs b/dust-lang/src/instruction/less_float.rs new file mode 100644 index 0000000..a5722fa --- /dev/null +++ b/dust-lang/src/instruction/less_float.rs @@ -0,0 +1,55 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct LessFloat { + pub comparator: bool, + pub left: Operand, + pub right: Operand, +} + +impl From for LessFloat { + fn from(instruction: Instruction) -> Self { + let comparator = instruction.d_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + LessFloat { + comparator, + left, + right, + } + } +} + +impl From for Instruction { + fn from(less_float: LessFloat) -> Self { + let operation = Operation::LESS_FLOAT; + let (b_field, b_is_constant) = less_float.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = less_float.right.as_index_and_constant_flag(); + let d_field = less_float.comparator; + + InstructionBuilder { + operation, + b_field, + c_field, + d_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for LessFloat { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let LessFloat { + comparator, + left, + right, + } = self; + let operator = if *comparator { "<" } else { "≥" }; + + write!(f, "if {left} {operator} {right} {{ JUMP +1 }}") + } +} diff --git a/dust-lang/src/instruction/less_int.rs b/dust-lang/src/instruction/less_int.rs new file mode 100644 index 0000000..c693d94 --- /dev/null +++ b/dust-lang/src/instruction/less_int.rs @@ -0,0 +1,55 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct LessInt { + pub comparator: bool, + pub left: Operand, + pub right: Operand, +} + +impl From for LessInt { + fn from(instruction: Instruction) -> Self { + let comparator = instruction.d_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + LessInt { + comparator, + left, + right, + } + } +} + +impl From for Instruction { + fn from(less_int: LessInt) -> Self { + let operation = Operation::LESS_INT; + let (b_field, b_is_constant) = less_int.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = less_int.right.as_index_and_constant_flag(); + let d_field = less_int.comparator; + + InstructionBuilder { + operation, + b_field, + c_field, + d_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for LessInt { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let LessInt { + comparator, + left, + right, + } = self; + let operator = if *comparator { "<" } else { "≥" }; + + write!(f, "if {left} {operator} {right} {{ JUMP +1 }}") + } +} diff --git a/dust-lang/src/instruction/less_str.rs b/dust-lang/src/instruction/less_str.rs new file mode 100644 index 0000000..c26b494 --- /dev/null +++ b/dust-lang/src/instruction/less_str.rs @@ -0,0 +1,55 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct LessStr { + pub comparator: bool, + pub left: Operand, + pub right: Operand, +} + +impl From for LessStr { + fn from(instruction: Instruction) -> Self { + let comparator = instruction.d_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + LessStr { + comparator, + left, + right, + } + } +} + +impl From for Instruction { + fn from(less_str: LessStr) -> Self { + let operation = Operation::LESS_STR; + let (b_field, b_is_constant) = less_str.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = less_str.right.as_index_and_constant_flag(); + let d_field = less_str.comparator; + + InstructionBuilder { + operation, + b_field, + c_field, + d_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for LessStr { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let LessStr { + comparator, + left, + right, + } = self; + let operator = if *comparator { "<" } else { "≥" }; + + write!(f, "if {left} {operator} {right} {{ JUMP +1 }}") + } +} diff --git a/dust-lang/src/instruction/load_boolean.rs b/dust-lang/src/instruction/load_boolean.rs index 9742d70..f14ff3c 100644 --- a/dust-lang/src/instruction/load_boolean.rs +++ b/dust-lang/src/instruction/load_boolean.rs @@ -1,7 +1,11 @@ +use std::fmt::{self, Display, Formatter}; + use crate::{Instruction, Operation}; +use super::InstructionBuilder; + pub struct LoadBoolean { - pub destination: u8, + pub destination: u16, pub value: bool, pub jump_next: bool, } @@ -19,10 +23,35 @@ impl From for LoadBoolean { impl From for Instruction { fn from(load_boolean: LoadBoolean) -> Self { let operation = Operation::LOAD_BOOLEAN; - let a = load_boolean.destination; - let b = load_boolean.value as u8; - let c = load_boolean.jump_next as u8; + let a_field = load_boolean.destination; + let b_field = load_boolean.value as u16; + let c_field = load_boolean.jump_next as u16; - Instruction::new(operation, a, b, c, false, false, false) + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + ..Default::default() + } + .build() + } +} + +impl Display for LoadBoolean { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let LoadBoolean { + destination, + value, + jump_next, + } = self; + + write!(f, "R{destination} = {value}")?; + + if *jump_next { + write!(f, " JUMP +1")?; + } + + Ok(()) } } diff --git a/dust-lang/src/instruction/load_constant.rs b/dust-lang/src/instruction/load_constant.rs index 2940a6c..f26b4c2 100644 --- a/dust-lang/src/instruction/load_constant.rs +++ b/dust-lang/src/instruction/load_constant.rs @@ -2,9 +2,11 @@ use std::fmt::{self, Display, Formatter}; use crate::{Instruction, Operation}; +use super::InstructionBuilder; + pub struct LoadConstant { - pub destination: u8, - pub constant_index: u8, + pub destination: u16, + pub constant_index: u16, pub jump_next: bool, } @@ -24,12 +26,14 @@ impl From for LoadConstant { impl From for Instruction { fn from(load_constant: LoadConstant) -> Self { - let operation = Operation::LOAD_CONSTANT; - let a = load_constant.destination; - let b = load_constant.constant_index; - let c = load_constant.jump_next as u8; - - Instruction::new(operation, a, b, c, false, false, false) + InstructionBuilder { + operation: Operation::LOAD_CONSTANT, + a_field: load_constant.destination, + b_field: load_constant.constant_index, + c_field: load_constant.jump_next as u16, + ..Default::default() + } + .build() } } @@ -41,12 +45,12 @@ impl Display for LoadConstant { jump_next, } = self; - write!(f, "R{destination} = Constant {constant_index}")?; + write!(f, "R{destination} = C{constant_index}")?; if *jump_next { - write!(f, " JUMP +1") - } else { - Ok(()) + write!(f, " JUMP +1")?; } + + Ok(()) } } diff --git a/dust-lang/src/instruction/load_function.rs b/dust-lang/src/instruction/load_function.rs index d1ec669..1692e02 100644 --- a/dust-lang/src/instruction/load_function.rs +++ b/dust-lang/src/instruction/load_function.rs @@ -1,40 +1,54 @@ use std::fmt::{self, Display, Formatter}; -use super::{Instruction, Operation}; +use super::{Instruction, InstructionBuilder, Operation}; pub struct LoadFunction { - pub destination: u8, - pub prototype_index: u8, + pub destination: u16, + pub prototype_index: u16, + pub jump_next: bool, } impl From for LoadFunction { fn from(instruction: Instruction) -> Self { let destination = instruction.a_field(); - let record_index = instruction.b_field(); + let prototype_index = instruction.b_field(); + let jump_next = instruction.c_field() != 0; LoadFunction { destination, - prototype_index: record_index, + prototype_index, + jump_next, } } } impl From for Instruction { fn from(load_function: LoadFunction) -> Self { - Instruction::new( - Operation::LOAD_FUNCTION, - load_function.destination, - load_function.prototype_index, - 0, - false, - false, - false, - ) + InstructionBuilder { + operation: Operation::LOAD_FUNCTION, + a_field: load_function.destination, + b_field: load_function.prototype_index, + c_field: load_function.jump_next as u16, + ..Default::default() + } + .build() } } impl Display for LoadFunction { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "R{} = F{}", self.destination, self.prototype_index) + let LoadFunction { + destination, + prototype_index, + jump_next, + } = self; + + write!(f, "R{destination} = P{prototype_index}")?; + + if *jump_next { + write!(f, " JUMP +1")?; + } + + Ok(()) } } diff --git a/dust-lang/src/instruction/load_list.rs b/dust-lang/src/instruction/load_list.rs index 2812cb4..d891ec5 100644 --- a/dust-lang/src/instruction/load_list.rs +++ b/dust-lang/src/instruction/load_list.rs @@ -1,28 +1,56 @@ +use std::fmt::{self, Display, Formatter}; + use crate::{Instruction, Operation}; +use super::InstructionBuilder; + pub struct LoadList { - pub destination: u8, - pub start_register: u8, + pub destination: u16, + pub start_register: u16, + pub jump_next: bool, } impl From for LoadList { fn from(instruction: Instruction) -> Self { let destination = instruction.a_field(); let start_register = instruction.b_field(); + let jump_next = instruction.c_field() != 0; LoadList { destination, start_register, + jump_next, } } } impl From for Instruction { fn from(load_list: LoadList) -> Self { - let operation = Operation::LOAD_LIST; - let a = load_list.destination; - let b = load_list.start_register; - - Instruction::new(operation, a, b, 0, false, false, false) + InstructionBuilder { + operation: Operation::LOAD_LIST, + a_field: load_list.destination, + b_field: load_list.start_register, + c_field: load_list.jump_next as u16, + ..Default::default() + } + .build() + } +} + +impl Display for LoadList { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let LoadList { + destination, + start_register, + jump_next, + } = self; + + write!(f, "R{destination} = [R{start_register}..R{destination}]")?; + + if *jump_next { + write!(f, " JUMP +1")?; + } + + Ok(()) } } diff --git a/dust-lang/src/instruction/load_self.rs b/dust-lang/src/instruction/load_self.rs index 9e5b999..1cb10e2 100644 --- a/dust-lang/src/instruction/load_self.rs +++ b/dust-lang/src/instruction/load_self.rs @@ -1,22 +1,51 @@ +use std::fmt::{self, Display, Formatter}; + use crate::{Instruction, Operation}; +use super::InstructionBuilder; + pub struct LoadSelf { - pub destination: u8, + pub destination: u16, + pub jump_next: bool, } impl From for LoadSelf { fn from(instruction: Instruction) -> Self { let destination = instruction.a_field(); + let jump_next = instruction.c_field() != 0; - LoadSelf { destination } + LoadSelf { + destination, + jump_next, + } } } impl From for Instruction { fn from(load_self: LoadSelf) -> Self { - let operation = Operation::LOAD_SELF; - let a = load_self.destination; - - Instruction::new(operation, a, 0, 0, false, false, false) + InstructionBuilder { + operation: Operation::LOAD_SELF, + a_field: load_self.destination, + c_field: load_self.jump_next as u16, + ..Default::default() + } + .build() + } +} + +impl Display for LoadSelf { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let LoadSelf { + destination, + jump_next, + } = self; + + write!(f, "R{destination} = SELF")?; + + if *jump_next { + write!(f, " JUMP +1")?; + } + + Ok(()) } } diff --git a/dust-lang/src/instruction/mod.rs b/dust-lang/src/instruction/mod.rs index d1e6afc..e99bc21 100644 --- a/dust-lang/src/instruction/mod.rs +++ b/dust-lang/src/instruction/mod.rs @@ -1,14 +1,17 @@ //! The Dust instruction set. //! -//! Each instruction is 64 bits and uses up to eight distinct fields. The instruction's layout is: +//! Each instruction is 64 bits and uses up to seven distinct fields. +//! +//! # Layout //! //! Bits | Description //! ----- | ----------- -//! 0-4 | Operation code -//! 5 | Flag indicating if the B field is a constant -//! 6 | Flag indicating if the C field is a constant -//! 7 | D field (boolean) -//! 8-15 | Type specifier +//! 0-6 | Operation +//! 7 | Unused +//! 8 | Flag indicating if the B field is a constant +//! 9 | Flag indicating if the C field is a constant +//! 10 | D field (boolean) +//! 11-15 | Unused //! 16-31 | A field (unsigned 16-bit integer) //! 32-47 | B field (unsigned 16-bit integer) //! 48-63 | C field (unsigned 16-bit integer) @@ -61,7 +64,7 @@ //! To read an instruction, check its operation with [`Instruction::operation`], then convert the //! instruction to the struct that corresponds to that operation. Like the example above, this //! removes the burden of dealing with the options directly and automatically casts the A, B, C and -//! D fields as `u8`, `bool` or `Argument` values. +//! D fields as `u16`, `bool` or `Argument` values. //! //! ``` //! # use dust_lang::instruction::{Instruction, Add, Argument, Operation}; @@ -90,58 +93,117 @@ //! //! assert!(is_add_assign); //! ``` -mod add; +mod add_byte; +mod add_char; +mod add_char_str; +mod add_float; +mod add_int; +mod add_str; +mod add_str_char; mod call; mod call_native; mod close; -mod divide; -mod equal; +mod divide_byte; +mod divide_float; +mod divide_int; +mod equal_bool; +mod equal_byte; +mod equal_char; +mod equal_char_str; +mod equal_float; +mod equal_int; +mod equal_str; +mod equal_str_char; mod get_local; mod jump; -mod less; -mod less_equal; +mod less_byte; +mod less_char; +mod less_equal_byte; +mod less_equal_char; +mod less_equal_float; +mod less_equal_int; +mod less_equal_str; +mod less_float; +mod less_int; +mod less_str; mod load_boolean; mod load_constant; mod load_function; mod load_list; mod load_self; -mod modulo; -mod multiply; -mod negate; +mod modulo_byte; +mod modulo_float; +mod modulo_int; +mod multiply_byte; +mod multiply_float; +mod multiply_int; +mod negate_float; +mod negate_int; mod not; mod operation; mod point; mod r#return; mod set_local; -mod subtract; +mod subtract_byte; +mod subtract_float; +mod subtract_int; mod test; mod test_set; -mod type_code; -pub use add::Add; +pub use add_byte::AddByte; +pub use add_char::AddChar; +pub use add_char_str::AddCharStr; +pub use add_float::AddFloat; +pub use add_int::AddInt; +pub use add_str::AddStr; +pub use add_str_char::AddStrChar; pub use call::Call; pub use call_native::CallNative; pub use close::Close; -pub use divide::Divide; -pub use equal::Equal; +pub use divide_byte::DivideByte; +pub use divide_float::DivideFloat; +pub use divide_int::DivideInt; +pub use equal_bool::EqualBool; +pub use equal_byte::EqualByte; +pub use equal_char::EqualChar; +pub use equal_char_str::EqualCharStr; +pub use equal_float::EqualFloat; +pub use equal_int::EqualInt; +pub use equal_str::EqualStr; +pub use equal_str_char::EqualStrChar; pub use get_local::GetLocal; pub use jump::Jump; -pub use less::Less; -pub use less_equal::LessEqual; +pub use less_byte::LessByte; +pub use less_char::LessChar; +pub use less_equal_byte::LessEqualByte; +pub use less_equal_char::LessEqualChar; +pub use less_equal_float::LessEqualFloat; +pub use less_equal_int::LessEqualInt; +pub use less_equal_str::LessEqualStr; +pub use less_float::LessFloat; +pub use less_int::LessInt; +pub use less_str::LessStr; pub use load_boolean::LoadBoolean; pub use load_constant::LoadConstant; pub use load_function::LoadFunction; pub use load_list::LoadList; pub use load_self::LoadSelf; -pub use modulo::Modulo; -pub use multiply::Multiply; -pub use negate::Negate; +pub use modulo_byte::ModuloByte; +pub use modulo_float::ModuloFloat; +pub use modulo_int::ModuloInt; +pub use multiply_byte::MultiplyByte; +pub use multiply_float::MultiplyFloat; +pub use multiply_int::MultiplyInt; +pub use negate_float::NegateFloat; +pub use negate_int::NegateInt; pub use not::Not; pub use operation::Operation; pub use point::Point; pub use r#return::Return; pub use set_local::SetLocal; -pub use subtract::Subtract; +pub use subtract_byte::SubtractByte; +pub use subtract_float::SubtractFloat; +pub use subtract_int::SubtractInt; pub use test::Test; pub use test_set::TestSet; @@ -150,6 +212,44 @@ use std::fmt::{self, Debug, Display, Formatter}; use crate::NativeFunction; +pub struct InstructionBuilder { + pub operation: Operation, + pub a_field: u16, + pub b_field: u16, + pub c_field: u16, + pub d_field: bool, + pub b_is_constant: bool, + pub c_is_constant: bool, +} + +impl InstructionBuilder { + pub fn build(self) -> Instruction { + let bits = self.operation.0 as u64 + | ((self.b_is_constant as u64) << 7) + | ((self.c_is_constant as u64) << 8) + | ((self.d_field as u64) << 9) + | ((self.a_field as u64) << 31) + | ((self.b_field as u64) << 47) + | ((self.c_field as u64) << 63); + + Instruction(bits) + } +} + +impl Default for InstructionBuilder { + fn default() -> Self { + InstructionBuilder { + operation: Operation::POINT, + a_field: 0, + b_field: 0, + c_field: 0, + d_field: false, + b_is_constant: false, + c_is_constant: false, + } + } +} + /// An operation and its arguments for the Dust virtual machine. /// /// See the [module-level documentation](index.html) for more information. @@ -157,88 +257,57 @@ use crate::NativeFunction; pub struct Instruction(u64); impl Instruction { - pub fn new( - operation: Operation, - type_specifier: u8, - a: u16, - b: u16, - c: u16, - d: bool, - b_is_constant: bool, - c_is_constant: bool, - ) -> Instruction { - let bits = operation.0 as u64 - | ((b_is_constant as u64) << 5) - | ((c_is_constant as u64) << 6) - | ((d as u64) << 7) - | ((type_specifier as u64) << 15) - | ((a as u64) << 31) - | ((b as u64) << 47) - | ((c as u64) << 63); - - Instruction(bits) - } - pub fn operation(&self) -> Operation { - let operation_bits = self.0 & 0b0001_1111; + let first_byte = (self.0 & 0b0111_1111) as u8; - Operation(operation_bits as u8) + Operation(first_byte) } pub fn b_is_constant(&self) -> bool { - (self.0 >> 5) & 1 == 1 + (self.0 >> 8) & 1 == 0 } pub fn c_is_constant(&self) -> bool { - (self.0 >> 6) & 1 == 1 + (self.0 >> 9) & 1 == 0 } pub fn d_field(&self) -> bool { - (self.0 >> 7) & 1 == 1 + (self.0 >> 10) & 1 == 0 } - pub fn a_field(&self) -> u8 { - (self.0 >> 8) as u8 + pub fn a_field(&self) -> u16 { + ((self.0 >> 31) & 0xFFFF) as u16 } - pub fn b_field(&self) -> u8 { - (self.0 >> 16) as u8 + pub fn b_field(&self) -> u16 { + ((self.0 >> 47) & 0xFFFF) as u16 } - pub fn c_field(&self) -> u8 { - (self.0 >> 24) as u8 + pub fn c_field(&self) -> u16 { + (self.0 >> 48) as u16 } - pub fn set_a_field(&mut self, bits: u8) { - self.0 &= 0xFFFFFFFF00000000 | ((bits as u64) << 31); + pub fn set_a_field(&mut self, bits: u16) { + self.0 = (bits as u64) << 31; } - pub fn set_b_field(&mut self, bits: u8) { - self.0 &= 0xFFFF0000FFFFFFFF | ((bits as u64) << 47); + pub fn set_b_field(&mut self, bits: u16) { + self.0 = (bits as u64) << 47; } - pub fn set_c_field(&mut self, bits: u8) {} - - pub fn decode(self) -> (Operation, InstructionData) { - (self.operation(), InstructionData { - a_field: self.a_field(), - b_field: self.b_field(), - c_field: self.c_field(), - b_is_constant: self.b_is_constant(), - c_is_constant: self.c_is_constant(), - d_field: self.d_field(), - }) + pub fn set_c_field(&mut self, bits: u16) { + self.0 = (bits as u64) << 63; } - pub fn point(from: u8, to: u8) -> Instruction { + pub fn point(from: u16, to: u16) -> Instruction { Instruction::from(Point { from, to }) } - pub fn close(from: u8, to: u8) -> Instruction { + pub fn close(from: u16, to: u16) -> Instruction { Instruction::from(Close { from, to }) } - pub fn load_boolean(destination: u8, value: bool, jump_next: bool) -> Instruction { + pub fn load_boolean(destination: u16, value: bool, jump_next: bool) -> Instruction { Instruction::from(LoadBoolean { destination, value, @@ -246,7 +315,7 @@ impl Instruction { }) } - pub fn load_constant(destination: u8, constant_index: u8, jump_next: bool) -> Instruction { + pub fn load_constant(destination: u16, constant_index: u16, jump_next: bool) -> Instruction { Instruction::from(LoadConstant { destination, constant_index, @@ -254,86 +323,368 @@ impl Instruction { }) } - pub fn load_function(destination: u8, prototype_index: u8) -> Instruction { + pub fn load_function(destination: u16, prototype_index: u16, jump_next: bool) -> Instruction { Instruction::from(LoadFunction { destination, prototype_index, + jump_next, }) } - pub fn load_list(destination: u8, start_register: u8) -> Instruction { + pub fn load_list(destination: u16, start_register: u16, jump_next: bool) -> Instruction { Instruction::from(LoadList { destination, start_register, + jump_next, }) } - pub fn load_self(destination: u8) -> Instruction { - Instruction::from(LoadSelf { destination }) + pub fn load_self(destination: u16, jump_next: bool) -> Instruction { + Instruction::from(LoadSelf { + destination, + jump_next, + }) } - pub fn get_local(destination: u8, local_index: u8) -> Instruction { + pub fn get_local(destination: u16, local_index: u16) -> Instruction { Instruction::from(GetLocal { destination, local_index, }) } - pub fn set_local(register: u8, local_index: u8) -> Instruction { + pub fn set_local(register: u16, local_index: u16) -> Instruction { Instruction::from(SetLocal { local_index, register_index: register, }) } - pub fn add(destination: u8, left: Argument, right: Argument) -> Instruction { - Instruction::from(Add { + pub fn add_int(destination: u16, left: Operand, right: Operand) -> Instruction { + Instruction::from(AddInt { destination, left, right, }) } - pub fn subtract(destination: u8, left: Argument, right: Argument) -> Instruction { - Instruction::from(Subtract { + pub fn add_float(destination: u16, left: Operand, right: Operand) -> Instruction { + Instruction::from(AddFloat { destination, left, right, }) } - pub fn multiply(destination: u8, left: Argument, right: Argument) -> Instruction { - Instruction::from(Multiply { + pub fn add_byte(destination: u16, left: Operand, right: Operand) -> Instruction { + Instruction::from(AddByte { destination, left, right, }) } - pub fn divide(destination: u8, left: Argument, right: Argument) -> Instruction { - Instruction::from(Divide { + pub fn add_str(destination: u16, left: Operand, right: Operand) -> Instruction { + Instruction::from(AddStr { destination, left, right, }) } - pub fn modulo(destination: u8, left: Argument, right: Argument) -> Instruction { - Instruction::from(Modulo { + pub fn add_char(destination: u16, left: Operand, right: Operand) -> Instruction { + Instruction::from(AddChar { destination, left, right, }) } - pub fn test(operand_register: u8, value: bool) -> Instruction { + pub fn add_str_char(destination: u16, left: Operand, right: Operand) -> Instruction { + Instruction::from(AddStrChar { + destination, + left, + right, + }) + } + + pub fn add_char_str(destination: u16, left: Operand, right: Operand) -> Instruction { + Instruction::from(AddCharStr { + destination, + left, + right, + }) + } + + pub fn subtract_int(destination: u16, left: Operand, right: Operand) -> Instruction { + Instruction::from(SubtractInt { + destination, + left, + right, + }) + } + + pub fn subtract_float(destination: u16, left: Operand, right: Operand) -> Instruction { + Instruction::from(SubtractFloat { + destination, + left, + right, + }) + } + + pub fn subtract_byte(destination: u16, left: Operand, right: Operand) -> Instruction { + Instruction::from(SubtractByte { + destination, + left, + right, + }) + } + + pub fn multiply_int(destination: u16, left: Operand, right: Operand) -> Instruction { + Instruction::from(MultiplyInt { + destination, + left, + right, + }) + } + + pub fn multiply_float(destination: u16, left: Operand, right: Operand) -> Instruction { + Instruction::from(MultiplyFloat { + destination, + left, + right, + }) + } + + pub fn multiply_byte(destination: u16, left: Operand, right: Operand) -> Instruction { + Instruction::from(MultiplyByte { + destination, + left, + right, + }) + } + + pub fn divide_int(destination: u16, left: Operand, right: Operand) -> Instruction { + Instruction::from(DivideInt { + destination, + left, + right, + }) + } + + pub fn divide_float(destination: u16, left: Operand, right: Operand) -> Instruction { + Instruction::from(DivideFloat { + destination, + left, + right, + }) + } + + pub fn divide_byte(destination: u16, left: Operand, right: Operand) -> Instruction { + Instruction::from(DivideByte { + destination, + left, + right, + }) + } + + pub fn modulo_int(destination: u16, left: Operand, right: Operand) -> Instruction { + Instruction::from(ModuloInt { + destination, + left, + right, + }) + } + + pub fn modulo_float(destination: u16, left: Operand, right: Operand) -> Instruction { + Instruction::from(ModuloFloat { + destination, + left, + right, + }) + } + + pub fn modulo_byte(destination: u16, left: Operand, right: Operand) -> Instruction { + Instruction::from(ModuloByte { + destination, + left, + right, + }) + } + + pub fn equal_int(comparator: bool, left: Operand, right: Operand) -> Instruction { + Instruction::from(EqualInt { + comparator, + left, + right, + }) + } + + pub fn equal_float(comparator: bool, left: Operand, right: Operand) -> Instruction { + Instruction::from(EqualFloat { + comparator, + left, + right, + }) + } + + pub fn equal_byte(comparator: bool, left: Operand, right: Operand) -> Instruction { + Instruction::from(EqualByte { + comparator, + left, + right, + }) + } + + pub fn equal_str(comparator: bool, left: Operand, right: Operand) -> Instruction { + Instruction::from(EqualStr { + comparator, + left, + right, + }) + } + + pub fn equal_char(comparator: bool, left: Operand, right: Operand) -> Instruction { + Instruction::from(EqualChar { + comparator, + left, + right, + }) + } + + pub fn equal_str_char(comparator: bool, left: Operand, right: Operand) -> Instruction { + Instruction::from(EqualStrChar { + comparator, + left, + right, + }) + } + + pub fn equal_char_str(comparator: bool, left: Operand, right: Operand) -> Instruction { + Instruction::from(EqualCharStr { + comparator, + left, + right, + }) + } + + pub fn equal_bool(comparator: bool, left: Operand, right: Operand) -> Instruction { + Instruction::from(EqualBool { + comparator, + left, + right, + }) + } + + pub fn less_int(comparator: bool, left: Operand, right: Operand) -> Instruction { + Instruction::from(LessInt { + comparator, + left, + right, + }) + } + + pub fn less_float(comparator: bool, left: Operand, right: Operand) -> Instruction { + Instruction::from(LessFloat { + comparator, + left, + right, + }) + } + + pub fn less_byte(comparator: bool, left: Operand, right: Operand) -> Instruction { + Instruction::from(LessByte { + comparator, + left, + right, + }) + } + + pub fn less_str(comparator: bool, left: Operand, right: Operand) -> Instruction { + Instruction::from(LessStr { + comparator, + left, + right, + }) + } + + pub fn less_char(comparator: bool, left: Operand, right: Operand) -> Instruction { + Instruction::from(LessChar { + comparator, + left, + right, + }) + } + + pub fn less_equal_int(comparator: bool, left: Operand, right: Operand) -> Instruction { + Instruction::from(LessEqualInt { + comparator, + left, + right, + }) + } + + pub fn less_equal_float(comparator: bool, left: Operand, right: Operand) -> Instruction { + Instruction::from(LessEqualFloat { + comparator, + left, + right, + }) + } + + pub fn less_equal_byte(comparator: bool, left: Operand, right: Operand) -> Instruction { + Instruction::from(LessEqualByte { + comparator, + left, + right, + }) + } + + pub fn less_equal_str(comparator: bool, left: Operand, right: Operand) -> Instruction { + Instruction::from(LessEqualStr { + comparator, + left, + right, + }) + } + + pub fn less_equal_char(comparator: bool, left: Operand, right: Operand) -> Instruction { + Instruction::from(LessEqualChar { + comparator, + left, + right, + }) + } + + pub fn negate_int(destination: u16, argument: Operand) -> Instruction { + Instruction::from(NegateInt { + destination, + argument, + }) + } + + pub fn negate_float(destination: u16, argument: Operand) -> Instruction { + Instruction::from(NegateFloat { + destination, + argument, + }) + } + + pub fn not(destination: u16, argument: Operand) -> Instruction { + Instruction::from(Not { + destination, + argument, + }) + } + + pub fn test(operand_register: u16, value: bool) -> Instruction { Instruction::from(Test { operand_register, test_value: value, }) } - pub fn test_set(destination: u8, argument: Argument, value: bool) -> Instruction { + pub fn test_set(destination: u16, argument: Operand, value: bool) -> Instruction { Instruction::from(TestSet { destination, argument, @@ -341,33 +692,7 @@ impl Instruction { }) } - pub fn equal(value: bool, left: Argument, right: Argument) -> Instruction { - Instruction::from(Equal { value, left, right }) - } - - pub fn less(value: bool, left: Argument, right: Argument) -> Instruction { - Instruction::from(Less { value, left, right }) - } - - pub fn less_equal(value: bool, left: Argument, right: Argument) -> Instruction { - Instruction::from(LessEqual { value, left, right }) - } - - pub fn negate(destination: u8, argument: Argument) -> Instruction { - Instruction::from(Negate { - destination, - argument, - }) - } - - pub fn not(destination: u8, argument: Argument) -> Instruction { - Instruction::from(Not { - destination, - argument, - }) - } - - pub fn jump(offset: u8, is_positive: bool) -> Instruction { + pub fn jump(offset: u16, is_positive: bool) -> Instruction { Instruction::from(Jump { offset, is_positive, @@ -375,9 +700,9 @@ impl Instruction { } pub fn call( - destination: u8, - function_register: u8, - argument_count: u8, + destination: u16, + function_register: u16, + argument_count: u16, is_recursive: bool, ) -> Instruction { Instruction::from(Call { @@ -389,9 +714,9 @@ impl Instruction { } pub fn call_native( - destination: u8, + destination: u16, function: NativeFunction, - argument_count: u8, + argument_count: u16, ) -> Instruction { Instruction::from(CallNative { destination, @@ -400,7 +725,7 @@ impl Instruction { }) } - pub fn r#return(should_return_value: bool, return_register: u8) -> Instruction { + pub fn r#return(should_return_value: bool, return_register: u16) -> Instruction { Instruction::from(Return { should_return_value, return_register, @@ -408,46 +733,66 @@ impl Instruction { } pub fn is_math(&self) -> bool { - matches!( - self.operation(), - Operation::ADD - | Operation::SUBTRACT - | Operation::MULTIPLY - | Operation::DIVIDE - | Operation::MODULO - ) + self.operation().is_math() } pub fn is_comparison(&self) -> bool { - matches!( - self.operation(), - Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL - ) + self.operation().is_comparison() } - pub fn as_argument(&self) -> Option { + pub fn as_argument(&self) -> Option { match self.operation() { - Operation::LOAD_CONSTANT => Some(Argument::Constant(self.b_field())), + Operation::LOAD_CONSTANT => Some(Operand::Constant(self.b_field())), Operation::LOAD_BOOLEAN | Operation::LOAD_LIST | Operation::LOAD_SELF | Operation::GET_LOCAL - | Operation::ADD - | Operation::SUBTRACT - | Operation::MULTIPLY - | Operation::DIVIDE - | Operation::MODULO - | Operation::EQUAL - | Operation::LESS - | Operation::LESS_EQUAL - | Operation::NEGATE + | Operation::ADD_INT + | Operation::ADD_FLOAT + | Operation::ADD_BYTE + | Operation::ADD_STR + | Operation::ADD_CHAR + | Operation::ADD_STR_CHAR + | Operation::ADD_CHAR_STR + | Operation::SUBTRACT_INT + | Operation::SUBTRACT_FLOAT + | Operation::SUBTRACT_BYTE + | Operation::MULTIPLY_INT + | Operation::MULTIPLY_FLOAT + | Operation::MULTIPLY_BYTE + | Operation::DIVIDE_INT + | Operation::DIVIDE_FLOAT + | Operation::DIVIDE_BYTE + | Operation::MODULO_INT + | Operation::MODULO_FLOAT + | Operation::MODULO_BYTE + | Operation::EQUAL_INT + | Operation::EQUAL_FLOAT + | Operation::EQUAL_BYTE + | Operation::EQUAL_STR + | Operation::EQUAL_CHAR + | Operation::EQUAL_STR_CHAR + | Operation::EQUAL_CHAR_STR + | Operation::EQUAL_BOOL + | Operation::LESS_INT + | Operation::LESS_FLOAT + | Operation::LESS_BYTE + | Operation::LESS_STR + | Operation::LESS_CHAR + | Operation::LESS_EQUAL_INT + | Operation::LESS_EQUAL_FLOAT + | Operation::LESS_EQUAL_BYTE + | Operation::LESS_EQUAL_STR + | Operation::LESS_EQUAL_CHAR + | Operation::NEGATE_INT + | Operation::NEGATE_FLOAT | Operation::NOT - | Operation::CALL => Some(Argument::Register(self.a_field())), + | Operation::CALL => Some(Operand::Register(self.a_field())), Operation::CALL_NATIVE => { let function = NativeFunction::from(self.b_field()); if function.returns_value() { - Some(Argument::Register(self.a_field())) + Some(Operand::Register(self.a_field())) } else { None } @@ -456,24 +801,24 @@ impl Instruction { } } - pub fn b_as_argument(&self) -> Argument { + pub fn b_as_argument(&self) -> Operand { if self.b_is_constant() { - Argument::Constant(self.b_field()) + Operand::Constant(self.b_field()) } else { - Argument::Register(self.b_field()) + Operand::Register(self.b_field()) } } - pub fn b_and_c_as_arguments(&self) -> (Argument, Argument) { + pub fn b_and_c_as_operands(&self) -> (Operand, Operand) { let left = if self.b_is_constant() { - Argument::Constant(self.b_field()) + Operand::Constant(self.b_field()) } else { - Argument::Register(self.b_field()) + Operand::Register(self.b_field()) }; let right = if self.c_is_constant() { - Argument::Constant(self.c_field()) + Operand::Constant(self.c_field()) } else { - Argument::Register(self.c_field()) + Operand::Register(self.c_field()) }; (left, right) @@ -488,12 +833,27 @@ impl Instruction { | Operation::LOAD_LIST | Operation::LOAD_SELF | Operation::GET_LOCAL - | Operation::ADD - | Operation::SUBTRACT - | Operation::MULTIPLY - | Operation::DIVIDE - | Operation::MODULO - | Operation::NEGATE + | Operation::ADD_INT + | Operation::ADD_FLOAT + | Operation::ADD_BYTE + | Operation::ADD_STR + | Operation::ADD_CHAR + | Operation::ADD_STR_CHAR + | Operation::ADD_CHAR_STR + | Operation::SUBTRACT_INT + | Operation::SUBTRACT_FLOAT + | Operation::SUBTRACT_BYTE + | Operation::MULTIPLY_INT + | Operation::MULTIPLY_FLOAT + | Operation::MULTIPLY_BYTE + | Operation::DIVIDE_INT + | Operation::DIVIDE_FLOAT + | Operation::DIVIDE_BYTE + | Operation::MODULO_INT + | Operation::MODULO_FLOAT + | Operation::MODULO_BYTE + | Operation::NEGATE_INT + | Operation::NEGATE_FLOAT | Operation::NOT | Operation::CALL => true, Operation::CALL_NATIVE => { @@ -503,9 +863,24 @@ impl Instruction { } Operation::CLOSE | Operation::SET_LOCAL - | Operation::EQUAL - | Operation::LESS - | Operation::LESS_EQUAL + | Operation::EQUAL_INT + | Operation::EQUAL_FLOAT + | Operation::EQUAL_BYTE + | Operation::EQUAL_STR + | Operation::EQUAL_CHAR + | Operation::EQUAL_STR_CHAR + | Operation::EQUAL_CHAR_STR + | Operation::EQUAL_BOOL + | Operation::LESS_INT + | Operation::LESS_FLOAT + | Operation::LESS_BYTE + | Operation::LESS_STR + | Operation::LESS_CHAR + | Operation::LESS_EQUAL_INT + | Operation::LESS_EQUAL_FLOAT + | Operation::LESS_EQUAL_BYTE + | Operation::LESS_EQUAL_STR + | Operation::LESS_EQUAL_CHAR | Operation::TEST | Operation::TEST_SET | Operation::JUMP @@ -519,242 +894,17 @@ impl Instruction { match operation { Operation::POINT => Point::from(*self).to_string(), - Operation::CLOSE => { - let Close { from, to } = Close::from(*self); - - format!("R{from}..R{to}") - } - Operation::LOAD_BOOLEAN => { - let LoadBoolean { - destination, - value, - jump_next, - } = LoadBoolean::from(*self); - - if jump_next { - format!("R{destination} = {value} && JUMP +1") - } else { - format!("R{destination} = {value}") - } - } - Operation::LOAD_CONSTANT => { - let LoadConstant { - destination, - constant_index, - jump_next, - } = LoadConstant::from(*self); - - if jump_next { - format!("R{destination} = C{constant_index} JUMP +1") - } else { - format!("R{destination} = C{constant_index}") - } - } + Operation::CLOSE => Close::from(*self).to_string(), + Operation::LOAD_BOOLEAN => LoadBoolean::from(*self).to_string(), + Operation::LOAD_CONSTANT => LoadConstant::from(*self).to_string(), Operation::LOAD_FUNCTION => LoadFunction::from(*self).to_string(), - Operation::LOAD_LIST => { - let LoadList { - destination, - start_register, - } = LoadList::from(*self); - let end_register = destination.saturating_sub(1); + Operation::LOAD_LIST => LoadList::from(*self).to_string(), + Operation::LOAD_SELF => LoadSelf::from(*self).to_string(), + Operation::GET_LOCAL => GetLocal::from(*self).to_string(), + Operation::SET_LOCAL => SetLocal::from(*self).to_string(), + Operation::ADD_INT => AddInt::from(*self).to_string(), - format!("R{destination} = [R{start_register}..=R{end_register}]",) - } - Operation::LOAD_SELF => { - let LoadSelf { destination } = LoadSelf::from(*self); - - format!("R{destination} = self") - } - Operation::GET_LOCAL => { - let GetLocal { - destination, - local_index, - } = GetLocal::from(*self); - - format!("R{destination} = L{local_index}") - } - Operation::SET_LOCAL => { - let SetLocal { - register_index, - local_index, - } = SetLocal::from(*self); - - format!("L{local_index} = R{register_index}") - } - Operation::ADD => { - let Add { - destination, - left, - right, - } = Add::from(*self); - - format!("R{destination} = {left} + {right}") - } - Operation::SUBTRACT => { - let Subtract { - destination, - left, - right, - } = Subtract::from(*self); - - format!("R{destination} = {left} - {right}") - } - Operation::MULTIPLY => { - let Multiply { - destination, - left, - right, - } = Multiply::from(*self); - - format!("R{destination} = {left} * {right}") - } - Operation::DIVIDE => { - let Divide { - destination, - left, - right, - } = Divide::from(*self); - - format!("R{destination} = {left} / {right}") - } - Operation::MODULO => { - let Modulo { - destination, - left, - right, - } = Modulo::from(*self); - - format!("R{destination} = {left} % {right}") - } - Operation::TEST => { - let Test { - operand_register, - test_value, - } = Test::from(*self); - let bang = if test_value { "" } else { "!" }; - - format!("if {bang}R{operand_register} {{ JUMP +1 }}",) - } - Operation::TEST_SET => { - let TestSet { - destination, - argument, - test_value, - } = TestSet::from(*self); - let bang = if test_value { "" } else { "!" }; - - format!("if {bang}{argument} {{ JUMP +1 }} else {{ R{destination} = {argument} }}") - } - 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 => { - let Less { value, left, right } = Less::from(*self); - let comparison_symbol = if value { "<" } else { ">=" }; - - format!("if {left} {comparison_symbol} {right} {{ JUMP +1 }}") - } - 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 => { - let Negate { - destination, - argument, - } = Negate::from(*self); - - format!("R{destination} = -{argument}") - } - Operation::NOT => { - let Not { - destination, - argument, - } = Not::from(*self); - - format!("R{destination} = !{argument}") - } - Operation::JUMP => { - let Jump { - offset, - is_positive, - } = Jump::from(*self); - - if is_positive { - format!("JUMP +{offset}") - } else { - format!("JUMP -{offset}") - } - } - Operation::CALL => { - let Call { - destination, - function_register, - argument_count, - .. - } = Call::from(*self); - let arguments_start = destination.saturating_sub(argument_count); - - match argument_count { - 0 => format!("R{destination} = R{function_register}()"), - 1 => format!("R{destination} = R{function_register}(R{arguments_start})"), - _ => { - format!( - "R{destination} = R{function_register}(R{arguments_start}..R{destination})" - ) - } - } - } - Operation::CALL_NATIVE => { - let CallNative { - destination, - function, - argument_count, - } = CallNative::from(*self); - let arguments_start = destination.saturating_sub(argument_count); - let arguments_end = arguments_start + argument_count; - let mut info_string = if function.returns_value() { - format!("R{destination} = ") - } else { - String::new() - }; - - match argument_count { - 0 => { - info_string.push_str(function.as_str()); - info_string.push_str("()"); - } - 1 => info_string.push_str(&format!("{function}(R{arguments_start})")), - _ => info_string - .push_str(&format!("{function}(R{arguments_start}..R{arguments_end})")), - } - - info_string - } - Operation::RETURN => { - let Return { - should_return_value, - return_register, - } = Return::from(*self); - - if should_return_value { - format!("RETURN R{return_register}") - } else { - String::new() - } - } - _ => { - if cfg!(debug_assertions) { - panic!("Unknown operation {}", self.operation()); - } else { - "RETURN".to_string() - } - } + _ => Operation::panic_from_unknown_code(operation.0), } } } @@ -771,57 +921,95 @@ impl Display for Instruction { } } -#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct InstructionData { - pub a_field: u8, - pub b_field: u8, - pub c_field: u8, - pub d_field: bool, - pub b_is_constant: bool, - pub c_is_constant: bool, -} - -impl Display for InstructionData { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{self:?}") - } -} - #[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] -pub enum Argument { - Constant(u8), - Register(u8), +pub enum Operand { + Constant(u16), + Register(u16), } -impl Argument { - pub fn index(&self) -> u8 { +impl Operand { + pub fn index(&self) -> u16 { match self { - Argument::Constant(index) => *index, - Argument::Register(index) => *index, + Operand::Constant(index) => *index, + Operand::Register(index) => *index, } } pub fn is_constant(&self) -> bool { - matches!(self, Argument::Constant(_)) + matches!(self, Operand::Constant(_)) } pub fn is_register(&self) -> bool { - matches!(self, Argument::Register(_)) + matches!(self, Operand::Register(_)) } - pub fn as_index_and_constant_flag(&self) -> (u8, bool) { + pub fn as_index_and_constant_flag(&self) -> (u16, bool) { match self { - Argument::Constant(index) => (*index, true), - Argument::Register(index) => (*index, false), + Operand::Constant(index) => (*index, true), + Operand::Register(index) => (*index, false), } } } -impl Display for Argument { +impl Display for Operand { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { - Argument::Constant(index) => write!(f, "C{index}"), - Argument::Register(index) => write!(f, "R{index}"), + Operand::Constant(index) => write!(f, "C{index}"), + Operand::Register(index) => write!(f, "R{index}"), } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn decode_operation() { + let instruction = Instruction::add_int(42, Operand::Constant(4), Operand::Register(2)); + + assert_eq!(instruction.operation(), Operation::ADD_INT); + } + + #[test] + fn decode_a_field() { + let instruction = Instruction::add_int(42, Operand::Constant(4), Operand::Register(2)); + + assert_eq!(42, instruction.a_field()); + } + + #[test] + fn decode_b_field() { + let instruction = Instruction::add_int(42, Operand::Constant(4), Operand::Register(2)); + + assert_eq!(4, instruction.b_field()); + } + + #[test] + fn decode_c_field() { + let instruction = Instruction::add_int(42, Operand::Constant(4), Operand::Register(2)); + + assert_eq!(2, instruction.c_field()); + } + + #[test] + fn decode_d_field() { + let instruction = Instruction::call(42, 4, 2, true); + + assert!(instruction.d_field()); + } + + #[test] + fn decode_b_is_constant() { + let instruction = Instruction::add_int(42, Operand::Constant(4), Operand::Register(2)); + + assert!(instruction.b_is_constant()); + } + + #[test] + fn decode_c_is_constant() { + let instruction = Instruction::add_int(42, Operand::Register(2), Operand::Constant(4)); + + assert!(instruction.c_is_constant()); + } +} diff --git a/dust-lang/src/instruction/modulo.rs b/dust-lang/src/instruction/modulo.rs deleted file mode 100644 index 9ba0f5b..0000000 --- a/dust-lang/src/instruction/modulo.rs +++ /dev/null @@ -1,31 +0,0 @@ -use crate::{Argument, Instruction, Operation}; - -pub struct Modulo { - pub destination: u8, - pub left: Argument, - pub right: Argument, -} - -impl From for Modulo { - fn from(instruction: Instruction) -> Self { - let destination = instruction.a_field(); - let (left, right) = instruction.b_and_c_as_arguments(); - - Modulo { - destination, - left, - right, - } - } -} - -impl From for Instruction { - fn from(modulo: Modulo) -> Self { - let operation = Operation::MODULO; - let a = modulo.destination; - let (b, b_is_constant) = modulo.left.as_index_and_constant_flag(); - let (c, c_is_constant) = modulo.right.as_index_and_constant_flag(); - - Instruction::new(operation, a, b, c, b_is_constant, c_is_constant, false) - } -} diff --git a/dust-lang/src/instruction/modulo_byte.rs b/dust-lang/src/instruction/modulo_byte.rs new file mode 100644 index 0000000..9e969d3 --- /dev/null +++ b/dust-lang/src/instruction/modulo_byte.rs @@ -0,0 +1,54 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct ModuloByte { + pub destination: u16, + pub left: Operand, + pub right: Operand, +} + +impl From for ModuloByte { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + ModuloByte { + destination, + left, + right, + } + } +} + +impl From for Instruction { + fn from(modulo_byte: ModuloByte) -> Self { + let operation = Operation::MODULO_BYTE; + let a_field = modulo_byte.destination; + let (b_field, b_is_constant) = modulo_byte.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = modulo_byte.right.as_index_and_constant_flag(); + + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for ModuloByte { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let ModuloByte { + destination, + left, + right, + } = self; + + write!(f, "R{} = {} % {}", destination, left, right) + } +} diff --git a/dust-lang/src/instruction/modulo_float.rs b/dust-lang/src/instruction/modulo_float.rs new file mode 100644 index 0000000..7b33022 --- /dev/null +++ b/dust-lang/src/instruction/modulo_float.rs @@ -0,0 +1,54 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct ModuloFloat { + pub destination: u16, + pub left: Operand, + pub right: Operand, +} + +impl From for ModuloFloat { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + ModuloFloat { + destination, + left, + right, + } + } +} + +impl From for Instruction { + fn from(modulo_float: ModuloFloat) -> Self { + let operation = Operation::MODULO_FLOAT; + let a_field = modulo_float.destination; + let (b_field, b_is_constant) = modulo_float.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = modulo_float.right.as_index_and_constant_flag(); + + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for ModuloFloat { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let ModuloFloat { + destination, + left, + right, + } = self; + + write!(f, "R{} = {} % {}", destination, left, right) + } +} diff --git a/dust-lang/src/instruction/modulo_int.rs b/dust-lang/src/instruction/modulo_int.rs new file mode 100644 index 0000000..e913893 --- /dev/null +++ b/dust-lang/src/instruction/modulo_int.rs @@ -0,0 +1,54 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct ModuloInt { + pub destination: u16, + pub left: Operand, + pub right: Operand, +} + +impl From for ModuloInt { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + ModuloInt { + destination, + left, + right, + } + } +} + +impl From for Instruction { + fn from(modulo_int: ModuloInt) -> Self { + let operation = Operation::MODULO_INT; + let a_field = modulo_int.destination; + let (b_field, b_is_constant) = modulo_int.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = modulo_int.right.as_index_and_constant_flag(); + + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for ModuloInt { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let ModuloInt { + destination, + left, + right, + } = self; + + write!(f, "R{} = {} % {}", destination, left, right) + } +} diff --git a/dust-lang/src/instruction/multiply.rs b/dust-lang/src/instruction/multiply.rs deleted file mode 100644 index fd73ff3..0000000 --- a/dust-lang/src/instruction/multiply.rs +++ /dev/null @@ -1,31 +0,0 @@ -use crate::{Argument, Instruction, Operation}; - -pub struct Multiply { - pub destination: u8, - pub left: Argument, - pub right: Argument, -} - -impl From for Multiply { - fn from(instruction: Instruction) -> Self { - let destination = instruction.a_field(); - let (left, right) = instruction.b_and_c_as_arguments(); - - Multiply { - destination, - left, - right, - } - } -} - -impl From for Instruction { - fn from(multiply: Multiply) -> Self { - let operation = Operation::MULTIPLY; - let a = multiply.destination; - let (b, b_options) = multiply.left.as_index_and_constant_flag(); - let (c, c_options) = multiply.right.as_index_and_constant_flag(); - - Instruction::new(operation, a, b, c, b_options, c_options, false) - } -} diff --git a/dust-lang/src/instruction/multiply_byte.rs b/dust-lang/src/instruction/multiply_byte.rs new file mode 100644 index 0000000..501776e --- /dev/null +++ b/dust-lang/src/instruction/multiply_byte.rs @@ -0,0 +1,54 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct MultiplyByte { + pub destination: u16, + pub left: Operand, + pub right: Operand, +} + +impl From for MultiplyByte { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + MultiplyByte { + destination, + left, + right, + } + } +} + +impl From for Instruction { + fn from(multiply_byte: MultiplyByte) -> Self { + let operation = Operation::MODULO_BYTE; + let a_field = multiply_byte.destination; + let (b_field, b_is_constant) = multiply_byte.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = multiply_byte.right.as_index_and_constant_flag(); + + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for MultiplyByte { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let MultiplyByte { + destination, + left, + right, + } = self; + + write!(f, "R{} = {} ✕ {}", destination, left, right) + } +} diff --git a/dust-lang/src/instruction/multiply_float.rs b/dust-lang/src/instruction/multiply_float.rs new file mode 100644 index 0000000..19f8292 --- /dev/null +++ b/dust-lang/src/instruction/multiply_float.rs @@ -0,0 +1,54 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct MultiplyFloat { + pub destination: u16, + pub left: Operand, + pub right: Operand, +} + +impl From for MultiplyFloat { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + MultiplyFloat { + destination, + left, + right, + } + } +} + +impl From for Instruction { + fn from(multiply_float: MultiplyFloat) -> Self { + let operation = Operation::MULTIPLY_FLOAT; + let a_field = multiply_float.destination; + let (b_field, b_is_constant) = multiply_float.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = multiply_float.right.as_index_and_constant_flag(); + + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for MultiplyFloat { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let MultiplyFloat { + destination, + left, + right, + } = self; + + write!(f, "R{} = {} ✕ {}", destination, left, right) + } +} diff --git a/dust-lang/src/instruction/multiply_int.rs b/dust-lang/src/instruction/multiply_int.rs new file mode 100644 index 0000000..00fbdf5 --- /dev/null +++ b/dust-lang/src/instruction/multiply_int.rs @@ -0,0 +1,54 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct MultiplyInt { + pub destination: u16, + pub left: Operand, + pub right: Operand, +} + +impl From for MultiplyInt { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + MultiplyInt { + destination, + left, + right, + } + } +} + +impl From for Instruction { + fn from(multiply_int: MultiplyInt) -> Self { + let operation = Operation::MULTIPLY_INT; + let a_field = multiply_int.destination; + let (b_field, b_is_constant) = multiply_int.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = multiply_int.right.as_index_and_constant_flag(); + + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for MultiplyInt { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let MultiplyInt { + destination, + left, + right, + } = self; + + write!(f, "R{} = {} ✕ {}", destination, left, right) + } +} diff --git a/dust-lang/src/instruction/negate.rs b/dust-lang/src/instruction/negate.rs deleted file mode 100644 index 405db8d..0000000 --- a/dust-lang/src/instruction/negate.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::{Argument, Instruction, Operation}; - -pub struct Negate { - pub destination: u8, - pub argument: Argument, -} - -impl From for Negate { - fn from(instruction: Instruction) -> Self { - let destination = instruction.a_field(); - let argument = instruction.b_as_argument(); - - Negate { - destination, - argument, - } - } -} - -impl From for Instruction { - fn from(negate: Negate) -> Self { - let operation = Operation::NEGATE; - let a = negate.destination; - let (b, b_is_constant) = negate.argument.as_index_and_constant_flag(); - let c = 0; - - Instruction::new(operation, a, b, c, b_is_constant, false, false) - } -} diff --git a/dust-lang/src/instruction/negate_float.rs b/dust-lang/src/instruction/negate_float.rs new file mode 100644 index 0000000..c0ed4d3 --- /dev/null +++ b/dust-lang/src/instruction/negate_float.rs @@ -0,0 +1,48 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct NegateFloat { + pub destination: u16, + pub argument: Operand, +} + +impl From for NegateFloat { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let argument = instruction.b_as_argument(); + + NegateFloat { + destination, + argument, + } + } +} + +impl From for Instruction { + fn from(negate_float: NegateFloat) -> Self { + let operation = Operation::NEGATE_FLOAT; + let a_field = negate_float.destination; + let (b_field, b_is_constant) = negate_float.argument.as_index_and_constant_flag(); + + InstructionBuilder { + operation, + a_field, + b_field, + b_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for NegateFloat { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let NegateFloat { + destination, + argument, + } = self; + + write!(f, "R{destination} = -{argument}") + } +} diff --git a/dust-lang/src/instruction/negate_int.rs b/dust-lang/src/instruction/negate_int.rs new file mode 100644 index 0000000..6f1f901 --- /dev/null +++ b/dust-lang/src/instruction/negate_int.rs @@ -0,0 +1,48 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct NegateInt { + pub destination: u16, + pub argument: Operand, +} + +impl From for NegateInt { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let argument = instruction.b_as_argument(); + + NegateInt { + destination, + argument, + } + } +} + +impl From for Instruction { + fn from(negate_int: NegateInt) -> Self { + let operation = Operation::NEGATE_INT; + let a_field = negate_int.destination; + let (b_field, b_is_constant) = negate_int.argument.as_index_and_constant_flag(); + + InstructionBuilder { + operation, + a_field, + b_field, + b_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for NegateInt { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let NegateInt { + destination, + argument, + } = self; + + write!(f, "R{destination} = -{argument}") + } +} diff --git a/dust-lang/src/instruction/not.rs b/dust-lang/src/instruction/not.rs index 70d7dd5..f26c4ea 100644 --- a/dust-lang/src/instruction/not.rs +++ b/dust-lang/src/instruction/not.rs @@ -1,8 +1,10 @@ -use crate::{Argument, Instruction, Operation}; +use crate::{Instruction, Operand, Operation}; + +use super::InstructionBuilder; pub struct Not { - pub destination: u8, - pub argument: Argument, + pub destination: u16, + pub argument: Operand, } impl From for Not { @@ -20,9 +22,16 @@ impl From for Not { impl From for Instruction { fn from(not: Not) -> Self { let operation = Operation::NOT; - let a = not.destination; - let (b, b_is_constant) = not.argument.as_index_and_constant_flag(); + let a_field = not.destination; + let (b_field, b_is_constant) = not.argument.as_index_and_constant_flag(); - Instruction::new(operation, a, b, 0, b_is_constant, false, false) + InstructionBuilder { + operation, + a_field, + b_field, + b_is_constant, + ..Default::default() + } + .build() } } diff --git a/dust-lang/src/instruction/operation.rs b/dust-lang/src/instruction/operation.rs index 0ab3851..ddded47 100644 --- a/dust-lang/src/instruction/operation.rs +++ b/dust-lang/src/instruction/operation.rs @@ -9,31 +9,90 @@ use serde::{Deserialize, Serialize}; pub struct Operation(pub u8); impl Operation { + // Stack manipulation pub const POINT: Operation = Operation(0); pub const CLOSE: Operation = Operation(1); + + // Loaders pub const LOAD_BOOLEAN: Operation = Operation(2); pub const LOAD_CONSTANT: Operation = Operation(3); pub const LOAD_FUNCTION: Operation = Operation(4); pub const LOAD_LIST: Operation = Operation(5); pub const LOAD_SELF: Operation = Operation(6); + + // Locals pub const GET_LOCAL: Operation = Operation(7); pub const SET_LOCAL: Operation = Operation(8); - pub const ADD: Operation = Operation(9); - pub const SUBTRACT: Operation = Operation(10); - pub const MULTIPLY: Operation = Operation(11); - pub const DIVIDE: Operation = Operation(12); - pub const MODULO: Operation = Operation(13); - pub const TEST: Operation = Operation(14); - pub const TEST_SET: Operation = Operation(15); - pub const EQUAL: Operation = Operation(16); - pub const LESS: Operation = Operation(17); - pub const LESS_EQUAL: Operation = Operation(18); - pub const NEGATE: Operation = Operation(19); - pub const NOT: Operation = Operation(20); - pub const CALL: Operation = Operation(21); - pub const CALL_NATIVE: Operation = Operation(22); - pub const JUMP: Operation = Operation(23); - pub const RETURN: Operation = Operation(24); + + // Addition + pub const ADD_INT: Operation = Operation(9); + pub const ADD_FLOAT: Operation = Operation(10); + pub const ADD_BYTE: Operation = Operation(11); + pub const ADD_STR: Operation = Operation(12); + pub const ADD_CHAR: Operation = Operation(13); + pub const ADD_STR_CHAR: Operation = Operation(14); + pub const ADD_CHAR_STR: Operation = Operation(15); + + // Subtraction + pub const SUBTRACT_INT: Operation = Operation(16); + pub const SUBTRACT_FLOAT: Operation = Operation(17); + pub const SUBTRACT_BYTE: Operation = Operation(18); + + // Multiplication + pub const MULTIPLY_INT: Operation = Operation(19); + pub const MULTIPLY_FLOAT: Operation = Operation(20); + pub const MULTIPLY_BYTE: Operation = Operation(21); + + // Division + pub const DIVIDE_INT: Operation = Operation(22); + pub const DIVIDE_FLOAT: Operation = Operation(23); + pub const DIVIDE_BYTE: Operation = Operation(24); + + // Modulo + pub const MODULO_INT: Operation = Operation(25); + pub const MODULO_FLOAT: Operation = Operation(26); + pub const MODULO_BYTE: Operation = Operation(27); + + // Equality + pub const EQUAL_INT: Operation = Operation(28); + pub const EQUAL_FLOAT: Operation = Operation(29); + pub const EQUAL_BYTE: Operation = Operation(30); + pub const EQUAL_STR: Operation = Operation(31); + pub const EQUAL_CHAR: Operation = Operation(32); + pub const EQUAL_STR_CHAR: Operation = Operation(33); + pub const EQUAL_CHAR_STR: Operation = Operation(34); + pub const EQUAL_BOOL: Operation = Operation(35); + + // < or >= comparison + pub const LESS_INT: Operation = Operation(36); + pub const LESS_FLOAT: Operation = Operation(37); + pub const LESS_BYTE: Operation = Operation(38); + pub const LESS_STR: Operation = Operation(39); + pub const LESS_CHAR: Operation = Operation(40); + + // <= or > comparison + pub const LESS_EQUAL_INT: Operation = Operation(41); + pub const LESS_EQUAL_FLOAT: Operation = Operation(42); + pub const LESS_EQUAL_BYTE: Operation = Operation(43); + pub const LESS_EQUAL_STR: Operation = Operation(44); + pub const LESS_EQUAL_CHAR: Operation = Operation(45); + + // Unary operations + pub const NEGATE_INT: Operation = Operation(46); + pub const NEGATE_FLOAT: Operation = Operation(47); + pub const NOT: Operation = Operation(48); + + // Logical operations + pub const TEST: Operation = Operation(49); + pub const TEST_SET: Operation = Operation(50); + + // Function calls + pub const CALL: Operation = Operation(51); + pub const CALL_NATIVE: Operation = Operation(52); + + // Control flow + pub const JUMP: Operation = Operation(53); + pub const RETURN: Operation = Operation(54); } impl Operation { @@ -48,18 +107,48 @@ impl Operation { 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::ADD_INT => "ADD_INT", + Self::ADD_FLOAT => "ADD_FLOAT", + Self::ADD_BYTE => "ADD_BYTE", + Self::ADD_STR => "ADD_STR", + Self::ADD_CHAR => "ADD_CHAR", + Self::ADD_STR_CHAR => "ADD_STR_CHAR", + Self::ADD_CHAR_STR => "ADD_CHAR_STR", + Self::SUBTRACT_INT => "SUBTRACT_INT", + Self::SUBTRACT_FLOAT => "SUBTRACT_FLOAT", + Self::SUBTRACT_BYTE => "SUBTRACT_BYTE", + Self::MULTIPLY_INT => "MULTIPLY_INT", + Self::MULTIPLY_FLOAT => "MULTIPLY_FLOAT", + Self::MULTIPLY_BYTE => "MULTIPLY_BYTE", + Self::DIVIDE_INT => "DIVIDE_INT", + Self::DIVIDE_FLOAT => "DIVIDE_FLOAT", + Self::DIVIDE_BYTE => "DIVIDE_BYTE", + Self::MODULO_INT => "MODULO_INT", + Self::MODULO_FLOAT => "MODULO_FLOAT", + Self::MODULO_BYTE => "MODULO_BYTE", + Self::EQUAL_INT => "EQUAL_INT", + Self::EQUAL_FLOAT => "EQUAL_FLOAT", + Self::EQUAL_BYTE => "EQUAL_BYTE", + Self::EQUAL_STR => "EQUAL_STR", + Self::EQUAL_CHAR => "EQUAL_CHAR", + Self::EQUAL_STR_CHAR => "EQUAL_STR_CHAR", + Self::EQUAL_CHAR_STR => "EQUAL_CHAR_STR", + Self::EQUAL_BOOL => "EQUAL_BOOL", + Self::LESS_INT => "LESS_INT", + Self::LESS_FLOAT => "LESS_FLOAT", + Self::LESS_BYTE => "LESS_BYTE", + Self::LESS_STR => "LESS_STR", + Self::LESS_CHAR => "LESS_CHAR", + Self::LESS_EQUAL_INT => "LESS_EQUAL_INT", + Self::LESS_EQUAL_FLOAT => "LESS_EQUAL_FLOAT", + Self::LESS_EQUAL_BYTE => "LESS_EQUAL_BYTE", + Self::LESS_EQUAL_STR => "LESS_EQUAL_STR", + Self::LESS_EQUAL_CHAR => "LESS_EQUAL_CHAR", + Self::NEGATE_INT => "NEGATE_INT", + Self::NEGATE_FLOAT => "NEGATE_FLOAT", + Self::NOT => "NOT", 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", @@ -68,6 +157,51 @@ impl Operation { } } + pub fn is_math(self) -> bool { + matches!( + self, + Operation::ADD_INT + | Operation::ADD_FLOAT + | Operation::ADD_BYTE + | Operation::SUBTRACT_INT + | Operation::SUBTRACT_FLOAT + | Operation::SUBTRACT_BYTE + | Operation::MULTIPLY_INT + | Operation::MULTIPLY_FLOAT + | Operation::MULTIPLY_BYTE + | Operation::DIVIDE_INT + | Operation::DIVIDE_FLOAT + | Operation::DIVIDE_BYTE + | Operation::MODULO_INT + | Operation::MODULO_FLOAT + | Operation::MODULO_BYTE + ) + } + + pub fn is_comparison(self) -> bool { + matches!( + self, + Operation::EQUAL_INT + | Operation::EQUAL_FLOAT + | Operation::EQUAL_BYTE + | Operation::EQUAL_STR + | Operation::EQUAL_CHAR + | Operation::EQUAL_STR_CHAR + | Operation::EQUAL_CHAR_STR + | Operation::EQUAL_BOOL + | Operation::LESS_INT + | Operation::LESS_FLOAT + | Operation::LESS_BYTE + | Operation::LESS_STR + | Operation::LESS_CHAR + | Operation::LESS_EQUAL_INT + | Operation::LESS_EQUAL_FLOAT + | Operation::LESS_EQUAL_BYTE + | Operation::LESS_EQUAL_STR + | Operation::LESS_EQUAL_CHAR + ) + } + pub fn panic_from_unknown_code(code: u8) -> ! { panic!("Unknown operation code: {code}"); } diff --git a/dust-lang/src/instruction/point.rs b/dust-lang/src/instruction/point.rs index fe4d43b..eb6e459 100644 --- a/dust-lang/src/instruction/point.rs +++ b/dust-lang/src/instruction/point.rs @@ -2,9 +2,11 @@ use std::fmt::{self, Display, Formatter}; use crate::{Instruction, Operation}; +use super::InstructionBuilder; + pub struct Point { - pub from: u8, - pub to: u8, + pub from: u16, + pub to: u16, } impl From for Point { @@ -16,6 +18,22 @@ impl From for Point { } } +impl From for Instruction { + fn from(r#move: Point) -> Self { + let operation = Operation::POINT; + let b_field = r#move.from; + let c_field = r#move.to; + + InstructionBuilder { + operation, + b_field, + c_field, + ..Default::default() + } + .build() + } +} + impl Display for Point { fn fmt(&self, f: &mut Formatter) -> fmt::Result { let Point { from, to } = self; @@ -23,13 +41,3 @@ impl Display for Point { write!(f, "{from} -> {to}") } } - -impl From for Instruction { - fn from(r#move: Point) -> Self { - let operation = Operation::POINT; - let b = r#move.from; - let c = r#move.to; - - Instruction::new(operation, 0, b, c, false, false, false) - } -} diff --git a/dust-lang/src/instruction/return.rs b/dust-lang/src/instruction/return.rs index b3c52c5..e1c9040 100644 --- a/dust-lang/src/instruction/return.rs +++ b/dust-lang/src/instruction/return.rs @@ -1,8 +1,10 @@ use crate::{Instruction, Operation}; +use super::InstructionBuilder; + pub struct Return { pub should_return_value: bool, - pub return_register: u8, + pub return_register: u16, } impl From for Return { @@ -20,9 +22,15 @@ impl From for Return { impl From for Instruction { fn from(r#return: Return) -> Self { let operation = Operation::RETURN; - let b = r#return.should_return_value as u8; - let c = r#return.return_register; + let b_field = r#return.should_return_value as u16; + let c_field = r#return.return_register; - Instruction::new(operation, 0, b, c, false, false, false) + InstructionBuilder { + operation, + b_field, + c_field, + ..Default::default() + } + .build() } } diff --git a/dust-lang/src/instruction/set_local.rs b/dust-lang/src/instruction/set_local.rs index 6e6ebf1..57b48a2 100644 --- a/dust-lang/src/instruction/set_local.rs +++ b/dust-lang/src/instruction/set_local.rs @@ -1,8 +1,12 @@ +use std::fmt::{self, Display, Formatter}; + use crate::{Instruction, Operation}; +use super::InstructionBuilder; + pub struct SetLocal { - pub register_index: u8, - pub local_index: u8, + pub register_index: u16, + pub local_index: u16, } impl From for SetLocal { @@ -20,9 +24,26 @@ impl From for SetLocal { impl From for Instruction { fn from(set_local: SetLocal) -> Self { let operation = Operation::SET_LOCAL; - let b = set_local.register_index; - let c = set_local.local_index; + let b_field = set_local.register_index; + let c_field = set_local.local_index; - Instruction::new(operation, 0, b, c, false, false, false) + InstructionBuilder { + operation, + b_field, + c_field, + ..Default::default() + } + .build() + } +} + +impl Display for SetLocal { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let SetLocal { + register_index, + local_index, + } = self; + + write!(f, "L{local_index} = R{register_index}") } } diff --git a/dust-lang/src/instruction/subtract.rs b/dust-lang/src/instruction/subtract.rs deleted file mode 100644 index 3923719..0000000 --- a/dust-lang/src/instruction/subtract.rs +++ /dev/null @@ -1,31 +0,0 @@ -use crate::{Argument, Instruction, Operation}; - -pub struct Subtract { - pub destination: u8, - pub left: Argument, - pub right: Argument, -} - -impl From for Subtract { - fn from(instruction: Instruction) -> Self { - let destination = instruction.a_field(); - let (left, right) = instruction.b_and_c_as_arguments(); - - Subtract { - destination, - left, - right, - } - } -} - -impl From for Instruction { - fn from(subtract: Subtract) -> Self { - let operation = Operation::SUBTRACT; - let a = subtract.destination; - let (b, b_is_constant) = subtract.left.as_index_and_constant_flag(); - let (c, c_is_constant) = subtract.right.as_index_and_constant_flag(); - - Instruction::new(operation, a, b, c, b_is_constant, c_is_constant, false) - } -} diff --git a/dust-lang/src/instruction/subtract_byte.rs b/dust-lang/src/instruction/subtract_byte.rs new file mode 100644 index 0000000..76de9a7 --- /dev/null +++ b/dust-lang/src/instruction/subtract_byte.rs @@ -0,0 +1,54 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct SubtractByte { + pub destination: u16, + pub left: Operand, + pub right: Operand, +} + +impl From for SubtractByte { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + SubtractByte { + destination, + left, + right, + } + } +} + +impl From for Instruction { + fn from(subtract_byte: SubtractByte) -> Self { + let operation = Operation::SUBTRACT_BYTE; + let a_field = subtract_byte.destination; + let (b_field, b_is_constant) = subtract_byte.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = subtract_byte.right.as_index_and_constant_flag(); + + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for SubtractByte { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let SubtractByte { + destination, + left, + right, + } = self; + + write!(f, "R{} = {} - {}", destination, left, right) + } +} diff --git a/dust-lang/src/instruction/subtract_float.rs b/dust-lang/src/instruction/subtract_float.rs new file mode 100644 index 0000000..d806a49 --- /dev/null +++ b/dust-lang/src/instruction/subtract_float.rs @@ -0,0 +1,54 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct SubtractFloat { + pub destination: u16, + pub left: Operand, + pub right: Operand, +} + +impl From for SubtractFloat { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + SubtractFloat { + destination, + left, + right, + } + } +} + +impl From for Instruction { + fn from(subtract_float: SubtractFloat) -> Self { + let operation = Operation::SUBTRACT_FLOAT; + let a_field = subtract_float.destination; + let (b_field, b_is_constant) = subtract_float.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = subtract_float.right.as_index_and_constant_flag(); + + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for SubtractFloat { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let SubtractFloat { + destination, + left, + right, + } = self; + + write!(f, "R{} = {} - {}", destination, left, right) + } +} diff --git a/dust-lang/src/instruction/subtract_int.rs b/dust-lang/src/instruction/subtract_int.rs new file mode 100644 index 0000000..b9b2ffd --- /dev/null +++ b/dust-lang/src/instruction/subtract_int.rs @@ -0,0 +1,54 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation}; + +pub struct SubtractInt { + pub destination: u16, + pub left: Operand, + pub right: Operand, +} + +impl From for SubtractInt { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let (left, right) = instruction.b_and_c_as_operands(); + + SubtractInt { + destination, + left, + right, + } + } +} + +impl From for Instruction { + fn from(subtract_int: SubtractInt) -> Self { + let operation = Operation::SUBTRACT_INT; + let a_field = subtract_int.destination; + let (b_field, b_is_constant) = subtract_int.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = subtract_int.right.as_index_and_constant_flag(); + + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + b_is_constant, + c_is_constant, + ..Default::default() + } + .build() + } +} + +impl Display for SubtractInt { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let SubtractInt { + destination, + left, + right, + } = self; + + write!(f, "R{} = {} - {}", destination, left, right) + } +} diff --git a/dust-lang/src/instruction/test.rs b/dust-lang/src/instruction/test.rs index 138483a..62124dd 100644 --- a/dust-lang/src/instruction/test.rs +++ b/dust-lang/src/instruction/test.rs @@ -1,7 +1,9 @@ use crate::{Instruction, Operation}; +use super::InstructionBuilder; + pub struct Test { - pub operand_register: u8, + pub operand_register: u16, pub test_value: bool, } @@ -19,14 +21,15 @@ impl From for Test { impl From for Instruction { fn from(test: Test) -> Self { - Instruction::new( - Operation::TEST, - 0, - test.operand_register, - test.test_value as u8, - false, - false, - false, - ) + let b_field = test.operand_register; + let c_field = test.test_value as u16; + + InstructionBuilder { + operation: Operation::TEST, + b_field, + c_field, + ..Default::default() + } + .build() } } diff --git a/dust-lang/src/instruction/test_set.rs b/dust-lang/src/instruction/test_set.rs index 27a15e5..4ae8191 100644 --- a/dust-lang/src/instruction/test_set.rs +++ b/dust-lang/src/instruction/test_set.rs @@ -1,8 +1,10 @@ -use crate::{Argument, Instruction, Operation}; +use crate::{Instruction, Operand, Operation}; + +use super::InstructionBuilder; pub struct TestSet { - pub destination: u8, - pub argument: Argument, + pub destination: u16, + pub argument: Operand, pub test_value: bool, } @@ -23,10 +25,18 @@ impl From for TestSet { impl From for Instruction { fn from(test_set: TestSet) -> Self { let operation = Operation::TEST; - let a = test_set.destination; - let (b, b_is_constant) = test_set.argument.as_index_and_constant_flag(); - let c = test_set.test_value as u8; + let a_field = test_set.destination; + let (b_field, b_is_constant) = test_set.argument.as_index_and_constant_flag(); + let c_field = test_set.test_value as u16; - Instruction::new(operation, a, b, c, b_is_constant, false, false) + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + b_is_constant, + ..Default::default() + } + .build() } } diff --git a/dust-lang/src/instruction/type_code.rs b/dust-lang/src/instruction/type_code.rs deleted file mode 100644 index 0e038ee..0000000 --- a/dust-lang/src/instruction/type_code.rs +++ /dev/null @@ -1,10 +0,0 @@ -pub struct TypeCode(pub u8); - -impl TypeCode { - const INTEGER: u8 = 0; - const FLOAT: u8 = 1; - const STRING: u8 = 2; - const BOOLEAN: u8 = 3; - const CHARACTER: u8 = 4; - const BYTE: u8 = 5; -} diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index f1e8dbd..bc6cb03 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -40,17 +40,17 @@ pub mod value; pub mod vm; pub use crate::chunk::{Chunk, Disassembler, Local, Scope}; -pub use crate::compiler::{compile, CompileError, Compiler}; +pub use crate::compiler::{CompileError, Compiler, compile}; pub use crate::dust_error::{AnnotatedError, DustError}; -pub use crate::instruction::{Argument, Instruction, InstructionData, Operation}; -pub use crate::lexer::{lex, LexError, Lexer}; +pub use crate::instruction::{Operand, Instruction, Operation}; +pub use crate::lexer::{LexError, Lexer, lex}; pub use crate::native_function::{NativeFunction, NativeFunctionError}; -pub use crate::r#type::{EnumType, FunctionType, StructType, Type, TypeConflict}; pub use crate::token::{Token, TokenKind, TokenOwned}; +pub use crate::r#type::{EnumType, FunctionType, StructType, Type, TypeConflict}; pub use crate::value::{ AbstractList, ConcreteValue, DustString, Function, RangeValue, Value, ValueError, }; -pub use crate::vm::{run, Pointer, Vm}; +pub use crate::vm::{Pointer, Vm, run}; use std::fmt::Display; diff --git a/dust-lang/src/native_function/assert.rs b/dust-lang/src/native_function/assert.rs index b748ee7..3cd7045 100644 --- a/dust-lang/src/native_function/assert.rs +++ b/dust-lang/src/native_function/assert.rs @@ -2,7 +2,7 @@ use std::{ops::Range, panic}; use crate::vm::ThreadData; -pub fn panic(data: &mut ThreadData, _: u8, argument_range: Range) -> bool { +pub fn panic(data: &mut ThreadData, _: u16, argument_range: Range) -> bool { let position = data.current_position(); let mut message = format!("Dust panic at {position}!"); diff --git a/dust-lang/src/native_function/io.rs b/dust-lang/src/native_function/io.rs index 696e5d5..89bf2b7 100644 --- a/dust-lang/src/native_function/io.rs +++ b/dust-lang/src/native_function/io.rs @@ -6,7 +6,7 @@ use crate::{ vm::{Register, ThreadData, get_next_action}, }; -pub fn read_line(data: &mut ThreadData, destination: u8, _argument_range: Range) -> bool { +pub fn read_line(data: &mut ThreadData, destination: u16, _argument_range: Range) -> bool { let mut buffer = String::new(); if stdin().read_line(&mut buffer).is_ok() { @@ -24,7 +24,7 @@ pub fn read_line(data: &mut ThreadData, destination: u8, _argument_range: Range< false } -pub fn write(data: &mut ThreadData, _: u8, argument_range: Range) -> bool { +pub fn write(data: &mut ThreadData, _: u16, argument_range: Range) -> bool { let mut stdout = stdout(); for register_index in argument_range { @@ -40,7 +40,7 @@ pub fn write(data: &mut ThreadData, _: u8, argument_range: Range) -> bool { false } -pub fn write_line(data: &mut ThreadData, _: u8, argument_range: Range) -> bool { +pub fn write_line(data: &mut ThreadData, _: u16, argument_range: Range) -> bool { let mut stdout = stdout().lock(); for register_index in argument_range { diff --git a/dust-lang/src/native_function/mod.rs b/dust-lang/src/native_function/mod.rs index 4917843..1926143 100644 --- a/dust-lang/src/native_function/mod.rs +++ b/dust-lang/src/native_function/mod.rs @@ -35,8 +35,8 @@ macro_rules! define_native_function { pub fn call( &self, data: &mut ThreadData, - destination: u8, - argument_range: Range, + destination: u16, + argument_range: Range, ) -> bool { match self { $( @@ -80,8 +80,8 @@ macro_rules! define_native_function { } } - impl From for NativeFunction { - fn from(bytes: u8) -> Self { + impl From for NativeFunction { + fn from(bytes: u16) -> Self { match bytes { $( $bytes => NativeFunction::$name, diff --git a/dust-lang/src/native_function/random.rs b/dust-lang/src/native_function/random.rs index f743b0b..1eae46a 100644 --- a/dust-lang/src/native_function/random.rs +++ b/dust-lang/src/native_function/random.rs @@ -7,7 +7,7 @@ use crate::{ vm::{Register, ThreadData, get_next_action}, }; -pub fn random_int(data: &mut ThreadData, destination: u8, argument_range: Range) -> bool { +pub fn random_int(data: &mut ThreadData, destination: u16, argument_range: Range) -> bool { let mut argument_range_iter = argument_range.into_iter(); let (min, max) = { let mut min = None; diff --git a/dust-lang/src/native_function/string.rs b/dust-lang/src/native_function/string.rs index 8d03c96..9e3546c 100644 --- a/dust-lang/src/native_function/string.rs +++ b/dust-lang/src/native_function/string.rs @@ -5,7 +5,7 @@ use crate::{ vm::{Register, ThreadData, get_next_action}, }; -pub fn to_string(data: &mut ThreadData, destination: u8, argument_range: Range) -> bool { +pub fn to_string(data: &mut ThreadData, destination: u16, argument_range: Range) -> bool { let argument_value = data.open_register_unchecked(argument_range.start); let argument_string = argument_value.display(data); let register = Register::Value(Value::Concrete(ConcreteValue::string(argument_string))); diff --git a/dust-lang/src/native_function/thread.rs b/dust-lang/src/native_function/thread.rs index 4786065..4b0cf85 100644 --- a/dust-lang/src/native_function/thread.rs +++ b/dust-lang/src/native_function/thread.rs @@ -10,7 +10,7 @@ use crate::{ vm::{Thread, ThreadData, get_next_action}, }; -fn start_thread(data: &mut ThreadData, argument_range: Range) -> JoinHandle<()> { +fn start_thread(data: &mut ThreadData, argument_range: Range) -> JoinHandle<()> { let mut argument_range_iter = argument_range.into_iter(); let function_argument = { loop { @@ -56,7 +56,7 @@ fn start_thread(data: &mut ThreadData, argument_range: Range) -> JoinHandle< .expect("Critical VM Error: Failed to spawn thread") } -pub fn spawn(data: &mut ThreadData, _: u8, argument_range: Range) -> bool { +pub fn spawn(data: &mut ThreadData, _: u16, argument_range: Range) -> bool { let _ = start_thread(data, argument_range); data.next_action = get_next_action(data); diff --git a/dust-lang/src/type.rs b/dust-lang/src/type.rs index e6264c4..1258526 100644 --- a/dust-lang/src/type.rs +++ b/dust-lang/src/type.rs @@ -273,13 +273,13 @@ impl Ord for Type { #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct FunctionType { - pub type_parameters: Vec, - pub value_parameters: Vec<(u8, Type)>, + pub type_parameters: Vec, + pub value_parameters: Vec<(u16, Type)>, pub return_type: Type, } impl FunctionType { - pub fn new>, U: Into>>( + pub fn new>, U: Into>>( type_parameters: T, value_parameters: U, return_type: Type, diff --git a/dust-lang/src/value/function.rs b/dust-lang/src/value/function.rs index fc74575..f331dcf 100644 --- a/dust-lang/src/value/function.rs +++ b/dust-lang/src/value/function.rs @@ -8,7 +8,7 @@ use super::DustString; pub struct Function { pub name: Option, pub r#type: FunctionType, - pub prototype_index: u8, + pub prototype_index: u16, } impl Display for Function { diff --git a/dust-lang/src/vm/function_call.rs b/dust-lang/src/vm/function_call.rs index c9cbe84..7db37aa 100644 --- a/dust-lang/src/vm/function_call.rs +++ b/dust-lang/src/vm/function_call.rs @@ -11,12 +11,12 @@ use super::Register; pub struct FunctionCall { pub chunk: Arc, pub ip: usize, - pub return_register: u8, + pub return_register: u16, pub registers: Vec, } impl FunctionCall { - pub fn new(chunk: Arc, return_register: u8) -> Self { + pub fn new(chunk: Arc, return_register: u16) -> Self { let register_count = chunk.register_count; Self { diff --git a/dust-lang/src/vm/mod.rs b/dust-lang/src/vm/mod.rs index 9e0ec9b..4cb6b1d 100644 --- a/dust-lang/src/vm/mod.rs +++ b/dust-lang/src/vm/mod.rs @@ -53,7 +53,7 @@ impl Vm { let _ = tx.send(value_option); }); - rx.recv().unwrap() + rx.recv().unwrap_or(None) } } @@ -76,9 +76,9 @@ impl Display for Register { #[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] pub enum Pointer { - Register(u8), - Constant(u8), - Stack(usize, u8), + Register(u16), + Constant(u16), + Stack(usize, u16), } impl Display for Pointer { diff --git a/dust-lang/src/vm/run_action.rs b/dust-lang/src/vm/run_action.rs index 5bb6cb4..d97f0d7 100644 --- a/dust-lang/src/vm/run_action.rs +++ b/dust-lang/src/vm/run_action.rs @@ -1,11 +1,10 @@ use tracing::trace; use crate::{ - AbstractList, Argument, ConcreteValue, Instruction, Type, Value, + AbstractList, ConcreteValue, Instruction, Operand, Type, Value, instruction::{ - Add, Call, CallNative, Close, Divide, Equal, GetLocal, Jump, Less, LessEqual, LoadBoolean, - LoadConstant, LoadFunction, LoadList, LoadSelf, Modulo, Multiply, Negate, Not, Point, - Return, SetLocal, Subtract, Test, TestSet, + Call, CallNative, Close, GetLocal, Jump, LoadBoolean, LoadConstant, LoadFunction, LoadList, + LoadSelf, Not, Point, Return, SetLocal, Test, TestSet, }, vm::FunctionCall, }; @@ -145,6 +144,7 @@ pub fn load_list(instruction: Instruction, data: &mut ThreadData) -> bool { let LoadList { destination, start_register, + jump_next, } = instruction.into(); let mut item_pointers = Vec::with_capacity((destination - start_register) as usize); let mut item_type = Type::Any; @@ -186,6 +186,7 @@ pub fn load_function(instruction: Instruction, data: &mut ThreadData) -> bool { let LoadFunction { destination, prototype_index, + jump_next, } = instruction.into(); let prototype_index = prototype_index as usize; let current_call = data.call_stack.last_mut_unchecked(); @@ -201,7 +202,10 @@ pub fn load_function(instruction: Instruction, data: &mut ThreadData) -> bool { } pub fn load_self(instruction: Instruction, data: &mut ThreadData) -> bool { - let LoadSelf { destination } = instruction.into(); + let LoadSelf { + destination, + jump_next, + } = instruction.into(); let current_call = data.call_stack.last_mut_unchecked(); let prototype = ¤t_call.chunk; let function = prototype.as_function(); @@ -397,8 +401,8 @@ pub fn test_set(instruction: Instruction, data: &mut ThreadData) -> bool { if boolean == test_value { } else { let pointer = match argument { - Argument::Constant(constant_index) => Pointer::Constant(constant_index), - Argument::Register(register_index) => Pointer::Register(register_index), + Operand::Constant(constant_index) => Pointer::Constant(constant_index), + Operand::Register(register_index) => Pointer::Register(register_index), }; let register = Register::Pointer(pointer); diff --git a/dust-lang/src/vm/thread.rs b/dust-lang/src/vm/thread.rs index 35c9811..30b84a6 100644 --- a/dust-lang/src/vm/thread.rs +++ b/dust-lang/src/vm/thread.rs @@ -2,7 +2,7 @@ use std::{mem::replace, sync::Arc, thread::JoinHandle}; use tracing::{info, trace}; -use crate::{Argument, Chunk, DustString, Span, Value, vm::FunctionCall}; +use crate::{Chunk, DustString, Operand, Span, Value, vm::FunctionCall}; use super::{Pointer, Register, RunAction, Stack}; @@ -72,7 +72,7 @@ impl Thread { pub struct ThreadData { pub call_stack: Stack, pub next_action: RunAction, - pub return_value_index: Option, + pub return_value_index: Option, pub spawned_threads: Vec>, } @@ -105,7 +105,7 @@ impl ThreadData { } } - pub fn get_register_unchecked(&self, register_index: u8) -> &Register { + pub fn get_register_unchecked(&self, register_index: u16) -> &Register { trace!("Get R{register_index}"); let register_index = register_index as usize; @@ -122,13 +122,13 @@ impl ThreadData { } } - pub fn set_register(&mut self, to_register: u8, register: Register) { + pub fn set_register(&mut self, to_register: u16, register: Register) { let to_register = to_register as usize; self.call_stack.last_mut_unchecked().registers[to_register] = register; } - pub fn open_register_unchecked(&self, register_index: u8) -> &Value { + pub fn open_register_unchecked(&self, register_index: u16) -> &Value { let register_index = register_index as usize; let register = if cfg!(debug_assertions) { @@ -151,7 +151,7 @@ impl ThreadData { } } - pub fn open_register_allow_empty_unchecked(&self, register_index: u8) -> Option<&Value> { + pub fn open_register_allow_empty_unchecked(&self, register_index: u16) -> Option<&Value> { trace!("Open R{register_index}"); let register = self.get_register_unchecked(register_index); @@ -165,7 +165,7 @@ impl ThreadData { } } - pub fn empty_register_or_clone_constant_unchecked(&mut self, register_index: u8) -> Value { + pub fn empty_register_or_clone_constant_unchecked(&mut self, register_index: u16) -> Value { let register_index = register_index as usize; let old_register = replace( &mut self.call_stack.last_mut_unchecked().registers[register_index], @@ -202,7 +202,7 @@ impl ThreadData { } } - pub fn clone_register_value_or_constant_unchecked(&self, register_index: u8) -> Value { + pub fn clone_register_value_or_constant_unchecked(&self, register_index: u16) -> Value { let register = self.get_register_unchecked(register_index); match register { @@ -232,14 +232,14 @@ impl ThreadData { } /// DRY helper to get a value from an Argument - pub fn get_argument_unchecked(&self, argument: Argument) -> &Value { + pub fn get_argument_unchecked(&self, argument: Operand) -> &Value { match argument { - Argument::Constant(constant_index) => self.get_constant_unchecked(constant_index), - Argument::Register(register_index) => self.open_register_unchecked(register_index), + Operand::Constant(constant_index) => self.get_constant_unchecked(constant_index), + Operand::Register(register_index) => self.open_register_unchecked(register_index), } } - pub fn get_constant_unchecked(&self, constant_index: u8) -> &Value { + pub fn get_constant_unchecked(&self, constant_index: u16) -> &Value { let constant_index = constant_index as usize; if cfg!(debug_assertions) { @@ -255,7 +255,7 @@ impl ThreadData { } } - pub fn get_local_register(&self, local_index: u8) -> u8 { + pub fn get_local_register(&self, local_index: u16) -> u16 { let local_index = local_index as usize; let chunk = &self.call_stack.last_unchecked().chunk; diff --git a/dust-lang/tests/basic.rs b/dust-lang/tests/basic.rs index 442592c..ec728e6 100644 --- a/dust-lang/tests/basic.rs +++ b/dust-lang/tests/basic.rs @@ -61,11 +61,11 @@ fn parentheses_precedence() { }, vec![ ( - Instruction::add(0, Argument::Constant(0), Argument::Constant(1)), + Instruction::add(0, Operand::Constant(0), Operand::Constant(1)), Span(3, 4) ), ( - Instruction::multiply(1, Argument::Register(0), Argument::Constant(2)), + Instruction::multiply(1, Operand::Register(0), Operand::Constant(2)), Span(8, 9) ), (Instruction::r#return(true), Span(11, 11)), @@ -97,19 +97,19 @@ fn math_operator_precedence() { }, vec![ ( - Instruction::add(0, Argument::Constant(0), Argument::Constant(1)), + Instruction::add(0, Operand::Constant(0), Operand::Constant(1)), Span(2, 3) ), ( - Instruction::multiply(1, Argument::Constant(2), Argument::Constant(3)), + Instruction::multiply(1, Operand::Constant(2), Operand::Constant(3)), Span(10, 11) ), ( - Instruction::divide(2, Argument::Register(1), Argument::Constant(4)), + Instruction::divide(2, Operand::Register(1), Operand::Constant(4)), Span(14, 15) ), ( - Instruction::subtract(3, Argument::Register(0), Argument::Register(2)), + Instruction::subtract(3, Operand::Register(0), Operand::Register(2)), Span(6, 7) ), (Instruction::r#return(true), Span(17, 17)), diff --git a/dust-lang/tests/comparison.rs b/dust-lang/tests/comparison.rs index ae19d6c..677a646 100644 --- a/dust-lang/tests/comparison.rs +++ b/dust-lang/tests/comparison.rs @@ -15,7 +15,7 @@ fn equal() { }, vec![ ( - Instruction::equal(0, true, Argument::Constant(0), Argument::Constant(1)), + Instruction::equal(0, true, Operand::Constant(0), Operand::Constant(1)), Span(2, 4) ), (Instruction::r#return(true), Span(6, 6)), @@ -43,7 +43,7 @@ fn greater() { }, vec![ ( - Instruction::less_equal(0, false, Argument::Constant(0), Argument::Constant(1)), + Instruction::less_equal(0, false, Operand::Constant(0), Operand::Constant(1)), Span(2, 3) ), (Instruction::r#return(true), Span(5, 5)), @@ -71,7 +71,7 @@ fn greater_than_or_equal() { }, vec![ ( - Instruction::less(0, false, Argument::Constant(0), Argument::Constant(1)), + Instruction::less(0, false, Operand::Constant(0), Operand::Constant(1)), Span(2, 4) ), (Instruction::r#return(true), Span(6, 6)), @@ -99,7 +99,7 @@ fn less_than() { }, vec![ ( - Instruction::less(0, true, Argument::Constant(0), Argument::Constant(1)), + Instruction::less(0, true, Operand::Constant(0), Operand::Constant(1)), Span(2, 3) ), (Instruction::r#return(true), Span(5, 5)), @@ -127,7 +127,7 @@ fn less_than_or_equal() { }, vec![ ( - Instruction::less_equal(0, true, Argument::Constant(0), Argument::Constant(1)), + Instruction::less_equal(0, true, Operand::Constant(0), Operand::Constant(1)), Span(2, 4) ), (Instruction::r#return(true), Span(6, 6)), @@ -155,7 +155,7 @@ fn not_equal() { }, vec![ ( - Instruction::equal(0, false, Argument::Constant(0), Argument::Constant(1)), + Instruction::equal(0, false, Operand::Constant(0), Operand::Constant(1)), Span(2, 4) ), (Instruction::r#return(true), Span(6, 6)), diff --git a/dust-lang/tests/functions.rs b/dust-lang/tests/functions.rs index 1ffdcfa..181529d 100644 --- a/dust-lang/tests/functions.rs +++ b/dust-lang/tests/functions.rs @@ -20,7 +20,7 @@ fn function() { }, vec![ ( - Instruction::add(2, Argument::Register(0), Argument::Register(1)), + Instruction::add(2, Operand::Register(0), Operand::Register(1)), Span(30, 31) ), (Instruction::r#return(true), Span(34, 35)), @@ -51,7 +51,7 @@ fn function_call() { (Instruction::load_constant(0, 0, false), Span(0, 35)), (Instruction::load_constant(1, 1, false), Span(36, 37)), (Instruction::load_constant(2, 2, false), Span(39, 40)), - (Instruction::call(3, Argument::Constant(0), 2), Span(35, 41)), + (Instruction::call(3, Operand::Constant(0), 2), Span(35, 41)), (Instruction::r#return(true), Span(41, 41)), ], vec![ @@ -64,7 +64,7 @@ fn function_call() { }, vec![ ( - Instruction::add(2, Argument::Register(0), Argument::Register(1)), + Instruction::add(2, Operand::Register(0), Operand::Register(1)), Span(30, 31) ), (Instruction::r#return(true), Span(34, 35)), @@ -112,7 +112,7 @@ fn function_declaration() { }, vec![ ( - Instruction::add(2, Argument::Register(0), Argument::Register(1)), + Instruction::add(2, Operand::Register(0), Operand::Register(1)), Span(35, 36) ), (Instruction::r#return(true), Span(39, 40)), diff --git a/dust-lang/tests/lists.rs b/dust-lang/tests/lists.rs index b8d8aac..adb7ba4 100644 --- a/dust-lang/tests/lists.rs +++ b/dust-lang/tests/lists.rs @@ -80,15 +80,15 @@ fn list_with_complex_expression() { vec![ (Instruction::load_constant(0, 0, false), Span(1, 2)), ( - Instruction::add(1, Argument::Constant(1), Argument::Constant(2)), + Instruction::add(1, Operand::Constant(1), Operand::Constant(2)), Span(6, 7) ), ( - Instruction::multiply(2, Argument::Constant(3), Argument::Constant(4)), + Instruction::multiply(2, Operand::Constant(3), Operand::Constant(4)), Span(14, 15) ), ( - Instruction::subtract(3, Argument::Register(1), Argument::Register(2)), + Instruction::subtract(3, Operand::Register(1), Operand::Register(2)), Span(10, 11) ), (Instruction::close(1, 3), Span(17, 18)), @@ -131,7 +131,7 @@ fn list_with_simple_expression() { vec![ (Instruction::load_constant(0, 0, false), Span(1, 2)), ( - Instruction::add(1, Argument::Constant(1), Argument::Constant(2)), + Instruction::add(1, Operand::Constant(1), Operand::Constant(2)), Span(6, 7) ), (Instruction::load_constant(2, 3, false), Span(11, 12)), diff --git a/dust-lang/tests/loops.rs b/dust-lang/tests/loops.rs index 252478c..5c7d121 100644 --- a/dust-lang/tests/loops.rs +++ b/dust-lang/tests/loops.rs @@ -16,12 +16,12 @@ fn r#while() { vec![ (Instruction::load_constant(0, 0, false), Span(12, 13)), ( - Instruction::less(0, true, Argument::Register(0), Argument::Constant(2)), + Instruction::less(0, true, Operand::Register(0), Operand::Constant(2)), Span(23, 24) ), (Instruction::jump(2, true), Span(41, 42)), ( - Instruction::add(0, Argument::Register(0), Argument::Constant(3)), + Instruction::add(0, Operand::Register(0), Operand::Constant(3)), Span(35, 36) ), (Instruction::jump(3, false), Span(41, 42)), diff --git a/dust-lang/tests/math/divide.rs b/dust-lang/tests/math/divide.rs index d81dfb8..9f40492 100644 --- a/dust-lang/tests/math/divide.rs +++ b/dust-lang/tests/math/divide.rs @@ -15,7 +15,7 @@ fn divide_bytes() { }, vec![ ( - Instruction::divide(0, Argument::Constant(0), Argument::Constant(1)), + Instruction::divide(0, Operand::Constant(0), Operand::Constant(1)), Span(5, 6) ), (Instruction::r#return(true), Span(11, 11)) @@ -43,7 +43,7 @@ fn divide_floats() { }, vec![ ( - Instruction::divide(0, Argument::Constant(0), Argument::Constant(0)), + Instruction::divide(0, Operand::Constant(0), Operand::Constant(0)), Span(4, 5) ), (Instruction::r#return(true), Span(9, 9)) @@ -71,7 +71,7 @@ fn divide_integers() { }, vec![ ( - Instruction::divide(0, Argument::Constant(0), Argument::Constant(0)), + Instruction::divide(0, Operand::Constant(0), Operand::Constant(0)), Span(2, 3) ), (Instruction::r#return(true), Span(5, 5)) diff --git a/dust-lang/tests/math/divide_assign.rs b/dust-lang/tests/math/divide_assign.rs index 943feee..7e44d83 100644 --- a/dust-lang/tests/math/divide_assign.rs +++ b/dust-lang/tests/math/divide_assign.rs @@ -16,7 +16,7 @@ fn divide_assign() { vec![ (Instruction::load_constant(0, 0, false), Span(12, 13)), ( - Instruction::divide(0, Argument::Register(0), Argument::Constant(0)), + Instruction::divide(0, Operand::Register(0), Operand::Constant(0)), Span(17, 19) ), (Instruction::get_local(1, 0), Span(23, 24)), diff --git a/dust-lang/tests/math/modulo.rs b/dust-lang/tests/math/modulo.rs index b1ee83e..d803338 100644 --- a/dust-lang/tests/math/modulo.rs +++ b/dust-lang/tests/math/modulo.rs @@ -15,7 +15,7 @@ fn modulo_floats() { }, vec![ ( - Instruction::modulo(0, Argument::Constant(0), Argument::Constant(0)), + Instruction::modulo(0, Operand::Constant(0), Operand::Constant(0)), Span(4, 5) ), (Instruction::r#return(true), Span(9, 9)) @@ -43,7 +43,7 @@ fn modulo_integers() { }, vec![ ( - Instruction::modulo(0, Argument::Constant(0), Argument::Constant(0)), + Instruction::modulo(0, Operand::Constant(0), Operand::Constant(0)), Span(2, 3) ), (Instruction::r#return(true), Span(5, 5)) diff --git a/dust-lang/tests/math/multiply.rs b/dust-lang/tests/math/multiply.rs index a3241c0..f54f044 100644 --- a/dust-lang/tests/math/multiply.rs +++ b/dust-lang/tests/math/multiply.rs @@ -15,7 +15,7 @@ fn multiply_floats() { }, vec![ ( - Instruction::multiply(0, Argument::Constant(0), Argument::Constant(0)), + Instruction::multiply(0, Operand::Constant(0), Operand::Constant(0)), Span(4, 5) ), (Instruction::r#return(true), Span(9, 9)), @@ -43,7 +43,7 @@ fn multiply_integers() { }, vec![ ( - Instruction::multiply(0, Argument::Constant(0), Argument::Constant(1)), + Instruction::multiply(0, Operand::Constant(0), Operand::Constant(1)), Span(2, 3) ), (Instruction::r#return(true), Span(5, 5)), diff --git a/dust-lang/tests/math/multiply_assign.rs b/dust-lang/tests/math/multiply_assign.rs index ec6f87d..065bd24 100644 --- a/dust-lang/tests/math/multiply_assign.rs +++ b/dust-lang/tests/math/multiply_assign.rs @@ -16,7 +16,7 @@ fn multiply_assign() { vec![ (Instruction::load_constant(0, 0, false), Span(12, 13)), ( - Instruction::multiply(0, Argument::Register(0), Argument::Constant(2)), + Instruction::multiply(0, Operand::Register(0), Operand::Constant(2)), Span(17, 19) ), (Instruction::get_local(1, 0), Span(22, 23)), diff --git a/dust-lang/tests/math/subtract.rs b/dust-lang/tests/math/subtract.rs index 2fc5b84..44f7b2d 100644 --- a/dust-lang/tests/math/subtract.rs +++ b/dust-lang/tests/math/subtract.rs @@ -15,7 +15,7 @@ fn subtract_floats() { }, vec![ ( - Instruction::subtract(0, Argument::Constant(0), Argument::Constant(0)), + Instruction::subtract(0, Operand::Constant(0), Operand::Constant(0)), Span(4, 5) ), (Instruction::r#return(true), Span(9, 9)), @@ -43,7 +43,7 @@ fn subtract_floats_saturate() { }, vec![ ( - Instruction::subtract(0, Argument::Constant(0), Argument::Constant(1)), + Instruction::subtract(0, Operand::Constant(0), Operand::Constant(1)), Span(25, 26) ), (Instruction::r#return(true), Span(36, 36)), @@ -74,7 +74,7 @@ fn subtract_integers() { }, vec![ ( - Instruction::subtract(0, Argument::Constant(0), Argument::Constant(1)), + Instruction::subtract(0, Operand::Constant(0), Operand::Constant(1)), Span(2, 3) ), (Instruction::r#return(true), Span(5, 5)), @@ -102,7 +102,7 @@ fn subtract_integers_saturate() { }, vec![ ( - Instruction::subtract(0, Argument::Constant(0), Argument::Constant(1)), + Instruction::subtract(0, Operand::Constant(0), Operand::Constant(1)), Span(21, 22) ), (Instruction::r#return(true), Span(24, 24)), diff --git a/dust-lang/tests/math/subtract_assign.rs b/dust-lang/tests/math/subtract_assign.rs index 733eded..7b20cbf 100644 --- a/dust-lang/tests/math/subtract_assign.rs +++ b/dust-lang/tests/math/subtract_assign.rs @@ -16,7 +16,7 @@ fn subtract_assign() { vec![ (Instruction::load_constant(0, 0, false), Span(12, 14)), ( - Instruction::subtract(0, Argument::Register(0), Argument::Constant(2)), + Instruction::subtract(0, Operand::Register(0), Operand::Constant(2)), Span(18, 20) ), (Instruction::get_local(1, 0), Span(24, 25)), diff --git a/dust-lang/tests/unary_operations.rs b/dust-lang/tests/unary_operations.rs index c04486e..3b44024 100644 --- a/dust-lang/tests/unary_operations.rs +++ b/dust-lang/tests/unary_operations.rs @@ -14,7 +14,7 @@ fn negate() { return_type: Type::Integer, }, vec![ - (Instruction::negate(0, Argument::Constant(0)), Span(0, 1)), + (Instruction::negate(0, Operand::Constant(0)), Span(0, 1)), (Instruction::r#return(true), Span(5, 5)), ], vec![ConcreteValue::Integer(42)], @@ -40,7 +40,7 @@ fn not() { }, vec![ (Instruction::load_boolean(0, true, false), Span(1, 5)), - (Instruction::not(1, Argument::Register(0)), Span(0, 1)), + (Instruction::not(1, Operand::Register(0)), Span(0, 1)), (Instruction::r#return(true), Span(5, 5)), ], vec![],