local function args(...) local t = {...} t.n = select('#', ...) return t end local function pass(...) return ... end function check_equal(name, args1, args2) local equal = args1.n == args2.n if equal then for i = 1, args1.n do if args1[i] ~= args2[i] then equal = false break end end end print(name, equal and "Good" or "BAD") if not equal then print(unpack(args1, 1, args1.n)) print(unpack(args2, 1, args2.n)) end end function check_equal_t(name, t1, t2) local equal = true local k2 for k, v in pairs(t1) do if t2[k] ~= v then equal = false end k2 = next(t2, k2) end if next(t2, k2) ~= nil then equal = false end print(name, equal and "Good" or "BAD") end check_equal("Return duplicated arguments", args((function(...) return ... ..., ... end)("A", "B", "C")), args("A", "B", "C", "A", "B", "C") ) check_equal("Return duplicated arguments with pass", args((function(...) return pass(...) ..., pass(...) end)("A", "B", "C")), args("A", "B", "C", "A", "B", "C") ) check_equal("Return triple duplicated arguments", args((function(...) return ... ..., ... ..., ... end)("A", nil)), args("A", nil, "A", nil, "A", nil) ) check_equal("Expansion at start of function arguments", args((function() return "A", "B", "C", "D" end)() ..., "E"), args("A", "B", "C", "D", "E") ) check_equal("Expansion in middle of function arguments", args("A", (function() return "B", "C" end)() ..., "D", "E"), args("A", "B", "C", "D", "E") ) check_equal("Expansion in middle of function arguments with vararg end", args("A", (function() return "B", "C" end)() ..., "D", (function() return "E", "F" end)()), args("A", "B", "C", "D", "E", "F") ) check_equal("Dual expansion in middle of function arguments", args("A", (function() return "B", "C" end)() ..., "D", (function() return "E", "F" end)() ..., "G"), args("A", "B", "C", "D", "E", "F", "G") ) check_equal("Expansion in assignment", args((function(...) local a, b, c, d, e = "A", ... ..., "E" return a, b, c, d, e end)("B", "C", "D")), args("A", "B", "C", "D", "E") ) function Lselect(n, ...) if n == '#' then local marker = {} local t = {... ..., marker} for k, v in pairs(t) do if v == marker then return k - 1 end end elseif n < 0 then return Lselect(Lselect('#', ...) + 1 + n, ...) end return ({...})[n] end check_equal("Lselect #", args(Lselect('#', "a", "b", nil, nil)), args(select('#', "a", "b", nil, nil)) ) check_equal_t("Standard table constructor", {"A", "B", "C", [0] = " ", k = "v", "D"}, {[0] = " ", [1] = "A", [2] = "B", [3] = "C", [4] = "D", ["k"] = "v"} ) check_equal_t("Multiple expanded unpacks", {unpack{4, unpack{5, 6} ..., 7} ..., 8}, {4, 5, 6, 7, 8} )