Repository navigation
weir v0.0.81
·
38 commits
to main
since this release
Immutable
release. Only release title and notes can be modified.
Fixed
- Launch is faster for scripts that import large modules. The
check-time walk that decides which module bindings are command
helpers asked, for every variable it met, whether the name was a
reifier's desugar spelling, and built 28 strings to answer each time.
The answer is now one table lookup. A script importing the 6,400-line
starship port goes from about 750 ms to about 400 ms before its first
line runs; bare startup was and is about 12 ms. - The check itself is leaner on large modules. The module loader
re-derived its command-helper table from every earlier binding on
each statement; the assembler, the district mask and doc attachment
each rescanned every physical line for its comment several times;
the load-target scan re-parsed the whole file; constructor lookup
rebuilt the set of imported types per use; and the command grammar
rebuilt its resolver-independent parsers on every attempt. Each now
does its work once. Same diagnostics, same trees: the starship import
goes from about 400 ms to about 250 ms (CPU-pinned medians 373 → 254
ms), a direct check of its largest file from 147 ms to 95 ms; bare
startup stays about 12 ms. - Imported modules check in parallel. The import graph is read
before any module checks, and a module whose imports are done checks
on a worker thread (as many as processors, at most 8) while the
importing file's check walks toward its import line; each result
surfaces at that line in load order, so diagnostics are unchanged to
the byte (an 80-file parity corpus, the starship port checked 50
times). On a 15-core box the starship import goes from 263 ms to 215
ms (medians of 9); pinned to one core it is the sequential loader,
249 ms as before; bare startup stays about 12 ms. What remains is the
collector's: the workstation GC marks on one thread, and the module
checks spend most of their parallel phase stopped for it. - The collector has less to do. Merging an imported module into the
importer rebuilt its set of taken type names once per type and walked
every type origin through an enumerator per lookup; it now keeps both
as it goes. Finalizing a statement's types and typed tree copied every
node even where nothing changed, and renaming an import's types copied
ones no rename touched; unchanged nodes are now shared. Same
diagnostics, same trees: the starship import allocates 254 MB instead
of 287 MB, promotes 13.3 MB instead of 15.7 MB out of the youngest
generation, and spends about 50 ms instead of 57 ms in GC pauses; it
goes from 246 ms to 225 ms pinned to one core and from 206 ms to 184
ms on 15 (medians of 25), a direct check of its largest file from
91 ms to 86 ms; bare startup stays about 10 ms. - The parser builds its grammar once. The command grammar was
rebuilt for every statement, and for every command line nested in a
let, anifor a value-headed pipe, because it held that statement's
name resolver; it now asks the current one as it parses. A postfix
chain rebuilt its index, slice and field parsers at every step, the
expression grammar's teaching alternatives read the source position
before checking the next character, and every node's span allocated
two positions on the way. Same diagnostics, same trees: the starship
import's parse allocates 79 MB instead of 151 MB, and the import goes
from 225 ms to 202 ms pinned to one core and from 192 ms to 167 ms on
15 (medians of 21); bare startup stays about 9 ms pinned. - A misspelled flag no longer prints the next argument. After an
unknown flag,Args.loadreported the following word as an
unexpected argument and quoted it, so--tokn hunter2for a
Secretflag printed the secret. The word is still reported, as
unexpected argument after '--tokn', without its text. cmd | exechonours the current directory, and is refused where
it would skip cleanup. The replaced process started in the
script's start directory whatevercdorwithin cdsaid; it now
starts in the session's. Inside anywithinblock (tmp,proc,
lock,serve,cd,env, or a barewithin … always)execis
now a check error: replacing the process left the temp dir behind,
orphaned the scoped process and never ranalways.let x = retry …runs each body line on its own. With the loop
head on theletline, same-indent body lines were glued into one
command (echo first echo second) with only a warning; they now
sequence as they do without thelet.- An explicit
Content-Typereplaces the body's. A request with
aContent-Typeheader and aText/Json/Formbody sent both,
comma-joined (text/plain, text/csv), which servers reject. The
explicit header now wins and exactly one is sent, as for
User-Agent. #savekeeps what it promises. A line that used a name later
redeclared was saved above the redeclaration and failed at run, and
an alias over a builtin (#alias ls = ls --color=never) dropped the
aliasedletwhile keeping its dependents. Both saved files now
check and run.- A top-level YAML
nullwritesnull.to yamlwrote empty
text for it, which does not read back, and anulldocument
vanished from ato yaml stream. Server.portreports the bound port. See Changed.Dir.movecrosses filesystems. A move to another mount failed
with "cannot access … Invalid cross-device link"; it now copies then
deletes, asmvandFile.movedo, and its errors name the paths.
A symlinked source moves as the link, exactly as on one filesystem.weir restorerepairs a locally modified signature. It said
presentand exited 0 whileverifysaid MODIFIED.Instant.tryParseWithraises for a format without a full date.
Such a format can never match, so returningNonehid the bug; it
now raises asparseWithand an unknown directive do.Http.withQueryputs the query before a#fragment. It
appended after it (h/p#frag?a=1), so the parameter was never sent.[<Wire "name">]matches a table header verbatim even when it
is spelled like the field.///above a one-line[<Attr>] field: Treaches--help.
The own-line attribute form worked; the inline one dropped the doc.weir -eand the REPL echo share one renderer. Piped, both
write a value's control characters byte-faithfully; at a terminal,
both show them visibly (\x00,\x1b). They used to disagree.- No more .NET exception text from
showof the minimum
Duration, strings past the length limit (Str.join,+,
interpolation,Str.replace,Bytes.toHexnow name the limit),
Json.inferShapeon bad JSON (and the message names
Json.inferShape, not#infer), an init file's bad#sessionenv
key (now a check error, NUL included), an out-of-range serve port,
anOthermethod that is not a token, an invalid or non-http URL, a
Transfer-Encodingrequest header (refused before send), a garbled
status line,weir add schemagiven a local path (add schema takes an http(s) URL), and a malformed.weir/lock.json. weir checkagrees with the run. It refused spec-valid code —
let q = 3 in q + 1inside an indented block,cmd | and cd din a
block — and passed code the run refused:Seq.pmap/piter/
pfirst/pforand a mutatingHttp.expectinsideplan,
[<Short "-">](a short is now one letter or digit). A misplaced
or unknown directive gets the run's message from check too, an
ambiguous imported case is named as such, env-key refusals are
located where the key is built, and a shared module's error is
reported once, not once per import.weir fmtno longer refuses a match arm continued by|>under
its body, a layout the checker accepts.- Clearer messages. No internal names (
'__hole1,'a1) or
parser expectation dumps in diagnostics; one shape for a bad flag or
env value (--rate: not a float: 'abc');--is refused as an
end-of-options marker instead of getting a did-you-mean;--help
keeps two spaces between a long flag and its text (wrapping when it
must) and shows string defaults quoted; a TLS handshake with a plain
HTTP port is no longer called an untrusted certificate; and a dozen
more located or reworded errors. - Docs match the binary. The reference and the skill file no
longer contradict behaviour:Seq.groupByforces its source,
Seq.takepast the end truncates whileskipraises,Size's
showdoes not parse back, identifiers take no',from yaml
refusesMapfields, a yaml patch's sequence appends depend on
patch order,File.existsis false for a directory, command output
starting with a UTF-16/32 byte-order mark decodes as that encoding,
and the echo shows 100 elements in-eand piped as at a terminal.
Changed
ServerConfig.portis anOption<int>.Some 8080binds that
port;Noneasks the kernel for a free one, andServer.port
reports the port actually bound (it said 0 forport = 0). Migrate
{ port = 8080; … }to{ port = Some 8080; … }.<,>,<=and>=compare strings, bools and Options.
WhateverSeq.sortorders, the operators now compare (strings
ordinally,falsebeforetrue,Nonefirst);Uuidstill has no
<.- The
-eand piped REPL echo shows 100 elements of a lazy seq,
as the terminal REPL does and#echoreports (it was 10).