Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ websocket, tls, sse), databases (sql, postgres, mysql, redis — pure-pith
wire protocols with tls, prepared statements, and pooling), data (json,
toml, csv, config, table), bytes and crypto (hash, checksum, encoding,
crypto, bits, binary), compression and archives (gzip/zlib, tar, zip),
text (regex, scanner, fmt), app plumbing (log, metrics, cli, testing,
text (regex, scanner, fmt), app plumbing (log, metrics, cli, env, testing,
diagnostic, time, datetime, rand, uuid, math), and lazy iterators
(std.iter).

Expand Down
6 changes: 6 additions & 0 deletions docs/concurrency.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,12 @@ set of `threadlocal` globals small and the values scratch-sized. use it
for state that is genuinely per-task; a value shared *across* tasks still
belongs in a struct or behind a channel.

this is what lets the std parsers and buffers be used from many tasks at
once: `std.json` and `std.toml` keep their parse arena in `threadlocal`
globals, and `std.io`'s readers/writers keep their per-instance state the
same way, so two tasks parsing or buffering concurrently each work in
their own state with no lock and no race.

things that are still intentionally explicit or still growing:

- task cancellation is cooperative, not forceful
Expand Down
5 changes: 3 additions & 2 deletions docs/grammar.ebnf
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ KEYWORD = "fn" | "if" | "elif" | "else" | "for" | "in" | "while"
| "match" | "select" | "default" | "timeout"
| "return" | "fail" | "break" | "continue"
| "struct" | "enum" | "interface" | "impl" | "type"
| "pub" | "mut" | "ref" | "weak"
| "pub" | "mut" | "ref" | "weak" | "threadlocal"
| "import" | "from" | "as"
| "self" | "true" | "false" | "none"
| "and" | "or" | "not" | "catch"
Expand All @@ -98,14 +98,15 @@ import_list = import_name , { "," , import_name }

import_name = IDENT , [ "as" , IDENT ] ;

(* a top-level binding may be marked `threadlocal` for per-os-thread storage *)
top_level_decl = [ "pub" ] , ( fn_decl
| struct_decl
| enum_decl
| interface_decl
| impl_decl
| type_alias
| test_decl
| binding ) , NEWLINE ;
| [ "threadlocal" ] , binding ) , NEWLINE ;

test_decl = "test" , STRING_LIT , ":" , block ;

Expand Down
16 changes: 9 additions & 7 deletions docs/limitations.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,15 @@ correctness story:
cannot yet be weak. container element removal leaks until the container dies,
and error-path early returns skip cleanup. all are bounded-leak by design —
the discipline never produces a dangling pointer in exchange.
- reading an optional that is synthesized rather than stored leaks a small
optional box per read. this covers a `weak` field read and an indexed read
of a collection whose element type is a struct (`items[i]` where `items` is
`List[Node]`): both build a fresh optional to carry the liveness/`some`
result, and that box is not reclaimed. a stored optional field read does not
synthesize and does not leak. the leak is bounded per read and never
dangles; releasing synthesized optional temporaries is a known follow-up.
- reading an optional that is synthesized rather than stored can leak a small
optional box per read. a `weak` field read builds a fresh optional to carry
the liveness result; the common consumers — `!= none` / `== none` and
`.value()` — now free that shell once the value is extracted, so the common
idiom no longer leaks. an indexed read of a collection whose element type is a
struct (`items[i]` where `items` is `List[Node]`) still synthesizes an optional
that is not reclaimed. a stored optional field read does not synthesize and
does not leak. the leak is bounded per read and never dangles; reclaiming the
remaining synthesized-optional temporaries is a known follow-up.
- a handful of edge cases logged during bring-up (cross-module float returns,
cross-module map reads, set codegen, negative float literals like `-1.0`) were
re-checked and all pass; they are now pinned by regression tests
Expand Down
Loading