1
0
forked from Mirror/wren

Add Stdin.readByte().

This commit is contained in:
Bob Nystrom
2016-05-20 11:50:14 -07:00
parent 872cfdcd42
commit 500dd41ccd
7 changed files with 140 additions and 55 deletions

View File

@ -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

View File

@ -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();

View File

@ -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_()

View File

@ -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"

View 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

View 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.