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() self.instructions.is_empty()
} }
pub fn instructions_mut(&mut self) -> &mut Vec<(Instruction, Span)> {
&mut self.instructions
}
pub fn get_instruction( pub fn get_instruction(
&self, &self,
offset: usize, offset: usize,
@ -61,6 +65,24 @@ impl Chunk {
self.instructions.push((instruction, position)); 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> { pub fn take_constants(self) -> Vec<Value> {
self.constants self.constants
} }
@ -494,7 +516,7 @@ impl<'a> ChunkDisassembler<'a> {
}; };
let bytecode = u32::from(instruction); let bytecode = u32::from(instruction);
let instruction_display = format!( 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); push_details(&instruction_display, &mut disassembly);

View File

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

View File

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

View File

@ -364,7 +364,11 @@ impl Vm {
for argument_index in for argument_index in
first_argument_index..first_argument_index + argument_count 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; let top_of_stack = function_vm.stack.len() as u8;
function_vm.set(top_of_stack, argument, position)?; 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(), *Instruction::less(true, 0, 1).set_c_is_constant(),
Span(23, 24) 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::add(0, 0, 2).set_c_is_constant(), Span(39, 40)),
(Instruction::jump(3, false), Span(41, 42)), (Instruction::jump(3, false), Span(41, 42)),
(Instruction::get_local(1, 0), Span(41, 42)), (Instruction::get_local(1, 0), Span(41, 42)),