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);
+		}
+	}
+
+}