Replace complex actions with a simple loop
This commit is contained in:
parent
0292a01162
commit
5de44b58ee
@ -1,6 +1,6 @@
|
||||
use std::{ops::Range, panic};
|
||||
|
||||
use crate::vm::{RuntimeValue, Thread};
|
||||
use crate::vm::Thread;
|
||||
|
||||
pub fn panic(data: &mut Thread, _: usize, argument_range: Range<usize>) {
|
||||
let current_frame = data.current_frame();
|
||||
@ -8,20 +8,9 @@ pub fn panic(data: &mut Thread, _: usize, argument_range: Range<usize>) {
|
||||
let mut message = format!("Dust panic at {position}!");
|
||||
|
||||
for register_index in argument_range {
|
||||
let string_value = current_frame.get_string_from_register(register_index);
|
||||
|
||||
match string_value {
|
||||
RuntimeValue::Raw(value) => {
|
||||
message.push_str(value.as_str());
|
||||
}
|
||||
RuntimeValue::Rc(rc) => {
|
||||
message.push_str(rc.as_str());
|
||||
}
|
||||
RuntimeValue::RefCell(ref_cell) => {
|
||||
message.push_str(ref_cell.borrow().as_str());
|
||||
}
|
||||
}
|
||||
let string = current_frame.get_string_from_register(register_index);
|
||||
|
||||
message.push_str(string);
|
||||
message.push('\n');
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::io::{stdin, stdout, Write};
|
||||
use std::ops::Range;
|
||||
|
||||
use crate::vm::{RuntimeValue, Thread};
|
||||
use crate::vm::Thread;
|
||||
use crate::DustString;
|
||||
|
||||
pub fn read_line(data: &mut Thread, destination: usize, _argument_range: Range<usize>) {
|
||||
@ -13,53 +13,34 @@ pub fn read_line(data: &mut Thread, destination: usize, _argument_range: Range<u
|
||||
|
||||
buffer.truncate(length.saturating_sub(1));
|
||||
|
||||
let string = RuntimeValue::Raw(DustString::from(buffer));
|
||||
let string = DustString::from(buffer);
|
||||
|
||||
current_frame.registers.strings[destination].set(string);
|
||||
current_frame
|
||||
.registers
|
||||
.strings
|
||||
.set_to_new_register(destination, string);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(data: &mut Thread, _: usize, argument_range: Range<usize>) {
|
||||
let current_frame = data.current_frame();
|
||||
let current_frame = data.current_frame_mut();
|
||||
let mut stdout = stdout();
|
||||
|
||||
for register_index in argument_range {
|
||||
let value = current_frame.get_string_from_register(register_index);
|
||||
|
||||
match value {
|
||||
RuntimeValue::Raw(value) => {
|
||||
let _ = stdout.write(value.as_bytes());
|
||||
}
|
||||
RuntimeValue::Rc(value) => {
|
||||
let _ = stdout.write(value.as_bytes());
|
||||
}
|
||||
RuntimeValue::RefCell(ref_cell) => {
|
||||
let _ = stdout.write(ref_cell.borrow().as_bytes());
|
||||
}
|
||||
}
|
||||
let string = current_frame.get_string_from_register(register_index);
|
||||
let _ = stdout.write(string.as_bytes());
|
||||
}
|
||||
|
||||
let _ = stdout.flush();
|
||||
}
|
||||
|
||||
pub fn write_line(data: &mut Thread, _: usize, argument_range: Range<usize>) {
|
||||
let current_frame = data.current_frame();
|
||||
let current_frame = data.current_frame_mut();
|
||||
let mut stdout = stdout().lock();
|
||||
|
||||
for register_index in argument_range {
|
||||
let value = current_frame.get_string_from_register(register_index);
|
||||
|
||||
match value {
|
||||
RuntimeValue::Raw(value) => {
|
||||
let _ = stdout.write(value.as_bytes());
|
||||
}
|
||||
RuntimeValue::Rc(value) => {
|
||||
let _ = stdout.write(value.as_bytes());
|
||||
}
|
||||
RuntimeValue::RefCell(ref_cell) => {
|
||||
let _ = stdout.write(ref_cell.borrow().as_bytes());
|
||||
}
|
||||
}
|
||||
let string = current_frame.get_string_from_register(register_index);
|
||||
let _ = stdout.write(string.as_bytes());
|
||||
}
|
||||
|
||||
let _ = stdout.write(b"\n");
|
||||
|
@ -2,7 +2,7 @@ use std::ops::Range;
|
||||
|
||||
use rand::Rng;
|
||||
|
||||
use crate::vm::{RuntimeValue, Thread};
|
||||
use crate::vm::Thread;
|
||||
|
||||
pub fn random_int(data: &mut Thread, destination: usize, argument_range: Range<usize>) {
|
||||
let current_frame = data.current_frame_mut();
|
||||
@ -14,9 +14,7 @@ pub fn random_int(data: &mut Thread, destination: usize, argument_range: Range<u
|
||||
let register_index = argument_range_iter
|
||||
.next()
|
||||
.unwrap_or_else(|| panic!("No argument was passed to \"random_int\""));
|
||||
let integer = current_frame
|
||||
.get_integer_from_register(register_index)
|
||||
.clone_inner();
|
||||
let integer = current_frame.get_integer_from_register(register_index);
|
||||
|
||||
if min.is_none() {
|
||||
min = Some(integer);
|
||||
@ -31,6 +29,5 @@ pub fn random_int(data: &mut Thread, destination: usize, argument_range: Range<u
|
||||
current_frame
|
||||
.registers
|
||||
.integers
|
||||
.get_mut(destination)
|
||||
.set(RuntimeValue::Raw(random_integer));
|
||||
.set_to_new_register(destination, random_integer);
|
||||
}
|
||||
|
@ -507,117 +507,117 @@ fn r#return(_: &mut usize, instruction: &Instruction, thread: &mut Thread, _: &m
|
||||
let return_type = instruction.b_type();
|
||||
let current_frame = thread.current_frame();
|
||||
|
||||
if should_return_value {
|
||||
match return_type {
|
||||
TypeCode::BOOLEAN => {
|
||||
let return_value = current_frame
|
||||
.get_boolean_from_register(return_register)
|
||||
.clone_inner();
|
||||
thread.return_value = Some(Value::boolean(return_value));
|
||||
}
|
||||
TypeCode::BYTE => {
|
||||
let return_value = current_frame
|
||||
.get_byte_from_register(return_register)
|
||||
.clone_inner();
|
||||
thread.return_value = Some(Value::byte(return_value));
|
||||
}
|
||||
TypeCode::CHARACTER => {
|
||||
let return_value = current_frame
|
||||
.get_character_from_register(return_register)
|
||||
.clone_inner();
|
||||
thread.return_value = Some(Value::character(return_value));
|
||||
}
|
||||
TypeCode::FLOAT => {
|
||||
let return_value = current_frame
|
||||
.get_float_from_register(return_register)
|
||||
.clone_inner();
|
||||
thread.return_value = Some(Value::float(return_value));
|
||||
}
|
||||
TypeCode::INTEGER => {
|
||||
let return_value = current_frame
|
||||
.get_integer_from_register(return_register)
|
||||
.clone_inner();
|
||||
thread.return_value = Some(Value::integer(return_value));
|
||||
}
|
||||
TypeCode::STRING => {
|
||||
let return_value = current_frame
|
||||
.get_string_from_register(return_register)
|
||||
.clone_inner();
|
||||
thread.return_value = Some(Value::string(return_value));
|
||||
}
|
||||
TypeCode::LIST => {
|
||||
let abstract_list = current_frame
|
||||
.get_list_from_register(return_register)
|
||||
.clone_inner();
|
||||
let mut concrete_list = Vec::with_capacity(abstract_list.item_pointers.len());
|
||||
// if should_return_value {
|
||||
// match return_type {
|
||||
// TypeCode::BOOLEAN => {
|
||||
// let return_value = current_frame
|
||||
// .get_boolean_from_register(return_register)
|
||||
// .clone_inner();
|
||||
// thread.return_value = Some(Value::boolean(return_value));
|
||||
// }
|
||||
// TypeCode::BYTE => {
|
||||
// let return_value = current_frame
|
||||
// .get_byte_from_register(return_register)
|
||||
// .clone_inner();
|
||||
// thread.return_value = Some(Value::byte(return_value));
|
||||
// }
|
||||
// TypeCode::CHARACTER => {
|
||||
// let return_value = current_frame
|
||||
// .get_character_from_register(return_register)
|
||||
// .clone_inner();
|
||||
// thread.return_value = Some(Value::character(return_value));
|
||||
// }
|
||||
// TypeCode::FLOAT => {
|
||||
// let return_value = current_frame
|
||||
// .get_float_from_register(return_register)
|
||||
// .clone_inner();
|
||||
// thread.return_value = Some(Value::float(return_value));
|
||||
// }
|
||||
// TypeCode::INTEGER => {
|
||||
// let return_value = current_frame
|
||||
// .get_integer_from_register(return_register)
|
||||
// .clone_inner();
|
||||
// thread.return_value = Some(Value::integer(return_value));
|
||||
// }
|
||||
// TypeCode::STRING => {
|
||||
// let return_value = current_frame
|
||||
// .get_string_from_register(return_register)
|
||||
// .clone_inner();
|
||||
// thread.return_value = Some(Value::string(return_value));
|
||||
// }
|
||||
// TypeCode::LIST => {
|
||||
// let abstract_list = current_frame
|
||||
// .get_list_from_register(return_register)
|
||||
// .clone_inner();
|
||||
// let mut concrete_list = Vec::with_capacity(abstract_list.item_pointers.len());
|
||||
|
||||
match abstract_list.item_type {
|
||||
TypeCode::BOOLEAN => {
|
||||
for pointer in abstract_list.item_pointers {
|
||||
let boolean = current_frame
|
||||
.get_boolean_from_pointer(&pointer)
|
||||
.clone_inner();
|
||||
let value = ConcreteValue::Boolean(boolean);
|
||||
// match abstract_list.item_type {
|
||||
// TypeCode::BOOLEAN => {
|
||||
// for pointer in abstract_list.item_pointers {
|
||||
// let boolean = current_frame
|
||||
// .get_boolean_from_pointer(&pointer)
|
||||
// .clone_inner();
|
||||
// let value = ConcreteValue::Boolean(boolean);
|
||||
|
||||
concrete_list.push(value);
|
||||
}
|
||||
}
|
||||
TypeCode::BYTE => {
|
||||
for pointer in abstract_list.item_pointers {
|
||||
let byte = current_frame.get_byte_from_pointer(&pointer).clone_inner();
|
||||
let value = ConcreteValue::Byte(byte);
|
||||
// concrete_list.push(value);
|
||||
// }
|
||||
// }
|
||||
// TypeCode::BYTE => {
|
||||
// for pointer in abstract_list.item_pointers {
|
||||
// let byte = current_frame.get_byte_from_pointer(&pointer).clone_inner();
|
||||
// let value = ConcreteValue::Byte(byte);
|
||||
|
||||
concrete_list.push(value);
|
||||
}
|
||||
}
|
||||
TypeCode::CHARACTER => {
|
||||
for pointer in abstract_list.item_pointers {
|
||||
let character = current_frame
|
||||
.get_character_from_pointer(&pointer)
|
||||
.clone_inner();
|
||||
let value = ConcreteValue::Character(character);
|
||||
// concrete_list.push(value);
|
||||
// }
|
||||
// }
|
||||
// TypeCode::CHARACTER => {
|
||||
// for pointer in abstract_list.item_pointers {
|
||||
// let character = current_frame
|
||||
// .get_character_from_pointer(&pointer)
|
||||
// .clone_inner();
|
||||
// let value = ConcreteValue::Character(character);
|
||||
|
||||
concrete_list.push(value);
|
||||
}
|
||||
}
|
||||
TypeCode::FLOAT => {
|
||||
for pointer in abstract_list.item_pointers {
|
||||
let float =
|
||||
current_frame.get_float_from_pointer(&pointer).clone_inner();
|
||||
let value = ConcreteValue::Float(float);
|
||||
// concrete_list.push(value);
|
||||
// }
|
||||
// }
|
||||
// TypeCode::FLOAT => {
|
||||
// for pointer in abstract_list.item_pointers {
|
||||
// let float =
|
||||
// current_frame.get_float_from_pointer(&pointer).clone_inner();
|
||||
// let value = ConcreteValue::Float(float);
|
||||
|
||||
concrete_list.push(value);
|
||||
}
|
||||
}
|
||||
TypeCode::INTEGER => {
|
||||
for pointer in abstract_list.item_pointers {
|
||||
let integer = current_frame
|
||||
.get_integer_from_pointer(&pointer)
|
||||
.clone_inner();
|
||||
let value = ConcreteValue::Integer(integer);
|
||||
// concrete_list.push(value);
|
||||
// }
|
||||
// }
|
||||
// TypeCode::INTEGER => {
|
||||
// for pointer in abstract_list.item_pointers {
|
||||
// let integer = current_frame
|
||||
// .get_integer_from_pointer(&pointer)
|
||||
// .clone_inner();
|
||||
// let value = ConcreteValue::Integer(integer);
|
||||
|
||||
concrete_list.push(value);
|
||||
}
|
||||
}
|
||||
TypeCode::STRING => {
|
||||
for pointer in abstract_list.item_pointers {
|
||||
let string = current_frame
|
||||
.get_string_from_pointer(&pointer)
|
||||
.clone_inner();
|
||||
let value = ConcreteValue::String(string);
|
||||
// concrete_list.push(value);
|
||||
// }
|
||||
// }
|
||||
// TypeCode::STRING => {
|
||||
// for pointer in abstract_list.item_pointers {
|
||||
// let string = current_frame
|
||||
// .get_string_from_pointer(&pointer)
|
||||
// .clone_inner();
|
||||
// let value = ConcreteValue::String(string);
|
||||
|
||||
concrete_list.push(value);
|
||||
}
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
// concrete_list.push(value);
|
||||
// }
|
||||
// }
|
||||
// _ => todo!(),
|
||||
// }
|
||||
|
||||
thread.return_value = Some(Value::Concrete(ConcreteValue::list(
|
||||
concrete_list,
|
||||
abstract_list.item_type,
|
||||
)));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
// thread.return_value = Some(Value::Concrete(ConcreteValue::list(
|
||||
// concrete_list,
|
||||
// abstract_list.item_type,
|
||||
// )));
|
||||
// }
|
||||
// _ => unreachable!(),
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ pub struct CallFrame {
|
||||
pub ip: usize,
|
||||
pub return_register: u16,
|
||||
pub registers: RegisterTable,
|
||||
pub constants: ConstantTable,
|
||||
}
|
||||
|
||||
impl CallFrame {
|
||||
@ -30,174 +29,126 @@ impl CallFrame {
|
||||
lists: RegisterList::new(chunk.list_register_count as usize),
|
||||
functions: RegisterList::new(chunk.function_register_count as usize),
|
||||
};
|
||||
let constants = ConstantTable {
|
||||
characters: chunk
|
||||
.character_constants
|
||||
.iter()
|
||||
.map(|&character| RuntimeValue::Raw(character))
|
||||
.collect(),
|
||||
floats: chunk
|
||||
.float_constants
|
||||
.iter()
|
||||
.map(|&float| RuntimeValue::Raw(float))
|
||||
.collect(),
|
||||
integers: chunk
|
||||
.integer_constants
|
||||
.iter()
|
||||
.map(|&integer| RuntimeValue::Raw(integer))
|
||||
.collect(),
|
||||
strings: chunk
|
||||
.string_constants
|
||||
.iter()
|
||||
.map(|string| RuntimeValue::Raw(string.clone()))
|
||||
.collect(),
|
||||
};
|
||||
|
||||
Self {
|
||||
chunk,
|
||||
ip: 0,
|
||||
return_register,
|
||||
registers,
|
||||
constants,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_boolean_from_register(&self, register_index: usize) -> &RuntimeValue<bool> {
|
||||
pub fn get_boolean_from_register(&self, register_index: usize) -> bool {
|
||||
let register = self.registers.booleans.get(register_index);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => value,
|
||||
Register::Value { value, .. } => *value,
|
||||
Register::Pointer { pointer, .. } => self.get_boolean_from_pointer(pointer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_boolean_from_pointer(&self, pointer: &Pointer) -> &RuntimeValue<bool> {
|
||||
pub fn get_boolean_from_pointer(&self, pointer: &Pointer) -> bool {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_boolean_from_register(*register_index),
|
||||
Pointer::Constant(_) => panic!("Attempted to get boolean from constant pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_byte_from_register(&self, register_index: usize) -> &RuntimeValue<u8> {
|
||||
pub fn get_byte_from_register(&self, register_index: usize) -> u8 {
|
||||
let register = self.registers.bytes.get(register_index);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => value,
|
||||
Register::Value { value, .. } => *value,
|
||||
Register::Pointer { pointer, .. } => self.get_byte_from_pointer(pointer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_byte_from_pointer(&self, pointer: &Pointer) -> &RuntimeValue<u8> {
|
||||
pub fn get_byte_from_pointer(&self, pointer: &Pointer) -> u8 {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_byte_from_register(*register_index),
|
||||
Pointer::Constant(_) => panic!("Attempted to get byte from constant pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_character_from_register(&self, register_index: usize) -> &RuntimeValue<char> {
|
||||
pub fn get_character_from_register(&self, register_index: usize) -> char {
|
||||
let register = self.registers.characters.get(register_index);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => value,
|
||||
Register::Value { value, .. } => *value,
|
||||
Register::Pointer { pointer, .. } => self.get_character_from_pointer(pointer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_character_from_pointer(&self, pointer: &Pointer) -> &RuntimeValue<char> {
|
||||
pub fn get_character_from_pointer(&self, pointer: &Pointer) -> char {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_character_from_register(*register_index),
|
||||
Pointer::Constant(constant_index) => self.get_character_constant(*constant_index),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_character_constant(&self, constant_index: usize) -> &RuntimeValue<char> {
|
||||
if cfg!(debug_assertions) {
|
||||
self.constants.characters.get(constant_index).unwrap()
|
||||
pub fn get_character_constant(&self, constant_index: usize) -> char {
|
||||
let constant = if cfg!(debug_assertions) {
|
||||
self.chunk.character_constants.get(constant_index).unwrap()
|
||||
} else {
|
||||
unsafe { self.constants.characters.get_unchecked(constant_index) }
|
||||
}
|
||||
unsafe { self.chunk.character_constants.get_unchecked(constant_index) }
|
||||
};
|
||||
|
||||
*constant
|
||||
}
|
||||
|
||||
pub fn get_float_from_register(&self, register_index: usize) -> &RuntimeValue<f64> {
|
||||
pub fn get_float_from_register(&self, register_index: usize) -> f64 {
|
||||
let register = self.registers.floats.get(register_index);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => value,
|
||||
Register::Value { value, .. } => *value,
|
||||
Register::Pointer { pointer, .. } => self.get_float_from_pointer(pointer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_float_from_pointer(&self, pointer: &Pointer) -> &RuntimeValue<f64> {
|
||||
pub fn get_float_from_pointer(&self, pointer: &Pointer) -> f64 {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_float_from_register(*register_index),
|
||||
Pointer::Constant(constant_index) => self.get_float_constant(*constant_index),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_float_constant(&self, constant_index: usize) -> &RuntimeValue<f64> {
|
||||
if cfg!(debug_assertions) {
|
||||
self.constants.floats.get(constant_index).unwrap()
|
||||
pub fn get_float_constant(&self, constant_index: usize) -> f64 {
|
||||
let constant = if cfg!(debug_assertions) {
|
||||
self.chunk.float_constants.get(constant_index).unwrap()
|
||||
} else {
|
||||
unsafe { self.constants.floats.get_unchecked(constant_index) }
|
||||
}
|
||||
unsafe { self.chunk.float_constants.get_unchecked(constant_index) }
|
||||
};
|
||||
|
||||
*constant
|
||||
}
|
||||
|
||||
pub fn get_integer_from_register(&self, register_index: usize) -> &RuntimeValue<i64> {
|
||||
pub fn get_integer_from_register(&self, register_index: usize) -> i64 {
|
||||
let register = self.registers.integers.get(register_index);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => value,
|
||||
Register::Value { value, .. } => *value,
|
||||
Register::Pointer { pointer, .. } => self.get_integer_from_pointer(pointer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_integer_from_register_mut(
|
||||
&mut self,
|
||||
register_index: usize,
|
||||
) -> &mut RuntimeValue<i64> {
|
||||
let register = self.registers.integers.get_mut(register_index);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => value,
|
||||
Register::Pointer { .. } => {
|
||||
panic!("Attempted to get mutable integer from pointer")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_integer_from_pointer(&self, pointer: &Pointer) -> &RuntimeValue<i64> {
|
||||
pub fn get_integer_from_pointer(&self, pointer: &Pointer) -> i64 {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_integer_from_register(*register_index),
|
||||
Pointer::Constant(constant_index) => self.get_integer_constant(*constant_index),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_integer_from_pointer_mut(&mut self, pointer: &Pointer) -> &mut RuntimeValue<i64> {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => {
|
||||
self.get_integer_from_register_mut(*register_index)
|
||||
}
|
||||
Pointer::Constant(constant_index) => self.get_integer_constant_mut(*constant_index),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_integer_constant(&self, constant_index: usize) -> &RuntimeValue<i64> {
|
||||
if cfg!(debug_assertions) {
|
||||
self.constants.integers.get(constant_index).unwrap()
|
||||
pub fn get_integer_constant(&self, constant_index: usize) -> i64 {
|
||||
let constant = if cfg!(debug_assertions) {
|
||||
self.chunk.integer_constants.get(constant_index).unwrap()
|
||||
} else {
|
||||
unsafe { self.constants.integers.get_unchecked(constant_index) }
|
||||
}
|
||||
unsafe { self.chunk.integer_constants.get_unchecked(constant_index) }
|
||||
};
|
||||
|
||||
*constant
|
||||
}
|
||||
|
||||
pub fn get_integer_constant_mut(&mut self, constant_index: usize) -> &mut RuntimeValue<i64> {
|
||||
if cfg!(debug_assertions) {
|
||||
self.constants.integers.get_mut(constant_index).unwrap()
|
||||
} else {
|
||||
unsafe { self.constants.integers.get_unchecked_mut(constant_index) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_string_from_register(&self, register_index: usize) -> &RuntimeValue<DustString> {
|
||||
pub fn get_string_from_register(&self, register_index: usize) -> &DustString {
|
||||
let register = self.registers.strings.get(register_index);
|
||||
|
||||
match register {
|
||||
@ -206,33 +157,22 @@ impl CallFrame {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_string_from_pointer(&self, pointer: &Pointer) -> &RuntimeValue<DustString> {
|
||||
pub fn get_string_from_pointer(&self, pointer: &Pointer) -> &DustString {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_string_from_register(*register_index),
|
||||
Pointer::Constant(constant_index) => self.get_string_constant(*constant_index),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_string_constant(&self, constant_index: usize) -> &RuntimeValue<DustString> {
|
||||
pub fn get_string_constant(&self, constant_index: usize) -> &DustString {
|
||||
if cfg!(debug_assertions) {
|
||||
self.constants.strings.get(constant_index).unwrap()
|
||||
self.chunk.string_constants.get(constant_index).unwrap()
|
||||
} else {
|
||||
unsafe { self.constants.strings.get_unchecked(constant_index) }
|
||||
unsafe { self.chunk.string_constants.get_unchecked(constant_index) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_string_constant_mut(
|
||||
&mut self,
|
||||
constant_index: usize,
|
||||
) -> &mut RuntimeValue<DustString> {
|
||||
if cfg!(debug_assertions) {
|
||||
self.constants.strings.get_mut(constant_index).unwrap()
|
||||
} else {
|
||||
unsafe { self.constants.strings.get_unchecked_mut(constant_index) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_list_from_register(&self, register_index: usize) -> &RuntimeValue<AbstractList> {
|
||||
pub fn get_list_from_register(&self, register_index: usize) -> &AbstractList {
|
||||
let register = self.registers.lists.get(register_index);
|
||||
|
||||
match register {
|
||||
@ -241,10 +181,7 @@ impl CallFrame {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_list_from_register_mut(
|
||||
&mut self,
|
||||
register_index: usize,
|
||||
) -> &mut RuntimeValue<AbstractList> {
|
||||
pub fn get_list_from_register_mut(&mut self, register_index: usize) -> &mut AbstractList {
|
||||
let register = self.registers.lists.get_mut(register_index);
|
||||
|
||||
match register {
|
||||
@ -253,14 +190,14 @@ impl CallFrame {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_list_from_pointer(&self, pointer: &Pointer) -> &RuntimeValue<AbstractList> {
|
||||
pub fn get_list_from_pointer(&self, pointer: &Pointer) -> &AbstractList {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_list_from_register(*register_index),
|
||||
Pointer::Constant(_) => panic!("Attempted to get list from constant pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_function_from_register(&self, register_index: usize) -> &RuntimeValue<Function> {
|
||||
pub fn get_function_from_register(&self, register_index: usize) -> &Function {
|
||||
let register = self.registers.functions.get(register_index);
|
||||
|
||||
match register {
|
||||
@ -269,10 +206,7 @@ impl CallFrame {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_function_from_register_mut(
|
||||
&mut self,
|
||||
register_index: usize,
|
||||
) -> &mut RuntimeValue<Function> {
|
||||
pub fn get_function_from_register_mut(&mut self, register_index: usize) -> &mut Function {
|
||||
let register = self.registers.functions.get_mut(register_index);
|
||||
|
||||
match register {
|
||||
@ -281,7 +215,7 @@ impl CallFrame {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_function_from_pointer(&self, pointer: &Pointer) -> &RuntimeValue<Function> {
|
||||
pub fn get_function_from_pointer(&self, pointer: &Pointer) -> &Function {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_function_from_register(*register_index),
|
||||
Pointer::Constant(_) => panic!("Attempted to get function from constant pointer"),
|
||||
@ -303,14 +237,6 @@ impl Display for CallFrame {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ConstantTable {
|
||||
pub characters: Vec<RuntimeValue<char>>,
|
||||
pub floats: Vec<RuntimeValue<f64>>,
|
||||
pub integers: Vec<RuntimeValue<i64>>,
|
||||
pub strings: Vec<RuntimeValue<DustString>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RegisterTable {
|
||||
pub booleans: RegisterList<bool>,
|
||||
@ -362,6 +288,12 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_to_new_register(&mut self, index: usize, new_value: T) {
|
||||
assert!(index < self.registers.len(), "Register index out of bounds");
|
||||
|
||||
self.registers[index] = Register::value(new_value)
|
||||
}
|
||||
|
||||
pub fn close(&mut self, index: usize) {
|
||||
if cfg!(debug_assertions) {
|
||||
self.registers.get_mut(index).unwrap().close()
|
||||
@ -395,17 +327,18 @@ impl<T> IndexMut<usize> for RegisterList<T> {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Register<T> {
|
||||
Value {
|
||||
value: RuntimeValue<T>,
|
||||
is_closed: bool,
|
||||
},
|
||||
Pointer {
|
||||
pointer: Pointer,
|
||||
is_closed: bool,
|
||||
},
|
||||
Value { value: T, is_closed: bool },
|
||||
Pointer { pointer: Pointer, is_closed: bool },
|
||||
}
|
||||
|
||||
impl<T> Register<T> {
|
||||
pub fn value(value: T) -> Self {
|
||||
Self::Value {
|
||||
value,
|
||||
is_closed: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_closed(&self) -> bool {
|
||||
match self {
|
||||
Self::Value { is_closed, .. } => *is_closed,
|
||||
@ -420,7 +353,7 @@ impl<T> Register<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set(&mut self, new_value: RuntimeValue<T>) {
|
||||
pub fn set(&mut self, new_value: T) {
|
||||
match self {
|
||||
Self::Value {
|
||||
value: old_value, ..
|
||||
@ -434,14 +367,14 @@ impl<T> Register<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_value(&self) -> &RuntimeValue<T> {
|
||||
pub fn as_value(&self) -> &T {
|
||||
match self {
|
||||
Self::Value { value, .. } => value,
|
||||
Self::Pointer { .. } => panic!("Attempted to use pointer as value"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_value_mut(&mut self) -> &mut RuntimeValue<T> {
|
||||
pub fn as_value_mut(&mut self) -> &mut T {
|
||||
match self {
|
||||
Self::Value { value, .. } => value,
|
||||
Self::Pointer { .. } => panic!("Attempted to use pointer as value"),
|
||||
@ -452,217 +385,12 @@ impl<T> Register<T> {
|
||||
impl<T: Default> Default for Register<T> {
|
||||
fn default() -> Self {
|
||||
Self::Value {
|
||||
value: RuntimeValue::Raw(Default::default()),
|
||||
value: Default::default(),
|
||||
is_closed: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum RuntimeValue<T> {
|
||||
Raw(T),
|
||||
Rc(Rc<T>),
|
||||
RefCell(Rc<RefCell<T>>),
|
||||
}
|
||||
|
||||
impl<T: Clone> RuntimeValue<T> {
|
||||
pub fn ref_cell(value: T) -> Self {
|
||||
Self::RefCell(Rc::new(RefCell::new(value)))
|
||||
}
|
||||
|
||||
pub fn rc(value: T) -> Self {
|
||||
Self::Rc(Rc::new(value))
|
||||
}
|
||||
|
||||
pub fn to_ref_cell(&mut self) -> Self {
|
||||
match self {
|
||||
Self::Raw(value) => RuntimeValue::ref_cell(value.clone()),
|
||||
Self::Rc(value) => RuntimeValue::ref_cell(value.as_ref().clone()),
|
||||
Self::RefCell(_) => self.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_rc(&mut self) -> Self {
|
||||
match self {
|
||||
Self::Raw(value) => RuntimeValue::rc(value.clone()),
|
||||
Self::Rc(_) => self.clone(),
|
||||
Self::RefCell(value) => RuntimeValue::rc(value.borrow().clone()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_inner(&mut self, new_value: T) {
|
||||
match self {
|
||||
Self::Raw(value) => *value = new_value,
|
||||
Self::RefCell(value) => {
|
||||
let _ = value.replace(new_value);
|
||||
}
|
||||
Self::Rc(_) => panic!("Attempted to modify immutable runtime value"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clone_inner(&self) -> T {
|
||||
match self {
|
||||
Self::Raw(value) => value.clone(),
|
||||
Self::Rc(value) => value.as_ref().clone(),
|
||||
Self::RefCell(value) => value.borrow().clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn borrow_mut(&self) -> RefMut<T> {
|
||||
match self {
|
||||
Self::RefCell(value) => value.borrow_mut(),
|
||||
_ => panic!("Attempted to borrow mutable reference from immutable runtime value"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const BYTE_ADD: fn(u8, u8) -> u8 = u8::saturating_add;
|
||||
|
||||
impl Add for &RuntimeValue<u8> {
|
||||
type Output = u8;
|
||||
|
||||
fn add(self, other: Self) -> Self::Output {
|
||||
let left = match self {
|
||||
RuntimeValue::Raw(value) => *value,
|
||||
RuntimeValue::Rc(value) => **value,
|
||||
RuntimeValue::RefCell(value) => *value.borrow(),
|
||||
};
|
||||
let right = match other {
|
||||
RuntimeValue::Raw(value) => *value,
|
||||
RuntimeValue::Rc(value) => **value,
|
||||
RuntimeValue::RefCell(value) => *value.borrow(),
|
||||
};
|
||||
|
||||
BYTE_ADD(left, right)
|
||||
}
|
||||
}
|
||||
|
||||
const FLOAT_ADD: fn(f64, f64) -> f64 = f64::add;
|
||||
|
||||
impl Add for &RuntimeValue<f64> {
|
||||
type Output = f64;
|
||||
|
||||
fn add(self, other: Self) -> Self::Output {
|
||||
let left = match self {
|
||||
RuntimeValue::Raw(value) => *value,
|
||||
RuntimeValue::Rc(value) => **value,
|
||||
RuntimeValue::RefCell(value) => *value.borrow(),
|
||||
};
|
||||
let right = match other {
|
||||
RuntimeValue::Raw(value) => *value,
|
||||
RuntimeValue::Rc(value) => **value,
|
||||
RuntimeValue::RefCell(value) => *value.borrow(),
|
||||
};
|
||||
|
||||
FLOAT_ADD(left, right)
|
||||
}
|
||||
}
|
||||
|
||||
const INTEGER_ADD: fn(i64, i64) -> i64 = i64::saturating_add;
|
||||
|
||||
impl Add for &RuntimeValue<i64> {
|
||||
type Output = i64;
|
||||
|
||||
fn add(self, other: Self) -> Self::Output {
|
||||
let left = match self {
|
||||
RuntimeValue::Raw(value) => *value,
|
||||
RuntimeValue::Rc(value) => **value,
|
||||
RuntimeValue::RefCell(value) => *value.borrow(),
|
||||
};
|
||||
let right = match other {
|
||||
RuntimeValue::Raw(value) => *value,
|
||||
RuntimeValue::Rc(value) => **value,
|
||||
RuntimeValue::RefCell(value) => *value.borrow(),
|
||||
};
|
||||
|
||||
INTEGER_ADD(left, right)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq> PartialEq for RuntimeValue<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(RuntimeValue::Raw(left), RuntimeValue::Raw(right)) => left == right,
|
||||
(RuntimeValue::Raw(left), RuntimeValue::Rc(right)) => left == &**right,
|
||||
(RuntimeValue::Raw(left), RuntimeValue::RefCell(right)) => {
|
||||
let right = right.borrow();
|
||||
|
||||
left == &*right
|
||||
}
|
||||
(RuntimeValue::Rc(left), RuntimeValue::Raw(right)) => **left == *right,
|
||||
(RuntimeValue::Rc(left), RuntimeValue::Rc(right)) => **left == **right,
|
||||
(RuntimeValue::Rc(left), RuntimeValue::RefCell(right)) => {
|
||||
let right = right.borrow();
|
||||
|
||||
**left == *right
|
||||
}
|
||||
(RuntimeValue::RefCell(left), RuntimeValue::RefCell(right)) => {
|
||||
let left = left.borrow();
|
||||
let right = right.borrow();
|
||||
|
||||
*left == *right
|
||||
}
|
||||
(RuntimeValue::RefCell(left), RuntimeValue::Raw(right)) => {
|
||||
let left = left.borrow();
|
||||
|
||||
*left == *right
|
||||
}
|
||||
(RuntimeValue::RefCell(left), RuntimeValue::Rc(right)) => {
|
||||
let left = left.borrow();
|
||||
|
||||
*left == **right
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialOrd> PartialOrd for RuntimeValue<T> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
match (self, other) {
|
||||
(RuntimeValue::Raw(left), RuntimeValue::Raw(right)) => left.partial_cmp(right),
|
||||
(RuntimeValue::Raw(left), RuntimeValue::Rc(right)) => left.partial_cmp(&**right),
|
||||
(RuntimeValue::Raw(left), RuntimeValue::RefCell(right)) => {
|
||||
let right = right.borrow();
|
||||
|
||||
left.partial_cmp(&*right)
|
||||
}
|
||||
(RuntimeValue::Rc(left), RuntimeValue::Raw(right)) => (**left).partial_cmp(right),
|
||||
(RuntimeValue::Rc(left), RuntimeValue::Rc(right)) => left.partial_cmp(right),
|
||||
(RuntimeValue::Rc(left), RuntimeValue::RefCell(right)) => {
|
||||
let right = right.borrow();
|
||||
|
||||
(**left).partial_cmp(&right)
|
||||
}
|
||||
(RuntimeValue::RefCell(left), RuntimeValue::RefCell(right)) => {
|
||||
let left = left.borrow();
|
||||
let right = right.borrow();
|
||||
|
||||
left.partial_cmp(&*right)
|
||||
}
|
||||
(RuntimeValue::RefCell(left), RuntimeValue::Raw(right)) => {
|
||||
let left = left.borrow();
|
||||
|
||||
left.partial_cmp(right)
|
||||
}
|
||||
(RuntimeValue::RefCell(left), RuntimeValue::Rc(right)) => {
|
||||
let left = left.borrow();
|
||||
|
||||
left.partial_cmp(&**right)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Display> Display for RuntimeValue<T> {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Raw(value) => write!(f, "{}", value),
|
||||
Self::Rc(value) => write!(f, "{}", value),
|
||||
Self::RefCell(value) => write!(f, "{}", value.borrow()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum Pointer {
|
||||
Register(usize),
|
||||
|
@ -1,11 +1,11 @@
|
||||
//! Virtual machine and errors
|
||||
mod action;
|
||||
// mod action;
|
||||
mod call_frame;
|
||||
mod thread;
|
||||
|
||||
use std::{rc::Rc, thread::Builder};
|
||||
|
||||
pub use call_frame::{CallFrame, Pointer, Register, RegisterTable, RuntimeValue};
|
||||
pub use call_frame::{CallFrame, Pointer, Register, RegisterTable};
|
||||
pub use thread::Thread;
|
||||
|
||||
use crossbeam_channel::bounded;
|
||||
|
@ -1,16 +1,14 @@
|
||||
use std::{rc::Rc, thread::JoinHandle};
|
||||
|
||||
use tracing::{info, trace};
|
||||
use tracing::info;
|
||||
|
||||
use crate::{
|
||||
vm::{action::ActionSequence, CallFrame},
|
||||
Chunk, DustString, Span, Value,
|
||||
instruction::TypeCode, vm::CallFrame, Chunk, ConcreteValue, DustString, Operation, Span, Value,
|
||||
};
|
||||
|
||||
pub struct Thread {
|
||||
chunk: Rc<Chunk>,
|
||||
call_stack: Vec<CallFrame>,
|
||||
pub return_value: Option<Value>,
|
||||
_spawned_threads: Vec<JoinHandle<()>>,
|
||||
}
|
||||
|
||||
@ -24,7 +22,6 @@ impl Thread {
|
||||
Thread {
|
||||
chunk,
|
||||
call_stack,
|
||||
return_value: None,
|
||||
_spawned_threads: Vec::new(),
|
||||
}
|
||||
}
|
||||
@ -38,13 +35,371 @@ impl Thread {
|
||||
.unwrap_or_else(|| DustString::from("anonymous"))
|
||||
);
|
||||
|
||||
let mut actions = ActionSequence::new(self.chunk.instructions.iter().copied());
|
||||
while !self.call_stack.is_empty() {
|
||||
let current_frame = self.current_frame_mut();
|
||||
let instructions = ¤t_frame.chunk.instructions;
|
||||
let ip = {
|
||||
let current = current_frame.ip;
|
||||
current_frame.ip += 1;
|
||||
|
||||
trace!("Thread actions: {}", actions);
|
||||
current
|
||||
};
|
||||
|
||||
actions.run(&mut self);
|
||||
assert!(ip < instructions.len(), "IP out of bounds");
|
||||
|
||||
self.return_value
|
||||
let instruction = &instructions[ip];
|
||||
|
||||
info!("Run instruction {}", instruction.operation());
|
||||
|
||||
match instruction.operation() {
|
||||
Operation::LOAD_CONSTANT => {
|
||||
let destination = instruction.a_field() as usize;
|
||||
let constant_index = instruction.b_field() as usize;
|
||||
let constant_type = instruction.b_type();
|
||||
let jump_next = instruction.c_field() != 0;
|
||||
|
||||
match constant_type {
|
||||
TypeCode::CHARACTER => {
|
||||
let character = current_frame.get_character_constant(constant_index);
|
||||
|
||||
current_frame
|
||||
.registers
|
||||
.characters
|
||||
.get_mut(destination)
|
||||
.set(character);
|
||||
}
|
||||
TypeCode::FLOAT => {
|
||||
let float = current_frame.get_float_constant(constant_index);
|
||||
|
||||
current_frame
|
||||
.registers
|
||||
.floats
|
||||
.get_mut(destination)
|
||||
.set(float);
|
||||
}
|
||||
TypeCode::INTEGER => {
|
||||
let integer = current_frame.get_integer_constant(constant_index);
|
||||
|
||||
current_frame
|
||||
.registers
|
||||
.integers
|
||||
.get_mut(destination)
|
||||
.set(integer);
|
||||
}
|
||||
TypeCode::STRING => {
|
||||
let string = current_frame.get_string_constant(constant_index).clone();
|
||||
|
||||
current_frame
|
||||
.registers
|
||||
.strings
|
||||
.get_mut(destination)
|
||||
.set(string);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
if jump_next {
|
||||
current_frame.ip += 1;
|
||||
}
|
||||
}
|
||||
Operation::LESS => match (instruction.b_type(), instruction.c_type()) {
|
||||
(TypeCode::INTEGER, TypeCode::INTEGER) => {
|
||||
let left = instruction.b_field() as usize;
|
||||
let left_is_constant = instruction.b_is_constant();
|
||||
let right = instruction.c_field() as usize;
|
||||
let right_is_constant = instruction.c_is_constant();
|
||||
let comparator = instruction.d_field();
|
||||
|
||||
let left_value = if left_is_constant {
|
||||
current_frame.get_integer_constant(left)
|
||||
} else {
|
||||
current_frame.get_integer_from_register(left)
|
||||
};
|
||||
let right_value = if right_is_constant {
|
||||
current_frame.get_integer_constant(right)
|
||||
} else {
|
||||
current_frame.get_integer_from_register(right)
|
||||
};
|
||||
let is_less_than = left_value < right_value;
|
||||
|
||||
if is_less_than == comparator {
|
||||
current_frame.ip += 1;
|
||||
}
|
||||
}
|
||||
_ => todo!(),
|
||||
},
|
||||
Operation::ADD => match (instruction.b_type(), instruction.c_type()) {
|
||||
(TypeCode::BYTE, TypeCode::BYTE) => {
|
||||
let left_index = instruction.b_field() as usize;
|
||||
let right_index = instruction.c_field() as usize;
|
||||
let destination_index = instruction.a_field() as usize;
|
||||
|
||||
let left_value = current_frame.get_byte_from_register(left_index);
|
||||
let right_value = current_frame.get_byte_from_register(right_index);
|
||||
let sum = left_value + right_value;
|
||||
|
||||
current_frame
|
||||
.registers
|
||||
.bytes
|
||||
.set_to_new_register(destination_index, sum);
|
||||
}
|
||||
(TypeCode::CHARACTER, TypeCode::CHARACTER) => {
|
||||
let left_index = instruction.b_field() as usize;
|
||||
let left_is_constant = instruction.b_is_constant();
|
||||
let right_index = instruction.c_field() as usize;
|
||||
let right_is_constant = instruction.c_is_constant();
|
||||
let destination_index = instruction.a_field() as usize;
|
||||
|
||||
let left_value = if left_is_constant {
|
||||
current_frame.get_character_constant(left_index)
|
||||
} else {
|
||||
current_frame.get_character_from_register(left_index)
|
||||
};
|
||||
let right_value = if right_is_constant {
|
||||
current_frame.get_character_constant(right_index)
|
||||
} else {
|
||||
current_frame.get_character_from_register(right_index)
|
||||
};
|
||||
let concatenated = {
|
||||
let mut concatenated = DustString::from(String::with_capacity(2));
|
||||
|
||||
concatenated.push(left_value);
|
||||
concatenated.push(right_value);
|
||||
|
||||
concatenated
|
||||
};
|
||||
|
||||
current_frame
|
||||
.registers
|
||||
.strings
|
||||
.set_to_new_register(destination_index, concatenated);
|
||||
}
|
||||
(TypeCode::CHARACTER, TypeCode::STRING) => {
|
||||
let left_index = instruction.b_field() as usize;
|
||||
let left_is_constant = instruction.b_is_constant();
|
||||
let right_index = instruction.c_field() as usize;
|
||||
let right_is_constant = instruction.c_is_constant();
|
||||
let destination_index = instruction.a_field() as usize;
|
||||
|
||||
let left_value = if left_is_constant {
|
||||
current_frame.get_character_constant(left_index)
|
||||
} else {
|
||||
current_frame.get_character_from_register(left_index)
|
||||
};
|
||||
let right_value = if right_is_constant {
|
||||
current_frame.get_string_constant(right_index)
|
||||
} else {
|
||||
current_frame.get_string_from_register(right_index)
|
||||
};
|
||||
let concatenated = DustString::from(format!("{left_value}{right_value}"));
|
||||
|
||||
current_frame
|
||||
.registers
|
||||
.strings
|
||||
.set_to_new_register(destination_index, concatenated);
|
||||
}
|
||||
(TypeCode::FLOAT, TypeCode::FLOAT) => {
|
||||
let left_index = instruction.b_field() as usize;
|
||||
let right_index = instruction.c_field() as usize;
|
||||
let destination_index = instruction.a_field() as usize;
|
||||
|
||||
let left_value = current_frame.get_float_from_register(left_index);
|
||||
let right_value = current_frame.get_float_from_register(right_index);
|
||||
let sum = left_value + right_value;
|
||||
|
||||
current_frame
|
||||
.registers
|
||||
.floats
|
||||
.set_to_new_register(destination_index, sum);
|
||||
}
|
||||
(TypeCode::INTEGER, TypeCode::INTEGER) => {
|
||||
let left = instruction.b_field() as usize;
|
||||
let left_is_constant = instruction.b_is_constant();
|
||||
let right = instruction.c_field() as usize;
|
||||
let right_is_constant = instruction.c_is_constant();
|
||||
let destination_index = instruction.a_field() as usize;
|
||||
|
||||
let left_value = if left_is_constant {
|
||||
current_frame.get_integer_constant(left)
|
||||
} else {
|
||||
current_frame.get_integer_from_register(left)
|
||||
};
|
||||
let right_value = if right_is_constant {
|
||||
current_frame.get_integer_constant(right)
|
||||
} else {
|
||||
current_frame.get_integer_from_register(right)
|
||||
};
|
||||
let sum = left_value + right_value;
|
||||
|
||||
current_frame
|
||||
.registers
|
||||
.integers
|
||||
.set_to_new_register(destination_index, sum);
|
||||
}
|
||||
(TypeCode::STRING, TypeCode::STRING) => {
|
||||
let left = instruction.b_field() as usize;
|
||||
let left_is_constant = instruction.b_is_constant();
|
||||
let right = instruction.c_field() as usize;
|
||||
let right_is_constant = instruction.c_is_constant();
|
||||
let destination_index = instruction.a_field() as usize;
|
||||
|
||||
let left_value = if left_is_constant {
|
||||
current_frame.get_string_constant(left)
|
||||
} else {
|
||||
current_frame.get_string_from_register(left)
|
||||
};
|
||||
let right_value = if right_is_constant {
|
||||
current_frame.get_string_constant(right)
|
||||
} else {
|
||||
current_frame.get_string_from_register(right)
|
||||
};
|
||||
let concatenated = DustString::from(format!("{left_value}{right_value}"));
|
||||
|
||||
current_frame
|
||||
.registers
|
||||
.strings
|
||||
.set_to_new_register(destination_index, concatenated);
|
||||
}
|
||||
_ => todo!(),
|
||||
},
|
||||
Operation::JUMP => {
|
||||
let offset = instruction.b_field() as usize;
|
||||
let is_positive = instruction.c_field() != 0;
|
||||
|
||||
if is_positive {
|
||||
current_frame.ip += offset;
|
||||
} else {
|
||||
current_frame.ip -= offset + 1;
|
||||
}
|
||||
}
|
||||
Operation::RETURN => {
|
||||
let should_return_value = instruction.b_field() != 0;
|
||||
let return_register = instruction.c_field() as usize;
|
||||
let return_type = instruction.b_type();
|
||||
|
||||
if should_return_value {
|
||||
match return_type {
|
||||
TypeCode::BOOLEAN => {
|
||||
let return_value =
|
||||
current_frame.get_boolean_from_register(return_register);
|
||||
|
||||
return Some(Value::boolean(return_value));
|
||||
}
|
||||
TypeCode::BYTE => {
|
||||
let return_value =
|
||||
current_frame.get_byte_from_register(return_register);
|
||||
|
||||
return Some(Value::byte(return_value));
|
||||
}
|
||||
TypeCode::CHARACTER => {
|
||||
let return_value =
|
||||
current_frame.get_character_from_register(return_register);
|
||||
|
||||
return Some(Value::character(return_value));
|
||||
}
|
||||
TypeCode::FLOAT => {
|
||||
let return_value =
|
||||
current_frame.get_float_from_register(return_register);
|
||||
|
||||
return Some(Value::float(return_value));
|
||||
}
|
||||
TypeCode::INTEGER => {
|
||||
let return_value =
|
||||
current_frame.get_integer_from_register(return_register);
|
||||
|
||||
return Some(Value::integer(return_value));
|
||||
}
|
||||
TypeCode::STRING => {
|
||||
let return_value = current_frame
|
||||
.get_string_from_register(return_register)
|
||||
.clone();
|
||||
|
||||
return Some(Value::string(return_value));
|
||||
}
|
||||
TypeCode::LIST => {
|
||||
let abstract_list =
|
||||
current_frame.get_list_from_register(return_register);
|
||||
|
||||
let mut concrete_list =
|
||||
Vec::with_capacity(abstract_list.item_pointers.len());
|
||||
|
||||
match abstract_list.item_type {
|
||||
TypeCode::BOOLEAN => {
|
||||
for pointer in &abstract_list.item_pointers {
|
||||
let boolean =
|
||||
current_frame.get_boolean_from_pointer(&pointer);
|
||||
let value = ConcreteValue::Boolean(boolean);
|
||||
|
||||
concrete_list.push(value);
|
||||
}
|
||||
}
|
||||
TypeCode::BYTE => {
|
||||
for pointer in &abstract_list.item_pointers {
|
||||
let byte =
|
||||
current_frame.get_byte_from_pointer(&pointer);
|
||||
let value = ConcreteValue::Byte(byte);
|
||||
|
||||
concrete_list.push(value);
|
||||
}
|
||||
}
|
||||
TypeCode::CHARACTER => {
|
||||
for pointer in &abstract_list.item_pointers {
|
||||
let character =
|
||||
current_frame.get_character_from_pointer(&pointer);
|
||||
let value = ConcreteValue::Character(character);
|
||||
|
||||
concrete_list.push(value);
|
||||
}
|
||||
}
|
||||
TypeCode::FLOAT => {
|
||||
for pointer in &abstract_list.item_pointers {
|
||||
let float =
|
||||
current_frame.get_float_from_pointer(&pointer);
|
||||
let value = ConcreteValue::Float(float);
|
||||
|
||||
concrete_list.push(value);
|
||||
}
|
||||
}
|
||||
TypeCode::INTEGER => {
|
||||
for pointer in &abstract_list.item_pointers {
|
||||
let integer =
|
||||
current_frame.get_integer_from_pointer(&pointer);
|
||||
let value = ConcreteValue::Integer(integer);
|
||||
|
||||
concrete_list.push(value);
|
||||
}
|
||||
}
|
||||
TypeCode::STRING => {
|
||||
for pointer in &abstract_list.item_pointers {
|
||||
let string = current_frame
|
||||
.get_string_from_pointer(pointer)
|
||||
.clone();
|
||||
let value = ConcreteValue::String(string);
|
||||
|
||||
concrete_list.push(value);
|
||||
}
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
|
||||
return Some(Value::Concrete(ConcreteValue::list(
|
||||
concrete_list,
|
||||
abstract_list.item_type,
|
||||
)));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
unimplemented => {
|
||||
todo!("{unimplemented} has not been implemented in the VM");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn current_position(&self) -> Span {
|
||||
|
Loading…
x
Reference in New Issue
Block a user