All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.org.luaj.vm2.Varargs.kt Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright (c) 2009 Luaj.org. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.luaj.vm2

import org.luaj.vm2.internal.*
import kotlin.math.*
import kotlin.reflect.*

/**
 * Class to encapsulate varargs values, either as part of a variable argument list, or multiple return values.
 *
 *
 * To construct varargs, use one of the static methods such as
 * `LuaValue.varargsOf(LuaValue,LuaValue)`
 *
 *
 *
 *
 * Any LuaValue can be used as a stand-in for Varargs, for both calls and return values.
 * When doing so, nargs() will return 1 and arg1() or arg(1) will return this.
 * This simplifies the case when calling or implementing varargs functions with only
 * 1 argument or 1 return value.
 *
 *
 * Varargs can also be derived from other varargs by appending to the front with a call
 * such as  `LuaValue.varargsOf(LuaValue,Varargs)`
 * or by taking a portion of the args using `Varargs.subargs(int start)`
 *
 *
 * @see LuaValue.varargsOf
 * @see LuaValue.varargsOf
 * @see LuaValue.varargsOf
 * @see LuaValue.varargsOf
 * @see LuaValue.varargsOf
 * @see LuaValue.varargsOf
 * @see LuaValue.subargs
 */
abstract class Varargs {

    /**
     * Return true if this is a TailcallVarargs
     * @return true if a tail call, false otherwise
     */
    open fun isTailcall(): Boolean = false

    /**
     * Get the n-th argument value (1-based).
     * @param i the index of the argument to get, 1 is the first argument
     * @return Value at position i, or LuaValue.NIL if there is none.
     * @see Varargs.arg1
     * @see LuaValue.NIL
     */
    abstract fun arg(i: Int): LuaValue

    /**
     * Get the number of arguments, or 0 if there are none.
     * @return number of arguments.
     */
    abstract fun narg(): Int

    /**
     * Get the first argument in the list.
     * @return LuaValue which is first in the list, or LuaValue.NIL if there are no values.
     * @see Varargs.arg
     * @see LuaValue.NIL
     */
    abstract fun arg1(): LuaValue

    /**
     * Evaluate any pending tail call and return result.
     * @return the evaluated tail call result
     */
    open fun eval(): Varargs = this

    // -----------------------------------------------------------------------
    // utilities to get specific arguments and type-check them.
    // -----------------------------------------------------------------------

    /** Gets the type of argument `i`
     * @param i the index of the argument to convert, 1 is the first argument
     * @return int value corresponding to one of the LuaValue integer type values
     * @see LuaValue.TNIL
     *
     * @see LuaValue.TBOOLEAN
     *
     * @see LuaValue.TNUMBER
     *
     * @see LuaValue.TSTRING
     *
     * @see LuaValue.TTABLE
     *
     * @see LuaValue.TFUNCTION
     *
     * @see LuaValue.TUSERDATA
     *
     * @see LuaValue.TTHREAD
     *
     */
    fun type(i: Int): Int = arg(i).type()

    /** Tests if argument i is nil.
     * @param i the index of the argument to test, 1 is the first argument
     * @return true if the argument is nil or does not exist, false otherwise
     * @see LuaValue.TNIL
     *
     */
    fun isnil(i: Int): Boolean = arg(i).isnil()

    /** Tests if argument i is a function.
     * @param i the index of the argument to test, 1 is the first argument
     * @return true if the argument exists and is a function or closure, false otherwise
     * @see LuaValue.TFUNCTION
     *
     */
    fun isfunction(i: Int): Boolean = arg(i).isfunction()

    /** Tests if argument i is a number.
     * Since anywhere a number is required, a string can be used that
     * is a number, this will return true for both numbers and
     * strings that can be interpreted as numbers.
     * @param i the index of the argument to test, 1 is the first argument
     * @return true if the argument exists and is a number or
     * string that can be interpreted as a number, false otherwise
     * @see LuaValue.TNUMBER
     *
     * @see LuaValue.TSTRING
     *
     */
    fun isnumber(i: Int): Boolean = arg(i).isnumber()

