← Commit history

refactor(front): remove ashfront CLI entry point and its test runner

lennoxrose committed on Oct 18, 2026 at 00:43 UTC

8f6c042parente290a79

165 files changed+114−2804

hearth/ashvm/tests/cases/basics/bare_reassign_test.ashremoved

+0−10
@@ -1,10 +0,0 @@
1-forge f(i) {
2- i = i + 1;
3- i = i * 2;
4- yield i;
5-}
6-say f(5);
7-
8-local x = 1;
9-x = x + 10;
10-say x;

hearth/ashvm/tests/cases/basics/booleans.ashremoved

+0−35
@@ -1,35 +0,0 @@
1-say yes;
2-say no;
3-say 1 < 2;
4-say 2 < 1;
5-say not yes;
6-say not 0;
7-say 1 == 1;
8-say "a" == "a";
9-say "a" == "b";
10-say 1 and 1;
11-say 0 or 1;
12-say yes == 1;
13-say yes == yes;
14-say type(yes);
15-say type(1 < 2);
16-say [yes, no, 3 > 4];
17-say {"ok": yes};
18-say str(no) + str(yes);
19-say has({"a": 1}, "a");
20-say has({"a": 1}, "b");
21-say yes + 1;
22-say file_exists("/nonexistent");
23-say contains("abc", "b");
24-local flag = 5 > 3;
25-given flag { say "flag set"; }
26-given not flag { say "bad"; } otherwise { say "ok"; }
27-say flag and not no;
28-say none == none;
29-say not none;
30-attempt { given {"a": 1} { say "bad"; } } handle (e) { say "map condition"; }
31-attempt { given "x" { say "bad"; } } handle (e) { say "string condition"; }
32-local n = 0;
33-during n < 3 { n++; }
34-say n;
35-say yes ? "t" : "f";

hearth/ashvm/tests/cases/basics/exponent_literals.ashremoved

+0−6
@@ -1,6 +0,0 @@
1-say 1e3;
2-say 1.5e-3;
3-say 2E2 + 1;
4-say num("-1.5e2");
5-say num("1e3") + 1;
6-say num("2.5E-1");

hearth/ashvm/tests/cases/basics/literals_test.ashremoved

+0−29
@@ -1,29 +0,0 @@
1-say yes;
2-say no;
3-say none;
4-
5-say yes == 1;
6-say no == 0;
7-say none == none;
8-say none == 0;
9-say none == no;
10-
11-given yes {
12- say "yes is truthy";
13-}
14-given no {
15- say "unreachable";
16-} otherwise {
17- say "no is falsy";
18-}
19-local x = none;
20-given x {
21- say "unreachable";
22-} otherwise {
23- say "none is falsy";
24-}
25-
26-local arr = [1, none, yes, no];
27-say arr;
28-local m = {"a": none, "b": yes};
29-say m;

hearth/ashvm/tests/cases/basics/modulo.ashremoved

+0−7
@@ -1,7 +0,0 @@
1-say 7 % 3;
2-say -7 % 3;
3-say 7 % -3;
4-say -7 % -3;
5-say 7.5 % 2;
6-say 10 % 2 == 0;
7-say 10 % 3 == 1;

hearth/ashvm/tests/cases/basics/number_format.ashremoved

+0−26
@@ -1,26 +0,0 @@
1-say 0;
2-say 3;
3-say -42;
4-say 0.5;
5-say -0.25;
6-say 3.14159265;
7-say 0.1 + 0.2;
8-say 123456789012;
9-say 999999999999999;
10-say 1e15;
11-say 1e21;
12-say -1e21;
13-say 1.5e-7;
14-say 1e-7;
15-say 0.000001;
16-say 0.0000005;
17-say 123456.789;
18-say 1e100;
19-say 1.2345678e30;
20-say 9.9999996;
21-say 0.9999999;
22-say 2.5e-300;
23-say 1 / 0;
24-say -1 / 0;
25-say str(1e21) + "|" + str(1.5) + "|" + str(-7);
26-say [1.5, 1e21, 2];

hearth/ashvm/tests/cases/basics/operators_test.ashremoved

+0−31
@@ -1,31 +0,0 @@
1-local x = 10;
2-x += 5;
3-say x;
4-x -= 3;
5-say x;
6-x *= 2;
7-say x;
8-x /= 4;
9-say x;
10-
11-local s = "hello";
12-s += " world";
13-say s;
14-
15-local i = 0;
16-i++;
17-i++;
18-i--;
19-say i;
20-
21-local n = 7;
22-say n > 5 ? "big" : "small";
23-say n < 5 ? "big" : n < 10 ? "medium" : "huge";
24-
25-say 5 & 3;
26-say 5 | 2;
27-say 5 ^ 1;
28-say ~5;
29-say 1 << 4;
30-say 256 >> 4;
31-say (5 & 3) == 1;

hearth/ashvm/tests/cases/basics/type_test.ashremoved

+0−8
@@ -1,8 +0,0 @@
1-say type(5);
2-say type("hi");
3-say type([1, 2]);
4-say type({"a": 1});
5-say type(none);
6-say type(yes);
7-forge f() { yield 1; }
8-say type(f);

hearth/ashvm/tests/cases/collections/array_mutation.ashremoved

+0−16
@@ -1,16 +0,0 @@
1-local a = [1, 2, 3, 4];
2-delete(a, 1);
3-say a;
4-say pop(a);
5-say a;
6-insert(a, 0, 9);
7-insert(a, len(a), 7);
8-insert(a, 1, 8);
9-say a;
10-say slice(a, 1, 3);
11-say slice(a, 0, 0);
12-attempt { pop([]); } handle (e) { say "empty"; }
13-attempt { delete(a, 10); } handle (e) { say "oob"; }
14-local m = {"k": 1};
15-delete(m, "k");
16-say len(m);

hearth/ashvm/tests/cases/collections/map_order.ashremoved

+0−30
@@ -1,30 +0,0 @@
1-local m = {};
2-m["b"] = 1; m["zeta"] = 2; m["alpha"] = 3; m["a"] = 4; m["mid"] = 5;
3-say keys(m);
4-say values(m);
5-delete(m, "alpha");
6-say keys(m);
7-m["alpha"] = 9;
8-m["b"] = 100;
9-say keys(m);
10-say m;
11-delete(m, "b");
12-delete(m, "zzz");
13-say keys(m);
14-say len(m);
15-say has(m, "b");
16-say has(m, "mid");
17-local big = {};
18-local i = 0;
19-during i < 100 { big[str(i)] = i; i++; }
20-i = 0;
21-during i < 100 { given i % 2 == 0 { delete(big, str(i)); } i++; }
22-say len(big);
23-say big["51"];
24-say keys(big)[0];
25-say keys(big)[49];
26-i = 0;
27-during i < 100 { given i % 2 == 0 { big[str(i)] = i; } i++; }
28-say len(big);
29-say keys(big)[50];
30-say big["98"];

hearth/ashvm/tests/cases/collections/maps_test.ashremoved

+0−22
@@ -1,22 +0,0 @@
1-local person = {"name": "Lennox", "age": 20};
2-say person;
3-say person["name"];
4-say person["age"];
5-
6-person["age"] = 21;
7-say person["age"];
8-
9-person["city"] = "Luebeck";
10-say person;
11-
12-say keys(person);
13-say values(person);
14-say has(person, "name");
15-say has(person, "zip");
16-
17-delete(person, "city");
18-say person;
19-
20-local empty = {};
21-say empty;
22-say len(person);

hearth/ashvm/tests/cases/collections/matrix_mul.ashremoved

+0−36
@@ -1,36 +0,0 @@
1-// matrix_mul(a, b) -- dispatches to Pyre's CPU backend for large square
2-// matrices (ash_gpu_matrix_multiply), computes directly in C for small
3-// ones (see src/builtins/C/matrix.c's ASH_GPU_MIN_N threshold). Both
4-// paths must agree.
5-local a = [[1, 2], [3, 4]];
6-local b = [[5, 6], [7, 8]];
7-say matrix_mul(a, b);
8-
9-forge make_matrix(n, v) {
10- local mat = [];
11- local i = 0;
12- during i < n {
13- local row = [];
14- local j = 0;
15- during j < n {
16- push(row, v);
17- j += 1;
18- }
19- push(mat, row);
20- i += 1;
21- }
22- yield mat;
23-}
24-
25-// Above the dispatch threshold -- exercises the Pyre CPU backend.
26-local n = 200;
27-local big_a = make_matrix(n, 1.5);
28-local big_b = make_matrix(n, 2.0);
29-local big_c = matrix_mul(big_a, big_b);
30-say big_c[0][0];
31-say big_c[n - 1][n - 1];
32-
33-// Error cases: not square, mismatched sizes, not arrays at all.
34-attempt { matrix_mul([1, 2, 3], [4, 5, 6]); } handle (e) { say "not nested: " + e; }
35-attempt { matrix_mul([[1, 2]], [[1, 2], [3, 4]]); } handle (e) { say "mismatched size: " + e; }
36-attempt { matrix_mul(5, 6); } handle (e) { say "not arrays: " + e; }

hearth/ashvm/tests/cases/collections/sort.ashremoved

+0−20
@@ -1,20 +0,0 @@
1-local a = [5, 2, 9, 1, 5, 6, -3, 0];
2-sort(a);
3-say a;
4-local s = ["pear", "apple", "fig", "banana", "apple", ""];
5-say sort(s);
6-local m = [{"k": 2, "t": "a"}, {"k": 1, "t": "b"}, {"k": 2, "t": "c"}, {"k": 1, "t": "d"}];
7-sort(m, forge (x, y) { yield x["k"] - y["k"]; });
8-say map(m, forge (x) { yield x["t"]; });
9-say sort([3, 1, 2], forge (x, y) { yield y - x; });
10-say sort([]);
11-say sort([1]);
12-local big = [];
13-local i = 0;
14-during i < 200 { push(big, (i * 37) % 101); i++; }
15-sort(big);
16-local ok = yes;
17-i = 1;
18-during i < len(big) { given big[i - 1] > big[i] { ok = no; } i++; }
19-say ok;
20-say len(big);

hearth/ashvm/tests/cases/collections/vm_arrays_test.ashremoved

+0−23
@@ -1,23 +0,0 @@
1-local nums = [1, 2, 3, 4, 5];
2-say nums;
3-say nums[0];
4-say nums[4];
5-
6-nums[0] = 99;
7-say nums;
8-
9-local sum = 0;
10-local i = 0;
11-during (i < 5) {
12- local sum = sum + nums[i];
13- local i = i + 1;
14-}
15-say sum;
16-
17-forge first(arr) {
18- yield arr[0];
19-}
20-say first(nums);
21-
22-local names = ["Ash", "Sonnet"];
23-say names[1];

hearth/ashvm/tests/cases/control_flow/each_test.ashremoved

+0−45
@@ -1,45 +0,0 @@
1-local nums = [10, 20, 30, 40, 50];
2-
3-each x in nums {
4- say x;
5-}
6-
7-each (y in nums) {
8- say y * 2;
9-}
10-
11-local m = {"a": 1, "b": 2, "c": 3};
12-each k in keys(m) {
13- say k + " = " + str(m[k]);
14-}
15-
16-local total = 0;
17-each n in nums {
18- local total = total + n;
19-}
20-say total;
21-
22-local empty = [];
23-local empty_count = 0;
24-each e in empty {
25- local empty_count = empty_count + 1;
26-}
27-say empty_count;
28-
29-local rows = [[1, 2], [3, 4], [5, 6]];
30-local line = "";
31-each row in rows {
32- local line = "";
33- each cell in row {
34- local line = line + str(cell) + " ";
35- }
36- say line;
37-}
38-
39-local outer_total = 0;
40-each a in [1, 2, 3] {
41- each b in [10, 20] {
42- local outer_total = outer_total + a * b;
43- }
44-}
45-say outer_total;

hearth/ashvm/tests/cases/control_flow/loop_body_locals_test.ashremoved

+0−42
@@ -1,42 +0,0 @@
1-// A fresh `local` declared inside a re-executed block must not leak across
2-// iterations/branches -- found via a cross-engine audit against kiln.
3-
4-local i = 0;
5-during i < 3 {
6- local x = i * 10;
7- say x;
8- i += 1;
9-}
10-
11-local arr = [1, 2, 3];
12-each n in arr {
13- local y = n * 10;
14- say y;
15-}
16-
17-local j = 0;
18-during j < 6 {
19- given j % 2 == 0 {
20- local a = j * 100;
21- say a;
22- } otherwise {
23- j += 1;
24- next;
25- }
26- j += 1;
27-}
28-
29-each x in arr {
30- given x == 2 { next; }
31- local z = x * 1000;
32- say z;
33-}
34-
35-each outer in [1, 2] {
36- local tmp = outer;
37- each inner in [10, 20] {
38- local tmp2 = outer + inner;
39- say tmp2;
40- }
41- say tmp;
42-}

hearth/ashvm/tests/cases/control_flow/loop_control_test.ashremoved

+0−41
@@ -1,41 +0,0 @@
1-local total = 0;
2-local j = 0;
3-during j < 10 {
4- j += 1;
5- given j == 3 {
6- next;
7- }
8- given j == 7 {
9- stop;
10- }
11- total += j;
12-}
13-say total;
14-say j;
15-
16-local sum = 0;
17-each v in [1, 2, 3, 4, 5, 6, 7, 8] {
18- given v == 2 {
19- next;
20- }
21- given v == 6 {
22- stop;
23- }
24- sum += v;
25-}
26-say sum;
27-
28-// stop only breaks the innermost loop
29-local results = [];
30-each a in [1, 2, 3] {
31- each b in [10, 20, 30] {
32- given b == 20 {
33- next;
34- }
35- given a == 3 {
36- stop;
37- }
38- local results = push(results, a * b);
39- }
40-}
41-say results;

hearth/ashvm/tests/cases/control_flow/short_circuit.ashremoved

+0−11
@@ -1,11 +0,0 @@
1-local a = [1, 2];
2-given 5 < len(a) and a[5] == 1 { say "bad"; } otherwise { say "ok and"; }
3-given 0 < len(a) or a[5] == 1 { say "ok or"; }
4-say 1 and 2;
5-say 0 or 3;
6-say 0 and 1;
7-say 1 or 0;
8-say 1 and 0 or 1;
9-local n = 0;
10-during n < 5 and n != 3 { n++; }
11-say n;

hearth/ashvm/tests/cases/control_flow/stop_pops_locals.ashremoved

+0−52
@@ -1,52 +0,0 @@
1-// `stop` leaves a loop whose body declared locals: later locals must still get the right slots.
2-forge plain() {
3- local q = 4;
4- during yes {
5- local t = q;
6- q = t + 1;
7- given q > 5 { stop; }
8- }
9- local s = "n";
10- yield s + str(q);
11-}
12-
13-forge nested() {
14- local q = 0;
15- during yes {
16- local a = q;
17- given a >= 0 {
18- local b = a + 1;
19- given b == 2 { stop; }
20- }
21- q += 1;
22- }
23- local after = "after";
24- yield after + str(q);
25-}
26-
27-forge each_stop() {
28- local last = 0;
29- each x in [1, 2, 3, 4] {
30- local y = x * 2;
31- given y > 4 { stop; }
32- last = y;
33- }
34- local tail = "tail";
35- yield tail + str(last);
36-}
37-
38-forge with_next() {
39- local c = 0;
40- during c < 3 {
41- local t = c;
42- c += 1;
43- given t == 1 { next; }
44- }
45- local done = "done";
46- yield done + str(c);
47-}
48-
49-say plain();
50-say nested();
51-say each_stop();
52-say with_next();

hearth/ashvm/tests/cases/core/vm_full_test.ashremoved

