diff --git a/CHANGELOG.md b/CHANGELOG.md index d6e042bdd..fc748f27e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project does not currently adhere to a particular versioning scheme. - Fix readback when hvm net has `a{n}` or `x{n}` vars. ([#659][gh-659]) - Fix imported constructors not being updated to Constructor expression. ([#674][gh-674]) - Fix parse error on parenthesized eraser. ([#675][gh-675]) +- Fix IO/FS/read_line when the line ends with a EOF. ([#638][gh-638]) ### Added @@ -426,4 +427,5 @@ and this project does not currently adhere to a particular versioning scheme. [gh-673]: https://github.com/HigherOrderCO/Bend/pull/673 [gh-674]: https://github.com/HigherOrderCO/Bend/issues/674 [gh-675]: https://github.com/HigherOrderCO/Bend/issues/675 +[gh-638]: https://github.com/HigherOrderCO/Bend/issues/638 [Unreleased]: https://github.com/HigherOrderCO/Bend/compare/0.2.36...HEAD diff --git a/src/fun/builtins.bend b/src/fun/builtins.bend index c6e830b8d..cca33de52 100644 --- a/src/fun/builtins.bend +++ b/src/fun/builtins.bend @@ -307,6 +307,7 @@ def IO/FS/read_line.read_chunks(fd, chunks): # Read line in 1kB chunks chunk <- IO/done_on_err(IO/FS/read(fd, 1024)) match res = List/split_once(chunk, '\n'): + # Found a newline, backtrack and join chunks case Result/Ok: (line, rest) = res.val (length, *) = List/length(rest) @@ -314,10 +315,18 @@ def IO/FS/read_line.read_chunks(fd, chunks): chunks = List/Cons(line, chunks) bytes = List/flatten(chunks) return wrap(bytes) + # Newline not found case Result/Err: line = res.val - chunks = List/Cons(line, chunks) - return IO/FS/read_line.read_chunks(fd, chunks) + (length, line) = List/length(line) + # If length is 0, the end of the file was reached, return as if it was a newline + if length == 0: + bytes = List/flatten(chunks) + return wrap(bytes) + # Otherwise, the line is still ongoing, read more chunks + else: + chunks = List/Cons(line, chunks) + return IO/FS/read_line.read_chunks(fd, chunks) # IO/FS/write_file(path: String, bytes: (List u24)) -> (IO None) # Writes a list of bytes to a file given by a path. diff --git a/tests/golden_tests/io/eof.txt b/tests/golden_tests/io/eof.txt new file mode 100644 index 000000000..f3a34851d --- /dev/null +++ b/tests/golden_tests/io/eof.txt @@ -0,0 +1 @@ +text \ No newline at end of file diff --git a/tests/golden_tests/io/read_line_eof.bend b/tests/golden_tests/io/read_line_eof.bend new file mode 100644 index 000000000..877b63308 --- /dev/null +++ b/tests/golden_tests/io/read_line_eof.bend @@ -0,0 +1,6 @@ +def main: + with IO: + fd <- IO/done_on_err(IO/FS/open("tests/golden_tests/io/eof.txt", "r")) + bytes <- IO/FS/read_line(fd) + txt = String/decode_utf8(bytes) + return wrap(txt) diff --git a/tests/snapshots/io__read_line_eof.bend.snap b/tests/snapshots/io__read_line_eof.bend.snap new file mode 100644 index 000000000..6c7d5ad3d --- /dev/null +++ b/tests/snapshots/io__read_line_eof.bend.snap @@ -0,0 +1,6 @@ +--- +source: tests/golden_tests.rs +input_file: tests/golden_tests/io/read_line_eof.bend +--- +Strict mode: +λa (a IO/Done/tag IO/MAGIC "text")