using Kotlin for scripting

This commit is contained in:
minjaesong
2020-04-17 23:45:48 +09:00
parent 00ef1a6a4a
commit 280b4148d9
24 changed files with 206 additions and 76 deletions

View File

@@ -0,0 +1,26 @@
<component name="libraryTable">
<library name="org.jetbrains.kotlin:kotlin-scripting-jsr223:1.3.71" type="repository">
<properties maven-id="org.jetbrains.kotlin:kotlin-scripting-jsr223:1.3.71" />
<CLASSES>
<root url="jar://$PROJECT_DIR$/lib/kotlin-scripting-jsr223-1.3.71.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/kotlin-script-runtime-1.3.71.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/kotlin-stdlib-1.3.71.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/kotlin-stdlib-common-1.3.71.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/annotations-13.0.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/kotlin-scripting-common-1.3.71.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/kotlinx-coroutines-core-1.2.1.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/kotlin-scripting-jvm-1.3.71.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/kotlin-scripting-jvm-host-1.3.71.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/trove4j-1.0.20181211.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/kotlin-scripting-compiler-1.3.71.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/kotlin-scripting-js-1.3.71.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/kotlin-util-klib-1.3.71.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/kotlin-util-io-1.3.71.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/kotlin-scripting-compiler-impl-1.3.71.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/kotlin-compiler-1.3.71.jar!/" />
<root url="jar://$PROJECT_DIR$/lib/kotlin-reflect-1.3.71.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

