Type coercion for luajava package, make luajava an "addon"

This commit is contained in:
James Roseborough
2007-06-24 15:04:19 +00:00
parent 1d7793f8e6
commit 93fc4699a9
18 changed files with 574 additions and 142 deletions

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<classpath> <classpath>
<classpathentry kind="src" path="src/main/java"/> <classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="src" path="src/addon/java"/>
<classpathentry kind="src" path="src/test/java"/> <classpathentry kind="src" path="src/test/java"/>
<classpathentry kind="src" path="src/test/res"/> <classpathentry kind="src" path="src/test/res"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>

View File

@@ -0,0 +1,65 @@
package lua.addon.luajava;
import java.util.HashMap;
import java.util.Map;
import lua.addon.luajava.LuaJava.LInstance;
import lua.value.LBoolean;
import lua.value.LDouble;
import lua.value.LInteger;
import lua.value.LNil;
import lua.value.LString;
import lua.value.LValue;
public class CoerceJavaToLua {
public static interface Coercion {
public LValue coerce( Object javaValue );
};
private static Map<Class,Coercion> COERCIONS = new HashMap<Class,Coercion>();
static {
Coercion boolCoercion = new Coercion() {
public LValue coerce( Object javaValue ) {
Boolean b = (Boolean) javaValue;
return b.booleanValue()? LBoolean.TRUE: LBoolean.FALSE;
}
} ;
Coercion intCoercion = new Coercion() {
public LValue coerce( Object javaValue ) {
Number n = (Number) javaValue;
return new LInteger( n.intValue() );
}
} ;
Coercion doubleCoercion = new Coercion() {
public LValue coerce( Object javaValue ) {
Number n = (Number) javaValue;
return new LDouble( n.doubleValue() );
}
} ;
Coercion stringCoercion = new Coercion() {
public LValue coerce( Object javaValue ) {
return new LString( javaValue.toString() );
}
} ;
COERCIONS.put( Boolean.class, boolCoercion );
COERCIONS.put( Byte.class, intCoercion );
COERCIONS.put( Short.class, intCoercion );
COERCIONS.put( Integer.class, intCoercion );
COERCIONS.put( Float.class, doubleCoercion );
COERCIONS.put( Double.class, doubleCoercion );
COERCIONS.put( String.class, stringCoercion );
}
public static LValue coerce(Object o) {
if ( o == null )
return LNil.NIL;
Class clazz = o.getClass();
Coercion c = COERCIONS.get( clazz );
if ( c != null )
return c.coerce( o );
return new LInstance( o, o.getClass() );
}
}

View File

