1
0

Continue VM optimizations

This commit is contained in:
Jeff 2024-12-14 08:49:02 -05:00
parent cd4fa6bef5
commit ec5033a32f
13 changed files with 175 additions and 239 deletions

View File

@ -46,7 +46,7 @@ use std::{
use colored::{ColoredString, Colorize};
use crate::{value::ConcreteValue, Chunk, Local};
use crate::{value::ConcreteValue, Chunk, Local, Value};
const INSTRUCTION_COLUMNS: [(&str, usize); 4] =
[("i", 5), ("POSITION", 12), ("OPERATION", 17), ("INFO", 24)];
@ -336,7 +336,7 @@ impl<'a, W: Write> Disassembler<'a, W> {
self.write_centered_with_border(CONSTANT_BORDERS[1])?;
for (index, value) in self.chunk.constants().iter().enumerate() {
let is_function = matches!(value, ConcreteValue::Function(_));
let is_function = matches!(value, Value::Concrete(ConcreteValue::Function(_)));
let type_display = value.r#type().to_string();
let value_display = if is_function {
"Function displayed below".to_string()
@ -353,7 +353,7 @@ impl<'a, W: Write> Disassembler<'a, W> {
self.write_centered_with_border(&constant_display)?;
if let ConcreteValue::Function(chunk) = value {
if let Value::Concrete(ConcreteValue::Function(chunk)) = value {
let function_disassembler = chunk
.disassembler(self.writer)
.style(self.style)

View File

@ -17,7 +17,7 @@ use std::io::Write;
use serde::{Deserialize, Serialize};
use smallvec::SmallVec;
use crate::{ConcreteValue, DustString, FunctionType, Instruction, Span};
use crate::{ConcreteValue, DustString, FunctionType, Instruction, Span, Value};
/// In-memory representation of a Dust program or function.
///
@ -28,7 +28,7 @@ pub struct Chunk {
r#type: FunctionType,
instructions: SmallVec<[(Instruction, Span); 32]>,
constants: SmallVec<[ConcreteValue; 16]>,
constants: SmallVec<[Value; 16]>,
locals: SmallVec<[Local; 8]>,
stack_size: usize,
@ -39,7 +39,7 @@ impl Chunk {
name: Option<DustString>,
r#type: FunctionType,
instructions: SmallVec<[(Instruction, Span); 32]>,
constants: SmallVec<[ConcreteValue; 16]>,
constants: SmallVec<[Value; 16]>,
locals: SmallVec<[Local; 8]>,
stack_size: usize,
) -> Self {
@ -57,7 +57,7 @@ impl Chunk {
name: Option<DustString>,
r#type: FunctionType,
instructions: impl Into<SmallVec<[(Instruction, Span); 32]>>,
constants: impl Into<SmallVec<[ConcreteValue; 16]>>,
constants: impl Into<SmallVec<[Value; 16]>>,
locals: impl Into<SmallVec<[Local; 8]>>,
) -> Self {
Self {
@ -82,7 +82,7 @@ impl Chunk {
self.instructions.is_empty()
}
pub fn constants(&self) -> &SmallVec<[ConcreteValue; 16]> {
pub fn constants(&self) -> &SmallVec<[Value; 16]> {
&self.constants
}

View File

@ -24,7 +24,7 @@ use crate::{
Not, Return, SetLocal, Test,
},
Argument, Chunk, ConcreteValue, DustError, DustString, FunctionType, Instruction, Lexer, Local,
NativeFunction, Operation, Scope, Span, Token, TokenKind, Type,
NativeFunction, Operation, Scope, Span, Token, TokenKind, Type, Value,
};
/// Compiles the input and returns a chunk.
@ -58,7 +58,7 @@ pub fn compile(source: &str) -> Result<Chunk, DustError> {
pub struct Compiler<'src> {
self_name: Option<DustString>,
instructions: SmallVec<[(Instruction, Type, Span); 32]>,
constants: SmallVec<[ConcreteValue; 16]>,
constants: SmallVec<[Value; 16]>,
locals: SmallVec<[(Local, Type); 8]>,
stack_size: usize,
@ -203,7 +203,8 @@ impl<'src> Compiler<'src> {
.rev()
.find_map(|(index, (local, _))| {
let constant = self.constants.get(local.identifier_index as usize)?;
let identifier = if let ConcreteValue::String(identifier) = constant {
let identifier =
if let Value::Concrete(ConcreteValue::String(identifier)) = constant {
identifier
} else {
return None;
@ -231,7 +232,7 @@ impl<'src> Compiler<'src> {
) -> (u8, u8) {
log::info!("Declaring local {identifier}");
let identifier = ConcreteValue::string(identifier);
let identifier = Value::Concrete(ConcreteValue::string(identifier));
let identifier_index = self.push_or_get_constant(identifier);
let local_index = self.locals.len() as u8;
@ -253,7 +254,7 @@ impl<'src> Compiler<'src> {
})
}
fn push_or_get_constant(&mut self, value: ConcreteValue) -> u8 {
fn push_or_get_constant(&mut self, value: Value) -> u8 {
if let Some(index) = self
.constants
.iter()
@ -405,7 +406,7 @@ impl<'src> Compiler<'src> {
position: Span,
) -> Result<(), CompileError> {
let r#type = constant.r#type();
let constant_index = self.push_or_get_constant(constant);
let constant_index = self.push_or_get_constant(Value::Concrete(constant));
let destination = self.next_register();
let load_constant = Instruction::load_constant(destination, constant_index, false);
@ -1618,7 +1619,7 @@ impl<'src> Compiler<'src> {
let function_end = function_compiler.previous_position.1;
let chunk = function_compiler.finish(None, value_parameters.clone());
let function = ConcreteValue::function(chunk);
let function = Value::Concrete(ConcreteValue::function(chunk));
let constant_index = self.push_or_get_constant(function);
let destination = self.next_register();
let function_type = FunctionType {

View File

@ -47,9 +47,7 @@ pub use crate::lexer::{lex, LexError, Lexer};
pub use crate::native_function::{NativeFunction, NativeFunctionError};
pub use crate::r#type::{EnumType, FunctionType, StructType, Type, TypeConflict};
pub use crate::token::{Token, TokenKind, TokenOwned};
pub use crate::value::{
AbstractValue, ConcreteValue, DustString, RangeValue, Value, ValueError, ValueRef,
};
pub use crate::value::{AbstractValue, ConcreteValue, DustString, RangeValue, Value, ValueError};
pub use crate::vm::{run, Vm, VmError};
use std::fmt::Display;

View File

@ -3,11 +3,11 @@ use std::panic;
use annotate_snippets::{Level, Renderer, Snippet};
use smallvec::SmallVec;
use crate::{DustString, NativeFunctionError, Value, ValueRef, Vm};
use crate::{DustString, NativeFunctionError, Value, Vm};
pub fn panic(
vm: &Vm,
arguments: SmallVec<[ValueRef; 4]>,
arguments: SmallVec<[&Value; 4]>,
) -> Result<Option<Value>, NativeFunctionError> {
let mut message: Option<DustString> = None;

View File

@ -2,12 +2,9 @@ use std::io::{stdin, stdout, Write};
use smallvec::SmallVec;
use crate::{ConcreteValue, NativeFunctionError, Value, ValueRef, Vm};
use crate::{ConcreteValue, NativeFunctionError, Value, Vm};
pub fn read_line(
vm: &Vm,
_: SmallVec<[ValueRef; 4]>,
) -> Result<Option<Value>, NativeFunctionError> {
pub fn read_line(vm: &Vm, _: SmallVec<[&Value; 4]>) -> Result<Option<Value>, NativeFunctionError> {
let mut buffer = String::new();
match stdin().read_line(&mut buffer) {
@ -27,7 +24,7 @@ pub fn read_line(
pub fn write(
vm: &Vm,
arguments: SmallVec<[ValueRef; 4]>,
arguments: SmallVec<[&Value; 4]>,
) -> Result<Option<Value>, NativeFunctionError> {
let mut stdout = stdout();
@ -50,7 +47,7 @@ pub fn write(
pub fn write_line(
vm: &Vm,
arguments: SmallVec<[ValueRef; 4]>,
arguments: SmallVec<[&Value; 4]>,
) -> Result<Option<Value>, NativeFunctionError> {
let mut stdout = stdout();

View File

@ -15,7 +15,7 @@ use std::{
use serde::{Deserialize, Serialize};
use smallvec::{smallvec, SmallVec};
use crate::{AnnotatedError, FunctionType, Span, Type, Value, ValueRef, Vm, VmError};
use crate::{AnnotatedError, FunctionType, Span, Type, Value, Vm, VmError};
macro_rules! define_native_function {
($(($name:ident, $bytes:literal, $str:expr, $type:expr, $function:expr)),*) => {
@ -33,7 +33,7 @@ macro_rules! define_native_function {
pub fn call<'a>(
&self,
vm: &Vm<'a>,
arguments: SmallVec<[ValueRef<'a>; 4]>,
arguments: SmallVec<[&Value; 4]>,
) -> Result<Option<Value>, NativeFunctionError> {
match self {
$(

View File

@ -1,10 +1,10 @@
use smallvec::SmallVec;
use crate::{ConcreteValue, NativeFunctionError, Value, ValueRef, Vm};
use crate::{ConcreteValue, NativeFunctionError, Value, Vm};
pub fn to_string(
vm: &Vm,
arguments: SmallVec<[ValueRef; 4]>,
arguments: SmallVec<[&Value; 4]>,
) -> Result<Option<Value>, NativeFunctionError> {
if arguments.len() != 1 {
return Err(NativeFunctionError::ExpectedArgumentCount {

View File

@ -1,11 +1,14 @@
use std::fmt::{self, Display, Formatter};
use crate::{vm::Pointer, ConcreteValue, DustString, Value, ValueRef, Vm, VmError};
use crate::{vm::Pointer, ConcreteValue, DustString, Type, Value, Vm, VmError};
#[derive(Debug, PartialEq, PartialOrd)]
pub enum AbstractValue {
FunctionSelf,
List { item_pointers: Vec<Pointer> },
List {
item_type: Type,
item_pointers: Vec<Pointer>,
},
}
impl AbstractValue {
@ -13,10 +16,6 @@ impl AbstractValue {
Value::Abstract(self)
}
pub fn to_value_ref(&self) -> ValueRef {
ValueRef::Abstract(self)
}
pub fn to_concrete_owned(&self, vm: &Vm) -> ConcreteValue {
match self {
AbstractValue::FunctionSelf => ConcreteValue::function(vm.chunk().clone()),
@ -26,7 +25,7 @@ impl AbstractValue {
for pointer in item_pointers {
let item_option = vm.follow_pointer_allow_empty(*pointer);
let item = match item_option {
Some(value_ref) => value_ref.into_concrete_owned(vm),
Some(value) => value.clone().into_concrete_owned(vm),
None => continue,
};
@ -65,6 +64,13 @@ impl AbstractValue {
Ok(display)
}
pub fn r#type(&self) -> Type {
match self {
AbstractValue::FunctionSelf => Type::SelfChunk,
AbstractValue::List { item_type, .. } => Type::List(Box::new(item_type.clone())),
}
}
}
impl Clone for AbstractValue {
@ -74,8 +80,10 @@ impl Clone for AbstractValue {
match self {
AbstractValue::FunctionSelf => AbstractValue::FunctionSelf,
AbstractValue::List {
item_type: r#type,
item_pointers: items,
} => AbstractValue::List {
item_type: r#type.clone(),
item_pointers: items.clone(),
},
}

View File

@ -3,7 +3,7 @@ use std::fmt::{self, Display, Formatter};
use serde::{Deserialize, Serialize};
use smartstring::{LazyCompact, SmartString};
use crate::{Chunk, Type, Value, ValueError, ValueRef};
use crate::{Chunk, Type, Value, ValueError};
use super::RangeValue;
@ -27,10 +27,6 @@ impl ConcreteValue {
Value::Concrete(self)
}
pub fn to_value_ref(&self) -> ValueRef {
ValueRef::Concrete(self)
}
pub fn function(chunk: Chunk) -> Self {
ConcreteValue::Function(Box::new(chunk))
}

View File

@ -6,25 +6,20 @@ mod range_value;
pub use abstract_value::AbstractValue;
pub use concrete_value::{ConcreteValue, DustString};
pub use range_value::RangeValue;
use serde::{Deserialize, Serialize};
use std::fmt::{self, Debug, Display, Formatter};
use crate::{Vm, VmError};
use crate::{Type, Vm, VmError};
#[derive(Clone, Debug, PartialEq, PartialOrd)]
#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
pub enum Value {
#[serde(skip)]
Abstract(AbstractValue),
Concrete(ConcreteValue),
}
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 into_concrete_owned(self, vm: &Vm) -> ConcreteValue {
match self {
Value::Abstract(abstract_value) => abstract_value.to_concrete_owned(vm),
@ -39,58 +34,24 @@ impl Value {
None
}
}
}
impl Display for Value {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
pub fn r#type(&self) -> Type {
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()),
Value::Abstract(abstract_value) => abstract_value.r#type(),
Value::Concrete(concrete_value) => concrete_value.r#type(),
}
}
pub fn into_concrete_owned(self, vm: &Vm) -> ConcreteValue {
match self {
ValueRef::Abstract(abstract_value) => abstract_value.to_concrete_owned(vm),
ValueRef::Concrete(concrete_value) => concrete_value.clone(),
}
}
pub fn display(&self, vm: &Vm) -> Result<DustString, VmError> {
match self {
ValueRef::Abstract(abstract_value) => abstract_value.to_dust_string(vm),
ValueRef::Concrete(concrete_value) => Ok(concrete_value.to_dust_string()),
}
}
#[inline(always)]
pub fn add(&self, other: ValueRef) -> Result<Value, ValueError> {
pub fn add(&self, other: &Value) -> Result<Value, ValueError> {
match (self, other) {
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
left.add(right).map(Value::Concrete)
}
(Value::Concrete(left), Value::Concrete(right)) => left.add(right).map(Value::Concrete),
_ => Err(ValueError::CannotAdd(self.to_owned(), other.to_owned())),
}
}
pub fn subtract(&self, other: ValueRef) -> Result<Value, ValueError> {
pub fn subtract(&self, other: &Value) -> Result<Value, ValueError> {
match (self, other) {
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
(Value::Concrete(left), Value::Concrete(right)) => {
left.subtract(right).map(Value::Concrete)
}
_ => Err(ValueError::CannotSubtract(
@ -100,9 +61,9 @@ impl ValueRef<'_> {
}
}
pub fn multiply(&self, other: ValueRef) -> Result<Value, ValueError> {
pub fn multiply(&self, other: &Value) -> Result<Value, ValueError> {
match (self, other) {
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
(Value::Concrete(left), Value::Concrete(right)) => {
left.multiply(right).map(Value::Concrete)
}
_ => Err(ValueError::CannotMultiply(
@ -112,18 +73,18 @@ impl ValueRef<'_> {
}
}
pub fn divide(&self, other: ValueRef) -> Result<Value, ValueError> {
pub fn divide(&self, other: &Value) -> Result<Value, ValueError> {
match (self, other) {
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
(Value::Concrete(left), Value::Concrete(right)) => {
left.divide(right).map(Value::Concrete)
}
_ => Err(ValueError::CannotDivide(self.to_owned(), other.to_owned())),
}
}
pub fn modulo(&self, other: ValueRef) -> Result<Value, ValueError> {
pub fn modulo(&self, other: &Value) -> Result<Value, ValueError> {
match (self, other) {
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
(Value::Concrete(left), Value::Concrete(right)) => {
left.modulo(right).map(Value::Concrete)
}
_ => Err(ValueError::CannotModulo(self.to_owned(), other.to_owned())),
@ -132,51 +93,58 @@ impl ValueRef<'_> {
pub fn negate(&self) -> Result<Value, ValueError> {
match self {
ValueRef::Concrete(concrete_value) => concrete_value.negate().map(Value::Concrete),
Value::Concrete(concrete_value) => concrete_value.negate().map(Value::Concrete),
_ => Err(ValueError::CannotNegate(self.to_owned())),
}
}
pub fn not(&self) -> Result<Value, ValueError> {
match self {
ValueRef::Concrete(concrete_value) => concrete_value.not().map(Value::Concrete),
Value::Concrete(concrete_value) => concrete_value.not().map(Value::Concrete),
_ => Err(ValueError::CannotNot(self.to_owned())),
}
}
pub fn equal(&self, other: ValueRef) -> Result<Value, ValueError> {
pub fn equal(&self, other: &Value) -> Result<Value, ValueError> {
match (self, other) {
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
(Value::Concrete(left), Value::Concrete(right)) => {
left.equal(right).map(Value::Concrete)
}
_ => Err(ValueError::CannotCompare(self.to_owned(), other.to_owned())),
}
}
pub fn less(&self, other: ValueRef) -> Result<Value, ValueError> {
pub fn less(&self, other: &Value) -> Result<Value, ValueError> {
match (self, other) {
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
(Value::Concrete(left), Value::Concrete(right)) => {
left.less_than(right).map(Value::Concrete)
}
_ => Err(ValueError::CannotCompare(self.to_owned(), other.to_owned())),
}
}
pub fn less_equal(&self, other: ValueRef) -> Result<Value, ValueError> {
pub fn less_equal(&self, other: &Value) -> Result<Value, ValueError> {
match (self, other) {
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
(Value::Concrete(left), Value::Concrete(right)) => {
left.less_than_or_equal(right).map(Value::Concrete)
}
_ => Err(ValueError::CannotCompare(self.to_owned(), other.to_owned())),
}
}
pub fn display(&self, vm: &Vm) -> Result<DustString, VmError> {
match self {
Value::Abstract(abstract_value) => abstract_value.to_dust_string(vm),
Value::Concrete(concrete_value) => Ok(concrete_value.to_dust_string()),
}
}
}
impl Display for ValueRef<'_> {
impl Display for Value {
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),
Value::Abstract(abstract_value) => write!(f, "{}", abstract_value),
Value::Concrete(concrete_value) => write!(f, "{}", concrete_value),
}
}
}

View File

@ -4,6 +4,7 @@ mod runners;
use std::{
fmt::{self, Display, Formatter},
io, iter,
rc::Rc,
};
use runners::Runner;
@ -11,10 +12,10 @@ use smallvec::SmallVec;
use crate::{
compile, instruction::*, AbstractValue, AnnotatedError, Chunk, ConcreteValue, DustError,
NativeFunctionError, Span, Value, ValueError, ValueRef,
NativeFunctionError, Span, Value, ValueError,
};
pub fn run(source: &str) -> Result<Option<ConcreteValue>, DustError> {
pub fn run(source: &str) -> Result<Option<Value>, DustError> {
let chunk = compile(source)?;
let vm = Vm::new(source, &chunk, None, None);
@ -35,7 +36,7 @@ pub struct Vm<'a> {
ip: usize,
last_assigned_register: Option<u8>,
source: &'a str,
return_value: Option<ConcreteValue>,
return_value: Option<Value>,
}
impl<'a> Vm<'a> {
@ -85,26 +86,31 @@ impl<'a> Vm<'a> {
position
}
pub fn run(mut self) -> Option<ConcreteValue> {
pub fn run(mut self) -> Option<Value> {
while self.ip < self.runners.len() && self.return_value.is_none() {
let runner = self.runners[self.ip];
runner.run(&mut self);
self.execute_next_runner();
}
self.return_value
}
pub(crate) fn follow_pointer(&self, pointer: Pointer) -> ValueRef {
pub fn execute_next_runner(&mut self) {
assert!(
self.ip < self.runners.len(),
"Runtime Error: IP out of bounds"
);
let runner = self.runners[self.ip];
runner.run(self);
}
pub(crate) fn follow_pointer(&self, pointer: Pointer) -> &Value {
log::trace!("Follow pointer {pointer}");
match pointer {
Pointer::Stack(register_index) => self.open_register(register_index),
Pointer::Constant(constant_index) => {
let constant = self.get_constant(constant_index);
ValueRef::Concrete(constant)
}
Pointer::Constant(constant_index) => self.get_constant(constant_index),
Pointer::ParentStack(register_index) => {
assert!(self.parent.is_some(), "Vm Error: Expected parent");
@ -113,15 +119,12 @@ impl<'a> Vm<'a> {
Pointer::ParentConstant(constant_index) => {
assert!(self.parent.is_some(), "Vm Error: Expected parent");
self.parent
.unwrap()
.get_constant(constant_index)
.to_value_ref()
self.parent.unwrap().get_constant(constant_index)
}
}
}
pub(crate) fn follow_pointer_allow_empty(&self, pointer: Pointer) -> Option<ValueRef> {
pub(crate) fn follow_pointer_allow_empty(&self, pointer: Pointer) -> Option<&Value> {
log::trace!("Follow pointer {pointer}");
match pointer {
@ -129,7 +132,7 @@ impl<'a> Vm<'a> {
Pointer::Constant(constant_index) => {
let constant = self.get_constant(constant_index);
Some(ValueRef::Concrete(constant))
Some(constant)
}
Pointer::ParentStack(register_index) => {
assert!(self.parent.is_some(), "Vm Error: Expected parent");
@ -141,18 +144,14 @@ impl<'a> Vm<'a> {
Pointer::ParentConstant(constant_index) => {
assert!(self.parent.is_some(), "Vm Error: Expected parent");
let constant = self
.parent
.unwrap()
.get_constant(constant_index)
.to_value_ref();
let constant = self.parent.unwrap().get_constant(constant_index);
Some(constant)
}
}
}
fn open_register(&self, register_index: u8) -> ValueRef {
fn open_register(&self, register_index: u8) -> &Value {
log::trace!("Open register R{register_index}");
let register_index = register_index as usize;
@ -165,13 +164,13 @@ impl<'a> Vm<'a> {
let register = &self.stack[register_index];
match register {
Register::Value(value) => value.to_ref(),
Register::Value(value) => value,
Register::Pointer(pointer) => self.follow_pointer(*pointer),
Register::Empty => panic!("VM Error: Register {register_index} is empty"),
}
}
fn open_register_allow_empty(&self, register_index: u8) -> Option<ValueRef> {
fn open_register_allow_empty(&self, register_index: u8) -> Option<&Value> {
log::trace!("Open register R{register_index}");
let register_index = register_index as usize;
@ -184,7 +183,7 @@ impl<'a> Vm<'a> {
let register = &self.stack[register_index];
match register {
Register::Value(value) => Some(value.to_ref()),
Register::Value(value) => Some(value),
Register::Pointer(pointer) => Some(self.follow_pointer(*pointer)),
Register::Empty => None,
}
@ -209,9 +208,9 @@ impl<'a> Vm<'a> {
}
/// DRY helper to get a value from an Argument
fn get_argument(&self, index: u8, is_constant: bool) -> ValueRef {
fn get_argument(&self, index: u8, is_constant: bool) -> &Value {
if is_constant {
self.get_constant(index).to_value_ref()
self.get_constant(index)
} else {
self.open_register(index)
}
@ -229,7 +228,7 @@ impl<'a> Vm<'a> {
self.stack[to_register] = register;
}
fn get_constant(&self, constant_index: u8) -> &ConcreteValue {
fn get_constant(&self, constant_index: u8) -> &Value {
let constant_index = constant_index as usize;
let constants = self.chunk.constants();

View File

@ -1,6 +1,8 @@
use std::{borrow::BorrowMut, cell::RefCell, rc::Rc};
use smallvec::SmallVec;
use crate::{AbstractValue, ConcreteValue, NativeFunction, Value, ValueRef};
use crate::{AbstractValue, ConcreteValue, NativeFunction, Type, Value};
use super::{Instruction, InstructionData, Pointer, Register, Vm};
@ -56,8 +58,7 @@ pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 24] = [
r#return,
];
#[allow(clippy::needless_lifetimes)]
pub fn r#move<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
pub fn r#move(vm: &mut Vm, instruction_data: InstructionData) {
let InstructionData { b, c, .. } = instruction_data;
let from_register_has_value = vm
.stack
@ -71,9 +72,7 @@ pub fn r#move<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
vm.ip += 1;
let next = vm.runners[vm.ip];
next.run(vm);
vm.execute_next_runner();
}
#[allow(clippy::needless_lifetimes)]
@ -93,9 +92,7 @@ pub fn close<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
vm.ip += 1;
let next = vm.runners[vm.ip];
next.run(vm);
vm.execute_next_runner();
}
#[allow(clippy::needless_lifetimes)]
@ -112,9 +109,7 @@ pub fn load_boolean<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionDat
vm.ip += 1;
}
let next = vm.runners[vm.ip];
next.run(vm);
vm.execute_next_runner();
}
#[allow(clippy::needless_lifetimes)]
@ -130,20 +125,29 @@ pub fn load_constant<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionDa
vm.ip += 1;
}
let next = vm.runners[vm.ip];
next.run(vm);
vm.execute_next_runner();
}
#[allow(clippy::needless_lifetimes)]
pub fn load_list<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
let InstructionData { a, b, .. } = instruction_data;
let mut item_pointers = Vec::new();
let mut item_pointers = Vec::with_capacity((a - b) as usize);
let stack = vm.stack.as_slice();
let mut item_type = Type::Any;
for register_index in b..a {
if let Register::Empty = stack[register_index as usize] {
continue;
match &stack[register_index as usize] {
Register::Empty => continue,
Register::Value(value) => {
if item_type == Type::Any {
item_type = value.r#type();
}
}
Register::Pointer(pointer) => {
if item_type == Type::Any {
item_type = vm.follow_pointer(*pointer).r#type();
}
}
}
let pointer = Pointer::Stack(register_index);
@ -151,16 +155,18 @@ pub fn load_list<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData)
item_pointers.push(pointer);
}
let list_value = AbstractValue::List { item_pointers }.to_value();
let list_value = AbstractValue::List {
item_type,
item_pointers,
}
.to_value();
let register = Register::Value(list_value);
vm.set_register(a, register);
vm.ip += 1;
let next = vm.runners[vm.ip];
next.run(vm);
vm.execute_next_runner();
}
#[allow(clippy::needless_lifetimes)]
@ -172,9 +178,7 @@ pub fn load_self<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData)
vm.ip += 1;
let next = vm.runners[vm.ip];
next.run(vm);
vm.execute_next_runner();
}
#[allow(clippy::needless_lifetimes)]
@ -187,9 +191,7 @@ pub fn get_local<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData)
vm.ip += 1;
let next = vm.runners[vm.ip];
next.run(vm);
vm.execute_next_runner();
}
#[allow(clippy::needless_lifetimes)]
@ -202,9 +204,7 @@ pub fn set_local<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData)
vm.ip += 1;
let next = vm.runners[vm.ip];
next.run(vm);
vm.execute_next_runner();
}
#[allow(clippy::needless_lifetimes)]
@ -220,7 +220,7 @@ pub fn add<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
let left = vm.get_argument(b, b_is_constant);
let right = vm.get_argument(c, c_is_constant);
let sum = match (left, right) {
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => match (left, right) {
(Value::Concrete(left), Value::Concrete(right)) => match (left, right) {
(ConcreteValue::Integer(left), ConcreteValue::Integer(right)) => {
ConcreteValue::Integer(left + right).to_value()
}
@ -234,9 +234,7 @@ pub fn add<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
vm.ip += 1;
let next = vm.runners[vm.ip];
next.run(vm);
vm.execute_next_runner();
}
#[allow(clippy::needless_lifetimes)]
@ -252,7 +250,7 @@ pub fn subtract<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
let left = vm.get_argument(b, b_is_constant);
let right = vm.get_argument(c, c_is_constant);
let difference = match (left, right) {
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => match (left, right) {
(Value::Concrete(left), Value::Concrete(right)) => match (left, right) {
(ConcreteValue::Integer(left), ConcreteValue::Integer(right)) => {
ConcreteValue::Integer(left - right).to_value()
}
@ -266,9 +264,7 @@ pub fn subtract<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
vm.ip += 1;
let next = vm.runners[vm.ip];
next.run(vm);
vm.execute_next_runner();
}
#[allow(clippy::needless_lifetimes)]
@ -284,7 +280,7 @@ pub fn multiply<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
let left = vm.get_argument(b, b_is_constant);
let right = vm.get_argument(c, c_is_constant);
let product = match (left, right) {
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => match (left, right) {
(Value::Concrete(left), Value::Concrete(right)) => match (left, right) {
(ConcreteValue::Integer(left), ConcreteValue::Integer(right)) => {
ConcreteValue::Integer(left * right).to_value()
}
@ -298,9 +294,7 @@ pub fn multiply<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
vm.ip += 1;
let next = vm.runners[vm.ip];
next.run(vm);
vm.execute_next_runner();
}
#[allow(clippy::needless_lifetimes)]
@ -316,7 +310,7 @@ pub fn divide<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
let left = vm.get_argument(b, b_is_constant);
let right = vm.get_argument(c, c_is_constant);
let quotient = match (left, right) {
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => match (left, right) {
(Value::Concrete(left), Value::Concrete(right)) => match (left, right) {
(ConcreteValue::Integer(left), ConcreteValue::Integer(right)) => {
ConcreteValue::Integer(left / right).to_value()
}
@ -330,9 +324,7 @@ pub fn divide<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
vm.ip += 1;
let next = vm.runners[vm.ip];
next.run(vm);
vm.execute_next_runner();
}
#[allow(clippy::needless_lifetimes)]
@ -348,7 +340,7 @@ pub fn modulo<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
let left = vm.get_argument(b, b_is_constant);
let right = vm.get_argument(c, c_is_constant);
let remainder = match (left, right) {
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => match (left, right) {
(Value::Concrete(left), Value::Concrete(right)) => match (left, right) {
(ConcreteValue::Integer(left), ConcreteValue::Integer(right)) => {
ConcreteValue::Integer(left % right).to_value()
}
@ -362,9 +354,7 @@ pub fn modulo<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
vm.ip += 1;
let next = vm.runners[vm.ip];
next.run(vm);
vm.execute_next_runner();
}
#[allow(clippy::needless_lifetimes)]
@ -376,7 +366,7 @@ pub fn test<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
..
} = instruction_data;
let value = vm.get_argument(b, b_is_constant);
let boolean = if let ValueRef::Concrete(ConcreteValue::Boolean(boolean)) = value {
let boolean = if let Value::Concrete(ConcreteValue::Boolean(boolean)) = value {
*boolean
} else {
panic!(
@ -392,9 +382,7 @@ pub fn test<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
vm.ip += 1;
}
let next = vm.runners[vm.ip];
next.run(vm);
vm.execute_next_runner();
}
#[allow(clippy::needless_lifetimes)]
@ -407,7 +395,7 @@ pub fn test_set<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
..
} = instruction_data;
let value = vm.get_argument(b, b_is_constant);
let boolean = if let ValueRef::Concrete(ConcreteValue::Boolean(boolean)) = value {
let boolean = if let Value::Concrete(ConcreteValue::Boolean(boolean)) = value {
*boolean
} else {
panic!(
@ -432,9 +420,7 @@ pub fn test_set<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
vm.ip += 1;
}
let next = vm.runners[vm.ip];
next.run(vm);
vm.execute_next_runner();
}
#[allow(clippy::needless_lifetimes)]
@ -457,13 +443,10 @@ pub fn equal<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
vm.ip += 1;
}
let next = vm.runners[vm.ip];
next.run(vm);
vm.execute_next_runner();
}
#[allow(clippy::needless_lifetimes)]
pub fn less<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
pub fn less(vm: &mut Vm, instruction_data: InstructionData) {
let InstructionData {
b,
c,
@ -482,9 +465,7 @@ pub fn less<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
vm.ip += 1;
}
let next = vm.runners[vm.ip];
next.run(vm);
vm.execute_next_runner();
}
#[allow(clippy::needless_lifetimes)]
@ -507,9 +488,7 @@ pub fn less_equal<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData)
vm.ip += 1;
}
let next = vm.runners[vm.ip];
next.run(vm);
vm.execute_next_runner();
}
#[allow(clippy::needless_lifetimes)]
@ -522,12 +501,12 @@ pub fn negate<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
} = instruction_data;
let argument = vm.get_argument(b, b_is_constant);
let negated = match argument {
ValueRef::Concrete(value) => match value {
Value::Concrete(value) => match value {
ConcreteValue::Float(float) => ConcreteValue::Float(-float),
ConcreteValue::Integer(integer) => ConcreteValue::Integer(-integer),
_ => panic!("Value Error: Cannot negate value"),
},
ValueRef::Abstract(_) => panic!("VM Error: Cannot negate value"),
Value::Abstract(_) => panic!("VM Error: Cannot negate value"),
};
let register = Register::Value(Value::Concrete(negated));
@ -535,9 +514,7 @@ pub fn negate<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
vm.ip += 1;
let next = vm.runners[vm.ip];
next.run(vm);
vm.execute_next_runner();
}
#[allow(clippy::needless_lifetimes)]
@ -550,7 +527,7 @@ pub fn not<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
} = instruction_data;
let argument = vm.get_argument(b, b_is_constant);
let not = match argument {
ValueRef::Concrete(ConcreteValue::Boolean(boolean)) => ConcreteValue::Boolean(!boolean),
Value::Concrete(ConcreteValue::Boolean(boolean)) => ConcreteValue::Boolean(!boolean),
_ => panic!("VM Error: Expected boolean value for NOT operation"),
};
let register = Register::Value(Value::Concrete(not));
@ -559,9 +536,7 @@ pub fn not<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
vm.ip += 1;
let next = vm.runners[vm.ip];
next.run(vm);
vm.execute_next_runner();
}
#[allow(clippy::needless_lifetimes)]
@ -576,9 +551,7 @@ pub fn jump<'c>(vm: &mut Vm<'c>, instruction_data: InstructionData) {
vm.ip -= offset
}
let next = vm.runners[vm.ip];
next.run(vm);
vm.execute_next_runner();
}
#[allow(clippy::needless_lifetimes)]
@ -591,9 +564,9 @@ pub fn call<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
..
} = instruction_data;
let function = vm.get_argument(b, b_is_constant);
let mut function_vm = if let ValueRef::Concrete(ConcreteValue::Function(chunk)) = function {
let mut function_vm = if let Value::Concrete(ConcreteValue::Function(chunk)) = function {
Vm::new(vm.source, chunk, Some(vm), None)
} else if let ValueRef::Abstract(AbstractValue::FunctionSelf) = function {
} else if let Value::Abstract(AbstractValue::FunctionSelf) = function {
Vm::new(vm.source, vm.chunk, Some(vm), Some(vm.runners.clone()))
} else {
panic!("VM Error: Expected function")
@ -620,16 +593,14 @@ pub fn call<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
let return_value = function_vm.run();
if let Some(concrete_value) = return_value {
let register = Register::Value(concrete_value.to_value());
let register = Register::Value(concrete_value);
vm.set_register(a, register);
}
vm.ip += 1;
let next = vm.runners[vm.ip];
next.run(vm);
vm.execute_next_runner();
}
#[allow(clippy::needless_lifetimes)]
@ -637,12 +608,12 @@ pub fn call_native<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData
let InstructionData { a, b, c, .. } = instruction_data;
let first_argument_index = (a - c) as usize;
let argument_range = first_argument_index..a as usize;
let mut arguments: SmallVec<[ValueRef; 4]> = SmallVec::new();
let mut arguments: SmallVec<[&Value; 4]> = SmallVec::new();
for register_index in argument_range {
let register = &vm.stack[register_index];
let value = match register {
Register::Value(value) => value.to_ref(),
Register::Value(value) => value,
Register::Pointer(pointer) => {
let value_option = vm.follow_pointer_allow_empty(*pointer);
@ -668,9 +639,7 @@ pub fn call_native<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData
vm.ip += 1;
let next = vm.runners[vm.ip];
next.run(vm);
vm.execute_next_runner();
}
#[allow(clippy::needless_lifetimes)]
@ -682,7 +651,7 @@ pub fn r#return<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
}
if let Some(register_index) = &vm.last_assigned_register {
let return_value = vm.open_register(*register_index).into_concrete_owned(vm);
let return_value = vm.open_register(*register_index).clone();
vm.return_value = Some(return_value);
} else {