Dynamic arrays

This commit is contained in:
Ginger Bill
2017-01-29 20:15:16 +00:00
parent ec9c8fb8a4
commit 984e36a151
13 changed files with 537 additions and 118 deletions

View File

@@ -4,7 +4,7 @@
set exe_name=odin.exe
:: Debug = 0, Release = 1
set release_mode=1
set release_mode=0
set compiler_flags= -nologo -Oi -TC -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
if %release_mode% EQU 0 ( rem Debug

View File

@@ -10,8 +10,19 @@
// #import win32 "sys/windows.odin";
main :: proc() {
// syntax();
procedure_overloading();
array: [dynamic]int;
defer free(array);
reserve(^array, 10);
append(^array, 2);
append(^array, 3);
append(^array, 5);
append(^array, 7);
append(^array, 11);
append(^array, 13);
for val, idx in array {
fmt.println(val, idx);
}
}
syntax :: proc() {

View File

@@ -116,6 +116,7 @@ __trap :: proc() #foreign __llvm_core "llvm.trap";
read_cycle_counter :: proc() -> u64 #foreign __llvm_core "llvm.readcyclecounter";
// IMPORTANT NOTE(bill): Must be in this order (as the compiler relies upon it)
Allocator_Mode :: enum u8 {
ALLOC,
FREE,
@@ -164,12 +165,16 @@ alloc_align :: proc(size, alignment: int) -> rawptr #inline {
return a.procedure(a.data, Allocator_Mode.ALLOC, size, alignment, nil, 0, 0);
}
free_ptr_with_allocator :: proc(a: Allocator, ptr: rawptr) #inline {
if ptr == nil {
return;
}
a.procedure(a.data, Allocator_Mode.FREE, 0, 0, ptr, 0, 0);
}
free_ptr :: proc(ptr: rawptr) #inline {
__check_context();
a := context.allocator;
if ptr != nil {
a.procedure(a.data, Allocator_Mode.FREE, 0, 0, ptr, 0, 0);
}
free_ptr_with_allocator(context.allocator, ptr);
}
free_all :: proc() #inline {
__check_context();
@@ -217,46 +222,21 @@ default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
using Allocator_Mode;
when false {
match mode {
case ALLOC:
total_size := size + alignment + size_of(mem.AllocationHeader);
ptr := os.heap_alloc(total_size);
header := (^mem.AllocationHeader)(ptr);
ptr = mem.align_forward(header+1, alignment);
mem.allocation_header_fill(header, ptr, size);
return mem.zero(ptr, size);
match mode {
case ALLOC:
return os.heap_alloc(size);
case FREE:
os.heap_free(mem.allocation_header(old_memory));
return nil;
case FREE:
os.heap_free(old_memory);
return nil;
case FREE_ALL:
// NOTE(bill): Does nothing
case FREE_ALL:
// NOTE(bill): Does nothing
case RESIZE:
total_size := size + alignment + size_of(mem.AllocationHeader);
ptr := os.heap_resize(mem.allocation_header(old_memory), total_size);
header := (^mem.AllocationHeader)(ptr);
ptr = mem.align_forward(header+1, alignment);
mem.allocation_header_fill(header, ptr, size);
return mem.zero(ptr, size);
}
} else {
match mode {
case ALLOC:
return os.heap_alloc(size);
case FREE:
os.heap_free(old_memory);
return nil;
case FREE_ALL:
// NOTE(bill): Does nothing
case RESIZE:
return os.heap_resize(old_memory, size);
}
case RESIZE:
ptr := os.heap_resize(old_memory, size);
assert(ptr != nil);
return ptr;
}
return nil;
@@ -336,3 +316,56 @@ __string_decode_rune :: proc(s: string) -> (rune, int) #inline {
return utf8.decode_rune(s);
}
Raw_Dynamic_Array :: struct #ordered {
data: rawptr,
count: int,
capacity: int,
allocator: Allocator,
};
__dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, capacity: int) -> bool {
array := cast(^Raw_Dynamic_Array)array_;
if capacity <= array.capacity {
return true;
}
__check_context();
if array.allocator.procedure == nil {
array.allocator = context.allocator;
}
assert(array.allocator.procedure != nil);
old_size := array.capacity * elem_size;
new_size := capacity * elem_size;
allocator := array.allocator;
new_data := allocator.procedure(allocator.data, Allocator_Mode.RESIZE, new_size, elem_align, array.data, old_size, 0);
if new_data == nil {
return false;
}
array.data = new_data;
array.capacity = capacity;
return true;
}
__dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int, item_ptr: rawptr) {
array := cast(^Raw_Dynamic_Array)array_;
ok := true;
if array.data == nil || array.capacity <= array.count {
capacity := 2 * array.capacity + 8;
ok := __dynamic_array_reserve(array, elem_size, elem_align, capacity);
}
if !ok {
// TODO(bill): Better error handling for failed reservation
return;
}
data := cast(^byte)array.data;
assert(data != nil);
mem.copy(data + (elem_size*array.count), item_ptr, elem_size);
array.count += 1;
}

View File

@@ -80,6 +80,9 @@ allocation_header_fill :: proc(header: ^Allocation_Header, data: rawptr, size: i
}
}
allocation_header :: proc(data: rawptr) -> ^Allocation_Header {
if data == nil {
return nil;
}
p := cast(^int)data;
for (p-1)^ == -1 {
p = (p-1);

View File

@@ -248,12 +248,23 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) {
heap_alloc :: proc(size: int) -> rawptr {
assert(size > 0);
return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, size);
}
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
if new_size == 0 {
heap_free(ptr);
return nil;
}
if ptr == nil {
return heap_alloc(new_size);
}
return win32.HeapReAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, ptr, new_size);
}
heap_free :: proc(ptr: rawptr) {
if ptr == nil {
return;
}
win32.HeapFree(win32.GetProcessHeap(), 0, ptr);
}

