Больше тестов Lua
This commit is contained in:
parent
da6e5aa694
commit
7a8e366c46
@ -17,6 +17,6 @@ public final class LuaJNI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static {
|
static {
|
||||||
//System.load(new File("lua_glue.dll").getAbsolutePath());
|
System.load(new File("lua_glue.dll").getAbsolutePath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ import javax.annotation.Nullable;
|
|||||||
public interface LuaJNR {
|
public interface LuaJNR {
|
||||||
public int lua_pcallk(@NotNull Pointer luaState, int numArgs, int numResults, int msgh, @LongLong long ctx, @LongLong long callback);
|
public int lua_pcallk(@NotNull Pointer luaState, int numArgs, int numResults, int msgh, @LongLong long ctx, @LongLong long callback);
|
||||||
public int lua_callk(@NotNull Pointer luaState, int numArgs, int numResults, @LongLong long ctx, @LongLong long callback);
|
public int lua_callk(@NotNull Pointer luaState, int numArgs, int numResults, @LongLong long ctx, @LongLong long callback);
|
||||||
public long lua_atpanic(@NotNull Pointer luaState, long fn);
|
public long lua_atpanic(@NotNull Pointer luaState, @LongLong long fn);
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public Pointer luaL_newstate();
|
public Pointer luaL_newstate();
|
||||||
@ -75,7 +75,7 @@ public interface LuaJNR {
|
|||||||
public void lua_pushstring(@NotNull Pointer luaState, @NotNull String value);
|
public void lua_pushstring(@NotNull Pointer luaState, @NotNull String value);
|
||||||
|
|
||||||
// двоичная строка
|
// двоичная строка
|
||||||
public long lua_pushlstring(@NotNull Pointer luaState, @NotNull Pointer stringPointer, @LongLong long length);
|
public long lua_pushlstring(@NotNull Pointer luaState, @LongLong long stringPointer, @LongLong long length);
|
||||||
|
|
||||||
// Загрузка Lua значений на стек
|
// Загрузка Lua значений на стек
|
||||||
public int lua_getglobal(@NotNull Pointer luaState, @NotNull String name);
|
public int lua_getglobal(@NotNull Pointer luaState, @NotNull String name);
|
||||||
|
@ -31,37 +31,18 @@ fun main() {
|
|||||||
if (true) {
|
if (true) {
|
||||||
val lua = LuaState()
|
val lua = LuaState()
|
||||||
|
|
||||||
Thread.sleep(5_000L)
|
Thread.sleep(4_000L)
|
||||||
|
|
||||||
lua.load(File("test.lua").readText())
|
lua.load(File("test.lua").readText())
|
||||||
//lua.load("print('hello world!', ...)")
|
lua.call()
|
||||||
|
|
||||||
//lua.push(GsonBuilder().create().fromJson(File("playerdata.json").reader(), JsonElement::class.java))
|
|
||||||
|
|
||||||
/*lua.push(JsonObject().also {
|
|
||||||
it.add("Сыр", JsonPrimitive("Гиршок"))
|
|
||||||
it.add("сас", JsonPrimitive("сос"))
|
|
||||||
it.add("сыс", JsonPrimitive(4))
|
|
||||||
it.add("ы", JsonNull.INSTANCE)
|
|
||||||
it.add("s", JsonObject().also {
|
|
||||||
it.add("Вложенный", JsonPrimitive("Объект!"))
|
|
||||||
})
|
|
||||||
})*/
|
|
||||||
|
|
||||||
lua.pcall()
|
|
||||||
|
|
||||||
lua.loadGlobal("printTable")
|
lua.loadGlobal("printTable")
|
||||||
lua.push(GsonBuilder().create().fromJson(File("playerdata.json").reader(), JsonElement::class.java))
|
lua.push(GsonBuilder().create().fromJson(File("playerdata.json").reader(), JsonElement::class.java))
|
||||||
lua.pcall(1)
|
lua.call(1)
|
||||||
|
|
||||||
/*for (t in 1 .. 100) {
|
lua.loadGlobal("test")
|
||||||
lua.loadGlobal("test")
|
lua.push("s".repeat(10))
|
||||||
|
lua.call(1)
|
||||||
for (i in 0 until t)
|
|
||||||
lua.push("sass".repeat(t))
|
|
||||||
|
|
||||||
lua.pcall(t)
|
|
||||||
}*/
|
|
||||||
|
|
||||||
Thread.sleep(4_000L)
|
Thread.sleep(4_000L)
|
||||||
|
|
||||||
|
@ -9,18 +9,19 @@ import com.kenai.jffi.CallContext
|
|||||||
import com.kenai.jffi.CallingConvention
|
import com.kenai.jffi.CallingConvention
|
||||||
import com.kenai.jffi.Closure
|
import com.kenai.jffi.Closure
|
||||||
import com.kenai.jffi.ClosureManager
|
import com.kenai.jffi.ClosureManager
|
||||||
|
import com.kenai.jffi.MemoryIO
|
||||||
import com.kenai.jffi.Type
|
import com.kenai.jffi.Type
|
||||||
import com.sun.jna.Native
|
|
||||||
import com.sun.jna.ptr.LongByReference
|
|
||||||
import jnr.ffi.Memory
|
import jnr.ffi.Memory
|
||||||
import jnr.ffi.NativeType
|
import jnr.ffi.NativeType
|
||||||
import jnr.ffi.Pointer
|
import org.apache.logging.log4j.LogManager
|
||||||
import org.lwjgl.system.MemoryUtil
|
import org.lwjgl.system.MemoryUtil
|
||||||
import java.io.Closeable
|
import java.io.Closeable
|
||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
import java.io.StringWriter
|
import java.io.StringWriter
|
||||||
|
import java.lang.ref.Cleaner
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
import java.nio.ByteOrder
|
import java.nio.ByteOrder
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
private fun stringToBuffer(str: String): ByteBuffer {
|
private fun stringToBuffer(str: String): ByteBuffer {
|
||||||
val bytes = str.toByteArray(charset = Charsets.UTF_8)
|
val bytes = str.toByteArray(charset = Charsets.UTF_8)
|
||||||
@ -34,17 +35,34 @@ private fun stringToBuffer(str: String): ByteBuffer {
|
|||||||
|
|
||||||
class LuaState : Closeable {
|
class LuaState : Closeable {
|
||||||
private val pointer = LuaJNR.INSTANCE.luaL_newstate() ?: throw OutOfMemoryError("Unable to allocate new LuaState")
|
private val pointer = LuaJNR.INSTANCE.luaL_newstate() ?: throw OutOfMemoryError("Unable to allocate new LuaState")
|
||||||
|
private val cleanable: Cleaner.Cleanable
|
||||||
|
private val sharedStringBufferPtr = MemoryIO.getInstance().allocateMemory(2L shl 16, false)
|
||||||
|
|
||||||
private var destroyed = false
|
init {
|
||||||
private val panicHandler = object : LuaJNR.lua_CFunction {
|
val pointer = pointer
|
||||||
override fun invoke(luaState: Pointer): Int {
|
val sharedStringBufferPtr = sharedStringBufferPtr
|
||||||
println("$this panicked!")
|
|
||||||
return 0
|
cleanable = CLEANER.register(this) {
|
||||||
|
LuaJNR.INSTANCE.lua_close(pointer)
|
||||||
|
MemoryIO.getInstance().freeMemory(sharedStringBufferPtr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val panicHandler = ClosureManager.getInstance().newClosure(
|
||||||
|
{
|
||||||
|
LOGGER.fatal("${this@LuaState} at $pointer has panicked! This should be impossible!")
|
||||||
|
exitProcess(1)
|
||||||
|
},
|
||||||
|
|
||||||
|
CallContext.getCallContext(Type.SINT, arrayOf(Type.POINTER), CallingConvention.DEFAULT, false)
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
cleanable.clean()
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
//LuaJNR.INSTANCE.lua_atpanic(pointer, panicHandler)
|
LuaJNR.INSTANCE.lua_atpanic(pointer, panicHandler.address)
|
||||||
|
|
||||||
LuaJNR.INSTANCE.luaopen_base(pointer)
|
LuaJNR.INSTANCE.luaopen_base(pointer)
|
||||||
storeGlobal("_G")
|
storeGlobal("_G")
|
||||||
@ -64,26 +82,15 @@ class LuaState : Closeable {
|
|||||||
storeGlobal("debug")
|
storeGlobal("debug")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun pushClosure(lambda: (state: LuaState) -> Unit) {
|
val stackTop: Int get() {
|
||||||
LuaJNI.lua_pushcclosure(pointer.address()) lazy@{
|
val value = LuaJNR.INSTANCE.lua_gettop(pointer)
|
||||||
try {
|
check(value >= 0) { "Invalid stack top $value" }
|
||||||
lambda.invoke(this@LuaState)
|
return value
|
||||||
} catch (err: Throwable) {
|
|
||||||
val builder = StringWriter()
|
|
||||||
val printWriter = PrintWriter(builder)
|
|
||||||
err.printStackTrace(printWriter)
|
|
||||||
push(builder.toString())
|
|
||||||
return@lazy 1
|
|
||||||
}
|
|
||||||
|
|
||||||
return@lazy 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun checkStack(minAmount: Int): Boolean {
|
|
||||||
return LuaJNR.INSTANCE.lua_checkstack(pointer, minAmount) > 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the acceptable index idx into an equivalent absolute index (that is, one that does not depend on the stack size).
|
||||||
|
*/
|
||||||
fun absoluteIndex(index: Int): Int {
|
fun absoluteIndex(index: Int): Int {
|
||||||
return LuaJNR.INSTANCE.lua_absindex(pointer, index)
|
return LuaJNR.INSTANCE.lua_absindex(pointer, index)
|
||||||
}
|
}
|
||||||
@ -116,17 +123,17 @@ class LuaState : Closeable {
|
|||||||
closure.dispose()
|
closure.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun pcall(numArgs: Int = 0, numResults: Int = 0): Int {
|
fun call(numArgs: Int = 0, numResults: Int = 0): Int {
|
||||||
val status = LuaJNR.INSTANCE.lua_pcallk(pointer, numArgs, numResults, 0, 0L, 0L)
|
val status = LuaJNR.INSTANCE.lua_pcallk(pointer, numArgs, numResults, 0, 0L, 0L)
|
||||||
|
|
||||||
if (status == LUA_ERRRUN) {
|
if (status == LUA_ERRRUN) {
|
||||||
throw LuaRuntimeException(getString())
|
throw LuaRuntimeException(popString())
|
||||||
}
|
}
|
||||||
|
|
||||||
return status
|
return status
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getString(index: Int = -1, limit: Long = 4096): String? {
|
fun popString(index: Int = -1, limit: Long = 2 shl 16): String? {
|
||||||
val len = Memory.allocateDirect(LuaJNR.RUNTIME, NativeType.SLONGLONG)
|
val len = Memory.allocateDirect(LuaJNR.RUNTIME, NativeType.SLONGLONG)
|
||||||
val p = LuaJNR.INSTANCE.lua_tolstring(pointer, absoluteIndex(index), len) ?: return null
|
val p = LuaJNR.INSTANCE.lua_tolstring(pointer, absoluteIndex(index), len) ?: return null
|
||||||
|
|
||||||
@ -143,21 +150,6 @@ class LuaState : Closeable {
|
|||||||
return readBytes.toString(charset = Charsets.UTF_8)
|
return readBytes.toString(charset = Charsets.UTF_8)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun close() {
|
|
||||||
if (destroyed) {
|
|
||||||
throw IllegalStateException("Already destroyed")
|
|
||||||
}
|
|
||||||
|
|
||||||
LuaJNR.INSTANCE.lua_close(pointer)
|
|
||||||
destroyed = true
|
|
||||||
}
|
|
||||||
|
|
||||||
val stackTop: Int get() {
|
|
||||||
val value = LuaJNR.INSTANCE.lua_gettop(pointer)
|
|
||||||
check(value >= 0) { "Invalid stack top $value" }
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
fun storeGlobal(name: String) {
|
fun storeGlobal(name: String) {
|
||||||
LuaJNR.INSTANCE.lua_setglobal(pointer, name)
|
LuaJNR.INSTANCE.lua_setglobal(pointer, name)
|
||||||
}
|
}
|
||||||
@ -166,6 +158,22 @@ class LuaState : Closeable {
|
|||||||
LuaJNR.INSTANCE.lua_getglobal(pointer, name)
|
LuaJNR.INSTANCE.lua_getglobal(pointer, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun push(closure: (state: LuaState) -> Unit) {
|
||||||
|
LuaJNI.lua_pushcclosure(pointer.address()) lazy@{
|
||||||
|
try {
|
||||||
|
closure.invoke(this@LuaState)
|
||||||
|
} catch (err: Throwable) {
|
||||||
|
val builder = StringWriter()
|
||||||
|
val printWriter = PrintWriter(builder)
|
||||||
|
err.printStackTrace(printWriter)
|
||||||
|
push(builder.toString())
|
||||||
|
return@lazy 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return@lazy 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun push() {
|
fun push() {
|
||||||
LuaJNR.INSTANCE.lua_pushnil(pointer)
|
LuaJNR.INSTANCE.lua_pushnil(pointer)
|
||||||
}
|
}
|
||||||
@ -178,23 +186,53 @@ class LuaState : Closeable {
|
|||||||
LuaJNR.INSTANCE.lua_pushinteger(pointer, value)
|
LuaJNR.INSTANCE.lua_pushinteger(pointer, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun push(value: Double) {
|
||||||
|
LuaJNR.INSTANCE.lua_pushnumber(pointer, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun push(value: Float) {
|
||||||
|
LuaJNR.INSTANCE.lua_pushnumber(pointer, value.toDouble())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun push(value: Boolean) {
|
||||||
|
LuaJNR.INSTANCE.lua_pushboolean(pointer, if (value) 1 else 0)
|
||||||
|
}
|
||||||
|
|
||||||
fun push(value: String) {
|
fun push(value: String) {
|
||||||
val bytes = value.toByteArray(Charsets.UTF_8)
|
val bytes = value.toByteArray(Charsets.UTF_8)
|
||||||
|
|
||||||
val block = LuaJNR.RUNTIME.memoryManager.allocateDirect(bytes.size) ?: throw OutOfMemoryError("Unable to allocate ${bytes.size} bytes on heap")
|
if (bytes.size < 2 shl 16) {
|
||||||
|
MemoryIO.getInstance().putByteArray(sharedStringBufferPtr, bytes, 0, bytes.size)
|
||||||
|
LuaJNR.INSTANCE.lua_pushlstring(pointer, sharedStringBufferPtr, bytes.size.toLong())
|
||||||
|
} else {
|
||||||
|
val mem = MemoryIO.getInstance()
|
||||||
|
val block = mem.allocateMemory(bytes.size.toLong(), false)
|
||||||
|
|
||||||
//try {
|
if (block == 0L)
|
||||||
block.put(0L, bytes, 0, bytes.size)
|
throw OutOfMemoryError("Unable to allocate ${bytes.size} bytes on heap")
|
||||||
LuaJNR.INSTANCE.lua_pushlstring(pointer, block, bytes.size.toLong())
|
|
||||||
//} finally {
|
try {
|
||||||
// Memory.allocate()
|
mem.putByteArray(block, bytes, 0, bytes.size)
|
||||||
//}
|
LuaJNR.INSTANCE.lua_pushlstring(pointer, block, bytes.size.toLong())
|
||||||
|
} finally {
|
||||||
|
mem.freeMemory(block)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun pushTable(arraySize: Int = 0, hashSize: Int = 0): Int {
|
||||||
|
LuaJNR.INSTANCE.lua_createtable(pointer, arraySize, hashSize)
|
||||||
|
return stackTop
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setTableValue(stackIndex: Int) {
|
||||||
|
LuaJNR.INSTANCE.lua_settable(pointer, stackIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun push(value: JsonElement) {
|
fun push(value: JsonElement) {
|
||||||
when (value) {
|
when (value) {
|
||||||
JsonNull.INSTANCE -> {
|
JsonNull.INSTANCE -> {
|
||||||
LuaJNR.INSTANCE.lua_pushnil(pointer)
|
push()
|
||||||
}
|
}
|
||||||
|
|
||||||
is JsonPrimitive -> {
|
is JsonPrimitive -> {
|
||||||
@ -202,39 +240,37 @@ class LuaState : Closeable {
|
|||||||
val num = value.asNumber
|
val num = value.asNumber
|
||||||
|
|
||||||
when (num) {
|
when (num) {
|
||||||
is Int, is Long -> LuaJNR.INSTANCE.lua_pushinteger(pointer, num.toLong())
|
is Int, is Long -> push(num.toLong())
|
||||||
else -> LuaJNR.INSTANCE.lua_pushnumber(pointer, num.toDouble())
|
else -> push(num.toDouble())
|
||||||
}
|
}
|
||||||
} else if (value.isString) {
|
} else if (value.isString) {
|
||||||
push(value.asString)
|
push(value.asString)
|
||||||
} else if (value.isBoolean) {
|
} else if (value.isBoolean) {
|
||||||
LuaJNR.INSTANCE.lua_pushboolean(pointer, if (value.asBoolean) 1 else 0)
|
push(value.asBoolean)
|
||||||
} else {
|
} else {
|
||||||
throw IllegalArgumentException(value.toString())
|
throw IllegalArgumentException(value.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is JsonArray -> {
|
is JsonArray -> {
|
||||||
LuaJNR.INSTANCE.lua_createtable(pointer, value.size(), 0)
|
val index = pushTable(arraySize = value.size())
|
||||||
val index = stackTop
|
|
||||||
|
|
||||||
for ((i, v) in value.withIndex()) {
|
for ((i, v) in value.withIndex()) {
|
||||||
LuaJNR.INSTANCE.lua_pushinteger(pointer, i.toLong() + 1L)
|
push(i + 1L)
|
||||||
push(v)
|
push(v)
|
||||||
|
|
||||||
LuaJNR.INSTANCE.lua_settable(pointer, index)
|
setTableValue(index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is JsonObject -> {
|
is JsonObject -> {
|
||||||
LuaJNR.INSTANCE.lua_createtable(pointer, 0, value.size())
|
val index = pushTable(hashSize = value.size())
|
||||||
val index = stackTop
|
|
||||||
|
|
||||||
for ((k, v) in value.entrySet()) {
|
for ((k, v) in value.entrySet()) {
|
||||||
push(k)
|
push(k)
|
||||||
push(v)
|
push(v)
|
||||||
|
|
||||||
LuaJNR.INSTANCE.lua_settable(pointer, index)
|
setTableValue(index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,4 +279,13 @@ class LuaState : Closeable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val LOGGER = LogManager.getLogger()
|
||||||
|
private val CLEANER = Cleaner.create {
|
||||||
|
val thread = Thread(it, "LuaState cleaner")
|
||||||
|
thread.priority = 1
|
||||||
|
thread
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
2
test.lua
2
test.lua
@ -16,7 +16,7 @@ function printTable(input)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function test(...)
|
function test(...)
|
||||||
print('Called test with ' .. select('#', ...) .. ' arguments: ' .. table.concat({...}, ', '))
|
print('Called test with ' .. select('#', ...) .. ' arguments: ' .. #table.concat({...}, ', '))
|
||||||
end
|
end
|
||||||
|
|
||||||
print(collectgarbage('count') * 1024)
|
print(collectgarbage('count') * 1024)
|
||||||
|
Loading…
Reference in New Issue
Block a user