From 302bc9ce6ce26904f7237ee73af15db8ce2c5907 Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 15 Nov 2024 19:18:00 -0500 Subject: [PATCH] Continue Value/VM overhaul --- dust-lang/src/chunk.rs | 20 +- dust-lang/src/compiler.rs | 26 +- dust-lang/src/disassembler.rs | 7 +- dust-lang/src/function.rs | 63 -- dust-lang/src/lib.rs | 4 +- dust-lang/src/native_function/logic.rs | 56 +- dust-lang/src/native_function/mod.rs | 7 +- dust-lang/src/value.rs | 983 ------------------------- dust-lang/src/value/mod.rs | 347 +++++++++ dust-lang/src/value/range.rs | 154 ++++ dust-lang/src/vm.rs | 566 +++++++------- 11 files changed, 809 insertions(+), 1424 deletions(-) delete mode 100644 dust-lang/src/function.rs delete mode 100644 dust-lang/src/value.rs create mode 100644 dust-lang/src/value/mod.rs create mode 100644 dust-lang/src/value/range.rs diff --git a/dust-lang/src/chunk.rs b/dust-lang/src/chunk.rs index e0bfb70..014a093 100644 --- a/dust-lang/src/chunk.rs +++ b/dust-lang/src/chunk.rs @@ -8,18 +8,18 @@ use std::fmt::{self, Debug, Display, Formatter}; use serde::{Deserialize, Serialize}; -use crate::{value::ConcreteValue, Disassembler, FunctionType, Instruction, Scope, Span, Type}; +use crate::{value::Value, Disassembler, FunctionType, Instruction, Scope, Span, Type}; /// In-memory representation of a Dust program or function. /// /// See the [module-level documentation](index.html) for more information. -#[derive(Clone, PartialOrd, Ord, Serialize, Deserialize)] +#[derive(Clone, PartialOrd, Serialize, Deserialize)] pub struct Chunk { - name: Option, // TODO: Use a bool indicating whether the chunk is named. If it is, get - r#type: FunctionType, // the name from C0. + name: Option, + r#type: FunctionType, instructions: Vec<(Instruction, Span)>, - constants: Vec, + constants: Vec, locals: Vec, } @@ -41,7 +41,7 @@ impl Chunk { pub fn with_data( name: Option, instructions: Vec<(Instruction, Span)>, - constants: Vec, + constants: Vec, locals: Vec, ) -> Self { Self { @@ -77,15 +77,15 @@ impl Chunk { self.instructions.is_empty() } - pub fn constants(&self) -> &Vec { + pub fn constants(&self) -> &Vec { &self.constants } - pub fn constants_mut(&mut self) -> &mut Vec { + pub fn constants_mut(&mut self) -> &mut Vec { &mut self.constants } - pub fn get_constant(&self, index: u8) -> Result<&ConcreteValue, ChunkError> { + pub fn get_constant(&self, index: u8) -> Result<&Value, ChunkError> { self.constants .get(index as usize) .ok_or(ChunkError::ConstantIndexOutOfBounds { @@ -93,7 +93,7 @@ impl Chunk { }) } - pub fn push_or_get_constant(&mut self, value: ConcreteValue) -> u8 { + pub fn push_or_get_constant(&mut self, value: Value) -> u8 { if let Some(index) = self .constants .iter() diff --git a/dust-lang/src/compiler.rs b/dust-lang/src/compiler.rs index ef0a4a0..b93efcb 100644 --- a/dust-lang/src/compiler.rs +++ b/dust-lang/src/compiler.rs @@ -13,7 +13,7 @@ use std::{ use colored::Colorize; use crate::{ - value::ConcreteValue, AnnotatedError, Chunk, ChunkError, DustError, FunctionType, Instruction, + value::Value, AnnotatedError, Chunk, ChunkError, DustError, FunctionType, Instruction, LexError, Lexer, Local, NativeFunction, Operation, Optimizer, Scope, Span, Token, TokenKind, TokenOwned, Type, TypeConflict, }; @@ -44,7 +44,7 @@ pub fn compile(source: &str) -> Result { /// Low-level tool for compiling the input a token at a time while assembling a chunk. /// /// See the [`compile`] function an example of how to create and use a Compiler. -#[derive(Debug, Eq, PartialEq, PartialOrd, Ord)] +#[derive(Debug, Eq, PartialEq, PartialOrd)] pub struct Compiler<'src> { chunk: Chunk, lexer: Lexer<'src>, @@ -158,7 +158,7 @@ impl<'src> Compiler<'src> { .chunk .constants() .get(local.identifier_index as usize)?; - let identifier = if let ConcreteValue::String(identifier) = constant { + let identifier = if let Value::String(identifier) = constant { identifier } else { return None; @@ -186,7 +186,7 @@ impl<'src> Compiler<'src> { ) -> (u8, u8) { log::debug!("Declare local {identifier}"); - let identifier = ConcreteValue::string(identifier); + let identifier = Value::string(identifier); let identifier_index = self.chunk.push_or_get_constant(identifier); self.chunk @@ -368,11 +368,7 @@ impl<'src> Compiler<'src> { self.chunk.instructions_mut().push((instruction, position)); } - fn emit_constant( - &mut self, - constant: ConcreteValue, - position: Span, - ) -> Result<(), CompileError> { + fn emit_constant(&mut self, constant: Value, position: Span) -> Result<(), CompileError> { let constant_index = self.chunk.push_or_get_constant(constant); let register = self.next_register(); @@ -418,7 +414,7 @@ impl<'src> Compiler<'src> { let byte = u8::from_str_radix(&text[2..], 16) .map_err(|error| CompileError::ParseIntError { error, position })?; - let value = ConcreteValue::byte(byte); + let value = Value::byte(byte); self.emit_constant(value, position)?; @@ -440,7 +436,7 @@ impl<'src> Compiler<'src> { if let Token::Character(character) = self.current_token { self.advance()?; - let value = ConcreteValue::character(character); + let value = Value::character(character); self.emit_constant(value, position)?; @@ -468,7 +464,7 @@ impl<'src> Compiler<'src> { error, position: self.previous_position, })?; - let value = ConcreteValue::float(float); + let value = Value::float(float); self.emit_constant(value, position)?; @@ -496,7 +492,7 @@ impl<'src> Compiler<'src> { error, position: self.previous_position, })?; - let value = ConcreteValue::integer(integer); + let value = Value::integer(integer); self.emit_constant(value, position)?; @@ -518,7 +514,7 @@ impl<'src> Compiler<'src> { if let Token::String(text) = self.current_token { self.advance()?; - let value = ConcreteValue::string(text); + let value = Value::string(text); self.emit_constant(value, position)?; @@ -1476,7 +1472,7 @@ impl<'src> Compiler<'src> { value_parameters, return_type, }; - let function = ConcreteValue::function(function_compiler.finish()); + let function = Value::function(function_compiler.finish()); let constant_index = self.chunk.push_or_get_constant(function); let function_end = self.current_position.1; let register = self.next_register(); diff --git a/dust-lang/src/disassembler.rs b/dust-lang/src/disassembler.rs index 0ecd8d5..b76aeb7 100644 --- a/dust-lang/src/disassembler.rs +++ b/dust-lang/src/disassembler.rs @@ -45,7 +45,7 @@ use std::env::current_exe; use colored::Colorize; -use crate::{value::ConcreteValue, Chunk, Local}; +use crate::{value::Value, Chunk, Local}; const INSTRUCTION_HEADER: [&str; 4] = [ "Instructions", @@ -313,9 +313,8 @@ impl<'a> Disassembler<'a> { } for (index, value) in self.chunk.constants().iter().enumerate() { - if let ConcreteValue::Function(function) = value { - let function_disassembly = function - .chunk() + if let Value::Function(chunk) = value { + let function_disassembly = chunk .disassembler() .styled(self.styled) .indent(self.indent + 1) diff --git a/dust-lang/src/function.rs b/dust-lang/src/function.rs deleted file mode 100644 index 44ad368..0000000 --- a/dust-lang/src/function.rs +++ /dev/null @@ -1,63 +0,0 @@ -use std::fmt::{self, Display, Formatter}; - -use serde::{Deserialize, Serialize}; - -use crate::{Chunk, Type}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct Function { - chunk: Chunk, -} - -impl Function { - pub fn new(chunk: Chunk) -> Self { - Self { chunk } - } - - pub fn chunk(&self) -> &Chunk { - &self.chunk - } - - pub fn r#type(&self) -> Type { - Type::Function(self.chunk.r#type().clone()) - } - - pub fn as_borrowed(&self) -> FunctionBorrowed { - FunctionBorrowed::new(&self.chunk) - } -} - -impl Display for Function { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{}", self.chunk.r#type()) - } -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] -pub struct FunctionBorrowed<'a> { - chunk: &'a Chunk, -} - -impl<'a> FunctionBorrowed<'a> { - pub fn new(chunk: &'a Chunk) -> Self { - Self { chunk } - } - - pub fn chunk(&self) -> &Chunk { - self.chunk - } - - pub fn r#type(&self) -> Type { - Type::Function(self.chunk.r#type().clone()) - } - - pub fn to_owned(&self) -> Function { - Function::new(self.chunk.clone()) - } -} - -impl<'a> Display for FunctionBorrowed<'a> { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{}", self.chunk.r#type()) - } -} diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index 8d04f93..e87115c 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -5,7 +5,6 @@ pub mod compiler; pub mod disassembler; pub mod dust_error; pub mod formatter; -pub mod function; pub mod instruction; pub mod lexer; pub mod native_function; @@ -22,7 +21,6 @@ pub use crate::compiler::{compile, CompileError, Compiler}; pub use crate::disassembler::Disassembler; pub use crate::dust_error::{AnnotatedError, DustError}; pub use crate::formatter::{format, Formatter}; -pub use crate::function::{Function, FunctionBorrowed}; pub use crate::instruction::Instruction; pub use crate::lexer::{lex, LexError, Lexer}; pub use crate::native_function::{NativeFunction, NativeFunctionError}; @@ -31,7 +29,7 @@ pub use crate::optimizer::Optimizer; pub use crate::r#type::{EnumType, FunctionType, StructType, Type, TypeConflict}; pub use crate::scope::Scope; pub use crate::token::{output_token_list, Token, TokenKind, TokenOwned}; -pub use crate::value::{ConcreteValue, Value, ValueError}; +pub use crate::value::{Value, ValueError}; pub use crate::vm::{run, Vm, VmError}; use std::fmt::Display; diff --git a/dust-lang/src/native_function/logic.rs b/dust-lang/src/native_function/logic.rs index 20b1c9e..e414743 100644 --- a/dust-lang/src/native_function/logic.rs +++ b/dust-lang/src/native_function/logic.rs @@ -1,12 +1,8 @@ use std::io::{self, stdout, Write}; -use crate::{ConcreteValue, Instruction, NativeFunctionError, Span, Value, Vm, VmError}; +use crate::{Instruction, NativeFunctionError, Span, Value, Vm, VmError}; -pub fn panic( - vm: &Vm, - instruction: Instruction, - position: Span, -) -> Result, VmError> { +pub fn panic(vm: &Vm, instruction: Instruction) -> Result, VmError> { let argument_count = instruction.c(); let message = if argument_count == 0 { None @@ -18,7 +14,7 @@ pub fn panic( message.push(' '); } - let argument = vm.open_register(argument_index, position)?; + let argument = vm.open_register(argument_index)?; message.push_str(&argument.to_string()); } @@ -28,15 +24,11 @@ pub fn panic( Err(VmError::NativeFunction(NativeFunctionError::Panic { message, - position, + position: vm.current_position(), })) } -pub fn to_string( - vm: &Vm, - instruction: Instruction, - position: Span, -) -> Result, VmError> { +pub fn to_string(vm: &Vm, instruction: Instruction) -> Result, VmError> { let argument_count = instruction.c(); if argument_count != 1 { @@ -44,7 +36,7 @@ pub fn to_string( NativeFunctionError::ExpectedArgumentCount { expected: 1, found: argument_count as usize, - position, + position: vm.current_position(), }, )); } @@ -52,19 +44,15 @@ pub fn to_string( let mut string = String::new(); for argument_index in 0..argument_count { - let argument = vm.open_register(argument_index, position)?; + let argument = vm.open_register(argument_index)?; string.push_str(&argument.to_string()); } - Ok(Some(ConcreteValue::String(string))) + Ok(Some(Value::String(string))) } -pub fn read_line( - _: &Vm, - instruction: Instruction, - position: Span, -) -> Result, VmError> { +pub fn read_line(vm: &Vm, instruction: Instruction) -> Result, VmError> { let argument_count = instruction.c(); if argument_count != 0 { @@ -72,7 +60,7 @@ pub fn read_line( NativeFunctionError::ExpectedArgumentCount { expected: 0, found: argument_count as usize, - position, + position: vm.current_position(), }, )); } @@ -80,28 +68,24 @@ pub fn read_line( let mut buffer = String::new(); match io::stdin().read_line(&mut buffer) { - Ok(_) => Ok(Some(ConcreteValue::String( + Ok(_) => Ok(Some(Value::String( buffer.trim_end_matches('\n').to_string(), ))), Err(error) => Err(VmError::NativeFunction(NativeFunctionError::Io { error: error.kind(), - position, + position: vm.current_position(), })), } } -pub fn write( - vm: &Vm, - instruction: Instruction, - position: Span, -) -> Result, VmError> { +pub fn write(vm: &Vm, instruction: Instruction) -> Result, VmError> { let to_register = instruction.a(); let argument_count = instruction.c(); let mut stdout = stdout(); let map_err = |io_error: io::Error| { VmError::NativeFunction(NativeFunctionError::Io { error: io_error.kind(), - position, + position: vm.current_position(), }) }; @@ -112,7 +96,7 @@ pub fn write( stdout.write(b" ").map_err(map_err)?; } - let argument_string = vm.open_register(argument_index, position)?.to_string(); + let argument_string = vm.open_register(argument_index)?.to_string(); stdout .write_all(argument_string.as_bytes()) @@ -122,18 +106,14 @@ pub fn write( Ok(None) } -pub fn write_line( - vm: &Vm, - instruction: Instruction, - position: Span, -) -> Result, VmError> { +pub fn write_line(vm: &Vm, instruction: Instruction) -> Result, VmError> { let to_register = instruction.a(); let argument_count = instruction.c(); let mut stdout = stdout(); let map_err = |io_error: io::Error| { VmError::NativeFunction(NativeFunctionError::Io { error: io_error.kind(), - position, + position: vm.current_position(), }) }; @@ -144,7 +124,7 @@ pub fn write_line( stdout.write(b" ").map_err(map_err)?; } - let argument_string = vm.open_register(argument_index, position)?.to_string(); + let argument_string = vm.open_register(argument_index)?.to_string(); stdout .write_all(argument_string.as_bytes()) diff --git a/dust-lang/src/native_function/mod.rs b/dust-lang/src/native_function/mod.rs index 6dd02ea..f2058f7 100644 --- a/dust-lang/src/native_function/mod.rs +++ b/dust-lang/src/native_function/mod.rs @@ -12,7 +12,7 @@ use std::{ use serde::{Deserialize, Serialize}; -use crate::{AnnotatedError, ConcreteValue, FunctionType, Instruction, Span, Type, Vm, VmError}; +use crate::{AnnotatedError, FunctionType, Instruction, Span, Type, Value, Vm, VmError}; macro_rules! define_native_function { ($(($name:ident, $byte:literal, $str:expr, $type:expr, $function:expr)),*) => { @@ -31,11 +31,10 @@ macro_rules! define_native_function { &self, vm: &mut Vm, instruction: Instruction, - span: Span - ) -> Result, VmError> { + ) -> Result, VmError> { match self { $( - NativeFunction::$name => $function(vm, instruction, span), + NativeFunction::$name => $function(vm, instruction), )* } } diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs deleted file mode 100644 index 5bf03b7..0000000 --- a/dust-lang/src/value.rs +++ /dev/null @@ -1,983 +0,0 @@ -//! Runtime values used by the VM. -use std::{ - cmp::Ordering, - fmt::{self, Debug, Display, Formatter}, - ops::{Range, RangeInclusive}, -}; - -use serde::{Deserialize, Serialize}; - -use crate::{function::Function, Chunk, FunctionBorrowed, Type}; - -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum ReferenceValue<'a> { - Concrete(&'a ConcreteValue), - Function(FunctionBorrowed<'a>), - List(&'a Vec<&'a ConcreteValue>), -} - -impl<'a> ReferenceValue<'a> { - pub fn to_value(self) -> Value<'a> { - Value::Reference(self) - } - - pub fn r#type(&self) -> Type { - match self { - ReferenceValue::Concrete(concrete) => concrete.r#type(), - ReferenceValue::Function(function) => function.r#type(), - ReferenceValue::List(list) => { - let item_type = list - .first() - .map(|value| value.r#type()) - .unwrap_or(Type::Any); - - Type::List { - item_type: Box::new(item_type), - length: list.len(), - } - } - } - } - - pub fn into_concrete(self) -> ConcreteValue { - match self { - ReferenceValue::Concrete(concrete) => concrete.clone(), - ReferenceValue::Function(function) => { - ConcreteValue::Function(Function::new(function.chunk().clone())) - } - ReferenceValue::List(list) => { - let mut items = Vec::new(); - - for value in list { - items.push((*value).clone()); - } - - ConcreteValue::List(items) - } - } - } -} - -#[derive(Clone, Debug, PartialEq)] -pub enum Value<'a> { - Concrete(ConcreteValue), - Reference(ReferenceValue<'a>), -} - -impl<'a> Value<'a> { - pub fn r#type(&self) -> Type { - match self { - Value::Concrete(concrete) => concrete.r#type(), - Value::Reference(reference) => reference.r#type(), - } - } - - pub fn into_concrete(self) -> ConcreteValue { - match self { - Value::Concrete(concrete) => concrete, - Value::Reference(reference) => reference.into_concrete(), - } - } - - pub fn as_boolean(&self) -> Option { - match self { - Value::Concrete(ConcreteValue::Boolean(boolean)) => Some(*boolean), - Value::Reference(ReferenceValue::Concrete(ConcreteValue::Boolean(boolean))) => { - Some(*boolean) - } - _ => None, - } - } - pub fn as_function(&self) -> Option { - match self { - Value::Concrete(ConcreteValue::Function(function)) => Some(function.as_borrowed()), - Value::Reference(ReferenceValue::Concrete(ConcreteValue::Function(function))) => { - Some(function.as_borrowed()) - } - _ => None, - } - } - - pub fn add(&self, other: &Self) -> Result { - match (self, other) { - (Value::Concrete(left), Value::Concrete(right)) => left.add(right), - (Value::Reference(ReferenceValue::Concrete(left)), Value::Concrete(right)) => { - left.add(right) - } - (Value::Concrete(left), Value::Reference(ReferenceValue::Concrete(right))) => { - left.add(right) - } - ( - Value::Reference(ReferenceValue::Concrete(left)), - Value::Reference(ReferenceValue::Concrete(right)), - ) => left.add(right), - _ => Err(ValueError::CannotAdd( - self.clone().into_concrete(), - other.clone().into_concrete(), - )), - } - } - - pub fn subtract(&self, other: &Self) -> Result { - let (left, right) = match (self, other) { - (Value::Concrete(left), Value::Concrete(right)) => (left, right), - (Value::Reference(left), Value::Reference(right)) => (*left, *right), - _ => { - return Err(ValueError::CannotSubtract( - self.clone().into_concrete(), - other.clone().into_concrete(), - )); - } - }; - - left.subtract(right) - } - - pub fn multiply(&self, other: &Self) -> Result { - let (left, right) = match (self, other) { - (Value::Concrete(left), Value::Concrete(right)) => (left, right), - (Value::Reference(left), Value::Reference(right)) => (*left, *right), - _ => { - return Err(ValueError::CannotMultiply( - self.clone().into_concrete(), - other.clone().into_concrete(), - )); - } - }; - - left.multiply(right) - } - - pub fn divide(&self, other: &Self) -> Result { - let (left, right) = match (self, other) { - (Value::Concrete(left), Value::Concrete(right)) => (left, right), - (Value::Reference(left), Value::Reference(right)) => (*left, *right), - _ => { - return Err(ValueError::CannotDivide( - self.clone().into_concrete(), - other.clone().into_concrete(), - )); - } - }; - - left.divide(right) - } - - pub fn modulo(&self, other: &Self) -> Result { - let (left, right) = match (self, other) { - (Value::Concrete(left), Value::Concrete(right)) => (left, right), - (Value::Reference(left), Value::Reference(right)) => (*left, *right), - _ => { - return Err(ValueError::CannotModulo( - self.clone().into_concrete(), - other.clone().into_concrete(), - )); - } - }; - - left.modulo(right) - } - - pub fn negate(&self) -> Result { - match self { - Value::Concrete(concrete) => concrete.negate(), - Value::Reference(reference) => reference.negate(), - _ => Err(ValueError::CannotNegate(self.clone().into_concrete())), - } - } - - pub fn not(&self) -> Result { - match self { - Value::Concrete(concrete) => concrete.not(), - Value::Reference(reference) => reference.not(), - _ => Err(ValueError::CannotNot(self.clone().into_concrete())), - } - } - - pub fn equal(&self, other: &Self) -> Result { - let (left, right) = match (self, other) { - (Value::Concrete(left), Value::Concrete(right)) => (left, right), - (Value::Reference(left), Value::Reference(right)) => (*left, *right), - _ => { - return Err(ValueError::CannotCompare( - self.clone().into_concrete(), - other.clone().into_concrete(), - )); - } - }; - - left.equal(right) - } - - pub fn less_than(&self, other: &Self) -> Result { - let (left, right) = match (self, other) { - (Value::Concrete(left), Value::Concrete(right)) => (left, right), - (Value::Reference(left), Value::Reference(right)) => (*left, *right), - _ => { - return Err(ValueError::CannotCompare( - self.clone().into_concrete(), - other.clone().into_concrete(), - )); - } - }; - - left.less_than(right) - } - - pub fn less_than_or_equal(&self, other: &Self) -> Result { - let (left, right) = match (self, other) { - (Value::Concrete(left), Value::Concrete(right)) => (left, right), - (Value::Reference(left), Value::Reference(right)) => (*left, *right), - _ => { - return Err(ValueError::CannotCompare( - self.clone().into_concrete(), - other.clone().into_concrete(), - )); - } - }; - - left.less_than_or_equal(right) - } -} - -impl<'a> Display for Value<'a> { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Value::Concrete(concrete) => write!(f, "{}", concrete), - Value::List(list) => { - write!(f, "[")?; - - for (index, value) in list.iter().enumerate() { - if index > 0 { - write!(f, ", ")?; - } - write!(f, "{}", value)?; - } - - write!(f, "]") - } - Value::Reference(reference) => write!(f, "{}", reference), - Value::FunctionBorrowed(function_reference) => { - write!(f, "{}", function_reference.chunk().r#type()) - } - } - } -} - -impl<'a> Eq for Value<'a> {} - -impl<'a> PartialOrd for Value<'a> { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl<'a> Ord for Value<'a> { - fn cmp(&self, other: &Self) -> Ordering { - match (self, other) { - (Value::Concrete(left), Value::Concrete(right)) => left.cmp(right), - (Value::Concrete(_), _) => Ordering::Greater, - (Value::List(left), Value::List(right)) => left.cmp(right), - (Value::List(_), _) => Ordering::Greater, - (Value::Reference(left), Value::Reference(right)) => left.cmp(right), - (Value::Reference(_), _) => Ordering::Greater, - (Value::FunctionBorrowed(left), Value::FunctionBorrowed(right)) => left.cmp(right), - (Value::FunctionBorrowed(_), _) => Ordering::Greater, - } - } -} - -#[derive(Debug, PartialEq, Serialize, Deserialize)] -pub enum ConcreteValue { - Boolean(bool), - Byte(u8), - Character(char), - Float(f64), - Function(Function), - Integer(i64), - List(Vec), - Range(RangeValue), - String(String), -} - -impl ConcreteValue { - pub fn boolean(value: bool) -> Self { - ConcreteValue::Boolean(value) - } - - pub fn byte(value: u8) -> Self { - ConcreteValue::Byte(value) - } - - pub fn character(value: char) -> Self { - ConcreteValue::Character(value) - } - - pub fn float(value: f64) -> Self { - ConcreteValue::Float(value) - } - - pub fn function(chunk: Chunk) -> Self { - ConcreteValue::Function(Function::new(chunk)) - } - - pub fn integer>(into_i64: T) -> Self { - ConcreteValue::Integer(into_i64.into()) - } - - pub fn list>>(into_list: T) -> Self { - ConcreteValue::List(into_list.into()) - } - - pub fn range(range: RangeValue) -> Self { - ConcreteValue::Range(range) - } - - pub fn string(to_string: T) -> Self { - ConcreteValue::String(to_string.to_string()) - } - - pub fn as_string(&self) -> Option<&String> { - if let ConcreteValue::String(string) = self { - Some(string) - } else { - None - } - } - - pub fn to_owned_value<'a>(self) -> Value<'a> { - Value::Concrete(self) - } - - pub fn as_reference_value(&self) -> Value { - Value::Reference(self) - } - - pub fn r#type(&self) -> Type { - match self { - ConcreteValue::Boolean(_) => Type::Boolean, - ConcreteValue::Byte(_) => Type::Byte, - ConcreteValue::Character(_) => Type::Character, - ConcreteValue::Float(_) => Type::Float, - ConcreteValue::Function(function) => function.r#type(), - ConcreteValue::Integer(_) => Type::Integer, - ConcreteValue::List(list) => { - let item_type = list.first().map_or(Type::Any, |item| item.r#type()); - - Type::List { - item_type: Box::new(item_type), - length: list.len(), - } - } - ConcreteValue::Range(range) => range.r#type(), - ConcreteValue::String(string) => Type::String { - length: Some(string.len()), - }, - } - } - - pub fn add(&self, other: &Self) -> Result { - use ConcreteValue::*; - - let sum = match (self, other) { - (Byte(left), Byte(right)) => ConcreteValue::byte(left.saturating_add(*right)), - (Float(left), Float(right)) => ConcreteValue::float(*left + *right), - (Integer(left), Integer(right)) => ConcreteValue::integer(left.saturating_add(*right)), - (String(left), String(right)) => ConcreteValue::string(format!("{}{}", left, right)), - _ => return Err(ValueError::CannotAdd(self.clone(), other.clone())), - }; - - Ok(sum) - } - - pub fn subtract(&self, other: &Self) -> Result { - use ConcreteValue::*; - - let difference = match (self, other) { - (Byte(left), Byte(right)) => ConcreteValue::byte(left.saturating_sub(*right)), - (Float(left), Float(right)) => ConcreteValue::float(left - right), - (Integer(left), Integer(right)) => ConcreteValue::integer(left.saturating_sub(*right)), - _ => return Err(ValueError::CannotSubtract(self.clone(), other.clone())), - }; - - Ok(difference) - } - - pub fn multiply(&self, other: &Self) -> Result { - use ConcreteValue::*; - - let product = match (self, other) { - (Byte(left), Byte(right)) => ConcreteValue::byte(left.saturating_mul(*right)), - (Float(left), Float(right)) => ConcreteValue::float(left * right), - (Integer(left), Integer(right)) => ConcreteValue::integer(left.saturating_mul(*right)), - _ => return Err(ValueError::CannotMultiply(self.clone(), other.clone())), - }; - - Ok(product) - } - - pub fn divide(&self, other: &Self) -> Result { - use ConcreteValue::*; - - let quotient = match (self, other) { - (Byte(left), Byte(right)) => ConcreteValue::byte(left.saturating_div(*right)), - (Float(left), Float(right)) => ConcreteValue::float(left / right), - (Integer(left), Integer(right)) => ConcreteValue::integer(left.saturating_div(*right)), - _ => return Err(ValueError::CannotMultiply(self.clone(), other.clone())), - }; - - Ok(quotient) - } - - pub fn modulo(&self, other: &Self) -> Result { - use ConcreteValue::*; - - let product = match (self, other) { - (Byte(left), Byte(right)) => ConcreteValue::byte(left.wrapping_rem(*right)), - (Float(left), Float(right)) => ConcreteValue::float(left % right), - (Integer(left), Integer(right)) => { - ConcreteValue::integer(left.wrapping_rem_euclid(*right)) - } - _ => return Err(ValueError::CannotMultiply(self.clone(), other.clone())), - }; - - Ok(product) - } - - pub fn negate(&self) -> Result { - use ConcreteValue::*; - - let negated = match self { - Boolean(value) => ConcreteValue::boolean(!value), - Byte(value) => ConcreteValue::byte(value.wrapping_neg()), - Float(value) => ConcreteValue::float(-value), - Integer(value) => ConcreteValue::integer(value.wrapping_neg()), - _ => return Err(ValueError::CannotNegate(self.clone())), - }; - - Ok(negated) - } - - pub fn not(&self) -> Result { - use ConcreteValue::*; - - let not = match self { - Boolean(value) => ConcreteValue::boolean(!value), - _ => return Err(ValueError::CannotNot(self.clone())), - }; - - Ok(not) - } - - pub fn equal(&self, other: &ConcreteValue) -> Result { - use ConcreteValue::*; - - let equal = match (self, other) { - (Boolean(left), Boolean(right)) => ConcreteValue::boolean(left == right), - (Byte(left), Byte(right)) => ConcreteValue::boolean(left == right), - (Character(left), Character(right)) => ConcreteValue::boolean(left == right), - (Float(left), Float(right)) => ConcreteValue::boolean(left == right), - (Function(left), Function(right)) => ConcreteValue::boolean(left == right), - (Integer(left), Integer(right)) => ConcreteValue::boolean(left == right), - (List(left), List(right)) => ConcreteValue::boolean(left == right), - (Range(left), Range(right)) => ConcreteValue::boolean(left == right), - (String(left), String(right)) => ConcreteValue::boolean(left == right), - _ => return Err(ValueError::CannotCompare(self.clone(), other.clone())), - }; - - Ok(equal) - } - - pub fn less_than(&self, other: &ConcreteValue) -> Result { - use ConcreteValue::*; - - let less_than = match (self, other) { - (Boolean(left), Boolean(right)) => ConcreteValue::boolean(left < right), - (Byte(left), Byte(right)) => ConcreteValue::boolean(left < right), - (Character(left), Character(right)) => ConcreteValue::boolean(left < right), - (Float(left), Float(right)) => ConcreteValue::boolean(left < right), - (Function(left), Function(right)) => ConcreteValue::boolean(left < right), - (Integer(left), Integer(right)) => ConcreteValue::boolean(left < right), - (List(left), List(right)) => ConcreteValue::boolean(left < right), - (Range(left), Range(right)) => ConcreteValue::boolean(left < right), - (String(left), String(right)) => ConcreteValue::boolean(left < right), - _ => return Err(ValueError::CannotCompare(self.clone(), other.clone())), - }; - - Ok(less_than) - } - - pub fn less_than_or_equal(&self, other: &ConcreteValue) -> Result { - use ConcreteValue::*; - - let less_than_or_equal = match (self, other) { - (Boolean(left), Boolean(right)) => ConcreteValue::boolean(left <= right), - (Byte(left), Byte(right)) => ConcreteValue::boolean(left <= right), - (Character(left), Character(right)) => ConcreteValue::boolean(left <= right), - (Float(left), Float(right)) => ConcreteValue::boolean(left <= right), - (Function(left), Function(right)) => ConcreteValue::boolean(left <= right), - (Integer(left), Integer(right)) => ConcreteValue::boolean(left <= right), - (List(left), List(right)) => ConcreteValue::boolean(left <= right), - (Range(left), Range(right)) => ConcreteValue::boolean(left <= right), - (String(left), String(right)) => ConcreteValue::boolean(left <= right), - _ => return Err(ValueError::CannotCompare(self.clone(), other.clone())), - }; - - Ok(less_than_or_equal) - } -} - -impl Clone for ConcreteValue { - fn clone(&self) -> Self { - log::trace!("Cloning concrete value {}", self); - - match self { - ConcreteValue::Boolean(boolean) => ConcreteValue::Boolean(*boolean), - ConcreteValue::Byte(byte) => ConcreteValue::Byte(*byte), - ConcreteValue::Character(character) => ConcreteValue::Character(*character), - ConcreteValue::Float(float) => ConcreteValue::Float(*float), - ConcreteValue::Function(function) => ConcreteValue::Function(function.clone()), - ConcreteValue::Integer(integer) => ConcreteValue::Integer(*integer), - ConcreteValue::List(list) => ConcreteValue::List(list.clone()), - ConcreteValue::Range(range) => ConcreteValue::Range(range.clone()), - ConcreteValue::String(string) => ConcreteValue::String(string.clone()), - } - } -} - -impl Eq for ConcreteValue {} - -impl PartialOrd for ConcreteValue { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for ConcreteValue { - fn cmp(&self, other: &Self) -> Ordering { - match (self, other) { - (ConcreteValue::Boolean(left), ConcreteValue::Boolean(right)) => left.cmp(right), - (ConcreteValue::Boolean(_), _) => Ordering::Greater, - (ConcreteValue::Byte(left), ConcreteValue::Byte(right)) => left.cmp(right), - (ConcreteValue::Byte(_), _) => Ordering::Greater, - (ConcreteValue::Character(left), ConcreteValue::Character(right)) => left.cmp(right), - (ConcreteValue::Character(_), _) => Ordering::Greater, - (ConcreteValue::Float(left), ConcreteValue::Float(right)) => { - left.to_bits().cmp(&right.to_bits()) - } - (ConcreteValue::Float(_), _) => Ordering::Greater, - (ConcreteValue::Function(left), ConcreteValue::Function(right)) => left.cmp(right), - (ConcreteValue::Function(_), _) => Ordering::Greater, - (ConcreteValue::Integer(left), ConcreteValue::Integer(right)) => left.cmp(right), - (ConcreteValue::Integer(_), _) => Ordering::Greater, - (ConcreteValue::List(left), ConcreteValue::List(right)) => left.cmp(right), - (ConcreteValue::List(_), _) => Ordering::Greater, - (ConcreteValue::Range(left), ConcreteValue::Range(right)) => left.cmp(right), - (ConcreteValue::Range(_), _) => Ordering::Greater, - (ConcreteValue::String(left), ConcreteValue::String(right)) => left.cmp(right), - (ConcreteValue::String(_), _) => Ordering::Greater, - } - } -} - -impl Display for ConcreteValue { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - ConcreteValue::Boolean(boolean) => write!(f, "{boolean}"), - ConcreteValue::Byte(byte) => write!(f, "0x{byte:02x}"), - ConcreteValue::Character(character) => write!(f, "{character}"), - ConcreteValue::Float(float) => { - write!(f, "{float}")?; - - if float.fract() == 0.0 { - write!(f, ".0")?; - } - - Ok(()) - } - ConcreteValue::Function(function) => write!(f, "{function}"), - ConcreteValue::Integer(integer) => write!(f, "{integer}"), - ConcreteValue::List(list) => { - write!(f, "[")?; - - for (index, element) in list.iter().enumerate() { - if index > 0 { - write!(f, ", ")?; - } - - write!(f, "{element}")?; - } - - write!(f, "]") - } - ConcreteValue::Range(range_value) => { - write!(f, "{range_value}") - } - ConcreteValue::String(string) => write!(f, "{string}"), - } - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] -pub enum RangeValue { - ByteRange { start: u8, end: u8 }, - ByteRangeInclusive { start: u8, end: u8 }, - CharacterRange { start: char, end: char }, - CharacterRangeInclusive { start: char, end: char }, - FloatRange { start: f64, end: f64 }, - FloatRangeInclusive { start: f64, end: f64 }, - IntegerRange { start: i64, end: i64 }, - IntegerRangeInclusive { start: i64, end: i64 }, -} - -impl RangeValue { - pub fn r#type(&self) -> Type { - let inner_type = match self { - RangeValue::ByteRange { .. } | RangeValue::ByteRangeInclusive { .. } => Type::Byte, - RangeValue::CharacterRange { .. } | RangeValue::CharacterRangeInclusive { .. } => { - Type::Character - } - RangeValue::FloatRange { .. } | RangeValue::FloatRangeInclusive { .. } => Type::Float, - RangeValue::IntegerRange { .. } | RangeValue::IntegerRangeInclusive { .. } => { - Type::Integer - } - }; - - Type::Range { - r#type: Box::new(inner_type), - } - } -} - -impl From> for RangeValue { - fn from(range: Range) -> Self { - RangeValue::ByteRange { - start: range.start, - end: range.end, - } - } -} - -impl From> for RangeValue { - fn from(range: RangeInclusive) -> Self { - RangeValue::ByteRangeInclusive { - start: *range.start(), - end: *range.end(), - } - } -} - -impl From> for RangeValue { - fn from(range: Range) -> Self { - RangeValue::CharacterRange { - start: range.start, - end: range.end, - } - } -} - -impl From> for RangeValue { - fn from(range: RangeInclusive) -> Self { - RangeValue::CharacterRangeInclusive { - start: *range.start(), - end: *range.end(), - } - } -} - -impl From> for RangeValue { - fn from(range: Range) -> Self { - RangeValue::FloatRange { - start: range.start, - end: range.end, - } - } -} - -impl From> for RangeValue { - fn from(range: RangeInclusive) -> Self { - RangeValue::FloatRangeInclusive { - start: *range.start(), - end: *range.end(), - } - } -} - -impl From> for RangeValue { - fn from(range: Range) -> Self { - RangeValue::IntegerRange { - start: range.start as i64, - end: range.end as i64, - } - } -} - -impl From> for RangeValue { - fn from(range: RangeInclusive) -> Self { - RangeValue::IntegerRangeInclusive { - start: *range.start() as i64, - end: *range.end() as i64, - } - } -} - -impl From> for RangeValue { - fn from(range: Range) -> Self { - RangeValue::IntegerRange { - start: range.start, - end: range.end, - } - } -} - -impl From> for RangeValue { - fn from(range: RangeInclusive) -> Self { - RangeValue::IntegerRangeInclusive { - start: *range.start(), - end: *range.end(), - } - } -} - -impl Display for RangeValue { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - RangeValue::ByteRange { start, end } => write!(f, "{}..{}", start, end), - RangeValue::ByteRangeInclusive { start, end } => { - write!(f, "{}..={}", start, end) - } - RangeValue::CharacterRange { start, end } => { - write!(f, "{}..{}", start, end) - } - RangeValue::CharacterRangeInclusive { start, end } => { - write!(f, "{}..={}", start, end) - } - RangeValue::FloatRange { start, end } => write!(f, "{}..{}", start, end), - RangeValue::FloatRangeInclusive { start, end } => { - write!(f, "{}..={}", start, end) - } - RangeValue::IntegerRange { start, end } => write!(f, "{}..{}", start, end), - RangeValue::IntegerRangeInclusive { start, end } => { - write!(f, "{}..={}", start, end) - } - } - } -} - -impl Eq for RangeValue {} - -impl PartialOrd for RangeValue { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for RangeValue { - fn cmp(&self, other: &Self) -> Ordering { - match (self, other) { - ( - RangeValue::ByteRange { - start: left_start, - end: left_end, - }, - RangeValue::ByteRange { - start: right_start, - end: right_end, - }, - ) => { - let start_cmp = left_start.cmp(right_start); - - if start_cmp != Ordering::Equal { - start_cmp - } else { - left_end.cmp(right_end) - } - } - (RangeValue::ByteRange { .. }, _) => Ordering::Greater, - ( - RangeValue::ByteRangeInclusive { - start: left_start, - end: left_end, - }, - RangeValue::ByteRangeInclusive { - start: right_start, - end: right_end, - }, - ) => { - let start_cmp = left_start.cmp(&right_start); - - if start_cmp != Ordering::Equal { - start_cmp - } else { - left_end.cmp(&right_end) - } - } - (RangeValue::ByteRangeInclusive { .. }, _) => Ordering::Greater, - ( - RangeValue::CharacterRange { - start: left_start, - end: left_end, - }, - RangeValue::CharacterRange { - start: right_start, - end: right_end, - }, - ) => { - let start_cmp = left_start.cmp(right_start); - - if start_cmp != Ordering::Equal { - start_cmp - } else { - left_end.cmp(right_end) - } - } - (RangeValue::CharacterRange { .. }, _) => Ordering::Greater, - ( - RangeValue::CharacterRangeInclusive { - start: left_start, - end: left_end, - }, - RangeValue::CharacterRangeInclusive { - start: right_start, - end: right_end, - }, - ) => { - let start_cmp = left_start.cmp(right_start); - - if start_cmp != Ordering::Equal { - start_cmp - } else { - left_end.cmp(right_end) - } - } - (RangeValue::CharacterRangeInclusive { .. }, _) => Ordering::Greater, - ( - RangeValue::FloatRange { - start: left_start, - end: left_end, - }, - RangeValue::FloatRange { - start: right_start, - end: right_end, - }, - ) => { - let start_cmp = left_start.partial_cmp(right_start).unwrap(); - - if start_cmp != Ordering::Equal { - start_cmp - } else { - left_end.partial_cmp(right_end).unwrap() - } - } - (RangeValue::FloatRange { .. }, _) => Ordering::Greater, - ( - RangeValue::FloatRangeInclusive { - start: left_start, - end: left_end, - }, - RangeValue::FloatRangeInclusive { - start: right_start, - end: right_end, - }, - ) => { - let start_cmp = left_start.partial_cmp(right_start).unwrap(); - - if start_cmp != Ordering::Equal { - start_cmp - } else { - left_end.partial_cmp(right_end).unwrap() - } - } - (RangeValue::FloatRangeInclusive { .. }, _) => Ordering::Greater, - ( - RangeValue::IntegerRange { - start: left_start, - end: left_end, - }, - RangeValue::IntegerRange { - start: right_start, - end: right_end, - }, - ) => { - let start_cmp = left_start.cmp(right_start); - - if start_cmp != Ordering::Equal { - start_cmp - } else { - left_end.cmp(right_end) - } - } - (RangeValue::IntegerRange { .. }, _) => Ordering::Greater, - ( - RangeValue::IntegerRangeInclusive { - start: left_start, - end: left_end, - }, - RangeValue::IntegerRangeInclusive { - start: right_start, - end: right_end, - }, - ) => { - let start_cmp = left_start.cmp(right_start); - - if start_cmp != Ordering::Equal { - start_cmp - } else { - left_end.cmp(right_end) - } - } - (RangeValue::IntegerRangeInclusive { .. }, _) => Ordering::Greater, - } - } -} - -#[derive(Clone, Debug, PartialEq)] -pub enum ValueError { - CannotAdd(ConcreteValue, ConcreteValue), - CannotAnd(ConcreteValue, ConcreteValue), - CannotCompare(ConcreteValue, ConcreteValue), - CannotDivide(ConcreteValue, ConcreteValue), - CannotModulo(ConcreteValue, ConcreteValue), - CannotMultiply(ConcreteValue, ConcreteValue), - CannotNegate(ConcreteValue), - CannotNot(ConcreteValue), - CannotSubtract(ConcreteValue, ConcreteValue), - CannotOr(ConcreteValue, ConcreteValue), -} - -impl Display for ValueError { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - ValueError::CannotAdd(left, right) => { - write!(f, "Cannot add {left} and {right}") - } - ValueError::CannotAnd(left, right) => { - write!(f, "Cannot use logical AND operation on {left} and {right}") - } - ValueError::CannotCompare(left, right) => { - write!(f, "Cannot compare {left} and {right}") - } - ValueError::CannotDivide(left, right) => { - write!(f, "Cannot divide {left} by {right}") - } - ValueError::CannotModulo(left, right) => { - write!(f, "Cannot use modulo operation on {left} and {right}") - } - ValueError::CannotMultiply(left, right) => { - write!(f, "Cannot multiply {left} by {right}") - } - ValueError::CannotNegate(value) => { - write!(f, "Cannot negate {value}") - } - ValueError::CannotNot(value) => { - write!(f, "Cannot use logical NOT operation on {value}") - } - ValueError::CannotSubtract(left, right) => { - write!(f, "Cannot subtract {right} from {left}") - } - ValueError::CannotOr(left, right) => { - write!(f, "Cannot use logical OR operation on {left} and {right}") - } - } - } -} diff --git a/dust-lang/src/value/mod.rs b/dust-lang/src/value/mod.rs new file mode 100644 index 0000000..16848c2 --- /dev/null +++ b/dust-lang/src/value/mod.rs @@ -0,0 +1,347 @@ +//! Runtime values used by the VM. +mod range; + +pub use range::RangeValue; + +use std::fmt::{self, Debug, Display, Formatter}; + +use serde::{Deserialize, Serialize}; + +use crate::{Chunk, Type}; + +#[derive(Debug, PartialEq, PartialOrd, Serialize, Deserialize)] +pub enum Value { + Boolean(bool), + Byte(u8), + Character(char), + Float(f64), + Function(Chunk), + Integer(i64), + List(Vec), + Range(RangeValue), + String(String), +} + +impl Value { + pub fn boolean(value: bool) -> Self { + Value::Boolean(value) + } + + pub fn byte(value: u8) -> Self { + Value::Byte(value) + } + + pub fn character(value: char) -> Self { + Value::Character(value) + } + + pub fn float(value: f64) -> Self { + Value::Float(value) + } + + pub fn function(chunk: Chunk) -> Self { + Value::Function(chunk) + } + + pub fn integer>(into_i64: T) -> Self { + Value::Integer(into_i64.into()) + } + + pub fn list>>(into_list: T) -> Self { + Value::List(into_list.into()) + } + + pub fn range(range: RangeValue) -> Self { + Value::Range(range) + } + + pub fn string(to_string: T) -> Self { + Value::String(to_string.to_string()) + } + + pub fn as_string(&self) -> Option<&String> { + if let Value::String(string) = self { + Some(string) + } else { + None + } + } + + pub fn r#type(&self) -> Type { + match self { + Value::Boolean(_) => Type::Boolean, + Value::Byte(_) => Type::Byte, + Value::Character(_) => Type::Character, + Value::Float(_) => Type::Float, + Value::Function(chunk) => Type::Function(chunk.r#type().clone()), + Value::Integer(_) => Type::Integer, + Value::List(list) => { + let item_type = list.first().map_or(Type::Any, |item| item.r#type()); + + Type::List { + item_type: Box::new(item_type), + length: list.len(), + } + } + Value::Range(range) => range.r#type(), + Value::String(string) => Type::String { + length: Some(string.len()), + }, + } + } + + pub fn add(&self, other: &Self) -> Result { + use Value::*; + + let sum = match (self, other) { + (Byte(left), Byte(right)) => Value::byte(left.saturating_add(*right)), + (Float(left), Float(right)) => Value::float(*left + *right), + (Integer(left), Integer(right)) => Value::integer(left.saturating_add(*right)), + (String(left), String(right)) => Value::string(format!("{}{}", left, right)), + _ => return Err(ValueError::CannotAdd(self.clone(), other.clone())), + }; + + Ok(sum) + } + + pub fn subtract(&self, other: &Self) -> Result { + use Value::*; + + let difference = match (self, other) { + (Byte(left), Byte(right)) => Value::byte(left.saturating_sub(*right)), + (Float(left), Float(right)) => Value::float(left - right), + (Integer(left), Integer(right)) => Value::integer(left.saturating_sub(*right)), + _ => return Err(ValueError::CannotSubtract(self.clone(), other.clone())), + }; + + Ok(difference) + } + + pub fn multiply(&self, other: &Self) -> Result { + use Value::*; + + let product = match (self, other) { + (Byte(left), Byte(right)) => Value::byte(left.saturating_mul(*right)), + (Float(left), Float(right)) => Value::float(left * right), + (Integer(left), Integer(right)) => Value::integer(left.saturating_mul(*right)), + _ => return Err(ValueError::CannotMultiply(self.clone(), other.clone())), + }; + + Ok(product) + } + + pub fn divide(&self, other: &Self) -> Result { + use Value::*; + + let quotient = match (self, other) { + (Byte(left), Byte(right)) => Value::byte(left.saturating_div(*right)), + (Float(left), Float(right)) => Value::float(left / right), + (Integer(left), Integer(right)) => Value::integer(left.saturating_div(*right)), + _ => return Err(ValueError::CannotMultiply(self.clone(), other.clone())), + }; + + Ok(quotient) + } + + pub fn modulo(&self, other: &Self) -> Result { + use Value::*; + + let product = match (self, other) { + (Byte(left), Byte(right)) => Value::byte(left.wrapping_rem(*right)), + (Float(left), Float(right)) => Value::float(left % right), + (Integer(left), Integer(right)) => Value::integer(left.wrapping_rem_euclid(*right)), + _ => return Err(ValueError::CannotMultiply(self.clone(), other.clone())), + }; + + Ok(product) + } + + pub fn negate(&self) -> Result { + use Value::*; + + let negated = match self { + Boolean(value) => Value::boolean(!value), + Byte(value) => Value::byte(value.wrapping_neg()), + Float(value) => Value::float(-value), + Integer(value) => Value::integer(value.wrapping_neg()), + _ => return Err(ValueError::CannotNegate(self.clone())), + }; + + Ok(negated) + } + + pub fn not(&self) -> Result { + use Value::*; + + let not = match self { + Boolean(value) => Value::boolean(!value), + _ => return Err(ValueError::CannotNot(self.clone())), + }; + + Ok(not) + } + + pub fn equal(&self, other: &Value) -> Result { + use Value::*; + + let equal = match (self, other) { + (Boolean(left), Boolean(right)) => Value::boolean(left == right), + (Byte(left), Byte(right)) => Value::boolean(left == right), + (Character(left), Character(right)) => Value::boolean(left == right), + (Float(left), Float(right)) => Value::boolean(left == right), + (Function(left), Function(right)) => Value::boolean(left == right), + (Integer(left), Integer(right)) => Value::boolean(left == right), + (List(left), List(right)) => Value::boolean(left == right), + (Range(left), Range(right)) => Value::boolean(left == right), + (String(left), String(right)) => Value::boolean(left == right), + _ => return Err(ValueError::CannotCompare(self.clone(), other.clone())), + }; + + Ok(equal) + } + + pub fn less_than(&self, other: &Value) -> Result { + use Value::*; + + let less_than = match (self, other) { + (Boolean(left), Boolean(right)) => Value::boolean(left < right), + (Byte(left), Byte(right)) => Value::boolean(left < right), + (Character(left), Character(right)) => Value::boolean(left < right), + (Float(left), Float(right)) => Value::boolean(left < right), + (Function(left), Function(right)) => Value::boolean(left < right), + (Integer(left), Integer(right)) => Value::boolean(left < right), + (List(left), List(right)) => Value::boolean(left < right), + (Range(left), Range(right)) => Value::boolean(left < right), + (String(left), String(right)) => Value::boolean(left < right), + _ => return Err(ValueError::CannotCompare(self.clone(), other.clone())), + }; + + Ok(less_than) + } + + pub fn less_than_or_equal(&self, other: &Value) -> Result { + use Value::*; + + let less_than_or_equal = match (self, other) { + (Boolean(left), Boolean(right)) => Value::boolean(left <= right), + (Byte(left), Byte(right)) => Value::boolean(left <= right), + (Character(left), Character(right)) => Value::boolean(left <= right), + (Float(left), Float(right)) => Value::boolean(left <= right), + (Function(left), Function(right)) => Value::boolean(left <= right), + (Integer(left), Integer(right)) => Value::boolean(left <= right), + (List(left), List(right)) => Value::boolean(left <= right), + (Range(left), Range(right)) => Value::boolean(left <= right), + (String(left), String(right)) => Value::boolean(left <= right), + _ => return Err(ValueError::CannotCompare(self.clone(), other.clone())), + }; + + Ok(less_than_or_equal) + } +} + +impl Clone for Value { + fn clone(&self) -> Self { + log::trace!("Cloning concrete value {}", self); + + match self { + Value::Boolean(boolean) => Value::Boolean(*boolean), + Value::Byte(byte) => Value::Byte(*byte), + Value::Character(character) => Value::Character(*character), + Value::Float(float) => Value::Float(*float), + Value::Function(function) => Value::Function(function.clone()), + Value::Integer(integer) => Value::Integer(*integer), + Value::List(list) => Value::List(list.clone()), + Value::Range(range) => Value::Range(range.clone()), + Value::String(string) => Value::String(string.clone()), + } + } +} + +impl Display for Value { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + Value::Boolean(boolean) => write!(f, "{boolean}"), + Value::Byte(byte) => write!(f, "0x{byte:02x}"), + Value::Character(character) => write!(f, "{character}"), + Value::Float(float) => { + write!(f, "{float}")?; + + if float.fract() == 0.0 { + write!(f, ".0")?; + } + + Ok(()) + } + Value::Function(function) => write!(f, "{function}"), + Value::Integer(integer) => write!(f, "{integer}"), + Value::List(list) => { + write!(f, "[")?; + + for (index, element) in list.iter().enumerate() { + if index > 0 { + write!(f, ", ")?; + } + + write!(f, "{element}")?; + } + + write!(f, "]") + } + Value::Range(range_value) => { + write!(f, "{range_value}") + } + Value::String(string) => write!(f, "{string}"), + } + } +} + +#[derive(Clone, Debug, PartialEq)] +pub enum ValueError { + CannotAdd(Value, Value), + CannotAnd(Value, Value), + CannotCompare(Value, Value), + CannotDivide(Value, Value), + CannotModulo(Value, Value), + CannotMultiply(Value, Value), + CannotNegate(Value), + CannotNot(Value), + CannotSubtract(Value, Value), + CannotOr(Value, Value), +} + +impl Display for ValueError { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + ValueError::CannotAdd(left, right) => { + write!(f, "Cannot add {left} and {right}") + } + ValueError::CannotAnd(left, right) => { + write!(f, "Cannot use logical AND operation on {left} and {right}") + } + ValueError::CannotCompare(left, right) => { + write!(f, "Cannot compare {left} and {right}") + } + ValueError::CannotDivide(left, right) => { + write!(f, "Cannot divide {left} by {right}") + } + ValueError::CannotModulo(left, right) => { + write!(f, "Cannot use modulo operation on {left} and {right}") + } + ValueError::CannotMultiply(left, right) => { + write!(f, "Cannot multiply {left} by {right}") + } + ValueError::CannotNegate(value) => { + write!(f, "Cannot negate {value}") + } + ValueError::CannotNot(value) => { + write!(f, "Cannot use logical NOT operation on {value}") + } + ValueError::CannotSubtract(left, right) => { + write!(f, "Cannot subtract {right} from {left}") + } + ValueError::CannotOr(left, right) => { + write!(f, "Cannot use logical OR operation on {left} and {right}") + } + } + } +} diff --git a/dust-lang/src/value/range.rs b/dust-lang/src/value/range.rs new file mode 100644 index 0000000..eb15135 --- /dev/null +++ b/dust-lang/src/value/range.rs @@ -0,0 +1,154 @@ +use std::{ + fmt::{self, Display, Formatter}, + ops::{Range, RangeInclusive}, +}; + +use serde::{Deserialize, Serialize}; + +use crate::Type; + +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] +pub enum RangeValue { + ByteRange { start: u8, end: u8 }, + ByteRangeInclusive { start: u8, end: u8 }, + CharacterRange { start: char, end: char }, + CharacterRangeInclusive { start: char, end: char }, + FloatRange { start: f64, end: f64 }, + FloatRangeInclusive { start: f64, end: f64 }, + IntegerRange { start: i64, end: i64 }, + IntegerRangeInclusive { start: i64, end: i64 }, +} + +impl RangeValue { + pub fn r#type(&self) -> Type { + let inner_type = match self { + RangeValue::ByteRange { .. } | RangeValue::ByteRangeInclusive { .. } => Type::Byte, + RangeValue::CharacterRange { .. } | RangeValue::CharacterRangeInclusive { .. } => { + Type::Character + } + RangeValue::FloatRange { .. } | RangeValue::FloatRangeInclusive { .. } => Type::Float, + RangeValue::IntegerRange { .. } | RangeValue::IntegerRangeInclusive { .. } => { + Type::Integer + } + }; + + Type::Range { + r#type: Box::new(inner_type), + } + } +} + +impl From> for RangeValue { + fn from(range: Range) -> Self { + RangeValue::ByteRange { + start: range.start, + end: range.end, + } + } +} + +impl From> for RangeValue { + fn from(range: RangeInclusive) -> Self { + RangeValue::ByteRangeInclusive { + start: *range.start(), + end: *range.end(), + } + } +} + +impl From> for RangeValue { + fn from(range: Range) -> Self { + RangeValue::CharacterRange { + start: range.start, + end: range.end, + } + } +} + +impl From> for RangeValue { + fn from(range: RangeInclusive) -> Self { + RangeValue::CharacterRangeInclusive { + start: *range.start(), + end: *range.end(), + } + } +} + +impl From> for RangeValue { + fn from(range: Range) -> Self { + RangeValue::FloatRange { + start: range.start, + end: range.end, + } + } +} + +impl From> for RangeValue { + fn from(range: RangeInclusive) -> Self { + RangeValue::FloatRangeInclusive { + start: *range.start(), + end: *range.end(), + } + } +} + +impl From> for RangeValue { + fn from(range: Range) -> Self { + RangeValue::IntegerRange { + start: range.start as i64, + end: range.end as i64, + } + } +} + +impl From> for RangeValue { + fn from(range: RangeInclusive) -> Self { + RangeValue::IntegerRangeInclusive { + start: *range.start() as i64, + end: *range.end() as i64, + } + } +} + +impl From> for RangeValue { + fn from(range: Range) -> Self { + RangeValue::IntegerRange { + start: range.start, + end: range.end, + } + } +} + +impl From> for RangeValue { + fn from(range: RangeInclusive) -> Self { + RangeValue::IntegerRangeInclusive { + start: *range.start(), + end: *range.end(), + } + } +} + +impl Display for RangeValue { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + RangeValue::ByteRange { start, end } => write!(f, "{}..{}", start, end), + RangeValue::ByteRangeInclusive { start, end } => { + write!(f, "{}..={}", start, end) + } + RangeValue::CharacterRange { start, end } => { + write!(f, "{}..{}", start, end) + } + RangeValue::CharacterRangeInclusive { start, end } => { + write!(f, "{}..={}", start, end) + } + RangeValue::FloatRange { start, end } => write!(f, "{}..{}", start, end), + RangeValue::FloatRangeInclusive { start, end } => { + write!(f, "{}..={}", start, end) + } + RangeValue::IntegerRange { start, end } => write!(f, "{}..{}", start, end), + RangeValue::IntegerRangeInclusive { start, end } => { + write!(f, "{}..={}", start, end) + } + } + } +} diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index a9f51c8..ce13c64 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -3,21 +3,28 @@ use std::{ cmp::Ordering, collections::HashMap, fmt::{self, Display, Formatter}, - mem::replace, - rc::Weak, }; use crate::{ - compile, value::ConcreteValue, AnnotatedError, Chunk, ChunkError, DustError, FunctionBorrowed, - Instruction, NativeFunction, NativeFunctionError, Operation, Span, Type, Value, ValueError, + compile, value::Value, AnnotatedError, Chunk, ChunkError, DustError, Instruction, + NativeFunction, NativeFunctionError, Operation, Span, Type, ValueError, }; -pub fn run(source: &str) -> Result, DustError> { +pub fn run(source: &str) -> Result, DustError> { let chunk = compile(source)?; + let has_return_value = *chunk.r#type().return_type != Type::None; let mut vm = Vm::new(&chunk, None); vm.run() - .map_err(|error| DustError::Runtime { error, source }) + .map_err(|error| DustError::Runtime { error, source })?; + + if has_return_value { + vm.take_top_of_stack_as_value() + .map(Some) + .map_err(|error| DustError::Runtime { error, source }) + } else { + Ok(None) + } } pub fn run_and_display_output(source: &str) { @@ -31,36 +38,43 @@ pub fn run_and_display_output(source: &str) { /// Dust virtual machine. /// /// See the [module-level documentation](index.html) for more information. -#[derive(Debug, Eq, PartialEq)] -pub struct Vm<'chunk, 'parent, 'stack> { +#[derive(Debug, PartialEq)] +pub struct Vm<'a> { + chunk: &'a Chunk, + stack: Vec, + parent: Option<&'a Vm<'a>>, + ip: usize, - chunk: &'chunk Chunk, - stack: Vec>, local_definitions: HashMap, last_assigned_register: Option, - parent: Option<&'parent Vm<'chunk, 'stack, 'parent>>, + current_position: Span, } -impl<'chunk, 'parent, 'stack: 'chunk + 'parent> Vm<'chunk, 'parent, 'stack> { +impl<'a> Vm<'a> { const STACK_LIMIT: usize = u16::MAX as usize; - pub fn new(chunk: &'chunk Chunk, parent: Option<&'parent Vm<'chunk, 'parent, 'stack>>) -> Self { + pub fn new(chunk: &'a Chunk, parent: Option<&'a Vm<'a>>) -> Self { Self { - ip: 0, chunk, stack: Vec::new(), + parent, + ip: 0, local_definitions: HashMap::new(), last_assigned_register: None, - parent, + current_position: Span(0, 0), } } - pub fn run(&'stack mut self) -> Result, VmError> { - while let Ok((instruction, position)) = self.read(Span(0, 0)).copied() { + pub fn current_position(&self) -> Span { + self.current_position + } + + pub fn run(&mut self) -> Result<(), VmError> { + while let Ok(instruction) = self.read() { log::info!( "{} | {} | {} | {}", self.ip - 1, - position, + self.current_position, instruction.operation(), instruction.disassembly_info(self.chunk) ); @@ -73,13 +87,10 @@ impl<'chunk, 'parent, 'stack: 'chunk + 'parent> Vm<'chunk, 'parent, 'stack> { .stack .get(from_register as usize) .is_some_and(|register| !matches!(register, Register::Empty)); + let register = Register::Pointer(Pointer::Stack(from_register)); if from_register_has_value { - self.set_register( - to_register, - Register::StackPointer(from_register), - position, - )?; + self.set_register(to_register, register)?; } } Operation::Close => { @@ -87,7 +98,9 @@ impl<'chunk, 'parent, 'stack: 'chunk + 'parent> Vm<'chunk, 'parent, 'stack> { let to_register = instruction.c(); if self.stack.len() < to_register as usize { - return Err(VmError::StackUnderflow { position }); + return Err(VmError::StackUnderflow { + position: self.current_position, + }); } for register_index in from_register..to_register { @@ -98,9 +111,9 @@ impl<'chunk, 'parent, 'stack: 'chunk + 'parent> Vm<'chunk, 'parent, 'stack> { let to_register = instruction.a(); let boolean = instruction.b_as_boolean(); let jump = instruction.c_as_boolean(); - let boolean = ConcreteValue::boolean(boolean); + let boolean = Value::boolean(boolean); - self.set_register(to_register, Register::Value(boolean), position)?; + self.set_register(to_register, Register::Value(boolean))?; if jump { self.ip += 1; @@ -113,8 +126,7 @@ impl<'chunk, 'parent, 'stack: 'chunk + 'parent> Vm<'chunk, 'parent, 'stack> { self.set_register( to_register, - Register::ConstantPointer(from_constant), - position, + Register::Pointer(Pointer::Constant(from_constant)), )?; if jump { @@ -127,18 +139,19 @@ impl<'chunk, 'parent, 'stack: 'chunk + 'parent> Vm<'chunk, 'parent, 'stack> { let mut list = Vec::new(); for register_index in start_register..to_register { - let value = self.open_register(register_index, position)?; + let value = self.open_register(register_index)?; list.push(value); } - self.set_register(to_register, Register::List(list), position)?; + // self.set_register(to_register, Register::List(list))?; + + todo!() } Operation::LoadSelf => { let to_register = instruction.a(); - let function = Value::FunctionBorrowed(FunctionBorrowed::new(self.chunk)); - // self.set_register(to_register, Register::Value(function), position)?; + // self.set_register(to_register, Register::Value(function))?; todo!() } @@ -154,15 +167,12 @@ impl<'chunk, 'parent, 'stack: 'chunk + 'parent> Vm<'chunk, 'parent, 'stack> { let local_register = self.local_definitions.get(&local_index).copied().ok_or( VmError::UndefinedLocal { local_index, - position, + position: self.current_position, }, )?; + let register = Register::Pointer(Pointer::Stack(local_register)); - self.set_register( - to_register, - Register::StackPointer(local_register), - position, - )?; + self.set_register(to_register, register)?; } Operation::SetLocal => { let from_register = instruction.a(); @@ -170,71 +180,73 @@ impl<'chunk, 'parent, 'stack: 'chunk + 'parent> Vm<'chunk, 'parent, 'stack> { let local_register = self.local_definitions.get(&to_local).copied().ok_or( VmError::UndefinedLocal { local_index: to_local, - position, + position: self.current_position, }, )?; + let register = Register::Pointer(Pointer::Stack(from_register)); - self.set_register( - local_register, - Register::StackPointer(from_register), - position, - )?; + self.set_register(local_register, register)?; } Operation::Add => { let to_register = instruction.a(); - let (left, right) = self.get_arguments(instruction, position)?; - let sum = left - .add(&right) - .map_err(|error| VmError::Value { error, position })?; + let (left, right) = self.get_arguments(instruction)?; + let sum = left.add(right).map_err(|error| VmError::Value { + error, + position: self.current_position, + })?; - self.set_register(to_register, Register::Value(sum), position)?; + self.set_register(to_register, Register::Value(sum))?; } Operation::Subtract => { let to_register = instruction.a(); - let (left, right) = self.get_arguments(instruction, position)?; - let difference = left - .subtract(&right) - .map_err(|error| VmError::Value { error, position })?; + let (left, right) = self.get_arguments(instruction)?; + let difference = left.subtract(right).map_err(|error| VmError::Value { + error, + position: self.current_position, + })?; - self.set_register(to_register, Register::Value(difference), position)?; + self.set_register(to_register, Register::Value(difference))?; } Operation::Multiply => { let to_register = instruction.a(); - let (left, right) = self.get_arguments(instruction, position)?; - let product = left - .multiply(&right) - .map_err(|error| VmError::Value { error, position })?; + let (left, right) = self.get_arguments(instruction)?; + let product = left.multiply(right).map_err(|error| VmError::Value { + error, + position: self.current_position, + })?; - self.set_register(to_register, Register::Value(product), position)?; + self.set_register(to_register, Register::Value(product))?; } Operation::Divide => { let to_register = instruction.a(); - let (left, right) = self.get_arguments(instruction, position)?; - let quotient = left - .divide(&right) - .map_err(|error| VmError::Value { error, position })?; + let (left, right) = self.get_arguments(instruction)?; + let quotient = left.divide(right).map_err(|error| VmError::Value { + error, + position: self.current_position, + })?; - self.set_register(to_register, Register::Value(quotient), position)?; + self.set_register(to_register, Register::Value(quotient))?; } Operation::Modulo => { let to_register = instruction.a(); - let (left, right) = self.get_arguments(instruction, position)?; - let remainder = left - .modulo(&right) - .map_err(|error| VmError::Value { error, position })?; + let (left, right) = self.get_arguments(instruction)?; + let remainder = left.modulo(right).map_err(|error| VmError::Value { + error, + position: self.current_position, + })?; - self.set_register(to_register, Register::Value(remainder), position)?; + self.set_register(to_register, Register::Value(remainder))?; } Operation::Test => { let register = instruction.a(); let test_value = instruction.c_as_boolean(); - let value = self.open_register(register, position)?; - let boolean = if let Some(boolean) = value.as_boolean() { - boolean + let value = self.open_register(register)?; + let boolean = if let Value::Boolean(boolean) = value { + *boolean } else { return Err(VmError::ExpectedBoolean { - found: value.into_concrete(), - position, + found: value.clone(), + position: self.current_position, }); }; @@ -245,270 +257,250 @@ impl<'chunk, 'parent, 'stack: 'chunk + 'parent> Vm<'chunk, 'parent, 'stack> { Operation::TestSet => todo!(), Operation::Equal => { debug_assert_eq!( - self.get_instruction(self.ip, position)?.0.operation(), + self.get_instruction(self.ip)?.0.operation(), Operation::Jump ); let compare_to = instruction.a_as_boolean(); - let (left, right) = self.get_arguments(instruction, position)?; - let equal_result = left - .equal(&right) - .map_err(|error| VmError::Value { error, position })?; - let is_equal = if let ConcreteValue::Boolean(boolean) = equal_result { + let (left, right) = self.get_arguments(instruction)?; + let equal_result = left.equal(right).map_err(|error| VmError::Value { + error, + position: self.current_position, + })?; + let is_equal = if let Value::Boolean(boolean) = equal_result { boolean } else { return Err(VmError::ExpectedBoolean { found: equal_result.clone(), - position, + position: self.current_position, }); }; if is_equal == compare_to { self.ip += 1; } else { - let jump = self.get_instruction(self.ip, position)?.0; + let jump = self.get_instruction(self.ip)?.0; self.jump(jump); } } Operation::Less => { debug_assert_eq!( - self.get_instruction(self.ip, position)?.0.operation(), + self.get_instruction(self.ip)?.0.operation(), Operation::Jump ); let compare_to = instruction.a_as_boolean(); - let (left, right) = self.get_arguments(instruction, position)?; - let less_result = left - .less_than(&right) - .map_err(|error| VmError::Value { error, position })?; - let is_less_than = if let ConcreteValue::Boolean(boolean) = less_result { + let (left, right) = self.get_arguments(instruction)?; + let less_result = left.less_than(right).map_err(|error| VmError::Value { + error, + position: self.current_position, + })?; + let is_less_than = if let Value::Boolean(boolean) = less_result { boolean } else { return Err(VmError::ExpectedBoolean { found: less_result.clone(), - position, + position: self.current_position, }); }; if is_less_than == compare_to { self.ip += 1; } else { - let jump = self.get_instruction(self.ip, position)?.0; + let jump = self.get_instruction(self.ip)?.0; self.jump(jump); } } Operation::LessEqual => { debug_assert_eq!( - self.get_instruction(self.ip, position)?.0.operation(), + self.get_instruction(self.ip)?.0.operation(), Operation::Jump ); let compare_to = instruction.a_as_boolean(); - let (left, right) = self.get_arguments(instruction, position)?; - let less_or_equal_result = left - .less_than_or_equal(&right) - .map_err(|error| VmError::Value { error, position })?; + let (left, right) = self.get_arguments(instruction)?; + let less_or_equal_result = + left.less_than_or_equal(right) + .map_err(|error| VmError::Value { + error, + position: self.current_position, + })?; let is_less_than_or_equal = - if let ConcreteValue::Boolean(boolean) = less_or_equal_result { + if let Value::Boolean(boolean) = less_or_equal_result { boolean } else { return Err(VmError::ExpectedBoolean { found: less_or_equal_result.clone(), - position, + position: self.current_position, }); }; if is_less_than_or_equal == compare_to { self.ip += 1; } else { - let jump = self.get_instruction(self.ip, position)?.0; + let jump = self.get_instruction(self.ip)?.0; self.jump(jump); } } Operation::Negate => { - let value = - self.get_argument(instruction.b(), instruction.b_is_constant(), position)?; - let negated = value - .negate() - .map_err(|error| VmError::Value { error, position })?; + let value = self.get_argument(instruction.b(), instruction.b_is_constant())?; + let negated = value.negate().map_err(|error| VmError::Value { + error, + position: self.current_position, + })?; - self.set_register(instruction.a(), Register::Value(negated), position)?; + self.set_register(instruction.a(), Register::Value(negated))?; } Operation::Not => { - let value = - self.get_argument(instruction.b(), instruction.b_is_constant(), position)?; - let not = value - .not() - .map_err(|error| VmError::Value { error, position })?; + let value = self.get_argument(instruction.b(), instruction.b_is_constant())?; + let not = value.not().map_err(|error| VmError::Value { + error, + position: self.current_position, + })?; - self.set_register(instruction.a(), Register::Value(not), position)?; + self.set_register(instruction.a(), Register::Value(not))?; } Operation::Jump => self.jump(instruction), Operation::Call => { let to_register = instruction.a(); let function_register = instruction.b(); let argument_count = instruction.c(); - let value = self.open_register(function_register, position)?; - let function = if let Some(function) = value.as_function() { - function + let value = self.open_register(function_register)?; + let chunk = if let Value::Function(chunk) = value { + chunk } else { return Err(VmError::ExpectedFunction { - found: value.into_concrete(), - position, + found: value.clone(), + position: self.current_position, }); }; - let mut function_vm = Vm::new(function.chunk(), Some(self)); - + let has_return_value = *chunk.r#type().return_type != Type::None; + let mut function_vm = Vm::new(chunk, Some(self)); let first_argument_index = function_register + 1; + let last_argument_index = first_argument_index + argument_count; - for argument_index in - first_argument_index..first_argument_index + argument_count - { + for argument_index in first_argument_index..last_argument_index { let top_of_stack = function_vm.stack.len() as u8; function_vm.set_register( top_of_stack, - Register::ParentStackPointer(argument_index), - position, + Register::Pointer(Pointer::ParentStack(argument_index)), )? } - let return_value = function_vm.run()?; + function_vm.run()?; - if let Some(value) = return_value { - self.set_register(to_register, Register::Value(value), position)?; + if has_return_value { + let top_of_stack = function_vm.stack.len() as u8 - 1; + + self.set_register( + to_register, + Register::Pointer(Pointer::ParentStack(top_of_stack)), + )?; } } Operation::CallNative => { let native_function = NativeFunction::from(instruction.b()); - let return_value = native_function.call(self, instruction, position)?; + let return_value = native_function.call(self, instruction)?; if let Some(concrete_value) = return_value { let to_register = instruction.a(); - self.set_register(to_register, Register::Value(concrete_value), position)?; + self.set_register(to_register, Register::Value(concrete_value))?; } } Operation::Return => { let should_return_value = instruction.b_as_boolean(); if !should_return_value { - return Ok(None); + return Ok(()); } return if let Some(register_index) = self.last_assigned_register { - self.open_register(register_index, position) - .map(|value| Some(value.into_concrete())) + let top_of_stack = self.stack.len() as u8 - 1; + + if register_index != top_of_stack { + self.stack + .push(Register::Pointer(Pointer::Stack(register_index))); + } + + Ok(()) } else { - Err(VmError::StackUnderflow { position }) + Err(VmError::StackUnderflow { + position: self.current_position, + }) }; } } } - Ok(None) + Ok(()) } - pub(crate) fn open_register( - &'stack self, - register_index: u8, - position: Span, - ) -> Result<&'stack ConcreteValue, VmError> { + fn resolve_pointer(&self, pointer: Pointer) -> Result<&Value, VmError> { + match pointer { + Pointer::Stack(register_index) => self.open_register(register_index), + Pointer::Constant(constant_index) => self.get_constant(constant_index), + Pointer::ParentStack(register_index) => { + let parent = self + .parent + .as_ref() + .ok_or_else(|| VmError::ExpectedParent { + position: self.current_position, + })?; + + parent.open_register(register_index) + } + Pointer::ParentConstant(constant_index) => { + let parent = self + .parent + .as_ref() + .ok_or_else(|| VmError::ExpectedParent { + position: self.current_position, + })?; + + parent.get_constant(constant_index) + } + } + } + + pub(crate) fn open_register(&self, register_index: u8) -> Result<&Value, VmError> { let register_index = register_index as usize; let register = self.stack .get(register_index) .ok_or_else(|| VmError::RegisterIndexOutOfBounds { index: register_index, - position, + position: self.current_position, })?; log::trace!("Open R{register_index} to {register}"); match register { Register::Value(value) => Ok(value), - Register::List(list) => Ok(ConcreteValue::List( - list.into_iter() - .map(|concrete_value| (*concrete_value).clone()) - .collect(), - )), - Register::StackPointer(register_index) => self.open_register(*register_index, position), - Register::ConstantPointer(constant_index) => { - self.get_constant(*constant_index, position) - } - Register::ParentStackPointer(register_index) => { - let parent = self.parent.ok_or(VmError::ExpectedParent { position })?; - - parent.open_register(*register_index, position) - } - Register::ParentConstantPointer(constant_index) => { - let parent = self - .parent - .as_ref() - .ok_or(VmError::ExpectedParent { position })?; - let constant = parent.get_constant(*constant_index, position)?; - - Ok(constant) - } + Register::Pointer(pointer) => self.resolve_pointer(*pointer), Register::Empty => Err(VmError::EmptyRegister { index: register_index, - position, + position: self.current_position, }), } } - fn get_concrete_from_register( - &'stack self, - register_index: u8, - position: Span, - ) -> Result { - let register_index = register_index as usize; - let register = - self.stack - .get(register_index) - .ok_or_else(|| VmError::RegisterIndexOutOfBounds { - index: register_index, - position, - })?; + fn take_top_of_stack_as_value(&mut self) -> Result { + let top_of_stack = self.stack.pop().ok_or(VmError::StackUnderflow { + position: self.current_position, + })?; - let value = match register { - Register::Value(concrete_value) => concrete_value.clone(), - Register::List(list) => { - let items = list.into_iter().map(|value| (*value).clone()).collect(); - - ConcreteValue::List(items) - } - Register::StackPointer(register_index) => { - self.get_concrete_from_register(*register_index, position)? - } - Register::ConstantPointer(constant_pointer) => { - self.get_constant(*constant_pointer, position)?.clone() - } - Register::ParentStackPointer(register_index) => { - let parent = self.parent.ok_or(VmError::ExpectedParent { position })?; - - parent.get_concrete_from_register(*register_index, position)? - } - Register::ParentConstantPointer(constant_index) => { - let parent = self - .parent - .as_ref() - .ok_or(VmError::ExpectedParent { position })?; - - parent.get_constant(*constant_index, position)?.clone() - } - Register::Empty => { - return Err(VmError::EmptyRegister { - index: register_index, - position, - }) - } - }; - - Ok(value) + match top_of_stack { + Register::Value(value) => Ok(value), + _ => Err(VmError::ExpectedValue { + found: top_of_stack, + position: self.current_position, + }), + } } /// DRY helper for handling JUMP instructions @@ -524,46 +516,34 @@ impl<'chunk, 'parent, 'stack: 'chunk + 'parent> Vm<'chunk, 'parent, 'stack> { } /// DRY helper to get a constant or register values - fn get_argument( - &'stack self, - index: u8, - is_constant: bool, - position: Span, - ) -> Result, VmError> { + fn get_argument(&self, index: u8, is_constant: bool) -> Result<&Value, VmError> { let argument = if is_constant { - self.get_constant(index, position)?.as_reference_value() + self.get_constant(index)? } else { - self.open_register(index, position)? + self.open_register(index)? }; Ok(argument) } /// DRY helper to get two arguments for binary operations - fn get_arguments( - &'stack self, - instruction: Instruction, - position: Span, - ) -> Result<(Value<'stack>, Value<'stack>), VmError> { - let left = self.get_argument(instruction.b(), instruction.b_is_constant(), position)?; - let right = self.get_argument(instruction.c(), instruction.c_is_constant(), position)?; + fn get_arguments(&self, instruction: Instruction) -> Result<(&Value, &Value), VmError> { + let left = self.get_argument(instruction.b(), instruction.b_is_constant())?; + let right = self.get_argument(instruction.c(), instruction.c_is_constant())?; Ok((left, right)) } - fn set_register( - &mut self, - to_register: u8, - register: Register<'stack>, - position: Span, - ) -> Result<(), VmError> { + fn set_register(&mut self, to_register: u8, register: Register) -> Result<(), VmError> { self.last_assigned_register = Some(to_register); let length = self.stack.len(); let to_register = to_register as usize; if length == Self::STACK_LIMIT { - return Err(VmError::StackOverflow { position }); + return Err(VmError::StackOverflow { + position: self.current_position, + }); } match to_register.cmp(&length) { @@ -599,28 +579,31 @@ impl<'chunk, 'parent, 'stack: 'chunk + 'parent> Vm<'chunk, 'parent, 'stack> { } } - fn get_constant(&self, index: u8, position: Span) -> Result<&'chunk ConcreteValue, VmError> { + fn get_constant(&self, index: u8) -> Result<&Value, VmError> { self.chunk .get_constant(index) - .map_err(|error| VmError::Chunk { error, position }) + .map_err(|error| VmError::Chunk { + error, + position: self.current_position, + }) } - fn read(&mut self, position: Span) -> Result<&(Instruction, Span), VmError> { - let ip = self.ip; + fn read(&mut self) -> Result { + let (instruction, position) = *self.get_instruction(self.ip)?; self.ip += 1; + self.current_position = position; - self.get_instruction(ip, position) + Ok(instruction) } - fn get_instruction( - &self, - index: usize, - position: Span, - ) -> Result<&(Instruction, Span), VmError> { + fn get_instruction(&self, index: usize) -> Result<&(Instruction, Span), VmError> { self.chunk .get_instruction(index) - .map_err(|error| VmError::Chunk { error, position }) + .map_err(|error| VmError::Chunk { + error, + position: self.current_position, + }) } fn define_local(&mut self, local_index: u8, register_index: u8) -> Result<(), VmError> { @@ -632,39 +615,38 @@ impl<'chunk, 'parent, 'stack: 'chunk + 'parent> Vm<'chunk, 'parent, 'stack> { } } -#[derive(Debug, Eq, PartialEq)] -enum Register<'stack> { +#[derive(Clone, Debug, PartialEq)] +enum Register { Empty, - Value(ConcreteValue), - List(Vec<&'stack ConcreteValue>), - StackPointer(u8), - ConstantPointer(u8), - ParentStackPointer(u8), - ParentConstantPointer(u8), + Value(Value), + Pointer(Pointer), } -impl<'stack> Display for Register<'stack> { +impl Display for Register { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { Self::Empty => write!(f, "empty"), Self::Value(value) => write!(f, "{}", value), - Self::List(values) => { - write!(f, "[")?; + Self::Pointer(pointer) => write!(f, "{}", pointer), + } + } +} - for (index, value) in values.iter().enumerate() { - if index > 0 { - write!(f, ", ")?; - } +#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub enum Pointer { + Stack(u8), + Constant(u8), + ParentStack(u8), + ParentConstant(u8), +} - write!(f, "{}", value)?; - } - - write!(f, "]") - } - Self::StackPointer(index) => write!(f, "R{}", index), - Self::ConstantPointer(index) => write!(f, "C{}", index), - Self::ParentStackPointer(index) => write!(f, "PR{}", index), - Self::ParentConstantPointer(index) => write!(f, "PC{}", index), +impl Display for Pointer { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + Self::Stack(index) => write!(f, "R{}", index), + Self::Constant(index) => write!(f, "C{}", index), + Self::ParentStack(index) => write!(f, "PR{}", index), + Self::ParentConstant(index) => write!(f, "PC{}", index), } } } @@ -672,52 +654,26 @@ impl<'stack> Display for Register<'stack> { #[derive(Clone, Debug, PartialEq)] pub enum VmError { // Stack errors - StackOverflow { - position: Span, - }, - StackUnderflow { - position: Span, - }, + StackOverflow { position: Span }, + StackUnderflow { position: Span }, // Register errors - EmptyRegister { - index: usize, - position: Span, - }, - RegisterIndexOutOfBounds { - index: usize, - position: Span, - }, + EmptyRegister { index: usize, position: Span }, + ExpectedValue { found: Register, position: Span }, + RegisterIndexOutOfBounds { index: usize, position: Span }, // Local errors - UndefinedLocal { - local_index: u8, - position: Span, - }, + UndefinedLocal { local_index: u8, position: Span }, // Execution errors - ExpectedBoolean { - found: ConcreteValue, - position: Span, - }, - ExpectedFunction { - found: ConcreteValue, - position: Span, - }, - ExpectedParent { - position: Span, - }, + ExpectedBoolean { found: Value, position: Span }, + ExpectedFunction { found: Value, position: Span }, + ExpectedParent { position: Span }, // Wrappers for foreign errors - Chunk { - error: ChunkError, - position: Span, - }, + Chunk { error: ChunkError, position: Span }, NativeFunction(NativeFunctionError), - Value { - error: ValueError, - position: Span, - }, + Value { error: ValueError, position: Span }, } impl AnnotatedError for VmError { @@ -732,6 +688,7 @@ impl AnnotatedError for VmError { Self::ExpectedBoolean { .. } => "Expected boolean", Self::ExpectedFunction { .. } => "Expected function", Self::ExpectedParent { .. } => "Expected parent", + Self::ExpectedValue { .. } => "Expected value", Self::NativeFunction(error) => error.description(), Self::RegisterIndexOutOfBounds { .. } => "Register index out of bounds", Self::StackOverflow { .. } => "Stack overflow", @@ -763,6 +720,7 @@ impl AnnotatedError for VmError { Self::ExpectedBoolean { position, .. } => *position, Self::ExpectedFunction { position, .. } => *position, Self::ExpectedParent { position } => *position, + Self::ExpectedValue { position, .. } => *position, Self::NativeFunction(error) => error.position(), Self::RegisterIndexOutOfBounds { position, .. } => *position, Self::StackOverflow { position } => *position,