Started with upgrading to Lua 5.3

This commit is contained in:
UnlegitDqrk
2026-03-01 21:42:19 +01:00
parent 01a8bd944e
commit 493b055a26
32 changed files with 1245 additions and 187 deletions

View File

@@ -237,12 +237,12 @@ public class LoadState {
int e = (int)((bits >> 52) & 0x7ffL) - 1023; int e = (int)((bits >> 52) & 0x7ffL) - 1023;
if ( e >= 0 && e < 31 ) { if ( e >= 0 && e < 63 ) {
long f = bits & 0xFFFFFFFFFFFFFL; long f = bits & 0xFFFFFFFFFFFFFL;
int shift = 52 - e; int shift = 52 - e;
long intPrecMask = ( 1L << shift ) - 1; long intPrecMask = shift > 0 ? ( 1L << shift ) - 1 : 0;
if ( ( f & intPrecMask ) == 0 ) { if ( shift <= 52 && ( f & intPrecMask ) == 0 ) {
int intValue = (int)( f >> shift ) | ( 1 << e ); long intValue = shift >= 0 ? (f >> shift) | (1L << e) : (f << (-shift)) | (1L << e);
return LuaInteger.valueOf( ( ( bits >> 63 ) != 0 ) ? -intValue : intValue ); return LuaInteger.valueOf( ( ( bits >> 63 ) != 0 ) ? -intValue : intValue );
} }
} }

View File

@@ -30,7 +30,7 @@ package org.luaj.vm2;
*/ */
public class Lua { public class Lua {
/** version is supplied by ant build task */ /** version is supplied by ant build task */
public static final String _VERSION = "Luaj 0.0"; public static final String _VERSION = "Lua 5.3";
/** use return values from previous op */ /** use return values from previous op */
public static final int LUA_MULTRET = -1; public static final int LUA_MULTRET = -1;
@@ -201,39 +201,45 @@ public class Lua {
public static final int OP_MUL = 15; /* A B C R(A) := RK(B) * RK(C) */ public static final int OP_MUL = 15; /* A B C R(A) := RK(B) * RK(C) */
public static final int OP_DIV = 16; /* A B C R(A) := RK(B) / RK(C) */ public static final int OP_DIV = 16; /* A B C R(A) := RK(B) / RK(C) */
public static final int OP_IDIV = 17; /* A B C R(A) := RK(B) // RK(C) */ public static final int OP_IDIV = 17; /* A B C R(A) := RK(B) // RK(C) */
public static final int OP_MOD = 18; /* A B C R(A) := RK(B) % RK(C) */ public static final int OP_BAND = 18; /* A B C R(A) := RK(B) & RK(C) */
public static final int OP_POW = 19; /* A B C R(A) := RK(B) ^ RK(C) */ public static final int OP_BOR = 19; /* A B C R(A) := RK(B) | RK(C) */
public static final int OP_UNM = 20; /* A B R(A) := -R(B) */ public static final int OP_BXOR = 20; /* A B C R(A) := RK(B) ~ RK(C) */
public static final int OP_NOT = 21; /* A B R(A) := not R(B) */ public static final int OP_SHL = 21; /* A B C R(A) := RK(B) << RK(C) */
public static final int OP_LEN = 22; /* A B R(A) := length of R(B) */ public static final int OP_SHR = 22; /* A B C R(A) := RK(B) >> RK(C) */
public static final int OP_MOD = 23; /* A B C R(A) := RK(B) % RK(C) */
public static final int OP_POW = 24; /* A B C R(A) := RK(B) ^ RK(C) */
public static final int OP_UNM = 25; /* A B R(A) := -R(B) */
public static final int OP_BNOT = 26; /* A B R(A) := ~R(B) */
public static final int OP_NOT = 27; /* A B R(A) := not R(B) */
public static final int OP_LEN = 28; /* A B R(A) := length of R(B) */
public static final int OP_CONCAT = 23; /* A B C R(A) := R(B).. ... ..R(C) */ public static final int OP_CONCAT = 29; /* A B C R(A) := R(B).. ... ..R(C) */
public static final int OP_JMP = 24; /* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */ public static final int OP_JMP = 30; /* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */
public static final int OP_EQ = 25; /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */ public static final int OP_EQ = 31; /* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
public static final int OP_LT = 26; /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ public static final int OP_LT = 32; /* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
public static final int OP_LE = 27; /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */ public static final int OP_LE = 33; /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
public static final int OP_TEST = 28; /* A C if not (R(A) <=> C) then pc++ */ public static final int OP_TEST = 34; /* A C if not (R(A) <=> C) then pc++ */
public static final int OP_TESTSET = 29; /* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ public static final int OP_TESTSET = 35; /* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */
public static final int OP_CALL = 30; /* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ public static final int OP_CALL = 36; /* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
public static final int OP_TAILCALL = 31; /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ public static final int OP_TAILCALL = 37; /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
public static final int OP_RETURN = 32; /* A B return R(A), ... ,R(A+B-2) (see note) */ public static final int OP_RETURN = 38; /* A B return R(A), ... ,R(A+B-2) (see note) */
public static final int OP_FORLOOP = 33; /* A sBx R(A)+=R(A+2); public static final int OP_FORLOOP = 39; /* A sBx R(A)+=R(A+2);
if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/ if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
public static final int OP_FORPREP = 34; /* A sBx R(A)-=R(A+2); pc+=sBx */ public static final int OP_FORPREP = 40; /* A sBx R(A)-=R(A+2); pc+=sBx */
public static final int OP_TFORCALL = 35; /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */ public static final int OP_TFORCALL = 41; /* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */
public static final int OP_TFORLOOP = 36; /* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx } */ public static final int OP_TFORLOOP = 42; /* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx } */
public static final int OP_SETLIST = 37; /* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */ public static final int OP_SETLIST = 43; /* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */
public static final int OP_CLOSURE = 38; /* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */ public static final int OP_CLOSURE = 44; /* A Bx R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n)) */
public static final int OP_VARARG = 39; /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */ public static final int OP_VARARG = 45; /* A B R(A), R(A+1), ..., R(A+B-1) = vararg */
public static final int OP_EXTRAARG = 40; /* Ax extra (larger) argument for previous opcode */ public static final int OP_EXTRAARG = 46; /* Ax extra (larger) argument for previous opcode */
public static final int NUM_OPCODES = OP_EXTRAARG + 1; public static final int NUM_OPCODES = OP_EXTRAARG + 1;
@@ -299,9 +305,15 @@ public class Lua {
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_MUL */ (0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_MUL */
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_DIV */ (0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_DIV */
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_IDIV */ (0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_IDIV */
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_BAND */
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_BOR */
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_BXOR */
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_SHL */
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_SHR */
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_MOD */ (0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_MOD */
(0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_POW */ (0<<7) | (1<<6) | (OpArgK<<4) | (OpArgK<<2) | (iABC), /* OP_POW */
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iABC), /* OP_UNM */ (0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iABC), /* OP_UNM */
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iABC), /* OP_BNOT */
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iABC), /* OP_NOT */ (0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iABC), /* OP_NOT */
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iABC), /* OP_LEN */ (0<<7) | (1<<6) | (OpArgR<<4) | (OpArgN<<2) | (iABC), /* OP_LEN */
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgR<<2) | (iABC), /* OP_CONCAT */ (0<<7) | (1<<6) | (OpArgR<<4) | (OpArgR<<2) | (iABC), /* OP_CONCAT */

View File

@@ -352,6 +352,26 @@ public class LuaClosure extends LuaFunction {
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).idiv((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).idiv((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
continue; continue;
case Lua.OP_BAND: /* A B C R(A):= RK(B) & RK(C) */
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).band((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
continue;
case Lua.OP_BOR: /* A B C R(A):= RK(B) | RK(C) */
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).bor((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
continue;
case Lua.OP_BXOR: /* A B C R(A):= RK(B) ~ RK(C) */
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).bxor((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
continue;
case Lua.OP_SHL: /* A B C R(A):= RK(B) << RK(C) */
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).shl((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
continue;
case Lua.OP_SHR: /* A B C R(A):= RK(B) >> RK(C) */
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).shr((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
continue;
case Lua.OP_MOD: /* A B C R(A):= RK(B) % RK(C) */ case Lua.OP_MOD: /* A B C R(A):= RK(B) % RK(C) */
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).mod((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]); stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).mod((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
continue; continue;
@@ -364,6 +384,10 @@ public class LuaClosure extends LuaFunction {
stack[a] = stack[i>>>23].neg(); stack[a] = stack[i>>>23].neg();
continue; continue;
case Lua.OP_BNOT: /* A B R(A):= ~R(B) */
stack[a] = stack[i>>>23].bnot();
continue;
case Lua.OP_NOT: /* A B R(A):= not R(B) */ case Lua.OP_NOT: /* A B R(A):= not R(B) */
stack[a] = stack[i>>>23].not(); stack[a] = stack[i>>>23].not();
continue; continue;

View File

@@ -75,8 +75,13 @@ public class LuaDouble extends LuaNumber {
final double v; final double v;
public static LuaNumber valueOf(double d) { public static LuaNumber valueOf(double d) {
int id = (int) d; if (!Double.isNaN(d) && !Double.isInfinite(d) && d >= Long.MIN_VALUE && d <= Long.MAX_VALUE) {
return d==id? (LuaNumber) LuaInteger.valueOf(id): (LuaNumber) new LuaDouble(d); long ld = (long) d;
if (d == ld) {
return LuaInteger.valueOf(ld);
}
}
return new LuaDouble(d);
} }
/** Don't allow ints to be boxed by DoubleValues */ /** Don't allow ints to be boxed by DoubleValues */
@@ -103,13 +108,14 @@ public class LuaDouble extends LuaNumber {
public double optdouble(double defval) { return v; } public double optdouble(double defval) { return v; }
public int optint(int defval) { return (int) (long) v; } public int optint(int defval) { return (int) (long) v; }
public LuaInteger optinteger(LuaInteger defval) { return LuaInteger.valueOf((int) (long)v); } public LuaInteger optinteger(LuaInteger defval) { return islong()? LuaInteger.valueOf((long) v): defval; }
public long optlong(long defval) { return (long) v; } public long optlong(long defval) { return (long) v; }
public LuaInteger checkinteger() { return LuaInteger.valueOf( (int) (long) v ); } public LuaInteger checkinteger() { if (!islong()) argerror("integer"); return LuaInteger.valueOf((long) v); }
// unary operators // unary operators
public LuaValue neg() { return valueOf(-v); } public LuaValue neg() { return valueOf(-v); }
public LuaValue bnot() { if (!islong()) throw new LuaError("number has no integer representation"); return LuaInteger.valueOf(~((long) v)); }
// object equality, used for key comparison // object equality, used for key comparison
public boolean equals(Object o) { return o instanceof LuaDouble? ((LuaDouble)o).v == v: false; } public boolean equals(Object o) { return o instanceof LuaDouble? ((LuaDouble)o).v == v: false; }
@@ -122,6 +128,7 @@ public class LuaDouble extends LuaNumber {
public boolean raweq( LuaValue val ) { return val.raweq(v); } public boolean raweq( LuaValue val ) { return val.raweq(v); }
public boolean raweq( double val ) { return v == val; } public boolean raweq( double val ) { return v == val; }
public boolean raweq( int val ) { return v == val; } public boolean raweq( int val ) { return v == val; }
public boolean raweq( long val ) { return v == val; }
// basic binary arithmetic // basic binary arithmetic
public LuaValue add( LuaValue rhs ) { return rhs.add(v); } public LuaValue add( LuaValue rhs ) { return rhs.add(v); }
@@ -146,6 +153,11 @@ public class LuaDouble extends LuaNumber {
public LuaValue idiv( double rhs ) { return LuaDouble.didiv(v,rhs); } public LuaValue idiv( double rhs ) { return LuaDouble.didiv(v,rhs); }
public LuaValue idiv( int rhs ) { return LuaDouble.didiv(v,rhs); } public LuaValue idiv( int rhs ) { return LuaDouble.didiv(v,rhs); }
public LuaValue idivInto( double lhs ) { return LuaDouble.didiv(lhs,v); } public LuaValue idivInto( double lhs ) { return LuaDouble.didiv(lhs,v); }
public LuaValue band( LuaValue rhs ) { if (!islong()) throw new LuaError("number has no integer representation"); LuaValue n = rhs.tonumber(); if (n.isnil()) return super.band(rhs); if (!n.islong()) throw new LuaError("number has no integer representation"); return LuaInteger.valueOf(((long) v) & n.tolong()); }
public LuaValue bor( LuaValue rhs ) { if (!islong()) throw new LuaError("number has no integer representation"); LuaValue n = rhs.tonumber(); if (n.isnil()) return super.bor(rhs); if (!n.islong()) throw new LuaError("number has no integer representation"); return LuaInteger.valueOf(((long) v) | n.tolong()); }
public LuaValue bxor( LuaValue rhs ) { if (!islong()) throw new LuaError("number has no integer representation"); LuaValue n = rhs.tonumber(); if (n.isnil()) return super.bxor(rhs); if (!n.islong()) throw new LuaError("number has no integer representation"); return LuaInteger.valueOf(((long) v) ^ n.tolong()); }
public LuaValue shl( LuaValue rhs ) { if (!islong()) throw new LuaError("number has no integer representation"); LuaValue n = rhs.tonumber(); if (n.isnil()) return super.shl(rhs); if (!n.islong()) throw new LuaError("number has no integer representation"); return LuaInteger.valueOf(LuaInteger.luaShiftLeft((long) v, n.tolong())); }
public LuaValue shr( LuaValue rhs ) { if (!islong()) throw new LuaError("number has no integer representation"); LuaValue n = rhs.tonumber(); if (n.isnil()) return super.shr(rhs); if (!n.islong()) throw new LuaError("number has no integer representation"); return LuaInteger.valueOf(LuaInteger.luaShiftRight((long) v, n.tolong())); }
public LuaValue mod( LuaValue rhs ) { return rhs.modFrom(v); } public LuaValue mod( LuaValue rhs ) { return rhs.modFrom(v); }
public LuaValue mod( double rhs ) { return LuaDouble.dmod(v,rhs); } public LuaValue mod( double rhs ) { return LuaDouble.dmod(v,rhs); }
public LuaValue mod( int rhs ) { return LuaDouble.dmod(v,rhs); } public LuaValue mod( int rhs ) { return LuaDouble.dmod(v,rhs); }

View File

@@ -24,7 +24,7 @@ package org.luaj.vm2;
import org.luaj.vm2.libs.MathLib; import org.luaj.vm2.libs.MathLib;
/** /**
* Extension of {@link LuaNumber} which can hold a Java int as its value. * Extension of {@link LuaNumber} which can hold a Java long as its value.
* <p> * <p>
* 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)} * via the static functions {@link LuaValue#valueOf(int)} or {@link LuaValue#valueOf(double)}
@@ -59,25 +59,23 @@ public class LuaInteger extends LuaNumber {
* @see LuaValue#valueOf(int) * @see LuaValue#valueOf(int)
* @see LuaValue#valueOf(double) * @see LuaValue#valueOf(double)
*/ */
public static LuaNumber valueOf(long l) { public static LuaInteger valueOf(long l) {
int i = (int) l; int i = (int) l;
return l==i? (i<=255 && i>=-256? intValues[i+256]: return l == i && i <= 255 && i >= -256 ? intValues[i+256] : new LuaInteger(l);
(LuaNumber) new LuaInteger(i)):
(LuaNumber) LuaDouble.valueOf(l);
} }
/** The value being held by this instance. */ /** The value being held by this instance. */
public final int v; public final long v;
/** /**
* Package protected constructor. * Package protected constructor.
* @see LuaValue#valueOf(int) * @see LuaValue#valueOf(int)
**/ **/
LuaInteger(int i) { LuaInteger(long i) {
this.v = i; this.v = i;
} }
public boolean isint() { return true; } public boolean isint() { return v == (int) v; }
public boolean isinttype() { return true; } public boolean isinttype() { return true; }
public boolean islong() { return true; } public boolean islong() { return true; }
@@ -85,33 +83,33 @@ public class LuaInteger extends LuaNumber {
public char tochar() { return (char) v; } public char tochar() { return (char) v; }
public double todouble() { return v; } public double todouble() { return v; }
public float tofloat() { return v; } public float tofloat() { return v; }
public int toint() { return v; } public int toint() { return (int) v; }
public long tolong() { return v; } public long tolong() { return v; }
public short toshort() { return (short) v; } public short toshort() { return (short) v; }
public double optdouble(double defval) { return v; } public double optdouble(double defval) { return v; }
public int optint(int defval) { return v; } public int optint(int defval) { return (int) v; }
public LuaInteger optinteger(LuaInteger defval) { return this; } public LuaInteger optinteger(LuaInteger defval) { return this; }
public long optlong(long defval) { return v; } public long optlong(long defval) { return v; }
public String tojstring() { public String tojstring() {
return Integer.toString(v); return Long.toString(v);
} }
public LuaString strvalue() { public LuaString strvalue() {
return LuaString.valueOf(Integer.toString(v)); return LuaString.valueOf(Long.toString(v));
} }
public LuaString optstring(LuaString defval) { public LuaString optstring(LuaString defval) {
return LuaString.valueOf(Integer.toString(v)); return LuaString.valueOf(Long.toString(v));
} }
public LuaValue tostring() { public LuaValue tostring() {
return LuaString.valueOf(Integer.toString(v)); return LuaString.valueOf(Long.toString(v));
} }
public String optjstring(String defval) { public String optjstring(String defval) {
return Integer.toString(v); return Long.toString(v);
} }
public LuaInteger checkinteger() { public LuaInteger checkinteger() {
@@ -123,15 +121,16 @@ public class LuaInteger extends LuaNumber {
} }
public int hashCode() { public int hashCode() {
return v; return hashCode(v);
} }
public static int hashCode(int x) { public static int hashCode(long x) {
return x; return (int) (x ^ (x >>> 32));
} }
// unary operators // unary operators
public LuaValue neg() { return valueOf(-(long)v); } public LuaValue neg() { return valueOf(-(long)v); }
public LuaValue bnot() { return valueOf(~v); }
// object equality, used for key comparison // object equality, used for key comparison
public boolean equals(Object o) { return o instanceof LuaInteger? ((LuaInteger)o).v == v: false; } public boolean equals(Object o) { return o instanceof LuaInteger? ((LuaInteger)o).v == v: false; }
@@ -144,60 +143,66 @@ public class LuaInteger extends LuaNumber {
public boolean raweq( LuaValue val ) { return val.raweq(v); } public boolean raweq( LuaValue val ) { return val.raweq(v); }
public boolean raweq( double val ) { return v == val; } public boolean raweq( double val ) { return v == val; }
public boolean raweq( int val ) { return v == val; } public boolean raweq( int val ) { return v == val; }
public boolean raweq( long val ) { return v == val; }
// arithmetic operators // arithmetic operators
public LuaValue add( LuaValue rhs ) { return rhs.add(v); } public LuaValue add( LuaValue rhs ) { LuaValue n = rhs.tonumber(); return n.isnil()? super.add(rhs): (n.isinttype()? LuaInteger.valueOf(v + n.tolong()): LuaDouble.valueOf(v + n.todouble())); }
public LuaValue add( double lhs ) { return LuaDouble.valueOf(lhs + v); } public LuaValue add( double lhs ) { return LuaDouble.valueOf(lhs + v); }
public LuaValue add( int lhs ) { return LuaInteger.valueOf(lhs + (long)v); } public LuaValue add( int lhs ) { return LuaInteger.valueOf(lhs + v); }
public LuaValue sub( LuaValue rhs ) { return rhs.subFrom(v); } public LuaValue sub( LuaValue rhs ) { LuaValue n = rhs.tonumber(); return n.isnil()? super.sub(rhs): (n.isinttype()? LuaInteger.valueOf(v - n.tolong()): LuaDouble.valueOf(v - n.todouble())); }
public LuaValue sub( double rhs ) { return LuaDouble.valueOf(v - rhs); } public LuaValue sub( double rhs ) { return LuaDouble.valueOf(v - rhs); }
public LuaValue sub( int rhs ) { return LuaDouble.valueOf(v - rhs); } public LuaValue sub( int rhs ) { return LuaInteger.valueOf(v - rhs); }
public LuaValue subFrom( double lhs ) { return LuaDouble.valueOf(lhs - v); } public LuaValue subFrom( double lhs ) { return LuaDouble.valueOf(lhs - v); }
public LuaValue subFrom( int lhs ) { return LuaInteger.valueOf(lhs - (long)v); } public LuaValue subFrom( int lhs ) { return LuaInteger.valueOf(lhs - v); }
public LuaValue mul( LuaValue rhs ) { return rhs.mul(v); } public LuaValue mul( LuaValue rhs ) { LuaValue n = rhs.tonumber(); return n.isnil()? super.mul(rhs): (n.isinttype()? LuaInteger.valueOf(v * n.tolong()): LuaDouble.valueOf(v * n.todouble())); }
public LuaValue mul( double lhs ) { return LuaDouble.valueOf(lhs * v); } public LuaValue mul( double lhs ) { return LuaDouble.valueOf(lhs * v); }
public LuaValue mul( int lhs ) { return LuaInteger.valueOf(lhs * (long)v); } public LuaValue mul( int lhs ) { return LuaInteger.valueOf(lhs * v); }
public LuaValue pow( LuaValue rhs ) { return rhs.powWith(v); } public LuaValue pow( LuaValue rhs ) { LuaValue n = rhs.tonumber(); return n.isnil()? super.pow(rhs): MathLib.dpow(v, n.todouble()); }
public LuaValue pow( double rhs ) { return MathLib.dpow(v,rhs); } public LuaValue pow( double rhs ) { return MathLib.dpow(v,rhs); }
public LuaValue pow( int rhs ) { return MathLib.dpow(v,rhs); } public LuaValue pow( int rhs ) { return MathLib.dpow(v,rhs); }
public LuaValue powWith( double lhs ) { return MathLib.dpow(lhs,v); } public LuaValue powWith( double lhs ) { return MathLib.dpow(lhs,v); }
public LuaValue powWith( int lhs ) { return MathLib.dpow(lhs,v); } public LuaValue powWith( int lhs ) { return MathLib.dpow(lhs,v); }
public LuaValue div( LuaValue rhs ) { return rhs.divInto(v); } public LuaValue div( LuaValue rhs ) { LuaValue n = rhs.tonumber(); return n.isnil()? super.div(rhs): LuaDouble.ddiv(v, n.todouble()); }
public LuaValue idiv( LuaValue rhs ) { return rhs.idivInto(v); } public LuaValue idiv( LuaValue rhs ) { LuaValue n = rhs.tonumber(); return n.isnil()? super.idiv(rhs): (n.isinttype()? LuaInteger.valueOf(luaFloorDiv(v, n.tolong())): LuaDouble.didiv(v, n.todouble())); }
public LuaValue div( double rhs ) { return LuaDouble.ddiv(v,rhs); } public LuaValue div( double rhs ) { return LuaDouble.ddiv(v,rhs); }
public LuaValue div( int rhs ) { return LuaDouble.ddiv(v,rhs); } public LuaValue div( int rhs ) { return LuaDouble.ddiv(v,rhs); }
public LuaValue divInto( double lhs ) { return LuaDouble.ddiv(lhs,v); } public LuaValue divInto( double lhs ) { return LuaDouble.ddiv(lhs,v); }
public LuaValue idiv( double rhs ) { return LuaDouble.didiv(v,rhs); } public LuaValue idiv( double rhs ) { return LuaDouble.didiv(v,rhs); }
public LuaValue idiv( int rhs ) { return LuaDouble.didiv(v,rhs); } public LuaValue idiv( int rhs ) { return LuaInteger.valueOf(luaFloorDiv(v, rhs)); }
public LuaValue idivInto( double lhs ) { return LuaDouble.didiv(lhs,v); } public LuaValue idivInto( double lhs ) { return LuaDouble.didiv(lhs,v); }
public LuaValue mod( LuaValue rhs ) { return rhs.modFrom(v); } public LuaValue band( LuaValue rhs ) { LuaValue n = rhs.tonumber(); if (n.isnil()) return super.band(rhs); if (!n.islong()) throw bitwiseError(); return LuaInteger.valueOf(v & n.tolong()); }
public LuaValue bor( LuaValue rhs ) { LuaValue n = rhs.tonumber(); if (n.isnil()) return super.bor(rhs); if (!n.islong()) throw bitwiseError(); return LuaInteger.valueOf(v | n.tolong()); }
public LuaValue bxor( LuaValue rhs ) { LuaValue n = rhs.tonumber(); if (n.isnil()) return super.bxor(rhs); if (!n.islong()) throw bitwiseError(); return LuaInteger.valueOf(v ^ n.tolong()); }
public LuaValue shl( LuaValue rhs ) { LuaValue n = rhs.tonumber(); if (n.isnil()) return super.shl(rhs); if (!n.islong()) throw bitwiseError(); return LuaInteger.valueOf(luaShiftLeft(v, n.tolong())); }
public LuaValue shr( LuaValue rhs ) { LuaValue n = rhs.tonumber(); if (n.isnil()) return super.shr(rhs); if (!n.islong()) throw bitwiseError(); return LuaInteger.valueOf(luaShiftRight(v, n.tolong())); }
public LuaValue mod( LuaValue rhs ) { LuaValue n = rhs.tonumber(); return n.isnil()? super.mod(rhs): (n.isinttype()? LuaInteger.valueOf(luaFloorMod(v, n.tolong())): LuaDouble.dmod(v, n.todouble())); }
public LuaValue mod( double rhs ) { return LuaDouble.dmod(v,rhs); } public LuaValue mod( double rhs ) { return LuaDouble.dmod(v,rhs); }
public LuaValue mod( int rhs ) { return LuaDouble.dmod(v,rhs); } public LuaValue mod( int rhs ) { return LuaInteger.valueOf(luaFloorMod(v, rhs)); }
public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs,v); } public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs,v); }
// relational operators // relational operators
public LuaValue lt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gt_b(v)? TRUE: FALSE) : super.lt(rhs); } public LuaValue lt( LuaValue rhs ) { LuaValue n = rhs.tonumber(); return n.isnil()? super.lt(rhs): (n.isinttype()? (v < n.tolong()? TRUE: FALSE): (v < n.todouble()? TRUE: FALSE)); }
public LuaValue lt( double rhs ) { return v < rhs? TRUE: FALSE; } public LuaValue lt( double rhs ) { return v < rhs? TRUE: FALSE; }
public LuaValue lt( int rhs ) { return v < rhs? TRUE: FALSE; } public LuaValue lt( int rhs ) { return v < rhs? TRUE: FALSE; }
public boolean lt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gt_b(v) : super.lt_b(rhs); } public boolean lt_b( LuaValue rhs ) { LuaValue n = rhs.tonumber(); return n.isnil()? super.lt_b(rhs): (n.isinttype()? v < n.tolong(): v < n.todouble()); }
public boolean lt_b( int rhs ) { return v < rhs; } public boolean lt_b( int rhs ) { return v < rhs; }
public boolean lt_b( double rhs ) { return v < rhs; } public boolean lt_b( double rhs ) { return v < rhs; }
public LuaValue lteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gteq_b(v)? TRUE: FALSE) : super.lteq(rhs); } public LuaValue lteq( LuaValue rhs ) { LuaValue n = rhs.tonumber(); return n.isnil()? super.lteq(rhs): (n.isinttype()? (v <= n.tolong()? TRUE: FALSE): (v <= n.todouble()? TRUE: FALSE)); }
public LuaValue lteq( double rhs ) { return v <= rhs? TRUE: FALSE; } public LuaValue lteq( double rhs ) { return v <= rhs? TRUE: FALSE; }
public LuaValue lteq( int rhs ) { return v <= rhs? TRUE: FALSE; } public LuaValue lteq( int rhs ) { return v <= rhs? TRUE: FALSE; }
public boolean lteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gteq_b(v) : super.lteq_b(rhs); } public boolean lteq_b( LuaValue rhs ) { LuaValue n = rhs.tonumber(); return n.isnil()? super.lteq_b(rhs): (n.isinttype()? v <= n.tolong(): v <= n.todouble()); }
public boolean lteq_b( int rhs ) { return v <= rhs; } public boolean lteq_b( int rhs ) { return v <= rhs; }
public boolean lteq_b( double rhs ) { return v <= rhs; } public boolean lteq_b( double rhs ) { return v <= rhs; }
public LuaValue gt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lt_b(v)? TRUE: FALSE) : super.gt(rhs); } public LuaValue gt( LuaValue rhs ) { LuaValue n = rhs.tonumber(); return n.isnil()? super.gt(rhs): (n.isinttype()? (v > n.tolong()? TRUE: FALSE): (v > n.todouble()? TRUE: FALSE)); }
public LuaValue gt( double rhs ) { return v > rhs? TRUE: FALSE; } public LuaValue gt( double rhs ) { return v > rhs? TRUE: FALSE; }
public LuaValue gt( int rhs ) { return v > rhs? TRUE: FALSE; } public LuaValue gt( int rhs ) { return v > rhs? TRUE: FALSE; }
public boolean gt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lt_b(v) : super.gt_b(rhs); } public boolean gt_b( LuaValue rhs ) { LuaValue n = rhs.tonumber(); return n.isnil()? super.gt_b(rhs): (n.isinttype()? v > n.tolong(): v > n.todouble()); }
public boolean gt_b( int rhs ) { return v > rhs; } public boolean gt_b( int rhs ) { return v > rhs; }
public boolean gt_b( double rhs ) { return v > rhs; } public boolean gt_b( double rhs ) { return v > rhs; }
public LuaValue gteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lteq_b(v)? TRUE: FALSE) : super.gteq(rhs); } public LuaValue gteq( LuaValue rhs ) { LuaValue n = rhs.tonumber(); return n.isnil()? super.gteq(rhs): (n.isinttype()? (v >= n.tolong()? TRUE: FALSE): (v >= n.todouble()? TRUE: FALSE)); }
public LuaValue gteq( double rhs ) { return v >= rhs? TRUE: FALSE; } public LuaValue gteq( double rhs ) { return v >= rhs? TRUE: FALSE; }
public LuaValue gteq( int rhs ) { return v >= rhs? TRUE: FALSE; } public LuaValue gteq( int rhs ) { return v >= rhs? TRUE: FALSE; }
public boolean gteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lteq_b(v) : super.gteq_b(rhs); } public boolean gteq_b( LuaValue rhs ) { LuaValue n = rhs.tonumber(); return n.isnil()? super.gteq_b(rhs): (n.isinttype()? v >= n.tolong(): v >= n.todouble()); }
public boolean gteq_b( int rhs ) { return v >= rhs; } public boolean gteq_b( int rhs ) { return v >= rhs; }
public boolean gteq_b( double rhs ) { return v >= rhs; } public boolean gteq_b( double rhs ) { return v >= rhs; }
@@ -205,7 +210,7 @@ public class LuaInteger extends LuaNumber {
public int strcmp( LuaString rhs ) { typerror("attempt to compare number with string"); return 0; } public int strcmp( LuaString rhs ) { typerror("attempt to compare number with string"); return 0; }
public int checkint() { public int checkint() {
return v; return (int) v;
} }
public long checklong() { public long checklong() {
return v; return v;
@@ -220,4 +225,41 @@ public class LuaInteger extends LuaNumber {
return valueOf( String.valueOf(v) ); return valueOf( String.valueOf(v) );
} }
private static long luaFloorDiv(long lhs, long rhs) {
if (rhs == 0) {
throw new LuaError("attempt to divide by zero");
}
long quotient = lhs / rhs;
long remainder = lhs % rhs;
if (remainder != 0 && ((lhs ^ rhs) < 0)) {
quotient--;
}
return quotient;
}
private static long luaFloorMod(long lhs, long rhs) {
if (rhs == 0) {
throw new LuaError("attempt to divide by zero");
}
return lhs - rhs * luaFloorDiv(lhs, rhs);
}
static long luaShiftLeft(long lhs, long rhs) {
if (rhs < 0) {
return luaShiftRight(lhs, -rhs);
}
return rhs >= Long.SIZE ? 0L : lhs << rhs;
}
static long luaShiftRight(long lhs, long rhs) {
if (rhs < 0) {
return luaShiftLeft(lhs, -rhs);
}
return rhs >= Long.SIZE ? 0L : lhs >>> rhs;
}
private static LuaError bitwiseError() {
return new LuaError("number has no integer representation");
}
} }

View File

@@ -262,6 +262,7 @@ public class LuaString extends LuaValue {
// unary operators // unary operators
public LuaValue neg() { double d = scannumber(); return Double.isNaN(d)? super.neg(): valueOf(-d); } public LuaValue neg() { double d = scannumber(); return Double.isNaN(d)? super.neg(): valueOf(-d); }
public LuaValue bnot() { double d = scannumber(); if (Double.isNaN(d)) return super.bnot(); if (d != (long) d) throw new LuaError("number has no integer representation"); return LuaInteger.valueOf(~((long) d)); }
// basic binary arithmetic // basic binary arithmetic
public LuaValue add( LuaValue rhs ) { double d = scannumber(); return Double.isNaN(d)? arithmt(ADD,rhs): rhs.add(d); } public LuaValue add( LuaValue rhs ) { double d = scannumber(); return Double.isNaN(d)? arithmt(ADD,rhs): rhs.add(d); }
@@ -287,6 +288,11 @@ public class LuaString extends LuaValue {
public LuaValue idiv( double rhs ) { return LuaDouble.didiv(checkarith(),rhs); } public LuaValue idiv( double rhs ) { return LuaDouble.didiv(checkarith(),rhs); }
public LuaValue idiv( int rhs ) { return LuaDouble.didiv(checkarith(),rhs); } public LuaValue idiv( int rhs ) { return LuaDouble.didiv(checkarith(),rhs); }
public LuaValue idivInto( double lhs ) { return LuaDouble.didiv(lhs, checkarith()); } public LuaValue idivInto( double lhs ) { return LuaDouble.didiv(lhs, checkarith()); }
public LuaValue band( LuaValue rhs ) { double d = scannumber(); if (Double.isNaN(d)) return super.band(rhs); if (d != (long) d) throw new LuaError("number has no integer representation"); LuaValue n = rhs.tonumber(); if (n.isnil()) return super.band(rhs); if (!n.islong()) throw new LuaError("number has no integer representation"); return LuaInteger.valueOf(((long) d) & n.tolong()); }
public LuaValue bor( LuaValue rhs ) { double d = scannumber(); if (Double.isNaN(d)) return super.bor(rhs); if (d != (long) d) throw new LuaError("number has no integer representation"); LuaValue n = rhs.tonumber(); if (n.isnil()) return super.bor(rhs); if (!n.islong()) throw new LuaError("number has no integer representation"); return LuaInteger.valueOf(((long) d) | n.tolong()); }
public LuaValue bxor( LuaValue rhs ) { double d = scannumber(); if (Double.isNaN(d)) return super.bxor(rhs); if (d != (long) d) throw new LuaError("number has no integer representation"); LuaValue n = rhs.tonumber(); if (n.isnil()) return super.bxor(rhs); if (!n.islong()) throw new LuaError("number has no integer representation"); return LuaInteger.valueOf(((long) d) ^ n.tolong()); }
public LuaValue shl( LuaValue rhs ) { double d = scannumber(); if (Double.isNaN(d)) return super.shl(rhs); if (d != (long) d) throw new LuaError("number has no integer representation"); LuaValue n = rhs.tonumber(); if (n.isnil()) return super.shl(rhs); if (!n.islong()) throw new LuaError("number has no integer representation"); return LuaInteger.valueOf(LuaInteger.luaShiftLeft((long) d, n.tolong())); }
public LuaValue shr( LuaValue rhs ) { double d = scannumber(); if (Double.isNaN(d)) return super.shr(rhs); if (d != (long) d) throw new LuaError("number has no integer representation"); LuaValue n = rhs.tonumber(); if (n.isnil()) return super.shr(rhs); if (!n.islong()) throw new LuaError("number has no integer representation"); return LuaInteger.valueOf(LuaInteger.luaShiftRight((long) d, n.tolong())); }
public LuaValue mod( LuaValue rhs ) { double d = scannumber(); return Double.isNaN(d)? arithmt(MOD,rhs): rhs.modFrom(d); } public LuaValue mod( LuaValue rhs ) { double d = scannumber(); return Double.isNaN(d)? arithmt(MOD,rhs): rhs.modFrom(d); }
public LuaValue mod( double rhs ) { return LuaDouble.dmod(checkarith(), rhs); } public LuaValue mod( double rhs ) { return LuaDouble.dmod(checkarith(), rhs); }
public LuaValue mod( int rhs ) { return LuaDouble.dmod(checkarith(), rhs); } public LuaValue mod( int rhs ) { return LuaDouble.dmod(checkarith(), rhs); }
@@ -344,10 +350,16 @@ public class LuaString extends LuaValue {
return (int) (long) checkdouble(); return (int) (long) checkdouble();
} }
public LuaInteger checkinteger() { public LuaInteger checkinteger() {
return valueOf(checkint()); double d = scannumber();
if (Double.isNaN(d) || d != (long) d)
argerror("integer");
return LuaInteger.valueOf((long) d);
} }
public long checklong() { public long checklong() {
return (long) checkdouble(); double d = scannumber();
if (Double.isNaN(d) || d != (long) d)
argerror("integer");
return (long) d;
} }
public double checkdouble() { public double checkdouble() {
double d = scannumber(); double d = scannumber();
@@ -765,8 +777,11 @@ public class LuaString extends LuaValue {
while ( i<j && m_bytes[j-1]==' ' ) --j; while ( i<j && m_bytes[j-1]==' ' ) --j;
if ( i>=j ) if ( i>=j )
return Double.NaN; return Double.NaN;
if ( m_bytes[i]=='0' && i+1<j && (m_bytes[i+1]=='x'||m_bytes[i+1]=='X')) int prefix = (m_bytes[i] == '+' || m_bytes[i] == '-') ? i + 1 : i;
return scanlong(16, i+2, j); if (prefix + 1 < j && m_bytes[prefix]=='0' && (m_bytes[prefix+1]=='x'||m_bytes[prefix+1]=='X')) {
double l = scanlong(16, prefix + 2, j, i != prefix);
return Double.isNaN(l)? scandouble(i,j): l;
}
double l = scanlong(10, i, j); double l = scanlong(10, i, j);
return Double.isNaN(l)? scandouble(i,j): l; return Double.isNaN(l)? scandouble(i,j): l;
} }
@@ -796,14 +811,15 @@ public class LuaString extends LuaValue {
* or Double.NaN if not * or Double.NaN if not
*/ */
private double scanlong( int base, int start, int end ) { private double scanlong( int base, int start, int end ) {
return scanlong(base, start, end, false);
}
private double scanlong( int base, int start, int end, boolean hasSign ) {
long x = 0; long x = 0;
boolean neg = (m_bytes[start] == '-'); boolean neg = hasSign && m_bytes[start - 1] == '-';
// --- fix starts here --- if (start >= end)
if(neg && m_bytes.length == 1) { return Double.NaN;
return Double.NaN; // this is only a '-' sign, no parsing any number is required for ( int i=start; i<end; i++ ) {
}
// --- fix ends here ---
for ( int i=(neg?start+1:start); i<end; i++ ) {
int digit = m_bytes[i] - (base<=10||(m_bytes[i]>='0'&&m_bytes[i]<='9')? '0': 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)); m_bytes[i]>='A'&&m_bytes[i]<='Z'? ('A'-10): ('a'-10));
if ( digit < 0 || digit >= base ) if ( digit < 0 || digit >= base )

View File

@@ -236,7 +236,7 @@ public class LuaTable extends LuaValue implements Metatable {
} }
public LuaValue rawget( LuaValue key ) { public LuaValue rawget( LuaValue key ) {
if ( key.isinttype() ) { if ( key.isint() ) {
int ikey = key.toint(); int ikey = key.toint();
if ( ikey>0 && ikey<=array.length ) { if ( ikey>0 && ikey<=array.length ) {
LuaValue v = m_metatable == null LuaValue v = m_metatable == null
@@ -279,7 +279,7 @@ public class LuaTable extends LuaValue implements Metatable {
/** caller must ensure key is not nil */ /** caller must ensure key is not nil */
public void rawset( LuaValue key, LuaValue value ) { public void rawset( LuaValue key, LuaValue value ) {
if ( !key.isinttype() || !arrayset(key.toint(), value) ) if ( !key.isint() || !arrayset(key.toint(), value) )
hashset( key, value ); hashset( key, value );
} }
@@ -388,7 +388,7 @@ public class LuaTable extends LuaValue implements Metatable {
do { do {
// find current key index // find current key index
if ( ! key.isnil() ) { if ( ! key.isnil() ) {
if ( key.isinttype() ) { if ( key.isint() ) {
i = key.toint(); i = key.toint();
if ( i>0 && i<=array.length ) { if ( i>0 && i<=array.length ) {
break; break;
@@ -473,7 +473,7 @@ public class LuaTable extends LuaValue implements Metatable {
} }
if ( checkLoadFactor() ) { if ( checkLoadFactor() ) {
if ( (m_metatable == null || !m_metatable.useWeakValues()) if ( (m_metatable == null || !m_metatable.useWeakValues())
&& key.isinttype() && key.toint() > 0 ) { && key.isint() && key.toint() > 0 ) {
// a rehash might make room in the array portion for this key. // a rehash might make room in the array portion for this key.
rehash( key.toint() ); rehash( key.toint() );
if ( arrayset(key.toint(), value) ) if ( arrayset(key.toint(), value) )
@@ -767,9 +767,9 @@ public class LuaTable extends LuaValue implements Metatable {
} }
protected static Entry defaultEntry(LuaValue key, LuaValue value) { protected static Entry defaultEntry(LuaValue key, LuaValue value) {
if ( key.isinttype() ) { if ( key.isint() ) {
return new IntKeyEntry( key.toint(), value ); return new IntKeyEntry( key.toint(), value );
} else if (value.type() == TNUMBER) { } else if (value.type() == TNUMBER && !value.isinttype()) {
return new NumberValueEntry( key, value.todouble() ); return new NumberValueEntry( key, value.todouble() );
} else { } else {
return new NormalEntry( key, value ); return new NormalEntry( key, value );

View File

@@ -216,6 +216,24 @@ public class LuaValue extends Varargs {
/** LuaString constant with value "__idiv" for use as metatag */ /** LuaString constant with value "__idiv" for use as metatag */
public static final LuaString IDIV = valueOf("__idiv"); public static final LuaString IDIV = valueOf("__idiv");
/** LuaString constant with value "__band" for use as metatag */
public static final LuaString BAND = valueOf("__band");
/** LuaString constant with value "__bor" for use as metatag */
public static final LuaString BOR = valueOf("__bor");
/** LuaString constant with value "__bxor" for use as metatag */
public static final LuaString BXOR = valueOf("__bxor");
/** LuaString constant with value "__shl" for use as metatag */
public static final LuaString SHL = valueOf("__shl");
/** LuaString constant with value "__shr" for use as metatag */
public static final LuaString SHR = valueOf("__shr");
/** LuaString constant with value "__bnot" for use as metatag */
public static final LuaString BNOT = valueOf("__bnot");
/** LuaString constant with value "__mul" for use as metatag */ /** LuaString constant with value "__mul" for use as metatag */
public static final LuaString MUL = valueOf("__mul"); public static final LuaString MUL = valueOf("__mul");
@@ -2010,6 +2028,13 @@ public class LuaValue extends Varargs {
* @throws LuaError if {@code this} is not a table or string, and has no {@link #UNM} metatag * @throws LuaError if {@code this} is not a table or string, and has no {@link #UNM} metatag
*/ */
public LuaValue neg() { return checkmetatag(UNM, "attempt to perform arithmetic on ").call(this); } public LuaValue neg() { return checkmetatag(UNM, "attempt to perform arithmetic on ").call(this); }
/** Unary bitwise not: return bitwise inverse value {@code (~this)}.
* @return numeric inverse as {@link LuaNumber} if integer-coercible,
* or metatag processing result if {@link #BNOT} metatag is defined
* @throws LuaError if {@code this} cannot be represented as an integer
*/
public LuaValue bnot() { return checkmetatag(BNOT, "attempt to perform bitwise operation on ").call(this); }
/** Length operator: return lua length of object {@code (#this)} including metatag processing as java int /** Length operator: return lua length of object {@code (#this)} including metatag processing as java int
* @return length as defined by the lua # operator * @return length as defined by the lua # operator
@@ -2141,6 +2166,15 @@ public class LuaValue extends Varargs {
*/ */
public boolean raweq( int val ) { return false; } public boolean raweq( int val ) { return false; }
/** Equals: Perform direct equality comparison with a long value
* without metatag processing.
* @param val The long value to compare with.
* @return true if {@code this} is a {@link LuaNumber}
* whose value equals val,
* otherwise false
*/
public boolean raweq( long val ) { return false; }
/** Perform equality testing metatag processing /** Perform equality testing metatag processing
* @param lhs left-hand-side of equality expression * @param lhs left-hand-side of equality expression
* @param lhsmt metatag value for left-hand-side * @param lhsmt metatag value for left-hand-side
@@ -2403,6 +2437,16 @@ public class LuaValue extends Varargs {
public LuaValue div( LuaValue rhs ) { return arithmt(DIV,rhs); } public LuaValue div( LuaValue rhs ) { return arithmt(DIV,rhs); }
public LuaValue idiv( LuaValue rhs ) { return arithmt(IDIV,rhs); } public LuaValue idiv( LuaValue rhs ) { return arithmt(IDIV,rhs); }
public LuaValue band( LuaValue rhs ) { return arithmt(BAND,rhs); }
public LuaValue bor( LuaValue rhs ) { return arithmt(BOR,rhs); }
public LuaValue bxor( LuaValue rhs ) { return arithmt(BXOR,rhs); }
public LuaValue shl( LuaValue rhs ) { return arithmt(SHL,rhs); }
public LuaValue shr( LuaValue rhs ) { return arithmt(SHR,rhs); }
/** Divide: Perform numeric divide operation by another value /** Divide: Perform numeric divide operation by another value
* of double type without metatag processing * of double type without metatag processing
@@ -2420,6 +2464,16 @@ public class LuaValue extends Varargs {
public LuaValue div( double rhs ) { return aritherror("div"); } public LuaValue div( double rhs ) { return aritherror("div"); }
public LuaValue idiv( double rhs ) { return aritherror("idiv"); } public LuaValue idiv( double rhs ) { return aritherror("idiv"); }
public LuaValue band( double rhs ) { return aritherror("band"); }
public LuaValue bor( double rhs ) { return aritherror("bor"); }
public LuaValue bxor( double rhs ) { return aritherror("bxor"); }
public LuaValue shl( double rhs ) { return aritherror("shl"); }
public LuaValue shr( double rhs ) { return aritherror("shr"); }
/** Divide: Perform numeric divide operation by another value /** Divide: Perform numeric divide operation by another value
* of int type without metatag processing * of int type without metatag processing
@@ -2437,6 +2491,16 @@ public class LuaValue extends Varargs {
public LuaValue div( int rhs ) { return aritherror("div"); } public LuaValue div( int rhs ) { return aritherror("div"); }
public LuaValue idiv( int rhs ) { return aritherror("idiv"); } public LuaValue idiv( int rhs ) { return aritherror("idiv"); }
public LuaValue band( int rhs ) { return aritherror("band"); }
public LuaValue bor( int rhs ) { return aritherror("bor"); }
public LuaValue bxor( int rhs ) { return aritherror("bxor"); }
public LuaValue shl( int rhs ) { return aritherror("shl"); }
public LuaValue shr( int rhs ) { return aritherror("shr"); }
/** Reverse-divide: Perform numeric divide operation into another value /** Reverse-divide: Perform numeric divide operation into another value
* with metatag processing * with metatag processing
@@ -2454,6 +2518,16 @@ public class LuaValue extends Varargs {
public LuaValue divInto(double lhs) { return arithmtwith(DIV,lhs); } public LuaValue divInto(double lhs) { return arithmtwith(DIV,lhs); }
public LuaValue idivInto(double lhs) { return arithmtwith(IDIV,lhs); } public LuaValue idivInto(double lhs) { return arithmtwith(IDIV,lhs); }
public LuaValue bandInto(double lhs) { return arithmtwith(BAND,lhs); }
public LuaValue borInto(double lhs) { return arithmtwith(BOR,lhs); }
public LuaValue bxorInto(double lhs) { return arithmtwith(BXOR,lhs); }
public LuaValue shlInto(double lhs) { return arithmtwith(SHL,lhs); }
public LuaValue shrInto(double lhs) { return arithmtwith(SHR,lhs); }
/** Modulo: Perform numeric modulo operation with another value /** Modulo: Perform numeric modulo operation with another value
* of unknown type, * of unknown type,
@@ -3173,6 +3247,13 @@ public class LuaValue extends Varargs {
* @return {@link LuaInteger} instance, possibly pooled, whose value is i * @return {@link LuaInteger} instance, possibly pooled, whose value is i
*/ */
public static LuaInteger valueOf(int i) { return LuaInteger.valueOf(i); } public static LuaInteger valueOf(int i) { return LuaInteger.valueOf(i); }
/** Convert java long to a {@link LuaValue}.
*
* @param l long value to convert
* @return {@link LuaInteger} instance, possibly pooled, whose value is l
*/
public static LuaInteger valueOf(long l) { return LuaInteger.valueOf(l); }
/** Convert java double to a {@link LuaValue}. /** Convert java double to a {@link LuaValue}.
* This may return a {@link LuaInteger} or {@link LuaDouble} depending * This may return a {@link LuaInteger} or {@link LuaDouble} depending

View File

@@ -277,6 +277,11 @@ public class Print extends Lua {
case OP_MUL: case OP_MUL:
case OP_DIV: case OP_DIV:
case OP_IDIV: case OP_IDIV:
case OP_BAND:
case OP_BOR:
case OP_BXOR:
case OP_SHL:
case OP_SHR:
case OP_POW: case OP_POW:
case OP_EQ: case OP_EQ:
case OP_LT: case OP_LT:

View File

@@ -890,6 +890,21 @@ public class FuncState extends Constants {
case OP_IDIV: case OP_IDIV:
r = v1.idiv(v2); r = v1.idiv(v2);
break; break;
case OP_BAND:
r = v1.band(v2);
break;
case OP_BOR:
r = v1.bor(v2);
break;
case OP_BXOR:
r = v1.bxor(v2);
break;
case OP_SHL:
r = v1.shl(v2);
break;
case OP_SHR:
r = v1.shr(v2);
break;
case OP_MOD: case OP_MOD:
r = v1.mod(v2); r = v1.mod(v2);
break; break;
@@ -899,6 +914,9 @@ public class FuncState extends Constants {
case OP_UNM: case OP_UNM:
r = v1.neg(); r = v1.neg();
break; break;
case OP_BNOT:
r = v1.bnot();
break;
case OP_LEN: case OP_LEN:
// r = v1.len(); // r = v1.len();
// break; // break;
@@ -918,7 +936,7 @@ public class FuncState extends Constants {
if (constfolding(op, e1, e2)) if (constfolding(op, e1, e2))
return; return;
else { else {
int o2 = (op != OP_UNM && op != OP_LEN) ? this.exp2RK(e2) int o2 = (op != OP_UNM && op != OP_BNOT && op != OP_LEN) ? this.exp2RK(e2)
: 0; : 0;
int o1 = this.exp2RK(e1); int o1 = this.exp2RK(e1);
if (o1 > o2) { if (o1 > o2) {
@@ -971,6 +989,15 @@ public class FuncState extends Constants {
this.codearith(OP_LEN, e, e2, line); this.codearith(OP_LEN, e, e2, line);
break; break;
} }
case LexState.OPR_BNOT: {
if (e.isnumeral())
e.u.setNval(e.u.nval().bnot());
else {
this.exp2anyreg(e);
this.codearith(OP_BNOT, e, e2, line);
}
break;
}
default: default:
_assert (false); _assert (false);
} }
@@ -995,6 +1022,11 @@ public class FuncState extends Constants {
case LexState.OPR_MUL: case LexState.OPR_MUL:
case LexState.OPR_DIV: case LexState.OPR_DIV:
case LexState.OPR_IDIV: case LexState.OPR_IDIV:
case LexState.OPR_BAND:
case LexState.OPR_BOR:
case LexState.OPR_BXOR:
case LexState.OPR_SHL:
case LexState.OPR_SHR:
case LexState.OPR_MOD: case LexState.OPR_MOD:
case LexState.OPR_POW: { case LexState.OPR_POW: {
if (!v.isnumeral()) if (!v.isnumeral())
@@ -1057,6 +1089,21 @@ public class FuncState extends Constants {
case LexState.OPR_IDIV: case LexState.OPR_IDIV:
this.codearith(OP_IDIV, e1, e2, line); this.codearith(OP_IDIV, e1, e2, line);
break; break;
case LexState.OPR_BAND:
this.codearith(OP_BAND, e1, e2, line);
break;
case LexState.OPR_BOR:
this.codearith(OP_BOR, e1, e2, line);
break;
case LexState.OPR_BXOR:
this.codearith(OP_BXOR, e1, e2, line);
break;
case LexState.OPR_SHL:
this.codearith(OP_SHL, e1, e2, line);
break;
case LexState.OPR_SHR:
this.codearith(OP_SHR, e1, e2, line);
break;
case LexState.OPR_MOD: case LexState.OPR_MOD:
this.codearith(OP_MOD, e1, e2, line); this.codearith(OP_MOD, e1, e2, line);
break; break;

View File

@@ -85,15 +85,16 @@ public class LexState extends Constants {
** grep "ORDER OPR" if you change these enums ** grep "ORDER OPR" if you change these enums
*/ */
static final int static final int
OPR_ADD=0, OPR_SUB=1, OPR_MUL=2, OPR_DIV=3, OPR_IDIV=4, OPR_MOD=5, OPR_POW=6, OPR_ADD=0, OPR_SUB=1, OPR_MUL=2, OPR_DIV=3, OPR_IDIV=4, OPR_BAND=5, OPR_BOR=6,
OPR_CONCAT=7, OPR_BXOR=7, OPR_SHL=8, OPR_SHR=9, OPR_MOD=10, OPR_POW=11,
OPR_NE=8, OPR_EQ=9, OPR_CONCAT=12,
OPR_LT=10, OPR_LE=11, OPR_GT=12, OPR_GE=13, OPR_NE=13, OPR_EQ=14,
OPR_AND=14, OPR_OR=15, OPR_LT=15, OPR_LE=16, OPR_GT=17, OPR_GE=18,
OPR_NOBINOPR=16; OPR_AND=19, OPR_OR=20,
OPR_NOBINOPR=21;
static final int static final int
OPR_MINUS=0, OPR_NOT=1, OPR_LEN=2, OPR_NOUNOPR=3; OPR_MINUS=0, OPR_NOT=1, OPR_LEN=2, OPR_BNOT=3, OPR_NOUNOPR=4;
/* exp kind */ /* exp kind */
static final int static final int
@@ -149,7 +150,7 @@ public class LexState extends Constants {
"end", "false", "for", "function", "goto", "if", "end", "false", "for", "function", "goto", "if",
"in", "local", "nil", "not", "or", "repeat", "in", "local", "nil", "not", "or", "repeat",
"return", "then", "true", "until", "while", "return", "then", "true", "until", "while",
"..", "...", "//", "==", ">=", "<=", "~=", "..", "...", "//", "<<", ">>", "==", ">=", "<=", "~=",
"::", "<eos>", "<number>", "<name>", "<string>", "<eof>", "::", "<eos>", "<number>", "<name>", "<string>", "<eof>",
}; };
@@ -160,8 +161,8 @@ public class LexState extends Constants {
TK_IN=268, TK_LOCAL=269, TK_NIL=270, TK_NOT=271, TK_OR=272, TK_REPEAT=273, TK_IN=268, TK_LOCAL=269, TK_NIL=270, TK_NOT=271, TK_OR=272, TK_REPEAT=273,
TK_RETURN=274, TK_THEN=275, TK_TRUE=276, TK_UNTIL=277, TK_WHILE=278, TK_RETURN=274, TK_THEN=275, TK_TRUE=276, TK_UNTIL=277, TK_WHILE=278,
/* other terminal symbols */ /* other terminal symbols */
TK_CONCAT=279, TK_DOTS=280, TK_IDIV=281, TK_EQ=282, TK_GE=283, TK_LE=284, TK_NE=285, TK_CONCAT=279, TK_DOTS=280, TK_IDIV=281, TK_SHL=282, TK_SHR=283, TK_EQ=284, TK_GE=285, TK_LE=286, TK_NE=287,
TK_DBCOLON=286, TK_EOS=287, TK_NUMBER=288, TK_NAME=289, TK_STRING=290; TK_DBCOLON=288, TK_EOS=289, TK_NUMBER=290, TK_NAME=291, TK_STRING=292;
final static int FIRST_RESERVED = TK_AND; final static int FIRST_RESERVED = TK_AND;
final static int NUM_RESERVED = TK_WHILE+1-FIRST_RESERVED; final static int NUM_RESERVED = TK_WHILE+1-FIRST_RESERVED;
@@ -335,52 +336,27 @@ public class LexState extends Constants {
} }
LuaValue strx2number(String str, SemInfo seminfo) { LuaValue strx2number(String str, SemInfo seminfo) {
char[] c = str.toCharArray(); String trimmed = str.trim();
int s = 0; try {
while ( s < c.length && isspace(c[s])) if (trimmed.indexOf('.') < 0 && trimmed.indexOf('p') < 0 && trimmed.indexOf('P') < 0) {
++s; boolean negative = trimmed.startsWith("-");
// Check for negative sign boolean positive = trimmed.startsWith("+");
double sgn = 1.0; int prefix = negative || positive ? 3 : 2;
if (s < c.length && c[s] == '-') { String digits = trimmed.substring(prefix);
sgn = -1.0; long value = Long.parseUnsignedLong(digits, 16);
++s; if (negative) {
} if (value == Long.MIN_VALUE) {
/* Check for "0x" */ return LuaValue.valueOf(Long.MIN_VALUE);
if (s + 2 >= c.length ) }
return LuaValue.ZERO; return LuaValue.valueOf(-value);
if (c[s++] != '0') }
return LuaValue.ZERO; return LuaValue.valueOf(value);
if (c[s] != 'x' && c[s] != 'X')
return LuaValue.ZERO;
++s;
// read integer part.
double m = 0;
int e = 0;
while (s < c.length && isxdigit(c[s]))
m = (m * 16) + hexvalue(c[s++]);
if (s < c.length && c[s] == '.') {
++s; // skip dot
while (s < c.length && isxdigit(c[s])) {
m = (m * 16) + hexvalue(c[s++]);
e -= 4; // Each fractional part shifts right by 2^4
} }
return LuaValue.valueOf(Double.parseDouble(trimmed));
} catch (NumberFormatException e) {
lexerror("malformed number (" + e.getMessage() + ")", TK_NUMBER);
return LuaValue.NIL;
} }
if (s < c.length && (c[s] == 'p' || c[s] == 'P')) {
++s;
int exp1 = 0;
boolean neg1 = false;
if (s < c.length && c[s] == '-') {
neg1 = true;
++s;
}
while (s < c.length && isdigit(c[s]))
exp1 = exp1 * 10 + c[s++] - '0';
if (neg1)
exp1 = -exp1;
e += exp1;
}
return LuaValue.valueOf(sgn * m * MathLib.dpow_d(2.0, e));
} }
boolean str2d(String str, SemInfo seminfo) { boolean str2d(String str, SemInfo seminfo) {
@@ -390,7 +366,12 @@ public class LexState extends Constants {
seminfo.r = strx2number(str, seminfo); seminfo.r = strx2number(str, seminfo);
else { else {
try { try {
seminfo.r = LuaValue.valueOf(Double.parseDouble(str.trim())); String trimmed = str.trim();
if (trimmed.indexOf('.') < 0 && trimmed.indexOf('e') < 0 && trimmed.indexOf('E') < 0) {
seminfo.r = LuaValue.valueOf(Long.parseLong(trimmed));
} else {
seminfo.r = LuaValue.valueOf(Double.parseDouble(trimmed));
}
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
lexerror("malformed number (" + e.getMessage() + ")", TK_NUMBER); lexerror("malformed number (" + e.getMessage() + ")", TK_NUMBER);
} }
@@ -640,7 +621,10 @@ public class LexState extends Constants {
} }
case '<': { case '<': {
nextChar(); nextChar();
if (current != '=') if (current == '<') {
nextChar();
return TK_SHL;
} else if (current != '=')
return '<'; return '<';
else { else {
nextChar(); nextChar();
@@ -649,7 +633,10 @@ public class LexState extends Constants {
} }
case '>': { case '>': {
nextChar(); nextChar();
if (current != '=') if (current == '>') {
nextChar();
return TK_SHR;
} else if (current != '=')
return '>'; return '>';
else { else {
nextChar(); nextChar();
@@ -1510,6 +1497,8 @@ public class LexState extends Constants {
return OPR_MINUS; return OPR_MINUS;
case '#': case '#':
return OPR_LEN; return OPR_LEN;
case '~':
return OPR_BNOT;
default: default:
return OPR_NOUNOPR; return OPR_NOUNOPR;
} }
@@ -1528,6 +1517,16 @@ public class LexState extends Constants {
return OPR_DIV; return OPR_DIV;
case TK_IDIV: case TK_IDIV:
return OPR_IDIV; return OPR_IDIV;
case '&':
return OPR_BAND;
case '|':
return OPR_BOR;
case '~':
return OPR_BXOR;
case TK_SHL:
return OPR_SHL;
case TK_SHR:
return OPR_SHR;
case '%': case '%':
return OPR_MOD; return OPR_MOD;
case '^': case '^':
@@ -1567,14 +1566,15 @@ public class LexState extends Constants {
}; };
static Priority[] priority = { /* ORDER OPR */ static Priority[] priority = { /* ORDER OPR */
new Priority(6, 6), new Priority(6, 6), new Priority(7, 7), new Priority(7, 7), new Priority(7, 7), new Priority(7, 7), /* `+' `-' `*' `/' `//' `%' */ new Priority(10, 10), new Priority(10, 10), new Priority(11, 11), new Priority(11, 11), new Priority(11, 11), new Priority(6, 6), new Priority(4, 4),
new Priority(10, 9), new Priority(5, 4), /* power and concat (right associative) */ new Priority(5, 5), new Priority(7, 7), new Priority(7, 7), new Priority(11, 11), new Priority(13, 12),
new Priority(3, 3), new Priority(3, 3), /* equality and inequality */ new Priority(8, 7),
new Priority(3, 3), new Priority(3, 3), new Priority(3, 3), new Priority(3, 3), /* order */ new Priority(3, 3), new Priority(3, 3),
new Priority(2, 2), new Priority(1, 1) /* logical (and/or) */ new Priority(3, 3), new Priority(3, 3), new Priority(3, 3), new Priority(3, 3),
new Priority(2, 2), new Priority(1, 1)
}; };
static final int UNARY_PRIORITY = 8; /* priority for unary operators */ static final int UNARY_PRIORITY = 12; /* priority for unary operators */
/* /*

View File

@@ -76,6 +76,7 @@ public class CoroutineLib extends TwoArgFunction {
globals = env.checkglobals(); globals = env.checkglobals();
LuaTable coroutine = new LuaTable(); LuaTable coroutine = new LuaTable();
coroutine.set("create", new Create()); coroutine.set("create", new Create());
coroutine.set("isyieldable", new IsYieldable());
coroutine.set("resume", new Resume()); coroutine.set("resume", new Resume());
coroutine.set("running", new Running()); coroutine.set("running", new Running());
coroutine.set("status", new Status()); coroutine.set("status", new Status());
@@ -99,6 +100,13 @@ public class CoroutineLib extends TwoArgFunction {
} }
} }
final class IsYieldable extends VarArgFunction {
public Varargs invoke(Varargs args) {
final LuaThread r = globals.running;
return valueOf(r != null && !r.isMainThread());
}
}
final class Running extends VarArgFunction { final class Running extends VarArgFunction {
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
final LuaThread r = globals.running; final LuaThread r = globals.running;
@@ -141,4 +149,4 @@ public class CoroutineLib extends TwoArgFunction {
} }
} }
} }
} }

View File

@@ -817,9 +817,15 @@ public class DebugLib extends TwoArgFunction {
case Lua.OP_MUL: tm = LuaValue.MUL; break; case Lua.OP_MUL: tm = LuaValue.MUL; break;
case Lua.OP_DIV: tm = LuaValue.DIV; break; case Lua.OP_DIV: tm = LuaValue.DIV; break;
case Lua.OP_IDIV: tm = LuaValue.IDIV; break; case Lua.OP_IDIV: tm = LuaValue.IDIV; break;
case Lua.OP_BAND: tm = LuaValue.BAND; break;
case Lua.OP_BOR: tm = LuaValue.BOR; break;
case Lua.OP_BXOR: tm = LuaValue.BXOR; break;
case Lua.OP_SHL: tm = LuaValue.SHL; break;
case Lua.OP_SHR: tm = LuaValue.SHR; break;
case Lua.OP_MOD: tm = LuaValue.MOD; break; case Lua.OP_MOD: tm = LuaValue.MOD; break;
case Lua.OP_POW: tm = LuaValue.POW; break; case Lua.OP_POW: tm = LuaValue.POW; break;
case Lua.OP_UNM: tm = LuaValue.UNM; break; case Lua.OP_UNM: tm = LuaValue.UNM; break;
case Lua.OP_BNOT: tm = LuaValue.BNOT; break;
case Lua.OP_LEN: tm = LuaValue.LEN; break; case Lua.OP_LEN: tm = LuaValue.LEN; break;
case Lua.OP_LT: tm = LuaValue.LT; break; case Lua.OP_LT: tm = LuaValue.LT; break;
case Lua.OP_LE: tm = LuaValue.LE; break; case Lua.OP_LE: tm = LuaValue.LE; break;

View File

@@ -113,7 +113,9 @@ public class MathLib extends TwoArgFunction {
math.set("huge", LuaDouble.POSINF ); math.set("huge", LuaDouble.POSINF );
math.set("ldexp", new ldexp()); math.set("ldexp", new ldexp());
math.set("max", new max()); math.set("max", new max());
math.set("maxinteger", LuaValue.valueOf(Long.MAX_VALUE));
math.set("min", new min()); math.set("min", new min());
math.set("mininteger", LuaValue.valueOf(Long.MIN_VALUE));
math.set("modf", new modf()); math.set("modf", new modf());
math.set("pi", Math.PI ); math.set("pi", Math.PI );
math.set("pow", new pow()); math.set("pow", new pow());
@@ -124,6 +126,9 @@ public class MathLib extends TwoArgFunction {
math.set("sin", new sin()); math.set("sin", new sin());
math.set("sqrt", new sqrt()); math.set("sqrt", new sqrt());
math.set("tan", new tan()); math.set("tan", new tan());
math.set("tointeger", new tointeger());
math.set("type", new type());
math.set("ult", new ult());
env.set("math", math); env.set("math", math);
if (!env.get("package").isnil()) env.get("package").get("loaded").set("math", math); if (!env.get("package").isnil()) env.get("package").get("loaded").set("math", math);
return math; return math;
@@ -229,6 +234,34 @@ public class MathLib extends TwoArgFunction {
return varargsOf( valueOf(intPart), valueOf(fracPart) ); return varargsOf( valueOf(intPart), valueOf(fracPart) );
} }
} }
static class tointeger extends OneArgFunction {
public LuaValue call(LuaValue arg) {
LuaValue n = arg.tonumber();
if (n.isnil() || !n.islong()) {
return NIL;
}
return LuaValue.valueOf(n.tolong());
}
}
static class type extends OneArgFunction {
public LuaValue call(LuaValue arg) {
LuaValue n = arg.tonumber();
if (n.isnil()) {
return NIL;
}
return LuaValue.valueOf(n.isinttype()? "integer": "float");
}
}
static class ult extends TwoArgFunction {
public LuaValue call(LuaValue x, LuaValue y) {
long a = x.checklong();
long b = y.checklong();
return valueOf(Long.compareUnsigned(a, b) < 0);
}
}
static class random extends LibFunction { static class random extends LibFunction {
Random random = new Random(); Random random = new Random();
@@ -236,17 +269,28 @@ public class MathLib extends TwoArgFunction {
return valueOf( random.nextDouble() ); return valueOf( random.nextDouble() );
} }
public LuaValue call(LuaValue a) { public LuaValue call(LuaValue a) {
int m = a.checkint(); long upper = a.checklong();
if (m<1) argerror(1, "interval is empty"); if (upper < 1) argerror(1, "interval is empty");
return valueOf( 1 + random.nextInt(m) ); return valueOf(nextLong(1, upper));
} }
public LuaValue call(LuaValue a, LuaValue b) { public LuaValue call(LuaValue a, LuaValue b) {
int m = a.checkint(); long lower = a.checklong();
int n = b.checkint(); long upper = b.checklong();
if (n<m) argerror(2, "interval is empty"); if (upper < lower) argerror(2, "interval is empty");
return valueOf( m + random.nextInt(n+1-m) ); return valueOf(nextLong(lower, upper));
}
private long nextLong(long lower, long upper) {
long bound = upper - lower + 1;
if (bound <= 0) {
long value;
do {
value = random.nextLong();
} while (Long.compareUnsigned(value - lower, upper - lower) > 0);
return value;
}
return lower + random.nextLong(bound);
} }
} }
static class randomseed extends OneArgFunction { static class randomseed extends OneArgFunction {

View File

@@ -23,9 +23,11 @@ package org.luaj.vm2.libs;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteOrder;
import org.luaj.vm2.Buffer; import org.luaj.vm2.Buffer;
import org.luaj.vm2.LuaClosure; import org.luaj.vm2.LuaClosure;
import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaString; import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaTable; import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
@@ -93,9 +95,12 @@ public class StringLib extends TwoArgFunction {
string.set("len", new len()); string.set("len", new len());
string.set("lower", new lower()); string.set("lower", new lower());
string.set("match", new match()); string.set("match", new match());
string.set("pack", new pack());
string.set("packsize", new packsize());
string.set("rep", new rep()); string.set("rep", new rep());
string.set("reverse", new reverse()); string.set("reverse", new reverse());
string.set("sub", new sub()); string.set("sub", new sub());
string.set("unpack", new unpack());
string.set("upper", new upper()); string.set("upper", new upper());
env.set("string", string); env.set("string", string);
@@ -327,6 +332,149 @@ public class StringLib extends TwoArgFunction {
} }
buf.append( (byte) '"' ); buf.append( (byte) '"' );
} }
static final class pack extends VarArgFunction {
public Varargs invoke(Varargs args) {
FormatState state = new FormatState(args.checkstring(1));
ByteArrayOutput out = new ByteArrayOutput();
int arg = 2;
while (state.hasMore()) {
FormatOption option = state.next();
int padding = state.alignmentPadding(out.size(), option);
out.pad(padding);
switch (option.kind) {
case PADDING:
out.pad(option.size);
break;
case ALIGN:
out.pad(option.size);
break;
case SIGNED:
writeInteger(out, args.checklong(arg++), option.size, state.littleEndian, true);
break;
case UNSIGNED:
writeInteger(out, checkUnsigned(args.checklong(arg++), option.size), option.size, state.littleEndian, false);
break;
case FLOAT:
writeFloat(out, (float) args.checkdouble(arg++), state.littleEndian);
break;
case DOUBLE:
writeDouble(out, args.checkdouble(arg++), state.littleEndian);
break;
case FIXED_STRING: {
LuaString s = args.checkstring(arg++);
if (s.rawlen() > option.size) {
argerror(arg - 1, "string longer than given size");
}
out.write(s);
out.pad(option.size - s.rawlen());
break;
}
case ZERO_STRING: {
LuaString s = args.checkstring(arg++);
for (int i = 0; i < s.rawlen(); i++) {
if (s.luaByte(i) == 0) {
argerror(arg - 1, "string contains zeros");
}
}
out.write(s);
out.writeByte(0);
break;
}
case SIZED_STRING: {
LuaString s = args.checkstring(arg++);
writeInteger(out, checkUnsigned(s.rawlen(), option.size), option.size, state.littleEndian, false);
out.write(s);
break;
}
default:
throw new LuaError("unsupported pack option");
}
}
return LuaString.valueUsing(out.toByteArray());
}
}
static final class packsize extends OneArgFunction {
public LuaValue call(LuaValue arg) {
FormatState state = new FormatState(arg.checkstring());
int offset = 0;
while (state.hasMore()) {
FormatOption option = state.next();
offset += state.alignmentPadding(offset, option);
if (option.kind == OptionKind.ZERO_STRING || option.kind == OptionKind.SIZED_STRING) {
throw new LuaError("variable-length format");
}
offset += option.size;
}
return valueOf(offset);
}
}
static final class unpack extends VarArgFunction {
public Varargs invoke(Varargs args) {
FormatState state = new FormatState(args.checkstring(1));
LuaString input = args.checkstring(2);
int position = posrelat(args.optint(3, 1), input.rawlen());
if (position < 1) {
position = 1;
}
int offset = position - 1;
java.util.ArrayList<LuaValue> values = new java.util.ArrayList<LuaValue>();
while (state.hasMore()) {
FormatOption option = state.next();
offset += state.alignmentPadding(offset, option);
requireBytes(input, offset, option.kind == OptionKind.ZERO_STRING ? 1 : option.size);
switch (option.kind) {
case PADDING:
case ALIGN:
offset += option.size;
break;
case SIGNED:
values.add(LuaValue.valueOf(readInteger(input, offset, option.size, state.littleEndian, true)));
offset += option.size;
break;
case UNSIGNED:
values.add(LuaValue.valueOf(readUnsignedInteger(input, offset, option.size, state.littleEndian)));
offset += option.size;
break;
case FLOAT:
values.add(LuaValue.valueOf(readFloat(input, offset, state.littleEndian)));
offset += option.size;
break;
case DOUBLE:
values.add(LuaValue.valueOf(readDouble(input, offset, state.littleEndian)));
offset += option.size;
break;
case FIXED_STRING:
values.add(input.substring(offset, offset + option.size));
offset += option.size;
break;
case ZERO_STRING: {
int end = findZero(input, offset);
values.add(input.substring(offset, end));
offset = end + 1;
break;
}
case SIZED_STRING: {
long len = readUnsignedInteger(input, offset, option.size, state.littleEndian);
offset += option.size;
if (len > Integer.MAX_VALUE) {
throw new LuaError("string length does not fit");
}
requireBytes(input, offset, (int) len);
values.add(input.substring(offset, offset + (int) len));
offset += (int) len;
break;
}
default:
throw new LuaError("unsupported unpack option");
}
}
values.add(LuaValue.valueOf(offset + 1));
return LuaValue.varargsOf(values.toArray(new LuaValue[values.size()]));
}
}
private static final String FLAGS = "-+ #0"; private static final String FLAGS = "-+ #0";
@@ -745,6 +893,371 @@ public class StringLib extends TwoArgFunction {
return valueOf(arg.checkjstring().toUpperCase()); return valueOf(arg.checkjstring().toUpperCase());
} }
} }
private static void requireBytes(LuaString input, int offset, int size) {
if (offset < 0 || offset + size > input.rawlen()) {
throw new LuaError("data string too short");
}
}
private static int findZero(LuaString input, int offset) {
for (int i = offset, n = input.rawlen(); i < n; i++) {
if (input.luaByte(i) == 0) {
return i;
}
}
throw new LuaError("unfinished string for format 'z'");
}
private static long checkUnsigned(long value, int size) {
if (value < 0) {
throw new LuaError("unsigned overflow");
}
if (size < 8 && value >= (1L << (size * 8))) {
throw new LuaError("unsigned overflow");
}
return value;
}
private static void writeInteger(ByteArrayOutput out, long value, int size, boolean littleEndian, boolean signed) {
if (size <= 0 || size > 16) {
throw new LuaError("integral size out of limits");
}
byte fill = (byte) ((signed && value < 0) ? 0xFF : 0x00);
byte[] bytes = new byte[size];
long v = value;
for (int i = 0; i < size; i++) {
int index = littleEndian ? i : (size - 1 - i);
if (i < 8) {
bytes[index] = (byte) (v & 0xFF);
v >>= 8;
} else {
bytes[index] = fill;
}
}
out.write(bytes);
}
private static long readInteger(LuaString input, int offset, int size, boolean littleEndian, boolean signed) {
if (!signed) {
return readUnsignedInteger(input, offset, size, littleEndian);
}
if (size <= 0 || size > 16) {
throw new LuaError("integral size out of limits");
}
requireBytes(input, offset, size);
long result = 0L;
int bytesToRead = Math.min(size, 8);
for (int i = 0; i < bytesToRead; i++) {
int index = littleEndian ? (offset + i) : (offset + size - 1 - i);
result |= ((long) input.luaByte(index)) << (8 * i);
}
int signIndex = littleEndian ? (offset + size - 1) : offset;
boolean negative = (input.luaByte(signIndex) & 0x80) != 0;
if (size < 8 && negative) {
result |= (-1L) << (size * 8);
}
if (size > 8) {
for (int i = 8; i < size; i++) {
int index = littleEndian ? (offset + i) : (offset + size - 1 - i);
int b = input.luaByte(index);
if (b != (negative ? 0xFF : 0x00)) {
throw new LuaError("integer overflow");
}
}
}
return result;
}
private static long readUnsignedInteger(LuaString input, int offset, int size, boolean littleEndian) {
if (size <= 0 || size > 16) {
throw new LuaError("integral size out of limits");
}
requireBytes(input, offset, size);
long result = 0L;
int bytesToRead = Math.min(size, 8);
for (int i = 0; i < bytesToRead; i++) {
int index = littleEndian ? (offset + i) : (offset + size - 1 - i);
result |= ((long) input.luaByte(index)) << (8 * i);
}
for (int i = 8; i < size; i++) {
int index = littleEndian ? (offset + i) : (offset + size - 1 - i);
if (input.luaByte(index) != 0) {
throw new LuaError("unsigned overflow");
}
}
if (result < 0) {
throw new LuaError("unsigned overflow");
}
return result;
}
private static void writeFloat(ByteArrayOutput out, float value, boolean littleEndian) {
writeFixed(out, Float.floatToIntBits(value) & 0xFFFFFFFFL, 4, littleEndian);
}
private static float readFloat(LuaString input, int offset, boolean littleEndian) {
return Float.intBitsToFloat((int) readFixed(input, offset, 4, littleEndian));
}
private static void writeDouble(ByteArrayOutput out, double value, boolean littleEndian) {
writeFixed(out, Double.doubleToLongBits(value), 8, littleEndian);
}
private static double readDouble(LuaString input, int offset, boolean littleEndian) {
return Double.longBitsToDouble(readFixed(input, offset, 8, littleEndian));
}
private static void writeFixed(ByteArrayOutput out, long bits, int size, boolean littleEndian) {
byte[] bytes = new byte[size];
for (int i = 0; i < size; i++) {
int index = littleEndian ? i : (size - 1 - i);
bytes[index] = (byte) ((bits >>> (8 * i)) & 0xFF);
}
out.write(bytes);
}
private static long readFixed(LuaString input, int offset, int size, boolean littleEndian) {
requireBytes(input, offset, size);
long bits = 0L;
for (int i = 0; i < size; i++) {
int index = littleEndian ? (offset + i) : (offset + size - 1 - i);
bits |= ((long) input.luaByte(index)) << (8 * i);
}
return bits;
}
private enum OptionKind {
PADDING,
ALIGN,
SIGNED,
UNSIGNED,
FLOAT,
DOUBLE,
FIXED_STRING,
ZERO_STRING,
SIZED_STRING
}
private static final class FormatOption {
final OptionKind kind;
final int size;
final int alignment;
FormatOption(OptionKind kind, int size, int alignment) {
this.kind = kind;
this.size = size;
this.alignment = alignment;
}
}
private static final class FormatState {
private final LuaString format;
private int index;
boolean littleEndian;
private int maxAlign;
FormatState(LuaString format) {
this.format = format;
this.littleEndian = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN;
this.maxAlign = 1;
}
boolean hasMore() {
skipSpaces();
return index < format.rawlen();
}
FormatOption next() {
while (index < format.rawlen()) {
int c = format.luaByte(index++);
switch (c) {
case ' ':
case '\t':
case '\n':
case '\r':
continue;
case '<':
littleEndian = true;
continue;
case '>':
littleEndian = false;
continue;
case '=':
littleEndian = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN;
continue;
case '!':
maxAlign = readCount();
if (maxAlign <= 0) {
throw new LuaError("invalid format option '!'");
}
continue;
case 'x':
return new FormatOption(OptionKind.PADDING, 1, 1);
case 'X': {
FormatOption next = peekNextSizedOption();
return new FormatOption(OptionKind.ALIGN, alignmentFor(next.size), 1);
}
case 'b':
return signed(1);
case 'B':
return unsigned(1);
case 'h':
return signed(2);
case 'H':
return unsigned(2);
case 'l':
return signed(8);
case 'L':
return unsigned(8);
case 'j':
return signed(8);
case 'J':
return unsigned(8);
case 'T':
return unsigned(8);
case 'i':
return signed(readOptionalCount(4));
case 'I':
return unsigned(readOptionalCount(4));
case 'f':
return new FormatOption(OptionKind.FLOAT, 4, alignmentFor(4));
case 'd':
case 'n':
return new FormatOption(OptionKind.DOUBLE, 8, alignmentFor(8));
case 'c': {
int size = readCount();
if (size < 0) {
throw new LuaError("missing size for format option 'c'");
}
return new FormatOption(OptionKind.FIXED_STRING, size, 1);
}
case 'z':
return new FormatOption(OptionKind.ZERO_STRING, 0, 1);
case 's': {
int size = readOptionalCount(8);
return new FormatOption(OptionKind.SIZED_STRING, size, alignmentFor(size));
}
default:
throw new LuaError("invalid format option '" + (char) c + "'");
}
}
throw new LuaError("unexpected end of format string");
}
int alignmentPadding(int offset, FormatOption option) {
int alignment = option.alignment;
if (alignment <= 1) {
return 0;
}
int mod = offset & (alignment - 1);
return mod == 0 ? 0 : (alignment - mod);
}
private FormatOption signed(int size) {
validateIntegralSize(size);
return new FormatOption(OptionKind.SIGNED, size, alignmentFor(size));
}
private FormatOption unsigned(int size) {
validateIntegralSize(size);
return new FormatOption(OptionKind.UNSIGNED, size, alignmentFor(size));
}
private FormatOption peekNextSizedOption() {
int savedIndex = index;
boolean savedEndian = littleEndian;
int savedMaxAlign = maxAlign;
FormatOption option = next();
index = savedIndex;
littleEndian = savedEndian;
maxAlign = savedMaxAlign;
if (option.kind == OptionKind.ZERO_STRING || option.kind == OptionKind.FIXED_STRING) {
throw new LuaError("invalid next option for option 'X'");
}
return option;
}
private int readCount() {
if (index >= format.rawlen() || !Character.isDigit((char) format.luaByte(index))) {
throw new LuaError("missing size for format option");
}
int value = 0;
while (index < format.rawlen() && Character.isDigit((char) format.luaByte(index))) {
value = value * 10 + (format.luaByte(index++) - '0');
}
return value;
}
private int readOptionalCount(int defaultValue) {
if (index < format.rawlen() && Character.isDigit((char) format.luaByte(index))) {
int value = readCount();
validateIntegralSize(value);
return value;
}
return defaultValue;
}
private int alignmentFor(int size) {
int alignment = Math.min(size, maxAlign);
if (alignment <= 1) {
return 1;
}
if ((alignment & (alignment - 1)) != 0) {
throw new LuaError("format asks for alignment not power of 2");
}
return alignment;
}
private void validateIntegralSize(int size) {
if (size < 1 || size > 16) {
throw new LuaError("integral size out of limits");
}
}
private void skipSpaces() {
while (index < format.rawlen()) {
int c = format.luaByte(index);
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
index++;
} else {
break;
}
}
}
}
private static final class ByteArrayOutput {
private final ByteArrayOutputStream out = new ByteArrayOutputStream();
void writeByte(int value) {
out.write(value);
}
void write(byte[] bytes) {
out.write(bytes, 0, bytes.length);
}
void write(LuaString s) {
byte[] bytes = new byte[s.rawlen()];
s.copyInto(0, bytes, 0, bytes.length);
write(bytes);
}
void pad(int count) {
for (int i = 0; i < count; i++) {
out.write(0);
}
}
int size() {
return out.size();
}
byte[] toByteArray() {
return out.toByteArray();
}
}
/** /**
* This utility method implements both string.find and string.match. * This utility method implements both string.find and string.match.

View File

@@ -21,6 +21,7 @@
******************************************************************************/ ******************************************************************************/
package org.luaj.vm2.libs; package org.luaj.vm2.libs;
import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaTable; import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs; import org.luaj.vm2.Varargs;
@@ -65,6 +66,7 @@ public class TableLib extends TwoArgFunction {
LuaTable table = new LuaTable(); LuaTable table = new LuaTable();
table.set("concat", new concat()); table.set("concat", new concat());
table.set("insert", new insert()); table.set("insert", new insert());
table.set("move", new move());
table.set("pack", new pack()); table.set("pack", new pack());
table.set("remove", new remove()); table.set("remove", new remove());
table.set("sort", new sort()); table.set("sort", new sort());
@@ -123,6 +125,33 @@ public class TableLib extends TwoArgFunction {
} }
} }
// "move" (a1, f, e, t [,a2]) -> a2
static class move extends VarArgFunction {
public Varargs invoke(Varargs args) {
LuaTable source = args.checktable(1);
int from = args.checkint(2);
int to = args.checkint(3);
int target = args.checkint(4);
LuaTable dest = args.opttable(5, source);
if (to >= from) {
int count = to - from + 1;
if (count < 0) {
throw new LuaError("too many elements to move");
}
if (target > from && target <= to && dest == source) {
for (int i = count - 1; i >= 0; i--) {
dest.set(target + i, source.get(from + i));
}
} else {
for (int i = 0; i < count; i++) {
dest.set(target + i, source.get(from + i));
}
}
}
return dest;
}
}
// "remove" (table [, pos]) -> removed-ele // "remove" (table [, pos]) -> removed-ele
static class remove extends VarArgFunction { static class remove extends VarArgFunction {
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {

View File

@@ -353,7 +353,7 @@ void FieldSep():
void Binop(): void Binop():
{} {}
{ {
"+" | "-" | "*" | "/" | "//" | "^" | "%" | ".." | "<" | "<=" | ">" | ">=" | "==" | "~=" | <AND> | <OR> "+" | "-" | "*" | "/" | "//" | "&" | "|" | "~" | "<<" | ">>" | "^" | "%" | ".." | "<" | "<=" | ">" | ">=" | "==" | "~=" | <AND> | <OR>
} }
void Unop(): void Unop():

View File

@@ -510,6 +510,11 @@ int Binop():
| "*" { return Lua.OP_MUL; } | "*" { return Lua.OP_MUL; }
| "/" { return Lua.OP_DIV; } | "/" { return Lua.OP_DIV; }
| "//" { return Lua.OP_IDIV; } | "//" { return Lua.OP_IDIV; }
| "&" { return Lua.OP_BAND; }
| "|" { return Lua.OP_BOR; }
| "~" { return Lua.OP_BXOR; }
| "<<" { return Lua.OP_SHL; }
| ">>" { return Lua.OP_SHR; }
| "^" { return Lua.OP_POW; } | "^" { return Lua.OP_POW; }
| "%" { return Lua.OP_MOD; } | "%" { return Lua.OP_MOD; }
| ".." { return Lua.OP_CONCAT; } | ".." { return Lua.OP_CONCAT; }
@@ -529,4 +534,5 @@ int Unop():
"-" { return Lua.OP_UNM; } "-" { return Lua.OP_UNM; }
| <NOT> { return Lua.OP_NOT; } | <NOT> { return Lua.OP_NOT; }
| "#" { return Lua.OP_LEN; } | "#" { return Lua.OP_LEN; }
| "~" { return Lua.OP_BNOT; }
} }

View File

@@ -25,7 +25,6 @@ import org.luaj.vm2.Globals;
import org.luaj.vm2.LoadState; import org.luaj.vm2.LoadState;
import org.luaj.vm2.compiler.LuaC; import org.luaj.vm2.compiler.LuaC;
import org.luaj.vm2.libs.BaseLib; import org.luaj.vm2.libs.BaseLib;
import org.luaj.vm2.libs.Bit32Lib;
import org.luaj.vm2.libs.CoroutineLib; import org.luaj.vm2.libs.CoroutineLib;
import org.luaj.vm2.libs.DebugLib; import org.luaj.vm2.libs.DebugLib;
import org.luaj.vm2.libs.MathLib; import org.luaj.vm2.libs.MathLib;
@@ -34,6 +33,7 @@ import org.luaj.vm2.libs.PackageLib;
import org.luaj.vm2.libs.ResourceFinder; import org.luaj.vm2.libs.ResourceFinder;
import org.luaj.vm2.libs.StringLib; import org.luaj.vm2.libs.StringLib;
import org.luaj.vm2.libs.TableLib; import org.luaj.vm2.libs.TableLib;
import org.luaj.vm2.libs.Utf8Lib;
/** The {@link JmePlatform} class is a convenience class to standardize /** The {@link JmePlatform} class is a convenience class to standardize
* how globals tables are initialized for the JME platform. * how globals tables are initialized for the JME platform.
@@ -73,7 +73,6 @@ import org.luaj.vm2.libs.TableLib;
* <li>{@link Globals}</li> * <li>{@link Globals}</li>
* <li>{@link BaseLib}</li> * <li>{@link BaseLib}</li>
* <li>{@link PackageLib}</li> * <li>{@link PackageLib}</li>
* <li>{@link Bit32Lib}</li>
* <li>{@link TableLib}</li> * <li>{@link TableLib}</li>
* <li>{@link StringLib}</li> * <li>{@link StringLib}</li>
* <li>{@link CoroutineLib}</li> * <li>{@link CoroutineLib}</li>
@@ -105,11 +104,11 @@ public class JmePlatform {
Globals globals = new Globals(); Globals globals = new Globals();
globals.load(new BaseLib()); globals.load(new BaseLib());
globals.load(new PackageLib()); globals.load(new PackageLib());
globals.load(new Bit32Lib());
globals.load(new OsLib()); globals.load(new OsLib());
globals.load(new MathLib()); globals.load(new MathLib());
globals.load(new TableLib()); globals.load(new TableLib());
globals.load(new StringLib()); globals.load(new StringLib());
globals.load(new Utf8Lib());
globals.load(new CoroutineLib()); globals.load(new CoroutineLib());
globals.load(new JmeIoLib()); globals.load(new JmeIoLib());
LoadState.install(globals); LoadState.install(globals);

View File

@@ -89,11 +89,15 @@ public class Exp extends SyntaxElement {
case Lua.OP_OR: return 0; case Lua.OP_OR: return 0;
case Lua.OP_AND: return 1; case Lua.OP_AND: return 1;
case Lua.OP_LT: case Lua.OP_GT: case Lua.OP_LE: case Lua.OP_GE: case Lua.OP_NEQ: case Lua.OP_EQ: return 2; case Lua.OP_LT: case Lua.OP_GT: case Lua.OP_LE: case Lua.OP_GE: case Lua.OP_NEQ: case Lua.OP_EQ: return 2;
case Lua.OP_CONCAT: return 3; case Lua.OP_BOR: return 3;
case Lua.OP_ADD: case Lua.OP_SUB: return 4; case Lua.OP_BXOR: return 4;
case Lua.OP_MUL: case Lua.OP_DIV: case Lua.OP_IDIV: case Lua.OP_MOD: return 5; case Lua.OP_BAND: return 5;
case Lua.OP_NOT: case Lua.OP_UNM: case Lua.OP_LEN: return 6; case Lua.OP_SHL: case Lua.OP_SHR: return 6;
case Lua.OP_POW: return 7; case Lua.OP_CONCAT: return 7;
case Lua.OP_ADD: case Lua.OP_SUB: return 8;
case Lua.OP_MUL: case Lua.OP_DIV: case Lua.OP_IDIV: case Lua.OP_MOD: return 9;
case Lua.OP_NOT: case Lua.OP_UNM: case Lua.OP_LEN: case Lua.OP_BNOT: return 10;
case Lua.OP_POW: return 11;
default: throw new IllegalStateException("precedence of bad op "+op); default: throw new IllegalStateException("precedence of bad op "+op);
} }
} }

View File

@@ -78,7 +78,7 @@ public class CoerceJavaToLua {
private static final class IntCoercion implements Coercion { private static final class IntCoercion implements Coercion {
public LuaValue coerce( Object javaValue ) { public LuaValue coerce( Object javaValue ) {
Number n = (Number) javaValue; Number n = (Number) javaValue;
return LuaInteger.valueOf( n.intValue() ); return LuaInteger.valueOf( n.longValue() );
} }
} }
@@ -149,7 +149,7 @@ public class CoerceJavaToLua {
COERCIONS.put( Character.class, charCoercion ); COERCIONS.put( Character.class, charCoercion );
COERCIONS.put( Short.class, intCoercion ); COERCIONS.put( Short.class, intCoercion );
COERCIONS.put( Integer.class, intCoercion ); COERCIONS.put( Integer.class, intCoercion );
COERCIONS.put( Long.class, doubleCoercion ); COERCIONS.put( Long.class, intCoercion );
COERCIONS.put( Float.class, doubleCoercion ); COERCIONS.put( Float.class, doubleCoercion );
COERCIONS.put( Double.class, doubleCoercion ); COERCIONS.put( Double.class, doubleCoercion );
COERCIONS.put( String.class, stringCoercion ); COERCIONS.put( String.class, stringCoercion );
@@ -160,9 +160,9 @@ public class CoerceJavaToLua {
/** /**
* Coerse a Java object to a corresponding lua value. * Coerse a Java object to a corresponding lua value.
* <p> * <p>
* Integral types {@code boolean}, {@code byte}, {@code char}, and {@code int} * Integral types {@code boolean}, {@code byte}, {@code char}, {@code int}, and {@code long}
* will become {@link LuaInteger}; * will become {@link LuaInteger};
* {@code long}, {@code float}, and {@code double} will become {@link LuaDouble}; * {@code float} and {@code double} will become {@link LuaDouble};
* {@code String} and {@code byte[]} will become {@link LuaString}; * {@code String} and {@code byte[]} will become {@link LuaString};
* types inheriting from {@link LuaValue} will be returned without coercion; * types inheriting from {@link LuaValue} will be returned without coercion;
* other types will become {@link LuaUserdata}. * other types will become {@link LuaUserdata}.

View File

@@ -292,7 +292,10 @@ public class CoerceLuaToJava {
public int score(LuaValue value) { public int score(LuaValue value) {
switch ( value.type() ) { switch ( value.type() ) {
case LuaValue.TNUMBER: case LuaValue.TNUMBER:
return inheritanceLevels( targetType, value.isint()? Integer.class: Double.class ); if (value.isinttype()) {
return inheritanceLevels( targetType, value.isint()? Integer.class: Long.class );
}
return inheritanceLevels( targetType, Double.class );
case LuaValue.TBOOLEAN: case LuaValue.TBOOLEAN:
return inheritanceLevels( targetType, Boolean.class ); return inheritanceLevels( targetType, Boolean.class );
case LuaValue.TSTRING: case LuaValue.TSTRING:
@@ -308,7 +311,10 @@ public class CoerceLuaToJava {
public Object coerce(LuaValue value) { public Object coerce(LuaValue value) {
switch ( value.type() ) { switch ( value.type() ) {
case LuaValue.TNUMBER: case LuaValue.TNUMBER:
return value.isint()? (Object) Integer.valueOf(value.toint()): (Object) Double.valueOf(value.todouble()); if (value.isinttype()) {
return value.isint()? (Object) Integer.valueOf(value.toint()): (Object) Long.valueOf(value.tolong());
}
return Double.valueOf(value.todouble());
case LuaValue.TBOOLEAN: case LuaValue.TBOOLEAN:
return value.toboolean()? Boolean.TRUE: Boolean.FALSE; return value.toboolean()? Boolean.TRUE: Boolean.FALSE;
case LuaValue.TSTRING: case LuaValue.TSTRING:
@@ -369,4 +375,4 @@ public class CoerceLuaToJava {
COERCIONS.put( c, co ); COERCIONS.put( c, co );
return co; return co;
} }
} }

View File

@@ -26,13 +26,13 @@ import org.luaj.vm2.LoadState;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs; import org.luaj.vm2.Varargs;
import org.luaj.vm2.compiler.LuaC; import org.luaj.vm2.compiler.LuaC;
import org.luaj.vm2.libs.Bit32Lib;
import org.luaj.vm2.libs.CoroutineLib; import org.luaj.vm2.libs.CoroutineLib;
import org.luaj.vm2.libs.DebugLib; import org.luaj.vm2.libs.DebugLib;
import org.luaj.vm2.libs.PackageLib; import org.luaj.vm2.libs.PackageLib;
import org.luaj.vm2.libs.ResourceFinder; import org.luaj.vm2.libs.ResourceFinder;
import org.luaj.vm2.libs.StringLib; import org.luaj.vm2.libs.StringLib;
import org.luaj.vm2.libs.TableLib; import org.luaj.vm2.libs.TableLib;
import org.luaj.vm2.libs.Utf8Lib;
/** The {@link JsePlatform} class is a convenience class to standardize /** The {@link JsePlatform} class is a convenience class to standardize
* how globals tables are initialized for the JSE platform. * how globals tables are initialized for the JSE platform.
@@ -63,7 +63,6 @@ import org.luaj.vm2.libs.TableLib;
* <li>{@link Globals}</li> * <li>{@link Globals}</li>
* <li>{@link JseBaseLib}</li> * <li>{@link JseBaseLib}</li>
* <li>{@link PackageLib}</li> * <li>{@link PackageLib}</li>
* <li>{@link Bit32Lib}</li>
* <li>{@link TableLib}</li> * <li>{@link TableLib}</li>
* <li>{@link StringLib}</li> * <li>{@link StringLib}</li>
* <li>{@link CoroutineLib}</li> * <li>{@link CoroutineLib}</li>
@@ -95,9 +94,9 @@ public class JsePlatform {
Globals globals = new Globals(); Globals globals = new Globals();
globals.load(new JseBaseLib()); globals.load(new JseBaseLib());
globals.load(new PackageLib()); globals.load(new PackageLib());
globals.load(new Bit32Lib());
globals.load(new TableLib()); globals.load(new TableLib());
globals.load(new JseStringLib()); globals.load(new JseStringLib());
globals.load(new Utf8Lib());
globals.load(new CoroutineLib()); globals.load(new CoroutineLib());
globals.load(new JseMathLib()); globals.load(new JseMathLib());
globals.load(new JseIoLib()); globals.load(new JseIoLib());

View File

@@ -520,6 +520,7 @@ public class JavaBuilder {
switch (o) { switch (o) {
default: default:
case Lua.OP_UNM: op = "neg"; break; case Lua.OP_UNM: op = "neg"; break;
case Lua.OP_BNOT: op = "bnot"; break;
case Lua.OP_NOT: op = "not"; break; case Lua.OP_NOT: op = "not"; break;
case Lua.OP_LEN: op = "len"; break; case Lua.OP_LEN: op = "len"; break;
} }
@@ -535,6 +536,11 @@ public class JavaBuilder {
case Lua.OP_MUL: op = "mul"; break; case Lua.OP_MUL: op = "mul"; break;
case Lua.OP_DIV: op = "div"; break; case Lua.OP_DIV: op = "div"; break;
case Lua.OP_IDIV: op = "idiv"; break; case Lua.OP_IDIV: op = "idiv"; break;
case Lua.OP_BAND: op = "band"; break;
case Lua.OP_BOR: op = "bor"; break;
case Lua.OP_BXOR: op = "bxor"; break;
case Lua.OP_SHL: op = "shl"; break;
case Lua.OP_SHR: op = "shr"; break;
case Lua.OP_MOD: op = "mod"; break; case Lua.OP_MOD: op = "mod"; break;
case Lua.OP_POW: op = "pow"; break; case Lua.OP_POW: op = "pow"; break;
} }

View File

@@ -112,6 +112,7 @@ public class JavaGen {
break; break;
case Lua.OP_UNM: /* A B R(A):= -R(B) */ case Lua.OP_UNM: /* A B R(A):= -R(B) */
case Lua.OP_BNOT: /* A B R(A):= ~R(B) */
case Lua.OP_NOT: /* A B R(A):= not R(B) */ case Lua.OP_NOT: /* A B R(A):= not R(B) */
case Lua.OP_LEN: /* A B R(A):= length of R(B) */ case Lua.OP_LEN: /* A B R(A):= length of R(B) */
builder.loadLocal( pc, b ); builder.loadLocal( pc, b );
@@ -166,6 +167,11 @@ public class JavaGen {
case Lua.OP_MUL: /* A B C R(A):= RK(B) * RK(C) */ case Lua.OP_MUL: /* A B C R(A):= RK(B) * RK(C) */
case Lua.OP_DIV: /* A B C R(A):= RK(B) / RK(C) */ case Lua.OP_DIV: /* A B C R(A):= RK(B) / RK(C) */
case Lua.OP_IDIV: /* A B C R(A):= RK(B) // RK(C) */ case Lua.OP_IDIV: /* A B C R(A):= RK(B) // RK(C) */
case Lua.OP_BAND: /* A B C R(A):= RK(B) & RK(C) */
case Lua.OP_BOR: /* A B C R(A):= RK(B) | RK(C) */
case Lua.OP_BXOR: /* A B C R(A):= RK(B) ~ RK(C) */
case Lua.OP_SHL: /* A B C R(A):= RK(B) << RK(C) */
case Lua.OP_SHR: /* A B C R(A):= RK(B) >> RK(C) */
case Lua.OP_MOD: /* A B C R(A):= RK(B) % RK(C) */ case Lua.OP_MOD: /* A B C R(A):= RK(B) % RK(C) */
case Lua.OP_POW: /* A B C R(A):= RK(B) ^ RK(C) */ case Lua.OP_POW: /* A B C R(A):= RK(B) ^ RK(C) */
loadLocalOrConstant( p, builder, pc, b ); loadLocalOrConstant( p, builder, pc, b );

View File

@@ -176,6 +176,7 @@ public class ProtoInfo {
case Lua.OP_MOVE:/* A B R(A) := R(B) */ case Lua.OP_MOVE:/* A B R(A) := R(B) */
case Lua.OP_UNM: /* A B R(A) := -R(B) */ case Lua.OP_UNM: /* A B R(A) := -R(B) */
case Lua.OP_BNOT: /* A B R(A) := ~R(B) */
case Lua.OP_NOT: /* A B R(A) := not R(B) */ case Lua.OP_NOT: /* A B R(A) := not R(B) */
case Lua.OP_LEN: /* A B R(A) := length of R(B) */ case Lua.OP_LEN: /* A B R(A) := length of R(B) */
case Lua.OP_TESTSET: /* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ case Lua.OP_TESTSET: /* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */
@@ -190,6 +191,11 @@ public class ProtoInfo {
case Lua.OP_MUL: /* A B C R(A) := RK(B) * RK(C) */ case Lua.OP_MUL: /* A B C R(A) := RK(B) * RK(C) */
case Lua.OP_DIV: /* A B C R(A) := RK(B) / RK(C) */ case Lua.OP_DIV: /* A B C R(A) := RK(B) / RK(C) */
case Lua.OP_IDIV: /* A B C R(A) := RK(B) // RK(C) */ case Lua.OP_IDIV: /* A B C R(A) := RK(B) // RK(C) */
case Lua.OP_BAND: /* A B C R(A) := RK(B) & RK(C) */
case Lua.OP_BOR: /* A B C R(A) := RK(B) | RK(C) */
case Lua.OP_BXOR: /* A B C R(A) := RK(B) ~ RK(C) */
case Lua.OP_SHL: /* A B C R(A) := RK(B) << RK(C) */
case Lua.OP_SHR: /* A B C R(A) := RK(B) >> RK(C) */
case Lua.OP_MOD: /* A B C R(A) := RK(B) % RK(C) */ case Lua.OP_MOD: /* A B C R(A) := RK(B) % RK(C) */
case Lua.OP_POW: /* A B C R(A) := RK(B) ^ RK(C) */ case Lua.OP_POW: /* A B C R(A) := RK(B) ^ RK(C) */
a = Lua.GETARG_A( ins ); a = Lua.GETARG_A( ins );

View File

@@ -980,6 +980,26 @@ public class LuaParser implements LuaParserConstants {
jj_consume_token(85); jj_consume_token(85);
{if (true) return Lua.OP_DIV;} {if (true) return Lua.OP_DIV;}
break; break;
case BAND:
jj_consume_token(BAND);
{if (true) return Lua.OP_BAND;}
break;
case BOR:
jj_consume_token(BOR);
{if (true) return Lua.OP_BOR;}
break;
case BNOT:
jj_consume_token(BNOT);
{if (true) return Lua.OP_BXOR;}
break;
case SHL:
jj_consume_token(SHL);
{if (true) return Lua.OP_SHL;}
break;
case SHR:
jj_consume_token(SHR);
{if (true) return Lua.OP_SHR;}
break;
case 86: case 86:
jj_consume_token(86); jj_consume_token(86);
{if (true) return Lua.OP_POW;} {if (true) return Lua.OP_POW;}
@@ -1046,6 +1066,10 @@ public class LuaParser implements LuaParserConstants {
jj_consume_token(69); jj_consume_token(69);
{if (true) return Lua.OP_LEN;} {if (true) return Lua.OP_LEN;}
break; break;
case BNOT:
jj_consume_token(BNOT);
{if (true) return Lua.OP_BNOT;}
break;
default: default:
jj_la1[33] = jj_gen; jj_la1[33] = jj_gen;
jj_consume_token(-1); jj_consume_token(-1);

View File

@@ -114,6 +114,16 @@ public interface LuaParserConstants {
int CHAR = 67; int CHAR = 67;
/** RegularExpression Id. */ /** RegularExpression Id. */
int LF = 68; int LF = 68;
/** RegularExpression Id. */
int BNOT = 95;
/** RegularExpression Id. */
int BAND = 96;
/** RegularExpression Id. */
int BOR = 97;
/** RegularExpression Id. */
int SHL = 98;
/** RegularExpression Id. */
int SHR = 99;
/** Lexical state. */ /** Lexical state. */
int DEFAULT = 0; int DEFAULT = 0;
@@ -237,6 +247,11 @@ public interface LuaParserConstants {
"\">=\"", "\">=\"",
"\"==\"", "\"==\"",
"\"~=\"", "\"~=\"",
"\"~\"",
"\"&\"",
"\"|\"",
"\"<<\"",
"\">>\"",
}; };
} }

View File

@@ -450,6 +450,8 @@ private int jjMoveStringLiteralDfa0_0()
{ {
case 35: case 35:
return jjStopAtPos(0, 69); return jjStopAtPos(0, 69);
case 38:
return jjStopAtPos(0, 96);
case 37: case 37:
return jjStopAtPos(0, 87); return jjStopAtPos(0, 87);
case 40: case 40:
@@ -478,13 +480,13 @@ private int jjMoveStringLiteralDfa0_0()
return jjStopAtPos(0, 70); return jjStopAtPos(0, 70);
case 60: case 60:
jjmatchedKind = 89; jjmatchedKind = 89;
return jjMoveStringLiteralDfa1_0(0x0L, 0x4000000L); return jjMoveStringLiteralDfa1_0(0x0L, 0x84000000L);
case 61: case 61:
jjmatchedKind = 71; jjmatchedKind = 71;
return jjMoveStringLiteralDfa1_0(0x0L, 0x20000000L); return jjMoveStringLiteralDfa1_0(0x0L, 0x20000000L);
case 62: case 62:
jjmatchedKind = 91; jjmatchedKind = 91;
return jjMoveStringLiteralDfa1_0(0x0L, 0x10000000L); return jjMoveStringLiteralDfa1_0(0x0L, 0x110000000L);
case 91: case 91:
jjmatchedKind = 77; jjmatchedKind = 77;
return jjMoveStringLiteralDfa1_0(0x7800L, 0x0L); return jjMoveStringLiteralDfa1_0(0x7800L, 0x0L);
@@ -525,6 +527,7 @@ private int jjMoveStringLiteralDfa0_0()
case 125: case 125:
return jjStopAtPos(0, 81); return jjStopAtPos(0, 81);
case 126: case 126:
jjmatchedKind = 95;
return jjMoveStringLiteralDfa1_0(0x0L, 0x40000000L); return jjMoveStringLiteralDfa1_0(0x0L, 0x40000000L);
default : default :
return jjMoveNfa_0(8, 0); return jjMoveNfa_0(8, 0);
@@ -557,10 +560,18 @@ private int jjMoveStringLiteralDfa1_0(long active0, long active1)
if ((active1 & 0x1L) != 0L) if ((active1 & 0x1L) != 0L)
return jjStopAtPos(1, 28); return jjStopAtPos(1, 28);
break; break;
case 60:
if ((active1 & 0x80000000L) != 0L)
return jjStopAtPos(1, 98);
break;
case 58: case 58:
if ((active1 & 0x2L) != 0L) if ((active1 & 0x2L) != 0L)
return jjStopAtPos(1, 65); return jjStopAtPos(1, 65);
break; break;
case 62:
if ((active1 & 0x100000000L) != 0L)
return jjStopAtPos(1, 99);
break;
case 61: case 61:
if ((active1 & 0x4000000L) != 0L) if ((active1 & 0x4000000L) != 0L)
return jjStopAtPos(1, 90); return jjStopAtPos(1, 90);
@@ -1759,7 +1770,7 @@ public static final int[] jjnewLexState = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
}; };
static final long[] jjtoToken = { static final long[] jjtoToken = {
0x601fffffef800001L, 0x7fffffe2L, 0x601fffffef800001L, 0xfffffffe2L,
}; };
static final long[] jjtoSkip = { static final long[] jjtoSkip = {
0x7e003eL, 0x0L, 0x7e003eL, 0x0L,
@@ -2105,3 +2116,5 @@ private void jjCheckNAddStates(int start, int end)
} }
} }
case 124:
return jjStopAtPos(0, 97);

View File

@@ -47,7 +47,7 @@ public class LuaScriptEngine extends AbstractScriptEngine implements ScriptEngin
private static final String __NAME__ = "Luaj"; private static final String __NAME__ = "Luaj";
private static final String __SHORT_NAME__ = "Luaj"; private static final String __SHORT_NAME__ = "Luaj";
private static final String __LANGUAGE__ = "lua"; private static final String __LANGUAGE__ = "lua";
private static final String __LANGUAGE_VERSION__ = "5.2"; private static final String __LANGUAGE_VERSION__ = "5.3";
private static final String __ARGV__ = "arg"; private static final String __ARGV__ = "arg";
private static final String __FILENAME__ = "?"; private static final String __FILENAME__ = "?";
@@ -244,7 +244,7 @@ public class LuaScriptEngine extends AbstractScriptEngine implements ScriptEngin
case LuaValue.TSTRING: return luajValue.tojstring(); case LuaValue.TSTRING: return luajValue.tojstring();
case LuaValue.TUSERDATA: return luajValue.checkuserdata(Object.class); case LuaValue.TUSERDATA: return luajValue.checkuserdata(Object.class);
case LuaValue.TNUMBER: return luajValue.isinttype()? case LuaValue.TNUMBER: return luajValue.isinttype()?
(Object) Integer.valueOf(luajValue.toint()): (Object) Long.valueOf(luajValue.tolong()):
(Object) Double.valueOf(luajValue.todouble()); (Object) Double.valueOf(luajValue.todouble());
default: return luajValue; default: return luajValue;
} }
@@ -263,4 +263,4 @@ public class LuaScriptEngine extends AbstractScriptEngine implements ScriptEngin
} }
} }
} }

View File

@@ -116,6 +116,127 @@ public class FragmentsTest extends TestSuite {
public void testFloorDivisionInExpression() { public void testFloorDivisionInExpression() {
runFragment(LuaValue.TRUE, "local x=5 local width=10 return x==width//2\n"); runFragment(LuaValue.TRUE, "local x=5 local width=10 return x==width//2\n");
} }
public void testLongIntegerLiteralPrecision() {
runFragment(
LuaValue.varargsOf(new LuaValue[] {
LuaValue.valueOf(9007199254740993L),
LuaValue.valueOf(9007199254740994L),
LuaValue.valueOf(9007199254740992L)
}),
"local x = 9007199254740993\nreturn x, x + 1, x - 1\n");
}
public void testBitwiseOperators() {
runFragment(
LuaValue.varargsOf(new LuaValue[] {
LuaValue.valueOf(2),
LuaValue.valueOf(7),
LuaValue.valueOf(5),
LuaValue.valueOf(12),
LuaValue.valueOf(1),
LuaValue.valueOf(-6)
}),
"return 6 & 3, 6 | 3, 6 ~ 3, 3 << 2, 6 >> 2, ~5\n");
}
public void testBitwisePrecedence() {
runFragment(LuaValue.valueOf(7), "return 1 | 2 & 6\n");
}
public void testTableMove() {
runFragment(
LuaValue.varargsOf(new LuaValue[] {
LuaValue.valueOf(1),
LuaValue.valueOf(2),
LuaValue.valueOf(3),
LuaValue.valueOf(1),
LuaValue.valueOf(2),
LuaValue.valueOf(3)
}),
"local t = {1,2,3}\nlocal d = {}\ntable.move(t, 1, 3, 1, d)\nreturn d[1], d[2], d[3], table.move(t, 1, 3, 2)[2], t[3], t[4]\n");
}
public void testUtf8Library() {
runFragment(
LuaValue.varargsOf(new LuaValue[] {
LuaValue.valueOf(2),
LuaValue.valueOf(2),
LuaValue.valueOf(97),
LuaValue.valueOf(228),
LuaValue.valueOf(2)
}),
"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");
}
public void testStringPackUnpack() {
runFragment(
LuaValue.varargsOf(new LuaValue[] {
LuaValue.valueOf(-5),
LuaValue.valueOf(513),
LuaValue.valueOf("hi"),
LuaValue.valueOf(10),
LuaValue.valueOf(7)
}),
"local s = string.pack('<i4I2z', -5, 513, 'hi')\nlocal a,b,c,n = string.unpack('<i4I2z', s)\nreturn a,b,c,n,string.packsize('<i4I2x')\n");
}
public void testStringPackFixedString() {
runFragment(
LuaValue.varargsOf(new LuaValue[] {
LuaValue.valueOf("ab\000\000"),
LuaValue.valueOf("ab\000\000"),
LuaValue.valueOf(5)
}),
"local s = string.pack('>c4', 'ab')\nreturn s, (string.unpack('>c4', s)), select(2, string.unpack('>c4', s))\n");
}
public void testMath53Helpers() {
runFragment(
LuaValue.varargsOf(new LuaValue[] {
LuaValue.valueOf("integer"),
LuaValue.valueOf(3),
LuaValue.TRUE,
LuaValue.valueOf(Long.MAX_VALUE),
LuaValue.valueOf(Long.MIN_VALUE),
LuaValue.valueOf("Lua 5.3")
}),
"return math.type(3), math.tointeger(3.0), math.ult(-1, 1), math.maxinteger, math.mininteger, _VERSION\n");
}
public void testHexFloatLiteralAndTonumber() {
runFragment(
LuaValue.varargsOf(new LuaValue[] {
LuaValue.valueOf(3.0),
LuaValue.valueOf(3.0),
LuaValue.valueOf(16)
}),
"return 0x1.8p1, tonumber('0x1.8p1'), tonumber('0x10')\n");
}
public void testCoroutineIsYieldable() {
runFragment(
LuaValue.varargsOf(new LuaValue[] {
LuaValue.FALSE,
LuaValue.TRUE
}),
"local co = coroutine.create(function() return coroutine.isyieldable() end)\n" +
"local ok, value = coroutine.resume(co)\n" +
"return coroutine.isyieldable(), value\n");
}
public void testMathRandomSupportsLongBounds() {
runFragment(
LuaValue.varargsOf(new LuaValue[] {
LuaValue.valueOf("integer"),
LuaValue.TRUE
}),
"math.randomseed(123)\nlocal v = math.random(9007199254740993, 9007199254740995)\nreturn math.type(v), v >= 9007199254740993 and v <= 9007199254740995\n");
}
public void testStandardGlobalsDoNotExposeBit32() {
runFragment(LuaValue.TRUE, "return bit32 == nil\n");
}
public void testForloopParamUpvalues() { public void testForloopParamUpvalues() {
runFragment( LuaValue.varargsOf(new LuaValue[] { runFragment( LuaValue.varargsOf(new LuaValue[] {

View File

@@ -40,6 +40,20 @@ public class LuaJavaCoercionTest extends TestCase {
assertEquals( Integer.class, o.getClass() ); assertEquals( Integer.class, o.getClass() );
assertEquals( new Integer(777), o ); assertEquals( new Integer(777), o );
} }
public void testJavaLongToLuaInteger() {
Long l = Long.valueOf(9007199254740993L);
LuaValue v = CoerceJavaToLua.coerce(l);
assertEquals( LuaInteger.class, v.getClass() );
assertEquals( 9007199254740993L, v.tolong() );
}
public void testLuaIntegerToJavaObjectUsesLongWhenNeeded() {
LuaInteger i = LuaInteger.valueOf(9007199254740993L);
Object o = CoerceLuaToJava.coerce(i, Object.class);
assertEquals( Long.class, o.getClass() );
assertEquals( Long.valueOf(9007199254740993L), o );
}
public void testJavaStringToLuaString() { public void testJavaStringToLuaString() {
String s = new String("777"); String s = new String("777");