From 6031d6b47906ba00f9dbed767cfe2289d03c7a07 Mon Sep 17 00:00:00 2001 From: Enyby Date: Sat, 21 Sep 2019 07:18:08 +0300 Subject: [PATCH 01/62] Fix lua error message on bad arg for 'load'. --- src/core/org/luaj/vm2/lib/BaseLib.java | 970 +++++++++++++------------ 1 file changed, 486 insertions(+), 484 deletions(-) diff --git a/src/core/org/luaj/vm2/lib/BaseLib.java b/src/core/org/luaj/vm2/lib/BaseLib.java index 0c2f43e0..524c7af7 100644 --- a/src/core/org/luaj/vm2/lib/BaseLib.java +++ b/src/core/org/luaj/vm2/lib/BaseLib.java @@ -1,484 +1,486 @@ -/******************************************************************************* -* 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; - -import java.io.IOException; -import java.io.InputStream; - -import org.luaj.vm2.Globals; -import org.luaj.vm2.Lua; -import org.luaj.vm2.LuaError; -import org.luaj.vm2.LuaString; -import org.luaj.vm2.LuaTable; -import org.luaj.vm2.LuaThread; -import org.luaj.vm2.LuaValue; -import org.luaj.vm2.Varargs; - -/** - * Subclass of {@link LibFunction} which implements the lua basic library functions. - *

- * This contains all library functions listed as "basic functions" in the lua documentation for JME. - * The functions dofile and loadfile use the - * {@link Globals#finder} instance to find resource files. - * Since JME has no file system by default, {@link BaseLib} implements - * {@link ResourceFinder} using {@link Class#getResource(String)}, - * which is the closest equivalent on JME. - * The default loader chain in {@link PackageLib} will use these as well. - *

- * To use basic library functions that include a {@link ResourceFinder} based on - * directory lookup, use {@link org.luaj.vm2.lib.jse.JseBaseLib} instead. - *

- * 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();
- * globals.get("print").call(LuaValue.valueOf("hello, world"));
- * } 
- *

- * For special cases where the smallest possible footprint is desired, - * a minimal set of libraries could be loaded - * directly via {@link Globals#load(LuaValue)} using code such as: - *

 {@code
- * Globals globals = new Globals();
- * globals.load(new JseBaseLib());
- * globals.get("print").call(LuaValue.valueOf("hello, world"));
- * } 
- * Doing so will ensure the library is properly initialized - * and loaded into the globals table. - *

- * This is a direct port of the corresponding library in C. - * @see org.luaj.vm2.lib.jse.JseBaseLib - * @see ResourceFinder - * @see Globals#finder - * @see LibFunction - * @see org.luaj.vm2.lib.jse.JsePlatform - * @see org.luaj.vm2.lib.jme.JmePlatform - * @see Lua 5.2 Base Lib Reference - */ -public class BaseLib extends TwoArgFunction implements ResourceFinder { - - Globals globals; - - - /** Perform one-time initialization on the library by adding base functions - * to the supplied environment, and returning it as the return value. - * @param modname the module name supplied if this is loaded via 'require'. - * @param env the environment to load into, which must be a Globals instance. - */ - public LuaValue call(LuaValue modname, LuaValue env) { - globals = env.checkglobals(); - globals.finder = this; - globals.baselib = this; - env.set( "_G", env ); - env.set( "_VERSION", Lua._VERSION ); - env.set("assert", new _assert()); - env.set("collectgarbage", new collectgarbage()); - env.set("dofile", new dofile()); - env.set("error", new error()); - env.set("getmetatable", new getmetatable()); - env.set("load", new load()); - env.set("loadfile", new loadfile()); - env.set("pcall", new pcall()); - env.set("print", new print(this)); - env.set("rawequal", new rawequal()); - env.set("rawget", new rawget()); - env.set("rawlen", new rawlen()); - env.set("rawset", new rawset()); - env.set("select", new select()); - env.set("setmetatable", new setmetatable()); - env.set("tonumber", new tonumber()); - env.set("tostring", new tostring()); - env.set("type", new type()); - env.set("xpcall", new xpcall()); - - next next; - env.set("next", next = new next()); - env.set("pairs", new pairs(next)); - env.set("ipairs", new ipairs()); - - return env; - } - - /** ResourceFinder implementation - * - * Tries to open the file as a resource, which can work for JSE and JME. - */ - public InputStream findResource(String filename) { - return getClass().getResourceAsStream(filename.startsWith("/")? filename: "/"+filename); - } - - - // "assert", // ( v [,message] ) -> v, message | ERR - static final class _assert extends VarArgFunction { - public Varargs invoke(Varargs args) { - if ( !args.arg1().toboolean() ) - error( args.narg()>1? args.optjstring(2,"assertion failed!"): "assertion failed!" ); - return args; - } - } - - // "collectgarbage", // ( opt [,arg] ) -> value - static final class collectgarbage extends VarArgFunction { - public Varargs invoke(Varargs args) { - String s = args.optjstring(1, "collect"); - if ( "collect".equals(s) ) { - System.gc(); - return ZERO; - } else if ( "count".equals(s) ) { - Runtime rt = Runtime.getRuntime(); - long used = rt.totalMemory() - rt.freeMemory(); - return varargsOf(valueOf(used/1024.), valueOf(used%1024)); - } else if ( "step".equals(s) ) { - System.gc(); - return LuaValue.TRUE; - } else { - this.argerror("gc op"); - } - return NIL; - } - } - - // "dofile", // ( filename ) -> result1, ... - final class dofile extends VarArgFunction { - public Varargs invoke(Varargs args) { - args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil"); - String filename = args.isstring(1)? args.tojstring(1): null; - Varargs v = filename == null? - loadStream( globals.STDIN, "=stdin", "bt", globals ): - loadFile( args.checkjstring(1), "bt", globals ); - return v.isnil(1)? error(v.tojstring(2)): v.arg1().invoke(); - } - } - - // "error", // ( message [,level] ) -> ERR - static final class error extends TwoArgFunction { - public LuaValue call(LuaValue arg1, LuaValue arg2) { - throw arg1.isnil()? new LuaError(null, arg2.optint(1)): - arg1.isstring()? new LuaError(arg1.tojstring(), arg2.optint(1)): - new LuaError(arg1); - } - } - - // "getmetatable", // ( object ) -> table - static final class getmetatable extends LibFunction { - public LuaValue call() { - return argerror(1, "value"); - } - public LuaValue call(LuaValue arg) { - LuaValue mt = arg.getmetatable(); - return mt!=null? mt.rawget(METATABLE).optvalue(mt): NIL; - } - } - // "load", // ( ld [, source [, mode [, env]]] ) -> chunk | nil, msg - final class load extends VarArgFunction { - public Varargs invoke(Varargs args) { - LuaValue ld = args.arg1(); - args.argcheck(ld.isstring() || ld.isfunction(), 1, "ld must be string or function"); - String source = args.optjstring(2, ld.isstring()? ld.tojstring(): "=(load)"); - String mode = args.optjstring(3, "bt"); - LuaValue env = args.optvalue(4, globals); - return loadStream(ld.isstring()? ld.strvalue().toInputStream(): - new StringInputStream(ld.checkfunction()), source, mode, env); - } - } - - // "loadfile", // ( [filename [, mode [, env]]] ) -> chunk | nil, msg - final class loadfile extends VarArgFunction { - public Varargs invoke(Varargs args) { - args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil"); - String filename = args.isstring(1)? args.tojstring(1): null; - String mode = args.optjstring(2, "bt"); - LuaValue env = args.optvalue(3, globals); - return filename == null? - loadStream( globals.STDIN, "=stdin", mode, env ): - loadFile( filename, mode, env ); - } - } - - // "pcall", // (f, arg1, ...) -> status, result1, ... - final class pcall extends VarArgFunction { - public Varargs invoke(Varargs args) { - LuaValue func = args.checkvalue(1); - if (globals != null && globals.debuglib != null) - globals.debuglib.onCall(this); - try { - return varargsOf(TRUE, func.invoke(args.subargs(2))); - } catch ( LuaError le ) { - final LuaValue m = le.getMessageObject(); - return varargsOf(FALSE, m!=null? m: NIL); - } catch ( Exception e ) { - final String m = e.getMessage(); - return varargsOf(FALSE, valueOf(m!=null? m: e.toString())); - } finally { - if (globals != null && globals.debuglib != null) - globals.debuglib.onReturn(); - } - } - } - - // "print", // (...) -> void - final class print extends VarArgFunction { - final BaseLib baselib; - print(BaseLib baselib) { - this.baselib = baselib; - } - public Varargs invoke(Varargs args) { - LuaValue tostring = globals.get("tostring"); - for ( int i=1, n=args.narg(); i<=n; i++ ) { - if ( i>1 ) globals.STDOUT.print( '\t' ); - LuaString s = tostring.call( args.arg(i) ).strvalue(); - globals.STDOUT.print(s.tojstring()); - } - globals.STDOUT.print('\n'); - return NONE; - } - } - - - // "rawequal", // (v1, v2) -> boolean - static final class rawequal extends LibFunction { - public LuaValue call() { - return argerror(1, "value"); - } - public LuaValue call(LuaValue arg) { - return argerror(2, "value"); - } - public LuaValue call(LuaValue arg1, LuaValue arg2) { - return valueOf(arg1.raweq(arg2)); - } - } - - // "rawget", // (table, index) -> value - static final class rawget extends LibFunction { - public LuaValue call() { - return argerror(1, "value"); - } - public LuaValue call(LuaValue arg) { - return argerror(2, "value"); - } - public LuaValue call(LuaValue arg1, LuaValue arg2) { - return arg1.checktable().rawget(arg2); - } - } - - - // "rawlen", // (v) -> value - static final class rawlen extends LibFunction { - public LuaValue call(LuaValue arg) { - return valueOf(arg.rawlen()); - } - } - - // "rawset", // (table, index, value) -> table - static final class rawset extends LibFunction { - public LuaValue call(LuaValue table) { - return argerror(2,"value"); - } - public LuaValue call(LuaValue table, LuaValue index) { - return argerror(3,"value"); - } - public LuaValue call(LuaValue table, LuaValue index, LuaValue value) { - LuaTable t = table.checktable(); - if (!index.isvalidkey()) argerror(2, "value"); - t.rawset(index, value); - return t; - } - } - - // "select", // (f, ...) -> value1, ... - static final class select extends VarArgFunction { - public Varargs invoke(Varargs args) { - int n = args.narg()-1; - if ( args.arg1().equals(valueOf("#")) ) - return valueOf(n); - int i = args.checkint(1); - if ( i == 0 || i < -n ) - argerror(1,"index out of range"); - return args.subargs(i<0? n+i+2: i+1); - } - } - - // "setmetatable", // (table, metatable) -> table - static final class setmetatable extends LibFunction { - public LuaValue call(LuaValue table) { - return argerror(2,"value"); - } - public LuaValue call(LuaValue table, LuaValue metatable) { - final LuaValue mt0 = table.checktable().getmetatable(); - if ( mt0!=null && !mt0.rawget(METATABLE).isnil() ) - error("cannot change a protected metatable"); - return table.setmetatable(metatable.isnil()? null: metatable.checktable()); - } - } - - // "tonumber", // (e [,base]) -> value - static final class tonumber extends LibFunction { - public LuaValue call(LuaValue e) { - return e.tonumber(); - } - public LuaValue call(LuaValue e, LuaValue base) { - if (base.isnil()) - return e.tonumber(); - final int b = base.checkint(); - if ( b < 2 || b > 36 ) - argerror(2, "base out of range"); - return e.checkstring().tonumber(b); - } - } - - // "tostring", // (e) -> value - static final class tostring extends LibFunction { - public LuaValue call(LuaValue arg) { - LuaValue h = arg.metatag(TOSTRING); - if ( ! h.isnil() ) - return h.call(arg); - LuaValue v = arg.tostring(); - if ( ! v.isnil() ) - return v; - return valueOf(arg.tojstring()); - } - } - - // "type", // (v) -> value - static final class type extends LibFunction { - public LuaValue call(LuaValue arg) { - return valueOf(arg.typename()); - } - } - - // "xpcall", // (f, err) -> result1, ... - final class xpcall extends VarArgFunction { - public Varargs invoke(Varargs args) { - final LuaThread t = globals.running; - final LuaValue preverror = t.errorfunc; - t.errorfunc = args.checkvalue(2); - try { - if (globals != null && globals.debuglib != null) - globals.debuglib.onCall(this); - try { - return varargsOf(TRUE, args.arg1().invoke(args.subargs(3))); - } catch ( LuaError le ) { - final LuaValue m = le.getMessageObject(); - return varargsOf(FALSE, m!=null? m: NIL); - } catch ( Exception e ) { - final String m = e.getMessage(); - return varargsOf(FALSE, valueOf(m!=null? m: e.toString())); - } finally { - if (globals != null && globals.debuglib != null) - globals.debuglib.onReturn(); - } - } finally { - t.errorfunc = preverror; - } - } - } - - // "pairs" (t) -> iter-func, t, nil - static final class pairs extends VarArgFunction { - final next next; - pairs(next next) { - this.next = next; - } - public Varargs invoke(Varargs args) { - return varargsOf( next, args.checktable(1), NIL ); - } - } - - // // "ipairs", // (t) -> iter-func, t, 0 - static final class ipairs extends VarArgFunction { - inext inext = new inext(); - public Varargs invoke(Varargs args) { - return varargsOf( inext, args.checktable(1), ZERO ); - } - } - - // "next" ( table, [index] ) -> next-index, next-value - static final class next extends VarArgFunction { - public Varargs invoke(Varargs args) { - return args.checktable(1).next(args.arg(2)); - } - } - - // "inext" ( table, [int-index] ) -> next-index, next-value - static final class inext extends VarArgFunction { - public Varargs invoke(Varargs args) { - return args.checktable(1).inext(args.arg(2)); - } - } - - /** - * Load from a named file, returning the chunk or nil,error of can't load - * @param env - * @param mode - * @return Varargs containing chunk, or NIL,error-text on error - */ - public Varargs loadFile(String filename, String mode, LuaValue env) { - InputStream is = globals.finder.findResource(filename); - if ( is == null ) - return varargsOf(NIL, valueOf("cannot open "+filename+": No such file or directory")); - try { - return loadStream(is, "@"+filename, mode, env); - } finally { - try { - is.close(); - } catch ( Exception e ) { - e.printStackTrace(); - } - } - } - - public Varargs loadStream(InputStream is, String chunkname, String mode, LuaValue env) { - try { - if ( is == null ) - return varargsOf(NIL, valueOf("not found: "+chunkname)); - return globals.load(is, chunkname, mode, env); - } catch (Exception e) { - return varargsOf(NIL, valueOf(e.getMessage())); - } - } - - - private static class StringInputStream extends InputStream { - final LuaValue func; - byte[] bytes; - int offset, remaining = 0; - StringInputStream(LuaValue func) { - this.func = func; - } - public int read() throws IOException { - if ( remaining <= 0 ) { - LuaValue s = func.call(); - if ( s.isnil() ) - return -1; - LuaString ls = s.strvalue(); - bytes = ls.m_bytes; - offset = ls.m_offset; - remaining = ls.m_length; - if (remaining <= 0) - return -1; - } - --remaining; - return 0xFF&bytes[offset++]; - } - } -} +/******************************************************************************* +* 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; + +import java.io.IOException; +import java.io.InputStream; + +import org.luaj.vm2.Globals; +import org.luaj.vm2.Lua; +import org.luaj.vm2.LuaError; +import org.luaj.vm2.LuaString; +import org.luaj.vm2.LuaTable; +import org.luaj.vm2.LuaThread; +import org.luaj.vm2.LuaValue; +import org.luaj.vm2.Varargs; + +/** + * Subclass of {@link LibFunction} which implements the lua basic library functions. + *

+ * This contains all library functions listed as "basic functions" in the lua documentation for JME. + * The functions dofile and loadfile use the + * {@link Globals#finder} instance to find resource files. + * Since JME has no file system by default, {@link BaseLib} implements + * {@link ResourceFinder} using {@link Class#getResource(String)}, + * which is the closest equivalent on JME. + * The default loader chain in {@link PackageLib} will use these as well. + *

+ * To use basic library functions that include a {@link ResourceFinder} based on + * directory lookup, use {@link org.luaj.vm2.lib.jse.JseBaseLib} instead. + *

+ * 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();
+ * globals.get("print").call(LuaValue.valueOf("hello, world"));
+ * } 
+ *

+ * For special cases where the smallest possible footprint is desired, + * a minimal set of libraries could be loaded + * directly via {@link Globals#load(LuaValue)} using code such as: + *

 {@code
+ * Globals globals = new Globals();
+ * globals.load(new JseBaseLib());
+ * globals.get("print").call(LuaValue.valueOf("hello, world"));
+ * } 
+ * Doing so will ensure the library is properly initialized + * and loaded into the globals table. + *

+ * This is a direct port of the corresponding library in C. + * @see org.luaj.vm2.lib.jse.JseBaseLib + * @see ResourceFinder + * @see Globals#finder + * @see LibFunction + * @see org.luaj.vm2.lib.jse.JsePlatform + * @see org.luaj.vm2.lib.jme.JmePlatform + * @see Lua 5.2 Base Lib Reference + */ +public class BaseLib extends TwoArgFunction implements ResourceFinder { + + Globals globals; + + + /** Perform one-time initialization on the library by adding base functions + * to the supplied environment, and returning it as the return value. + * @param modname the module name supplied if this is loaded via 'require'. + * @param env the environment to load into, which must be a Globals instance. + */ + public LuaValue call(LuaValue modname, LuaValue env) { + globals = env.checkglobals(); + globals.finder = this; + globals.baselib = this; + env.set( "_G", env ); + env.set( "_VERSION", Lua._VERSION ); + env.set("assert", new _assert()); + env.set("collectgarbage", new collectgarbage()); + env.set("dofile", new dofile()); + env.set("error", new error()); + env.set("getmetatable", new getmetatable()); + env.set("load", new load()); + env.set("loadfile", new loadfile()); + env.set("pcall", new pcall()); + env.set("print", new print(this)); + env.set("rawequal", new rawequal()); + env.set("rawget", new rawget()); + env.set("rawlen", new rawlen()); + env.set("rawset", new rawset()); + env.set("select", new select()); + env.set("setmetatable", new setmetatable()); + env.set("tonumber", new tonumber()); + env.set("tostring", new tostring()); + env.set("type", new type()); + env.set("xpcall", new xpcall()); + + next next; + env.set("next", next = new next()); + env.set("pairs", new pairs(next)); + env.set("ipairs", new ipairs()); + + return env; + } + + /** ResourceFinder implementation + * + * Tries to open the file as a resource, which can work for JSE and JME. + */ + public InputStream findResource(String filename) { + return getClass().getResourceAsStream(filename.startsWith("/")? filename: "/"+filename); + } + + + // "assert", // ( v [,message] ) -> v, message | ERR + static final class _assert extends VarArgFunction { + public Varargs invoke(Varargs args) { + if ( !args.arg1().toboolean() ) + error( args.narg()>1? args.optjstring(2,"assertion failed!"): "assertion failed!" ); + return args; + } + } + + // "collectgarbage", // ( opt [,arg] ) -> value + static final class collectgarbage extends VarArgFunction { + public Varargs invoke(Varargs args) { + String s = args.optjstring(1, "collect"); + if ( "collect".equals(s) ) { + System.gc(); + return ZERO; + } else if ( "count".equals(s) ) { + Runtime rt = Runtime.getRuntime(); + long used = rt.totalMemory() - rt.freeMemory(); + return varargsOf(valueOf(used/1024.), valueOf(used%1024)); + } else if ( "step".equals(s) ) { + System.gc(); + return LuaValue.TRUE; + } else { + this.argerror("gc op"); + } + return NIL; + } + } + + // "dofile", // ( filename ) -> result1, ... + final class dofile extends VarArgFunction { + public Varargs invoke(Varargs args) { + args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil"); + String filename = args.isstring(1)? args.tojstring(1): null; + Varargs v = filename == null? + loadStream( globals.STDIN, "=stdin", "bt", globals ): + loadFile( args.checkjstring(1), "bt", globals ); + return v.isnil(1)? error(v.tojstring(2)): v.arg1().invoke(); + } + } + + // "error", // ( message [,level] ) -> ERR + static final class error extends TwoArgFunction { + public LuaValue call(LuaValue arg1, LuaValue arg2) { + throw arg1.isnil()? new LuaError(null, arg2.optint(1)): + arg1.isstring()? new LuaError(arg1.tojstring(), arg2.optint(1)): + new LuaError(arg1); + } + } + + // "getmetatable", // ( object ) -> table + static final class getmetatable extends LibFunction { + public LuaValue call() { + return argerror(1, "value"); + } + public LuaValue call(LuaValue arg) { + LuaValue mt = arg.getmetatable(); + return mt!=null? mt.rawget(METATABLE).optvalue(mt): NIL; + } + } + // "load", // ( ld [, source [, mode [, env]]] ) -> chunk | nil, msg + final class load extends VarArgFunction { + public Varargs invoke(Varargs args) { + LuaValue ld = args.arg1(); + if (!ld.isstring() && !ld.isfunction()) { + throw new LuaError("bad argument #1 to 'load' (string or function expected, got " + ld.typename() + ")"); + } + String source = args.optjstring(2, ld.isstring()? ld.tojstring(): "=(load)"); + String mode = args.optjstring(3, "bt"); + LuaValue env = args.optvalue(4, globals); + return loadStream(ld.isstring()? ld.strvalue().toInputStream(): + new StringInputStream(ld.checkfunction()), source, mode, env); + } + } + + // "loadfile", // ( [filename [, mode [, env]]] ) -> chunk | nil, msg + final class loadfile extends VarArgFunction { + public Varargs invoke(Varargs args) { + args.argcheck(args.isstring(1) || args.isnil(1), 1, "filename must be string or nil"); + String filename = args.isstring(1)? args.tojstring(1): null; + String mode = args.optjstring(2, "bt"); + LuaValue env = args.optvalue(3, globals); + return filename == null? + loadStream( globals.STDIN, "=stdin", mode, env ): + loadFile( filename, mode, env ); + } + } + + // "pcall", // (f, arg1, ...) -> status, result1, ... + final class pcall extends VarArgFunction { + public Varargs invoke(Varargs args) { + LuaValue func = args.checkvalue(1); + if (globals != null && globals.debuglib != null) + globals.debuglib.onCall(this); + try { + return varargsOf(TRUE, func.invoke(args.subargs(2))); + } catch ( LuaError le ) { + final LuaValue m = le.getMessageObject(); + return varargsOf(FALSE, m!=null? m: NIL); + } catch ( Exception e ) { + final String m = e.getMessage(); + return varargsOf(FALSE, valueOf(m!=null? m: e.toString())); + } finally { + if (globals != null && globals.debuglib != null) + globals.debuglib.onReturn(); + } + } + } + + // "print", // (...) -> void + final class print extends VarArgFunction { + final BaseLib baselib; + print(BaseLib baselib) { + this.baselib = baselib; + } + public Varargs invoke(Varargs args) { + LuaValue tostring = globals.get("tostring"); + for ( int i=1, n=args.narg(); i<=n; i++ ) { + if ( i>1 ) globals.STDOUT.print( '\t' ); + LuaString s = tostring.call( args.arg(i) ).strvalue(); + globals.STDOUT.print(s.tojstring()); + } + globals.STDOUT.print('\n'); + return NONE; + } + } + + + // "rawequal", // (v1, v2) -> boolean + static final class rawequal extends LibFunction { + public LuaValue call() { + return argerror(1, "value"); + } + public LuaValue call(LuaValue arg) { + return argerror(2, "value"); + } + public LuaValue call(LuaValue arg1, LuaValue arg2) { + return valueOf(arg1.raweq(arg2)); + } + } + + // "rawget", // (table, index) -> value + static final class rawget extends LibFunction { + public LuaValue call() { + return argerror(1, "value"); + } + public LuaValue call(LuaValue arg) { + return argerror(2, "value"); + } + public LuaValue call(LuaValue arg1, LuaValue arg2) { + return arg1.checktable().rawget(arg2); + } + } + + + // "rawlen", // (v) -> value + static final class rawlen extends LibFunction { + public LuaValue call(LuaValue arg) { + return valueOf(arg.rawlen()); + } + } + + // "rawset", // (table, index, value) -> table + static final class rawset extends LibFunction { + public LuaValue call(LuaValue table) { + return argerror(2,"value"); + } + public LuaValue call(LuaValue table, LuaValue index) { + return argerror(3,"value"); + } + public LuaValue call(LuaValue table, LuaValue index, LuaValue value) { + LuaTable t = table.checktable(); + if (!index.isvalidkey()) argerror(2, "value"); + t.rawset(index, value); + return t; + } + } + + // "select", // (f, ...) -> value1, ... + static final class select extends VarArgFunction { + public Varargs invoke(Varargs args) { + int n = args.narg()-1; + if ( args.arg1().equals(valueOf("#")) ) + return valueOf(n); + int i = args.checkint(1); + if ( i == 0 || i < -n ) + argerror(1,"index out of range"); + return args.subargs(i<0? n+i+2: i+1); + } + } + + // "setmetatable", // (table, metatable) -> table + static final class setmetatable extends LibFunction { + public LuaValue call(LuaValue table) { + return argerror(2,"value"); + } + public LuaValue call(LuaValue table, LuaValue metatable) { + final LuaValue mt0 = table.checktable().getmetatable(); + if ( mt0!=null && !mt0.rawget(METATABLE).isnil() ) + error("cannot change a protected metatable"); + return table.setmetatable(metatable.isnil()? null: metatable.checktable()); + } + } + + // "tonumber", // (e [,base]) -> value + static final class tonumber extends LibFunction { + public LuaValue call(LuaValue e) { + return e.tonumber(); + } + public LuaValue call(LuaValue e, LuaValue base) { + if (base.isnil()) + return e.tonumber(); + final int b = base.checkint(); + if ( b < 2 || b > 36 ) + argerror(2, "base out of range"); + return e.checkstring().tonumber(b); + } + } + + // "tostring", // (e) -> value + static final class tostring extends LibFunction { + public LuaValue call(LuaValue arg) { + LuaValue h = arg.metatag(TOSTRING); + if ( ! h.isnil() ) + return h.call(arg); + LuaValue v = arg.tostring(); + if ( ! v.isnil() ) + return v; + return valueOf(arg.tojstring()); + } + } + + // "type", // (v) -> value + static final class type extends LibFunction { + public LuaValue call(LuaValue arg) { + return valueOf(arg.typename()); + } + } + + // "xpcall", // (f, err) -> result1, ... + final class xpcall extends VarArgFunction { + public Varargs invoke(Varargs args) { + final LuaThread t = globals.running; + final LuaValue preverror = t.errorfunc; + t.errorfunc = args.checkvalue(2); + try { + if (globals != null && globals.debuglib != null) + globals.debuglib.onCall(this); + try { + return varargsOf(TRUE, args.arg1().invoke(args.subargs(3))); + } catch ( LuaError le ) { + final LuaValue m = le.getMessageObject(); + return varargsOf(FALSE, m!=null? m: NIL); + } catch ( Exception e ) { + final String m = e.getMessage(); + return varargsOf(FALSE, valueOf(m!=null? m: e.toString())); + } finally { + if (globals != null && globals.debuglib != null) + globals.debuglib.onReturn(); + } + } finally { + t.errorfunc = preverror; + } + } + } + + // "pairs" (t) -> iter-func, t, nil + static final class pairs extends VarArgFunction { + final next next; + pairs(next next) { + this.next = next; + } + public Varargs invoke(Varargs args) { + return varargsOf( next, args.checktable(1), NIL ); + } + } + + // // "ipairs", // (t) -> iter-func, t, 0 + static final class ipairs extends VarArgFunction { + inext inext = new inext(); + public Varargs invoke(Varargs args) { + return varargsOf( inext, args.checktable(1), ZERO ); + } + } + + // "next" ( table, [index] ) -> next-index, next-value + static final class next extends VarArgFunction { + public Varargs invoke(Varargs args) { + return args.checktable(1).next(args.arg(2)); + } + } + + // "inext" ( table, [int-index] ) -> next-index, next-value + static final class inext extends VarArgFunction { + public Varargs invoke(Varargs args) { + return args.checktable(1).inext(args.arg(2)); + } + } + + /** + * Load from a named file, returning the chunk or nil,error of can't load + * @param env + * @param mode + * @return Varargs containing chunk, or NIL,error-text on error + */ + public Varargs loadFile(String filename, String mode, LuaValue env) { + InputStream is = globals.finder.findResource(filename); + if ( is == null ) + return varargsOf(NIL, valueOf("cannot open "+filename+": No such file or directory")); + try { + return loadStream(is, "@"+filename, mode, env); + } finally { + try { + is.close(); + } catch ( Exception e ) { + e.printStackTrace(); + } + } + } + + public Varargs loadStream(InputStream is, String chunkname, String mode, LuaValue env) { + try { + if ( is == null ) + return varargsOf(NIL, valueOf("not found: "+chunkname)); + return globals.load(is, chunkname, mode, env); + } catch (Exception e) { + return varargsOf(NIL, valueOf(e.getMessage())); + } + } + + + private static class StringInputStream extends InputStream { + final LuaValue func; + byte[] bytes; + int offset, remaining = 0; + StringInputStream(LuaValue func) { + this.func = func; + } + public int read() throws IOException { + if ( remaining <= 0 ) { + LuaValue s = func.call(); + if ( s.isnil() ) + return -1; + LuaString ls = s.strvalue(); + bytes = ls.m_bytes; + offset = ls.m_offset; + remaining = ls.m_length; + if (remaining <= 0) + return -1; + } + --remaining; + return 0xFF&bytes[offset++]; + } + } +} From 0fa27c3783ce25be87e34249f4ea7a2e1be97b0d Mon Sep 17 00:00:00 2001 From: Enyby Date: Mon, 23 Sep 2019 00:39:42 +0300 Subject: [PATCH 02/62] EOZ (-1) not a space char. Fix bug with endless loop at not ended \z sequence. ``` local function lexerror (s, err) local st, msg = load('return ' .. s, '') if err ~= '' then err = err .. "'" end assert(not st and string.find(msg, "near .-" .. err)) end lexerror("'alo \\z \n\n", "") ``` --- src/core/org/luaj/vm2/compiler/LexState.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/org/luaj/vm2/compiler/LexState.java b/src/core/org/luaj/vm2/compiler/LexState.java index 58864110..1fbfd38a 100644 --- a/src/core/org/luaj/vm2/compiler/LexState.java +++ b/src/core/org/luaj/vm2/compiler/LexState.java @@ -198,7 +198,7 @@ public class LexState extends Constants { } private boolean isspace(int c) { - return (c <= ' '); + return (c >= 0 && c <= ' '); } From e7b11110a3c1c57fe5c4c97fd8a3ea8cab671d5d Mon Sep 17 00:00:00 2001 From: Enyby Date: Mon, 23 Sep 2019 01:53:01 +0300 Subject: [PATCH 03/62] Raise lexerror if failed parse number as double. --- src/core/org/luaj/vm2/compiler/LexState.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/core/org/luaj/vm2/compiler/LexState.java b/src/core/org/luaj/vm2/compiler/LexState.java index 1fbfd38a..5885a7d6 100644 --- a/src/core/org/luaj/vm2/compiler/LexState.java +++ b/src/core/org/luaj/vm2/compiler/LexState.java @@ -388,8 +388,13 @@ public class LexState extends Constants { seminfo.r = LuaValue.ZERO; else if (str.indexOf('x')>=0 || str.indexOf('X')>=0) seminfo.r = strx2number(str, seminfo); - else - seminfo.r = LuaValue.valueOf(Double.parseDouble(str.trim())); + else { + try { + seminfo.r = LuaValue.valueOf(Double.parseDouble(str.trim())); + } catch (NumberFormatException e) { + lexerror("malformed number (" + e.getMessage() + ")", TK_NUMBER); + } + } return true; } From f383c277281aabaed0781c9b25f9b34b605512ba Mon Sep 17 00:00:00 2001 From: Enyby Date: Mon, 23 Sep 2019 01:54:27 +0300 Subject: [PATCH 04/62] We not in C anymore. --- src/core/org/luaj/vm2/compiler/LexState.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/org/luaj/vm2/compiler/LexState.java b/src/core/org/luaj/vm2/compiler/LexState.java index 5885a7d6..4b9e31c3 100644 --- a/src/core/org/luaj/vm2/compiler/LexState.java +++ b/src/core/org/luaj/vm2/compiler/LexState.java @@ -413,7 +413,6 @@ public class LexState extends Constants { else break; } - save('\0'); String str = new String(buff, 0, nbuff); str2d(str, seminfo); } From 868928779f15ea6f7462b6f0a37594f2918e085f Mon Sep 17 00:00:00 2001 From: Enyby Date: Sun, 6 Oct 2019 16:43:11 +0300 Subject: [PATCH 05/62] Fix rewrite io.input inside io.lines. ``` do local t = os.tmpname() local f = io.open(t, 'w') f:write('test') f:close() local i = io.input() for l in io.lines(t) do end local n = io.input() assert(n == i, tostring(n).." ~= "..tostring(i)) os.remove(t) print('+') end ``` --- src/core/org/luaj/vm2/lib/IoLib.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/org/luaj/vm2/lib/IoLib.java b/src/core/org/luaj/vm2/lib/IoLib.java index fa41b7bf..bb853ca1 100644 --- a/src/core/org/luaj/vm2/lib/IoLib.java +++ b/src/core/org/luaj/vm2/lib/IoLib.java @@ -371,7 +371,7 @@ public class IoLib extends TwoArgFunction { // io.lines(filename) -> iterator public Varargs _io_lines(String filename) { - infile = filename==null? input(): ioopenfile(FTYPE_NAMED, filename,"r"); + File infile = filename==null? input(): ioopenfile(FTYPE_NAMED, filename,"r"); checkopen(infile); return lines(infile); } From c62ba1f22e9aa8bb60eab1d9a4430bf84fdb2390 Mon Sep 17 00:00:00 2001 From: Enyby Date: Sun, 6 Oct 2019 16:54:44 +0300 Subject: [PATCH 06/62] File tostring respect closed. --- src/jse/org/luaj/vm2/lib/jse/JseIoLib.java | 28 +++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/jse/org/luaj/vm2/lib/jse/JseIoLib.java b/src/jse/org/luaj/vm2/lib/jse/JseIoLib.java index 9655de26..83a7c13c 100644 --- a/src/jse/org/luaj/vm2/lib/jse/JseIoLib.java +++ b/src/jse/org/luaj/vm2/lib/jse/JseIoLib.java @@ -36,20 +36,20 @@ import org.luaj.vm2.LuaValue; import org.luaj.vm2.lib.IoLib; import org.luaj.vm2.lib.LibFunction; -/** - * Subclass of {@link IoLib} and therefore {@link LibFunction} which implements the lua standard {@code io} - * library for the JSE platform. - *

- * It uses RandomAccessFile to implement seek on files. +/** + * Subclass of {@link IoLib} and therefore {@link LibFunction} which implements the lua standard {@code io} + * library for the JSE platform. *

- * Typically, this library is included as part of a call to + * It uses RandomAccessFile to implement seek on files. + *

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

 {@code
  * Globals globals = JsePlatform.standardGlobals();
  * globals.get("io").get("write").call(LuaValue.valueOf("hello, world\n"));
  * } 
*

- * For special cases where the smallest possible footprint is desired, + * For special cases where the smallest possible footprint is desired, * a minimal set of libraries could be loaded * directly via {@link Globals#load(LuaValue)} using code such as: *

 {@code
@@ -96,9 +96,9 @@ public class JseIoLib extends IoLib {
 	
 	protected File openProgram(String prog, String mode) throws IOException {
 		final Process p = Runtime.getRuntime().exec(prog);
-		return "w".equals(mode)? 
-				new FileImpl( p.getOutputStream() ):  
-				new FileImpl( p.getInputStream() ); 
+		return "w".equals(mode)?
+				new FileImpl( p.getOutputStream() ):
+				new FileImpl( p.getInputStream() );
 	}
 
 	protected File tmpFile() throws IOException {
@@ -133,7 +133,7 @@ public class JseIoLib extends IoLib {
 			this( null, null, o );
 		}
 		public String tojstring() {
-			return "file ("+this.hashCode()+")";
+			return "file (" + (this.closed ? "closed" : this.hashCode()) + ")";
 		}
 		public boolean isstdfile() {
 			return file == null;
@@ -199,11 +199,11 @@ public class JseIoLib extends IoLib {
 			}
 			notimplemented();
 			return 0;
-		}		
+		}
 		
-		// return char if read, -1 if eof, throw IOException on other exception 
+		// return char if read, -1 if eof, throw IOException on other exception
 		public int read() throws IOException {
-			if ( is != null ) 
+			if ( is != null )
 				return is.read();
 			else if ( file != null ) {
 				return file.read();

From 14745ba76a109f2acbe10b17a8f323189d463eea Mon Sep 17 00:00:00 2001
From: Enyby 
Date: Sun, 6 Oct 2019 18:40:31 +0300
Subject: [PATCH 07/62] Fix call io.read, file:read without params.

---
 src/core/org/luaj/vm2/lib/IoLib.java | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/core/org/luaj/vm2/lib/IoLib.java b/src/core/org/luaj/vm2/lib/IoLib.java
index bb853ca1..d50adf2e 100644
--- a/src/core/org/luaj/vm2/lib/IoLib.java
+++ b/src/core/org/luaj/vm2/lib/IoLib.java
@@ -492,6 +492,7 @@ public class IoLib extends TwoArgFunction {
 
 	private Varargs ioread(File f, Varargs args) throws IOException {
 		int i,n=args.narg();
+		if (n == 0) return freadline(f);
 		LuaValue[] v = new LuaValue[n];
 		LuaValue ai,vi;
 		LuaString fmt;

From 83f2e1d96afae36a18c8654686ed0e33a961d3e3 Mon Sep 17 00:00:00 2001
From: Enyby 
Date: Sun, 6 Oct 2019 18:53:15 +0300
Subject: [PATCH 08/62] Fix io.read and file:read do not support '*L' format.
 #54

---
 src/core/org/luaj/vm2/lib/IoLib.java | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/src/core/org/luaj/vm2/lib/IoLib.java b/src/core/org/luaj/vm2/lib/IoLib.java
index d50adf2e..cffefb02 100644
--- a/src/core/org/luaj/vm2/lib/IoLib.java
+++ b/src/core/org/luaj/vm2/lib/IoLib.java
@@ -434,7 +434,7 @@ public class IoLib extends TwoArgFunction {
 
 	//	lines iterator(s,var) -> var'
 	public Varargs _lines_iter(LuaValue file) throws IOException {
-		return freadline(checkfile(file));
+		return freadline(checkfile(file),false);
 	}
 
 	private File output() {
@@ -492,7 +492,7 @@ public class IoLib extends TwoArgFunction {
 
 	private Varargs ioread(File f, Varargs args) throws IOException {
 		int i,n=args.narg();
-		if (n == 0) return freadline(f);
+		if (n == 0) return freadline(f,false);
 		LuaValue[] v = new LuaValue[n];
 		LuaValue ai,vi;
 		LuaString fmt;
@@ -506,7 +506,8 @@ public class IoLib extends TwoArgFunction {
 					if ( fmt.m_length == 2 && fmt.m_bytes[fmt.m_offset] == '*' ) {
 						switch ( fmt.m_bytes[fmt.m_offset+1] ) {
 						case 'n': vi = freadnumber(f); break item;
-						case 'l': vi = freadline(f); break item;
+						case 'l': vi = freadline(f,false); break item;
+						case 'L': vi = freadline(f,true); break item;
 						case 'a': vi = freadall(f); break item;
 						}
 					}
@@ -560,15 +561,15 @@ public class IoLib extends TwoArgFunction {
 			return NIL;
 		return LuaString.valueUsing(b, 0, r);
 	}
-	public static LuaValue freaduntil(File f,boolean lineonly) throws IOException {
+	public static LuaValue freaduntil(File f,boolean lineonly,boolean withend) throws IOException {
 		ByteArrayOutputStream baos = new ByteArrayOutputStream();
 		int c;
 		try {
 			if ( lineonly ) {
 				loop: while ( (c = f.read()) > 0 ) {
 					switch ( c ) {
-					case '\r': break;
-					case '\n': break loop;
+					case '\r': if (withend) baos.write(c); break;
+					case '\n': if (withend) baos.write(c); break loop;
 					default: baos.write(c); break;
 					}
 				}
@@ -583,15 +584,15 @@ public class IoLib extends TwoArgFunction {
 			(LuaValue) NIL:
 			(LuaValue) LuaString.valueUsing(baos.toByteArray());
 	}
-	public static LuaValue freadline(File f) throws IOException {
-		return freaduntil(f,true);
+	public static LuaValue freadline(File f,boolean withend) throws IOException {
+		return freaduntil(f,true,withend);
 	}
 	public static LuaValue freadall(File f) throws IOException {
 		int n = f.remaining();
 		if ( n >= 0 ) {
 			return freadbytes(f, n);
 		} else {
-			return freaduntil(f,false);
+			return freaduntil(f,false,false);
 		}
 	}
 	public static LuaValue freadnumber(File f) throws IOException {

From 8345bee6b4c1703716ccab9758d80402781f8634 Mon Sep 17 00:00:00 2001
From: Enyby 
Date: Sun, 6 Oct 2019 19:09:01 +0300
Subject: [PATCH 09/62] Fix io.lines and file:lines do not honor additional
 params. #52 Fix io.lines do not close file on EOF. #53 Improve error message
 for io.lines and file:lines on closed file.

---
 src/core/org/luaj/vm2/lib/IoLib.java | 45 ++++++++++++++++++++--------
 1 file changed, 32 insertions(+), 13 deletions(-)

diff --git a/src/core/org/luaj/vm2/lib/IoLib.java b/src/core/org/luaj/vm2/lib/IoLib.java
index cffefb02..0d7565b7 100644
--- a/src/core/org/luaj/vm2/lib/IoLib.java
+++ b/src/core/org/luaj/vm2/lib/IoLib.java
@@ -95,6 +95,12 @@ public class IoLib extends TwoArgFunction {
 		// return number of bytes read if positive, false if eof, throw IOException on other exception
 		abstract public int read(byte[] bytes, int offset, int length) throws IOException;
 		
+		public boolean eof() throws IOException {
+			try {
+				return peek() < 0;
+			} catch (EOFException e) { return true; }
+		}
+		
 		// delegate method access to file methods table
 		public LuaValue get( LuaValue key ) {
 			return filemethods.get(key);
@@ -269,8 +275,15 @@ public class IoLib extends TwoArgFunction {
 	static final class IoLibV extends VarArgFunction {
 		private File f;
 		public IoLib iolib;
+		private boolean toclose;
+		private Varargs args;
 		public IoLibV() {
 		}
+		public IoLibV(File f, String name, int opcode, IoLib iolib, boolean toclose, Varargs args) {
+			this(f, name, opcode, iolib);
+			this.toclose = toclose;
+			this.args = args;
+		}
 		public IoLibV(File f, String name, int opcode, IoLib iolib) {
 			super();
 			this.f = f;
@@ -290,20 +303,20 @@ public class IoLib extends TwoArgFunction {
 				case IO_TYPE:		return iolib._io_type(args.arg1());
 				case IO_POPEN:		return iolib._io_popen(args.checkjstring(1),args.optjstring(2,"r"));
 				case IO_OPEN:		return iolib._io_open(args.checkjstring(1), args.optjstring(2,"r"));
-				case IO_LINES:		return iolib._io_lines(args.isvalue(1)? args.checkjstring(1): null);
+				case IO_LINES:		return iolib._io_lines(args);
 				case IO_READ:		return iolib._io_read(args);
 				case IO_WRITE:		return iolib._io_write(args);
 					
 				case FILE_CLOSE:	return iolib._file_close(args.arg1());
 				case FILE_FLUSH:	return iolib._file_flush(args.arg1());
 				case FILE_SETVBUF:	return iolib._file_setvbuf(args.arg1(),args.checkjstring(2),args.optint(3,1024));
-				case FILE_LINES:	return iolib._file_lines(args.arg1());
+				case FILE_LINES:	return iolib._file_lines(args);
 				case FILE_READ:		return iolib._file_read(args.arg1(),args.subargs(2));
 				case FILE_SEEK:		return iolib._file_seek(args.arg1(),args.optjstring(2,"cur"),args.optint(3,0));
 				case FILE_WRITE:	return iolib._file_write(args.arg1(),args.subargs(2));
 
 				case IO_INDEX:		return iolib._io_index(args.arg(2));
-				case LINES_ITER:	return iolib._lines_iter(f);
+				case LINES_ITER:	return iolib._lines_iter(f, toclose, this.args);
 				}
 			} catch ( IOException ioe ) {
 				return errorresult(ioe);
@@ -369,11 +382,12 @@ public class IoLib extends TwoArgFunction {
 		return rawopenfile(FTYPE_NAMED, filename, mode);
 	}
 
-	//	io.lines(filename) -> iterator
-	public Varargs _io_lines(String filename) {
+	//	io.lines(filename, ...) -> iterator
+	public Varargs _io_lines(Varargs args) {
+		String filename = args.isvalue(1)? args.checkjstring(1): null;
 		File infile = filename==null? input(): ioopenfile(FTYPE_NAMED, filename,"r");
 		checkopen(infile);
-		return lines(infile);
+		return lines(infile, filename != null, args.subargs(filename != null ? 2 : 1));
 	}
 
 	//	io.read(...) -> (...)
@@ -405,9 +419,9 @@ public class IoLib extends TwoArgFunction {
 		return LuaValue.TRUE;
 	}
 
-	// file:lines() -> iterator
-	public Varargs _file_lines(LuaValue file) {
-		return lines(checkfile(file));
+	// file:lines(...) -> iterator
+	public Varargs _file_lines(Varargs args) {
+		return lines(checkfile(args.arg1()), false, args.subargs(2));
 	}
 
 	//	file:read(...) -> (...)
@@ -433,8 +447,13 @@ public class IoLib extends TwoArgFunction {
 	}
 
 	//	lines iterator(s,var) -> var'
-	public Varargs _lines_iter(LuaValue file) throws IOException {
-		return freadline(checkfile(file),false);
+	public Varargs _lines_iter(LuaValue file, boolean toclose, Varargs args) throws IOException {
+		File f = optfile(file);
+		if ( f == null ) argerror(1, "not a file: " + file);
+		if ( f.isclosed() )	error("file is already closed");
+		Varargs ret = ioread(f, args);
+		if (toclose && ret.isnil(1) && f.eof()) f.close();
+		return ret;
 	}
 
 	private File output() {
@@ -476,9 +495,9 @@ public class IoLib extends TwoArgFunction {
 		return varargsOf(NIL, valueOf(errortext));
 	}
 
-	private Varargs lines(final File f) {
+	private Varargs lines(final File f, boolean toclose, Varargs args) {
 		try {
-			return new IoLibV(f,"lnext",LINES_ITER,this);
+			return new IoLibV(f,"lnext",LINES_ITER,this,toclose,args);
 		} catch ( Exception e ) {
 			return error("lines: "+e);
 		}

From 832ec739ea350fff4f15f574bd4f06d876064527 Mon Sep 17 00:00:00 2001
From: Enyby 
Date: Sun, 6 Oct 2019 23:35:45 +0300
Subject: [PATCH 10/62] Close not closed file on GC. #55 Relevant only for
 J2SE, not for J2ME.

---
 src/core/org/luaj/vm2/lib/IoLib.java | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/src/core/org/luaj/vm2/lib/IoLib.java b/src/core/org/luaj/vm2/lib/IoLib.java
index 0d7565b7..c757ce65 100644
--- a/src/core/org/luaj/vm2/lib/IoLib.java
+++ b/src/core/org/luaj/vm2/lib/IoLib.java
@@ -118,6 +118,14 @@ public class IoLib extends TwoArgFunction {
 		public String tojstring() {
 			return "file: " + Integer.toHexString(hashCode());
 		}
+		
+		public void finalize() {
+			if (!isclosed()) {
+				try {
+					close();
+				} catch (IOException ignore) {}
+			}
+		}
 	}
 
 	/** Enumerated value representing stdin */

From 934a8fc57b4fdff853c2fc313b79c83dfba1275c Mon Sep 17 00:00:00 2001
From: Enyby 
Date: Sun, 6 Oct 2019 23:49:04 +0300
Subject: [PATCH 11/62] Fix io.read(0) on EOF.

---
 src/core/org/luaj/vm2/lib/IoLib.java | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/core/org/luaj/vm2/lib/IoLib.java b/src/core/org/luaj/vm2/lib/IoLib.java
index c757ce65..3bda6ce4 100644
--- a/src/core/org/luaj/vm2/lib/IoLib.java
+++ b/src/core/org/luaj/vm2/lib/IoLib.java
@@ -582,6 +582,7 @@ public class IoLib extends TwoArgFunction {
 	// ------------- file reading utilitied ------------------
 	
 	public static LuaValue freadbytes(File f, int count) throws IOException {
+		if (count == 0) return f.eof() ? NIL : EMPTYSTRING;
 		byte[] b = new byte[count];
 		int r;
 		if ( ( r = f.read(b,0,b.length) ) < 0 )

From 65beda4c2b414ebf77e4bddda6d2184332098356 Mon Sep 17 00:00:00 2001
From: Enyby 
Date: Mon, 7 Oct 2019 00:23:34 +0300
Subject: [PATCH 12/62] Fix read all at EOF.

---
 src/core/org/luaj/vm2/lib/IoLib.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/core/org/luaj/vm2/lib/IoLib.java b/src/core/org/luaj/vm2/lib/IoLib.java
index 3bda6ce4..34b3e941 100644
--- a/src/core/org/luaj/vm2/lib/IoLib.java
+++ b/src/core/org/luaj/vm2/lib/IoLib.java
@@ -618,7 +618,7 @@ public class IoLib extends TwoArgFunction {
 	public static LuaValue freadall(File f) throws IOException {
 		int n = f.remaining();
 		if ( n >= 0 ) {
-			return freadbytes(f, n);
+			return n == 0 ? EMPTYSTRING : freadbytes(f, n);
 		} else {
 			return freaduntil(f,false,false);
 		}

From 984fa30bf6678771630cebfa715d61b1ebcc342c Mon Sep 17 00:00:00 2001
From: Enyby 
Date: Mon, 7 Oct 2019 00:25:07 +0300
Subject: [PATCH 13/62] Fix read all stdin in JSE.

---
 src/jse/org/luaj/vm2/lib/jse/JseIoLib.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/jse/org/luaj/vm2/lib/jse/JseIoLib.java b/src/jse/org/luaj/vm2/lib/jse/JseIoLib.java
index 83a7c13c..d00d5db1 100644
--- a/src/jse/org/luaj/vm2/lib/jse/JseIoLib.java
+++ b/src/jse/org/luaj/vm2/lib/jse/JseIoLib.java
@@ -321,7 +321,7 @@ public class JseIoLib extends IoLib {
 		}
 
 		public int remaining() throws IOException {
-			return 0;
+			return -1;
 		}
 
 		public int peek() throws IOException, EOFException {

From f9f78b81da37f19f7d193efc180614291d2ee299 Mon Sep 17 00:00:00 2001
From: Enyby 
Date: Mon, 7 Oct 2019 14:26:21 +0300
Subject: [PATCH 14/62] Allow read zero bytes in io lib methods.

---
 src/core/org/luaj/vm2/lib/IoLib.java | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/core/org/luaj/vm2/lib/IoLib.java b/src/core/org/luaj/vm2/lib/IoLib.java
index 34b3e941..94a9ef52 100644
--- a/src/core/org/luaj/vm2/lib/IoLib.java
+++ b/src/core/org/luaj/vm2/lib/IoLib.java
@@ -594,7 +594,7 @@ public class IoLib extends TwoArgFunction {
 		int c;
 		try {
 			if ( lineonly ) {
-				loop: while ( (c = f.read()) > 0 ) {
+				loop: while ( (c = f.read()) >= 0 ) {
 					switch ( c ) {
 					case '\r': if (withend) baos.write(c); break;
 					case '\n': if (withend) baos.write(c); break loop;
@@ -602,7 +602,7 @@ public class IoLib extends TwoArgFunction {
 					}
 				}
 			} else {
-				while ( (c = f.read()) > 0 )
+				while ( (c = f.read()) >= 0 )
 					baos.write(c);
 			}
 		} catch ( EOFException e ) {

From a50deaa75c27812b0d46439e31303af3359d5900 Mon Sep 17 00:00:00 2001
From: Enyby 
Date: Mon, 7 Oct 2019 14:52:12 +0300
Subject: [PATCH 15/62] Fix raise error from io.lines and file:lines.

---
 src/core/org/luaj/vm2/lib/IoLib.java | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/core/org/luaj/vm2/lib/IoLib.java b/src/core/org/luaj/vm2/lib/IoLib.java
index 94a9ef52..bd5420f8 100644
--- a/src/core/org/luaj/vm2/lib/IoLib.java
+++ b/src/core/org/luaj/vm2/lib/IoLib.java
@@ -327,6 +327,10 @@ public class IoLib extends TwoArgFunction {
 				case LINES_ITER:	return iolib._lines_iter(f, toclose, this.args);
 				}
 			} catch ( IOException ioe ) {
+				if (opcode == LINES_ITER) {
+					String s = ioe.getMessage();
+					error(s != null ? s : ioe.toString());
+				}
 				return errorresult(ioe);
 			}
 			return NONE;

From e2ede7f91c2760f6ab3ca2600222c3a502e833e1 Mon Sep 17 00:00:00 2001
From: Enyby 
Date: Mon, 7 Oct 2019 17:11:13 +0300
Subject: [PATCH 16/62] Fix call io.lines(nil, ...).

---
 src/core/org/luaj/vm2/lib/IoLib.java | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/core/org/luaj/vm2/lib/IoLib.java b/src/core/org/luaj/vm2/lib/IoLib.java
index bd5420f8..0ece498e 100644
--- a/src/core/org/luaj/vm2/lib/IoLib.java
+++ b/src/core/org/luaj/vm2/lib/IoLib.java
@@ -396,10 +396,10 @@ public class IoLib extends TwoArgFunction {
 
 	//	io.lines(filename, ...) -> iterator
 	public Varargs _io_lines(Varargs args) {
-		String filename = args.isvalue(1)? args.checkjstring(1): null;
+		String filename = args.optjstring(1, null);
 		File infile = filename==null? input(): ioopenfile(FTYPE_NAMED, filename,"r");
 		checkopen(infile);
-		return lines(infile, filename != null, args.subargs(filename != null ? 2 : 1));
+		return lines(infile, filename != null, args.subargs(2));
 	}
 
 	//	io.read(...) -> (...)

From db58e1808b0e8ecaa3fe6eb5aede32004f6dd49d Mon Sep 17 00:00:00 2001
From: Enyby 
Date: Mon, 7 Oct 2019 18:08:47 +0300
Subject: [PATCH 17/62] Fix load script from func.

---
 src/core/org/luaj/vm2/lib/BaseLib.java | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/core/org/luaj/vm2/lib/BaseLib.java b/src/core/org/luaj/vm2/lib/BaseLib.java
index 524c7af7..a990d2bb 100644
--- a/src/core/org/luaj/vm2/lib/BaseLib.java
+++ b/src/core/org/luaj/vm2/lib/BaseLib.java
@@ -468,10 +468,12 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
 			this.func = func;
 		}
 		public int read() throws IOException {
-			if ( remaining <= 0 ) {
+			if ( remaining < 0 )
+				return -1;
+			if ( remaining == 0 ) {
 				LuaValue s = func.call();
 				if ( s.isnil() )
-					return -1;
+					return remaining = -1;
 				LuaString ls = s.strvalue();
 				bytes = ls.m_bytes;
 				offset = ls.m_offset;

From d0bb0409a37478f5f21cb06e1b79c5caa509986a Mon Sep 17 00:00:00 2001
From: Mikhael-Danilov 
Date: Mon, 7 Oct 2019 20:23:45 +0300
Subject: [PATCH 18/62] Fix link

Fix link to examples/android/src/android/LuajViewLuajView.java
---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index d0ca2241..cacee17d 100644
--- a/README.md
+++ b/README.md
@@ -412,7 +412,7 @@ and the math operations include all those supported by Java SE.
 Android applications should use the JsePlatform, and can include the Luajava library 
 to simplify access to underlying Android APIs.  
 A specialized Globals.finder should be provided to find scripts and data for loading.
-See examples/android/src/android/LuajView
+See examples/android/src/android/LuajView.java
 for an example that loads from the "res" Android project directory.
 The ant build script is examples/android/build.xml.  
 

From 60d130cecc222540ba3cb167b436b9409b56d99e Mon Sep 17 00:00:00 2001
From: Enyby 
Date: Sat, 12 Oct 2019 16:08:36 +0300
Subject: [PATCH 19/62] Fix corrupted args for io.lines and file:lines on reuse
 stack elements.

---
 src/core/org/luaj/vm2/Varargs.java   | 122 ++++++++++++++-------------
 src/core/org/luaj/vm2/lib/IoLib.java |   2 +-
 2 files changed, 63 insertions(+), 61 deletions(-)

diff --git a/src/core/org/luaj/vm2/Varargs.java b/src/core/org/luaj/vm2/Varargs.java
index fb012297..9fa93569 100644
--- a/src/core/org/luaj/vm2/Varargs.java
+++ b/src/core/org/luaj/vm2/Varargs.java
@@ -24,16 +24,16 @@ package org.luaj.vm2;
 /**
  * Class to encapsulate varargs values, either as part of a variable argument list, or multiple return values.
  * 

- * To construct varargs, use one of the static methods such as + * To construct varargs, use one of the static methods such as * {@code LuaValue.varargsOf(LuaValue,LuaValue)} *

*

- * Any LuaValue can be used as a stand-in for Varargs, for both calls and return values. - * When doing so, nargs() will return 1 and arg1() or arg(1) will return this. - * This simplifies the case when calling or implementing varargs functions with only - * 1 argument or 1 return value. + * Any LuaValue can be used as a stand-in for Varargs, for both calls and return values. + * When doing so, nargs() will return 1 and arg1() or arg(1) will return this. + * This simplifies the case when calling or implementing varargs functions with only + * 1 argument or 1 return value. *

- * Varargs can also be derived from other varargs by appending to the front with a call + * Varargs can also be derived from other varargs by appending to the front with a call * such as {@code LuaValue.varargsOf(LuaValue,Varargs)} * or by taking a portion of the args using {@code Varargs.subargs(int start)} *

@@ -57,22 +57,22 @@ public abstract class Varargs { abstract public LuaValue arg( int i ); /** - * Get the number of arguments, or 0 if there are none. - * @return number of arguments. + * Get the number of arguments, or 0 if there are none. + * @return number of arguments. */ abstract public int narg(); /** - * Get the first argument in the list. + * Get the first argument in the list. * @return LuaValue which is first in the list, or LuaValue.NIL if there are no values. * @see Varargs#arg(int) * @see LuaValue#NIL */ abstract public LuaValue arg1(); - /** + /** * Evaluate any pending tail call and return result. - * @return the evaluated tail call result + * @return the evaluated tail call result */ public Varargs eval() { return this; } @@ -88,7 +88,7 @@ public abstract class Varargs { // utilities to get specific arguments and type-check them. // ----------------------------------------------------------------------- - /** Gets the type of argument {@code i} + /** Gets the type of argument {@code i} * @param i the index of the argument to convert, 1 is the first argument * @return int value corresponding to one of the LuaValue integer type values * @see LuaValue#TNIL @@ -117,20 +117,20 @@ public abstract class Varargs { public boolean isfunction(int i) { return arg(i).isfunction(); } /** Tests if argument i is a number. - * Since anywhere a number is required, a string can be used that - * is a number, this will return true for both numbers and - * strings that can be interpreted as numbers. + * Since anywhere a number is required, a string can be used that + * is a number, this will return true for both numbers and + * strings that can be interpreted as numbers. * @param i the index of the argument to test, 1 is the first argument - * @return true if the argument exists and is a number or + * @return true if the argument exists and is a number or * string that can be interpreted as a number, false otherwise * @see LuaValue#TNUMBER * @see LuaValue#TSTRING * */ public boolean isnumber(int i) { return arg(i).isnumber(); } - /** Tests if argument i is a string. - * Since all lua numbers can be used where strings are used, - * this will return true for both strings and numbers. + /** Tests if argument i is a string. + * Since all lua numbers can be used where strings are used, + * this will return true for both strings and numbers. * @param i the index of the argument to test, 1 is the first argument * @return true if the argument exists and is a string or number, false otherwise * @see LuaValue#TNUMBER @@ -167,7 +167,7 @@ public abstract class Varargs { /** Return argument i as a boolean value, {@code defval} if nil, or throw a LuaError if any other type. * @param i the index of the argument to test, 1 is the first argument - * @return true if argument i is boolean true, false if it is false, or defval if not supplied or nil + * @return true if argument i is boolean true, false if it is false, or defval if not supplied or nil * @exception LuaError if the argument is not a lua boolean * */ public boolean optboolean(int i, boolean defval) { return arg(i).optboolean(defval); } @@ -256,7 +256,7 @@ public abstract class Varargs { * */ public Object optuserdata(int i, Object defval) { return arg(i).optuserdata(defval); } - /** Return argument i as a java Object if it is a userdata whose instance Class c or a subclass, + /** Return argument i as a java Object if it is a userdata whose instance Class c or a subclass, * {@code defval} if nil, or throw a LuaError if any other type. * @param i the index of the argument to test, 1 is the first argument * @param c the class to which the userdata instance must be assignable @@ -363,7 +363,7 @@ public abstract class Varargs { * */ public Object checkuserdata(int i) { return arg(i).checkuserdata(); } - /** Return argument i as a java Object if it is a userdata whose instance Class c or a subclass, + /** Return argument i as a java Object if it is a userdata whose instance Class c or a subclass, * or throw an error if any other type. * @param i the index of the argument to test, 1 is the first argument * @param c the class to which the userdata instance must be assignable @@ -387,7 +387,7 @@ public abstract class Varargs { public LuaValue checknotnil(int i) { return arg(i).checknotnil(); } /** Performs test on argument i as a LuaValue when a user-supplied assertion passes, or throw an error. - * Returns normally if the value of {@code test} is {@code true}, otherwise throws and argument error with + * Returns normally if the value of {@code test} is {@code true}, otherwise throws and argument error with * the supplied message, {@code msg}. * @param test user supplied assertion to test against * @param i the index to report in any error message @@ -404,20 +404,20 @@ public abstract class Varargs { return i>narg() || arg(i).isnil(); } - /** Convert argument {@code i} to java boolean based on lua rules for boolean evaluation. + /** Convert argument {@code i} to java boolean based on lua rules for boolean evaluation. * @param i the index of the argument to convert, 1 is the first argument * @return {@code false} if argument i is nil or false, otherwise {@code true} * */ public boolean toboolean(int i) { return arg(i).toboolean(); } - /** Return argument i as a java byte value, discarding any fractional part and truncating, + /** Return argument i as a java byte value, discarding any fractional part and truncating, * or 0 if not a number. * @param i the index of the argument to convert, 1 is the first argument * @return byte value with fraction discarded and truncated if necessary if argument i is number, otherwise 0 * */ public byte tobyte(int i) { return arg(i).tobyte(); } - /** Return argument i as a java char value, discarding any fractional part and truncating, + /** Return argument i as a java char value, discarding any fractional part and truncating, * or 0 if not a number. * @param i the index of the argument to convert, 1 is the first argument * @return char value with fraction discarded and truncated if necessary if argument i is number, otherwise 0 @@ -430,21 +430,21 @@ public abstract class Varargs { * */ public double todouble(int i) { return arg(i).todouble(); } - /** Return argument i as a java float value, discarding excess fractional part and truncating, + /** Return argument i as a java float value, discarding excess fractional part and truncating, * or 0 if not a number. * @param i the index of the argument to convert, 1 is the first argument * @return float value with excess fraction discarded and truncated if necessary if argument i is number, otherwise 0 * */ public float tofloat(int i) { return arg(i).tofloat(); } - /** Return argument i as a java int value, discarding any fractional part and truncating, + /** Return argument i as a java int value, discarding any fractional part and truncating, * or 0 if not a number. * @param i the index of the argument to convert, 1 is the first argument * @return int value with fraction discarded and truncated if necessary if argument i is number, otherwise 0 * */ public int toint(int i) { return arg(i).toint(); } - /** Return argument i as a java long value, discarding any fractional part and truncating, + /** Return argument i as a java long value, discarding any fractional part and truncating, * or 0 if not a number. * @param i the index of the argument to convert, 1 is the first argument * @return long value with fraction discarded and truncated if necessary if argument i is number, otherwise 0 @@ -457,7 +457,7 @@ public abstract class Varargs { * */ public String tojstring(int i) { return arg(i).tojstring(); } - /** Return argument i as a java short value, discarding any fractional part and truncating, + /** Return argument i as a java short value, discarding any fractional part and truncating, * or 0 if not a number. * @param i the index of the argument to convert, 1 is the first argument * @return short value with fraction discarded and truncated if necessary if argument i is number, otherwise 0 @@ -477,8 +477,8 @@ public abstract class Varargs { * */ public Object touserdata(int i,Class c) { return arg(i).touserdata(c); } - /** Convert the list of varargs values to a human readable java String. - * @return String value in human readable form such as {1,2}. + /** Convert the list of varargs values to a human readable java String. + * @return String value in human readable form such as {1,2}. */ public String tojstring() { Buffer sb = new Buffer(); @@ -491,8 +491,8 @@ public abstract class Varargs { return sb.tojstring(); } - /** Convert the value or values to a java String using Varargs.tojstring() - * @return String value in human readable form. + /** Convert the value or values to a java String using Varargs.tojstring() + * @return String value in human readable form. * @see Varargs#tojstring() */ public String toString() { return tojstring(); } @@ -544,21 +544,21 @@ public abstract class Varargs { } } - /** Varargs implemenation backed by two values. + /** Varargs implemenation backed by two values. *

* This is an internal class not intended to be used directly. - * Instead use the corresponding static method on LuaValue. - * + * Instead use the corresponding static method on LuaValue. + * * @see LuaValue#varargsOf(LuaValue, Varargs) */ static final class PairVarargs extends Varargs { private final LuaValue v1; private final Varargs v2; - /** Construct a Varargs from an two LuaValue. + /** Construct a Varargs from an two LuaValue. *

* This is an internal class not intended to be used directly. - * Instead use the corresponding static method on LuaValue. - * + * Instead use the corresponding static method on LuaValue. + * * @see LuaValue#varargsOf(LuaValue, Varargs) */ PairVarargs(LuaValue v1, Varargs v2) { @@ -571,8 +571,8 @@ public abstract class Varargs { public int narg() { return 1+v2.narg(); } - public LuaValue arg1() { - return v1; + public LuaValue arg1() { + return v1; } public Varargs subargs(final int start) { if (start == 1) @@ -585,22 +585,22 @@ public abstract class Varargs { } } - /** Varargs implemenation backed by an array of LuaValues + /** Varargs implemenation backed by an array of LuaValues *

* This is an internal class not intended to be used directly. - * Instead use the corresponding static methods on LuaValue. - * + * Instead use the corresponding static methods on LuaValue. + * * @see LuaValue#varargsOf(LuaValue[]) * @see LuaValue#varargsOf(LuaValue[], Varargs) */ static final class ArrayVarargs extends Varargs { private final LuaValue[] v; private final Varargs r; - /** Construct a Varargs from an array of LuaValue. + /** Construct a Varargs from an array of LuaValue. *

* This is an internal class not intended to be used directly. - * Instead use the corresponding static methods on LuaValue. - * + * Instead use the corresponding static methods on LuaValue. + * * @see LuaValue#varargsOf(LuaValue[]) * @see LuaValue#varargsOf(LuaValue[], Varargs) */ @@ -631,11 +631,11 @@ public abstract class Varargs { } } - /** Varargs implemenation backed by an array of LuaValues + /** Varargs implemenation backed by an array of LuaValues *

* This is an internal class not intended to be used directly. - * Instead use the corresponding static methods on LuaValue. - * + * Instead use the corresponding static methods on LuaValue. + * * @see LuaValue#varargsOf(LuaValue[], int, int) * @see LuaValue#varargsOf(LuaValue[], int, int, Varargs) */ @@ -644,11 +644,11 @@ public abstract class Varargs { private final LuaValue[] v; private final int length; private final Varargs more; - /** Construct a Varargs from an array of LuaValue. + /** Construct a Varargs from an array of LuaValue. *

* This is an internal class not intended to be used directly. - * Instead use the corresponding static methods on LuaValue. - * + * Instead use the corresponding static methods on LuaValue. + * * @see LuaValue#varargsOf(LuaValue[], int, int) */ ArrayPartVarargs(LuaValue[] v, int offset, int length) { @@ -657,11 +657,11 @@ public abstract class Varargs { this.length = length; this.more = LuaValue.NONE; } - /** Construct a Varargs from an array of LuaValue and additional arguments. + /** Construct a Varargs from an array of LuaValue and additional arguments. *

* This is an internal class not intended to be used directly. - * Instead use the corresponding static method on LuaValue. - * + * Instead use the corresponding static method on LuaValue. + * * @see LuaValue#varargsOf(LuaValue[], int, int, Varargs) */ public ArrayPartVarargs(LuaValue[] v, int offset, int length, Varargs more) { @@ -676,8 +676,8 @@ public abstract class Varargs { public int narg() { return length + more.narg(); } - public LuaValue arg1() { - return length>0? v[offset]: more.arg1(); + public LuaValue arg1() { + return length>0? v[offset]: more.arg1(); } public Varargs subargs(int start) { if (start <= 0) @@ -707,8 +707,10 @@ public abstract class Varargs { /** Return Varargs that cannot be using a shared array for the storage, and is flattened. * Internal utility method not intended to be called directly from user code. * @return Varargs containing same values, but flattened and with a new array if needed. + * @exclude + * @hide */ - Varargs dealias() { + public Varargs dealias() { int n = narg(); switch (n) { case 0: return LuaValue.NONE; diff --git a/src/core/org/luaj/vm2/lib/IoLib.java b/src/core/org/luaj/vm2/lib/IoLib.java index 0ece498e..9b2cb25d 100644 --- a/src/core/org/luaj/vm2/lib/IoLib.java +++ b/src/core/org/luaj/vm2/lib/IoLib.java @@ -290,7 +290,7 @@ public class IoLib extends TwoArgFunction { public IoLibV(File f, String name, int opcode, IoLib iolib, boolean toclose, Varargs args) { this(f, name, opcode, iolib); this.toclose = toclose; - this.args = args; + this.args = args.dealias(); } public IoLibV(File f, String name, int opcode, IoLib iolib) { super(); From 3613bc0862d323332c5c5b9fc5d627a3cc2fbf69 Mon Sep 17 00:00:00 2001 From: Enyby Date: Sat, 12 Oct 2019 17:51:04 +0300 Subject: [PATCH 20/62] Add check for values passed to file:vsetbuf and file:seek. --- src/core/org/luaj/vm2/lib/IoLib.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/core/org/luaj/vm2/lib/IoLib.java b/src/core/org/luaj/vm2/lib/IoLib.java index 9b2cb25d..e386f4d8 100644 --- a/src/core/org/luaj/vm2/lib/IoLib.java +++ b/src/core/org/luaj/vm2/lib/IoLib.java @@ -427,6 +427,12 @@ public class IoLib extends TwoArgFunction { // file:setvbuf(mode,[size]) -> void public Varargs _file_setvbuf(LuaValue file, String mode, int size) { + if ("no".equals(mode)) { + } else if ("full".equals(mode)) { + } else if ("line".equals(mode)) { + } else { + argerror(1, "invalid option '" + mode + "', must be one of 'no', 'full' or 'line'"); + } checkfile(file).setvbuf(mode,size); return LuaValue.TRUE; } @@ -443,6 +449,12 @@ public class IoLib extends TwoArgFunction { // file:seek([whence][,offset]) -> pos | nil,error public Varargs _file_seek(LuaValue file, String whence, int offset) throws IOException { + if ("set".equals(whence)) { + } else if ("end".equals(whence)) { + } else if ("cur".equals(whence)) { + } else { + argerror(1, "invalid option '" + whence + "', must be one of 'set', 'cur' or 'end'"); + } return valueOf( checkfile(file).seek(whence,offset) ); } From 20eca5760dc99cd2326fafa8f1ede145108b0989 Mon Sep 17 00:00:00 2001 From: Enyby Date: Sat, 12 Oct 2019 17:57:37 +0300 Subject: [PATCH 21/62] Fix detect io lib read modes like file:read('*all'). --- src/core/org/luaj/vm2/lib/IoLib.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/org/luaj/vm2/lib/IoLib.java b/src/core/org/luaj/vm2/lib/IoLib.java index e386f4d8..cf8e1d2e 100644 --- a/src/core/org/luaj/vm2/lib/IoLib.java +++ b/src/core/org/luaj/vm2/lib/IoLib.java @@ -546,7 +546,7 @@ public class IoLib extends TwoArgFunction { break item; case LuaValue.TSTRING: fmt = ai.checkstring(); - if ( fmt.m_length == 2 && fmt.m_bytes[fmt.m_offset] == '*' ) { + if ( fmt.m_length >= 2 && fmt.m_bytes[fmt.m_offset] == '*' ) { switch ( fmt.m_bytes[fmt.m_offset+1] ) { case 'n': vi = freadnumber(f); break item; case 'l': vi = freadline(f,false); break item; From f3b8a1eddc682090e84983c9cc6bc8fb1bb30846 Mon Sep 17 00:00:00 2001 From: Enyby Date: Sat, 12 Oct 2019 19:12:44 +0300 Subject: [PATCH 22/62] Fix default setvbuf size. --- src/core/org/luaj/vm2/lib/IoLib.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/org/luaj/vm2/lib/IoLib.java b/src/core/org/luaj/vm2/lib/IoLib.java index cf8e1d2e..c5bd46a8 100644 --- a/src/core/org/luaj/vm2/lib/IoLib.java +++ b/src/core/org/luaj/vm2/lib/IoLib.java @@ -317,7 +317,7 @@ public class IoLib extends TwoArgFunction { case FILE_CLOSE: return iolib._file_close(args.arg1()); case FILE_FLUSH: return iolib._file_flush(args.arg1()); - case FILE_SETVBUF: return iolib._file_setvbuf(args.arg1(),args.checkjstring(2),args.optint(3,1024)); + case FILE_SETVBUF: return iolib._file_setvbuf(args.arg1(),args.checkjstring(2),args.optint(3,8192)); case FILE_LINES: return iolib._file_lines(args); case FILE_READ: return iolib._file_read(args.arg1(),args.subargs(2)); case FILE_SEEK: return iolib._file_seek(args.arg1(),args.optjstring(2,"cur"),args.optint(3,0)); From 6efb6f000e8e28cb33e6a123c1518e2f576e7f6c Mon Sep 17 00:00:00 2001 From: Enyby Date: Sun, 13 Oct 2019 05:58:32 +0300 Subject: [PATCH 23/62] Improve error message for file:seek and file:setvbuf. --- src/core/org/luaj/vm2/lib/IoLib.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/org/luaj/vm2/lib/IoLib.java b/src/core/org/luaj/vm2/lib/IoLib.java index c5bd46a8..d49c2551 100644 --- a/src/core/org/luaj/vm2/lib/IoLib.java +++ b/src/core/org/luaj/vm2/lib/IoLib.java @@ -431,7 +431,7 @@ public class IoLib extends TwoArgFunction { } else if ("full".equals(mode)) { } else if ("line".equals(mode)) { } else { - argerror(1, "invalid option '" + mode + "', must be one of 'no', 'full' or 'line'"); + argerror(1, "invalid value: '" + mode + "'; must be one of 'no', 'full' or 'line'"); } checkfile(file).setvbuf(mode,size); return LuaValue.TRUE; @@ -453,7 +453,7 @@ public class IoLib extends TwoArgFunction { } else if ("end".equals(whence)) { } else if ("cur".equals(whence)) { } else { - argerror(1, "invalid option '" + whence + "', must be one of 'set', 'cur' or 'end'"); + argerror(1, "invalid value: '" + whence + "'; must be one of 'set', 'cur' or 'end'"); } return valueOf( checkfile(file).seek(whence,offset) ); } From edfe1a5fdef2f672637db3b0c048bb82fa245acd Mon Sep 17 00:00:00 2001 From: Enyby Date: Sun, 13 Oct 2019 06:16:21 +0300 Subject: [PATCH 24/62] Add check for io.popen modes. --- src/core/org/luaj/vm2/lib/IoLib.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/org/luaj/vm2/lib/IoLib.java b/src/core/org/luaj/vm2/lib/IoLib.java index d49c2551..98c220b5 100644 --- a/src/core/org/luaj/vm2/lib/IoLib.java +++ b/src/core/org/luaj/vm2/lib/IoLib.java @@ -386,6 +386,7 @@ public class IoLib extends TwoArgFunction { // io.popen(prog, [mode]) -> file public Varargs _io_popen(String prog, String mode) throws IOException { + if (!"r".equals(mode) && !"w".equals(mode)) argerror(2, "invalid value: '" + mode + "'; must be one of 'r' or 'w'"); return openProgram(prog, mode); } From 2f5aa594bd3df6636b0b06468e43f36b5953a6f9 Mon Sep 17 00:00:00 2001 From: Enyby Date: Mon, 14 Oct 2019 14:11:38 +0300 Subject: [PATCH 25/62] Fix getobjname for get constant name if it stored on register. --- src/core/org/luaj/vm2/lib/DebugLib.java | 27 ++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/core/org/luaj/vm2/lib/DebugLib.java b/src/core/org/luaj/vm2/lib/DebugLib.java index fd7c4c3c..5bb9fb6a 100644 --- a/src/core/org/luaj/vm2/lib/DebugLib.java +++ b/src/core/org/luaj/vm2/lib/DebugLib.java @@ -796,8 +796,8 @@ public class DebugLib extends TwoArgFunction { LuaString vn = (Lua.GET_OPCODE(i) == Lua.OP_GETTABLE) /* name of indexed variable */ ? p.getlocalname(t + 1, pc) : (t < p.upvalues.length ? p.upvalues[t].name : QMARK); - name = kname(p, k); - return new NameWhat( name.tojstring(), vn != null && vn.eq_b(ENV)? "global": "field" ); + String jname = kname(p, pc, k); + return new NameWhat( jname, vn != null && vn.eq_b(ENV)? "global": "field" ); } case Lua.OP_GETUPVAL: { int u = Lua.GETARG_B(i); /* upvalue index */ @@ -816,8 +816,8 @@ public class DebugLib extends TwoArgFunction { } case Lua.OP_SELF: { int k = Lua.GETARG_C(i); /* key index */ - name = kname(p, k); - return new NameWhat( name.tojstring(), "method" ); + String jname = kname(p, pc, k); + return new NameWhat( jname, "method" ); } default: break; @@ -826,11 +826,20 @@ public class DebugLib extends TwoArgFunction { return null; /* no useful name found */ } - static LuaString kname(Prototype p, int c) { - if (Lua.ISK(c) && p.k[Lua.INDEXK(c)].isstring()) - return p.k[Lua.INDEXK(c)].strvalue(); - else - return QMARK; + static String kname(Prototype p, int pc, int c) { + if (Lua.ISK(c)) { /* is 'c' a constant? */ + LuaValue k = p.k[Lua.INDEXK(c)]; + if (k.isstring()) { /* literal constant? */ + return k.tojstring(); /* it is its own name */ + } /* else no reasonable name found */ + } else { /* 'c' is a register */ + NameWhat what = getobjname(p, pc, c); /* search for 'c' */ + if (what != null && "constant".equals(what.namewhat)) { /* found a constant name? */ + return what.name; /* 'name' already filled */ + } + /* else no reasonable name found */ + } + return "?"; /* no reasonable name found */ } /* From f8d7731b5661beb195ed04741a70316f4d0df0bd Mon Sep 17 00:00:00 2001 From: Enyby Date: Mon, 14 Oct 2019 14:12:08 +0300 Subject: [PATCH 26/62] Fix NPE on getobjname in some cases. --- src/core/org/luaj/vm2/lib/DebugLib.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/org/luaj/vm2/lib/DebugLib.java b/src/core/org/luaj/vm2/lib/DebugLib.java index 5bb9fb6a..a81ef230 100644 --- a/src/core/org/luaj/vm2/lib/DebugLib.java +++ b/src/core/org/luaj/vm2/lib/DebugLib.java @@ -802,7 +802,7 @@ public class DebugLib extends TwoArgFunction { case Lua.OP_GETUPVAL: { int u = Lua.GETARG_B(i); /* upvalue index */ name = u < p.upvalues.length ? p.upvalues[u].name : QMARK; - return new NameWhat( name.tojstring(), "upvalue" ); + return name == null ? null : new NameWhat( name.tojstring(), "upvalue" ); } case Lua.OP_LOADK: case Lua.OP_LOADKX: { From dbab0aed01deefb7aca4e04dd9baf9525fc86c0b Mon Sep 17 00:00:00 2001 From: Enyby Date: Mon, 14 Oct 2019 18:33:25 +0300 Subject: [PATCH 27/62] Fix odd varargs methods. --- src/core/org/luaj/vm2/Varargs.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/core/org/luaj/vm2/Varargs.java b/src/core/org/luaj/vm2/Varargs.java index 9fa93569..e56d8dcf 100644 --- a/src/core/org/luaj/vm2/Varargs.java +++ b/src/core/org/luaj/vm2/Varargs.java @@ -291,7 +291,7 @@ public abstract class Varargs { * @return java double value if argument i is a number or string that converts to a number * @exception LuaError if the argument is not a number * */ - public double checkdouble(int i) { return arg(i).checknumber().todouble(); } + public double checkdouble(int i) { return arg(i).checkdouble(); } /** Return argument i as a function, or throw an error if an incompatible type. * @param i the index of the argument to test, 1 is the first argument @@ -300,12 +300,12 @@ public abstract class Varargs { * */ public LuaFunction checkfunction(int i) { return arg(i).checkfunction(); } - /** Return argument i as a java int value, discarding any fractional part, or throw an error if not a number. + /** Return argument i as a java int value, or throw an error if it cannot be converted to one. * @param i the index of the argument to test, 1 is the first argument - * @return int value with fraction discarded and truncated if necessary if argument i is number - * @exception LuaError if the argument is not a number + * @return int value if argument i is a number or string that converts to a number + * @exception LuaError if the argument cannot be represented by a java int value * */ - public int checkint(int i) { return arg(i).checknumber().toint(); } + public int checkint(int i) { return arg(i).checkint(); } /** Return argument i as a java int value, or throw an error if not a number or is not representable by a java int. * @param i the index of the argument to test, 1 is the first argument @@ -314,12 +314,12 @@ public abstract class Varargs { * */ public LuaInteger checkinteger(int i) { return arg(i).checkinteger(); } - /** Return argument i as a java long value, discarding any fractional part, or throw an error if not a number. + /** Return argument i as a java long value, or throw an error if it cannot be converted to one. * @param i the index of the argument to test, 1 is the first argument - * @return long value with fraction discarded and truncated if necessary if argument i is number - * @exception LuaError if the argument is not a number + * @return long value if argument i is a number or string that converts to a number + * @exception LuaError if the argument cannot be represented by a java long value * */ - public long checklong(int i) { return arg(i).checknumber().tolong(); } + public long checklong(int i) { return arg(i).checklong(); } /** Return argument i as a LuaNumber, or throw an error if not a number or string that can be converted to a number. * @param i the index of the argument to test, 1 is the first argument From 5609d8c92b02b292ddc0148e30be7b38a5c207f6 Mon Sep 17 00:00:00 2001 From: Enyby Date: Sat, 19 Oct 2019 20:53:56 +0300 Subject: [PATCH 28/62] Add check mode for io.open. #57 --- src/core/org/luaj/vm2/lib/IoLib.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/core/org/luaj/vm2/lib/IoLib.java b/src/core/org/luaj/vm2/lib/IoLib.java index 98c220b5..13f6f986 100644 --- a/src/core/org/luaj/vm2/lib/IoLib.java +++ b/src/core/org/luaj/vm2/lib/IoLib.java @@ -583,6 +583,17 @@ public class IoLib extends TwoArgFunction { } private File rawopenfile(int filetype, String filename, String mode) throws IOException { + int len = mode.length(); + for (int i = 0; i < len; i++) { // [rwa][+]?b* + char ch = mode.charAt(i); + if (i == 0 && "rwa".indexOf(ch) >= 0) continue; + if (i == 1 && ch == '+') continue; + if (i >= 1 && ch == 'b') continue; + len = -1; + break; + } + if (len <= 0) argerror(2, "invalid mode: '" + mode + "'"); + switch (filetype) { case FTYPE_STDIN: return wrapStdin(); case FTYPE_STDOUT: return wrapStdout(); From 169202362e3a9d52386c13ce5591d49a2fac4a1b Mon Sep 17 00:00:00 2001 From: Enyby Date: Sun, 20 Oct 2019 00:34:54 +0300 Subject: [PATCH 29/62] Fix error message for collectgarbage invalid option. --- src/core/org/luaj/vm2/lib/BaseLib.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/org/luaj/vm2/lib/BaseLib.java b/src/core/org/luaj/vm2/lib/BaseLib.java index a990d2bb..d990e659 100644 --- a/src/core/org/luaj/vm2/lib/BaseLib.java +++ b/src/core/org/luaj/vm2/lib/BaseLib.java @@ -152,7 +152,7 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder { System.gc(); return LuaValue.TRUE; } else { - this.argerror("gc op"); + argerror(1, "invalid option '" + s + "'"); } return NIL; } From 5fe0a3950d4955e31a018fd2f9aead569c556edf Mon Sep 17 00:00:00 2001 From: Enyby Date: Sun, 20 Oct 2019 06:45:53 +0300 Subject: [PATCH 30/62] Improve get name for func. --- src/core/org/luaj/vm2/LuaFunction.java | 27 +++++++++++++----------- src/core/org/luaj/vm2/lib/StringLib.java | 8 +++---- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/core/org/luaj/vm2/LuaFunction.java b/src/core/org/luaj/vm2/LuaFunction.java index 2730952e..83bee86d 100644 --- a/src/core/org/luaj/vm2/LuaFunction.java +++ b/src/core/org/luaj/vm2/LuaFunction.java @@ -22,14 +22,14 @@ package org.luaj.vm2; -/** - * Base class for functions implemented in Java. +/** + * Base class for functions implemented in Java. *

- * Direct subclass include {@link org.luaj.vm2.lib.LibFunction} - * which is the base class for - * all built-in library functions coded in Java, - * and {@link LuaClosure}, which represents a lua closure - * whose bytecode is interpreted when the function is invoked. + * Direct subclass include {@link org.luaj.vm2.lib.LibFunction} + * which is the base class for + * all built-in library functions coded in Java, + * and {@link LuaClosure}, which represents a lua closure + * whose bytecode is interpreted when the function is invoked. * @see LuaValue * @see LuaClosure * @see org.luaj.vm2.lib.LibFunction @@ -57,11 +57,11 @@ public class LuaFunction extends LuaValue { } public LuaFunction optfunction(LuaFunction defval) { - return this; + return this; } - public LuaValue getmetatable() { - return s_metatable; + public LuaValue getmetatable() { + return s_metatable; } public String tojstring() { @@ -72,12 +72,15 @@ public class LuaFunction extends LuaValue { return valueOf(tojstring()); } - /** Return the last part of the class name, to be used as a function name in tojstring and elsewhere. + /** Return the last part of the class name, to be used as a function name in tojstring and elsewhere. * @return String naming the last part of the class name after the last dot (.) or dollar sign ($). + * If the first character is '_', it is skipped. */ public String classnamestub() { String s = getClass().getName(); - return s.substring(Math.max(s.lastIndexOf('.'),s.lastIndexOf('$'))+1); + int offset = Math.max(s.lastIndexOf('.'), s.lastIndexOf('$')) + 1; + if (s.charAt(offset) == '_') offset++; + return s.substring(offset); } /** Return a human-readable name for this function. Returns the last part of the class name by default. diff --git a/src/core/org/luaj/vm2/lib/StringLib.java b/src/core/org/luaj/vm2/lib/StringLib.java index 6b75ee8a..8dd4f3b6 100644 --- a/src/core/org/luaj/vm2/lib/StringLib.java +++ b/src/core/org/luaj/vm2/lib/StringLib.java @@ -83,8 +83,8 @@ public class StringLib extends TwoArgFunction { */ public LuaValue call(LuaValue modname, LuaValue env) { LuaTable string = new LuaTable(); - string.set("byte", new byte_()); - string.set("char", new char_()); + string.set("byte", new _byte()); + string.set("char", new _char()); string.set("dump", new dump()); string.set("find", new find()); string.set("format", new format()); @@ -117,7 +117,7 @@ public class StringLib extends TwoArgFunction { * * @param args the calling args */ - static final class byte_ extends VarArgFunction { + static final class _byte extends VarArgFunction { public Varargs invoke(Varargs args) { LuaString s = args.checkstring(1); int l = s.m_length; @@ -148,7 +148,7 @@ public class StringLib extends TwoArgFunction { * * @param args the calling VM */ - static final class char_ extends VarArgFunction { + static final class _char extends VarArgFunction { public Varargs invoke(Varargs args) { int n = args.narg(); byte[] bytes = new byte[n]; From c71f27769777c1dff3a2a95c0920b20cc0f0d5fb Mon Sep 17 00:00:00 2001 From: Enyby Date: Sun, 20 Oct 2019 07:07:17 +0300 Subject: [PATCH 31/62] Improve error messages for lib table. --- src/core/org/luaj/vm2/lib/TableLib.java | 16 +++++----------- src/core/org/luaj/vm2/lib/TableLibFunction.java | 9 +++++++++ 2 files changed, 14 insertions(+), 11 deletions(-) create mode 100644 src/core/org/luaj/vm2/lib/TableLibFunction.java diff --git a/src/core/org/luaj/vm2/lib/TableLib.java b/src/core/org/luaj/vm2/lib/TableLib.java index 74456952..02b82ad4 100644 --- a/src/core/org/luaj/vm2/lib/TableLib.java +++ b/src/core/org/luaj/vm2/lib/TableLib.java @@ -73,12 +73,6 @@ public class TableLib extends TwoArgFunction { if (!env.get("package").isnil()) env.get("package").get("loaded").set("table", table); return NIL; } - - static class TableLibFunction extends LibFunction { - public LuaValue call() { - return argerror(1, "table expected, got no value"); - } - } // "concat" (table [, sep [, i [, j]]]) -> string static class concat extends TableLibFunction { @@ -104,12 +98,12 @@ public class TableLib extends TwoArgFunction { return argerror(2, "value expected"); } case 2: { - LuaTable table = args.arg1().checktable(); + LuaTable table = args.checktable(1); table.insert(table.length()+1,args.arg(2)); return NONE; } default: { - args.arg1().checktable().insert(args.checkint(2),args.arg(3)); + args.checktable(1).insert(args.checkint(2),args.arg(3)); return NONE; } } @@ -128,15 +122,15 @@ public class TableLib extends TwoArgFunction { // "remove" (table [, pos]) -> removed-ele static class remove extends VarArgFunction { public Varargs invoke(Varargs args) { - return args.arg1().checktable().remove(args.optint(2, 0)); + return args.checktable(1).remove(args.optint(2, 0)); } } // "sort" (table [, comp]) static class sort extends VarArgFunction { public Varargs invoke(Varargs args) { - args.arg1().checktable().sort( - args.arg(2).isnil()? NIL: args.arg(2).checkfunction()); + args.checktable(1).sort( + args.isnil(2)? NIL: args.checkfunction(2)); return NONE; } } diff --git a/src/core/org/luaj/vm2/lib/TableLibFunction.java b/src/core/org/luaj/vm2/lib/TableLibFunction.java new file mode 100644 index 00000000..5fabef7e --- /dev/null +++ b/src/core/org/luaj/vm2/lib/TableLibFunction.java @@ -0,0 +1,9 @@ +package org.luaj.vm2.lib; + +import org.luaj.vm2.LuaValue; + +class TableLibFunction extends LibFunction { + public LuaValue call() { + return argerror(1, "table expected, got no value"); + } +} From af35c4d89e7762bf6957844fd61e30218c7f7634 Mon Sep 17 00:00:00 2001 From: Enyby Date: Sun, 20 Oct 2019 07:17:46 +0300 Subject: [PATCH 32/62] Improve error messages for base lib. --- src/core/org/luaj/vm2/lib/BaseLib.java | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/core/org/luaj/vm2/lib/BaseLib.java b/src/core/org/luaj/vm2/lib/BaseLib.java index d990e659..26e1d8c7 100644 --- a/src/core/org/luaj/vm2/lib/BaseLib.java +++ b/src/core/org/luaj/vm2/lib/BaseLib.java @@ -182,7 +182,7 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder { // "getmetatable", // ( object ) -> table static final class getmetatable extends LibFunction { public LuaValue call() { - return argerror(1, "value"); + return argerror(1, "value expected"); } public LuaValue call(LuaValue arg) { LuaValue mt = arg.getmetatable(); @@ -260,10 +260,10 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder { // "rawequal", // (v1, v2) -> boolean static final class rawequal extends LibFunction { public LuaValue call() { - return argerror(1, "value"); + return argerror(1, "value expected"); } public LuaValue call(LuaValue arg) { - return argerror(2, "value"); + return argerror(2, "value expected"); } public LuaValue call(LuaValue arg1, LuaValue arg2) { return valueOf(arg1.raweq(arg2)); @@ -271,12 +271,9 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder { } // "rawget", // (table, index) -> value - static final class rawget extends LibFunction { - public LuaValue call() { - return argerror(1, "value"); - } + static final class rawget extends TableLibFunction { public LuaValue call(LuaValue arg) { - return argerror(2, "value"); + return argerror(2, "value expected"); } public LuaValue call(LuaValue arg1, LuaValue arg2) { return arg1.checktable().rawget(arg2); @@ -292,16 +289,16 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder { } // "rawset", // (table, index, value) -> table - static final class rawset extends LibFunction { + static final class rawset extends TableLibFunction { public LuaValue call(LuaValue table) { - return argerror(2,"value"); + return argerror(2,"value expected"); } public LuaValue call(LuaValue table, LuaValue index) { - return argerror(3,"value"); + return argerror(3,"value expected"); } public LuaValue call(LuaValue table, LuaValue index, LuaValue value) { LuaTable t = table.checktable(); - if (!index.isvalidkey()) argerror(2, "value"); + if (!index.isvalidkey()) argerror(2, "table index is nil"); t.rawset(index, value); return t; } @@ -321,9 +318,9 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder { } // "setmetatable", // (table, metatable) -> table - static final class setmetatable extends LibFunction { + static final class setmetatable extends TableLibFunction { public LuaValue call(LuaValue table) { - return argerror(2,"value"); + return argerror(2,"nil or table expected"); } public LuaValue call(LuaValue table, LuaValue metatable) { final LuaValue mt0 = table.checktable().getmetatable(); From ac3475deee0ba8f71677b29601b9902fd53be4a0 Mon Sep 17 00:00:00 2001 From: Enyby Date: Sun, 20 Oct 2019 07:19:34 +0300 Subject: [PATCH 33/62] Improved error messages for lib functions. --- src/core/org/luaj/vm2/lib/LibFunction.java | 90 +++++++++++----------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/src/core/org/luaj/vm2/lib/LibFunction.java b/src/core/org/luaj/vm2/lib/LibFunction.java index b537dab4..eba56072 100644 --- a/src/core/org/luaj/vm2/lib/LibFunction.java +++ b/src/core/org/luaj/vm2/lib/LibFunction.java @@ -27,21 +27,21 @@ import org.luaj.vm2.LuaValue; import org.luaj.vm2.Varargs; /** - * Subclass of {@link LuaFunction} common to Java functions exposed to lua. + * Subclass of {@link LuaFunction} common to Java functions exposed to lua. *

- * To provide for common implementations in JME and JSE, + * To provide for common implementations in JME and JSE, * library functions are typically grouped on one or more library classes * and an opcode per library function is defined and used to key the switch - * to the correct function within the library. + * to the correct function within the library. *

- * Since lua functions can be called with too few or too many arguments, - * and there are overloaded {@link LuaValue#call()} functions with varying + * Since lua functions can be called with too few or too many arguments, + * and there are overloaded {@link LuaValue#call()} functions with varying * number of arguments, a Java function exposed in lua needs to handle the - * argument fixup when a function is called with a number of arguments - * differs from that expected. + * argument fixup when a function is called with a number of arguments + * differs from that expected. *

- * To simplify the creation of library functions, - * there are 5 direct subclasses to handle common cases based on number of + * To simplify the creation of library functions, + * there are 5 direct subclasses to handle common cases based on number of * argument values and number of return return values. *

    *
  • {@link ZeroArgFunction}
  • @@ -51,13 +51,13 @@ import org.luaj.vm2.Varargs; *
  • {@link VarArgFunction}
  • *
*

- * To be a Java library that can be loaded via {@code require}, it should have - * a public constructor that returns a {@link LuaValue} that, when executed, - * initializes the library. - *

- * For example, the following code will implement a library called "hyperbolic" + * To be a Java library that can be loaded via {@code require}, it should have + * a public constructor that returns a {@link LuaValue} that, when executed, + * initializes the library. + *

+ * For example, the following code will implement a library called "hyperbolic" * with two functions, "sinh", and "cosh": -

 {@code 
+ 
 {@code
  * import org.luaj.vm2.LuaValue;
  * import org.luaj.vm2.lib.*;
  * 
@@ -86,13 +86,13 @@ import org.luaj.vm2.Varargs;
  *	}
  *}
  *}
- * The default constructor is used to instantiate the library + * The default constructor is used to instantiate the library * in response to {@code require 'hyperbolic'} statement, - * provided it is on Java"s class path. - * This instance is then invoked with 2 arguments: the name supplied to require(), - * and the environment for this function. The library may ignore these, or use - * them to leave side effects in the global environment, for example. - * In the previous example, two functions are created, 'sinh', and 'cosh', and placed + * provided it is on Java"s class path. + * This instance is then invoked with 2 arguments: the name supplied to require(), + * and the environment for this function. The library may ignore these, or use + * them to leave side effects in the global environment, for example. + * In the previous example, two functions are created, 'sinh', and 'cosh', and placed * into a global table called 'hyperbolic' using the supplied 'env' argument. *

* To test it, a script such as this can be used: @@ -105,7 +105,7 @@ import org.luaj.vm2.Varargs; * end * print( 'sinh(.5)', hyperbolic.sinh(.5) ) * print( 'cosh(.5)', hyperbolic.cosh(.5) ) - * }

+ * }
*

* It should produce something like: *

 {@code
@@ -115,16 +115,16 @@ import org.luaj.vm2.Varargs;
  * k,v	sinh	function: 3dbbd242
  * sinh(.5)	0.5210953
  * cosh(.5)	1.127626
- * }
- *

- * See the source code in any of the library functions - * such as {@link BaseLib} or {@link TableLib} for other examples. + * } + *

+ * See the source code in any of the library functions + * such as {@link BaseLib} or {@link TableLib} for other examples. */ abstract public class LibFunction extends LuaFunction { - /** User-defined opcode to differentiate between instances of the library function class. + /** User-defined opcode to differentiate between instances of the library function class. *

- * Subclass will typicall switch on this value to provide the specific behavior for each function. + * Subclass will typicall switch on this value to provide the specific behavior for each function. */ protected int opcode; @@ -135,37 +135,37 @@ abstract public class LibFunction extends LuaFunction { protected String name; /** Default constructor for use by subclasses */ - protected LibFunction() { + protected LibFunction() { } public String tojstring() { return name != null ? "function: " + name : super.tojstring(); } - /** - * Bind a set of library functions. + /** + * Bind a set of library functions. *

- * An array of names is provided, and the first name is bound - * with opcode = 0, second with 1, etc. - * @param env The environment to apply to each bound function + * An array of names is provided, and the first name is bound + * with opcode = 0, second with 1, etc. + * @param env The environment to apply to each bound function * @param factory the Class to instantiate for each bound function * @param names array of String names, one for each function. - * @see #bind(LuaValue, Class, String[], int) + * @see #bind(LuaValue, Class, String[], int) */ protected void bind(LuaValue env, Class factory, String[] names ) { bind( env, factory, names, 0 ); } - /** - * Bind a set of library functions, with an offset + /** + * Bind a set of library functions, with an offset *

- * An array of names is provided, and the first name is bound - * with opcode = {@code firstopcode}, second with {@code firstopcode+1}, etc. - * @param env The environment to apply to each bound function + * An array of names is provided, and the first name is bound + * with opcode = {@code firstopcode}, second with {@code firstopcode+1}, etc. + * @param env The environment to apply to each bound function * @param factory the Class to instantiate for each bound function * @param names array of String names, one for each function. - * @param firstopcode the first opcode to use - * @see #bind(LuaValue, Class, String[]) + * @param firstopcode the first opcode to use + * @see #bind(LuaValue, Class, String[]) */ protected void bind(LuaValue env, Class factory, String[] names, int firstopcode ) { try { @@ -178,7 +178,7 @@ abstract public class LibFunction extends LuaFunction { } catch ( Exception e ) { throw new LuaError( "bind failed: "+e ); } - } + } /** Java code generation utility to allocate storage for upvalue, leave it empty */ protected static LuaValue[] newupe() { @@ -196,7 +196,7 @@ abstract public class LibFunction extends LuaFunction { } public LuaValue call() { - return argerror(1,"value"); + return argerror(1,"value expected"); } public LuaValue call(LuaValue a) { return call(); @@ -219,4 +219,4 @@ abstract public class LibFunction extends LuaFunction { default: return call(args.arg1(),args.arg(2),args.arg(3),args.arg(4)); } } -} +} From 4db34780b7afcc8c553cfedb17a4175aeb8d02f2 Mon Sep 17 00:00:00 2001 From: Enyby Date: Sun, 20 Oct 2019 18:43:10 +0300 Subject: [PATCH 34/62] Fix build error. --- src/jse/org/luaj/vm2/lib/jse/JseIoLib.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jse/org/luaj/vm2/lib/jse/JseIoLib.java b/src/jse/org/luaj/vm2/lib/jse/JseIoLib.java index d00d5db1..cfaf6f4a 100644 --- a/src/jse/org/luaj/vm2/lib/jse/JseIoLib.java +++ b/src/jse/org/luaj/vm2/lib/jse/JseIoLib.java @@ -133,7 +133,7 @@ public class JseIoLib extends IoLib { this( null, null, o ); } public String tojstring() { - return "file (" + (this.closed ? "closed" : this.hashCode()) + ")"; + return "file (" + (this.closed ? "closed" : String.valueOf(this.hashCode())) + ")"; } public boolean isstdfile() { return file == null; From 3a6c38257007aed90b06d1c5b49ee9f42c9897e0 Mon Sep 17 00:00:00 2001 From: Enyby Date: Sun, 20 Oct 2019 19:19:14 +0300 Subject: [PATCH 35/62] Fix 'error' call. #60 --- src/core/org/luaj/vm2/LuaClosure.java | 22 ++++++++++++++++++++-- src/core/org/luaj/vm2/lib/BaseLib.java | 6 +++--- src/core/org/luaj/vm2/lib/DebugLib.java | 8 ++++++-- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/core/org/luaj/vm2/LuaClosure.java b/src/core/org/luaj/vm2/LuaClosure.java index 7877cc62..8214690c 100644 --- a/src/core/org/luaj/vm2/LuaClosure.java +++ b/src/core/org/luaj/vm2/LuaClosure.java @@ -21,6 +21,8 @@ ******************************************************************************/ package org.luaj.vm2; +import org.luaj.vm2.lib.DebugLib.CallFrame; + /** * Extension of {@link LuaFunction} which executes lua bytecode. *

@@ -547,8 +549,24 @@ public class LuaClosure extends LuaFunction { } private void processErrorHooks(LuaError le, Prototype p, int pc) { - le.fileline = (p.source != null? p.source.tojstring(): "?") + ":" - + (p.lineinfo != null && pc >= 0 && pc < p.lineinfo.length? String.valueOf(p.lineinfo[pc]): "?"); + String file = "?"; + int line = -1; + { + CallFrame frame = null; + if (globals != null && globals.debuglib != null) { + frame = globals.debuglib.getCallFrame(le.level); + if (frame != null) { + String src = frame.shortsource(); + file = src != null ? src : "?"; + line = frame.currentline(); + } + } + if (frame == null) { + file = p.source != null? p.source.tojstring(): "?"; + line = p.lineinfo != null && pc >= 0 && pc < p.lineinfo.length ? p.lineinfo[pc] : -1; + } + } + le.fileline = file + ":" + line; le.traceback = errorHook(le.getMessage(), le.level); } diff --git a/src/core/org/luaj/vm2/lib/BaseLib.java b/src/core/org/luaj/vm2/lib/BaseLib.java index 26e1d8c7..fb86825b 100644 --- a/src/core/org/luaj/vm2/lib/BaseLib.java +++ b/src/core/org/luaj/vm2/lib/BaseLib.java @@ -173,9 +173,9 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder { // "error", // ( message [,level] ) -> ERR static final class error extends TwoArgFunction { public LuaValue call(LuaValue arg1, LuaValue arg2) { - throw arg1.isnil()? new LuaError(null, arg2.optint(1)): - arg1.isstring()? new LuaError(arg1.tojstring(), arg2.optint(1)): - new LuaError(arg1); + if (arg1.isnil()) throw new LuaError(NIL); + if (!arg1.isstring() || arg2.optint(1) == 0) throw new LuaError(arg1); + throw new LuaError(arg1.tojstring(), arg2.optint(1)); } } diff --git a/src/core/org/luaj/vm2/lib/DebugLib.java b/src/core/org/luaj/vm2/lib/DebugLib.java index a81ef230..167ea36c 100644 --- a/src/core/org/luaj/vm2/lib/DebugLib.java +++ b/src/core/org/luaj/vm2/lib/DebugLib.java @@ -442,6 +442,10 @@ public class DebugLib extends TwoArgFunction { return callstack().traceback(level); } + public CallFrame getCallFrame(int level) { + return callstack().getCallFrame(level); + } + void callHook(LuaThread.State s, LuaValue type, LuaValue arg) { if (s.inhook || s.hookfunc == null) return; s.inhook = true; @@ -645,7 +649,7 @@ public class DebugLib extends TwoArgFunction { } - static class CallFrame { + public static class CallFrame { LuaFunction f; int pc; int top; @@ -691,7 +695,7 @@ public class DebugLib extends TwoArgFunction { return NIL; } } - int currentline() { + public int currentline() { if ( !f.isclosure() ) return -1; int[] li = f.checkclosure().p.lineinfo; return li==null || pc<0 || pc>=li.length? -1: li[pc]; From c8461b81284a40e08d5346b4657c0b1d85dabe79 Mon Sep 17 00:00:00 2001 From: Enyby Date: Mon, 21 Oct 2019 08:43:53 +0300 Subject: [PATCH 36/62] Fix pattern classes in string lib. ``` local ref = { } for cl in string.gmatch('acdglpsuwxACDGLPSUWX', '.') do local list = '' for i = 0, 255 do if string.match(string.char(i), '%'..cl) then list = list..i..',' end end if ref[cl] then assert(ref[cl] == list, cl..':\n'..list..'\n'..ref[cl]) else print(cl..' = "'..list..'",') end end print('+') ``` --- src/core/org/luaj/vm2/lib/StringLib.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/core/org/luaj/vm2/lib/StringLib.java b/src/core/org/luaj/vm2/lib/StringLib.java index 8dd4f3b6..12cbb3c8 100644 --- a/src/core/org/luaj/vm2/lib/StringLib.java +++ b/src/core/org/luaj/vm2/lib/StringLib.java @@ -821,7 +821,7 @@ public class StringLib extends TwoArgFunction { static { CHAR_TABLE = new byte[256]; - for ( int i = 0; i < 256; ++i ) { + for ( int i = 0; i < 128; ++i ) { final char c = (char) i; CHAR_TABLE[i] = (byte)( ( Character.isDigit( c ) ? MASK_DIGIT : 0 ) | ( Character.isLowerCase( c ) ? MASK_LOWERCASE : 0 ) | @@ -830,7 +830,7 @@ public class StringLib extends TwoArgFunction { if ( ( c >= 'a' && c <= 'f' ) || ( c >= 'A' && c <= 'F' ) || ( c >= '0' && c <= '9' ) ) { CHAR_TABLE[i] |= MASK_HEXDIGIT; } - if ( ( c >= '!' && c <= '/' ) || ( c >= ':' && c <= '@' ) ) { + if ( ( c >= '!' && c <= '/' ) || ( c >= ':' && c <= '@' ) || ( c >= '[' && c <= '`' ) || ( c >= '{' && c <= '~' ) ) { CHAR_TABLE[i] |= MASK_PUNCT; } if ( ( CHAR_TABLE[i] & ( MASK_LOWERCASE | MASK_UPPERCASE ) ) != 0 ) { @@ -842,7 +842,7 @@ public class StringLib extends TwoArgFunction { CHAR_TABLE['\r'] |= MASK_SPACE; CHAR_TABLE['\n'] |= MASK_SPACE; CHAR_TABLE['\t'] |= MASK_SPACE; - CHAR_TABLE[0x0C /* '\v' */ ] |= MASK_SPACE; + CHAR_TABLE[0x0B /* '\v' */ ] |= MASK_SPACE; CHAR_TABLE['\f'] |= MASK_SPACE; }; @@ -1008,9 +1008,10 @@ public class StringLib extends TwoArgFunction { case 'c': res = ( cdata & MASK_CONTROL ) != 0; break; case 'p': res = ( cdata & MASK_PUNCT ) != 0; break; case 's': res = ( cdata & MASK_SPACE ) != 0; break; + case 'g': res = ( cdata & ( MASK_ALPHA | MASK_DIGIT | MASK_PUNCT ) ) != 0; break; case 'w': res = ( cdata & ( MASK_ALPHA | MASK_DIGIT ) ) != 0; break; case 'x': res = ( cdata & MASK_HEXDIGIT ) != 0; break; - case 'z': res = ( c == 0 ); break; + case 'z': res = ( c == 0 ); break; /* deprecated option */ default: return cl == c; } return ( lcl == cl ) ? res : !res; From 22e7a8c620bd6dcd35b2a45e0ead4bd955e536ae Mon Sep 17 00:00:00 2001 From: Enyby Date: Mon, 21 Oct 2019 10:16:43 +0300 Subject: [PATCH 37/62] Fix lexer bugs. Already handled by case above. --- src/core/org/luaj/vm2/compiler/LexState.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/core/org/luaj/vm2/compiler/LexState.java b/src/core/org/luaj/vm2/compiler/LexState.java index 4b9e31c3..d19ba49f 100644 --- a/src/core/org/luaj/vm2/compiler/LexState.java +++ b/src/core/org/luaj/vm2/compiler/LexState.java @@ -696,9 +696,6 @@ public class LexState extends Constants { _assert (!currIsNewline()); nextChar(); continue; - } else if (isdigit(current)) { - read_numeral(seminfo); - return TK_NUMBER; } else if (isalpha(current) || current == '_') { /* identifier or reserved word */ LuaString ts; From f0e9348ae25b7eff36d8e5063f552e98aff0cbca Mon Sep 17 00:00:00 2001 From: Enyby Date: Mon, 21 Oct 2019 10:17:26 +0300 Subject: [PATCH 38/62] Fix lexer bugs. Already handled by inside isalnum. --- src/core/org/luaj/vm2/compiler/LexState.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/org/luaj/vm2/compiler/LexState.java b/src/core/org/luaj/vm2/compiler/LexState.java index d19ba49f..ca4e0970 100644 --- a/src/core/org/luaj/vm2/compiler/LexState.java +++ b/src/core/org/luaj/vm2/compiler/LexState.java @@ -701,7 +701,7 @@ public class LexState extends Constants { LuaString ts; do { save_and_next(); - } while (isalnum(current) || current == '_'); + } while (isalnum(current)); ts = newstring(buff, 0, nbuff); if ( RESERVED.containsKey(ts) ) return ((Integer)RESERVED.get(ts)).intValue(); From fe7bd07450bf7073b0642e2f1b18869cd5676a2b Mon Sep 17 00:00:00 2001 From: Enyby Date: Mon, 21 Oct 2019 10:20:06 +0300 Subject: [PATCH 39/62] Fix lexer bugs. Wrong work with spaces. --- src/core/org/luaj/vm2/compiler/LexState.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/core/org/luaj/vm2/compiler/LexState.java b/src/core/org/luaj/vm2/compiler/LexState.java index ca4e0970..6e6a6708 100644 --- a/src/core/org/luaj/vm2/compiler/LexState.java +++ b/src/core/org/luaj/vm2/compiler/LexState.java @@ -589,6 +589,13 @@ public class LexState extends Constants { inclinenumber(); continue; } + case ' ': + case '\f': + case '\t': + case 0x0B: /* \v */ { + nextChar(); + continue; + } case '-': { nextChar(); if (current != '-') @@ -692,11 +699,7 @@ public class LexState extends Constants { return TK_EOS; } default: { - if (isspace(current)) { - _assert (!currIsNewline()); - nextChar(); - continue; - } else if (isalpha(current) || current == '_') { + if (isalpha(current) || current == '_') { /* identifier or reserved word */ LuaString ts; do { From 0d2aa6cc54f436b10381187bb2c58dc6dd0d9f4e Mon Sep 17 00:00:00 2001 From: Enyby Date: Mon, 21 Oct 2019 23:25:30 +0300 Subject: [PATCH 40/62] Switch little-endian by default as original Lua does. --- src/core/org/luaj/vm2/compiler/DumpState.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/org/luaj/vm2/compiler/DumpState.java b/src/core/org/luaj/vm2/compiler/DumpState.java index cc213315..3f92ba63 100644 --- a/src/core/org/luaj/vm2/compiler/DumpState.java +++ b/src/core/org/luaj/vm2/compiler/DumpState.java @@ -28,14 +28,14 @@ import java.io.OutputStream; import org.luaj.vm2.Globals; import org.luaj.vm2.LoadState; import org.luaj.vm2.LocVars; -import org.luaj.vm2.Prototype; import org.luaj.vm2.LuaString; import org.luaj.vm2.LuaValue; +import org.luaj.vm2.Prototype; /** Class to dump a {@link Prototype} into an output stream, as part of compiling. *

- * Generally, this class is not used directly, but rather indirectly via a command + * Generally, this class is not used directly, but rather indirectly via a command * line interface tool such as {@link luac}. *

* A lua binary file is created via {@link DumpState#dump}: @@ -85,7 +85,7 @@ public class DumpState { public static final int NUMBER_FORMAT_DEFAULT = NUMBER_FORMAT_FLOATS_OR_DOUBLES; // header fields - private boolean IS_LITTLE_ENDIAN = false; + private boolean IS_LITTLE_ENDIAN = true; private int NUMBER_FORMAT = NUMBER_FORMAT_DEFAULT; private int SIZEOF_LUA_NUMBER = 8; private static final int SIZEOF_INT = 4; @@ -190,7 +190,7 @@ public class DumpState { dumpString((LuaString)o); break; default: - throw new IllegalArgumentException("bad type for " + o); + throw new IllegalArgumentException("bad type for " + o); } } n = f.p.length; From ef8175050b404e8c60eed902975d0d88c465c366 Mon Sep 17 00:00:00 2001 From: Enyby Date: Mon, 21 Oct 2019 23:26:10 +0300 Subject: [PATCH 41/62] Remove unused field. --- src/core/org/luaj/vm2/LoadState.java | 37 ++++++++++++++-------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/core/org/luaj/vm2/LoadState.java b/src/core/org/luaj/vm2/LoadState.java index ece3f885..8d71a74a 100644 --- a/src/core/org/luaj/vm2/LoadState.java +++ b/src/core/org/luaj/vm2/LoadState.java @@ -31,10 +31,10 @@ import java.io.InputStream; *

* The {@link LoadState} class provides the default {@link Globals.Undumper} * which is used to undump a string of bytes that represent a lua binary file -* using either the C-based lua compiler, or luaj's +* using either the C-based lua compiler, or luaj's * {@link org.luaj.vm2.compiler.LuaC} compiler. *

-* The canonical method to load and execute code is done +* The canonical method to load and execute code is done * indirectly using the Globals: *

 {@code
 * Globals globals = JsePlatform.standardGlobals();
@@ -44,10 +44,10 @@ import java.io.InputStream;
 * This should work regardless of which {@link Globals.Compiler} or {@link Globals.Undumper}
 * have been installed.
 * 

-* By default, when using {@link org.luaj.vm2.lib.jse.JsePlatform} or +* By default, when using {@link org.luaj.vm2.lib.jse.JsePlatform} or * {@link org.luaj.vm2.lib.jme.JmePlatform} * to construct globals, the {@link LoadState} default undumper is installed -* as the default {@link Globals.Undumper}. +* as the default {@link Globals.Undumper}. *

* * A lua binary file is created via the {@link org.luaj.vm2.compiler.DumpState} class @@ -60,7 +60,7 @@ import java.io.InputStream; * byte[] lua_binary_file_bytes = o.toByteArray(); * }

* -* The {@link LoadState}'s default undumper {@link #instance} +* The {@link LoadState}'s default undumper {@link #instance} * may be used directly to undump these bytes: *
 {@code
 * Prototypep = LoadState.instance.undump(new ByteArrayInputStream(lua_binary_file_bytes), "main.lua");
@@ -99,7 +99,7 @@ public class LoadState {
 	/** format corresponding to number-patched lua, all numbers are 32-bit (4 byte) ints */
 	public static final int NUMBER_FORMAT_NUM_PATCH_INT32      = 4;
 	
-	// type constants	
+	// type constants
 	public static final int LUA_TINT            = (-2);
 	public static final int LUA_TNONE			= (-1);
 	public static final int LUA_TNIL			= 0;
@@ -155,7 +155,6 @@ public class LoadState {
 	private static final LuaValue[]     NOVALUES    = {};
 	private static final Prototype[] NOPROTOS    = {};
 	private static final LocVars[]   NOLOCVARS   = {};
-	private static final LuaString[]  NOSTRVALUES = {};
 	private static final Upvaldesc[]  NOUPVALDESCS = {};
 	private static final int[]       NOINTS      = {};
 	
@@ -168,17 +167,17 @@ public class LoadState {
 	}
 	
 	/** Load a 4-byte int value from the input stream
-	 * @return the int value laoded.  
+	 * @return the int value laoded.
 	 **/
 	int loadInt() throws IOException {
 		is.readFully(buf,0,4);
-		return luacLittleEndian? 
+		return luacLittleEndian?
 				(buf[3] << 24) | ((0xff & buf[2]) << 16) | ((0xff & buf[1]) << 8) | (0xff & buf[0]):
 				(buf[0] << 24) | ((0xff & buf[1]) << 16) | ((0xff & buf[2]) << 8) | (0xff & buf[3]);
 	}
 	
 	/** Load an array of int values from the input stream
-	 * @return the array of int values laoded.  
+	 * @return the array of int values laoded.
 	 **/
 	int[] loadIntArray() throws IOException {
 		int n = loadInt();
@@ -192,7 +191,7 @@ public class LoadState {
 		is.readFully(buf,0,m);
 		int[] array = new int[n];
 		for ( int i=0, j=0; i
Date: Tue, 22 Oct 2019 07:00:21 +0300
Subject: [PATCH 42/62] Fix os.tmpname.

---
 src/jse/org/luaj/vm2/lib/jse/JseOsLib.java | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/jse/org/luaj/vm2/lib/jse/JseOsLib.java b/src/jse/org/luaj/vm2/lib/jse/JseOsLib.java
index 79d67d9f..af63c8af 100644
--- a/src/jse/org/luaj/vm2/lib/jse/JseOsLib.java
+++ b/src/jse/org/luaj/vm2/lib/jse/JseOsLib.java
@@ -33,8 +33,8 @@ import org.luaj.vm2.lib.OsLib;
 /**
  * Subclass of {@link LibFunction} which implements the standard lua {@code os} library.
  * 

- * This contains more complete implementations of the following functions - * using features that are specific to JSE: + * This contains more complete implementations of the following functions + * using features that are specific to JSE: *

    *
  • {@code execute()}
  • *
  • {@code remove()}
  • @@ -42,18 +42,18 @@ import org.luaj.vm2.lib.OsLib; *
  • {@code tmpname()}
  • *
*

- * Because the nature of the {@code os} library is to encapsulate - * os-specific features, the behavior of these functions varies considerably - * from their counterparts in the C platform. + * Because the nature of the {@code os} library is to encapsulate + * os-specific features, the behavior of these functions varies considerably + * from their counterparts in the C platform. *

- * 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("os").get("time").call() );
  * } 
*

- * For special cases where the smallest possible footprint is desired, + * For special cases where the smallest possible footprint is desired, * a minimal set of libraries could be loaded * directly via {@link Globals#load(LuaValue)} using code such as: *

 {@code
@@ -126,7 +126,7 @@ public class JseOsLib extends org.luaj.vm2.lib.OsLib {
 	protected String tmpname() {
 		try {
 			java.io.File f = java.io.File.createTempFile(TMP_PREFIX ,TMP_SUFFIX);
-			return f.getName();
+			return f.getAbsolutePath();
 		} catch ( IOException ioe ) {
 			return super.tmpname();
 		}

From 05e82f1c3f6f84d77b1ba49096e911fbb68560a4 Mon Sep 17 00:00:00 2001
From: Enyby 
Date: Sun, 27 Oct 2019 23:08:44 +0200
Subject: [PATCH 43/62] Add package.config. #49

---
 src/core/org/luaj/vm2/lib/PackageLib.java | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/core/org/luaj/vm2/lib/PackageLib.java b/src/core/org/luaj/vm2/lib/PackageLib.java
index db344818..4c2147c9 100644
--- a/src/core/org/luaj/vm2/lib/PackageLib.java
+++ b/src/core/org/luaj/vm2/lib/PackageLib.java
@@ -144,6 +144,7 @@ public class PackageLib extends TwoArgFunction {
 		searchers.set(2, lua_searcher     = new lua_searcher());
 		searchers.set(3, java_searcher    = new java_searcher());
 		package_.set(_SEARCHERS, searchers);
+		package_.set("config", FILE_SEP + "\n;\n?\n!\n-\n");
 		package_.get(_LOADED).set("package", package_);
 		env.set("package", package_);
 		globals.package_ = this;

From b57eb247bab4d03a39a89bb78c4e8b37e0e064ab Mon Sep 17 00:00:00 2001
From: Enyby 
Date: Sat, 2 Nov 2019 15:18:48 +0200
Subject: [PATCH 44/62] Fix table.unpack.

---
 src/core/org/luaj/vm2/lib/TableLib.java | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/src/core/org/luaj/vm2/lib/TableLib.java b/src/core/org/luaj/vm2/lib/TableLib.java
index 02b82ad4..a1f7db80 100644
--- a/src/core/org/luaj/vm2/lib/TableLib.java
+++ b/src/core/org/luaj/vm2/lib/TableLib.java
@@ -140,11 +140,9 @@ public class TableLib extends TwoArgFunction {
 	static class unpack extends VarArgFunction {
 		public Varargs invoke(Varargs args) {
 			LuaTable t = args.checktable(1);
-			switch (args.narg()) {
-			case 1: return t.unpack();
-			case 2: return t.unpack(args.checkint(2));
-			default: return t.unpack(args.checkint(2), args.checkint(3));
-			}
+			// do not waste resource for calc rawlen if arg3 is not nil
+			int len = args.arg(3).isnil() ? t.rawlen() : 0;
+			return t.unpack(args.optint(2, 1), args.optint(3, len));
 		}
 	}
 }

From 53bd4bf71fb353e5e9da29f4448ec51b2b8374c2 Mon Sep 17 00:00:00 2001
From: Enyby 
Date: Sat, 2 Nov 2019 17:02:21 +0200
Subject: [PATCH 45/62] Fix compiler Bug{ what = [[label between local
 definitions can mix-up their initializations]], report = [[Karel Tuma,
 2016/03/01]], since = [[5.2]], fix = nil, example = [[ do   local k = 0  
 local x   ::foo::   local y       -- should be reset to nil after goto, but
 it is not   assert(not y)   y = true   k = k + 1   if k < 2 then goto foo end
 end ]], patch = [[ --- lparser.c	2015/11/02 16:09:30	2.149 +++
 lparser.c	2016/03/03 12:03:37 @@ -1226,7 +1226,7 @@    checkrepeated(fs,
 ll, label);  /* check for repeated labels */    checknext(ls, TK_DBCOLON); 
 /* skip double colon */    /* create new entry for this label */ -  l =
 newlabelentry(ls, ll, label, line, fs->pc); +  l = newlabelentry(ls, ll,
 label, line, luaK_getlabel(fs));    skipnoopstat(ls);  /* skip other no-op
 statements */    if (block_follow(ls, 0)) {  /* label is last no-op statement
 in the block? */      /* assume that locals are already out of scope */ ]] }

---
 src/core/org/luaj/vm2/compiler/LexState.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/core/org/luaj/vm2/compiler/LexState.java b/src/core/org/luaj/vm2/compiler/LexState.java
index 6e6a6708..0192de05 100644
--- a/src/core/org/luaj/vm2/compiler/LexState.java
+++ b/src/core/org/luaj/vm2/compiler/LexState.java
@@ -1748,7 +1748,7 @@ public class LexState extends Constants {
 		fs.checkrepeated(dyd.label, dyd.n_label, label);  /* check for repeated labels */
 		checknext(TK_DBCOLON);  /* skip double colon */
 		/* create new entry for this label */
-		l = newlabelentry(dyd.label=grow(dyd.label, dyd.n_label+1), dyd.n_label++, label, line, fs.pc);
+		l = newlabelentry(dyd.label=grow(dyd.label, dyd.n_label+1), dyd.n_label++, label, line, fs.getlabel());
 		skipnoopstat();  /* skip other no-op statements */
 		if (block_follow(false)) {  /* label is last no-op statement in the block? */
 			/* assume that locals are already out of scope */

From 99f21b627756b288f759d26b90e360805b7b27eb Mon Sep 17 00:00:00 2001
From: Enyby 
Date: Sun, 3 Nov 2019 14:03:53 +0200
Subject: [PATCH 46/62] Speed up table.sort.

---
 src/core/org/luaj/vm2/LuaTable.java | 107 ++++++++++++++--------------
 1 file changed, 55 insertions(+), 52 deletions(-)

diff --git a/src/core/org/luaj/vm2/LuaTable.java b/src/core/org/luaj/vm2/LuaTable.java
index d95e261c..c0505c90 100644
--- a/src/core/org/luaj/vm2/LuaTable.java
+++ b/src/core/org/luaj/vm2/LuaTable.java
@@ -25,23 +25,23 @@ import java.lang.ref.WeakReference;
 import java.util.Vector;
 
 /**
- * Subclass of {@link LuaValue} for representing lua tables. 
+ * Subclass of {@link LuaValue} for representing lua tables.
  * 

* Almost all API's implemented in {@link LuaTable} are defined and documented in {@link LuaValue}. *

* If a table is needed, the one of the type-checking functions can be used such as - * {@link #istable()}, + * {@link #istable()}, * {@link #checktable()}, or - * {@link #opttable(LuaTable)} + * {@link #opttable(LuaTable)} *

- * The main table operations are defined on {@link LuaValue} + * The main table operations are defined on {@link LuaValue} * for getting and setting values with and without metatag processing: *

    - *
  • {@link #get(LuaValue)}
  • - *
  • {@link #set(LuaValue,LuaValue)}
  • - *
  • {@link #rawget(LuaValue)}
  • + *
  • {@link #get(LuaValue)}
  • + *
  • {@link #set(LuaValue,LuaValue)}
  • + *
  • {@link #rawget(LuaValue)}
  • *
  • {@link #rawset(LuaValue,LuaValue)}
  • - *
  • plus overloads such as {@link #get(String)}, {@link #get(int)}, and so on
  • + *
  • plus overloads such as {@link #get(String)}, {@link #get(int)}, and so on
  • *
*

* To iterate over key-value pairs from Java, use @@ -56,7 +56,7 @@ import java.util.Vector; * }}

* *

- * As with other types, {@link LuaTable} instances should be constructed via one of the table constructor + * As with other types, {@link LuaTable} instances should be constructed via one of the table constructor * methods on {@link LuaValue}: *

    *
  • {@link LuaValue#tableOf()} empty table
  • @@ -92,7 +92,7 @@ public class LuaTable extends LuaValue implements Metatable { hash = NOBUCKETS; } - /** + /** * Construct table with preset capacity. * @param narray capacity of array part * @param nhash capacity of hash part @@ -102,9 +102,9 @@ public class LuaTable extends LuaValue implements Metatable { } /** - * Construct table with named and unnamed parts. + * Construct table with named and unnamed parts. * @param named Named elements in order {@code key-a, value-a, key-b, value-b, ... } - * @param unnamed Unnamed elements in order {@code value-1, value-2, ... } + * @param unnamed Unnamed elements in order {@code value-1, value-2, ... } * @param lastarg Additional unnamed values beyond {@code unnamed.length} */ public LuaTable(LuaValue[] named, LuaValue[] unnamed, Varargs lastarg) { @@ -123,17 +123,17 @@ public class LuaTable extends LuaValue implements Metatable { } /** - * Construct table of unnamed elements. - * @param varargs Unnamed elements in order {@code value-1, value-2, ... } + * Construct table of unnamed elements. + * @param varargs Unnamed elements in order {@code value-1, value-2, ... } */ public LuaTable(Varargs varargs) { this(varargs,1); } /** - * Construct table of unnamed elements. + * Construct table of unnamed elements. * @param varargs Unnamed elements in order {@code value-1, value-2, ... } - * @param firstarg the index in varargs of the first argument to include in the table + * @param firstarg the index in varargs of the first argument to include in the table */ public LuaTable(Varargs varargs, int firstarg) { int nskip = firstarg-1; @@ -152,8 +152,8 @@ public class LuaTable extends LuaValue implements Metatable { return "table"; } - public boolean istable() { - return true; + public boolean istable() { + return true; } public LuaTable checktable() { @@ -185,17 +185,17 @@ public class LuaTable extends LuaValue implements Metatable { return v; } - /** - * Get the length of the array part of the table. - * @return length of the array part, does not relate to count of objects in the table. + /** + * Get the length of the array part of the table. + * @return length of the array part, does not relate to count of objects in the table. */ protected int getArrayLength() { return array.length; } - /** - * Get the length of the hash part of the table. - * @return length of the hash part, does not relate to count of objects in the table. + /** + * Get the length of the hash part of the table. + * @return length of the hash part, does not relate to count of objects in the table. */ protected int getHashLength() { return hash.length; @@ -294,7 +294,7 @@ public class LuaTable extends LuaValue implements Metatable { } /** Remove the element at a position in a list-table - * + * * @param pos the position to remove * @return The removed item, or {@link #NONE} if not removed */ @@ -313,7 +313,7 @@ public class LuaTable extends LuaValue implements Metatable { } /** Insert an element at a position in a list-table - * + * * @param pos the position to remove * @param value The value to insert */ @@ -355,14 +355,14 @@ public class LuaTable extends LuaValue implements Metatable { return rawlen(); } - public LuaValue len() { + public LuaValue len() { final LuaValue h = metatag(LEN); if (h.toboolean()) return h.call(this); return LuaInteger.valueOf(rawlen()); } - public int rawlen() { + public int rawlen() { int a = getArrayLength(); int n = a+1,m=0; while ( !rawget(n).isnil() ) { @@ -380,7 +380,7 @@ public class LuaTable extends LuaValue implements Metatable { } /** - * Get the next element after a particular key in the table + * Get the next element after a particular key in the table * @return key,value or nil */ public Varargs next( LuaValue key ) { @@ -441,8 +441,8 @@ public class LuaTable extends LuaValue implements Metatable { } /** - * Get the next element after a particular key in the - * contiguous array part of a table + * Get the next element after a particular key in the + * contiguous array part of a table * @return key,value or none */ public Varargs inext(LuaValue key) { @@ -517,7 +517,7 @@ public class LuaTable extends LuaValue implements Metatable { } } - /** + /** * Find the hashtable slot to use * @param key key to look for * @return slot to use @@ -779,7 +779,7 @@ public class LuaTable extends LuaValue implements Metatable { // // implemented heap sort from wikipedia // - // Only sorts the contiguous array part. + // Only sorts the contiguous array part. // /** Sort the table using a comparator. * @param comparator {@link LuaValue} to be called to compare elements. @@ -789,17 +789,21 @@ public class LuaTable extends LuaValue implements Metatable { if (m_metatable != null && m_metatable.useWeakValues()) { dropWeakArrayValues(); } + LuaValue[] array = this.array; int n = array.length; while ( n > 0 && array[n-1] == null ) --n; - if ( n > 1 ) - heapSort(n, comparator); + if ( n > 1 ) + heapSort(n, comparator.isnil() ? null : comparator); } private void heapSort(int count, LuaValue cmpfunc) { heapify(count, cmpfunc); + LuaValue[] array = this.array; for ( int end=count-1; end>0; ) { - swap(end, 0); + LuaValue a = array[end]; // swap(end, 0) + array[end] = array[0]; + array[0] = a; siftDown(0, --end, cmpfunc); } } @@ -810,12 +814,15 @@ public class LuaTable extends LuaValue implements Metatable { } private void siftDown(int start, int end, LuaValue cmpfunc) { - for ( int root=start; root*2+1 <= end; ) { - int child = root*2+1; + LuaValue[] array = this.array; + for ( int root=start; root*2+1 <= end; ) { + int child = root*2+1; if (child < end && compare(child, child + 1, cmpfunc)) - ++child; + ++child; if (compare(root, child, cmpfunc)) { - swap(root, child); + LuaValue a = array[root]; // swap(root, child) + array[root] = array[child]; + array[child] = a; root = child; } else return; @@ -824,6 +831,8 @@ public class LuaTable extends LuaValue implements Metatable { private boolean compare(int i, int j, LuaValue cmpfunc) { LuaValue a, b; + LuaValue[] array = this.array; + Metatable m_metatable = this.m_metatable; if (m_metatable == null) { a = array[i]; b = array[j]; @@ -833,22 +842,16 @@ public class LuaTable extends LuaValue implements Metatable { } if ( a == null || b == null ) return false; - if ( ! cmpfunc.isnil() ) { + if ( cmpfunc != null ) { return cmpfunc.call(a,b).toboolean(); } else { return a.lt_b(b); } } - private void swap(int i, int j) { - LuaValue a = array[i]; - array[i] = array[j]; - array[j] = a; - } - - /** This may be deprecated in a future release. + /** This may be deprecated in a future release. * It is recommended to count via iteration over next() instead - * @return count of keys in the table + * @return count of keys in the table * */ public int keyCount() { LuaValue k = LuaValue.NIL; @@ -859,9 +862,9 @@ public class LuaTable extends LuaValue implements Metatable { } } - /** This may be deprecated in a future release. - * It is recommended to use next() instead - * @return array of keys in the table + /** This may be deprecated in a future release. + * It is recommended to use next() instead + * @return array of keys in the table * */ public LuaValue[] keys() { Vector l = new Vector(); From 9a20aa807751a606fe12fe492b3cb1b3241c314c Mon Sep 17 00:00:00 2001 From: Enyby Date: Sun, 3 Nov 2019 15:55:32 +0200 Subject: [PATCH 47/62] Check `pos` bounds for table.insert. --- src/core/org/luaj/vm2/lib/TableLib.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/core/org/luaj/vm2/lib/TableLib.java b/src/core/org/luaj/vm2/lib/TableLib.java index a1f7db80..b77c7a30 100644 --- a/src/core/org/luaj/vm2/lib/TableLib.java +++ b/src/core/org/luaj/vm2/lib/TableLib.java @@ -94,18 +94,22 @@ public class TableLib extends TwoArgFunction { static class insert extends VarArgFunction { public Varargs invoke(Varargs args) { switch (args.narg()) { - case 0: case 1: { - return argerror(2, "value expected"); - } case 2: { LuaTable table = args.checktable(1); table.insert(table.length()+1,args.arg(2)); return NONE; } - default: { - args.checktable(1).insert(args.checkint(2),args.arg(3)); + case 3: { + LuaTable table = args.checktable(1); + int pos = args.checkint(2); + int max = table.length() + 1; + if (pos < 1 || pos > max) argerror(2, "position out of bounds: " + pos + " not between 1 and " + max); + table.insert(pos, args.arg(3)); return NONE; } + default: { + return error("wrong number of arguments to 'table.insert': " + args.narg() + " (must be 2 or 3)"); + } } } } From e120008f9bab49daff9f01979c87eb2e827f46bb Mon Sep 17 00:00:00 2001 From: Enyby Date: Sun, 3 Nov 2019 16:08:01 +0200 Subject: [PATCH 48/62] Validate table.remove `pos`. --- src/core/org/luaj/vm2/lib/TableLib.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/core/org/luaj/vm2/lib/TableLib.java b/src/core/org/luaj/vm2/lib/TableLib.java index b77c7a30..086ac8ef 100644 --- a/src/core/org/luaj/vm2/lib/TableLib.java +++ b/src/core/org/luaj/vm2/lib/TableLib.java @@ -126,7 +126,13 @@ public class TableLib extends TwoArgFunction { // "remove" (table [, pos]) -> removed-ele static class remove extends VarArgFunction { public Varargs invoke(Varargs args) { - return args.checktable(1).remove(args.optint(2, 0)); + LuaTable table = args.checktable(1); + int size = table.length(); + int pos = args.optint(2, size); + if (pos != size && (pos < 1 || pos > size + 1)) { + argerror(2, "position out of bounds: " + pos + " not between 1 and " + (size + 1)); + } + return table.remove(pos); } } From bf663878cb19c37186789fcd4ff3105d15e9e8e8 Mon Sep 17 00:00:00 2001 From: Enyby Date: Mon, 4 Nov 2019 07:57:49 +0200 Subject: [PATCH 49/62] Add support for metatags to table lib methods: sort, insert, remove, unpack. ``` do -- testing table library with metamethods local function test (proxy, t) for i = 1, 10 do table.insert(proxy, 1, i) end assert(#proxy == 10 and #t == 10, tostring(#proxy)..'; '..tostring(#t)) for i = 1, 10 do assert(t[i] == 11 - i) end table.sort(proxy) for i = 1, 10 do assert(t[i] == i and proxy[i] == i, i..': '..tostring(proxy[i])..'; '..tostring(t[i])) end assert(table.concat(proxy, ",") == "1,2,3,4,5,6,7,8,9,10") for i = 1, 8 do assert(table.remove(proxy, 1) == i) end assert(#proxy == 2 and #t == 2) local a, b, c = table.unpack(proxy) assert(a == 9 and b == 10 and c == nil) end -- all virtual local t = {} local proxy = setmetatable({}, { __len = function () return #t end, __index = t, __newindex = t, }) test(proxy, t) -- only __newindex local count = 0 t = setmetatable({}, { __newindex = function (t,k,v) count = count + 1; rawset(t,k,v) end}) test(t, t) assert(count == 10) -- after first 10, all other sets are not new -- no __newindex t = setmetatable({}, { __index = function (_,k) return k + 1 end, __len = function (_) return 5 end}) assert(table.concat(t, ";") == "2;3;4;5;6") end function check (a, f) f = f or function (x,y) return x n) return NONE; - LuaValue v = rawget(pos); + LuaValue v = get(pos); for ( LuaValue r=v; !r.isnil(); ) { - r = rawget(pos+1); - rawset(pos++, r); + r = get(pos+1); + set(pos++, r); } return v.isnil()? NONE: v; } @@ -319,10 +319,10 @@ public class LuaTable extends LuaValue implements Metatable { */ public void insert(int pos, LuaValue value) { if ( pos == 0 ) - pos = rawlen()+1; + pos = length()+1; while ( ! value.isnil() ) { - LuaValue v = rawget( pos ); - rawset(pos++, value); + LuaValue v = get( pos ); + set(pos++, value); value = v; } } @@ -789,40 +789,35 @@ public class LuaTable extends LuaValue implements Metatable { if (m_metatable != null && m_metatable.useWeakValues()) { dropWeakArrayValues(); } - LuaValue[] array = this.array; - int n = array.length; - while ( n > 0 && array[n-1] == null ) - --n; + int n = length(); if ( n > 1 ) heapSort(n, comparator.isnil() ? null : comparator); } private void heapSort(int count, LuaValue cmpfunc) { heapify(count, cmpfunc); - LuaValue[] array = this.array; - for ( int end=count-1; end>0; ) { - LuaValue a = array[end]; // swap(end, 0) - array[end] = array[0]; - array[0] = a; - siftDown(0, --end, cmpfunc); + for ( int end=count; end>1; ) { + LuaValue a = get(end); // swap(end, 1) + set(end, get(1)); + set(1, a); + siftDown(1, --end, cmpfunc); } } private void heapify(int count, LuaValue cmpfunc) { - for ( int start=count/2-1; start>=0; --start ) - siftDown(start, count - 1, cmpfunc); + for ( int start=count/2; start>0; --start ) + siftDown(start, count, cmpfunc); } private void siftDown(int start, int end, LuaValue cmpfunc) { - LuaValue[] array = this.array; - for ( int root=start; root*2+1 <= end; ) { - int child = root*2+1; + for ( int root=start; root*2 <= end; ) { + int child = root*2; if (child < end && compare(child, child + 1, cmpfunc)) ++child; if (compare(root, child, cmpfunc)) { - LuaValue a = array[root]; // swap(root, child) - array[root] = array[child]; - array[child] = a; + LuaValue a = get(root); // swap(root, child) + set(root, get(child)); + set(child, a); root = child; } else return; @@ -830,16 +825,7 @@ public class LuaTable extends LuaValue implements Metatable { } private boolean compare(int i, int j, LuaValue cmpfunc) { - LuaValue a, b; - LuaValue[] array = this.array; - Metatable m_metatable = this.m_metatable; - if (m_metatable == null) { - a = array[i]; - b = array[j]; - } else { - a = m_metatable.arrayget(array, i); - b = m_metatable.arrayget(array, j); - } + LuaValue a = get(i), b = get(j); if ( a == null || b == null ) return false; if ( cmpfunc != null ) { diff --git a/src/core/org/luaj/vm2/lib/TableLib.java b/src/core/org/luaj/vm2/lib/TableLib.java index 086ac8ef..64959277 100644 --- a/src/core/org/luaj/vm2/lib/TableLib.java +++ b/src/core/org/luaj/vm2/lib/TableLib.java @@ -151,7 +151,7 @@ public class TableLib extends TwoArgFunction { public Varargs invoke(Varargs args) { LuaTable t = args.checktable(1); // do not waste resource for calc rawlen if arg3 is not nil - int len = args.arg(3).isnil() ? t.rawlen() : 0; + int len = args.arg(3).isnil() ? t.length() : 0; return t.unpack(args.optint(2, 1), args.optint(3, len)); } } From 6bc8fd6b1bebcf3e9771301d898fcbea48bd869f Mon Sep 17 00:00:00 2001 From: Enyby Date: Sat, 9 Nov 2019 23:12:31 +0200 Subject: [PATCH 50/62] Fix numeric for add order. --- src/core/org/luaj/vm2/LuaClosure.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/org/luaj/vm2/LuaClosure.java b/src/core/org/luaj/vm2/LuaClosure.java index 8214690c..46a3556f 100644 --- a/src/core/org/luaj/vm2/LuaClosure.java +++ b/src/core/org/luaj/vm2/LuaClosure.java @@ -417,7 +417,7 @@ public class LuaClosure extends LuaFunction { { LuaValue limit = stack[a + 1]; LuaValue step = stack[a + 2]; - LuaValue idx = step.add(stack[a]); + LuaValue idx = stack[a].add(step); if (step.gt_b(0)? idx.lteq_b(limit): idx.gteq_b(limit)) { stack[a] = idx; stack[a + 3] = idx; From 8c42c4712bf95114a5cb19f830c1b8162aa4a455 Mon Sep 17 00:00:00 2001 From: Enyby Date: Sat, 9 Nov 2019 23:20:06 +0200 Subject: [PATCH 51/62] Fix empty matches in patterns. ``` do -- new (5.3.3) semantics for empty matches assert(string.gsub("a b cd", " *", "-") == "-a-b-c-d-") local res = "" local sub = "a \nbc\t\td" local i = 1 for p, e in string.gmatch(sub, "()%s*()") do res = res .. string.sub(sub, i, p - 1) .. "-" i = e end assert(res == "-a-b-c-d-") end ``` --- src/core/org/luaj/vm2/lib/StringLib.java | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/core/org/luaj/vm2/lib/StringLib.java b/src/core/org/luaj/vm2/lib/StringLib.java index 12cbb3c8..696970fb 100644 --- a/src/core/org/luaj/vm2/lib/StringLib.java +++ b/src/core/org/luaj/vm2/lib/StringLib.java @@ -527,19 +527,20 @@ public class StringLib extends TwoArgFunction { private final int srclen; private final MatchState ms; private int soffset; + private int lastmatch; public GMatchAux(Varargs args, LuaString src, LuaString pat) { this.srclen = src.length(); this.ms = new MatchState(args, src, pat); this.soffset = 0; + this.lastmatch = -1; } public Varargs invoke(Varargs args) { for ( ; soffset<=srclen; soffset++ ) { ms.reset(); int res = ms.match(soffset, 0); - if ( res >=0 ) { + if ( res >=0 && res != lastmatch ) { int soff = soffset; - soffset = res; - if (soff == res) soffset++; /* empty match? go at least one position */ + lastmatch = soffset = res; return ms.push_captures( true, soff, res ); } } @@ -598,6 +599,7 @@ public class StringLib extends TwoArgFunction { LuaString src = args.checkstring( 1 ); final int srclen = src.length(); LuaString p = args.checkstring( 2 ); + int lastmatch = -1; /* end of last match */ LuaValue repl = args.arg( 3 ); int max_s = args.optint( 4, srclen + 1 ); final boolean anchor = p.length() > 0 && p.charAt( 0 ) == '^'; @@ -610,18 +612,15 @@ public class StringLib extends TwoArgFunction { while ( n < max_s ) { ms.reset(); int res = ms.match( soffset, anchor ? 1 : 0 ); - if ( res != -1 ) { + if ( res != -1 && res != lastmatch ) { /* match? */ n++; - ms.add_value( lbuf, soffset, res, repl ); + ms.add_value( lbuf, soffset, res, repl ); /* add replacement to buffer */ + soffset = lastmatch = res; } - if ( res != -1 && res > soffset ) - soffset = res; - else if ( soffset < srclen ) + else if ( soffset < srclen ) /* otherwise, skip one character */ lbuf.append( (byte) src.luaByte( soffset++ ) ); - else - break; - if ( anchor ) - break; + else break; /* end of subject */ + if ( anchor ) break; } lbuf.append( src.substring( soffset, srclen ) ); return varargsOf(lbuf.tostring(), valueOf(n)); From 5813d56f894835856a33c77079d16284955c1809 Mon Sep 17 00:00:00 2001 From: Enyby Date: Sat, 9 Nov 2019 23:21:39 +0200 Subject: [PATCH 52/62] Improve error messages for invalid capture index. --- src/core/org/luaj/vm2/lib/StringLib.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/org/luaj/vm2/lib/StringLib.java b/src/core/org/luaj/vm2/lib/StringLib.java index 696970fb..550a47f7 100644 --- a/src/core/org/luaj/vm2/lib/StringLib.java +++ b/src/core/org/luaj/vm2/lib/StringLib.java @@ -938,7 +938,7 @@ public class StringLib extends TwoArgFunction { if ( i == 0 ) { return s.substring( soff, end ); } else { - return error( "invalid capture index" ); + return error( "invalid capture index %" + (i + 1) ); } } else { int l = clen[i]; @@ -957,7 +957,7 @@ public class StringLib extends TwoArgFunction { private int check_capture( int l ) { l -= '1'; if ( l < 0 || l >= level || this.clen[l] == CAP_UNFINISHED ) { - error("invalid capture index"); + error("invalid capture index %" + (l + 1)); } return l; } From 0f0ec4bf7b782ddde1ea4d8e0dc106b7f251db0b Mon Sep 17 00:00:00 2001 From: Enyby Date: Sat, 9 Nov 2019 23:25:07 +0200 Subject: [PATCH 53/62] Add check for too complex patterns. ``` -- bug since 2.5 (C-stack overflow) do local function f (size) local s = string.rep("a", size) local p = string.rep(".?", size) return pcall(string.match, s, p) end local r, m = f(80) assert(r and #m == 80) r, m = f(200000) assert(not r and string.find(m, "too complex"), tostring(r)..", "..tostring(m)) end ``` --- src/core/org/luaj/vm2/lib/StringLib.java | 148 ++++++++++++----------- 1 file changed, 79 insertions(+), 69 deletions(-) diff --git a/src/core/org/luaj/vm2/lib/StringLib.java b/src/core/org/luaj/vm2/lib/StringLib.java index 550a47f7..0e6260e0 100644 --- a/src/core/org/luaj/vm2/lib/StringLib.java +++ b/src/core/org/luaj/vm2/lib/StringLib.java @@ -803,6 +803,8 @@ public class StringLib extends TwoArgFunction { private static final LuaString SPECIALS = valueOf("^$*+?.([%-"); private static final int MAX_CAPTURES = 32; + private static final int MAXCCALLS = 200; + private static final int CAP_UNFINISHED = -1; private static final int CAP_POSITION = -2; @@ -846,6 +848,7 @@ public class StringLib extends TwoArgFunction { }; static class MatchState { + int matchdepth; /* control for recursive depth (to avoid C stack overflow) */ final LuaString s; final LuaString p; final Varargs args; @@ -860,10 +863,12 @@ public class StringLib extends TwoArgFunction { this.level = 0; this.cinit = new int[ MAX_CAPTURES ]; this.clen = new int[ MAX_CAPTURES ]; + this.matchdepth = MAXCCALLS; } void reset() { level = 0; + this.matchdepth = MAXCCALLS; } private void add_s( Buffer lbuf, LuaString news, int soff, int e ) { @@ -1052,81 +1057,86 @@ public class StringLib extends TwoArgFunction { * where match ends, otherwise returns -1. */ int match( int soffset, int poffset ) { - while ( true ) { - // 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() ) - return soffset; - switch ( p.luaByte( poffset ) ) { - case '(': - if ( ++poffset < p.length() && p.luaByte( poffset ) == ')' ) - return start_capture( soffset, poffset + 1, CAP_POSITION ); - else - return start_capture( soffset, poffset, CAP_UNFINISHED ); - case ')': - return end_capture( soffset, poffset + 1 ); - case L_ESC: - if ( poffset + 1 == p.length() ) - error("malformed pattern (ends with '%')"); - switch ( p.luaByte( poffset + 1 ) ) { - case 'b': - soffset = matchbalance( soffset, poffset + 2 ); - if ( soffset == -1 ) return -1; - poffset += 4; - continue; - case 'f': { - poffset += 2; - if ( poffset == p.length() || p.luaByte( poffset ) != '[' ) { - error("Missing '[' after '%f' in pattern"); + if (matchdepth-- == 0) error("pattern too complex"); + try { + while ( true ) { + // 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() ) + return soffset; + switch ( p.luaByte( poffset ) ) { + case '(': + if ( ++poffset < p.length() && p.luaByte( poffset ) == ')' ) + return start_capture( soffset, poffset + 1, CAP_POSITION ); + else + return start_capture( soffset, poffset, CAP_UNFINISHED ); + case ')': + return end_capture( soffset, poffset + 1 ); + case L_ESC: + if ( poffset + 1 == p.length() ) + error("malformed pattern (ends with '%')"); + switch ( p.luaByte( poffset + 1 ) ) { + case 'b': + soffset = matchbalance( soffset, poffset + 2 ); + if ( soffset == -1 ) return -1; + poffset += 4; + continue; + case 'f': { + poffset += 2; + if ( poffset == p.length() || p.luaByte( poffset ) != '[' ) { + error("Missing '[' after '%f' in pattern"); + } + int ep = classend( poffset ); + 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( next, poffset, ep - 1 ) ) + return -1; + poffset = ep; + continue; } - int ep = classend( poffset ); - 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( next, poffset, ep - 1 ) ) + default: { + int c = p.luaByte( poffset + 1 ); + if ( Character.isDigit( (char) c ) ) { + soffset = match_capture( soffset, c ); + if ( soffset == -1 ) + return -1; + return match( soffset, poffset + 2 ); + } + } + } + case '$': + if ( poffset + 1 == p.length() ) + return ( soffset == s.length() ) ? soffset : -1; + } + int ep = classend( poffset ); + boolean m = soffset < s.length() && singlematch( s.luaByte( soffset ), poffset, ep ); + int pc = ( ep < p.length() ) ? p.luaByte( ep ) : '\0'; + + switch ( pc ) { + case '?': + int res; + if ( m && ( ( res = match( soffset + 1, ep + 1 ) ) != -1 ) ) + return res; + poffset = ep + 1; + continue; + case '*': + return max_expand( soffset, poffset, ep ); + case '+': + return ( m ? max_expand( soffset + 1, poffset, ep ) : -1 ); + case '-': + return min_expand( soffset, poffset, ep ); + default: + if ( !m ) return -1; + soffset++; poffset = ep; continue; } - default: { - int c = p.luaByte( poffset + 1 ); - if ( Character.isDigit( (char) c ) ) { - soffset = match_capture( soffset, c ); - if ( soffset == -1 ) - return -1; - return match( soffset, poffset + 2 ); - } - } - } - case '$': - if ( poffset + 1 == p.length() ) - return ( soffset == s.length() ) ? soffset : -1; - } - int ep = classend( poffset ); - boolean m = soffset < s.length() && singlematch( s.luaByte( soffset ), poffset, ep ); - int pc = ( ep < p.length() ) ? p.luaByte( ep ) : '\0'; - - switch ( pc ) { - case '?': - int res; - if ( m && ( ( res = match( soffset + 1, ep + 1 ) ) != -1 ) ) - return res; - poffset = ep + 1; - continue; - case '*': - return max_expand( soffset, poffset, ep ); - case '+': - return ( m ? max_expand( soffset + 1, poffset, ep ) : -1 ); - case '-': - return min_expand( soffset, poffset, ep ); - default: - if ( !m ) - return -1; - soffset++; - poffset = ep; - continue; } + } finally { + matchdepth++; } } From ee2d5284e72f1dba6d3c459811f392517ea23093 Mon Sep 17 00:00:00 2001 From: Enyby Date: Sat, 9 Nov 2019 23:25:58 +0200 Subject: [PATCH 54/62] Fix '%b' pattern error message. --- src/core/org/luaj/vm2/lib/StringLib.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/org/luaj/vm2/lib/StringLib.java b/src/core/org/luaj/vm2/lib/StringLib.java index 0e6260e0..6ad1d8cc 100644 --- a/src/core/org/luaj/vm2/lib/StringLib.java +++ b/src/core/org/luaj/vm2/lib/StringLib.java @@ -1201,7 +1201,7 @@ public class StringLib extends TwoArgFunction { int matchbalance( int soff, int poff ) { final int plen = p.length(); if ( poff == plen || poff + 1 == plen ) { - error( "unbalanced pattern" ); + error( "malformed pattern (missing arguments to '%b')" ); } final int slen = s.length(); if ( soff >= slen ) From da0b06555a7d73a323d3dc34d411539751f54690 Mon Sep 17 00:00:00 2001 From: Enyby Date: Sat, 9 Nov 2019 23:26:48 +0200 Subject: [PATCH 55/62] Fix pattern error message. --- src/core/org/luaj/vm2/lib/StringLib.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/org/luaj/vm2/lib/StringLib.java b/src/core/org/luaj/vm2/lib/StringLib.java index 6ad1d8cc..8011459a 100644 --- a/src/core/org/luaj/vm2/lib/StringLib.java +++ b/src/core/org/luaj/vm2/lib/StringLib.java @@ -1085,7 +1085,7 @@ public class StringLib extends TwoArgFunction { case 'f': { poffset += 2; if ( poffset == p.length() || p.luaByte( poffset ) != '[' ) { - error("Missing '[' after '%f' in pattern"); + error("missing '[' after '%f' in pattern"); } int ep = classend( poffset ); int previous = ( soffset == 0 ) ? '\0' : s.luaByte( soffset - 1 ); From 725cf89b6fd93096248a617f07cf0b40c7781cb2 Mon Sep 17 00:00:00 2001 From: Enyby Date: Mon, 11 Nov 2019 02:29:20 +0200 Subject: [PATCH 56/62] Fix metamethods for compare with string. --- src/core/org/luaj/vm2/LuaString.java | 172 +++++++++++++-------------- 1 file changed, 86 insertions(+), 86 deletions(-) diff --git a/src/core/org/luaj/vm2/LuaString.java b/src/core/org/luaj/vm2/LuaString.java index 2c3e8869..08c1022b 100644 --- a/src/core/org/luaj/vm2/LuaString.java +++ b/src/core/org/luaj/vm2/LuaString.java @@ -31,28 +31,28 @@ import java.io.PrintStream; import org.luaj.vm2.lib.MathLib; /** - * Subclass of {@link LuaValue} for representing lua strings. + * Subclass of {@link LuaValue} for representing lua strings. *

    - * Because lua string values are more nearly sequences of bytes than + * Because lua string values are more nearly sequences of bytes than * sequences of characters or unicode code points, the {@link LuaString} - * implementation holds the string value in an internal byte array. + * implementation holds the string value in an internal byte array. *

    - * {@link LuaString} values are not considered mutable once constructed, + * {@link LuaString} values are not considered mutable once constructed, * so multiple {@link LuaString} values can chare a single byte array. *

    * Currently {@link LuaString}s are pooled via a centrally managed weak table. - * To ensure that as many string values as possible take advantage of this, - * Constructors are not exposed directly. As with number, booleans, and nil, + * To ensure that as many string values as possible take advantage of this, + * Constructors are not exposed directly. As with number, booleans, and nil, * instance construction should be via {@link LuaValue#valueOf(byte[])} or similar API. *

    * Because of this pooling, users of LuaString must not directly alter the * bytes in a LuaString, or undefined behavior will result. *

    - * When Java Strings are used to initialize {@link LuaString} data, the UTF8 encoding is assumed. - * The functions + * When Java Strings are used to initialize {@link LuaString} data, the UTF8 encoding is assumed. + * The functions * {@link #lengthAsUtf8(char[])}, - * {@link #encodeToUtf8(char[], int, byte[], int)}, and - * {@link #decodeAsUtf8(byte[], int, int)} + * {@link #encodeToUtf8(char[], int, byte[], int)}, and + * {@link #decodeAsUtf8(byte[], int, int)} * are used to convert back and forth between UTF8 byte arrays and character arrays. * * @see LuaValue @@ -63,15 +63,15 @@ public class LuaString extends LuaValue { /** The singleton instance for string metatables that forwards to the string functions. * Typically, this is set to the string metatable as a side effect of loading the string - * library, and is read-write to provide flexible behavior by default. When used in a + * library, and is read-write to provide flexible behavior by default. When used in a * server environment where there may be roge scripts, this should be replaced with a * read-only table since it is shared across all lua code in this Java VM. */ public static LuaValue s_metatable; /** The bytes for the string. These must not be mutated directly because - * the backing may be shared by multiple LuaStrings, and the hash code is - * computed only at construction time. + * the backing may be shared by multiple LuaStrings, and the hash code is + * computed only at construction time. * It is exposed only for performance and legacy reasons. */ public final byte[] m_bytes; @@ -84,29 +84,29 @@ public class LuaString extends LuaValue { /** The hashcode for this string. Computed at construct time. */ private final int m_hashcode; - /** Size of cache of recent short strings. This is the maximum number of LuaStrings that + /** Size of cache of recent short strings. This is the maximum number of LuaStrings that * will be retained in the cache of recent short strings. Exposed to package for testing. */ static final int RECENT_STRINGS_CACHE_SIZE = 128; - /** Maximum length of a string to be considered for recent short strings caching. + /** Maximum length of a string to be considered for recent short strings caching. * This effectively limits the total memory that can be spent on the recent strings cache, - * because no LuaString whose backing exceeds this length will be put into the cache. + * because no LuaString whose backing exceeds this length will be put into the cache. * Exposed to package for testing. */ static final int RECENT_STRINGS_MAX_LENGTH = 32; - /** Simple cache of recently created strings that are short. - * This is simply a list of strings, indexed by their hash codes modulo the cache size - * that have been recently constructed. If a string is being constructed frequently - * from different contexts, it will generally show up as a cache hit and resolve + /** Simple cache of recently created strings that are short. + * This is simply a list of strings, indexed by their hash codes modulo the cache size + * that have been recently constructed. If a string is being constructed frequently + * from different contexts, it will generally show up as a cache hit and resolve * to the same value. */ private static final class RecentShortStrings { - private static final LuaString recent_short_strings[] = + private static final LuaString recent_short_strings[] = new LuaString[RECENT_STRINGS_CACHE_SIZE]; } /** - * Get a {@link LuaString} instance whose bytes match - * the supplied Java String using the UTF8 encoding. + * Get a {@link LuaString} instance whose bytes match + * the supplied Java String using the UTF8 encoding. * @param string Java String containing characters to encode as UTF8 * @return {@link LuaString} with UTF8 bytes corresponding to the supplied String */ @@ -120,7 +120,7 @@ public class LuaString extends LuaValue { /** Construct a {@link LuaString} for a portion of a byte array. *

    * The array is first be used as the backing for this object, so clients must not change contents. - * If the supplied value for 'len' is more than half the length of the container, the + * If the supplied value for 'len' is more than half the length of the container, the * supplied byte array will be used as the backing, otherwise the bytes will be copied to a * new byte array, and cache lookup may be performed. *

    @@ -172,11 +172,11 @@ public class LuaString extends LuaValue { /** Construct a {@link LuaString} using the supplied characters as byte values. *

    - * Only the low-order 8-bits of each character are used, the remainder is ignored. + * Only the low-order 8-bits of each character are used, the remainder is ignored. *

    - * This is most useful for constructing byte sequences that do not conform to UTF8. - * @param bytes array of char, whose values are truncated at 8-bits each and put into a byte array. - * @return {@link LuaString} wrapping a copy of the byte buffer + * This is most useful for constructing byte sequences that do not conform to UTF8. + * @param bytes array of char, whose values are truncated at 8-bits each and put into a byte array. + * @return {@link LuaString} wrapping a copy of the byte buffer */ public static LuaString valueOf(char[] bytes) { return valueOf(bytes, 0, bytes.length); @@ -184,11 +184,11 @@ public class LuaString extends LuaValue { /** Construct a {@link LuaString} using the supplied characters as byte values. *

    - * Only the low-order 8-bits of each character are used, the remainder is ignored. + * Only the low-order 8-bits of each character are used, the remainder is ignored. *

    - * This is most useful for constructing byte sequences that do not conform to UTF8. - * @param bytes array of char, whose values are truncated at 8-bits each and put into a byte array. - * @return {@link LuaString} wrapping a copy of the byte buffer + * This is most useful for constructing byte sequences that do not conform to UTF8. + * @param bytes array of char, whose values are truncated at 8-bits each and put into a byte array. + * @return {@link LuaString} wrapping a copy of the byte buffer */ public static LuaString valueOf(char[] bytes, int off, int len) { byte[] b = new byte[len]; @@ -215,7 +215,7 @@ public class LuaString extends LuaValue { * The LuaString returned will either be a new LuaString containing the byte array, * or be an existing LuaString used already having the same value. *

    - * The caller must not mutate the contents of the byte array after this call, as + * The caller must not mutate the contents of the byte array after this call, as * it may be used elsewhere due to recent short string caching. * @param bytes byte buffer * @return {@link LuaString} wrapping the byte buffer @@ -241,11 +241,11 @@ public class LuaString extends LuaValue { } public boolean isstring() { - return true; + return true; } - public LuaValue getmetatable() { - return s_metatable; + public LuaValue getmetatable() { + return s_metatable; } public int type() { @@ -289,20 +289,20 @@ public class LuaString extends LuaValue { public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs, checkarith()); } // relational operators, these only work with other strings - public LuaValue lt( LuaValue rhs ) { return rhs.strcmp(this)>0? LuaValue.TRUE: FALSE; } - public boolean lt_b( LuaValue rhs ) { return rhs.strcmp(this)>0; } + public LuaValue lt( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)>0? LuaValue.TRUE: FALSE) : super.lt(rhs); } + public boolean lt_b( LuaValue rhs ) { return rhs.isstring() ? rhs.strcmp(this)>0 : super.lt_b(rhs); } public boolean lt_b( int rhs ) { typerror("attempt to compare string with number"); return false; } public boolean lt_b( double rhs ) { typerror("attempt to compare string with number"); return false; } - public LuaValue lteq( LuaValue rhs ) { return rhs.strcmp(this)>=0? LuaValue.TRUE: FALSE; } - public boolean lteq_b( LuaValue rhs ) { return rhs.strcmp(this)>=0; } + public LuaValue lteq( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)>=0? LuaValue.TRUE: FALSE) : super.lteq(rhs); } + public boolean lteq_b( LuaValue rhs ) { return rhs.isstring() ? rhs.strcmp(this)>=0 : super.lteq_b(rhs); } public boolean lteq_b( int rhs ) { typerror("attempt to compare string with number"); return false; } public boolean lteq_b( double rhs ) { typerror("attempt to compare string with number"); return false; } - public LuaValue gt( LuaValue rhs ) { return rhs.strcmp(this)<0? LuaValue.TRUE: FALSE; } - public boolean gt_b( LuaValue rhs ) { return rhs.strcmp(this)<0; } + public LuaValue gt( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)<0? LuaValue.TRUE: FALSE) : super.gt(rhs); } + public boolean gt_b( LuaValue rhs ) { return rhs.isstring() ? rhs.strcmp(this)<0 : super.gt_b(rhs); } public boolean gt_b( int rhs ) { typerror("attempt to compare string with number"); return false; } public boolean gt_b( double rhs ) { typerror("attempt to compare string with number"); return false; } - public LuaValue gteq( LuaValue rhs ) { return rhs.strcmp(this)<=0? LuaValue.TRUE: FALSE; } - public boolean gteq_b( LuaValue rhs ) { return rhs.strcmp(this)<=0; } + public LuaValue gteq( LuaValue rhs ) { return rhs.isstring() ? (rhs.strcmp(this)<=0? LuaValue.TRUE: FALSE) : super.gteq(rhs); } + public boolean gteq_b( LuaValue rhs ) { return rhs.isstring() ? rhs.strcmp(this)<=0 : super.gteq_b(rhs); } public boolean gteq_b( int rhs ) { typerror("attempt to compare string with number"); return false; } public boolean gteq_b( double rhs ) { typerror("attempt to compare string with number"); return false; } @@ -310,14 +310,14 @@ public class LuaString extends LuaValue { public LuaValue concat(LuaValue rhs) { return rhs.concatTo(this); } public Buffer concat(Buffer rhs) { return rhs.concatTo(this); } public LuaValue concatTo(LuaNumber lhs) { return concatTo(lhs.strvalue()); } - public LuaValue concatTo(LuaString lhs) { + public LuaValue concatTo(LuaString lhs) { byte[] b = new byte[lhs.m_length+this.m_length]; System.arraycopy(lhs.m_bytes, lhs.m_offset, b, 0, lhs.m_length); System.arraycopy(this.m_bytes, this.m_offset, b, lhs.m_length, this.m_length); return valueUsing(b, 0, b.length); } - // string comparison + // string comparison public int strcmp(LuaValue lhs) { return -lhs.strcmp(this); } public int strcmp(LuaString rhs) { for ( int i=0, j=0; i=0 ) + while ( --n>=0 ) if ( a[i++]!=b[j++] ) return false; return true; @@ -535,8 +535,8 @@ public class LuaString extends LuaValue { return luaByte( index ); } - public String checkjstring() { - return tojstring(); + public String checkjstring() { + return tojstring(); } public LuaString checkstring() { @@ -552,7 +552,7 @@ public class LuaString extends LuaValue { } /** - * Copy the bytes of the string into the given byte array. + * Copy the bytes of the string into the given byte array. * @param strOffset offset from which to copy * @param bytes destination byte array * @param arrayOffset offset in destination @@ -626,12 +626,12 @@ public class LuaString extends LuaValue { /** - * Convert to Java String interpreting as utf8 characters. + * Convert to Java String interpreting as utf8 characters. * * @param bytes byte array in UTF8 encoding to convert * @param offset starting index in byte array * @param length number of bytes to convert - * @return Java String corresponding to the value of bytes interpreted using UTF8 + * @return Java String corresponding to the value of bytes interpreted using UTF8 * @see #lengthAsUtf8(char[]) * @see #encodeToUtf8(char[], int, byte[], int) * @see #isValidUtf8() @@ -662,7 +662,7 @@ public class LuaString extends LuaValue { * @see #decodeAsUtf8(byte[], int, int) * @see #isValidUtf8() */ - public static int lengthAsUtf8(char[] chars) { + public static int lengthAsUtf8(char[] chars) { int i,b; char c; for ( i=b=chars.length; --i>=0; ) @@ -673,7 +673,7 @@ public class LuaString extends LuaValue { /** * Encode the given Java string as UTF-8 bytes, writing the result to bytes - * starting at offset. + * starting at offset. *

    * The string should be measured first with lengthAsUtf8 * to make sure the given byte array is large enough. @@ -694,11 +694,11 @@ public class LuaString extends LuaValue { bytes[j++] = (byte) c; } else if ( c < 0x800 ) { bytes[j++] = (byte) (0xC0 | ((c>>6) & 0x1f)); - bytes[j++] = (byte) (0x80 | ( c & 0x3f)); + bytes[j++] = (byte) (0x80 | ( c & 0x3f)); } else { bytes[j++] = (byte) (0xE0 | ((c>>12) & 0x0f)); bytes[j++] = (byte) (0x80 | ((c>>6) & 0x3f)); - bytes[j++] = (byte) (0x80 | ( c & 0x3f)); + bytes[j++] = (byte) (0x80 | ( c & 0x3f)); } } return j - off; @@ -714,12 +714,12 @@ public class LuaString extends LuaValue { for (int i=m_offset,j=m_offset+m_length; i= 0 ) continue; - if ( ((c & 0xE0) == 0xC0) - && i 36 ) @@ -788,7 +788,7 @@ public class LuaString extends LuaValue { * @param base the base to use, such as 10 * @param start the index to start searching from * @param end the first index beyond the search range - * @return double value if conversion is valid, + * @return double value if conversion is valid, * or Double.NaN if not */ private double scanlong( int base, int start, int end ) { @@ -798,7 +798,7 @@ public class LuaString extends LuaValue { int digit = m_bytes[i] - (base<=10||(m_bytes[i]>='0'&&m_bytes[i]<='9')? '0': m_bytes[i]>='A'&&m_bytes[i]<='Z'? ('A'-10): ('a'-10)); if ( digit < 0 || digit >= base ) - return Double.NaN; + return Double.NaN; x = x * base + digit; if ( x < 0 ) return Double.NaN; // overflow @@ -810,7 +810,7 @@ public class LuaString extends LuaValue { * Scan and convert a double value, or return Double.NaN if not a double. * @param start the index to start searching from * @param end the first index beyond the search range - * @return double value if conversion is valid, + * @return double value if conversion is valid, * or Double.NaN if not */ private double scandouble(int start, int end) { @@ -833,7 +833,7 @@ public class LuaString extends LuaValue { c[i-start] = (char) m_bytes[i]; try { return Double.parseDouble(new String(c)); - } catch ( Exception e ) { + } catch ( Exception e ) { return Double.NaN; } } From ca646662429f39d43361f38cafc8b25bb8cb0211 Mon Sep 17 00:00:00 2001 From: Enyby Date: Mon, 11 Nov 2019 02:47:19 +0200 Subject: [PATCH 57/62] Fix metamethods for compare with numbers. ``` t = {} t.__lt = function (a,b,c) collectgarbage() assert(c == nil) if type(a) == 'table' then a = a.x end if type(b) == 'table' then b = b.x end return aOp(1)) and not(Op(1)>Op(2)) and (Op(2)>Op(1))) assert(not(Op('a')>Op('a')) and not(Op('a')>Op('b')) and (Op('b')>Op('a'))) assert((Op(1)>=Op(1)) and not(Op(1)>=Op(2)) and (Op(2)>=Op(1))) assert((1 >= Op(1)) and not(1 >= Op(2)) and (Op(2) >= 1)) assert((Op('a')>=Op('a')) and not(Op('a')>=Op('b')) and (Op('b')>=Op('a'))) assert(('a' >= Op('a')) and not(Op('a') >= 'b') and (Op('b') >= Op('a'))) end test() ``` --- src/core/org/luaj/vm2/LuaDouble.java | 62 +++++++++++++-------------- src/core/org/luaj/vm2/LuaInteger.java | 56 ++++++++++++------------ 2 files changed, 59 insertions(+), 59 deletions(-) diff --git a/src/core/org/luaj/vm2/LuaDouble.java b/src/core/org/luaj/vm2/LuaDouble.java index 53961dc2..0c5cdd66 100644 --- a/src/core/org/luaj/vm2/LuaDouble.java +++ b/src/core/org/luaj/vm2/LuaDouble.java @@ -24,18 +24,18 @@ package org.luaj.vm2; import org.luaj.vm2.lib.MathLib; /** - * Extension of {@link LuaNumber} which can hold a Java double as its value. + * Extension of {@link LuaNumber} which can hold a Java double as its value. *

    - * These instance are not instantiated directly by clients, but indirectly + * These instance are not instantiated directly by clients, but indirectly * via the static functions {@link LuaValue#valueOf(int)} or {@link LuaValue#valueOf(double)} - * functions. This ensures that values which can be represented as int - * are wrapped in {@link LuaInteger} instead of {@link LuaDouble}. + * functions. This ensures that values which can be represented as int + * are wrapped in {@link LuaInteger} instead of {@link LuaDouble}. *

    * Almost all API's implemented in LuaDouble are defined and documented in {@link LuaValue}. *

    * However the constants {@link #NAN}, {@link #POSINF}, {@link #NEGINF}, - * {@link #JSTR_NAN}, {@link #JSTR_POSINF}, and {@link #JSTR_NEGINF} may be useful - * when dealing with Nan or Infinite values. + * {@link #JSTR_NAN}, {@link #JSTR_POSINF}, and {@link #JSTR_NEGINF} may be useful + * when dealing with Nan or Infinite values. *

    * LuaDouble also defines functions for handling the unique math rules of lua devision and modulo in *

      @@ -43,7 +43,7 @@ import org.luaj.vm2.lib.MathLib; *
    • {@link #ddiv_d(double, double)}
    • *
    • {@link #dmod(double, double)}
    • *
    • {@link #dmod_d(double, double)}
    • - *
    + *
*

* @see LuaValue * @see LuaNumber @@ -90,7 +90,7 @@ public class LuaDouble extends LuaNumber { } public boolean islong() { - return v == (long) v; + return v == (long) v; } public byte tobyte() { return (byte) (long) v; } @@ -151,12 +151,12 @@ public class LuaDouble extends LuaNumber { /** Divide two double numbers according to lua math, and return a {@link LuaValue} result. * @param lhs Left-hand-side of the division. * @param rhs Right-hand-side of the division. - * @return {@link LuaValue} for the result of the division, + * @return {@link LuaValue} for the result of the division, * taking into account positive and negiative infinity, and Nan - * @see #ddiv_d(double, double) + * @see #ddiv_d(double, double) */ public static LuaValue ddiv(double lhs, double rhs) { - return rhs!=0? valueOf( lhs / rhs ): lhs>0? POSINF: lhs==0? NAN: NEGINF; + return rhs!=0? valueOf( lhs / rhs ): lhs>0? POSINF: lhs==0? NAN: NEGINF; } /** Divide two double numbers according to lua math, and return a double result. @@ -166,15 +166,15 @@ public class LuaDouble extends LuaNumber { * @see #ddiv(double, double) */ public static double ddiv_d(double lhs, double rhs) { - return rhs!=0? lhs / rhs: lhs>0? Double.POSITIVE_INFINITY: lhs==0? Double.NaN: Double.NEGATIVE_INFINITY; + return rhs!=0? lhs / rhs: lhs>0? Double.POSITIVE_INFINITY: lhs==0? Double.NaN: Double.NEGATIVE_INFINITY; } /** Take modulo double numbers according to lua math, and return a {@link LuaValue} result. * @param lhs Left-hand-side of the modulo. * @param rhs Right-hand-side of the modulo. - * @return {@link LuaValue} for the result of the modulo, + * @return {@link LuaValue} for the result of the modulo, * using lua's rules for modulo - * @see #dmod_d(double, double) + * @see #dmod_d(double, double) */ public static LuaValue dmod(double lhs, double rhs) { if (rhs == 0 || lhs == Double.POSITIVE_INFINITY || lhs == Double.NEGATIVE_INFINITY) return NAN; @@ -190,7 +190,7 @@ public class LuaDouble extends LuaNumber { /** Take modulo for double numbers according to lua math, and return a double result. * @param lhs Left-hand-side of the modulo. * @param rhs Right-hand-side of the modulo. - * @return double value for the result of the modulo, + * @return double value for the result of the modulo, * using lua's rules for modulo * @see #dmod(double, double) */ @@ -206,28 +206,28 @@ public class LuaDouble extends LuaNumber { } // relational operators - public LuaValue lt( LuaValue rhs ) { return rhs.gt_b(v)? LuaValue.TRUE: FALSE; } + public LuaValue lt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gt_b(v)? TRUE: FALSE) : super.lt(rhs); } public LuaValue lt( double rhs ) { return v < rhs? TRUE: FALSE; } public LuaValue lt( int rhs ) { return v < rhs? TRUE: FALSE; } - public boolean lt_b( LuaValue rhs ) { return rhs.gt_b(v); } + public boolean lt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gt_b(v) : super.lt_b(rhs); } public boolean lt_b( int rhs ) { return v < rhs; } public boolean lt_b( double rhs ) { return v < rhs; } - public LuaValue lteq( LuaValue rhs ) { return rhs.gteq_b(v)? LuaValue.TRUE: FALSE; } + public LuaValue lteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gteq_b(v)? TRUE: FALSE) : super.lteq(rhs); } public LuaValue lteq( double rhs ) { return v <= rhs? TRUE: FALSE; } public LuaValue lteq( int rhs ) { return v <= rhs? TRUE: FALSE; } - public boolean lteq_b( LuaValue rhs ) { return rhs.gteq_b(v); } + public boolean lteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gteq_b(v) : super.lteq_b(rhs); } public boolean lteq_b( int rhs ) { return v <= rhs; } public boolean lteq_b( double rhs ) { return v <= rhs; } - public LuaValue gt( LuaValue rhs ) { return rhs.lt_b(v)? LuaValue.TRUE: FALSE; } + public LuaValue gt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lt_b(v)? TRUE: FALSE) : super.gt(rhs); } public LuaValue gt( double rhs ) { return v > rhs? TRUE: FALSE; } public LuaValue gt( int rhs ) { return v > rhs? TRUE: FALSE; } - public boolean gt_b( LuaValue rhs ) { return rhs.lt_b(v); } + public boolean gt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lt_b(v) : super.gt_b(rhs); } public boolean gt_b( int rhs ) { return v > rhs; } public boolean gt_b( double rhs ) { return v > rhs; } - public LuaValue gteq( LuaValue rhs ) { return rhs.lteq_b(v)? LuaValue.TRUE: FALSE; } + public LuaValue gteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lteq_b(v)? TRUE: FALSE) : super.gteq(rhs); } public LuaValue gteq( double rhs ) { return v >= rhs? TRUE: FALSE; } public LuaValue gteq( int rhs ) { return v >= rhs? TRUE: FALSE; } - public boolean gteq_b( LuaValue rhs ) { return rhs.lteq_b(v); } + public boolean gteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lteq_b(v) : super.gteq_b(rhs); } public boolean gteq_b( int rhs ) { return v >= rhs; } public boolean gteq_b( double rhs ) { return v >= rhs; } @@ -236,17 +236,17 @@ public class LuaDouble extends LuaNumber { public String tojstring() { /* - if ( v == 0.0 ) { // never occurs in J2me + if ( v == 0.0 ) { // never occurs in J2me long bits = Double.doubleToLongBits( v ); return ( bits >> 63 == 0 ) ? "0" : "-0"; } */ long l = (long) v; - if ( l == v ) + if ( l == v ) return Long.toString(l); if ( Double.isNaN(v) ) return JSTR_NAN; - if ( Double.isInfinite(v) ) + if ( Double.isInfinite(v) ) return (v<0? JSTR_NEGINF: JSTR_POSINF); return Float.toString((float)v); } @@ -268,11 +268,11 @@ public class LuaDouble extends LuaNumber { } public LuaNumber optnumber(LuaNumber defval) { - return this; + return this; } public boolean isnumber() { - return true; + return true; } public boolean isstring() { @@ -287,14 +287,14 @@ public class LuaDouble extends LuaNumber { public LuaNumber checknumber() { return this; } public double checkdouble() { return v; } - public String checkjstring() { + public String checkjstring() { return tojstring(); } - public LuaString checkstring() { + public LuaString checkstring() { return LuaString.valueOf(tojstring()); } public boolean isvalidkey() { return !Double.isNaN(v); - } + } } diff --git a/src/core/org/luaj/vm2/LuaInteger.java b/src/core/org/luaj/vm2/LuaInteger.java index 6c4cb7ba..e5e651dc 100644 --- a/src/core/org/luaj/vm2/LuaInteger.java +++ b/src/core/org/luaj/vm2/LuaInteger.java @@ -24,14 +24,14 @@ package org.luaj.vm2; import org.luaj.vm2.lib.MathLib; /** - * Extension of {@link LuaNumber} which can hold a Java int as its value. + * Extension of {@link LuaNumber} which can hold a Java int as its value. *

- * These instance are not instantiated directly by clients, but indirectly + * These instance are not instantiated directly by clients, but indirectly * via the static functions {@link LuaValue#valueOf(int)} or {@link LuaValue#valueOf(double)} - * functions. This ensures that policies regarding pooling of instances are - * encapsulated. + * functions. This ensures that policies regarding pooling of instances are + * encapsulated. *

- * There are no API's specific to LuaInteger that are useful beyond what is already + * There are no API's specific to LuaInteger that are useful beyond what is already * exposed in {@link LuaValue}. * * @see LuaValue @@ -61,16 +61,16 @@ public class LuaInteger extends LuaNumber { */ public static LuaNumber valueOf(long l) { int i = (int) l; - return l==i? (i<=255 && i>=-256? intValues[i+256]: - (LuaNumber) new LuaInteger(i)): + return l==i? (i<=255 && i>=-256? intValues[i+256]: + (LuaNumber) new LuaInteger(i)): (LuaNumber) LuaDouble.valueOf(l); } /** The value being held by this instance. */ public final int v; - /** - * Package protected constructor. + /** + * Package protected constructor. * @see LuaValue#valueOf(int) **/ LuaInteger(int i) { @@ -103,15 +103,15 @@ public class LuaInteger extends LuaNumber { } public LuaString optstring(LuaString defval) { - return LuaString.valueOf(Integer.toString(v)); + return LuaString.valueOf(Integer.toString(v)); } public LuaValue tostring() { - return LuaString.valueOf(Integer.toString(v)); + return LuaString.valueOf(Integer.toString(v)); } - public String optjstring(String defval) { - return Integer.toString(v); + public String optjstring(String defval) { + return Integer.toString(v); } public LuaInteger checkinteger() { @@ -172,48 +172,48 @@ public class LuaInteger extends LuaNumber { public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs,v); } // relational operators - public LuaValue lt( LuaValue rhs ) { return rhs.gt_b(v)? TRUE: FALSE; } + public LuaValue lt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gt_b(v)? TRUE: FALSE) : super.lt(rhs); } public LuaValue lt( double rhs ) { return v < rhs? TRUE: FALSE; } public LuaValue lt( int rhs ) { return v < rhs? TRUE: FALSE; } - public boolean lt_b( LuaValue rhs ) { return rhs.gt_b(v); } + public boolean lt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gt_b(v) : super.lt_b(rhs); } public boolean lt_b( int rhs ) { return v < rhs; } public boolean lt_b( double rhs ) { return v < rhs; } - public LuaValue lteq( LuaValue rhs ) { return rhs.gteq_b(v)? TRUE: FALSE; } + public LuaValue lteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gteq_b(v)? TRUE: FALSE) : super.lteq(rhs); } public LuaValue lteq( double rhs ) { return v <= rhs? TRUE: FALSE; } public LuaValue lteq( int rhs ) { return v <= rhs? TRUE: FALSE; } - public boolean lteq_b( LuaValue rhs ) { return rhs.gteq_b(v); } + public boolean lteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gteq_b(v) : super.lteq_b(rhs); } public boolean lteq_b( int rhs ) { return v <= rhs; } public boolean lteq_b( double rhs ) { return v <= rhs; } - public LuaValue gt( LuaValue rhs ) { return rhs.lt_b(v)? TRUE: FALSE; } + public LuaValue gt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lt_b(v)? TRUE: FALSE) : super.gt(rhs); } public LuaValue gt( double rhs ) { return v > rhs? TRUE: FALSE; } public LuaValue gt( int rhs ) { return v > rhs? TRUE: FALSE; } - public boolean gt_b( LuaValue rhs ) { return rhs.lt_b(v); } + public boolean gt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lt_b(v) : super.gt_b(rhs); } public boolean gt_b( int rhs ) { return v > rhs; } public boolean gt_b( double rhs ) { return v > rhs; } - public LuaValue gteq( LuaValue rhs ) { return rhs.lteq_b(v)? TRUE: FALSE; } + public LuaValue gteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lteq_b(v)? TRUE: FALSE) : super.gteq(rhs); } public LuaValue gteq( double rhs ) { return v >= rhs? TRUE: FALSE; } public LuaValue gteq( int rhs ) { return v >= rhs? TRUE: FALSE; } - public boolean gteq_b( LuaValue rhs ) { return rhs.lteq_b(v); } + public boolean gteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lteq_b(v) : super.gteq_b(rhs); } public boolean gteq_b( int rhs ) { return v >= rhs; } public boolean gteq_b( double rhs ) { return v >= rhs; } // string comparison public int strcmp( LuaString rhs ) { typerror("attempt to compare number with string"); return 0; } - public int checkint() { - return v; + public int checkint() { + return v; } public long checklong() { - return v; + return v; } public double checkdouble() { return v; } - public String checkjstring() { - return String.valueOf(v); + public String checkjstring() { + return String.valueOf(v); } - public LuaString checkstring() { - return valueOf( String.valueOf(v) ); + public LuaString checkstring() { + return valueOf( String.valueOf(v) ); } } From d201bc301233d8dd1d12a5181f9ac98412f777bf Mon Sep 17 00:00:00 2001 From: Enyby Date: Sun, 15 Dec 2019 20:39:26 +0200 Subject: [PATCH 58/62] Fix work with weak tables. ``` a = {}; setmetatable(a, {__mode = 'vk'}); a[1], a[2], a[3] = {}, {}, {}; for k, v in pairs(a) do print(k, v) end print('ok') ``` --- src/core/org/luaj/vm2/LuaTable.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/org/luaj/vm2/LuaTable.java b/src/core/org/luaj/vm2/LuaTable.java index b4b6cae2..9aa8f065 100644 --- a/src/core/org/luaj/vm2/LuaTable.java +++ b/src/core/org/luaj/vm2/LuaTable.java @@ -472,7 +472,8 @@ public class LuaTable extends LuaValue implements Metatable { } } if ( checkLoadFactor() ) { - if ( key.isinttype() && key.toint() > 0 ) { + if ( (m_metatable == null || !(m_metatable.useWeakKeys() || m_metatable.useWeakValues())) + && key.isinttype() && key.toint() > 0 ) { // a rehash might make room in the array portion for this key. rehash( key.toint() ); if ( arrayset(key.toint(), value) ) From d6737c0bb35a8b15607a380fffd153bbaa721d55 Mon Sep 17 00:00:00 2001 From: Enyby Date: Mon, 16 Dec 2019 15:31:13 +0200 Subject: [PATCH 59/62] Improve work with weak keys. ``` for _, m in ipairs({'', 'k', 'kv', 'v'}) do print('test', m) a = {}; setmetatable(a, {__mode = m}); a[1], a[2], a[3] = {}, {}, {}; for k, v in pairs(a) do print(k, v) end end print('ok') ``` --- src/core/org/luaj/vm2/LuaTable.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/org/luaj/vm2/LuaTable.java b/src/core/org/luaj/vm2/LuaTable.java index 9aa8f065..7f98b56c 100644 --- a/src/core/org/luaj/vm2/LuaTable.java +++ b/src/core/org/luaj/vm2/LuaTable.java @@ -472,7 +472,7 @@ public class LuaTable extends LuaValue implements Metatable { } } if ( checkLoadFactor() ) { - if ( (m_metatable == null || !(m_metatable.useWeakKeys() || m_metatable.useWeakValues())) + if ( (m_metatable == null || !m_metatable.useWeakValues()) && key.isinttype() && key.toint() > 0 ) { // a rehash might make room in the array portion for this key. rehash( key.toint() ); From 27edcc9a927db3f07f276700e26af3064dff00db Mon Sep 17 00:00:00 2001 From: Enyby Date: Sun, 29 Dec 2019 16:46:58 +0200 Subject: [PATCH 60/62] Fix possible error in rare cases in LuaTable: java.lang.ArrayIndexOutOfBoundsException: length=0; index=0 --- src/core/org/luaj/vm2/LuaTable.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/org/luaj/vm2/LuaTable.java b/src/core/org/luaj/vm2/LuaTable.java index 7f98b56c..a35dcc3f 100644 --- a/src/core/org/luaj/vm2/LuaTable.java +++ b/src/core/org/luaj/vm2/LuaTable.java @@ -720,7 +720,7 @@ public class LuaTable extends LuaValue implements Metatable { StrongSlot entry = slot.first(); if (entry != null) newArray[ k - 1 ] = entry.value(); - } else { + } else if ( !(slot instanceof DeadSlot) ) { int j = slot.keyindex( newHashMask ); newHash[j] = slot.relink( newHash[j] ); } From 30e60a883e392126b12d57281a59502d1856ee60 Mon Sep 17 00:00:00 2001 From: Enyby Date: Wed, 1 Apr 2020 19:31:39 +0300 Subject: [PATCH 61/62] Create LICENSE Source: https://web.archive.org/web/20140514153921/http://sourceforge.net/dbimage.php?id=196142 --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..d74b1d54 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2007 LuaJ. 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. From daf3da94e3cdba0ac6a289148d7e38bd53d3fe64 Mon Sep 17 00:00:00 2001 From: Enyby Date: Wed, 1 Apr 2020 19:36:00 +0300 Subject: [PATCH 62/62] Fix #66: Broken license link. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cacee17d..30f17dbd 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ James Roseborough, Ian Farmer, Version 3.0.2 Copyright © 2009-2014 Luaj.org. Freely available under the terms of the -Luaj license. +Luaj license.