Improve control flow register consolidation
This commit is contained in:
parent
6d17ba9a2c
commit
6f0955c29a
@ -27,7 +27,7 @@ use std::sync::Arc;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{DustString, Function, FunctionType, Instruction, Span, Value};
|
||||
use crate::{ConcreteValue, DustString, Function, FunctionType, Instruction, Span, Value};
|
||||
|
||||
/// Representation of a Dust program or function.
|
||||
///
|
||||
@ -39,38 +39,22 @@ pub struct Chunk {
|
||||
|
||||
pub(crate) instructions: Vec<Instruction>,
|
||||
pub(crate) positions: Vec<Span>,
|
||||
pub(crate) constants: Vec<Value>,
|
||||
pub(crate) constants: Vec<ConcreteValue>,
|
||||
pub(crate) locals: Vec<Local>,
|
||||
pub(crate) prototypes: Vec<Arc<Chunk>>,
|
||||
|
||||
pub(crate) register_count: usize,
|
||||
pub(crate) boolean_register_count: usize,
|
||||
pub(crate) byte_register_count: usize,
|
||||
pub(crate) character_register_count: usize,
|
||||
pub(crate) float_register_count: usize,
|
||||
pub(crate) integer_register_count: usize,
|
||||
pub(crate) string_register_count: usize,
|
||||
pub(crate) list_register_count: usize,
|
||||
pub(crate) function_register_count: usize,
|
||||
pub(crate) prototype_index: u16,
|
||||
}
|
||||
|
||||
impl Chunk {
|
||||
#[cfg(any(test, debug_assertions))]
|
||||
pub fn with_data(
|
||||
name: Option<DustString>,
|
||||
r#type: FunctionType,
|
||||
instructions: impl Into<Vec<Instruction>>,
|
||||
positions: impl Into<Vec<Span>>,
|
||||
constants: impl Into<Vec<Value>>,
|
||||
locals: impl Into<Vec<Local>>,
|
||||
prototypes: impl IntoIterator<Item = Chunk>,
|
||||
) -> Self {
|
||||
Self {
|
||||
name,
|
||||
r#type,
|
||||
instructions: instructions.into(),
|
||||
positions: positions.into(),
|
||||
constants: constants.into(),
|
||||
locals: locals.into(),
|
||||
prototypes: prototypes.into_iter().map(Arc::new).collect(),
|
||||
register_count: 0,
|
||||
prototype_index: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_function(&self) -> Function {
|
||||
Function {
|
||||
name: self.name.clone(),
|
||||
|
@ -19,7 +19,6 @@
|
||||
//! pass that chunk to the VM. Otherwise, if the compiler gives no errors and the VM encounters a
|
||||
//! runtime error, it is the compiler's fault and the error should be fixed here.
|
||||
mod error;
|
||||
mod optimize;
|
||||
mod parse_rule;
|
||||
mod type_checks;
|
||||
|
||||
@ -30,12 +29,10 @@ use type_checks::{check_math_type, check_math_types};
|
||||
|
||||
use std::{mem::replace, sync::Arc};
|
||||
|
||||
use optimize::control_flow_register_consolidation;
|
||||
|
||||
use crate::{
|
||||
Chunk, ConcreteValue, DustError, DustString, FunctionType, Instruction, Lexer, Local,
|
||||
NativeFunction, Operand, Operation, Scope, Span, Token, TokenKind, Type, Value,
|
||||
instruction::{CallNative, Close, Jump, LoadList, Point, Return, TypeCode},
|
||||
NativeFunction, Operand, Operation, Scope, Span, Token, TokenKind, Type,
|
||||
instruction::{CallNative, Jump, LoadList, Point, Return, TypeCode},
|
||||
};
|
||||
|
||||
/// Compiles the input and returns a chunk.
|
||||
@ -88,7 +85,7 @@ pub struct Compiler<'src> {
|
||||
|
||||
/// Constants that have been compiled. These are assigned to the chunk when [`Compiler::finish`]
|
||||
/// is called.
|
||||
constants: Vec<Value>,
|
||||
constants: Vec<ConcreteValue>,
|
||||
|
||||
/// Block-local variables and their types. The locals are assigned to the chunk when
|
||||
/// [`Compiler::finish`] is called. The types are discarded after compilation.
|
||||
@ -98,10 +95,6 @@ pub struct Compiler<'src> {
|
||||
/// [`Compiler::finish`] is called.
|
||||
prototypes: Vec<Arc<Chunk>>,
|
||||
|
||||
/// Maximum stack size required by the chunk. This is assigned to the chunk when
|
||||
/// [`Compiler::finish`] is called.
|
||||
stack_size: usize,
|
||||
|
||||
/// The first boolean register index that the compiler should use. This is used to avoid reusing
|
||||
/// the registers that are used for the function's arguments.
|
||||
minimum_boolean_register: u16,
|
||||
@ -175,7 +168,6 @@ impl<'src> Compiler<'src> {
|
||||
constants: Vec::new(),
|
||||
locals: Vec::new(),
|
||||
prototypes: Vec::new(),
|
||||
stack_size: 0,
|
||||
lexer,
|
||||
minimum_byte_register: 0,
|
||||
minimum_boolean_register: 0,
|
||||
@ -234,6 +226,14 @@ impl<'src> Compiler<'src> {
|
||||
/// will allow [`Compiler::function_name`] to be both the name used for recursive calls and the
|
||||
/// name of the function when it is compiled. The name can later be seen in the VM's call stack.
|
||||
pub fn finish(self) -> Chunk {
|
||||
let boolean_register_count = self.next_boolean_register() as usize;
|
||||
let byte_register_count = self.next_byte_register() as usize;
|
||||
let character_register_count = self.next_character_register() as usize;
|
||||
let float_register_count = self.next_float_register() as usize;
|
||||
let integer_register_count = self.next_integer_register() as usize;
|
||||
let string_register_count = self.next_string_register() as usize;
|
||||
let list_register_count = self.next_list_register() as usize;
|
||||
let function_register_count = self.next_function_register() as usize;
|
||||
let (instructions, positions): (Vec<Instruction>, Vec<Span>) = self
|
||||
.instructions
|
||||
.into_iter()
|
||||
@ -253,7 +253,14 @@ impl<'src> Compiler<'src> {
|
||||
constants: self.constants,
|
||||
locals,
|
||||
prototypes: self.prototypes,
|
||||
register_count: self.stack_size,
|
||||
boolean_register_count,
|
||||
byte_register_count,
|
||||
character_register_count,
|
||||
float_register_count,
|
||||
integer_register_count,
|
||||
string_register_count,
|
||||
list_register_count,
|
||||
function_register_count,
|
||||
prototype_index: self.prototype_index,
|
||||
}
|
||||
}
|
||||
@ -411,12 +418,11 @@ impl<'src> Compiler<'src> {
|
||||
.rev()
|
||||
.find_map(|(index, (local, _))| {
|
||||
let constant = self.constants.get(local.identifier_index as usize)?;
|
||||
let identifier =
|
||||
if let Value::Concrete(ConcreteValue::String(identifier)) = constant {
|
||||
identifier
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
let identifier = if let ConcreteValue::String(identifier) = constant {
|
||||
identifier
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
|
||||
if identifier == identifier_text {
|
||||
Some(index as u16)
|
||||
@ -440,7 +446,7 @@ impl<'src> Compiler<'src> {
|
||||
) -> (u16, u16) {
|
||||
info!("Declaring local {identifier}");
|
||||
|
||||
let identifier = Value::Concrete(ConcreteValue::string(identifier));
|
||||
let identifier = ConcreteValue::string(identifier);
|
||||
let identifier_index = self.push_or_get_constant(identifier);
|
||||
let local_index = self.locals.len() as u16;
|
||||
|
||||
@ -462,7 +468,7 @@ impl<'src> Compiler<'src> {
|
||||
})
|
||||
}
|
||||
|
||||
fn push_or_get_constant(&mut self, value: Value) -> u16 {
|
||||
fn push_or_get_constant(&mut self, value: ConcreteValue) -> u16 {
|
||||
if let Some(index) = self
|
||||
.constants
|
||||
.iter()
|
||||
@ -592,12 +598,6 @@ impl<'src> Compiler<'src> {
|
||||
position.to_string()
|
||||
);
|
||||
|
||||
if instruction.yields_value() {
|
||||
let destination = instruction.a_field() as usize;
|
||||
|
||||
self.stack_size = (destination + 1).max(self.stack_size);
|
||||
}
|
||||
|
||||
self.instructions.push((instruction, r#type, position));
|
||||
}
|
||||
|
||||
@ -607,7 +607,7 @@ impl<'src> Compiler<'src> {
|
||||
position: Span,
|
||||
) -> Result<(), CompileError> {
|
||||
let r#type = constant.r#type();
|
||||
let constant_index = self.push_or_get_constant(Value::Concrete(constant));
|
||||
let constant_index = self.push_or_get_constant(constant);
|
||||
let destination = match r#type {
|
||||
Type::Character => self.next_character_register(),
|
||||
Type::Float => self.next_float_register(),
|
||||
@ -615,7 +615,8 @@ impl<'src> Compiler<'src> {
|
||||
Type::String => self.next_string_register(),
|
||||
_ => todo!(),
|
||||
};
|
||||
let load_constant = Instruction::load_constant(destination, constant_index, false);
|
||||
let load_constant =
|
||||
Instruction::load_constant(destination, constant_index, r#type.type_code(), false);
|
||||
|
||||
self.emit_instruction(load_constant, r#type, position);
|
||||
|
||||
@ -1420,7 +1421,7 @@ impl<'src> Compiler<'src> {
|
||||
}
|
||||
|
||||
let if_block_end = self.instructions.len();
|
||||
let mut if_block_distance = (if_block_end - if_block_start) as u16;
|
||||
let mut if_block_distance = if_block_end - if_block_start;
|
||||
let if_block_type = self.get_last_instruction_type();
|
||||
|
||||
if let Token::Else = self.current_token {
|
||||
@ -1442,7 +1443,7 @@ impl<'src> Compiler<'src> {
|
||||
}
|
||||
|
||||
let else_block_end = self.instructions.len();
|
||||
let else_block_distance = (else_block_end - if_block_end) as u16;
|
||||
let else_block_distance = else_block_end - if_block_end;
|
||||
let else_block_type = self.get_last_instruction_type();
|
||||
|
||||
if let Err(conflict) = if_block_type.check(&else_block_type) {
|
||||
@ -1455,16 +1456,17 @@ impl<'src> Compiler<'src> {
|
||||
match else_block_distance {
|
||||
0 => {}
|
||||
1 => {
|
||||
if let Some(Operation::LOAD_BOOLEAN | Operation::LOAD_CONSTANT) =
|
||||
self.get_last_operation()
|
||||
if let Some([Operation::LOAD_BOOLEAN | Operation::LOAD_CONSTANT, _]) =
|
||||
self.get_last_operations()
|
||||
{
|
||||
let (loader, _, _) = self.instructions.last_mut().unwrap();
|
||||
let loader_index = self.instructions.len() - 2;
|
||||
let (loader, _, _) = self.instructions.get_mut(loader_index).unwrap();
|
||||
|
||||
loader.set_c_field(true as u16);
|
||||
} else {
|
||||
if_block_distance += 1;
|
||||
let jump = Instruction::from(Jump {
|
||||
offset: else_block_distance,
|
||||
offset: else_block_distance as u16,
|
||||
is_positive: true,
|
||||
});
|
||||
|
||||
@ -1475,7 +1477,7 @@ impl<'src> Compiler<'src> {
|
||||
2.. => {
|
||||
if_block_distance += 1;
|
||||
let jump = Instruction::from(Jump {
|
||||
offset: else_block_distance,
|
||||
offset: else_block_distance as u16,
|
||||
is_positive: true,
|
||||
});
|
||||
|
||||
@ -1484,11 +1486,21 @@ impl<'src> Compiler<'src> {
|
||||
}
|
||||
}
|
||||
|
||||
let jump = Instruction::jump(if_block_distance, true);
|
||||
let jump = Instruction::jump(if_block_distance as u16, true);
|
||||
|
||||
self.instructions
|
||||
.insert(if_block_start, (jump, Type::None, if_block_start_position));
|
||||
control_flow_register_consolidation(self);
|
||||
|
||||
let if_block_last_instruction_index = self.instructions.len() - else_block_distance - 1;
|
||||
let else_block_last_instruction_index = self.instructions.len() - 1;
|
||||
|
||||
let if_block_last_instruction = self.instructions[if_block_last_instruction_index].0;
|
||||
let else_block_last_instruction =
|
||||
&mut self.instructions[else_block_last_instruction_index].0;
|
||||
|
||||
else_block_last_instruction.set_a_field(if_block_last_instruction.a_field());
|
||||
|
||||
println!("{if_block_last_instruction_index} {else_block_last_instruction_index}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,64 +0,0 @@
|
||||
//! Functions used by the compiler to optimize a chunk's bytecode during compilation.
|
||||
|
||||
use tracing::debug;
|
||||
|
||||
use crate::{Compiler, Instruction, Operation};
|
||||
|
||||
/// Optimizes a control flow pattern to use fewer registers and avoid using a `POINT` instruction.
|
||||
/// Use this after parsing an if/else statement.
|
||||
///
|
||||
/// This makes the following examples compile to the same bytecode:
|
||||
///
|
||||
/// ```dust
|
||||
/// 4 == 4
|
||||
/// ```
|
||||
///
|
||||
/// ```dust
|
||||
/// if 4 == 4 { true } else { false }
|
||||
/// ```
|
||||
///
|
||||
/// When they occur in the sequence shown below, instructions can be optimized by taking advantage
|
||||
/// of the loaders' ability to skip an instruction after loading a value. If these instructions are
|
||||
/// the result of a binary expression, this will not change anything because they were already
|
||||
/// emitted optimally. Control flow patterns, however, can be optimized because the load
|
||||
/// instructions are from seperate expressions that each uses its own register. Since only one of
|
||||
/// the two branches will be executed, this is wasteful. It would also require the compiler to emit
|
||||
/// a `POINT` instruction to prevent the VM from encountering an empty register.
|
||||
///
|
||||
/// The instructions must be in the following order:
|
||||
/// - `TEST` or any of the `EQUAL`, `LESS` or `LESS_EQUAL` instructions
|
||||
/// - `JUMP`
|
||||
/// - `LOAD_BOOLEAN` or `LOAD_CONSTANT`
|
||||
/// - `LOAD_BOOLEAN` or `LOAD_CONSTANT`
|
||||
///
|
||||
/// This optimization was taken from `A No-Frills Introduction to Lua 5.1 VM Instructions` by
|
||||
/// Kein-Hong Man.
|
||||
pub fn control_flow_register_consolidation(compiler: &mut Compiler) {
|
||||
if !matches!(
|
||||
compiler.get_last_operations(),
|
||||
Some([
|
||||
Operation::TEST | Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL,
|
||||
Operation::JUMP,
|
||||
Operation::LOAD_BOOLEAN | Operation::LOAD_CONSTANT,
|
||||
Operation::LOAD_BOOLEAN | Operation::LOAD_CONSTANT,
|
||||
])
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
debug!("Consolidating registers for control flow optimization");
|
||||
|
||||
let first_loader_index = compiler.instructions.len() - 2;
|
||||
let (first_loader, _, _) = &mut compiler.instructions.get_mut(first_loader_index).unwrap();
|
||||
let first_loader_destination = first_loader.a_field();
|
||||
*first_loader =
|
||||
Instruction::load_boolean(first_loader.a_field(), first_loader.b_field() != 0, true);
|
||||
|
||||
let second_loader_index = compiler.instructions.len() - 1;
|
||||
let (second_loader, _, _) = &mut compiler.instructions.get_mut(second_loader_index).unwrap();
|
||||
*second_loader = Instruction::load_boolean(
|
||||
first_loader_destination,
|
||||
second_loader.b_field() != 0,
|
||||
false,
|
||||
);
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode};
|
||||
use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
|
||||
|
||||
pub struct Add {
|
||||
pub destination: u16,
|
||||
@ -36,7 +36,7 @@ impl From<Add> for Instruction {
|
||||
let b_type = add.left_type;
|
||||
let c_type = add.right_type;
|
||||
|
||||
InstructionBuilder {
|
||||
InstructionFields {
|
||||
operation,
|
||||
a_field,
|
||||
b_field,
|
||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use crate::{Instruction, Operation};
|
||||
|
||||
use super::InstructionBuilder;
|
||||
use super::InstructionFields;
|
||||
|
||||
pub struct Call {
|
||||
pub destination: u16,
|
||||
@ -34,7 +34,7 @@ impl From<Call> for Instruction {
|
||||
let c_field = call.argument_count;
|
||||
let d_field = call.is_recursive;
|
||||
|
||||
InstructionBuilder {
|
||||
InstructionFields {
|
||||
operation: Operation::CALL,
|
||||
a_field,
|
||||
b_field,
|
||||
|
@ -2,7 +2,7 @@ use std::fmt::Display;
|
||||
|
||||
use crate::{Instruction, NativeFunction, Operation};
|
||||
|
||||
use super::InstructionBuilder;
|
||||
use super::InstructionFields;
|
||||
|
||||
pub struct CallNative {
|
||||
pub destination: u16,
|
||||
@ -30,7 +30,7 @@ impl From<CallNative> for Instruction {
|
||||
let b_field = call_native.function as u16;
|
||||
let c_field = call_native.argument_count;
|
||||
|
||||
InstructionBuilder {
|
||||
InstructionFields {
|
||||
operation,
|
||||
a_field,
|
||||
b_field,
|
||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use crate::{Instruction, Operation};
|
||||
|
||||
use super::InstructionBuilder;
|
||||
use super::InstructionFields;
|
||||
|
||||
pub struct Close {
|
||||
pub from: u16,
|
||||
@ -24,7 +24,7 @@ impl From<Close> for Instruction {
|
||||
let b_field = close.from;
|
||||
let c_field = close.to;
|
||||
|
||||
InstructionBuilder {
|
||||
InstructionFields {
|
||||
operation,
|
||||
b_field,
|
||||
c_field,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode};
|
||||
use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
|
||||
|
||||
pub struct Divide {
|
||||
pub destination: u16,
|
||||
@ -36,7 +36,7 @@ impl From<Divide> for Instruction {
|
||||
let b_type = divide.left_type;
|
||||
let c_type = divide.right_type;
|
||||
|
||||
InstructionBuilder {
|
||||
InstructionFields {
|
||||
operation,
|
||||
a_field,
|
||||
b_field,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode};
|
||||
use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
|
||||
|
||||
pub struct Equal {
|
||||
pub comparator: bool,
|
||||
@ -36,7 +36,7 @@ impl From<Equal> for Instruction {
|
||||
let b_type = equal_bool.left_type;
|
||||
let c_type = equal_bool.right_type;
|
||||
|
||||
InstructionBuilder {
|
||||
InstructionFields {
|
||||
operation,
|
||||
b_field,
|
||||
c_field,
|
||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use crate::{Instruction, Operation};
|
||||
|
||||
use super::InstructionBuilder;
|
||||
use super::InstructionFields;
|
||||
|
||||
pub struct Jump {
|
||||
pub offset: u16,
|
||||
@ -24,7 +24,7 @@ impl From<Jump> for Instruction {
|
||||
let b_field = jump.offset;
|
||||
let c_field = jump.is_positive as u16;
|
||||
|
||||
InstructionBuilder {
|
||||
InstructionFields {
|
||||
operation,
|
||||
b_field,
|
||||
c_field,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode};
|
||||
use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
|
||||
|
||||
pub struct Less {
|
||||
pub comparator: bool,
|
||||
@ -36,7 +36,7 @@ impl From<Less> for Instruction {
|
||||
let b_type = less.left_type;
|
||||
let c_type = less.right_type;
|
||||
|
||||
InstructionBuilder {
|
||||
InstructionFields {
|
||||
operation,
|
||||
b_field,
|
||||
c_field,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode};
|
||||
use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
|
||||
|
||||
pub struct LessEqual {
|
||||
pub comparator: bool,
|
||||
@ -36,7 +36,7 @@ impl From<LessEqual> for Instruction {
|
||||
let b_type = less_equal_byte.left_type;
|
||||
let c_type = less_equal_byte.right_type;
|
||||
|
||||
InstructionBuilder {
|
||||
InstructionFields {
|
||||
operation,
|
||||
b_field,
|
||||
c_field,
|
||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use crate::{Instruction, Operation};
|
||||
|
||||
use super::InstructionBuilder;
|
||||
use super::InstructionFields;
|
||||
|
||||
pub struct LoadBoolean {
|
||||
pub destination: u16,
|
||||
@ -27,7 +27,7 @@ impl From<LoadBoolean> for Instruction {
|
||||
let b_field = load_boolean.value as u16;
|
||||
let c_field = load_boolean.jump_next as u16;
|
||||
|
||||
InstructionBuilder {
|
||||
InstructionFields {
|
||||
operation,
|
||||
a_field,
|
||||
b_field,
|
||||
|
@ -2,11 +2,12 @@ use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use crate::{Instruction, Operation};
|
||||
|
||||
use super::InstructionBuilder;
|
||||
use super::{InstructionFields, TypeCode};
|
||||
|
||||
pub struct LoadConstant {
|
||||
pub destination: u16,
|
||||
pub constant_index: u16,
|
||||
pub constant_type: TypeCode,
|
||||
pub jump_next: bool,
|
||||
}
|
||||
|
||||
@ -14,11 +15,13 @@ impl From<Instruction> for LoadConstant {
|
||||
fn from(instruction: Instruction) -> Self {
|
||||
let destination = instruction.a_field();
|
||||
let constant_index = instruction.b_field();
|
||||
let constant_type = instruction.b_type();
|
||||
let jump_next = instruction.c_field() != 0;
|
||||
|
||||
LoadConstant {
|
||||
destination,
|
||||
constant_index,
|
||||
constant_type,
|
||||
jump_next,
|
||||
}
|
||||
}
|
||||
@ -26,10 +29,11 @@ impl From<Instruction> for LoadConstant {
|
||||
|
||||
impl From<LoadConstant> for Instruction {
|
||||
fn from(load_constant: LoadConstant) -> Self {
|
||||
InstructionBuilder {
|
||||
InstructionFields {
|
||||
operation: Operation::LOAD_CONSTANT,
|
||||
a_field: load_constant.destination,
|
||||
b_field: load_constant.constant_index,
|
||||
b_type: load_constant.constant_type,
|
||||
c_field: load_constant.jump_next as u16,
|
||||
..Default::default()
|
||||
}
|
||||
@ -42,10 +46,21 @@ impl Display for LoadConstant {
|
||||
let LoadConstant {
|
||||
destination,
|
||||
constant_index,
|
||||
constant_type,
|
||||
jump_next,
|
||||
} = self;
|
||||
|
||||
write!(f, "R{destination} = C{constant_index}")?;
|
||||
match *constant_type {
|
||||
TypeCode::BOOLEAN => write!(f, "R_BOOL_{destination}")?,
|
||||
TypeCode::BYTE => write!(f, "R_BYTE_{destination}")?,
|
||||
TypeCode::CHARACTER => write!(f, "R_CHAR_{destination}")?,
|
||||
TypeCode::FLOAT => write!(f, "R_FLOAT_{destination}")?,
|
||||
TypeCode::INTEGER => write!(f, "R_INT_{destination}")?,
|
||||
TypeCode::STRING => write!(f, "R_STR_{destination}")?,
|
||||
unsupported => panic!("Unsupported type code: {}", unsupported.0),
|
||||
}
|
||||
|
||||
write!(f, " = C{constant_index}")?;
|
||||
|
||||
if *jump_next {
|
||||
write!(f, " JUMP +1")?;
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use super::{Instruction, InstructionBuilder, Operation};
|
||||
use super::{Instruction, InstructionFields, Operation};
|
||||
|
||||
pub struct LoadFunction {
|
||||
pub destination: u16,
|
||||
@ -24,7 +24,7 @@ impl From<Instruction> for LoadFunction {
|
||||
|
||||
impl From<LoadFunction> for Instruction {
|
||||
fn from(load_function: LoadFunction) -> Self {
|
||||
InstructionBuilder {
|
||||
InstructionFields {
|
||||
operation: Operation::LOAD_FUNCTION,
|
||||
a_field: load_function.destination,
|
||||
b_field: load_function.prototype_index,
|
||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use crate::{Instruction, Operation};
|
||||
|
||||
use super::InstructionBuilder;
|
||||
use super::InstructionFields;
|
||||
|
||||
pub struct LoadList {
|
||||
pub destination: u16,
|
||||
@ -26,7 +26,7 @@ impl From<Instruction> for LoadList {
|
||||
|
||||
impl From<LoadList> for Instruction {
|
||||
fn from(load_list: LoadList) -> Self {
|
||||
InstructionBuilder {
|
||||
InstructionFields {
|
||||
operation: Operation::LOAD_LIST,
|
||||
a_field: load_list.destination,
|
||||
b_field: load_list.start_register,
|
||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use crate::{Instruction, Operation};
|
||||
|
||||
use super::InstructionBuilder;
|
||||
use super::InstructionFields;
|
||||
|
||||
pub struct LoadSelf {
|
||||
pub destination: u16,
|
||||
@ -23,7 +23,7 @@ impl From<Instruction> for LoadSelf {
|
||||
|
||||
impl From<LoadSelf> for Instruction {
|
||||
fn from(load_self: LoadSelf) -> Self {
|
||||
InstructionBuilder {
|
||||
InstructionFields {
|
||||
operation: Operation::LOAD_SELF,
|
||||
a_field: load_self.destination,
|
||||
c_field: load_self.jump_next as u16,
|
||||
|
@ -151,7 +151,7 @@ pub use type_code::TypeCode;
|
||||
use crate::NativeFunction;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct InstructionBuilder {
|
||||
pub struct InstructionFields {
|
||||
pub operation: Operation,
|
||||
pub a_field: u16,
|
||||
pub b_field: u16,
|
||||
@ -163,7 +163,7 @@ pub struct InstructionBuilder {
|
||||
pub c_type: TypeCode,
|
||||
}
|
||||
|
||||
impl InstructionBuilder {
|
||||
impl InstructionFields {
|
||||
pub fn build(self) -> Instruction {
|
||||
let bits = ((self.operation.0 as u64) << 57)
|
||||
| ((self.b_is_constant as u64) << 56)
|
||||
@ -179,9 +179,9 @@ impl InstructionBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Instruction> for InstructionBuilder {
|
||||
impl From<&Instruction> for InstructionFields {
|
||||
fn from(instruction: &Instruction) -> Self {
|
||||
InstructionBuilder {
|
||||
InstructionFields {
|
||||
operation: instruction.operation(),
|
||||
a_field: instruction.a_field(),
|
||||
b_field: instruction.b_field(),
|
||||
@ -195,9 +195,9 @@ impl From<&Instruction> for InstructionBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for InstructionBuilder {
|
||||
impl Default for InstructionFields {
|
||||
fn default() -> Self {
|
||||
InstructionBuilder {
|
||||
InstructionFields {
|
||||
operation: Operation::POINT,
|
||||
a_field: 0,
|
||||
b_field: 0,
|
||||
@ -261,15 +261,21 @@ impl Instruction {
|
||||
}
|
||||
|
||||
pub fn set_a_field(&mut self, bits: u16) {
|
||||
self.0 = (bits as u64) << 31;
|
||||
let mut fields = InstructionFields::from(&*self);
|
||||
fields.a_field = bits;
|
||||
*self = fields.build();
|
||||
}
|
||||
|
||||
pub fn set_b_field(&mut self, bits: u16) {
|
||||
self.0 = (bits as u64) << 47;
|
||||
let mut fields = InstructionFields::from(&*self);
|
||||
fields.b_field = bits;
|
||||
*self = fields.build();
|
||||
}
|
||||
|
||||
pub fn set_c_field(&mut self, bits: u16) {
|
||||
self.0 = (bits as u64) << 63;
|
||||
let mut fields = InstructionFields::from(&*self);
|
||||
fields.c_field = bits;
|
||||
*self = fields.build();
|
||||
}
|
||||
|
||||
pub fn point(destination: u16, to: Operand) -> Instruction {
|
||||
@ -288,10 +294,16 @@ impl Instruction {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn load_constant(destination: u16, constant_index: u16, jump_next: bool) -> Instruction {
|
||||
pub fn load_constant(
|
||||
destination: u16,
|
||||
constant_index: u16,
|
||||
constant_type: TypeCode,
|
||||
jump_next: bool,
|
||||
) -> Instruction {
|
||||
Instruction::from(LoadConstant {
|
||||
destination,
|
||||
constant_index,
|
||||
constant_type,
|
||||
jump_next,
|
||||
})
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode};
|
||||
use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
|
||||
|
||||
pub struct Modulo {
|
||||
pub destination: u16,
|
||||
@ -36,7 +36,7 @@ impl From<Modulo> for Instruction {
|
||||
let b_type = modulo.left_type;
|
||||
let c_type = modulo.right_type;
|
||||
|
||||
InstructionBuilder {
|
||||
InstructionFields {
|
||||
operation,
|
||||
a_field,
|
||||
b_field,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode};
|
||||
use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
|
||||
|
||||
pub struct Multiply {
|
||||
pub destination: u16,
|
||||
@ -36,7 +36,7 @@ impl From<Multiply> for Instruction {
|
||||
let b_type = multiply.left_type;
|
||||
let c_type = multiply.right_type;
|
||||
|
||||
InstructionBuilder {
|
||||
InstructionFields {
|
||||
operation,
|
||||
a_field,
|
||||
b_field,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode};
|
||||
use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
|
||||
|
||||
pub struct Negate {
|
||||
pub destination: u16,
|
||||
@ -29,7 +29,7 @@ impl From<Negate> for Instruction {
|
||||
let (b_field, b_is_constant) = negate.argument.as_index_and_constant_flag();
|
||||
let b_type = negate.argument_type;
|
||||
|
||||
InstructionBuilder {
|
||||
InstructionFields {
|
||||
operation,
|
||||
a_field,
|
||||
b_field,
|
||||
|
@ -2,7 +2,7 @@ use std::fmt::Display;
|
||||
|
||||
use crate::{Instruction, Operand, Operation};
|
||||
|
||||
use super::InstructionBuilder;
|
||||
use super::InstructionFields;
|
||||
|
||||
pub struct Not {
|
||||
pub destination: u16,
|
||||
@ -27,7 +27,7 @@ impl From<Not> for Instruction {
|
||||
let a_field = not.destination;
|
||||
let (b_field, b_is_constant) = not.argument.as_index_and_constant_flag();
|
||||
|
||||
InstructionBuilder {
|
||||
InstructionFields {
|
||||
operation,
|
||||
a_field,
|
||||
b_field,
|
||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use crate::{Instruction, Operation};
|
||||
|
||||
use super::{InstructionBuilder, Operand};
|
||||
use super::{InstructionFields, Operand};
|
||||
|
||||
pub struct Point {
|
||||
pub destination: u16,
|
||||
@ -24,7 +24,7 @@ impl From<Point> for Instruction {
|
||||
let a_field = r#move.destination;
|
||||
let (b_field, b_is_constant) = r#move.to.as_index_and_constant_flag();
|
||||
|
||||
InstructionBuilder {
|
||||
InstructionFields {
|
||||
operation,
|
||||
a_field,
|
||||
b_field,
|
||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use crate::{Instruction, Operation};
|
||||
|
||||
use super::{InstructionBuilder, TypeCode};
|
||||
use super::{InstructionFields, TypeCode};
|
||||
|
||||
pub struct Return {
|
||||
pub should_return_value: bool,
|
||||
@ -31,7 +31,7 @@ impl From<Return> for Instruction {
|
||||
let b_type = r#return.r#type;
|
||||
let c_field = r#return.return_register;
|
||||
|
||||
InstructionBuilder {
|
||||
InstructionFields {
|
||||
operation,
|
||||
b_field,
|
||||
b_type,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode};
|
||||
use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
|
||||
|
||||
pub struct Subtract {
|
||||
pub destination: u16,
|
||||
@ -36,7 +36,7 @@ impl From<Subtract> for Instruction {
|
||||
let b_type = subtract.left_type;
|
||||
let c_type = subtract.right_type;
|
||||
|
||||
InstructionBuilder {
|
||||
InstructionFields {
|
||||
operation,
|
||||
a_field,
|
||||
b_field,
|
||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use crate::{Instruction, Operation};
|
||||
|
||||
use super::InstructionBuilder;
|
||||
use super::InstructionFields;
|
||||
|
||||
pub struct Test {
|
||||
pub operand_register: u16,
|
||||
@ -26,7 +26,7 @@ impl From<Test> for Instruction {
|
||||
let b_field = test.operand_register;
|
||||
let c_field = test.test_value as u16;
|
||||
|
||||
InstructionBuilder {
|
||||
InstructionFields {
|
||||
operation: Operation::TEST,
|
||||
b_field,
|
||||
c_field,
|
||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use crate::{Instruction, Operand, Operation};
|
||||
|
||||
use super::InstructionBuilder;
|
||||
use super::InstructionFields;
|
||||
|
||||
pub struct TestSet {
|
||||
pub destination: u16,
|
||||
@ -31,7 +31,7 @@ impl From<TestSet> for Instruction {
|
||||
let (b_field, b_is_constant) = test_set.argument.as_index_and_constant_flag();
|
||||
let c_field = test_set.test_value as u16;
|
||||
|
||||
InstructionBuilder {
|
||||
InstructionFields {
|
||||
operation,
|
||||
a_field,
|
||||
b_field,
|
||||
|
@ -35,6 +35,46 @@ impl ConcreteValue {
|
||||
ConcreteValue::String(to_string.into())
|
||||
}
|
||||
|
||||
pub fn as_boolean(&self) -> Option<bool> {
|
||||
if let ConcreteValue::Boolean(boolean) = self {
|
||||
Some(*boolean)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_byte(&self) -> Option<u8> {
|
||||
if let ConcreteValue::Byte(byte) = self {
|
||||
Some(*byte)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_character(&self) -> Option<char> {
|
||||
if let ConcreteValue::Character(character) = self {
|
||||
Some(*character)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_float(&self) -> Option<f64> {
|
||||
if let ConcreteValue::Float(float) = self {
|
||||
Some(*float)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_integer(&self) -> Option<i64> {
|
||||
if let ConcreteValue::Integer(integer) = self {
|
||||
Some(*integer)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_string(&self) -> Option<&DustString> {
|
||||
if let ConcreteValue::String(string) = self {
|
||||
Some(string)
|
||||
@ -43,6 +83,22 @@ impl ConcreteValue {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_list(&self) -> Option<&Vec<ConcreteValue>> {
|
||||
if let ConcreteValue::List(list) = self {
|
||||
Some(list)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_range(&self) -> Option<&RangeValue> {
|
||||
if let ConcreteValue::Range(range) = self {
|
||||
Some(range)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn display(&self) -> DustString {
|
||||
DustString::from(self.to_string())
|
||||
}
|
||||
@ -147,7 +203,7 @@ impl ConcreteValue {
|
||||
return Err(ValueError::CannotMultiply(
|
||||
self.clone().to_value(),
|
||||
other.clone().to_value(),
|
||||
))
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
@ -165,7 +221,7 @@ impl ConcreteValue {
|
||||
return Err(ValueError::CannotMultiply(
|
||||
self.clone().to_value(),
|
||||
other.clone().to_value(),
|
||||
))
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
@ -185,7 +241,7 @@ impl ConcreteValue {
|
||||
return Err(ValueError::CannotMultiply(
|
||||
self.clone().to_value(),
|
||||
other.clone().to_value(),
|
||||
))
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
@ -255,7 +311,7 @@ impl ConcreteValue {
|
||||
return Err(ValueError::CannotCompare(
|
||||
self.clone().to_value(),
|
||||
other.clone().to_value(),
|
||||
))
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
@ -278,7 +334,7 @@ impl ConcreteValue {
|
||||
return Err(ValueError::CannotCompare(
|
||||
self.clone().to_value(),
|
||||
other.clone().to_value(),
|
||||
))
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,16 +1,9 @@
|
||||
use tracing::trace;
|
||||
|
||||
use crate::{
|
||||
AbstractList, ConcreteValue, Instruction, Operand, Type, Value,
|
||||
instruction::{
|
||||
Add, Call, CallNative, Divide, Equal, InstructionBuilder, Jump, Less, LessEqual,
|
||||
LoadBoolean, LoadConstant, LoadFunction, LoadList, LoadSelf, Modulo, Multiply, Negate, Not,
|
||||
Return, Subtract, Test, TestSet, TypeCode,
|
||||
},
|
||||
vm::CallFrame,
|
||||
Instruction, Value,
|
||||
instruction::{InstructionFields, TypeCode},
|
||||
};
|
||||
|
||||
use super::{Pointer, Register, thread::Thread};
|
||||
use super::thread::Thread;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ActionSequence {
|
||||
@ -34,20 +27,20 @@ impl ActionSequence {
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct Action {
|
||||
pub logic: RunnerLogic,
|
||||
pub instruction: InstructionBuilder,
|
||||
pub instruction: InstructionFields,
|
||||
}
|
||||
|
||||
impl From<&Instruction> for Action {
|
||||
fn from(instruction: &Instruction) -> Self {
|
||||
let operation = instruction.operation();
|
||||
let logic = RUNNER_LOGIC_TABLE[operation.0 as usize];
|
||||
let instruction = InstructionBuilder::from(instruction);
|
||||
let instruction = InstructionFields::from(instruction);
|
||||
|
||||
Action { logic, instruction }
|
||||
}
|
||||
}
|
||||
|
||||
pub type RunnerLogic = fn(InstructionBuilder, &mut Thread);
|
||||
pub type RunnerLogic = fn(InstructionFields, &mut Thread);
|
||||
|
||||
pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 23] = [
|
||||
point,
|
||||
@ -75,21 +68,21 @@ pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 23] = [
|
||||
r#return,
|
||||
];
|
||||
|
||||
pub fn point(instruction: InstructionBuilder, thread: &mut Thread) {}
|
||||
pub fn point(instruction: InstructionFields, thread: &mut Thread) {}
|
||||
|
||||
pub fn close(instruction: InstructionBuilder, thread: &mut Thread) {}
|
||||
pub fn close(instruction: InstructionFields, thread: &mut Thread) {}
|
||||
|
||||
pub fn load_boolean(instruction: InstructionBuilder, thread: &mut Thread) {}
|
||||
pub fn load_boolean(instruction: InstructionFields, thread: &mut Thread) {}
|
||||
|
||||
pub fn load_constant(instruction: InstructionBuilder, thread: &mut Thread) {}
|
||||
pub fn load_constant(instruction: InstructionFields, thread: &mut Thread) {}
|
||||
|
||||
pub fn load_list(instruction: InstructionBuilder, thread: &mut Thread) {}
|
||||
pub fn load_list(instruction: InstructionFields, thread: &mut Thread) {}
|
||||
|
||||
pub fn load_function(instruction: InstructionBuilder, thread: &mut Thread) {}
|
||||
pub fn load_function(instruction: InstructionFields, thread: &mut Thread) {}
|
||||
|
||||
pub fn load_self(instruction: InstructionBuilder, thread: &mut Thread) {}
|
||||
pub fn load_self(instruction: InstructionFields, thread: &mut Thread) {}
|
||||
|
||||
pub fn add(instruction: InstructionBuilder, thread: &mut Thread) {
|
||||
pub fn add(instruction: InstructionFields, thread: &mut Thread) {
|
||||
let destination = instruction.a_field as usize;
|
||||
let left = instruction.b_field as usize;
|
||||
let left_is_constant = instruction.b_is_constant;
|
||||
@ -161,35 +154,81 @@ pub fn add(instruction: InstructionBuilder, thread: &mut Thread) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn subtract(instruction: InstructionBuilder, thread: &mut Thread) {}
|
||||
pub fn subtract(instruction: InstructionFields, thread: &mut Thread) {}
|
||||
|
||||
pub fn multiply(instruction: InstructionBuilder, thread: &mut Thread) {}
|
||||
pub fn multiply(instruction: InstructionFields, thread: &mut Thread) {}
|
||||
|
||||
pub fn divide(instruction: InstructionBuilder, thread: &mut Thread) {}
|
||||
pub fn divide(instruction: InstructionFields, thread: &mut Thread) {}
|
||||
|
||||
pub fn modulo(instruction: InstructionBuilder, thread: &mut Thread) {}
|
||||
pub fn modulo(instruction: InstructionFields, thread: &mut Thread) {}
|
||||
|
||||
pub fn test(instruction: InstructionBuilder, thread: &mut Thread) {}
|
||||
pub fn test(instruction: InstructionFields, thread: &mut Thread) {}
|
||||
|
||||
pub fn test_set(instruction: InstructionBuilder, thread: &mut Thread) {}
|
||||
pub fn test_set(instruction: InstructionFields, thread: &mut Thread) {}
|
||||
|
||||
pub fn equal(instruction: InstructionBuilder, thread: &mut Thread) {}
|
||||
pub fn equal(instruction: InstructionFields, thread: &mut Thread) {}
|
||||
|
||||
pub fn less(instruction: InstructionBuilder, thread: &mut Thread) {}
|
||||
pub fn less(instruction: InstructionFields, thread: &mut Thread) {
|
||||
let comparator = instruction.d_field;
|
||||
let left = instruction.b_field as usize;
|
||||
let left_type = instruction.b_type;
|
||||
let left_is_constant = instruction.b_is_constant;
|
||||
let right = instruction.c_field as usize;
|
||||
let right_type = instruction.c_type;
|
||||
let right_is_constant = instruction.c_is_constant;
|
||||
|
||||
pub fn less_equal(instruction: InstructionBuilder, thread: &mut Thread) {}
|
||||
match (left_type, right_type) {
|
||||
(TypeCode::INTEGER, TypeCode::INTEGER) => {
|
||||
let left_value = if left_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(left).as_integer().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(left).as_integer().unwrap_unchecked() }
|
||||
}
|
||||
} else {
|
||||
thread.get_integer_register(left)
|
||||
};
|
||||
let right_value = if right_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(right).as_integer().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(right).as_integer().unwrap_unchecked() }
|
||||
}
|
||||
} else {
|
||||
thread.get_integer_register(right)
|
||||
};
|
||||
let result = left_value < right_value;
|
||||
|
||||
pub fn negate(instruction: InstructionBuilder, thread: &mut Thread) {}
|
||||
if result == comparator {
|
||||
thread.current_frame_mut().ip += 1;
|
||||
}
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn not(instruction: InstructionBuilder, thread: &mut Thread) {}
|
||||
pub fn less_equal(instruction: InstructionFields, thread: &mut Thread) {}
|
||||
|
||||
pub fn jump(instruction: InstructionBuilder, thread: &mut Thread) {}
|
||||
pub fn negate(instruction: InstructionFields, thread: &mut Thread) {}
|
||||
|
||||
pub fn call(instruction: InstructionBuilder, thread: &mut Thread) {}
|
||||
pub fn not(instruction: InstructionFields, thread: &mut Thread) {}
|
||||
|
||||
pub fn call_native(instruction: InstructionBuilder, thread: &mut Thread) {}
|
||||
pub fn jump(instruction: InstructionFields, thread: &mut Thread) {
|
||||
let offset = instruction.b_field as usize;
|
||||
let is_positive = instruction.c_field != 0;
|
||||
|
||||
pub fn r#return(instruction: InstructionBuilder, thread: &mut Thread) {
|
||||
if is_positive {
|
||||
thread.current_frame_mut().ip += offset;
|
||||
} else {
|
||||
thread.current_frame_mut().ip -= offset;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn call(instruction: InstructionFields, thread: &mut Thread) {}
|
||||
|
||||
pub fn call_native(instruction: InstructionFields, thread: &mut Thread) {}
|
||||
|
||||
pub fn r#return(instruction: InstructionFields, thread: &mut Thread) {
|
||||
let should_return_value = instruction.b_field != 0;
|
||||
let return_register = instruction.c_field as usize;
|
||||
let return_type = instruction.b_type;
|
||||
|
@ -2,7 +2,7 @@ use std::{sync::Arc, thread::JoinHandle};
|
||||
|
||||
use tracing::{info, trace};
|
||||
|
||||
use crate::{Chunk, DustString, Span, Value, vm::CallFrame};
|
||||
use crate::{Chunk, ConcreteValue, DustString, Span, Value, vm::CallFrame};
|
||||
|
||||
use super::call_frame::{Pointer, Register};
|
||||
|
||||
@ -557,7 +557,7 @@ impl Thread {
|
||||
*register = Register::Value(value);
|
||||
}
|
||||
|
||||
pub fn get_constant(&self, constant_index: usize) -> &Value {
|
||||
pub fn get_constant(&self, constant_index: usize) -> &ConcreteValue {
|
||||
if cfg!(debug_assertions) {
|
||||
self.chunk.constants.get(constant_index).unwrap()
|
||||
} else {
|
||||
|
Loading…
x
Reference in New Issue
Block a user