From d5b4278571e876b2e68707c1a5b8180cd41aa105 Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 21 Feb 2025 05:00:20 -0500 Subject: [PATCH] Implement function calls in the VM --- dust-lang/src/chunk/disassembler.rs | 57 +- dust-lang/src/chunk/mod.rs | 1 + dust-lang/src/compiler/error.rs | 12 +- dust-lang/src/compiler/mod.rs | 123 +- dust-lang/src/dust_error.rs | 47 +- dust-lang/src/instruction/call.rs | 49 +- dust-lang/src/instruction/load_function.rs | 2 +- dust-lang/src/instruction/mod.rs | 8 +- dust-lang/src/instruction/move.rs | 2 + dust-lang/src/lib.rs | 2 +- dust-lang/src/native_function/assert.rs | 22 - dust-lang/src/native_function/io.rs | 56 - dust-lang/src/native_function/mod.rs | 150 +- dust-lang/src/native_function/random.rs | 37 - dust-lang/src/native_function/thread.rs | 11 - dust-lang/src/type.rs | 2 +- dust-lang/src/value/abstract_list.rs | 246 +- dust-lang/src/value/concrete_value.rs | 11 +- dust-lang/src/value/function.rs | 3 +- dust-lang/src/vm/action/add.rs | 287 -- dust-lang/src/vm/action/equal.rs | 217 -- dust-lang/src/vm/action/jump.rs | 48 - dust-lang/src/vm/action/less.rs | 212 -- dust-lang/src/vm/action/less_equal.rs | 227 -- dust-lang/src/vm/action/mod.rs | 623 ---- dust-lang/src/vm/call_frame.rs | 317 -- dust-lang/src/vm/mod.rs | 243 +- dust-lang/src/vm/thread.rs | 2921 +++++++++-------- .../compiler_errors/assignment_errors.rs | 10 +- 29 files changed, 2202 insertions(+), 3744 deletions(-) delete mode 100644 dust-lang/src/native_function/assert.rs delete mode 100644 dust-lang/src/native_function/io.rs delete mode 100644 dust-lang/src/native_function/random.rs delete mode 100644 dust-lang/src/native_function/thread.rs delete mode 100644 dust-lang/src/vm/action/add.rs delete mode 100644 dust-lang/src/vm/action/equal.rs delete mode 100644 dust-lang/src/vm/action/jump.rs delete mode 100644 dust-lang/src/vm/action/less.rs delete mode 100644 dust-lang/src/vm/action/less_equal.rs delete mode 100644 dust-lang/src/vm/action/mod.rs delete mode 100644 dust-lang/src/vm/call_frame.rs diff --git a/dust-lang/src/chunk/disassembler.rs b/dust-lang/src/chunk/disassembler.rs index 332dd03..da763b6 100644 --- a/dust-lang/src/chunk/disassembler.rs +++ b/dust-lang/src/chunk/disassembler.rs @@ -65,6 +65,13 @@ const LOCAL_BORDERS: [&str; 3] = [ "╰─────┴────────────────┴──────────────────────────┴────────────┴───────┴───────╯", ]; +const ARGUMENT_LIST_COLUMNS: [(&str, usize); 2] = [("i", 5), ("REGISTERS", 21)]; +const ARGUMENT_LIST_BORDERS: [&str; 3] = [ + "╭─────┬─────────────────────╮", + "├─────┼─────────────────────┤", + "╰─────┴─────────────────────╯", +]; + const CONSTANT_COLUMNS: [(&str, usize); 3] = [("i", 5), ("TYPE", 26), ("VALUE", 26)]; const CONSTANT_BORDERS: [&str; 3] = [ "╭─────┬──────────────────────────┬──────────────────────────╮", @@ -326,8 +333,17 @@ impl<'a, W: Write> Disassembler<'a, W> { .map(|value| value.to_string()) .unwrap_or_else(|| "unknown".to_string()); let type_display = r#type.to_string(); - let type_caps = type_display.to_uppercase(); - let register_display = format!("R_{type_caps}_{register_index}"); + let register_display = match r#type { + Type::Boolean => format!("R_BOOL_{register_index}"), + Type::Byte => format!("R_BYTE_{register_index}"), + Type::Character => format!("R_CHAR_{register_index}"), + Type::Float => format!("R_FLOAT_{register_index}"), + Type::Integer => format!("R_INT_{register_index}"), + Type::String => format!("R_STR_{register_index}"), + Type::List(_) => format!("R_LIST_{register_index}"), + Type::Function(_) => format!("R_FN_{register_index}"), + _ => unreachable!(), + }; let scope = scope.to_string(); let row = format!( "│{index:^5}│{identifier_display:^16}│{type_display:^26}│{register_display:^12}│{scope:^7}│{is_mutable:^7}│" @@ -423,7 +439,38 @@ impl<'a, W: Write> Disassembler<'a, W> { Ok(()) } - pub fn write_prototype_section(&mut self) -> Result<(), io::Error> { + fn write_argument_list_section(&mut self) -> Result<(), io::Error> { + let mut column_name_line = String::new(); + + for (column_name, width) in ARGUMENT_LIST_COLUMNS { + column_name_line.push_str(&format!("│{:^width$}", column_name, width = width)); + } + + column_name_line.push('│'); + self.write_center_border_bold("Argument Lists")?; + self.write_center_border(ARGUMENT_LIST_BORDERS[0])?; + self.write_center_border(&column_name_line)?; + self.write_center_border(ARGUMENT_LIST_BORDERS[1])?; + + for (index, argument_list) in self.chunk.argument_lists.iter().enumerate() { + let argument_list_display = format!( + "│{index:^5}│{:^21}│", + argument_list + .iter() + .map(|index| index.to_string()) + .collect::>() + .join(", ") + ); + + self.write_center_border(&argument_list_display)?; + } + + self.write_center_border(ARGUMENT_LIST_BORDERS[2])?; + + Ok(()) + } + + fn write_prototype_section(&mut self) -> Result<(), io::Error> { self.write_center_border_bold("Prototypes")?; for chunk in &self.chunk.prototypes { @@ -495,6 +542,10 @@ impl<'a, W: Write> Disassembler<'a, W> { self.write_constant_section()?; } + if !self.chunk.argument_lists.is_empty() { + self.write_argument_list_section()?; + } + if !self.chunk.prototypes.is_empty() { self.write_prototype_section()?; } diff --git a/dust-lang/src/chunk/mod.rs b/dust-lang/src/chunk/mod.rs index 4e35e81..a16d807 100644 --- a/dust-lang/src/chunk/mod.rs +++ b/dust-lang/src/chunk/mod.rs @@ -42,6 +42,7 @@ pub struct Chunk { pub string_constants: Vec, pub locals: Vec, pub prototypes: Vec>, + pub argument_lists: Vec>, pub boolean_register_count: u16, pub byte_register_count: u16, diff --git a/dust-lang/src/compiler/error.rs b/dust-lang/src/compiler/error.rs index 6a4be85..f9e7108 100644 --- a/dust-lang/src/compiler/error.rs +++ b/dust-lang/src/compiler/error.rs @@ -222,12 +222,6 @@ impl AnnotatedError for CompileError { fn detail_snippets(&self) -> Vec<(String, Span)> { match self { - Self::CannotAddType { - argument_type, - position, - } => { - vec![(format!("Cannot add type `{}`", argument_type), *position)] - } Self::CannotAddArguments { left_type, left_position, @@ -242,6 +236,12 @@ impl AnnotatedError for CompileError { ), ] } + Self::CannotAddType { + argument_type, + position, + } => { + vec![(format!("Cannot add type `{}`", argument_type), *position)] + } Self::ReturnTypeConflict { conflict, position } => { vec![( format!( diff --git a/dust-lang/src/compiler/mod.rs b/dust-lang/src/compiler/mod.rs index 9b6fa84..e813acc 100644 --- a/dust-lang/src/compiler/mod.rs +++ b/dust-lang/src/compiler/mod.rs @@ -107,6 +107,11 @@ pub struct Compiler<'src> { /// [`Compiler::finish`] is called. prototypes: Vec>, + /// Lists of arguments for each function call. The integers represent the register of each + /// argument. Note that the type of each argument is not stored, so the caller must check the + /// function's type to determine the type of each argument. + argument_lists: Vec>, + /// The first boolean register index that the compiler should use. This is used to avoid reusing /// the registers that are used for the function's arguments. minimum_boolean_register: u16, @@ -179,6 +184,7 @@ impl<'src> Compiler<'src> { string_constants: Vec::new(), locals: Vec::new(), prototypes: Vec::new(), + argument_lists: Vec::new(), lexer, minimum_byte_register: 0, minimum_boolean_register: 0, @@ -212,20 +218,12 @@ impl<'src> Compiler<'src> { self.current_position.to_string() ); - loop { + while !matches!(self.current_token, Token::Eof | Token::RightBrace) { self.parse(Precedence::None)?; - - if matches!(self.current_token, Token::Eof | Token::RightBrace) { - if self.get_last_operation() == Some(Operation::RETURN) { - break; - } - - self.parse_implicit_return()?; - - break; - } } + self.parse_implicit_return()?; + info!("End chunk"); Ok(()) @@ -237,6 +235,12 @@ impl<'src> Compiler<'src> { /// will allow [`Compiler::function_name`] to be both the name used for recursive calls and the /// name of the function when it is compiled. The name can later be seen in the VM's call stack. pub fn finish(mut self) -> Chunk { + if self.instructions.is_empty() { + let r#return = Instruction::r#return(false, 0, TypeCode::NONE); + + self.emit_instruction(r#return, Type::None, self.current_position); + } + let boolean_register_count = self.next_boolean_register(); let byte_register_count = self.next_byte_register(); let character_register_count = self.next_character_register(); @@ -262,6 +266,7 @@ impl<'src> Compiler<'src> { string_constants: self.string_constants, locals: self.locals, prototypes: self.prototypes, + argument_lists: self.argument_lists, boolean_register_count, byte_register_count, character_register_count, @@ -397,7 +402,7 @@ impl<'src> Compiler<'src> { .iter() .rev() .find_map(|(instruction, _, _)| { - if instruction.b_type() == TypeCode::FUNCTION && instruction.yields_value() { + if instruction.operation() == Operation::LOAD_FUNCTION { Some(instruction.a_field() + 1) } else { None @@ -1253,6 +1258,8 @@ impl<'src> Compiler<'src> { Type::Float => self.next_float_register(), Type::Integer => self.next_integer_register(), Type::String => self.next_string_register(), + Type::List(_) => self.next_list_register(), + Type::Function(_) => self.next_function_register(), _ => todo!(), }; let point = Instruction::r#move( @@ -1801,26 +1808,21 @@ impl<'src> Compiler<'src> { let r#return = Instruction::r#return(false, 0, TypeCode::NONE); self.emit_instruction(r#return, Type::None, self.current_position); - } else { - let (previous_expression_type, previous_register) = self - .instructions - .last() - .map(|(instruction, r#type, _)| { - if instruction.yields_value() { - (r#type.clone(), instruction.a_field()) - } else { - (Type::None, 0) - } - }) - .ok_or_else(|| CompileError::ExpectedExpression { - found: self.previous_token.to_owned(), - position: self.previous_position, - })?; - + } else if let Some((previous_expression_type, previous_destination_register)) = + self.instructions.last().map(|(instruction, r#type, _)| { + if r#type == &Type::None { + (Type::None, 0) + } else if instruction.yields_value() { + (r#type.clone(), instruction.a_field()) + } else { + (Type::None, 0) + } + }) + { let should_return_value = previous_expression_type != Type::None; let r#return = Instruction::r#return( should_return_value, - previous_register, + previous_destination_register, previous_expression_type.type_code(), ); @@ -2034,12 +2036,13 @@ impl<'src> Compiler<'src> { } let load_function = Instruction::load_function(destination, prototype_index, false); + let r#type = if identifier.is_some() { + Type::None + } else { + Type::Function(function_type) + }; - self.emit_instruction( - load_function, - Type::Function(function_type), - Span(function_start, function_end), - ); + self.emit_instruction(load_function, r#type, Span(function_start, function_end)); Ok(()) } @@ -2056,19 +2059,8 @@ impl<'src> Compiler<'src> { found: self.previous_token.to_owned(), position: self.previous_position, })?; + let b_field = last_instruction.b_field(); - if !matches!( - last_instruction_type, - Type::Function { .. } | Type::SelfFunction - ) { - return Err(CompileError::ExpectedFunction { - found: self.previous_token.to_owned(), - actual_type: last_instruction_type.clone(), - position: self.previous_position, - }); - } - - let function_register = last_instruction.a_field(); let function_return_type = match last_instruction_type { Type::Function(function_type) => *function_type.return_type.clone(), Type::SelfFunction => *self.r#type.return_type.clone(), @@ -2080,17 +2072,43 @@ impl<'src> Compiler<'src> { }); } }; - let is_recursive = last_instruction_type == &Type::SelfFunction; + let function_register = if last_instruction.operation() == Operation::LOAD_FUNCTION { + last_instruction.a_field() + } else if last_instruction.operation() == Operation::MOVE { + self.instructions.pop(); - let mut argument_count = 0; + b_field + } else { + return Err(CompileError::ExpectedFunction { + found: self.previous_token.to_owned(), + actual_type: last_instruction_type.clone(), + position: self.previous_position, + }); + }; + + let mut argument_list = Vec::new(); while !self.allow(Token::RightParenthesis)? { self.parse_expression()?; self.allow(Token::Comma)?; - argument_count += 1; + let argument_index = match self.get_last_instruction_type() { + Type::Boolean => self.next_boolean_register() - 1, + Type::Byte => self.next_byte_register() - 1, + Type::Character => self.next_character_register() - 1, + Type::Float => self.next_float_register() - 1, + Type::Integer => self.next_integer_register() - 1, + Type::String => self.next_string_register() - 1, + _ => todo!(), + }; + + argument_list.push(argument_index); } + let argument_list_index = self.argument_lists.len() as u16; + + self.argument_lists.push(argument_list); + let end = self.current_position.1; let destination = match function_return_type { Type::None => 0, @@ -2102,7 +2120,12 @@ impl<'src> Compiler<'src> { Type::String => self.next_string_register(), _ => todo!(), }; - let call = Instruction::call(destination, function_register, argument_count, is_recursive); + let call = Instruction::call( + destination, + function_register, + argument_list_index, + function_return_type.type_code(), + ); self.emit_instruction(call, function_return_type, Span(start, end)); diff --git a/dust-lang/src/dust_error.rs b/dust-lang/src/dust_error.rs index da94b40..b870c9b 100644 --- a/dust-lang/src/dust_error.rs +++ b/dust-lang/src/dust_error.rs @@ -4,50 +4,36 @@ use std::fmt::{self, Display, Formatter}; use annotate_snippets::{Level, Renderer, Snippet}; -use crate::{CompileError, NativeFunctionError, Span}; +use crate::{CompileError, Span}; /// A top-level error that can occur during the interpretation of Dust code. #[derive(Debug, PartialEq)] -pub enum DustError<'src> { - Compile { - error: CompileError, - source: &'src str, - }, - NativeFunction { - error: NativeFunctionError, - source: &'src str, - }, +pub struct DustError<'src> { + pub error: CompileError, + pub source: &'src str, } impl<'src> DustError<'src> { pub fn compile(error: CompileError, source: &'src str) -> Self { - DustError::Compile { error, source } + DustError { error, source } } pub fn report(&self) -> String { - let (title, description, detail_snippets, help_snippets) = match self { - Self::Compile { error, .. } => ( - CompileError::title(), - error.description(), - error.detail_snippets(), - error.help_snippets(), - ), - Self::NativeFunction { error, .. } => ( - NativeFunctionError::title(), - error.description(), - error.detail_snippets(), - error.help_snippets(), - ), - }; + let (title, description, detail_snippets, help_snippets) = ( + CompileError::title(), + self.error.description(), + self.error.detail_snippets(), + self.error.help_snippets(), + ); let label = format!("{}: {}", title, description); let message = Level::Error .title(&label) .snippets(detail_snippets.iter().map(|(details, position)| { - Snippet::source(self.source()) + Snippet::source(self.source) .annotation(Level::Info.span(position.0..position.1).label(details)) })) .snippets(help_snippets.iter().map(|(help, position)| { - Snippet::source(self.source()) + Snippet::source(self.source) .annotation(Level::Help.span(position.0..position.1).label(help)) })); let mut report = String::new(); @@ -57,13 +43,6 @@ impl<'src> DustError<'src> { report } - - fn source(&self) -> &str { - match self { - Self::Compile { source, .. } => source, - Self::NativeFunction { source, .. } => source, - } - } } impl Display for DustError<'_> { diff --git a/dust-lang/src/instruction/call.rs b/dust-lang/src/instruction/call.rs index cbbf5a1..7ea459b 100644 --- a/dust-lang/src/instruction/call.rs +++ b/dust-lang/src/instruction/call.rs @@ -2,27 +2,27 @@ use std::fmt::{self, Display, Formatter}; use crate::{Instruction, Operation}; -use super::InstructionFields; +use super::{InstructionFields, TypeCode}; pub struct Call { pub destination: u16, pub function_register: u16, - pub argument_count: u16, - pub is_recursive: bool, + pub argument_list_index: u16, + pub return_type: TypeCode, } impl From for Call { fn from(instruction: Instruction) -> Self { let destination = instruction.a_field(); let function_register = instruction.b_field(); - let argument_count = instruction.c_field(); - let is_recursive = instruction.d_field(); + let argument_list_index = instruction.c_field(); + let return_type = instruction.b_type(); Call { destination, function_register, - argument_count, - is_recursive, + argument_list_index, + return_type, } } } @@ -31,15 +31,15 @@ impl From for Instruction { fn from(call: Call) -> Self { let a_field = call.destination; let b_field = call.function_register; - let c_field = call.argument_count; - let d_field = call.is_recursive; + let b_type = call.return_type; + let c_field = call.argument_list_index; InstructionFields { operation: Operation::CALL, a_field, b_field, + b_type, c_field, - d_field, ..Default::default() } .build() @@ -51,23 +51,24 @@ impl Display for Call { let Call { destination, function_register, - argument_count, + argument_list_index, + return_type, .. } = 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})" - ) - } + match *return_type { + TypeCode::NONE => {} + TypeCode::BOOLEAN => write!(f, "R_BOOL_{destination} = ")?, + TypeCode::BYTE => write!(f, "R_BYTE_{destination} = ")?, + TypeCode::CHARACTER => write!(f, "R_CHR_{destination} = ")?, + TypeCode::FLOAT => write!(f, "R_FLT_{destination} = ")?, + TypeCode::INTEGER => write!(f, "R_INT_{destination} = ")?, + TypeCode::STRING => write!(f, "R_STR_{destination} = ")?, + TypeCode::LIST => write!(f, "R_LIST_{destination} = ")?, + TypeCode::FUNCTION => write!(f, "R_FN_{destination} = ")?, + _ => unreachable!(), } + + write!(f, "R_FN_{function_register}({argument_list_index})") } } diff --git a/dust-lang/src/instruction/load_function.rs b/dust-lang/src/instruction/load_function.rs index f0a3252..bcf5265 100644 --- a/dust-lang/src/instruction/load_function.rs +++ b/dust-lang/src/instruction/load_function.rs @@ -43,7 +43,7 @@ impl Display for LoadFunction { jump_next, } = self; - write!(f, "R{destination} = P{prototype_index}")?; + write!(f, "R_FN_{destination} = P{prototype_index}")?; if *jump_next { write!(f, " JUMP +1")?; diff --git a/dust-lang/src/instruction/mod.rs b/dust-lang/src/instruction/mod.rs index ed9252b..22e41af 100644 --- a/dust-lang/src/instruction/mod.rs +++ b/dust-lang/src/instruction/mod.rs @@ -544,14 +544,14 @@ impl Instruction { pub fn call( destination: u16, function_register: u16, - argument_count: u16, - is_recursive: bool, + argument_list_register: u16, + return_type: TypeCode, ) -> Instruction { Instruction::from(Call { destination, function_register, - argument_count, - is_recursive, + argument_list_index: argument_list_register, + return_type, }) } diff --git a/dust-lang/src/instruction/move.rs b/dust-lang/src/instruction/move.rs index d7698a2..7f65e67 100644 --- a/dust-lang/src/instruction/move.rs +++ b/dust-lang/src/instruction/move.rs @@ -51,6 +51,8 @@ impl Display for Move { TypeCode::FLOAT => write!(f, "R_FLOAT_{destination} -> {to}"), TypeCode::INTEGER => write!(f, "R_INT_{destination} -> {to}"), TypeCode::STRING => write!(f, "R_STR_{destination} -> {to}"), + TypeCode::LIST => write!(f, "R_LIST_{destination} -> {to}"), + TypeCode::FUNCTION => write!(f, "R_FN_{destination} -> {to}"), unsupported => write!( f, "Unsupported type code: {unsupported} for MOVE instruction" diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index 07dfa5b..ba5548a 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -44,7 +44,7 @@ pub use crate::compiler::{compile, CompileError, Compiler}; pub use crate::dust_error::{AnnotatedError, DustError}; pub use crate::instruction::{Instruction, Operand, Operation}; pub use crate::lexer::{lex, LexError, Lexer}; -pub use crate::native_function::{NativeFunction, NativeFunctionError}; +pub use crate::native_function::NativeFunction; pub use crate::r#type::{EnumType, FunctionType, StructType, Type, TypeConflict}; pub use crate::token::{Token, TokenKind, TokenOwned}; pub use crate::value::{ diff --git a/dust-lang/src/native_function/assert.rs b/dust-lang/src/native_function/assert.rs deleted file mode 100644 index b4b6e70..0000000 --- a/dust-lang/src/native_function/assert.rs +++ /dev/null @@ -1,22 +0,0 @@ -use std::{ops::Range, panic}; - -use crate::vm::Thread; - -pub fn panic(data: &mut Thread, _: usize, argument_range: Range) { - let current_frame = data.current_frame(); - let position = data.current_position(); - let mut message = format!("Dust panic at {position}!"); - - for register_index in argument_range { - let string = current_frame - .registers - .strings - .get(register_index) - .as_value(); - - message.push_str(string); - message.push('\n'); - } - - panic!("{}", message) -} diff --git a/dust-lang/src/native_function/io.rs b/dust-lang/src/native_function/io.rs deleted file mode 100644 index 7ec44e9..0000000 --- a/dust-lang/src/native_function/io.rs +++ /dev/null @@ -1,56 +0,0 @@ -use std::io::{stdin, stdout, Write}; -use std::ops::Range; - -use crate::vm::Thread; -use crate::DustString; - -pub fn read_line(data: &mut Thread, destination: usize, _argument_range: Range) { - let current_frame = data.current_frame_mut(); - let mut buffer = String::new(); - - if stdin().read_line(&mut buffer).is_ok() { - let length = buffer.len(); - - buffer.truncate(length.saturating_sub(1)); - - let string = DustString::from(buffer); - - current_frame - .registers - .strings - .set_to_new_register(destination, string); - } -} - -pub fn write(data: &mut Thread, _: usize, argument_range: Range) { - let current_frame = data.current_frame_mut(); - let mut stdout = stdout(); - - for register_index in argument_range { - let string = current_frame - .registers - .strings - .get(register_index) - .as_value(); - let _ = stdout.write(string.as_bytes()); - } - - let _ = stdout.flush(); -} - -pub fn write_line(data: &mut Thread, _: usize, argument_range: Range) { - let current_frame = data.current_frame_mut(); - let mut stdout = stdout().lock(); - - for register_index in argument_range { - let string = current_frame - .registers - .strings - .get(register_index) - .as_value(); - let _ = stdout.write(string.as_bytes()); - } - - let _ = stdout.write(b"\n"); - let _ = stdout.flush(); -} diff --git a/dust-lang/src/native_function/mod.rs b/dust-lang/src/native_function/mod.rs index 3c429b8..fca05fc 100644 --- a/dust-lang/src/native_function/mod.rs +++ b/dust-lang/src/native_function/mod.rs @@ -2,21 +2,15 @@ //! //! Native functions are used to implement features that are not possible to implement in Dust //! itself or that are more efficient to implement in Rust. -mod assert; -mod io; -mod random; -mod thread; use std::{ fmt::{self, Display, Formatter}, - io::ErrorKind as IoErrorKind, ops::Range, - string::ParseError, }; use serde::{Deserialize, Serialize}; -use crate::{AnnotatedError, FunctionType, Span, Type, vm::Thread}; +use crate::{vm::Thread, FunctionType, Type}; macro_rules! define_native_function { ($(($name:ident, $bytes:literal, $str:expr, $type:expr, $function:expr)),*) => { @@ -86,11 +80,7 @@ macro_rules! define_native_function { $bytes => NativeFunction::$name, )* _ => { - if cfg!(test) { - panic!("Invalid native function byte: {}", bytes) - } else { - NativeFunction::Panic - } + panic!("Invalid native function byte: {}", bytes); } } } @@ -129,13 +119,13 @@ define_native_function! { // ), // (AssertEqual, 1_u8, "assert_equal", false), // (AssertNotEqual, 2_u8, "assert_not_equal", false), - ( - Panic, - 3, - "panic", - FunctionType::new([], [], Type::None), - assert::panic - ), + // ( + // Panic, + // 3, + // "panic", + // FunctionType::new([], [], Type::None), + // assert::panic + // ), // // Type conversion // (Parse, 4_u8, "parse", true), @@ -199,42 +189,42 @@ define_native_function! { // // Read // (Read, 48_u8, "read", true), // (ReadFile, 49_u8, "read_file", true), - ( - ReadLine, - 50, - "read_line", - FunctionType::new([], [], Type::String), - io::read_line - ), + // ( + // ReadLine, + // 50, + // "read_line", + // FunctionType::new([], [], Type::String), + // io::read_line + // ), // (ReadTo, 51_u8, "read_to", false), // (ReadUntil, 52_u8, "read_until", true), // // Write // (AppendFile, 53_u8, "append_file", false), // (PrependFile, 54_u8, "prepend_file", false), - ( - Write, - 55, - "write", - FunctionType::new([], [Type::String], Type::None), - io::write - ), + // ( + // Write, + // 55, + // "write", + // FunctionType::new([], [Type::String], Type::None), + // io::write + // ), // (WriteFile, 56_u8, "write_file", false), - ( - WriteLine, - 57, - "write_line", - FunctionType::new([], [Type::String], Type::None), - io::write_line - ), + // ( + // WriteLine, + // 57, + // "write_line", + // FunctionType::new([], [Type::String], Type::None), + // io::write_line + // ), // // Random - ( - RandomInteger, - 58, - "random_int", - FunctionType::new([], [Type::Integer, Type::Integer], Type::Integer), - random::random_int - ), + // ( + // RandomInteger, + // 58, + // "random_int", + // FunctionType::new([], [Type::Integer, Type::Integer], Type::Integer), + // random::random_int + // ), // Thread ( @@ -242,70 +232,8 @@ define_native_function! { 60, "spawn", FunctionType::new([], [ Type::function([], [], Type::None)], Type::None), - thread::spawn + spawn ) } -#[derive(Debug, Clone, PartialEq)] -pub enum NativeFunctionError { - ExpectedArgumentCount { - expected: usize, - found: usize, - position: Span, - }, - Panic { - message: String, - position: Span, - }, - Parse { - error: ParseError, - position: Span, - }, - Io { - error: IoErrorKind, - position: Span, - }, -} - -impl AnnotatedError for NativeFunctionError { - fn title() -> &'static str { - "Native Function Error" - } - - fn description(&self) -> &'static str { - match self { - NativeFunctionError::ExpectedArgumentCount { .. } => { - "Expected a different number of arguments" - } - NativeFunctionError::Panic { .. } => "Explicit panic", - NativeFunctionError::Parse { .. } => "Failed to parse value", - NativeFunctionError::Io { .. } => "I/O error", - } - } - - fn detail_snippets(&self) -> Vec<(String, Span)> { - match self { - NativeFunctionError::ExpectedArgumentCount { - expected, - found, - position, - } => vec![( - format!("Expected {expected} arguments, found {found}"), - *position, - )], - NativeFunctionError::Panic { message, position } => { - vec![(format!("Dust panic!\n{message}"), *position)] - } - NativeFunctionError::Parse { error, position } => { - vec![(format!("{error}"), *position)] - } - NativeFunctionError::Io { error, position } => { - vec![(format!("{error}"), *position)] - } - } - } - - fn help_snippets(&self) -> Vec<(String, Span)> { - Vec::with_capacity(0) - } -} +fn spawn(_: &mut Thread, _: usize, _: Range) {} diff --git a/dust-lang/src/native_function/random.rs b/dust-lang/src/native_function/random.rs deleted file mode 100644 index 2a44b45..0000000 --- a/dust-lang/src/native_function/random.rs +++ /dev/null @@ -1,37 +0,0 @@ -use std::ops::Range; - -use rand::Rng; - -use crate::vm::Thread; - -pub fn random_int(data: &mut Thread, destination: usize, argument_range: Range) { - let current_frame = data.current_frame_mut(); - let mut argument_range_iter = argument_range.into_iter(); - let (min, max) = { - let mut min = None; - - loop { - let register_index = argument_range_iter - .next() - .unwrap_or_else(|| panic!("No argument was passed to \"random_int\"")); - let integer = current_frame - .registers - .integers - .get(register_index) - .copy_value(); - - if let Some(min) = min { - break (min, integer); - } else { - min = Some(integer); - } - } - }; - - let random_integer = rand::thread_rng().gen_range(min..max); - - current_frame - .registers - .integers - .set_to_new_register(destination, random_integer); -} diff --git a/dust-lang/src/native_function/thread.rs b/dust-lang/src/native_function/thread.rs deleted file mode 100644 index 832fa5e..0000000 --- a/dust-lang/src/native_function/thread.rs +++ /dev/null @@ -1,11 +0,0 @@ -use std::{ops::Range, thread::JoinHandle}; - -use crate::vm::Thread; - -fn start_thread(_thread: &mut Thread, _argument_range: Range) -> JoinHandle<()> { - todo!(); -} - -pub fn spawn(data: &mut Thread, _: usize, argument_range: Range) { - let _ = start_thread(data, argument_range); -} diff --git a/dust-lang/src/type.rs b/dust-lang/src/type.rs index 67b1eea..113b54b 100644 --- a/dust-lang/src/type.rs +++ b/dust-lang/src/type.rs @@ -313,7 +313,7 @@ impl Default for FunctionType { impl Display for FunctionType { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "fn ")?; + write!(f, "fn")?; if !self.type_parameters.is_empty() { write!(f, "<")?; diff --git a/dust-lang/src/value/abstract_list.rs b/dust-lang/src/value/abstract_list.rs index 8e2c085..22bf05c 100644 --- a/dust-lang/src/value/abstract_list.rs +++ b/dust-lang/src/value/abstract_list.rs @@ -1,4 +1,7 @@ -use std::fmt::{self, Display, Formatter}; +use std::{ + fmt::{self, Display, Formatter}, + sync::Arc, +}; use crate::{ instruction::TypeCode, @@ -15,7 +18,6 @@ pub struct AbstractList { impl AbstractList { pub fn display(&self, thread: &Thread) -> DustString { - let current_frame = thread.current_frame(); let mut display = DustString::new(); display.push('['); @@ -25,15 +27,110 @@ impl AbstractList { display.push_str(", "); } - let item_display = match self.item_type { - TypeCode::BOOLEAN => current_frame.get_boolean_from_pointer(pointer).to_string(), - TypeCode::BYTE => current_frame.get_byte_from_pointer(pointer).to_string(), - TypeCode::CHARACTER => current_frame - .get_character_from_pointer(pointer) - .to_string(), - TypeCode::FLOAT => current_frame.get_float_from_pointer(pointer).to_string(), - TypeCode::INTEGER => current_frame.get_integer_from_pointer(pointer).to_string(), - TypeCode::STRING => current_frame.get_string_from_pointer(pointer).to_string(), + let item_display = match (pointer, self.item_type) { + (Pointer::Register(register_index), TypeCode::BOOLEAN) => { + let boolean = thread + .current_registers() + .booleans + .get(register_index as usize) + .as_value(); + + format!("{}", boolean) + } + (Pointer::Register(register_index), TypeCode::BYTE) => { + let byte = thread + .current_registers() + .bytes + .get(register_index as usize) + .as_value(); + + format!("{}", byte) + } + (Pointer::Constant(constant_index), TypeCode::CHARACTER) => { + let character = thread + .current_frame() + .chunk + .character_constants + .get(constant_index as usize) + .unwrap(); + + format!("{}", character) + } + (Pointer::Register(register_index), TypeCode::CHARACTER) => { + let character = thread + .current_registers() + .characters + .get(register_index as usize) + .as_value(); + + format!("{}", character) + } + (Pointer::Constant(constant_index), TypeCode::FLOAT) => { + let float = thread + .current_frame() + .chunk + .float_constants + .get(constant_index as usize) + .unwrap(); + + format!("{}", float) + } + (Pointer::Register(register_index), TypeCode::FLOAT) => { + let float = thread + .current_registers() + .floats + .get(register_index as usize) + .as_value(); + + format!("{}", float) + } + (Pointer::Constant(constant_index), TypeCode::INTEGER) => { + let integer = thread + .current_frame() + .chunk + .integer_constants + .get(constant_index as usize) + .unwrap(); + + format!("{}", integer) + } + (Pointer::Register(register_index), TypeCode::INTEGER) => { + let integer = thread + .current_registers() + .integers + .get(register_index as usize) + .as_value(); + + format!("{}", integer) + } + (Pointer::Constant(constant_index), TypeCode::STRING) => { + let string = thread + .current_frame() + .chunk + .string_constants + .get(constant_index as usize) + .unwrap(); + + format!("{}", string) + } + (Pointer::Register(register_index), TypeCode::STRING) => { + let string = thread + .current_registers() + .strings + .get(register_index as usize) + .as_value(); + + format!("{}", string) + } + (Pointer::Register(register_index), TypeCode::LIST) => { + let list = thread + .current_registers() + .lists + .get(register_index as usize) + .as_value(); + + format!("{}", list) + } _ => todo!(), }; @@ -51,45 +148,130 @@ impl AbstractList { match self.item_type { TypeCode::BOOLEAN => { for pointer in &self.item_pointers { - let boolean = thread.current_frame().get_boolean_from_pointer(*pointer); + let boolean = *thread + .current_registers() + .booleans + .get(pointer.index() as usize) + .as_value(); concrete_list.push(ConcreteValue::Boolean(boolean)); } } TypeCode::BYTE => { for pointer in &self.item_pointers { - let byte = thread.current_frame().get_byte_from_pointer(*pointer); + let byte = *thread + .current_registers() + .bytes + .get(pointer.index() as usize) + .as_value(); concrete_list.push(ConcreteValue::Byte(byte)); } } TypeCode::CHARACTER => { for pointer in &self.item_pointers { - let character = thread.current_frame().get_character_from_pointer(*pointer); + let character = match pointer { + Pointer::Register(register_index) => { + let character = *thread + .current_registers() + .characters + .get(*register_index as usize) + .as_value(); + + character + } + Pointer::Constant(constant_index) => { + let character = thread + .current_frame() + .chunk + .character_constants + .get(*constant_index as usize) + .unwrap(); + + *character + } + }; concrete_list.push(ConcreteValue::Character(character)); } } TypeCode::FLOAT => { for pointer in &self.item_pointers { - let float = thread.current_frame().get_float_from_pointer(*pointer); + let float = match pointer { + Pointer::Register(register_index) => { + let float = *thread + .current_registers() + .floats + .get(*register_index as usize) + .as_value(); + + float + } + Pointer::Constant(constant_index) => { + let float = thread + .current_frame() + .chunk + .float_constants + .get(*constant_index as usize) + .unwrap(); + + *float + } + }; concrete_list.push(ConcreteValue::Float(float)); } } TypeCode::INTEGER => { for pointer in &self.item_pointers { - let integer = thread.current_frame().get_integer_from_pointer(*pointer); + let integer = match pointer { + Pointer::Register(register_index) => { + let integer = *thread + .current_registers() + .integers + .get(*register_index as usize) + .as_value(); + + integer + } + Pointer::Constant(constant_index) => { + let integer = thread + .current_frame() + .chunk + .integer_constants + .get(*constant_index as usize) + .unwrap(); + + *integer + } + }; concrete_list.push(ConcreteValue::Integer(integer)); } } TypeCode::STRING => { for pointer in &self.item_pointers { - let string = thread - .current_frame() - .get_string_from_pointer(*pointer) - .clone(); + let string = match pointer { + Pointer::Register(register_index) => { + let string = thread + .current_registers() + .strings + .get(*register_index as usize) + .as_value(); + + string.clone() + } + Pointer::Constant(constant_index) => { + let string = thread + .current_frame() + .chunk + .string_constants + .get(*constant_index as usize) + .unwrap(); + + string.clone() + } + }; concrete_list.push(ConcreteValue::String(string)); } @@ -97,13 +279,33 @@ impl AbstractList { TypeCode::LIST => { for pointer in &self.item_pointers { let list = thread - .current_frame() - .get_list_from_pointer(pointer) + .current_registers() + .lists + .get(pointer.index() as usize) + .as_value() .to_concrete(thread); concrete_list.push(list); } } + TypeCode::FUNCTION => { + for pointer in &self.item_pointers { + let prototype_index = thread + .current_registers() + .functions + .get(pointer.index() as usize) + .as_value() + .prototype_index as usize; + let chunk = thread + .current_frame() + .chunk + .prototypes + .get(prototype_index) + .unwrap(); + + concrete_list.push(ConcreteValue::Function(Arc::clone(chunk))); + } + } _ => todo!(), } diff --git a/dust-lang/src/value/concrete_value.rs b/dust-lang/src/value/concrete_value.rs index 794ff11..84a8ca5 100644 --- a/dust-lang/src/value/concrete_value.rs +++ b/dust-lang/src/value/concrete_value.rs @@ -1,10 +1,13 @@ -use std::fmt::{self, Display, Formatter}; +use std::{ + fmt::{self, Display, Formatter}, + sync::Arc, +}; use serde::{Deserialize, Serialize}; use smartstring::{LazyCompact, SmartString}; use tracing::trace; -use crate::{Type, Value}; +use crate::{Chunk, Type, Value}; use super::RangeValue; @@ -17,6 +20,7 @@ pub enum ConcreteValue { Byte(u8), Character(char), Float(f64), + Function(Arc), Integer(i64), List(Vec), Range(RangeValue), @@ -114,6 +118,7 @@ impl ConcreteValue { ConcreteValue::List(items) => items.first().map_or(Type::Any, |item| item.r#type()), ConcreteValue::Range(range) => range.r#type(), ConcreteValue::String(_) => Type::String, + ConcreteValue::Function(chunk) => Type::Function(chunk.r#type.clone()), } } } @@ -131,6 +136,7 @@ impl Clone for ConcreteValue { ConcreteValue::List(items) => ConcreteValue::List(items.clone()), ConcreteValue::Range(range) => ConcreteValue::Range(*range), ConcreteValue::String(string) => ConcreteValue::String(string.clone()), + ConcreteValue::Function(chunk) => ConcreteValue::Function(chunk.clone()), } } } @@ -168,6 +174,7 @@ impl Display for ConcreteValue { write!(f, "{range_value}") } ConcreteValue::String(string) => write!(f, "{string}"), + ConcreteValue::Function(chunk) => write!(f, "{}", chunk.r#type), } } } diff --git a/dust-lang/src/value/function.rs b/dust-lang/src/value/function.rs index a8d6345..bbc664b 100644 --- a/dust-lang/src/value/function.rs +++ b/dust-lang/src/value/function.rs @@ -16,8 +16,9 @@ impl Display for Function { let mut type_string = self.r#type.to_string(); if let Some(name) = &self.name { - debug_assert!(type_string.starts_with("fn ")); + debug_assert!(type_string.starts_with("fn")); + type_string.insert(2, ' '); type_string.insert_str(3, name); } diff --git a/dust-lang/src/vm/action/add.rs b/dust-lang/src/vm/action/add.rs deleted file mode 100644 index e3fcc71..0000000 --- a/dust-lang/src/vm/action/add.rs +++ /dev/null @@ -1,287 +0,0 @@ -use std::ops::Add; - -use tracing::trace; - -use crate::{ - vm::{call_frame::RuntimeValue, Thread}, - DustString, Instruction, -}; - -use super::Cache; - -pub fn add_bytes(_: &mut usize, instruction: &Instruction, thread: &mut Thread, _: &mut Cache) { - let destination_index = instruction.a_field() as usize; - let left_index = instruction.b_field() as usize; - let right_index = instruction.c_field() as usize; - - let current_frame = thread.current_frame_mut(); - let left_value = current_frame.get_byte_from_register(left_index).clone(); - let right_value = current_frame.get_byte_from_register(right_index).clone(); - let sum = left_value.add(&right_value); - - current_frame - .registers - .bytes - .get_mut(destination_index) - .as_value_mut() - .set_inner(sum); -} - -pub fn add_characters( - _: &mut usize, - instruction: &Instruction, - thread: &mut Thread, - _: &mut Cache, -) { - let destination_index = instruction.a_field() as usize; - let left_index = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - - let current_frame = thread.current_frame_mut(); - let left_value = if left_is_constant { - current_frame.get_character_constant(left_index) - } else { - current_frame.get_character_from_register(left_index) - }; - let right_value = if right_is_constant { - current_frame.get_character_constant(right) - } else { - current_frame.get_character_from_register(right) - }; - let concatenated = { - let mut concatenated = DustString::from(String::with_capacity(2)); - - concatenated.push(left_value.clone_inner()); - concatenated.push(right_value.clone_inner()); - - RuntimeValue::Raw(concatenated) - }; - - current_frame - .registers - .strings - .get_mut(destination_index) - .set(concatenated); -} - -pub fn add_floats(_: &mut usize, instruction: &Instruction, thread: &mut Thread, _: &mut Cache) { - let destination = instruction.a_field() as usize; - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - - let current_frame = thread.current_frame_mut(); - let left_value = if left_is_constant { - current_frame.get_float_constant(left) - } else { - current_frame.get_float_from_register(left) - } - .clone(); - let right_value = if right_is_constant { - current_frame.get_float_constant(right) - } else { - current_frame.get_float_from_register(right) - } - .clone(); - let sum = left_value.add(&right_value); - - current_frame - .registers - .floats - .get_mut(destination) - .as_value_mut() - .set_inner(sum); -} - -pub fn add_integers(_: &mut usize, instruction: &Instruction, thread: &mut Thread, _: &mut Cache) { - let destination = instruction.a_field() as usize; - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - - let current_frame = thread.current_frame_mut(); - let left_value = if left_is_constant { - current_frame.get_integer_constant(left) - } else { - current_frame.get_integer_from_register(left) - } - .clone(); - let right_value = if right_is_constant { - current_frame.get_integer_constant(right) - } else { - current_frame.get_integer_from_register(right) - } - .clone(); - let sum = left_value.add(&right_value); - - current_frame - .registers - .integers - .get_mut(destination) - .as_value_mut() - .set_inner(sum); -} - -pub fn add_strings(_: &mut usize, instruction: &Instruction, thread: &mut Thread, _: &mut Cache) { - let destination = instruction.a_field() as usize; - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - - let current_frame = thread.current_frame_mut(); - let left_value = if left_is_constant { - current_frame.get_string_constant(left) - } else { - current_frame.get_string_from_register(left) - }; - let right_value = if right_is_constant { - current_frame.get_string_constant(right) - } else { - current_frame.get_string_from_register(right) - }; - let concatenated = DustString::from(format!("{left_value}{right_value}")); - - current_frame - .registers - .strings - .get_mut(destination) - .as_value_mut() - .set_inner(concatenated); -} - -pub fn add_character_string( - _: &mut usize, - instruction: &Instruction, - thread: &mut Thread, - _: &mut Cache, -) { - let destination = instruction.a_field() as usize; - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - - let current_frame = thread.current_frame_mut(); - let left_value = if left_is_constant { - current_frame.get_character_constant(left) - } else { - current_frame.get_character_from_register(left) - }; - let right_value = if right_is_constant { - current_frame.get_string_constant(right) - } else { - current_frame.get_string_from_register(right) - }; - let concatenated = DustString::from(format!("{left_value}{right_value}")); - - current_frame - .registers - .strings - .get_mut(destination) - .as_value_mut() - .set_inner(concatenated); -} - -pub fn add_string_character( - _: &mut usize, - instruction: &Instruction, - thread: &mut Thread, - _: &mut Cache, -) { - let destination = instruction.a_field() as usize; - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - - let current_frame = thread.current_frame_mut(); - let left_value = if left_is_constant { - current_frame.get_string_constant(left) - } else { - current_frame.get_string_from_register(left) - }; - let right_value = if right_is_constant { - current_frame.get_character_constant(right) - } else { - current_frame.get_character_from_register(right) - }; - let concatenated = DustString::from(format!("{left_value}{right_value}")); - - current_frame - .registers - .strings - .get_mut(destination) - .as_value_mut() - .set_inner(concatenated); -} - -pub fn optimized_add_integer( - _: &mut usize, - instruction: &Instruction, - thread: &mut Thread, - cache: &mut Cache, -) { - if let Cache::IntegerMath([destination, left, right]) = cache { - trace!("OPTIMIZED_ADD using integer cache"); - - let sum = left.add(right); - - *destination.borrow_mut() = sum; - } else { - let destination_index = instruction.a_field() as usize; - let left_index = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right_index = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let current_frame = thread.current_frame_mut(); - let left_value = if left_is_constant { - let value = current_frame.get_integer_constant_mut(left_index).to_rc(); - - current_frame.constants.integers[left_index] = value.clone(); - - value - } else { - let value = current_frame - .get_integer_from_register_mut(left_index) - .to_ref_cell(); - - current_frame.registers.integers[left_index].set(value.clone()); - - value - }; - let right_value = if right_is_constant { - let value = current_frame.get_integer_constant_mut(right_index).to_rc(); - - current_frame.constants.integers[right_index] = value.clone(); - - value - } else { - let value = current_frame - .get_integer_from_register_mut(right_index) - .to_ref_cell(); - - current_frame.registers.integers[right_index].set(value.clone()); - - value - }; - let sum = left_value.add(&right_value); - let destination = { - let mut value = current_frame - .get_integer_from_register_mut(destination_index) - .to_ref_cell(); - - value.set_inner(sum); - - current_frame.registers.integers[destination_index].set(value.clone()); - - value - }; - - *cache = Cache::IntegerMath([destination, left_value, right_value]); - } -} diff --git a/dust-lang/src/vm/action/equal.rs b/dust-lang/src/vm/action/equal.rs deleted file mode 100644 index ed335cb..0000000 --- a/dust-lang/src/vm/action/equal.rs +++ /dev/null @@ -1,217 +0,0 @@ -use tracing::trace; - -use crate::{vm::Thread, Instruction}; - -use super::Cache; - -pub fn equal_booleans( - ip: &mut usize, - instruction: &Instruction, - thread: &mut Thread, - _: &mut Cache, -) { - let left_index = instruction.b_field() as usize; - let right_index = instruction.c_field() as usize; - let comparator = instruction.d_field(); - - let current_frame = thread.current_frame_mut(); - let left_value = current_frame.get_boolean_from_register(left_index); - let right_value = current_frame.get_boolean_from_register(right_index); - let is_equal = left_value == right_value; - - if is_equal == comparator { - *ip += 1; - } -} - -pub fn equal_bytes(ip: &mut usize, instruction: &Instruction, thread: &mut Thread, _: &mut Cache) { - let left = instruction.b_field() as usize; - let right = instruction.c_field() as usize; - let comparator = instruction.d_field(); - - let current_frame = thread.current_frame_mut(); - let left_value = current_frame.get_byte_from_register(left); - let right_value = current_frame.get_byte_from_register(right); - let is_equal = left_value == right_value; - - if is_equal == comparator { - *ip += 1; - } -} - -pub fn equal_characters( - ip: &mut usize, - instruction: &Instruction, - thread: &mut Thread, - _: &mut Cache, -) { - let left_index = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right_index = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let current_frame = thread.current_frame_mut(); - let left_value = if left_is_constant { - current_frame.get_character_constant(left_index) - } else { - current_frame.get_character_from_register(left_index) - }; - let right_value = if right_is_constant { - current_frame.get_character_constant(right_index) - } else { - current_frame.get_character_from_register(right_index) - }; - let is_equal = left_value == right_value; - - if is_equal == comparator { - *ip += 1; - } -} - -pub fn equal_floats(ip: &mut usize, instruction: &Instruction, thread: &mut Thread, _: &mut Cache) { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let current_frame = thread.current_frame_mut(); - let left_value = if left_is_constant { - current_frame.get_float_constant(left) - } else { - current_frame.get_float_from_register(left) - }; - let right_value = if right_is_constant { - current_frame.get_float_constant(right) - } else { - current_frame.get_float_from_register(right) - }; - let is_equal = left_value == right_value; - - if is_equal == comparator { - *ip += 1; - } -} - -pub fn equal_integers( - ip: &mut usize, - instruction: &Instruction, - thread: &mut Thread, - _: &mut Cache, -) { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let current_frame = thread.current_frame_mut(); - let left_value = if left_is_constant { - current_frame.get_integer_constant(left) - } else { - current_frame.get_integer_from_register(left) - }; - let right_value = if right_is_constant { - current_frame.get_integer_constant(right) - } else { - current_frame.get_integer_from_register(right) - }; - let is_equal = left_value == right_value; - - if is_equal == comparator { - *ip += 1; - } -} - -pub fn equal_strings( - ip: &mut usize, - instruction: &Instruction, - thread: &mut Thread, - _: &mut Cache, -) { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let current_frame = thread.current_frame_mut(); - let left_value = if left_is_constant { - current_frame.get_string_constant(left) - } else { - current_frame.get_string_from_register(left) - }; - let right_value = if right_is_constant { - current_frame.get_string_constant(right) - } else { - current_frame.get_string_from_register(right) - }; - let is_equal = left_value == right_value; - - if is_equal == comparator { - *ip += 1; - } -} - -pub fn optimized_equal_integers( - ip: &mut usize, - instruction: &Instruction, - thread: &mut Thread, - cache: &mut Cache, -) { - if let Cache::IntegerComparison([left, right]) = cache { - trace!("equal_INTEGERS_OPTIMIZED using cache"); - - let is_equal = left == right; - - if is_equal { - *ip += 1; - } - } else { - let left_index = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right_index = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let current_frame = thread.current_frame_mut(); - let left_value = if left_is_constant { - let value = current_frame.get_integer_constant_mut(left_index).to_rc(); - - current_frame.constants.integers[left_index] = value.clone(); - - value - } else { - let value = current_frame - .get_integer_from_register_mut(left_index) - .to_ref_cell(); - - current_frame.registers.integers[left_index].set(value.clone()); - - value - }; - let right_value = if right_is_constant { - let value = current_frame.get_integer_constant_mut(right_index).to_rc(); - - current_frame.constants.integers[right_index] = value.clone(); - - value - } else { - let value = current_frame - .get_integer_from_register_mut(right_index) - .to_ref_cell(); - - current_frame.registers.integers[right_index].set(value.clone()); - - value - }; - let is_equal = left_value == right_value; - - if is_equal == comparator { - *ip += 1; - } - - *cache = Cache::IntegerComparison([left_value, right_value]); - } -} diff --git a/dust-lang/src/vm/action/jump.rs b/dust-lang/src/vm/action/jump.rs deleted file mode 100644 index 210bd04..0000000 --- a/dust-lang/src/vm/action/jump.rs +++ /dev/null @@ -1,48 +0,0 @@ -use tracing::trace; - -use crate::{vm::Thread, Instruction}; - -use super::Cache; - -pub fn jump(ip: &mut usize, instruction: &Instruction, _: &mut Thread, _: &mut Cache) { - let offset = instruction.b_field() as usize; - let is_positive = instruction.c_field() != 0; - - if is_positive { - trace!("JUMP +{}", offset); - } else { - trace!("JUMP -{}", offset); - } - - if is_positive { - *ip += offset; - } else { - *ip -= offset + 1; - } -} - -pub fn optimized_jump_forward( - ip: &mut usize, - instruction: &Instruction, - _: &mut Thread, - _: &mut Cache, -) { - let offset = instruction.b_field() as usize; - - trace!("JUMP +{}", offset); - - *ip += offset; -} - -pub fn optimized_jump_backward( - ip: &mut usize, - instruction: &Instruction, - _: &mut Thread, - _: &mut Cache, -) { - let offset = instruction.b_field() as usize; - - trace!("JUMP -{}", offset); - - *ip -= offset + 1; -} diff --git a/dust-lang/src/vm/action/less.rs b/dust-lang/src/vm/action/less.rs deleted file mode 100644 index edbfc2d..0000000 --- a/dust-lang/src/vm/action/less.rs +++ /dev/null @@ -1,212 +0,0 @@ -use tracing::trace; - -use crate::{vm::Thread, Instruction}; - -use super::Cache; - -pub fn less_booleans( - ip: &mut usize, - instruction: &Instruction, - thread: &mut Thread, - _: &mut Cache, -) { - let left_index = instruction.b_field() as usize; - let right_index = instruction.c_field() as usize; - let comparator = instruction.d_field(); - - let current_frame = thread.current_frame_mut(); - let left_value = current_frame.get_boolean_from_register(left_index); - let right_value = current_frame.get_boolean_from_register(right_index); - let is_less_than = left_value < right_value; - - if is_less_than == comparator { - *ip += 1; - } -} - -pub fn less_bytes(ip: &mut usize, instruction: &Instruction, thread: &mut Thread, _: &mut Cache) { - let left = instruction.b_field() as usize; - let right = instruction.c_field() as usize; - let comparator = instruction.d_field(); - - let current_frame = thread.current_frame_mut(); - let left_value = current_frame.get_byte_from_register(left); - let right_value = current_frame.get_byte_from_register(right); - let is_less_than = left_value < right_value; - - if is_less_than == comparator { - *ip += 1; - } -} - -pub fn less_characters( - ip: &mut usize, - instruction: &Instruction, - thread: &mut Thread, - _: &mut Cache, -) { - let left_index = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right_index = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let current_frame = thread.current_frame_mut(); - let left_value = if left_is_constant { - current_frame.get_character_constant(left_index) - } else { - current_frame.get_character_from_register(left_index) - }; - let right_value = if right_is_constant { - current_frame.get_character_constant(right_index) - } else { - current_frame.get_character_from_register(right_index) - }; - let is_less_than = left_value < right_value; - - if is_less_than == comparator { - *ip += 1; - } -} - -pub fn less_floats(ip: &mut usize, instruction: &Instruction, thread: &mut Thread, _: &mut Cache) { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let current_frame = thread.current_frame_mut(); - let left_value = if left_is_constant { - current_frame.get_float_constant(left) - } else { - current_frame.get_float_from_register(left) - }; - let right_value = if right_is_constant { - current_frame.get_float_constant(right) - } else { - current_frame.get_float_from_register(right) - }; - let is_less_than = left_value < right_value; - - if is_less_than == comparator { - *ip += 1; - } -} - -pub fn less_integers( - ip: &mut usize, - instruction: &Instruction, - thread: &mut Thread, - _: &mut Cache, -) { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let current_frame = thread.current_frame_mut(); - let left_value = if left_is_constant { - current_frame.get_integer_constant(left) - } else { - current_frame.get_integer_from_register(left) - }; - let right_value = if right_is_constant { - current_frame.get_integer_constant(right) - } else { - current_frame.get_integer_from_register(right) - }; - let is_less_than = left_value < right_value; - - if is_less_than == comparator { - *ip += 1; - } -} - -pub fn less_strings(ip: &mut usize, instruction: &Instruction, thread: &mut Thread, _: &mut Cache) { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let current_frame = thread.current_frame_mut(); - let left_value = if left_is_constant { - current_frame.get_string_constant(left) - } else { - current_frame.get_string_from_register(left) - }; - let right_value = if right_is_constant { - current_frame.get_string_constant(right) - } else { - current_frame.get_string_from_register(right) - }; - let is_less_than = left_value < right_value; - - if is_less_than == comparator { - *ip += 1; - } -} - -pub fn optimized_less_integers( - ip: &mut usize, - instruction: &Instruction, - thread: &mut Thread, - cache: &mut Cache, -) { - if let Cache::IntegerComparison([left, right]) = cache { - trace!("OPTIMIZED_LESS using integer cache"); - - let is_less_than = left < right; - - if is_less_than { - *ip += 1; - } - } else { - let left_index = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right_index = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let current_frame = thread.current_frame_mut(); - let left_value = if left_is_constant { - let value = current_frame.get_integer_constant_mut(left_index).to_rc(); - - current_frame.constants.integers[left_index] = value.clone(); - - value - } else { - let value = current_frame - .get_integer_from_register_mut(left_index) - .to_ref_cell(); - - current_frame.registers.integers[left_index].set(value.clone()); - - value - }; - let right_value = if right_is_constant { - let value = current_frame.get_integer_constant_mut(right_index).to_rc(); - - current_frame.constants.integers[right_index] = value.clone(); - - value - } else { - let value = current_frame - .get_integer_from_register_mut(right_index) - .to_ref_cell(); - - current_frame.registers.integers[right_index].set(value.clone()); - - value - }; - let is_less_than = left_value < right_value; - - if is_less_than == comparator { - *ip += 1; - } - - *cache = Cache::IntegerComparison([left_value, right_value]); - } -} diff --git a/dust-lang/src/vm/action/less_equal.rs b/dust-lang/src/vm/action/less_equal.rs deleted file mode 100644 index 56a31d3..0000000 --- a/dust-lang/src/vm/action/less_equal.rs +++ /dev/null @@ -1,227 +0,0 @@ -use tracing::trace; - -use crate::{vm::Thread, Instruction}; - -use super::Cache; - -pub fn less_equal_booleans( - ip: &mut usize, - instruction: &Instruction, - thread: &mut Thread, - _: &mut Cache, -) { - let left_index = instruction.b_field() as usize; - let right_index = instruction.c_field() as usize; - let comparator = instruction.d_field(); - - let current_frame = thread.current_frame_mut(); - let left_value = current_frame.get_boolean_from_register(left_index); - let right_value = current_frame.get_boolean_from_register(right_index); - let is_less_than_or_equal = left_value <= right_value; - - if is_less_than_or_equal == comparator { - *ip += 1; - } -} - -pub fn less_equal_bytes( - ip: &mut usize, - instruction: &Instruction, - thread: &mut Thread, - _: &mut Cache, -) { - let left = instruction.b_field() as usize; - let right = instruction.c_field() as usize; - let comparator = instruction.d_field(); - - let current_frame = thread.current_frame_mut(); - let left_value = current_frame.get_byte_from_register(left); - let right_value = current_frame.get_byte_from_register(right); - let is_less_than_or_equal = left_value <= right_value; - - if is_less_than_or_equal == comparator { - *ip += 1; - } -} - -pub fn less_equal_characters( - ip: &mut usize, - instruction: &Instruction, - thread: &mut Thread, - _: &mut Cache, -) { - let left_index = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right_index = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let current_frame = thread.current_frame_mut(); - let left_value = if left_is_constant { - current_frame.get_character_constant(left_index) - } else { - current_frame.get_character_from_register(left_index) - }; - let right_value = if right_is_constant { - current_frame.get_character_constant(right_index) - } else { - current_frame.get_character_from_register(right_index) - }; - let is_less_than_or_equal = left_value <= right_value; - - if is_less_than_or_equal == comparator { - *ip += 1; - } -} - -pub fn less_equal_floats( - ip: &mut usize, - instruction: &Instruction, - thread: &mut Thread, - _: &mut Cache, -) { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let current_frame = thread.current_frame_mut(); - let left_value = if left_is_constant { - current_frame.get_float_constant(left) - } else { - current_frame.get_float_from_register(left) - }; - let right_value = if right_is_constant { - current_frame.get_float_constant(right) - } else { - current_frame.get_float_from_register(right) - }; - let is_less_than_or_equal = left_value <= right_value; - - if is_less_than_or_equal == comparator { - *ip += 1; - } -} - -pub fn less_equal_integers( - ip: &mut usize, - instruction: &Instruction, - thread: &mut Thread, - _: &mut Cache, -) { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let current_frame = thread.current_frame_mut(); - let left_value = if left_is_constant { - current_frame.get_integer_constant(left) - } else { - current_frame.get_integer_from_register(left) - }; - let right_value = if right_is_constant { - current_frame.get_integer_constant(right) - } else { - current_frame.get_integer_from_register(right) - }; - let is_less_than_or_equal = left_value <= right_value; - - if is_less_than_or_equal == comparator { - *ip += 1; - } -} - -pub fn less_equal_strings( - ip: &mut usize, - instruction: &Instruction, - thread: &mut Thread, - _: &mut Cache, -) { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let current_frame = thread.current_frame_mut(); - let left_value = if left_is_constant { - current_frame.get_string_constant(left) - } else { - current_frame.get_string_from_register(left) - }; - let right_value = if right_is_constant { - current_frame.get_string_constant(right) - } else { - current_frame.get_string_from_register(right) - }; - let is_less_than_or_equal = left_value <= right_value; - - if is_less_than_or_equal == comparator { - *ip += 1; - } -} - -pub fn optimized_less_equal_integers( - ip: &mut usize, - instruction: &Instruction, - thread: &mut Thread, - cache: &mut Cache, -) { - if let Cache::IntegerComparison([left, right]) = cache { - trace!("LESS_INTEGERS_OPTIMIZED using cache"); - - let is_less_than_or_equal = left <= right; - - if is_less_than_or_equal { - *ip += 1; - } - } else { - let left_index = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right_index = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let current_frame = thread.current_frame_mut(); - let left_value = if left_is_constant { - let value = current_frame.get_integer_constant_mut(left_index).to_rc(); - - current_frame.constants.integers[left_index] = value.clone(); - - value - } else { - let value = current_frame - .get_integer_from_register_mut(left_index) - .to_ref_cell(); - - current_frame.registers.integers[left_index].set(value.clone()); - - value - }; - let right_value = if right_is_constant { - let value = current_frame.get_integer_constant_mut(right_index).to_rc(); - - current_frame.constants.integers[right_index] = value.clone(); - - value - } else { - let value = current_frame - .get_integer_from_register_mut(right_index) - .to_ref_cell(); - - current_frame.registers.integers[right_index].set(value.clone()); - - value - }; - let is_less_than_or_equal = left_value <= right_value; - - if is_less_than_or_equal == comparator { - *ip += 1; - } - - *cache = Cache::IntegerComparison([left_value, right_value]); - } -} diff --git a/dust-lang/src/vm/action/mod.rs b/dust-lang/src/vm/action/mod.rs deleted file mode 100644 index 9e3a26b..0000000 --- a/dust-lang/src/vm/action/mod.rs +++ /dev/null @@ -1,623 +0,0 @@ -mod add; -mod equal; -mod jump; -mod less; -mod less_equal; - -use add::{ - add_bytes, add_character_string, add_characters, add_floats, add_integers, - add_string_character, add_strings, optimized_add_integer, -}; -use equal::{ - equal_booleans, equal_bytes, equal_characters, equal_floats, equal_integers, equal_strings, - optimized_equal_integers, -}; -use jump::{jump, optimized_jump_backward, optimized_jump_forward}; -use less::{ - less_booleans, less_bytes, less_characters, less_floats, less_integers, less_strings, - optimized_less_integers, -}; - -use less_equal::{ - less_equal_booleans, less_equal_bytes, less_equal_characters, less_equal_floats, - less_equal_integers, less_equal_strings, optimized_less_equal_integers, -}; -use tracing::info; - -use std::fmt::{self, Display, Formatter}; - -use crate::{instruction::TypeCode, AbstractList, ConcreteValue, Instruction, Operation, Value}; - -use super::{call_frame::RuntimeValue, thread::Thread, Pointer}; - -pub type ActionLogic = fn(&mut usize, &Instruction, &mut Thread, &mut Cache); - -#[derive(Debug)] -pub struct ActionSequence { - actions: Vec, -} - -impl ActionSequence { - pub fn new + DoubleEndedIterator>( - instructions: T, - ) -> Self { - let mut actions = Vec::new(); - let mut instructions_reversed = instructions.rev(); - - while let Some(instruction) = instructions_reversed.next() { - if instruction.operation() == Operation::JUMP { - let backward_offset = instruction.b_field() as usize; - let is_positive = instruction.c_field() != 0; - - if !is_positive { - let mut loop_actions = Vec::with_capacity(backward_offset); - let jump_action = Action::optimized(instruction); - - loop_actions.push(jump_action); - - for _ in 0..backward_offset { - let instruction = instructions_reversed.next().unwrap(); - let action = Action::optimized(instruction); - - loop_actions.push(action); - } - - loop_actions.reverse(); - - let cache = Cache::LoopActions(ActionSequence { - actions: loop_actions, - }); - - let action = Action { - instruction, - logic: r#loop, - cache, - }; - - actions.push(action); - - continue; - } - } - - let action = Action::unoptimized(instruction); - - actions.push(action); - } - - actions.reverse(); - - ActionSequence { actions } - } - - pub fn run(&mut self, thread: &mut Thread) { - let mut local_ip = 0; - - while local_ip < self.actions.len() { - let action = if cfg!(debug_assertions) { - self.actions.get_mut(local_ip).unwrap() - } else { - unsafe { self.actions.get_unchecked_mut(local_ip) } - }; - local_ip += 1; - - info!("Run {action}"); - - (action.logic)( - &mut local_ip, - &action.instruction, - thread, - &mut action.cache, - ); - } - } -} - -impl Display for ActionSequence { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "[")?; - - for (index, action) in self.actions.iter().enumerate() { - if index > 0 { - write!(f, ", ")?; - } - - write!(f, "{action}")?; - } - - write!(f, "]") - } -} - -#[derive(Debug)] -pub struct Action { - instruction: Instruction, - logic: ActionLogic, - cache: Cache, -} - -#[derive(Debug)] -pub enum Cache { - Empty, - IntegerMath([RuntimeValue; 3]), - IntegerComparison([RuntimeValue; 2]), - LoopActions(ActionSequence), -} - -impl Action { - pub fn unoptimized(instruction: Instruction) -> Self { - let logic = match instruction.operation() { - Operation::POINT => point, - Operation::CLOSE => close, - Operation::LOAD_ENCODED => load_encoded, - Operation::LOAD_CONSTANT => load_constant, - Operation::LOAD_LIST => load_list, - Operation::LOAD_FUNCTION => load_function, - Operation::LOAD_SELF => load_self, - Operation::ADD => match (instruction.b_type(), instruction.c_type()) { - (TypeCode::INTEGER, TypeCode::INTEGER) => add_integers, - (TypeCode::FLOAT, TypeCode::FLOAT) => add_floats, - (TypeCode::BYTE, TypeCode::BYTE) => add_bytes, - (TypeCode::STRING, TypeCode::STRING) => add_strings, - (TypeCode::CHARACTER, TypeCode::CHARACTER) => add_characters, - (TypeCode::STRING, TypeCode::CHARACTER) => add_string_character, - (TypeCode::CHARACTER, TypeCode::STRING) => add_character_string, - _ => unreachable!(), - }, - Operation::SUBTRACT => subtract, - Operation::MULTIPLY => multiply, - Operation::DIVIDE => divide, - Operation::MODULO => modulo, - Operation::NEGATE => negate, - Operation::NOT => not, - Operation::EQUAL => match (instruction.b_type(), instruction.c_type()) { - (TypeCode::BOOLEAN, TypeCode::BOOLEAN) => equal_booleans, - (TypeCode::BYTE, TypeCode::BYTE) => equal_bytes, - (TypeCode::CHARACTER, TypeCode::CHARACTER) => equal_characters, - (TypeCode::FLOAT, TypeCode::FLOAT) => equal_floats, - (TypeCode::INTEGER, TypeCode::INTEGER) => equal_integers, - (TypeCode::STRING, TypeCode::STRING) => equal_strings, - _ => todo!(), - }, - Operation::LESS => match (instruction.b_type(), instruction.c_type()) { - (TypeCode::BOOLEAN, TypeCode::BOOLEAN) => less_booleans, - (TypeCode::BYTE, TypeCode::BYTE) => less_bytes, - (TypeCode::CHARACTER, TypeCode::CHARACTER) => less_characters, - (TypeCode::FLOAT, TypeCode::FLOAT) => less_floats, - (TypeCode::INTEGER, TypeCode::INTEGER) => less_integers, - (TypeCode::STRING, TypeCode::STRING) => less_strings, - _ => todo!(), - }, - Operation::LESS_EQUAL => match (instruction.b_type(), instruction.c_type()) { - (TypeCode::BOOLEAN, TypeCode::BOOLEAN) => less_equal_booleans, - (TypeCode::BYTE, TypeCode::BYTE) => less_equal_bytes, - (TypeCode::CHARACTER, TypeCode::CHARACTER) => less_equal_characters, - (TypeCode::FLOAT, TypeCode::FLOAT) => less_equal_floats, - (TypeCode::INTEGER, TypeCode::INTEGER) => less_equal_integers, - (TypeCode::STRING, TypeCode::STRING) => less_equal_strings, - _ => todo!(), - }, - Operation::TEST => test, - Operation::TEST_SET => test_set, - Operation::CALL => call, - Operation::CALL_NATIVE => call_native, - Operation::JUMP => jump, - Operation::RETURN => r#return, - _ => todo!(), - }; - - Action { - instruction, - logic, - cache: Cache::Empty, - } - } - - pub fn optimized(instruction: Instruction) -> Self { - let logic = match instruction.operation() { - Operation::JUMP => match instruction.c_field() { - 0 => optimized_jump_backward, - _ => optimized_jump_forward, - }, - Operation::ADD => match (instruction.b_type(), instruction.c_type()) { - (TypeCode::INTEGER, TypeCode::INTEGER) => optimized_add_integer, - _ => todo!(), - }, - Operation::EQUAL => match (instruction.b_type(), instruction.c_type()) { - (TypeCode::INTEGER, TypeCode::INTEGER) => optimized_equal_integers, - _ => todo!(), - }, - Operation::LESS => match (instruction.b_type(), instruction.c_type()) { - (TypeCode::INTEGER, TypeCode::INTEGER) => optimized_less_integers, - _ => todo!(), - }, - Operation::LESS_EQUAL => match (instruction.b_type(), instruction.c_type()) { - (TypeCode::INTEGER, TypeCode::INTEGER) => optimized_less_equal_integers, - _ => todo!(), - }, - _ => todo!(), - }; - - Action { - instruction, - logic, - cache: Cache::Empty, - } - } -} - -impl Display for Action { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - if let Cache::LoopActions(actions) = &self.cache { - write!(f, "LOOP: {actions}")?; - } else { - write!(f, "{}", self.instruction.operation())?; - } - - Ok(()) - } -} - -fn r#loop(_: &mut usize, _: &Instruction, thread: &mut Thread, cache: &mut Cache) { - if let Cache::LoopActions(actions) = cache { - actions.run(thread); - } -} - -fn point(_: &mut usize, instruction: &Instruction, thread: &mut Thread, _: &mut Cache) { - todo!() -} - -fn close(_: &mut usize, instruction: &Instruction, thread: &mut Thread, _: &mut Cache) { - todo!() -} - -fn load_encoded(ip: &mut usize, instruction: &Instruction, thread: &mut Thread, _: &mut Cache) { - let destination = instruction.a_field(); - let value_type = instruction.b_type(); - let jump_next = instruction.c_field() != 0; - - match value_type { - TypeCode::BOOLEAN => { - let value = instruction.b_field() != 0; - - thread - .current_frame_mut() - .registers - .booleans - .get_mut(destination as usize) - .as_value_mut() - .set_inner(value); - } - TypeCode::BYTE => { - let value = instruction.b_field() as u8; - - thread - .current_frame_mut() - .registers - .bytes - .get_mut(destination as usize) - .as_value_mut() - .set_inner(value); - } - _ => unreachable!(), - } - - if jump_next { - *ip += 1; - } -} - -fn load_constant(ip: &mut usize, instruction: &Instruction, thread: &mut Thread, _: &mut Cache) { - let destination = instruction.a_field() as usize; - let constant_index = instruction.b_field() as usize; - let constant_type = instruction.b_type(); - let jump_next = instruction.c_field() != 0; - let current_frame = thread.current_frame_mut(); - - match constant_type { - TypeCode::CHARACTER => { - let constant = current_frame.get_character_constant(constant_index).clone(); - - current_frame - .registers - .characters - .get_mut(destination) - .set(constant); - } - TypeCode::FLOAT => { - let constant = current_frame.get_float_constant(constant_index).clone(); - - current_frame - .registers - .floats - .get_mut(destination) - .set(constant); - } - TypeCode::INTEGER => { - let constant = current_frame.get_integer_constant(constant_index).clone(); - - current_frame - .registers - .integers - .get_mut(destination) - .set(constant); - } - TypeCode::STRING => { - let constant = current_frame.get_string_constant(constant_index).clone(); - - current_frame - .registers - .strings - .get_mut(destination) - .set(constant); - } - _ => unreachable!(), - } - - if jump_next { - *ip += 1; - } -} - -fn load_list(ip: &mut usize, instruction: &Instruction, thread: &mut Thread, _: &mut Cache) { - let destination = instruction.a_field() as usize; - let start_register = instruction.b_field() as usize; - let item_type = instruction.b_type(); - let end_register = instruction.c_field() as usize; - let jump_next = instruction.d_field(); - let current_frame = thread.current_frame_mut(); - - let mut item_pointers = Vec::with_capacity(end_register - start_register + 1); - - match item_type { - TypeCode::BOOLEAN => { - for register_index in start_register..=end_register { - let register_is_closed = current_frame.registers.booleans.is_closed(register_index); - - if register_is_closed { - continue; - } - - item_pointers.push(Pointer::Register(register_index)); - } - } - TypeCode::BYTE => { - for register_index in start_register..=end_register { - let register_is_closed = current_frame.registers.bytes.is_closed(register_index); - - if register_is_closed { - continue; - } - - item_pointers.push(Pointer::Register(register_index)); - } - } - TypeCode::CHARACTER => { - for register_index in start_register..=end_register { - let register_is_closed = - current_frame.registers.characters.is_closed(register_index); - - if register_is_closed { - continue; - } - - item_pointers.push(Pointer::Register(register_index)); - } - } - TypeCode::FLOAT => { - for register_index in start_register..=end_register { - let register_is_closed = current_frame.registers.floats.is_closed(register_index); - - if register_is_closed { - continue; - } - - item_pointers.push(Pointer::Register(register_index)); - } - } - TypeCode::INTEGER => { - for register_index in start_register..=end_register { - let register_is_closed = current_frame.registers.integers.is_closed(register_index); - - if register_is_closed { - continue; - } - - item_pointers.push(Pointer::Register(register_index)); - } - } - TypeCode::STRING => { - for register_index in start_register..=end_register { - let register_is_closed = current_frame.registers.strings.is_closed(register_index); - - if register_is_closed { - continue; - } - - item_pointers.push(Pointer::Register(register_index)); - } - } - _ => unreachable!(), - } - - let list = RuntimeValue::Raw(AbstractList { - item_type, - item_pointers, - }); - - current_frame.registers.lists.get_mut(destination).set(list); - - if jump_next { - *ip += 1; - } -} - -fn load_function(_: &mut usize, _: &Instruction, _: &mut Thread, _: &mut Cache) { - todo!() -} - -fn load_self(_: &mut usize, _: &Instruction, _: &mut Thread, _: &mut Cache) { - todo!() -} - -fn subtract(_: &mut usize, instruction: &Instruction, thread: &mut Thread, _: &mut Cache) { - todo!() -} - -fn multiply(_: &mut usize, instruction: &Instruction, thread: &mut Thread, _: &mut Cache) { - todo!() -} - -fn divide(_: &mut usize, instruction: &Instruction, thread: &mut Thread, _: &mut Cache) { - todo!() -} - -fn modulo(_: &mut usize, instruction: &Instruction, thread: &mut Thread, _: &mut Cache) { - todo!() -} - -fn test(ip: &mut usize, instruction: &Instruction, thread: &mut Thread, _: &mut Cache) { - todo!() -} - -fn test_set(_: &mut usize, _: &Instruction, _: &mut Thread, _: &mut Cache) { - todo!() -} - -fn negate(_: &mut usize, _: &Instruction, _: &mut Thread, _: &mut Cache) { - todo!() -} - -fn not(_: &mut usize, _: &Instruction, _: &mut Thread, _: &mut Cache) { - todo!() -} - -fn call(_: &mut usize, _: &Instruction, _: &mut Thread, _: &mut Cache) { - todo!() -} - -fn call_native(_: &mut usize, _: &Instruction, _: &mut Thread, _: &mut Cache) { - todo!() -} - -fn r#return(_: &mut usize, instruction: &Instruction, thread: &mut Thread, _: &mut Cache) { - let should_return_value = instruction.b_field() != 0; - let return_register = instruction.c_field() as usize; - let return_type = instruction.b_type(); - let current_frame = thread.current_frame(); - - // if should_return_value { - // match return_type { - // TypeCode::BOOLEAN => { - // let return_value = current_frame - // .get_boolean_from_register(return_register) - // .clone_inner(); - // thread.return_value = Some(Value::boolean(return_value)); - // } - // TypeCode::BYTE => { - // let return_value = current_frame - // .get_byte_from_register(return_register) - // .clone_inner(); - // thread.return_value = Some(Value::byte(return_value)); - // } - // TypeCode::CHARACTER => { - // let return_value = current_frame - // .get_character_from_register(return_register) - // .clone_inner(); - // thread.return_value = Some(Value::character(return_value)); - // } - // TypeCode::FLOAT => { - // let return_value = current_frame - // .get_float_from_register(return_register) - // .clone_inner(); - // thread.return_value = Some(Value::float(return_value)); - // } - // TypeCode::INTEGER => { - // let return_value = current_frame - // .get_integer_from_register(return_register) - // .clone_inner(); - // thread.return_value = Some(Value::integer(return_value)); - // } - // TypeCode::STRING => { - // let return_value = current_frame - // .get_string_from_register(return_register) - // .clone_inner(); - // thread.return_value = Some(Value::string(return_value)); - // } - // TypeCode::LIST => { - // let abstract_list = current_frame - // .get_list_from_register(return_register) - // .clone_inner(); - // let mut concrete_list = Vec::with_capacity(abstract_list.item_pointers.len()); - - // match abstract_list.item_type { - // TypeCode::BOOLEAN => { - // for pointer in abstract_list.item_pointers { - // let boolean = current_frame - // .get_boolean_from_pointer(&pointer) - // .clone_inner(); - // let value = ConcreteValue::Boolean(boolean); - - // concrete_list.push(value); - // } - // } - // TypeCode::BYTE => { - // for pointer in abstract_list.item_pointers { - // let byte = current_frame.get_byte_from_pointer(&pointer).clone_inner(); - // let value = ConcreteValue::Byte(byte); - - // concrete_list.push(value); - // } - // } - // TypeCode::CHARACTER => { - // for pointer in abstract_list.item_pointers { - // let character = current_frame - // .get_character_from_pointer(&pointer) - // .clone_inner(); - // let value = ConcreteValue::Character(character); - - // concrete_list.push(value); - // } - // } - // TypeCode::FLOAT => { - // for pointer in abstract_list.item_pointers { - // let float = - // current_frame.get_float_from_pointer(&pointer).clone_inner(); - // let value = ConcreteValue::Float(float); - - // concrete_list.push(value); - // } - // } - // TypeCode::INTEGER => { - // for pointer in abstract_list.item_pointers { - // let integer = current_frame - // .get_integer_from_pointer(&pointer) - // .clone_inner(); - // let value = ConcreteValue::Integer(integer); - - // concrete_list.push(value); - // } - // } - // TypeCode::STRING => { - // for pointer in abstract_list.item_pointers { - // let string = current_frame - // .get_string_from_pointer(&pointer) - // .clone_inner(); - // let value = ConcreteValue::String(string); - - // concrete_list.push(value); - // } - // } - // _ => todo!(), - // } - - // thread.return_value = Some(Value::Concrete(ConcreteValue::list( - // concrete_list, - // abstract_list.item_type, - // ))); - // } - // _ => unreachable!(), - // } - // } -} diff --git a/dust-lang/src/vm/call_frame.rs b/dust-lang/src/vm/call_frame.rs deleted file mode 100644 index 422ae35..0000000 --- a/dust-lang/src/vm/call_frame.rs +++ /dev/null @@ -1,317 +0,0 @@ -use std::{ - fmt::{self, Debug, Display, Formatter}, - ops::{Index, IndexMut, RangeInclusive}, - sync::Arc, -}; - -use smallvec::SmallVec; - -use crate::{AbstractList, Chunk, DustString, Function}; - -#[derive(Debug)] -pub struct CallFrame { - pub chunk: Arc, - pub ip: usize, - pub return_register: u16, - pub registers: RegisterTable, -} - -impl CallFrame { - pub fn new(chunk: Arc, return_register: u16) -> Self { - let registers = RegisterTable { - booleans: RegisterList::new(chunk.boolean_register_count as usize), - bytes: RegisterList::new(chunk.byte_register_count as usize), - characters: RegisterList::new(chunk.character_register_count as usize), - floats: RegisterList::new(chunk.float_register_count as usize), - integers: RegisterList::new(chunk.integer_register_count as usize), - strings: RegisterList::new(chunk.string_register_count as usize), - lists: RegisterList::new(chunk.list_register_count as usize), - functions: RegisterList::new(chunk.function_register_count as usize), - }; - - Self { - chunk, - ip: 0, - return_register, - registers, - } - } - - pub fn get_boolean_from_pointer(&self, pointer: Pointer) -> bool { - match pointer { - Pointer::Register(register_index) => { - *self.registers.booleans.get(register_index).as_value() - } - Pointer::Constant(_) => panic!("Attempted to get boolean from constant pointer"), - } - } - - pub fn get_byte_from_pointer(&self, pointer: Pointer) -> u8 { - match pointer { - Pointer::Register(register_index) => { - *self.registers.bytes.get(register_index).as_value() - } - Pointer::Constant(_) => panic!("Attempted to get byte from constant pointer"), - } - } - - pub fn get_character_from_pointer(&self, pointer: Pointer) -> char { - match pointer { - Pointer::Register(register_index) => { - *self.registers.characters.get(register_index).as_value() - } - Pointer::Constant(constant_index) => self.get_character_constant(constant_index), - } - } - - pub fn get_character_constant(&self, constant_index: usize) -> char { - if cfg!(debug_assertions) { - *self.chunk.character_constants.get(constant_index).unwrap() - } else { - unsafe { *self.chunk.character_constants.get_unchecked(constant_index) } - } - } - - pub fn get_float_from_pointer(&self, pointer: Pointer) -> f64 { - match pointer { - Pointer::Register(register_index) => { - *self.registers.floats.get(register_index).as_value() - } - Pointer::Constant(constant_index) => self.get_float_constant(constant_index), - } - } - - pub fn get_float_constant(&self, constant_index: usize) -> f64 { - if cfg!(debug_assertions) { - *self.chunk.float_constants.get(constant_index).unwrap() - } else { - unsafe { *self.chunk.float_constants.get_unchecked(constant_index) } - } - } - - pub fn get_integer_from_pointer(&self, pointer: Pointer) -> i64 { - match pointer { - Pointer::Register(register_index) => { - *self.registers.integers.get(register_index).as_value() - } - Pointer::Constant(constant_index) => self.get_integer_constant(constant_index), - } - } - - pub fn get_integer_constant(&self, constant_index: usize) -> i64 { - if cfg!(debug_assertions) { - *self.chunk.integer_constants.get(constant_index).unwrap() - } else { - unsafe { *self.chunk.integer_constants.get_unchecked(constant_index) } - } - } - - pub fn get_string_from_pointer(&self, pointer: Pointer) -> &DustString { - match pointer { - Pointer::Register(register_index) => { - self.registers.strings.get(register_index).as_value() - } - Pointer::Constant(constant_index) => self.get_string_constant(constant_index), - } - } - - pub fn get_string_constant(&self, constant_index: usize) -> &DustString { - if cfg!(debug_assertions) { - self.chunk.string_constants.get(constant_index).unwrap() - } else { - unsafe { self.chunk.string_constants.get_unchecked(constant_index) } - } - } - - pub fn get_list_from_pointer(&self, pointer: &Pointer) -> &AbstractList { - match pointer { - Pointer::Register(register_index) => { - self.registers.lists.get(*register_index).as_value() - } - Pointer::Constant(_) => panic!("Attempted to get list from constant pointer"), - } - } - - pub fn get_function_from_pointer(&self, pointer: &Pointer) -> &Function { - match pointer { - Pointer::Register(register_index) => { - self.registers.functions.get(*register_index).as_value() - } - Pointer::Constant(_) => panic!("Attempted to get function from constant pointer"), - } - } -} - -impl Display for CallFrame { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!( - f, - "FunctionCall: {} | IP: {}", - self.chunk - .name - .as_ref() - .unwrap_or(&DustString::from("anonymous")), - self.ip, - ) - } -} - -#[derive(Debug)] -pub struct RegisterTable { - pub booleans: RegisterList, - pub bytes: RegisterList, - pub characters: RegisterList, - pub floats: RegisterList, - pub integers: RegisterList, - pub strings: RegisterList, - pub lists: RegisterList, - pub functions: RegisterList, -} - -#[derive(Debug)] -pub struct RegisterList { - pub registers: SmallVec<[Register; STACK_LEN]>, -} - -impl RegisterList -where - T: Clone + Default, -{ - pub fn new(length: usize) -> Self { - let mut registers = SmallVec::with_capacity(length); - - for _ in 0..length { - registers.push(Register::default()); - } - - Self { registers } - } - - pub fn get(&self, index: usize) -> &Register { - if cfg!(debug_assertions) { - self.registers.get(index).unwrap() - } else { - unsafe { self.registers.get_unchecked(index) } - } - } - - pub fn get_many_mut(&mut self, indices: RangeInclusive) -> &mut [Register] { - let registers = if cfg!(debug_assertions) { - self.registers.get_disjoint_mut([indices]).unwrap() - } else { - unsafe { self.registers.get_disjoint_unchecked_mut([indices]) } - }; - - registers[0] - } - - pub fn get_mut(&mut self, index: usize) -> &mut Register { - if cfg!(debug_assertions) { - let length = self.registers.len(); - - self.registers - .get_mut(index) - .unwrap_or_else(|| panic!("Index out of bounds: {index}. Length is {length}")) - } else { - unsafe { self.registers.get_unchecked_mut(index) } - } - } - - pub fn set_to_new_register(&mut self, index: usize, new_value: T) { - assert!(index < self.registers.len(), "Register index out of bounds"); - - self.registers[index] = Register::value(new_value) - } - - pub fn close(&mut self, index: usize) { - if cfg!(debug_assertions) { - self.registers.get_mut(index).unwrap().close() - } else { - unsafe { self.registers.get_unchecked_mut(index).close() } - } - } - - pub fn is_closed(&self, index: usize) -> bool { - if cfg!(debug_assertions) { - self.registers.get(index).unwrap().is_closed() - } else { - unsafe { self.registers.get_unchecked(index).is_closed() } - } - } -} - -impl Index for RegisterList { - type Output = Register; - - fn index(&self, index: usize) -> &Self::Output { - &self.registers[index] - } -} - -impl IndexMut for RegisterList { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.registers[index] - } -} - -#[derive(Clone, Copy, Debug)] -pub struct Register { - value: T, - is_closed: bool, -} - -impl Register { - pub fn value(value: T) -> Self { - Self { - value, - is_closed: false, - } - } - - pub fn is_closed(&self) -> bool { - self.is_closed - } - - pub fn close(&mut self) { - self.is_closed = true; - } - - pub fn set(&mut self, new_value: T) { - self.value = new_value; - } - - pub fn as_value(&self) -> &T { - &self.value - } - - pub fn as_value_mut(&mut self) -> &mut T { - &mut self.value - } -} - -impl Register { - pub fn copy_value(&self) -> T { - self.value - } -} - -impl Register { - pub fn clone_value(&self) -> T { - self.value.clone() - } -} - -impl Default for Register { - fn default() -> Self { - Self { - value: Default::default(), - is_closed: false, - } - } -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] -pub enum Pointer { - Register(usize), - Constant(usize), -} diff --git a/dust-lang/src/vm/mod.rs b/dust-lang/src/vm/mod.rs index 894d4c9..300e31d 100644 --- a/dust-lang/src/vm/mod.rs +++ b/dust-lang/src/vm/mod.rs @@ -1,17 +1,19 @@ //! Virtual machine and errors // mod action; -mod call_frame; mod thread; -use std::{sync::Arc, thread::Builder}; +use std::{ + ops::{Index, IndexMut, RangeInclusive}, + sync::Arc, + thread::Builder, +}; -pub use call_frame::{CallFrame, Pointer, Register, RegisterTable}; pub use thread::Thread; use crossbeam_channel::bounded; use tracing::{span, Level}; -use crate::{compile, Chunk, DustError, Value}; +use crate::{compile, AbstractList, Chunk, DustError, DustString, Function, Value}; pub fn run(source: &str) -> Result, DustError> { let chunk = compile(source)?; @@ -56,3 +58,236 @@ impl Vm { rx.recv().unwrap_or(None) } } + +#[derive(Clone, Debug)] +pub struct CallFrame { + pub chunk: Arc, + pub ip: usize, + pub return_register: u16, +} + +impl CallFrame { + pub fn new(chunk: Arc, return_register: u16) -> Self { + Self { + chunk, + ip: 0, + return_register, + } + } + + pub fn get_character_constant(&self, constant_index: usize) -> char { + if cfg!(debug_assertions) { + *self.chunk.character_constants.get(constant_index).unwrap() + } else { + unsafe { *self.chunk.character_constants.get_unchecked(constant_index) } + } + } + + pub fn get_float_constant(&self, constant_index: usize) -> f64 { + if cfg!(debug_assertions) { + *self.chunk.float_constants.get(constant_index).unwrap() + } else { + unsafe { *self.chunk.float_constants.get_unchecked(constant_index) } + } + } + + pub fn get_integer_constant(&self, constant_index: usize) -> i64 { + if cfg!(debug_assertions) { + *self.chunk.integer_constants.get(constant_index).unwrap() + } else { + unsafe { *self.chunk.integer_constants.get_unchecked(constant_index) } + } + } + + pub fn get_string_constant(&self, constant_index: usize) -> &DustString { + if cfg!(debug_assertions) { + self.chunk.string_constants.get(constant_index).unwrap() + } else { + unsafe { self.chunk.string_constants.get_unchecked(constant_index) } + } + } +} + +#[derive(Debug)] +pub struct RegisterTable { + pub booleans: RegisterList, + pub bytes: RegisterList, + pub characters: RegisterList, + pub floats: RegisterList, + pub integers: RegisterList, + pub strings: RegisterList, + pub lists: RegisterList, + pub functions: RegisterList, +} + +impl RegisterTable { + pub fn new(chunk: &Chunk) -> Self { + Self { + booleans: RegisterList::new(chunk.boolean_register_count as usize), + bytes: RegisterList::new(chunk.byte_register_count as usize), + characters: RegisterList::new(chunk.character_register_count as usize), + floats: RegisterList::new(chunk.float_register_count as usize), + integers: RegisterList::new(chunk.integer_register_count as usize), + strings: RegisterList::new(chunk.string_register_count as usize), + lists: RegisterList::new(chunk.list_register_count as usize), + functions: RegisterList::new(chunk.function_register_count as usize), + } + } +} + +#[derive(Debug)] +pub struct RegisterList { + pub registers: Vec>, +} + +impl RegisterList +where + T: Clone + Default, +{ + pub fn new(length: usize) -> Self { + let mut registers = Vec::with_capacity(length); + + for _ in 0..length { + registers.push(Register::default()); + } + + Self { registers } + } + + pub fn get(&self, index: usize) -> &Register { + if cfg!(debug_assertions) { + self.registers.get(index).unwrap() + } else { + unsafe { self.registers.get_unchecked(index) } + } + } + + pub fn get_many_mut(&mut self, indices: RangeInclusive) -> &mut [Register] { + let registers = if cfg!(debug_assertions) { + self.registers.get_disjoint_mut([indices]).unwrap() + } else { + unsafe { self.registers.get_disjoint_unchecked_mut([indices]) } + }; + + registers[0] + } + + pub fn get_mut(&mut self, index: usize) -> &mut Register { + if cfg!(debug_assertions) { + let length = self.registers.len(); + + self.registers + .get_mut(index) + .unwrap_or_else(|| panic!("Index out of bounds: {index}. Length is {length}")) + } else { + unsafe { self.registers.get_unchecked_mut(index) } + } + } + + pub fn set_to_new_register(&mut self, index: usize, new_value: T) { + assert!(index < self.registers.len(), "Register index out of bounds"); + + self.registers[index] = Register::value(new_value) + } + + pub fn close(&mut self, index: usize) { + if cfg!(debug_assertions) { + self.registers.get_mut(index).unwrap().close() + } else { + unsafe { self.registers.get_unchecked_mut(index).close() } + } + } + + pub fn is_closed(&self, index: usize) -> bool { + if cfg!(debug_assertions) { + self.registers.get(index).unwrap().is_closed() + } else { + unsafe { self.registers.get_unchecked(index).is_closed() } + } + } +} + +impl Index for RegisterList { + type Output = Register; + + fn index(&self, index: usize) -> &Self::Output { + &self.registers[index] + } +} + +impl IndexMut for RegisterList { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.registers[index] + } +} + +#[derive(Clone, Copy, Debug)] +pub struct Register { + value: T, + is_closed: bool, +} + +impl Register { + pub fn value(value: T) -> Self { + Self { + value, + is_closed: false, + } + } + + pub fn is_closed(&self) -> bool { + self.is_closed + } + + pub fn close(&mut self) { + self.is_closed = true; + } + + pub fn set(&mut self, new_value: T) { + self.value = new_value; + } + + pub fn as_value(&self) -> &T { + &self.value + } + + pub fn as_value_mut(&mut self) -> &mut T { + &mut self.value + } +} + +impl Register { + pub fn copy_value(&self) -> T { + self.value + } +} + +impl Register { + pub fn clone_value(&self) -> T { + self.value.clone() + } +} + +impl Default for Register { + fn default() -> Self { + Self { + value: Default::default(), + is_closed: false, + } + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub enum Pointer { + Register(u16), + Constant(u16), +} + +impl Pointer { + pub fn index(&self) -> u16 { + match self { + Pointer::Register(index) => *index, + Pointer::Constant(index) => *index, + } + } +} diff --git a/dust-lang/src/vm/thread.rs b/dust-lang/src/vm/thread.rs index 96a9224..d514fa0 100644 --- a/dust-lang/src/vm/thread.rs +++ b/dust-lang/src/vm/thread.rs @@ -1,16 +1,19 @@ use std::{sync::Arc, thread::JoinHandle}; -use tracing::info; +use tracing::{info, trace}; use crate::{ instruction::TypeCode, vm::{CallFrame, Pointer}, - AbstractList, Chunk, DustString, Operation, Span, Value, + AbstractList, Chunk, DustString, Operation, Span, Type, Value, }; +use super::RegisterTable; + pub struct Thread { chunk: Arc, call_stack: Vec, + register_stack: Vec, _spawned_threads: Vec>, } @@ -21,1429 +24,19 @@ impl Thread { call_stack.push(main_call); + let mut register_stack = Vec::with_capacity(chunk.prototypes.len() + 1); + let main_registers = RegisterTable::new(&chunk); + + register_stack.push(main_registers); + Thread { chunk, call_stack, + register_stack, _spawned_threads: Vec::new(), } } - pub fn run(mut self) -> Option { - info!( - "Starting thread {}", - self.chunk - .name - .clone() - .unwrap_or_else(|| DustString::from("anonymous")) - ); - - while !self.call_stack.is_empty() { - let current_frame = self.current_frame_mut(); - let instructions = ¤t_frame.chunk.instructions; - let ip = { - let current = current_frame.ip; - current_frame.ip += 1; - - current - }; - - assert!(ip < instructions.len(), "IP out of bounds"); - - let instruction = &instructions[ip]; - - info!("IP = {ip} Run {}", instruction.operation()); - - match instruction.operation() { - Operation::MOVE => { - let source = instruction.b_field() as usize; - let destination = instruction.a_field() as usize; - let source_type = instruction.b_type(); - - match source_type { - TypeCode::BOOLEAN => { - let value = current_frame.registers.booleans.get(source).copy_value(); - - current_frame - .registers - .booleans - .get_mut(destination) - .set(value); - } - TypeCode::BYTE => { - let value = current_frame.registers.bytes.get(source).copy_value(); - - current_frame - .registers - .bytes - .get_mut(destination) - .set(value); - } - TypeCode::CHARACTER => { - let value = current_frame.registers.characters.get(source).copy_value(); - - current_frame - .registers - .characters - .get_mut(destination) - .set(value); - } - TypeCode::FLOAT => { - let value = current_frame.registers.floats.get(source).copy_value(); - - current_frame - .registers - .floats - .get_mut(destination) - .set(value); - } - TypeCode::INTEGER => { - let value = current_frame.registers.integers.get(source).copy_value(); - - current_frame - .registers - .integers - .get_mut(destination) - .set(value); - } - TypeCode::STRING => { - let value = current_frame.registers.strings.get(source).clone_value(); - - current_frame - .registers - .strings - .get_mut(destination) - .set(value); - } - TypeCode::LIST => { - let value = current_frame.registers.lists.get(source).clone_value(); - - current_frame - .registers - .lists - .get_mut(destination) - .set(value); - } - _ => todo!(), - } - } - Operation::CLOSE => { - let from = instruction.b_field() as usize; - let to = instruction.c_field() as usize; - let r#type = instruction.b_type(); - - match r#type { - TypeCode::BOOLEAN => { - let registers = - current_frame.registers.booleans.get_many_mut(from..=to); - - for register in registers { - register.close(); - } - } - TypeCode::BYTE => { - let registers = current_frame.registers.bytes.get_many_mut(from..=to); - - for register in registers { - register.close(); - } - } - TypeCode::CHARACTER => { - let registers = - current_frame.registers.characters.get_many_mut(from..=to); - - for register in registers { - register.close(); - } - } - TypeCode::FLOAT => { - let registers = current_frame.registers.floats.get_many_mut(from..=to); - - for register in registers { - register.close(); - } - } - TypeCode::INTEGER => { - let registers = - current_frame.registers.integers.get_many_mut(from..=to); - - for register in registers { - register.close(); - } - } - TypeCode::STRING => { - let registers = current_frame.registers.strings.get_many_mut(from..=to); - - for register in registers { - register.close(); - } - } - TypeCode::LIST => { - let registers = current_frame.registers.lists.get_many_mut(from..=to); - - for register in registers { - register.close(); - } - } - _ => unreachable!("Invalid CLOSE instruction"), - } - } - Operation::LOAD_ENCODED => { - let destination = instruction.a_field() as usize; - let value_type = instruction.b_type(); - let jump_next = instruction.c_field() != 0; - - match value_type { - TypeCode::BOOLEAN => { - let boolean = instruction.b_field() != 0; - - current_frame - .registers - .booleans - .set_to_new_register(destination, boolean); - } - TypeCode::BYTE => { - let byte = instruction.b_field() as u8; - - current_frame - .registers - .bytes - .set_to_new_register(destination, byte); - } - _ => unreachable!("Invalid LOAD_ENCODED instruction"), - } - - if jump_next { - current_frame.ip += 1; - } - } - Operation::LOAD_CONSTANT => { - let destination = instruction.a_field() as usize; - let constant_index = instruction.b_field() as usize; - let constant_type = instruction.b_type(); - let jump_next = instruction.c_field() != 0; - - match constant_type { - TypeCode::CHARACTER => { - let character = current_frame.get_character_constant(constant_index); - - current_frame - .registers - .characters - .get_mut(destination) - .set(character); - } - TypeCode::FLOAT => { - let float = current_frame.get_float_constant(constant_index); - - current_frame - .registers - .floats - .get_mut(destination) - .set(float); - } - TypeCode::INTEGER => { - let integer = current_frame.get_integer_constant(constant_index); - - current_frame - .registers - .integers - .get_mut(destination) - .set(integer); - } - TypeCode::STRING => { - let string = current_frame.get_string_constant(constant_index).clone(); - - current_frame - .registers - .strings - .get_mut(destination) - .set(string); - } - _ => unreachable!("Invalid LOAD_CONSTANT operation"), - } - - if jump_next { - current_frame.ip += 1; - } - } - Operation::LOAD_LIST => { - let destination = instruction.a_field() as usize; - let start_register = instruction.b_field() as usize; - let item_type = instruction.b_type(); - let end_register = instruction.c_field() as usize; - let jump_next = instruction.d_field(); - - let mut item_pointers = Vec::with_capacity(end_register - start_register + 1); - - match item_type { - TypeCode::BOOLEAN => { - for register_index in start_register..=end_register { - let register_is_closed = - current_frame.registers.booleans.is_closed(register_index); - - if register_is_closed { - continue; - } - - item_pointers.push(Pointer::Register(register_index)); - } - } - TypeCode::BYTE => { - for register_index in start_register..=end_register { - let register_is_closed = - current_frame.registers.bytes.is_closed(register_index); - - if register_is_closed { - continue; - } - - item_pointers.push(Pointer::Register(register_index)); - } - } - TypeCode::CHARACTER => { - for register_index in start_register..=end_register { - let register_is_closed = - current_frame.registers.characters.is_closed(register_index); - - if register_is_closed { - continue; - } - - item_pointers.push(Pointer::Register(register_index)); - } - } - TypeCode::FLOAT => { - for register_index in start_register..=end_register { - let register_is_closed = - current_frame.registers.floats.is_closed(register_index); - - if register_is_closed { - continue; - } - - item_pointers.push(Pointer::Register(register_index)); - } - } - TypeCode::INTEGER => { - for register_index in start_register..=end_register { - let register_is_closed = - current_frame.registers.integers.is_closed(register_index); - - if register_is_closed { - continue; - } - - item_pointers.push(Pointer::Register(register_index)); - } - } - TypeCode::STRING => { - for register_index in start_register..=end_register { - let register_is_closed = - current_frame.registers.strings.is_closed(register_index); - - if register_is_closed { - continue; - } - - item_pointers.push(Pointer::Register(register_index)); - } - } - TypeCode::LIST => { - for register_index in start_register..=end_register { - let register_is_closed = - current_frame.registers.lists.is_closed(register_index); - - if register_is_closed { - continue; - } - - item_pointers.push(Pointer::Register(register_index)); - } - } - _ => unreachable!("Invalid LOAD_LIST instruction"), - } - - let list = AbstractList { - item_type, - item_pointers, - }; - - current_frame.registers.lists.get_mut(destination).set(list); - - if jump_next { - current_frame.ip += 1; - } - } - Operation::LOAD_FUNCTION => { - let destination = instruction.a_field() as usize; - let prototype_index = instruction.b_field() as usize; - let jump_next = instruction.c_field() != 0; - let prototype = if cfg!(debug_assertions) { - current_frame.chunk.prototypes.get(prototype_index).unwrap() - } else { - unsafe { - current_frame - .chunk - .prototypes - .get_unchecked(prototype_index) - } - }; - let function = prototype.as_function(); - - current_frame - .registers - .functions - .set_to_new_register(destination, function); - - if jump_next { - current_frame.ip += 1; - } - } - Operation::LOAD_SELF => { - let destination = instruction.a_field() as usize; - let jump_next = instruction.c_field() != 0; - let self_function = current_frame.chunk.as_function(); - - current_frame - .registers - .functions - .set_to_new_register(destination, self_function); - - if jump_next { - current_frame.ip += 1; - } - } - Operation::ADD => match (instruction.b_type(), instruction.c_type()) { - (TypeCode::BYTE, TypeCode::BYTE) => { - let left_index = instruction.b_field() as usize; - let right_index = instruction.c_field() as usize; - let destination_index = instruction.a_field() as usize; - - let left_value = current_frame.registers.bytes.get(left_index).copy_value(); - let right_value = - current_frame.registers.bytes.get(right_index).copy_value(); - let sum = left_value + right_value; - - current_frame - .registers - .bytes - .set_to_new_register(destination_index, sum); - } - (TypeCode::CHARACTER, TypeCode::CHARACTER) => { - let left_index = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right_index = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let destination_index = instruction.a_field() as usize; - - let left_value = if left_is_constant { - current_frame.get_character_constant(left_index) - } else { - current_frame - .registers - .characters - .get(left_index) - .copy_value() - }; - let right_value = if right_is_constant { - current_frame.get_character_constant(right_index) - } else { - current_frame - .registers - .characters - .get(right_index) - .copy_value() - }; - let concatenated = { - let mut concatenated = DustString::from(String::with_capacity(2)); - - concatenated.push(left_value); - concatenated.push(right_value); - - concatenated - }; - - current_frame - .registers - .strings - .set_to_new_register(destination_index, concatenated); - } - (TypeCode::CHARACTER, TypeCode::STRING) => { - let left_index = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right_index = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let destination_index = instruction.a_field() as usize; - - let left_value = if left_is_constant { - current_frame.get_character_constant(left_index) - } else { - current_frame - .registers - .characters - .get(left_index) - .copy_value() - }; - let right_value = if right_is_constant { - current_frame.get_string_constant(right_index) - } else { - current_frame.registers.strings.get(right_index).as_value() - }; - let concatenated = DustString::from(format!("{left_value}{right_value}")); - - current_frame - .registers - .strings - .set_to_new_register(destination_index, concatenated); - } - (TypeCode::FLOAT, TypeCode::FLOAT) => { - let left_index = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right_index = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let destination_index = instruction.a_field() as usize; - - let left_value = if left_is_constant { - current_frame.get_float_constant(left_index) - } else { - current_frame.registers.floats.get(left_index).copy_value() - }; - let right_value = if right_is_constant { - current_frame.get_float_constant(right_index) - } else { - current_frame.registers.floats.get(right_index).copy_value() - }; - let sum = left_value + right_value; - - current_frame - .registers - .floats - .set_to_new_register(destination_index, sum); - } - (TypeCode::INTEGER, TypeCode::INTEGER) => { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let destination_index = instruction.a_field() as usize; - - let left_value = if left_is_constant { - current_frame.get_integer_constant(left) - } else { - current_frame.registers.integers.get(left).copy_value() - }; - let right_value = if right_is_constant { - current_frame.get_integer_constant(right) - } else { - current_frame.registers.integers.get(right).copy_value() - }; - let sum = left_value + right_value; - - current_frame - .registers - .integers - .set_to_new_register(destination_index, sum); - } - (TypeCode::STRING, TypeCode::CHARACTER) => { - let left_index = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right_index = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let destination_index = instruction.a_field() as usize; - - let left_value = if left_is_constant { - current_frame.get_string_constant(left_index) - } else { - current_frame.registers.strings.get(left_index).as_value() - }; - let right_value = if right_is_constant { - current_frame.get_character_constant(right_index) - } else { - current_frame - .registers - .characters - .get(right_index) - .copy_value() - }; - let concatenated = DustString::from(format!("{left_value}{right_value}")); - - current_frame - .registers - .strings - .set_to_new_register(destination_index, concatenated); - } - (TypeCode::STRING, TypeCode::STRING) => { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let destination_index = instruction.a_field() as usize; - - let left_value = if left_is_constant { - current_frame.get_string_constant(left) - } else { - current_frame.registers.strings.get(left).as_value() - }; - let right_value = if right_is_constant { - current_frame.get_string_constant(right) - } else { - current_frame.registers.strings.get(right).as_value() - }; - let concatenated = DustString::from(format!("{left_value}{right_value}")); - - current_frame - .registers - .strings - .set_to_new_register(destination_index, concatenated); - } - _ => unreachable!("Invalid ADD instruction"), - }, - Operation::SUBTRACT => match (instruction.b_type(), instruction.c_type()) { - (TypeCode::BYTE, TypeCode::BYTE) => { - let left_index = instruction.b_field() as usize; - let right_index = instruction.c_field() as usize; - let destination_index = instruction.a_field() as usize; - - let left_value = current_frame.registers.bytes.get(left_index).copy_value(); - let right_value = - current_frame.registers.bytes.get(right_index).copy_value(); - let difference = left_value - right_value; - - current_frame - .registers - .bytes - .set_to_new_register(destination_index, difference); - } - (TypeCode::FLOAT, TypeCode::FLOAT) => { - let left_index = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right_index = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let destination_index = instruction.a_field() as usize; - - let left_value = if left_is_constant { - current_frame.get_float_constant(left_index) - } else { - current_frame.registers.floats.get(left_index).copy_value() - }; - let right_value = if right_is_constant { - current_frame.get_float_constant(right_index) - } else { - current_frame.registers.floats.get(right_index).copy_value() - }; - let difference = left_value - right_value; - - current_frame - .registers - .floats - .set_to_new_register(destination_index, difference); - } - (TypeCode::INTEGER, TypeCode::INTEGER) => { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let destination_index = instruction.a_field() as usize; - - let left_value = if left_is_constant { - current_frame.get_integer_constant(left) - } else { - current_frame.registers.integers.get(left).copy_value() - }; - let right_value = if right_is_constant { - current_frame.get_integer_constant(right) - } else { - current_frame.registers.integers.get(right).copy_value() - }; - let difference = left_value - right_value; - - current_frame - .registers - .integers - .set_to_new_register(destination_index, difference); - } - _ => unreachable!("Invalid SUBTRACT instruction"), - }, - Operation::MULTIPLY => match (instruction.b_type(), instruction.c_type()) { - (TypeCode::BYTE, TypeCode::BYTE) => { - let left_index = instruction.b_field() as usize; - let right_index = instruction.c_field() as usize; - let destination_index = instruction.a_field() as usize; - - let left_value = current_frame.registers.bytes.get(left_index).copy_value(); - let right_value = - current_frame.registers.bytes.get(right_index).copy_value(); - let product = left_value * right_value; - - current_frame - .registers - .bytes - .set_to_new_register(destination_index, product); - } - (TypeCode::FLOAT, TypeCode::FLOAT) => { - let left_index = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right_index = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let destination_index = instruction.a_field() as usize; - - let left_value = if left_is_constant { - current_frame.get_float_constant(left_index) - } else { - current_frame.registers.floats.get(left_index).copy_value() - }; - let right_value = if right_is_constant { - current_frame.get_float_constant(right_index) - } else { - current_frame.registers.floats.get(right_index).copy_value() - }; - let product = left_value * right_value; - - current_frame - .registers - .floats - .set_to_new_register(destination_index, product); - } - (TypeCode::INTEGER, TypeCode::INTEGER) => { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let destination_index = instruction.a_field() as usize; - - let left_value = if left_is_constant { - current_frame.get_integer_constant(left) - } else { - current_frame.registers.integers.get(left).copy_value() - }; - let right_value = if right_is_constant { - current_frame.get_integer_constant(right) - } else { - current_frame.registers.integers.get(right).copy_value() - }; - let product = left_value * right_value; - - current_frame - .registers - .integers - .set_to_new_register(destination_index, product); - } - _ => unreachable!("Invalid MULTIPLY instruction"), - }, - Operation::DIVIDE => match (instruction.b_type(), instruction.c_type()) { - (TypeCode::BYTE, TypeCode::BYTE) => { - let left_index = instruction.b_field() as usize; - let right_index = instruction.c_field() as usize; - let destination_index = instruction.a_field() as usize; - - let left_value = current_frame.registers.bytes.get(left_index).copy_value(); - let right_value = - current_frame.registers.bytes.get(right_index).copy_value(); - let quotient = left_value / right_value; - - current_frame - .registers - .bytes - .set_to_new_register(destination_index, quotient); - } - (TypeCode::FLOAT, TypeCode::FLOAT) => { - let left_index = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right_index = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let destination_index = instruction.a_field() as usize; - - let left_value = if left_is_constant { - current_frame.get_float_constant(left_index) - } else { - current_frame.registers.floats.get(left_index).copy_value() - }; - let right_value = if right_is_constant { - current_frame.get_float_constant(right_index) - } else { - current_frame.registers.floats.get(right_index).copy_value() - }; - let quotient = left_value / right_value; - - current_frame - .registers - .floats - .set_to_new_register(destination_index, quotient); - } - (TypeCode::INTEGER, TypeCode::INTEGER) => { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let destination_index = instruction.a_field() as usize; - - let left_value = if left_is_constant { - current_frame.get_integer_constant(left) - } else { - current_frame.registers.integers.get(left).copy_value() - }; - let right_value = if right_is_constant { - current_frame.get_integer_constant(right) - } else { - current_frame.registers.integers.get(right).copy_value() - }; - let quotient = left_value / right_value; - - current_frame - .registers - .integers - .set_to_new_register(destination_index, quotient); - } - _ => unreachable!("Invalid DIVIDE instruction"), - }, - Operation::MODULO => match (instruction.b_type(), instruction.c_type()) { - (TypeCode::BYTE, TypeCode::BYTE) => { - let left_index = instruction.b_field() as usize; - let right_index = instruction.c_field() as usize; - let destination_index = instruction.a_field() as usize; - - let left_value = current_frame.registers.bytes.get(left_index).copy_value(); - let right_value = - current_frame.registers.bytes.get(right_index).copy_value(); - let remainder = left_value % right_value; - - current_frame - .registers - .bytes - .set_to_new_register(destination_index, remainder); - } - (TypeCode::FLOAT, TypeCode::FLOAT) => { - let left_index = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right_index = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let destination_index = instruction.a_field() as usize; - - let left_value = if left_is_constant { - current_frame.get_float_constant(left_index) - } else { - current_frame.registers.floats.get(left_index).copy_value() - }; - let right_value = if right_is_constant { - current_frame.get_float_constant(right_index) - } else { - current_frame.registers.floats.get(right_index).copy_value() - }; - let remainder = left_value % right_value; - - current_frame - .registers - .floats - .set_to_new_register(destination_index, remainder); - } - (TypeCode::INTEGER, TypeCode::INTEGER) => { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let destination_index = instruction.a_field() as usize; - - let left_value = if left_is_constant { - current_frame.get_integer_constant(left) - } else { - current_frame.registers.integers.get(left).copy_value() - }; - let right_value = if right_is_constant { - current_frame.get_integer_constant(right) - } else { - current_frame.registers.integers.get(right).copy_value() - }; - let remainder = left_value % right_value; - - current_frame - .registers - .integers - .set_to_new_register(destination_index, remainder); - } - _ => unreachable!("Invalid MODULO instruction"), - }, - Operation::EQUAL => match (instruction.b_type(), instruction.c_type()) { - (TypeCode::BOOLEAN, TypeCode::BOOLEAN) => { - let left_index = instruction.b_field() as usize; - let right_index = instruction.c_field() as usize; - let comparator = instruction.d_field(); - - let left_value = current_frame - .registers - .booleans - .get(left_index) - .copy_value(); - let right_value = current_frame - .registers - .booleans - .get(right_index) - .copy_value(); - - // See for more info. - let is_equal = matches!((left_value as i8) - (right_value as i8), 0); - - if is_equal == comparator { - current_frame.ip += 1; - } - } - (TypeCode::BYTE, TypeCode::BYTE) => { - let left = instruction.b_field() as usize; - let right = instruction.c_field() as usize; - let comparator = instruction.d_field(); - - let left_value = current_frame.registers.bytes.get(left).copy_value(); - let right_value = current_frame.registers.bytes.get(right).copy_value(); - let is_equal = left_value == right_value; - - if is_equal == comparator { - current_frame.ip += 1; - } - } - (TypeCode::CHARACTER, TypeCode::CHARACTER) => { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let left_value = if left_is_constant { - current_frame.get_character_constant(left) - } else { - current_frame.registers.characters.get(left).copy_value() - }; - let right_value = if right_is_constant { - current_frame.get_character_constant(right) - } else { - current_frame.registers.characters.get(right).copy_value() - }; - let is_equal = left_value == right_value; - - if is_equal == comparator { - current_frame.ip += 1; - } - } - (TypeCode::FLOAT, TypeCode::FLOAT) => { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let left_value = if left_is_constant { - current_frame.get_float_constant(left) - } else { - current_frame.registers.floats.get(left).copy_value() - }; - let right_value = if right_is_constant { - current_frame.get_float_constant(right) - } else { - current_frame.registers.floats.get(right).copy_value() - }; - let is_equal = left_value == right_value; - - if is_equal == comparator { - current_frame.ip += 1; - } - } - (TypeCode::INTEGER, TypeCode::INTEGER) => { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let left_value = if left_is_constant { - current_frame.get_integer_constant(left) - } else { - current_frame.registers.integers.get(left).copy_value() - }; - let right_value = if right_is_constant { - current_frame.get_integer_constant(right) - } else { - current_frame.registers.integers.get(right).copy_value() - }; - let is_equal = left_value == right_value; - - if is_equal == comparator { - current_frame.ip += 1; - } - } - (TypeCode::STRING, TypeCode::STRING) => { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let left_value = if left_is_constant { - current_frame.get_string_constant(left) - } else { - current_frame.registers.strings.get(left).as_value() - }; - let right_value = if right_is_constant { - current_frame.get_string_constant(right) - } else { - current_frame.registers.strings.get(right).as_value() - }; - let is_equal = left_value == right_value; - - if is_equal == comparator { - current_frame.ip += 1; - } - } - (TypeCode::LIST, TypeCode::LIST) => { - let left = instruction.b_field() as usize; - let right = instruction.c_field() as usize; - let comparator = instruction.d_field(); - - let left_value = current_frame.registers.lists.get(left).as_value(); - let right_value = current_frame.registers.lists.get(right).as_value(); - let is_equal = left_value == right_value; - - if is_equal == comparator { - current_frame.ip += 1; - } - } - (TypeCode::FUNCTION, TypeCode::FUNCTION) => { - let left = instruction.b_field() as usize; - let right = instruction.c_field() as usize; - let comparator = instruction.d_field(); - - let left_value = current_frame.registers.functions.get(left).as_value(); - let right_value = current_frame.registers.functions.get(right).as_value(); - let is_equal = left_value == right_value; - - if is_equal == comparator { - current_frame.ip += 1; - } - } - _ => unreachable!("Invalid EQUAL instruction"), - }, - Operation::LESS => match (instruction.b_type(), instruction.c_type()) { - (TypeCode::BOOLEAN, TypeCode::BOOLEAN) => { - let left_index = instruction.b_field() as usize; - let right_index = instruction.c_field() as usize; - let comparator = instruction.d_field(); - - let left_value = current_frame - .registers - .booleans - .get(left_index) - .copy_value(); - let right_value = current_frame - .registers - .booleans - .get(right_index) - .copy_value(); - - // See for more info. - let is_less_than = matches!((left_value as i8) - (right_value as i8), -1); - - if is_less_than == comparator { - current_frame.ip += 1; - } - } - (TypeCode::BYTE, TypeCode::BYTE) => { - let left = instruction.b_field() as usize; - let right = instruction.c_field() as usize; - let comparator = instruction.d_field(); - - let left_value = current_frame.registers.bytes.get(left).copy_value(); - let right_value = current_frame.registers.bytes.get(right).copy_value(); - let is_less_than = left_value < right_value; - - if is_less_than == comparator { - current_frame.ip += 1; - } - } - (TypeCode::CHARACTER, TypeCode::CHARACTER) => { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let left_value = if left_is_constant { - current_frame.get_character_constant(left) - } else { - current_frame.registers.characters.get(left).copy_value() - }; - let right_value = if right_is_constant { - current_frame.get_character_constant(right) - } else { - current_frame.registers.characters.get(right).copy_value() - }; - let is_less_than = left_value < right_value; - - if is_less_than == comparator { - current_frame.ip += 1; - } - } - (TypeCode::FLOAT, TypeCode::FLOAT) => { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let left_value = if left_is_constant { - current_frame.get_float_constant(left) - } else { - current_frame.registers.floats.get(left).copy_value() - }; - let right_value = if right_is_constant { - current_frame.get_float_constant(right) - } else { - current_frame.registers.floats.get(right).copy_value() - }; - let is_less_than = left_value < right_value; - - if is_less_than == comparator { - current_frame.ip += 1; - } - } - (TypeCode::INTEGER, TypeCode::INTEGER) => { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let left_value = if left_is_constant { - current_frame.get_integer_constant(left) - } else { - current_frame.registers.integers.get(left).copy_value() - }; - let right_value = if right_is_constant { - current_frame.get_integer_constant(right) - } else { - current_frame.registers.integers.get(right).copy_value() - }; - let is_less_than = left_value < right_value; - - if is_less_than == comparator { - current_frame.ip += 1; - } - } - (TypeCode::STRING, TypeCode::STRING) => { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let left_value = if left_is_constant { - current_frame.get_string_constant(left) - } else { - current_frame.registers.strings.get(left).as_value() - }; - let right_value = if right_is_constant { - current_frame.get_string_constant(right) - } else { - current_frame.registers.strings.get(right).as_value() - }; - let is_less_than = left_value < right_value; - - if is_less_than == comparator { - current_frame.ip += 1; - } - } - (TypeCode::LIST, TypeCode::LIST) => { - let left = instruction.b_field() as usize; - let right = instruction.c_field() as usize; - let comparator = instruction.d_field(); - - let left_value = current_frame.registers.lists.get(left).as_value(); - let right_value = current_frame.registers.lists.get(right).as_value(); - let is_less_than = left_value < right_value; - - if is_less_than == comparator { - current_frame.ip += 1; - } - } - (TypeCode::FUNCTION, TypeCode::FUNCTION) => { - let left = instruction.b_field() as usize; - let right = instruction.c_field() as usize; - let comparator = instruction.d_field(); - - let left_value = current_frame.registers.functions.get(left).as_value(); - let right_value = current_frame.registers.functions.get(right).as_value(); - let is_less_than = left_value < right_value; - - if is_less_than == comparator { - current_frame.ip += 1; - } - } - _ => unreachable!("Invalid LESS instruction"), - }, - Operation::LESS_EQUAL => match (instruction.b_type(), instruction.c_type()) { - (TypeCode::BOOLEAN, TypeCode::BOOLEAN) => { - let left_index = instruction.b_field() as usize; - let right_index = instruction.c_field() as usize; - let comparator = instruction.d_field(); - - let left_value = current_frame - .registers - .booleans - .get(left_index) - .copy_value(); - let right_value = current_frame - .registers - .booleans - .get(right_index) - .copy_value(); - - // See for more info. - let is_less_than_or_equal = - matches!(left_value as i8 - right_value as i8, -1 | 0); - - if is_less_than_or_equal == comparator { - current_frame.ip += 1; - } - } - (TypeCode::BYTE, TypeCode::BYTE) => { - let left = instruction.b_field() as usize; - let right = instruction.c_field() as usize; - let comparator = instruction.d_field(); - - let left_value = current_frame.registers.bytes.get(left).copy_value(); - let right_value = current_frame.registers.bytes.get(right).copy_value(); - let is_less_than_or_equal = left_value <= right_value; - - if is_less_than_or_equal == comparator { - current_frame.ip += 1; - } - } - (TypeCode::CHARACTER, TypeCode::CHARACTER) => { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let left_value = if left_is_constant { - current_frame.get_character_constant(left) - } else { - current_frame.registers.characters.get(left).copy_value() - }; - let right_value = if right_is_constant { - current_frame.get_character_constant(right) - } else { - current_frame.registers.characters.get(right).copy_value() - }; - let is_less_than_or_equal = left_value <= right_value; - - if is_less_than_or_equal == comparator { - current_frame.ip += 1; - } - } - (TypeCode::FLOAT, TypeCode::FLOAT) => { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let left_value = if left_is_constant { - current_frame.get_float_constant(left) - } else { - current_frame.registers.floats.get(left).copy_value() - }; - let right_value = if right_is_constant { - current_frame.get_float_constant(right) - } else { - current_frame.registers.floats.get(right).copy_value() - }; - let is_less_than_or_equal = left_value <= right_value; - - if is_less_than_or_equal == comparator { - current_frame.ip += 1; - } - } - (TypeCode::INTEGER, TypeCode::INTEGER) => { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let left_value = if left_is_constant { - current_frame.get_integer_constant(left) - } else { - current_frame.registers.integers.get(left).copy_value() - }; - let right_value = if right_is_constant { - current_frame.get_integer_constant(right) - } else { - current_frame.registers.integers.get(right).copy_value() - }; - let is_less_than_or_equal = left_value <= right_value; - - if is_less_than_or_equal == comparator { - current_frame.ip += 1; - } - } - (TypeCode::STRING, TypeCode::STRING) => { - let left = instruction.b_field() as usize; - let left_is_constant = instruction.b_is_constant(); - let right = instruction.c_field() as usize; - let right_is_constant = instruction.c_is_constant(); - let comparator = instruction.d_field(); - - let left_value = if left_is_constant { - current_frame.get_string_constant(left) - } else { - current_frame.registers.strings.get(left).as_value() - }; - let right_value = if right_is_constant { - current_frame.get_string_constant(right) - } else { - current_frame.registers.strings.get(right).as_value() - }; - let is_less_than_or_equal = left_value <= right_value; - - if is_less_than_or_equal == comparator { - current_frame.ip += 1; - } - } - (TypeCode::LIST, TypeCode::LIST) => { - let left = instruction.b_field() as usize; - let right = instruction.c_field() as usize; - let comparator = instruction.d_field(); - - let left_value = current_frame.registers.lists.get(left).as_value(); - let right_value = current_frame.registers.lists.get(right).as_value(); - let is_less_than_or_equal = left_value <= right_value; - - if is_less_than_or_equal == comparator { - current_frame.ip += 1; - } - } - (TypeCode::FUNCTION, TypeCode::FUNCTION) => { - let left = instruction.b_field() as usize; - let right = instruction.c_field() as usize; - let comparator = instruction.d_field(); - - let left_value = current_frame.registers.functions.get(left).as_value(); - let right_value = current_frame.registers.functions.get(right).as_value(); - let is_less_than_or_equal = left_value <= right_value; - - if is_less_than_or_equal == comparator { - current_frame.ip += 1; - } - } - _ => unreachable!("Invalid LESS_EQUAL instruction"), - }, - Operation::TEST => { - let operand_register_index = instruction.b_field() as usize; - let test_value = instruction.c_field() != 0; - let operand_boolean = current_frame - .registers - .booleans - .get(operand_register_index) - .copy_value(); - - if operand_boolean == test_value { - current_frame.ip += 1; - } - } - Operation::JUMP => { - let offset = instruction.b_field() as usize; - let is_positive = instruction.c_field() != 0; - - if is_positive { - current_frame.ip += offset; - } else { - current_frame.ip -= offset + 1; - } - } - Operation::RETURN => { - let should_return_value = instruction.b_field() != 0; - let return_register = instruction.c_field() as usize; - let return_type = instruction.b_type(); - - if should_return_value { - match return_type { - TypeCode::BOOLEAN => { - let return_value = current_frame - .registers - .booleans - .get(return_register) - .copy_value(); - - return Some(Value::boolean(return_value)); - } - TypeCode::BYTE => { - let return_value = current_frame - .registers - .bytes - .get(return_register) - .copy_value(); - - return Some(Value::byte(return_value)); - } - TypeCode::CHARACTER => { - let return_value = current_frame - .registers - .characters - .get(return_register) - .copy_value(); - - return Some(Value::character(return_value)); - } - TypeCode::FLOAT => { - let return_value = current_frame - .registers - .floats - .get(return_register) - .copy_value(); - - return Some(Value::float(return_value)); - } - TypeCode::INTEGER => { - let return_value = current_frame - .registers - .integers - .get(return_register) - .copy_value(); - - return Some(Value::integer(return_value)); - } - TypeCode::STRING => { - let return_value = current_frame - .registers - .strings - .get(return_register) - .clone_value(); - - return Some(Value::string(return_value)); - } - TypeCode::LIST => { - let concrete_list = current_frame - .registers - .lists - .get(return_register) - .as_value() - .clone() - .to_concrete(&self); - - return Some(Value::Concrete(concrete_list)); - } - _ => unreachable!(), - } - } else { - return None; - } - } - unimplemented => { - todo!("{unimplemented} has not been implemented in the VM"); - } - } - } - - None - } - pub fn current_position(&self) -> Span { let current_frame = self.current_frame(); @@ -1465,4 +58,1496 @@ impl Thread { unsafe { self.call_stack.last_mut().unwrap_unchecked() } } } + + pub fn current_registers(&self) -> &RegisterTable { + if cfg!(debug_assertions) { + self.register_stack.last().unwrap() + } else { + unsafe { self.register_stack.last().unwrap_unchecked() } + } + } + + pub fn current_registers_mut(&mut self) -> &mut RegisterTable { + if cfg!(debug_assertions) { + self.register_stack.last_mut().unwrap() + } else { + unsafe { self.register_stack.last_mut().unwrap_unchecked() } + } + } + + pub fn run(mut self) -> Option { + info!( + "Starting thread {}", + self.chunk + .name + .clone() + .unwrap_or_else(|| DustString::from("anonymous")) + ); + + loop { + let current_frame = if cfg!(debug_assertions) { + self.call_stack.last_mut().unwrap() + } else { + unsafe { self.call_stack.last_mut().unwrap_unchecked() } + }; + let registers = if cfg!(debug_assertions) { + self.register_stack.last_mut().unwrap() + } else { + unsafe { self.register_stack.last_mut().unwrap_unchecked() } + }; + let instructions = ¤t_frame.chunk.instructions; + let ip = current_frame.ip; + current_frame.ip += 1; + + assert!(ip < instructions.len(), "IP out of bounds"); + + let instruction = instructions[ip]; + + info!("IP = {ip} Run {}", instruction.operation()); + + match instruction.operation() { + Operation::MOVE => { + let source = instruction.b_field() as usize; + let destination = instruction.a_field() as usize; + let source_type = instruction.b_type(); + + match source_type { + TypeCode::BOOLEAN => { + let value = registers.booleans.get(source).copy_value(); + + registers.booleans.get_mut(destination).set(value); + } + TypeCode::BYTE => { + let value = registers.bytes.get(source).copy_value(); + + registers.bytes.get_mut(destination).set(value); + } + TypeCode::CHARACTER => { + let value = registers.characters.get(source).copy_value(); + + registers.characters.get_mut(destination).set(value); + } + TypeCode::FLOAT => { + let value = registers.floats.get(source).copy_value(); + + registers.floats.get_mut(destination).set(value); + } + TypeCode::INTEGER => { + let value = registers.integers.get(source).copy_value(); + + registers.integers.get_mut(destination).set(value); + } + TypeCode::STRING => { + let value = registers.strings.get(source).clone_value(); + + registers.strings.get_mut(destination).set(value); + } + TypeCode::LIST => { + let value = registers.lists.get(source).clone_value(); + + registers.lists.get_mut(destination).set(value); + } + _ => todo!(), + } + } + Operation::CLOSE => { + let from = instruction.b_field() as usize; + let to = instruction.c_field() as usize; + let r#type = instruction.b_type(); + + match r#type { + TypeCode::BOOLEAN => { + let registers = registers.booleans.get_many_mut(from..=to); + + for register in registers { + register.close(); + } + } + TypeCode::BYTE => { + let registers = registers.bytes.get_many_mut(from..=to); + + for register in registers { + register.close(); + } + } + TypeCode::CHARACTER => { + let registers = registers.characters.get_many_mut(from..=to); + + for register in registers { + register.close(); + } + } + TypeCode::FLOAT => { + let registers = registers.floats.get_many_mut(from..=to); + + for register in registers { + register.close(); + } + } + TypeCode::INTEGER => { + let registers = registers.integers.get_many_mut(from..=to); + + for register in registers { + register.close(); + } + } + TypeCode::STRING => { + let registers = registers.strings.get_many_mut(from..=to); + + for register in registers { + register.close(); + } + } + TypeCode::LIST => { + let registers = registers.lists.get_many_mut(from..=to); + + for register in registers { + register.close(); + } + } + _ => unreachable!("Invalid CLOSE instruction"), + } + } + Operation::LOAD_ENCODED => { + let destination = instruction.a_field() as usize; + let value_type = instruction.b_type(); + let jump_next = instruction.c_field() != 0; + + match value_type { + TypeCode::BOOLEAN => { + let boolean = instruction.b_field() != 0; + + registers.booleans.set_to_new_register(destination, boolean); + } + TypeCode::BYTE => { + let byte = instruction.b_field() as u8; + + registers.bytes.set_to_new_register(destination, byte); + } + _ => unreachable!("Invalid LOAD_ENCODED instruction"), + } + + if jump_next { + current_frame.ip += 1; + } + } + Operation::LOAD_CONSTANT => { + let destination = instruction.a_field() as usize; + let constant_index = instruction.b_field() as usize; + let constant_type = instruction.b_type(); + let jump_next = instruction.c_field() != 0; + + match constant_type { + TypeCode::CHARACTER => { + let character = current_frame.get_character_constant(constant_index); + + registers.characters.get_mut(destination).set(character); + } + TypeCode::FLOAT => { + let float = current_frame.get_float_constant(constant_index); + + registers.floats.get_mut(destination).set(float); + } + TypeCode::INTEGER => { + let integer = current_frame.get_integer_constant(constant_index); + + registers.integers.get_mut(destination).set(integer); + } + TypeCode::STRING => { + let string = current_frame.get_string_constant(constant_index).clone(); + + registers.strings.get_mut(destination).set(string); + } + _ => unreachable!("Invalid LOAD_CONSTANT operation"), + } + + if jump_next { + current_frame.ip += 1; + } + } + Operation::LOAD_LIST => { + let destination = instruction.a_field() as usize; + let start_register = instruction.b_field() as usize; + let item_type = instruction.b_type(); + let end_register = instruction.c_field() as usize; + let jump_next = instruction.d_field(); + + let mut item_pointers = Vec::with_capacity(end_register - start_register + 1); + + match item_type { + TypeCode::BOOLEAN => { + for register_index in start_register..=end_register { + let register_is_closed = + registers.booleans.is_closed(register_index); + + if register_is_closed { + continue; + } + + item_pointers.push(Pointer::Register(register_index as u16)); + } + } + TypeCode::BYTE => { + for register_index in start_register..=end_register { + let register_is_closed = registers.bytes.is_closed(register_index); + + if register_is_closed { + continue; + } + + item_pointers.push(Pointer::Register(register_index as u16)); + } + } + TypeCode::CHARACTER => { + for register_index in start_register..=end_register { + let register_is_closed = + registers.characters.is_closed(register_index); + + if register_is_closed { + continue; + } + + item_pointers.push(Pointer::Register(register_index as u16)); + } + } + TypeCode::FLOAT => { + for register_index in start_register..=end_register { + let register_is_closed = registers.floats.is_closed(register_index); + + if register_is_closed { + continue; + } + + item_pointers.push(Pointer::Register(register_index as u16)); + } + } + TypeCode::INTEGER => { + for register_index in start_register..=end_register { + let register_is_closed = + registers.integers.is_closed(register_index); + + if register_is_closed { + continue; + } + + item_pointers.push(Pointer::Register(register_index as u16)); + } + } + TypeCode::STRING => { + for register_index in start_register..=end_register { + let register_is_closed = + registers.strings.is_closed(register_index); + + if register_is_closed { + continue; + } + + item_pointers.push(Pointer::Register(register_index as u16)); + } + } + TypeCode::LIST => { + for register_index in start_register..=end_register { + let register_is_closed = registers.lists.is_closed(register_index); + + if register_is_closed { + continue; + } + + item_pointers.push(Pointer::Register(register_index as u16)); + } + } + _ => unreachable!("Invalid LOAD_LIST instruction"), + } + + let list = AbstractList { + item_type, + item_pointers, + }; + + registers.lists.get_mut(destination).set(list); + + if jump_next { + current_frame.ip += 1; + } + } + Operation::LOAD_FUNCTION => { + let destination = instruction.a_field() as usize; + let prototype_index = instruction.b_field() as usize; + let jump_next = instruction.c_field() != 0; + let prototype = if cfg!(debug_assertions) { + current_frame.chunk.prototypes.get(prototype_index).unwrap() + } else { + unsafe { + current_frame + .chunk + .prototypes + .get_unchecked(prototype_index) + } + }; + let function = prototype.as_function(); + + registers + .functions + .set_to_new_register(destination, function); + + if jump_next { + current_frame.ip += 1; + } + } + Operation::LOAD_SELF => { + let destination = instruction.a_field() as usize; + let jump_next = instruction.c_field() != 0; + let self_function = current_frame.chunk.as_function(); + + registers + .functions + .set_to_new_register(destination, self_function); + + if jump_next { + current_frame.ip += 1; + } + } + Operation::ADD => match (instruction.b_type(), instruction.c_type()) { + (TypeCode::BYTE, TypeCode::BYTE) => { + let left_index = instruction.b_field() as usize; + let right_index = instruction.c_field() as usize; + let destination_index = instruction.a_field() as usize; + + let left_value = registers.bytes.get(left_index).copy_value(); + let right_value = registers.bytes.get(right_index).copy_value(); + let sum = left_value + right_value; + + registers.bytes.set_to_new_register(destination_index, sum); + } + (TypeCode::CHARACTER, TypeCode::CHARACTER) => { + let left_index = instruction.b_field() as usize; + let left_is_constant = instruction.b_is_constant(); + let right_index = instruction.c_field() as usize; + let right_is_constant = instruction.c_is_constant(); + let destination_index = instruction.a_field() as usize; + + let left_value = if left_is_constant { + current_frame.get_character_constant(left_index) + } else { + registers.characters.get(left_index).copy_value() + }; + let right_value = if right_is_constant { + current_frame.get_character_constant(right_index) + } else { + registers.characters.get(right_index).copy_value() + }; + let concatenated = { + let mut concatenated = DustString::from(String::with_capacity(2)); + + concatenated.push(left_value); + concatenated.push(right_value); + + concatenated + }; + + registers + .strings + .set_to_new_register(destination_index, concatenated); + } + (TypeCode::CHARACTER, TypeCode::STRING) => { + let left_index = instruction.b_field() as usize; + let left_is_constant = instruction.b_is_constant(); + let right_index = instruction.c_field() as usize; + let right_is_constant = instruction.c_is_constant(); + let destination_index = instruction.a_field() as usize; + + let left_value = if left_is_constant { + current_frame.get_character_constant(left_index) + } else { + registers.characters.get(left_index).copy_value() + }; + let right_value = if right_is_constant { + current_frame.get_string_constant(right_index) + } else { + registers.strings.get(right_index).as_value() + }; + let concatenated = DustString::from(format!("{left_value}{right_value}")); + + registers + .strings + .set_to_new_register(destination_index, concatenated); + } + (TypeCode::FLOAT, TypeCode::FLOAT) => { + let left_index = instruction.b_field() as usize; + let left_is_constant = instruction.b_is_constant(); + let right_index = instruction.c_field() as usize; + let right_is_constant = instruction.c_is_constant(); + let destination_index = instruction.a_field() as usize; + + let left_value = if left_is_constant { + current_frame.get_float_constant(left_index) + } else { + registers.floats.get(left_index).copy_value() + }; + let right_value = if right_is_constant { + current_frame.get_float_constant(right_index) + } else { + registers.floats.get(right_index).copy_value() + }; + let sum = left_value + right_value; + + registers.floats.set_to_new_register(destination_index, sum); + } + (TypeCode::INTEGER, TypeCode::INTEGER) => { + let left = instruction.b_field() as usize; + let left_is_constant = instruction.b_is_constant(); + let right = instruction.c_field() as usize; + let right_is_constant = instruction.c_is_constant(); + let destination_index = instruction.a_field() as usize; + + let left_value = if left_is_constant { + current_frame.get_integer_constant(left) + } else { + registers.integers.get(left).copy_value() + }; + let right_value = if right_is_constant { + current_frame.get_integer_constant(right) + } else { + registers.integers.get(right).copy_value() + }; + let sum = left_value + right_value; + + registers + .integers + .set_to_new_register(destination_index, sum); + } + (TypeCode::STRING, TypeCode::CHARACTER) => { + let left_index = instruction.b_field() as usize; + let left_is_constant = instruction.b_is_constant(); + let right_index = instruction.c_field() as usize; + let right_is_constant = instruction.c_is_constant(); + let destination_index = instruction.a_field() as usize; + + let left_value = if left_is_constant { + current_frame.get_string_constant(left_index) + } else { + registers.strings.get(left_index).as_value() + }; + let right_value = if right_is_constant { + current_frame.get_character_constant(right_index) + } else { + registers.characters.get(right_index).copy_value() + }; + let concatenated = DustString::from(format!("{left_value}{right_value}")); + + registers + .strings + .set_to_new_register(destination_index, concatenated); + } + (TypeCode::STRING, TypeCode::STRING) => { + let left = instruction.b_field() as usize; + let left_is_constant = instruction.b_is_constant(); + let right = instruction.c_field() as usize; + let right_is_constant = instruction.c_is_constant(); + let destination_index = instruction.a_field() as usize; + + let left_value = if left_is_constant { + current_frame.get_string_constant(left) + } else { + registers.strings.get(left).as_value() + }; + let right_value = if right_is_constant { + current_frame.get_string_constant(right) + } else { + registers.strings.get(right).as_value() + }; + let concatenated = DustString::from(format!("{left_value}{right_value}")); + + registers + .strings + .set_to_new_register(destination_index, concatenated); + } + _ => unreachable!("Invalid ADD instruction"), + }, + Operation::SUBTRACT => match (instruction.b_type(), instruction.c_type()) { + (TypeCode::BYTE, TypeCode::BYTE) => { + let left_index = instruction.b_field() as usize; + let right_index = instruction.c_field() as usize; + let destination_index = instruction.a_field() as usize; + + let left_value = registers.bytes.get(left_index).copy_value(); + let right_value = registers.bytes.get(right_index).copy_value(); + let difference = left_value - right_value; + + registers + .bytes + .set_to_new_register(destination_index, difference); + } + (TypeCode::FLOAT, TypeCode::FLOAT) => { + let left_index = instruction.b_field() as usize; + let left_is_constant = instruction.b_is_constant(); + let right_index = instruction.c_field() as usize; + let right_is_constant = instruction.c_is_constant(); + let destination_index = instruction.a_field() as usize; + + let left_value = if left_is_constant { + current_frame.get_float_constant(left_index) + } else { + registers.floats.get(left_index).copy_value() + }; + let right_value = if right_is_constant { + current_frame.get_float_constant(right_index) + } else { + registers.floats.get(right_index).copy_value() + }; + let difference = left_value - right_value; + + registers + .floats + .set_to_new_register(destination_index, difference); + } + (TypeCode::INTEGER, TypeCode::INTEGER) => { + let left = instruction.b_field() as usize; + let left_is_constant = instruction.b_is_constant(); + let right = instruction.c_field() as usize; + let right_is_constant = instruction.c_is_constant(); + let destination_index = instruction.a_field() as usize; + + let left_value = if left_is_constant { + current_frame.get_integer_constant(left) + } else { + registers.integers.get(left).copy_value() + }; + let right_value = if right_is_constant { + current_frame.get_integer_constant(right) + } else { + registers.integers.get(right).copy_value() + }; + let difference = left_value - right_value; + + registers + .integers + .set_to_new_register(destination_index, difference); + } + _ => unreachable!("Invalid SUBTRACT instruction"), + }, + Operation::MULTIPLY => match (instruction.b_type(), instruction.c_type()) { + (TypeCode::BYTE, TypeCode::BYTE) => { + let left_index = instruction.b_field() as usize; + let right_index = instruction.c_field() as usize; + let destination_index = instruction.a_field() as usize; + + let left_value = registers.bytes.get(left_index).copy_value(); + let right_value = registers.bytes.get(right_index).copy_value(); + let product = left_value * right_value; + + registers + .bytes + .set_to_new_register(destination_index, product); + } + (TypeCode::FLOAT, TypeCode::FLOAT) => { + let left_index = instruction.b_field() as usize; + let left_is_constant = instruction.b_is_constant(); + let right_index = instruction.c_field() as usize; + let right_is_constant = instruction.c_is_constant(); + let destination_index = instruction.a_field() as usize; + + let left_value = if left_is_constant { + current_frame.get_float_constant(left_index) + } else { + registers.floats.get(left_index).copy_value() + }; + let right_value = if right_is_constant { + current_frame.get_float_constant(right_index) + } else { + registers.floats.get(right_index).copy_value() + }; + let product = left_value * right_value; + + registers + .floats + .set_to_new_register(destination_index, product); + } + (TypeCode::INTEGER, TypeCode::INTEGER) => { + let left = instruction.b_field() as usize; + let left_is_constant = instruction.b_is_constant(); + let right = instruction.c_field() as usize; + let right_is_constant = instruction.c_is_constant(); + let destination_index = instruction.a_field() as usize; + + let left_value = if left_is_constant { + current_frame.get_integer_constant(left) + } else { + registers.integers.get(left).copy_value() + }; + let right_value = if right_is_constant { + current_frame.get_integer_constant(right) + } else { + registers.integers.get(right).copy_value() + }; + let product = left_value * right_value; + + registers + .integers + .set_to_new_register(destination_index, product); + } + _ => unreachable!("Invalid MULTIPLY instruction"), + }, + Operation::DIVIDE => match (instruction.b_type(), instruction.c_type()) { + (TypeCode::BYTE, TypeCode::BYTE) => { + let left_index = instruction.b_field() as usize; + let right_index = instruction.c_field() as usize; + let destination_index = instruction.a_field() as usize; + + let left_value = registers.bytes.get(left_index).copy_value(); + let right_value = registers.bytes.get(right_index).copy_value(); + let quotient = left_value / right_value; + + registers + .bytes + .set_to_new_register(destination_index, quotient); + } + (TypeCode::FLOAT, TypeCode::FLOAT) => { + let left_index = instruction.b_field() as usize; + let left_is_constant = instruction.b_is_constant(); + let right_index = instruction.c_field() as usize; + let right_is_constant = instruction.c_is_constant(); + let destination_index = instruction.a_field() as usize; + + let left_value = if left_is_constant { + current_frame.get_float_constant(left_index) + } else { + registers.floats.get(left_index).copy_value() + }; + let right_value = if right_is_constant { + current_frame.get_float_constant(right_index) + } else { + registers.floats.get(right_index).copy_value() + }; + let quotient = left_value / right_value; + + registers + .floats + .set_to_new_register(destination_index, quotient); + } + (TypeCode::INTEGER, TypeCode::INTEGER) => { + let left = instruction.b_field() as usize; + let left_is_constant = instruction.b_is_constant(); + let right = instruction.c_field() as usize; + let right_is_constant = instruction.c_is_constant(); + let destination_index = instruction.a_field() as usize; + + let left_value = if left_is_constant { + current_frame.get_integer_constant(left) + } else { + registers.integers.get(left).copy_value() + }; + let right_value = if right_is_constant { + current_frame.get_integer_constant(right) + } else { + registers.integers.get(right).copy_value() + }; + let quotient = left_value / right_value; + + registers + .integers + .set_to_new_register(destination_index, quotient); + } + _ => unreachable!("Invalid DIVIDE instruction"), + }, + Operation::MODULO => match (instruction.b_type(), instruction.c_type()) { + (TypeCode::BYTE, TypeCode::BYTE) => { + let left_index = instruction.b_field() as usize; + let right_index = instruction.c_field() as usize; + let destination_index = instruction.a_field() as usize; + + let left_value = registers.bytes.get(left_index).copy_value(); + let right_value = registers.bytes.get(right_index).copy_value(); + let remainder = left_value % right_value; + + registers + .bytes + .set_to_new_register(destination_index, remainder); + } + (TypeCode::FLOAT, TypeCode::FLOAT) => { + let left_index = instruction.b_field() as usize; + let left_is_constant = instruction.b_is_constant(); + let right_index = instruction.c_field() as usize; + let right_is_constant = instruction.c_is_constant(); + let destination_index = instruction.a_field() as usize; + + let left_value = if left_is_constant { + current_frame.get_float_constant(left_index) + } else { + registers.floats.get(left_index).copy_value() + }; + let right_value = if right_is_constant { + current_frame.get_float_constant(right_index) + } else { + registers.floats.get(right_index).copy_value() + }; + let remainder = left_value % right_value; + + registers + .floats + .set_to_new_register(destination_index, remainder); + } + (TypeCode::INTEGER, TypeCode::INTEGER) => { + let left = instruction.b_field() as usize; + let left_is_constant = instruction.b_is_constant(); + let right = instruction.c_field() as usize; + let right_is_constant = instruction.c_is_constant(); + let destination_index = instruction.a_field() as usize; + + let left_value = if left_is_constant { + current_frame.get_integer_constant(left) + } else { + registers.integers.get(left).copy_value() + }; + let right_value = if right_is_constant { + current_frame.get_integer_constant(right) + } else { + registers.integers.get(right).copy_value() + }; + let remainder = left_value % right_value; + + registers + .integers + .set_to_new_register(destination_index, remainder); + } + _ => unreachable!("Invalid MODULO instruction"), + }, + Operation::EQUAL => match (instruction.b_type(), instruction.c_type()) { + (TypeCode::BOOLEAN, TypeCode::BOOLEAN) => { + let left_index = instruction.b_field() as usize; + let right_index = instruction.c_field() as usize; + let comparator = instruction.d_field(); + + let left_value = registers.booleans.get(left_index).copy_value(); + let right_value = registers.booleans.get(right_index).copy_value(); + + // See for more info. + let is_equal = matches!((left_value as i8) - (right_value as i8), 0); + + if is_equal == comparator { + current_frame.ip += 1; + } + } + (TypeCode::BYTE, TypeCode::BYTE) => { + let left = instruction.b_field() as usize; + let right = instruction.c_field() as usize; + let comparator = instruction.d_field(); + + let left_value = registers.bytes.get(left).copy_value(); + let right_value = registers.bytes.get(right).copy_value(); + let is_equal = left_value == right_value; + + if is_equal == comparator { + current_frame.ip += 1; + } + } + (TypeCode::CHARACTER, TypeCode::CHARACTER) => { + let left = instruction.b_field() as usize; + let left_is_constant = instruction.b_is_constant(); + let right = instruction.c_field() as usize; + let right_is_constant = instruction.c_is_constant(); + let comparator = instruction.d_field(); + + let left_value = if left_is_constant { + current_frame.get_character_constant(left) + } else { + registers.characters.get(left).copy_value() + }; + let right_value = if right_is_constant { + current_frame.get_character_constant(right) + } else { + registers.characters.get(right).copy_value() + }; + let is_equal = left_value == right_value; + + if is_equal == comparator { + current_frame.ip += 1; + } + } + (TypeCode::FLOAT, TypeCode::FLOAT) => { + let left = instruction.b_field() as usize; + let left_is_constant = instruction.b_is_constant(); + let right = instruction.c_field() as usize; + let right_is_constant = instruction.c_is_constant(); + let comparator = instruction.d_field(); + + let left_value = if left_is_constant { + current_frame.get_float_constant(left) + } else { + registers.floats.get(left).copy_value() + }; + let right_value = if right_is_constant { + current_frame.get_float_constant(right) + } else { + registers.floats.get(right).copy_value() + }; + let is_equal = left_value == right_value; + + if is_equal == comparator { + current_frame.ip += 1; + } + } + (TypeCode::INTEGER, TypeCode::INTEGER) => { + let left = instruction.b_field() as usize; + let left_is_constant = instruction.b_is_constant(); + let right = instruction.c_field() as usize; + let right_is_constant = instruction.c_is_constant(); + let comparator = instruction.d_field(); + + let left_value = if left_is_constant { + current_frame.get_integer_constant(left) + } else { + registers.integers.get(left).copy_value() + }; + let right_value = if right_is_constant { + current_frame.get_integer_constant(right) + } else { + registers.integers.get(right).copy_value() + }; + let is_equal = left_value == right_value; + + if is_equal == comparator { + current_frame.ip += 1; + } + } + (TypeCode::STRING, TypeCode::STRING) => { + let left = instruction.b_field() as usize; + let left_is_constant = instruction.b_is_constant(); + let right = instruction.c_field() as usize; + let right_is_constant = instruction.c_is_constant(); + let comparator = instruction.d_field(); + + let left_value = if left_is_constant { + current_frame.get_string_constant(left) + } else { + registers.strings.get(left).as_value() + }; + let right_value = if right_is_constant { + current_frame.get_string_constant(right) + } else { + registers.strings.get(right).as_value() + }; + let is_equal = left_value == right_value; + + if is_equal == comparator { + current_frame.ip += 1; + } + } + (TypeCode::LIST, TypeCode::LIST) => { + let left = instruction.b_field() as usize; + let right = instruction.c_field() as usize; + let comparator = instruction.d_field(); + + let left_value = registers.lists.get(left).as_value(); + let right_value = registers.lists.get(right).as_value(); + let is_equal = left_value == right_value; + + if is_equal == comparator { + current_frame.ip += 1; + } + } + (TypeCode::FUNCTION, TypeCode::FUNCTION) => { + let left = instruction.b_field() as usize; + let right = instruction.c_field() as usize; + let comparator = instruction.d_field(); + + let left_value = registers.functions.get(left).as_value(); + let right_value = registers.functions.get(right).as_value(); + let is_equal = left_value == right_value; + + if is_equal == comparator { + current_frame.ip += 1; + } + } + _ => unreachable!("Invalid EQUAL instruction"), + }, + Operation::LESS => match (instruction.b_type(), instruction.c_type()) { + (TypeCode::BOOLEAN, TypeCode::BOOLEAN) => { + let left_index = instruction.b_field() as usize; + let right_index = instruction.c_field() as usize; + let comparator = instruction.d_field(); + + let left_value = registers.booleans.get(left_index).copy_value(); + let right_value = registers.booleans.get(right_index).copy_value(); + + // See for more info. + let is_less_than = matches!((left_value as i8) - (right_value as i8), -1); + + if is_less_than == comparator { + current_frame.ip += 1; + } + } + (TypeCode::BYTE, TypeCode::BYTE) => { + let left = instruction.b_field() as usize; + let right = instruction.c_field() as usize; + let comparator = instruction.d_field(); + + let left_value = registers.bytes.get(left).copy_value(); + let right_value = registers.bytes.get(right).copy_value(); + let is_less_than = left_value < right_value; + + if is_less_than == comparator { + current_frame.ip += 1; + } + } + (TypeCode::CHARACTER, TypeCode::CHARACTER) => { + let left = instruction.b_field() as usize; + let left_is_constant = instruction.b_is_constant(); + let right = instruction.c_field() as usize; + let right_is_constant = instruction.c_is_constant(); + let comparator = instruction.d_field(); + + let left_value = if left_is_constant { + current_frame.get_character_constant(left) + } else { + registers.characters.get(left).copy_value() + }; + let right_value = if right_is_constant { + current_frame.get_character_constant(right) + } else { + registers.characters.get(right).copy_value() + }; + let is_less_than = left_value < right_value; + + if is_less_than == comparator { + current_frame.ip += 1; + } + } + (TypeCode::FLOAT, TypeCode::FLOAT) => { + let left = instruction.b_field() as usize; + let left_is_constant = instruction.b_is_constant(); + let right = instruction.c_field() as usize; + let right_is_constant = instruction.c_is_constant(); + let comparator = instruction.d_field(); + + let left_value = if left_is_constant { + current_frame.get_float_constant(left) + } else { + registers.floats.get(left).copy_value() + }; + let right_value = if right_is_constant { + current_frame.get_float_constant(right) + } else { + registers.floats.get(right).copy_value() + }; + let is_less_than = left_value < right_value; + + if is_less_than == comparator { + current_frame.ip += 1; + } + } + (TypeCode::INTEGER, TypeCode::INTEGER) => { + let left = instruction.b_field() as usize; + let left_is_constant = instruction.b_is_constant(); + let right = instruction.c_field() as usize; + let right_is_constant = instruction.c_is_constant(); + let comparator = instruction.d_field(); + + let left_value = if left_is_constant { + current_frame.get_integer_constant(left) + } else { + registers.integers.get(left).copy_value() + }; + let right_value = if right_is_constant { + current_frame.get_integer_constant(right) + } else { + registers.integers.get(right).copy_value() + }; + let is_less_than = left_value < right_value; + + if is_less_than == comparator { + current_frame.ip += 1; + } + } + (TypeCode::STRING, TypeCode::STRING) => { + let left = instruction.b_field() as usize; + let left_is_constant = instruction.b_is_constant(); + let right = instruction.c_field() as usize; + let right_is_constant = instruction.c_is_constant(); + let comparator = instruction.d_field(); + + let left_value = if left_is_constant { + current_frame.get_string_constant(left) + } else { + registers.strings.get(left).as_value() + }; + let right_value = if right_is_constant { + current_frame.get_string_constant(right) + } else { + registers.strings.get(right).as_value() + }; + let is_less_than = left_value < right_value; + + if is_less_than == comparator { + current_frame.ip += 1; + } + } + (TypeCode::LIST, TypeCode::LIST) => { + let left = instruction.b_field() as usize; + let right = instruction.c_field() as usize; + let comparator = instruction.d_field(); + + let left_value = registers.lists.get(left).as_value(); + let right_value = registers.lists.get(right).as_value(); + let is_less_than = left_value < right_value; + + if is_less_than == comparator { + current_frame.ip += 1; + } + } + (TypeCode::FUNCTION, TypeCode::FUNCTION) => { + let left = instruction.b_field() as usize; + let right = instruction.c_field() as usize; + let comparator = instruction.d_field(); + + let left_value = registers.functions.get(left).as_value(); + let right_value = registers.functions.get(right).as_value(); + let is_less_than = left_value < right_value; + + if is_less_than == comparator { + current_frame.ip += 1; + } + } + _ => unreachable!("Invalid LESS instruction"), + }, + Operation::LESS_EQUAL => match (instruction.b_type(), instruction.c_type()) { + (TypeCode::BOOLEAN, TypeCode::BOOLEAN) => { + let left_index = instruction.b_field() as usize; + let right_index = instruction.c_field() as usize; + let comparator = instruction.d_field(); + + let left_value = registers.booleans.get(left_index).copy_value(); + let right_value = registers.booleans.get(right_index).copy_value(); + + // See for more info. + let is_less_than_or_equal = + matches!(left_value as i8 - right_value as i8, -1 | 0); + + if is_less_than_or_equal == comparator { + current_frame.ip += 1; + } + } + (TypeCode::BYTE, TypeCode::BYTE) => { + let left = instruction.b_field() as usize; + let right = instruction.c_field() as usize; + let comparator = instruction.d_field(); + + let left_value = registers.bytes.get(left).copy_value(); + let right_value = registers.bytes.get(right).copy_value(); + let is_less_than_or_equal = left_value <= right_value; + + if is_less_than_or_equal == comparator { + current_frame.ip += 1; + } + } + (TypeCode::CHARACTER, TypeCode::CHARACTER) => { + let left = instruction.b_field() as usize; + let left_is_constant = instruction.b_is_constant(); + let right = instruction.c_field() as usize; + let right_is_constant = instruction.c_is_constant(); + let comparator = instruction.d_field(); + + let left_value = if left_is_constant { + current_frame.get_character_constant(left) + } else { + registers.characters.get(left).copy_value() + }; + let right_value = if right_is_constant { + current_frame.get_character_constant(right) + } else { + registers.characters.get(right).copy_value() + }; + let is_less_than_or_equal = left_value <= right_value; + + if is_less_than_or_equal == comparator { + current_frame.ip += 1; + } + } + (TypeCode::FLOAT, TypeCode::FLOAT) => { + let left = instruction.b_field() as usize; + let left_is_constant = instruction.b_is_constant(); + let right = instruction.c_field() as usize; + let right_is_constant = instruction.c_is_constant(); + let comparator = instruction.d_field(); + + let left_value = if left_is_constant { + current_frame.get_float_constant(left) + } else { + registers.floats.get(left).copy_value() + }; + let right_value = if right_is_constant { + current_frame.get_float_constant(right) + } else { + registers.floats.get(right).copy_value() + }; + let is_less_than_or_equal = left_value <= right_value; + + if is_less_than_or_equal == comparator { + current_frame.ip += 1; + } + } + (TypeCode::INTEGER, TypeCode::INTEGER) => { + let left = instruction.b_field() as usize; + let left_is_constant = instruction.b_is_constant(); + let right = instruction.c_field() as usize; + let right_is_constant = instruction.c_is_constant(); + let comparator = instruction.d_field(); + + let left_value = if left_is_constant { + current_frame.get_integer_constant(left) + } else { + registers.integers.get(left).copy_value() + }; + let right_value = if right_is_constant { + current_frame.get_integer_constant(right) + } else { + registers.integers.get(right).copy_value() + }; + let is_less_than_or_equal = left_value <= right_value; + + if is_less_than_or_equal == comparator { + current_frame.ip += 1; + } + } + (TypeCode::STRING, TypeCode::STRING) => { + let left = instruction.b_field() as usize; + let left_is_constant = instruction.b_is_constant(); + let right = instruction.c_field() as usize; + let right_is_constant = instruction.c_is_constant(); + let comparator = instruction.d_field(); + + let left_value = if left_is_constant { + current_frame.get_string_constant(left) + } else { + registers.strings.get(left).as_value() + }; + let right_value = if right_is_constant { + current_frame.get_string_constant(right) + } else { + registers.strings.get(right).as_value() + }; + let is_less_than_or_equal = left_value <= right_value; + + if is_less_than_or_equal == comparator { + current_frame.ip += 1; + } + } + (TypeCode::LIST, TypeCode::LIST) => { + let left = instruction.b_field() as usize; + let right = instruction.c_field() as usize; + let comparator = instruction.d_field(); + + let left_value = registers.lists.get(left).as_value(); + let right_value = registers.lists.get(right).as_value(); + let is_less_than_or_equal = left_value <= right_value; + + if is_less_than_or_equal == comparator { + current_frame.ip += 1; + } + } + (TypeCode::FUNCTION, TypeCode::FUNCTION) => { + let left = instruction.b_field() as usize; + let right = instruction.c_field() as usize; + let comparator = instruction.d_field(); + + let left_value = registers.functions.get(left).as_value(); + let right_value = registers.functions.get(right).as_value(); + let is_less_than_or_equal = left_value <= right_value; + + if is_less_than_or_equal == comparator { + current_frame.ip += 1; + } + } + _ => unreachable!("Invalid LESS_EQUAL instruction"), + }, + Operation::TEST => { + let operand_register_index = instruction.b_field() as usize; + let test_value = instruction.c_field() != 0; + let operand_boolean = + registers.booleans.get(operand_register_index).copy_value(); + + if operand_boolean == test_value { + current_frame.ip += 1; + } + } + Operation::CALL => { + let destination = instruction.a_field(); + let function_register = instruction.b_field(); + let argument_list_register = instruction.c_field(); + + let function = registers + .functions + .get(function_register as usize) + .as_value(); + let function_prototype = current_frame + .chunk + .prototypes + .get(function.prototype_index as usize) + .unwrap(); + let argument_list = current_frame + .chunk + .argument_lists + .get(argument_list_register as usize) + .unwrap(); + let call_frame = CallFrame { + chunk: Arc::clone(function_prototype), + ip: 0, + return_register: destination, + }; + let mut new_registers = RegisterTable::new(function_prototype); + + for (r#type, register_index) in function + .r#type + .value_parameters + .iter() + .zip(argument_list.iter()) + { + let register_index = *register_index as usize; + + match r#type { + Type::Boolean => { + let boolean = *registers.booleans.get(register_index).as_value(); + + *new_registers + .booleans + .get_mut(register_index) + .as_value_mut() = boolean; + } + Type::Integer => { + let integer = *registers.integers.get(register_index).as_value(); + + *new_registers + .integers + .get_mut(register_index) + .as_value_mut() = integer; + } + Type::String => { + let string = + registers.strings.get(register_index).as_value().clone(); + + *new_registers.strings.get_mut(register_index).as_value_mut() = + string; + } + _ => unreachable!(), + } + } + + self.call_stack.push(call_frame); + self.register_stack.push(new_registers); + + trace!( + "Call Stack: [{}]", + self.call_stack + .iter() + .map(|call_frame| format!( + "{}:{} ", + call_frame + .chunk + .name + .clone() + .unwrap_or_else(|| DustString::from("anonymous")), + call_frame.ip + )) + .collect::() + ); + } + Operation::JUMP => { + let offset = instruction.b_field() as usize; + let is_positive = instruction.c_field() != 0; + + if is_positive { + current_frame.ip += offset; + } else { + current_frame.ip -= offset + 1; + } + } + Operation::RETURN => { + let should_return_value = instruction.b_field() != 0; + let return_register = instruction.c_field() as usize; + let return_type = instruction.b_type(); + + if self.call_stack.len() == 1 { + if should_return_value { + match return_type { + TypeCode::BOOLEAN => { + let return_value = + registers.booleans.get(return_register).copy_value(); + + return Some(Value::boolean(return_value)); + } + TypeCode::BYTE => { + let return_value = + registers.bytes.get(return_register).copy_value(); + + return Some(Value::byte(return_value)); + } + TypeCode::CHARACTER => { + let return_value = + registers.characters.get(return_register).copy_value(); + + return Some(Value::character(return_value)); + } + TypeCode::FLOAT => { + let return_value = + registers.floats.get(return_register).copy_value(); + + return Some(Value::float(return_value)); + } + TypeCode::INTEGER => { + let return_value = + registers.integers.get(return_register).copy_value(); + + return Some(Value::integer(return_value)); + } + TypeCode::STRING => { + let return_value = + registers.strings.get(return_register).clone_value(); + + return Some(Value::string(return_value)); + } + TypeCode::LIST => { + let concrete_list = registers + .lists + .get(return_register) + .as_value() + .clone() + .to_concrete(&self); + + return Some(Value::Concrete(concrete_list)); + } + TypeCode::FUNCTION => { + let return_value = + registers.functions.get(return_register).clone_value(); + + return Some(Value::Function(return_value)); + } + _ => unreachable!(), + } + } else { + return None; + } + } else if should_return_value { + match return_type { + TypeCode::BOOLEAN => { + let return_value = + registers.booleans.get(return_register).copy_value(); + let return_register = + self.call_stack.last().unwrap().return_register as usize; + + self.call_stack.pop(); + self.register_stack.pop(); + + let registers = self.register_stack.last_mut().unwrap(); + + *registers.booleans.get_mut(return_register).as_value_mut() = + return_value; + } + TypeCode::BYTE => { + let return_value = + registers.bytes.get(return_register).copy_value(); + let return_register = + self.call_stack.last().unwrap().return_register as usize; + + self.call_stack.pop(); + self.register_stack.pop(); + + let registers = self.register_stack.last_mut().unwrap(); + + *registers.bytes.get_mut(return_register).as_value_mut() = + return_value; + } + TypeCode::CHARACTER => { + let return_value = + registers.characters.get(return_register).copy_value(); + let return_register = + self.call_stack.last().unwrap().return_register as usize; + + self.call_stack.pop(); + self.register_stack.pop(); + + let registers = self.register_stack.last_mut().unwrap(); + + *registers.characters.get_mut(return_register).as_value_mut() = + return_value; + } + TypeCode::FLOAT => { + let return_value = + registers.floats.get(return_register).copy_value(); + let return_register = + self.call_stack.last().unwrap().return_register as usize; + + self.call_stack.pop(); + self.register_stack.pop(); + + let registers = self.register_stack.last_mut().unwrap(); + + *registers.floats.get_mut(return_register).as_value_mut() = + return_value; + } + TypeCode::INTEGER => { + let return_value = + registers.integers.get(return_register).copy_value(); + let return_register = + self.call_stack.last().unwrap().return_register as usize; + + self.call_stack.pop(); + self.register_stack.pop(); + + let registers = self.register_stack.last_mut().unwrap(); + + *registers.integers.get_mut(return_register).as_value_mut() = + return_value; + } + TypeCode::STRING => { + let return_value = + registers.strings.get(return_register).clone_value(); + let return_register = + self.call_stack.last().unwrap().return_register as usize; + + self.call_stack.pop(); + self.register_stack.pop(); + + let registers = self.register_stack.last_mut().unwrap(); + + *registers.strings.get_mut(return_register).as_value_mut() = + return_value; + } + TypeCode::LIST => { + let return_value = + registers.lists.get(return_register).as_value().clone(); + let return_register = + self.call_stack.last().unwrap().return_register as usize; + + self.call_stack.pop(); + self.register_stack.pop(); + + let registers = self.register_stack.last_mut().unwrap(); + + *registers.lists.get_mut(return_register).as_value_mut() = + return_value; + } + TypeCode::FUNCTION => { + let return_value = + registers.functions.get(return_register).clone_value(); + let return_register = + self.call_stack.last().unwrap().return_register as usize; + + self.call_stack.pop(); + self.register_stack.pop(); + + let registers = self.register_stack.last_mut().unwrap(); + + *registers.functions.get_mut(return_register).as_value_mut() = + return_value; + } + _ => unreachable!(), + } + } + } + unimplemented => { + todo!("{unimplemented} has not been implemented in the VM"); + } + } + } + } } diff --git a/dust-lang/tests/compiler_errors/assignment_errors.rs b/dust-lang/tests/compiler_errors/assignment_errors.rs index a117612..4d2844e 100644 --- a/dust-lang/tests/compiler_errors/assignment_errors.rs +++ b/dust-lang/tests/compiler_errors/assignment_errors.rs @@ -6,7 +6,7 @@ fn add_assign_expects_mutable_variable() { assert_eq!( compile(source), - Err(DustError::Compile { + Err(DustError { error: CompileError::ExpectedMutableVariable { found: Token::Integer("1").to_owned(), position: Span(0, 1) @@ -22,7 +22,7 @@ fn divide_assign_expects_mutable_variable() { assert_eq!( compile(source), - Err(DustError::Compile { + Err(DustError { error: CompileError::ExpectedMutableVariable { found: Token::Integer("1").to_owned(), position: Span(0, 1) @@ -38,7 +38,7 @@ fn multiply_assign_expects_mutable_variable() { assert_eq!( compile(source), - Err(DustError::Compile { + Err(DustError { error: CompileError::ExpectedMutableVariable { found: Token::Integer("1").to_owned(), position: Span(0, 1) @@ -54,7 +54,7 @@ fn subtract_assign_expects_mutable_variable() { assert_eq!( compile(source), - Err(DustError::Compile { + Err(DustError { error: CompileError::ExpectedMutableVariable { found: Token::Integer("1").to_owned(), position: Span(0, 1) @@ -70,7 +70,7 @@ fn modulo_assign_expects_mutable_variable() { assert_eq!( compile(source), - Err(DustError::Compile { + Err(DustError { error: CompileError::ExpectedMutableVariable { found: Token::Integer("1").to_owned(), position: Span(0, 1)