From f1ab17ed4ef68a7591f8aa786e3c02d33d038f05 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Wed, 19 Jul 2017 14:01:56 +0100 Subject: [PATCH] `type_info_of`; enum_value_to_string and string_to_enum_value --- code/demo.odin | 3 +- core/_preload.odin | 16 +++--- core/fmt.odin | 128 +++++++++++++++++++++++++-------------------- src/check_expr.cpp | 14 +++-- src/checker.cpp | 21 ++++---- src/ir.cpp | 31 ++++++----- src/parser.cpp | 1 + src/tokenizer.cpp | 2 +- 8 files changed, 123 insertions(+), 93 deletions(-) diff --git a/code/demo.odin b/code/demo.odin index 4b88bfea1..ce2a160a1 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,5 +1,6 @@ import "fmt.odin"; main :: proc() { - fmt.println("Hellope!"); + v, ok := fmt.string_to_enum_value(Allocator.Mode, "FreeAll"); + if ok do assert(v == Allocator.Mode.FreeAll); } diff --git a/core/_preload.odin b/core/_preload.odin index 89785b7d3..99f6a828f 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -20,7 +20,7 @@ import ( -// IMPORTANT NOTE(bill): `type_info` cannot be used within a +// IMPORTANT NOTE(bill): `type_info_of` cannot be used within a // #shared_global_scope due to the internals of the compiler. // This could change at a later date if the all these data structures are // implemented within the compiler rather than in this "preload" file @@ -38,10 +38,12 @@ CallingConvention :: enum { // The compiler relies upon this _exact_ order TypeInfo :: struct #ordered { // Core Types - EnumValue :: struct #raw_union { - f: f64; - i: i128; - } + EnumValue :: union { + rune, + i8, i16, i32, i64, i128, int, + u8, u16, u32, u64, u128, uint, + f32, f64, + }; Record :: struct #ordered { types: []^TypeInfo; names: []string; @@ -416,7 +418,7 @@ __get_map_header :: proc(m: ^$T/map[$K]$V) -> __MapHeader #cc_contextless { value: V; } - _, is_string := type_info_base(type_info(K)).variant.(TypeInfo.String); + _, is_string := type_info_base(type_info_of(K)).variant.(TypeInfo.String); header.is_key_string = is_string; header.entry_size = size_of(Entry); header.entry_align = align_of(Entry); @@ -427,7 +429,7 @@ __get_map_header :: proc(m: ^$T/map[$K]$V) -> __MapHeader #cc_contextless { __get_map_key :: proc(key: $K) -> __MapKey #cc_contextless { map_key: __MapKey; - ti := type_info_base_without_enum(type_info(K)); + ti := type_info_base_without_enum(type_info_of(K)); match _ in ti { case TypeInfo.Integer: match 8*size_of(key) { diff --git a/core/fmt.odin b/core/fmt.odin index 25262ef2a..59c624aaf 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -183,8 +183,8 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) { write_string(buf, info.name); case Integer: match { - case ti == type_info(int): write_string(buf, "int"); - case ti == type_info(uint): write_string(buf, "uint"); + case ti == type_info_of(int): write_string(buf, "int"); + case ti == type_info_of(uint): write_string(buf, "uint"); case: write_string(buf, info.signed ? "i" : "u"); write_int(buf, i64(8*ti.size), 10); @@ -648,6 +648,70 @@ fmt_pointer :: proc(fi: ^FmtInfo, p: rawptr, verb: rune) { _fmt_int(fi, u, 16, false, 8*size_of(rawptr), __DIGITS_UPPER); } +enum_value_to_string :: proc(v: any) -> (string, bool) { + v.type_info = type_info_base(v.type_info); + + using TypeInfo; + match e in v.type_info.variant { + case: return "", false; + case Enum: + get_str :: proc(i: $T, e: Enum) -> (string, bool) { + if types.is_string(e.base) { + for val, idx in e.values { + if v, ok := val.(T); ok && v == i { + return e.names[idx], true; + } + } + } else if len(e.values) == 0 { + return "", true; + } else { + for val, idx in e.values { + if v, ok := val.(T); ok && v == i { + return e.names[idx], true; + } + } + } + return "", false; + } + + a := any{v.data, type_info_base(e.base)}; + match v in a { + case rune: return get_str(v, e); + case i8: return get_str(v, e); + case i16: return get_str(v, e); + case i32: return get_str(v, e); + case i64: return get_str(v, e); + case i128: return get_str(v, e); + case int: return get_str(v, e); + case u8: return get_str(v, e); + case u16: return get_str(v, e); + case u32: return get_str(v, e); + case u64: return get_str(v, e); + case u128: return get_str(v, e); + case uint: return get_str(v, e); + + case f32: return get_str(v, e); + case f64: return get_str(v, e); + } + } + + return "", false; +} + +string_to_enum_value :: proc(T: type, s: string) -> (T, bool) { + ti := type_info_base(type_info_of(T)); + if e, ok := ti.variant.(TypeInfo.Enum); ok { + for str, idx in e.names { + if s == str { + // NOTE(bill): Unsafe cast + ptr := cast(^T)&e.values[idx]; + return ptr^, true; + } + } + } + return T{}, false; +} + fmt_enum :: proc(fi: ^FmtInfo, v: any, verb: rune) { if v.type_info == nil || v.data == nil { write_string(fi.buf, ""); @@ -656,64 +720,16 @@ fmt_enum :: proc(fi: ^FmtInfo, v: any, verb: rune) { using TypeInfo; match e in v.type_info.variant { - case: - fmt_bad_verb(fi, verb); - return; + case: fmt_bad_verb(fi, verb); case Enum: match verb { + case: fmt_bad_verb(fi, verb); case 'd', 'f': fmt_arg(fi, any{v.data, type_info_base(e.base)}, verb); case 's', 'v': - i: i128; - f: f64; - ok: bool; - a := any{v.data, type_info_base(e.base)}; - match v in a { - case rune: i = i128(v); - case i8: i = i128(v); - case i16: i = i128(v); - case i32: i = i128(v); - case i64: i = i128(v); - case i128: i = i128(v); - case int: i = i128(v); - case u8: i = i128(v); - case u16: i = i128(v); - case u32: i = i128(v); - case u64: i = i128(v); - case u128: i = i128(v); - case uint: i = i128(v); - - case f32: f = f64(v); i = i128(transmute(i64, f)); - case f64: f = f64(v); i = i128(transmute(i64, f)); - } - - if types.is_string(e.base) { - for val, idx in e.values { - if val.i == i { - write_string(fi.buf, e.names[idx]); - ok = true; - break; - } - } - } else if len(e.values) == 0 { - write_string(fi.buf, ""); - ok = true; - } else { - for val, idx in e.values { - if val.i == i { - write_string(fi.buf, e.names[idx]); - ok = true; - break; - } - } - } - - if !ok { - write_string(fi.buf, "!%(BAD ENUM VALUE)"); - } - case: - fmt_bad_verb(fi, verb); - return; + str, ok := enum_value_to_string(v); + if !ok do str = "!%(BAD ENUM VALUE)"; + write_string(fi.buf, str); } } } @@ -762,7 +778,7 @@ fmt_value :: proc(fi: ^FmtInfo, v: any, verb: rune) { case String: fmt_arg(fi, v, verb); case Pointer: - if v.type_info == type_info(^TypeInfo) { + if v.type_info == type_info_of(^TypeInfo) { write_type(fi.buf, (cast(^^TypeInfo)v.data)^); } else { fmt_pointer(fi, (cast(^rawptr)v.data)^, verb); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 2a4d60872..ef65409c1 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4835,7 +4835,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id case BuiltinProc_size_of: case BuiltinProc_align_of: case BuiltinProc_offset_of: - case BuiltinProc_type_info: + case BuiltinProc_type_info_of: case BuiltinProc_transmute: // NOTE(bill): The first arg may be a Type, this will be checked case by case break; @@ -5295,10 +5295,10 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id break; - case BuiltinProc_type_info: { - // proc type_info(Type) -> ^Type_Info + case BuiltinProc_type_info_of: { + // proc type_info_of(Type) -> ^Type_Info if (c->context.scope->is_global) { - compiler_error("`type_info` Cannot be declared within a #shared_global_scope due to how the internals of the compiler works"); + compiler_error("`type_info_of` Cannot be declared within a #shared_global_scope due to how the internals of the compiler works"); } // NOTE(bill): The type information may not be setup yet @@ -5311,7 +5311,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id } Type *t = o.type; if (t == nullptr || t == t_invalid || is_type_polymorphic(operand->type)) { - error(ce->args[0], "Invalid argument for `type_info`"); + error(ce->args[0], "Invalid argument for `type_info_of`"); return false; } t = default_type(t); @@ -7110,6 +7110,10 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t o->mode = Addressing_Builtin; o->builtin_id = BuiltinProc_type_of; break; + case Token_type_info_of: + o->mode = Addressing_Builtin; + o->builtin_id = BuiltinProc_type_info_of; + break; default: error(node, "Illegal implicit name `%.*s`", LIT(i->string)); diff --git a/src/checker.cpp b/src/checker.cpp index c2694774d..98e47c86a 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -40,7 +40,7 @@ enum BuiltinProcId { BuiltinProc_align_of, BuiltinProc_offset_of, BuiltinProc_type_of, - BuiltinProc_type_info, + BuiltinProc_type_info_of, BuiltinProc_compile_assert, @@ -86,7 +86,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("align_of"), 1, false, Expr_Expr}, {STR_LIT("offset_of"), 2, false, Expr_Expr}, {STR_LIT("type_of"), 1, false, Expr_Expr}, - {STR_LIT("type_info"), 1, false, Expr_Expr}, + {STR_LIT("type_info_of"), 1, false, Expr_Expr}, {STR_LIT("compile_assert"), 1, false, Expr_Expr}, @@ -521,14 +521,15 @@ void scope_lookup_parent_entity(Scope *scope, String name, Scope **scope_, Entit if (found) { Entity *e = *found; if (gone_thru_proc) { - // if (e->kind == Entity_Label) { - // continue; - // } - // if (e->kind == Entity_Variable && - // !e->scope->is_file && - // !e->scope->is_global) { - // continue; - // } + // IMPORTANT TODO(bill): Is this correct?! + if (e->kind == Entity_Label) { + continue; + } + if (e->kind == Entity_Variable && + !e->scope->is_file && + !e->scope->is_global) { + continue; + } } if (entity_) *entity_ = e; diff --git a/src/ir.cpp b/src/ir.cpp index 833edb0e2..61f8d8ffa 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3866,7 +3866,7 @@ irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv return ir_emit_source_code_location(proc, procedure, pos); } break; - case BuiltinProc_type_info: { + case BuiltinProc_type_info_of: { Type *t = default_type(type_of_expr(proc->module->info, ce->args[0])); return ir_type_info(proc, t); } break; @@ -4793,7 +4793,17 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { AstNode *p = unparen_expr(ce->proc); if (proc_mode == Addressing_Builtin) { Entity *e = entity_of_ident(proc->module->info, p); - BuiltinProcId id = cast(BuiltinProcId)(e != nullptr ? e->Builtin.id : BuiltinProc_DIRECTIVE); + BuiltinProcId id = BuiltinProc_Invalid; + if (e != nullptr) { + id = cast(BuiltinProcId)e->Builtin.id; + } else { + id = BuiltinProc_DIRECTIVE; + if (ce->proc->kind == AstNode_Implicit) { + ast_node(i, Implicit, ce->proc); + GB_ASSERT(i->kind == Token_type_info_of); + id = BuiltinProc_type_info_of; + } + } return ir_build_builtin_proc(proc, expr, tv, id); } @@ -8106,24 +8116,19 @@ void ir_gen_tree(irGen *s) { str_lit("__$enum_values"), cast(i64)entry_index); bool is_value_int = is_type_integer(t->Enum.base_type); + if (!is_value_int) { + GB_ASSERT(is_type_float(t->Enum.base_type)); + } for (isize i = 0; i < count; 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; + irValue *v = ir_value_constant(a, t->Enum.base_type, value); - if (is_value_int) { - value_ep = ir_emit_conv(proc, value_ep, t_i128_ptr); - ir_emit_store(proc, value_ep, ir_value_constant(a, t_i128, value)); - } else { - GB_ASSERT(is_type_float(t->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_const_f64(a, f)); - } - - ir_emit_store(proc, name_ep, ir_const_string(a, fields[i]->token.string)); + ir_emit_store(proc, value_ep, ir_emit_conv(proc, v, t_type_info_enum_value)); + ir_emit_store(proc, name_ep, ir_const_string(a, fields[i]->token.string)); } irValue *v_count = ir_const_int(a, count); diff --git a/src/parser.cpp b/src/parser.cpp index a7da2ee9e..4b8c597db 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2217,6 +2217,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) { case Token_size_of: case Token_align_of: case Token_offset_of: + case Token_type_info_of: return parse_call_expr(f, ast_implicit(f, advance_token(f))); diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 1b4d290f3..68ecf6178 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -107,7 +107,6 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \ 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_bit_field, "bit_field"), \ TOKEN_KIND(Token_vector, "vector"), \ @@ -123,6 +122,7 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \ TOKEN_KIND(Token_align_of, "align_of"), \ TOKEN_KIND(Token_offset_of, "offset_of"), \ TOKEN_KIND(Token_type_of, "type_of"), \ + TOKEN_KIND(Token_type_info_of, "type_info_of"), \ TOKEN_KIND(Token_asm, "asm"), \ TOKEN_KIND(Token_yield, "yield"), \ TOKEN_KIND(Token_await, "await"), \