break and continue in loops
This commit is contained in:
@@ -2001,6 +2001,66 @@ control_flow_compiles_and_runs :: proc(t: ^testing.T) {
|
||||
testing.expect(t, strings.contains(string(stdout), "or-taken"))
|
||||
}
|
||||
|
||||
@(test)
|
||||
break_and_continue_compile_and_run :: proc(t: ^testing.T) {
|
||||
output := "/tmp/brolang-test-break-continue"
|
||||
defer _ = os.remove(output)
|
||||
status := compiler_core.compile_package("examples/programs/break_continue", output)
|
||||
testing.expect_value(t, status, 0)
|
||||
state := run_executable(output)
|
||||
// `while` break, range-for `continue`, nested innermost-targeting break, a
|
||||
// `continue` on the final element of an inclusive `u8` range (no overflow
|
||||
// trap), and an exitable `while true` together produce 42.
|
||||
testing.expect_value(t, state.exit_code, 42)
|
||||
}
|
||||
|
||||
@(test)
|
||||
break_and_continue_misuse_is_diagnosed :: proc(t: ^testing.T) {
|
||||
// `break`/`continue` outside any loop are rejected, and a non-void function
|
||||
// that exits a `while true` via `break` without returning is flagged as
|
||||
// missing a return (the `all_paths_return` refinement).
|
||||
text := `main :: func() i32 {
|
||||
bad_break()
|
||||
bad_continue()
|
||||
return missing_return()
|
||||
}
|
||||
bad_break :: func() void {
|
||||
break
|
||||
}
|
||||
bad_continue :: func() void {
|
||||
continue
|
||||
}
|
||||
missing_return :: func() i32 {
|
||||
while true {
|
||||
break
|
||||
}
|
||||
}
|
||||
`
|
||||
source_file := source.Source{path="test.bro", text=text}
|
||||
diagnostics := source.init_diagnostics(&source_file)
|
||||
defer source.destroy_diagnostics(&diagnostics)
|
||||
symbols := symbol.init_table()
|
||||
defer symbol.destroy_table(&symbols)
|
||||
stream := lexer.lex(&source_file, &diagnostics, &symbols)
|
||||
defer delete(stream.items)
|
||||
ast_module := parser.parse(&stream, &source_file, &diagnostics)
|
||||
defer ast.destroy_module(&ast_module)
|
||||
hir_module := checker.check(&ast_module, &diagnostics, &symbols)
|
||||
defer hir.destroy_module(&hir_module)
|
||||
|
||||
break_outside := false
|
||||
continue_outside := false
|
||||
missing := false
|
||||
for diagnostic in diagnostics.items {
|
||||
break_outside = break_outside || strings.contains(diagnostic.message, "'break' outside of a loop")
|
||||
continue_outside = continue_outside || strings.contains(diagnostic.message, "'continue' outside of a loop")
|
||||
missing = missing || strings.contains(diagnostic.message, "'missing_return' does not return a value")
|
||||
}
|
||||
testing.expect(t, break_outside)
|
||||
testing.expect(t, continue_outside)
|
||||
testing.expect(t, missing)
|
||||
}
|
||||
|
||||
@(test)
|
||||
foreign_function_links_from_c_source :: proc(t: ^testing.T) {
|
||||
output := "/tmp/brolang-test-foreign-source"
|
||||
|
||||
Reference in New Issue
Block a user