From 10abd91c85fd0f9ca16d5e63839632facd1bc5e6 Mon Sep 17 00:00:00 2001 From: Jeff Date: Wed, 30 Oct 2024 09:50:45 -0400 Subject: [PATCH] Add failing control flow test with new panic function --- dust-lang/src/instruction.rs | 24 ++- dust-lang/src/parser.rs | 2 +- dust-lang/tests/control_flow.rs | 293 ++++++++++++++++++++++++++++++++ dust-lang/tests/expressions.rs | 264 ---------------------------- 4 files changed, 310 insertions(+), 273 deletions(-) create mode 100644 dust-lang/tests/control_flow.rs diff --git a/dust-lang/src/instruction.rs b/dust-lang/src/instruction.rs index 6c23633..c7ea1bf 100644 --- a/dust-lang/src/instruction.rs +++ b/dust-lang/src/instruction.rs @@ -346,11 +346,10 @@ impl Instruction { } pub fn yields_value(&self) -> bool { - matches!( + if matches!( self.operation(), Operation::Add | Operation::Call - | Operation::CallNative | Operation::Divide | Operation::GetLocal | Operation::LoadBoolean @@ -362,7 +361,17 @@ impl Instruction { | Operation::Negate | Operation::Not | 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 { @@ -582,11 +591,12 @@ impl Instruction { let native_function = NativeFunction::from(self.b()); let argument_count = self.c(); let mut output = String::new(); + let native_function_name = native_function.as_str(); if native_function.returns_value() { - let native_function_name = native_function.as_str(); - output.push_str(&format!("R{} = {}(", to_register, native_function_name)); + } else { + output.push_str(&format!("{}(", native_function_name)); } if argument_count != 0 { @@ -601,9 +611,7 @@ impl Instruction { } } - if native_function.returns_value() { - output.push(')'); - } + output.push(')'); output } diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index 21a2bb8..15e2a6b 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -1101,7 +1101,7 @@ impl<'src> Parser<'src> { self.allow(Token::Comma)?; } - let end = self.current_position.1; + let end = self.previous_position.1; let to_register = self.next_register(); let argument_count = to_register - start_register; self.current_is_expression = native_function.returns_value(); diff --git a/dust-lang/tests/control_flow.rs b/dust-lang/tests/control_flow.rs new file mode 100644 index 0000000..057bd83 --- /dev/null +++ b/dust-lang/tests/control_flow.rs @@ -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)); +} diff --git a/dust-lang/tests/expressions.rs b/dust-lang/tests/expressions.rs index e9ca8d2..3434f42 100644 --- a/dust-lang/tests/expressions.rs +++ b/dust-lang/tests/expressions.rs @@ -271,66 +271,6 @@ fn equal() { 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] fn function() { 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)))); } -#[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] fn less_than() { let source = "1 < 2";