From e4882578f29ec83e2295c75f9ab145393a8d3d13 Mon Sep 17 00:00:00 2001 From: James Roseborough Date: Thu, 4 Oct 2007 23:51:39 +0000 Subject: [PATCH] Add "Java API" like "C API" for use with JavaFunctions. --- .../java/lua/addon/luacompat/LuaCompat.java | 28 +- .../java/lua/addon/luacompat/StrLib.java | 38 +- src/main/java/lua/Builtin.java | 4 +- src/main/java/lua/JavaFunction.java | 74 + src/main/java/lua/VM.java | 1355 ++++++++++++++++- src/main/java/lua/debug/DebugStackState.java | 4 +- src/main/java/lua/value/LFunction.java | 4 +- src/main/java/lua/value/LValue.java | 2 +- 8 files changed, 1392 insertions(+), 117 deletions(-) create mode 100644 src/main/java/lua/JavaFunction.java diff --git a/src/addon/java/lua/addon/luacompat/LuaCompat.java b/src/addon/java/lua/addon/luacompat/LuaCompat.java index 378adb74..b964dd16 100644 --- a/src/addon/java/lua/addon/luacompat/LuaCompat.java +++ b/src/addon/java/lua/addon/luacompat/LuaCompat.java @@ -219,7 +219,7 @@ public class LuaCompat extends LFunction { if ( t instanceof LTable ) { ( (LTable) t ).put( k, v ); } else { - vm.lua_error( "expected table" ); + vm.error( "expected table" ); } } break; case SETFENV: @@ -478,8 +478,8 @@ public class LuaCompat extends LFunction { private static boolean loadis(VM vm, InputStream is, String chunkname ) { try { vm.setResult(); - if ( 0 != vm.lua_load(is, chunkname) ) { - vm.setErrorResult( LNil.NIL, "cannot load "+chunkname+": "+vm.lua_tolvalue(-1) ); + if ( 0 != vm.load(is, chunkname) ) { + vm.setErrorResult( LNil.NIL, "cannot load "+chunkname+": "+vm.topointer(-1) ); return false; } else { return true; @@ -515,10 +515,10 @@ public class LuaCompat extends LFunction { private void dofile( VM vm ) { String filename = vm.getArgAsString(0); if ( loadfile( vm, filename ) ) { - int s = vm.lua_pcall(1, 0); + int s = vm.pcall(1, 0, 0); vm.setResult( LInteger.valueOf( s!=0? 1: 0 ) ); } else { - vm.lua_error("cannot open "+filename); + vm.error("cannot open "+filename); } } @@ -532,7 +532,7 @@ public class LuaCompat extends LFunction { // return true if loaded, false if error put onto stack private boolean load(VM vm, LValue chunkPartLoader, String chunkname) { if ( ! (chunkPartLoader instanceof Closure) ) { - vm.lua_error("not a closure: "+chunkPartLoader); + vm.error("not a closure: "+chunkPartLoader); } // load all the parts @@ -541,7 +541,7 @@ public class LuaCompat extends LFunction { try { while ( true ) { vm.setResult(c); - if ( 0 != vm.lua_pcall(0, 1) ) { + if ( 0 != vm.pcall(0, 1, 0) ) { vm.setErrorResult(LNil.NIL, vm.getArgAsString(0)); return false; } @@ -599,7 +599,7 @@ public class LuaCompat extends LFunction { // ======================== Module, Package loading ============================= public static void module( VM vm ) { - vm.lua_error( "module not implemented" ); + vm.error( "module not implemented" ); } /** @@ -635,9 +635,9 @@ public class LuaCompat extends LFunction { else { String s = modname.toJavaString(); if ( ! loadfile(vm, s+".luac") && ! loadfile(vm, s+".lua") ) - vm.lua_error( "not found: "+s ); - else if ( 0 == vm.lua_pcall(0, 1) ) { - LValue result = vm.lua_tolvalue( -1 ); + vm.error( "not found: "+s ); + else if ( 0 == vm.pcall(0, 1, 0) ) { + LValue result = vm.topointer( -1 ); if ( result != LNil.NIL ) LOADED.put(modname, result); else if ( ! LOADED.containsKey(modname) ) @@ -648,11 +648,11 @@ public class LuaCompat extends LFunction { } public static void loadlib( VM vm ) { - vm.lua_error( "loadlib not implemented" ); + vm.error( "loadlib not implemented" ); } public static void seeall( VM vm ) { - vm.lua_error( "seeall not implemented" ); + vm.error( "seeall not implemented" ); } @@ -683,7 +683,7 @@ public class LuaCompat extends LFunction { } vm.setResult( new LString( baos.toByteArray() ) ); } catch (IOException e) { - vm.lua_error(e.getMessage()); + vm.error(e.getMessage()); } } diff --git a/src/addon/java/lua/addon/luacompat/StrLib.java b/src/addon/java/lua/addon/luacompat/StrLib.java index 8af72705..edf4839b 100644 --- a/src/addon/java/lua/addon/luacompat/StrLib.java +++ b/src/addon/java/lua/addon/luacompat/StrLib.java @@ -68,7 +68,7 @@ public class StrLib { * TODO: port dumping code as optional add-on */ static void dump( VM vm ) { - vm.lua_error("dump() not supported"); + vm.error("dump() not supported"); } /** @@ -509,8 +509,8 @@ public class StrLib { lbuf.append( s.substring( soff, e ) ); } else { push_onecapture( b - '1', soff, e ); - lbuf.append( vm.lua_tolvalue( -1 ).luaAsString() ); - vm.lua_pop( 1 ); + lbuf.append( vm.topointer( -1 ).luaAsString() ); + vm.pop( 1 ); } } } @@ -523,25 +523,25 @@ public class StrLib { } else if ( repl instanceof LFunction ) { vm.push( repl ); int n = push_captures( true, soffset, end ); - vm.lua_call( n, 1 ); + vm.call( n, 1 ); } else if ( repl instanceof LTable ) { // Need to call push_onecapture here for the error checking push_onecapture( 0, soffset, end ); - LValue k = vm.lua_tolvalue( -1 ); - vm.lua_pop( 1 ); + LValue k = vm.topointer( -1 ); + vm.pop( 1 ); ((LTable) repl).luaGetTable( vm, repl, k ); } else { - vm.lua_error( "string/function/table expected" ); + vm.error( "string/function/table expected" ); return; } - repl = vm.lua_tolvalue( -1 ); + repl = vm.topointer( -1 ); if ( !repl.luaAsBoolean() ) { repl = s.substring( soffset, end ); } else if ( ! ( repl instanceof LString || repl instanceof LNumber ) ) { - vm.lua_error( "invalid replacement value (a "+repl.luaGetTypeName()+")" ); + vm.error( "invalid replacement value (a "+repl.luaGetTypeName()+")" ); } - vm.lua_pop( 1 ); + vm.pop( 1 ); lbuf.append( repl.luaAsString() ); } @@ -558,12 +558,12 @@ public class StrLib { if ( i == 0 ) { vm.push( s.substring( soff, end ) ); } else { - vm.lua_error( "invalid capture index" ); + vm.error( "invalid capture index" ); } } else { int l = clen[i]; if ( l == CAP_UNFINISHED ) { - vm.lua_error( "unfinished capture" ); + vm.error( "unfinished capture" ); } if ( l == CAP_POSITION ) { vm.push( LInteger.valueOf( cinit[i] + 1 ) ); @@ -577,7 +577,7 @@ public class StrLib { private int check_capture( int l ) { l -= '1'; if ( l < 0 || l >= level || this.clen[l] == CAP_UNFINISHED ) { - vm.lua_error("invalid capture index"); + vm.error("invalid capture index"); } return l; } @@ -587,7 +587,7 @@ public class StrLib { for ( level--; level >= 0; level-- ) if ( clen[level] == CAP_UNFINISHED ) return level; - vm.lua_error("invalid pattern capture"); + vm.error("invalid pattern capture"); return 0; } @@ -595,7 +595,7 @@ public class StrLib { switch ( p.luaByte( poffset++ ) ) { case L_ESC: if ( poffset == p.length() ) { - vm.lua_error( "malformed pattern (ends with %)" ); + vm.error( "malformed pattern (ends with %)" ); } return poffset + 1; @@ -603,7 +603,7 @@ public class StrLib { if ( p.luaByte( poffset ) == '^' ) poffset++; do { if ( poffset == p.length() ) { - vm.lua_error( "malformed pattern (missing ])" ); + vm.error( "malformed pattern (missing ])" ); } if ( p.luaByte( poffset++ ) == L_ESC && poffset != p.length() ) poffset++; @@ -695,7 +695,7 @@ public class StrLib { case 'f': { poffset += 2; if ( p.luaByte( poffset ) != '[' ) { - vm.lua_error("Missing [ after %f in pattern"); + vm.error("Missing [ after %f in pattern"); } int ep = classend( poffset ); int previous = ( soffset == 0 ) ? -1 : s.luaByte( soffset - 1 ); @@ -775,7 +775,7 @@ public class StrLib { int res; int level = this.level; if ( level >= MAX_CAPTURES ) { - vm.lua_error( "too many captures" ); + vm.error( "too many captures" ); } cinit[ level ] = soff; clen[ level ] = what; @@ -807,7 +807,7 @@ public class StrLib { int matchbalance( int soff, int poff ) { final int plen = p.length(); if ( poff == plen || poff + 1 == plen ) { - vm.lua_error( "unbalanced pattern" ); + vm.error( "unbalanced pattern" ); } if ( s.luaByte( soff ) != p.luaByte( poff ) ) return -1; diff --git a/src/main/java/lua/Builtin.java b/src/main/java/lua/Builtin.java index c78b4533..61a4ce2c 100644 --- a/src/main/java/lua/Builtin.java +++ b/src/main/java/lua/Builtin.java @@ -78,9 +78,9 @@ final class Builtin extends LFunction { break; case PCALL: { int n = vm.getArgCount(); - int s = vm.lua_pcall( n-1, Lua.LUA_MULTRET ); + int s = vm.pcall( n-1, Lua.LUA_MULTRET, 0 ); if ( s != 0 ) { - LValue v = vm.lua_tolvalue(-1); + LValue v = vm.topointer(-1); vm.setResult( LBoolean.FALSE ); vm.push( v ); } else { diff --git a/src/main/java/lua/JavaFunction.java b/src/main/java/lua/JavaFunction.java new file mode 100644 index 00000000..ef3a3fce --- /dev/null +++ b/src/main/java/lua/JavaFunction.java @@ -0,0 +1,74 @@ +package lua; + +import lua.value.LFunction; + + +/** +Type for Java functions. + + +

+In order to communicate properly with Lua, +a Java function must use the following protocol, +which defines the way parameters and results are passed: +a Java function receives its arguments from Lua in its stack +in direct order (the first argument is pushed first). +So, when the function starts, +lua_gettop(L) returns the number of arguments received by the function. +The first argument (if any) is at index 1 +and its last argument is at index lua_gettop(L). +To return values to Lua, a Java function just pushes them onto the stack, +in direct order (the first result is pushed first), +and returns the number of results. +Any other value in the stack below the results will be properly +discarded by Lua. +Like a Lua function, a Java function called by Lua can also return +many results. + + +

+As an example, the following function receives a variable number +of numerical arguments and returns their average and sum: + +


+     int foo (VM lua) {
+		int n = lua.gettop();    // number of arguments 
+		double sum = 0;
+		int i;
+		for (i = 1; i <= n; i++) {
+			if (!lua.isnumber(L, i)) {
+				lua.pushstring(L, "incorrect argument");
+				lua.error(L);
+			}
+			sum += lua.tonumber(L, i);
+		}
+		lua.pushnumber(L, sum/n);   // first result 
+		lua.pushnumber(L, sum);     // second result 
+		return 2;                   // number of results 
+	}
+
+ */ + +abstract public class JavaFunction extends LFunction { + + /** + * Called to invoke a JavaFunction. + * + * The implementation should manipulate the stack + * via the VM Java API in the same way that lua_CFunctions + * do so in standard lua. + * + * @param lua the LuaState calling this function. + * @return number of results pushed onto the stack. + */ + abstract public int invoke( VM lua ); + + /** + * Set up a Java invocation, and fix up the results + * when it returns. + */ + public boolean luaStackCall(VM vm) { + vm.invokeJavaFunction( this ); + return true; + } +} diff --git a/src/main/java/lua/VM.java b/src/main/java/lua/VM.java index 4d3ae3d0..c42f6aa6 100644 --- a/src/main/java/lua/VM.java +++ b/src/main/java/lua/VM.java @@ -3,31 +3,70 @@ package lua; import java.io.InputStream; import lua.io.Closure; -import lua.value.LNil; import lua.value.LString; import lua.value.LValue; - +/** + *
+ *

VM

+ * + *
+ * typedef struct VM;
+ * 
+ * + *

+ * Opaque structure that keeps the whole state of a Lua interpreter. The Lua + * library is fully reentrant: it has no global variables. All information about + * a state is kept in this structure. + * + * + *

+ * Here we list all functions and types from the C API in alphabetical + * order. Each function has an indicator like this: [-o, +p, + * x] + * + *

+ * The first field, o, is how many elements the function pops + * from the stack. The second field, p, is how many elements the + * function pushes onto the stack. (Any function always pushes its results after + * popping its arguments.) A field in the form x|y means the + * function may push (or pop) x or y elements, + * depending on the situation; an interrogation mark '?' means + * that we cannot know how many elements the function pops/pushes by looking + * only at its arguments (e.g., they may depend on what is on the stack). The + * third field, x, tells whether the function may throw errors: '-' + * means the function never throws any error; 'm' means the + * function may throw an error only due to not enough memory; 'e' + * means the function may throw other kinds of errors; 'v' + * means the function may throw an error on purpose. + * + * + */ public interface VM { // ================ interfaces for performing calls - /** Push an argument or return value onto the stack + /** + * @deprecated - push by type instead or use pushlvalue() */ public void push( LValue value ); - /** Push an int argument or return value onto the stack + /** + * @deprecated - use pushinteger() instead */ public void push( int value ); - /** Push a double argument or return value onto the stack + /** + * @deprecated - use pushnumber() instead */ public void push( double value ); - /** Push a boolean argument or return value onto the stack + /** + * @deprecated - use pushboolean() instead */ public void push( boolean value ); - /** Push a String argument or return value onto the stack + /** + * @deprecated - use pushstring or pushlstring instead */ public void push( String value ); @@ -38,6 +77,12 @@ public interface VM { */ public void prepStackCall(); + /** + * Invoke a JavaFunction being called via prepStackCall() + * @param javaFunction + */ + public void invokeJavaFunction(JavaFunction javaFunction); + /** * Execute bytecodes until the current call completes * or the vm yields. @@ -53,102 +98,265 @@ public interface VM { * @param values */ public void doCall(Closure c, LValue[] values); + /** - * Set the number of results that are expected from the function being called. - * (This should be called before prepStackCall) + * @deprecated - use JavaFunction and Java API instead. */ public void setExpectedResultCount( int nresults ); /** - * Returns the number of results that are expected by the calling function, - * or -1 if the calling function can accept a variable number of results. + * @deprecated - use JavaFunction and Java API instead. */ public int getExpectedResultCount(); /** - * Adjust the stack to contain the expected number of results by adjusting - * the top. + * @deprecated - use JavaFunction and Java API instead. */ public void adjustResults(); // ================ interfaces for getting arguments when called /** - * Get the number of argumnets supplied in the call. + * @deprecated - use JavaFunction and Java API instead. */ public int getArgCount(); /** - * Get the index-th argument supplied, or NIL if fewer than index were supplied. - * @param index - * @return + * @deprecated - use JavaFunction and Java API instead. */ public LValue getArg(int index); /** - * Get the index-th argument as an int value, or 0 if fewer than index arguments were supplied. - * @param index - * @return + * @deprecated - use JavaFunction and Java API instead. */ public int getArgAsInt( int index ); /** - * Get the index-th argument as a double value, or 0 if fewer than index arguments were supplied. - * @param index - * @return + * @deprecated - use JavaFunction and Java API instead. */ public double getArgAsDouble( int index ); /** - * Get the index-th argument as a boolean value, or false if fewer than index arguments were supplied. - * @param index - * @return + * @deprecated - use JavaFunction and Java API instead. */ public boolean getArgAsBoolean( int index ); /** - * Get the index-th argument as a String value, or "" if fewer than index arguments were supplied. - * @param index - * @return + * @deprecated - use JavaFunction and Java API instead. */ public String getArgAsString( int index ); /** - * Get the index-th argument as an LString value, or "" if fewer than index arguments were supplied. - * @param index - * @return + * @deprecated - use JavaFunction and Java API instead. */ public LString getArgAsLuaString( int index ); - /** Set top to base in preparation for pushing return values. - * Can be used when returning no values. - * - * Once this is called, calls to getArg() are undefined. - * - * @see push() to push additional results once result is reset. + /** + * @deprecated - use JavaFunction and Java API instead. */ public void setResult(); - /** Convenience utility to set val to stack[base] and top to base + 1 - * in preparation for returning one value - * - * Once this is called, calls to getArg() are undefined. - * - * @param val value to provide as the only result. + /** + * @deprecated - use JavaFunction and Java API instead. */ public void setResult(LValue val); /** - * Set up an error result on the stack. - * @param value the LValue to return as the first return value - * @param message the String error message to supply + * @deprecated - use JavaFunction and Java API instead. */ public void setErrorResult(LValue value, String message); - // ====================== lua Java API ======================= - + // =============================================================== + // Lua Java API + // =============================================================== + + /** + * Sets a new panic function and returns the old one. [-0, +0, -] + * + * + *

+ * If an error happens outside any protected environment, Lua calls a + * panic function and then calls exit(EXIT_FAILURE), + * thus exiting the host application. Your panic function may avoid this + * exit by never returning (e.g., doing a long jump). + * + * + *

+ * The panic function can access the error message at the top of the stack. + */ + public JavaFunction atpanic(JavaFunction panicf); + + /** + * Calls a function. [-(nargs + 1), +nresults, e] + * + * + *

+ * To call a function you must use the following protocol: first, the + * function to be called is pushed onto the stack; then, the arguments to + * the function are pushed in direct order; that is, the first argument is + * pushed first. Finally you call lua_call; + * nargs is the number of arguments that you pushed onto the + * stack. All arguments and the function value are popped from the stack + * when the function is called. The function results are pushed onto the + * stack when the function returns. The number of results is adjusted to + * nresults, unless nresults is LUA_MULTRET. In this case, + * all results from the function are pushed. Lua takes care that + * the returned values fit into the stack space. The function results are + * pushed onto the stack in direct order (the first result is pushed first), + * so that after the call the last result is on the top of the stack. + * + * + *

+ * Any error inside the called function is propagated upwards (with a + * longjmp). + * + * + *

+ * The following example shows how the host program may do the equivalent to + * this Lua code: + * + *

+	 * a = f("how", t.x, 14)
+	 * 
+ * + *

+ * Here it is in C: + * + *

+	 * lua_getfield(L, LUA_GLOBALSINDEX, "f"); // function to be called 
+	 * lua_pushstring(L, "how"); // 1st argument 
+	 * lua_getfield(L, LUA_GLOBALSINDEX, "t"); // table to be indexed 
+	 * lua_getfield(L, -1, "x"); // push result of t.x (2nd arg) 
+	 * lua_remove(L, -2); // remove 't' from the stack 
+	 * lua_pushinteger(L, 14); // 3rd argument 
+	 * lua_call(L, 3, 1); // call 'f' with 3 arguments and 1 result 
+	 * lua_setfield(L, LUA_GLOBALSINDEX, "a"); // set global 'a' 
+	 * 
+ * + *

+ * Note that the code above is "balanced": at its end, the stack is back to + * its original configuration. This is considered good programming practice. + */ + public void call(int nargs, int nresults); + + /** + * + * Ensures that there are at least extra free stack slots in + * the stack. [-0, +0, -] + * + *

+ * It returns false if it cannot grow the stack to that size. This function + * never shrinks the stack; if the stack is already larger than the new + * size, it is left unchanged. + * + */ + public void checkstack(int extra); + + /** + * Closes the given Lua state. [-0, +0, -] + * + *

+ * Destroys all objects in the given Lua state (calling the corresponding + * garbage-collection metamethods, if any) and frees all dynamic memory used + * by this state. On several platforms, you may not need to call this + * function, because all resources are naturally released when the host + * program ends. On the other hand, long-running programs, such as a daemon + * or a web server, might need to release states as soon as they are not + * needed, to avoid growing too large. + */ + public void close(); + + /** + * Concatenates the n values at the top of the stack. [-n, +1, e] + * + *

+ * Concatenates the n values at the top of the stack, pops + * them, and leaves the result at the top. If n is 1, + * the result is the single value on the stack (that is, the function does + * nothing); if n is 0, the result is the empty string. + * Concatenation is performed following the usual semantics of Lua (see §2.5.4). + */ + public void concat(int n); + + /** + * Calls the C function func in protected mode. [-0, +(0|1), -] + * + *

+ * func starts with only one element in its stack, a light + * userdata containing ud. In case of errors, lua_cpcall returns the same error + * codes as lua_pcall, plus the + * error object on the top of the stack; otherwise, it returns zero, and + * does not change the stack. All values returned by func are + * discarded. + */ + public int javapcall(JavaFunction func, Object ud); + + /** + * Creates a new empty table and pushes it onto the stack. [-0, +1, m] + * + *

+ * The new table has space pre-allocated for narr array + * elements and nrec non-array elements. This pre-allocation + * is useful when you know exactly how many elements the table will have. + * Otherwise you can use the function lua_newtable. + */ + public void createtable(int narr, int nrec); + + /** + * Dumps a function as a binary chunk. [-0, +0, + * m] + * + *

+ * Receives a Lua function on the top of the stack and produces a binary + * chunk that, if loaded again, results in a function equivalent to the one + * dumped. As it produces parts of the chunk, lua_dump + * calls function writer (see lua_Writer) + * with the given data to write them. + *

+ * The value returned is the error code returned by the last call to the + * writer; 0 means no errors. + * + * + *

+ * This function does not pop the Lua function from the stack. + * + */ + public void dump(); + + /** + * Tests if two items on the stack are equal. [-0, +0, + * e] + * + *

+ * Returns 1 if the two values in acceptable indices index1 + * and index2 are equal, following the semantics of the Lua + * == operator (that is, may call metamethods). Otherwise + * returns 0. Also returns 0 if any of the indices is non valid. + * + * + */ + public boolean equal(int index1, int index2); + + /** + * Generates a Lua error. [-1, +0, v] + * + *

+ * The error message (which can actually be a Lua value of any type) must be + * on the stack top. This function does a long jump, and therefore never + * returns. (see luaL_error). + * + */ + public void error(); + /** * Raises an error. The message is pushed onto the stack and used as the error message. * It also adds at the beginning of the message the file name and the line number where @@ -157,41 +365,1034 @@ public interface VM { * In the java implementation this throws a RuntimeException, possibly filling * line number information first. */ - public void lua_error(String message); - - /** - * Run the method on the stack, propagating any error that occurs. - * @param nArgs number of arguments on the stack - * @param nResults number of results on the stack - */ - public void lua_call(int nArgs, int nResults); - - /** - * Run the method on the stack in protected mode. - * @param nArgs number of arguments on the stack - * @param nResults number of results on the stack - * @return 0 if successful, LUA_ERRMEM if no memory, LUA_ERRRUN for any other error - */ - public int lua_pcall(int nArgs, int nResults); - + public void error(String message); /** + * Controls the garbage collector. [-0, +0, e] * - * @param is InputStream providing the data to be loaded - * @param chunkname Name of the chunk to be used in debugging - * @return 0 if successful, LUA_ERRMEM if no memory, LUA_ERRSYNTAX for i/o or any other errors + *

+ * This function performs several tasks, according to the value of the + * parameter what: + * + *

*/ - public int lua_load( InputStream is, String chunkname ); + public void gc(int what, int data); /** - * Get a value on the stack, relative to the top or bottom - * @param i index from bottom if 0 or greater, index from top if less than 0 - * @return + * Pushes a value's environment table. [-0, +1, + * -] + * + *

+ * Pushes onto the stack the environment table of the value at the given + * index. */ - public LValue lua_tolvalue(int i); - + public void getfenv(int index); + /** - * Pop some number of items off the stack. + * Dereference a tables field. [-0, +1, e] + * + *

+ * Pushes onto the stack the value t[k], where + * t is the value at the given valid index. As in Lua, this + * function may trigger a metamethod for the "index" event (see §2.8). + * */ - public void lua_pop(int n); + public void getfield(int index, String k); + + /** + * Look up a global value. [-0, +1, e] + * + *

+ * Pushes onto the stack the value of the global name. It is + * defined as a macro: + * + *

+	 * 	 #define lua_getglobal(L,s)  lua_getfield(L, LUA_GLOBALSINDEX, s)
+	 * 	
+	 * 
+ */ + public void getglobal(String s); + + /** + * Get a value's metatable. [-0, +(0|1), -] + * + *

+ * Pushes onto the stack the metatable of the value at the given acceptable + * index. If the index is not valid, or if the value does not have a + * metatable, the function returns 0 and pushes nothing on the stack. + */ + public void getmetatable(int index); + + /** + * Dereference a table's list element. [-1, +1, + * e] + * + *

+ * Pushes onto the stack the value t[k], where + * t is the value at the given valid index and k + * is the value at the top of the stack. + * + *

+ * This function pops the key from the stack (putting the resulting value in + * its place). As in Lua, this function may trigger a metamethod for the + * "index" event (see §2.8). + */ + public void gettable(int index); + + /** + * Returns the index of the top element in the stack. [-0, +0, -] + * + *

+ * Because indices start at 1, this result is equal to the number of + * elements in the stack (and so 0 means an empty stack). + */ + public int gettop(); + + /** + * Insert the top item somewhere in the stack. [-1, +1, + * -] + * + *

+ * Moves the top element into the given valid index, shifting up the + * elements above this index to open space. Cannot be called with a + * pseudo-index, because a pseudo-index is not an actual stack position. + * + */ + public void insert(int index); + + /** + * Test if a value is boolean. [-0, +0, -] + * + *

+ * Returns 1 if the value at the given acceptable index has type boolean, + * and 0 otherwise. + * + */ + public boolean isboolean(int index); + + /** + * Test if a value is a JavaFunction. [-0, +0, -] + * + *

+ * Returns 1 if the value at the given acceptable index is a + * C function, and 0 otherwise. + * + */ + public boolean isjavafunction(int index); + + /** + * Test if a value is a function. [-0, +0, -] + * + *

+ * Returns true if the value at the given acceptable index is a function + * (either C or Lua), and false otherwise. + * + */ + public boolean isfunction(int index); + + /** + * Test if a value is light user data [-0, +0, -] + * + *

+ * Returns 1 if the value at the given acceptable index is a light userdata, + * and 0 otherwise. + */ + public boolean islightuserdata(int index); + + /** + * Test if a value is nil [-0, +0, -] + * + *

+ * Returns 1 if the value at the given acceptable index is nil, and + * 0 otherwise. + */ + public boolean isnil(int index); + + /** + * Test if a value is not valid [-0, +0, -] + * + *

+ * Returns 1 if the the given acceptable index is not valid (that is, it + * refers to an element outside the current stack), and 0 otherwise. + */ + public boolean isnone(int index); + + /** + * Test if a value is nil or not valid [-0, +0, + * -] + * + *

+ * Returns 1 if the the given acceptable index is not valid (that is, it + * refers to an element outside the current stack) or if the value at this + * index is nil, and 0 otherwise. + */ + public boolean isnoneornil(int index); + + /** + * Test if a value is a number [-0, +0, -] + * + *

+ * Returns 1 if the value at the given acceptable index is a number or a + * string convertible to a number, and 0 otherwise. + */ + public boolean isnumber(int index); + + /** + * Test if a value is a string [-0, +0, m] + * + *

+ * Returns 1 if the value at the given acceptable index is a string or a + * number (which is always convertible to a string), and 0 otherwise. + */ + public boolean isstring(int index); + + /** + * Test if a value is a table [-0, +0, -] + * + *

+ * Returns 1 if the value at the given acceptable index is a table, and + * 0 otherwise. + */ + public boolean istable(int index); + + /** + * Test if a value is a thread [-0, +0, -] + * + *

+ * Returns 1 if the value at the given acceptable index is a thread, and + * 0 otherwise. + */ + public boolean isthread(int index); + + /** + * Test if a value is a userdata [-0, +0, -] + * + *

+ * Returns 1 if the value at the given acceptable index is a userdata + * (either full or light), and 0 otherwise. + */ + public boolean isuserdata(int index); + + /** + * Compare two values [-0, +0, e] + * + *

+ * Returns 1 if the value at acceptable index index1 is + * smaller than the value at acceptable index index2, + * following the semantics of the Lua < operator (that is, + * may call metamethods). Otherwise returns 0. Also returns 0 if + * any of the indices is non valid. + */ + public boolean lessthan(int index1, int index2); + + /** + * Loads a Lua chunk. [-0, +1, -] + * + *

+ * If there are no errors, lua_load + * pushes the compiled chunk as a Lua function on top of the stack. + * Otherwise, it pushes an error message. The return values of lua_load are: + * + *

+ * + *

+ * This function only loads a chunk; it does not run it. + * + * + *

+ * lua_load automatically detects + * whether the chunk is text or binary, and loads it accordingly (see + * program luac). + * + * + *

+ * The lua_load function uses a + * user-supplied reader function to read the chunk (see lua_Reader). The + * data argument is an opaque value passed to the reader + * function. + * + * + *

+ * The chunkname argument gives a name to the chunk, which is + * used for error messages and in debug information (see §3.8). + */ + public int load(InputStream is, String chunkname); + + /** + * Create a table [-0, +1, m] + * + *

+ * Creates a new empty table and pushes it onto the stack. It is equivalent + * to lua_createtable(L, 0, 0). + */ + public void newtable(); + + /** + * Create a thread [-0, +1, m] + * + *

+ * Creates a new thread, pushes it on the stack, and returns a pointer to a + * lua_State that represents this + * new thread. The new state returned by this function shares with the + * original state all global objects (such as tables), but has an + * independent execution stack. + * + * + *

+ * There is no explicit function to close or to destroy a thread. Threads + * are subject to garbage collection, like any Lua object. + */ + public void newthread(); + + /** + * Create a userdata [-0, +1, m] + * + *

+ * This function allocates a new block of memory with the given size, pushes + * onto the stack a new full userdata with the block address, and returns + * this address. + * + * + *

+ * Userdata represent C values in Lua. A full userdata + * represents a block of memory. It is an object (like a table): you must + * create it, it can have its own metatable, and you can detect when it is + * being collected. A full userdata is only equal to itself (under raw + * equality). + * + * + *

+ * When Lua collects a full userdata with a gc metamethod, + * Lua calls the metamethod and marks the userdata as finalized. When this + * userdata is collected again then Lua frees its corresponding memory. + */ + public void newuserdata(Object o); + + /** + * Traverse to the next table item. [-1, +(2|0), + * e] + * + *

+ * Pops a key from the stack, and pushes a key-value pair from the table at + * the given index (the "next" pair after the given key). If there are no + * more elements in the table, then lua_next + * returns 0 (and pushes nothing). + * + * + *

+ * A typical traversal looks like this: + * + *

+	 * // table is in the stack at index 't' 
+	 * lua_pushnil(L); // first key 
+	 * while (lua_next(L, t) != 0) {
+	 * 	// uses 'key' (at index -2) and 'value' (at index -1) 
+	 * 	printf("%s - %s\n", lua_typename(L, lua_type(L, -2)), lua_typename(L,
+	 * 			lua_type(L, -1)));
+	 * 	// removes 'value'; keeps 'key' for next iteration 
+	 * 	lua_pop(L, 1);
+	 * }
+	 * 
+ * + *

+ * While traversing a table, do not call lua_tolstring + * directly on a key, unless you know that the key is actually a string. + * Recall that lua_tolstring + * changes the value at the given index; this confuses the next + * call to lua_next. + */ + public int next(int index); + + /** + * Get the length of an object [-0, +0, -] + * + *

+ * Returns the "length" of the value at the given acceptable index: for + * strings, this is the string length; for tables, this is the result of the + * length operator ('#'); for userdata, this is the size of + * the block of memory allocated for the userdata; for other values, it + * is 0. + */ + public int objlen(int index); + + /** + * Calls a function in protected mode. [-(nargs + 1), + * +(nresults|1), -] + * + * + *

+ * Both nargs and nresults have the same + * meaning as in lua_call. If there + * are no errors during the call, lua_pcall + * behaves exactly like lua_call. + * However, if there is any error, lua_pcall + * catches it, pushes a single value on the stack (the error message), and + * returns an error code. Like lua_call, + * lua_pcall always removes the + * function and its arguments from the stack. + * + * + *

+ * If errfunc is 0, then the error message returned on the + * stack is exactly the original error message. Otherwise, + * errfunc is the stack index of an + * error handler function. (In the current implementation, this + * index cannot be a pseudo-index.) In case of runtime errors, this function + * will be called with the error message and its return value will be the + * message returned on the stack by lua_pcall. + * + * + *

+ * Typically, the error handler function is used to add more debug + * information to the error message, such as a stack traceback. Such + * information cannot be gathered after the return of lua_pcall, + * since by then the stack has unwound. + * + * + *

+ * The lua_pcall function returns + * 0 in case of success or one of the following error codes (defined in + * lua.h): + * + *

+ */ + public int pcall(int nargs, int nresults, int errfunc); + + /** + * Pops n elements from the stack. [-n, + * +0, -] + */ + public void pop(int n); + + /** + * Pushes a boolean value with value b onto the stack. [-0, +1, -] + * + */ + public void pushboolean(boolean b); + + /** + * Pushes a new C closure onto the stack. [-n, +1, + * m] + * + * + *

+ * When a Java function is created, it is possible to associate some + * values with it, thus creating a C closure (see §3.4); these values are then accessible to the + * function whenever it is called. To associate values with a + * C function, first these values should be pushed onto the stack (when + * there are multiple values, the first value is pushed first). Then lua_pushcclosure is called + * to create and push the C function onto the stack, with the argument + * n telling how many values should be associated with the + * function. lua_pushcclosure + * also pops these values from the stack. + */ + public void pushclosure(JavaFunction fn, int n); + + /** + * Pushes a Java function onto the stack. [-0, +1, + * m] + * + *

+ * This function receives a pointer to a C function and pushes onto the + * stack a Lua value of type function that, when called, + * invokes the corresponding C function. + * + * + *

+ * Any function to be registered in Lua must follow the correct protocol to + * receive its parameters and return its results (see lua_CFunction). + * + */ + public void pushjavafunction(JavaFunction f); + + /** + * Format and push a string. [-0, +1, m] + * + *

+ * Pushes onto the stack a formatted string and returns a pointer to this + * string. It is similar to the C function sprintf, but + * has some important differences: + * + *

+ */ + public String pushfstring(String fmt, Object[] args); + + /** + * Pushes a number with value n onto the stack. [-0, +1, -] + */ + public void pushinteger(int n); + + /** + * Pushes a light userdata onto the stack. [-0, +1, + * -] + * + * + *

+ * Userdata represent C values in Lua. A light userdata + * represents a pointer. It is a value (like a number): you do not create + * it, it has no individual metatable, and it is not collected (as it was + * never created). A light userdata is equal to "any" light userdata with + * the same C address. + */ + public void pushlightuserdata(Object p); + + /** + * Push string bytes onto the stack as a string. [-0, +1, + * m] + * + * Pushes the string pointed to by s with size + * len onto the stack. Lua makes (or reuses) an internal copy + * of the given string, so the memory at s can be freed or + * reused immediately after the function returns. The string can contain + * embedded zeros. + */ + public void pushlstring(byte[] bytes, int offset, int length); + + /** + * Pushes a nil value onto the stack. [-0, +1, -] + * + */ + public void pushnil(); + + /** + * Pushes a number with value d onto the stack. [-0, +1, -] + * + */ + public void pushnumber(double d); + + /** + * Push a String onto the stack. [-0, +1, m] + * + *

+ * Pushes the String s onto the stack. Lua makes (or reuses) + * an internal copy of the given string, so the memory at s + * can be freed or reused immediately after the function returns. The string + * cannot contain embedded zeros; it is assumed to end at the first zero. + */ + public void pushstring(String s); + + /** + * Push a thread onto the stack. [-0, +1, -] + * + * Pushes the thread represented by L onto the stack. Returns + * 1 if this thread is the main thread of its state. + */ + public void pushthread(); + + /** + * Push a value from the stack onto the stack. [-0, +1, + * -] + * + *

+ * Pushes a copy of the element at the given valid index onto the stack. + */ + public void pushvalue(int index); + + /** + * Format and push a string. [-0, +1, m] + * + *

+ * Equivalent to lua_pushfstring, + * except that it receives a va_list instead of a variable + * number of arguments. + */ + public void pushvfstring(String format, Object[] args); + + /** + * Test if two objects are the same object. [-0, +0, + * -] + * + *

+ * Returns 1 if the two values in acceptable indices index1 + * and index2 are primitively equal (that is, without calling + * metamethods). Otherwise returns 0. Also returns 0 if any of the + * indices are non valid. + */ + public void rawequal(int index1, int index2); + + /** + * Do a table get without metadata calls. [-1, +1, + * -] + * + *

+ * Similar to lua_gettable, but + * does a raw access (i.e., without metamethods). + */ + public void rawget(int index); + + /** + * Do a integer-key table get without metadata calls. [-0, +1, -] + * + *

+ * Pushes onto the stack the value t[n], where + * t is the value at the given valid index. The access is + * raw; that is, it does not invoke metamethods. + */ + public void rawgeti(int index, int n); + + /** + * Do a table set without metadata calls. [-2, +0, + * m] + * + *

+ * Similar to lua_settable, but + * does a raw assignment (i.e., without metamethods). + */ + public void rawset(int index); + + /** + * Do a integer-key table set without metadata calls. [-1, +0, m] + * + *

+ * Does the equivalent of t[n] = v, where t + * is the value at the given valid index and v is the value + * at the top of the stack. + * + * + *

+ * This function pops the value from the stack. The assignment is raw; that + * is, it does not invoke metamethods. + */ + public void rawseti(int index, int n); + + /** + * Register a JavaFunction with a specific name. [-0, +0, + * m] + * + *

+ * Sets the C function f as the new value of global + * name. It is defined as a macro: + * + *

+	 * 	 #define lua_register(L,n,f) \
+	 * 	 (lua_pushcfunction(L, f), lua_setglobal(L, n))
+	 * 	
+	 * 
+ */ + public void register(String name, JavaFunction f); + + /** + * Remove an element from the stack. [-1, +0, -] + * + *

+ * Removes the element at the given valid index, shifting down the elements + * above this index to fill the gap. Cannot be called with a pseudo-index, + * because a pseudo-index is not an actual stack position. + */ + public void remove(int index); + + /** + * Replace an element on the stack. [-1, +0, -] + * + *

+ * Moves the top element into the given position (and pops it), without + * shifting any element (therefore replacing the value at the given + * position). + */ + public void replace(int index); + + /** + * Starts and resumes a coroutine in a given thread. [-?, + * +?, -] + * + * + *

+ * To start a coroutine, you first create a new thread (see lua_newthread); then you push + * onto its stack the main function plus any arguments; then you call lua_resume, with + * narg being the number of arguments. This call returns when + * the coroutine suspends or finishes its execution. When it returns, the + * stack contains all values passed to lua_yield, + * or all values returned by the body function. lua_resume + * returns LUA_YIELD if the + * coroutine yields, 0 if the coroutine finishes its execution without + * errors, or an error code in case of errors (see lua_pcall). + * In case of errors, the stack is not unwound, so you can use the debug API + * over it. The error message is on the top of the stack. To restart a + * coroutine, you put on its stack only the values to be passed as results + * from yield, and then call lua_resume. + */ + public void resume(int narg); + + /** + * Set the environment for a value. [-1, +0, -] + * + *

+ * Pops a table from the stack and sets it as the new environment for the + * value at the given index. If the value at the given index is neither a + * function nor a thread nor a userdata, lua_setfenv + * returns 0. Otherwise it returns 1. + */ + public int setfenv(int index); + + /** + * Set the value of a table field. [-1, +0, e] + * + *

+ * Does the equivalent to t[k] = v, where t + * is the value at the given valid index and v is the value + * at the top of the stack. + * + * + *

+ * This function pops the value from the stack. As in Lua, this function may + * trigger a metamethod for the "newindex" event (see §2.8). + */ + public void setfield(int index, String k); + + /** + * Set the value of a global variable. [-1, +0, + * e] + * + *

+ * Pops a value from the stack and sets it as the new value of global + * name. It is defined as a macro: + * + *

+	 * 	 #define lua_setglobal(L,s)   lua_setfield(L, LUA_GLOBALSINDEX, s)
+	 * 	
+	 * 
+ */ + public void setglobal(String name); + + /** + * Set the metatable of a value. [-1, +0, -] + * + *

+ * Pops a table from the stack and sets it as the new metatable for the + * value at the given acceptable index. + */ + public void setmetatable(int index); + + /** + * Set the value of a table for a key. [-2, +0, + * e] + * + *

+ * Does the equivalent to t[k] = v, where t + * is the value at the given valid index, v is the value at + * the top of the stack, and k is the value just below the + * top. + * + * + *

+ * This function pops both the key and the value from the stack. As in Lua, + * this function may trigger a metamethod for the "newindex" event (see §2.8). + */ + public void settable(int index); + + /** + * Set the top of the stack. [-?, +?, -] + * + *

+ * Accepts any acceptable index, or 0, and sets the stack top to this + * index. If the new top is larger than the old one, then the new elements + * are filled with nil. If index is 0, then all + * stack elements are removed. + */ + public void settop(int index); + + /** + * Returns the status of the thread L. [-0, +0, -] + * + * + * + *

+ * The status can be 0 for a normal thread, an error code if the thread + * finished its execution with an error, or LUA_YIELD + * if the thread is suspended. + * + */ + public void status(); + + /** + * Get a value as a boolean. [-0, +0, -] + * + *

+ * Converts the Lua value at the given acceptable index to a C boolean + * value (0 or 1). Like all tests in Lua, lua_toboolean returns 1 for + * any Lua value different from false and nil; otherwise it + * returns 0. It also returns 0 when called with a non-valid index. (If you + * want to accept only actual boolean values, use lua_isboolean + * to test the value's type.) + * + */ + public boolean toboolean(int index); + + /** + * Get a value as a JavaFunction. + *


+ *

lua_tocfunction

+ *

+ * [-0, +0, -] + * + *

+	 * lua_CFunction lua_tocfunction (lua_State *L, int index);
+	 * 
+ * + *

+ * Converts a value at the given acceptable index to a C function. That + * value must be a C function; otherwise, returns NULL. + */ + public JavaFunction tojavafunction(int index); + + /** + * Get a value as an int. [-0, +0, -] + * + *

+ * Converts the Lua value at the given acceptable index to the signed + * integral type lua_Integer. + * The Lua value must be a number or a string convertible to a number (see + * §2.2.1); otherwise, lua_tointeger + * returns 0. + * + * + *

+ * If the number is not an integer, it is truncated in some non-specified + * way. + */ + public int tointeger(int index); + + /** + * Gets the value of a string as byte array. [-0, +0, + * m] + * + *

+ * Converts the Lua value at the given acceptable index to a C string. + * If len is not NULL, it also sets + * *len with the string length. The Lua value must be a + * string or a number; otherwise, the function returns NULL. + * If the value is a number, then lua_tolstring + * also changes the actual value in the stack to a string. (This + * change confuses lua_next when lua_tolstring is applied to + * keys during a table traversal.) + * + * + *

+ * lua_tolstring returns a + * fully aligned pointer to a string inside the Lua state. This string + * always has a zero ('\0') after its last character (as + * in C), but may contain other zeros in its body. Because Lua has + * garbage collection, there is no guarantee that the pointer returned by lua_tolstring will be valid + * after the corresponding value is removed from the stack. + */ + public LString tolstring(int index); + + /** + * Convert a value to a double. [-0, +0, -] + * + *

+ * Converts the Lua value at the given acceptable index to the C type + * lua_Number (see lua_Number). The Lua value must + * be a number or a string convertible to a number (see §2.2.1); otherwise, lua_tonumber + * returns 0. + * + */ + public double tonumber(int index); + + /** + * Get the raw Object at a stack location. [-0, +0, + * -] + * + *

+ * Converts the value at the given acceptable index to a generic + * C pointer (void*). The value may be a userdata, a + * table, a thread, or a function; otherwise, lua_topointer + * returns NULL. Different objects will give different + * pointers. There is no way to convert the pointer back to its original + * value. + * + * + *

+ * Typically this function is used only for debug information. + */ + public LValue topointer(int index); + + /** + * Get a stack value as a String. [-0, +0, m] + * + *

+ * Equivalent to lua_tolstring + * with len equal to NULL. + */ + public String tostring(int index); + + /** + * Get a thread value from the stack. [-0, +0, -] + * + *

+ * Converts the value at the given acceptable index to a Lua thread + * (represented as lua_State*). This value must be a thread; + * otherwise, the function returns NULL. + */ + public StackState tothread(int index); + + /** + * Get the Object from a userdata value. [-0, +0, + * -] + * + *

+ * If the value at the given acceptable index is a full userdata, returns + * its block address. If the value is a light userdata, returns its pointer. + * Otherwise, returns NULL. + * + */ + public Object touserdata(int index); + + /** + * Get the type of a value. [-0, +0, -] + * + *

+ * Returns the type of the value in the given acceptable index, or + * LUA_TNONE for a non-valid index (that is, an index to an + * "empty" stack position). The types returned by lua_type + * are coded by the following constants defined in lua.h: + * LUA_TNIL, LUA_TNUMBER, + * LUA_TBOOLEAN, LUA_TSTRING, + * LUA_TTABLE, LUA_TFUNCTION, + * LUA_TUSERDATA, LUA_TTHREAD, and + * LUA_TLIGHTUSERDATA. + */ + public int type(int index); + + /** + * Get the type name for a value. [-0, +0, -] + * + *

+ * Returns the name of the type encoded by the value tp, + * which must be one the values returned by lua_type. + */ + public String typename(int tp); + + /** + * Exchange values between threads. [-?, +?, -] + * + *

+ * Exchange values between different threads of the same global + * state. + * + * + *

+ * This function pops n values from the stack + * from, and pushes them onto the stack to. + */ + public void xmove(StackState to, int n); + + /** + * Yields a coroutine. [-?, +?, -] + * + * + *

+ * This function should only be called as the return expression of a + * C function, as follows: + * + *

+	 * return lua_yield(L, nresults);
+	 * 
+ * + *

+ * When a C function calls lua_yield + * in that way, the running coroutine suspends its execution, and the call + * to lua_resume that started + * this coroutine returns. The parameter nresults is the + * number of values from the stack that are passed as results to lua_resume. + * + */ + public void yield(int nresults); + } diff --git a/src/main/java/lua/debug/DebugStackState.java b/src/main/java/lua/debug/DebugStackState.java index 29c125d8..fc4c57a8 100644 --- a/src/main/java/lua/debug/DebugStackState.java +++ b/src/main/java/lua/debug/DebugStackState.java @@ -89,8 +89,8 @@ public class DebugStackState extends StackState implements DebugRequestListener // override and fill in line number info - public void lua_error(String message) { - super.lua_error( getFileLine(cc)+": "+message ); + public void error(String message) { + super.error( getFileLine(cc)+": "+message ); } private void printLuaTrace() { diff --git a/src/main/java/lua/value/LFunction.java b/src/main/java/lua/value/LFunction.java index f90024cb..a5ad8276 100644 --- a/src/main/java/lua/value/LFunction.java +++ b/src/main/java/lua/value/LFunction.java @@ -15,14 +15,14 @@ public class LFunction extends LValue { vm.push( table ); vm.push( key ); vm.push( val ); - vm.lua_call( 3, 0 ); + vm.call( 3, 0 ); } public void luaGetTable(VM vm, LValue table, LValue key) { vm.push( this ); vm.push( table ); vm.push( key ); - vm.lua_call( 2, 1 ); + vm.call( 2, 1 ); } public int luaGetType() { diff --git a/src/main/java/lua/value/LValue.java b/src/main/java/lua/value/LValue.java index 43624c85..4fb0b15b 100644 --- a/src/main/java/lua/value/LValue.java +++ b/src/main/java/lua/value/LValue.java @@ -33,7 +33,7 @@ public class LValue { // perform a lua call, return true if the call is to a lua function, false // if it ran to completion. public boolean luaStackCall(VM vm) { - vm.lua_error("attempt to call "+this); + vm.error("attempt to call "+this); return false; }