changeset 14:2ddf85634d20

whitespace handling; comments; if/while/repeat statements; git-svn-id: https://luan-java.googlecode.com/svn/trunk@15 21e917c8-12df-6dd8-5cb6-c86387c605b9
author fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9>
date Mon, 26 Nov 2012 10:18:46 +0000
parents 3b22ffbdb83a
children bb59d7ea223b
files src/luan/interp/IfStmt.java src/luan/interp/LuaParser.java src/luan/interp/RepeatStmt.java src/luan/interp/WhileStmt.java src/luan/lib/BasicLib.java
diffstat 5 files changed, 195 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/interp/IfStmt.java	Mon Nov 26 10:18:46 2012 +0000
@@ -0,0 +1,26 @@
+package luan.interp;
+
+import luan.Lua;
+import luan.LuaState;
+import luan.LuaException;
+
+
+final class IfStmt implements Stmt {
+	private final Expr cnd;
+	private final Stmt thenStmt;
+	private final Stmt elseStmt;
+
+	IfStmt(Expr cnd,Stmt thenStmt,Stmt elseStmt) {
+		this.cnd = cnd;
+		this.thenStmt = thenStmt;
+		this.elseStmt = elseStmt;
+	}
+
+	@Override public void eval(LuaState lua) throws LuaException {
+		if( Lua.toBoolean( cnd.eval(lua) ) ) {
+			thenStmt.eval(lua);
+		} else {
+			elseStmt.eval(lua);
+		}
+	}
+}
--- a/src/luan/interp/LuaParser.java	Fri Nov 23 13:04:03 2012 +0000
+++ b/src/luan/interp/LuaParser.java	Mon Nov 26 10:18:46 2012 +0000
@@ -11,6 +11,9 @@
 import org.parboiled.Rule;
 import org.parboiled.parserunners.ReportingParseRunner;
 import org.parboiled.support.ParsingResult;
+import org.parboiled.support.Var;
+import org.parboiled.support.StringVar;
+import org.parboiled.support.ValueStack;
 import org.parboiled.errors.ErrorUtils;
 import luan.Lua;
 import luan.LuaNumber;
