From 148936ea8b22f9d2c23c24ed34ab409077a35328 Mon Sep 17 00:00:00 2001 From: zaoqi Date: Fri, 9 Aug 2019 22:09:43 +0800 Subject: [PATCH] LuaJ: https://github.com/luaj/luaj/commit/6d2deb4cb6e951b5818c2966850777e9049c8330 --- README.md | 2 +- app/src/main/java/org/luaj/vm2/Lua.java | 48 +- .../main/java/org/luaj/vm2/LuaClosure.java | 115 +- app/src/main/java/org/luaj/vm2/LuaDouble.java | 18 +- app/src/main/java/org/luaj/vm2/LuaString.java | 12 +- app/src/main/java/org/luaj/vm2/LuaTable.java | 46 +- app/src/main/java/org/luaj/vm2/LuaValue.java | 1638 ++++++++--------- app/src/main/java/org/luaj/vm2/Print.java | 219 ++- .../java/org/luaj/vm2/compiler/Constants.java | 13 +- .../java/org/luaj/vm2/compiler/FuncState.java | 31 +- .../java/org/luaj/vm2/compiler/LexState.java | 34 +- .../main/java/org/luaj/vm2/compiler/LuaC.java | 2 +- .../main/java/org/luaj/vm2/lib/BaseLib.java | 73 +- .../main/java/org/luaj/vm2/lib/Bit32Lib.java | 10 +- .../java/org/luaj/vm2/lib/CoroutineLib.java | 26 +- .../main/java/org/luaj/vm2/lib/DebugLib.java | 134 +- app/src/main/java/org/luaj/vm2/lib/IoLib.java | 94 +- .../java/org/luaj/vm2/lib/LibFunction.java | 2 +- .../main/java/org/luaj/vm2/lib/MathLib.java | 97 +- app/src/main/java/org/luaj/vm2/lib/OsLib.java | 130 +- .../java/org/luaj/vm2/lib/PackageLib.java | 84 +- .../main/java/org/luaj/vm2/lib/StringLib.java | 260 +-- .../main/java/org/luaj/vm2/lib/TableLib.java | 12 +- .../org/luaj/vm2/lib/jse/CoerceJavaToLua.java | 14 +- .../java/org/luaj/vm2/lib/jse/JavaClass.java | 52 +- .../java/org/luaj/vm2/lib/jse/JseBaseLib.java | 4 +- .../java/org/luaj/vm2/lib/jse/JseMathLib.java | 23 +- .../java/org/luaj/vm2/lib/jse/JseOsLib.java | 8 +- .../org/luaj/vm2/lib/jse/JsePlatform.java | 21 +- .../org/luaj/vm2/lib/jse/JseStringLib.java | 39 + .../java/org/luaj/vm2/lib/jse/LuajavaLib.java | 64 +- 31 files changed, 1725 insertions(+), 1600 deletions(-) create mode 100644 app/src/main/java/org/luaj/vm2/lib/jse/JseStringLib.java diff --git a/README.md b/README.md index 82718b32..5ee2b427 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ Attribution XPrivacyLua uses: -* [LuaJ](https://sourceforge.net/projects/luaj/). Copyright 2007-2013 LuaJ. All rights reserved. See [license](http://luaj.sourceforge.net/license.txt). +* [LuaJ](https://github.com/luaj/luaj). Copyright 2007-2013 LuaJ. All rights reserved. See [license](http://luaj.sourceforge.net/license.txt). * [Glide](https://bumptech.github.io/glide/). Copyright 2014 Google, Inc. All rights reserved. See [license](https://raw.githubusercontent.com/bumptech/glide/master/LICENSE). * [Android Support Library](https://developer.android.com/tools/support-library/). Copyright (C) 2011 The Android Open Source Project. See [license](https://android.googlesource.com/platform/frameworks/support/+/master/LICENSE.txt). diff --git a/app/src/main/java/org/luaj/vm2/Lua.java b/app/src/main/java/org/luaj/vm2/Lua.java index 9b9b0ce1..7a57841e 100644 --- a/app/src/main/java/org/luaj/vm2/Lua.java +++ b/app/src/main/java/org/luaj/vm2/Lua.java @@ -23,14 +23,14 @@ /** - * Constants for lua limits and opcodes. + * Constants for lua limits and opcodes. *

