Browse Source

`type_info_of`; enum_value_to_string and string_to_enum_value

Ginger Bill 8 years ago
parent
commit
f1ab17ed4e
8 changed files with 120 additions and 90 deletions
  1. 2 1
      code/demo.odin
  2. 9 7
      core/_preload.odin
  3. 69 53
      core/fmt.odin
  4. 9 5
      src/check_expr.cpp
  5. 11 10
      src/checker.cpp
  6. 18 13
      src/ir.cpp
  7. 1 0
      src/parser.cpp
  8. 1 1
      src/tokenizer.cpp

+ 2 - 1
code/demo.odin

@@ -1,5 +1,6 @@
 import "fmt.odin";
 import "fmt.odin";
 
 
 main :: proc() {
 main :: proc() {
-	fmt.println("Hellope!");
+	v, ok := fmt.string_to_enum_value(Allocator.Mode, "FreeAll");
+	if ok do assert(v == Allocator.Mode.FreeAll);
 }
 }

+ 9 - 7
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.
 // #shared_global_scope due to  the internals of the compiler.
 // This could change at a later date if the all these data structures are
 // This could change at a later date if the all these data structures are
 // implemented within the compiler rather than in this "preload" file
 // implemented within the compiler rather than in this "preload" file
@@ -38,10 +38,12 @@ CallingConvention :: enum {
 // The compiler relies upon this _exact_ order
 // The compiler relies upon this _exact_ order
 TypeInfo :: struct #ordered {
 TypeInfo :: struct #ordered {
 // Core Types
 // 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 {
 	Record :: struct #ordered {
 		types:        []^TypeInfo;
 		types:        []^TypeInfo;
 		names:        []string;
 		names:        []string;
@@ -416,7 +418,7 @@ __get_map_header :: proc(m: ^$T/map[$K]$V) -> __MapHeader #cc_contextless {
 		value: V;
 		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.is_key_string = is_string;
 	header.entry_size    = size_of(Entry);
 	header.entry_size    = size_of(Entry);
 	header.entry_align   = align_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 {
 __get_map_key :: proc(key: $K) -> __MapKey #cc_contextless {
 	map_key: __MapKey;
 	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 {
 	match _ in ti {
 	case TypeInfo.Integer:
 	case TypeInfo.Integer:
 		match 8*size_of(key) {
 		match 8*size_of(key) {

+ 69 - 53
core/fmt.odin

@@ -183,8 +183,8 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) {
 		write_string(buf, info.name);
 		write_string(buf, info.name);
 	case Integer:
 	case Integer:
 		match {
 		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:
 		case:
 			write_string(buf, info.signed ? "i" : "u");
 			write_string(buf, info.signed ? "i" : "u");
 			write_int(buf, i64(8*ti.size), 10);
 			write_int(buf, i64(8*ti.size), 10);
@@ -648,72 +648,88 @@ fmt_pointer :: proc(fi: ^FmtInfo, p: rawptr, verb: rune) {
 	_fmt_int(fi, u, 16, false, 8*size_of(rawptr), __DIGITS_UPPER);
 	_fmt_int(fi, u, 16, false, 8*size_of(rawptr), __DIGITS_UPPER);
 }
 }
 
 
-fmt_enum :: proc(fi: ^FmtInfo, v: any, verb: rune) {
-	if v.type_info == nil || v.data == nil {
-		write_string(fi.buf, "<nil>");
-		return;
-	}
+enum_value_to_string :: proc(v: any) -> (string, bool) {
+	v.type_info = type_info_base(v.type_info);
 
 
 	using TypeInfo;
 	using TypeInfo;
 	match e in v.type_info.variant {
 	match e in v.type_info.variant {
-	case:
-		fmt_bad_verb(fi, verb);
-		return;
+	case: return "", false;
 	case Enum:
 	case Enum:
-		match 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));
-			}
-
+		get_str :: proc(i: $T, e: Enum) -> (string, bool) {
 			if types.is_string(e.base) {
 			if types.is_string(e.base) {
 				for val, idx in e.values {
 				for val, idx in e.values {
-					if val.i == i {
-						write_string(fi.buf, e.names[idx]);
-						ok = true;
-						break;
+					if v, ok := val.(T); ok && v == i {
+						return e.names[idx], true;
 					}
 					}
 				}
 				}
 			} else if len(e.values) == 0 {
 			} else if len(e.values) == 0 {
-				write_string(fi.buf, "");
-				ok = true;
+				return "", true;
 			} else {
 			} else {
 				for val, idx in e.values {
 				for val, idx in e.values {
-					if val.i == i {
-						write_string(fi.buf, e.names[idx]);
-						ok = true;
-						break;
+					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);
+		}
+	}
 
 
-			if !ok {
-				write_string(fi.buf, "!%(BAD ENUM VALUE)");
+	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;
 			}
 			}
-		case:
-			fmt_bad_verb(fi, verb);
-			return;
+		}
+	}
+	return T{}, false;
+}
+
+fmt_enum :: proc(fi: ^FmtInfo, v: any, verb: rune) {
+	if v.type_info == nil || v.data == nil {
+		write_string(fi.buf, "<nil>");
+		return;
+	}
+
+	using TypeInfo;
+	match e in v.type_info.variant {
+	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':
+			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 String:     fmt_arg(fi, v, verb);
 
 
 	case Pointer:
 	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)^);
 			write_type(fi.buf, (cast(^^TypeInfo)v.data)^);
 		} else {
 		} else {
 			fmt_pointer(fi, (cast(^rawptr)v.data)^, verb);
 			fmt_pointer(fi, (cast(^rawptr)v.data)^, verb);

+ 9 - 5
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_size_of:
 	case BuiltinProc_align_of:
 	case BuiltinProc_align_of:
 	case BuiltinProc_offset_of:
 	case BuiltinProc_offset_of:
-	case BuiltinProc_type_info:
+	case BuiltinProc_type_info_of:
 	case BuiltinProc_transmute:
 	case BuiltinProc_transmute:
 		// NOTE(bill): The first arg may be a Type, this will be checked case by case
 		// NOTE(bill): The first arg may be a Type, this will be checked case by case
 		break;
 		break;
@@ -5295,10 +5295,10 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 		break;
 		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) {
 		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
 		// 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;
 		Type *t = o.type;
 		if (t == nullptr || t == t_invalid || is_type_polymorphic(operand->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;
 			return false;
 		}
 		}
 		t = default_type(t);
 		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->mode       = Addressing_Builtin;
 			o->builtin_id = BuiltinProc_type_of;
 			o->builtin_id = BuiltinProc_type_of;
 			break;
 			break;
+		case Token_type_info_of:
+			o->mode       = Addressing_Builtin;
+			o->builtin_id = BuiltinProc_type_info_of;
+			break;
 
 
 		default:
 		default:
 			error(node, "Illegal implicit name `%.*s`", LIT(i->string));
 			error(node, "Illegal implicit name `%.*s`", LIT(i->string));

+ 11 - 10
src/checker.cpp

@@ -40,7 +40,7 @@ enum BuiltinProcId {
 	BuiltinProc_align_of,
 	BuiltinProc_align_of,
 	BuiltinProc_offset_of,
 	BuiltinProc_offset_of,
 	BuiltinProc_type_of,
 	BuiltinProc_type_of,
-	BuiltinProc_type_info,
+	BuiltinProc_type_info_of,
 
 
 	BuiltinProc_compile_assert,
 	BuiltinProc_compile_assert,
 
 
@@ -86,7 +86,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
 	{STR_LIT("align_of"),         1, false, Expr_Expr},
 	{STR_LIT("align_of"),         1, false, Expr_Expr},
 	{STR_LIT("offset_of"),        2, false, Expr_Expr},
 	{STR_LIT("offset_of"),        2, false, Expr_Expr},
 	{STR_LIT("type_of"),          1, 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},
 	{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) {
 		if (found) {
 			Entity *e = *found;
 			Entity *e = *found;
 			if (gone_thru_proc) {
 			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;
 			if (entity_) *entity_ = e;

+ 18 - 13
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);
 		return ir_emit_source_code_location(proc, procedure, pos);
 	} break;
 	} break;
 
 
-	case BuiltinProc_type_info: {
+	case BuiltinProc_type_info_of: {
 		Type *t = default_type(type_of_expr(proc->module->info, ce->args[0]));
 		Type *t = default_type(type_of_expr(proc->module->info, ce->args[0]));
 		return ir_type_info(proc, t);
 		return ir_type_info(proc, t);
 	} break;
 	} break;
@@ -4793,7 +4793,17 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
 		AstNode *p = unparen_expr(ce->proc);
 		AstNode *p = unparen_expr(ce->proc);
 		if (proc_mode == Addressing_Builtin) {
 		if (proc_mode == Addressing_Builtin) {
 			Entity *e = entity_of_ident(proc->module->info, p);
 			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);
 			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);
 							                                         str_lit("__$enum_values"), cast(i64)entry_index);
 
 
 							bool is_value_int = is_type_integer(t->Enum.base_type);
 							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++) {
 							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);
 								irValue *value_ep = ir_emit_array_epi(proc, value_array, i);
 
 
 								ExactValue value = fields[i]->Constant.value;
 								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);
 							irValue *v_count = ir_const_int(a, count);

+ 1 - 0
src/parser.cpp

@@ -2217,6 +2217,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
 	case Token_size_of:
 	case Token_size_of:
 	case Token_align_of:
 	case Token_align_of:
 	case Token_offset_of:
 	case Token_offset_of:
+	case Token_type_info_of:
 		return parse_call_expr(f, ast_implicit(f, advance_token(f)));
 		return parse_call_expr(f, ast_implicit(f, advance_token(f)));
 
 
 
 

+ 1 - 1
src/tokenizer.cpp

@@ -107,7 +107,6 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
 	TOKEN_KIND(Token_macro,                  "macro"),                  \
 	TOKEN_KIND(Token_macro,                  "macro"),                  \
 	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_enum,                   "enum"),                   \
 	TOKEN_KIND(Token_enum,                   "enum"),                   \
 	TOKEN_KIND(Token_bit_field,              "bit_field"),              \
 	TOKEN_KIND(Token_bit_field,              "bit_field"),              \
 	TOKEN_KIND(Token_vector,                 "vector"),                 \
 	TOKEN_KIND(Token_vector,                 "vector"),                 \
@@ -123,6 +122,7 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
 	TOKEN_KIND(Token_align_of,               "align_of"),               \
 	TOKEN_KIND(Token_align_of,               "align_of"),               \
 	TOKEN_KIND(Token_offset_of,              "offset_of"),              \
 	TOKEN_KIND(Token_offset_of,              "offset_of"),              \
 	TOKEN_KIND(Token_type_of,                "type_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_asm,                    "asm"),                    \
 	TOKEN_KIND(Token_yield,                  "yield"),                  \
 	TOKEN_KIND(Token_yield,                  "yield"),                  \
 	TOKEN_KIND(Token_await,                  "await"),                  \
 	TOKEN_KIND(Token_await,                  "await"),                  \