From 4b8a082d11b175f1732b9537d6f4835498254e0c Mon Sep 17 00:00:00 2001 From: zinc Date: Thu, 15 Oct 2026 14:33:46 +0330 Subject: test.sh: hold fixtures on interp, micro, x86-64 jit and llvm --- tests/test.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'tests/test.sh') diff --git a/tests/test.sh b/tests/test.sh index 6d8453e..3b505fc 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 beta 1 1" "interp the command line reaches argv, after " 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=$? @@ -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" -- cgit v1.2.3 From ee4900f847eec5a050c1cf909d5662efe82930f4 Mon Sep 17 00:00:00 2001 From: zinc Date: Thu, 15 Oct 2026 14:35:19 +0330 Subject: lsp: hold and shared hovers, completion of the keywords, shared variables marked in hover and completion; tmLanguage keywords; hold_lsp_test.js --- editors/vscode/syntaxes/zc.tmLanguage.json | 2 +- src/lsp/server.zc | 10 +++++- tests/drivers/hold_lsp_test.js | 54 ++++++++++++++++++++++++++++++ tests/test.sh | 3 ++ 4 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 tests/drivers/hold_lsp_test.js (limited to 'tests/test.sh') diff --git a/editors/vscode/syntaxes/zc.tmLanguage.json b/editors/vscode/syntaxes/zc.tmLanguage.json index 3869418..f8743d3 100644 --- a/editors/vscode/syntaxes/zc.tmLanguage.json +++ b/editors/vscode/syntaxes/zc.tmLanguage.json @@ -91,7 +91,7 @@ }, { "name": "keyword.other.zc", - "match": "\\b(as|unchecked|unbounded|asm|quote|sizeof|typeof|len|cap|push|pop|resize|o3|include|embed|memdebug|fixed|typecheck)\\b" + "match": "\\b(as|unchecked|unbounded|hold|shared|asm|quote|sizeof|typeof|len|cap|push|pop|resize|o3|include|embed|memdebug|fixed|typecheck)\\b" }, { "name": "keyword.operator.memory.zc", diff --git a/src/lsp/server.zc b/src/lsp/server.zc index 65881a9..d776b1d 100644 --- a/src/lsp/server.zc +++ b/src/lsp/server.zc @@ -412,6 +412,7 @@ int gap_out(int from, int to) { return 0; } // is c an operator character, which the highlighter marks as an operator. +int hov_shared; // the hold block of the global being hovered, when it is shared int isopc(int c) { char* s = "+-*/%=<>!&|^~?@#$"; int i = 0; @@ -1725,6 +1726,8 @@ char* kwtext() { if (hname_is("switch")) return "switch (e) { case 1, 2: ... default: ... }~a branch on constant labels. the cases don't fall through, and break leaves early."; if (hname_is("break")) return "break;~leaves the innermost loop or switch."; if (hname_is("continue")) return "continue;~goes on to the next pass of the innermost loop."; + if (hname_is("hold")) return "hold { shared let c; fn a() { } fn b() { } }~a monitor at the top level. its shared variables are one copy for every actor, and only the functions written in the block can use them. each call to one of those functions holds the block's lock for the whole call; a call from one to another doesn't lock again. blocks are entered in the order they are declared."; + if (hname_is("shared")) return "shared let c; / shared int[4] counts;~inside a hold block: a variable every actor sees, used only by the block's functions under its lock. it holds numbers or arrays of numbers, since each actor has its own heap."; if (hname_is("defer")) return "defer e; or defer { }~runs the statement when the enclosing block ends, on every way out of it (falling off the end, return, break, continue). several run last registered first, and what they name is read when they run. return, break and continue are not allowed inside. defer rt.free(p); is the transfer of p for the ownership analysis."; if (hname_is("return")) return "return e; or return;~leaves the function with a value, or leaves a void function. returning an owned local transfers it to the caller automatically."; if (hname_is("enum")) return "enum name { A, B = 5 };~global constants. under typecheck on they are a type of their own, and a member can carry fields to make a constructor."; @@ -1843,6 +1846,7 @@ int hover_named(int i, int o, int kind) { else if (st == run.S_U) hov_text(".u"); else if (st == run.S_D) hov_text(".d"); else if (st == run.S_DEAD) hov_text(".expired"); hov_put(' '); k = o; while (k < end) { hov_put(dc(base, k)); k++; } if (kind == 1) hov_text(" // parameter;"); + else if (kind == 3 && hov_shared > 0) { hov_text(" // shared in hold block "); hov_number(hov_shared); hov_text(": the block's functions use it under its lock;"); } else if (kind == 3) hov_text(" // global;"); else if (kind == 4) hov_text(" // field;"); else hov_text("; // local"); @@ -2004,7 +2008,9 @@ int do_hover(int i) { else if ((v & 15) == run.K_GVAR || (v & 15) == run.K_GARR) { s = run.rsrec[r * run.RS_W + 3]; q = 0; o = 0 - 1; while (q < run.rsn) { if (run.rsrec[q * run.RS_W + 3] == s && lt_find(run.rsrec[q * run.RS_W]) >= 0) { o = run.rsrec[q * run.RS_W]; break; } q++; } + hov_shared = 0; if (s >= 0 && (run.sflag[s] & run.F_SHARED)) hov_shared = run.sflag[s] / run.F_SHARED_RANK; if (o >= 0) hover_named(i, o, 3); else if (v & 16) hover_global(i, 2); else hover_global(i, 1); + hov_shared = 0; } else if (v & 16) hover_global(i, 2); else hover_global(i, 1); } else hover_global(i, 0); @@ -3123,7 +3129,7 @@ int cp_symbol(int s, char* label) { bstr sig = cp_signature(run.sname[s]), doc; int k = 0, kind = 6; hn = 0; if (sig) { while (k < rt.len_s(sig)) { hov_put(rt.at_s(sig, k)); k++; } } - else { if (run.stype[s]) { hov_type(run.stype[s]); hov_put(' '); } hov_text(label); } + else { if ((run.skind[s] == run.K_GVAR || run.skind[s] == run.K_GARR) && (run.sflag[s] & run.F_SHARED)) hov_text("shared "); if (run.stype[s]) { hov_type(run.stype[s]); hov_put(' '); } hov_text(label); } if (run.skind[s] == run.K_FN || run.skind[s] == run.K_ENH) kind = 3; else if (run.skind[s] == run.K_TYPE) kind = 22; else if (run.skind[s] == run.K_CONST) kind = 21; @@ -3264,6 +3270,8 @@ int do_completion(int i) { if (run.skind[s] != run.K_DOC && run.lookup(run.sname[s]) == s && (run.skind[s] != run.K_FN || (run.sflag[s] & (run.F_DEF | run.F_DECL)))) cp_symbol(s, run.sname[s]); s++; } + if (cp_score("hold") >= 0) { hn = 0; hov_text("hold { shared let c; fn f() { } }"); if (cp_add("hold", 14, 0, 1)) cp_docs[cp_n - 1] = cp_copy("a monitor: shared variables for every actor, used under the block's lock by the functions written in it"); } + if (cp_score("shared") >= 0) { hn = 0; hov_text("shared let name;"); if (cp_add("shared", 14, 0, 1)) cp_docs[cp_n - 1] = cp_copy("inside a hold block: a variable every actor sees, used only by the block's functions"); } run.probe_off = cp_cursor; old = chk_stream; chk_stream = 0; check_doc(i); chk_stream = old; run.probe_off = -1; member = 0; if (run.probe_has == 2 && run.probe_mem && run.probe_mem[0] == run.TY_STRUCT) member = run.probe_mem[2]; 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/test.sh b/tests/test.sh index 3b505fc..90599ed 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -646,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" -- cgit v1.2.3 From b6af0e942dcde433db96a298a25490aa44e88173 Mon Sep 17 00:00:00 2001 From: zinc Date: Thu, 15 Oct 2026 15:25:23 +0330 Subject: hold: copy hold.h with micro.c everywhere; xref baseline for hold globals; lsp keyword completion yields to a same-named symbol; compiler message avoids the word actor --- Makefile | 2 +- docs/SPEC.md | 2 +- src/baremetal/run.sh | 4 ++-- src/compiler/decl.zc | 2 +- src/lsp/server.zc | 16 ++++++++++++++-- src/tools/parity.sh | 2 +- src/tools/zcc | 2 +- tests/bench/bench_bytes.sh | 2 +- tests/bench/bench_share.sh | 2 +- tests/bench/bench_strings.sh | 2 +- tests/drivers/imagekit.py | 2 +- tests/test.sh | 10 +++++----- tests/xref.baseline | 8 +++++++- 13 files changed, 37 insertions(+), 19 deletions(-) (limited to 'tests/test.sh') diff --git a/Makefile b/Makefile index ceed9be..ff9e9d0 100644 --- a/Makefile +++ b/Makefile @@ -58,7 +58,7 @@ WEB := $(B)/web MAP := $(B)/core/map # hand-written core headers, the generated map, and where #embed finds the genome image COREINC := -Isrc/core -I$(MAP) --embed-dir=$(B)/core -CORE_H := src/core/genome.h src/core/fops.h src/core/bops.h src/core/stack.h $(MAP)/memmap.h +CORE_H := src/core/genome.h src/core/fops.h src/core/bops.h src/core/stack.h src/core/hold.h $(MAP)/memmap.h # the sources the compiler genome is built from, and the files it embeds # the compiler is the files named in src/compiler/parts, in that order ZC_PARTS := $(addprefix src/compiler/,$(shell cat src/compiler/parts)) diff --git a/docs/SPEC.md b/docs/SPEC.md index a4f8397..7dd1247 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -823,7 +823,7 @@ hold { ``` `hold` followed by `{` at the top level starts a hold block; elsewhere `hold` and `shared` are ordinary names. a hold block contains shared variable declarations, functions, and any other top-level items. hold blocks don't nest (error: hold blocks don't nest). each block has a rank, its position among the unit's hold blocks, from 1. -5.16.2 a shared variable is a global with one value for the whole program, seen by every actor (docs/ACTOR.md); every other global is each actor's own copy. its type is a number type or a fixed array of one. a pointer, string, struct, growable array or function type is error: x: is shared, so it holds numbers: no pointers, strings or structs (each actor has its own heap). an initializer is a constant, as for any global. +5.16.2 a shared variable is a global with one value for the whole program, seen by every actor (docs/ACTOR.md); every other global is each actor's own copy. its type is a number type or a fixed array of one. a pointer, string, struct, growable array or function type is error: x: is shared, so it holds numbers: no pointers, strings or structs (each worker has its own heap). an initializer is a constant, as for any global. 5.16.3 only the functions written in the block can name its shared variables. a use anywhere else, including in another hold block, is error: x: is shared in a hold block; only the functions written inside that block can use it (they hold its lock). a use in a closure, even one written inside the block, is error: x: is shared; a closure can't use it, because it may run after the hold block's lock is released. a function of a hold block can't be `o3` (error: f: is in a hold block and can't be o3). diff --git a/src/baremetal/run.sh b/src/baremetal/run.sh index 43f8a4c..5f812fa 100755 --- a/src/baremetal/run.sh +++ b/src/baremetal/run.sh @@ -69,7 +69,7 @@ if [ "$mode" = run ] || [ "$mode" = io ]; then # the map is sized to the program, so a bigger runtime or program just gets a bigger board ${CC:-$(sh src/tools/findcc.sh)} -O2 -w src/tools/genmap.c -o "$D/genmap" GENMAP="$D/genmap" bash src/tools/automap.sh run "$D/img" src/runtime/run.zc "$src" >"$D/genmap.log" 2>&1 || { cat "$D/genmap.log" >&2; exit 1; } - cp src/micro/micro.c src/micro/micro_port.h src/core/fops.h src/core/bops.h src/core/stack.h src/core/genome.h "$D/img/" + cp src/micro/micro.c src/micro/micro_port.h src/core/fops.h src/core/bops.h src/core/stack.h src/core/hold.h src/core/genome.h "$D/img/" "$cc" $common $def -I"$D/img" -c "$D/img/micro.c" -o "$D/micro.o" if [ "$mode" = io ]; then "$cc" $common $def -DBARE_INPUT=1 -I"$D/img" -c src/baremetal/port.c -o "$D/port.o" @@ -80,7 +80,7 @@ if [ "$mode" = run ] || [ "$mode" = io ]; then fi elif [ "$mode" = compile ]; then [ -f build/core/genome.bin ] || { echo "baremetal: no build/core/genome.bin; run make genome first" >&2; exit 1; } - cp src/micro/micro.c src/micro/micro_port.h build/core/map/memmap.h build/core/genome.bin src/core/genome.h src/core/fops.h src/core/bops.h src/core/stack.h "$D/" + cp src/micro/micro.c src/micro/micro_port.h build/core/map/memmap.h build/core/genome.bin src/core/genome.h src/core/fops.h src/core/bops.h src/core/stack.h src/core/hold.h "$D/" "$cc" $common $def -I"$D" -c "$D/micro.c" -o "$D/micro.o" "$cc" $common $def -DBARE_INPUT=1 -I"$D" -c src/baremetal/port.c -o "$D/port.o" timeout=90 diff --git a/src/compiler/decl.zc b/src/compiler/decl.zc index fed7b8d..55e23a7 100644 --- a/src/compiler/decl.zc +++ b/src/compiler/decl.zc @@ -264,7 +264,7 @@ int kw_hold() { if (skind[s] == K_GVAR || skind[s] == K_GARR) { t = stype[s]; w = 1; if (skind[s] == K_GARR) { w = tsz(t); if (t[0] == TY_ARR) t = t[1]; } - if (t && (isptr(t) || isagg(t) || t == tbstr || t[0] == TY_DYN || t[0] == TY_FN)) serrn(sname[s], "is shared, so it holds numbers: no pointers, strings or structs (each actor has its own heap)"); + if (t && (isptr(t) || isagg(t) || t == tbstr || t[0] == TY_DYN || t[0] == TY_FN)) serrn(sname[s], "is shared, so it holds numbers: no pointers, strings or structs (each worker has its own heap)"); sflag[s] = sflag[s] | F_SHARED | rank * F_SHARED_RANK; if (hold_nshared >= 64) serr("too many shared variables in one hold block (64)"); else { hold_tab[hold_nshared * 2] = sval[s]; hold_tab[hold_nshared * 2 + 1] = w; hold_nshared++; } diff --git a/src/lsp/server.zc b/src/lsp/server.zc index d776b1d..85f3ea5 100644 --- a/src/lsp/server.zc +++ b/src/lsp/server.zc @@ -3100,6 +3100,18 @@ int cp_score(char* name) { if (exact) { if (n == i) return 0; return 10 + n - i; } return 100 + score + n - i; } +// a label already offered (a symbol named like a keyword wins over the keyword) +int cp_has(char* name) { + int k = 0, i; + while (k < cp_n) { + i = 0; + while (name[i] && cp_name[k][i] == name[i]) i++; + if (!name[i] && !cp_name[k][i]) return 1; + k++; + } + return 0; +} + int cp_add(char* name, int kind, int dead, int relevance) { int score = cp_score(name); if (score < 0) return 0; @@ -3270,8 +3282,8 @@ int do_completion(int i) { if (run.skind[s] != run.K_DOC && run.lookup(run.sname[s]) == s && (run.skind[s] != run.K_FN || (run.sflag[s] & (run.F_DEF | run.F_DECL)))) cp_symbol(s, run.sname[s]); s++; } - if (cp_score("hold") >= 0) { hn = 0; hov_text("hold { shared let c; fn f() { } }"); if (cp_add("hold", 14, 0, 1)) cp_docs[cp_n - 1] = cp_copy("a monitor: shared variables for every actor, used under the block's lock by the functions written in it"); } - if (cp_score("shared") >= 0) { hn = 0; hov_text("shared let name;"); if (cp_add("shared", 14, 0, 1)) cp_docs[cp_n - 1] = cp_copy("inside a hold block: a variable every actor sees, used only by the block's functions"); } + if (cp_score("hold") >= 0 && !cp_has("hold")) { hn = 0; hov_text("hold { shared let c; fn f() { } }"); if (cp_add("hold", 14, 0, 1)) cp_docs[cp_n - 1] = cp_copy("a monitor: shared variables for every actor, used under the block's lock by the functions written in it"); } + if (cp_score("shared") >= 0 && !cp_has("shared")) { hn = 0; hov_text("shared let name;"); if (cp_add("shared", 14, 0, 1)) cp_docs[cp_n - 1] = cp_copy("inside a hold block: a variable every actor sees, used only by the block's functions"); } run.probe_off = cp_cursor; old = chk_stream; chk_stream = 0; check_doc(i); chk_stream = old; run.probe_off = -1; member = 0; if (run.probe_has == 2 && run.probe_mem && run.probe_mem[0] == run.TY_STRUCT) member = run.probe_mem[2]; diff --git a/src/tools/parity.sh b/src/tools/parity.sh index 2d2086d..1b90885 100755 --- a/src/tools/parity.sh +++ b/src/tools/parity.sh @@ -71,7 +71,7 @@ SRCS="src/runtime/rt.zc src/core/core.zc src/runtime/run.zc" if cmp -s "$W/prefix.new" "$W/prefix.zc"; then rm "$W/prefix.new"; else mv "$W/prefix.new" "$W/prefix.zc"; fi nprefix=$(wc -l < "$W/prefix.zc") # what the compiled image depends on besides the program -DEPS="$ZC0 $MKG $W/prefix.zc src/micro/micro.c src/micro/port_linux.c src/micro/micro_port.h src/core/fops.h src/core/bops.h src/core/stack.h src/core/genome.h build/core/map/memmap.h" +DEPS="$ZC0 $MKG $W/prefix.zc src/micro/micro.c src/micro/port_linux.c src/micro/micro_port.h src/core/fops.h src/core/bops.h src/core/stack.h src/core/hold.h src/core/genome.h build/core/map/memmap.h" # one line of a program's output: newlines as /, control bytes as ?, cut to 60 columns short() { diff --git a/src/tools/zcc b/src/tools/zcc index ba38e97..a53fe01 100755 --- a/src/tools/zcc +++ b/src/tools/zcc @@ -41,7 +41,7 @@ trap cleanup EXIT # the map and the genome for this program only ( cd "$here" && bash src/tools/automap.sh run "$work/run" src/runtime/run.zc "$abs" ) >/dev/null cp "$here/src/micro/micro.c" "$here/src/micro/micro_port.h" "$here/src/micro/port_linux.c" \ - "$here/src/core/fops.h" "$here/src/core/bops.h" "$here/src/core/stack.h" "$here/src/core/genome.h" "$work/run/" + "$here/src/core/fops.h" "$here/src/core/bops.h" "$here/src/core/stack.h" "$here/src/core/hold.h" "$here/src/core/genome.h" "$work/run/" # static where the toolchain allows it; a plain link otherwise, with a note static=-static 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/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/test.sh b/tests/test.sh index 90599ed..c31cfb7 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -337,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" @@ -381,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##$input#g" | tr '\n' '/') b=$($T/zymr &1 | tr '\n' '/') @@ -413,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" 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 -- cgit v1.2.3