Add arithmetic metatag processing when left hand side is a number and right hand side has metatable

This commit is contained in:
James Roseborough
2011-11-13 18:08:18 +00:00
parent 4d605cfedc
commit ebb7169f17
3 changed files with 90 additions and 46 deletions

View File

@@ -732,6 +732,7 @@ and LuaForge:
<tr valign="top"><td>&nbsp;&nbsp;<b>2.0.3</b></td><td><ul> <tr valign="top"><td>&nbsp;&nbsp;<b>2.0.3</b></td><td><ul>
<li>Improve coroutine state logic including let unreferenced coroutines be garbage collected </li> <li>Improve coroutine state logic including let unreferenced coroutines be garbage collected </li>
<li>Fix lua command vararg values passed into main script to match what is in global arg table </li> <li>Fix lua command vararg values passed into main script to match what is in global arg table </li>
<li>Add arithmetic metatag processing when left hand side is a number and right hand side has metatable </li>
</ul></td></tr> </ul></td></tr>
</table></td></tr></table> </table></td></tr></table>

View File

@@ -2161,27 +2161,23 @@ public class LuaValue extends Varargs {
public LuaValue add( LuaValue rhs ) { return arithmt(ADD,rhs); } public LuaValue add( LuaValue rhs ) { return arithmt(ADD,rhs); }
/** Add: Perform numeric add operation with another value /** Add: Perform numeric add operation with another value
* of double type without metatag processing * of double type with metatag processing
* <p> * <p>
* {@code this} must derive from {@link LuaNumber} * {@code this} must derive from {@link LuaNumber}
* or derive from {@link LuaString} and be convertible to a number * or derive from {@link LuaString} and be convertible to a number
* <p>
* For metatag processing {@link #add(LuaValue)} must be used
* *
* @param rhs The right-hand-side value to perform the add with * @param rhs The right-hand-side value to perform the add with
* @return value of {@code (this + rhs)} if this is numeric * @return value of {@code (this + rhs)} if this is numeric
* @throws LuaError if {@code this} is not a number or string convertible to number * @throws LuaError if {@code this} is not a number or string convertible to number
* @see #add(LuaValue) * @see #add(LuaValue)
*/ */
public LuaValue add(double rhs) { return aritherror("add"); } public LuaValue add(double rhs) { return arithmtwith(ADD,rhs); }
/** Add: Perform numeric add operation with another value /** Add: Perform numeric add operation with another value
* of int type without metatag processing * of int type with metatag processing
* <p> * <p>
* {@code this} must derive from {@link LuaNumber} * {@code this} must derive from {@link LuaNumber}
* or derive from {@link LuaString} and be convertible to a number * or derive from {@link LuaString} and be convertible to a number
* <p>
* For metatag processing {@link #add(LuaValue)} must be used
* *
* @param rhs The right-hand-side value to perform the add with * @param rhs The right-hand-side value to perform the add with
* @return value of {@code (this + rhs)} if this is numeric * @return value of {@code (this + rhs)} if this is numeric
@@ -2207,12 +2203,10 @@ public class LuaValue extends Varargs {
public LuaValue sub( LuaValue rhs ) { return arithmt(SUB,rhs); } public LuaValue sub( LuaValue rhs ) { return arithmt(SUB,rhs); }
/** Subtract: Perform numeric subtract operation with another value /** Subtract: Perform numeric subtract operation with another value
* of double type without metatag processing * of double type with metatag processing
* <p> * <p>
* {@code this} must derive from {@link LuaNumber} * {@code this} must derive from {@link LuaNumber}
* or derive from {@link LuaString} and be convertible to a number * or derive from {@link LuaString} and be convertible to a number
* <p>
* For metatag processing {@link #sub(LuaValue)} must be used
* *
* @param rhs The right-hand-side value to perform the subtract with * @param rhs The right-hand-side value to perform the subtract with
* @return value of {@code (this - rhs)} if this is numeric * @return value of {@code (this - rhs)} if this is numeric
@@ -2222,12 +2216,10 @@ public class LuaValue extends Varargs {
public LuaValue sub( double rhs ) { return aritherror("sub"); } public LuaValue sub( double rhs ) { return aritherror("sub"); }
/** Subtract: Perform numeric subtract operation with another value /** Subtract: Perform numeric subtract operation with another value
* of int type without metatag processing * of int type with metatag processing
* <p> * <p>
* {@code this} must derive from {@link LuaNumber} * {@code this} must derive from {@link LuaNumber}
* or derive from {@link LuaString} and be convertible to a number * or derive from {@link LuaString} and be convertible to a number
* <p>
* For metatag processing {@link #sub(LuaValue)} must be used
* *
* @param rhs The right-hand-side value to perform the subtract with * @param rhs The right-hand-side value to perform the subtract with
* @return value of {@code (this - rhs)} if this is numeric * @return value of {@code (this - rhs)} if this is numeric
@@ -2237,12 +2229,10 @@ public class LuaValue extends Varargs {
public LuaValue sub( int rhs ) { return aritherror("sub"); } public LuaValue sub( int rhs ) { return aritherror("sub"); }
/** Reverse-subtract: Perform numeric subtract operation from an int value /** Reverse-subtract: Perform numeric subtract operation from an int value
* without metatag processing * with metatag processing
* <p> * <p>
* {@code this} must derive from {@link LuaNumber} * {@code this} must derive from {@link LuaNumber}
* or derive from {@link LuaString} and be convertible to a number * or derive from {@link LuaString} and be convertible to a number
* <p>
* For metatag processing {@link #sub(LuaValue)} must be used
* *
* @param lhs The left-hand-side value from which to perform the subtraction * @param lhs The left-hand-side value from which to perform the subtraction
* @return value of {@code (lhs - this)} if this is numeric * @return value of {@code (lhs - this)} if this is numeric
@@ -2251,7 +2241,7 @@ public class LuaValue extends Varargs {
* @see #sub(double) * @see #sub(double)
* @see #sub(int) * @see #sub(int)
*/ */
public LuaValue subFrom(double lhs) { return aritherror("sub"); } public LuaValue subFrom(double lhs) { return arithmtwith(SUB,lhs); }
/** Reverse-subtract: Perform numeric subtract operation from a double value /** Reverse-subtract: Perform numeric subtract operation from a double value
* without metatag processing * without metatag processing
@@ -2287,27 +2277,23 @@ public class LuaValue extends Varargs {
public LuaValue mul( LuaValue rhs ) { return arithmt(MUL,rhs); } public LuaValue mul( LuaValue rhs ) { return arithmt(MUL,rhs); }
/** Multiply: Perform numeric multiply operation with another value /** Multiply: Perform numeric multiply operation with another value
* of double type without metatag processing * of double type with metatag processing
* <p> * <p>
* {@code this} must derive from {@link LuaNumber} * {@code this} must derive from {@link LuaNumber}
* or derive from {@link LuaString} and be convertible to a number * or derive from {@link LuaString} and be convertible to a number
* <p>
* For metatag processing {@link #mul(LuaValue)} must be used
* *
* @param rhs The right-hand-side value to perform the multiply with * @param rhs The right-hand-side value to perform the multiply with
* @return value of {@code (this * rhs)} if this is numeric * @return value of {@code (this * rhs)} if this is numeric
* @throws LuaError if {@code this} is not a number or string convertible to number * @throws LuaError if {@code this} is not a number or string convertible to number
* @see #mul(LuaValue) * @see #mul(LuaValue)
*/ */
public LuaValue mul(double rhs) { return aritherror("mul"); } public LuaValue mul(double rhs) { return arithmtwith(MUL,rhs); }
/** Multiply: Perform numeric multiply operation with another value /** Multiply: Perform numeric multiply operation with another value
* of int type without metatag processing * of int type with metatag processing
* <p> * <p>
* {@code this} must derive from {@link LuaNumber} * {@code this} must derive from {@link LuaNumber}
* or derive from {@link LuaString} and be convertible to a number * or derive from {@link LuaString} and be convertible to a number
* <p>
* For metatag processing {@link #mul(LuaValue)} must be used
* *
* @param rhs The right-hand-side value to perform the multiply with * @param rhs The right-hand-side value to perform the multiply with
* @return value of {@code (this * rhs)} if this is numeric * @return value of {@code (this * rhs)} if this is numeric
@@ -2332,12 +2318,10 @@ public class LuaValue extends Varargs {
public LuaValue pow( LuaValue rhs ) { return arithmt(POW,rhs); } public LuaValue pow( LuaValue rhs ) { return arithmt(POW,rhs); }
/** Raise to power: Raise this value to a power /** Raise to power: Raise this value to a power
* of double type without metatag processing * of double type with metatag processing
* <p> * <p>
* {@code this} must derive from {@link LuaNumber} * {@code this} must derive from {@link LuaNumber}
* or derive from {@link LuaString} and be convertible to a number * or derive from {@link LuaString} and be convertible to a number
* <p>
* For metatag processing {@link #pow(LuaValue)} must be used
* *
* @param rhs The power to raise this value to * @param rhs The power to raise this value to
* @return value of {@code (this ^ rhs)} if this is numeric * @return value of {@code (this ^ rhs)} if this is numeric
@@ -2347,12 +2331,10 @@ public class LuaValue extends Varargs {
public LuaValue pow( double rhs ) { return aritherror("pow"); } public LuaValue pow( double rhs ) { return aritherror("pow"); }
/** Raise to power: Raise this value to a power /** Raise to power: Raise this value to a power
* of int type without metatag processing * of int type with metatag processing
* <p> * <p>
* {@code this} must derive from {@link LuaNumber} * {@code this} must derive from {@link LuaNumber}
* or derive from {@link LuaString} and be convertible to a number * or derive from {@link LuaString} and be convertible to a number
* <p>
* For metatag processing {@link #pow(LuaValue)} must be used
* *
* @param rhs The power to raise this value to * @param rhs The power to raise this value to
* @return value of {@code (this ^ rhs)} if this is numeric * @return value of {@code (this ^ rhs)} if this is numeric
@@ -2362,12 +2344,10 @@ public class LuaValue extends Varargs {
public LuaValue pow( int rhs ) { return aritherror("pow"); } public LuaValue pow( int rhs ) { return aritherror("pow"); }
/** Reverse-raise to power: Raise another value of double type to this power /** Reverse-raise to power: Raise another value of double type to this power
* without metatag processing * with metatag processing
* <p> * <p>
* {@code this} must derive from {@link LuaNumber} * {@code this} must derive from {@link LuaNumber}
* or derive from {@link LuaString} and be convertible to a number * or derive from {@link LuaString} and be convertible to a number
* <p>
* For metatag processing {@link #pow(LuaValue)} must be used
* *
* @param lhs The left-hand-side value which will be raised to this power * @param lhs The left-hand-side value which will be raised to this power
* @return value of {@code (lhs ^ this)} if this is numeric * @return value of {@code (lhs ^ this)} if this is numeric
@@ -2376,15 +2356,13 @@ public class LuaValue extends Varargs {
* @see #pow(double) * @see #pow(double)
* @see #pow(int) * @see #pow(int)
*/ */
public LuaValue powWith(double lhs) { return aritherror("mul"); } public LuaValue powWith(double lhs) { return arithmtwith(POW,lhs); }
/** Reverse-raise to power: Raise another value of double type to this power /** Reverse-raise to power: Raise another value of double type to this power
* without metatag processing * with metatag processing
* <p> * <p>
* {@code this} must derive from {@link LuaNumber} * {@code this} must derive from {@link LuaNumber}
* or derive from {@link LuaString} and be convertible to a number * or derive from {@link LuaString} and be convertible to a number
* <p>
* For metatag processing {@link #pow(LuaValue)} must be used
* *
* @param lhs The left-hand-side value which will be raised to this power * @param lhs The left-hand-side value which will be raised to this power
* @return value of {@code (lhs ^ this)} if this is numeric * @return value of {@code (lhs ^ this)} if this is numeric
@@ -2442,12 +2420,10 @@ public class LuaValue extends Varargs {
public LuaValue div( int rhs ) { return aritherror("div"); } public LuaValue div( int rhs ) { return aritherror("div"); }
/** Reverse-divide: Perform numeric divide operation into another value /** Reverse-divide: Perform numeric divide operation into another value
* without metatag processing * with metatag processing
* <p> * <p>
* {@code this} must derive from {@link LuaNumber} * {@code this} must derive from {@link LuaNumber}
* or derive from {@link LuaString} and be convertible to a number * or derive from {@link LuaString} and be convertible to a number
* <p>
* For metatag processing {@link #div(LuaValue)} must be used
* *
* @param lhs The left-hand-side value which will be divided by this * @param lhs The left-hand-side value which will be divided by this
* @return value of {@code (lhs / this)} if this is numeric * @return value of {@code (lhs / this)} if this is numeric
@@ -2456,7 +2432,7 @@ public class LuaValue extends Varargs {
* @see #div(double) * @see #div(double)
* @see #div(int) * @see #div(int)
*/ */
public LuaValue divInto(double lhs) { return aritherror("divInto"); } public LuaValue divInto(double lhs) { return arithmtwith(DIV,lhs); }
/** Modulo: Perform numeric modulo operation with another value /** Modulo: Perform numeric modulo operation with another value
* of unknown type, * of unknown type,
@@ -2505,12 +2481,10 @@ public class LuaValue extends Varargs {
public LuaValue mod( int rhs ) { return aritherror("mod"); } public LuaValue mod( int rhs ) { return aritherror("mod"); }
/** Reverse-modulo: Perform numeric modulo operation from another value /** Reverse-modulo: Perform numeric modulo operation from another value
* without metatag processing * with metatag processing
* <p> * <p>
* {@code this} must derive from {@link LuaNumber} * {@code this} must derive from {@link LuaNumber}
* or derive from {@link LuaString} and be convertible to a number * or derive from {@link LuaString} and be convertible to a number
* <p>
* For metatag processing {@link #mod(LuaValue)} must be used
* *
* @param lhs The left-hand-side value which will be modulo'ed by this * @param lhs The left-hand-side value which will be modulo'ed by this
* @return value of {@code (lhs % this)} if this is numeric * @return value of {@code (lhs % this)} if this is numeric
@@ -2519,7 +2493,7 @@ public class LuaValue extends Varargs {
* @see #mod(double) * @see #mod(double)
* @see #mod(int) * @see #mod(int)
*/ */
public LuaValue modFrom(double lhs) { return aritherror("modFrom"); } public LuaValue modFrom(double lhs) { return arithmtwith(MOD,lhs); }
/** Perform metatag processing for arithmetic operations. /** Perform metatag processing for arithmetic operations.
* <p> * <p>
@@ -2552,6 +2526,34 @@ public class LuaValue extends Varargs {
return h.call( this, op2 ); return h.call( this, op2 );
} }
/** Perform metatag processing for arithmetic operations when the left-hand-side is a number.
* <p>
* Finds the supplied metatag value for {@code this} and invokes it,
* or throws {@link LuaError} if neither is defined.
* @param tag The metatag to look up
* @param op1 The value of the left-hand-side to perform the operation with
* @return {@link LuaValue} resulting from metatag processing
* @throws LuaError if metatag was not defined for either operand
* @see #add(LuaValue)
* @see #sub(LuaValue)
* @see #mul(LuaValue)
* @see #pow(LuaValue)
* @see #div(LuaValue)
* @see #mod(LuaValue)
* @see #ADD
* @see #SUB
* @see #MUL
* @see #POW
* @see #DIV
* @see #MOD
*/
protected LuaValue arithmtwith(LuaValue tag, double op1) {
LuaValue h = metatag(tag);
if ( h.isnil() )
error( "attempt to perform arithmetic "+tag+" on number and "+typename() );
return h.call( LuaValue.valueOf(op1), this );
}
/** Less than: Perform numeric or string comparison with another value /** Less than: Perform numeric or string comparison with another value
* of unknown type, * of unknown type,
* including metatag processing, and returning {@link LuaValue}. * including metatag processing, and returning {@link LuaValue}.

View File

@@ -635,6 +635,47 @@ public class UnaryBinaryOperatorsTest extends TestCase {
} }
} }
public void testArithMetatagNumberTable() {
LuaValue zero = LuaValue.ZERO;
LuaValue one = LuaValue.ONE;
LuaValue tbl = new LuaTable();
try { tbl.add(zero); fail("did not throw error"); } catch ( LuaError le ) { };
try { zero.add(tbl); fail("did not throw error"); } catch ( LuaError le ) { };
tbl.setmetatable(LuaValue.tableOf( new LuaValue[] { LuaValue.ADD, RETURN_ONE, } ));
assertEquals( one, tbl.add(zero) );
assertEquals( one, zero.add(tbl) );
try { tbl.sub(zero); fail("did not throw error"); } catch ( LuaError le ) { };
try { zero.sub(tbl); fail("did not throw error"); } catch ( LuaError le ) { };
tbl.setmetatable(LuaValue.tableOf( new LuaValue[] { LuaValue.SUB, RETURN_ONE, } ));
assertEquals( one, tbl.sub(zero) );
assertEquals( one, zero.sub(tbl) );
try { tbl.mul(zero); fail("did not throw error"); } catch ( LuaError le ) { };
try { zero.mul(tbl); fail("did not throw error"); } catch ( LuaError le ) { };
tbl.setmetatable(LuaValue.tableOf( new LuaValue[] { LuaValue.MUL, RETURN_ONE, } ));
assertEquals( one, tbl.mul(zero) );
assertEquals( one, zero.mul(tbl) );
try { tbl.div(zero); fail("did not throw error"); } catch ( LuaError le ) { };
try { zero.div(tbl); fail("did not throw error"); } catch ( LuaError le ) { };
tbl.setmetatable(LuaValue.tableOf( new LuaValue[] { LuaValue.DIV, RETURN_ONE, } ));
assertEquals( one, tbl.div(zero) );
assertEquals( one, zero.div(tbl) );
try { tbl.pow(zero); fail("did not throw error"); } catch ( LuaError le ) { };
try { zero.pow(tbl); fail("did not throw error"); } catch ( LuaError le ) { };
tbl.setmetatable(LuaValue.tableOf( new LuaValue[] { LuaValue.POW, RETURN_ONE, } ));
assertEquals( one, tbl.pow(zero) );
assertEquals( one, zero.pow(tbl) );
try { tbl.mod(zero); fail("did not throw error"); } catch ( LuaError le ) { };
try { zero.mod(tbl); fail("did not throw error"); } catch ( LuaError le ) { };
tbl.setmetatable(LuaValue.tableOf( new LuaValue[] { LuaValue.MOD, RETURN_ONE, } ));
assertEquals( one, tbl.mod(zero) );
assertEquals( one, zero.mod(tbl) );
}
public void testCompareStrings() { public void testCompareStrings() {
// these are lexical compare! // these are lexical compare!