mirror of
https://github.com/odin-lang/Odin.git
synced 2026-01-06 13:07:59 +00:00
Add parse_int; Fix union bugs with size, alignment, and recursive definition checking
This commit is contained in:
@@ -18,6 +18,52 @@ parse_bool :: proc(s: string) -> (result: bool, ok: bool) {
|
||||
return false, false;
|
||||
}
|
||||
|
||||
_digit_value :: proc(r: rune) -> (int) {
|
||||
ri := cast(int)r;
|
||||
v: int = 16;
|
||||
match {
|
||||
case '0' <= r && r <= '9':
|
||||
v = ri - '0';
|
||||
case 'a' <= r && r <= 'z':
|
||||
v = ri - 'a' + 10;
|
||||
case 'A' <= r && r <= 'Z':
|
||||
v = ri - 'A' + 10;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
parse_i64 :: proc(s: string, base: int) -> i64 {
|
||||
result: i64;
|
||||
for r in s {
|
||||
v := _digit_value(r);
|
||||
if v >= base {
|
||||
break;
|
||||
}
|
||||
result *= cast(i64)base;
|
||||
result += cast(i64)v;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
parse_u64 :: proc(s: string, base: int) -> u64 {
|
||||
result: u64;
|
||||
for r in s {
|
||||
v := _digit_value(r);
|
||||
if v >= base {
|
||||
break;
|
||||
}
|
||||
result *= cast(u64)base;
|
||||
result += cast(u64)v;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
parse_int :: proc(s: string, base: int) -> int {
|
||||
return cast(int)parse_i64(s, base);
|
||||
}
|
||||
parse_uint :: proc(s: string, base: int) -> uint {
|
||||
return cast(uint)parse_u64(s, base);
|
||||
}
|
||||
|
||||
|
||||
append_bool :: proc(buf: []byte, b: bool) -> string {
|
||||
s := b ? "true" : "false";
|
||||
append(buf, ..cast([]byte)s);
|
||||
|
||||
@@ -601,6 +601,8 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) {
|
||||
|
||||
union_type->Record.fields = fields;
|
||||
union_type->Record.field_count = field_count;
|
||||
union_type->Record.are_offsets_set = false;
|
||||
|
||||
|
||||
for_array(i, ut->variants) {
|
||||
AstNode *variant = ut->variants.e[i];
|
||||
@@ -668,6 +670,8 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) {
|
||||
add_entity_use(c, f->name, e);
|
||||
}
|
||||
|
||||
type_set_offsets(c->allocator, union_type);
|
||||
|
||||
gb_temp_arena_memory_end(tmp);
|
||||
|
||||
union_type->Record.variants = variants;
|
||||
|
||||
55
src/ir.c
55
src/ir.c
@@ -886,7 +886,7 @@ irValue *ir_instr_union_tag_value(irProcedure *p, irValue *address) {
|
||||
irValue *v = ir_alloc_instr(p, irInstr_UnionTagValue);
|
||||
irInstr *i = &v->Instr;
|
||||
i->UnionTagValue.address = address;
|
||||
i->UnionTagValue.type = t_int_ptr;
|
||||
i->UnionTagValue.type = t_int;
|
||||
return v;
|
||||
}
|
||||
|
||||
@@ -1986,6 +1986,27 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *
|
||||
return ir_emit(proc, ir_instr_binary_op(proc, op, left, right, type));
|
||||
}
|
||||
|
||||
irValue *ir_emit_union_tag_ptr(irProcedure *proc, irValue *u) {
|
||||
Type *t = ir_type(u);
|
||||
GB_ASSERT_MSG(is_type_pointer(t) &&
|
||||
is_type_union(type_deref(t)), "%s", type_to_string(t));
|
||||
irValue *tag_ptr = ir_emit(proc, ir_instr_union_tag_ptr(proc, u));
|
||||
Type *tpt = ir_type(tag_ptr);
|
||||
GB_ASSERT(is_type_pointer(tpt));
|
||||
tpt = base_type(type_deref(tpt));
|
||||
GB_ASSERT(tpt == t_int);
|
||||
return tag_ptr;
|
||||
}
|
||||
|
||||
irValue *ir_emit_union_tag_value(irProcedure *proc, irValue *u) {
|
||||
Type *t = ir_type(u);
|
||||
GB_ASSERT(is_type_union(t));
|
||||
GB_ASSERT(are_types_identical(t, ir_type(u)));
|
||||
return ir_emit(proc, ir_instr_union_tag_value(proc, u));
|
||||
}
|
||||
|
||||
irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irValue *right);
|
||||
|
||||
irValue *ir_emit_comp_against_nil(irProcedure *proc, TokenKind op_kind, irValue *x) {
|
||||
Type *t = ir_type(x);
|
||||
if (is_type_any(t)) {
|
||||
@@ -2034,6 +2055,9 @@ irValue *ir_emit_comp_against_nil(irProcedure *proc, TokenKind op_kind, irValue
|
||||
} else if (op_kind == Token_NotEq) {
|
||||
return ir_emit_arith(proc, Token_And, a, b, t_bool);
|
||||
}
|
||||
} else if (is_type_union(t)) {
|
||||
irValue *tag = ir_emit_union_tag_value(proc, x);
|
||||
return ir_emit_comp(proc, op_kind, tag, v_zero);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -2108,25 +2132,6 @@ irValue *ir_emit_array_epi(irProcedure *proc, irValue *s, i32 index) {
|
||||
return ir_emit_array_ep(proc, s, ir_const_i32(proc->module->allocator, index));
|
||||
}
|
||||
|
||||
irValue *ir_emit_union_tag_ptr(irProcedure *proc, irValue *u) {
|
||||
Type *t = ir_type(u);
|
||||
GB_ASSERT_MSG(is_type_pointer(t) &&
|
||||
is_type_union(type_deref(t)), "%s", type_to_string(t));
|
||||
irValue *tag_ptr = ir_emit(proc, ir_instr_union_tag_ptr(proc, u));
|
||||
Type *tpt = ir_type(tag_ptr);
|
||||
GB_ASSERT(is_type_pointer(tpt));
|
||||
tpt = base_type(type_deref(tpt));
|
||||
GB_ASSERT(tpt == t_int);
|
||||
return tag_ptr;
|
||||
}
|
||||
|
||||
irValue *ir_emit_union_tag_value(irProcedure *proc, irValue *u) {
|
||||
Type *t = ir_type(u);
|
||||
GB_ASSERT(is_type_union(t));
|
||||
GB_ASSERT(are_types_identical(t, ir_type(u)));
|
||||
return ir_emit(proc, ir_instr_union_tag_value(proc, u));
|
||||
}
|
||||
|
||||
|
||||
|
||||
irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) {
|
||||
@@ -2697,14 +2702,14 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
|
||||
Entity *f = dst->Record.variants[i];
|
||||
if (are_types_identical(f->type, src_type)) {
|
||||
ir_emit_comment(proc, str_lit("union - child to parent"));
|
||||
gbAllocator allocator = proc->module->allocator;
|
||||
gbAllocator a = proc->module->allocator;
|
||||
irValue *parent = ir_add_local_generated(proc, t);
|
||||
irValue *tag_ptr = ir_emit_union_tag_ptr(proc, parent);
|
||||
ir_emit_store(proc, tag_ptr, ir_const_int(allocator, i));
|
||||
|
||||
irValue *underlying = ir_emit_conv(proc, parent, make_type_pointer(allocator, src_type));
|
||||
irValue *underlying = ir_emit_conv(proc, parent, make_type_pointer(a, src_type));
|
||||
ir_emit_store(proc, underlying, value);
|
||||
|
||||
irValue *tag_ptr = ir_emit_union_tag_ptr(proc, parent);
|
||||
ir_emit_store(proc, tag_ptr, ir_const_int(a, i));
|
||||
|
||||
return ir_emit_load(proc, parent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,7 +231,7 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
||||
case TypeRecord_Union: {
|
||||
// NOTE(bill): The zero size array is used to fix the alignment used in a structure as
|
||||
// LLVM takes the first element's alignment as the entire alignment (like C)
|
||||
i64 size_of_union = type_size_of(heap_allocator(), t) - build_context.word_size;
|
||||
i64 size_of_union = type_size_of(heap_allocator(), t) - build_context.word_size;
|
||||
i64 align_of_union = type_align_of(heap_allocator(), t);
|
||||
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8], i%lld}", align_of_union, size_of_union, word_bits);
|
||||
} return;
|
||||
|
||||
@@ -1197,7 +1197,11 @@ Token expect_token(AstFile *f, TokenKind kind) {
|
||||
syntax_error(f->curr_token, "Expected `%.*s`, got `%.*s`",
|
||||
LIT(token_strings[kind]),
|
||||
LIT(token_strings[prev.kind]));
|
||||
if (prev.kind == Token_EOF) {
|
||||
gb_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
next_token(f);
|
||||
return prev;
|
||||
}
|
||||
|
||||
59
src/types.c
59
src/types.c
@@ -402,6 +402,7 @@ void set_base_type(Type *t, Type *base) {
|
||||
|
||||
Type *alloc_type(gbAllocator a, TypeKind kind) {
|
||||
Type *t = gb_alloc_item(a, Type);
|
||||
gb_zero_item(t);
|
||||
t->kind = kind;
|
||||
return t;
|
||||
}
|
||||
@@ -837,6 +838,12 @@ bool type_has_nil(Type *t) {
|
||||
case Type_DynamicArray:
|
||||
case Type_Map:
|
||||
return true;
|
||||
case Type_Record:
|
||||
switch (t->Record.kind) {
|
||||
case TypeRecord_Union:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1138,7 +1145,6 @@ ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) {
|
||||
Entity *ey = py.params->Tuple.variables[0];
|
||||
bool ok = are_types_identical(ex->type, ey->type);
|
||||
if (ok) {
|
||||
gb_printf_err("Here\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1520,7 +1526,7 @@ void type_path_free(TypePath *tp) {
|
||||
TypePath *type_path_push(TypePath *tp, Type *t) {
|
||||
GB_ASSERT(tp != NULL);
|
||||
|
||||
for_array(i, tp->path) {
|
||||
for (isize i = 0; i < tp->path.count; i++) {
|
||||
if (tp->path.e[i] == t) {
|
||||
// TODO(bill):
|
||||
GB_ASSERT(is_type_named(t));
|
||||
@@ -1601,6 +1607,7 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
if (t->failure) {
|
||||
return FAILURE_ALIGNMENT;
|
||||
}
|
||||
|
||||
t = base_type(t);
|
||||
|
||||
switch (t->kind) {
|
||||
@@ -1705,6 +1712,18 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
break;
|
||||
case TypeRecord_Union: {
|
||||
i64 max = 1;
|
||||
if (t->Record.field_count > 0) {
|
||||
Type *field_type = t->Record.fields[0]->type;
|
||||
type_path_push(path, field_type);
|
||||
if (path->failure) {
|
||||
return FAILURE_ALIGNMENT;
|
||||
}
|
||||
i64 align = type_align_of_internal(allocator, field_type, path);
|
||||
type_path_pop(path);
|
||||
if (max < align) {
|
||||
max = align;
|
||||
}
|
||||
}
|
||||
// NOTE(bill): field zero is null
|
||||
for (isize i = 1; i < t->Record.variant_count; i++) {
|
||||
Type *variant = t->Record.variants[i]->type;
|
||||
@@ -1795,8 +1814,18 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
if (t->failure) {
|
||||
return FAILURE_SIZE;
|
||||
}
|
||||
t = base_type(t);
|
||||
|
||||
switch (t->kind) {
|
||||
case Type_Named: {
|
||||
type_path_push(path, t);
|
||||
if (path->failure) {
|
||||
return FAILURE_ALIGNMENT;
|
||||
}
|
||||
i64 size = type_size_of_internal(allocator, t->Named.base, path);
|
||||
type_path_pop(path);
|
||||
return size;
|
||||
} break;
|
||||
|
||||
case Type_Basic: {
|
||||
GB_ASSERT(is_type_typed(t));
|
||||
BasicKind kind = t->Basic.kind;
|
||||
@@ -1907,15 +1936,26 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
} break;
|
||||
|
||||
case TypeRecord_Union: {
|
||||
i64 count = t->Record.variant_count;
|
||||
i64 align = type_align_of_internal(allocator, t, path);
|
||||
if (path->failure) {
|
||||
return FAILURE_SIZE;
|
||||
}
|
||||
i64 max = 0;
|
||||
// NOTE(bill): Zeroth field is invalid
|
||||
for (isize i = 1; i < count; i++) {
|
||||
i64 size = type_size_of_internal(allocator, t->Record.variants[i]->type, path);
|
||||
type_set_offsets(allocator, t);
|
||||
|
||||
i64 max = 0;
|
||||
isize field_count = t->Record.field_count;
|
||||
isize variant_count = t->Record.variant_count;
|
||||
if (field_count > 0) {
|
||||
Type *end_type = t->Record.fields[field_count-1]->type;
|
||||
i64 end_offset = t->Record.offsets[field_count-1];
|
||||
i64 end_size = type_size_of_internal(allocator, end_type, path);
|
||||
max = end_offset + end_size ;
|
||||
}
|
||||
|
||||
for (isize i = 1; i < variant_count; i++) {
|
||||
Type *variant_type = t->Record.variants[i]->type;
|
||||
i64 size = type_size_of_internal(allocator, variant_type, path);
|
||||
if (max < size) {
|
||||
max = size;
|
||||
}
|
||||
@@ -1923,7 +1963,8 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
|
||||
// NOTE(bill): Align to int
|
||||
i64 size = align_formula(max, build_context.word_size);
|
||||
size += type_size_of_internal(allocator, t_int, path);
|
||||
return align_formula(size, align);
|
||||
size = align_formula(size, align);
|
||||
return size;
|
||||
} break;
|
||||
|
||||
case TypeRecord_RawUnion: {
|
||||
@@ -2111,7 +2152,7 @@ gbString write_type_to_string(gbString str, Type *type) {
|
||||
}
|
||||
str = gb_string_append_length(str, f->token.string.text, f->token.string.len);
|
||||
str = gb_string_appendc(str, ": ");
|
||||
str = write_type_to_string(str, base_type(f->type));
|
||||
str = write_type_to_string(str, f->type);
|
||||
}
|
||||
for (isize i = 1; i < type->Record.variant_count; i++) {
|
||||
Entity *f = type->Record.variants[i];
|
||||
|
||||
Reference in New Issue
Block a user