package mtmc.emulator import mtmc.os.fs.Console import mtmc.os.fs.System import mtmc.os.shell.Shell import mtmc.tokenizer.MTMCScanner import mtmc.tokenizer.MTMCToken class MTMCConsole(private val computer: MonTanaMiniComputer) { var mode: Mode = Mode.NON_INTERACTIVE var sysConsole: Console? = null // non-interactive data private val output = StringBuilder() private var shortValueSet = false private var shortValue: Short = 0 private var stringValue: String? = null // TODO invert so shell is driving and console is just IO fun start() { mode = Mode.INTERACTIVE sysConsole = System.console Shell.printShellWelcome(computer) while (true) { val cmd = sysConsole!!.readLine("mtmc > ") computer.oS.processCommand(cmd) } } fun println(x: String) { print(x) print("\n") } fun print(x: String) { output.append(x) if (mode == Mode.INTERACTIVE) { kotlin.io.print(x) } else { if (x.contains("\n")) { computer.notifyOfConsoleUpdate() } else { computer.notifyOfConsolePrinting() } } } fun readChar(): Char { if (mode == Mode.INTERACTIVE) { val tokens = MTMCScanner(sysConsole!!.readLine(), "#").tokenize() val token = tokens.first() check(token.type === MTMCToken.TokenType.CHAR) return token.charValue() } else { this.shortValueSet = false return Char(this.shortValue.toUShort()) } } fun readInt(): Short { if (mode == Mode.INTERACTIVE) { return sysConsole!!.readLine().toShort() } else { this.shortValueSet = false return shortValue } } fun hasShortValue(): Boolean { return (mode == Mode.INTERACTIVE || shortValueSet) } fun setShortValue(shortValue: Short) { this.shortValue = shortValue this.shortValueSet = true } fun setCharValue(charValue: Char) { this.shortValue = charValue.code.toShort() this.shortValueSet = true } fun getOutput(): String { return output.toString() } fun consumeLines(): String { val index = output.lastIndexOf("\n") val text = if (index >= 0) output.substring(0, index + 1) else "" if (index >= 0) { output.removeRange(0, index + 1) } return text } fun writeInt(value: Short) { print(value.toString() + "") } fun setStringValue(stringValue: String?) { this.stringValue = stringValue } fun readString(): String? { if (mode == Mode.INTERACTIVE) { return sysConsole!!.readLine() } else { val stringValue = this.stringValue this.stringValue = null return stringValue } } fun hasReadString(): Boolean { return (mode == Mode.INTERACTIVE || stringValue != null) } fun setReadString(stringValue: String?) { this.stringValue = stringValue } fun resetOutput() { output.removeRange(0, output.length) } enum class Mode { NON_INTERACTIVE, INTERACTIVE, } }