Skip to content
This repository was archived by the owner on Jun 16, 2021. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions ion/gen.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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 = "); \
Expand Down Expand Up @@ -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;
Expand Down
30 changes: 25 additions & 5 deletions ion/resolve.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}
Expand Down
8 changes: 8 additions & 0 deletions ion/system_packages/builtin/typeinfo.ion
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ enum TypeKind {
TYPE_ULONG,
TYPE_LLONG,
TYPE_ULLONG,
TYPE_ENUM,
TYPE_FLOAT,
TYPE_DOUBLE,
TYPE_CONST,
Expand All @@ -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;
Expand All @@ -40,6 +46,8 @@ struct TypeInfo {
base: typeid;
fields: TypeFieldInfo*;
num_fields: int;
enum_items: TypeEnumItemInfo*;
num_enum_items: int;
}

@foreign
Expand Down
4 changes: 4 additions & 0 deletions ion/test1/subtest1/subtest1.ion
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import LIBC = libc {printf}

enum SubOptions {
SubOptions_I, SubOptions_J, SubOptions_K,
}

func bogus_func() {
printf("Hello, world!\n");
// asdf;
Expand Down
73 changes: 72 additions & 1 deletion ion/test1/test1.ion
Original file line number Diff line number Diff line change
Expand Up @@ -510,12 +510,55 @@ func print_any(any: Any) {
case typeof(float):
printf("%f", *(:float const *)any.ptr);
default:
printf("<unknown>");
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("<unknown>");
}
}
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");
Expand Down Expand Up @@ -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; i<typeinfo.num_enum_items; i++) {
printf("%s%s=%lld", prefix, typeinfo.enum_items[i].name, typeinfo.enum_items[i].int_value);
prefix = ", ";
}
printf(" }");
case TYPE_STRUCT, TYPE_UNION:
printf(" %s={ ", typeinfo.kind == TYPE_STRUCT ? "struct" : "union");
for (i := 0; i < typeinfo.num_fields; i++) {
Expand All @@ -584,6 +637,12 @@ func println_typeinfo(type: typeid) {
printf("\n");
}

enum Options {
Options_A,
Options_B,
Options_C,
}

func test_typeinfo() {
i := 42;
f := 3.14;
Expand All @@ -602,6 +661,18 @@ 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));

o = 32;
println_any({&o, typeof(o)});

so := subtest1.SubOptions_I;
println_any({&so, typeof(so)});
println_typeinfo(typeof(so));
}

struct Ints {
Expand Down
16 changes: 15 additions & 1 deletion ion/type.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ typedef struct TypeField {
size_t offset;
} TypeField;

typedef struct TypeEnumItem {
Sym *sym;
} TypeEnumItem;

struct Type {
TypeKind kind;
size_t size;
Expand All @@ -50,6 +54,10 @@ struct Type {
TypeField *fields;
size_t num_fields;
} aggregate;
struct {
TypeEnumItem *enum_items;
size_t num_enum_items;
} enumeration;
struct {
Type **params;
size_t num_params;
Expand Down Expand Up @@ -428,12 +436,18 @@ Type *type_incomplete(Sym *sym) {
return type;
}

Type *type_enum(Sym *sym, Type *base) {
Type *type_enum(Sym *sym, Type *base, TypeEnumItem* items, size_t num_items) {
Type *type = type_alloc(TYPE_ENUM);
type->sym = 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;
}

Expand Down