diff --git a/core/src/main/java/org/luaj/vm2/LoadState.java b/core/src/main/java/org/luaj/vm2/LoadState.java
index e353020c..2010eed8 100644
--- a/core/src/main/java/org/luaj/vm2/LoadState.java
+++ b/core/src/main/java/org/luaj/vm2/LoadState.java
@@ -237,12 +237,12 @@ public class LoadState {
int e = (int)((bits >> 52) & 0x7ffL) - 1023;
- if ( e >= 0 && e < 31 ) {
+ if ( e >= 0 && e < 63 ) {
long f = bits & 0xFFFFFFFFFFFFFL;
int shift = 52 - e;
- long intPrecMask = ( 1L << shift ) - 1;
- if ( ( f & intPrecMask ) == 0 ) {
- int intValue = (int)( f >> shift ) | ( 1 << e );
+ long intPrecMask = shift > 0 ? ( 1L << shift ) - 1 : 0;
+ if ( shift <= 52 && ( f & intPrecMask ) == 0 ) {
+ long intValue = shift >= 0 ? (f >> shift) | (1L << e) : (f << (-shift)) | (1L << e);
return LuaInteger.valueOf( ( ( bits >> 63 ) != 0 ) ? -intValue : intValue );
}
}
diff --git a/core/src/main/java/org/luaj/vm2/Lua.java b/core/src/main/java/org/luaj/vm2/Lua.java
index a4148b51..2e55b55e 100644
--- a/core/src/main/java/org/luaj/vm2/Lua.java
+++ b/core/src/main/java/org/luaj/vm2/Lua.java
@@ -30,7 +30,7 @@ package org.luaj.vm2;
*/
public class Lua {
/** 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 */
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_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_MOD = 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_UNM = 20; /* A B R(A) := -R(B) */
- public static final int OP_NOT = 21; /* A B R(A) := not R(B) */
- public static final int OP_LEN = 22; /* A B R(A) := length of R(B) */
+ public static final int OP_BAND = 18; /* 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_BXOR = 20; /* A B C R(A) := RK(B) ~ RK(C) */
+ public static final int OP_SHL = 21; /* A B C R(A) := RK(B) << RK(C) */
+ 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_EQ = 25; /* 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_LE = 27; /* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
+ 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 = 31; /* 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 = 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_TESTSET = 29; /* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */
+ public static final int OP_TEST = 34; /* A C if not (R(A) <=> C) then 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_TAILCALL = 31; /* 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_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 = 37; /* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
+ 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) }*/
- 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_TFORLOOP = 36; /* 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_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 = 42; /* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx } */
+ 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;
@@ -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_DIV */
(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_POW */
(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_LEN */
(0<<7) | (1<<6) | (OpArgR<<4) | (OpArgR<<2) | (iABC), /* OP_CONCAT */
diff --git a/core/src/main/java/org/luaj/vm2/LuaClosure.java b/core/src/main/java/org/luaj/vm2/LuaClosure.java
index 9cd209c2..25e9d60e 100644
--- a/core/src/main/java/org/luaj/vm2/LuaClosure.java
+++ b/core/src/main/java/org/luaj/vm2/LuaClosure.java
@@ -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]);
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) */
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).mod((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
continue;
@@ -364,6 +384,10 @@ public class LuaClosure extends LuaFunction {
stack[a] = stack[i>>>23].neg();
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) */
stack[a] = stack[i>>>23].not();
continue;
diff --git a/core/src/main/java/org/luaj/vm2/LuaDouble.java b/core/src/main/java/org/luaj/vm2/LuaDouble.java
index e38daf67..d9980bde 100644
--- a/core/src/main/java/org/luaj/vm2/LuaDouble.java
+++ b/core/src/main/java/org/luaj/vm2/LuaDouble.java
@@ -75,8 +75,13 @@ public class LuaDouble extends LuaNumber {
final double v;
public static LuaNumber valueOf(double d) {
- int id = (int) d;
- return d==id? (LuaNumber) LuaInteger.valueOf(id): (LuaNumber) new LuaDouble(d);
+ if (!Double.isNaN(d) && !Double.isInfinite(d) && d >= Long.MIN_VALUE && d <= Long.MAX_VALUE) {
+ long ld = (long) d;
+ if (d == ld) {
+ return LuaInteger.valueOf(ld);
+ }
+ }
+ return new LuaDouble(d);
}
/** 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 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 LuaInteger checkinteger() { return LuaInteger.valueOf( (int) (long) v ); }
+ public LuaInteger checkinteger() { if (!islong()) argerror("integer"); return LuaInteger.valueOf((long) v); }
// unary operators
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
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( double val ) { return v == val; }
public boolean raweq( int val ) { return v == val; }
+ public boolean raweq( long val ) { return v == val; }
// basic binary arithmetic
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( int rhs ) { return LuaDouble.didiv(v,rhs); }
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( double rhs ) { return LuaDouble.dmod(v,rhs); }
public LuaValue mod( int rhs ) { return LuaDouble.dmod(v,rhs); }
diff --git a/core/src/main/java/org/luaj/vm2/LuaInteger.java b/core/src/main/java/org/luaj/vm2/LuaInteger.java
index 36f7e5d9..240ff72b 100644
--- a/core/src/main/java/org/luaj/vm2/LuaInteger.java
+++ b/core/src/main/java/org/luaj/vm2/LuaInteger.java
@@ -24,7 +24,7 @@ package org.luaj.vm2;
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.
*
* These instance are not instantiated directly by clients, but indirectly
* 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(double)
*/
- public static LuaNumber valueOf(long l) {
+ public static LuaInteger valueOf(long l) {
int i = (int) l;
- return l==i? (i<=255 && i>=-256? intValues[i+256]:
- (LuaNumber) new LuaInteger(i)):
- (LuaNumber) LuaDouble.valueOf(l);
+ return l == i && i <= 255 && i >= -256 ? intValues[i+256] : new LuaInteger(l);
}
/** The value being held by this instance. */
- public final int v;
+ public final long v;
/**
* Package protected constructor.
* @see LuaValue#valueOf(int)
**/
- LuaInteger(int i) {
+ LuaInteger(long i) {
this.v = i;
}
- public boolean isint() { return true; }
+ public boolean isint() { return v == (int) v; }
public boolean isinttype() { return true; }
public boolean islong() { return true; }
@@ -85,33 +83,33 @@ public class LuaInteger extends LuaNumber {
public char tochar() { return (char) v; }
public double todouble() { return v; }
public float tofloat() { return v; }
- public int toint() { return v; }
+ public int toint() { return (int) v; }
public long tolong() { return v; }
public short toshort() { return (short) 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 long optlong(long defval) { return v; }
public String tojstring() {
- return Integer.toString(v);
+ return Long.toString(v);
}
public LuaString strvalue() {
- return LuaString.valueOf(Integer.toString(v));
+ return LuaString.valueOf(Long.toString(v));
}
public LuaString optstring(LuaString defval) {
- return LuaString.valueOf(Integer.toString(v));
+ return LuaString.valueOf(Long.toString(v));
}
public LuaValue tostring() {
- return LuaString.valueOf(Integer.toString(v));
+ return LuaString.valueOf(Long.toString(v));
}
public String optjstring(String defval) {
- return Integer.toString(v);
+ return Long.toString(v);
}
public LuaInteger checkinteger() {
@@ -123,15 +121,16 @@ public class LuaInteger extends LuaNumber {
}
public int hashCode() {
- return v;
+ return hashCode(v);
}
- public static int hashCode(int x) {
- return x;
+ public static int hashCode(long x) {
+ return (int) (x ^ (x >>> 32));
}
// unary operators
public LuaValue neg() { return valueOf(-(long)v); }
+ public LuaValue bnot() { return valueOf(~v); }
// object equality, used for key comparison
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( double val ) { return v == val; }
public boolean raweq( int val ) { return v == val; }
+ public boolean raweq( long val ) { return v == val; }
// 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( int lhs ) { return LuaInteger.valueOf(lhs + (long)v); }
- public LuaValue sub( LuaValue rhs ) { return rhs.subFrom(v); }
+ public LuaValue add( int lhs ) { return LuaInteger.valueOf(lhs + 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( 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( int lhs ) { return LuaInteger.valueOf(lhs - (long)v); }
- public LuaValue mul( LuaValue rhs ) { return rhs.mul(v); }
+ public LuaValue subFrom( int lhs ) { return LuaInteger.valueOf(lhs - 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( int lhs ) { return LuaInteger.valueOf(lhs * (long)v); }
- public LuaValue pow( LuaValue rhs ) { return rhs.powWith(v); }
+ public LuaValue mul( int lhs ) { return LuaInteger.valueOf(lhs * 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( int rhs ) { return MathLib.dpow(v,rhs); }
public LuaValue powWith( double 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 idiv( LuaValue rhs ) { return rhs.idivInto(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 ) { 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( int rhs ) { return LuaDouble.ddiv(v,rhs); }
public LuaValue divInto( double lhs ) { return LuaDouble.ddiv(lhs,v); }
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 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( 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); }
// 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( 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( 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( 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( 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( 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( 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( 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( 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 checkint() {
- return v;
+ return (int) v;
}
public long checklong() {
return v;
@@ -220,4 +225,41 @@ public class LuaInteger extends LuaNumber {
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");
+ }
+
}
diff --git a/core/src/main/java/org/luaj/vm2/LuaString.java b/core/src/main/java/org/luaj/vm2/LuaString.java
index 5182993d..e3198728 100644
--- a/core/src/main/java/org/luaj/vm2/LuaString.java
+++ b/core/src/main/java/org/luaj/vm2/LuaString.java
@@ -262,6 +262,7 @@ public class LuaString extends LuaValue {
// unary operators
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
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( int rhs ) { return LuaDouble.didiv(checkarith(),rhs); }
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( double 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();
}
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() {
- return (long) checkdouble();
+ double d = scannumber();
+ if (Double.isNaN(d) || d != (long) d)
+ argerror("integer");
+ return (long) d;
}
public double checkdouble() {
double d = scannumber();
@@ -765,8 +777,11 @@ public class LuaString extends LuaValue {
while ( i=j )
return Double.NaN;
- if ( m_bytes[i]=='0' && i+1= end)
+ return Double.NaN;
+ for ( int i=start; i='0'&&m_bytes[i]<='9')? '0':
m_bytes[i]>='A'&&m_bytes[i]<='Z'? ('A'-10): ('a'-10));
if ( digit < 0 || digit >= base )
diff --git a/core/src/main/java/org/luaj/vm2/LuaTable.java b/core/src/main/java/org/luaj/vm2/LuaTable.java
index a35dcc3f..4a764829 100644
--- a/core/src/main/java/org/luaj/vm2/LuaTable.java
+++ b/core/src/main/java/org/luaj/vm2/LuaTable.java
@@ -236,7 +236,7 @@ public class LuaTable extends LuaValue implements Metatable {
}
public LuaValue rawget( LuaValue key ) {
- if ( key.isinttype() ) {
+ if ( key.isint() ) {
int ikey = key.toint();
if ( ikey>0 && ikey<=array.length ) {
LuaValue v = m_metatable == null
@@ -279,7 +279,7 @@ public class LuaTable extends LuaValue implements Metatable {
/** caller must ensure key is not nil */
public void rawset( LuaValue key, LuaValue value ) {
- if ( !key.isinttype() || !arrayset(key.toint(), value) )
+ if ( !key.isint() || !arrayset(key.toint(), value) )
hashset( key, value );
}
@@ -388,7 +388,7 @@ public class LuaTable extends LuaValue implements Metatable {
do {
// find current key index
if ( ! key.isnil() ) {
- if ( key.isinttype() ) {
+ if ( key.isint() ) {
i = key.toint();
if ( i>0 && i<=array.length ) {
break;
@@ -473,7 +473,7 @@ public class LuaTable extends LuaValue implements Metatable {
}
if ( checkLoadFactor() ) {
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.
rehash( key.toint() );
if ( arrayset(key.toint(), value) )
@@ -767,9 +767,9 @@ public class LuaTable extends LuaValue implements Metatable {
}
protected static Entry defaultEntry(LuaValue key, LuaValue value) {
- if ( key.isinttype() ) {
+ if ( key.isint() ) {
return new IntKeyEntry( key.toint(), value );
- } else if (value.type() == TNUMBER) {
+ } else if (value.type() == TNUMBER && !value.isinttype()) {
return new NumberValueEntry( key, value.todouble() );
} else {
return new NormalEntry( key, value );
diff --git a/core/src/main/java/org/luaj/vm2/LuaValue.java b/core/src/main/java/org/luaj/vm2/LuaValue.java
index d13b413e..1862f206 100644
--- a/core/src/main/java/org/luaj/vm2/LuaValue.java
+++ b/core/src/main/java/org/luaj/vm2/LuaValue.java
@@ -216,6 +216,24 @@ public class LuaValue extends Varargs {
/** LuaString constant with value "__idiv" for use as metatag */
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 */
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
*/
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
* @return length as defined by the lua # operator
@@ -2141,6 +2166,15 @@ public class LuaValue extends Varargs {
*/
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
* @param lhs left-hand-side of equality expression
* @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 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
* 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 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
* 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 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
* with metatag processing
@@ -2454,6 +2518,16 @@ public class LuaValue extends Varargs {
public LuaValue divInto(double lhs) { return arithmtwith(DIV,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
* of unknown type,
@@ -3173,6 +3247,13 @@ public class LuaValue extends Varargs {
* @return {@link LuaInteger} instance, possibly pooled, whose value is 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}.
* This may return a {@link LuaInteger} or {@link LuaDouble} depending
diff --git a/core/src/main/java/org/luaj/vm2/Print.java b/core/src/main/java/org/luaj/vm2/Print.java
index 1965658d..b655bf8f 100644
--- a/core/src/main/java/org/luaj/vm2/Print.java
+++ b/core/src/main/java/org/luaj/vm2/Print.java
@@ -277,6 +277,11 @@ public class Print extends Lua {
case OP_MUL:
case OP_DIV:
case OP_IDIV:
+ case OP_BAND:
+ case OP_BOR:
+ case OP_BXOR:
+ case OP_SHL:
+ case OP_SHR:
case OP_POW:
case OP_EQ:
case OP_LT:
diff --git a/core/src/main/java/org/luaj/vm2/compiler/FuncState.java b/core/src/main/java/org/luaj/vm2/compiler/FuncState.java
index b0506963..9f2c4ddb 100644
--- a/core/src/main/java/org/luaj/vm2/compiler/FuncState.java
+++ b/core/src/main/java/org/luaj/vm2/compiler/FuncState.java
@@ -890,6 +890,21 @@ public class FuncState extends Constants {
case OP_IDIV:
r = v1.idiv(v2);
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:
r = v1.mod(v2);
break;
@@ -899,6 +914,9 @@ public class FuncState extends Constants {
case OP_UNM:
r = v1.neg();
break;
+ case OP_BNOT:
+ r = v1.bnot();
+ break;
case OP_LEN:
// r = v1.len();
// break;
@@ -918,7 +936,7 @@ public class FuncState extends Constants {
if (constfolding(op, e1, e2))
return;
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;
int o1 = this.exp2RK(e1);
if (o1 > o2) {
@@ -971,6 +989,15 @@ public class FuncState extends Constants {
this.codearith(OP_LEN, e, e2, line);
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:
_assert (false);
}
@@ -995,6 +1022,11 @@ public class FuncState extends Constants {
case LexState.OPR_MUL:
case LexState.OPR_DIV:
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_POW: {
if (!v.isnumeral())
@@ -1057,6 +1089,21 @@ public class FuncState extends Constants {
case LexState.OPR_IDIV:
this.codearith(OP_IDIV, e1, e2, line);
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:
this.codearith(OP_MOD, e1, e2, line);
break;
diff --git a/core/src/main/java/org/luaj/vm2/compiler/LexState.java b/core/src/main/java/org/luaj/vm2/compiler/LexState.java
index 3cfa0980..bc9b360f 100644
--- a/core/src/main/java/org/luaj/vm2/compiler/LexState.java
+++ b/core/src/main/java/org/luaj/vm2/compiler/LexState.java
@@ -85,15 +85,16 @@ public class LexState extends Constants {
** grep "ORDER OPR" if you change these enums
*/
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_CONCAT=7,
- OPR_NE=8, OPR_EQ=9,
- OPR_LT=10, OPR_LE=11, OPR_GT=12, OPR_GE=13,
- OPR_AND=14, OPR_OR=15,
- OPR_NOBINOPR=16;
+ OPR_ADD=0, OPR_SUB=1, OPR_MUL=2, OPR_DIV=3, OPR_IDIV=4, OPR_BAND=5, OPR_BOR=6,
+ OPR_BXOR=7, OPR_SHL=8, OPR_SHR=9, OPR_MOD=10, OPR_POW=11,
+ OPR_CONCAT=12,
+ OPR_NE=13, OPR_EQ=14,
+ OPR_LT=15, OPR_LE=16, OPR_GT=17, OPR_GE=18,
+ OPR_AND=19, OPR_OR=20,
+ OPR_NOBINOPR=21;
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 */
static final int
@@ -149,7 +150,7 @@ public class LexState extends Constants {
"end", "false", "for", "function", "goto", "if",
"in", "local", "nil", "not", "or", "repeat",
"return", "then", "true", "until", "while",
- "..", "...", "//", "==", ">=", "<=", "~=",
+ "..", "...", "//", "<<", ">>", "==", ">=", "<=", "~=",
"::", "", "", "", "", "",
};
@@ -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_RETURN=274, TK_THEN=275, TK_TRUE=276, TK_UNTIL=277, TK_WHILE=278,
/* 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_DBCOLON=286, TK_EOS=287, TK_NUMBER=288, TK_NAME=289, TK_STRING=290;
+ 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=288, TK_EOS=289, TK_NUMBER=290, TK_NAME=291, TK_STRING=292;
final static int FIRST_RESERVED = TK_AND;
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) {
- char[] c = str.toCharArray();
- int s = 0;
- while ( s < c.length && isspace(c[s]))
- ++s;
- // Check for negative sign
- double sgn = 1.0;
- if (s < c.length && c[s] == '-') {
- sgn = -1.0;
- ++s;
- }
- /* Check for "0x" */
- if (s + 2 >= c.length )
- return LuaValue.ZERO;
- if (c[s++] != '0')
- return LuaValue.ZERO;
- 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
+ String trimmed = str.trim();
+ try {
+ if (trimmed.indexOf('.') < 0 && trimmed.indexOf('p') < 0 && trimmed.indexOf('P') < 0) {
+ boolean negative = trimmed.startsWith("-");
+ boolean positive = trimmed.startsWith("+");
+ int prefix = negative || positive ? 3 : 2;
+ String digits = trimmed.substring(prefix);
+ long value = Long.parseUnsignedLong(digits, 16);
+ if (negative) {
+ if (value == Long.MIN_VALUE) {
+ return LuaValue.valueOf(Long.MIN_VALUE);
+ }
+ return LuaValue.valueOf(-value);
+ }
+ return LuaValue.valueOf(value);
}
+ 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) {
@@ -390,7 +366,12 @@ public class LexState extends Constants {
seminfo.r = strx2number(str, seminfo);
else {
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) {
lexerror("malformed number (" + e.getMessage() + ")", TK_NUMBER);
}
@@ -640,7 +621,10 @@ public class LexState extends Constants {
}
case '<': {
nextChar();
- if (current != '=')
+ if (current == '<') {
+ nextChar();
+ return TK_SHL;
+ } else if (current != '=')
return '<';
else {
nextChar();
@@ -649,7 +633,10 @@ public class LexState extends Constants {
}
case '>': {
nextChar();
- if (current != '=')
+ if (current == '>') {
+ nextChar();
+ return TK_SHR;
+ } else if (current != '=')
return '>';
else {
nextChar();
@@ -1510,6 +1497,8 @@ public class LexState extends Constants {
return OPR_MINUS;
case '#':
return OPR_LEN;
+ case '~':
+ return OPR_BNOT;
default:
return OPR_NOUNOPR;
}
@@ -1528,6 +1517,16 @@ public class LexState extends Constants {
return OPR_DIV;
case TK_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 '%':
return OPR_MOD;
case '^':
@@ -1567,14 +1566,15 @@ public class LexState extends Constants {
};
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, 9), new Priority(5, 4), /* power and concat (right associative) */
- new Priority(3, 3), new Priority(3, 3), /* equality and inequality */
- new Priority(3, 3), new Priority(3, 3), new Priority(3, 3), new Priority(3, 3), /* order */
- new Priority(2, 2), new Priority(1, 1) /* logical (and/or) */
+ 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(5, 5), new Priority(7, 7), new Priority(7, 7), new Priority(11, 11), new Priority(13, 12),
+ new Priority(8, 7),
+ new Priority(3, 3), new Priority(3, 3),
+ 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 */
/*
diff --git a/core/src/main/java/org/luaj/vm2/libs/CoroutineLib.java b/core/src/main/java/org/luaj/vm2/libs/CoroutineLib.java
index f70607ca..3b9f26c2 100644
--- a/core/src/main/java/org/luaj/vm2/libs/CoroutineLib.java
+++ b/core/src/main/java/org/luaj/vm2/libs/CoroutineLib.java
@@ -76,6 +76,7 @@ public class CoroutineLib extends TwoArgFunction {
globals = env.checkglobals();
LuaTable coroutine = new LuaTable();
coroutine.set("create", new Create());
+ coroutine.set("isyieldable", new IsYieldable());
coroutine.set("resume", new Resume());
coroutine.set("running", new Running());
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 {
public Varargs invoke(Varargs args) {
final LuaThread r = globals.running;
@@ -141,4 +149,4 @@ public class CoroutineLib extends TwoArgFunction {
}
}
}
-}
\ No newline at end of file
+}
diff --git a/core/src/main/java/org/luaj/vm2/libs/DebugLib.java b/core/src/main/java/org/luaj/vm2/libs/DebugLib.java
index da6fdb7b..3be24b01 100644
--- a/core/src/main/java/org/luaj/vm2/libs/DebugLib.java
+++ b/core/src/main/java/org/luaj/vm2/libs/DebugLib.java
@@ -817,9 +817,15 @@ public class DebugLib extends TwoArgFunction {
case Lua.OP_MUL: tm = LuaValue.MUL; break;
case Lua.OP_DIV: tm = LuaValue.DIV; 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_POW: tm = LuaValue.POW; 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_LT: tm = LuaValue.LT; break;
case Lua.OP_LE: tm = LuaValue.LE; break;
diff --git a/core/src/main/java/org/luaj/vm2/libs/MathLib.java b/core/src/main/java/org/luaj/vm2/libs/MathLib.java
index d2dfba51..3b37b22d 100644
--- a/core/src/main/java/org/luaj/vm2/libs/MathLib.java
+++ b/core/src/main/java/org/luaj/vm2/libs/MathLib.java
@@ -113,7 +113,9 @@ public class MathLib extends TwoArgFunction {
math.set("huge", LuaDouble.POSINF );
math.set("ldexp", new ldexp());
math.set("max", new max());
+ math.set("maxinteger", LuaValue.valueOf(Long.MAX_VALUE));
math.set("min", new min());
+ math.set("mininteger", LuaValue.valueOf(Long.MIN_VALUE));
math.set("modf", new modf());
math.set("pi", Math.PI );
math.set("pow", new pow());
@@ -124,6 +126,9 @@ public class MathLib extends TwoArgFunction {
math.set("sin", new sin());
math.set("sqrt", new sqrt());
math.set("tan", new tan());
+ math.set("tointeger", new tointeger());
+ math.set("type", new type());
+ math.set("ult", new ult());
env.set("math", math);
if (!env.get("package").isnil()) env.get("package").get("loaded").set("math", math);
return math;
@@ -229,6 +234,34 @@ public class MathLib extends TwoArgFunction {
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 {
Random random = new Random();
@@ -236,17 +269,28 @@ public class MathLib extends TwoArgFunction {
return valueOf( random.nextDouble() );
}
public LuaValue call(LuaValue a) {
- int m = a.checkint();
- if (m<1) argerror(1, "interval is empty");
- return valueOf( 1 + random.nextInt(m) );
+ long upper = a.checklong();
+ if (upper < 1) argerror(1, "interval is empty");
+ return valueOf(nextLong(1, upper));
}
public LuaValue call(LuaValue a, LuaValue b) {
- int m = a.checkint();
- int n = b.checkint();
- if (n 0);
+ return value;
+ }
+ return lower + random.nextLong(bound);
}
-
}
static class randomseed extends OneArgFunction {
diff --git a/core/src/main/java/org/luaj/vm2/libs/StringLib.java b/core/src/main/java/org/luaj/vm2/libs/StringLib.java
index 86de6509..4b7f2d43 100644
--- a/core/src/main/java/org/luaj/vm2/libs/StringLib.java
+++ b/core/src/main/java/org/luaj/vm2/libs/StringLib.java
@@ -23,9 +23,11 @@ package org.luaj.vm2.libs;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.nio.ByteOrder;
import org.luaj.vm2.Buffer;
import org.luaj.vm2.LuaClosure;
+import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
@@ -93,9 +95,12 @@ public class StringLib extends TwoArgFunction {
string.set("len", new len());
string.set("lower", new lower());
string.set("match", new match());
+ string.set("pack", new pack());
+ string.set("packsize", new packsize());
string.set("rep", new rep());
string.set("reverse", new reverse());
string.set("sub", new sub());
+ string.set("unpack", new unpack());
string.set("upper", new upper());
env.set("string", string);
@@ -327,6 +332,149 @@ public class StringLib extends TwoArgFunction {
}
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 values = new java.util.ArrayList();
+ 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";
@@ -745,6 +893,371 @@ public class StringLib extends TwoArgFunction {
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.
diff --git a/core/src/main/java/org/luaj/vm2/libs/TableLib.java b/core/src/main/java/org/luaj/vm2/libs/TableLib.java
index 4c58b853..26e1de59 100644
--- a/core/src/main/java/org/luaj/vm2/libs/TableLib.java
+++ b/core/src/main/java/org/luaj/vm2/libs/TableLib.java
@@ -21,6 +21,7 @@
******************************************************************************/
package org.luaj.vm2.libs;
+import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
@@ -65,6 +66,7 @@ public class TableLib extends TwoArgFunction {
LuaTable table = new LuaTable();
table.set("concat", new concat());
table.set("insert", new insert());
+ table.set("move", new move());
table.set("pack", new pack());
table.set("remove", new remove());
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
static class remove extends VarArgFunction {
public Varargs invoke(Varargs args) {
diff --git a/grammar/Lua52.jj b/grammar/Lua52.jj
index c5e0c26e..24ee23f5 100644
--- a/grammar/Lua52.jj
+++ b/grammar/Lua52.jj
@@ -353,7 +353,7 @@ void FieldSep():
void Binop():
{}
{
- "+" | "-" | "*" | "/" | "//" | "^" | "%" | ".." | "<" | "<=" | ">" | ">=" | "==" | "~=" | |
+"+" | "-" | "*" | "/" | "//" | "&" | "|" | "~" | "<<" | ">>" | "^" | "%" | ".." | "<" | "<=" | ">" | ">=" | "==" | "~=" | |
}
void Unop():
diff --git a/grammar/LuaParser.jj b/grammar/LuaParser.jj
index 2dc3cfa3..05f00df7 100644
--- a/grammar/LuaParser.jj
+++ b/grammar/LuaParser.jj
@@ -510,6 +510,11 @@ int Binop():
| "*" { return Lua.OP_MUL; }
| "/" { return Lua.OP_DIV; }
| "//" { 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_MOD; }
| ".." { return Lua.OP_CONCAT; }
@@ -529,4 +534,5 @@ int Unop():
"-" { return Lua.OP_UNM; }
| { return Lua.OP_NOT; }
| "#" { return Lua.OP_LEN; }
+| "~" { return Lua.OP_BNOT; }
}
diff --git a/jme/src/main/java/org/luaj/vm2/libs/jme/JmePlatform.java b/jme/src/main/java/org/luaj/vm2/libs/jme/JmePlatform.java
index 8619e068..4e27d7fe 100644
--- a/jme/src/main/java/org/luaj/vm2/libs/jme/JmePlatform.java
+++ b/jme/src/main/java/org/luaj/vm2/libs/jme/JmePlatform.java
@@ -25,7 +25,6 @@ import org.luaj.vm2.Globals;
import org.luaj.vm2.LoadState;
import org.luaj.vm2.compiler.LuaC;
import org.luaj.vm2.libs.BaseLib;
-import org.luaj.vm2.libs.Bit32Lib;
import org.luaj.vm2.libs.CoroutineLib;
import org.luaj.vm2.libs.DebugLib;
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.StringLib;
import org.luaj.vm2.libs.TableLib;
+import org.luaj.vm2.libs.Utf8Lib;
/** The {@link JmePlatform} class is a convenience class to standardize
* how globals tables are initialized for the JME platform.
@@ -73,7 +73,6 @@ import org.luaj.vm2.libs.TableLib;
* {@link Globals}
* {@link BaseLib}
* {@link PackageLib}
- * {@link Bit32Lib}
* {@link TableLib}
* {@link StringLib}
* {@link CoroutineLib}
@@ -105,11 +104,11 @@ public class JmePlatform {
Globals globals = new Globals();
globals.load(new BaseLib());
globals.load(new PackageLib());
- globals.load(new Bit32Lib());
globals.load(new OsLib());
globals.load(new MathLib());
globals.load(new TableLib());
globals.load(new StringLib());
+ globals.load(new Utf8Lib());
globals.load(new CoroutineLib());
globals.load(new JmeIoLib());
LoadState.install(globals);
diff --git a/jse/src/main/java/org/luaj/vm2/ast/Exp.java b/jse/src/main/java/org/luaj/vm2/ast/Exp.java
index ed9afc09..0afaae03 100644
--- a/jse/src/main/java/org/luaj/vm2/ast/Exp.java
+++ b/jse/src/main/java/org/luaj/vm2/ast/Exp.java
@@ -89,11 +89,15 @@ public class Exp extends SyntaxElement {
case Lua.OP_OR: return 0;
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_CONCAT: return 3;
- case Lua.OP_ADD: case Lua.OP_SUB: return 4;
- case Lua.OP_MUL: case Lua.OP_DIV: case Lua.OP_IDIV: case Lua.OP_MOD: return 5;
- case Lua.OP_NOT: case Lua.OP_UNM: case Lua.OP_LEN: return 6;
- case Lua.OP_POW: return 7;
+ case Lua.OP_BOR: return 3;
+ case Lua.OP_BXOR: return 4;
+ case Lua.OP_BAND: return 5;
+ case Lua.OP_SHL: case Lua.OP_SHR: return 6;
+ 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);
}
}
diff --git a/jse/src/main/java/org/luaj/vm2/libs/jse/CoerceJavaToLua.java b/jse/src/main/java/org/luaj/vm2/libs/jse/CoerceJavaToLua.java
index 66f7558c..536ab793 100644
--- a/jse/src/main/java/org/luaj/vm2/libs/jse/CoerceJavaToLua.java
+++ b/jse/src/main/java/org/luaj/vm2/libs/jse/CoerceJavaToLua.java
@@ -78,7 +78,7 @@ public class CoerceJavaToLua {
private static final class IntCoercion implements Coercion {
public LuaValue coerce( Object 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( Short.class, intCoercion );
COERCIONS.put( Integer.class, intCoercion );
- COERCIONS.put( Long.class, doubleCoercion );
+ COERCIONS.put( Long.class, intCoercion );
COERCIONS.put( Float.class, doubleCoercion );
COERCIONS.put( Double.class, doubleCoercion );
COERCIONS.put( String.class, stringCoercion );
@@ -160,9 +160,9 @@ public class CoerceJavaToLua {
/**
* Coerse a Java object to a corresponding lua value.
*
- * 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};
- * {@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};
* types inheriting from {@link LuaValue} will be returned without coercion;
* other types will become {@link LuaUserdata}.
diff --git a/jse/src/main/java/org/luaj/vm2/libs/jse/CoerceLuaToJava.java b/jse/src/main/java/org/luaj/vm2/libs/jse/CoerceLuaToJava.java
index b3380152..94c4ce18 100644
--- a/jse/src/main/java/org/luaj/vm2/libs/jse/CoerceLuaToJava.java
+++ b/jse/src/main/java/org/luaj/vm2/libs/jse/CoerceLuaToJava.java
@@ -292,7 +292,10 @@ public class CoerceLuaToJava {
public int score(LuaValue value) {
switch ( value.type() ) {
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:
return inheritanceLevels( targetType, Boolean.class );
case LuaValue.TSTRING:
@@ -308,7 +311,10 @@ public class CoerceLuaToJava {
public Object coerce(LuaValue value) {
switch ( value.type() ) {
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:
return value.toboolean()? Boolean.TRUE: Boolean.FALSE;
case LuaValue.TSTRING:
@@ -369,4 +375,4 @@ public class CoerceLuaToJava {
COERCIONS.put( c, co );
return co;
}
-}
\ No newline at end of file
+}
diff --git a/jse/src/main/java/org/luaj/vm2/libs/jse/JsePlatform.java b/jse/src/main/java/org/luaj/vm2/libs/jse/JsePlatform.java
index c1c82f9f..55cc03ef 100644
--- a/jse/src/main/java/org/luaj/vm2/libs/jse/JsePlatform.java
+++ b/jse/src/main/java/org/luaj/vm2/libs/jse/JsePlatform.java
@@ -26,13 +26,13 @@ import org.luaj.vm2.LoadState;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
import org.luaj.vm2.compiler.LuaC;
-import org.luaj.vm2.libs.Bit32Lib;
import org.luaj.vm2.libs.CoroutineLib;
import org.luaj.vm2.libs.DebugLib;
import org.luaj.vm2.libs.PackageLib;
import org.luaj.vm2.libs.ResourceFinder;
import org.luaj.vm2.libs.StringLib;
import org.luaj.vm2.libs.TableLib;
+import org.luaj.vm2.libs.Utf8Lib;
/** The {@link JsePlatform} class is a convenience class to standardize
* how globals tables are initialized for the JSE platform.
@@ -63,7 +63,6 @@ import org.luaj.vm2.libs.TableLib;
*
{@link Globals}
* {@link JseBaseLib}
* {@link PackageLib}
- * {@link Bit32Lib}
* {@link TableLib}
* {@link StringLib}
* {@link CoroutineLib}
@@ -95,9 +94,9 @@ public class JsePlatform {
Globals globals = new Globals();
globals.load(new JseBaseLib());
globals.load(new PackageLib());
- globals.load(new Bit32Lib());
globals.load(new TableLib());
globals.load(new JseStringLib());
+ globals.load(new Utf8Lib());
globals.load(new CoroutineLib());
globals.load(new JseMathLib());
globals.load(new JseIoLib());
diff --git a/jse/src/main/java/org/luaj/vm2/luajc/JavaBuilder.java b/jse/src/main/java/org/luaj/vm2/luajc/JavaBuilder.java
index c9df8cff..889e05d1 100644
--- a/jse/src/main/java/org/luaj/vm2/luajc/JavaBuilder.java
+++ b/jse/src/main/java/org/luaj/vm2/luajc/JavaBuilder.java
@@ -520,6 +520,7 @@ public class JavaBuilder {
switch (o) {
default:
case Lua.OP_UNM: op = "neg"; break;
+ case Lua.OP_BNOT: op = "bnot"; break;
case Lua.OP_NOT: op = "not"; 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_DIV: op = "div"; 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_POW: op = "pow"; break;
}
diff --git a/jse/src/main/java/org/luaj/vm2/luajc/JavaGen.java b/jse/src/main/java/org/luaj/vm2/luajc/JavaGen.java
index 6fe2d021..380fd26d 100644
--- a/jse/src/main/java/org/luaj/vm2/luajc/JavaGen.java
+++ b/jse/src/main/java/org/luaj/vm2/luajc/JavaGen.java
@@ -112,6 +112,7 @@ public class JavaGen {
break;
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_LEN: /* A B R(A):= length of R(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_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_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_POW: /* A B C R(A):= RK(B) ^ RK(C) */
loadLocalOrConstant( p, builder, pc, b );
diff --git a/jse/src/main/java/org/luaj/vm2/luajc/ProtoInfo.java b/jse/src/main/java/org/luaj/vm2/luajc/ProtoInfo.java
index 25c9e9f6..7f557cf0 100644
--- a/jse/src/main/java/org/luaj/vm2/luajc/ProtoInfo.java
+++ b/jse/src/main/java/org/luaj/vm2/luajc/ProtoInfo.java
@@ -176,6 +176,7 @@ public class ProtoInfo {
case Lua.OP_MOVE:/* 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_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++ */
@@ -190,6 +191,11 @@ public class ProtoInfo {
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_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_POW: /* A B C R(A) := RK(B) ^ RK(C) */
a = Lua.GETARG_A( ins );
diff --git a/jse/src/main/java/org/luaj/vm2/parser/LuaParser.java b/jse/src/main/java/org/luaj/vm2/parser/LuaParser.java
index 1674a1c1..ffa31cca 100644
--- a/jse/src/main/java/org/luaj/vm2/parser/LuaParser.java
+++ b/jse/src/main/java/org/luaj/vm2/parser/LuaParser.java
@@ -980,6 +980,26 @@ public class LuaParser implements LuaParserConstants {
jj_consume_token(85);
{if (true) return Lua.OP_DIV;}
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:
jj_consume_token(86);
{if (true) return Lua.OP_POW;}
@@ -1046,6 +1066,10 @@ public class LuaParser implements LuaParserConstants {
jj_consume_token(69);
{if (true) return Lua.OP_LEN;}
break;
+ case BNOT:
+ jj_consume_token(BNOT);
+ {if (true) return Lua.OP_BNOT;}
+ break;
default:
jj_la1[33] = jj_gen;
jj_consume_token(-1);
diff --git a/jse/src/main/java/org/luaj/vm2/parser/LuaParserConstants.java b/jse/src/main/java/org/luaj/vm2/parser/LuaParserConstants.java
index 30c44c29..e0da5472 100644
--- a/jse/src/main/java/org/luaj/vm2/parser/LuaParserConstants.java
+++ b/jse/src/main/java/org/luaj/vm2/parser/LuaParserConstants.java
@@ -114,6 +114,16 @@ public interface LuaParserConstants {
int CHAR = 67;
/** RegularExpression Id. */
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. */
int DEFAULT = 0;
@@ -237,6 +247,11 @@ public interface LuaParserConstants {
"\">=\"",
"\"==\"",
"\"~=\"",
+ "\"~\"",
+ "\"&\"",
+ "\"|\"",
+ "\"<<\"",
+ "\">>\"",
};
}
diff --git a/jse/src/main/java/org/luaj/vm2/parser/LuaParserTokenManager.java b/jse/src/main/java/org/luaj/vm2/parser/LuaParserTokenManager.java
index ca130b2f..aed79893 100644
--- a/jse/src/main/java/org/luaj/vm2/parser/LuaParserTokenManager.java
+++ b/jse/src/main/java/org/luaj/vm2/parser/LuaParserTokenManager.java
@@ -450,6 +450,8 @@ private int jjMoveStringLiteralDfa0_0()
{
case 35:
return jjStopAtPos(0, 69);
+ case 38:
+ return jjStopAtPos(0, 96);
case 37:
return jjStopAtPos(0, 87);
case 40:
@@ -478,13 +480,13 @@ private int jjMoveStringLiteralDfa0_0()
return jjStopAtPos(0, 70);
case 60:
jjmatchedKind = 89;
- return jjMoveStringLiteralDfa1_0(0x0L, 0x4000000L);
+ return jjMoveStringLiteralDfa1_0(0x0L, 0x84000000L);
case 61:
jjmatchedKind = 71;
return jjMoveStringLiteralDfa1_0(0x0L, 0x20000000L);
case 62:
jjmatchedKind = 91;
- return jjMoveStringLiteralDfa1_0(0x0L, 0x10000000L);
+ return jjMoveStringLiteralDfa1_0(0x0L, 0x110000000L);
case 91:
jjmatchedKind = 77;
return jjMoveStringLiteralDfa1_0(0x7800L, 0x0L);
@@ -525,6 +527,7 @@ private int jjMoveStringLiteralDfa0_0()
case 125:
return jjStopAtPos(0, 81);
case 126:
+ jjmatchedKind = 95;
return jjMoveStringLiteralDfa1_0(0x0L, 0x40000000L);
default :
return jjMoveNfa_0(8, 0);
@@ -557,10 +560,18 @@ private int jjMoveStringLiteralDfa1_0(long active0, long active1)
if ((active1 & 0x1L) != 0L)
return jjStopAtPos(1, 28);
break;
+ case 60:
+ if ((active1 & 0x80000000L) != 0L)
+ return jjStopAtPos(1, 98);
+ break;
case 58:
if ((active1 & 0x2L) != 0L)
return jjStopAtPos(1, 65);
break;
+ case 62:
+ if ((active1 & 0x100000000L) != 0L)
+ return jjStopAtPos(1, 99);
+ break;
case 61:
if ((active1 & 0x4000000L) != 0L)
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,
};
static final long[] jjtoToken = {
- 0x601fffffef800001L, 0x7fffffe2L,
+ 0x601fffffef800001L, 0xfffffffe2L,
};
static final long[] jjtoSkip = {
0x7e003eL, 0x0L,
@@ -2105,3 +2116,5 @@ private void jjCheckNAddStates(int start, int end)
}
}
+ case 124:
+ return jjStopAtPos(0, 97);
diff --git a/jse/src/main/java/org/luaj/vm2/script/LuaScriptEngine.java b/jse/src/main/java/org/luaj/vm2/script/LuaScriptEngine.java
index e8525c0e..297f480d 100644
--- a/jse/src/main/java/org/luaj/vm2/script/LuaScriptEngine.java
+++ b/jse/src/main/java/org/luaj/vm2/script/LuaScriptEngine.java
@@ -47,7 +47,7 @@ public class LuaScriptEngine extends AbstractScriptEngine implements ScriptEngin
private static final String __NAME__ = "Luaj";
private static final String __SHORT_NAME__ = "Luaj";
private static final String __LANGUAGE__ = "lua";
- private static final String __LANGUAGE_VERSION__ = "5.2";
+ private static final String __LANGUAGE_VERSION__ = "5.3";
private static final String __ARGV__ = "arg";
private static final String __FILENAME__ = "?";
@@ -244,7 +244,7 @@ public class LuaScriptEngine extends AbstractScriptEngine implements ScriptEngin
case LuaValue.TSTRING: return luajValue.tojstring();
case LuaValue.TUSERDATA: return luajValue.checkuserdata(Object.class);
case LuaValue.TNUMBER: return luajValue.isinttype()?
- (Object) Integer.valueOf(luajValue.toint()):
+ (Object) Long.valueOf(luajValue.tolong()):
(Object) Double.valueOf(luajValue.todouble());
default: return luajValue;
}
@@ -263,4 +263,4 @@ public class LuaScriptEngine extends AbstractScriptEngine implements ScriptEngin
}
}
-}
\ No newline at end of file
+}
diff --git a/jse/src/test/java/org/luaj/vm2/FragmentsTest.java b/jse/src/test/java/org/luaj/vm2/FragmentsTest.java
index 12a19bc5..be93e45f 100644
--- a/jse/src/test/java/org/luaj/vm2/FragmentsTest.java
+++ b/jse/src/test/java/org/luaj/vm2/FragmentsTest.java
@@ -116,6 +116,127 @@ public class FragmentsTest extends TestSuite {
public void testFloorDivisionInExpression() {
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('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() {
runFragment( LuaValue.varargsOf(new LuaValue[] {
diff --git a/jse/src/test/java/org/luaj/vm2/libs/jse/LuaJavaCoercionTest.java b/jse/src/test/java/org/luaj/vm2/libs/jse/LuaJavaCoercionTest.java
index 16e536a9..64ac13fd 100644
--- a/jse/src/test/java/org/luaj/vm2/libs/jse/LuaJavaCoercionTest.java
+++ b/jse/src/test/java/org/luaj/vm2/libs/jse/LuaJavaCoercionTest.java
@@ -40,6 +40,20 @@ public class LuaJavaCoercionTest extends TestCase {
assertEquals( Integer.class, o.getClass() );
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() {
String s = new String("777");