    /** Tests if argument i is a string.
     * Since all lua numbers can be used where strings are used,
     * this will return true for both strings and numbers.
     * @param i the index of the argument to test, 1 is the first argument
     * @return true if the argument exists and is a string or number, false otherwise
     * @see LuaValue.TNUMBER
     *
     * @see LuaValue.TSTRING
     *
     */
    fun isstring(i: Int): Boolean = arg(i).isstring()

    /** Tests if argument i is a table.
     * @param i the index of the argument to test, 1 is the first argument
     * @return true if the argument exists and is a lua table, false otherwise
     * @see LuaValue.TTABLE
     *
     */
    fun istable(i: Int): Boolean = arg(i).istable()

    /** Tests if argument i is a thread.
     * @param i the index of the argument to test, 1 is the first argument
     * @return true if the argument exists and is a lua thread, false otherwise
     * @see LuaValue.TTHREAD
     *
     */
    fun isthread(i: Int): Boolean = arg(i).isthread()

    /** Tests if argument i is a userdata.
     * @param i the index of the argument to test, 1 is the first argument
     * @return true if the argument exists and is a userdata, false otherwise
     * @see LuaValue.TUSERDATA
     *
     */
    fun isuserdata(i: Int): Boolean = arg(i).isuserdata()

    /** Tests if a value exists at argument i.
     * @param i the index of the argument to test, 1 is the first argument
     * @return true if the argument exists, false otherwise
     */
    fun isvalue(i: Int): Boolean = i > 0 && i <= narg()

    /** Return argument i as a boolean value, `defval` if nil, or throw a LuaError if any other type.
     * @param i the index of the argument to test, 1 is the first argument
     * @return true if argument i is boolean true, false if it is false, or defval if not supplied or nil
     * @exception LuaError if the argument is not a lua boolean
     */
    fun optboolean(i: Int, defval: Boolean): Boolean = arg(i).optboolean(defval)

    /** Return argument i as a closure, `defval` if nil, or throw a LuaError if any other type.
     * @param i the index of the argument to test, 1 is the first argument
     * @return LuaClosure if argument i is a closure, or defval if not supplied or nil
     * @exception LuaError if the argument is not a lua closure
     */
    fun optclosure(i: Int, defval: LuaClosure): LuaClosure? = arg(i).optclosure(defval)

    /** Return argument i as a double, `defval` if nil, or throw a LuaError if it cannot be converted to one.
     * @param i the index of the argument to test, 1 is the first argument
     * @return java double value if argument i is a number or string that converts to a number, or defval if not supplied or nil
     * @exception LuaError if the argument is not a number
     */
    fun optdouble(i: Int, defval: Double): Double = arg(i).optdouble(defval)

    /** Return argument i as a function, `defval` if nil, or throw a LuaError  if an incompatible type.
     * @param i the index of the argument to test, 1 is the first argument
     * @return LuaValue that can be called if argument i is lua function or closure, or defval if not supplied or nil
     * @exception LuaError if the argument is not a lua function or closure
     */
    fun optfunction(i: Int, defval: LuaFunction?): LuaFunction? = arg(i).optfunction(defval)

    /** Return argument i as a java int value, discarding any fractional part, `defval` if nil, or throw a LuaError  if not a number.
     * @param i the index of the argument to test, 1 is the first argument
     * @return int value with fraction discarded and truncated if necessary if argument i is number, or defval if not supplied or nil
     * @exception LuaError if the argument is not a number
     */
    fun optint(i: Int, defval: Int): Int = arg(i).optint(defval)

    /** Return argument i as a java int value, `defval` if nil, or throw a LuaError  if not a number or is not representable by a java int.
     * @param i the index of the argument to test, 1 is the first argument
     * @return LuaInteger value that fits in a java int without rounding, or defval if not supplied or nil
     * @exception LuaError if the argument cannot be represented by a java int value
     */
    fun optinteger(i: Int, defval: LuaInteger): LuaInteger? = arg(i).optinteger(defval)

