Expand VM functionality; Slow the VM down quite a bit
This commit is contained in:
parent
7153cc16f2
commit
b0f7ca7992
@ -299,7 +299,7 @@ impl<'src> Compiler<'src> {
|
||||
.iter()
|
||||
.rev()
|
||||
.find_map(|(instruction, r#type, _)| {
|
||||
if (r#type == &Type::Byte)
|
||||
if *r#type == Type::Byte
|
||||
|| (instruction.operation() == Operation::LOAD_ENCODED
|
||||
&& instruction.b_type() == TypeCode::BYTE)
|
||||
{
|
||||
@ -332,8 +332,11 @@ impl<'src> Compiler<'src> {
|
||||
self.instructions
|
||||
.iter()
|
||||
.rev()
|
||||
.find_map(|(instruction, _, _)| {
|
||||
if instruction.b_type() == TypeCode::FLOAT && instruction.yields_value() {
|
||||
.find_map(|(instruction, r#type, _)| {
|
||||
if *r#type == Type::Float
|
||||
|| (instruction.operation() == Operation::LOAD_CONSTANT
|
||||
&& instruction.b_type() == TypeCode::FLOAT)
|
||||
{
|
||||
Some(instruction.a_field() + 1)
|
||||
} else {
|
||||
None
|
||||
|
@ -14,9 +14,9 @@ pub fn add_bytes(_: &mut usize, instruction: &InstructionFields, thread: &mut Th
|
||||
let right_index = instruction.c_field as usize;
|
||||
|
||||
let current_frame = thread.current_frame_mut();
|
||||
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.add(right_value);
|
||||
let left_value = current_frame.get_byte_from_register(left_index).clone();
|
||||
let right_value = current_frame.get_byte_from_register(right_index).clone();
|
||||
let sum = left_value.add(&right_value);
|
||||
|
||||
current_frame
|
||||
.registers
|
||||
@ -72,13 +72,15 @@ pub fn add_floats(_: &mut usize, instruction: &InstructionFields, thread: &mut T
|
||||
current_frame.get_float_constant(left)
|
||||
} else {
|
||||
current_frame.get_float_from_register(left)
|
||||
};
|
||||
}
|
||||
.clone();
|
||||
let right_value = if right_is_constant {
|
||||
current_frame.get_float_constant(right)
|
||||
} else {
|
||||
current_frame.get_float_from_register(right)
|
||||
};
|
||||
let sum = left_value.add(right_value);
|
||||
}
|
||||
.clone();
|
||||
let sum = left_value.add(&right_value);
|
||||
|
||||
current_frame
|
||||
.registers
|
||||
@ -100,13 +102,15 @@ pub fn add_integers(_: &mut usize, instruction: &InstructionFields, thread: &mut
|
||||
current_frame.get_integer_constant(left)
|
||||
} else {
|
||||
current_frame.get_integer_from_register(left)
|
||||
};
|
||||
}
|
||||
.clone();
|
||||
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.add(right_value);
|
||||
}
|
||||
.clone();
|
||||
let sum = left_value.add(&right_value);
|
||||
|
||||
current_frame
|
||||
.registers
|
||||
@ -201,12 +205,13 @@ pub fn add_string_character(_: &mut usize, instruction: &InstructionFields, thre
|
||||
}
|
||||
|
||||
pub fn optimized_add_integer(
|
||||
_: &mut usize,
|
||||
instruction: &InstructionFields,
|
||||
thread: &mut Thread,
|
||||
cache: &mut Option<[RuntimeValue<i64>; 3]>,
|
||||
) {
|
||||
if let Some([destination, left, right]) = cache {
|
||||
trace!("ADD_INTEGERS_OPTIMIZED using cache");
|
||||
trace!("OPTIMIZED_ADD using integer cache");
|
||||
|
||||
let sum = left.add(right);
|
||||
|
||||
|
@ -139,9 +139,9 @@ pub fn optimized_equal_integers(
|
||||
ip: &mut usize,
|
||||
instruction: &InstructionFields,
|
||||
thread: &mut Thread,
|
||||
cache: &mut Option<[RuntimeValue<i64>; 2]>,
|
||||
cache: &mut Option<[RuntimeValue<i64>; 3]>,
|
||||
) {
|
||||
if let Some([left, right]) = cache {
|
||||
if let Some([_, left, right]) = cache {
|
||||
trace!("equal_INTEGERS_OPTIMIZED using cache");
|
||||
|
||||
let is_equal = left == right;
|
||||
@ -193,6 +193,6 @@ pub fn optimized_equal_integers(
|
||||
*ip += 1;
|
||||
}
|
||||
|
||||
*cache = Some([left_value, right_value]);
|
||||
*cache = Some([RuntimeValue::Raw(0), left_value, right_value]);
|
||||
}
|
||||
}
|
||||
|
@ -139,10 +139,10 @@ pub fn optimized_less_integers(
|
||||
ip: &mut usize,
|
||||
instruction: &InstructionFields,
|
||||
thread: &mut Thread,
|
||||
cache: &mut Option<[RuntimeValue<i64>; 2]>,
|
||||
cache: &mut Option<[RuntimeValue<i64>; 3]>,
|
||||
) {
|
||||
if let Some([left, right]) = cache {
|
||||
trace!("LESS_INTEGERS_OPTIMIZED using cache");
|
||||
if let Some([_, left, right]) = cache {
|
||||
trace!("OPTIMIZED_LESS using integer cache");
|
||||
|
||||
let is_less_than = left < right;
|
||||
|
||||
@ -193,6 +193,6 @@ pub fn optimized_less_integers(
|
||||
*ip += 1;
|
||||
}
|
||||
|
||||
*cache = Some([left_value, right_value]);
|
||||
*cache = Some([RuntimeValue::Raw(0), left_value, right_value]);
|
||||
}
|
||||
}
|
||||
|
@ -139,9 +139,9 @@ pub fn optimized_less_equal_integers(
|
||||
ip: &mut usize,
|
||||
instruction: &InstructionFields,
|
||||
thread: &mut Thread,
|
||||
cache: &mut Option<[RuntimeValue<i64>; 2]>,
|
||||
cache: &mut Option<[RuntimeValue<i64>; 3]>,
|
||||
) {
|
||||
if let Some([left, right]) = cache {
|
||||
if let Some([_, left, right]) = cache {
|
||||
trace!("LESS_INTEGERS_OPTIMIZED using cache");
|
||||
|
||||
let is_less_than_or_equal = left <= right;
|
||||
@ -193,6 +193,6 @@ pub fn optimized_less_equal_integers(
|
||||
*ip += 1;
|
||||
}
|
||||
|
||||
*cache = Some([left_value, right_value]);
|
||||
*cache = Some([RuntimeValue::Raw(0), left_value, right_value]);
|
||||
}
|
||||
}
|
||||
|
@ -25,14 +25,18 @@ use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use crate::{
|
||||
instruction::{InstructionFields, TypeCode},
|
||||
Operation, Value,
|
||||
AbstractList, ConcreteValue, Operation, Value,
|
||||
};
|
||||
|
||||
use super::{call_frame::RuntimeValue, thread::Thread};
|
||||
use super::{call_frame::RuntimeValue, thread::Thread, Pointer};
|
||||
|
||||
pub type ActionLogic = fn(&mut usize, &InstructionFields, &mut Thread);
|
||||
pub type OptimizedActionLogicIntegers =
|
||||
fn(&mut usize, &InstructionFields, &mut Thread, &mut Option<[RuntimeValue<i64>; 3]>);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ActionSequence {
|
||||
actions: Vec<(Action, InstructionFields)>,
|
||||
actions: Vec<Action>,
|
||||
}
|
||||
|
||||
impl ActionSequence {
|
||||
@ -49,13 +53,13 @@ impl ActionSequence {
|
||||
let mut loop_actions = Vec::with_capacity(backward_offset + 1);
|
||||
let jump_action = Action::optimized(&instruction);
|
||||
|
||||
loop_actions.push((jump_action, instruction));
|
||||
loop_actions.push(jump_action);
|
||||
|
||||
for _ in 0..backward_offset {
|
||||
let instruction = instructions_reversed.next().unwrap();
|
||||
let action = Action::optimized(&instruction);
|
||||
|
||||
loop_actions.push((action, instruction));
|
||||
loop_actions.push(action);
|
||||
}
|
||||
|
||||
loop_actions.reverse();
|
||||
@ -64,7 +68,7 @@ impl ActionSequence {
|
||||
actions: loop_actions,
|
||||
});
|
||||
|
||||
actions.push((r#loop, instruction));
|
||||
actions.push(r#loop);
|
||||
|
||||
continue;
|
||||
}
|
||||
@ -72,7 +76,7 @@ impl ActionSequence {
|
||||
|
||||
let action = Action::unoptimized(instruction);
|
||||
|
||||
actions.push((action, instruction));
|
||||
actions.push(action);
|
||||
}
|
||||
|
||||
actions.reverse();
|
||||
@ -84,7 +88,11 @@ impl ActionSequence {
|
||||
let mut local_ip = 0;
|
||||
|
||||
while local_ip < self.actions.len() {
|
||||
let (action, instruction) = &mut self.actions[local_ip];
|
||||
let action = if cfg!(debug_assertions) {
|
||||
self.actions.get_mut(local_ip).unwrap()
|
||||
} else {
|
||||
unsafe { self.actions.get_unchecked_mut(local_ip) }
|
||||
};
|
||||
local_ip += 1;
|
||||
|
||||
info!("Run {action}");
|
||||
@ -96,17 +104,12 @@ impl ActionSequence {
|
||||
Action::Loop { actions } => {
|
||||
actions.run(thread);
|
||||
}
|
||||
Action::OptimizedAddIntegers(cache) => {
|
||||
optimized_add_integer(instruction, thread, cache);
|
||||
}
|
||||
Action::OptimizedEqualIntegers(cache) => {
|
||||
optimized_equal_integers(&mut local_ip, instruction, thread, cache);
|
||||
}
|
||||
Action::OptimizedLessIntegers(cache) => {
|
||||
optimized_less_integers(&mut local_ip, instruction, thread, cache);
|
||||
}
|
||||
Action::OptimizedLessEqualIntegers(cache) => {
|
||||
optimized_less_equal_integers(&mut local_ip, instruction, thread, cache);
|
||||
Action::OptimizedIntegers {
|
||||
logic,
|
||||
instruction,
|
||||
cache,
|
||||
} => {
|
||||
logic(&mut local_ip, &*instruction, thread, cache);
|
||||
}
|
||||
Action::OptimizedJumpForward { offset } => {
|
||||
local_ip += *offset;
|
||||
@ -123,7 +126,7 @@ impl Display for ActionSequence {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "[")?;
|
||||
|
||||
for (index, (action, _)) in self.actions.iter().enumerate() {
|
||||
for (index, action) in self.actions.iter().enumerate() {
|
||||
if index > 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
@ -144,10 +147,11 @@ enum Action {
|
||||
Loop {
|
||||
actions: ActionSequence,
|
||||
},
|
||||
OptimizedAddIntegers(Option<[RuntimeValue<i64>; 3]>),
|
||||
OptimizedEqualIntegers(Option<[RuntimeValue<i64>; 2]>),
|
||||
OptimizedLessIntegers(Option<[RuntimeValue<i64>; 2]>),
|
||||
OptimizedLessEqualIntegers(Option<[RuntimeValue<i64>; 2]>),
|
||||
OptimizedIntegers {
|
||||
logic: OptimizedActionLogicIntegers,
|
||||
instruction: InstructionFields,
|
||||
cache: Option<[RuntimeValue<i64>; 3]>,
|
||||
},
|
||||
OptimizedJumpForward {
|
||||
offset: usize,
|
||||
},
|
||||
@ -224,19 +228,35 @@ impl Action {
|
||||
pub fn optimized(instruction: &InstructionFields) -> Self {
|
||||
match instruction.operation {
|
||||
Operation::ADD => match (instruction.b_type, instruction.c_type) {
|
||||
(TypeCode::INTEGER, TypeCode::INTEGER) => Action::OptimizedAddIntegers(None),
|
||||
(TypeCode::INTEGER, TypeCode::INTEGER) => Action::OptimizedIntegers {
|
||||
logic: optimized_add_integer,
|
||||
instruction: *instruction,
|
||||
cache: None,
|
||||
},
|
||||
_ => todo!(),
|
||||
},
|
||||
Operation::EQUAL => match (instruction.b_type, instruction.c_type) {
|
||||
(TypeCode::INTEGER, TypeCode::INTEGER) => Action::OptimizedEqualIntegers(None),
|
||||
(TypeCode::INTEGER, TypeCode::INTEGER) => Action::OptimizedIntegers {
|
||||
logic: optimized_equal_integers,
|
||||
instruction: *instruction,
|
||||
cache: None,
|
||||
},
|
||||
_ => todo!(),
|
||||
},
|
||||
Operation::LESS => match (instruction.b_type, instruction.c_type) {
|
||||
(TypeCode::INTEGER, TypeCode::INTEGER) => Action::OptimizedLessIntegers(None),
|
||||
(TypeCode::INTEGER, TypeCode::INTEGER) => Action::OptimizedIntegers {
|
||||
logic: optimized_less_integers,
|
||||
instruction: *instruction,
|
||||
cache: None,
|
||||
},
|
||||
_ => todo!(),
|
||||
},
|
||||
Operation::LESS_EQUAL => match (instruction.b_type, instruction.c_type) {
|
||||
(TypeCode::INTEGER, TypeCode::INTEGER) => Action::OptimizedLessEqualIntegers(None),
|
||||
(TypeCode::INTEGER, TypeCode::INTEGER) => Action::OptimizedIntegers {
|
||||
logic: optimized_less_equal_integers,
|
||||
instruction: *instruction,
|
||||
cache: None,
|
||||
},
|
||||
_ => todo!(),
|
||||
},
|
||||
Operation::JUMP => {
|
||||
@ -267,17 +287,8 @@ impl Display for Action {
|
||||
Action::Loop { actions } => {
|
||||
write!(f, "LOOP: {actions}")
|
||||
}
|
||||
Action::OptimizedAddIntegers { .. } => {
|
||||
write!(f, "ADD_INTEGERS_OPTIMIZED")
|
||||
}
|
||||
Action::OptimizedEqualIntegers { .. } => {
|
||||
write!(f, "EQUAL_INTEGERS_OPTIMIZED")
|
||||
}
|
||||
Action::OptimizedLessIntegers { .. } => {
|
||||
write!(f, "LESS_INTEGERS_OPTIMIZED")
|
||||
}
|
||||
Action::OptimizedLessEqualIntegers { .. } => {
|
||||
write!(f, "LESS_EQUAL_INTEGERS_OPTIMIZED")
|
||||
Action::OptimizedIntegers { instruction, .. } => {
|
||||
write!(f, "OPTIMIZED_{}", instruction.operation)
|
||||
}
|
||||
Action::OptimizedJumpForward { offset } => {
|
||||
write!(f, "JUMP +{offset}")
|
||||
@ -289,8 +300,6 @@ impl Display for Action {
|
||||
}
|
||||
}
|
||||
|
||||
pub type ActionLogic = fn(&mut usize, &InstructionFields, &mut Thread);
|
||||
|
||||
fn point(_: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||
todo!()
|
||||
}
|
||||
@ -388,7 +397,96 @@ fn load_constant(ip: &mut usize, instruction: &InstructionFields, thread: &mut T
|
||||
}
|
||||
|
||||
fn load_list(ip: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||
todo!()
|
||||
let destination = instruction.a_field as usize;
|
||||
let start_register = instruction.b_field as usize;
|
||||
let item_type = instruction.b_type;
|
||||
let end_register = instruction.c_field as usize;
|
||||
let jump_next = instruction.d_field;
|
||||
let current_frame = thread.current_frame_mut();
|
||||
|
||||
let mut item_pointers = Vec::with_capacity(end_register - start_register + 1);
|
||||
|
||||
match item_type {
|
||||
TypeCode::BOOLEAN => {
|
||||
for register_index in start_register..=end_register {
|
||||
let register_is_closed = current_frame.registers.booleans.is_closed(register_index);
|
||||
|
||||
if register_is_closed {
|
||||
continue;
|
||||
}
|
||||
|
||||
item_pointers.push(Pointer::Register(register_index));
|
||||
}
|
||||
}
|
||||
TypeCode::BYTE => {
|
||||
for register_index in start_register..=end_register {
|
||||
let register_is_closed = current_frame.registers.bytes.is_closed(register_index);
|
||||
|
||||
if register_is_closed {
|
||||
continue;
|
||||
}
|
||||
|
||||
item_pointers.push(Pointer::Register(register_index));
|
||||
}
|
||||
}
|
||||
TypeCode::CHARACTER => {
|
||||
for register_index in start_register..=end_register {
|
||||
let register_is_closed =
|
||||
current_frame.registers.characters.is_closed(register_index);
|
||||
|
||||
if register_is_closed {
|
||||
continue;
|
||||
}
|
||||
|
||||
item_pointers.push(Pointer::Register(register_index));
|
||||
}
|
||||
}
|
||||
TypeCode::FLOAT => {
|
||||
for register_index in start_register..=end_register {
|
||||
let register_is_closed = current_frame.registers.floats.is_closed(register_index);
|
||||
|
||||
if register_is_closed {
|
||||
continue;
|
||||
}
|
||||
|
||||
item_pointers.push(Pointer::Register(register_index));
|
||||
}
|
||||
}
|
||||
TypeCode::INTEGER => {
|
||||
for register_index in start_register..=end_register {
|
||||
let register_is_closed = current_frame.registers.integers.is_closed(register_index);
|
||||
|
||||
if register_is_closed {
|
||||
continue;
|
||||
}
|
||||
|
||||
item_pointers.push(Pointer::Register(register_index));
|
||||
}
|
||||
}
|
||||
TypeCode::STRING => {
|
||||
for register_index in start_register..=end_register {
|
||||
let register_is_closed = current_frame.registers.strings.is_closed(register_index);
|
||||
|
||||
if register_is_closed {
|
||||
continue;
|
||||
}
|
||||
|
||||
item_pointers.push(Pointer::Register(register_index));
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
let list = RuntimeValue::Raw(AbstractList {
|
||||
item_type,
|
||||
item_pointers,
|
||||
});
|
||||
|
||||
current_frame.registers.lists.get_mut(destination).set(list);
|
||||
|
||||
if jump_next {
|
||||
*ip += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn load_function(_: &mut usize, _: &InstructionFields, _: &mut Thread) {
|
||||
@ -423,10 +521,6 @@ fn test_set(_: &mut usize, _: &InstructionFields, _: &mut Thread) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn less_equal(ip: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn negate(_: &mut usize, _: &InstructionFields, _: &mut Thread) {
|
||||
todo!()
|
||||
}
|
||||
@ -488,7 +582,76 @@ fn r#return(_: &mut usize, instruction: &InstructionFields, thread: &mut Thread)
|
||||
thread.return_value = Some(Value::string(return_value));
|
||||
}
|
||||
TypeCode::LIST => {
|
||||
todo!()
|
||||
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);
|
||||
|
||||
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::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::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!(),
|
||||
}
|
||||
|
||||
thread.return_value = Some(Value::Concrete(ConcreteValue::list(
|
||||
concrete_list,
|
||||
abstract_list.item_type,
|
||||
)));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
@ -231,6 +231,62 @@ impl CallFrame {
|
||||
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);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => value,
|
||||
Register::Pointer { pointer, .. } => self.get_list_from_pointer(pointer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_list_from_register_mut(
|
||||
&mut self,
|
||||
register_index: usize,
|
||||
) -> &mut RuntimeValue<AbstractList> {
|
||||
let register = self.registers.lists.get_mut(register_index);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => value,
|
||||
Register::Pointer { .. } => panic!("Attempted to get mutable list from pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_list_from_pointer(&self, pointer: &Pointer) -> &RuntimeValue<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> {
|
||||
let register = self.registers.functions.get(register_index);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => value,
|
||||
Register::Pointer { pointer, .. } => self.get_function_from_pointer(pointer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_function_from_register_mut(
|
||||
&mut self,
|
||||
register_index: usize,
|
||||
) -> &mut RuntimeValue<Function> {
|
||||
let register = self.registers.functions.get_mut(register_index);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => value,
|
||||
Register::Pointer { .. } => panic!("Attempted to get mutable function from pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_function_from_pointer(&self, pointer: &Pointer) -> &RuntimeValue<Function> {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_function_from_register(*register_index),
|
||||
Pointer::Constant(_) => panic!("Attempted to get function from constant pointer"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for CallFrame {
|
||||
@ -460,42 +516,66 @@ impl<T: Clone> RuntimeValue<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Add<Output = T> + Copy> Add for &RuntimeValue<T> {
|
||||
type Output = T;
|
||||
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 {
|
||||
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();
|
||||
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(),
|
||||
};
|
||||
|
||||
*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();
|
||||
BYTE_ADD(left, right)
|
||||
}
|
||||
}
|
||||
|
||||
**left + *right
|
||||
}
|
||||
(RuntimeValue::RefCell(left), RuntimeValue::RefCell(right)) => {
|
||||
let left = left.borrow();
|
||||
let right = right.borrow();
|
||||
const FLOAT_ADD: fn(f64, f64) -> f64 = f64::add;
|
||||
|
||||
*left + *right
|
||||
}
|
||||
(RuntimeValue::RefCell(left), RuntimeValue::Raw(right)) => {
|
||||
let left = left.borrow();
|
||||
impl Add for &RuntimeValue<f64> {
|
||||
type Output = f64;
|
||||
|
||||
*left + *right
|
||||
}
|
||||
(RuntimeValue::RefCell(left), RuntimeValue::Rc(right)) => {
|
||||
let left = left.borrow();
|
||||
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(),
|
||||
};
|
||||
|
||||
*left + **right
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use dust_lang::{
|
||||
Chunk, ConcreteValue, DustString, FunctionType, Instruction, Span, Type, Value, compile,
|
||||
instruction::TypeCode, run,
|
||||
compile, instruction::TypeCode, run, Chunk, ConcreteValue, DustString, FunctionType,
|
||||
Instruction, Span, Type, Value,
|
||||
};
|
||||
|
||||
#[test]
|
||||
@ -67,7 +67,7 @@ fn load_character() {
|
||||
Instruction::r#return(true, 0, TypeCode::CHARACTER),
|
||||
],
|
||||
positions: vec![Span(0, 3), Span(3, 3)],
|
||||
constants: vec![ConcreteValue::Character('a')],
|
||||
character_constants: vec!['a'],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::character('a'));
|
||||
@ -86,7 +86,7 @@ fn load_float() {
|
||||
Instruction::r#return(true, 0, TypeCode::FLOAT),
|
||||
],
|
||||
positions: vec![Span(0, 5), Span(5, 5)],
|
||||
constants: vec![ConcreteValue::Float(42.42)],
|
||||
float_constants: vec![42.42],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::float(42.42));
|
||||
@ -105,7 +105,7 @@ fn load_integer() {
|
||||
Instruction::r#return(true, 0, TypeCode::INTEGER),
|
||||
],
|
||||
positions: vec![Span(0, 2), Span(2, 2)],
|
||||
constants: vec![ConcreteValue::Integer(42)],
|
||||
integer_constants: vec![42],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::integer(42));
|
||||
@ -124,7 +124,7 @@ fn load_string() {
|
||||
Instruction::r#return(true, 0, TypeCode::STRING),
|
||||
],
|
||||
positions: vec![Span(0, 15), Span(15, 15)],
|
||||
constants: vec![ConcreteValue::String(DustString::from("Hello, World!"))],
|
||||
string_constants: vec![DustString::from("Hello, World!")],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::string("Hello, World!"));
|
||||
@ -191,7 +191,7 @@ fn load_character_list() {
|
||||
Instruction::r#return(true, 0, TypeCode::LIST),
|
||||
],
|
||||
positions: vec![Span(1, 4), Span(6, 9), Span(0, 10), Span(10, 10)],
|
||||
constants: vec![ConcreteValue::Character('a'), ConcreteValue::Character('b')],
|
||||
character_constants: vec!['a', 'b'],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::Concrete(ConcreteValue::List {
|
||||
@ -215,7 +215,7 @@ fn load_float_list() {
|
||||
Instruction::r#return(true, 0, TypeCode::LIST),
|
||||
],
|
||||
positions: vec![Span(1, 6), Span(8, 13), Span(0, 14), Span(14, 14)],
|
||||
constants: vec![ConcreteValue::Float(42.42), ConcreteValue::Float(24.24)],
|
||||
float_constants: vec![42.42, 24.24],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::Concrete(ConcreteValue::List {
|
||||
@ -240,11 +240,7 @@ fn load_integer_list() {
|
||||
Instruction::r#return(true, 0, TypeCode::LIST),
|
||||
],
|
||||
positions: vec![Span(1, 2), Span(4, 5), Span(7, 8), Span(0, 9), Span(9, 9)],
|
||||
constants: vec![
|
||||
ConcreteValue::Integer(1),
|
||||
ConcreteValue::Integer(2),
|
||||
ConcreteValue::Integer(3),
|
||||
],
|
||||
integer_constants: vec![1, 2, 3],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::Concrete(ConcreteValue::List {
|
||||
@ -272,10 +268,7 @@ fn load_string_list() {
|
||||
Instruction::r#return(true, 0, TypeCode::LIST),
|
||||
],
|
||||
positions: vec![Span(1, 8), Span(10, 17), Span(0, 18), Span(18, 18)],
|
||||
constants: vec![
|
||||
ConcreteValue::String(DustString::from("Hello")),
|
||||
ConcreteValue::String(DustString::from("World")),
|
||||
],
|
||||
string_constants: vec![DustString::from("Hello"), DustString::from("World")],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::Concrete(ConcreteValue::List {
|
||||
@ -315,12 +308,7 @@ fn load_nested_list() {
|
||||
Span(0, 16),
|
||||
Span(16, 16),
|
||||
],
|
||||
constants: vec![
|
||||
ConcreteValue::Integer(1),
|
||||
ConcreteValue::Integer(2),
|
||||
ConcreteValue::Integer(3),
|
||||
ConcreteValue::Integer(4),
|
||||
],
|
||||
integer_constants: vec![1, 2, 3, 4],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::Concrete(ConcreteValue::List {
|
||||
@ -386,16 +374,7 @@ fn load_deeply_nested_list() {
|
||||
Span(0, 36),
|
||||
Span(36, 36),
|
||||
],
|
||||
constants: vec![
|
||||
ConcreteValue::Integer(1),
|
||||
ConcreteValue::Integer(2),
|
||||
ConcreteValue::Integer(3),
|
||||
ConcreteValue::Integer(4),
|
||||
ConcreteValue::Integer(5),
|
||||
ConcreteValue::Integer(6),
|
||||
ConcreteValue::Integer(7),
|
||||
ConcreteValue::Integer(8),
|
||||
],
|
||||
integer_constants: vec![1, 2, 3, 4, 5, 6, 7, 8],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::Concrete(ConcreteValue::List {
|
||||
|
Loading…
x
Reference in New Issue
Block a user