diff --git a/src/core/org/luaj/vm2/LuaBoolean.java b/src/core/org/luaj/vm2/LuaBoolean.java index 58b7a22a..31edbc3a 100644 --- a/src/core/org/luaj/vm2/LuaBoolean.java +++ b/src/core/org/luaj/vm2/LuaBoolean.java @@ -70,9 +70,4 @@ public class LuaBoolean extends LuaValue { public LuaValue getmetatable() { return s_metatable; } - - // equality - public boolean eq_b( LuaValue val ) { - return this == val || (s_metatable!=null && val.isboolean() && LuaValue.eqmtcall(this, val, s_metatable)); - } } diff --git a/src/core/org/luaj/vm2/LuaDouble.java b/src/core/org/luaj/vm2/LuaDouble.java index 912c6a4b..69e1bafb 100644 --- a/src/core/org/luaj/vm2/LuaDouble.java +++ b/src/core/org/luaj/vm2/LuaDouble.java @@ -75,7 +75,8 @@ public class LuaDouble extends LuaNumber { public boolean equals(Object o) { return o instanceof LuaDouble? ((LuaDouble)o).v == v: false; } // equality w/ metatable processing - public boolean eq_b( LuaValue val ) { return val.raweq(v) || (s_metatable!=null && val.type()==TNUMBER && LuaValue.eqmtcall(val, this, s_metatable)); } + public LuaValue eq( LuaValue val ) { return val.raweq(v)? TRUE: FALSE; } + public boolean eq_b( LuaValue val ) { return val.raweq(v); } // equality w/o metatable processing public boolean raweq( LuaValue val ) { return val.raweq(v); } diff --git a/src/core/org/luaj/vm2/LuaFunction.java b/src/core/org/luaj/vm2/LuaFunction.java index 0d1ec3c3..7038a055 100644 --- a/src/core/org/luaj/vm2/LuaFunction.java +++ b/src/core/org/luaj/vm2/LuaFunction.java @@ -67,9 +67,4 @@ public class LuaFunction extends LuaValue { public void setfenv(LuaValue env) { this.env = env!=null? env: NIL; } - - // equality - public boolean eq_b( LuaValue val ) { - return this == val || (s_metatable!=null && val.isfunction() && LuaValue.eqmtcall(this, val, s_metatable)); - } } diff --git a/src/core/org/luaj/vm2/LuaInteger.java b/src/core/org/luaj/vm2/LuaInteger.java index b985cea3..99eb38d3 100644 --- a/src/core/org/luaj/vm2/LuaInteger.java +++ b/src/core/org/luaj/vm2/LuaInteger.java @@ -105,7 +105,8 @@ public class LuaInteger extends LuaNumber { public boolean equals(Object o) { return o instanceof LuaInteger? ((LuaInteger)o).v == v: false; } // equality w/ metatable processing - public boolean eq_b( LuaValue val ) { return val.raweq(v) || (s_metatable!=null && val.type()==TNUMBER && LuaValue.eqmtcall(val, this, s_metatable)); } + public LuaValue eq( LuaValue val ) { return val.raweq(v)? TRUE: FALSE; } + public boolean eq_b( LuaValue val ) { return val.raweq(v); } // equality w/o metatable processing public boolean raweq( LuaValue val ) { return val.raweq(v); } diff --git a/src/core/org/luaj/vm2/LuaNil.java b/src/core/org/luaj/vm2/LuaNil.java index 772bc4d1..2c1ff6c1 100644 --- a/src/core/org/luaj/vm2/LuaNil.java +++ b/src/core/org/luaj/vm2/LuaNil.java @@ -83,8 +83,4 @@ public class LuaNil extends LuaValue { public Object optuserdata(Object defval) { return defval; } public Object optuserdata(Class c, Object defval) { return defval; } public LuaValue optvalue(LuaValue defval) { return defval; } - - // equality - public LuaValue eq( LuaValue val ) { return this == val? TRUE: FALSE; } - public boolean eq_b( LuaValue val ) { return this == val; } } diff --git a/src/core/org/luaj/vm2/LuaString.java b/src/core/org/luaj/vm2/LuaString.java index 615c0f16..eab8c0d4 100644 --- a/src/core/org/luaj/vm2/LuaString.java +++ b/src/core/org/luaj/vm2/LuaString.java @@ -298,17 +298,8 @@ public class LuaString extends LuaValue { } // equality w/ metatable processing - public boolean eq_b( LuaValue val ) { - if ( val.raweq(this) ) return true; - if ( s_metatable == null || val.type()!=TSTRING || s_inmeta) return false; - s_inmeta = true; - try { - return LuaValue.eqmtcall(val, this, s_metatable); - } finally { - s_inmeta = false; - } - } - private static boolean s_inmeta = false; + public LuaValue eq( LuaValue val ) { return val.raweq(this)? TRUE: FALSE; } + public boolean eq_b( LuaValue val ) { return val.raweq(this); } // equality w/o metatable processing public boolean raweq( LuaValue val ) { diff --git a/src/core/org/luaj/vm2/LuaTable.java b/src/core/org/luaj/vm2/LuaTable.java index 905d22fc..d2808f82 100644 --- a/src/core/org/luaj/vm2/LuaTable.java +++ b/src/core/org/luaj/vm2/LuaTable.java @@ -577,6 +577,7 @@ public class LuaTable extends LuaValue { } // equality w/ metatable processing + public LuaValue eq( LuaValue val ) { return eq_b(val)? TRUE: FALSE; } public boolean eq_b( LuaValue val ) { if ( this == val ) return true; if ( m_metatable == null || !val.istable() ) return false; diff --git a/src/core/org/luaj/vm2/LuaThread.java b/src/core/org/luaj/vm2/LuaThread.java index ff145ed7..01a34374 100644 --- a/src/core/org/luaj/vm2/LuaThread.java +++ b/src/core/org/luaj/vm2/LuaThread.java @@ -242,9 +242,4 @@ public class LuaThread extends LuaValue implements Runnable { } } - - // equality - public boolean eq_b( LuaValue val ) { - return this == val || (s_metatable!=null && val.isthread() && LuaValue.eqmtcall(this, val, s_metatable)); - } } diff --git a/src/core/org/luaj/vm2/LuaUserdata.java b/src/core/org/luaj/vm2/LuaUserdata.java index d7d79d14..a790838f 100644 --- a/src/core/org/luaj/vm2/LuaUserdata.java +++ b/src/core/org/luaj/vm2/LuaUserdata.java @@ -105,8 +105,8 @@ public class LuaUserdata extends LuaValue { } // equality w/ metatable processing - public LuaValue eq( LuaValue val ) { return val.eq_b(this)? TRUE: FALSE; } - public boolean eq_b( LuaUserdata val ) { + public LuaValue eq( LuaValue val ) { return eq_b(val)? TRUE: FALSE; } + public boolean eq_b( LuaValue val ) { if ( val.raweq(this) ) return true; if ( m_metatable == null || !val.isuserdata() ) return false; LuaValue valmt = val.getmetatable(); diff --git a/src/core/org/luaj/vm2/LuaValue.java b/src/core/org/luaj/vm2/LuaValue.java index f8b93e19..9e8ab277 100644 --- a/src/core/org/luaj/vm2/LuaValue.java +++ b/src/core/org/luaj/vm2/LuaValue.java @@ -256,9 +256,9 @@ public class LuaValue extends Varargs { public boolean equals(Object obj) { return this == obj; } // arithmetic equality with metatag processing - public LuaValue eq( LuaValue val ) { return eq_b(val)? TRUE: FALSE; } - public boolean eq_b( LuaValue val ) { return false; } - public LuaValue neq( LuaValue val ) { return eq_b(val)? FALSE: TRUE; } + public LuaValue eq( LuaValue val ) { return this == val? TRUE: FALSE; } + public boolean eq_b( LuaValue val ) { return this == val; } + public LuaValue neq( LuaValue val ) { return eq_b(val)? FALSE: TRUE; } public boolean neq_b( LuaValue val ) { return !eq_b(val); } // equality without metatag processing @@ -273,10 +273,6 @@ public class LuaValue extends Varargs { LuaValue h = lhsmt.rawget(EQ); return h.isnil() || h!=rhsmt.rawget(EQ)? false: h.call(lhs,rhs).toboolean(); } - public static final boolean eqmtcall(LuaValue lhs, LuaValue rhs, LuaValue sharedmt) { - LuaValue h = sharedmt.rawget(EQ); - return h.isnil()? false: h.call(lhs,rhs).toboolean(); - } // arithmetic operators public LuaValue add( LuaValue rhs ) { return arithmt(ADD,rhs); } diff --git a/src/core/org/luaj/vm2/lib/BaseLib.java b/src/core/org/luaj/vm2/lib/BaseLib.java index d07f698b..cc08a2e9 100644 --- a/src/core/org/luaj/vm2/lib/BaseLib.java +++ b/src/core/org/luaj/vm2/lib/BaseLib.java @@ -303,9 +303,11 @@ public class BaseLib extends OneArgFunction implements ResourceFinder { case 17: { // "tostring", // (e) -> value LuaValue arg = args.checkvalue(1); LuaValue h = arg.metatag(TOSTRING); - if ( ! h.isnil() ) return h.call(arg); + if ( ! h.isnil() ) + return h.call(arg); LuaValue v = arg.tostring(); - if ( ! v.isnil() ) return v; + if ( ! v.isnil() ) + return v; return valueOf(arg.tojstring()); } case 18: { // "tonumber", // (e [,base]) -> value diff --git a/test/junit/org/luaj/vm2/UnaryBinaryOperatorsTest.java b/test/junit/org/luaj/vm2/UnaryBinaryOperatorsTest.java index 5bfc5586..702bf00e 100644 --- a/test/junit/org/luaj/vm2/UnaryBinaryOperatorsTest.java +++ b/test/junit/org/luaj/vm2/UnaryBinaryOperatorsTest.java @@ -235,6 +235,10 @@ public class UnaryBinaryOperatorsTest extends TestCase { LuaValue tbl = new LuaTable(); LuaValue tbl2 = new LuaTable(); LuaValue tbl3 = new LuaTable(); + LuaValue uda = new LuaUserdata(new Object()); + LuaValue udb = new LuaUserdata(uda.touserdata()); + LuaValue uda2 = new LuaUserdata(new Object()); + LuaValue uda3 = new LuaUserdata(uda.touserdata()); LuaValue nilb = LuaValue.valueOf( LuaValue.NIL.toboolean() ); LuaValue oneb = LuaValue.valueOf( LuaValue.ONE.toboolean() ); assertEquals( LuaValue.FALSE, nilb ); @@ -247,26 +251,30 @@ public class UnaryBinaryOperatorsTest extends TestCase { LuaString.s_metatable = LuaValue.tableOf( new LuaValue[] { LuaValue.EQ, RETURN_NIL, } ); tbl.setmetatable(LuaValue.tableOf( new LuaValue[] { LuaValue.EQ, RETURN_NIL, } )); tbl2.setmetatable(LuaValue.tableOf( new LuaValue[] { LuaValue.EQ, RETURN_NIL, } )); + uda.setmetatable(LuaValue.tableOf( new LuaValue[] { LuaValue.EQ, RETURN_NIL, } )); + udb.setmetatable(uda.getmetatable()); + uda2.setmetatable(LuaValue.tableOf( new LuaValue[] { LuaValue.EQ, RETURN_NIL, } )); // diff metatag function tbl3.setmetatable(LuaValue.tableOf( new LuaValue[] { LuaValue.EQ, RETURN_ONE, } )); + uda3.setmetatable(LuaValue.tableOf( new LuaValue[] { LuaValue.EQ, RETURN_ONE, } )); - // same type, same value, does not invoke metatag op + // primitive types or same valu do not invoke metatag as per C implementation assertEquals( tru, tru.eq(tru) ); - assertEquals( tru, tbl.eq(tbl) ); assertEquals( tru, one.eq(one) ); - // same type, different value, same metatag op. comparabile via metatag op - assertEquals( nilb, tbl.eq(tbl2) ); - assertEquals( nilb, tbl2.eq(tbl) ); - assertEquals( nilb, tru.eq(fal) ); - assertEquals( nilb, fal.eq(tru) ); - assertEquals( nilb, zer.eq(one) ); - assertEquals( nilb, one.eq(zer) ); - assertEquals( nilb, pi.eq(ee) ); - assertEquals( nilb, ee.eq(pi) ); - assertEquals( nilb, pi.eq(one) ); - assertEquals( nilb, one.eq(pi) ); - assertEquals( nilb, abc.eq(def) ); - assertEquals( nilb, def.eq(abc) ); + assertEquals( tru, abc.eq(abc) ); + assertEquals( tru, tbl.eq(tbl) ); + assertEquals( tru, uda.eq(uda) ); + assertEquals( tru, uda.eq(udb) ); + assertEquals( fal, tru.eq(fal) ); + assertEquals( fal, fal.eq(tru) ); + assertEquals( fal, zer.eq(one) ); + assertEquals( fal, one.eq(zer) ); + assertEquals( fal, pi.eq(ee) ); + assertEquals( fal, ee.eq(pi) ); + assertEquals( fal, pi.eq(one) ); + assertEquals( fal, one.eq(pi) ); + assertEquals( fal, abc.eq(def) ); + assertEquals( fal, def.eq(abc) ); // different types. not comparable assertEquals( fal, fal.eq(tbl) ); assertEquals( fal, tbl.eq(fal) ); @@ -276,9 +284,20 @@ public class UnaryBinaryOperatorsTest extends TestCase { assertEquals( fal, one.eq(fal) ); assertEquals( fal, abc.eq(one) ); assertEquals( fal, one.eq(abc) ); + assertEquals( fal, tbl.eq(uda) ); + assertEquals( fal, uda.eq(tbl) ); + // same type, same value, does not invoke metatag op + assertEquals( tru, tbl.eq(tbl) ); + // same type, different value, same metatag op. comparabile via metatag op + assertEquals( nilb, tbl.eq(tbl2) ); + assertEquals( nilb, tbl2.eq(tbl) ); + assertEquals( nilb, uda.eq(uda2) ); + assertEquals( nilb, uda2.eq(uda) ); // same type, different metatag ops. not comparable assertEquals( fal, tbl.eq(tbl3) ); assertEquals( fal, tbl3.eq(tbl) ); + assertEquals( fal, uda.eq(uda3) ); + assertEquals( fal, uda3.eq(uda) ); // always use right argument LuaBoolean.s_metatable = LuaValue.tableOf( new LuaValue[] { LuaValue.EQ, RETURN_ONE, } ); @@ -286,26 +305,30 @@ public class UnaryBinaryOperatorsTest extends TestCase { LuaString.s_metatable = LuaValue.tableOf( new LuaValue[] { LuaValue.EQ, RETURN_ONE, } ); tbl.setmetatable(LuaValue.tableOf( new LuaValue[] { LuaValue.EQ, RETURN_ONE, } )); tbl2.setmetatable(LuaValue.tableOf( new LuaValue[] { LuaValue.EQ, RETURN_ONE, } )); + uda.setmetatable(LuaValue.tableOf( new LuaValue[] { LuaValue.EQ, RETURN_ONE, } )); + udb.setmetatable(uda.getmetatable()); + uda2.setmetatable(LuaValue.tableOf( new LuaValue[] { LuaValue.EQ, RETURN_ONE, } )); // diff metatag function tbl3.setmetatable(LuaValue.tableOf( new LuaValue[] { LuaValue.EQ, RETURN_NIL, } )); + uda3.setmetatable(LuaValue.tableOf( new LuaValue[] { LuaValue.EQ, RETURN_NIL, } )); - // same type, same value, does not invoke metatag op + // primitive types or same value do not invoke metatag as per C implementation assertEquals( tru, tru.eq(tru) ); - assertEquals( tru, tbl.eq(tbl) ); assertEquals( tru, one.eq(one) ); - // same type, different value, same metatag op. comparabile via metatag op - assertEquals( oneb, tbl.eq(tbl2) ); - assertEquals( oneb, tbl2.eq(tbl) ); - assertEquals( oneb, tru.eq(fal) ); - assertEquals( oneb, fal.eq(tru) ); - assertEquals( oneb, zer.eq(one) ); - assertEquals( oneb, one.eq(zer) ); - assertEquals( oneb, pi.eq(ee) ); - assertEquals( oneb, ee.eq(pi) ); - assertEquals( oneb, pi.eq(one) ); - assertEquals( oneb, one.eq(pi) ); - assertEquals( oneb, abc.eq(def) ); - assertEquals( oneb, def.eq(abc) ); + assertEquals( tru, abc.eq(abc) ); + assertEquals( tru, tbl.eq(tbl) ); + assertEquals( tru, uda.eq(uda) ); + assertEquals( tru, uda.eq(udb) ); + assertEquals( fal, tru.eq(fal) ); + assertEquals( fal, fal.eq(tru) ); + assertEquals( fal, zer.eq(one) ); + assertEquals( fal, one.eq(zer) ); + assertEquals( fal, pi.eq(ee) ); + assertEquals( fal, ee.eq(pi) ); + assertEquals( fal, pi.eq(one) ); + assertEquals( fal, one.eq(pi) ); + assertEquals( fal, abc.eq(def) ); + assertEquals( fal, def.eq(abc) ); // different types. not comparable assertEquals( fal, fal.eq(tbl) ); assertEquals( fal, tbl.eq(fal) ); @@ -315,9 +338,20 @@ public class UnaryBinaryOperatorsTest extends TestCase { assertEquals( fal, one.eq(fal) ); assertEquals( fal, abc.eq(one) ); assertEquals( fal, one.eq(abc) ); + assertEquals( fal, tbl.eq(uda) ); + assertEquals( fal, uda.eq(tbl) ); + // same type, same value, does not invoke metatag op + assertEquals( tru, tbl.eq(tbl) ); + // same type, different value, same metatag op. comparabile via metatag op + assertEquals( oneb, tbl.eq(tbl2) ); + assertEquals( oneb, tbl2.eq(tbl) ); + assertEquals( oneb, uda.eq(uda2) ); + assertEquals( oneb, uda2.eq(uda) ); // same type, different metatag ops. not comparable assertEquals( fal, tbl.eq(tbl3) ); assertEquals( fal, tbl3.eq(tbl) ); + assertEquals( fal, uda.eq(uda3) ); + assertEquals( fal, uda3.eq(uda) ); } finally { LuaBoolean.s_metatable = null; diff --git a/test/lua/metatags.lua b/test/lua/metatags.lua index 0edfb438..676590be 100644 --- a/test/lua/metatags.lua +++ b/test/lua/metatags.lua @@ -1,15 +1,15 @@ -print( '---- initial metatables' ) -local anumber = 111 -local aboolean = false -local afunction = function() end -local athread = coroutine.create( afunction ) -local atable = {} +local anumber,bnumber = 111,23.45 +local astring,bstring = "abc","def" +local anumstr,bnumstr = tostring(anumber),tostring(bnumber) +local aboolean,bboolean = false,true +local afunction,bfunction = function() end, function() end +local athread,bthead = coroutine.create(afunction),coroutine.create(bfunction) +local atable,btable = {},{} local values = { anumber, aboolean, afunction, athread, atable } -for i=1,#values do - print( debug.getmetatable( values[i] ) ) -end +local groups local ts = tostring local tb,count = {},0 + tostring = function(o) local t = type(o) if t~='thread' and t~='function' and t~='table' then return ts(o) end @@ -21,11 +21,23 @@ tostring = function(o) end local buildop = function(name) + return function(a,b) + print( 'mt.__'..name..'()', a, b ) + return '__'..name..'-result' + end +end +local buildop3 = function(name) return function(a,b,c) print( 'mt.__'..name..'()', a, b, c ) return '__'..name..'-result' end end +local buildop1 = function(name) + return function(a) + print( 'mt.__'..name..'()', a ) + return '__'..name..'-result' + end +end local mt = { __call=buildop('call'), @@ -35,17 +47,12 @@ local mt = { __div=buildop('div'), __pow=buildop('pow'), __mod=buildop('mod'), - __unm=buildop('unm'), - __len=buildop('neg'), - __eq=buildop('eq'), + __unm=buildop1('unm'), + __len=buildop1('len'), __lt=buildop('lt'), __le=buildop('le'), - __tostring=function(a,b) - return 'mt.__tostring('..type(a)..','..type(b)..')' - end, - __metatable={}, __index=buildop('index'), - __newindex=buildop('newindex'), + __newindex=buildop3('newindex'), __concat=buildop('concat'), } @@ -56,9 +63,48 @@ ecall = function(pattern, ...) return s,e end +print( '---- __eq same types' ) +local eqmt = { __eq=buildop('eq'), } +groups = { {nil,nil}, {true,false}, {123,456}, {11,5.5}, {afunction,bfunction}, {athread,bthread}, {astring,bstring}, {anumber,anumstr} } +for i=1,#groups do + local a,b = groups[i][1], groups[i][2] + local amt,bmt = debug.getmetatable(a),debug.getmetatable(b) + print( type(a), type(b), 'before', pcall( function() return a==b end ) ) + print( type(a), type(b), 'before', pcall( function() return a~=b end ) ) + print( debug.setmetatable( a, eqmt ) ) + print( debug.setmetatable( b, eqmt ) ) + print( type(a), type(b), 'after', pcall( function() return a==b end ) ) + print( type(a), type(b), 'after', pcall( function() return a~=b end ) ) + print( debug.setmetatable( a, amt ) ) + print( debug.setmetatable( b, bmt ) ) +end + +print( '---- __eq, tables - should invoke metatag comparison' ) +groups = { {atable,btable} } +for i=1,#groups do + local a,b = groups[i][1], groups[i][2] + local amt,bmt = debug.getmetatable(a),debug.getmetatable(b) + print( type(a), type(b), 'before', pcall( function() return a==b end ) ) + print( type(a), type(b), 'before', pcall( function() return a~=b end ) ) + print( debug.setmetatable( a, eqmt ) ) + print( debug.setmetatable( b, eqmt ) ) + print( type(a), type(b), 'after-a', pcall( function() return a==b end ) ) + print( type(a), type(b), 'after-a', pcall( function() return a~=b end ) ) + print( debug.setmetatable( a, amt ) ) + print( debug.setmetatable( b, bmt ) ) +end + + +print( 'nilmt', debug.getmetatable(nil) ) +print( 'boolmt', debug.getmetatable(true) ) +print( 'number', debug.getmetatable(1) ) +print( 'function', debug.getmetatable(afunction) ) +print( 'thread', debug.getmetatable(athread) ) + print( '---- __call' ) for i=1,#values do local a = values[i] + local amt = debug.getmetatable(a) print( type(a), 'before', ecall( 'attempt to call', function() return a('a','b') end ) ) print( debug.setmetatable( a, mt ) ) print( type(a), 'after', pcall( function() return a() end ) ) @@ -66,13 +112,14 @@ for i=1,#values do print( type(a), 'after', pcall( function() return a('a','b') end ) ) print( type(a), 'after', pcall( function() return a('a','b','c') end ) ) print( type(a), 'after', pcall( function() return a('a','b','c','d') end ) ) - print( debug.setmetatable( a, nil ) ) + print( debug.setmetatable( a, amt ) ) end print( '---- __add, __sub, __mul, __div, __pow, __mod' ) local groups = { {aboolean, aboolean}, {aboolean, athread}, {aboolean, afunction}, {aboolean, "abc"}, {aboolean, atable} } for i=1,#groups do local a,b = groups[i][1], groups[i][2] + local amt,bmt = debug.getmetatable(a),debug.getmetatable(b) print( type(a), type(b), 'before', ecall( 'attempt to perform arithmetic', function() return a+b end ) ) print( type(a), type(b), 'before', ecall( 'attempt to perform arithmetic', function() return b+a end ) ) print( type(a), type(b), 'before', ecall( 'attempt to perform arithmetic', function() return a-b end ) ) @@ -94,29 +141,33 @@ for i=1,#groups do print( type(a), type(b), 'after', pcall( function() return b^a end ) ) print( type(a), type(b), 'after', pcall( function() return a%b end ) ) print( type(a), type(b), 'after', pcall( function() return b%a end ) ) - print( debug.setmetatable( a, nil ) ) + print( debug.setmetatable( a, amt ) ) + print( debug.setmetatable( b, bmt ) ) end print( '---- __len' ) -values = { aboolean, afunction, athread } +values = { aboolean, afunction, athread, anumber } for i=1,#values do local a = values[i] + local amt = debug.getmetatable(a) print( type(a), 'before', ecall( 'attempt to get length of ', function() return #a end ) ) print( debug.setmetatable( a, mt ) ) print( type(a), 'after', pcall( function() return #a end ) ) - print( debug.setmetatable( a, nil ) ) + print( debug.setmetatable( a, amt ) ) end - +-- print( '---- __neg' ) -values = { aboolean, afunction, athread, "abcd", atable } +values = { aboolean, afunction, athread, "abcd", atable, anumber } for i=1,#values do - print( type(values[i]), 'before', ecall( 'attempt to get length of ', function() return #values[i] end ) ) - print( debug.setmetatable( values[i], mt ) ) - print( type(values[i]), 'after', pcall( function() return #values[i] end ) ) - print( debug.setmetatable( values[i], nil ) ) + local a = values[i] + local amt = debug.getmetatable(a) + print( type(v), 'before', ecall( 'attempt to perform arithmetic ', function() return -a end ) ) + print( debug.setmetatable( a, mt ) ) + print( type(v), 'after', pcall( function() return -a end ) ) + print( debug.setmetatable( a, amt ) ) end -print( '---- __eq, __lt, __le, same types' ) +print( '---- __lt, __le, same types' ) local bfunction = function() end local bthread = coroutine.create( bfunction ) local btable = {} @@ -124,69 +175,59 @@ local groups groups = { {true, true}, {true, false}, {afunction, bfunction}, {athread, bthread}, {atable, atable}, {atable, btable} } for i=1,#groups do local a,b = groups[i][1], groups[i][2] - print( type(a), type(b), 'before', pcall( function() return a==b end ) ) - print( type(a), type(b), 'before', pcall( function() return a~=b end ) ) + local amt,bmt = debug.getmetatable(a),debug.getmetatable(b) print( type(a), type(b), 'before', ecall( 'attempt to compare', function() return ab end ) ) print( type(a), type(b), 'before', ecall( 'attempt to compare', function() return a>=b end ) ) print( debug.setmetatable( a, mt ) ) print( debug.setmetatable( b, mt ) ) - print( type(a), type(b), 'after', pcall( function() return a==b end ) ) - print( type(a), type(b), 'after', pcall( function() return a~=b end ) ) print( type(a), type(b), 'after', pcall( function() return ab end ) ) print( type(a), type(b), 'after', pcall( function() return a>=b end ) ) - print( debug.setmetatable( a, nil ) ) - print( debug.setmetatable( b, nil ) ) + print( debug.setmetatable( a, amt ) ) + print( debug.setmetatable( b, bmt ) ) end -print( '---- __eq, __lt, __le, different types' ) +print( '---- __lt, __le, different types' ) groups = { {aboolean, athread}, } for i=1,#groups do local a,b = groups[i][1], groups[i][2] - print( type(a), type(b), 'before', pcall( function() return a==b end ) ) - print( type(a), type(b), 'before', pcall( function() return a~=b end ) ) + local amt,bmt = debug.getmetatable(a),debug.getmetatable(b) print( type(a), type(b), 'before', ecall( 'attempt to compare', function() return ab end ) ) print( type(a), type(b), 'before', ecall( 'attempt to compare', function() return a>=b end ) ) print( debug.setmetatable( a, mt ) ) print( debug.setmetatable( b, mt ) ) - print( type(a), type(b), 'after-a', pcall( function() return a==b end ) ) - print( type(a), type(b), 'after-a', pcall( function() return a~=b end ) ) print( type(a), type(b), 'after-a', ecall( 'attempt to compare', function() return ab end ) ) print( type(a), type(b), 'after-a', ecall( 'attempt to compare', function() return a>=b end ) ) - print( debug.setmetatable( a, nil ) ) - print( debug.setmetatable( b, nil ) ) + print( debug.setmetatable( a, amt ) ) + print( debug.setmetatable( b, bmt ) ) end print( '---- __tostring' ) values = { aboolean, afunction, athread, atable, "abc" } +local strmt = { __tostring=function(a) + return 'mt.__tostring('..type(a)..')' + end, +} for i=1,#values do local a = values[i] - print( debug.setmetatable( a, mt ) ) + local amt = debug.getmetatable(a) + print( debug.setmetatable( a, strmt ) ) print( type(a), 'after', pcall( function() return ts(a) end ) ) - print( debug.setmetatable( a, nil ) ) -end - -print( '---- __metatable' ) -values = { aboolean, afunction, athread, atable, "abc" } -for i=1,#values do - local a = values[i] - print( type(a), 'before', pcall( function() return debug.getmetatable(a), getmetatable(a) end ) ) - print( debug.setmetatable( a, mt ) ) - print( type(a), 'after', pcall( function() return debug.getmetatable(a), getmetatable(a) end ) ) - print( debug.setmetatable( a, nil ) ) + print( debug.setmetatable( a, amt ) ) end print( '---- __index, __newindex' ) values = { aboolean, anumber, afunction, athread } for i=1,#values do local a = values[i] + local amt = debug.getmetatable(a) print( type(a), 'before', ecall( 'attempt to index', function() return a.foo end ) ) print( type(a), 'before', ecall( 'attempt to index', function() return a[123] end ) ) print( type(a), 'before', ecall( 'index', function() a.foo = 'bar' end ) ) @@ -198,7 +239,7 @@ for i=1,#values do print( type(a), 'after', pcall( function() a.foo = 'bar' end ) ) print( type(a), 'after', pcall( function() a[123] = 'bar' end ) ) print( type(a), 'after', ecall( 'attempt to call', function() return a:foo() end ) ) - print( debug.setmetatable( a, nil ) ) + print( debug.setmetatable( a, amt ) ) end print( '---- __concat' ) @@ -216,6 +257,7 @@ local concatmt = { } for i=1,#groups do local a,b = groups[i][1], groups[i][2] + local amt,bmt = debug.getmetatable(a),debug.getmetatable(b) print( type(a), type(b), 'before', ecall( 'attempt to concatenate ', function() return a..b end ) ) print( type(a), type(b), 'before', ecall( 'attempt to concatenate ', function() return b..a end ) ) print( type(a), type(s), type(t), 'before', ecall( 'attempt to concatenate ', function() return a..s..t end ) ) @@ -227,6 +269,18 @@ for i=1,#groups do print( type(a), type(s), type(t), 'before', pcall( function() return a..s..t end ) ) print( type(s), type(a), type(t), 'before', ecall( 'attempt to concatenate ', function() return s..a..t end ) ) print( type(s), type(t), type(a), 'before', ecall( 'attempt to concatenate ', function() return s..t..a end ) ) - print( debug.setmetatable( a, nil ) ) + print( debug.setmetatable( a, amt ) ) + print( debug.setmetatable( b, bmt ) ) end +print( '---- __metatable' ) +values = { aboolean, afunction, athread, atable, "abc" } +local mtmt = { __metatable={}, } +for i=1,#values do + local a = values[i] + local amt = debug.getmetatable(a) + print( type(a), 'before', pcall( function() return debug.getmetatable(a), getmetatable(a) end ) ) + print( debug.setmetatable( a, mtmt ) ) + print( type(a), 'after', pcall( function() return debug.getmetatable(a), getmetatable(a) end ) ) + print( debug.setmetatable( a, amt ) ) +end