    /** Return argument i as a java long value, discarding any fractional part, `defval` if nil, or throw a LuaError  if not a number.
     * @param i the index of the argument to test, 1 is the first argument
     * @return long value with fraction discarded and truncated if necessary if argument i is number, or defval if not supplied or nil
     * @exception LuaError if the argument is not a number
     */
    fun optlong(i: Int, defval: Long): Long = arg(i).optlong(defval)

    /** Return argument i as a LuaNumber, `defval` if nil, or throw a LuaError  if not a number or string that can be converted to a number.
     * @param i the index of the argument to test, 1 is the first argument, or defval if not supplied or nil
     * @return LuaNumber if argument i is number or can be converted to a number
     * @exception LuaError if the argument is not a number
     */
    fun optnumber(i: Int, defval: LuaNumber): LuaNumber? = arg(i).optnumber(defval)

    /** Return argument i as a java String if a string or number, `defval` if nil, or throw a LuaError  if any other type
     * @param i the index of the argument to test, 1 is the first argument
     * @return String value if argument i is a string or number, or defval if not supplied or nil
     * @exception LuaError if the argument is not a string or number
     */
    fun optjstring(i: Int, defval: String?): String? = arg(i).optjstring(defval)

    /** Return argument i as a LuaString if a string or number, `defval` if nil, or throw a LuaError  if any other type
     * @param i the index of the argument to test, 1 is the first argument
     * @return LuaString value if argument i is a string or number, or defval if not supplied or nil
     * @exception LuaError if the argument is not a string or number
     */
    fun optstring(i: Int, defval: LuaString): LuaString? = arg(i).optstring(defval)

    /** Return argument i as a LuaTable if a lua table, `defval` if nil, or throw a LuaError  if any other type.
     * @param i the index of the argument to test, 1 is the first argument
     * @return LuaTable value if a table, or defval if not supplied or nil
     * @exception LuaError if the argument is not a lua table
     */
    fun opttable(i: Int, defval: LuaTable): LuaTable? = arg(i).opttable(defval)

    /** Return argument i as a LuaThread if a lua thread, `defval` if nil, or throw a LuaError  if any other type.
     * @param i the index of the argument to test, 1 is the first argument
     * @return LuaThread value if a thread, or defval if not supplied or nil
     * @exception LuaError if the argument is not a lua thread
     */
    fun optthread(i: Int, defval: LuaThread): LuaThread? = arg(i).optthread(defval)

    /** Return argument i as a java Object if a userdata, `defval` if nil, or throw a LuaError  if any other type.
     * @param i the index of the argument to test, 1 is the first argument
     * @return java Object value if argument i is a userdata, or defval if not supplied or nil
     * @exception LuaError if the argument is not a userdata
     */
    fun optuserdata(i: Int, defval: Any?): Any? = arg(i).optuserdata(defval)

    /** Return argument i as a java Object if it is a userdata whose instance Class c or a subclass,
     * `defval` if nil, or throw a LuaError  if any other type.
     * @param i the index of the argument to test, 1 is the first argument
     * @param c the class to which the userdata instance must be assignable
     * @return java Object value if argument i is a userdata whose instance Class c or a subclass, or defval if not supplied or nil
     * @exception LuaError if the argument is not a userdata or from whose instance c is not assignable
     */
    fun optuserdata(i: Int, c: KClass<*>, defval: Any): Any? = arg(i).optuserdata(c, defval)

    /** Return argument i as a LuaValue if it exists, or `defval`.
     * @param i the index of the argument to test, 1 is the first argument
     * @return LuaValue value if the argument exists, defval if not
     * @exception LuaError if the argument does not exist.
     */
    fun optvalue(i: Int, defval: LuaValue): LuaValue = if (i > 0 && i <= narg()) arg(i) else defval

    /** Return argument i as a boolean value, or throw an error if any other type.
     * @param i the index of the argument to test, 1 is the first argument
     * @return true if argument i is boolean true, false if it is false
     * @exception LuaError if the argument is not a lua boolean
     */
    fun checkboolean(i: Int): Boolean = arg(i).checkboolean()

