353 lines
9.9 KiB
Kotlin
353 lines
9.9 KiB
Kotlin
package ru.dbotthepony.kstarbound.lua
|
|
|
|
import com.google.gson.JsonElement
|
|
import it.unimi.dsi.fastutil.objects.ObjectIterators
|
|
import org.classdump.luna.LuaRuntimeException
|
|
import org.classdump.luna.Table
|
|
import org.classdump.luna.TableFactory
|
|
import org.classdump.luna.impl.NonsuspendableFunctionException
|
|
import org.classdump.luna.lib.ArgumentIterator
|
|
import org.classdump.luna.lib.TableLib
|
|
import org.classdump.luna.runtime.AbstractFunction0
|
|
import org.classdump.luna.runtime.AbstractFunction1
|
|
import org.classdump.luna.runtime.AbstractFunction2
|
|
import org.classdump.luna.runtime.AbstractFunction3
|
|
import org.classdump.luna.runtime.AbstractFunction4
|
|
import org.classdump.luna.runtime.AbstractFunctionAnyArg
|
|
import org.classdump.luna.runtime.Dispatch
|
|
import org.classdump.luna.runtime.ExecutionContext
|
|
import org.classdump.luna.runtime.LuaFunction
|
|
import org.classdump.luna.runtime.UnresolvedControlThrowable
|
|
import kotlin.math.max
|
|
import kotlin.math.min
|
|
|
|
fun ExecutionContext.indexNoYield(table: Any, key: Any): Any? {
|
|
return try {
|
|
Dispatch.index(this, table, key)
|
|
returnBuffer.get0()
|
|
} catch (err: UnresolvedControlThrowable) {
|
|
throw RuntimeException("attempt to yield across C boundary", err)
|
|
}
|
|
}
|
|
|
|
fun ExecutionContext.indexSetNoYield(table: Any, key: Any, value: Any?) {
|
|
try {
|
|
Dispatch.setindex(this, table, key, value)
|
|
} catch (err: UnresolvedControlThrowable) {
|
|
throw RuntimeException("attempt to yield across C boundary", err)
|
|
}
|
|
}
|
|
|
|
fun ArgumentIterator.nextOptionalFloat(): Double? {
|
|
if (hasNext()) {
|
|
return nextFloat()
|
|
} else {
|
|
return null
|
|
}
|
|
}
|
|
|
|
fun ArgumentIterator.nextOptionalInteger(): Long? {
|
|
if (hasNext()) {
|
|
return nextInteger()
|
|
} else {
|
|
return null
|
|
}
|
|
}
|
|
|
|
operator fun Table.set(index: Any, value: Any?) {
|
|
rawset(index, value)
|
|
}
|
|
|
|
@Deprecated("Trying to set JSON to Lua table", level = DeprecationLevel.ERROR)
|
|
operator fun Table.set(index: Any, value: JsonElement?) {
|
|
rawset(index, value)
|
|
}
|
|
|
|
operator fun Table.set(index: Long, value: Any?) {
|
|
rawset(index, value)
|
|
}
|
|
|
|
@Deprecated("Trying to set JSON to Lua table", level = DeprecationLevel.ERROR)
|
|
operator fun Table.set(index: Long, value: JsonElement?) {
|
|
rawset(index, value)
|
|
}
|
|
|
|
operator fun Table.set(index: Int, value: Any?) {
|
|
rawset(index.toLong(), value)
|
|
}
|
|
|
|
@Deprecated("Trying to set JSON to Lua table", level = DeprecationLevel.ERROR)
|
|
operator fun Table.set(index: Int, value: JsonElement?) {
|
|
rawset(index.toLong(), value)
|
|
}
|
|
|
|
operator fun Table.get(index: Any): Any? = rawget(index)
|
|
operator fun Table.get(index: Long): Any? = rawget(index)
|
|
operator fun Table.get(index: Int): Any? = rawget(index.toLong())
|
|
|
|
operator fun Table.contains(index: Any): Boolean {
|
|
return rawget(index) != null
|
|
}
|
|
|
|
operator fun Table.contains(index: Long): Boolean {
|
|
return rawget(index) != null
|
|
}
|
|
|
|
operator fun Table.iterator(): Iterator<Map.Entry<Any, Any>> {
|
|
var key: Any? = initialKey() ?: return ObjectIterators.emptyIterator()
|
|
data class Pair(override val key: Any, override val value: Any) : Map.Entry<Any, Any>
|
|
|
|
return object : Iterator<Map.Entry<Any, Any>> {
|
|
override fun hasNext(): Boolean {
|
|
return key != null
|
|
}
|
|
|
|
override fun next(): Map.Entry<Any, Any> {
|
|
val ikey = key ?: throw NoSuchElementException()
|
|
val value = get(ikey)!!
|
|
key = successorKeyOf(ikey)
|
|
return Pair(ikey, value)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* to be used in places where we need to "unpack" table, like this:
|
|
*
|
|
* ```lua
|
|
* local array = unpack(tab)
|
|
* ```
|
|
*
|
|
* except this function unpacks using rawget
|
|
*/
|
|
fun Table.unpackAsArray(): Array<Any?> {
|
|
var min = Long.MAX_VALUE
|
|
var max = 0L
|
|
|
|
for ((k, v) in this) {
|
|
if (k is Long) {
|
|
max = max(k, max)
|
|
min = min(k, min)
|
|
}
|
|
}
|
|
|
|
val length = max - min
|
|
|
|
if (length <= 0L)
|
|
return arrayOf()
|
|
|
|
val array = arrayOfNulls<Any>(length.toInt())
|
|
var i2 = 0
|
|
|
|
for (i in min .. max) {
|
|
array[i2++] = this[i]
|
|
}
|
|
|
|
return array
|
|
}
|
|
|
|
fun TableFactory.tableOf(vararg values: Any?): Table {
|
|
val table = newTable(values.size, 0)
|
|
|
|
for ((i, v) in values.withIndex()) {
|
|
table[i + 1L] = v
|
|
}
|
|
|
|
return table
|
|
}
|
|
|
|
fun TableFactory.tableMapOf(vararg values: Pair<Any, Any?>): Table {
|
|
val table = newTable(0, values.size)
|
|
|
|
for ((k, v) in values) {
|
|
table[k] = v
|
|
}
|
|
|
|
return table
|
|
}
|
|
|
|
fun TableFactory.tableOf(): Table {
|
|
return newTable()
|
|
}
|
|
|
|
@Deprecated("Function is a stub")
|
|
fun luaStub(message: String = "not yet implemented"): LuaFunction<Any?, Any?, Any?, Any?, Any?> {
|
|
return object : LuaFunction<Any?, Any?, Any?, Any?, Any?>() {
|
|
override fun resume(context: ExecutionContext?, suspendedState: Any?) {
|
|
throw NonsuspendableFunctionException(this::class.java)
|
|
}
|
|
|
|
override fun invoke(context: ExecutionContext?) {
|
|
throw LuaRuntimeException("NYI: $message")
|
|
}
|
|
|
|
override fun invoke(context: ExecutionContext?, arg1: Any?) {
|
|
throw LuaRuntimeException("NYI: $message")
|
|
}
|
|
|
|
override fun invoke(context: ExecutionContext?, arg1: Any?, arg2: Any?) {
|
|
throw LuaRuntimeException("NYI: $message")
|
|
}
|
|
|
|
override fun invoke(context: ExecutionContext?, arg1: Any?, arg2: Any?, arg3: Any?) {
|
|
throw LuaRuntimeException("NYI: $message")
|
|
}
|
|
|
|
override fun invoke(context: ExecutionContext?, arg1: Any?, arg2: Any?, arg3: Any?, arg4: Any?) {
|
|
throw LuaRuntimeException("NYI: $message")
|
|
}
|
|
|
|
override fun invoke(context: ExecutionContext?, arg1: Any?, arg2: Any?, arg3: Any?, arg4: Any?, arg5: Any?) {
|
|
throw LuaRuntimeException("NYI: $message")
|
|
}
|
|
|
|
override fun invoke(context: ExecutionContext?, args: Array<out Any>?) {
|
|
throw LuaRuntimeException("NYI: $message")
|
|
}
|
|
}
|
|
}
|
|
|
|
fun luaFunctionN(name: String, callable: ExecutionContext.(ArgumentIterator) -> Unit): LuaFunction<Any, Any, Any, Any, Any> {
|
|
return object : AbstractFunctionAnyArg() {
|
|
override fun resume(context: ExecutionContext, suspendedState: Any) {
|
|
throw NonsuspendableFunctionException(this::class.java)
|
|
}
|
|
|
|
override fun invoke(context: ExecutionContext, args: Array<out Any>) {
|
|
try {
|
|
callable.invoke(context, ArgumentIterator.of(context, name, args))
|
|
} catch (err: ClassCastException) {
|
|
throw LuaRuntimeException(err)
|
|
} catch (err: NullPointerException) {
|
|
throw LuaRuntimeException(err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fun luaFunctionNS(name: String, callable: ExecutionContext.(ArgumentIterator) -> StateMachine): LuaFunction<Any, Any, Any, Any, Any> {
|
|
return object : AbstractFunctionAnyArg() {
|
|
override fun resume(context: ExecutionContext, suspendedState: Any) {
|
|
(suspendedState as StateMachine).run(context)
|
|
}
|
|
|
|
override fun invoke(context: ExecutionContext, args: Array<out Any>) {
|
|
try {
|
|
callable.invoke(context, ArgumentIterator.of(context, name, args)).run(context)
|
|
} catch (err: ClassCastException) {
|
|
throw LuaRuntimeException(err)
|
|
} catch (err: NullPointerException) {
|
|
throw LuaRuntimeException(err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fun luaFunctionArray(callable: ExecutionContext.(Array<out Any?>) -> Unit): LuaFunction<Any, Any, Any, Any, Any> {
|
|
return object : AbstractFunctionAnyArg() {
|
|
override fun resume(context: ExecutionContext, suspendedState: Any) {
|
|
throw NonsuspendableFunctionException(this::class.java)
|
|
}
|
|
|
|
override fun invoke(context: ExecutionContext, args: Array<out Any?>) {
|
|
try {
|
|
callable.invoke(context, args)
|
|
} catch (err: ClassCastException) {
|
|
throw LuaRuntimeException(err)
|
|
} catch (err: NullPointerException) {
|
|
throw LuaRuntimeException(err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fun luaFunction(callable: ExecutionContext.() -> Unit): LuaFunction<*, *, *, *, *> {
|
|
return object : AbstractFunction0() {
|
|
override fun resume(context: ExecutionContext, suspendedState: Any) {
|
|
throw NonsuspendableFunctionException(this::class.java)
|
|
}
|
|
|
|
override fun invoke(context: ExecutionContext) {
|
|
try {
|
|
callable.invoke(context)
|
|
} catch (err: ClassCastException) {
|
|
throw LuaRuntimeException(err)
|
|
} catch (err: NullPointerException) {
|
|
throw LuaRuntimeException(err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fun <T> luaFunction(callable: ExecutionContext.(T) -> Unit): LuaFunction<T, *, *, *, *> {
|
|
return object : AbstractFunction1<T>() {
|
|
override fun resume(context: ExecutionContext, suspendedState: Any) {
|
|
throw NonsuspendableFunctionException(this::class.java)
|
|
}
|
|
|
|
override fun invoke(context: ExecutionContext, arg1: T) {
|
|
try {
|
|
callable.invoke(context, arg1)
|
|
} catch (err: ClassCastException) {
|
|
throw LuaRuntimeException(err)
|
|
} catch (err: NullPointerException) {
|
|
throw LuaRuntimeException(err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fun <T, T2> luaFunction(callable: ExecutionContext.(T, T2) -> Unit): LuaFunction<T, T2, *, *, *> {
|
|
return object : AbstractFunction2<T, T2>() {
|
|
override fun resume(context: ExecutionContext, suspendedState: Any) {
|
|
throw NonsuspendableFunctionException(this::class.java)
|
|
}
|
|
|
|
override fun invoke(context: ExecutionContext, arg1: T, arg2: T2) {
|
|
try {
|
|
callable.invoke(context, arg1, arg2)
|
|
} catch (err: ClassCastException) {
|
|
throw LuaRuntimeException(err)
|
|
} catch (err: NullPointerException) {
|
|
throw LuaRuntimeException(err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fun <T, T2, T3> luaFunction(callable: ExecutionContext.(T, T2, T3) -> Unit): LuaFunction<T, T2, T3, *, *> {
|
|
return object : AbstractFunction3<T, T2, T3>() {
|
|
override fun resume(context: ExecutionContext, suspendedState: Any) {
|
|
throw NonsuspendableFunctionException(this::class.java)
|
|
}
|
|
|
|
override fun invoke(context: ExecutionContext, arg1: T, arg2: T2, arg3: T3) {
|
|
try {
|
|
callable.invoke(context, arg1, arg2, arg3)
|
|
} catch (err: ClassCastException) {
|
|
throw LuaRuntimeException(err)
|
|
} catch (err: NullPointerException) {
|
|
throw LuaRuntimeException(err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fun <T, T2, T3, T4> luaFunction(callable: ExecutionContext.(T, T2, T3, T4) -> Unit): LuaFunction<T, T2, T3, T4, *> {
|
|
return object : AbstractFunction4<T, T2, T3, T4>() {
|
|
override fun resume(context: ExecutionContext, suspendedState: Any) {
|
|
throw NonsuspendableFunctionException(this::class.java)
|
|
}
|
|
|
|
override fun invoke(context: ExecutionContext, arg1: T, arg2: T2, arg3: T3, arg4: T4) {
|
|
try {
|
|
callable.invoke(context, arg1, arg2, arg3, arg4)
|
|
} catch (err: ClassCastException) {
|
|
throw LuaRuntimeException(err)
|
|
} catch (err: NullPointerException) {
|
|
throw LuaRuntimeException(err)
|
|
}
|
|
}
|
|
}
|
|
}
|