aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar zinc <zinc@downsta.ir> 2026-10-14 10:42:28 +0000
committerGravatar zinc <zinc@downsta.ir> 2026-10-14 10:42:28 +0000
commitea052eab91b304459ddf64281fc93fc152597412 (patch)
tree8dcd378d6634626dd2529c2aef684890999de963 /src
parenttodo: the spec verifier restarted from the first agent's partial work (diff)
parentfix std hover, full capture terminator, bare static calls, void main in run-o... (diff)
Merge four small fixes: std hovers, capture terminator, bare static calls, void main; todo updated
Diffstat (limited to 'src')
-rw-r--r--src/compiler/expr.zc4
-rw-r--r--src/compiler/types.zc6
-rw-r--r--src/lib/std.zc5
-rw-r--r--src/lsp/server.zc40
-rw-r--r--src/runtime/run.zc5
5 files changed, 47 insertions, 13 deletions
diff --git a/src/compiler/expr.zc b/src/compiler/expr.zc
index c6d29c6..40de6ef 100644
--- a/src/compiler/expr.zc
+++ b/src/compiler/expr.zc
@@ -1014,7 +1014,9 @@ int primary() {
return C_PLAIN;
}
s = source_lookup(n);
- if (mstruct && !ginst) { ms = lookup(methname(mstruct, n)); if (ms >= 0 && skind[ms] == K_CONST) s = ms; }
+ // in a method of a struct a bare name is that struct's own constant or static function first, so it
+ // wins over a global (a top-level function or constant) of the same name
+ if (mstruct && !ginst) { ms = lookup(methname(mstruct, n)); if (ms >= 0 && (skind[ms] == K_CONST || (skind[ms] == K_FN && (sflag[ms] & F_STATIC)))) s = ms; }
if (s < 0 && rt.eq_w(n, "new")) s = source_lookup(s_new);
if (s >= 0) rs_put(toff, RS_SYM, rs_sym(s), s);
if (s >= 0 && skind[s] == K_KW) {
diff --git a/src/compiler/types.zc b/src/compiler/types.zc
index c643f0b..6dda110 100644
--- a/src/compiler/types.zc
+++ b/src/compiler/types.zc
@@ -497,8 +497,9 @@ int dtype() {
}
return 0;
}
-// the struct whose body or methods are being compiled, when it declares constants: a bare
-// name there is looked up as Struct.name before the global scope
+// the struct whose body or methods are being compiled: a bare name there is looked up as Struct.name
+// (a constant, or a static function called by its bare name) before the global scope, so the struct's
+// own wins over a global of the same name
char* mstruct;
// does a constant declaration start in a struct body? const NAME = e; const T NAME = e;
// (a field of a const type has no initializer, so the = tells them apart)
@@ -652,6 +653,7 @@ int kw_struct() {
}
accept(s_semi);
i = 0;
+ if (!gen) mstruct = n;
while (i < nm) { fn_method_compile = 1; methdef(n, mn[i], mq[i], mst[i], mty[i], mrt[i], mrg[i]); fn_method_compile = 0; i++; }
mdg = 0;
mstruct = msv;
diff --git a/src/lib/std.zc b/src/lib/std.zc
index 33ab1e9..772b887 100644
--- a/src/lib/std.zc
+++ b/src/lib/std.zc
@@ -73,7 +73,8 @@ int libinit() {
// rt.put_s("hello world!"); // nothing on the terminal
// std.capture.end(buf);
// rt.put_s(buf); // hello world!
-// the buffer holds 256 characters, and output past that is dropped.
+// the buffer holds 256 characters, and output past that is dropped. it has one
+// more word for the 0 that end() writes, so a full capture is still a string.
// one capture at a time, and the buffer belongs to whoever holds it.
struct capture {
// starts a capture: output goes into a new buffer instead of the terminal.
@@ -81,7 +82,7 @@ struct capture {
static char* start() {
int cap = 256;
rt.outmode = 2; rt.outn = 0; rt.outcap = cap;
- rt.outbuf = rt.new(cap);
+ rt.outbuf = rt.new(cap + 1);
return rt.outbuf;
}
// stops the capture and ends the buffer with a 0.
diff --git a/src/lsp/server.zc b/src/lsp/server.zc
index afa8de4..a43f910 100644
--- a/src/lsp/server.zc
+++ b/src/lsp/server.zc
@@ -1761,6 +1761,12 @@ int hover_method(int i) {
if (!found) ls = le + 1;
}
if (!found) return 0;
+ return hover_method_at(i, sg);
+}
+// the markdown of the method whose signature starts at byte sg of document i: the
+// signature up to the body, a ; or the end of the line, then the docs above it
+int hover_method_at(int i, int sg) {
+ int base = doff[i], size = dsize[i], k, se;
// the signature: up to the body, a ; or the end of the line
se = sg;
while (se < size && dc(base, se) != 10 && dc(base, se) != '{' && dc(base, se) != ';') se++;
@@ -1919,17 +1925,24 @@ int hover_global(int i, int kind) {
r = rs_find(hoff);
if (r >= 0 && run.rsrec[r * run.RS_W + 1] == run.RS_SYM && run.rsrec[r * run.RS_W + 3] >= 0 && kind != 2) {
s = run.rsrec[r * run.RS_W + 3];
- if (run.skind[s] != run.K_KW && bs_find(run.sname[s])) { hover_fill(bs_load(bs_k)); return hn; }
+ if (run.skind[s] != run.K_KW && bs_find(run.sname[s])) { bs_hover(); return hn; }
}
if (kind != 2) { kt = kwtext(); if (kt) return kw_put(kt); }
- if (kind == 1) { if (bs_find(hname)) { hover_fill(bs_load(bs_k)); return hn; } hover_blob(i); return hn; }
+ if (kind == 1) { if (bs_find(hname)) { bs_hover(); return hn; } hover_blob(i); return hn; }
if (hover_scan(i)) { hover_fill(i); return hn; }
if (hover_method(i)) return hn;
if (kind == 0 && hover_local(i)) return hn;
- if (kind != 2 && bs_find(hname)) { hover_fill(bs_load(bs_k)); return hn; }
+ if (kind != 2 && bs_find(hname)) { bs_hover(); return hn; }
hover_blob(i);
return hn;
}
+// is symbol s declared in an embedded library source (the text of std or icon, included
+// from tinyvm:std.zc and tinyvm:icon.zc)? such a symbol is a user symbol to the compiler
+// (rs_sym sets 16 for it) but its text is not in the document, so hover looks it up by
+// its qualified name in the library source, as it does for the runtime.
+int hover_embedded_sym(int s) {
+ return s >= 0 && run.sdsrc && run.sdsrc[s] && bs_name(run.sdsrc[s]) && bs_source(run.sdsrc[s]) >= 0;
+}
// the hover at the cursor. the compiler's record of the name decides what it
// is: a local is its declaration, a parameter the header that names it, and a
// symbol is looked up as that kind of symbol. a name with no record is found by
@@ -1950,7 +1963,9 @@ int do_hover(int i) {
else if (k == run.RS_FIELD && v >= 0) hover_named(i, v, 4);
else if (k == run.RS_LOCAL) hover_local(i);
else if (k == run.RS_SYM) {
- if ((v & 15) == run.K_GVAR || (v & 15) == run.K_GARR) {
+ // a symbol from an embedded library source (std, icon) is above the user's symbols but is not in the document: its declaration is found in that source by its qualified name
+ if ((v & 16) && hover_embedded_sym(run.rsrec[r * run.RS_W + 3])) hover_global(i, 1);
+ else if ((v & 15) == run.K_GVAR || (v & 15) == run.K_GARR) {
s = run.rsrec[r * run.RS_W + 3]; q = 0; o = 0 - 1;
while (q < run.rsn) { if (run.rsrec[q * run.RS_W + 3] == s && lt_find(run.rsrec[q * run.RS_W]) >= 0) { o = run.rsrec[q * run.RS_W]; break; } q++; }
if (o >= 0) hover_named(i, o, 3); else if (v & 16) hover_global(i, 2); else hover_global(i, 1);
@@ -2261,16 +2276,29 @@ int bs_method(int dd, char* name, int dot) {
}
return 0 - 1;
}
+// did the last bs_find_in hit find a method of a struct (bs_off is its name), not a top-level declaration
+int bs_meth;
+// the hover of the declaration the last successful bs_find found: a method by its line, anything else
+// by the scan that found it
+int bs_hover() {
+ int dd = bs_load(bs_k), q;
+ if (!bs_meth) return hover_fill(dd);
+ q = bs_off;
+ while (q > 0 && dc(doff[dd], q - 1) != 10) q--;
+ while (q < bs_off && (dc(doff[dd], q) == 32 || dc(doff[dd], q) == 9)) q++;
+ hn = 0; hover_method_at(dd, q);
+ return hn;
+}
// locate a declaration inside one source, after removing its module prefix.
int bs_find_in(int k, char* name) {
int n = 0, dot = -1, o, dd = bs_load(k);
while (name[n]) { if (name[n] == '.' && dot < 0) dot = n; n++; }
if (dot > 0 && name[dot + 1]) {
o = bs_method(dd, name, dot);
- if (o >= 0) { bs_k = k; bs_off = o; return 1; }
+ if (o >= 0) { bs_k = k; bs_off = o; bs_meth = 1; return 1; }
} else if (dot < 0) {
set_hname(name);
- if (hover_scan(dd)) { bs_k = k; bs_off = decl_off(doff[dd], hdl, hdle); return 1; }
+ if (hover_scan(dd)) { bs_k = k; bs_off = decl_off(doff[dd], hdl, hdle); bs_meth = 0; return 1; }
}
return 0;
}
diff --git a/src/runtime/run.zc b/src/runtime/run.zc
index a8f82e2..19a5234 100644
--- a/src/runtime/run.zc
+++ b/src/runtime/run.zc
@@ -8,9 +8,10 @@ include rt;
//
// cat build/run/rt.zc src/runtime/run.zc examples/hello.zc | ./zc0 >build/run/genome.h
-// the program's entry point, written by the program (see start).
+// the program's entry point, written by the program (see start). the prototype is untyped so
+// that main may be declared int, void or untyped, as in any other program: its value is ignored.
namespace;
-int main();
+fn main();
namespace run;
include rt;