hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit e740ad87e1d2305fe67852c184cf856b67aebfc3
parent 46d0b88eff89c5b054e238f0c299ca99f5201338
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sun, 28 Mar 2021 12:38:04 -0400

rt: restructure +test per module conventions

Diffstat:
Mrt/+linux/abort.ha | 20+-------------------
Art/+test/run.ha | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Drt/+test/start.ha | 124-------------------------------------------------------------------------------
Rrt/+test/abort.ha -> rt/abort+test.ha | 0
Art/abort.ha | 21+++++++++++++++++++++
Art/start+test.ha | 22++++++++++++++++++++++
Mscripts/gen-stdlib | 8+++++---
Mstdlib.mk | 9++++++---
8 files changed, 163 insertions(+), 149 deletions(-)

diff --git a/rt/+linux/abort.ha b/rt/+linux/abort.ha @@ -1,25 +1,7 @@ -export @noreturn @symbol("rt.abort") fn _abort(msg: str) void = { +fn platform_abort(msg: str) void = { const prefix = "Abort: "; write(2, prefix: *const char, len(prefix)); write(2, msg: *const char, len(msg)); write(2, "\n": *const char, 1); kill(getpid(), SIGABRT); }; - -// See harec:include/gen.h -const reasons: [_]str = [ - "slice or array access out of bounds", // 0 - "type assertion failed", // 1 - "out of memory", // 2 -]; - -export @noreturn fn abort_fixed(loc: str, i: int) void = { - const prefix = "Abort: "; - const sep = ": "; - write(2, prefix: *const char, len(prefix)); - write(2, loc: *const char, len(loc)); - write(2, sep: *const char, len(sep)); - write(2, reasons[i]: *const char, len(reasons[i])); - write(2, "\n": *const char, 1); - kill(getpid(), SIGABRT); -}; diff --git a/rt/+test/run.ha b/rt/+test/run.ha @@ -0,0 +1,108 @@ +type test = struct { + name: str, + func: *fn() void, +}; + +type abort_reason = struct { + loc: str, + msg: str, +}; + +const @symbol("__test_array_start") test_start: [*]test; +const @symbol("__test_array_end") test_end: [*]test; + +let jmp: jmpbuf = jmpbuf { ... }; +let reason: abort_reason = abort_reason { ... }; + +export fn tests_main() size = { + const ntest = (&test_end: uintptr - &test_start: uintptr): size / size(test); + let maxname = 0z; + for (let i = 0z; i < ntest; i += 1) { + if (len(test_start[i].name) > maxname) { + maxname = len(test_start[i].name); + }; + }; + + let failures: [](str, abort_reason) = []; + let npass = 0z, nfail = 0z; + print("Running "); + print(ztos(ntest)); + print(" tests:\n\n"); + time_start(); + for (let i = 0z; i < ntest; i += 1) { + if (!should_test(test_start[i].name)) { + continue; + }; + print(test_start[i].name); + dots(maxname - len(test_start[i].name) + 3); + print(" "); + + if (setjmp(&jmp) != 0) { + nfail += 1; + append(failures, (test_start[i].name, reason)); + print("FAIL\n"); + continue; + }; + test_start[i].func(); + + npass += 1; + print("OK\n"); + }; + let end = time_stop(); + + if (nfail != 0) { + print("\n"); + print(ztos(nfail)); + if (nfail == 1) { + print(" test failed:\n"); + } else { + print(" tests failed:\n"); + }; + for (let i = 0z; i < nfail; i += 1) { + print(failures[i].0); + print(": "); + if (len(failures[i].1.loc) != 0) { + print(failures[i].1.loc); + print(": "); + }; + print(failures[i].1.msg); + print("\n"); + }; + }; + + print("\n"); + print(ztos(npass)); + print(" passed; "); + print(ztos(nfail)); + print(" failed; "); + print(ztos(ntest)); + print(" tests completed in "); + print(ztos(end.0)); + print("."); + print(ztos(end.1)); + print("s\n"); + + return nfail; +}; + +fn print(msg: str) void = write(1, msg: *const char, len(msg)); + +fn dots(n: size) void = { + // XXX: this is slow, I guess + for (let i = 0z; i < n; i += 1) { + print("."); + }; +}; + +fn should_test(name: str) bool = { + if (argc == 1) { + return true; + }; + for (let i = 1z; i < argc; i += 1) { + let s = from_c_unsafe(argv[i]); + if (name == s) { + return true; + }; + }; + return false; +}; diff --git a/rt/+test/start.ha b/rt/+test/start.ha @@ -1,124 +0,0 @@ -type test = struct { - name: str, - func: *fn() void, -}; - -type abort_reason = struct { - loc: str, - msg: str, -}; - -const @symbol("__init_array_start") init_start: [*]*fn() void; -const @symbol("__init_array_end") init_end: [*]*fn() void; -const @symbol("__fini_array_start") fini_start: [*]*fn() void; -const @symbol("__fini_array_end") fini_end: [*]*fn() void; -const @symbol("__test_array_start") test_start: [*]test; -const @symbol("__test_array_end") test_end: [*]test; - -let jmp: jmpbuf = jmpbuf { ... }; -let reason: abort_reason = abort_reason { ... }; - -export @noreturn fn start_ha() void = { - const ninit = (&init_end: uintptr - &init_start: uintptr): size - / size(*fn() void); - for (let i = 0z; i < ninit; i += 1) { - init_start[i](); - }; - - const ntest = (&test_end: uintptr - &test_start: uintptr): size / size(test); - let maxname = 0z; - for (let i = 0z; i < ntest; i += 1) { - if (len(test_start[i].name) > maxname) { - maxname = len(test_start[i].name); - }; - }; - - let failures: [](str, abort_reason) = []; - let npass = 0z, nfail = 0z; - print("Running "); - print(ztos(ntest)); - print(" tests:\n\n"); - time_start(); - for (let i = 0z; i < ntest; i += 1) { - if (!should_test(test_start[i].name)) { - continue; - }; - print(test_start[i].name); - dots(maxname - len(test_start[i].name) + 3); - print(" "); - - if (setjmp(&jmp) != 0) { - nfail += 1; - append(failures, (test_start[i].name, reason)); - print("FAIL\n"); - continue; - }; - test_start[i].func(); - - npass += 1; - print("OK\n"); - }; - let end = time_stop(); - - if (nfail != 0) { - print("\n"); - print(ztos(nfail)); - if (nfail == 1) { - print(" test failed:\n"); - } else { - print(" tests failed:\n"); - }; - for (let i = 0z; i < nfail; i += 1) { - print(failures[i].0); - print(": "); - if (len(failures[i].1.loc) != 0) { - print(failures[i].1.loc); - print(": "); - }; - print(failures[i].1.msg); - print("\n"); - }; - }; - - print("\n"); - print(ztos(npass)); - print(" passed; "); - print(ztos(nfail)); - print(" failed; "); - print(ztos(ntest)); - print(" tests completed in "); - print(ztos(end.0)); - print("."); - print(ztos(end.1)); - print("s\n"); - - const nfini = (&fini_end: uintptr - &fini_start: uintptr): size - / size(*fn() void); - for (let i = 0z; i < nfini; i += 1) { - fini_start[i](); - }; - - exit(if (nfail > 0) 1 else 0); -}; - -fn print(msg: str) void = write(1, msg: *const char, len(msg)); - -fn dots(n: size) void = { - // XXX: this is slow, I guess - for (let i = 0z; i < n; i += 1) { - print("."); - }; -}; - -fn should_test(name: str) bool = { - if (argc == 1) { - return true; - }; - for (let i = 1z; i < argc; i += 1) { - let s = from_c_unsafe(argv[i]); - if (name == s) { - return true; - }; - }; - return false; -}; diff --git a/rt/+test/abort.ha b/rt/abort+test.ha diff --git a/rt/abort.ha b/rt/abort.ha @@ -0,0 +1,21 @@ +export @noreturn @symbol("rt.abort") fn _abort(msg: str) void = { + platform_abort(msg); +}; + +// See harec:include/gen.h +const reasons: [_]str = [ + "slice or array access out of bounds", // 0 + "type assertion failed", // 1 + "out of memory", // 2 +]; + +export @noreturn fn abort_fixed(loc: str, i: int) void = { + const prefix = "Abort: "; + const sep = ": "; + write(2, prefix: *const char, len(prefix)); + write(2, loc: *const char, len(loc)); + write(2, sep: *const char, len(sep)); + write(2, reasons[i]: *const char, len(reasons[i])); + write(2, "\n": *const char, 1); + kill(getpid(), SIGABRT); +}; diff --git a/rt/start+test.ha b/rt/start+test.ha @@ -0,0 +1,22 @@ +const @symbol("__init_array_start") init_start: [*]*fn() void; +const @symbol("__init_array_end") init_end: [*]*fn() void; +const @symbol("__fini_array_start") fini_start: [*]*fn() void; +const @symbol("__fini_array_end") fini_end: [*]*fn() void; + +export @noreturn fn start_ha() void = { + const ninit = (&init_end: uintptr - &init_start: uintptr): size + / size(*fn() void); + for (let i = 0z; i < ninit; i += 1) { + init_start[i](); + }; + + let nfail = tests_main(); + + const nfini = (&fini_end: uintptr - &fini_start: uintptr): size + / size(*fn() void); + for (let i = 0z; i < nfini; i += 1) { + fini_start[i](); + }; + + exit(if (nfail > 0) 1 else 0); +}; diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib @@ -16,6 +16,7 @@ eval ". $srcdir/gen-stdlib.sh" gensrcs_rt() { gen_srcs rt \ + '$(PLATFORM)/abort.ha' \ '$(PLATFORM)/env.ha' \ '$(PLATFORM)/errno.ha' \ '$(PLATFORM)/types.ha' \ @@ -44,14 +45,15 @@ rt() { then printf '%s\n' 'rtscript=$(STDLIB)/rt/hare.sc' gensrcs_rt \ - '$(PLATFORM)/abort.ha' \ + abort.ha \ start.ha else gensrcs_rt \ + start+test.ha \ + abort+test.ha \ '+test/$(PLATFORM).ha' \ - +test/abort.ha \ +test/cstring.ha \ - +test/start.ha \ + +test/run.ha \ +test/ztos.ha fi gen_ssa rt diff --git a/stdlib.mk b/stdlib.mk @@ -3,6 +3,7 @@ # rt rtscript=$(STDLIB)/rt/hare.sc stdlib_rt_srcs= \ + $(STDLIB)/rt/$(PLATFORM)/abort.ha \ $(STDLIB)/rt/$(PLATFORM)/env.ha \ $(STDLIB)/rt/$(PLATFORM)/errno.ha \ $(STDLIB)/rt/$(PLATFORM)/types.ha \ @@ -21,7 +22,7 @@ stdlib_rt_srcs= \ $(STDLIB)/rt/memcpy.ha \ $(STDLIB)/rt/memset.ha \ $(STDLIB)/rt/strcmp.ha \ - $(STDLIB)/rt/$(PLATFORM)/abort.ha \ + $(STDLIB)/rt/abort.ha \ $(STDLIB)/rt/start.ha $(HARECACHE)/rt/rt.ssa: $(stdlib_rt_srcs) $(stdlib_rt) @@ -688,6 +689,7 @@ $(HARECACHE)/uuid/uuid.ssa: $(stdlib_uuid_srcs) $(stdlib_rt) $(stdlib_crypto_ran # rt testlib_rt_srcs= \ + $(STDLIB)/rt/$(PLATFORM)/abort.ha \ $(STDLIB)/rt/$(PLATFORM)/env.ha \ $(STDLIB)/rt/$(PLATFORM)/errno.ha \ $(STDLIB)/rt/$(PLATFORM)/types.ha \ @@ -706,10 +708,11 @@ testlib_rt_srcs= \ $(STDLIB)/rt/memcpy.ha \ $(STDLIB)/rt/memset.ha \ $(STDLIB)/rt/strcmp.ha \ + $(STDLIB)/rt/start+test.ha \ + $(STDLIB)/rt/abort+test.ha \ $(STDLIB)/rt/+test/$(PLATFORM).ha \ - $(STDLIB)/rt/+test/abort.ha \ $(STDLIB)/rt/+test/cstring.ha \ - $(STDLIB)/rt/+test/start.ha \ + $(STDLIB)/rt/+test/run.ha \ $(STDLIB)/rt/+test/ztos.ha $(TESTCACHE)/rt/rt.ssa: $(testlib_rt_srcs) $(testlib_rt)