Updated to Lua 5.5
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
LuaJ is a Java implementation of Lua with JSE and JME targets.
|
||||
|
||||
This fork is maintained by Open Autonomous Connection and is built with Maven only. The current codebase targets Lua 5.4 semantics in the supported runtime paths, including the recent work around `<close>`, `<const>`, updated weak-table behavior, binary chunk compatibility, and library alignment.
|
||||
This fork is maintained by Open Autonomous Connection and is built with Maven only. The current codebase targets Lua 5.5 semantics in the supported runtime paths, including `global`, named vararg tables, read-only `for` variables, `table.create`, updated `utf8.offset`, binary chunk compatibility, and the existing Lua 5.4 `<close>` and `<const>` behavior.
|
||||
|
||||
## Modules
|
||||
|
||||
@@ -80,8 +80,9 @@ For the core VM without the JSE platform layer:
|
||||
|
||||
- LuaJ runs on the host JVM garbage collector. Resource cleanup is not equivalent to native Lua finalization.
|
||||
- Explicit close is still the correct pattern for files, iterators, and host-backed resources.
|
||||
- `LuaJC` is available on JSE and covered by the current Maven test path.
|
||||
- `LuaJC` is available on JSE and covered by the current Maven test path. For 5.5-only constructs that the legacy bytecode generator does not model directly, it falls back to generated delegate wrappers over `LuaClosure`.
|
||||
- JME support remains in the Maven build, with environment-specific limitations depending on available Java ME APIs.
|
||||
- The repository currently passes `.\mvnw.cmd -q clean test`.
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -92,10 +93,6 @@ Relevant examples are in:
|
||||
- `examples/lua`
|
||||
- `examples/maven`
|
||||
|
||||
## Status
|
||||
|
||||
Current implementation notes for the Lua 5.4 work are tracked in `LUA54_STATUS.md`.
|
||||
|
||||
## License
|
||||
|
||||
This project is distributed under the terms in `LICENSE`.
|
||||
|
||||
@@ -127,8 +127,9 @@ public class LoadState {
|
||||
public static final String SOURCE_BINARY_STRING = "binary string";
|
||||
|
||||
|
||||
/** for header of binary files -- this is Lua 5.4 */
|
||||
public static final int LUAC_VERSION = 0x54;
|
||||
/** for header of binary files -- this is Lua 5.5 */
|
||||
public static final int LUAC_VERSION = 0x55;
|
||||
public static final int LUAC_VERSION_54 = 0x54;
|
||||
public static final int LUAC_VERSION_53 = 0x53;
|
||||
public static final int LUAC_VERSION_52 = 0x52;
|
||||
|
||||
@@ -177,7 +178,7 @@ public class LoadState {
|
||||
}
|
||||
|
||||
private boolean isModernVersion() {
|
||||
return luacVersion == LUAC_VERSION || luacVersion == LUAC_VERSION_53;
|
||||
return luacVersion == LUAC_VERSION || luacVersion == LUAC_VERSION_54 || luacVersion == LUAC_VERSION_53;
|
||||
}
|
||||
|
||||
/** Load a 4-byte int value from the input stream
|
||||
@@ -369,7 +370,7 @@ public class LoadState {
|
||||
LuaString varname = loadString();
|
||||
int startpc = loadInt();
|
||||
int endpc = loadInt();
|
||||
if (luacVersion == LUAC_VERSION) {
|
||||
if (luacVersion == LUAC_VERSION || luacVersion == LUAC_VERSION_54) {
|
||||
int slot = loadInt();
|
||||
boolean toclose = is.readByte() != 0;
|
||||
boolean isconst = is.readByte() != 0;
|
||||
@@ -405,6 +406,9 @@ public class LoadState {
|
||||
f.numparams = is.readUnsignedByte();
|
||||
f.is_vararg = is.readUnsignedByte();
|
||||
f.maxstacksize = is.readUnsignedByte();
|
||||
if (luacVersion == LUAC_VERSION) {
|
||||
f.varargname = loadString();
|
||||
}
|
||||
f.code = loadIntArray();
|
||||
if (isModernVersion()) {
|
||||
loadConstants(f);
|
||||
|
||||
@@ -30,7 +30,7 @@ package org.luaj.vm2;
|
||||
*/
|
||||
public class Lua {
|
||||
/** version is supplied by ant build task */
|
||||
public static final String _VERSION = "Lua 5.4";
|
||||
public static final String _VERSION = "Lua 5.5";
|
||||
|
||||
/** use return values from previous op */
|
||||
public static final int LUA_MULTRET = -1;
|
||||
|
||||
@@ -257,6 +257,8 @@ public class LuaClosure extends LuaFunction implements PrototypeProvider {
|
||||
// TODO: use linked list.
|
||||
UpValue[] openups = p.p.length>0? new UpValue[stack.length]: null;
|
||||
boolean[] closedLocals = hasToCloseLocals()? new boolean[stack.length]: NOCLOSEVARS;
|
||||
if (p.varargname != null && p.numparams < stack.length)
|
||||
stack[p.numparams] = packVarargs(varargs);
|
||||
|
||||
// allow for debug hooks
|
||||
if (globals != null && globals.debuglib != null)
|
||||
@@ -633,6 +635,12 @@ public class LuaClosure extends LuaFunction implements PrototypeProvider {
|
||||
}
|
||||
}
|
||||
|
||||
private LuaTable packVarargs(Varargs varargs) {
|
||||
LuaTable table = LuaValue.tableOf(varargs, 1);
|
||||
table.set("n", LuaValue.valueOf(varargs.narg()));
|
||||
return table;
|
||||
}
|
||||
|
||||
private boolean hasToCloseLocals() {
|
||||
if (p.locvars == null)
|
||||
return false;
|
||||
|
||||
@@ -99,6 +99,7 @@ public class Prototype {
|
||||
public int lastlinedefined;
|
||||
public int numparams;
|
||||
public int is_vararg;
|
||||
public LuaString varargname;
|
||||
public int maxstacksize;
|
||||
private static final Upvaldesc[] NOUPVALUES = {};
|
||||
private static final Prototype[] NOSUBPROTOS = {};
|
||||
|
||||
@@ -276,6 +276,7 @@ public class DumpState {
|
||||
dumpChar(f.numparams);
|
||||
dumpChar(f.is_vararg);
|
||||
dumpChar(f.maxstacksize);
|
||||
dumpString(f.varargname);
|
||||
dumpCode(f);
|
||||
dumpConstants(f);
|
||||
dumpUpvalues(f);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
******************************************************************************/
|
||||
package org.luaj.vm2.compiler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.luaj.vm2.LocVars;
|
||||
@@ -45,6 +46,8 @@ public class FuncState extends Constants {
|
||||
boolean upval; /* true if some variable in the block is an upvalue */
|
||||
boolean toclose; /* true if some variable in the block needs __close handling */
|
||||
boolean isloop; /* true if `block' is a loop */
|
||||
BlockCnt declPrevious; /* lexical declaration scope chain */
|
||||
ArrayList globaldecls; /* explicit global declarations in this block */
|
||||
};
|
||||
|
||||
Prototype f; /* current function header */
|
||||
@@ -226,6 +229,9 @@ public class FuncState extends Constants {
|
||||
bl.upval = false;
|
||||
bl.toclose = false;
|
||||
bl.previous = this.bl;
|
||||
bl.declPrevious = ls.declbl;
|
||||
bl.globaldecls = null;
|
||||
ls.declbl = bl;
|
||||
this.bl = bl;
|
||||
_assert(this.freereg == this.nactvar);
|
||||
}
|
||||
@@ -241,6 +247,7 @@ public class FuncState extends Constants {
|
||||
if (bl.isloop)
|
||||
ls.breaklabel(); /* close pending breaks */
|
||||
this.bl = bl.previous;
|
||||
ls.declbl = bl.declPrevious;
|
||||
this.removevars(bl.nactvar);
|
||||
_assert(bl.nactvar == this.nactvar);
|
||||
this.freereg = this.nactvar; /* free registers */
|
||||
|
||||
@@ -23,6 +23,7 @@ package org.luaj.vm2.compiler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.luaj.vm2.LocVars;
|
||||
@@ -146,11 +147,12 @@ public class LexState extends Constants {
|
||||
LuaString source; /* current source name */
|
||||
LuaString envn; /* environment variable name */
|
||||
byte decpoint; /* locale decimal point */
|
||||
FuncState.BlockCnt declbl; /* lexical declaration scope chain */
|
||||
|
||||
/* ORDER RESERVED */
|
||||
final static String luaX_tokens [] = {
|
||||
"and", "break", "continue", "do", "else", "elseif",
|
||||
"end", "false", "for", "function", "goto", "if",
|
||||
"end", "false", "for", "function", "global", "goto", "if",
|
||||
"in", "local", "nil", "not", "or", "repeat",
|
||||
"return", "then", "true", "until", "while",
|
||||
"..", "...", "//", "<<", ">>", "==", ">=", "<=", "~=",
|
||||
@@ -160,12 +162,12 @@ public class LexState extends Constants {
|
||||
final static int
|
||||
/* terminal symbols denoted by reserved words */
|
||||
TK_AND=257, TK_BREAK=258, TK_CONTINUE=259, TK_DO=260, TK_ELSE=261, TK_ELSEIF=262,
|
||||
TK_END=263, TK_FALSE=264, TK_FOR=265, TK_FUNCTION=266, TK_GOTO=267, TK_IF=268,
|
||||
TK_IN=269, TK_LOCAL=270, TK_NIL=271, TK_NOT=272, TK_OR=273, TK_REPEAT=274,
|
||||
TK_RETURN=275, TK_THEN=276, TK_TRUE=277, TK_UNTIL=278, TK_WHILE=279,
|
||||
TK_END=263, TK_FALSE=264, TK_FOR=265, TK_FUNCTION=266, TK_GLOBAL=267, TK_GOTO=268, TK_IF=269,
|
||||
TK_IN=270, TK_LOCAL=271, TK_NIL=272, TK_NOT=273, TK_OR=274, TK_REPEAT=275,
|
||||
TK_RETURN=276, TK_THEN=277, TK_TRUE=278, TK_UNTIL=279, TK_WHILE=280,
|
||||
/* other terminal symbols */
|
||||
TK_CONCAT=280, TK_DOTS=281, TK_IDIV=282, TK_SHL=283, TK_SHR=284, TK_EQ=285, TK_GE=286, TK_LE=287, TK_NE=288,
|
||||
TK_DBCOLON=289, TK_EOS=290, TK_NUMBER=291, TK_NAME=292, TK_STRING=293;
|
||||
TK_CONCAT=281, TK_DOTS=282, TK_IDIV=283, TK_SHL=284, TK_SHR=285, TK_EQ=286, TK_GE=287, TK_LE=288, TK_NE=289,
|
||||
TK_DBCOLON=290, TK_EOS=291, TK_NUMBER=292, TK_NAME=293, TK_STRING=294;
|
||||
|
||||
final static int FIRST_RESERVED = TK_AND;
|
||||
final static int NUM_RESERVED = TK_WHILE+1-FIRST_RESERVED;
|
||||
@@ -868,6 +870,18 @@ public class LexState extends Constants {
|
||||
}
|
||||
};
|
||||
|
||||
static final class GlobalDecl {
|
||||
final LuaString name;
|
||||
final boolean isconst;
|
||||
final boolean wildcard;
|
||||
|
||||
GlobalDecl(LuaString name, boolean isconst, boolean wildcard) {
|
||||
this.name = name;
|
||||
this.isconst = isconst;
|
||||
this.wildcard = wildcard;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* description of pending goto statements and label statements */
|
||||
static class Labeldesc {
|
||||
@@ -1028,14 +1042,48 @@ public class LexState extends Constants {
|
||||
LuaString varname = this.str_checkname();
|
||||
FuncState fs = this.fs;
|
||||
if (FuncState.singlevaraux(fs, varname, var, 1) == VVOID) { /* global name? */
|
||||
expdesc key = new expdesc();
|
||||
FuncState.singlevaraux(fs, this.envn, var, 1); /* get environment variable */
|
||||
_assert(var.k == VLOCAL || var.k == VUPVAL);
|
||||
this.codestring(key, varname); /* key is variable name */
|
||||
fs.indexed(var, key); /* env[varname] */
|
||||
if (!resolveglobal(varname, var))
|
||||
this.semerror("variable '" + varname.tojstring() + "' is not declared");
|
||||
}
|
||||
}
|
||||
|
||||
private void makeglobalvar(LuaString varname, expdesc var) {
|
||||
expdesc key = new expdesc();
|
||||
FuncState.singlevaraux(this.fs, this.envn, var, 1);
|
||||
_assert(var.k == VLOCAL || var.k == VUPVAL);
|
||||
this.codestring(key, varname);
|
||||
this.fs.indexed(var, key);
|
||||
}
|
||||
|
||||
private boolean resolveglobal(LuaString varname, expdesc var) {
|
||||
boolean explicitSeen = false;
|
||||
for (FuncState.BlockCnt block = declbl; block != null; block = block.declPrevious) {
|
||||
if (block.globaldecls == null)
|
||||
continue;
|
||||
explicitSeen = true;
|
||||
for (int i = block.globaldecls.size() - 1; i >= 0; i--) {
|
||||
GlobalDecl decl = (GlobalDecl) block.globaldecls.get(i);
|
||||
if (decl.wildcard || decl.name.eq_b(varname)) {
|
||||
makeglobalvar(varname, var);
|
||||
var.isconst = decl.isconst;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!explicitSeen) {
|
||||
makeglobalvar(varname, var);
|
||||
var.isconst = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void registerglobaldecl(LuaString name, boolean isconst, boolean wildcard) {
|
||||
if (declbl.globaldecls == null)
|
||||
declbl.globaldecls = new ArrayList();
|
||||
declbl.globaldecls.add(new GlobalDecl(name, isconst, wildcard));
|
||||
}
|
||||
|
||||
void adjust_assign(int nvars, int nexps, expdesc e) {
|
||||
FuncState fs = this.fs;
|
||||
int extra = nvars - nexps;
|
||||
@@ -1337,7 +1385,9 @@ public class LexState extends Constants {
|
||||
/* parlist -> [ param { `,' param } ] */
|
||||
FuncState fs = this.fs;
|
||||
Prototype f = fs.f;
|
||||
int firstparam = fs.nactvar;
|
||||
int nparams = 0;
|
||||
LuaString varargname = null;
|
||||
f.is_vararg = 0;
|
||||
if (this.t.token != ')') { /* is `parlist' not empty? */
|
||||
do {
|
||||
@@ -1350,14 +1400,19 @@ public class LexState extends Constants {
|
||||
case TK_DOTS: { /* param . `...' */
|
||||
this.next();
|
||||
f.is_vararg = 1;
|
||||
if (this.t.token == TK_NAME) {
|
||||
varargname = this.str_checkname();
|
||||
this.new_localvar(varargname);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: this.syntaxerror("<name> or " + LUA_QL("...") + " expected");
|
||||
}
|
||||
} while ((f.is_vararg==0) && this.testnext(','));
|
||||
}
|
||||
this.adjustlocalvars(nparams);
|
||||
f.numparams = fs.nactvar;
|
||||
this.adjustlocalvars(nparams + (varargname != null ? 1 : 0));
|
||||
f.numparams = firstparam + nparams;
|
||||
f.varargname = varargname;
|
||||
fs.reserveregs(fs.nactvar); /* reserve register for parameters */
|
||||
}
|
||||
|
||||
@@ -1764,7 +1819,7 @@ public class LexState extends Constants {
|
||||
}
|
||||
|
||||
void check_readonly(expdesc v) {
|
||||
if ((v.k == VLOCAL || v.k == VUPVAL) && v.isconst)
|
||||
if (v.isconst)
|
||||
this.semerror("attempt to assign to const variable");
|
||||
}
|
||||
|
||||
@@ -1948,7 +2003,7 @@ public class LexState extends Constants {
|
||||
this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_INDEX);
|
||||
this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_LIMIT);
|
||||
this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_STEP);
|
||||
this.new_localvar(varname);
|
||||
this.new_localvar(varname, false, true);
|
||||
this.checknext('=');
|
||||
this.exp1(); /* initial value */
|
||||
this.checknext(',');
|
||||
@@ -1975,9 +2030,9 @@ public class LexState extends Constants {
|
||||
this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_STATE);
|
||||
this.new_localvarliteral(RESERVED_LOCAL_VAR_FOR_CONTROL);
|
||||
/* create declared variables */
|
||||
this.new_localvar(indexname);
|
||||
this.new_localvar(indexname, false, true);
|
||||
while (this.testnext(',')) {
|
||||
this.new_localvar(this.str_checkname());
|
||||
this.new_localvar(this.str_checkname(), false, true);
|
||||
++nvars;
|
||||
}
|
||||
this.checknext(TK_IN);
|
||||
@@ -2100,6 +2155,70 @@ public class LexState extends Constants {
|
||||
this.adjustlocalvars(nvars);
|
||||
}
|
||||
|
||||
private boolean parseGlobalAttribute() {
|
||||
this.checknext('<');
|
||||
LuaString attr = this.str_checkname();
|
||||
this.checknext('>');
|
||||
if (attr.eq_b(LuaValue.valueOf("const")))
|
||||
return true;
|
||||
if (attr.eq_b(LuaValue.valueOf("close")))
|
||||
this.syntaxerror("global variables do not support attribute 'close'");
|
||||
this.syntaxerror("unknown attribute '" + attr.tojstring() + "'");
|
||||
return false;
|
||||
}
|
||||
|
||||
private void storeDeclaredGlobals(ArrayList names, expdesc e, int nvars, int nexps) {
|
||||
ArrayList vars = new ArrayList(nvars);
|
||||
for (int i = 0; i < nvars; i++) {
|
||||
expdesc var = new expdesc();
|
||||
makeglobalvar((LuaString) names.get(i), var);
|
||||
vars.add(var);
|
||||
}
|
||||
if (nexps == nvars) {
|
||||
fs.setoneret(e);
|
||||
fs.storevar((expdesc) vars.get(nvars - 1), e);
|
||||
nvars--;
|
||||
}
|
||||
for (int i = nvars - 1; i >= 0; i--) {
|
||||
expdesc value = new expdesc();
|
||||
value.init(VNONRELOC, this.fs.freereg - 1);
|
||||
fs.storevar((expdesc) vars.get(i), value);
|
||||
}
|
||||
}
|
||||
|
||||
void globalstat() {
|
||||
int nvars = 0;
|
||||
int nexps = 0;
|
||||
expdesc e = new expdesc();
|
||||
boolean defaultConst = false;
|
||||
ArrayList names = new ArrayList();
|
||||
ArrayList consts = new ArrayList();
|
||||
this.next(); /* skip GLOBAL */
|
||||
if (this.t.token == '<')
|
||||
defaultConst = parseGlobalAttribute();
|
||||
if (this.t.token == '*') {
|
||||
this.next();
|
||||
registerglobaldecl(null, defaultConst, true);
|
||||
return;
|
||||
}
|
||||
do {
|
||||
LuaString name = this.str_checkname();
|
||||
boolean isconst = defaultConst;
|
||||
if (this.t.token == '<')
|
||||
isconst = parseGlobalAttribute();
|
||||
names.add(name);
|
||||
consts.add(Boolean.valueOf(isconst));
|
||||
nvars++;
|
||||
} while (this.testnext(','));
|
||||
if (this.testnext('=')) {
|
||||
nexps = this.explist(e);
|
||||
this.adjust_assign(nvars, nexps, e);
|
||||
storeDeclaredGlobals(names, e, nvars, nexps);
|
||||
}
|
||||
for (int i = 0; i < nvars; i++)
|
||||
registerglobaldecl((LuaString) names.get(i), ((Boolean) consts.get(i)).booleanValue(), false);
|
||||
}
|
||||
|
||||
|
||||
boolean funcname(expdesc v) {
|
||||
/* funcname -> NAME {field} [`:' NAME] */
|
||||
@@ -2216,6 +2335,10 @@ public class LexState extends Constants {
|
||||
this.localstat();
|
||||
break;
|
||||
}
|
||||
case TK_GLOBAL: {
|
||||
this.globalstat();
|
||||
break;
|
||||
}
|
||||
case TK_DBCOLON: { /* stat -> label */
|
||||
next(); /* skip double colon */
|
||||
labelstat(str_checkname(), line);
|
||||
|
||||
@@ -65,6 +65,7 @@ public class TableLib extends TwoArgFunction {
|
||||
public LuaValue call(LuaValue modname, LuaValue env) {
|
||||
LuaTable table = new LuaTable();
|
||||
table.set("concat", new concat());
|
||||
table.set("create", new create());
|
||||
table.set("insert", new insert());
|
||||
table.set("move", new move());
|
||||
table.set("pack", new pack());
|
||||
@@ -125,6 +126,25 @@ public class TableLib extends TwoArgFunction {
|
||||
}
|
||||
}
|
||||
|
||||
// "create" (size [, value]) -> table
|
||||
static class create extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
int size = args.checkint(1);
|
||||
if (size < 0) {
|
||||
argerror(1, "size out of range");
|
||||
}
|
||||
LuaTable table = LuaValue.tableOf(size, 0);
|
||||
if (!args.isnoneornil(2)) {
|
||||
LuaValue value = args.arg(2);
|
||||
table.presize(size);
|
||||
for (int i = 1; i <= size; i++) {
|
||||
table.set(i, value);
|
||||
}
|
||||
}
|
||||
return table;
|
||||
}
|
||||
}
|
||||
|
||||
// "move" (a1, f, e, t [,a2]) -> a2
|
||||
static class move extends VarArgFunction {
|
||||
public Varargs invoke(Varargs args) {
|
||||
|
||||
@@ -133,7 +133,8 @@ public class Utf8Lib extends TwoArgFunction {
|
||||
if (i <= len && isContinuation(s.luaByte(i - 1))) {
|
||||
throw new LuaError("initial position is a continuation byte");
|
||||
}
|
||||
return LuaValue.valueOf(i);
|
||||
Decoded decoded = decode(s, i - 1);
|
||||
return LuaValue.varargsOf(new LuaValue[] { LuaValue.valueOf(i), LuaValue.valueOf(decoded.next) });
|
||||
}
|
||||
int pos = i - 1;
|
||||
if (n > 0) {
|
||||
@@ -147,7 +148,8 @@ public class Utf8Lib extends TwoArgFunction {
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
return LuaValue.valueOf(pos + 1);
|
||||
Decoded decoded = decode(s, pos);
|
||||
return LuaValue.varargsOf(new LuaValue[] { LuaValue.valueOf(pos + 1), LuaValue.valueOf(decoded.next) });
|
||||
}
|
||||
while (n < 0) {
|
||||
if (pos <= 0) {
|
||||
@@ -162,7 +164,8 @@ public class Utf8Lib extends TwoArgFunction {
|
||||
}
|
||||
n++;
|
||||
}
|
||||
return LuaValue.valueOf(pos + 1);
|
||||
Decoded decoded = decode(s, pos);
|
||||
return LuaValue.varargsOf(new LuaValue[] { LuaValue.valueOf(pos + 1), LuaValue.valueOf(decoded.next) });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ public class LuaJC implements Globals.Loader {
|
||||
}
|
||||
|
||||
private boolean requiresInterpreterDelegate(Prototype p) {
|
||||
return hasToCloseLocals(p) || usesInterpreterOnlyRuntimeSemantics(p);
|
||||
return hasToCloseLocals(p) || hasNamedVarargTables(p) || usesInterpreterOnlyRuntimeSemantics(p);
|
||||
}
|
||||
|
||||
private boolean hasToCloseLocals(Prototype p) {
|
||||
@@ -148,6 +148,20 @@ public class LuaJC implements Globals.Loader {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasNamedVarargTables(Prototype p) {
|
||||
if (p.varargname != null) {
|
||||
return true;
|
||||
}
|
||||
if (p.p != null) {
|
||||
for (int i = 0; i < p.p.length; i++) {
|
||||
if (p.p[i] != null && hasNamedVarargTables(p.p[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean usesInterpreterOnlyRuntimeSemantics(Prototype p) {
|
||||
if (prototypeReferences(p, "xpcall") || prototypeReferences(p, "debug")) {
|
||||
return true;
|
||||
|
||||
@@ -51,7 +51,7 @@ public class LuaScriptEngine extends AbstractScriptEngine implements ScriptEngin
|
||||
private static final String __NAME__ = "Luaj";
|
||||
private static final String __SHORT_NAME__ = "Luaj";
|
||||
private static final String __LANGUAGE__ = "lua";
|
||||
private static final String __LANGUAGE_VERSION__ = "5.4";
|
||||
private static final String __LANGUAGE_VERSION__ = "5.5";
|
||||
private static final String __ARGV__ = "arg";
|
||||
private static final String __FILENAME__ = "?";
|
||||
|
||||
|
||||
@@ -499,7 +499,8 @@ public class FragmentsTest extends TestSuite {
|
||||
LuaValue.valueOf(2),
|
||||
LuaValue.valueOf(228),
|
||||
LuaValue.valueOf(97),
|
||||
LuaValue.valueOf(2)
|
||||
LuaValue.valueOf(2),
|
||||
LuaValue.valueOf(3)
|
||||
}),
|
||||
"local s = utf8.char(97, 228)\nlocal iter, state, var = utf8.codes(s)\nlocal _, cp = iter(state, var)\nreturn utf8.len(s), utf8.codepoint(s, 2), cp, utf8.offset(s, 2)\n");
|
||||
}
|
||||
@@ -550,7 +551,7 @@ public class FragmentsTest extends TestSuite {
|
||||
runFragment(
|
||||
LuaValue.varargsOf(new LuaValue[] {
|
||||
LuaValue.valueOf(123),
|
||||
LuaValue.valueOf(84)
|
||||
LuaValue.valueOf(85)
|
||||
}),
|
||||
"local dumped = string.dump(function() return 123 end)\n" +
|
||||
"local loaded = assert(load(dumped, 'dumped', 'b'))\n" +
|
||||
@@ -565,11 +566,21 @@ public class FragmentsTest extends TestSuite {
|
||||
LuaValue.FALSE,
|
||||
LuaValue.valueOf(Long.MAX_VALUE),
|
||||
LuaValue.valueOf(Long.MIN_VALUE),
|
||||
LuaValue.valueOf("Lua 5.4")
|
||||
LuaValue.valueOf("Lua 5.5")
|
||||
}),
|
||||
"return math.type(3), math.tointeger(3.0), math.ult(-1, 1), math.maxinteger, math.mininteger, _VERSION\n");
|
||||
}
|
||||
|
||||
public void testTableCreate55() {
|
||||
runFragment(
|
||||
LuaValue.varargsOf(new LuaValue[] {
|
||||
LuaValue.valueOf(3),
|
||||
LuaValue.valueOf("x"),
|
||||
LuaValue.valueOf("x")
|
||||
}),
|
||||
"local t = table.create(3, 'x')\nreturn #t, t[1], t[3]\n");
|
||||
}
|
||||
|
||||
public void testHexFloatLiteralAndTonumber() {
|
||||
runFragment(
|
||||
LuaValue.varargsOf(new LuaValue[] {
|
||||
@@ -734,6 +745,101 @@ public class FragmentsTest extends TestSuite {
|
||||
}
|
||||
}
|
||||
|
||||
public void testGlobalDeclaration55() {
|
||||
runFragment(
|
||||
LuaValue.varargsOf(new LuaValue[] {
|
||||
LuaValue.valueOf(7),
|
||||
LuaValue.valueOf(7)
|
||||
}),
|
||||
"global answer = 7\nlocal function f() return answer end\nreturn f(), answer\n");
|
||||
}
|
||||
|
||||
public void testGlobalDeclarationRejectsUndeclaredName() {
|
||||
Globals globals = JsePlatform.debugGlobals();
|
||||
try {
|
||||
switch (TEST_TYPE) {
|
||||
case TEST_TYPE_LUAJC:
|
||||
LuaJC.install(globals);
|
||||
globals.load(new StringReader("global answer = 7\nreturn missing\n"), getName());
|
||||
break;
|
||||
default:
|
||||
globals.compilePrototype(new StringReader("global answer = 7\nreturn missing\n"), getName());
|
||||
break;
|
||||
}
|
||||
fail("expected LuaError");
|
||||
} catch (LuaError e) {
|
||||
assertTrue(e.getMessage().indexOf("is not declared") >= 0);
|
||||
} catch (Exception e) {
|
||||
fail(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public void testGlobalConstRejectsAssignment55() {
|
||||
Globals globals = JsePlatform.debugGlobals();
|
||||
try {
|
||||
switch (TEST_TYPE) {
|
||||
case TEST_TYPE_LUAJC:
|
||||
LuaJC.install(globals);
|
||||
globals.load(new StringReader("global <const> answer = 7\nanswer = 8\n"), getName());
|
||||
break;
|
||||
default:
|
||||
globals.compilePrototype(new StringReader("global <const> answer = 7\nanswer = 8\n"), getName());
|
||||
break;
|
||||
}
|
||||
fail("expected LuaError");
|
||||
} catch (LuaError e) {
|
||||
assertTrue(e.getMessage().indexOf("attempt to assign to const variable") >= 0);
|
||||
} catch (Exception e) {
|
||||
fail(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public void testNamedVarargTable55() {
|
||||
runFragment(
|
||||
LuaValue.varargsOf(new LuaValue[] {
|
||||
LuaValue.valueOf(1),
|
||||
LuaValue.valueOf(2),
|
||||
LuaValue.valueOf(2),
|
||||
LuaValue.valueOf(3),
|
||||
LuaValue.valueOf(2)
|
||||
}),
|
||||
"local function f(a, ...rest)\n" +
|
||||
" return a, rest[1], rest.n, rest[2], select('#', ...)\n" +
|
||||
"end\n" +
|
||||
"return f(1, 2, 3)\n");
|
||||
}
|
||||
|
||||
public void testNamedVarargDumpRoundTrip55() {
|
||||
runFragment(
|
||||
LuaValue.varargsOf(new LuaValue[] {
|
||||
LuaValue.valueOf(2),
|
||||
LuaValue.valueOf(5)
|
||||
}),
|
||||
"local dumped = string.dump(function(...rest) return rest.n, rest[2] end)\n" +
|
||||
"local loaded = assert(load(dumped, 'dumped', 'b'))\n" +
|
||||
"return loaded(4, 5)\n");
|
||||
}
|
||||
|
||||
public void testForLoopVariableRejectsAssignment55() {
|
||||
Globals globals = JsePlatform.debugGlobals();
|
||||
try {
|
||||
switch (TEST_TYPE) {
|
||||
case TEST_TYPE_LUAJC:
|
||||
LuaJC.install(globals);
|
||||
globals.load(new StringReader("for i = 1, 3 do i = 7 end\n"), getName());
|
||||
break;
|
||||
default:
|
||||
globals.compilePrototype(new StringReader("for i = 1, 3 do i = 7 end\n"), getName());
|
||||
break;
|
||||
}
|
||||
fail("expected LuaError");
|
||||
} catch (LuaError e) {
|
||||
assertTrue(e.getMessage().indexOf("attempt to assign to const variable") >= 0);
|
||||
} catch (Exception e) {
|
||||
fail(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public void testCoroutineClose54() {
|
||||
runFragment(
|
||||
LuaValue.varargsOf(new LuaValue[] {
|
||||
@@ -1024,9 +1130,9 @@ public class FragmentsTest extends TestSuite {
|
||||
public void testNumericForUpvalues() {
|
||||
runFragment( LuaValue.valueOf(8),
|
||||
"for i = 3,4 do\n"+
|
||||
" i = i + 5\n"+
|
||||
" local j = i + 5\n"+
|
||||
" local a = function()\n"+
|
||||
" return i\n"+
|
||||
" return j\n"+
|
||||
" end\n" +
|
||||
" return a()\n"+
|
||||
"end\n");
|
||||
|
||||
@@ -83,9 +83,9 @@ public class ScriptEngineTests extends TestSuite {
|
||||
ScriptEngine e = new ScriptEngineManager().getEngineByName("luaj");
|
||||
ScriptEngineFactory f = e.getFactory();
|
||||
assertEquals("Luaj", f.getEngineName());
|
||||
assertEquals("Lua 5.4", f.getEngineVersion());
|
||||
assertEquals("Lua 5.5", f.getEngineVersion());
|
||||
assertEquals("lua", f.getLanguageName());
|
||||
assertEquals("5.4", f.getLanguageVersion());
|
||||
assertEquals("5.5", f.getLanguageVersion());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user