+0−39
@@ -1,39 +0,0 @@
1-local person = {"name": "Ash", "version": 2};
2-say person;
3-say person["name"];
4-person["version"] = 3;
5-say person;
6-say keys(person);
7-say values(person);
8-say has(person, "name");
9-delete(person, "version");
10-say person;
11-
12-forge double(x) { yield x * 2; }
13-local f = double;
14-say f(21);
15-
16-local nums = [1, 2, 3, 4, 5];
17-local doubled = map(nums, double);
18-say doubled;
19-
20-forge isEven(x) { yield x % 2 == 0; }
21-local evens = filter(nums, isEven);
22-say evens;
23-
24-forge add(a, b) { yield a + b; }
25-local total = reduce(nums, add, 0);
26-say total;
27-
28-say upper("hello");
29-say lower("WORLD");
30-say trim(" spaced ");
31-say split("a,b,c", ",");
32-say join(["x", "y", "z"], "-");
33-say substring("hello world", 0, 5);
34-say indexOf("hello world", "world");
35-say replace("foo bar foo", "foo", "baz");
36-
37-write_file("/tmp/ashvm_test.txt", "vm file test\n");
38-say file_exists("/tmp/ashvm_test.txt");
39-say read_file("/tmp/ashvm_test.txt");

hearth/ashvm/tests/cases/errors/attempt_array_delete.ashremoved

+0−10
@@ -1,10 +0,0 @@
1-local a = [1, 2, 3];
2-attempt { delete(a, 0); say "deleted"; say a; push(a, 9); delete(a, 99); say "unreachable"; } handle (e) { say "caught: " + e; }
3-say a;
4-attempt { local m = {"x": 1}; delete(m, "x"); say m; say m["x"]; } handle (e) { say "caught: " + e; }
5-local i = 0;
6-during i < 3 {
7- attempt { delete(a, 10); } handle (e) { say "again: " + e; }
8- i++;
9-}
10-say "end";

hearth/ashvm/tests/cases/errors/attempt_stale_handler.ashremoved

+0−21
@@ -1,21 +0,0 @@
1-forge f() {
2- local i = 0;
3- during i < 3 {
4- attempt { local x = 1; } handle (e) { say "inner"; }
5- i++;
6- }
7- raise "boom";
8-}
9-attempt { f(); } handle (e) { say "outer: " + e; }
10-forge g() {
11- attempt { yield 5; } handle (e) { say "no"; }
12-}
13-forge h() { local v = g(); raise "boom2"; }
14-attempt { h(); } handle (e) { say "outer: " + e; }
15-local i = 0;
16-during i < 3 {
17- i++;
18- attempt { next; } handle (e) { say "no"; }
19-}
20-attempt { raise "second"; } handle (e) { say "caught " + e; }
21-say "done";

hearth/ashvm/tests/cases/errors/error_handling_test.ashremoved

+0−57
@@ -1,57 +0,0 @@
1-forge risky(n) {
2- given (n > 3) {
3- local undefined_thing = does_not_exist + 1;
4- }
5- yield n;
6-}
7-
8-local result = 0;
9-attempt {
10- local result = risky(5);
11- say "should not reach here";
12-} handle (e) {
13- say "caught: " + e;
14-}
15-say "after attempt 1, result still: " + str(result);
16-
17-local arr = [1, 2, 3];
18-attempt {
19- say arr[10];
20-} handle (e) {
21- say "caught: " + e;
22-}
23-
24-local m = {"a": 1};
25-attempt {
26- say m["missing_key"];
27-} handle (e) {
28- say "caught: " + e;
29-}
30-
31-forge needs_two(a, b) { yield a + b; }
32-attempt {
33- say needs_two(1);
34-} handle (e) {
35- say "caught: " + e;
36-}
37-
38-attempt {
39- local content = read_file("/tmp/does_not_exist_xyz_ash.txt");
40-} handle (e) {
41- say "caught: " + e;
42-}
43-
44-attempt {
45- attempt {
46- local x = totally_undefined_var;
47- } handle (inner) {
48- say "inner caught: " + inner;
49- }
50- say "inner attempt/handle resolved, continuing outer attempt";
51-} handle (outer) {
52- say "outer should not see this: " + outer;
53-}
54-
55-say "program completed normally";
56-local final_check = 42;
57-say final_check;

hearth/ashvm/tests/cases/errors/error_message_field.ashremoved

+0−5
@@ -1,5 +0,0 @@
1-attempt { local a = [1]; say a[3]; } handle (e) { say e.message; say "x: " + e; }
2-attempt { raise {"message": "custom", "line": 3}; } handle (e) { say e.message; say e.line; }
3-attempt { raise "plain"; } handle (e) { say e.message == e; }
4-local m = {"inner": {"deep": 7}};
5-say m.inner.deep;

hearth/ashvm/tests/cases/errors/error_messages.ashremoved

+0−23
@@ -1,23 +0,0 @@
1-local a = [1, 2];
2-attempt { say a[5]; } handle (e) { say e; }
3-attempt { say {"k": 1}["zz"]; } handle (e) { say e; }
4-attempt { say "abc"[9]; } handle (e) { say e; }
5-attempt { say "x" + 1; } handle (e) { say e; }
6-attempt { say 1 + "x"; } handle (e) { say e; }
7-attempt { say str("t"); } handle (e) { say e; }
8-attempt { pop([]); } handle (e) { say e; }
9-attempt { delete([1], 3); } handle (e) { say e; }
10-attempt { insert([1], 3, 0); } handle (e) { say e; }
11-attempt { slice([1, 2], 1, 5); } handle (e) { say e; }
12-attempt { chr(0); } handle (e) { say e; }
13-attempt { ord(""); } handle (e) { say e; }
14-attempt { repeat("a", -2); } handle (e) { say e; }
15-attempt { read_file("/nonexistent/file"); } handle (e) { say e; }
16-attempt { list_dir("/nonexistent"); } handle (e) { say e; }
17-attempt { given [1] { say "bad"; } } handle (e) { say e; }
18-attempt { raise "custom"; } handle (e) { say e; }
19-attempt { raise {"kind": "parse", "line": 3, "col": 7}; } handle (e) { say e["kind"] + ":" + str(e["line"]) + ":" + str(e["col"]); }
20-attempt { raise [1, 2]; } handle (e) { say e; }
21-attempt { raise 42; } handle (e) { say e + 1; }
22-forge f() { raise {"m": "inner"}; }
23-attempt { f(); } handle (e) { say e["m"]; }

hearth/ashvm/tests/cases/errors/raise_test.ashremoved

+0−22
@@ -1,22 +0,0 @@
1-attempt {
2- raise "custom error: " + str(42);
3-} handle (e) {
4- say "caught: " + e;
5-}
6-say "after";
7-
8-forge validate(x) {
9- given x < 0 {
10- raise "negative value: " + str(x);
11- }
12- yield x;
13-}
14-
15-attempt {
16- say validate(5);
17- say validate(-3);
18- say "unreachable";
19-} handle (e) {
20- say "caught: " + e;
21-}
22-say "done";

hearth/ashvm/tests/cases/errors/type_errors.ashremoved

+0−6
@@ -1,6 +0,0 @@
1-attempt { say "x" + 1; } handle (e) { say "caught plus"; }
2-attempt { say 1 + "x"; } handle (e) { say "caught plus2"; }
3-attempt { say str("text"); } handle (e) { say "caught str"; }
4-say "a" + "b";
5-say 1 + 2;
6-say str(5);

hearth/ashvm/tests/cases/errors/vm_trycatch_test.ashremoved

+0−52
@@ -1,52 +0,0 @@
1-local arr = [1, 2, 3];
2-attempt {
3- say arr[10];
4-} handle (e) {
5- say "caught: " + e;
6-}
7-say "after array test";
8-
9-local m = {"a": 1};
10-attempt {
11- say m["missing"];
12-} handle (e) {
13- say "caught: " + e;
14-}
15-
16-attempt {
17- local content = read_file("/tmp/nonexistent_ashvm_xyz.txt");
18-} handle (e) {
19- say "caught: " + e;
20-}
21-
22-forge risky(n) {
23- given (n > 3) {
24- local arr2 = [1, 2];
25- say arr2[99];
26- }
27- yield n;
28-}
29-
30-attempt {
31- local result = risky(5);
32- say "should not say";
33-} handle (e) {
34- say "caught in function: " + e;
35-}
36-say "still running after function error";
37-
38-attempt {
39- attempt {
40- local arr3 = [1];
41- say arr3[5];
42- } handle (inner) {
43- say "inner caught: " + inner;
44- }
45- say "inner resolved";
46-} handle (outer) {
47- say "outer should not fire";
48-}
49-
50-say "program completed";
51-local final = 42;
52-say final;

hearth/ashvm/tests/cases/functions/builtins_as_values.ashremoved

+0−9
@@ -1,9 +0,0 @@
1-say type(len);
2-say map([1, 22, 333], str);
3-say map(["a", "bb"], len);
4-say map(["ab", "cd"], upper);
5-say filter([1, 2, 3, 4], forge (x) { yield x > 2; });
6-local f = len;
7-say f("hello");
8-say reduce([1, 2, 3], forge (a, b) { yield a + b; }, 0);
9-say map([4, 9], sqrt);

hearth/ashvm/tests/cases/functions/closures_test.ashremoved

+0−21
@@ -1,21 +0,0 @@
1-forge make_adder(x) {
2- yield forge(y) { yield x + y; };
3-}
4-
5-local add5 = make_adder(5);
6-local add10 = make_adder(10);
7-say add5(3);
8-say add10(3);
9-
10-local nums = [1, 2, 3];
11-local shift100 = make_adder(100);
12-local shifted = map(nums, shift100);
13-say shifted;
14-
15-forge compose(f, g) {
16- yield forge(x) { yield f(g(x)); };
17-}
18-forge double(x) { yield x * 2; }
19-forge inc(x) { yield x + 1; }
20-local doubleThenInc = compose(inc, double);
21-say doubleThenInc(5);

hearth/ashvm/tests/cases/functions/forward_declarations.ashremoved

+0−20
@@ -1,20 +0,0 @@
1-say is_even(10);
2-say is_odd(7);
3-say is_even(7);
4-forge is_even(n) {
5- given n == 0 { yield yes; }
6- yield is_odd(n - 1);
7-}
8-forge is_odd(n) {
9- given n == 0 { yield no; }
10- yield is_even(n - 1);
11-}
12-say twice(3);
13-forge twice(x) { yield helper(x) * 2; }
14-forge helper(x) { yield x + 1; }
15-local f = helper;
16-say f(5);
17-say map([1, 2], twice);
18-forge shadow(a) { yield a; }
19-local shadow = forge (a) { yield a * 100; };
20-say shadow(2);

hearth/ashvm/tests/cases/functions/functional_test.ashremoved

+0−20
@@ -1,20 +0,0 @@
1-forge double(x) { yield x * 2; }
2-forge is_even(x) { yield x % 2 == 0; }
3-
4-local nums = [1, 2, 3, 4, 5, 6];
5-
6-local doubled = map(nums, double);
7-say doubled;
8-
9-local evens = filter(nums, is_even);
10-say evens;
11-
12-local total = reduce(nums, forge(acc, x) { yield acc + x; }, 0);
13-say total;
14-
15-local squareLambda = forge(x) { yield x * x; };
16-local squares = map(nums, squareLambda);
17-say squares;
18-
19-local f = double;
20-say f(21);

hearth/ashvm/tests/cases/functions/vm_closures_test.ashremoved

+0−24
@@ -1,24 +0,0 @@
1-forge make_adder(x) {
2- yield forge(y) { yield x + y; };
3-}
4-
5-local add5 = make_adder(5);
6-local add10 = make_adder(10);
7-say add5(3);
8-say add10(3);
9-
10-local nums = [1, 2, 3];
11-local shift100 = make_adder(100);
12-local shifted = map(nums, shift100);
13-say shifted;
14-
15-forge compose(f, g) {
16- yield forge(x) { yield f(g(x)); };
17-}
18-forge double(x) { yield x * 2; }
19-forge inc(x) { yield x + 1; }
20-local doubleThenInc = compose(inc, double);
21-say doubleThenInc(5);
22-
23-local total = reduce(nums, forge(acc, n) { yield acc + n; }, 0);
24-say total;

hearth/ashvm/tests/cases/imports/ash.libs/testlib/testlib.ashremoved

+0−5
@@ -1,5 +0,0 @@
1-local VERSION = "1.0";
2-
3-forge square(x) {
4- yield x * x;
5-}

hearth/ashvm/tests/cases/imports/fixtures/collision_dir_one/shared.ashremoved

+0−3
@@ -1,3 +0,0 @@
1-forge fromOne() {
2- yield 1;
3-}

hearth/ashvm/tests/cases/imports/fixtures/collision_dir_two/shared.ashremoved

+0−3
@@ -1,3 +0,0 @@
1-forge fromTwo() {
2- yield 2;
3-}

hearth/ashvm/tests/cases/imports/fixtures/imports_basic_lib.ashremoved

+0−7
@@ -1,7 +0,0 @@
1-forge helper(x) {
2- yield x * 2;
3-}
4-
5-forge add(a, b) {
6- yield a + b + helper(1);
7-}

hearth/ashvm/tests/cases/imports/fixtures/imports_circular_a.ashremoved

+0−5
@@ -1,5 +0,0 @@
1-@import <./imports_circular_b.ash>;
2-
3-forge fromA() {
4- yield 1;
5-}

hearth/ashvm/tests/cases/imports/fixtures/imports_circular_b.ashremoved

+0−5
@@ -1,5 +0,0 @@
1-@import <./imports_circular_a.ash>;
2-
3-forge fromB() {
4- yield 2;
5-}

hearth/ashvm/tests/cases/imports/fixtures/imports_collision_main.ashremoved

+0−4
@@ -1,4 +0,0 @@
1-@import <./collision_dir_one/shared.ash>;
2-@import <./collision_dir_two/shared.ash>;
3-
4-say shared.fromOne();

hearth/ashvm/tests/cases/imports/fixtures/imports_const_lib.ashremoved

+0−6
@@ -1,6 +0,0 @@
1-local PI = 3.14159;
2-local GREETING = "hello from lib";
3-
4-forge circleArea(r) {
5- yield PI * r * r;
6-}

hearth/ashvm/tests/cases/imports/fixtures/imports_diamond_b.ashremoved

+0−5
@@ -1,5 +0,0 @@
1-@import <./imports_diamond_d.ash>;
2-
3-forge fromB() {
4- yield imports_diamond_d.base() + 1;
5-}

hearth/ashvm/tests/cases/imports/fixtures/imports_diamond_c.ashremoved

+0−5
@@ -1,5 +0,0 @@
1-@import <./imports_diamond_d.ash>;
2-
3-forge fromC() {
4- yield imports_diamond_d.base() + 2;
5-}

hearth/ashvm/tests/cases/imports/fixtures/imports_diamond_d.ashremoved

+0−3
@@ -1,3 +0,0 @@
1-forge base() {
2- yield 100;
3-}

hearth/ashvm/tests/cases/imports/fixtures/imports_state_lib.ashremoved

+0−15
@@ -1,15 +0,0 @@
1-local DIGITS = "0123456789abcdef";
2-local TABLE = [10, 20, 30];
3-local COUNT = 0;
4-local CONFIG = {"name": "stateful", "level": 2};
5-local DOUBLE = 21 * 2;
6-local ENABLED = yes;
7-
8-forge bump() { COUNT += 1; yield COUNT; }
9-forge hexdigit(n) { yield substring(DIGITS, n, n + 1); }
10-forge table_at(i) { yield TABLE[i]; }
11-forge add_item(v) { push(TABLE, v); yield len(TABLE); }
12-forge set_level(l) { CONFIG["level"] = l; }
13-forge level() { yield CONFIG["level"]; }
14-forge reset() { COUNT = 0; }
15-forge bump2() { COUNT++; yield COUNT; }

hearth/ashvm/tests/cases/imports/fixtures/imports_statement_lib.ashremoved

+0−19
@@ -1,19 +0,0 @@
1-// Covers two bugs found writing the first real forgepack module (see
2-// CHANGELOG.md): a `local` inside a loop in an imported function used to
3-// be misdiagnosed as a failed top-level namespaced-constant declaration,
4-// and a namespaced call used as its OWN statement (not nested in an
5-// expression) used to fail to parse entirely.
6-forge sum_doubled(arr) {
7- local total = 0;
8- local i = 0;
9- during i < len(arr) {
10- local doubled = arr[i] * 2;
11- total += doubled;
12- i += 1;
13- }
14- yield total;
15-}
16-
17-forge announce(label) {
18- say "announced: " + label;
19-}

hearth/ashvm/tests/cases/imports/fixtures/imports_transitive_mid.ashremoved

