aboutsummaryrefslogtreecommitdiff
path: root/src/tools/zc0.c
diff options
context:
space:
mode:
authorGravatar Moon Flower <moonflower@elhenney.local> 2026-10-14 08:29:46 +0330
committerGravatar Moon Flower <moonflower@elhenney.local> 2026-10-14 08:29:46 +0330
commit1c53304d03414890af0da7432d1aea87e754a14a (patch)
tree97190d86cf548c9bc63f68c86a4d2a4f09809713 /src/tools/zc0.c
parenta (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 'src/tools/zc0.c')
-rw-r--r--src/tools/zc0.c103
1 files changed, 86 insertions, 17 deletions
diff --git a/src/tools/zc0.c b/src/tools/zc0.c
index 5ef5737..446557b 100644
--- a/src/tools/zc0.c
+++ b/src/tools/zc0.c
@@ -27,6 +27,7 @@ enum { O_Q, O_LD, O_ST, O_PICK, O_DROP, O_SWAP, O_CALL, O_JMP, O_JZ, O_RET,
O_IN, O_EMPTY, O_OUT, O_ADD, O_SUB, O_MUL, O_AND, O_OR, O_XOR, O_SHR, O_LT };
static const char *mn = "q@!$_~cjzr,?.+-*&|^><%";
+static char module_name[64];
static char *src; static int pos, line = 1, tstart, hdr_start;
/* the signature of the function being defined: its header's source text, for the language server (ZC0DOCS) */
static char sgtext[400], sgname[80];
@@ -78,6 +79,7 @@ static void doccomment(void) /* pos is on the first slash */
while (k >= 0 && (src[k] == ' ' || src[k] == '\t')) k--;
bol = k < 0 || src[k] == '\n';
pos += 2;
+ if (src[pos] == ':') { dn = 0; dlast = cl; docpending = 0; while (src[pos] && src[pos] != '\n') pos++; return; }
if (!bol) { while (src[pos] && src[pos] != '\n') pos++; return; }
if (dn && dlast != cl - 1) dn = 0;
if (src[pos] == ' ') pos++;
@@ -176,6 +178,11 @@ static void next(void)
while (src[pos] && src[pos] != '"' && i < 4095) ts[i++] = (char)esc();
ts[i] = 0; if (src[pos] == '"') pos++; tk = T_BSTR; return;
}
+ if (src[pos] == '.' && (!strcmp(ts,"rt") || !strcmp(ts,"run") || !strcmp(ts,"core") || !strcmp(ts,"lsp") || !strcmp(ts,"std") || !strcmp(ts,"icon"))) {
+ ts[i++] = src[pos++];
+ while (isalnum((unsigned char)src[pos]) || src[pos] == '_') ts[i++] = src[pos++];
+ ts[i] = 0;
+ }
tk = T_ID; return;
}
if (src[pos] == '\'') { pos++; tv = esc(); if (src[pos++] != '\'') die("bad char literal"); tk = T_NUM; strcpy(ts, "'c'"); return; }
@@ -198,10 +205,24 @@ typedef struct { char name[64]; int kind, sig, defd; int64_t val; } Sym;
static Sym sy[16384]; static int nsy;
typedef struct { int at, sym; } Fix;
static Fix fx[65536]; static int nfx;
-static Sym *find(const char *n) { int i; for (i = nsy; i--;) if (!strcmp(sy[i].name, n)) return &sy[i]; return 0; }
+static Sym *find_raw(const char *n) { int i; for (i = nsy; i--;) if (!strcmp(sy[i].name, n)) return &sy[i]; return 0; }
+static void qualify(char *dst, size_t size, const char *name) {
+ if (!module_name[0] || strchr(name, '.')) snprintf(dst, size, "%s", name);
+ else if (!strncmp(name, "doc ", 4) || !strncmp(name, "sig ", 4)) snprintf(dst, size, "%.4s%s.%s", name, module_name, name + 4);
+ else snprintf(dst, size, "%s.%s", module_name, name);
+}
+static Sym *find(const char *name) {
+ char full[256]; Sym *s;
+ qualify(full, sizeof full, name); s = find_raw(full); if (s) return s;
+ s = find_raw(name); if (s || strchr(name, '.')) return s;
+ const char *modules[] = { "rt", "run", "core", "lsp", 0 };
+ for (int i = 0; modules[i]; i++) { snprintf(full,sizeof full,"%s.%s",modules[i],name); s=find_raw(full); if(s) return s; }
+ return 0;
+}
static Sym *add(const char *n, int kind, int64_t val)
{
- Sym *s = find(n);
+ char full[256]; qualify(full, sizeof full, n); n = full;
+ Sym *s = find_raw(n);
if (s && s->kind == K_FN && kind == K_FN && !s->defd) { s->val = val; return s; } /* prototype or forward use */
s = &sy[nsy++]; strncpy(s->name, n, 63); s->kind = kind; s->val = val; s->defd = 1; s->sig = 0; return s;
}
@@ -318,11 +339,11 @@ static int64_t cexpr(void)
/* ---- types ----
zc0 has no types: a type is read and thrown away. all it has to know is the
- shape, so that [n]T still reserves n words and the rest reserve one. the
+ shape, so that T[n] still reserves n words and the rest reserve one. the
grammar is the compiler's own (see ptype in compiler.zc):
ptype a type, then any number of (params): int(int, int) is a function type
ptype0 a type with its stars: int*, vec<T>*, point**
- ptype1 a base: [n]T, []T, fixed []T, fn, a name, or a generic instance
+ ptype1 a base: T[n], T[?], fixed T[?], fn, a name, or a generic instance
each returns the words a variable of the type takes: n for a fixed array, 1
for a growable handle or anything scalar. */
static int ptype0(void);
@@ -330,12 +351,7 @@ static int ptype(void);
static int ptype1(void)
{
int n, e;
- if (accept("[")) {
- if (accept("]")) { ptype0(); return 1; } /* []T is a handle */
- n = (int)cexpr(); expect("]");
- e = ptype0();
- return n > 0 ? n * e : e;
- }
+ if (is("[")) { die("array types are postfix: T[N], T[] or T[?]"); return 1; }
if (is("fixed")) { next(); return ptype0(); }
if (is("fn")) { next(); return 1; } /* fn(int): the parameters follow, in ptype */
if (tk != T_ID) { die("a type name"); return 1; }
@@ -350,14 +366,30 @@ static int ptype1(void)
static int ptype0(void)
{
int n = ptype1();
- while (accept("*")) n = 1;
+ while (is("*") || is("[")) {
+ if (accept("*")) n = 1;
+ else {
+ int count = 0, cap = 8, *dims = malloc(cap * sizeof(int));
+ if (!dims) die("cannot allocate array dimensions");
+ while (accept("[")) {
+ int length;
+ if (accept("?")) { expect("]"); length = -2; }
+ else if (accept("]")) length = -1;
+ else { length = (int)cexpr(); expect("]"); }
+ if (count == cap) { cap *= 2; int *more = realloc(dims, cap * sizeof(int)); if (!more) die("cannot grow array dimensions"); dims = more; }
+ dims[count++] = length;
+ }
+ while (count) { int length = dims[--count]; if (length == -2) n = 1; else n = length < 0 ? 0 : n * length; }
+ free(dims);
+ }
+ }
return n;
}
static int ptype(void)
{
int n = ptype0();
while (accept("(")) {
- if (!accept(")")) { do { ptype(); } while (accept(",")); expect(")"); }
+ if (!accept(")")) { do { ptype(); if (accept(".")) ident(); } while (accept(",")); expect(")"); }
n = 1;
}
return n;
@@ -435,6 +467,7 @@ static void bstrlit(void)
}
static int returns_bstr(const char *n)
{
+ if (!strncmp(n, "rt.", 3)) n += 3;
return !strcmp(n, "cat_s") || !strcmp(n, "slice_s") || !strcmp(n, "n_to_s") || !strcmp(n, "new_s");
}
static int args(void) { int n = 0; expect("("); if (!accept(")")) { do { expr(); rval(); n++; } while (accept(",")); expect(")"); } return n; }
@@ -457,6 +490,13 @@ static void primary(void)
if (s && s->kind == K_GARR) { lit(s->val); return; }
if (is("(")) {
int na = args();
+ if (s && s->kind == K_ENH) {
+ if (na != (s->sig & 15)) die("wrong number of enhancement inputs");
+ op(22 + (int)s->val);
+ if (((s->sig >> 4) & 15) == 0) lit(0);
+ else if (((s->sig >> 4) & 15) != 1) die("multiple enhancement outputs need asm");
+ xs = 0; xf = 0; return;
+ }
if (!strcmp(n, "put_s") && na == 1 && xs) fnref("put_bs");
else if (!strcmp(n, "len")) fnref("len_s");
else fnref(n);
@@ -671,7 +711,7 @@ static void fndef(int ret)
char *n = ident(); Sym *s; int np = 0, tags = 0, t, frame, i, helper, busy, done, check, node;
if (dsn && !dnm[0]) strcpy(dnm, n);
char pn[16][64];
- s = find(n);
+ char full_name[256]; qualify(full_name, sizeof full_name, n); s = find_raw(full_name);
if (!s || s->kind != K_FN) { s = add(n, K_FN, 0); s->defd = 0; }
expect("(");
if (!accept(")")) {
@@ -705,7 +745,7 @@ static void fndef(int ret)
nlo = 0; nslot = 0; nepi = 0; infn = 1;
for (i = 0; i < np; i++) { strcpy(lo[nlo].name, pn[i]); lo[nlo].arr = 0; lo[nlo].flt = 0; lo[nlo].str = 0; lo[nlo++].slot = nslot++; }
/* retain the caller's pointer until the frame has its final segment. */
- helper = !find("frame_busy") || !strcmp(s->name, "frame_grow") || !strcmp(s->name, "frame_leave");
+ helper = !find("frame_busy") || !strcmp(s->name, "rt.frame_grow") || !strcmp(s->name, "rt.frame_leave");
lit(ZFP); op(O_LD); if (!helper) { lit(0); op(O_PICK); }
frame = here; lit(0); op(O_SUB); lit(ZFP); op(O_ST);
if (!helper) {
@@ -756,6 +796,12 @@ static void enhdef(void)
}
static void top1(void)
{
+ if (accept("namespace")) {
+ if (is(";")) module_name[0] = 0;
+ else { snprintf(module_name, sizeof module_name, "%s", ident()); }
+ expect(";"); return;
+ }
+ if (accept("include")) { do { ident(); } while (accept(",")); expect(";"); return; }
{
if (accept("unchecked")) { top1(); return; }
if (accept("fn")) { fndef(0); return; }
@@ -790,6 +836,21 @@ static void top1(void)
}
}
+/* section headings organize the source; they do not document a symbol. */
+static int doc_section(const char *text, int length)
+{
+ int start = 0, end, a, b;
+ while (start < length) {
+ end = start; while (end < length && text[end] != '\n') end++;
+ a = start; b = end;
+ while (a < b && isspace((unsigned char)text[a])) a++;
+ while (b > a && isspace((unsigned char)text[b - 1])) b--;
+ if (b - a >= 4 && text[a] == '-' && text[a + 1] == '-' && text[b - 1] == '-' && text[b - 2] == '-') return 1;
+ start = end + 1;
+ }
+ return 0;
+}
+
/* one item, with the doc comment above it kept under the name it declares */
static void top(void)
{
@@ -801,7 +862,7 @@ static void top(void)
if (dn && dline == line) { memcpy(dsnap, dbuf, dn); dsn = dn; dline = 0; }
top1();
#ifdef ZC0DOCS /* enabled for images that carry editor documentation */
- if (dsn && dnm[0]) {
+ if (dsn && dnm[0] && !doc_section(dsnap, dsn)) {
int j = here, a, i = 0, k, c; uint64_t w; char nm[80];
lit(0); op(O_JMP); a = here;
emit(dsn);
@@ -834,8 +895,16 @@ static void top(void)
}
}
-int main(void)
+int main(int argc, char **argv)
{
+ if (argc == 2 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))) {
+ fputs("usage: zc0 [--help|-h] < source.zc > genome.h\n"
+ "compiles bootstrap source from stdin into a c genome header on stdout.\n"
+ "source must define start(); memory layout is selected when zc0 is built.\n"
+ "options:\n --help, -h show this help and exit\n", stdout);
+ return 0;
+ }
+ if (argc != 1) { fputs("zc0: unexpected arguments; use --help for usage\n", stderr); return 2; }
#ifdef _WIN32
_setmode(_fileno(stdin), _O_BINARY);
_setmode(_fileno(stdout), _O_BINARY);
@@ -856,7 +925,7 @@ int main(void)
}
buf[n] = 0; src = buf; next();
/* image header: set the frame pointer, jump to start, then the symbol blob pointer and image end */
- lit(FTOP); lit(ZFP); op(O_ST); fnref("start"); op(O_JMP); emit(0); emit(0);
+ lit(FTOP); lit(ZFP); op(O_ST); fnref(strstr(src, "namespace run;") ? "run.start" : "start"); op(O_JMP); emit(0); emit(0);
top();
for (i = 0; i < nfx; i++) {
Sym *s = &sy[fx[i].sym];