1
0

Use new instruction features

This commit is contained in:
Jeff 2024-11-28 05:36:10 -05:00
parent cc6a152f3c
commit 7e2ebf54c7
5 changed files with 185 additions and 107 deletions

View File

@ -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)

View File

@ -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 { "!" };

View File

@ -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)
} }
} }

View File

@ -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)
} }
} }

View File

@ -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);