+0−3
@@ -1,3 +0,0 @@
1-@import <./imports_basic_lib.ash>;
2-
3-forge mid_triple(x) { yield imports_basic_lib.add(x, imports_basic_lib.add(x, x)); }

hearth/ashvm/tests/cases/imports/imports_alias_test.ashremoved

+0−6
@@ -1,6 +0,0 @@
1-@import <./fixtures/imports_basic_lib.ash> as lib;
2-@import <./fixtures/imports_const_lib.ash> as k;
3-
4-say lib.add(3, 4);
5-say lib.helper(10);
6-say k.GREETING;

hearth/ashvm/tests/cases/imports/imports_basic_test.ashremoved

+0−4
@@ -1,4 +0,0 @@
1-@import <./fixtures/imports_basic_lib.ash>;
2-
3-say imports_basic_lib.add(3, 4);
4-say imports_basic_lib.helper(10);

hearth/ashvm/tests/cases/imports/imports_const_test.ashremoved

+0−5
@@ -1,5 +0,0 @@
1-@import <./fixtures/imports_const_lib.ash>;
2-
3-say imports_const_lib.PI;
4-say imports_const_lib.GREETING;
5-say imports_const_lib.circleArea(2);

hearth/ashvm/tests/cases/imports/imports_diamond_test.ashremoved

+0−6
@@ -1,6 +0,0 @@
1-@import <./fixtures/imports_diamond_b.ash>;
2-@import <./fixtures/imports_diamond_c.ash>;
3-
4-say imports_diamond_b.fromB();
5-say imports_diamond_c.fromC();
6-say imports_diamond_d.base();

hearth/ashvm/tests/cases/imports/imports_lib_test.ashremoved

+0−4
@@ -1,4 +0,0 @@
1-@import <testlib>;
2-
3-say testlib.VERSION;
4-say testlib.square(6);

hearth/ashvm/tests/cases/imports/imports_state_test.ashremoved

+0−17
@@ -1,17 +0,0 @@
1-@import <./fixtures/imports_state_lib.ash>;
2-
3-say imports_state_lib.bump();
4-say imports_state_lib.bump();
5-say imports_state_lib.hexdigit(11);
6-say imports_state_lib.table_at(1);
7-say imports_state_lib.add_item(40);
8-say imports_state_lib.add_item(50);
9-say imports_state_lib.TABLE;
10-imports_state_lib.set_level(9);
11-say imports_state_lib.level();
12-say imports_state_lib.CONFIG["name"];
13-say imports_state_lib.DOUBLE;
14-say imports_state_lib.ENABLED;
15-imports_state_lib.reset();
16-say imports_state_lib.bump2();
17-say imports_state_lib.COUNT;

hearth/ashvm/tests/cases/imports/imports_statement_test.ashremoved

+0−4
@@ -1,4 +0,0 @@
1-@import <./fixtures/imports_statement_lib.ash>;
2-
3-say imports_statement_lib.sum_doubled([1, 2, 3]);
4-imports_statement_lib.announce("done");

hearth/ashvm/tests/cases/imports/imports_transitive_test.ashremoved

+0−5
@@ -1,5 +0,0 @@
1-@import <./fixtures/imports_transitive_mid.ash>;
2-
3-say imports_transitive_mid.mid_triple(4);
4-say imports_basic_lib.add(1, 2);
5-say imports_basic_lib.helper(10);

hearth/ashvm/tests/cases/io/fs_ops.ashremoved

+0−15
@@ -1,15 +0,0 @@
1-local d = "/tmp/ash_fs_test_dir";
2-delete_file(d + "/b.txt"); delete_file(d + "/a.txt"); delete_file(d + "/c.txt");
3-make_dir(d);
4-say file_exists(d + "/a.txt");
5-write_file(d + "/a.txt", "hello");
6-write_file(d + "/b.txt", "world");
7-say rename_file(d + "/b.txt", d + "/c.txt");
8-say rename_file(d + "/nope.txt", d + "/x.txt");
9-say sort(list_dir(d));
10-say read_file(d + "/c.txt");
11-say delete_file(d + "/a.txt");
12-say delete_file(d + "/a.txt");
13-say delete_file(d + "/c.txt");
14-say list_dir(d);
15-attempt { list_dir(d + "/missing"); } handle (e) { say "no dir"; }

hearth/ashvm/tests/cases/memory/GcChurn.ashadded

+28−0
@@ -0,0 +1,28 @@
1+package memory;
2+
3+import ash.util.ArrayList;
4+
5+/// Allocates ~1.2M short-lived strings and lists. The default VM never frees them (hundreds of MB
6+/// here); the experimental collector (make GC=1) keeps the footprint small. Output is identical.
7+class GcChurn {
8+ static int churn(int n) {
9+ ArrayList<ArrayList<String>> keep = new ArrayList<>();
10+ int i = 0;
11+ while (i < n) {
12+ String s = "item-" + i;
13+ String t = s + "-" + s;
14+ ArrayList<String> pair = new ArrayList<>();
15+ pair.add(s);
16+ pair.add(t);
17+ if (i % 1000 == 0) {
18+ keep.add(pair);
19+ }
20+ i += 1;
21+ }
22+ return keep.size();
23+ }
24+
25+ public static void main(String[] args) {
26+ System.out.println(churn(200000));
27+ }
28+}

hearth/ashvm/tests/cases/memory/GcChurn.outadded

+1−0
@@ -0,0 +1 @@
1+200

hearth/ashvm/tests/cases/memory/gc_churn.ashremoved

+0−15
@@ -1,15 +0,0 @@
1-// Allocates ~1.2M short-lived strings, arrays and maps. The default VM never frees them (about 200 MB
2-// here); the experimental collector (make GC=1) keeps the footprint small. Output is identical.
3-forge churn(n) {
4- local keep = [];
5- local i = 0;
6- during i < n {
7- local s = "item-" + str(i);
8- local t = s + "-" + s;
9- local m = {"a": s, "b": [s, t]};
10- given i % 1000 == 0 { push(keep, m); }
11- i += 1;
12- }
13- yield len(keep);
14-}
15-say churn(200000);

hearth/ashvm/tests/cases/strings/affix_ops.ashremoved

+0−16
@@ -1,16 +0,0 @@
1-say contains("hello world", "o w");
2-say contains("hello", "xyz");
3-say contains("hello", "");
4-say starts_with("hello", "he");
5-say starts_with("hello", "hello!");
6-say starts_with("hello", "");
7-say starts_with("hello", "el");
8-say ends_with("hello", "llo");
9-say ends_with("hello", "hell");
10-say ends_with("hello", "");
11-say ends_with("lo", "hello");
12-say repeat("ab", 3);
13-say repeat("x", 0);
14-say repeat("", 5) + "|";
15-say len(repeat("abc", 1000));
16-attempt { repeat("a", -1); } handle (e) { say "neg"; }

hearth/ashvm/tests/cases/strings/chr_ord.ashremoved

+0−7
@@ -1,7 +0,0 @@
1-say ord("A");
2-say chr(97) + chr(98);
3-say ord(chr(200));
4-say chr(ord("z") - 1);
5-local s = "hello";
6-local i = 0;
7-during i < len(s) { say ord(substring(s, i, i + 1)); i++; }

hearth/ashvm/tests/cases/strings/escapes_test.ashremoved

+0−9
@@ -1,9 +0,0 @@
1-say "line one\nline two";
2-say "tab\there";
3-say "quote: \"hello\"";
4-say "backslash: \\";
5-write_file("/tmp/ash_escape_test.txt", "Hello from Ash!\n");
6-local content = read_file("/tmp/ash_escape_test.txt");
7-say content;
8-append_file("/tmp/ash_escape_test.txt", "Second line\n");
9-say read_file("/tmp/ash_escape_test.txt");

hearth/ashvm/tests/cases/strings/string_compare.ashremoved

+0−9
@@ -1,9 +0,0 @@
1-say "a" < "b";
2-say "b" < "a";
3-say "abc" <= "abc";
4-say "abd" > "abc";
5-say "" < "a";
6-say "Z" < "a";
7-say 1 < 2;
8-local s = "m";
9-given s >= "k" { say "fused ok"; }

hearth/ashvm/tests/cases/strings/strings_files_test.ashremoved

+0−19
@@ -1,19 +0,0 @@
1-local parts = split("a,b,c", ",");
2-say parts;
3-say join(parts, "-");
4-say substring("hello world", 0, 5);
5-say indexOf("hello world", "world");
6-say indexOf("hello world", "xyz");
7-say replace("foo bar foo", "foo", "baz");
8-say upper("hello");
9-say lower("WORLD");
10-say trim(" spaced ");
11-
12-write_file("/tmp/ash_test.txt", "Hello from Ash!\n");
13-say file_exists("/tmp/ash_test.txt");
14-local content = read_file("/tmp/ash_test.txt");
15-say content;
16-append_file("/tmp/ash_test.txt", "Second line\n");
17-local content2 = read_file("/tmp/ash_test.txt");
18-say content2;
19-say file_exists("/tmp/nonexistent_file_xyz.txt");

hearth/ashvm/tests/cases/strings/vm_strings_test.ashremoved

+0−12
@@ -1,12 +0,0 @@
1-local name = "Ash";
2-say "Hello, " + name + "!";
3-
4-local a = "abc";
5-local b = "abc";
6-say a == b;
7-say a == "xyz";
8-
9-forge greet(who) {
10- yield "Hi " + who;
11-}
12-say greet("world");

hearth/ashvm/tests/scripts/gc_check.shmodified

