changeset 44:57054fa43189

implement table lib git-svn-id: https://luan-java.googlecode.com/svn/trunk@45 21e917c8-12df-6dd8-5cb6-c86387c605b9
author fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9>
date Wed, 26 Dec 2012 23:53:25 +0000
parents 80b67b1a653c
children b1b14d09fc98
files src/luan/Lua.java src/luan/LuaException.java src/luan/LuaJavaFunction.java src/luan/LuaNumber.java src/luan/LuaState.java src/luan/LuaTable.java src/luan/interp/AddExpr.java src/luan/interp/DivExpr.java src/luan/interp/LenExpr.java src/luan/interp/LtExpr.java src/luan/interp/LuaParser.java src/luan/interp/LuaStateImpl.java src/luan/interp/ModExpr.java src/luan/interp/MulExpr.java src/luan/interp/NumericForStmt.java src/luan/interp/PowExpr.java src/luan/interp/SubExpr.java src/luan/interp/TableExpr.java src/luan/interp/UnmExpr.java src/luan/lib/BasicLib.java src/luan/lib/JavaLib.java src/luan/lib/LuaRuntimeException.java src/luan/lib/StringLib.java src/luan/lib/TableLib.java src/luan/tools/CmdLine.java
diffstat 25 files changed, 368 insertions(+), 62 deletions(-) [+]
line wrap: on
line diff
--- a/src/luan/Lua.java	Tue Dec 25 03:42:42 2012 +0000
+++ b/src/luan/Lua.java	Wed Dec 26 23:53:25 2012 +0000
@@ -37,9 +37,9 @@
 			String s = (String)obj;
 			try {
 				if( base==null )
-					return new LuaNumber( Double.parseDouble(s) );
+					return LuaNumber.of( Double.parseDouble(s) );
 				else
-					return new LuaNumber( Long.parseLong(s,base) );
+					return LuaNumber.of( Long.parseLong(s,base) );
 			} catch(NumberFormatException e) {}
 		}
 		return null;
--- a/src/luan/LuaException.java	Tue Dec 25 03:42:42 2012 +0000
+++ b/src/luan/LuaException.java	Wed Dec 26 23:53:25 2012 +0000
@@ -25,9 +25,11 @@
 		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();
 		}
--- a/src/luan/LuaJavaFunction.java	Tue Dec 25 03:42:42 2012 +0000
+++ b/src/luan/LuaJavaFunction.java	Wed Dec 26 23:53:25 2012 +0000
@@ -130,7 +130,7 @@
 			if( obj == null )
 				return NULL_RTN;
 			Number n = (Number)obj;
-			LuaNumber ln = new LuaNumber(n.doubleValue());
+			LuaNumber ln = LuaNumber.of(n);
 			return new Object[]{ln};
 		}
 	};
@@ -143,7 +143,7 @@
 			for( int i=0; i<rtn.length; i++ ) {
 				Number n = (Number)Array.get(obj,i);
 				if( n != null )
-					rtn[i] = new LuaNumber(n.doubleValue());
+					rtn[i] = LuaNumber.of(n.doubleValue());
 			}
 			return rtn;
 		}
--- a/src/luan/LuaNumber.java	Tue Dec 25 03:42:42 2012 +0000
+++ b/src/luan/LuaNumber.java	Wed Dec 26 23:53:25 2012 +0000
@@ -4,7 +4,7 @@
 public final class LuaNumber implements Comparable<LuaNumber> {
 	final double n;
 
-	public LuaNumber(double n) {
+	private LuaNumber(double n) {
 		this.n = n;
 	}
 
@@ -43,4 +43,25 @@
 		return Double.compare(n,ln.n);
 	}
 
+	public static LuaNumber of(double n) {
+		return new LuaNumber(n);
+	}
+
+	private static LuaNumber[] ints = new LuaNumber[100];
+	static {
+		for( int i=0; i<ints.length; i++ ) {
+			ints[i] = new LuaNumber(i);
+		}
+	}
+
+	public static LuaNumber of(int n) {
+		if( 0 <= n && n < ints.length )
+			return ints[n];
+		return new LuaNumber(n);
+	}
+
+	public static LuaNumber of(Number n) {
+		return n instanceof Integer ? of(n.intValue()) : of(n.doubleValue());
+	}
+
 }
--- a/src/luan/LuaState.java	Tue Dec 25 03:42:42 2012 +0000
+++ b/src/luan/LuaState.java	Wed Dec 26 23:53:25 2012 +0000
@@ -84,4 +84,28 @@
 		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 LuaNumber && o2 instanceof LuaNumber ) {
+			LuaNumber n1 = (LuaNumber)o1;
+			LuaNumber n2 = (LuaNumber)o2;
+			return n1.compareTo(n2) < 0;
+		}
+		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	Tue Dec 25 03:42:42 2012 +0000
+++ b/src/luan/LuaTable.java	Wed Dec 26 23:53:25 2012 +0000
@@ -1,23 +1,83 @@
 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;
 
 
 public class LuaTable {
-	private final Map<Object,Object> map = new HashMap<Object,Object>();
-	private LuaTable metatable;
+	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;
+	}
 
 	@Override public String toString() {
 		return "table: " + Integer.toHexString(hashCode());
 	}
 
 	public Object get(Object key) {
+		if( list != null && key instanceof LuaNumber ) {
+			LuaNumber ln = (LuaNumber)key;
+			int i = (int)ln.n;
+			if( i == ln.n ) {
+				i--;
+				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) {
+		if( key instanceof LuaNumber ) {
+			LuaNumber ln = (LuaNumber)key;
+			int i = (int)ln.n;
+			if( i == ln.n ) {
+				i--;
+				if( list == null && i == 0 )
+					list = new ArrayList<Object>();
+				if( list != null ) {
+					if( i == list.size() ) {
+						if( val != null ) {
+							list.add(val);
+							if( map != null ) {
+								while(true) {
+									Object v = map.remove(LuaNumber.of(list.size()+1));
+									if( v == null )
+										break;
+									list.add(v);
+								}
+							}
+						}
+						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( val == null ) {
 			return map.remove(key);
 		} else {
@@ -25,16 +85,82 @@
 		}
 	}
 
+	public void insert(int pos,Object value) {
+		if( list == null )
+			list = new ArrayList<Object>();
+		list.add(pos-1,value);
+	}
+
+	public Object remove(int pos) {
+		if( list == null )
+			list = new ArrayList<Object>();
+		return list.remove(pos-1);
+	}
+
+	public void sort(Comparator<Object> cmp) {
+		if( list != null )
+			Collections.sort(list,cmp);
+	}
+
 	public int length() {
-		int i = 0;
-		while( map.containsKey( new LuaNumber(i) ) ) {
-			i++;
-		}
-		return i;
+		return list==null ? 0 : list.size();
 	}
 
 	public Iterator<Map.Entry<Object,Object>> iterator() {
-		return map.entrySet().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() {
+				LuaNumber key = LuaNumber.of(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) {
+		if( list == null )
+			list = new ArrayList<Object>();
+		return new LuaTable(new ArrayList<Object>(list.subList(from-1,to-1)));
 	}
 
 	public LuaTable getMetatable() {
@@ -44,4 +170,26 @@
 	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();
+		}
+	}
 }
--- a/src/luan/interp/AddExpr.java	Tue Dec 25 03:42:42 2012 +0000
+++ b/src/luan/interp/AddExpr.java	Wed Dec 26 23:53:25 2012 +0000
@@ -18,7 +18,7 @@
 		LuaNumber n1 = Lua.toNumber(o1);
 		LuaNumber n2 = Lua.toNumber(o2);
 		if( n1 != null && n2 != null )
-			return new LuaNumber( n1.value() + n2.value() );
+			return LuaNumber.of( n1.value() + n2.value() );
 		return arithmetic(lua,"__add",o1,o2);
 	}
 }
--- a/src/luan/interp/DivExpr.java	Tue Dec 25 03:42:42 2012 +0000
+++ b/src/luan/interp/DivExpr.java	Wed Dec 26 23:53:25 2012 +0000
@@ -18,7 +18,7 @@
 		LuaNumber n1 = Lua.toNumber(o1);
 		LuaNumber n2 = Lua.toNumber(o2);
 		if( n1 != null && n2 != null )
-			return new LuaNumber( n1.value() / n2.value() );
+			return LuaNumber.of( n1.value() / n2.value() );
 		return arithmetic(lua,"__div",o1,o2);
 	}
 }
--- a/src/luan/interp/LenExpr.java	Tue Dec 25 03:42:42 2012 +0000
+++ b/src/luan/interp/LenExpr.java	Wed Dec 26 23:53:25 2012 +0000
@@ -18,7 +18,7 @@
 		Object o = op.eval(lua);
 		if( o instanceof String ) {
 			String s = (String)o;
-			return new LuaNumber( s.length() );
+			return LuaNumber.of( s.length() );
 		}
 		LuaFunction fn = lua.getHandlerFunction(se,"__len",o);
 		if( fn != null )
--- a/src/luan/interp/LtExpr.java	Tue Dec 25 03:42:42 2012 +0000
+++ b/src/luan/interp/LtExpr.java	Wed Dec 26 23:53:25 2012 +0000
@@ -16,19 +16,6 @@
 	@Override public Object eval(LuaStateImpl lua) throws LuaException {
 		Object o1 = op1.eval(lua);
 		Object o2 = op2.eval(lua);
-		if( o1 instanceof LuaNumber && o2 instanceof LuaNumber ) {
-			LuaNumber n1 = (LuaNumber)o1;
-			LuaNumber n2 = (LuaNumber)o2;
-			return n1.compareTo(n2) < 0;
-		}
-		if( o1 instanceof String && o2 instanceof String ) {
-			String s1 = (String)o1;
-			String s2 = (String)o2;
-			return s1.compareTo(s2) < 0;
-		}
-		LuaFunction fn = lua.getBinHandler(se,"__lt",o1,o2);
-		if( fn != null )
-			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) );
+		return lua.isLessThan(se,o1,o2);
 	}
 }
--- a/src/luan/interp/LuaParser.java	Tue Dec 25 03:42:42 2012 +0000
+++ b/src/luan/interp/LuaParser.java	Wed Dec 26 23:53:25 2012 +0000
@@ -304,7 +304,7 @@
 		return Sequence(
 			start.set(currentIndex()),
 			Keyword("for"), Name(), '=', Spaces(), Expr(), Keyword("to"), Expr(),
-			push( new ConstExpr(new LuaNumber(1)) ),  // default step
+			push( new ConstExpr(LuaNumber.of(1)) ),  // default step
 			Optional(
 				Keyword("step"),
 				drop(),
@@ -894,7 +894,7 @@
 	Rule NumberLiteral() {
 		return Sequence(
 			Number(),
-			push(new LuaNumber((Double)pop()))
+			push(LuaNumber.of((Double)pop()))
 		);
 	}
 
--- a/src/luan/interp/LuaStateImpl.java	Tue Dec 25 03:42:42 2012 +0000
+++ b/src/luan/interp/LuaStateImpl.java	Wed Dec 26 23:53:25 2012 +0000
@@ -13,13 +13,6 @@
 
 final class LuaStateImpl extends LuaState {
 
-	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);
-	}
-
 	final Object arithmetic(LuaElement el,String op,Object o1,Object o2) throws LuaException {
 		LuaFunction fn = getBinHandler(el,op,o1,o2);
 		if( fn != null )
--- a/src/luan/interp/ModExpr.java	Tue Dec 25 03:42:42 2012 +0000
+++ b/src/luan/interp/ModExpr.java	Wed Dec 26 23:53:25 2012 +0000
@@ -18,7 +18,7 @@
 		LuaNumber n1 = Lua.toNumber(o1);
 		LuaNumber n2 = Lua.toNumber(o2);
 		if( n1 != null && n2 != null )
-			return new LuaNumber( n1.value() % n2.value() );
+			return LuaNumber.of( n1.value() % n2.value() );
 		return arithmetic(lua,"__mod",o1,o2);
 	}
 }
