Continue VM optimizations
This commit is contained in:
parent
cd4fa6bef5
commit
ec5033a32f
@ -46,7 +46,7 @@ use std::{
|
|||||||
|
|
||||||
use colored::{ColoredString, Colorize};
|
use colored::{ColoredString, Colorize};
|
||||||
|
|
||||||
use crate::{value::ConcreteValue, Chunk, Local};
|
use crate::{value::ConcreteValue, Chunk, Local, Value};
|
||||||
|
|
||||||
const INSTRUCTION_COLUMNS: [(&str, usize); 4] =
|
const INSTRUCTION_COLUMNS: [(&str, usize); 4] =
|
||||||
[("i", 5), ("POSITION", 12), ("OPERATION", 17), ("INFO", 24)];
|
[("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])?;
|
self.write_centered_with_border(CONSTANT_BORDERS[1])?;
|
||||||
|
|
||||||
for (index, value) in self.chunk.constants().iter().enumerate() {
|
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 type_display = value.r#type().to_string();
|
||||||
let value_display = if is_function {
|
let value_display = if is_function {
|
||||||
"Function displayed below".to_string()
|
"Function displayed below".to_string()
|
||||||
@ -353,7 +353,7 @@ impl<'a, W: Write> Disassembler<'a, W> {
|
|||||||
|
|
||||||
self.write_centered_with_border(&constant_display)?;
|
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
|
let function_disassembler = chunk
|
||||||
.disassembler(self.writer)
|
.disassembler(self.writer)
|
||||||
.style(self.style)
|
.style(self.style)
|
||||||
|
@ -17,7 +17,7 @@ use std::io::Write;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use smallvec::SmallVec;
|
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.
|
/// In-memory representation of a Dust program or function.
|
||||||
///
|
///
|
||||||
@ -28,7 +28,7 @@ pub struct Chunk {
|
|||||||
r#type: FunctionType,
|
r#type: FunctionType,
|
||||||
|
|
||||||
instructions: SmallVec<[(Instruction, Span); 32]>,
|
instructions: SmallVec<[(Instruction, Span); 32]>,
|
||||||
constants: SmallVec<[ConcreteValue; 16]>,
|
constants: SmallVec<[Value; 16]>,
|
||||||
locals: SmallVec<[Local; 8]>,
|
locals: SmallVec<[Local; 8]>,
|
||||||
|
|
||||||
stack_size: usize,
|
stack_size: usize,
|
||||||
@ -39,7 +39,7 @@ impl Chunk {
|
|||||||
name: Option<DustString>,
|
name: Option<DustString>,
|
||||||
r#type: FunctionType,
|
r#type: FunctionType,
|
||||||
instructions: SmallVec<[(Instruction, Span); 32]>,
|
instructions: SmallVec<[(Instruction, Span); 32]>,
|
||||||
constants: SmallVec<[ConcreteValue; 16]>,
|
constants: SmallVec<[Value; 16]>,
|
||||||
locals: SmallVec<[Local; 8]>,
|
locals: SmallVec<[Local; 8]>,
|
||||||
stack_size: usize,
|
stack_size: usize,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
@ -57,7 +57,7 @@ impl Chunk {
|
|||||||
name: Option<DustString>,
|
name: Option<DustString>,
|
||||||
r#type: FunctionType,
|
r#type: FunctionType,
|
||||||
instructions: impl Into<SmallVec<[(Instruction, Span); 32]>>,
|
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]>>,
|
locals: impl Into<SmallVec<[Local; 8]>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -82,7 +82,7 @@ impl Chunk {
|
|||||||
self.instructions.is_empty()
|
self.instructions.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn constants(&self) -> &SmallVec<[ConcreteValue; 16]> {
|
pub fn constants(&self) -> &SmallVec<[Value; 16]> {
|
||||||
&self.constants
|
&self.constants
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ use crate::{
|
|||||||
Not, Return, SetLocal, Test,
|
Not, Return, SetLocal, Test,
|
||||||
},
|
},
|
||||||
Argument, Chunk, ConcreteValue, DustError, DustString, FunctionType, Instruction, Lexer, Local,
|
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.
|
/// Compiles the input and returns a chunk.
|
||||||
@ -58,7 +58,7 @@ pub fn compile(source: &str) -> Result<Chunk, DustError> {
|
|||||||
pub struct Compiler<'src> {
|
pub struct Compiler<'src> {
|
||||||
self_name: Option<DustString>,
|
self_name: Option<DustString>,
|
||||||
instructions: SmallVec<[(Instruction, Type, Span); 32]>,
|
instructions: SmallVec<[(Instruction, Type, Span); 32]>,
|
||||||
constants: SmallVec<[ConcreteValue; 16]>,
|
constants: SmallVec<[Value; 16]>,
|
||||||
locals: SmallVec<[(Local, Type); 8]>,
|
locals: SmallVec<[(Local, Type); 8]>,
|
||||||
stack_size: usize,
|
stack_size: usize,
|
||||||
|
|
||||||
@ -203,7 +203,8 @@ impl<'src> Compiler<'src> {
|
|||||||
.rev()
|
.rev()
|
||||||
.find_map(|(index, (local, _))| {
|
.find_map(|(index, (local, _))| {
|
||||||
let constant = self.constants.get(local.identifier_index as usize)?;
|
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
|
identifier
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
@ -231,7 +232,7 @@ impl<'src> Compiler<'src> {
|
|||||||
) -> (u8, u8) {
|
) -> (u8, u8) {
|
||||||
log::info!("Declaring local {identifier}");
|
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 identifier_index = self.push_or_get_constant(identifier);
|
||||||
let local_index = self.locals.len() as u8;
|
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
|
if let Some(index) = self
|
||||||
.constants
|
.constants
|
||||||
.iter()
|
.iter()
|
||||||
@ -405,7 +406,7 @@ impl<'src> Compiler<'src> {
|
|||||||
position: Span,
|
position: Span,
|
||||||
) -> Result<(), CompileError> {
|
) -> Result<(), CompileError> {
|
||||||
let r#type = constant.r#type();
|
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 destination = self.next_register();
|
||||||
let load_constant = Instruction::load_constant(destination, constant_index, false);
|
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 function_end = function_compiler.previous_position.1;
|
||||||
let chunk = function_compiler.finish(None, value_parameters.clone());
|
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 constant_index = self.push_or_get_constant(function);
|
||||||
let destination = self.next_register();
|
let destination = self.next_register();
|
||||||
let function_type = FunctionType {
|
let function_type = FunctionType {
|
||||||
|
@ -47,9 +47,7 @@ pub use crate::lexer::{lex, LexError, Lexer};
|
|||||||
pub use crate::native_function::{NativeFunction, NativeFunctionError};
|
pub use crate::native_function::{NativeFunction, NativeFunctionError};
|
||||||
pub use crate::r#type::{EnumType, FunctionType, StructType, Type, TypeConflict};
|
pub use crate::r#type::{EnumType, FunctionType, StructType, Type, TypeConflict};
|
||||||
pub use crate::token::{Token, TokenKind, TokenOwned};
|
pub use crate::token::{Token, TokenKind, TokenOwned};
|
||||||
pub use crate::value::{
|
pub use crate::value::{AbstractValue, ConcreteValue, DustString, RangeValue, Value, ValueError};
|
||||||
AbstractValue, ConcreteValue, DustString, RangeValue, Value, ValueError, ValueRef,
|
|
||||||
};
|
|
||||||
pub use crate::vm::{run, Vm, VmError};
|
pub use crate::vm::{run, Vm, VmError};
|
||||||
|
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
@ -3,11 +3,11 @@ use std::panic;
|
|||||||
use annotate_snippets::{Level, Renderer, Snippet};
|
use annotate_snippets::{Level, Renderer, Snippet};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
use crate::{DustString, NativeFunctionError, Value, ValueRef, Vm};
|
use crate::{DustString, NativeFunctionError, Value, Vm};
|
||||||
|
|
||||||
pub fn panic(
|
pub fn panic(
|
||||||
vm: &Vm,
|
vm: &Vm,
|
||||||
arguments: SmallVec<[ValueRef; 4]>,
|
arguments: SmallVec<[&Value; 4]>,
|
||||||
) -> Result<Option<Value>, NativeFunctionError> {
|
) -> Result<Option<Value>, NativeFunctionError> {
|
||||||
let mut message: Option<DustString> = None;
|
let mut message: Option<DustString> = None;
|
||||||
|
|
||||||
|
@ -2,12 +2,9 @@ use std::io::{stdin, stdout, Write};
|
|||||||
|
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
use crate::{ConcreteValue, NativeFunctionError, Value, ValueRef, Vm};
|
use crate::{ConcreteValue, NativeFunctionError, Value, Vm};
|
||||||
|
|
||||||
pub fn read_line(
|
pub fn read_line(vm: &Vm, _: SmallVec<[&Value; 4]>) -> Result<Option<Value>, NativeFunctionError> {
|
||||||
vm: &Vm,
|
|
||||||
_: SmallVec<[ValueRef; 4]>,
|
|
||||||
) -> Result<Option<Value>, NativeFunctionError> {
|
|
||||||
let mut buffer = String::new();
|
let mut buffer = String::new();
|
||||||
|
|
||||||
match stdin().read_line(&mut buffer) {
|
match stdin().read_line(&mut buffer) {
|
||||||
@ -27,7 +24,7 @@ pub fn read_line(
|
|||||||
|
|
||||||
pub fn write(
|
pub fn write(
|
||||||
vm: &Vm,
|
vm: &Vm,
|
||||||
arguments: SmallVec<[ValueRef; 4]>,
|
arguments: SmallVec<[&Value; 4]>,
|
||||||
) -> Result<Option<Value>, NativeFunctionError> {
|
) -> Result<Option<Value>, NativeFunctionError> {
|
||||||
let mut stdout = stdout();
|
let mut stdout = stdout();
|
||||||
|
|
||||||
@ -50,7 +47,7 @@ pub fn write(
|
|||||||
|
|
||||||
pub fn write_line(
|
pub fn write_line(
|
||||||
vm: &Vm,
|
vm: &Vm,
|
||||||
arguments: SmallVec<[ValueRef; 4]>,
|
arguments: SmallVec<[&Value; 4]>,
|
||||||
) -> Result<Option<Value>, NativeFunctionError> {
|
) -> Result<Option<Value>, NativeFunctionError> {
|
||||||
let mut stdout = stdout();
|
let mut stdout = stdout();
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ use std::{
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use smallvec::{smallvec, SmallVec};
|
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 {
|
macro_rules! define_native_function {
|
||||||
($(($name:ident, $bytes:literal, $str:expr, $type:expr, $function:expr)),*) => {
|
($(($name:ident, $bytes:literal, $str:expr, $type:expr, $function:expr)),*) => {
|
||||||
@ -33,7 +33,7 @@ macro_rules! define_native_function {
|
|||||||
pub fn call<'a>(
|
pub fn call<'a>(
|
||||||
&self,
|
&self,
|
||||||
vm: &Vm<'a>,
|
vm: &Vm<'a>,
|
||||||
arguments: SmallVec<[ValueRef<'a>; 4]>,
|
arguments: SmallVec<[&Value; 4]>,
|
||||||
) -> Result<Option<Value>, NativeFunctionError> {
|
) -> Result<Option<Value>, NativeFunctionError> {
|
||||||
match self {
|
match self {
|
||||||
$(
|
$(
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
use crate::{ConcreteValue, NativeFunctionError, Value, ValueRef, Vm};
|
use crate::{ConcreteValue, NativeFunctionError, Value, Vm};
|
||||||
|
|
||||||
pub fn to_string(
|
pub fn to_string(
|
||||||
vm: &Vm,
|
vm: &Vm,
|
||||||
arguments: SmallVec<[ValueRef; 4]>,
|
arguments: SmallVec<[&Value; 4]>,
|
||||||
) -> Result<Option<Value>, NativeFunctionError> {
|
) -> Result<Option<Value>, NativeFunctionError> {
|
||||||
if arguments.len() != 1 {
|
if arguments.len() != 1 {
|
||||||
return Err(NativeFunctionError::ExpectedArgumentCount {
|
return Err(NativeFunctionError::ExpectedArgumentCount {
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
use std::fmt::{self, Display, Formatter};
|
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)]
|
#[derive(Debug, PartialEq, PartialOrd)]
|
||||||
pub enum AbstractValue {
|
pub enum AbstractValue {
|
||||||
FunctionSelf,
|
FunctionSelf,
|
||||||
List { item_pointers: Vec<Pointer> },
|
List {
|
||||||
|
item_type: Type,
|
||||||
|
item_pointers: Vec<Pointer>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractValue {
|
impl AbstractValue {
|
||||||
@ -13,10 +16,6 @@ impl AbstractValue {
|
|||||||
Value::Abstract(self)
|
Value::Abstract(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_value_ref(&self) -> ValueRef {
|
|
||||||
ValueRef::Abstract(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_concrete_owned(&self, vm: &Vm) -> ConcreteValue {
|
pub fn to_concrete_owned(&self, vm: &Vm) -> ConcreteValue {
|
||||||
match self {
|
match self {
|
||||||
AbstractValue::FunctionSelf => ConcreteValue::function(vm.chunk().clone()),
|
AbstractValue::FunctionSelf => ConcreteValue::function(vm.chunk().clone()),
|
||||||
@ -26,7 +25,7 @@ impl AbstractValue {
|
|||||||
for pointer in item_pointers {
|
for pointer in item_pointers {
|
||||||
let item_option = vm.follow_pointer_allow_empty(*pointer);
|
let item_option = vm.follow_pointer_allow_empty(*pointer);
|
||||||
let item = match item_option {
|
let item = match item_option {
|
||||||
Some(value_ref) => value_ref.into_concrete_owned(vm),
|
Some(value) => value.clone().into_concrete_owned(vm),
|
||||||
None => continue,
|
None => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -65,6 +64,13 @@ impl AbstractValue {
|
|||||||
|
|
||||||
Ok(display)
|
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 {
|
impl Clone for AbstractValue {
|
||||||
@ -74,8 +80,10 @@ impl Clone for AbstractValue {
|
|||||||
match self {
|
match self {
|
||||||
AbstractValue::FunctionSelf => AbstractValue::FunctionSelf,
|
AbstractValue::FunctionSelf => AbstractValue::FunctionSelf,
|
||||||
AbstractValue::List {
|
AbstractValue::List {
|
||||||
|
item_type: r#type,
|
||||||
item_pointers: items,
|
item_pointers: items,
|
||||||
} => AbstractValue::List {
|
} => AbstractValue::List {
|
||||||
|
item_type: r#type.clone(),
|
||||||
item_pointers: items.clone(),
|
item_pointers: items.clone(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use smartstring::{LazyCompact, SmartString};
|
use smartstring::{LazyCompact, SmartString};
|
||||||
|
|
||||||
use crate::{Chunk, Type, Value, ValueError, ValueRef};
|
use crate::{Chunk, Type, Value, ValueError};
|
||||||
|
|
||||||
use super::RangeValue;
|
use super::RangeValue;
|
||||||
|
|
||||||
@ -27,10 +27,6 @@ impl ConcreteValue {
|
|||||||
Value::Concrete(self)
|
Value::Concrete(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_value_ref(&self) -> ValueRef {
|
|
||||||
ValueRef::Concrete(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn function(chunk: Chunk) -> Self {
|
pub fn function(chunk: Chunk) -> Self {
|
||||||
ConcreteValue::Function(Box::new(chunk))
|
ConcreteValue::Function(Box::new(chunk))
|
||||||
}
|
}
|
||||||
|
@ -6,25 +6,20 @@ mod range_value;
|
|||||||
pub use abstract_value::AbstractValue;
|
pub use abstract_value::AbstractValue;
|
||||||
pub use concrete_value::{ConcreteValue, DustString};
|
pub use concrete_value::{ConcreteValue, DustString};
|
||||||
pub use range_value::RangeValue;
|
pub use range_value::RangeValue;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use std::fmt::{self, Debug, Display, Formatter};
|
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 {
|
pub enum Value {
|
||||||
|
#[serde(skip)]
|
||||||
Abstract(AbstractValue),
|
Abstract(AbstractValue),
|
||||||
Concrete(ConcreteValue),
|
Concrete(ConcreteValue),
|
||||||
}
|
}
|
||||||
|
|
||||||
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 into_concrete_owned(self, vm: &Vm) -> ConcreteValue {
|
pub fn into_concrete_owned(self, vm: &Vm) -> ConcreteValue {
|
||||||
match self {
|
match self {
|
||||||
Value::Abstract(abstract_value) => abstract_value.to_concrete_owned(vm),
|
Value::Abstract(abstract_value) => abstract_value.to_concrete_owned(vm),
|
||||||
@ -39,58 +34,24 @@ impl Value {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Value {
|
pub fn r#type(&self) -> Type {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
||||||
match self {
|
match self {
|
||||||
Value::Abstract(abstract_value) => write!(f, "{}", abstract_value),
|
Value::Abstract(abstract_value) => abstract_value.r#type(),
|
||||||
Value::Concrete(concrete_value) => write!(f, "{}", concrete_value),
|
Value::Concrete(concrete_value) => concrete_value.r#type(),
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
|
|
||||||
pub enum ValueRef<'a> {
|
|
||||||
Abstract(&'a AbstractValue),
|
|
||||||
Concrete(&'a ConcreteValue),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ValueRef<'_> {
|
|
||||||
pub fn to_owned(&self) -> Value {
|
|
||||||
match self {
|
|
||||||
ValueRef::Abstract(abstract_value) => Value::Abstract((*abstract_value).clone()),
|
|
||||||
ValueRef::Concrete(concrete_value) => Value::Concrete((*concrete_value).clone()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_concrete_owned(self, vm: &Vm) -> ConcreteValue {
|
pub fn add(&self, other: &Value) -> Result<Value, ValueError> {
|
||||||
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> {
|
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
|
(Value::Concrete(left), Value::Concrete(right)) => left.add(right).map(Value::Concrete),
|
||||||
left.add(right).map(Value::Concrete)
|
|
||||||
}
|
|
||||||
_ => Err(ValueError::CannotAdd(self.to_owned(), other.to_owned())),
|
_ => 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) {
|
match (self, other) {
|
||||||
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
|
(Value::Concrete(left), Value::Concrete(right)) => {
|
||||||
left.subtract(right).map(Value::Concrete)
|
left.subtract(right).map(Value::Concrete)
|
||||||
}
|
}
|
||||||
_ => Err(ValueError::CannotSubtract(
|
_ => 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) {
|
match (self, other) {
|
||||||
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
|
(Value::Concrete(left), Value::Concrete(right)) => {
|
||||||
left.multiply(right).map(Value::Concrete)
|
left.multiply(right).map(Value::Concrete)
|
||||||
}
|
}
|
||||||
_ => Err(ValueError::CannotMultiply(
|
_ => 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) {
|
match (self, other) {
|
||||||
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
|
(Value::Concrete(left), Value::Concrete(right)) => {
|
||||||
left.divide(right).map(Value::Concrete)
|
left.divide(right).map(Value::Concrete)
|
||||||
}
|
}
|
||||||
_ => Err(ValueError::CannotDivide(self.to_owned(), other.to_owned())),
|
_ => 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) {
|
match (self, other) {
|
||||||
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
|
(Value::Concrete(left), Value::Concrete(right)) => {
|
||||||
left.modulo(right).map(Value::Concrete)
|
left.modulo(right).map(Value::Concrete)
|
||||||
}
|
}
|
||||||
_ => Err(ValueError::CannotModulo(self.to_owned(), other.to_owned())),
|
_ => Err(ValueError::CannotModulo(self.to_owned(), other.to_owned())),
|
||||||
@ -132,51 +93,58 @@ impl ValueRef<'_> {
|
|||||||
|
|
||||||
pub fn negate(&self) -> Result<Value, ValueError> {
|
pub fn negate(&self) -> Result<Value, ValueError> {
|
||||||
match self {
|
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())),
|
_ => Err(ValueError::CannotNegate(self.to_owned())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn not(&self) -> Result<Value, ValueError> {
|
pub fn not(&self) -> Result<Value, ValueError> {
|
||||||
match self {
|
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())),
|
_ => 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) {
|
match (self, other) {
|
||||||
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
|
(Value::Concrete(left), Value::Concrete(right)) => {
|
||||||
left.equal(right).map(Value::Concrete)
|
left.equal(right).map(Value::Concrete)
|
||||||
}
|
}
|
||||||
_ => Err(ValueError::CannotCompare(self.to_owned(), other.to_owned())),
|
_ => 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) {
|
match (self, other) {
|
||||||
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
|
(Value::Concrete(left), Value::Concrete(right)) => {
|
||||||
left.less_than(right).map(Value::Concrete)
|
left.less_than(right).map(Value::Concrete)
|
||||||
}
|
}
|
||||||
_ => Err(ValueError::CannotCompare(self.to_owned(), other.to_owned())),
|
_ => 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) {
|
match (self, other) {
|
||||||
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
|
(Value::Concrete(left), Value::Concrete(right)) => {
|
||||||
left.less_than_or_equal(right).map(Value::Concrete)
|
left.less_than_or_equal(right).map(Value::Concrete)
|
||||||
}
|
}
|
||||||
_ => Err(ValueError::CannotCompare(self.to_owned(), other.to_owned())),
|
_ => 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 {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
ValueRef::Abstract(abstract_value) => write!(f, "{}", abstract_value),
|
Value::Abstract(abstract_value) => write!(f, "{}", abstract_value),
|
||||||
ValueRef::Concrete(concrete_value) => write!(f, "{}", concrete_value),
|
Value::Concrete(concrete_value) => write!(f, "{}", concrete_value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ mod runners;
|
|||||||
use std::{
|
use std::{
|
||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
io, iter,
|
io, iter,
|
||||||
|
rc::Rc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use runners::Runner;
|
use runners::Runner;
|
||||||
@ -11,10 +12,10 @@ use smallvec::SmallVec;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
compile, instruction::*, AbstractValue, AnnotatedError, Chunk, ConcreteValue, DustError,
|
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 chunk = compile(source)?;
|
||||||
let vm = Vm::new(source, &chunk, None, None);
|
let vm = Vm::new(source, &chunk, None, None);
|
||||||
|
|
||||||
@ -35,7 +36,7 @@ pub struct Vm<'a> {
|
|||||||
ip: usize,
|
ip: usize,
|
||||||
last_assigned_register: Option<u8>,
|
last_assigned_register: Option<u8>,
|
||||||
source: &'a str,
|
source: &'a str,
|
||||||
return_value: Option<ConcreteValue>,
|
return_value: Option<Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Vm<'a> {
|
impl<'a> Vm<'a> {
|
||||||
@ -85,26 +86,31 @@ impl<'a> Vm<'a> {
|
|||||||
position
|
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() {
|
while self.ip < self.runners.len() && self.return_value.is_none() {
|
||||||
let runner = self.runners[self.ip];
|
self.execute_next_runner();
|
||||||
|
|
||||||
runner.run(&mut self);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.return_value
|
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}");
|
log::trace!("Follow pointer {pointer}");
|
||||||
|
|
||||||
match pointer {
|
match pointer {
|
||||||
Pointer::Stack(register_index) => self.open_register(register_index),
|
Pointer::Stack(register_index) => self.open_register(register_index),
|
||||||
Pointer::Constant(constant_index) => {
|
Pointer::Constant(constant_index) => self.get_constant(constant_index),
|
||||||
let constant = self.get_constant(constant_index);
|
|
||||||
|
|
||||||
ValueRef::Concrete(constant)
|
|
||||||
}
|
|
||||||
Pointer::ParentStack(register_index) => {
|
Pointer::ParentStack(register_index) => {
|
||||||
assert!(self.parent.is_some(), "Vm Error: Expected parent");
|
assert!(self.parent.is_some(), "Vm Error: Expected parent");
|
||||||
|
|
||||||
@ -113,15 +119,12 @@ impl<'a> Vm<'a> {
|
|||||||
Pointer::ParentConstant(constant_index) => {
|
Pointer::ParentConstant(constant_index) => {
|
||||||
assert!(self.parent.is_some(), "Vm Error: Expected parent");
|
assert!(self.parent.is_some(), "Vm Error: Expected parent");
|
||||||
|
|
||||||
self.parent
|
self.parent.unwrap().get_constant(constant_index)
|
||||||
.unwrap()
|
|
||||||
.get_constant(constant_index)
|
|
||||||
.to_value_ref()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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}");
|
log::trace!("Follow pointer {pointer}");
|
||||||
|
|
||||||
match pointer {
|
match pointer {
|
||||||
@ -129,7 +132,7 @@ impl<'a> Vm<'a> {
|
|||||||
Pointer::Constant(constant_index) => {
|
Pointer::Constant(constant_index) => {
|
||||||
let constant = self.get_constant(constant_index);
|
let constant = self.get_constant(constant_index);
|
||||||
|
|
||||||
Some(ValueRef::Concrete(constant))
|
Some(constant)
|
||||||
}
|
}
|
||||||
Pointer::ParentStack(register_index) => {
|
Pointer::ParentStack(register_index) => {
|
||||||
assert!(self.parent.is_some(), "Vm Error: Expected parent");
|
assert!(self.parent.is_some(), "Vm Error: Expected parent");
|
||||||
@ -141,18 +144,14 @@ impl<'a> Vm<'a> {
|
|||||||
Pointer::ParentConstant(constant_index) => {
|
Pointer::ParentConstant(constant_index) => {
|
||||||
assert!(self.parent.is_some(), "Vm Error: Expected parent");
|
assert!(self.parent.is_some(), "Vm Error: Expected parent");
|
||||||
|
|
||||||
let constant = self
|
let constant = self.parent.unwrap().get_constant(constant_index);
|
||||||
.parent
|
|
||||||
.unwrap()
|
|
||||||
.get_constant(constant_index)
|
|
||||||
.to_value_ref();
|
|
||||||
|
|
||||||
Some(constant)
|
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}");
|
log::trace!("Open register R{register_index}");
|
||||||
|
|
||||||
let register_index = register_index as usize;
|
let register_index = register_index as usize;
|
||||||
@ -165,13 +164,13 @@ impl<'a> Vm<'a> {
|
|||||||
let register = &self.stack[register_index];
|
let register = &self.stack[register_index];
|
||||||
|
|
||||||
match register {
|
match register {
|
||||||
Register::Value(value) => value.to_ref(),
|
Register::Value(value) => value,
|
||||||
Register::Pointer(pointer) => self.follow_pointer(*pointer),
|
Register::Pointer(pointer) => self.follow_pointer(*pointer),
|
||||||
Register::Empty => panic!("VM Error: Register {register_index} is empty"),
|
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}");
|
log::trace!("Open register R{register_index}");
|
||||||
|
|
||||||
let register_index = register_index as usize;
|
let register_index = register_index as usize;
|
||||||
@ -184,7 +183,7 @@ impl<'a> Vm<'a> {
|
|||||||
let register = &self.stack[register_index];
|
let register = &self.stack[register_index];
|
||||||
|
|
||||||
match register {
|
match register {
|
||||||
Register::Value(value) => Some(value.to_ref()),
|
Register::Value(value) => Some(value),
|
||||||
Register::Pointer(pointer) => Some(self.follow_pointer(*pointer)),
|
Register::Pointer(pointer) => Some(self.follow_pointer(*pointer)),
|
||||||
Register::Empty => None,
|
Register::Empty => None,
|
||||||
}
|
}
|
||||||
@ -209,9 +208,9 @@ impl<'a> Vm<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// DRY helper to get a value from an Argument
|
/// 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 {
|
if is_constant {
|
||||||
self.get_constant(index).to_value_ref()
|
self.get_constant(index)
|
||||||
} else {
|
} else {
|
||||||
self.open_register(index)
|
self.open_register(index)
|
||||||
}
|
}
|
||||||
@ -229,7 +228,7 @@ impl<'a> Vm<'a> {
|
|||||||
self.stack[to_register] = register;
|
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 constant_index = constant_index as usize;
|
||||||
let constants = self.chunk.constants();
|
let constants = self.chunk.constants();
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
use std::{borrow::BorrowMut, cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
use crate::{AbstractValue, ConcreteValue, NativeFunction, Value, ValueRef};
|
use crate::{AbstractValue, ConcreteValue, NativeFunction, Type, Value};
|
||||||
|
|
||||||
use super::{Instruction, InstructionData, Pointer, Register, Vm};
|
use super::{Instruction, InstructionData, Pointer, Register, Vm};
|
||||||
|
|
||||||
@ -56,8 +58,7 @@ pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 24] = [
|
|||||||
r#return,
|
r#return,
|
||||||
];
|
];
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
pub fn r#move(vm: &mut Vm, instruction_data: InstructionData) {
|
||||||
pub fn r#move<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|
||||||
let InstructionData { b, c, .. } = instruction_data;
|
let InstructionData { b, c, .. } = instruction_data;
|
||||||
let from_register_has_value = vm
|
let from_register_has_value = vm
|
||||||
.stack
|
.stack
|
||||||
@ -71,9 +72,7 @@ pub fn r#move<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
|
|
||||||
vm.ip += 1;
|
vm.ip += 1;
|
||||||
|
|
||||||
let next = vm.runners[vm.ip];
|
vm.execute_next_runner();
|
||||||
|
|
||||||
next.run(vm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -93,9 +92,7 @@ pub fn close<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
|
|
||||||
vm.ip += 1;
|
vm.ip += 1;
|
||||||
|
|
||||||
let next = vm.runners[vm.ip];
|
vm.execute_next_runner();
|
||||||
|
|
||||||
next.run(vm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[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;
|
vm.ip += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let next = vm.runners[vm.ip];
|
vm.execute_next_runner();
|
||||||
|
|
||||||
next.run(vm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[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;
|
vm.ip += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let next = vm.runners[vm.ip];
|
vm.execute_next_runner();
|
||||||
|
|
||||||
next.run(vm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
pub fn load_list<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
pub fn load_list<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
||||||
let InstructionData { a, b, .. } = instruction_data;
|
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 stack = vm.stack.as_slice();
|
||||||
|
let mut item_type = Type::Any;
|
||||||
|
|
||||||
for register_index in b..a {
|
for register_index in b..a {
|
||||||
if let Register::Empty = stack[register_index as usize] {
|
match &stack[register_index as usize] {
|
||||||
continue;
|
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);
|
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);
|
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);
|
let register = Register::Value(list_value);
|
||||||
|
|
||||||
vm.set_register(a, register);
|
vm.set_register(a, register);
|
||||||
|
|
||||||
vm.ip += 1;
|
vm.ip += 1;
|
||||||
|
|
||||||
let next = vm.runners[vm.ip];
|
vm.execute_next_runner();
|
||||||
|
|
||||||
next.run(vm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[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;
|
vm.ip += 1;
|
||||||
|
|
||||||
let next = vm.runners[vm.ip];
|
vm.execute_next_runner();
|
||||||
|
|
||||||
next.run(vm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[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;
|
vm.ip += 1;
|
||||||
|
|
||||||
let next = vm.runners[vm.ip];
|
vm.execute_next_runner();
|
||||||
|
|
||||||
next.run(vm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[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;
|
vm.ip += 1;
|
||||||
|
|
||||||
let next = vm.runners[vm.ip];
|
vm.execute_next_runner();
|
||||||
|
|
||||||
next.run(vm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[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 left = vm.get_argument(b, b_is_constant);
|
||||||
let right = vm.get_argument(c, c_is_constant);
|
let right = vm.get_argument(c, c_is_constant);
|
||||||
let sum = match (left, right) {
|
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), ConcreteValue::Integer(right)) => {
|
||||||
ConcreteValue::Integer(left + right).to_value()
|
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;
|
vm.ip += 1;
|
||||||
|
|
||||||
let next = vm.runners[vm.ip];
|
vm.execute_next_runner();
|
||||||
|
|
||||||
next.run(vm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[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 left = vm.get_argument(b, b_is_constant);
|
||||||
let right = vm.get_argument(c, c_is_constant);
|
let right = vm.get_argument(c, c_is_constant);
|
||||||
let difference = match (left, right) {
|
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), ConcreteValue::Integer(right)) => {
|
||||||
ConcreteValue::Integer(left - right).to_value()
|
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;
|
vm.ip += 1;
|
||||||
|
|
||||||
let next = vm.runners[vm.ip];
|
vm.execute_next_runner();
|
||||||
|
|
||||||
next.run(vm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[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 left = vm.get_argument(b, b_is_constant);
|
||||||
let right = vm.get_argument(c, c_is_constant);
|
let right = vm.get_argument(c, c_is_constant);
|
||||||
let product = match (left, right) {
|
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), ConcreteValue::Integer(right)) => {
|
||||||
ConcreteValue::Integer(left * right).to_value()
|
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;
|
vm.ip += 1;
|
||||||
|
|
||||||
let next = vm.runners[vm.ip];
|
vm.execute_next_runner();
|
||||||
|
|
||||||
next.run(vm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[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 left = vm.get_argument(b, b_is_constant);
|
||||||
let right = vm.get_argument(c, c_is_constant);
|
let right = vm.get_argument(c, c_is_constant);
|
||||||
let quotient = match (left, right) {
|
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), ConcreteValue::Integer(right)) => {
|
||||||
ConcreteValue::Integer(left / right).to_value()
|
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;
|
vm.ip += 1;
|
||||||
|
|
||||||
let next = vm.runners[vm.ip];
|
vm.execute_next_runner();
|
||||||
|
|
||||||
next.run(vm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[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 left = vm.get_argument(b, b_is_constant);
|
||||||
let right = vm.get_argument(c, c_is_constant);
|
let right = vm.get_argument(c, c_is_constant);
|
||||||
let remainder = match (left, right) {
|
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), ConcreteValue::Integer(right)) => {
|
||||||
ConcreteValue::Integer(left % right).to_value()
|
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;
|
vm.ip += 1;
|
||||||
|
|
||||||
let next = vm.runners[vm.ip];
|
vm.execute_next_runner();
|
||||||
|
|
||||||
next.run(vm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -376,7 +366,7 @@ pub fn test<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
..
|
..
|
||||||
} = instruction_data;
|
} = instruction_data;
|
||||||
let value = vm.get_argument(b, b_is_constant);
|
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
|
*boolean
|
||||||
} else {
|
} else {
|
||||||
panic!(
|
panic!(
|
||||||
@ -392,9 +382,7 @@ pub fn test<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
vm.ip += 1;
|
vm.ip += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let next = vm.runners[vm.ip];
|
vm.execute_next_runner();
|
||||||
|
|
||||||
next.run(vm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -407,7 +395,7 @@ pub fn test_set<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
..
|
..
|
||||||
} = instruction_data;
|
} = instruction_data;
|
||||||
let value = vm.get_argument(b, b_is_constant);
|
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
|
*boolean
|
||||||
} else {
|
} else {
|
||||||
panic!(
|
panic!(
|
||||||
@ -432,9 +420,7 @@ pub fn test_set<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
vm.ip += 1;
|
vm.ip += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let next = vm.runners[vm.ip];
|
vm.execute_next_runner();
|
||||||
|
|
||||||
next.run(vm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -457,13 +443,10 @@ pub fn equal<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
vm.ip += 1;
|
vm.ip += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let next = vm.runners[vm.ip];
|
vm.execute_next_runner();
|
||||||
|
|
||||||
next.run(vm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
pub fn less(vm: &mut Vm, instruction_data: InstructionData) {
|
||||||
pub fn less<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|
||||||
let InstructionData {
|
let InstructionData {
|
||||||
b,
|
b,
|
||||||
c,
|
c,
|
||||||
@ -482,9 +465,7 @@ pub fn less<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
vm.ip += 1;
|
vm.ip += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let next = vm.runners[vm.ip];
|
vm.execute_next_runner();
|
||||||
|
|
||||||
next.run(vm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[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;
|
vm.ip += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let next = vm.runners[vm.ip];
|
vm.execute_next_runner();
|
||||||
|
|
||||||
next.run(vm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -522,12 +501,12 @@ pub fn negate<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
} = instruction_data;
|
} = instruction_data;
|
||||||
let argument = vm.get_argument(b, b_is_constant);
|
let argument = vm.get_argument(b, b_is_constant);
|
||||||
let negated = match argument {
|
let negated = match argument {
|
||||||
ValueRef::Concrete(value) => match value {
|
Value::Concrete(value) => match value {
|
||||||
ConcreteValue::Float(float) => ConcreteValue::Float(-float),
|
ConcreteValue::Float(float) => ConcreteValue::Float(-float),
|
||||||
ConcreteValue::Integer(integer) => ConcreteValue::Integer(-integer),
|
ConcreteValue::Integer(integer) => ConcreteValue::Integer(-integer),
|
||||||
_ => panic!("Value Error: Cannot negate value"),
|
_ => 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));
|
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;
|
vm.ip += 1;
|
||||||
|
|
||||||
let next = vm.runners[vm.ip];
|
vm.execute_next_runner();
|
||||||
|
|
||||||
next.run(vm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -550,7 +527,7 @@ pub fn not<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
} = instruction_data;
|
} = instruction_data;
|
||||||
let argument = vm.get_argument(b, b_is_constant);
|
let argument = vm.get_argument(b, b_is_constant);
|
||||||
let not = match argument {
|
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"),
|
_ => panic!("VM Error: Expected boolean value for NOT operation"),
|
||||||
};
|
};
|
||||||
let register = Register::Value(Value::Concrete(not));
|
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;
|
vm.ip += 1;
|
||||||
|
|
||||||
let next = vm.runners[vm.ip];
|
vm.execute_next_runner();
|
||||||
|
|
||||||
next.run(vm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -576,9 +551,7 @@ pub fn jump<'c>(vm: &mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
vm.ip -= offset
|
vm.ip -= offset
|
||||||
}
|
}
|
||||||
|
|
||||||
let next = vm.runners[vm.ip];
|
vm.execute_next_runner();
|
||||||
|
|
||||||
next.run(vm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -591,9 +564,9 @@ pub fn call<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
..
|
..
|
||||||
} = instruction_data;
|
} = instruction_data;
|
||||||
let function = vm.get_argument(b, b_is_constant);
|
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)
|
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()))
|
Vm::new(vm.source, vm.chunk, Some(vm), Some(vm.runners.clone()))
|
||||||
} else {
|
} else {
|
||||||
panic!("VM Error: Expected function")
|
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();
|
let return_value = function_vm.run();
|
||||||
|
|
||||||
if let Some(concrete_value) = return_value {
|
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.set_register(a, register);
|
||||||
}
|
}
|
||||||
|
|
||||||
vm.ip += 1;
|
vm.ip += 1;
|
||||||
|
|
||||||
let next = vm.runners[vm.ip];
|
vm.execute_next_runner();
|
||||||
|
|
||||||
next.run(vm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[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 InstructionData { a, b, c, .. } = instruction_data;
|
||||||
let first_argument_index = (a - c) as usize;
|
let first_argument_index = (a - c) as usize;
|
||||||
let argument_range = first_argument_index..a 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 {
|
for register_index in argument_range {
|
||||||
let register = &vm.stack[register_index];
|
let register = &vm.stack[register_index];
|
||||||
let value = match register {
|
let value = match register {
|
||||||
Register::Value(value) => value.to_ref(),
|
Register::Value(value) => value,
|
||||||
Register::Pointer(pointer) => {
|
Register::Pointer(pointer) => {
|
||||||
let value_option = vm.follow_pointer_allow_empty(*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;
|
vm.ip += 1;
|
||||||
|
|
||||||
let next = vm.runners[vm.ip];
|
vm.execute_next_runner();
|
||||||
|
|
||||||
next.run(vm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[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 {
|
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);
|
vm.return_value = Some(return_value);
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user