Pass all tests
This commit is contained in:
parent
9d0aa13e8a
commit
d857f42434
@ -437,7 +437,13 @@ impl<'a> ChunkDisassembler<'a> {
|
||||
};
|
||||
let jump_offset = if let Some(jump_offset) = jump_offset {
|
||||
let index = index as isize;
|
||||
let jump_index = index + jump_offset + 1;
|
||||
let jump_index = {
|
||||
if jump_offset > 0 {
|
||||
index + (jump_offset + 1)
|
||||
} else {
|
||||
index + jump_offset
|
||||
}
|
||||
};
|
||||
|
||||
format!("{index} -> {jump_index}")
|
||||
} else {
|
||||
|
@ -345,11 +345,13 @@ impl<'src> Parser<'src> {
|
||||
fn handle_binary_argument(
|
||||
&mut self,
|
||||
instruction: &Instruction,
|
||||
) -> Result<(bool, bool, u8), ParseError> {
|
||||
) -> Result<(bool, bool, bool, u8), ParseError> {
|
||||
let mut push_back = false;
|
||||
let mut is_constant = false;
|
||||
let mut is_local = false;
|
||||
let argument = match instruction.operation() {
|
||||
Operation::GetLocal => {
|
||||
is_local = true;
|
||||
let local_index = instruction.b();
|
||||
let local = self.chunk.get_local(local_index, self.current_position)?;
|
||||
|
||||
@ -378,13 +380,13 @@ impl<'src> Parser<'src> {
|
||||
}
|
||||
};
|
||||
|
||||
Ok((push_back, is_constant, argument))
|
||||
Ok((push_back, is_constant, is_local, argument))
|
||||
}
|
||||
|
||||
fn parse_math_binary(&mut self) -> Result<(), ParseError> {
|
||||
let (left_instruction, left_position) =
|
||||
self.chunk.pop_instruction(self.current_position)?;
|
||||
let (push_back_left, left_is_constant, left) =
|
||||
let (push_back_left, left_is_constant, left_is_local, left) =
|
||||
self.handle_binary_argument(&left_instruction)?;
|
||||
|
||||
let operator = self.current_token;
|
||||
@ -394,12 +396,21 @@ impl<'src> Parser<'src> {
|
||||
self.advance()?;
|
||||
self.parse(rule.precedence.increment())?;
|
||||
|
||||
let register = if left_is_local {
|
||||
left
|
||||
} else {
|
||||
let current = self.current_register;
|
||||
|
||||
self.increment_register()?;
|
||||
|
||||
current
|
||||
};
|
||||
let mut new_instruction = match operator.kind() {
|
||||
TokenKind::Plus => Instruction::add(self.current_register, left, 0),
|
||||
TokenKind::Minus => Instruction::subtract(self.current_register, left, 0),
|
||||
TokenKind::Star => Instruction::multiply(self.current_register, left, 0),
|
||||
TokenKind::Slash => Instruction::divide(self.current_register, left, 0),
|
||||
TokenKind::Percent => Instruction::modulo(self.current_register, left, 0),
|
||||
TokenKind::Plus => Instruction::add(register, left, 0),
|
||||
TokenKind::Minus => Instruction::subtract(register, left, 0),
|
||||
TokenKind::Star => Instruction::multiply(register, left, 0),
|
||||
TokenKind::Slash => Instruction::divide(register, left, 0),
|
||||
TokenKind::Percent => Instruction::modulo(register, left, 0),
|
||||
_ => {
|
||||
return Err(ParseError::ExpectedTokenMultiple {
|
||||
expected: &[
|
||||
@ -415,11 +426,9 @@ impl<'src> Parser<'src> {
|
||||
}
|
||||
};
|
||||
|
||||
self.increment_register()?;
|
||||
|
||||
let (right_instruction, right_position) =
|
||||
self.chunk.pop_instruction(self.current_position)?;
|
||||
let (push_back_right, right_is_constant, right) =
|
||||
let (push_back_right, right_is_constant, right_is_local, right) =
|
||||
self.handle_binary_argument(&right_instruction)?;
|
||||
|
||||
new_instruction.set_c(right);
|
||||
@ -476,7 +485,7 @@ impl<'src> Parser<'src> {
|
||||
fn parse_comparison_binary(&mut self) -> Result<(), ParseError> {
|
||||
let (left_instruction, left_position) =
|
||||
self.chunk.pop_instruction(self.current_position)?;
|
||||
let (push_back_left, left_is_constant, left) =
|
||||
let (push_back_left, left_is_constant, _, left) =
|
||||
self.handle_binary_argument(&left_instruction)?;
|
||||
|
||||
let operator = self.current_token;
|
||||
@ -510,7 +519,7 @@ impl<'src> Parser<'src> {
|
||||
|
||||
let (right_instruction, right_position) =
|
||||
self.chunk.pop_instruction(self.current_position)?;
|
||||
let (push_back_right, right_is_constant, right) =
|
||||
let (push_back_right, right_is_constant, _, right) =
|
||||
self.handle_binary_argument(&right_instruction)?;
|
||||
|
||||
instruction.set_c(right);
|
||||
@ -771,14 +780,14 @@ impl<'src> Parser<'src> {
|
||||
self.parse_block(allow_assignment, allow_return)?;
|
||||
|
||||
let jump_end = self.chunk.len();
|
||||
let jump_distance = jump_end.saturating_sub(jump_start) as u8;
|
||||
let jump_distance = jump_end.abs_diff(jump_start) as u8;
|
||||
let jump_back = Instruction::jump(jump_distance, false);
|
||||
let jump_over_index = self.chunk.find_last_instruction(Operation::Jump);
|
||||
|
||||
if let Some(index) = jump_over_index {
|
||||
let (mut jump_over, jump_over_position) = self.chunk.remove_instruction(index);
|
||||
let (_, jump_over_position) = self.chunk.remove_instruction(index);
|
||||
let jump_over = Instruction::jump(jump_distance - 1, true);
|
||||
|
||||
jump_over.set_b(jump_distance);
|
||||
self.chunk
|
||||
.insert_instruction(index, jump_over, jump_over_position);
|
||||
}
|
||||
|
@ -356,7 +356,7 @@ impl Vm {
|
||||
let new_ip = if is_positive {
|
||||
self.ip + offset as usize
|
||||
} else {
|
||||
self.ip - offset as usize
|
||||
self.ip - (offset + 1) as usize
|
||||
};
|
||||
|
||||
self.ip = new_ip;
|
||||
|
@ -332,7 +332,33 @@ fn if_else_expression() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn if_expression() {
|
||||
fn if_expression_false() {
|
||||
let source = "if 1 == 2 { 2 }";
|
||||
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(Chunk::with_data(
|
||||
vec![
|
||||
(
|
||||
*Instruction::equal(true, 0, 1)
|
||||
.set_b_is_constant()
|
||||
.set_c_is_constant(),
|
||||
Span(5, 7)
|
||||
),
|
||||
(Instruction::jump(1, true), Span(5, 7)),
|
||||
(Instruction::load_constant(0, 2, false), Span(12, 13)),
|
||||
(Instruction::r#return(), Span(15, 15)),
|
||||
],
|
||||
vec![Value::integer(1), Value::integer(2), Value::integer(2)],
|
||||
vec![]
|
||||
)),
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn if_expression_true() {
|
||||
let source = "if 1 == 1 { 2 }";
|
||||
|
||||
assert_eq!(
|
||||
@ -730,12 +756,15 @@ fn subtract() {
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(Chunk::with_data(
|
||||
vec![(
|
||||
*Instruction::subtract(0, 0, 1)
|
||||
.set_b_is_constant()
|
||||
.set_c_is_constant(),
|
||||
Span(2, 3)
|
||||
),],
|
||||
vec![
|
||||
(
|
||||
*Instruction::subtract(0, 0, 1)
|
||||
.set_b_is_constant()
|
||||
.set_c_is_constant(),
|
||||
Span(2, 3)
|
||||
),
|
||||
(Instruction::r#return(), Span(5, 5)),
|
||||
],
|
||||
vec![Value::integer(1), Value::integer(2)],
|
||||
vec![]
|
||||
))
|
||||
@ -759,6 +788,7 @@ fn variable_and() {
|
||||
(Instruction::test(2, false), Span(31, 33)),
|
||||
(Instruction::jump(1, true), Span(31, 33)),
|
||||
(Instruction::get_local(3, 1), Span(34, 35)),
|
||||
(Instruction::r#return(), Span(35, 35)),
|
||||
],
|
||||
vec![],
|
||||
vec![
|
||||
@ -779,23 +809,20 @@ fn r#while() {
|
||||
parse(source),
|
||||
Ok(Chunk::with_data(
|
||||
vec![
|
||||
(Instruction::load_constant(0, 0, false), Span(0, 1)),
|
||||
(Instruction::define_local(0, 0, true), Span(0, 0)),
|
||||
(Instruction::load_constant(0, 0, false), Span(12, 13)),
|
||||
(Instruction::define_local(0, 0, true), Span(8, 9)),
|
||||
(
|
||||
*Instruction::less(false, 0, 1)
|
||||
.set_b_is_constant()
|
||||
.set_c_is_constant(),
|
||||
Span(0, 1)
|
||||
*Instruction::less(true, 0, 1).set_c_is_constant(),
|
||||
Span(23, 24)
|
||||
),
|
||||
(Instruction::jump(1, true), Span(0, 1)),
|
||||
(Instruction::load_boolean(1, true, true), Span(0, 1)),
|
||||
(Instruction::load_boolean(1, false, false), Span(0, 1)),
|
||||
(Instruction::add(0, 0, 2), Span(0, 1)),
|
||||
(Instruction::jump(0, false), Span(0, 1)),
|
||||
(Instruction::get_local(3, 0), Span(0, 1)),
|
||||
(Instruction::jump(2, true), Span(23, 24)),
|
||||
(*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)),
|
||||
(Instruction::r#return(), Span(42, 42)),
|
||||
],
|
||||
vec![],
|
||||
vec![]
|
||||
vec![Value::integer(0), Value::integer(5), Value::integer(1),],
|
||||
vec![Local::new(Identifier::new("x"), true, 0, Some(0)),]
|
||||
)),
|
||||
);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user