Started with upgrading to Lua 5.3
This commit is contained in:
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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); }
|
||||
|
||||
@@ -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.
|
||||
* <p>
|
||||
* 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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 && m_bytes[j-1]==' ' ) --j;
|
||||
if ( i>=j )
|
||||
return Double.NaN;
|
||||
if ( m_bytes[i]=='0' && i+1<j && (m_bytes[i+1]=='x'||m_bytes[i+1]=='X'))
|
||||
return scanlong(16, i+2, j);
|
||||
int prefix = (m_bytes[i] == '+' || m_bytes[i] == '-') ? i + 1 : i;
|
||||
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);
|
||||
return Double.isNaN(l)? scandouble(i,j): l;
|
||||
}
|
||||
@@ -796,14 +811,15 @@ public class LuaString extends LuaValue {
|
||||
* or Double.NaN if not
|
||||
*/
|
||||
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;
|
||||
boolean neg = (m_bytes[start] == '-');
|
||||
// --- fix starts here ---
|
||||
if(neg && m_bytes.length == 1) {
|
||||
return Double.NaN; // this is only a '-' sign, no parsing any number is required
|
||||
}
|
||||
// --- fix ends here ---
|
||||
for ( int i=(neg?start+1:start); i<end; i++ ) {
|
||||
boolean neg = hasSign && m_bytes[start - 1] == '-';
|
||||
if (start >= end)
|
||||
return Double.NaN;
|
||||
for ( int i=start; i<end; i++ ) {
|
||||
int digit = m_bytes[i] - (base<=10||(m_bytes[i]>='0'&&m_bytes[i]<='9')? '0':
|
||||
m_bytes[i]>='A'&&m_bytes[i]<='Z'? ('A'-10): ('a'-10));
|
||||
if ( digit < 0 || digit >= base )
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
"..", "...", "//", "==", ">=", "<=", "~=",
|
||||
"..", "...", "//", "<<", ">>", "==", ">=", "<=", "~=",
|
||||
"::", "<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_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 */
|
||||
|
||||
|
||||
/*
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<m) argerror(2, "interval is empty");
|
||||
return valueOf( m + random.nextInt(n+1-m) );
|
||||
long lower = a.checklong();
|
||||
long upper = b.checklong();
|
||||
if (upper < lower) argerror(2, "interval is empty");
|
||||
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 {
|
||||
|
||||
@@ -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<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";
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user