1
0

Add failing control flow test with new panic function

This commit is contained in:
Jeff 2024-10-30 09:50:45 -04:00
parent bd23853657
commit 10abd91c85
4 changed files with 310 additions and 273 deletions

View File

@ -346,11 +346,10 @@ impl Instruction {
} }
pub fn yields_value(&self) -> bool { pub fn yields_value(&self) -> bool {
matches!( if matches!(
self.operation(), self.operation(),
Operation::Add Operation::Add
| Operation::Call | Operation::Call
| Operation::CallNative
| Operation::Divide | Operation::Divide
| Operation::GetLocal | Operation::GetLocal
| Operation::LoadBoolean | Operation::LoadBoolean
@ -362,7 +361,17 @@ impl Instruction {
| Operation::Negate | Operation::Negate
| Operation::Not | Operation::Not
| Operation::Subtract | Operation::Subtract
) ) {
return true;
}
if matches!(self.operation(), Operation::CallNative) {
let native_function = NativeFunction::from(self.b());
return native_function.returns_value();
}
false
} }
pub fn disassembly_info(&self, chunk: Option<&Chunk>) -> String { pub fn disassembly_info(&self, chunk: Option<&Chunk>) -> String {
@ -582,11 +591,12 @@ impl Instruction {
let native_function = NativeFunction::from(self.b()); let native_function = NativeFunction::from(self.b());
let argument_count = self.c(); let argument_count = self.c();
let mut output = String::new(); let mut output = String::new();
if native_function.returns_value() {
let native_function_name = native_function.as_str(); let native_function_name = native_function.as_str();
if native_function.returns_value() {
output.push_str(&format!("R{} = {}(", to_register, native_function_name)); output.push_str(&format!("R{} = {}(", to_register, native_function_name));
} else {
output.push_str(&format!("{}(", native_function_name));
} }
if argument_count != 0 { if argument_count != 0 {
@ -601,9 +611,7 @@ impl Instruction {
} }
} }
if native_function.returns_value() {
output.push(')'); output.push(')');
}
output output
} }

View File

@ -1101,7 +1101,7 @@ impl<'src> Parser<'src> {
self.allow(Token::Comma)?; self.allow(Token::Comma)?;
} }
let end = self.current_position.1; let end = self.previous_position.1;
let to_register = self.next_register(); let to_register = self.next_register();
let argument_count = to_register - start_register; let argument_count = to_register - start_register;
self.current_is_expression = native_function.returns_value(); self.current_is_expression = native_function.returns_value();

View File

