hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit da868e283b1a38de2346695c7e9916e200adc410
parent ef3d2b2d0fce8450e4f91ab5166558c013c0c5fc
Author: Alexey Yerin <yyp@disroot.org>
Date:   Sat, 27 Jan 2024 22:47:32 +0300

bufio::scanner: Always shift readout before requesting reads

Some functions did not follow this pattern (most importantly, scan_byte), which
caused the scanner to wrongly assume it has enough capacity and return random
bytes from its buffer.

The reason for that is (scan.pending == 0) check that assumes all of
scan.buffer[0..scan.pending] is the readahead data, which is not the case before
shifting since scan.pending includes scan.readout as well.

This could have been caught by a simple unit test, but there were no tests for
base scanner functionality.

Signed-off-by: Alexey Yerin <yyp@disroot.org>

Diffstat:
Mbufio/scanner.ha | 12+++++++-----
Mbufio/scanner_test+test.ha | 10++++++++++
2 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/bufio/scanner.ha b/bufio/scanner.ha @@ -68,6 +68,10 @@ export fn finish(scan: *scanner) void = { fn scan_read(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = { let scan = s: *scanner; + + // Consume previous read, if any + scan_shift(scan); + if (scan.pending == 0) { match (scan_readahead(scan)?) { case io::EOF => @@ -77,9 +81,6 @@ fn scan_read(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = { }; }; - // Consume previous read, if any - scan_shift(scan); - const n = if (len(buf) > scan.pending) scan.pending else len(buf); buf[..n] = scan_consume(scan, n)[..]; return n; @@ -133,6 +134,9 @@ fn scan_consume(scan: *scanner, n: size) []u8 = { // Reads one byte from a [[scanner]]. export fn scan_byte(scan: *scanner) (u8 | io::EOF | io::error) = { + // Consume previous read, if any + scan_shift(scan); + if (scan.pending == 0) { match (scan_readahead(scan)?) { case io::EOF => @@ -142,8 +146,6 @@ export fn scan_byte(scan: *scanner) (u8 | io::EOF | io::error) = { }; }; - // Consume previous read, if any - scan_shift(scan); return scan_consume(scan, 1)[0]; }; diff --git a/bufio/scanner_test+test.ha b/bufio/scanner_test+test.ha @@ -115,6 +115,16 @@ use strings; }; }; +@test fn scan_byte() void = { + let in = memio::fixed([1, 2, 3]); + let scanner = newscanner(&in, 3); + + assert(scan_byte(&scanner) as u8 == 1); + assert(scan_byte(&scanner) as u8 == 2); + assert(scan_byte(&scanner) as u8 == 3); + assert(scan_byte(&scanner) is io::EOF); +}; + @test fn scan_read() void = { const expected: [_]u8 = [ 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,