+7−6
@@ -1,6 +1,6 @@
11 #!/usr/bin/env bash
22 # ashvm/tests/scripts/gc_check.sh
3-# Checks the collector (make GC=1) against the default VM: (1) every ashvm test case prints exactly
3+# Checks the collector (make GC=1) against the default VM: (1) every test program prints exactly
44 # the same when the collector runs at EVERY safe point (ASH_GC_STRESS=1), (2) a churn program needs
55 # far less memory, (3) the default build contains no collector code. bin/ashvm is rebuilt at the end,
66 # so it is left as `make @ashvm` would leave it (no collector).
@@ -17,14 +17,15 @@ make clean >/dev/null 2>&1; make >/dev/null 2>&1 # restore the default binary
1717 fail=0
1818 if nm "$TMP/default" | grep -q gc_collect; then echo "FAIL default build contains the collector"; fail=1; else echo "OK default build has no collector"; fi
1919
20-for f in tests/cases/*/*.ash; do
20+for f in tests/cases/*/*.ash ../front/tests/cases/run/*_j.ash ../../examples/*.ash; do
2121 d=$(dirname "$f")
22- a=$(cd "$d" && "$TMP/default" "$(basename "$f")" 2>&1; echo "rc=$?")
23- b=$(cd "$d" && ASH_GC_STRESS=1 "$TMP/gc" "$(basename "$f")" 2>&1; echo "rc=$?")
22+ flags=(); case "$f" in *_wrap_*) flags=(--wrap-int);; esac
23+ a=$(cd "$d" && "$TMP/default" run "${flags[@]}" "$(basename "$f")" 2>&1; echo "rc=$?")
24+ b=$(cd "$d" && ASH_GC_STRESS=1 "$TMP/gc" run "${flags[@]}" "$(basename "$f")" 2>&1; echo "rc=$?")
2425 if [ "$a" == "$b" ]; then echo "OK $(basename "$f") (gc stress)"; else echo "FAIL $(basename "$f") differs under GC stress"; fail=1; fi
2526 done
2627
2728 peak() { python3 -c "import resource,subprocess,sys;subprocess.run(sys.argv[1:],stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL);print(resource.getrusage(resource.RUSAGE_CHILDREN).ru_maxrss//1024)" "$@"; }
28-pd=$(peak "$TMP/default" tests/cases/memory/gc_churn.ash); pg=$(peak "$TMP/gc" tests/cases/memory/gc_churn.ash)
29-if [ "$pg" -lt $((pd / 3)) ]; then echo "OK gc_churn peak memory: default ${pd} MB, collector ${pg} MB"; else echo "FAIL gc_churn memory: default ${pd} MB, collector ${pg} MB"; fail=1; fi
29+pd=$(peak "$TMP/default" run tests/cases/memory/GcChurn.ash); pg=$(peak "$TMP/gc" run tests/cases/memory/GcChurn.ash)
30+if [ "$pg" -lt $((pd / 3)) ]; then echo "OK GcChurn peak memory: default ${pd} MB, collector ${pg} MB"; else echo "FAIL GcChurn memory: default ${pd} MB, collector ${pg} MB"; fail=1; fi
3031 exit $fail

hearth/ashvm/tests/scripts/imports_circular_check.shremoved

+0−23
@@ -1,23 +0,0 @@
1-#!/usr/bin/env bash
2-set -uo pipefail
3-cd "$(dirname "$0")/../.."
4-
5-OUT=$(../../bin/ashvm tests/cases/imports/fixtures/imports_circular_a.ash 2>&1)
6-STATUS=$?
7-
8-if [[ $STATUS -eq 0 ]]; then
9- echo "FAIL: expected nonzero exit, got 0"
10- exit 1
11-fi
12-if [[ "$OUT" != *"circular import"* ]]; then
13- echo "FAIL: expected 'circular import' in output, got:"
14- echo "$OUT"
15- exit 1
16-fi
17-if [[ "$OUT" != *"imports_circular_a.ash"* || "$OUT" != *"imports_circular_b.ash"* ]]; then
18- echo "FAIL: expected both file names in the cycle message, got:"
19- echo "$OUT"
20- exit 1
21-fi
22-
23-echo "OK: imports_circular_check"

hearth/ashvm/tests/scripts/imports_collision_check.shremoved

+0−23
@@ -1,23 +0,0 @@
1-#!/usr/bin/env bash
2-set -uo pipefail
3-cd "$(dirname "$0")/../.."
4-
5-OUT=$(../../bin/ashvm tests/cases/imports/fixtures/imports_collision_main.ash 2>&1)
6-STATUS=$?
7-
8-if [[ $STATUS -eq 0 ]]; then
9- echo "FAIL: expected nonzero exit, got 0"
10- exit 1
11-fi
12-if [[ "$OUT" != *"namespace"* ]]; then
13- echo "FAIL: expected 'namespace' in output, got:"
14- echo "$OUT"
15- exit 1
16-fi
17-if [[ "$OUT" != *"collision_dir_one/shared.ash"* || "$OUT" != *"collision_dir_two/shared.ash"* ]]; then
18- echo "FAIL: expected BOTH colliding resolved paths in the message, got:"
19- echo "$OUT"
20- exit 1
21-fi
22-
23-echo "OK: imports_collision_check"

hearth/ashvm/tests/scripts/run_regression.shmodified

+12−51
@@ -1,60 +1,21 @@
11 #!/usr/bin/env bash
2-# ashvm/tests/scripts/run_regression.sh baseline|check
3-# Compiles+runs every ashvm/tests/cases/*/*.ash and diffs stdout against a
4-# captured baseline -- mirrors kiln/tests/scripts/run_regression.sh. ashvm has no
5-# --target/--link flags and no input()-driven test today, so this is
6-# simpler than kiln's version.
2+# ashvm/tests/scripts/run_regression.sh
3+# Runs every program through `ashvm run` and compares stdout+stderr byte for byte with the
4+# sibling .out file. Programs: ashvm/tests/cases/*/*.ash, the shared front-end cases
5+# (front/tests/cases/run/*_j.ash; *_wrap_* need --wrap-int) and ../../examples/*.ash.
76 set -uo pipefail
87 cd "$(dirname "$0")/../.." # -> ashvm/
98
10-MODE="${1:-check}"
11-if [[ "$MODE" != "baseline" && "$MODE" != "check" ]]; then
12- echo "usage: $0 baseline|check" >&2
13- exit 2
14-fi
15-
16-OUTDIR="/tmp/ashvm_regression/$MODE"
17-rm -rf "$OUTDIR"
18-mkdir -p "$OUTDIR"
19-
20-rm -f /tmp/ash_test.txt
21-
229 make -s || { echo "build failed"; exit 1; }
23-
24-for f in tests/cases/*/*.ash; do
25- name=$(basename "$f" .ash)
26- out="$OUTDIR/${name}.out"
27- if ! ../../bin/ashvm "$f" > "$out" 2>&1; then
28- echo "RUN FAIL" >> "$out"
29- fi
30-done
31-
32-if [[ "$MODE" == "baseline" ]]; then
33- echo "baseline captured in $OUTDIR"
34- exit 0
35-fi
10+VM=../../bin/ashvm
11+TMP=$(mktemp -d); trap 'rm -rf "$TMP"' EXIT
3612
3713 fail=0
38-for f in "$OUTDIR"/*.out; do
39- name=$(basename "$f" .out)
40- base="/tmp/ashvm_regression/baseline/${name}.out"
41- if [[ ! -f "$base" ]]; then
42- echo "NEW: $name (no baseline to compare)"
43- continue
44- fi
45- if diff -q "$base" "$f" > /dev/null; then
46- echo "OK: $name"
47- else
48- echo "DIFF: $name"
49- diff "$base" "$f"
50- fail=1
51- fi
14+for f in tests/cases/*/*.ash ../front/tests/cases/run/*_j.ash ../../examples/*.ash; do
15+ flags=()
16+ case "$f" in *_wrap_*) flags=(--wrap-int);; esac
17+ rm -rf /tmp/ash_stdlib_test_dir /tmp/ash_example_io
18+ "$VM" run "${flags[@]}" "$f" > "$TMP/out" 2>&1
19+ if cmp -s "$TMP/out" "${f%.ash}.out"; then echo "OK: $f"; else echo "DIFF: $f"; diff "$TMP/out" "${f%.ash}.out" | head -10; fail=1; fi
5220 done
53-if ! ./tests/scripts/imports_circular_check.sh; then
54- fail=1
55-fi
56-if ! ./tests/scripts/imports_collision_check.sh; then
57- fail=1
58-fi
59-
6021 exit $fail

hearth/front/Makefilemodified

+12−17
@@ -2,10 +2,12 @@ CC = gcc
22 .DEFAULT_GOAL := all
33 CFLAGS = -Wall -Wextra -std=c11 -O2 -Isrc -DASH_STDLIB_DIR=\"$(abspath stdlib)\"
44
5-# Shared front end for new (Java-like) Ash: lexer, parser, AST, type checker and
6-# lowering, linked by both ashvm and kiln (see MIGRATION.md, decision D12).
5+# Shared front end for Ash: lexer, parser, AST, type checker, lowering and the internal IR
6+# lexer, built as libashfront.a and linked by both ashvm and kiln (see MIGRATION.md, D12).
7+# There is no front-end executable: ashvm and kiln are the user-facing tools.
78 # Same layout rule as the other subprojects: src/<sub>/C/x.c -> src/<sub>/O/x.o.
89 FRONT_SRC = \
10+ src/ir/C/ir_lex.c \
911 src/jcommon/C/jcommon.c \
1012 src/jlex/C/jlex.c \
1113 src/jparse/C/jparse_decl.c \
@@ -22,42 +24,35 @@ FRONT_SRC = \
2224 src/jlower/C/lower_class.c \
2325 src/jlower/C/lower_prelude.c \
2426 src/jlower/C/lower_prelude_long.c \
25- src/jlower/C/lower_prune.c
27+ src/jlower/C/lower_prune.c \
28+ src/jdriver/C/jdriver.c \
29+ src/jrepl/C/jrepl.c
2630
2731 obj_of = $(patsubst %.c,%.o,$(subst /C/,/O/,$(1)))
2832 dep_of = $(patsubst %.c,%.d,$(subst /C/,/D/,$(1)))
2933 FRONT_OBJ = $(foreach s,$(FRONT_SRC),$(call obj_of,$(s)))
30-APP_SRC = src/app/C/main.c
31-APP_OBJ = $(foreach s,$(APP_SRC),$(call obj_of,$(s)))
32-ALL_DEP = $(foreach s,$(FRONT_SRC) $(APP_SRC),$(call dep_of,$(s)))
34+ALL_DEP = $(foreach s,$(FRONT_SRC),$(call dep_of,$(s)))
3335
3436 define compile_rule
3537 $(call obj_of,$(1)): $(1)
3638 @mkdir -p $$(dir $$@) $$(dir $(call dep_of,$(1)))
3739 $$(CC) $$(CFLAGS) -MMD -MP -MF $(call dep_of,$(1)) -MT $$@ -c $$< -o $$@
3840 endef
39-$(foreach s,$(FRONT_SRC) $(APP_SRC),$(eval $(call compile_rule,$(s))))
41+$(foreach s,$(FRONT_SRC),$(eval $(call compile_rule,$(s))))
4042
4143 LIB = ../../bin/libashfront.a
42-TOOL = ../../bin/ashfront
4344
44-all: $(LIB) $(TOOL)
45-
46-lib: $(LIB)
45+all: $(LIB)
4746
4847 $(LIB): $(FRONT_OBJ)
4948 mkdir -p ../../bin
5049 ar rcs $@ $(FRONT_OBJ)
5150
52-$(TOOL): $(APP_OBJ) $(LIB)
53- mkdir -p ../../bin
54- $(CC) $(CFLAGS) -o $@ $(APP_OBJ) $(LIB)
55-
5651 -include $(ALL_DEP)
5752
5853 clean:
5954 find src -name '*.o' -delete
6055 find src -name '*.d' -delete
61- rm -f $(LIB) $(TOOL)
56+ rm -f $(LIB)
6257
63-.PHONY: all lib clean
58+.PHONY: all clean

hearth/front/src/app/C/main.cremoved

+0−105
@@ -1,105 +0,0 @@
1-#define _DEFAULT_SOURCE
2-#include <stdio.h>
3-#include <stdlib.h>
4-#include <string.h>
5-#include <sys/stat.h>
6-#include <unistd.h>
7-
8-#include "jcommon/H/jcommon.h"
9-#include "jlower/H/jlower.h"
10-#include "jparse/H/jparse.h"
11-#include "jtypes/H/jtypes.h"
12-
13-/* ashfront: developer tool for the new-Ash front end.
14- * ashfront --parse <file.ash> parse only
15- * ashfront --check <file.ash> parse and type-check (loads the stdlib lazily)
16- * ashfront --lower <file.ash> print the generated old-Ash module
17- * ashfront --run <file.ash> lower and execute on ashvm (found next to ashfront, or $ASHVM)
18- * ashfront --build <file.ash> -o <out> lower and compile to a native binary with kiln ($KILN)
19- * Any mode that lowers also accepts --wrap-int: Java's 32-bit int overflow (about 2x slower arithmetic loops). */
20-
21-static int write_file(const char *path, const char *text) {
22- FILE *f = fopen(path, "wb");
23- if (!f) return -1;
24- fputs(text, f);
25- fclose(f);
26- return 0;
27-}
28-
29-static char *self_dir(const char *argv0) {
30- char *d = j_strdup(argv0);
31- char *slash = strrchr(d, '/');
32- if (slash) *slash = 0;
33- else strcpy(d, ".");
34- return d;
35-}
36-
37-int main(int argc, char **argv) {
38- /* --wrap-int may appear anywhere after the mode; strip it before positional parsing */
39- for (int i = 2; i < argc; i++) {
40- if (!strcmp(argv[i], "--wrap-int")) {
41- jl_wrap_int = 1;
42- for (int j = i; j < argc - 1; j++) argv[j] = argv[j + 1];
43- argc--;
44- i--;
45- }
46- }
47- const char *mode = argc > 1 ? argv[1] : "";
48- int parse = !strcmp(mode, "--parse"), check = !strcmp(mode, "--check");
49- int lower = !strcmp(mode, "--lower"), run = !strcmp(mode, "--run"), build = !strcmp(mode, "--build");
50- if (argc < 3 || !(parse || check || lower || run || build) || (build && (argc < 5 || strcmp(argv[3], "-o") != 0))) {
51- fprintf(stderr, "usage: %s --parse|--check|--lower|--run <file.ash>\n %s --build <file.ash> -o <output>\n", argv[0], argv[0]);
52- return 2;
53- }
54- char *src = j_read_file(argv[2]);
55- if (!src) {
56- fprintf(stderr, "error: cannot read %s\n", argv[2]);
57- return 1;
58- }
59- if (parse) {
60- Node *u = jparse_unit(argv[2], src);
61- printf("parsed %s: %d types\n", argv[2], u->l2.count);
62- return 0;
63- }
64- Node *head = jparse_unit(argv[2], src);
65- jt_init_default_roots(argv[2], head->name);
66- JClass *entry = jt_load_unit(argv[2], src);
67- jt_check_all();
68- if (j_error_count()) {
69- fprintf(stderr, "%d error(s)\n", j_error_count());
70- return 1;
71- }
72- if (check) {
73- printf("checked %s: ok\n", argv[2]);
74- return 0;
75- }
76- char *module = jlower_program(entry);
77- if (!module || j_error_count()) {
78- fprintf(stderr, "%d error(s)\n", j_error_count());
79- return 1;
80- }
81- if (lower) {
82- fputs(module, stdout);
83- return 0;
84- }
85- char dir[] = "/tmp/ashrun_XXXXXX";
86- if (!mkdtemp(dir)) {
87- perror("mkdtemp");
88- return 1;
89- }
90- char *mod_path = j_fmt("%s/prog.ash", dir), *run_path = j_fmt("%s/run.ash", dir);
91- if (write_file(mod_path, module) || write_file(run_path, jlower_driver("prog.ash"))) {
92- fprintf(stderr, "error: cannot write to %s\n", dir);
93- return 1;
94- }
95- if (build) {
96- const char *kiln = getenv("KILN");
97- char *kiln_path = kiln ? j_strdup(kiln) : j_fmt("%s/kiln", self_dir(argv[0]));
98- char *bcmd = j_fmt("'%s' '%s' -o '%s'; rc=$?; rm -rf '%s'; exit $rc", kiln_path, run_path, argv[4], dir);
99- return system(bcmd) == 0 ? 0 : 1;
100- }
101- const char *vm = getenv("ASHVM");
102- char *vm_path = vm ? j_strdup(vm) : j_fmt("%s/ashvm", self_dir(argv[0]));
103- char *cmd = j_fmt("'%s' '%s'; rc=$?; rm -rf '%s'; exit $rc", vm_path, run_path, dir);
104- return system(cmd) == 0 ? 0 : 1;
105-}

hearth/front/src/app/D/.gitkeepremoved

+0−0

No content changes. View the file on GitHub

hearth/front/src/app/O/.gitkeepremoved

+0−0

No content changes. View the file on GitHub

hearth/front/tests/cases/syntax/KitchenSink.ashmodified

