--- source: src/main.rs expression: compiled input_file: test-data/lua5.3-tests/events.lua --- print('testing metatables'); local debug = require('debug') X = 20 B = 30 _ENV = setmetatable({}, { __index = _G }) collectgarbage(); X = X + 10 assert(X == 30 && _G.X == 20); B = false assert(B == false); B = nil assert(B == 30); assert(getmetatable({}) == nil); assert(getmetatable(4) == nil); assert(getmetatable(nil) == nil); a = { name = "NAME" } setmetatable(a, { __metatable = "xuxu", __tostring = fn (x) { return x.name } }); assert(getmetatable(a) == "xuxu"); assert(tostring(a) == "NAME"); assert(pcall(setmetatable, a, {}) == false); a.name = "gororoba" assert(tostring(a) == "gororoba"); local a, t = { 10, 20, 30, x = "10", y = "20" }, {} assert(setmetatable(a, t) == a); assert(getmetatable(a) == t); assert(setmetatable(a, nil) == a); assert(getmetatable(a) == nil); assert(setmetatable(a, t) == a); global fn f(t, i, e) { assert(!e); local p = rawget(t, "parent") return (p && p[(i)] + 3), "dummy return" } t.__index = f a.parent = { z = 25, x = 12, 4 = 24 } assert(a[(1)] == 10 && a.z == 28 && a[(4)] == 27 && a.x == "10"); collectgarbage(); a = setmetatable({}, t) global fn f(t, i, v) { rawset(t, i, v - 3); } setmetatable(t, t); t.__newindex = f a[(1)] = 30 a.x = "101" a[(5)] = 200 assert(a[(1)] == 27 && a.x == 98 && a[(5)] == 197); { local mt = {} mt.__newindex = mt local t = setmetatable({}, mt) t[(1)] = 10 assert(mt[(1)] == 10); } local c = {} a = setmetatable({}, t) t.__newindex = c a[(1)] = 10 a[(2)] = 20 a[(3)] = 90 assert(c[(1)] == 10 && c[(2)] == 20 && c[(3)] == 90); { local a a = setmetatable({}, { __index = setmetatable({}, { __index = setmetatable({}, { __index = fn (_, n) { return a[(n - 3)] + 4, "lixo" } }) }) }) a[(0)] = 20 for i = 0, 10 { assert(a[(i * 3)] == 20 + i * 4); } } { local foi local a = {} for i = 1, 10 { a[(i)] = 0 a[('a' .. i)] = 0 } setmetatable(a, { __newindex = fn (t, k, v) { foi = true rawset(t, k, v); } }); foi = false a[(1)] = 0 assert(!foi); foi = false a[('a1')] = 0 assert(!foi); foi = false a[('a11')] = 0 assert(foi); foi = false a[(11)] = 0 assert(foi); foi = false a[(1)] = nil assert(!foi); foi = false a[(1)] = nil assert(foi); } setmetatable(t, nil); global fn f(t, ...) { return t, { ... } } t.__call = f { local x, y = a(table.unpack({ 'a', 1 })) assert(x == a && y[(1)] == 'a' && y[(2)] == 1 && y[(3)] == nil); x, y = a() assert(x == a && y[(1)] == nil); } local b = setmetatable({}, t) setmetatable(b, t); global fn f(op) { return fn (...) { cap = { 0 = op, ... } return (...) } } t.__add = f("add") t.__sub = f("sub") t.__mul = f("mul") t.__div = f("div") t.__idiv = f("idiv") t.__mod = f("mod") t.__unm = f("unm") t.__pow = f("pow") t.__len = f("len") t.__band = f("band") t.__bor = f("bor") t.__bxor = f("bxor") t.__shl = f("shl") t.__shr = f("shr") t.__bnot = f("bnot") assert(b + 5 == b); assert(cap[(0)] == "add" && cap[(1)] == b && cap[(2)] == 5 && cap[(3)] == nil); assert(b + '5' == b); assert(cap[(0)] == "add" && cap[(1)] == b && cap[(2)] == '5' && cap[(3)] == nil); assert(5 + b == 5); assert(cap[(0)] == "add" && cap[(1)] == 5 && cap[(2)] == b && cap[(3)] == nil); assert('5' + b == '5'); assert(cap[(0)] == "add" && cap[(1)] == '5' && cap[(2)] == b && cap[(3)] == nil); b = b - 3 assert(getmetatable(b) == t); assert(5 - a == 5); assert(cap[(0)] == "sub" && cap[(1)] == 5 && cap[(2)] == a && cap[(3)] == nil); assert('5' - a == '5'); assert(cap[(0)] == "sub" && cap[(1)] == '5' && cap[(2)] == a && cap[(3)] == nil); assert(a * a == a); assert(cap[(0)] == "mul" && cap[(1)] == a && cap[(2)] == a && cap[(3)] == nil); assert(a / 0 == a); assert(cap[(0)] == "div" && cap[(1)] == a && cap[(2)] == 0 && cap[(3)] == nil); assert(a % 2 == a); assert(cap[(0)] == "mod" && cap[(1)] == a && cap[(2)] == 2 && cap[(3)] == nil); assert(a /_ (1 / 0) == a); assert(cap[(0)] == "idiv" && cap[(1)] == a && cap[(2)] == 1 / 0 && cap[(3)] == nil); assert(a & "hi" == a); assert(cap[(0)] == "band" && cap[(1)] == a && cap[(2)] == "hi" && cap[(3)] == nil); assert(a | "hi" == a); assert(cap[(0)] == "bor" && cap[(1)] == a && cap[(2)] == "hi" && cap[(3)] == nil); assert("hi" ~ a == "hi"); assert(cap[(0)] == "bxor" && cap[(1)] == "hi" && cap[(2)] == a && cap[(3)] == nil); assert(-a == a); assert(cap[(0)] == "unm" && cap[(1)] == a); assert(a ^ 4 == a); assert(cap[(0)] == "pow" && cap[(1)] == a && cap[(2)] == 4 && cap[(3)] == nil); assert(a ^ '4' == a); assert(cap[(0)] == "pow" && cap[(1)] == a && cap[(2)] == '4' && cap[(3)] == nil); assert(4 ^ a == 4); assert(cap[(0)] == "pow" && cap[(1)] == 4 && cap[(2)] == a && cap[(3)] == nil); assert('4' ^ a == '4'); assert(cap[(0)] == "pow" && cap[(1)] == '4' && cap[(2)] == a && cap[(3)] == nil); assert(#a == a); assert(cap[(0)] == "len" && cap[(1)] == a); assert(^^a == a); assert(cap[(0)] == "bnot" && cap[(1)] == a); assert(a << 3 == a); assert(cap[(0)] == "shl" && cap[(1)] == a && cap[(2)] == 3); assert(1.5 >> a == 1.5); assert(cap[(0)] == "shr" && cap[(1)] == 1.5 && cap[(2)] == a); t = setmetatable({ 1, 2, 3 }, { __len = fn () { return 10 } }) assert(#t == 10 && rawlen(t) == 3); assert(rawlen("abc") == 3); assert(!pcall(rawlen, io.stdin)); assert(!pcall(rawlen, 34)); assert(!pcall(rawlen)); assert(rawlen(string.rep('a', 1000)) == 1000); t = {} t.__lt = fn (a, b, c) { collectgarbage(); assert(c == nil); if type(a) == 'table' { a = a.x } if type(b) == 'table' { b = b.x } return a < b, "dummy" } global fn Op(x) { return setmetatable({ x = x }, t) } local fn test() { assert(!(Op(1) < Op(1)) && (Op(1) < Op(2)) && !(Op(2) < Op(1))); assert(!(1 < Op(1)) && (Op(1) < 2) && !(2 < Op(1))); assert(!(Op('a') < Op('a')) && (Op('a') < Op('b')) && !(Op('b') < Op('a'))); assert(!('a' < Op('a')) && (Op('a') < 'b') && !(Op('b') < Op('a'))); assert((Op(1) <= Op(1)) && (Op(1) <= Op(2)) && !(Op(2) <= Op(1))); assert((Op('a') <= Op('a')) && (Op('a') <= Op('b')) && !(Op('b') <= Op('a'))); assert(!(Op(1) > Op(1)) && !(Op(1) > Op(2)) && (Op(2) > Op(1))); assert(!(Op('a') > Op('a')) && !(Op('a') > Op('b')) && (Op('b') > Op('a'))); assert((Op(1) >= Op(1)) && !(Op(1) >= Op(2)) && (Op(2) >= Op(1))); assert((1 >= Op(1)) && !(1 >= Op(2)) && (Op(2) >= 1)); assert((Op('a') >= Op('a')) && !(Op('a') >= Op('b')) && (Op('b') >= Op('a'))); assert(('a' >= Op('a')) && !(Op('a') >= 'b') && (Op('b') >= Op('a'))); } test(); t.__le = fn (a, b, c) { assert(c == nil); if type(a) == 'table' { a = a.x } if type(b) == 'table' { b = b.x } return a <= b, "dummy" } test(); local fn rawSet(x) { local y = {} for _, k with pairs(x) { y[(k)] = 1 } return y } local fn Set(x) { return setmetatable(rawSet(x), t) } t.__lt = fn (a, b) { for k with pairs(a) { if !b[(k)] { return false } b[(k)] = nil } return next(b) != nil } t.__le = nil assert(Set({ 1, 2, 3 }) < Set({ 1, 2, 3, 4 })); assert(!(Set({ 1, 2, 3, 4 }) < Set({ 1, 2, 3, 4 }))); assert((Set({ 1, 2, 3, 4 }) <= Set({ 1, 2, 3, 4 }))); assert((Set({ 1, 2, 3, 4 }) >= Set({ 1, 2, 3, 4 }))); assert((Set({ 1, 3 }) <= Set({ 3, 5 }))); t.__le = fn (a, b) { for k with pairs(a) { if !b[(k)] { return false } } return true } assert(!(Set({ 1, 3 }) <= Set({ 3, 5 }))); assert(!(Set({ 1, 3 }) <= Set({ 3, 5 }))); assert(!(Set({ 1, 3 }) >= Set({ 3, 5 }))); t.__eq = fn (a, b) { for k with pairs(a) { if !b[(k)] { return false } b[(k)] = nil } return next(b) == nil } local s = Set({ 1, 3, 5 }) assert(s == Set({ 3, 5, 1 })); assert(!rawequal(s, Set({ 3, 5, 1 }))); assert(rawequal(s, s)); assert(Set({ 1, 3, 5, 1 }) == rawSet({ 3, 5, 1 })); assert(rawSet({ 1, 3, 5, 1 }) == Set({ 3, 5, 1 })); assert(Set({ 1, 3, 5 }) != Set({ 3, 5, 1, 6 })); t[(Set({ 1, 3, 5 }))] = 1 assert(t[(Set({ 1, 3, 5 }))] == nil); if !T { (Message || print)('\n >>> testC not active: skipping tests for \z userdata equality <<<\n'); } else { local u1 = T.newuserdata(0) local u2 = T.newuserdata(0) local u3 = T.newuserdata(0) assert(u1 != u2 && u1 != u3); debug.setuservalue(u1, 1); debug.setuservalue(u2, 2); debug.setuservalue(u3, 1); debug.setmetatable(u1, { __eq = fn (a, b) { return debug.getuservalue(a) == debug.getuservalue(b) } }); debug.setmetatable(u2, { __eq = fn (a, b) { return true } }); assert(u1 == u3 && u3 == u1 && u1 != u2); assert(u2 == u1 && u2 == u3 && u3 == u2); assert(u2 != {}); } t.__concat = fn (a, b, c) { assert(c == nil); if type(a) == 'table' { a = a.val } if type(b) == 'table' { b = b.val } if A { return a .. b } else { return setmetatable({ val = a .. b }, t) } } c = { val = "c" } setmetatable(c, t); d = { val = "d" } setmetatable(d, t); A = true assert(c .. d == 'cd'); assert(0 .. "a" .. "b" .. c .. d .. "e" .. "f" .. (5 + 3) .. "g" == "0abcdef8g"); A = false assert((c .. d .. c .. d).val == 'cdcd'); x = c .. d assert(getmetatable(x) == t && x.val == 'cd'); x = 0 .. "a" .. "b" .. c .. d .. "e" .. "f" .. "g" assert(x.val == "0abcdefg"); c = {} local x setmetatable(c, { __concat = fn (a, b) { assert(type(a) == "number" && b == c || type(b) == "number" && a == c); return c } }); assert(c .. 5 == c && 5 .. c == c); assert(4 .. c .. 5 == c && 4 .. 5 .. 6 .. 7 .. c == c); local t1, t2, c, d t1 = {} c = {} setmetatable(c, t1); d = {} t1.__eq = fn () { return true } t1.__lt = fn () { return true } setmetatable(d, t1); assert(c == d && c < d && !(d <= c)); t2 = {} t2.__eq = t1.__eq t2.__lt = t1.__lt setmetatable(d, t2); assert(c == d && c < d && !(d <= c)); local i local tt = { __call = fn (t, ...) { i = i + 1 if t.f { return t.f(...) } else { return { ... } } } } local a = setmetatable({}, tt) local b = setmetatable({ f = a }, tt) local c = setmetatable({ f = b }, tt) i = 0 x = c(3, 4, 5) assert(i == 3 && x[(1)] == 3 && x[(3)] == 5); assert(_G.X == 20); print('+'); local _g = _G _ENV = setmetatable({}, { __index = fn (_, k) { return _g[(k)] } }) a = {} rawset(a, "x", 1, 2, 3); assert(a.x == 1 && rawget(a, "x", 3) == 1); print('+'); mt = { __index = fn (a, b) { return a + b }, __len = fn (x) { return math.floor(x) } } debug.setmetatable(10, mt); assert(getmetatable(-2) == mt); assert((10)[(3)] == 13); assert((10)[("3")] == 13); assert(#3.45 == 3); debug.setmetatable(23, nil); assert(getmetatable(-2) == nil); debug.setmetatable(true, mt); assert(getmetatable(false) == mt); mt.__index = fn (a, b) { return a || b } assert((true)[(false)] == true); assert((false)[(false)] == false); debug.setmetatable(false, nil); assert(getmetatable(true) == nil); debug.setmetatable(nil, mt); assert(getmetatable(nil) == mt); mt.__add = fn (a, b) { return (a || 0) + (b || 0) } assert(10 + nil == 10); assert(nil + 23 == 23); assert(nil + nil == 0); debug.setmetatable(nil, nil); assert(getmetatable(nil) == nil); debug.setmetatable(nil, {}); a = {} setmetatable(a, a); a.__index = a a.__newindex = a assert(!pcall(fn (a, b) { return a[(b)] }, a, 10)); assert(!pcall(fn (a, b, c) { a[(b)] = c }, a, 10, true)); T, K, V = nil grandparent = {} grandparent.__newindex = fn (t, k, v) { T = t K = k V = v } parent = {} parent.__newindex = parent setmetatable(parent, grandparent); child = setmetatable({}, parent) child.foo = 10 assert(T == parent && K == "foo" && V == 10); print('OK'); return 12