--- a/src/luan/interp/MulExpr.java	Tue Dec 25 03:42:42 2012 +0000
+++ b/src/luan/interp/MulExpr.java	Wed Dec 26 23:53:25 2012 +0000
@@ -18,7 +18,7 @@
 		LuaNumber n1 = Lua.toNumber(o1);
 		LuaNumber n2 = Lua.toNumber(o2);
 		if( n1 != null && n2 != null )
-			return new LuaNumber( n1.value() * n2.value() );
+			return LuaNumber.of( n1.value() * n2.value() );
 		return arithmetic(lua,"__mul",o1,o2);
 	}
 }
--- a/src/luan/interp/NumericForStmt.java	Tue Dec 25 03:42:42 2012 +0000
+++ b/src/luan/interp/NumericForStmt.java	Wed Dec 26 23:53:25 2012 +0000
@@ -28,7 +28,7 @@
 		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) );
+				lua.stackSet( iVar, LuaNumber.of(v) );
 				block.eval(lua);
 				v += step;
 			}
--- a/src/luan/interp/PowExpr.java	Tue Dec 25 03:42:42 2012 +0000
+++ b/src/luan/interp/PowExpr.java	Wed Dec 26 23:53:25 2012 +0000
@@ -18,7 +18,7 @@
 		LuaNumber n1 = Lua.toNumber(o1);
 		LuaNumber n2 = Lua.toNumber(o2);
 		if( n1 != null && n2 != null )
-			return new LuaNumber( Math.pow( n1.value(), n2.value() ) );
+			return LuaNumber.of( Math.pow( n1.value(), n2.value() ) );
 		return arithmetic(lua,"__pow",o1,o2);
 	}
 }
--- a/src/luan/interp/SubExpr.java	Tue Dec 25 03:42:42 2012 +0000
+++ b/src/luan/interp/SubExpr.java	Wed Dec 26 23:53:25 2012 +0000
@@ -18,7 +18,7 @@
 		LuaNumber n1 = Lua.toNumber(o1);
 		LuaNumber n2 = Lua.toNumber(o2);
 		if( n1 != null && n2 != null )
-			return new LuaNumber( n1.value() - n2.value() );
+			return LuaNumber.of( n1.value() - n2.value() );
 		return arithmetic(lua,"__sub",o1,o2);
 	}
 }
--- a/src/luan/interp/TableExpr.java	Tue Dec 25 03:42:42 2012 +0000
+++ b/src/luan/interp/TableExpr.java	Wed Dec 26 23:53:25 2012 +0000
@@ -34,7 +34,7 @@
 		}
 		Object[] a = expressions.eval(lua);
 		for( int i=0; i<a.length; i++ ) {
-			table.put( new LuaNumber(i+1), a[i] );
+			table.put( LuaNumber.of(i+1), a[i] );
 		}
 		return table;
 	}
--- a/src/luan/interp/UnmExpr.java	Tue Dec 25 03:42:42 2012 +0000
+++ b/src/luan/interp/UnmExpr.java	Wed Dec 26 23:53:25 2012 +0000
@@ -18,7 +18,7 @@
 		Object o = op.eval(lua);
 		LuaNumber n = Lua.toNumber(o);
 		if( n != null )
-			return new LuaNumber( -n.value() );
+			return LuaNumber.of( -n.value() );
 		LuaFunction fn = lua.getHandlerFunction(se,"__unm",o);
 		if( fn != null ) {
 			return Lua.first(lua.call(fn,se,"__unm",o));
--- a/src/luan/lib/BasicLib.java	Tue Dec 25 03:42:42 2012 +0000
+++ b/src/luan/lib/BasicLib.java	Wed Dec 26 23:53:25 2012 +0000
@@ -121,8 +121,7 @@
 		return lua.call(fn,LuaElement.JAVA,null);
 	}
 
