diff --git a/dust-lang/src/chunk/constant_table.rs b/dust-lang/src/chunk/constant_table.rs deleted file mode 100644 index 4c0c1ed..0000000 --- a/dust-lang/src/chunk/constant_table.rs +++ /dev/null @@ -1,62 +0,0 @@ -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 b9dd48c..817f4e2 100644 --- a/dust-lang/src/chunk/disassembler.rs +++ b/dust-lang/src/chunk/disassembler.rs @@ -43,14 +43,14 @@ use std::io::{self, Write}; use colored::{ColoredString, Colorize}; -use crate::{Chunk, Local, Type}; +use crate::{Chunk, Local}; const INSTRUCTION_COLUMNS: [(&str, usize); 4] = - [("i", 5), ("POSITION", 12), ("OPERATION", 17), ("INFO", 24)]; + [("i", 5), ("POSITION", 12), ("OPERATION", 17), ("INFO", 36)]; const INSTRUCTION_BORDERS: [&str; 3] = [ - "╭─────┬────────────┬─────────────────┬────────────────────────╮", - "├─────┼────────────┼─────────────────┼────────────────────────┤", - "╰─────┴────────────┴─────────────────┴────────────────────────╯", + "╭─────┬────────────┬─────────────────┬────────────────────────────────────╮", + "├─────┼────────────┼─────────────────┼────────────────────────────────────┤", + "╰─────┴────────────┴─────────────────┴────────────────────────────────────╯", ]; const LOCAL_COLUMNS: [(&str, usize); 5] = [ @@ -286,7 +286,7 @@ impl<'a, W: Write> Disassembler<'a, W> { .unwrap_or("stripped".to_string()); let operation = instruction.operation().to_string(); let info = instruction.disassembly_info(); - let row = format!("│{index:^5}│{position:^12}│{operation:^17}│{info:^24}│"); + let row = format!("│{index:^5}│{position:^12}│{operation:^17}│{info:^36}│"); self.write_center_border(&row)?; } @@ -322,7 +322,6 @@ 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()); @@ -353,88 +352,8 @@ impl<'a, W: Write> Disassembler<'a, W> { self.write_center_border(&column_name_line)?; self.write_center_border(CONSTANT_BORDERS[1])?; - 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(); + for (index, value) in self.chunk.constants.iter().enumerate() { + let type_display = value.r#type().to_string(); let value_display = { let mut value_string = value.to_string(); @@ -455,7 +374,7 @@ impl<'a, W: Write> Disassembler<'a, W> { } pub fn write_prototype_section(&mut self) -> Result<(), io::Error> { - self.write_center_border_bold("Prototypes")?; + self.write_center_border_bold("Functions")?; for chunk in &self.chunk.prototypes { chunk diff --git a/dust-lang/src/chunk/mod.rs b/dust-lang/src/chunk/mod.rs index 29f68b7..2944767 100644 --- a/dust-lang/src/chunk/mod.rs +++ b/dust-lang/src/chunk/mod.rs @@ -13,12 +13,10 @@ //! [`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; @@ -29,7 +27,7 @@ use std::sync::Arc; use serde::{Deserialize, Serialize}; -use crate::{DustString, Function, FunctionType, Instruction, Span}; +use crate::{DustString, Function, FunctionType, Instruction, Span, Value}; /// Representation of a Dust program or function. /// @@ -41,7 +39,7 @@ pub struct Chunk { pub(crate) instructions: Vec, pub(crate) positions: Vec, - pub(crate) constants: ConstantTable, + pub(crate) constants: Vec, pub(crate) locals: Vec, pub(crate) prototypes: Vec>, @@ -56,7 +54,7 @@ impl Chunk { r#type: FunctionType, instructions: impl Into>, positions: impl Into>, - constants: ConstantTable, + constants: impl Into>, locals: impl Into>, prototypes: impl IntoIterator, ) -> Self { @@ -65,7 +63,7 @@ impl Chunk { r#type, instructions: instructions.into(), positions: positions.into(), - constants, + constants: constants.into(), locals: locals.into(), prototypes: prototypes.into_iter().map(Arc::new).collect(), register_count: 0, diff --git a/dust-lang/src/compiler/error.rs b/dust-lang/src/compiler/error.rs index 63aee4f..98eb619 100644 --- a/dust-lang/src/compiler/error.rs +++ b/dust-lang/src/compiler/error.rs @@ -104,6 +104,14 @@ pub enum CompileError { right_type: Type, position: Span, }, + CannotNegateType { + argument_type: Type, + position: Span, + }, + CannotNotType { + argument_type: Type, + position: Span, + }, CannotSubtractType { argument_type: Type, position: Span, @@ -182,6 +190,8 @@ impl AnnotatedError for CompileError { Self::CannotMutateImmutableVariable { .. } => "Cannot mutate immutable variable", Self::CannotMultiplyArguments { .. } => "Cannot multiply these types", Self::CannotMultiplyType { .. } => "Cannot multiply this type", + Self::CannotNegateType { .. } => "Cannot negate this type", + Self::CannotNotType { .. } => "Cannot apply \"not\" operation to this type", Self::CannotResolveRegisterType { .. } => "Cannot resolve register type", Self::CannotResolveVariableType { .. } => "Cannot resolve type", Self::CannotSubtractType { .. } => "Cannot subtract from this type", @@ -251,8 +261,10 @@ impl AnnotatedError for CompileError { right_position, } => { vec![( - format!("Type \"{left_type}\" cannot be added to type \"{right_type}\". Try converting one of the values to the other type."), - Span(left_position.0, right_position.1) + format!( + "Type \"{left_type}\" cannot be, added to type \"{right_type}\". Try converting one of the values to the other type." + ), + Span(left_position.0, right_position.1), )] } _ => Vec::with_capacity(0), diff --git a/dust-lang/src/compiler/mod.rs b/dust-lang/src/compiler/mod.rs index cb007b1..8df9d3a 100644 --- a/dust-lang/src/compiler/mod.rs +++ b/dust-lang/src/compiler/mod.rs @@ -35,8 +35,7 @@ use optimize::control_flow_register_consolidation; use crate::{ Chunk, ConcreteValue, DustError, DustString, FunctionType, Instruction, Lexer, Local, NativeFunction, Operand, Operation, Scope, Span, Token, TokenKind, Type, Value, - chunk::ConstantTable, - instruction::{GetLocal, Jump, LoadList}, + instruction::{CallNative, Close, GetLocal, Jump, LoadList, Return, SetLocal, TypeCode}, }; /// Compiles the input and returns a chunk. @@ -89,7 +88,7 @@ pub struct Compiler<'src> { /// Constants that have been compiled. These are assigned to the chunk when [`Compiler::finish`] /// is called. - constants: ConstantTable, + constants: Vec, /// Block-local variables and their types. The locals are assigned to the chunk when /// [`Compiler::finish`] is called. The types are discarded after compilation. @@ -145,7 +144,7 @@ impl<'src> Compiler<'src> { return_type: Type::None, }, instructions: Vec::new(), - constants: ConstantTable::new(), + constants: Vec::new(), locals: Vec::new(), prototypes: Vec::new(), stack_size: 0, @@ -216,7 +215,7 @@ impl<'src> Compiler<'src> { r#type: self.r#type, instructions, positions, - constants: self.constants, + constants: self.constants.to_vec(), locals, prototypes: self.prototypes, register_count: self.stack_size, @@ -276,10 +275,13 @@ impl<'src> Compiler<'src> { .enumerate() .rev() .find_map(|(index, (local, _))| { - let identifier = self - .constants - .strings - .get(local.identifier_index as usize)?; + let constant = self.constants.get(local.identifier_index as usize)?; + let identifier = + if let Value::Concrete(ConcreteValue::String(identifier)) = constant { + identifier + } else { + return None; + }; if identifier == identifier_text { Some(index as u16) @@ -303,8 +305,8 @@ impl<'src> Compiler<'src> { ) -> (u16, u16) { info!("Declaring local {identifier}"); - let identifier = DustString::from(identifier); - let identifier_index = self.push_or_get_constant_string(identifier); + let identifier = Value::Concrete(ConcreteValue::string(identifier)); + let identifier_index = self.push_or_get_constant(identifier); let local_index = self.locals.len() as u16; self.locals.push(( @@ -320,102 +322,24 @@ impl<'src> Compiler<'src> { .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_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 { + fn push_or_get_constant(&mut self, value: Value) -> u16 { if let Some(index) = self .constants - .bytes .iter() - .position(|&byte| byte == new_byte) + .position(|constant| constant == &value) { index as u16 } else { - self.constants.bytes.push(new_byte); + let index = self.constants.len() as u16; - (self.constants.bytes.len() - 1) as u16 - } - } + self.constants.push(value); - 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 + index } } @@ -557,14 +481,6 @@ 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; @@ -735,17 +651,39 @@ impl<'src> Compiler<'src> { } let destination = self.next_register(); - 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], - found: operator.to_owned(), - position: operator_position, - }); - } + let type_code = match previous_type { + Type::Boolean => TypeCode::BOOLEAN, + Type::Byte => TypeCode::BYTE, + Type::Character => TypeCode::CHARACTER, + Type::Float => TypeCode::FLOAT, + Type::Integer => TypeCode::INTEGER, + Type::String => TypeCode::STRING, + _ => match operator { + Token::Minus => { + return Err(CompileError::CannotNegateType { + argument_type: previous_type, + position: previous_position, + }); + } + Token::Bang => { + return Err(CompileError::CannotNotType { + argument_type: previous_type, + position: previous_position, + }); + } + _ => { + return Err(CompileError::ExpectedTokenMultiple { + expected: &[TokenKind::Bang, TokenKind::Minus], + found: operator.to_owned(), + position: operator_position, + }); + } + }, + }; + let instruction = match operator { + Token::Bang => Instruction::not(destination, argument), + Token::Minus => Instruction::negate(destination, argument, type_code), + _ => unreachable!(), }; self.emit_instruction(instruction, previous_type, operator_position); @@ -768,43 +706,15 @@ impl<'src> Compiler<'src> { Operation::LOAD_BOOLEAN | Operation::LOAD_LIST | Operation::LOAD_SELF - | 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::ADD + | Operation::SUBTRACT + | Operation::MULTIPLY + | Operation::DIVIDE + | Operation::MODULO + | Operation::EQUAL + | Operation::LESS + | Operation::LESS_EQUAL + | Operation::NEGATE | Operation::NOT | Operation::CALL => (Operand::Register(instruction.a_field()), true), Operation::CALL_NATIVE => { @@ -869,6 +779,16 @@ impl<'src> Compiler<'src> { check_math_type(&left_type, operator, &left_position)?; + let left_type_code = match left_type { + Type::Boolean => TypeCode::BOOLEAN, + Type::Byte => TypeCode::BYTE, + Type::Character => TypeCode::CHARACTER, + Type::Float => TypeCode::FLOAT, + Type::Integer => TypeCode::INTEGER, + Type::String => TypeCode::STRING, + _ => unreachable!(), + }; + if is_assignment && !left_is_mutable_local { return Err(CompileError::ExpectedMutableVariable { found: self.previous_token.to_owned(), @@ -891,9 +811,19 @@ impl<'src> Compiler<'src> { &right_position, )?; + let right_type_code = match right_type { + Type::Boolean => TypeCode::BOOLEAN, + Type::Byte => TypeCode::BYTE, + Type::Character => TypeCode::CHARACTER, + Type::Float => TypeCode::FLOAT, + Type::Integer => TypeCode::INTEGER, + Type::String => TypeCode::STRING, + _ => unreachable!(), + }; + if push_back_right { self.instructions - .push((right_instruction, right_type.clone(), right_position)); + .push((right_instruction, right_type, right_position)); } let r#type = if is_assignment { @@ -911,63 +841,21 @@ impl<'src> Compiler<'src> { } else { self.next_register() }; - let instruction = match (operator, left_type, right_type) { - (Token::Plus, Type::Byte, Type::Byte) => { - Instruction::add_byte(destination, left, right) + let instruction = match operator { + Token::Plus | Token::PlusEqual => { + Instruction::add(destination, left, left_type_code, right, right_type_code) } - (Token::Plus, Type::Character, Type::Character) => { - Instruction::add_char(destination, left, right) + Token::Minus | Token::MinusEqual => { + Instruction::subtract(destination, left, left_type_code, right, right_type_code) } - (Token::Plus, Type::Character, Type::String) => { - Instruction::add_char_str(destination, left, right) + Token::Star | Token::StarEqual => { + Instruction::multiply(destination, left, left_type_code, right, right_type_code) } - (Token::Plus, Type::Float, Type::Float) => { - Instruction::add_float(destination, left, right) + Token::Slash | Token::SlashEqual => { + Instruction::divide(destination, left, left_type_code, right, right_type_code) } - (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) + Token::Percent | Token::PercentEqual => { + Instruction::modulo(destination, left, left_type_code, right, right_type_code) } _ => { return Err(CompileError::ExpectedTokenMultiple { @@ -995,9 +883,13 @@ impl<'src> Compiler<'src> { } fn parse_comparison_binary(&mut self) -> Result<(), CompileError> { - if self - .get_last_operation() - .is_some_and(|operation| operation.is_comparison()) + if let Some( + [ + Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL, + _, + _, + ], + ) = self.get_last_operations() { return Err(CompileError::ComparisonChain { position: self.current_position, @@ -1016,9 +908,21 @@ impl<'src> Compiler<'src> { let operator_position = self.current_position; let rule = ParseRule::from(&operator); + // TODO: Check if the left type is a valid type for comparison + + let left_type_code = match left_type { + Type::Boolean => TypeCode::BOOLEAN, + Type::Byte => TypeCode::BYTE, + Type::Character => TypeCode::CHARACTER, + Type::Float => TypeCode::FLOAT, + Type::Integer => TypeCode::INTEGER, + Type::String => TypeCode::STRING, + _ => unreachable!(), + }; + if push_back_left { self.instructions - .push((left_instruction, left_type.clone(), left_position)); + .push((left_instruction, left_type, left_position)); } self.advance()?; @@ -1033,112 +937,41 @@ impl<'src> Compiler<'src> { })?; let (right, push_back_right) = self.handle_binary_argument(&right_instruction)?; + // TODO: Check if the right type is a valid type for comparison + // TODO: Check if the left and right types are compatible + + let right_type_code = match right_type { + Type::Boolean => TypeCode::BOOLEAN, + Type::Byte => TypeCode::BYTE, + Type::Character => TypeCode::CHARACTER, + Type::Float => TypeCode::FLOAT, + Type::Integer => TypeCode::INTEGER, + Type::String => TypeCode::STRING, + _ => unreachable!(), + }; + if push_back_right { self.instructions - .push((right_instruction, right_type.clone(), right_position)); + .push((right_instruction, right_type, right_position)); } let destination = self.next_register(); - let comparison = match (operator, left_type, right_type) { - (Token::DoubleEqual, Type::Boolean, Type::Boolean) => { - Instruction::equal_bool(true, left, right) + let comparison = match operator { + Token::DoubleEqual => { + Instruction::equal(true, left, left_type_code, right, right_type_code) } - (Token::DoubleEqual, Type::Byte, Type::Byte) => { - Instruction::equal_byte(true, left, right) + Token::BangEqual => { + Instruction::equal(false, left, left_type_code, right, right_type_code) } - (Token::DoubleEqual, Type::Character, Type::Character) => { - Instruction::equal_char(true, left, right) + Token::Less => Instruction::less(true, left, left_type_code, right, right_type_code), + Token::LessEqual => { + Instruction::less_equal(true, left, left_type_code, right, right_type_code) } - (Token::DoubleEqual, Type::Character, Type::String) => { - Instruction::equal_char_str(true, left, right) + Token::Greater => { + Instruction::less_equal(false, left, left_type_code, right, right_type_code) } - (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) + Token::GreaterEqual => { + Instruction::less(false, left, left_type_code, right, right_type_code) } _ => { return Err(CompileError::ExpectedTokenMultiple { @@ -1223,23 +1056,7 @@ impl<'src> Compiler<'src> { if !matches!( instructions[0].0.operation(), - 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::TEST | Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL ) || !matches!(instructions[1].0.operation(), Operation::JUMP) { continue; @@ -1321,7 +1138,10 @@ impl<'src> Compiler<'src> { math_instruction.set_a_field(local_register_index); } else { let register = self.next_register() - 1; - let set_local = Instruction::set_local(register, local_index); + let set_local = Instruction::from(SetLocal { + register_index: register, + local_index, + }); self.emit_instruction(set_local, Type::None, start_position); } @@ -1396,7 +1216,10 @@ impl<'src> Compiler<'src> { } if expected_register < actual_register { - let close = Instruction::close(expected_register, actual_register); + let close = Instruction::from(Close { + from: expected_register, + to: actual_register, + }); self.emit_instruction(close, Type::None, self.current_position); } @@ -1420,22 +1243,7 @@ impl<'src> Compiler<'src> { if matches!( self.get_last_operations(), Some([ - 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::EQUAL | Operation::LESS | Operation::LESS_EQUAL, Operation::JUMP, Operation::LOAD_BOOLEAN, Operation::LOAD_BOOLEAN @@ -1508,7 +1316,10 @@ impl<'src> Compiler<'src> { loader.set_c_field(true as u16); } else { if_block_distance += 1; - let jump = Instruction::jump(else_block_distance, true); + let jump = Instruction::from(Jump { + offset: else_block_distance, + is_positive: true, + }); self.instructions .insert(if_block_end, (jump, Type::None, self.current_position)); @@ -1516,7 +1327,10 @@ impl<'src> Compiler<'src> { } 2.. => { if_block_distance += 1; - let jump = Instruction::jump(else_block_distance, true); + let jump = Instruction::from(Jump { + offset: else_block_distance, + is_positive: true, + }); self.instructions .insert(if_block_end, (jump, Type::None, self.current_position)); @@ -1535,29 +1349,14 @@ impl<'src> Compiler<'src> { fn parse_while(&mut self) -> Result<(), CompileError> { self.advance()?; - let expression_start = self.instructions.len() as u16; + let expression_start = self.instructions.len(); self.parse_expression()?; if matches!( self.get_last_operations(), Some([ - 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::EQUAL | Operation::LESS | Operation::LESS_EQUAL, Operation::JUMP, Operation::LOAD_BOOLEAN, Operation::LOAD_BOOLEAN @@ -1577,15 +1376,21 @@ impl<'src> Compiler<'src> { self.parse_block()?; - 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); + let block_end = self.instructions.len(); + let jump_distance = (block_end - block_start + 1) as u16; + let jump = Instruction::from(Jump { + offset: jump_distance, + is_positive: 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::jump(jump_back_distance, false); + let jump_back_distance = (block_end - expression_start + 1) as u16; + let jump_back = Instruction::from(Jump { + offset: jump_back_distance, + is_positive: false, + }); self.emit_instruction(jump_back, Type::None, self.current_position); @@ -1604,9 +1409,13 @@ impl<'src> Compiler<'src> { self.parse_expression()?; let actual_register = self.next_register() - 1; + let registers_to_close = actual_register - expected_register; - if expected_register < actual_register { - let close = Instruction::close(expected_register, actual_register); + if registers_to_close > 0 { + let close = Instruction::from(Close { + from: expected_register, + to: actual_register, + }); self.emit_instruction(close, Type::None, self.current_position); } @@ -1618,7 +1427,11 @@ 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::call_native(destination, function, argument_count); + let call_native = Instruction::from(CallNative { + destination, + function, + argument_count, + }); self.emit_instruction(call_native, return_type, Span(start, end)); @@ -1681,7 +1494,10 @@ impl<'src> Compiler<'src> { }; let end = self.current_position.1; let return_register = self.next_register() - 1; - let r#return = Instruction::r#return(should_return_value, return_register); + let r#return = Instruction::from(Return { + should_return_value, + return_register, + }); self.emit_instruction(r#return, Type::None, Span(start, end)); @@ -1980,13 +1796,16 @@ impl<'src> Compiler<'src> { let registers_to_close = (actual_register - expected_register).saturating_sub(1); if registers_to_close > 0 { - let close = Instruction::close(expected_register, actual_register); + let close = Instruction::from(Close { + from: expected_register, + to: 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 3d45bad..bf22d34 100644 --- a/dust-lang/src/compiler/optimize.rs +++ b/dust-lang/src/compiler/optimize.rs @@ -37,23 +37,7 @@ pub fn control_flow_register_consolidation(compiler: &mut Compiler) { if !matches!( compiler.get_last_operations(), Some([ - 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::TEST | Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL, 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 new file mode 100644 index 0000000..94230bb --- /dev/null +++ b/dust-lang/src/instruction/add.rs @@ -0,0 +1,69 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode}; + +pub struct Add { + pub destination: u16, + pub left: Operand, + pub left_type: TypeCode, + pub right: Operand, + pub right_type: TypeCode, +} + +impl From for Add { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let (left, right) = instruction.b_and_c_as_operands(); + let left_type = instruction.b_type(); + let right_type = instruction.c_type(); + + Add { + destination, + left, + left_type, + right, + right_type, + } + } +} + +impl From for Instruction { + fn from(add: Add) -> Self { + let operation = Operation::ADD; + let a_field = add.destination; + let (b_field, b_is_constant) = add.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = add.right.as_index_and_constant_flag(); + let b_type = add.left_type; + let c_type = add.right_type; + + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + b_is_constant, + c_is_constant, + b_type, + c_type, + ..Default::default() + } + .build() + } +} + +impl Display for Add { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let Add { + destination, + left, + left_type, + right, + right_type, + } = self; + + write!( + f, + "R{destination} = {left}({left_type}) + {right}({right_type})", + ) + } +} diff --git a/dust-lang/src/instruction/add_byte.rs b/dust-lang/src/instruction/add_byte.rs deleted file mode 100644 index 764badd..0000000 --- a/dust-lang/src/instruction/add_byte.rs +++ /dev/null @@ -1,54 +0,0 @@ -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 deleted file mode 100644 index f0260ea..0000000 --- a/dust-lang/src/instruction/add_char.rs +++ /dev/null @@ -1,54 +0,0 @@ -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 deleted file mode 100644 index 4ffe95e..0000000 --- a/dust-lang/src/instruction/add_char_str.rs +++ /dev/null @@ -1,54 +0,0 @@ -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 deleted file mode 100644 index a8292f6..0000000 --- a/dust-lang/src/instruction/add_float.rs +++ /dev/null @@ -1,54 +0,0 @@ -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 deleted file mode 100644 index 21f2bf7..0000000 --- a/dust-lang/src/instruction/add_int.rs +++ /dev/null @@ -1,56 +0,0 @@ -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 deleted file mode 100644 index a43a3c9..0000000 --- a/dust-lang/src/instruction/add_str.rs +++ /dev/null @@ -1,54 +0,0 @@ -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 deleted file mode 100644 index 8638fd8..0000000 --- a/dust-lang/src/instruction/add_str_char.rs +++ /dev/null @@ -1,54 +0,0 @@ -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 571bbb8..ff69533 100644 --- a/dust-lang/src/instruction/call.rs +++ b/dust-lang/src/instruction/call.rs @@ -1,3 +1,5 @@ +use std::fmt::{self, Display, Formatter}; + use crate::{Instruction, Operation}; use super::InstructionBuilder; @@ -43,3 +45,29 @@ impl From for Instruction { .build() } } + +impl Display for Call { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let Call { + destination, + function_register, + argument_count, + .. + } = self; + let arguments_start = destination.saturating_sub(*argument_count); + + match argument_count { + 0 => write!(f, "R{destination} = R{function_register}()"), + 1 => write!( + f, + "R{destination} = R{function_register}(R{arguments_start})" + ), + _ => { + write!( + f, + "R{destination} = R{function_register}(R{arguments_start}..R{destination})" + ) + } + } + } +} diff --git a/dust-lang/src/instruction/call_native.rs b/dust-lang/src/instruction/call_native.rs index c40733a..f66fac4 100644 --- a/dust-lang/src/instruction/call_native.rs +++ b/dust-lang/src/instruction/call_native.rs @@ -1,3 +1,5 @@ +use std::fmt::Display; + use crate::{Instruction, NativeFunction, Operation}; use super::InstructionBuilder; @@ -38,3 +40,27 @@ impl From for Instruction { .build() } } + +impl Display for CallNative { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let CallNative { + destination, + function, + argument_count, + } = self; + let arguments_start = destination.saturating_sub(*argument_count); + let arguments_end = arguments_start + argument_count; + + if function.returns_value() { + write!(f, "R{destination} = ")?; + } + + match argument_count { + 0 => { + write!(f, "{function}()") + } + 1 => write!(f, "{function}(R{arguments_start})"), + _ => write!(f, "{function}(R{arguments_start}..R{arguments_end})"), + } + } +} diff --git a/dust-lang/src/instruction/divide.rs b/dust-lang/src/instruction/divide.rs new file mode 100644 index 0000000..d039f90 --- /dev/null +++ b/dust-lang/src/instruction/divide.rs @@ -0,0 +1,69 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode}; + +pub struct Divide { + pub destination: u16, + pub left: Operand, + pub left_type: TypeCode, + pub right: Operand, + pub right_type: TypeCode, +} + +impl From for Divide { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let (left, right) = instruction.b_and_c_as_operands(); + let left_type = instruction.b_type(); + let right_type = instruction.c_type(); + + Divide { + destination, + left, + left_type, + right, + right_type, + } + } +} + +impl From for Instruction { + fn from(divide: Divide) -> Self { + let operation = Operation::DIVIDE; + let a_field = divide.destination; + let (b_field, b_is_constant) = divide.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = divide.right.as_index_and_constant_flag(); + let b_type = divide.left_type; + let c_type = divide.right_type; + + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + b_is_constant, + c_is_constant, + b_type, + c_type, + ..Default::default() + } + .build() + } +} + +impl Display for Divide { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let Divide { + destination, + left, + left_type, + right, + right_type, + } = self; + + write!( + f, + "R{destination} = {left_type}({left}) ÷ {right_type}({right})", + ) + } +} diff --git a/dust-lang/src/instruction/divide_byte.rs b/dust-lang/src/instruction/divide_byte.rs deleted file mode 100644 index ce2a4c4..0000000 --- a/dust-lang/src/instruction/divide_byte.rs +++ /dev/null @@ -1,54 +0,0 @@ -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 deleted file mode 100644 index aaaef22..0000000 --- a/dust-lang/src/instruction/divide_float.rs +++ /dev/null @@ -1,54 +0,0 @@ -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 deleted file mode 100644 index b52ced0..0000000 --- a/dust-lang/src/instruction/divide_int.rs +++ /dev/null @@ -1,54 +0,0 @@ -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_bool.rs b/dust-lang/src/instruction/equal.rs similarity index 55% rename from dust-lang/src/instruction/equal_bool.rs rename to dust-lang/src/instruction/equal.rs index 03a0997..6d1aed6 100644 --- a/dust-lang/src/instruction/equal_bool.rs +++ b/dust-lang/src/instruction/equal.rs @@ -1,32 +1,40 @@ use std::fmt::{self, Display, Formatter}; -use super::{Instruction, InstructionBuilder, Operand, Operation}; +use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode}; -pub struct EqualBool { +pub struct Equal { pub comparator: bool, pub left: Operand, + pub left_type: TypeCode, pub right: Operand, + pub right_type: TypeCode, } -impl From for EqualBool { +impl From for Equal { fn from(instruction: Instruction) -> Self { let comparator = instruction.d_field(); let (left, right) = instruction.b_and_c_as_operands(); + let left_type = instruction.b_type(); + let right_type = instruction.c_type(); - EqualBool { + Equal { comparator, left, + left_type, right, + right_type, } } } -impl From for Instruction { - fn from(equal_bool: EqualBool) -> Self { - let operation = Operation::EQUAL_BOOL; +impl From for Instruction { + fn from(equal_bool: Equal) -> Self { + let operation = Operation::EQUAL; 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; + let b_type = equal_bool.left_type; + let c_type = equal_bool.right_type; InstructionBuilder { operation, @@ -35,21 +43,28 @@ impl From for Instruction { d_field, b_is_constant, c_is_constant, + b_type, + c_type, ..Default::default() } .build() } } -impl Display for EqualBool { +impl Display for Equal { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let EqualBool { + let Equal { comparator, left, + left_type, right, + right_type, } = self; let operator = if *comparator { "==" } else { "≠" }; - write!(f, "if {left} {operator} {right} {{ JUMP +1 }}") + write!( + f, + "if {left}({left_type}) {operator} {right}({right_type}) {{ JUMP +1 }}" + ) } } diff --git a/dust-lang/src/instruction/equal_byte.rs b/dust-lang/src/instruction/equal_byte.rs deleted file mode 100644 index 3be0ddb..0000000 --- a/dust-lang/src/instruction/equal_byte.rs +++ /dev/null @@ -1,55 +0,0 @@ -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 deleted file mode 100644 index 4e60a77..0000000 --- a/dust-lang/src/instruction/equal_char.rs +++ /dev/null @@ -1,55 +0,0 @@ -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 deleted file mode 100644 index eb15ae4..0000000 --- a/dust-lang/src/instruction/equal_char_str.rs +++ /dev/null @@ -1,55 +0,0 @@ -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 deleted file mode 100644 index 6149c2c..0000000 --- a/dust-lang/src/instruction/equal_float.rs +++ /dev/null @@ -1,55 +0,0 @@ -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 deleted file mode 100644 index cebc38d..0000000 --- a/dust-lang/src/instruction/equal_int.rs +++ /dev/null @@ -1,55 +0,0 @@ -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 deleted file mode 100644 index f4cc0c4..0000000 --- a/dust-lang/src/instruction/equal_str.rs +++ /dev/null @@ -1,55 +0,0 @@ -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 deleted file mode 100644 index ccd0dd4..0000000 --- a/dust-lang/src/instruction/equal_str_char.rs +++ /dev/null @@ -1,55 +0,0 @@ -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/jump.rs b/dust-lang/src/instruction/jump.rs index cf55b7c..23b82ce 100644 --- a/dust-lang/src/instruction/jump.rs +++ b/dust-lang/src/instruction/jump.rs @@ -1,3 +1,5 @@ +use std::fmt::{self, Display, Formatter}; + use crate::{Instruction, Operation}; use super::InstructionBuilder; @@ -31,3 +33,15 @@ impl From for Instruction { .build() } } + +impl Display for Jump { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let Jump { + offset, + is_positive, + } = self; + let sign = if *is_positive { "+" } else { "-" }; + + write!(f, "JUMP {sign}{offset}") + } +} diff --git a/dust-lang/src/instruction/less.rs b/dust-lang/src/instruction/less.rs new file mode 100644 index 0000000..67fa53b --- /dev/null +++ b/dust-lang/src/instruction/less.rs @@ -0,0 +1,70 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode}; + +pub struct Less { + pub comparator: bool, + pub left: Operand, + pub left_type: TypeCode, + pub right: Operand, + pub right_type: TypeCode, +} + +impl From for Less { + fn from(instruction: Instruction) -> Self { + let comparator = instruction.d_field(); + let (left, right) = instruction.b_and_c_as_operands(); + let left_type = instruction.b_type(); + let right_type = instruction.c_type(); + + Less { + comparator, + left, + left_type, + right, + right_type, + } + } +} + +impl From for Instruction { + fn from(less: Less) -> Self { + let operation = Operation::LESS; + let (b_field, b_is_constant) = less.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = less.right.as_index_and_constant_flag(); + let d_field = less.comparator; + let b_type = less.left_type; + let c_type = less.right_type; + + InstructionBuilder { + operation, + b_field, + c_field, + d_field, + b_is_constant, + c_is_constant, + b_type, + c_type, + ..Default::default() + } + .build() + } +} + +impl Display for Less { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let Less { + comparator, + left, + left_type, + right, + right_type, + } = self; + let operator = if *comparator { "<" } else { "≥" }; + + write!( + f, + "if {left_type}({left}) {operator} {right_type}({right}) {{ JUMP +1 }}" + ) + } +} diff --git a/dust-lang/src/instruction/less_byte.rs b/dust-lang/src/instruction/less_byte.rs deleted file mode 100644 index 7b657f0..0000000 --- a/dust-lang/src/instruction/less_byte.rs +++ /dev/null @@ -1,55 +0,0 @@ -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 deleted file mode 100644 index 0f26ccf..0000000 --- a/dust-lang/src/instruction/less_char.rs +++ /dev/null @@ -1,55 +0,0 @@ -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_byte.rs b/dust-lang/src/instruction/less_equal.rs similarity index 54% rename from dust-lang/src/instruction/less_equal_byte.rs rename to dust-lang/src/instruction/less_equal.rs index 08b1cac..fc3238f 100644 --- a/dust-lang/src/instruction/less_equal_byte.rs +++ b/dust-lang/src/instruction/less_equal.rs @@ -1,32 +1,40 @@ use std::fmt::{self, Display, Formatter}; -use super::{Instruction, InstructionBuilder, Operand, Operation}; +use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode}; -pub struct LessEqualByte { +pub struct LessEqual { pub comparator: bool, pub left: Operand, + pub left_type: TypeCode, pub right: Operand, + pub right_type: TypeCode, } -impl From for LessEqualByte { +impl From for LessEqual { fn from(instruction: Instruction) -> Self { let comparator = instruction.d_field(); let (left, right) = instruction.b_and_c_as_operands(); + let left_type = instruction.b_type(); + let right_type = instruction.c_type(); - LessEqualByte { + LessEqual { comparator, left, + left_type, right, + right_type, } } } -impl From for Instruction { - fn from(less_equal_byte: LessEqualByte) -> Self { - let operation = Operation::LESS_EQUAL_BYTE; +impl From for Instruction { + fn from(less_equal_byte: LessEqual) -> Self { + let operation = Operation::LESS_EQUAL; 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; + let b_type = less_equal_byte.left_type; + let c_type = less_equal_byte.right_type; InstructionBuilder { operation, @@ -35,21 +43,28 @@ impl From for Instruction { d_field, b_is_constant, c_is_constant, + b_type, + c_type, ..Default::default() } .build() } } -impl Display for LessEqualByte { +impl Display for LessEqual { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let LessEqualByte { + let LessEqual { comparator, left, + left_type, right, + right_type, } = self; let operator = if *comparator { "≤" } else { ">" }; - write!(f, "if {left} {operator} {right} {{ JUMP +1 }}") + write!( + f, + "if {left_type}({left}) {operator} {right_type}({right}) {{ JUMP +1 }}" + ) } } diff --git a/dust-lang/src/instruction/less_equal_char.rs b/dust-lang/src/instruction/less_equal_char.rs deleted file mode 100644 index bd0777e..0000000 --- a/dust-lang/src/instruction/less_equal_char.rs +++ /dev/null @@ -1,55 +0,0 @@ -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 deleted file mode 100644 index f552f0b..0000000 --- a/dust-lang/src/instruction/less_equal_float.rs +++ /dev/null @@ -1,55 +0,0 @@ -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 deleted file mode 100644 index ede40c8..0000000 --- a/dust-lang/src/instruction/less_equal_int.rs +++ /dev/null @@ -1,55 +0,0 @@ -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 deleted file mode 100644 index 4b8ae2b..0000000 --- a/dust-lang/src/instruction/less_equal_str.rs +++ /dev/null @@ -1,55 +0,0 @@ -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 deleted file mode 100644 index a5722fa..0000000 --- a/dust-lang/src/instruction/less_float.rs +++ /dev/null @@ -1,55 +0,0 @@ -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 deleted file mode 100644 index c693d94..0000000 --- a/dust-lang/src/instruction/less_int.rs +++ /dev/null @@ -1,55 +0,0 @@ -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 deleted file mode 100644 index c26b494..0000000 --- a/dust-lang/src/instruction/less_str.rs +++ /dev/null @@ -1,55 +0,0 @@ -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/mod.rs b/dust-lang/src/instruction/mod.rs index e99bc21..6b55724 100644 --- a/dust-lang/src/instruction/mod.rs +++ b/dust-lang/src/instruction/mod.rs @@ -7,11 +7,11 @@ //! Bits | Description //! ----- | ----------- //! 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 +//! 7 | Flag indicating if the B field is a constant +//! 8 | Flag indicating if the C field is a constant +//! 9 | D field (boolean) +//! 10-12 | B field type +//! 13-15 | C field type //! 16-31 | A field (unsigned 16-bit integer) //! 32-47 | B field (unsigned 16-bit integer) //! 48-63 | C field (unsigned 16-bit integer) @@ -93,122 +93,64 @@ //! //! assert!(is_add_assign); //! ``` -mod add_byte; -mod add_char; -mod add_char_str; -mod add_float; -mod add_int; -mod add_str; -mod add_str_char; +mod add; mod call; mod call_native; mod close; -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 divide; +mod equal; mod get_local; mod jump; -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 less; +mod less_equal; mod load_boolean; mod load_constant; mod load_function; mod load_list; mod load_self; -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 modulo; +mod multiply; +mod negate; mod not; mod operation; mod point; mod r#return; mod set_local; -mod subtract_byte; -mod subtract_float; -mod subtract_int; +mod subtract; mod test; mod test_set; +mod type_code; -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 add::Add; pub use call::Call; pub use call_native::CallNative; pub use close::Close; -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 divide::Divide; +pub use equal::Equal; pub use get_local::GetLocal; pub use jump::Jump; -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 less::Less; +pub use less_equal::LessEqual; 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_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 modulo::Modulo; +pub use multiply::Multiply; +pub use negate::Negate; 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_byte::SubtractByte; -pub use subtract_float::SubtractFloat; -pub use subtract_int::SubtractInt; +pub use subtract::Subtract; pub use test::Test; pub use test_set::TestSet; use serde::{Deserialize, Serialize}; use std::fmt::{self, Debug, Display, Formatter}; +pub use type_code::TypeCode; use crate::NativeFunction; @@ -220,17 +162,21 @@ pub struct InstructionBuilder { pub d_field: bool, pub b_is_constant: bool, pub c_is_constant: bool, + pub b_type: TypeCode, + pub c_type: TypeCode, } 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); + let bits = ((self.operation.0 as u64) << 57) + | ((self.b_is_constant as u64) << 56) + | ((self.c_is_constant as u64) << 55) + | ((self.d_field as u64) << 54) + | ((self.b_type.0 as u64) << 51) + | ((self.c_type.0 as u64) << 48) + | ((self.a_field as u64) << 32) + | ((self.b_field as u64) << 16) + | (self.c_field as u64); Instruction(bits) } @@ -246,11 +192,13 @@ impl Default for InstructionBuilder { d_field: false, b_is_constant: false, c_is_constant: false, + b_type: TypeCode::BOOLEAN, + c_type: TypeCode::BOOLEAN, } } } -/// An operation and its arguments for the Dust virtual machine. +/// An instruction for the Dust virtual machine. /// /// See the [module-level documentation](index.html) for more information. #[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] @@ -258,33 +206,45 @@ pub struct Instruction(u64); impl Instruction { pub fn operation(&self) -> Operation { - let first_byte = (self.0 & 0b0111_1111) as u8; + let first_7_bits = (self.0 >> 57) as u8; - Operation(first_byte) + Operation(first_7_bits) } pub fn b_is_constant(&self) -> bool { - (self.0 >> 8) & 1 == 0 + (self.0 >> 56) & 1 != 0 } pub fn c_is_constant(&self) -> bool { - (self.0 >> 9) & 1 == 0 + (self.0 >> 55) & 1 != 0 } pub fn d_field(&self) -> bool { - (self.0 >> 10) & 1 == 0 + (self.0 >> 54) & 1 == 0 + } + + pub fn b_type(&self) -> TypeCode { + let byte = ((self.0 >> 51) & 0b111) as u8; + + TypeCode(byte) + } + + pub fn c_type(&self) -> TypeCode { + let byte = ((self.0 >> 48) & 0b111) as u8; + + TypeCode(byte) } pub fn a_field(&self) -> u16 { - ((self.0 >> 31) & 0xFFFF) as u16 + ((self.0 >> 32) & 0xFFFF) as u16 } pub fn b_field(&self) -> u16 { - ((self.0 >> 47) & 0xFFFF) as u16 + ((self.0 >> 16) & 0xFFFF) as u16 } pub fn c_field(&self) -> u16 { - (self.0 >> 48) as u16 + (self.0 & 0xFFFF) as u16 } pub fn set_a_field(&mut self, bits: u16) { @@ -360,313 +320,139 @@ impl Instruction { }) } - pub fn add_int(destination: u16, left: Operand, right: Operand) -> Instruction { - Instruction::from(AddInt { + pub fn add( + destination: u16, + left: Operand, + left_type: TypeCode, + right: Operand, + right_type: TypeCode, + ) -> Instruction { + Instruction::from(Add { destination, left, + left_type, right, + right_type, }) } - pub fn add_float(destination: u16, left: Operand, right: Operand) -> Instruction { - Instruction::from(AddFloat { + pub fn subtract( + destination: u16, + left: Operand, + left_type: TypeCode, + right: Operand, + right_type: TypeCode, + ) -> Instruction { + Instruction::from(Subtract { destination, left, + left_type, right, + right_type, }) } - pub fn add_byte(destination: u16, left: Operand, right: Operand) -> Instruction { - Instruction::from(AddByte { + pub fn multiply( + destination: u16, + left: Operand, + left_type: TypeCode, + right: Operand, + right_type: TypeCode, + ) -> Instruction { + Instruction::from(Multiply { destination, left, + left_type, right, + right_type, }) } - pub fn add_str(destination: u16, left: Operand, right: Operand) -> Instruction { - Instruction::from(AddStr { + pub fn divide( + destination: u16, + left: Operand, + left_type: TypeCode, + right: Operand, + right_type: TypeCode, + ) -> Instruction { + Instruction::from(Divide { destination, left, + left_type, right, + right_type, }) } - pub fn add_char(destination: u16, left: Operand, right: Operand) -> Instruction { - Instruction::from(AddChar { + pub fn modulo( + destination: u16, + left: Operand, + left_type: TypeCode, + right: Operand, + right_type: TypeCode, + ) -> Instruction { + Instruction::from(Modulo { destination, left, + left_type, right, + right_type, }) } - 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 { + pub fn equal( + comparator: bool, + left: Operand, + left_type: TypeCode, + right: Operand, + right_type: TypeCode, + ) -> Instruction { + Instruction::from(Equal { comparator, left, + left_type, right, + right_type, }) } - pub fn equal_float(comparator: bool, left: Operand, right: Operand) -> Instruction { - Instruction::from(EqualFloat { + pub fn less( + comparator: bool, + left: Operand, + left_type: TypeCode, + right: Operand, + right_type: TypeCode, + ) -> Instruction { + Instruction::from(Less { comparator, left, + left_type, right, + right_type, }) } - pub fn equal_byte(comparator: bool, left: Operand, right: Operand) -> Instruction { - Instruction::from(EqualByte { + pub fn less_equal( + comparator: bool, + left: Operand, + left_type: TypeCode, + right: Operand, + right_type: TypeCode, + ) -> Instruction { + Instruction::from(LessEqual { comparator, left, + left_type, right, + right_type, }) } - 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 { + pub fn negate(destination: u16, argument: Operand, argument_type: TypeCode) -> Instruction { + Instruction::from(Negate { destination, argument, + argument_type, }) } @@ -747,45 +533,15 @@ impl Instruction { | Operation::LOAD_LIST | Operation::LOAD_SELF | Operation::GET_LOCAL - | 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::ADD + | Operation::SUBTRACT + | Operation::MULTIPLY + | Operation::DIVIDE + | Operation::MODULO + | Operation::EQUAL + | Operation::LESS + | Operation::LESS_EQUAL + | Operation::NEGATE | Operation::NOT | Operation::CALL => Some(Operand::Register(self.a_field())), Operation::CALL_NATIVE => { @@ -833,27 +589,12 @@ impl Instruction { | Operation::LOAD_LIST | Operation::LOAD_SELF | Operation::GET_LOCAL - | 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::ADD + | Operation::SUBTRACT + | Operation::MULTIPLY + | Operation::DIVIDE + | Operation::MODULO + | Operation::NEGATE | Operation::NOT | Operation::CALL => true, Operation::CALL_NATIVE => { @@ -863,29 +604,14 @@ impl Instruction { } Operation::CLOSE | Operation::SET_LOCAL - | 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::EQUAL + | Operation::LESS + | Operation::LESS_EQUAL | Operation::TEST | Operation::TEST_SET | Operation::JUMP | Operation::RETURN => false, - _ => Operation::panic_from_unknown_code(self.operation().0), + _ => self.operation().panic_from_unknown_code(), } } @@ -902,9 +628,24 @@ impl Instruction { 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(), + Operation::ADD => Add::from(*self).to_string(), + Operation::SUBTRACT => Subtract::from(*self).to_string(), + Operation::MULTIPLY => Multiply::from(*self).to_string(), + Operation::DIVIDE => Divide::from(*self).to_string(), + Operation::MODULO => Modulo::from(*self).to_string(), + Operation::NEGATE => Negate::from(*self).to_string(), + Operation::NOT => Not::from(*self).to_string(), + Operation::EQUAL => Equal::from(*self).to_string(), + Operation::LESS => Less::from(*self).to_string(), + Operation::LESS_EQUAL => LessEqual::from(*self).to_string(), + Operation::TEST => Test::from(*self).to_string(), + Operation::TEST_SET => TestSet::from(*self).to_string(), + Operation::CALL => Call::from(*self).to_string(), + Operation::CALL_NATIVE => CallNative::from(*self).to_string(), + Operation::JUMP => Jump::from(*self).to_string(), + Operation::RETURN => Return::from(*self).to_string(), - _ => Operation::panic_from_unknown_code(operation.0), + _ => operation.panic_from_unknown_code(), } } } @@ -966,50 +707,118 @@ mod tests { #[test] fn decode_operation() { - let instruction = Instruction::add_int(42, Operand::Constant(4), Operand::Register(2)); + let instruction = Instruction::add( + 42, + Operand::Constant(4), + TypeCode::STRING, + Operand::Register(2), + TypeCode::CHARACTER, + ); - assert_eq!(instruction.operation(), Operation::ADD_INT); + assert_eq!(instruction.operation(), Operation::ADD); } #[test] fn decode_a_field() { - let instruction = Instruction::add_int(42, Operand::Constant(4), Operand::Register(2)); + let instruction = Instruction::add( + 42, + Operand::Constant(4), + TypeCode::STRING, + Operand::Register(2), + TypeCode::CHARACTER, + ); assert_eq!(42, instruction.a_field()); } #[test] fn decode_b_field() { - let instruction = Instruction::add_int(42, Operand::Constant(4), Operand::Register(2)); + let instruction = Instruction::add( + 42, + Operand::Constant(4), + TypeCode::STRING, + Operand::Register(2), + TypeCode::CHARACTER, + ); assert_eq!(4, instruction.b_field()); } #[test] fn decode_c_field() { - let instruction = Instruction::add_int(42, Operand::Constant(4), Operand::Register(2)); + let instruction = Instruction::add( + 42, + Operand::Constant(4), + TypeCode::STRING, + Operand::Register(2), + TypeCode::CHARACTER, + ); assert_eq!(2, instruction.c_field()); } #[test] fn decode_d_field() { - let instruction = Instruction::call(42, 4, 2, true); + let instruction = Instruction::add( + 42, + Operand::Constant(4), + TypeCode::STRING, + Operand::Register(2), + TypeCode::CHARACTER, + ); assert!(instruction.d_field()); } #[test] fn decode_b_is_constant() { - let instruction = Instruction::add_int(42, Operand::Constant(4), Operand::Register(2)); + let instruction = Instruction::add( + 42, + Operand::Constant(4), + TypeCode::STRING, + Operand::Register(2), + TypeCode::CHARACTER, + ); assert!(instruction.b_is_constant()); } #[test] fn decode_c_is_constant() { - let instruction = Instruction::add_int(42, Operand::Register(2), Operand::Constant(4)); + let instruction = Instruction::add( + 42, + Operand::Register(2), + TypeCode::STRING, + Operand::Constant(4), + TypeCode::CHARACTER, + ); assert!(instruction.c_is_constant()); } + + #[test] + fn decode_b_type() { + let instruction = Instruction::add( + 42, + Operand::Constant(4), + TypeCode::STRING, + Operand::Register(2), + TypeCode::CHARACTER, + ); + + assert_eq!(TypeCode::STRING, instruction.b_type()); + } + + #[test] + fn decode_c_type() { + let instruction = Instruction::add( + 42, + Operand::Constant(4), + TypeCode::STRING, + Operand::Register(2), + TypeCode::CHARACTER, + ); + + assert_eq!(TypeCode::CHARACTER, instruction.c_type()); + } } diff --git a/dust-lang/src/instruction/modulo.rs b/dust-lang/src/instruction/modulo.rs new file mode 100644 index 0000000..64d3548 --- /dev/null +++ b/dust-lang/src/instruction/modulo.rs @@ -0,0 +1,69 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode}; + +pub struct Modulo { + pub destination: u16, + pub left: Operand, + pub left_type: TypeCode, + pub right: Operand, + pub right_type: TypeCode, +} + +impl From for Modulo { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let (left, right) = instruction.b_and_c_as_operands(); + let left_type = instruction.b_type(); + let right_type = instruction.c_type(); + + Modulo { + destination, + left, + left_type, + right, + right_type, + } + } +} + +impl From for Instruction { + fn from(modulo: Modulo) -> Self { + let operation = Operation::MODULO; + let a_field = modulo.destination; + let (b_field, b_is_constant) = modulo.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = modulo.right.as_index_and_constant_flag(); + let b_type = modulo.left_type; + let c_type = modulo.right_type; + + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + b_is_constant, + c_is_constant, + b_type, + c_type, + ..Default::default() + } + .build() + } +} + +impl Display for Modulo { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let Modulo { + destination, + left, + left_type, + right, + right_type, + } = self; + + write!( + f, + "R{destination} = {left_type}({left}) % {right_type}({right})", + ) + } +} diff --git a/dust-lang/src/instruction/modulo_byte.rs b/dust-lang/src/instruction/modulo_byte.rs deleted file mode 100644 index 9e969d3..0000000 --- a/dust-lang/src/instruction/modulo_byte.rs +++ /dev/null @@ -1,54 +0,0 @@ -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 deleted file mode 100644 index 7b33022..0000000 --- a/dust-lang/src/instruction/modulo_float.rs +++ /dev/null @@ -1,54 +0,0 @@ -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 deleted file mode 100644 index e913893..0000000 --- a/dust-lang/src/instruction/modulo_int.rs +++ /dev/null @@ -1,54 +0,0 @@ -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 new file mode 100644 index 0000000..62fa34e --- /dev/null +++ b/dust-lang/src/instruction/multiply.rs @@ -0,0 +1,69 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode}; + +pub struct Multiply { + pub destination: u16, + pub left: Operand, + pub left_type: TypeCode, + pub right: Operand, + pub right_type: TypeCode, +} + +impl From for Multiply { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let (left, right) = instruction.b_and_c_as_operands(); + let left_type = instruction.b_type(); + let right_type = instruction.c_type(); + + Multiply { + destination, + left, + left_type, + right, + right_type, + } + } +} + +impl From for Instruction { + fn from(multiply: Multiply) -> Self { + let operation = Operation::MULTIPLY; + let a_field = multiply.destination; + let (b_field, b_is_constant) = multiply.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = multiply.right.as_index_and_constant_flag(); + let b_type = multiply.left_type; + let c_type = multiply.right_type; + + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + b_is_constant, + c_is_constant, + b_type, + c_type, + ..Default::default() + } + .build() + } +} + +impl Display for Multiply { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let Multiply { + destination, + left, + left_type, + right, + right_type, + } = self; + + write!( + f, + "R{destination} = {left_type}({left}) ✕ {right_type}({right})", + ) + } +} diff --git a/dust-lang/src/instruction/multiply_byte.rs b/dust-lang/src/instruction/multiply_byte.rs deleted file mode 100644 index 501776e..0000000 --- a/dust-lang/src/instruction/multiply_byte.rs +++ /dev/null @@ -1,54 +0,0 @@ -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 deleted file mode 100644 index 19f8292..0000000 --- a/dust-lang/src/instruction/multiply_float.rs +++ /dev/null @@ -1,54 +0,0 @@ -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 deleted file mode 100644 index 00fbdf5..0000000 --- a/dust-lang/src/instruction/multiply_int.rs +++ /dev/null @@ -1,54 +0,0 @@ -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 new file mode 100644 index 0000000..e2a4aa4 --- /dev/null +++ b/dust-lang/src/instruction/negate.rs @@ -0,0 +1,54 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode}; + +pub struct Negate { + pub destination: u16, + pub argument: Operand, + pub argument_type: TypeCode, +} + +impl From for Negate { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let argument = instruction.b_as_argument(); + let argument_type = instruction.b_type(); + + Negate { + destination, + argument, + argument_type, + } + } +} + +impl From for Instruction { + fn from(negate: Negate) -> Self { + let operation = Operation::NEGATE; + let a_field = negate.destination; + let (b_field, b_is_constant) = negate.argument.as_index_and_constant_flag(); + let b_type = negate.argument_type; + + InstructionBuilder { + operation, + a_field, + b_field, + b_is_constant, + b_type, + ..Default::default() + } + .build() + } +} + +impl Display for Negate { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let Negate { + destination, + argument, + argument_type, + } = self; + + write!(f, "R{destination} = -{argument_type}({argument})") + } +} diff --git a/dust-lang/src/instruction/negate_float.rs b/dust-lang/src/instruction/negate_float.rs deleted file mode 100644 index c0ed4d3..0000000 --- a/dust-lang/src/instruction/negate_float.rs +++ /dev/null @@ -1,48 +0,0 @@ -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 deleted file mode 100644 index 6f1f901..0000000 --- a/dust-lang/src/instruction/negate_int.rs +++ /dev/null @@ -1,48 +0,0 @@ -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 f26c4ea..51a06db 100644 --- a/dust-lang/src/instruction/not.rs +++ b/dust-lang/src/instruction/not.rs @@ -1,3 +1,5 @@ +use std::fmt::Display; + use crate::{Instruction, Operand, Operation}; use super::InstructionBuilder; @@ -35,3 +37,14 @@ impl From for Instruction { .build() } } + +impl Display for Not { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Not { + destination, + argument, + } = self; + + write!(f, "R{destination} = !{argument}") + } +} diff --git a/dust-lang/src/instruction/operation.rs b/dust-lang/src/instruction/operation.rs index ddded47..4c4a708 100644 --- a/dust-lang/src/instruction/operation.rs +++ b/dust-lang/src/instruction/operation.rs @@ -24,62 +24,20 @@ impl Operation { pub const GET_LOCAL: Operation = Operation(7); pub const SET_LOCAL: Operation = Operation(8); - // 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); + // Arithmetic + pub const ADD: Operation = Operation(9); + pub const SUBTRACT: Operation = Operation(16); + pub const MULTIPLY: Operation = Operation(19); + pub const DIVIDE: Operation = Operation(22); + pub const MODULO: Operation = Operation(25); - // 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); + // Comparison + pub const EQUAL: Operation = Operation(28); + pub const LESS: Operation = Operation(36); + pub const LESS_EQUAL: Operation = Operation(41); // Unary operations - pub const NEGATE_INT: Operation = Operation(46); - pub const NEGATE_FLOAT: Operation = Operation(47); + pub const NEGATE: Operation = Operation(46); pub const NOT: Operation = Operation(48); // Logical operations @@ -107,45 +65,15 @@ impl Operation { Self::LOAD_SELF => "LOAD_SELF", Self::GET_LOCAL => "GET_LOCAL", Self::SET_LOCAL => "SET_LOCAL", - 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::ADD => "ADD", + Self::SUBTRACT => "SUBTRACT", + Self::MULTIPLY => "MULTIPLY", + Self::DIVIDE => "DIVIDE", + Self::MODULO => "MODULO", + Self::EQUAL => "EQUAL", + Self::LESS => "LESS", + Self::LESS_EQUAL => "LESS_EQUAL", + Self::NEGATE => "NEGATE", Self::NOT => "NOT", Self::TEST => "TEST", Self::TEST_SET => "TEST_SET", @@ -153,57 +81,30 @@ impl Operation { Self::CALL_NATIVE => "CALL_NATIVE", Self::JUMP => "JUMP", Self::RETURN => "RETURN", - _ => Self::panic_from_unknown_code(self.0), + _ => self.panic_from_unknown_code(), } } 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 + Operation::ADD + | Operation::SUBTRACT + | Operation::MULTIPLY + | Operation::DIVIDE + | Operation::MODULO ) } 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 + Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL ) } - pub fn panic_from_unknown_code(code: u8) -> ! { - panic!("Unknown operation code: {code}"); + pub fn panic_from_unknown_code(self) -> ! { + panic!("Unknown operation code: {}", self.0); } } diff --git a/dust-lang/src/instruction/return.rs b/dust-lang/src/instruction/return.rs index e1c9040..b1c6e76 100644 --- a/dust-lang/src/instruction/return.rs +++ b/dust-lang/src/instruction/return.rs @@ -1,3 +1,5 @@ +use std::fmt::{self, Display, Formatter}; + use crate::{Instruction, Operation}; use super::InstructionBuilder; @@ -34,3 +36,18 @@ impl From for Instruction { .build() } } + +impl Display for Return { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let Return { + should_return_value, + return_register, + } = self; + + if *should_return_value { + write!(f, "RETURN R{return_register}") + } else { + write!(f, "RETURN") + } + } +} diff --git a/dust-lang/src/instruction/subtract.rs b/dust-lang/src/instruction/subtract.rs new file mode 100644 index 0000000..df3f68f --- /dev/null +++ b/dust-lang/src/instruction/subtract.rs @@ -0,0 +1,69 @@ +use std::fmt::{self, Display, Formatter}; + +use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode}; + +pub struct Subtract { + pub destination: u16, + pub left: Operand, + pub left_type: TypeCode, + pub right: Operand, + pub right_type: TypeCode, +} + +impl From for Subtract { + fn from(instruction: Instruction) -> Self { + let destination = instruction.a_field(); + let (left, right) = instruction.b_and_c_as_operands(); + let left_type = instruction.b_type(); + let right_type = instruction.c_type(); + + Subtract { + destination, + left, + left_type, + right, + right_type, + } + } +} + +impl From for Instruction { + fn from(subtract: Subtract) -> Self { + let operation = Operation::SUBTRACT; + let a_field = subtract.destination; + let (b_field, b_is_constant) = subtract.left.as_index_and_constant_flag(); + let (c_field, c_is_constant) = subtract.right.as_index_and_constant_flag(); + let b_type = subtract.left_type; + let c_type = subtract.right_type; + + InstructionBuilder { + operation, + a_field, + b_field, + c_field, + b_is_constant, + c_is_constant, + b_type, + c_type, + ..Default::default() + } + .build() + } +} + +impl Display for Subtract { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let Subtract { + destination, + left, + left_type, + right, + right_type, + } = self; + + write!( + f, + "R{destination} = {left_type}({left}) - {right_type}({right})", + ) + } +} diff --git a/dust-lang/src/instruction/subtract_byte.rs b/dust-lang/src/instruction/subtract_byte.rs deleted file mode 100644 index 76de9a7..0000000 --- a/dust-lang/src/instruction/subtract_byte.rs +++ /dev/null @@ -1,54 +0,0 @@ -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 deleted file mode 100644 index d806a49..0000000 --- a/dust-lang/src/instruction/subtract_float.rs +++ /dev/null @@ -1,54 +0,0 @@ -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 deleted file mode 100644 index b9b2ffd..0000000 --- a/dust-lang/src/instruction/subtract_int.rs +++ /dev/null @@ -1,54 +0,0 @@ -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 62124dd..e826ed3 100644 --- a/dust-lang/src/instruction/test.rs +++ b/dust-lang/src/instruction/test.rs @@ -1,3 +1,5 @@ +use std::fmt::{self, Display, Formatter}; + use crate::{Instruction, Operation}; use super::InstructionBuilder; @@ -33,3 +35,15 @@ impl From for Instruction { .build() } } + +impl Display for Test { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let Test { + operand_register, + test_value, + } = self; + let bang = if *test_value { "" } else { "!" }; + + write!(f, "if {bang}R{operand_register} {{ JUMP +1 }}") + } +} diff --git a/dust-lang/src/instruction/test_set.rs b/dust-lang/src/instruction/test_set.rs index 4ae8191..c946767 100644 --- a/dust-lang/src/instruction/test_set.rs +++ b/dust-lang/src/instruction/test_set.rs @@ -1,3 +1,5 @@ +use std::fmt::{self, Display, Formatter}; + use crate::{Instruction, Operand, Operation}; use super::InstructionBuilder; @@ -40,3 +42,19 @@ impl From for Instruction { .build() } } + +impl Display for TestSet { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let TestSet { + destination, + argument, + test_value, + } = self; + let bang = if *test_value { "" } else { "!" }; + + write!( + f, + "if {bang}{argument} {{ JUMP +1 }} else {{ R{destination} = {argument} }}" + ) + } +} diff --git a/dust-lang/src/instruction/type_code.rs b/dust-lang/src/instruction/type_code.rs new file mode 100644 index 0000000..daf6e82 --- /dev/null +++ b/dust-lang/src/instruction/type_code.rs @@ -0,0 +1,31 @@ +use std::fmt::Display; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct TypeCode(pub u8); + +impl TypeCode { + pub const BOOLEAN: TypeCode = TypeCode(0); + pub const BYTE: TypeCode = TypeCode(1); + pub const CHARACTER: TypeCode = TypeCode(2); + pub const FLOAT: TypeCode = TypeCode(3); + pub const INTEGER: TypeCode = TypeCode(4); + pub const STRING: TypeCode = TypeCode(5); + + pub fn panic_from_unknown_code(self) -> ! { + panic!("Unknown type code: {}", self.0); + } +} + +impl Display for TypeCode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + TypeCode::BOOLEAN => write!(f, "bool"), + TypeCode::BYTE => write!(f, "byte"), + TypeCode::CHARACTER => write!(f, "char"), + TypeCode::FLOAT => write!(f, "float"), + TypeCode::INTEGER => write!(f, "int"), + TypeCode::STRING => write!(f, "str"), + _ => self.panic_from_unknown_code(), + } + } +} diff --git a/dust-lang/src/value/mod.rs b/dust-lang/src/value/mod.rs index 6a37fbf..b9b7d91 100644 --- a/dust-lang/src/value/mod.rs +++ b/dust-lang/src/value/mod.rs @@ -58,6 +58,30 @@ impl Value { } } + pub fn as_byte(&self) -> Option { + if let Value::Concrete(ConcreteValue::Byte(byte)) = self { + Some(*byte) + } else { + None + } + } + + pub fn as_character(&self) -> Option { + if let Value::Concrete(ConcreteValue::Character(character)) = self { + Some(*character) + } else { + None + } + } + + pub fn as_float(&self) -> Option { + if let Value::Concrete(ConcreteValue::Float(float)) = self { + Some(*float) + } else { + None + } + } + pub fn as_function(&self) -> Option<&Function> { if let Value::Function(function) = self { Some(function) diff --git a/dust-lang/src/vm/run_action.rs b/dust-lang/src/vm/run_action.rs index d97f0d7..25a4527 100644 --- a/dust-lang/src/vm/run_action.rs +++ b/dust-lang/src/vm/run_action.rs @@ -3,8 +3,9 @@ use tracing::trace; use crate::{ AbstractList, ConcreteValue, Instruction, Operand, Type, Value, instruction::{ - Call, CallNative, Close, GetLocal, Jump, LoadBoolean, LoadConstant, LoadFunction, LoadList, - LoadSelf, Not, Point, Return, SetLocal, Test, TestSet, + 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, TypeCode, }, vm::FunctionCall, }; @@ -252,12 +253,42 @@ pub fn add(instruction: Instruction, data: &mut ThreadData) -> bool { let Add { destination, left, + left_type, right, + right_type, } = instruction.into(); - let left = data.get_argument_unchecked(left); - let right = data.get_argument_unchecked(right); - let sum = left.add(right); - let register = Register::Value(sum); + let sum = match (left_type, right_type) { + (TypeCode::INTEGER, TypeCode::INTEGER) => { + let left = unsafe { + data.get_argument_unchecked(left) + .as_integer() + .unwrap_unchecked() + }; + let right = unsafe { + data.get_argument_unchecked(right) + .as_integer() + .unwrap_unchecked() + }; + + ConcreteValue::Integer(left + right) + } + (TypeCode::FLOAT, TypeCode::FLOAT) => { + let left = unsafe { + data.get_argument_unchecked(left) + .as_float() + .unwrap_unchecked() + }; + let right = unsafe { + data.get_argument_unchecked(right) + .as_float() + .unwrap_unchecked() + }; + + ConcreteValue::Float(left + right) + } + _ => panic!("VM Error: Cannot add values"), + }; + let register = Register::Value(Value::Concrete(sum)); data.set_register(destination, register); @@ -270,12 +301,42 @@ pub fn subtract(instruction: Instruction, data: &mut ThreadData) -> bool { let Subtract { destination, left, + left_type, right, + right_type, } = instruction.into(); - let left = data.get_argument_unchecked(left); - let right = data.get_argument_unchecked(right); - let difference = left.subtract(right); - let register = Register::Value(difference); + let difference = match (left_type, right_type) { + (TypeCode::INTEGER, TypeCode::INTEGER) => { + let left = unsafe { + data.get_argument_unchecked(left) + .as_integer() + .unwrap_unchecked() + }; + let right = unsafe { + data.get_argument_unchecked(right) + .as_integer() + .unwrap_unchecked() + }; + + ConcreteValue::Integer(left - right) + } + (TypeCode::FLOAT, TypeCode::FLOAT) => { + let left = unsafe { + data.get_argument_unchecked(left) + .as_float() + .unwrap_unchecked() + }; + let right = unsafe { + data.get_argument_unchecked(right) + .as_float() + .unwrap_unchecked() + }; + + ConcreteValue::Float(left - right) + } + _ => panic!("VM Error: Cannot subtract values"), + }; + let register = Register::Value(Value::Concrete(difference)); data.set_register(destination, register); @@ -288,20 +349,42 @@ pub fn multiply(instruction: Instruction, data: &mut ThreadData) -> bool { let Multiply { destination, left, + left_type, right, + right_type, } = instruction.into(); - let left = data.get_argument_unchecked(left); - let right = data.get_argument_unchecked(right); - let product = match (left, right) { - (Value::Concrete(left), Value::Concrete(right)) => match (left, right) { - (ConcreteValue::Integer(left), ConcreteValue::Integer(right)) => { - ConcreteValue::Integer(left * right).to_value() - } - _ => panic!("Value Error: Cannot multiply values"), - }, - _ => panic!("Value Error: Cannot multiply values"), + let product = match (left_type, right_type) { + (TypeCode::INTEGER, TypeCode::INTEGER) => { + let left = unsafe { + data.get_argument_unchecked(left) + .as_integer() + .unwrap_unchecked() + }; + let right = unsafe { + data.get_argument_unchecked(right) + .as_integer() + .unwrap_unchecked() + }; + + ConcreteValue::Integer(left * right) + } + (TypeCode::FLOAT, TypeCode::FLOAT) => { + let left = unsafe { + data.get_argument_unchecked(left) + .as_float() + .unwrap_unchecked() + }; + let right = unsafe { + data.get_argument_unchecked(right) + .as_float() + .unwrap_unchecked() + }; + + ConcreteValue::Float(left * right) + } + _ => panic!("VM Error: Cannot multiply values"), }; - let register = Register::Value(product); + let register = Register::Value(Value::Concrete(product)); data.set_register(destination, register); @@ -314,20 +397,42 @@ pub fn divide(instruction: Instruction, data: &mut ThreadData) -> bool { let Divide { destination, left, + left_type, right, + right_type, } = instruction.into(); - let left = data.get_argument_unchecked(left); - let right = data.get_argument_unchecked(right); - let quotient = match (left, right) { - (Value::Concrete(left), Value::Concrete(right)) => match (left, right) { - (ConcreteValue::Integer(left), ConcreteValue::Integer(right)) => { - ConcreteValue::Integer(left / right).to_value() - } - _ => panic!("Value Error: Cannot divide values"), - }, - _ => panic!("Value Error: Cannot divide values"), + let quotient = match (left_type, right_type) { + (TypeCode::INTEGER, TypeCode::INTEGER) => { + let left = unsafe { + data.get_argument_unchecked(left) + .as_integer() + .unwrap_unchecked() + }; + let right = unsafe { + data.get_argument_unchecked(right) + .as_integer() + .unwrap_unchecked() + }; + + ConcreteValue::Integer(left / right) + } + (TypeCode::FLOAT, TypeCode::FLOAT) => { + let left = unsafe { + data.get_argument_unchecked(left) + .as_float() + .unwrap_unchecked() + }; + let right = unsafe { + data.get_argument_unchecked(right) + .as_float() + .unwrap_unchecked() + }; + + ConcreteValue::Float(left / right) + } + _ => panic!("VM Error: Cannot divide values"), }; - let register = Register::Value(quotient); + let register = Register::Value(Value::Concrete(quotient)); data.set_register(destination, register); @@ -340,20 +445,28 @@ pub fn modulo(instruction: Instruction, data: &mut ThreadData) -> bool { let Modulo { destination, left, + left_type, right, + right_type, } = instruction.into(); - let left = data.get_argument_unchecked(left); - let right = data.get_argument_unchecked(right); - let remainder = match (left, right) { - (Value::Concrete(left), Value::Concrete(right)) => match (left, right) { - (ConcreteValue::Integer(left), ConcreteValue::Integer(right)) => { - ConcreteValue::Integer(left % right).to_value() - } - _ => panic!("Value Error: Cannot modulo values"), - }, - _ => panic!("Value Error: Cannot modulo values"), + let remainder = match (left_type, right_type) { + (TypeCode::INTEGER, TypeCode::INTEGER) => { + let left = unsafe { + data.get_argument_unchecked(left) + .as_integer() + .unwrap_unchecked() + }; + let right = unsafe { + data.get_argument_unchecked(right) + .as_integer() + .unwrap_unchecked() + }; + + ConcreteValue::Integer(left % right) + } + _ => panic!("VM Error: Cannot modulo values"), }; - let register = Register::Value(remainder); + let register = Register::Value(Value::Concrete(remainder)); data.set_register(destination, register); @@ -415,12 +528,18 @@ pub fn test_set(instruction: Instruction, data: &mut ThreadData) -> bool { } pub fn equal(instruction: Instruction, data: &mut ThreadData) -> bool { - let Equal { value, left, right } = instruction.into(); + let Equal { + comparator, + left, + left_type, + right, + right_type, + } = instruction.into(); let left = data.get_argument_unchecked(left); let right = data.get_argument_unchecked(right); let is_equal = left.equals(right); - if is_equal == value { + if is_equal == comparator { let current_call = data.call_stack.last_mut_unchecked(); current_call.ip += 1; @@ -432,12 +551,18 @@ pub fn equal(instruction: Instruction, data: &mut ThreadData) -> bool { } pub fn less(instruction: Instruction, data: &mut ThreadData) -> bool { - let Less { value, left, right } = instruction.into(); + let Less { + comparator, + left, + left_type, + right, + right_type, + } = instruction.into(); let left = data.get_argument_unchecked(left); let right = data.get_argument_unchecked(right); let is_less = left < right; - if is_less == value { + if is_less == comparator { let current_call = data.call_stack.last_mut_unchecked(); current_call.ip += 1; @@ -449,12 +574,18 @@ pub fn less(instruction: Instruction, data: &mut ThreadData) -> bool { } pub fn less_equal(instruction: Instruction, data: &mut ThreadData) -> bool { - let LessEqual { value, left, right } = instruction.into(); + let LessEqual { + comparator, + left, + left_type, + right, + right_type, + } = instruction.into(); let left = data.get_argument_unchecked(left); let right = data.get_argument_unchecked(right); let is_less_or_equal = left <= right; - if is_less_or_equal == value { + if is_less_or_equal == comparator { let current_call = data.call_stack.last_mut_unchecked(); current_call.ip += 1; @@ -469,6 +600,7 @@ pub fn negate(instruction: Instruction, data: &mut ThreadData) -> bool { let Negate { destination, argument, + argument_type, } = instruction.into(); let argument = data.get_argument_unchecked(argument); let negated = argument.negate();