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/ext_cache_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/ext_cache_test.js')
| -rw-r--r-- | tests/drivers/ext_cache_test.js | 27 |
1 files changed, 26 insertions, 1 deletions
diff --git a/tests/drivers/ext_cache_test.js b/tests/drivers/ext_cache_test.js index 11bf50b..f389fcc 100644 --- a/tests/drivers/ext_cache_test.js +++ b/tests/drivers/ext_cache_test.js @@ -29,8 +29,15 @@ const stub = { appendMarkdown(v) { this.value += v; return this; } appendCodeblock(v, language) { this.value += '\n```' + language + '\n' + v + '\n```\n'; return this; } }, + CompletionItem: class { constructor(label, kind) { Object.assign(this, { label, kind }); } }, + CompletionList: class { constructor(items, isIncomplete) { Object.assign(this, { items, isIncomplete }); } }, + CompletionItemKind: { Variable: 5 }, + CompletionItemTag: { Deprecated: 1 }, + CodeActionKind: { QuickFix: 'quickfix' }, + CodeAction: class { constructor(title, kind) { Object.assign(this, { title, kind }); } }, + WorkspaceEdit: class { constructor() { this.edits = []; } replace(uri, range, newText) { this.edits.push({ uri, range, newText }); } }, Hover: class { constructor(c) { this.contents = c; } }, - Uri: { parse: s => ({ toString: () => s, fsPath: decodeURIComponent(s.replace(/^file:\/\//, '')) }) }, + Uri: { file: p => ({ toString: () => 'file://' + p, fsPath: p }), parse: s => ({ toString: () => s, fsPath: decodeURIComponent(s.replace(/^file:\/\//, '')) }) }, workspace: { workspaceFolders: undefined, textDocuments: world.textDocuments, @@ -41,6 +48,7 @@ const stub = { for (const k of ['onDidChange', 'onDidCreate', 'onDidDelete']) w[k] = f => { w.handlers[k] = f; return { dispose() {} }; }; return w; }, + registerTextDocumentContentProvider: () => ({ dispose() {} }), ...['onDidChangeConfiguration', 'onDidOpenTextDocument', 'onDidChangeTextDocument', 'onDidSaveTextDocument', 'onDidCloseTextDocument'] .reduce((o, k) => { o[k] = f => { world.listeners[k] = f; return { dispose() {} }; }; return o; }, {}), }, @@ -54,7 +62,12 @@ const stub = { delete() {}, dispose() {}, }), registerDocumentSemanticTokensProvider: () => ({ dispose() {} }), + registerCompletionItemProvider: (sel, p) => { world.completion = p; return { dispose() {} }; }, + registerCodeActionsProvider: (sel, p) => { world.actions = p; return { dispose() {} }; }, registerHoverProvider: (sel, p) => { world.hover = p; return { dispose() {} }; }, + registerDocumentFormattingEditProvider: () => ({ dispose() {} }), + registerDefinitionProvider: (sel, p) => { world.definition = p; return { dispose() {} }; }, + registerReferenceProvider: (sel, p) => { world.references = p; return { dispose() {} }; }, }, commands: { registerCommand: () => ({ dispose() {} }) }, }; @@ -116,6 +129,9 @@ const mainUri = 'file://' + main; const hv = world.hover && await world.hover.provideHover(mainDoc, { line: 1, character: 4 }); const hc = hv && hv.contents[0]; check('the hover is markdown with a zc code block, parsed and not escaped', hc && !hc.escaped && /^```zc\n/.test(hc.value) && /\n```/.test(hc.value), JSON.stringify(hc)); + const suggestions = await world.completion.provideCompletionItems(mainDoc, { line: 1, character: 4 }, { isCancellationRequested: false }); + check('completion provider returns signatures and replacement ranges', suggestions instanceof stub.CompletionList && suggestions.items.some(c => c.detail && c.range && c.insertText), JSON.stringify(suggestions && suggestions.items.slice(0, 2))); + check('cancelled completion requests are ignored', await world.completion.provideCompletionItems(mainDoc, { line: 1, character: 4 }, { isCancellationRequested: true }) === null); check('session one: the answer is saved under a key', savedKeys.length === 1 && /^[0-9a-f]{64}$/.test(savedKeys[0]), JSON.stringify(savedKeys)); ext.deactivate(); await sleep(700); @@ -146,6 +162,15 @@ const mainUri = 'file://' + main; await sleep(200); check('the old tree is answered from the cache, without asking the server', world.lines.some(l => /from the cache/.test(l)) && !world.lines.some(l => /-> textDocument\/didChange/.test(l)), JSON.stringify(world.lines.slice(-4))); + const expiredDoc = doc(path.join(root, 'expired.zc'), 'include rt; fn main() {\n let used = rt.new(int, 3);\n rt.free(used);\n \n}'); + const expiredList = await world.completion.provideCompletionItems(expiredDoc, { line: 3, character: 1 }, { isCancellationRequested: false }); + const expiredItem = expiredList && expiredList.items.find(c => c.label === 'used'); + check('completion maps consumed lifetimes to the editor strikethrough tag', expiredItem && expiredItem.tags?.[0] === stub.CompletionItemTag.Deprecated && /lifetime ended/.test(expiredItem.documentation?.value)); + const actionDoc = doc(path.join(root, 'imports.zc'), 'fn main() { rt.put_n(7); }'); + const actions = await world.actions.provideCodeActions(actionDoc, new stub.Range(0, 15, 0, 15), {}, { isCancellationRequested: false }); + check('quick fixes reach the editor as workspace edits', actions.some(a => a.kind === 'quickfix' && a.edit.edits.some(e => e.newText === 'include rt;\n'))); + const cancelled = await world.actions.provideCodeActions(actionDoc, new stub.Range(0, 15, 0, 15), {}, { isCancellationRequested: true }); + check('cancelled quick-fix requests produce no editor edits', cancelled.length === 0); ext.deactivate(); await sleep(700); fs.rmSync(root, { recursive: true, force: true }); |
