lua/testes/vararg.lua
Roberto I f33cc4ddec New conceptual model for vararg
Conceptually, all functions get their vararg arguments in a vararg
table. The storing of vararg arguments in the stack is always treated
as an optimization.
2025-11-26 11:18:29 -03:00

261 lines
6.1 KiB
Lua

-- $Id: testes/vararg.lua $
-- See Copyright Notice in file lua.h
print('testing vararg')
local function f (a, ...t)
local x = {n = select('#', ...), ...}
assert(x.n == t.n)
for i = 1, x.n do
assert(a[i] == x[i] and x[i] == t[i])
end
return x.n
end
local function c12 (...)
assert(arg == _G.arg) -- no local 'arg'
local x = {...}; x.n = #x
local res = (x.n==2 and x[1] == 1 and x[2] == 2)
if res then res = 55 end
return res, 2
end
local function vararg (... t) return t end
local call = function (f, args) return f(table.unpack(args, 1, args.n)) end
assert(f() == 0)
assert(f({1,2,3}, 1, 2, 3) == 3)
assert(f({"alo", nil, 45, f, nil}, "alo", nil, 45, f, nil) == 5)
assert(vararg().n == 0)
assert(vararg(nil, nil).n == 2)
assert(c12(1,2)==55)
local a,b = assert(call(c12, {1,2}))
assert(a == 55 and b == 2)
a = call(c12, {1,2;n=2})
assert(a == 55 and b == 2)
a = call(c12, {1,2;n=1})
assert(not a)
assert(c12(1,2,3) == false)
local a = vararg(call(next, {_G,nil;n=2}))
local b,c = next(_G)
assert(a[1] == b and a[2] == c and a.n == 2)
a = vararg(call(call, {c12, {1,2}}))
assert(a.n == 2 and a[1] == 55 and a[2] == 2)
a = call(print, {'+'})
assert(a == nil)
local t = {1, 10}
function t:f (...) local arg = {...}; return self[...]+#arg end
assert(t:f(1,4) == 3 and t:f(2) == 11)
print('+')
local lim = 20
local i, a = 1, {}
while i <= lim do a[i] = i+0.3; i=i+1 end
function f(a, b, c, d, ...)
local more = {...}
assert(a == 1.3 and more[1] == 5.3 and
more[lim-4] == lim+0.3 and not more[lim-3])
end
local function g (a,b,c)
assert(a == 1.3 and b == 2.3 and c == 3.3)
end
call(f, a)
call(g, a)
a = {}
i = 1
while i <= lim do a[i] = i; i=i+1 end
assert(call(math.max, a) == lim)
print("+")
-- new-style varargs
local function oneless (a, ...) return ... end
function f (n, a, ...)
local b
assert(arg == _G.arg) -- no local 'arg'
if n == 0 then
local b, c, d = ...
return a, b, c, d, oneless(oneless(oneless(...)))
else
n, b, a = n-1, ..., a
assert(b == ...)
return f(n, a, ...)
end
end
a,b,c,d,e = assert(f(10,5,4,3,2,1))
assert(a==5 and b==4 and c==3 and d==2 and e==1)
a,b,c,d,e = f(4)
assert(a==nil and b==nil and c==nil and d==nil and e==nil)
do -- vararg expressions using unpack
local function aux (a, v, ...t)
for k, val in pairs(v) do t[k] = val end
return ...
end
local t = table.pack(aux(10, {11, [5] = 24}, 1, 2, 3, nil, 4))
assert(t.n == 5 and t[1] == 11 and t[2] == 2 and t[3] == 3
and t[4] == nil and t[5] == 24)
local t = table.pack(aux(nil, {1, [20] = "a", [30] = "b", n = 30}))
assert(t.n == 30 and t[1] == 1 and t[20] == "a" and t[30] == "b")
-- table has only those four elements
assert(next(t, next(t, next(t, next(t, next(t, nil))))) == nil)
local a, b, c, d = aux(nil, {}, 10, 20, 30)
assert(a == 10 and b == 20 and c == 30 and d == nil)
local function aux (a, b, n, ...t) t.n = n; return b, ... end
local t = table.pack(aux(10, 1, 10000))
assert(t.n == 10001 and t[1] == 1 and #t == 1)
local function checkerr (emsg, f, ...)
local st, msg = pcall(f, ...)
assert(not st and string.find(msg, emsg))
end
checkerr("no proper 'n'", aux, 1, 1, -1)
checkerr("no proper 'n'", aux, 1, 1, math.maxinteger)
checkerr("no proper 'n'", aux, 1, 1, math.mininteger)
checkerr("no proper 'n'", aux, 1, 1, 1.0)
end
-- varargs for main chunks
local f = assert(load[[ return {...} ]])
local x = f(2,3)
assert(x[1] == 2 and x[2] == 3 and x[3] == undef)
f = load[[
local x = {...}
for i=1,select('#', ...) do assert(x[i] == select(i, ...)) end
assert(x[select('#', ...)+1] == undef)
return true
]]
assert(f("a", "b", nil, {}, assert))
assert(f())
a = {select(3, table.unpack{10,20,30,40})}
assert(#a == 2 and a[1] == 30 and a[2] == 40)
a = {select(1)}
assert(next(a) == nil)
a = {select(-1, 3, 5, 7)}
assert(a[1] == 7 and a[2] == undef)
a = {select(-2, 3, 5, 7)}
assert(a[1] == 5 and a[2] == 7 and a[3] == undef)
pcall(select, 10000)
pcall(select, -10000)
-- bug in 5.2.2
function f(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10,
p11, p12, p13, p14, p15, p16, p17, p18, p19, p20,
p21, p22, p23, p24, p25, p26, p27, p28, p29, p30,
p31, p32, p33, p34, p35, p36, p37, p38, p39, p40,
p41, p42, p43, p44, p45, p46, p48, p49, p50, ...)
local a1,a2,a3,a4,a5,a6,a7
local a8,a9,a10,a11,a12,a13,a14
end
-- assertion fail here
f()
-- missing arguments in tail call
do
local function f(a,b,c) return c, b end
local function g() return f(1,2) end
local a, b = g()
assert(a == nil and b == 2)
end
do -- vararg parameter used in nested functions
local function foo (...tab1)
return function (...tab2)
return {tab1, tab2}
end
end
local f = foo(10, 20, 30)
local t = f("a", "b")
assert(t[1].n == 3 and t[1][1] == 10)
assert(t[2].n == 2 and t[2][1] == "a")
end
do -- vararg parameter is read-only
local st, msg = load("return function (... t) t = 10 end")
assert(string.find(msg, "const variable 't'"))
local st, msg = load[[
local function foo (...extra)
return function (...) extra = nil end
end
]]
assert(string.find(msg, "const variable 'extra'"))
end
do -- _ENV as vararg parameter
local st, msg = load[[
local function aux (... _ENV)
global <const> a
a = 10
end ]]
assert(string.find(msg, "const variable 'a'"))
local function aux (..._ENV)
global a; a = 10
return a
end
assert(aux() == 10)
local function aux (... _ENV)
global a = 10
return a
end
assert(aux() == 10)
end
do -- access to vararg parameter
local function notab (keys, t, ...v)
for _, k in pairs(keys) do
assert(t[k] == v[k])
end
assert(t.n == v.n)
return ...
end
local t = table.pack(10, 20, 30)
local keys = {-1, 0, 1, t.n, t.n + 1, 1.0, 1.1, "n", print, "k", "1"}
notab(keys, t, 10, 20, 30) -- ensure stack space
local m = collectgarbage"count"
notab(keys, t, 10, 20, 30)
-- 'notab' does not create any table/object
assert(m == collectgarbage"count")
-- writing to the vararg table
local function foo (...t)
t[1] = t[1] + 10
return t[1]
end
assert(foo(10, 30) == 20)
end
print('OK')