forked from Mirror/wren
Add Stdin.readByte().
This commit is contained in:
@ -4,6 +4,13 @@ The standard input stream.
|
||||
|
||||
## Static Methods
|
||||
|
||||
### **readByte**()
|
||||
|
||||
Reads one byte of input from stdin. Blocks the current fiber until a byte has
|
||||
been received.
|
||||
|
||||
Returns the byte value as a number or `null` if stdin is closed.
|
||||
|
||||
### **readLine**()
|
||||
|
||||
Reads one line of input from stdin. Blocks the current fiber until a full line
|
||||
|
||||
@ -496,7 +496,7 @@ static void allocCallback(uv_handle_t* handle, size_t suggestedSize,
|
||||
}
|
||||
|
||||
static void stdinReadCallback(uv_stream_t* stream, ssize_t numRead,
|
||||
const uv_buf_t* buffer)
|
||||
const uv_buf_t* buffer)
|
||||
{
|
||||
WrenVM* vm = getVM();
|
||||
|
||||
|
||||
@ -215,55 +215,79 @@ foreign class Stat {
|
||||
}
|
||||
|
||||
class Stdin {
|
||||
static readLine() {
|
||||
if (__isClosed == true) {
|
||||
Fiber.abort("Stdin was closed.")
|
||||
static readByte() {
|
||||
return read_ {
|
||||
// Peel off the first byte.
|
||||
var byte = __buffered.bytes[0]
|
||||
__buffered = __buffered[1..-1]
|
||||
return byte
|
||||
}
|
||||
}
|
||||
|
||||
static readLine() {
|
||||
return read_ {
|
||||
// TODO: Handle Windows line separators.
|
||||
var lineSeparator = __buffered.indexOf("\n")
|
||||
if (lineSeparator == -1) return null
|
||||
|
||||
// Split the line at the separator.
|
||||
var line = __buffered[0...lineSeparator]
|
||||
__buffered = __buffered[lineSeparator + 1..-1]
|
||||
return line
|
||||
}
|
||||
}
|
||||
|
||||
static read_(handleData) {
|
||||
// See if we're already buffered enough to immediately produce a result.
|
||||
if (__buffered != null && !__buffered.isEmpty) {
|
||||
var result = handleData.call()
|
||||
if (result != null) return result
|
||||
}
|
||||
|
||||
if (__isClosed == true) Fiber.abort("Stdin was closed.")
|
||||
|
||||
// Otherwise, we need to wait for input to come in.
|
||||
__handleData = handleData
|
||||
|
||||
// TODO: Error if other fiber is already waiting.
|
||||
readStart_()
|
||||
|
||||
__waitingFiber = Fiber.current
|
||||
var line = Scheduler.runNextScheduled_()
|
||||
var result = Scheduler.runNextScheduled_()
|
||||
|
||||
readStop_()
|
||||
return line
|
||||
return result
|
||||
}
|
||||
|
||||
static onData_(data) {
|
||||
// If data is null, it means stdin just closed.
|
||||
if (data == null) {
|
||||
__isClosed = true
|
||||
readStop_()
|
||||
|
||||
if (__line != null) {
|
||||
// Emit the last line.
|
||||
var line = __line
|
||||
__line = null
|
||||
if (__waitingFiber != null) __waitingFiber.transfer(line)
|
||||
if (__buffered != null) {
|
||||
// TODO: Is this correct for readByte()?
|
||||
// Emit the last remaining bytes.
|
||||
var result = __buffered
|
||||
__buffered = null
|
||||
__waitingFiber.transfer(result)
|
||||
} else {
|
||||
__waitingFiber.transferError("Stdin was closed.")
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Handle Windows line separators.
|
||||
var lineSeparator = data.indexOf("\n")
|
||||
|
||||
if (__line == null) __line = ""
|
||||
if (lineSeparator == -1) {
|
||||
// No end of line yet, so just accumulate it.
|
||||
__line = __line + data
|
||||
// Append to the buffer.
|
||||
if (__buffered == null) {
|
||||
__buffered = data
|
||||
} else {
|
||||
// Split the line at the separator.
|
||||
var line = __line + data[0...lineSeparator]
|
||||
if (lineSeparator > 0 && lineSeparator < data.count - 1) {
|
||||
// Buffer up the characters after the separator for the next line.
|
||||
__line = data[lineSeparator + 1..-1]
|
||||
} else {
|
||||
__line = ""
|
||||
}
|
||||
|
||||
if (__waitingFiber != null) __waitingFiber.transfer(line)
|
||||
// TODO: Instead of concatenating strings each time, it's probably faster
|
||||
// to keep a list of buffers and flatten lazily.
|
||||
__buffered = __buffered + data
|
||||
}
|
||||
|
||||
// Ask the data handler if we have a complete result now.
|
||||
var result = __handleData.call()
|
||||
if (result != null) __waitingFiber.transfer(result)
|
||||
}
|
||||
|
||||
foreign static readStart_()
|
||||
|
||||
@ -217,55 +217,79 @@ static const char* ioModuleSource =
|
||||
"}\n"
|
||||
"\n"
|
||||
"class Stdin {\n"
|
||||
" static readLine() {\n"
|
||||
" if (__isClosed == true) {\n"
|
||||
" Fiber.abort(\"Stdin was closed.\")\n"
|
||||
" static readByte() {\n"
|
||||
" return read_ {\n"
|
||||
" // Peel off the first byte.\n"
|
||||
" var byte = __buffered.bytes[0]\n"
|
||||
" __buffered = __buffered[1..-1]\n"
|
||||
" return byte\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static readLine() {\n"
|
||||
" return read_ {\n"
|
||||
" // TODO: Handle Windows line separators.\n"
|
||||
" var lineSeparator = __buffered.indexOf(\"\n\")\n"
|
||||
" if (lineSeparator == -1) return null\n"
|
||||
"\n"
|
||||
" // Split the line at the separator.\n"
|
||||
" var line = __buffered[0...lineSeparator]\n"
|
||||
" __buffered = __buffered[lineSeparator + 1..-1]\n"
|
||||
" return line\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static read_(handleData) {\n"
|
||||
" // See if we're already buffered enough to immediately produce a result.\n"
|
||||
" if (__buffered != null && !__buffered.isEmpty) {\n"
|
||||
" var result = handleData.call()\n"
|
||||
" if (result != null) return result\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" if (__isClosed == true) Fiber.abort(\"Stdin was closed.\")\n"
|
||||
"\n"
|
||||
" // Otherwise, we need to wait for input to come in.\n"
|
||||
" __handleData = handleData\n"
|
||||
"\n"
|
||||
" // TODO: Error if other fiber is already waiting.\n"
|
||||
" readStart_()\n"
|
||||
"\n"
|
||||
" __waitingFiber = Fiber.current\n"
|
||||
" var line = Scheduler.runNextScheduled_()\n"
|
||||
" var result = Scheduler.runNextScheduled_()\n"
|
||||
"\n"
|
||||
" readStop_()\n"
|
||||
" return line\n"
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static onData_(data) {\n"
|
||||
" // If data is null, it means stdin just closed.\n"
|
||||
" if (data == null) {\n"
|
||||
" __isClosed = true\n"
|
||||
" readStop_()\n"
|
||||
"\n"
|
||||
" if (__line != null) {\n"
|
||||
" // Emit the last line.\n"
|
||||
" var line = __line\n"
|
||||
" __line = null\n"
|
||||
" if (__waitingFiber != null) __waitingFiber.transfer(line)\n"
|
||||
" if (__buffered != null) {\n"
|
||||
" // TODO: Is this correct for readByte()?\n"
|
||||
" // Emit the last remaining bytes.\n"
|
||||
" var result = __buffered\n"
|
||||
" __buffered = null\n"
|
||||
" __waitingFiber.transfer(result)\n"
|
||||
" } else {\n"
|
||||
" __waitingFiber.transferError(\"Stdin was closed.\")\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" // TODO: Handle Windows line separators.\n"
|
||||
" var lineSeparator = data.indexOf(\"\n\")\n"
|
||||
"\n"
|
||||
" if (__line == null) __line = \"\"\n"
|
||||
" if (lineSeparator == -1) {\n"
|
||||
" // No end of line yet, so just accumulate it.\n"
|
||||
" __line = __line + data\n"
|
||||
" // Append to the buffer.\n"
|
||||
" if (__buffered == null) {\n"
|
||||
" __buffered = data\n"
|
||||
" } else {\n"
|
||||
" // Split the line at the separator.\n"
|
||||
" var line = __line + data[0...lineSeparator]\n"
|
||||
" if (lineSeparator > 0 && lineSeparator < data.count - 1) {\n"
|
||||
" // Buffer up the characters after the separator for the next line.\n"
|
||||
" __line = data[lineSeparator + 1..-1]\n"
|
||||
" } else {\n"
|
||||
" __line = \"\"\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" if (__waitingFiber != null) __waitingFiber.transfer(line)\n"
|
||||
" // TODO: Instead of concatenating strings each time, it's probably faster\n"
|
||||
" // to keep a list of buffers and flatten lazily.\n"
|
||||
" __buffered = __buffered + data\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" // Ask the data handler if we have a complete result now.\n"
|
||||
" var result = __handleData.call()\n"
|
||||
" if (result != null) __waitingFiber.transfer(result)\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" foreign static readStart_()\n"
|
||||
|
||||
21
test/io/stdin/read_byte.wren
Normal file
21
test/io/stdin/read_byte.wren
Normal file
@ -0,0 +1,21 @@
|
||||
import "io" for Stdin
|
||||
|
||||
for (i in 1...13) {
|
||||
System.print(Stdin.readByte())
|
||||
}
|
||||
|
||||
// stdin: first
|
||||
// expect: 102
|
||||
// expect: 105
|
||||
// expect: 114
|
||||
// expect: 115
|
||||
// expect: 116
|
||||
// expect: 10
|
||||
|
||||
// stdin: second
|
||||
// expect: 115
|
||||
// expect: 101
|
||||
// expect: 99
|
||||
// expect: 111
|
||||
// expect: 110
|
||||
// expect: 100
|
||||
9
test/io/stdin/read_byte_eof.wren
Normal file
9
test/io/stdin/read_byte_eof.wren
Normal file
@ -0,0 +1,9 @@
|
||||
import "io" for Stdin
|
||||
|
||||
Stdin.readLine() // stdin: one line
|
||||
|
||||
var error = Fiber.new {
|
||||
Stdin.readByte()
|
||||
}.try()
|
||||
|
||||
System.print(error) // expect: Stdin was closed.
|
||||
Reference in New Issue
Block a user