    /** Return argument i as a closure, or throw an error if any other type.
     * @param i the index of the argument to test, 1 is the first argument
     * @return LuaClosure if argument i is a closure.
     * @exception LuaError if the argument is not a lua closure
     */
    fun checkclosure(i: Int): LuaClosure? = arg(i).checkclosure()

    /** Return argument i as a double, or throw an error if it cannot be converted to one.
     * @param i the index of the argument to test, 1 is the first argument
     * @return java double value if argument i is a number or string that converts to a number
     * @exception LuaError if the argument is not a number
     */
    fun checkdouble(i: Int): Double = arg(i).checknumber()!!.todouble()

    /** Return argument i as a function, or throw an error if an incompatible type.
     * @param i the index of the argument to test, 1 is the first argument
     * @return LuaValue that can be called if argument i is lua function or closure
     * @exception LuaError if the argument is not a lua function or closure
     */
    fun checkfunction(i: Int): LuaFunction? = arg(i).checkfunction()

    /** Return argument i as a java int value, discarding any fractional part, or throw an error if not a number.
     * @param i the index of the argument to test, 1 is the first argument
     * @return int value with fraction discarded and truncated if necessary if argument i is number
     * @exception LuaError if the argument is not a number
     */
    fun checkint(i: Int): Int = arg(i).checknumber()!!.toint()

    /** Return argument i as a java int value, or throw an error if not a number or is not representable by a java int.
     * @param i the index of the argument to test, 1 is the first argument
     * @return LuaInteger value that fits in a java int without rounding
     * @exception LuaError if the argument cannot be represented by a java int value
     */
    fun checkinteger(i: Int): LuaInteger? = arg(i).checkinteger()

    /** Return argument i as a java long value, discarding any fractional part, or throw an error if not a number.
     * @param i the index of the argument to test, 1 is the first argument
     * @return long value with fraction discarded and truncated if necessary if argument i is number
     * @exception LuaError if the argument is not a number
     */
    fun checklong(i: Int): Long = arg(i).checknumber()!!.tolong()

    /** Return argument i as a LuaNumber, or throw an error if not a number or string that can be converted to a number.
     * @param i the index of the argument to test, 1 is the first argument
     * @return LuaNumber if argument i is number or can be converted to a number
     * @exception LuaError if the argument is not a number
     */
    fun checknumber(i: Int): LuaNumber? = arg(i).checknumber()

    /** Return argument i as a java String if a string or number, or throw an error if any other type
     * @param i the index of the argument to test, 1 is the first argument
     * @return String value if argument i is a string or number
     * @exception LuaError if the argument is not a string or number
     */
    fun checkjstring(i: Int): String? = arg(i).checkjstring()

    /** Return argument i as a LuaString if a string or number, or throw an error if any other type
     * @param i the index of the argument to test, 1 is the first argument
     * @return LuaString value if argument i is a string or number
     * @exception LuaError if the argument is not a string or number
     */
    fun checkstring(i: Int): LuaString? = arg(i).checkstring()

    /** Return argument i as a LuaTable if a lua table, or throw an error if any other type.
     * @param i the index of the argument to test, 1 is the first argument
     * @return LuaTable value if a table
     * @exception LuaError if the argument is not a lua table
     */
    fun checktable(i: Int): LuaTable? = arg(i).checktable()

    /** Return argument i as a LuaThread if a lua thread, or throw an error if any other type.
     * @param i the index of the argument to test, 1 is the first argument
     * @return LuaThread value if a thread
     * @exception LuaError if the argument is not a lua thread
     */
    fun checkthread(i: Int): LuaThread? = arg(i).checkthread()

    /** Return argument i as a java Object if a userdata, or throw an error if any other type.
     * @param i the index of the argument to test, 1 is the first argument
     * @return java Object value if argument i is a userdata
     * @exception LuaError if the argument is not a userdata
     */
    fun checkuserdata(i: Int): Any? = arg(i).checkuserdata()

    /** Return argument i as a java Object if it is a userdata whose instance Class c or a subclass,
     * or throw an error if any other type.
     * @param i the index of the argument to test, 1 is the first argument
     * @param c the class to which the userdata instance must be assignable
     * @return java Object value if argument i is a userdata whose instance Class c or a subclass
     * @exception LuaError if the argument is not a userdata or from whose instance c is not assignable
     */
    fun checkuserdata(i: Int, c: KClass<*>): Any? = arg(i).checkuserdata(c)

