allocation related primitives
This commit is contained in:
+165
-10
@@ -1294,6 +1294,160 @@ immutable_pointer_and_slice_bindings_preserve_mutable_pointees :: proc(t: ^testi
|
||||
testing.expect_value(t, len(diagnostics.items), 0)
|
||||
}
|
||||
|
||||
@(test)
|
||||
many_item_pointer_slices_compile_and_run :: proc(t: ^testing.T) {
|
||||
directory := "/tmp/brolang-test-pointer-slices"
|
||||
main_path := "/tmp/brolang-test-pointer-slices/main.bro"
|
||||
output := "/tmp/brolang-test-pointer-slices-output"
|
||||
text := `main func() i32 {
|
||||
values [4]mut i32 = [3, 4, 5, 6]
|
||||
pointer *mut i32 :: (&values).ptr
|
||||
const_pointer *i32 :: pointer
|
||||
all []mut i32 :: pointer[..4]
|
||||
middle []mut i32 :: pointer[1..3]
|
||||
readonly []i32 :: const_pointer[..2]
|
||||
|
||||
if (all.len != 4) return 1
|
||||
if (middle.len != 2) return 2
|
||||
all[0] = 10
|
||||
if (readonly[0] != 10) return 3
|
||||
if (middle.ptr[0] != 4) return 4
|
||||
return 0
|
||||
}
|
||||
`
|
||||
_ = os2.remove_all(directory)
|
||||
defer _ = os2.remove_all(directory)
|
||||
defer _ = os.remove(output)
|
||||
testing.expect(t, os.make_directory(directory) == nil)
|
||||
testing.expect(t, os.write_entire_file(main_path, transmute([]byte)text))
|
||||
status := compiler_core.compile_package(directory, output)
|
||||
testing.expect_value(t, status, 0)
|
||||
state := run_executable(output)
|
||||
testing.expect_value(t, state.exit_code, 0)
|
||||
}
|
||||
|
||||
@(test)
|
||||
many_item_pointer_slices_require_end_bound :: proc(t: ^testing.T) {
|
||||
text := `main func() void {
|
||||
values [2]i32 = [1, 2]
|
||||
pointer *i32 :: (&values).ptr
|
||||
_ = pointer[..]
|
||||
_ = pointer[1..]
|
||||
}
|
||||
`
|
||||
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)
|
||||
|
||||
end_bound_errors := 0
|
||||
for diagnostic in diagnostics.items {
|
||||
if strings.contains(diagnostic.message, "many-item pointer slicing requires an explicit end bound") {
|
||||
end_bound_errors += 1
|
||||
}
|
||||
}
|
||||
testing.expect_value(t, end_bound_errors, 2)
|
||||
}
|
||||
|
||||
@(test)
|
||||
layout_builtins_compile_and_run :: proc(t: ^testing.T) {
|
||||
directory := "/tmp/brolang-test-layout-builtins"
|
||||
main_path := "/tmp/brolang-test-layout-builtins/main.bro"
|
||||
output := "/tmp/brolang-test-layout-builtins-output"
|
||||
text := `Point :: struct {
|
||||
x i32
|
||||
y u8
|
||||
}
|
||||
|
||||
Opaque :: opaque
|
||||
Color :: enum {
|
||||
red
|
||||
blue
|
||||
}
|
||||
UserID :: distinct u32
|
||||
SIZE_GLOBAL :: size_of(i32)
|
||||
|
||||
needs_usize func(value usize) usize {
|
||||
return value
|
||||
}
|
||||
|
||||
buffer func($T type) [size_of(T)]u8 {
|
||||
data [size_of(T)]u8 = undefined
|
||||
return data
|
||||
}
|
||||
|
||||
main func() i32 {
|
||||
bytes [_]u8 :: buffer(i32)
|
||||
if (needs_usize(SIZE_GLOBAL) != 4) return 1
|
||||
if (bytes.len != 4) return 2
|
||||
if (size_of([3]u8) != 3) return 3
|
||||
if (size_of([]u8) != 16) return 4
|
||||
if (align_of([]u8) != 8) return 5
|
||||
if (size_of(*anyopaque) != 8) return 6
|
||||
if (size_of(?*i32) != 8) return 7
|
||||
if (size_of(*Opaque) != 8) return 8
|
||||
if (size_of(Color) != 2) return 9
|
||||
if (align_of(Color) != 2) return 10
|
||||
if (size_of(Point) != 8) return 11
|
||||
if (align_of(Point) != 4) return 12
|
||||
if (size_of(UserID) != 4) return 13
|
||||
if (align_of(UserID) != 4) return 14
|
||||
return 0
|
||||
}
|
||||
`
|
||||
_ = os2.remove_all(directory)
|
||||
defer _ = os2.remove_all(directory)
|
||||
defer _ = os.remove(output)
|
||||
testing.expect(t, os.make_directory(directory) == nil)
|
||||
testing.expect(t, os.write_entire_file(main_path, transmute([]byte)text))
|
||||
status := compiler_core.compile_package(directory, output)
|
||||
testing.expect_value(t, status, 0)
|
||||
state := run_executable(output)
|
||||
testing.expect_value(t, state.exit_code, 0)
|
||||
}
|
||||
|
||||
@(test)
|
||||
layout_builtins_reject_unsized_targets :: proc(t: ^testing.T) {
|
||||
text := `Opaque :: opaque
|
||||
Fn :: alias func() void
|
||||
|
||||
main func() void {
|
||||
_ = size_of(void)
|
||||
_ = align_of(anyopaque)
|
||||
_ = size_of(Fn)
|
||||
_ = size_of(Opaque)
|
||||
_ = align_of(1)
|
||||
}
|
||||
`
|
||||
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)
|
||||
|
||||
bad_layout_targets := 0
|
||||
target_type_error := false
|
||||
for diagnostic in diagnostics.items {
|
||||
bad_layout_targets += 1 if strings.contains(diagnostic.message, "layout target must be a sized runtime value type") else 0
|
||||
target_type_error = target_type_error || strings.contains(diagnostic.message, "layout target must be a type")
|
||||
}
|
||||
testing.expect_value(t, bad_layout_targets, 4)
|
||||
testing.expect(t, target_type_error)
|
||||
}
|
||||
|
||||
@(test)
|
||||
slicing_an_array_variable_takes_its_address_implicitly :: proc(t: ^testing.T) {
|
||||
// Milestone 10: `arr[a..b]` on an array variable slices without an explicit
|
||||
@@ -3109,7 +3263,7 @@ allocator_contract_compiles_and_runs :: proc(t: ^testing.T) {
|
||||
}
|
||||
|
||||
@(test)
|
||||
allocator_contract_heap_global_lowers :: proc(t: ^testing.T) {
|
||||
allocator_contract_c_allocator_global_lowers :: proc(t: ^testing.T) {
|
||||
sources := source.init_store()
|
||||
defer source.destroy_store(&sources)
|
||||
diagnostics := source.init_store_diagnostics(&sources)
|
||||
@@ -3125,15 +3279,15 @@ allocator_contract_heap_global_lowers :: proc(t: ^testing.T) {
|
||||
ir_module := lower.lower(&hir_module)
|
||||
defer ir.destroy_module(&ir_module)
|
||||
|
||||
found_heap := false
|
||||
found_c_allocator := false
|
||||
found_anyopaque_context := false
|
||||
found_alloc_callback := false
|
||||
found_free_callback := false
|
||||
for global in hir_module.globals {
|
||||
if symbol.resolve(&symbols, global.name) != "heap" {
|
||||
if symbol.resolve(&symbols, global.name) != "c_allocator" {
|
||||
continue
|
||||
}
|
||||
found_heap = true
|
||||
found_c_allocator = true
|
||||
for field in types.fields_for(&hir_module.types, global.type) {
|
||||
name := symbol.resolve(&symbols, symbol.Id(field.name))
|
||||
callback_pointer, _, _, callable := types.function_pointer(field.type, &hir_module.types)
|
||||
@@ -3155,31 +3309,31 @@ allocator_contract_heap_global_lowers :: proc(t: ^testing.T) {
|
||||
|
||||
testing.expect_value(t, len(diagnostics.items), 0)
|
||||
testing.expect(t, len(ir_module.functions) > 0)
|
||||
testing.expect(t, found_heap)
|
||||
testing.expect(t, found_c_allocator)
|
||||
testing.expect(t, found_anyopaque_context)
|
||||
testing.expect(t, found_alloc_callback)
|
||||
testing.expect(t, found_free_callback)
|
||||
}
|
||||
|
||||
@(test)
|
||||
milestone_25_heap_compiles_and_runs :: proc(t: ^testing.T) {
|
||||
output := "/tmp/brolang-test-heap"
|
||||
milestone_25_c_allocator_compiles_and_runs :: proc(t: ^testing.T) {
|
||||
output := "/tmp/brolang-test-c-allocator"
|
||||
defer _ = os.remove(output)
|
||||
status := compiler_core.compile_package("examples/programs/heap", output, nil, target.DEFAULT, cimport.Options{}, ".")
|
||||
status := compiler_core.compile_package("examples/programs/mem_allocator", output, nil, target.DEFAULT, cimport.Options{}, ".")
|
||||
testing.expect_value(t, status, 0)
|
||||
state := run_executable(output)
|
||||
testing.expect_value(t, state.exit_code, 0)
|
||||
}
|
||||
|
||||
@(test)
|
||||
milestone_25_heap_emits_libc_alloc_declarations :: proc(t: ^testing.T) {
|
||||
milestone_25_c_allocator_emits_libc_alloc_declarations :: proc(t: ^testing.T) {
|
||||
sources := source.init_store()
|
||||
defer source.destroy_store(&sources)
|
||||
diagnostics := source.init_store_diagnostics(&sources)
|
||||
defer source.destroy_diagnostics(&diagnostics)
|
||||
symbols := symbol.init_table()
|
||||
defer symbol.destroy_table(&symbols)
|
||||
ast_module, loaded := loader.load("examples/programs/heap", &sources, &diagnostics, &symbols, context.allocator, context.allocator, cimport.Options{}, target.DEFAULT, ".")
|
||||
ast_module, loaded := loader.load("examples/programs/mem_allocator", &sources, &diagnostics, &symbols, context.allocator, context.allocator, cimport.Options{}, target.DEFAULT, ".")
|
||||
defer ast.destroy_module(&ast_module)
|
||||
testing.expect(t, loaded)
|
||||
|
||||
@@ -3192,6 +3346,7 @@ milestone_25_heap_emits_libc_alloc_declarations :: proc(t: ^testing.T) {
|
||||
|
||||
testing.expect_value(t, len(diagnostics.items), 0)
|
||||
testing.expect(t, strings.contains(llvm_text, "declare ptr @malloc(i64)"))
|
||||
testing.expect(t, strings.contains(llvm_text, "declare i32 @posix_memalign(ptr, i64, i64)"))
|
||||
testing.expect(t, strings.contains(llvm_text, "declare void @free(ptr)"))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user