1
0

Refactor to fix bugs with loops; Add close instructions while calling functions

This commit is contained in:
Jeff 2024-10-20 00:06:22 -04:00
parent 13b4cfffcc
commit f15cf84c4d
5 changed files with 127 additions and 67 deletions

View File

@ -47,6 +47,10 @@ impl Chunk {
self.instructions.is_empty()
}
pub fn instructions_mut(&mut self) -> &mut Vec<(Instruction, Span)> {
&mut self.instructions
}
pub fn get_instruction(
&self,
offset: usize,
@ -61,6 +65,24 @@ impl Chunk {
self.instructions.push((instruction, position));
}
pub fn insert_instruction(
&mut self,
index: usize,
instruction: Instruction,
position: Span,
) -> Result<(), ChunkError> {
if index > self.instructions.len() {
Err(ChunkError::InstructionIndexOfBounds {
offset: index,
position,
})
} else {
self.instructions.insert(index, (instruction, position));
Ok(())
}
}
pub fn take_constants(self) -> Vec<Value> {
self.constants
}
@ -494,7 +516,7 @@ impl<'a> ChunkDisassembler<'a> {
};
let bytecode = u32::from(instruction);
let instruction_display = format!(
"{index:<5} {bytecode:<08X} {operation:15} {info:25} {jump_offset:8} {position:8}"
"{index:<5} {bytecode:<08X} {operation:15} {info:20} {jump_offset:8} {position:13}"
);
push_details(&instruction_display, &mut disassembly);

View File

@ -9,8 +9,8 @@ use colored::Colorize;
use serde::{Deserialize, Serialize};
use crate::{
AnnotatedError, Chunk, ChunkError, DustError, FunctionType, Identifier, Instruction, LexError,
Lexer, Operation, Span, Token, TokenKind, TokenOwned, Type, Value,
instruction, operation, AnnotatedError, Chunk, ChunkError, DustError, FunctionType, Identifier,
Instruction, LexError, Lexer, Operation, Span, Token, TokenKind, TokenOwned, Type, Value,
};
pub fn parse(source: &str) -> Result<Chunk, DustError> {
@ -27,7 +27,7 @@ pub fn parse(source: &str) -> Result<Chunk, DustError> {
.map_err(|error| DustError::Parse { error, source })?;
}
Ok(parser.take_chunk())
Ok(parser.finish())
}
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize)]
@ -70,7 +70,7 @@ impl<'src> Parser<'src> {
})
}
pub fn take_chunk(self) -> Chunk {
pub fn finish(self) -> Chunk {
log::info!("End chunk");
self.chunk
@ -172,11 +172,33 @@ impl<'src> Parser<'src> {
}
fn get_previous_jump_mut(&mut self) -> Option<&mut Instruction> {
self.current_statement
let staged_jump = self
.current_statement
.iter_mut()
.rev()
.find(|(instruction, _)| matches!(instruction.operation(), Operation::Jump))
.map(|(instruction, _)| instruction)
.find_map(|(instruction, _)| {
if matches!(instruction.operation(), Operation::Jump) {
Some(instruction)
} else {
None
}
});
if staged_jump.is_some() {
staged_jump
} else {
self.chunk
.instructions_mut()
.iter_mut()
.rev()
.find_map(|(instruction, _)| {
if matches!(instruction.operation(), Operation::Jump) {
Some(instruction)
} else {
None
}
})
}
}
fn emit_constant(&mut self, value: Value, position: Span) -> Result<(), ParseError> {
@ -435,7 +457,7 @@ impl<'src> Parser<'src> {
_ => {
push_back = true;
instruction.a()
self.next_register()
}
};
@ -495,17 +517,17 @@ impl<'src> Parser<'src> {
self.next_register()
};
let mut new_instruction = match operator.kind() {
TokenKind::Plus => Instruction::add(register, left, right),
TokenKind::PlusEqual => Instruction::add(register, left, right),
TokenKind::Minus => Instruction::subtract(register, left, right),
TokenKind::MinusEqual => Instruction::subtract(register, left, right),
TokenKind::Star => Instruction::multiply(register, left, right),
TokenKind::StarEqual => Instruction::multiply(register, left, right),
TokenKind::Slash => Instruction::divide(register, left, right),
TokenKind::SlashEqual => Instruction::divide(register, left, right),
TokenKind::Percent => Instruction::modulo(register, left, right),
TokenKind::PercentEqual => Instruction::modulo(register, left, right),
let mut new_instruction = match operator {
Token::Plus => Instruction::add(register, left, right),
Token::PlusEqual => Instruction::add(register, left, right),
Token::Minus => Instruction::subtract(register, left, right),
Token::MinusEqual => Instruction::subtract(register, left, right),
Token::Star => Instruction::multiply(register, left, right),
Token::StarEqual => Instruction::multiply(register, left, right),
Token::Slash => Instruction::divide(register, left, right),
Token::SlashEqual => Instruction::divide(register, left, right),
Token::Percent => Instruction::modulo(register, left, right),
Token::PercentEqual => Instruction::modulo(register, left, right),
_ => {
return Err(ParseError::ExpectedTokenMultiple {
expected: &[
@ -536,6 +558,15 @@ impl<'src> Parser<'src> {
self.emit_instruction(new_instruction, operator_position);
if let Token::PlusEqual
| Token::MinusEqual
| Token::StarEqual
| Token::SlashEqual
| Token::PercentEqual = operator
{
self.commit_current_statement();
}
Ok(())
}
@ -577,12 +608,12 @@ impl<'src> Parser<'src> {
self.handle_binary_argument(&right_instruction)?;
let mut instruction = match operator {
Token::DoubleEqual => Instruction::equal(true, left.saturating_sub(1), right),
Token::BangEqual => Instruction::equal(false, left.saturating_sub(1), right),
Token::Less => Instruction::less(true, left.saturating_sub(1), right),
Token::LessEqual => Instruction::less_equal(true, left.saturating_sub(1), right),
Token::Greater => Instruction::less_equal(false, left.saturating_sub(1), right),
Token::GreaterEqual => Instruction::less(false, left.saturating_sub(1), right),
Token::DoubleEqual => Instruction::equal(true, left, right),
Token::BangEqual => Instruction::equal(false, left, right),
Token::Less => Instruction::less(true, left, right),
Token::LessEqual => Instruction::less_equal(true, left, right),
Token::Greater => Instruction::less_equal(false, left, right),
Token::GreaterEqual => Instruction::less(false, left, right),
_ => {
return Err(ParseError::ExpectedTokenMultiple {
@ -800,7 +831,6 @@ impl<'src> Parser<'src> {
let expected_register = self.next_register();
self.parse_expression()?;
self.commit_current_statement();
let actual_register = self.next_register() - 1;
@ -893,9 +923,6 @@ impl<'src> Parser<'src> {
fn parse_while(&mut self, allowed: Allowed) -> Result<(), ParseError> {
self.advance()?;
let jump_start = self.chunk.len() + self.current_statement.len();
self.parse_expression()?;
if let Some(
@ -904,8 +931,11 @@ impl<'src> Parser<'src> {
{
self.current_statement.pop();
self.current_statement.pop();
self.current_statement.pop();
}
let jump_start = self.chunk.len() + self.current_statement.len();
self.parse_block(Allowed {
assignment: true,
explicit_return: allowed.explicit_return,
@ -913,16 +943,17 @@ impl<'src> Parser<'src> {
})?;
let jump_end = self.chunk.len() + self.current_statement.len();
let jump_distance = jump_end.abs_diff(jump_start) as u8;
let jump_back = Instruction::jump(jump_distance, false);
if let Some(jump_over) = self.get_previous_jump_mut() {
*jump_over = Instruction::jump(jump_distance - 1, true);
}
let jump_distance = jump_end.abs_diff(jump_start) as u8 + 1;
let jump_back = Instruction::jump(jump_distance + 1, false);
self.emit_instruction(jump_back, self.current_position);
self.commit_current_statement();
self.chunk
.push_instruction(jump_back, self.current_position);
self.chunk.insert_instruction(
jump_start,
Instruction::jump(jump_distance, true),
self.current_position,
)?;
Ok(())
}
@ -1223,7 +1254,19 @@ impl<'src> Parser<'src> {
self.advance()?;
while !self.allow(Token::RightParenthesis)? {
let expected_register = self.next_register();
self.parse_expression()?;
let actual_register = self.next_register() - 1;
if expected_register < actual_register {
self.emit_instruction(
Instruction::close(expected_register, actual_register),
self.current_position,
);
}
self.allow(Token::Comma)?;
}

View File

@ -121,7 +121,7 @@ impl Value {
pub fn subtract(&self, other: &Value) -> Result<Value, ValueError> {
let (left, right) = match (self, other) {
(Value::Primitive(left), Value::Primitive(right)) => (left, right),
_ => return Err(ValueError::CannotAdd(self.clone(), other.clone())),
_ => return Err(ValueError::CannotSubtract(self.clone(), other.clone())),
};
let difference = left
.subtract(right)
@ -133,7 +133,7 @@ impl Value {
pub fn multiply(&self, other: &Value) -> Result<Value, ValueError> {
let (left, right) = match (self, other) {
(Value::Primitive(left), Value::Primitive(right)) => (left, right),
_ => return Err(ValueError::CannotAdd(self.clone(), other.clone())),
_ => return Err(ValueError::CannotMultiply(self.clone(), other.clone())),
};
let product = left
.multiply(right)
@ -145,7 +145,7 @@ impl Value {
pub fn divide(&self, other: &Value) -> Result<Value, ValueError> {
let (left, right) = match (self, other) {
(Value::Primitive(left), Value::Primitive(right)) => (left, right),
_ => return Err(ValueError::CannotAdd(self.clone(), other.clone())),
_ => return Err(ValueError::CannotDivide(self.clone(), other.clone())),
};
let quotient = left
.divide(right)
@ -157,7 +157,7 @@ impl Value {
pub fn modulo(&self, other: &Value) -> Result<Value, ValueError> {
let (left, right) = match (self, other) {
(Value::Primitive(left), Value::Primitive(right)) => (left, right),
_ => return Err(ValueError::CannotAdd(self.clone(), other.clone())),
_ => return Err(ValueError::CannotModulo(self.clone(), other.clone())),
};
let remainder = left
.modulo(right)
@ -169,7 +169,7 @@ impl Value {
pub fn less_than(&self, other: &Value) -> Result<Value, ValueError> {
let (left, right) = match (self, other) {
(Value::Primitive(left), Value::Primitive(right)) => (left, right),
_ => return Err(ValueError::CannotAdd(self.clone(), other.clone())),
_ => return Err(ValueError::CannotCompare(self.clone(), other.clone())),
};
Ok(Value::boolean(left < right))
@ -178,18 +178,16 @@ impl Value {
pub fn less_than_or_equal(&self, other: &Value) -> Result<Value, ValueError> {
let (left, right) = match (self, other) {
(Value::Primitive(left), Value::Primitive(right)) => (left, right),
_ => return Err(ValueError::CannotAdd(self.clone(), other.clone())),
_ => return Err(ValueError::CannotCompare(self.clone(), other.clone())),
};
left.less_than_or_equal(right)
.ok_or_else(|| ValueError::CannotLessThanOrEqual(self.clone(), other.clone()))
.map(Value::Primitive)
Ok(Value::boolean(left <= right))
}
pub fn equal(&self, other: &Value) -> Result<Value, ValueError> {
let (left, right) = match (self, other) {
(Value::Primitive(left), Value::Primitive(right)) => (left, right),
_ => return Err(ValueError::CannotAdd(self.clone(), other.clone())),
_ => return Err(ValueError::CannotCompare(self.clone(), other.clone())),
};
Ok(Value::boolean(left == right))
@ -198,7 +196,7 @@ impl Value {
pub fn not_equal(&self, other: &Value) -> Result<Value, ValueError> {
let (left, right) = match (self, other) {
(Value::Primitive(left), Value::Primitive(right)) => (left, right),
_ => return Err(ValueError::CannotAdd(self.clone(), other.clone())),
_ => return Err(ValueError::CannotCompare(self.clone(), other.clone())),
};
Ok(Value::boolean(left != right))
@ -931,13 +929,12 @@ impl Display for Object {
pub enum ValueError {
CannotAdd(Value, Value),
CannotAnd(Value, Value),
CannotCompare(Value, Value),
CannotDisplay {
value: Value,
vm_error: Box<VmError>,
},
CannotDivide(Value, Value),
CannotLessThan(Value, Value),
CannotLessThanOrEqual(Value, Value),
CannotModulo(Value, Value),
CannotMultiply(Value, Value),
CannotNegate(Value),
@ -973,6 +970,12 @@ impl Display for ValueError {
left_display, right_display
)
}
ValueError::CannotCompare(left, right) => {
let left_display = get_value_display(left);
let right_display = get_value_display(right);
write!(f, "Cannot compare {} and {}", left_display, right_display)
}
ValueError::CannotDisplay { value, vm_error } => {
let value_display = get_value_display(value);
@ -984,18 +987,6 @@ impl Display for ValueError {
write!(f, "Cannot divide {} by {}", left_display, right_display)
}
ValueError::CannotLessThan(left, right) => {
let left_display = get_value_display(left);
let right_display = get_value_display(right);
write!(f, "Cannot compare {} and {}", left_display, right_display)
}
ValueError::CannotLessThanOrEqual(left, right) => {
let left_display = get_value_display(left);
let right_display = get_value_display(right);
write!(f, "Cannot compare {} and {}", left_display, right_display)
}
ValueError::CannotModulo(left, right) => {
let left_display = get_value_display(left);
let right_display = get_value_display(right);

View File

@ -364,7 +364,11 @@ impl Vm {
for argument_index in
first_argument_index..first_argument_index + argument_count
{
let argument = self.get(argument_index, position)?.clone();
let argument = match self.get(argument_index, position) {
Ok(value) => value.clone(),
Err(VmError::EmptyRegister { .. }) => continue,
Err(error) => return Err(error),
};
let top_of_stack = function_vm.stack.len() as u8;
function_vm.set(top_of_stack, argument, position)?;

View File

@ -1049,7 +1049,7 @@ fn r#while() {
*Instruction::less(true, 0, 1).set_c_is_constant(),
Span(23, 24)
),
(Instruction::jump(2, true), Span(23, 24)),
(Instruction::jump(2, true), Span(41, 42)),
(*Instruction::add(0, 0, 2).set_c_is_constant(), Span(39, 40)),
(Instruction::jump(3, false), Span(41, 42)),
(Instruction::get_local(1, 0), Span(41, 42)),