ww: import toolchain — C bootstrap + ww-side self-host (phases 0-10)
C bootstrap (phases 0-9):
cmd/wwc, cmd/6c, cmd/6a, cmd/6l, cmd/ww, rt, lib/*.
ww-side self-host (phase 10):
selfhost/cmd/wwc — ww-cgen frontend; bootstrap fixed point.
selfhost/cmd/6a — assembler; byte-identical to C 6a (test 991).
selfhost/cmd/6l — linker w/ archive (.a) support; byte-identical
to C 6l (test 992).
selfhost/cmd/ww — driver (build/run/version); byte-identical to
C ww (test 993).
make test: 15/15. make bootstrap: ww2.s == ww3.s, ww2.o == ww3.o,
ww2 == ww3 byte-identical, with the full ww-tooled chain.
This commit is contained in:
82
lib/bufio/bufio.ww
Normal file
82
lib/bufio/bufio.ww
Normal file
@@ -0,0 +1,82 @@
|
||||
// bufio — buffered reader/writer over io.stream. Plan 9 'bio'
|
||||
// analogue, lowered to ww. The buffer is owned by the caller and
|
||||
// passed in at init time; we don't allocate.
|
||||
//
|
||||
// We keep the stream pointer as *void here to avoid a cross-module
|
||||
// type name (the module-import system isn't online yet); a later
|
||||
// revision will replace it with *io.stream once `use` resolves
|
||||
// types from imported modules.
|
||||
|
||||
type stream_p = *void;
|
||||
|
||||
type buf = struct {
|
||||
s: stream_p,
|
||||
data: *u8,
|
||||
cap: i32,
|
||||
r: i32, // read cursor
|
||||
w: i32, // write cursor (for writers)
|
||||
};
|
||||
|
||||
export fn rinit(b: *buf, s: stream_p, data: *u8, cap: i32) void = {
|
||||
b.s = s;
|
||||
b.data = data;
|
||||
b.cap = cap;
|
||||
b.r = 0;
|
||||
b.w = 0;
|
||||
};
|
||||
|
||||
// peek1 — look at the next byte without consuming. Returns -1 on
|
||||
// empty buffer; the caller is responsible for refilling via the
|
||||
// stream when this happens.
|
||||
export fn peek1(b: *buf) i32 = {
|
||||
if (b.r < b.w) {
|
||||
return b.data[b.r]: i32;
|
||||
};
|
||||
return -1;
|
||||
};
|
||||
|
||||
// take1 — pop one byte. -1 if empty.
|
||||
export fn take1(b: *buf) i32 = {
|
||||
if (b.r < b.w) {
|
||||
let c: u8 = b.data[b.r];
|
||||
b.r += 1;
|
||||
return c: i32;
|
||||
};
|
||||
return -1;
|
||||
};
|
||||
|
||||
// avail — bytes left to read out of the buffer.
|
||||
export fn avail(b: *buf) i32 = {
|
||||
return b.w - b.r;
|
||||
};
|
||||
|
||||
// Distinct alias so `(str | linerr)` has two variant types the
|
||||
// tagged-union machinery can keep apart at the tag level. The error
|
||||
// variant carries a short description; callers compare with errors.is
|
||||
// or just inspect by length.
|
||||
type linerr = str;
|
||||
|
||||
// takeline — Hare-style fallible line read. Drains the buffer up to
|
||||
// (but not including) the next '\n' and advances the cursor past the
|
||||
// newline. Returns the line as a borrowed str on success, or a linerr
|
||||
// describing why no line was available:
|
||||
// - "eof" when the buffer is empty
|
||||
// - "no newline" when the buffer contains data but no '\n'
|
||||
//
|
||||
// The returned str borrows from the underlying buffer; callers must
|
||||
// consume it (or copy) before refilling.
|
||||
export fn takeline(b: *buf) (str | linerr) = {
|
||||
if (b.r >= b.w) { return "eof": linerr; };
|
||||
let i: i32 = b.r;
|
||||
for (i < b.w) {
|
||||
if (b.data[i] == 10u8) {
|
||||
let s: str;
|
||||
s.ptr = b.data + b.r;
|
||||
s.len = i - b.r;
|
||||
b.r = i + 1;
|
||||
return s;
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
return "no newline": linerr;
|
||||
};
|
||||
Reference in New Issue
Block a user