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

View File

@ -1,7 +1,5 @@
//! Tools used by the compiler to optimize a chunk's bytecode. //! Tools used by the compiler to optimize a chunk's bytecode.
use smallvec::SmallVec;
use crate::{instruction::SetLocal, CompileError, Compiler, Instruction, Operation, Span, Type}; use crate::{instruction::SetLocal, CompileError, Compiler, Instruction, Operation, Span, Type};
fn get_last_operations<const COUNT: usize>( 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. //! 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( //! let add_1 = Instruction::add(
//! u8::Register(0), //! 0,
//! Argument::Local(1), //! Argument::Register(1),
//! Argument::Constant(2) //! Argument::Constant(2)
//! ); //! );
//! let add_2 = Instruction::from(Add { //! let add_2 = Instruction::from(Add {
//! destination: u8::Register(0), //! destination: 0,
//! left: Argument::Local(1), //! left: Argument::Register(1),
//! right: Argument::Constant(2), //! right: Argument::Constant(2),
//! }); //! });
//! //!
@ -57,21 +57,20 @@
//! //!
//! ## Reading Instructions //! ## Reading Instructions
//! //!
//! To read an instruction, check its `operation` field, then convert the instruction to the struct //! To read an instruction, check its operation with [`Instruction::operation`], then convert the
//! that corresponds to that operation. Like the example above, this removes the burden of dealing //! instruction to the struct that corresponds to that operation. Like the example above, this
//! with the options and handles the process of reading the options and the instruction's fields //! removes the burden of dealing with the options directly and automatically casts the A, B, C and
//! into `u8` or `Argument` enums when appropriate. //! 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( //! # let mystery_instruction = Instruction::add(
//! u8::Local(1), //! # 1,
//! Argument::Local(1), //! # Argument::Register(1),
//! Argument::Constant(2) //! # Argument::Constant(2)
//! ); //! # );
//! //! // Let's read an instruction and see if it performs addition-assignment,
//! // Let's read an instruction and see if it performs addition-assignment, like in one of the //! // like in one of the following examples:
//! // following examples:
//! // - `a += 2` //! // - `a += 2`
//! // - `a = a + 2` //! // - `a = a + 2`
//! // - `a = 2 + a` //! // - `a = 2 + a`
@ -79,7 +78,7 @@
//! let operation = mystery_instruction.operation(); //! let operation = mystery_instruction.operation();
//! //!
//! match operation { //! match operation {
//! Operation::ADD => { //! Operation::Add => {
//! let Add { destination, left, right } = Add::from(&mystery_instruction); //! let Add { destination, left, right } = Add::from(&mystery_instruction);
//! let is_add_assign = //! let is_add_assign =
//! left == Argument::Register(destination) //! left == Argument::Register(destination)
@ -87,10 +86,7 @@
//! //!
//! assert!(is_add_assign); //! assert!(is_add_assign);
//! } //! }
//! // Handle other operations... //! _ => {} // Handle other operations...
//! _ => {
//! panic!("Unknown operation code: {operation}");
//! }
//! } //! }
//! ``` //! ```
mod add; 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() { match self.operation() {
Operation::LoadConstant => Some(Argument::Constant(self.b)), Operation::LoadConstant => Some(Argument::Constant(self.b)),
Operation::LoadBoolean Operation::LoadBoolean
@ -592,7 +588,7 @@ impl Instruction {
} = Less::from(self); } = Less::from(self);
let comparison_symbol = if value { "<" } else { ">=" }; let comparison_symbol = if value { "<" } else { ">=" };
format!("R{destination} {left} {comparison_symbol} {right}") format!("R{destination} = {left} {comparison_symbol} {right}")
} }
Operation::LessEqual => { Operation::LessEqual => {
let LessEqual { let LessEqual {
@ -603,7 +599,7 @@ impl Instruction {
} = LessEqual::from(self); } = LessEqual::from(self);
let comparison_symbol = if value { "<=" } else { ">" }; let comparison_symbol = if value { "<=" } else { ">" };
format!("R{destination} {left} {comparison_symbol} {right}") format!("R{destination} = {left} {comparison_symbol} {right}")
} }
Operation::Negate => { Operation::Negate => {
let 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 { pub enum Argument {
Constant(u8), Constant(u8),
Register(u8), Register(u8),
@ -740,15 +736,15 @@ mod tests {
use super::*; use super::*;
#[test] #[test]
fn instruction_is_8_bytes() { fn instruction_is_4_bytes() {
assert_eq!(size_of::<Instruction>(), 8); assert_eq!(size_of::<Instruction>(), 4);
} }
#[test] #[test]
fn instruction_layout() { fn instruction_layout() {
assert_eq!(offset_of!(Instruction, a), 0); assert_eq!(offset_of!(Instruction, metadata), 0);
assert_eq!(offset_of!(Instruction, b), 1); assert_eq!(offset_of!(Instruction, a), 1);
assert_eq!(offset_of!(Instruction, c), 2); assert_eq!(offset_of!(Instruction, b), 2);
assert_eq!(offset_of!(Instruction, metadata), 3); assert_eq!(offset_of!(Instruction, c), 3);
} }
} }

View File

@ -47,6 +47,6 @@ impl Scope {
impl Display for Scope { impl Display for Scope {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { 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()); let mut resolved_items = Vec::with_capacity(items.len());
for pointer in items { 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); 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 { match self {
Value::Abstract(abstract_value) => abstract_value.to_concrete_owned(vm), 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 { match self {
ValueRef::Abstract(abstract_value) => abstract_value.to_concrete_owned(vm), 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 local_register_index = self.get_local_register(local_index)?;
let register = Register::Pointer(Pointer::Stack(register_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 => { Operation::Add => {
let Add { let Add {
@ -471,7 +471,7 @@ impl<'a> Vm<'a> {
self.chunk self.chunk
} else { } else {
return Err(VmError::ExpectedFunction { return Err(VmError::ExpectedFunction {
found: function.to_concrete_owned(self)?, found: function.into_concrete_owned(self)?,
position: self.current_position(), position: self.current_position(),
}); });
}; };
@ -521,7 +521,7 @@ impl<'a> Vm<'a> {
return if let Some(register_index) = self.last_assigned_register { return if let Some(register_index) = self.last_assigned_register {
let return_value = self let return_value = self
.open_register(register_index)? .open_register(register_index)?
.to_concrete_owned(self)?; .into_concrete_owned(self)?;
Ok(Some(return_value)) Ok(Some(return_value))
} else { } else {