aboutsummaryrefslogtreecommitdiff
path: root/README.md
diff options
context:
space:
mode:
authorGravatar zinc <zinc@downsta.ir> 2026-10-14 08:30:01 +0000
committerGravatar zinc <zinc@downsta.ir> 2026-10-14 08:30:01 +0000
commitd274751e89f75cc0f0e25c6e5e87ef91b64597ee (patch)
treeef76f2cfe9d2a09f3fe5d27278cf775649bc162f /README.md
parentlsp: quick fixes for hints and bare library names; comment cleanup (diff)
zc: untyped local const, c precedence for && and ||, import fixes for every module
const name = value; inside a function declares a local constant that takes the initializer's type. the let quick fix now writes a bare const. the self-hosted compiler bound || tighter than &&, unlike zc0 and the readme. no existing source mixed them without parentheses, so only new code was affected. missing-name diagnostics and their quick fixes now search every module: rt, core, run, loaded files, and std, icon and actor scanned from source, including static groups (std.Text.itoa). typos suggest module exports (putc -> rt.put_c) and get a change-to fix.
Diffstat (limited to 'README.md')
-rw-r--r--README.md4
1 files changed, 2 insertions, 2 deletions
diff --git a/README.md b/README.md
index 2a7a073..235fedb 100644
--- a/README.md
+++ b/README.md
@@ -97,7 +97,7 @@ check mode records errors instead of printing them and continues after an error,
- **diagnostics** on open, change and save, with an id echoed on every reply, `MethodNotFound` for unknown requests and `-32002` before `initialize`.
- **definition and references** (`textDocument/definition`, `textDocument/references`): a local, parameter or field goes to its declaration by the offset the compiler recorded, and a function, global, constant, struct or type goes to where the compiler saw it defined, in an included file too (the file is found from the document's directory upward, then as written in the `include`). references lists the uses in the document, with the declaration when asked. built-in names navigate to their embedded source when one is available.
- **module completions**: after an imported namespace and a dot, completion lists that module's exported members with signatures and documentation; it does not add unrelated local or module names. module hovers and completions cover `rt`, `run`, `core`, `lsp`, `std` and `icon`.
-- **import quick fixes**: compiler diagnostics for missing imports or unqualified exports offer a workspace edit. the edit adds the needed `include` without duplicating an existing import, qualifies bare exports, and preserves namespace declarations, comments, and crlf line endings. the editor client applies only edits for the current document version, while keeping protocol version epochs separate from editor document versions.
+- **import quick fixes**: compiler diagnostics for missing imports or unqualified exports offer a workspace edit. a bare name is looked up in every module: the runtime and compiler modules, loaded files, and the libraries under `src/lib` read from source even when they are not included, including static groups (`itoa` becomes `std.Text.itoa` with `include std;`). a misspelled name gets the closest defined name or module export (`putc` becomes `rt.put_c`). the edit adds the needed `include` without duplicating an existing import, qualifies bare exports, and preserves namespace declarations, comments, and crlf line endings. the editor client applies only edits for the current document version, while keeping protocol version epochs separate from editor document versions.
- **semantic tokens** (`textDocument/semanticTokens/full`) in 12 types: keyword, type, function, variable, string, number, operator, comment, parameter, property, macro, enumMember. token kinds come from the compiler's symbol tables and declarations. check mode records each resolved name and source location, following the compiler's lookup order: locals and parameters precede globals, and built-ins are checked last. a local named `cap` is a variable wherever it is in scope, and the built-in `cap` only applies to uses outside that scope.
- **formatting** (`textDocument/formatting`, and `zclsp --format < file.zc` on the command line): a pretty-printer in the spirit of clang-format with `ColumnLimit: 0`. it keeps the author's line breaks and sets the indent of every line (from braces, open parentheses and unfinished statements; `case` labels are indented one level inside their `switch` by default), the spaces after commas and around `=`, `==`, `&&` and the like, the blank lines between lines, and the final line break. it never moves a token to another line, and it leaves strings, comments, `asm` and `vm` blocks and everything after a backtick as written, so the tokens of a program are the same before and after. options come from a `.zcformat` file in the document's directory or the nearest directory above it, one `Key: value` per line (`#` starts a comment), then from the editor's tab size and `insertSpaces`, then from the defaults: `UseTab: true`, `IndentWidth: 4` (the spaces of a level when `UseTab` is false), `MaxEmptyLines: 1`, `ContinuationIndent: 1`, `NormalizeSpacing: true`, `CaseIndent: 1`, `FinalNewline: true`. `CaseIndent: 0` aligns each `case` label with its `switch`. `tests/drivers/format_test.js` formats every `.zc` file in the repository and checks that the tokens are unchanged and that formatting twice gives the same text.
- **streaming and cancelling**: a check of a document with 100 or more top-level items sends the diagnostics found so far each time the item count doubles, so errors near the top appear before a large file is done. before each of those points the server queries the host (`core.syscall(42)`) for pending input. if input is waiting, the check is dropped without publishing because newer text may replace the current document. the check publishes once no newer input is waiting. smaller documents are checked in one go.
@@ -167,7 +167,7 @@ fn main() {
}
```
-declarations are C-style, type first: `int a = 1, b;`, `node* p = rt.new(node);`, `char[4] buf;`, `point origin;`. `let` declares without a type: it infers `char*` from a word-string literal and `bstr` from a packed byte-string literal, infers other pointers and function types from the initializer, uses a pointer alias for an in-place array or struct, and keeps numbers as plain words. `let a[10];` is an untyped array. statements are declarations, `if`/`else`, `while`, `do`/`while`, `for`, `switch`, `break`, `continue`, `return`, `{ }` blocks, `asm { }` and expressions. `do` body `while (` cond `);` runs the body once before the test, and `continue` jumps to the test. `enum color { RED, GREEN = 5, BLUE };` makes global constants, and `color` is a type of its own in typed code (`typecheck on;`): a member takes the enum, a plain int does not become a `color`, and a `color` still becomes an `int`. untyped code treats the members as plain ints. each member is also reached as `color.BLUE`, in an expression or a `case` label. a member can carry fields too: `enum shape { circle { int r; }, rect { int w; int h; }, dot };` makes the constructors `shape.circle(3)` and `shape.rect(4, 5)`, which return an owned `shape*`, and `shape.dot()`. the tag is the word at offset 0 of the object. a `switch` over a `shape*` matches a member with `case circle(r):`, which binds its fields in that arm only. a switch on a tagged enum that leaves out a member and has no `default` gets a warning on its line (not an error). `(T)e` is a cast with the same meaning as `e as T`: the bits stay, the type changes. it has to be a simple type the parser can see in a few tokens, `int` or `*node`, not a nested array. `include "path";` reads a file and compiles it at that point, signatures first, so a library can live in its own file. each file has its own namespace and imports; dependencies included by a file do not import into the caller. `u`, `m` and `d` are ordinary names. a tag is `.u`, `.m` or `.d`, and `u*x` with no space before the star is still a recast. `switch (e) { case 1, 2: ... default: ... }` takes constant labels, and its cases don't fall through: each ends where the next begins, and `break` leaves early. operators follow C precedence, including `c ? a : b`, plus `p.x` and `p->x` (the same thing: `.` goes through a pointer on its own), `e as T` to change a type without changing the bits, and the casts below. comparisons and `&& ||` give 0 or 1. `/`, `%` and `<<` compile to native enhancement opcodes. character literals, `0x` hex and the usual escapes are there.
+declarations are C-style, type first: `int a = 1, b;`, `node* p = rt.new(node);`, `char[4] buf;`, `point origin;`. `let` declares without a type: it infers `char*` from a word-string literal and `bstr` from a packed byte-string literal, infers other pointers and function types from the initializer, uses a pointer alias for an in-place array or struct, and keeps numbers as plain words. `let a[10];` is an untyped array. `const k = 5;` inside a function is a local constant with no type: it takes the initializer's type, needs an initializer, and can't be assigned. statements are declarations, `if`/`else`, `while`, `do`/`while`, `for`, `switch`, `break`, `continue`, `return`, `{ }` blocks, `asm { }` and expressions. `do` body `while (` cond `);` runs the body once before the test, and `continue` jumps to the test. `enum color { RED, GREEN = 5, BLUE };` makes global constants, and `color` is a type of its own in typed code (`typecheck on;`): a member takes the enum, a plain int does not become a `color`, and a `color` still becomes an `int`. untyped code treats the members as plain ints. each member is also reached as `color.BLUE`, in an expression or a `case` label. a member can carry fields too: `enum shape { circle { int r; }, rect { int w; int h; }, dot };` makes the constructors `shape.circle(3)` and `shape.rect(4, 5)`, which return an owned `shape*`, and `shape.dot()`. the tag is the word at offset 0 of the object. a `switch` over a `shape*` matches a member with `case circle(r):`, which binds its fields in that arm only. a switch on a tagged enum that leaves out a member and has no `default` gets a warning on its line (not an error). `(T)e` is a cast with the same meaning as `e as T`: the bits stay, the type changes. it has to be a simple type the parser can see in a few tokens, `int` or `*node`, not a nested array. `include "path";` reads a file and compiles it at that point, signatures first, so a library can live in its own file. each file has its own namespace and imports; dependencies included by a file do not import into the caller. `u`, `m` and `d` are ordinary names. a tag is `.u`, `.m` or `.d`, and `u*x` with no space before the star is still a recast. `switch (e) { case 1, 2: ... default: ... }` takes constant labels, and its cases don't fall through: each ends where the next begins, and `break` leaves early. operators follow C precedence, including `c ? a : b`, plus `p.x` and `p->x` (the same thing: `.` goes through a pointer on its own), `e as T` to change a type without changing the bits, and the casts below. comparisons and `&& ||` give 0 or 1. `/`, `%` and `<<` compile to native enhancement opcodes. character literals, `0x` hex and the usual escapes are there.
functions are declared like C, return type first: `int f(int x)`, `node*.u make()`, `.u grab()` (a tag on its own), `void log(char* s)`. `fn f(a, b)` starts without explicit parameter or return types; constraints from calls and returned values propagate through callers and callees until inference reaches a fixed point, including recursive calls anchored by typed callees. conflicting argument types or an unknown reassignment leave the affected type unresolved instead of choosing a type. the learning example [32](examples/learn/32-inferred-calls.zc) shows this propagation and an owned raw-list return. a generic function lists its type parameters after its name, `T first<T>(*list<T> l)`, the same place a call gives explicit ones, `first<int>(l)`. the return type can use them before they're declared: while it's read, an unknown name is taken as a type parameter, and the list after the name has to confirm it. function types are written the same way, `int(int, *char)`, and `fn(int)` for one that returns a word. the earlier `fn f(...) -> T` spelling is gone.