Refactor to use new instruction features
This commit is contained in:
parent
b574ecc4cb
commit
cc6a152f3c
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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(),
|
||||||
|
@ -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;
|
||||||
|
@ -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())),
|
||||||
|
@ -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)
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user