harec

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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:
MMakefile | 1+
Mconfig.sh | 1+
Mconfigure | 1+
Mrt/Makefile | 6+++---
Mrt/types.ha | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mrt/types_arch+x86_64.ha | 5+++++
Msrc/gen.c | 6+++---
Msrc/types.c | 5++---
Mtests/13-tagged.ha | 20++++++++++----------
Mtests/18-match.ha | 32+++++++++++++-------------------
Atests/34-reflect.ha | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtests/configure | 3++-
Atypes/Makefile | 15+++++++++++++++
Atypes/configure | 2++
Atypes/reflect.ha | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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, +};