Continue refactor; Condense registers in logic chains
This commit is contained in:
parent
a9e867aaab
commit
98a7b7984a
@ -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 {
|
||||||
|
@ -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>(
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user