mirror of
https://github.com/odin-lang/Odin.git
synced 2026-01-06 04:57:55 +00:00
Dynamic arrays
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
109
src/check_expr.c
109
src/check_expr.c
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
225
src/ir.c
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
34
src/parser.c
34
src/parser.c
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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)); }
|
||||
|
||||
72
src/types.c
72
src/types.c
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user