Mercurial Hosting > luan
changeset 37:8a57ebfdfd78
add JavaLib
git-svn-id: https://luan-java.googlecode.com/svn/trunk@38 21e917c8-12df-6dd8-5cb6-c86387c605b9
author | fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9> |
---|---|
date | Thu, 20 Dec 2012 02:36:07 +0000 |
parents | 2a35154aec14 |
children | 30fcb4fb0f76 |
files | src/luan/CmdLine.java src/luan/Lua.java src/luan/LuaException.java src/luan/LuaJavaFunction.java src/luan/LuaState.java src/luan/MetatableGetter.java src/luan/interp/AddExpr.java src/luan/interp/BinaryOpExpr.java src/luan/interp/ConcatExpr.java src/luan/interp/DivExpr.java src/luan/interp/EqExpr.java src/luan/interp/FnCall.java src/luan/interp/IndexExpr.java src/luan/interp/LeExpr.java src/luan/interp/LenExpr.java src/luan/interp/LtExpr.java src/luan/interp/LuaStateImpl.java src/luan/interp/ModExpr.java src/luan/interp/MulExpr.java src/luan/interp/PowExpr.java src/luan/interp/SetTableEntry.java src/luan/interp/SubExpr.java src/luan/interp/UnmExpr.java src/luan/interp/Utils.java src/luan/lib/BasicLib.java src/luan/lib/JavaLib.java |
diffstat | 26 files changed, 494 insertions(+), 91 deletions(-) [+] |
line wrap: on
line diff
--- a/src/luan/CmdLine.java Tue Dec 18 09:53:42 2012 +0000 +++ b/src/luan/CmdLine.java Thu Dec 20 02:36:07 2012 +0000 @@ -3,6 +3,7 @@ import java.util.Arrays; import java.util.Scanner; import luan.lib.BasicLib; +import luan.lib.JavaLib; import luan.interp.LuaCompiler; @@ -11,6 +12,7 @@ public static void main(String[] args) throws Exception { LuaState lua = LuaCompiler.newLuaState(); BasicLib.register(lua); + JavaLib.register(lua); boolean interactive = false; boolean showVersion = false; int i = 0;
--- a/src/luan/Lua.java Tue Dec 18 09:53:42 2012 +0000 +++ b/src/luan/Lua.java Thu Dec 20 02:36:07 2012 +0000 @@ -65,11 +65,4 @@ throw new LuaException( "attempt to call a " + type(obj) + " value" ); } - public static LuaTable getMetatable(Object obj) { - if( !(obj instanceof LuaTable) ) - return null; - LuaTable table = (LuaTable)obj; - return table.getMetatable(); - } - }
--- a/src/luan/LuaException.java Tue Dec 18 09:53:42 2012 +0000 +++ b/src/luan/LuaException.java Thu Dec 20 02:36:07 2012 +0000 @@ -7,4 +7,8 @@ super(msg); } + public LuaException(Exception e) { + super(e); + } + }
--- a/src/luan/LuaJavaFunction.java Tue Dec 18 09:53:42 2012 +0000 +++ b/src/luan/LuaJavaFunction.java Thu Dec 20 02:36:07 2012 +0000 @@ -2,11 +2,12 @@ import java.lang.reflect.Array; import java.lang.reflect.Method; +import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public final class LuaJavaFunction extends LuaFunction { - private final Method method; + private final JavaMethod method; private final Object obj; private final RtnConverter rtnConverter; private final boolean takesLuaState; @@ -14,6 +15,14 @@ private final Class<?> varArgCls; public LuaJavaFunction(Method method,Object obj) { + this( JavaMethod.of(method), obj ); + } + + public LuaJavaFunction(Constructor constr,Object obj) { + this( JavaMethod.of(constr), obj ); + } + + LuaJavaFunction(JavaMethod method,Object obj) { this.method = method; this.obj = obj; this.rtnConverter = getRtnConverter(method); @@ -27,6 +36,10 @@ } } + public Class<?>[] getParameterTypes() { + return method.getParameterTypes(); + } + @Override public Object[] call(LuaState lua,Object... args) { args = fixArgs(lua,args); Object rtn; @@ -36,6 +49,8 @@ throw new RuntimeException(e); } catch(InvocationTargetException e) { throw new RuntimeException(e); + } catch(InstantiationException e) { + throw new RuntimeException(e); } return rtnConverter.convert(rtn); } @@ -108,7 +123,7 @@ } }; - private static RtnConverter getRtnConverter(Method m) { + private static RtnConverter getRtnConverter(JavaMethod m) { Class<?> rtnType = m.getReturnType(); if( rtnType == Void.TYPE ) return RTN_EMPTY; @@ -222,12 +237,12 @@ } }; - private static boolean takesLuaState(Method m) { + private static boolean takesLuaState(JavaMethod m) { Class<?>[] paramTypes = m.getParameterTypes(); return paramTypes.length > 0 && paramTypes[0].equals(LuaState.class); } - private static ArgConverter[] getArgConverters(boolean takesLuaState,Method m) { + private static ArgConverter[] getArgConverters(boolean takesLuaState,JavaMethod m) { final boolean isVarArgs = m.isVarArgs(); Class<?>[] paramTypes = m.getParameterTypes(); if( takesLuaState ) { @@ -259,4 +274,53 @@ return ARG_SAME; } + + + private static abstract class JavaMethod { + abstract boolean isVarArgs(); + abstract Class<?>[] getParameterTypes(); + abstract Object invoke(Object obj,Object... args) + throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException; + abstract Class<?> getReturnType(); + + static JavaMethod of(final Method m) { + return new JavaMethod() { + boolean isVarArgs() { + return m.isVarArgs(); + } + Class<?>[] getParameterTypes() { + return m.getParameterTypes(); + } + Object invoke(Object obj,Object... args) + throws IllegalAccessException, IllegalArgumentException, InvocationTargetException + { + return m.invoke(obj,args); + } + Class<?> getReturnType() { + return m.getReturnType(); + } + }; + } + + static JavaMethod of(final Constructor c) { + return new JavaMethod() { + boolean isVarArgs() { + return c.isVarArgs(); + } + Class<?>[] getParameterTypes() { + return c.getParameterTypes(); + } + Object invoke(Object obj,Object... args) + throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException + { + return c.newInstance(args); + } + Class<?> getReturnType() { + return c.getDeclaringClass(); + } + }; + } + + } + }
--- a/src/luan/LuaState.java Tue Dec 18 09:53:42 2012 +0000 +++ b/src/luan/LuaState.java Thu Dec 20 02:36:07 2012 +0000 @@ -4,4 +4,6 @@ public interface LuaState { public LuaTable global(); public String toString(Object obj) throws LuaException; + public LuaTable getMetatable(Object obj); + public void addMetatableGetter(MetatableGetter mg); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/MetatableGetter.java Thu Dec 20 02:36:07 2012 +0000 @@ -0,0 +1,5 @@ +package luan; + +public interface MetatableGetter { + public LuaTable getMetatable(Object obj); +}
--- a/src/luan/interp/AddExpr.java Tue Dec 18 09:53:42 2012 +0000 +++ b/src/luan/interp/AddExpr.java Thu Dec 20 02:36:07 2012 +0000 @@ -18,6 +18,6 @@ LuaNumber n2 = Lua.toNumber(o2); if( n1 != null && n2 != null ) return new LuaNumber( n1.value() + n2.value() ); - return arithmetic(lua,"__add",o1,o2); + return lua.arithmetic("__add",o1,o2); } }
--- a/src/luan/interp/BinaryOpExpr.java Tue Dec 18 09:53:42 2012 +0000 +++ b/src/luan/interp/BinaryOpExpr.java Thu Dec 20 02:36:07 2012 +0000 @@ -15,18 +15,4 @@ this.op2 = op2; } - static final LuaFunction getBinHandler(String op,Object o1,Object o2) throws LuaException { - LuaFunction f1 = Utils.getHandlerFunction(op,o1); - if( f1 != null ) - return f1; - return Utils.getHandlerFunction(op,o2); - } - - static final Object arithmetic(LuaStateImpl lua,String op,Object o1,Object o2) throws LuaException { - LuaFunction fn = getBinHandler(op,o1,o2); - if( fn != null ) - return Utils.first(fn.call(lua,o1,o2)); - String type = Lua.toNumber(o1)==null ? Lua.type(o1) : Lua.type(o2); - throw new LuaException("attempt to perform arithmetic on a "+type+" value"); - } }
--- a/src/luan/interp/ConcatExpr.java Tue Dec 18 09:53:42 2012 +0000 +++ b/src/luan/interp/ConcatExpr.java Thu Dec 20 02:36:07 2012 +0000 @@ -18,7 +18,7 @@ String s2 = Lua.asString(o2); if( s1 != null && s2 != null ) return s1 + s2; - LuaFunction fn = getBinHandler("__concat",o1,o2); + LuaFunction fn = lua.getBinHandler("__concat",o1,o2); if( fn != null ) return Utils.first(fn.call(lua,o1,o2)); String type = s1==null ? Lua.type(o1) : Lua.type(o2);
--- a/src/luan/interp/DivExpr.java Tue Dec 18 09:53:42 2012 +0000 +++ b/src/luan/interp/DivExpr.java Thu Dec 20 02:36:07 2012 +0000 @@ -18,6 +18,6 @@ LuaNumber n2 = Lua.toNumber(o2); if( n1 != null && n2 != null ) return new LuaNumber( n1.value() / n2.value() ); - return arithmetic(lua,"__div",o1,o2); + return lua.arithmetic("__div",o1,o2); } }
--- a/src/luan/interp/EqExpr.java Tue Dec 18 09:53:42 2012 +0000 +++ b/src/luan/interp/EqExpr.java Thu Dec 20 02:36:07 2012 +0000 @@ -20,8 +20,8 @@ return true; if( !o1.getClass().equals(o2.getClass()) ) return false; - LuaTable mt1 = Lua.getMetatable(o1); - LuaTable mt2 = Lua.getMetatable(o2); + LuaTable mt1 = lua.getMetatable(o1); + LuaTable mt2 = lua.getMetatable(o2); if( mt1==null || mt2==null ) return false; Object f = mt1.get("__eq");
--- a/src/luan/interp/FnCall.java Tue Dec 18 09:53:42 2012 +0000 +++ b/src/luan/interp/FnCall.java Thu Dec 20 02:36:07 2012 +0000 @@ -23,7 +23,7 @@ LuaFunction fn = (LuaFunction)o; return fn.call( lua, args.eval(lua) ); } - Object h = Utils.getHandler("__call",o); + Object h = lua.getHandler("__call",o); if( h != null ) return call(lua,h); throw new LuaException( "attempt to call a " + Lua.type(o) + " value" );
--- a/src/luan/interp/IndexExpr.java Tue Dec 18 09:53:42 2012 +0000 +++ b/src/luan/interp/IndexExpr.java Thu Dec 20 02:36:07 2012 +0000 @@ -23,11 +23,11 @@ Object value = tbl.get(key); if( value != null ) return value; - h = Utils.getHandler("__index",t); + h = lua.getHandler("__index",t); if( h==null ) return null; } else { - h = Utils.getHandler("__index",t); + h = lua.getHandler("__index",t); if( h==null ) throw new LuaException( "attempt to index a " + Lua.type(t) + " value" ); }
--- a/src/luan/interp/LeExpr.java Tue Dec 18 09:53:42 2012 +0000 +++ b/src/luan/interp/LeExpr.java Thu Dec 20 02:36:07 2012 +0000 @@ -25,10 +25,10 @@ String s2 = (String)o2; return s1.compareTo(s2) <= 0; } - LuaFunction fn = getBinHandler("__le",o1,o2); + LuaFunction fn = lua.getBinHandler("__le",o1,o2); if( fn != null ) return Lua.toBoolean( Utils.first(fn.call(lua,o1,o2)) ); - fn = getBinHandler("__lt",o1,o2); + fn = lua.getBinHandler("__lt",o1,o2); if( fn != null ) return !Lua.toBoolean( Utils.first(fn.call(lua,o2,o1)) ); throw new LuaException( "attempt to compare " + Lua.type(o1) + " with " + Lua.type(o2) );
--- a/src/luan/interp/LenExpr.java Tue Dec 18 09:53:42 2012 +0000 +++ b/src/luan/interp/LenExpr.java Thu Dec 20 02:36:07 2012 +0000 @@ -19,7 +19,7 @@ String s = (String)o; return new LuaNumber( s.length() ); } - LuaFunction fn = Utils.getHandlerFunction("__len",o); + LuaFunction fn = lua.getHandlerFunction("__len",o); if( fn != null ) return Utils.first(fn.call(lua,o)); if( o instanceof LuaTable ) {
--- a/src/luan/interp/LtExpr.java Tue Dec 18 09:53:42 2012 +0000 +++ b/src/luan/interp/LtExpr.java Thu Dec 20 02:36:07 2012 +0000 @@ -25,7 +25,7 @@ String s2 = (String)o2; return s1.compareTo(s2) < 0; } - LuaFunction fn = getBinHandler("__lt",o1,o2); + LuaFunction fn = lua.getBinHandler("__lt",o1,o2); if( fn != null ) return Lua.toBoolean( Utils.first(fn.call(lua,o1,o2)) ); throw new LuaException( "attempt to compare " + Lua.type(o1) + " with " + Lua.type(o2) );
--- a/src/luan/interp/LuaStateImpl.java Tue Dec 18 09:53:42 2012 +0000 +++ b/src/luan/interp/LuaStateImpl.java Thu Dec 20 02:36:07 2012 +0000 @@ -1,21 +1,25 @@ package luan.interp; +import java.util.List; +import java.util.ArrayList; import luan.Lua; import luan.LuaState; import luan.LuaTable; import luan.LuaFunction; +import luan.MetatableGetter; import luan.LuaException; final class LuaStateImpl implements LuaState { private final LuaTable global = new LuaTable(); + private final List<MetatableGetter> mtGetters = new ArrayList<MetatableGetter>(); @Override public LuaTable global() { return global; } @Override public String toString(Object obj) throws LuaException { - LuaFunction fn = Utils.getHandlerFunction("__tostring",obj); + LuaFunction fn = getHandlerFunction("__tostring",obj); if( fn != null ) return Lua.checkString( Utils.first( fn.call(this,obj) ) ); if( obj == null ) @@ -23,6 +27,51 @@ return obj.toString(); } + @Override public LuaTable getMetatable(Object obj) { + if( obj instanceof LuaTable ) { + LuaTable table = (LuaTable)obj; + return table.getMetatable(); + } + for( MetatableGetter mg : mtGetters ) { + LuaTable table = mg.getMetatable(obj); + if( table != null ) + return table; + } + return null; + } + + public void addMetatableGetter(MetatableGetter mg) { + mtGetters.add(mg); + } + + Object getHandler(String op,Object obj) throws LuaException { + LuaTable t = getMetatable(obj); + return t==null ? null : t.get(op); + } + + LuaFunction getHandlerFunction(String op,Object obj) throws LuaException { + Object f = getHandler(op,obj); + if( f == null ) + return null; + return Lua.checkFunction(f); + } + + LuaFunction getBinHandler(String op,Object o1,Object o2) throws LuaException { + LuaFunction f1 = getHandlerFunction(op,o1); + if( f1 != null ) + return f1; + return getHandlerFunction(op,o2); + } + + final Object arithmetic(String op,Object o1,Object o2) throws LuaException { + LuaFunction fn = getBinHandler(op,o1,o2); + if( fn != null ) + return Utils.first(fn.call(this,o1,o2)); + String type = Lua.toNumber(o1)==null ? Lua.type(o1) : Lua.type(o2); + throw new LuaException("attempt to perform arithmetic on a "+type+" value"); + } + + private static class Frame { final Frame previousFrame; final LuaClosure closure;
--- a/src/luan/interp/ModExpr.java Tue Dec 18 09:53:42 2012 +0000 +++ b/src/luan/interp/ModExpr.java Thu Dec 20 02:36:07 2012 +0000 @@ -18,6 +18,6 @@ LuaNumber n2 = Lua.toNumber(o2); if( n1 != null && n2 != null ) return new LuaNumber( n1.value() % n2.value() ); - return arithmetic(lua,"__mod",o1,o2); + return lua.arithmetic("__mod",o1,o2); } }
--- a/src/luan/interp/MulExpr.java Tue Dec 18 09:53:42 2012 +0000 +++ b/src/luan/interp/MulExpr.java Thu Dec 20 02:36:07 2012 +0000 @@ -18,6 +18,6 @@ LuaNumber n2 = Lua.toNumber(o2); if( n1 != null && n2 != null ) return new LuaNumber( n1.value() * n2.value() ); - return arithmetic(lua,"__mul",o1,o2); + return lua.arithmetic("__mul",o1,o2); } }
--- a/src/luan/interp/PowExpr.java Tue Dec 18 09:53:42 2012 +0000 +++ b/src/luan/interp/PowExpr.java Thu Dec 20 02:36:07 2012 +0000 @@ -18,6 +18,6 @@ LuaNumber n2 = Lua.toNumber(o2); if( n1 != null && n2 != null ) return new LuaNumber( Math.pow( n1.value(), n2.value() ) ); - return arithmetic(lua,"__pow",o1,o2); + return lua.arithmetic("__pow",o1,o2); } }
--- a/src/luan/interp/SetTableEntry.java Tue Dec 18 09:53:42 2012 +0000 +++ b/src/luan/interp/SetTableEntry.java Thu Dec 20 02:36:07 2012 +0000 @@ -26,12 +26,12 @@ Object old = table.put(key,value); if( old != null ) return; - h = Utils.getHandler("__newindex",t); + h = lua.getHandler("__newindex",t); if( h==null ) return; table.put(key,old); } else { - h = Utils.getHandler("__newindex",t); + h = lua.getHandler("__newindex",t); if( h==null ) throw new LuaException( "attempt to index a " + Lua.type(t) + " value" ); }
--- a/src/luan/interp/SubExpr.java Tue Dec 18 09:53:42 2012 +0000 +++ b/src/luan/interp/SubExpr.java Thu Dec 20 02:36:07 2012 +0000 @@ -18,6 +18,6 @@ LuaNumber n2 = Lua.toNumber(o2); if( n1 != null && n2 != null ) return new LuaNumber( n1.value() - n2.value() ); - return arithmetic(lua,"__sub",o1,o2); + return lua.arithmetic("__sub",o1,o2); } }
--- a/src/luan/interp/UnmExpr.java Tue Dec 18 09:53:42 2012 +0000 +++ b/src/luan/interp/UnmExpr.java Thu Dec 20 02:36:07 2012 +0000 @@ -18,7 +18,7 @@ LuaNumber n = Lua.toNumber(o); if( n != null ) return new LuaNumber( -n.value() ); - LuaFunction fn = Utils.getHandlerFunction("__unm",o); + LuaFunction fn = lua.getHandlerFunction("__unm",o); if( fn != null ) return Utils.first(fn.call(lua,o)); throw new LuaException("attempt to perform arithmetic on a "+Lua.type(o)+" value");
--- a/src/luan/interp/Utils.java Tue Dec 18 09:53:42 2012 +0000 +++ b/src/luan/interp/Utils.java Thu Dec 20 02:36:07 2012 +0000 @@ -13,16 +13,4 @@ return a.length==0 ? null : a[0]; } - static final Object getHandler(String op,Object obj) throws LuaException { - LuaTable t = Lua.getMetatable(obj); - return t==null ? null : t.get(op); - } - - static final LuaFunction getHandlerFunction(String op,Object obj) throws LuaException { - Object f = getHandler(op,obj); - if( f == null ) - return null; - return Lua.checkFunction(f); - } - }
--- a/src/luan/lib/BasicLib.java Tue Dec 18 09:53:42 2012 +0000 +++ b/src/luan/lib/BasicLib.java Thu Dec 20 02:36:07 2012 +0000 @@ -18,26 +18,26 @@ import luan.interp.LuaCompiler; -public class BasicLib { +public final class BasicLib { public static void register(LuaState lua) { - LuaTable t = lua.global(); - t.put( "_G", t ); - add( t, "getmetatable", Object.class ); - add( t, "ipairs", LuaTable.class ); - add( t, "load", LuaState.class, String.class ); - add( t, "loadfile", LuaState.class, String.class ); - add( t, "pairs", LuaTable.class ); - add( t, "print", LuaState.class, new Object[0].getClass() ); - add( t, "rawequal", Object.class, Object.class ); - add( t, "rawget", LuaTable.class, Object.class ); - add( t, "rawlen", Object.class ); - add( t, "rawset", LuaTable.class, Object.class, Object.class ); - add( t, "setmetatable", LuaTable.class, LuaTable.class ); - add( t, "tonumber", Object.class, Integer.class ); - add( t, "tostring", LuaState.class, Object.class ); - add( t, "type", Object.class ); - t.put( "_VERSION", Lua.version ); + LuaTable global = lua.global(); + global.put( "_G", global ); + add( global, "getmetatable", LuaState.class, Object.class ); + add( global, "ipairs", LuaTable.class ); + add( global, "load", LuaState.class, String.class ); + add( global, "loadfile", LuaState.class, String.class ); + add( global, "pairs", LuaTable.class ); + add( global, "print", LuaState.class, new Object[0].getClass() ); + add( global, "rawequal", Object.class, Object.class ); + add( global, "rawget", LuaTable.class, Object.class ); + add( global, "rawlen", Object.class ); + add( global, "rawset", LuaTable.class, Object.class, Object.class ); + add( global, "setmetatable", LuaTable.class, LuaTable.class ); + add( global, "tonumber", Object.class, Integer.class ); + add( global, "tostring", LuaState.class, Object.class ); + add( global, "type", Object.class ); + global.put( "_VERSION", Lua.version ); } private static void add(LuaTable t,String method,Class<?>... parameterTypes) { @@ -99,8 +99,8 @@ private static class TableIter { private final Iterator<Map.Entry<Object,Object>> iter; - TableIter(LuaTable t) { - this.iter = t.iterator(); + TableIter(Iterator<Map.Entry<Object,Object>> iter) { + this.iter = iter; } public Object[] next() { @@ -110,18 +110,25 @@ return new Object[]{entry.getKey(),entry.getValue()}; } } - - public static LuaFunction pairs(LuaTable t) { + private static final Method nextTableIter; + static { try { - TableIter ti = new TableIter(t); - Method m = TableIter.class.getMethod("next"); - m.setAccessible(true); - return new LuaJavaFunction(m,ti); + nextTableIter = TableIter.class.getMethod("next"); + nextTableIter.setAccessible(true); } catch(NoSuchMethodException e) { throw new RuntimeException(e); } } + static LuaFunction pairs(Iterator<Map.Entry<Object,Object>> iter) { + TableIter ti = new TableIter(iter); + return new LuaJavaFunction(nextTableIter,ti); + } + + public static LuaFunction pairs(LuaTable t) { + return pairs(t.iterator()); + } + private static class ArrayIter { private final LuaTable t; private double i = 0.0; @@ -136,20 +143,23 @@ return val==null ? LuaFunction.EMPTY_RTN : new Object[]{n,val}; } } - - public static LuaFunction ipairs(LuaTable t) { + private static final Method nextArrayIter; + static { try { - ArrayIter ai = new ArrayIter(t); - Method m = ArrayIter.class.getMethod("next"); - m.setAccessible(true); - return new LuaJavaFunction(m,ai); + nextArrayIter = ArrayIter.class.getMethod("next"); + nextArrayIter.setAccessible(true); } catch(NoSuchMethodException e) { throw new RuntimeException(e); } } - public static LuaTable getmetatable(Object obj) { - return Lua.getMetatable(obj); + public static LuaFunction ipairs(LuaTable t) { + ArrayIter ai = new ArrayIter(t); + return new LuaJavaFunction(nextArrayIter,ai); + } + + public static LuaTable getmetatable(LuaState lua,Object obj) { + return lua.getMetatable(obj); } public static LuaTable setmetatable(LuaTable table,LuaTable metatable) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/lib/JavaLib.java Thu Dec 20 02:36:07 2012 +0000 @@ -0,0 +1,300 @@ +package luan.lib; + +import java.lang.reflect.Array; +import java.lang.reflect.Member; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Constructor; +import java.lang.reflect.Modifier; +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; +import luan.LuaNumber; +import luan.LuaState; +import luan.LuaTable; +import luan.MetatableGetter; +import luan.LuaException; +import luan.LuaFunction; +import luan.LuaJavaFunction; + + +public final class JavaLib { + + public static void register(LuaState lua) { + lua.addMetatableGetter(mg); + LuaTable module = new LuaTable(); + LuaTable global = lua.global(); + global.put("java",module); + try { + global.put( "import", new LuaJavaFunction(JavaLib.class.getMethod("importClass",LuaState.class,String.class),null) ); + module.put( "class", new LuaJavaFunction(JavaLib.class.getMethod("getClass",String.class),null) ); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + add( global, "ipairs", Object.class ); + add( global, "pairs", Object.class ); + } + + private static final LuaTable mt = new LuaTable(); + static { + add( mt, "__index", Object.class, Object.class ); + } + + private static void add(LuaTable t,String method,Class<?>... parameterTypes) { + try { + t.put( method, new LuaJavaFunction(JavaLib.class.getMethod(method,parameterTypes),null) ); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + private static final MetatableGetter mg = new MetatableGetter() { + public LuaTable getMetatable(Object obj) { + if( obj==null ) + return null; + return mt; + } + }; + + public static Object __index(Object obj,Object key) throws LuaException { + if( obj instanceof Static ) { + if( key instanceof String ) { + String name = (String)key; + Static st = (Static)obj; + Class cls = st.cls; + if( "class".equals(name) ) { + return cls; + } else if( "new".equals(name) ) { + Constructor<?>[] constructors = cls.getConstructors(); + if( constructors.length > 0 ) { + if( constructors.length==1 ) { + return new LuaJavaFunction(constructors[0],null); + } else { + List<LuaJavaFunction> fns = new ArrayList<LuaJavaFunction>(); + for( Constructor constructor : constructors ) { + fns.add(new LuaJavaFunction(constructor,null)); + } + return new AmbiguousJavaFunction(fns); + } + } + } else { + List<Member> members = getStaticMembers(cls,name); + if( !members.isEmpty() ) { + return member(null,members); + } + } + } + throw new LuaException("invalid index for java class: "+key); + } + Class cls = obj.getClass(); + if( cls.isArray() ) { + if( "length".equals(key) ) { + return Array.getLength(obj); + } + if( key instanceof LuaNumber ) { + LuaNumber n = (LuaNumber)key; + double d = n.value(); + int i = (int)d; + if( d==i ) { + return Array.get(obj,i); + } + } + throw new LuaException("invalid index for java array: "+key); + } + if( key instanceof String ) { + String name = (String)key; + if( "instanceof".equals(name) ) { + return new LuaJavaFunction(instanceOf,new InstanceOf(obj)); + } else { + List<Member> members = getMembers(cls,name); + if( !members.isEmpty() ) { + return member(obj,members); + } + } + } + throw new LuaException("invalid index for java object: "+key); + } + + private static Object member(Object obj,List<Member> members) throws LuaException { + try { + if( members.size()==1 ) { + Member member = members.get(0); + if( member instanceof Field ) { + Field field = (Field)member; + Object value = field.get(obj); + if( value instanceof Number ) { + Number n = (Number)value; + value = new LuaNumber(n.doubleValue()); + } + return value; + } else { + Method method = (Method)member; + return new LuaJavaFunction(method,obj); + } + } else { + List<LuaJavaFunction> fns = new ArrayList<LuaJavaFunction>(); + for( Member member : members ) { + Method method = (Method)member; + fns.add(new LuaJavaFunction(method,obj)); + } + return new AmbiguousJavaFunction(fns); + } + } catch(IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + private static Map<Class,Map<String,List<Member>>> memberMap = new HashMap<Class,Map<String,List<Member>>>(); + + private static synchronized List<Member> getMembers(Class cls,String name) { + Map<String,List<Member>> clsMap = memberMap.get(cls); + if( clsMap == null ) { + clsMap = new HashMap<String,List<Member>>(); + for( Field field : cls.getFields() ) { + String s = field.getName(); + List<Member> list = clsMap.get(s); + if( list == null ) { + list = new ArrayList<Member>(); + clsMap.put(s,list); + } + list.add(field); + } + for( Method method : cls.getMethods() ) { + String s = method.getName(); + List<Member> list = clsMap.get(s); + if( list == null ) { + list = new ArrayList<Member>(); + clsMap.put(s,list); + } + list.add(method); + } + memberMap.put(cls,clsMap); + } + return clsMap.get(name); + } + + private static synchronized List<Member> getStaticMembers(Class cls,String name) { + List<Member> staticMembers = new ArrayList<Member>(); + for( Member m : getMembers(cls,name) ) { + if( Modifier.isStatic(m.getModifiers()) ) + staticMembers.add(m); + } + return staticMembers; + } + + static class Static { + final Class cls; + + Static(Class cls) { + this.cls = cls; + } + } + + public static Static getClass(String name) throws LuaException { + try { + return new Static( Class.forName(name) ); + } catch(ClassNotFoundException e) { + throw new LuaException(e); + } + } + + public static void importClass(LuaState lua,String name) throws LuaException { + lua.global().put( name.substring(name.lastIndexOf('.')+1), getClass(name) ); + } + + static class AmbiguousJavaFunction extends LuaFunction { + private final Map<Integer,List<LuaJavaFunction>> fnMap = new HashMap<Integer,List<LuaJavaFunction>>(); + + AmbiguousJavaFunction(List<LuaJavaFunction> fns) { + for( LuaJavaFunction fn : fns ) { + Integer n = fn.getParameterTypes().length; + List<LuaJavaFunction> list = fnMap.get(n); + if( list==null ) { + list = new ArrayList<LuaJavaFunction>(); + fnMap.put(n,list); + } + list.add(fn); + } + } + + @Override public Object[] call(LuaState lua,Object... args) throws LuaException { + for( LuaJavaFunction fn : fnMap.get(args.length) ) { + try { + return fn.call(lua,args); + } catch(IllegalArgumentException e) {} + } + throw new LuaException("no method matched args"); + } + } + + + public static LuaFunction pairs(Object t) throws LuaException { + if( t instanceof LuaTable ) + return BasicLib.pairs((LuaTable)t); + if( t instanceof Map ) { + @SuppressWarnings("unchecked") + Map<Object,Object> m = (Map<Object,Object>)t; + return BasicLib.pairs(m.entrySet().iterator()); + } + throw new LuaException( "bad argument #1 to 'pairs' (table or Map expected)" ); + } + + private static class Iter { + private final Iterator iter; + private double i = 0.0; + + Iter(Iterable t) { + this.iter = t.iterator(); + } + + public Object[] next() { + if( !iter.hasNext() ) + return LuaFunction.EMPTY_RTN ; + return new Object[]{ new LuaNumber(i++), iter.next() }; + } + } + private static final Method nextIter; + static { + try { + nextIter = Iter.class.getMethod("next"); + nextIter.setAccessible(true); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + public static LuaFunction ipairs(Object t) throws LuaException { + if( t instanceof LuaTable ) + return BasicLib.ipairs((LuaTable)t); + if( t instanceof Iterable ) { + Iter ai = new Iter((Iterable)t); + return new LuaJavaFunction(nextIter,ai); + } + throw new LuaException( "bad argument #1 to 'ipairs' (table or Iterable expected)" ); + } + + + private static class InstanceOf { + private final Object obj; + + InstanceOf(Object obj) { + this.obj = obj; + } + + public boolean instanceOf(Static st) { + return st.cls.isInstance(obj); + } + } + private static final Method instanceOf; + static { + try { + instanceOf = InstanceOf.class.getMethod("instanceOf",Static.class); + instanceOf.setAccessible(true); + } catch(NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + +}