diff src/luan/interp/LuaParser.java @ 21:c93d8c781853

add functions git-svn-id: https://luan-java.googlecode.com/svn/trunk@22 21e917c8-12df-6dd8-5cb6-c86387c605b9
author fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9>
date Tue, 04 Dec 2012 09:16:03 +0000
parents d85510d92eee
children 7ee247560db5
line wrap: on
line diff
--- a/src/luan/interp/LuaParser.java	Sun Dec 02 10:51:18 2012 +0000
+++ b/src/luan/interp/LuaParser.java	Tue Dec 04 09:16:03 2012 +0000
@@ -22,11 +22,21 @@
 
 
 public class LuaParser extends BaseParser<Object> {
+
+	static final class Frame {
+		final Frame parent;
+		final List<String> symbols = new ArrayList<String>();
+		int stackSize = 0;
+		int loops = 0;
+
+		Frame(Frame parent) {
+			this.parent = parent;
+		}
+	}
+
 	int nEquals;
 	int parens = 0;
-	List<String> symbols = new ArrayList<String>();
-	int stackSize = 0;
-	int loops = 0;
+	Frame frame = new Frame(null);
 
 	boolean nEquals(int n) {
 		nEquals = n;
@@ -43,7 +53,23 @@
 		return true;
 	}
 
+	List<String> symbols() {
+		return frame.symbols;
+	}
+
+	int symbolsSize() {
+		return frame.symbols.size();
+	}
+
+	boolean addSymbol(String name) {
+		frame.symbols.add(name);
+		if( frame.stackSize < symbolsSize() )
+			frame.stackSize = symbolsSize();
+		return true;
+	}
+
 	int index(String name) {
+		List<String> symbols = frame.symbols;
 		int i = symbols.size();
 		while( --i >= 0 ) {
 			if( symbols.get(i).equals(name) )
@@ -53,6 +79,7 @@
 	}
 
 	boolean popSymbols(int n) {
+		List<String> symbols = frame.symbols;
 		while( n-- > 0 ) {
 			symbols.remove(symbols.size()-1);
 		}
@@ -60,12 +87,12 @@
 	}
 
 	boolean incLoops() {
-		loops++;
+		frame.loops++;
 		return true;
 	}
 
 	boolean decLoops() {
-		loops--;
+		frame.loops--;
 		return true;
 	}
 
@@ -75,21 +102,18 @@
 			Spaces(),
 			FirstOf(
 				Sequence( ExpList(), EOI ),
-				Sequence( Chunk(), EOI )
+				Sequence(
+					Block(),
+					EOI,
+					push( new Chunk( (Stmt)pop(), frame.stackSize, 0 ) )
+				)
 			)
 		);
 	}
 
-	Rule Chunk() {
-		return Sequence(
-			Block(),
-			push( new Chunk( (Stmt)pop(), stackSize ) )
-		);
-	}
-
 	Rule Block() {
 		Var<List<Stmt>> stmts = new Var<List<Stmt>>(new ArrayList<Stmt>());
-		Var<Integer> stackStart = new Var<Integer>(symbols.size());
+		Var<Integer> stackStart = new Var<Integer>(symbolsSize());
 		return Sequence(
 			Optional( Stmt(stmts) ),
 			ZeroOrMore(
@@ -101,9 +125,7 @@
 	}
 
 	Stmt newBlock(List<Stmt> stmts,int stackStart) {
-		if( stackSize < symbols.size() )
-			stackSize = symbols.size();
-		int stackEnd = symbols.size();
+		int stackEnd = symbolsSize();
 		popSymbols( stackEnd - stackStart );
 		if( stmts.isEmpty() )
 			return Stmt.EMPTY;
@@ -134,6 +156,9 @@
 			LocalStmt(stmts),
 			Sequence(
 				FirstOf(
+					ReturnStmt(),
+					FunctionStmt(),
+					LocalFunctionStmt(),
 					BreakStmt(),
 					GenericForStmt(),
 					NumericForStmt(),
@@ -149,20 +174,54 @@
 		);
 	}
 
+	Rule ReturnStmt() {
+		return Sequence(
+			Keyword("return"), Expressions(),
+			push( new ReturnStmt( (Expressions)pop() ) )
+		);
+	}
+
+	Rule FunctionStmt() {
+		return Sequence(
+			Keyword("function"), FnName(), Function(),
+			push( new SetStmt( (Settable)pop(1), expr(pop()) ) )
+		);
+	}
+
+	Rule FnName() {
+		return Sequence(
+			push(null),  // marker
+			Name(),
+			ZeroOrMore(
+				'.', Spaces(),
+				makeVarExp(),
+				NameExpr()
+			),
+			makeSettableVar()
+		);
+	}
+
+	Rule LocalFunctionStmt() {
+		return Sequence(
+			Keyword("local"), Keyword("function"), LocalName(), Function(),
+			push( new SetStmt( new SetLocalVar(symbolsSize()-1), expr(pop()) ) )
+		);
+	}
+
 	Rule BreakStmt() {
 		return Sequence(
 			Keyword("break"),
-			loops > 0,
+			frame.loops > 0,
 			push( new BreakStmt() )
 		);
 	}
 
 	Rule GenericForStmt() {
-		Var<Integer> stackStart = new Var<Integer>(symbols.size());
+		Var<Integer> stackStart = new Var<Integer>(symbolsSize());
 		return Sequence(
 			Keyword("for"), NameList(), Keyword("in"), Expr(), Keyword("do"), LoopBlock(), Keyword("end"),
-			push( new GenericForStmt( stackStart.get(), symbols.size() - stackStart.get(), expr(pop(1)), (Stmt)pop() ) ),
-			popSymbols( symbols.size() - stackStart.get() )
+			push( new GenericForStmt( stackStart.get(), symbolsSize() - stackStart.get(), expr(pop(1)), (Stmt)pop() ) ),
+			popSymbols( symbolsSize() - stackStart.get() )
 		);
 	}
 
@@ -175,9 +234,9 @@
 				drop(),
 				Expr()
 			),
-			symbols.add( (String)pop(3) ),  // add "for" var to symbols
+			addSymbol( (String)pop(3) ),  // add "for" var to symbols
 			Keyword("do"), LoopBlock(), Keyword("end"),
-			push( new NumericForStmt( symbols.size()-1, expr(pop(3)), expr(pop(2)), expr(pop(1)), (Stmt)pop() ) ),
+			push( new NumericForStmt( symbolsSize()-1, expr(pop(3)), expr(pop(2)), expr(pop(1)), (Stmt)pop() ) ),
 			popSymbols(1)
 		);
 	}
