harec

[hare] Hare compiler, written in C11 for POSIX OSs
Log | Files | Refs | README | LICENSE

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:
Mrt/compile.ha | 9++++++---
Mtests/00-constants.ha | 76++++++++++++++++++++++++++++++++++++++--------------------------------------
Mtests/01-arrays.ha | 10+++++-----
Mtests/03-pointers.ha | 50+++++++++++++++++++++++++-------------------------
Mtests/05-implicit-casts.ha | 42+++++++++++++++++++++---------------------
Mtests/06-structs.ha | 4++--
Mtests/08-slices.ha | 24++++++++++++------------
Mtests/09-funcs.ha | 6+++---
Mtests/11-globals.ha | 6+++---
Mtests/12-loops.ha | 12++++++------
Mtests/13-tagged.ha | 34+++++++++++++++++-----------------
Mtests/15-enums.ha | 20++++++++++----------
Mtests/19-append.ha | 26+++++++++++++-------------
Mtests/21-tuples.ha | 26+++++++++++++-------------
Mtests/23-errors.ha | 50++++++++++++++++++++++++++++----------------------
Mtests/24-imports.ha | 54+++++++++++++++++++++++++++---------------------------
Mtests/27-rt.ha | 4++--
Mtests/28-insert.ha | 18+++++++++---------
Mtests/34-declarations.ha | 22+++++++++++-----------
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.