changeset 12:9cea1aea5eef

CmdLine can run files git-svn-id: https://luan-java.googlecode.com/svn/trunk@13 21e917c8-12df-6dd8-5cb6-c86387c605b9
author fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9>
date Fri, 23 Nov 2012 10:37:40 +0000
parents b7d7069fee58
children 3b22ffbdb83a
files src/luan/CmdLine.java src/luan/LuaFunction.java src/luan/LuaJavaFunction.java src/luan/interp/FnCall.java src/luan/interp/LuaParser.java src/luan/interp/Stmt.java src/luan/lib/BasicLib.java
diffstat 7 files changed, 207 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/src/luan/CmdLine.java	Thu Nov 22 10:51:56 2012 +0000
+++ b/src/luan/CmdLine.java	Fri Nov 23 10:37:40 2012 +0000
@@ -1,39 +1,54 @@
 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();
+		BasicLib.register(lua);
+		boolean interactive = false;
+		int i = 0;
+		while( i < args.length ) {
+			String arg = args[i];
+			if( !arg.startsWith("-") )
+				break;
+			if( arg.equals("-i") ) {
+				interactive = true;
+			} else {
+				throw new RuntimeException("invalid option: "+arg);
+			}
+			i++;
+		}
+		if( i == args.length ) {
+			interactive = true;
+		} else {
+			String file = args[i++];
+			try {
+				LuaFunction fn = BasicLib.loadFile(file);
+				fn.call(lua);
+			} catch(LuaException e) {
+				System.out.println(e.getMessage());
+				return;
+			}
+		}
+		if( interactive )
+			interactive(lua);
+	}
+
+	static void interactive(LuaState lua) {
 		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);
-				}
+			try {
+				LuaFunction fn = BasicLib.load(input);
+				Object[] rtn = fn.call(lua);
+				if( rtn.length > 0 )
+					BasicLib.print(rtn);
+			} catch(LuaException e) {
+				System.out.println(e.getMessage());
 			}
 		}
 	}
--- a/src/luan/LuaFunction.java	Thu Nov 22 10:51:56 2012 +0000
+++ b/src/luan/LuaFunction.java	Fri Nov 23 10:37:40 2012 +0000
@@ -3,7 +3,9 @@
 
 public abstract class LuaFunction {
 
-	public abstract Object[] call(Object... args);
+	public abstract Object[] call(LuaState lua,Object... args) throws LuaException;
+
+	public static final Object[] EMPTY_RTN = new Object[0];
 
 	@Override public String toString() {
 		return "function: " + Integer.toHexString(hashCode());
--- a/src/luan/LuaJavaFunction.java	Thu Nov 22 10:51:56 2012 +0000
+++ b/src/luan/LuaJavaFunction.java	Fri Nov 23 10:37:40 2012 +0000
@@ -25,7 +25,7 @@
 		}
 	}
 
-	@Override public Object[] call(Object... args) {
+	@Override public Object[] call(LuaState lua,Object... args) {
 		args = fixArgs(args);
 		Object rtn;
 		try {
@@ -76,15 +76,19 @@
 		public Object[] convert(Object obj);
 	}
 
-	private static final Object[] EMPTY = new Object[0];
-
 	private static final RtnConverter RTN_EMPTY = new RtnConverter() {
 		public Object[] convert(Object obj) {
-			return EMPTY;
+			return EMPTY_RTN;
 		}
 	};
 
-	private static final RtnConverter RTN_SAME = new RtnConverter() {
+	private static final RtnConverter RTN_ARRAY = new RtnConverter() {
+		public Object[] convert(Object obj) {
+			return (Object[])obj;
+		}
+	};
+
+	private static final RtnConverter RTN_ONE = new RtnConverter() {
 		public Object[] convert(Object obj) {
 			return new Object[]{obj};
 		}
@@ -112,7 +116,9 @@
 			|| rtnType == Double.TYPE
 		)
 			return RTN_NUMBER;
-		return RTN_SAME;
+		if( rtnType.isArray() )
+			return RTN_ARRAY;
+		return RTN_ONE;
 	}
 
 
--- a/src/luan/interp/FnCall.java	Thu Nov 22 10:51:56 2012 +0000
+++ b/src/luan/interp/FnCall.java	Fri Nov 23 10:37:40 2012 +0000
@@ -19,6 +19,6 @@
 
 	@Override public List eval(LuaState lua) throws LuaException {
 		LuaFunction fn = Lua.checkFunction( fnExpr.eval(lua) );
-		return Arrays.asList( fn.call( args.eval(lua).toArray() ) );
+		return Arrays.asList( fn.call( lua, args.eval(lua).toArray() ) );
 	}
 }
--- a/src/luan/interp/LuaParser.java	Thu Nov 22 10:51:56 2012 +0000
+++ b/src/luan/interp/LuaParser.java	Fri Nov 23 10:37:40 2012 +0000
@@ -1,5 +1,8 @@
 package luan.interp;
 
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Arrays;
 import java.util.List;
 import java.util.ArrayList;
 import java.util.Scanner;
@@ -20,14 +23,64 @@
 		return Sequence(
 			Spaces(),
 			FirstOf(
-				Sequence( Expressions(), EOI ),
-				Sequence( Stmt(), EOI )
+				Sequence( ExpList(), EOI ),
+				Sequence( Chunk(), EOI )
 			)
 		);
 	}
 
