changeset 48:64ecb7a3aad7

rename Lua to Luan git-svn-id: https://luan-java.googlecode.com/svn/trunk@49 21e917c8-12df-6dd8-5cb6-c86387c605b9
author fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9>
date Fri, 28 Dec 2012 03:29:12 +0000
parents 659c7139e903
children 8ede219cd111
files src/luan/Lua.java src/luan/LuaElement.java src/luan/LuaException.java src/luan/LuaFunction.java src/luan/LuaJavaFunction.java src/luan/LuaSource.java src/luan/LuaState.java src/luan/LuaTable.java src/luan/Luan.java src/luan/LuanElement.java src/luan/LuanException.java src/luan/LuanFunction.java src/luan/LuanJavaFunction.java src/luan/LuanSource.java src/luan/LuanState.java src/luan/LuanTable.java src/luan/MetatableGetter.java src/luan/StackTraceElement.java src/luan/interp/AddExpr.java src/luan/interp/AndExpr.java src/luan/interp/BinaryOpExpr.java src/luan/interp/Block.java src/luan/interp/BreakStmt.java src/luan/interp/Chunk.java src/luan/interp/Closure.java src/luan/interp/Code.java src/luan/interp/CodeImpl.java src/luan/interp/ConcatExpr.java src/luan/interp/ConstExpr.java src/luan/interp/DivExpr.java src/luan/interp/EqExpr.java src/luan/interp/ExpList.java src/luan/interp/Expr.java src/luan/interp/Expressions.java src/luan/interp/ExpressionsExpr.java src/luan/interp/ExpressionsStmt.java src/luan/interp/FnCall.java src/luan/interp/GenericForStmt.java src/luan/interp/GetLocalVar.java src/luan/interp/GetUpVar.java src/luan/interp/IfStmt.java src/luan/interp/IndexExpr.java src/luan/interp/LeExpr.java src/luan/interp/LenExpr.java src/luan/interp/LtExpr.java src/luan/interp/LuaClosure.java src/luan/interp/LuaCompiler.java src/luan/interp/LuaParser.java src/luan/interp/LuaStateImpl.java src/luan/interp/LuanCompiler.java src/luan/interp/LuanParser.java src/luan/interp/LuanStateImpl.java src/luan/interp/ModExpr.java src/luan/interp/MulExpr.java src/luan/interp/NotExpr.java src/luan/interp/NumericForStmt.java src/luan/interp/OrExpr.java src/luan/interp/PowExpr.java src/luan/interp/RepeatStmt.java src/luan/interp/ReturnStmt.java src/luan/interp/SetLocalVar.java src/luan/interp/SetStmt.java src/luan/interp/SetTableEntry.java src/luan/interp/SetUpVar.java src/luan/interp/Settable.java src/luan/interp/Stmt.java src/luan/interp/SubExpr.java src/luan/interp/TableExpr.java src/luan/interp/UnaryOpExpr.java src/luan/interp/UnmExpr.java src/luan/interp/UpValue.java src/luan/interp/VarArgs.java src/luan/interp/WhileStmt.java src/luan/lib/BasicLib.java src/luan/lib/JavaLib.java src/luan/lib/LuaRuntimeException.java src/luan/lib/LuanRuntimeException.java src/luan/lib/StringLib.java src/luan/lib/TableLib.java src/luan/tools/CmdLine.java
diffstat 80 files changed, 2845 insertions(+), 2845 deletions(-) [+]
line wrap: on
line diff
--- a/src/luan/Lua.java	Thu Dec 27 04:36:44 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +0,0 @@
-package luan;
-
-
-public class Lua {
-	public static final String version = "Luan 0.0";
-
-	public static String type(Object obj) {
-		if( obj == null )
-			return "nil";
-		if( obj instanceof String )
-			return "string";
-		if( obj instanceof Boolean )
-			return "boolean";
-		if( obj instanceof Number )
-			return "number";
-		return "userdata";
-	}
-
-	public static boolean toBoolean(Object obj) {
-		return obj != null && !Boolean.FALSE.equals(obj);
-	}
-
-	public static String asString(Object obj) {
-		if( obj instanceof String )
-			return (String)obj;
-		if( obj instanceof Number )
-			return toString((Number)obj);
-		return null;
-	}
-
-	public static Number toNumber(Object obj) {
-		return toNumber(obj,null);
-	}
-
-	public static Number toNumber(Object obj,Integer base) {
-		if( obj instanceof Number )
-			return (Number)obj;
-		if( obj instanceof String ) {
-			String s = (String)obj;
-			try {
-				if( base==null )
-					return Double.valueOf(s);
-				else
-					return Long.valueOf(s,base);
-			} catch(NumberFormatException e) {}
-		}
-		return null;
-	}
-
-	public static Object first(Object[] a) {
-		return a.length==0 ? null : a[0];
-	}
-
-	public static String toString(Number n) {
-		if( n instanceof Integer )
-			return n.toString();
-		String s = n.toString();
-		int iE = s.indexOf('E');
-		String ending  = null;
-		if( iE != -1 ) {
-			ending = s.substring(iE);
-			s = s.substring(0,iE);
-		}
-		if( s.endsWith(".0") )
-			s = s.substring(0,s.length()-2);
-		if( ending != null )
-			s += ending;
-		return s;
-	}
-
-	public static Integer asInteger(Object obj) {
-		if( obj instanceof Integer )
-			return (Integer)obj;
-		if( !(obj instanceof Number) )
-			return null;
-		Number n = (Number)obj;
-		int i = n.intValue();
-		return i==n.doubleValue() ? Integer.valueOf(i) : null;
-	}
-}
--- a/src/luan/LuaElement.java	Thu Dec 27 04:36:44 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-package luan;
-
-
-public abstract class LuaElement {
-
-	final String toString(String fnName) {
-		return location() + ": in " + (fnName==null ? "main chunk" : "function '"+fnName+"'");
-	}
-
-	abstract String location();
-
-	public static final LuaElement JAVA = new LuaElement(){
-		@Override String location() {
-			return "Java";
-		}
-	};
-}
--- a/src/luan/LuaException.java	Thu Dec 27 04:36:44 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-package luan;
-
-
-public class LuaException extends Exception {
-	private final String stackTrace;
-
-	public LuaException(LuaState lua,LuaElement el,Object msg) {
-		super(message(msg),cause(msg));
-		stackTrace = stackTrace(lua,el,msg);
-	}
-
-	@Override public String getMessage() {
-		return super.getMessage() + stackTrace;
-	}
-
-	private String message() {
-		return super.getMessage();
-	}
-
-	private static Throwable cause(Object msg) {
-		return msg instanceof Throwable ? (Throwable)msg : null;
-	}
-
-	private static String message(Object msg) {
-		if( msg instanceof LuaException ) {
-			LuaException le = (LuaException)msg;
-			return le.message();
-/*
-		} else if( msg instanceof Throwable ) {
-			Throwable t = (Throwable)msg;
-			return t.getMessage();
-*/
-		} else {
-			return msg.toString();
-		}
-	}
-
-	private static String stackTrace(LuaState lua,LuaElement el,Object msg) {
-		StringBuilder buf = new StringBuilder();
-		for( int i  = lua.stackTrace.size() - 1; i>=0; i-- ) {
-			StackTraceElement stackTraceElement = lua.stackTrace.get(i);
-			buf.append( "\n\t" ).append( el.toString(stackTraceElement.fnName) );
-			el = stackTraceElement.call;
-		}
-		if( msg instanceof LuaException ) {
-			LuaException le = (LuaException)msg;
-			buf.append( "\ncaused by:" ).append( le.stackTrace );
-		}
-		return buf.toString();
-	}
-}
--- a/src/luan/LuaFunction.java	Thu Dec 27 04:36:44 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-package luan;
-
-
-public abstract class LuaFunction {
-
-	public abstract Object[] call(LuaState lua,Object[] args) throws LuaException;
-
-	public static final Object[] EMPTY_RTN = new Object[0];
-
-	@Override public String toString() {
-		return "function: " + Integer.toHexString(hashCode());
-	}
-
-}
--- a/src/luan/LuaJavaFunction.java	Thu Dec 27 04:36:44 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,465 +0,0 @@
-package luan;
-
-import java.lang.reflect.Array;
-import java.lang.reflect.Method;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-
-public final class LuaJavaFunction extends LuaFunction {
-	private final JavaMethod method;
-	private final Object obj;
-	private final RtnConverter rtnConverter;
-	private final boolean takesLuaState;
-	private final ArgConverter[] argConverters;
-	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);
-		this.takesLuaState = takesLuaState(method);
-		this.argConverters = getArgConverters(takesLuaState,method);
-		if( method.isVarArgs() ) {
-			Class<?>[] paramTypes = method.getParameterTypes();
-			this.varArgCls = paramTypes[paramTypes.length-1].getComponentType();
-		} else {
-			this.varArgCls = null;
-		}
-	}
-
-	public Class<?>[] getParameterTypes() {
-		return method.getParameterTypes();
-	}
-
-	@Override public Object[] call(LuaState lua,Object[] args) throws LuaException {
-		args = fixArgs(lua,args);
-		Object rtn;
-		try {
-			rtn = method.invoke(obj,args);
-		} catch(IllegalArgumentException e) {
-			checkArgs(lua,args);
-			throw e;
-		} catch(IllegalAccessException e) {
-			throw new RuntimeException(e);
-		} catch(InvocationTargetException e) {
-			Throwable cause = e.getCause();
-			if( cause instanceof Error )
-				throw (Error)cause;
-			if( cause instanceof RuntimeException )
-				throw (RuntimeException)cause;
-			if( cause instanceof LuaException )
-				throw (LuaException)cause;
-			throw new RuntimeException(e);
-		} catch(InstantiationException e) {
-			throw new RuntimeException(e);
-		}
-		return rtnConverter.convert(rtn);
-	}
-
-	private void checkArgs(LuaState lua,Object[] args) throws LuaException {
-		Class<?>[] a = getParameterTypes();
-		for( int i=0; i<a.length; i++ ) {
-			if( !a[i].isInstance(args[i]) ) {
-				String got = args[i].getClass().getName();
-				String expected = a[i].getName();
-				if( !takesLuaState )
-					i++;
-				throw new LuaException(lua,LuaElement.JAVA,"bad argument #"+i+" ("+expected+" expected, got "+got+")");
-			}
-		}
-	}
-
-	private Object[] fixArgs(LuaState lua,Object[] args) {
-		int n = argConverters.length;
-		Object[] rtn;
-		int start = 0;
-		if( !takesLuaState && varArgCls==null && args.length == n ) {
-			rtn = args;
-		} else {
-			if( takesLuaState )
-				n++;
-			rtn = new Object[n];
-			if( takesLuaState ) {
-				rtn[start++] = lua;
-			}
-			n = argConverters.length;
-			if( varArgCls != null ) {
-				n--;
-				if( args.length < argConverters.length ) {
-					rtn[rtn.length-1] = Array.newInstance(varArgCls,0);
-				} else {
-					int len = args.length - n;
-					Object varArgs = Array.newInstance(varArgCls,len);
-					ArgConverter ac = argConverters[n];
-					for( int i=0; i<len; i++ ) {
-						Array.set( varArgs, i, ac.convert(args[n+i]) );
-					}
-					rtn[rtn.length-1] = varArgs;
-				}
-			}
-			System.arraycopy(args,0,rtn,start,Math.min(args.length,n));
-		}
-		for( int i=0; i<n; i++ ) {
-			rtn[start+i] = argConverters[i].convert(rtn[start+i]);
-		}
-		return rtn;
-	}
-
-
-	private interface RtnConverter {
-		public Object[] convert(Object obj);
-	}
-
-	private static final RtnConverter RTN_EMPTY = new RtnConverter() {
-		public Object[] convert(Object obj) {
-			return EMPTY_RTN;
-		}
-	};
-
-	private static final RtnConverter RTN_ARRAY = new RtnConverter() {
-		public Object[] convert(Object obj) {
-			if( obj == null )
-				return NULL_RTN;
-			return (Object[])obj;
-		}
-	};
-
-	private static final RtnConverter RTN_ONE = new RtnConverter() {
-		public Object[] convert(Object obj) {
-			return new Object[]{obj};
-		}
-	};
-
-	private static final Object[] NULL_RTN = new Object[1];
-
-	private static final RtnConverter RTN_NUMBER_ARRAY = new RtnConverter() {
-		public Object[] convert(Object obj) {
-			if( obj == null )
-				return NULL_RTN;
-			Object[] rtn = new Object[Array.getLength(obj)];
-			for( int i=0; i<rtn.length; i++ ) {
-				rtn[i] = Array.get(obj,i);
-			}
-			return rtn;
-		}
-	};
-
-	private static RtnConverter getRtnConverter(JavaMethod m) {
-		Class<?> rtnType = m.getReturnType();
-		if( rtnType == Void.TYPE )
-			return RTN_EMPTY;
-		if( rtnType.isArray() ) {
-			rtnType = rtnType.getComponentType();
-			if( isNumber(rtnType) )
-				return RTN_NUMBER_ARRAY;
-			return RTN_ARRAY;
-		}
-		return RTN_ONE;
-	}
-
-	private static boolean isNumber(Class<?> rtnType) {
-		return rtnType == Byte.TYPE
-			|| rtnType == Short.TYPE
-			|| rtnType == Integer.TYPE
-			|| rtnType == Long.TYPE
-			|| rtnType == Float.TYPE
-			|| rtnType == Double.TYPE
-		;
-	}
-
-	private interface ArgConverter {
-		public Object convert(Object obj);
-	}
-
-	private static final ArgConverter ARG_SAME = new ArgConverter() {
-		public Object convert(Object obj) {
-			return obj;
-		}
-	};
-
-	private static final ArgConverter ARG_DOUBLE = new ArgConverter() {
-		public Object convert(Object obj) {
-			if( obj instanceof Double )
-				return obj;
-			if( obj instanceof Number ) {
-				Number n = (Number)obj;
-				return n.doubleValue();
-			}
-			if( obj instanceof String ) {
-				String s = (String)obj;
-				try {
-					return Double.valueOf(s);
-				} catch(NumberFormatException e) {}
-			}
-			return obj;
-		}
-	};
-
-	private static final ArgConverter ARG_FLOAT = new ArgConverter() {
-		public Object convert(Object obj) {
-			if( obj instanceof Float )
-				return obj;
-			if( obj instanceof Number ) {
-				Number n = (Number)obj;
-				float r = n.floatValue();
-				if( r==n.doubleValue() )
-					return r;
-			}
-			if( obj instanceof String ) {
-				String s = (String)obj;
-				try {
-					return Float.valueOf(s);
-				} catch(NumberFormatException e) {}
-			}
-			return obj;
-		}
-	};
-
-	private static final ArgConverter ARG_LONG = new ArgConverter() {
-		public Object convert(Object obj) {
-			if( obj instanceof Long )
-				return obj;
-			if( obj instanceof Number ) {
-				Number n = (Number)obj;
-				long r = n.longValue();
-				if( r==n.doubleValue() )
-					return r;
-			}
-			else if( obj instanceof String ) {
-				String s = (String)obj;
-				try {
-					return Long.valueOf(s);
-				} catch(NumberFormatException e) {}
-			}
-			return obj;
-		}
-	};
-
-	private static final ArgConverter ARG_INTEGER = new ArgConverter() {
-		public Object convert(Object obj) {
-			if( obj instanceof Integer )
-				return obj;
-			if( obj instanceof Number ) {
-				Number n = (Number)obj;
-				int r = n.intValue();
-				if( r==n.doubleValue() )
-					return r;
-			}
-			else if( obj instanceof String ) {
-				String s = (String)obj;
-				try {
-					return Integer.valueOf(s);
-				} catch(NumberFormatException e) {}
-			}
-			return obj;
-		}
-	};
-
-	private static final ArgConverter ARG_SHORT = new ArgConverter() {
-		public Object convert(Object obj) {
-			if( obj instanceof Short )
-				return obj;
-			if( obj instanceof Number ) {
-				Number n = (Number)obj;
-				short r = n.shortValue();
-				if( r==n.doubleValue() )
-					return r;
-			}
-			else if( obj instanceof String ) {
-				String s = (String)obj;
-				try {
-					return Short.valueOf(s);
-				} catch(NumberFormatException e) {}
-			}
-			return obj;
-		}
-	};
-
-	private static final ArgConverter ARG_BYTE = new ArgConverter() {
-		public Object convert(Object obj) {
-			if( obj instanceof Byte )
-				return obj;
-			if( obj instanceof Number ) {
-				Number n = (Number)obj;
-				byte r = n.byteValue();
-				if( r==n.doubleValue() )
-					return r;
-			}
-			else if( obj instanceof String ) {
-				String s = (String)obj;
-				try {
-					return Byte.valueOf(s);
-				} catch(NumberFormatException e) {}
-			}
-			return obj;
-		}
-	};
-
-	private static final ArgConverter ARG_TABLE = new ArgConverter() {
-		public Object convert(Object obj) {
-			if( obj instanceof List ) {
-				@SuppressWarnings("unchecked")
-				List<Object> list = (List<Object>)obj;
-				return new LuaTable(list);
-			}
-			if( obj instanceof Map ) {
-				@SuppressWarnings("unchecked")
-				Map<Object,Object> map = (Map<Object,Object>)obj;
-				return new LuaTable(map);
-			}
-			if( obj instanceof Set ) {
-				@SuppressWarnings("unchecked")
-				Set<Object> set = (Set<Object>)obj;
-				return new LuaTable(set);
-			}
-			return obj;
-		}
-	};
-
-	private static final ArgConverter ARG_MAP = new ArgConverter() {
-		public Object convert(Object obj) {
-			if( obj instanceof LuaTable ) {
-				LuaTable t = (LuaTable)obj;
-				return t.asMap();
-			}
-			return obj;
-		}
-	};
-
-	private static final ArgConverter ARG_LIST = new ArgConverter() {
-		public Object convert(Object obj) {
-			if( obj instanceof LuaTable ) {
-				LuaTable t = (LuaTable)obj;
-				if( t.isList() )
-					return t.asList();
-			}
-			return obj;
-		}
-	};
-
-	private static final ArgConverter ARG_SET = new ArgConverter() {
-		public Object convert(Object obj) {
-			if( obj instanceof LuaTable ) {
-				LuaTable t = (LuaTable)obj;
-				if( t.isSet() )
-					return t.asSet();
-			}
-			return obj;
-		}
-	};
-
-	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,JavaMethod m) {
-		final boolean isVarArgs = m.isVarArgs();
-		Class<?>[] paramTypes = m.getParameterTypes();
-		if( takesLuaState ) {
-			Class<?>[] t = new Class<?>[paramTypes.length-1];
-			System.arraycopy(paramTypes,1,t,0,t.length);
-			paramTypes = t;
-		}
-		ArgConverter[] a = new ArgConverter[paramTypes.length];
-		for( int i=0; i<a.length; i++ ) {
-			Class<?> paramType = paramTypes[i];
-			if( isVarArgs && i == a.length-1 )
-				paramType = paramType.getComponentType();
-			a[i] = getArgConverter(paramType);
-		}
-		return a;
-	}
-
-	private static ArgConverter getArgConverter(Class<?> cls) {
-		if( cls == Double.TYPE || cls.equals(Double.class) )
-			return ARG_DOUBLE;
-		if( cls == Float.TYPE || cls.equals(Float.class) )
-			return ARG_FLOAT;
-		if( cls == Long.TYPE || cls.equals(Long.class) )
-			return ARG_LONG;
-		if( cls == Integer.TYPE || cls.equals(Integer.class) )
-			return ARG_INTEGER;
-		if( cls == Short.TYPE || cls.equals(Short.class) )
-			return ARG_SHORT;
-		if( cls == Byte.TYPE || cls.equals(Byte.class) )
-			return ARG_BYTE;
-		if( cls.equals(LuaTable.class) )
-			return ARG_TABLE;
-		if( cls.equals(Map.class) )
-			return ARG_MAP;
-		if( cls.equals(List.class) )
-			return ARG_LIST;
-		if( cls.equals(Set.class) )
-			return ARG_SET;
-		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() {
-				@Override boolean isVarArgs() {
-					return m.isVarArgs();
-				}
-				@Override Class<?>[] getParameterTypes() {
-					return m.getParameterTypes();
-				}
-				@Override Object invoke(Object obj,Object... args)
-					throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
-				{
-					return m.invoke(obj,args);
-				}
-				@Override Class<?> getReturnType() {
-					return m.getReturnType();
-				}
-				@Override public String toString() {
-					return m.toString();
-				}
-			};
-		}
-	
-		static JavaMethod of(final Constructor c) {
-			return new JavaMethod() {
-				@Override boolean isVarArgs() {
-					return c.isVarArgs();
-				}
-				@Override Class<?>[] getParameterTypes() {
-					return c.getParameterTypes();
-				}
-				@Override Object invoke(Object obj,Object... args)
-					throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException
-				{
-					return c.newInstance(args);
-				}
-				@Override Class<?> getReturnType() {
-					return c.getDeclaringClass();
-				}
-				@Override public String toString() {
-					return c.toString();
-				}
-			};
-		}
-	
-	}
-
-}
--- a/src/luan/LuaSource.java	Thu Dec 27 04:36:44 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-package luan;
-
-
-public final class LuaSource {
-	public final String name;
-	public final String text;
-
-	public LuaSource(String name,String text) {
-		this.name = name;
-		this.text = text;
-	}
-
-	public static final class Element extends LuaElement {
-		public final LuaSource source;
-		public final int start;
-		public final int end;
-
-		public Element(LuaSource source,int start,int end) {
-			if( source==null )
-				throw new NullPointerException("source is null");
-			this.source = source;
-			this.start = start;
-			this.end = end;
-		}
-
-		public String text() {
-			return source.text.substring(start,end);
-		}
-
-		@Override String location() {
-			return source.name + ':' + lineNumber();
-		}
-
-		private int lineNumber() {
-			int line = 0;
-			int i = -1;
-			do {
-				line++;
-				i = source.text.indexOf('\n',i+1);
-			} while( i != -1 && i < start );
-			return line;
-		}
-
-	}
-}
--- a/src/luan/LuaState.java	Thu Dec 27 04:36:44 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,113 +0,0 @@
-package luan;
-
-import java.util.List;
-import java.util.ArrayList;
-
-
-public abstract class LuaState {
-	private final LuaTable global = new LuaTable();
-	private final List<MetatableGetter> mtGetters = new ArrayList<MetatableGetter>();
-	final List<StackTraceElement> stackTrace = new ArrayList<StackTraceElement>();
-
-	public final LuaTable global() {
-		return global;
-	}
-
-	public final 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 final void addMetatableGetter(MetatableGetter mg) {
-		mtGetters.add(mg);
-	}
-
-	public Object[] call(LuaFunction fn,LuaElement calledFrom,String fnName,Object... args) throws LuaException {
-		stackTrace.add( new StackTraceElement(calledFrom,fnName) );
-		try {
-			return fn.call(this,args);
-		} finally {
-			stackTrace.remove(stackTrace.size()-1);
-		}
-	}
-
-	public final String checkString(LuaElement el,Object obj) throws LuaException {
-		String s = Lua.asString(obj);
-		if( s == null )
-			throw new LuaException( this, el, "attempt to use a " + Lua.type(obj) + " as a string" );
-		return s;
-	}
-
-	public final Number checkNumber(LuaElement el,Object obj) throws LuaException {
-		Number n = Lua.toNumber(obj);
-		if( n == null )
-			throw new LuaException( this, el, "attempt to perform arithmetic on a " + Lua.type(obj) + " value" );
-		return n;
-	}
-
-	public final LuaFunction checkFunction(LuaElement el,Object obj) throws LuaException {
-		if( obj instanceof LuaFunction )
-			return (LuaFunction)obj;
-		throw new LuaException( this, el, "attempt to call a " + Lua.type(obj) + " value" );
-	}
-
-	public final String toString(LuaElement el,Object obj) throws LuaException {
-		LuaFunction fn = getHandlerFunction(el,"__tostring",obj);
-		if( fn != null )
-			return checkString( el, Lua.first( call(fn,el,"__tostring",obj) ) );
-		if( obj == null )
-			return "nil";
-		if( obj instanceof Number )
-			return Lua.toString((Number)obj);
-		if( obj instanceof LuaException ) {
-			LuaException le = (LuaException)obj;
-			return le.getMessage();
-		}
-		return obj.toString();
-	}
-
-	public final LuaFunction getHandlerFunction(LuaElement el,String op,Object obj) throws LuaException {
-		Object f = getHandler(op,obj);
-		if( f == null )
-			return null;
-		return checkFunction(el,f);
-	}
-
-	public final Object getHandler(String op,Object obj) {
-		LuaTable t = getMetatable(obj);
-		return t==null ? null : t.get(op);
-	}
-
-
-	public final LuaFunction getBinHandler(LuaElement el,String op,Object o1,Object o2) throws LuaException {
-		LuaFunction f1 = getHandlerFunction(el,op,o1);
-		if( f1 != null )
-			return f1;
-		return getHandlerFunction(el,op,o2);
-	}
-
-	public final boolean isLessThan(LuaElement el,Object o1,Object o2) throws LuaException {
-		if( o1 instanceof Number && o2 instanceof Number ) {
-			Number n1 = (Number)o1;
-			Number n2 = (Number)o2;
-			return n1.doubleValue() < n2.doubleValue();
-		}
-		if( o1 instanceof String && o2 instanceof String ) {
-			String s1 = (String)o1;
-			String s2 = (String)o2;
-			return s1.compareTo(s2) < 0;
-		}
-		LuaFunction fn = getBinHandler(el,"__lt",o1,o2);
-		if( fn != null )
-			return Lua.toBoolean( Lua.first(call(fn,el,"__lt",o1,o2)) );
-		throw new LuaException( this, el, "attempt to compare " + Lua.type(o1) + " with " + Lua.type(o2) );
-	}
-}
--- a/src/luan/LuaTable.java	Thu Dec 27 04:36:44 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,289 +0,0 @@
-package luan;
-
-import java.util.Iterator;
-import java.util.ListIterator;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Set;
-import java.util.HashSet;
-
-
-public class LuaTable {
-	private Map<Object,Object> map = null;
-	private List<Object> list = null;
-	private LuaTable metatable = null;
-
-	public LuaTable() {}
-
-	public LuaTable(List<Object> list) {
-		this.list = list;
-	}
-
-	public LuaTable(Map<Object,Object> map) {
-		this.map = map;
-	}
-
-	public LuaTable(Set<Object> set) {
-		map = new HashMap<Object,Object>();
-		for( Object obj : set ) {
-			map.put(obj,Boolean.TRUE);
-		}
-	}
-
-	boolean isList() {
-		return map==null || map.isEmpty();
-	}
-
-	List<Object> asList() {
-		return list!=null ? list : Collections.emptyList();
-	}
-
-	Map<Object,Object> asMap() {
-		if( list == null || list.isEmpty() )
-			return map!=null ? map : Collections.emptyMap();
-		Map<Object,Object> rtn = map!=null ? new HashMap<Object,Object>(map) : new HashMap<Object,Object>();
-		for( ListIterator iter = list.listIterator(); iter.hasNext(); ) {
-			int i = iter.nextIndex();
-			rtn.put(i+1,iter.next());
-		}
-		return rtn;
-	}
-
-	boolean isSet() {
-		if( list != null ) {
-			for( Object obj : list ) {
-				if( obj!=null && !obj.equals(Boolean.TRUE) )
-					return false;
-			}
-		}
-		if( map != null ) {
-			for( Object obj : map.values() ) {
-				if( !obj.equals(Boolean.TRUE) )
-					return false;
-			}
-		}
-		return true;
-	}
-
-	Set<Object> asSet() {
-		if( list == null || list.isEmpty() )
-			return map!=null ? map.keySet() : Collections.emptySet();
-		Set<Object> rtn = map!=null ? new HashSet<Object>(map.keySet()) : new HashSet<Object>();
-		for( int i=1; i<=list.size(); i++ ) {
-			rtn.add(i);
-		}
-		return rtn;
-	}
-
-	@Override public String toString() {
-//		return "table: " + Integer.toHexString(hashCode());
-		StringBuilder sb = new StringBuilder();
-		sb.append('{');
-		boolean isFirst = true;
-		if( list != null ) {
-			boolean gotNull = false;
-			for( int i=0; i<list.size(); i++ ) {
-				Object obj = list.get(i);
-				if( obj==null ) {
-					gotNull = true;
-				} else {
-					if( isFirst ) {
-						isFirst = false;
-					} else {
-						sb.append(", ");
-					}
-					if( gotNull )
-						sb.append(i+1).append('=');
-					sb.append(obj);
-				}
-			}
-		}
-		if( map != null ) {
-			for( Map.Entry<Object,Object> entry : map.entrySet() ) {
-				if( isFirst ) {
-					isFirst = false;
-				} else {
-					sb.append(", ");
-				}
-				sb.append(entry.getKey()).append('=').append(entry.getValue());
-			}
-		}
-		sb.append('}');
-		return sb.toString();
-	}
-
-	public Object get(Object key) {
-		if( list != null ) {
-			Integer iT = Lua.asInteger(key);
-			if( iT != null ) {
-				int i = iT - 1;
-				if( i>=0 && i<list.size() )
-					return list.get(i);
-			}
-		}
-		if( map==null )
-			return null;
-		return map.get(key);
-	}
-
-	public Object put(Object key,Object val) {
-		Integer iT = Lua.asInteger(key);
-		if( iT != null ) {
-			int i = iT - 1;
-			if( list != null || i == 0 ) {
-				if( i == list().size() ) {
-					if( val != null ) {
-						list.add(val);
-						mapToList();
-					}
-					return null;
-				} else if( i>=0 && i<list.size() ) {
-					Object old = list.get(i);
-					list.set(i,val);
-					if( val == null && i == list.size()-1 ) {
-						while( i>=0 && list.get(i)==null ) {
-							list.remove(i--);
-						}
-					}
-					return old;
-				}
-			}
-		}
-		if( map==null ) {
-			map = new HashMap<Object,Object>();
-		}
-		if( key instanceof Number && !(key instanceof Double) ) {
-			Number n = (Number)key;
-			key = Double.valueOf(n.doubleValue());
-		}
-		if( val == null ) {
-			return map.remove(key);
-		} else {
-			return map.put(key,val);
-		}
-	}
-
-	private void mapToList() {
-		if( map != null ) {
-			while(true) {
-				Object v = map.remove(Double.valueOf(list.size()+1));
-				if( v == null )
-					break;
-				list.add(v);
-			}
-		}
-	}
-
-	private List<Object> list() {
-		if( list == null ) {
-			list = new ArrayList<Object>();
-			mapToList();
-		}
-		return list;
-	}
-
-	public void insert(int pos,Object value) {
-		list().add(pos-1,value);
-	}
-
-	public Object remove(int pos) {
-		return list().remove(pos-1);
-	}
-
-	public void sort(Comparator<Object> cmp) {
-		Collections.sort(list(),cmp);
-	}
-
-	public int length() {
-		return list==null ? 0 : list.size();
-	}
-
-	public Iterator<Map.Entry<Object,Object>> iterator() {
-		if( list == null ) {
-			if( map == null )
-				return Collections.<Map.Entry<Object,Object>>emptyList().iterator();
-			return map.entrySet().iterator();
-		}
-		if( map == null )
-			return listIterator();
-		return new Iterator<Map.Entry<Object,Object>>() {
-			Iterator<Map.Entry<Object,Object>> iter = listIterator();
-			boolean isList = true;
-			public boolean hasNext() {
-				boolean b = iter.hasNext();
-				if( !b && isList ) {
-					iter = map.entrySet().iterator();
-					isList = false;
-					b = iter.hasNext();
-				}
-				return b;
-			}
-			public Map.Entry<Object,Object> next() {
-				return iter.next();
-			}
-			public void remove() {
-				throw new UnsupportedOperationException();
-			}
-		};
-	}
-
-	public Iterator<Map.Entry<Object,Object>> listIterator() {
-		if( list == null )
-			return Collections.<Map.Entry<Object,Object>>emptyList().iterator();
-		final ListIterator iter = list.listIterator();
-		return new Iterator<Map.Entry<Object,Object>>() {
-			public boolean hasNext() {
-				return iter.hasNext();
-			}
-			public Map.Entry<Object,Object> next() {
-				Double key = Double.valueOf(iter.nextIndex()+1);
-				return new MapEntry(key,iter.next());
-			}
-			public void remove() {
-				throw new UnsupportedOperationException();
-			}
-		};
-	}
-
-	public Object[] listToArray() {
-		return list==null ? new Object[0] : list.toArray();
-	}
-
-	public LuaTable subList(int from,int to) {
-		return new LuaTable(new ArrayList<Object>(list().subList(from-1,to-1)));
-	}
-
-	public LuaTable getMetatable() {
-		return metatable;
-	}
-
-	public void setMetatable(LuaTable metatable) {
-		this.metatable = metatable;
-	}
-
-	private static final class MapEntry implements Map.Entry<Object,Object> {
-		private final Object key;
-		private final Object value;
-
-		MapEntry(Object key,Object value) {
-			this.key = key;
-			this.value = value;
-		}
-
-		@Override public Object getKey() {
-			return key;
-		}
-
-		@Override public Object getValue() {
-			return value;
-		}
-
-		@Override public Object setValue(Object value) {
-			throw new UnsupportedOperationException();
-		}
-	}
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/Luan.java	Fri Dec 28 03:29:12 2012 +0000
@@ -0,0 +1,80 @@
+package luan;
+
+
+public class Luan {
+	public static final String version = "Luan 0.0";
+
+	public static String type(Object obj) {
+		if( obj == null )
+			return "nil";
+		if( obj instanceof String )
+			return "string";
+		if( obj instanceof Boolean )
+			return "boolean";
+		if( obj instanceof Number )
+			return "number";
+		return "userdata";
+	}
+
+	public static boolean toBoolean(Object obj) {
+		return obj != null && !Boolean.FALSE.equals(obj);
+	}
+
+	public static String asString(Object obj) {
+		if( obj instanceof String )
+			return (String)obj;
+		if( obj instanceof Number )
+			return toString((Number)obj);
+		return null;
+	}
+
+	public static Number toNumber(Object obj) {
+		return toNumber(obj,null);
+	}
+
+	public static Number toNumber(Object obj,Integer base) {
+		if( obj instanceof Number )
+			return (Number)obj;
+		if( obj instanceof String ) {
+			String s = (String)obj;
+			try {
+				if( base==null )
+					return Double.valueOf(s);
+				else
+					return Long.valueOf(s,base);
+			} catch(NumberFormatException e) {}
+		}
+		return null;
+	}
+
+	public static Object first(Object[] a) {
+		return a.length==0 ? null : a[0];
+	}
+
+	public static String toString(Number n) {
+		if( n instanceof Integer )
+			return n.toString();
+		String s = n.toString();
+		int iE = s.indexOf('E');
+		String ending  = null;
+		if( iE != -1 ) {
+			ending = s.substring(iE);
+			s = s.substring(0,iE);
+		}
+		if( s.endsWith(".0") )
+			s = s.substring(0,s.length()-2);
+		if( ending != null )
+			s += ending;
+		return s;
+	}
+
+	public static Integer asInteger(Object obj) {
+		if( obj instanceof Integer )
+			return (Integer)obj;
+		if( !(obj instanceof Number) )
+			return null;
+		Number n = (Number)obj;
+		int i = n.intValue();
+		return i==n.doubleValue() ? Integer.valueOf(i) : null;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/LuanElement.java	Fri Dec 28 03:29:12 2012 +0000
@@ -0,0 +1,17 @@
+package luan;
+
+
+public abstract class LuanElement {
+
+	final String toString(String fnName) {
+		return location() + ": in " + (fnName==null ? "main chunk" : "function '"+fnName+"'");
+	}
+
+	abstract String location();
+
+	public static final LuanElement JAVA = new LuanElement(){
+		@Override String location() {
+			return "Java";
+		}
+	};
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/LuanException.java	Fri Dec 28 03:29:12 2012 +0000
@@ -0,0 +1,51 @@
+package luan;
+
+
+public class LuanException extends Exception {
+	private final String stackTrace;
+
+	public LuanException(LuanState lua,LuanElement el,Object msg) {
+		super(message(msg),cause(msg));
+		stackTrace = stackTrace(lua,el,msg);
+	}
+
+	@Override public String getMessage() {
+		return super.getMessage() + stackTrace;
+	}
+
+	private String message() {
+		return super.getMessage();
+	}
+
+	private static Throwable cause(Object msg) {
+		return msg instanceof Throwable ? (Throwable)msg : null;
+	}
+
+	private static String message(Object msg) {
+		if( msg instanceof LuanException ) {
+			LuanException le = (LuanException)msg;
+			return le.message();
+/*
+		} else if( msg instanceof Throwable ) {
+			Throwable t = (Throwable)msg;
+			return t.getMessage();
+*/
+		} else {
+			return msg.toString();
+		}
+	}
+
+	private static String stackTrace(LuanState lua,LuanElement el,Object msg) {
+		StringBuilder buf = new StringBuilder();
+		for( int i  = lua.stackTrace.size() - 1; i>=0; i-- ) {
+			StackTraceElement stackTraceElement = lua.stackTrace.get(i);
+			buf.append( "\n\t" ).append( el.toString(stackTraceElement.fnName) );
+			el = stackTraceElement.call;
+		}
+		if( msg instanceof LuanException ) {
+			LuanException le = (LuanException)msg;
+			buf.append( "\ncaused by:" ).append( le.stackTrace );
+		}
+		return buf.toString();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/LuanFunction.java	Fri Dec 28 03:29:12 2012 +0000
@@ -0,0 +1,14 @@
+package luan;
+
+
+public abstract class LuanFunction {
+
+	public abstract Object[] call(LuanState lua,Object[] args) throws LuanException;
+
+	public static final Object[] EMPTY_RTN = new Object[0];
+
+	@Override public String toString() {
+		return "function: " + Integer.toHexString(hashCode());
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/LuanJavaFunction.java	Fri Dec 28 03:29:12 2012 +0000
@@ -0,0 +1,465 @@
+package luan;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+
+public final class LuanJavaFunction extends LuanFunction {
+	private final JavaMethod method;
+	private final Object obj;
+	private final RtnConverter rtnConverter;
+	private final boolean takesLuaState;
+	private final ArgConverter[] argConverters;
+	private final Class<?> varArgCls;
+
+	public LuanJavaFunction(Method method,Object obj) {
+		this( JavaMethod.of(method), obj );
+	}
+
+	public LuanJavaFunction(Constructor constr,Object obj) {
+		this( JavaMethod.of(constr), obj );
+	}
+
+	LuanJavaFunction(JavaMethod method,Object obj) {
+		this.method = method;
+		this.obj = obj;
+		this.rtnConverter = getRtnConverter(method);
+		this.takesLuaState = takesLuaState(method);
+		this.argConverters = getArgConverters(takesLuaState,method);
+		if( method.isVarArgs() ) {
+			Class<?>[] paramTypes = method.getParameterTypes();
+			this.varArgCls = paramTypes[paramTypes.length-1].getComponentType();
+		} else {
+			this.varArgCls = null;
+		}
+	}
+
+	public Class<?>[] getParameterTypes() {
+		return method.getParameterTypes();
+	}
+
+	@Override public Object[] call(LuanState lua,Object[] args) throws LuanException {
+		args = fixArgs(lua,args);
+		Object rtn;
+		try {
+			rtn = method.invoke(obj,args);
+		} catch(IllegalArgumentException e) {
+			checkArgs(lua,args);
+			throw e;
+		} catch(IllegalAccessException e) {
+			throw new RuntimeException(e);
+		} catch(InvocationTargetException e) {
+			Throwable cause = e.getCause();
+			if( cause instanceof Error )
+				throw (Error)cause;
+			if( cause instanceof RuntimeException )
+				throw (RuntimeException)cause;
+			if( cause instanceof LuanException )
+				throw (LuanException)cause;
+			throw new RuntimeException(e);
+		} catch(InstantiationException e) {
+			throw new RuntimeException(e);
+		}
+		return rtnConverter.convert(rtn);
+	}
+
+	private void checkArgs(LuanState lua,Object[] args) throws LuanException {
+		Class<?>[] a = getParameterTypes();
+		for( int i=0; i<a.length; i++ ) {
+			if( !a[i].isInstance(args[i]) ) {
+				String got = args[i].getClass().getName();
+				String expected = a[i].getName();
+				if( !takesLuaState )
+					i++;
+				throw new LuanException(lua,LuanElement.JAVA,"bad argument #"+i+" ("+expected+" expected, got "+got+")");
+			}
+		}
+	}
+
+	private Object[] fixArgs(LuanState lua,Object[] args) {
+		int n = argConverters.length;
+		Object[] rtn;
+		int start = 0;
+		if( !takesLuaState && varArgCls==null && args.length == n ) {
+			rtn = args;
+		} else {
+			if( takesLuaState )
+				n++;
+			rtn = new Object[n];
+			if( takesLuaState ) {
+				rtn[start++] = lua;
+			}
+			n = argConverters.length;
+			if( varArgCls != null ) {
+				n--;
+				if( args.length < argConverters.length ) {
+					rtn[rtn.length-1] = Array.newInstance(varArgCls,0);
+				} else {
+					int len = args.length - n;
+					Object varArgs = Array.newInstance(varArgCls,len);
+					ArgConverter ac = argConverters[n];
+					for( int i=0; i<len; i++ ) {
+						Array.set( varArgs, i, ac.convert(args[n+i]) );
+					}
+					rtn[rtn.length-1] = varArgs;
+				}
+			}
+			System.arraycopy(args,0,rtn,start,Math.min(args.length,n));
+		}
+		for( int i=0; i<n; i++ ) {
+			rtn[start+i] = argConverters[i].convert(rtn[start+i]);
+		}
+		return rtn;
+	}
+
+
+	private interface RtnConverter {
+		public Object[] convert(Object obj);
+	}
+
+	private static final RtnConverter RTN_EMPTY = new RtnConverter() {
+		public Object[] convert(Object obj) {
+			return EMPTY_RTN;
+		}
+	};
+
+	private static final RtnConverter RTN_ARRAY = new RtnConverter() {
+		public Object[] convert(Object obj) {
+			if( obj == null )
+				return NULL_RTN;
+			return (Object[])obj;
+		}
+	};
+
+	private static final RtnConverter RTN_ONE = new RtnConverter() {
+		public Object[] convert(Object obj) {
+			return new Object[]{obj};
+		}
+	};
+
+	private static final Object[] NULL_RTN = new Object[1];
+
+	private static final RtnConverter RTN_NUMBER_ARRAY = new RtnConverter() {
+		public Object[] convert(Object obj) {
+			if( obj == null )
+				return NULL_RTN;
+			Object[] rtn = new Object[Array.getLength(obj)];
+			for( int i=0; i<rtn.length; i++ ) {
+				rtn[i] = Array.get(obj,i);
+			}
+			return rtn;
+		}
+	};
+
+	private static RtnConverter getRtnConverter(JavaMethod m) {
+		Class<?> rtnType = m.getReturnType();
+		if( rtnType == Void.TYPE )
+			return RTN_EMPTY;
+		if( rtnType.isArray() ) {
+			rtnType = rtnType.getComponentType();
+			if( isNumber(rtnType) )
+				return RTN_NUMBER_ARRAY;
+			return RTN_ARRAY;
+		}
+		return RTN_ONE;
+	}
+
+	private static boolean isNumber(Class<?> rtnType) {
+		return rtnType == Byte.TYPE
+			|| rtnType == Short.TYPE
+			|| rtnType == Integer.TYPE
+			|| rtnType == Long.TYPE
+			|| rtnType == Float.TYPE
+			|| rtnType == Double.TYPE
+		;
+	}
+
+	private interface ArgConverter {
+		public Object convert(Object obj);
+	}
+
+	private static final ArgConverter ARG_SAME = new ArgConverter() {
+		public Object convert(Object obj) {
+			return obj;
+		}
+	};
+
+	private static final ArgConverter ARG_DOUBLE = new ArgConverter() {
+		public Object convert(Object obj) {
+			if( obj instanceof Double )
+				return obj;
+			if( obj instanceof Number ) {
+				Number n = (Number)obj;
+				return n.doubleValue();
+			}
+			if( obj instanceof String ) {
+				String s = (String)obj;
+				try {
+					return Double.valueOf(s);
+				} catch(NumberFormatException e) {}
+			}
+			return obj;
+		}
+	};
+
+	private static final ArgConverter ARG_FLOAT = new ArgConverter() {
+		public Object convert(Object obj) {
+			if( obj instanceof Float )
+				return obj;
+			if( obj instanceof Number ) {
+				Number n = (Number)obj;
+				float r = n.floatValue();
+				if( r==n.doubleValue() )
+					return r;
+			}
+			if( obj instanceof String ) {
+				String s = (String)obj;
+				try {
+					return Float.valueOf(s);
+				} catch(NumberFormatException e) {}
+			}
+			return obj;
+		}
+	};
+
+	private static final ArgConverter ARG_LONG = new ArgConverter() {
+		public Object convert(Object obj) {
+			if( obj instanceof Long )
+				return obj;
+			if( obj instanceof Number ) {
+				Number n = (Number)obj;
+				long r = n.longValue();
+				if( r==n.doubleValue() )
+					return r;
+			}
+			else if( obj instanceof String ) {
+				String s = (String)obj;
+				try {
+					return Long.valueOf(s);
+				} catch(NumberFormatException e) {}
+			}
+			return obj;
+		}
+	};
+
+	private static final ArgConverter ARG_INTEGER = new ArgConverter() {
+		public Object convert(Object obj) {
+			if( obj instanceof Integer )
+				return obj;
+			if( obj instanceof Number ) {
+				Number n = (Number)obj;
+				int r = n.intValue();
+				if( r==n.doubleValue() )
+					return r;
+			}
+			else if( obj instanceof String ) {
+				String s = (String)obj;
+				try {
+					return Integer.valueOf(s);
+				} catch(NumberFormatException e) {}
+			}
+			return obj;
+		}
+	};
+
+	private static final ArgConverter ARG_SHORT = new ArgConverter() {
+		public Object convert(Object obj) {
+			if( obj instanceof Short )
+				return obj;
+			if( obj instanceof Number ) {
+				Number n = (Number)obj;
+				short r = n.shortValue();
+				if( r==n.doubleValue() )
+					return r;
+			}
+			else if( obj instanceof String ) {
+				String s = (String)obj;
+				try {
+					return Short.valueOf(s);
+				} catch(NumberFormatException e) {}
+			}
+			return obj;
+		}
+	};
+
+	private static final ArgConverter ARG_BYTE = new ArgConverter() {
+		public Object convert(Object obj) {
+			if( obj instanceof Byte )
+				return obj;
+			if( obj instanceof Number ) {
+				Number n = (Number)obj;
+				byte r = n.byteValue();
+				if( r==n.doubleValue() )
+					return r;
+			}
+			else if( obj instanceof String ) {
+				String s = (String)obj;
+				try {
+					return Byte.valueOf(s);
+				} catch(NumberFormatException e) {}
+			}
+			return obj;
+		}
+	};
+
+	private static final ArgConverter ARG_TABLE = new ArgConverter() {
+		public Object convert(Object obj) {
+			if( obj instanceof List ) {
+				@SuppressWarnings("unchecked")
+				List<Object> list = (List<Object>)obj;
+				return new LuanTable(list);
+			}
+			if( obj instanceof Map ) {
+				@SuppressWarnings("unchecked")
+				Map<Object,Object> map = (Map<Object,Object>)obj;
+				return new LuanTable(map);
+			}
+			if( obj instanceof Set ) {
+				@SuppressWarnings("unchecked")
+				Set<Object> set = (Set<Object>)obj;
+				return new LuanTable(set);
+			}
+			return obj;
+		}
+	};
+
+	private static final ArgConverter ARG_MAP = new ArgConverter() {
+		public Object convert(Object obj) {
+			if( obj instanceof LuanTable ) {
+				LuanTable t = (LuanTable)obj;
+				return t.asMap();
+			}
+			return obj;
+		}
+	};
+
+	private static final ArgConverter ARG_LIST = new ArgConverter() {
+		public Object convert(Object obj) {
+			if( obj instanceof LuanTable ) {
+				LuanTable t = (LuanTable)obj;
+				if( t.isList() )
+					return t.asList();
+			}
+			return obj;
+		}
+	};
+
+	private static final ArgConverter ARG_SET = new ArgConverter() {
+		public Object convert(Object obj) {
+			if( obj instanceof LuanTable ) {
+				LuanTable t = (LuanTable)obj;
+				if( t.isSet() )
+					return t.asSet();
+			}
+			return obj;
+		}
+	};
+
+	private static boolean takesLuaState(JavaMethod m) {
+		Class<?>[] paramTypes = m.getParameterTypes();
+		return paramTypes.length > 0 && paramTypes[0].equals(LuanState.class);
+	}
+
+	private static ArgConverter[] getArgConverters(boolean takesLuaState,JavaMethod m) {
+		final boolean isVarArgs = m.isVarArgs();
+		Class<?>[] paramTypes = m.getParameterTypes();
+		if( takesLuaState ) {
+			Class<?>[] t = new Class<?>[paramTypes.length-1];
+			System.arraycopy(paramTypes,1,t,0,t.length);
+			paramTypes = t;
+		}
+		ArgConverter[] a = new ArgConverter[paramTypes.length];
+		for( int i=0; i<a.length; i++ ) {
+			Class<?> paramType = paramTypes[i];
+			if( isVarArgs && i == a.length-1 )
+				paramType = paramType.getComponentType();
+			a[i] = getArgConverter(paramType);
+		}
+		return a;
+	}
+
+	private static ArgConverter getArgConverter(Class<?> cls) {
+		if( cls == Double.TYPE || cls.equals(Double.class) )
+			return ARG_DOUBLE;
+		if( cls == Float.TYPE || cls.equals(Float.class) )
+			return ARG_FLOAT;
+		if( cls == Long.TYPE || cls.equals(Long.class) )
+			return ARG_LONG;
+		if( cls == Integer.TYPE || cls.equals(Integer.class) )
+			return ARG_INTEGER;
+		if( cls == Short.TYPE || cls.equals(Short.class) )
+			return ARG_SHORT;
+		if( cls == Byte.TYPE || cls.equals(Byte.class) )
+			return ARG_BYTE;
+		if( cls.equals(LuanTable.class) )
+			return ARG_TABLE;
+		if( cls.equals(Map.class) )
+			return ARG_MAP;
+		if( cls.equals(List.class) )
+			return ARG_LIST;
+		if( cls.equals(Set.class) )
+			return ARG_SET;
+		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() {
+				@Override boolean isVarArgs() {
+					return m.isVarArgs();
+				}
+				@Override Class<?>[] getParameterTypes() {
+					return m.getParameterTypes();
+				}
+				@Override Object invoke(Object obj,Object... args)
+					throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
+				{
+					return m.invoke(obj,args);
+				}
+				@Override Class<?> getReturnType() {
+					return m.getReturnType();
+				}
+				@Override public String toString() {
+					return m.toString();
+				}
+			};
+		}
+	
+		static JavaMethod of(final Constructor c) {
+			return new JavaMethod() {
+				@Override boolean isVarArgs() {
+					return c.isVarArgs();
+				}
+				@Override Class<?>[] getParameterTypes() {
+					return c.getParameterTypes();
+				}
+				@Override Object invoke(Object obj,Object... args)
+					throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException
+				{
+					return c.newInstance(args);
+				}
+				@Override Class<?> getReturnType() {
+					return c.getDeclaringClass();
+				}
+				@Override public String toString() {
+					return c.toString();
+				}
+			};
+		}
+	
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/LuanSource.java	Fri Dec 28 03:29:12 2012 +0000
@@ -0,0 +1,45 @@
+package luan;
+
+
+public final class LuanSource {
+	public final String name;
+	public final String text;
+
+	public LuanSource(String name,String text) {
+		this.name = name;
+		this.text = text;
+	}
+
+	public static final class Element extends LuanElement {
+		public final LuanSource source;
+		public final int start;
+		public final int end;
+
+		public Element(LuanSource source,int start,int end) {
+			if( source==null )
+				throw new NullPointerException("source is null");
+			this.source = source;
+			this.start = start;
+			this.end = end;
+		}
+
+		public String text() {
+			return source.text.substring(start,end);
+		}
+
+		@Override String location() {
+			return source.name + ':' + lineNumber();
+		}
+
+		private int lineNumber() {
+			int line = 0;
+			int i = -1;
+			do {
+				line++;
+				i = source.text.indexOf('\n',i+1);
+			} while( i != -1 && i < start );
+			return line;
+		}
+
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/LuanState.java	Fri Dec 28 03:29:12 2012 +0000
@@ -0,0 +1,113 @@
+package luan;
+
+import java.util.List;
+import java.util.ArrayList;
+
+
+public abstract class LuanState {
+	private final LuanTable global = new LuanTable();
+	private final List<MetatableGetter> mtGetters = new ArrayList<MetatableGetter>();
+	final List<StackTraceElement> stackTrace = new ArrayList<StackTraceElement>();
+
+	public final LuanTable global() {
+		return global;
+	}
+
+	public final LuanTable getMetatable(Object obj) {
+		if( obj instanceof LuanTable ) {
+			LuanTable table = (LuanTable)obj;
+			return table.getMetatable();
+		}
+		for( MetatableGetter mg : mtGetters ) {
+			LuanTable table = mg.getMetatable(obj);
+			if( table != null )
+				return table;
+		}
+		return null;
+	}
+
+	public final void addMetatableGetter(MetatableGetter mg) {
+		mtGetters.add(mg);
+	}
+
+	public Object[] call(LuanFunction fn,LuanElement calledFrom,String fnName,Object... args) throws LuanException {
+		stackTrace.add( new StackTraceElement(calledFrom,fnName) );
+		try {
+			return fn.call(this,args);
+		} finally {
+			stackTrace.remove(stackTrace.size()-1);
+		}
+	}
+
+	public final String checkString(LuanElement el,Object obj) throws LuanException {
+		String s = Luan.asString(obj);
+		if( s == null )
+			throw new LuanException( this, el, "attempt to use a " + Luan.type(obj) + " as a string" );
+		return s;
+	}
+
+	public final Number checkNumber(LuanElement el,Object obj) throws LuanException {
+		Number n = Luan.toNumber(obj);
+		if( n == null )
+			throw new LuanException( this, el, "attempt to perform arithmetic on a " + Luan.type(obj) + " value" );
+		return n;
+	}
+
+	public final LuanFunction checkFunction(LuanElement el,Object obj) throws LuanException {
+		if( obj instanceof LuanFunction )
+			return (LuanFunction)obj;
+		throw new LuanException( this, el, "attempt to call a " + Luan.type(obj) + " value" );
+	}
+
+	public final String toString(LuanElement el,Object obj) throws LuanException {
+		LuanFunction fn = getHandlerFunction(el,"__tostring",obj);
+		if( fn != null )
+			return checkString( el, Luan.first( call(fn,el,"__tostring",obj) ) );
+		if( obj == null )
+			return "nil";
+		if( obj instanceof Number )
+			return Luan.toString((Number)obj);
+		if( obj instanceof LuanException ) {
+			LuanException le = (LuanException)obj;
+			return le.getMessage();
+		}
+		return obj.toString();
+	}
+
+	public final LuanFunction getHandlerFunction(LuanElement el,String op,Object obj) throws LuanException {
+		Object f = getHandler(op,obj);
+		if( f == null )
+			return null;
+		return checkFunction(el,f);
+	}
+
+	public final Object getHandler(String op,Object obj) {
+		LuanTable t = getMetatable(obj);
+		return t==null ? null : t.get(op);
+	}
+
+
+	public final LuanFunction getBinHandler(LuanElement el,String op,Object o1,Object o2) throws LuanException {
+		LuanFunction f1 = getHandlerFunction(el,op,o1);
+		if( f1 != null )
+			return f1;
+		return getHandlerFunction(el,op,o2);
+	}
+
+	public final boolean isLessThan(LuanElement el,Object o1,Object o2) throws LuanException {
+		if( o1 instanceof Number && o2 instanceof Number ) {
+			Number n1 = (Number)o1;
+			Number n2 = (Number)o2;
+			return n1.doubleValue() < n2.doubleValue();
+		}
+		if( o1 instanceof String && o2 instanceof String ) {
+			String s1 = (String)o1;
+			String s2 = (String)o2;
+			return s1.compareTo(s2) < 0;
+		}
+		LuanFunction fn = getBinHandler(el,"__lt",o1,o2);
+		if( fn != null )
+			return Luan.toBoolean( Luan.first(call(fn,el,"__lt",o1,o2)) );
+		throw new LuanException( this, el, "attempt to compare " + Luan.type(o1) + " with " + Luan.type(o2) );
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/LuanTable.java	Fri Dec 28 03:29:12 2012 +0000
@@ -0,0 +1,289 @@
+package luan;
+
+import java.util.Iterator;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Set;
+import java.util.HashSet;
+
+
+public class LuanTable {
+	private Map<Object,Object> map = null;
+	private List<Object> list = null;
+	private LuanTable metatable = null;
+
+	public LuanTable() {}
+
+	public LuanTable(List<Object> list) {
+		this.list = list;
+	}
+
+	public LuanTable(Map<Object,Object> map) {
+		this.map = map;
+	}
+
+	public LuanTable(Set<Object> set) {
+		map = new HashMap<Object,Object>();
+		for( Object obj : set ) {
+			map.put(obj,Boolean.TRUE);
+		}
+	}
+
+	boolean isList() {
+		return map==null || map.isEmpty();
+	}
+
+	List<Object> asList() {
+		return list!=null ? list : Collections.emptyList();
+	}
+
+	Map<Object,Object> asMap() {
+		if( list == null || list.isEmpty() )
+			return map!=null ? map : Collections.emptyMap();
+		Map<Object,Object> rtn = map!=null ? new HashMap<Object,Object>(map) : new HashMap<Object,Object>();
+		for( ListIterator iter = list.listIterator(); iter.hasNext(); ) {
+			int i = iter.nextIndex();
+			rtn.put(i+1,iter.next());
+		}
+		return rtn;
+	}
+
+	boolean isSet() {
+		if( list != null ) {
+			for( Object obj : list ) {
+				if( obj!=null && !obj.equals(Boolean.TRUE) )
+					return false;
+			}
+		}
+		if( map != null ) {
+			for( Object obj : map.values() ) {
+				if( !obj.equals(Boolean.TRUE) )
+					return false;
+			}
+		}
+		return true;
+	}
+
+	Set<Object> asSet() {
+		if( list == null || list.isEmpty() )
+			return map!=null ? map.keySet() : Collections.emptySet();
+		Set<Object> rtn = map!=null ? new HashSet<Object>(map.keySet()) : new HashSet<Object>();
+		for( int i=1; i<=list.size(); i++ ) {
+			rtn.add(i);
+		}
+		return rtn;
+	}
+
+	@Override public String toString() {
+//		return "table: " + Integer.toHexString(hashCode());
+		StringBuilder sb = new StringBuilder();
+		sb.append('{');
+		boolean isFirst = true;
+		if( list != null ) {
+			boolean gotNull = false;
+			for( int i=0; i<list.size(); i++ ) {
+				Object obj = list.get(i);
+				if( obj==null ) {
+					gotNull = true;
+				} else {
+					if( isFirst ) {
+						isFirst = false;
+					} else {
+						sb.append(", ");
+					}
+					if( gotNull )
+						sb.append(i+1).append('=');
+					sb.append(obj);
+				}
+			}
+		}
+		if( map != null ) {
+			for( Map.Entry<Object,Object> entry : map.entrySet() ) {
+				if( isFirst ) {
+					isFirst = false;
+				} else {
+					sb.append(", ");
+				}
+				sb.append(entry.getKey()).append('=').append(entry.getValue());
+			}
+		}
+		sb.append('}');
+		return sb.toString();
+	}
+
+	public Object get(Object key) {
+		if( list != null ) {
+			Integer iT = Luan.asInteger(key);
+			if( iT != null ) {
+				int i = iT - 1;
+				if( i>=0 && i<list.size() )
+					return list.get(i);
+			}
+		}
+		if( map==null )
+			return null;
+		return map.get(key);
+	}
+
+	public Object put(Object key,Object val) {
+		Integer iT = Luan.asInteger(key);
+		if( iT != null ) {
+			int i = iT - 1;
+			if( list != null || i == 0 ) {
+				if( i == list().size() ) {
+					if( val != null ) {
+						list.add(val);
+						mapToList();
+					}
+					return null;
+				} else if( i>=0 && i<list.size() ) {
+					Object old = list.get(i);
+					list.set(i,val);
+					if( val == null && i == list.size()-1 ) {
+						while( i>=0 && list.get(i)==null ) {
+							list.remove(i--);
+						}
+					}
+					return old;
+				}
+			}
+		}
+		if( map==null ) {
+			map = new HashMap<Object,Object>();
+		}
+		if( key instanceof Number && !(key instanceof Double) ) {
+			Number n = (Number)key;
+			key = Double.valueOf(n.doubleValue());
+		}
+		if( val == null ) {
+			return map.remove(key);
+		} else {
+			return map.put(key,val);
+		}
+	}
+
+	private void mapToList() {
+		if( map != null ) {
+			while(true) {
+				Object v = map.remove(Double.valueOf(list.size()+1));
+				if( v == null )
+					break;
+				list.add(v);
+			}
+		}
+	}
+
+	private List<Object> list() {
+		if( list == null ) {
+			list = new ArrayList<Object>();
+			mapToList();
+		}
+		return list;
+	}
+
+	public void insert(int pos,Object value) {
+		list().add(pos-1,value);
+	}
+
+	public Object remove(int pos) {
+		return list().remove(pos-1);
+	}
+
+	public void sort(Comparator<Object> cmp) {
+		Collections.sort(list(),cmp);
+	}
+
+	public int length() {
+		return list==null ? 0 : list.size();
+	}
+
+	public Iterator<Map.Entry<Object,Object>> iterator() {
+		if( list == null ) {
+			if( map == null )
+				return Collections.<Map.Entry<Object,Object>>emptyList().iterator();
+			return map.entrySet().iterator();
+		}
+		if( map == null )
+			return listIterator();
+		return new Iterator<Map.Entry<Object,Object>>() {
+			Iterator<Map.Entry<Object,Object>> iter = listIterator();
+			boolean isList = true;
+			public boolean hasNext() {
+				boolean b = iter.hasNext();
+				if( !b && isList ) {
+					iter = map.entrySet().iterator();
+					isList = false;
+					b = iter.hasNext();
+				}
+				return b;
+			}
+			public Map.Entry<Object,Object> next() {
+				return iter.next();
+			}
+			public void remove() {
+				throw new UnsupportedOperationException();
+			}
+		};
+	}
+
+	public Iterator<Map.Entry<Object,Object>> listIterator() {
+		if( list == null )
+			return Collections.<Map.Entry<Object,Object>>emptyList().iterator();
+		final ListIterator iter = list.listIterator();
+		return new Iterator<Map.Entry<Object,Object>>() {
+			public boolean hasNext() {
+				return iter.hasNext();
+			}
+			public Map.Entry<Object,Object> next() {
+				Double key = Double.valueOf(iter.nextIndex()+1);
+				return new MapEntry(key,iter.next());
+			}
+			public void remove() {
+				throw new UnsupportedOperationException();
+			}
+		};
+	}
+
+	public Object[] listToArray() {
+		return list==null ? new Object[0] : list.toArray();
+	}
+
+	public LuanTable subList(int from,int to) {
+		return new LuanTable(new ArrayList<Object>(list().subList(from-1,to-1)));
+	}
+
+	public LuanTable getMetatable() {
+		return metatable;
+	}
+
+	public void setMetatable(LuanTable metatable) {
+		this.metatable = metatable;
+	}
+
+	private static final class MapEntry implements Map.Entry<Object,Object> {
+		private final Object key;
+		private final Object value;
+
+		MapEntry(Object key,Object value) {
+			this.key = key;
+			this.value = value;
+		}
+
+		@Override public Object getKey() {
+			return key;
+		}
+
+		@Override public Object getValue() {
+			return value;
+		}
+
+		@Override public Object setValue(Object value) {
+			throw new UnsupportedOperationException();
+		}
+	}
+}
--- a/src/luan/MetatableGetter.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/MetatableGetter.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,5 +1,5 @@
 package luan;
 
 public interface MetatableGetter {
-	public LuaTable getMetatable(Object obj);
+	public LuanTable getMetatable(Object obj);
 }
--- a/src/luan/StackTraceElement.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/StackTraceElement.java	Fri Dec 28 03:29:12 2012 +0000
@@ -2,10 +2,10 @@
 
 
 final class StackTraceElement {
-	final LuaElement call;
+	final LuanElement call;
 	final String fnName;
 
-	StackTraceElement(LuaElement call,String fnName) {
+	StackTraceElement(LuanElement call,String fnName) {
 		this.call = call;
 		this.fnName = fnName;
 	}
--- a/src/luan/interp/AddExpr.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/AddExpr.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,21 +1,21 @@
 package luan.interp;
 
-import luan.Lua;
-import luan.LuaException;
-import luan.LuaSource;
+import luan.Luan;
+import luan.LuanException;
+import luan.LuanSource;
 
 
 final class AddExpr extends BinaryOpExpr {
 
-	AddExpr(LuaSource.Element se,Expr op1,Expr op2) {
+	AddExpr(LuanSource.Element se,Expr op1,Expr op2) {
 		super(se,op1,op2);
 	}
 
-	@Override public Object eval(LuaStateImpl lua) throws LuaException {
+	@Override public Object eval(LuanStateImpl lua) throws LuanException {
 		Object o1 = op1.eval(lua);
 		Object o2 = op2.eval(lua);
-		Number n1 = Lua.toNumber(o1);
-		Number n2 = Lua.toNumber(o2);
+		Number n1 = Luan.toNumber(o1);
+		Number n2 = Luan.toNumber(o2);
 		if( n1 != null && n2 != null )
 			return n1.doubleValue() + n2.doubleValue();
 		return arithmetic(lua,"__add",o1,o2);
--- a/src/luan/interp/AndExpr.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/AndExpr.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,18 +1,18 @@
 package luan.interp;
 
-import luan.Lua;
-import luan.LuaException;
-import luan.LuaSource;
+import luan.Luan;
+import luan.LuanException;
+import luan.LuanSource;
 
 
 final class AndExpr extends BinaryOpExpr {
 
-	AndExpr(LuaSource.Element se,Expr op1,Expr op2) {
+	AndExpr(LuanSource.Element se,Expr op1,Expr op2) {
 		super(se,op1,op2);
 	}
 
-	@Override public Object eval(LuaStateImpl lua) throws LuaException {
+	@Override public Object eval(LuanStateImpl lua) throws LuanException {
 		Object v1 = op1.eval(lua);
-		return !Lua.toBoolean(v1) ? v1 : op2.eval(lua);
+		return !Luan.toBoolean(v1) ? v1 : op2.eval(lua);
 	}
 }
--- a/src/luan/interp/BinaryOpExpr.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/BinaryOpExpr.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,23 +1,23 @@
 package luan.interp;
 
-import luan.Lua;
-import luan.LuaTable;
-import luan.LuaFunction;
-import luan.LuaException;
-import luan.LuaSource;
+import luan.Luan;
+import luan.LuanTable;
+import luan.LuanFunction;
+import luan.LuanException;
+import luan.LuanSource;
 
 
 abstract class BinaryOpExpr extends CodeImpl implements Expr {
 	final Expr op1;
 	final Expr op2;
 
-	BinaryOpExpr(LuaSource.Element se,Expr op1,Expr op2) {
+	BinaryOpExpr(LuanSource.Element se,Expr op1,Expr op2) {
 		super(se);
 		this.op1 = op1;
 		this.op2 = op2;
 	}
 
-	Object arithmetic(LuaStateImpl lua,String op,Object o1,Object o2) throws LuaException {
+	Object arithmetic(LuanStateImpl lua,String op,Object o1,Object o2) throws LuanException {
 		return lua.arithmetic(se(),"__mod",o1,o2);
 	}
 
--- a/src/luan/interp/Block.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/Block.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,6 +1,6 @@
 package luan.interp;
 
-import luan.LuaException;
+import luan.LuanException;
 
 
 final class Block implements Stmt {
@@ -16,7 +16,7 @@
 		this.stackEnd = stackEnd;
 	}
 
-	@Override public void eval(LuaStateImpl lua) throws LuaException {
+	@Override public void eval(LuanStateImpl lua) throws LuanException {
 		try {
 			for( Stmt stmt : stmts ) {
 				stmt.eval(lua);
--- a/src/luan/interp/BreakStmt.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/BreakStmt.java	Fri Dec 28 03:29:12 2012 +0000
@@ -3,7 +3,7 @@
 
 final class BreakStmt implements Stmt {
 
-	@Override public void eval(LuaStateImpl lua) {
+	@Override public void eval(LuanStateImpl lua) {
 		throw new BreakException();
 	}
 }
--- a/src/luan/interp/Chunk.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/Chunk.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,7 +1,7 @@
 package luan.interp;
 
-import luan.LuaException;
-import luan.LuaSource;
+import luan.LuanException;
+import luan.LuanSource;
 
 
 final class Chunk extends CodeImpl implements Expr {
@@ -11,7 +11,7 @@
 	final boolean isVarArg;
 	final UpValue.Getter[] upValueGetters;
 
-	Chunk(LuaSource.Element se,Stmt block,int stackSize,int numArgs,boolean isVarArg,UpValue.Getter[] upValueGetters) {
+	Chunk(LuanSource.Element se,Stmt block,int stackSize,int numArgs,boolean isVarArg,UpValue.Getter[] upValueGetters) {
 		super(se);
 		this.block = block;
 		this.stackSize = stackSize;
@@ -35,11 +35,11 @@
 		}
 	}
 
-	LuaClosure newClosure(LuaStateImpl lua) {
-		return new LuaClosure(this,lua);
+	Closure newClosure(LuanStateImpl lua) {
+		return new Closure(this,lua);
 	}
 
-	@Override public Object eval(LuaStateImpl lua) {
+	@Override public Object eval(LuanStateImpl lua) {
 		return newClosure(lua);
 	}
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/interp/Closure.java	Fri Dec 28 03:29:12 2012 +0000
@@ -0,0 +1,66 @@
+package luan.interp;
+
+import luan.LuanFunction;
+import luan.LuanState;
+import luan.LuanElement;
+import luan.LuanException;
+
+
+final class Closure extends LuanFunction {
+	private final Chunk chunk;
+	final UpValue[] upValues;
+	private final static UpValue[] NO_UP_VALUES = new UpValue[0];
+
+	Closure(Chunk chunk,LuanStateImpl lua) {
+		this.chunk = chunk;
+		UpValue.Getter[] upValueGetters = chunk.upValueGetters;
+		if( upValueGetters.length==0 ) {
+			upValues = NO_UP_VALUES;
+		} else {
+			upValues = new UpValue[upValueGetters.length];
+			for( int i=0; i<upValues.length; i++ ) {
+				upValues[i] = upValueGetters[i].get(lua);
+			}
+		}
+	}
+
+	public Object[] call(LuanState lua,Object[] args) throws LuanException {
+		return call(this,(LuanStateImpl)lua,args);
+	}
+
+	private static Object[] call(Closure closure,LuanStateImpl lua,Object[] args) throws LuanException {
+		while(true) {
+			Chunk chunk = closure.chunk;
+			Object[] varArgs = null;
+			if( chunk.isVarArg ) {
+				if( args.length > chunk.numArgs ) {
+					varArgs = new Object[ args.length - chunk.numArgs ];
+					for( int i=0; i<varArgs.length; i++ ) {
+						varArgs[i] = args[chunk.numArgs+i];
+					}
+				} else {
+					varArgs = LuanFunction.EMPTY_RTN;
+				}
+			}
+			Object[] stack = lua.newFrame(closure,chunk.stackSize,varArgs);
+			final int n = Math.min(args.length,chunk.numArgs);
+			for( int i=0; i<n; i++ ) {
+				stack[i] = args[i];
+			}
+			Object[] returnValues;
+			Closure tailFn;
+			try {
+				chunk.block.eval(lua);
+			} catch(ReturnException e) {
+			} finally {
+				returnValues = lua.returnValues;
+				closure = lua.tailFn;
+				lua.popFrame();
+			}
+			if( closure == null )
+				return returnValues;
+			args = returnValues;
+		}
+	}
+
+}
--- a/src/luan/interp/Code.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/Code.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,8 +1,8 @@
 package luan.interp;
 
-import luan.LuaSource;
+import luan.LuanSource;
 
 
 interface Code {
-	public LuaSource.Element se();
+	public LuanSource.Element se();
 }
--- a/src/luan/interp/CodeImpl.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/CodeImpl.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,16 +1,16 @@
 package luan.interp;
 
-import luan.LuaSource;
+import luan.LuanSource;
 
 
 class CodeImpl implements Code {
-	final LuaSource.Element se;
+	final LuanSource.Element se;
 
-	CodeImpl(LuaSource.Element se) {
+	CodeImpl(LuanSource.Element se) {
 		this.se = se;
 	}
 
-	@Override public final LuaSource.Element se() {
+	@Override public final LuanSource.Element se() {
 		return se;
 	}
 }
--- a/src/luan/interp/ConcatExpr.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/ConcatExpr.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,28 +1,28 @@
 package luan.interp;
 
-import luan.Lua;
-import luan.LuaFunction;
-import luan.LuaException;
-import luan.LuaSource;
+import luan.Luan;
+import luan.LuanFunction;
+import luan.LuanException;
+import luan.LuanSource;
 
 
 final class ConcatExpr extends BinaryOpExpr {
 
-	ConcatExpr(LuaSource.Element se,Expr op1,Expr op2) {
+	ConcatExpr(LuanSource.Element se,Expr op1,Expr op2) {
 		super(se,op1,op2);
 	}
 
-	@Override public Object eval(LuaStateImpl lua) throws LuaException {
+	@Override public Object eval(LuanStateImpl lua) throws LuanException {
 		Object o1 = op1.eval(lua);
 		Object o2 = op2.eval(lua);
-		String s1 = Lua.asString(o1);
-		String s2 = Lua.asString(o2);
+		String s1 = Luan.asString(o1);
+		String s2 = Luan.asString(o2);
 		if( s1 != null && s2 != null )
 			return s1 + s2;
-		LuaFunction fn = lua.getBinHandler(se,"__concat",o1,o2);
+		LuanFunction fn = lua.getBinHandler(se,"__concat",o1,o2);
 		if( fn != null )
-			return Lua.first(lua.call(fn,se,"__concat",o1,o2));
-		String type = s1==null ? Lua.type(o1) : Lua.type(o2);
-		throw new LuaException( lua, se, "attempt to concatenate a " + type + " value" );
+			return Luan.first(lua.call(fn,se,"__concat",o1,o2));
+		String type = s1==null ? Luan.type(o1) : Luan.type(o2);
+		throw new LuanException( lua, se, "attempt to concatenate a " + type + " value" );
 	}
 }
--- a/src/luan/interp/ConstExpr.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/ConstExpr.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,6 +1,6 @@
 package luan.interp;
 
-import luan.LuaSource;
+import luan.LuanSource;
 
 
 final class ConstExpr implements Expr {
@@ -10,11 +10,11 @@
 		this.obj = obj;
 	}
 
-	@Override public Object eval(LuaStateImpl lua) {
+	@Override public Object eval(LuanStateImpl lua) {
 		return obj;
 	}
 
-	@Override public final LuaSource.Element se() {
+	@Override public final LuanSource.Element se() {
 		return null;
 	}
 }
--- a/src/luan/interp/DivExpr.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/DivExpr.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,21 +1,21 @@
 package luan.interp;
 
-import luan.Lua;
-import luan.LuaException;
-import luan.LuaSource;
+import luan.Luan;
+import luan.LuanException;
+import luan.LuanSource;
 
 
 final class DivExpr extends BinaryOpExpr {
 
-	DivExpr(LuaSource.Element se,Expr op1,Expr op2) {
+	DivExpr(LuanSource.Element se,Expr op1,Expr op2) {
 		super(se,op1,op2);
 	}
 
-	@Override public Object eval(LuaStateImpl lua) throws LuaException {
+	@Override public Object eval(LuanStateImpl lua) throws LuanException {
 		Object o1 = op1.eval(lua);
 		Object o2 = op2.eval(lua);
-		Number n1 = Lua.toNumber(o1);
-		Number n2 = Lua.toNumber(o2);
+		Number n1 = Luan.toNumber(o1);
+		Number n2 = Luan.toNumber(o2);
 		if( n1 != null && n2 != null )
 			return n1.doubleValue() / n2.doubleValue();
 		return arithmetic(lua,"__div",o1,o2);
--- a/src/luan/interp/EqExpr.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/EqExpr.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,19 +1,19 @@
 package luan.interp;
 
-import luan.Lua;
-import luan.LuaFunction;
-import luan.LuaTable;
-import luan.LuaException;
-import luan.LuaSource;
+import luan.Luan;
+import luan.LuanFunction;
+import luan.LuanTable;
+import luan.LuanException;
+import luan.LuanSource;
 
 
 final class EqExpr extends BinaryOpExpr {
 
-	EqExpr(LuaSource.Element se,Expr op1,Expr op2) {
+	EqExpr(LuanSource.Element se,Expr op1,Expr op2) {
 		super(se,op1,op2);
 	}
 
-	@Override public Object eval(LuaStateImpl lua) throws LuaException {
+	@Override public Object eval(LuanStateImpl lua) throws LuanException {
 		Object o1 = op1.eval(lua);
 		Object o2 = op2.eval(lua);
 		if( o1 == o2 || o1 != null && o1.equals(o2) )
@@ -25,14 +25,14 @@
 		}
 		if( !o1.getClass().equals(o2.getClass()) )
 			return false;
-		LuaTable mt1 = lua.getMetatable(o1);
-		LuaTable mt2 = lua.getMetatable(o2);
+		LuanTable mt1 = lua.getMetatable(o1);
+		LuanTable mt2 = lua.getMetatable(o2);
 		if( mt1==null || mt2==null )
 			return false;
 		Object f = mt1.get("__eq");
 		if( f == null || !f.equals(mt2.get("__eq")) )
 			return null;
-		LuaFunction fn = lua.checkFunction(se,f);
-		return Lua.toBoolean( Lua.first(lua.call(fn,se,"__eq",o1,o2)) );
+		LuanFunction fn = lua.checkFunction(se,f);
+		return Luan.toBoolean( Luan.first(lua.call(fn,se,"__eq",o1,o2)) );
 	}
 }
--- a/src/luan/interp/ExpList.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/ExpList.java	Fri Dec 28 03:29:12 2012 +0000
@@ -3,14 +3,14 @@
 import java.util.List;
 import java.util.ArrayList;
 import java.util.Collections;
-import luan.LuaException;
-import luan.LuaSource;
+import luan.LuanException;
+import luan.LuanSource;
 
 
 final class ExpList implements Expressions {
 
 	private interface Adder {
-		public void addTo(LuaStateImpl lua,List<Object> list) throws LuaException;
+		public void addTo(LuanStateImpl lua,List<Object> list) throws LuanException;
 		public Code code();
 	}
 
@@ -21,7 +21,7 @@
 			this.expr = expr;
 		}
 
-		public void addTo(LuaStateImpl lua,List<Object> list) throws LuaException {
+		public void addTo(LuanStateImpl lua,List<Object> list) throws LuanException {
 			list.add( expr.eval(lua) );
 		}
 
@@ -38,7 +38,7 @@
 			this.expressions = expressions;
 		}
 
-		public void addTo(LuaStateImpl lua,List<Object> list) throws LuaException {
+		public void addTo(LuanStateImpl lua,List<Object> list) throws LuanException {
 			for( Object val : expressions.eval(lua) ) {
 				list.add( val );
 			}
@@ -81,11 +81,11 @@
 
 	static final Expressions emptyExpList = new Expressions() {
 
-		@Override public Object[] eval(LuaStateImpl lua) {
+		@Override public Object[] eval(LuanStateImpl lua) {
 			return EMPTY;
 		}
 
-		@Override public LuaSource.Element se() {
+		@Override public LuanSource.Element se() {
 			return null;
 		}
 	};
@@ -97,11 +97,11 @@
 			this.expr = expr;
 		}
 
-		@Override public Object[] eval(LuaStateImpl lua) throws LuaException {
+		@Override public Object[] eval(LuanStateImpl lua) throws LuanException {
 			return new Object[]{expr.eval(lua)};
 		}
 
-		@Override public LuaSource.Element se() {
+		@Override public LuanSource.Element se() {
 			return expr.se();
 		}
 	}
@@ -112,7 +112,7 @@
 		this.adders = adders;
 	}
 
-	@Override public Object[] eval(LuaStateImpl lua) throws LuaException {
+	@Override public Object[] eval(LuanStateImpl lua) throws LuanException {
 		List<Object> list = new ArrayList<Object>();
 		for( Adder adder : adders ) {
 			adder.addTo(lua,list);
@@ -120,7 +120,7 @@
 		return list.toArray();
 	}
 
-	@Override public LuaSource.Element se() {
-		return new LuaSource.Element(adders[0].code().se().source,adders[0].code().se().start,adders[adders.length-1].code().se().end);
+	@Override public LuanSource.Element se() {
+		return new LuanSource.Element(adders[0].code().se().source,adders[0].code().se().start,adders[adders.length-1].code().se().end);
 	}
 }
--- a/src/luan/interp/Expr.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/Expr.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,8 +1,8 @@
 package luan.interp;
 
-import luan.LuaException;
+import luan.LuanException;
 
 
 interface Expr extends Code {
-	public Object eval(LuaStateImpl lua) throws LuaException;
+	public Object eval(LuanStateImpl lua) throws LuanException;
 }
--- a/src/luan/interp/Expressions.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/Expressions.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,8 +1,8 @@
 package luan.interp;
 
-import luan.LuaException;
+import luan.LuanException;
 
 
 interface Expressions extends Code {
-	public Object[] eval(LuaStateImpl lua) throws LuaException;
+	public Object[] eval(LuanStateImpl lua) throws LuanException;
 }
--- a/src/luan/interp/ExpressionsExpr.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/ExpressionsExpr.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,9 +1,9 @@
 package luan.interp;
 
 import java.util.List;
-import luan.Lua;
-import luan.LuaException;
-import luan.LuaSource;
+import luan.Luan;
+import luan.LuanException;
+import luan.LuanSource;
 
 
 final class ExpressionsExpr implements Expr {
@@ -13,11 +13,11 @@
 		this.expressions = expressions;
 	}
 
-	@Override public Object eval(LuaStateImpl lua) throws LuaException {
-		return Lua.first( expressions.eval(lua) );
+	@Override public Object eval(LuanStateImpl lua) throws LuanException {
+		return Luan.first( expressions.eval(lua) );
 	}
 
-	public LuaSource.Element se() {
+	public LuanSource.Element se() {
 		return expressions.se();
 	}
 
--- a/src/luan/interp/ExpressionsStmt.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/ExpressionsStmt.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,6 +1,6 @@
 package luan.interp;
 
-import luan.LuaException;
+import luan.LuanException;
 
 
 final class ExpressionsStmt implements Stmt {
@@ -10,7 +10,7 @@
 		this.expressions = expressions;
 	}
 
-	@Override public void eval(LuaStateImpl lua) throws LuaException {
+	@Override public void eval(LuanStateImpl lua) throws LuanException {
 		expressions.eval(lua);
 	}
 
--- a/src/luan/interp/FnCall.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/FnCall.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,9 +1,9 @@
 package luan.interp;
 
-import luan.Lua;
-import luan.LuaFunction;
-import luan.LuaException;
-import luan.LuaSource;
+import luan.Luan;
+import luan.LuanFunction;
+import luan.LuanException;
+import luan.LuanSource;
 
 
 final class FnCall extends CodeImpl implements Expressions {
@@ -11,25 +11,25 @@
 	final Expressions args;
 	final String fnName;
 
-	FnCall(LuaSource.Element se,Expr fnExpr,Expressions args) {
+	FnCall(LuanSource.Element se,Expr fnExpr,Expressions args) {
 		super(se);
 		this.fnExpr = fnExpr;
 		this.args = args;
 		this.fnName = fnExpr.se().text();
 	}
 
-	@Override public Object[] eval(LuaStateImpl lua) throws LuaException {
+	@Override public Object[] eval(LuanStateImpl lua) throws LuanException {
 		return call( lua, fnExpr.eval(lua) );
 	}
 
-	private Object[] call(LuaStateImpl lua,Object o) throws LuaException {
-		if( o instanceof LuaFunction ) {
-			LuaFunction fn = (LuaFunction)o;
+	private Object[] call(LuanStateImpl lua,Object o) throws LuanException {
+		if( o instanceof LuanFunction ) {
+			LuanFunction fn = (LuanFunction)o;
 			return lua.call( fn, se, fnName, args.eval(lua) );
 		}
 		Object h = lua.getHandler("__call",o);
 		if( h != null )
 			return call(lua,h);
-		throw new LuaException( lua, se, "attempt to call a " + Lua.type(o) + " value" );
+		throw new LuanException( lua, se, "attempt to call a " + Luan.type(o) + " value" );
 	}
 }
--- a/src/luan/interp/GenericForStmt.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/GenericForStmt.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,9 +1,9 @@
 package luan.interp;
 
-import luan.Lua;
-import luan.LuaException;
-import luan.LuaFunction;
-import luan.LuaSource;
+import luan.Luan;
+import luan.LuanException;
+import luan.LuanFunction;
+import luan.LuanSource;
 
 
 final class GenericForStmt extends CodeImpl implements Stmt {
@@ -12,7 +12,7 @@
 	private final Expr iterExpr;
 	private final Stmt block;
 
-	GenericForStmt(LuaSource.Element se,int iVars,int nVars,Expr iterExpr,Stmt block) {
+	GenericForStmt(LuanSource.Element se,int iVars,int nVars,Expr iterExpr,Stmt block) {
 		super(se);
 		this.iVars = iVars;
 		this.nVars = nVars;
@@ -20,8 +20,8 @@
 		this.block = block;
 	}
 
-	@Override public void eval(LuaStateImpl lua) throws LuaException {
-		LuaFunction iter = lua.checkFunction( se, iterExpr.eval(lua) );
+	@Override public void eval(LuanStateImpl lua) throws LuanException {
+		LuanFunction iter = lua.checkFunction( se, iterExpr.eval(lua) );
 		try {
 			while(true) {
 				Object[] vals = lua.call(iter,iterExpr.se(),iterExpr.se().text());
--- a/src/luan/interp/GetLocalVar.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/GetLocalVar.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,17 +1,17 @@
 package luan.interp;
 
-import luan.LuaSource;
+import luan.LuanSource;
 
 
 final class GetLocalVar extends CodeImpl implements Expr {
 	private final int index;
 
-	GetLocalVar(LuaSource.Element se,int index) {
+	GetLocalVar(LuanSource.Element se,int index) {
 		super(se);
 		this.index = index;
 	}
 
-	@Override public Object eval(LuaStateImpl lua) {
+	@Override public Object eval(LuanStateImpl lua) {
 		return lua.stackGet(index);
 	}
 }
--- a/src/luan/interp/GetUpVar.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/GetUpVar.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,17 +1,17 @@
 package luan.interp;
 
-import luan.LuaSource;
+import luan.LuanSource;
 
 
 final class GetUpVar extends CodeImpl implements Expr {
 	private final int index;
 
-	GetUpVar(LuaSource.Element se,int index) {
+	GetUpVar(LuanSource.Element se,int index) {
 		super(se);
 		this.index = index;
 	}
 
-	@Override public Object eval(LuaStateImpl lua) {
+	@Override public Object eval(LuanStateImpl lua) {
 		return lua.closure().upValues[index].get();
 	}
 }
--- a/src/luan/interp/IfStmt.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/IfStmt.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,7 +1,7 @@
 package luan.interp;
 
-import luan.Lua;
-import luan.LuaException;
+import luan.Luan;
+import luan.LuanException;
 
 
 final class IfStmt implements Stmt {
@@ -15,8 +15,8 @@
 		this.elseStmt = elseStmt;
 	}
 
-	@Override public void eval(LuaStateImpl lua) throws LuaException {
-		if( Lua.toBoolean( cnd.eval(lua) ) ) {
+	@Override public void eval(LuanStateImpl lua) throws LuanException {
+		if( Luan.toBoolean( cnd.eval(lua) ) ) {
 			thenStmt.eval(lua);
 		} else {
 			elseStmt.eval(lua);
--- a/src/luan/interp/IndexExpr.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/IndexExpr.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,26 +1,26 @@
 package luan.interp;
 
-import luan.Lua;
-import luan.LuaException;
-import luan.LuaTable;
-import luan.LuaFunction;
-import luan.LuaSource;
+import luan.Luan;
+import luan.LuanException;
+import luan.LuanTable;
+import luan.LuanFunction;
+import luan.LuanSource;
 
 
 final class IndexExpr extends BinaryOpExpr {
 
-	IndexExpr(LuaSource.Element se,Expr op1,Expr op2) {
+	IndexExpr(LuanSource.Element se,Expr op1,Expr op2) {
 		super(se,op1,op2);
 	}
 
-	@Override public Object eval(LuaStateImpl lua) throws LuaException {
+	@Override public Object eval(LuanStateImpl lua) throws LuanException {
 		return index(lua,op1.eval(lua),op2.eval(lua));
 	}
 
-	private Object index(LuaStateImpl lua,Object t,Object key) throws LuaException {
+	private Object index(LuanStateImpl lua,Object t,Object key) throws LuanException {
 		Object h;
-		if( t instanceof LuaTable ) {
-			LuaTable tbl = (LuaTable)t;
+		if( t instanceof LuanTable ) {
+			LuanTable tbl = (LuanTable)t;
 			Object value = tbl.get(key);
 			if( value != null )
 				return value;
@@ -30,11 +30,11 @@
 		} else {
 			h = lua.getHandler("__index",t);
 			if( h==null )
-				throw new LuaException( lua, se, "attempt to index a " + Lua.type(t) + " value" );
+				throw new LuanException( lua, se, "attempt to index a " + Luan.type(t) + " value" );
 		}
-		if( h instanceof LuaFunction ) {
-			LuaFunction fn = (LuaFunction)h;
-			return Lua.first(lua.call(fn,se,"__index",t,key));
+		if( h instanceof LuanFunction ) {
+			LuanFunction fn = (LuanFunction)h;
+			return Luan.first(lua.call(fn,se,"__index",t,key));
 		}
 		return index(lua,h,key);
 	}
--- a/src/luan/interp/LeExpr.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/LeExpr.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,18 +1,18 @@
 package luan.interp;
 
-import luan.Lua;
-import luan.LuaFunction;
-import luan.LuaException;
-import luan.LuaSource;
+import luan.Luan;
+import luan.LuanFunction;
+import luan.LuanException;
+import luan.LuanSource;
 
 
 final class LeExpr extends BinaryOpExpr {
 
-	LeExpr(LuaSource.Element se,Expr op1,Expr op2) {
+	LeExpr(LuanSource.Element se,Expr op1,Expr op2) {
 		super(se,op1,op2);
 	}
 
-	@Override public Object eval(LuaStateImpl lua) throws LuaException {
+	@Override public Object eval(LuanStateImpl lua) throws LuanException {
 		Object o1 = op1.eval(lua);
 		Object o2 = op2.eval(lua);
 		if( o1 instanceof Number && o2 instanceof Number ) {
@@ -25,12 +25,12 @@
 			String s2 = (String)o2;
 			return s1.compareTo(s2) <= 0;
 		}
-		LuaFunction fn = lua.getBinHandler(se,"__le",o1,o2);
+		LuanFunction fn = lua.getBinHandler(se,"__le",o1,o2);
 		if( fn != null )
-			return Lua.toBoolean( Lua.first(lua.call(fn,se,"__le",o1,o2)) );
+			return Luan.toBoolean( Luan.first(lua.call(fn,se,"__le",o1,o2)) );
 		fn = lua.getBinHandler(se,"__lt",o1,o2);
 		if( fn != null )
-			return !Lua.toBoolean( Lua.first(lua.call(fn,se,"__lt",o2,o1)) );
-		throw new LuaException( lua, se, "attempt to compare " + Lua.type(o1) + " with " + Lua.type(o2) );
+			return !Luan.toBoolean( Luan.first(lua.call(fn,se,"__lt",o2,o1)) );
+		throw new LuanException( lua, se, "attempt to compare " + Luan.type(o1) + " with " + Luan.type(o2) );
 	}
 }
--- a/src/luan/interp/LenExpr.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/LenExpr.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,31 +1,31 @@
 package luan.interp;
 
-import luan.Lua;
-import luan.LuaTable;
-import luan.LuaFunction;
-import luan.LuaException;
-import luan.LuaSource;
+import luan.Luan;
+import luan.LuanTable;
+import luan.LuanFunction;
+import luan.LuanException;
+import luan.LuanSource;
 
 
 final class LenExpr extends UnaryOpExpr {
 
-	LenExpr(LuaSource.Element se,Expr op) {
+	LenExpr(LuanSource.Element se,Expr op) {
 		super(se,op);
 	}
 
-	@Override public Object eval(LuaStateImpl lua) throws LuaException {
+	@Override public Object eval(LuanStateImpl lua) throws LuanException {
 		Object o = op.eval(lua);
 		if( o instanceof String ) {
 			String s = (String)o;
 			return s.length();
 		}
-		LuaFunction fn = lua.getHandlerFunction(se,"__len",o);
+		LuanFunction fn = lua.getHandlerFunction(se,"__len",o);
 		if( fn != null )
-			return Lua.first(lua.call(fn,se,"__len",o));
-		if( o instanceof LuaTable ) {
-			LuaTable t = (LuaTable)o;
+			return Luan.first(lua.call(fn,se,"__len",o));
+		if( o instanceof LuanTable ) {
+			LuanTable t = (LuanTable)o;
 			return t.length();
 		}
-		throw new LuaException( lua, se, "attempt to get length of a " + Lua.type(o) + " value" );
+		throw new LuanException( lua, se, "attempt to get length of a " + Luan.type(o) + " value" );
 	}
 }
--- a/src/luan/interp/LtExpr.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/LtExpr.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,18 +1,18 @@
 package luan.interp;
 
-import luan.Lua;
-import luan.LuaFunction;
-import luan.LuaException;
-import luan.LuaSource;
+import luan.Luan;
+import luan.LuanFunction;
+import luan.LuanException;
+import luan.LuanSource;
 
 
 final class LtExpr extends BinaryOpExpr {
 
-	LtExpr(LuaSource.Element se,Expr op1,Expr op2) {
+	LtExpr(LuanSource.Element se,Expr op1,Expr op2) {
 		super(se,op1,op2);
 	}
 
-	@Override public Object eval(LuaStateImpl lua) throws LuaException {
+	@Override public Object eval(LuanStateImpl lua) throws LuanException {
 		Object o1 = op1.eval(lua);
 		Object o2 = op2.eval(lua);
 		return lua.isLessThan(se,o1,o2);
--- a/src/luan/interp/LuaClosure.java	Thu Dec 27 04:36:44 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-package luan.interp;
-
-import luan.LuaFunction;
-import luan.LuaState;
-import luan.LuaElement;
-import luan.LuaException;
-
-
-final class LuaClosure extends LuaFunction {
-	private final Chunk chunk;
-	final UpValue[] upValues;
-	private final static UpValue[] NO_UP_VALUES = new UpValue[0];
-
-	LuaClosure(Chunk chunk,LuaStateImpl lua) {
-		this.chunk = chunk;
-		UpValue.Getter[] upValueGetters = chunk.upValueGetters;
-		if( upValueGetters.length==0 ) {
-			upValues = NO_UP_VALUES;
-		} else {
-			upValues = new UpValue[upValueGetters.length];
-			for( int i=0; i<upValues.length; i++ ) {
-				upValues[i] = upValueGetters[i].get(lua);
-			}
-		}
-	}
-
-	public Object[] call(LuaState lua,Object[] args) throws LuaException {
-		return call(this,(LuaStateImpl)lua,args);
-	}
-
-	private static Object[] call(LuaClosure closure,LuaStateImpl lua,Object[] args) throws LuaException {
-		while(true) {
-			Chunk chunk = closure.chunk;
-			Object[] varArgs = null;
-			if( chunk.isVarArg ) {
-				if( args.length > chunk.numArgs ) {
-					varArgs = new Object[ args.length - chunk.numArgs ];
-					for( int i=0; i<varArgs.length; i++ ) {
-						varArgs[i] = args[chunk.numArgs+i];
-					}
-				} else {
-					varArgs = LuaFunction.EMPTY_RTN;
-				}
-			}
-			Object[] stack = lua.newFrame(closure,chunk.stackSize,varArgs);
-			final int n = Math.min(args.length,chunk.numArgs);
-			for( int i=0; i<n; i++ ) {
-				stack[i] = args[i];
-			}
-			Object[] returnValues;
-			LuaClosure tailFn;
-			try {
-				chunk.block.eval(lua);
-			} catch(ReturnException e) {
-			} finally {
-				returnValues = lua.returnValues;
-				closure = lua.tailFn;
-				lua.popFrame();
-			}
-			if( closure == null )
-				return returnValues;
-			args = returnValues;
-		}
-	}
-
-}
--- a/src/luan/interp/LuaCompiler.java	Thu Dec 27 04:36:44 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-package luan.interp;
-
-import org.parboiled.Parboiled;
-import org.parboiled.errors.ErrorUtils;
-import org.parboiled.parserunners.ReportingParseRunner;
-import org.parboiled.parserunners.TracingParseRunner;
-import org.parboiled.support.ParsingResult;
-import luan.LuaFunction;
-import luan.LuaState;
-import luan.LuaException;
-import luan.LuaSource;
-import luan.LuaElement;
-
-
-public final class LuaCompiler {
-	private LuaCompiler() {}  // never
-
-	public static LuaFunction compile(LuaState lua,LuaSource src) throws LuaException {
-		LuaParser parser = Parboiled.createParser(LuaParser.class);
-		parser.source = src;
-		ParsingResult<?> result = new ReportingParseRunner(parser.Target()).run(src.text);
-//		ParsingResult<?> result = new TracingParseRunner(parser.Target()).run(src);
-		if( result.hasErrors() )
-			throw new LuaException( lua, null, ErrorUtils.printParseErrors(result) );
-		Object resultValue = result.resultValue;
-		if( resultValue instanceof Expressions ) {
-			final Expressions expressions = (Expressions)resultValue;
-			return new LuaFunction() {
-				public Object[] call(LuaState lua,Object[] args) throws LuaException {
-					return expressions.eval((LuaStateImpl)lua);
-				}
-			};
-		}
-		Chunk chunk = (Chunk)resultValue;
-		return chunk.newClosure((LuaStateImpl)lua);
-	}
-
-	public static LuaState newLuaState() {
-		return new LuaStateImpl();
-	}
-}
--- a/src/luan/interp/LuaParser.java	Thu Dec 27 04:36:44 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1090 +0,0 @@
-package luan.interp;
-
-import java.util.Set;
-import java.util.HashSet;
-import java.util.Arrays;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Scanner;
-import org.parboiled.BaseParser;
-import org.parboiled.Parboiled;
-import org.parboiled.Rule;
-import org.parboiled.parserunners.ReportingParseRunner;
-import org.parboiled.support.ParsingResult;
-import org.parboiled.support.Var;
-import org.parboiled.support.StringVar;
-import org.parboiled.support.StringBuilderVar;
-import org.parboiled.support.ValueStack;
-import org.parboiled.errors.ErrorUtils;
-import luan.Lua;
-import luan.LuaState;
-import luan.LuaSource;
-
-
-class LuaParser extends BaseParser<Object> {
-
-	LuaSource source;
-
-	LuaSource.Element se(int start) {
-		return new LuaSource.Element(source,start,currentIndex());
-	}
-
-	static final String _ENV = "_ENV";
-
-	static final class Frame {
-		final Frame parent;
-		final List<String> symbols = new ArrayList<String>();
-		int stackSize = 0;
-		int loops = 0;
-		boolean isVarArg = false;
-		final List<String> upValueSymbols = new ArrayList<String>();
-		final List<UpValue.Getter> upValueGetters = new ArrayList<UpValue.Getter>();
-
-		Frame() {
-			this.parent = null;
-			upValueSymbols.add(_ENV);
-			upValueGetters.add(UpValue.globalGetter);
-		}
-
-		Frame(Frame parent) {
-			this.parent = parent;
-		}
-
-		int stackIndex(String name) {
-			int i = symbols.size();
-			while( --i >= 0 ) {
-				if( symbols.get(i).equals(name) )
-					return i;
-			}
-			return -1;
-		}
-
-		int upValueIndex(String name) {
-			int i = upValueSymbols.size();
-			while( --i >= 0 ) {
-				if( upValueSymbols.get(i).equals(name) )
-					return i;
-			}
-			if( parent==null )
-				return -1;
-			i = parent.stackIndex(name);
-			if( i != -1 ) {
-				upValueGetters.add(new UpValue.StackGetter(i));
-			} else {
-				i = parent.upValueIndex(name);
-				if( i == -1 )
-					return -1;
-				upValueGetters.add(new UpValue.NestedGetter(i));
-			}
-			upValueSymbols.add(name);
-			return upValueSymbols.size() - 1;
-		}
-	}
-
-	static final UpValue.Getter[] NO_UP_VALUE_GETTERS = new UpValue.Getter[0];
-
-	int nEquals;
-	int parens = 0;
-	Frame frame = new Frame();
-
-	boolean nEquals(int n) {
-		nEquals = n;
-		return true;
-	}
-
-	boolean incParens() {
-		parens++;
-		return true;
-	}
-
-	boolean decParens() {
-		parens--;
-		return true;
-	}
-
-	List<String> symbols() {
-		return frame.symbols;
-	}
-
-	int symbolsSize() {
-		return frame.symbols.size();
-	}
-
-	boolean addSymbol(String name) {
-		frame.symbols.add(name);
-		if( frame.stackSize < symbolsSize() )
-			frame.stackSize = symbolsSize();
-		return true;
-	}
-
-	boolean addSymbols(List<String> names) {
-		frame.symbols.addAll(names);
-		if( frame.stackSize < symbolsSize() )
-			frame.stackSize = symbolsSize();
-		return true;
-	}
-
-	int stackIndex(String name) {
-		return frame.stackIndex(name);
-	}
-
-	boolean popSymbols(int n) {
-		List<String> symbols = frame.symbols;
-		while( n-- > 0 ) {
-			symbols.remove(symbols.size()-1);
-		}
-		return true;
-	}
-
-	int upValueIndex(String name) {
-		return frame.upValueIndex(name);
-	}
-
-	boolean incLoops() {
-		frame.loops++;
-		return true;
-	}
-
-	boolean decLoops() {
-		frame.loops--;
-		return true;
-	}
-
-	Chunk newChunk(int start) {
-		return new Chunk( se(start), (Stmt)pop(), frame.stackSize, symbolsSize(), frame.isVarArg, frame.upValueGetters.toArray(NO_UP_VALUE_GETTERS) );
-	}
-
-	Rule Target() {
-		Var<Integer> start = new Var<Integer>();
-		return Sequence(
-			Spaces(),
-			FirstOf(
-				Sequence( ExpList(), EOI ),
-				Sequence(
-					start.set(currentIndex()),
-					action( frame.isVarArg = true ),
-					Block(),
-					EOI,
-					push( newChunk(start.get()) )
-				)
-			)
-		);
-	}
-
-	Rule Block() {
-		Var<List<Stmt>> stmts = new Var<List<Stmt>>(new ArrayList<Stmt>());
-		Var<Integer> stackStart = new Var<Integer>(symbolsSize());
-		return Sequence(
-			Optional( Stmt(stmts) ),
-			ZeroOrMore(
-				StmtSep(),
-				Optional( Stmt(stmts) )
-			),
-			push( newBlock(stmts.get(),stackStart.get()) )
-		);
-	}
-
-	Stmt newBlock(List<Stmt> stmts,int stackStart) {
-		int stackEnd = symbolsSize();
-		popSymbols( stackEnd - stackStart );
-		if( stmts.isEmpty() )
-			return Stmt.EMPTY;
-		if( stmts.size()==1 && stackStart==stackEnd )
-			return stmts.get(0);
-		return new Block( stmts.toArray(new Stmt[0]), stackStart, stackEnd );
-	}
-
-	Rule StmtSep() {
-		return Sequence(
-			FirstOf(
-				';',
-				Sequence(
-					Optional( "--", ZeroOrMore(NoneOf("\r\n")) ),
-					EndOfLine()
-				)
-			),
-			Spaces()
-		);
-	}
-
-	Rule EndOfLine() {
-		return FirstOf("\r\n", '\r', '\n');
-	}
-
-	Rule Stmt(Var<List<Stmt>> stmts) {
-		return FirstOf(
-			LocalStmt(stmts),
-			Sequence(
-				FirstOf(
-					ReturnStmt(),
-					FunctionStmt(),
-					LocalFunctionStmt(),
-					BreakStmt(),
-					GenericForStmt(),
-					NumericForStmt(),
-					TryStmt(),
-					DoStmt(),
-					WhileStmt(),
-					RepeatStmt(),
-					IfStmt(),
-					SetStmt(),
-					ExpressionsStmt()
-				),
-				stmts.get().add( (Stmt)pop() )
-			)
-		);
-	}
-
-	Rule ReturnStmt() {
-		Var<Integer> start = new Var<Integer>();
-		return Sequence(
-			start.set(currentIndex()),
-			Keyword("return"), Expressions(),
-			push( new ReturnStmt( se(start.get()), (Expressions)pop() ) )
-		);
-	}
-
-	Rule FunctionStmt() {
-		return Sequence(
-			Keyword("function"), FnName(), Function(),
-			push( new SetStmt( (Settable)pop(1), expr(pop()) ) )
-		);
-	}
-
-	Rule FnName() {
-		Var<Integer> start = new Var<Integer>();
-		return Sequence(
-			start.set(currentIndex()),
-			push(null),  // marker
-			Name(),
-			ZeroOrMore(
-				'.', Spaces(),
-				makeVarExp(start.get()),
-				NameExpr()
-			),
-			makeSettableVar(start.get())
-		);
-	}
-
-	Rule LocalFunctionStmt() {
-		return Sequence(
-			Keyword("local"), Keyword("function"),
-			Name(),
-			addSymbol( (String)pop() ),
-			Function(),
-			push( new SetStmt( new SetLocalVar(symbolsSize()-1), expr(pop()) ) )
-		);
-	}
-
-	Rule BreakStmt() {
-		return Sequence(
-			Keyword("break"),
-			frame.loops > 0,
-			push( new BreakStmt() )
-		);
-	}
-
-	Rule GenericForStmt() {
-		Var<Integer> start = new Var<Integer>();
-		Var<Integer> stackStart = new Var<Integer>(symbolsSize());
-		Var<List<String>> names = new Var<List<String>>(new ArrayList<String>());
-		return Sequence(
-			start.set(currentIndex()),
-			Keyword("for"), NameList(names), Keyword("in"), Expr(), Keyword("do"),
-			addSymbols(names.get()),
-			LoopBlock(), Keyword("end"),
-			push( new GenericForStmt( se(start.get()), stackStart.get(), symbolsSize() - stackStart.get(), expr(pop(1)), (Stmt)pop() ) ),
-			popSymbols( symbolsSize() - stackStart.get() )
-		);
-	}
-
-	Rule NumericForStmt() {
-		Var<Integer> start = new Var<Integer>();
-		return Sequence(
-			start.set(currentIndex()),
-			Keyword("for"), Name(), '=', Spaces(), Expr(), Keyword("to"), Expr(),
-			push( new ConstExpr(1) ),  // default step
-			Optional(
-				Keyword("step"),
-				drop(),
-				Expr()
-			),
-			addSymbol( (String)pop(3) ),  // add "for" var to symbols
-			Keyword("do"), LoopBlock(), Keyword("end"),
-			push( new NumericForStmt( se(start.get()), symbolsSize()-1, expr(pop(3)), expr(pop(2)), expr(pop(1)), (Stmt)pop() ) ),
-			popSymbols(1)
-		);
-	}
-
-	Rule TryStmt() {
-		return Sequence(
-			Keyword("try"), Block(),
-			Keyword("catch"), Name(), addSymbol( (String)pop() ),
-			Keyword("do"), Block(), Keyword("end"),
-			push( new TryStmt( (Stmt)pop(1), symbolsSize()-1, (Stmt)pop() ) ),
-			popSymbols(1)
-		);
-	}
-
-	Rule DoStmt() {
-		return Sequence(
-			Keyword("do"), Block(), Keyword("end")
-		);
-	}
-
-	Rule LocalStmt(Var<List<Stmt>> stmts) {
-		Var<List<String>> names = new Var<List<String>>(new ArrayList<String>());
-		return Sequence(
-			Keyword("local"), NameList(names),
-			Optional(
-				'=', Spaces(), ExpList(),
-				stmts.get().add( newSetLocalStmt(names.get().size()) )
-			),
-			addSymbols(names.get())
-		);
-	}
-
-	Rule NameList(Var<List<String>> names) {
-		return Sequence(
-			Name(),
-			names.get().add( (String)pop() ),
-			ZeroOrMore(
-				',', Spaces(), Name(),
-				names.get().add( (String)pop() )
-			)
-		);
-	}
-
-	SetStmt newSetLocalStmt(int nVars) {
-		Expressions values = (Expressions)pop();
-		SetLocalVar[] vars = new SetLocalVar[nVars];
-		int stackStart = symbolsSize();
-		for( int i=0; i<vars.length; i++ ) {
-			vars[i] = new SetLocalVar(stackStart+i);
-		}
-		return new SetStmt( vars, values );
-	}
-
-	Rule WhileStmt() {
-		return Sequence(
-			Keyword("while"), Expr(), Keyword("do"), LoopBlock(), Keyword("end"),
-			push( new WhileStmt( expr(pop(1)), (Stmt)pop() ) )
-		);
-	}
-
-	Rule RepeatStmt() {
-		return Sequence(
-			Keyword("repeat"), LoopBlock(), Keyword("until"), Expr(),
-			push( new RepeatStmt( (Stmt)pop(1), expr(pop()) ) )
-		);
-	}
-
-	Rule LoopBlock() {
-		return Sequence( incLoops(), Block(), decLoops() );
-	}
-
-	Rule IfStmt() {
-		Var<Integer> n = new Var<Integer>(1);
-		return Sequence(
-			Keyword("if"), Expr(), Keyword("then"), Block(),
-			push(Stmt.EMPTY),
-			ZeroOrMore(
-				Keyword("elseif"), drop(), Expr(), Keyword("then"), Block(),
-				push(Stmt.EMPTY),
-				n.set(n.get()+1)
-			),
-			Optional(
-				Keyword("else"), drop(), Block()
-			),
-			Keyword("end"),
-			buildIfStmt(n.get())
-		);
-	}
-
-	boolean buildIfStmt(int n) {
-		while( n-- > 0 ) {
-			Stmt elseStmt = (Stmt)pop();
-			Stmt thenStmt = (Stmt)pop();
-			Expr cnd = expr(pop());
-			push( new IfStmt(cnd,thenStmt,elseStmt) );
-		}
-		return true;
-	}
-
-	Rule SetStmt() {
-		return Sequence(
-			VarList(),
-			'=', Spaces(),
-			ExpList(),
-			push( newSetStmt() )
-		);
-	}
-
-	Rule ExpressionsStmt() {
-		return Sequence(
-			ExpList(),
-			push( new ExpressionsStmt((Expressions)pop()) )
-		);
-	}
-
-	SetStmt newSetStmt() {
-		Expressions values = (Expressions)pop();
-		@SuppressWarnings("unchecked")
-		List<Settable> vars = (List<Settable>)pop();
-		return new SetStmt( vars.toArray(new Settable[0]), values );
-	}
-
-	Rule VarList() {
-		Var<List<Settable>> vars = new Var<List<Settable>>(new ArrayList<Settable>());
-		return Sequence(
-			SettableVar(),
-			vars.get().add( (Settable)pop() ),
-			ZeroOrMore(
-				',', Spaces(), SettableVar(),
-				vars.get().add( (Settable)pop() )
-			),
-			push(vars.get())
-		);
-	}
-
-	Rule SettableVar() {
-		Var<Integer> start = new Var<Integer>();
-		return Sequence(
-			start.set(currentIndex()),
-			Var(),
-			makeSettableVar(start.get())
-		);
-	}
-
-	boolean makeSettableVar(int start) {
-		Object obj2 = pop();
-		if( obj2==null )
-			return false;
-		Object obj1 = pop();
-		if( obj1!=null ) {
-			Expr key = expr(obj2);
-			Expr table = expr(obj1);
-			return push( new SetTableEntry(se(start),table,key) );
-		}
-		String name = (String)obj2;
-		int index = stackIndex(name);
-		if( index != -1 )
-			return push( new SetLocalVar(index) );
-		index = upValueIndex(name);
-		if( index != -1 )
-			return push( new SetUpVar(index) );
-		return push( new SetTableEntry( se(start), env(), new ConstExpr(name) ) );
-	}
-
-	Rule Expr() {
-		return FirstOf(
-			VarArgs(),
-			OrExpr()
-		);
-	}
-
-	Rule OrExpr() {
-		Var<Integer> start = new Var<Integer>();
-		return Sequence(
-			start.set(currentIndex()),
-			AndExpr(),
-			ZeroOrMore( "or", Spaces(), AndExpr(), push( new OrExpr(se(start.get()),expr(pop(1)),expr(pop())) ) )
-		);
-	}
-
-	Rule AndExpr() {
-		Var<Integer> start = new Var<Integer>();
-		return Sequence(
-			start.set(currentIndex()),
-			RelExpr(),
-			ZeroOrMore( "and", Spaces(), RelExpr(), push( new AndExpr(se(start.get()),expr(pop(1)),expr(pop())) ) )
-		);
-	}
-
-	Rule RelExpr() {
-		Var<Integer> start = new Var<Integer>();
-		return Sequence(
-			start.set(currentIndex()),
-			ConcatExpr(),
-			ZeroOrMore(
-				FirstOf(
-					Sequence( "==", Spaces(), ConcatExpr(), push( new EqExpr(se(start.get()),expr(pop(1)),expr(pop())) ) ),
-					Sequence( "~=", Spaces(), ConcatExpr(), push( new NotExpr(se(start.get()),new EqExpr(se(start.get()),expr(pop(1)),expr(pop()))) ) ),
-					Sequence( "<=", Spaces(), ConcatExpr(), push( new LeExpr(se(start.get()),expr(pop(1)),expr(pop())) ) ),
-					Sequence( ">=", Spaces(), ConcatExpr(), push( new LeExpr(se(start.get()),expr(pop()),expr(pop())) ) ),
-					Sequence( "<", Spaces(), ConcatExpr(), push( new LtExpr(se(start.get()),expr(pop(1)),expr(pop())) ) ),
-					Sequence( ">", Spaces(), ConcatExpr(), push( new LtExpr(se(start.get()),expr(pop()),expr(pop())) ) )
-				)
-			)
-		);
-	}
-
-	Rule ConcatExpr() {
-		Var<Integer> start = new Var<Integer>();
-		return Sequence(
-			start.set(currentIndex()),
-			SumExpr(),
-			Optional( "..", Spaces(), ConcatExpr(), push( new ConcatExpr(se(start.get()),expr(pop(1)),expr(pop())) ) )
-		);
-	}
-
-	Rule SumExpr() {
-		Var<Integer> start = new Var<Integer>();
-		return Sequence(
-			start.set(currentIndex()),
-			TermExpr(),
-			ZeroOrMore(
-				FirstOf(
-					Sequence( '+', Spaces(), TermExpr(), push( new AddExpr(se(start.get()),expr(pop(1)),expr(pop())) ) ),
-					Sequence( '-', TestNot('-'), Spaces(), TermExpr(), push( new SubExpr(se(start.get()),expr(pop(1)),expr(pop())) ) )
-				)
-			)
-		);
-	}
-
-	Rule TermExpr() {
-		Var<Integer> start = new Var<Integer>();
-		return Sequence(
-			start.set(currentIndex()),
-			UnaryExpr(),
-			ZeroOrMore(
-				FirstOf(
-					Sequence( '*', Spaces(), UnaryExpr(), push( new MulExpr(se(start.get()),expr(pop(1)),expr(pop())) ) ),
-					Sequence( '/', Spaces(), UnaryExpr(), push( new DivExpr(se(start.get()),expr(pop(1)),expr(pop())) ) ),
-					Sequence( '%', Spaces(), UnaryExpr(), push( new ModExpr(se(start.get()),expr(pop(1)),expr(pop())) ) )
-				)
-			)
-		);
-	}
-
-	Rule UnaryExpr() {
-		Var<Integer> start = new Var<Integer>();
-		return Sequence(
-			start.set(currentIndex()),
-			FirstOf(
-				Sequence( '#', Spaces(), PowExpr(), push( new LenExpr(se(start.get()),expr(pop())) ) ),
-				Sequence( '-', TestNot('-'), Spaces(), PowExpr(), push( new UnmExpr(se(start.get()),expr(pop())) ) ),
-				Sequence( "not", Spaces(), PowExpr(), push( new NotExpr(se(start.get()),expr(pop())) ) ),
-				PowExpr()
-			)
-		);
-	}
-
-	Rule PowExpr() {
-		Var<Integer> start = new Var<Integer>();
-		return Sequence(
-			start.set(currentIndex()),
-			SingleExpr(),
-			Optional( '^', Spaces(), PowExpr(), push( new PowExpr(se(start.get()),expr(pop(1)),expr(pop())) ) )
-		);
-	}
-
-	Rule SingleExpr() {
-		return FirstOf(
-			FunctionExpr(),
-			TableExpr(),
-			VarExp(),
-			LiteralExpr()
-		);
-	}
-
-	Rule FunctionExpr() {
-		return Sequence( "function", Spaces(), Function() );
-	}
-
-	Rule Function() {
-		Var<Integer> start = new Var<Integer>();
-		Var<List<String>> names = new Var<List<String>>(new ArrayList<String>());
-		return Sequence(
-			start.set(currentIndex()),
-			'(', incParens(), Spaces(),
-			action( frame = new Frame(frame) ),
-			Optional(
-				FirstOf(
-					Sequence(
-						NameList(names), addSymbols(names.get()),
-						Optional( ',', Spaces(), VarArgName() )
-					),
-					VarArgName()
-				)
-			),
-			')', decParens(), Spaces(), Block(), Keyword("end"),
-			push( newChunk(start.get()) ),
-			action( frame = frame.parent )
-		);
-	}
-
-	Rule VarArgName() {
-		return Sequence(
-			"...", Spaces(),
-			action( frame.isVarArg = true )
-		);
-	}
-
-	Rule VarArgs() {
-		Var<Integer> start = new Var<Integer>();
-		return Sequence(
-			start.set(currentIndex()),
-			"...", Spaces(),
-			frame.isVarArg,
-			push( new VarArgs(se(start.get())) )
-		);
-	}
-
-	Rule TableExpr() {
-		Var<Integer> start = new Var<Integer>();
-		Var<List<TableExpr.Field>> fields = new Var<List<TableExpr.Field>>(new ArrayList<TableExpr.Field>());
-		Var<ExpList.Builder> builder = new Var<ExpList.Builder>(new ExpList.Builder());
-		return Sequence(
-			start.set(currentIndex()),
-			'{', incParens(), Spaces(),
-			Optional(
-				Field(fields,builder),
-				ZeroOrMore(
-					FieldSep(),
-					Field(fields,builder)
-				),
-				Optional( FieldSep() )
-			),
-			'}', decParens(),
-			Spaces(),
-			push( new TableExpr( se(start.get()), fields.get().toArray(new TableExpr.Field[0]), builder.get().build() ) )
-		);
-	}
-
-	Rule FieldSep() {
-		return Sequence( AnyOf(",;"), Spaces() );
-	}
-
-	Rule Field(Var<List<TableExpr.Field>> fields,Var<ExpList.Builder> builder) {
-		return FirstOf(
-			Sequence(
-				FirstOf( SubExpr(), NameExpr() ),
-				'=', Spaces(), Expr(),
-				fields.get().add( new TableExpr.Field( expr(pop(1)), expr(pop()) ) )
-			),
-			Sequence(
-				Expr(),
-				addToExpList(builder.get())
-			)
-		);
-	}
-
-	static Expr expr(Object obj) {
-		if( obj instanceof Expressions )
-			return new ExpressionsExpr((Expressions)obj);
-		return (Expr)obj;
-	}
-
-	Rule VarExp() {
-		Var<Integer> start = new Var<Integer>();
-		return Sequence(
-			start.set(currentIndex()),
-			Var(),
-			makeVarExp(start.get())
-		);
-	}
-
-	Rule Var() {
-		Var<Integer> start = new Var<Integer>();
-		return Sequence(
-			start.set(currentIndex()),
-			FirstOf(
-				Sequence(
-					'(', incParens(), Spaces(), Expr(), ')', decParens(), Spaces(),
-					push(expr(pop())),
-					push(null)  // marker
-				),
-				Sequence(
-					push(null),  // marker
-					Name()
-				)
-			),
-			ZeroOrMore(
-				makeVarExp(start.get()),
-				FirstOf(
-					SubExpr(),
-					Sequence( '.', Spaces(), NameExpr() ),
-					Sequence(
-						Args(start),
-						push(null)  // marker
-					)
-				)
-			)
-		);
-	}
-
-	Expr env() {
-		int index = stackIndex(_ENV);
-		if( index != -1 )
-			return new GetLocalVar(null,index);
-		index = upValueIndex(_ENV);
-		if( index != -1 )
-			return new GetUpVar(null,index);
-		throw new RuntimeException("_ENV not found");
-	}
-
-	boolean makeVarExp(int start) {
-		Object obj2 = pop();
-		if( obj2==null )
-			return true;
-		Object obj1 = pop();
-		if( obj1 != null )
-			return push( new IndexExpr( se(start), expr(obj1), expr(obj2) ) );
-		String name = (String)obj2;
-		int index = stackIndex(name);
-		if( index != -1 )
-			return push( new GetLocalVar(se(start),index) );
-		index = upValueIndex(name);
-		if( index != -1 )
-			return push( new GetUpVar(se(start),index) );
-		return push( new IndexExpr( se(start), env(), new ConstExpr(name) ) );
-	}
-
-	// function should be on top of the stack
-	Rule Args(Var<Integer> start) {
-		return Sequence(
-			FirstOf(
-				Sequence(
-					'(', incParens(), Spaces(), Expressions(), ')', decParens(), Spaces()
-				),
-				Sequence(
-					TableExpr(),
-					push( new ExpList.SingleExpList(expr(pop())) )
-				),
-				Sequence(
-					StringLiteral(), Spaces(),
-					push( new ExpList.SingleExpList(new ConstExpr(pop())) )
-				)
-			),
-			push( new FnCall( se(start.get()), expr(pop(1)), (Expressions)pop() ) )
-		);
-	}
-
-	Rule Expressions() {
-		return FirstOf(
-			ExpList(),
-			push( ExpList.emptyExpList )
-		);
-	}
-
-	Rule ExpList() {
-		Var<ExpList.Builder> builder = new Var<ExpList.Builder>(new ExpList.Builder());
-		return Sequence(
-			Expr(),
-			addToExpList(builder.get()),
-			ZeroOrMore(
-				',', Spaces(), Expr(),
-				addToExpList(builder.get())
-			),
-			push( builder.get().build() )
-		);
-	}
-
-	boolean addToExpList(ExpList.Builder bld) {
-		Object obj = pop();
-		if( obj instanceof Expressions ) {
-			bld.add( (Expressions)obj );
-		} else {
-			bld.add( (Expr)obj );
-		}
-		return true;
-	}
-
-	Rule SubExpr() {
-		return Sequence( '[', incParens(), Spaces(), Expr(), ']', decParens(), Spaces() );
-	}
-
-	Rule NameExpr() {
-		return Sequence(
-			Name(),
-			push( new ConstExpr((String)pop()) )
-		);
-	}
-
-	Rule Name() {
-		return Sequence(
-			Sequence(
-				NameFirstChar(),
-				ZeroOrMore( NameChar() )
-			),
-			!keywords.contains(match()),
-			push(match()),
-			Spaces()
-		);
-	}
-
-	Rule NameChar() {
-		return FirstOf( NameFirstChar(), Digit() );
-	}
-
-	Rule NameFirstChar() {
-		return FirstOf(
-			CharRange('a', 'z'),
-			CharRange('A', 'Z'),
-			'_'
-		);
-	}
-
-	Rule Keyword(String keyword) {
-		return Sequence(
-			keyword,
-			TestNot( NameChar() ),
-			Spaces()
-		);
-	}
-
-	static final Set<String> keywords = new HashSet<String>(Arrays.asList(
-		"and",
-		"break",
-		"catch",
-		"do",
-		"else",
-		"elseif",
-		"end",
-		"false",
-		"for",
-		"function",
-		"goto",
-		"if",
-		"in",
-		"local",
-		"nil",
-		"not",
-		"or",
-		"repeat",
-		"return",
-		"step",
-		"then",
-		"to",
-		"true",
-		"try",
-		"until",
-		"while"
-	));
-
-	Rule LiteralExpr() {
-		return Sequence(
-			Literal(), Spaces(),
-			push(new ConstExpr(pop()))
-		);
-	}
-
-	Rule Literal() {
-		return FirstOf(
-			NilLiteral(),
-			BooleanLiteral(),
-			NumberLiteral(),
-			StringLiteral()
-		);
-	}
-
-	Rule NilLiteral() {
-		return Sequence( "nil", push(null) );
-	}
-
-	Rule BooleanLiteral() {
-		return FirstOf(
-			Sequence( "true", push(true) ),
-			Sequence( "false", push(false) )
-		);
-	}
-
-	Rule NumberLiteral() {
-		return FirstOf(
-			Sequence(
-				IgnoreCase("0x"),
-				HexNumber()
-			),
-			Sequence(
-				DecNumber(),
-				push(Double.valueOf(match()))
-			)
-		);
-	}
-
-	Rule DecNumber() {
-		return FirstOf(
-			Sequence(
-				Int(),
-				Optional( '.', Optional(Int()) ),
-				Exponent()
-			),
-			Sequence( '.', Int(), Exponent() )
-		);
-	}
-
-	Rule Exponent() {
-		return Optional(
-			IgnoreCase('e'),
-			Optional(AnyOf("+-")),
-			Int()
-		);
-	}
-
-	Rule Int() {
-		return OneOrMore(Digit());
-	}
-
-	Rule Digit() {
-		return CharRange('0', '9');
-	}
-
-	Rule HexNumber() {
-		return FirstOf(
-			Sequence(
-				HexInt(),
-				push( (double)Long.parseLong(match(),16) ),
-				Optional( '.', Optional(HexDec()) ),
-				HexExponent()
-			),
-			Sequence( push(0.0), '.', HexDec(), HexExponent() )
-		);
-	}
-
-	Rule HexDec() {
-		return Sequence(
-			HexInt(),
-			push( (Double)pop() + (double)Long.parseLong(match(),16) / Math.pow(16,matchLength()) )
-		);
-	}
-
-	Rule HexExponent() {
-		return Optional(
-			IgnoreCase('p'),
-			Sequence(
-				Optional(AnyOf("+-")),
-				HexInt()
-			),
-			push( (Double)pop() * Math.pow(2,(double)Long.parseLong(match())) )
-		);
-	}
-
-	Rule HexInt() {
-		return OneOrMore(Digit());
-	}
-
-
-	Rule HexDigit() {
-		return FirstOf(
-			Digit(),
-			AnyOf("abcdefABCDEF")
-		);
-	}
-
-	Rule StringLiteral() {
-		return FirstOf(
-			QuotedString('"'),
-			QuotedString('\''),
-			LongString()
-		);
-	}
-
-	Rule LongString() {
-		return Sequence(
-			'[',
-			ZeroOrMore('='),
-			nEquals(matchLength()),
-			'[',
-			ZeroOrMore(
-				TestNot(LongBracketsEnd()),
-				ANY
-			),
-			push( match() ),
-			LongBracketsEnd()
-		);
-	}
-
-	Rule QuotedString(char quote) {
-		StringBuilderVar buf = new StringBuilderVar();
-		return Sequence(
-			quote,
-			ZeroOrMore(
-				FirstOf(
-					Sequence(
-						NoneOf("\\\n"+quote),
-						buf.append(matchedChar())
-					),
-					EscSeq(buf)
-				)
-			),
-			quote,
-			push( buf.getString() )
-		);
-	}
-
-	Rule EscSeq(StringBuilderVar buf) {
-		return Sequence(
-			'\\',
-			FirstOf(
-				Sequence( 'a', buf.append('\u0007') ),
-				Sequence( 'b', buf.append('\b') ),
-				Sequence( 'f', buf.append('\f') ),
-				Sequence( 'n', buf.append('\n') ),
-				Sequence( 'r', buf.append('\r') ),
-				Sequence( 't', buf.append('\t') ),
-				Sequence( 'v', buf.append('\u000b') ),
-				Sequence( '\\', buf.append('\\') ),
-				Sequence( '"', buf.append('"') ),
-				Sequence( '\'', buf.append('\'') ),
-				Sequence(
-					'x',
-					Sequence( HexDigit(), HexDigit() ),
-					buf.append( (char)Integer.parseInt(match(),16) )
-				),
-				Sequence(
-					Sequence(
-						Digit(),
-						Optional(
-							Digit(),
-							Optional(
-								Digit()
-							)
-						)
-					),
-					buf.append( (char)Integer.parseInt(match()) )
-				)
-			)
-		);
-	}
-
-	Rule Spaces() {
-		return ZeroOrMore(
-			FirstOf(
-				AnyOf(" \t"),
-				Comment(),
-				Sequence( '\\', EndOfLine() ),
-				Sequence( AnyOf("\r\n"), parens > 0 )
-			)
-		);
-	}
-
-	Rule Comment() {
-		return Sequence(
-			"--[",
-			ZeroOrMore('='),
-			nEquals(matchLength()),
-			'[',
-			ZeroOrMore(
-				TestNot(LongBracketsEnd()),
-				ANY
-			),
-			LongBracketsEnd()
-		);
-	}
-
-	Rule LongBracketsEnd() {
-		return Sequence( ']', ZeroOrMore('='), nEquals==matchLength(), ']' );
-	}
-
-	static boolean action(Object obj) {
-		return true;
-	}
-
-	// for debugging
-	boolean print(Object o) {
-		System.out.println(o);
-		return true;
-	}
-
-}
--- a/src/luan/interp/LuaStateImpl.java	Thu Dec 27 04:36:44 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-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;
-import luan.LuaElement;
-
-
-final class LuaStateImpl extends LuaState {
-
-	final Object arithmetic(LuaElement el,String op,Object o1,Object o2) throws LuaException {
-		LuaFunction fn = getBinHandler(el,op,o1,o2);
-		if( fn != null )
-			return Lua.first(call(fn,el,op,o1,o2));
-		String type = Lua.toNumber(o1)==null ? Lua.type(o1) : Lua.type(o2);
-		throw new LuaException(this,el,"attempt to perform arithmetic on a "+type+" value");
-	}
-
-
-	private static class Frame {
-		final Frame previousFrame;
-		final LuaClosure closure;
-		final Object[] stack;
-		final Object[] varArgs;
-		UpValue[] downValues = null;
-
-		Frame( Frame previousFrame, LuaClosure closure, int stackSize, Object[] varArgs) {
-			this.previousFrame = previousFrame;
-			this.closure = closure;
-			this.stack = new Object[stackSize];
-			this.varArgs = varArgs;
-		}
-
-		void stackClear(int start,int end) {
-			if( downValues != null ) {
-				for( int i=start; i<end; i++ ) {
-					UpValue downValue = downValues[i];
-					if( downValue != null ) {
-						downValue.close();
-						downValues[i] = null;
-					}
-				}
-			}
-			for( int i=start; i<end; i++ ) {
-				stack[i] = null;
-			}
-		}
-
-		UpValue getUpValue(int index) {
-			if( downValues==null )
-				downValues = new UpValue[stack.length];
-			if( downValues[index] == null )
-				downValues[index] = new UpValue(stack,index);
-			return downValues[index];
-		}
-	}
-
-	private Frame frame = null;
-	Object[] returnValues;
-	LuaClosure tailFn;
-
-	// returns stack
-	Object[] newFrame(LuaClosure closure, int stackSize, Object[] varArgs) {
-		frame = new Frame(frame,closure,stackSize,varArgs);
-		return frame.stack;
-	}
-
-	void popFrame() {
-		returnValues = LuaFunction.EMPTY_RTN;
-		tailFn = null;
-		frame = frame.previousFrame;
-	}
-
-	Object stackGet(int index) {
-		return frame.stack[index];
-	}
-
-	void stackSet(int index,Object value) {
-		frame.stack[index] = value;
-	}
-
-	void stackClear(int start,int end) {
-		frame.stackClear(start,end);
-	}
-
-	Object[] varArgs() {
-		return frame.varArgs;
-	}
-
-	LuaClosure closure() {
-		return frame.closure;
-	}
-
-	UpValue getUpValue(int index) {
-		return frame.getUpValue(index);
-	}
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/interp/LuanCompiler.java	Fri Dec 28 03:29:12 2012 +0000
@@ -0,0 +1,41 @@
+package luan.interp;
+
+import org.parboiled.Parboiled;
+import org.parboiled.errors.ErrorUtils;
+import org.parboiled.parserunners.ReportingParseRunner;
+import org.parboiled.parserunners.TracingParseRunner;
+import org.parboiled.support.ParsingResult;
+import luan.LuanFunction;
+import luan.LuanState;
+import luan.LuanException;
+import luan.LuanSource;
+import luan.LuanElement;
+
+
+public final class LuanCompiler {
+	private LuanCompiler() {}  // never
+
+	public static LuanFunction compile(LuanState lua,LuanSource src) throws LuanException {
+		LuanParser parser = Parboiled.createParser(LuanParser.class);
+		parser.source = src;
+		ParsingResult<?> result = new ReportingParseRunner(parser.Target()).run(src.text);
+//		ParsingResult<?> result = new TracingParseRunner(parser.Target()).run(src);
+		if( result.hasErrors() )
+			throw new LuanException( lua, null, ErrorUtils.printParseErrors(result) );
+		Object resultValue = result.resultValue;
+		if( resultValue instanceof Expressions ) {
+			final Expressions expressions = (Expressions)resultValue;
+			return new LuanFunction() {
+				public Object[] call(LuanState lua,Object[] args) throws LuanException {
+					return expressions.eval((LuanStateImpl)lua);
+				}
+			};
+		}
+		Chunk chunk = (Chunk)resultValue;
+		return chunk.newClosure((LuanStateImpl)lua);
+	}
+
+	public static LuanState newLuaState() {
+		return new LuanStateImpl();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/interp/LuanParser.java	Fri Dec 28 03:29:12 2012 +0000
@@ -0,0 +1,1090 @@
+package luan.interp;
+
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Arrays;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Scanner;
+import org.parboiled.BaseParser;
+import org.parboiled.Parboiled;
+import org.parboiled.Rule;
+import org.parboiled.parserunners.ReportingParseRunner;
+import org.parboiled.support.ParsingResult;
+import org.parboiled.support.Var;
+import org.parboiled.support.StringVar;
+import org.parboiled.support.StringBuilderVar;
+import org.parboiled.support.ValueStack;
+import org.parboiled.errors.ErrorUtils;
+import luan.Luan;
+import luan.LuanState;
+import luan.LuanSource;
+
+
+class LuanParser extends BaseParser<Object> {
+
+	LuanSource source;
+
+	LuanSource.Element se(int start) {
+		return new LuanSource.Element(source,start,currentIndex());
+	}
+
+	static final String _ENV = "_ENV";
+
+	static final class Frame {
+		final Frame parent;
+		final List<String> symbols = new ArrayList<String>();
+		int stackSize = 0;
+		int loops = 0;
+		boolean isVarArg = false;
+		final List<String> upValueSymbols = new ArrayList<String>();
+		final List<UpValue.Getter> upValueGetters = new ArrayList<UpValue.Getter>();
+
+		Frame() {
+			this.parent = null;
+			upValueSymbols.add(_ENV);
+			upValueGetters.add(UpValue.globalGetter);
+		}
+
+		Frame(Frame parent) {
+			this.parent = parent;
+		}
+
+		int stackIndex(String name) {
+			int i = symbols.size();
+			while( --i >= 0 ) {
+				if( symbols.get(i).equals(name) )
+					return i;
+			}
+			return -1;
+		}
+
+		int upValueIndex(String name) {
+			int i = upValueSymbols.size();
+			while( --i >= 0 ) {
+				if( upValueSymbols.get(i).equals(name) )
+					return i;
+			}
+			if( parent==null )
+				return -1;
+			i = parent.stackIndex(name);
+			if( i != -1 ) {
+				upValueGetters.add(new UpValue.StackGetter(i));
+			} else {
+				i = parent.upValueIndex(name);
+				if( i == -1 )
+					return -1;
+				upValueGetters.add(new UpValue.NestedGetter(i));
+			}
+			upValueSymbols.add(name);
+			return upValueSymbols.size() - 1;
+		}
+	}
+
+	static final UpValue.Getter[] NO_UP_VALUE_GETTERS = new UpValue.Getter[0];
+
+	int nEquals;
+	int parens = 0;
+	Frame frame = new Frame();
+
+	boolean nEquals(int n) {
+		nEquals = n;
+		return true;
+	}
+
+	boolean incParens() {
+		parens++;
+		return true;
+	}
+
+	boolean decParens() {
+		parens--;
+		return true;
+	}
+
+	List<String> symbols() {
+		return frame.symbols;
+	}
+
+	int symbolsSize() {
+		return frame.symbols.size();
+	}
+
+	boolean addSymbol(String name) {
+		frame.symbols.add(name);
+		if( frame.stackSize < symbolsSize() )
+			frame.stackSize = symbolsSize();
+		return true;
+	}
+
+	boolean addSymbols(List<String> names) {
+		frame.symbols.addAll(names);
+		if( frame.stackSize < symbolsSize() )
+			frame.stackSize = symbolsSize();
+		return true;
+	}
+
+	int stackIndex(String name) {
+		return frame.stackIndex(name);
+	}
+
+	boolean popSymbols(int n) {
+		List<String> symbols = frame.symbols;
+		while( n-- > 0 ) {
+			symbols.remove(symbols.size()-1);
+		}
+		return true;
+	}
+
+	int upValueIndex(String name) {
+		return frame.upValueIndex(name);
+	}
+
+	boolean incLoops() {
+		frame.loops++;
+		return true;
+	}
+
+	boolean decLoops() {
+		frame.loops--;
+		return true;
+	}
+
+	Chunk newChunk(int start) {
+		return new Chunk( se(start), (Stmt)pop(), frame.stackSize, symbolsSize(), frame.isVarArg, frame.upValueGetters.toArray(NO_UP_VALUE_GETTERS) );
+	}
+
+	Rule Target() {
+		Var<Integer> start = new Var<Integer>();
+		return Sequence(
+			Spaces(),
+			FirstOf(
+				Sequence( ExpList(), EOI ),
+				Sequence(
+					start.set(currentIndex()),
+					action( frame.isVarArg = true ),
+					Block(),
+					EOI,
+					push( newChunk(start.get()) )
+				)
+			)
+		);
+	}
+
+	Rule Block() {
+		Var<List<Stmt>> stmts = new Var<List<Stmt>>(new ArrayList<Stmt>());
+		Var<Integer> stackStart = new Var<Integer>(symbolsSize());
+		return Sequence(
+			Optional( Stmt(stmts) ),
+			ZeroOrMore(
+				StmtSep(),
+				Optional( Stmt(stmts) )
+			),
+			push( newBlock(stmts.get(),stackStart.get()) )
+		);
+	}
+
+	Stmt newBlock(List<Stmt> stmts,int stackStart) {
+		int stackEnd = symbolsSize();
+		popSymbols( stackEnd - stackStart );
+		if( stmts.isEmpty() )
+			return Stmt.EMPTY;
+		if( stmts.size()==1 && stackStart==stackEnd )
+			return stmts.get(0);
+		return new Block( stmts.toArray(new Stmt[0]), stackStart, stackEnd );
+	}
+
+	Rule StmtSep() {
+		return Sequence(
+			FirstOf(
+				';',
+				Sequence(
+					Optional( "--", ZeroOrMore(NoneOf("\r\n")) ),
+					EndOfLine()
+				)
+			),
+			Spaces()
+		);
+	}
+
+	Rule EndOfLine() {
+		return FirstOf("\r\n", '\r', '\n');
+	}
+
+	Rule Stmt(Var<List<Stmt>> stmts) {
+		return FirstOf(
+			LocalStmt(stmts),
+			Sequence(
+				FirstOf(
+					ReturnStmt(),
+					FunctionStmt(),
+					LocalFunctionStmt(),
+					BreakStmt(),
+					GenericForStmt(),
+					NumericForStmt(),
+					TryStmt(),
+					DoStmt(),
+					WhileStmt(),
+					RepeatStmt(),
+					IfStmt(),
+					SetStmt(),
+					ExpressionsStmt()
+				),
+				stmts.get().add( (Stmt)pop() )
+			)
+		);
+	}
+
+	Rule ReturnStmt() {
+		Var<Integer> start = new Var<Integer>();
+		return Sequence(
+			start.set(currentIndex()),
+			Keyword("return"), Expressions(),
+			push( new ReturnStmt( se(start.get()), (Expressions)pop() ) )
+		);
+	}
+
+	Rule FunctionStmt() {
+		return Sequence(
+			Keyword("function"), FnName(), Function(),
+			push( new SetStmt( (Settable)pop(1), expr(pop()) ) )
+		);
+	}
+
+	Rule FnName() {
+		Var<Integer> start = new Var<Integer>();
+		return Sequence(
+			start.set(currentIndex()),
+			push(null),  // marker
+			Name(),
+			ZeroOrMore(
+				'.', Spaces(),
+				makeVarExp(start.get()),
+				NameExpr()
+			),
+			makeSettableVar(start.get())
+		);
+	}
+
+	Rule LocalFunctionStmt() {
+		return Sequence(
+			Keyword("local"), Keyword("function"),
+			Name(),
+			addSymbol( (String)pop() ),
+			Function(),
+			push( new SetStmt( new SetLocalVar(symbolsSize()-1), expr(pop()) ) )
+		);
+	}
+
+	Rule BreakStmt() {
+		return Sequence(
+			Keyword("break"),
+			frame.loops > 0,
+			push( new BreakStmt() )
+		);
+	}
+
+	Rule GenericForStmt() {
+		Var<Integer> start = new Var<Integer>();
+		Var<Integer> stackStart = new Var<Integer>(symbolsSize());
+		Var<List<String>> names = new Var<List<String>>(new ArrayList<String>());
+		return Sequence(
+			start.set(currentIndex()),
+			Keyword("for"), NameList(names), Keyword("in"), Expr(), Keyword("do"),
+			addSymbols(names.get()),
+			LoopBlock(), Keyword("end"),
+			push( new GenericForStmt( se(start.get()), stackStart.get(), symbolsSize() - stackStart.get(), expr(pop(1)), (Stmt)pop() ) ),
+			popSymbols( symbolsSize() - stackStart.get() )
+		);
+	}
+
+	Rule NumericForStmt() {
+		Var<Integer> start = new Var<Integer>();
+		return Sequence(
+			start.set(currentIndex()),
+			Keyword("for"), Name(), '=', Spaces(), Expr(), Keyword("to"), Expr(),
+			push( new ConstExpr(1) ),  // default step
+			Optional(
+				Keyword("step"),
+				drop(),
+				Expr()
+			),
+			addSymbol( (String)pop(3) ),  // add "for" var to symbols
+			Keyword("do"), LoopBlock(), Keyword("end"),
+			push( new NumericForStmt( se(start.get()), symbolsSize()-1, expr(pop(3)), expr(pop(2)), expr(pop(1)), (Stmt)pop() ) ),
+			popSymbols(1)
+		);
+	}
+
+	Rule TryStmt() {
+		return Sequence(
+			Keyword("try"), Block(),
+			Keyword("catch"), Name(), addSymbol( (String)pop() ),
+			Keyword("do"), Block(), Keyword("end"),
+			push( new TryStmt( (Stmt)pop(1), symbolsSize()-1, (Stmt)pop() ) ),
+			popSymbols(1)
+		);
+	}
+
+	Rule DoStmt() {
+		return Sequence(
+			Keyword("do"), Block(), Keyword("end")
+		);
+	}
+
+	Rule LocalStmt(Var<List<Stmt>> stmts) {
+		Var<List<String>> names = new Var<List<String>>(new ArrayList<String>());
+		return Sequence(
+			Keyword("local"), NameList(names),
+			Optional(
+				'=', Spaces(), ExpList(),
+				stmts.get().add( newSetLocalStmt(names.get().size()) )
+			),
+			addSymbols(names.get())
+		);
+	}
+
+	Rule NameList(Var<List<String>> names) {
+		return Sequence(
+			Name(),
+			names.get().add( (String)pop() ),
+			ZeroOrMore(
+				',', Spaces(), Name(),
+				names.get().add( (String)pop() )
+			)
+		);
+	}
+
+	SetStmt newSetLocalStmt(int nVars) {
+		Expressions values = (Expressions)pop();
+		SetLocalVar[] vars = new SetLocalVar[nVars];
+		int stackStart = symbolsSize();
+		for( int i=0; i<vars.length; i++ ) {
+			vars[i] = new SetLocalVar(stackStart+i);
+		}
+		return new SetStmt( vars, values );
+	}
+
+	Rule WhileStmt() {
+		return Sequence(
+			Keyword("while"), Expr(), Keyword("do"), LoopBlock(), Keyword("end"),
+			push( new WhileStmt( expr(pop(1)), (Stmt)pop() ) )
+		);
+	}
+
+	Rule RepeatStmt() {
+		return Sequence(
+			Keyword("repeat"), LoopBlock(), Keyword("until"), Expr(),
+			push( new RepeatStmt( (Stmt)pop(1), expr(pop()) ) )
+		);
+	}
+
+	Rule LoopBlock() {
+		return Sequence( incLoops(), Block(), decLoops() );
+	}
+
+	Rule IfStmt() {
+		Var<Integer> n = new Var<Integer>(1);
+		return Sequence(
+			Keyword("if"), Expr(), Keyword("then"), Block(),
+			push(Stmt.EMPTY),
+			ZeroOrMore(
+				Keyword("elseif"), drop(), Expr(), Keyword("then"), Block(),
+				push(Stmt.EMPTY),
+				n.set(n.get()+1)
+			),
+			Optional(
+				Keyword("else"), drop(), Block()
+			),
+			Keyword("end"),
+			buildIfStmt(n.get())
+		);
+	}
+
+	boolean buildIfStmt(int n) {
+		while( n-- > 0 ) {
+			Stmt elseStmt = (Stmt)pop();
+			Stmt thenStmt = (Stmt)pop();
+			Expr cnd = expr(pop());
+			push( new IfStmt(cnd,thenStmt,elseStmt) );
+		}
+		return true;
+	}
+
+	Rule SetStmt() {
+		return Sequence(
+			VarList(),
+			'=', Spaces(),
+			ExpList(),
+			push( newSetStmt() )
+		);
+	}
+
+	Rule ExpressionsStmt() {
+		return Sequence(
+			ExpList(),
+			push( new ExpressionsStmt((Expressions)pop()) )
+		);
+	}
+
+	SetStmt newSetStmt() {
+		Expressions values = (Expressions)pop();
+		@SuppressWarnings("unchecked")
+		List<Settable> vars = (List<Settable>)pop();
+		return new SetStmt( vars.toArray(new Settable[0]), values );
+	}
+
+	Rule VarList() {
+		Var<List<Settable>> vars = new Var<List<Settable>>(new ArrayList<Settable>());
+		return Sequence(
+			SettableVar(),
+			vars.get().add( (Settable)pop() ),
+			ZeroOrMore(
+				',', Spaces(), SettableVar(),
+				vars.get().add( (Settable)pop() )
+			),
+			push(vars.get())
+		);
+	}
+
+	Rule SettableVar() {
+		Var<Integer> start = new Var<Integer>();
+		return Sequence(
+			start.set(currentIndex()),
+			Var(),
+			makeSettableVar(start.get())
+		);
+	}
+
+	boolean makeSettableVar(int start) {
+		Object obj2 = pop();
+		if( obj2==null )
+			return false;
+		Object obj1 = pop();
+		if( obj1!=null ) {
+			Expr key = expr(obj2);
+			Expr table = expr(obj1);
+			return push( new SetTableEntry(se(start),table,key) );
+		}
+		String name = (String)obj2;
+		int index = stackIndex(name);
+		if( index != -1 )
+			return push( new SetLocalVar(index) );
+		index = upValueIndex(name);
+		if( index != -1 )
+			return push( new SetUpVar(index) );
+		return push( new SetTableEntry( se(start), env(), new ConstExpr(name) ) );
+	}
+
+	Rule Expr() {
+		return FirstOf(
+			VarArgs(),
+			OrExpr()
+		);
+	}
+
+	Rule OrExpr() {
+		Var<Integer> start = new Var<Integer>();
+		return Sequence(
+			start.set(currentIndex()),
+			AndExpr(),
+			ZeroOrMore( "or", Spaces(), AndExpr(), push( new OrExpr(se(start.get()),expr(pop(1)),expr(pop())) ) )
+		);
+	}
+
+	Rule AndExpr() {
+		Var<Integer> start = new Var<Integer>();
+		return Sequence(
+			start.set(currentIndex()),
+			RelExpr(),
+			ZeroOrMore( "and", Spaces(), RelExpr(), push( new AndExpr(se(start.get()),expr(pop(1)),expr(pop())) ) )
+		);
+	}
+
+	Rule RelExpr() {
+		Var<Integer> start = new Var<Integer>();
+		return Sequence(
+			start.set(currentIndex()),
+			ConcatExpr(),
+			ZeroOrMore(
+				FirstOf(
+					Sequence( "==", Spaces(), ConcatExpr(), push( new EqExpr(se(start.get()),expr(pop(1)),expr(pop())) ) ),
+					Sequence( "~=", Spaces(), ConcatExpr(), push( new NotExpr(se(start.get()),new EqExpr(se(start.get()),expr(pop(1)),expr(pop()))) ) ),
+					Sequence( "<=", Spaces(), ConcatExpr(), push( new LeExpr(se(start.get()),expr(pop(1)),expr(pop())) ) ),
+					Sequence( ">=", Spaces(), ConcatExpr(), push( new LeExpr(se(start.get()),expr(pop()),expr(pop())) ) ),
+					Sequence( "<", Spaces(), ConcatExpr(), push( new LtExpr(se(start.get()),expr(pop(1)),expr(pop())) ) ),
+					Sequence( ">", Spaces(), ConcatExpr(), push( new LtExpr(se(start.get()),expr(pop()),expr(pop())) ) )
+				)
+			)
+		);
+	}
+
+	Rule ConcatExpr() {
+		Var<Integer> start = new Var<Integer>();
+		return Sequence(
+			start.set(currentIndex()),
+			SumExpr(),
+			Optional( "..", Spaces(), ConcatExpr(), push( new ConcatExpr(se(start.get()),expr(pop(1)),expr(pop())) ) )
+		);
+	}
+
+	Rule SumExpr() {
+		Var<Integer> start = new Var<Integer>();
+		return Sequence(
+			start.set(currentIndex()),
+			TermExpr(),
+			ZeroOrMore(
+				FirstOf(
+					Sequence( '+', Spaces(), TermExpr(), push( new AddExpr(se(start.get()),expr(pop(1)),expr(pop())) ) ),
+					Sequence( '-', TestNot('-'), Spaces(), TermExpr(), push( new SubExpr(se(start.get()),expr(pop(1)),expr(pop())) ) )
+				)
+			)
+		);
+	}
+
+	Rule TermExpr() {
+		Var<Integer> start = new Var<Integer>();
+		return Sequence(
+			start.set(currentIndex()),
+			UnaryExpr(),
+			ZeroOrMore(
+				FirstOf(
+					Sequence( '*', Spaces(), UnaryExpr(), push( new MulExpr(se(start.get()),expr(pop(1)),expr(pop())) ) ),
+					Sequence( '/', Spaces(), UnaryExpr(), push( new DivExpr(se(start.get()),expr(pop(1)),expr(pop())) ) ),
+					Sequence( '%', Spaces(), UnaryExpr(), push( new ModExpr(se(start.get()),expr(pop(1)),expr(pop())) ) )
+				)
+			)
+		);
+	}
+
+	Rule UnaryExpr() {
+		Var<Integer> start = new Var<Integer>();
+		return Sequence(
+			start.set(currentIndex()),
+			FirstOf(
+				Sequence( '#', Spaces(), PowExpr(), push( new LenExpr(se(start.get()),expr(pop())) ) ),
+				Sequence( '-', TestNot('-'), Spaces(), PowExpr(), push( new UnmExpr(se(start.get()),expr(pop())) ) ),
+				Sequence( "not", Spaces(), PowExpr(), push( new NotExpr(se(start.get()),expr(pop())) ) ),
+				PowExpr()
+			)
+		);
+	}
+
+	Rule PowExpr() {
+		Var<Integer> start = new Var<Integer>();
+		return Sequence(
+			start.set(currentIndex()),
+			SingleExpr(),
+			Optional( '^', Spaces(), PowExpr(), push( new PowExpr(se(start.get()),expr(pop(1)),expr(pop())) ) )
+		);
+	}
+
+	Rule SingleExpr() {
+		return FirstOf(
+			FunctionExpr(),
+			TableExpr(),
+			VarExp(),
+			LiteralExpr()
+		);
+	}
+
+	Rule FunctionExpr() {
+		return Sequence( "function", Spaces(), Function() );
+	}
+
+	Rule Function() {
+		Var<Integer> start = new Var<Integer>();
+		Var<List<String>> names = new Var<List<String>>(new ArrayList<String>());
+		return Sequence(
+			start.set(currentIndex()),
+			'(', incParens(), Spaces(),
+			action( frame = new Frame(frame) ),
+			Optional(
+				FirstOf(
+					Sequence(
+						NameList(names), addSymbols(names.get()),
+						Optional( ',', Spaces(), VarArgName() )
+					),
+					VarArgName()
+				)
+			),
+			')', decParens(), Spaces(), Block(), Keyword("end"),
+			push( newChunk(start.get()) ),
+			action( frame = frame.parent )
+		);
+	}
+
+	Rule VarArgName() {
+		return Sequence(
+			"...", Spaces(),
+			action( frame.isVarArg = true )
+		);
+	}
+
+	Rule VarArgs() {
+		Var<Integer> start = new Var<Integer>();
+		return Sequence(
+			start.set(currentIndex()),
+			"...", Spaces(),
+			frame.isVarArg,
+			push( new VarArgs(se(start.get())) )
+		);
+	}
+
+	Rule TableExpr() {
+		Var<Integer> start = new Var<Integer>();
+		Var<List<TableExpr.Field>> fields = new Var<List<TableExpr.Field>>(new ArrayList<TableExpr.Field>());
+		Var<ExpList.Builder> builder = new Var<ExpList.Builder>(new ExpList.Builder());
+		return Sequence(
+			start.set(currentIndex()),
+			'{', incParens(), Spaces(),
+			Optional(
+				Field(fields,builder),
+				ZeroOrMore(
+					FieldSep(),
+					Field(fields,builder)
+				),
+				Optional( FieldSep() )
+			),
+			'}', decParens(),
+			Spaces(),
+			push( new TableExpr( se(start.get()), fields.get().toArray(new TableExpr.Field[0]), builder.get().build() ) )
+		);
+	}
+
+	Rule FieldSep() {
+		return Sequence( AnyOf(",;"), Spaces() );
+	}
+
+	Rule Field(Var<List<TableExpr.Field>> fields,Var<ExpList.Builder> builder) {
+		return FirstOf(
+			Sequence(
+				FirstOf( SubExpr(), NameExpr() ),
+				'=', Spaces(), Expr(),
+				fields.get().add( new TableExpr.Field( expr(pop(1)), expr(pop()) ) )
+			),
+			Sequence(
+				Expr(),
+				addToExpList(builder.get())
+			)
+		);
+	}
+
+	static Expr expr(Object obj) {
+		if( obj instanceof Expressions )
+			return new ExpressionsExpr((Expressions)obj);
+		return (Expr)obj;
+	}
+
+	Rule VarExp() {
+		Var<Integer> start = new Var<Integer>();
+		return Sequence(
+			start.set(currentIndex()),
+			Var(),
+			makeVarExp(start.get())
+		);
+	}
+
+	Rule Var() {
+		Var<Integer> start = new Var<Integer>();
+		return Sequence(
+			start.set(currentIndex()),
+			FirstOf(
+				Sequence(
+					'(', incParens(), Spaces(), Expr(), ')', decParens(), Spaces(),
+					push(expr(pop())),
+					push(null)  // marker
+				),
+				Sequence(
+					push(null),  // marker
+					Name()
+				)
+			),
+			ZeroOrMore(
+				makeVarExp(start.get()),
+				FirstOf(
+					SubExpr(),
+					Sequence( '.', Spaces(), NameExpr() ),
+					Sequence(
+						Args(start),
+						push(null)  // marker
+					)
+				)
+			)
+		);
+	}
+
+	Expr env() {
+		int index = stackIndex(_ENV);
+		if( index != -1 )
+			return new GetLocalVar(null,index);
+		index = upValueIndex(_ENV);
+		if( index != -1 )
+			return new GetUpVar(null,index);
+		throw new RuntimeException("_ENV not found");
+	}
+
+	boolean makeVarExp(int start) {
+		Object obj2 = pop();
+		if( obj2==null )
+			return true;
+		Object obj1 = pop();
+		if( obj1 != null )
+			return push( new IndexExpr( se(start), expr(obj1), expr(obj2) ) );
+		String name = (String)obj2;
+		int index = stackIndex(name);
+		if( index != -1 )
+			return push( new GetLocalVar(se(start),index) );
+		index = upValueIndex(name);
+		if( index != -1 )
+			return push( new GetUpVar(se(start),index) );
+		return push( new IndexExpr( se(start), env(), new ConstExpr(name) ) );
+	}
+
+	// function should be on top of the stack
+	Rule Args(Var<Integer> start) {
+		return Sequence(
+			FirstOf(
+				Sequence(
+					'(', incParens(), Spaces(), Expressions(), ')', decParens(), Spaces()
+				),
+				Sequence(
+					TableExpr(),
+					push( new ExpList.SingleExpList(expr(pop())) )
+				),
+				Sequence(
+					StringLiteral(), Spaces(),
+					push( new ExpList.SingleExpList(new ConstExpr(pop())) )
+				)
+			),
+			push( new FnCall( se(start.get()), expr(pop(1)), (Expressions)pop() ) )
+		);
+	}
+
+	Rule Expressions() {
+		return FirstOf(
+			ExpList(),
+			push( ExpList.emptyExpList )
+		);
+	}
+
+	Rule ExpList() {
+		Var<ExpList.Builder> builder = new Var<ExpList.Builder>(new ExpList.Builder());
+		return Sequence(
+			Expr(),
+			addToExpList(builder.get()),
+			ZeroOrMore(
+				',', Spaces(), Expr(),
+				addToExpList(builder.get())
+			),
+			push( builder.get().build() )
+		);
+	}
+
+	boolean addToExpList(ExpList.Builder bld) {
+		Object obj = pop();
+		if( obj instanceof Expressions ) {
+			bld.add( (Expressions)obj );
+		} else {
+			bld.add( (Expr)obj );
+		}
+		return true;
+	}
+
+	Rule SubExpr() {
+		return Sequence( '[', incParens(), Spaces(), Expr(), ']', decParens(), Spaces() );
+	}
+
+	Rule NameExpr() {
+		return Sequence(
+			Name(),
+			push( new ConstExpr((String)pop()) )
+		);
+	}
+
+	Rule Name() {
+		return Sequence(
+			Sequence(
+				NameFirstChar(),
+				ZeroOrMore( NameChar() )
+			),
+			!keywords.contains(match()),
+			push(match()),
+			Spaces()
+		);
+	}
+
+	Rule NameChar() {
+		return FirstOf( NameFirstChar(), Digit() );
+	}
+
+	Rule NameFirstChar() {
+		return FirstOf(
+			CharRange('a', 'z'),
+			CharRange('A', 'Z'),
+			'_'
+		);
+	}
+
+	Rule Keyword(String keyword) {
+		return Sequence(
+			keyword,
+			TestNot( NameChar() ),
+			Spaces()
+		);
+	}
+
+	static final Set<String> keywords = new HashSet<String>(Arrays.asList(
+		"and",
+		"break",
+		"catch",
+		"do",
+		"else",
+		"elseif",
+		"end",
+		"false",
+		"for",
+		"function",
+		"goto",
+		"if",
+		"in",
+		"local",
+		"nil",
+		"not",
+		"or",
+		"repeat",
+		"return",
+		"step",
+		"then",
+		"to",
+		"true",
+		"try",
+		"until",
+		"while"
+	));
+
+	Rule LiteralExpr() {
+		return Sequence(
+			Literal(), Spaces(),
+			push(new ConstExpr(pop()))
+		);
+	}
+
+	Rule Literal() {
+		return FirstOf(
+			NilLiteral(),
+			BooleanLiteral(),
+			NumberLiteral(),
+			StringLiteral()
+		);
+	}
+
+	Rule NilLiteral() {
+		return Sequence( "nil", push(null) );
+	}
+
+	Rule BooleanLiteral() {
+		return FirstOf(
+			Sequence( "true", push(true) ),
+			Sequence( "false", push(false) )
+		);
+	}
+
+	Rule NumberLiteral() {
+		return FirstOf(
+			Sequence(
+				IgnoreCase("0x"),
+				HexNumber()
+			),
+			Sequence(
+				DecNumber(),
+				push(Double.valueOf(match()))
+			)
+		);
+	}
+
+	Rule DecNumber() {
+		return FirstOf(
+			Sequence(
+				Int(),
+				Optional( '.', Optional(Int()) ),
+				Exponent()
+			),
+			Sequence( '.', Int(), Exponent() )
+		);
+	}
+
+	Rule Exponent() {
+		return Optional(
+			IgnoreCase('e'),
+			Optional(AnyOf("+-")),
+			Int()
+		);
+	}
+
+	Rule Int() {
+		return OneOrMore(Digit());
+	}
+
+	Rule Digit() {
+		return CharRange('0', '9');
+	}
+
+	Rule HexNumber() {
+		return FirstOf(
+			Sequence(
+				HexInt(),
+				push( (double)Long.parseLong(match(),16) ),
+				Optional( '.', Optional(HexDec()) ),
+				HexExponent()
+			),
+			Sequence( push(0.0), '.', HexDec(), HexExponent() )
+		);
+	}
+
+	Rule HexDec() {
+		return Sequence(
+			HexInt(),
+			push( (Double)pop() + (double)Long.parseLong(match(),16) / Math.pow(16,matchLength()) )
+		);
+	}
+
+	Rule HexExponent() {
+		return Optional(
+			IgnoreCase('p'),
+			Sequence(
+				Optional(AnyOf("+-")),
+				HexInt()
+			),
+			push( (Double)pop() * Math.pow(2,(double)Long.parseLong(match())) )
+		);
+	}
+
+	Rule HexInt() {
+		return OneOrMore(Digit());
+	}
+
+
+	Rule HexDigit() {
+		return FirstOf(
+			Digit(),
+			AnyOf("abcdefABCDEF")
+		);
+	}
+
+	Rule StringLiteral() {
+		return FirstOf(
+			QuotedString('"'),
+			QuotedString('\''),
+			LongString()
+		);
+	}
+
+	Rule LongString() {
+		return Sequence(
+			'[',
+			ZeroOrMore('='),
+			nEquals(matchLength()),
+			'[',
+			ZeroOrMore(
+				TestNot(LongBracketsEnd()),
+				ANY
+			),
+			push( match() ),
+			LongBracketsEnd()
+		);
+	}
+
+	Rule QuotedString(char quote) {
+		StringBuilderVar buf = new StringBuilderVar();
+		return Sequence(
+			quote,
+			ZeroOrMore(
+				FirstOf(
+					Sequence(
+						NoneOf("\\\n"+quote),
+						buf.append(matchedChar())
+					),
+					EscSeq(buf)
+				)
+			),
+			quote,
+			push( buf.getString() )
+		);
+	}
+
+	Rule EscSeq(StringBuilderVar buf) {
+		return Sequence(
+			'\\',
+			FirstOf(
+				Sequence( 'a', buf.append('\u0007') ),
+				Sequence( 'b', buf.append('\b') ),
+				Sequence( 'f', buf.append('\f') ),
+				Sequence( 'n', buf.append('\n') ),
+				Sequence( 'r', buf.append('\r') ),
+				Sequence( 't', buf.append('\t') ),
+				Sequence( 'v', buf.append('\u000b') ),
+				Sequence( '\\', buf.append('\\') ),
+				Sequence( '"', buf.append('"') ),
+				Sequence( '\'', buf.append('\'') ),
+				Sequence(
+					'x',
+					Sequence( HexDigit(), HexDigit() ),
+					buf.append( (char)Integer.parseInt(match(),16) )
+				),
+				Sequence(
+					Sequence(
+						Digit(),
+						Optional(
+							Digit(),
+							Optional(
+								Digit()
+							)
+						)
+					),
+					buf.append( (char)Integer.parseInt(match()) )
+				)
+			)
+		);
+	}
+
+	Rule Spaces() {
+		return ZeroOrMore(
+			FirstOf(
+				AnyOf(" \t"),
+				Comment(),
+				Sequence( '\\', EndOfLine() ),
+				Sequence( AnyOf("\r\n"), parens > 0 )
+			)
+		);
+	}
+
+	Rule Comment() {
+		return Sequence(
+			"--[",
+			ZeroOrMore('='),
+			nEquals(matchLength()),
+			'[',
+			ZeroOrMore(
+				TestNot(LongBracketsEnd()),
+				ANY
+			),
+			LongBracketsEnd()
+		);
+	}
+
+	Rule LongBracketsEnd() {
+		return Sequence( ']', ZeroOrMore('='), nEquals==matchLength(), ']' );
+	}
+
+	static boolean action(Object obj) {
+		return true;
+	}
+
+	// for debugging
+	boolean print(Object o) {
+		System.out.println(o);
+		return true;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/interp/LuanStateImpl.java	Fri Dec 28 03:29:12 2012 +0000
@@ -0,0 +1,102 @@
+package luan.interp;
+
+import java.util.List;
+import java.util.ArrayList;
+import luan.Luan;
+import luan.LuanState;
+import luan.LuanTable;
+import luan.LuanFunction;
+import luan.MetatableGetter;
+import luan.LuanException;
+import luan.LuanElement;
+
+
+final class LuanStateImpl extends LuanState {
+
+	final Object arithmetic(LuanElement el,String op,Object o1,Object o2) throws LuanException {
+		LuanFunction fn = getBinHandler(el,op,o1,o2);
+		if( fn != null )
+			return Luan.first(call(fn,el,op,o1,o2));
+		String type = Luan.toNumber(o1)==null ? Luan.type(o1) : Luan.type(o2);
+		throw new LuanException(this,el,"attempt to perform arithmetic on a "+type+" value");
+	}
+
+
+	private static class Frame {
+		final Frame previousFrame;
+		final Closure closure;
+		final Object[] stack;
+		final Object[] varArgs;
+		UpValue[] downValues = null;
+
+		Frame( Frame previousFrame, Closure closure, int stackSize, Object[] varArgs) {
+			this.previousFrame = previousFrame;
+			this.closure = closure;
+			this.stack = new Object[stackSize];
+			this.varArgs = varArgs;
+		}
+
+		void stackClear(int start,int end) {
+			if( downValues != null ) {
+				for( int i=start; i<end; i++ ) {
+					UpValue downValue = downValues[i];
+					if( downValue != null ) {
+						downValue.close();
+						downValues[i] = null;
+					}
+				}
+			}
+			for( int i=start; i<end; i++ ) {
+				stack[i] = null;
+			}
+		}
+
+		UpValue getUpValue(int index) {
+			if( downValues==null )
+				downValues = new UpValue[stack.length];
+			if( downValues[index] == null )
+				downValues[index] = new UpValue(stack,index);
+			return downValues[index];
+		}
+	}
+
+	private Frame frame = null;
+	Object[] returnValues;
+	Closure tailFn;
+
+	// returns stack
+	Object[] newFrame(Closure closure, int stackSize, Object[] varArgs) {
+		frame = new Frame(frame,closure,stackSize,varArgs);
+		return frame.stack;
+	}
+
+	void popFrame() {
+		returnValues = LuanFunction.EMPTY_RTN;
+		tailFn = null;
+		frame = frame.previousFrame;
+	}
+
+	Object stackGet(int index) {
+		return frame.stack[index];
+	}
+
+	void stackSet(int index,Object value) {
+		frame.stack[index] = value;
+	}
+
+	void stackClear(int start,int end) {
+		frame.stackClear(start,end);
+	}
+
+	Object[] varArgs() {
+		return frame.varArgs;
+	}
+
+	Closure closure() {
+		return frame.closure;
+	}
+
+	UpValue getUpValue(int index) {
+		return frame.getUpValue(index);
+	}
+}
--- a/src/luan/interp/ModExpr.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/ModExpr.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,21 +1,21 @@
 package luan.interp;
 
-import luan.Lua;
-import luan.LuaException;
-import luan.LuaSource;
+import luan.Luan;
+import luan.LuanException;
+import luan.LuanSource;
 
 
 final class ModExpr extends BinaryOpExpr {
 
-	ModExpr(LuaSource.Element se,Expr op1,Expr op2) {
+	ModExpr(LuanSource.Element se,Expr op1,Expr op2) {
 		super(se,op1,op2);
 	}
 
-	@Override public Object eval(LuaStateImpl lua) throws LuaException {
+	@Override public Object eval(LuanStateImpl lua) throws LuanException {
 		Object o1 = op1.eval(lua);
 		Object o2 = op2.eval(lua);
-		Number n1 = Lua.toNumber(o1);
-		Number n2 = Lua.toNumber(o2);
+		Number n1 = Luan.toNumber(o1);
+		Number n2 = Luan.toNumber(o2);
 		if( n1 != null && n2 != null )
 			return n1.doubleValue() % n2.doubleValue();
 		return arithmetic(lua,"__mod",o1,o2);
--- a/src/luan/interp/MulExpr.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/MulExpr.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,21 +1,21 @@
 package luan.interp;
 
-import luan.Lua;
-import luan.LuaException;
-import luan.LuaSource;
+import luan.Luan;
+import luan.LuanException;
+import luan.LuanSource;
 
 
 final class MulExpr extends BinaryOpExpr {
 
-	MulExpr(LuaSource.Element se,Expr op1,Expr op2) {
+	MulExpr(LuanSource.Element se,Expr op1,Expr op2) {
 		super(se,op1,op2);
 	}
 
-	@Override public Object eval(LuaStateImpl lua) throws LuaException {
+	@Override public Object eval(LuanStateImpl lua) throws LuanException {
 		Object o1 = op1.eval(lua);
 		Object o2 = op2.eval(lua);
-		Number n1 = Lua.toNumber(o1);
-		Number n2 = Lua.toNumber(o2);
+		Number n1 = Luan.toNumber(o1);
+		Number n2 = Luan.toNumber(o2);
 		if( n1 != null && n2 != null )
 			return n1.doubleValue() * n2.doubleValue();
 		return arithmetic(lua,"__mul",o1,o2);
--- a/src/luan/interp/NotExpr.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/NotExpr.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,17 +1,17 @@
 package luan.interp;
 
-import luan.Lua;
-import luan.LuaException;
-import luan.LuaSource;
+import luan.Luan;
+import luan.LuanException;
+import luan.LuanSource;
 
 
 final class NotExpr extends UnaryOpExpr {
 
-	NotExpr(LuaSource.Element se,Expr op) {
+	NotExpr(LuanSource.Element se,Expr op) {
 		super(se,op);
 	}
 
-	@Override public Object eval(LuaStateImpl lua) throws LuaException {
-		return !Lua.toBoolean(op.eval(lua));
+	@Override public Object eval(LuanStateImpl lua) throws LuanException {
+		return !Luan.toBoolean(op.eval(lua));
 	}
 }
--- a/src/luan/interp/NumericForStmt.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/NumericForStmt.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,8 +1,8 @@
 package luan.interp;
 
-import luan.Lua;
-import luan.LuaException;
-import luan.LuaSource;
+import luan.Luan;
+import luan.LuanException;
+import luan.LuanSource;
 
 
 final class NumericForStmt extends CodeImpl implements Stmt {
@@ -12,7 +12,7 @@
 	private final Expr stepExpr;
 	private final Stmt block;
 
-	NumericForStmt(LuaSource.Element se,int iVar,Expr fromExpr,Expr toExpr,Expr stepExpr,Stmt block) {
+	NumericForStmt(LuanSource.Element se,int iVar,Expr fromExpr,Expr toExpr,Expr stepExpr,Stmt block) {
 		super(se);
 		this.iVar = iVar;
 		this.fromExpr = fromExpr;
@@ -21,7 +21,7 @@
 		this.block = block;
 	}
 
-	@Override public void eval(LuaStateImpl lua) throws LuaException {
+	@Override public void eval(LuanStateImpl lua) throws LuanException {
 		double v = lua.checkNumber( se, fromExpr.eval(lua) ).doubleValue();
 		double limit = lua.checkNumber( se, toExpr.eval(lua) ).doubleValue();
 		double step = lua.checkNumber( se, stepExpr.eval(lua) ).doubleValue();
--- a/src/luan/interp/OrExpr.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/OrExpr.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,18 +1,18 @@
 package luan.interp;
 
-import luan.Lua;
-import luan.LuaException;
-import luan.LuaSource;
+import luan.Luan;
+import luan.LuanException;
+import luan.LuanSource;
 
 
 final class OrExpr extends BinaryOpExpr {
 
-	OrExpr(LuaSource.Element se,Expr op1,Expr op2) {
+	OrExpr(LuanSource.Element se,Expr op1,Expr op2) {
 		super(se,op1,op2);
 	}
 
-	@Override public Object eval(LuaStateImpl lua) throws LuaException {
+	@Override public Object eval(LuanStateImpl lua) throws LuanException {
 		Object v1 = op1.eval(lua);
-		return Lua.toBoolean(v1) ? v1 : op2.eval(lua);
+		return Luan.toBoolean(v1) ? v1 : op2.eval(lua);
 	}
 }
--- a/src/luan/interp/PowExpr.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/PowExpr.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,21 +1,21 @@
 package luan.interp;
 
-import luan.Lua;
-import luan.LuaException;
-import luan.LuaSource;
+import luan.Luan;
+import luan.LuanException;
+import luan.LuanSource;
 
 
 final class PowExpr extends BinaryOpExpr {
 
-	PowExpr(LuaSource.Element se,Expr op1,Expr op2) {
+	PowExpr(LuanSource.Element se,Expr op1,Expr op2) {
 		super(se,op1,op2);
 	}
 
-	@Override public Object eval(LuaStateImpl lua) throws LuaException {
+	@Override public Object eval(LuanStateImpl lua) throws LuanException {
 		Object o1 = op1.eval(lua);
 		Object o2 = op2.eval(lua);
-		Number n1 = Lua.toNumber(o1);
-		Number n2 = Lua.toNumber(o2);
+		Number n1 = Luan.toNumber(o1);
+		Number n2 = Luan.toNumber(o2);
 		if( n1 != null && n2 != null )
 			return Math.pow( n1.doubleValue(), n2.doubleValue() );
 		return arithmetic(lua,"__pow",o1,o2);
--- a/src/luan/interp/RepeatStmt.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/RepeatStmt.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,7 +1,7 @@
 package luan.interp;
 
-import luan.Lua;
-import luan.LuaException;
+import luan.Luan;
+import luan.LuanException;
 
 
 final class RepeatStmt implements Stmt {
@@ -13,11 +13,11 @@
 		this.cnd = cnd;
 	}
 
-	@Override public void eval(LuaStateImpl lua) throws LuaException {
+	@Override public void eval(LuanStateImpl lua) throws LuanException {
 		try {
 			do {
 				doStmt.eval(lua);
-			} while( !Lua.toBoolean( cnd.eval(lua) ) );
+			} while( !Luan.toBoolean( cnd.eval(lua) ) );
 		} catch(BreakException e) {}
 	}
 }
--- a/src/luan/interp/ReturnStmt.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/ReturnStmt.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,9 +1,9 @@
 package luan.interp;
 
-import luan.Lua;
-import luan.LuaException;
-import luan.LuaFunction;
-import luan.LuaSource;
+import luan.Luan;
+import luan.LuanException;
+import luan.LuanFunction;
+import luan.LuanSource;
 
 
 final class ReturnStmt extends CodeImpl implements Stmt {
@@ -11,7 +11,7 @@
 	private final Expr tailFnExpr;
 	boolean throwReturnException = true;
 
-	ReturnStmt(LuaSource.Element se,Expressions expressions) {
+	ReturnStmt(LuanSource.Element se,Expressions expressions) {
 		super(se);
 		if( expressions instanceof FnCall ) {  // tail call
 			FnCall fnCall = (FnCall)expressions;
@@ -23,12 +23,12 @@
 		}
 	}
 
-	@Override public void eval(LuaStateImpl lua) throws LuaException {
+	@Override public void eval(LuanStateImpl lua) throws LuanException {
 		lua.returnValues = expressions.eval(lua);
 		if( tailFnExpr != null ) {
-			LuaFunction tailFn = lua.checkFunction( se, tailFnExpr.eval(lua) );
-			if( tailFn instanceof LuaClosure ) {
-				lua.tailFn = (LuaClosure)tailFn;
+			LuanFunction tailFn = lua.checkFunction( se, tailFnExpr.eval(lua) );
+			if( tailFn instanceof Closure ) {
+				lua.tailFn = (Closure)tailFn;
 			} else {
 				lua.returnValues =  lua.call(tailFn,tailFnExpr.se(),tailFnExpr.se().text(),lua.returnValues);
 			}
--- a/src/luan/interp/SetLocalVar.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/SetLocalVar.java	Fri Dec 28 03:29:12 2012 +0000
@@ -8,7 +8,7 @@
 		this.index = index;
 	}
 
-	@Override public void set(LuaStateImpl lua,Object value) {
+	@Override public void set(LuanStateImpl lua,Object value) {
 		lua.stackSet( index, value );
 	}
 }
--- a/src/luan/interp/SetStmt.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/SetStmt.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,7 +1,7 @@
 package luan.interp;
 
-import luan.Lua;
-import luan.LuaException;
+import luan.Luan;
+import luan.LuanException;
 
 
 final class SetStmt implements Stmt {
@@ -17,7 +17,7 @@
 		this.expressions = expressions;
 	}
 
-	@Override public void eval(LuaStateImpl lua) throws LuaException {
+	@Override public void eval(LuanStateImpl lua) throws LuanException {
 		final Object[] vals = expressions.eval(lua);
 		for( int i=0; i<vars.length; i++ ) {
 			Object val = i < vals.length ? vals[i] : null;
--- a/src/luan/interp/SetTableEntry.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/SetTableEntry.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,30 +1,30 @@
 package luan.interp;
 
-import luan.LuaException;
-import luan.LuaTable;
-import luan.Lua;
-import luan.LuaFunction;
-import luan.LuaSource;
+import luan.LuanException;
+import luan.LuanTable;
+import luan.Luan;
+import luan.LuanFunction;
+import luan.LuanSource;
 
 
 final class SetTableEntry extends CodeImpl implements Settable {
 	private final Expr tableExpr;
 	private final Expr keyExpr;
 
-	SetTableEntry(LuaSource.Element se,Expr tableExpr,Expr keyExpr) {
+	SetTableEntry(LuanSource.Element se,Expr tableExpr,Expr keyExpr) {
 		super(se);
 		this.tableExpr = tableExpr;
 		this.keyExpr = keyExpr;
 	}
 
-	@Override public void set(LuaStateImpl lua,Object value) throws LuaException {
+	@Override public void set(LuanStateImpl lua,Object value) throws LuanException {
 		newindex( lua, tableExpr.eval(lua), keyExpr.eval(lua), value );
 	}
 
-	private void newindex(LuaStateImpl lua,Object t,Object key,Object value) throws LuaException {
+	private void newindex(LuanStateImpl lua,Object t,Object key,Object value) throws LuanException {
 		Object h;
-		if( t instanceof LuaTable ) {
-			LuaTable table = (LuaTable)t;
+		if( t instanceof LuanTable ) {
+			LuanTable table = (LuanTable)t;
 			Object old = table.put(key,value);
 			if( old != null )
 				return;
@@ -35,10 +35,10 @@
 		} else {
 			h = lua.getHandler("__newindex",t);
 			if( h==null )
-				throw new LuaException( lua, se, "attempt to index a " + Lua.type(t) + " value" );
+				throw new LuanException( lua, se, "attempt to index a " + Luan.type(t) + " value" );
 		}
-		if( h instanceof LuaFunction ) {
-			LuaFunction fn = (LuaFunction)h;
+		if( h instanceof LuanFunction ) {
+			LuanFunction fn = (LuanFunction)h;
 			lua.call(fn,se,"__newindex",t,key,value);
 		}
 		newindex(lua,h,key,value);
--- a/src/luan/interp/SetUpVar.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/SetUpVar.java	Fri Dec 28 03:29:12 2012 +0000
@@ -8,7 +8,7 @@
 		this.index = index;
 	}
 
-	@Override public void set(LuaStateImpl lua,Object value) {
+	@Override public void set(LuanStateImpl lua,Object value) {
 		lua.closure().upValues[index].set(value);
 	}
 }
--- a/src/luan/interp/Settable.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/Settable.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,8 +1,8 @@
 package luan.interp;
 
-import luan.LuaException;
+import luan.LuanException;
 
 
 interface Settable {
-	public void set(LuaStateImpl lua,Object value) throws LuaException;
+	public void set(LuanStateImpl lua,Object value) throws LuanException;
 }
--- a/src/luan/interp/Stmt.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/Stmt.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,12 +1,12 @@
 package luan.interp;
 
-import luan.LuaException;
+import luan.LuanException;
 
 
 interface Stmt {
-	public void eval(LuaStateImpl lua) throws LuaException;
+	public void eval(LuanStateImpl lua) throws LuanException;
 
 	static final Stmt EMPTY = new Stmt() {
-		@Override public void eval(LuaStateImpl lua) {}
+		@Override public void eval(LuanStateImpl lua) {}
 	};
 }
--- a/src/luan/interp/SubExpr.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/SubExpr.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,21 +1,21 @@
 package luan.interp;
 
-import luan.Lua;
-import luan.LuaException;
-import luan.LuaSource;
+import luan.Luan;
+import luan.LuanException;
+import luan.LuanSource;
 
 
 final class SubExpr extends BinaryOpExpr {
 
-	SubExpr(LuaSource.Element se,Expr op1,Expr op2) {
+	SubExpr(LuanSource.Element se,Expr op1,Expr op2) {
 		super(se,op1,op2);
 	}
 
-	@Override public Object eval(LuaStateImpl lua) throws LuaException {
+	@Override public Object eval(LuanStateImpl lua) throws LuanException {
 		Object o1 = op1.eval(lua);
 		Object o2 = op2.eval(lua);
-		Number n1 = Lua.toNumber(o1);
-		Number n2 = Lua.toNumber(o2);
+		Number n1 = Luan.toNumber(o1);
+		Number n2 = Luan.toNumber(o2);
 		if( n1 != null && n2 != null )
 			return n1.doubleValue() - n2.doubleValue();
 		return arithmetic(lua,"__sub",o1,o2);
--- a/src/luan/interp/TableExpr.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/TableExpr.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,8 +1,8 @@
 package luan.interp;
 
-import luan.LuaException;
-import luan.LuaTable;
-import luan.LuaSource;
+import luan.LuanException;
+import luan.LuanTable;
+import luan.LuanSource;
 
 
 final class TableExpr extends CodeImpl implements Expr {
@@ -20,14 +20,14 @@
 	private final Field[] fields;
 	private final Expressions expressions;
 
-	TableExpr(LuaSource.Element se,Field[] fields,Expressions expressions) {
+	TableExpr(LuanSource.Element se,Field[] fields,Expressions expressions) {
 		super(se);
 		this.fields = fields;
 		this.expressions = expressions;
 	}
 
-	@Override public Object eval(LuaStateImpl lua) throws LuaException {
-		LuaTable table = new LuaTable();
+	@Override public Object eval(LuanStateImpl lua) throws LuanException {
+		LuanTable table = new LuanTable();
 		for( Field field : fields ) {
 			table.put( field.key.eval(lua), field.value.eval(lua) );
 		}
--- a/src/luan/interp/UnaryOpExpr.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/UnaryOpExpr.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,12 +1,12 @@
 package luan.interp;
 
-import luan.LuaSource;
+import luan.LuanSource;
 
 
 abstract class UnaryOpExpr extends CodeImpl implements Expr {
 	final Expr op;
 
-	UnaryOpExpr(LuaSource.Element se,Expr op) {
+	UnaryOpExpr(LuanSource.Element se,Expr op) {
 		super(se);
 		this.op = op;
 	}
--- a/src/luan/interp/UnmExpr.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/UnmExpr.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,27 +1,27 @@
 package luan.interp;
 
-import luan.Lua;
-import luan.LuaFunction;
-import luan.LuaException;
-import luan.LuaSource;
+import luan.Luan;
+import luan.LuanFunction;
+import luan.LuanException;
+import luan.LuanSource;
 
 
 // unary minus
 final class UnmExpr extends UnaryOpExpr {
 
-	UnmExpr(LuaSource.Element se,Expr op) {
+	UnmExpr(LuanSource.Element se,Expr op) {
 		super(se,op);
 	}
 
-	@Override public Object eval(LuaStateImpl lua) throws LuaException {
+	@Override public Object eval(LuanStateImpl lua) throws LuanException {
 		Object o = op.eval(lua);
-		Number n = Lua.toNumber(o);
+		Number n = Luan.toNumber(o);
 		if( n != null )
 			return -n.doubleValue();
-		LuaFunction fn = lua.getHandlerFunction(se,"__unm",o);
+		LuanFunction fn = lua.getHandlerFunction(se,"__unm",o);
 		if( fn != null ) {
-			return Lua.first(lua.call(fn,se,"__unm",o));
+			return Luan.first(lua.call(fn,se,"__unm",o));
 		}
-		throw new LuaException(lua,se,"attempt to perform arithmetic on a "+Lua.type(o)+" value");
+		throw new LuanException(lua,se,"attempt to perform arithmetic on a "+Luan.type(o)+" value");
 	}
 }
--- a/src/luan/interp/UpValue.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/UpValue.java	Fri Dec 28 03:29:12 2012 +0000
@@ -36,7 +36,7 @@
 	}
 
 	static interface Getter {
-		public UpValue get(LuaStateImpl lua);
+		public UpValue get(LuanStateImpl lua);
 	}
 
 	static final class StackGetter implements Getter {
@@ -46,7 +46,7 @@
 			this.index = index;
 		}
 
-		public UpValue get(LuaStateImpl lua) {
+		public UpValue get(LuanStateImpl lua) {
 			return lua.getUpValue(index);
 		}
 	}
@@ -58,13 +58,13 @@
 			this.index = index;
 		}
 
-		public UpValue get(LuaStateImpl lua) {
+		public UpValue get(LuanStateImpl lua) {
 			return lua.closure().upValues[index];
 		}
 	}
 
 	static final Getter globalGetter = new Getter() {
-		public UpValue get(LuaStateImpl lua) {
+		public UpValue get(LuanStateImpl lua) {
 			return new UpValue(lua.global());
 		}
 	};
--- a/src/luan/interp/VarArgs.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/VarArgs.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,15 +1,15 @@
 package luan.interp;
 
-import luan.LuaSource;
+import luan.LuanSource;
 
 
 final class VarArgs extends CodeImpl implements Expressions {
 
-	VarArgs(LuaSource.Element se) {
+	VarArgs(LuanSource.Element se) {
 		super(se);
 	}
 
-	@Override public Object[] eval(LuaStateImpl lua) {
+	@Override public Object[] eval(LuanStateImpl lua) {
 		return lua.varArgs();
 	}
 }
--- a/src/luan/interp/WhileStmt.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/interp/WhileStmt.java	Fri Dec 28 03:29:12 2012 +0000
@@ -1,7 +1,7 @@
 package luan.interp;
 
-import luan.Lua;
-import luan.LuaException;
+import luan.Luan;
+import luan.LuanException;
 
 
 final class WhileStmt implements Stmt {
@@ -13,9 +13,9 @@
 		this.doStmt = doStmt;
 	}
 
-	@Override public void eval(LuaStateImpl lua) throws LuaException {
+	@Override public void eval(LuanStateImpl lua) throws LuanException {
 		try {
-			while( Lua.toBoolean( cnd.eval(lua) ) ) {
+			while( Luan.toBoolean( cnd.eval(lua) ) ) {
 				doStmt.eval(lua);
 			}
 		} catch(BreakException e) {}
--- a/src/luan/lib/BasicLib.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/lib/BasicLib.java	Fri Dec 28 03:29:12 2012 +0000
@@ -8,53 +8,53 @@
 import java.lang.reflect.Method;
 import java.util.Iterator;
 import java.util.Map;
-import luan.Lua;
-import luan.LuaState;
-import luan.LuaTable;
-import luan.LuaFunction;
-import luan.LuaJavaFunction;
-import luan.LuaException;
-import luan.LuaSource;
-import luan.LuaElement;
-import luan.interp.LuaCompiler;
+import luan.Luan;
+import luan.LuanState;
+import luan.LuanTable;
+import luan.LuanFunction;
+import luan.LuanJavaFunction;
+import luan.LuanException;
+import luan.LuanSource;
+import luan.LuanElement;
+import luan.interp.LuanCompiler;
 
 
 public final class BasicLib {
 
-	public static void register(LuaState lua) {
-		LuaTable global = lua.global();
+	public static void register(LuanState lua) {
+		LuanTable global = lua.global();
 		global.put( "_G", global );
-		add( global, "do_file", LuaState.class, String.class );
-		add( global, "error", LuaState.class, Object.class );
-		add( global, "get_metatable", LuaState.class, Object.class );
-		add( global, "ipairs", LuaTable.class );
-		add( global, "load", LuaState.class, String.class, String.class );
-		add( global, "load_file", LuaState.class, String.class );
-		add( global, "pairs", LuaTable.class );
-		add( global, "print", LuaState.class, new Object[0].getClass() );
+		add( global, "do_file", LuanState.class, String.class );
+		add( global, "error", LuanState.class, Object.class );
+		add( global, "get_metatable", LuanState.class, Object.class );
+		add( global, "ipairs", LuanTable.class );
+		add( global, "load", LuanState.class, String.class, String.class );
+		add( global, "load_file", LuanState.class, String.class );
+		add( global, "pairs", LuanTable.class );
+		add( global, "print", LuanState.class, new Object[0].getClass() );
 		add( global, "raw_equal", Object.class, Object.class );
-		add( global, "raw_get", LuaTable.class, Object.class );
-		add( global, "raw_len", LuaState.class, Object.class );
-		add( global, "raw_set", LuaTable.class, Object.class, Object.class );
-		add( global, "set_metatable", LuaTable.class, LuaTable.class );
+		add( global, "raw_get", LuanTable.class, Object.class );
+		add( global, "raw_len", LuanState.class, Object.class );
+		add( global, "raw_set", LuanTable.class, Object.class, Object.class );
+		add( global, "set_metatable", LuanTable.class, LuanTable.class );
 		add( global, "to_number", Object.class, Integer.class );
-		add( global, "to_string", LuaState.class, Object.class );
+		add( global, "to_string", LuanState.class, Object.class );
 		add( global, "type", Object.class );
-		global.put( "_VERSION", Lua.version );
+		global.put( "_VERSION", Luan.version );
 
-		add( global, "make_standard", LuaState.class );
+		add( global, "make_standard", LuanState.class );
 	}
 
-	private static void add(LuaTable t,String method,Class<?>... parameterTypes) {
+	private static void add(LuanTable t,String method,Class<?>... parameterTypes) {
 		try {
-			t.put( method, new LuaJavaFunction(BasicLib.class.getMethod(method,parameterTypes),null) );
+			t.put( method, new LuanJavaFunction(BasicLib.class.getMethod(method,parameterTypes),null) );
 		} catch(NoSuchMethodException e) {
 			throw new RuntimeException(e);
 		}
 	}
 
-	public static void make_standard(LuaState lua) {
-		LuaTable global = lua.global();
+	public static void make_standard(LuanState lua) {
+		LuanTable global = lua.global();
 		global.put( "dofile", global.get("do_file") );
 		global.put( "getmetatable", global.get("get_metatable") );
 		global.put( "loadfile", global.get("load_file") );
@@ -67,21 +67,21 @@
 		global.put( "tostring", global.get("to_string") );
 	}
 
-	public static void print(LuaState lua,Object... args) throws LuaException {
+	public static void print(LuanState lua,Object... args) throws LuanException {
 		for( int i=0; i<args.length; i++ ) {
 			if( i > 0 )
 				System.out.print('\t');
-			System.out.print( lua.toString(LuaElement.JAVA,args[i]) );
+			System.out.print( lua.toString(LuanElement.JAVA,args[i]) );
 		}
 		System.out.println();
 	}
 
 	public static String type(Object obj) {
-		return Lua.type(obj);
+		return Luan.type(obj);
 	}
 
-	public static LuaFunction load(LuaState lua,String text,String sourceName) throws LuaException {
-		return LuaCompiler.compile(lua,new LuaSource(sourceName,text));
+	public static LuanFunction load(LuanState lua,String text,String sourceName) throws LuanException {
+		return LuanCompiler.compile(lua,new LuanSource(sourceName,text));
 	}
 
 	public static String readAll(Reader in)
@@ -106,44 +106,44 @@
 	}
 
 
-	public static LuaFunction load_file(LuaState lua,String fileName) throws LuaException {
+	public static LuanFunction load_file(LuanState lua,String fileName) throws LuanException {
 		try {
 			String src = fileName==null ? readAll(new InputStreamReader(System.in)) : read(new File(fileName));
 			return load(lua,src,fileName);
 		} catch(IOException e) {
-			throw new LuaException(lua,LuaElement.JAVA,e);
+			throw new LuanException(lua,LuanElement.JAVA,e);
 		}
 	}
 
-	public static Object[] do_file(LuaState lua,String fileName) throws LuaException {
-		LuaFunction fn = load_file(lua,fileName);
-		return lua.call(fn,LuaElement.JAVA,null);
+	public static Object[] do_file(LuanState lua,String fileName) throws LuanException {
+		LuanFunction fn = load_file(lua,fileName);
+		return lua.call(fn,LuanElement.JAVA,null);
 	}
 
-	private static LuaFunction pairs(final Iterator<Map.Entry<Object,Object>> iter) {
-		return new LuaFunction() {
-			public Object[] call(LuaState lua,Object[] args) {
+	private static LuanFunction pairs(final Iterator<Map.Entry<Object,Object>> iter) {
+		return new LuanFunction() {
+			public Object[] call(LuanState lua,Object[] args) {
 				if( !iter.hasNext() )
-					return LuaFunction.EMPTY_RTN;
+					return LuanFunction.EMPTY_RTN;
 				Map.Entry<Object,Object> entry = iter.next();
 				return new Object[]{entry.getKey(),entry.getValue()};
 			}
 		};
 	}
 
-	public static LuaFunction pairs(LuaTable t) {
+	public static LuanFunction pairs(LuanTable t) {
 		return pairs( t.iterator() );
 	}
 
-	public static LuaFunction ipairs(LuaTable t) {
+	public static LuanFunction ipairs(LuanTable t) {
 		return pairs( t.listIterator() );
 	}
 
-	public static LuaTable get_metatable(LuaState lua,Object obj) {
+	public static LuanTable get_metatable(LuanState lua,Object obj) {
 		return lua.getMetatable(obj);
 	}
 
-	public static LuaTable set_metatable(LuaTable table,LuaTable metatable) {
+	public static LuanTable set_metatable(LuanTable table,LuanTable metatable) {
 		table.setMetatable(metatable);
 		return table;
 	}
@@ -152,37 +152,37 @@
 		return v1 == v2 || v1 != null && v1.equals(v2);
 	}
 
-	public static Object raw_get(LuaTable table,Object index) {
+	public static Object raw_get(LuanTable table,Object index) {
 		return table.get(index);
 	}
 
-	public static LuaTable raw_set(LuaTable table,Object index,Object value) {
+	public static LuanTable raw_set(LuanTable table,Object index,Object value) {
 		table.put(index,value);
 		return table;
 	}
 
-	public static int raw_len(LuaState lua,Object v) throws LuaException {
+	public static int raw_len(LuanState lua,Object v) throws LuanException {
 		if( v instanceof String ) {
 			String s = (String)v;
 			return s.length();
 		}
-		if( v instanceof LuaTable ) {
-			LuaTable t = (LuaTable)v;
+		if( v instanceof LuanTable ) {
+			LuanTable t = (LuanTable)v;
 			return t.length();
 		}
-		throw new LuaException( lua, LuaElement.JAVA, "bad argument #1 to 'raw_len' (table or string expected)" );
+		throw new LuanException( lua, LuanElement.JAVA, "bad argument #1 to 'raw_len' (table or string expected)" );
 	}
 
 	public static Number to_number(Object e,Integer base) {
-		return Lua.toNumber(e,base);
+		return Luan.toNumber(e,base);
 	}
 
-	public static String to_string(LuaState lua,Object v) throws LuaException {
-		return lua.toString(LuaElement.JAVA,v);
+	public static String to_string(LuanState lua,Object v) throws LuanException {
+		return lua.toString(LuanElement.JAVA,v);
 	}
 
-	public static void error(LuaState lua,Object msg) throws LuaException {
-		throw new LuaException(lua,LuaElement.JAVA,msg);
+	public static void error(LuanState lua,Object msg) throws LuanException {
+		throw new LuanException(lua,LuanElement.JAVA,msg);
 	}
 
 }
--- a/src/luan/lib/JavaLib.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/lib/JavaLib.java	Fri Dec 28 03:29:12 2012 +0000
@@ -11,53 +11,53 @@
 import java.util.List;
 import java.util.ArrayList;
 import java.util.Iterator;
-import luan.Lua;
-import luan.LuaState;
-import luan.LuaTable;
+import luan.Luan;
+import luan.LuanState;
+import luan.LuanTable;
 import luan.MetatableGetter;
-import luan.LuaException;
-import luan.LuaFunction;
-import luan.LuaJavaFunction;
-import luan.LuaElement;
+import luan.LuanException;
+import luan.LuanFunction;
+import luan.LuanJavaFunction;
+import luan.LuanElement;
 
 
 public final class JavaLib {
 
-	public static void register(LuaState lua) {
+	public static void register(LuanState lua) {
 		lua.addMetatableGetter(mg);
-		LuaTable module = new LuaTable();
-		LuaTable global = lua.global();
+		LuanTable module = new LuanTable();
+		LuanTable 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",LuaState.class,String.class),null) );
+			global.put( "import", new LuanJavaFunction(JavaLib.class.getMethod("importClass",LuanState.class,String.class),null) );
+			module.put( "class", new LuanJavaFunction(JavaLib.class.getMethod("getClass",LuanState.class,String.class),null) );
 		} catch(NoSuchMethodException e) {
 			throw new RuntimeException(e);
 		}
 	}
 
-	private static final LuaTable mt = new LuaTable();
+	private static final LuanTable mt = new LuanTable();
 	static {
-		add( mt, "__index", LuaState.class, Object.class, Object.class );
+		add( mt, "__index", LuanState.class, Object.class, Object.class );
 	}
 
-	private static void add(LuaTable t,String method,Class<?>... parameterTypes) {
+	private static void add(LuanTable t,String method,Class<?>... parameterTypes) {
 		try {
-			t.put( method, new LuaJavaFunction(JavaLib.class.getMethod(method,parameterTypes),null) );
+			t.put( method, new LuanJavaFunction(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) {
+		public LuanTable getMetatable(Object obj) {
 			if( obj==null )
 				return null;
 			return mt;
 		}
 	};
 
-	public static Object __index(LuaState lua,Object obj,Object key) throws LuaException {
+	public static Object __index(LuanState lua,Object obj,Object key) throws LuanException {
 		if( obj instanceof Static ) {
 			if( key instanceof String ) {
 				String name = (String)key;
@@ -69,11 +69,11 @@
 					Constructor<?>[] constructors = cls.getConstructors();
 					if( constructors.length > 0 ) {
 						if( constructors.length==1 ) {
-							return new LuaJavaFunction(constructors[0],null);
+							return new LuanJavaFunction(constructors[0],null);
 						} else {
-							List<LuaJavaFunction> fns = new ArrayList<LuaJavaFunction>();
+							List<LuanJavaFunction> fns = new ArrayList<LuanJavaFunction>();
 							for( Constructor constructor : constructors ) {
-								fns.add(new LuaJavaFunction(constructor,null));
+								fns.add(new LuanJavaFunction(constructor,null));
 							}
 							return new AmbiguousJavaFunction(fns);
 						}
@@ -85,23 +85,23 @@
 					}
 				}
 			}
-			throw new LuaException(lua,LuaElement.JAVA,"invalid index for java class: "+key);
+			throw new LuanException(lua,LuanElement.JAVA,"invalid index for java class: "+key);
 		}
 		Class cls = obj.getClass();
 		if( cls.isArray() ) {
 			if( "length".equals(key) ) {
 				return Array.getLength(obj);
 			}
-			Integer i = Lua.asInteger(key);
+			Integer i = Luan.asInteger(key);
 			if( i != null ) {
 				return Array.get(obj,i);
 			}
-			throw new LuaException(lua,LuaElement.JAVA,"invalid index for java array: "+key);
+			throw new LuanException(lua,LuanElement.JAVA,"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));
+				return new LuanJavaFunction(instanceOf,new InstanceOf(obj));
 			} else {
 				List<Member> members = getMembers(cls,name);
 				if( !members.isEmpty() ) {
@@ -109,10 +109,10 @@
 				}
 			}
 		}
-		throw new LuaException(lua,LuaElement.JAVA,"invalid index for java object: "+key);
+		throw new LuanException(lua,LuanElement.JAVA,"invalid index for java object: "+key);
 	}
 
-	private static Object member(Object obj,List<Member> members) throws LuaException {
+	private static Object member(Object obj,List<Member> members) throws LuanException {
 		try {
 			if( members.size()==1 ) {
 				Member member = members.get(0);
@@ -121,13 +121,13 @@
 					return field.get(obj);
 				} else {
 					Method method = (Method)member;
-					return new LuaJavaFunction(method,obj);
+					return new LuanJavaFunction(method,obj);
 				}
 			} else {
-				List<LuaJavaFunction> fns = new ArrayList<LuaJavaFunction>();
+				List<LuanJavaFunction> fns = new ArrayList<LuanJavaFunction>();
 				for( Member member : members ) {
 					Method method = (Method)member;
-					fns.add(new LuaJavaFunction(method,obj));
+					fns.add(new LuanJavaFunction(method,obj));
 				}
 				return new AmbiguousJavaFunction(fns);
 			}
@@ -182,40 +182,40 @@
 		}
 	}
 
-	public static Static getClass(LuaState lua,String name) throws LuaException {
+	public static Static getClass(LuanState lua,String name) throws LuanException {
 		try {
 			return new Static( Class.forName(name) );
 		} catch(ClassNotFoundException e) {
-			throw new LuaException(lua,LuaElement.JAVA,e);
+			throw new LuanException(lua,LuanElement.JAVA,e);
 		}
 	}
 
-	public static void importClass(LuaState lua,String name) throws LuaException {
+	public static void importClass(LuanState lua,String name) throws LuanException {
 		lua.global().put( name.substring(name.lastIndexOf('.')+1), getClass(lua,name) );
 	}
 
-	static class AmbiguousJavaFunction extends LuaFunction {
-		private final Map<Integer,List<LuaJavaFunction>> fnMap = new HashMap<Integer,List<LuaJavaFunction>>();
+	static class AmbiguousJavaFunction extends LuanFunction {
+		private final Map<Integer,List<LuanJavaFunction>> fnMap = new HashMap<Integer,List<LuanJavaFunction>>();
 
-		AmbiguousJavaFunction(List<LuaJavaFunction> fns) {
-			for( LuaJavaFunction fn : fns ) {
+		AmbiguousJavaFunction(List<LuanJavaFunction> fns) {
+			for( LuanJavaFunction fn : fns ) {
 				Integer n = fn.getParameterTypes().length;
-				List<LuaJavaFunction> list = fnMap.get(n);
+				List<LuanJavaFunction> list = fnMap.get(n);
 				if( list==null ) {
-					list = new ArrayList<LuaJavaFunction>();
+					list = new ArrayList<LuanJavaFunction>();
 					fnMap.put(n,list);
 				}
 				list.add(fn);
 			}
 		}
 
-		@Override public Object[] call(LuaState lua,Object[] args) throws LuaException {
-			for( LuaJavaFunction fn : fnMap.get(args.length) ) {
+		@Override public Object[] call(LuanState lua,Object[] args) throws LuanException {
+			for( LuanJavaFunction fn : fnMap.get(args.length) ) {
 				try {
 					return fn.call(lua,args);
 				} catch(IllegalArgumentException e) {}
 			}
-			throw new LuaException(lua,LuaElement.JAVA,"no method matched args");
+			throw new LuanException(lua,LuanElement.JAVA,"no method matched args");
 		}
 	}
 
--- a/src/luan/lib/LuaRuntimeException.java	Thu Dec 27 04:36:44 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-package luan.lib;
-
-import luan.LuaException;
-
-
-public final class LuaRuntimeException extends RuntimeException {
-	public LuaRuntimeException(LuaException e) {
-		super(e);
-	}
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/lib/LuanRuntimeException.java	Fri Dec 28 03:29:12 2012 +0000
@@ -0,0 +1,10 @@
+package luan.lib;
+
+import luan.LuanException;
+
+
+public final class LuanRuntimeException extends RuntimeException {
+	public LuanRuntimeException(LuanException e) {
+		super(e);
+	}
+}
--- a/src/luan/lib/StringLib.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/lib/StringLib.java	Fri Dec 28 03:29:12 2012 +0000
@@ -2,27 +2,27 @@
 
 import java.util.regex.Pattern;
 import java.util.regex.Matcher;
-import luan.Lua;
-import luan.LuaState;
-import luan.LuaTable;
-import luan.LuaFunction;
-import luan.LuaJavaFunction;
-import luan.LuaElement;
-import luan.LuaException;
+import luan.Luan;
+import luan.LuanState;
+import luan.LuanTable;
+import luan.LuanFunction;
+import luan.LuanJavaFunction;
+import luan.LuanElement;
+import luan.LuanException;
 
 
 public final class StringLib {
 
-	public static void register(LuaState lua) {
-		LuaTable module = new LuaTable();
-		LuaTable global = lua.global();
+	public static void register(LuanState lua) {
+		LuanTable module = new LuanTable();
+		LuanTable global = lua.global();
 		global.put("string",module);
 		try {
-			module.put( "byte", new LuaJavaFunction(StringLib.class.getMethod("byte_",String.class,Integer.class,Integer.class),null) );
-			module.put( "char", new LuaJavaFunction(StringLib.class.getMethod("char_",new byte[0].getClass()),null) );
+			module.put( "byte", new LuanJavaFunction(StringLib.class.getMethod("byte_",String.class,Integer.class,Integer.class),null) );
+			module.put( "char", new LuanJavaFunction(StringLib.class.getMethod("char_",new byte[0].getClass()),null) );
 			add( module, "find", String.class, String.class, Integer.class, Boolean.class );
 			add( module, "gmatch", String.class, String.class );
-			add( module, "gsub", LuaState.class, String.class, String.class, Object.class, Integer.class );
+			add( module, "gsub", LuanState.class, String.class, String.class, Object.class, Integer.class );
 			add( module, "len", String.class );
 			add( module, "lower", String.class );
 			add( module, "match", String.class, String.class, Integer.class );
@@ -35,8 +35,8 @@
 		}
 	}
 
-	private static void add(LuaTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException {
-		t.put( method, new LuaJavaFunction(StringLib.class.getMethod(method,parameterTypes),null) );
+	private static void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException {
+		t.put( method, new LuanJavaFunction(StringLib.class.getMethod(method,parameterTypes),null) );
 	}
 
 	static int start(String s,int i) {
@@ -126,12 +126,12 @@
 		return rtn;
 	}
 
-	public static LuaFunction gmatch(String s,String pattern) {
+	public static LuanFunction gmatch(String s,String pattern) {
 		final Matcher m = Pattern.compile(pattern).matcher(s);
-		return new LuaFunction() {
-			public Object[] call(LuaState lua,Object[] args) {
+		return new LuanFunction() {
+			public Object[] call(LuanState lua,Object[] args) {
 				if( !m.find() )
-					return LuaFunction.EMPTY_RTN;
+					return LuanFunction.EMPTY_RTN;
 				final int n = m.groupCount();
 				if( n == 0 )
 					return new String[]{m.group()};
@@ -144,7 +144,7 @@
 		};
 	}
 
-	public static Object[] gsub(LuaState lua,String s,String pattern,Object repl,Integer n) throws LuaException {
+	public static Object[] gsub(LuanState lua,String s,String pattern,Object repl,Integer n) throws LuanException {
 		int max = n==null ? Integer.MAX_VALUE : n;
 		final Matcher m = Pattern.compile(pattern).matcher(s);
 		if( repl instanceof String ) {
@@ -158,17 +158,17 @@
 			m.appendTail(sb);
 			return new Object[]{ sb.toString(), i };
 		}
-		if( repl instanceof LuaTable ) {
-			LuaTable t = (LuaTable)repl;
+		if( repl instanceof LuanTable ) {
+			LuanTable t = (LuanTable)repl;
 			int i = 0;
 			StringBuffer sb = new StringBuffer();
 			while( i<max && m.find() ) {
 				String match = m.groupCount()==0 ? m.group() : m.group(0);
 				Object val = t.get(match);
-				if( Lua.toBoolean(val) ) {
-					String replacement = Lua.asString(val);
+				if( Luan.toBoolean(val) ) {
+					String replacement = Luan.asString(val);
 					if( replacement==null )
-						throw new LuaException( lua, LuaElement.JAVA, "invalid replacement value (a "+Lua.type(val)+")" );
+						throw new LuanException( lua, LuanElement.JAVA, "invalid replacement value (a "+Luan.type(val)+")" );
 					m.appendReplacement(sb,replacement);
 				}
 				i++;
@@ -176,8 +176,8 @@
 			m.appendTail(sb);
 			return new Object[]{ sb.toString(), i };
 		}
-		if( repl instanceof LuaFunction ) {
-			LuaFunction fn = (LuaFunction)repl;
+		if( repl instanceof LuanFunction ) {
+			LuanFunction fn = (LuanFunction)repl;
 			int i = 0;
 			StringBuffer sb = new StringBuffer();
 			while( i<max && m.find() ) {
@@ -191,11 +191,11 @@
 						args[j] = m.group(j);
 					}
 				}
-				Object val = Lua.first( lua.call(fn,LuaElement.JAVA,"repl-arg",args) );
-				if( Lua.toBoolean(val) ) {
-					String replacement = Lua.asString(val);
+				Object val = Luan.first( lua.call(fn,LuanElement.JAVA,"repl-arg",args) );
+				if( Luan.toBoolean(val) ) {
+					String replacement = Luan.asString(val);
 					if( replacement==null )
-						throw new LuaException( lua, LuaElement.JAVA, "invalid replacement value (a "+Lua.type(val)+")" );
+						throw new LuanException( lua, LuanElement.JAVA, "invalid replacement value (a "+Luan.type(val)+")" );
 					m.appendReplacement(sb,replacement);
 				}
 				i++;
@@ -203,7 +203,7 @@
 			m.appendTail(sb);
 			return new Object[]{ sb.toString(), i };
 		}
-		throw new LuaException( lua, LuaElement.JAVA, "bad argument #3 to 'gsub' (string/function/table expected)" );
+		throw new LuanException( lua, LuanElement.JAVA, "bad argument #3 to 'gsub' (string/function/table expected)" );
 	}
 
 }
--- a/src/luan/lib/TableLib.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/lib/TableLib.java	Fri Dec 28 03:29:12 2012 +0000
@@ -3,39 +3,39 @@
 import java.util.Comparator;
 import java.util.ArrayList;
 import java.util.Arrays;
-import luan.Lua;
-import luan.LuaState;
-import luan.LuaTable;
-import luan.LuaFunction;
-import luan.LuaJavaFunction;
-import luan.LuaElement;
-import luan.LuaException;
+import luan.Luan;
+import luan.LuanState;
+import luan.LuanTable;
+import luan.LuanFunction;
+import luan.LuanJavaFunction;
+import luan.LuanElement;
+import luan.LuanException;
 
 
 public final class TableLib {
 
-	public static void register(LuaState lua) {
-		LuaTable module = new LuaTable();
-		LuaTable global = lua.global();
+	public static void register(LuanState lua) {
+		LuanTable module = new LuanTable();
+		LuanTable global = lua.global();
 		global.put("table",module);
 		try {
-			add( module, "concat", LuaState.class, LuaTable.class, String.class, Integer.class, Integer.class );
-			add( module, "insert", LuaState.class, LuaTable.class, Integer.TYPE, Object.class );
+			add( module, "concat", LuanState.class, LuanTable.class, String.class, Integer.class, Integer.class );
+			add( module, "insert", LuanState.class, LuanTable.class, Integer.TYPE, Object.class );
 			add( module, "pack", new Object[0].getClass() );
-			add( module, "remove", LuaState.class, LuaTable.class, Integer.TYPE );
-			add( module, "sort", LuaState.class, LuaTable.class, LuaFunction.class );
-			add( module, "sub_list", LuaTable.class, Integer.TYPE, Integer.TYPE );
-			add( module, "unpack", LuaTable.class );
+			add( module, "remove", LuanState.class, LuanTable.class, Integer.TYPE );
+			add( module, "sort", LuanState.class, LuanTable.class, LuanFunction.class );
+			add( module, "sub_list", LuanTable.class, Integer.TYPE, Integer.TYPE );
+			add( module, "unpack", LuanTable.class );
 		} catch(NoSuchMethodException e) {
 			throw new RuntimeException(e);
 		}
 	}
 
-	private static void add(LuaTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException {
-		t.put( method, new LuaJavaFunction(TableLib.class.getMethod(method,parameterTypes),null) );
+	private static void add(LuanTable t,String method,Class<?>... parameterTypes) throws NoSuchMethodException {
+		t.put( method, new LuanJavaFunction(TableLib.class.getMethod(method,parameterTypes),null) );
 	}
 
-	public static String concat(LuaState lua,LuaTable list,String sep,Integer i,Integer j) throws LuaException {
+	public static String concat(LuanState lua,LuanTable list,String sep,Integer i,Integer j) throws LuanException {
 		int first = i==null ? 1 : i;
 		int last = j==null ? list.length() : j;
 		StringBuilder buf = new StringBuilder();
@@ -45,27 +45,27 @@
 				break;
 			if( sep!=null && k > first )
 				buf.append(sep);
-			String s = Lua.asString(val);
+			String s = Luan.asString(val);
 			if( s==null )
-				throw new LuaException( lua, LuaElement.JAVA, "invalid value ("+Lua.type(val)+") at index "+k+" in table for 'concat'" );
+				throw new LuanException( lua, LuanElement.JAVA, "invalid value ("+Luan.type(val)+") at index "+k+" in table for 'concat'" );
 			buf.append(val);
 		}
 		return buf.toString();
 	}
 
-	public static void insert(LuaState lua,LuaTable list,int pos,Object value) throws LuaException {
+	public static void insert(LuanState lua,LuanTable list,int pos,Object value) throws LuanException {
 		try {
 			list.insert(pos,value);
 		} catch(IndexOutOfBoundsException e) {
-			throw new LuaException( lua, LuaElement.JAVA, e);
+			throw new LuanException( lua, LuanElement.JAVA, e);
 		}
 	}
 
-	public static Object remove(LuaState lua,LuaTable list,int pos) throws LuaException {
+	public static Object remove(LuanState lua,LuanTable list,int pos) throws LuanException {
 		try {
 			return list.remove(pos);
 		} catch(IndexOutOfBoundsException e) {
-			throw new LuaException( lua, LuaElement.JAVA, e);
+			throw new LuanException( lua, LuanElement.JAVA, e);
 		}
 	}
 
@@ -73,15 +73,15 @@
 		public boolean isLessThan(Object o1,Object o2);
 	}
 
-	public static void sort(final LuaState lua,LuaTable list,final LuaFunction comp) throws LuaException {
+	public static void sort(final LuanState lua,LuanTable list,final LuanFunction comp) throws LuanException {
 		final LessThan lt;
 		if( comp==null ) {
 			lt = new LessThan() {
 				public boolean isLessThan(Object o1,Object o2) {
 					try {
-						return lua.isLessThan(LuaElement.JAVA,o1,o2);
-					} catch(LuaException e) {
-						throw new LuaRuntimeException(e);
+						return lua.isLessThan(LuanElement.JAVA,o1,o2);
+					} catch(LuanException e) {
+						throw new LuanRuntimeException(e);
 					}
 				}
 			};
@@ -89,9 +89,9 @@
 			lt = new LessThan() {
 				public boolean isLessThan(Object o1,Object o2) {
 					try {
-						return Lua.toBoolean(Lua.first(lua.call(comp,LuaElement.JAVA,"comp-arg",o1,o2)));
-					} catch(LuaException e) {
-						throw new LuaRuntimeException(e);
+						return Luan.toBoolean(Luan.first(lua.call(comp,LuanElement.JAVA,"comp-arg",o1,o2)));
+					} catch(LuanException e) {
+						throw new LuanRuntimeException(e);
 					}
 				}
 			};
@@ -102,20 +102,20 @@
 					return lt.isLessThan(o1,o2) ? -1 : lt.isLessThan(o2,o1) ? 1 : 0;
 				}
 			} );
-		} catch(LuaRuntimeException e) {
-			throw (LuaException)e.getCause();
+		} catch(LuanRuntimeException e) {
+			throw (LuanException)e.getCause();
 		}
 	}
 
-	public static LuaTable pack(Object[] args) {
-		return new LuaTable(new ArrayList<Object>(Arrays.asList(args)));
+	public static LuanTable pack(Object[] args) {
+		return new LuanTable(new ArrayList<Object>(Arrays.asList(args)));
 	}
 
-	public static Object[] unpack(LuaTable list) {
+	public static Object[] unpack(LuanTable list) {
 		return list.listToArray();
 	}
 
-	public static LuaTable sub_list(LuaTable list,int from,int to) {
+	public static LuanTable sub_list(LuanTable list,int from,int to) {
 		return list.subList(from,to);
 	}
 
--- a/src/luan/tools/CmdLine.java	Thu Dec 27 04:36:44 2012 +0000
+++ b/src/luan/tools/CmdLine.java	Fri Dec 28 03:29:12 2012 +0000
@@ -6,18 +6,18 @@
 import luan.lib.JavaLib;
 import luan.lib.StringLib;
 import luan.lib.TableLib;
-import luan.Lua;
-import luan.LuaState;
-import luan.LuaFunction;
-import luan.LuaTable;
-import luan.LuaException;
-import luan.interp.LuaCompiler;
+import luan.Luan;
+import luan.LuanState;
+import luan.LuanFunction;
+import luan.LuanTable;
+import luan.LuanException;
+import luan.interp.LuanCompiler;
 
 
 public class CmdLine {
 
 	public static void main(String[] args) {
-		LuaState lua = LuaCompiler.newLuaState();
+		LuanState lua = LuanCompiler.newLuaState();
 		BasicLib.register(lua);
 		JavaLib.register(lua);
 		StringLib.register(lua);
@@ -43,16 +43,16 @@
 						error("'-e' needs argument");
 					String cmd = args[i];
 					try {
-						LuaFunction fn = BasicLib.load(lua,cmd,"(command line)");
+						LuanFunction fn = BasicLib.load(lua,cmd,"(command line)");
 						lua.call(fn,null,null);
-					} catch(LuaException e) {
+					} catch(LuanException e) {
 						System.err.println("command line error: "+e.getMessage());
 						System.exit(-1);
 					}
 				} else if( arg.equals("-") ) {
 					try {
 						BasicLib.do_file(lua,"stdin");
-					} catch(LuaException e) {
+					} catch(LuanException e) {
 						System.err.println(e.getMessage());
 						System.exit(-1);
 					}
@@ -64,20 +64,20 @@
 			}
 		}
 		if( showVersion )
-			System.out.println(Lua.version);
+			System.out.println(Luan.version);
 		if( i < args.length ) {
 			String file = args[i++];
 			Object[] varArgs = new Object[args.length-1];
 			System.arraycopy(args,1,varArgs,0,varArgs.length);
-			LuaTable argsTable = new LuaTable();
+			LuanTable argsTable = new LuanTable();
 			for( int j=0; j<args.length; j++ ) {
 				argsTable.put( j, args[j] );
 			}
 			lua.global().put("arg",argsTable);
 			try {
-				LuaFunction fn = BasicLib.load_file(lua,file);
+				LuanFunction fn = BasicLib.load_file(lua,file);
 				lua.call(fn,null,null,varArgs);
-			} catch(LuaException e) {
+			} catch(LuanException e) {
 //				System.err.println("error: "+e.getMessage());
 				e.printStackTrace();
 				System.exit(-1);
@@ -101,16 +101,16 @@
 		System.exit(-1);
 	}
 
-	static void interactive(LuaState lua) {
+	static void interactive(LuanState lua) {
 		while( true ) {
 			System.out.print("> ");
 			String input = new Scanner(System.in).nextLine();
 			try {
-				LuaFunction fn = BasicLib.load(lua,input,"stdin");
+				LuanFunction fn = BasicLib.load(lua,input,"stdin");
 				Object[] rtn = lua.call(fn,null,null);
 				if( rtn.length > 0 )
 					BasicLib.print(lua,rtn);
-			} catch(LuaException e) {
+			} catch(LuanException e) {
 				System.out.println(e.getMessage());
 			}
 		}