commit c58aca7a0361e28bf25f24414e9fc00c11184f14
parent 6ddc4027de2150ce98235cb07e597361faad4c6c
Author: Drew DeVault <sir@cmpwn.com>
Date: Sat, 25 Sep 2021 12:18:05 +0200
tests: add 34-reflect, fix other tests
Type IDs have changed and any test which relied on that was broken.
Diffstat:
15 files changed, 302 insertions(+), 41 deletions(-)
diff --git a/Makefile b/Makefile
@@ -8,6 +8,7 @@ harec: $(harec_objects)
@printf 'CCLD\t$@\n'
@$(CC) $(LDFLAGS) -o $@ $(harec_objects) $(LIBS)
+include types/Makefile
include rt/Makefile
include tests/Makefile
diff --git a/config.sh b/config.sh
@@ -221,6 +221,7 @@ run_configure() {
printf "Populating build dir... "
populate "$srcdir/doc"
populate "$srcdir/include"
+ populate "$srcdir/types"
populate "$srcdir/rt"
populate "$srcdir/src"
populate "$srcdir/tests"
diff --git a/configure b/configure
@@ -28,6 +28,7 @@ harec() {
all="harec"
+subdir types
subdir rt
subdir tests
diff --git a/rt/Makefile b/rt/Makefile
@@ -11,14 +11,14 @@ libhart_srcs+=\
rt/strcmp.ha \
rt/types.ha
-libhart.a: harec $(libhart_srcs) $(libhart_objs) $(rtstart)
+libhart.a: harec $(libhart_srcs) $(libhart_objs) $(rtstart) types/types.o
@printf 'HAREC\t$@\n'
@mkdir -p $(HARECACHE)/rt
@./harec -Nrt -t$(HARECACHE)/rt/rt.td -o $@.ssa $(libhart_srcs)
@$(QBE) -o $@.s $@.ssa
@$(AS) -g -o $@.o $@.s
- @$(AR) -csr $@ $@.o $(libhart_objs)
- @rm $@.o $@.s $@.ssa
+ @$(AR) -csr $@ $@.o $(libhart_objs) types/types.o
+ #@rm $@.o $@.s $@.ssa
clean-rt:
@rm -f libhart.a $(libhart_objs) $(rtstart)
diff --git a/rt/types.ha b/rt/types.ha
@@ -14,11 +14,82 @@ type types::flags = enum u8 {
ERROR = 1 << 1,
};
-type types::repr = (types::builtin | void);
+type types::repr = (types::alias | types::array | types::builtin
+ | types::enum_ | types::func | types::pointer | types::slice_repr
+ | types::struct_union | types::tagged | types::tuple);
+
+type types::alias = struct {
+ ident: []str,
+ secondary: type,
+};
+
+type types::array = struct {
+ length: size,
+ members: type,
+};
type types::builtin = enum u8 {
BOOL, CHAR, F32, F64, I16, I32, I64, I8, INT, NULL, RUNE, SIZE, STR,
- U16, U32, U64, U8, UINT, UINTPTR, VOID,
+ TYPE, U16, U32, U64, U8, UINT, UINTPTR, VOID,
+};
+
+type types::enum_ = struct {
+ storage: types::builtin,
+ values: [](str, u64),
+};
+
+type types::variadism = enum {
+ NONE,
+ C,
+ HARE,
+};
+
+type types::func_flags = enum uint {
+ NORETURN = 1 << 0,
+};
+
+type types::func = struct {
+ result: type,
+ variadism: types::variadism,
+ flags: types::func_flags,
+ params: []type,
+};
+
+type types::pointer_flags = enum u8 {
+ NONE = 0,
+ NULLABLE = 1 << 0,
+};
+
+type types::pointer = struct {
+ referent: type,
+ flags: types::pointer_flags,
+};
+
+type types::slice_repr = type;
+
+type types::struct_kind = enum {
+ STRUCT,
+ UNION,
+};
+
+type types::struct_union = struct {
+ kind: types::struct_kind,
+ fields: []types::struct_field,
+};
+
+type types::struct_field = struct {
+ name: str,
+ offs: size,
+ type_: type,
+};
+
+type types::tagged = []type;
+
+type types::tuple = []types::tuple_value;
+
+type types::tuple_value = struct {
+ offs: size,
+ type_: type,
};
export const @hidden builtin_char: types::typeinfo = types::typeinfo {
diff --git a/rt/types_arch+x86_64.ha b/rt/types_arch+x86_64.ha
@@ -26,4 +26,9 @@ export const @hidden builtin_int: types::typeinfo = types::typeinfo {
id = 2843771249,
sz = 8, al = 8, flags = 0,
repr = types::builtin::NULL,
+}, @hidden builtin_type: types::typeinfo = types::typeinfo {
+ // TODO: This type ID is wrong
+ id = 3181589295,
+ sz = 8, al = 8, flags = 0,
+ repr = types::builtin::TYPE,
};
diff --git a/src/gen.c b/src/gen.c
@@ -2514,7 +2514,6 @@ mktyperef(struct gen_context *ctx, const struct type *type)
switch (type->storage) {
case STORAGE_BOOL:
case STORAGE_CHAR:
- case STORAGE_ENUM:
case STORAGE_F32:
case STORAGE_F64:
case STORAGE_I16:
@@ -2525,7 +2524,8 @@ mktyperef(struct gen_context *ctx, const struct type *type)
case STORAGE_NULL:
case STORAGE_RUNE:
case STORAGE_SIZE:
- case STORAGE_TYPE: // TODO: Add me to builtins & audit
+ case STORAGE_STRING:
+ case STORAGE_TYPE:
case STORAGE_U16:
case STORAGE_U32:
case STORAGE_U64:
@@ -2552,10 +2552,10 @@ mktyperef(struct gen_context *ctx, const struct type *type)
.name = name,
};
case STORAGE_ARRAY:
+ case STORAGE_ENUM:
case STORAGE_FUNCTION:
case STORAGE_POINTER:
case STORAGE_SLICE:
- case STORAGE_STRING:
case STORAGE_STRUCT:
case STORAGE_TAGGED:
case STORAGE_TUPLE:
diff --git a/src/types.c b/src/types.c
@@ -575,8 +575,6 @@ type_is_assignable(const struct type *to, const struct type *from)
case STORAGE_ICONST:
case STORAGE_FCONST:
assert(0); // Invariant
- case STORAGE_TYPE:
- assert(0); // TODO
case STORAGE_I8:
case STORAGE_I16:
case STORAGE_I32:
@@ -677,8 +675,9 @@ type_is_assignable(const struct type *to, const struct type *from)
case STORAGE_RUNE:
case STORAGE_STRUCT:
case STORAGE_TUPLE:
- case STORAGE_UNION:
+ case STORAGE_TYPE:
case STORAGE_UINTPTR:
+ case STORAGE_UNION:
return false;
}
diff --git a/tests/13-tagged.ha b/tests/13-tagged.ha
@@ -20,19 +20,19 @@ fn storage() void = {
tag: uint,
union { _u8: u8, _u16: u16, _u32: u32, _u64: u64 },
};
- assert(y.tag == 3181589295); // u8 type ID
+ assert(y.tag == 1268499444); // u8 type ID
assert(y._u8 == 42);
x = 1337u16;
- assert(y.tag == 3481467866); // u16 type ID
+ assert(y.tag == 4119164483); // u16 type ID
assert(y._u16 == 1337);
x = 0xCAFEBABEu32;
- assert(y.tag == 1906196061); // u32 type ID
+ assert(y.tag == 3481467866); // u32 type ID
assert(y._u32 == 0xCAFEBABE);
x = 0xCAFEBABEDEADBEEFu64;
- assert(y.tag == 1268499444); // u64 type ID
+ assert(y.tag == 1906196061); // u64 type ID
assert(y._u64 == 0xCAFEBABEDEADBEEF);
};
@@ -97,9 +97,9 @@ fn membercast() void = {
id: uint,
data: int,
};
- assert(p.id == 3012680272);
+ assert(p.id == 3650376889);
x = 1337;
- assert(p.id == 1737287038);
+ assert(p.id == 461893804);
assert(p.data == 1337);
// Align of 4
@@ -111,7 +111,7 @@ fn membercast() void = {
fdata: f32,
},
};
- assert(p.id == 1737287038);
+ assert(p.id == 461893804);
assert(p.data.idata == 1337);
x = 13.37f32;
assert(p.id == 930681398);
@@ -123,7 +123,7 @@ fn membercast() void = {
id: uint,
data: size,
};
- assert(p.id == 4119164483);
+ assert(p.id == 2843771249);
assert(p.data == 1337z);
};
@@ -138,7 +138,7 @@ fn subsetcast() void = {
i: int,
},
};
- assert(p.tag == 4119164483);
+ assert(p.tag == 2843771249);
assert(p.data.z == 1337z);
// Disjoint alignment
@@ -151,7 +151,7 @@ fn subsetcast() void = {
i: int,
},
};
- assert(p.tag == 1737287038);
+ assert(p.tag == 461893804);
assert(p.data.i == 1337);
};
diff --git a/tests/18-match.ha b/tests/18-match.ha
@@ -1,3 +1,14 @@
+type foo = void;
+type bar = void;
+type foobar = (foo | bar);
+type baz = int;
+type foobarbaz = (foobar | baz);
+type signed = (i8 | i16 | i32 | i64 | int);
+type unsigned = (u8 | u16 | u32 | u64 | uint | size);
+type integer = (...signed | ...unsigned);
+type align_4 = (void | int);
+type align_8 = (void | int | i64);
+
fn tagged() void = {
let cases: [3](int | uint | str) = [10i, 10u, "hello"];
let expected: [_]size = [1, 2, 5];
@@ -62,10 +73,6 @@ fn pointer() void = {
assert(z == 1337);
};
-type foo = void;
-type bar = void;
-type foobar = (foo | bar);
-
fn alias() void = {
let cases: []foobar = [foo, bar];
let expected = [42, 24];
@@ -112,12 +119,6 @@ fn implicit_cast() void = {
assert(a is foobar);
};
-type foo = void;
-type bar = void;
-type foobar = (foo | bar);
-type baz = int;
-type foobarbaz = (foobar | baz);
-
fn transitivity() void = {
let x: (foobar | int) = 10;
match (x) {
@@ -187,11 +188,7 @@ fn transitivity() void = {
assert(visit);
};
-type signed = (i8 | i16 | i32 | i64 | int);
-type unsigned = (u8 | u16 | u32 | u64 | uint | size);
-type integer = (...signed | ...unsigned);
-
-export fn numeric() void = {
+fn numeric() void = {
// Real-world test
let visit = true;
let x: integer = 1337i;
@@ -210,10 +207,7 @@ export fn numeric() void = {
assert(visit);
};
-type align_4 = (void | int);
-type align_8 = (void | int | i64);
-
-export fn alignment_conversion() void = {
+fn alignment_conversion() void = {
let x: align_8 = 1234i;
match (x) {
case y: align_4 =>
diff --git a/tests/34-reflect.ha b/tests/34-reflect.ha
@@ -0,0 +1,52 @@
+use types;
+use types::{builtin};
+
+fn builtins() void = {
+ const cases: [_](type, size, size, builtin) = [
+ (type(u8), 1, 1, builtin::U8),
+ (type(u16), 2, 2, builtin::U16),
+ (type(u32), 4, 4, builtin::U32),
+ (type(u64), 8, 8, builtin::U64),
+ (type(i8), 1, 1, builtin::I8),
+ (type(i16), 2, 2, builtin::I16),
+ (type(i32), 4, 4, builtin::I32),
+ (type(i64), 8, 8, builtin::I64),
+ (type(f32), 4, 4, builtin::F32),
+ (type(f64), 8, 8, builtin::F64),
+ (type(rune), 4, 4, builtin::RUNE),
+ (type(char), 1, 1, builtin::CHAR),
+ (type(void), 0, 0, builtin::VOID),
+ (type(str), size(str), size(uintptr), builtin::STR),
+ (type(bool), size(uint), size(uint), builtin::BOOL),
+ (type(int), size(int), size(int), builtin::INT),
+ (type(uint), size(uint), size(uint), builtin::UINT),
+ (type(size), size(size), size(size), builtin::SIZE),
+ (type(uintptr), size(uintptr), size(uintptr), builtin::UINTPTR),
+ (type(type), size(type), size(type), builtin::TYPE), // so meta
+ ];
+ for (let i = 0z; i < len(cases); i += 1) {
+ const item = cases[i];
+ let t = types::reflect(item.0);
+ assert(t.sz == item.1);
+ assert(t.al == item.2);
+ let b = t.repr as builtin;
+ assert(b == item.3);
+ };
+};
+
+type alias = i32;
+
+fn aliases() void = {
+ let t = types::reflect(type(alias));
+ assert(t.sz == 4);
+ assert(t.al == 4);
+ let a = t.repr as types::alias;
+ assert(a.secondary == type(i32));
+ assert(len(a.ident) == 1);
+ assert(a.ident[0] == "alias");
+};
+
+export fn main() void = {
+ builtins();
+ aliases();
+};
diff --git a/tests/configure b/tests/configure
@@ -36,7 +36,8 @@ tests() {
29-unarithm \
31-postfix \
32-copy \
- 33-yield
+ 33-yield \
+ 34-reflect
do
cat <<EOF
tests/$t: libhart.a tests/$t.ha
diff --git a/types/Makefile b/types/Makefile
@@ -0,0 +1,15 @@
+types_srcs+=\
+ types/reflect.ha
+
+types/types.o: harec $(types_srcs)
+ @printf 'HAREC\t$@\n'
+ @mkdir -p $(HARECACHE)/types
+ @./harec -Ntypes -t$(HARECACHE)/types/types.td -o $@.ssa $(types_srcs)
+ @$(QBE) -o $@.s $@.ssa
+ @$(AS) -g -o $@ $@.s
+ @rm $@.s $@.ssa
+
+clean-types:
+ @rm -f types/types.o
+
+.PHONY: types clean-types
diff --git a/types/configure b/types/configure
@@ -0,0 +1,2 @@
+#!/bin/sh
+# no-op
diff --git a/types/reflect.ha b/types/reflect.ha
@@ -0,0 +1,119 @@
+// The sz field of [[typeinfo]] is set to this value to indicate that the size
+// of the type is undefined.
+export def SIZE_UNDEFINED: size = -1: size;
+
+// Structure detailing information about a specific type.
+export type typeinfo = struct {
+ id: uint,
+ sz: size,
+ al: size,
+ flags: flags,
+ repr: repr,
+};
+
+// Returns [[typeinfo]] for the provided type.
+export fn reflect(in: type) *typeinfo = in: *typeinfo;
+
+// Type flags.
+export type flags = enum u8 {
+ NONE = 0,
+ CONST = 1 << 0,
+ ERROR = 1 << 1,
+};
+
+// Details of the type representation.
+export type repr = (alias | array | builtin
+ | enum_ | func | pointer | slice_repr
+ | struct_union | tagged | tuple);
+
+// A type alias.
+export type alias = struct {
+ ident: []str,
+ secondary: type,
+};
+
+// An array type.
+export type array = struct {
+ length: size,
+ members: type,
+};
+
+// A built-in type.
+export type builtin = enum u8 {
+ BOOL, CHAR, F32, F64, I16, I32, I64, I8, INT, NULL, RUNE, SIZE, STR,
+ TYPE, U16, U32, U64, U8, UINT, UINTPTR, VOID,
+};
+
+// An enum type.
+export type enum_ = struct {
+ storage: builtin,
+ values: [](str, u64),
+};
+
+// Indicates the variadism of a [[func]].
+export type variadism = enum {
+ NONE,
+ C,
+ HARE,
+};
+
+// Indicats if a [[func]] has the @noreturn attribute.
+export type func_flags = enum uint {
+ NORETURN = 1 << 0,
+};
+
+// A function type, e.g. fn(x: int, y: int) int.
+export type func = struct {
+ result: type,
+ variadism: variadism,
+ flags: func_flags,
+ params: []type,
+};
+
+// Flags which apply to a pointer type.
+export type pointer_flags = enum u8 {
+ NONE = 0,
+ NULLABLE = 1 << 0,
+};
+
+// *int
+export type pointer = struct {
+ referent: type,
+ flags: pointer_flags,
+};
+
+// Type information for slice members. Distinct from [[slice]], which is the
+// representation of a slice object at runtime.
+export type slice_repr = type;
+
+// Indicates if a [[_struct]] was declared as a struct or union type.
+export type struct_kind = enum {
+ STRUCT,
+ UNION,
+};
+
+// struct { ... } or union { ... }
+export type struct_union = struct {
+ kind: struct_kind,
+ fields: []struct_field,
+};
+
+// A single struct field.
+export type struct_field = struct {
+ // "" for an anonymous field
+ name: str,
+ offs: size,
+ type_: type,
+};
+
+// A tagged union type, e.g. (int | uint | void).
+export type tagged = []type;
+
+// A tuple type, e.g. (a, b, c)
+export type tuple = []tuple_value;
+
+// A single value of a tuple type.
+export type tuple_value = struct {
+ offs: size,
+ type_: type,
+};