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 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.
|
/// Representation of a Dust program or function.
|
||||||
///
|
///
|
||||||
@ -39,38 +39,22 @@ pub struct Chunk {
|
|||||||
|
|
||||||
pub(crate) instructions: Vec<Instruction>,
|
pub(crate) instructions: Vec<Instruction>,
|
||||||
pub(crate) positions: Vec<Span>,
|
pub(crate) positions: Vec<Span>,
|
||||||
pub(crate) constants: Vec<Value>,
|
pub(crate) constants: Vec<ConcreteValue>,
|
||||||
pub(crate) locals: Vec<Local>,
|
pub(crate) locals: Vec<Local>,
|
||||||
pub(crate) prototypes: Vec<Arc<Chunk>>,
|
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,
|
pub(crate) prototype_index: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Chunk {
|
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 {
|
pub fn as_function(&self) -> Function {
|
||||||
Function {
|
Function {
|
||||||
name: self.name.clone(),
|
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
|
//! 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.
|
//! runtime error, it is the compiler's fault and the error should be fixed here.
|
||||||
mod error;
|
mod error;
|
||||||
mod optimize;
|
|
||||||
mod parse_rule;
|
mod parse_rule;
|
||||||
mod type_checks;
|
mod type_checks;
|
||||||
|
|
||||||
@ -30,12 +29,10 @@ use type_checks::{check_math_type, check_math_types};
|
|||||||
|
|
||||||
use std::{mem::replace, sync::Arc};
|
use std::{mem::replace, sync::Arc};
|
||||||
|
|
||||||
use optimize::control_flow_register_consolidation;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Chunk, ConcreteValue, DustError, DustString, FunctionType, Instruction, Lexer, Local,
|
Chunk, ConcreteValue, DustError, DustString, FunctionType, Instruction, Lexer, Local,
|
||||||
NativeFunction, Operand, Operation, Scope, Span, Token, TokenKind, Type, Value,
|
NativeFunction, Operand, Operation, Scope, Span, Token, TokenKind, Type,
|
||||||
instruction::{CallNative, Close, Jump, LoadList, Point, Return, TypeCode},
|
instruction::{CallNative, Jump, LoadList, Point, Return, TypeCode},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Compiles the input and returns a chunk.
|
/// 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`]
|
/// Constants that have been compiled. These are assigned to the chunk when [`Compiler::finish`]
|
||||||
/// is called.
|
/// is called.
|
||||||
constants: Vec<Value>,
|
constants: Vec<ConcreteValue>,
|
||||||
|
|
||||||
/// Block-local variables and their types. The locals are assigned to the chunk when
|
/// Block-local variables and their types. The locals are assigned to the chunk when
|
||||||
/// [`Compiler::finish`] is called. The types are discarded after compilation.
|
/// [`Compiler::finish`] is called. The types are discarded after compilation.
|
||||||
@ -98,10 +95,6 @@ pub struct Compiler<'src> {
|
|||||||
/// [`Compiler::finish`] is called.
|
/// [`Compiler::finish`] is called.
|
||||||
prototypes: Vec<Arc<Chunk>>,
|
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 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.
|
/// the registers that are used for the function's arguments.
|
||||||
minimum_boolean_register: u16,
|
minimum_boolean_register: u16,
|
||||||
@ -175,7 +168,6 @@ impl<'src> Compiler<'src> {
|
|||||||
constants: Vec::new(),
|
constants: Vec::new(),
|
||||||
locals: Vec::new(),
|
locals: Vec::new(),
|
||||||
prototypes: Vec::new(),
|
prototypes: Vec::new(),
|
||||||
stack_size: 0,
|
|
||||||
lexer,
|
lexer,
|
||||||
minimum_byte_register: 0,
|
minimum_byte_register: 0,
|
||||||
minimum_boolean_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
|
/// 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.
|
/// 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 {
|
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
|
let (instructions, positions): (Vec<Instruction>, Vec<Span>) = self
|
||||||
.instructions
|
.instructions
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -253,7 +253,14 @@ impl<'src> Compiler<'src> {
|
|||||||
constants: self.constants,
|
constants: self.constants,
|
||||||
locals,
|
locals,
|
||||||
prototypes: self.prototypes,
|
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,
|
prototype_index: self.prototype_index,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -411,12 +418,11 @@ impl<'src> Compiler<'src> {
|
|||||||
.rev()
|
.rev()
|
||||||
.find_map(|(index, (local, _))| {
|
.find_map(|(index, (local, _))| {
|
||||||
let constant = self.constants.get(local.identifier_index as usize)?;
|
let constant = self.constants.get(local.identifier_index as usize)?;
|
||||||
let identifier =
|
let identifier = if let ConcreteValue::String(identifier) = constant {
|
||||||
if let Value::Concrete(ConcreteValue::String(identifier)) = constant {
|
identifier
|
||||||
identifier
|
} else {
|
||||||
} else {
|
return None;
|
||||||
return None;
|
};
|
||||||
};
|
|
||||||
|
|
||||||
if identifier == identifier_text {
|
if identifier == identifier_text {
|
||||||
Some(index as u16)
|
Some(index as u16)
|
||||||
@ -440,7 +446,7 @@ impl<'src> Compiler<'src> {
|
|||||||
) -> (u16, u16) {
|
) -> (u16, u16) {
|
||||||
info!("Declaring local {identifier}");
|
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 identifier_index = self.push_or_get_constant(identifier);
|
||||||
let local_index = self.locals.len() as u16;
|
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
|
if let Some(index) = self
|
||||||
.constants
|
.constants
|
||||||
.iter()
|
.iter()
|
||||||
@ -592,12 +598,6 @@ impl<'src> Compiler<'src> {
|
|||||||
position.to_string()
|
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));
|
self.instructions.push((instruction, r#type, position));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -607,7 +607,7 @@ impl<'src> Compiler<'src> {
|
|||||||
position: Span,
|
position: Span,
|
||||||
) -> Result<(), CompileError> {
|
) -> Result<(), CompileError> {
|
||||||
let r#type = constant.r#type();
|
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 {
|
let destination = match r#type {
|
||||||
Type::Character => self.next_character_register(),
|
Type::Character => self.next_character_register(),
|
||||||
Type::Float => self.next_float_register(),
|
Type::Float => self.next_float_register(),
|
||||||
@ -615,7 +615,8 @@ impl<'src> Compiler<'src> {
|
|||||||
Type::String => self.next_string_register(),
|
Type::String => self.next_string_register(),
|
||||||
_ => todo!(),
|
_ => 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);
|
self.emit_instruction(load_constant, r#type, position);
|
||||||
|
|
||||||
@ -1420,7 +1421,7 @@ impl<'src> Compiler<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let if_block_end = self.instructions.len();
|
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();
|
let if_block_type = self.get_last_instruction_type();
|
||||||
|
|
||||||
if let Token::Else = self.current_token {
|
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_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();
|
let else_block_type = self.get_last_instruction_type();
|
||||||
|
|
||||||
if let Err(conflict) = if_block_type.check(&else_block_type) {
|
if let Err(conflict) = if_block_type.check(&else_block_type) {
|
||||||
@ -1455,16 +1456,17 @@ impl<'src> Compiler<'src> {
|
|||||||
match else_block_distance {
|
match else_block_distance {
|
||||||
0 => {}
|
0 => {}
|
||||||
1 => {
|
1 => {
|
||||||
if let Some(Operation::LOAD_BOOLEAN | Operation::LOAD_CONSTANT) =
|
if let Some([Operation::LOAD_BOOLEAN | Operation::LOAD_CONSTANT, _]) =
|
||||||
self.get_last_operation()
|
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);
|
loader.set_c_field(true as u16);
|
||||||
} else {
|
} else {
|
||||||
if_block_distance += 1;
|
if_block_distance += 1;
|
||||||
let jump = Instruction::from(Jump {
|
let jump = Instruction::from(Jump {
|
||||||
offset: else_block_distance,
|
offset: else_block_distance as u16,
|
||||||
is_positive: true,
|
is_positive: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1475,7 +1477,7 @@ impl<'src> Compiler<'src> {
|
|||||||
2.. => {
|
2.. => {
|
||||||
if_block_distance += 1;
|
if_block_distance += 1;
|
||||||
let jump = Instruction::from(Jump {
|
let jump = Instruction::from(Jump {
|
||||||
offset: else_block_distance,
|
offset: else_block_distance as u16,
|
||||||
is_positive: true,
|
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
|
self.instructions
|
||||||
.insert(if_block_start, (jump, Type::None, if_block_start_position));
|
.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(())
|
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 std::fmt::{self, Display, Formatter};
|
||||||
|
|
||||||
use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode};
|
use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
|
||||||
|
|
||||||
pub struct Add {
|
pub struct Add {
|
||||||
pub destination: u16,
|
pub destination: u16,
|
||||||
@ -36,7 +36,7 @@ impl From<Add> for Instruction {
|
|||||||
let b_type = add.left_type;
|
let b_type = add.left_type;
|
||||||
let c_type = add.right_type;
|
let c_type = add.right_type;
|
||||||
|
|
||||||
InstructionBuilder {
|
InstructionFields {
|
||||||
operation,
|
operation,
|
||||||
a_field,
|
a_field,
|
||||||
b_field,
|
b_field,
|
||||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
|
|
||||||
use crate::{Instruction, Operation};
|
use crate::{Instruction, Operation};
|
||||||
|
|
||||||
use super::InstructionBuilder;
|
use super::InstructionFields;
|
||||||
|
|
||||||
pub struct Call {
|
pub struct Call {
|
||||||
pub destination: u16,
|
pub destination: u16,
|
||||||
@ -34,7 +34,7 @@ impl From<Call> for Instruction {
|
|||||||
let c_field = call.argument_count;
|
let c_field = call.argument_count;
|
||||||
let d_field = call.is_recursive;
|
let d_field = call.is_recursive;
|
||||||
|
|
||||||
InstructionBuilder {
|
InstructionFields {
|
||||||
operation: Operation::CALL,
|
operation: Operation::CALL,
|
||||||
a_field,
|
a_field,
|
||||||
b_field,
|
b_field,
|
||||||
|
@ -2,7 +2,7 @@ use std::fmt::Display;
|
|||||||
|
|
||||||
use crate::{Instruction, NativeFunction, Operation};
|
use crate::{Instruction, NativeFunction, Operation};
|
||||||
|
|
||||||
use super::InstructionBuilder;
|
use super::InstructionFields;
|
||||||
|
|
||||||
pub struct CallNative {
|
pub struct CallNative {
|
||||||
pub destination: u16,
|
pub destination: u16,
|
||||||
@ -30,7 +30,7 @@ impl From<CallNative> for Instruction {
|
|||||||
let b_field = call_native.function as u16;
|
let b_field = call_native.function as u16;
|
||||||
let c_field = call_native.argument_count;
|
let c_field = call_native.argument_count;
|
||||||
|
|
||||||
InstructionBuilder {
|
InstructionFields {
|
||||||
operation,
|
operation,
|
||||||
a_field,
|
a_field,
|
||||||
b_field,
|
b_field,
|
||||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
|
|
||||||
use crate::{Instruction, Operation};
|
use crate::{Instruction, Operation};
|
||||||
|
|
||||||
use super::InstructionBuilder;
|
use super::InstructionFields;
|
||||||
|
|
||||||
pub struct Close {
|
pub struct Close {
|
||||||
pub from: u16,
|
pub from: u16,
|
||||||
@ -24,7 +24,7 @@ impl From<Close> for Instruction {
|
|||||||
let b_field = close.from;
|
let b_field = close.from;
|
||||||
let c_field = close.to;
|
let c_field = close.to;
|
||||||
|
|
||||||
InstructionBuilder {
|
InstructionFields {
|
||||||
operation,
|
operation,
|
||||||
b_field,
|
b_field,
|
||||||
c_field,
|
c_field,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
|
|
||||||
use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode};
|
use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
|
||||||
|
|
||||||
pub struct Divide {
|
pub struct Divide {
|
||||||
pub destination: u16,
|
pub destination: u16,
|
||||||
@ -36,7 +36,7 @@ impl From<Divide> for Instruction {
|
|||||||
let b_type = divide.left_type;
|
let b_type = divide.left_type;
|
||||||
let c_type = divide.right_type;
|
let c_type = divide.right_type;
|
||||||
|
|
||||||
InstructionBuilder {
|
InstructionFields {
|
||||||
operation,
|
operation,
|
||||||
a_field,
|
a_field,
|
||||||
b_field,
|
b_field,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
|
|
||||||
use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode};
|
use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
|
||||||
|
|
||||||
pub struct Equal {
|
pub struct Equal {
|
||||||
pub comparator: bool,
|
pub comparator: bool,
|
||||||
@ -36,7 +36,7 @@ impl From<Equal> for Instruction {
|
|||||||
let b_type = equal_bool.left_type;
|
let b_type = equal_bool.left_type;
|
||||||
let c_type = equal_bool.right_type;
|
let c_type = equal_bool.right_type;
|
||||||
|
|
||||||
InstructionBuilder {
|
InstructionFields {
|
||||||
operation,
|
operation,
|
||||||
b_field,
|
b_field,
|
||||||
c_field,
|
c_field,
|
||||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
|
|
||||||
use crate::{Instruction, Operation};
|
use crate::{Instruction, Operation};
|
||||||
|
|
||||||
use super::InstructionBuilder;
|
use super::InstructionFields;
|
||||||
|
|
||||||
pub struct Jump {
|
pub struct Jump {
|
||||||
pub offset: u16,
|
pub offset: u16,
|
||||||
@ -24,7 +24,7 @@ impl From<Jump> for Instruction {
|
|||||||
let b_field = jump.offset;
|
let b_field = jump.offset;
|
||||||
let c_field = jump.is_positive as u16;
|
let c_field = jump.is_positive as u16;
|
||||||
|
|
||||||
InstructionBuilder {
|
InstructionFields {
|
||||||
operation,
|
operation,
|
||||||
b_field,
|
b_field,
|
||||||
c_field,
|
c_field,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
|
|
||||||
use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode};
|
use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
|
||||||
|
|
||||||
pub struct Less {
|
pub struct Less {
|
||||||
pub comparator: bool,
|
pub comparator: bool,
|
||||||
@ -36,7 +36,7 @@ impl From<Less> for Instruction {
|
|||||||
let b_type = less.left_type;
|
let b_type = less.left_type;
|
||||||
let c_type = less.right_type;
|
let c_type = less.right_type;
|
||||||
|
|
||||||
InstructionBuilder {
|
InstructionFields {
|
||||||
operation,
|
operation,
|
||||||
b_field,
|
b_field,
|
||||||
c_field,
|
c_field,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
|
|
||||||
use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode};
|
use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
|
||||||
|
|
||||||
pub struct LessEqual {
|
pub struct LessEqual {
|
||||||
pub comparator: bool,
|
pub comparator: bool,
|
||||||
@ -36,7 +36,7 @@ impl From<LessEqual> for Instruction {
|
|||||||
let b_type = less_equal_byte.left_type;
|
let b_type = less_equal_byte.left_type;
|
||||||
let c_type = less_equal_byte.right_type;
|
let c_type = less_equal_byte.right_type;
|
||||||
|
|
||||||
InstructionBuilder {
|
InstructionFields {
|
||||||
operation,
|
operation,
|
||||||
b_field,
|
b_field,
|
||||||
c_field,
|
c_field,
|
||||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
|
|
||||||
use crate::{Instruction, Operation};
|
use crate::{Instruction, Operation};
|
||||||
|
|
||||||
use super::InstructionBuilder;
|
use super::InstructionFields;
|
||||||
|
|
||||||
pub struct LoadBoolean {
|
pub struct LoadBoolean {
|
||||||
pub destination: u16,
|
pub destination: u16,
|
||||||
@ -27,7 +27,7 @@ impl From<LoadBoolean> for Instruction {
|
|||||||
let b_field = load_boolean.value as u16;
|
let b_field = load_boolean.value as u16;
|
||||||
let c_field = load_boolean.jump_next as u16;
|
let c_field = load_boolean.jump_next as u16;
|
||||||
|
|
||||||
InstructionBuilder {
|
InstructionFields {
|
||||||
operation,
|
operation,
|
||||||
a_field,
|
a_field,
|
||||||
b_field,
|
b_field,
|
||||||
|
@ -2,11 +2,12 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
|
|
||||||
use crate::{Instruction, Operation};
|
use crate::{Instruction, Operation};
|
||||||
|
|
||||||
use super::InstructionBuilder;
|
use super::{InstructionFields, TypeCode};
|
||||||
|
|
||||||
pub struct LoadConstant {
|
pub struct LoadConstant {
|
||||||
pub destination: u16,
|
pub destination: u16,
|
||||||
pub constant_index: u16,
|
pub constant_index: u16,
|
||||||
|
pub constant_type: TypeCode,
|
||||||
pub jump_next: bool,
|
pub jump_next: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -14,11 +15,13 @@ impl From<Instruction> for LoadConstant {
|
|||||||
fn from(instruction: Instruction) -> Self {
|
fn from(instruction: Instruction) -> Self {
|
||||||
let destination = instruction.a_field();
|
let destination = instruction.a_field();
|
||||||
let constant_index = instruction.b_field();
|
let constant_index = instruction.b_field();
|
||||||
|
let constant_type = instruction.b_type();
|
||||||
let jump_next = instruction.c_field() != 0;
|
let jump_next = instruction.c_field() != 0;
|
||||||
|
|
||||||
LoadConstant {
|
LoadConstant {
|
||||||
destination,
|
destination,
|
||||||
constant_index,
|
constant_index,
|
||||||
|
constant_type,
|
||||||
jump_next,
|
jump_next,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -26,10 +29,11 @@ impl From<Instruction> for LoadConstant {
|
|||||||
|
|
||||||
impl From<LoadConstant> for Instruction {
|
impl From<LoadConstant> for Instruction {
|
||||||
fn from(load_constant: LoadConstant) -> Self {
|
fn from(load_constant: LoadConstant) -> Self {
|
||||||
InstructionBuilder {
|
InstructionFields {
|
||||||
operation: Operation::LOAD_CONSTANT,
|
operation: Operation::LOAD_CONSTANT,
|
||||||
a_field: load_constant.destination,
|
a_field: load_constant.destination,
|
||||||
b_field: load_constant.constant_index,
|
b_field: load_constant.constant_index,
|
||||||
|
b_type: load_constant.constant_type,
|
||||||
c_field: load_constant.jump_next as u16,
|
c_field: load_constant.jump_next as u16,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
@ -42,10 +46,21 @@ impl Display for LoadConstant {
|
|||||||
let LoadConstant {
|
let LoadConstant {
|
||||||
destination,
|
destination,
|
||||||
constant_index,
|
constant_index,
|
||||||
|
constant_type,
|
||||||
jump_next,
|
jump_next,
|
||||||
} = self;
|
} = 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 {
|
if *jump_next {
|
||||||
write!(f, " JUMP +1")?;
|
write!(f, " JUMP +1")?;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
|
|
||||||
use super::{Instruction, InstructionBuilder, Operation};
|
use super::{Instruction, InstructionFields, Operation};
|
||||||
|
|
||||||
pub struct LoadFunction {
|
pub struct LoadFunction {
|
||||||
pub destination: u16,
|
pub destination: u16,
|
||||||
@ -24,7 +24,7 @@ impl From<Instruction> for LoadFunction {
|
|||||||
|
|
||||||
impl From<LoadFunction> for Instruction {
|
impl From<LoadFunction> for Instruction {
|
||||||
fn from(load_function: LoadFunction) -> Self {
|
fn from(load_function: LoadFunction) -> Self {
|
||||||
InstructionBuilder {
|
InstructionFields {
|
||||||
operation: Operation::LOAD_FUNCTION,
|
operation: Operation::LOAD_FUNCTION,
|
||||||
a_field: load_function.destination,
|
a_field: load_function.destination,
|
||||||
b_field: load_function.prototype_index,
|
b_field: load_function.prototype_index,
|
||||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
|
|
||||||
use crate::{Instruction, Operation};
|
use crate::{Instruction, Operation};
|
||||||
|
|
||||||
use super::InstructionBuilder;
|
use super::InstructionFields;
|
||||||
|
|
||||||
pub struct LoadList {
|
pub struct LoadList {
|
||||||
pub destination: u16,
|
pub destination: u16,
|
||||||
@ -26,7 +26,7 @@ impl From<Instruction> for LoadList {
|
|||||||
|
|
||||||
impl From<LoadList> for Instruction {
|
impl From<LoadList> for Instruction {
|
||||||
fn from(load_list: LoadList) -> Self {
|
fn from(load_list: LoadList) -> Self {
|
||||||
InstructionBuilder {
|
InstructionFields {
|
||||||
operation: Operation::LOAD_LIST,
|
operation: Operation::LOAD_LIST,
|
||||||
a_field: load_list.destination,
|
a_field: load_list.destination,
|
||||||
b_field: load_list.start_register,
|
b_field: load_list.start_register,
|
||||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
|
|
||||||
use crate::{Instruction, Operation};
|
use crate::{Instruction, Operation};
|
||||||
|
|
||||||
use super::InstructionBuilder;
|
use super::InstructionFields;
|
||||||
|
|
||||||
pub struct LoadSelf {
|
pub struct LoadSelf {
|
||||||
pub destination: u16,
|
pub destination: u16,
|
||||||
@ -23,7 +23,7 @@ impl From<Instruction> for LoadSelf {
|
|||||||
|
|
||||||
impl From<LoadSelf> for Instruction {
|
impl From<LoadSelf> for Instruction {
|
||||||
fn from(load_self: LoadSelf) -> Self {
|
fn from(load_self: LoadSelf) -> Self {
|
||||||
InstructionBuilder {
|
InstructionFields {
|
||||||
operation: Operation::LOAD_SELF,
|
operation: Operation::LOAD_SELF,
|
||||||
a_field: load_self.destination,
|
a_field: load_self.destination,
|
||||||
c_field: load_self.jump_next as u16,
|
c_field: load_self.jump_next as u16,
|
||||||
|
@ -151,7 +151,7 @@ pub use type_code::TypeCode;
|
|||||||
use crate::NativeFunction;
|
use crate::NativeFunction;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub struct InstructionBuilder {
|
pub struct InstructionFields {
|
||||||
pub operation: Operation,
|
pub operation: Operation,
|
||||||
pub a_field: u16,
|
pub a_field: u16,
|
||||||
pub b_field: u16,
|
pub b_field: u16,
|
||||||
@ -163,7 +163,7 @@ pub struct InstructionBuilder {
|
|||||||
pub c_type: TypeCode,
|
pub c_type: TypeCode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InstructionBuilder {
|
impl InstructionFields {
|
||||||
pub fn build(self) -> Instruction {
|
pub fn build(self) -> Instruction {
|
||||||
let bits = ((self.operation.0 as u64) << 57)
|
let bits = ((self.operation.0 as u64) << 57)
|
||||||
| ((self.b_is_constant as u64) << 56)
|
| ((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 {
|
fn from(instruction: &Instruction) -> Self {
|
||||||
InstructionBuilder {
|
InstructionFields {
|
||||||
operation: instruction.operation(),
|
operation: instruction.operation(),
|
||||||
a_field: instruction.a_field(),
|
a_field: instruction.a_field(),
|
||||||
b_field: instruction.b_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 {
|
fn default() -> Self {
|
||||||
InstructionBuilder {
|
InstructionFields {
|
||||||
operation: Operation::POINT,
|
operation: Operation::POINT,
|
||||||
a_field: 0,
|
a_field: 0,
|
||||||
b_field: 0,
|
b_field: 0,
|
||||||
@ -261,15 +261,21 @@ impl Instruction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_a_field(&mut self, bits: u16) {
|
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) {
|
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) {
|
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 {
|
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 {
|
Instruction::from(LoadConstant {
|
||||||
destination,
|
destination,
|
||||||
constant_index,
|
constant_index,
|
||||||
|
constant_type,
|
||||||
jump_next,
|
jump_next,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
|
|
||||||
use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode};
|
use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
|
||||||
|
|
||||||
pub struct Modulo {
|
pub struct Modulo {
|
||||||
pub destination: u16,
|
pub destination: u16,
|
||||||
@ -36,7 +36,7 @@ impl From<Modulo> for Instruction {
|
|||||||
let b_type = modulo.left_type;
|
let b_type = modulo.left_type;
|
||||||
let c_type = modulo.right_type;
|
let c_type = modulo.right_type;
|
||||||
|
|
||||||
InstructionBuilder {
|
InstructionFields {
|
||||||
operation,
|
operation,
|
||||||
a_field,
|
a_field,
|
||||||
b_field,
|
b_field,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
|
|
||||||
use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode};
|
use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
|
||||||
|
|
||||||
pub struct Multiply {
|
pub struct Multiply {
|
||||||
pub destination: u16,
|
pub destination: u16,
|
||||||
@ -36,7 +36,7 @@ impl From<Multiply> for Instruction {
|
|||||||
let b_type = multiply.left_type;
|
let b_type = multiply.left_type;
|
||||||
let c_type = multiply.right_type;
|
let c_type = multiply.right_type;
|
||||||
|
|
||||||
InstructionBuilder {
|
InstructionFields {
|
||||||
operation,
|
operation,
|
||||||
a_field,
|
a_field,
|
||||||
b_field,
|
b_field,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
|
|
||||||
use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode};
|
use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
|
||||||
|
|
||||||
pub struct Negate {
|
pub struct Negate {
|
||||||
pub destination: u16,
|
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_field, b_is_constant) = negate.argument.as_index_and_constant_flag();
|
||||||
let b_type = negate.argument_type;
|
let b_type = negate.argument_type;
|
||||||
|
|
||||||
InstructionBuilder {
|
InstructionFields {
|
||||||
operation,
|
operation,
|
||||||
a_field,
|
a_field,
|
||||||
b_field,
|
b_field,
|
||||||
|
@ -2,7 +2,7 @@ use std::fmt::Display;
|
|||||||
|
|
||||||
use crate::{Instruction, Operand, Operation};
|
use crate::{Instruction, Operand, Operation};
|
||||||
|
|
||||||
use super::InstructionBuilder;
|
use super::InstructionFields;
|
||||||
|
|
||||||
pub struct Not {
|
pub struct Not {
|
||||||
pub destination: u16,
|
pub destination: u16,
|
||||||
@ -27,7 +27,7 @@ impl From<Not> for Instruction {
|
|||||||
let a_field = not.destination;
|
let a_field = not.destination;
|
||||||
let (b_field, b_is_constant) = not.argument.as_index_and_constant_flag();
|
let (b_field, b_is_constant) = not.argument.as_index_and_constant_flag();
|
||||||
|
|
||||||
InstructionBuilder {
|
InstructionFields {
|
||||||
operation,
|
operation,
|
||||||
a_field,
|
a_field,
|
||||||
b_field,
|
b_field,
|
||||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
|
|
||||||
use crate::{Instruction, Operation};
|
use crate::{Instruction, Operation};
|
||||||
|
|
||||||
use super::{InstructionBuilder, Operand};
|
use super::{InstructionFields, Operand};
|
||||||
|
|
||||||
pub struct Point {
|
pub struct Point {
|
||||||
pub destination: u16,
|
pub destination: u16,
|
||||||
@ -24,7 +24,7 @@ impl From<Point> for Instruction {
|
|||||||
let a_field = r#move.destination;
|
let a_field = r#move.destination;
|
||||||
let (b_field, b_is_constant) = r#move.to.as_index_and_constant_flag();
|
let (b_field, b_is_constant) = r#move.to.as_index_and_constant_flag();
|
||||||
|
|
||||||
InstructionBuilder {
|
InstructionFields {
|
||||||
operation,
|
operation,
|
||||||
a_field,
|
a_field,
|
||||||
b_field,
|
b_field,
|
||||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
|
|
||||||
use crate::{Instruction, Operation};
|
use crate::{Instruction, Operation};
|
||||||
|
|
||||||
use super::{InstructionBuilder, TypeCode};
|
use super::{InstructionFields, TypeCode};
|
||||||
|
|
||||||
pub struct Return {
|
pub struct Return {
|
||||||
pub should_return_value: bool,
|
pub should_return_value: bool,
|
||||||
@ -31,7 +31,7 @@ impl From<Return> for Instruction {
|
|||||||
let b_type = r#return.r#type;
|
let b_type = r#return.r#type;
|
||||||
let c_field = r#return.return_register;
|
let c_field = r#return.return_register;
|
||||||
|
|
||||||
InstructionBuilder {
|
InstructionFields {
|
||||||
operation,
|
operation,
|
||||||
b_field,
|
b_field,
|
||||||
b_type,
|
b_type,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
|
|
||||||
use super::{Instruction, InstructionBuilder, Operand, Operation, TypeCode};
|
use super::{Instruction, InstructionFields, Operand, Operation, TypeCode};
|
||||||
|
|
||||||
pub struct Subtract {
|
pub struct Subtract {
|
||||||
pub destination: u16,
|
pub destination: u16,
|
||||||
@ -36,7 +36,7 @@ impl From<Subtract> for Instruction {
|
|||||||
let b_type = subtract.left_type;
|
let b_type = subtract.left_type;
|
||||||
let c_type = subtract.right_type;
|
let c_type = subtract.right_type;
|
||||||
|
|
||||||
InstructionBuilder {
|
InstructionFields {
|
||||||
operation,
|
operation,
|
||||||
a_field,
|
a_field,
|
||||||
b_field,
|
b_field,
|
||||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
|
|
||||||
use crate::{Instruction, Operation};
|
use crate::{Instruction, Operation};
|
||||||
|
|
||||||
use super::InstructionBuilder;
|
use super::InstructionFields;
|
||||||
|
|
||||||
pub struct Test {
|
pub struct Test {
|
||||||
pub operand_register: u16,
|
pub operand_register: u16,
|
||||||
@ -26,7 +26,7 @@ impl From<Test> for Instruction {
|
|||||||
let b_field = test.operand_register;
|
let b_field = test.operand_register;
|
||||||
let c_field = test.test_value as u16;
|
let c_field = test.test_value as u16;
|
||||||
|
|
||||||
InstructionBuilder {
|
InstructionFields {
|
||||||
operation: Operation::TEST,
|
operation: Operation::TEST,
|
||||||
b_field,
|
b_field,
|
||||||
c_field,
|
c_field,
|
||||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
|
|
||||||
use crate::{Instruction, Operand, Operation};
|
use crate::{Instruction, Operand, Operation};
|
||||||
|
|
||||||
use super::InstructionBuilder;
|
use super::InstructionFields;
|
||||||
|
|
||||||
pub struct TestSet {
|
pub struct TestSet {
|
||||||
pub destination: u16,
|
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 (b_field, b_is_constant) = test_set.argument.as_index_and_constant_flag();
|
||||||
let c_field = test_set.test_value as u16;
|
let c_field = test_set.test_value as u16;
|
||||||
|
|
||||||
InstructionBuilder {
|
InstructionFields {
|
||||||
operation,
|
operation,
|
||||||
a_field,
|
a_field,
|
||||||
b_field,
|
b_field,
|
||||||
|
@ -35,6 +35,46 @@ impl ConcreteValue {
|
|||||||
ConcreteValue::String(to_string.into())
|
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> {
|
pub fn as_string(&self) -> Option<&DustString> {
|
||||||
if let ConcreteValue::String(string) = self {
|
if let ConcreteValue::String(string) = self {
|
||||||
Some(string)
|
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 {
|
pub fn display(&self) -> DustString {
|
||||||
DustString::from(self.to_string())
|
DustString::from(self.to_string())
|
||||||
}
|
}
|
||||||
@ -147,7 +203,7 @@ impl ConcreteValue {
|
|||||||
return Err(ValueError::CannotMultiply(
|
return Err(ValueError::CannotMultiply(
|
||||||
self.clone().to_value(),
|
self.clone().to_value(),
|
||||||
other.clone().to_value(),
|
other.clone().to_value(),
|
||||||
))
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -165,7 +221,7 @@ impl ConcreteValue {
|
|||||||
return Err(ValueError::CannotMultiply(
|
return Err(ValueError::CannotMultiply(
|
||||||
self.clone().to_value(),
|
self.clone().to_value(),
|
||||||
other.clone().to_value(),
|
other.clone().to_value(),
|
||||||
))
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -185,7 +241,7 @@ impl ConcreteValue {
|
|||||||
return Err(ValueError::CannotMultiply(
|
return Err(ValueError::CannotMultiply(
|
||||||
self.clone().to_value(),
|
self.clone().to_value(),
|
||||||
other.clone().to_value(),
|
other.clone().to_value(),
|
||||||
))
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -255,7 +311,7 @@ impl ConcreteValue {
|
|||||||
return Err(ValueError::CannotCompare(
|
return Err(ValueError::CannotCompare(
|
||||||
self.clone().to_value(),
|
self.clone().to_value(),
|
||||||
other.clone().to_value(),
|
other.clone().to_value(),
|
||||||
))
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -278,7 +334,7 @@ impl ConcreteValue {
|
|||||||
return Err(ValueError::CannotCompare(
|
return Err(ValueError::CannotCompare(
|
||||||
self.clone().to_value(),
|
self.clone().to_value(),
|
||||||
other.clone().to_value(),
|
other.clone().to_value(),
|
||||||
))
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,16 +1,9 @@
|
|||||||
use tracing::trace;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AbstractList, ConcreteValue, Instruction, Operand, Type, Value,
|
Instruction, Value,
|
||||||
instruction::{
|
instruction::{InstructionFields, TypeCode},
|
||||||
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,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{Pointer, Register, thread::Thread};
|
use super::thread::Thread;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ActionSequence {
|
pub struct ActionSequence {
|
||||||
@ -34,20 +27,20 @@ impl ActionSequence {
|
|||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub struct Action {
|
pub struct Action {
|
||||||
pub logic: RunnerLogic,
|
pub logic: RunnerLogic,
|
||||||
pub instruction: InstructionBuilder,
|
pub instruction: InstructionFields,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&Instruction> for Action {
|
impl From<&Instruction> for Action {
|
||||||
fn from(instruction: &Instruction) -> Self {
|
fn from(instruction: &Instruction) -> Self {
|
||||||
let operation = instruction.operation();
|
let operation = instruction.operation();
|
||||||
let logic = RUNNER_LOGIC_TABLE[operation.0 as usize];
|
let logic = RUNNER_LOGIC_TABLE[operation.0 as usize];
|
||||||
let instruction = InstructionBuilder::from(instruction);
|
let instruction = InstructionFields::from(instruction);
|
||||||
|
|
||||||
Action { logic, 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] = [
|
pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 23] = [
|
||||||
point,
|
point,
|
||||||
@ -75,21 +68,21 @@ pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 23] = [
|
|||||||
r#return,
|
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 destination = instruction.a_field as usize;
|
||||||
let left = instruction.b_field as usize;
|
let left = instruction.b_field as usize;
|
||||||
let left_is_constant = instruction.b_is_constant;
|
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 should_return_value = instruction.b_field != 0;
|
||||||
let return_register = instruction.c_field as usize;
|
let return_register = instruction.c_field as usize;
|
||||||
let return_type = instruction.b_type;
|
let return_type = instruction.b_type;
|
||||||
|
@ -2,7 +2,7 @@ use std::{sync::Arc, thread::JoinHandle};
|
|||||||
|
|
||||||
use tracing::{info, trace};
|
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};
|
use super::call_frame::{Pointer, Register};
|
||||||
|
|
||||||
@ -557,7 +557,7 @@ impl Thread {
|
|||||||
*register = Register::Value(value);
|
*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) {
|
if cfg!(debug_assertions) {
|
||||||
self.chunk.constants.get(constant_index).unwrap()
|
self.chunk.constants.get(constant_index).unwrap()
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user