mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
Bring back enum but using iota
This commit is contained in:
+22
-6
@@ -11,11 +11,27 @@ import {
|
|||||||
win32 "sys/windows.odin";
|
win32 "sys/windows.odin";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Thing enum f64 {
|
||||||
|
_, // Ignore first value
|
||||||
|
A = 1<<(10*iota),
|
||||||
|
B,
|
||||||
|
C,
|
||||||
|
D,
|
||||||
|
}
|
||||||
|
|
||||||
proc main() {
|
proc main() {
|
||||||
var x = if false {
|
var ti = type_info(Thing);
|
||||||
give 123;
|
match type info : type_info_base(ti) {
|
||||||
} else {
|
case Type_Info.Enum:
|
||||||
give 321;
|
for var i = 0; i < info.names.count; i++ {
|
||||||
};
|
if i > 0 {
|
||||||
fmt.println(x);
|
fmt.print(", ");
|
||||||
|
}
|
||||||
|
fmt.print(info.names[i]);
|
||||||
|
}
|
||||||
|
fmt.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.println(Thing.A, Thing.B, Thing.C, Thing.D);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-18
@@ -73,6 +73,10 @@ type {
|
|||||||
Struct Type_Info_Record;
|
Struct Type_Info_Record;
|
||||||
Union Type_Info_Record;
|
Union Type_Info_Record;
|
||||||
Raw_Union Type_Info_Record;
|
Raw_Union Type_Info_Record;
|
||||||
|
Enum struct #ordered {
|
||||||
|
base ^Type_Info;
|
||||||
|
names []string;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,12 +116,11 @@ proc fmuladd64(a, b, c f64) -> f64 #foreign "llvm.fmuladd.f64"
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
type Allocator_Mode u8;
|
type Allocator_Mode enum u8 {
|
||||||
const {
|
ALLOC = iota,
|
||||||
ALLOCATOR_ALLOC Allocator_Mode = iota;
|
FREE,
|
||||||
ALLOCATOR_FREE;
|
FREE_ALL,
|
||||||
ALLOCATOR_FREE_ALL;
|
RESIZE,
|
||||||
ALLOCATOR_RESIZE;
|
|
||||||
}
|
}
|
||||||
type {
|
type {
|
||||||
Allocator_Proc proc(allocator_data rawptr, mode Allocator_Mode,
|
Allocator_Proc proc(allocator_data rawptr, mode Allocator_Mode,
|
||||||
@@ -160,20 +163,20 @@ proc alloc(size int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNM
|
|||||||
proc alloc_align(size, alignment int) -> rawptr #inline {
|
proc alloc_align(size, alignment int) -> rawptr #inline {
|
||||||
__check_context();
|
__check_context();
|
||||||
var a = context.allocator;
|
var a = context.allocator;
|
||||||
return a.procedure(a.data, ALLOCATOR_ALLOC, size, alignment, nil, 0, 0);
|
return a.procedure(a.data, Allocator_Mode.ALLOC, size, alignment, nil, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
proc free(ptr rawptr) #inline {
|
proc free(ptr rawptr) #inline {
|
||||||
__check_context();
|
__check_context();
|
||||||
var a = context.allocator;
|
var a = context.allocator;
|
||||||
if ptr != nil {
|
if ptr != nil {
|
||||||
a.procedure(a.data, ALLOCATOR_FREE, 0, 0, ptr, 0, 0);
|
a.procedure(a.data, Allocator_Mode.FREE, 0, 0, ptr, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
proc free_all() #inline {
|
proc free_all() #inline {
|
||||||
__check_context();
|
__check_context();
|
||||||
var a = context.allocator;
|
var a = context.allocator;
|
||||||
a.procedure(a.data, ALLOCATOR_FREE_ALL, 0, 0, nil, 0, 0);
|
a.procedure(a.data, Allocator_Mode.FREE_ALL, 0, 0, nil, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -181,7 +184,7 @@ proc resize (ptr rawptr, old_size, new_size int) -> rawptr #inline { return
|
|||||||
proc resize_align(ptr rawptr, old_size, new_size, alignment int) -> rawptr #inline {
|
proc resize_align(ptr rawptr, old_size, new_size, alignment int) -> rawptr #inline {
|
||||||
__check_context();
|
__check_context();
|
||||||
var a = context.allocator;
|
var a = context.allocator;
|
||||||
return a.procedure(a.data, ALLOCATOR_RESIZE, new_size, alignment, ptr, old_size, 0);
|
return a.procedure(a.data, Allocator_Mode.RESIZE, new_size, alignment, ptr, old_size, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -214,9 +217,11 @@ proc default_resize_align(old_memory rawptr, old_size, new_size, alignment int)
|
|||||||
proc default_allocator_proc(allocator_data rawptr, mode Allocator_Mode,
|
proc default_allocator_proc(allocator_data rawptr, mode Allocator_Mode,
|
||||||
size, alignment int,
|
size, alignment int,
|
||||||
old_memory rawptr, old_size int, flags u64) -> rawptr {
|
old_memory rawptr, old_size int, flags u64) -> rawptr {
|
||||||
|
using Allocator_Mode;
|
||||||
|
|
||||||
when false {
|
when false {
|
||||||
match mode {
|
match mode {
|
||||||
case ALLOCATOR_ALLOC:
|
case ALLOC:
|
||||||
var total_size = size + alignment + size_of(mem.AllocationHeader);
|
var total_size = size + alignment + size_of(mem.AllocationHeader);
|
||||||
var ptr = os.heap_alloc(total_size);
|
var ptr = os.heap_alloc(total_size);
|
||||||
var header = ptr as ^mem.AllocationHeader;
|
var header = ptr as ^mem.AllocationHeader;
|
||||||
@@ -224,14 +229,14 @@ proc default_allocator_proc(allocator_data rawptr, mode Allocator_Mode,
|
|||||||
mem.allocation_header_fill(header, ptr, size);
|
mem.allocation_header_fill(header, ptr, size);
|
||||||
return mem.zero(ptr, size);
|
return mem.zero(ptr, size);
|
||||||
|
|
||||||
case ALLOCATOR_FREE:
|
case FREE:
|
||||||
os.heap_free(mem.allocation_header(old_memory));
|
os.heap_free(mem.allocation_header(old_memory));
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
case ALLOCATOR_FREE_ALL:
|
case FREE_ALL:
|
||||||
// NOTE(bill): Does nothing
|
// NOTE(bill): Does nothing
|
||||||
|
|
||||||
case ALLOCATOR_RESIZE:
|
case RESIZE:
|
||||||
var total_size = size + alignment + size_of(mem.AllocationHeader);
|
var total_size = size + alignment + size_of(mem.AllocationHeader);
|
||||||
var ptr = os.heap_resize(mem.allocation_header(old_memory), total_size);
|
var ptr = os.heap_resize(mem.allocation_header(old_memory), total_size);
|
||||||
var header = ptr as ^mem.AllocationHeader;
|
var header = ptr as ^mem.AllocationHeader;
|
||||||
@@ -241,17 +246,17 @@ proc default_allocator_proc(allocator_data rawptr, mode Allocator_Mode,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match mode {
|
match mode {
|
||||||
case ALLOCATOR_ALLOC:
|
case ALLOC:
|
||||||
return os.heap_alloc(size);
|
return os.heap_alloc(size);
|
||||||
|
|
||||||
case ALLOCATOR_FREE:
|
case FREE:
|
||||||
os.heap_free(old_memory);
|
os.heap_free(old_memory);
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
case ALLOCATOR_FREE_ALL:
|
case FREE_ALL:
|
||||||
// NOTE(bill): Does nothing
|
// NOTE(bill): Does nothing
|
||||||
|
|
||||||
case ALLOCATOR_RESIZE:
|
case RESIZE:
|
||||||
return os.heap_resize(old_memory, size);
|
return os.heap_resize(old_memory, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -292,6 +292,12 @@ proc bprint_type(buf ^[]byte, ti ^Type_Info) {
|
|||||||
bprint_type(buf, info.fields[i].type_info);
|
bprint_type(buf, info.fields[i].type_info);
|
||||||
}
|
}
|
||||||
bprint_string(buf, "}");
|
bprint_string(buf, "}");
|
||||||
|
|
||||||
|
case Enum:
|
||||||
|
bprint_string(buf, "enum ");
|
||||||
|
bprint_type(buf, info.base);
|
||||||
|
bprint_string(buf, " {}");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -463,6 +469,10 @@ proc bprint_any(buf ^[]byte, arg any) {
|
|||||||
bprint_string(buf, "(union)");
|
bprint_string(buf, "(union)");
|
||||||
case Raw_Union:
|
case Raw_Union:
|
||||||
bprint_string(buf, "(raw_union)");
|
bprint_string(buf, "(raw_union)");
|
||||||
|
|
||||||
|
case Enum:
|
||||||
|
bprint_any(buf, make_any(info.base, arg.data));
|
||||||
|
|
||||||
case Procedure:
|
case Procedure:
|
||||||
bprint_type(buf, arg.type_info);
|
bprint_type(buf, arg.type_info);
|
||||||
bprint_string(buf, " @ ");
|
bprint_string(buf, " @ ");
|
||||||
|
|||||||
+5
-4
@@ -163,10 +163,11 @@ proc arena_allocator(arena ^Arena) -> Allocator {
|
|||||||
proc arena_allocator_proc(allocator_data rawptr, mode Allocator_Mode,
|
proc arena_allocator_proc(allocator_data rawptr, mode Allocator_Mode,
|
||||||
size, alignment int,
|
size, alignment int,
|
||||||
old_memory rawptr, old_size int, flags u64) -> rawptr {
|
old_memory rawptr, old_size int, flags u64) -> rawptr {
|
||||||
|
using Allocator_Mode;
|
||||||
var arena = allocator_data as ^Arena;
|
var arena = allocator_data as ^Arena;
|
||||||
|
|
||||||
match mode {
|
match mode {
|
||||||
case ALLOCATOR_ALLOC:
|
case ALLOC:
|
||||||
var total_size = size + alignment;
|
var total_size = size + alignment;
|
||||||
|
|
||||||
if arena.memory.count + total_size > arena.memory.capacity {
|
if arena.memory.count + total_size > arena.memory.capacity {
|
||||||
@@ -180,14 +181,14 @@ proc arena_allocator_proc(allocator_data rawptr, mode Allocator_Mode,
|
|||||||
arena.memory.count += total_size;
|
arena.memory.count += total_size;
|
||||||
return zero(ptr, size);
|
return zero(ptr, size);
|
||||||
|
|
||||||
case ALLOCATOR_FREE:
|
case FREE:
|
||||||
// NOTE(bill): Free all at once
|
// NOTE(bill): Free all at once
|
||||||
// Use Arena_Temp_Memory if you want to free a block
|
// Use Arena_Temp_Memory if you want to free a block
|
||||||
|
|
||||||
case ALLOCATOR_FREE_ALL:
|
case FREE_ALL:
|
||||||
arena.memory.count = 0;
|
arena.memory.count = 0;
|
||||||
|
|
||||||
case ALLOCATOR_RESIZE:
|
case RESIZE:
|
||||||
return default_resize_align(old_memory, old_size, size, alignment);
|
return default_resize_align(old_memory, old_size, size, alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { // Windows reserves errors >= 1<<29 for application use
|
const { // Windows reserves errors >= 1<<29 for application use
|
||||||
ERROR_FILE_IS_PIPE Error = 1<<29 + iota;
|
ERROR_FILE_IS_PIPE Error = 1<<29 + 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1027,7 +1027,7 @@ void init_preload(Checker *c) {
|
|||||||
t_type_info_member = type_info_member_entity->type;
|
t_type_info_member = type_info_member_entity->type;
|
||||||
t_type_info_member_ptr = make_type_pointer(c->allocator, t_type_info_member);
|
t_type_info_member_ptr = make_type_pointer(c->allocator, t_type_info_member);
|
||||||
|
|
||||||
if (record->field_count != 17) {
|
if (record->field_count != 18) {
|
||||||
compiler_error("Invalid `Type_Info` layout");
|
compiler_error("Invalid `Type_Info` layout");
|
||||||
}
|
}
|
||||||
t_type_info_named = record->fields[ 1]->type;
|
t_type_info_named = record->fields[ 1]->type;
|
||||||
@@ -1046,6 +1046,7 @@ void init_preload(Checker *c) {
|
|||||||
t_type_info_struct = record->fields[14]->type;
|
t_type_info_struct = record->fields[14]->type;
|
||||||
t_type_info_union = record->fields[15]->type;
|
t_type_info_union = record->fields[15]->type;
|
||||||
t_type_info_raw_union = record->fields[16]->type;
|
t_type_info_raw_union = record->fields[16]->type;
|
||||||
|
t_type_info_enum = record->fields[17]->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t_allocator == NULL) {
|
if (t_allocator == NULL) {
|
||||||
|
|||||||
+128
-10
@@ -18,6 +18,7 @@ bool check_is_terminating (AstNode *node);
|
|||||||
bool check_has_break (AstNode *stmt, bool implicit);
|
bool check_has_break (AstNode *stmt, bool implicit);
|
||||||
void check_stmt (Checker *c, AstNode *node, u32 flags);
|
void check_stmt (Checker *c, AstNode *node, u32 flags);
|
||||||
void check_stmt_list (Checker *c, AstNodeArray stmts, u32 flags);
|
void check_stmt_list (Checker *c, AstNodeArray stmts, u32 flags);
|
||||||
|
void check_init_constant (Checker *c, Entity *e, Operand *operand);
|
||||||
|
|
||||||
|
|
||||||
gb_inline Type *check_type(Checker *c, AstNode *expression) {
|
gb_inline Type *check_type(Checker *c, AstNode *expression) {
|
||||||
@@ -724,6 +725,106 @@ void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
|
|||||||
// return i < j ? -1 : i > j;
|
// return i < j ? -1 : i > j;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *node) {
|
||||||
|
ast_node(et, EnumType, node);
|
||||||
|
GB_ASSERT(is_type_enum(enum_type));
|
||||||
|
|
||||||
|
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
||||||
|
|
||||||
|
Type *base_type = t_int;
|
||||||
|
if (et->base_type != NULL) {
|
||||||
|
base_type = check_type(c, et->base_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (base_type == NULL || !(is_type_integer(base_type) || is_type_float(base_type))) {
|
||||||
|
error_node(node, "Base type for enumeration must be numeric");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(bill): Must be up here for the `check_init_constant` system
|
||||||
|
enum_type->Record.enum_base_type = base_type;
|
||||||
|
|
||||||
|
MapEntity entity_map = {0}; // Key: String
|
||||||
|
map_entity_init_with_reserve(&entity_map, c->tmp_allocator, 2*(et->fields.count));
|
||||||
|
|
||||||
|
Entity **fields = gb_alloc_array(c->allocator, Entity *, et->fields.count);
|
||||||
|
isize field_index = 0;
|
||||||
|
|
||||||
|
Type *constant_type = enum_type;
|
||||||
|
if (named_type != NULL) {
|
||||||
|
constant_type = named_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
AstNode *prev_expr = NULL;
|
||||||
|
|
||||||
|
i64 iota = 0;
|
||||||
|
|
||||||
|
for_array(i, et->fields) {
|
||||||
|
AstNode *field = et->fields.e[i];
|
||||||
|
AstNode *ident = NULL;
|
||||||
|
if (field->kind == AstNode_FieldValue) {
|
||||||
|
ast_node(fv, FieldValue, field);
|
||||||
|
if (fv->field == NULL || fv->field->kind != AstNode_Ident) {
|
||||||
|
error_node(field, "An enum field's name must be an identifier");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ident = fv->field;
|
||||||
|
prev_expr = fv->value;
|
||||||
|
} else if (field->kind == AstNode_Ident) {
|
||||||
|
ident = field;
|
||||||
|
} else {
|
||||||
|
error_node(field, "An enum field's name must be an identifier");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String name = ident->Ident.string;
|
||||||
|
|
||||||
|
if (str_ne(name, str_lit("_"))) {
|
||||||
|
ExactValue v = make_exact_value_integer(iota);
|
||||||
|
Entity *e = make_entity_constant(c->allocator, c->context.scope, ident->Ident, constant_type, v);
|
||||||
|
e->identifier = ident;
|
||||||
|
e->flags |= EntityFlag_Visited;
|
||||||
|
|
||||||
|
|
||||||
|
AstNode *init = prev_expr;
|
||||||
|
if (init == NULL) {
|
||||||
|
error_node(field, "Missing initial expression for enumeration, e.g. iota");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
GB_ASSERT(c->context.iota.kind == ExactValue_Invalid);
|
||||||
|
c->context.iota = e->Constant.value;
|
||||||
|
e->Constant.value = (ExactValue){0};
|
||||||
|
|
||||||
|
Operand operand = {0};
|
||||||
|
check_expr(c, &operand, init);
|
||||||
|
|
||||||
|
check_init_constant(c, e, &operand);
|
||||||
|
c->context.iota = (ExactValue){0};
|
||||||
|
|
||||||
|
if (operand.mode == Addressing_Constant) {
|
||||||
|
HashKey key = hash_string(name);
|
||||||
|
if (map_entity_get(&entity_map, key) != NULL) {
|
||||||
|
error_node(ident, "`%.*s` is already declared in this enumeration", LIT(name));
|
||||||
|
} else {
|
||||||
|
map_entity_set(&entity_map, key, e);
|
||||||
|
add_entity(c, c->context.scope, NULL, e);
|
||||||
|
fields[field_index++] = e;
|
||||||
|
add_entity_use(c, field, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iota++;
|
||||||
|
}
|
||||||
|
|
||||||
|
GB_ASSERT(field_index <= et->fields.count);
|
||||||
|
|
||||||
|
enum_type->Record.fields = fields;
|
||||||
|
enum_type->Record.field_count = field_index;
|
||||||
|
|
||||||
|
gb_temp_arena_memory_end(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_variadic_) {
|
Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_variadic_) {
|
||||||
if (params.count == 0) {
|
if (params.count == 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1105,6 +1206,16 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) {
|
|||||||
goto end;
|
goto end;
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(et, EnumType, e);
|
||||||
|
type = make_type_enum(c->allocator);
|
||||||
|
set_base_type(named_type, type);
|
||||||
|
check_open_scope(c, e);
|
||||||
|
check_enum_type(c, type, named_type, e);
|
||||||
|
check_close_scope(c);
|
||||||
|
type->Record.node = e;
|
||||||
|
goto end;
|
||||||
|
case_end;
|
||||||
|
|
||||||
case_ast_node(pt, ProcType, e);
|
case_ast_node(pt, ProcType, e);
|
||||||
type = alloc_type(c->allocator, Type_Proc);
|
type = alloc_type(c->allocator, Type_Proc);
|
||||||
set_base_type(named_type, type);
|
set_base_type(named_type, type);
|
||||||
@@ -1114,6 +1225,7 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) {
|
|||||||
goto end;
|
goto end;
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
|
||||||
case_ast_node(ce, CallExpr, e);
|
case_ast_node(ce, CallExpr, e);
|
||||||
Operand o = {0};
|
Operand o = {0};
|
||||||
check_expr_or_type(c, &o, e);
|
check_expr_or_type(c, &o, e);
|
||||||
@@ -1161,7 +1273,7 @@ end:
|
|||||||
|
|
||||||
bool check_unary_op(Checker *c, Operand *o, Token op) {
|
bool check_unary_op(Checker *c, Operand *o, Token op) {
|
||||||
// TODO(bill): Handle errors correctly
|
// TODO(bill): Handle errors correctly
|
||||||
Type *type = base_type(base_vector_type(o->type));
|
Type *type = base_type(base_enum_type(base_vector_type(o->type)));
|
||||||
gbString str = NULL;
|
gbString str = NULL;
|
||||||
switch (op.kind) {
|
switch (op.kind) {
|
||||||
case Token_Add:
|
case Token_Add:
|
||||||
@@ -1197,7 +1309,7 @@ bool check_unary_op(Checker *c, Operand *o, Token op) {
|
|||||||
|
|
||||||
bool check_binary_op(Checker *c, Operand *o, Token op) {
|
bool check_binary_op(Checker *c, Operand *o, Token op) {
|
||||||
// TODO(bill): Handle errors correctly
|
// TODO(bill): Handle errors correctly
|
||||||
Type *type = base_type(base_vector_type(o->type));
|
Type *type = base_type(base_enum_type(base_vector_type(o->type)));
|
||||||
switch (op.kind) {
|
switch (op.kind) {
|
||||||
case Token_Sub:
|
case Token_Sub:
|
||||||
case Token_SubEq:
|
case Token_SubEq:
|
||||||
@@ -1274,6 +1386,8 @@ bool check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, Exa
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type = base_type(base_enum_type(type));
|
||||||
|
|
||||||
if (is_type_boolean(type)) {
|
if (is_type_boolean(type)) {
|
||||||
return in_value.kind == ExactValue_Bool;
|
return in_value.kind == ExactValue_Bool;
|
||||||
} else if (is_type_string(type)) {
|
} else if (is_type_string(type)) {
|
||||||
@@ -2036,10 +2150,10 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (op.kind == Token_Add || op.kind == Token_Sub) {
|
if (op.kind == Token_Add || op.kind == Token_Sub) {
|
||||||
if (is_type_pointer(x->type) && is_type_integer(y->type)) {
|
if (is_type_pointer(x->type) && is_type_integer(base_enum_type(y->type))) {
|
||||||
*x = check_ptr_addition(c, op.kind, x, y, node);
|
*x = check_ptr_addition(c, op.kind, x, y, node);
|
||||||
return;
|
return;
|
||||||
} else if (is_type_integer(x->type) && is_type_pointer(y->type)) {
|
} else if (is_type_integer(base_enum_type(x->type)) && is_type_pointer(y->type)) {
|
||||||
if (op.kind == Token_Sub) {
|
if (op.kind == Token_Sub) {
|
||||||
gbString lhs = expr_to_string(x->expr);
|
gbString lhs = expr_to_string(x->expr);
|
||||||
gbString rhs = expr_to_string(y->expr);
|
gbString rhs = expr_to_string(y->expr);
|
||||||
@@ -2247,20 +2361,22 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_type_untyped(target_type)) {
|
if (is_type_untyped(target_type)) {
|
||||||
Type *x = operand->type;
|
GB_ASSERT(operand->type->kind == Type_Basic);
|
||||||
Type *y = target_type;
|
GB_ASSERT(target_type->kind == Type_Basic);
|
||||||
if (is_type_numeric(x) && is_type_numeric(y)) {
|
BasicKind x_kind = operand->type->Basic.kind;
|
||||||
if (x < y) {
|
BasicKind y_kind = target_type->Basic.kind;
|
||||||
|
if (is_type_numeric(operand->type) && is_type_numeric(target_type)) {
|
||||||
|
if (x_kind < y_kind) {
|
||||||
operand->type = target_type;
|
operand->type = target_type;
|
||||||
update_expr_type(c, operand->expr, target_type, false);
|
update_expr_type(c, operand->expr, target_type, false);
|
||||||
}
|
}
|
||||||
} else if (x != y) {
|
} else if (x_kind != y_kind) {
|
||||||
convert_untyped_error(c, operand, target_type);
|
convert_untyped_error(c, operand, target_type);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type *t = base_type(target_type);
|
Type *t = base_type(base_enum_type(target_type));
|
||||||
switch (t->kind) {
|
switch (t->kind) {
|
||||||
case Type_Basic:
|
case Type_Basic:
|
||||||
if (operand->mode == Addressing_Constant) {
|
if (operand->mode == Addressing_Constant) {
|
||||||
@@ -4366,7 +4482,9 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
|||||||
case AstNode_ArrayType:
|
case AstNode_ArrayType:
|
||||||
case AstNode_VectorType:
|
case AstNode_VectorType:
|
||||||
case AstNode_StructType:
|
case AstNode_StructType:
|
||||||
|
case AstNode_UnionType:
|
||||||
case AstNode_RawUnionType:
|
case AstNode_RawUnionType:
|
||||||
|
case AstNode_EnumType:
|
||||||
o->mode = Addressing_Type;
|
o->mode = Addressing_Type;
|
||||||
o->type = check_type(c, node);
|
o->type = check_type(c, node);
|
||||||
break;
|
break;
|
||||||
|
|||||||
+14
-1
@@ -934,8 +934,21 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
}
|
}
|
||||||
f->using_parent = e;
|
f->using_parent = e;
|
||||||
}
|
}
|
||||||
|
} else if (is_type_enum(t)) {
|
||||||
|
for (isize i = 0; i < t->Record.field_count; i++) {
|
||||||
|
Entity *f = t->Record.fields[i];
|
||||||
|
Entity *found = scope_insert_entity(c->context.scope, f);
|
||||||
|
if (found != NULL) {
|
||||||
|
gbString expr_str = expr_to_string(expr);
|
||||||
|
error(us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));
|
||||||
|
gb_string_free(expr_str);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
f->using_parent = e;
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
error(us->token, "`using` can be only applied to `union` type entities");
|
error(us->token, "`using` can be only applied to `union` or `enum` type entities");
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
|||||||
+47
-2
@@ -64,6 +64,7 @@ typedef enum TypeRecordKind {
|
|||||||
TypeRecord_Struct,
|
TypeRecord_Struct,
|
||||||
TypeRecord_RawUnion,
|
TypeRecord_RawUnion,
|
||||||
TypeRecord_Union, // Tagged
|
TypeRecord_Union, // Tagged
|
||||||
|
TypeRecord_Enum,
|
||||||
|
|
||||||
TypeRecord_Count,
|
TypeRecord_Count,
|
||||||
} TypeRecordKind;
|
} TypeRecordKind;
|
||||||
@@ -82,6 +83,8 @@ typedef struct TypeRecord {
|
|||||||
bool struct_is_packed;
|
bool struct_is_packed;
|
||||||
bool struct_is_ordered;
|
bool struct_is_ordered;
|
||||||
Entity **fields_in_src_order; // Entity_Variable
|
Entity **fields_in_src_order; // Entity_Variable
|
||||||
|
|
||||||
|
Type * enum_base_type;
|
||||||
} TypeRecord;
|
} TypeRecord;
|
||||||
|
|
||||||
#define TYPE_KINDS \
|
#define TYPE_KINDS \
|
||||||
@@ -270,6 +273,7 @@ gb_global Type *t_type_info_tuple = NULL;
|
|||||||
gb_global Type *t_type_info_struct = NULL;
|
gb_global Type *t_type_info_struct = NULL;
|
||||||
gb_global Type *t_type_info_union = NULL;
|
gb_global Type *t_type_info_union = NULL;
|
||||||
gb_global Type *t_type_info_raw_union = NULL;
|
gb_global Type *t_type_info_raw_union = NULL;
|
||||||
|
gb_global Type *t_type_info_enum = NULL;
|
||||||
|
|
||||||
gb_global Type *t_allocator = NULL;
|
gb_global Type *t_allocator = NULL;
|
||||||
gb_global Type *t_allocator_ptr = NULL;
|
gb_global Type *t_allocator_ptr = NULL;
|
||||||
@@ -285,7 +289,10 @@ gbString type_to_string(Type *type);
|
|||||||
|
|
||||||
Type *base_type(Type *t) {
|
Type *base_type(Type *t) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (t == NULL || t->kind != Type_Named) {
|
if (t == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (t->kind != Type_Named) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (t == t->Named.base) {
|
if (t == t->Named.base) {
|
||||||
@@ -296,6 +303,16 @@ Type *base_type(Type *t) {
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type *base_enum_type(Type *t) {
|
||||||
|
Type *bt = base_type(t);
|
||||||
|
if (bt != NULL &&
|
||||||
|
bt->kind == Type_Record &&
|
||||||
|
bt->Record.kind == TypeRecord_Enum) {
|
||||||
|
return bt->Record.enum_base_type;
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
void set_base_type(Type *t, Type *base) {
|
void set_base_type(Type *t, Type *base) {
|
||||||
if (t && t->kind == Type_Named) {
|
if (t && t->kind == Type_Named) {
|
||||||
t->Named.base = base;
|
t->Named.base = base;
|
||||||
@@ -367,6 +384,13 @@ Type *make_type_raw_union(gbAllocator a) {
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type *make_type_enum(gbAllocator a) {
|
||||||
|
Type *t = alloc_type(a, Type_Record);
|
||||||
|
t->Record.kind = TypeRecord_Enum;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -492,7 +516,7 @@ bool is_type_ordered(Type *t) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool is_type_constant_type(Type *t) {
|
bool is_type_constant_type(Type *t) {
|
||||||
t = base_type(t);
|
t = base_type(base_enum_type(t));
|
||||||
if (t->kind == Type_Basic) {
|
if (t->kind == Type_Basic) {
|
||||||
return (t->Basic.flags & BasicFlag_ConstantType) != 0;
|
return (t->Basic.flags & BasicFlag_ConstantType) != 0;
|
||||||
}
|
}
|
||||||
@@ -598,6 +622,11 @@ bool is_type_raw_union(Type *t) {
|
|||||||
t = base_type(t);
|
t = base_type(t);
|
||||||
return (t->kind == Type_Record && t->Record.kind == TypeRecord_RawUnion);
|
return (t->kind == Type_Record && t->Record.kind == TypeRecord_RawUnion);
|
||||||
}
|
}
|
||||||
|
bool is_type_enum(Type *t) {
|
||||||
|
t = base_type(t);
|
||||||
|
return (t->kind == Type_Record && t->Record.kind == TypeRecord_Enum);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool is_type_any(Type *t) {
|
bool is_type_any(Type *t) {
|
||||||
t = base_type(t);
|
t = base_type(t);
|
||||||
@@ -642,6 +671,8 @@ bool is_type_comparable(Type *t) {
|
|||||||
if (!is_type_comparable(t->Record.fields[i]->type))
|
if (!is_type_comparable(t->Record.fields[i]->type))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
} else if (is_type_enum(t)) {
|
||||||
|
return is_type_comparable(base_enum_type(t));
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} break;
|
} break;
|
||||||
@@ -712,6 +743,8 @@ bool are_types_identical(Type *x, Type *y) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case TypeRecord_Enum:
|
||||||
|
return x == y; // NOTE(bill): All enums are unique
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -992,6 +1025,18 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
|
|||||||
GB_ASSERT(f->kind == Entity_TypeName);
|
GB_ASSERT(f->kind == Entity_TypeName);
|
||||||
String str = f->token.string;
|
String str = f->token.string;
|
||||||
|
|
||||||
|
if (str_eq(field_name, str)) {
|
||||||
|
sel.entity = f;
|
||||||
|
selection_add_index(&sel, i);
|
||||||
|
return sel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (is_type_enum(type)) {
|
||||||
|
for (isize i = 0; i < type->Record.field_count; i++) {
|
||||||
|
Entity *f = type->Record.fields[i];
|
||||||
|
GB_ASSERT(f->kind == Entity_Constant);
|
||||||
|
String str = f->token.string;
|
||||||
|
|
||||||
if (str_eq(field_name, str)) {
|
if (str_eq(field_name, str)) {
|
||||||
sel.entity = f;
|
sel.entity = f;
|
||||||
selection_add_index(&sel, i);
|
selection_add_index(&sel, i);
|
||||||
|
|||||||
+13
-1
@@ -347,7 +347,7 @@ AST_NODE_KIND(_TypeBegin, "", i32) \
|
|||||||
AST_NODE_KIND(EnumType, "enum type", struct { \
|
AST_NODE_KIND(EnumType, "enum type", struct { \
|
||||||
Token token; \
|
Token token; \
|
||||||
AstNode *base_type; \
|
AstNode *base_type; \
|
||||||
AstNodeArray fields; \
|
AstNodeArray fields; /* FieldValue */ \
|
||||||
}) \
|
}) \
|
||||||
AST_NODE_KIND(_TypeEnd, "", i32)
|
AST_NODE_KIND(_TypeEnd, "", i32)
|
||||||
|
|
||||||
@@ -2548,6 +2548,18 @@ AstNode *parse_identifier_or_type(AstFile *f) {
|
|||||||
return make_raw_union_type(f, token, decls, decl_count);
|
return make_raw_union_type(f, token, decls, decl_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Token_enum: {
|
||||||
|
Token token = expect_token(f, Token_enum);
|
||||||
|
AstNode *base_type = NULL;
|
||||||
|
if (f->curr_token.kind != Token_OpenBrace) {
|
||||||
|
base_type = parse_type(f);
|
||||||
|
}
|
||||||
|
Token open = expect_token(f, Token_OpenBrace);
|
||||||
|
AstNodeArray fields = parse_element_list(f);
|
||||||
|
Token close = expect_token(f, Token_CloseBrace);
|
||||||
|
return make_enum_type(f, token, base_type, fields);
|
||||||
|
}
|
||||||
|
|
||||||
case Token_proc: {
|
case Token_proc: {
|
||||||
Token token = f->curr_token;
|
Token token = f->curr_token;
|
||||||
AstNode *pt = parse_proc_type(f, NULL, NULL);
|
AstNode *pt = parse_proc_type(f, NULL, NULL);
|
||||||
|
|||||||
@@ -5484,6 +5484,49 @@ void ssa_gen_tree(ssaGen *s) {
|
|||||||
ssa_emit_store(proc, len, field_count);
|
ssa_emit_store(proc, len, field_count);
|
||||||
ssa_emit_store(proc, cap, field_count);
|
ssa_emit_store(proc, cap, field_count);
|
||||||
} break;
|
} break;
|
||||||
|
case TypeRecord_Enum:
|
||||||
|
tag = ssa_add_local_generated(proc, t_type_info_enum);
|
||||||
|
{
|
||||||
|
GB_ASSERT(t->Record.enum_base_type != NULL);
|
||||||
|
ssaValue *base = ssa_type_info(proc, t->Record.enum_base_type);
|
||||||
|
ssa_emit_store(proc, ssa_emit_struct_ep(proc, tag, 0), base);
|
||||||
|
|
||||||
|
if (t->Record.field_count > 0) {
|
||||||
|
Entity **fields = t->Record.fields;
|
||||||
|
isize count = t->Record.field_count;
|
||||||
|
ssaValue *name_array = NULL;
|
||||||
|
|
||||||
|
{
|
||||||
|
Token token = {Token_Ident};
|
||||||
|
i32 id = cast(i32)entry_index;
|
||||||
|
char name_base[] = "__$enum_names";
|
||||||
|
isize name_len = gb_size_of(name_base) + 10;
|
||||||
|
token.string.text = gb_alloc_array(a, u8, name_len);
|
||||||
|
token.string.len = gb_snprintf(cast(char *)token.string.text, name_len,
|
||||||
|
"%s-%d", name_base, id)-1;
|
||||||
|
Entity *e = make_entity_variable(a, NULL, token, make_type_array(a, t_string, count), false);
|
||||||
|
name_array = ssa_make_value_global(a, e, NULL);
|
||||||
|
name_array->Global.is_private = true;
|
||||||
|
ssa_module_add_value(m, e, name_array);
|
||||||
|
map_ssa_value_set(&m->members, hash_string(token.string), name_array);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (isize i = 0; i < count; i++) {
|
||||||
|
ssaValue *name_ep = ssa_emit_array_epi(proc, name_array, i);
|
||||||
|
ssa_emit_store(proc, name_ep, ssa_make_const_string(a, fields[i]->token.string));
|
||||||
|
}
|
||||||
|
|
||||||
|
ssaValue *v_count = ssa_make_const_int(a, count);
|
||||||
|
|
||||||
|
ssaValue *names = ssa_emit_struct_ep(proc, tag, 1);
|
||||||
|
ssaValue *name_array_elem = ssa_array_elem(proc, name_array);
|
||||||
|
|
||||||
|
ssa_emit_store(proc, ssa_emit_struct_ep(proc, names, 0), name_array_elem);
|
||||||
|
ssa_emit_store(proc, ssa_emit_struct_ep(proc, names, 1), v_count);
|
||||||
|
ssa_emit_store(proc, ssa_emit_struct_ep(proc, names, 2), v_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -225,6 +225,9 @@ void ssa_print_type(ssaFileBuffer *f, ssaModule *m, Type *t) {
|
|||||||
i64 align_of_union = type_align_of(s, heap_allocator(), t);
|
i64 align_of_union = type_align_of(s, heap_allocator(), t);
|
||||||
ssa_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8]}", align_of_union, size_of_union);
|
ssa_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8]}", align_of_union, size_of_union);
|
||||||
} break;
|
} break;
|
||||||
|
case TypeRecord_Enum:
|
||||||
|
ssa_print_type(f, m, base_enum_type(t));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@@ -299,7 +302,7 @@ void ssa_print_compound_element(ssaFileBuffer *f, ssaModule *m, ExactValue v, Ty
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ssa_print_exact_value(ssaFileBuffer *f, ssaModule *m, ExactValue value, Type *type) {
|
void ssa_print_exact_value(ssaFileBuffer *f, ssaModule *m, ExactValue value, Type *type) {
|
||||||
type = base_type(type);
|
type = base_type(base_enum_type(type));
|
||||||
if (is_type_float(type)) {
|
if (is_type_float(type)) {
|
||||||
value = exact_value_to_float(value);
|
value = exact_value_to_float(value);
|
||||||
} else if (is_type_integer(type)) {
|
} else if (is_type_integer(type)) {
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
|||||||
TOKEN_KIND(Token_struct, "struct"), \
|
TOKEN_KIND(Token_struct, "struct"), \
|
||||||
TOKEN_KIND(Token_union, "union"), \
|
TOKEN_KIND(Token_union, "union"), \
|
||||||
TOKEN_KIND(Token_raw_union, "raw_union"), \
|
TOKEN_KIND(Token_raw_union, "raw_union"), \
|
||||||
|
TOKEN_KIND(Token_enum, "enum"), \
|
||||||
TOKEN_KIND(Token_vector, "vector"), \
|
TOKEN_KIND(Token_vector, "vector"), \
|
||||||
TOKEN_KIND(Token_using, "using"), \
|
TOKEN_KIND(Token_using, "using"), \
|
||||||
TOKEN_KIND(Token_asm, "asm"), \
|
TOKEN_KIND(Token_asm, "asm"), \
|
||||||
|
|||||||
Reference in New Issue
Block a user