@@ -18,6 +21,7 @@
 
 
 public class LuaParser extends BaseParser<Object> {
+	static final Object PAREN = new Object();
 
 	public Rule Target() {
 		return Sequence(
@@ -51,7 +55,7 @@
 
 	Stmt newChunk() {
 		@SuppressWarnings("unchecked")
-		List<Stmt> stmts = (List<Stmt>)peek();
+		List<Stmt> stmts = (List<Stmt>)pop();
 		switch( stmts.size() ) {
 		case 0:
 			return Stmt.EMPTY;
@@ -63,12 +67,28 @@
 	}
 
 	Rule StmtSep() {
-		return Sequence( OneOrMore(AnyOf(";\r\n")), Spaces() );
+		return Sequence(
+			FirstOf(
+				';',
+				Sequence(
+					Optional( "--", ZeroOrMore(NoneOf("\r\n")) ),
+					EndOfLine()
+				)
+			),
+			Spaces()
+		);
+	}
+
+	Rule EndOfLine() {
+		return FirstOf("\r\n", '\r', '\n');
 	}
 
 	Rule Stmt() {
 		return Sequence(
 			FirstOf(
+				WhileStmt(),
+				RepeatStmt(),
+				IfStmt(),
 				SetStmt(),
 				ExpressionsStmt()
 			),
@@ -76,13 +96,48 @@
 		);
 	}
 
-	Rule ExpressionsStmt() {
+	Rule WhileStmt() {
+		return Sequence(
+			"while", Spaces(), Expr(), "do", Spaces(), Chunk(), "end", Spaces(),
+			push( new WhileStmt( expr(pop(1)), (Stmt)pop() ) )
+		);
+	}
+
+	Rule RepeatStmt() {
+		return Sequence(
+			"repeat", Spaces(), Chunk(), "until", Spaces(), Expr(),
+			push( new RepeatStmt( (Stmt)pop(1), expr(pop()) ) )
+		);
+	}
+
+	Rule IfStmt() {
+		Var<Integer> n = new Var<Integer>(1);
 		return Sequence(
-			ExpList(),
-			push( new ExpressionsStmt((Expressions)pop()) )
+			"if", Spaces(), Expr(), "then", Spaces(), Chunk(),
+			push(Stmt.EMPTY),
+			ZeroOrMore(
+				"elseif", Spaces(), drop(), Expr(), "then", Spaces(), Chunk(),
+				push(Stmt.EMPTY),
+				n.set(n.get()+1)
+			),
+			Optional(
+				"else", Spaces(), drop(), Chunk()
+			),
+			"end", Spaces(),
+			buildIfStmt(n.get())
 		);
 	}
 
+	boolean buildIfStmt(int n) {
+		while( n-- > 0 ) {
+			Stmt elseStmt = (Stmt)pop();
+			Stmt thenStmt = (Stmt)pop();
+			Expr cnd = expr(pop());
+			push( new IfStmt(cnd,thenStmt,elseStmt) );
+		}
+		return true;
+	}
+
 	Rule SetStmt() {
 		return Sequence(
 			VarList(),
@@ -92,6 +147,13 @@
 		);
 	}
 
+	Rule ExpressionsStmt() {
+		return Sequence(
+			ExpList(),
+			push( new ExpressionsStmt((Expressions)pop()) )
+		);
+	}
+
 	SetStmt newSetStmt() {
 		Expressions values = (Expressions)pop();
 		@SuppressWarnings("unchecked")
@@ -170,7 +232,7 @@
 			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( '-', TestNot('-'), Spaces(), TermExpr(), push( new SubExpr(expr(pop(1)),expr(pop())) ) )
 				)
 			)
 		);
@@ -192,7 +254,7 @@
 	Rule UnaryExpr() {
 		return FirstOf(
 			Sequence( '#', Spaces(), PowExpr(), push( new LenExpr(expr(pop())) ) ),
-			Sequence( '-', Spaces(), PowExpr(), push( new UnmExpr(expr(pop())) ) ),
+			Sequence( '-', TestNot('-'), Spaces(), PowExpr(), push( new UnmExpr(expr(pop())) ) ),
 			Sequence( "not", Spaces(), PowExpr(), push( new NotExpr(expr(pop())) ) ),
 			PowExpr()
 		);
@@ -216,6 +278,7 @@
 	Rule TableExpr() {
 		return Sequence(
 			'{', Spaces(),
+			push(PAREN),
 			push( new ArrayList<TableExpr.Field>() ),
 			push( 1.0 ),  // counter
 			Optional(
@@ -226,8 +289,10 @@
 				),
 				Optional( FieldSep() )
 			),
-			'}', Spaces(),
-			push( newTableExpr() )
+			'}',
+			push( newTableExpr() ),
+			drop(1),
+			Spaces()
 		);
 	}
 
@@ -292,7 +357,7 @@
 		return Sequence(
 			FirstOf(
 				Sequence(
-					'(', Spaces(), Expr(), ')', Spaces(),
+					'(', Spaces(), push(PAREN), Expr(), ')', drop(1), Spaces(),
 					push(expr(pop())),
 					push(null)  // marker
 				),
@@ -327,7 +392,7 @@
 		return Sequence(
 			FirstOf(
 				Sequence(
-					'(', Spaces(), Expressions(), ')', Spaces()
+					'(', Spaces(), push(PAREN), Expressions(), ')', drop(1), Spaces()
 				),
 				Sequence(
 					TableExpr(),
@@ -374,7 +439,7 @@
 	}
 
 	Rule SubExpr() {
-		return Sequence( '[', Spaces(), Expr(), ']', Spaces() );
+		return Sequence( '[', Spaces(), push(PAREN), Expr(), ']', drop(1), Spaces() );
 	}
 
 	Rule Name() {
@@ -579,12 +644,56 @@
 	}
 
 	Rule Spaces() {
-		return ZeroOrMore(AnyOf(" \t"));
+		return ZeroOrMore(
+			FirstOf(
+				AnyOf(" \t"),
+				Comment(),
+				Sequence( '\\', EndOfLine() ),
+				Sequence( AnyOf("\r\n"), inParen() )
+			)
+		);
+	}
+
+	boolean inParen() {
+		ValueStack stack = getContext().getValueStack();
+		int size = stack.size();
+		for( int i=0; i<size; i++ ) {
+			if( peek(i) == PAREN )
+				return true;
+		}
+		return false;
+	}
+
+	Rule Comment() {
+		Var<Integer> n = new Var<Integer>();
+		return Sequence(
+			"--[",
+			ZeroOrMore('='),
+			setN(n),
+			'[',
+			ZeroOrMore(
+				TestNot(CommentEnd(n)),
+				ANY
+			),
+			CommentEnd(n)
+		);
+	}
+
+	Rule CommentEnd(Var<Integer> n) {
+		return Sequence( ']', ZeroOrMore('='), eqN(n), ']' );
+	}
+
+	boolean setN(Var<Integer> n) {
+		return n.set(matchLength());
+	}
+
+	boolean eqN(Var<Integer> n) {
+		return n.get()==matchLength();
 	}
 
 	// for debugging
-	boolean print(String s) {
-		System.out.println(s);
+	boolean print(Object o) {
+		System.out.println(o);
 		return true;
 	}
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/interp/RepeatStmt.java	Mon Nov 26 10:18:46 2012 +0000
@@ -0,0 +1,22 @@
+package luan.interp;
+
+import luan.Lua;
+import luan.LuaState;
+import luan.LuaException;
+
+
+final class RepeatStmt implements Stmt {
+	private final Stmt doStmt;
+	private final Expr cnd;
+
+	RepeatStmt(Stmt doStmt,Expr cnd) {
+		this.doStmt = doStmt;
+		this.cnd = cnd;
+	}
+
+	@Override public void eval(LuaState lua) throws LuaException {
+		do {
+			doStmt.eval(lua);
+		} while( !Lua.toBoolean( cnd.eval(lua) ) );
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/interp/WhileStmt.java	Mon Nov 26 10:18:46 2012 +0000
@@ -0,0 +1,22 @@
+package luan.interp;
+
+import luan.Lua;
+import luan.LuaState;
+import luan.LuaException;
+
+
+final class WhileStmt implements Stmt {
+	private final Expr cnd;
+	private final Stmt doStmt;
+
+	WhileStmt(Expr cnd,Stmt doStmt) {
+		this.cnd = cnd;
+		this.doStmt = doStmt;
+	}
+
+	@Override public void eval(LuaState lua) throws LuaException {
+		while( Lua.toBoolean( cnd.eval(lua) ) ) {
+			doStmt.eval(lua);
+		}
+	}
+}
--- a/src/luan/lib/BasicLib.java	Fri Nov 23 13:04:03 2012 +0000
+++ b/src/luan/lib/BasicLib.java	Mon Nov 26 10:18:46 2012 +0000
@@ -50,6 +50,7 @@
 	public static LuaFunction load(String ld) throws LuaException {
 		LuaParser parser = Parboiled.createParser(LuaParser.class);
 		ParsingResult<?> result = new ReportingParseRunner(parser.Target()).run(ld);
+//		ParsingResult<?> result = new TracingParseRunner(parser.Target()).run(ld);
 		if( result.hasErrors() )
 			throw new LuaException( ErrorUtils.printParseErrors(result) );
 		Object resultValue = result.resultValue;