Updated to Lua 5.5
This commit is contained in:
@@ -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) });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user