diff --git a/ion/gen.c b/ion/gen.c index 72aed75..b5a6497 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", @@ -1101,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 = "); \ @@ -1157,12 +1168,19 @@ 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(", .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"); 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/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 23ad558..3c9e0db 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, @@ -31,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; @@ -40,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 30a5a95..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"); @@ -566,6 +609,16 @@ 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); + 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; }