+2−2
@@ -92,7 +92,7 @@ public class KitchenSink extends Animal<String> implements Runnable {
9292 x = x >>> 2 << 1;
9393 List<Map<String, Integer>> nested = new ArrayList<>();
9494 int r = flag ? 1 : 2;
95- String s = (String) null;
95+ String? s = (String?) null;
9696 int cast = (int) d;
9797 if (x > 3) {
9898 x++;
@@ -131,7 +131,7 @@ public class KitchenSink extends Animal<String> implements Runnable {
131131 } catch (IllegalArgumentException | IllegalStateException e) {
132132 System.out.println(e.getMessage());
133133 } catch (Exception e) {
134- throw e;
134+ throw new RuntimeException("rethrown", e);
135135 } finally {
136136 x = 0;
137137 }

hearth/front/tests/scripts/check_types.shmodified

+5−5
@@ -1,18 +1,18 @@
11 #!/usr/bin/env bash
2-# Type-checker regression: ok_*_j.ash must check clean, err_*_j.ash must fail and
2+# Type-checker regression (`ashvm check`): ok_*_j.ash must check clean, err_*_j.ash must fail and
33 # print every "// expect: <text>" line of the file.
44 set -u
55 cd "$(dirname "$0")/../.."
6-BIN=../../bin/ashfront
6+VM=../../bin/ashvm
77 dir=tests/cases/types
88 fail=0
99 for f in "$dir"/ok_*_j.ash; do
10- if ! out=$($BIN --check "$f" 2>&1); then
10+ if ! out=$($VM check "$f" 2>&1); then
1111 echo "FAIL $f (expected clean)"; echo "$out"; fail=1
1212 else echo "ok $f"; fi
1313 done
1414 for f in "$dir"/err_*_j.ash; do
15- out=$($BIN --check "$f" 2>&1); rc=$?
15+ out=$($VM check "$f" 2>&1); rc=$?
1616 if [ $rc -eq 0 ]; then echo "FAIL $f (expected errors)"; fail=1; continue; fi
1717 miss=0
1818 while IFS= read -r want; do
@@ -21,6 +21,6 @@ for f in "$dir"/err_*_j.ash; do
2121 if [ $miss -eq 1 ]; then echo "$out"; fail=1; else echo "ok $f"; fi
2222 done
2323 for f in tests/cases/syntax/*.ash ../../main.ash; do
24- if $BIN --parse "$f" >/dev/null 2>&1; then echo "ok $f (parses)"; else echo "FAIL $f (parse)"; fail=1; fi
24+ if $VM check "$f" >/dev/null 2>&1; then echo "ok $f (checks)"; else echo "FAIL $f (check)"; fail=1; fi
2525 done
2626 exit $fail

hearth/front/tests/scripts/run_cases.shremoved

+0−31
@@ -1,31 +0,0 @@
1-#!/usr/bin/env bash
2-# Runtime regression. Every tests/cases/run/*_j.ash and every ../../examples/*.ash is lowered and
3-# executed on ashvm, and its stdout compared byte-for-byte with the matching .out file.
4-# Examples are additionally compiled to a native binary with kiln and compared again.
5-set -u
6-cd "$(dirname "$0")/../.."
7-BIN=../../bin/ashfront
8-TMP=$(mktemp -d)
9-trap 'rm -rf "$TMP"' EXIT
10-fail=0
11-check() { # name act exp
12- if [ "$2" == "$(cat "$3")" ]; then echo "ok $1"; else echo "FAIL $1"; diff <(echo "$2") "$3" | head -20; fail=1; fi
13-}
14-for f in tests/cases/run/*_j.ash; do
15- rm -rf /tmp/ash_stdlib_test_dir
16- flags=""
17- case "$f" in *_wrap_*) flags="--wrap-int";; esac # *_wrap_* tests need Java 32-bit int semantics
18- act=$($BIN --run $flags "$f" 2>&1); check "$f (ashvm $flags)" "$act" "${f%.ash}.out"
19-done
20-for f in ../../examples/*.ash; do
21- n=$(basename "$f" .ash)
22- rm -rf /tmp/ash_example_io
23- act=$($BIN --run "$f" 2>&1); check "examples/$n (ashvm)" "$act" "${f%.ash}.out"
24- if [ -x ../../bin/kiln ]; then
25- rm -rf /tmp/ash_example_io
26- if $BIN --build "$f" -o "$TMP/$n" >"$TMP/$n.err" 2>&1; then
27- act=$("$TMP/$n" 2>&1); check "examples/$n (kiln native)" "$act" "${f%.ash}.out"
28- else echo "FAIL examples/$n (kiln build)"; head -5 "$TMP/$n.err"; fail=1; fi
29- fi
30-done
31-exit $fail

hearth/kiln/tests/cases/basics/bare_reassign.ashremoved

+0−10
@@ -1,10 +0,0 @@
1-forge f(i) {
2- i = i + 1;
3- i = i * 2;
4- yield i;
5-}
6-say f(5);
7-
8-local x = 1;
9-x = x + 10;
10-say x;

hearth/kiln/tests/cases/basics/bitwise.ashremoved

+0−9
@@ -1,9 +0,0 @@
1-say 5 & 3;
2-say 5 | 2;
3-say 5 ^ 1;
4-say 1 << 4;
5-say 256 >> 4;
6-say ~0;
7-say ~5;
8-say -8 >> 1;
9-say (5 & 3) == 1;

hearth/kiln/tests/cases/basics/block_comments.ashremoved

+0−10
@@ -1,10 +0,0 @@
1-/* this is a block comment */
2-say 1;
3-/* multi
4- line
5- comment */
6-say 2;
7-say /* inline */ 3;
8-local x = 5; /* trailing */ say x;
9-// still works
10-say 4;

hearth/kiln/tests/cases/basics/booleans.ashremoved

+0−35
@@ -1,35 +0,0 @@
1-say yes;
2-say no;
3-say 1 < 2;
4-say 2 < 1;
5-say not yes;
6-say not 0;
7-say 1 == 1;
8-say "a" == "a";
9-say "a" == "b";
10-say 1 and 1;
11-say 0 or 1;
12-say yes == 1;
13-say yes == yes;
14-say type(yes);
15-say type(1 < 2);
16-say [yes, no, 3 > 4];
17-say {"ok": yes};
18-say str(no) + str(yes);
19-say has({"a": 1}, "a");
20-say has({"a": 1}, "b");
21-say yes + 1;
22-say file_exists("/nonexistent");
23-say contains("abc", "b");
24-local flag = 5 > 3;
25-given flag { say "flag set"; }
26-given not flag { say "bad"; } otherwise { say "ok"; }
27-say flag and not no;
28-say none == none;
29-say not none;
30-attempt { given {"a": 1} { say "bad"; } } handle (e) { say "map condition"; }
31-attempt { given "x" { say "bad"; } } handle (e) { say "string condition"; }
32-local n = 0;
33-during n < 3 { n++; }
34-say n;
35-say yes ? "t" : "f";

hearth/kiln/tests/cases/basics/compound_assignment.ashremoved

+0−32
@@ -1,32 +0,0 @@
1-local x = 5;
2-x += 3;
3-say x;
4-x -= 2;
5-say x;
6-x *= 4;
7-say x;
8-x /= 3;
9-say x;
10-
11-local s = "hello";
12-s += " world";
13-say s;
14-
15-local i = 0;
16-i++;
17-i++;
18-say i;
19-i--;
20-say i;
21-
22-local total = 0;
23-each (n in [1,2,3,4,5]) {
24- total += n;
25-}
26-say total;
27-
28-local j = 0;
29-during (j < 5) {
30- j++;
31-}
32-say j;

hearth/kiln/tests/cases/basics/exponent.ashremoved

+0−9
@@ -1,9 +0,0 @@
1-say 2 ** 10;
2-say 2 ** 0;
3-say 5 ** 1;
4-say 2 ** -2;
5-say -2 ** 2;
6-say 3 ** 3;
7-say 2 ** 3 ** 2;
8-say 2 ** 3 * 4;
9-say (2 ** 3) * 4;

hearth/kiln/tests/cases/basics/exponent_literals.ashremoved

+0−6
@@ -1,6 +0,0 @@
1-say 1e3;
2-say 1.5e-3;
3-say 2E2 + 1;
4-say num("-1.5e2");
5-say num("1e3") + 1;
6-say num("2.5E-1");

hearth/kiln/tests/cases/basics/floats.ashremoved

+0−22
@@ -1,22 +0,0 @@
1-say 10 / 4;
2-say 0.5;
3-say -3.25;
4-say 1.5 + 2.25;
5-say 0.1 + 0.2;
6-
7-local x = 2.5;
8-say x < 3;
9-say x > 3;
10-
11-forge avg(a, b) {
12- yield (a + b) / 2;
13-}
14-say avg(1, 2);
15-
16-forge half(n) {
17- given (n < 1) {
18- yield n;
19- }
20- yield half(n / 2) + 0.1;
21-}
22-say half(4);

hearth/kiln/tests/cases/basics/hello.ashremoved

+0−1
@@ -1 +0,0 @@
1-say 1 + 2 * 3;

hearth/kiln/tests/cases/basics/math_builtins.ashremoved

+0−8
@@ -1,8 +0,0 @@
1-say sqrt(16);
2-say sqrt(2);
3-say abs(-5.5);
4-say abs(5.5);
5-say floor(3.7);
6-say floor(-3.7);
7-say floor(3.0);
8-say floor(-3.0);

hearth/kiln/tests/cases/basics/modulo.ashremoved

+0−7
@@ -1,7 +0,0 @@
1-say 7 % 3;
2-say -7 % 3;
3-say 7 % -3;
4-say -7 % -3;
5-say 7.5 % 2;
6-say 10 % 2 == 0;
7-say 10 % 3 == 1;

hearth/kiln/tests/cases/basics/number_format.ashremoved

+0−26
@@ -1,26 +0,0 @@
1-say 0;
2-say 3;
3-say -42;
4-say 0.5;
5-say -0.25;
6-say 3.14159265;
7-say 0.1 + 0.2;
8-say 123456789012;
9-say 999999999999999;
10-say 1e15;
11-say 1e21;
12-say -1e21;
13-say 1.5e-7;
14-say 1e-7;
15-say 0.000001;
16-say 0.0000005;
17-say 123456.789;
18-say 1e100;
19-say 1.2345678e30;
20-say 9.9999996;
21-say 0.9999999;
22-say 2.5e-300;
23-say 1 / 0;
24-say -1 / 0;
25-say str(1e21) + "|" + str(1.5) + "|" + str(-7);
26-say [1.5, 1e21, 2];

hearth/kiln/tests/cases/basics/numeric_literals.ashremoved

+0−10
@@ -1,10 +0,0 @@
1-say 0xF;
2-say 0x1A;
3-say 0xFF;
4-say 1e3;
5-say 1.5e2;
6-say 2e-2;
7-say 1_000_000;
8-say 1_000.5;
9-say 0x10 + 1;
10-say 3.14159;

hearth/kiln/tests/cases/basics/ternary.ashremoved

+0−10
@@ -1,10 +0,0 @@
1-say yes ? "yes" : "no";
2-say no ? "yes" : "no";
3-local x = 5;
4-say x > 3 ? "big" : "small";
5-say x < 3 ? "big" : x < 10 ? "medium" : "huge";
6-local m = { "a": yes, "b": no };
7-say m["a"] ? "a is true" : "a is false";
8-forge max(a, b) { yield a > b ? a : b; }
9-say max(3, 7);
10-say max(10, 2);

hearth/kiln/tests/cases/basics/true_false_nil.ashremoved

+0−14
@@ -1,14 +0,0 @@
1-say yes;
2-say no;
3-say none;
4-say yes == 1;
5-say no == 0;
6-say none == none;
7-say none == 0;
8-say none == no;
9-given (yes) { say "yes"; }
10-given (no) { say "no"; } otherwise { say "else"; }
11-local x = none;
12-given (x) { say "truthy"; } otherwise { say "falsy nil"; }
13-local y = yes;
14-say y;

hearth/kiln/tests/cases/basics/type.ashremoved

+0−8
@@ -1,8 +0,0 @@
1-say type(5);
2-say type("hi");
3-say type([1, 2]);
4-say type({"a": 1});
5-say type(none);
6-say type(yes);
7-forge f() { yield 1; }
8-say type(f);

hearth/kiln/tests/cases/basics/unary_not.ashremoved

+0−7
@@ -1,7 +0,0 @@
1-say not no;
2-say not yes;
3-say not 0;
4-say not 5;
5-say not none;
6-say not not 5;
7-given (not no) { say "works"; }

hearth/kiln/tests/cases/collections/array_mutation.ashremoved

+0−16
@@ -1,16 +0,0 @@
1-local a = [1, 2, 3, 4];
2-delete(a, 1);
3-say a;
4-say pop(a);
5-say a;
6-insert(a, 0, 9);
7-insert(a, len(a), 7);
8-insert(a, 1, 8);
9-say a;
10-say slice(a, 1, 3);
11-say slice(a, 0, 0);
12-attempt { pop([]); } handle (e) { say "empty"; }
13-attempt { delete(a, 10); } handle (e) { say "oob"; }
14-local m = {"k": 1};
15-delete(m, "k");
16-say len(m);

hearth/kiln/tests/cases/collections/arrays.ashremoved

+0−28
@@ -1,28 +0,0 @@
1-local a = [1, 2, 3];
2-say a[0];
3-say a[1];
4-say a[2];
5-say len(a);
6-
7-a[0] = 99;
8-say a[0];
9-
10-local b = ["x", "y", "z"];
11-say b[1];
12-
13-local c = [1];
14-push(c, 2);
15-push(c, 3);
16-say len(c);
17-say c[0];
18-say c[1];
19-say c[2];
20-
21-local d = [];
22-local i = 0;
23-during (i < 10) {
24- push(d, i);
25- i = i + 1;
26-}
27-say len(d);
28-say d[9];

hearth/kiln/tests/cases/collections/chained_index_assign.ashremoved

+0−38
@@ -1,38 +0,0 @@
1-// C[i][j] = val -- nested index mutation without a manual intermediate
2-// extraction (local row = C[i]; row[j] = val; C[i] = row;).
3-local a = [[1, 2], [3, 4]];
4-a[0][1] = 99;
5-say a;
6-
7-// three levels deep
8-local b = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]];
9-b[1][0][1] = 999;
10-say b;
11-
12-// matrix-multiply-shaped accumulation: a 2D result built with plain `=`,
13-// not a manual row-then-store dance
14-local n = 3;
15-local c = [[0, 0, 0], [0, 0, 0], [0, 0, 0]];
16-local i = 0;
17-during (i < n) {
18- local j = 0;
19- during (j < n) {
20- c[i][j] = (i * n) + j;
21- j = j + 1;
22- }
23- i = i + 1;
24-}
25-say c;
26-
27-// mixed array/map chain
28-local m = {"row": [1, 2, 3]};
29-m["row"][1] = 42;
30-say m["row"];
31-
32-// plain single-level assignment still works (no regression)
33-local arr = [1, 2, 3];
34-arr[0] = 7;
35-say arr;
36-
37-// a string anywhere in the chain is still immutable
38-attempt { local s = ["hi"]; s[0][0] = "x"; } handle (e) { say "immutable"; }

hearth/kiln/tests/cases/collections/keys_values.ashremoved

+0−15
@@ -1,15 +0,0 @@
1-local m = {"a": 1, "b": 2, "c": 3};
2-local ks = keys(m);
3-local vs = values(m);
4-say len(ks);
5-say len(vs);
6-say ks[0];
7-say ks[1];
8-say ks[2];
9-say vs[0];
10-say vs[1];
11-say vs[2];
12-
13-local empty_m = {};
14-say len(keys(empty_m));
15-say len(values(empty_m));

hearth/kiln/tests/cases/collections/map_order.ashremoved

+0−30
@@ -1,30 +0,0 @@
1-local m = {};
2-m["b"] = 1; m["zeta"] = 2; m["alpha"] = 3; m["a"] = 4; m["mid"] = 5;
3-say keys(m);
4-say values(m);
5-delete(m, "alpha");
6-say keys(m);
7-m["alpha"] = 9;
8-m["b"] = 100;
9-say keys(m);
10-say m;
11-delete(m, "b");
12-delete(m, "zzz");
13-say keys(m);
14-say len(m);
15-say has(m, "b");
16-say has(m, "mid");
17-local big = {};
18-local i = 0;
19-during i < 100 { big[str(i)] = i; i++; }
20-i = 0;
21-during i < 100 { given i % 2 == 0 { delete(big, str(i)); } i++; }
22-say len(big);
23-say big["51"];
24-say keys(big)[0];
25-say keys(big)[49];
26-i = 0;
27-during i < 100 { given i % 2 == 0 { big[str(i)] = i; } i++; }
28-say len(big);
29-say keys(big)[50];
30-say big["98"];

hearth/kiln/tests/cases/collections/maps.ashremoved

+0−31
@@ -1,31 +0,0 @@
1-local m = {"a": 1, "b": 2};
2-say m["a"];
3-say m["b"];
4-
5-m["c"] = 3;
6-say m["c"];
7-
8-m["a"] = 99;
9-say m["a"];
10-
11-say has(m, "b");
12-say has(m, "z");
13-
14-delete(m, "b");
15-say has(m, "b");
16-say m["c"];
17-
18-local g = {};
19-g["a"] = 1;
20-g["b"] = 2;
21-g["c"] = 3;
22-g["d"] = 4;
23-g["e"] = 5;
24-g["f"] = 6;
25-g["g"] = 7;
26-g["h"] = 8;
27-g["i"] = 9;
28-g["j"] = 10;
29-say g["a"];
30-say g["e"];
31-say g["j"];

hearth/kiln/tests/cases/collections/sort.ashremoved

+0−20
@@ -1,20 +0,0 @@
1-local a = [5, 2, 9, 1, 5, 6, -3, 0];
2-sort(a);
3-say a;
4-local s = ["pear", "apple", "fig", "banana", "apple", ""];
5-say sort(s);
6-local m = [{"k": 2, "t": "a"}, {"k": 1, "t": "b"}, {"k": 2, "t": "c"}, {"k": 1, "t": "d"}];
7-sort(m, forge (x, y) { yield x["k"] - y["k"]; });
8-say map(m, forge (x) { yield x["t"]; });
9-say sort([3, 1, 2], forge (x, y) { yield y - x; });
10-say sort([]);
11-say sort([1]);
12-local big = [];
13-local i = 0;
14-during i < 200 { push(big, (i * 37) % 101); i++; }
15-sort(big);
16-local ok = yes;
17-i = 1;
18-during i < len(big) { given big[i - 1] > big[i] { ok = no; } i++; }
19-say ok;
20-say len(big);

hearth/kiln/tests/cases/control_flow/block_scoping.ashremoved

+0−41
@@ -1,41 +0,0 @@
1-local x = 1;
2-given (yes) {
3- local x = 2;
4- say x;
5-}
6-say x;
7-
8-local y = 10;
9-during (y < 13) {
10- local z = y * 2;
11- say z;
12- y = y + 1;
13-}
14-
15-// 20 given-blocks, each declaring 4 UNIQUE-named variables (80 total) --
16-// leaking would exceed MAX_KILN_VARS (64) and fail to compile; scoped
17-// slot reuse keeps this well under the cap. Verified during planning:
18-// this exact file (with the shadowing local above already showing the
19-// bug) fails pre-fix with "error: too many variables" at block index 15.
20-local count = 0;
21-given (yes) { local a0=1; local b0=2; local c0=3; local d0=4; count = count + 1; }
22-given (yes) { local a1=1; local b1=2; local c1=3; local d1=4; count = count + 1; }
23-given (yes) { local a2=1; local b2=2; local c2=3; local d2=4; count = count + 1; }
24-given (yes) { local a3=1; local b3=2; local c3=3; local d3=4; count = count + 1; }
25-given (yes) { local a4=1; local b4=2; local c4=3; local d4=4; count = count + 1; }
26-given (yes) { local a5=1; local b5=2; local c5=3; local d5=4; count = count + 1; }
27-given (yes) { local a6=1; local b6=2; local c6=3; local d6=4; count = count + 1; }
28-given (yes) { local a7=1; local b7=2; local c7=3; local d7=4; count = count + 1; }
29-given (yes) { local a8=1; local b8=2; local c8=3; local d8=4; count = count + 1; }
30-given (yes) { local a9=1; local b9=2; local c9=3; local d9=4; count = count + 1; }
31-given (yes) { local a10=1; local b10=2; local c10=3; local d10=4; count = count + 1; }
32-given (yes) { local a11=1; local b11=2; local c11=3; local d11=4; count = count + 1; }
33-given (yes) { local a12=1; local b12=2; local c12=3; local d12=4; count = count + 1; }
34-given (yes) { local a13=1; local b13=2; local c13=3; local d13=4; count = count + 1; }
35-given (yes) { local a14=1; local b14=2; local c14=3; local d14=4; count = count + 1; }
36-given (yes) { local a15=1; local b15=2; local c15=3; local d15=4; count = count + 1; }
37-given (yes) { local a16=1; local b16=2; local c16=3; local d16=4; count = count + 1; }
38-given (yes) { local a17=1; local b17=2; local c17=3; local d17=4; count = count + 1; }
39-given (yes) { local a18=1; local b18=2; local c18=3; local d18=4; count = count + 1; }
40-given (yes) { local a19=1; local b19=2; local c19=3; local d19=4; count = count + 1; }
41-say count;

hearth/kiln/tests/cases/control_flow/block_scoping_closures.ashremoved

