| /* |
| * $Id: LuaConsole.java 79 2012-01-08 11:08:32Z andre@naef.com $ |
| * See LICENSE.txt for license terms. |
| */ |
| |
| package com.naef.jnlua.console; |
| |
| import java.io.BufferedReader; |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.io.OutputStreamWriter; |
| |
| import com.naef.jnlua.LuaException; |
| import com.naef.jnlua.LuaRuntimeException; |
| import com.naef.jnlua.LuaState; |
| |
| /** |
| * A simple Lua console. |
| * |
| * <p> |
| * The console collects input until a line with the sole content of the word |
| * <i>go</i> is encountered. At that point, the collected input is run as a Lua |
| * chunk. If the Lua chunk loads and runs successfully, the console displays the |
| * returned values of the chunk as well as the execution time based on a |
| * <code>System.nanoTime()</code> measurement. Otherwise, the console shows the |
| * error that has occurred. |
| * </p> |
| * |
| * <p> |
| * Expressions can be printed by prepending <i>=</i> to the expression at the |
| * beginning of a chunk. The console translates <i>=</i> into |
| * <code>return</code> followed by a space and executes the chunk immediately. |
| * No separate <i>go</i> is required. Therefore, expressions printed this way |
| * must be entered on a single line. |
| * </p> |
| */ |
| public class LuaConsole { |
| // -- Static |
| private static final String[] EMPTY_ARGS = new String[0]; |
| |
| /** |
| * Main routine. |
| * |
| * @param args |
| * the command line arguments |
| */ |
| public static void main(String[] args) { |
| LuaConsole luaConsole = new LuaConsole(args); |
| luaConsole.run(); |
| System.exit(0); |
| } |
| |
| // -- State |
| private LuaState luaState; |
| |
| // -- Construction |
| /** |
| * Creates a new instance. |
| */ |
| public LuaConsole() { |
| this(EMPTY_ARGS); |
| } |
| |
| /** |
| * Creates a new instance with the specified command line arguments. The |
| * arguments are passed to Lua as the <code>argv</code> global variable. |
| * |
| * @param args |
| */ |
| public LuaConsole(String[] args) { |
| luaState = new LuaState(); |
| |
| // Process arguments |
| luaState.newTable(args.length, 0); |
| for (int i = 0; i < args.length; i++) { |
| luaState.pushString(args[i]); |
| luaState.rawSet(-2, i + 1); |
| } |
| luaState.setGlobal("argv"); |
| |
| // Open standard libraries |
| luaState.openLibs(); |
| |
| // Set buffer mode |
| luaState.load("io.stdout:setvbuf(\"no\")", "=consoleInitStdout"); |
| luaState.call(0, 0); |
| luaState.load("io.stderr:setvbuf(\"no\")", "=consoleInitStderr"); |
| luaState.call(0, 0); |
| } |
| |
| // -- Properties |
| /** |
| * Returns the Lua state of this console. |
| * |
| * @return the Lua state |
| */ |
| public LuaState getLuaState() { |
| return luaState; |
| } |
| |
| // -- Operations |
| /** |
| * Runs the console. |
| */ |
| public void run() { |
| // Banner |
| System.out.println(String.format("JNLua %s Console using Lua %s.", |
| LuaState.VERSION, LuaState.LUA_VERSION)); |
| System.out.print("Type 'go' on an empty line to evaluate a chunk. "); |
| System.out.println("Type =<expression> to print an expression."); |
| |
| // Prepare reader |
| BufferedReader bufferedReader = new BufferedReader( |
| new InputStreamReader(System.in)); |
| try { |
| // Process chunks |
| chunk: while (true) { |
| ByteArrayOutputStream out = new ByteArrayOutputStream(); |
| OutputStreamWriter outWriter = new OutputStreamWriter(out, |
| "UTF-8"); |
| boolean firstLine = true; |
| |
| // Process lines |
| while (true) { |
| String line = bufferedReader.readLine(); |
| if (line == null) { |
| break chunk; |
| } |
| if (line.equals("go")) { |
| outWriter.flush(); |
| InputStream in = new ByteArrayInputStream(out |
| .toByteArray()); |
| runChunk(in); |
| continue chunk; |
| } |
| if (firstLine && line.startsWith("=")) { |
| outWriter.write("return " + line.substring(1)); |
| outWriter.flush(); |
| InputStream in = new ByteArrayInputStream(out |
| .toByteArray()); |
| runChunk(in); |
| continue chunk; |
| } |
| outWriter.write(line); |
| outWriter.write('\n'); |
| firstLine = false; |
| } |
| } |
| } catch (IOException e) { |
| System.out.print("IO error: "); |
| System.out.print(e.getMessage()); |
| System.out.println(); |
| } |
| } |
| |
| /** |
| * Runs a chunk of Lua code from an input stream. |
| */ |
| protected void runChunk(InputStream in) throws IOException { |
| try { |
| long start = System.nanoTime(); |
| luaState.setTop(0); |
| luaState.load(in, "=console", "t"); |
| luaState.call(0, LuaState.MULTRET); |
| long stop = System.nanoTime(); |
| for (int i = 1; i <= luaState.getTop(); i++) { |
| if (i > 1) { |
| System.out.print(", "); |
| } |
| switch (luaState.type(i)) { |
| case BOOLEAN: |
| System.out.print(Boolean.valueOf(luaState.toBoolean(i))); |
| break; |
| case NUMBER: |
| case STRING: |
| System.out.print(luaState.toString(i)); |
| break; |
| default: |
| System.out.print(luaState.typeName(i)); |
| } |
| } |
| System.out.print("\t#msec="); |
| System.out.print(String.format("%.3f", (stop - start) / 1000000.0)); |
| System.out.println(); |
| } catch (LuaRuntimeException e) { |
| e.printLuaStackTrace(); |
| } catch (LuaException e) { |
| System.err.println(e.getMessage()); |
| } |
| } |
| } |