contextual payload construction
This commit is contained in:
@@ -2514,6 +2514,181 @@ main func() i32 {
|
||||
testing.expect_value(t, compiler_core.compile_package(directory, output), 1)
|
||||
}
|
||||
|
||||
@(test)
|
||||
contextual_payload_variants_compile :: proc(t: ^testing.T) {
|
||||
text := `DetailError :: union(enum) {
|
||||
code i32
|
||||
empty void
|
||||
}
|
||||
make_payload func() i32 {
|
||||
return 7
|
||||
}
|
||||
accept func(value DetailError) i32 {
|
||||
match value {
|
||||
.code |n|: return n
|
||||
.empty: return 0
|
||||
}
|
||||
}
|
||||
make_code func(value i32) DetailError {
|
||||
return .code{value}
|
||||
}
|
||||
with_detail func(value i32) i32 ! DetailError {
|
||||
if (value == 0) return .code{5}
|
||||
if (value == 1) return .empty
|
||||
return value
|
||||
}
|
||||
main func() i32 {
|
||||
e DetailError = .code{3}
|
||||
recovered :: with_detail(0) catch |err| {
|
||||
match err {
|
||||
.code |n|: yield n
|
||||
.empty: yield 9
|
||||
}
|
||||
}
|
||||
return accept(e) + accept(.code{4}) + accept(make_code(5)) + accept(.code{make_payload()}) + recovered - 24
|
||||
}
|
||||
`
|
||||
source_file := source.Source{path="contextual_payload.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)
|
||||
ir_module := lower.lower(&hir_module)
|
||||
defer ir.destroy_module(&ir_module)
|
||||
llvm_text := llvm.emit(&ir_module, &diagnostics, &symbols)
|
||||
defer delete(llvm_text)
|
||||
|
||||
testing.expect_value(t, len(diagnostics.items), 0)
|
||||
testing.expect(t, strings.contains(llvm_text, "call void @llvm.memcpy.p0.p0.i64"))
|
||||
}
|
||||
|
||||
@(test)
|
||||
inline_fallible_error_types_compile :: proc(t: ^testing.T) {
|
||||
text := `inline_enum func(value i32) i32 ! enum {
|
||||
inline_bad
|
||||
inline_worse
|
||||
} {
|
||||
if (value == 0) return .inline_bad
|
||||
if (value < 0) return .inline_worse
|
||||
return value
|
||||
}
|
||||
inline_union func(value i32) i32 ! union(enum) {
|
||||
inline_code i32
|
||||
inline_empty void
|
||||
} {
|
||||
if (value == 0) return .inline_code{6}
|
||||
if (value == 1) return .inline_empty
|
||||
return value
|
||||
}
|
||||
main func() i32 {
|
||||
a :: inline_enum(0) catch |e| {
|
||||
if (e == .inline_bad) {
|
||||
yield 10
|
||||
} else {
|
||||
yield 11
|
||||
}
|
||||
}
|
||||
b :: inline_union(0) catch |e| {
|
||||
match e {
|
||||
.inline_code |n|: yield n
|
||||
.inline_empty: yield 12
|
||||
}
|
||||
}
|
||||
return a + b - 16
|
||||
}
|
||||
`
|
||||
source_file := source.Source{path="inline_errors.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)
|
||||
ir_module := lower.lower(&hir_module)
|
||||
defer ir.destroy_module(&ir_module)
|
||||
llvm_text := llvm.emit(&ir_module, &diagnostics, &symbols)
|
||||
defer delete(llvm_text)
|
||||
|
||||
testing.expect_value(t, len(diagnostics.items), 0)
|
||||
testing.expect(t, len(hir_module.functions) > 1)
|
||||
testing.expect(t, len(llvm_text) > 0)
|
||||
}
|
||||
|
||||
@(test)
|
||||
contextual_payload_variants_reject_bad_forms :: proc(t: ^testing.T) {
|
||||
text := `DetailError :: union(enum) {
|
||||
code i32
|
||||
empty void
|
||||
}
|
||||
missing_payload func() DetailError {
|
||||
return .code
|
||||
}
|
||||
void_payload func() DetailError {
|
||||
return .empty{1}
|
||||
}
|
||||
empty_payload func() DetailError {
|
||||
return .code{}
|
||||
}
|
||||
multi_payload func() DetailError {
|
||||
return .code{1, 2}
|
||||
}
|
||||
unknown_payload func() DetailError {
|
||||
return .missing{1}
|
||||
}
|
||||
no_context func() i32 {
|
||||
_ = .code{1}
|
||||
return 0
|
||||
}
|
||||
main func() i32 {
|
||||
_ = missing_payload()
|
||||
_ = void_payload()
|
||||
_ = empty_payload()
|
||||
_ = multi_payload()
|
||||
_ = unknown_payload()
|
||||
return no_context()
|
||||
}
|
||||
`
|
||||
source_file := source.Source{path="bad_contextual_payload.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)
|
||||
|
||||
found_missing := false
|
||||
found_void := false
|
||||
payload_arity_errors := 0
|
||||
found_unknown := false
|
||||
found_no_context := false
|
||||
for diagnostic in diagnostics.items {
|
||||
found_missing = found_missing || strings.contains(diagnostic.message, "needs a payload")
|
||||
found_void = found_void || strings.contains(diagnostic.message, "void variant 'empty' takes no value")
|
||||
payload_arity_errors += 1 if strings.contains(diagnostic.message, "requires exactly one expression") else 0
|
||||
found_unknown = found_unknown || strings.contains(diagnostic.message, "unknown variant '.missing'")
|
||||
found_no_context = found_no_context || strings.contains(diagnostic.message, "requires a tagged-union context")
|
||||
}
|
||||
testing.expect(t, found_missing)
|
||||
testing.expect(t, found_void)
|
||||
testing.expect(t, payload_arity_errors >= 2)
|
||||
testing.expect(t, found_unknown)
|
||||
testing.expect(t, found_no_context)
|
||||
}
|
||||
|
||||
@(test)
|
||||
errors_example_compiles_and_runs :: proc(t: ^testing.T) {
|
||||
output := "/tmp/brolang-test-errors"
|
||||
|
||||
Reference in New Issue
Block a user