+0−50
@@ -1,50 +0,0 @@
1-// closure created and returned from inside an given-block, capturing a
2-// block-scoped variable; call it after the block, once its slot has
3-// been reused by a later declaration
4-forge make_from_if() {
5- local f = 0;
6- given (yes) {
7- local x = 42;
8- f = forge() { yield x; };
9- }
10- local after = 999; // reuses x's old slot
11- yield f;
12-}
13-local cf = make_from_if();
14-say cf();
15-
16-// closure capturing a variable that shadows an outer same-named one --
17-// the closure must see the INNER value; the outer variable must be
18-// untouched afterward
19-forge make_shadow() {
20- local x = 1;
21- local f = 0;
22- given (yes) {
23- local x = 2;
24- f = forge() { yield x; };
25- }
26- yield [x, f()];
27-}
28-local r = make_shadow();
29-say r[0];
30-say r[1];
31-
32-// closures created inside a during body (compiled once, run 3 times),
33-// each capturing that iteration's own block-scoped value
34-forge make_list() {
35- local fns = [];
36- local i = 0;
37- during (i < 3) {
38- local captured = i;
39- push(fns, forge() { yield captured; });
40- i = i + 1;
41- }
42- yield fns;
43-}
44-local list = make_list();
45-local l0 = list[0];
46-local l1 = list[1];
47-local l2 = list[2];
48-say l0();
49-say l1();
50-say l2();

hearth/kiln/tests/cases/control_flow/break_continue.ashremoved

+0−47
@@ -1,47 +0,0 @@
1-local i = 0;
2-during (i < 10) {
3- i = i + 1;
4- given (i == 5) { stop; }
5- say i;
6-}
7-say "---";
8-
9-local j = 0;
10-during (j < 5) {
11- j = j + 1;
12- given (j == 3) { next; }
13- say j;
14-}
15-say "---";
16-
17-each (x in [1,2,3,4,5]) {
18- given (x == 3) { stop; }
19- say x;
20-}
21-say "---";
22-
23-each (x in [1,2,3,4,5]) {
24- given (x == 3) { next; }
25- say x;
26-}
27-say "---";
28-
29-// nested loops: stop only exits innermost
30-each (i in [1,2]) {
31- each (j in [1,2,3]) {
32- given (j == 2) { stop; }
33- say i * 10 + j;
34- }
35-}
36-say "---";
37-
38-// stop/next inside function's own loop, not affecting caller
39-forge find_first_even(arr) {
40- each (x in arr) {
41- given (x - floor(x/2)*2 == 0) {
42- yield x;
43- }
44- }
45- yield -1;
46-}
47-say find_first_even([1, 3, 5, 4, 7]);

hearth/kiln/tests/cases/control_flow/control_flow.ashremoved

+0−20
@@ -1,20 +0,0 @@
1-local x = 5;
2-x = x + 1;
3-say x;
4-
5-given (x > 5) {
6- say 1;
7-} otherwise {
8- say 0;
9-}
10-
11-local i = 0;
12-during (i < 3) {
13- say i;
14- i = i + 1;
15-}
16-
17-say 1 == 1;
18-say 1 != 1;
19-say (1 < 2) and (3 > 2);
20-say (1 > 2) or (3 < 2);

hearth/kiln/tests/cases/control_flow/for_loop_scoping.ashremoved

+0−15
@@ -1,15 +0,0 @@
1-// loop variable no longer leaks: outer x, same name, must be untouched
2-local x = 9;
3-each (x in [1, 2, 3]) {
4- say x;
5-}
6-say x;
7-
8-// nested each loops with the same variable name at each level -- each
9-// level's binding is independent
10-each (n in [1, 2]) {
11- each (n in [10, 20]) {
12- say n;
13- }
14- say n;
15-}

hearth/kiln/tests/cases/control_flow/for_loops.ashremoved

+0−44
@@ -1,44 +0,0 @@
1-local nums = [10, 20, 30];
2-each (x in nums) {
3- say x;
4-}
5-
6-// nested each loops
7-local a = [1, 2];
8-local b = [10, 20];
9-each (i in a) {
10- each (j in b) {
11- say i * j;
12- }
13-}
14-
15-// each loop calling a higher-order builtin in its body
16-forge double(x) { yield x * 2; }
17-each (x in nums) {
18- local d = map([x], double);
19- say d[0];
20-}
21-
22-// empty array
23-local empty = [];
24-each (x in empty) {
25- say "should not print";
26-}
27-say "after empty loop";
28-
29-// each loop inside a function, recursion-safe check
30-forge sum_array(arr) {
31- local total = 0;
32- each (v in arr) {
33- total = total + v;
34- }
35- yield total;
36-}
37-say sum_array(nums);
38-say sum_array([1, 2, 3, 4, 5]);
39-
40-// loop variable reused/reassignable, doesn't affect iteration
41-each (x in nums) {
42- x = x + 1000;
43- say x;
44-}

hearth/kiln/tests/cases/control_flow/loop_body_locals.ashremoved

+0−42
@@ -1,42 +0,0 @@
1-// A fresh `local` declared inside a re-executed block must not leak across
2-// iterations/branches -- found via a cross-engine audit against kiln.
3-
4-local i = 0;
5-during i < 3 {
6- local x = i * 10;
7- say x;
8- i += 1;
9-}
10-
11-local arr = [1, 2, 3];
12-each n in arr {
13- local y = n * 10;
14- say y;
15-}
16-
17-local j = 0;
18-during j < 6 {
19- given j % 2 == 0 {
20- local a = j * 100;
21- say a;
22- } otherwise {
23- j += 1;
24- next;
25- }
26- j += 1;
27-}
28-
29-each x in arr {
30- given x == 2 { next; }
31- local z = x * 1000;
32- say z;
33-}
34-
35-each outer in [1, 2] {
36- local tmp = outer;
37- each inner in [10, 20] {
38- local tmp2 = outer + inner;
39- say tmp2;
40- }
41- say tmp;
42-}

hearth/kiln/tests/cases/control_flow/short_circuit.ashremoved

+0−11
@@ -1,11 +0,0 @@
1-local a = [1, 2];
2-given 5 < len(a) and a[5] == 1 { say "bad"; } otherwise { say "ok and"; }
3-given 0 < len(a) or a[5] == 1 { say "ok or"; }
4-say 1 and 2;
5-say 0 or 3;
6-say 0 and 1;
7-say 1 or 0;
8-say 1 and 0 or 1;
9-local n = 0;
10-during n < 5 and n != 3 { n++; }
11-say n;

hearth/kiln/tests/cases/control_flow/stop_pops_locals.ashremoved

+0−52
@@ -1,52 +0,0 @@
1-// `stop` leaves a loop whose body declared locals: later locals must still get the right slots.
2-forge plain() {
3- local q = 4;
4- during yes {
5- local t = q;
6- q = t + 1;
7- given q > 5 { stop; }
8- }
9- local s = "n";
10- yield s + str(q);
11-}
12-
13-forge nested() {
14- local q = 0;
15- during yes {
16- local a = q;
17- given a >= 0 {
18- local b = a + 1;
19- given b == 2 { stop; }
20- }
21- q += 1;
22- }
23- local after = "after";
24- yield after + str(q);
25-}
26-
27-forge each_stop() {
28- local last = 0;
29- each x in [1, 2, 3, 4] {
30- local y = x * 2;
31- given y > 4 { stop; }
32- last = y;
33- }
34- local tail = "tail";
35- yield tail + str(last);
36-}
37-
38-forge with_next() {
39- local c = 0;
40- during c < 3 {
41- local t = c;
42- c += 1;
43- given t == 1 { next; }
44- }
45- local done = "done";
46- yield done + str(c);
47-}
48-
49-say plain();
50-say nested();
51-say each_stop();
52-say with_next();

hearth/kiln/tests/cases/errors/attempt_array_delete.ashremoved

+0−10
@@ -1,10 +0,0 @@
1-local a = [1, 2, 3];
2-attempt { delete(a, 0); say "deleted"; say a; push(a, 9); delete(a, 99); say "unreachable"; } handle (e) { say "caught: " + e; }
3-say a;
4-attempt { local m = {"x": 1}; delete(m, "x"); say m; say m["x"]; } handle (e) { say "caught: " + e; }
5-local i = 0;
6-during i < 3 {
7- attempt { delete(a, 10); } handle (e) { say "again: " + e; }
8- i++;
9-}
10-say "end";

hearth/kiln/tests/cases/errors/attempt_stale_handler.ashremoved

+0−21
@@ -1,21 +0,0 @@
1-forge f() {
2- local i = 0;
3- during i < 3 {
4- attempt { local x = 1; } handle (e) { say "inner"; }
5- i++;
6- }
7- raise "boom";
8-}
9-attempt { f(); } handle (e) { say "outer: " + e; }
10-forge g() {
11- attempt { yield 5; } handle (e) { say "no"; }
12-}
13-forge h() { local v = g(); raise "boom2"; }
14-attempt { h(); } handle (e) { say "outer: " + e; }
15-local i = 0;
16-during i < 3 {
17- i++;
18- attempt { next; } handle (e) { say "no"; }
19-}
20-attempt { raise "second"; } handle (e) { say "caught " + e; }
21-say "done";

hearth/kiln/tests/cases/errors/error_message_field.ashremoved

+0−5
@@ -1,5 +0,0 @@
1-attempt { local a = [1]; say a[3]; } handle (e) { say e.message; say "x: " + e; }
2-attempt { raise {"message": "custom", "line": 3}; } handle (e) { say e.message; say e.line; }
3-attempt { raise "plain"; } handle (e) { say e.message == e; }
4-local m = {"inner": {"deep": 7}};
5-say m.inner.deep;

hearth/kiln/tests/cases/errors/error_messages.ashremoved

+0−23
@@ -1,23 +0,0 @@
1-local a = [1, 2];
2-attempt { say a[5]; } handle (e) { say e; }
3-attempt { say {"k": 1}["zz"]; } handle (e) { say e; }
4-attempt { say "abc"[9]; } handle (e) { say e; }
5-attempt { say "x" + 1; } handle (e) { say e; }
6-attempt { say 1 + "x"; } handle (e) { say e; }
7-attempt { say str("t"); } handle (e) { say e; }
8-attempt { pop([]); } handle (e) { say e; }
9-attempt { delete([1], 3); } handle (e) { say e; }
10-attempt { insert([1], 3, 0); } handle (e) { say e; }
11-attempt { slice([1, 2], 1, 5); } handle (e) { say e; }
12-attempt { chr(0); } handle (e) { say e; }
13-attempt { ord(""); } handle (e) { say e; }
14-attempt { repeat("a", -2); } handle (e) { say e; }
15-attempt { read_file("/nonexistent/file"); } handle (e) { say e; }
16-attempt { list_dir("/nonexistent"); } handle (e) { say e; }
17-attempt { given [1] { say "bad"; } } handle (e) { say e; }
18-attempt { raise "custom"; } handle (e) { say e; }
19-attempt { raise {"kind": "parse", "line": 3, "col": 7}; } handle (e) { say e["kind"] + ":" + str(e["line"]) + ":" + str(e["col"]); }
20-attempt { raise [1, 2]; } handle (e) { say e; }
21-attempt { raise 42; } handle (e) { say e + 1; }
22-forge f() { raise {"m": "inner"}; }
23-attempt { f(); } handle (e) { say e["m"]; }

hearth/kiln/tests/cases/errors/throw.ashremoved

+0−22
@@ -1,22 +0,0 @@
1-attempt {
2- raise "custom error!";
3-} handle (e) {
4- say "caught: " + e;
5-}
6-say "after";
7-
8-forge validate(x) {
9- given (x < 0) {
10- raise "negative value: " + str(x);
11- }
12- yield x;
13-}
14-
15-attempt {
16- say validate(5);
17- say validate(-3);
18- say "unreachable";
19-} handle (e) {
20- say "caught: " + e;
21-}
22-say "done";

hearth/kiln/tests/cases/errors/try_catch.ashremoved

+0−49
@@ -1,49 +0,0 @@
1-// basic handle of an out-of-bounds array error, execution continues after
2-local a = [1, 2, 3];
3-attempt {
4- say a[10];
5-} handle (e) {
6- say "caught 1";
7-}
8-say "after 1";
9-
10-// handle of a missing-map-key error
11-local m = {"x": 1};
12-attempt {
13- say m["missing"];
14-} handle (e) {
15- say "caught 2";
16-}
17-say "after 2";
18-
19-// no error raised -- the attempt body's own value still prints, handle is skipped
20-attempt {
21- say 42;
22-} handle (e) {
23- say "should not print";
24-}
25-
26-// nested attempt/handle: inner catches its own error, outer never sees it
27-attempt {
28- attempt {
29- say a[99];
30- } handle (e) {
31- say "inner caught";
32- }
33- say "after inner";
34-} handle (e) {
35- say "outer should not run";
36-}
37-
38-// error raised inside a function called from within a attempt -- unwinds
39-// through the call
40-forge boom() {
41- local z = [1];
42- yield z[5];
43-}
44-attempt {
45- boom();
46-} handle (e) {
47- say "caught from function";
48-}
49-say "done";

hearth/kiln/tests/cases/errors/try_catch_scoping.ashremoved

+0−27
@@ -1,27 +0,0 @@
1-local e = "outer";
2-attempt {
3- raise "inner";
4-} handle (e) {
5- say e;
6-}
7-say e;
8-
9-attempt {
10- say "no error";
11-} handle (e) {
12- say "should not run";
13-}
14-say e;
15-
16-// nested attempt/handle, inner handle variable shadows outer's
17-attempt {
18- attempt {
19- raise "deep";
20- } handle (e) {
21- say e;
22- }
23- say e;
24-} handle (e) {
25- say "outer should not run";
26-}
27-say e;

hearth/kiln/tests/cases/errors/type_errors.ashremoved

+0−6
@@ -1,6 +0,0 @@
1-attempt { say "x" + 1; } handle (e) { say "caught plus"; }
2-attempt { say 1 + "x"; } handle (e) { say "caught plus2"; }
3-attempt { say str("text"); } handle (e) { say "caught str"; }
4-say "a" + "b";
5-say 1 + 2;
6-say str(5);

hearth/kiln/tests/cases/functions/builtins_as_values.ashremoved

+0−9
@@ -1,9 +0,0 @@
1-say type(len);
2-say map([1, 22, 333], str);
3-say map(["a", "bb"], len);
4-say map(["ab", "cd"], upper);
5-say filter([1, 2, 3, 4], forge (x) { yield x > 2; });
6-local f = len;
7-say f("hello");
8-say reduce([1, 2, 3], forge (a, b) { yield a + b; }, 0);
9-say map([4, 9], sqrt);

hearth/kiln/tests/cases/functions/closures.ashremoved

+0−31
@@ -1,31 +0,0 @@
1-// M8: lambda assigned to a variable and called
2-local square = forge(x) { yield x * x; };
3-say square(5);
4-
5-// named function referenced as a value and called indirectly
6-forge add(a, b) { yield a + b; }
7-local op = add;
8-say op(3, 4);
9-
10-// genuine capture: adder-generator (partial application / currying)
11-forge make_adder(n) {
12- yield forge(x) { yield x + n; };
13-}
14-local add5 = make_adder(5);
15-local add10 = make_adder(10);
16-say add5(1);
17-say add10(1);
18-say add5(2);
19-
20-// higher-order function: pass a closure into a plain function
21-forge apply_twice(f, x) {
22- yield f(f(x));
23-}
24-say apply_twice(square, 3);
25-
26-// closure capturing multiple outer variables
27-forge make_scaler(mul, offset) {
28- yield forge(x) { yield x * mul + offset; };
29-}
30-local scale = make_scaler(2, 1);
31-say scale(10);

hearth/kiln/tests/cases/functions/forward_declarations.ashremoved

+0−20
@@ -1,20 +0,0 @@
1-say is_even(10);
2-say is_odd(7);
3-say is_even(7);
4-forge is_even(n) {
5- given n == 0 { yield yes; }
6- yield is_odd(n - 1);
7-}
8-forge is_odd(n) {
9- given n == 0 { yield no; }
10- yield is_even(n - 1);
11-}
12-say twice(3);
13-forge twice(x) { yield helper(x) * 2; }
14-forge helper(x) { yield x + 1; }
15-local f = helper;
16-say f(5);
17-say map([1, 2], twice);
18-forge shadow(a) { yield a; }
19-local shadow = forge (a) { yield a * 100; };
20-say shadow(2);

hearth/kiln/tests/cases/functions/functions.ashremoved