BIN
lib/annotations-13.0.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -6,7 +6,6 @@ import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration
import com.badlogic.gdx.graphics.OrthographicCamera import com.badlogic.gdx.graphics.OrthographicCamera
import com.badlogic.gdx.graphics.g2d.SpriteBatch import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.tsvm.peripheral.GraphicsAdapter import net.torvald.tsvm.peripheral.GraphicsAdapter
import kotlin.math.roundToInt
class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter() { class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter() {
@@ -43,8 +42,8 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter()
//vmRunner = VMRunnerFactory(vm, "lua") //vmRunner = VMRunnerFactory(vm, "lua")
//vmRunner.executeCommand(gpuTestPalette) //vmRunner.executeCommand(gpuTestPalette)
// TEST KTS PRG // TEST KTS PRG
vmRunner = VMRunnerFactory(vm, "js") vmRunner = VMRunnerFactory(vm, "kts")
vmRunner.executeCommand(gpuTestPaletteJs) vmRunner.executeCommand(gpuTestPaletteKt)
} }
private var updateAkku = 0.0 private var updateAkku = 0.0
@@ -86,35 +85,54 @@ class VMGUI(val appConfig: LwjglApplicationConfiguration) : ApplicationAdapter()
fun poke(addr: Long, value: Byte) = vm.poke(addr, value) fun poke(addr: Long, value: Byte) = vm.poke(addr, value)
private fun paintTestPalette() { private fun paintTestPalette() {
val peripheralSlot = vm.findPeribyType(VM.PERITYPE_GRAPHICS)!! }
val hwoff = VM.HW_RESERVE_SIZE * peripheralSlot
for (y in 0 until 360) { private val gpuTestPaletteKt = """
for (x in 0 until GraphicsAdapter.WIDTH) { val w = 560
val palnum = 20 * (y / 30) + (x / (GraphicsAdapter.WIDTH / 20)) val h = 448
vm.poke(-(y.toLong() * GraphicsAdapter.WIDTH + x + 1) - hwoff, palnum.toByte()) val hwoff = 1048576
}
}
for (y in 360 until GraphicsAdapter.HEIGHT) { fun inthash(x: Int): Int {
for (x in 0 until GraphicsAdapter.WIDTH) { var x = (x.shr(16) xor x) * 0x45d9f3b
val palnum = 240 + (x / 35) x = (x.shr(16) xor x) * 0x45d9f3b
vm.poke(-(y.toLong() * GraphicsAdapter.WIDTH + x + 1) - hwoff, palnum.toByte()) x = (x.shr(16) xor x)
} return x
} }
//vm.poke(-262143L - hwoff, Math.random().times(255.0).toByte()) var rng = (Math.floor(Math.random() * 2147483647) + 1).toInt()
//vm.poke(-262144L - hwoff, Math.random().times(255.0).toByte())
for (k in 0 until 2240) { bindings.forEach {
// text foreground println(it)
vm.poke(-(254912 + k + 1) - hwoff, -2) // white }
// text background
vm.poke(-(254912 + 2240 + k + 1) - hwoff, -1) // transparent println(zzz)
// texts
vm.poke(-(254912 + 2240*2 + k + 1) - hwoff, Math.random().times(255).roundToInt().toByte()) while (true) {
val tstart: Long = System.nanoTime()
for (y1 in 0..359) {
for (x1 in 0 until w) {
val palnum = 20 * (y1 / 30) + (x1 / 28)
vm.poke(-(y1 * w + x1 + 1L) - hwoff, inthash(palnum + rng).toByte())
} }
} }
for (y2 in 360 until h) {
for (x2 in 0 until w) {
val palnum = 240 + x2 / 35
vm.poke(-(y2 * w + x2 + 1L) - hwoff, palnum.toByte())
}
}
for (k in 0..2239) {
vm.poke(-(254912L + k + 1) - hwoff, -2) // white
vm.poke(-(254912L + 2240 + k + 1) - hwoff, -1) // transparent
vm.poke(-(254912L + 2240 * 2 + k + 1) - hwoff, Math.round(Math.random() * 255).toByte())
}
rng = inthash(rng)
val tend: Long = System.nanoTime()
println("Apparent FPS: " + 1000000000.0 / (tend - tstart))
}
""".trimIndent()
private val gpuTestPalette = """ private val gpuTestPalette = """
local vm = require("rawmem") local vm = require("rawmem")
local bit = require("bit32") local bit = require("bit32")
@@ -132,7 +150,7 @@ end
local rng = math.floor(math.random() * 2147483647) local rng = math.floor(math.random() * 2147483647)
while true do while true do
local tstart = os.clock() local tstart = vm.nanotime()
for y = 0, 359 do for y = 0, 359 do
for x = 0, w - 1 do for x = 0, w - 1 do
@@ -156,43 +174,12 @@ while true do
rng = inthash(rng) rng = inthash(rng)
local tend = os.clock() local tend = vm.nanotime()
print("Apparent FPS: "..tostring(1.0 / (tend - tstart))) print("Apparent FPS: "..tostring(1000000000.0 / (tend - tstart)))
end end
""".trimIndent() """.trimIndent()
private val gpuTestPaletteKt = """
import kotlin.math.roundToInt
local w = 560
local h = 448
val hwoff = 1048576
while (true) {
for (y in 0 until 360) {
for (x in 0 until w) {
val palnum = 20 * (y / 30) + (x / 28)
poke(-(y.toLong() * w + x + 1) - hwoff, palnum.toByte())
}
}
for (y in 360 until h) {
for (x in 0 until w) {
val palnum = 240 + (x / 35)
poke(-(y.toLong() * w + x + 1) - hwoff, palnum.toByte())
}
}
for (k in 0 until 2240) {
poke(-(254912 + k + 1) - hwoff, -2) // white
poke(-(254912 + 2240 + k + 1) - hwoff, -1) // transparent
poke(-(254912 + 2240*2 + k + 1) - hwoff, Math.random().times(255).roundToInt().toByte())
}
}
""".trimIndent()
private val gpuTestPaletteJs = """ private val gpuTestPaletteJs = """
var w = 560 var w = 560
var h = 448 var h = 448
@@ -208,7 +195,7 @@ function inthash(x) {
return x return x
} }
var rng = Math.floor(Math.random() * 2147483647) var rng = Math.floor(Math.random() * 2147483647) + 1
while (true) { while (true) {
@@ -243,6 +230,101 @@ while (true) {
""".trimIndent() """.trimIndent()
private val gpuTestPaletteJava = """
int w = 560;
int h = 448;
int hwoff = 1048576;
int inthash(double x) {
return inthash((int) x);
}
int inthash(int x) {
x = ((x >> 16) ^ x) * 0x45d9f3b;
x = ((x >> 16) ^ x) * 0x45d9f3b;
x = (x >> 16) ^ x;
return x;
}
int rng = Math.floor(Math.random() * 2147483647) + 1;
while (true) {
long tstart = nanotime.invoke();
for (int y1 = 0; y1 < 360; y1++) {
for (int x1 = 0; x1 < w; x1++) {
int palnum = 20 * (y1 / 30) + (x1 / 28);
poke.invoke(-(y1 * w + x1 + 1) - hwoff, inthash(palnum + rng));
}
}
for (int y2 = 360; y2 < h; y2++) {
for (int x2 = 0; x2 < w; x2++) {
int palnum = 240 + x2 / 35;
poke.invoke(-(y2 * w + x2 + 1) - hwoff, palnum);
}
}
for (int k = 0; k < 2240; k++) {
poke.invoke(-(254912 + k + 1) - hwoff, -2); // white
poke.invoke(-(254912 + 2240 + k + 1) - hwoff, -1); // transparent
poke.invoke(-(254912 + 2240*2 + k + 1) - hwoff, Math.round(Math.random() * 255));
}
rng = inthash(rng);
long tend = nanotime.invoke();
System.out.println("Apparent FPS: " + (1000000000.0 / (tend - tstart)));
}
""".trimIndent()
private val gpuTestPalettePy = """
import math
import random
w = 560
h = 448
hwoff = 1048576
def inthash(x):
x = ((x >> 16) ^ x) * 0x45d9f3b
x = ((x >> 16) ^ x) * 0x45d9f3b
x = (x >> 16) ^ x
return x
rng = random.randint(1, 2147483647)
while True:
tstart = nanotime.invoke()
for y1 in range(0, 360):
for x1 in range(0, w):
palnum = 20 * int(y1 / 30) + int(x1 / 28)
poke.invoke(-(y1 * w + x1 + 1) - hwoff, inthash(palnum + rng))
for y2 in range(360, h):
for x2 in range(0, w):
palnum = 240 + int(x2 / 35)
poke.invoke(-(y2 * w + x2 + 1) - hwoff, palnum)
for k in range(0, 2240):
poke.invoke(-(254912 + k + 1) - hwoff, -2)
poke.invoke(-(254912 + 2240 + k + 1) - hwoff, -1)
poke.invoke(-(254912 + 2240*2 + k + 1) - hwoff, random.randint(0, 255))
rng = inthash(rng)
tend = nanotime.invoke()
print("Apparent FPS: " + str(1000000000.0 / (tend - tstart)))
""".trimIndent()
private fun renderGame(delta: Float) { private fun renderGame(delta: Float) {

View File

@@ -1,6 +1,9 @@
package net.torvald.tsvm package net.torvald.tsvm
import net.torvald.tsvm.firmware.Firmware import net.torvald.tsvm.firmware.Firmware
import org.luaj.vm2.LuaTable
import org.luaj.vm2.LuaValue
import org.luaj.vm2.lib.ZeroArgFunction
import org.luaj.vm2.lib.jse.JsePlatform import org.luaj.vm2.lib.jse.JsePlatform
class VMLuaAdapter(val vm: VM) { class VMLuaAdapter(val vm: VM) {

View File

@@ -1,8 +1,10 @@
package net.torvald.tsvm package net.torvald.tsvm
import javax.script.Compilable
import javax.script.ScriptContext import javax.script.ScriptContext
import javax.script.ScriptEngineManager import javax.script.ScriptEngineManager
import javax.script.SimpleScriptContext import javax.script.SimpleScriptContext
import kotlin.test.assertNotNull
abstract class VMRunner(val extension: String) { abstract class VMRunner(val extension: String) {
@@ -13,7 +15,17 @@ abstract class VMRunner(val extension: String) {
object VMRunnerFactory { object VMRunnerFactory {
private var firstTime = true
operator fun invoke(vm: VM, extension: String): VMRunner { operator fun invoke(vm: VM, extension: String): VMRunner {
if (firstTime) {
firstTime = false
ScriptEngineManager().engineFactories.forEach {
println("[VMRunnerFactory] ext: ${it.extensions}, name: ${it.engineName}")
}
}
return when (extension) { return when (extension) {
"lua" -> { "lua" -> {
object : VMRunner(extension) { object : VMRunner(extension) {
@@ -28,40 +40,34 @@ object VMRunnerFactory {
} }
} }
} }
"kt", "kts" -> { else -> {
object : VMRunner(extension) { object : VMRunner(extension) {
private val engine = ScriptEngineManager().getEngineByExtension(extension)
init { init {
TODO() assertNotNull(engine, "Script engine for extension $extension not found")
} }
override fun executeCommand(command: String) {
TODO()
}
}
}
"js" -> {
object : VMRunner(extension) {
private val engine = ScriptEngineManager().getEngineByExtension("js")!!
private val context = SimpleScriptContext() private val context = SimpleScriptContext()
private val bind = context.getBindings(ScriptContext.ENGINE_SCOPE) private val bind = context.getBindings(ScriptContext.ENGINE_SCOPE)
init { init {
engine.eval("true") as Boolean // init the engine here bind.put("zzz", 42)
bind.put("vm", vm) // TODO use delegator class to access peripheral (do not expose VM itself)
bind.put("poke", { a: Long, b: Byte -> vm.poke(a, b) }) bind.put("poke", { a: Long, b: Byte -> vm.poke(a, b) }) // kts: lambda does not work...
bind.put("nanotime", { System.nanoTime() }) bind.put("nanotime", { System.nanoTime() })
} }
override fun executeCommand(command: String) { override fun executeCommand(command: String) {
thread = Thread { thread = Thread {
//(engine as Compilable).compile(command).eval(context) // compiling does not work with bindings in kts
engine.eval(command, context) engine.eval(command, context)
} }
thread.start() thread.start()
} }
} }
} }
else -> throw UnsupportedOperationException("Unsupported script extension: $extension") //else -> throw UnsupportedOperationException("Unsupported script extension: $extension")
} }
} }
} }

View File

@@ -6,6 +6,7 @@ import org.luaj.vm2.LuaTable
import org.luaj.vm2.LuaValue import org.luaj.vm2.LuaValue
import org.luaj.vm2.lib.OneArgFunction import org.luaj.vm2.lib.OneArgFunction
import org.luaj.vm2.lib.TwoArgFunction import org.luaj.vm2.lib.TwoArgFunction
import org.luaj.vm2.lib.ZeroArgFunction
internal class Firmware(val vm: VM) : TwoArgFunction() { internal class Firmware(val vm: VM) : TwoArgFunction() {
@@ -52,6 +53,11 @@ internal class Firmware(val vm: VM) : TwoArgFunction() {
val t = LuaTable() val t = LuaTable()
t["poke"] = Poke(vm) t["poke"] = Poke(vm)
t["peek"] = Peek(vm) t["peek"] = Peek(vm)
t["nanotime"] = object : ZeroArgFunction() {
override fun call(): LuaValue {
return LuaValue.valueOf(System.nanoTime().toDouble())
}
}
if (!env["package"].isnil()) env["package"]["loaded"]["rawmem"] = t if (!env["package"].isnil()) env["package"]["loaded"]["rawmem"] = t
return t return t
} }

View File

@@ -8,5 +8,6 @@
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="KotlinJavaRuntime" level="project" /> <orderEntry type="library" name="KotlinJavaRuntime" level="project" />
<orderEntry type="library" name="org.jetbrains.kotlin:kotlin-scripting-jsr223:1.3.71" level="project" />
</component> </component>
</module> </module>