@@ -0,0 +1,144 @@
package lua.addon.luajava;
import java.util.HashMap;
import java.util.Map;
import lua.StackState;
import lua.addon.luajava.LuaJava.LInstance;
import lua.value.LBoolean;
import lua.value.LDouble;
import lua.value.LInteger;
import lua.value.LNil;
import lua.value.LNumber;
import lua.value.LString;
import lua.value.LValue;
public class CoerceLuaToJava {
public static interface Coercion {
public Object coerce( LValue value );
public int score( LValue value );
};
private static Map<Class,Coercion> COERCIONS = new HashMap<Class,Coercion>();
private static Coercion OBJECT_COERCION;
static {
Coercion boolCoercion = new Coercion() {
public Object coerce(LValue value) {
return value.luaAsBoolean()? Boolean.TRUE: Boolean.FALSE;
}
public int score(LValue value) {
if ( value instanceof LBoolean || value == LNil.NIL )
return 0;
if ( value instanceof LNumber )
return 1;
return 4;
}
};
Coercion intCoercion = new Coercion() {
public Object coerce(LValue value) {
return Integer.valueOf( value.luaAsInt() );
}
public int score(LValue value) {
if ( value instanceof LInteger )
return 0;
if ( value instanceof LNumber )
return 1;
if ( value instanceof LBoolean || value == LNil.NIL )
return 2;
return 4;
}
};
Coercion stringCoercion = new Coercion() {
public Object coerce(LValue value) {
return value.luaAsString();
}
public int score(LValue value) {
if ( value instanceof LInstance )
return 0;
return 1;
}
};
Coercion objectCoercion = new Coercion() {
public Object coerce(LValue value) {
if ( value instanceof LInstance )
return ((LInstance)value).instance;
if ( value instanceof LString )
return value.luaAsString();
if ( value instanceof LInteger )
return Integer.valueOf(value.luaAsInt());
if ( value instanceof LDouble )
return Double.valueOf(value.luaAsDouble());
if ( value instanceof LBoolean )
return Boolean.valueOf(value.luaAsBoolean());
if ( value == LNil.NIL )
return null;
return value;
}
public int score(LValue value) {
if ( value instanceof LString )
return 0;
return 0x10;
}
};
COERCIONS.put( Boolean.TYPE, boolCoercion );
COERCIONS.put( Boolean.class, boolCoercion );
COERCIONS.put( Byte.TYPE, intCoercion );
COERCIONS.put( Byte.class, intCoercion );
COERCIONS.put( Short.TYPE, intCoercion );
COERCIONS.put( Short.class, intCoercion );
COERCIONS.put( Integer.TYPE, intCoercion );
COERCIONS.put( Integer.class, intCoercion );
COERCIONS.put( Long.TYPE, intCoercion );
COERCIONS.put( Long.class, intCoercion );
COERCIONS.put( String.class, stringCoercion );
COERCIONS.put( Object.class, objectCoercion );
}
static Object coerceArg(LValue v, Class type) {
Coercion co = COERCIONS.get( type );
if ( co != null )
return co.coerce( v );
if ( v instanceof LInstance )
return ((LInstance) v).instance;
return v;
}
static Object[] coerceArgs(StackState state, int base, int nargs, Class[] parameterTypes) {
int n = parameterTypes.length;
Object[] args = new Object[n];
for ( int i=0; i<n && i<nargs; i++ )
args[i] = coerceArg( state.stack[base+i], parameterTypes[i] );
return args;
}
/*
* Score parameter types for match with supplied parameter list
*
* 1) exact number of args
* 2) java has more args
* 3) java has less args
* 4) types coerce well
*/
static int scoreParamTypes(LValue[] stack, int base, int nargs, Class[] paramTypes) {
int njava = paramTypes.length;
int score = (njava == nargs? 0: njava > nargs? 0x4000: 0x8000);
for ( int i=0; i<nargs && i<njava; i++ ) {
LValue v = stack[base+i];
Class c = paramTypes[i];
Coercion co = COERCIONS.get( c );
if ( co != null ) {
score += co.score( v );
} else if ( v instanceof LInstance ) {
Object o = ((LInstance) v).instance;
if ( ! c.isAssignableFrom(o.getClass()) )
score += 0x10000;
} else {
score += 0x100;
}
}
return score;
}
}

View File

@@ -0,0 +1,182 @@
package lua.addon.luajava;
/** LuaJava-like bindings to Java scripting.
*
* TODO: coerce types on way in and out, pick method base on arg count ant types.
*/
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import lua.GlobalState;
import lua.StackState;
import lua.value.LFunction;
import lua.value.LString;
import lua.value.LTable;
import lua.value.LValue;
public final class LuaJava extends LFunction {
public static void install() {
LTable luajava = new LTable();
for ( int i=0; i<NAMES.length; i++ )
luajava.m_hash.put( new LString( NAMES[i] ), new LuaJava(i) );
GlobalState.getGlobalsTable().m_hash.put( new LString( "luajava" ), luajava );
}
private static final int NEWINSTANCE = 0;
private static final int BINDCLASS = 1;
private static final int NEW = 2;
private static final int CREATEPROXY = 3;
private static final int LOADLIB = 4;
private static final String[] NAMES = {
"newInstance",
"bindClass",
"new",
"createProxy",
"loadLib" };
private int id;
private LuaJava( int id ) {
this.id = id;
}
public String toString() {
return "luajava."+NAMES[id];
}
// perform a lua call
public void luaStackCall(StackState state, int base, int top, int nresults) {
String className;
switch ( id ) {
case BINDCLASS:
className = state.stack[base+1].luaAsString();
try {
Class clazz = Class.forName(className);
state.stack[base] = new LInstance( clazz, clazz );
state.top = base+1;
} catch (Exception e) {
throw new RuntimeException(e);
}
break;
case NEWINSTANCE:
className = state.stack[base+1].luaAsString();
try {
Class clazz = Class.forName(className);
Constructor[] cons = clazz.getConstructors();
Constructor con = cons[0];
Class[] paramTypes = con.getParameterTypes();
int paramsBase = base + 2;
int nargs = top - paramsBase;
int score = CoerceLuaToJava.scoreParamTypes( state.stack, paramsBase, nargs, paramTypes );
for ( int i=1; i<cons.length; i++ ) {
Constructor c = cons[i];
Class[] p = c.getParameterTypes();
int s = CoerceLuaToJava.scoreParamTypes( state.stack, paramsBase, nargs, p );
if ( s < score ) {
con = c;
paramTypes = p;
score = s;
}
}
Object[] args = CoerceLuaToJava.coerceArgs( state, paramsBase, nargs, paramTypes );
Object o = con.newInstance( args );
state.stack[base] = new LInstance( o, clazz );
state.top = base+1;
} catch (Exception e) {
throw new RuntimeException(e);
}
break;
default:
luaUnsupportedOperation();
}
if (nresults >= 0)
state.adjustTop(base + nresults);
}
static class LInstance extends LValue {
Object instance;
private Class clazz;
public LInstance(Object o, Class clazz) {
this.instance = o;
this.clazz = clazz;
}
public String luaAsString() {
return instance.toString();
}
public void luaGetTable(StackState state, int base, LValue table, LValue key) {
final String s = key.luaAsString();
try {
Field f = clazz.getField(s);
Object o = f.get(instance);
LValue v = CoerceJavaToLua.coerce( o );
state.stack[base] = v;
state.top = base + 1;
} catch (NoSuchFieldException nsfe) {
state.stack[base] = new LMethod(instance,clazz,s);
state.top = base + 1;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void luaSetTable(StackState state, int base, LValue table, LValue key, LValue val) {
Class c = instance.getClass();
String s = key.luaAsString();
try {
Field f = c.getField(s);
Object v = CoerceLuaToJava.coerceArg(val, f.getType());
f.set(instance,v);
state.top = base;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
private static final class LMethod extends LFunction {
private final Object instance;
private final Class clazz;
private final String s;
private LMethod(Object instance, Class clazz, String s) {
this.instance = instance;
this.clazz = clazz;
this.s = s;
}
public String toString() {
return clazz.getName()+"."+s+"()";
}
public void luaStackCall(StackState state, int base, int top, int nresults) {
try {
Method[] meths = clazz.getMethods();
Method meth = null;
Class[] paramTypes = null;
int score = Integer.MAX_VALUE;
int paramsBase = base + 2;
int nargs = top - paramsBase;
for ( int i=0; i<meths.length; i++ ) {
Method m = meths[i];
String name = m.getName();
if ( s.equals(name) ) {
Class[] p = m.getParameterTypes();
int s = CoerceLuaToJava.scoreParamTypes( state.stack, paramsBase, nargs, p );
if ( s < score ) {
meth = m;
paramTypes = p;
score = s;
}
}
}
Object[] args = CoerceLuaToJava.coerceArgs( state, paramsBase, nargs, paramTypes );
Object result = meth.invoke( instance, args );
state.stack[base] = CoerceJavaToLua.coerce(result);
state.top = base + 1;
state.adjustTop(base+nresults);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}

View File

@@ -4,7 +4,6 @@ import java.util.Hashtable;
import lua.value.LString; import lua.value.LString;
import lua.value.LTable; import lua.value.LTable;
import lua.value.LValue;
/** /**
** `global state', shared by all threads of this state ** `global state', shared by all threads of this state
@@ -42,11 +41,15 @@ public class GlobalState {
// TString *tmname[TM_N]; /* array with tag-method names */ // TString *tmname[TM_N]; /* array with tag-method names */
// } global_State; // } global_State;
// //
public static LValue getGlobalsTable() { private static LTable _G;
LTable table = new LTable();
Builtin.addBuiltins( table ); static {
LuaJava.addBuiltins( table ); _G = new LTable();
table.m_hash.put(new LString("_G"), table); Builtin.addBuiltins( _G );
return table; _G .m_hash.put(new LString("_G"), _G );
}
public static LTable getGlobalsTable() {
return _G;
} }
} }

View File

@@ -1,125 +0,0 @@
/**
*
*/
package lua;
/** LuaJava-like bindings to Java scripting.
*
* TODO: coerce types on way in and out, pick method base on arg count ant types.
*/
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import lua.value.LFunction;
import lua.value.LString;
import lua.value.LTable;
import lua.value.LValue;
final class LuaJava extends LFunction {
static void addBuiltins(LTable table) {
LTable luajava = new LTable();
for ( int i=0; i<NAMES.length; i++ )
luajava.m_hash.put( new LString( NAMES[i] ), new LuaJava(i) );
table.m_hash.put( new LString( "luajava" ), luajava );
}
private static final int NEWINSTANCE = 0;
private static final int BINDCLASS = 1;
private static final int NEW = 2;
private static final int CREATEPROXY = 3;
private static final int LOADLIB = 4;
private static final String[] NAMES = { "newInstance", "bindClass", "new", "createProxy", "loadLib" };
private int id;
private LuaJava( int id ) {
this.id = id;
}
public String toString() {
return "builtin."+NAMES[id];
}
// perform a lua call
public void luaStackCall(StackState state, int base, int top, int nresults) {
switch ( id ) {
case NEWINSTANCE:
String className = state.stack[base+1].luaAsString();
try {
Class c = Class.forName(className);
Object o = c.newInstance();
state.stack[base] = new LInstance( o );
state.top = base+1;
} catch (Exception e) {
throw new RuntimeException(e);
}
break;
default:
luaUnsupportedOperation();
}
if (nresults >= 0)
state.adjustTop(base + nresults);
}
static class LInstance extends LValue {
private Object instance;
public LInstance(Object o) {
this.instance = o;
}
public String luaAsString() {
return instance.toString();
}
public void luaGetTable(StackState state, int base, LValue table, LValue key) {
Class c = instance.getClass();
final String s = key.luaAsString();
try {
Field f = c.getField(s);
Object o = f.get(instance);
String v = String.valueOf(o);
state.stack[base] = new LString( v );
state.top = base + 1;
} catch (NoSuchFieldException nsfe) {
state.stack[base] = new LMethod(instance,s);
state.top = base + 1;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void luaSetTable(StackState state, int base, LValue table, LValue key, LValue val) {
Class c = instance.getClass();
String s = key.luaAsString();
try {
Field f = c.getField(s);
String v = val.luaAsString();
f.set(instance,v);
state.top = base;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
private static final class LMethod extends LFunction {
private final Object instance;
private final String s;
private LMethod(Object instance, String s) {
this.instance = instance;
this.s = s;
}
public void luaStackCall(StackState state, int base, int top, int nresults) {
Class c = instance.getClass();
try {
Method m = c.getMethod(s,new Class[0]);
Object o = m.invoke(instance,new Object[0]);
String v = String.valueOf(o);
state.stack[base] = new LString( v );
state.top = base + 1;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}

View File

@@ -40,7 +40,7 @@ public class LDouble extends LNumber {
case Lua.OP_MUL: return new LDouble( lhs * rhs ); case Lua.OP_MUL: return new LDouble( lhs * rhs );
case Lua.OP_DIV: return new LDouble( lhs / rhs ); case Lua.OP_DIV: return new LDouble( lhs / rhs );
case Lua.OP_MOD: return new LDouble( lhs % rhs ); case Lua.OP_MOD: return new LDouble( lhs % rhs );
case Lua.OP_POW: return new LDouble( Math.pow(lhs, rhs) ); // case Lua.OP_POW: return new LDouble( Math.pow(lhs, rhs) );
} }
return luaUnsupportedOperation(); return luaUnsupportedOperation();
} }
@@ -49,6 +49,10 @@ public class LDouble extends LNumber {
return (int) m_value; return (int) m_value;
} }
public double luaAsDouble() {
return m_value;
}
// binary compares on integers, first dispatch // binary compares on integers, first dispatch
public boolean luaBinCmpUnknown(int opcode, LValue lhs) { public boolean luaBinCmpUnknown(int opcode, LValue lhs) {
return lhs.luaBinCmpDouble( opcode, this.m_value ); return lhs.luaBinCmpDouble( opcode, this.m_value );

View File

@@ -35,7 +35,7 @@ public class LInteger extends LNumber {
case Lua.OP_MUL: return new LInteger( m_value * rhs ); case Lua.OP_MUL: return new LInteger( m_value * rhs );
case Lua.OP_DIV: return new LInteger( m_value / rhs ); case Lua.OP_DIV: return new LInteger( m_value / rhs );
case Lua.OP_MOD: return new LInteger( m_value % rhs ); case Lua.OP_MOD: return new LInteger( m_value % rhs );
case Lua.OP_POW: return new LInteger( (int) Math.pow(m_value, rhs) ); // case Lua.OP_POW: return new LInteger( (int) Math.pow(m_value, rhs) );
} }
return luaUnsupportedOperation(); return luaUnsupportedOperation();
} }

View File

@@ -6,17 +6,23 @@ import lua.StackState;
public class LString extends LValue { public class LString extends LValue {
final String m_string; final String m_string;
final int m_hash;
public LString(String string) { public LString(String string) {
this.m_string = string; this.m_string = string;
this.m_hash = string.hashCode();
} }
public boolean equals(Object o) { public boolean equals(Object o) {
return o != null && o instanceof LString && m_string.equals(((LString)o).m_string); if ( o != null && o instanceof LString ) {
LString s = (LString) o;
return m_hash == s.m_hash && m_string.equals(s.m_string);
}
return false;
} }
public int hashCode() { public int hashCode() {
return m_string.hashCode(); return m_hash;
} }
// TODO: what to do with LuaState? // TODO: what to do with LuaState?

View File

@@ -7,7 +7,7 @@ abstract
public class LValue { public class LValue {
protected static LValue luaUnsupportedOperation() { protected static LValue luaUnsupportedOperation() {
throw new java.lang.UnsupportedOperationException(); throw new java.lang.RuntimeException( "not supported" );
} }
public String id() { public String id() {
@@ -106,6 +106,11 @@ public class LValue {
return 0; return 0;
} }
/** Return value as a double */
public double luaAsDouble() {
return luaAsInt();
}
/** Arithmetic negative */ /** Arithmetic negative */
public LValue luaUnaryMinus() { public LValue luaUnaryMinus() {
return luaUnsupportedOperation(); return luaUnsupportedOperation();

View File

@@ -0,0 +1,49 @@
import java.io.IOException;
import java.io.InputStream;
import lua.GlobalState;
import lua.StackState;
import lua.addon.luajava.LuaJava;
import lua.io.Closure;
import lua.io.LoadState;
import lua.io.Proto;
import lua.value.LString;
/**
* Program to run a compiled lua chunk for test purposes,
* but with the LuaJava add-ons added in
*
* @author jim_roseborough
*/
public class LuaJavaAppRunner {
public static void main( String[] args ) throws IOException {
// add LuaJava bindings
LuaJava.install();
// get script name
String script = (args.length>0? args[0]: "/swingapp.luac");
System.out.println("loading '"+script+"'");
// new lua state
StackState state = new StackState();
// push args onto stack
for ( int i=1; i<args.length; i++ )
state.push(new LString(args[i]));
// load the file
InputStream is = LuaJavaAppRunner.class.getResourceAsStream( script );
Proto p = LoadState.undump(state, is, script);
// create closure to execute
Closure c = new Closure( state, p );
state.push( c );
for ( int i=0; i<args.length; i++ )
state.push( new LString(args[i]) );
state.docall(args.length, 0);
}
}

View File

@@ -1,5 +1,4 @@
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@@ -19,7 +18,7 @@ public class LuacRunner {
public static void main( String[] args ) throws IOException { public static void main( String[] args ) throws IOException {
// get script name // get script name
String script = (args.length>0? args[0]: "src/test/res/test1.luac"); String script = (args.length>0? args[0]: "/test1.luac");
System.out.println("loading '"+script+"'"); System.out.println("loading '"+script+"'");
// new lua state // new lua state
@@ -30,7 +29,7 @@ public class LuacRunner {
state.push(new LString(args[i])); state.push(new LString(args[i]));
// load the file // load the file
InputStream is = new FileInputStream( script ); InputStream is = LuacRunner.class.getResourceAsStream( script );
Proto p = LoadState.undump(state, is, script); Proto p = LoadState.undump(state, is, script);
// create closure to execute // create closure to execute

View File

@@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
LUA_HOME=/cygdrive/c/programs/lua5.1 LUA_HOME=/cygdrive/c/programs/lua5.1
TESTS="test1 test2 test3 test4 test5" TESTS="test1 test2 test3 test4 test5 swingapp"
TESTS="test7" TESTS="swingapp"
for x in $TESTS for x in $TESTS
do do
echo compiling $x echo compiling $x

20
src/test/res/swingapp.lua Normal file
View File

@@ -0,0 +1,20 @@
frame = luajava.newInstance( "javax.swing.JFrame", "Texts" );
pane = luajava.newInstance( "javax.swing.JPanel" );
borderFactory = luajava.bindClass( "javax.swing.BorderFactory" )
border = borderFactory:createEmptyBorder( 30, 30, 10, 30 )
pane:setBorder( border )
label = luajava.newInstance( "javax.swing.JLabel", "This is a Label" );
layout = luajava.newInstance( "java.awt.GridLayout", 2, 2 );
pane:setLayout( layout )
pane:add( label )
pane:setBounds( 20, 30, 10, 30 )
borderLayout = luajava.bindClass( "java.awt.BorderLayout" )
frame:getContentPane():add(pane, borderLayout.CENTER )
jframe = luajava.bindClass( "javax.swing.JFrame" )
frame:setDefaultCloseOperation(jframe.EXIT_ON_CLOSE)
frame:pack()
frame:setVisible(true)

BIN
src/test/res/swingapp.luac Normal file

Binary file not shown.

View File

@@ -1,5 +1,84 @@
for cycle = 1,100 do
a = 123 + 456 a = 123 + 456
print( a ) print( a )
i = 777
while i<780 do
print(i)
i = i+1
end
a,b = 0,1
while true do -- infinite loop
print( b )
a,b = b,a+b
if a>10 then break end -- exit the loop if the condition is true
end
for count = 336,330,-2 do print(count) end -- numerical iteration
function sum(a,b,c,d) -- "sum" method
local d = d or 0
return a+b+c+d -- return sum
end
print( sum( 1, 2, 3, 4 ) )
print( sum( 5, 6, 7 ) )
print( sum( 9, 10, 11, 12, 13, 14 ) )
print( sum( sum(1,2,3,4), sum(5,6,7), sum(9,10,11,12,13,14), 15 ) )
function f0() print( "f0:" ) end
function f1(a) print( "f1:", a ) end
function f2(a,b) print( "f2:", a, b ) end
function f3(a,b,c) print( "f3:", a, b, c ) end
function f4(a,b,c,d) print( "f4:", a, b, c, d ) end
f0() f0( "a1/1" ) f0( "a1/2", "a2/2" ) f0( "a1/3", "a2/3", "a3/3" ) f0( "a1/4", "a2/4", "a3/4", "a4/4" )
f1() f1( "a1/1" ) f1( "a1/2", "a2/2" ) f1( "a1/3", "a2/3", "a3/3" ) f1( "a1/4", "a2/4", "a3/4", "a4/4" )
f2() f2( "a1/1" ) f2( "a1/2", "a2/2" ) f2( "a1/3", "a2/3", "a3/3" ) f2( "a1/4", "a2/4", "a3/4", "a4/4" )
f3() f3( "a1/1" ) f3( "a1/2", "a2/2" ) f3( "a1/3", "a2/3", "a3/3" ) f3( "a1/4", "a2/4", "a3/4", "a4/4" )
f4() f4( "a1/1" ) f4( "a1/2", "a2/2" ) f4( "a1/3", "a2/3", "a3/3" ) f4( "a1/4", "a2/4", "a3/4", "a4/4" )
function g0(a,b,c,d) return end
function g1(a,b,c,d) return d end
function g2(a,b,c,d) return c, d end
function g3(a,b,c,d) return b, c, d end
function g4(a,b,c,d) return a, b, c, d end
z = g0("c0.1/4", "c0.2/4", "c0.3/4", "c0.4/4")
print( "z0:", z )
z = g2("c2.1/4", "c2.2/4", "c2.3/4", "c2.4/4")
print( "z2:", z )
z = g4("c4.1/4", "c4.2/4", "c4.3/4", "c4.4/4")
print( "z4:", z )
a,b,c,d = g0( "c0.1/4", "c0.2/4", "c0.3/4", "c0.4/4" )
print( "g0:", a, b, c, d, "(eol)" )
a,b,c,d = g2( "b2.1/4", "b2.2/4", "b2.3/4", "b2.4/4" )
print( "g2:", a, b, c, d, "(eol)" )
a,b,c,d = g4( "b4.1/4", "b4.2/4", "b4.3/4", "b4.4/4" )
print( "g4:", a, b, c, d, "(eol)" )
function func(a,b,c)
return a, b, c
end
print( func(11, 12, 13) )
print( func(23, 22, 21) )
print( func(func(32,33,34), func(45,46,47), func(58,59,50)) )
function p(a,...)
print("a",a)
-- print("...",...)
-- print("...,a",...,a)
-- print("a,...",a,...)
end
p()
p("q")
p("q","r")
p("q","r","s")
end

Binary file not shown.

BIN
src/test/res/test7.luac Normal file

Binary file not shown.