From ff473e83425c74bae2cee4c9d68435c7b346533e Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Sun, 8 Jan 2017 20:24:12 +0000 Subject: [PATCH] "Old style" enums name and value information `count`, `min_value`, `max_value` constants --- code/demo.odin | 44 ++++++---- core/_preload.odin | 8 +- core/fmt.odin | 70 +++++++-------- src/check_decl.c | 8 -- src/check_expr.c | 209 +++++++++++++++++++++++++++++++++------------ src/checker.c | 16 +++- src/entity.c | 3 - src/ir.c | 90 ++++++++++++++++++- src/types.c | 37 ++++++-- 9 files changed, 350 insertions(+), 135 deletions(-) diff --git a/code/demo.odin b/code/demo.odin index 1fe4c564d..285abe14d 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,21 +1,31 @@ #import "fmt.odin"; main :: proc() { - fmt.printf("%f", 123); + using Type_Info; + is_type_integer :: proc(info: ^Type_Info) -> bool { + if info == nil { + return false; + } + + match type i : type_info_base(info) { + case Integer: + return true; + } + return false; + } + + ti := type_info_base(type_info(Allocator_Mode)); + match type e : ti { + case Enum: + is_int := is_type_integer(e.base); + for i : 0.. f64 #foreign "llvm.fmuladd.f64" Allocator_Mode :: enum u8 { - ALLOC = iota, + ALLOC, FREE, FREE_ALL, RESIZE, diff --git a/core/fmt.odin b/core/fmt.odin index 37295f4f7..b5452e531 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -190,36 +190,30 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) { if info.ordered { buffer_write_string(buf, "#ordered "); } buffer_write_string(buf, "{"); for field, i : info.fields { - if i > 0 { - buffer_write_string(buf, ", "); - } buffer_write_string(buf, field.name); buffer_write_string(buf, ": "); buffer_write_type(buf, field.type_info); + buffer_write_byte(buf, ';'); } buffer_write_string(buf, "}"); case Union: buffer_write_string(buf, "union {"); for field, i : info.fields { - if i > 0 { - buffer_write_string(buf, ", "); - } buffer_write_string(buf, field.name); buffer_write_string(buf, ": "); buffer_write_type(buf, field.type_info); + buffer_write_byte(buf, ';'); } buffer_write_string(buf, "}"); case Raw_Union: buffer_write_string(buf, "raw_union {"); for field, i : info.fields { - if i > 0 { - buffer_write_string(buf, ", "); - } buffer_write_string(buf, field.name); buffer_write_string(buf, ": "); buffer_write_type(buf, field.type_info); + buffer_write_byte(buf, ';'); } buffer_write_string(buf, "}"); @@ -232,14 +226,6 @@ buffer_write_type :: proc(buf: ^Buffer, ti: ^Type_Info) { } -make_any :: proc(type_info: ^Type_Info, data: rawptr) -> any { - a: any; - a.type_info = type_info; - a.data = data; - return a; -} - - bprint :: proc(buf: ^Buffer, args: ...any) -> int { is_type_string :: proc(info: ^Type_Info) -> bool { using Type_Info; @@ -411,7 +397,8 @@ fmt_write_padding :: proc(fi: ^Fmt_Info, width: int) { } fmt_integer :: proc(fi: ^Fmt_Info, u: u64, base: int, signed: bool, digits: string) { - negative := signed && (u as i64) < 0; + u_i64 := u as i64; + negative := signed && u_i64 < 0; if negative { u = -u; } @@ -591,12 +578,14 @@ fmt_string :: proc(fi: ^Fmt_Info, s: string, verb: rune) { } fmt_pointer :: proc(fi: ^Fmt_Info, p: rawptr, verb: rune) { - if verb != 'p' { + match verb { + case 'p', 'v': + default: fmt_bad_verb(fi, verb); return; } u := p as uint as u64; - if !fi.hash { + if !fi.hash || verb == 'v' { buffer_write_string(fi.buf, "0x"); } fmt_integer(fi, u, 16, false, __DIGITS_UPPER); @@ -612,14 +601,12 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { using Type_Info; match type info : v.type_info { case Named: - if verb != 'v' { - fmt_bad_verb(fi, verb); - return; - } - - a := make_any(info.base, v.data); match type b : info.base { case Struct: + if verb != 'v' { + fmt_bad_verb(fi, verb); + return; + } buffer_write_string(fi.buf, info.name); buffer_write_byte(fi.buf, '{'); for f, i : b.fields { @@ -630,12 +617,12 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { // bprint_any(fi.buf, f.offset); buffer_write_string(fi.buf, " = "); data := v.data as ^byte + f.offset; - fmt_arg(fi, make_any(f.type_info, data), 'v'); + fmt_arg(fi, any{f.type_info, data as rawptr}, 'v'); } buffer_write_byte(fi.buf, '}'); default: - fmt_value(fi, a, verb); + fmt_value(fi, any{info.base, v.data}, verb); } case Boolean: fmt_arg(fi, v, verb); @@ -644,14 +631,18 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { case String: fmt_arg(fi, v, verb); case Pointer: - fmt_pointer(fi, (v.data as ^rawptr)^, verb); + if v.type_info == type_info(^Type_Info) { + buffer_write_type(fi.buf, (v.data as ^^Type_Info)^); + } else { + fmt_pointer(fi, (v.data as ^rawptr)^, verb); + } case Maybe: // TODO(bill): Correct verbs for Maybe types? size := mem.size_of_type_info(info.elem); data := slice_ptr(v.data as ^byte, size+1); if data[size] != 0 { - fmt_arg(fi, make_any(info.elem, v.data), verb); + fmt_arg(fi, any{info.elem, v.data}, verb); } else { buffer_write_string(fi.buf, "nil"); } @@ -669,7 +660,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { buffer_write_string(fi.buf, ", "); } data := v.data as ^byte + i*info.elem_size; - fmt_arg(fi, make_any(info.elem, data), 'v'); + fmt_arg(fi, any{info.elem, data as rawptr}, 'v'); } case Slice: @@ -686,7 +677,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { buffer_write_string(fi.buf, ", "); } data := slice.data + i*info.elem_size; - fmt_arg(fi, make_any(info.elem, data), 'v'); + fmt_arg(fi, any{info.elem, data as rawptr}, 'v'); } case Vector: @@ -713,7 +704,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { } data := v.data as ^byte + i*info.elem_size; - fmt_value(fi, make_any(info.elem, data), 'v'); + fmt_value(fi, any{info.elem, data as rawptr}, 'v'); } case Struct: @@ -728,7 +719,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { buffer_write_string(fi.buf, " = "); data := v.data as ^byte + f.offset; ti := f.type_info; - fmt_value(fi, make_any(ti, data), 'v'); + fmt_value(fi, any{ti, data as rawptr}, 'v'); } case Union: @@ -737,7 +728,7 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { buffer_write_string(fi.buf, "(raw_union)"); case Enum: - fmt_value(fi, make_any(info.base, v.data), verb); + fmt_arg(fi, any{info.base, v.data}, verb); case Procedure: buffer_write_type(fi.buf, v.type_info); @@ -753,11 +744,16 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) { } fi.arg = arg; - if verb == 'T' { // Type Info - buffer_write_type(fi.buf, arg.type_info); + if verb == 'T' { + ti := arg.type_info; + if ti == type_info(^Type_Info) { + ti = (arg.data as ^^Type_Info)^; + } + buffer_write_type(fi.buf, ti); return; } + base_arg := arg; base_arg.type_info = type_info_base(base_arg.type_info); match type a : base_arg { diff --git a/src/check_decl.c b/src/check_decl.c index 9f683cf29..1c5cc1b06 100644 --- a/src/check_decl.c +++ b/src/check_decl.c @@ -249,9 +249,6 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init, } e->flags |= EntityFlag_Visited; - c->context.iota = e->Constant.value; - e->Constant.value = (ExactValue){0}; - if (type_expr) { Type *t = check_type(c, type_expr); if (!is_type_constant_type(t)) { @@ -259,7 +256,6 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init, error_node(type_expr, "Invalid constant type `%s`", str); gb_string_free(str); e->type = t_invalid; - c->context.iota = (ExactValue){0}; return; } e->type = t; @@ -270,9 +266,6 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init, check_expr_or_type(c, &operand, init); } if (operand.mode == Addressing_Type) { - c->context.iota = (ExactValue){0}; - - e->Constant.value = (ExactValue){0}; e->kind = Entity_TypeName; DeclInfo *d = c->context.decl; @@ -282,7 +275,6 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init, } check_init_constant(c, e, &operand); - c->context.iota = (ExactValue){0}; if (operand.mode == Addressing_Invalid) { error(e->token, "Illegal cyclic declaration"); diff --git a/src/check_expr.c b/src/check_expr.c index 2c772d149..c52d463f2 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -263,11 +263,13 @@ bool check_is_assignable_to(Checker *c, Operand *operand, Type *type) { } // ^T <- rawptr +#if 0 // TODO(bill): Should C-style (not C++) pointer cast be allowed? - // if (is_type_pointer(dst) && is_type_rawptr(src)) { - // return true; - // } - + if (is_type_pointer(dst) && is_type_rawptr(src)) { + return true; + } +#endif +#if 1 // rawptr <- ^T if (is_type_rawptr(dst) && is_type_pointer(src)) { // TODO(bill): Handle this properly @@ -276,8 +278,7 @@ bool check_is_assignable_to(Checker *c, Operand *operand, Type *type) { } return true; } - - +#endif if (dst->kind == Type_Array && src->kind == Type_Array) { if (are_types_identical(dst->Array.elem, src->Array.elem)) { @@ -702,20 +703,21 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod 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; + isize field_count = 0; Type *constant_type = enum_type; if (named_type != NULL) { constant_type = named_type; } - AstNode *prev_expr = NULL; - - i64 iota = 0; + ExactValue iota = make_exact_value_integer(-1); + ExactValue min_value = make_exact_value_integer(0); + ExactValue max_value = make_exact_value_integer(0); for_array(i, et->fields) { AstNode *field = et->fields.e[i]; AstNode *ident = NULL; + AstNode *init = NULL; if (field->kind == AstNode_FieldValue) { ast_node(fv, FieldValue, field); if (fv->field == NULL || fv->field->kind != AstNode_Ident) { @@ -723,7 +725,7 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod continue; } ident = fv->field; - prev_expr = fv->value; + init = fv->value; } else if (field->kind == AstNode_Ident) { ident = field; } else { @@ -732,48 +734,73 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod } 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; + if (init != NULL) { + Operand o = {0}; + check_expr(c, &o, init); + if (o.mode != Addressing_Constant) { + error_node(init, "Enumeration value must be a constant"); + o.mode = Addressing_Invalid; } - - ExactValue context_iota = c->context.iota; - 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 = context_iota; - - 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); - } + if (o.mode != Addressing_Invalid) { + check_assignment(c, &o, constant_type, str_lit("enumeration")); } + if (o.mode != Addressing_Invalid) { + iota = o.value; + } else { + iota = exact_binary_operator_value(Token_Add, iota, make_exact_value_integer(1)); + } + } else { + iota = exact_binary_operator_value(Token_Add, iota, make_exact_value_integer(1)); + } + + + // NOTE(bill): Skip blank identifiers + if (str_eq(name, str_lit("_"))) { + continue; + } else if (str_eq(name, str_lit("count"))) { + error_node(field, "`count` is a reserved identifier for enumerations"); + continue; + } else if (str_eq(name, str_lit("min_value"))) { + error_node(field, "`min_value` is a reserved identifier for enumerations"); + continue; + } else if (str_eq(name, str_lit("max_value"))) { + error_node(field, "`max_value` is a reserved identifier for enumerations"); + continue; + } + + if (compare_exact_values(Token_Gt, min_value, iota)) { + min_value = iota; + } + if (compare_exact_values(Token_Lt, max_value, iota)) { + max_value = iota; + } + + Entity *e = make_entity_constant(c->allocator, c->context.scope, ident->Ident, constant_type, iota); + e->identifier = ident; + e->flags |= EntityFlag_Visited; + + 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_count++] = e; + add_entity_use(c, field, e); } - iota++; } - GB_ASSERT(field_index <= et->fields.count); + GB_ASSERT(field_count <= et->fields.count); enum_type->Record.fields = fields; - enum_type->Record.field_count = field_index; + enum_type->Record.field_count = field_count; + + enum_type->Record.enum_count = make_entity_constant(c->allocator, c->context.scope, + make_token_ident(str_lit("count")), t_int, make_exact_value_integer(field_count)); + enum_type->Record.enum_min_value = make_entity_constant(c->allocator, c->context.scope, + make_token_ident(str_lit("min_value")), constant_type, min_value); + enum_type->Record.enum_max_value = make_entity_constant(c->allocator, c->context.scope, + make_token_ident(str_lit("max_value")), constant_type, max_value); gb_temp_arena_memory_end(tmp); } @@ -926,15 +953,7 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type) { o->type = t_invalid; return; } - if (e == e_iota) { - if (c->context.iota.kind == ExactValue_Invalid) { - error(e->token, "Use of `iota` outside a enumeration is not allowed"); - return; - } - o->value = c->context.iota; - } else { - o->value = e->Constant.value; - } + o->value = e->Constant.value; if (o->value.kind == ExactValue_Invalid) { return; } @@ -4091,7 +4110,6 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint } } } - } break; case Type_Slice: @@ -4162,6 +4180,85 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint } } break; + case Type_Basic: { + if (!is_type_any(t)) { + if (cl->elems.count != 0) { + error_node(node, "Illegal compound literal"); + } + break; + } + if (cl->elems.count == 0) { + break; // NOTE(bill): No need to init + } + { // Checker values + Type *field_types[2] = {t_type_info_ptr, t_rawptr}; + isize field_count = 2; + if (cl->elems.e[0]->kind == AstNode_FieldValue) { + bool fields_visited[2] = {0}; + + for_array(i, cl->elems) { + AstNode *elem = cl->elems.e[i]; + if (elem->kind != AstNode_FieldValue) { + error_node(elem, "Mixture of `field = value` and value elements in a `any` literal is not allowed"); + continue; + } + ast_node(fv, FieldValue, elem); + if (fv->field->kind != AstNode_Ident) { + gbString expr_str = expr_to_string(fv->field); + error_node(elem, "Invalid field name `%s` in `any` literal", expr_str); + gb_string_free(expr_str); + continue; + } + String name = fv->field->Ident.string; + + Selection sel = lookup_field(c->allocator, type, name, o->mode == Addressing_Type); + if (sel.entity == NULL) { + error_node(elem, "Unknown field `%.*s` in `any` literal", LIT(name)); + continue; + } + + isize index = sel.index.e[0]; + + if (fields_visited[index]) { + error_node(elem, "Duplicate field `%.*s` in `any` literal", LIT(name)); + continue; + } + + fields_visited[index] = true; + check_expr(c, o, fv->value); + + // NOTE(bill): `any` literals can never be constant + is_constant = false; + + check_assignment(c, o, field_types[index], str_lit("`any` literal")); + } + } else { + for_array(index, cl->elems) { + AstNode *elem = cl->elems.e[index]; + if (elem->kind == AstNode_FieldValue) { + error_node(elem, "Mixture of `field = value` and value elements in a `any` literal is not allowed"); + continue; + } + + + check_expr(c, o, elem); + if (index >= field_count) { + error_node(o->expr, "Too many values in `any` literal, expected %td", field_count); + break; + } + + // NOTE(bill): `any` literals can never be constant + is_constant = false; + + check_assignment(c, o, field_types[index], str_lit("`any` literal")); + } + if (cl->elems.count < field_count) { + error(cl->close, "Too few values in `any` literal, expected %td, got %td", field_count, cl->elems.count); + } + } + } + } break; + default: { gbString str = type_to_string(type); error_node(node, "Invalid compound literal type `%s`", str); diff --git a/src/checker.c b/src/checker.c index 6685d56ab..15dfe76f4 100644 --- a/src/checker.c +++ b/src/checker.c @@ -210,7 +210,6 @@ typedef struct CheckerContext { Scope * scope; DeclInfo * decl; u32 stmt_state_flags; - ExactValue iota; // Value of `iota` in a constant declaration; Invalid otherwise } CheckerContext; #define MAP_TYPE TypeAndValue @@ -549,7 +548,6 @@ void init_universal_scope(BuildContext *bc) { // Constants add_global_constant(a, str_lit("true"), t_untyped_bool, make_exact_value_bool(true)); add_global_constant(a, str_lit("false"), t_untyped_bool, make_exact_value_bool(false)); - add_global_constant(a, str_lit("iota"), t_untyped_integer, make_exact_value_integer(0)); add_global_entity(make_entity_nil(a, str_lit("nil"), t_untyped_nil)); @@ -570,9 +568,10 @@ void init_universal_scope(BuildContext *bc) { } - t_u8_ptr = make_type_pointer(a, t_u8); + t_u8_ptr = make_type_pointer(a, t_u8); t_int_ptr = make_type_pointer(a, t_int); - e_iota = scope_lookup_entity(universal_scope, str_lit("iota")); + t_i64_ptr = make_type_pointer(a, t_i64); + t_f64_ptr = make_type_pointer(a, t_f64); } @@ -1020,6 +1019,11 @@ void init_preload(Checker *c) { compiler_error("Could not find type declaration for `Type_Info_Member`\n" "Is `runtime.odin` missing from the `core` directory relative to odin.exe?"); } + Entity *type_info_enum_value_entity = current_scope_lookup_entity(c->global_scope, str_lit("Type_Info_Enum_Value")); + if (type_info_entity == NULL) { + compiler_error("Could not find type declaration for `Type_Info_Enum_Value`\n" + "Is `runtime.odin` missing from the `core` directory relative to odin.exe?"); + } t_type_info = type_info_entity->type; t_type_info_ptr = make_type_pointer(c->allocator, t_type_info); GB_ASSERT(is_type_union(type_info_entity->type)); @@ -1028,6 +1032,10 @@ void init_preload(Checker *c) { 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_enum_value = type_info_enum_value_entity->type; + t_type_info_enum_value_ptr = make_type_pointer(c->allocator, t_type_info_enum_value); + + if (record->field_count != 18) { compiler_error("Invalid `Type_Info` layout"); } diff --git a/src/entity.c b/src/entity.c index 17fb70e06..a35c68d08 100644 --- a/src/entity.c +++ b/src/entity.c @@ -85,9 +85,6 @@ struct Entity { }; -Entity *e_iota = NULL; - - Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token, Type *type) { Entity *entity = gb_alloc_item(a, Entity); entity->kind = kind; diff --git a/src/ir.c b/src/ir.c index 789c8eddd..69d8d989c 100644 --- a/src/ir.c +++ b/src/ir.c @@ -1051,6 +1051,12 @@ irValue *ir_make_const_i32(gbAllocator a, i64 i) { irValue *ir_make_const_i64(gbAllocator a, i64 i) { return ir_make_value_constant(a, t_i64, make_exact_value_integer(i)); } +irValue *ir_make_const_f32(gbAllocator a, f32 f) { + return ir_make_value_constant(a, t_f32, make_exact_value_float(f)); +} +irValue *ir_make_const_f64(gbAllocator a, f64 f) { + return ir_make_value_constant(a, t_f64, make_exact_value_float(f)); +} irValue *ir_make_const_bool(gbAllocator a, bool b) { return ir_make_value_constant(a, t_bool, make_exact_value_bool(b != 0)); } @@ -3743,6 +3749,48 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { ir_emit_store(proc, gep2, ir_make_const_int(proc->module->allocator, slice->ConstantSlice.count)); } } break; + + case Type_Basic: { + GB_ASSERT(is_type_any(bt)); + if (cl->elems.count > 0) { + ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, make_exact_value_compound(expr))); + String field_names[2] = { + str_lit("type_info"), + str_lit("data"), + }; + Type *field_types[2] = { + t_type_info_ptr, + t_rawptr, + }; + + for_array(field_index, cl->elems) { + AstNode *elem = cl->elems.e[field_index]; + + irValue *field_expr = NULL; + isize index = field_index; + + if (elem->kind == AstNode_FieldValue) { + ast_node(fv, FieldValue, elem); + Selection sel = lookup_field(proc->module->allocator, bt, fv->field->Ident.string, false); + index = sel.index.e[0]; + elem = fv->value; + } else { + TypeAndValue *tav = type_and_value_of_expression(proc->module->info, elem); + Selection sel = lookup_field(proc->module->allocator, bt, field_names[field_index], false); + index = sel.index.e[0]; + } + + field_expr = ir_build_expr(proc, elem); + + GB_ASSERT(ir_type(field_expr)->kind != Type_Tuple); + + Type *ft = field_types[index]; + irValue *fv = ir_emit_conv(proc, field_expr, ft); + irValue *gep = ir_emit_struct_ep(proc, v, index); + ir_emit_store(proc, gep, fv); + } + } + } } return ir_make_addr(v, expr); @@ -5682,6 +5730,7 @@ void ir_gen_tree(irGen *s) { Entity **fields = t->Record.fields; isize count = t->Record.field_count; irValue *name_array = NULL; + irValue *value_array = NULL; { Token token = {Token_Ident}; @@ -5698,8 +5747,40 @@ void ir_gen_tree(irGen *s) { map_ir_value_set(&m->members, hash_string(token.string), name_array); } + { + Token token = {Token_Ident}; + i32 id = cast(i32)entry_index; + char name_base[] = "__$enum_values"; + 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_type_info_enum_value, count)); + value_array = ir_make_value_global(a, e, NULL); + value_array->Global.is_private = true; + ir_module_add_value(m, e, value_array); + map_ir_value_set(&m->members, hash_string(token.string), value_array); + } + + bool is_value_int = is_type_integer(t->Record.enum_base_type); + for (isize i = 0; i < count; i++) { - irValue *name_ep = ir_emit_array_epi(proc, name_array, i); + irValue *name_ep = ir_emit_array_epi(proc, name_array, i); + irValue *value_ep = ir_emit_array_epi(proc, value_array, i); + + ExactValue value = fields[i]->Constant.value; + + if (is_value_int) { + i64 i = value.value_integer; + value_ep = ir_emit_conv(proc, value_ep, t_i64_ptr); + ir_emit_store(proc, value_ep, ir_make_const_i64(a, i)); + } else { + GB_ASSERT(is_type_float(t->Record.enum_base_type)); + f64 f = value.value_float; + value_ep = ir_emit_conv(proc, value_ep, t_f64_ptr); + ir_emit_store(proc, value_ep, ir_make_const_f64(a, f)); + } + ir_emit_store(proc, name_ep, ir_make_const_string(a, fields[i]->token.string)); } @@ -5711,6 +5792,13 @@ void ir_gen_tree(irGen *s) { ir_emit_store(proc, ir_emit_struct_ep(proc, names, 0), name_array_elem); ir_emit_store(proc, ir_emit_struct_ep(proc, names, 1), v_count); ir_emit_store(proc, ir_emit_struct_ep(proc, names, 2), v_count); + + irValue *values = ir_emit_struct_ep(proc, tag, 2); + irValue *value_array_elem = ir_array_elem(proc, value_array); + + ir_emit_store(proc, ir_emit_struct_ep(proc, values, 0), value_array_elem); + ir_emit_store(proc, ir_emit_struct_ep(proc, values, 1), v_count); + ir_emit_store(proc, ir_emit_struct_ep(proc, values, 2), v_count); } } break; diff --git a/src/types.c b/src/types.c index 779924cd4..9e6f6bd23 100644 --- a/src/types.c +++ b/src/types.c @@ -84,7 +84,10 @@ typedef struct TypeRecord { bool struct_is_ordered; Entity **fields_in_src_order; // Entity_Variable - Type * enum_base_type; + Type * enum_base_type; + Entity *enum_count; + Entity *enum_min_value; + Entity *enum_max_value; } TypeRecord; #define TYPE_KINDS \ @@ -253,11 +256,15 @@ gb_global Type *t_rune = &basic_type_aliases[1]; gb_global Type *t_u8_ptr = NULL; gb_global Type *t_int_ptr = NULL; +gb_global Type *t_i64_ptr = NULL; +gb_global Type *t_f64_ptr = NULL; -gb_global Type *t_type_info = NULL; -gb_global Type *t_type_info_ptr = NULL; -gb_global Type *t_type_info_member = NULL; -gb_global Type *t_type_info_member_ptr = NULL; +gb_global Type *t_type_info = NULL; +gb_global Type *t_type_info_member = NULL; +gb_global Type *t_type_info_enum_value = NULL; +gb_global Type *t_type_info_ptr = NULL; +gb_global Type *t_type_info_member_ptr = NULL; +gb_global Type *t_type_info_enum_value_ptr = NULL; gb_global Type *t_type_info_named = NULL; gb_global Type *t_type_info_integer = NULL; @@ -1043,11 +1050,27 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n if (str_eq(field_name, str)) { sel.entity = f; - selection_add_index(&sel, i); + // selection_add_index(&sel, i); return sel; } } } else if (is_type_enum(type)) { + // NOTE(bill): These may not have been added yet, so check in case + if (type->Record.enum_count != NULL) { + if (str_eq(field_name, str_lit("count"))) { + sel.entity = type->Record.enum_count; + return sel; + } + if (str_eq(field_name, str_lit("min_value"))) { + sel.entity = type->Record.enum_min_value; + return sel; + } + if (str_eq(field_name, str_lit("max_value"))) { + sel.entity = type->Record.enum_max_value; + return sel; + } + } + for (isize i = 0; i < type->Record.field_count; i++) { Entity *f = type->Record.fields[i]; GB_ASSERT(f->kind == Entity_Constant); @@ -1055,7 +1078,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n if (str_eq(field_name, str)) { sel.entity = f; - selection_add_index(&sel, i); + // selection_add_index(&sel, i); return sel; } }