+0−30
@@ -1,30 +0,0 @@
1-forge add(a, b) {
2- yield a + b;
3-}
4-say add(2, 3);
5-
6-forge fact(n) {
7- given (n <= 1) {
8- yield 1;
9- }
10- yield n * fact(n - 1);
11-}
12-say fact(5);
13-
14-forge fib(n) {
15- given (n < 2) {
16- yield n;
17- }
18- yield fib(n - 1) + fib(n - 2);
19-}
20-say fib(10);
21-
22-forge noop() {
23-}
24-say noop();
25-
26-forge square(x) {
27- yield x * x;
28-}
29-local y = 5;
30-say square(y) + square(y + 1);

hearth/kiln/tests/cases/functions/higher_order.ashremoved

+0−26
@@ -1,26 +0,0 @@
1-local nums = [1, 2, 3, 4, 5];
2-
3-forge double(x) { yield x * 2; }
4-local doubled = map(nums, double);
5-say doubled[0];
6-say doubled[1];
7-say doubled[4];
8-say len(doubled);
9-
10-forge is_even(x) { yield x - floor(x / 2) * 2 == 0; }
11-local evens = filter(nums, is_even);
12-say len(evens);
13-say evens[0];
14-say evens[1];
15-
16-forge add(a, b) { yield a + b; }
17-say reduce(nums, add, 0);
18-say reduce(nums, add, 100);
19-
20-local squares = map(nums, forge(x) { yield x * x; });
21-say squares[2];
22-say squares[4];
23-
24-local empty = [];
25-local mapped_empty = map(empty, double);
26-say len(mapped_empty);

hearth/kiln/tests/cases/imports/ash.libs/testlib/testlib.ashremoved

+0−5
@@ -1,5 +0,0 @@
1-local VERSION = "1.0";
2-
3-forge square(x) {
4- yield x * x;
5-}

hearth/kiln/tests/cases/imports/fixtures/collision_dir_one/shared.ashremoved

+0−3
@@ -1,3 +0,0 @@
1-forge fromOne() {
2- yield 1;
3-}

hearth/kiln/tests/cases/imports/fixtures/collision_dir_two/shared.ashremoved

+0−3
@@ -1,3 +0,0 @@
1-forge fromTwo() {
2- yield 2;
3-}

hearth/kiln/tests/cases/imports/fixtures/imports_basic_lib.ashremoved

+0−7
@@ -1,7 +0,0 @@
1-forge helper(x) {
2- yield x * 2;
3-}
4-
5-forge add(a, b) {
6- yield a + b + helper(1);
7-}

hearth/kiln/tests/cases/imports/fixtures/imports_circular_a.ashremoved

+0−5
@@ -1,5 +0,0 @@
1-@import <./imports_circular_b.ash>;
2-
3-forge fromA() {
4- yield 1;
5-}

hearth/kiln/tests/cases/imports/fixtures/imports_circular_b.ashremoved

+0−5
@@ -1,5 +0,0 @@
1-@import <./imports_circular_a.ash>;
2-
3-forge fromB() {
4- yield 2;
5-}

hearth/kiln/tests/cases/imports/fixtures/imports_collision_main.ashremoved

+0−4
@@ -1,4 +0,0 @@
1-@import <./collision_dir_one/shared.ash>;
2-@import <./collision_dir_two/shared.ash>;
3-
4-say shared.fromOne();

hearth/kiln/tests/cases/imports/fixtures/imports_const_lib.ashremoved

+0−6
@@ -1,6 +0,0 @@
1-local PI = 3.14159;
2-local GREETING = "hello from lib";
3-
4-forge circleArea(r) {
5- yield PI * r * r;
6-}

hearth/kiln/tests/cases/imports/fixtures/imports_diamond_b.ashremoved

+0−5
@@ -1,5 +0,0 @@
1-@import <./imports_diamond_d.ash>;
2-
3-forge fromB() {
4- yield imports_diamond_d.base() + 1;
5-}

hearth/kiln/tests/cases/imports/fixtures/imports_diamond_c.ashremoved

+0−5
@@ -1,5 +0,0 @@
1-@import <./imports_diamond_d.ash>;
2-
3-forge fromC() {
4- yield imports_diamond_d.base() + 2;
5-}

hearth/kiln/tests/cases/imports/fixtures/imports_diamond_d.ashremoved

+0−3
@@ -1,3 +0,0 @@
1-forge base() {
2- yield 100;
3-}

hearth/kiln/tests/cases/imports/fixtures/imports_state_lib.ashremoved

+0−15
@@ -1,15 +0,0 @@
1-local DIGITS = "0123456789abcdef";
2-local TABLE = [10, 20, 30];
3-local COUNT = 0;
4-local CONFIG = {"name": "stateful", "level": 2};
5-local DOUBLE = 21 * 2;
6-local ENABLED = yes;
7-
8-forge bump() { COUNT += 1; yield COUNT; }
9-forge hexdigit(n) { yield substring(DIGITS, n, n + 1); }
10-forge table_at(i) { yield TABLE[i]; }
11-forge add_item(v) { push(TABLE, v); yield len(TABLE); }
12-forge set_level(l) { CONFIG["level"] = l; }
13-forge level() { yield CONFIG["level"]; }
14-forge reset() { COUNT = 0; }
15-forge bump2() { COUNT++; yield COUNT; }

hearth/kiln/tests/cases/imports/fixtures/imports_statement_lib.ashremoved

+0−19
@@ -1,19 +0,0 @@
1-// Covers two bugs found writing the first real forgepack module (see
2-// CHANGELOG.md): a `local` inside a loop in an imported function used to
3-// be misdiagnosed as a failed top-level namespaced-constant declaration,
4-// and a namespaced call used as its OWN statement (not nested in an
5-// expression) used to fail to parse entirely.
6-forge sum_doubled(arr) {
7- local total = 0;
8- local i = 0;
9- during i < len(arr) {
10- local doubled = arr[i] * 2;
11- total += doubled;
12- i += 1;
13- }
14- yield total;
15-}
16-
17-forge announce(label) {
18- say "announced: " + label;
19-}

hearth/kiln/tests/cases/imports/fixtures/imports_transitive_mid.ashremoved

+0−3
@@ -1,3 +0,0 @@
1-@import <./imports_basic_lib.ash>;
2-
3-forge mid_triple(x) { yield imports_basic_lib.add(x, imports_basic_lib.add(x, x)); }

hearth/kiln/tests/cases/imports/imports_alias_test.ashremoved

+0−6
@@ -1,6 +0,0 @@
1-@import <./fixtures/imports_basic_lib.ash> as lib;
2-@import <./fixtures/imports_const_lib.ash> as k;
3-
4-say lib.add(3, 4);
5-say lib.helper(10);
6-say k.GREETING;

hearth/kiln/tests/cases/imports/imports_basic.ashremoved

+0−4
@@ -1,4 +0,0 @@
1-@import <./fixtures/imports_basic_lib.ash>;
2-
3-say imports_basic_lib.add(3, 4);
4-say imports_basic_lib.helper(10);

hearth/kiln/tests/cases/imports/imports_const.ashremoved

+0−5
@@ -1,5 +0,0 @@
1-@import <./fixtures/imports_const_lib.ash>;
2-
3-say imports_const_lib.PI;
4-say imports_const_lib.GREETING;
5-say imports_const_lib.circleArea(2);

hearth/kiln/tests/cases/imports/imports_diamond.ashremoved

+0−6
@@ -1,6 +0,0 @@
1-@import <./fixtures/imports_diamond_b.ash>;
2-@import <./fixtures/imports_diamond_c.ash>;
3-
4-say imports_diamond_b.fromB();
5-say imports_diamond_c.fromC();
6-say imports_diamond_d.base();

hearth/kiln/tests/cases/imports/imports_lib.ashremoved

+0−4
@@ -1,4 +0,0 @@
1-@import <testlib>;
2-
3-say testlib.VERSION;
4-say testlib.square(6);

hearth/kiln/tests/cases/imports/imports_state_test.ashremoved

+0−17
@@ -1,17 +0,0 @@
1-@import <./fixtures/imports_state_lib.ash>;
2-
3-say imports_state_lib.bump();
4-say imports_state_lib.bump();
5-say imports_state_lib.hexdigit(11);
6-say imports_state_lib.table_at(1);
7-say imports_state_lib.add_item(40);
8-say imports_state_lib.add_item(50);
9-say imports_state_lib.TABLE;
10-imports_state_lib.set_level(9);
11-say imports_state_lib.level();
12-say imports_state_lib.CONFIG["name"];
13-say imports_state_lib.DOUBLE;
14-say imports_state_lib.ENABLED;
15-imports_state_lib.reset();
16-say imports_state_lib.bump2();
17-say imports_state_lib.COUNT;

hearth/kiln/tests/cases/imports/imports_statement.ashremoved

+0−4
@@ -1,4 +0,0 @@
1-@import <./fixtures/imports_statement_lib.ash>;
2-
3-say imports_statement_lib.sum_doubled([1, 2, 3]);
4-imports_statement_lib.announce("done");

hearth/kiln/tests/cases/imports/imports_transitive_test.ashremoved

+0−5
@@ -1,5 +0,0 @@
1-@import <./fixtures/imports_transitive_mid.ash>;
2-
3-say imports_transitive_mid.mid_triple(4);
4-say imports_basic_lib.add(1, 2);
5-say imports_basic_lib.helper(10);

hearth/kiln/tests/cases/io/argv.ashremoved

+0−6
@@ -1,6 +0,0 @@
1-local args = argv();
2-say len(args);
3-say args[0];
4-each (a in args) {
5- say a;
6-}

hearth/kiln/tests/cases/io/file_io.ashremoved

+0−7
@@ -1,7 +0,0 @@
1-local path = "/tmp/kiln_file_test.txt";
2-say file_exists(path);
3-say write_file(path, "hello, file!\nsecond line");
4-say file_exists(path);
5-say read_file(path);
6-say append_file(path, "\nappended");
7-say read_file(path);

hearth/kiln/tests/cases/io/fs_ops.ashremoved

+0−15
@@ -1,15 +0,0 @@
1-local d = "/tmp/ash_fs_test_dir";
2-delete_file(d + "/b.txt"); delete_file(d + "/a.txt"); delete_file(d + "/c.txt");
3-make_dir(d);
4-say file_exists(d + "/a.txt");
5-write_file(d + "/a.txt", "hello");
6-write_file(d + "/b.txt", "world");
7-say rename_file(d + "/b.txt", d + "/c.txt");
8-say rename_file(d + "/nope.txt", d + "/x.txt");
9-say sort(list_dir(d));
10-say read_file(d + "/c.txt");
11-say delete_file(d + "/a.txt");
12-say delete_file(d + "/a.txt");
13-say delete_file(d + "/c.txt");
14-say list_dir(d);
15-attempt { list_dir(d + "/missing"); } handle (e) { say "no dir"; }

hearth/kiln/tests/cases/io/input_builtin.ashremoved

+0−4
@@ -1,4 +0,0 @@
1-local name = input();
2-say "hello, " + name + "!";
3-local x = num(input());
4-say x + 1;

hearth/kiln/tests/cases/memory/HeapGrowth.ashadded

+16−0
@@ -0,0 +1,16 @@
1+package memory;
2+
3+/// Allocates well past the old fixed 16MB bump-heap cap (each iteration leaks a fresh 4-element
4+/// array, nothing is ever freed) to exercise the allocator's dynamic growth instead of segfaulting.
5+class HeapGrowth {
6+ public static void main(String[] args) {
7+ int total = 0;
8+ int i = 0;
9+ while (i < 2000000) {
10+ int[] arr = { i, i + 1, i + 2, i + 3 };
11+ total = total + arr[0];
12+ i = i + 1;
13+ }
14+ System.out.println(total);
15+ }
16+}

hearth/kiln/tests/cases/memory/HeapGrowth.outadded

+1−0
@@ -0,0 +1 @@
1+1999999000000

hearth/kiln/tests/cases/memory/heap_growth.ashremoved

+0−11
@@ -1,11 +0,0 @@
1-// Allocates well past the old fixed 16MB bump-heap cap (each iteration
2-// leaks a fresh 4-element array, nothing is ever freed) to exercise the
3-// allocator's dynamic growth instead of segfaulting partway through.
4-local total = 0;
5-local i = 0;
6-during (i < 2000000) {
7- local arr = [i, i + 1, i + 2, i + 3];
8- total = total + arr[0];
9- i = i + 1;
10-}
11-say total;

hearth/kiln/tests/cases/strings/affix_ops.ashremoved

+0−16
@@ -1,16 +0,0 @@
1-say contains("hello world", "o w");
2-say contains("hello", "xyz");
3-say contains("hello", "");
4-say starts_with("hello", "he");
5-say starts_with("hello", "hello!");
6-say starts_with("hello", "");
7-say starts_with("hello", "el");
8-say ends_with("hello", "llo");
9-say ends_with("hello", "hell");
10-say ends_with("hello", "");
11-say ends_with("lo", "hello");
12-say repeat("ab", 3);
13-say repeat("x", 0);
14-say repeat("", 5) + "|";
15-say len(repeat("abc", 1000));
16-attempt { repeat("a", -1); } handle (e) { say "neg"; }

hearth/kiln/tests/cases/strings/chr_ord.ashremoved

+0−7
@@ -1,7 +0,0 @@
1-say ord("A");
2-say chr(97) + chr(98);
3-say ord(chr(200));
4-say chr(ord("z") - 1);
5-local s = "hello";
6-local i = 0;
7-during i < len(s) { say ord(substring(s, i, i + 1)); i++; }

hearth/kiln/tests/cases/strings/convert_builtins.ashremoved

+0−10
@@ -1,10 +0,0 @@
1-say str(42);
2-say str(3.5);
3-say str(-7.25);
4-say str(0);
5-say num("42");
6-say num("3.5");
7-say num("-7.25");
8-say num(" 12.5abc");
9-say num("abc");
10-say num(str(123.456));

hearth/kiln/tests/cases/strings/string_builtins2.ashremoved

+0−14
@@ -1,14 +0,0 @@
1-say upper("hello world");
2-say lower("HELLO WORLD");
3-say upper("Already Mixed 123!");
4-say trim(" hi there ");
5-say trim("no spaces");
6-say trim(" ");
7-say substring("hello world", 0, 5);
8-say substring("hello world", 6, 11);
9-say substring("hello world", -3, 100);
10-say substring("hello world", 8, 3);
11-say indexOf("hello world", "world");
12-say indexOf("hello world", "xyz");
13-say indexOf("hello world", "");
14-say indexOf("hello world", "hello world");

hearth/kiln/tests/cases/strings/string_builtins3.ashremoved

+0−27
@@ -1,27 +0,0 @@
1-local parts = split("a,b,c", ",");
2-say len(parts);
3-say parts[0];
4-say parts[1];
5-say parts[2];
6-
7-local chars = split("abc", "");
8-say len(chars);
9-say chars[0];
10-say chars[2];
11-
12-local empty1 = split("", ",");
13-say len(empty1);
14-say empty1[0];
15-
16-local empty2 = split("", "");
17-say len(empty2);
18-
19-say join(["a", "b", "c"], "-");
20-say join(["x"], ",");
21-say join([], ",");
22-
23-say replace("hello world", "world", "there");
24-say replace("aaa", "a", "bb");
25-say replace("hello", "xyz", "abc");
26-say replace("hello", "", "X");
27-say replace("banana", "a", "o");

hearth/kiln/tests/cases/strings/string_compare.ashremoved

+0−9
@@ -1,9 +0,0 @@
1-say "a" < "b";
2-say "b" < "a";
3-say "abc" <= "abc";
4-say "abd" > "abc";
5-say "" < "a";
6-say "Z" < "a";
7-say 1 < 2;
8-local s = "m";
9-given s >= "k" { say "fused ok"; }

hearth/kiln/tests/cases/strings/string_index.ashremoved

+0−17
@@ -1,17 +0,0 @@
1-local s = "hello";
2-say s[0];
3-say s[4];
4-say s[1] + s[2];
5-
6-attempt {
7- say s[10];
8-} handle (e) {
9- say "caught: " + e;
10-}
11-
12-attempt {
13- s[0] = "H";
14-} handle (e) {
15- say "caught: " + e;
16-}
17-say "done";