    /** Return argument i as a LuaValue if it exists, or throw an error.
     * @param i the index of the argument to test, 1 is the first argument
     * @return LuaValue value if the argument exists
     * @exception LuaError if the argument does not exist.
     */
    fun checkvalue(i: Int): LuaValue = if (i <= narg()) arg(i) else LuaValue.argerror(i, "value expected")

    /** Return argument i as a LuaValue if it is not nil, or throw an error if it is nil.
     * @param i the index of the argument to test, 1 is the first argument
     * @return LuaValue value if the argument is not nil
     * @exception LuaError if the argument doesn't exist or evaluates to nil.
     */
    fun checknotnil(i: Int): LuaValue = arg(i).checknotnil()

    /** Performs test on argument i as a LuaValue when a user-supplied assertion passes, or throw an error.
     * Returns normally if the value of `test` is `true`, otherwise throws and argument error with
     * the supplied message, `msg`.
     * @param test user supplied assertion to test against
     * @param i the index to report in any error message
     * @param msg the error message to use when the test fails
     * @exception LuaError if the the value of `test` is `false`
     */
    fun argcheck(test: Boolean, i: Int, msg: String) { if (!test) LuaValue.argerror(i, msg) }

    /** Return true if there is no argument or nil at argument i.
     * @param i the index of the argument to test, 1 is the first argument
     * @return true if argument i contains either no argument or nil
     */
    fun isnoneornil(i: Int): Boolean = i > narg() || arg(i).isnil()

    /** Convert argument `i` to java boolean based on lua rules for boolean evaluation.
     * @param i the index of the argument to convert, 1 is the first argument
     * @return `false` if argument i is nil or false, otherwise `true`
     */
    fun toboolean(i: Int): Boolean = arg(i).toboolean()

    /** Return argument i as a java byte value, discarding any fractional part and truncating,
     * or 0 if not a number.
     * @param i the index of the argument to convert, 1 is the first argument
     * @return byte value with fraction discarded and truncated if necessary if argument i is number, otherwise 0
     */
    fun tobyte(i: Int): Byte = arg(i).tobyte()

    /** Return argument i as a java char value, discarding any fractional part and truncating,
     * or 0 if not a number.
     * @param i the index of the argument to convert, 1 is the first argument
     * @return char value with fraction discarded and truncated if necessary if argument i is number, otherwise 0
     */
    fun tochar(i: Int): Char = arg(i).tochar()

    /** Return argument i as a java double value or 0 if not a number.
     * @param i the index of the argument to convert, 1 is the first argument
     * @return double value if argument i is number, otherwise 0
     */
    fun todouble(i: Int): Double = arg(i).todouble()

    /** Return argument i as a java float value, discarding excess fractional part and truncating,
     * or 0 if not a number.
     * @param i the index of the argument to convert, 1 is the first argument
     * @return float value with excess fraction discarded and truncated if necessary if argument i is number, otherwise 0
     */
    fun tofloat(i: Int): Float = arg(i).tofloat()

    /** Return argument i as a java int value, discarding any fractional part and truncating,
     * or 0 if not a number.
     * @param i the index of the argument to convert, 1 is the first argument
     * @return int value with fraction discarded and truncated if necessary if argument i is number, otherwise 0
     */
    fun toint(i: Int): Int = arg(i).toint()

    /** Return argument i as a java long value, discarding any fractional part and truncating,
     * or 0 if not a number.
     * @param i the index of the argument to convert, 1 is the first argument
     * @return long value with fraction discarded and truncated if necessary if argument i is number, otherwise 0
     */
    fun tolong(i: Int): Long = arg(i).tolong()

    /** Return argument i as a java String based on the type of the argument.
     * @param i the index of the argument to convert, 1 is the first argument
     * @return String value representing the type
     */
    fun tojstring(i: Int): String = arg(i).tojstring()

