/******************************************************************************* * 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; /** * Class to encapsulate varargs values, either as part of a variable argument list, or multiple return values. * <p> * To construct varargs, use one of the static methods such as * {@code LuaValue.varargsOf(LuaValue,LuaValue)} * <p> * <p> * 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. * <p> * Varargs can also be derived from other varargs by appending to the front with a call * such as {@code LuaValue.varargsOf(LuaValue,Varargs)} * or by taking a portion of the args using {@code Varargs.subargs(int start)} * <p> * @see LuaValue#varargsOf(LuaValue[]) * @see LuaValue#varargsOf(LuaValue, Varargs) * @see LuaValue#varargsOf(LuaValue[], Varargs) * @see LuaValue#varargsOf(LuaValue, LuaValue, Varargs) * @see LuaValue#varargsOf(LuaValue[], int, int) * @see LuaValue#varargsOf(LuaValue[], int, int, Varargs) * @see LuaValue#subargs(int) */ public abstract class Varargs { /** * 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 public LuaValue arg( int i ); /** * Get the number of arguments, or 0 if there are none. * @return number of arguments. */ abstract public int narg(); /** * 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(int) * @see LuaValue#NIL */ abstract public LuaValue arg1(); /** * Evaluate any pending tail call and return result. * @return the evaluated tail call result */ public Varargs eval() { return this; } /** * Return true if this is a TailcallVarargs * @return true if a tail call, false otherwise */ public boolean isTailcall() { return false; } // ----------------------------------------------------------------------- // utilities to get specific arguments and type-check them. // ----------------------------------------------------------------------- /** Gets the type of argument {@code 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 * */ public int type(int i) { return 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 * */ public boolean isnil(int i) { return 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 * */ public boolean isfunction(int i) { return 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 * */ public boolean isnumber(int i) { return 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 * */ public boolean isstring(int i) { return 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 * */ public boolean istable(int i) { return 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 * */ public boolean isthread(int i) { return 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 * */ public boolean isuserdata(int i) { return 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 * */ public boolean isvalue(int i) { return i>0 && i<=narg(); } /** Return argument i as a boolean value, {@code 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 * */ public boolean optboolean(int i, boolean defval) { return arg(i).optboolean(defval); } /** Return argument i as a closure, {@code 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 * */ public LuaClosure optclosure(int i, LuaClosure defval) { return arg(i).optclosure(defval); } /** Return argument i as a double, {@code 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 * */ public double optdouble(int i, double defval) { return arg(i).optdouble(defval); } /** Return argument i as a function, {@code 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 * */ public LuaFunction optfunction(int i, LuaFunction defval) { return arg(i).optfunction(defval); } /** Return argument i as a java int value, discarding any fractional part, {@code 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 * */ public int optint(int i, int defval) { return arg(i).optint(defval); } /** Return argument i as a java int value, {@code 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 * */ public LuaInteger optinteger(int i, LuaInteger defval) { return arg(i).optinteger(defval); } /** Return argument i as a java long value, discarding any fractional part, {@code 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 * */ public long optlong(int i, long defval) { return arg(i).optlong(defval); } /** Return argument i as a LuaNumber, {@code 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 * */ public LuaNumber optnumber(int i, LuaNumber defval) { return arg(i).optnumber(defval); } /** Return argument i as a java String if a string or number, {@code 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 * */ public String optjstring(int i, String defval) { return arg(i).optjstring(defval); } /** Return argument i as a LuaString if a string or number, {@code 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 * */ public LuaString optstring(int i, LuaString defval) { return arg(i).optstring(defval); } /** Return argument i as a LuaTable if a lua table, {@code 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 * */ public LuaTable opttable(int i, LuaTable defval) { return arg(i).opttable(defval); } /** Return argument i as a LuaThread if a lua thread, {@code 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 * */ public LuaThread optthread(int i, LuaThread defval) { return arg(i).optthread(defval); } /** Return argument i as a java Object if a userdata, {@code 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 * */ public Object optuserdata(int i, Object defval) { return arg(i).optuserdata(defval); } /** Return argument i as a java Object if it is a userdata whose instance Class c or a subclass, * {@code 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 * */ public Object optuserdata(int i, Class c, Object defval) { return arg(i).optuserdata(c,defval); } /** Return argument i as a LuaValue if it exists, or {@code 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. * */ public LuaValue optvalue(int i, LuaValue defval) { return i>0 && i<=narg()? arg(i): 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 * */ public boolean checkboolean(int i) { return 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 * */ public LuaClosure checkclosure(int i) { return 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 * */ public double checkdouble(int i) { return 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 * */ public LuaFunction checkfunction(int i) { return 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 * */ public int checkint(int i) { return 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 * */ public LuaInteger checkinteger(int i) { return 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 * */ public long checklong(int i) { return 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 * */ public LuaNumber checknumber(int i) { return 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 * */ public String checkjstring(int i) { return 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 * */ public LuaString checkstring(int i) { return 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 * */ public LuaTable checktable(int i) { return 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 * */ public LuaThread checkthread(int i) { return 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 * */ public Object checkuserdata(int i) { return 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 * */ public Object checkuserdata(int i,Class c) { return 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. * */ public LuaValue checkvalue(int i) { return i<=narg()? arg(i): 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. * */ public LuaValue checknotnil(int i) { return arg(i).checknotnil(); } /** Return argument i as a LuaValue when a user-supplied assertion passes, or throw an error. * @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 * @return LuaValue value if the value of {@code test} is {@code true} * @exception LuaError if the the value of {@code test} is {@code false} * */ public void argcheck(boolean test, int i, String msg) { 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 * */ public boolean isnoneornil(int i) { return i>narg() || arg(i).isnil(); } /** Convert argument {@code 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 {@code false} if argument i is nil or false, otherwise {@code true} * */ public boolean toboolean(int i) { return 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 * */ public byte tobyte(int i) { return 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 * */ public char tochar(int i) { return 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 * */ public double todouble(int i) { return 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 * */ public float tofloat(int i) { return 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 * */ public int toint(int i) { return 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 * */ public long tolong(int i) { return 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 * */ public String tojstring(int i) { return 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 * */ public short toshort(int i) { return 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 * */ public Object touserdata(int i) { return 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 * */ public Object touserdata(int i,Class c) { return 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}. */ public String tojstring() { Buffer sb = new Buffer(); sb.append( "(" ); for ( int i=1,n=narg(); i<=n; i++ ) { if (i>1) sb.append( "," ); sb.append( arg(i).tojstring() ); } 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() */ public String toString() { return tojstring(); } /** * Create a {@code Varargs} instance containing arguments starting at index {@code 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 public Varargs subargs(final int start); /** * Implementation of Varargs for use in the Varargs.subargs() function. * @see Varargs#subargs(int) */ static class SubVarargs extends Varargs { private final Varargs v; private final int start; private final int end; public SubVarargs(Varargs varargs, int start, int end) { this.v = varargs; this.start = start; this.end = end; } public LuaValue arg(int i) { i += start-1; return i>=start && i<=end? v.arg(i): LuaValue.NIL; } public LuaValue arg1() { return v.arg(start); } public int narg() { return end+1-start; } public Varargs subargs(final int start) { if (start == 1) return this; final int newstart = this.start + start - 1; if (start > 0) { if (newstart >= this.end) return LuaValue.NONE; if (newstart == this.end) return v.arg(this.end); if (newstart == this.end-1) return new Varargs.PairVarargs(v.arg(this.end-1), v.arg(this.end)); return new SubVarargs(v, newstart, this.end); } return new SubVarargs(v, newstart, this.end); } } /** Varargs implemenation backed by two values. * <p> * This is an internal class not intended to be used directly. * Instead use the corresponding static method on LuaValue. * * @see LuaValue#varargsOf(LuaValue, Varargs) */ static final class PairVarargs extends Varargs { private final LuaValue v1; private final Varargs v2; /** Construct a Varargs from an two LuaValue. * <p> * This is an internal class not intended to be used directly. * Instead use the corresponding static method on LuaValue. * * @see LuaValue#varargsOf(LuaValue, Varargs) */ PairVarargs(LuaValue v1, Varargs v2) { this.v1 = v1; this.v2 = v2; } public LuaValue arg(int i) { return i==1? v1: v2.arg(i-1); } public int narg() { return 1+v2.narg(); } public LuaValue arg1() { return v1; } public Varargs subargs(final int start) { if (start == 1) return this; if (start == 2) return v2; if (start > 2) return v2.subargs(start - 1); return LuaValue.argerror(1, "start must be > 0"); } } /** Varargs implemenation backed by an array of LuaValues * <p> * This is an internal class not intended to be used directly. * Instead use the corresponding static methods on LuaValue. * * @see LuaValue#varargsOf(LuaValue[]) * @see LuaValue#varargsOf(LuaValue[], Varargs) */ static final class ArrayVarargs extends Varargs { private final LuaValue[] v; private final Varargs r; /** Construct a Varargs from an array of LuaValue. * <p> * This is an internal class not intended to be used directly. * Instead use the corresponding static methods on LuaValue. * * @see LuaValue#varargsOf(LuaValue[]) * @see LuaValue#varargsOf(LuaValue[], Varargs) */ ArrayVarargs(LuaValue[] v, Varargs r) { this.v = v; this.r = r ; for (int i = 0; i < v.length; ++i) if (v[i] == null) throw new IllegalArgumentException("nulls in array"); } public LuaValue arg(int i) { return i < 1 ? LuaValue.NIL: i <= v.length? v[i - 1]: r.arg(i-v.length); } public int narg() { return v.length+r.narg(); } public LuaValue arg1() { return v.length>0? v[0]: r.arg1(); } public Varargs subargs(int start) { if (start <= 0) LuaValue.argerror(1, "start must be > 0"); if (start == 1) return this; if (start > v.length) return r.subargs(start - v.length); return LuaValue.varargsOf(v, start - 1, v.length - (start - 1), r); } } /** Varargs implemenation backed by an array of LuaValues * <p> * This is an internal class not intended to be used directly. * Instead use the corresponding static methods on LuaValue. * * @see LuaValue#varargsOf(LuaValue[], int, int) * @see LuaValue#varargsOf(LuaValue[], int, int, Varargs) */ static final class ArrayPartVarargs extends Varargs { private final int offset; private final LuaValue[] v; private final int length; private final Varargs more; /** Construct a Varargs from an array of LuaValue. * <p> * This is an internal class not intended to be used directly. * Instead use the corresponding static methods on LuaValue. * * @see LuaValue#varargsOf(LuaValue[], int, int) */ ArrayPartVarargs(LuaValue[] v, int offset, int length) { this.v = v; this.offset = offset; this.length = length; this.more = LuaValue.NONE; } /** Construct a Varargs from an array of LuaValue and additional arguments. * <p> * This is an internal class not intended to be used directly. * Instead use the corresponding static method on LuaValue. * * @see LuaValue#varargsOf(LuaValue[], int, int, Varargs) */ public ArrayPartVarargs(LuaValue[] v, int offset, int length, Varargs more) { this.v = v; this.offset = offset; this.length = length; this.more = more; } public LuaValue arg(final int i) { return i < 1? LuaValue.NIL: i <= length? v[offset+i-1]: more.arg(i-length); } public int narg() { return length + more.narg(); } public LuaValue arg1() { return length>0? v[offset]: more.arg1(); } public Varargs subargs(int start) { if (start <= 0) LuaValue.argerror(1, "start must be > 0"); if (start == 1) return this; if (start > length) return more.subargs(start - length); return LuaValue.varargsOf(v, offset + start - 1, length - (start - 1), more); } } }