commit 917811557f5bc72a128b8d9f104a0774b34ea3b2
parent 11711a528c4ec4f17a4e6ea64f3215bb0e3c87f5
Author: Bor Grošelj Simić <bgs@turminal.net>
Date: Thu, 25 Aug 2022 01:26:52 +0200
tests: detect signal-induced exit
Previous checks for rt::compile return value succeeded in cases harec
exited with SIGABRT or SIGSEGV and that resulted in masked bugs on
multiple occasions.
Signed-off-by: Bor Grošelj Simić <bgs@turminal.net>
Diffstat:
19 files changed, 251 insertions(+), 242 deletions(-)
diff --git a/rt/compile.ha b/rt/compile.ha
@@ -1,5 +1,8 @@
+export type exited = int, signaled = int;
+export type exit_status = (exited | signaled);
+
// Runs the Hare compiler and returns the exit status.
-export fn compile(src: const str) int = {
+export fn compile(src: const str) exit_status = {
let status = 0;
let pipefd = [-1, -1];
assert(pipe2(&pipefd, 0) == 0);
@@ -38,7 +41,7 @@ export fn compile(src: const str) int = {
wait4(child, &status, 0, null);
};
- return if (wifexited(status)) wexitstatus(status)
- else if (wifsignaled(status)) wtermsig(status)
+ return if (wifexited(status)) wexitstatus(status): exited
+ else if (wifsignaled(status)) wtermsig(status): signaled
else abort();
};
diff --git a/tests/00-constants.ha b/tests/00-constants.ha
@@ -1,4 +1,4 @@
-use rt;
+use rt::{compile, exited, EXIT_SUCCESS};
type my_enum = enum u8 {
FOO,
@@ -34,61 +34,61 @@ fn assignment() void = {
let rtu3: (rune | u64 | void) = void;
i = 127;
- assert(rt::compile("export fn main() void = { let i = 0i8; i = 128; };") != 0);
+ assert(compile("export fn main() void = { let i = 0i8; i = 128; };") as exited != EXIT_SUCCESS);
u = 18446744073709551615;
- assert(rt::compile("export fn main() void = { let u = 0u32; u = 4294967296; };") != 0);
- assert(rt::compile("export fn main() void = { let f = 0.0f64; f = 0; };") != 0);
- assert(rt::compile("export fn main() void = { let r = 'a'; r = 0; };") != 0);
+ assert(compile("export fn main() void = { let u = 0u32; u = 4294967296; };") as exited != EXIT_SUCCESS);
+ assert(compile("export fn main() void = { let f = 0.0f64; f = 0; };") as exited != EXIT_SUCCESS);
+ assert(compile("export fn main() void = { let r = 'a'; r = 0; };") as exited != EXIT_SUCCESS);
e = 0;
- assert(rt::compile("type my_enum = enum u8 { FOO }; export fn main() void = { let e: my_enum = my_enum::FOO; e = 256; };") != 0);
- assert(rt::compile("export fn main() void = { let p: nullable *void = null; p = 0; };") != 0);
- assert(rt::compile("export fn main() void = { let b = false; b = 0; };") != 0);
- assert(rt::compile("export fn main() void = { let n = null; n = 0; };") != 0);
- assert(rt::compile("export fn main() void = { let s: struct { i: int } = struct { i: int = 0 }; s = 0; };") != 0);
- assert(rt::compile("export fn main() void = { let t = (0, 1); t = 0; };") != 0);
- assert(rt::compile("export fn main() void = { let a = [0, 1]; a = 0; };") != 0);
- assert(rt::compile("export fn main() void = { let s = \"\"; s = 0; };") != 0);
+ assert(compile("type my_enum = enum u8 { FOO }; export fn main() void = { let e: my_enum = my_enum::FOO; e = 256; };") as exited != EXIT_SUCCESS);
+ assert(compile("export fn main() void = { let p: nullable *void = null; p = 0; };") as exited != EXIT_SUCCESS);
+ assert(compile("export fn main() void = { let b = false; b = 0; };") as exited != EXIT_SUCCESS);
+ assert(compile("export fn main() void = { let n = null; n = 0; };") as exited != EXIT_SUCCESS);
+ assert(compile("export fn main() void = { let s: struct { i: int } = struct { i: int = 0 }; s = 0; };") as exited != EXIT_SUCCESS);
+ assert(compile("export fn main() void = { let t = (0, 1); t = 0; };") as exited != EXIT_SUCCESS);
+ assert(compile("export fn main() void = { let a = [0, 1]; a = 0; };") as exited != EXIT_SUCCESS);
+ assert(compile("export fn main() void = { let s = \"\"; s = 0; };") as exited != EXIT_SUCCESS);
itu1 = 0;
itu2 = 0;
itu3 = 0;
- assert(rt::compile("export fn main() void = { let itu4: (u32 | u64 | void) = void; itu4 = 0; };") != 0);
- assert(rt::compile("export fn main() void = { let itu5: (str | void) = void; itu5 = 0; };") != 0);
+ assert(compile("export fn main() void = { let itu4: (u32 | u64 | void) = void; itu4 = 0; };") as exited != EXIT_SUCCESS);
+ assert(compile("export fn main() void = { let itu5: (str | void) = void; itu5 = 0; };") as exited != EXIT_SUCCESS);
- assert(rt::compile("export fn main() void = { let i = 0i8; i = 0.0; };") != 0);
- assert(rt::compile("export fn main() void = { let u = 0u8; u = 0.0; };") != 0);
+ assert(compile("export fn main() void = { let i = 0i8; i = 0.0; };") as exited != EXIT_SUCCESS);
+ assert(compile("export fn main() void = { let u = 0u8; u = 0.0; };") as exited != EXIT_SUCCESS);
f = 0.0;
- assert(rt::compile("export fn main() void = { let r = 'a'; r = 0.0; };") != 0);
- assert(rt::compile("type my_enum = enum u8 { FOO }; export fn main() void = { let e: my_enum = my_enum::FOO; e = 0.0; };") != 0);
- assert(rt::compile("export fn main() void = { let p: nullable *void = null; p = 0.0; };") != 0);
- assert(rt::compile("export fn main() void = { let b = false; b = 0.0; };") != 0);
- assert(rt::compile("export fn main() void = { let n = null; n = 0.0; };") != 0);
- assert(rt::compile("export fn main() void = { let s: struct { i: int } = struct { i: int = 0 }; s = 0.0; };") != 0);
- assert(rt::compile("export fn main() void = { let t = (0, 1); t = 0.0; };") != 0);
- assert(rt::compile("export fn main() void = { let a = [0, 1]; a = 0.0; };") != 0);
- assert(rt::compile("export fn main() void = { let s = ""; s = 0.0; };") != 0);
+ assert(compile("export fn main() void = { let r = 'a'; r = 0.0; };") as exited != EXIT_SUCCESS);
+ assert(compile("type my_enum = enum u8 { FOO }; export fn main() void = { let e: my_enum = my_enum::FOO; e = 0.0; };") as exited != EXIT_SUCCESS);
+ assert(compile("export fn main() void = { let p: nullable *void = null; p = 0.0; };") as exited != EXIT_SUCCESS);
+ assert(compile("export fn main() void = { let b = false; b = 0.0; };") as exited != EXIT_SUCCESS);
+ assert(compile("export fn main() void = { let n = null; n = 0.0; };") as exited != EXIT_SUCCESS);
+ assert(compile("export fn main() void = { let s: struct { i: int } = struct { i: int = 0 }; s = 0.0; };") as exited != EXIT_SUCCESS);
+ assert(compile("export fn main() void = { let t = (0, 1); t = 0.0; };") as exited != EXIT_SUCCESS);
+ assert(compile("export fn main() void = { let a = [0, 1]; a = 0.0; };") as exited != EXIT_SUCCESS);
+ assert(compile("export fn main() void = { let s = ""; s = 0.0; };") as exited != EXIT_SUCCESS);
ftu1 = 0.0;
ftu2 = 0.0;
ftu3 = 0.0;
- assert(rt::compile("type my_f32 = f32; export fn main() void = { let ftu4: (f32 | my_f32 | void) = void; ftu4 = 0.0; };") != 0);
- assert(rt::compile("export fn main() void = { let ftu5: (str | void) = void; ftu5 = 0.0; };") != 0);
+ assert(compile("type my_f32 = f32; export fn main() void = { let ftu4: (f32 | my_f32 | void) = void; ftu4 = 0.0; };") as exited != EXIT_SUCCESS);
+ assert(compile("export fn main() void = { let ftu5: (str | void) = void; ftu5 = 0.0; };") as exited != EXIT_SUCCESS);
i = 'a';
u = 'a';
- assert(rt::compile("export fn main() void = { let f = 0.0f64; f = 'a'; };") != 0);
+ assert(compile("export fn main() void = { let f = 0.0f64; f = 'a'; };") as exited != EXIT_SUCCESS);
r = 'a';
e = 'a';
- assert(rt::compile("export fn main() void = { let p: nullable *void = null; p = 'a'; };") != 0);
- assert(rt::compile("export fn main() void = { let b = false; b = 'a'; };") != 0);
- assert(rt::compile("export fn main() void = { let n = null; n = 'a'; };") != 0);
- assert(rt::compile("export fn main() void = { let s: struct { i: int } = struct { i: int = 0 }; s = 'a'; };") != 0);
- assert(rt::compile("export fn main() void = { let t = (0, 1); t = 'a'; };") != 0);
- assert(rt::compile("export fn main() void = { let a = [0, 1]; a = 'a'; };") != 0);
- assert(rt::compile("export fn main() void = { let s = ""; s = 'a'; };") != 0);
+ assert(compile("export fn main() void = { let p: nullable *void = null; p = 'a'; };") as exited != EXIT_SUCCESS);
+ assert(compile("export fn main() void = { let b = false; b = 'a'; };") as exited != EXIT_SUCCESS);
+ assert(compile("export fn main() void = { let n = null; n = 'a'; };") as exited != EXIT_SUCCESS);
+ assert(compile("export fn main() void = { let s: struct { i: int } = struct { i: int = 0 }; s = 'a'; };") as exited != EXIT_SUCCESS);
+ assert(compile("export fn main() void = { let t = (0, 1); t = 'a'; };") as exited != EXIT_SUCCESS);
+ assert(compile("export fn main() void = { let a = [0, 1]; a = 'a'; };") as exited != EXIT_SUCCESS);
+ assert(compile("export fn main() void = { let s = ""; s = 'a'; };") as exited != EXIT_SUCCESS);
rtu1 = 'a';
rtu2 = 'a';
rtu3 = 'a';
- assert(rt::compile("export fn main() void = { let rtu4: (u32 | u64 | void) = void; rtu4 = 'a'; };") != 0);
- assert(rt::compile("export fn main() void = { let rtu5: (str | void) = void; rtu5 = 'a'; };") != 0);
+ assert(compile("export fn main() void = { let rtu4: (u32 | u64 | void) = void; rtu4 = 'a'; };") as exited != EXIT_SUCCESS);
+ assert(compile("export fn main() void = { let rtu5: (str | void) = void; rtu5 = 'a'; };") as exited != EXIT_SUCCESS);
};
fn aggregates() void = {
diff --git a/tests/01-arrays.ha b/tests/01-arrays.ha
@@ -1,4 +1,4 @@
-use rt;
+use rt::{compile, exited, EXIT_SUCCESS};
fn indexing() void = {
let x = [1, 2, 3];
@@ -50,7 +50,7 @@ fn assignment() void = {
assert(y[0] == 1 && y[1] == 2 && y[2] == 3);
assert(z[0] == 1 && z[1] == 2 && z[2] == 3);
- assert(rt::compile("
+ assert(compile("
export fn main() void = {
let a: [3]uint = [1u,2u,3u];
let b: uint = 0;
@@ -58,15 +58,15 @@ fn assignment() void = {
let ptr: *[3]uint = &a;
ptr = &b;
};
- ") != 0);
+ ") as exited != EXIT_SUCCESS);
- assert(rt::compile(`
+ assert(compile(`
export fn main() void = {
let a: *[*]uint = &[1u,2u,3u];
let b: [3]str = ["a", "b", "c"];
a = &b;
};
- `) != 0);
+ `) as exited != EXIT_SUCCESS);
};
fn param(x: [3]int) void = {
diff --git a/tests/03-pointers.ha b/tests/03-pointers.ha
@@ -1,4 +1,4 @@
-use rt;
+use rt::{compile, exited, EXIT_SUCCESS};
type intp = *int;
@@ -17,9 +17,9 @@ fn _nullable() void = {
x = &y;
assert(*(x: *int) == 42);
- assert(rt::compile(
+ assert(compile(
"fn test() void = { let x: nullable *int = null; let z = *x; };",
- ) != 0);
+ ) as exited != EXIT_SUCCESS);
};
fn casts() void = {
@@ -48,67 +48,67 @@ fn casts() void = {
};
fn reject() void = {
- assert(rt::compile("
+ assert(compile("
type s = null;
fn test() void = {
void;
};
- ") != 0);
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS);
+ assert(compile("
type s = *null;
fn test() void = {
void;
};
- ") != 0);
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS);
+ assert(compile("
fn test() void = {
let a = &null;
};
- ") != 0);
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS);
+ assert(compile("
fn test() void = {
let a = &3: null;
};
- ") != 0);
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS);
+ assert(compile("
fn test() void = {
let b: nullable *int = null;
let a = b as null;
};
- ") != 0);
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS);
+ assert(compile("
fn test() void = {
let a = (null, 3);
};
- ") != 0);
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS);
+ assert(compile("
fn test() void = {
let a: []null = [null];
};
- ") != 0);
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS);
+ assert(compile("
fn test() void = {
let a = [null];
};
- ") != 0);
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS);
+ assert(compile("
fn test() void = {
let a: [_]null = [null];
};
- ") != 0);
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS);
+ assert(compile("
fn test() void = {
let a = null;
};
- ") != 0);
+ ") as exited != EXIT_SUCCESS);
// type assertions on non-nullable pointers are prohibited
- assert(rt::compile("
+ assert(compile("
fn test() void = {
let a: *int = &4;
assert(a as *int);
};
- ") != 0);
+ ") as exited != EXIT_SUCCESS);
};
export fn main() void = {
diff --git a/tests/05-implicit-casts.ha b/tests/05-implicit-casts.ha
@@ -1,4 +1,4 @@
-use rt;
+use rt::{compile, exited, EXIT_SUCCESS};
type subtype = struct {
foo: int,
@@ -44,7 +44,7 @@ fn rules() void = {
// Implementation-defined precision
if (size(int) == 8) {
- assert(rt::compile("fn test() void = { let i: int = 42i64; };") == 0);
+ assert(compile("fn test() void = { let i: int = 42i64; };") as exited == EXIT_SUCCESS);
};
let i: int = 42i;
i = 42i32;
@@ -52,7 +52,7 @@ fn rules() void = {
i = 42i8;
if (size(uint) == 8) {
- assert(rt::compile("fn test() void = { let u: uint = 42u64; };") == 0);
+ assert(compile("fn test() void = { let u: uint = 42u64; };") as exited == EXIT_SUCCESS);
};
let u: uint = 42u;
u = 42u32;
@@ -60,20 +60,20 @@ fn rules() void = {
u = 42u8;
// Precision loss (should fail)
- assert(rt::compile("fn test() void = { let _i8: i8 = 42i16; };") != 0);
- assert(rt::compile("fn test() void = { let _i8: i8 = 42i32; };") != 0);
- assert(rt::compile("fn test() void = { let _i8: i8 = 42i64; };") != 0);
- assert(rt::compile("fn test() void = { let _i8: i8 = 42i; };") != 0);
- assert(rt::compile("fn test() void = { let _i16: i16 = 42i32; };") != 0);
- assert(rt::compile("fn test() void = { let _i16: i16 = 42i64; };") != 0);
- assert(rt::compile("fn test() void = { let _i32: i32 = 42i64; };") != 0);
- assert(rt::compile("fn test() void = { let _u8: u8 = 42u16; };") != 0);
- assert(rt::compile("fn test() void = { let _u8: u8 = 42u32; };") != 0);
- assert(rt::compile("fn test() void = { let _u8: u8 = 42u64; };") != 0);
- assert(rt::compile("fn test() void = { let _u8: u8 = 42u; };") != 0);
- assert(rt::compile("fn test() void = { let _u16: u16 = 42u32; };") != 0);
- assert(rt::compile("fn test() void = { let _u16: u16 = 42u64; };") != 0);
- assert(rt::compile("fn test() void = { let _u32: u32 = 42u64; };") != 0);
+ assert(compile("fn test() void = { let _i8: i8 = 42i16; };") as exited != EXIT_SUCCESS);
+ assert(compile("fn test() void = { let _i8: i8 = 42i32; };") as exited != EXIT_SUCCESS);
+ assert(compile("fn test() void = { let _i8: i8 = 42i64; };") as exited != EXIT_SUCCESS);
+ assert(compile("fn test() void = { let _i8: i8 = 42i; };") as exited != EXIT_SUCCESS);
+ assert(compile("fn test() void = { let _i16: i16 = 42i32; };") as exited != EXIT_SUCCESS);
+ assert(compile("fn test() void = { let _i16: i16 = 42i64; };") as exited != EXIT_SUCCESS);
+ assert(compile("fn test() void = { let _i32: i32 = 42i64; };") as exited != EXIT_SUCCESS);
+ assert(compile("fn test() void = { let _u8: u8 = 42u16; };") as exited != EXIT_SUCCESS);
+ assert(compile("fn test() void = { let _u8: u8 = 42u32; };") as exited != EXIT_SUCCESS);
+ assert(compile("fn test() void = { let _u8: u8 = 42u64; };") as exited != EXIT_SUCCESS);
+ assert(compile("fn test() void = { let _u8: u8 = 42u; };") as exited != EXIT_SUCCESS);
+ assert(compile("fn test() void = { let _u16: u16 = 42u32; };") as exited != EXIT_SUCCESS);
+ assert(compile("fn test() void = { let _u16: u16 = 42u64; };") as exited != EXIT_SUCCESS);
+ assert(compile("fn test() void = { let _u32: u32 = 42u64; };") as exited != EXIT_SUCCESS);
// Pointer conversions
let cchr: *const char = "hello world";
@@ -87,12 +87,12 @@ fn rules() void = {
let sptr: *struct { foo: int } = &super3 { ... };
// Invalid pointer conversions
- assert(rt::compile(
+ assert(compile(
"fn test() void = { let x: nullable *int = null; let y: *int = x; };"
- ) != 0);
- assert(rt::compile(
+ ) as exited != EXIT_SUCCESS);
+ assert(compile(
"fn test() void = { let x: int = 10; let y: *int = &x; let y: *uint = x; };"
- ) != 0);
+ ) as exited != EXIT_SUCCESS);
// Non-const from const (copy)
const j = 10;
diff --git a/tests/06-structs.ha b/tests/06-structs.ha
@@ -1,4 +1,4 @@
-use rt;
+use rt::{compile, exited, EXIT_SUCCESS};
fn padding() void = {
assert(size(struct { x: i32, y: i32 }) == 8);
@@ -183,7 +183,7 @@ fn invariants() void = {
"type s = struct { x: void, a: str };"
];
for (let i = 0z; i < len(failures); i += 1) {
- assert(rt::compile(failures[i]) != 0);
+ assert(compile(failures[i]) as exited != EXIT_SUCCESS);
};
};
diff --git a/tests/08-slices.ha b/tests/08-slices.ha
@@ -1,4 +1,4 @@
-use rt;
+use rt::{compile, exited, EXIT_SUCCESS};
fn from_array() void = {
let src = [1, 2, 3];
@@ -55,12 +55,12 @@ fn measurements() void = {
fn indexing() void = {
let x = [1, 3, 3, 7];
assert(x[0] == 1 && x[1] == 3 && x[2] == 3 && x[3] == 7);
- assert(rt::compile(
+ assert(compile(
"fn test() void = { let x: []int = [1, 2, 3]; x[\"hello\"]; };"
- ) != 0, "non-numeric index");
- assert(rt::compile(
+ ) as exited != EXIT_SUCCESS);
+ assert(compile(
"fn test() void = { let x = 10; x[10]; };"
- ) != 0, "indexing non-array, non-slice object");
+ ) as exited != EXIT_SUCCESS);
};
fn zero3(s: []int) void = {
@@ -90,9 +90,9 @@ fn assignment() void = {
assert(z[0] == 1 && z[1] == 42 && z[2] == 69 && z[3] == 1337 && z[4] == 5);
z[2..5] = y;
assert(z[0] == 1 && z[1] == 42 && z[2] == 0 && z[3] == 0 && z[4] == 0);
- assert(rt::compile(
+ assert(compile(
"export fn main() void = { let a: []int = [1]; a[..] += a; };"
- ) != 0, "binop slice assignment");
+ ) as exited != EXIT_SUCCESS);
};
fn assert_slice_eq(actual: []int, expected: []int) void = {
@@ -124,12 +124,12 @@ fn slicing() void = {
assert_slice_eq(p[1..], [2, 3, 4, 5]);
assert_slice_eq(p[5..], []);
- assert(rt::compile(
+ assert(compile(
"fn test() void = { let x = \"test\"; x[1..3]; };"
- ) != 0, "slicing non-array, non-slice object");
- assert(rt::compile(
+ ) as exited != EXIT_SUCCESS);
+ assert(compile(
"fn test() void = { let x = [1, 2, 3]; x[\"hi\"..]; };"
- ) != 0, "slicing object with non-array, non-slice range");
+ ) as exited != EXIT_SUCCESS);
};
type tree = struct {
@@ -138,7 +138,7 @@ type tree = struct {
};
fn sum_tree(t: tree) u64 = {
- let sum = t.value;
+ let sum = t.value;
for (let i = 0z; i < len(t.children); i += 1) {
sum += sum_tree(t.children[i]);
};
diff --git a/tests/09-funcs.ha b/tests/09-funcs.ha
@@ -1,4 +1,4 @@
-use rt;
+use rt::{compile, exit, exited, EXIT_SUCCESS};
fn simple() int = return 69;
@@ -43,7 +43,7 @@ let x: int = 42;
};
@fini fn fini() void = {
- rt::exit(42); // Magic number
+ exit(42); // Magic number
};
@fini fn fini() void = {
@@ -80,7 +80,7 @@ fn reject() void = {
];
for (let i = 0z; i < len(failures); i += 1) {
- assert(rt::compile(failures[i]) != 0);
+ assert(compile(failures[i]) as exited != EXIT_SUCCESS);
};
};
diff --git a/tests/11-globals.ha b/tests/11-globals.ha
@@ -1,4 +1,4 @@
-use rt;
+use rt::{compile, exited, EXIT_SUCCESS};
let x: int = 42, y: int = 69;
@@ -58,8 +58,8 @@ fn storage() void = {
};
fn invariants() void = {
- assert(rt::compile("fn test() int; let x: int = test();") != 0);
- assert(rt::compile("const a: u8 = 2; const b: u8 = a + 5;") != 0);
+ assert(compile("fn test() int; let x: int = test();") as exited != EXIT_SUCCESS);
+ assert(compile("const a: u8 = 2; const b: u8 = a + 5;") as exited != EXIT_SUCCESS);
};
fn counter() int = {
diff --git a/tests/12-loops.ha b/tests/12-loops.ha
@@ -1,4 +1,4 @@
-use rt;
+use rt::{compile, exited, EXIT_SUCCESS};
fn scope() void = {
let x = 0;
@@ -9,7 +9,7 @@ fn scope() void = {
break;
};
};
- assert(rt::compile("fn test() void = { for (true) { let x = 10; }; x; };") != 0);
+ assert(compile("fn test() void = { for (true) { let x = 10; }; x; };") as exited != EXIT_SUCCESS);
// To make sure that the afterthought is part of the loop's scope
for (let i = 0; true; (if (true) { break; })) true;
};
@@ -91,10 +91,10 @@ fn label() void = {
};
};
assert(i == 8);
- assert(rt::compile("fn test() void = { :foo for (true) { break :bar; }; };") != 0);
- assert(rt::compile("fn test() void = { for (true) { break :bar; }; };") != 0);
- assert(rt::compile("fn test() void = { break :bar; };") != 0);
- assert(rt::compile("fn test() void = { :foo for (true) { :foo for (true) void; } ; };") != 0);
+ assert(compile("fn test() void = { :foo for (true) { break :bar; }; };") as exited != EXIT_SUCCESS);
+ assert(compile("fn test() void = { for (true) { break :bar; }; };") as exited != EXIT_SUCCESS);
+ assert(compile("fn test() void = { break :bar; };") as exited != EXIT_SUCCESS);
+ assert(compile("fn test() void = { :foo for (true) { :foo for (true) void; } ; };") as exited != EXIT_SUCCESS);
};
type abool = bool;
diff --git a/tests/13-tagged.ha b/tests/13-tagged.ha
@@ -1,4 +1,4 @@
-use rt;
+use rt::{compile, exited, EXIT_SUCCESS};
fn measurements() void = {
const x: (u8 | u16 | u32 | u64) = 1337u16; // With padding
@@ -56,19 +56,19 @@ fn reduction() void = {
const b: (i16 | i8) = a;
const c: (i8 | i16 | i32) = a;
const d: (i8 | i16 | i8 | i16) = a;
- assert(rt::compile(
+ assert(compile(
// Cannot reduce to a single member
"fn test() void = {
let a: (u8 | u8) = 42u8;
};"
- ) != 0);
- assert(rt::compile(
+ ) as exited != EXIT_SUCCESS);
+ assert(compile(
// Cannot assign from more general type
"fn test() void = {
let a: (i8 | i16 | i32) = 42i8;
let b: (i8 | i16) = a;
};"
- ) != 0);
+ ) as exited != EXIT_SUCCESS);
assert(a is i8 && b is i8 && c is i8 && d is i8);
assert(size((i8 | i16 | i32)) == size((i8 | (i16 | i32))));
assert(size(integer) == size(signed));
@@ -191,50 +191,50 @@ fn assertions() void = {
fn reject() void = {
// cannot type assert into a disjoint tagged type
- assert(rt::compile(
+ assert(compile(
"fn test() void = {
let a: (u8 | u16) = 42u8;
let b = a as (str | void);
};"
- ) != 0);
+ ) as exited != EXIT_SUCCESS);
// cannot type assert into non-member type
- assert(rt::compile(
+ assert(compile(
"fn test() void = {
let a: (u8 | u16) = 42u8;
let b = a as *str;
};"
- ) != 0);
+ ) as exited != EXIT_SUCCESS);
// cannot type assert into superset
- assert(rt::compile(
+ assert(compile(
"fn test() void = {
let a: (u8 | u16) = 42u8;
let b = a as (u8 | u16 | void);
};"
- ) != 0);
+ ) as exited != EXIT_SUCCESS);
// cannot type assert into the same type
- assert(rt::compile(
+ assert(compile(
"fn test() void = {
let a: (u8 | u16) = 42u8;
let b = a as (u8 | u16);
};"
- ) != 0);
+ ) as exited != EXIT_SUCCESS);
// cannot have members of undefined size
- assert(rt::compile(
+ assert(compile(
"fn test() (void | [*]int) = {
void;
};"
- ) != 0);
+ ) as exited != EXIT_SUCCESS);
// cannot have <2 members
- assert(rt::compile(
+ assert(compile(
"fn test() (void | void) = {
void;
};"
- ) != 0);
+ ) as exited != EXIT_SUCCESS);
};
export fn main() void = {
diff --git a/tests/15-enums.ha b/tests/15-enums.ha
@@ -1,4 +1,4 @@
-use rt;
+use rt::{compile, exited, EXIT_SUCCESS};
use testmod;
type implicit_values = enum {
@@ -68,21 +68,21 @@ fn storage() void = {
fn reject() void = {
// enum type definition used outside type declaration
- assert(rt::compile("export let a: enum { A, B } = 0;") != 0);
- assert(rt::compile("export let a: int = 0: enum{A, B}: int;") != 0);
+ assert(compile("export let a: enum { A, B } = 0;") as exited != EXIT_SUCCESS);
+ assert(compile("export let a: int = 0: enum{A, B}: int;") as exited != EXIT_SUCCESS);
// enum circular dependencies
- assert(rt::compile("type a = enum { A = B, B = A };") != 0);
- assert(rt::compile("type a = enum { A = b::B },
- b = enum { B = a::A };") != 0);
- assert(rt::compile("
+ assert(compile("type a = enum { A = B, B = A };") as exited != EXIT_SUCCESS);
+ assert(compile("type a = enum { A = b::B },
+ b = enum { B = a::A };") as exited != EXIT_SUCCESS);
+ assert(compile("
def a: int = e::VAL1;
type e = enum { VAL1 = a };
- ") != 0);
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS);
+ assert(compile("
def a: int = e::VAL1;
type e = enum { VAL1 = VAL2, VAL2 = a };
- ") != 0);
+ ") as exited != EXIT_SUCCESS);
};
type interdependent1 = enum {
diff --git a/tests/19-append.ha b/tests/19-append.ha
@@ -1,4 +1,4 @@
-use rt;
+use rt::{compile, exited, EXIT_SUCCESS};
fn basics() void = {
let x: []int = [];
@@ -68,33 +68,33 @@ fn typehints() void = {
};
fn reject() void = {
- assert(rt::compile("
+ assert(compile("
let x: []u8 = [0u8];
let y: int = 42;
append(x, y);
- ") != 0); // object member type != value type
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS); // object member type != value type
+ assert(compile("
let x: []u8 = [0u8];
let y = 42u8;
append(x, y...);
- ") != 0); // value is not an array or a slice
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS); // value is not an array or a slice
+ assert(compile("
let x: []u8 = [0u8];
let y: []int = [42];
append(x, y...);
- ") != 0); // object member type != value member type
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS); // object member type != value member type
+ assert(compile("
let x: []u8 = [0u8];
append(x, [42i...], 5);
- ") != 0); // same as above, but for an expression with length
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS); // same as above, but for an expression with length
+ assert(compile("
let x: []u8 = [0u8];
append(x, [0u8...], 2i);
- ") != 0); // length expression is not assignable to size
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS); // length expression is not assignable to size
+ assert(compile("
let x: []u8 = [0u8];
append(x, [42], 3);
- ") != 0); // must be an expandable array
+ ") as exited != EXIT_SUCCESS); // must be an expandable array
};
export fn main() void = {
diff --git a/tests/21-tuples.ha b/tests/21-tuples.ha
@@ -1,4 +1,4 @@
-use rt;
+use rt::{compile, exited, EXIT_SUCCESS};
fn storage() void = {
let x: (int, size) = (42, 1337);
@@ -112,38 +112,38 @@ fn unpacking() void = {
unpacking_addone(), unpacking_addone());
assert(a == 1 && b == 2 && d == 4);
- assert(rt::compile("
+ assert(compile("
export fn main() void = {
let (_, _) = (1, 2);
};
- ") != 0);
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS);
+ assert(compile("
export fn main() void = {
let (x, y) = (1, 2, 3);
};
- ") != 0);
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS);
+ assert(compile("
export fn main() void = {
let (x, y) = 5;
};
- ") != 0);
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS);
+ assert(compile("
fn getval() int = 5;
export fn main() void = {
static let (a, b) = (2, getval());
};
- ") != 0);
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS);
+ assert(compile("
fn getval() int = 5;
export fn main() void = {
static let (a, _) = (2, getval());
};
- ") != 0);
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS);
+ assert(compile("
export fn main() void = {
let (a, b): int = (2, 3);
};
- ") != 0);
+ ") as exited != EXIT_SUCCESS);
};
// Regression tests for miscellaneous compiler bugs
diff --git a/tests/23-errors.ha b/tests/23-errors.ha
@@ -1,4 +1,4 @@
-use rt;
+use rt::{compile, exited, EXIT_SUCCESS};
type err_int = !int;
@@ -29,37 +29,43 @@ fn propagate() void = {
};
fn cannotignore() void = {
- assert(rt::compile("type error = void!;
-
-export fn main() int = {
- error;
- return 42;
-};") != 0);
+ assert(compile("
+ type error = !void;
+
+ export fn main() int = {
+ error;
+ return 42;
+ };
+ ") as exited != EXIT_SUCCESS);
err_if_false(true)!;
};
fn void_assignability() void = {
- assert(rt::compile(`type err = !void;
+ assert(compile(`
+ type err = !void;
-fn reterr() (int | err) = {
- return err;
-};
+ fn reterr() (int | err) = {
+ return err;
+ };
-fn properr() void = {
- reterr()?;
-};
+ fn properr() void = {
+ reterr()?;
+ };
-export fn main() void = void;`) != 0); // error types cannot be assigned to void
+ export fn main() void = void;
+ `) as exited != EXIT_SUCCESS); // error types cannot be assigned to void
- assert(rt::compile(`fn disallow_1() void = {
- return "I am illegal";
-};
+ assert(compile(`
+ fn disallow_1() void = {
+ return "I am illegal";
+ };
-fn disallow_2() void = {
- return 12;
-};
+ fn disallow_2() void = {
+ return 12;
+ };
-export fn main() void = void;`) != 0); // non-void types cannot be assigned to void
+ export fn main() void = void;
+ `) as exited != EXIT_SUCCESS); // non-void types cannot be assigned to void
};
export fn main() void = {
diff --git a/tests/24-imports.ha b/tests/24-imports.ha
@@ -1,4 +1,4 @@
-use rt;
+use rt::{compile, exited, EXIT_SUCCESS};
use testmod;
fn _enum() void = {
@@ -7,80 +7,80 @@ fn _enum() void = {
};
fn accept() void = {
- assert(rt::compile("
+ assert(compile("
use testmod;
export fn main() void = static assert(testmod::val == 42);
- ") == rt::EXIT_SUCCESS);
- assert(rt::compile("
+ ") as exited == EXIT_SUCCESS);
+ assert(compile("
use testmod;
use alias = testmod;
export fn main() void = static assert(testmod::val == alias::val);
- ") == rt::EXIT_SUCCESS);
- assert(rt::compile("
+ ") as exited == EXIT_SUCCESS);
+ assert(compile("
use testmod;
use testmod::{val, val2};
export fn main() void = static assert(
testmod::val == val && testmod::val2 == val2
);
- ") == rt::EXIT_SUCCESS);
- assert(rt::compile("
+ ") as exited == EXIT_SUCCESS);
+ assert(compile("
use testmod;
use testmod::*;
export fn main() void = static assert(
testmod::val == val && testmod::val2 == val2
);
- ") == rt::EXIT_SUCCESS);
- assert(rt::compile("
+ ") as exited == EXIT_SUCCESS);
+ assert(compile("
use testmod;
use testmod::{alias = val, val2};
export fn main() void = static assert(
testmod::val == alias && testmod::val2 == val2
);
- ") == rt::EXIT_SUCCESS);
- assert(rt::compile("
+ ") as exited == EXIT_SUCCESS);
+ assert(compile("
use testmod;
use modalias = testmod::{valalias = val, val2};
export fn main() void = static assert(
testmod::val == modalias::valalias && testmod::val2 == modalias::val2
);
- ") == rt::EXIT_SUCCESS);
+ ") as exited == EXIT_SUCCESS);
};
fn reject() void = {
- assert(rt::compile("
+ assert(compile("
use wrong;
export fn main() void = { testmod::val };
- ") == rt::EXIT_FAILURE);
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS);
+ assert(compile("
use testmod::{val};
export fn main() void = static assert(
testmod::val == 42
);
- ") == rt::EXIT_FAILURE);
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS);
+ assert(compile("
use testmod::{val};
export fn main() void = static assert(
val2 == 90
);
- ") == rt::EXIT_FAILURE);
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS);
+ assert(compile("
use testmod;
use test = testmod::*;
export fn main() void = void;
- ") == rt::EXIT_FAILURE);
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS);
+ assert(compile("
use testmod;
use testmod*;
export fn main() void = void;
- ") == rt::EXIT_FAILURE);
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS);
+ assert(compile("
use testmod::{alias = val, val2};
export fn main() void = static assert(val == 42);
- ") == rt::EXIT_FAILURE);
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS);
+ assert(compile("
use modalias = testmod::{valalias = val, val2};
export fn main() void = static assert(valalias == 42);
- ") == rt::EXIT_FAILURE);
+ ") as exited != EXIT_SUCCESS);
};
diff --git a/tests/27-rt.ha b/tests/27-rt.ha
@@ -7,12 +7,12 @@ fn compile() void = {
fn test() void = {
void;
};"
- ) == 0);
+ ) as rt::exited == rt::EXIT_SUCCESS);
assert(rt::compile("
fn test() void = {
let a: int = [1, 2, 3];
};"
- ) != 0);
+ ) as rt::exited != rt::EXIT_SUCCESS);
};
export fn main() void = {
diff --git a/tests/28-insert.ha b/tests/28-insert.ha
@@ -1,4 +1,4 @@
-use rt;
+use rt::{compile, exited, EXIT_SUCCESS};
fn basics() void = {
let x: []int = alloc([1, 2, 5]);
@@ -62,26 +62,26 @@ fn typehints() void = {
};
fn reject() void = {
- assert(rt::compile("
+ assert(compile("
let x: []u8 = [0u8];
let y: int = 42;
insert(x[1], y);
- ") != 0); // object member type != value type
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS); // object member type != value type
+ assert(compile("
let x: []u8 = [0u8];
let y = 42u8;
insert(x[1], y...);
- ") != 0); // value is not an array or a slice
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS); // value is not an array or a slice
+ assert(compile("
let x: []u8 = [0u8];
let y: []int = [42];
insert(x[1], y...);
- ") != 0); // object member type != value member type
- assert(rt::compile("
+ ") as exited != EXIT_SUCCESS); // object member type != value member type
+ assert(compile("
let x: []u8 = [0u8];
let y: []int = [42];
insert(x[1], [y...], 3);
- ") != 0); // insert expression doesn't have a length parameter
+ ") as exited != EXIT_SUCCESS); // insert expression doesn't have a length parameter
};
export fn main() void = {
diff --git a/tests/34-declarations.ha b/tests/34-declarations.ha
@@ -1,4 +1,4 @@
-use rt;
+use rt::{compile, exited, EXIT_SUCCESS};
// interdependent constants
def A1: int = -1;
@@ -206,16 +206,16 @@ fn sz() void = {
fn reject() void = {
// TODO: figure out a better way to test these
- assert(rt::compile("type a = b; type b = a;") != 0);
- assert(rt::compile("type a = [20]a;") != 0);
- assert(rt::compile("type a = b; type b = a;") != 0);
- assert(rt::compile("type a = [20]a;") != 0);
- assert(rt::compile("type a = unknown;") != 0);
- assert(rt::compile("def x: int = 6; type a = x;") != 0);
- assert(rt::compile("type a = int; type a = str;") != 0);
- assert(rt::compile("def a: int = b; def b: int = a;") != 0);
- assert(rt::compile("def x: size = size(t); type t = [x]int;") != 0);
- assert(rt::compile("def a: int = 12; type t = (int |(...a | a));") != 0);
+ assert(compile("type a = b; type b = a;") as exited != EXIT_SUCCESS);
+ assert(compile("type a = [20]a;") as exited != EXIT_SUCCESS);
+ assert(compile("type a = b; type b = a;") as exited != EXIT_SUCCESS);
+ assert(compile("type a = [20]a;") as exited != EXIT_SUCCESS);
+ assert(compile("type a = unknown;") as exited != EXIT_SUCCESS);
+ assert(compile("def x: int = 6; type a = x;") as exited != EXIT_SUCCESS);
+ assert(compile("type a = int; type a = str;") as exited != EXIT_SUCCESS);
+ assert(compile("def a: int = b; def b: int = a;") as exited != EXIT_SUCCESS);
+ assert(compile("def x: size = size(t); type t = [x]int;") as exited != EXIT_SUCCESS);
+ assert(compile("def a: int = 12; type t = (int |(...a | a));") as exited != EXIT_SUCCESS);
};
// Types t_0 to t_9 form a complete directed graph on 10 vertices.