lib: collapse the manual rt_ensure append workarounds onto the fixed builtin (#34 follow-up)
shlex.appendstr, getopt.appendoption, bytes.appendslice and
strings.appendstr existed only because the append builtin stored the
first 8 bytes of the element; each carried its own @symbol("rt_ensure")
bind and a grow-then-store-through-*T body, with comments promising to
"collapse in one go when the append builtin is fixed". The previous
commit fixed the builtin; this removes all four helpers and their
rt_ensure binds and spells every call site as plain append().
Bonus correctness: getopt's appendoption passed a hardcoded membsz of
24, stale since the str 24B redesign made option {rune, str} 32B — the
manual growth under-allocated past 6 options while &opts.ptr[i] strode
32 (latent OOB). The builtin derives membsz from the type table
(probe: MOVQ $32, SI), closing that drift by construction.
This commit is contained in:
@@ -30,7 +30,7 @@
|
||||
//
|
||||
// - Drop nomem: ww os.alloc has no recoverable failure path (OOM
|
||||
// yields a poisonous pointer that faults on deref; see lib/os.ww
|
||||
// comment). Same precedent as strings.dup, getopt.appendoption.
|
||||
// comment). Same precedent as strings.dup.
|
||||
// Hare's (...|syntaxerr|nomem) collapses to (...|syntaxerr).
|
||||
//
|
||||
// - Byte-wise iteration via i32 cursor instead of Hare's
|
||||
@@ -55,15 +55,6 @@
|
||||
// "write one byte" path goes through `io.write(s, buf[0:1])`
|
||||
// against a stack `[N]u8`. Same shape as fmt's rune-arm.
|
||||
//
|
||||
// - `[]str` grown via direct rt_ensure rather than the `append`
|
||||
// builtin: cgen lowers `append(slice, element)` to a single MOVQ
|
||||
// of the first 8 bytes, which drops the `len` half of a 16B str
|
||||
// element. [[appendstr]] writes both halves through `*str`.
|
||||
// Same gap, same workaround, same comment shape as
|
||||
// [[getopt.appendoption]] (lib/getopt/getopt.ww:96-106) — kept
|
||||
// greppable across modules. When the append-builtin is fixed,
|
||||
// all three (getopt, shlex, anywhere else) collapse in one go.
|
||||
//
|
||||
// - Internal [[dupstr]] inlined rather than `use strings;`: keeps
|
||||
// the dep surface small for a 6-line helper. shlex doesn't reach
|
||||
// for any other strings:: routine, and callers free split()'s
|
||||
@@ -94,13 +85,6 @@ import memio;
|
||||
import os;
|
||||
import strings;
|
||||
|
||||
// rt_ensure is the runtime slice-growth helper invoked by the
|
||||
// `append(s, v)` builtin. We bind it directly because the builtin's
|
||||
// expansion stores only 8 bytes of the new element (cgen emits a
|
||||
// single MOVQ), losing the `len` half of a `str` (16B). No public
|
||||
// stdlib facade exposes it, hence the direct @symbol.
|
||||
@symbol("rt_ensure") fn rtensure(s: *void, membsz: u64) void;
|
||||
|
||||
// syntaxerr — the input wasn't a valid shell-tokenizable string
|
||||
// (unterminated quote / bare trailing backslash). Mirrors Hare's
|
||||
// shlex::syntaxerr; a `!void` so it can ride a tagged-union return
|
||||
@@ -127,18 +111,6 @@ fn dupstr(s: str) str = {
|
||||
return strings.frombytes(buf);
|
||||
};
|
||||
|
||||
// appendstr — grow `*slice` by one and store `item` (16B). Bypasses
|
||||
// the `append` builtin's first-8B-only store gap; mirror of
|
||||
// [[getopt.appendoption]] for the `[]option` case.
|
||||
fn appendstr(slice: *[]str, item: str) void = {
|
||||
let newlen: i32 = slice.len + 1;
|
||||
slice.len = newlen;
|
||||
rtensure(slice: *void, size(str): u64);
|
||||
let dst: *str = &slice.ptr[newlen - 1];
|
||||
dst.ptr = item.ptr;
|
||||
dst.len = item.len;
|
||||
};
|
||||
|
||||
// freepartial — drop a partially built [[split]] result on the
|
||||
// syntaxerr path. Hare uses a `defer if (!ok)` guard; ww has no defer,
|
||||
// so we hand-roll the cleanup at every error return. Mirror of
|
||||
@@ -271,7 +243,7 @@ export fn split(in: str) ([]str | syntaxerr) = {
|
||||
if (!first) {
|
||||
let view: str = memio.string(&st);
|
||||
let owned: str = dupstr(view);
|
||||
appendstr(&slice, owned);
|
||||
append(slice, owned);
|
||||
memio.reset(&st);
|
||||
};
|
||||
dirty = false;
|
||||
@@ -315,7 +287,7 @@ export fn split(in: str) ([]str | syntaxerr) = {
|
||||
if (dirty) {
|
||||
let view: str = memio.string(&st);
|
||||
let owned: str = dupstr(view);
|
||||
appendstr(&slice, owned);
|
||||
append(slice, owned);
|
||||
};
|
||||
|
||||
let _c = io.close(snk);
|
||||
|
||||
Reference in New Issue
Block a user