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> { var key: Any? = initialKey() ?: return ObjectIterators.emptyIterator() data class Pair(override val key: Any, override val value: Any) : Map.Entry return object : Iterator> { override fun hasNext(): Boolean { return key != null } override fun next(): Map.Entry { 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 { return object : LuaFunction() { 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?) { throw LuaRuntimeException("NYI: $message") } } } fun luaFunctionN(name: String, callable: ExecutionContext.(ArgumentIterator) -> Unit): LuaFunction { return object : AbstractFunctionAnyArg() { override fun resume(context: ExecutionContext, suspendedState: Any) { throw NonsuspendableFunctionException(this::class.java) } override fun invoke(context: ExecutionContext, args: Array) { callable.invoke(context, ArgumentIterator.of(context, name, args)) } } } fun luaFunctionNS(name: String, callable: ExecutionContext.(ArgumentIterator) -> StateMachine): LuaFunction { return object : AbstractFunctionAnyArg() { override fun resume(context: ExecutionContext, suspendedState: Any) { (suspendedState as StateMachine).run(context) } override fun invoke(context: ExecutionContext, args: Array) { callable.invoke(context, ArgumentIterator.of(context, name, args)).run(context) } } } fun luaFunctionArray(callable: ExecutionContext.(Array) -> Unit): LuaFunction { return object : AbstractFunctionAnyArg() { override fun resume(context: ExecutionContext, suspendedState: Any) { throw NonsuspendableFunctionException(this::class.java) } override fun invoke(context: ExecutionContext, args: Array) { 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 luaFunction(callable: ExecutionContext.(T) -> Unit): LuaFunction { return object : AbstractFunction1() { override fun resume(context: ExecutionContext, suspendedState: Any) { throw NonsuspendableFunctionException(this::class.java) } override fun invoke(context: ExecutionContext, arg1: T) { callable.invoke(context, arg1) } } } fun luaFunction(callable: ExecutionContext.(T, T2) -> Unit): LuaFunction { return object : AbstractFunction2() { 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 luaFunction(callable: ExecutionContext.(T, T2, T3) -> Unit): LuaFunction { return object : AbstractFunction3() { 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 luaFunction(callable: ExecutionContext.(T, T2, T3, T4) -> Unit): LuaFunction { return object : AbstractFunction4() { 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) } } }