From cc6a152f3c86a7ae78faf8e8f3381354cbe787ed Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 28 Nov 2024 05:02:51 -0500 Subject: [PATCH] Refactor to use new instruction features --- dust-lang/src/disassembler.rs | 16 +- dust-lang/src/lexer.rs | 4 +- dust-lang/src/optimize.rs | 26 +++- dust-lang/src/scope.rs | 2 - dust-lang/src/value/abstract_value.rs | 10 +- dust-lang/src/value/concrete_value.rs | 70 +++++++-- dust-lang/src/value/mod.rs | 150 +++++++++++++++++-- dust-lang/src/vm.rs | 202 +++++++++++++++----------- 8 files changed, 361 insertions(+), 119 deletions(-) diff --git a/dust-lang/src/disassembler.rs b/dust-lang/src/disassembler.rs index 619e39c..9e4bfef 100644 --- a/dust-lang/src/disassembler.rs +++ b/dust-lang/src/disassembler.rs @@ -50,8 +50,8 @@ use crate::{value::ConcreteValue, Chunk, Local}; const INSTRUCTION_HEADER: [&str; 4] = [ "Instructions", "------------", - " i POSITION OPERATION TYPE INFO ", - "--- ---------- ------------- -------------------------------- --------------------------------", + " i POSITION OPERATION TYPE INFO ", + "--- ---------- ------------- -------------- --------------------------------", ]; const CONSTANT_HEADER: [&str; 4] = [ @@ -259,10 +259,18 @@ impl<'a> Disassembler<'a> { { let position = position.to_string(); let operation = instruction.operation().to_string(); - let r#type = r#type.to_string(); + let type_display = { + let mut type_string = r#type.to_string(); + + if type_string.len() > 14 { + type_string = format!("{type_string:.11}..."); + } + + type_string + }; let info = instruction.disassembly_info(); let instruction_display = - format!("{index:^3} {position:^10} {operation:13} {type:^32} {info:^32}"); + format!("{index:^3} {position:^10} {operation:13} {type_display:^14} {info:^32}"); self.push_details(&instruction_display); } diff --git a/dust-lang/src/lexer.rs b/dust-lang/src/lexer.rs index 8811d2b..604b907 100644 --- a/dust-lang/src/lexer.rs +++ b/dust-lang/src/lexer.rs @@ -30,9 +30,7 @@ use crate::{dust_error::AnnotatedError, CompileError, DustError, Span, Token}; /// ] /// ); /// ``` -pub fn lex<'tokens, 'src: 'tokens>( - source: &'src str, -) -> Result, Span)>, DustError> { +pub fn lex(source: &str) -> Result, DustError> { let mut lexer = Lexer::new(source); let mut tokens = Vec::new(); diff --git a/dust-lang/src/optimize.rs b/dust-lang/src/optimize.rs index 2d454c5..fecc510 100644 --- a/dust-lang/src/optimize.rs +++ b/dust-lang/src/optimize.rs @@ -18,10 +18,10 @@ use crate::{instruction::SetLocal, Chunk, Operation}; /// ``` /// /// The instructions must be in the following order: -/// - `Operation::Equal` | `Operation::Less` | `Operation::LessEqual` | `Operation::Test` -/// - `Operation::Jump` -/// - `Operation::LoadBoolean` | `Operation::LoadConstant` -/// - `Operation::LoadBoolean` | `Operation::LoadConstant` +/// - `Equal`, `Less`, `LessEqual` or `Test` +/// - `Jump` +/// - `LoadBoolean` or `LoadConstant` +/// - `LoadBoolean` or `LoadConstant` pub fn optimize_control_flow(chunk: &mut Chunk) { if !matches!( chunk.get_last_operations(), @@ -49,6 +49,24 @@ pub fn optimize_control_flow(chunk: &mut Chunk) { *second_loader = second_loader_new; } +/// Optimizes a math instruction followed by a SetLocal instruction. +/// +/// The SetLocal instruction is removed and the math instruction is modified to use the local as +/// its destination. This makes the following two code snippets compile to the same bytecode: +/// +/// ```dust +/// let a = 0; +/// a = a + 1; +/// ``` +/// +/// ```dust +/// let a = 0; +/// a += 1; +/// ``` +/// +/// The instructions must be in the following order: +/// - `Add`, `Subtract`, `Multiply`, `Divide` or `Modulo` +/// - `SetLocal` pub fn optimize_set_local(chunk: &mut Chunk) { if !matches!( chunk.get_last_operations(), diff --git a/dust-lang/src/scope.rs b/dust-lang/src/scope.rs index fd9f5c0..4e84988 100644 --- a/dust-lang/src/scope.rs +++ b/dust-lang/src/scope.rs @@ -34,13 +34,11 @@ impl Scope { } } - #[inline] pub fn begin(&mut self, block_index: u8) { self.depth += 1; self.block_index = block_index; } - #[inline] pub fn end(&mut self, block_index: u8) { self.depth -= 1; self.block_index = block_index; diff --git a/dust-lang/src/value/abstract_value.rs b/dust-lang/src/value/abstract_value.rs index 6b91958..6d59096 100644 --- a/dust-lang/src/value/abstract_value.rs +++ b/dust-lang/src/value/abstract_value.rs @@ -1,6 +1,6 @@ use std::fmt::{self, Display, Formatter}; -use crate::{vm::Pointer, ConcreteValue, Vm, VmError}; +use crate::{vm::Pointer, ConcreteValue, Value, ValueRef, Vm, VmError}; #[derive(Debug, PartialEq, PartialOrd)] pub enum AbstractValue { @@ -9,6 +9,14 @@ pub enum AbstractValue { } impl AbstractValue { + pub fn to_value(self) -> Value { + Value::Abstract(self) + } + + pub fn to_value_ref(&self) -> ValueRef { + ValueRef::Abstract(self) + } + pub fn to_concrete_owned(&self, vm: &Vm) -> Result { match self { AbstractValue::FunctionSelf => Ok(ConcreteValue::Function(vm.chunk().clone())), diff --git a/dust-lang/src/value/concrete_value.rs b/dust-lang/src/value/concrete_value.rs index e23abd3..fae26c0 100644 --- a/dust-lang/src/value/concrete_value.rs +++ b/dust-lang/src/value/concrete_value.rs @@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter}; use serde::{Deserialize, Serialize}; -use crate::{Chunk, Type, ValueError}; +use crate::{Chunk, Type, Value, ValueError, ValueRef}; use super::RangeValue; @@ -20,6 +20,14 @@ pub enum ConcreteValue { } impl ConcreteValue { + pub fn to_value(self) -> Value { + Value::Concrete(self) + } + + pub fn to_value_ref(&self) -> ValueRef { + ValueRef::Concrete(self) + } + pub fn list>>(into_list: T) -> Self { ConcreteValue::List(into_list.into()) } @@ -62,7 +70,12 @@ impl ConcreteValue { (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())), + _ => { + return Err(ValueError::CannotAdd( + self.clone().to_value(), + other.clone().to_value(), + )) + } }; Ok(sum) @@ -75,7 +88,12 @@ impl ConcreteValue { (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())), + _ => { + return Err(ValueError::CannotSubtract( + self.clone().to_value(), + other.clone().to_value(), + )) + } }; Ok(difference) @@ -88,7 +106,12 @@ impl ConcreteValue { (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())), + _ => { + return Err(ValueError::CannotMultiply( + self.clone().to_value(), + other.clone().to_value(), + )) + } }; Ok(product) @@ -101,7 +124,12 @@ impl ConcreteValue { (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())), + _ => { + return Err(ValueError::CannotMultiply( + self.clone().to_value(), + other.clone().to_value(), + )) + } }; Ok(quotient) @@ -116,7 +144,12 @@ impl ConcreteValue { (Integer(left), Integer(right)) => { ConcreteValue::Integer(left.wrapping_rem_euclid(*right)) } - _ => return Err(ValueError::CannotMultiply(self.clone(), other.clone())), + _ => { + return Err(ValueError::CannotMultiply( + self.clone().to_value(), + other.clone().to_value(), + )) + } }; Ok(product) @@ -130,7 +163,7 @@ impl ConcreteValue { 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())), + _ => return Err(ValueError::CannotNegate(self.clone().to_value())), }; Ok(negated) @@ -141,7 +174,7 @@ impl ConcreteValue { let not = match self { Boolean(value) => ConcreteValue::Boolean(!value), - _ => return Err(ValueError::CannotNot(self.clone())), + _ => return Err(ValueError::CannotNot(self.clone().to_value())), }; Ok(not) @@ -160,7 +193,12 @@ impl ConcreteValue { (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())), + _ => { + return Err(ValueError::CannotCompare( + self.clone().to_value(), + other.clone().to_value(), + )) + } }; Ok(equal) @@ -179,7 +217,12 @@ impl ConcreteValue { (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())), + _ => { + return Err(ValueError::CannotCompare( + self.clone().to_value(), + other.clone().to_value(), + )) + } }; Ok(less_than) @@ -198,7 +241,12 @@ impl ConcreteValue { (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())), + _ => { + return Err(ValueError::CannotCompare( + self.clone().to_value(), + other.clone().to_value(), + )) + } }; Ok(less_than_or_equal) diff --git a/dust-lang/src/value/mod.rs b/dust-lang/src/value/mod.rs index 5378c36..5d8b04a 100644 --- a/dust-lang/src/value/mod.rs +++ b/dust-lang/src/value/mod.rs @@ -18,6 +18,13 @@ pub enum Value { } impl Value { + pub fn to_ref(&self) -> ValueRef { + match self { + Value::Abstract(abstract_value) => ValueRef::Abstract(abstract_value), + Value::Concrete(concrete_value) => ValueRef::Concrete(concrete_value), + } + } + pub fn to_concrete_owned(&self, vm: &Vm) -> Result { match self { Value::Abstract(abstract_value) => abstract_value.to_concrete_owned(vm), @@ -33,13 +40,29 @@ impl Value { } } -#[derive(Clone, Debug, PartialEq, PartialOrd)] +impl Display for Value { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + Value::Abstract(abstract_value) => write!(f, "{}", abstract_value), + Value::Concrete(concrete_value) => write!(f, "{}", concrete_value), + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] pub enum ValueRef<'a> { Abstract(&'a AbstractValue), Concrete(&'a ConcreteValue), } impl ValueRef<'_> { + pub fn to_owned(&self) -> Value { + match self { + ValueRef::Abstract(abstract_value) => Value::Abstract((*abstract_value).clone()), + ValueRef::Concrete(concrete_value) => Value::Concrete((*concrete_value).clone()), + } + } + pub fn to_concrete_owned(&self, vm: &Vm) -> Result { match self { ValueRef::Abstract(abstract_value) => abstract_value.to_concrete_owned(vm), @@ -53,20 +76,125 @@ impl ValueRef<'_> { ValueRef::Concrete(concrete_value) => Ok(concrete_value.to_string()), } } + + pub fn add(&self, other: ValueRef) -> Result { + match (self, other) { + (ValueRef::Concrete(left), ValueRef::Concrete(right)) => { + left.add(right).map(|result| result.to_value()) + } + _ => Err(ValueError::CannotAdd(self.to_owned(), other.to_owned())), + } + } + + pub fn subtract(&self, other: ValueRef) -> Result { + match (self, other) { + (ValueRef::Concrete(left), ValueRef::Concrete(right)) => { + left.subtract(right).map(|result| result.to_value()) + } + _ => Err(ValueError::CannotSubtract( + self.to_owned(), + other.to_owned(), + )), + } + } + + pub fn multiply(&self, other: ValueRef) -> Result { + match (self, other) { + (ValueRef::Concrete(left), ValueRef::Concrete(right)) => { + left.multiply(right).map(|result| result.to_value()) + } + _ => Err(ValueError::CannotMultiply( + self.to_owned(), + other.to_owned(), + )), + } + } + + pub fn divide(&self, other: ValueRef) -> Result { + match (self, other) { + (ValueRef::Concrete(left), ValueRef::Concrete(right)) => { + left.divide(right).map(|result| result.to_value()) + } + _ => Err(ValueError::CannotDivide(self.to_owned(), other.to_owned())), + } + } + + pub fn modulo(&self, other: ValueRef) -> Result { + match (self, other) { + (ValueRef::Concrete(left), ValueRef::Concrete(right)) => { + left.modulo(right).map(|result| result.to_value()) + } + _ => Err(ValueError::CannotModulo(self.to_owned(), other.to_owned())), + } + } + + pub fn negate(&self) -> Result { + match self { + ValueRef::Concrete(concrete_value) => { + concrete_value.negate().map(|result| result.to_value()) + } + _ => Err(ValueError::CannotNegate(self.to_owned())), + } + } + + pub fn not(&self) -> Result { + match self { + ValueRef::Concrete(concrete_value) => { + concrete_value.not().map(|result| result.to_value()) + } + _ => Err(ValueError::CannotNot(self.to_owned())), + } + } + + pub fn equal(&self, other: ValueRef) -> Result { + match (self, other) { + (ValueRef::Concrete(left), ValueRef::Concrete(right)) => { + left.equal(right).map(|result| result.to_value()) + } + _ => Err(ValueError::CannotCompare(self.to_owned(), other.to_owned())), + } + } + + pub fn less_than(&self, other: ValueRef) -> Result { + match (self, other) { + (ValueRef::Concrete(left), ValueRef::Concrete(right)) => { + left.less_than(right).map(|result| result.to_value()) + } + _ => Err(ValueError::CannotCompare(self.to_owned(), other.to_owned())), + } + } + + pub fn less_than_or_equal(&self, other: ValueRef) -> Result { + match (self, other) { + (ValueRef::Concrete(left), ValueRef::Concrete(right)) => left + .less_than_or_equal(right) + .map(|result| result.to_value()), + _ => Err(ValueError::CannotCompare(self.to_owned(), other.to_owned())), + } + } +} + +impl Display for ValueRef<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + ValueRef::Abstract(abstract_value) => write!(f, "{}", abstract_value), + ValueRef::Concrete(concrete_value) => write!(f, "{}", concrete_value), + } + } } #[derive(Clone, Debug, PartialEq)] pub enum ValueError { - CannotAdd(ConcreteValue, ConcreteValue), - CannotAnd(ConcreteValue, ConcreteValue), - CannotCompare(ConcreteValue, ConcreteValue), - CannotDivide(ConcreteValue, ConcreteValue), - CannotModulo(ConcreteValue, ConcreteValue), - CannotMultiply(ConcreteValue, ConcreteValue), - CannotNegate(ConcreteValue), - CannotNot(ConcreteValue), - CannotSubtract(ConcreteValue, ConcreteValue), - CannotOr(ConcreteValue, ConcreteValue), + CannotAdd(Value, Value), + CannotAnd(Value, Value), + CannotCompare(Value, Value), + CannotDivide(Value, Value), + CannotModulo(Value, Value), + CannotMultiply(Value, Value), + CannotNegate(Value), + CannotNot(Value), + CannotSubtract(Value, Value), + CannotOr(Value, Value), } impl Display for ValueError { diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index 9c726d0..0103b47 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -6,8 +6,11 @@ use std::{ }; use crate::{ - compile, AbstractValue, AnnotatedError, Chunk, ChunkError, ConcreteValue, DustError, - Instruction, NativeFunction, NativeFunctionError, Operation, Span, Value, ValueError, ValueRef, + compile, + instruction::{Negate, Not}, + AbstractValue, AnnotatedError, Argument, Chunk, ChunkError, ConcreteValue, Destination, + DustError, Instruction, NativeFunction, NativeFunctionError, Operation, Span, Value, + ValueError, ValueRef, }; pub fn run(source: &str) -> Result, DustError> { @@ -98,9 +101,9 @@ impl<'a> Vm<'a> { let to_register = instruction.a(); let boolean = instruction.b_as_boolean(); let jump = instruction.c_as_boolean(); - let boolean = ConcreteValue::Boolean(boolean); + let boolean = ConcreteValue::Boolean(boolean).to_value(); - self.set_register(to_register, Register::ConcreteValue(boolean))?; + self.set_register(to_register, Register::Value(boolean))?; if jump { self.ip += 1; @@ -135,14 +138,14 @@ impl<'a> Vm<'a> { pointers.push(pointer); } - self.set_register( - to_register, - Register::AbstractValue(AbstractValue::List { items: pointers }), - )?; + let register = + Register::Value(AbstractValue::List { items: pointers }.to_value()); + + self.set_register(to_register, register)?; } Operation::LoadSelf => { let to_register = instruction.a(); - let register = Register::AbstractValue(AbstractValue::FunctionSelf); + let register = Register::Value(AbstractValue::FunctionSelf.to_value()); self.set_register(to_register, register)?; } @@ -179,7 +182,7 @@ impl<'a> Vm<'a> { position: self.current_position, })?; - self.set_register(to_register, Register::ConcreteValue(sum))?; + self.set_register(to_register, Register::Value(sum))?; } Operation::Subtract => { let to_register = instruction.a(); @@ -189,7 +192,7 @@ impl<'a> Vm<'a> { position: self.current_position, })?; - self.set_register(to_register, Register::ConcreteValue(difference))?; + self.set_register(to_register, Register::Value(difference))?; } Operation::Multiply => { let to_register = instruction.a(); @@ -199,7 +202,7 @@ impl<'a> Vm<'a> { position: self.current_position, })?; - self.set_register(to_register, Register::ConcreteValue(product))?; + self.set_register(to_register, Register::Value(product))?; } Operation::Divide => { let to_register = instruction.a(); @@ -209,7 +212,7 @@ impl<'a> Vm<'a> { position: self.current_position, })?; - self.set_register(to_register, Register::ConcreteValue(quotient))?; + self.set_register(to_register, Register::Value(quotient))?; } Operation::Modulo => { let to_register = instruction.a(); @@ -219,7 +222,7 @@ impl<'a> Vm<'a> { position: self.current_position, })?; - self.set_register(to_register, Register::ConcreteValue(remainder))?; + self.set_register(to_register, Register::Value(remainder))?; } Operation::Test => { let test_register = instruction.b(); @@ -230,7 +233,7 @@ impl<'a> Vm<'a> { *boolean } else { return Err(VmError::ExpectedBoolean { - found: value.to_concrete_owned(self)?, + found: value.to_owned(), position: self.current_position, }); }; @@ -249,7 +252,7 @@ impl<'a> Vm<'a> { *boolean } else { return Err(VmError::ExpectedBoolean { - found: value.to_concrete_owned(self)?, + found: value.to_owned(), position: self.current_position, }); }; @@ -270,14 +273,15 @@ impl<'a> Vm<'a> { error, position: self.current_position, })?; - let is_equal = if let ConcreteValue::Boolean(boolean) = equal_result { - boolean - } else { - return Err(VmError::ExpectedBoolean { - found: equal_result.clone(), - position: self.current_position, - }); - }; + let is_equal = + if let Value::Concrete(ConcreteValue::Boolean(boolean)) = equal_result { + boolean + } else { + return Err(VmError::ExpectedBoolean { + found: equal_result, + position: self.current_position, + }); + }; if is_equal == compare_to { self.ip += 1; @@ -294,14 +298,15 @@ impl<'a> Vm<'a> { error, position: self.current_position, })?; - let is_less_than = if let ConcreteValue::Boolean(boolean) = less_result { - boolean - } else { - return Err(VmError::ExpectedBoolean { - found: less_result.clone(), - position: self.current_position, - }); - }; + let is_less_than = + if let Value::Concrete(ConcreteValue::Boolean(boolean)) = less_result { + boolean + } else { + return Err(VmError::ExpectedBoolean { + found: less_result, + position: self.current_position, + }); + }; if is_less_than == compare_to { self.ip += 1; @@ -321,11 +326,13 @@ impl<'a> Vm<'a> { position: self.current_position, })?; let is_less_than_or_equal = - if let ConcreteValue::Boolean(boolean) = less_or_equal_result { + if let Value::Concrete(ConcreteValue::Boolean(boolean)) = + less_or_equal_result + { boolean } else { return Err(VmError::ExpectedBoolean { - found: less_or_equal_result.clone(), + found: less_or_equal_result, position: self.current_position, }); }; @@ -339,22 +346,34 @@ impl<'a> Vm<'a> { } } Operation::Negate => { - let value = self.get_argument(instruction.b(), instruction.b_is_constant())?; + let Negate { + destination, + argument, + } = Negate::from(&instruction); + let value = self.get_argument(argument)?; let negated = value.negate().map_err(|error| VmError::Value { error, position: self.current_position, })?; + let register_index = self.get_destination(destination)?; + let register = Register::Value(negated); - self.set_register(instruction.a(), Register::ConcreteValue(negated))?; + self.set_register(register_index, register)?; } Operation::Not => { - let value = self.get_argument(instruction.b(), instruction.b_is_constant())?; + let Not { + destination, + argument, + } = Not::from(&instruction); + let value = self.get_argument(argument)?; let not = value.not().map_err(|error| VmError::Value { error, position: self.current_position, })?; + let register_index = self.get_destination(destination)?; + let register = Register::Value(not); - self.set_register(instruction.a(), Register::ConcreteValue(not))?; + self.set_register(register_index, register)?; } Operation::Jump => self.jump(instruction), Operation::Call => { @@ -382,13 +401,17 @@ impl<'a> Vm<'a> { function_vm.set_register( argument_index as u16, Register::Pointer(Pointer::ParentStack(argument_register_index)), - )? + )?; + + function_vm.local_definitions[argument_index] = Some(argument_index as u16); } let return_value = function_vm.run()?; - if let Some(value) = return_value { - self.set_register(to_register, Register::ConcreteValue(value))?; + if let Some(concrete_value) = return_value { + let register = Register::Value(concrete_value.to_value()); + + self.set_register(to_register, register)?; } } Operation::CallNative => { @@ -397,15 +420,7 @@ impl<'a> Vm<'a> { if let Some(value) = return_value { let to_register = instruction.a(); - - let register = match value { - Value::Abstract(abstract_value) => { - Register::AbstractValue(abstract_value) - } - Value::Concrete(concrete_value) => { - Register::ConcreteValue(concrete_value) - } - }; + let register = Register::Value(value); self.set_register(to_register, register)?; } @@ -480,9 +495,8 @@ impl<'a> Vm<'a> { log::trace!("Open R{register_index} to {register}"); match register { - Register::ConcreteValue(value) => Ok(ValueRef::Concrete(value)), + Register::Value(value) => Ok(value.to_ref()), 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, @@ -506,9 +520,8 @@ impl<'a> Vm<'a> { log::trace!("Open R{register_index} to {register}"); match register { - Register::ConcreteValue(value) => Ok(Some(ValueRef::Concrete(value))), + Register::Value(value) => Ok(Some(value.to_ref())), Register::Pointer(pointer) => self.follow_pointer(*pointer).map(Some), - Register::AbstractValue(abstract_value) => Ok(Some(ValueRef::Abstract(abstract_value))), Register::Empty => Ok(None), } } @@ -525,34 +538,43 @@ impl<'a> Vm<'a> { self.ip = new_ip; } - /// DRY helper to get a constant or register values - fn get_argument(&self, index: u16, is_constant: bool) -> Result<&ConcreteValue, VmError> { - let argument = if is_constant { - self.get_constant(index)? - } else { - 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, - }) - } - } + fn get_destination(&self, destination: Destination) -> Result { + let index = match destination { + Destination::Register(register_index) => register_index, + Destination::Local(local_index) => self + .local_definitions + .get(local_index as usize) + .copied() + .flatten() + .ok_or_else(|| VmError::UndefinedLocal { + local_index, + position: self.current_position, + })?, }; - Ok(argument) + Ok(index) + } + + /// DRY helper to get a constant or register values + fn get_argument(&self, argument: Argument) -> Result { + let value_ref = match argument { + Argument::Constant(constant_index) => { + ValueRef::Concrete(self.get_constant(constant_index)?) + } + Argument::Register(register_index) => self.open_register(register_index)?, + Argument::Local(local_index) => self.get_local(local_index)?, + }; + + Ok(value_ref) } /// DRY helper to get two arguments for binary operations - 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())?; + fn get_arguments(&self, instruction: Instruction) -> Result<(ValueRef, ValueRef), VmError> { + let (left, right) = instruction.b_and_c_as_arguments(); + let left_value = self.get_argument(left)?; + let right_value = self.get_argument(right)?; - Ok((left, right)) + Ok((left_value, right_value)) } fn set_register(&mut self, to_register: u16, register: Register) -> Result<(), VmError> { @@ -600,15 +622,31 @@ impl<'a> Vm<'a> { } } - fn get_constant(&self, index: u16) -> Result<&ConcreteValue, VmError> { + fn get_constant(&self, constant_index: u16) -> Result<&ConcreteValue, VmError> { self.chunk - .get_constant(index) + .get_constant(constant_index) .map_err(|error| VmError::Chunk { error, position: self.current_position, }) } + fn get_local(&self, local_index: u16) -> Result { + let register_index = self + .local_definitions + .get(local_index as usize) + .ok_or_else(|| VmError::UndefinedLocal { + local_index, + position: self.current_position, + })? + .ok_or_else(|| VmError::UndefinedLocal { + local_index, + position: self.current_position, + })?; + + self.open_register(register_index) + } + fn read(&mut self) -> Result { let (instruction, _type, position) = self.chunk @@ -628,8 +666,7 @@ impl<'a> Vm<'a> { #[derive(Clone, Debug, PartialEq)] pub enum Register { Empty, - ConcreteValue(ConcreteValue), - AbstractValue(AbstractValue), + Value(Value), Pointer(Pointer), } @@ -637,9 +674,8 @@ impl Display for Register { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { Self::Empty => write!(f, "empty"), - Self::ConcreteValue(value) => write!(f, "{}", value), + Self::Value(value) => write!(f, "{}", value), Self::Pointer(pointer) => write!(f, "{}", pointer), - Self::AbstractValue(value) => write!(f, "{}", value), } } } @@ -699,7 +735,7 @@ pub enum VmError { // Execution errors ExpectedBoolean { - found: ConcreteValue, + found: Value, position: Span, }, ExpectedFunction {