@@ -189,7 +248,7 @@
 	}
 
 	Rule LocalStmt(Var<List<Stmt>> stmts) {
-		Var<Integer> stackStart = new Var<Integer>(symbols.size());
+		Var<Integer> stackStart = new Var<Integer>(symbolsSize());
 		return Sequence(
 			Keyword("local"), NameList(),
 			Optional(
@@ -201,18 +260,23 @@
 
 	Rule NameList() {
 		return Sequence(
-			Name(),
-			symbols.add( (String)pop() ),
+			LocalName(),
 			ZeroOrMore(
-				',', Spaces(), Name(),
-				symbols.add( (String)pop() )
+				',', Spaces(), LocalName()
 			)
 		);
 	}
 
+	Rule LocalName() {
+		return Sequence(
+			Name(),
+			addSymbol( (String)pop() )
+		);
+	}
+
 	SetStmt newSetLocalStmt(int stackStart) {
 		Expressions values = (Expressions)pop();
-		SetLocalVar[] vars = new SetLocalVar[symbols.size()-stackStart];
+		SetLocalVar[] vars = new SetLocalVar[symbolsSize()-stackStart];
 		for( int i=0; i<vars.length; i++ ) {
 			vars[i] = new SetLocalVar(stackStart+i);
 		}
@@ -289,36 +353,39 @@
 	}
 
 	Rule VarList() {
+		Var<List<Settable>> vars = new Var<List<Settable>>(new ArrayList<Settable>());
 		return Sequence(
-			push(new ArrayList<Settable>()),
-			Var(),
-			addToVarList(),
+			SettableVar(),
+			vars.get().add( (Settable)pop() ),
 			ZeroOrMore(
-				',', Spaces(), Var(),
-				addToVarList()
-			)
+				',', Spaces(), SettableVar(),
+				vars.get().add( (Settable)pop() )
+			),
+			push(vars.get())
 		);
 	}
 
-	boolean addToVarList() {
+	Rule SettableVar() {
+		return Sequence( Var(), makeSettableVar() );
+	}
+
+	boolean makeSettableVar() {
 		Object obj2 = pop();
 		if( obj2==null )
 			return false;
 		Object obj1 = pop();
-		@SuppressWarnings("unchecked")
-		List<Settable> vars = (List<Settable>)peek();
 		if( obj1==null ) {
 			String name = (String)obj2;
 			int index = index(name);
 			if( index == -1 ) {
-				vars.add( new SetTableEntry( EnvExpr.INSTANCE, new ConstExpr(name) ) );
+				push( new SetTableEntry( EnvExpr.INSTANCE, new ConstExpr(name) ) );
 			} else {
-				vars.add( new SetLocalVar(index) );
+				push( new SetLocalVar(index) );
 			}
 		} else {
 			Expr key = expr(obj2);
 			Expr table = expr(obj1);
-			vars.add( new SetTableEntry(table,key) );
+			push( new SetTableEntry(table,key) );
 		}
 		return true;
 	}
@@ -407,12 +474,26 @@
 
 	Rule SingleExpr() {
 		return FirstOf(
+			FunctionExpr(),
 			TableExpr(),
 			VarExp(),
 			LiteralExpr()
 		);
 	}
 
+	Rule FunctionExpr() {
+		return Sequence( "function", Spaces(), Function() );
+	}
+
+	Rule Function() {
+		return Sequence(
+			action( frame = new Frame(frame) ),
+			'(', incParens(), Spaces(), Optional(NameList()), ')', decParens(), Spaces(), Block(), Keyword("end"),
+			push( new Chunk( (Stmt)pop(), frame.stackSize, symbolsSize() ) ),
+			action( frame = frame.parent )
+		);
+	}
+
 	Rule TableExpr() {
 		return Sequence(
 			'{', incParens(), Spaces(),