diff options
| author | 2026-10-15 17:03:03 +0330 | |
|---|---|---|
| committer | 2026-10-15 17:03:03 +0330 | |
| commit | 7cb983bbea98d2038b2a8015a6d1f1afd40991c9 (patch) | |
| tree | ec3d88a15801207fc6d8d3c6d142617ffec85460 /tests | |
| parent | merge work/borrow: borrow returns before definition, borrows clause, borrow m... (diff) | |
| parent | bench: rss probe path fix (diff) | |
merge work/actors: wasm seed bootstrap (seed/MANIFEST), shared copy-on-write actor memory, top-level hold blocks on all backends and lsp
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/bench/bench_bytes.sh | 2 | ||||
| -rw-r--r-- | tests/bench/bench_share.sh | 2 | ||||
| -rw-r--r-- | tests/bench/bench_strings.sh | 2 | ||||
| -rw-r--r-- | tests/bench/rss/a0.zc | 11 | ||||
| -rw-r--r-- | tests/bench/rss/a10.zc | 11 | ||||
| -rw-r--r-- | tests/bench/rss/a100.zc | 11 | ||||
| -rw-r--r-- | tests/bench/rss/measure.py | 13 | ||||
| -rw-r--r-- | tests/drivers/hold_lsp_test.js | 54 | ||||
| -rw-r--r-- | tests/drivers/hold_test.py | 28 | ||||
| -rw-r--r-- | tests/drivers/imagekit.py | 2 | ||||
| -rw-r--r-- | tests/hold/accept/isolated_globals.zc | 18 | ||||
| -rw-r--r-- | tests/hold/accept/monitor.zc | 15 | ||||
| -rw-r--r-- | tests/hold/accept/race.zc | 21 | ||||
| -rw-r--r-- | tests/hold/accept/rank_order.zc | 7 | ||||
| -rw-r--r-- | tests/hold/accept/reentrant.zc | 12 | ||||
| -rw-r--r-- | tests/hold/reject/actor_handler.zc | 8 | ||||
| -rw-r--r-- | tests/hold/reject/closure.zc | 5 | ||||
| -rw-r--r-- | tests/hold/reject/nested.zc | 5 | ||||
| -rw-r--r-- | tests/hold/reject/o3.zc | 5 | ||||
| -rw-r--r-- | tests/hold/reject/order.zc | 7 | ||||
| -rw-r--r-- | tests/hold/reject/outside.zc | 5 | ||||
| -rw-r--r-- | tests/hold/reject/pointer.zc | 5 | ||||
| -rwxr-xr-x | tests/test.sh | 25 | ||||
| -rw-r--r-- | tests/xref.baseline | 8 |
24 files changed, 272 insertions, 10 deletions
diff --git a/tests/bench/bench_bytes.sh b/tests/bench/bench_bytes.sh index 775b71d..c509da4 100644 --- a/tests/bench/bench_bytes.sh +++ b/tests/bench/bench_bytes.sh @@ -10,7 +10,7 @@ T=$(mktemp -d) trap 'rm -rf "$T"' EXIT $CC -O2 -w src/tools/genmap.c -o "$T/genmap" || exit 1 GENMAP="$T/genmap" bash src/tools/automap.sh run "$T/run" src/runtime/run.zc tests/programs/bench_bytes.zc >/dev/null || exit 1 -cp src/micro/micro.c src/micro/micro_port.h src/micro/port_linux.c src/core/core.c src/core/io_linux.c src/core/fops.h src/core/bops.h src/core/stack.h src/core/genome.h "$T/run/" +cp src/micro/micro.c src/micro/micro_port.h src/micro/port_linux.c src/core/core.c src/core/io_linux.c src/core/fops.h src/core/bops.h src/core/stack.h src/core/hold.h src/core/genome.h "$T/run/" $CC -O2 -w -DJTYPE=int "$T/run/core.c" "$T/run/io_linux.c" -o "$T/zy" || exit 1 $CC -O2 -w "$T/run/micro.c" "$T/run/port_linux.c" -o "$T/zym" || exit 1 vms=("$T/zy" "$T/zym"); names=("interp" "micro") diff --git a/tests/bench/bench_share.sh b/tests/bench/bench_share.sh index 5cb1bfd..c47f5f5 100644 --- a/tests/bench/bench_share.sh +++ b/tests/bench/bench_share.sh @@ -8,7 +8,7 @@ T=$(mktemp -d) trap 'rm -rf "$T"' EXIT $CC -O2 -w src/tools/genmap.c -o "$T/genmap" || exit 1 "$T/genmap" --preset run -o "$T/run" >/dev/null || exit 1 -cp src/tools/zc0.c src/micro/micro.c src/micro/micro_port.h src/micro/port_linux.c src/core/core.c src/core/io_linux.c src/core/fops.h src/core/bops.h src/core/stack.h src/core/genome.h "$T/run/" +cp src/tools/zc0.c src/micro/micro.c src/micro/micro_port.h src/micro/port_linux.c src/core/core.c src/core/io_linux.c src/core/fops.h src/core/bops.h src/core/stack.h src/core/hold.h src/core/genome.h "$T/run/" $CC -O1 -w "$T/run/zc0.c" -o "$T/zc0" || exit 1 cat "$T/run/rt.zc" src/core/core.zc src/runtime/run.zc tests/programs/bench_share.zc | "$T/zc0" > "$T/run/genome.bin" || exit 1 $CC -O2 -w -DJTYPE=int "$T/run/core.c" "$T/run/io_linux.c" -o "$T/zy" || exit 1 diff --git a/tests/bench/bench_strings.sh b/tests/bench/bench_strings.sh index b14bf57..8bf3b77 100644 --- a/tests/bench/bench_strings.sh +++ b/tests/bench/bench_strings.sh @@ -8,7 +8,7 @@ T=$(mktemp -d) trap 'rm -rf "$T"' EXIT $CC -O2 -w src/tools/genmap.c -o "$T/genmap" || exit 1 "$T/genmap" --preset run -o "$T/run" >/dev/null || exit 1 -cp src/tools/zc0.c src/micro/micro.c src/micro/micro_port.h src/micro/port_linux.c src/core/core.c src/core/io_linux.c src/core/fops.h src/core/bops.h src/core/stack.h src/core/genome.h "$T/run/" +cp src/tools/zc0.c src/micro/micro.c src/micro/micro_port.h src/micro/port_linux.c src/core/core.c src/core/io_linux.c src/core/fops.h src/core/bops.h src/core/stack.h src/core/hold.h src/core/genome.h "$T/run/" $CC -O1 -w "$T/run/zc0.c" -o "$T/zc0" || exit 1 cat "$T/run/rt.zc" src/core/core.zc src/runtime/run.zc tests/programs/bench_strings.zc | "$T/zc0" > "$T/run/genome.bin" || exit 1 $CC -O2 -w -DJTYPE=int "$T/run/core.c" "$T/run/io_linux.c" -o "$T/zy" || exit 1 diff --git a/tests/bench/rss/a0.zc b/tests/bench/rss/a0.zc new file mode 100644 index 0000000..b8555d0 --- /dev/null +++ b/tests/bench/rss/a0.zc @@ -0,0 +1,11 @@ +namespace; +include rt, actor; +typecheck on; +int work(int n) { rt.syscall(48, 500, 0, 0); return n + 1; } +fn main() { + let n = 0, i = 0, sum = 0; + actor.Actor<int, int>*[101] as; + while (i < n) { as[i] = rt.new(actor.Actor<int, int>); as[i].spawn(work); as[i].recv(fn(int v) { sum = sum + v; return 0; }); as[i].send(i); i++; } + i = 0; while (i < n) { as[i].await(); as[i].close(); i++; } + rt.put_n(sum); rt.put_c(10); return 0; +} diff --git a/tests/bench/rss/a10.zc b/tests/bench/rss/a10.zc new file mode 100644 index 0000000..aa09ce1 --- /dev/null +++ b/tests/bench/rss/a10.zc @@ -0,0 +1,11 @@ +namespace; +include rt, actor; +typecheck on; +int work(int n) { rt.syscall(48, 500, 0, 0); return n + 1; } +fn main() { + let n = 10, i = 0, sum = 0; + actor.Actor<int, int>*[101] as; + while (i < n) { as[i] = rt.new(actor.Actor<int, int>); as[i].spawn(work); as[i].recv(fn(int v) { sum = sum + v; return 0; }); as[i].send(i); i++; } + i = 0; while (i < n) { as[i].await(); as[i].close(); i++; } + rt.put_n(sum); rt.put_c(10); return 0; +} diff --git a/tests/bench/rss/a100.zc b/tests/bench/rss/a100.zc new file mode 100644 index 0000000..f869026 --- /dev/null +++ b/tests/bench/rss/a100.zc @@ -0,0 +1,11 @@ +namespace; +include rt, actor; +typecheck on; +int work(int n) { rt.syscall(48, 500, 0, 0); return n + 1; } +fn main() { + let n = 100, i = 0, sum = 0; + actor.Actor<int, int>*[101] as; + while (i < n) { as[i] = rt.new(actor.Actor<int, int>); as[i].spawn(work); as[i].recv(fn(int v) { sum = sum + v; return 0; }); as[i].send(i); i++; } + i = 0; while (i < n) { as[i].await(); as[i].close(); i++; } + rt.put_n(sum); rt.put_c(10); return 0; +} diff --git a/tests/bench/rss/measure.py b/tests/bench/rss/measure.py new file mode 100644 index 0000000..b4ad889 --- /dev/null +++ b/tests/bench/rss/measure.py @@ -0,0 +1,13 @@ +import sys,subprocess,resource,os +repo=sys.argv[1] +for b in ['zy','zyi','zym']: + row=[b] + for n in [0,10,100]: + pid=os.fork() + if pid==0: + fd=os.open(os.path.dirname(os.path.abspath(__file__))+f'/a{n}.zc',os.O_RDONLY); os.dup2(fd,0) + nul=os.open('/dev/null',os.O_WRONLY); os.dup2(nul,1) + os.chdir(repo); os.execv(f'{repo}/build/bin/{b}',[b]) + _,st,ru=os.wait4(pid,0) + row.append(f'{ru.ru_maxrss/1024:.1f}' + ('' if st==0 else f'(st{st})')) + print(' '.join(row)) diff --git a/tests/drivers/hold_lsp_test.js b/tests/drivers/hold_lsp_test.js new file mode 100644 index 0000000..65d8154 --- /dev/null +++ b/tests/drivers/hold_lsp_test.js @@ -0,0 +1,54 @@ +// hold blocks in the language server: hover on hold, shared and a shared variable, +// completion offers the keywords and marks shared variables, and a use outside the +// block is a diagnostic. usage: node tests/drivers/hold_lsp_test.js path/to/zclsp +const TIMEOUT_SCALE = Number(process.env.ZC_TEST_TIMEOUT_SCALE) || 1; +const assert = require('assert'); +const cp = require('child_process'); +const server = process.argv[2]; +const uri = 'file:///hold.zc'; +const frame = m => { const body = Buffer.from(JSON.stringify(m)); return Buffer.concat([Buffer.from('Content-Length: ' + body.length + '\r\n\r\n'), body]); }; +function session(text, request) { + const messages = [ + { jsonrpc: '2.0', id: 1, method: 'initialize', params: {} }, + { jsonrpc: '2.0', method: 'textDocument/didOpen', params: { textDocument: { uri, version: 1, languageId: 'zc', text } } }, + ]; + if (request) messages.push(Object.assign({ jsonrpc: '2.0', id: 2 }, request)); + messages.push({ jsonrpc: '2.0', method: 'exit' }); + const result = cp.spawnSync(server, [], { input: Buffer.concat(messages.map(frame)), timeout: 15000 * TIMEOUT_SCALE, maxBuffer: 8 << 20 }); + assert.strictEqual(result.status, 0, String(result.stderr)); + const out = []; let data = result.stdout; + while (data.length) { + const end = data.indexOf('\r\n\r\n'); + const count = Number(/Content-Length:\s*(\d+)/i.exec(data.subarray(0, end).toString())[1]); + out.push(JSON.parse(data.subarray(end + 4, end + 4 + count).toString())); + data = data.subarray(end + 4 + count); + } + return out; +} +function at(text, needle, nth = 0, delta = 0) { + let o = -1; for (let i = 0; i <= nth; i++) o = text.indexOf(needle, o + 1); + assert.ok(o >= 0, needle); o += delta; + const before = text.slice(0, o); + return { line: before.split('\n').length - 1, character: before.length - before.lastIndexOf('\n') - 1 }; +} +const hover = (text, needle, nth) => { const r = session(text, { method: 'textDocument/hover', params: { textDocument: { uri }, position: at(text, needle, nth) } }).find(m => m.id === 2); return r && r.result && r.result.contents.value || ''; }; +const good = 'namespace;\ninclude rt;\nhold {\n shared let count = 0;\n fn inc() { count = count + 1; return count; }\n}\nfn main() { return inc(); }\n'; +let h = hover(good, 'hold'); +assert.ok(h.includes('monitor') && h.includes('lock'), 'hover on hold explains the block: ' + h); +h = hover(good, 'shared'); +assert.ok(h.includes('every actor'), 'hover on shared: ' + h); +h = hover(good, 'count', 1); +assert.ok(h.includes('shared in hold block 1'), 'hover on a shared variable names its block: ' + h); +const bad = 'namespace;\ninclude rt;\nhold { shared let count; fn inc() { count++; return count; } }\nfn main() { count = 2; return inc(); }\n'; +const diags = session(bad).filter(m => m.method === 'textDocument/publishDiagnostics').flatMap(m => m.params.diagnostics); +assert.ok(diags.some(d => d.message.includes('count: is shared in a hold block') && d.range.start.line === 3), 'use outside the block is a diagnostic on its line: ' + JSON.stringify(diags)); +const partial = 'namespace;\ninclude rt;\nhold { shared let count; fn inc() { count++; return count; } }\nho\nfn main() { return inc(); }\n'; +let r = session(partial, { method: 'textDocument/completion', params: { textDocument: { uri }, position: at(partial, '\nho', 0, 3) } }).find(m => m.id === 2); +let items = (r.result.items || r.result); +assert.ok(items.some(i => i.label === 'hold'), 'completion offers hold'); +const partial2 = 'namespace;\ninclude rt;\nhold { shared let count; fn inc() { cou; return count; } }\nfn main() { return inc(); }\n'; +r = session(partial2, { method: 'textDocument/completion', params: { textDocument: { uri }, position: at(partial2, 'cou;', 0, 3) } }).find(m => m.id === 2); +items = (r.result.items || r.result); +const it = items.find(i => i.label === 'count'); +assert.ok(it && String(it.detail).startsWith('shared'), 'completion marks a shared variable: ' + JSON.stringify(it)); +console.log('hold lsp: 6 checks passed'); diff --git a/tests/drivers/hold_test.py b/tests/drivers/hold_test.py new file mode 100644 index 0000000..1f6ea39 --- /dev/null +++ b/tests/drivers/hold_test.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 +# hold blocks (spec 4.16): accepted programs print what their first line expects, rejected +# ones report the error their first line names (exit 1), and trapping ones stop with +# exit 2 and the message named. usage: hold_test.py [VM] +from pathlib import Path +import subprocess, sys +root = Path(__file__).resolve().parents[2] +vm = sys.argv[1] if len(sys.argv) > 1 else 'build/bin/zy' +count = bad = 0 +for case in sorted((root / 'tests/hold').glob('*/*.zc')): + src = case.read_text(); first = src.splitlines()[0] + p = subprocess.run([str(root / vm) if not Path(vm).is_absolute() else vm], input=src, text=True, capture_output=True, cwd=root, timeout=60) + out = p.stdout + p.stderr + if first.startswith('// expect: '): + ok = p.returncode == 0 and p.stdout.strip() == first[11:].strip() + elif first.startswith('// error: '): + ok = p.returncode == 1 and first[10:].strip() in out + elif first.startswith('// trap: '): + ok = p.returncode == 2 and first[9:].strip() in out + else: + ok = False + count += 1 + if not ok: + bad += 1; print(f'FAIL {case.relative_to(root)}: rc={p.returncode} out={out[:300]!r}') + else: + print(f'ok {case.relative_to(root)}') +print(f'{count - bad}/{count} hold fixtures passed') +sys.exit(1 if bad or not count else 0) diff --git a/tests/drivers/imagekit.py b/tests/drivers/imagekit.py index 6cc083f..5df4810 100644 --- a/tests/drivers/imagekit.py +++ b/tests/drivers/imagekit.py @@ -9,7 +9,7 @@ from pathlib import Path ROOT = Path(__file__).resolve().parents[2] DEFAULT_MAP = ROOT / 'build' / 'core' / 'map' / 'memmap.h' MICRO_SOURCES = ['src/micro/micro.c', 'src/micro/micro_port.h', 'src/micro/port_linux.c', - 'src/core/fops.h', 'src/core/bops.h', 'src/core/stack.h', 'src/core/genome.h'] + 'src/core/fops.h', 'src/core/bops.h', 'src/core/stack.h', 'src/core/hold.h', 'src/core/genome.h'] def compiler(): diff --git a/tests/hold/accept/isolated_globals.zc b/tests/hold/accept/isolated_globals.zc new file mode 100644 index 0000000..08a3e5c --- /dev/null +++ b/tests/hold/accept/isolated_globals.zc @@ -0,0 +1,18 @@ +// expect: 0 3 +// a plain global is each actor's own; only a shared variable of a hold block is seen by all +namespace; +include rt, actor; +typecheck on; +let plain = 0; +hold { shared let seen = 0; fn note() { seen++; return seen; } fn seen_now() { return seen; } } +int work(int n) { plain = plain + n; note(); return plain; } +fn main() { + actor.Actor<int,int>* a = rt.new(actor.Actor<int,int>), b = rt.new(actor.Actor<int,int>), c = rt.new(actor.Actor<int,int>); + a.spawn(work); b.spawn(work); c.spawn(work); + a.send(5); b.send(6); c.send(7); + a.recv(fn(int n) { return 0; }); b.recv(fn(int n) { return 0; }); c.recv(fn(int n) { return 0; }); + a.await(); b.await(); c.await(); + rt.put_n(plain); rt.put_c(' '); rt.put_n(seen_now()); rt.put_c(10); + a.close(); b.close(); c.close(); + return 0; +} diff --git a/tests/hold/accept/monitor.zc b/tests/hold/accept/monitor.zc new file mode 100644 index 0000000..7dfe6f0 --- /dev/null +++ b/tests/hold/accept/monitor.zc @@ -0,0 +1,15 @@ +// expect: 902 +namespace; +include rt; +hold { + shared let c = 5; + shared int[3] hist; + fn bump(int k) { c = c + k; hist[0]++; return c; } + fn twice(int k) { bump(k); return bump(k); } + fn get() { return c * 100 + hist[0]; } +} +fn main() { + twice(2); + rt.put_n(get()); rt.put_c(10); + return 0; +} diff --git a/tests/hold/accept/race.zc b/tests/hold/accept/race.zc new file mode 100644 index 0000000..f7fdb61 --- /dev/null +++ b/tests/hold/accept/race.zc @@ -0,0 +1,21 @@ +// expect: 90000 +// many actors increment one shared counter through a read, then a write; the hold block's lock makes every increment count +namespace; +include rt, actor; +typecheck on; +hold { + shared let count = 0; + fn inc() { let v = count; count = v + 1; return v; } + fn total() { return count; } +} +int work(int n) { let i = 0; while (i < n) { inc(); i++; } return n; } +fn main() { + let i = 0; actor.Actor<int,int>*[?] xs = rt.new(actor.Actor<int,int>*[?]); + while (i < 8) { actor.Actor<int,int>* a = rt.new(actor.Actor<int,int>); a.spawn(work); push(xs, a); i++; } + i = 0; while (i < 8) { xs[i].send(10000); i++; } + work(10000); + i = 0; while (i < 8) { xs[i].recv(fn(int n) { return 0; }); xs[i].await(); i++; } + rt.put_n(total()); rt.put_c(10); + i = 0; while (i < 8) { xs[i].close(); i++; } + return 0; +} diff --git a/tests/hold/accept/rank_order.zc b/tests/hold/accept/rank_order.zc new file mode 100644 index 0000000..9fc903a --- /dev/null +++ b/tests/hold/accept/rank_order.zc @@ -0,0 +1,7 @@ +// expect: 10 +namespace; +include rt; +int gb(); +hold { shared let a; fn ga() { a++; return gb(); } } +hold { shared let b; fn gb() { b++; return b * 10; } } +fn main() { rt.put_n(ga()); rt.put_c(10); return 0; } diff --git a/tests/hold/accept/reentrant.zc b/tests/hold/accept/reentrant.zc new file mode 100644 index 0000000..f0c8293 --- /dev/null +++ b/tests/hold/accept/reentrant.zc @@ -0,0 +1,12 @@ +// expect: 3 1 +// a function of a block calling another of the same block doesn't take the lock again, and a later block may be entered from an earlier one +namespace; +include rt; +int later(); +hold { + shared let depth, calls; + fn inner() { calls++; return depth; } + fn outer() { depth = depth + 1; inner(); inner(); inner(); return calls; } +} +hold { shared let seen; fn later() { seen++; return seen; } } +fn main() { rt.put_n(outer()); rt.put_c(' '); rt.put_n(later()); rt.put_c(10); return 0; } diff --git a/tests/hold/reject/actor_handler.zc b/tests/hold/reject/actor_handler.zc new file mode 100644 index 0000000..5548cad --- /dev/null +++ b/tests/hold/reject/actor_handler.zc @@ -0,0 +1,8 @@ +// error: total: is shared in a hold block; only the functions written inside that block can use it +// shared state reached from an actor's handler without going through its hold block +namespace; +include rt, actor; +typecheck on; +hold { shared let total; fn add(int n) { total = total + n; return total; } } +int work(int n) { total = total + n; return n; } +fn main() { actor.Actor<int,int>* a = rt.new(actor.Actor<int,int>); a.spawn(work); a.send(1); a.close(); return 0; } diff --git a/tests/hold/reject/closure.zc b/tests/hold/reject/closure.zc new file mode 100644 index 0000000..5c082d2 --- /dev/null +++ b/tests/hold/reject/closure.zc @@ -0,0 +1,5 @@ +// error: c: is shared; a closure can't use it +namespace; +include rt; +hold { shared let c; fn a() { let f = fn() { return c; }; return f(); } } +fn main() { return a(); } diff --git a/tests/hold/reject/nested.zc b/tests/hold/reject/nested.zc new file mode 100644 index 0000000..b8d38a6 --- /dev/null +++ b/tests/hold/reject/nested.zc @@ -0,0 +1,5 @@ +// error: hold blocks don't nest +namespace; +include rt; +hold { shared let c; hold { shared let d; } } +fn main() { return 0; } diff --git a/tests/hold/reject/o3.zc b/tests/hold/reject/o3.zc new file mode 100644 index 0000000..87c2dd5 --- /dev/null +++ b/tests/hold/reject/o3.zc @@ -0,0 +1,5 @@ +// error: f: is in a hold block and can't be o3 +namespace; +include rt; +hold { shared let c; o3 int f(int k) { return k; } } +fn main() { return f(1); } diff --git a/tests/hold/reject/order.zc b/tests/hold/reject/order.zc new file mode 100644 index 0000000..9a2943b --- /dev/null +++ b/tests/hold/reject/order.zc @@ -0,0 +1,7 @@ +// trap: was entered while +// blocks are entered in declaration order; going back to an earlier block while a later one is held stops the program +namespace; +include rt; +hold { shared let a; fn ga() { a++; return a; } } +hold { shared let b; fn gb() { b++; return ga(); } } +fn main() { rt.put_n(gb()); rt.put_c(10); return 0; } diff --git a/tests/hold/reject/outside.zc b/tests/hold/reject/outside.zc new file mode 100644 index 0000000..a202898 --- /dev/null +++ b/tests/hold/reject/outside.zc @@ -0,0 +1,5 @@ +// error: c: is shared in a hold block; only the functions written inside that block can use it +namespace; +include rt; +hold { shared let c; fn a() { c++; return c; } } +fn main() { c = 3; return a(); } diff --git a/tests/hold/reject/pointer.zc b/tests/hold/reject/pointer.zc new file mode 100644 index 0000000..6306a62 --- /dev/null +++ b/tests/hold/reject/pointer.zc @@ -0,0 +1,5 @@ +// error: name: is shared, so it holds numbers +namespace; +include rt; +hold { shared char* name = "x"; fn a() { return 0; } } +fn main() { return a(); } diff --git a/tests/test.sh b/tests/test.sh index 6d8453e..c31cfb7 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -273,6 +273,9 @@ s_interp() { python3 tests/drivers/actor_test.py $T/zy > $T/actor.out 2>&1; r=$? grep -v '^ok' $T/actor.out chk $r 0 "native isolated actor acceptance, rejection and regression fixtures" + python3 tests/drivers/hold_test.py $T/zy > $T/hold.out 2>&1; r=$? + grep -v '^ok' $T/hold.out + chk $r 0 "native hold blocks: monitors, rejections, a race between actors, rank order" chk "$(ZC_ARG_TEST=ok $T/zy tests/programs/args.zc alpha beta < tests/programs/args.zc)" "4 <eval> beta 1 1" "interp the command line reaches argv, after <eval>" chk "$($T/zy < tests/programs/cabi.zc | md5sum)" "$(md5sum < tests/programs/cabi.expected)" "interp native calls and callbacks (extern, cfunc)" chk "$($T/zy < tests/programs/cabi_o3.zc | md5sum)" "$(md5sum < tests/programs/cabi_o3.expected)" "interp native calls from o3 code, more arguments than registers" @@ -298,6 +301,9 @@ s_micro() { python3 tests/drivers/actor_test.py $T/zym > $T/actor.out 2>&1; r=$? grep -v '^ok' $T/actor.out chk $r 0 "micro isolated actor acceptance, rejection and regression fixtures" + python3 tests/drivers/hold_test.py $T/zym > $T/hold.out 2>&1; r=$? + grep -v '^ok' $T/hold.out + chk $r 0 "micro hold blocks: monitors, rejections, a race between actors, rank order" if command -v node >/dev/null && command -v tsc >/dev/null && node src/js/mklayout.js --map $MAP/memmap.h --out $T/jsvm >/dev/null \ && cp $ROOT/s1/genome.bin $T/jsvm/ && tsc src/js/tinyvm.ts --target es2020 --lib es2020,dom --module commonjs --outDir $T/jsvm; then python3 tests/drivers/fuzz_compiler.py $ROOT/zy $T/zym --js $T/jsvm/tinyvm.js > $T/fuzz.out 2>&1; r=$? @@ -331,10 +337,10 @@ s_small() { cmp -s $T/small/memmap.h $T/small-flags/memmap.h && cmp -s $T/small/rt.zc $T/small-flags/rt.zc \ && cmp -s $T/small/compiler.zc $T/small-flags/compiler.zc && cmp -s $T/small/map.txt $T/small-flags/map.txt \ && chk 1 1 "compiler flags reproduce the small map" || chk 0 1 "compiler flags reproduce the small map" - cp src/tools/zc0.c src/core/fops.h src/core/bops.h src/core/stack.h src/core/genome.h $T/small/ + cp src/tools/zc0.c src/core/fops.h src/core/bops.h src/core/stack.h src/core/hold.h src/core/genome.h $T/small/ $CC -O1 -w -fwrapv $T/small/zc0.c -o $T/zc0s || exit 1 cat $T/small/rt.zc src/core/core.zc $T/small/compiler.zc | $T/zc0s > $T/small/genome.bin || exit 1 - cp src/micro/micro.c src/micro/micro_port.h src/micro/port_linux.c src/micro/port_stub.c src/core/core.c src/core/io_linux.c src/core/fops.h src/core/bops.h src/core/stack.h src/core/genome.h $T/small/ + cp src/micro/micro.c src/micro/micro_port.h src/micro/port_linux.c src/micro/port_stub.c src/core/core.c src/core/io_linux.c src/core/fops.h src/core/bops.h src/core/stack.h src/core/hold.h src/core/genome.h $T/small/ $CC -pthread -DZY_THREADS -O2 -w -fwrapv $T/small/micro.c $T/small/port_linux.c -o $T/zyms || exit 1 $CC -pthread -O2 -w -fwrapv -DJTYPE=int $T/small/core.c $T/small/io_linux.c -o $T/zys || exit 1 $CC -ffreestanding -w -c $T/small/micro.c -o $T/micro_s.o && $CC -ffreestanding -w -c $T/small/port_stub.c -o $T/stub_s.o && chk 1 1 "small microcore compiles freestanding" || chk 0 1 "small microcore compiles freestanding" @@ -375,14 +381,14 @@ s_runonly() { # its own run map: the run-only image is built against this one, and the # small-machine section lays out its own rather than sharing this $T/genmap --preset run -o $T/run || exit 1 - cp src/tools/zc0.c src/micro/micro.c src/micro/micro_port.h src/micro/port_linux.c src/micro/port_stub.c src/core/fops.h src/core/bops.h src/core/stack.h src/core/genome.h $T/run/ + cp src/tools/zc0.c src/micro/micro.c src/micro/micro_port.h src/micro/port_linux.c src/micro/port_stub.c src/core/fops.h src/core/bops.h src/core/stack.h src/core/hold.h src/core/genome.h $T/run/ $CC -O1 -w -fwrapv $T/run/zc0.c -o $T/zc0r || exit 1 runonly() { # $1 label, $2 source. the program is already in the image, so it reads no source. # the map is sized to the program: src/tools/automap.sh lays it out for the image's own length local a b d=$T/run-$1 input=$2 if [ "$1" = gc ]; then input=$T/collector-progress.zc; sed -E 's/f >= [0-9]+/f > 0/' "$2" > "$input"; fi GENMAP=$T/genmap bash src/tools/automap.sh run $d src/runtime/run.zc "$input" >/dev/null || { chk 0 1 "run $1 builds"; return; } - cp src/micro/micro.c src/micro/micro_port.h src/micro/port_linux.c src/micro/port_stub.c src/core/fops.h src/core/bops.h src/core/stack.h src/core/genome.h $d/ + cp src/micro/micro.c src/micro/micro_port.h src/micro/port_linux.c src/micro/port_stub.c src/core/fops.h src/core/bops.h src/core/stack.h src/core/hold.h src/core/genome.h $d/ $CC -pthread -DZY_THREADS -O2 -w -fwrapv $d/micro.c $d/port_linux.c -o $T/zymr || { chk 0 1 "run $1 links"; return; } a=$($T/zy < "$input" 2>&1 | sed "s#<stdin>#$input#g" | tr '\n' '/') b=$($T/zymr </dev/null 2>&1 | tr '\n' '/') @@ -407,7 +413,7 @@ s_runonly() { runonly zc0bstr tests/programs/zc0bstr.zc runonly zc0umd tests/programs/zc0umd.zc runonly wiring examples/wiring.zc - d=$T/run-echo; GENMAP=$T/genmap bash src/tools/automap.sh run $d src/runtime/run.zc examples/echo.zc >/dev/null && cp src/micro/micro.c src/micro/micro_port.h src/micro/port_linux.c src/micro/port_stub.c src/core/fops.h src/core/bops.h src/core/stack.h src/core/genome.h $d/ \ + d=$T/run-echo; GENMAP=$T/genmap bash src/tools/automap.sh run $d src/runtime/run.zc examples/echo.zc >/dev/null && cp src/micro/micro.c src/micro/micro_port.h src/micro/port_linux.c src/micro/port_stub.c src/core/fops.h src/core/bops.h src/core/stack.h src/core/hold.h src/core/genome.h $d/ \ && $CC -pthread -DZY_THREADS -O2 -w -fwrapv $d/micro.c $d/port_linux.c -o $T/zymr \ && chk "$(printf 'abc\n' | $T/zymr | tr '\n' '/')" "$( (cat examples/echo.zc; printf '`abc\n') | $T/zy | tr '\n' '/')" "run echo" \ || chk 0 1 "run echo" @@ -526,6 +532,9 @@ s_jit() { bash tests/drivers/jit_x64_test.sh $T/zyi $T/zyx > $T/jit_x64.out 2>&1; r=$? grep '^DIFF' $T/jit_x64.out chk $r 0 "x86-64 jit agrees with the interpreter: $(tail -n 1 $T/jit_x64.out)" + python3 tests/drivers/hold_test.py $T/zyx > $T/hold_x64.out 2>&1; r=$? + grep -v '^ok' $T/hold_x64.out + chk $r 0 "x86-64 jit hold blocks" chk "$(ZYNOENH=1 $T/zyx < tests/programs/enh_ops.zc | md5sum)" "$(md5sum < tests/programs/enh_ops.expected)" "x86-64 jit with enhancements called through xrun (ZYNOENH=1)" chk "$(ZYTRACE=1 $T/zyx < tests/programs/o3.zc 2>&1 | grep -c 'bytes of x86-64')" "7" "x86-64 jit compiles the o3 regions it can (one has too many live values)" chk "$(ZYTRACE=1 $T/zyx < tests/programs/o3_freelist.zc 2>&1 | grep -c ' inline at ')" "11" "x86-64 jit inlines new_k and recycle_leaf in compiled o3 regions" @@ -546,6 +555,9 @@ s_llvm() { if [ $llvm_ok = 1 ]; then run $T/zyl "llvm" chk "$(ZYTRACE=1 $T/zyl < tests/programs/o3.zc 2>&1 | grep -c 'compiled by llvm')" "8" "llvm compiles every o3 region" + python3 tests/drivers/hold_test.py $T/zyl > $T/hold.out 2>&1; r=$? + grep -v '^ok' $T/hold.out + chk $r 0 "llvm hold blocks" printf '#!/bin/sh\nZYHOT=1 exec %s "$@"\n' $T/zyl > $T/llall; chmod +x $T/llall chk "$($T/zyl < tests/programs/structval.zc)" "34 3520 18 325 810 340" "llvm structs by value (the call goes through the interpreter's native call)" chk "$($T/zyl < tests/programs/structret.zc)" "3 4 3.500000 4.000000 24 8 1.000000 3.500000" "llvm structs returned from a c function" @@ -634,6 +646,9 @@ s_lsp() { node tests/drivers/codeactions_client_test.js > $T/codeactions-client.out 2>&1; r=$? grep -v '^ok' $T/codeactions-client.out chk $r 0 "lsp: versioned import quick-fix edits" + node tests/drivers/hold_lsp_test.js $lsp > $T/holdlsp.out 2>&1; r=$? + cat $T/holdlsp.out | grep -v passed + chk $r 0 "lsp hold blocks: hover, completion and diagnostics" node tests/drivers/completion_test.js $lsp > $T/completion.out 2>&1; r=$? grep -v '^ok' $T/completion.out chk $r 0 "lsp: fuzzy completions, signatures, scope and expired lifetimes" diff --git a/tests/xref.baseline b/tests/xref.baseline index 26b6931..79e948b 100644 --- a/tests/xref.baseline +++ b/tests/xref.baseline @@ -161,6 +161,7 @@ fbnd chk_reset closure ctx_pop fn_begin kw_unbounded fchk chk_reset ctx_pop defer_one fn_begin kw_unchecked fdepth block blockexpr casebody chk_reset ctx_pop fn_begin kw_for kw_switch substmt fframe chk_reset ctx_pop prologue +fhold fndef fieldcap field_note fieldn field_note types_init fieldnames field_note @@ -236,6 +237,11 @@ hl_lev hint_set hl_n chk_unit hint_set hl_off hint_set hlimit build_image_grow chk_unit reserve_code start syntax_resident +hold_count kw_hold +hold_cur kw_hold +hold_desc kw_hold +hold_nshared kw_hold +hold_tab kw_hold ht_end ht_note ht_n ht_note ht_start ht_note @@ -630,7 +636,7 @@ sdsrc addsym def_note reserve_symbols send_check args field seqtop seqasm zc_init sfix addsym enhdef fndef fnref reserve_symbols -sflag add_kw addsym blob_load call enhdef fndef fndone fwdfn_at ginstance kw_extern kw_struct methcall methdecl prescan_fn reserve_symbols retcheck +sflag add_kw addsym blob_load call enhdef fndef fndone fwdfn_at ginstance kw_extern kw_hold kw_struct methcall methdecl prescan_fn reserve_symbols retcheck sgb sig_attach sgb_initial sigcap sig_attach |
