Refactor to fix bugs with loops; Add close instructions while calling functions
This commit is contained in:
parent
13b4cfffcc
commit
f15cf84c4d
@ -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);
|
||||
|
@ -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)?;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)?;
|
||||
|
@ -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)),
|
||||
|
Loading…
Reference in New Issue
Block a user