1
0

Continue refactor; Condense registers in logic chains

This commit is contained in:
Jeff 2024-12-09 08:27:45 -05:00
parent a9e867aaab
commit 98a7b7984a
7 changed files with 86 additions and 69 deletions

View File

@ -610,12 +610,13 @@ impl<'src> Compiler<'src> {
&mut self,
instruction: &Instruction,
) -> Result<(Argument, bool), CompileError> {
let argument = instruction.destination_as_argument().ok_or_else(|| {
CompileError::ExpectedExpression {
found: self.previous_token.to_owned(),
position: self.previous_position,
}
})?;
let argument =
instruction
.as_argument()
.ok_or_else(|| CompileError::ExpectedExpression {
found: self.previous_token.to_owned(),
position: self.previous_position,
})?;
let push_back = matches!(argument, Argument::Register(_));
Ok((argument, push_back))
@ -867,7 +868,20 @@ impl<'src> Compiler<'src> {
self.get_last_operations(),
Some([Operation::Test, Operation::Jump, _])
);
let (left_instruction, left_type, left_position) = self.pop_last_instruction()?;
let (mut left_instruction, left_type, left_position) = self.pop_last_instruction()?;
if is_logic_chain {
let destination = self
.instructions
.iter()
.rev()
.nth(2)
.map_or(0, |(instruction, _, _)| instruction.a);
left_instruction.a = destination;
}
let jump_index = self.instructions.len().saturating_sub(1);
let mut jump_distance = if is_logic_chain {
self.instructions.pop().map_or(0, |(jump, _, _)| {
@ -886,13 +900,10 @@ impl<'src> Compiler<'src> {
});
}
let (argument, push_back) = self.handle_binary_argument(&left_instruction)?;
let is_local = left_instruction.operation() == Operation::GetLocal;
let (left, _) = self.handle_binary_argument(&left_instruction)?;
if push_back || is_local {
self.instructions
.push((left_instruction, left_type.clone(), left_position));
}
self.instructions
.push((left_instruction, left_type.clone(), left_position));
let operator = self.current_token;
let operator_position = self.current_position;
@ -908,16 +919,16 @@ impl<'src> Compiler<'src> {
})
}
};
let test = Instruction::from(Test {
argument,
test_value: test_boolean,
});
let test = Instruction::test(left, test_boolean);
self.advance()?;
self.emit_instruction(test, Type::None, operator_position);
self.emit_instruction(Instruction::jump(1, true), Type::None, operator_position);
self.parse_sub_expression(&rule.precedence)?;
let (mut right_instruction, _, _) = self.instructions.last_mut().unwrap();
right_instruction.a = left_instruction.a;
if is_logic_chain {
let expression_length = self.instructions.len() - jump_index - 1;
jump_distance += expression_length as u8;
@ -992,7 +1003,7 @@ impl<'src> Compiler<'src> {
});
self.emit_instruction(set_local, Type::None, start_position);
optimize_set_local(self);
optimize_set_local(self)?;
return Ok(());
}
@ -1092,7 +1103,7 @@ impl<'src> Compiler<'src> {
self.parse_expression()?;
if let Some((instruction, _, _)) = self.instructions.last() {
let argument = match instruction.destination_as_argument() {
let argument = match instruction.as_argument() {
Some(argument) => argument,
None => {
return Err(CompileError::ExpectedExpression {
@ -1323,7 +1334,18 @@ impl<'src> Compiler<'src> {
}
fn parse_sub_expression(&mut self, precedence: &Precedence) -> Result<(), CompileError> {
self.parse(precedence.increment())
self.parse(precedence.increment())?;
let expression_type = self.get_last_instruction_type();
if expression_type == Type::None || self.instructions.is_empty() {
return Err(CompileError::ExpectedExpression {
found: self.previous_token.to_owned(),
position: self.current_position,
});
}
Ok(())
}
fn parse_return_statement(&mut self) -> Result<(), CompileError> {
@ -1572,12 +1594,13 @@ impl<'src> Compiler<'src> {
});
}
let function = last_instruction.destination_as_argument().ok_or_else(|| {
CompileError::ExpectedExpression {
found: self.previous_token.to_owned(),
position: self.previous_position,
}
})?;
let function =
last_instruction
.as_argument()
.ok_or_else(|| CompileError::ExpectedExpression {
found: self.previous_token.to_owned(),
position: self.previous_position,
})?;
let register_type = self.get_register_type(function.index())?;
let function_return_type = match register_type {
Type::Function(function_type) => function_type.return_type,

View File

@ -1,7 +1,5 @@
//! Tools used by the compiler to optimize a chunk's bytecode.
use smallvec::SmallVec;
use crate::{instruction::SetLocal, CompileError, Compiler, Instruction, Operation, Span, Type};
fn get_last_operations<const COUNT: usize>(

View File

@ -40,15 +40,15 @@
//! write, this ensures that the instruction has the correct flags to represent the arguments.
//!
//! ```
//! # use dust_lang::instruction::{Instruction, Add, u8, Argument};
//! # use dust_lang::instruction::{Instruction, Add, Argument};
//! let add_1 = Instruction::add(
//! u8::Register(0),
//! Argument::Local(1),
//! 0,
//! Argument::Register(1),
//! Argument::Constant(2)
//! );
//! let add_2 = Instruction::from(Add {
//! destination: u8::Register(0),
//! left: Argument::Local(1),
//! destination: 0,
//! left: Argument::Register(1),
//! right: Argument::Constant(2),
//! });
//!
@ -57,21 +57,20 @@
//!
//! ## Reading Instructions
//!
//! To read an instruction, check its `operation` field, then convert the instruction to the struct
//! that corresponds to that operation. Like the example above, this removes the burden of dealing
//! with the options and handles the process of reading the options and the instruction's fields
//! into `u8` or `Argument` enums when appropriate.
//! To read an instruction, check its operation with [`Instruction::operation`], then convert the
//! instruction to the struct that corresponds to that operation. Like the example above, this
//! removes the burden of dealing with the options directly and automatically casts the A, B, C and
//! D fields as `u8`, `bool` or `Argument` values.
//!
//! ```
//! # use dust_lang::instruction::{Instruction, Add, u8, Argument, Operation};
//! # use dust_lang::instruction::{Instruction, Add, Argument, Operation};
//! # let mystery_instruction = Instruction::add(
//! u8::Local(1),
//! Argument::Local(1),
//! Argument::Constant(2)
//! );
//!
//! // Let's read an instruction and see if it performs addition-assignment, like in one of the
//! // following examples:
//! # 1,
//! # Argument::Register(1),
//! # Argument::Constant(2)
//! # );
//! // Let's read an instruction and see if it performs addition-assignment,
//! // like in one of the following examples:
//! // - `a += 2`
//! // - `a = a + 2`
//! // - `a = 2 + a`
@ -79,7 +78,7 @@
//! let operation = mystery_instruction.operation();
//!
//! match operation {
//! Operation::ADD => {
//! Operation::Add => {
//! let Add { destination, left, right } = Add::from(&mystery_instruction);
//! let is_add_assign =
//! left == Argument::Register(destination)
@ -87,10 +86,7 @@
//!
//! assert!(is_add_assign);
//! }
//! // Handle other operations...
//! _ => {
//! panic!("Unknown operation code: {operation}");
//! }
//! _ => {} // Handle other operations...
//! }
//! ```
mod add;
@ -357,7 +353,7 @@ impl Instruction {
})
}
pub fn destination_as_argument(&self) -> Option<Argument> {
pub fn as_argument(&self) -> Option<Argument> {
match self.operation() {
Operation::LoadConstant => Some(Argument::Constant(self.b)),
Operation::LoadBoolean
@ -592,7 +588,7 @@ impl Instruction {
} = Less::from(self);
let comparison_symbol = if value { "<" } else { ">=" };
format!("R{destination} {left} {comparison_symbol} {right}")
format!("R{destination} = {left} {comparison_symbol} {right}")
}
Operation::LessEqual => {
let LessEqual {
@ -603,7 +599,7 @@ impl Instruction {
} = LessEqual::from(self);
let comparison_symbol = if value { "<=" } else { ">" };
format!("R{destination} {left} {comparison_symbol} {right}")
format!("R{destination} = {left} {comparison_symbol} {right}")
}
Operation::Negate => {
let Negate {
@ -687,7 +683,7 @@ impl Debug for Instruction {
}
}
#[derive(Debug, Clone, Copy)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Argument {
Constant(u8),
Register(u8),
@ -740,15 +736,15 @@ mod tests {
use super::*;
#[test]
fn instruction_is_8_bytes() {
assert_eq!(size_of::<Instruction>(), 8);
fn instruction_is_4_bytes() {
assert_eq!(size_of::<Instruction>(), 4);
}
#[test]
fn instruction_layout() {
assert_eq!(offset_of!(Instruction, a), 0);
assert_eq!(offset_of!(Instruction, b), 1);
assert_eq!(offset_of!(Instruction, c), 2);
assert_eq!(offset_of!(Instruction, metadata), 3);
assert_eq!(offset_of!(Instruction, metadata), 0);
assert_eq!(offset_of!(Instruction, a), 1);
assert_eq!(offset_of!(Instruction, b), 2);
assert_eq!(offset_of!(Instruction, c), 3);
}
}

View File

@ -47,6 +47,6 @@ impl Scope {
impl Display for Scope {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "({}, {})", self.depth, self.block_index)
write!(f, "{}.{}", self.depth, self.block_index)
}
}

View File

@ -24,7 +24,7 @@ impl AbstractValue {
let mut resolved_items = Vec::with_capacity(items.len());
for pointer in items {
let resolved_item = vm.follow_pointer(*pointer)?.to_concrete_owned(vm)?;
let resolved_item = vm.follow_pointer(*pointer)?.into_concrete_owned(vm)?;
resolved_items.push(resolved_item);
}

View File

@ -25,10 +25,10 @@ impl Value {
}
}
pub fn to_concrete_owned(&self, vm: &Vm) -> Result<ConcreteValue, VmError> {
pub fn into_concrete_owned(self, vm: &Vm) -> Result<ConcreteValue, VmError> {
match self {
Value::Abstract(abstract_value) => abstract_value.to_concrete_owned(vm),
Value::Concrete(concrete_value) => Ok(concrete_value.clone()),
Value::Concrete(concrete_value) => Ok(concrete_value),
}
}
@ -64,10 +64,10 @@ impl ValueRef<'_> {
}
}
pub fn to_concrete_owned(&self, vm: &Vm) -> Result<ConcreteValue, VmError> {
pub fn into_concrete_owned(self, vm: &Vm) -> Result<ConcreteValue, VmError> {
match self {
ValueRef::Abstract(abstract_value) => abstract_value.to_concrete_owned(vm),
ValueRef::Concrete(concrete_value) => Ok((*concrete_value).clone()),
ValueRef::Concrete(concrete_value) => Ok(concrete_value.clone()),
}
}

View File

@ -169,7 +169,7 @@ impl<'a> Vm<'a> {
let local_register_index = self.get_local_register(local_index)?;
let register = Register::Pointer(Pointer::Stack(register_index));
self.set_register(local_register_index, register);
self.set_register(local_register_index, register)?;
}
Operation::Add => {
let Add {
@ -471,7 +471,7 @@ impl<'a> Vm<'a> {
self.chunk
} else {
return Err(VmError::ExpectedFunction {
found: function.to_concrete_owned(self)?,
found: function.into_concrete_owned(self)?,
position: self.current_position(),
});
};
@ -521,7 +521,7 @@ impl<'a> Vm<'a> {
return if let Some(register_index) = self.last_assigned_register {
let return_value = self
.open_register(register_index)?
.to_concrete_owned(self)?;
.into_concrete_owned(self)?;
Ok(Some(return_value))
} else {