changeset 19:a7c13c6017f7

add GenericForStmt git-svn-id: https://luan-java.googlecode.com/svn/trunk@20 21e917c8-12df-6dd8-5cb6-c86387c605b9
author fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9>
date Sun, 02 Dec 2012 10:08:24 +0000
parents 3971113699b8
children d85510d92eee
files src/luan/CmdLine.java src/luan/LuaTable.java src/luan/interp/GenericForStmt.java src/luan/interp/LuaParser.java src/luan/interp/SetStmt.java src/luan/lib/BasicLib.java
diffstat 6 files changed, 151 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/src/luan/CmdLine.java	Sun Dec 02 07:00:44 2012 +0000
+++ b/src/luan/CmdLine.java	Sun Dec 02 10:08:24 2012 +0000
@@ -30,7 +30,8 @@
 				LuaFunction fn = BasicLib.loadFile(file);
 				fn.call(lua);
 			} catch(LuaException e) {
-				System.out.println(e.getMessage());
+//				System.out.println(e.getMessage());
+				e.printStackTrace();
 				return;
 			}
 		}
--- a/src/luan/LuaTable.java	Sun Dec 02 07:00:44 2012 +0000
+++ b/src/luan/LuaTable.java	Sun Dec 02 10:08:24 2012 +0000
@@ -5,7 +5,7 @@
 
 
 public class LuaTable {
-	private final Map<Object,Object> map = new HashMap<Object,Object>();
+	public final Map<Object,Object> map = new HashMap<Object,Object>();
 
 	@Override public String toString() {
 		return "table: " + Integer.toHexString(hashCode());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/interp/GenericForStmt.java	Sun Dec 02 10:08:24 2012 +0000
@@ -0,0 +1,42 @@
+package luan.interp;
+
+import luan.Lua;
+import luan.LuaState;
+import luan.LuaException;
+import luan.LuaFunction;
+
+
+final class GenericForStmt 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) {
+		this.iVars = iVars;
+		this.nVars = nVars;
+		this.iterExpr = iterExpr;
+		this.block = block;
+	}
+
+	@Override public void eval(LuaState lua) throws LuaException {
+		LuaFunction iter = Lua.checkFunction( iterExpr.eval(lua) );
+		Object[] stack = lua.stack();
+		try {
+			while(true) {
+				Object[] vals = iter.call(lua);
+				if( vals.length==0 || vals[0]==null )
+					break;
+				for( int i=0; i<nVars; i++ ) {
+					stack[iVars+i] = i < vals.length ? vals[i] : null;
+				}
+				block.eval(lua);
+			}
+		} finally {
+			for( int i=iVars; i<iVars+nVars; i++ ) {
+				stack[i] = null;
+			}
+		}
+	}
+
+}
--- a/src/luan/interp/LuaParser.java	Sun Dec 02 07:00:44 2012 +0000
+++ b/src/luan/interp/LuaParser.java	Sun Dec 02 10:08:24 2012 +0000
@@ -45,13 +45,19 @@
 	int index(String name) {
 		int i = symbols.size();
 		while( --i >= 0 ) {
-System.out.println("index ["+name+"] ["+symbols.get(i)+"] "+symbols.get(i).equals(name));
 			if( symbols.get(i).equals(name) )
 				return i;
 		}
 		return -1;
 	}
 
