From a659b1ccc4b9c646006db826a962466f59f1262f Mon Sep 17 00:00:00 2001 From: Nicolas Date: Sun, 30 Sep 2018 13:15:28 +0200 Subject: [PATCH 1/2] Add basic type info for enum types. We populate the `base` field with the type of the enum. I.e. ```ion enum Foo = int8 { A, B, C } #assert(get_typeinfo(typeof(Foo)).base == typeof(int8)) ``` --- ion/gen.c | 12 +++++++++--- ion/system_packages/builtin/typeinfo.ion | 1 + ion/test1/test1.ion | 14 ++++++++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/ion/gen.c b/ion/gen.c index 72aed75..a6085aa 100644 --- a/ion/gen.c +++ b/ion/gen.c @@ -470,6 +470,7 @@ const char *typeid_kind_names[NUM_TYPE_KINDS] = { [TYPE_ULONG] = "TYPE_ULONG", [TYPE_LLONG] = "TYPE_LLONG", [TYPE_ULLONG] = "TYPE_ULLONG", + [TYPE_ENUM] = "TYPE_ENUM", [TYPE_FLOAT] = "TYPE_FLOAT", [TYPE_DOUBLE] = "TYPE_DOUBLE", [TYPE_CONST] = "TYPE_CONST", @@ -1157,12 +1158,17 @@ void gen_typeinfo(Type *type) { gen_typeinfo_fields(type); genlnf("}},"); break; + case TYPE_ENUM: + gen_typeinfo_header("TYPE_ENUM", type); + genf(", .name = "); + gen_str(get_gen_name(type->sym), false); + genf(", .base = "); + gen_typeid(type->base); + genf("},"); + break; case TYPE_FUNC: genf("NULL, // Func"); break; - case TYPE_ENUM: - genf("NULL, // Enum"); - break; case TYPE_INCOMPLETE: genf("NULL, // Incomplete: %s", get_gen_name(type->sym)); break; diff --git a/ion/system_packages/builtin/typeinfo.ion b/ion/system_packages/builtin/typeinfo.ion index 23ad558..284db41 100644 --- a/ion/system_packages/builtin/typeinfo.ion +++ b/ion/system_packages/builtin/typeinfo.ion @@ -15,6 +15,7 @@ enum TypeKind { TYPE_ULONG, TYPE_LLONG, TYPE_ULLONG, + TYPE_ENUM, TYPE_FLOAT, TYPE_DOUBLE, TYPE_CONST, diff --git a/ion/test1/test1.ion b/ion/test1/test1.ion index 30a5a95..75de1ab 100644 --- a/ion/test1/test1.ion +++ b/ion/test1/test1.ion @@ -566,6 +566,9 @@ func print_typeinfo(type: typeid) { print_type(type); printf(" size=%d align=%d", typeinfo.size, typeinfo.align); switch (typeinfo.kind) { + case TYPE_ENUM: + printf(" enum="); + print_type(typeinfo.base); case TYPE_STRUCT, TYPE_UNION: printf(" %s={ ", typeinfo.kind == TYPE_STRUCT ? "struct" : "union"); for (i := 0; i < typeinfo.num_fields; i++) { @@ -584,6 +587,12 @@ func println_typeinfo(type: typeid) { printf("\n"); } +enum Options { + Options_A, + Options_B, + Options_C, +} + func test_typeinfo() { i := 42; f := 3.14; @@ -602,6 +611,11 @@ func test_typeinfo() { println_typeinfo(typeof(UartCtrl)); println_typeinfo(typeof(:IntOrPtr*)); println_typeinfo(typeof(IntOrPtr)); + + // Demonstrate typeinfos for enums: + o := Options_B; + println_any({&o, typeof(o)}); + println_typeinfo(typeof(o)); } struct Ints { From 12cbaa237f3165eef5432b5143a74371f67ad1d4 Mon Sep 17 00:00:00 2001 From: Nicolas Date: Sun, 30 Sep 2018 14:08:46 +0200 Subject: [PATCH 2/2] Add typeinfo about enum values This allows printing the constant corresponding to the value, or simply enumerating the constants. Note however that the name corresponds to the externally known name, (i.e. C name) rather than the ion name. --- ion/gen.c | 14 +++++- ion/resolve.c | 30 ++++++++++-- ion/system_packages/builtin/typeinfo.ion | 7 +++ ion/test1/subtest1/subtest1.ion | 4 ++ ion/test1/test1.ion | 59 +++++++++++++++++++++++- ion/type.c | 16 ++++++- 6 files changed, 122 insertions(+), 8 deletions(-) diff --git a/ion/gen.c b/ion/gen.c index a6085aa..b5a6497 100644 --- a/ion/gen.c +++ b/ion/gen.c @@ -1102,6 +1102,16 @@ void gen_typeinfo_fields(Type *type) { gen_indent--; } +void gen_typeinfo_enum_items(Type *type) { + gen_indent++; + for (size_t i = 0; i < type->enumeration.num_enum_items; i++) { + TypeEnumItem enum_item = type->enumeration.enum_items[i]; + const char* name = get_gen_name(enum_item.sym); + genf("{ .name = \"%s\", .int_value = %s },", name, name); + } + gen_indent--; +} + #define CASE(kind, name) \ case kind: \ genf("&(TypeInfo){" #kind ", .size = sizeof(" #name "), .align = sizeof(" #name "), .name = "); \ @@ -1164,7 +1174,9 @@ void gen_typeinfo(Type *type) { gen_str(get_gen_name(type->sym), false); genf(", .base = "); gen_typeid(type->base); - genf("},"); + genf(", .num_enum_items = %d, .enum_items = (TypeEnumItemInfo[]) {", type->enumeration.num_enum_items); + gen_typeinfo_enum_items(type); + genf("}},"); break; case TYPE_FUNC: genf("NULL, // Func"); diff --git a/ion/resolve.c b/ion/resolve.c index d56e019..4d68e2d 100644 --- a/ion/resolve.c +++ b/ion/resolve.c @@ -819,6 +819,23 @@ Type *resolve_init(SrcPos pos, Typespec *typespec, Expr *expr) { return type; } +Type *resolve_decl_enum(Sym *sym, Decl *decl) { + assert(decl->kind == DECL_ENUM); + Type *base = decl->enum_decl.type ? resolve_typespec(decl->enum_decl.type) : type_int; + if (!is_integer_type(base)) { + fatal_error(decl->pos, "Base type of enum must be integer type"); + } + TypeEnumItem *enum_items = NULL; + for (size_t i = 0; i < decl->enum_decl.num_items; i++) { + EnumItem item = decl->enum_decl.items[i]; + Sym *enum_item_sym = get_package_sym(sym->home_package, item.name); + buf_push(enum_items, (TypeEnumItem) { .sym = enum_item_sym }); + } + Type *type = type_enum(sym, base, enum_items, buf_len(enum_items)); + buf_free(enum_items); + return type; +} + Type *resolve_decl_var(Decl *decl) { assert(decl->kind == DECL_VAR); return resolve_init(decl->pos, decl->var.type, decl->var.expr); @@ -1204,11 +1221,7 @@ void resolve_sym(Sym *sym) { if (decl && decl->kind == DECL_TYPEDEF) { sym->type = resolve_typespec(decl->typedef_decl.type); } else if (decl->kind == DECL_ENUM) { - Type *base = decl->enum_decl.type ? resolve_typespec(decl->enum_decl.type) : type_int; - if (!is_integer_type(base)) { - fatal_error(decl->pos, "Base type of enum must be integer type"); - } - sym->type = type_enum(sym, base); + sym->type = resolve_decl_enum(sym, decl); } else { sym->type = type_incomplete(sym); } @@ -1241,6 +1254,13 @@ void finalize_sym(Sym *sym) { if (sym->decl && !is_decl_foreign(sym->decl) && !sym->decl->is_incomplete) { if (sym->kind == SYM_TYPE) { complete_type(sym->type); + // Enumeration values are needed for the typeinfo, and + // therefore we need the symbol to be resolved and emitted + if (!flag_notypeinfo && sym->type->kind == TYPE_ENUM) { + for (TypeEnumItem *it = sym->type->enumeration.enum_items; it < sym->type->enumeration.enum_items + sym->type->enumeration.num_enum_items; it++) { + resolve_sym(it->sym); + } + } } else if (sym->kind == SYM_FUNC) { resolve_func_body(sym); } diff --git a/ion/system_packages/builtin/typeinfo.ion b/ion/system_packages/builtin/typeinfo.ion index 284db41..3c9e0db 100644 --- a/ion/system_packages/builtin/typeinfo.ion +++ b/ion/system_packages/builtin/typeinfo.ion @@ -32,6 +32,11 @@ struct TypeFieldInfo { offset: int; } +struct TypeEnumItemInfo { + name: char const*; + int_value: int64; // base type is enough to represent these values +} + struct TypeInfo { kind: TypeKind; size: int; @@ -41,6 +46,8 @@ struct TypeInfo { base: typeid; fields: TypeFieldInfo*; num_fields: int; + enum_items: TypeEnumItemInfo*; + num_enum_items: int; } @foreign diff --git a/ion/test1/subtest1/subtest1.ion b/ion/test1/subtest1/subtest1.ion index caac49d..3cb3659 100644 --- a/ion/test1/subtest1/subtest1.ion +++ b/ion/test1/subtest1/subtest1.ion @@ -1,5 +1,9 @@ import LIBC = libc {printf} +enum SubOptions { + SubOptions_I, SubOptions_J, SubOptions_K, +} + func bogus_func() { printf("Hello, world!\n"); // asdf; diff --git a/ion/test1/test1.ion b/ion/test1/test1.ion index 75de1ab..fb9cb12 100644 --- a/ion/test1/test1.ion +++ b/ion/test1/test1.ion @@ -510,12 +510,55 @@ func print_any(any: Any) { case typeof(float): printf("%f", *(:float const *)any.ptr); default: - printf(""); + typeinfo := get_typeinfo(any.type); + if (typeinfo.kind == TYPE_ENUM) { + value := int64_from_integer({any.ptr, typeinfo.base}); + enum_item: TypeEnumItemInfo*; + for (i:=0; i < typeinfo.num_enum_items; i++) { + if (typeinfo.enum_items[i].int_value == value) { + enum_item = &typeinfo.enum_items[i]; + } + } + if (!enum_item) { + printf("%lld (undefined enum item)", value); + } else { + printf("%lld (%s)", enum_item.int_value, enum_item.name); + } + } else { + printf(""); + } } printf(": "); print_type(any.type); } +func int64_from_integer(any: Any) : int64 { + switch(any.type) { + case typeof(uint): { + return *(:uint const*) any.ptr; + } + case typeof(int): { + return *(:int const*) any.ptr; + } + case typeof(ulong): { + return *(:ulong const*) any.ptr; + } + case typeof(long): { + return *(:long const*) any.ptr; + } + case typeof(llong): { + return *(:llong const*) any.ptr; + } + case typeof(ullong): { + return *(:ullong const*) any.ptr; + } + default: { + #assert(false); + return 0; + } + } +} + func println_any(any: Any) { print_any(any); printf("\n"); @@ -569,6 +612,13 @@ func print_typeinfo(type: typeid) { case TYPE_ENUM: printf(" enum="); print_type(typeinfo.base); + printf(" { "); + prefix := ""; + for (i:=0; isym = sym; type->base = base; type->size = type_int->size; type->align = type_int->align; + TypeEnumItem *enum_items = NULL; + for (TypeEnumItem *it = items; it < items + num_items; it++) { + buf_push(enum_items, *it); + } + type->enumeration.num_enum_items = buf_len(enum_items); + type->enumeration.enum_items = enum_items; return type; }