* This is a direct translation of C lua distribution header file constants - * for bytecode creation and processing. + * for bytecode creation and processing. */ public class Lua { /** version is supplied by ant build task */ - public static final String _VERSION = "Luaj 0.0"; + public static final String _VERSION = "Luaj-jse 3.0.2"; /** use return values from previous op */ public static final int LUA_MULTRET = -1; @@ -80,7 +80,6 @@ public class Lua { public static final int POS_Bx = POS_C; public static final int POS_Ax = POS_A; - public static final int MAX_OP = ((1<>1); /* `sBx' is signed */ public static final int MAXARG_Ax = ((1<= R(A - 1) */ public static final int OP_EQ = 24; /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */ public static final int OP_LT = 25; /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ public static final int OP_LE = 26; /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */ - public static final int OP_TEST = 27; /* A C if not (R(A) <=> C) then pc++ */ - public static final int OP_TESTSET = 28; /* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ + public static final int OP_TEST = 27; /* A C if not (R(A) <=> C) then pc++ */ + public static final int OP_TESTSET = 28; /* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ public static final int OP_CALL = 29; /* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ public static final int OP_TAILCALL = 30; /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ @@ -225,7 +225,7 @@ public static int RKASK(int x) { public static final int OP_FORPREP = 33; /* A sBx R(A)-=R(A+2); pc+=sBx */ public static final int OP_TFORCALL = 34; /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */ - public static final int OP_TFORLOOP = 35; /* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx } */ + public static final int OP_TFORLOOP = 35; /* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx } */ public static final int OP_SETLIST = 36; /* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */ public static final int OP_CLOSURE = 37; /* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */ @@ -237,11 +237,11 @@ public static int RKASK(int x) { public static final int NUM_OPCODES = OP_EXTRAARG + 1; /* pseudo-opcodes used in parsing only. */ - public static final int OP_GT = 63; // > + public static final int OP_GT = 63; // > public static final int OP_GE = 62; // >= - public static final int OP_NEQ = 61; // ~= - public static final int OP_AND = 60; // and - public static final int OP_OR = 59; // or + public static final int OP_NEQ = 61; // ~= + public static final int OP_AND = 60; // and + public static final int OP_OR = 59; // or /*=========================================================================== Notes: @@ -271,7 +271,7 @@ set top (like in OP_CALL with C == 0). ** bits 4-5: B arg mode ** bit 6: instruction set register A ** bit 7: operator is a test - */ + */ public static final int OpArgN = 0; /* argument is not used */ public static final int OpArgU = 1; /* argument is used */ @@ -353,7 +353,7 @@ public static String chunkid( String source ) { source = "[string \""+source; end = "\"]"; } - int n = source.length() + end.length(); + int n = source.length() + end.length(); if ( n > MAXSRC ) source = source.substring(0,MAXSRC-end.length()-3) + "..."; return source + end; diff --git a/app/src/main/java/org/luaj/vm2/LuaClosure.java b/app/src/main/java/org/luaj/vm2/LuaClosure.java index 9f766924..7877cc62 100644 --- a/app/src/main/java/org/luaj/vm2/LuaClosure.java +++ b/app/src/main/java/org/luaj/vm2/LuaClosure.java @@ -22,22 +22,22 @@ package org.luaj.vm2; /** - * Extension of {@link LuaFunction} which executes lua bytecode. + * Extension of {@link LuaFunction} which executes lua bytecode. *

- * A {@link LuaClosure} is a combination of a {@link Prototype} + * A {@link LuaClosure} is a combination of a {@link Prototype} * and a {@link LuaValue} to use as an environment for execution. * Normally the {@link LuaValue} is a {@link Globals} in which case the environment - * will contain standard lua libraries. + * will contain standard lua libraries. * *

* There are three main ways {@link LuaClosure} instances are created: - *

* *

Loading

- * Typically, this library is included as part of a call to either + * Typically, this library is included as part of a call to either * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()} *
 {@code
  * Globals globals = JsePlatform.standardGlobals();
  * System.out.println( globals.get("require").call"foo") );
  * } 
*

- * To instantiate and use it directly, + * To instantiate and use it directly, * link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as: *

 {@code
  * Globals globals = new Globals();
@@ -67,8 +67,8 @@
  * } 
*

Limitations

* This library has been implemented to match as closely as possible the behavior in the corresponding library in C. - * However, the default filesystem search semantics are different and delegated to the bas library - * as outlined in the {@link BaseLib} and {@link org.luaj.vm2.lib.jse.JseBaseLib} documentation. + * However, the default filesystem search semantics are different and delegated to the bas library + * as outlined in the {@link BaseLib} and {@link org.luaj.vm2.lib.jse.JseBaseLib} documentation. *

* @see LibFunction * @see BaseLib @@ -81,23 +81,26 @@ public class PackageLib extends TwoArgFunction { /** The default value to use for package.path. This can be set with the system property * "luaj.package.path", and is "?.lua" by default. */ - public static String DEFAULT_LUA_PATH; + public static final String DEFAULT_LUA_PATH; static { + String path = null; try { - DEFAULT_LUA_PATH = System.getProperty("luaj.package.path"); + path = System.getProperty("luaj.package.path"); } catch (Exception e) { System.out.println(e.toString()); } - if (DEFAULT_LUA_PATH == null) - DEFAULT_LUA_PATH = "?.lua"; + if (path == null) { + path = "?.lua"; + } + DEFAULT_LUA_PATH = path; } - private static final LuaString _LOADED = valueOf("loaded"); + static final LuaString _LOADED = valueOf("loaded"); private static final LuaString _LOADLIB = valueOf("loadlib"); - private static final LuaString _PRELOAD = valueOf("preload"); - private static final LuaString _PATH = valueOf("path"); - private static final LuaString _SEARCHPATH = valueOf("searchpath"); - private static final LuaString _SEARCHERS = valueOf("searchers"); + static final LuaString _PRELOAD = valueOf("preload"); + static final LuaString _PATH = valueOf("path"); + static final LuaString _SEARCHPATH = valueOf("searchpath"); + static final LuaString _SEARCHERS = valueOf("searchers"); /** The globals that were used to load this library. */ Globals globals; @@ -153,7 +156,7 @@ public void setIsLoaded(String name, LuaTable value) { } - /** Set the lua path used by this library instance to a new value. + /** Set the lua path used by this library instance to a new value. * Merely sets the value of {@link path} to be used in subsequent searches. */ public void setLuaPath( String newLuaPath ) { package_.set(_PATH, LuaValue.valueOf(newLuaPath)); @@ -165,33 +168,33 @@ public String tojstring() { // ======================== Package loading ============================= - /** + /** * require (modname) * - * Loads the given module. The function starts by looking into the package.loaded table - * to determine whether modname is already loaded. If it is, then require returns the value + * Loads the given module. The function starts by looking into the package.loaded table + * to determine whether modname is already loaded. If it is, then require returns the value * stored at package.loaded[modname]. Otherwise, it tries to find a loader for the module. * - * To find a loader, require is guided by the package.searchers sequence. - * By changing this sequence, we can change how require looks for a module. + * To find a loader, require is guided by the package.searchers sequence. + * By changing this sequence, we can change how require looks for a module. * The following explanation is based on the default configuration for package.searchers. * - * First require queries package.preload[modname]. If it has a value, this value - * (which should be a function) is the loader. Otherwise require searches for a Lua loader using - * the path stored in package.path. If that also fails, it searches for a Java loader using + * First require queries package.preload[modname]. If it has a value, this value + * (which should be a function) is the loader. Otherwise require searches for a Lua loader using + * the path stored in package.path. If that also fails, it searches for a Java loader using * the classpath, using the public default constructor, and casting the instance to LuaFunction. * - * Once a loader is found, require calls the loader with two arguments: modname and an extra value + * Once a loader is found, require calls the loader with two arguments: modname and an extra value * dependent on how it got the loader. If the loader came from a file, this extra value is the file name. - * If the loader is a Java instance of LuaFunction, this extra value is the environment. - * If the loader returns any non-nil value, require assigns the returned value to package.loaded[modname]. - * If the loader does not return a non-nil value and has not assigned any value to package.loaded[modname], + * If the loader is a Java instance of LuaFunction, this extra value is the environment. + * If the loader returns any non-nil value, require assigns the returned value to package.loaded[modname]. + * If the loader does not return a non-nil value and has not assigned any value to package.loaded[modname], * then require assigns true to this entry. * In any case, require returns the final value of package.loaded[modname]. - * + * * If there is any error loading or running the module, or if it cannot find any loader for the module, * then require raises an error. - */ + */ public class require extends OneArgFunction { public LuaValue call( LuaValue arg ) { LuaString name = arg.checkstring(); @@ -210,7 +213,7 @@ public LuaValue call( LuaValue arg ) { for ( int i=1; true; i++ ) { LuaValue searcher = tbl.get(i); if ( searcher.isnil() ) { - error( "module '"+name+"' not found: "+name+sb ); + error( "module '"+name+"' not found: "+name+sb ); } /* call loader with module name as argument */ @@ -226,14 +229,14 @@ public LuaValue call( LuaValue arg ) { result = loader.arg1().call(name, loader.arg(2)); if ( ! result.isnil() ) loaded.set( name, result ); - else if ( (result = loaded.get(name)) == _SENTINEL ) + else if ( (result = loaded.get(name)) == _SENTINEL ) loaded.set( name, result = LuaValue.TRUE ); return result; } } public static class loadlib extends VarArgFunction { - public Varargs loadlib( Varargs args ) { + public Varargs invoke( Varargs args ) { args.checkstring(1); return varargsOf(NIL, valueOf("dynamic libraries not enabled"), valueOf("absent")); } @@ -243,7 +246,7 @@ public class preload_searcher extends VarArgFunction { public Varargs invoke(Varargs args) { LuaString name = args.checkstring(1); LuaValue val = package_.get(_PRELOAD).get(name); - return val.isnil()? + return val.isnil()? valueOf("\n\tno field package.preload['"+name+"']"): val; } @@ -252,11 +255,10 @@ public Varargs invoke(Varargs args) { public class lua_searcher extends VarArgFunction { public Varargs invoke(Varargs args) { LuaString name = args.checkstring(1); - InputStream is = null; // get package path LuaValue path = package_.get(_PATH); - if ( ! path.isstring() ) + if ( ! path.isstring() ) return valueOf("package.path is not a string"); // get the searchpath function. @@ -268,7 +270,7 @@ public Varargs invoke(Varargs args) { LuaString filename = v.arg1().strvalue(); // Try to load the file. - v = globals.loadfile(filename.tojstring()); + v = globals.loadfile(filename.tojstring()); if ( v.arg1().isfunction() ) return LuaValue.varargsOf(v.arg1(), filename); @@ -353,9 +355,9 @@ public static final String toClassname( String filename ) { StringBuffer sb = new StringBuffer(j); for ( int i=0; i - * Typically, this library is included as part of a call to either + * Typically, this library is included as part of a call to either * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()} *

 {@code
  * Globals globals = JsePlatform.standardGlobals();
  * System.out.println( globals.get("string").get("upper").call( LuaValue.valueOf("abcde") ) );
  * } 
*

- * To instantiate and use it directly, + * To instantiate and use it directly, * link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as: *

 {@code
  * Globals globals = new Globals();
  * globals.load(new JseBaseLib());
  * globals.load(new PackageLib());
- * globals.load(new StringLib());
+ * globals.load(new JseStringLib());
  * System.out.println( globals.get("string").get("upper").call( LuaValue.valueOf("abcde") ) );
  * } 
*

@@ -61,8 +61,8 @@ */ public class StringLib extends TwoArgFunction { - /** Construct a StringLib, which can be initialized by calling it with a - * modname string, and a global environment table as arguments using + /** Construct a StringLib, which can be initialized by calling it with a + * modname string, and a global environment table as arguments using * {@link #call(LuaValue, LuaValue)}. */ public StringLib() { } @@ -75,8 +75,8 @@ public StringLib() { * If the shared strings metatable instance is null, will set the metatable as * the global shared metatable for strings. *

- * All tables and metatables are read-write by default so if this will be used in - * a server environment, sandboxing should be used. In particular, the + * All tables and metatables are read-write by default so if this will be used in + * a server environment, sandboxing should be used. In particular, the * {@link LuaString#s_metatable} table should probably be made read-only. * @param modname the module name supplied if this is loaded via 'require'. * @param env the environment to load into, typically a Globals instance. @@ -97,17 +97,17 @@ public LuaValue call(LuaValue modname, LuaValue env) { string.set("reverse", new reverse()); string.set("sub", new sub()); string.set("upper", new upper()); - LuaTable mt = LuaValue.tableOf( - new LuaValue[] { INDEX, string }); + env.set("string", string); - env.get("package").get("loaded").set("string", string); - if (LuaString.s_metatable == null) - LuaString.s_metatable = mt; + if (!env.get("package").isnil()) env.get("package").get("loaded").set("string", string); + if (LuaString.s_metatable == null) { + LuaString.s_metatable = LuaValue.tableOf(new LuaValue[] { INDEX, string }); + } return string; } /** - * string.byte (s [, i [, j]]) + * string.byte (s [, i [, j]]) * * Returns the internal numerical codes of the * characters s[i], s[i+1], ..., s[j]. The default value for i is 1; the @@ -137,12 +137,12 @@ public Varargs invoke(Varargs args) { } } - /** + /** * string.char (...) * - * Receives zero or more integers. Returns a string with length equal - * to the number of arguments, in which each character has the internal - * numerical code equal to its corresponding argument. + * Receives zero or more integers. Returns a string with length equal + * to the number of arguments, in which each character has the internal + * numerical code equal to its corresponding argument. * * Note that numerical codes are not necessarily portable across platforms. * @@ -154,28 +154,30 @@ public Varargs invoke(Varargs args) { byte[] bytes = new byte[n]; for ( int i=0, a=1; i=256) argerror(a, "invalid value"); + if (c<0 || c>=256) argerror(a, "invalid value for string.char [0; 255]: " + c); bytes[i] = (byte) c; } return LuaString.valueUsing( bytes ); } } - /** - * string.dump (function) + /** + * string.dump (function[, stripDebug]) * - * Returns a string containing a binary representation of the given function, - * so that a later loadstring on this string returns a copy of the function. + * Returns a string containing a binary representation of the given function, + * so that a later loadstring on this string returns a copy of the function. * function must be a Lua function without upvalues. - * + * Boolean param stripDebug - true to strip debugging info, false otherwise. + * The default value for stripDebug is true. + * * TODO: port dumping code as optional add-on */ - static final class dump extends OneArgFunction { - public LuaValue call(LuaValue arg) { - LuaValue f = arg.checkfunction(); + static final class dump extends VarArgFunction { + public Varargs invoke(Varargs args) { + LuaValue f = args.checkfunction(1); ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { - DumpState.dump( ((LuaClosure)f).p, baos, true ); + DumpState.dump( ((LuaClosure)f).p, baos, args.optboolean(2, true) ); return LuaString.valueUsing(baos.toByteArray()); } catch (IOException e) { return error( e.getMessage() ); @@ -183,20 +185,20 @@ public LuaValue call(LuaValue arg) { } } - /** + /** * string.find (s, pattern [, init [, plain]]) * - * Looks for the first match of pattern in the string s. - * If it finds a match, then find returns the indices of s - * where this occurrence starts and ends; otherwise, it returns nil. - * A third, optional numerical argument init specifies where to start the search; - * its default value is 1 and may be negative. A value of true as a fourth, - * optional argument plain turns off the pattern matching facilities, - * so the function does a plain "find substring" operation, - * with no characters in pattern being considered "magic". + * Looks for the first match of pattern in the string s. + * If it finds a match, then find returns the indices of s + * where this occurrence starts and ends; otherwise, it returns nil. + * A third, optional numerical argument init specifies where to start the search; + * its default value is 1 and may be negative. A value of true as a fourth, + * optional argument plain turns off the pattern matching facilities, + * so the function does a plain "find substring" operation, + * with no characters in pattern being considered "magic". * Note that if plain is given, then init must be given as well. * - * If the pattern has captures, then in a successful match the captured values + * If the pattern has captures, then in a successful match the captured values * are also returned, after the two indices. */ static final class find extends VarArgFunction { @@ -205,30 +207,30 @@ public Varargs invoke(Varargs args) { } } - /** + /** * string.format (formatstring, ...) * - * Returns a formatted version of its variable number of arguments following - * the description given in its first argument (which must be a string). - * The format string follows the same rules as the printf family of standard C functions. - * The only differences are that the options/modifiers *, l, L, n, p, and h are not supported - * and that there is an extra option, q. The q option formats a string in a form suitable - * to be safely read back by the Lua interpreter: the string is written between double quotes, - * and all double quotes, newlines, embedded zeros, and backslashes in the string are correctly + * Returns a formatted version of its variable number of arguments following + * the description given in its first argument (which must be a string). + * The format string follows the same rules as the printf family of standard C functions. + * The only differences are that the options/modifiers *, l, L, n, p, and h are not supported + * and that there is an extra option, q. The q option formats a string in a form suitable + * to be safely read back by the Lua interpreter: the string is written between double quotes, + * and all double quotes, newlines, embedded zeros, and backslashes in the string are correctly * escaped when written. For instance, the call * string.format('%q', 'a string with "quotes" and \n new line') * * will produce the string: * "a string with \"quotes\" and \ * new line" - * - * The options c, d, E, e, f, g, G, i, o, u, X, and x all expect a number as argument, - * whereas q and s expect a string. * - * This function does not accept string values containing embedded zeros, - * except as arguments to the q option. + * The options c, d, E, e, f, g, G, i, o, u, X, and x all expect a number as argument, + * whereas q and s expect a string. + * + * This function does not accept string values containing embedded zeros, + * except as arguments to the q option. */ - static final class format extends VarArgFunction { + final class format extends VarArgFunction { public Varargs invoke(Varargs args) { LuaString fmt = args.checkstring( 1 ); final int n = fmt.length(); @@ -259,7 +261,7 @@ public Varargs invoke(Varargs args) { break; case 'i': case 'd': - fdsc.format( result, args.checkint( arg ) ); + fdsc.format( result, args.checklong( arg ) ); break; case 'o': case 'u': @@ -298,7 +300,7 @@ public Varargs invoke(Varargs args) { } } - private static void addquoted(Buffer buf, LuaString s) { + static void addquoted(Buffer buf, LuaString s) { int c; buf.append( (byte) '"' ); for ( int i = 0, n = s.length(); i < n; i++ ) { @@ -328,7 +330,7 @@ private static void addquoted(Buffer buf, LuaString s) { private static final String FLAGS = "-+ #0"; - static class FormatDesc { + class FormatDesc { private boolean leftAdjust; private boolean zeroPad; @@ -338,11 +340,13 @@ static class FormatDesc { private static final int MAX_FLAGS = 5; private int width; - private int precision; + int precision; public final int conversion; public final int length; + public final String src; + public FormatDesc(Varargs args, LuaString strfrmt, final int start) { int p = start, n = strfrmt.length(); int c = 0; @@ -390,6 +394,7 @@ public FormatDesc(Varargs args, LuaString strfrmt, final int start) { zeroPad &= !leftAdjust; // '-' overrides '0' conversion = c; length = p - start; + src = strfrmt.substring(start - 1, p).tojstring(); } public void format(Buffer buf, byte c) { @@ -465,8 +470,7 @@ else if ( precision == -1 && zeroPad && width > minwidth ) } public void format(Buffer buf, double x) { - // TODO - buf.append( String.valueOf( x ) ); + buf.append( StringLib.this.format(src, x) ); } public void format(Buffer buf, LuaString s) { @@ -476,27 +480,31 @@ public void format(Buffer buf, LuaString s) { buf.append(s); } - public static final void pad(Buffer buf, char c, int n) { + public final void pad(Buffer buf, char c, int n) { byte b = (byte)c; while ( n-- > 0 ) buf.append(b); } } - /** + protected String format(String src, double x) { + return String.valueOf(x); + } + + /** * string.gmatch (s, pattern) * - * Returns an iterator function that, each time it is called, returns the next captures - * from pattern over string s. If pattern specifies no captures, then the - * whole match is produced in each call. + * Returns an iterator function that, each time it is called, returns the next captures + * from pattern over string s. If pattern specifies no captures, then the + * whole match is produced in each call. * * As an example, the following loop * s = "hello world from Lua" * for w in string.gmatch(s, "%a+") do * print(w) * end - * - * will iterate over all the words from string s, printing one per line. + * + * will iterate over all the words from string s, printing one per line. * The next example collects all pairs key=value from the given string into a table: * t = {} * s = "from=world, to=Lua" @@ -504,7 +512,7 @@ public static final void pad(Buffer buf, char c, int n) { * t[k] = v * end * - * For this function, a '^' at the start of a pattern does not work as an anchor, + * For this function, a '^' at the start of a pattern does not work as an anchor, * as this would prevent the iteration. */ static final class gmatch extends VarArgFunction { @@ -525,12 +533,13 @@ public GMatchAux(Varargs args, LuaString src, LuaString pat) { this.soffset = 0; } public Varargs invoke(Varargs args) { - for ( ; soffset=0 ) { int soff = soffset; soffset = res; + if (soff == res) soffset++; /* empty match? go at least one position */ return ms.push_captures( true, soff, res ); } } @@ -539,28 +548,28 @@ public Varargs invoke(Varargs args) { } - /** + /** * string.gsub (s, pattern, repl [, n]) - * Returns a copy of s in which all (or the first n, if given) occurrences of the - * pattern have been replaced by a replacement string specified by repl, which - * may be a string, a table, or a function. gsub also returns, as its second value, + * Returns a copy of s in which all (or the first n, if given) occurrences of the + * pattern have been replaced by a replacement string specified by repl, which + * may be a string, a table, or a function. gsub also returns, as its second value, * the total number of matches that occurred. * - * If repl is a string, then its value is used for replacement. - * The character % works as an escape character: any sequence in repl of the form %n, - * with n between 1 and 9, stands for the value of the n-th captured substring (see below). - * The sequence %0 stands for the whole match. The sequence %% stands for a single %. - * - * If repl is a table, then the table is queried for every match, using the first capture - * as the key; if the pattern specifies no captures, then the whole match is used as the key. + * If repl is a string, then its value is used for replacement. + * The character % works as an escape character: any sequence in repl of the form %n, + * with n between 1 and 9, stands for the value of the n-th captured substring (see below). + * The sequence %0 stands for the whole match. The sequence %% stands for a single %. * - * If repl is a function, then this function is called every time a match occurs, - * with all captured substrings passed as arguments, in order; if the pattern specifies - * no captures, then the whole match is passed as a sole argument. + * If repl is a table, then the table is queried for every match, using the first capture + * as the key; if the pattern specifies no captures, then the whole match is used as the key. * - * If the value returned by the table query or by the function call is a string or a number, - * then it is used as the replacement string; otherwise, if it is false or nil, - * then there is no replacement (that is, the original match is kept in the string). + * If repl is a function, then this function is called every time a match occurs, + * with all captured substrings passed as arguments, in order; if the pattern specifies + * no captures, then the whole match is passed as a sole argument. + * + * If the value returned by the table query or by the function call is a string or a number, + * then it is used as the replacement string; otherwise, if it is false or nil, + * then there is no replacement (that is, the original match is kept in the string). * * Here are some examples: * x = string.gsub("hello world", "(%w+)", "%1 %1") @@ -619,11 +628,11 @@ else if ( soffset < srclen ) } } - /** + /** * string.len (s) * - * Receives a string and returns its length. The empty string "" has length 0. - * Embedded zeros are counted, so "a\000bc\000" has length 5. + * Receives a string and returns its length. The empty string "" has length 0. + * Embedded zeros are counted, so "a\000bc\000" has length 5. */ static final class len extends OneArgFunction { public LuaValue call(LuaValue arg) { @@ -631,11 +640,11 @@ public LuaValue call(LuaValue arg) { } } - /** + /** * string.lower (s) * - * Receives a string and returns a copy of this string with all uppercase letters - * changed to lowercase. All other characters are left unchanged. + * Receives a string and returns a copy of this string with all uppercase letters + * changed to lowercase. All other characters are left unchanged. * The definition of what an uppercase letter is depends on the current locale. */ static final class lower extends OneArgFunction { @@ -662,7 +671,7 @@ public Varargs invoke(Varargs args) { /** * string.rep (s, n) * - * Returns a string that is the concatenation of n copies of the string s. + * Returns a string that is the concatenation of n copies of the string s. */ static final class rep extends VarArgFunction { public Varargs invoke(Varargs args) { @@ -677,10 +686,10 @@ public Varargs invoke(Varargs args) { } } - /** + /** * string.reverse (s) * - * Returns a string that is the string s reversed. + * Returns a string that is the string s reversed. */ static final class reverse extends OneArgFunction { public LuaValue call(LuaValue arg) { @@ -693,15 +702,15 @@ public LuaValue call(LuaValue arg) { } } - /** + /** * string.sub (s, i [, j]) * - * Returns the substring of s that starts at i and continues until j; - * i and j may be negative. If j is absent, then it is assumed to be equal to -1 - * (which is the same as the string length). In particular, the call - * string.sub(s,1,j) - * returns a prefix of s with length j, and - * string.sub(s, -i) + * Returns the substring of s that starts at i and continues until j; + * i and j may be negative. If j is absent, then it is assumed to be equal to -1 + * (which is the same as the string length). In particular, the call + * string.sub(s,1,j) + * returns a prefix of s with length j, and + * string.sub(s, -i) * returns a suffix of s with length i. */ static final class sub extends VarArgFunction { @@ -725,12 +734,12 @@ public Varargs invoke(Varargs args) { } } - /** + /** * string.upper (s) * - * Receives a string and returns a copy of this string with all lowercase letters - * changed to uppercase. All other characters are left unchanged. - * The definition of what a lowercase letter is depends on the current locale. + * Receives a string and returns a copy of this string with all lowercase letters + * changed to uppercase. All other characters are left unchanged. + * The definition of what a lowercase letter is depends on the current locale. */ static final class upper extends OneArgFunction { public LuaValue call(LuaValue arg) { @@ -764,7 +773,7 @@ static Varargs str_find_aux( Varargs args, boolean find ) { boolean anchor = false; int poff = 0; - if ( pat.luaByte( 0 ) == '^' ) { + if ( pat.length() > 0 && pat.luaByte( 0 ) == '^' ) { anchor = true; poff = 1; } @@ -785,7 +794,7 @@ static Varargs str_find_aux( Varargs args, boolean find ) { return NIL; } - private static int posrelat( int pos, int len ) { + static int posrelat( int pos, int len ) { return ( pos >= 0 ) ? pos : len + pos + 1; } @@ -807,7 +816,7 @@ private static int posrelat( int pos, int len ) { private static final byte MASK_CONTROL = 0x40; private static final byte MASK_HEXDIGIT = (byte)0x80; - private static final byte[] CHAR_TABLE; + static final byte[] CHAR_TABLE; static { CHAR_TABLE = new byte[256]; @@ -866,8 +875,14 @@ private void add_s( Buffer lbuf, LuaString news, int soff, int e ) { lbuf.append( (byte) b ); } else { ++i; // skip ESC - b = (byte) news.luaByte( i ); + b = (byte)(i < l ? news.luaByte( i ) : 0); if ( !Character.isDigit( (char) b ) ) { + if (b != L_ESC) error( "invalid use of '" + (char)L_ESC + + "' in replacement string: after '" + (char)L_ESC + + "' must be '0'-'9' or '" + (char)L_ESC + + "', but found " + (i < l ? "symbol '" + (char)b + "' with code " + b + + " at pos " + (i + 1) : + "end of string")); lbuf.append( b ); } else if ( b == '0' ) { lbuf.append( s.substring( soff, e ) ); @@ -961,19 +976,19 @@ int classend( int poffset ) { switch ( p.luaByte( poffset++ ) ) { case L_ESC: if ( poffset == p.length() ) { - error( "malformed pattern (ends with %)" ); + error( "malformed pattern (ends with '%')" ); } return poffset + 1; case '[': - if ( p.luaByte( poffset ) == '^' ) poffset++; + if ( poffset != p.length() && p.luaByte( poffset ) == '^' ) poffset++; do { if ( poffset == p.length() ) { - error( "malformed pattern (missing ])" ); + error( "malformed pattern (missing ']')" ); } - if ( p.luaByte( poffset++ ) == L_ESC && poffset != p.length() ) - poffset++; - } while ( p.luaByte( poffset ) != ']' ); + if ( p.luaByte( poffset++ ) == L_ESC && poffset < p.length() ) + poffset++; /* skip escapes (e.g. '%]') */ + } while ( poffset == p.length() || p.luaByte( poffset ) != ']' ); return poffset + 1; default: return poffset; @@ -1038,7 +1053,7 @@ boolean singlematch( int c, int poff, int ep ) { */ int match( int soffset, int poffset ) { while ( true ) { - // Check if we are at the end of the pattern - + // Check if we are at the end of the pattern - // equivalent to the '\0' case in the C version, but our pattern // string is not NUL-terminated. if ( poffset == p.length() ) @@ -1062,13 +1077,14 @@ int match( int soffset, int poffset ) { continue; case 'f': { poffset += 2; - if ( p.luaByte( poffset ) != '[' ) { - error("Missing [ after %f in pattern"); + if ( poffset == p.length() || p.luaByte( poffset ) != '[' ) { + error("Missing '[' after '%f' in pattern"); } int ep = classend( poffset ); - int previous = ( soffset == 0 ) ? -1 : s.luaByte( soffset - 1 ); + int previous = ( soffset == 0 ) ? '\0' : s.luaByte( soffset - 1 ); + int next = ( soffset == s.length() ) ? '\0' : s.luaByte( soffset ); if ( matchbracketclass( previous, poffset, ep - 1 ) || - matchbracketclass( s.luaByte( soffset ), poffset, ep - 1 ) ) + !matchbracketclass( next, poffset, ep - 1 ) ) return -1; poffset = ep; continue; diff --git a/app/src/main/java/org/luaj/vm2/lib/TableLib.java b/app/src/main/java/org/luaj/vm2/lib/TableLib.java index bc613676..74456952 100644 --- a/app/src/main/java/org/luaj/vm2/lib/TableLib.java +++ b/app/src/main/java/org/luaj/vm2/lib/TableLib.java @@ -25,19 +25,19 @@ import org.luaj.vm2.LuaValue; import org.luaj.vm2.Varargs; -/** - * Subclass of {@link LibFunction} which implements the lua standard {@code table} - * library. +/** + * Subclass of {@link LibFunction} which implements the lua standard {@code table} + * library. * *

- * Typically, this library is included as part of a call to either + * Typically, this library is included as part of a call to either * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()} *

 {@code
  * Globals globals = JsePlatform.standardGlobals();
  * System.out.println( globals.get("table").get("length").call( LuaValue.tableOf() ) );
  * } 
*

- * To instantiate and use it directly, + * To instantiate and use it directly, * link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as: *

 {@code
  * Globals globals = new Globals();
@@ -70,7 +70,7 @@ public LuaValue call(LuaValue modname, LuaValue env) {
 		table.set("sort", new sort());
 		table.set("unpack", new unpack());
 		env.set("table", table);
-		env.get("package").get("loaded").set("table", table);
+		if (!env.get("package").isnil()) env.get("package").get("loaded").set("table", table);
 		return NIL;
 	}
 
diff --git a/app/src/main/java/org/luaj/vm2/lib/jse/CoerceJavaToLua.java b/app/src/main/java/org/luaj/vm2/lib/jse/CoerceJavaToLua.java
index 107fafd0..177f9acf 100644
--- a/app/src/main/java/org/luaj/vm2/lib/jse/CoerceJavaToLua.java
+++ b/app/src/main/java/org/luaj/vm2/lib/jse/CoerceJavaToLua.java
@@ -102,11 +102,11 @@ public LuaValue coerce( Object javaValue ) {
 		}
 	}
 
-	//private static final class BytesCoercion implements Coercion {
-	//	public LuaValue coerce( Object javaValue ) {
-	//		return LuaValue.valueOf((byte[]) javaValue);
-	//	}
-	//}
+	private static final class BytesCoercion implements Coercion {
+		public LuaValue coerce( Object javaValue ) {
+			return LuaValue.valueOf((byte[]) javaValue);
+		}
+	}
 
 	private static final class ClassCoercion implements Coercion {
 		public LuaValue coerce( Object javaValue ) {
@@ -142,7 +142,7 @@ public LuaValue coerce( Object javaValue ) {
 		Coercion charCoercion = new CharCoercion() ;
 		Coercion doubleCoercion = new DoubleCoercion() ;
 		Coercion stringCoercion = new StringCoercion() ;
-		//Coercion bytesCoercion = new BytesCoercion() ;
+		Coercion bytesCoercion = new BytesCoercion() ;
 		Coercion classCoercion = new ClassCoercion() ;
 		COERCIONS.put( Boolean.class, boolCoercion );
 		COERCIONS.put( Byte.class, intCoercion );
@@ -153,7 +153,7 @@ public LuaValue coerce( Object javaValue ) {
 		COERCIONS.put( Float.class, doubleCoercion );
 		COERCIONS.put( Double.class, doubleCoercion );
 		COERCIONS.put( String.class, stringCoercion );
-		//COERCIONS.put( byte[].class, bytesCoercion );
+		COERCIONS.put( byte[].class, bytesCoercion );
 		COERCIONS.put( Class.class, classCoercion );
 	}
 
diff --git a/app/src/main/java/org/luaj/vm2/lib/jse/JavaClass.java b/app/src/main/java/org/luaj/vm2/lib/jse/JavaClass.java
index 4011eee3..553c8e73 100644
--- a/app/src/main/java/org/luaj/vm2/lib/jse/JavaClass.java
+++ b/app/src/main/java/org/luaj/vm2/lib/jse/JavaClass.java
@@ -26,7 +26,6 @@
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -76,22 +75,10 @@ public LuaValue coerce(Object javaValue) {
 	Field getField(LuaValue key) {
 		if ( fields == null ) {
 			Map m = new HashMap();
-			List n = new ArrayList();
-			for (Method p : ((Class) m_instance).getMethods())
-				n.add(p.getName());
-			for (Method p : ((Class) m_instance).getDeclaredMethods())
-				n.add(p.getName());
-			List lf = new ArrayList();
-			for (Field p : ((Class) m_instance).getFields())
-				if (!n.contains(p.getName()))
-					lf.add(p);
-			for (Field p : ((Class) m_instance).getDeclaredFields())
-				if (!n.contains(p.getName()) && !lf.contains(p))
-					lf.add(p);
-			Field[] f = lf.toArray(new Field[0]);
+			Field[] f = ((Class)m_instance).getFields();
 			for ( int i=0; i lm = new ArrayList();
-			lm.addAll(Arrays.asList(((Class) m_instance).getMethods()));
-			for (Method p : ((Class) m_instance).getDeclaredMethods())
-				if (!lm.contains(p))
-					lm.add(p);
-			Method[] m = lm.toArray(new Method[0]);
+			Method[] m = ((Class)m_instance).getMethods();
 			for ( int i=0; i lc = new ArrayList();
-			lc.addAll(Arrays.asList(((Class) m_instance).getConstructors()));
-			for (Constructor p : ((Class) m_instance).getDeclaredConstructors())
-				if (!lc.contains(p))
-					lc.add(p);
-			Constructor[] c = lc.toArray(new Constructor[0]);
+			Constructor[] c = ((Class)m_instance).getConstructors();
 			List list = new ArrayList();
 			for ( int i=0; i
- * It is used to allocate either a set of standard globals using 
+ * It is used to allocate either a set of standard globals using
  * {@link #standardGlobals()} or debug globals using {@link #debugGlobals()}
  * 

* A simple example of initializing globals and using them from Java is: @@ -52,7 +51,7 @@ * globals.load( new FileInputStream("main.lua"), "main.lua" ).call(); * }

*

- * although {@code require} could also be used: + * although {@code require} could also be used: *

 {@code
  * globals.get("require").call(LuaValue.valueOf("main"));
  * } 
@@ -73,8 +72,8 @@ *
  • {@link org.luaj.vm2.lib.jse.JseOsLib}
  • *
  • {@link org.luaj.vm2.lib.jse.LuajavaLib}
  • * - * In addition, the {@link LuaC} compiler is installed so lua files may be loaded in their source form. - *

    + * In addition, the {@link LuaC} compiler is installed so lua files may be loaded in their source form. + *

    * The debug globals are simply the standard globals plus the {@code debug} library {@link DebugLib}. *

    * The class ensures that initialization is done in the correct order. @@ -98,7 +97,7 @@ public static Globals standardGlobals() { globals.load(new PackageLib()); globals.load(new Bit32Lib()); globals.load(new TableLib()); - globals.load(new StringLib()); + globals.load(new JseStringLib()); globals.load(new CoroutineLib()); globals.load(new JseMathLib()); globals.load(new JseIoLib()); @@ -106,7 +105,7 @@ public static Globals standardGlobals() { globals.load(new LuajavaLib()); LoadState.install(globals); LuaC.install(globals); - return globals; + return globals; } /** Create standard globals including the {@link DebugLib} library. @@ -124,9 +123,9 @@ public static Globals debugGlobals() { } - /** Simple wrapper for invoking a lua function with command line arguments. + /** Simple wrapper for invoking a lua function with command line arguments. * The supplied function is first given a new Globals object as its environment - * then the program is run with arguments. + * then the program is run with arguments. * @return {@link Varargs} containing any values returned by mainChunk. */ public static Varargs luaMain(LuaValue mainChunk, String[] args) { diff --git a/app/src/main/java/org/luaj/vm2/lib/jse/JseStringLib.java b/app/src/main/java/org/luaj/vm2/lib/jse/JseStringLib.java new file mode 100644 index 00000000..41177787 --- /dev/null +++ b/app/src/main/java/org/luaj/vm2/lib/jse/JseStringLib.java @@ -0,0 +1,39 @@ +/******************************************************************************* +* Copyright (c) 2009 Luaj.org. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +******************************************************************************/ +package org.luaj.vm2.lib.jse; + +public class JseStringLib extends org.luaj.vm2.lib.StringLib { + + /** public constructor */ + public JseStringLib() { + } + + protected String format(String src, double x) { + String out; + try { + out = String.format(src, new Object[] {Double.valueOf(x)}); + } catch (Throwable e) { + out = super.format(src, x); + } + return out; + } +} diff --git a/app/src/main/java/org/luaj/vm2/lib/jse/LuajavaLib.java b/app/src/main/java/org/luaj/vm2/lib/jse/LuajavaLib.java index 4d9b634f..35f1f850 100644 --- a/app/src/main/java/org/luaj/vm2/lib/jse/LuajavaLib.java +++ b/app/src/main/java/org/luaj/vm2/lib/jse/LuajavaLib.java @@ -37,38 +37,38 @@ import org.luaj.vm2.lib.LibFunction; import org.luaj.vm2.lib.VarArgFunction; -/** - * Subclass of {@link LibFunction} which implements the features of the luajava package. - *

    - * Luajava is an approach to mixing lua and java using simple functions that bind - * java classes and methods to lua dynamically. The API is documented on the +/** + * Subclass of {@link LibFunction} which implements the features of the luajava package. + *

    + * Luajava is an approach to mixing lua and java using simple functions that bind + * java classes and methods to lua dynamically. The API is documented on the * luajava documentation pages. * *

    - * Typically, this library is included as part of a call to + * Typically, this library is included as part of a call to * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} *

     {@code
      * Globals globals = JsePlatform.standardGlobals();
      * System.out.println( globals.get("luajava").get("bindClass").call( LuaValue.valueOf("java.lang.System") ).invokeMethod("currentTimeMillis") );
      * } 
    *

    - * To instantiate and use it directly, + * To instantiate and use it directly, * link it into your globals table via {@link Globals#load} using code such as: *

     {@code
      * Globals globals = new Globals();
      * globals.load(new JseBaseLib());
      * globals.load(new PackageLib());
      * globals.load(new LuajavaLib());
    - * globals.load( 
    + * globals.load(
      *      "sys = luajava.bindClass('java.lang.System')\n"+
    - *      "print ( sys:currentTimeMillis() )\n", "main.lua" ).call(); 
    + *      "print ( sys:currentTimeMillis() )\n", "main.lua" ).call();
      * } 
    *

    * - * The {@code luajava} library is available + * The {@code luajava} library is available * on all JSE platforms via the call to {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} - * and the luajava api's are simply invoked from lua. - * Because it makes extensive use of Java's reflection API, it is not available + * and the luajava api's are simply invoked from lua. + * Because it makes extensive use of Java's reflection API, it is not available * on JME, but can be used in Android applications. *

    * This has been implemented to match as closely as possible the behavior in the corresponding library in C. @@ -91,10 +91,10 @@ public class LuajavaLib extends VarArgFunction { static final int LOADLIB = 5; static final String[] NAMES = { - "bindClass", - "newInstance", - "new", - "createProxy", + "bindClass", + "newInstance", + "new", + "createProxy", "loadLib", }; @@ -112,7 +112,7 @@ public Varargs invoke(Varargs args) { LuaTable t = new LuaTable(); bind( t, this.getClass(), NAMES, BINDCLASS ); env.set("luajava", t); - env.get("package").get("loaded").set("luajava", t); + if (!env.get("package").isnil()) env.get("package").get("loaded").set("luajava", t); return t; } case BINDCLASS: { @@ -122,13 +122,13 @@ public Varargs invoke(Varargs args) { case NEWINSTANCE: case NEW: { // get constructor - final LuaValue c = args.checkvalue(1); + final LuaValue c = args.checkvalue(1); final Class clazz = (opcode==NEWINSTANCE? classForName(c.tojstring()): (Class) c.checkuserdata(Class.class)); final Varargs consargs = args.subargs(2); return JavaClass.forClass(clazz).getConstructor().invoke(consargs); } - case CREATEPROXY: { + case CREATEPROXY: { final int niface = args.narg()-1; if ( niface <= 0 ) throw new LuaError("no interfaces"); @@ -136,7 +136,7 @@ public Varargs invoke(Varargs args) { // get the interfaces final Class[] ifaces = new Class[niface]; - for ( int i=0; i