1
0

Fix while loop jumps; Pass tests

This commit is contained in:
Jeff 2024-10-31 20:33:46 -04:00
parent 604962c535
commit febd7bb054
6 changed files with 234 additions and 226 deletions

View File

@ -1092,7 +1092,7 @@ impl<'src> Parser<'src> {
fn parse_while(&mut self, allowed: Allowed) -> Result<(), ParseError> {
self.advance()?;
let jump_start = self.chunk.len() as u8;
let expression_start = self.chunk.len() as u8;
self.parse_expression()?;
@ -1102,21 +1102,27 @@ impl<'src> Parser<'src> {
{
self.chunk.instructions_mut().pop();
self.chunk.instructions_mut().pop();
self.chunk.instructions_mut().pop();
}
let block_start = self.chunk.len();
self.parse_block(Allowed {
assignment: true,
explicit_return: allowed.explicit_return,
implicit_return: false,
})?;
if let Some(jump) = self.get_last_jump_mut() {
jump.set_b(jump.b() + 1);
}
let block_end = self.chunk.len() as u8;
let jump_end = self.chunk.len() as u8;
let jump_distance = jump_end - jump_start;
let jump_back = Instruction::jump(jump_distance, false);
self.chunk.insert_instruction(
block_start,
Instruction::jump(block_end - block_start as u8 + 1, true),
self.current_position,
)?;
let jump_back_distance = block_end - expression_start + 1;
let jump_back = Instruction::jump(jump_back_distance, false);
self.emit_instruction(jump_back, self.current_position);
self.optimize_statement();

View File

@ -353,7 +353,7 @@ impl Vm {
let new_ip = if is_positive {
self.ip + jump_distance as usize
} else {
self.ip - jump_distance as usize
self.ip - jump_distance as usize - 1
};
self.jump_to_ip(new_ip);

View File

@ -0,0 +1,169 @@
use dust_lang::*;
#[test]
fn equal() {
let source = "1 == 2";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::equal(true, 0, 1)
.set_b_is_constant()
.set_c_is_constant(),
Span(2, 4)
),
(Instruction::jump(1, true), Span(2, 4)),
(Instruction::load_boolean(0, true, true), Span(2, 4)),
(Instruction::load_boolean(0, false, false), Span(2, 4)),
(Instruction::r#return(true), Span(6, 6)),
],
vec![Value::integer(1), Value::integer(2)],
vec![]
)),
);
assert_eq!(run(source), Ok(Some(Value::boolean(false))));
}
#[test]
fn greater() {
let source = "1 > 2";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::less_equal(false, 0, 1)
.set_b_is_constant()
.set_c_is_constant(),
Span(2, 3)
),
(Instruction::jump(1, true), Span(2, 3)),
(Instruction::load_boolean(0, true, true), Span(2, 3)),
(Instruction::load_boolean(0, false, false), Span(2, 3)),
(Instruction::r#return(true), Span(5, 5)),
],
vec![Value::integer(1), Value::integer(2)],
vec![]
)),
);
assert_eq!(run(source), Ok(Some(Value::boolean(false))));
}
#[test]
fn greater_than_or_equal() {
let source = "1 >= 2";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::less(false, 0, 1)
.set_b_is_constant()
.set_c_is_constant(),
Span(2, 4)
),
(Instruction::jump(1, true), Span(2, 4)),
(Instruction::load_boolean(0, true, true), Span(2, 4)),
(Instruction::load_boolean(0, false, false), Span(2, 4)),
(Instruction::r#return(true), Span(6, 6)),
],
vec![Value::integer(1), Value::integer(2)],
vec![]
)),
);
assert_eq!(run(source), Ok(Some(Value::boolean(false))));
}
#[test]
fn less_than() {
let source = "1 < 2";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::less(true, 0, 1)
.set_b_is_constant()
.set_c_is_constant(),
Span(2, 3)
),
(Instruction::jump(1, true), Span(2, 3)),
(Instruction::load_boolean(0, true, true), Span(2, 3)),
(Instruction::load_boolean(0, false, false), Span(2, 3)),
(Instruction::r#return(true), Span(5, 5)),
],
vec![Value::integer(1), Value::integer(2)],
vec![]
)),
);
assert_eq!(run(source), Ok(Some(Value::boolean(true))));
}
#[test]
fn less_than_or_equal() {
let source = "1 <= 2";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::less_equal(true, 0, 1)
.set_b_is_constant()
.set_c_is_constant(),
Span(2, 4)
),
(Instruction::jump(1, true), Span(2, 4)),
(Instruction::load_boolean(0, true, true), Span(2, 4)),
(Instruction::load_boolean(0, false, false), Span(2, 4)),
(Instruction::r#return(true), Span(6, 6)),
],
vec![Value::integer(1), Value::integer(2)],
vec![]
)),
);
assert_eq!(run(source), Ok(Some(Value::boolean(true))));
}
#[test]
fn not_equal() {
let source = "1 != 2";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::equal(false, 0, 1)
.set_b_is_constant()
.set_c_is_constant(),
Span(2, 4)
),
(Instruction::jump(1, true), Span(2, 4)),
(Instruction::load_boolean(0, true, true), Span(2, 4)),
(Instruction::load_boolean(0, false, false), Span(2, 4)),
(Instruction::r#return(true), Span(6, 6)),
],
vec![Value::integer(1), Value::integer(2)],
vec![]
)),
);
assert_eq!(run(source), Ok(Some(Value::boolean(true))));
}

