From de4da84ca3159ad0ebcf13729716be5f4d7bbc2a Mon Sep 17 00:00:00 2001 From: zinc Date: Thu, 15 Oct 2026 09:42:25 +0330 Subject: std: add std.Io (print, println, nl, put_*, put_f, get_c, eof, read, getline) with test, learn example and docs --- tests/programs/stdio.expected | 8 ++++++++ tests/programs/stdio.zc | 18 ++++++++++++++++++ tests/test.sh | 1 + 3 files changed, 27 insertions(+) create mode 100644 tests/programs/stdio.expected create mode 100644 tests/programs/stdio.zc (limited to 'tests') diff --git a/tests/programs/stdio.expected b/tests/programs/stdio.expected new file mode 100644 index 0000000..4a7fd8a --- /dev/null +++ b/tests/programs/stdio.expected @@ -0,0 +1,8 @@ +hi -42 2.500000 +line +bytes 0xff s +8 caught 7 +3:abc +3:lon +7 103 +-1 1 diff --git a/tests/programs/stdio.zc b/tests/programs/stdio.zc new file mode 100644 index 0000000..5a79262 --- /dev/null +++ b/tests/programs/stdio.zc @@ -0,0 +1,18 @@ +include rt, std; + +// std.Io: the writers, a capture of them, and the line reader over program input. +fn main() { + std.Io.print("hi "); std.Io.put_n(-42); std.Io.put_c(32); std.Io.put_f(2.5); std.Io.nl(); + std.Io.println("line"); std.Io.put_bs(b"bytes"); std.Io.put_c(32); std.Io.put_hex(255); + std.Io.put_c(32); std.Io.put_s("s"); std.Io.nl(); + let cap = std.capture.start(); + std.Io.print("caught "); std.Io.put_n(7); + std.capture.end(cap); + std.Io.put_n(std.Text.len(cap)); std.Io.put_c(32); std.Io.println(cap); + char[32] buf; int n = std.Io.getline(buf, 32); + std.Io.put_n(n); std.Io.print(":"); std.Io.println(buf); + n = std.Io.getline(buf, 4); std.Io.put_n(n); std.Io.print(":"); std.Io.println(buf); + n = std.Io.read(buf, 32); std.Io.put_n(n); std.Io.put_c(32); std.Io.put_n(buf[0]); std.Io.nl(); + n = std.Io.getline(buf, 32); std.Io.put_n(n); std.Io.put_c(32); std.Io.put_n(std.Io.eof()); std.Io.nl(); + return 0; +} diff --git a/tests/test.sh b/tests/test.sh index 8bf7a9b..7745a66 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -155,6 +155,7 @@ run(){ # $1 = vm command, $2 = label chk "$($vm < tests/programs/use_std.zc)" "42 -7 1" "$l include and the string helpers" chk "$($vm < tests/programs/stdbuf.zc)" "4 1 266 8" "$l stdlib arena and packed byte buffer" chk "$($vm < tests/programs/stdmore.zc)" "$(printf '5 1 0 0 7 copy me 12 -1 0 1 0 1\n9 mixed 123 9 MIXED 123\n11 [padded line]\n42 3 9 10 12 81 9 10 -1 0\n6 1 2 -1 1 0')" "$l stdlib text, byte-string and num helpers" + chk "$( (cat tests/programs/stdio.zc; printf '`abc\nlonger\nxyz') | $vm)" "$(cat tests/programs/stdio.expected)" "$l std.Io writers, capture, getline and read" chk "$(ZC_FILE=tests/data/hi.txt $vm < examples/cli.zc)" "6 h" "$l reading a file named by the environment" chk "$(ZC_ARG_TEST=ok $vm < tests/programs/args.zc)" "1 1 1" "$l argv and envp from the host, argv[0] is on stdin" chk "$(ZC_ARG_TEST=ok $vm < tests/programs/capture.zc)" "0 -- cgit v1.2.3 From 992f004bf31e8902744d86dee595305907144ff1 Mon Sep 17 00:00:00 2001 From: zinc Date: Thu, 15 Oct 2026 09:43:55 +0330 Subject: lsp: complete a module path one level at a time (std. lists groups, std.File. and std.Io. their members) --- src/lsp/server.zc | 28 ++++++++++++++++++++++++---- tests/drivers/completion_test.js | 13 ++++++++++++- 2 files changed, 36 insertions(+), 5 deletions(-) (limited to 'tests') diff --git a/src/lsp/server.zc b/src/lsp/server.zc index bc2c967..65137a6 100644 --- a/src/lsp/server.zc +++ b/src/lsp/server.zc @@ -3180,6 +3180,16 @@ int gen_completion() { } ws("]}}"); return 0; } +// a group such as File in std.File.write, offered once as a namespace unless its own symbol (a struct) is listed. +int cp_group(char* nm, int from, int to) { + int k = 0; char* g = cp_copy(nm); + g[to] = 0; + if (run.lookup(g) >= 0) return 0; + while (k < cp_n) { if (rt.eq_w(cp_name[k], g + from)) return 0; k++; } + hn = 0; hov_text("namespace "); hov_text(g); + cp_add(g + from, 9, 0, 2); + return 0; +} int do_completion(int i) { int s, k, j, old, n, head, c; word member, fields; char* nm; char* owner = 0; cp_i = i; cp_n = 0; @@ -3190,20 +3200,30 @@ int do_completion(int i) { n = cp_cursor - cp_start; cp_prefix = lsp_grow(0, 0, n + 1); k = 0; while (k < n) { cp_prefix[k] = dc(doff[i], cp_start + k); k++; } if (cp_start > 0 && dc(doff[i], cp_start - 1) == '.') { + // the owner is the whole dotted path before the last dot (std or std.File); its first part must be a module. head = cp_start - 1; - while (head > 0 && hid(dc(doff[i], head - 1))) head--; + while (head > 0 && (hid(dc(doff[i], head - 1)) || (dc(doff[i], head - 1) == '.' && head > 1 && hid(dc(doff[i], head - 2))))) head--; n = cp_start - 1 - head; owner = m*lsp_grow(0, 0, n + 1); k = 0; while (k < n) { owner[k] = dc(doff[i], head + k); k++; } owner[n] = 0; - if (!run.module_known(owner)) owner = 0; + k = 0; while (owner[k] && owner[k] != '.') k++; + c = owner[k]; owner[k] = 0; + if (!run.module_known(owner)) owner = 0; else owner[k] = c; } // the full check supplies functions declared later; the probe supplies locals and their current lifetimes. ensure_checked(i); if (owner) { - if (run.module_imported(owner)) { + // one level at a time: owner.name is listed, owner.group.name only as its group. + k = 0; while (owner[k] && owner[k] != '.') k++; + c = owner[k]; owner[k] = 0; j = run.module_imported(owner); owner[k] = c; + if (j) { n = rt.len_w(owner); s = 0; while (s < run.nsym) { nm = run.sname[s]; k = 0; while (k < n && nm[k] == owner[k]) k++; - if (k == n && nm[k] == '.' && run.skind[s] != run.K_DOC && run.lookup(nm) == s) cp_symbol(s, nm + n + 1); + if (k == n && nm[k] == '.' && nm[k + 1] && run.skind[s] != run.K_DOC && run.lookup(nm) == s) { + j = k + 1; while (nm[j] && nm[j] != '.') j++; + if (!nm[j]) cp_symbol(s, nm + n + 1); + else cp_group(nm, n + 1, j); + } s++; } } diff --git a/tests/drivers/completion_test.js b/tests/drivers/completion_test.js index f1ee5e6..4b767a1 100644 --- a/tests/drivers/completion_test.js +++ b/tests/drivers/completion_test.js @@ -104,4 +104,15 @@ assert.match(get(r.items, 'map').documentation.value, /transform.*each element/) assert.ok(!r.items.some(c => ['push', 'pop', 'resize'].includes(c.label)), 'library algorithms do not make a fixed array growable'); r = complete('include rt; fn main() { int[?] items = {}; items.| }'); assert.ok(!r.items.some(c => ['map', 'filter'].includes(c.label)), 'library methods require an explicit import'); -console.log('ok completion: signatures, docs, fuzzy ranking, scope, array members, shadowing and consumed lifetimes'); +r = complete('include std; fn main() { std.| }'); +for (const name of ['File', 'Io', 'Text', 'Host', 'argv', 'bnew']) get(r.items, name); +assert.ok(!r.items.some(c => c.label.includes('.')), 'module completion lists one level: ' + r.items.filter(c => c.label.includes('.')).map(c => c.label)); +r = complete('include std; fn main() { std.File.| }'); +for (const name of ['read', 'write']) get(r.items, name); +assert.ok(!r.items.some(c => ['Io', 'File', 'main', 'int'].includes(c.label)), 'group completion lists only its members'); +r = complete('include std; fn main() { std.Io.| }'); +for (const name of ['print', 'println', 'put_n', 'put_f', 'getline']) get(r.items, name); +assert.ok(!r.items.some(c => ['write', 'itoa', 'main', 'int'].includes(c.label)), 'std.Io. lists only Io members'); +r = complete('include std; fn main() { std.Io.pr| }'); +assert.deepStrictEqual(r.items.map(c => c.label).sort(), ['print', 'println']); +console.log('ok completion: signatures, docs, fuzzy ranking, scope, array members, shadowing, consumed lifetimes and one level of a module path'); -- cgit v1.2.3