anonymous struct payloads
This commit is contained in:
@@ -2568,6 +2568,90 @@ main func() i32 {
|
||||
testing.expect(t, strings.contains(llvm_text, "call void @llvm.memcpy.p0.p0.i64"))
|
||||
}
|
||||
|
||||
@(test)
|
||||
anonymous_struct_payloads_and_keyed_payload_sugar_compile :: proc(t: ^testing.T) {
|
||||
text := `PayloadError :: union(enum) {
|
||||
not_found struct {
|
||||
path i32
|
||||
line i32
|
||||
}
|
||||
wrapped struct {
|
||||
path i32
|
||||
line i32
|
||||
}
|
||||
scalar i32
|
||||
empty void
|
||||
}
|
||||
OtherError :: union(enum) {
|
||||
not_found struct {
|
||||
path i32
|
||||
line i32
|
||||
}
|
||||
other void
|
||||
}
|
||||
BothError :: alias PayloadError | OtherError
|
||||
accept func(value PayloadError) i32 {
|
||||
match value {
|
||||
.not_found |info|: return info.path + info.line
|
||||
.wrapped |info|: return info.path * 10 + info.line
|
||||
.scalar |n|: return n
|
||||
.empty: return 0
|
||||
}
|
||||
}
|
||||
with_payload func(value i32) i32 ! PayloadError {
|
||||
if (value == 0) return .not_found{path = 4, line = 5}
|
||||
if (value == 1) return .scalar{7}
|
||||
return value
|
||||
}
|
||||
inline_payload func(value i32) i32 ! union(enum) {
|
||||
inline_bad struct {
|
||||
code i32
|
||||
line i32
|
||||
}
|
||||
} {
|
||||
if (value == 0) return .inline_bad{code = 6, line = 7}
|
||||
return value
|
||||
}
|
||||
main func() i32 {
|
||||
e PayloadError = .not_found{path = 1, line = 2}
|
||||
a :: accept(e)
|
||||
b :: accept(.wrapped{line = 4, path = 3})
|
||||
c :: with_payload(0) catch |err| {
|
||||
match err {
|
||||
.not_found |info|: yield info.path + info.line
|
||||
.wrapped |info|: yield info.path + info.line
|
||||
.scalar |n|: yield n
|
||||
.empty: yield 0
|
||||
}
|
||||
}
|
||||
d :: inline_payload(0) catch |err| {
|
||||
match err {
|
||||
.inline_bad |info|: yield info.code + info.line
|
||||
}
|
||||
}
|
||||
return a + b + c + d - 59
|
||||
}
|
||||
`
|
||||
source_file := source.Source{path="anonymous_payloads.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(llvm_text) > 0)
|
||||
}
|
||||
|
||||
@(test)
|
||||
inline_fallible_error_types_compile :: proc(t: ^testing.T) {
|
||||
text := `inline_enum func(value i32) i32 ! enum {
|
||||
@@ -2689,6 +2773,77 @@ main func() i32 {
|
||||
testing.expect(t, found_no_context)
|
||||
}
|
||||
|
||||
@(test)
|
||||
anonymous_struct_payloads_reject_bad_forms :: proc(t: ^testing.T) {
|
||||
text := `Bad :: union(enum) {
|
||||
payload struct {
|
||||
x i32
|
||||
y i32
|
||||
}
|
||||
scalar i32
|
||||
}
|
||||
unknown func() Bad {
|
||||
return .payload{x = 1, z = 2}
|
||||
}
|
||||
duplicate func() Bad {
|
||||
return .payload{x = 1, x = 2, y = 3}
|
||||
}
|
||||
missing func() Bad {
|
||||
return .payload{x = 1}
|
||||
}
|
||||
scalar_keyed func() Bad {
|
||||
return .scalar{value = 1}
|
||||
}
|
||||
A :: union(enum) {
|
||||
dup struct {
|
||||
x i32
|
||||
}
|
||||
}
|
||||
B :: union(enum) {
|
||||
dup struct {
|
||||
x i64
|
||||
}
|
||||
}
|
||||
Conflict :: alias A | B
|
||||
main func() i32 {
|
||||
_ = unknown()
|
||||
_ = duplicate()
|
||||
_ = missing()
|
||||
_ = scalar_keyed()
|
||||
return 0
|
||||
}
|
||||
`
|
||||
source_file := source.Source{path="bad_anonymous_payloads.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_unknown := false
|
||||
found_duplicate := false
|
||||
found_missing := false
|
||||
found_keyed_non_struct := false
|
||||
found_conflict := false
|
||||
for diagnostic in diagnostics.items {
|
||||
found_unknown = found_unknown || strings.contains(diagnostic.message, "unknown struct field 'z'")
|
||||
found_duplicate = found_duplicate || strings.contains(diagnostic.message, "duplicate initializer for struct field 'x'")
|
||||
found_missing = found_missing || strings.contains(diagnostic.message, "missing initializer for struct field 'y'")
|
||||
found_keyed_non_struct = found_keyed_non_struct || strings.contains(diagnostic.message, "keyed contextual payload requires a struct payload")
|
||||
found_conflict = found_conflict || strings.contains(diagnostic.message, "same variant name")
|
||||
}
|
||||
testing.expect(t, found_unknown)
|
||||
testing.expect(t, found_duplicate)
|
||||
testing.expect(t, found_missing)
|
||||
testing.expect(t, found_keyed_non_struct)
|
||||
testing.expect(t, found_conflict)
|
||||
}
|
||||
|
||||
@(test)
|
||||
errors_example_compiles_and_runs :: proc(t: ^testing.T) {
|
||||
output := "/tmp/brolang-test-errors"
|
||||
|
||||
Reference in New Issue
Block a user