Continue Value/VM overhaul
This commit is contained in:
parent
69458a138d
commit
7b91e879b7
@ -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<Value>,
|
||||
constants: Vec<ConcreteValue>,
|
||||
locals: Vec<Local>,
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ impl Chunk {
|
||||
pub fn with_data(
|
||||
name: Option<String>,
|
||||
instructions: Vec<(Instruction, Span)>,
|
||||
constants: Vec<Value>,
|
||||
constants: Vec<ConcreteValue>,
|
||||
locals: Vec<Local>,
|
||||
) -> Self {
|
||||
Self {
|
||||
@ -77,15 +77,15 @@ impl Chunk {
|
||||
self.instructions.is_empty()
|
||||
}
|
||||
|
||||
pub fn constants(&self) -> &Vec<Value> {
|
||||
pub fn constants(&self) -> &Vec<ConcreteValue> {
|
||||
&self.constants
|
||||
}
|
||||
|
||||
pub fn constants_mut(&mut self) -> &mut Vec<Value> {
|
||||
pub fn constants_mut(&mut self) -> &mut Vec<ConcreteValue> {
|
||||
&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()
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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<Option<Value>, VmError> {
|
||||
pub fn panic<'a>(vm: &'a Vm<'a>, instruction: Instruction) -> Result<Option<ValueOwned>, 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<Option<Value>, 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<Option<Value>, VmError
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn to_string(vm: &Vm, instruction: Instruction) -> Result<Option<Value>, VmError> {
|
||||
pub fn to_string<'a>(
|
||||
vm: &'a Vm<'a>,
|
||||
instruction: Instruction,
|
||||
) -> Result<Option<ValueOwned>, VmError> {
|
||||
let argument_count = instruction.c();
|
||||
|
||||
if argument_count != 1 {
|
||||
@ -45,14 +49,18 @@ pub fn to_string(vm: &Vm, instruction: Instruction) -> Result<Option<Value>, 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<Option<Value>, VmError> {
|
||||
pub fn read_line<'a>(
|
||||
vm: &'a Vm<'a>,
|
||||
instruction: Instruction,
|
||||
) -> Result<Option<ValueOwned>, VmError> {
|
||||
let argument_count = instruction.c();
|
||||
|
||||
if argument_count != 0 {
|
||||
@ -68,9 +76,11 @@ pub fn read_line(vm: &Vm, instruction: Instruction) -> Result<Option<Value>, 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<Option<Value>, VmE
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(vm: &Vm, instruction: Instruction) -> Result<Option<Value>, VmError> {
|
||||
pub fn write<'a>(vm: &'a Vm<'a>, instruction: Instruction) -> Result<Option<ValueOwned>, 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<Option<Value>, 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<Option<Value>, VmError
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn write_line(vm: &Vm, instruction: Instruction) -> Result<Option<Value>, VmError> {
|
||||
pub fn write_line<'a>(
|
||||
vm: &'a Vm<'a>,
|
||||
instruction: Instruction,
|
||||
) -> Result<Option<ValueOwned>, 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<Option<Value>, 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())
|
||||
|
@ -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<Option<Value>, VmError> {
|
||||
) -> Result<Option<ValueOwned>, VmError> {
|
||||
match self {
|
||||
$(
|
||||
NativeFunction::$name => $function(vm, instruction),
|
||||
|
89
dust-lang/src/value/abstract_value.rs
Normal file
89
dust-lang/src/value/abstract_value.rs
Normal file
@ -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<Pointer>,
|
||||
item_type: Type,
|
||||
},
|
||||
}
|
||||
|
||||
impl AbstractValue {
|
||||
pub fn to_concrete_owned(&self, vm: &Vm) -> Result<ConcreteValue, VmError> {
|
||||
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<String, VmError> {
|
||||
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, "]")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
295
dust-lang/src/value/concrete_value.rs
Normal file
295
dust-lang/src/value/concrete_value.rs
Normal file
@ -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<ConcreteValue>),
|
||||
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<T: Into<i64>>(into_i64: T) -> Self {
|
||||
ConcreteValue::Integer(into_i64.into())
|
||||
}
|
||||
|
||||
pub fn list<T: Into<Vec<ConcreteValue>>>(into_list: T) -> Self {
|
||||
ConcreteValue::List(into_list.into())
|
||||
}
|
||||
|
||||
pub fn range(range: RangeValue) -> Self {
|
||||
ConcreteValue::Range(range)
|
||||
}
|
||||
|
||||
pub fn string<T: ToString>(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<ConcreteValue, ValueError> {
|
||||
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<ConcreteValue, ValueError> {
|
||||
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<ConcreteValue, ValueError> {
|
||||
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<ConcreteValue, ValueError> {
|
||||
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<ConcreteValue, ValueError> {
|
||||
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<ConcreteValue, ValueError> {
|
||||
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<ConcreteValue, ValueError> {
|
||||
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<ConcreteValue, ValueError> {
|
||||
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<ConcreteValue, ValueError> {
|
||||
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<ConcreteValue, ValueError> {
|
||||
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}"),
|
||||
}
|
||||
}
|
||||
}
|
@ -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<Value>),
|
||||
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<T: Into<i64>>(into_i64: T) -> Self {
|
||||
Value::Integer(into_i64.into())
|
||||
}
|
||||
|
||||
pub fn list<T: Into<Vec<Value>>>(into_list: T) -> Self {
|
||||
Value::List(into_list.into())
|
||||
}
|
||||
|
||||
pub fn range(range: RangeValue) -> Self {
|
||||
Value::Range(range)
|
||||
}
|
||||
|
||||
pub fn string<T: ToString>(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 {
|
||||
impl ValueRef<'_> {
|
||||
pub fn to_concrete_owned(&self, vm: &Vm) -> Result<ConcreteValue, VmError> {
|
||||
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()),
|
||||
},
|
||||
ValueRef::Abstract(abstract_value) => abstract_value.to_concrete_owned(vm),
|
||||
ValueRef::Concrete(concrete_value) => Ok((*concrete_value).clone()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(&self, other: &Self) -> Result<Value, ValueError> {
|
||||
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<Value, ValueError> {
|
||||
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<Value, ValueError> {
|
||||
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<Value, ValueError> {
|
||||
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<Value, ValueError> {
|
||||
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<Value, ValueError> {
|
||||
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<Value, ValueError> {
|
||||
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<Value, ValueError> {
|
||||
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<Value, ValueError> {
|
||||
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<Value, ValueError> {
|
||||
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);
|
||||
|
||||
pub fn display(&self, vm: &Vm) -> Result<String, VmError> {
|
||||
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<ConcreteValue, VmError> {
|
||||
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")?;
|
||||
ValueOwned::Abstract(abstract_value) => abstract_value.to_concrete_owned(vm),
|
||||
ValueOwned::Concrete(concrete_value) => Ok(concrete_value.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
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<String, VmError> {
|
||||
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 {
|
||||
|
@ -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<Option<Value>, DustError> {
|
||||
pub fn run(source: &str) -> Result<Option<ConcreteValue>, 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<Option<ValueRef>, 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<ValueRef, VmError> {
|
||||
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<ValueRef, VmError> {
|
||||
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<Value, VmError> {
|
||||
fn take_top_of_stack_as_value(&mut self) -> Result<ConcreteValue, VmError> {
|
||||
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<Instruction, VmError> {
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user