    /** Return argument i as a java short value, discarding any fractional part and truncating,
     * or 0 if not a number.
     * @param i the index of the argument to convert, 1 is the first argument
     * @return short value with fraction discarded and truncated if necessary if argument i is number, otherwise 0
     */
    fun toshort(i: Int): Short = arg(i).toshort()

    /** Return argument i as a java Object if a userdata, or null.
     * @param i the index of the argument to convert, 1 is the first argument
     * @return java Object value if argument i is a userdata, otherwise null
     */
    fun touserdata(i: Int): Any? = arg(i).touserdata()

    /** Return argument i as a java Object if it is a userdata whose instance Class c or a subclass, or null.
     * @param i the index of the argument to convert, 1 is the first argument
     * @param c the class to which the userdata instance must be assignable
     * @return java Object value if argument i is a userdata whose instance Class c or a subclass, otherwise null
     */
    fun touserdata(i: Int, c: KClass<*>): Any? = arg(i).touserdata(c)

    /** Convert the list of varargs values to a human readable java String.
     * @return String value in human readable form such as {1,2}.
     */
    open fun tojstring(): String {
        val sb = Buffer()
        sb.append("(")
        var i = 1
        val n = narg()
        while (i <= n) {
            if (i > 1) sb.append(",")
            sb.append(arg(i).tojstring())
            i++
        }
        sb.append(")")
        return sb.tojstring()
    }

    /** Convert the value or values to a java String using Varargs.tojstring()
     * @return String value in human readable form.
     * @see Varargs.tojstring
     */
    override fun toString(): String = tojstring()

    /**
     * Create a `Varargs` instance containing arguments starting at index `start`
     * @param start the index from which to include arguments, where 1 is the first argument.
     * @return Varargs containing argument { start, start+1,  ... , narg-start-1 }
     */
    abstract fun subargs(start: Int): Varargs

    /**
     * Implementation of Varargs for use in the Varargs.subargs() function.
     * @see Varargs.subargs
     */
    internal class SubVarargs(private val v: Varargs, private val start: Int, private val end: Int) : Varargs() {
        override fun arg(i: Int): LuaValue {
            var i = i
            i += start - 1
            return if (i >= start && i <= end) v.arg(i) else LuaValue.NIL
        }

        override fun arg1(): LuaValue = v.arg(start)

        override fun narg(): Int = end + 1 - start

        override fun subargs(start: Int): Varargs {
            if (start == 1) return this
            val newstart = this.start + start - 1
            return if (start > 0) {
                when {
                    newstart >= this.end -> LuaValue.NONE
                    newstart == this.end -> v.arg(this.end)
                    else -> if (newstart == this.end - 1) PairVarargs(v.arg(this.end - 1), v.arg(this.end)) else SubVarargs(v, newstart, this.end)
                }
            } else {
                SubVarargs(v, newstart, this.end)
            }
        }
    }

    /** Varargs implemenation backed by two values.
     *
     *
     * This is an internal class not intended to be used directly.
     * Instead use the corresponding static method on LuaValue.
     *
     * @see LuaValue.varargsOf
     */
    /** Construct a Varargs from an two LuaValue.
     *
     *
     * This is an internal class not intended to be used directly.
     * Instead use the corresponding static method on LuaValue.
     *
     * @see LuaValue.varargsOf
     */
    internal class PairVarargs(private val v1: LuaValue, private val v2: Varargs) : Varargs() {
        override fun arg(i: Int): LuaValue = if (i == 1) v1 else v2.arg(i - 1)
        override fun narg(): Int = 1 + v2.narg()
        override fun arg1(): LuaValue = v1

        override fun subargs(start: Int): Varargs = when (start) {
            1 -> this
            2 -> v2
            else -> if (start > 2) v2.subargs(start - 1) else LuaValue.argerror(1, "start must be > 0")
        }
    }

