bug fixes
This commit is contained in:
@@ -732,12 +732,23 @@
|
|||||||
- deferred: build graph / steps / caching, multiple artifacts, computed paths
|
- deferred: build graph / steps / caching, multiple artifacts, computed paths
|
||||||
(needs string building), struct field defaults to drop `&[]` on empty lists
|
(needs string building), struct field defaults to drop `&[]` on empty lists
|
||||||
|
|
||||||
29. basic `std/arraylist` implementation using the new `std/mem` typed allocation
|
29. fix bugs (implemented)
|
||||||
|
- `return _` was already the supported empty return for void functions; the original
|
||||||
|
bare-`return` report was stale
|
||||||
|
- catch value blocks may end by returning from the function instead of yielding when
|
||||||
|
every path exits
|
||||||
|
- implicit-conversion diagnostics render source-level composite and named types instead
|
||||||
|
of internal `<type N>` ids
|
||||||
|
- aliases resolve transparently in value contexts, including composed enum/union sums
|
||||||
|
- final open-constant defaults feed one last inference fixpoint before stale
|
||||||
|
specializations are pruned
|
||||||
|
|
||||||
30. disallow arbitrary integer division
|
30. basic `std/arraylist` implementation using the new `std/mem` typed allocation
|
||||||
|
|
||||||
|
31. disallow arbitrary integer division
|
||||||
- take inspiration from zig
|
- take inspiration from zig
|
||||||
- see also below for a word on unchecked casts
|
- see also below for a word on unchecked casts
|
||||||
- the user should be explicit about what they mean with integer division (e.g. `div`, `rem`)
|
- the user should be explicit about what they mean with integer division (e.g. `div`, `rem`, `trunc`)
|
||||||
|
|
||||||
## A word on unchecked casts
|
## A word on unchecked casts
|
||||||
|
|
||||||
|
|||||||
+131
-30
@@ -265,14 +265,100 @@ record_unused_locals :: proc(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// type_label renders a type for a diagnostic, resolving a named type (enum/union/struct/
|
write_type_label :: proc(checker: ^Checker, builder: ^strings.Builder, value: types.Type) {
|
||||||
// distinct) to its declared source name; primitives and unnamed types fall back to
|
store := &checker.module.types
|
||||||
// `types.name` (which prints `<type N>` for anonymous nodes).
|
item, ok := types.node(store, value)
|
||||||
type_label :: proc(checker: ^Checker, value: types.Type) -> string {
|
if !ok {
|
||||||
if node, ok := types.node(&checker.module.types, value); ok && node.name != 0 {
|
strings.write_string(builder, types.name(value))
|
||||||
return symbol_text(checker, symbol.Id(node.name))
|
return
|
||||||
}
|
}
|
||||||
return types.name(value)
|
if item.name != 0 {
|
||||||
|
strings.write_string(builder, symbol_text(checker, symbol.Id(item.name)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch item.kind {
|
||||||
|
case .Array:
|
||||||
|
strings.write_byte(builder, '[')
|
||||||
|
if item.inferred_count {
|
||||||
|
strings.write_byte(builder, '_')
|
||||||
|
} else {
|
||||||
|
fmt.sbprintf(builder, "%d", item.count)
|
||||||
|
}
|
||||||
|
if item.has_sentinel {
|
||||||
|
fmt.sbprintf(builder, ";%d", item.sentinel)
|
||||||
|
}
|
||||||
|
strings.write_byte(builder, ']')
|
||||||
|
if item.mutable {
|
||||||
|
strings.write_string(builder, "mut ")
|
||||||
|
}
|
||||||
|
write_type_label(checker, builder, item.child)
|
||||||
|
case .Pointer:
|
||||||
|
if item.has_sentinel {
|
||||||
|
fmt.sbprintf(builder, "[*;%d]", item.sentinel)
|
||||||
|
} else {
|
||||||
|
strings.write_byte(builder, '*' if item.many else '@')
|
||||||
|
}
|
||||||
|
if item.mutable {
|
||||||
|
strings.write_string(builder, "mut ")
|
||||||
|
}
|
||||||
|
write_type_label(checker, builder, item.child)
|
||||||
|
case .Slice:
|
||||||
|
if item.has_sentinel {
|
||||||
|
fmt.sbprintf(builder, "[;%d]", item.sentinel)
|
||||||
|
} else {
|
||||||
|
strings.write_string(builder, "[]")
|
||||||
|
}
|
||||||
|
if item.mutable {
|
||||||
|
strings.write_string(builder, "mut ")
|
||||||
|
}
|
||||||
|
write_type_label(checker, builder, item.child)
|
||||||
|
case .Range:
|
||||||
|
strings.write_string(builder, "range(")
|
||||||
|
write_type_label(checker, builder, item.child)
|
||||||
|
strings.write_byte(builder, ')')
|
||||||
|
case .Optional:
|
||||||
|
strings.write_byte(builder, '?')
|
||||||
|
write_type_label(checker, builder, item.child)
|
||||||
|
case .Function:
|
||||||
|
strings.write_string(builder, "c_func(" if item.c_abi else "func(")
|
||||||
|
for param, index in types.params_for(store, value) {
|
||||||
|
if index > 0 {
|
||||||
|
strings.write_string(builder, ", ")
|
||||||
|
}
|
||||||
|
write_type_label(checker, builder, param.type)
|
||||||
|
}
|
||||||
|
if item.variadic {
|
||||||
|
if item.field_count > 0 {
|
||||||
|
strings.write_string(builder, ", ")
|
||||||
|
}
|
||||||
|
strings.write_string(builder, "...")
|
||||||
|
}
|
||||||
|
strings.write_string(builder, ") ")
|
||||||
|
write_type_label(checker, builder, item.child)
|
||||||
|
case .Fallible:
|
||||||
|
write_type_label(checker, builder, item.child)
|
||||||
|
strings.write_string(builder, " ! ")
|
||||||
|
write_type_label(checker, builder, item.extra)
|
||||||
|
case .Struct:
|
||||||
|
strings.write_string(builder, "struct")
|
||||||
|
case .Union:
|
||||||
|
strings.write_string(builder, "union")
|
||||||
|
case .Enum:
|
||||||
|
strings.write_string(builder, "enum")
|
||||||
|
case .Alias, .Distinct, .Named:
|
||||||
|
write_type_label(checker, builder, item.child)
|
||||||
|
case .Invalid, .Void, .Anyopaque, .Int_Constraint, .Float_Constraint, .Range_Constraint, .Scalar:
|
||||||
|
strings.write_string(builder, types.name(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render dynamic types using source syntax so diagnostics never expose internal
|
||||||
|
// type-store ids such as `<type 230>`.
|
||||||
|
type_label :: proc(checker: ^Checker, value: types.Type) -> string {
|
||||||
|
builder := strings.builder_make(context.temp_allocator)
|
||||||
|
write_type_label(checker, &builder, value)
|
||||||
|
return strings.to_string(builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
is_ptr_cast_call :: proc(checker: ^Checker, expr: ast.Expr) -> bool {
|
is_ptr_cast_call :: proc(checker: ^Checker, expr: ast.Expr) -> bool {
|
||||||
@@ -460,6 +546,8 @@ type_from_syntax :: proc(
|
|||||||
store := &checker.module.types
|
store := &checker.module.types
|
||||||
changed := false
|
changed := false
|
||||||
#partial switch item.kind {
|
#partial switch item.kind {
|
||||||
|
case .Alias:
|
||||||
|
return type_from_syntax(checker, item.child, pkg, file, depth+1)
|
||||||
case .Array:
|
case .Array:
|
||||||
child := type_from_syntax(checker, item.child, pkg, file, depth+1)
|
child := type_from_syntax(checker, item.child, pkg, file, depth+1)
|
||||||
changed = changed || child != item.child
|
changed = changed || child != item.child
|
||||||
@@ -3246,6 +3334,7 @@ infer_all :: proc(checker: ^Checker) {
|
|||||||
ensure_spec(checker, main_template, nil)
|
ensure_spec(checker, main_template, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defaults_applied := false
|
||||||
for {
|
for {
|
||||||
changed := false
|
changed := false
|
||||||
checker.global_demands_dirty = false
|
checker.global_demands_dirty = false
|
||||||
@@ -3334,22 +3423,30 @@ infer_all :: proc(checker: ^Checker) {
|
|||||||
changed = true
|
changed = true
|
||||||
}
|
}
|
||||||
if !changed {
|
if !changed {
|
||||||
|
if !defaults_applied {
|
||||||
|
defaults_applied = true
|
||||||
|
defaulted := false
|
||||||
|
// No authoritative demand can still arrive. Assign final defaults, then
|
||||||
|
// continue the same fixpoint so dependent globals/specs observe them.
|
||||||
|
for global, index in checker.ast_module.globals {
|
||||||
|
if global.external || is_runtime_type(checker, checker.global_types[index]) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if checker.global_open_const[index] {
|
||||||
|
checker.global_types[index] = types.smallest_signed_for_literal(i64(checker.global_const_value[index]))
|
||||||
|
defaulted = true
|
||||||
|
} else if checker.global_open_float[index] {
|
||||||
|
checker.global_types[index] = types.F64
|
||||||
|
defaulted = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if defaulted {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Any open constant that no use ever demanded now takes its default: an integer
|
|
||||||
// constant the smallest signed type that holds its value, a float constant f64.
|
|
||||||
for global, index in checker.ast_module.globals {
|
|
||||||
if global.external || is_runtime_type(checker, checker.global_types[index]) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if checker.global_open_const[index] {
|
|
||||||
checker.global_types[index] = types.smallest_signed_for_literal(i64(checker.global_const_value[index]))
|
|
||||||
} else if checker.global_open_float[index] {
|
|
||||||
checker.global_types[index] = types.F64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
prune_specs :: proc(checker: ^Checker) {
|
prune_specs :: proc(checker: ^Checker) {
|
||||||
@@ -3604,8 +3701,8 @@ coerce_expr :: proc(
|
|||||||
checker.diagnostics,
|
checker.diagnostics,
|
||||||
span,
|
span,
|
||||||
"cannot implicitly convert %s to %s",
|
"cannot implicitly convert %s to %s",
|
||||||
types.name(actual),
|
type_label(checker, actual),
|
||||||
types.name(expected),
|
type_label(checker, expected),
|
||||||
)
|
)
|
||||||
return invalid_hir_expr(checker, span, id, expected)
|
return invalid_hir_expr(checker, span, id, expected)
|
||||||
}
|
}
|
||||||
@@ -4533,7 +4630,7 @@ build_compound_expr :: proc(
|
|||||||
}
|
}
|
||||||
handler: [dynamic]hir.Stmt_Id
|
handler: [dynamic]hir.Stmt_Id
|
||||||
handler.allocator = checker.allocator
|
handler.allocator = checker.allocator
|
||||||
fallback, _ = build_value_source(ctx, &handler, expr.body, success, expr.span)
|
fallback, _ = build_value_source(ctx, &handler, expr.body, success, expr.span, allow_exit=true)
|
||||||
body = handler[:]
|
body = handler[:]
|
||||||
resize(ctx.locals, capture_start)
|
resize(ctx.locals, capture_start)
|
||||||
}
|
}
|
||||||
@@ -6683,18 +6780,17 @@ build_block :: proc(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// build_value_block builds a `{ ... yield v }` value block whose final statement
|
// build_value_block builds a `{ ... yield v }` value block whose final statement
|
||||||
// must be a `yield`: it builds the leading statements inline (their own scope and
|
// must be a `yield`. Catch handlers may instead exit on every path, in which case
|
||||||
// defers), evaluates the yield expression in that scope, then — capturing the value
|
// `allow_exit` leaves the fallback expression invalid. Otherwise it builds the leading
|
||||||
// first, like a function return — runs the block's defers and closes the scope. The
|
// statements inline, evaluates the yield in their scope, then captures the value before
|
||||||
// resulting `value`/`value_type` are spliced into the enclosing declaration or
|
// running defers. `expected` is the binding's type (INVALID for an untyped `::`).
|
||||||
// assignment. `expected` is the binding's type (INVALID for an untyped `::`, where
|
|
||||||
// the yield's natural type is taken). Statements are appended to `body`.
|
|
||||||
build_value_block :: proc(
|
build_value_block :: proc(
|
||||||
ctx: ^Build_Ctx,
|
ctx: ^Build_Ctx,
|
||||||
body: ^[dynamic]hir.Stmt_Id,
|
body: ^[dynamic]hir.Stmt_Id,
|
||||||
body_stmts: []ast.Stmt_Id,
|
body_stmts: []ast.Stmt_Id,
|
||||||
expected: types.Type,
|
expected: types.Type,
|
||||||
span: source.Span,
|
span: source.Span,
|
||||||
|
allow_exit := false,
|
||||||
) -> (value: hir.Expr_Id, value_type: types.Type) {
|
) -> (value: hir.Expr_Id, value_type: types.Type) {
|
||||||
checker := ctx.checker
|
checker := ctx.checker
|
||||||
n := len(body_stmts)
|
n := len(body_stmts)
|
||||||
@@ -6705,6 +6801,10 @@ build_value_block :: proc(
|
|||||||
for s in inner {
|
for s in inner {
|
||||||
append(body, s)
|
append(body, s)
|
||||||
}
|
}
|
||||||
|
if allow_exit && all_paths_exit(&checker.module, inner) {
|
||||||
|
delete(inner, checker.allocator)
|
||||||
|
return hir.INVALID_EXPR, expected
|
||||||
|
}
|
||||||
delete(inner, checker.allocator)
|
delete(inner, checker.allocator)
|
||||||
id := source.add(checker.diagnostics, span, "a value block must end with an explicit 'yield'")
|
id := source.add(checker.diagnostics, span, "a value block must end with an explicit 'yield'")
|
||||||
ctx.problematic^ = true
|
ctx.problematic^ = true
|
||||||
@@ -6782,6 +6882,7 @@ build_value_source :: proc(
|
|||||||
span: source.Span,
|
span: source.Span,
|
||||||
label := symbol.INVALID,
|
label := symbol.INVALID,
|
||||||
value_control_flow := false,
|
value_control_flow := false,
|
||||||
|
allow_exit := false,
|
||||||
) -> (value: hir.Expr_Id, value_type: types.Type) {
|
) -> (value: hir.Expr_Id, value_type: types.Type) {
|
||||||
checker := ctx.checker
|
checker := ctx.checker
|
||||||
if symbol.is_valid(label) {
|
if symbol.is_valid(label) {
|
||||||
@@ -6797,7 +6898,7 @@ build_value_source :: proc(
|
|||||||
return build_value_match(ctx, body, body_stmts[0], expected, span)
|
return build_value_match(ctx, body, body_stmts[0], expected, span)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return build_value_block(ctx, body, body_stmts, expected, span)
|
return build_value_block(ctx, body, body_stmts, expected, span, allow_exit)
|
||||||
}
|
}
|
||||||
|
|
||||||
// new_value_slot allocates a fresh, un-nameable mutable local to hold a value-if/loop
|
// new_value_slot allocates a fresh, un-nameable mutable local to hold a value-if/loop
|
||||||
|
|||||||
@@ -132,7 +132,8 @@ Expr :: struct {
|
|||||||
integer: i64,
|
integer: i64,
|
||||||
args: []Expr_Id,
|
args: []Expr_Id,
|
||||||
// `Catch` block handlers use `body` for the handler statements and `target`
|
// `Catch` block handlers use `body` for the handler statements and `target`
|
||||||
// for the optional captured error local.
|
// for the optional captured error local. A missing `right` means the handler
|
||||||
|
// exits on every path and therefore has no fallback value.
|
||||||
body: []Stmt_Id,
|
body: []Stmt_Id,
|
||||||
target: Ref,
|
target: Ref,
|
||||||
left: Expr_Id,
|
left: Expr_Id,
|
||||||
|
|||||||
+12
-10
@@ -466,16 +466,18 @@ lower_compound_expr :: proc(state: ^State, expr_id: hir.Expr_Id) -> ir.Instructi
|
|||||||
}
|
}
|
||||||
lower_statements(state, expr.body)
|
lower_statements(state, expr.body)
|
||||||
}
|
}
|
||||||
fallback := lower_nested_expr(state, expr.right)
|
if expr.right != hir.INVALID_EXPR {
|
||||||
append_instruction(state, ir.Instruction{
|
fallback := lower_nested_expr(state, expr.right)
|
||||||
op=.Store, span=expr.span, type=success,
|
append_instruction(state, ir.Instruction{
|
||||||
target=ir.INVALID_REF, a=slot, b=fallback, diagnostic=source.INVALID_DIAGNOSTIC,
|
op=.Store, span=expr.span, type=success,
|
||||||
})
|
target=ir.INVALID_REF, a=slot, b=fallback, diagnostic=source.INVALID_DIAGNOSTIC,
|
||||||
append_instruction(state, ir.Instruction{
|
})
|
||||||
op=.Br, span=expr.span, type=types.VOID, integer=merge_lbl,
|
append_instruction(state, ir.Instruction{
|
||||||
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
op=.Br, span=expr.span, type=types.VOID, integer=merge_lbl,
|
||||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
target=ir.INVALID_REF, a=ir.INVALID_INSTRUCTION, b=ir.INVALID_INSTRUCTION,
|
||||||
})
|
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
append_instruction(state, ir.Instruction{
|
append_instruction(state, ir.Instruction{
|
||||||
op=.Label, span=expr.span, type=types.VOID, integer=success_lbl,
|
op=.Label, span=expr.span, type=types.VOID, integer=success_lbl,
|
||||||
|
|||||||
+79
-35
@@ -3961,6 +3961,77 @@ main func() i32 {
|
|||||||
testing.expect_value(t, compiler_core.compile_package(directory, output), 1)
|
testing.expect_value(t, compiler_core.compile_package(directory, output), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
terminating_catch_block_compiles_and_runs :: proc(t: ^testing.T) {
|
||||||
|
text := `Failure :: enum {
|
||||||
|
bad
|
||||||
|
}
|
||||||
|
may_fail func(fail bool) i32 ! Failure {
|
||||||
|
if (fail) return .bad
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
recover func(fail bool) i32 {
|
||||||
|
value :: may_fail(fail) catch |_| {
|
||||||
|
return 40
|
||||||
|
}
|
||||||
|
return value + 1
|
||||||
|
}
|
||||||
|
main func() i32 {
|
||||||
|
return recover(false) + recover(true) - 42
|
||||||
|
}
|
||||||
|
`
|
||||||
|
directory := "/tmp/brolang-test-terminating-catch"
|
||||||
|
main_path := "/tmp/brolang-test-terminating-catch/main.bro"
|
||||||
|
output := "/tmp/brolang-test-terminating-catch-output"
|
||||||
|
_ = 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))
|
||||||
|
testing.expect_value(t, compiler_core.compile_package(directory, output), 0)
|
||||||
|
state := run_executable(output)
|
||||||
|
testing.expect_value(t, state.exit_code, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
conversion_diagnostics_render_source_types :: proc(t: ^testing.T) {
|
||||||
|
text := `Allocator :: struct {
|
||||||
|
marker i32
|
||||||
|
}
|
||||||
|
take func(allocator Allocator, memory []mut u8) void {}
|
||||||
|
main func() void {
|
||||||
|
allocator Allocator = Allocator { marker = 0 }
|
||||||
|
data [1]mut u8 = [0]
|
||||||
|
take(data[..], allocator)
|
||||||
|
}
|
||||||
|
`
|
||||||
|
source_file := source.Source{path="type_labels.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)
|
||||||
|
|
||||||
|
slice_to_allocator := false
|
||||||
|
allocator_to_slice := false
|
||||||
|
internal_type_id := false
|
||||||
|
for diagnostic in diagnostics.items {
|
||||||
|
slice_to_allocator = slice_to_allocator ||
|
||||||
|
strings.contains(diagnostic.message, "cannot implicitly convert []mut u8 to Allocator")
|
||||||
|
allocator_to_slice = allocator_to_slice ||
|
||||||
|
strings.contains(diagnostic.message, "cannot implicitly convert Allocator to []mut u8")
|
||||||
|
internal_type_id = internal_type_id || strings.contains(diagnostic.message, "<type ")
|
||||||
|
}
|
||||||
|
testing.expect(t, slice_to_allocator)
|
||||||
|
testing.expect(t, allocator_to_slice)
|
||||||
|
testing.expect(t, !internal_type_id)
|
||||||
|
}
|
||||||
|
|
||||||
@(test)
|
@(test)
|
||||||
contextual_payload_variants_compile :: proc(t: ^testing.T) {
|
contextual_payload_variants_compile :: proc(t: ^testing.T) {
|
||||||
text := `DetailError :: union(enum) {
|
text := `DetailError :: union(enum) {
|
||||||
@@ -4941,26 +5012,6 @@ folded_constant_addition_compiles_and_runs :: proc(t: ^testing.T) {
|
|||||||
testing.expect_value(t, state.exit_code, 0)
|
testing.expect_value(t, state.exit_code, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@(test)
|
|
||||||
unused_invalid_global_does_not_trap :: proc(t: ^testing.T) {
|
|
||||||
output := "/tmp/brolang-test-invalid-unused"
|
|
||||||
defer _ = os.remove(output)
|
|
||||||
status := compiler_core.compile_package("examples/programs/invalid_unused_global", output)
|
|
||||||
testing.expect_value(t, status, 1)
|
|
||||||
state := run_executable(output)
|
|
||||||
testing.expect_value(t, state.exit_code, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
@(test)
|
|
||||||
used_invalid_global_traps :: proc(t: ^testing.T) {
|
|
||||||
output := "/tmp/brolang-test-invalid-used"
|
|
||||||
defer _ = os.remove(output)
|
|
||||||
status := compiler_core.compile_package("examples/programs/invalid_used_global", output)
|
|
||||||
testing.expect_value(t, status, 1)
|
|
||||||
state := run_executable(output)
|
|
||||||
testing.expect(t, !state.success)
|
|
||||||
}
|
|
||||||
|
|
||||||
@(test)
|
@(test)
|
||||||
main_int_is_constrained_to_i32 :: proc(t: ^testing.T) {
|
main_int_is_constrained_to_i32 :: proc(t: ^testing.T) {
|
||||||
output := "/tmp/brolang-test-main-int"
|
output := "/tmp/brolang-test-main-int"
|
||||||
@@ -4981,16 +5032,6 @@ main_i32_returns_directly :: proc(t: ^testing.T) {
|
|||||||
testing.expect_value(t, state.exit_code, 4)
|
testing.expect_value(t, state.exit_code, 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
@(test)
|
|
||||||
transitive_problematic_global_is_deferred :: proc(t: ^testing.T) {
|
|
||||||
output := "/tmp/brolang-test-transitive-unused"
|
|
||||||
defer _ = os.remove(output)
|
|
||||||
status := compiler_core.compile_package("examples/programs/invalid_transitive_unused_global", output)
|
|
||||||
testing.expect_value(t, status, 1)
|
|
||||||
state := run_executable(output)
|
|
||||||
testing.expect_value(t, state.exit_code, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
@(test)
|
@(test)
|
||||||
checked_addition_traps_on_overflow :: proc(t: ^testing.T) {
|
checked_addition_traps_on_overflow :: proc(t: ^testing.T) {
|
||||||
output := "/tmp/brolang-test-overflow"
|
output := "/tmp/brolang-test-overflow"
|
||||||
@@ -6159,13 +6200,16 @@ main func() void {}
|
|||||||
hir_module := checker.check(&ast_module, &diagnostics, &symbols)
|
hir_module := checker.check(&ast_module, &diagnostics, &symbols)
|
||||||
defer hir.destroy_module(&hir_module)
|
defer hir.destroy_module(&hir_module)
|
||||||
|
|
||||||
found_signed_range := 0
|
found_expression_range := 0
|
||||||
|
found_literal_range := 0
|
||||||
found_u64_range := false
|
found_u64_range := false
|
||||||
for diagnostic in diagnostics.items {
|
for diagnostic in diagnostics.items {
|
||||||
found_signed_range += 1 if strings.contains(diagnostic.message, "exceeds signed i64 range") else 0
|
found_expression_range += 1 if strings.contains(diagnostic.message, "exceeds signed i64 range") else 0
|
||||||
|
found_literal_range += 1 if strings.contains(diagnostic.message, "does not fit in i64") else 0
|
||||||
found_u64_range = found_u64_range || strings.contains(diagnostic.message, "magnitude does not fit in u64")
|
found_u64_range = found_u64_range || strings.contains(diagnostic.message, "magnitude does not fit in u64")
|
||||||
}
|
}
|
||||||
testing.expect_value(t, found_signed_range, 4)
|
testing.expect_value(t, found_expression_range, 2)
|
||||||
|
testing.expect_value(t, found_literal_range, 2)
|
||||||
testing.expect(t, found_u64_range)
|
testing.expect(t, found_u64_range)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6479,7 +6523,7 @@ main func() void {
|
|||||||
for global in hir_module.globals {
|
for global in hir_module.globals {
|
||||||
name := symbol.resolve(&symbols, global.name)
|
name := symbol.resolve(&symbols, global.name)
|
||||||
if name == "counter" {
|
if name == "counter" {
|
||||||
found_counter = global.writable && !global.is_static && types.equal(global.type, types.I8)
|
found_counter = global.writable && !global.is_static && types.equal(global.type, types.I32)
|
||||||
} else if name == "ratio" {
|
} else if name == "ratio" {
|
||||||
found_ratio = global.writable && !global.is_static && types.equal(global.type, types.F64)
|
found_ratio = global.writable && !global.is_static && types.equal(global.type, types.F64)
|
||||||
} else if name == "span" {
|
} else if name == "span" {
|
||||||
@@ -6494,7 +6538,7 @@ main func() void {
|
|||||||
testing.expect(t, found_span)
|
testing.expect(t, found_span)
|
||||||
testing.expect(t, found_values)
|
testing.expect(t, found_values)
|
||||||
testing.expect(t, strings.contains(llvm_text, "internal global"))
|
testing.expect(t, strings.contains(llvm_text, "internal global"))
|
||||||
testing.expect(t, !strings.contains(llvm_text, "internal constant i8 0"))
|
testing.expect(t, !strings.contains(llvm_text, "internal constant i32 0"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@(test)
|
@(test)
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
bad int = 4
|
|
||||||
|
|
||||||
read_bad func() int {
|
|
||||||
return bad
|
|
||||||
}
|
|
||||||
|
|
||||||
derived int :: read_bad()
|
|
||||||
|
|
||||||
main func() void {
|
|
||||||
_ = 1
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
bad int = 4
|
|
||||||
|
|
||||||
main func() void {
|
|
||||||
_ = 1
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
bad int = 4
|
|
||||||
|
|
||||||
main func() void {
|
|
||||||
_ = bad
|
|
||||||
}
|
|
||||||
+6
-6
@@ -1,9 +1,7 @@
|
|||||||
c :: import "@ffi/c"
|
c :: import "@ffi/c"
|
||||||
|
|
||||||
AllocatorVTable :: struct {
|
AllocError :: enum {
|
||||||
alloc @func(context ?*mut anyopaque, size usize, alignment usize) ?*mut u8
|
out_of_memory
|
||||||
realloc @func(context ?*mut anyopaque, memory ?*mut u8, old_size usize, new_size usize, alignment usize) ?*mut u8
|
|
||||||
free @func(context ?*mut anyopaque, memory ?*mut u8, size usize, alignment usize) void
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Allocator :: struct {
|
Allocator :: struct {
|
||||||
@@ -11,8 +9,10 @@ Allocator :: struct {
|
|||||||
vtable @AllocatorVTable
|
vtable @AllocatorVTable
|
||||||
}
|
}
|
||||||
|
|
||||||
AllocError :: enum {
|
AllocatorVTable :: struct {
|
||||||
out_of_memory
|
alloc @func(context ?*mut anyopaque, size usize, alignment usize) ?*mut u8
|
||||||
|
realloc @func(context ?*mut anyopaque, memory ?*mut u8, old_size usize, new_size usize, alignment usize) ?*mut u8
|
||||||
|
free @func(context ?*mut anyopaque, memory ?*mut u8, size usize, alignment usize) void
|
||||||
}
|
}
|
||||||
|
|
||||||
raw_alloc func(allocator Allocator, size usize, alignment usize) ?*mut u8 {
|
raw_alloc func(allocator Allocator, size usize, alignment usize) ?*mut u8 {
|
||||||
|
|||||||
@@ -0,0 +1,420 @@
|
|||||||
|
# generated by brolang translate-c from stdio.h
|
||||||
|
|
||||||
|
# unsupported in bindings: C union '__mbstate_t' has no native spelling
|
||||||
|
__darwin_pthread_handler_rec :: c_struct {
|
||||||
|
__routine ?*c_func(_ ?*mut anyopaque) void
|
||||||
|
__arg ?*mut anyopaque
|
||||||
|
__next ?*mut __darwin_pthread_handler_rec
|
||||||
|
}
|
||||||
|
_opaque_pthread_attr_t :: c_struct {
|
||||||
|
__sig c_long
|
||||||
|
__opaque [56]c_char
|
||||||
|
}
|
||||||
|
_opaque_pthread_cond_t :: c_struct {
|
||||||
|
__sig c_long
|
||||||
|
__opaque [40]c_char
|
||||||
|
}
|
||||||
|
_opaque_pthread_condattr_t :: c_struct {
|
||||||
|
__sig c_long
|
||||||
|
__opaque [8]c_char
|
||||||
|
}
|
||||||
|
_opaque_pthread_mutex_t :: c_struct {
|
||||||
|
__sig c_long
|
||||||
|
__opaque [56]c_char
|
||||||
|
}
|
||||||
|
_opaque_pthread_mutexattr_t :: c_struct {
|
||||||
|
__sig c_long
|
||||||
|
__opaque [8]c_char
|
||||||
|
}
|
||||||
|
_opaque_pthread_once_t :: c_struct {
|
||||||
|
__sig c_long
|
||||||
|
__opaque [8]c_char
|
||||||
|
}
|
||||||
|
_opaque_pthread_rwlock_t :: c_struct {
|
||||||
|
__sig c_long
|
||||||
|
__opaque [192]c_char
|
||||||
|
}
|
||||||
|
_opaque_pthread_rwlockattr_t :: c_struct {
|
||||||
|
__sig c_long
|
||||||
|
__opaque [16]c_char
|
||||||
|
}
|
||||||
|
_opaque_pthread_t :: c_struct {
|
||||||
|
__sig c_long
|
||||||
|
__cleanup_stack ?*mut __darwin_pthread_handler_rec
|
||||||
|
__opaque [8176]c_char
|
||||||
|
}
|
||||||
|
__sbuf :: c_struct {
|
||||||
|
_base ?*mut c_uchar
|
||||||
|
_size c_int
|
||||||
|
}
|
||||||
|
__sFILEX :: opaque
|
||||||
|
__sFILE :: c_struct {
|
||||||
|
_p ?*mut c_uchar
|
||||||
|
_r c_int
|
||||||
|
_w c_int
|
||||||
|
_flags c_short
|
||||||
|
_file c_short
|
||||||
|
_bf __sbuf
|
||||||
|
_lbfsize c_int
|
||||||
|
_cookie ?*mut anyopaque
|
||||||
|
_close ?*c_func(_ ?*mut anyopaque) c_int
|
||||||
|
_read ?*c_func(_ ?*mut anyopaque, _ ?*mut c_char, _ c_int) c_int
|
||||||
|
_seek ?*c_func(_ ?*mut anyopaque, _ c_longlong, _ c_int) c_longlong
|
||||||
|
_write ?*c_func(_ ?*mut anyopaque, _ ?*c_char, _ c_int) c_int
|
||||||
|
_ub __sbuf
|
||||||
|
_extra ?*mut __sFILEX
|
||||||
|
_ur c_int
|
||||||
|
_ubuf [3]c_uchar
|
||||||
|
_nbuf [1]c_uchar
|
||||||
|
_lb __sbuf
|
||||||
|
_blksize c_int
|
||||||
|
_offset c_longlong
|
||||||
|
}
|
||||||
|
|
||||||
|
__int8_t :: alias c_schar
|
||||||
|
__uint8_t :: alias c_uchar
|
||||||
|
__int16_t :: alias c_short
|
||||||
|
__uint16_t :: alias c_ushort
|
||||||
|
__int32_t :: alias c_int
|
||||||
|
__uint32_t :: alias c_uint
|
||||||
|
__int64_t :: alias c_longlong
|
||||||
|
__uint64_t :: alias c_ulonglong
|
||||||
|
__darwin_intptr_t :: alias c_long
|
||||||
|
__darwin_natural_t :: alias c_uint
|
||||||
|
__darwin_ct_rune_t :: alias c_int
|
||||||
|
__darwin_mbstate_t :: alias __mbstate_t
|
||||||
|
__darwin_ptrdiff_t :: alias c_long
|
||||||
|
__darwin_size_t :: alias c_ulong
|
||||||
|
__darwin_va_list :: alias ?*mut c_char
|
||||||
|
__darwin_wchar_t :: alias c_int
|
||||||
|
__darwin_rune_t :: alias c_int
|
||||||
|
__darwin_wint_t :: alias c_int
|
||||||
|
__darwin_clock_t :: alias c_ulong
|
||||||
|
__darwin_socklen_t :: alias c_uint
|
||||||
|
__darwin_ssize_t :: alias c_long
|
||||||
|
__darwin_time_t :: alias c_long
|
||||||
|
__darwin_blkcnt_t :: alias c_longlong
|
||||||
|
__darwin_blksize_t :: alias c_int
|
||||||
|
__darwin_dev_t :: alias c_int
|
||||||
|
__darwin_fsblkcnt_t :: alias c_uint
|
||||||
|
__darwin_fsfilcnt_t :: alias c_uint
|
||||||
|
__darwin_gid_t :: alias c_uint
|
||||||
|
__darwin_id_t :: alias c_uint
|
||||||
|
__darwin_ino64_t :: alias c_ulonglong
|
||||||
|
__darwin_ino_t :: alias c_ulonglong
|
||||||
|
__darwin_mach_port_name_t :: alias c_uint
|
||||||
|
__darwin_mach_port_t :: alias c_uint
|
||||||
|
__darwin_mode_t :: alias c_ushort
|
||||||
|
__darwin_off_t :: alias c_longlong
|
||||||
|
__darwin_pid_t :: alias c_int
|
||||||
|
__darwin_sigset_t :: alias c_uint
|
||||||
|
__darwin_suseconds_t :: alias c_int
|
||||||
|
__darwin_uid_t :: alias c_uint
|
||||||
|
__darwin_useconds_t :: alias c_uint
|
||||||
|
__darwin_uuid_t :: alias [16]c_uchar
|
||||||
|
__darwin_uuid_string_t :: alias [37]c_char
|
||||||
|
__darwin_pthread_attr_t :: alias _opaque_pthread_attr_t
|
||||||
|
__darwin_pthread_cond_t :: alias _opaque_pthread_cond_t
|
||||||
|
__darwin_pthread_condattr_t :: alias _opaque_pthread_condattr_t
|
||||||
|
__darwin_pthread_key_t :: alias c_ulong
|
||||||
|
__darwin_pthread_mutex_t :: alias _opaque_pthread_mutex_t
|
||||||
|
__darwin_pthread_mutexattr_t :: alias _opaque_pthread_mutexattr_t
|
||||||
|
__darwin_pthread_once_t :: alias _opaque_pthread_once_t
|
||||||
|
__darwin_pthread_rwlock_t :: alias _opaque_pthread_rwlock_t
|
||||||
|
__darwin_pthread_rwlockattr_t :: alias _opaque_pthread_rwlockattr_t
|
||||||
|
__darwin_pthread_t :: alias ?*mut _opaque_pthread_t
|
||||||
|
__darwin_nl_item :: alias c_int
|
||||||
|
__darwin_wctrans_t :: alias c_int
|
||||||
|
__darwin_wctype_t :: alias c_uint
|
||||||
|
int8_t :: alias c_schar
|
||||||
|
int16_t :: alias c_short
|
||||||
|
int32_t :: alias c_int
|
||||||
|
int64_t :: alias c_longlong
|
||||||
|
u_int8_t :: alias c_uchar
|
||||||
|
u_int16_t :: alias c_ushort
|
||||||
|
u_int32_t :: alias c_uint
|
||||||
|
u_int64_t :: alias c_ulonglong
|
||||||
|
register_t :: alias c_longlong
|
||||||
|
intptr_t :: alias c_long
|
||||||
|
uintptr_t :: alias c_ulong
|
||||||
|
user_addr_t :: alias c_ulonglong
|
||||||
|
user_size_t :: alias c_ulonglong
|
||||||
|
user_ssize_t :: alias c_longlong
|
||||||
|
user_long_t :: alias c_longlong
|
||||||
|
user_ulong_t :: alias c_ulonglong
|
||||||
|
user_time_t :: alias c_longlong
|
||||||
|
user_off_t :: alias c_longlong
|
||||||
|
syscall_arg_t :: alias c_ulonglong
|
||||||
|
va_list :: alias ?*mut c_char
|
||||||
|
size_t :: alias c_ulong
|
||||||
|
fpos_t :: alias c_longlong
|
||||||
|
FILE :: alias __sFILE
|
||||||
|
off_t :: alias c_longlong
|
||||||
|
ssize_t :: alias c_long
|
||||||
|
|
||||||
|
_DARWIN_FEATURE_64_BIT_INODE c_int :: 1
|
||||||
|
_DARWIN_FEATURE_ONLY_64_BIT_INODE c_int :: 1
|
||||||
|
_DARWIN_FEATURE_ONLY_VERS_1050 c_int :: 1
|
||||||
|
_DARWIN_FEATURE_ONLY_UNIX_CONFORMANCE c_int :: 1
|
||||||
|
_DARWIN_FEATURE_UNIX_CONFORMANCE c_int :: 3
|
||||||
|
_FORTIFY_SOURCE c_int :: 2
|
||||||
|
RENAME_SECLUDE c_int :: 1
|
||||||
|
RENAME_SWAP c_int :: 2
|
||||||
|
RENAME_EXCL c_int :: 4
|
||||||
|
RENAME_RESERVED1 c_int :: 8
|
||||||
|
RENAME_NOFOLLOW_ANY c_int :: 16
|
||||||
|
RENAME_RESOLVE_BENEATH c_int :: 32
|
||||||
|
SEEK_SET c_int :: 0
|
||||||
|
SEEK_CUR c_int :: 1
|
||||||
|
SEEK_END c_int :: 2
|
||||||
|
SEEK_HOLE c_int :: 3
|
||||||
|
SEEK_DATA c_int :: 4
|
||||||
|
_IOFBF c_int :: 0
|
||||||
|
_IOLBF c_int :: 1
|
||||||
|
_IONBF c_int :: 2
|
||||||
|
BUFSIZ c_int :: 1024
|
||||||
|
FOPEN_MAX c_int :: 20
|
||||||
|
FILENAME_MAX c_int :: 1024
|
||||||
|
L_tmpnam c_int :: 1024
|
||||||
|
TMP_MAX c_int :: 308915776
|
||||||
|
L_ctermid c_int :: 1024
|
||||||
|
_USE_FORTIFY_LEVEL c_int :: 2
|
||||||
|
|
||||||
|
renameat c_func(_ c_int, _ ?*c_char, _ c_int, _ ?*c_char) c_int
|
||||||
|
renamex_np c_func(_ ?*c_char, _ ?*c_char, _ c_uint) c_int
|
||||||
|
renameatx_np c_func(_ c_int, _ ?*c_char, _ c_int, _ ?*c_char, _ c_uint) c_int
|
||||||
|
printf c_func(_ ?*c_char, ...) c_int
|
||||||
|
clearerr c_func(_ ?*mut __sFILE) void
|
||||||
|
fclose c_func(_ ?*mut __sFILE) c_int
|
||||||
|
feof c_func(_ ?*mut __sFILE) c_int
|
||||||
|
ferror c_func(_ ?*mut __sFILE) c_int
|
||||||
|
fflush c_func(_ ?*mut __sFILE) c_int
|
||||||
|
fgetc c_func(_ ?*mut __sFILE) c_int
|
||||||
|
fgetpos c_func(_ ?*mut __sFILE, _ ?*mut c_longlong) c_int
|
||||||
|
fgets c_func(_ ?*mut c_char, __size c_int, _ ?*mut __sFILE) ?*mut c_char
|
||||||
|
fopen c_func(__filename ?*c_char, __mode ?*c_char) ?*mut __sFILE
|
||||||
|
fprintf c_func(_ ?*mut __sFILE, _ ?*c_char, ...) c_int
|
||||||
|
fputc c_func(_ c_int, _ ?*mut __sFILE) c_int
|
||||||
|
fputs c_func(_ ?*c_char, _ ?*mut __sFILE) c_int
|
||||||
|
fread c_func(__ptr ?*mut anyopaque, __size c_ulong, __nitems c_ulong, __stream ?*mut __sFILE) c_ulong
|
||||||
|
freopen c_func(_ ?*c_char, _ ?*c_char, _ ?*mut __sFILE) ?*mut __sFILE
|
||||||
|
fscanf c_func(_ ?*mut __sFILE, _ ?*c_char, ...) c_int
|
||||||
|
fseek c_func(_ ?*mut __sFILE, _ c_long, _ c_int) c_int
|
||||||
|
fsetpos c_func(_ ?*mut __sFILE, _ ?*c_longlong) c_int
|
||||||
|
ftell c_func(_ ?*mut __sFILE) c_long
|
||||||
|
fwrite c_func(__ptr ?*anyopaque, __size c_ulong, __nitems c_ulong, __stream ?*mut __sFILE) c_ulong
|
||||||
|
getc c_func(_ ?*mut __sFILE) c_int
|
||||||
|
getchar c_func() c_int
|
||||||
|
gets c_func(_ ?*mut c_char) ?*mut c_char
|
||||||
|
perror c_func(_ ?*c_char) void
|
||||||
|
putc c_func(_ c_int, _ ?*mut __sFILE) c_int
|
||||||
|
putchar c_func(_ c_int) c_int
|
||||||
|
puts c_func(_ ?*c_char) c_int
|
||||||
|
remove c_func(_ ?*c_char) c_int
|
||||||
|
rename c_func(__old ?*c_char, __new ?*c_char) c_int
|
||||||
|
rewind c_func(_ ?*mut __sFILE) void
|
||||||
|
scanf c_func(_ ?*c_char, ...) c_int
|
||||||
|
setbuf c_func(_ ?*mut __sFILE, _ ?*mut c_char) void
|
||||||
|
setvbuf c_func(_ ?*mut __sFILE, _ ?*mut c_char, _ c_int, __size c_ulong) c_int
|
||||||
|
sprintf c_func(_ ?*mut c_char, _ ?*c_char, ...) c_int
|
||||||
|
sscanf c_func(_ ?*c_char, _ ?*c_char, ...) c_int
|
||||||
|
tmpfile c_func() ?*mut __sFILE
|
||||||
|
tmpnam c_func(_ ?*mut c_char) ?*mut c_char
|
||||||
|
ungetc c_func(_ c_int, _ ?*mut __sFILE) c_int
|
||||||
|
vfprintf c_func(_ ?*mut __sFILE, _ ?*c_char, _ ?*mut c_char) c_int
|
||||||
|
vprintf c_func(_ ?*c_char, _ ?*mut c_char) c_int
|
||||||
|
vsprintf c_func(_ ?*mut c_char, _ ?*c_char, _ ?*mut c_char) c_int
|
||||||
|
ctermid c_func(_ ?*mut c_char) ?*mut c_char
|
||||||
|
fdopen c_func(_ c_int, _ ?*c_char) ?*mut __sFILE
|
||||||
|
fileno c_func(_ ?*mut __sFILE) c_int
|
||||||
|
pclose c_func(_ ?*mut __sFILE) c_int
|
||||||
|
popen c_func(_ ?*c_char, _ ?*c_char) ?*mut __sFILE
|
||||||
|
__srget c_func(_ ?*mut __sFILE) c_int
|
||||||
|
__svfscanf c_func(_ ?*mut __sFILE, _ ?*c_char, _ ?*mut c_char) c_int
|
||||||
|
__swbuf c_func(_ c_int, _ ?*mut __sFILE) c_int
|
||||||
|
__sputc c_func(_c c_int, _p ?*mut __sFILE) c_int
|
||||||
|
flockfile c_func(_ ?*mut __sFILE) void
|
||||||
|
ftrylockfile c_func(_ ?*mut __sFILE) c_int
|
||||||
|
funlockfile c_func(_ ?*mut __sFILE) void
|
||||||
|
getc_unlocked c_func(_ ?*mut __sFILE) c_int
|
||||||
|
getchar_unlocked c_func() c_int
|
||||||
|
putc_unlocked c_func(_ c_int, _ ?*mut __sFILE) c_int
|
||||||
|
putchar_unlocked c_func(_ c_int) c_int
|
||||||
|
getw c_func(_ ?*mut __sFILE) c_int
|
||||||
|
putw c_func(_ c_int, _ ?*mut __sFILE) c_int
|
||||||
|
tempnam c_func(__dir ?*c_char, __prefix ?*c_char) ?*mut c_char
|
||||||
|
fseeko c_func(__stream ?*mut __sFILE, __offset c_longlong, __whence c_int) c_int
|
||||||
|
ftello c_func(__stream ?*mut __sFILE) c_longlong
|
||||||
|
snprintf c_func(__str ?*mut c_char, __size c_ulong, __format ?*c_char, ...) c_int
|
||||||
|
vfscanf c_func(__stream ?*mut __sFILE, __format ?*c_char, _ ?*mut c_char) c_int
|
||||||
|
vscanf c_func(__format ?*c_char, _ ?*mut c_char) c_int
|
||||||
|
vsnprintf c_func(__str ?*mut c_char, __size c_ulong, __format ?*c_char, _ ?*mut c_char) c_int
|
||||||
|
vsscanf c_func(__str ?*c_char, __format ?*c_char, _ ?*mut c_char) c_int
|
||||||
|
dprintf c_func(_ c_int, _ ?*c_char, ...) c_int
|
||||||
|
vdprintf c_func(_ c_int, _ ?*c_char, _ ?*mut c_char) c_int
|
||||||
|
getdelim c_func(__linep ?*mut ?*mut c_char, __linecapp ?*mut c_ulong, __delimiter c_int, __stream ?*mut __sFILE) c_long
|
||||||
|
getline c_func(__linep ?*mut ?*mut c_char, __linecapp ?*mut c_ulong, __stream ?*mut __sFILE) c_long
|
||||||
|
fmemopen c_func(__buf ?*mut anyopaque, __size c_ulong, __mode ?*c_char) ?*mut __sFILE
|
||||||
|
open_memstream c_func(__bufp ?*mut ?*mut c_char, __sizep ?*mut c_ulong) ?*mut __sFILE
|
||||||
|
asprintf c_func(_ ?*mut ?*mut c_char, _ ?*c_char, ...) c_int
|
||||||
|
ctermid_r c_func(_ ?*mut c_char) ?*mut c_char
|
||||||
|
fgetln c_func(_ ?*mut __sFILE, __len ?*mut c_ulong) ?*mut c_char
|
||||||
|
fmtcheck c_func(_ ?*c_char, _ ?*c_char) ?*c_char
|
||||||
|
fpurge c_func(_ ?*mut __sFILE) c_int
|
||||||
|
setbuffer c_func(_ ?*mut __sFILE, _ ?*mut c_char, __size c_int) void
|
||||||
|
setlinebuf c_func(_ ?*mut __sFILE) c_int
|
||||||
|
vasprintf c_func(_ ?*mut ?*mut c_char, _ ?*c_char, _ ?*mut c_char) c_int
|
||||||
|
funopen c_func(_ ?*anyopaque, _ ?*c_func(_ ?*mut anyopaque, _ ?*mut c_char, _ c_int) c_int, _ ?*c_func(_ ?*mut anyopaque, _ ?*c_char, _ c_int) c_int, _ ?*c_func(_ ?*mut anyopaque, _ c_longlong, _ c_int) c_longlong, _ ?*c_func(_ ?*mut anyopaque) c_int) ?*mut __sFILE
|
||||||
|
__snprintf_chk c_func(_ ?*mut c_char, __maxlen c_ulong, _ c_int, _ c_ulong, _ ?*c_char, ...) c_int
|
||||||
|
__vsnprintf_chk c_func(_ ?*mut c_char, __maxlen c_ulong, _ c_int, _ c_ulong, _ ?*c_char, _ ?*mut c_char) c_int
|
||||||
|
__sprintf_chk c_func(_ ?*mut c_char, _ c_int, _ c_ulong, _ ?*c_char, ...) c_int
|
||||||
|
__vsprintf_chk c_func(_ ?*mut c_char, _ c_int, _ c_ulong, _ ?*c_char, _ ?*mut c_char) c_int
|
||||||
|
|
||||||
|
# unsupported in bindings: external variable '__stdinp' has no native spelling
|
||||||
|
# unsupported in bindings: external variable '__stdoutp' has no native spelling
|
||||||
|
# unsupported in bindings: external variable '__stderrp' has no native spelling
|
||||||
|
# unsupported in bindings: external variable 'sys_nerr' has no native spelling
|
||||||
|
# unsupported in bindings: external variable 'sys_errlist' has no native spelling
|
||||||
|
# unsupported in bindings: _STDIO_H_ — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _LIBC_BOUNDS_H_ — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _CDEFS_H_ — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _LIBC_COUNT — C function-like macros are not supported
|
||||||
|
# unsupported in bindings: _LIBC_COUNT_OR_NULL — C function-like macros are not supported
|
||||||
|
# unsupported in bindings: _LIBC_SIZE — C function-like macros are not supported
|
||||||
|
# unsupported in bindings: _LIBC_SIZE_OR_NULL — C function-like macros are not supported
|
||||||
|
# unsupported in bindings: _LIBC_ENDED_BY — C function-like macros are not supported
|
||||||
|
# unsupported in bindings: _LIBC_SINGLE — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _LIBC_UNSAFE_INDEXABLE — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _LIBC_CSTR — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _LIBC_NULL_TERMINATED — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _LIBC_FLEX_COUNT — C function-like macros are not supported
|
||||||
|
# unsupported in bindings: _LIBC_SINGLE_BY_DEFAULT — C function-like macros are not supported
|
||||||
|
# unsupported in bindings: _LIBC_PTRCHECK_REPLACED — C function-like macros are not supported
|
||||||
|
# unsupported in bindings: _LIBC_FORGE_PTR — C function-like macros are not supported
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_0 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_1 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_2 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_3 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_4 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_5 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_6 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_7 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_8 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_9 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_10 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_10_2 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_10_3 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_11 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_11_2 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_11_3 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_11_4 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_12 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_12_1 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_12_2 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_12_4 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_13 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_13_1 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_13_2 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_13_4 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_14 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_14_1 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_14_4 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_14_5 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_14_6 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_15 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_15_1 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_15_4 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_X_VERSION_10_16 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_11_0 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_11_1 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_11_3 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_11_4 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_11_5 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_11_6 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_12_0 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_12_1 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_12_2 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_12_3 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_12_4 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_12_5 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_12_6 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_12_7 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_13_0 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_13_1 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_13_2 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_13_3 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_13_4 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_13_5 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_13_6 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_13_7 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_14_0 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_14_1 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_14_2 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_14_3 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_14_4 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_14_5 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_14_6 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_14_7 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_15_0 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_15_1 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_15_2 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_15_3 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_15_4 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_15_5 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_15_6 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_16_0 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_26_0 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_26_1 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_26_2 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_26_3 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: MAC_OS_VERSION_26_4 — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: _SYS__TYPES_H_ — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _BSD_MACHINE__TYPES_H_ — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _BSD_ARM__TYPES_H_ — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _SYS__PTHREAD_TYPES_H_ — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _VA_LIST_T — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _BSD_MACHINE_TYPES_H_ — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _ARM_MACHTYPES_H_ — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _MACHTYPES_H_ — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _INT8_T — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _INT16_T — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _INT32_T — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _INT64_T — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _U_INT8_T — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _U_INT16_T — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _U_INT32_T — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _U_INT64_T — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _INTPTR_T — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _UINTPTR_T — C macro has no replacement value
|
||||||
|
# unsupported in bindings: USER_ADDR_NULL — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: CAST_USER_ADDR_T — C function-like macros are not supported
|
||||||
|
# unsupported in bindings: _SIZE_T — C macro has no replacement value
|
||||||
|
# unsupported in bindings: NULL — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: _SYS_STDIO_H_ — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _FSTDIO — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _SEEK_SET_H_ — C macro has no replacement value
|
||||||
|
# unsupported in bindings: EOF — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: P_tmpdir — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: stdin — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: stdout — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: stderr — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: _LIBC_COUNT__L_CTERMID — C macro is not a supported constant
|
||||||
|
# unsupported in bindings: _CTERMID_H_ — C macro has no replacement value
|
||||||
|
# unsupported in bindings: getc_unlocked — C function-like macros are not supported
|
||||||
|
# unsupported in bindings: putc_unlocked — C function-like macros are not supported
|
||||||
|
# unsupported in bindings: getchar_unlocked — C function-like macros are not supported
|
||||||
|
# unsupported in bindings: putchar_unlocked — C function-like macros are not supported
|
||||||
|
# unsupported in bindings: _OFF_T — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _SSIZE_T — C macro has no replacement value
|
||||||
|
# unsupported in bindings: fropen — C function-like macros are not supported
|
||||||
|
# unsupported in bindings: fwopen — C function-like macros are not supported
|
||||||
|
# unsupported in bindings: feof_unlocked — C function-like macros are not supported
|
||||||
|
# unsupported in bindings: ferror_unlocked — C function-like macros are not supported
|
||||||
|
# unsupported in bindings: clearerr_unlocked — C function-like macros are not supported
|
||||||
|
# unsupported in bindings: fileno_unlocked — C function-like macros are not supported
|
||||||
|
# unsupported in bindings: _SECURE__STDIO_H_ — C macro has no replacement value
|
||||||
|
# unsupported in bindings: _SECURE__COMMON_H_ — C macro has no replacement value
|
||||||
|
# unsupported in bindings: sprintf — C function-like macros are not supported
|
||||||
|
# unsupported in bindings: vsprintf — C function-like macros are not supported
|
||||||
|
# unsupported in bindings: snprintf — C function-like macros are not supported
|
||||||
|
# unsupported in bindings: vsnprintf — C function-like macros are not supported
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
malloc c_func(__size c_ulong) ?*mut anyopaque
|
||||||
|
realloc c_func(__ptr ?*mut anyopaque, __size c_ulong) ?*mut anyopaque
|
||||||
|
free c_func(_ ?*mut anyopaque) void
|
||||||
|
posix_memalign c_func(__memptr ?*mut ?*mut anyopaque, __alignment c_ulong, __size c_ulong) c_int
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import "@ffi/c"
|
||||||
|
import "@std/mem"
|
||||||
|
|
||||||
|
main func() void {
|
||||||
|
allocator :: mem.c_allocator
|
||||||
|
|
||||||
|
data :: mem.alloc(u8, allocator, 24) catch |_| {
|
||||||
|
_ = c.printf("Failed to allocate memory\n")
|
||||||
|
return _
|
||||||
|
}
|
||||||
|
defer mem.free(u8, allocator, data)
|
||||||
|
|
||||||
|
data[0] = 'H'
|
||||||
|
_ = c.printf("data[0] = %s\n", data[0])
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# Build configuration surface for `brolang build` (v0).
|
||||||
|
#
|
||||||
|
# A project's `build.bro` imports this module and declares a top-level constant
|
||||||
|
# named `config` of type `BuildConfig`. `brolang build [root]` type-checks
|
||||||
|
# build.bro, reads the config, and writes root/build/name.
|
||||||
|
#
|
||||||
|
# Declarative and literal-only: one executable per build. List fields take an
|
||||||
|
# address-of an array literal (`&["raylib"]`); empty lists are written `&[]`.
|
||||||
|
BuildConfig :: struct {
|
||||||
|
name []u8 # output executable name under root/build
|
||||||
|
source []u8 # program package directory, relative to build.bro
|
||||||
|
libraries [][]u8 # library names to link (-l)
|
||||||
|
lib_paths [][]u8 # library search directories (-L)
|
||||||
|
includes [][]u8 # C include directories (-I)
|
||||||
|
defines [][]u8 # C preprocessor defines (name or name=value)
|
||||||
|
links [][]u8 # extra linker inputs (object/source files, -framework pairs)
|
||||||
|
}
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
c :: import "@ffi/c"
|
||||||
|
|
||||||
|
AllocError :: enum {
|
||||||
|
out_of_memory
|
||||||
|
}
|
||||||
|
|
||||||
|
Allocator :: struct {
|
||||||
|
context ?*mut anyopaque
|
||||||
|
vtable @AllocatorVTable
|
||||||
|
}
|
||||||
|
|
||||||
|
AllocatorVTable :: struct {
|
||||||
|
alloc @func(context ?*mut anyopaque, size usize, alignment usize) ?*mut u8
|
||||||
|
realloc @func(context ?*mut anyopaque, memory ?*mut u8, old_size usize, new_size usize, alignment usize) ?*mut u8
|
||||||
|
free @func(context ?*mut anyopaque, memory ?*mut u8, size usize, alignment usize) void
|
||||||
|
}
|
||||||
|
|
||||||
|
raw_alloc func(allocator Allocator, size usize, alignment usize) ?*mut u8 {
|
||||||
|
return allocator.vtable.alloc(allocator.context, size, alignment)
|
||||||
|
}
|
||||||
|
|
||||||
|
raw_realloc func(allocator Allocator, memory ?*mut u8, old_size usize, new_size usize, alignment usize) ?*mut u8 {
|
||||||
|
return allocator.vtable.realloc(allocator.context, memory, old_size, new_size, alignment)
|
||||||
|
}
|
||||||
|
|
||||||
|
raw_free func(allocator Allocator, memory ?*mut u8, size usize, alignment usize) void {
|
||||||
|
allocator.vtable.free(allocator.context, memory, size, alignment)
|
||||||
|
}
|
||||||
|
|
||||||
|
_empty_storage [1]mut u64 = [0]
|
||||||
|
|
||||||
|
_empty_slice func($T type, count usize) []mut T {
|
||||||
|
pointer *mut T :: ptr_cast(T, (&_empty_storage).ptr)
|
||||||
|
return pointer[..count]
|
||||||
|
}
|
||||||
|
|
||||||
|
alloc func($T type, allocator Allocator, count usize) []mut T ! AllocError {
|
||||||
|
if count == 0 {
|
||||||
|
return _empty_slice(T, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
element_size usize :: size_of(T)
|
||||||
|
if element_size == 0 {
|
||||||
|
return _empty_slice(T, count)
|
||||||
|
}
|
||||||
|
if count > max_value(usize) / element_size {
|
||||||
|
return .out_of_memory
|
||||||
|
}
|
||||||
|
|
||||||
|
memory ?*mut u8 = raw_alloc(allocator, count * element_size, align_of(T))
|
||||||
|
if memory |bytes| {
|
||||||
|
pointer *mut T :: ptr_cast(T, bytes)
|
||||||
|
return pointer[..count]
|
||||||
|
}
|
||||||
|
return .out_of_memory
|
||||||
|
}
|
||||||
|
|
||||||
|
free func($T type, allocator Allocator, memory []mut T) void {
|
||||||
|
if memory.len != 0 and size_of(T) != 0 {
|
||||||
|
raw_free(allocator, ptr_cast(u8, memory.ptr), memory.len * size_of(T), align_of(T))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_malloc_alignment usize :: 16 # ponytail: aarch64-macos libc malloc alignment assumption.
|
||||||
|
|
||||||
|
_power_of_two func(value usize) bool {
|
||||||
|
if value == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
current usize = value
|
||||||
|
while current > 1 {
|
||||||
|
half usize = current / 2
|
||||||
|
if half * 2 != current {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
current = half
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
_c_alloc func(_ ?*mut anyopaque, size usize, alignment usize) ?*mut u8 {
|
||||||
|
if _power_of_two(alignment) == false {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
|
||||||
|
if alignment <= _malloc_alignment {
|
||||||
|
return ptr_cast(u8, c.malloc(c_ulong(size)))
|
||||||
|
}
|
||||||
|
|
||||||
|
memory [1]mut ?*mut anyopaque = [none]
|
||||||
|
status c_int = c.posix_memalign((&memory).ptr, c_ulong(alignment), c_ulong(size))
|
||||||
|
if status != 0 {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
|
||||||
|
return ptr_cast(u8, memory[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
_c_realloc func(_ ?*mut anyopaque, memory ?*mut u8, old_size usize, new_size usize, alignment usize) ?*mut u8 {
|
||||||
|
if _power_of_two(alignment) == false {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
|
||||||
|
if new_size == 0 {
|
||||||
|
c.free(memory)
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
|
||||||
|
if memory |old_memory| {
|
||||||
|
if alignment <= _malloc_alignment {
|
||||||
|
return ptr_cast(u8, c.realloc(old_memory, c_ulong(new_size)))
|
||||||
|
}
|
||||||
|
|
||||||
|
new_memory ?*mut u8 = _c_alloc(none, new_size, alignment)
|
||||||
|
if new_memory |new_bytes| {
|
||||||
|
copy_size usize = old_size
|
||||||
|
if new_size < copy_size {
|
||||||
|
copy_size = new_size
|
||||||
|
}
|
||||||
|
i usize = 0
|
||||||
|
while i < copy_size : i += 1 {
|
||||||
|
new_bytes[i] = old_memory[i]
|
||||||
|
}
|
||||||
|
c.free(old_memory)
|
||||||
|
}
|
||||||
|
return new_memory
|
||||||
|
}
|
||||||
|
|
||||||
|
return _c_alloc(none, new_size, alignment)
|
||||||
|
}
|
||||||
|
|
||||||
|
_c_free func(_ ?*mut anyopaque, memory ?*mut u8, _ usize, _ usize) void {
|
||||||
|
c.free(memory)
|
||||||
|
}
|
||||||
|
|
||||||
|
_c_vtable AllocatorVTable :: AllocatorVTable {
|
||||||
|
alloc = _c_alloc,
|
||||||
|
realloc = _c_realloc,
|
||||||
|
free = _c_free,
|
||||||
|
}
|
||||||
|
|
||||||
|
c_allocator Allocator :: Allocator {
|
||||||
|
context = none,
|
||||||
|
vtable = &_c_vtable,
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user