Fix metamethods for compare with numbers.

```
t = {}
t.__lt = function (a,b,c)
  collectgarbage()
  assert(c == nil)
  if type(a) == 'table' then a = a.x end
  if type(b) == 'table' then b = b.x end
 return a<b, "dummy"
end

function Op(x) return setmetatable({x=x}, t) end

local function test ()
  assert(not(Op(1)<Op(1)) and (Op(1)<Op(2)) and not(Op(2)<Op(1)))
  assert(not(1 < Op(1)) and (Op(1) < 2) and not(2 < Op(1)))
  assert(not(Op('a')<Op('a')) and (Op('a')<Op('b')) and not(Op('b')<Op('a')))
  assert(not('a' < Op('a')) and (Op('a') < 'b') and not(Op('b') < Op('a')))
  assert((Op(1)<=Op(1)) and (Op(1)<=Op(2)) and not(Op(2)<=Op(1)))
  assert((Op('a')<=Op('a')) and (Op('a')<=Op('b')) and not(Op('b')<=Op('a')))
  assert(not(Op(1)>Op(1)) and not(Op(1)>Op(2)) and (Op(2)>Op(1)))
  assert(not(Op('a')>Op('a')) and not(Op('a')>Op('b')) and (Op('b')>Op('a')))
  assert((Op(1)>=Op(1)) and not(Op(1)>=Op(2)) and (Op(2)>=Op(1)))
  assert((1 >= Op(1)) and not(1 >= Op(2)) and (Op(2) >= 1))
  assert((Op('a')>=Op('a')) and not(Op('a')>=Op('b')) and (Op('b')>=Op('a')))
  assert(('a' >= Op('a')) and not(Op('a') >= 'b') and (Op('b') >= Op('a')))
end

test()
```
This commit is contained in:
Enyby
2019-11-11 02:47:19 +02:00
parent 725cf89b6f
commit ca64666242
2 changed files with 59 additions and 59 deletions

View File

@@ -24,18 +24,18 @@ package org.luaj.vm2;
import org.luaj.vm2.lib.MathLib; import org.luaj.vm2.lib.MathLib;
/** /**
* Extension of {@link LuaNumber} which can hold a Java double as its value. * Extension of {@link LuaNumber} which can hold a Java double as its value.
* <p> * <p>
* These instance are not instantiated directly by clients, but indirectly * These instance are not instantiated directly by clients, but indirectly
* via the static functions {@link LuaValue#valueOf(int)} or {@link LuaValue#valueOf(double)} * via the static functions {@link LuaValue#valueOf(int)} or {@link LuaValue#valueOf(double)}
* functions. This ensures that values which can be represented as int * functions. This ensures that values which can be represented as int
* are wrapped in {@link LuaInteger} instead of {@link LuaDouble}. * are wrapped in {@link LuaInteger} instead of {@link LuaDouble}.
* <p> * <p>
* Almost all API's implemented in LuaDouble are defined and documented in {@link LuaValue}. * Almost all API's implemented in LuaDouble are defined and documented in {@link LuaValue}.
* <p> * <p>
* However the constants {@link #NAN}, {@link #POSINF}, {@link #NEGINF}, * However the constants {@link #NAN}, {@link #POSINF}, {@link #NEGINF},
* {@link #JSTR_NAN}, {@link #JSTR_POSINF}, and {@link #JSTR_NEGINF} may be useful * {@link #JSTR_NAN}, {@link #JSTR_POSINF}, and {@link #JSTR_NEGINF} may be useful
* when dealing with Nan or Infinite values. * when dealing with Nan or Infinite values.
* <p> * <p>
* LuaDouble also defines functions for handling the unique math rules of lua devision and modulo in * LuaDouble also defines functions for handling the unique math rules of lua devision and modulo in
* <ul> * <ul>
@@ -43,7 +43,7 @@ import org.luaj.vm2.lib.MathLib;
* <li>{@link #ddiv_d(double, double)}</li> * <li>{@link #ddiv_d(double, double)}</li>
* <li>{@link #dmod(double, double)}</li> * <li>{@link #dmod(double, double)}</li>
* <li>{@link #dmod_d(double, double)}</li> * <li>{@link #dmod_d(double, double)}</li>
* </ul> * </ul>
* <p> * <p>
* @see LuaValue * @see LuaValue
* @see LuaNumber * @see LuaNumber
@@ -90,7 +90,7 @@ public class LuaDouble extends LuaNumber {
} }
public boolean islong() { public boolean islong() {
return v == (long) v; return v == (long) v;
} }
public byte tobyte() { return (byte) (long) v; } public byte tobyte() { return (byte) (long) v; }
@@ -151,12 +151,12 @@ public class LuaDouble extends LuaNumber {
/** Divide two double numbers according to lua math, and return a {@link LuaValue} result. /** Divide two double numbers according to lua math, and return a {@link LuaValue} result.
* @param lhs Left-hand-side of the division. * @param lhs Left-hand-side of the division.
* @param rhs Right-hand-side of the division. * @param rhs Right-hand-side of the division.
* @return {@link LuaValue} for the result of the division, * @return {@link LuaValue} for the result of the division,
* taking into account positive and negiative infinity, and Nan * taking into account positive and negiative infinity, and Nan
* @see #ddiv_d(double, double) * @see #ddiv_d(double, double)
*/ */
public static LuaValue ddiv(double lhs, double rhs) { public static LuaValue ddiv(double lhs, double rhs) {
return rhs!=0? valueOf( lhs / rhs ): lhs>0? POSINF: lhs==0? NAN: NEGINF; return rhs!=0? valueOf( lhs / rhs ): lhs>0? POSINF: lhs==0? NAN: NEGINF;
} }
/** Divide two double numbers according to lua math, and return a double result. /** Divide two double numbers according to lua math, and return a double result.
@@ -166,15 +166,15 @@ public class LuaDouble extends LuaNumber {
* @see #ddiv(double, double) * @see #ddiv(double, double)
*/ */
public static double ddiv_d(double lhs, double rhs) { public static double ddiv_d(double lhs, double rhs) {
return rhs!=0? lhs / rhs: lhs>0? Double.POSITIVE_INFINITY: lhs==0? Double.NaN: Double.NEGATIVE_INFINITY; return rhs!=0? lhs / rhs: lhs>0? Double.POSITIVE_INFINITY: lhs==0? Double.NaN: Double.NEGATIVE_INFINITY;
} }
/** Take modulo double numbers according to lua math, and return a {@link LuaValue} result. /** Take modulo double numbers according to lua math, and return a {@link LuaValue} result.
* @param lhs Left-hand-side of the modulo. * @param lhs Left-hand-side of the modulo.
* @param rhs Right-hand-side of the modulo. * @param rhs Right-hand-side of the modulo.
* @return {@link LuaValue} for the result of the modulo, * @return {@link LuaValue} for the result of the modulo,
* using lua's rules for modulo * using lua's rules for modulo
* @see #dmod_d(double, double) * @see #dmod_d(double, double)
*/ */
public static LuaValue dmod(double lhs, double rhs) { public static LuaValue dmod(double lhs, double rhs) {
if (rhs == 0 || lhs == Double.POSITIVE_INFINITY || lhs == Double.NEGATIVE_INFINITY) return NAN; if (rhs == 0 || lhs == Double.POSITIVE_INFINITY || lhs == Double.NEGATIVE_INFINITY) return NAN;
@@ -190,7 +190,7 @@ public class LuaDouble extends LuaNumber {
/** Take modulo for double numbers according to lua math, and return a double result. /** Take modulo for double numbers according to lua math, and return a double result.
* @param lhs Left-hand-side of the modulo. * @param lhs Left-hand-side of the modulo.
* @param rhs Right-hand-side of the modulo. * @param rhs Right-hand-side of the modulo.
* @return double value for the result of the modulo, * @return double value for the result of the modulo,
* using lua's rules for modulo * using lua's rules for modulo
* @see #dmod(double, double) * @see #dmod(double, double)
*/ */
@@ -206,28 +206,28 @@ public class LuaDouble extends LuaNumber {
} }
// relational operators // relational operators
public LuaValue lt( LuaValue rhs ) { return rhs.gt_b(v)? LuaValue.TRUE: FALSE; } public LuaValue lt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gt_b(v)? TRUE: FALSE) : super.lt(rhs); }
public LuaValue lt( double rhs ) { return v < rhs? TRUE: FALSE; } public LuaValue lt( double rhs ) { return v < rhs? TRUE: FALSE; }
public LuaValue lt( int rhs ) { return v < rhs? TRUE: FALSE; } public LuaValue lt( int rhs ) { return v < rhs? TRUE: FALSE; }
public boolean lt_b( LuaValue rhs ) { return rhs.gt_b(v); } public boolean lt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gt_b(v) : super.lt_b(rhs); }
public boolean lt_b( int rhs ) { return v < rhs; } public boolean lt_b( int rhs ) { return v < rhs; }
public boolean lt_b( double rhs ) { return v < rhs; } public boolean lt_b( double rhs ) { return v < rhs; }
public LuaValue lteq( LuaValue rhs ) { return rhs.gteq_b(v)? LuaValue.TRUE: FALSE; } public LuaValue lteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gteq_b(v)? TRUE: FALSE) : super.lteq(rhs); }
public LuaValue lteq( double rhs ) { return v <= rhs? TRUE: FALSE; } public LuaValue lteq( double rhs ) { return v <= rhs? TRUE: FALSE; }
public LuaValue lteq( int rhs ) { return v <= rhs? TRUE: FALSE; } public LuaValue lteq( int rhs ) { return v <= rhs? TRUE: FALSE; }
public boolean lteq_b( LuaValue rhs ) { return rhs.gteq_b(v); } public boolean lteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gteq_b(v) : super.lteq_b(rhs); }
public boolean lteq_b( int rhs ) { return v <= rhs; } public boolean lteq_b( int rhs ) { return v <= rhs; }
public boolean lteq_b( double rhs ) { return v <= rhs; } public boolean lteq_b( double rhs ) { return v <= rhs; }
public LuaValue gt( LuaValue rhs ) { return rhs.lt_b(v)? LuaValue.TRUE: FALSE; } public LuaValue gt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lt_b(v)? TRUE: FALSE) : super.gt(rhs); }
public LuaValue gt( double rhs ) { return v > rhs? TRUE: FALSE; } public LuaValue gt( double rhs ) { return v > rhs? TRUE: FALSE; }
public LuaValue gt( int rhs ) { return v > rhs? TRUE: FALSE; } public LuaValue gt( int rhs ) { return v > rhs? TRUE: FALSE; }
public boolean gt_b( LuaValue rhs ) { return rhs.lt_b(v); } public boolean gt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lt_b(v) : super.gt_b(rhs); }
public boolean gt_b( int rhs ) { return v > rhs; } public boolean gt_b( int rhs ) { return v > rhs; }
public boolean gt_b( double rhs ) { return v > rhs; } public boolean gt_b( double rhs ) { return v > rhs; }
public LuaValue gteq( LuaValue rhs ) { return rhs.lteq_b(v)? LuaValue.TRUE: FALSE; } public LuaValue gteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lteq_b(v)? TRUE: FALSE) : super.gteq(rhs); }
public LuaValue gteq( double rhs ) { return v >= rhs? TRUE: FALSE; } public LuaValue gteq( double rhs ) { return v >= rhs? TRUE: FALSE; }
public LuaValue gteq( int rhs ) { return v >= rhs? TRUE: FALSE; } public LuaValue gteq( int rhs ) { return v >= rhs? TRUE: FALSE; }
public boolean gteq_b( LuaValue rhs ) { return rhs.lteq_b(v); } public boolean gteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lteq_b(v) : super.gteq_b(rhs); }
public boolean gteq_b( int rhs ) { return v >= rhs; } public boolean gteq_b( int rhs ) { return v >= rhs; }
public boolean gteq_b( double rhs ) { return v >= rhs; } public boolean gteq_b( double rhs ) { return v >= rhs; }
@@ -236,17 +236,17 @@ public class LuaDouble extends LuaNumber {
public String tojstring() { public String tojstring() {
/* /*
if ( v == 0.0 ) { // never occurs in J2me if ( v == 0.0 ) { // never occurs in J2me
long bits = Double.doubleToLongBits( v ); long bits = Double.doubleToLongBits( v );
return ( bits >> 63 == 0 ) ? "0" : "-0"; return ( bits >> 63 == 0 ) ? "0" : "-0";
} }
*/ */
long l = (long) v; long l = (long) v;
if ( l == v ) if ( l == v )
return Long.toString(l); return Long.toString(l);
if ( Double.isNaN(v) ) if ( Double.isNaN(v) )
return JSTR_NAN; return JSTR_NAN;
if ( Double.isInfinite(v) ) if ( Double.isInfinite(v) )
return (v<0? JSTR_NEGINF: JSTR_POSINF); return (v<0? JSTR_NEGINF: JSTR_POSINF);
return Float.toString((float)v); return Float.toString((float)v);
} }
@@ -268,11 +268,11 @@ public class LuaDouble extends LuaNumber {
} }
public LuaNumber optnumber(LuaNumber defval) { public LuaNumber optnumber(LuaNumber defval) {
return this; return this;
} }
public boolean isnumber() { public boolean isnumber() {
return true; return true;
} }
public boolean isstring() { public boolean isstring() {
@@ -287,14 +287,14 @@ public class LuaDouble extends LuaNumber {
public LuaNumber checknumber() { return this; } public LuaNumber checknumber() { return this; }
public double checkdouble() { return v; } public double checkdouble() { return v; }
public String checkjstring() { public String checkjstring() {
return tojstring(); return tojstring();
} }
public LuaString checkstring() { public LuaString checkstring() {
return LuaString.valueOf(tojstring()); return LuaString.valueOf(tojstring());
} }
public boolean isvalidkey() { public boolean isvalidkey() {
return !Double.isNaN(v); return !Double.isNaN(v);
} }
} }

View File

@@ -24,14 +24,14 @@ package org.luaj.vm2;
import org.luaj.vm2.lib.MathLib; import org.luaj.vm2.lib.MathLib;
/** /**
* Extension of {@link LuaNumber} which can hold a Java int as its value. * Extension of {@link LuaNumber} which can hold a Java int as its value.
* <p> * <p>
* These instance are not instantiated directly by clients, but indirectly * These instance are not instantiated directly by clients, but indirectly
* via the static functions {@link LuaValue#valueOf(int)} or {@link LuaValue#valueOf(double)} * via the static functions {@link LuaValue#valueOf(int)} or {@link LuaValue#valueOf(double)}
* functions. This ensures that policies regarding pooling of instances are * functions. This ensures that policies regarding pooling of instances are
* encapsulated. * encapsulated.
* <p> * <p>
* There are no API's specific to LuaInteger that are useful beyond what is already * There are no API's specific to LuaInteger that are useful beyond what is already
* exposed in {@link LuaValue}. * exposed in {@link LuaValue}.
* *
* @see LuaValue * @see LuaValue
@@ -61,16 +61,16 @@ public class LuaInteger extends LuaNumber {
*/ */
public static LuaNumber valueOf(long l) { public static LuaNumber valueOf(long l) {
int i = (int) l; int i = (int) l;
return l==i? (i<=255 && i>=-256? intValues[i+256]: return l==i? (i<=255 && i>=-256? intValues[i+256]:
(LuaNumber) new LuaInteger(i)): (LuaNumber) new LuaInteger(i)):
(LuaNumber) LuaDouble.valueOf(l); (LuaNumber) LuaDouble.valueOf(l);
} }
/** The value being held by this instance. */ /** The value being held by this instance. */
public final int v; public final int v;
/** /**
* Package protected constructor. * Package protected constructor.
* @see LuaValue#valueOf(int) * @see LuaValue#valueOf(int)
**/ **/
LuaInteger(int i) { LuaInteger(int i) {
@@ -103,15 +103,15 @@ public class LuaInteger extends LuaNumber {
} }
public LuaString optstring(LuaString defval) { public LuaString optstring(LuaString defval) {
return LuaString.valueOf(Integer.toString(v)); return LuaString.valueOf(Integer.toString(v));
} }
public LuaValue tostring() { public LuaValue tostring() {
return LuaString.valueOf(Integer.toString(v)); return LuaString.valueOf(Integer.toString(v));
} }
public String optjstring(String defval) { public String optjstring(String defval) {
return Integer.toString(v); return Integer.toString(v);
} }
public LuaInteger checkinteger() { public LuaInteger checkinteger() {
@@ -172,48 +172,48 @@ public class LuaInteger extends LuaNumber {
public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs,v); } public LuaValue modFrom( double lhs ) { return LuaDouble.dmod(lhs,v); }
// relational operators // relational operators
public LuaValue lt( LuaValue rhs ) { return rhs.gt_b(v)? TRUE: FALSE; } public LuaValue lt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gt_b(v)? TRUE: FALSE) : super.lt(rhs); }
public LuaValue lt( double rhs ) { return v < rhs? TRUE: FALSE; } public LuaValue lt( double rhs ) { return v < rhs? TRUE: FALSE; }
public LuaValue lt( int rhs ) { return v < rhs? TRUE: FALSE; } public LuaValue lt( int rhs ) { return v < rhs? TRUE: FALSE; }
public boolean lt_b( LuaValue rhs ) { return rhs.gt_b(v); } public boolean lt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gt_b(v) : super.lt_b(rhs); }
public boolean lt_b( int rhs ) { return v < rhs; } public boolean lt_b( int rhs ) { return v < rhs; }
public boolean lt_b( double rhs ) { return v < rhs; } public boolean lt_b( double rhs ) { return v < rhs; }
public LuaValue lteq( LuaValue rhs ) { return rhs.gteq_b(v)? TRUE: FALSE; } public LuaValue lteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.gteq_b(v)? TRUE: FALSE) : super.lteq(rhs); }
public LuaValue lteq( double rhs ) { return v <= rhs? TRUE: FALSE; } public LuaValue lteq( double rhs ) { return v <= rhs? TRUE: FALSE; }
public LuaValue lteq( int rhs ) { return v <= rhs? TRUE: FALSE; } public LuaValue lteq( int rhs ) { return v <= rhs? TRUE: FALSE; }
public boolean lteq_b( LuaValue rhs ) { return rhs.gteq_b(v); } public boolean lteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.gteq_b(v) : super.lteq_b(rhs); }
public boolean lteq_b( int rhs ) { return v <= rhs; } public boolean lteq_b( int rhs ) { return v <= rhs; }
public boolean lteq_b( double rhs ) { return v <= rhs; } public boolean lteq_b( double rhs ) { return v <= rhs; }
public LuaValue gt( LuaValue rhs ) { return rhs.lt_b(v)? TRUE: FALSE; } public LuaValue gt( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lt_b(v)? TRUE: FALSE) : super.gt(rhs); }
public LuaValue gt( double rhs ) { return v > rhs? TRUE: FALSE; } public LuaValue gt( double rhs ) { return v > rhs? TRUE: FALSE; }
public LuaValue gt( int rhs ) { return v > rhs? TRUE: FALSE; } public LuaValue gt( int rhs ) { return v > rhs? TRUE: FALSE; }
public boolean gt_b( LuaValue rhs ) { return rhs.lt_b(v); } public boolean gt_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lt_b(v) : super.gt_b(rhs); }
public boolean gt_b( int rhs ) { return v > rhs; } public boolean gt_b( int rhs ) { return v > rhs; }
public boolean gt_b( double rhs ) { return v > rhs; } public boolean gt_b( double rhs ) { return v > rhs; }
public LuaValue gteq( LuaValue rhs ) { return rhs.lteq_b(v)? TRUE: FALSE; } public LuaValue gteq( LuaValue rhs ) { return rhs instanceof LuaNumber ? (rhs.lteq_b(v)? TRUE: FALSE) : super.gteq(rhs); }
public LuaValue gteq( double rhs ) { return v >= rhs? TRUE: FALSE; } public LuaValue gteq( double rhs ) { return v >= rhs? TRUE: FALSE; }
public LuaValue gteq( int rhs ) { return v >= rhs? TRUE: FALSE; } public LuaValue gteq( int rhs ) { return v >= rhs? TRUE: FALSE; }
public boolean gteq_b( LuaValue rhs ) { return rhs.lteq_b(v); } public boolean gteq_b( LuaValue rhs ) { return rhs instanceof LuaNumber ? rhs.lteq_b(v) : super.gteq_b(rhs); }
public boolean gteq_b( int rhs ) { return v >= rhs; } public boolean gteq_b( int rhs ) { return v >= rhs; }
public boolean gteq_b( double rhs ) { return v >= rhs; } public boolean gteq_b( double rhs ) { return v >= rhs; }
// string comparison // string comparison
public int strcmp( LuaString rhs ) { typerror("attempt to compare number with string"); return 0; } public int strcmp( LuaString rhs ) { typerror("attempt to compare number with string"); return 0; }
public int checkint() { public int checkint() {
return v; return v;
} }
public long checklong() { public long checklong() {
return v; return v;
} }
public double checkdouble() { public double checkdouble() {
return v; return v;
} }
public String checkjstring() { public String checkjstring() {
return String.valueOf(v); return String.valueOf(v);
} }
public LuaString checkstring() { public LuaString checkstring() {
return valueOf( String.valueOf(v) ); return valueOf( String.valueOf(v) );
} }
} }