    /** Varargs implemenation backed by an array of LuaValues
     *
     *
     * This is an internal class not intended to be used directly.
     * Instead use the corresponding static methods on LuaValue.
     *
     * @see LuaValue.varargsOf
     * @see LuaValue.varargsOf
     */
    /** Construct a Varargs from an array of LuaValue.
     *
     *
     * This is an internal class not intended to be used directly.
     * Instead use the corresponding static methods on LuaValue.
     *
     * @see LuaValue.varargsOf
     * @see LuaValue.varargsOf
     */
    class ArrayVarargs(private val v: Array, private val r: Varargs) : Varargs() {
        override fun arg(i: Int): LuaValue = if (i < 1) LuaValue.NIL else if (i <= v.size) v[i - 1] else r.arg(i - v.size)
        override fun narg(): Int = v.size + r.narg()
        override fun arg1(): LuaValue = if (v.size > 0) v[0] else r.arg1()

        override fun subargs(start: Int): Varargs = when {
            start <= 0 -> LuaValue.argerror(1, "start must be > 0")
            start == 1 -> this
            else -> if (start > v.size) r.subargs(start - v.size) else LuaValue.varargsOf(
                v,
                start - 1,
                v.size - (start - 1),
                r
            )
        }

        override fun copyto(dest: Array, offset: Int, length: Int) {
            val n = min(v.size, length)
            arraycopy(v, 0, dest, offset, n)
            r.copyto(dest, offset + n, length - n)
        }
    }

    /** Varargs implemenation backed by an array of LuaValues
     *
     *
     * This is an internal class not intended to be used directly.
     * Instead use the corresponding static methods on LuaValue.
     *
     * @see LuaValue.varargsOf
     * @see LuaValue.varargsOf
     */
    internal class ArrayPartVarargs : Varargs {
        private val offset: Int
        private val v: Array
        private val length: Int
        private val more: Varargs

        /** Construct a Varargs from an array of LuaValue.
         *
         *
         * This is an internal class not intended to be used directly.
         * Instead use the corresponding static methods on LuaValue.
         *
         * @see LuaValue.varargsOf
         */
        constructor(v: Array, offset: Int, length: Int) {
            this.v = v
            this.offset = offset
            this.length = length
            this.more = LuaValue.NONE
        }

        /** Construct a Varargs from an array of LuaValue and additional arguments.
         *
         *
         * This is an internal class not intended to be used directly.
         * Instead use the corresponding static method on LuaValue.
         *
         * @see LuaValue.varargsOf
         */
        constructor(v: Array, offset: Int, length: Int, more: Varargs) {
            this.v = v
            this.offset = offset
            this.length = length
            this.more = more
        }

        override fun arg(i: Int): LuaValue = if (i < 1) LuaValue.NIL else if (i <= length) v[offset + i - 1] else more.arg(i - length)
        override fun narg(): Int = length + more.narg()
        override fun arg1(): LuaValue = if (length > 0) v[offset] else more.arg1()

        override fun subargs(start: Int): Varargs = when {
            start <= 0 -> LuaValue.argerror(1, "start must be > 0")
            start == 1 -> this
            else -> if (start > length) more.subargs(start - length) else LuaValue.varargsOf(
                v,
                offset + start - 1,
                length - (start - 1),
                more
            )
        }

        override fun copyto(dest: Array, offset: Int, length: Int) {
            val n = min(this.length, length)
            arraycopy(this.v, this.offset, dest, offset, n)
            more.copyto(dest, offset + n, length - n)
        }
    }

    /** Copy values in a varargs into a destination array.
     * Internal utility method not intended to be called directly from user code.
     * @return Varargs containing same values, but flattened.
     */
    open fun copyto(dest: Array, offset: Int, length: Int) {
        for (i in 0 until length) dest[offset + i] = arg(i + 1)
    }

    /** Return Varargs that cannot be using a shared array for the storage, and is flattened.
     * Internal utility method not intended to be called directly from user code.
     * @return Varargs containing same values, but flattened and with a new array if needed.
     */
    fun dealias(): Varargs {
        val n = narg()
        return when (n) {
            0 -> LuaValue.NONE
            1 -> arg1()
            2 -> PairVarargs(arg1(), arg(2))
            else -> {
                val v = arrayOfNulls(n) as Array
                copyto(v, 0, n)
                ArrayVarargs(v, LuaValue.NONE)
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy