separate instructionset type

This commit is contained in:
2018-11-27 03:12:18 -05:00
parent bda23d7e9d
commit fcb017e6df
19 changed files with 263 additions and 174 deletions

View File

@@ -1,125 +1,32 @@
package befide.befunge.b93
import befide.befunge.b93.state.*
import befide.befunge.core.*
import befide.befunge.core.util.chooseOne
import befide.befunge.core.events.IpChange
import befide.befunge.core.events.StackChange
import befide.befunge.core.util.readAll
import befide.befunge.events.Event
import befide.befunge.core.util.Event
import java.io.PipedReader
import java.io.PipedWriter
import java.util.*
class Interpreter93(stdinSrc: PipedWriter, stdoutDest: PipedReader)
: Interpreter<Vec2, LongData, PointerMode> {
: MutableInterpreter<Vec2, LongData, PointerMode>() {
override val ip = Pointer93()
override val funge = Funge93()
override val stack = Stack<LongData>()
override fun stackDefault() = LongData.ZERO
override val onIpChange = Event<IpChange<Vec2, PointerMode>>()
override val onStackChange = Event<StackChange<LongData>>()
override val stdin: PipedReader = PipedReader(stdinSrc)
override val stdout: PipedWriter = PipedWriter(stdoutDest)
private fun notifyIp(op: () -> Unit) {
val from = ip.copy()
op()
val to = ip.copy()
onIpChange(IpChange(from, to))
}
private fun move(dir: Vec2? = null) = notifyIp {
ip.pos = funge.next(ip.pos, dir ?: ip.delta)
}
private fun pop(): LongData {
val d = if (stack.empty()) LongData.ZERO else stack.pop()
onStackChange(StackChange(StackOp.Pop, d))
return d
}
private fun push(vararg data: LongData) {
for (d in data) {
stack.push(d)
onStackChange(StackChange(StackOp.Push, d))
}
}
private fun argPop(n: Int, op: (Array<LongData>) -> Unit) {
val args = (0 until n).map { pop() }.toTypedArray()
op(args)
}
private var mode
get() = ip.mode
set(mode) = notifyIp { ip.mode = mode }
private var delta
get() = ip.delta
set(delta) = notifyIp { ip.delta = delta }
override fun step() {
val instr = funge[ip.pos]
when (mode) {
PointerMode.Terminated -> return
PointerMode.String -> when (instr.char) {
null -> Unit
'"' -> mode = PointerMode.Normal
else -> push(instr)
}
PointerMode.Normal -> when (instr.char) {
null -> Unit
in "0123456789abcdef" -> push(LongData(instr.char.toString().toLong(16)))
'+' -> argPop(2) { (b, a) -> push(a + b) }
'-' -> argPop(2) { (b, a) -> push(a - b) }
'*' -> argPop(2) { (b, a) -> push(a * b) }
'/' -> argPop(2) { (b, a) -> push(a / b) }
'%' -> argPop(2) { (b, a) -> push(a mod b) }
'!' -> argPop(1) { (n) -> push(LongData(if (n.data == 0L) 1L else 0L)) }
'`' -> argPop(2) { (b, a) -> push(LongData(if (a.data > b.data) 1L else 0L)) }
'>' -> delta = Vec2.RIGHT
'<' -> delta = Vec2.LEFT
'v' -> delta = Vec2.DOWN
'^' -> delta = Vec2.UP
'?' -> delta = Vec2.DIRS.chooseOne()
'#' -> move()
'_' -> argPop(1) { (n) -> delta = if (n.data == 0L) Vec2.RIGHT else Vec2.LEFT }
'|' -> argPop(1) { (n) -> delta = if (n.data == 0L) Vec2.DOWN else Vec2.UP }
'"' -> mode = PointerMode.String
':' -> argPop(1) { (n) -> push(n, n) }
'\\' -> argPop(2) { (b, a) -> push(b, a) }
'$' -> pop()
'.' -> argPop(1) { (n) -> stdout.write("${n.data} ") }
',' -> argPop(1) { (ch) -> stdout.write(ch.data.toChar().toString()) }
'p' -> argPop(3) { (y, x, n) -> funge[Vec2(x.data.toInt(), y.data.toInt())] = n }
'g' -> argPop(2) { (y, x) -> push(funge[Vec2(x.data.toInt(), y.data.toInt())]) }
'~' -> push(LongData(stdin.read().toLong()))
'&' -> {
val chars = generateSequence {
stdin.read().takeIf { it.toChar().isDigit() }
}
val long = chars.joinToString("").toLong()
push(LongData(long))
}
'@' -> mode = PointerMode.Terminated
}
}
move()
}
override val instructionSet = Befunge93Instructions()
override fun reset() {
stdin.readAll()
@@ -133,9 +40,9 @@ fun main(args: Array<String>) {
val int = Interpreter93(stdinSrc, stdoutDest)
// int.onIpChange += {
// println(it.to.pos)
// }
int.onIpChange += {
println(it.to.pos)
}
int.funge.src = """2>:3g" "-!v\ g30 <
|!`"O":+1_:.:03p>03g+:"O"`|
@@ -144,7 +51,7 @@ fun main(args: Array<String>) {
while (int.ip.mode != PointerMode.Terminated) {
int.step()
print(stdoutDest.readAll())
}
print(stdoutDest.readAll())
}

View File

@@ -0,0 +1,67 @@
package befide.befunge.b93
import befide.befunge.b93.state.LongData
import befide.befunge.b93.state.PointerMode
import befide.befunge.b93.state.Vec2
import befide.befunge.core.InstructionSet
import befide.befunge.core.MutableInterpreter
import befide.befunge.core.util.chooseOne
class Befunge93Instructions : InstructionSet<Vec2, LongData, PointerMode> {
override fun MutableInterpreter<Vec2, LongData, PointerMode>.handle() {
when (mode) {
PointerMode.Terminated -> return
PointerMode.String -> when (instr.char) {
null -> Unit
'"' -> mode = PointerMode.Normal
else -> push(instr)
}
PointerMode.Normal -> when (instr.char) {
null -> Unit
in "0123456789abcdef" -> push(LongData(instr.char.toString().toLong(16)))
'+' -> pop(2).let { (b, a) -> push(a + b) }
'-' -> pop(2).let { (b, a) -> push(a - b) }
'*' -> pop(2).let { (b, a) -> push(a * b) }
'/' -> pop(2).let { (b, a) -> push(a / b) }
'%' -> pop(2).let { (b, a) -> push(a mod b) }
'!' -> pop(1).let { (n) -> push(LongData(if (n.data == 0L) 1L else 0L)) }
'`' -> pop(2).let { (b, a) -> push(LongData(if (a.data > b.data) 1L else 0L)) }
'>' -> delta = Vec2.RIGHT
'<' -> delta = Vec2.LEFT
'v' -> delta = Vec2.DOWN
'^' -> delta = Vec2.UP
'?' -> delta = Vec2.DIRS.chooseOne()
'#' -> move()
'_' -> pop().let { n -> delta = if (n.data == 0L) Vec2.RIGHT else Vec2.LEFT }
'|' -> pop().let { n -> delta = if (n.data == 0L) Vec2.DOWN else Vec2.UP }
'"' -> mode = PointerMode.String
':' -> pop().let { n -> push(n, n) }
'\\' -> pop(2).let { (b, a) -> push(b, a) }
'$' -> pop()
'.' -> pop().let { n -> stdout.write("${n.data} ") }
',' -> pop().let { ch -> stdout.write(ch.data.toChar().toString()) }
'p' -> pop(3).let { (y, x, n) -> funge[Vec2(x.data.toInt(), y.data.toInt())] = n }
'g' -> pop(2).let { (y, x) -> push(funge[Vec2(x.data.toInt(), y.data.toInt())]) }
'~' -> push(LongData(stdin.read().toLong()))
'&' -> {
val chars = generateSequence {
stdin.read().takeIf { it.toChar().isDigit() }
}
val long = chars.joinToString("").toLong()
push(LongData(long))
}
'@' -> mode = PointerMode.Terminated
}
}
}
}

View File

@@ -1,8 +1,8 @@
package befide.befunge.b93
package befide.befunge.b93.state
import befide.befunge.core.FungeChange
import befide.befunge.core.MutableFunge
import befide.befunge.events.Event
import befide.befunge.core.events.FungeChange
import befide.befunge.core.state.MutableFunge
import befide.befunge.core.util.Event
class Funge93
: MutableFunge<Vec2, LongData> {

View File

@@ -1,11 +1,10 @@
package befide.befunge.b93
package befide.befunge.b93.state
import befide.befunge.core.Data
import befide.befunge.core.state.Data
import befide.befunge.core.util.mod
data class LongData(val data: Long)
: Data {
companion object {
val SPACE = LongData(' ')
val ZERO = LongData(0)

View File

@@ -1,6 +1,7 @@
package befide.befunge.b93
package befide.befunge.b93.state
import befide.befunge.core.MutablePointer
import befide.befunge.core.state.MutablePointer
import befide.befunge.core.state.Pointer
enum class PointerMode {
Normal, String, Terminated
@@ -9,4 +10,7 @@ enum class PointerMode {
data class Pointer93(override var pos: Vec2 = Vec2.ZERO,
override var delta: Vec2 = Vec2.RIGHT,
override var mode: PointerMode = PointerMode.Normal)
: MutablePointer<Vec2, PointerMode>
: MutablePointer<Vec2, PointerMode> {
override fun copy(): Pointer<Vec2, PointerMode> = Pointer93(pos, delta, mode)
}

View File

@@ -1,4 +1,4 @@
package befide.befunge.b93
package befide.befunge.b93.state
import befide.befunge.core.util.mod

View File

@@ -0,0 +1,9 @@
package befide.befunge.core
import befide.befunge.core.state.Data
interface InstructionSet<V, D : Data, M : Enum<M>> {
fun MutableInterpreter<V, D, M>.handle()
fun step(inter: MutableInterpreter<V, D, M>) = inter.handle()
}

View File

@@ -1,69 +1,26 @@
package befide.befunge.core
import befide.befunge.events.Event
import befide.befunge.core.events.IpChange
import befide.befunge.core.events.StackChange
import befide.befunge.core.state.Data
import befide.befunge.core.state.Funge
import befide.befunge.core.state.Pointer
import befide.befunge.core.util.Event
import java.io.PipedReader
import java.io.PipedWriter
import java.util.*
interface Pointer<V, M : Enum<M>> {
val pos: V
val delta: V
val mode: M
}
interface MutablePointer<V, M : Enum<M>>
: Pointer<V, M> {
override var pos: V
override var delta: V
override var mode: M
}
interface Data {
val char: Char?
}
data class FungeChange<V, D : Data>
(val funge: Funge<V, D>,
val pos: V,
val from: D,
val to: D)
interface Funge<V, D : Data> {
val size: V
val data: List<List<D>>
val src: String
fun next(pos: V, delta: V): V
operator fun get(pos: V): D
val onChange: Event<FungeChange<V, D>>
}
interface MutableFunge<V, D : Data>
: Funge<V, D> {
override var data: List<List<D>>
override var src: String
operator fun set(pos: V, data: D)
}
data class IpChange<V, M : Enum<M>>
(val from: Pointer<V, M>, val to: Pointer<V, M>)
enum class StackOp { Push, Pop }
data class StackChange<D : Data>
(val op: StackOp, val data: D)
interface Interpreter<V, D : Data, M : Enum<M>> {
val ip: Pointer<V, M>
val funge: Funge<V, D>
val stack: List<D>
fun stackDefault(): D
val mode: M get() = ip.mode
val delta: V get() = ip.delta
val pos: V get() = ip.pos
val instr: D get() = funge[ip.pos]
val onIpChange: Event<IpChange<V, M>>
val onStackChange: Event<StackChange<D>>
@@ -72,4 +29,5 @@ interface Interpreter<V, D : Data, M : Enum<M>> {
fun step()
fun reset()
}
}

View File

@@ -0,0 +1,66 @@
package befide.befunge.core
import befide.befunge.core.events.IpChange
import befide.befunge.core.events.StackChange
import befide.befunge.core.events.StackOp
import befide.befunge.core.state.Data
import befide.befunge.core.state.MutableFunge
import befide.befunge.core.state.MutablePointer
import java.util.*
abstract class MutableInterpreter<V, D : Data, M : Enum<M>>
: Interpreter<V, D, M> {
abstract override val ip: MutablePointer<V, M>
abstract override val funge: MutableFunge<V, D>
abstract override val stack: Stack<D>
abstract val instructionSet: InstructionSet<V, D, M>
override fun step() {
instructionSet.step(this)
move()
}
fun notifyIp(op: () -> Unit) {
val from = ip.copy()
op()
val to = ip.copy()
onIpChange(IpChange(from, to))
}
fun notifyStack(op: StackOp, block: () -> D): D {
val res = block()
onStackChange(StackChange(op, res))
return res
}
override var mode: M
get() = ip.mode
set(mode) = notifyIp { ip.mode = mode }
override var delta: V
get() = ip.delta
set(delta) = notifyIp { ip.delta = delta }
override var pos: V
get() = ip.pos
set(pos) = notifyIp { ip.pos = pos }
fun move(delta: V? = null) {
pos = funge.next(pos, delta ?: this.delta)
}
fun pop(): D = notifyStack(StackOp.Pop) {
if (stack.empty()) stackDefault() else stack.pop()
}
fun pop(n: Int): List<D> {
return (0 until n).map { notifyStack(StackOp.Pop) { stack.pop() } }
}
fun push(vararg data: D) {
for (datum in data) {
notifyStack(StackOp.Push) { stack.push(datum) }
}
}
}

View File

@@ -0,0 +1,10 @@
package befide.befunge.core.events
import befide.befunge.core.state.Data
import befide.befunge.core.state.Funge
data class FungeChange<V, D : Data>
(val funge: Funge<V, D>,
val pos: V,
val from: D,
val to: D)

View File

@@ -0,0 +1,6 @@
package befide.befunge.core.events
import befide.befunge.core.state.Pointer
data class IpChange<V, M : Enum<M>>
(val from: Pointer<V, M>, val to: Pointer<V, M>)

View File

@@ -0,0 +1,8 @@
package befide.befunge.core.events
import befide.befunge.core.state.Data
enum class StackOp { Push, Pop }
data class StackChange<D : Data>
(val op: StackOp, val data: D)

View File

@@ -0,0 +1,5 @@
package befide.befunge.core.state
interface Data {
val char: Char?
}

View File

@@ -0,0 +1,17 @@
package befide.befunge.core.state
import befide.befunge.core.events.FungeChange
import befide.befunge.core.util.Event
interface Funge<V, D : Data> {
val size: V
val data: List<List<D>>
val src: String
fun next(pos: V, delta: V): V
operator fun get(pos: V): D
val onChange: Event<FungeChange<V, D>>
}

View File

@@ -0,0 +1,10 @@
package befide.befunge.core.state
interface MutableFunge<V, D : Data>
: Funge<V, D> {
override var data: List<List<D>>
override var src: String
operator fun set(pos: V, data: D)
}

View File

@@ -0,0 +1,9 @@
package befide.befunge.core.state
interface MutablePointer<V, M : Enum<M>>
: Pointer<V, M> {
override var pos: V
override var delta: V
override var mode: M
}

View File

@@ -0,0 +1,9 @@
package befide.befunge.core.state
interface Pointer<V, M : Enum<M>> {
val pos: V
val delta: V
val mode: M
fun copy(): Pointer<V, M>
}

View File

@@ -1,4 +1,4 @@
package befide.befunge.events
package befide.befunge.core.util
import java.util.function.Consumer

View File

@@ -1,6 +1,7 @@
package befide.befunge.core.util
import java.io.PipedReader
import java.util.*
import kotlin.random.Random
@@ -21,3 +22,7 @@ fun <T> List<T>.chooseOne(): T = this[Random.nextInt(size)]
fun PipedReader.readAll(): String = generateSequence {
if (ready()) read().toChar() else null
}.joinToString("")
inline fun <reified T> Stack<T>.pop(n: Int): List<T> {
return (0 until n).map { pop() }
}