changeset 40:e3624b7cd603

implement stack trace git-svn-id: https://luan-java.googlecode.com/svn/trunk@41 21e917c8-12df-6dd8-5cb6-c86387c605b9
author fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9>
date Fri, 21 Dec 2012 10:45:54 +0000
parents e5bcb1eeafc1
children c53dc854e6cc
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/StackTraceElement.java src/luan/interp/AddExpr.java src/luan/interp/AndExpr.java src/luan/interp/BinaryOpExpr.java src/luan/interp/Chunk.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/FnCall.java src/luan/interp/GenericForStmt.java src/luan/interp/GetLocalVar.java src/luan/interp/GetUpVar.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/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/ReturnStmt.java src/luan/interp/SetTableEntry.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/Utils.java src/luan/interp/VarArgs.java src/luan/lib/BasicLib.java src/luan/lib/JavaLib.java src/luan/tools/CmdLine.java
diffstat 52 files changed, 553 insertions(+), 336 deletions(-) [+]
line wrap: on
line diff
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/Lua.java
--- a/src/luan/Lua.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/Lua.java	Fri Dec 21 10:45:54 2012 +0000
@@ -26,13 +26,6 @@
 		return null;
 	}
 
-	public static String checkString(Object obj) throws LuaException {
-		String s = asString(obj);
-		if( s == null )
-			throw new LuaException( "attempt to use a " + Lua.type(obj) + " as a string" );
-		return s;
-	}
-
 	public static LuaNumber toNumber(Object obj) {
 		return toNumber(obj,null);
 	}
@@ -52,17 +45,8 @@
 		return null;
 	}
 
-	public static LuaNumber checkNumber(Object obj) throws LuaException {
-		LuaNumber n = toNumber(obj);
-		if( n == null )
-			throw new LuaException( "attempt to perform arithmetic on a " + type(obj) + " value" );
-		return n;
-	}
-
-	public static LuaFunction checkFunction(Object obj) throws LuaException {
-		if( obj instanceof LuaFunction )
-			return (LuaFunction)obj;
-		throw new LuaException( "attempt to call a " + type(obj) + " value" );
+	public static Object first(Object[] a) {
+		return a.length==0 ? null : a[0];
 	}
 
 }
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/LuaElement.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/LuaElement.java	Fri Dec 21 10:45:54 2012 +0000
@@ -0,0 +1,16 @@
+package luan;
+
+
+public abstract class LuaElement {
+	abstract String toString(String fnName);
+
+	final String function(String fnName) {
+		return fnName==null ? "main chunk" : "function '"+fnName+"'";
+	}
+
+	public static final LuaElement JAVA = new LuaElement(){
+		@Override public String toString(String fnName) {
+			return "java: in " + function(fnName);
+		}
+	};
+}
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/LuaException.java
--- a/src/luan/LuaException.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/LuaException.java	Fri Dec 21 10:45:54 2012 +0000
@@ -3,12 +3,26 @@
 
 public class LuaException extends Exception {
 
-	public LuaException(String msg) {
-		super(msg);
+	public LuaException(LuaState lua,LuaElement el,String msg) {
+		super(hideNull(msg)+stackTrace(lua,el));
+	}
+
+	public LuaException(LuaState lua,LuaElement el,Exception cause) {
+		super(hideNull(cause.getMessage())+stackTrace(lua,el),cause);
+	}
+
+	private static String hideNull(String s) {
+		return s==null ? "" : s;
 	}
 
-	public LuaException(Exception e) {
-		super(e);
+	private static String stackTrace(LuaState lua,LuaElement el) {
+		StringBuilder buf = new StringBuilder();
+		int i = lua.stackTrace.size() - 1;
+		do {
+			StackTraceElement stackTraceElement = lua.stackTrace.get(i);
+			buf.append( "\n\t" ).append( el.toString(stackTraceElement.fnName) );
+			el = stackTraceElement.call;
+		} while( --i >= 0 );
+		return buf.toString();
 	}
-
 }
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/LuaFunction.java
--- a/src/luan/LuaFunction.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/LuaFunction.java	Fri Dec 21 10:45:54 2012 +0000
@@ -3,7 +3,7 @@
 
 public abstract class LuaFunction {
 
-	public abstract Object[] call(LuaState lua,Object... args) throws LuaException;
+	public abstract Object[] call(LuaState lua,Object[] args) throws LuaException;
 
 	public static final Object[] EMPTY_RTN = new Object[0];
 
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/LuaJavaFunction.java
--- a/src/luan/LuaJavaFunction.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/LuaJavaFunction.java	Fri Dec 21 10:45:54 2012 +0000
@@ -40,7 +40,7 @@
 		return method.getParameterTypes();
 	}
 
-	@Override public Object[] call(LuaState lua,Object... args) {
+	@Override public Object[] call(LuaState lua,Object[] args) throws LuaException {
 		args = fixArgs(lua,args);
 		Object rtn;
 		try {
@@ -48,6 +48,13 @@
 		} 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);
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/LuaSource.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/LuaSource.java	Fri Dec 21 10:45:54 2012 +0000
@@ -0,0 +1,45 @@
+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 public String toString(String fnName) {
+			return source.name + ':' + lineNumber() + ": in " + function(fnName);
+		}
+
+		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;
+		}
+
+	}
+}
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/LuaState.java
--- a/src/luan/LuaState.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/LuaState.java	Fri Dec 21 10:45:54 2012 +0000
@@ -1,9 +1,83 @@
 package luan;
 
+import java.util.List;
+import java.util.ArrayList;
+
 
-public interface LuaState {
-	public LuaTable global();
-	public String toString(Object obj) throws LuaException;
-	public LuaTable getMetatable(Object obj);
-	public void addMetatableGetter(MetatableGetter mg);
+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 LuaNumber checkNumber(LuaElement el,Object obj) throws LuaException {
+		LuaNumber 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";
+		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);
+	}
+
 }
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/StackTraceElement.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/StackTraceElement.java	Fri Dec 21 10:45:54 2012 +0000
@@ -0,0 +1,12 @@
+package luan;
+
+
+final class StackTraceElement {
+	final LuaElement call;
+	final String fnName;
+
+	StackTraceElement(LuaElement call,String fnName) {
+		this.call = call;
+		this.fnName = fnName;
+	}
+}
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/AddExpr.java
--- a/src/luan/interp/AddExpr.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/AddExpr.java	Fri Dec 21 10:45:54 2012 +0000
@@ -3,12 +3,13 @@
 import luan.Lua;
 import luan.LuaNumber;
 import luan.LuaException;
