proper error handling in ROMBASIC

Former-commit-id: b5bd084e6807c765cdd6d3ffff1b1628321b9c6a
Former-commit-id: 55c3bb3cd56c7867809c0819f178aeebf1e46676
This commit is contained in:
Song Minjae
2016-09-22 18:16:38 +09:00
parent 6caae90d7e
commit 433f27bef2
24 changed files with 208 additions and 137 deletions

View File

@@ -253,7 +253,7 @@ constructor() : BasicGameState() {
// draw actors //
/////////////////
actorContainer.forEach { actor ->
if (actor is Visible && actor.inScreen() && actor !is Player) { // if visible and within screen
if (actor is Visible && actor.inScreen() && actor !is Player) { // if echo and within screen
actor.drawBody(gc, g)
}
}
@@ -281,7 +281,7 @@ constructor() : BasicGameState() {
// draw actor glows //
//////////////////////
actorContainer.forEach { actor ->
if (actor is Visible && actor.inScreen() && actor !is Player) { // if visible and within screen
if (actor is Visible && actor.inScreen() && actor !is Player) { // if echo and within screen
actor.drawGlow(gc, g)
}
}

View File

@@ -19,7 +19,8 @@ import org.newdawn.slick.state.StateBasedGame
*/
class StateVTTest : BasicGameState() {
val vt = SimpleTextTerminal(SimpleTextTerminal.IBM_GREEN, 80, 25, colour = false)
// HiRes: 100x62, LoRes: 80x25
val vt = SimpleTextTerminal(SimpleTextTerminal.ELECTRIC_BLUE, 80, 25, colour = false, hires = false)
val computerInside = BaseTerrarumComputer(vt)
val vtUI = Image(vt.displayW, vt.displayH)

View File

@@ -67,7 +67,7 @@ class ExportMap : ConsoleCommand {
override fun printUsage() {
val echo = Echo()
echo.execute("Usage: export <name>")
echo.execute("Exports current map into visible image.")
echo.execute("Exports current map into echo image.")
echo.execute("The image can be found at %adddata%/terrarum/Exports")
}

View File

@@ -14,7 +14,7 @@ import org.newdawn.slick.GameContainer
import org.newdawn.slick.Graphics
/**
* Base class for every actor that has physical (or visible) body. This includes furnishings, paintings, gadgets, etc.
* Base class for every actor that has physical (or echo) body. This includes furnishings, paintings, gadgets, etc.
*
* Created by minjaesong on 16-03-14.
*/
@@ -959,7 +959,7 @@ open class ActorWithBody : Actor(), Visible {
// warnings
if (sprite == null && isVisible)
println("[ActorWithBody] Caution: actor ${this.javaClass.simpleName} is visible but the sprite was not set.")
println("[ActorWithBody] Caution: actor ${this.javaClass.simpleName} is echo but the sprite was not set.")
else if (sprite != null && !isVisible)
println("[ActorWithBody] Caution: actor ${this.javaClass.simpleName} is invisible but the sprite was given.")

View File

@@ -670,7 +670,7 @@ object LightmapRenderer {
var blues = IntArray(MUL) // do.
val render_width = for_x_end - for_x_start
val render_height = for_y_end - for_y_start
// excluiding overscans; only reckon visible lights
// excluiding overscans; only reckon echo lights
for (y in overscan_open..render_height + overscan_open + 1) {
for (x in overscan_open..render_width + overscan_open + 1) {
reds[lightmap[y][x].rawR()] += 1

View File

@@ -19,8 +19,8 @@ _G.DLE = string.char(16) -- default error colour
_G.getMem = function() collectgarbage() return collectgarbage("count") * 1024 end
-- getTotalMem: implemented in Kotlin class
_G.getFreeMem = function() return getTotalMem() - getMem() end
_G.runscript = function(s, env)
local code, reason = load(s, env)
_G.runscript = function(s, source, ...)
local code, reason = load(s, source)
if _G.getFreeMem() <= 0 then
print("out of memory")
@@ -29,9 +29,9 @@ _G.runscript = function(s, env)
end
if code then
xpcall(code, eprint)
xpcall(code(...), eprint)
else
print(DLE..tostring(reason))
print(DLE..tostring(reason)) -- it catches syntax errors
end
end
_G.__scanMode__ = "UNINIT" -- part of inputstream implementation
@@ -59,16 +59,22 @@ if shell.status == shell.halt then
end
-- load Lua prompt, if bios is not found
if (#_COMPUTER.OEM > 0) then print(_COMPUTER.OEM) end
print("Rom basic "..DC2.._VERSION..DC4)
print("Copyright (C) 1994-2015 Lua.org, PUC-Rio")
print(DC2..tostring(math.floor(getFreeMem()/1024+0.5))..DC4.." Kbytes free")
print("To boot your system, run 'boot()'")
print("Ok")
while not native.isHalted() do
io.write(_COMPUTER.prompt)
local s = io.read()
runscript(s, "=stdin")
while not native.isHalted() do
io.write(_COMPUTER.prompt)
local s = io.read()
xpcall(
function() _G.runscript(s, "=stdin") end,
function(s) print(DLE..s) end -- it catches logical errors
)
end
end
native.closeInputString()
__haltsystemexplicit__()
return

View File

@@ -6,10 +6,10 @@
-- ALIASES --
-------------
fs.dofile = function(p)
fs.dofile = function(p, ...)
local f = fs.open(p, "r")
local s = f.readAll()
_G.runscript(s, "="..p)
_G.runscript(s, "="..p, ...)
end
_G.loadstring = _G.load
@@ -18,6 +18,15 @@ _G.print = term.print
--_G.dofile = function(f) fs.dofile(f) end
_G.boot = function() fs.dofile("/boot/efi") end
fs.fetchText = function(p)
local file = fs.open(p, "r")
local text = file.readAll()
file.close()
return text
end
-----------------------------------------
-- INPUTSTREAM AND SCANNER (java-like) --
@@ -38,9 +47,9 @@ override fun keyPressed(key: Int, c: Char) {
...it basically says to close the input if RETURN is hit,
and THIS exact part will close the input for this function.
]]
_G.__scanForLine__ = function()
_G.__scanforline__ = function(echo) -- pass '1' to not echo; pass nothing to echo
native.closeInputString()
native.openInput()
native.openInput(echo or 0)
_G.__scanMode__ = "line"
local s
repeat -- we can do this ONLY IF lua execution process is SEPARATE THREAD
@@ -51,9 +60,9 @@ _G.__scanForLine__ = function()
end
-- use Keys API to identify the keycode
_G.__scanForChar__ = function()
_G.__scanforchar__ = function(echo) -- pass '1' to not echo; pass nothing to echo
native.closeInputString()
native.openInput()
native.openInput(echo or 0)
_G.__scanMode__ = "a_key"
local key
repeat -- we can do this ONLY IF lua execution process is SEPARATE THREAD
@@ -63,7 +72,7 @@ _G.__scanForChar__ = function()
return key
end
io.read = _G.__scanForLine__
io.read = _G.__scanforline__
-----------------

View File

@@ -38,6 +38,7 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
globals["fs"]["open"] = OpenFile(computer) //CC compliant
globals["fs"]["parent"] = GetParentDir(computer)
// fs.dofile defined in ROMLIB
// fs.fetchText defined in ROMLIB
}
companion object {
@@ -300,7 +301,7 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
}
catch (e: FileNotFoundException) {
e.printStackTrace()
throw LuaError("$path: No such file.")
throw LuaError("$path: no such file.")
}
}
"rb" -> {
@@ -312,7 +313,7 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
}
catch (e: FileNotFoundException) {
e.printStackTrace()
throw LuaError("$path: No such file.")
throw LuaError("$path: no such file.")
}
}
"w", "a" -> {
@@ -325,7 +326,7 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
}
catch (e: FileNotFoundException) {
e.printStackTrace()
throw LuaError("$path: Is a directory.")
throw LuaError("$path: is a directory.")
}
}
"wb", "ab" -> {
@@ -338,7 +339,7 @@ internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
}
catch (e: FileNotFoundException) {
e.printStackTrace()
throw LuaError("$path: Is a directory.")
throw LuaError("$path: is a directory.")
}
}
}

View File

@@ -1,6 +1,7 @@
package net.torvald.terrarum.virtualcomputer.luaapi
import li.cil.repack.org.luaj.vm2.Globals
import li.cil.repack.org.luaj.vm2.LuaFunction
import li.cil.repack.org.luaj.vm2.LuaTable
import li.cil.repack.org.luaj.vm2.LuaValue
import li.cil.repack.org.luaj.vm2.lib.OneArgFunction
@@ -61,9 +62,14 @@ internal class HostAccessProvider(globals: Globals, computer: BaseTerrarumComput
}
}
class NativeOpenInput(val term: Teletype) : ZeroArgFunction() {
class NativeOpenInput(val term: Teletype) : LuaFunction() {
override fun call(): LuaValue {
term.openInput()
term.openInput(true)
return LuaValue.NONE
}
override fun call(echo: LuaValue): LuaValue {
term.openInput(if (echo.checkint() == 1) false else true)
return LuaValue.NONE
}
}

View File

@@ -32,11 +32,15 @@ internal class Term(globals: Globals, term: Teletype) {
globals["term"]["resetColour"] = Term.ResetColour(term)
globals["term"]["clear"] = Term.Clear(term)
globals["term"]["clearLine"] = Term.ClearLine(term)
globals["term"]["setCursor"] = Term.SetCursor(term)
globals["term"]["getCursor"] = Term.GetCursorPos(term)
globals["term"]["getX"] = Term.GetCursorX(term)
globals["term"]["getY"] = Term.GetCursorY(term)
globals["term"]["setX"] = Term.SetCursorX(term)
globals["term"]["setY"] = Term.SetCursorY(term)
globals["term"]["blink"] = Term.SetCursorBlink(term)
globals["term"]["size"] = Term.GetSize(term)
globals["term"]["height"] = Term.GetHeight(term)
globals["term"]["isCol"] = Term.IsColour(term)
globals["term"]["setForeCol"] = Term.SetForeColour(term)
globals["term"]["setBackCol"] = Term.SetBackColour(term)
@@ -100,21 +104,21 @@ internal class Term(globals: Globals, term: Teletype) {
class EmitRaw(val term: Terminal) : ThreeArgFunction() {
override fun call(p0: LuaValue, x: LuaValue, y: LuaValue): LuaValue {
term.emitChar(p0.checkint(), x.checkint(), y.checkint())
term.emitChar(p0.checkint(), x.checkint() - 1, y.checkint() - 1)
return LuaValue.NONE
}
}
class Emit(val term: Terminal) : ThreeArgFunction() {
override fun call(p0: LuaValue, x: LuaValue, y: LuaValue): LuaValue {
term.emitChar(p0.checkint().toChar(), x.checkint(), y.checkint())
term.emitChar(p0.checkint().toChar(), x.checkint() - 1, y.checkint() - 1)
return LuaValue.NONE
}
}
class EmitString(val term: Terminal) : ThreeArgFunction() {
override fun call(p0: LuaValue, x: LuaValue, y: LuaValue): LuaValue {
term.emitString(p0.checkIBM437(), x.checkint(), y.checkint())
term.emitString(p0.checkIBM437(), x.checkint() - 1, y.checkint() - 1)
return LuaValue.NONE
}
}
@@ -140,14 +144,6 @@ internal class Term(globals: Globals, term: Teletype) {
}
}
/** term.setCursorPos(number x, number y), One-based */
class SetCursorPos(val term: Terminal) : TwoArgFunction() {
override fun call(x: LuaValue, y: LuaValue): LuaValue {
term.setCursor(x.checkint() - 1, y.checkint() - 1)
return LuaValue.NONE
}
}
/** term.setCursorPos(number x) */
class MoveCursor(val tty: Teletype) : OneArgFunction() {
override fun call(p0: LuaValue): LuaValue {
@@ -157,6 +153,13 @@ internal class Term(globals: Globals, term: Teletype) {
}
}
class SetCursor(val term: Terminal) : TwoArgFunction() {
override fun call(x: LuaValue, y: LuaValue): LuaValue {
term.setCursor(x.checkint() - 1, y.checkint() - 1)
return LuaValue.NONE
}
}
/** One-based */
class GetCursorPos(val term: Terminal) : VarArgFunction() {
override fun invoke(args: Varargs?): Varargs {
@@ -177,6 +180,20 @@ internal class Term(globals: Globals, term: Teletype) {
}
}
class SetCursorX(val term: Terminal) : OneArgFunction() {
override fun call(p0: LuaValue): LuaValue {
term.setCursor(p0.checkint() - 1, term.cursorY)
return LuaValue.NONE
}
}
class SetCursorY(val term: Terminal) : OneArgFunction() {
override fun call(p0: LuaValue): LuaValue {
term.setCursor(term.cursorX - 1, p0.checkint())
return LuaValue.NONE
}
}
/** term.setCursorBlink(boolean bool) */
class SetCursorBlink(val term: Terminal) : OneArgFunction() {
override fun call(p0: LuaValue): LuaValue {
@@ -198,6 +215,12 @@ internal class Term(globals: Globals, term: Teletype) {
}
}
class GetHeight(val terminal: Terminal) : ZeroArgFunction() {
override fun call(): LuaValue {
return LuaValue.valueOf(terminal.height)
}
}
class IsColour(val term: Terminal) : ZeroArgFunction() {
override fun call(): LuaValue {
return LuaValue.valueOf(term.coloursCount > 4)

View File

@@ -18,7 +18,8 @@ import java.nio.ByteBuffer
* Created by minjaesong on 16-09-07.
*/
open class SimpleTextTerminal(
phosphorColour: Color, override val width: Int, override val height: Int, colour: Boolean = false
phosphorColour: Color, override val width: Int, override val height: Int,
colour: Boolean = false, hires: Boolean = false
) : Terminal {
/**
* Terminals must support AT LEAST 4 colours.
@@ -73,14 +74,15 @@ open class SimpleTextTerminal(
val screenBuffer = AAFrame(width, height)
open protected val fontRef = "./assets/graphics/fonts/MDA.png"
open protected val fontRef = "./assets/graphics/fonts/${if (hires) "milky.png" else "MDA.png"}"
open protected val fontImg = Image(fontRef)
open protected val fontW = fontImg.width / 16
open protected val fontH = fontImg.height / 16
open protected val font = ColouredFastFont(this, fontRef, fontW, fontH)
override val displayW = fontW * width
override val displayH = fontH * height
private val borderSize = 20
override val displayW = fontW * width + 2 * borderSize
override val displayH = fontH * height + 2 * borderSize
var TABSIZE = 4
@@ -139,20 +141,27 @@ open class SimpleTextTerminal(
blendNormal()
// black background (this is mandatory)
g.color = Color.black
g.fillRect(0f, 0f, displayW.toFloat(), displayH.toFloat())
// screen buffer
for (y in 0..height - 1) {
for (x in 0..width - 1) {
val ch = screenBuffer.getChar(x, y)
// background
g.color = getColor(screenBuffer.getBackgroundColour(x, y))
g.fillRect(fontW * x.toFloat(), fontH * y.toFloat(), fontW.toFloat(), fontH.toFloat())
g.fillRect(fontW * x.toFloat() + borderSize, fontH * y.toFloat() + borderSize,
fontW.toFloat(), fontH.toFloat())
// foreground
if (ch.toInt() != 0 && ch.toInt() != 32) {
g.color = getColor(screenBuffer.getForegroundColour(x, y))
g.drawString(
Character.toString(ch),
fontW * x.toFloat(), fontH * y.toFloat())
fontW * x.toFloat() + borderSize, fontH * y.toFloat() + borderSize)
}
}
}
@@ -162,8 +171,8 @@ open class SimpleTextTerminal(
g.color = getColor(foreDefault)
if (cursorBlinkOn && cursorBlink)
g.fillRect(
fontW * cursorX.toFloat(),
fontH * cursorY.toFloat(),
fontW * cursorX.toFloat() + borderSize,
fontH * cursorY.toFloat() + borderSize,
fontW.toFloat(),
fontH.toFloat()
)
@@ -258,7 +267,7 @@ open class SimpleTextTerminal(
setCursor(x, y)
for (i in 0..s.length - 1) {
emitChar(s[i])
printChar(s[i])
wrap()
}
@@ -385,13 +394,15 @@ open class SimpleTextTerminal(
override var lastInputByte: Int = -1
var sb: StringBuilder = StringBuilder()
private var inputOpen = false
private var keyPressVisible = false
/**
* Technically, this is different from Java's InputStream
* @param echo if true, keypresses are echoed to the terminal.
*/
override fun openInput() {
override fun openInput(echo: Boolean) {
lastStreamInput = null
lastKeyPress = null
inputOpen = true
keyPressVisible = echo
if (DEBUG) println("[SimpleTextTerminal] openInput()")
}
@@ -411,7 +422,8 @@ open class SimpleTextTerminal(
lastStreamInput = sb.toString()
sb = StringBuilder()
if (DEBUG) println("[SimpleTextTerminal] closeInputString(), $lastStreamInput")
if (DEBUG)
println("[SimpleTextTerminal] closeInputString(), ${if (keyPressVisible) lastStreamInput else "<keypress hidden>"}")
return lastStreamInput!!
}
@@ -421,7 +433,7 @@ open class SimpleTextTerminal(
if (inputOpen) {
if (c == ASCII_CR)
printChar(ASCII_LF)
else
else if (keyPressVisible)
printChar(c)
if (!asciiControlInUse.contains(c)) sb.append(c)
else if (c == ASCII_DEL && sb.length > 0) sb.deleteCharAt(sb.length - 1)
@@ -437,7 +449,7 @@ open class SimpleTextTerminal(
val AMBER = Color(255, 183, 0) // P3, 602 nm
val IBM_GREEN = Color(74, 255, 0) // P39, 525 nm
val WHITE = Color(228, 234, 255) // P4, 7 500 K
val ELECTRIC_BLUE = Color(0, 239, 255) // imaginary, 486 nm
val ELECTRIC_BLUE = Color(0, 226, 255) // imaginary, 483 nm
val RED = Color(250, 0, 0) // <= 645 nm
val ASCII_NUL = 0.toChar()

View File

@@ -34,7 +34,10 @@ interface Teletype {
fun newLine()
fun scroll(amount: Int = 1)
fun openInput()
/**
* @param echo if true, keypresses are echoed to the terminal.
*/
fun openInput(echo: Boolean = true)
fun closeInputKey(keyFromUI: Int): Int
fun closeInputString(): String

View File

@@ -132,9 +132,9 @@ class TeletypeTerminal : Teletype {
val DEBUG = true
/**
* Technically, this is different from Java's InputStream
* @param echo if true, keypresses are echoed to the terminal.
*/
override fun openInput() {
override fun openInput(echo: Boolean) {
lastStreamInput = null
lastKeyPress = null
inputOpen = true