diff options
| author | 2026-10-14 08:29:46 +0330 | |
|---|---|---|
| committer | 2026-10-14 08:29:46 +0330 | |
| commit | 1c53304d03414890af0da7432d1aea87e754a14a (patch) | |
| tree | 97190d86cf548c9bc63f68c86a4d2a4f09809713 /tests/drivers/hover_features_test.js | |
| parent | a (diff) | |
feat: grow memory limits, add icon/actor libraries, overhaul LSP diagnostics
Compiler and VM
- make every memory map limit dynamic and adjustable at both build time and
runtime, including compiler tables, stacks, and every execution region
- reserve and grow tables, operand and return stacks, frame segments, and
image-building output without relocating live code or globals
- rename i/o and string helpers consistently (puts -> put_s, putn -> put_n,
scat -> cat_s) across compiler, runtime, examples, tests, and docs
- recast and consume values assigned to globals from inside functions
- allow fixed and const together, add typed closure returns (fn:t(...)),
multi-include syntax (include rt, run, core;), and recurse type inference
- never infer string literals as word, anywhere, as argument, variable, or
return type
- draft docs/BORROW.md: a borrow checker less intrusive than Rust's but more
intelligent
LSP and editor integration
- require explicit includes and give every toolchain area its own namespace
(rt, lsp, run, core)
- hover for built-in types, inferred types, values known at hover time, array
and pointer lifetime/size, library names in include statements, and inferred
lifetimes with explanations
- honor /* */ comments as documentation for variables and arguments, and stop
misattributing section headers or trailing comments as variable hints
- stream diagnostics and cancel stale requests on change
- jump to definition and references, including cross-file
- quick fixes with automatic library import, and namespace completion
Hints and diagnostics
- render hints as blue squigglies by default, with hints on/small/off per file
- suppress magic-number hints via a preceding /* */ comment, and say so
- warn on unused arguments; allow multiple _ discards in parameters, pattern
matching, and tagged enums, warning if a _ is actually used
- rewrite hint and comment prose in professional compiler-doc register
Libraries
- add icon.zc: run-time self-modification, find/replace syntax, type and block
edits, and step-through inspection of locals and globals
- add actor.zc: async actors with Actor<I,O>, implicit this, spawn/recv/send,
injected into the compiler machinery at include time rather than built in
Tooling and docs
- reorganize sources, tests, and designs into subdirectories
- unify windows entry points in tinyvm.bat and add a matching tinyvm.sh
- add --help across the toolchain
- polish the learning guide, stdlib docs, and design notes
Tests
- add accept, reject, and regression coverage across the compiler, LSP,
- runtime, icon, actors, threads, formatting, and the toolchain contracts,
plus fuzzers and property tests
Diffstat (limited to 'tests/drivers/hover_features_test.js')
| -rw-r--r-- | tests/drivers/hover_features_test.js | 86 |
1 files changed, 66 insertions, 20 deletions
diff --git a/tests/drivers/hover_features_test.js b/tests/drivers/hover_features_test.js index 895e923..d6e1226 100644 --- a/tests/drivers/hover_features_test.js +++ b/tests/drivers/hover_features_test.js @@ -38,15 +38,15 @@ for (const type of ['word', 'int', 'char', 'bool', 'float', 'f64', 'f32', 'byte' assert.ok(value && value.startsWith('```zc\n') && value.includes('\n\n'), type + ' has formatted built-in documentation'); } assert.match(hover('void noop() {}\nfn main() { return 0; }\n', 'void'), /no meaningful result/); -const array = 'fn main() {\n [4]u8 values;\n return values[0];\n}\n'; +const array = 'fn main() {\n u8[4] values;\n return values[0];\n}\n'; assert.match(hover(array, '[4]'), /fixed length of 4/); -assert.match(hover(array, 'values', 1), /type \[4\]u8/); +assert.match(hover(array, 'values', 1), /\(u8\[4\]\) let values/); const struct = 'struct pair { int left; float right; };\nfn main() { pair value; return value.left; }\n'; assert.match(hover(struct, 'pair', 1), /int left;[\s\S]*float right;/); -assert.match(hover(struct, 'value', 1), /type pair/); +assert.match(hover(struct, 'value', 1), /\(pair\) let value/); const fields = 'struct pair { int /* left field */ left, /* right field */ right; };\nfn main() { pair p; return p.left + p.right; }\n'; -assert.match(hover(fields, 'left +'), /field; type int[\s\S]*left field/); -assert.match(hover(fields, 'right;'), /field; type int[\s\S]*right field/); +assert.match(hover(fields, 'left +'), /\(int\) let left \/\/ field;[\s\S]*left field/); +assert.match(hover(fields, 'right;'), /\(int\) let right \/\/ field;[\s\S]*right field/); const empty = '/**/ int helper() { return 1; }\nfn main() { return helper(); }\n'; assert.match(hover(empty, 'helper();'), /int helper\(\)/); const variableDocs = 'fn main() {\n int /* first variable */ first = 1, /* second variable */ second = 2;\n return first + second;\n}\n'; @@ -63,23 +63,69 @@ const functionDocs = '/**\n * adds **one** to its argument.\n */\nint add(int x) assert.match(hover(functionDocs, 'add(2)'), /adds \*\*one\*\*/); const inferred = 'fn twice(x) { return x * 2; }\nfn main() { let value = twice(3); return value; }\n'; assert.match(hover(inferred, 'twice(3)'), /int twice\(int x\)/); -assert.match(hover(inferred, 'x *'), /type int/); -assert.match(hover(inferred, 'value;'), /type int/); +assert.match(hover(inferred, 'x *'), /\(int\) let x \/\/ parameter;/); +assert.match(hover(inferred, 'value;'), /\(int\) let value/); const pointer = 'int read(int* p) { return p[0]; }\nfn main() { int value = 3; return read(&value); }\n'; -assert.match(hover(pointer, 'p[0]'), /type int\*[\s\S]*pointer to `int`/); -const alias = 'type row = [3]int;\nfn main() { row values; return values[0]; }\n'; -assert.match(hover(alias, 'row values'), /\[3\]int[\s\S]*fixed length of 3/); +assert.match(hover(pointer, 'p[0]'), /\(int\*\) let p \/\/ parameter;[\s\S]*pointer to `int`/); +const alias = 'type row = int[3];\nfn main() { row values; return values[0]; }\n'; +assert.match(hover(alias, 'row values'), /int\[3\][\s\S]*fixed length of 3/); const enumeration = 'enum color { red, green = 5, blue };\nfn main() { color shade = green; return shade; }\n'; -assert.match(hover(enumeration, 'shade;'), /type color/); -const dynamic = 'fn main() { []int items; push(items, 3); return len(items); }\n'; -assert.match(hover(dynamic, 'items);'), /type \[\]int[\s\S]*growable array handle/); +assert.match(hover(enumeration, 'shade;'), /\(color\) let shade/); +const dynamic = 'fn main() { int[?] items; push(items, 3); return len(items); }\n'; +assert.match(hover(dynamic, 'items);'), /\(int\[\?\]\) let items[\s\S]*growable array handle/); const callable = 'fn main() { let apply = fn(int x) { return x + 1; }; return apply(2); }\n'; -assert.match(hover(callable, 'apply(2)'), /type .*\([\s\S]*callable value/); -assert.match(hover(callable, 'apply(2)'), /type int\(int\)/); +assert.match(hover(callable, 'apply(2)'), /\(.*\([\s\S]*callable value/); +assert.match(hover(callable, 'apply(2)'), /\(int\(int\)\) let.m apply/); const floatClosure = 'fn main() { let f = fn(float x) { return x + 1.5; }; let result = f(2.0); return result; }\n'; -assert.match(hover(floatClosure, 'result;'), /type float/); -const inferredPointer = 'struct node { int value; };\nfn make_node() { return new(node); }\nfn main() { let p = make_node(); return p.value; }\n'; -assert.match(hover(inferredPointer, 'p.value'), /type node\*/); -const aggregateAlias = 'fn main() { [3]int a; a[1] = 7; let alias = a; return alias[1]; }\n'; -assert.match(hover(aggregateAlias, 'alias[1]'), /type int\*/); +assert.match(hover(floatClosure, 'result;'), /\(float\) let result/); +const inferredPointer = 'include rt;\nstruct node { int value; };\nfn make_node() { return new(node); }\nfn main() { let p = make_node(); return p.value; }\n'; +assert.match(hover(inferredPointer, 'p.value'), /\(node\*\) let.m p/); +const aggregateAlias = 'fn main() { int[3] a; a[1] = 7; let alias = a; return alias[1]; }\n'; +assert.match(hover(aggregateAlias, 'alias[1]'), /\(int\*\) let alias/); +const sections = '// --- values ---\n// these declarations form a group.\nconst int limit = 7;\nfn main() { return limit; }'; +assert.ok(!hover(sections, 'limit;').includes('these declarations form a group')); +assert.ok(!hover(sections, 'limit;').includes('--- values ---')); +const blockSection = '/* ---- values ---- */\nint limit = 7;\nfn main() { return limit; }'; +assert.ok(!hover(blockSection, 'limit;').includes('---- values ----')); +const trailing = 'fn main() {\n int n = 7; // the current count\n int next = 2;\n return n + next;\n}'; +assert.match(hover(trailing, 'n +'), /the current count/); +assert.ok(!hover(trailing, 'next;').includes('the current count')); +const trailingBlock = 'fn main() { int a = 1, b = 2; /* final count */\n return a + b; }'; +assert.ok(!hover(trailingBlock, 'a +').includes('final count')); +assert.match(hover(trailingBlock, 'b;'), /final count/); +const adjacent = 'fn main() { int a /* first count */ = 1, b /* second count */ = 2; return a + b; }'; +assert.match(hover(adjacent, 'a +'), /first count/); +assert.ok(!hover(adjacent, 'a +').includes('second count')); +assert.match(hover(adjacent, 'b;'), /second count/); +// section headings end a doc block; trailing comments belong to their own line's declaration +const sectionDocs = '// ---- one ----\n\n// adds.\nint add(int a, int b) { return a + b; } // after add\n// overview\n// ---- two ----\nint sub(int a, int b) { return a - b; }\n// ---- three ----\n// own doc\nint mul(int a, int b) { return a * b; }\nint g = 3; /* after g */\nfn main() { return add(1, 2) + sub(3, 1) + mul(2, 2) + g; }\n'; +const addHover = hover(sectionDocs, 'add(1'); +assert.ok(addHover.includes('adds.') && addHover.includes('after add') && !addHover.includes('overview') && !addHover.includes('after g'), addHover); +assert.strictEqual(hover(sectionDocs, 'sub(3'), '```zc\nint sub(int a, int b)\n```'); +const mulHover = hover(sectionDocs, 'mul(2'); +assert.ok(!mulHover.includes('own doc') && !mulHover.includes('three') && !mulHover.includes('after'), mulHover); +assert.ok(hover(sectionDocs, 'g; }').includes('after g')); +// ownership and transfers explained in hovers +const lifeDocs = 'include rt; struct node { int v; node* next; };\nint*.u make(int n) { int* q = new(int); *q = n; return u*q; }\nfn take(.d p) { return p[0]; }\nfn main() {\n let a = make(1);\n node* b = new(node), c = new(node);\n b.next = c;\n node* r = b.next;\n let d = new(3);\n take(d*d);\n return a[0] + r.v;\n}\n'; +assert.match(hover(lifeDocs, 'q = new'), /let.m q[\s\S]*passed up: returned on line 2/); +assert.match(hover(lifeDocs, 'a ='), /let.m a[\s\S]*freed where its block ends on line 12/); +assert.match(hover(lifeDocs, 'r.v'), /borrows from `b`, declared on line 6/); +assert.match(hover(lifeDocs, 'c = new'), /passed down: stored in a container `b` on line 7/); +assert.match(hover(lifeDocs, 'd = new'), /passed down: given to a d parameter on line 10/); +const declaredResult = 'fn main() { let f = fn:float(int x) { return x; }; return f(2); }\n'; +assert.match(hover(declaredResult, 'f(2)'), /\(float\(int\)\) let.m f/); +const nonDocs = '//: scratch region overview\nint scratch = 1;\n/* public count */ int count = 2; //: implementation note\nfn main() { return scratch + count; }'; +assert.ok(!hover(nonDocs, 'scratch +').includes('scratch region overview')); +assert.match(hover(nonDocs, 'count;'), /public count/); +assert.ok(!hover(nonDocs, 'count;').includes('implementation note')); +const globals = 'let hello = "hello", prog[20000];\nint count = 3;\nfn main() { return hello[0] + prog[0] + count; }\n'; +for (const [name, type, use] of [['hello', 'char*', 'hello[0]'], ['prog', 'word[20000]', 'prog[0]'], ['count', 'int', 'count;']]) { + for (const needle of [name, use]) { + const value = hover(globals, needle); + assert.ok(value.startsWith('```zc\n(' + type + ') let ' + name + ' // global;\n```'), value); + assert.ok(!value.includes('; type '), value); + } +} +assert.match(hover('include run; fn main() { return run.sval[0]; }', 'sval'), /symbol[\s\S]*value/i); +assert.match(hover('include rt; fn main() { return rt.len_s(b"bytes"); }', 'len_s'), /number of bytes in a packed byte string/i); console.log('ok built-in and composite types, inferred signatures, and separate block docs'); |