+import luan.LuaSource;
 
 
 final class AddExpr extends BinaryOpExpr {
 
-	AddExpr(Expr op1,Expr op2) {
-		super(op1,op2);
+	AddExpr(LuaSource.Element se,Expr op1,Expr op2) {
+		super(se,op1,op2);
 	}
 
 	@Override public Object eval(LuaStateImpl lua) throws LuaException {
@@ -18,6 +19,6 @@
 		LuaNumber n2 = Lua.toNumber(o2);
 		if( n1 != null && n2 != null )
 			return new LuaNumber( n1.value() + n2.value() );
-		return lua.arithmetic("__add",o1,o2);
+		return arithmetic(lua,"__add",o1,o2);
 	}
 }
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/AndExpr.java
--- a/src/luan/interp/AndExpr.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/AndExpr.java	Fri Dec 21 10:45:54 2012 +0000
@@ -2,12 +2,13 @@
 
 import luan.Lua;
 import luan.LuaException;
+import luan.LuaSource;
 
 
 final class AndExpr extends BinaryOpExpr {
 
-	AndExpr(Expr op1,Expr op2) {
-		super(op1,op2);
+	AndExpr(LuaSource.Element se,Expr op1,Expr op2) {
+		super(se,op1,op2);
 	}
 
 	@Override public Object eval(LuaStateImpl lua) throws LuaException {
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/BinaryOpExpr.java
--- a/src/luan/interp/BinaryOpExpr.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/BinaryOpExpr.java	Fri Dec 21 10:45:54 2012 +0000
@@ -4,15 +4,21 @@
 import luan.LuaTable;
 import luan.LuaFunction;
 import luan.LuaException;
+import luan.LuaSource;
 
 
-abstract class BinaryOpExpr implements Expr {
+abstract class BinaryOpExpr extends CodeImpl implements Expr {
 	final Expr op1;
 	final Expr op2;
 
-	BinaryOpExpr(Expr op1,Expr op2) {
+	BinaryOpExpr(LuaSource.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 {
+		return lua.arithmetic(se(),"__mod",o1,o2);
+	}
+
 }
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/Chunk.java
--- a/src/luan/interp/Chunk.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/Chunk.java	Fri Dec 21 10:45:54 2012 +0000
@@ -1,16 +1,18 @@
 package luan.interp;
 
 import luan.LuaException;
+import luan.LuaSource;
 
 
-final class Chunk implements Expr {
+final class Chunk extends CodeImpl implements Expr {
 	final Stmt block;
 	final int stackSize;
 	final int numArgs;
 	final boolean isVarArg;
 	final UpValue.Getter[] upValueGetters;
 
-	Chunk(Stmt block,int stackSize,int numArgs,boolean isVarArg,UpValue.Getter[] upValueGetters) {
+	Chunk(LuaSource.Element se,Stmt block,int stackSize,int numArgs,boolean isVarArg,UpValue.Getter[] upValueGetters) {
+		super(se);
 		this.block = block;
 		this.stackSize = stackSize;
 		this.numArgs = numArgs;
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/Code.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/interp/Code.java	Fri Dec 21 10:45:54 2012 +0000
@@ -0,0 +1,8 @@
+package luan.interp;
+
+import luan.LuaSource;
+
+
+interface Code {
+	public LuaSource.Element se();
+}
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/CodeImpl.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/interp/CodeImpl.java	Fri Dec 21 10:45:54 2012 +0000
@@ -0,0 +1,16 @@
+package luan.interp;
+
+import luan.LuaSource;
+
+
+class CodeImpl implements Code {
+	final LuaSource.Element se;
+
+	CodeImpl(LuaSource.Element se) {
+		this.se = se;
+	}
+
+	@Override public final LuaSource.Element se() {
+		return se;
+	}
+}
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/ConcatExpr.java
--- a/src/luan/interp/ConcatExpr.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/ConcatExpr.java	Fri Dec 21 10:45:54 2012 +0000
@@ -3,12 +3,13 @@
 import luan.Lua;
 import luan.LuaFunction;
 import luan.LuaException;
+import luan.LuaSource;
 
 
 final class ConcatExpr extends BinaryOpExpr {
 
-	ConcatExpr(Expr op1,Expr op2) {
-		super(op1,op2);
+	ConcatExpr(LuaSource.Element se,Expr op1,Expr op2) {
+		super(se,op1,op2);
 	}
 
 	@Override public Object eval(LuaStateImpl lua) throws LuaException {
@@ -18,10 +19,10 @@
 		String s2 = Lua.asString(o2);
 		if( s1 != null && s2 != null )
 			return s1 + s2;
-		LuaFunction fn = lua.getBinHandler("__concat",o1,o2);
+		LuaFunction fn = lua.getBinHandler(se,"__concat",o1,o2);
 		if( fn != null )
-			return Utils.first(fn.call(lua,o1,o2));
+			return Lua.first(lua.call(fn,se,"__concat",o1,o2));
 		String type = s1==null ? Lua.type(o1) : Lua.type(o2);
-		throw new LuaException( "attempt to concatenate a " + type + " value" );
+		throw new LuaException( lua, se, "attempt to concatenate a " + type + " value" );
 	}
 }
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/ConstExpr.java
--- a/src/luan/interp/ConstExpr.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/ConstExpr.java	Fri Dec 21 10:45:54 2012 +0000
@@ -1,5 +1,7 @@
 package luan.interp;
 
+import luan.LuaSource;
+
 
 final class ConstExpr implements Expr {
 	private final Object obj;
@@ -11,4 +13,8 @@
 	@Override public Object eval(LuaStateImpl lua) {
 		return obj;
 	}
+
+	@Override public final LuaSource.Element se() {
+		return null;
+	}
 }
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/DivExpr.java
--- a/src/luan/interp/DivExpr.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/DivExpr.java	Fri Dec 21 10:45:54 2012 +0000
@@ -3,12 +3,13 @@
 import luan.Lua;
 import luan.LuaNumber;
 import luan.LuaException;
+import luan.LuaSource;
 
 
 final class DivExpr extends BinaryOpExpr {
 
-	DivExpr(Expr op1,Expr op2) {
-		super(op1,op2);
+	DivExpr(LuaSource.Element se,Expr op1,Expr op2) {
+		super(se,op1,op2);
 	}
 
 	@Override public Object eval(LuaStateImpl lua) throws LuaException {
@@ -18,6 +19,6 @@
 		LuaNumber n2 = Lua.toNumber(o2);
 		if( n1 != null && n2 != null )
 			return new LuaNumber( n1.value() / n2.value() );
-		return lua.arithmetic("__div",o1,o2);
+		return arithmetic(lua,"__div",o1,o2);
 	}
 }
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/EqExpr.java
--- a/src/luan/interp/EqExpr.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/EqExpr.java	Fri Dec 21 10:45:54 2012 +0000
@@ -5,12 +5,13 @@
 import luan.LuaFunction;
 import luan.LuaTable;
 import luan.LuaException;
+import luan.LuaSource;
 
 
 final class EqExpr extends BinaryOpExpr {
 
-	EqExpr(Expr op1,Expr op2) {
-		super(op1,op2);
+	EqExpr(LuaSource.Element se,Expr op1,Expr op2) {
+		super(se,op1,op2);
 	}
 
 	@Override public Object eval(LuaStateImpl lua) throws LuaException {
@@ -27,7 +28,7 @@
 		Object f = mt1.get("__eq");
 		if( f == null || !f.equals(mt2.get("__eq")) )
 			return null;
-		LuaFunction fn = Lua.checkFunction(f);
-		return Lua.toBoolean( Utils.first(fn.call(lua,o1,o2)) );
+		LuaFunction fn = lua.checkFunction(se,f);
+		return Lua.toBoolean( Lua.first(lua.call(fn,se,"__eq",o1,o2)) );
 	}
 }
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/ExpList.java
--- a/src/luan/interp/ExpList.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/ExpList.java	Fri Dec 21 10:45:54 2012 +0000
@@ -4,12 +4,14 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import luan.LuaException;
+import luan.LuaSource;
 
 
 final class ExpList implements Expressions {
 
 	private interface Adder {
 		public void addTo(LuaStateImpl lua,List<Object> list) throws LuaException;
+		public Code code();
 	}
 
 	private static class ExprAdder implements Adder {
@@ -23,6 +25,10 @@
 			list.add( expr.eval(lua) );
 		}
 
+		public Code code() {
+			return expr;
+		}
+
 	}
 
 	private static class ExpressionsAdder implements Adder {
@@ -38,6 +44,10 @@
 			}
 		}
 
+		public Code code() {
+			return expressions;
+		}
+
 	}
 
 	static class Builder {
@@ -70,9 +80,14 @@
 	private static final Object[] EMPTY = new Object[0];
 
 	static final Expressions emptyExpList = new Expressions() {
+
 		@Override public Object[] eval(LuaStateImpl lua) {
 			return EMPTY;
 		}
+
+		@Override public LuaSource.Element se() {
+			return null;
+		}
 	};
 
 	static class SingleExpList implements Expressions {
@@ -85,6 +100,10 @@
 		@Override public Object[] eval(LuaStateImpl lua) throws LuaException {
 			return new Object[]{expr.eval(lua)};
 		}
+
+		@Override public LuaSource.Element se() {
+			return expr.se();
+		}
 	}
 
 	private final Adder[] adders;
@@ -100,4 +119,8 @@
 		}
 		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);
+	}
 }
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/Expr.java
--- a/src/luan/interp/Expr.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/Expr.java	Fri Dec 21 10:45:54 2012 +0000
@@ -3,6 +3,6 @@
 import luan.LuaException;
 
 
-interface Expr {
+interface Expr extends Code {
 	public Object eval(LuaStateImpl lua) throws LuaException;
 }
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/Expressions.java
--- a/src/luan/interp/Expressions.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/Expressions.java	Fri Dec 21 10:45:54 2012 +0000
@@ -3,6 +3,6 @@
 import luan.LuaException;
 
 
-interface Expressions {
+interface Expressions extends Code {
 	public Object[] eval(LuaStateImpl lua) throws LuaException;
 }
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/ExpressionsExpr.java
--- a/src/luan/interp/ExpressionsExpr.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/ExpressionsExpr.java	Fri Dec 21 10:45:54 2012 +0000
@@ -3,6 +3,7 @@
 import java.util.List;
 import luan.Lua;
 import luan.LuaException;
+import luan.LuaSource;
 
 
 final class ExpressionsExpr implements Expr {
@@ -13,6 +14,11 @@
 	}
 
 	@Override public Object eval(LuaStateImpl lua) throws LuaException {
-		return Utils.first( expressions.eval(lua) );
+		return Lua.first( expressions.eval(lua) );
 	}
+
+	public LuaSource.Element se() {
+		return expressions.se();
+	}
+
 }
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/FnCall.java
--- a/src/luan/interp/FnCall.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/FnCall.java	Fri Dec 21 10:45:54 2012 +0000
@@ -3,15 +3,19 @@
 import luan.Lua;
 import luan.LuaFunction;
 import luan.LuaException;
+import luan.LuaSource;
 
 
-final class FnCall implements Expressions {
+final class FnCall extends CodeImpl implements Expressions {
 	final Expr fnExpr;
 	final Expressions args;
+	final String fnName;
 
-	FnCall(Expr fnExpr,Expressions args) {
+	FnCall(LuaSource.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 {
@@ -21,11 +25,11 @@
 	private Object[] call(LuaStateImpl lua,Object o) throws LuaException {
 		if( o instanceof LuaFunction ) {
 			LuaFunction fn = (LuaFunction)o;
-			return fn.call( lua, args.eval(lua) );
+			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( "attempt to call a " + Lua.type(o) + " value" );
+		throw new LuaException( lua, se, "attempt to call a " + Lua.type(o) + " value" );
 	}
 }
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/GenericForStmt.java
--- a/src/luan/interp/GenericForStmt.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/GenericForStmt.java	Fri Dec 21 10:45:54 2012 +0000
@@ -3,15 +3,17 @@
 import luan.Lua;
 import luan.LuaException;
 import luan.LuaFunction;
+import luan.LuaSource;
 
 
-final class GenericForStmt implements Stmt {
+final class GenericForStmt extends CodeImpl implements Stmt {
 	private final int iVars;
 	private final int nVars;
 	private final Expr iterExpr;
 	private final Stmt block;
 
-	GenericForStmt(int iVars,int nVars,Expr iterExpr,Stmt block) {
+	GenericForStmt(LuaSource.Element se,int iVars,int nVars,Expr iterExpr,Stmt block) {
+		super(se);
 		this.iVars = iVars;
 		this.nVars = nVars;
 		this.iterExpr = iterExpr;
@@ -19,10 +21,10 @@
 	}
 
 	@Override public void eval(LuaStateImpl lua) throws LuaException {
-		LuaFunction iter = Lua.checkFunction( iterExpr.eval(lua) );
+		LuaFunction iter = lua.checkFunction( se, iterExpr.eval(lua) );
 		try {
 			while(true) {
-				Object[] vals = iter.call(lua);
+				Object[] vals = lua.call(iter,iterExpr.se(),iterExpr.se().text());
 				if( vals.length==0 || vals[0]==null )
 					break;
 				for( int i=0; i<nVars; i++ ) {
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/GetLocalVar.java
--- a/src/luan/interp/GetLocalVar.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/GetLocalVar.java	Fri Dec 21 10:45:54 2012 +0000
@@ -1,10 +1,13 @@
 package luan.interp;
 
+import luan.LuaSource;
+
 
-final class GetLocalVar implements Expr {
+final class GetLocalVar extends CodeImpl implements Expr {
 	private final int index;
 
-	GetLocalVar(int index) {
+	GetLocalVar(LuaSource.Element se,int index) {
+		super(se);
 		this.index = index;
 	}
 
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/GetUpVar.java
--- a/src/luan/interp/GetUpVar.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/GetUpVar.java	Fri Dec 21 10:45:54 2012 +0000
@@ -1,10 +1,13 @@
 package luan.interp;
 
+import luan.LuaSource;
+
 
-final class GetUpVar implements Expr {
+final class GetUpVar extends CodeImpl implements Expr {
 	private final int index;
 
-	GetUpVar(int index) {
+	GetUpVar(LuaSource.Element se,int index) {
+		super(se);
 		this.index = index;
 	}
 
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/IndexExpr.java
--- a/src/luan/interp/IndexExpr.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/IndexExpr.java	Fri Dec 21 10:45:54 2012 +0000
@@ -4,19 +4,20 @@
 import luan.LuaException;
 import luan.LuaTable;
 import luan.LuaFunction;
+import luan.LuaSource;
 
 
 final class IndexExpr extends BinaryOpExpr {
 
-	IndexExpr(Expr op1,Expr op2) {
-		super(op1,op2);
+	IndexExpr(LuaSource.Element se,Expr op1,Expr op2) {
+		super(se,op1,op2);
 	}
 
 	@Override public Object eval(LuaStateImpl lua) throws LuaException {
 		return index(lua,op1.eval(lua),op2.eval(lua));
 	}
 
-	private static Object index(LuaStateImpl lua,Object t,Object key) throws LuaException {
+	private Object index(LuaStateImpl lua,Object t,Object key) throws LuaException {
 		Object h;
 		if( t instanceof LuaTable ) {
 			LuaTable tbl = (LuaTable)t;
@@ -29,11 +30,11 @@
 		} else {
 			h = lua.getHandler("__index",t);
 			if( h==null )
-				throw new LuaException( "attempt to index a " + Lua.type(t) + " value" );
+				throw new LuaException( lua, se, "attempt to index a " + Lua.type(t) + " value" );
 		}
 		if( h instanceof LuaFunction ) {
 			LuaFunction fn = (LuaFunction)h;
-			return Utils.first(fn.call(lua,t,key));
+			return Lua.first(lua.call(fn,se,"__index",t,key));
 		}
 		return index(lua,h,key);
 	}
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/LeExpr.java
--- a/src/luan/interp/LeExpr.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/LeExpr.java	Fri Dec 21 10:45:54 2012 +0000
@@ -4,12 +4,13 @@
 import luan.LuaNumber;
 import luan.LuaFunction;
 import luan.LuaException;
+import luan.LuaSource;
 
 
 final class LeExpr extends BinaryOpExpr {
 
-	LeExpr(Expr op1,Expr op2) {
-		super(op1,op2);
+	LeExpr(LuaSource.Element se,Expr op1,Expr op2) {
+		super(se,op1,op2);
 	}
 
 	@Override public Object eval(LuaStateImpl lua) throws LuaException {
@@ -25,12 +26,12 @@
 			String s2 = (String)o2;
 			return s1.compareTo(s2) <= 0;
 		}
-		LuaFunction fn = lua.getBinHandler("__le",o1,o2);
+		LuaFunction fn = lua.getBinHandler(se,"__le",o1,o2);
 		if( fn != null )
-			return Lua.toBoolean( Utils.first(fn.call(lua,o1,o2)) );
-		fn = lua.getBinHandler("__lt",o1,o2);
+			return Lua.toBoolean( Lua.first(lua.call(fn,se,"__le",o1,o2)) );
+		fn = lua.getBinHandler(se,"__lt",o1,o2);
 		if( fn != null )
-			return !Lua.toBoolean( Utils.first(fn.call(lua,o2,o1)) );
-		throw new LuaException( "attempt to compare " + Lua.type(o1) + " with " + Lua.type(o2) );
+			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) );
 	}
 }
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/LenExpr.java
--- a/src/luan/interp/LenExpr.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/LenExpr.java	Fri Dec 21 10:45:54 2012 +0000
@@ -5,12 +5,13 @@
 import luan.LuaTable;
 import luan.LuaFunction;
 import luan.LuaException;
+import luan.LuaSource;
 
 
 final class LenExpr extends UnaryOpExpr {
 
-	LenExpr(Expr op) {
-		super(op);
+	LenExpr(LuaSource.Element se,Expr op) {
+		super(se,op);
 	}
 
 	@Override public Object eval(LuaStateImpl lua) throws LuaException {
@@ -19,13 +20,13 @@
 			String s = (String)o;
 			return new LuaNumber( s.length() );
 		}
-		LuaFunction fn = lua.getHandlerFunction("__len",o);
+		LuaFunction fn = lua.getHandlerFunction(se,"__len",o);
 		if( fn != null )
-			return Utils.first(fn.call(lua,o));
+			return Lua.first(lua.call(fn,se,"__len",o));
 		if( o instanceof LuaTable ) {
 			LuaTable t = (LuaTable)o;
 			return t.length();
 		}
-		throw new LuaException( "attempt to get length of a " + Lua.type(o) + " value" );
+		throw new LuaException( lua, se, "attempt to get length of a " + Lua.type(o) + " value" );
 	}
 }
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/LtExpr.java
--- a/src/luan/interp/LtExpr.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/LtExpr.java	Fri Dec 21 10:45:54 2012 +0000
@@ -4,12 +4,13 @@
 import luan.LuaNumber;
 import luan.LuaFunction;
 import luan.LuaException;
+import luan.LuaSource;
 
 
 final class LtExpr extends BinaryOpExpr {
 
-	LtExpr(Expr op1,Expr op2) {
-		super(op1,op2);
+	LtExpr(LuaSource.Element se,Expr op1,Expr op2) {
+		super(se,op1,op2);
 	}
 
 	@Override public Object eval(LuaStateImpl lua) throws LuaException {
@@ -25,9 +26,9 @@
 			String s2 = (String)o2;
 			return s1.compareTo(s2) < 0;
 		}
-		LuaFunction fn = lua.getBinHandler("__lt",o1,o2);
+		LuaFunction fn = lua.getBinHandler(se,"__lt",o1,o2);
 		if( fn != null )
-			return Lua.toBoolean( Utils.first(fn.call(lua,o1,o2)) );
-		throw new LuaException( "attempt to compare " + Lua.type(o1) + " with " + Lua.type(o2) );
+			return Lua.toBoolean( Lua.first(lua.call(fn,se,"__lt",o1,o2)) );
+		throw new LuaException( lua, se, "attempt to compare " + Lua.type(o1) + " with " + Lua.type(o2) );
 	}
 }
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/LuaClosure.java
--- a/src/luan/interp/LuaClosure.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/LuaClosure.java	Fri Dec 21 10:45:54 2012 +0000
@@ -2,6 +2,7 @@
 
 import luan.LuaFunction;
 import luan.LuaState;
+import luan.LuaElement;
 import luan.LuaException;
 
 
@@ -23,7 +24,7 @@
 		}
 	}
 
-	public Object[] call(LuaState lua,Object... args) throws LuaException {
+	public Object[] call(LuaState lua,Object[] args) throws LuaException {
 		return call(this,(LuaStateImpl)lua,args);
 	}
 
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/LuaCompiler.java
--- a/src/luan/interp/LuaCompiler.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/LuaCompiler.java	Fri Dec 21 10:45:54 2012 +0000
@@ -8,22 +8,25 @@
 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,String src) throws LuaException {
+	public static LuaFunction compile(LuaState lua,LuaSource src) throws LuaException {
 		LuaParser parser = Parboiled.createParser(LuaParser.class);
-		ParsingResult<?> result = new ReportingParseRunner(parser.Target()).run(src);
+		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( ErrorUtils.printParseErrors(result) );
+			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 {
+				public Object[] call(LuaState lua,Object[] args) throws LuaException {
 					return expressions.eval((LuaStateImpl)lua);
 				}
 			};
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/LuaParser.java
--- a/src/luan/interp/LuaParser.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/LuaParser.java	Fri Dec 21 10:45:54 2012 +0000
@@ -19,10 +19,17 @@
 import luan.Lua;
 import luan.LuaNumber;
 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 {
@@ -144,20 +151,22 @@
 		return true;
 	}
 
-	Chunk newChunk() {
-		return new Chunk( (Stmt)pop(), frame.stackSize, symbolsSize(), frame.isVarArg, frame.upValueGetters.toArray(NO_UP_VALUE_GETTERS) );
+	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() )
+					push( newChunk(start.get()) )
 				)
 			)
 		);
@@ -227,9 +236,11 @@
 	}
 
 	Rule ReturnStmt() {
+		Var<Integer> start = new Var<Integer>();
 		return Sequence(
+			start.set(currentIndex()),
 			Keyword("return"), Expressions(),
-			push( new ReturnStmt( (Expressions)pop() ) )
+			push( new ReturnStmt( se(start.get()), (Expressions)pop() ) )
 		);
 	}
 
@@ -241,15 +252,17 @@
 	}
 
 	Rule FnName() {
+		Var<Integer> start = new Var<Integer>();
 		return Sequence(
+			start.set(currentIndex()),
 			push(null),  // marker
 			Name(),
 			ZeroOrMore(
 				'.', Spaces(),
-				makeVarExp(),
+				makeVarExp(start.get()),
 				NameExpr()
 			),
-			makeSettableVar()
+			makeSettableVar(start.get())
 		);
 	}
 
@@ -272,19 +285,23 @@
 	}
 
 	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( stackStart.get(), symbolsSize() - stackStart.get(), expr(pop(1)), (Stmt)pop() ) ),
+			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(new LuaNumber(1)) ),  // default step
 			Optional(
@@ -294,7 +311,7 @@
 			),
 			addSymbol( (String)pop(3) ),  // add "for" var to symbols
 			Keyword("do"), LoopBlock(), Keyword("end"),
-			push( new NumericForStmt( symbolsSize()-1, expr(pop(3)), expr(pop(2)), expr(pop(1)), (Stmt)pop() ) ),
+			push( new NumericForStmt( se(start.get()), symbolsSize()-1, expr(pop(3)), expr(pop(2)), expr(pop(1)), (Stmt)pop() ) ),
 			popSymbols(1)
 		);
 	}
@@ -421,10 +438,15 @@
 	}
 
 	Rule SettableVar() {
-		return Sequence( Var(), makeSettableVar() );
+		Var<Integer> start = new Var<Integer>();
+		return Sequence(
+			start.set(currentIndex()),
+			Var(),
+			makeSettableVar(start.get())
+		);
 	}
 
-	boolean makeSettableVar() {
+	boolean makeSettableVar(int start) {
 		Object obj2 = pop();
 		if( obj2==null )
 			return false;
@@ -432,7 +454,7 @@
 		if( obj1!=null ) {
 			Expr key = expr(obj2);
 			Expr table = expr(obj1);
-			return push( new SetTableEntry(table,key) );
+			return push( new SetTableEntry(se(start),table,key) );
 		}
 		String name = (String)obj2;
 		int index = stackIndex(name);
@@ -441,7 +463,7 @@
 		index = upValueIndex(name);
 		if( index != -1 )
 			return push( new SetUpVar(index) );
-		return push( new SetTableEntry( env(), new ConstExpr(name) ) );
+		return push( new SetTableEntry( se(start), env(), new ConstExpr(name) ) );
 	}
 
 	Rule Expr() {
@@ -452,80 +474,98 @@
 	}
 
 	Rule OrExpr() {
+		Var<Integer> start = new Var<Integer>();
 		return Sequence(
+			start.set(currentIndex()),
 			AndExpr(),
-			ZeroOrMore( "or", Spaces(), AndExpr(), push( new OrExpr(expr(pop(1)),expr(pop())) ) )
+			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(expr(pop(1)),expr(pop())) ) )
+			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(expr(pop(1)),expr(pop())) ) ),
-					Sequence( "~=", Spaces(), ConcatExpr(), push( new NotExpr(new EqExpr(expr(pop(1)),expr(pop()))) ) ),
-					Sequence( "<=", Spaces(), ConcatExpr(), push( new LeExpr(expr(pop(1)),expr(pop())) ) ),
-					Sequence( ">=", Spaces(), ConcatExpr(), push( new LeExpr(expr(pop()),expr(pop())) ) ),
-					Sequence( "<", Spaces(), ConcatExpr(), push( new LtExpr(expr(pop(1)),expr(pop())) ) ),
-					Sequence( ">", Spaces(), ConcatExpr(), push( new LtExpr(expr(pop()),expr(pop())) ) )
+					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(expr(pop(1)),expr(pop())) ) )
+			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(expr(pop(1)),expr(pop())) ) ),
-					Sequence( '-', TestNot('-'), Spaces(), TermExpr(), push( new SubExpr(expr(pop(1)),expr(pop())) ) )
+					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(expr(pop(1)),expr(pop())) ) ),
-					Sequence( '/', Spaces(), UnaryExpr(), push( new DivExpr(expr(pop(1)),expr(pop())) ) ),
-					Sequence( '%', Spaces(), UnaryExpr(), push( new ModExpr(expr(pop(1)),expr(pop())) ) )
+					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() {
-		return FirstOf(
-			Sequence( '#', Spaces(), PowExpr(), push( new LenExpr(expr(pop())) ) ),
-			Sequence( '-', TestNot('-'), Spaces(), PowExpr(), push( new UnmExpr(expr(pop())) ) ),
-			Sequence( "not", Spaces(), PowExpr(), push( new NotExpr(expr(pop())) ) ),
-			PowExpr()
+		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(expr(pop(1)),expr(pop())) ) )
+			Optional( '^', Spaces(), PowExpr(), push( new PowExpr(se(start.get()),expr(pop(1)),expr(pop())) ) )
 		);
 	}
 
@@ -543,8 +583,10 @@
 	}
 
 	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(
@@ -557,7 +599,7 @@
 				)
 			),
 			')', decParens(), Spaces(), Block(), Keyword("end"),
-			push( newChunk() ),
+			push( newChunk(start.get()) ),
 			action( frame = frame.parent )
 		);
 	}
@@ -570,17 +612,21 @@
 	}
 
 	Rule VarArgs() {
+		Var<Integer> start = new Var<Integer>();
 		return Sequence(
+			start.set(currentIndex()),
 			"...", Spaces(),
 			frame.isVarArg,
-			push( VarArgs.INSTANCE )
+			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),
@@ -592,7 +638,7 @@
 			),
 			'}', decParens(),
 			Spaces(),
-			push( new TableExpr( fields.get().toArray(new TableExpr.Field[0]), builder.get().build() ) )
+			push( new TableExpr( se(start.get()), fields.get().toArray(new TableExpr.Field[0]), builder.get().build() ) )
 		);
 	}
 
@@ -621,14 +667,18 @@
 	}
 
 	Rule VarExp() {
+		Var<Integer> start = new Var<Integer>();
 		return Sequence(
+			start.set(currentIndex()),
 			Var(),
-			makeVarExp()
+			makeVarExp(start.get())
 		);
 	}
 
 	Rule Var() {
+		Var<Integer> start = new Var<Integer>();
 		return Sequence(
+			start.set(currentIndex()),
 			FirstOf(
 				Sequence(
 					'(', incParens(), Spaces(), Expr(), ')', decParens(), Spaces(),
@@ -641,12 +691,12 @@
 				)
 			),
 			ZeroOrMore(
-				makeVarExp(),
+				makeVarExp(start.get()),
 				FirstOf(
 					SubExpr(),
 					Sequence( '.', Spaces(), NameExpr() ),
 					Sequence(
-						Args(),
+						Args(start),
 						push(null)  // marker
 					)
 				)
@@ -657,32 +707,32 @@
 	Expr env() {
 		int index = stackIndex(_ENV);
 		if( index != -1 )
-			return new GetLocalVar(index);
+			return new GetLocalVar(null,index);
 		index = upValueIndex(_ENV);
 		if( index != -1 )
-			return new GetUpVar(index);
+			return new GetUpVar(null,index);
 		throw new RuntimeException("_ENV not found");
 	}
 
-	boolean makeVarExp() {
+	boolean makeVarExp(int start) {
 		Object obj2 = pop();
 		if( obj2==null )
 			return true;
 		Object obj1 = pop();
 		if( obj1 != null )
-			return push( new IndexExpr( expr(obj1), expr(obj2) ) );
+			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(index) );
+			return push( new GetLocalVar(se(start),index) );
 		index = upValueIndex(name);
 		if( index != -1 )
-			return push( new GetUpVar(index) );
-		return push( new IndexExpr( env(), new ConstExpr(name) ) );
+			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() {
+	Rule Args(Var<Integer> start) {
 		return Sequence(
 			FirstOf(
 				Sequence(
@@ -697,7 +747,7 @@
 					push( new ExpList.SingleExpList(new ConstExpr(pop())) )
 				)
 			),
-			push( new FnCall( expr(pop(1)), (Expressions)pop() ) )
+			push( new FnCall( se(start.get()), expr(pop(1)), (Expressions)pop() ) )
 		);
 	}
 
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/LuaStateImpl.java
--- a/src/luan/interp/LuaStateImpl.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/LuaStateImpl.java	Fri Dec 21 10:45:54 2012 +0000
@@ -8,67 +8,24 @@
 import luan.LuaFunction;
 import luan.MetatableGetter;
 import luan.LuaException;
+import luan.LuaElement;
 
 
-final class LuaStateImpl implements LuaState {
-	private final LuaTable global = new LuaTable();
-	private final List<MetatableGetter> mtGetters = new ArrayList<MetatableGetter>();
-
-	@Override public LuaTable global() {
-		return global;
-	}
+final class LuaStateImpl extends LuaState {
 
-	@Override public String toString(Object obj) throws LuaException {
-		LuaFunction fn = getHandlerFunction("__tostring",obj);
-		if( fn != null )
-			return Lua.checkString( Utils.first( fn.call(this,obj) ) );
-		if( obj == null )
-			return "nil";
-		return obj.toString();
+	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);
 	}
 
-	@Override public LuaTable getMetatable(Object obj) {
-		if( obj instanceof LuaTable ) {
-			LuaTable table = (LuaTable)obj;
-			return table.getMetatable();
-		}
-		for( MetatableGetter mg : mtGetters ) {
-			LuaTable table = mg.getMetatable(obj);
-			if( table != null )
-				return table;
-		}
-		return null;
-	}
-
-	public void addMetatableGetter(MetatableGetter mg) {
-		mtGetters.add(mg);
-	}
-
-	Object getHandler(String op,Object obj) throws LuaException {
-		LuaTable t = getMetatable(obj);
-		return t==null ? null : t.get(op);
-	}
-
-	LuaFunction getHandlerFunction(String op,Object obj) throws LuaException {
-		Object f = getHandler(op,obj);
-		if( f == null )
-			return null;
-		return Lua.checkFunction(f);
-	}
-
-	LuaFunction getBinHandler(String op,Object o1,Object o2) throws LuaException {
-		LuaFunction f1 = getHandlerFunction(op,o1);
-		if( f1 != null )
-			return f1;
-		return getHandlerFunction(op,o2);
-	}
-
-	final Object arithmetic(String op,Object o1,Object o2) throws LuaException {
-		LuaFunction fn = getBinHandler(op,o1,o2);
+	final Object arithmetic(LuaElement el,String op,Object o1,Object o2) throws LuaException {
+		LuaFunction fn = getBinHandler(el,op,o1,o2);
 		if( fn != null )
-			return Utils.first(fn.call(this,o1,o2));
+			return Lua.first(call(fn,el,op,o1,o2));
 		String type = Lua.toNumber(o1)==null ? Lua.type(o1) : Lua.type(o2);
-		throw new LuaException("attempt to perform arithmetic on a "+type+" value");
+		throw new LuaException(this,el,"attempt to perform arithmetic on a "+type+" value");
 	}
 
 
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/ModExpr.java
--- a/src/luan/interp/ModExpr.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/ModExpr.java	Fri Dec 21 10:45:54 2012 +0000
@@ -3,12 +3,13 @@
 import luan.Lua;
 import luan.LuaNumber;
 import luan.LuaException;
+import luan.LuaSource;
 
 
 final class ModExpr extends BinaryOpExpr {
 
-	ModExpr(Expr op1,Expr op2) {
-		super(op1,op2);
+	ModExpr(LuaSource.Element se,Expr op1,Expr op2) {
+		super(se,op1,op2);
 	}
 
 	@Override public Object eval(LuaStateImpl lua) throws LuaException {
@@ -18,6 +19,6 @@
 		LuaNumber n2 = Lua.toNumber(o2);
 		if( n1 != null && n2 != null )
 			return new LuaNumber( n1.value() % n2.value() );
-		return lua.arithmetic("__mod",o1,o2);
+		return arithmetic(lua,"__mod",o1,o2);
 	}
 }
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/MulExpr.java
--- a/src/luan/interp/MulExpr.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/MulExpr.java	Fri Dec 21 10:45:54 2012 +0000
@@ -3,12 +3,13 @@
 import luan.Lua;
 import luan.LuaNumber;
 import luan.LuaException;
+import luan.LuaSource;
 
 
 final class MulExpr extends BinaryOpExpr {
 
-	MulExpr(Expr op1,Expr op2) {
-		super(op1,op2);
+	MulExpr(LuaSource.Element se,Expr op1,Expr op2) {
+		super(se,op1,op2);
 	}
 
 	@Override public Object eval(LuaStateImpl lua) throws LuaException {
@@ -18,6 +19,6 @@
 		LuaNumber n2 = Lua.toNumber(o2);
 		if( n1 != null && n2 != null )
 			return new LuaNumber( n1.value() * n2.value() );
-		return lua.arithmetic("__mul",o1,o2);
+		return arithmetic(lua,"__mul",o1,o2);
 	}
 }
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/NotExpr.java
--- a/src/luan/interp/NotExpr.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/NotExpr.java	Fri Dec 21 10:45:54 2012 +0000
@@ -2,12 +2,13 @@
 
 import luan.Lua;
 import luan.LuaException;
+import luan.LuaSource;
 
 
 final class NotExpr extends UnaryOpExpr {
 
-	NotExpr(Expr op) {
-		super(op);
+	NotExpr(LuaSource.Element se,Expr op) {
+		super(se,op);
 	}
 
 	@Override public Object eval(LuaStateImpl lua) throws LuaException {
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/NumericForStmt.java
--- a/src/luan/interp/NumericForStmt.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/NumericForStmt.java	Fri Dec 21 10:45:54 2012 +0000
@@ -3,16 +3,18 @@
 import luan.Lua;
 import luan.LuaNumber;
 import luan.LuaException;
+import luan.LuaSource;
 
 
-final class NumericForStmt implements Stmt {
+final class NumericForStmt extends CodeImpl implements Stmt {
 	private final int iVar;
 	private final Expr fromExpr;
 	private final Expr toExpr;
 	private final Expr stepExpr;
 	private final Stmt block;
 
-	NumericForStmt(int iVar,Expr fromExpr,Expr toExpr,Expr stepExpr,Stmt block) {
+	NumericForStmt(LuaSource.Element se,int iVar,Expr fromExpr,Expr toExpr,Expr stepExpr,Stmt block) {
+		super(se);
 		this.iVar = iVar;
 		this.fromExpr = fromExpr;
 		this.toExpr = toExpr;
@@ -21,9 +23,9 @@
 	}
 
 	@Override public void eval(LuaStateImpl lua) throws LuaException {
-		double v = Lua.checkNumber( fromExpr.eval(lua) ).value();
-		double limit = Lua.checkNumber( toExpr.eval(lua) ).value();
-		double step = Lua.checkNumber( stepExpr.eval(lua) ).value();
+		double v = lua.checkNumber( se, fromExpr.eval(lua) ).value();
+		double limit = lua.checkNumber( se, toExpr.eval(lua) ).value();
+		double step = lua.checkNumber( se, stepExpr.eval(lua) ).value();
 		try {
 			while( step > 0.0 && v <= limit || step < 0.0 && v >= limit ) {
 				lua.stackSet( iVar, new LuaNumber(v) );
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/OrExpr.java
--- a/src/luan/interp/OrExpr.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/OrExpr.java	Fri Dec 21 10:45:54 2012 +0000
@@ -2,12 +2,13 @@
 
 import luan.Lua;
 import luan.LuaException;
+import luan.LuaSource;
 
 
 final class OrExpr extends BinaryOpExpr {
 
-	OrExpr(Expr op1,Expr op2) {
-		super(op1,op2);
+	OrExpr(LuaSource.Element se,Expr op1,Expr op2) {
+		super(se,op1,op2);
 	}
 
 	@Override public Object eval(LuaStateImpl lua) throws LuaException {
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/PowExpr.java
--- a/src/luan/interp/PowExpr.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/PowExpr.java	Fri Dec 21 10:45:54 2012 +0000
@@ -3,12 +3,13 @@
 import luan.Lua;
 import luan.LuaNumber;
 import luan.LuaException;
+import luan.LuaSource;
 
 
 final class PowExpr extends BinaryOpExpr {
 
-	PowExpr(Expr op1,Expr op2) {
-		super(op1,op2);
+	PowExpr(LuaSource.Element se,Expr op1,Expr op2) {
+		super(se,op1,op2);
 	}
 
 	@Override public Object eval(LuaStateImpl lua) throws LuaException {
@@ -18,6 +19,6 @@
 		LuaNumber n2 = Lua.toNumber(o2);
 		if( n1 != null && n2 != null )
 			return new LuaNumber( Math.pow( n1.value(), n2.value() ) );
-		return lua.arithmetic("__pow",o1,o2);
+		return arithmetic(lua,"__pow",o1,o2);
 	}
 }
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/ReturnStmt.java
--- a/src/luan/interp/ReturnStmt.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/ReturnStmt.java	Fri Dec 21 10:45:54 2012 +0000
@@ -3,14 +3,16 @@
 import luan.Lua;
 import luan.LuaException;
 import luan.LuaFunction;
+import luan.LuaSource;
 
 
-final class ReturnStmt implements Stmt {
+final class ReturnStmt extends CodeImpl implements Stmt {
 	private final Expressions expressions;
 	private final Expr tailFnExpr;
 	boolean throwReturnException = true;
 
-	ReturnStmt(Expressions expressions) {
+	ReturnStmt(LuaSource.Element se,Expressions expressions) {
+		super(se);
 		if( expressions instanceof FnCall ) {  // tail call
 			FnCall fnCall = (FnCall)expressions;
 			this.expressions = fnCall.args;
@@ -24,11 +26,11 @@
 	@Override public void eval(LuaStateImpl lua) throws LuaException {
 		lua.returnValues = expressions.eval(lua);
 		if( tailFnExpr != null ) {
-			LuaFunction tailFn = Lua.checkFunction( tailFnExpr.eval(lua) );
+			LuaFunction tailFn = lua.checkFunction( se, tailFnExpr.eval(lua) );
 			if( tailFn instanceof LuaClosure ) {
 				lua.tailFn = (LuaClosure)tailFn;
 			} else {
-				lua.returnValues =  tailFn.call(lua,lua.returnValues);
+				lua.returnValues =  lua.call(tailFn,tailFnExpr.se(),tailFnExpr.se().text(),lua.returnValues);
 			}
 		}
 		if( throwReturnException )
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/SetTableEntry.java
--- a/src/luan/interp/SetTableEntry.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/SetTableEntry.java	Fri Dec 21 10:45:54 2012 +0000
@@ -4,13 +4,15 @@
 import luan.LuaTable;
 import luan.Lua;
 import luan.LuaFunction;
+import luan.LuaSource;
 
 
-final class SetTableEntry implements Settable {
+final class SetTableEntry extends CodeImpl implements Settable {
 	private final Expr tableExpr;
 	private final Expr keyExpr;
 
-	SetTableEntry(Expr tableExpr,Expr keyExpr) {
+	SetTableEntry(LuaSource.Element se,Expr tableExpr,Expr keyExpr) {
+		super(se);
 		this.tableExpr = tableExpr;
 		this.keyExpr = keyExpr;
 	}
@@ -19,7 +21,7 @@
 		newindex( lua, tableExpr.eval(lua), keyExpr.eval(lua), value );
 	}
 
-	private static void newindex(LuaStateImpl lua,Object t,Object key,Object value) throws LuaException {
+	private void newindex(LuaStateImpl lua,Object t,Object key,Object value) throws LuaException {
 		Object h;
 		if( t instanceof LuaTable ) {
 			LuaTable table = (LuaTable)t;
@@ -33,11 +35,11 @@
 		} else {
 			h = lua.getHandler("__newindex",t);
 			if( h==null )
-				throw new LuaException( "attempt to index a " + Lua.type(t) + " value" );
+				throw new LuaException( lua, se, "attempt to index a " + Lua.type(t) + " value" );
 		}
 		if( h instanceof LuaFunction ) {
 			LuaFunction fn = (LuaFunction)h;
-			fn.call(lua,t,key,value);
+			lua.call(fn,se,"__newindex",t,key,value);
 		}
 		newindex(lua,h,key,value);
 	}
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/Stmt.java
--- a/src/luan/interp/Stmt.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/Stmt.java	Fri Dec 21 10:45:54 2012 +0000
@@ -7,6 +7,6 @@
 	public void eval(LuaStateImpl lua) throws LuaException;
 
 	static final Stmt EMPTY = new Stmt() {
-		public void eval(LuaStateImpl lua) {}
+		@Override public void eval(LuaStateImpl lua) {}
 	};
 }
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/SubExpr.java
--- a/src/luan/interp/SubExpr.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/SubExpr.java	Fri Dec 21 10:45:54 2012 +0000
@@ -3,12 +3,13 @@
 import luan.Lua;
 import luan.LuaNumber;
 import luan.LuaException;
+import luan.LuaSource;
 
 
 final class SubExpr extends BinaryOpExpr {
 
-	SubExpr(Expr op1,Expr op2) {
-		super(op1,op2);
+	SubExpr(LuaSource.Element se,Expr op1,Expr op2) {
+		super(se,op1,op2);
 	}
 
 	@Override public Object eval(LuaStateImpl lua) throws LuaException {
@@ -18,6 +19,6 @@
 		LuaNumber n2 = Lua.toNumber(o2);
 		if( n1 != null && n2 != null )
 			return new LuaNumber( n1.value() - n2.value() );
-		return lua.arithmetic("__sub",o1,o2);
+		return arithmetic(lua,"__sub",o1,o2);
 	}
 }
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/TableExpr.java
--- a/src/luan/interp/TableExpr.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/TableExpr.java	Fri Dec 21 10:45:54 2012 +0000
@@ -3,9 +3,10 @@
 import luan.LuaException;
 import luan.LuaTable;
 import luan.LuaNumber;
+import luan.LuaSource;
 
 
-final class TableExpr implements Expr {
+final class TableExpr extends CodeImpl implements Expr {
 
 	static class Field {
 		final Expr key;
@@ -20,7 +21,8 @@
 	private final Field[] fields;
 	private final Expressions expressions;
 
-	TableExpr(Field[] fields,Expressions expressions) {
+	TableExpr(LuaSource.Element se,Field[] fields,Expressions expressions) {
+		super(se);
 		this.fields = fields;
 		this.expressions = expressions;
 	}
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/UnaryOpExpr.java
--- a/src/luan/interp/UnaryOpExpr.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/UnaryOpExpr.java	Fri Dec 21 10:45:54 2012 +0000
@@ -1,10 +1,13 @@
 package luan.interp;
 
+import luan.LuaSource;
+
 
-abstract class UnaryOpExpr implements Expr {
+abstract class UnaryOpExpr extends CodeImpl implements Expr {
 	final Expr op;
 
-	UnaryOpExpr(Expr op) {
+	UnaryOpExpr(LuaSource.Element se,Expr op) {
+		super(se);
 		this.op = op;
 	}
 }
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/UnmExpr.java
--- a/src/luan/interp/UnmExpr.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/UnmExpr.java	Fri Dec 21 10:45:54 2012 +0000
@@ -4,13 +4,14 @@
 import luan.LuaNumber;
 import luan.LuaFunction;
 import luan.LuaException;
+import luan.LuaSource;
 
 
 // unary minus
 final class UnmExpr extends UnaryOpExpr {
 
-	UnmExpr(Expr op) {
-		super(op);
+	UnmExpr(LuaSource.Element se,Expr op) {
+		super(se,op);
 	}
 
 	@Override public Object eval(LuaStateImpl lua) throws LuaException {
@@ -18,9 +19,10 @@
 		LuaNumber n = Lua.toNumber(o);
 		if( n != null )
 			return new LuaNumber( -n.value() );
-		LuaFunction fn = lua.getHandlerFunction("__unm",o);
-		if( fn != null )
-			return Utils.first(fn.call(lua,o));
-		throw new LuaException("attempt to perform arithmetic on a "+Lua.type(o)+" value");
+		LuaFunction fn = lua.getHandlerFunction(se,"__unm",o);
+		if( fn != null ) {
+			return Lua.first(lua.call(fn,se,"__unm",o));
+		}
+		throw new LuaException(lua,se,"attempt to perform arithmetic on a "+Lua.type(o)+" value");
 	}
 }
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/Utils.java
--- a/src/luan/interp/Utils.java	Thu Dec 20 02:54:06 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-package luan.interp;
-
-import luan.Lua;
-import luan.LuaFunction;
-import luan.LuaTable;
-import luan.LuaException;
-
-
-final class Utils {
-	private Utils() {}  // never
-
-	static Object first(Object[] a) {
-		return a.length==0 ? null : a[0];
-	}
-
-}
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/interp/VarArgs.java
--- a/src/luan/interp/VarArgs.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/interp/VarArgs.java	Fri Dec 21 10:45:54 2012 +0000
@@ -1,10 +1,13 @@
 package luan.interp;
 
+import luan.LuaSource;
+
 
-final class VarArgs implements Expressions {
-	static final VarArgs INSTANCE = new VarArgs();
+final class VarArgs extends CodeImpl implements Expressions {
 
-	private VarArgs() {}
+	VarArgs(LuaSource.Element se) {
+		super(se);
+	}
 
 	@Override public Object[] eval(LuaStateImpl lua) {
 		return lua.varArgs();
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/lib/BasicLib.java
--- a/src/luan/lib/BasicLib.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/lib/BasicLib.java	Fri Dec 21 10:45:54 2012 +0000
@@ -15,6 +15,8 @@
 import luan.LuaFunction;
 import luan.LuaJavaFunction;
 import luan.LuaException;
+import luan.LuaSource;
+import luan.LuaElement;
 import luan.interp.LuaCompiler;
 
 
@@ -26,13 +28,13 @@
 		add( global, "do_file", LuaState.class, String.class );
 		add( global, "get_metatable", LuaState.class, Object.class );
 		add( global, "ipairs", LuaTable.class );
-		add( global, "load", LuaState.class, String.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, "raw_equal", Object.class, Object.class );
 		add( global, "raw_get", LuaTable.class, Object.class );
-		add( global, "raw_len", 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, "to_number", Object.class, Integer.class );
@@ -69,7 +71,7 @@
 		for( int i=0; i<args.length; i++ ) {
 			if( i > 0 )
 				System.out.print('\t');
-			System.out.print( lua.toString(args[i]) );
+			System.out.print( lua.toString(LuaElement.JAVA,args[i]) );
 		}
 		System.out.println();
 	}
@@ -78,8 +80,8 @@
 		return Lua.type(obj);
 	}
 
-	public static LuaFunction load(LuaState lua,String ld) throws LuaException {
-		return LuaCompiler.compile(lua,ld);
+	public static LuaFunction load(LuaState lua,String text,String sourceName) throws LuaException {
+		return LuaCompiler.compile(lua,new LuaSource(sourceName,text));
 	}
 
 	public static String readAll(Reader in)
@@ -104,13 +106,18 @@
 	}
 
 
-	public static LuaFunction load_file(LuaState lua,String fileName) throws LuaException,IOException {
-		String src = fileName==null ? readAll(new InputStreamReader(System.in)) : read(new File(fileName));
-		return load(lua,src);
+	public static LuaFunction load_file(LuaState lua,String fileName) throws LuaException {
+		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);
+		}
 	}
 
-	public static Object[] do_file(LuaState lua,String fileName) throws LuaException,IOException {
-		return load_file(lua,fileName).call(lua);
+	public static Object[] do_file(LuaState lua,String fileName) throws LuaException {
+		LuaFunction fn = load_file(lua,fileName);
+		return lua.call(fn,LuaElement.JAVA,null);
 	}
 
 	private static class TableIter {
@@ -197,7 +204,7 @@
 		return table;
 	}
 
-	public static int raw_len(Object v) throws LuaException {
+	public static int raw_len(LuaState lua,Object v) throws LuaException {
 		if( v instanceof String ) {
 			String s = (String)v;
 			return s.length();
@@ -206,7 +213,7 @@
 			LuaTable t = (LuaTable)v;
 			return t.length();
 		}
-		throw new LuaException( "bad argument #1 to 'raw_len' (table or string expected)" );
+		throw new LuaException( lua, LuaElement.JAVA, "bad argument #1 to 'raw_len' (table or string expected)" );
 	}
 
 	public static LuaNumber to_number(Object e,Integer base) {
@@ -214,6 +221,6 @@
 	}
 
 	public static String to_string(LuaState lua,Object v) throws LuaException {
-		return lua.toString(v);
+		return lua.toString(LuaElement.JAVA,v);
 	}
 }
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/lib/JavaLib.java
--- a/src/luan/lib/JavaLib.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/lib/JavaLib.java	Fri Dec 21 10:45:54 2012 +0000
@@ -18,6 +18,7 @@
 import luan.LuaException;
 import luan.LuaFunction;
 import luan.LuaJavaFunction;
+import luan.LuaElement;
 
 
 public final class JavaLib {
@@ -29,17 +30,15 @@
 		global.put("java",module);
 		try {
 			global.put( "import", new LuaJavaFunction(JavaLib.class.getMethod("importClass",LuaState.class,String.class),null) );
-			module.put( "class", new LuaJavaFunction(JavaLib.class.getMethod("getClass",String.class),null) );
+			module.put( "class", new LuaJavaFunction(JavaLib.class.getMethod("getClass",LuaState.class,String.class),null) );
 		} catch(NoSuchMethodException e) {
 			throw new RuntimeException(e);
 		}
-		add( global, "ipairs", Object.class );
-		add( global, "pairs", Object.class );
 	}
 
 	private static final LuaTable mt = new LuaTable();
 	static {
-		add( mt, "__index", Object.class, Object.class );
+		add( mt, "__index", LuaState.class, Object.class, Object.class );
 	}
 
 	private static void add(LuaTable t,String method,Class<?>... parameterTypes) {
@@ -58,7 +57,7 @@
 		}
 	};
 
-	public static Object __index(Object obj,Object key) throws LuaException {
+	public static Object __index(LuaState lua,Object obj,Object key) throws LuaException {
 		if( obj instanceof Static ) {
 			if( key instanceof String ) {
 				String name = (String)key;
@@ -86,7 +85,7 @@
 					}
 				}
 			}
-			throw new LuaException("invalid index for java class: "+key);
+			throw new LuaException(lua,LuaElement.JAVA,"invalid index for java class: "+key);
 		}
 		Class cls = obj.getClass();
 		if( cls.isArray() ) {
@@ -101,7 +100,7 @@
 					return Array.get(obj,i);
 				}
 			}
-			throw new LuaException("invalid index for java array: "+key);
+			throw new LuaException(lua,LuaElement.JAVA,"invalid index for java array: "+key);
 		}
 		if( key instanceof String ) {
 			String name = (String)key;
@@ -114,7 +113,7 @@
 				}
 			}
 		}
-		throw new LuaException("invalid index for java object: "+key);
+		throw new LuaException(lua,LuaElement.JAVA,"invalid index for java object: "+key);
 	}
 
 	private static Object member(Object obj,List<Member> members) throws LuaException {
@@ -192,16 +191,16 @@
 		}
 	}
 
-	public static Static getClass(String name) throws LuaException {
+	public static Static getClass(LuaState lua,String name) throws LuaException {
 		try {
 			return new Static( Class.forName(name) );
 		} catch(ClassNotFoundException e) {
-			throw new LuaException(e);
+			throw new LuaException(lua,LuaElement.JAVA,e);
 		}
 	}
 
 	public static void importClass(LuaState lua,String name) throws LuaException {
-		lua.global().put( name.substring(name.lastIndexOf('.')+1), getClass(name) );
+		lua.global().put( name.substring(name.lastIndexOf('.')+1), getClass(lua,name) );
 	}
 
 	static class AmbiguousJavaFunction extends LuaFunction {
@@ -219,63 +218,16 @@
 			}
 		}
 
-		@Override public Object[] call(LuaState lua,Object... args) throws LuaException {
+		@Override public Object[] call(LuaState lua,Object[] args) throws LuaException {
 			for( LuaJavaFunction fn : fnMap.get(args.length) ) {
 				try {
 					return fn.call(lua,args);
 				} catch(IllegalArgumentException e) {}
 			}
-			throw new LuaException("no method matched args");
+			throw new LuaException(lua,LuaElement.JAVA,"no method matched args");
 		}
 	}
 
-
-	public static LuaFunction pairs(Object t) throws LuaException {
-		if( t instanceof LuaTable )
-			return BasicLib.pairs((LuaTable)t);
-		if( t instanceof Map ) {
-			@SuppressWarnings("unchecked")
-			Map<Object,Object> m = (Map<Object,Object>)t;
-			return BasicLib.pairs(m.entrySet().iterator());
-		}
-		throw new LuaException( "bad argument #1 to 'pairs' (table or Map expected)" );
-	}
-
-	private static class Iter {
-		private final Iterator iter;
-		private double i = 0.0;
-
-		Iter(Iterable t) {
-			this.iter = t.iterator();
-		}
-
-		public Object[] next() {
-			if( !iter.hasNext() )
-				return LuaFunction.EMPTY_RTN ;
-			return new Object[]{ new LuaNumber(i++), iter.next() };
-		}
-	}
-	private static final Method nextIter;
-	static {
-		try {
-			nextIter = Iter.class.getMethod("next");
-			nextIter.setAccessible(true);
-		} catch(NoSuchMethodException e) {
-			throw new RuntimeException(e);
-		}
-	}
-
-	public static LuaFunction ipairs(Object t) throws LuaException {
-		if( t instanceof LuaTable )
-			return BasicLib.ipairs((LuaTable)t);
-		if( t instanceof Iterable ) {
-			Iter ai = new Iter((Iterable)t);
-			return new LuaJavaFunction(nextIter,ai);
-		}
-		throw new LuaException( "bad argument #1 to 'ipairs' (table or Iterable expected)" );
-	}
-
-
 	private static class InstanceOf {
 		private final Object obj;
 
diff -r e5bcb1eeafc1 -r e3624b7cd603 src/luan/tools/CmdLine.java
--- a/src/luan/tools/CmdLine.java	Thu Dec 20 02:54:06 2012 +0000
+++ b/src/luan/tools/CmdLine.java	Fri Dec 21 10:45:54 2012 +0000
@@ -15,10 +15,11 @@
 
 public class CmdLine {
 
-	public static void main(String[] args) throws Exception {
+	public static void main(String[] args) {
 		LuaState lua = LuaCompiler.newLuaState();
 		BasicLib.register(lua);
 		JavaLib.register(lua);
+		BasicLib.make_standard(lua);
 		boolean interactive = false;
 		boolean showVersion = false;
 		int i = 0;
@@ -39,15 +40,15 @@
 						error("'-e' needs argument");
 					String cmd = args[i];
 					try {
-						LuaFunction fn = BasicLib.load(lua,cmd);
-						fn.call(lua);
+						LuaFunction fn = BasicLib.load(lua,cmd,"(command line)");
+						lua.call(fn,null,null);
 					} catch(LuaException e) {
 						System.err.println("command line error: "+e.getMessage());
 						System.exit(-1);
 					}
 				} else if( arg.equals("-") ) {
 					try {
-						BasicLib.do_file(lua,null);
+						BasicLib.do_file(lua,"stdin");
 					} catch(LuaException e) {
 						System.err.println(e.getMessage());
 						System.exit(-1);
@@ -72,10 +73,10 @@
 			lua.global().put("arg",argsTable);
 			try {
 				LuaFunction fn = BasicLib.load_file(lua,file);
-				fn.call(lua,varArgs);
+				lua.call(fn,null,null,varArgs);
 			} catch(LuaException e) {
-//				System.err.println(e.getMessage());
-				e.printStackTrace();
+				System.err.println(e);
+//				e.printStackTrace();
 				System.exit(-1);
 			}
 		}
@@ -102,8 +103,8 @@
 			System.out.print("> ");
 			String input = new Scanner(System.in).nextLine();
 			try {
-				LuaFunction fn = BasicLib.load(lua,input);
-				Object[] rtn = fn.call(lua);
+				LuaFunction fn = BasicLib.load(lua,input,"stdin");
+				Object[] rtn = lua.call(fn,null,null);
 				if( rtn.length > 0 )
 					BasicLib.print(lua,rtn);
 			} catch(LuaException e) {