Fix a couple of bugs in the REPL.
- Not sure what was going on, but fix #456. It makes more sense for the REPL to invoke the compiled code as a fiber than a function anyway. - Flush stdout before reading from stdin since System.print() no longer does that automatically.
This commit is contained in:
+43
-36
@@ -1,5 +1,5 @@
|
||||
import "meta" for Meta
|
||||
import "io" for Stdin
|
||||
import "io" for Stdin, Stdout
|
||||
import "os" for Platform
|
||||
|
||||
/// Abstract base class for the REPL. Manages the input line and history, but
|
||||
@@ -154,51 +154,44 @@ class Repl {
|
||||
|
||||
System.print()
|
||||
|
||||
// Guess if it looks like a statement or expression. Statements need to be
|
||||
// evaluated at the top level in case they declare variables, but they
|
||||
// don't return a value. Expressions need to have their result displayed.
|
||||
var tokens = lex(input, false)
|
||||
// Guess if it looks like a statement or expression. If it looks like an
|
||||
// expression, we try to print the result.
|
||||
var token = lexFirst(input)
|
||||
|
||||
// No code, so do nothing.
|
||||
if (tokens.isEmpty) return
|
||||
if (token == null) return
|
||||
|
||||
var first = tokens[0]
|
||||
var isStatement =
|
||||
first.type == Token.breakKeyword ||
|
||||
first.type == Token.classKeyword ||
|
||||
first.type == Token.forKeyword ||
|
||||
first.type == Token.foreignKeyword ||
|
||||
first.type == Token.ifKeyword ||
|
||||
first.type == Token.importKeyword ||
|
||||
first.type == Token.returnKeyword ||
|
||||
first.type == Token.varKeyword ||
|
||||
first.type == Token.whileKeyword
|
||||
token.type == Token.breakKeyword ||
|
||||
token.type == Token.classKeyword ||
|
||||
token.type == Token.forKeyword ||
|
||||
token.type == Token.foreignKeyword ||
|
||||
token.type == Token.ifKeyword ||
|
||||
token.type == Token.importKeyword ||
|
||||
token.type == Token.returnKeyword ||
|
||||
token.type == Token.varKeyword ||
|
||||
token.type == Token.whileKeyword
|
||||
|
||||
var fiber
|
||||
if (isStatement) {
|
||||
fiber = Fiber.new {
|
||||
// TODO: Should evaluate in main module, not repl's own.
|
||||
Meta.eval(input)
|
||||
}
|
||||
|
||||
var result = fiber.try()
|
||||
if (fiber.error == null) return
|
||||
fiber = Meta.compile(input)
|
||||
} else {
|
||||
// TODO: Should evaluate in main module, not repl's own.
|
||||
var function = Meta.compileExpression(input)
|
||||
if (function == null) return
|
||||
|
||||
fiber = Fiber.new(function)
|
||||
var result = fiber.try()
|
||||
if (fiber.error == null) {
|
||||
// TODO: Handle error in result.toString.
|
||||
showResult(result)
|
||||
return
|
||||
}
|
||||
fiber = Meta.compileExpression(input)
|
||||
}
|
||||
|
||||
// TODO: Include callstack.
|
||||
showRuntimeError("Runtime error: %(fiber.error)")
|
||||
// Stop if there was a compile error.
|
||||
if (fiber == null) return
|
||||
|
||||
var result = fiber.try()
|
||||
if (fiber.error != null) {
|
||||
// TODO: Include callstack.
|
||||
showRuntimeError("Runtime error: %(fiber.error)")
|
||||
return
|
||||
}
|
||||
|
||||
if (!isStatement) {
|
||||
showResult(result)
|
||||
}
|
||||
}
|
||||
|
||||
lex(line, includeWhitespace) {
|
||||
@@ -217,6 +210,18 @@ class Repl {
|
||||
return tokens
|
||||
}
|
||||
|
||||
lexFirst(line) {
|
||||
var lexer = Lexer.new(line)
|
||||
while (true) {
|
||||
var token = lexer.readToken()
|
||||
if (token.type == Token.eof) return null
|
||||
|
||||
if (token.type != Token.comment && token.type != Token.whitespace) {
|
||||
return token
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the best possible auto-completion for the current line, or null if
|
||||
/// there is none. The completion is the remaining string to append to the
|
||||
/// line, not the entire completed line.
|
||||
@@ -256,6 +261,7 @@ class SimpleRepl is Repl {
|
||||
|
||||
// Write the line.
|
||||
System.write(line)
|
||||
Stdout.flush()
|
||||
}
|
||||
|
||||
showResult(value) {
|
||||
@@ -351,6 +357,7 @@ class AnsiRepl is Repl {
|
||||
|
||||
// Position the cursor.
|
||||
System.write("\r\x1b[%(2 + cursor)C")
|
||||
Stdout.flush()
|
||||
}
|
||||
|
||||
showResult(value) {
|
||||
|
||||
+43
-36
@@ -1,7 +1,7 @@
|
||||
// Generated automatically from src/module/repl.wren. Do not edit.
|
||||
static const char* replModuleSource =
|
||||
"import \"meta\" for Meta\n"
|
||||
"import \"io\" for Stdin\n"
|
||||
"import \"io\" for Stdin, Stdout\n"
|
||||
"import \"os\" for Platform\n"
|
||||
"\n"
|
||||
"/// Abstract base class for the REPL. Manages the input line and history, but\n"
|
||||
@@ -156,51 +156,44 @@ static const char* replModuleSource =
|
||||
"\n"
|
||||
" System.print()\n"
|
||||
"\n"
|
||||
" // Guess if it looks like a statement or expression. Statements need to be\n"
|
||||
" // evaluated at the top level in case they declare variables, but they\n"
|
||||
" // don't return a value. Expressions need to have their result displayed.\n"
|
||||
" var tokens = lex(input, false)\n"
|
||||
" // Guess if it looks like a statement or expression. If it looks like an\n"
|
||||
" // expression, we try to print the result.\n"
|
||||
" var token = lexFirst(input)\n"
|
||||
"\n"
|
||||
" // No code, so do nothing.\n"
|
||||
" if (tokens.isEmpty) return\n"
|
||||
" if (token == null) return\n"
|
||||
"\n"
|
||||
" var first = tokens[0]\n"
|
||||
" var isStatement =\n"
|
||||
" first.type == Token.breakKeyword ||\n"
|
||||
" first.type == Token.classKeyword ||\n"
|
||||
" first.type == Token.forKeyword ||\n"
|
||||
" first.type == Token.foreignKeyword ||\n"
|
||||
" first.type == Token.ifKeyword ||\n"
|
||||
" first.type == Token.importKeyword ||\n"
|
||||
" first.type == Token.returnKeyword ||\n"
|
||||
" first.type == Token.varKeyword ||\n"
|
||||
" first.type == Token.whileKeyword\n"
|
||||
" token.type == Token.breakKeyword ||\n"
|
||||
" token.type == Token.classKeyword ||\n"
|
||||
" token.type == Token.forKeyword ||\n"
|
||||
" token.type == Token.foreignKeyword ||\n"
|
||||
" token.type == Token.ifKeyword ||\n"
|
||||
" token.type == Token.importKeyword ||\n"
|
||||
" token.type == Token.returnKeyword ||\n"
|
||||
" token.type == Token.varKeyword ||\n"
|
||||
" token.type == Token.whileKeyword\n"
|
||||
"\n"
|
||||
" var fiber\n"
|
||||
" if (isStatement) {\n"
|
||||
" fiber = Fiber.new {\n"
|
||||
" // TODO: Should evaluate in main module, not repl's own.\n"
|
||||
" Meta.eval(input)\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" var result = fiber.try()\n"
|
||||
" if (fiber.error == null) return\n"
|
||||
" fiber = Meta.compile(input)\n"
|
||||
" } else {\n"
|
||||
" // TODO: Should evaluate in main module, not repl's own.\n"
|
||||
" var function = Meta.compileExpression(input)\n"
|
||||
" if (function == null) return\n"
|
||||
"\n"
|
||||
" fiber = Fiber.new(function)\n"
|
||||
" var result = fiber.try()\n"
|
||||
" if (fiber.error == null) {\n"
|
||||
" // TODO: Handle error in result.toString.\n"
|
||||
" showResult(result)\n"
|
||||
" return\n"
|
||||
" }\n"
|
||||
" fiber = Meta.compileExpression(input)\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" // TODO: Include callstack.\n"
|
||||
" showRuntimeError(\"Runtime error: %(fiber.error)\")\n"
|
||||
" // Stop if there was a compile error.\n"
|
||||
" if (fiber == null) return\n"
|
||||
"\n"
|
||||
" var result = fiber.try()\n"
|
||||
" if (fiber.error != null) {\n"
|
||||
" // TODO: Include callstack.\n"
|
||||
" showRuntimeError(\"Runtime error: %(fiber.error)\")\n"
|
||||
" return\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" if (!isStatement) {\n"
|
||||
" showResult(result)\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" lex(line, includeWhitespace) {\n"
|
||||
@@ -219,6 +212,18 @@ static const char* replModuleSource =
|
||||
" return tokens\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" lexFirst(line) {\n"
|
||||
" var lexer = Lexer.new(line)\n"
|
||||
" while (true) {\n"
|
||||
" var token = lexer.readToken()\n"
|
||||
" if (token.type == Token.eof) return null\n"
|
||||
"\n"
|
||||
" if (token.type != Token.comment && token.type != Token.whitespace) {\n"
|
||||
" return token\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" /// Gets the best possible auto-completion for the current line, or null if\n"
|
||||
" /// there is none. The completion is the remaining string to append to the\n"
|
||||
" /// line, not the entire completed line.\n"
|
||||
@@ -258,6 +263,7 @@ static const char* replModuleSource =
|
||||
"\n"
|
||||
" // Write the line.\n"
|
||||
" System.write(line)\n"
|
||||
" Stdout.flush()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" showResult(value) {\n"
|
||||
@@ -353,6 +359,7 @@ static const char* replModuleSource =
|
||||
"\n"
|
||||
" // Position the cursor.\n"
|
||||
" System.write(\"\r\x1b[%(2 + cursor)C\")\n"
|
||||
" Stdout.flush()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" showResult(value) {\n"
|
||||
|
||||
Reference in New Issue
Block a user