@ -0,0 +1,293 @@
use dust_lang::*;
#[test]
fn equality_assignment_long() {
let source = "let a = if 4 == 4 { true } else { false }; a";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::equal(true, 0, 1)
.set_b_is_constant()
.set_c_is_constant(),
Span(13, 15)
),
(Instruction::jump(3), Span(13, 15)),
(Instruction::load_boolean(0, true, true), Span(20, 24)),
(Instruction::load_boolean(0, false, false), Span(34, 39)),
(Instruction::define_local(0, 0, false), Span(4, 5)),
(Instruction::get_local(1, 0), Span(43, 44)),
(Instruction::r#return(true), Span(44, 44)),
],
vec![Value::integer(4), Value::integer(4)],
vec![Local::new(Identifier::new("a"), None, false, 0, 0)]
)),
);
assert_eq!(run(source), Ok(Some(Value::boolean(true))));
}
#[test]
fn equality_assignment_short() {
let source = "let a = 4 == 4 a";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::equal(true, 0, 1)
.set_b_is_constant()
.set_c_is_constant(),
Span(10, 12)
),
(Instruction::jump(3), Span(10, 12)),
(Instruction::load_boolean(0, true, true), Span(10, 12)),
(Instruction::load_boolean(0, false, false), Span(10, 12)),
(Instruction::define_local(0, 0, false), Span(4, 5)),
(Instruction::get_local(1, 0), Span(15, 16)),
(Instruction::r#return(true), Span(16, 16)),
],
vec![Value::integer(4), Value::integer(4)],
vec![Local::new(Identifier::new("a"), None, false, 0, 0)]
)),
);
assert_eq!(run(source), Ok(Some(Value::boolean(true))));
}
#[test]
fn if_else_complex() {
let source = "
if 1 == 1 {
1; 2; 3; 4;
} else {
1; 2; 3; 4;
}";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::equal(true, 0, 1)
.set_b_is_constant()
.set_c_is_constant(),
Span(14, 16)
),
(Instruction::jump(7), Span(14, 16)),
(Instruction::load_constant(0, 2, false), Span(33, 34)),
(Instruction::load_constant(1, 3, false), Span(36, 37)),
(Instruction::load_constant(2, 4, false), Span(39, 40)),
(Instruction::load_constant(3, 5, false), Span(42, 43)),
(Instruction::jump(11), Span(95, 95)),
(Instruction::load_constant(4, 6, false), Span(74, 75)),
(Instruction::load_constant(5, 7, false), Span(77, 78)),
(Instruction::load_constant(6, 8, false), Span(80, 81)),
(Instruction::load_constant(7, 9, false), Span(83, 84)),
(Instruction::r#return(true), Span(95, 95)),
],
vec![
Value::integer(1),
Value::integer(1),
Value::integer(1),
Value::integer(2),
Value::integer(3),
Value::integer(4),
Value::integer(1),
Value::integer(2),
Value::integer(3),
Value::integer(4)
],
vec![]
))
)
}
// #[test]
// fn if_else_nested() {
// let source = r#"
// if 0 == 1 {
// if 0 == 2 {
// 1;
// } else {
// 2;
// }
// } else {
// if 0 == 3 {
// 3;
// } else {
// 4;
// }
// }"#;
// assert_eq!(
// parse(source),
// Ok(Chunk::with_data(
// None,
// vec![
// (
// *Instruction::equal(true, 0, 1)
// .set_b_is_constant()
// .set_c_is_constant(),
// Span(14, 16)
// ),
// (Instruction::jump(7), Span(14, 16)),
// (
// *Instruction::equal(true, 0, 2)
// .set_b_is_constant()
// .set_c_is_constant(),
// Span(38, 41)
// ),
// (Instruction::jump(3), Span(38, 41)),
// (Instruction::load_constant(0, 1, false), Span(61, 62)),
// (Instruction::jump(11), Span(95, 95)),
// (
// *Instruction::equal(true, 0, 3)
// .set_b_is_constant()
// .set_c_is_constant(),
// Span(77, 79)
// ),
// (Instruction::jump(3), Span(77, 79)),
// (Instruction::load_constant(0, 2, false), Span(94, 95)),
// (Instruction::jump(11), Span(95, 95)),
// (Instruction::load_constant(0, 3, false), Span(114, 115)),
// (Instruction::jump(11), Span(95, 95)),
// (Instruction::load_constant(0, 4, false), Span(134, 135)),
// (Instruction::r#return(true), Span(146, 146)),
// ],
// vec![
// Value::integer(0),
// Value::integer(1),
// Value::integer(0),
// Value::integer(2),
// Value::integer(1),
// Value::integer(0),
// Value::integer(3),
// Value::integer(3),
// Value::integer(4)
// ],
// vec![]
// ))
// );
// assert_eq!(run(source), Ok(Some(Value::integer(4))));
// }
#[test]
fn if_else_false() {
let source = "if 1 == 2 { panic() } else { 42 }";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::equal(true, 0, 1)
.set_b_is_constant()
.set_c_is_constant(),
Span(5, 7)
),
(Instruction::jump(3), Span(5, 7)),
(
Instruction::call_native(0, NativeFunction::Panic, 0),
Span(12, 19)
),
(Instruction::load_constant(0, 2, false), Span(29, 31)),
(Instruction::r#return(true), Span(33, 33)),
],
vec![Value::integer(1), Value::integer(2), Value::integer(42)],
vec![]
)),
);
assert_eq!(run(source), Ok(Some(Value::integer(42))));
}
#[test]
fn if_else_true() {
let source = "if 1 == 1 { 42 } else { panic() }";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::equal(true, 0, 1)
.set_b_is_constant()
.set_c_is_constant(),
Span(5, 7)
),
(Instruction::jump(3), Span(5, 7)),
(Instruction::load_constant(0, 2, false), Span(12, 14)),
(
Instruction::call_native(1, NativeFunction::Panic, 0),
Span(24, 31)
),
],
vec![Value::integer(1), Value::integer(1), Value::integer(42)],
vec![]
)),
);
assert_eq!(run(source), Ok(Some(Value::integer(42))));
}
#[test]
fn if_expression_false() {
let source = "if 1 == 2 { 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(5, 7)
),
(Instruction::jump(3), Span(5, 7)),
(Instruction::load_constant(0, 2, false), Span(12, 13)),
],
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!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::equal(true, 0, 1)
.set_b_is_constant()
.set_c_is_constant(),
Span(5, 7)
),
(Instruction::jump(3), Span(5, 7)),
(Instruction::load_constant(0, 2, false), Span(12, 13)),
],
vec![Value::integer(1), Value::integer(1), Value::integer(2)],
vec![]
)),
);
assert_eq!(run(source), Ok(None));
}

