changeset 679:43522473599d

make java line numbers match
author Franklin Schmidt <fschmidt@gmail.com>
date Thu, 14 Apr 2016 15:19:25 -0600
parents 49f3d290bebd
children ecd436959855
files core/src/luan/impl/LuanParser.java core/src/luan/impl/Parser.java
diffstat 2 files changed, 281 insertions(+), 229 deletions(-) [+]
line wrap: on
line diff
diff -r 49f3d290bebd -r 43522473599d core/src/luan/impl/LuanParser.java
--- a/core/src/luan/impl/LuanParser.java	Wed Apr 13 16:24:48 2016 -0600
+++ b/core/src/luan/impl/LuanParser.java	Thu Apr 14 15:19:25 2016 -0600
@@ -1,5 +1,7 @@
 package luan.impl;
 
+//import java.io.StringWriter;
+//import java.io.PrintWriter;
 import java.util.Set;
 import java.util.HashSet;
 import java.util.Arrays;
@@ -36,9 +38,9 @@
 				stmt.add( new Object() {
 					@Override public String toString() {
 						if( !isPointer )
-							return "Object " + javaName + ";\n";
+							return "Object " + javaName + ";  ";
 						else
-							return "final Pointer " + javaName + " = new Pointer();\n";
+							return "final Pointer " + javaName + " = new Pointer();  ";
 					}
 				} );
 			} else {
@@ -55,9 +57,9 @@
 				stmt.add( new Object() {
 					@Override public String toString() {
 						if( !isPointer )
-							return ";\n";
+							return ";  ";
 						else
-							return ");\n";
+							return ");  ";
 					}
 				} );
 			}
