Fix while loop jumps; Pass tests
This commit is contained in:
parent
604962c535
commit
febd7bb054
@ -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();
|
||||
|
@ -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);
|
||||
|
169
dust-lang/tests/comparison.rs
Normal file
169
dust-lang/tests/comparison.rs
Normal 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))));
|
||||
}
|
@ -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
47
dust-lang/tests/logic.rs
Normal 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))));
|
||||
}
|
@ -11,7 +11,7 @@ while count <= 15 {
|
||||
} else if divides_by_5 {
|
||||
"buzz"
|
||||
} else {
|
||||
string(count)
|
||||
to_string(count)
|
||||
}
|
||||
|
||||
write_line(output)
|
||||
|
Loading…
Reference in New Issue
Block a user