View File

@ -48,29 +48,6 @@ fn add_assign() {
assert_eq!(run(source), Ok(Some(Value::integer(3))));
}
#[test]
fn and() {
let source = "true && false";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(Instruction::load_boolean(0, true, false), Span(0, 4)),
(Instruction::test(0, false), Span(5, 7)),
(Instruction::jump(4, true), Span(5, 7)),
(Instruction::load_boolean(1, false, false), Span(8, 13)),
(Instruction::r#return(true), Span(13, 13)),
],
vec![],
vec![]
))
);
assert_eq!(run(source), Ok(Some(Value::boolean(false))));
}
#[test]
fn block_scope() {
let source = "
@ -243,34 +220,6 @@ fn empty_list() {
assert_eq!(run(source), Ok(Some(Value::list(0, 0, Type::Any))));
}
#[test]
fn equal() {
let source = "1 == 2";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::equal(true, 0, 1)
.set_b_is_constant()
.set_c_is_constant(),
Span(2, 4)
),
(Instruction::jump(3, true), Span(2, 4)),
(Instruction::load_boolean(0, true, true), Span(2, 4)),
(Instruction::load_boolean(0, false, false), Span(2, 4)),
(Instruction::r#return(true), Span(6, 6)),
],
vec![Value::integer(1), Value::integer(2)],
vec![]
)),
);
assert_eq!(run(source), Ok(Some(Value::boolean(false))));
}
#[test]
fn function() {
let source = "fn(a: int, b: int) -> int { a + b }";
@ -404,118 +353,6 @@ fn function_call() {
assert_eq!(run(source), Ok(Some(Value::integer(3))));
}
#[test]
fn greater() {
let source = "1 > 2";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::less_equal(false, 0, 1)
.set_b_is_constant()
.set_c_is_constant(),
Span(2, 3)
),
(Instruction::jump(3, true), Span(2, 3)),
(Instruction::load_boolean(0, true, true), Span(2, 3)),
(Instruction::load_boolean(0, false, false), Span(2, 3)),
(Instruction::r#return(true), Span(5, 5)),
],
vec![Value::integer(1), Value::integer(2)],
vec![]
)),
);
assert_eq!(run(source), Ok(Some(Value::boolean(false))));
}
#[test]
fn greater_than_or_equal() {
let source = "1 >= 2";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::less(false, 0, 1)
.set_b_is_constant()
.set_c_is_constant(),
Span(2, 4)
),
(Instruction::jump(3, true), Span(2, 4)),
(Instruction::load_boolean(0, true, true), Span(2, 4)),
(Instruction::load_boolean(0, false, false), Span(2, 4)),
(Instruction::r#return(true), Span(6, 6)),
],
vec![Value::integer(1), Value::integer(2)],
vec![]
)),
);
assert_eq!(run(source), Ok(Some(Value::boolean(false))));
}
#[test]
fn less_than() {
let source = "1 < 2";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::less(true, 0, 1)
.set_b_is_constant()
.set_c_is_constant(),
Span(2, 3)
),
(Instruction::jump(3, true), Span(2, 3)),
(Instruction::load_boolean(0, true, true), Span(2, 3)),
(Instruction::load_boolean(0, false, false), Span(2, 3)),
(Instruction::r#return(true), Span(5, 5)),
],
vec![Value::integer(1), Value::integer(2)],
vec![]
)),
);
assert_eq!(run(source), Ok(Some(Value::boolean(true))));
}
#[test]
fn less_than_or_equal() {
let source = "1 <= 2";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::less_equal(true, 0, 1)
.set_b_is_constant()
.set_c_is_constant(),
Span(2, 4)
),
(Instruction::jump(3, true), Span(2, 4)),
(Instruction::load_boolean(0, true, true), Span(2, 4)),
(Instruction::load_boolean(0, false, false), Span(2, 4)),
(Instruction::r#return(true), Span(6, 6)),
],
vec![Value::integer(1), Value::integer(2)],
vec![]
)),
);
assert_eq!(run(source), Ok(Some(Value::boolean(true))));
}
#[test]
fn list() {
let source = "[1, 2, 3]";
@ -747,57 +584,6 @@ fn not() {
assert_eq!(run(source), Ok(Some(Value::boolean(false))));
}
#[test]
fn not_equal() {
let source = "1 != 2";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::equal(false, 0, 1)
.set_b_is_constant()
.set_c_is_constant(),
Span(2, 4)
),
(Instruction::jump(3, true), Span(2, 4)),
(Instruction::load_boolean(0, true, true), Span(2, 4)),
(Instruction::load_boolean(0, false, false), Span(2, 4)),
(Instruction::r#return(true), Span(6, 6)),
],
vec![Value::integer(1), Value::integer(2)],
vec![]
)),
);
assert_eq!(run(source), Ok(Some(Value::boolean(true))));
}
#[test]
fn or() {
let source = "true || false";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(Instruction::load_boolean(0, true, false), Span(0, 4)),
(Instruction::test(0, true), Span(5, 7)),
(Instruction::jump(4, true), Span(5, 7)),
(Instruction::load_boolean(1, false, false), Span(8, 13)),
(Instruction::r#return(true), Span(13, 13)),
],
vec![],
vec![]
))
);
assert_eq!(run(source), Ok(Some(Value::boolean(true))));
}
#[test]
fn parentheses_precedence() {
let source = "(1 + 2) * 3";
@ -917,7 +703,7 @@ fn variable_and() {
(Instruction::define_local(1, 1, false), Span(18, 19)),
(Instruction::get_local(2, 0), Span(29, 30)),
(Instruction::test(2, false), Span(31, 33)),
(Instruction::jump(8, true), Span(31, 33)),
(Instruction::jump(1, true), Span(31, 33)),
(Instruction::get_local(3, 1), Span(34, 35)),
(Instruction::r#return(true), Span(35, 35)),
],
@ -947,9 +733,9 @@ fn r#while() {
*Instruction::less(true, 0, 1).set_c_is_constant(),
Span(23, 24)
),
(Instruction::jump(7, true), Span(23, 24)),
(*Instruction::add(0, 0, 2).set_c_is_constant(), Span(39, 40)),
(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)),
(Instruction::r#return(true), Span(42, 42)),
],

47
dust-lang/tests/logic.rs Normal file
View File

@ -0,0 +1,47 @@
use dust_lang::*;
#[test]
fn and() {
let source = "true && false";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(Instruction::load_boolean(0, true, false), Span(0, 4)),
(Instruction::test(0, false), Span(5, 7)),
(Instruction::jump(1, true), Span(5, 7)),
(Instruction::load_boolean(1, false, false), Span(8, 13)),
(Instruction::r#return(true), Span(13, 13)),
],
vec![],
vec![]
))
);
assert_eq!(run(source), Ok(Some(Value::boolean(false))));
}
#[test]
fn or() {
let source = "true || false";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(Instruction::load_boolean(0, true, false), Span(0, 4)),
(Instruction::test(0, true), Span(5, 7)),
(Instruction::jump(1, true), Span(5, 7)),
(Instruction::load_boolean(1, false, false), Span(8, 13)),
(Instruction::r#return(true), Span(13, 13)),
],
vec![],
vec![]
))
);
assert_eq!(run(source), Ok(Some(Value::boolean(true))));
}

View File

@ -11,7 +11,7 @@ while count <= 15 {
} else if divides_by_5 {
"buzz"
} else {
string(count)
to_string(count)
}
write_line(output)