hearth/kiln/tests/cases/strings/strings.ashremoved

+0−37
@@ -1,37 +0,0 @@
1-say "hello";
2-say "hello, " + "ash!";
3-
4-local s = "x";
5-say s == "x";
6-say s == "y";
7-say s != "x";
8-
9-local a = "foo";
10-local b = "bar";
11-say a + b;
12-
13-say "line1\nline2";
14-say "quote: \"hi\"";
15-
16-forge greet(name) {
17- yield "hello, " + name;
18-}
19-say greet("world");
20-
21-local x = "a";
22-x = x + "b";
23-x = x + "c";
24-say x;
25-
26-forge repeat(s, n) {
27- given (n <= 0) {
28- yield "";
29- }
30- yield s + repeat(s, n - 1);
31-}
32-say repeat("ab", 5);
33-
34-local n = 5;
35-say n;
36-say s + "test";
37-say n + 1;

hearth/kiln/tests/scripts/imports_circular_check.shremoved

+0−26
@@ -1,26 +0,0 @@
1-#!/usr/bin/env bash
2-# kiln/tests/scripts/imports_circular_check.sh -- not part of run_regression.sh's
3-# stdout-diff loop, since this test asserts a COMPILE FAILURE with
4-# specific message content, not a successful program's stdout.
5-set -uo pipefail
6-cd "$(dirname "$0")/../.."
7-
8-OUT=$(../../bin/kiln tests/cases/imports/fixtures/imports_circular_a.ash -o /tmp/imports_circular_a 2>&1)
9-STATUS=$?
10-
11-if [[ $STATUS -eq 0 ]]; then
12- echo "FAIL: expected nonzero exit, got 0"
13- exit 1
14-fi
15-if [[ "$OUT" != *"circular import"* ]]; then
16- echo "FAIL: expected 'circular import' in output, got:"
17- echo "$OUT"
18- exit 1
19-fi
20-if [[ "$OUT" != *"imports_circular_a.ash"* || "$OUT" != *"imports_circular_b.ash"* ]]; then
21- echo "FAIL: expected both file names in the cycle message, got:"
22- echo "$OUT"
23- exit 1
24-fi
25-
26-echo "OK: imports_circular_check"

hearth/kiln/tests/scripts/imports_collision_check.shremoved

+0−27
@@ -1,27 +0,0 @@
1-#!/usr/bin/env bash
2-# kiln/tests/scripts/imports_collision_check.sh -- asserts BOTH resolved paths
3-# appear in the error message, not just that a compile error fires (see
4-# the design spec's "Testing plan" section -- with no `as` clause to
5-# disambiguate, this message is the only diagnostic a user gets).
6-set -uo pipefail
7-cd "$(dirname "$0")/../.."
8-
9-OUT=$(../../bin/kiln tests/cases/imports/fixtures/imports_collision_main.ash -o /tmp/imports_collision_main 2>&1)
10-STATUS=$?
11-
12-if [[ $STATUS -eq 0 ]]; then
13- echo "FAIL: expected nonzero exit, got 0"
14- exit 1
15-fi
16-if [[ "$OUT" != *"namespace"* ]]; then
17- echo "FAIL: expected 'namespace' in output, got:"
18- echo "$OUT"
19- exit 1
20-fi
21-if [[ "$OUT" != *"collision_dir_one/shared.ash"* || "$OUT" != *"collision_dir_two/shared.ash"* ]]; then
22- echo "FAIL: expected BOTH colliding resolved paths in the message, got:"
23- echo "$OUT"
24- exit 1
25-fi
26-
27-echo "OK: imports_collision_check"

hearth/kiln/tests/scripts/run_regression.shmodified

+16−50
@@ -1,59 +1,25 @@
11 #!/usr/bin/env bash
2-# kiln/tests/scripts/run_regression.sh baseline|check
2+# kiln/tests/scripts/run_regression.sh
3+# Compiles every program to a native Linux binary and compares its stdout+stderr byte for byte
4+# with the sibling .out file. Programs: kiln/tests/cases/*/*.ash, the shared front-end cases
5+# (front/tests/cases/run/*_j.ash; *_wrap_* need --wrap-int) and ../../examples/*.ash.
36 set -uo pipefail
47 cd "$(dirname "$0")/../.." # -> kiln/
58
6-MODE="${1:-check}"
7-if [[ "$MODE" != "baseline" && "$MODE" != "check" ]]; then
8- echo "usage: $0 baseline|check" >&2
9- exit 2
10-fi
11-
12-OUTDIR="/tmp/kiln_regression/$MODE"
13-BINDIR="/tmp/kiln_regression/bin"
14-rm -rf "$OUTDIR"
15-mkdir -p "$OUTDIR"
16-mkdir -p "$BINDIR"
17-
18-# Clean up test files that don't clean up after themselves
19-rm -f /tmp/kiln_file_test.txt
20-
219 make -s || { echo "build failed"; exit 1; }
10+KILN=../../bin/kiln
11+TMP=$(mktemp -d); trap 'rm -rf "$TMP"' EXIT
2212
2313 fail=0
24-for f in tests/cases/*/*.ash; do
25- name=$(basename "$f" .ash)
26- bin="$BINDIR/${name}.bin"
27- out="$OUTDIR/${name}.out"
28- if ! ../../bin/kiln "$f" -o "$bin" > "$out" 2>&1; then
29- echo "COMPILE FAIL" >> "$out"
30- continue
31- fi
32- if [[ "$name" == "input_builtin" ]]; then
33- printf 'World\n5\n' | "$bin" >> "$out" 2>&1
34- else
35- "$bin" >> "$out" 2>&1
36- fi
37-done
38-
39-if [[ "$MODE" == "baseline" ]]; then
40- echo "baseline captured in $OUTDIR"
41- exit 0
42-fi
43-
44-for f in "$OUTDIR"/*.out; do
45- name=$(basename "$f" .out)
46- base="/tmp/kiln_regression/baseline/${name}.out"
47- if [[ ! -f "$base" ]]; then
48- echo "NEW: $name (no baseline to compare)"
49- continue
50- fi
51- if diff -q "$base" "$f" > /dev/null; then
52- echo "OK: $name"
53- else
54- echo "DIFF: $name"
55- diff "$base" "$f"
56- fail=1
57- fi
14+for f in tests/cases/*/*.ash ../front/tests/cases/run/*_j.ash ../../examples/*.ash; do
15+ n=$(basename "$f" .ash)
16+ # kiln's native runtime prints doubles with 7 significant digits, not Java's shortest round-trip form
17+ [ "$n" == run_double_j ] && continue
18+ flags=()
19+ case "$f" in *_wrap_*) flags=(--wrap-int);; esac
20+ if ! "$KILN" "$f" -o "$TMP/$n" "${flags[@]}" > "$TMP/$n.err" 2>&1; then echo "COMPILE FAIL: $f"; head -5 "$TMP/$n.err"; fail=1; continue; fi
21+ rm -rf /tmp/ash_stdlib_test_dir /tmp/ash_example_io
22+ "$TMP/$n" > "$TMP/$n.out" 2>&1 < /dev/null
23+ if cmp -s "$TMP/$n.out" "${f%.ash}.out"; then echo "OK: $f"; else echo "DIFF: $f"; diff "$TMP/$n.out" "${f%.ash}.out" | head -10; fail=1; fi
5824 done
5925 exit $fail

hearth/kiln/tests/scripts/shared_link_check.shmodified

+10−52
@@ -1,83 +1,41 @@
11 #!/usr/bin/env bash
22 # kiln/tests/scripts/shared_link_check.sh
33 #
4-# --link=shared had NO automated coverage at all before this (run_regression.sh
5-# only ever compiles with kiln's default --link=static) -- this fills that
6-# gap generally, and specifically covers matrix_mul (codegen/C/collections/matrix_mul.c,
7-# elf/H/elf_dynamic.h's second DT_NEEDED for libpyre.so), the one builtin
8-# that only exists under --link=shared at all.
4+# --link=shared coverage (run_regression.sh only compiles with kiln's default --link=static).
95 #
10-# 1. Rebuilds kiln, libkilnrt.so, and libpyre.so, installing both at
11-# kiln's hardcoded rpath (KILN_RPATH, elf/H/elf_dynamic.h) -- there is
12-# no env-var override, so this writes to /usr/local/lib/kiln for real,
13-# same as doing it by hand.
14-# 2. Compiles a sample of ordinary test cases BOTH --link=static and
15-# --link=shared and diffs their output -- proving the two modes agree
16-# wherever both can run a program, which also means the second
17-# DT_NEEDED and the combined GOT/hash/dynsym table didn't disturb
18-# kiln's own existing runtime imports (heap_alloc, print_top, ...).
19-# 3. Compiles and runs a small matrix_mul program (inline here, not under
20-# tests/cases/ -- run_regression.sh's tests/cases/*/*.ash glob would
21-# pick it up and "COMPILE FAIL" with kiln's default --link=static,
22-# which is correct behavior but not what that suite is for) under
23-# --link=shared, and separately confirms --link=static rejects it with
24-# a clear compile error instead of silently ignoring it.
6+# 1. Rebuilds kiln and libkilnrt.so, installing it at kiln's hardcoded rpath (KILN_RPATH,
7+# elf/H/elf_dynamic.h) -- there is no env-var override, so this writes to /usr/local/lib/kiln
8+# for real, same as doing it by hand.
9+# 2. Compiles a sample of programs BOTH --link=static and --link=shared and diffs their output --
10+# proving the two modes agree wherever both can run a program, which also means the combined
11+# GOT/hash/dynsym table didn't disturb kiln's own runtime imports (heap_alloc, print_top, ...).
2512 set -uo pipefail
2613 cd "$(dirname "$0")/../.." # -> kiln/
2714
2815 make -s || { echo "build failed"; exit 1; }
2916 ../../bin/kiln --emit-runtime -o /usr/local/lib/kiln/libkilnrt.so || { echo "emit-runtime failed"; exit 1; }
30-(cd ../pyre && make -s lib) || { echo "pyre build failed"; exit 1; }
3117
3218 OUTDIR=/tmp/kiln_shared_check
3319 rm -rf "$OUTDIR"
3420 mkdir -p "$OUTDIR"
3521
3622 fail=0
3723
38-for f in tests/cases/basics/*.ash tests/cases/collections/*.ash tests/cases/strings/*.ash; do
24+for f in ../front/tests/cases/run/run_lang_j.ash ../front/tests/cases/run/run_oop_j.ash ../front/tests/cases/run/run_stdlib_j.ash ../../examples/*.ash; do
3925 name=$(basename "$f" .ash)
4026 static_out="$OUTDIR/${name}.static.out"
4127 shared_out="$OUTDIR/${name}.shared.out"
4228 ../../bin/kiln "$f" -o "$OUTDIR/${name}.static" --link=static > "$static_out" 2>&1
4329 ../../bin/kiln "$f" -o "$OUTDIR/${name}.shared" --link=shared > "$shared_out" 2>&1
44- if [[ "$name" == "input_builtin" ]]; then
45- printf 'World\n5\n' | timeout 10 "$OUTDIR/${name}.static" >> "$static_out" 2>&1
46- printf 'World\n5\n' | timeout 10 "$OUTDIR/${name}.shared" >> "$shared_out" 2>&1
47- else
48- timeout 10 "$OUTDIR/${name}.static" >> "$static_out" 2>&1
49- timeout 10 "$OUTDIR/${name}.shared" >> "$shared_out" 2>&1
50- fi
30+ timeout 10 "$OUTDIR/${name}.static" >> "$static_out" 2>&1 < /dev/null
31+ timeout 10 "$OUTDIR/${name}.shared" >> "$shared_out" 2>&1 < /dev/null
5132 if ! diff -q "$static_out" "$shared_out" > /dev/null; then
5233 echo "MISMATCH: $name (static vs shared)"
5334 diff "$static_out" "$shared_out"
5435 fail=1
5536 fi
5637 done
5738
58-cat > "$OUTDIR/matrix_mul_shared.ash" << 'EOF'
59-local a = [[1, 2], [3, 4]];
60-local b = [[5, 6], [7, 8]];
61-say matrix_mul(a, b);
62-EOF
63-
64-../../bin/kiln "$OUTDIR/matrix_mul_shared.ash" -o "$OUTDIR/matrix_mul_shared.bin" --link=shared > "$OUTDIR/matrix_mul_shared.out" 2>&1
65-timeout 10 "$OUTDIR/matrix_mul_shared.bin" >> "$OUTDIR/matrix_mul_shared.out" 2>&1
66-if ! grep -qF '[[19, 22], [43, 50]]' "$OUTDIR/matrix_mul_shared.out"; then
67- echo "MISMATCH: matrix_mul under --link=shared did not produce the expected result"
68- cat "$OUTDIR/matrix_mul_shared.out"
69- fail=1
70-fi
71-
72-if ../../bin/kiln "$OUTDIR/matrix_mul_shared.ash" -o "$OUTDIR/matrix_mul_static.bin" --link=static > "$OUTDIR/matrix_mul_static_reject.out" 2>&1; then
73- echo "MISMATCH: matrix_mul under --link=static should have been rejected at compile time, but compiled"
74- fail=1
75-elif ! grep -q "requires --link=shared" "$OUTDIR/matrix_mul_static_reject.out"; then
76- echo "MISMATCH: matrix_mul --link=static rejection message changed unexpectedly"
77- cat "$OUTDIR/matrix_mul_static_reject.out"
78- fail=1
79-fi
80-
8139 if [[ $fail -eq 0 ]]; then
8240 echo "shared_link_check: OK"
8341 else

hearth/kiln/tests/scripts/windows_emulated_check.shmodified

+2−2
@@ -15,9 +15,9 @@ fi
1515 make -s || { echo "build failed"; exit 1; }
1616 OUT=/tmp/kiln_winemu_out; mkdir -p "$OUT"
1717 pass=0; fail=0
18-for f in tests/cases/*/*.ash; do
18+for f in tests/cases/*/*.ash ../front/tests/cases/run/*_j.ash ../../examples/*.ash; do
1919 n=$(basename "$f" .ash); d=$(dirname "$f")
20- case $n in argv|input*|*circular*|*collision*) continue;; esac # need real arguments / stdin / expected failure
20+ case $n in *_wrap_*|run_double_j) continue;; esac # need --wrap-int / print doubles differently on kiln
2121 rm -rf /tmp/ash_fs_test_dir
2222 (cd "$d" && "$KILN" "$n.ash" -o "$OUT/lin_$n" >/dev/null 2>&1 && "$KILN" "$n.ash" -o "$OUT/win_$n.exe" --target=windows >/dev/null 2>&1) || { echo "COMPILE-FAIL: $n"; fail=$((fail + 1)); continue; }
2323 (cd "$d" && timeout 120 "$OUT/lin_$n" < /dev/null > "$OUT/lin_$n.out" 2>&1)

hearth/kiln/tests/scripts/windows_wine_check.shmodified

+2−2
@@ -15,9 +15,9 @@ export WINEPREFIX="${WINEPREFIX:-$HOME/.cache/ash_wine_prefix}" WINEDEBUG=-all W
1515 make -s || { echo "build failed"; exit 1; }
1616 OUT=/tmp/kiln_wine_out; mkdir -p "$OUT"
1717 pass=0; fail=0
18-for f in tests/cases/*/*.ash; do
18+for f in tests/cases/*/*.ash ../front/tests/cases/run/*_j.ash ../../examples/*.ash; do
1919 n=$(basename "$f" .ash); d=$(dirname "$f")
20- case $n in argv|input*|*circular*|*collision*) continue;; esac # need real arguments / stdin / expected failure
20+ case $n in *_wrap_*|run_double_j) continue;; esac # need --wrap-int / print doubles differently on kiln
2121 rm -rf /tmp/ash_fs_test_dir
2222 (cd "$d" && "$KILN" "$n.ash" -o "$OUT/lin_$n" >/dev/null 2>&1 && "$KILN" "$n.ash" -o "$OUT/win_$n.exe" --target=windows >/dev/null 2>&1) || { echo "COMPILE-FAIL: $n"; fail=$((fail + 1)); continue; }
2323 (cd "$d" && timeout 120 "$OUT/lin_$n" < /dev/null > "$OUT/lin_$n.out" 2>&1)