@@ -90,7 +92,7 @@
 		}
 
 		String init() {
-			return "upValues[" + i + "] = " + value + ";\n";
+			return "upValues[" + i + "] = " + value + ";  ";
 		}
 
 		@Override public Expr exp() {
@@ -164,34 +166,29 @@
 	}
 
 	private static class In {
-		static final In NOTHING = new In(false,false);
+		static final In NOTHING = new In(false);
 
-		final boolean parens;
 		final boolean template;
 
-		private In(boolean parens,boolean template) {
-			this.parens = parens;
+		private In(boolean template) {
 			this.template = template;
 		}
 
-		In parens() {
-			return parens ? this : new In(true,false);
-		}
-
 		In template() {
-			return template ? this : new In(false,true);
+			return template ? this : new In(true);
 		}
 	}
 
 //	final LuanSource source;
 	private Frame frame;
 	private final Parser parser;
-	private final Stmts top = new Stmts();
+	private final Stmts top;
 
 	LuanParser(String sourceName,String sourceText) {
 //		this.source = source;
 		this.frame = new Frame();
 		this.parser = new Parser(sourceName,sourceText);
+		this.top = new Stmts();
 	}
 
 	void addVar(String name) {
@@ -199,7 +196,7 @@
 		if( name != null ) {
 			LocalSym sym = frame.addLocalSym( name );
 			sym.isPointer = true;
-			top.add( "final Pointer " + sym.javaName + " = upValues[" + upSym.i + "];\n" );
+			top.add( "final Pointer " + sym.javaName + " = upValues[" + upSym.i + "];  " );
 		}
 	}
 
@@ -252,13 +249,13 @@
 	}
 
 	Class Expression() throws ParseException {
-		Spaces(In.NOTHING);
+		Spaces();
 		parser.begin();
 		Expr expr = ExprZ(In.NOTHING);
 		if( expr != null && parser.endOfInput() ) {
 			top.add( "return " );
 			top.addAll( expr );
-			top.add( ";\n" );
+			top.add( ";  " );
 			top.hasReturn = true;
 			return parser.success(newFnClass(top));
 		}
@@ -276,10 +273,10 @@
 	}
 
 	void GetRequiredModule() throws ParseException {
-		Spaces(In.NOTHING);
+		Spaces();
 		parser.begin();
 		frame.isVarArg = true;
-		top.add( "final Object[] varArgs = LuanImpl.varArgs(args,0);\n" );
+		top.add( "final Object[] varArgs = LuanImpl.varArgs(args,0);  " );
 		Stmts block = RequiredBlock();
 		top.addAll( block );
 		top.hasReturn = block.hasReturn;
@@ -292,37 +289,40 @@
 		Stmts stmts = new Stmts();
 		int stackStart = symbolsSize();
 		boolean isReturn = Stmt(stmts);
-		while( !isReturn && StmtSep(stmts) ) {
-			Spaces(In.NOTHING);
+		while( !isReturn && (StmtSep() || TemplateSep(stmts)) ) {
+			Spaces();
+			stmts.addNewLines();
 			isReturn = Stmt(stmts);
 		}
-		while( StmtSep(null) )
-			Spaces(In.NOTHING);
+		while( StmtSep() )
+			Spaces();
+		stmts.addNewLines();
 		int stackEnd = symbolsSize();
 		popSymbols( stackEnd - stackStart );
 		stmts.hasReturn = isReturn;
 		return stmts;
 	}
 
-	private boolean StmtSep(Stmts stmts) throws ParseException {
-		parser.begin();
-		if( parser.match( ';' ) )
-			return parser.success();
-		if( EndOfLine() )
-			return parser.success();
-		if( stmts != null ) {
-//			parser.rollback();
-			Stmts stmt = TemplateStmt();
-			if( stmt != null ) {
-				stmts.addAll(stmt);
-				return parser.success();
-			}
+	private boolean StmtSep() throws ParseException {
+		return parser.match( ';' ) || EndOfLine();
+	}
+
+	private boolean TemplateSep(Stmts stmts) throws ParseException {
+		Stmts stmt = TemplateStmt();
+		if( stmt != null ) {
+			stmts.addAll(stmt);
+			return true;
 		}
-		return parser.failure();
+		return false;
 	}
 
 	private boolean EndOfLine() {
-		return parser.match( "\r\n" ) || parser.match( '\r' ) || parser.match( '\n' );
+		if( parser.match( "\r\n" ) || parser.match( '\r' ) || parser.match( '\n' ) ) {
+			parser.sb().append('\n');
+			return true;
+		} else {
+			return false;
+		}
 	}
 
 	private boolean Stmt(Stmts stmts) throws ParseException {
@@ -379,7 +379,7 @@
 		Expr writeCall = callExpStr( writeExp, exprs );
 		Stmts stmt = new Stmts();
 		stmt.addAll( writeCall );
-		stmt.add( ";\n" );
+		stmt.add( ";  " );
 		return stmt;
 	}
 
@@ -394,11 +394,11 @@
 		List<Expr> builder = new ArrayList<Expr>();
 		while(true) {
 			if( parser.match( "<%=" ) ) {
-				Spaces(inTemplate);
+				Spaces();
 				builder.add( RequiredExpr(inTemplate) );
 				RequiredMatch( "%>" );
 			} else if( parser.match( "<%" ) ) {
-				Spaces(inTemplate);
+				Spaces();
 				return parser.success(expString(builder));
 			} else {
 				int i = parser.currentIndex();
@@ -416,7 +416,7 @@
 
 	private Stmts ReturnStmt() throws ParseException {
 		parser.begin();
-		if( !Keyword("return",In.NOTHING) )
+		if( !Keyword("return") )
 			return parser.failure(null);
 		Expr exprs = ExpStringList(In.NOTHING);
 		Stmts stmt = new Stmts();
@@ -425,20 +425,20 @@
 			stmt.addAll( exprs );
 		else
 			stmt.add( "LuanFunction.NOTHING" );
-		stmt.add( ";\n" );
+		stmt.add( ";  " );
 		return parser.success( stmt );
 	}
 
 	private Stmts FunctionStmt() throws ParseException {
 		parser.begin();
-		if( !Keyword("function",In.NOTHING) )
+		if( !Keyword("function") )
 			return parser.failure(null);
 
 		parser.currentIndex();
-		Var var = nameVar(RequiredName(In.NOTHING));
+		Var var = nameVar(RequiredName());
 		while( parser.match( '.' ) ) {
-			Spaces(In.NOTHING);
-			Expr exp = NameExpr(In.NOTHING);
+			Spaces();
+			Expr exp = NameExpr();
 			if( exp==null )
 				return parser.failure(null);
 			var = indexVar( var.exp(), exp );
@@ -450,10 +450,10 @@
 
 	private Stmts LocalFunctionStmt() throws ParseException {
 		parser.begin();
-		if( !(Keyword("local",In.NOTHING) && Keyword("function",In.NOTHING)) )
+		if( !(Keyword("local") && Keyword("function")) )
 			return parser.failure(null);
 		Stmts stmt = new Stmts();
-		String name = RequiredName(In.NOTHING);
+		String name = RequiredName();
 		stmt.addAll( addSymbol(name,null) );
 		Expr fnDef = RequiredFunction(In.NOTHING);
 		stmt.addAll( nameVar(name).set(fnDef) );
@@ -462,12 +462,12 @@
 
 	private Stmts BreakStmt() throws ParseException {
 		parser.begin();
-		if( !Keyword("break",In.NOTHING) )
+		if( !Keyword("break") )
 			return parser.failure(null);
 		if( frame.loops <= 0 )
 			throw parser.exception("'break' outside of loop");
 		Stmts stmt = new Stmts();
-		stmt.add( "break;\n" );
+		stmt.add( "break;  " );
 		return parser.success( stmt );
 	}
 
@@ -476,10 +476,10 @@
 	private Stmts ForStmt() throws ParseException {
 		parser.begin();
 		int stackStart = symbolsSize();
-		if( !Keyword("for",In.NOTHING) )
+		if( !Keyword("for") )
 			return parser.failure(null);
-		List<String> names = RequiredNameList(In.NOTHING);
-		if( !Keyword("in",In.NOTHING) )
+		List<String> names = RequiredNameList();
+		if( !Keyword("in") )
 			return parser.failure(null);
 		Expr expr = RequiredExpr(In.NOTHING).single();
 		RequiredKeyword("do",In.NOTHING);
@@ -492,23 +492,23 @@
 			+"LuanFunction "+fnVar+" = Luan.checkFunction("
 		);
 		stmt.addAll( expr );
-		stmt.add( ");\n" );
-		stmt.add( "while(true) {\n" );
+		stmt.add( ");  " );
+		stmt.add( "while(true) {  " );
 		stmt.addAll( makeLocalSetStmt(names,fnExp) );
 		stmt.add( "if( " );
 		stmt.addAll( nameVar(names.get(0)).exp() );
- 		stmt.add( "==null )  break;\n" );
+ 		stmt.add( "==null )  break;  " );
 		Stmts loop = RequiredLoopBlock();
 		RequiredKeyword("end",In.NOTHING);
 		stmt.addAll( loop );
-		stmt.add( "}\n" );
+		stmt.add( "}  " );
 		popSymbols( symbolsSize() - stackStart );
 		return parser.success(stmt);
 	}
 
 	private Stmts DoStmt() throws ParseException {
 		parser.begin();
-		if( !Keyword("do",In.NOTHING) )
+		if( !Keyword("do") )
 			return parser.failure(null);
 		Stmts stmt = RequiredBlock();
 		RequiredKeyword("end",In.NOTHING);
@@ -517,17 +517,17 @@
 
 	private Stmts LocalStmt() throws ParseException {
 		parser.begin();
-		if( !Keyword("local",In.NOTHING) )
+		if( !Keyword("local") )
 			return parser.failure(null);
-		List<String> names = NameList(In.NOTHING);
+		List<String> names = NameList();
 		if( names==null ) {
-			if( Keyword("function",In.NOTHING) )
+			if( Keyword("function") )
 				return parser.failure(null);  // handled later
 			throw parser.exception("Invalid local statement");
 		}
 		Stmts stmt = new Stmts();
 		if( parser.match( '=' ) ) {
-			Spaces(In.NOTHING);
+			Spaces();
 			Expr values = ExpStringList(In.NOTHING);
 			if( values==null )
 				throw parser.exception("Expressions expected");
@@ -542,32 +542,32 @@
 		return parser.success(stmt);
 	}
 
-	private List<String> RequiredNameList(In in) throws ParseException {
+	private List<String> RequiredNameList() throws ParseException {
 		parser.begin();
-		List<String> names = NameList(in);
+		List<String> names = NameList();
 		if( names==null )
 			throw parser.exception("Name expected");
 		return parser.success(names);
 	}
 
-	private List<String> NameList(In in) throws ParseException {
-		String name = Name(in);
+	private List<String> NameList() throws ParseException {
+		String name = Name();
 		if( name==null )
 			return null;
 		List<String> names = new ArrayList<String>();
 		names.add(name);
-		while( (name=anotherName(in)) != null ) {
+		while( (name=anotherName()) != null ) {
 			names.add(name);
 		}
 		return names;
 	}
 
-	private String anotherName(In in) throws ParseException {
+	private String anotherName() throws ParseException {
 		parser.begin();
 		if( !parser.match( ',' ) )
 			return parser.failure(null);
-		Spaces(in);
-		String name = Name(in);
+		Spaces();
+		String name = Name();
 		if( name==null )
 			return parser.failure(null);
 		return parser.success(name);
@@ -575,7 +575,7 @@
 
 	private Stmts WhileStmt() throws ParseException {
 		parser.begin();
-		if( !Keyword("while",In.NOTHING) )
+		if( !Keyword("while") )
 			return parser.failure(null);
 		Expr cnd = RequiredExpr(In.NOTHING).single();
 		RequiredKeyword("do",In.NOTHING);
@@ -584,25 +584,25 @@
 		Stmts stmt = new Stmts();
 		stmt.add( "while( Luan.checkBoolean(" );
 		stmt.addAll( cnd );
-		stmt.add( ") ) {\n" );
+		stmt.add( ") ) {  " );
 		stmt.addAll( loop );
-		stmt.add( "}\n" );
+		stmt.add( "}  " );
 		return parser.success( stmt );
 	}
 
 	private Stmts RepeatStmt() throws ParseException {
 		parser.begin();
-		if( !Keyword("repeat",In.NOTHING) )
+		if( !Keyword("repeat") )
 			return parser.failure(null);
 		Stmts loop =RequiredLoopBlock();
 		RequiredKeyword("until",In.NOTHING);
 		Expr cnd = RequiredExpr(In.NOTHING).single();
 		Stmts stmt = new Stmts();
-		stmt.add( "do {\n" );
+		stmt.add( "do {  " );
 		stmt.addAll( loop );
 		stmt.add( "} while( !Luan.checkBoolean(" );
 		stmt.addAll( cnd );
-		stmt.add( ") );\n" );
+		stmt.add( ") );  " );
 		return parser.success( stmt );
 	}
 
@@ -615,7 +615,7 @@
 
 	private Stmts IfStmt() throws ParseException {
 		parser.begin();
-		if( !Keyword("if",In.NOTHING) )
+		if( !Keyword("if") )
 			return parser.failure(null);
 		Stmts stmt = new Stmts();
 		Expr cnd;
@@ -625,24 +625,24 @@
 		block = RequiredBlock();
 		stmt.add( "if( Luan.checkBoolean(" );
 		stmt.addAll( cnd );
-		stmt.add( ") ) {\n" );
+		stmt.add( ") ) {  " );
 		stmt.addAll( block );
-		while( Keyword("elseif",In.NOTHING) ) {
+		while( Keyword("elseif") ) {
 			cnd = RequiredExpr(In.NOTHING).single();
 			RequiredKeyword("then",In.NOTHING);
 			block = RequiredBlock();
 			stmt.add( "} else if( Luan.checkBoolean(" );
 			stmt.addAll( cnd );
-			stmt.add( ") ) {\n" );
+			stmt.add( ") ) {  " );
 			stmt.addAll( block );
 		}
-		if( Keyword("else",In.NOTHING) ) {
+		if( Keyword("else") ) {
 			block = RequiredBlock();
-			stmt.add( "} else {\n" );
+			stmt.add( "} else {  " );
 			stmt.addAll( block );
 		}
 		RequiredKeyword("end",In.NOTHING);
-		stmt.add( "}\n" );
+		stmt.add( "}  " );
 		return parser.success( stmt );
 	}
 
@@ -654,7 +654,7 @@
 			return parser.failure(null);
 		vars.add(v);
 		while( parser.match( ',' ) ) {
-			Spaces(In.NOTHING);
+			Spaces();
 			v = SettableVar();
 			if( v == null )
 				return parser.failure(null);
@@ -662,7 +662,7 @@
 		}
 		if( !parser.match( '=' ) )
 			return parser.failure(null);
-		Spaces(In.NOTHING);
+		Spaces();
 		Expr values = ExpStringList(In.NOTHING);
 		if( values==null )
 //			throw parser.exception("Expressions expected");
@@ -678,7 +678,7 @@
 		String varName = values.valType==Val.ARRAY ? "a" : "t";
 		stmt.add( varName + " = " );
 		stmt.addAll( values );
-		stmt.add( ";\n" );
+		stmt.add( ";  " );
 		Expr t = new Expr(values.valType,false);
 		t.add( varName );
 		t = t.single();
@@ -699,7 +699,7 @@
 		String varName = values.valType==Val.ARRAY ? "a" : "t";
 		stmt.add( varName + " = " );
 		stmt.addAll( values );
-		stmt.add( ";\n" );
+		stmt.add( ";  " );
 		Expr t = new Expr(values.valType,false);
 		t.add( varName );
 		t = t.single();
@@ -724,7 +724,7 @@
 			} else {
 				stmt.addAll( exp );
 			}
-			stmt.add( ";\n" );
+			stmt.add( ";  " );
 			return parser.success( stmt );
 		}
 		return parser.failure(null);
@@ -752,7 +752,7 @@
 		Expr exp = AndExpr(in);
 		if( exp==null )
 			return parser.failure(null);
-		while( Keyword("or",in) ) {
+		while( Keyword("or") ) {
 			exp = exp.single();
 			Expr exp2 = required(RelExpr(in)).single();
 			Expr newExp = new Expr(Val.SINGLE,true);
@@ -771,7 +771,7 @@
 		Expr exp = RelExpr(in);
 		if( exp==null )
 			return parser.failure(null);
-		while( Keyword("and",in) ) {
+		while( Keyword("and") ) {
 			exp = exp.single();
 			Expr exp2 = required(RelExpr(in)).single();
 			Expr newExp = new Expr(Val.SINGLE,true);
@@ -792,7 +792,7 @@
 			return parser.failure(null);
 		while(true) {
 			if( parser.match("==") ) {
-				Spaces(in);
+				Spaces();
 				exp = exp.single();
 				Expr exp2 = required(ConcatExpr(in)).single();
 				Expr newExp = new Expr(Val.SINGLE,false);
@@ -803,7 +803,7 @@
 				newExp.add( ")" );
 				exp = newExp;
 			} else if( parser.match("~=") ) {
-				Spaces(in);
+				Spaces();
 				exp = exp.single();
 				Expr exp2 = required(ConcatExpr(in)).single();
 				Expr newExp = new Expr(Val.SINGLE,false);
@@ -814,7 +814,7 @@
 				newExp.add( ")" );
 				exp = newExp;
 			} else if( parser.match("<=") ) {
-				Spaces(in);
+				Spaces();
 				exp = exp.single();
 				Expr exp2 = required(ConcatExpr(in)).single();
 				Expr newExp = new Expr(Val.SINGLE,false);
@@ -825,7 +825,7 @@
 				newExp.add( ")" );
 				exp = newExp;
 			} else if( parser.match(">=") ) {
-				Spaces(in);
+				Spaces();
 				exp = exp.single();
 				Expr exp2 = required(ConcatExpr(in)).single();
 				Expr newExp = new Expr(Val.SINGLE,false);
@@ -836,7 +836,7 @@
 				newExp.add( ")" );
 				exp = newExp;
 			} else if( parser.match("<") ) {
-				Spaces(in);
+				Spaces();
 				exp = exp.single();
 				Expr exp2 = required(ConcatExpr(in)).single();
 				Expr newExp = new Expr(Val.SINGLE,false);
@@ -847,7 +847,7 @@
 				newExp.add( ")" );
 				exp = newExp;
 			} else if( parser.match(">") ) {
-				Spaces(in);
+				Spaces();
 				exp = exp.single();
 				Expr exp2 = required(ConcatExpr(in)).single();
 				Expr newExp = new Expr(Val.SINGLE,false);
@@ -869,7 +869,7 @@
 		if( exp==null )
 			return parser.failure(null);
 		if( parser.match("..") ) {
-			Spaces(in);
+			Spaces();
 			exp = exp.single();
 			Expr exp2 = required(ConcatExpr(in)).single();
 			Expr newExp = new Expr(Val.SINGLE,false);
@@ -890,7 +890,7 @@
 			return parser.failure(null);
 		while(true) {
 			if( parser.match('+') ) {
-				Spaces(in);
+				Spaces();
 				exp = exp.single();
 				Expr exp2 = required(TermExpr(in)).single();
 				Expr newExp = new Expr(Val.SINGLE,false);
@@ -901,7 +901,7 @@
 				newExp.add( ")" );
 				exp = newExp;
 			} else if( Minus() ) {
-				Spaces(in);
+				Spaces();
 				exp = exp.single();
 				Expr exp2 = required(TermExpr(in)).single();
 				Expr newExp = new Expr(Val.SINGLE,false);
@@ -929,7 +929,7 @@
 			return parser.failure(null);
 		while(true) {
 			if( parser.match('*') ) {
-				Spaces(in);
+				Spaces();
 				exp = exp.single();
 				Expr exp2 = required(UnaryExpr(in)).single();
 				Expr newExp = new Expr(Val.SINGLE,false);
@@ -940,7 +940,7 @@
 				newExp.add( ")" );
 				exp = newExp;
 			} else if( parser.match('/') ) {
-				Spaces(in);
+				Spaces();
 				exp = exp.single();
 				Expr exp2 = required(UnaryExpr(in)).single();
 				Expr newExp = new Expr(Val.SINGLE,false);
@@ -951,7 +951,7 @@
 				newExp.add( ")" );
 				exp = newExp;
 			} else if( Mod() ) {
-				Spaces(in);
+				Spaces();
 				exp = exp.single();
 				Expr exp2 = required(UnaryExpr(in)).single();
 				Expr newExp = new Expr(Val.SINGLE,false);
@@ -975,7 +975,7 @@
 	private Expr UnaryExpr(In in) throws ParseException {
 		parser.begin();
 		if( parser.match('#') ) {
-			Spaces(in);
+			Spaces();
 			Expr exp = required(UnaryExpr(in)).single();
 			Expr newExp = new Expr(Val.SINGLE,false);
 			newExp.add( "LuanImpl.len(luan," );
@@ -984,7 +984,7 @@
 			return parser.success(newExp);
 		}
 		if( Minus() ) {
-			Spaces(in);
+			Spaces();
 			Expr exp = required(UnaryExpr(in)).single();
 			Expr newExp = new Expr(Val.SINGLE,false);
 			newExp.add( "LuanImpl.unm(luan," );
@@ -992,8 +992,8 @@
 			newExp.add( ")" );
 			return parser.success(newExp);
 		}
-		if( Keyword("not",in) ) {
-			Spaces(in);
+		if( Keyword("not") ) {
+			Spaces();
 			Expr exp = required(UnaryExpr(in)).single();
 			Expr newExp = new Expr(Val.SINGLE,false);
 			newExp.add( "!Luan.checkBoolean(" );
@@ -1013,7 +1013,7 @@
 		if( exp1==null )
 			return parser.failure(null);
 		if( parser.match('^') ) {
-			Spaces(in);
+			Spaces();
 			Expr exp2 = required(PowExpr(in));
 			Expr newExp = new Expr(Val.SINGLE,false);
 			newExp.add( "LuanImpl.pow(luan," );
@@ -1034,14 +1034,14 @@
 		exp = VarExp(in);
 		if( exp != null )
 			return parser.success(exp);
-		exp = VarArgs(in);
+		exp = VarArgs();
 		if( exp != null )
 			return parser.success(exp);
 		return parser.failure(null);
 	}
 
 	private Expr FunctionExpr(In in) throws ParseException {
-		if( !Keyword("function",in) )
+		if( !Keyword("function") )
 			return null;
 		return RequiredFunction(in);
 	}
@@ -1049,58 +1049,57 @@
 	private Expr RequiredFunction(In in) throws ParseException {
 		parser.begin();
 		RequiredMatch('(');
-		In inParens = in.parens();
-		Spaces(inParens);
+		Spaces();
 		frame = new Frame(frame);
 		Stmts stmt = new Stmts();
-		List<String> names = NameList(in);
+		List<String> names = NameList();
 		if( names != null ) {
 			Expr args = new Expr(Val.ARRAY,false);
 			args.add( "args" );
 			stmt.addAll( makeLocalSetStmt(names,args) );
 			if( parser.match(',') ) {
-				Spaces(inParens);
+				Spaces();
 				if( !parser.match("...") )
 					throw parser.exception();
-				Spaces(inParens);
+				Spaces();
 				frame.isVarArg = true;
-				stmt.add( "final Object[] varArgs = LuanImpl.varArgs(args," + names.size() + ");\n" );
+				stmt.add( "final Object[] varArgs = LuanImpl.varArgs(args," + names.size() + ");  " );
 			}
 		} else if( parser.match("...") ) {
-			Spaces(inParens);
+			Spaces();
 			frame.isVarArg = true;
-			stmt.add( "final Object[] varArgs = LuanImpl.varArgs(args,0);\n" );
+			stmt.add( "final Object[] varArgs = LuanImpl.varArgs(args,0);  " );
 		}
 		RequiredMatch(')');
-		Spaces(in);
+		Spaces();
 		Stmts block = RequiredBlock();
 		stmt.addAll( block );
 		stmt.hasReturn = block.hasReturn;
+		Expr fnDef = newFnExpStr(stmt);
 		RequiredKeyword("end",in);
-		Expr fnDef = newFnExpStr(stmt);
 		frame = frame.parent;
 		return parser.success(fnDef);
 	}
 
-	private Expr VarArgs(In in) throws ParseException {
+	private Expr VarArgs() throws ParseException {
 		parser.begin();
 		if( !frame.isVarArg || !parser.match("...") )
 			return parser.failure(null);
-		Spaces(in);
+		Spaces();
 		Expr exp = new Expr(Val.ARRAY,false);
 		exp.add("varArgs");
 		return parser.success(exp);
 	}
 
-	private Expr TableExpr(In in) throws ParseException {
+	private Expr TableExpr() throws ParseException {
 		parser.begin();
 		if( !parser.match('{') )
 			return parser.failure(null);
-		Spaces(In.NOTHING);
+		Spaces();
 		List<Expr> builder = new ArrayList<Expr>();
 		Field(builder);
 		while( FieldSep() ) {
-			Spaces(In.NOTHING);
+			Spaces();
 			Field(builder);
 		}
 		Expr exp = TemplateExpressions(In.NOTHING);
@@ -1108,7 +1107,7 @@
 			builder.add(exp);
 		if( !parser.match('}') )
 			throw parser.exception("Expected table element or '}'");
-		Spaces(in);
+		Spaces();
 		exp = new Expr(Val.SINGLE,false);
 		exp.add( "LuanImpl.table(" );
 		exp.addAll( expString(builder).array() );
@@ -1124,9 +1123,9 @@
 		parser.begin();
 		Expr exp = SubExpr(In.NOTHING);
 		if( exp==null )
-			exp = NameExpr(In.NOTHING);
+			exp = NameExpr();
 		if( exp!=null && parser.match('=') ) {
-			Spaces(In.NOTHING);
+			Spaces();
 			Expr val = RequiredExpr(In.NOTHING).single();
 			Expr newExp = new Expr(Val.SINGLE,false);
 			newExp.add( "new TableField(" );
@@ -1165,21 +1164,20 @@
 
 	private Var VarStart(In in) throws ParseException {
 		if( parser.match('(') ) {
-			In inParens = in.parens();
-			Spaces(inParens);
-			Expr exp = RequiredExpr(inParens).single();
+			Spaces();
+			Expr exp = RequiredExpr(in).single();
 			RequiredMatch(')');
-			Spaces(in);
+			Spaces();
 			return exprVar(exp);
 		}
-		String name = Name(in);
+		String name = Name();
 		if( name != null )
 			return nameVar(name);
 		Expr exp;
-		exp = TableExpr(in);
+		exp = TableExpr();
 		if( exp != null )
 			return exprVar(exp);
-		exp = Literal(in);
+		exp = Literal();
 		if( exp != null )
 			return exprVar(exp);
 		return null;
@@ -1191,8 +1189,8 @@
 		if( exp2 != null )
 			return parser.success(indexVar(exp1,exp2));
 		if( parser.match('.') ) {
-			Spaces(in);
-			exp2 = NameExpr(in);
+			Spaces();
+			exp2 = NameExpr();
 			if( exp2!=null )
 				return parser.success(indexVar(exp1,exp2));
 			return parser.failure(null);
@@ -1242,7 +1240,7 @@
 					stmt.addAll( sym.exp() );
 					stmt.add( " = " );
 					stmt.addAll( val.single() );
-					stmt.add( ";\n" );
+					stmt.add( ";  " );
 					return stmt;
 				}
 				Expr envExpr = env();
@@ -1289,7 +1287,7 @@
 				stmt.addAll( key.single() );
 				stmt.add( "," );
 				stmt.addAll( val.single() );
-				stmt.add( ");\n" );
+				stmt.add( ");  " );
 				return stmt;
 			}
 		};
@@ -1305,31 +1303,23 @@
 	private boolean args(In in,List<Expr> builder) throws ParseException {
 		parser.begin();
 		if( parser.match('(') ) {
-			In inParens = in.parens();
-			Spaces(inParens);
-			ExpList(inParens,builder);  // optional
+			Spaces();
+			ExpList(in,builder);  // optional
 			if( !parser.match(')') )
 				throw parser.exception("Expression or ')' expected");
-			Spaces(in);
+			Spaces();
 			return parser.success();
 		}
-		Expr exp = TableExpr(in);
+		Expr exp = TableExpr();
 		if( exp != null ) {
 			builder.add(exp);
 			return parser.success();
 		}
-		String s = StringLiteral(in);
+		String s = StringLiteral();
 		if( s != null ) {
 			builder.add( constExpStr(s) );
 			return parser.success();
 		}
-/*
-		Expressions exps = TemplateExpressions(in);
-		if( exps != null ) {
-			builder.add(exps);
-			return parser.success();
-		}
-*/
 		return parser.failure();
 	}
 
@@ -1350,7 +1340,7 @@
 			return parser.failure();
 		builder.add(exp);
 		while( parser.match(',') ) {
-			Spaces(in);
+			Spaces();
 			exp = TemplateExpressions(in);
 			if( exp != null ) {
 				builder.add(exp);
@@ -1365,30 +1355,30 @@
 		parser.begin();
 		if( !parser.match('[') || parser.test("[") || parser.test("=") )
 			return parser.failure(null);
-		Spaces(In.NOTHING);
+		Spaces();
 		Expr exp = RequiredExpr(In.NOTHING).single();
 		RequiredMatch(']');
-		Spaces(in);
+		Spaces();
 		return parser.success(exp);
 	}
 
-	private Expr NameExpr(In in) throws ParseException {
+	private Expr NameExpr() throws ParseException {
 		parser.begin();
-		String name = Name(in);
+		String name = Name();
 		if( name==null )
 			return parser.failure(null);
 		return parser.success(constExpStr(name));
 	}
 
-	private String RequiredName(In in) throws ParseException {
+	private String RequiredName() throws ParseException {
 		parser.begin();
-		String name = Name(in);
+		String name = Name();
 		if( name==null )
 			throw parser.exception("Name expected");
 		return parser.success(name);
 	}
 
-	private String Name(In in) throws ParseException {
+	private String Name() throws ParseException {
 		int start = parser.begin();
 		if( !NameFirstChar() )
 			return parser.failure(null);
@@ -1396,7 +1386,7 @@
 		String match = parser.textFrom(start);
 		if( keywords.contains(match) )
 			return parser.failure(null);
-		Spaces(in);
+		Spaces();
 		return parser.success(match);
 	}
 
@@ -1419,15 +1409,15 @@
 	}
 
 	private void RequiredKeyword(String keyword,In in) throws ParseException {
-		if( !Keyword(keyword,in) )
+		if( !Keyword(keyword) )
 			throw parser.exception("'"+keyword+"' expected");
 	}
 
-	private boolean Keyword(String keyword,In in) throws ParseException {
+	private boolean Keyword(String keyword) throws ParseException {
 		parser.begin();
 		if( !parser.match(keyword) || NameChar() )
 			return parser.failure();
-		Spaces(in);
+		Spaces();
 		return parser.success();
 	}
 
@@ -1456,20 +1446,20 @@
 		"while"
 	));
 
-	private Expr Literal(In in) throws ParseException {
+	private Expr Literal() throws ParseException {
 		parser.begin();
-		if( NilLiteral(in) ) {
+		if( NilLiteral() ) {
 			Expr exp = new Expr(Val.SINGLE,false);
 			exp.add( "null" );
 			return parser.success(exp);
 		}
-		Boolean b = BooleanLiteral(in);
+		Boolean b = BooleanLiteral();
 		if( b != null ) {
 			Expr exp = new Expr(Val.SINGLE,false);
 			exp.add( b.toString() );
 			return parser.success(exp);
 		}
-		Number n = NumberLiteral(in);
+		Number n = NumberLiteral();
 		if( n != null ) {
 			String s = n.toString();
 			if( n instanceof Long )
@@ -1478,13 +1468,18 @@
 			exp.add( s );
 			return parser.success(exp);
 		}
-		String s = StringLiteral(in);
+		String s = StringLiteral();
 		if( s != null )
 			return parser.success(constExpStr(s));
 		return parser.failure(null);
 	}
 
 	private Expr constExpStr(String s) {
+		int n = 0;
+		int from = 0;
+		while( (from = s.indexOf('\n',from) + 1) != 0 ) {
+			n++;
+		}
 		s = s
 			.replace("\\","\\\\")
 			.replace("\"","\\\"")
@@ -1493,24 +1488,27 @@
 			.replace("\t","\\t")
 			.replace("\b","\\b")
 		;
+		s = "\"" + s + "\"";
+		while( n-- > 0 )
+			s += "\n";
 		Expr exp = new Expr(Val.SINGLE,false);
-		exp.add( "\""+s+"\"" );
+		exp.add( s );
 		return exp;
 	}
 
-	private boolean NilLiteral(In in) throws ParseException {
-		return Keyword("nil",in);
+	private boolean NilLiteral() throws ParseException {
+		return Keyword("nil");
 	}
 
-	private Boolean BooleanLiteral(In in) throws ParseException {
-		if( Keyword("true",in) )
+	private Boolean BooleanLiteral() throws ParseException {
+		if( Keyword("true") )
 			return true;
-		if( Keyword("false",in) )
+		if( Keyword("false") )
 			return false;
 		return null;
 	}
 
-	private Number NumberLiteral(In in) throws ParseException {
+	private Number NumberLiteral() throws ParseException {
 		parser.begin();
 		Number n;
 		if( parser.matchIgnoreCase("0x") ) {
@@ -1520,7 +1518,7 @@
 		}
 		if( n==null || NameChar() )
 			return parser.failure(null);
-		Spaces(in);
+		Spaces();
 		return parser.success(n);
 	}
 
@@ -1620,14 +1618,14 @@
 		return Digit() || parser.anyOf("abcdefABCDEF");
 	}
 
-	private String StringLiteral(In in) throws ParseException {
+	private String StringLiteral() throws ParseException {
 		String s;
 		if( (s=QuotedString('"'))==null
 			&& (s=QuotedString('\''))==null
 			&& (s=LongString())==null
 		)
 			return null;
-		Spaces(in);
+		Spaces();
 		return s;
 	}
 
@@ -1689,13 +1687,15 @@
 			if( Digit() ) Digit();  // optional
 			return parser.success((char)Integer.parseInt(parser.textFrom(start)));
 		}
-		if( EndOfLine() )
+		if( EndOfLine() ) {
+			parser.sb().setLength(parser.sb().length()-1);
 			return parser.success('\n');
+		}
 		return parser.failure(null);
 	}
 
-	private void Spaces(In in) throws ParseException {
-		while( parser.anyOf(" \t") || Comment() || ContinueOnNextLine() || in.parens && EndOfLine() );
+	private void Spaces() throws ParseException {
+		while( parser.anyOf(" \t") || Comment() || ContinueOnNextLine() );
 	}
 
 	private boolean ContinueOnNextLine() {
@@ -1723,9 +1723,10 @@
 		if( !parser.match('[') )
 			return parser.failure();
 		while( !LongBracketsEnd(nEquals) ) {
-			if( !parser.anyChar() )
+			if( !(EndOfLine() || parser.anyChar()) )
 				throw parser.exception("Unclosed comment");
 		}
+		parser.upSb();
 		return parser.success();
 	}
 
@@ -1744,7 +1745,25 @@
 
 
 
-	private static class ParseList extends ArrayList {
+	private class ParseList extends ArrayList {
+
+		void addNewLines() {
+			if( parser.sb().length() > 0 ) {
+				add( parser.sb().toString() );
+				parser.sb().setLength(0);
+/*
+if( parser.sourceName.equals("stdin") ) {
+	StringWriter sw = new StringWriter();
+	new Throwable().printStackTrace(new PrintWriter(sw,true));
+//	add(sw.toString());
+}
+*/
+			}
+		}
+
+		ParseList() {
+			addNewLines();
+		}
 
 		@Override public boolean add(Object obj) {
 			if( obj instanceof List )  throw new RuntimeException();
@@ -1770,7 +1789,7 @@
 
 	private enum Val { SINGLE, ARRAY }
 
-	private static class Expr extends ParseList {
+	private class Expr extends ParseList {
 		final Val valType;
 		final boolean isStmt;
 
@@ -1837,7 +1856,7 @@
 		}
 	}
 
-	private static class Stmts extends ParseList {
+	private class Stmts extends ParseList {
 		boolean hasReturn = false;
 	}
 
@@ -1860,50 +1879,49 @@
 
 	private String toFnString(Stmts stmts,List<UpSym> upValueSymbols,String className) {
 		if( !stmts.hasReturn )
-			stmts.add( "return LuanFunction.NOTHING;\n" );
+			stmts.add( "\nreturn LuanFunction.NOTHING;" );
 		return ""
-			+"package luan.impl;\n"
-			+"import luan.Luan;\n"
-			+"import luan.LuanFunction;\n"
-			+"import luan.LuanState;\n"
-			+"import luan.LuanJava;\n"
-			+"import luan.LuanException;\n"
-			+"import luan.modules.PackageLuan;\n"
-			+"\n"
-			+"public class " + className +" extends Closure {\n"
-			+"	public "+className+"(LuanJava java) throws LuanException {\n"
-			+"		super("+upValueSymbols.size()+",java);\n"
-			+		init(upValueSymbols)
-			+"	}\n"
-			+"\n"
-			+"	@Override public Object doCall(LuanState luan,Object[] args) throws LuanException {\n"
-			+"		Object t;\n"
-			+"		Object[] a;\n"
-			+"		" + stmts
-			+"	}\n"
+			+"package luan.impl;  "
+			+"import luan.Luan;  "
+			+"import luan.LuanFunction;  "
+			+"import luan.LuanState;  "
+			+"import luan.LuanJava;  "
+			+"import luan.LuanException;  "
+			+"import luan.modules.PackageLuan;  "
+
+			+"public class " + className +" extends Closure {  "
+				+"public "+className+"(LuanJava java) throws LuanException {  "
+					+"super("+upValueSymbols.size()+",java);  "
+					+ init(upValueSymbols)
+				+"}  "
+
+				+"@Override public Object doCall(LuanState luan,Object[] args) throws LuanException {  "
+					+"Object t;  "
+					+"Object[] a;  "
+					+ stmts
+				+"\n}  "
 			+"}\n"
 		;
 	}
 
-	private static Expr toFnExpStr(Stmts stmt,List<UpSym> upValueSymbols) {
+	private Expr toFnExpStr(Stmts stmt,List<UpSym> upValueSymbols) {
+		stmt.addNewLines();
 		if( !stmt.hasReturn )
-			stmt.add( "return LuanFunction.NOTHING;\n" );
+			stmt.add( "return LuanFunction.NOTHING;  " );
 		Expr exp = new Expr(Val.SINGLE,false);
 		exp.add( ""
-			+"\n"
-			+"new Closure("+upValueSymbols.size()+",java) {\n"
-			+"{\n"
-			+ init(upValueSymbols)
-			+"}\n"
-			+"	@Override public Object doCall(LuanState luan,Object[] args) throws LuanException {\n"
-			+"		Object t;\n"
-			+"		Object[] a;\n"
-			+"		"
+			+"new Closure("+upValueSymbols.size()+",java) {  "
+				+"{  "
+				+ init(upValueSymbols)
+				+"}  "
+				+"@Override public Object doCall(LuanState luan,Object[] args) throws LuanException {  "
+					+"Object t;  "
+					+"Object[] a;  "
 		);
 		exp.addAll( stmt );
 		exp.add( ""
-			+"	}\n"
-			+"}\n"
+				+"}  "
+			+"}  "
 		);
 		return exp;
 	}
diff -r 49f3d290bebd -r 43522473599d core/src/luan/impl/Parser.java
--- a/core/src/luan/impl/Parser.java	Wed Apr 13 16:24:48 2016 -0600
+++ b/core/src/luan/impl/Parser.java	Thu Apr 14 15:19:25 2016 -0600
@@ -2,11 +2,17 @@
 
 
 final class Parser {
+
+	private static class Frame {
+		int i;
+		StringBuilder sb;
+	}
+
 //	private final LuanSource src;
 	public final String sourceName;
 	public final String text;
 	private final int len;
-	private int[] stack = new int[256];
+	private Frame[] stack = new Frame[256];
 	private int frame = 0;
 	private int iHigh;
 
@@ -15,31 +21,37 @@
 		this.sourceName = sourceName;
 		this.text = text;
 		this.len = text.length();
+		stack[0] = new Frame();
 	}
 
 	private int i() {
-		return stack[frame];
+		return stack[frame].i;
 	}
 
 	private void i(int i) {
-		stack[frame] += i;
-		if( iHigh < stack[frame] )
-			iHigh = stack[frame];
+		Frame f = stack[frame];
+		f.i += i;
+		if( iHigh < f.i )
+			iHigh = f.i;
 	}
 
 	public int begin() {
 		frame++;
 		if( frame == stack.length ) {
-			int[] a = new int[2*frame];
+			Frame[] a = new Frame[2*frame];
 			System.arraycopy(stack,0,a,0,frame);
 			stack = a;
 		}
-		stack[frame] = stack[frame-1];
+		Frame f = new Frame();
+		f.i = stack[frame-1].i;
+		stack[frame] = f;
 		return i();
 	}
 
 	public void rollback() {
-		stack[frame] = stack[frame-1];
+		Frame f = stack[frame];
+		f.i = stack[frame-1].i;
+		f.sb = null;
 	}
 
 	public <T> T success(T t) {
@@ -48,8 +60,10 @@
 	}
 
 	public boolean success() {
+		Frame f = stack[frame];
+		if( f.sb != null && f.sb.length() > 0 )  throw new RuntimeException("sb not emtpy");
 		frame--;
-		stack[frame] = stack[frame+1];
+		stack[frame].i = f.i;
 		return true;
 	}
 
@@ -71,6 +85,26 @@
 		return exception("Invalid input");
 	}
 
+	public StringBuilder sb() {
+		Frame f = stack[frame];
+		if( f.sb == null )
+			f.sb = new StringBuilder();
+		return f.sb;
+	}
+
+	public void upSb() {
+		Frame f = stack[frame];
+		StringBuilder sb = f.sb;
+		if( sb != null && sb.length() > 0 ) {
+			Frame fUp = stack[frame-1];
+			if( fUp.sb == null )
+				fUp.sb = sb;
+			else
+				fUp.sb.append(sb.toString());
+			f.sb = null;
+		}
+	}
+
 	public int currentIndex() {
 		return i();
 	}