changeset 11:b7d7069fee58

add assignment statement and CmdLine git-svn-id: https://luan-java.googlecode.com/svn/trunk@12 21e917c8-12df-6dd8-5cb6-c86387c605b9
author fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9>
date Thu, 22 Nov 2012 10:51:56 +0000
parents 8217d8485715
children 9cea1aea5eef
files src/luan/CmdLine.java src/luan/interp/AddExpr.java src/luan/interp/AndExpr.java src/luan/interp/BinaryOpExpr.java src/luan/interp/Block.java src/luan/interp/ConcatExpr.java src/luan/interp/ConstExpr.java src/luan/interp/DivExpr.java src/luan/interp/EnvExpr.java src/luan/interp/EqExpr.java src/luan/interp/ExpList.java src/luan/interp/Expr.java src/luan/interp/Expressions.java src/luan/interp/ExpressionsExpr.java src/luan/interp/ExpressionsStmt.java src/luan/interp/FnCall.java src/luan/interp/GetExpr.java src/luan/interp/LeExpr.java src/luan/interp/LenExpr.java src/luan/interp/LtExpr.java src/luan/interp/LuaParser.java src/luan/interp/ModExpr.java src/luan/interp/MulExpr.java src/luan/interp/NotExpr.java src/luan/interp/OrExpr.java src/luan/interp/PowExpr.java src/luan/interp/SetStmt.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/Values.java src/luan/interp/ValuesExpr.java src/luan/interp/ValuesStmt.java
diffstat 35 files changed, 308 insertions(+), 143 deletions(-) [+]
line wrap: on
line diff
diff -r 8217d8485715 -r b7d7069fee58 src/luan/CmdLine.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/CmdLine.java	Thu Nov 22 10:51:56 2012 +0000
@@ -0,0 +1,40 @@
+package luan;
+
+import java.util.List;
+import java.util.Scanner;
+import org.parboiled.Parboiled;
+import org.parboiled.errors.ErrorUtils;
+import org.parboiled.parserunners.ReportingParseRunner;
+import org.parboiled.support.ParsingResult;
+import luan.interp.Expressions;
+import luan.interp.Stmt;
+import luan.interp.LuaParser;
+import luan.lib.BasicLib;
+
+
+public class CmdLine {
+
+	public static void main(String[] args) throws Exception {
+		LuaParser parser = Parboiled.createParser(LuaParser.class);
+		LuaState lua = new LuaState();
+		while( true ) {
+			System.out.print("> ");
+			String input = new Scanner(System.in).nextLine();
+			ParsingResult<?> result = new ReportingParseRunner(parser.Target()).run(input);
+			if( result.hasErrors() ) {
+				System.out.println("Parse Errors:\n" + ErrorUtils.printParseErrors(result));
+			} else {
+				Object resultValue = result.resultValue;
+				if( resultValue instanceof Expressions ) {
+					Expressions expressions = (Expressions)resultValue;
+					List vals = expressions.eval(lua);
+					if( !vals.isEmpty() )
+						BasicLib.print( vals.toArray() );
+				} else {
+					Stmt stmt = (Stmt)resultValue;
+					stmt.eval(lua);
+				}
+			}
+		}
+	}
+}
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/AddExpr.java
--- a/src/luan/interp/AddExpr.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/AddExpr.java	Thu Nov 22 10:51:56 2012 +0000
@@ -12,7 +12,7 @@
 		super(op1,op2);
 	}
 
-	@Override Object eval(LuaState lua) throws LuaException {
+	@Override public Object eval(LuaState lua) throws LuaException {
 		double n1 = Lua.checkNumber(op1.eval(lua)).value();
 		double n2 = Lua.checkNumber(op2.eval(lua)).value();
 		return new LuaNumber( n1 + n2 );
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/AndExpr.java
--- a/src/luan/interp/AndExpr.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/AndExpr.java	Thu Nov 22 10:51:56 2012 +0000
@@ -11,7 +11,7 @@
 		super(op1,op2);
 	}
 
-	@Override Object eval(LuaState lua) throws LuaException {
+	@Override public Object eval(LuaState lua) throws LuaException {
 		Object v1 = op1.eval(lua);
 		return !Lua.toBoolean(v1) ? v1 : op2.eval(lua);
 	}
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/BinaryOpExpr.java
--- a/src/luan/interp/BinaryOpExpr.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/BinaryOpExpr.java	Thu Nov 22 10:51:56 2012 +0000
@@ -1,7 +1,7 @@
 package luan.interp;
 
 
-abstract class BinaryOpExpr extends Expr {
+abstract class BinaryOpExpr implements Expr {
 	final Expr op1;
 	final Expr op2;
 
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/Block.java
--- a/src/luan/interp/Block.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/Block.java	Thu Nov 22 10:51:56 2012 +0000
@@ -4,14 +4,14 @@
 import luan.LuaException;
 
 
-final class Block extends Stmt {
+final class Block implements Stmt {
 	private final Stmt[] stmts;
 
 	Block(Stmt[] stmts) {
 		this.stmts = stmts;
 	}
 
-	@Override void eval(LuaState lua) throws LuaException {
+	@Override public void eval(LuaState lua) throws LuaException {
 		for( Stmt stmt : stmts ) {
 			stmt.eval(lua);
 		}
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/ConcatExpr.java
--- a/src/luan/interp/ConcatExpr.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/ConcatExpr.java	Thu Nov 22 10:51:56 2012 +0000
@@ -12,7 +12,7 @@
 		super(op1,op2);
 	}
 
-	@Override Object eval(LuaState lua) throws LuaException {
+	@Override public Object eval(LuaState lua) throws LuaException {
 		return toString(op1.eval(lua)) + toString(op2.eval(lua));
 	}
 
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/ConstExpr.java
--- a/src/luan/interp/ConstExpr.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/ConstExpr.java	Thu Nov 22 10:51:56 2012 +0000
@@ -3,14 +3,14 @@
 import luan.LuaState;
 
 
-final class ConstExpr extends Expr {
+final class ConstExpr implements Expr {
 	private final Object obj;
 
 	ConstExpr(Object obj) {
 		this.obj = obj;
 	}
 
-	@Override Object eval(LuaState lua) {
+	@Override public Object eval(LuaState lua) {
 		return obj;
 	}
 }
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/DivExpr.java
--- a/src/luan/interp/DivExpr.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/DivExpr.java	Thu Nov 22 10:51:56 2012 +0000
@@ -12,7 +12,7 @@
 		super(op1,op2);
 	}
 
-	@Override Object eval(LuaState lua) throws LuaException {
+	@Override public Object eval(LuaState lua) throws LuaException {
 		double n1 = Lua.checkNumber(op1.eval(lua)).value();
 		double n2 = Lua.checkNumber(op2.eval(lua)).value();
 		return new LuaNumber( n1 / n2 );
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/EnvExpr.java
--- a/src/luan/interp/EnvExpr.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/EnvExpr.java	Thu Nov 22 10:51:56 2012 +0000
@@ -3,12 +3,12 @@
 import luan.LuaState;
 
 
-final class EnvExpr extends Expr {
+final class EnvExpr implements Expr {
 	static final EnvExpr INSTANCE = new EnvExpr();
 
 	private EnvExpr() {}
 
-	@Override Object eval(LuaState lua) {
+	@Override public Object eval(LuaState lua) {
 		return lua.env();
 	}
 }
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/EqExpr.java
--- a/src/luan/interp/EqExpr.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/EqExpr.java	Thu Nov 22 10:51:56 2012 +0000
@@ -12,7 +12,7 @@
 		super(op1,op2);
 	}
 
-	@Override Object eval(LuaState lua) throws LuaException {
+	@Override public Object eval(LuaState lua) throws LuaException {
 		Object v1 = op1.eval(lua);
 		Object v2 = op2.eval(lua);
 		return v1 == v2 || v1 != null && v1.equals(v2);
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/ExpList.java
--- a/src/luan/interp/ExpList.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/ExpList.java	Thu Nov 22 10:51:56 2012 +0000
@@ -7,7 +7,7 @@
 import luan.LuaState;
 
 
-final class ExpList extends Values {
+final class ExpList implements Expressions {
 
 	private interface Adder {
 		public void addTo(LuaState lua,List<Object> list) throws LuaException;
@@ -26,15 +26,15 @@
 
 	}
 
-	private static class ValuesAdder implements Adder {
-		private final Values values;
+	private static class ExpressionsAdder implements Adder {
+		private final Expressions expressions;
 
-		ValuesAdder(Values values) {
-			this.values = values;
+		ExpressionsAdder(Expressions expressions) {
+			this.expressions = expressions;
 		}
 
 		public void addTo(LuaState lua,List<Object> list) throws LuaException {
-			for( Object val : values.eval(lua) ) {
+			for( Object val : expressions.eval(lua) ) {
 				list.add( val );
 			}
 		}
@@ -48,18 +48,18 @@
 			adders.add( new ExprAdder(expr) );
 		}
 
-		void add(Values values) {
-			adders.add( new ValuesAdder(values) );
+		void add(Expressions expressions) {
+			adders.add( new ExpressionsAdder(expressions) );
 		}
 
-		Values build() {
+		Expressions build() {
 			if( adders.isEmpty() )
 				return emptyExpList;
 			if( adders.size() == 1 ) {
 				Adder adder = adders.get(0);
-				if( adder instanceof ValuesAdder ) {
-					ValuesAdder va = (ValuesAdder)adder;
-					return va.values;
+				if( adder instanceof ExpressionsAdder ) {
+					ExpressionsAdder ea = (ExpressionsAdder)adder;
+					return ea.expressions;
 				}
 				ExprAdder ea = (ExprAdder)adder;
 				return new SingleExpList(ea.expr);
@@ -68,20 +68,20 @@
 		}
 	}
 
-	private static final Values emptyExpList = new Values() {
-		List eval(LuaState lua) {
+	static final Expressions emptyExpList = new Expressions() {
+		@Override public List eval(LuaState lua) {
 			return Collections.emptyList();
 		}
 	};
 
-	private static class SingleExpList extends Values {
+	static class SingleExpList implements Expressions {
 		private final Expr expr;
 
 		SingleExpList(Expr expr) {
 			this.expr = expr;
 		}
 
-		List eval(LuaState lua) throws LuaException {
+		@Override public List eval(LuaState lua) throws LuaException {
 			return Collections.singletonList( expr.eval(lua) );
 		}
 	}
@@ -92,7 +92,7 @@
 		this.adders = adders;
 	}
 
-	List eval(LuaState lua) throws LuaException {
+	@Override public List eval(LuaState lua) throws LuaException {
 		List<Object> list = new ArrayList<Object>();
 		for( Adder adder : adders ) {
 			adder.addTo(lua,list);
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/Expr.java
--- a/src/luan/interp/Expr.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/Expr.java	Thu Nov 22 10:51:56 2012 +0000
@@ -4,6 +4,6 @@
 import luan.LuaException;
 
 
-abstract class Expr {
-	abstract Object eval(LuaState lua) throws LuaException;
+interface Expr {
+	public Object eval(LuaState lua) throws LuaException;
 }
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/Expressions.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/interp/Expressions.java	Thu Nov 22 10:51:56 2012 +0000
@@ -0,0 +1,10 @@
+package luan.interp;
+
+import java.util.List;
+import luan.LuaException;
+import luan.LuaState;
+
+
+public interface Expressions {
+	public List eval(LuaState lua) throws LuaException;
+}
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/ExpressionsExpr.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/interp/ExpressionsExpr.java	Thu Nov 22 10:51:56 2012 +0000
@@ -0,0 +1,20 @@
+package luan.interp;
+
+import java.util.List;
+import luan.Lua;
+import luan.LuaException;
+import luan.LuaState;
+
+
+final class ExpressionsExpr implements Expr {
+	private final Expressions expressions;
+
+	ExpressionsExpr(Expressions expressions) {
+		this.expressions = expressions;
+	}
+
+	@Override public Object eval(LuaState lua) throws LuaException {
+		List list = expressions.eval(lua);
+		return list.isEmpty() ? null : list.get(0);
+	}
+}
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/ExpressionsStmt.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/interp/ExpressionsStmt.java	Thu Nov 22 10:51:56 2012 +0000
@@ -0,0 +1,18 @@
+package luan.interp;
+
+import luan.LuaState;
+import luan.LuaException;
+
+
+final class ExpressionsStmt implements Stmt {
+	private final Expressions expressions;
+
+	ExpressionsStmt(Expressions expressions) {
+		this.expressions = expressions;
+	}
+
+	@Override public void eval(LuaState lua) throws LuaException {
+		expressions.eval(lua);
+	}
+
+}
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/FnCall.java
--- a/src/luan/interp/FnCall.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/FnCall.java	Thu Nov 22 10:51:56 2012 +0000
@@ -8,16 +8,16 @@
 import luan.LuaState;
 
 
-final class FnCall extends Values {
+final class FnCall implements Expressions {
 	private final Expr fnExpr;
-	private final Values args;
+	private final Expressions args;
 
-	FnCall(Expr fnExpr,Values args) {
+	FnCall(Expr fnExpr,Expressions args) {
 		this.fnExpr = fnExpr;
 		this.args = args;
 	}
 
-	List eval(LuaState lua) throws LuaException {
+	@Override public List eval(LuaState lua) throws LuaException {
 		LuaFunction fn = Lua.checkFunction( fnExpr.eval(lua) );
 		return Arrays.asList( fn.call( args.eval(lua).toArray() ) );
 	}
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/GetExpr.java
--- a/src/luan/interp/GetExpr.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/GetExpr.java	Thu Nov 22 10:51:56 2012 +0000
@@ -12,7 +12,7 @@
 		super(op1,op2);
 	}
 
-	@Override Object eval(LuaState lua) throws LuaException {
+	@Override public Object eval(LuaState lua) throws LuaException {
 		Object t = op1.eval(lua);
 		if( t instanceof LuaTable ) {
 			LuaTable tbl = (LuaTable)t;
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/LeExpr.java
--- a/src/luan/interp/LeExpr.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/LeExpr.java	Thu Nov 22 10:51:56 2012 +0000
@@ -12,7 +12,7 @@
 		super(op1,op2);
 	}
 
-	@Override Object eval(LuaState lua) throws LuaException {
+	@Override public Object eval(LuaState lua) throws LuaException {
 		Object v1 = op1.eval(lua);
 		Object v2 = op2.eval(lua);
 		if( v1 instanceof LuaNumber && v2 instanceof LuaNumber ) {
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/LenExpr.java
--- a/src/luan/interp/LenExpr.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/LenExpr.java	Thu Nov 22 10:51:56 2012 +0000
@@ -13,7 +13,7 @@
 		super(op);
 	}
 
-	@Override Object eval(LuaState lua) throws LuaException {
+	@Override public Object eval(LuaState lua) throws LuaException {
 		return new LuaNumber( length(op.eval(lua)) );
 	}
 
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/LtExpr.java
--- a/src/luan/interp/LtExpr.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/LtExpr.java	Thu Nov 22 10:51:56 2012 +0000
@@ -12,7 +12,7 @@
 		super(op1,op2);
 	}
 
-	@Override Object eval(LuaState lua) throws LuaException {
+	@Override public Object eval(LuaState lua) throws LuaException {
 		Object v1 = op1.eval(lua);
 		Object v2 = op2.eval(lua);
 		if( v1 instanceof LuaNumber && v2 instanceof LuaNumber ) {
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/LuaParser.java
--- a/src/luan/interp/LuaParser.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/LuaParser.java	Thu Nov 22 10:51:56 2012 +0000
@@ -16,8 +16,58 @@
 
 public class LuaParser extends BaseParser<Object> {
 
-	Rule Target() {
-		return Sequence(Spaces(), Expr(), EOI);
+	public Rule Target() {
+		return Sequence(
+			Spaces(),
+			FirstOf(
+				Sequence( Expressions(), EOI ),
+				Sequence( Stmt(), EOI )
+			)
+		);
+	}
+
+	Rule Stmt() {
+		return SetStmt();
+	}
+
+	Rule SetStmt() {
+		return Sequence(
+			VarList(),
+			'=', Spaces(),
+			ExpList(),
+			push( newSetStmt() )
+		);
+	}
+
+	SetStmt newSetStmt() {
+		Expressions values = (Expressions)pop();
+		@SuppressWarnings("unchecked")
+		List<SetStmt.Var> vars = (List<SetStmt.Var>)pop();
+		return new SetStmt( vars.toArray(new SetStmt.Var[0]), values );
+	}
+
+	Rule VarList() {
+		return Sequence(
+			push(new ArrayList<SetStmt.Var>()),
+			Var(),
+			addToVarList(),
+			ZeroOrMore(
+				',', Spaces(), Var(),
+				addToVarList()
+			)
+		);
+	}
+
+	boolean addToVarList() {
+		Object obj = pop();
+		if( obj==null )
+			return false;
+		Expr key = expr(obj);
+		Expr table = expr(pop());
+		@SuppressWarnings("unchecked")
+		List<SetStmt.Var> vars = (List<SetStmt.Var>)peek();
+		vars.add( new SetStmt.Var(table,key) );
+		return true;
 	}
 
 	Rule Expr() {
@@ -27,14 +77,14 @@
 	Rule OrExpr() {
 		return Sequence(
 			AndExpr(),
-			ZeroOrMore( "or", Spaces(), AndExpr(), push( new OrExpr((Expr)pop(1),(Expr)pop()) ) )
+			ZeroOrMore( "or", Spaces(), AndExpr(), push( new OrExpr(expr(pop(1)),expr(pop())) ) )
 		);
 	}
 
 	Rule AndExpr() {
 		return Sequence(
 			RelExpr(),
-			ZeroOrMore( "and", Spaces(), RelExpr(), push( new AndExpr((Expr)pop(1),(Expr)pop()) ) )
+			ZeroOrMore( "and", Spaces(), RelExpr(), push( new AndExpr(expr(pop(1)),expr(pop())) ) )
 		);
 	}
 
@@ -43,12 +93,12 @@
 			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(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())) ) )
 				)
 			)
 		);
@@ -57,7 +107,7 @@
 	Rule ConcatExpr() {
 		return Sequence(
 			SumExpr(),
-			Optional( "..", Spaces(), ConcatExpr(), push( new ConcatExpr((Expr)pop(1),(Expr)pop()) ) )
+			Optional( "..", Spaces(), ConcatExpr(), push( new ConcatExpr(expr(pop(1)),expr(pop())) ) )
 		);
 	}
 
@@ -66,8 +116,8 @@
 			TermExpr(),
 			ZeroOrMore(
 				FirstOf(
-					Sequence( '+', Spaces(), TermExpr(), push( new AddExpr((Expr)pop(1),(Expr)pop()) ) ),
-					Sequence( '-', Spaces(), TermExpr(), push( new SubExpr((Expr)pop(1),(Expr)pop()) ) )
+					Sequence( '+', Spaces(), TermExpr(), push( new AddExpr(expr(pop(1)),expr(pop())) ) ),
+					Sequence( '-', Spaces(), TermExpr(), push( new SubExpr(expr(pop(1)),expr(pop())) ) )
 				)
 			)
 		);
@@ -78,9 +128,9 @@
 			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(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())) ) )
 				)
 			)
 		);
@@ -88,9 +138,9 @@
 
 	Rule UnaryExpr() {
 		return FirstOf(
-			Sequence( '#', Spaces(), PowExpr(), push( new LenExpr((Expr)pop()) ) ),
-			Sequence( '-', Spaces(), PowExpr(), push( new UnmExpr((Expr)pop()) ) ),
-			Sequence( "not", Spaces(), PowExpr(), push( new NotExpr((Expr)pop()) ) ),
+			Sequence( '#', Spaces(), PowExpr(), push( new LenExpr(expr(pop())) ) ),
+			Sequence( '-', Spaces(), PowExpr(), push( new UnmExpr(expr(pop())) ) ),
+			Sequence( "not", Spaces(), PowExpr(), push( new NotExpr(expr(pop())) ) ),
 			PowExpr()
 		);
 	}
@@ -98,14 +148,14 @@
 	Rule PowExpr() {
 		return Sequence(
 			SingleExpr(),
-			Optional( '^', Spaces(), PowExpr(), push( new PowExpr((Expr)pop(1),(Expr)pop()) ) )
+			Optional( '^', Spaces(), PowExpr(), push( new PowExpr(expr(pop(1)),expr(pop())) ) )
 		);
 	}
 
 	Rule SingleExpr() {
 		return FirstOf(
 			TableExpr(),
-			PrefixExpr(),
+			VarExp(),
 			LiteralExpr()
 		);
 	}
@@ -154,7 +204,7 @@
 	}
 
 	boolean addField() {
-		TableExpr.Field field = new TableExpr.Field( (Expr)pop(1), (Expr)pop() );
+		TableExpr.Field field = new TableExpr.Field( expr(pop(1)), expr(pop()) );
 		@SuppressWarnings("unchecked")
 		List<TableExpr.Field> list = (List<TableExpr.Field>)peek(1);
 		list.add(field);
@@ -162,7 +212,7 @@
 	}
 
 	boolean addIndexedField() {
-		Expr val = (Expr)pop();
+		Expr val = expr(pop());
 		double i = (Double)pop();
 		TableExpr.Field field = new TableExpr.Field( new ConstExpr(new LuaNumber(i)), val );
 		push( i + 1 );
@@ -172,33 +222,108 @@
 		return true;
 	}
 
-	Rule PrefixExpr() {
+	static Expr expr(Object obj) {
+		if( obj instanceof Expressions )
+			return new ExpressionsExpr((Expressions)obj);
+		return (Expr)obj;
+	}
+
+	Rule VarExp() {
+		return Sequence(
+			Var(),
+			makeVarExp()
+		);
+	}
+
+	Rule Var() {
 		return Sequence(
 			FirstOf(
-				Sequence( '(', Spaces(), Expr(), ')', Spaces() ),
-				Var()
+				Sequence(
+					'(', Spaces(), Expr(), ')', Spaces(),
+					push(expr(pop())),
+					push(null)  // marker
+				),
+				Sequence(
+					push(EnvExpr.INSTANCE),
+					Name()
+				)
 			),
 			ZeroOrMore(
+				makeVarExp(),
 				FirstOf(
 					SubExpr(),
-					Sequence( '.', Spaces(), Name() )
-				),
-				push( new GetExpr( (Expr)pop(1), (Expr)pop() ) )
+					Sequence( '.', Spaces(), Name() ),
+					Sequence(
+						Args(),
+						push(null)  // marker
+					)
+				)
 			)
 		);
 	}
 
-	Rule SubExpr() {
-		return Sequence( '[', Spaces(), Expr(), ']', Spaces() );
+	boolean makeVarExp() {
+		Object obj = pop();
+		if( obj==null )
+			return true;
+		return push( new GetExpr( expr(pop()), expr(obj) ) );
+	}
+
+	// function should be on top of the stack
+	Rule Args() {
+		return Sequence(
+			FirstOf(
+				Sequence(
+					'(', Spaces(), Expressions(), ')', Spaces()
+				),
+				Sequence(
+					TableExpr(),
+					push( new ExpList.SingleExpList(expr(pop())) )
+				),
+				Sequence(
+					StringLiteral(), Spaces(),
+					push( new ExpList.SingleExpList(new ConstExpr(pop())) )
+				)
+			),
+			push( new FnCall( expr(pop(1)), (Expressions)pop() ) )
+		);
 	}
 
-	Rule Var() {
+	Rule Expressions() {
+		return FirstOf(
+			ExpList(),
+			push( ExpList.emptyExpList )
+		);
+	}
+
+	Rule ExpList() {
 		return Sequence(
-			Name(),
-			push( new GetExpr( EnvExpr.INSTANCE, (Expr)pop() ) )
+			push(new ExpList.Builder()),
+			Expr(),
+			addToExpList(),
+			ZeroOrMore(
+				',', Spaces(), Expr(),
+				addToExpList()
+			),
+			push( ((ExpList.Builder)pop()).build() )
 		);
 	}
 
+	boolean addToExpList() {
+		Object obj = pop();
+		ExpList.Builder bld = (ExpList.Builder)peek();
+		if( obj instanceof Expressions ) {
+			bld.add( (Expressions)obj );
+		} else {
+			bld.add( (Expr)obj );
+		}
+		return true;
+	}
+
+	Rule SubExpr() {
+		return Sequence( '[', Spaces(), Expr(), ']', Spaces() );
+	}
+
 	Rule Name() {
 		return Sequence(
 			Sequence(
@@ -273,13 +398,13 @@
 			Sequence(
 				Int(),
 				Optional( '.', Optional(Int()) ),
-				NumberExp()
+				Exponent()
 			),
-			Sequence( '.', Int(), NumberExp() )
+			Sequence( '.', Int(), Exponent() )
 		);
 	}
 
-	Rule NumberExp() {
+	Rule Exponent() {
 		return Optional(
 			IgnoreCase('e'),
 			Optional(AnyOf("+-")),
@@ -381,7 +506,7 @@
 			if( result.hasErrors() ) {
 				System.out.println("Parse Errors:\n" + ErrorUtils.printParseErrors(result));
 			} else {
-				Expr expr = (Expr)result.resultValue;
+				Expr expr = expr(result.resultValue);
 				LuaState lua = new LuaState();
 				Object val = expr.eval(lua);
 				System.out.println("Result: "+Lua.toString(val));
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/ModExpr.java
--- a/src/luan/interp/ModExpr.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/ModExpr.java	Thu Nov 22 10:51:56 2012 +0000
@@ -12,7 +12,7 @@
 		super(op1,op2);
 	}
 
-	@Override Object eval(LuaState lua) throws LuaException {
+	@Override public Object eval(LuaState lua) throws LuaException {
 		double n1 = Lua.checkNumber(op1.eval(lua)).value();
 		double n2 = Lua.checkNumber(op2.eval(lua)).value();
 		return new LuaNumber( n1 % n2 );
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/MulExpr.java
--- a/src/luan/interp/MulExpr.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/MulExpr.java	Thu Nov 22 10:51:56 2012 +0000
@@ -12,7 +12,7 @@
 		super(op1,op2);
 	}
 
-	@Override Object eval(LuaState lua) throws LuaException {
+	@Override public Object eval(LuaState lua) throws LuaException {
 		double n1 = Lua.checkNumber(op1.eval(lua)).value();
 		double n2 = Lua.checkNumber(op2.eval(lua)).value();
 		return new LuaNumber( n1 * n2 );
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/NotExpr.java
--- a/src/luan/interp/NotExpr.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/NotExpr.java	Thu Nov 22 10:51:56 2012 +0000
@@ -11,7 +11,7 @@
 		super(op);
 	}
 
-	@Override Object eval(LuaState lua) throws LuaException {
+	@Override public Object eval(LuaState lua) throws LuaException {
 		return !Lua.toBoolean(op.eval(lua));
 	}
 }
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/OrExpr.java
--- a/src/luan/interp/OrExpr.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/OrExpr.java	Thu Nov 22 10:51:56 2012 +0000
@@ -11,7 +11,7 @@
 		super(op1,op2);
 	}
 
-	@Override Object eval(LuaState lua) throws LuaException {
+	@Override public Object eval(LuaState lua) throws LuaException {
 		Object v1 = op1.eval(lua);
 		return Lua.toBoolean(v1) ? v1 : op2.eval(lua);
 	}
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/PowExpr.java
--- a/src/luan/interp/PowExpr.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/PowExpr.java	Thu Nov 22 10:51:56 2012 +0000
@@ -12,7 +12,7 @@
 		super(op1,op2);
 	}
 
-	@Override Object eval(LuaState lua) throws LuaException {
+	@Override public Object eval(LuaState lua) throws LuaException {
 		double n1 = Lua.checkNumber(op1.eval(lua)).value();
 		double n2 = Lua.checkNumber(op2.eval(lua)).value();
 		return new LuaNumber( Math.pow(n1,n2) );
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/SetStmt.java
--- a/src/luan/interp/SetStmt.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/SetStmt.java	Thu Nov 22 10:51:56 2012 +0000
@@ -7,7 +7,7 @@
 import luan.LuaTable;
 
 
-final class SetStmt extends Stmt {
+final class SetStmt implements Stmt {
 
 	static class Var {
 		final Expr table;
@@ -20,15 +20,15 @@
 	}
 
 	private final Var[] vars;
-	private final Values values;
+	private final Expressions expressions;
 
-	SetStmt(Var[] vars,Values values) {
+	SetStmt(Var[] vars,Expressions expressions) {
 		this.vars = vars;
-		this.values = values;
+		this.expressions = expressions;
 	}
 
-	@Override void eval(LuaState lua) throws LuaException {
-		List vals = values.eval(lua);
+	@Override public void eval(LuaState lua) throws LuaException {
+		List vals = expressions.eval(lua);
 		int n = vals.size();
 		for( int i=0; i<vars.length; i++ ) {
 			Var var = vars[i];
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/Stmt.java
--- a/src/luan/interp/Stmt.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/Stmt.java	Thu Nov 22 10:51:56 2012 +0000
@@ -4,6 +4,6 @@
 import luan.LuaException;
 
 
-abstract class Stmt {
-	abstract void eval(LuaState lua) throws LuaException;
+public interface Stmt {
+	public void eval(LuaState lua) throws LuaException;
 }
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/SubExpr.java
--- a/src/luan/interp/SubExpr.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/SubExpr.java	Thu Nov 22 10:51:56 2012 +0000
@@ -12,7 +12,7 @@
 		super(op1,op2);
 	}
 
-	@Override Object eval(LuaState lua) throws LuaException {
+	@Override public Object eval(LuaState lua) throws LuaException {
 		double n1 = Lua.checkNumber(op1.eval(lua)).value();
 		double n2 = Lua.checkNumber(op2.eval(lua)).value();
 		return new LuaNumber( n1 - n2 );
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/TableExpr.java
--- a/src/luan/interp/TableExpr.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/TableExpr.java	Thu Nov 22 10:51:56 2012 +0000
@@ -5,7 +5,7 @@
 import luan.LuaTable;
 
 
-final class TableExpr extends Expr {
+final class TableExpr implements Expr {
 
 	static class Field {
 		final Expr key;
@@ -23,7 +23,7 @@
 		this.fields = fields;
 	}
 
-	@Override Object eval(LuaState lua) throws LuaException {
+	@Override public Object eval(LuaState lua) throws LuaException {
 		LuaTable table = new LuaTable();
 		for( Field field : fields ) {
 			table.set( field.key.eval(lua), field.value.eval(lua) );
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/UnaryOpExpr.java
--- a/src/luan/interp/UnaryOpExpr.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/UnaryOpExpr.java	Thu Nov 22 10:51:56 2012 +0000
@@ -1,7 +1,7 @@
 package luan.interp;
 
 
-abstract class UnaryOpExpr extends Expr {
+abstract class UnaryOpExpr implements Expr {
 	final Expr op;
 
 	UnaryOpExpr(Expr op) {
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/UnmExpr.java
--- a/src/luan/interp/UnmExpr.java	Thu Nov 22 04:37:10 2012 +0000
+++ b/src/luan/interp/UnmExpr.java	Thu Nov 22 10:51:56 2012 +0000
@@ -13,7 +13,7 @@
 		super(op);
 	}
 
-	@Override Object eval(LuaState lua) throws LuaException {
+	@Override public Object eval(LuaState lua) throws LuaException {
 		double n = Lua.checkNumber(op.eval(lua)).value();
 		return new LuaNumber( -n );
 	}
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/Values.java
--- a/src/luan/interp/Values.java	Thu Nov 22 04:37:10 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-package luan.interp;
-
-import java.util.List;
-import luan.LuaException;
-import luan.LuaState;
-
-
-abstract class Values {
-	abstract List eval(LuaState lua) throws LuaException;
-}
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/ValuesExpr.java
--- a/src/luan/interp/ValuesExpr.java	Thu Nov 22 04:37:10 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-package luan.interp;
-
-import java.util.List;
-import luan.Lua;
-import luan.LuaException;
-import luan.LuaState;
-
-
-final class ValuesExpr extends Expr {
-	private final Values values;
-
-	ValuesExpr(Values values) {
-		this.values = values;
-	}
-
-	@Override Object eval(LuaState lua) throws LuaException {
-		List list = values.eval(lua);
-		return list.isEmpty() ? null : list.get(0);
-	}
-}
diff -r 8217d8485715 -r b7d7069fee58 src/luan/interp/ValuesStmt.java
--- a/src/luan/interp/ValuesStmt.java	Thu Nov 22 04:37:10 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,18 +0,0 @@
-package luan.interp;
-
-import luan.LuaState;
-import luan.LuaException;
-
-
-final class ValuesStmt extends Stmt {
-	private final Values values;
-
-	ValuesStmt(Values values) {
-		this.values = values;
-	}
-
-	@Override void eval(LuaState lua) throws LuaException {
-		values.eval(lua);
-	}
-
-}