--- source: src/main.rs expression: compiled input_file: test-data/lua5.1-tests/events.lua --- print('testing metatables'); X = 20 B = 30 setfenv(1, 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 = {} setmetatable(a, { __metatable = "xuxu", __tostring = fn (x) { return x.name } }); assert(getmetatable(a) == "xuxu"); assert(tostring(a) == nil); 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); } t.__newindex = f a[(1)] = 30 a.x = "101" a[(5)] = 200 assert(a[(1)] == 27 && a.x == 98 && a[(5)] == 197); 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); } global fn f(t, ...) { return t, { ... } } t.__call = f { local x, y = a(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.__mod = f("mod") t.__unm = f("unm") t.__pow = f("pow") 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 == 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); 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(!(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(!(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'))); } 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 Set(x) { local y = {} for _, k with pairs(x) { y[(k)] = 1 } return setmetatable(y, 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 }) == 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); 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 x = c .. d assert(getmetatable(x) == t && x.val == 'cd'); x = 0 .. "a" .. "b" .. c .. d .. "e" .. "f" .. "g" assert(x.val == "0abcdefg"); local t1, t2, c, d t1 = {} c = {} setmetatable(c, t1); d = {} t1.__eq = fn () { return true } t1.__lt = fn () { return true } assert(c != d && !pcall(fn () { return c < d })); 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); assert(_G == getfenv(0)); print('+'); local _g = _G setfenv(1, setmetatable({}, { __index = fn (_, k) { return _g[(k)] } })); assert(getmetatable(newproxy()) == nil); assert(getmetatable(newproxy(false)) == nil); local u = newproxy(true) getmetatable(u).__newindex = fn (u, k, v) { getmetatable(u)[(k)] = v } getmetatable(u).__index = fn (u, k) { return getmetatable(u)[(k)] } for i = 1, 10 { u[(i)] = i } for i = 1, 10 { assert(u[(i)] == i); } local k = newproxy(u) assert(getmetatable(k) == getmetatable(u)); a = {} rawset(a, "x", 1, 2, 3); assert(a.x == 1 && rawget(a, "x", 3) == 1); print('+'); mt = {} debug.setmetatable(10, mt); assert(getmetatable(-2) == mt); mt.__index = fn (a, b) { return a + b } assert((10)[(3)] == 13); assert((10)[("3")] == 13); 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, {}); print('OK'); return 12