From f15cf84c4dd54e021081714c51b204b37bb89a2e Mon Sep 17 00:00:00 2001 From: Jeff Date: Sun, 20 Oct 2024 00:06:22 -0400 Subject: [PATCH] Refactor to fix bugs with loops; Add close instructions while calling functions --- dust-lang/src/chunk.rs | 28 +++++++- dust-lang/src/parser.rs | 117 ++++++++++++++++++++++----------- dust-lang/src/value.rs | 41 +++++------- dust-lang/src/vm.rs | 6 +- dust-lang/tests/expressions.rs | 2 +- 5 files changed, 127 insertions(+), 67 deletions(-) diff --git a/dust-lang/src/chunk.rs b/dust-lang/src/chunk.rs index 45af65e..ef97f1d 100644 --- a/dust-lang/src/chunk.rs +++ b/dust-lang/src/chunk.rs @@ -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 { self.constants } @@ -267,8 +289,8 @@ impl<'a> ChunkDisassembler<'a> { const INSTRUCTION_HEADER: [&'static str; 4] = [ "Instructions", "------------", - "INDEX BYTECODE OPERATION INFO JUMP POSITION", - "----- -------- --------------- ------------------------- -------- --------", + "INDEX BYTECODE OPERATION INFO JUMP POSITION ", + "----- -------- --------------- -------------------- -------- -------------", ]; const CONSTANT_HEADER: [&'static str; 4] = @@ -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); diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index 68355fe..5bc81a3 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -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 { @@ -27,7 +27,7 @@ pub fn parse(source: &str) -> Result { .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)?; } diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index 19c344a..93ee212 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -121,7 +121,7 @@ impl Value { pub fn subtract(&self, other: &Value) -> Result { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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, }, 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); diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index cd0bdf5..97e5343 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -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)?; diff --git a/dust-lang/tests/expressions.rs b/dust-lang/tests/expressions.rs index 5140440..03ae7f6 100644 --- a/dust-lang/tests/expressions.rs +++ b/dust-lang/tests/expressions.rs @@ -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)),