-	public static LuaFunction pairs(LuaTable t) {
-		final Iterator<Map.Entry<Object,Object>> iter = t.iterator();
+	private static LuaFunction pairs(final Iterator<Map.Entry<Object,Object>> iter) {
 		return new LuaFunction() {
 			public Object[] call(LuaState lua,Object[] args) {
 				if( !iter.hasNext() )
@@ -133,15 +132,12 @@
 		};
 	}
 
-	public static LuaFunction ipairs(final LuaTable t) {
-		return new LuaFunction() {
-			private double i = 0.0;
-			public Object[] call(LuaState lua,Object[] args) {
-				LuaNumber n = new LuaNumber(++i);
-				Object val = t.get(n);
-				return val==null ? LuaFunction.EMPTY_RTN : new Object[]{n,val};
-			}
-		};
+	public static LuaFunction pairs(LuaTable t) {
+		return pairs( t.iterator() );
+	}
+
+	public static LuaFunction ipairs(LuaTable t) {
+		return pairs( t.listIterator() );
 	}
 
 	public static LuaTable get_metatable(LuaState lua,Object obj) {
--- a/src/luan/lib/JavaLib.java	Tue Dec 25 03:42:42 2012 +0000
+++ b/src/luan/lib/JavaLib.java	Wed Dec 26 23:53:25 2012 +0000
@@ -125,7 +125,7 @@
 					Object value = field.get(obj);
 					if( value instanceof Number ) {
 						Number n = (Number)value;
-						value = new LuaNumber(n.doubleValue());
+						value = LuaNumber.of(n);
 					}
 					return value;
 				} else {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/lib/LuaRuntimeException.java	Wed Dec 26 23:53:25 2012 +0000
@@ -0,0 +1,10 @@
+package luan.lib;
+
+import luan.LuaException;
+
+
+public final class LuaRuntimeException extends RuntimeException {
+	public LuaRuntimeException(LuaException e) {
+		super(e);
+	}
+}
--- a/src/luan/lib/StringLib.java	Tue Dec 25 03:42:42 2012 +0000
+++ b/src/luan/lib/StringLib.java	Wed Dec 26 23:53:25 2012 +0000
@@ -157,7 +157,7 @@
 				i++;
 			}
 			m.appendTail(sb);
-			return new Object[]{ sb.toString(), new LuaNumber(i) };
+			return new Object[]{ sb.toString(), LuaNumber.of(i) };
 		}
 		if( repl instanceof LuaTable ) {
 			LuaTable t = (LuaTable)repl;
@@ -175,7 +175,7 @@
 				i++;
 			}
 			m.appendTail(sb);
-			return new Object[]{ sb.toString(), new LuaNumber(i) };
+			return new Object[]{ sb.toString(), LuaNumber.of(i) };
 		}
 		if( repl instanceof LuaFunction ) {
 			LuaFunction fn = (LuaFunction)repl;
@@ -202,7 +202,7 @@
 				i++;
 			}
 			m.appendTail(sb);
-			return new Object[]{ sb.toString(), new LuaNumber(i) };
+			return new Object[]{ sb.toString(), LuaNumber.of(i) };
 		}
 		throw new LuaException( lua, LuaElement.JAVA, "bad argument #3 to 'gsub' (string/function/table expected)" );
 	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/lib/TableLib.java	Wed Dec 26 23:53:25 2012 +0000
