KStarbound/src/main/kotlin/ru/dbotthepony/kstarbound/lua/Functions.kt

245 lines
7.7 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.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
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.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)
}
}
}
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
}
@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>) {
callable.invoke(context, ArgumentIterator.of(context, name, args))
}
}
}
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>) {
callable.invoke(context, ArgumentIterator.of(context, name, args)).run(context)
}
}
}
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?>) {
callable.invoke(context, args)
}
}
}
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) {
callable.invoke(context)
}
}
}
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) {
callable.invoke(context, arg1)
}
}
}
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) {
callable.invoke(context, arg1, arg2)
}
}
}
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) {
callable.invoke(context, arg1, arg2, arg3)
}
}
}
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) {
callable.invoke(context, arg1, arg2, arg3, arg4)
}
}
}