View File

@@ -1140,6 +1140,13 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) {
goto end;
case_end;
case_ast_node(dat, DynamicArrayType, e);
Type *elem = check_type_extra(c, dat->elem, NULL);
type = make_type_dynamic_array(c->allocator, elem);
goto end;
case_end;
case_ast_node(vt, VectorType, e);
Type *elem = check_type(c, vt->elem);
@@ -1984,7 +1991,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
return;
}
if (token_is_shift(op)) {
if (token_is_shift(op.kind)) {
check_shift(c, x, y, node);
return;
}
@@ -2019,7 +2026,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
return;
}
if (token_is_comparison(op)) {
if (token_is_comparison(op.kind)) {
check_comparison(c, x, y, op.kind);
return;
}
@@ -2138,9 +2145,9 @@ void update_expr_type(Checker *c, AstNode *e, Type *type, bool final) {
// See above note in UnaryExpr case
break;
}
if (token_is_comparison(be->op)) {
}
else if (token_is_shift(be->op)) {
if (token_is_comparison(be->op.kind)) {
// NOTE(bill): Do nothing as the types are fine
} else if (token_is_shift(be->op.kind)) {
update_expr_type(c, be->left, type, final);
} else {
update_expr_type(c, be->left, type, final);
@@ -2658,11 +2665,13 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
ok = true;
} else if (is_type_string(type)) {
ok = true;
} else if (is_type_dynamic_array(type)) {
ok = true;
}
if (!ok) {
gbString type_str = type_to_string(type);
error_node(operand->expr, "You can only free pointers, slices, and strings, got `%s`", type_str);
error_node(operand->expr, "Invalid type for `free`, got `%s`", type_str);
gb_string_free(type_str);
return false;
}
@@ -2671,6 +2680,80 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
operand->mode = Addressing_NoValue;
} break;
case BuiltinProc_reserve: {
// reserve :: proc(^[dynamic]Type, count: int) {
Type *type = operand->type;
if (!is_type_pointer(type)) {
gbString str = type_to_string(type);
error_node(operand->expr, "Expected a pointer to a dynamic array, got `%s`", str);
gb_string_free(str);
return false;
}
type = type_deref(type);
if (!is_type_dynamic_array(type)) {
gbString str = type_to_string(type);
error_node(operand->expr, "Expected a pointer to a dynamic array, got `%s`", str);
gb_string_free(str);
return false;
}
AstNode *capacity = ce->args.e[1];
Operand op = {0};
check_expr(c, &op, capacity);
if (op.mode == Addressing_Invalid) {
return false;
}
Type *arg_type = base_type(op.type);
if (!is_type_integer(arg_type)) {
error_node(operand->expr, "`reserve` capacities must be an integer");
return false;
}
operand->type = NULL;
operand->mode = Addressing_NoValue;
} break;
case BuiltinProc_append: {
// append :: proc(^[dynamic]Type, item: Type) {
Type *type = operand->type;
if (!is_type_pointer(type)) {
gbString str = type_to_string(type);
error_node(operand->expr, "Expected a pointer to a dynamic array, got `%s`", str);
gb_string_free(str);
return false;
}
type = base_type(type_deref(type));
if (!is_type_dynamic_array(type)) {
gbString str = type_to_string(type);
error_node(operand->expr, "Expected a pointer to a dynamic array, got `%s`", str);
gb_string_free(str);
return false;
}
Type *elem = type->DynamicArray.elem;
AstNode *item = ce->args.e[1];
Operand op = {0};
check_expr(c, &op, item);
if (op.mode == Addressing_Invalid) {
return false;
}
Type *arg_type = op.type;
if (!check_is_assignable_to(c, &op, elem)) {
gbString elem_str = type_to_string(elem);
gbString str = type_to_string(arg_type);
error_node(operand->expr, "Expected `%s` for `append` item, got `%s`", elem_str, str);
gb_string_free(str);
gb_string_free(elem_str);
return false;
}
operand->type = NULL;
operand->mode = Addressing_NoValue;
} break;
case BuiltinProc_size_of: {
// size_of :: proc(Type) -> untyped int
Type *type = check_type(c, ce->args.e[0]);
@@ -3839,6 +3922,11 @@ bool check_set_index_data(Operand *o, Type *t, i64 *max_count) {
o->type = t->Slice.elem;
o->mode = Addressing_Variable;
return true;
case Type_DynamicArray:
o->type = t->DynamicArray.elem;
o->mode = Addressing_Variable;
return true;
}
return false;
@@ -4750,6 +4838,10 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
case Type_Slice:
valid = true;
break;
case Type_DynamicArray:
valid = true;
break;
}
if (!valid) {
@@ -5101,6 +5193,11 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
str = write_expr_to_string(str, at->elem);
case_end;
case_ast_node(at, DynamicArrayType, node);
str = gb_string_appendc(str, "[dynamic]");
str = write_expr_to_string(str, at->elem);
case_end;
case_ast_node(vt, VectorType, node);
str = gb_string_appendc(str, "[vector ");
str = write_expr_to_string(str, vt->count);

View File

@@ -697,6 +697,13 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
val = t->Array.elem;
idx = t_int;
break;
case Type_DynamicArray:
// val = make_type_pointer(c->allocator, t->DynamicArray.elem);
val = t->DynamicArray.elem;
idx = t_int;
break;
case Type_Slice:
// val = make_type_pointer(c->allocator, t->Slice.elem);
val = t->Slice.elem;

View File

@@ -125,6 +125,9 @@ typedef enum BuiltinProcId {
BuiltinProc_new_slice,
BuiltinProc_free,
BuiltinProc_reserve,
BuiltinProc_append,
BuiltinProc_size_of,
BuiltinProc_size_of_val,
BuiltinProc_align_of,
@@ -169,6 +172,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
{STR_LIT("new_slice"), 2, false, Expr_Expr},
{STR_LIT("free"), 1, false, Expr_Stmt},
{STR_LIT("reserve"), 2, false, Expr_Stmt},
{STR_LIT("append"), 2, false, Expr_Stmt},
{STR_LIT("size_of"), 1, false, Expr_Expr},
{STR_LIT("size_of_val"), 1, false, Expr_Expr},
{STR_LIT("align_of"), 1, false, Expr_Expr},

225
src/ir.c
View File

@@ -1620,6 +1620,13 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) {
case 0: result_type = make_type_pointer(a, t->Maybe.elem); break;
case 1: result_type = make_type_pointer(a, t_bool); break;
}
} else if (is_type_dynamic_array(t)) {
switch (index) {
case 0: result_type = make_type_pointer(a, make_type_pointer(a, t->DynamicArray.elem)); break;
case 1: result_type = t_int_ptr; break;
case 2: result_type = t_int_ptr; break;
case 3: result_type = t_allocator_ptr; break;
}
} else {
GB_PANIC("TODO(bill): struct_gep type: %s, %d", type_to_string(ir_type(s)), index);
}
@@ -1667,6 +1674,13 @@ irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) {
case 0: result_type = t->Maybe.elem; break;
case 1: result_type = t_bool; break;
}
} else if (is_type_dynamic_array(t)) {
switch (index) {
case 0: result_type = make_type_pointer(a, t->DynamicArray.elem); break;
case 1: result_type = t_int; break;
case 2: result_type = t_int; break;
case 3: result_type = t_allocator; break;
}
} else {
GB_PANIC("TODO(bill): struct_ev type: %s, %d", type_to_string(ir_type(s)), index);
}
@@ -1765,29 +1779,52 @@ irValue *ir_array_elem(irProcedure *proc, irValue *array) {
return ir_emit_array_ep(proc, array, v_zero32);
}
irValue *ir_array_len(irProcedure *proc, irValue *array) {
Type *t = ir_type(array);
Type *t = base_type(ir_type(array));
GB_ASSERT(t->kind == Type_Array);
return ir_make_const_int(proc->module->allocator, t->Array.count);
}
irValue *ir_slice_elem(irProcedure *proc, irValue *slice) {
Type *t = ir_type(slice);
Type *t = base_type(ir_type(slice));
GB_ASSERT(t->kind == Type_Slice);
return ir_emit_struct_ev(proc, slice, 0);
}
irValue *ir_slice_len(irProcedure *proc, irValue *slice) {
Type *t = ir_type(slice);
irValue *ir_slice_count(irProcedure *proc, irValue *slice) {
Type *t = base_type(ir_type(slice));
GB_ASSERT(t->kind == Type_Slice);
return ir_emit_struct_ev(proc, slice, 1);
}
irValue *ir_dynamic_array_elem(irProcedure *proc, irValue *da) {
Type *t = ir_type(da);
GB_ASSERT(t->kind == Type_DynamicArray);
return ir_emit_struct_ev(proc, da, 0);
}
irValue *ir_dynamic_array_count(irProcedure *proc, irValue *da) {
Type *t = base_type(ir_type(da));
GB_ASSERT_MSG(t->kind == Type_DynamicArray, "%s", type_to_string(t));
return ir_emit_struct_ev(proc, da, 1);
}
irValue *ir_dynamic_array_capacity(irProcedure *proc, irValue *da) {
Type *t = base_type(ir_type(da));
GB_ASSERT(t->kind == Type_DynamicArray);
return ir_emit_struct_ev(proc, da, 2);
}
irValue *ir_dynamic_array_allocator(irProcedure *proc, irValue *da) {
Type *t = base_type(ir_type(da));
GB_ASSERT(t->kind == Type_DynamicArray);
return ir_emit_struct_ev(proc, da, 3);
}
irValue *ir_string_elem(irProcedure *proc, irValue *string) {
Type *t = ir_type(string);
Type *t = base_type(ir_type(string));
GB_ASSERT(t->kind == Type_Basic && t->Basic.kind == Basic_string);
return ir_emit_struct_ev(proc, string, 0);
}
irValue *ir_string_len(irProcedure *proc, irValue *string) {
Type *t = ir_type(string);
Type *t = base_type(ir_type(string));
GB_ASSERT_MSG(t->kind == Type_Basic && t->Basic.kind == Basic_string, "%s", type_to_string(t));
return ir_emit_struct_ev(proc, string, 1);
}
@@ -1806,7 +1843,7 @@ irValue *ir_add_local_slice(irProcedure *proc, Type *slice_type, irValue *base,
if (high == NULL) {
switch (bt->kind) {
case Type_Array: high = ir_array_len(proc, base); break;
case Type_Slice: high = ir_slice_len(proc, base); break;
case Type_Slice: high = ir_slice_count(proc, base); break;
case Type_Pointer: high = v_one; break;
}
}
@@ -2069,7 +2106,7 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
// []byte/[]u8 <-> string
if (is_type_u8_slice(src) && is_type_string(dst)) {
irValue *elem = ir_slice_elem(proc, value);
irValue *len = ir_slice_len(proc, value);
irValue *len = ir_slice_count(proc, value);
return ir_emit_string(proc, elem, len);
}
if (is_type_string(src) && is_type_u8_slice(dst)) {
@@ -2912,12 +2949,25 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
case BuiltinProc_free: {
ir_emit_comment(proc, str_lit("free"));
gbAllocator allocator = proc->module->allocator;
gbAllocator a = proc->module->allocator;
AstNode *node = ce->args.e[0];
TypeAndValue tav = *type_and_value_of_expression(proc->module->info, node);
Type *type = base_type(tav.type);
irValue *val = ir_build_expr(proc, node);
if (is_type_dynamic_array(type)) {
irValue *da_allocator = ir_emit_struct_ev(proc, val, 3);
irValue *ptr = ir_emit_struct_ev(proc, val, 0);
ptr = ir_emit_conv(proc, ptr, t_rawptr);
irValue **args = gb_alloc_array(a, irValue *, 1);
args[0] = da_allocator;
args[1] = ptr;
return ir_emit_global_call(proc, "free_ptr_with_allocator", args, 2);
}
irValue *ptr = NULL;
if (is_type_pointer(type)) {
ptr = val;
@@ -2935,11 +2985,66 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
ptr = ir_emit_conv(proc, ptr, t_rawptr);
irValue **args = gb_alloc_array(allocator, irValue *, 1);
irValue **args = gb_alloc_array(a, irValue *, 1);
args[0] = ptr;
return ir_emit_global_call(proc, "free_ptr", args, 1);
} break;
case BuiltinProc_reserve: {
ir_emit_comment(proc, str_lit("reserve"));
gbAllocator a = proc->module->allocator;
irValue *array_ptr = ir_build_expr(proc, ce->args.e[0]);
Type *type = ir_type(array_ptr);
GB_ASSERT(is_type_pointer(type));
type = base_type(type_deref(type));
GB_ASSERT(is_type_dynamic_array(type));
Type *elem = type->DynamicArray.elem;
irValue *elem_size = ir_make_const_int(a, type_size_of(proc->module->sizes, a, elem));
irValue *elem_align = ir_make_const_int(a, type_align_of(proc->module->sizes, a, elem));
array_ptr = ir_emit_conv(proc, array_ptr, t_rawptr);
irValue *capacity = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t_int);
irValue **args = gb_alloc_array(a, irValue *, 4);
args[0] = array_ptr;
args[1] = elem_size;
args[2] = elem_align;
args[3] = capacity;
return ir_emit_global_call(proc, "__dynamic_array_reserve", args, 4);
} break;
case BuiltinProc_append: {
ir_emit_comment(proc, str_lit("append"));
gbAllocator a = proc->module->allocator;
irValue *array_ptr = ir_build_expr(proc, ce->args.e[0]);
Type *type = ir_type(array_ptr);
GB_ASSERT(is_type_pointer(type));
type = base_type(type_deref(type));
GB_ASSERT(is_type_dynamic_array(type));
Type *elem = type->DynamicArray.elem;
irValue *elem_size = ir_make_const_int(a, type_size_of(proc->module->sizes, a, elem));
irValue *elem_align = ir_make_const_int(a, type_align_of(proc->module->sizes, a, elem));
array_ptr = ir_emit_conv(proc, array_ptr, t_rawptr);
irValue *item_ptr = ir_add_local_generated(proc, elem);
irValue *item = ir_build_expr(proc, ce->args.e[1]);
ir_emit_store(proc, item_ptr, item);
irValue **args = gb_alloc_array(a, irValue *, 4);
args[0] = array_ptr;
args[1] = elem_size;
args[2] = elem_align;
args[3] = ir_emit_conv(proc, item_ptr, t_rawptr);
return ir_emit_global_call(proc, "__dynamic_array_append", args, 4);
} break;
case BuiltinProc_assert: {
ir_emit_comment(proc, str_lit("assert"));
irValue *cond = ir_build_expr(proc, ce->args.e[0]);
@@ -3010,8 +3115,8 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
irValue *dst = ir_emit_conv(proc, ir_slice_elem(proc, dst_slice), t_rawptr);
irValue *src = ir_emit_conv(proc, ir_slice_elem(proc, src_slice), t_rawptr);
irValue *len_dst = ir_slice_len(proc, dst_slice);
irValue *len_src = ir_slice_len(proc, src_slice);
irValue *len_dst = ir_slice_count(proc, dst_slice);
irValue *len_src = ir_slice_count(proc, src_slice);
irValue *cond = ir_emit_comp(proc, Token_Lt, len_dst, len_src);
irValue *len = ir_emit_select(proc, cond, len_dst, len_src);
@@ -3038,7 +3143,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
irValue *slice = ir_emit_load(proc, slice_ptr);
irValue *elem = ir_slice_elem(proc, slice);
irValue *len = ir_slice_len(proc, slice);
irValue *len = ir_slice_count(proc, slice);
irValue *cap = ir_slice_cap(proc, slice);
Type *elem_type = type_deref(ir_type(elem));
@@ -3522,14 +3627,32 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
}
}
irValue *elem = ir_slice_elem(proc, slice);
irValue *len = ir_slice_len(proc, slice);
irValue *len = ir_slice_count(proc, slice);
irValue *index = ir_emit_conv(proc, ir_build_expr(proc, ie->index), t_int);
ir_emit_bounds_check(proc, ast_node_token(ie->index), index, len);
irValue *v = ir_emit_ptr_offset(proc, elem, index);
return ir_make_addr(v, expr);
} break;
case Type_DynamicArray: {
irValue *dynamic_array = NULL;
if (using_addr != NULL) {
dynamic_array = ir_emit_load(proc, using_addr);
} else {
dynamic_array = ir_build_expr(proc, ie->expr);
if (deref) {
dynamic_array = ir_emit_load(proc, dynamic_array);
}
}
irValue *elem = ir_dynamic_array_elem(proc, dynamic_array);
irValue *len = ir_dynamic_array_count(proc, dynamic_array);
irValue *index = ir_emit_conv(proc, ir_build_expr(proc, ie->index), t_int);
ir_emit_bounds_check(proc, ast_node_token(ie->index), index, len);
irValue *v = ir_emit_ptr_offset(proc, elem, index);
return ir_make_addr(v, expr);
} break;
case Type_Basic: { // Basic_string
TypeAndValue *tv = map_tav_get(&proc->module->info->types, hash_pointer(ie->expr));
irValue *str;
@@ -3580,7 +3703,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
case Type_Slice: {
Type *slice_type = type;
if (high == NULL) high = ir_slice_len(proc, base);
if (high == NULL) high = ir_slice_count(proc, base);
ir_emit_slice_bounds_check(proc, se->open, low, high, false);
@@ -3588,14 +3711,30 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
irValue *len = ir_emit_arith(proc, Token_Sub, high, low, t_int);
irValue *slice = ir_add_local_generated(proc, slice_type);
irValue *gep0 = ir_emit_struct_ep(proc, slice, 0);
irValue *gep1 = ir_emit_struct_ep(proc, slice, 1);
ir_emit_store(proc, gep0, elem);
ir_emit_store(proc, gep1, len);
ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 0), elem);
ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 1), len);
return ir_make_addr(slice, expr);
}
case Type_DynamicArray: {
Type *dynamic_array = type;
if (high == NULL) high = ir_dynamic_array_count(proc, base);
ir_emit_slice_bounds_check(proc, se->open, low, high, false);
irValue *elem = ir_emit_ptr_offset(proc, ir_dynamic_array_elem(proc, base), low);
irValue *len = ir_emit_arith(proc, Token_Sub, high, low, t_int);
irValue *slice = ir_add_local_generated(proc, dynamic_array);
ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 0), elem);
ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 1), len);
return ir_make_addr(slice, expr);
}
case Type_Array: {
Type *slice_type = make_type_slice(a, type->Array.elem);
@@ -3607,10 +3746,8 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
irValue *len = ir_emit_arith(proc, Token_Sub, high, low, t_int);
irValue *slice = ir_add_local_generated(proc, slice_type);
irValue *gep0 = ir_emit_struct_ep(proc, slice, 0);
irValue *gep1 = ir_emit_struct_ep(proc, slice, 1);
ir_emit_store(proc, gep0, elem);
ir_emit_store(proc, gep1, len);
ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 0), elem);
ir_emit_store(proc, ir_emit_struct_ep(proc, slice, 1), len);
return ir_make_addr(slice, expr);
}
@@ -3973,7 +4110,7 @@ void ir_emit_increment(irProcedure *proc, irValue *addr) {
}
void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type,
void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type, irValue *count_ptr,
irValue **val_, irValue **idx_, irBlock **loop_, irBlock **done_) {
irValue *count = NULL;
Type *expr_type = base_type(type_deref(ir_type(expr)));
@@ -3981,12 +4118,6 @@ void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type,
case Type_Array:
count = ir_make_const_int(proc->module->allocator, expr_type->Array.count);
break;
case Type_Slice:
count = ir_slice_len(proc, expr);
break;
default:
GB_PANIC("Cannot do range_indexed of %s", type_to_string(expr_type));
break;
}
irValue *val = NULL;
@@ -4007,6 +4138,9 @@ void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type,
body = ir_add_block(proc, NULL, "for.index.body");
done = ir_add_block(proc, NULL, "for.index.done");
if (count == NULL) {
count = ir_emit_load(proc, count_ptr);
}
irValue *cond = ir_emit_comp(proc, Token_Lt, incr, count);
ir_emit_if(proc, cond, body, done);
proc->curr_block = body;
@@ -4020,7 +4154,10 @@ void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type,
} break;
case Type_Slice: {
irValue *elem = ir_slice_elem(proc, expr);
// val = ir_emit_ptr_offset(proc, elem, idx);
val = ir_emit_load(proc, ir_emit_ptr_offset(proc, elem, idx));
} break;
case Type_DynamicArray: {
irValue *elem = ir_dynamic_array_elem(proc, expr);
val = ir_emit_load(proc, ir_emit_ptr_offset(proc, elem, idx));
} break;
default:
@@ -4578,18 +4715,38 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
Type *et = base_type(type_deref(expr_type));
switch (et->kind) {
case Type_Array: {
irValue *count_ptr = NULL;
irValue *array = ir_build_addr(proc, rs->expr).addr;
if (is_type_pointer(type_deref(ir_type(array)))) {
array = ir_emit_load(proc, array);
}
ir_build_range_indexed(proc, array, val_type, &val, &index, &loop, &done);
count_ptr = ir_add_local_generated(proc, t_int);
ir_emit_store(proc, count_ptr, ir_make_const_int(proc->module->allocator, et->Array.count));
ir_build_range_indexed(proc, array, val_type, count_ptr, &val, &index, &loop, &done);
} break;
case Type_DynamicArray: {
irValue *count_ptr = NULL;
irValue *array = ir_build_expr(proc, rs->expr);
if (is_type_pointer(type_deref(ir_type(array)))) {
count_ptr = ir_emit_struct_ep(proc, array, 1);
array = ir_emit_load(proc, array);
} else {
count_ptr = ir_add_local_generated(proc, t_int);
ir_emit_store(proc, count_ptr, ir_dynamic_array_count(proc, array));
}
ir_build_range_indexed(proc, array, val_type, count_ptr, &val, &index, &loop, &done);
} break;
case Type_Slice: {
irValue *count_ptr = NULL;
irValue *slice = ir_build_expr(proc, rs->expr);
if (is_type_pointer(ir_type(slice))) {
count_ptr = ir_emit_struct_ep(proc, slice, 1);
slice = ir_emit_load(proc, slice);
} else {
count_ptr = ir_add_local_generated(proc, t_int);
ir_emit_store(proc, count_ptr, ir_slice_count(proc, slice));
}
ir_build_range_indexed(proc, slice, val_type, &val, &index, &loop, &done);
ir_build_range_indexed(proc, slice, val_type, count_ptr, &val, &index, &loop, &done);
} break;
case Type_Basic: {
irValue *string = ir_build_expr(proc, rs->expr);

View File

@@ -194,6 +194,13 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
ir_print_type(f, m, t->Slice.elem);
ir_fprintf(f, "*, i%lld, i%lld}", word_bits, word_bits);
return;
case Type_DynamicArray:
ir_fprintf(f, "{");
ir_print_type(f, m, t->Slice.elem);
ir_fprintf(f, "*, i%lld, i%lld,", word_bits, word_bits);
ir_print_type(f, m, t_allocator);
ir_fprintf(f, "}");
return;
case Type_Record: {
switch (t->Record.kind) {
case TypeRecord_Struct:

View File

@@ -341,6 +341,10 @@ AST_NODE_KIND(_TypeBegin, "", i32) \
AstNode *count; \
AstNode *elem; \
}) \
AST_NODE_KIND(DynamicArrayType, "dynamic array type", struct { \
Token token; \
AstNode *elem; \
}) \
AST_NODE_KIND(VectorType, "vector type", struct { \
Token token; \
AstNode *count; \
@@ -553,6 +557,8 @@ Token ast_node_token(AstNode *node) {
return node->MaybeType.token;
case AstNode_ArrayType:
return node->ArrayType.token;
case AstNode_DynamicArrayType:
return node->DynamicArrayType.token;
case AstNode_VectorType:
return node->VectorType.token;
case AstNode_StructType:
@@ -1080,6 +1086,13 @@ AstNode *make_array_type(AstFile *f, Token token, AstNode *count, AstNode *elem)
return result;
}
AstNode *make_dynamic_array_type(AstFile *f, Token token, AstNode *elem) {
AstNode *result = make_node(f, AstNode_DynamicArrayType);
result->DynamicArrayType.token = token;
result->DynamicArrayType.elem = elem;
return result;
}
AstNode *make_vector_type(AstFile *f, Token token, AstNode *count, AstNode *elem) {
AstNode *result = make_node(f, AstNode_VectorType);
result->VectorType.token = token;
@@ -1267,7 +1280,6 @@ void fix_advance_to_next_stmt(AstFile *f) {
case Token_if:
case Token_when:
case Token_return:
case Token_range:
case Token_match:
case Token_defer:
case Token_asm:
@@ -1463,7 +1475,7 @@ AstNode *parse_value(AstFile *f) {
return value;
}
AstNode *parse_identifier_or_type(AstFile *f);
AstNode *parse_type_or_ident(AstFile *f);
void check_proc_add_tag(AstFile *f, AstNode *tag_expr, u64 *tags, ProcTag tag, String tag_name) {
@@ -1839,7 +1851,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
break;
default: {
AstNode *type = parse_identifier_or_type(f);
AstNode *type = parse_type_or_ident(f);
if (type != NULL) {
// TODO(bill): Is this correct???
// NOTE(bill): Sanity check as identifiers should be handled already
@@ -2204,7 +2216,7 @@ void parse_check_name_list_for_reserves(AstFile *f, AstNodeArray names) {
}
AstNode *parse_type_attempt(AstFile *f) {
AstNode *type = parse_identifier_or_type(f);
AstNode *type = parse_type_or_ident(f);
if (type != NULL) {
// TODO(bill): Handle?
}
@@ -2415,7 +2427,7 @@ AstNode *parse_var_type(AstFile *f, bool allow_ellipsis) {
if (allow_ellipsis && f->curr_token.kind == Token_Ellipsis) {
Token tok = f->curr_token;
next_token(f);
AstNode *type = parse_identifier_or_type(f);
AstNode *type = parse_type_or_ident(f);
if (type == NULL) {
error(tok, "variadic field missing type after `...`");
type = make_bad_expr(f, tok, f->curr_token);
@@ -2561,7 +2573,7 @@ AstNodeArray parse_record_fields(AstFile *f, isize *field_count_, u32 flags, Str
return parse_field_list(f, field_count_, flags, Token_Comma, Token_CloseBrace);
}
AstNode *parse_identifier_or_type(AstFile *f) {
AstNode *parse_type_or_ident(AstFile *f) {
switch (f->curr_token.kind) {
case Token_Ident: {
AstNode *e = parse_identifier(f);
@@ -2597,7 +2609,6 @@ AstNode *parse_identifier_or_type(AstFile *f) {
}
case Token_OpenBracket: {
f->expr_level++;
Token token = expect_token(f, Token_OpenBracket);
AstNode *count_expr = NULL;
bool is_vector = false;
@@ -2607,16 +2618,23 @@ AstNode *parse_identifier_or_type(AstFile *f) {
} else if (f->curr_token.kind == Token_vector) {
next_token(f);
if (f->curr_token.kind != Token_CloseBracket) {
f->expr_level++;
count_expr = parse_expr(f, false);
f->expr_level--;
} else {
syntax_error(f->curr_token, "Vector type missing count");
}
is_vector = true;
} else if (f->curr_token.kind == Token_dynamic) {
next_token(f);
expect_token(f, Token_CloseBracket);
return make_dynamic_array_type(f, token, parse_type(f));
} else if (f->curr_token.kind != Token_CloseBracket) {
f->expr_level++;
count_expr = parse_expr(f, false);
f->expr_level--;
}
expect_token(f, Token_CloseBracket);
f->expr_level--;
if (is_vector) {
return make_vector_type(f, token, count_expr, parse_type(f));
}

View File

@@ -80,41 +80,40 @@ TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \
TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
\
TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
TOKEN_KIND(Token_type, "type"), \
TOKEN_KIND(Token_proc, "proc"), \
TOKEN_KIND(Token_macro, "macro"), \
TOKEN_KIND(Token_match, "match"), \
TOKEN_KIND(Token_break, "break"), \
TOKEN_KIND(Token_continue, "continue"), \
TOKEN_KIND(Token_fallthrough, "fallthrough"), \
TOKEN_KIND(Token_case, "case"), \
TOKEN_KIND(Token_default, "default"), \
TOKEN_KIND(Token_then, "then"), \
TOKEN_KIND(Token_when, "when"), \
TOKEN_KIND(Token_if, "if"), \
TOKEN_KIND(Token_else, "else"), \
TOKEN_KIND(Token_for, "for"), \
TOKEN_KIND(Token_in, "in"), \
TOKEN_KIND(Token_when, "when"), \
TOKEN_KIND(Token_range, "range"), \
TOKEN_KIND(Token_break, "break"), \
TOKEN_KIND(Token_continue, "continue"), \
TOKEN_KIND(Token_fallthrough, "fallthrough"), \
TOKEN_KIND(Token_match, "match"), \
TOKEN_KIND(Token_type, "type"), \
TOKEN_KIND(Token_default, "default"), \
TOKEN_KIND(Token_case, "case"), \
TOKEN_KIND(Token_defer, "defer"), \
TOKEN_KIND(Token_return, "return"), \
TOKEN_KIND(Token_give, "give"), \
TOKEN_KIND(Token_proc, "proc"), \
TOKEN_KIND(Token_macro, "macro"), \
TOKEN_KIND(Token_struct, "struct"), \
TOKEN_KIND(Token_union, "union"), \
TOKEN_KIND(Token_raw_union, "raw_union"), \
TOKEN_KIND(Token_enum, "enum"), \
TOKEN_KIND(Token_vector, "vector"), \
TOKEN_KIND(Token_dynamic, "dynamic"), \
TOKEN_KIND(Token_using, "using"), \
TOKEN_KIND(Token_no_alias, "no_alias"), \
TOKEN_KIND(Token_immutable, "immutable"), \
TOKEN_KIND(Token_thread_local, "thread_local"), \
TOKEN_KIND(Token_asm, "asm"), \
TOKEN_KIND(Token_push_allocator, "push_allocator"), \
TOKEN_KIND(Token_push_context, "push_context"), \
TOKEN_KIND(Token_cast, "cast"), \
TOKEN_KIND(Token_transmute, "transmute"), \
TOKEN_KIND(Token_down_cast, "down_cast"), \
TOKEN_KIND(Token_union_cast, "union_cast"), \
TOKEN_KIND(Token_push_allocator, "push_allocator"), \
TOKEN_KIND(Token_push_context, "push_context"), \
TOKEN_KIND(Token_asm, "asm"), \
TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \
TOKEN_KIND(Token_Count, "")
@@ -264,20 +263,20 @@ void compiler_error(char *fmt, ...) {
gb_inline bool token_is_literal(Token t) {
return gb_is_between(t.kind, Token__LiteralBegin+1, Token__LiteralEnd-1);
gb_inline bool token_is_literal(TokenKind t) {
return gb_is_between(t, Token__LiteralBegin+1, Token__LiteralEnd-1);
}
gb_inline bool token_is_operator(Token t) {
return gb_is_between(t.kind, Token__OperatorBegin+1, Token__OperatorEnd-1);
gb_inline bool token_is_operator(TokenKind t) {
return gb_is_between(t, Token__OperatorBegin+1, Token__OperatorEnd-1);
}
gb_inline bool token_is_keyword(Token t) {
return gb_is_between(t.kind, Token__KeywordBegin+1, Token__KeywordEnd-1);
gb_inline bool token_is_keyword(TokenKind t) {
return gb_is_between(t, Token__KeywordBegin+1, Token__KeywordEnd-1);
}
gb_inline bool token_is_comparison(Token t) {
return gb_is_between(t.kind, Token__ComparisonBegin+1, Token__ComparisonEnd-1);
gb_inline bool token_is_comparison(TokenKind t) {
return gb_is_between(t, Token__ComparisonBegin+1, Token__ComparisonEnd-1);
}
gb_inline bool token_is_shift(Token t) {
return t.kind == Token_Shl || t.kind == Token_Shr;
gb_inline bool token_is_shift(TokenKind t) {
return t == Token_Shl || t == Token_Shr;
}
gb_inline void print_token(Token t) { gb_printf("%.*s\n", LIT(t.string)); }

View File

@@ -97,6 +97,7 @@ typedef struct TypeRecord {
TYPE_KIND(Basic, BasicType) \
TYPE_KIND(Pointer, struct { Type *elem; }) \
TYPE_KIND(Array, struct { Type *elem; i64 count; }) \
TYPE_KIND(DynamicArray, struct { Type *elem; }) \
TYPE_KIND(Vector, struct { Type *elem; i64 count; }) \
TYPE_KIND(Slice, struct { Type *elem; }) \
TYPE_KIND(Maybe, struct { Type *elem; }) \
@@ -385,6 +386,12 @@ Type *make_type_array(gbAllocator a, Type *elem, i64 count) {
return t;
}
Type *make_type_dynamic_array(gbAllocator a, Type *elem) {
Type *t = alloc_type(a, Type_DynamicArray);
t->DynamicArray.elem = elem;
return t;
}
Type *make_type_vector(gbAllocator a, Type *elem, i64 count) {
Type *t = alloc_type(a, Type_Vector);
t->Vector.elem = elem;
@@ -616,6 +623,10 @@ bool is_type_array(Type *t) {
t = base_type(t);
return t->kind == Type_Array;
}
bool is_type_dynamic_array(Type *t) {
t = base_type(t);
return t->kind == Type_DynamicArray;
}
bool is_type_slice(Type *t) {
t = base_type(t);
return t->kind == Type_Slice;
@@ -690,6 +701,7 @@ bool type_has_nil(Type *t) {
return false;
} break;
case Type_Slice:
case Type_DynamicArray:
case Type_Proc:
case Type_Pointer:
case Type_Maybe:
@@ -750,6 +762,12 @@ bool are_types_identical(Type *x, Type *y) {
}
break;
case Type_DynamicArray:
if (y->kind == Type_DynamicArray) {
return are_types_identical(x->DynamicArray.elem, y->DynamicArray.elem);
}
break;
case Type_Vector:
if (y->kind == Type_Vector) {
return (x->Vector.count == y->Vector.count) && are_types_identical(x->Vector.elem, y->Vector.elem);
@@ -973,7 +991,10 @@ gb_global Entity *entity__any_data = NULL;
gb_global Entity *entity__string_data = NULL;
gb_global Entity *entity__string_count = NULL;
gb_global Entity *entity__slice_count = NULL;
gb_global Entity *entity__slice_capacity = NULL;
gb_global Entity *entity__dynamic_array_count = NULL;
gb_global Entity *entity__dynamic_array_capacity = NULL;
gb_global Entity *entity__dynamic_array_allocator = NULL;
Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_name, bool is_type, Selection sel);
@@ -1142,6 +1163,39 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
sel.entity = entity__slice_count;
return sel;
}
} else if (type->kind == Type_DynamicArray) {
String data_str = str_lit("data");
String count_str = str_lit("count");
String capacity_str = str_lit("capacity");
String allocator_str = str_lit("allocator");
if (str_eq(field_name, data_str)) {
selection_add_index(&sel, 0);
// HACK(bill): Memory leak
sel.entity = make_entity_field(a, NULL, make_token_ident(data_str), make_type_pointer(a, type->DynamicArray.elem), false, 0);
return sel;
} else if (str_eq(field_name, count_str)) {
selection_add_index(&sel, 1);
if (entity__dynamic_array_count == NULL) {
entity__dynamic_array_count = make_entity_field(a, NULL, make_token_ident(count_str), t_int, false, 1);
}
sel.entity = entity__dynamic_array_count;
return sel;
} else if (str_eq(field_name, capacity_str)) {
selection_add_index(&sel, 2);
if (entity__dynamic_array_capacity == NULL) {
entity__dynamic_array_capacity = make_entity_field(a, NULL, make_token_ident(capacity_str), t_int, false, 2);
}
sel.entity = entity__dynamic_array_capacity;
return sel;
} else if (str_eq(field_name, allocator_str)) {
selection_add_index(&sel, 3);
if (entity__dynamic_array_allocator == NULL) {
entity__dynamic_array_allocator = make_entity_field(a, NULL, make_token_ident(allocator_str), t_allocator, false, 3);
}
sel.entity = entity__dynamic_array_allocator;
return sel;
}
}
if (type->kind != Type_Record) {
@@ -1351,6 +1405,14 @@ i64 type_align_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, Type
type_path_pop(path);
return align;
}
case Type_DynamicArray:
// data, count, capacity, allocator
return s.word_size;
case Type_Slice:
return s.word_size;
case Type_Vector: {
Type *elem = t->Vector.elem;
type_path_push(path, elem);
@@ -1537,6 +1599,9 @@ i64 type_size_of_internal(BaseTypeSizes s, gbAllocator allocator, Type *t, TypeP
return alignment*(count-1) + size;
} break;
case Type_DynamicArray:
return 3*s.word_size + type_size_of(s, allocator, t_allocator);
case Type_Vector: {
i64 count, bit_size, total_size_in_bits, total_size;
count = t->Vector.count;
@@ -1736,6 +1801,11 @@ gbString write_type_to_string(gbString str, Type *type) {
str = write_type_to_string(str, type->Array.elem);
break;
case Type_DynamicArray:
str = gb_string_appendc(str, "[dynamic]");
str = write_type_to_string(str, type->DynamicArray.elem);
break;
case Type_Record: {
switch (type->Record.kind) {
case TypeRecord_Struct: