Started with upgrading to Lua 5.3

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

View File

@@ -237,12 +237,12 @@ public class LoadState {
int e = (int)((bits >> 52) & 0x7ffL) - 1023;
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 );
}
}

View File

@@ -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 */

View File

@@ -352,6 +352,26 @@ public class LuaClosure extends LuaFunction {
stack[a] = ((b=i>>>23)>0xff? k[b&0x0ff]: stack[b]).idiv((c=(i>>14)&0x1ff)>0xff? k[c&0x0ff]: stack[c]);
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;

View File

@@ -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); }

View File

@@ -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");
}
}

View File

@@ -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 )

View File

@@ -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 );

View File

@@ -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

View File

@@ -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:

View File

@@ -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;

View File

@@ -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 */
/*

View File

@@ -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 {
}
}
}
}
}

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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.

View File

@@ -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) {