From 7b91e879b7563ad498248f5ddbfcff04199a8c49 Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 15 Nov 2024 21:42:27 -0500 Subject: [PATCH] Continue Value/VM overhaul --- dust-lang/src/chunk.rs | 14 +- dust-lang/src/compiler.rs | 24 +- dust-lang/src/disassembler.rs | 4 +- dust-lang/src/lib.rs | 4 +- dust-lang/src/native_function/logic.rs | 43 ++- dust-lang/src/native_function/mod.rs | 4 +- dust-lang/src/value/abstract_value.rs | 89 +++++ dust-lang/src/value/concrete_value.rs | 295 ++++++++++++++++ dust-lang/src/value/mod.rs | 329 +++--------------- .../src/value/{range.rs => range_value.rs} | 0 dust-lang/src/vm.rs | 192 +++++++--- 11 files changed, 619 insertions(+), 379 deletions(-) create mode 100644 dust-lang/src/value/abstract_value.rs create mode 100644 dust-lang/src/value/concrete_value.rs rename dust-lang/src/value/{range.rs => range_value.rs} (100%) diff --git a/dust-lang/src/chunk.rs b/dust-lang/src/chunk.rs index 014a093..caa62ec 100644 --- a/dust-lang/src/chunk.rs +++ b/dust-lang/src/chunk.rs @@ -8,7 +8,7 @@ use std::fmt::{self, Debug, Display, Formatter}; use serde::{Deserialize, Serialize}; -use crate::{value::Value, Disassembler, FunctionType, Instruction, Scope, Span, Type}; +use crate::{ConcreteValue, Disassembler, FunctionType, Instruction, Scope, Span, Type}; /// In-memory representation of a Dust program or function. /// @@ -19,7 +19,7 @@ pub struct Chunk { 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<&Value, ChunkError> { + pub fn get_constant(&self, index: u8) -> Result<&ConcreteValue, 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: Value) -> u8 { + pub fn push_or_get_constant(&mut self, value: ConcreteValue) -> u8 { if let Some(index) = self .constants .iter() diff --git a/dust-lang/src/compiler.rs b/dust-lang/src/compiler.rs index b93efcb..41f2f03 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::Value, AnnotatedError, Chunk, ChunkError, DustError, FunctionType, Instruction, + value::ConcreteValue, AnnotatedError, Chunk, ChunkError, DustError, FunctionType, Instruction, LexError, Lexer, Local, NativeFunction, Operation, Optimizer, Scope, Span, Token, TokenKind, TokenOwned, Type, TypeConflict, }; @@ -158,7 +158,7 @@ impl<'src> Compiler<'src> { .chunk .constants() .get(local.identifier_index as usize)?; - let identifier = if let Value::String(identifier) = constant { + let identifier = if let ConcreteValue::String(identifier) = constant { identifier } else { return None; @@ -186,7 +186,7 @@ impl<'src> Compiler<'src> { ) -> (u8, u8) { log::debug!("Declare local {identifier}"); - let identifier = Value::string(identifier); + let identifier = ConcreteValue::string(identifier); let identifier_index = self.chunk.push_or_get_constant(identifier); self.chunk @@ -368,7 +368,11 @@ impl<'src> Compiler<'src> { self.chunk.instructions_mut().push((instruction, position)); } - fn emit_constant(&mut self, constant: Value, position: Span) -> Result<(), CompileError> { + fn emit_constant( + &mut self, + constant: ConcreteValue, + position: Span, + ) -> Result<(), CompileError> { let constant_index = self.chunk.push_or_get_constant(constant); let register = self.next_register(); @@ -414,7 +418,7 @@ impl<'src> Compiler<'src> { let byte = u8::from_str_radix(&text[2..], 16) .map_err(|error| CompileError::ParseIntError { error, position })?; - let value = Value::byte(byte); + let value = ConcreteValue::byte(byte); self.emit_constant(value, position)?; @@ -436,7 +440,7 @@ impl<'src> Compiler<'src> { if let Token::Character(character) = self.current_token { self.advance()?; - let value = Value::character(character); + let value = ConcreteValue::character(character); self.emit_constant(value, position)?; @@ -464,7 +468,7 @@ impl<'src> Compiler<'src> { error, position: self.previous_position, })?; - let value = Value::float(float); + let value = ConcreteValue::float(float); self.emit_constant(value, position)?; @@ -492,7 +496,7 @@ impl<'src> Compiler<'src> { error, position: self.previous_position, })?; - let value = Value::integer(integer); + let value = ConcreteValue::integer(integer); self.emit_constant(value, position)?; @@ -514,7 +518,7 @@ impl<'src> Compiler<'src> { if let Token::String(text) = self.current_token { self.advance()?; - let value = Value::string(text); + let value = ConcreteValue::string(text); self.emit_constant(value, position)?; @@ -1472,7 +1476,7 @@ impl<'src> Compiler<'src> { value_parameters, return_type, }; - let function = Value::function(function_compiler.finish()); + let function = ConcreteValue::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 b76aeb7..528b23d 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::Value, Chunk, Local}; +use crate::{value::ConcreteValue, Chunk, Local}; const INSTRUCTION_HEADER: [&str; 4] = [ "Instructions", @@ -313,7 +313,7 @@ impl<'a> Disassembler<'a> { } for (index, value) in self.chunk.constants().iter().enumerate() { - if let Value::Function(chunk) = value { + if let ConcreteValue::Function(chunk) = value { let function_disassembly = chunk .disassembler() .styled(self.styled) diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index e87115c..9aaee78 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -29,7 +29,9 @@ 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::{Value, ValueError}; +pub use crate::value::{ + AbstractValue, ConcreteValue, RangeValue, ValueError, ValueOwned, ValueRef, +}; 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 95395c0..d3ecc25 100644 --- a/dust-lang/src/native_function/logic.rs +++ b/dust-lang/src/native_function/logic.rs @@ -1,8 +1,8 @@ use std::io::{self, stdout, Write}; -use crate::{Instruction, NativeFunctionError, Value, Vm, VmError}; +use crate::{ConcreteValue, Instruction, NativeFunctionError, ValueOwned, Vm, VmError}; -pub fn panic(vm: &Vm, instruction: Instruction) -> Result, VmError> { +pub fn panic<'a>(vm: &'a Vm<'a>, instruction: Instruction) -> Result, VmError> { let argument_count = instruction.c(); let message = if argument_count == 0 { None @@ -15,8 +15,9 @@ pub fn panic(vm: &Vm, instruction: Instruction) -> Result, VmError } let argument = vm.open_register(argument_index)?; + let argument_string = argument.display(vm)?; - message.push_str(&argument.to_string()); + message.push_str(&argument_string); } Some(message) @@ -28,7 +29,10 @@ pub fn panic(vm: &Vm, instruction: Instruction) -> Result, VmError })) } -pub fn to_string(vm: &Vm, instruction: Instruction) -> Result, VmError> { +pub fn to_string<'a>( + vm: &'a Vm<'a>, + instruction: Instruction, +) -> Result, VmError> { let argument_count = instruction.c(); if argument_count != 1 { @@ -45,14 +49,18 @@ pub fn to_string(vm: &Vm, instruction: Instruction) -> Result, VmE for argument_index in 0..argument_count { let argument = vm.open_register(argument_index)?; + let argument_string = argument.display(vm)?; - string.push_str(&argument.to_string()); + string.push_str(&argument_string); } - Ok(Some(Value::String(string))) + Ok(Some(ValueOwned::Concrete(ConcreteValue::String(string)))) } -pub fn read_line(vm: &Vm, instruction: Instruction) -> Result, VmError> { +pub fn read_line<'a>( + vm: &'a Vm<'a>, + instruction: Instruction, +) -> Result, VmError> { let argument_count = instruction.c(); if argument_count != 0 { @@ -68,9 +76,11 @@ pub fn read_line(vm: &Vm, instruction: Instruction) -> Result, VmE let mut buffer = String::new(); match io::stdin().read_line(&mut buffer) { - Ok(_) => Ok(Some(Value::String( - buffer.trim_end_matches('\n').to_string(), - ))), + Ok(_) => { + buffer = buffer.trim_end_matches('\n').to_string(); + + Ok(Some(ValueOwned::Concrete(ConcreteValue::String(buffer)))) + } Err(error) => Err(VmError::NativeFunction(NativeFunctionError::Io { error: error.kind(), position: vm.current_position(), @@ -78,7 +88,7 @@ pub fn read_line(vm: &Vm, instruction: Instruction) -> Result, VmE } } -pub fn write(vm: &Vm, instruction: Instruction) -> Result, VmError> { +pub fn write<'a>(vm: &'a Vm<'a>, instruction: Instruction) -> Result, VmError> { let to_register = instruction.a(); let argument_count = instruction.c(); let mut stdout = stdout(); @@ -96,7 +106,8 @@ pub fn write(vm: &Vm, instruction: Instruction) -> Result, VmError stdout.write(b" ").map_err(map_err)?; } - let argument_string = vm.open_register(argument_index)?.to_string(); + let argument = vm.open_register(argument_index)?; + let argument_string = argument.display(vm)?; stdout .write_all(argument_string.as_bytes()) @@ -106,7 +117,10 @@ pub fn write(vm: &Vm, instruction: Instruction) -> Result, VmError Ok(None) } -pub fn write_line(vm: &Vm, instruction: Instruction) -> Result, VmError> { +pub fn write_line<'a>( + vm: &'a Vm<'a>, + instruction: Instruction, +) -> Result, VmError> { let to_register = instruction.a(); let argument_count = instruction.c(); let mut stdout = stdout(); @@ -124,7 +138,8 @@ pub fn write_line(vm: &Vm, instruction: Instruction) -> Result, Vm stdout.write(b" ").map_err(map_err)?; } - let argument_string = vm.open_register(argument_index)?.to_string(); + let argument = vm.open_register(argument_index)?; + let argument_string = argument.display(vm)?; 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 f2058f7..886d669 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, FunctionType, Instruction, Span, Type, Value, Vm, VmError}; +use crate::{AnnotatedError, FunctionType, Instruction, Span, Type, ValueOwned, Vm, VmError}; macro_rules! define_native_function { ($(($name:ident, $byte:literal, $str:expr, $type:expr, $function:expr)),*) => { @@ -31,7 +31,7 @@ macro_rules! define_native_function { &self, vm: &mut Vm, instruction: Instruction, - ) -> Result, VmError> { + ) -> Result, VmError> { match self { $( NativeFunction::$name => $function(vm, instruction), diff --git a/dust-lang/src/value/abstract_value.rs b/dust-lang/src/value/abstract_value.rs new file mode 100644 index 0000000..50ce9e4 --- /dev/null +++ b/dust-lang/src/value/abstract_value.rs @@ -0,0 +1,89 @@ +use std::fmt::{self, Display, Formatter}; + +use crate::{vm::Pointer, ConcreteValue, Type, Vm, VmError}; + +#[derive(Debug, PartialEq, PartialOrd)] +pub enum AbstractValue { + FunctionSelf, + List { + items: Vec, + item_type: Type, + }, +} + +impl AbstractValue { + pub fn to_concrete_owned(&self, vm: &Vm) -> Result { + match self { + AbstractValue::FunctionSelf => Ok(ConcreteValue::Function(vm.chunk().clone())), + AbstractValue::List { items, .. } => { + let mut resolved_items = Vec::with_capacity(items.len()); + + for pointer in items { + let resolved_item = vm.follow_pointer(*pointer)?.to_concrete_owned(vm)?; + + resolved_items.push(resolved_item); + } + + Ok(ConcreteValue::List(resolved_items)) + } + } + } + + pub fn display(&self, vm: &Vm) -> Result { + match self { + AbstractValue::FunctionSelf => Ok("self".to_string()), + AbstractValue::List { items, .. } => { + let mut display = "[".to_string(); + + for (i, item) in items.iter().enumerate() { + if i > 0 { + display.push_str(", "); + } + + let item_display = vm.follow_pointer(*item)?.display(vm)?; + + display.push_str(&item_display); + } + + display.push_str("]"); + + Ok(display) + } + } + } +} + +impl Clone for AbstractValue { + fn clone(&self) -> Self { + log::trace!("Cloning abstract value {:?}", self); + + match self { + AbstractValue::FunctionSelf => AbstractValue::FunctionSelf, + AbstractValue::List { items, item_type } => AbstractValue::List { + items: items.clone(), + item_type: item_type.clone(), + }, + } + } +} + +impl Display for AbstractValue { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + AbstractValue::FunctionSelf => write!(f, "self"), + AbstractValue::List { items, .. } => { + write!(f, "[")?; + + for (i, item) in items.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + + write!(f, "{}", item)?; + } + + write!(f, "]") + } + } + } +} diff --git a/dust-lang/src/value/concrete_value.rs b/dust-lang/src/value/concrete_value.rs new file mode 100644 index 0000000..27cfd61 --- /dev/null +++ b/dust-lang/src/value/concrete_value.rs @@ -0,0 +1,295 @@ +use std::fmt::{self, Display, Formatter}; + +use serde::{Deserialize, Serialize}; + +use crate::{Chunk, Type, ValueError}; + +use super::RangeValue; + +#[derive(Debug, PartialEq, PartialOrd, Serialize, Deserialize)] +pub enum ConcreteValue { + Boolean(bool), + Byte(u8), + Character(char), + Float(f64), + Function(Chunk), + 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(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 r#type(&self) -> Type { + match self { + ConcreteValue::Boolean(_) => Type::Boolean, + ConcreteValue::Byte(_) => Type::Byte, + ConcreteValue::Character(_) => Type::Character, + ConcreteValue::Float(_) => Type::Float, + ConcreteValue::Function(chunk) => Type::Function(chunk.r#type().clone()), + 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), + ConcreteValue::String(string) => ConcreteValue::String(string.clone()), + } + } +} + +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, item) in list.iter().enumerate() { + if index > 0 { + write!(f, ", ")?; + } + + write!(f, "{item}")?; + } + + write!(f, "]") + } + ConcreteValue::Range(range_value) => { + write!(f, "{range_value}") + } + ConcreteValue::String(string) => write!(f, "{string}"), + } + } +} diff --git a/dust-lang/src/value/mod.rs b/dust-lang/src/value/mod.rs index 5324d98..23f1750 100644 --- a/dust-lang/src/value/mod.rs +++ b/dust-lang/src/value/mod.rs @@ -1,312 +1,71 @@ //! Runtime values used by the VM. -mod range; +mod abstract_value; +mod concrete_value; +mod range_value; -pub use range::RangeValue; +pub use abstract_value::AbstractValue; +pub use concrete_value::ConcreteValue; +pub use range_value::RangeValue; use std::fmt::{self, Debug, Display, Formatter}; -use serde::{Deserialize, Serialize}; +use crate::{Vm, VmError}; -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), +#[derive(Clone, Debug)] +pub enum ValueRef<'a> { + Abstract(&'a AbstractValue), + Concrete(&'a ConcreteValue), } -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 +impl ValueRef<'_> { + pub fn to_concrete_owned(&self, vm: &Vm) -> Result { + match self { + ValueRef::Abstract(abstract_value) => abstract_value.to_concrete_owned(vm), + ValueRef::Concrete(concrete_value) => Ok((*concrete_value).clone()), } } - pub fn r#type(&self) -> Type { + pub fn display(&self, vm: &Vm) -> Result { 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), - Value::String(string) => Value::String(string.clone()), + ValueRef::Abstract(abstract_value) => abstract_value.display(vm), + ValueRef::Concrete(concrete_value) => Ok(concrete_value.to_string()), } } } -impl Display for Value { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { +pub enum ValueOwned { + Abstract(AbstractValue), + Concrete(ConcreteValue), +} + +impl ValueOwned { + pub fn to_concrete_owned(&self, vm: &Vm) -> 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}")?; + ValueOwned::Abstract(abstract_value) => abstract_value.to_concrete_owned(vm), + ValueOwned::Concrete(concrete_value) => Ok(concrete_value.clone()), + } + } - 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}"), + pub fn display(&self, vm: &Vm) -> Result { + match self { + ValueOwned::Abstract(abstract_value) => abstract_value.display(vm), + ValueOwned::Concrete(concrete_value) => Ok(concrete_value.to_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), + 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 { diff --git a/dust-lang/src/value/range.rs b/dust-lang/src/value/range_value.rs similarity index 100% rename from dust-lang/src/value/range.rs rename to dust-lang/src/value/range_value.rs diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index 8f76371..1c0f49b 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -3,14 +3,16 @@ use std::{ cmp::Ordering, collections::HashMap, fmt::{self, Display, Formatter}, + io, }; use crate::{ - compile, value::Value, AnnotatedError, Chunk, ChunkError, DustError, Instruction, - NativeFunction, NativeFunctionError, Operation, Span, Type, ValueError, + compile, AbstractValue, AnnotatedError, Chunk, ChunkError, ConcreteValue, DustError, + Instruction, NativeFunction, NativeFunctionError, Operation, Span, Type, ValueError, + ValueOwned, ValueRef, }; -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); @@ -65,11 +67,15 @@ impl<'a> Vm<'a> { } } + pub fn chunk(&self) -> &Chunk { + self.chunk + } + pub fn current_position(&self) -> Span { self.current_position } - pub fn run(&mut self) -> Result<(), VmError> { + pub fn run(&mut self) -> Result, VmError> { while let Ok(instruction) = self.read() { log::info!( "{} | {} | {} | {}", @@ -111,9 +117,9 @@ impl<'a> Vm<'a> { let to_register = instruction.a(); let boolean = instruction.b_as_boolean(); let jump = instruction.c_as_boolean(); - let boolean = Value::boolean(boolean); + let boolean = ConcreteValue::boolean(boolean); - self.set_register(to_register, Register::Value(boolean))?; + self.set_register(to_register, Register::ConcreteValue(boolean))?; if jump { self.ip += 1; @@ -195,7 +201,7 @@ impl<'a> Vm<'a> { position: self.current_position, })?; - self.set_register(to_register, Register::Value(sum))?; + self.set_register(to_register, Register::ConcreteValue(sum))?; } Operation::Subtract => { let to_register = instruction.a(); @@ -205,7 +211,7 @@ impl<'a> Vm<'a> { position: self.current_position, })?; - self.set_register(to_register, Register::Value(difference))?; + self.set_register(to_register, Register::ConcreteValue(difference))?; } Operation::Multiply => { let to_register = instruction.a(); @@ -215,7 +221,7 @@ impl<'a> Vm<'a> { position: self.current_position, })?; - self.set_register(to_register, Register::Value(product))?; + self.set_register(to_register, Register::ConcreteValue(product))?; } Operation::Divide => { let to_register = instruction.a(); @@ -225,7 +231,7 @@ impl<'a> Vm<'a> { position: self.current_position, })?; - self.set_register(to_register, Register::Value(quotient))?; + self.set_register(to_register, Register::ConcreteValue(quotient))?; } Operation::Modulo => { let to_register = instruction.a(); @@ -235,17 +241,18 @@ impl<'a> Vm<'a> { position: self.current_position, })?; - self.set_register(to_register, Register::Value(remainder))?; + self.set_register(to_register, Register::ConcreteValue(remainder))?; } Operation::Test => { let register = instruction.a(); let test_value = instruction.c_as_boolean(); let value = self.open_register(register)?; - let boolean = if let Value::Boolean(boolean) = value { + let boolean = if let ValueRef::Concrete(ConcreteValue::Boolean(boolean)) = value + { *boolean } else { return Err(VmError::ExpectedBoolean { - found: value.clone(), + found: value.to_concrete_owned(self)?, position: self.current_position, }); }; @@ -267,7 +274,7 @@ impl<'a> Vm<'a> { error, position: self.current_position, })?; - let is_equal = if let Value::Boolean(boolean) = equal_result { + let is_equal = if let ConcreteValue::Boolean(boolean) = equal_result { boolean } else { return Err(VmError::ExpectedBoolean { @@ -296,7 +303,7 @@ impl<'a> Vm<'a> { error, position: self.current_position, })?; - let is_less_than = if let Value::Boolean(boolean) = less_result { + let is_less_than = if let ConcreteValue::Boolean(boolean) = less_result { boolean } else { return Err(VmError::ExpectedBoolean { @@ -328,7 +335,7 @@ impl<'a> Vm<'a> { position: self.current_position, })?; let is_less_than_or_equal = - if let Value::Boolean(boolean) = less_or_equal_result { + if let ConcreteValue::Boolean(boolean) = less_or_equal_result { boolean } else { return Err(VmError::ExpectedBoolean { @@ -352,7 +359,7 @@ impl<'a> Vm<'a> { position: self.current_position, })?; - self.set_register(instruction.a(), Register::Value(negated))?; + self.set_register(instruction.a(), Register::ConcreteValue(negated))?; } Operation::Not => { let value = self.get_argument(instruction.b(), instruction.b_is_constant())?; @@ -361,7 +368,7 @@ impl<'a> Vm<'a> { position: self.current_position, })?; - self.set_register(instruction.a(), Register::Value(not))?; + self.set_register(instruction.a(), Register::ConcreteValue(not))?; } Operation::Jump => self.jump(instruction), Operation::Call => { @@ -369,11 +376,13 @@ impl<'a> Vm<'a> { let function_register = instruction.b(); let argument_count = instruction.c(); let value = self.open_register(function_register)?; - let chunk = if let Value::Function(chunk) = value { + let chunk = if let ValueRef::Concrete(ConcreteValue::Function(chunk)) = value { chunk + } else if let ValueRef::Abstract(AbstractValue::FunctionSelf) = value { + self.chunk } else { return Err(VmError::ExpectedFunction { - found: value.clone(), + found: value.to_concrete_owned(self)?, position: self.current_position, }); }; @@ -406,28 +415,32 @@ impl<'a> Vm<'a> { let native_function = NativeFunction::from(instruction.b()); let return_value = native_function.call(self, instruction)?; - if let Some(concrete_value) = return_value { + if let Some(value) = return_value { let to_register = instruction.a(); - self.set_register(to_register, Register::Value(concrete_value))?; + let register = match value { + ValueOwned::Abstract(abstract_value) => { + Register::AbstractValue(abstract_value) + } + ValueOwned::Concrete(concrete_value) => { + Register::ConcreteValue(concrete_value) + } + }; + + self.set_register(to_register, register)?; } } Operation::Return => { let should_return_value = instruction.b_as_boolean(); if !should_return_value { - return Ok(()); + return Ok(None); } return if let Some(register_index) = self.last_assigned_register { - let top_of_stack = self.stack.len() as u8 - 1; + let value_ref = self.open_register(register_index)?; - if register_index != top_of_stack { - self.stack - .push(Register::Pointer(Pointer::Stack(register_index))); - } - - Ok(()) + Ok(Some(value_ref)) } else { Err(VmError::StackUnderflow { position: self.current_position, @@ -437,13 +450,17 @@ impl<'a> Vm<'a> { } } - Ok(()) + Ok(None) } - fn resolve_pointer(&self, pointer: Pointer) -> Result<&Value, VmError> { + pub(crate) fn follow_pointer(&self, pointer: Pointer) -> Result { match pointer { Pointer::Stack(register_index) => self.open_register(register_index), - Pointer::Constant(constant_index) => self.get_constant(constant_index), + Pointer::Constant(constant_index) => { + let constant = self.get_constant(constant_index)?; + + Ok(ValueRef::Concrete(constant)) + } Pointer::ParentStack(register_index) => { let parent = self .parent @@ -461,13 +478,14 @@ impl<'a> Vm<'a> { .ok_or_else(|| VmError::ExpectedParent { position: self.current_position, })?; + let constant = parent.get_constant(constant_index)?; - parent.get_constant(constant_index) + Ok(ValueRef::Concrete(constant)) } } } - pub(crate) fn open_register(&self, register_index: u8) -> Result<&Value, VmError> { + pub(crate) fn open_register(&self, register_index: u8) -> Result { let register_index = register_index as usize; let register = self.stack @@ -480,8 +498,9 @@ impl<'a> Vm<'a> { log::trace!("Open R{register_index} to {register}"); match register { - Register::Value(value) => Ok(value), - Register::Pointer(pointer) => self.resolve_pointer(*pointer), + Register::ConcreteValue(value) => Ok(ValueRef::Concrete(value)), + Register::Pointer(pointer) => self.follow_pointer(*pointer), + Register::AbstractValue(abstract_value) => Ok(ValueRef::Abstract(abstract_value)), Register::Empty => Err(VmError::EmptyRegister { index: register_index, position: self.current_position, @@ -489,13 +508,13 @@ impl<'a> Vm<'a> { } } - fn take_top_of_stack_as_value(&mut self) -> Result { + 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, })?; match top_of_stack { - Register::Value(value) => Ok(value), + Register::ConcreteValue(value) => Ok(value), _ => Err(VmError::ExpectedValue { found: top_of_stack, position: self.current_position, @@ -516,18 +535,29 @@ impl<'a> Vm<'a> { } /// DRY helper to get a constant or register values - fn get_argument(&self, index: u8, is_constant: bool) -> Result<&Value, VmError> { + fn get_argument(&self, index: u8, is_constant: bool) -> Result<&ConcreteValue, VmError> { let argument = if is_constant { self.get_constant(index)? } else { - self.open_register(index)? + match self.open_register(index)? { + ValueRef::Concrete(concrete_value) => concrete_value, + ValueRef::Abstract(abstract_value) => { + return Err(VmError::ExpectedConcreteValue { + found: abstract_value.clone(), + position: self.current_position, + }) + } + } }; Ok(argument) } /// DRY helper to get two arguments for binary operations - fn get_arguments(&self, instruction: Instruction) -> Result<(&Value, &Value), VmError> { + fn get_arguments( + &self, + instruction: Instruction, + ) -> Result<(&ConcreteValue, &ConcreteValue), VmError> { let left = self.get_argument(instruction.b(), instruction.b_is_constant())?; let right = self.get_argument(instruction.c(), instruction.c_is_constant())?; @@ -579,7 +609,7 @@ impl<'a> Vm<'a> { } } - fn get_constant(&self, index: u8) -> Result<&Value, VmError> { + fn get_constant(&self, index: u8) -> Result<&ConcreteValue, VmError> { self.chunk .get_constant(index) .map_err(|error| VmError::Chunk { @@ -589,7 +619,7 @@ impl<'a> Vm<'a> { } fn read(&mut self) -> Result { - let (instruction, position) = *self.get_instruction(self.ip)?; + let (instruction, position) = self.get_instruction(self.ip)?; self.ip += 1; self.current_position = position; @@ -597,9 +627,10 @@ impl<'a> Vm<'a> { Ok(instruction) } - fn get_instruction(&self, index: usize) -> Result<&(Instruction, Span), VmError> { + fn get_instruction(&self, index: usize) -> Result<(Instruction, Span), VmError> { self.chunk .get_instruction(index) + .copied() .map_err(|error| VmError::Chunk { error, position: self.current_position, @@ -618,16 +649,18 @@ impl<'a> Vm<'a> { #[derive(Clone, Debug, PartialEq)] pub enum Register { Empty, - Value(Value), + ConcreteValue(ConcreteValue), Pointer(Pointer), + AbstractValue(AbstractValue), } 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::ConcreteValue(value) => write!(f, "{}", value), Self::Pointer(pointer) => write!(f, "{}", pointer), + Self::AbstractValue(value) => write!(f, "{}", value), } } } @@ -654,26 +687,64 @@ impl Display for Pointer { #[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 }, - ExpectedValue { found: Register, position: Span }, - RegisterIndexOutOfBounds { index: usize, position: Span }, + EmptyRegister { + index: usize, + position: Span, + }, + ExpectedConcreteValue { + found: AbstractValue, + 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: Value, position: Span }, - ExpectedFunction { found: Value, position: Span }, - ExpectedParent { position: Span }, + ExpectedBoolean { + found: ConcreteValue, + position: Span, + }, + ExpectedFunction { + found: ConcreteValue, + position: Span, + }, + ExpectedParent { + position: Span, + }, + ValueDisplay { + error: io::ErrorKind, + 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 { @@ -686,6 +757,7 @@ impl AnnotatedError for VmError { Self::Chunk { .. } => "Chunk error", Self::EmptyRegister { .. } => "Empty register", Self::ExpectedBoolean { .. } => "Expected boolean", + Self::ExpectedConcreteValue { .. } => "Expected concrete value", Self::ExpectedFunction { .. } => "Expected function", Self::ExpectedParent { .. } => "Expected parent", Self::ExpectedValue { .. } => "Expected value", @@ -695,6 +767,7 @@ impl AnnotatedError for VmError { Self::StackUnderflow { .. } => "Stack underflow", Self::UndefinedLocal { .. } => "Undefined local", Self::Value { .. } => "Value error", + Self::ValueDisplay { .. } => "Value display error", } } @@ -709,6 +782,7 @@ impl AnnotatedError for VmError { } Self::NativeFunction(error) => error.details(), Self::Value { error, .. } => Some(error.to_string()), + Self::ValueDisplay { error, .. } => Some(error.to_string() + " while displaying value"), _ => None, } } @@ -718,6 +792,7 @@ impl AnnotatedError for VmError { Self::Chunk { position, .. } => *position, Self::EmptyRegister { position, .. } => *position, Self::ExpectedBoolean { position, .. } => *position, + Self::ExpectedConcreteValue { position, .. } => *position, Self::ExpectedFunction { position, .. } => *position, Self::ExpectedParent { position } => *position, Self::ExpectedValue { position, .. } => *position, @@ -727,6 +802,7 @@ impl AnnotatedError for VmError { Self::StackUnderflow { position } => *position, Self::UndefinedLocal { position, .. } => *position, Self::Value { position, .. } => *position, + Self::ValueDisplay { position, .. } => *position, } } }