@@ -0,0 +1,123 @@
+package luan.lib;
+
+import java.util.Comparator;
+import java.util.ArrayList;
+import java.util.Arrays;
+import luan.Lua;
+import luan.LuaState;
+import luan.LuaTable;
+import luan.LuaNumber;
+import luan.LuaFunction;
+import luan.LuaJavaFunction;
+import luan.LuaElement;
+import luan.LuaException;
+
+
+public final class TableLib {
+
+	public static void register(LuaState lua) {
+		LuaTable module = new LuaTable();
+		LuaTable 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, "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 );
+		} 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) );
+	}
+
+	public static String concat(LuaState lua,LuaTable list,String sep,Integer i,Integer j) throws LuaException {
+		int first = i==null ? 1 : i;
+		int last = j==null ? list.length() : j;
+		StringBuilder buf = new StringBuilder();
+		for( int k=first; k<=last; k++ ) {
+			Object val = list.get(LuaNumber.of(k));
+			if( val==null )
+				break;
+			if( sep!=null && k > first )
+				buf.append(sep);
+			String s = Lua.asString(val);
+			if( s==null )
+				throw new LuaException( lua, LuaElement.JAVA, "invalid value ("+Lua.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 {
+		try {
+			list.insert(pos,value);
+		} catch(IndexOutOfBoundsException e) {
+			throw new LuaException( lua, LuaElement.JAVA, e);
+		}
+	}
+
+	public static Object remove(LuaState lua,LuaTable list,int pos) throws LuaException {
+		try {
+			return list.remove(pos);
+		} catch(IndexOutOfBoundsException e) {
+			throw new LuaException( lua, LuaElement.JAVA, e);
+		}
+	}
+
+	private static interface LessThan {
+		public boolean isLessThan(Object o1,Object o2);
+	}
+
+	public static void sort(final LuaState lua,LuaTable list,final LuaFunction comp) throws LuaException {
+		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);
+					}
+				}
+			};
+		} else {
+			lt = new LessThan() {
+				public boolean isLessThan(Object o1,Object o2) {
+					try {
+						return Lua.toBoolean(lua.call(comp,LuaElement.JAVA,"comp-arg",o1,o2));
+					} catch(LuaException e) {
+						throw new LuaRuntimeException(e);
+					}
+				}
+			};
+		}
+		try {
+			list.sort( new Comparator<Object>() {
+				public int compare(Object o1,Object o2) {
+					return lt.isLessThan(o1,o2) ? -1 : lt.isLessThan(o2,o1) ? 1 : 0;
+				}
+			} );
+		} catch(LuaRuntimeException e) {
+			throw (LuaException)e.getCause();
+		}
+	}
+
+	public static LuaTable pack(Object[] args) {
+		return new LuaTable(new ArrayList<Object>(Arrays.asList(args)));
+	}
+
+	public static Object[] unpack(LuaTable list) {
+		return list.listToArray();
+	}
+
+	public static LuaTable sub_list(LuaTable list,int from,int to) {
+		return list.subList(from,to);
+	}
+
+}
--- a/src/luan/tools/CmdLine.java	Tue Dec 25 03:42:42 2012 +0000
+++ b/src/luan/tools/CmdLine.java	Wed Dec 26 23:53:25 2012 +0000
@@ -5,6 +5,7 @@
 import luan.lib.BasicLib;
 import luan.lib.JavaLib;
 import luan.lib.StringLib;
+import luan.lib.TableLib;
 import luan.Lua;
 import luan.LuaState;
 import luan.LuaFunction;
@@ -21,6 +22,7 @@
 		BasicLib.register(lua);
 		JavaLib.register(lua);
 		StringLib.register(lua);
+		TableLib.register(lua);
 		BasicLib.make_standard(lua);
 		boolean interactive = false;
 		boolean showVersion = false;
@@ -70,7 +72,7 @@
 			System.arraycopy(args,1,varArgs,0,varArgs.length);
 			LuaTable argsTable = new LuaTable();
 			for( int j=0; j<args.length; j++ ) {
-				argsTable.put( new LuaNumber(j), args[j] );
+				argsTable.put( LuaNumber.of(j), args[j] );
 			}
 			lua.global().put("arg",argsTable);
 			try {