diff --git a/src/protocol/tests/parser_validation.rs b/src/protocol/tests/parser_validation.rs index 6097189b80e9c09c378adf4323dcd43b49e0ad33..6cc4e99196c67d163d5265831256da171defe96e 100644 --- a/src/protocol/tests/parser_validation.rs +++ b/src/protocol/tests/parser_validation.rs @@ -4,6 +4,8 @@ use super::*; + + #[test] fn test_correct_struct_instance() { Tester::new_single_source_expect_ok( @@ -634,4 +636,110 @@ fn test_incorrect_select_statement() { sync select { auto a = get(rx) -> {} } }" ); +} + +#[test] +fn test_incorrect_goto_statement() { + Tester::new_single_source_expect_err( + "goto missing var in same scope", + "func f() -> u32 { + goto exit; + auto v = 5; + exit: return 0; + }" + ).error(|e| { e + .assert_num(3) + .assert_occurs_at(0, "exit;").assert_msg_has(0, "skips over a variable") + .assert_occurs_at(1, "exit:").assert_msg_has(1, "jumps to this label") + .assert_occurs_at(2, "v = 5").assert_msg_has(2, "skips over this variable"); + }); + + Tester::new_single_source_expect_err( + "goto missing var in outer scope", + "func f() -> u32 { + if (true) { + goto exit; + } + auto v = 0; + exit: return 1; + }" + ).error(|e| { e + .assert_num(3) + .assert_occurs_at(0, "exit;").assert_msg_has(0, "skips over a variable") + .assert_occurs_at(1, "exit:").assert_msg_has(1, "jumps to this label") + .assert_occurs_at(2, "v = 0").assert_msg_has(2, "skips over this variable"); + }); + + Tester::new_single_source_expect_err( + "goto jumping into scope", + "func f() -> u32 { + goto nested; + { + nested: return 0; + } + return 1; + }" + ).error(|e| { e + .assert_num(1) + .assert_occurs_at(0, "nested;") + .assert_msg_has(0, "could not find this label"); + }); + + Tester::new_single_source_expect_err( + "goto jumping outside sync", + "primitive f() { + sync { goto exit; } + exit: u32 v = 0; + }" + ).error(|e| { e + .assert_num(3) + .assert_occurs_at(0, "goto exit;").assert_msg_has(0, "not escape the surrounding sync") + .assert_occurs_at(1, "exit: u32 v").assert_msg_has(1, "target of the goto") + .assert_occurs_at(2, "sync {").assert_msg_has(2, "jump past this"); + }) +} + +#[test] +fn test_incorrect_while_statement() { + // Just testing the error cases caught at compile-time. Other ones need + // evaluation testing + Tester::new_single_source_expect_err( + "break wrong earlier loop", + "func f() -> u32 { + target: while (true) {} + while (true) { break target; } + return 0; + }" + ).error(|e| { e + .assert_num(2) + .assert_occurs_at(0, "target; }").assert_msg_has(0, "not nested under the target") + .assert_occurs_at(1, "target: while").assert_msg_has(1, "is found here"); + }); + + Tester::new_single_source_expect_err( + "break wrong later loop", + "func f() -> u32 { + while (true) { break target; } + target: while (true) {} + return 0; + }" + ).error(|e| { e + .assert_num(2) + .assert_occurs_at(0, "target; }").assert_msg_has(0, "not nested under the target") + .assert_occurs_at(1, "target: while").assert_msg_has(1, "is found here"); + }); + + Tester::new_single_source_expect_err( + "break outside of sync", + "primitive f() { + outer: while (true) { //mark + sync while(true) { break outer; } + } + }" + ).error(|e| { e + .assert_num(3) + .assert_occurs_at(0, "break outer;").assert_msg_has(0, "may not escape the surrounding") + .assert_occurs_at(1, "while (true) { //mark").assert_msg_has(1, "escapes out of this loop") + .assert_occurs_at(2, "sync while").assert_msg_has(2, "escape this synchronous block"); + }); } \ No newline at end of file