lib+test: graduate bufio to Hare scanner on io.stream

Scanner subset: newscanner, finish, scanbyte, scanline, scantok,
overflow (named-void). Buffer caller-owned; EOF_DISCARD default.
Skips Hare's scanner-as-io.stream embed pending task #6 (chained
N_DOT-of-N_DOT miscompile).
This commit is contained in:
2026-05-13 20:38:55 +09:00
parent 2243849855
commit 036b2c851f
4 changed files with 640 additions and 83 deletions

View File

@@ -1300,35 +1300,49 @@ static const struct row rows[] = {
"fn main() i32 = {\n"
" return dispatch(classify(1)) + dispatch(classify(2)) + dispatch(classify(3));\n"
"};", 60 },
/* bufio.readline: drain successive '\\n'-terminated lines from a
* pre-filled buffer, then a trailing fragment that returns the
* `linerr` variant carrying \"no newline\" (10 chars). */
/* bufio.scanline: drain '\\n'-terminated lines from a memio.fixed
* source through a bufio.scanner. The trailing "baz" fragment has
* no newline; under the EOF_DISCARD default it's dropped and the
* call returns io.eof. Also pins the cross-module type ref
* (scanner stores *io.stream) end-to-end through `use`. */
{ "use bufio;\n"
"use io;\n"
"use memio;\n"
"fn main() i32 = {\n"
" let raw: [11]u8;\n"
" raw[0] = 102u8; raw[1] = 111u8; raw[2] = 111u8; raw[3] = 10u8;\n"
" raw[4] = 98u8; raw[5] = 97u8; raw[6] = 114u8; raw[7] = 10u8;\n"
" raw[8] = 98u8; raw[9] = 97u8; raw[10] = 122u8;\n"
" let b: bufio.buf;\n"
" b.s = nil; b.data = raw.ptr; b.cap = 11; b.r = 0; b.w = 11;\n"
" let mem: memio.state;\n"
" let m: io.stream;\n"
" memio.fixed(&mem, &m, raw[0:11]);\n"
" let buf: [16]u8;\n"
" let sc: bufio.scanner;\n"
" bufio.newscanner(&sc, &m, buf[0:16]);\n"
" let acc: i32 = 0;\n"
" let l1: (str | bufio.linerr) = bufio.readline(&b);\n"
" let l1: (str | io.eof | io.closed | bufio.overflow) = bufio.scanline(&sc);\n"
" match (l1) {\n"
" case let s: str => acc += s.len: i32;\n"
" case let e: bufio.linerr => acc += -100;\n"
" case let s: str => acc += s.len;\n"
" case io.eof => acc += -100;\n"
" case io.closed => acc += -1000;\n"
" case bufio.overflow => acc += -10000;\n"
" };\n"
" let l2: (str | bufio.linerr) = bufio.readline(&b);\n"
" let l2: (str | io.eof | io.closed | bufio.overflow) = bufio.scanline(&sc);\n"
" match (l2) {\n"
" case let s: str => acc += s.len: i32;\n"
" case let e: bufio.linerr => acc += -100;\n"
" case let s: str => acc += s.len;\n"
" case io.eof => acc += -100;\n"
" case io.closed => acc += -1000;\n"
" case bufio.overflow => acc += -10000;\n"
" };\n"
" let l3: (str | bufio.linerr) = bufio.readline(&b);\n"
" let l3: (str | io.eof | io.closed | bufio.overflow) = bufio.scanline(&sc);\n"
" match (l3) {\n"
" case let s: str => acc += -100;\n"
" case let e: bufio.linerr => acc += e.len: i32;\n"
" case let s: str => acc += -100;\n"
" case io.eof => acc += 7;\n"
" case io.closed => acc += -1000;\n"
" case bufio.overflow => acc += -10000;\n"
" };\n"
" return acc;\n"
"};", 16 }, /* 3 + 3 + len(\"no newline\")=10 */
"};", 13 }, /* 3 + 3 + 7 (eof arm) */
/* `(scalar, str)` tuple return: AX:DX:CX convention extends the
* tagged-union ABI. AX = scalar, DX = str.ptr, CX = str.len.
* Receive sites destructure off the same regs regardless of