Use new instruction features
This commit is contained in:
parent
cc6a152f3c
commit
7e2ebf54c7
@ -785,7 +785,7 @@ impl<'src> Compiler<'src> {
|
|||||||
};
|
};
|
||||||
let test = Instruction::from(Test {
|
let test = Instruction::from(Test {
|
||||||
argument,
|
argument,
|
||||||
value: test_boolean,
|
test_value: test_boolean,
|
||||||
});
|
});
|
||||||
let jump = Instruction::from(Jump {
|
let jump = Instruction::from(Jump {
|
||||||
offset: 1,
|
offset: 1,
|
||||||
@ -976,7 +976,7 @@ impl<'src> Compiler<'src> {
|
|||||||
let test_register = instruction.a();
|
let test_register = instruction.a();
|
||||||
let test = Instruction::from(Test {
|
let test = Instruction::from(Test {
|
||||||
argument: Argument::Register(test_register),
|
argument: Argument::Register(test_register),
|
||||||
value: true,
|
test_value: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.emit_instruction(test, Type::None, self.current_position)
|
self.emit_instruction(test, Type::None, self.current_position)
|
||||||
|
@ -256,14 +256,17 @@ impl Instruction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn test(argument: Argument, value: bool) -> Instruction {
|
pub fn test(argument: Argument, value: bool) -> Instruction {
|
||||||
Instruction::from(Test { argument, value })
|
Instruction::from(Test {
|
||||||
|
argument,
|
||||||
|
test_value: value,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn test_set(destination: Destination, argument: Argument, value: bool) -> Instruction {
|
pub fn test_set(destination: Destination, argument: Argument, value: bool) -> Instruction {
|
||||||
Instruction::from(TestSet {
|
Instruction::from(TestSet {
|
||||||
destination,
|
destination,
|
||||||
argument,
|
argument,
|
||||||
value,
|
test_value: value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -650,7 +653,10 @@ impl Instruction {
|
|||||||
format!("{destination} = {left} % {right}")
|
format!("{destination} = {left} % {right}")
|
||||||
}
|
}
|
||||||
Operation::Test => {
|
Operation::Test => {
|
||||||
let Test { argument, value } = Test::from(self);
|
let Test {
|
||||||
|
argument,
|
||||||
|
test_value: value,
|
||||||
|
} = Test::from(self);
|
||||||
let bang = if value { "" } else { "!" };
|
let bang = if value { "" } else { "!" };
|
||||||
|
|
||||||
format!("if {bang}{argument} {{ JUMP +1 }}",)
|
format!("if {bang}{argument} {{ JUMP +1 }}",)
|
||||||
@ -659,7 +665,7 @@ impl Instruction {
|
|||||||
let TestSet {
|
let TestSet {
|
||||||
destination,
|
destination,
|
||||||
argument,
|
argument,
|
||||||
value,
|
test_value: value,
|
||||||
} = TestSet::from(self);
|
} = TestSet::from(self);
|
||||||
let bang = if value { "" } else { "!" };
|
let bang = if value { "" } else { "!" };
|
||||||
|
|
||||||
|
@ -2,14 +2,14 @@ use crate::{Argument, Instruction, Operation};
|
|||||||
|
|
||||||
pub struct Test {
|
pub struct Test {
|
||||||
pub argument: Argument,
|
pub argument: Argument,
|
||||||
pub value: bool,
|
pub test_value: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&Instruction> for Test {
|
impl From<&Instruction> for Test {
|
||||||
fn from(instruction: &Instruction) -> Self {
|
fn from(instruction: &Instruction) -> Self {
|
||||||
Test {
|
Test {
|
||||||
argument: instruction.b_as_argument(),
|
argument: instruction.b_as_argument(),
|
||||||
value: instruction.c_as_boolean(),
|
test_value: instruction.c_as_boolean(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -20,6 +20,6 @@ impl From<Test> for Instruction {
|
|||||||
.set_b(test.argument.index())
|
.set_b(test.argument.index())
|
||||||
.set_b_is_constant(test.argument.is_constant())
|
.set_b_is_constant(test.argument.is_constant())
|
||||||
.set_b_is_local(test.argument.is_local())
|
.set_b_is_local(test.argument.is_local())
|
||||||
.set_c_to_boolean(test.value)
|
.set_c_to_boolean(test.test_value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ use crate::{Argument, Destination, Instruction, Operation};
|
|||||||
pub struct TestSet {
|
pub struct TestSet {
|
||||||
pub destination: Destination,
|
pub destination: Destination,
|
||||||
pub argument: Argument,
|
pub argument: Argument,
|
||||||
pub value: bool,
|
pub test_value: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&Instruction> for TestSet {
|
impl From<&Instruction> for TestSet {
|
||||||
@ -17,7 +17,7 @@ impl From<&Instruction> for TestSet {
|
|||||||
TestSet {
|
TestSet {
|
||||||
destination,
|
destination,
|
||||||
argument: instruction.b_as_argument(),
|
argument: instruction.b_as_argument(),
|
||||||
value: instruction.c_as_boolean(),
|
test_value: instruction.c_as_boolean(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -35,6 +35,6 @@ impl From<TestSet> for Instruction {
|
|||||||
.set_b(test_set.argument.index())
|
.set_b(test_set.argument.index())
|
||||||
.set_b_is_constant(test_set.argument.is_constant())
|
.set_b_is_constant(test_set.argument.is_constant())
|
||||||
.set_b_is_local(test_set.argument.is_local())
|
.set_b_is_local(test_set.argument.is_local())
|
||||||
.set_c_to_boolean(test_set.value)
|
.set_c_to_boolean(test_set.test_value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,9 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
compile,
|
compile, instruction::*, AbstractValue, AnnotatedError, Argument, Chunk, ChunkError,
|
||||||
instruction::{Negate, Not},
|
ConcreteValue, Destination, DustError, Instruction, NativeFunction, NativeFunctionError,
|
||||||
AbstractValue, AnnotatedError, Argument, Chunk, ChunkError, ConcreteValue, Destination,
|
Operation, Span, Value, ValueError, ValueRef,
|
||||||
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> {
|
||||||
@ -71,69 +69,75 @@ impl<'a> Vm<'a> {
|
|||||||
|
|
||||||
match instruction.operation() {
|
match instruction.operation() {
|
||||||
Operation::Move => {
|
Operation::Move => {
|
||||||
let to_register = instruction.a();
|
let Move { from, to } = Move::from(&instruction);
|
||||||
let from_register = instruction.b();
|
|
||||||
let from_register_has_value = self
|
let from_register_has_value = self
|
||||||
.stack
|
.stack
|
||||||
.get(from_register as usize)
|
.get(from as usize)
|
||||||
.is_some_and(|register| !matches!(register, Register::Empty));
|
.is_some_and(|register| !matches!(register, Register::Empty));
|
||||||
let register = Register::Pointer(Pointer::Stack(from_register));
|
let register = Register::Pointer(Pointer::Stack(from));
|
||||||
|
|
||||||
if from_register_has_value {
|
if from_register_has_value {
|
||||||
self.set_register(to_register, register)?;
|
self.set_register(to, register)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Operation::Close => {
|
Operation::Close => {
|
||||||
let from_register = instruction.b();
|
let Close { from, to } = Close::from(&instruction);
|
||||||
let to_register = instruction.c();
|
|
||||||
|
|
||||||
if self.stack.len() < to_register as usize {
|
if self.stack.len() < to as usize {
|
||||||
return Err(VmError::StackUnderflow {
|
return Err(VmError::StackUnderflow {
|
||||||
position: self.current_position,
|
position: self.current_position,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
for register_index in from_register..to_register {
|
for register_index in from..to {
|
||||||
self.stack[register_index as usize] = Register::Empty;
|
self.stack[register_index as usize] = Register::Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Operation::LoadBoolean => {
|
Operation::LoadBoolean => {
|
||||||
let to_register = instruction.a();
|
let LoadBoolean {
|
||||||
let boolean = instruction.b_as_boolean();
|
destination,
|
||||||
let jump = instruction.c_as_boolean();
|
value,
|
||||||
let boolean = ConcreteValue::Boolean(boolean).to_value();
|
jump_next,
|
||||||
|
} = LoadBoolean::from(&instruction);
|
||||||
|
let register_index = self.get_destination(destination)?;
|
||||||
|
let boolean = ConcreteValue::Boolean(value).to_value();
|
||||||
|
let register = Register::Value(boolean);
|
||||||
|
|
||||||
self.set_register(to_register, Register::Value(boolean))?;
|
self.set_register(register_index, register)?;
|
||||||
|
|
||||||
if jump {
|
if jump_next {
|
||||||
self.ip += 1;
|
self.ip += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Operation::LoadConstant => {
|
Operation::LoadConstant => {
|
||||||
let to_register = instruction.a();
|
let LoadConstant {
|
||||||
let from_constant = instruction.b();
|
destination,
|
||||||
let jump = instruction.c_as_boolean();
|
constant_index,
|
||||||
|
jump_next,
|
||||||
|
} = LoadConstant::from(&instruction);
|
||||||
|
let register_index = self.get_destination(destination)?;
|
||||||
|
let register = Register::Pointer(Pointer::Constant(constant_index));
|
||||||
|
|
||||||
self.set_register(
|
self.set_register(register_index, register)?;
|
||||||
to_register,
|
|
||||||
Register::Pointer(Pointer::Constant(from_constant)),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if jump {
|
if jump_next {
|
||||||
self.ip += 1
|
self.ip += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Operation::LoadList => {
|
Operation::LoadList => {
|
||||||
let to_register = instruction.a();
|
let LoadList {
|
||||||
let start_register = instruction.b();
|
destination,
|
||||||
|
start_register,
|
||||||
|
} = LoadList::from(&instruction);
|
||||||
|
let register_index = self.get_destination(destination)?;
|
||||||
let mut pointers = Vec::new();
|
let mut pointers = Vec::new();
|
||||||
|
|
||||||
for register_index in start_register..to_register {
|
for register in start_register..register_index {
|
||||||
if let Some(Register::Empty) = self.stack.get(register_index as usize) {
|
if let Some(Register::Empty) = self.stack.get(register as usize) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let pointer = Pointer::Stack(register_index);
|
let pointer = Pointer::Stack(register);
|
||||||
|
|
||||||
pointers.push(pointer);
|
pointers.push(pointer);
|
||||||
}
|
}
|
||||||
@ -141,23 +145,30 @@ impl<'a> Vm<'a> {
|
|||||||
let register =
|
let register =
|
||||||
Register::Value(AbstractValue::List { items: pointers }.to_value());
|
Register::Value(AbstractValue::List { items: pointers }.to_value());
|
||||||
|
|
||||||
self.set_register(to_register, register)?;
|
self.set_register(register_index, register)?;
|
||||||
}
|
}
|
||||||
Operation::LoadSelf => {
|
Operation::LoadSelf => {
|
||||||
let to_register = instruction.a();
|
let LoadSelf { destination } = LoadSelf::from(&instruction);
|
||||||
|
let register_index = self.get_destination(destination)?;
|
||||||
let register = Register::Value(AbstractValue::FunctionSelf.to_value());
|
let register = Register::Value(AbstractValue::FunctionSelf.to_value());
|
||||||
|
|
||||||
self.set_register(to_register, register)?;
|
self.set_register(register_index, register)?;
|
||||||
}
|
}
|
||||||
Operation::DefineLocal => {
|
Operation::DefineLocal => {
|
||||||
let from_register = instruction.a();
|
let DefineLocal {
|
||||||
let to_local = instruction.b();
|
register,
|
||||||
|
local_index,
|
||||||
|
is_mutable,
|
||||||
|
} = DefineLocal::from(&instruction);
|
||||||
|
|
||||||
self.local_definitions[to_local as usize] = Some(from_register);
|
self.local_definitions[local_index as usize] = Some(register);
|
||||||
}
|
}
|
||||||
Operation::GetLocal => {
|
Operation::GetLocal => {
|
||||||
let to_register = instruction.a();
|
let GetLocal {
|
||||||
let local_index = instruction.b();
|
destination,
|
||||||
|
local_index,
|
||||||
|
} = GetLocal::from(&instruction);
|
||||||
|
let register_index = self.get_destination(destination)?;
|
||||||
let local_register = self.local_definitions[local_index as usize].ok_or(
|
let local_register = self.local_definitions[local_index as usize].ok_or(
|
||||||
VmError::UndefinedLocal {
|
VmError::UndefinedLocal {
|
||||||
local_index,
|
local_index,
|
||||||
@ -166,68 +177,102 @@ impl<'a> Vm<'a> {
|
|||||||
)?;
|
)?;
|
||||||
let register = Register::Pointer(Pointer::Stack(local_register));
|
let register = Register::Pointer(Pointer::Stack(local_register));
|
||||||
|
|
||||||
self.set_register(to_register, register)?;
|
self.set_register(register_index, register)?;
|
||||||
}
|
}
|
||||||
Operation::SetLocal => {
|
Operation::SetLocal => {
|
||||||
let from_register = instruction.a();
|
let SetLocal {
|
||||||
let to_local = instruction.b();
|
register,
|
||||||
|
local_index,
|
||||||
|
} = SetLocal::from(&instruction);
|
||||||
|
|
||||||
self.local_definitions[to_local as usize] = Some(from_register);
|
self.local_definitions[local_index as usize] = Some(register);
|
||||||
}
|
}
|
||||||
Operation::Add => {
|
Operation::Add => {
|
||||||
let to_register = instruction.a();
|
let Add {
|
||||||
let (left, right) = self.get_arguments(instruction)?;
|
destination,
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
} = Add::from(&instruction);
|
||||||
|
let register_index = self.get_destination(destination)?;
|
||||||
|
let left = self.get_argument(left)?;
|
||||||
|
let right = self.get_argument(right)?;
|
||||||
let sum = left.add(right).map_err(|error| VmError::Value {
|
let sum = left.add(right).map_err(|error| VmError::Value {
|
||||||
error,
|
error,
|
||||||
position: self.current_position,
|
position: self.current_position,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
self.set_register(to_register, Register::Value(sum))?;
|
self.set_register(register_index, Register::Value(sum))?;
|
||||||
}
|
}
|
||||||
Operation::Subtract => {
|
Operation::Subtract => {
|
||||||
let to_register = instruction.a();
|
let Subtract {
|
||||||
let (left, right) = self.get_arguments(instruction)?;
|
destination,
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
} = Subtract::from(&instruction);
|
||||||
|
let register_index = self.get_destination(destination)?;
|
||||||
|
let left = self.get_argument(left)?;
|
||||||
|
let right = self.get_argument(right)?;
|
||||||
let difference = left.subtract(right).map_err(|error| VmError::Value {
|
let difference = left.subtract(right).map_err(|error| VmError::Value {
|
||||||
error,
|
error,
|
||||||
position: self.current_position,
|
position: self.current_position,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
self.set_register(to_register, Register::Value(difference))?;
|
self.set_register(register_index, Register::Value(difference))?;
|
||||||
}
|
}
|
||||||
Operation::Multiply => {
|
Operation::Multiply => {
|
||||||
let to_register = instruction.a();
|
let Multiply {
|
||||||
let (left, right) = self.get_arguments(instruction)?;
|
destination,
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
} = Multiply::from(&instruction);
|
||||||
|
let register_index = self.get_destination(destination)?;
|
||||||
|
let left = self.get_argument(left)?;
|
||||||
|
let right = self.get_argument(right)?;
|
||||||
let product = left.multiply(right).map_err(|error| VmError::Value {
|
let product = left.multiply(right).map_err(|error| VmError::Value {
|
||||||
error,
|
error,
|
||||||
position: self.current_position,
|
position: self.current_position,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
self.set_register(to_register, Register::Value(product))?;
|
self.set_register(register_index, Register::Value(product))?;
|
||||||
}
|
}
|
||||||
Operation::Divide => {
|
Operation::Divide => {
|
||||||
let to_register = instruction.a();
|
let Divide {
|
||||||
let (left, right) = self.get_arguments(instruction)?;
|
destination,
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
} = Divide::from(&instruction);
|
||||||
|
let register_index = self.get_destination(destination)?;
|
||||||
|
let left = self.get_argument(left)?;
|
||||||
|
let right = self.get_argument(right)?;
|
||||||
let quotient = left.divide(right).map_err(|error| VmError::Value {
|
let quotient = left.divide(right).map_err(|error| VmError::Value {
|
||||||
error,
|
error,
|
||||||
position: self.current_position,
|
position: self.current_position,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
self.set_register(to_register, Register::Value(quotient))?;
|
self.set_register(register_index, Register::Value(quotient))?;
|
||||||
}
|
}
|
||||||
Operation::Modulo => {
|
Operation::Modulo => {
|
||||||
let to_register = instruction.a();
|
let Modulo {
|
||||||
let (left, right) = self.get_arguments(instruction)?;
|
destination,
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
} = Modulo::from(&instruction);
|
||||||
|
let register_index = self.get_destination(destination)?;
|
||||||
|
let left = self.get_argument(left)?;
|
||||||
|
let right = self.get_argument(right)?;
|
||||||
let remainder = left.modulo(right).map_err(|error| VmError::Value {
|
let remainder = left.modulo(right).map_err(|error| VmError::Value {
|
||||||
error,
|
error,
|
||||||
position: self.current_position,
|
position: self.current_position,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
self.set_register(to_register, Register::Value(remainder))?;
|
self.set_register(register_index, Register::Value(remainder))?;
|
||||||
}
|
}
|
||||||
Operation::Test => {
|
Operation::Test => {
|
||||||
let test_register = instruction.b();
|
let Test {
|
||||||
let test_value = instruction.c_as_boolean();
|
argument,
|
||||||
let value = self.open_register(test_register)?;
|
test_value,
|
||||||
|
} = Test::from(&instruction);
|
||||||
|
let value = self.get_argument(argument)?;
|
||||||
let boolean = if let ValueRef::Concrete(ConcreteValue::Boolean(boolean)) = value
|
let boolean = if let ValueRef::Concrete(ConcreteValue::Boolean(boolean)) = value
|
||||||
{
|
{
|
||||||
*boolean
|
*boolean
|
||||||
@ -243,10 +288,13 @@ impl<'a> Vm<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Operation::TestSet => {
|
Operation::TestSet => {
|
||||||
let to_register = instruction.a();
|
let TestSet {
|
||||||
let test_register = instruction.b();
|
destination,
|
||||||
let test_value = instruction.c_as_boolean();
|
argument,
|
||||||
let value = self.open_register(test_register)?;
|
test_value,
|
||||||
|
} = TestSet::from(&instruction);
|
||||||
|
let register_index = self.get_destination(destination)?;
|
||||||
|
let value = self.get_argument(argument)?;
|
||||||
let boolean = if let ValueRef::Concrete(ConcreteValue::Boolean(boolean)) = value
|
let boolean = if let ValueRef::Concrete(ConcreteValue::Boolean(boolean)) = value
|
||||||
{
|
{
|
||||||
*boolean
|
*boolean
|
||||||
@ -260,15 +308,28 @@ impl<'a> Vm<'a> {
|
|||||||
if boolean == test_value {
|
if boolean == test_value {
|
||||||
self.ip += 1;
|
self.ip += 1;
|
||||||
} else {
|
} else {
|
||||||
let register = Register::Pointer(Pointer::Stack(test_register));
|
let pointer = match argument {
|
||||||
|
Argument::Constant(constant_index) => Pointer::Constant(constant_index),
|
||||||
|
Argument::Local(local_index) => {
|
||||||
|
let register_index = self.local_definitions[local_index as usize]
|
||||||
|
.ok_or(VmError::UndefinedLocal {
|
||||||
|
local_index,
|
||||||
|
position: self.current_position,
|
||||||
|
})?;
|
||||||
|
|
||||||
self.set_register(to_register, register)?;
|
Pointer::Stack(register_index)
|
||||||
|
}
|
||||||
|
Argument::Register(register_index) => Pointer::Stack(register_index),
|
||||||
|
};
|
||||||
|
let register = Register::Pointer(pointer);
|
||||||
|
|
||||||
|
self.set_register(register_index, register)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Operation::Equal => {
|
Operation::Equal => {
|
||||||
let compare_to = instruction.a_as_boolean();
|
let Equal { value, left, right } = Equal::from(&instruction);
|
||||||
let (left, right) = self.get_arguments(instruction)?;
|
let left = self.get_argument(left)?;
|
||||||
|
let right = self.get_argument(right)?;
|
||||||
let equal_result = left.equal(right).map_err(|error| VmError::Value {
|
let equal_result = left.equal(right).map_err(|error| VmError::Value {
|
||||||
error,
|
error,
|
||||||
position: self.current_position,
|
position: self.current_position,
|
||||||
@ -283,7 +344,7 @@ impl<'a> Vm<'a> {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
if is_equal == compare_to {
|
if is_equal == value {
|
||||||
self.ip += 1;
|
self.ip += 1;
|
||||||
} else {
|
} else {
|
||||||
let jump = self.read()?;
|
let jump = self.read()?;
|
||||||
@ -292,8 +353,9 @@ impl<'a> Vm<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Operation::Less => {
|
Operation::Less => {
|
||||||
let compare_to = instruction.a_as_boolean();
|
let Less { value, left, right } = Less::from(&instruction);
|
||||||
let (left, right) = self.get_arguments(instruction)?;
|
let left = self.get_argument(left)?;
|
||||||
|
let right = self.get_argument(right)?;
|
||||||
let less_result = left.less_than(right).map_err(|error| VmError::Value {
|
let less_result = left.less_than(right).map_err(|error| VmError::Value {
|
||||||
error,
|
error,
|
||||||
position: self.current_position,
|
position: self.current_position,
|
||||||
@ -308,7 +370,7 @@ impl<'a> Vm<'a> {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
if is_less_than == compare_to {
|
if is_less_than == value {
|
||||||
self.ip += 1;
|
self.ip += 1;
|
||||||
} else {
|
} else {
|
||||||
let jump = self.read()?;
|
let jump = self.read()?;
|
||||||
@ -317,8 +379,9 @@ impl<'a> Vm<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Operation::LessEqual => {
|
Operation::LessEqual => {
|
||||||
let compare_to = instruction.a_as_boolean();
|
let LessEqual { value, left, right } = LessEqual::from(&instruction);
|
||||||
let (left, right) = self.get_arguments(instruction)?;
|
let left = self.get_argument(left)?;
|
||||||
|
let right = self.get_argument(right)?;
|
||||||
let less_or_equal_result =
|
let less_or_equal_result =
|
||||||
left.less_than_or_equal(right)
|
left.less_than_or_equal(right)
|
||||||
.map_err(|error| VmError::Value {
|
.map_err(|error| VmError::Value {
|
||||||
@ -337,7 +400,7 @@ impl<'a> Vm<'a> {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
if is_less_than_or_equal == compare_to {
|
if is_less_than_or_equal == value {
|
||||||
self.ip += 1;
|
self.ip += 1;
|
||||||
} else {
|
} else {
|
||||||
let jump = self.read()?;
|
let jump = self.read()?;
|
||||||
@ -377,26 +440,29 @@ impl<'a> Vm<'a> {
|
|||||||
}
|
}
|
||||||
Operation::Jump => self.jump(instruction),
|
Operation::Jump => self.jump(instruction),
|
||||||
Operation::Call => {
|
Operation::Call => {
|
||||||
let to_register = instruction.a();
|
let Call {
|
||||||
let function_register = instruction.b();
|
destination,
|
||||||
let argument_count = instruction.c();
|
function,
|
||||||
let value = self.open_register(function_register)?;
|
argument_count,
|
||||||
let chunk = if let ValueRef::Concrete(ConcreteValue::Function(chunk)) = value {
|
} = Call::from(&instruction);
|
||||||
|
let register_index = self.get_destination(destination)?;
|
||||||
|
let function = self.get_argument(function)?;
|
||||||
|
let chunk = if let ValueRef::Concrete(ConcreteValue::Function(chunk)) = function
|
||||||
|
{
|
||||||
chunk
|
chunk
|
||||||
} else if let ValueRef::Abstract(AbstractValue::FunctionSelf) = value {
|
} else if let ValueRef::Abstract(AbstractValue::FunctionSelf) = function {
|
||||||
self.chunk
|
self.chunk
|
||||||
} else {
|
} else {
|
||||||
return Err(VmError::ExpectedFunction {
|
return Err(VmError::ExpectedFunction {
|
||||||
found: value.to_concrete_owned(self)?,
|
found: function.to_concrete_owned(self)?,
|
||||||
position: self.current_position,
|
position: self.current_position,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
let mut function_vm = Vm::new(chunk, Some(self));
|
let mut function_vm = Vm::new(chunk, Some(self));
|
||||||
let first_argument_index = function_register + 1;
|
let first_argument_index = register_index - argument_count;
|
||||||
let last_argument_index = first_argument_index + argument_count;
|
|
||||||
|
|
||||||
for (argument_index, argument_register_index) in
|
for (argument_index, argument_register_index) in
|
||||||
(first_argument_index..last_argument_index).enumerate()
|
(first_argument_index..register_index).enumerate()
|
||||||
{
|
{
|
||||||
function_vm.set_register(
|
function_vm.set_register(
|
||||||
argument_index as u16,
|
argument_index as u16,
|
||||||
@ -411,22 +477,28 @@ impl<'a> Vm<'a> {
|
|||||||
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.to_value());
|
||||||
|
|
||||||
self.set_register(to_register, register)?;
|
self.set_register(register_index, register)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Operation::CallNative => {
|
Operation::CallNative => {
|
||||||
let native_function = NativeFunction::from(instruction.b());
|
let CallNative {
|
||||||
let return_value = native_function.call(self, instruction)?;
|
destination,
|
||||||
|
function,
|
||||||
|
argument_count,
|
||||||
|
} = CallNative::from(&instruction);
|
||||||
|
let return_value = function.call(self, instruction)?;
|
||||||
|
|
||||||
if let Some(value) = return_value {
|
if let Some(value) = return_value {
|
||||||
let to_register = instruction.a();
|
let register_index = self.get_destination(destination)?;
|
||||||
let register = Register::Value(value);
|
let register = Register::Value(value);
|
||||||
|
|
||||||
self.set_register(to_register, register)?;
|
self.set_register(register_index, register)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Operation::Return => {
|
Operation::Return => {
|
||||||
let should_return_value = instruction.b_as_boolean();
|
let Return {
|
||||||
|
should_return_value,
|
||||||
|
} = Return::from(&instruction);
|
||||||
|
|
||||||
if !should_return_value {
|
if !should_return_value {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
|
Loading…
Reference in New Issue
Block a user