add defer
This commit is contained in:
@@ -2061,6 +2061,69 @@ missing_return :: func() i32 {
|
||||
testing.expect(t, missing)
|
||||
}
|
||||
|
||||
@(test)
|
||||
defer_compiles_and_runs :: proc(t: ^testing.T) {
|
||||
output := "/tmp/brolang-test-defer"
|
||||
defer _ = os.remove(output)
|
||||
status := compiler_core.compile_package("examples/programs/defer", output)
|
||||
testing.expect_value(t, status, 0)
|
||||
state := run_executable(output)
|
||||
// LIFO, runs on fall-through / break / continue / return (with the return value
|
||||
// captured before defers run), scoped bare blocks, and `defer { ... }` blocks
|
||||
// together produce 42.
|
||||
testing.expect_value(t, state.exit_code, 42)
|
||||
}
|
||||
|
||||
@(test)
|
||||
defer_misuse_is_diagnosed :: proc(t: ^testing.T) {
|
||||
// Deferring control flow that would escape the defer is rejected: `defer return`,
|
||||
// `defer break`, and a `return` inside a `defer { ... }` block.
|
||||
text := `main :: func() i32 {
|
||||
bad_defer_return()
|
||||
bad_defer_break()
|
||||
bad_return_in_defer()
|
||||
return 0
|
||||
}
|
||||
bad_defer_return :: func() void {
|
||||
defer return
|
||||
}
|
||||
bad_defer_break :: func() void {
|
||||
for 0..3 |i| {
|
||||
defer break
|
||||
_ = i
|
||||
}
|
||||
}
|
||||
bad_return_in_defer :: func() void {
|
||||
defer {
|
||||
return
|
||||
}
|
||||
}
|
||||
`
|
||||
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)
|
||||
|
||||
defer_return := false
|
||||
defer_break := false
|
||||
return_in_defer := false
|
||||
for diagnostic in diagnostics.items {
|
||||
defer_return = defer_return || strings.contains(diagnostic.message, "cannot defer a 'return' statement")
|
||||
defer_break = defer_break || strings.contains(diagnostic.message, "cannot defer a 'break' statement")
|
||||
return_in_defer = return_in_defer || strings.contains(diagnostic.message, "cannot 'return' inside a 'defer'")
|
||||
}
|
||||
testing.expect(t, defer_return)
|
||||
testing.expect(t, defer_break)
|
||||
testing.expect(t, return_in_defer)
|
||||
}
|
||||
|
||||
@(test)
|
||||
foreign_function_links_from_c_source :: proc(t: ^testing.T) {
|
||||
output := "/tmp/brolang-test-foreign-source"
|
||||
|
||||
Reference in New Issue
Block a user