aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorGravatar Moon Flower <moonflower@elhenney.local> 2026-10-12 08:46:23 +0330
committerGravatar Moon Flower <moonflower@elhenney.local> 2026-10-12 08:46:23 +0330
commitecc350ca5c2eb50be8309c5f14f8bf0d87db9a02 (patch)
tree70e0af76a1b13affff7c6cc8aac7b3e6ef960478 /examples
a
Diffstat (limited to 'examples')
-rw-r--r--examples/bf.zc48
-rw-r--r--examples/cli.zc12
-rw-r--r--examples/cli2.zc29
-rw-r--r--examples/dump.zc30
-rw-r--r--examples/echo.zc2
-rw-r--r--examples/fact.zc4
-rw-r--r--examples/hello.zc1
-rw-r--r--examples/lang.zc49
-rw-r--r--examples/learn/01-hello.out1
-rw-r--r--examples/learn/01-hello.zc4
-rw-r--r--examples/learn/02-loops.out1
-rw-r--r--examples/learn/02-loops.zc6
-rw-r--r--examples/learn/03-do-continue.out1
-rw-r--r--examples/learn/03-do-continue.zc6
-rw-r--r--examples/learn/04-enums.out1
-rw-r--r--examples/learn/04-enums.zc5
-rw-r--r--examples/learn/05-small-ints.out3
-rw-r--r--examples/learn/05-small-ints.zc9
-rw-r--r--examples/learn/06-floats.out1
-rw-r--r--examples/learn/06-floats.zc6
-rw-r--r--examples/learn/07-bytes.out1
-rw-r--r--examples/learn/07-bytes.zc7
-rw-r--r--examples/learn/08-byte-strings.out2
-rw-r--r--examples/learn/08-byte-strings.zc8
-rw-r--r--examples/learn/09-shared.out1
-rw-r--r--examples/learn/09-shared.zc8
-rw-r--r--examples/learn/10-owned.out1
-rw-r--r--examples/learn/10-owned.zc6
-rw-r--r--examples/learn/11-tags.out1
-rw-r--r--examples/learn/11-tags.zc6
-rw-r--r--examples/learn/12-aliases.out1
-rw-r--r--examples/learn/12-aliases.zc8
-rw-r--r--examples/learn/13-memdebug.out2
-rw-r--r--examples/learn/13-memdebug.zc10
-rw-r--r--examples/learn/14-include.out1
-rw-r--r--examples/learn/14-include.zc7
-rw-r--r--examples/learn/15-generics.out1
-rw-r--r--examples/learn/15-generics.zc9
-rw-r--r--examples/learn/16-tagged-enums.out2
-rw-r--r--examples/learn/16-tagged-enums.zc18
-rw-r--r--examples/learn/17-switch.out1
-rw-r--r--examples/learn/17-switch.zc6
-rw-r--r--examples/learn/18-o3.out2
-rw-r--r--examples/learn/18-o3.zc10
-rw-r--r--examples/learn/19-growable.out3
-rw-r--r--examples/learn/19-growable.zc13
-rw-r--r--examples/learn/20-text-num.out2
-rw-r--r--examples/learn/20-text-num.zc6
-rw-r--r--examples/learn/21-host.out1
-rw-r--r--examples/learn/21-host.zc5
-rw-r--r--examples/learn/22-raw-x86.out1
-rw-r--r--examples/learn/22-raw-x86.zc5
-rw-r--r--examples/learn/23-c-abi.out2
-rw-r--r--examples/learn/23-c-abi.zc12
-rw-r--r--examples/learn/24-backtick.out1
-rw-r--r--examples/learn/24-backtick.zc5
-rw-r--r--examples/learn/25-closures.out2
-rw-r--r--examples/learn/25-closures.zc8
-rw-r--r--examples/learn/26-closure-state.out3
-rw-r--r--examples/learn/26-closure-state.zc13
-rw-r--r--examples/life.zc35
-rw-r--r--examples/lists.zc32
-rw-r--r--examples/mandel.zc32
-rw-r--r--examples/opt_test.zc54
-rw-r--r--examples/primes.zc35
-rw-r--r--examples/quine.zc1
-rw-r--r--examples/repl.zc25
-rw-r--r--examples/selfpatch.zc16
-rw-r--r--examples/staged.zc33
-rw-r--r--examples/strings.zc8
-rw-r--r--examples/struct_closure_opt.zc47
-rw-r--r--examples/tree.zc26
-rw-r--r--examples/typed.zc51
-rw-r--r--examples/wiring.zc18
74 files changed, 833 insertions, 0 deletions
diff --git a/examples/bf.zc b/examples/bf.zc
new file mode 100644
index 0000000..5169b2b
--- /dev/null
+++ b/examples/bf.zc
@@ -0,0 +1,48 @@
+// a brainfuck compiler. it turns a brainfuck program into zc source, hands
+// that to the compiler that's sitting in memory, and runs the result, which on
+// arm64 means native code. runs of + - < > fold into one statement each.
+// give it a program after a backtick, or it runs the hello world below.
+let out[30000], n, depth;
+fn emit(s) { let i = 0; while (s[i]) { out[n] = s[i]; n++; i++; } return 0; }
+fn emitn(int v) { if (v >= 10) emitn(v / 10); out[n] = '0' + v % 10; n++; return 0; }
+// how many times does c repeat from s[i]
+int run(s, int i, int c) { int k = 0; while (s[i + k] == c) k++; return k; }
+
+fn translate(s) {
+ int i = 0, k;
+ n = 0; depth = 0;
+ emit("let t[30000], p = 0;\n");
+ while (s[i]) {
+ switch (s[i]) {
+ case '+', '-':
+ k = run(s, i, s[i]);
+ emit("t[p] = (t[p] "); emit(s[i] == '+' ? "+ " : "- "); emitn(k); emit(") & 255;\n");
+ i = i + k; continue;
+ case '>', '<':
+ k = run(s, i, s[i]);
+ emit("p "); emit(s[i] == '>' ? "+= " : "-= "); emitn(k); emit(";\n");
+ i = i + k; continue;
+ case '[': emit("while (t[p]) {\n"); depth++;
+ case ']': emit("}\n"); depth--;
+ case '.': emit("put_c(t[p]);\n");
+ case ',': emit("t[p] = eof() ? 0 : get_c() & 255;\n");
+ }
+ i++;
+ }
+ emit("return 0;\n");
+ out[n] = 0;
+ return depth;
+}
+let hello = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.";
+let prog[20000];
+fn main() {
+ let src = hello, k = 0, lines = 0, i = 0;
+ while (!eof() && k < 19999) { let c = get_c(); if (c != 10) { prog[k] = c; k++; } }
+ prog[k] = 0;
+ if (k) src = prog;
+ if (translate(src)) { put_s("unbalanced brackets\n"); return 1; }
+ while (out[i]) { if (out[i] == 10) lines++; i++; }
+ put_s("compiled to "); put_n(lines); put_s(" lines of zc, running it:\n");
+ evals(out);
+ return 0;
+}
diff --git a/examples/cli.zc b/examples/cli.zc
new file mode 100644
index 0000000..113a0da
--- /dev/null
+++ b/examples/cli.zc
@@ -0,0 +1,12 @@
+// print the length and first character of the file named by ZC_FILE
+include "src/lib/std.zc";
+fn main() {
+ let name[80], s, n;
+ n = Host.env("ZC_FILE", name, 80);
+ if (n < 0) { put_s("no file\n"); return 1; }
+ s = readfile(name);
+ if (!s) { put_s("can't read\n"); return 1; }
+ put_n(len_w(s)); put_c(' '); put_c(s[0]); put_c(10);
+ free(d*s);
+ return 0;
+}
diff --git a/examples/cli2.zc b/examples/cli2.zc
new file mode 100644
index 0000000..0c3de12
--- /dev/null
+++ b/examples/cli2.zc
@@ -0,0 +1,29 @@
+// the command line, the environment, and capturing what a program writes.
+// run it as: ./bin/zy examples/cli2.zc one two (the first is this file's path
+// when zy is given one, otherwise <eval>, exactly as argv[0] is in c)
+include "src/lib/std.zc";
+
+fn main() {
+ put_s("argv: ");
+ for (int i = 0; i < argc; i++) { put_s(argv[i]); if (i + 1 < argc) put_s(" "); }
+ put_c(10);
+
+ // envp holds NAME=value strings, so a program can walk all of them
+ let n = 0;
+ for (int i = 0; i < envc; i++) if (Text.starts(envp[i], "HOME=")) n = n + 1;
+ put_s("HOME is set: "); put_n(n > 0); put_c(10);
+
+ // the same name the old way, one lookup instead of a walk
+ let v[80];
+ put_n(Host.env("HOME", v, 80) > 0); put_c(10);
+
+ // capture what the program writes, instead of printing it. every put_c,
+ // put_s and put_n from here on lands in the buffer.
+ let buf = capture.start();
+ put_s("this goes into the buffer, not the terminal");
+ put_c(10);
+ buf.end(); // stops the capture and terminates the string
+ put_s("captured "); put_n(len_w(buf)); put_s(" characters: ");
+ put_s(buf);
+ return 0;
+} \ No newline at end of file
diff --git a/examples/dump.zc b/examples/dump.zc
new file mode 100644
index 0000000..df9a864
--- /dev/null
+++ b/examples/dump.zc
@@ -0,0 +1,30 @@
+// printing any struct with no printing code: the heap knows each object's
+// type, and reflection walks its fields
+struct person { char* name; int age; };
+struct item { char* name; int count; person* owner; };
+
+fn dump(p) {
+ let t = typeof_obj(p), i = 0;
+ if (!t) { put_s("?"); return 0; }
+ tprint(t); put_s(" { ");
+ while (i < tnfields(t)) {
+ let ft = tftype(t, i), v = p[tfoff(t, i)];
+ if (i) put_s(", ");
+ put_s(tfname(t, i)); put_s(": ");
+ if (tkind(ft) == TY_PTR && telem(ft) == typeof(char)) { put_c('"'); put_s(v); put_c('"'); }
+ else if (tkind(ft) == TY_PTR) { if (v) dump(v); else put_s("null"); }
+ else put_n(v);
+ i++;
+ }
+ put_s(" }");
+ return 0;
+}
+fn main() {
+ person* ana = new(person);
+ ana.name = "ana"; ana.age = 30;
+ item* lamp = new(item);
+ lamp.name = "lamp"; lamp.count = 3; lamp.owner = ana;
+ dump(lamp); put_c(10);
+ free(d*lamp);
+ return 0;
+}
diff --git a/examples/echo.zc b/examples/echo.zc
new file mode 100644
index 0000000..79eb877
--- /dev/null
+++ b/examples/echo.zc
@@ -0,0 +1,2 @@
+// everything after the backtick is left unread, for the program itself
+fn main() { while (!eof()) put_c(get_c()); return 0; }
diff --git a/examples/fact.zc b/examples/fact.zc
new file mode 100644
index 0000000..1790900
--- /dev/null
+++ b/examples/fact.zc
@@ -0,0 +1,4 @@
+fn fact(n) { if (n < 2) return 1; return n * fact(n - 1); }
+// prints in binary, like the old asm example
+fn bin(n) { if (n > 1) bin(n >> 1); put_c('0' + (n & 1)); return 0; }
+fn main() { bin(fact(10)); put_c(10); put_n(fact(10)); put_c(10); return 0; }
diff --git a/examples/hello.zc b/examples/hello.zc
new file mode 100644
index 0000000..c0a0a97
--- /dev/null
+++ b/examples/hello.zc
@@ -0,0 +1 @@
+fn main() { put_s("hello, world!\n"); return 0; }
diff --git a/examples/lang.zc b/examples/lang.zc
new file mode 100644
index 0000000..6e992b4
--- /dev/null
+++ b/examples/lang.zc
@@ -0,0 +1,49 @@
+// growing the language from inside a program, while it compiles
+
+// x |> f calls f(x). on a stack machine that's just "call": the value is
+// already on the stack, under f's address.
+immediate fn pipe_op() { next(); add_binop("|>", 1, "c"); return 0; }
+pipe_op
+
+// unless (c) stmt
+immediate fn unless() {
+ let a;
+ next(); expect(intern("(")); plainuse(expr()); rval(); expect(intern(")"));
+ emitseq(useq[0], ulen[0]); // not
+ a = hole(); op(O_JZ);
+ substmt();
+ setlit(a, here);
+ return 0;
+}
+// assert (c): the failure message carries the line it was written on
+fn assert_fail(int line) { put_s("assertion failed on line "); put_n(line); put_c(10); halt(); return 0; }
+immediate fn assert() {
+ let a, l = tline;
+ next(); expect(intern("(")); plainuse(expr()); rval(); expect(intern(")"));
+ emitseq(useq[0], ulen[0]); // not: the jump below skips the failure when it holds
+ a = hole(); op(O_JZ);
+ lit(l); callname(intern("assert_fail")); op(O_DROP);
+ setlit(a, here);
+ return 0;
+}
+// times N { body }: the body pasted N times, at compile time
+immediate fn times() {
+ let n, b, i = 0;
+ next(); n = tv; next();
+ b = grab();
+ while (i < n) { feed(qdup(b)); i++; }
+ free(d*b);
+ return 0;
+}
+
+fn double(x) { return x * 2; }
+fn inc(x) { return x + 1; }
+fn main() {
+ put_n(5 |> double |> inc |> double); put_c(10);
+ unless (1 > 2) put_s("one isn't bigger than two\n");
+ times 3 { put_c('*'); }
+ put_c(10);
+ assert(double(4) == 8);
+ assert(inc(1) == 3);
+ return 0;
+}
diff --git a/examples/learn/01-hello.out b/examples/learn/01-hello.out
new file mode 100644
index 0000000..270c611
--- /dev/null
+++ b/examples/learn/01-hello.out
@@ -0,0 +1 @@
+hello, world!
diff --git a/examples/learn/01-hello.zc b/examples/learn/01-hello.zc
new file mode 100644
index 0000000..10cf4bf
--- /dev/null
+++ b/examples/learn/01-hello.zc
@@ -0,0 +1,4 @@
+fn main() {
+ put_s("hello, world!\n");
+ return 0;
+}
diff --git a/examples/learn/02-loops.out b/examples/learn/02-loops.out
new file mode 100644
index 0000000..1e8b314
--- /dev/null
+++ b/examples/learn/02-loops.out
@@ -0,0 +1 @@
+6
diff --git a/examples/learn/02-loops.zc b/examples/learn/02-loops.zc
new file mode 100644
index 0000000..832e32f
--- /dev/null
+++ b/examples/learn/02-loops.zc
@@ -0,0 +1,6 @@
+fn main() {
+ let i = 0, n = 0;
+ while (i < 4) { n = n + i; i++; }
+ put_n(n); put_c(10);
+ return 0;
+}
diff --git a/examples/learn/03-do-continue.out b/examples/learn/03-do-continue.out
new file mode 100644
index 0000000..b1bd38b
--- /dev/null
+++ b/examples/learn/03-do-continue.out
@@ -0,0 +1 @@
+13
diff --git a/examples/learn/03-do-continue.zc b/examples/learn/03-do-continue.zc
new file mode 100644
index 0000000..70959f4
--- /dev/null
+++ b/examples/learn/03-do-continue.zc
@@ -0,0 +1,6 @@
+fn main() {
+ int n = 0, i = 0;
+ do { i++; if (i == 2) continue; n = n + i; } while (i < 5);
+ put_n(n); put_c(10);
+ return 0;
+}
diff --git a/examples/learn/04-enums.out b/examples/learn/04-enums.out
new file mode 100644
index 0000000..ead6e4a
--- /dev/null
+++ b/examples/learn/04-enums.out
@@ -0,0 +1 @@
+0 5 6
diff --git a/examples/learn/04-enums.zc b/examples/learn/04-enums.zc
new file mode 100644
index 0000000..8f80e3c
--- /dev/null
+++ b/examples/learn/04-enums.zc
@@ -0,0 +1,5 @@
+enum color { RED, GREEN = 5, BLUE };
+fn main() {
+ put_n(RED); put_c(32); put_n(GREEN); put_c(32); put_n(BLUE); put_c(10);
+ return 0;
+}
diff --git a/examples/learn/05-small-ints.out b/examples/learn/05-small-ints.out
new file mode 100644
index 0000000..2a9bc9e
--- /dev/null
+++ b/examples/learn/05-small-ints.out
@@ -0,0 +1,3 @@
+4
+13
+44
diff --git a/examples/learn/05-small-ints.zc b/examples/learn/05-small-ints.zc
new file mode 100644
index 0000000..b288181
--- /dev/null
+++ b/examples/learn/05-small-ints.zc
@@ -0,0 +1,9 @@
+fn main() {
+ u8 a = 250; a = a + 10;
+ put_n(a); put_c(10);
+ put_n(sizeof([100]u8)); put_c(10);
+ u8* px = new(u8, 4096);
+ px[10] = 300;
+ put_n(px[10]); put_c(10);
+ return 0;
+}
diff --git a/examples/learn/06-floats.out b/examples/learn/06-floats.out
new file mode 100644
index 0000000..9406425
--- /dev/null
+++ b/examples/learn/06-floats.out
@@ -0,0 +1 @@
+4.000000
diff --git a/examples/learn/06-floats.zc b/examples/learn/06-floats.zc
new file mode 100644
index 0000000..06d23fa
--- /dev/null
+++ b/examples/learn/06-floats.zc
@@ -0,0 +1,6 @@
+fn put_f(x) { asm { x @ #1220 } return 0; }
+fn main() {
+ let a = 1.5;
+ put_f(a + 2.5); put_c(10);
+ return 0;
+}
diff --git a/examples/learn/07-bytes.out b/examples/learn/07-bytes.out
new file mode 100644
index 0000000..209c2ea
--- /dev/null
+++ b/examples/learn/07-bytes.out
@@ -0,0 +1 @@
+17 8721
diff --git a/examples/learn/07-bytes.zc b/examples/learn/07-bytes.zc
new file mode 100644
index 0000000..7d06282
--- /dev/null
+++ b/examples/learn/07-bytes.zc
@@ -0,0 +1,7 @@
+fn main() {
+ let w = 0;
+ st8(addr_b(&w), 0x11);
+ st8(addr_b(&w) + 1, 0x22);
+ put_n(ld8(addr_b(&w))); put_c(32); put_n(w); put_c(10);
+ return 0;
+}
diff --git a/examples/learn/08-byte-strings.out b/examples/learn/08-byte-strings.out
new file mode 100644
index 0000000..1e10779
--- /dev/null
+++ b/examples/learn/08-byte-strings.out
@@ -0,0 +1,2 @@
+hello, zc
+9 42
diff --git a/examples/learn/08-byte-strings.zc b/examples/learn/08-byte-strings.zc
new file mode 100644
index 0000000..0959ceb
--- /dev/null
+++ b/examples/learn/08-byte-strings.zc
@@ -0,0 +1,8 @@
+fn main() {
+ let name = b"zc";
+ let hi = b"hello, " + name;
+ put_s(hi); put_c(10);
+ put_n(len(hi)); put_c(32);
+ put_n(s_to_n(b"40") + 2); put_c(10);
+ return 0;
+}
diff --git a/examples/learn/09-shared.out b/examples/learn/09-shared.out
new file mode 100644
index 0000000..2fb73a0
--- /dev/null
+++ b/examples/learn/09-shared.out
@@ -0,0 +1 @@
+1 1
diff --git a/examples/learn/09-shared.zc b/examples/learn/09-shared.zc
new file mode 100644
index 0000000..ab3ca06
--- /dev/null
+++ b/examples/learn/09-shared.zc
@@ -0,0 +1,8 @@
+fn main() {
+ let tail = cons(1, 2);
+ let left = cons(tail, 3);
+ let right = cons(tail, 4);
+ put_n(car(car(left))); put_c(32);
+ put_n(car(left) == car(right)); put_c(10);
+ return 0;
+}
diff --git a/examples/learn/10-owned.out b/examples/learn/10-owned.out
new file mode 100644
index 0000000..7f8f011
--- /dev/null
+++ b/examples/learn/10-owned.out
@@ -0,0 +1 @@
+7
diff --git a/examples/learn/10-owned.zc b/examples/learn/10-owned.zc
new file mode 100644
index 0000000..3aff9a4
--- /dev/null
+++ b/examples/learn/10-owned.zc
@@ -0,0 +1,6 @@
+fn main() {
+ int* p = new(int);
+ *p = 7;
+ put_n(*p); put_c(10);
+ return 0;
+}
diff --git a/examples/learn/11-tags.out b/examples/learn/11-tags.out
new file mode 100644
index 0000000..b8626c4
--- /dev/null
+++ b/examples/learn/11-tags.out
@@ -0,0 +1 @@
+4
diff --git a/examples/learn/11-tags.zc b/examples/learn/11-tags.zc
new file mode 100644
index 0000000..08edb58
--- /dev/null
+++ b/examples/learn/11-tags.zc
@@ -0,0 +1,6 @@
+int*.u box(int v) { int* b = new(int); *b = v; return u*b; }
+fn main() {
+ int* p = box(4);
+ put_n(*p); put_c(10);
+ return 0;
+}
diff --git a/examples/learn/12-aliases.out b/examples/learn/12-aliases.out
new file mode 100644
index 0000000..b8626c4
--- /dev/null
+++ b/examples/learn/12-aliases.out
@@ -0,0 +1 @@
+4
diff --git a/examples/learn/12-aliases.zc b/examples/learn/12-aliases.zc
new file mode 100644
index 0000000..abb39d5
--- /dev/null
+++ b/examples/learn/12-aliases.zc
@@ -0,0 +1,8 @@
+struct node { int v; node* next; };
+fn main() {
+ node* a = new(node), b = new(node);
+ a.v = 3; b.v = 4; a.next = b;
+ node* c = a.next;
+ put_n(c.v); put_c(10);
+ return 0;
+}
diff --git a/examples/learn/13-memdebug.out b/examples/learn/13-memdebug.out
new file mode 100644
index 0000000..c168a7b
--- /dev/null
+++ b/examples/learn/13-memdebug.out
@@ -0,0 +1,2 @@
+leak: line 4 3 words
+1
diff --git a/examples/learn/13-memdebug.zc b/examples/learn/13-memdebug.zc
new file mode 100644
index 0000000..80ee0da
--- /dev/null
+++ b/examples/learn/13-memdebug.zc
@@ -0,0 +1,10 @@
+memdebug on;
+int* g;
+fn main() {
+ int* p = new(int);
+ *p = 1;
+ g = d*p;
+ put_n(memreport());
+ put_c(10);
+ return 0;
+}
diff --git a/examples/learn/14-include.out b/examples/learn/14-include.out
new file mode 100644
index 0000000..1e8b314
--- /dev/null
+++ b/examples/learn/14-include.out
@@ -0,0 +1 @@
+6
diff --git a/examples/learn/14-include.zc b/examples/learn/14-include.zc
new file mode 100644
index 0000000..c126389
--- /dev/null
+++ b/examples/learn/14-include.zc
@@ -0,0 +1,7 @@
+include "src/lib/std.zc";
+fn main() {
+ let s = readfile("tests/data/hi.txt");
+ put_n(len_w(s)); put_c(10);
+ free(d*s);
+ return 0;
+}
diff --git a/examples/learn/15-generics.out b/examples/learn/15-generics.out
new file mode 100644
index 0000000..ec63514
--- /dev/null
+++ b/examples/learn/15-generics.out
@@ -0,0 +1 @@
+9
diff --git a/examples/learn/15-generics.zc b/examples/learn/15-generics.zc
new file mode 100644
index 0000000..dfc4833
--- /dev/null
+++ b/examples/learn/15-generics.zc
@@ -0,0 +1,9 @@
+struct record<K, V> { K key; V val; };
+struct point { int x; int y; };
+K keyof<K, V>(record<K, V>* r) { return r.key; }
+fn main() {
+ record<int, point>* r = new(record<int, point>);
+ r.key = 9;
+ put_n(keyof(r)); put_c(10);
+ return 0;
+}
diff --git a/examples/learn/16-tagged-enums.out b/examples/learn/16-tagged-enums.out
new file mode 100644
index 0000000..0b2b75d
--- /dev/null
+++ b/examples/learn/16-tagged-enums.out
@@ -0,0 +1,2 @@
+27
+10
diff --git a/examples/learn/16-tagged-enums.zc b/examples/learn/16-tagged-enums.zc
new file mode 100644
index 0000000..ba430f4
--- /dev/null
+++ b/examples/learn/16-tagged-enums.zc
@@ -0,0 +1,18 @@
+enum shape { circle { int r; }, rect { int w; int h; }, dot };
+int area(shape* s) {
+ switch (s) {
+ case circle(r): return r * r * 3;
+ case rect(w, h): return w * h;
+ case dot: return 0;
+ }
+ return -1;
+}
+fn main() {
+ shape* s = shape.circle(3);
+ put_n(area(s)); put_c(10);
+ free(d*s);
+ shape* t = shape.rect(2, 5);
+ put_n(area(t)); put_c(10);
+ free(d*t);
+ return 0;
+}
diff --git a/examples/learn/17-switch.out b/examples/learn/17-switch.out
new file mode 100644
index 0000000..f719efd
--- /dev/null
+++ b/examples/learn/17-switch.out
@@ -0,0 +1 @@
+two
diff --git a/examples/learn/17-switch.zc b/examples/learn/17-switch.zc
new file mode 100644
index 0000000..f03aba9
--- /dev/null
+++ b/examples/learn/17-switch.zc
@@ -0,0 +1,6 @@
+fn main() {
+ int k = 2;
+ switch (k) { case 1: put_s("one"); break; case 2: put_s("two"); break; default: put_s("other"); }
+ put_c(10);
+ return 0;
+}
diff --git a/examples/learn/18-o3.out b/examples/learn/18-o3.out
new file mode 100644
index 0000000..11c5ab3
--- /dev/null
+++ b/examples/learn/18-o3.out
@@ -0,0 +1,2 @@
+30
+143
diff --git a/examples/learn/18-o3.zc b/examples/learn/18-o3.zc
new file mode 100644
index 0000000..cb2237a
--- /dev/null
+++ b/examples/learn/18-o3.zc
@@ -0,0 +1,10 @@
+o3 int sum(fixed []int a) { int s = 0; for (int i = 0; i < len(a); i++) s += a[i]; return s; }
+fn main() {
+ fixed []int a = new(fixed []int, 5);
+ for (int i = 0; i < 5; i++) a[i] = i * i;
+ put_n(sum(a)); put_c(10);
+ o3 int hits = 0;
+ o3 { for (int i = 0; i < 1000; i++) if (i % 7 == 3) hits++; }
+ put_n(hits); put_c(10);
+ return 0;
+}
diff --git a/examples/learn/19-growable.out b/examples/learn/19-growable.out
new file mode 100644
index 0000000..4a9aeea
--- /dev/null
+++ b/examples/learn/19-growable.out
@@ -0,0 +1,3 @@
+2
+5
+3
diff --git a/examples/learn/19-growable.zc b/examples/learn/19-growable.zc
new file mode 100644
index 0000000..e5ed8de
--- /dev/null
+++ b/examples/learn/19-growable.zc
@@ -0,0 +1,13 @@
+struct cnt {
+ int n;
+ static int make() { return 3; }
+ int get() { return this.n; }
+};
+fn main() {
+ []int xs = new([]int);
+ push(xs, 4); push(xs, 5);
+ put_n(len(xs)); put_c(10);
+ put_n(pop(xs)); put_c(10);
+ put_n(cnt.make()); put_c(10);
+ return 0;
+}
diff --git a/examples/learn/20-text-num.out b/examples/learn/20-text-num.out
new file mode 100644
index 0000000..7b3cce8
--- /dev/null
+++ b/examples/learn/20-text-num.out
@@ -0,0 +1,2 @@
+6 1024 7
+124
diff --git a/examples/learn/20-text-num.zc b/examples/learn/20-text-num.zc
new file mode 100644
index 0000000..027b721
--- /dev/null
+++ b/examples/learn/20-text-num.zc
@@ -0,0 +1,6 @@
+include "src/lib/std.zc";
+fn main() {
+ put_n(Num.gcd(12, 18)); put_c(32); put_n(Num.pow(2, 10)); put_c(32); put_n(Num.isqrt(50)); put_c(10);
+ put_n(Text.atoi("123") + 1); put_c(10);
+ return 0;
+}
diff --git a/examples/learn/21-host.out b/examples/learn/21-host.out
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/examples/learn/21-host.out
@@ -0,0 +1 @@
+1
diff --git a/examples/learn/21-host.zc b/examples/learn/21-host.zc
new file mode 100644
index 0000000..550e747
--- /dev/null
+++ b/examples/learn/21-host.zc
@@ -0,0 +1,5 @@
+include "src/lib/std.zc";
+fn main() {
+ put_n(Host.now() > 0); put_c(10);
+ return 0;
+}
diff --git a/examples/learn/22-raw-x86.out b/examples/learn/22-raw-x86.out
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/examples/learn/22-raw-x86.out
@@ -0,0 +1 @@
+1
diff --git a/examples/learn/22-raw-x86.zc b/examples/learn/22-raw-x86.zc
new file mode 100644
index 0000000..e274aee
--- /dev/null
+++ b/examples/learn/22-raw-x86.zc
@@ -0,0 +1,5 @@
+include "src/lib/std.zc";
+fn main() {
+ put_n(Host.raw(39, 0, 0, 0, 0, 0, 0) > 0); put_c(10);
+ return 0;
+}
diff --git a/examples/learn/23-c-abi.out b/examples/learn/23-c-abi.out
new file mode 100644
index 0000000..0701ad5
--- /dev/null
+++ b/examples/learn/23-c-abi.out
@@ -0,0 +1,2 @@
+1.414214
+1 3 5 9
diff --git a/examples/learn/23-c-abi.zc b/examples/learn/23-c-abi.zc
new file mode 100644
index 0000000..3df4b75
--- /dev/null
+++ b/examples/learn/23-c-abi.zc
@@ -0,0 +1,12 @@
+fn put_f(x) { asm { x @ #1220 } return 0; }
+extern double sqrt(double);
+extern void qsort(word *base, long n, long size, void *cmp);
+int cmp(int* a, int* b) { return *a - *b; }
+fn main() {
+ let a[4];
+ a[0] = 5; a[1] = 3; a[2] = 9; a[3] = 1;
+ put_f(sqrt(2.0)); put_c(10);
+ qsort(a, 4, 8, cfunc(cmp));
+ put_n(a[0]); put_c(32); put_n(a[1]); put_c(32); put_n(a[2]); put_c(32); put_n(a[3]); put_c(10);
+ return 0;
+}
diff --git a/examples/learn/24-backtick.out b/examples/learn/24-backtick.out
new file mode 100644
index 0000000..81bf396
--- /dev/null
+++ b/examples/learn/24-backtick.out
@@ -0,0 +1 @@
+ab
diff --git a/examples/learn/24-backtick.zc b/examples/learn/24-backtick.zc
new file mode 100644
index 0000000..0317631
--- /dev/null
+++ b/examples/learn/24-backtick.zc
@@ -0,0 +1,5 @@
+fn main() {
+ put_c(get_c()); put_c(get_c()); put_c(10);
+ return 0;
+}
+`abc
diff --git a/examples/learn/25-closures.out b/examples/learn/25-closures.out
new file mode 100644
index 0000000..b04b592
--- /dev/null
+++ b/examples/learn/25-closures.out
@@ -0,0 +1,2 @@
+11
+15
diff --git a/examples/learn/25-closures.zc b/examples/learn/25-closures.zc
new file mode 100644
index 0000000..72c236d
--- /dev/null
+++ b/examples/learn/25-closures.zc
@@ -0,0 +1,8 @@
+fn apply(f, x) { return f(x); }
+fn main() {
+ let k = 10;
+ let add = fn(x) { return x + k; };
+ put_n(add(1)); put_c(10);
+ put_n(apply(add, 5)); put_c(10);
+ return 0;
+}
diff --git a/examples/learn/26-closure-state.out b/examples/learn/26-closure-state.out
new file mode 100644
index 0000000..33aea5d
--- /dev/null
+++ b/examples/learn/26-closure-state.out
@@ -0,0 +1,3 @@
+109
+1 5
+0
diff --git a/examples/learn/26-closure-state.zc b/examples/learn/26-closure-state.zc
new file mode 100644
index 0000000..f3ddf50
--- /dev/null
+++ b/examples/learn/26-closure-state.zc
@@ -0,0 +1,13 @@
+fn main() {
+ let base = 2;
+ let outer = fn(x) {
+ let inner = fn(y) { return y + base + x; };
+ return inner(100);
+ };
+ put_n(outer(7)); put_c(10);
+ let count = 0;
+ let tick = fn(d) { count = count + d; return count; };
+ put_n(tick(1)); put_c(32); put_n(tick(4)); put_c(10);
+ put_n(count); put_c(10);
+ return 0;
+}
diff --git a/examples/life.zc b/examples/life.zc
new file mode 100644
index 0000000..6ac34e0
--- /dev/null
+++ b/examples/life.zc
@@ -0,0 +1,35 @@
+// conway's life on a 10 x 20 torus, with typed 2d arrays in a struct.
+// a glider walks diagonally and wraps around the edges.
+const H = 10, W = 20;
+struct board { [10][20]int c; };
+
+int get(board* b, int y, int x) { return b.c[(y + H) % H][(x + W) % W]; }
+fn step(board* from, board* to) {
+ for (int y = 0; y < H; y++)
+ for (int x = 0; x < W; x++) {
+ int n = 0;
+ for (int dy = 0 - 1; dy <= 1; dy++)
+ for (int dx = 0 - 1; dx <= 1; dx++)
+ if (dy || dx) n += get(from, y + dy, x + dx);
+ to.c[y][x] = n == 3 || (n == 2 && from.c[y][x]);
+ }
+ return 0;
+}
+fn show(board* b, int gen) {
+ put_s("generation "); put_n(gen); put_c(10);
+ for (int y = 0; y < H; y++) { for (int x = 0; x < W; x++) put_c(b.c[y][x] ? '#' : '.'); put_c(10); }
+ return 0;
+}
+fn main() {
+ board* a = new(board), b = new(board);
+ a.c[0][1] = 1; a.c[1][2] = 1; a.c[2][0] = 1; a.c[2][1] = 1; a.c[2][2] = 1;
+ // two generations a pass, a -> b -> a: owned boards can't be swapped
+ // through a temporary, since the analyzer can't follow that
+ for (int g = 0; g <= 40; g += 2) {
+ if (g % 20 == 0) show(a, g);
+ step(a, b);
+ step(b, a);
+ }
+ free(d*a); free(d*b);
+ return 0;
+}
diff --git a/examples/lists.zc b/examples/lists.zc
new file mode 100644
index 0000000..02059f3
--- /dev/null
+++ b/examples/lists.zc
@@ -0,0 +1,32 @@
+// ownership in practice: a list owns its boxes. nothing here calls free;
+// everything is released at the end of the block that owns it.
+.u box(v) { let b = new(1); b[0] = v; return u*b; }
+.u mklist(cap) { let l = new(cap + 1); l[0] = 0; return u*l; }
+// item m*arrives (it was given down), and goes d*on into the borrowed list
+fn push(.m l, .d item) { l[l[0] + 1] = d*item; l[0] = l[0] + 1; return 0; }
+fn show(.m l) {
+ let i = 1;
+ put_c('[');
+ while (i <= l[0]) { if (i > 1) put_c(' '); put_n(l[i][0]); i++; }
+ put_c(']');
+ return 0;
+}
+.u squares(n) {
+ let l = mklist(n), i = 0;
+ while (i < n) {
+ let b = box(i * i);
+ push(l, d*b);
+ i++;
+ }
+ return u*l;
+}
+fn main() {
+ let before = live_objects();
+ {
+ let l = squares(6);
+ show(l); put_c(10);
+ put_s("live: "); put_n(live_objects() - before); put_c(10);
+ }
+ put_s("after the block: "); put_n(live_objects() - before); put_c(10);
+ return 0;
+}
diff --git a/examples/mandel.zc b/examples/mandel.zc
new file mode 100644
index 0000000..0a8f69e
--- /dev/null
+++ b/examples/mandel.zc
@@ -0,0 +1,32 @@
+// the mandelbrot set in 16.16 fixed point. a word is 64 bits, so the product
+// fits and the point sits 16 bits down. the jit inlines it as a multiply and a shift.
+enhance fmul(a, b) micro "a = mul a b; a = sar a 16";
+
+const ONE = 65536, W = 72, H = 28, MAXIT = 40;
+let shades = " .,:;-=+*%#@";
+
+int escape(int cx, int cy) {
+ int x = 0, y = 0, i = 0;
+ while (i < MAXIT) {
+ int xx = fmul(x, x), yy = fmul(y, y);
+ if (xx + yy > 4 * ONE) return i;
+ y = 2 * fmul(x, y) + cy;
+ x = xx - yy + cx;
+ i++;
+ }
+ return MAXIT;
+}
+fn main() {
+ int row = 0;
+ while (row < H) {
+ int col = 0, cy = (row * 2400 / (H - 1) - 1200) * ONE / 1000;
+ while (col < W) {
+ int cx = (col * 3200 / (W - 1) - 2200) * ONE / 1000, it = escape(cx, cy);
+ put_c(it == MAXIT ? '@' : shades[it * 11 / MAXIT]);
+ col++;
+ }
+ put_c(10);
+ row++;
+ }
+ return 0;
+}
diff --git a/examples/opt_test.zc b/examples/opt_test.zc
new file mode 100644
index 0000000..c581283
--- /dev/null
+++ b/examples/opt_test.zc
@@ -0,0 +1,54 @@
+// a tour of the compiler's optimization hints. the program is valid and runs;
+// the hints only show up in the editor (or the lsp cli), never in a normal build.
+// each function below triggers one of them.
+
+fn sink(.d p) { free(d*p); return 0; }
+
+// a variable that is written and never read
+fn dead() {
+ let unused = 5;
+ return 1;
+}
+
+// never reassigned, so it could be a const
+fn constant() {
+ let width = 40;
+ return width + 2;
+}
+
+// multiplying by a power of two is a shift
+fn shifty(n) { return n * 8; }
+
+// a number with no name
+fn magic(n) { return n + 1234; }
+
+// new inside a loop allocates every pass
+fn looping() {
+ let i = 0;
+ while (i < 3) {
+ let buf = new(10);
+ buf[0] = i;
+ sink(d*buf);
+ i++;
+ }
+ return i;
+}
+
+// a small buffer that never leaves the function can live on the stack
+fn scratch() {
+ let buf = new(8);
+ buf[0] = 7;
+ return buf[0];
+}
+
+// a consuming call takes the object after its allocation
+fn handoff() {
+ let tmp = new(4);
+ sink(d*tmp);
+ return 0;
+}
+
+fn main() {
+ put_n(dead() + constant() + shifty(2) + magic(0) + looping() + scratch() + handoff()); put_c(10);
+ return 0;
+}
diff --git a/examples/primes.zc b/examples/primes.zc
new file mode 100644
index 0000000..43ae2e8
--- /dev/null
+++ b/examples/primes.zc
@@ -0,0 +1,35 @@
+// primes below 60000: an o3 sieve over a fixed array, the primes
+// gathered into a growable one, then a few questions asked of them.
+// with ZYTRACE=1 the o3 lines show each region being lifted and compiled.
+
+// marks the composites; f[i] ends up 1 for every prime i
+o3 int sieve(fixed []int f) {
+ int n = len(f), c = 0;
+ for (int i = 2; i < n; i++) f[i] = 1;
+ for (int i = 2; i * i < n; i++)
+ if (f[i]) for (int j = i * i; j < n; j += i) f[j] = 0;
+ for (int i = 2; i < n; i++) c += f[i];
+ return c;
+}
+// the largest gap between neighbours, and where it starts
+o3 int gap(fixed []int f, int* at) {
+ int n = len(f), last = 2, best = 0, where = 0;
+ for (int i = 3; i < n; i++)
+ if (f[i]) { if (i - last > best) { best = i - last; where = last; } last = i; }
+ *at = where;
+ return best;
+}
+fn main() {
+ fixed []int f = new(fixed []int, 60000);
+ []int ps = new([]int);
+ int c = sieve(f), at = 0, twins = 0;
+ for (int i = 2; i < len(f); i++) if (f[i]) push(ps, i);
+ o3 { for (int k = 1; k < len(ps); k++) if (ps[k] - ps[k - 1] == 2) twins++; }
+ put_s("primes below 60000: "); put_n(c); put_c(10);
+ put_s("the last five:"); for (int k = len(ps) - 5; k < len(ps); k++) { put_c(' '); put_n(ps[k]); } put_c(10);
+ put_s("twin pairs: "); put_n(twins); put_c(10);
+ int g = gap(f, &at);
+ put_s("widest gap: "); put_n(g); put_s(", after "); put_n(at); put_c(10);
+ free(d*f); free(d*ps);
+ return 0;
+}
diff --git a/examples/quine.zc b/examples/quine.zc
new file mode 100644
index 0000000..9c69e69
--- /dev/null
+++ b/examples/quine.zc
@@ -0,0 +1 @@
+let s="let s=#;fn main(){let i=0;while(s[i]){if(s[i]==35){put_c(34);put_s(s);put_c(34);}else put_c(s[i]);i++;}put_c(10);return 0;}";fn main(){let i=0;while(s[i]){if(s[i]==35){put_c(34);put_s(s);put_c(34);}else put_c(s[i]);i++;}put_c(10);return 0;}
diff --git a/examples/repl.zc b/examples/repl.zc
new file mode 100644
index 0000000..235063f
--- /dev/null
+++ b/examples/repl.zc
@@ -0,0 +1,25 @@
+// a repl on the resident compiler: each backtick-separated chunk of input is
+// compiled as a function body and run. definitions (fn ...) can be loaded too:
+// a chunk that starts with "fn" goes through load instead of eval.
+let buf[4000];
+fn readchunk() {
+ let n = 0, c;
+ while (!eof()) {
+ c = get_c();
+ if (c == 96) break;
+ if (n < 3999) { buf[n] = c; n++; }
+ }
+ buf[n] = 0;
+ return n;
+}
+fn main() {
+ let q, i;
+ while (!eof()) {
+ readchunk();
+ q = tokens(buf);
+ if (q[0] && q[1] == T_ID && q[2] == intern("fn")) load(q);
+ else eval(q);
+ free(d*q);
+ }
+ return 0;
+}
diff --git a/examples/selfpatch.zc b/examples/selfpatch.zc
new file mode 100644
index 0000000..e3f821d
--- /dev/null
+++ b/examples/selfpatch.zc
@@ -0,0 +1,16 @@
+// code is data: find the literal 'A' inside f's compiled words and rewrite it.
+// on the jit the store lands on translated code, which gets dropped and
+// retranslated on the next call.
+fn f() { put_c('A'); return 0; }
+fn litw(v) { return v + v + 1; } // how the vm encodes a literal push
+fn main() {
+ let p = f;
+ f();
+ while (*p != litw('A')) p++;
+ *p = litw('B');
+ f();
+ *p = litw('C');
+ f();
+ put_c(10);
+ return 0;
+}
diff --git a/examples/staged.zc b/examples/staged.zc
new file mode 100644
index 0000000..a180ae3
--- /dev/null
+++ b/examples/staged.zc
@@ -0,0 +1,33 @@
+// staged code: a program writes a specialized function as source, compiles it
+// while running, and calls it. here, polynomials with their coefficients baked
+// in as constants, so there's no loop and no array left at runtime.
+let buf[2000], n;
+fn put(s) { let i = 0; while (s[i]) { buf[n] = s[i]; n++; i++; } return 0; }
+fn putnum(int v) { if (v >= 10) putnum(v / 10); buf[n] = '0' + v % 10; n++; return 0; }
+
+// coefficients c[0] + c[1] x + ... in horner form: ((c3 x + c2) x + c1) x + c0
+fn specialize(int* c, int deg) {
+ n = 0;
+ put("fn poly(x) { return ");
+ for (int i = 0; i < deg; i++) put("(");
+ if (c[deg] < 0) { put("0 - "); putnum(0 - c[deg]); } else putnum(c[deg]);
+ for (int i = deg - 1; i >= 0; i--) {
+ put(") * x ");
+ if (c[i] < 0) { put("- "); putnum(0 - c[i]); } else { put("+ "); putnum(c[i]); }
+ }
+ put("; }");
+ buf[n] = 0;
+ return buf;
+}
+fn main() {
+ [4]int c;
+ c[0] = 7; c[1] = 0 - 3; c[2] = 0; c[3] = 2; // 2x^3 - 3x + 7
+ let src = specialize(c, 3), q = tokens(src);
+ put_s(src); put_c(10);
+ load(q); // compiled now, into the running program
+ free(d*q);
+ let f = sval[lookups("poly")]; // and found by name in the compiler's symbol table
+ for (int x = 0 - 2; x <= 3; x++) { put_n(f(x)); put_c(' '); }
+ put_c(10);
+ return 0;
+}
diff --git a/examples/strings.zc b/examples/strings.zc
new file mode 100644
index 0000000..0959ceb
--- /dev/null
+++ b/examples/strings.zc
@@ -0,0 +1,8 @@
+fn main() {
+ let name = b"zc";
+ let hi = b"hello, " + name;
+ put_s(hi); put_c(10);
+ put_n(len(hi)); put_c(32);
+ put_n(s_to_n(b"40") + 2); put_c(10);
+ return 0;
+}
diff --git a/examples/struct_closure_opt.zc b/examples/struct_closure_opt.zc
new file mode 100644
index 0000000..67315bf
--- /dev/null
+++ b/examples/struct_closure_opt.zc
@@ -0,0 +1,47 @@
+// struct methods, closures and ownership in one file, written so the
+// compiler's hints have something to say about it. it runs as it is.
+
+struct point {
+ let x, y;
+
+ // methods get a hidden first parameter called this
+ fn dist(other) {
+ let dx = this.x - other.x;
+ let dy = this.y - other.y;
+ return dx * dx + dy * dy;
+ }
+}
+
+fn sink(.d p) { free(d*p); return 0; }
+
+fn features() {
+ // a closure copies the variables it uses when it is made
+ let base = 100;
+ let add = fn(a, b) { return a + b + base; };
+ let total = add(10, 20);
+
+ let p1 = new(point);
+ p1.x = 5; p1.y = 12;
+ let p2 = new(point);
+ p2.x = 0; p2.y = 0;
+
+ // made and given away on the next line, so it never needed a name
+ let tmp = new(2);
+ sink(d*tmp);
+
+ // allocated again on every pass of the loop
+ let i = 0;
+ while (i < 3) {
+ let scratch = new(10);
+ scratch[0] = i;
+ sink(d*scratch);
+ i++;
+ }
+
+ return total + p1.dist(p2);
+}
+
+fn main() {
+ put_n(features()); put_c(10);
+ return 0;
+}
diff --git a/examples/tree.zc b/examples/tree.zc
new file mode 100644
index 0000000..9ef515e
--- /dev/null
+++ b/examples/tree.zc
@@ -0,0 +1,26 @@
+// a binary search tree where every node owns its children. there's no free
+// anywhere: when the root's block ends, the whole tree goes with it.
+struct node { int v; node* left, right; };
+
+node*.u leaf(int v) { node* n = new(node); n.v = v; return u*n; }
+// n is borrowed; storing a new leaf into it makes n the leaf's owner
+fn insert(node*.m n, int v) {
+ if (v < n.v) { if (n.left) insert(n.left, v); else n.left = leaf(v); }
+ else { if (n.right) insert(n.right, v); else n.right = leaf(v); }
+ return 0;
+}
+fn walk(node* n) { if (!n) return 0; walk(n.left); put_n(n.v); put_c(' '); walk(n.right); return 0; }
+int height(node* n) { if (!n) return 0; int l = height(n.left), r = height(n.right); return 1 + (l > r ? l : r); }
+
+fn main() {
+ let before = live_objects();
+ {
+ node* root = leaf(50);
+ int x = 7;
+ for (int i = 0; i < 30; i++) { x = (x * 37 + 11) % 100; insert(root, x); }
+ walk(root); put_c(10);
+ put_s("height "); put_n(height(root)); put_s(", live objects "); put_n(live_objects() - before); put_c(10);
+ }
+ put_s("after the block: "); put_n(live_objects() - before); put_c(10);
+ return 0;
+}
diff --git a/examples/typed.zc b/examples/typed.zc
new file mode 100644
index 0000000..44aff88
--- /dev/null
+++ b/examples/typed.zc
@@ -0,0 +1,51 @@
+// types: structs, a generic container, and looking at it all through reflection.
+// a pointer type put_s its star after the type, like c: int*, point*, vec<T>*.
+typecheck on;
+struct point { int x, y; };
+struct vec<T> { int len, cap; T* items; };
+
+vec<T>*.u mkvec<T>(int cap) {
+ vec<T>* v = new(vec<T>);
+ v.cap = cap;
+ v.items = new(T, cap);
+ return u*v;
+}
+
+// x is given away (.d): the vector's memory holds it from now on, and the
+// collector looks after it
+bool push<T>(vec<T>* v, T.d x) {
+ if (v.len == v.cap) { free(d*x); return 0; }
+ v.items[v.len] = d*x;
+ v.len++;
+ return 1;
+}
+
+fn show(word t) {
+ let i = 0;
+ tprint(t); put_s(" is "); put_n(tsize(t)); put_s(" words: ");
+ while (i < tnfields(t)) {
+ if (i) put_s(", ");
+ put_s(tfname(t, i)); put_s(" "); tprint(tftype(t, i));
+ i++;
+ }
+ put_c(10);
+ return 0;
+}
+
+int main() {
+ vec<point*>* v = mkvec<point*>(4);
+ int i = 0;
+ while (i < 3) {
+ point* p = new(point);
+ p.x = i; p.y = i * i;
+ push(v, d*p);
+ i++;
+ }
+ put_s("last: "); put_n(v.items[2].y); put_c(10);
+ show(typeof(point));
+ show(typeof(*v));
+ put_s("push is "); tprint(sigof(push)); put_c(10);
+ // each set of type arguments gets its own copy of mkvec, so what it stamped is vec<point*>
+ put_s("the heap says v is a "); tprint(typeof_obj(v)); put_s(", and v.items[0] is a "); tprint(typeof_obj(v.items[0])); put_c(10);
+ return 0;
+}
diff --git a/examples/wiring.zc b/examples/wiring.zc
new file mode 100644
index 0000000..d10ecf5
--- /dev/null
+++ b/examples/wiring.zc
@@ -0,0 +1,18 @@
+// virtual enhancements: custom opcodes wired into the cpu while compiling.
+// the recipes run through the core's optimizer; the jit inlines the result.
+enhance popcount(x) micro
+ "r1 = shr x 1; r1 = and r1 0x5555555555555555; x = sub x r1"
+ "; r1 = shr x 2; r1 = and r1 0x3333333333333333; x = and x 0x3333333333333333; x = add x r1"
+ "; r1 = shr x 4; x = add x r1; x = and x 0x0f0f0f0f0f0f0f0f; x = mul x 0x0101010101010101; x = shr x 56";
+enhance div10(x) micro "x = udiv x 10"; // becomes a multiply-high, no divide
+enhance hypot2(a, b) vm { 0 $ * ~ 0 $ * + }; // lifted from vm code
+enhance 2 minmax(a, b) micro "r2 = min a b; r1 = max a b; r0 = r2";
+let lo, hi;
+fn main() {
+ put_n(popcount(0xff00ff)); put_c(' ');
+ put_n(div10(12345)); put_c(' ');
+ put_n(hypot2(3, 4)); put_c(' ');
+ asm { 9 4 minmax hi ! lo ! }
+ put_n(lo); put_c('/'); put_n(hi); put_c(10);
+ return 0;
+} \ No newline at end of file