+	boolean popSymbols(int n) {
+		while( n-- > 0 ) {
+			symbols.remove(symbols.size()-1);
+		}
+		return true;
+	}
+
 	public Rule Target() {
 		return Sequence(
 			Spaces(),
@@ -71,28 +77,27 @@
 
 	Rule Block() {
 		Var<List<Stmt>> stmts = new Var<List<Stmt>>(new ArrayList<Stmt>());
-		Var<Integer> stackCount = new Var<Integer>(0);
+		Var<Integer> stackStart = new Var<Integer>(symbols.size());
 		return Sequence(
-			Optional( Stmt(stmts,stackCount) ),
+			Optional( Stmt(stmts) ),
 			ZeroOrMore(
 				StmtSep(),
-				Optional( Stmt(stmts,stackCount) )
+				Optional( Stmt(stmts) )
 			),
-			push( newBlock(stmts.get(),stackCount.get()) )
+			push( newBlock(stmts.get(),stackStart.get()) )
 		);
 	}
 
-	Stmt newBlock(List<Stmt> stmts,int stackN) {
+	Stmt newBlock(List<Stmt> stmts,int stackStart) {
 		if( stackSize < symbols.size() )
 			stackSize = symbols.size();
-		for( int i=0; i<stackN; i++ ) {
-			symbols.remove(symbols.size()-1);  // pop
-		}
+		int stackEnd = symbols.size();
+		popSymbols( stackEnd - stackStart );
 		if( stmts.isEmpty() )
 			return Stmt.EMPTY;
-		if( stmts.size()==1 && stackN==0 )
+		if( stmts.size()==1 && stackStart==stackEnd )
 			return stmts.get(0);
-		return new Block( stmts.toArray(new Stmt[0]), symbols.size(), symbols.size()+stackN );
+		return new Block( stmts.toArray(new Stmt[0]), stackStart, stackEnd );
 	}
 
 	Rule StmtSep() {
@@ -112,11 +117,12 @@
 		return FirstOf("\r\n", '\r', '\n');
 	}
 
-	Rule Stmt(Var<List<Stmt>> stmts,Var<Integer> stackCount) {
+	Rule Stmt(Var<List<Stmt>> stmts) {
 		return FirstOf(
-			LocalStmt(stmts,stackCount),
+			LocalStmt(stmts),
 			Sequence(
 				FirstOf(
+					GenericForStmt(),
 					NumericForStmt(),
 					DoStmt(),
 					WhileStmt(),
@@ -130,6 +136,15 @@
 		);
 	}
 
+	Rule GenericForStmt() {
+		Var<Integer> stackStart = new Var<Integer>(symbols.size());
+		return Sequence(
+			Keyword("for"), NameList(), Keyword("in"), Expr(), Keyword("do"), Block(), Keyword("end"),
+			push( new GenericForStmt( stackStart.get(), symbols.size() - stackStart.get(), expr(pop(1)), (Stmt)pop() ) ),
+			popSymbols( symbols.size() - stackStart.get() )
+		);
+	}
+
 	Rule NumericForStmt() {
 		return Sequence(
 			Keyword("for"), Name(), '=', Spaces(), Expr(), ',', Spaces(), Expr(),
@@ -142,7 +157,7 @@
 			symbols.add( (String)pop(3) ),  // add "for" var to symbols
 			Keyword("do"), Block(), Keyword("end"),
 			push( new NumericForStmt( symbols.size()-1, expr(pop(3)), expr(pop(2)), expr(pop(1)), (Stmt)pop() ) ),
-			action( symbols.remove(symbols.size()-1) )  // pop
+			popSymbols(1)
 		);
 	}
 
@@ -152,37 +167,33 @@
 		);
 	}
 
-	Rule LocalStmt(Var<List<Stmt>> stmts,Var<Integer> stackCount) {
-		Var<List<String>> names = new Var<List<String>>(new ArrayList<String>());
+	Rule LocalStmt(Var<List<Stmt>> stmts) {
+		Var<Integer> stackStart = new Var<Integer>(symbols.size());
 		return Sequence(
-			Keyword("local"),
-			Name(),
-			newName(names.get(),stackCount),
-			ZeroOrMore(
-				',', Spaces(), Name(),
-				newName(names.get(),stackCount)
-			),
+			Keyword("local"), NameList(),
 			Optional(
-				'=', Spaces(),
-				ExpList(),
-				stmts.get().add( newSetLocalStmt(names.get()) )
+				'=', Spaces(), ExpList(),
+				stmts.get().add( newSetLocalStmt(stackStart.get()) )
 			)
 		);
 	}
 
-	boolean newName(List<String> names,Var<Integer> stackCount) {
-		String name = (String)pop();
-		names.add(name);
-		symbols.add(name);
-		stackCount.set( stackCount.get() + 1 );
-		return true;
+	Rule NameList() {
+		return Sequence(
+			Name(),
+			symbols.add( (String)pop() ),
+			ZeroOrMore(
+				',', Spaces(), Name(),
+				symbols.add( (String)pop() )
+			)
+		);
 	}
 
-	SetStmt newSetLocalStmt(List<String> names) {
+	SetStmt newSetLocalStmt(int stackStart) {
 		Expressions values = (Expressions)pop();
-		SetLocalVar[] vars = new SetLocalVar[names.size()];
+		SetLocalVar[] vars = new SetLocalVar[symbols.size()-stackStart];
 		for( int i=0; i<vars.length; i++ ) {
-			vars[i] = new SetLocalVar(index(names.get(i)));
+			vars[i] = new SetLocalVar(stackStart+i);
 		}
 		return new SetStmt( vars, values );
 	}
--- a/src/luan/interp/SetStmt.java	Sun Dec 02 07:00:44 2012 +0000
+++ b/src/luan/interp/SetStmt.java	Sun Dec 02 10:08:24 2012 +0000
@@ -17,9 +17,8 @@
 	@Override public void eval(LuaState lua) throws LuaException {
 		final Object[] vals = expressions.eval(lua);
 		for( int i=0; i<vars.length; i++ ) {
-			Settable var = vars[i];
 			Object val = i < vals.length ? vals[i] : null;
-			var.set(lua,val);
+			vars[i].set(lua,val);
 		}
 	}
 
--- a/src/luan/lib/BasicLib.java	Sun Dec 02 07:00:44 2012 +0000
+++ b/src/luan/lib/BasicLib.java	Sun Dec 02 10:08:24 2012 +0000
@@ -2,6 +2,9 @@
 
 import java.io.FileReader;
 import java.io.IOException;
+import java.lang.reflect.Method;
+import java.util.Iterator;
+import java.util.Map;
 import org.parboiled.Parboiled;
 import org.parboiled.errors.ErrorUtils;
 import org.parboiled.parserunners.ReportingParseRunner;
@@ -10,6 +13,7 @@
 import luan.Lua;
 import luan.LuaState;
 import luan.LuaTable;
+import luan.LuaNumber;
 import luan.LuaFunction;
 import luan.LuaJavaFunction;
 import luan.LuaException;
@@ -24,6 +28,10 @@
 		LuaTable t = lua.env();
 		add( t, "print", new Object[0].getClass() );
 		add( t, "type", Object.class );
+		add( t, "load", String.class );
+		add( t, "loadFile", String.class );
+		add( t, "pairs", LuaTable.class );
+		add( t, "ipairs", LuaTable.class );
 	}
 
 	private static void add(LuaTable t,String method,Class<?>... parameterTypes) {
@@ -86,4 +94,55 @@
 		return load(readFile(fileName));
 	}
 
+	private static class TableIter {
+		private final Iterator<Map.Entry<Object,Object>> iter;
+
+		TableIter(LuaTable t) {
+			this.iter = t.map.entrySet().iterator();
+		}
+
+		public Object[] next() {
+			if( !iter.hasNext() )
+				return LuaFunction.EMPTY_RTN;
+			Map.Entry<Object,Object> entry = iter.next();
+			return new Object[]{entry.getKey(),entry.getValue()};
+		}
+	}
+
+	public static LuaFunction pairs(LuaTable t) {
+		try {
+			TableIter ti = new TableIter(t);
+			Method m = TableIter.class.getMethod("next");
+			m.setAccessible(true);
+			return new LuaJavaFunction(m,ti);
+		} catch(NoSuchMethodException e) {
+			throw new RuntimeException(e);
+		}
+	}
+
+	private static class ArrayIter {
+		private final LuaTable t;
+		private double i = 0.0;
+
+		ArrayIter(LuaTable t) {
+			this.t = t;
+		}
+
+		public Object[] next() {
+			LuaNumber n = new LuaNumber(++i);
+			Object val = t.get(n);
+			return val==null ? LuaFunction.EMPTY_RTN : new Object[]{n,val};
+		}
+	}
+
+	public static LuaFunction ipairs(LuaTable t) {
+		try {
+			ArrayIter ai = new ArrayIter(t);
+			Method m = ArrayIter.class.getMethod("next");
+			m.setAccessible(true);
+			return new LuaJavaFunction(m,ai);
+		} catch(NoSuchMethodException e) {
+			throw new RuntimeException(e);
+		}
+	}
 }