diff options
| author | 2026-10-14 08:29:46 +0330 | |
|---|---|---|
| committer | 2026-10-14 08:29:46 +0330 | |
| commit | 1c53304d03414890af0da7432d1aea87e754a14a (patch) | |
| tree | 97190d86cf548c9bc63f68c86a4d2a4f09809713 /tests/actor | |
| 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/actor')
23 files changed, 205 insertions, 0 deletions
diff --git a/tests/actor/accept/declaration.zc b/tests/actor/accept/declaration.zc new file mode 100644 index 0000000..099c0eb --- /dev/null +++ b/tests/actor/accept/declaration.zc @@ -0,0 +1,11 @@ +namespace; +include rt, actor; +typecheck on; +actor Counter { int total; int handle(int value) { this.total += value; return this.total; } } +fn main() { + Counter* a = rt.new(Counter), b = rt.new(Counter); let left = 0, right = 0; + a.spawn(); b.spawn(); a.recv(fn(int n) { left = n; return 0; }); b.recv(fn(int n) { right = n; return 0; }); + a.send(2); a.send(3); b.send(7); a.await(); b.await(); + rt.put_n(left); rt.put_c(' '); rt.put_n(right); rt.put_c(' '); rt.put_n(a.total); rt.put_c(' '); rt.put_n(b.total); rt.put_c(10); + a.close(); b.close(); return 0; +} diff --git a/tests/actor/accept/failed_worker.zc b/tests/actor/accept/failed_worker.zc new file mode 100644 index 0000000..056a6b6 --- /dev/null +++ b/tests/actor/accept/failed_worker.zc @@ -0,0 +1,11 @@ +namespace; +include rt, actor; +typecheck on; +int fail(int n) { rt.syscall(7, 2, 0, 0); return n; } +int healthy(int n) { return n + 1; } +fn main() { + actor.Actor<int,int>* a = rt.new(actor.Actor<int,int>); a.spawn(fail); a.recv(fn(int n) { return 0; }); a.send(1); + rt.put_n(a.await()); rt.put_c(' '); rt.put_n(a.send(2)); rt.put_c(' '); a.close(); + actor.Actor<int,int>* b = rt.new(actor.Actor<int,int>); let result = 0; b.spawn(healthy); b.recv(fn(int n) { result = n; return 0; }); b.send(2); b.await(); + rt.put_n(result); rt.put_c(10); b.close(); return 0; +} diff --git a/tests/actor/accept/functions.zc b/tests/actor/accept/functions.zc new file mode 100644 index 0000000..f869789 --- /dev/null +++ b/tests/actor/accept/functions.zc @@ -0,0 +1,12 @@ +namespace; +include rt, actor; +typecheck on; +type Operation = int(int); +int handle(Operation operation) { return operation(3); } +fn main() { + actor.Actor<Operation,int>* a = rt.new(actor.Actor<Operation,int>); + a.spawn(handle); let result = 0; a.recv(fn(int n) { result = n; return 0; }); + char* text = rt.new(char, 3); text[0] = 'a'; text[1] = 'b'; let offset = 7; float scale = 2.0; + Operation operation = fn:int(int n) { if (scale == 2.0) return n + offset + rt.len_w(text); return -1; }; + a.send(operation); a.await(); rt.put_n(result); rt.put_c(10); a.close(); return 0; +} diff --git a/tests/actor/accept/generic_declaration.zc b/tests/actor/accept/generic_declaration.zc new file mode 100644 index 0000000..a5e5e77 --- /dev/null +++ b/tests/actor/accept/generic_declaration.zc @@ -0,0 +1,15 @@ +namespace; +include rt, actor; +typecheck on; +actor Counter<T> { T total; T handle(T input) { this.total += input; return this.total; } } +fn main() { + Counter<int>* a = rt.new(Counter<int>), b = rt.new(Counter<int>); + Counter<float>* c = rt.new(Counter<float>); int left = 0, right = 0, floating = 0; + a.spawn(); b.spawn(); c.spawn(); + a.recv(fn(int n) { left = n; return 0; }); b.recv(fn(int n) { right = n; return 0; }); + c.recv(fn(float n) { floating = n; return 0; }); + a.send(2); a.send(3); b.send(7); c.send(1.5); c.send(2.5); + a.await(); b.await(); c.await(); + rt.put_n(left); rt.put_c(' '); rt.put_n(right); rt.put_c(' '); rt.put_n(floating); rt.put_c(' '); rt.put_n(a.total); rt.put_c(10); + a.close(); b.close(); c.close(); return 0; +} diff --git a/tests/actor/accept/graphs.zc b/tests/actor/accept/graphs.zc new file mode 100644 index 0000000..f90469c --- /dev/null +++ b/tests/actor/accept/graphs.zc @@ -0,0 +1,14 @@ +namespace; +include rt, actor; +typecheck on; +struct Node { int value; Node* next; } +struct Message { char* text; int[?] numbers; Node* node; } +int handle(Message* m) { m.text[0] = 'X'; m.numbers[0] += 10; return rt.len_w(m.text) + m.numbers[0] + m.node.next.value; } +fn main() { + actor.Actor<Message*, int>* a = rt.new(actor.Actor<Message*, int>); + a.spawn(handle); let result = 0; a.recv(fn(int n) { result = n; return 0; }); + Message* m = rt.new(Message); m.text = rt.new(char, 4); m.text[0] = 'a'; m.text[1] = 'b'; m.text[2] = 'c'; + m.numbers = rt.new(int[?]); push(m.numbers, 5); m.node = rt.new(Node); m.node.value = 7; m.node.next = m.node; + a.send(m); a.await(); + rt.put_n(result); rt.put_c(' '); rt.put_c(m.text[0]); rt.put_c(' '); rt.put_n(m.numbers[0]); rt.put_c(10); a.close(); return 0; +} diff --git a/tests/actor/accept/lifecycle.zc b/tests/actor/accept/lifecycle.zc new file mode 100644 index 0000000..0c953e4 --- /dev/null +++ b/tests/actor/accept/lifecycle.zc @@ -0,0 +1,10 @@ +namespace; +include rt, actor; +typecheck on; +int handle(int n) { return n; } +fn main() { + let total = 0; + { actor.Actor<int,int>* a = rt.new(actor.Actor<int,int>); a.spawn(handle); a.recv(fn(int n) { total += n; return 0; }); a.send(1); a.await(); a.close(); rt.put_n(a.send(3)); rt.put_c(' '); a.close(); } + { actor.Actor<int,int>* b = rt.new(actor.Actor<int,int>); b.spawn(handle); b.recv(fn(int n) { total += n; return 0; }); b.send(2); b.await(); b.close(); } + rt.put_n(total); rt.put_c(10); return 0; +} diff --git a/tests/actor/accept/parallel.zc b/tests/actor/accept/parallel.zc new file mode 100644 index 0000000..3d47f34 --- /dev/null +++ b/tests/actor/accept/parallel.zc @@ -0,0 +1,18 @@ +namespace; +include rt, actor; +typecheck on; +int delayed(int n) { rt.syscall(48, 300, 0, 0); return n + 1; } +fn main() { + actor.Actor<int, int>* a = rt.new(actor.Actor<int, int>), b = rt.new(actor.Actor<int, int>); + let first = 0, second = 0; + a.spawn(delayed); b.spawn(delayed); + a.recv(fn(int value) { first = value; return 0; }); + b.recv(fn(int value) { second = value; return 0; }); + let started = rt.syscall(50, 0, 0, 0); + a.send(10); b.send(20); + rt.put_n(first); rt.put_c(' '); rt.put_n(second); rt.put_c(10); + a.await(); b.await(); + rt.put_n(first); rt.put_c(' '); rt.put_n(second); rt.put_c(10); + rt.put_n(rt.syscall(50, 0, 0, 0) - started); rt.put_c(10); + a.close(); b.close(); return 0; +} diff --git a/tests/actor/accept/pointer_scalar.zc b/tests/actor/accept/pointer_scalar.zc new file mode 100644 index 0000000..219129a --- /dev/null +++ b/tests/actor/accept/pointer_scalar.zc @@ -0,0 +1,13 @@ +namespace; +include rt, actor; +typecheck on; +struct Node { int value; } +struct Message { int marker; Node* node; } +fn main() { + Node* original = rt.new(Node); original.value = 4; let marker = (original as int) + 0; + actor.Actor<Message*,int>* a = rt.new(actor.Actor<Message*,int>); + a.spawn(fn:int(Message* m) { return m.marker == marker && m.node as int != m.marker && m.node.value == 4; }); + let result = 0; a.recv(fn(int n) { result = n; return 0; }); + Message* message = rt.new(Message); message.marker = marker; message.node = original; + a.send(message); a.await(); rt.put_n(result); rt.put_c(10); a.close(); return 0; +} diff --git a/tests/actor/accept/results.zc b/tests/actor/accept/results.zc new file mode 100644 index 0000000..9cc557e --- /dev/null +++ b/tests/actor/accept/results.zc @@ -0,0 +1,9 @@ +namespace; +include rt, actor; +typecheck on; +char*.u respond(int n) { char* p = rt.new(char, 3); p[0] = 'o'; p[1] = 'k'; return u*p; } +fn main() { + actor.Actor<int, char*>* a = rt.new(actor.Actor<int, char*>); + a.spawn(respond); a.recv(fn(char* value) { rt.put_s(value); rt.put_c(10); return 0; }); + a.send(1); a.await(); a.close(); return 0; +} diff --git a/tests/actor/accept/safepoint.zc b/tests/actor/accept/safepoint.zc new file mode 100644 index 0000000..23c8eca --- /dev/null +++ b/tests/actor/accept/safepoint.zc @@ -0,0 +1,10 @@ +namespace; +include rt, actor; +typecheck on; +int handle(int n) { return n * 2; } +fn main() { + actor.Actor<int,int>* a = rt.new(actor.Actor<int,int>); + let result = 0; a.spawn(handle); a.recv(fn(int n) { result = n; return 0; }); + a.send(4); rt.syscall(48, 50, 0, 0); + rt.put_n(result); rt.put_c(10); a.close(); return 0; +} diff --git a/tests/actor/accept/state.zc b/tests/actor/accept/state.zc new file mode 100644 index 0000000..e53a12a --- /dev/null +++ b/tests/actor/accept/state.zc @@ -0,0 +1,15 @@ +namespace; +include rt, actor; +typecheck on; +actor Counter { int value; fn add(int n) { this.value += n; return this.value; } int handle(int n) { return this.add(n); } } +fn main() { + actor.Actor<int, int>* a = rt.new(actor.Actor<int, int>), b = rt.new(actor.Actor<int, int>); + let state = 0, aresult = 0, bresult = 0; + a.spawn(fn(int n) { state += n; return state; }); + b.spawn(fn(int n) { state += n; return state; }); + a.recv(fn(int n) { aresult = n; return 0; }); b.recv(fn(int n) { bresult = n; return 0; }); + a.send(2); a.send(3); b.send(7); a.await(); b.await(); + rt.put_n(state); rt.put_c(' '); rt.put_n(aresult); rt.put_c(' '); rt.put_n(bresult); rt.put_c(10); + Counter c; c.value = 0; c.add(4); rt.put_n(c.value); rt.put_c(10); + a.close(); b.close(); return 0; +} diff --git a/tests/actor/accept/values.zc b/tests/actor/accept/values.zc new file mode 100644 index 0000000..2f6c103 --- /dev/null +++ b/tests/actor/accept/values.zc @@ -0,0 +1,12 @@ +namespace; +include rt, actor; +typecheck on; +struct Payload { i16 small; u32 large; float fraction; bstr text; } +float handle(Payload* p) { return p.small + p.large + p.fraction + rt.len_s(p.text); } +fn main() { + actor.Actor<Payload*,float>* a = rt.new(actor.Actor<Payload*,float>); + a.spawn(handle); let answer = 0; + a.recv(fn(float n) { answer = n == 6.5; return 0; }); + Payload p; p.small = -2; p.large = 4; p.fraction = 1.5; p.text = b"abc"; + a.send(&p); a.await(); rt.put_n(answer); rt.put_c(10); a.close(); return 0; +} diff --git a/tests/actor/regression/generic_extensions.zc b/tests/actor/regression/generic_extensions.zc new file mode 100644 index 0000000..4a4476d --- /dev/null +++ b/tests/actor/regression/generic_extensions.zc @@ -0,0 +1,8 @@ +namespace; +include rt, run; +run.syntax("record", run.kw_struct); +record Value { int amount; } +int calls; +fn tick() { calls++; return 0; } +run.statement_hook(tick); +fn main() { int value = 1; value++; rt.put_n(calls); rt.put_c(10); return 0; } diff --git a/tests/actor/regression/generic_typed_method.zc b/tests/actor/regression/generic_typed_method.zc new file mode 100644 index 0000000..2038ad3 --- /dev/null +++ b/tests/actor/regression/generic_typed_method.zc @@ -0,0 +1,5 @@ +namespace; +include rt; +typecheck on; +struct Box<T> { T value; T echo(T input) { this.value = input; return this.value; } } +fn main() { Box<int> a; Box<float> b; rt.put_n(a.echo(7)); rt.put_c(' '); int result = b.echo(2.5); rt.put_n(result); rt.put_c(10); return 0; } diff --git a/tests/actor/regression/module_helpers.zc b/tests/actor/regression/module_helpers.zc new file mode 100644 index 0000000..90f481f --- /dev/null +++ b/tests/actor/regression/module_helpers.zc @@ -0,0 +1,7 @@ +namespace helpers; +include rt; +int offset = 6; +T add<T>(T value) { return value + offset; } +namespace; +include rt, helpers; +fn main() { rt.put_n(helpers.add(4)); rt.put_c(10); return 0; } diff --git a/tests/actor/regression/plain.zc b/tests/actor/regression/plain.zc new file mode 100644 index 0000000..307d80c --- /dev/null +++ b/tests/actor/regression/plain.zc @@ -0,0 +1,4 @@ +namespace; +include rt; +struct Counter { int value; fn add(int n) { this.value += n; return this.value; } } +fn main() { Counter c; rt.put_n(c.add(3)); rt.put_c(10); return 0; } diff --git a/tests/actor/reject/explicit_this.zc b/tests/actor/reject/explicit_this.zc new file mode 100644 index 0000000..caa30d0 --- /dev/null +++ b/tests/actor/reject/explicit_this.zc @@ -0,0 +1,4 @@ +namespace; +include rt, actor; +actor Counter { int value; fn add(Counter* this, int n) { this.value += n; return this.value; } } +fn main() { Counter c; return c.add(1); } diff --git a/tests/actor/reject/generic_input.zc b/tests/actor/reject/generic_input.zc new file mode 100644 index 0000000..d13bc7c --- /dev/null +++ b/tests/actor/reject/generic_input.zc @@ -0,0 +1,5 @@ +namespace; +include rt, actor; +typecheck on; +actor Counter<T> { T handle(T value) { return value; } } +fn main() { Counter<int>* a = rt.new(Counter<int>); a.spawn(); a.send("wrong"); return 0; } diff --git a/tests/actor/reject/generic_method_return.zc b/tests/actor/reject/generic_method_return.zc new file mode 100644 index 0000000..4b2ba9b --- /dev/null +++ b/tests/actor/reject/generic_method_return.zc @@ -0,0 +1,5 @@ +namespace; +include rt; +typecheck on; +struct Box<T> { T wrong(T input) { return "wrong"; } } +fn main() { Box<int> a; a.wrong(7); return 0; } diff --git a/tests/actor/reject/input_type.zc b/tests/actor/reject/input_type.zc new file mode 100644 index 0000000..259f772 --- /dev/null +++ b/tests/actor/reject/input_type.zc @@ -0,0 +1,5 @@ +namespace; +include rt, actor; +typecheck on; +int handle(int n) { return n; } +fn main() { actor.Actor<int,int>* a = rt.new(actor.Actor<int,int>); a.spawn(handle); a.send("wrong"); a.close(); return 0; } diff --git a/tests/actor/reject/nested_missing_import.zc b/tests/actor/reject/nested_missing_import.zc new file mode 100644 index 0000000..bdf42bd --- /dev/null +++ b/tests/actor/reject/nested_missing_import.zc @@ -0,0 +1,3 @@ +namespace; +include run; +fn main() { run.evals("return rt.len_w(\"abc\");"); return 0; } diff --git a/tests/actor/reject/no_include.zc b/tests/actor/reject/no_include.zc new file mode 100644 index 0000000..662bb4f --- /dev/null +++ b/tests/actor/reject/no_include.zc @@ -0,0 +1,4 @@ +namespace; +include rt; +actor Counter { int value; } +fn main() { return 0; } diff --git a/tests/actor/reject/output_type.zc b/tests/actor/reject/output_type.zc new file mode 100644 index 0000000..1d0df34 --- /dev/null +++ b/tests/actor/reject/output_type.zc @@ -0,0 +1,5 @@ +namespace; +include rt, actor; +typecheck on; +int handle(int n) { return n; } +fn main() { actor.Actor<int,int>* a = rt.new(actor.Actor<int,int>); a.spawn(handle); a.recv(fn(char* n) { return 0; }); a.close(); return 0; } |
