1
0

Refactor to use new instruction features

This commit is contained in:
Jeff 2024-11-28 05:02:51 -05:00
parent b574ecc4cb
commit cc6a152f3c
8 changed files with 361 additions and 119 deletions

View File

@ -50,8 +50,8 @@ use crate::{value::ConcreteValue, Chunk, Local};
const INSTRUCTION_HEADER: [&str; 4] = [ const INSTRUCTION_HEADER: [&str; 4] = [
"Instructions", "Instructions",
"------------", "------------",
" i POSITION OPERATION TYPE INFO ", " i POSITION OPERATION TYPE INFO ",
"--- ---------- ------------- -------------------------------- --------------------------------", "--- ---------- ------------- -------------- --------------------------------",
]; ];
const CONSTANT_HEADER: [&str; 4] = [ const CONSTANT_HEADER: [&str; 4] = [
@ -259,10 +259,18 @@ impl<'a> Disassembler<'a> {
{ {
let position = position.to_string(); let position = position.to_string();
let operation = instruction.operation().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 info = instruction.disassembly_info();
let instruction_display = 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); self.push_details(&instruction_display);
} }

View File

@ -30,9 +30,7 @@ use crate::{dust_error::AnnotatedError, CompileError, DustError, Span, Token};
/// ] /// ]
/// ); /// );
/// ``` /// ```
pub fn lex<'tokens, 'src: 'tokens>( pub fn lex(source: &str) -> Result<Vec<(Token, Span)>, DustError> {
source: &'src str,
) -> Result<Vec<(Token<'src>, Span)>, DustError> {
let mut lexer = Lexer::new(source); let mut lexer = Lexer::new(source);
let mut tokens = Vec::new(); let mut tokens = Vec::new();

View File

@ -18,10 +18,10 @@ use crate::{instruction::SetLocal, Chunk, Operation};
/// ``` /// ```
/// ///
/// The instructions must be in the following order: /// The instructions must be in the following order:
/// - `Operation::Equal` | `Operation::Less` | `Operation::LessEqual` | `Operation::Test` /// - `Equal`, `Less`, `LessEqual` or `Test`
/// - `Operation::Jump` /// - `Jump`
/// - `Operation::LoadBoolean` | `Operation::LoadConstant` /// - `LoadBoolean` or `LoadConstant`
/// - `Operation::LoadBoolean` | `Operation::LoadConstant` /// - `LoadBoolean` or `LoadConstant`
pub fn optimize_control_flow(chunk: &mut Chunk) { pub fn optimize_control_flow(chunk: &mut Chunk) {
if !matches!( if !matches!(
chunk.get_last_operations(), chunk.get_last_operations(),
@ -49,6 +49,24 @@ pub fn optimize_control_flow(chunk: &mut Chunk) {
*second_loader = second_loader_new; *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) { pub fn optimize_set_local(chunk: &mut Chunk) {
if !matches!( if !matches!(
chunk.get_last_operations(), chunk.get_last_operations(),

View File

@ -34,13 +34,11 @@ impl Scope {
} }
} }
#[inline]
pub fn begin(&mut self, block_index: u8) { pub fn begin(&mut self, block_index: u8) {
self.depth += 1; self.depth += 1;
self.block_index = block_index; self.block_index = block_index;
} }
#[inline]
pub fn end(&mut self, block_index: u8) { pub fn end(&mut self, block_index: u8) {
self.depth -= 1; self.depth -= 1;
self.block_index = block_index; self.block_index = block_index;

View File

@ -1,6 +1,6 @@
use std::fmt::{self, Display, Formatter}; 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)] #[derive(Debug, PartialEq, PartialOrd)]
pub enum AbstractValue { pub enum AbstractValue {
@ -9,6 +9,14 @@ pub enum AbstractValue {
} }
impl 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<ConcreteValue, VmError> { pub fn to_concrete_owned(&self, vm: &Vm) -> Result<ConcreteValue, VmError> {
match self { match self {
AbstractValue::FunctionSelf => Ok(ConcreteValue::Function(vm.chunk().clone())), AbstractValue::FunctionSelf => Ok(ConcreteValue::Function(vm.chunk().clone())),

View File

@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{Chunk, Type, ValueError}; use crate::{Chunk, Type, Value, ValueError, ValueRef};
use super::RangeValue; use super::RangeValue;
@ -20,6 +20,14 @@ pub enum ConcreteValue {
} }
impl 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<T: Into<Vec<ConcreteValue>>>(into_list: T) -> Self { pub fn list<T: Into<Vec<ConcreteValue>>>(into_list: T) -> Self {
ConcreteValue::List(into_list.into()) ConcreteValue::List(into_list.into())
} }
@ -62,7 +70,12 @@ impl ConcreteValue {
(Float(left), Float(right)) => ConcreteValue::Float(*left + *right), (Float(left), Float(right)) => ConcreteValue::Float(*left + *right),
(Integer(left), Integer(right)) => ConcreteValue::Integer(left.saturating_add(*right)), (Integer(left), Integer(right)) => ConcreteValue::Integer(left.saturating_add(*right)),
(String(left), String(right)) => ConcreteValue::string(format!("{}{}", left, 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) Ok(sum)
@ -75,7 +88,12 @@ impl ConcreteValue {
(Byte(left), Byte(right)) => ConcreteValue::Byte(left.saturating_sub(*right)), (Byte(left), Byte(right)) => ConcreteValue::Byte(left.saturating_sub(*right)),
(Float(left), Float(right)) => ConcreteValue::Float(left - right), (Float(left), Float(right)) => ConcreteValue::Float(left - right),
(Integer(left), Integer(right)) => ConcreteValue::Integer(left.saturating_sub(*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) Ok(difference)
@ -88,7 +106,12 @@ impl ConcreteValue {
(Byte(left), Byte(right)) => ConcreteValue::Byte(left.saturating_mul(*right)), (Byte(left), Byte(right)) => ConcreteValue::Byte(left.saturating_mul(*right)),
(Float(left), Float(right)) => ConcreteValue::Float(left * right), (Float(left), Float(right)) => ConcreteValue::Float(left * right),
(Integer(left), Integer(right)) => ConcreteValue::Integer(left.saturating_mul(*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) Ok(product)
@ -101,7 +124,12 @@ impl ConcreteValue {
(Byte(left), Byte(right)) => ConcreteValue::Byte(left.saturating_div(*right)), (Byte(left), Byte(right)) => ConcreteValue::Byte(left.saturating_div(*right)),
(Float(left), Float(right)) => ConcreteValue::Float(left / right), (Float(left), Float(right)) => ConcreteValue::Float(left / right),
(Integer(left), Integer(right)) => ConcreteValue::Integer(left.saturating_div(*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) Ok(quotient)
@ -116,7 +144,12 @@ impl ConcreteValue {
(Integer(left), Integer(right)) => { (Integer(left), Integer(right)) => {
ConcreteValue::Integer(left.wrapping_rem_euclid(*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) Ok(product)
@ -130,7 +163,7 @@ impl ConcreteValue {
Byte(value) => ConcreteValue::Byte(value.wrapping_neg()), Byte(value) => ConcreteValue::Byte(value.wrapping_neg()),
Float(value) => ConcreteValue::Float(-value), Float(value) => ConcreteValue::Float(-value),
Integer(value) => ConcreteValue::Integer(value.wrapping_neg()), Integer(value) => ConcreteValue::Integer(value.wrapping_neg()),
_ => return Err(ValueError::CannotNegate(self.clone())), _ => return Err(ValueError::CannotNegate(self.clone().to_value())),
}; };
Ok(negated) Ok(negated)
@ -141,7 +174,7 @@ impl ConcreteValue {
let not = match self { let not = match self {
Boolean(value) => ConcreteValue::Boolean(!value), Boolean(value) => ConcreteValue::Boolean(!value),
_ => return Err(ValueError::CannotNot(self.clone())), _ => return Err(ValueError::CannotNot(self.clone().to_value())),
}; };
Ok(not) Ok(not)
@ -160,7 +193,12 @@ impl ConcreteValue {
(List(left), List(right)) => ConcreteValue::Boolean(left == right), (List(left), List(right)) => ConcreteValue::Boolean(left == right),
(Range(left), Range(right)) => ConcreteValue::Boolean(left == right), (Range(left), Range(right)) => ConcreteValue::Boolean(left == right),
(String(left), String(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) Ok(equal)
@ -179,7 +217,12 @@ impl ConcreteValue {
(List(left), List(right)) => ConcreteValue::Boolean(left < right), (List(left), List(right)) => ConcreteValue::Boolean(left < right),
(Range(left), Range(right)) => ConcreteValue::Boolean(left < right), (Range(left), Range(right)) => ConcreteValue::Boolean(left < right),
(String(left), String(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) Ok(less_than)
@ -198,7 +241,12 @@ impl ConcreteValue {
(List(left), List(right)) => ConcreteValue::Boolean(left <= right), (List(left), List(right)) => ConcreteValue::Boolean(left <= right),
(Range(left), Range(right)) => ConcreteValue::Boolean(left <= right), (Range(left), Range(right)) => ConcreteValue::Boolean(left <= right),
(String(left), String(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) Ok(less_than_or_equal)

View File

@ -18,6 +18,13 @@ pub enum Value {
} }
impl 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<ConcreteValue, VmError> { pub fn to_concrete_owned(&self, vm: &Vm) -> Result<ConcreteValue, VmError> {
match self { match self {
Value::Abstract(abstract_value) => abstract_value.to_concrete_owned(vm), 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> { pub enum ValueRef<'a> {
Abstract(&'a AbstractValue), Abstract(&'a AbstractValue),
Concrete(&'a ConcreteValue), Concrete(&'a ConcreteValue),
} }
impl ValueRef<'_> { 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<ConcreteValue, VmError> { pub fn to_concrete_owned(&self, vm: &Vm) -> Result<ConcreteValue, VmError> {
match self { match self {
ValueRef::Abstract(abstract_value) => abstract_value.to_concrete_owned(vm), 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()), ValueRef::Concrete(concrete_value) => Ok(concrete_value.to_string()),
} }
} }
pub fn add(&self, other: ValueRef) -> Result<Value, ValueError> {
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<Value, ValueError> {
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<Value, ValueError> {
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<Value, ValueError> {
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<Value, ValueError> {
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<Value, ValueError> {
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<Value, ValueError> {
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<Value, ValueError> {
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<Value, ValueError> {
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<Value, ValueError> {
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)] #[derive(Clone, Debug, PartialEq)]
pub enum ValueError { pub enum ValueError {
CannotAdd(ConcreteValue, ConcreteValue), CannotAdd(Value, Value),
CannotAnd(ConcreteValue, ConcreteValue), CannotAnd(Value, Value),
CannotCompare(ConcreteValue, ConcreteValue), CannotCompare(Value, Value),
CannotDivide(ConcreteValue, ConcreteValue), CannotDivide(Value, Value),
CannotModulo(ConcreteValue, ConcreteValue), CannotModulo(Value, Value),
CannotMultiply(ConcreteValue, ConcreteValue), CannotMultiply(Value, Value),
CannotNegate(ConcreteValue), CannotNegate(Value),
CannotNot(ConcreteValue), CannotNot(Value),
CannotSubtract(ConcreteValue, ConcreteValue), CannotSubtract(Value, Value),
CannotOr(ConcreteValue, ConcreteValue), CannotOr(Value, Value),
} }
impl Display for ValueError { impl Display for ValueError {

View File

@ -6,8 +6,11 @@ use std::{
}; };
use crate::{ use crate::{
compile, AbstractValue, AnnotatedError, Chunk, ChunkError, ConcreteValue, DustError, compile,
Instruction, NativeFunction, NativeFunctionError, Operation, Span, Value, ValueError, ValueRef, 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<Option<ConcreteValue>, DustError> { pub fn run(source: &str) -> Result<Option<ConcreteValue>, DustError> {
@ -98,9 +101,9 @@ impl<'a> Vm<'a> {
let to_register = instruction.a(); let to_register = instruction.a();
let boolean = instruction.b_as_boolean(); let boolean = instruction.b_as_boolean();
let jump = instruction.c_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 { if jump {
self.ip += 1; self.ip += 1;
@ -135,14 +138,14 @@ impl<'a> Vm<'a> {
pointers.push(pointer); pointers.push(pointer);
} }
self.set_register( let register =
to_register, Register::Value(AbstractValue::List { items: pointers }.to_value());
Register::AbstractValue(AbstractValue::List { items: pointers }),
)?; self.set_register(to_register, register)?;
} }
Operation::LoadSelf => { Operation::LoadSelf => {
let to_register = instruction.a(); 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)?; self.set_register(to_register, register)?;
} }
@ -179,7 +182,7 @@ impl<'a> Vm<'a> {
position: self.current_position, position: self.current_position,
})?; })?;
self.set_register(to_register, Register::ConcreteValue(sum))?; self.set_register(to_register, Register::Value(sum))?;
} }
Operation::Subtract => { Operation::Subtract => {
let to_register = instruction.a(); let to_register = instruction.a();
@ -189,7 +192,7 @@ impl<'a> Vm<'a> {
position: self.current_position, position: self.current_position,
})?; })?;
self.set_register(to_register, Register::ConcreteValue(difference))?; self.set_register(to_register, Register::Value(difference))?;
} }
Operation::Multiply => { Operation::Multiply => {
let to_register = instruction.a(); let to_register = instruction.a();
@ -199,7 +202,7 @@ impl<'a> Vm<'a> {
position: self.current_position, position: self.current_position,
})?; })?;
self.set_register(to_register, Register::ConcreteValue(product))?; self.set_register(to_register, Register::Value(product))?;
} }
Operation::Divide => { Operation::Divide => {
let to_register = instruction.a(); let to_register = instruction.a();
@ -209,7 +212,7 @@ impl<'a> Vm<'a> {
position: self.current_position, position: self.current_position,
})?; })?;
self.set_register(to_register, Register::ConcreteValue(quotient))?; self.set_register(to_register, Register::Value(quotient))?;
} }
Operation::Modulo => { Operation::Modulo => {
let to_register = instruction.a(); let to_register = instruction.a();
@ -219,7 +222,7 @@ impl<'a> Vm<'a> {
position: self.current_position, position: self.current_position,
})?; })?;
self.set_register(to_register, Register::ConcreteValue(remainder))?; self.set_register(to_register, Register::Value(remainder))?;
} }
Operation::Test => { Operation::Test => {
let test_register = instruction.b(); let test_register = instruction.b();
@ -230,7 +233,7 @@ impl<'a> Vm<'a> {
*boolean *boolean
} else { } else {
return Err(VmError::ExpectedBoolean { return Err(VmError::ExpectedBoolean {
found: value.to_concrete_owned(self)?, found: value.to_owned(),
position: self.current_position, position: self.current_position,
}); });
}; };
@ -249,7 +252,7 @@ impl<'a> Vm<'a> {
*boolean *boolean
} else { } else {
return Err(VmError::ExpectedBoolean { return Err(VmError::ExpectedBoolean {
found: value.to_concrete_owned(self)?, found: value.to_owned(),
position: self.current_position, position: self.current_position,
}); });
}; };
@ -270,14 +273,15 @@ impl<'a> Vm<'a> {
error, error,
position: self.current_position, position: self.current_position,
})?; })?;
let is_equal = if let ConcreteValue::Boolean(boolean) = equal_result { let is_equal =
boolean if let Value::Concrete(ConcreteValue::Boolean(boolean)) = equal_result {
} else { boolean
return Err(VmError::ExpectedBoolean { } else {
found: equal_result.clone(), return Err(VmError::ExpectedBoolean {
position: self.current_position, found: equal_result,
}); position: self.current_position,
}; });
};
if is_equal == compare_to { if is_equal == compare_to {
self.ip += 1; self.ip += 1;
@ -294,14 +298,15 @@ impl<'a> Vm<'a> {
error, error,
position: self.current_position, position: self.current_position,
})?; })?;
let is_less_than = if let ConcreteValue::Boolean(boolean) = less_result { let is_less_than =
boolean if let Value::Concrete(ConcreteValue::Boolean(boolean)) = less_result {
} else { boolean
return Err(VmError::ExpectedBoolean { } else {
found: less_result.clone(), return Err(VmError::ExpectedBoolean {
position: self.current_position, found: less_result,
}); position: self.current_position,
}; });
};
if is_less_than == compare_to { if is_less_than == compare_to {
self.ip += 1; self.ip += 1;
@ -321,11 +326,13 @@ impl<'a> Vm<'a> {
position: self.current_position, position: self.current_position,
})?; })?;
let is_less_than_or_equal = 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 boolean
} else { } else {
return Err(VmError::ExpectedBoolean { return Err(VmError::ExpectedBoolean {
found: less_or_equal_result.clone(), found: less_or_equal_result,
position: self.current_position, position: self.current_position,
}); });
}; };
@ -339,22 +346,34 @@ impl<'a> Vm<'a> {
} }
} }
Operation::Negate => { 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 { let negated = value.negate().map_err(|error| VmError::Value {
error, error,
position: self.current_position, 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 => { 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 { let not = value.not().map_err(|error| VmError::Value {
error, error,
position: self.current_position, 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::Jump => self.jump(instruction),
Operation::Call => { Operation::Call => {
@ -382,13 +401,17 @@ impl<'a> Vm<'a> {
function_vm.set_register( function_vm.set_register(
argument_index as u16, argument_index as u16,
Register::Pointer(Pointer::ParentStack(argument_register_index)), Register::Pointer(Pointer::ParentStack(argument_register_index)),
)? )?;
function_vm.local_definitions[argument_index] = Some(argument_index as u16);
} }
let return_value = function_vm.run()?; let return_value = function_vm.run()?;
if let Some(value) = return_value { if let Some(concrete_value) = return_value {
self.set_register(to_register, Register::ConcreteValue(value))?; let register = Register::Value(concrete_value.to_value());
self.set_register(to_register, register)?;
} }
} }
Operation::CallNative => { Operation::CallNative => {
@ -397,15 +420,7 @@ impl<'a> Vm<'a> {
if let Some(value) = return_value { if let Some(value) = return_value {
let to_register = instruction.a(); let to_register = instruction.a();
let register = Register::Value(value);
let register = match value {
Value::Abstract(abstract_value) => {
Register::AbstractValue(abstract_value)
}
Value::Concrete(concrete_value) => {
Register::ConcreteValue(concrete_value)
}
};
self.set_register(to_register, register)?; self.set_register(to_register, register)?;
} }
@ -480,9 +495,8 @@ impl<'a> Vm<'a> {
log::trace!("Open R{register_index} to {register}"); log::trace!("Open R{register_index} to {register}");
match 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::Pointer(pointer) => self.follow_pointer(*pointer),
Register::AbstractValue(abstract_value) => Ok(ValueRef::Abstract(abstract_value)),
Register::Empty => Err(VmError::EmptyRegister { Register::Empty => Err(VmError::EmptyRegister {
index: register_index, index: register_index,
position: self.current_position, position: self.current_position,
@ -506,9 +520,8 @@ impl<'a> Vm<'a> {
log::trace!("Open R{register_index} to {register}"); log::trace!("Open R{register_index} to {register}");
match 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::Pointer(pointer) => self.follow_pointer(*pointer).map(Some),
Register::AbstractValue(abstract_value) => Ok(Some(ValueRef::Abstract(abstract_value))),
Register::Empty => Ok(None), Register::Empty => Ok(None),
} }
} }
@ -525,34 +538,43 @@ impl<'a> Vm<'a> {
self.ip = new_ip; self.ip = new_ip;
} }
/// DRY helper to get a constant or register values fn get_destination(&self, destination: Destination) -> Result<u16, VmError> {
fn get_argument(&self, index: u16, is_constant: bool) -> Result<&ConcreteValue, VmError> { let index = match destination {
let argument = if is_constant { Destination::Register(register_index) => register_index,
self.get_constant(index)? Destination::Local(local_index) => self
} else { .local_definitions
match self.open_register(index)? { .get(local_index as usize)
ValueRef::Concrete(concrete_value) => concrete_value, .copied()
ValueRef::Abstract(abstract_value) => { .flatten()
return Err(VmError::ExpectedConcreteValue { .ok_or_else(|| VmError::UndefinedLocal {
found: abstract_value.clone(), local_index,
position: self.current_position, position: self.current_position,
}) })?,
}
}
}; };
Ok(argument) Ok(index)
}
/// DRY helper to get a constant or register values
fn get_argument(&self, argument: Argument) -> Result<ValueRef, VmError> {
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 /// DRY helper to get two arguments for binary operations
fn get_arguments( fn get_arguments(&self, instruction: Instruction) -> Result<(ValueRef, ValueRef), VmError> {
&self, let (left, right) = instruction.b_and_c_as_arguments();
instruction: Instruction, let left_value = self.get_argument(left)?;
) -> Result<(&ConcreteValue, &ConcreteValue), VmError> { let right_value = self.get_argument(right)?;
let left = self.get_argument(instruction.b(), instruction.b_is_constant())?;
let right = self.get_argument(instruction.c(), instruction.c_is_constant())?;
Ok((left, right)) Ok((left_value, right_value))
} }
fn set_register(&mut self, to_register: u16, register: Register) -> Result<(), VmError> { 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 self.chunk
.get_constant(index) .get_constant(constant_index)
.map_err(|error| VmError::Chunk { .map_err(|error| VmError::Chunk {
error, error,
position: self.current_position, position: self.current_position,
}) })
} }
fn get_local(&self, local_index: u16) -> Result<ValueRef, VmError> {
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<Instruction, VmError> { fn read(&mut self) -> Result<Instruction, VmError> {
let (instruction, _type, position) = let (instruction, _type, position) =
self.chunk self.chunk
@ -628,8 +666,7 @@ impl<'a> Vm<'a> {
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Register { pub enum Register {
Empty, Empty,
ConcreteValue(ConcreteValue), Value(Value),
AbstractValue(AbstractValue),
Pointer(Pointer), Pointer(Pointer),
} }
@ -637,9 +674,8 @@ impl Display for Register {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
Self::Empty => write!(f, "empty"), Self::Empty => write!(f, "empty"),
Self::ConcreteValue(value) => write!(f, "{}", value), Self::Value(value) => write!(f, "{}", value),
Self::Pointer(pointer) => write!(f, "{}", pointer), Self::Pointer(pointer) => write!(f, "{}", pointer),
Self::AbstractValue(value) => write!(f, "{}", value),
} }
} }
} }
@ -699,7 +735,7 @@ pub enum VmError {
// Execution errors // Execution errors
ExpectedBoolean { ExpectedBoolean {
found: ConcreteValue, found: Value,
position: Span, position: Span,
}, },
ExpectedFunction { ExpectedFunction {