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 std::{ops::Range, panic};
|
||||||
|
|
||||||
use crate::vm::{RuntimeValue, Thread};
|
use crate::vm::Thread;
|
||||||
|
|
||||||
pub fn panic(data: &mut Thread, _: usize, argument_range: Range<usize>) {
|
pub fn panic(data: &mut Thread, _: usize, argument_range: Range<usize>) {
|
||||||
let current_frame = data.current_frame();
|
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}!");
|
let mut message = format!("Dust panic at {position}!");
|
||||||
|
|
||||||
for register_index in argument_range {
|
for register_index in argument_range {
|
||||||
let string_value = current_frame.get_string_from_register(register_index);
|
let string = 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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
message.push_str(string);
|
||||||
message.push('\n');
|
message.push('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::io::{stdin, stdout, Write};
|
use std::io::{stdin, stdout, Write};
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use crate::vm::{RuntimeValue, Thread};
|
use crate::vm::Thread;
|
||||||
use crate::DustString;
|
use crate::DustString;
|
||||||
|
|
||||||
pub fn read_line(data: &mut Thread, destination: usize, _argument_range: Range<usize>) {
|
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));
|
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>) {
|
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();
|
let mut stdout = stdout();
|
||||||
|
|
||||||
for register_index in argument_range {
|
for register_index in argument_range {
|
||||||
let value = current_frame.get_string_from_register(register_index);
|
let string = current_frame.get_string_from_register(register_index);
|
||||||
|
let _ = stdout.write(string.as_bytes());
|
||||||
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 _ = stdout.flush();
|
let _ = stdout.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_line(data: &mut Thread, _: usize, argument_range: Range<usize>) {
|
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();
|
let mut stdout = stdout().lock();
|
||||||
|
|
||||||
for register_index in argument_range {
|
for register_index in argument_range {
|
||||||
let value = current_frame.get_string_from_register(register_index);
|
let string = current_frame.get_string_from_register(register_index);
|
||||||
|
let _ = stdout.write(string.as_bytes());
|
||||||
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 _ = stdout.write(b"\n");
|
let _ = stdout.write(b"\n");
|
||||||
|
@ -2,7 +2,7 @@ use std::ops::Range;
|
|||||||
|
|
||||||
use rand::Rng;
|
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>) {
|
pub fn random_int(data: &mut Thread, destination: usize, argument_range: Range<usize>) {
|
||||||
let current_frame = data.current_frame_mut();
|
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
|
let register_index = argument_range_iter
|
||||||
.next()
|
.next()
|
||||||
.unwrap_or_else(|| panic!("No argument was passed to \"random_int\""));
|
.unwrap_or_else(|| panic!("No argument was passed to \"random_int\""));
|
||||||
let integer = current_frame
|
let integer = current_frame.get_integer_from_register(register_index);
|
||||||
.get_integer_from_register(register_index)
|
|
||||||
.clone_inner();
|
|
||||||
|
|
||||||
if min.is_none() {
|
if min.is_none() {
|
||||||
min = Some(integer);
|
min = Some(integer);
|
||||||
@ -31,6 +29,5 @@ pub fn random_int(data: &mut Thread, destination: usize, argument_range: Range<u
|
|||||||
current_frame
|
current_frame
|
||||||
.registers
|
.registers
|
||||||
.integers
|
.integers
|
||||||
.get_mut(destination)
|
.set_to_new_register(destination, random_integer);
|
||||||
.set(RuntimeValue::Raw(random_integer));
|
|
||||||
}
|
}
|
||||||
|
@ -507,117 +507,117 @@ fn r#return(_: &mut usize, instruction: &Instruction, thread: &mut Thread, _: &m
|
|||||||
let return_type = instruction.b_type();
|
let return_type = instruction.b_type();
|
||||||
let current_frame = thread.current_frame();
|
let current_frame = thread.current_frame();
|
||||||
|
|
||||||
if should_return_value {
|
// if should_return_value {
|
||||||
match return_type {
|
// match return_type {
|
||||||
TypeCode::BOOLEAN => {
|
// TypeCode::BOOLEAN => {
|
||||||
let return_value = current_frame
|
// let return_value = current_frame
|
||||||
.get_boolean_from_register(return_register)
|
// .get_boolean_from_register(return_register)
|
||||||
.clone_inner();
|
// .clone_inner();
|
||||||
thread.return_value = Some(Value::boolean(return_value));
|
// thread.return_value = Some(Value::boolean(return_value));
|
||||||
}
|
// }
|
||||||
TypeCode::BYTE => {
|
// TypeCode::BYTE => {
|
||||||
let return_value = current_frame
|
// let return_value = current_frame
|
||||||
.get_byte_from_register(return_register)
|
// .get_byte_from_register(return_register)
|
||||||
.clone_inner();
|
// .clone_inner();
|
||||||
thread.return_value = Some(Value::byte(return_value));
|
// thread.return_value = Some(Value::byte(return_value));
|
||||||
}
|
// }
|
||||||
TypeCode::CHARACTER => {
|
// TypeCode::CHARACTER => {
|
||||||
let return_value = current_frame
|
// let return_value = current_frame
|
||||||
.get_character_from_register(return_register)
|
// .get_character_from_register(return_register)
|
||||||
.clone_inner();
|
// .clone_inner();
|
||||||
thread.return_value = Some(Value::character(return_value));
|
// thread.return_value = Some(Value::character(return_value));
|
||||||
}
|
// }
|
||||||
TypeCode::FLOAT => {
|
// TypeCode::FLOAT => {
|
||||||
let return_value = current_frame
|
// let return_value = current_frame
|
||||||
.get_float_from_register(return_register)
|
// .get_float_from_register(return_register)
|
||||||
.clone_inner();
|
// .clone_inner();
|
||||||
thread.return_value = Some(Value::float(return_value));
|
// thread.return_value = Some(Value::float(return_value));
|
||||||
}
|
// }
|
||||||
TypeCode::INTEGER => {
|
// TypeCode::INTEGER => {
|
||||||
let return_value = current_frame
|
// let return_value = current_frame
|
||||||
.get_integer_from_register(return_register)
|
// .get_integer_from_register(return_register)
|
||||||
.clone_inner();
|
// .clone_inner();
|
||||||
thread.return_value = Some(Value::integer(return_value));
|
// thread.return_value = Some(Value::integer(return_value));
|
||||||
}
|
// }
|
||||||
TypeCode::STRING => {
|
// TypeCode::STRING => {
|
||||||
let return_value = current_frame
|
// let return_value = current_frame
|
||||||
.get_string_from_register(return_register)
|
// .get_string_from_register(return_register)
|
||||||
.clone_inner();
|
// .clone_inner();
|
||||||
thread.return_value = Some(Value::string(return_value));
|
// thread.return_value = Some(Value::string(return_value));
|
||||||
}
|
// }
|
||||||
TypeCode::LIST => {
|
// TypeCode::LIST => {
|
||||||
let abstract_list = current_frame
|
// let abstract_list = current_frame
|
||||||
.get_list_from_register(return_register)
|
// .get_list_from_register(return_register)
|
||||||
.clone_inner();
|
// .clone_inner();
|
||||||
let mut concrete_list = Vec::with_capacity(abstract_list.item_pointers.len());
|
// let mut concrete_list = Vec::with_capacity(abstract_list.item_pointers.len());
|
||||||
|
|
||||||
match abstract_list.item_type {
|
// match abstract_list.item_type {
|
||||||
TypeCode::BOOLEAN => {
|
// TypeCode::BOOLEAN => {
|
||||||
for pointer in abstract_list.item_pointers {
|
// for pointer in abstract_list.item_pointers {
|
||||||
let boolean = current_frame
|
// let boolean = current_frame
|
||||||
.get_boolean_from_pointer(&pointer)
|
// .get_boolean_from_pointer(&pointer)
|
||||||
.clone_inner();
|
// .clone_inner();
|
||||||
let value = ConcreteValue::Boolean(boolean);
|
// let value = ConcreteValue::Boolean(boolean);
|
||||||
|
|
||||||
concrete_list.push(value);
|
// concrete_list.push(value);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
TypeCode::BYTE => {
|
// TypeCode::BYTE => {
|
||||||
for pointer in abstract_list.item_pointers {
|
// for pointer in abstract_list.item_pointers {
|
||||||
let byte = current_frame.get_byte_from_pointer(&pointer).clone_inner();
|
// let byte = current_frame.get_byte_from_pointer(&pointer).clone_inner();
|
||||||
let value = ConcreteValue::Byte(byte);
|
// let value = ConcreteValue::Byte(byte);
|
||||||
|
|
||||||
concrete_list.push(value);
|
// concrete_list.push(value);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
TypeCode::CHARACTER => {
|
// TypeCode::CHARACTER => {
|
||||||
for pointer in abstract_list.item_pointers {
|
// for pointer in abstract_list.item_pointers {
|
||||||
let character = current_frame
|
// let character = current_frame
|
||||||
.get_character_from_pointer(&pointer)
|
// .get_character_from_pointer(&pointer)
|
||||||
.clone_inner();
|
// .clone_inner();
|
||||||
let value = ConcreteValue::Character(character);
|
// let value = ConcreteValue::Character(character);
|
||||||
|
|
||||||
concrete_list.push(value);
|
// concrete_list.push(value);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
TypeCode::FLOAT => {
|
// TypeCode::FLOAT => {
|
||||||
for pointer in abstract_list.item_pointers {
|
// for pointer in abstract_list.item_pointers {
|
||||||
let float =
|
// let float =
|
||||||
current_frame.get_float_from_pointer(&pointer).clone_inner();
|
// current_frame.get_float_from_pointer(&pointer).clone_inner();
|
||||||
let value = ConcreteValue::Float(float);
|
// let value = ConcreteValue::Float(float);
|
||||||
|
|
||||||
concrete_list.push(value);
|
// concrete_list.push(value);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
TypeCode::INTEGER => {
|
// TypeCode::INTEGER => {
|
||||||
for pointer in abstract_list.item_pointers {
|
// for pointer in abstract_list.item_pointers {
|
||||||
let integer = current_frame
|
// let integer = current_frame
|
||||||
.get_integer_from_pointer(&pointer)
|
// .get_integer_from_pointer(&pointer)
|
||||||
.clone_inner();
|
// .clone_inner();
|
||||||
let value = ConcreteValue::Integer(integer);
|
// let value = ConcreteValue::Integer(integer);
|
||||||
|
|
||||||
concrete_list.push(value);
|
// concrete_list.push(value);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
TypeCode::STRING => {
|
// TypeCode::STRING => {
|
||||||
for pointer in abstract_list.item_pointers {
|
// for pointer in abstract_list.item_pointers {
|
||||||
let string = current_frame
|
// let string = current_frame
|
||||||
.get_string_from_pointer(&pointer)
|
// .get_string_from_pointer(&pointer)
|
||||||
.clone_inner();
|
// .clone_inner();
|
||||||
let value = ConcreteValue::String(string);
|
// let value = ConcreteValue::String(string);
|
||||||
|
|
||||||
concrete_list.push(value);
|
// concrete_list.push(value);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
_ => todo!(),
|
// _ => todo!(),
|
||||||
}
|
// }
|
||||||
|
|
||||||
thread.return_value = Some(Value::Concrete(ConcreteValue::list(
|
// thread.return_value = Some(Value::Concrete(ConcreteValue::list(
|
||||||
concrete_list,
|
// concrete_list,
|
||||||
abstract_list.item_type,
|
// abstract_list.item_type,
|
||||||
)));
|
// )));
|
||||||
}
|
// }
|
||||||
_ => unreachable!(),
|
// _ => unreachable!(),
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@ pub struct CallFrame {
|
|||||||
pub ip: usize,
|
pub ip: usize,
|
||||||
pub return_register: u16,
|
pub return_register: u16,
|
||||||
pub registers: RegisterTable,
|
pub registers: RegisterTable,
|
||||||
pub constants: ConstantTable,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CallFrame {
|
impl CallFrame {
|
||||||
@ -30,174 +29,126 @@ impl CallFrame {
|
|||||||
lists: RegisterList::new(chunk.list_register_count as usize),
|
lists: RegisterList::new(chunk.list_register_count as usize),
|
||||||
functions: RegisterList::new(chunk.function_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 {
|
Self {
|
||||||
chunk,
|
chunk,
|
||||||
ip: 0,
|
ip: 0,
|
||||||
return_register,
|
return_register,
|
||||||
registers,
|
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);
|
let register = self.registers.booleans.get(register_index);
|
||||||
|
|
||||||
match register {
|
match register {
|
||||||
Register::Value { value, .. } => value,
|
Register::Value { value, .. } => *value,
|
||||||
Register::Pointer { pointer, .. } => self.get_boolean_from_pointer(pointer),
|
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 {
|
match pointer {
|
||||||
Pointer::Register(register_index) => self.get_boolean_from_register(*register_index),
|
Pointer::Register(register_index) => self.get_boolean_from_register(*register_index),
|
||||||
Pointer::Constant(_) => panic!("Attempted to get boolean from constant pointer"),
|
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);
|
let register = self.registers.bytes.get(register_index);
|
||||||
|
|
||||||
match register {
|
match register {
|
||||||
Register::Value { value, .. } => value,
|
Register::Value { value, .. } => *value,
|
||||||
Register::Pointer { pointer, .. } => self.get_byte_from_pointer(pointer),
|
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 {
|
match pointer {
|
||||||
Pointer::Register(register_index) => self.get_byte_from_register(*register_index),
|
Pointer::Register(register_index) => self.get_byte_from_register(*register_index),
|
||||||
Pointer::Constant(_) => panic!("Attempted to get byte from constant pointer"),
|
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);
|
let register = self.registers.characters.get(register_index);
|
||||||
|
|
||||||
match register {
|
match register {
|
||||||
Register::Value { value, .. } => value,
|
Register::Value { value, .. } => *value,
|
||||||
Register::Pointer { pointer, .. } => self.get_character_from_pointer(pointer),
|
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 {
|
match pointer {
|
||||||
Pointer::Register(register_index) => self.get_character_from_register(*register_index),
|
Pointer::Register(register_index) => self.get_character_from_register(*register_index),
|
||||||
Pointer::Constant(constant_index) => self.get_character_constant(*constant_index),
|
Pointer::Constant(constant_index) => self.get_character_constant(*constant_index),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_character_constant(&self, constant_index: usize) -> &RuntimeValue<char> {
|
pub fn get_character_constant(&self, constant_index: usize) -> char {
|
||||||
if cfg!(debug_assertions) {
|
let constant = if cfg!(debug_assertions) {
|
||||||
self.constants.characters.get(constant_index).unwrap()
|
self.chunk.character_constants.get(constant_index).unwrap()
|
||||||
} else {
|
} 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);
|
let register = self.registers.floats.get(register_index);
|
||||||
|
|
||||||
match register {
|
match register {
|
||||||
Register::Value { value, .. } => value,
|
Register::Value { value, .. } => *value,
|
||||||
Register::Pointer { pointer, .. } => self.get_float_from_pointer(pointer),
|
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 {
|
match pointer {
|
||||||
Pointer::Register(register_index) => self.get_float_from_register(*register_index),
|
Pointer::Register(register_index) => self.get_float_from_register(*register_index),
|
||||||
Pointer::Constant(constant_index) => self.get_float_constant(*constant_index),
|
Pointer::Constant(constant_index) => self.get_float_constant(*constant_index),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_float_constant(&self, constant_index: usize) -> &RuntimeValue<f64> {
|
pub fn get_float_constant(&self, constant_index: usize) -> f64 {
|
||||||
if cfg!(debug_assertions) {
|
let constant = if cfg!(debug_assertions) {
|
||||||
self.constants.floats.get(constant_index).unwrap()
|
self.chunk.float_constants.get(constant_index).unwrap()
|
||||||
} else {
|
} 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);
|
let register = self.registers.integers.get(register_index);
|
||||||
|
|
||||||
match register {
|
match register {
|
||||||
Register::Value { value, .. } => value,
|
Register::Value { value, .. } => *value,
|
||||||
Register::Pointer { pointer, .. } => self.get_integer_from_pointer(pointer),
|
Register::Pointer { pointer, .. } => self.get_integer_from_pointer(pointer),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_integer_from_register_mut(
|
pub fn get_integer_from_pointer(&self, pointer: &Pointer) -> i64 {
|
||||||
&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> {
|
|
||||||
match pointer {
|
match pointer {
|
||||||
Pointer::Register(register_index) => self.get_integer_from_register(*register_index),
|
Pointer::Register(register_index) => self.get_integer_from_register(*register_index),
|
||||||
Pointer::Constant(constant_index) => self.get_integer_constant(*constant_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> {
|
pub fn get_integer_constant(&self, constant_index: usize) -> i64 {
|
||||||
match pointer {
|
let constant = if cfg!(debug_assertions) {
|
||||||
Pointer::Register(register_index) => {
|
self.chunk.integer_constants.get(constant_index).unwrap()
|
||||||
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()
|
|
||||||
} else {
|
} 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> {
|
pub fn get_string_from_register(&self, register_index: usize) -> &DustString {
|
||||||
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> {
|
|
||||||
let register = self.registers.strings.get(register_index);
|
let register = self.registers.strings.get(register_index);
|
||||||
|
|
||||||
match register {
|
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 {
|
match pointer {
|
||||||
Pointer::Register(register_index) => self.get_string_from_register(*register_index),
|
Pointer::Register(register_index) => self.get_string_from_register(*register_index),
|
||||||
Pointer::Constant(constant_index) => self.get_string_constant(*constant_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) {
|
if cfg!(debug_assertions) {
|
||||||
self.constants.strings.get(constant_index).unwrap()
|
self.chunk.string_constants.get(constant_index).unwrap()
|
||||||
} else {
|
} else {
|
||||||
unsafe { self.constants.strings.get_unchecked(constant_index) }
|
unsafe { self.chunk.string_constants.get_unchecked(constant_index) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_string_constant_mut(
|
pub fn get_list_from_register(&self, register_index: usize) -> &AbstractList {
|
||||||
&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> {
|
|
||||||
let register = self.registers.lists.get(register_index);
|
let register = self.registers.lists.get(register_index);
|
||||||
|
|
||||||
match register {
|
match register {
|
||||||
@ -241,10 +181,7 @@ impl CallFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_list_from_register_mut(
|
pub fn get_list_from_register_mut(&mut self, register_index: usize) -> &mut AbstractList {
|
||||||
&mut self,
|
|
||||||
register_index: usize,
|
|
||||||
) -> &mut RuntimeValue<AbstractList> {
|
|
||||||
let register = self.registers.lists.get_mut(register_index);
|
let register = self.registers.lists.get_mut(register_index);
|
||||||
|
|
||||||
match register {
|
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 {
|
match pointer {
|
||||||
Pointer::Register(register_index) => self.get_list_from_register(*register_index),
|
Pointer::Register(register_index) => self.get_list_from_register(*register_index),
|
||||||
Pointer::Constant(_) => panic!("Attempted to get list from constant pointer"),
|
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);
|
let register = self.registers.functions.get(register_index);
|
||||||
|
|
||||||
match register {
|
match register {
|
||||||
@ -269,10 +206,7 @@ impl CallFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_function_from_register_mut(
|
pub fn get_function_from_register_mut(&mut self, register_index: usize) -> &mut Function {
|
||||||
&mut self,
|
|
||||||
register_index: usize,
|
|
||||||
) -> &mut RuntimeValue<Function> {
|
|
||||||
let register = self.registers.functions.get_mut(register_index);
|
let register = self.registers.functions.get_mut(register_index);
|
||||||
|
|
||||||
match register {
|
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 {
|
match pointer {
|
||||||
Pointer::Register(register_index) => self.get_function_from_register(*register_index),
|
Pointer::Register(register_index) => self.get_function_from_register(*register_index),
|
||||||
Pointer::Constant(_) => panic!("Attempted to get function from constant pointer"),
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct RegisterTable {
|
pub struct RegisterTable {
|
||||||
pub booleans: RegisterList<bool>,
|
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) {
|
pub fn close(&mut self, index: usize) {
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
self.registers.get_mut(index).unwrap().close()
|
self.registers.get_mut(index).unwrap().close()
|
||||||
@ -395,17 +327,18 @@ impl<T> IndexMut<usize> for RegisterList<T> {
|
|||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Register<T> {
|
pub enum Register<T> {
|
||||||
Value {
|
Value { value: T, is_closed: bool },
|
||||||
value: RuntimeValue<T>,
|
Pointer { pointer: Pointer, is_closed: bool },
|
||||||
is_closed: bool,
|
|
||||||
},
|
|
||||||
Pointer {
|
|
||||||
pointer: Pointer,
|
|
||||||
is_closed: bool,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Register<T> {
|
impl<T> Register<T> {
|
||||||
|
pub fn value(value: T) -> Self {
|
||||||
|
Self::Value {
|
||||||
|
value,
|
||||||
|
is_closed: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_closed(&self) -> bool {
|
pub fn is_closed(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Value { is_closed, .. } => *is_closed,
|
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 {
|
match self {
|
||||||
Self::Value {
|
Self::Value {
|
||||||
value: old_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 {
|
match self {
|
||||||
Self::Value { value, .. } => value,
|
Self::Value { value, .. } => value,
|
||||||
Self::Pointer { .. } => panic!("Attempted to use pointer as 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 {
|
match self {
|
||||||
Self::Value { value, .. } => value,
|
Self::Value { value, .. } => value,
|
||||||
Self::Pointer { .. } => panic!("Attempted to use pointer as 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> {
|
impl<T: Default> Default for Register<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::Value {
|
Self::Value {
|
||||||
value: RuntimeValue::Raw(Default::default()),
|
value: Default::default(),
|
||||||
is_closed: false,
|
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)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub enum Pointer {
|
pub enum Pointer {
|
||||||
Register(usize),
|
Register(usize),
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
//! Virtual machine and errors
|
//! Virtual machine and errors
|
||||||
mod action;
|
// mod action;
|
||||||
mod call_frame;
|
mod call_frame;
|
||||||
mod thread;
|
mod thread;
|
||||||
|
|
||||||
use std::{rc::Rc, thread::Builder};
|
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;
|
pub use thread::Thread;
|
||||||
|
|
||||||
use crossbeam_channel::bounded;
|
use crossbeam_channel::bounded;
|
||||||
|
@ -1,16 +1,14 @@
|
|||||||
use std::{rc::Rc, thread::JoinHandle};
|
use std::{rc::Rc, thread::JoinHandle};
|
||||||
|
|
||||||
use tracing::{info, trace};
|
use tracing::info;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
vm::{action::ActionSequence, CallFrame},
|
instruction::TypeCode, vm::CallFrame, Chunk, ConcreteValue, DustString, Operation, Span, Value,
|
||||||
Chunk, DustString, Span, Value,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Thread {
|
pub struct Thread {
|
||||||
chunk: Rc<Chunk>,
|
chunk: Rc<Chunk>,
|
||||||
call_stack: Vec<CallFrame>,
|
call_stack: Vec<CallFrame>,
|
||||||
pub return_value: Option<Value>,
|
|
||||||
_spawned_threads: Vec<JoinHandle<()>>,
|
_spawned_threads: Vec<JoinHandle<()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,7 +22,6 @@ impl Thread {
|
|||||||
Thread {
|
Thread {
|
||||||
chunk,
|
chunk,
|
||||||
call_stack,
|
call_stack,
|
||||||
return_value: None,
|
|
||||||
_spawned_threads: Vec::new(),
|
_spawned_threads: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -38,13 +35,371 @@ impl Thread {
|
|||||||
.unwrap_or_else(|| DustString::from("anonymous"))
|
.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 {
|
pub fn current_position(&self) -> Span {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user