View File

@ -271,66 +271,6 @@ fn equal() {
assert_eq!(run(source), Ok(Some(Value::boolean(false)))); assert_eq!(run(source), Ok(Some(Value::boolean(false))));
} }
#[test]
fn equality_assignment_long() {
let source = "let a = if 4 == 4 { true } else { false }; a";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::equal(true, 0, 1)
.set_b_is_constant()
.set_c_is_constant(),
Span(13, 15)
),
(Instruction::jump(3), Span(13, 15)),
(Instruction::load_boolean(0, true, true), Span(20, 24)),
(Instruction::load_boolean(0, false, false), Span(34, 39)),
(Instruction::define_local(0, 0, false), Span(4, 5)),
(Instruction::get_local(1, 0), Span(43, 44)),
(Instruction::r#return(true), Span(44, 44)),
],
vec![Value::integer(4), Value::integer(4)],
vec![Local::new(Identifier::new("a"), None, false, 0, 0)]
)),
);
assert_eq!(run(source), Ok(Some(Value::boolean(true))));
}
#[test]
fn equality_assignment_short() {
let source = "let a = 4 == 4 a";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::equal(true, 0, 1)
.set_b_is_constant()
.set_c_is_constant(),
Span(10, 12)
),
(Instruction::jump(3), Span(10, 12)),
(Instruction::load_boolean(0, true, true), Span(10, 12)),
(Instruction::load_boolean(0, false, false), Span(10, 12)),
(Instruction::define_local(0, 0, false), Span(4, 5)),
(Instruction::get_local(1, 0), Span(15, 16)),
(Instruction::r#return(true), Span(16, 16)),
],
vec![Value::integer(4), Value::integer(4)],
vec![Local::new(Identifier::new("a"), None, false, 0, 0)]
)),
);
assert_eq!(run(source), Ok(Some(Value::boolean(true))));
}
#[test] #[test]
fn function() { fn function() {
let source = "fn(a: int, b: int) -> int { a + b }"; let source = "fn(a: int, b: int) -> int { a + b }";
@ -520,210 +460,6 @@ fn greater_than_or_equal() {
assert_eq!(run(source), Ok(Some(Value::boolean(false)))); assert_eq!(run(source), Ok(Some(Value::boolean(false))));
} }
#[test]
fn if_else_complex() {
let source = "
if 1 == 1 {
1; 2; 3; 4;
} else {
1; 2; 3; 4;
}";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::equal(true, 0, 1)
.set_b_is_constant()
.set_c_is_constant(),
Span(14, 16)
),
(Instruction::jump(7), Span(14, 16)),
(Instruction::load_constant(0, 2, false), Span(33, 34)),
(Instruction::load_constant(1, 3, false), Span(36, 37)),
(Instruction::load_constant(2, 4, false), Span(39, 40)),
(Instruction::load_constant(3, 5, false), Span(42, 43)),
(Instruction::jump(11), Span(95, 95)),
(Instruction::load_constant(4, 6, false), Span(74, 75)),
(Instruction::load_constant(5, 7, false), Span(77, 78)),
(Instruction::load_constant(6, 8, false), Span(80, 81)),
(Instruction::load_constant(7, 9, false), Span(83, 84)),
(Instruction::r#return(true), Span(95, 95)),
],
vec![
Value::integer(1),
Value::integer(1),
Value::integer(1),
Value::integer(2),
Value::integer(3),
Value::integer(4),
Value::integer(1),
Value::integer(2),
Value::integer(3),
Value::integer(4)
],
vec![]
))
)
}
// #[test]
// fn if_else_nested() {
// let source = r#"
// if 0 == 1 {
// if 0 == 2 {
// 1;
// } else {
// 2;
// }
// } else {
// if 0 == 3 {
// 3;
// } else {
// 4;
// }
// }"#;
// assert_eq!(
// parse(source),
// Ok(Chunk::with_data(
// None,
// vec![
// (
// *Instruction::equal(true, 0, 1)
// .set_b_is_constant()
// .set_c_is_constant(),
// Span(14, 16)
// ),
// (Instruction::jump(7), Span(14, 16)),
// (
// *Instruction::equal(true, 0, 2)
// .set_b_is_constant()
// .set_c_is_constant(),
// Span(38, 41)
// ),
// (Instruction::jump(3), Span(38, 41)),
// (Instruction::load_constant(0, 1, false), Span(61, 62)),
// (Instruction::jump(11), Span(95, 95)),
// (
// *Instruction::equal(true, 0, 3)
// .set_b_is_constant()
// .set_c_is_constant(),
// Span(77, 79)
// ),
// (Instruction::jump(3), Span(77, 79)),
// (Instruction::load_constant(0, 2, false), Span(94, 95)),
// (Instruction::jump(11), Span(95, 95)),
// (Instruction::load_constant(0, 3, false), Span(114, 115)),
// (Instruction::jump(11), Span(95, 95)),
// (Instruction::load_constant(0, 4, false), Span(134, 135)),
// (Instruction::r#return(true), Span(146, 146)),
// ],
// vec![
// Value::integer(0),
// Value::integer(1),
// Value::integer(0),
// Value::integer(2),
// Value::integer(1),
// Value::integer(0),
// Value::integer(3),
// Value::integer(3),
// Value::integer(4)
// ],
// vec![]
// ))
// );
// assert_eq!(run(source), Ok(Some(Value::integer(4))));
// }
#[test]
fn if_else_simple() {
let source = "if 1 == 1 { 2 } else { 3 }";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::equal(true, 0, 1)
.set_b_is_constant()
.set_c_is_constant(),
Span(5, 7)
),
(Instruction::jump(3), Span(5, 7)),
(Instruction::load_constant(0, 2, true), Span(12, 13)),
(Instruction::load_constant(0, 3, false), Span(23, 24)),
(Instruction::r#return(true), Span(26, 26)),
],
vec![
Value::integer(1),
Value::integer(1),
Value::integer(2),
Value::integer(3)
],
vec![]
)),
);
assert_eq!(run(source), Ok(Some(Value::integer(2))));
}
#[test]
fn if_expression_false() {
let source = "if 1 == 2 { 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(5, 7)
),
(Instruction::jump(3), Span(5, 7)),
(Instruction::load_constant(0, 2, false), Span(12, 13)),
],
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!(
parse(source),
Ok(Chunk::with_data(
None,
vec![
(
*Instruction::equal(true, 0, 1)
.set_b_is_constant()
.set_c_is_constant(),
Span(5, 7)
),
(Instruction::jump(3), Span(5, 7)),
(Instruction::load_constant(0, 2, false), Span(12, 13)),
],
vec![Value::integer(1), Value::integer(1), Value::integer(2)],
vec![]
)),
);
assert_eq!(run(source), Ok(None));
}
#[test] #[test]
fn less_than() { fn less_than() {
let source = "1 < 2"; let source = "1 < 2";