+	Rule Chunk() {
+		return Sequence(
+			push(new ArrayList<Stmt>()),
+			Optional( Stmt() ),
+			ZeroOrMore(
+				StmtSep(),
+				Optional( Stmt() )
+			),
+			push( newChunk() )
+		);
+	}
+
+	boolean addStmt() {
+		Stmt stmt = (Stmt)pop();
+		@SuppressWarnings("unchecked")
+		List<Stmt> stmts = (List<Stmt>)peek();
+		stmts.add(stmt);
+		return true;
+	}
+
+	Stmt newChunk() {
+		@SuppressWarnings("unchecked")
+		List<Stmt> stmts = (List<Stmt>)peek();
+		switch( stmts.size() ) {
+		case 0:
+			return Stmt.EMPTY;
+		case 1:
+			return stmts.get(0);
+		default:
+			return new Block(stmts.toArray(new Stmt[0]));
+		}
+	}
+
+	Rule StmtSep() {
+		return Sequence( OneOrMore(AnyOf(";\r\n")), Spaces() );
+	}
+
 	Rule Stmt() {
-		return SetStmt();
+		return Sequence(
+			FirstOf(
+				SetStmt(),
+				ExpressionsStmt()
+			),
+			addStmt()
+		);
+	}
+
+	Rule ExpressionsStmt() {
+		return Sequence(
+			ExpList(),
+			push( new ExpressionsStmt((Expressions)pop()) )
+		);
 	}
 
 	Rule SetStmt() {
@@ -332,7 +385,7 @@
 					FirstOf( NameStart(), Digit() )
 				)
 			),
-			push( new ConstExpr(match()) ),
+			pushNameExpr(),
 			Spaces()
 		);
 	}
@@ -345,6 +398,38 @@
 		);
 	}
 
+	boolean pushNameExpr() {
+		String name = match();
+		if( keywords.contains(name) )
+			return false;
+		return push( new ConstExpr(name) );
+	}
+
+	private static final Set<String> keywords = new HashSet<String>(Arrays.asList(
+		"and",
+		"break",
+		"do",
+		"else",
+		"elseif",
+		"end",
+		"false",
+		"for",
+		"function",
+		"goto",
+		"if",
+		"in",
+		"local",
+		"nil",
+		"not",
+		"or",
+		"repeat",
+		"return",
+		"then",
+		"true",
+		"until",
+		"while"
+	));
+
 	Rule LiteralExpr() {
 		return Sequence(
 			Literal(), Spaces(),
@@ -493,10 +578,16 @@
 		return true;
 	}
 
-	public Rule Spaces() {
+	Rule Spaces() {
 		return ZeroOrMore(AnyOf(" \t"));
 	}
 
+	// for debugging
+	boolean print(String s) {
+		System.out.println(s);
+		return true;
+	}
+
 	// for testing
 	public static void main(String[] args) throws Exception {
 		LuaParser parser = Parboiled.createParser(LuaParser.class);
--- a/src/luan/interp/Stmt.java	Thu Nov 22 10:51:56 2012 +0000
+++ b/src/luan/interp/Stmt.java	Fri Nov 23 10:37:40 2012 +0000
@@ -6,4 +6,8 @@
 
 public interface Stmt {
 	public void eval(LuaState lua) throws LuaException;
+
+	static final Stmt EMPTY = new Stmt() {
+		public void eval(LuaState lua) {}
+	};
 }
--- a/src/luan/lib/BasicLib.java	Thu Nov 22 10:51:56 2012 +0000
+++ b/src/luan/lib/BasicLib.java	Fri Nov 23 10:37:40 2012 +0000
@@ -1,13 +1,27 @@
 package luan.lib;
 
+import java.io.FileReader;
+import java.io.IOException;
+import org.parboiled.Parboiled;
+import org.parboiled.errors.ErrorUtils;
+import org.parboiled.parserunners.ReportingParseRunner;
+import org.parboiled.parserunners.TracingParseRunner;
+import org.parboiled.support.ParsingResult;
 import luan.Lua;
+import luan.LuaState;
 import luan.LuaTable;
+import luan.LuaFunction;
 import luan.LuaJavaFunction;
+import luan.LuaException;
+import luan.interp.LuaParser;
+import luan.interp.Expressions;
+import luan.interp.Stmt;
 
 
 public class BasicLib {
 
-	public static void register(LuaTable t) {
+	public static void register(LuaState lua) {
+		LuaTable t = lua.env();
 		add( t, "print", new Object[0].getClass() );
 		add( t, "type", Object.class );
 	}
@@ -33,4 +47,42 @@
 		return Lua.type(obj);
 	}
 
+	public static LuaFunction load(String ld) throws LuaException {
+		LuaParser parser = Parboiled.createParser(LuaParser.class);
+		ParsingResult<?> result = new ReportingParseRunner(parser.Target()).run(ld);
+		if( result.hasErrors() )
+			throw new LuaException( ErrorUtils.printParseErrors(result) );
+		Object resultValue = result.resultValue;
+		if( resultValue instanceof Expressions ) {
+			final Expressions expressions = (Expressions)resultValue;
+			return new LuaFunction() {
+				public Object[] call(LuaState lua,Object... args) throws LuaException {
+					return expressions.eval(lua).toArray();
+				}
+			};
+		}
+		final Stmt stmt = (Stmt)resultValue;
+		return new LuaFunction() {
+			public Object[] call(LuaState lua,Object... args) throws LuaException {
+				stmt.eval(lua);
+				return LuaFunction.EMPTY_RTN;
+			}
+		};
+	}
+
+	public static String readFile(String fileName) throws IOException {
+		StringBuilder sb = new StringBuilder();
+		FileReader in = new FileReader(fileName);
+		char[] buf = new char[8192];
+		int n;
+		while( (n=in.read(buf)) != -1 ) {
+			sb.append(buf,0,n);
+		}
+		return sb.toString();
+	}
+
+	public static LuaFunction loadFile(String fileName) throws LuaException,IOException {
+		return load(readFile(fileName));
+	}
+
 }