Module:Arguments/sandbox: Difference between revisions

Content deleted Content added
add a comment to warn future coders about the pairs problem
memoize nils to a separate nilArgs table
Line 7:
 
local arguments = {}
 
local nilArg = {} -- Used for memoizing nil arguments in metaArgs.
 
-- Generate four different tidyVal functions, so that we don't have to check the
Line 76 ⟶ 74:
luaArgs = frame
end
 
-- Set up the argsorder andof metaArgsprecedence tables.of argsthe willargument betables. theIf onethe accessedvariables fromare
-- functionsnil, and metaArgsnothing will holdbe added to the actualtable, which is how arguments.we Theavoid metatableclashes
-- connectsbetween the twoframe/parent togetherargs and the Lua args.
local args, metaArgs, metatableargTables = {}, {}, {fargs}
argTables[#argTables + 1] = pargs
setmetatable(args, metatable)
argTables[#argTables + 1] = luaArgs
 
--[[
Line 113 ⟶ 112:
end
end
 
--[[
-- Set up the args, metaArgs and nilArgs tables. args will be the one
-- accessed from functions, and metaArgs will hold the actual arguments. Nil
-- arguments are memoized in nilArgs, and the metatable connects all of them
-- together.
--]]
local args, metaArgs, nilArgs, metatable = {}, {}, {}, {}
setmetatable(args, metatable)
 
local function mergeArgs(iterator, tables)
Line 124 ⟶ 132:
for _, t in ipairs(tables) do
for key, val in iterator(t) do
local metaArgsVal =if metaArgs[key] == nil then
if metaArgsVal == nil or metaArgsVal == nilArg then
local tidiedVal = tidyVal(key, val)
if tidiedVal == nil then
metaArgsnilArgs[key] = nilArgtrue
else
metaArgs[key] = tidiedVal
Line 136 ⟶ 143:
end
end
 
-- Set the order of precedence of the argument tables. If the variables are
-- nil, nothing will be added to the table, which is how we avoid clashes
-- between the frame/parent args and the Lua args.
local argTables = {fargs}
argTables[#argTables + 1] = pargs
argTables[#argTables + 1] = luaArgs
 
--[[
-- Define metatable behaviour. Arguments are memoized in the metaArgs table,
-- and are only fetched from the argument tables once. Nil arguments are
-- also memoized using the nilArgnilArgs variabletable in order to increase performance.
-- Also, we keep a record in the metatable of when pairs and ipairs have
-- been called, so we do not run pairs and ipairs on fargs and pargs more
Line 157:
metatable.__index = function (t, key)
local val = metaArgs[key]
if metatable.donePairs or val ~= nil then
--[[return val
elseif val == nilArgnilArgs[key] then
-- We have either memoized the argument already, or pairs has been
return nil
-- called, meaning that mergeArgs has already copied all of the
-- available arguments into the metaArgs table. We need to check for
-- pairs as we can't memoize nils to the metaArgs table while pairs
-- is iterating. Adding new instances of nilArg to the metaArgs
-- table while pairs is iterating over it produces undefined
-- behaviour in the next() function.
--]]
if val == nilArg then
return nil
else
return val
end
end
for _, argTable in ipairs(argTables) do
local argTableVal = tidyVal(key, argTable[key])
if argTableVal == nil then
metaArgsnilArgs[key] = nilArgtrue
else
metaArgs[key] = argTableVal
Line 201 ⟶ 190:
)
elseif val == nil then
metaArgsnilArgs[key] = nilArgtrue -- Memoize nils.
else
metaArgs[key] = val
Line 213 ⟶ 202:
metatable.doneIpairs = true
end
return function pairs(t, kmetaArgs)
local nk, val = next(metaArgs, k)
if val == nilArg then
val = nil
end
return nk, val
end
end
 
Line 227 ⟶ 210:
metatable.doneIpairs = true
end
return function ipairs(t, imetaArgs)
local val = metaArgs[i + 1]
if val == nil then
return nil
elseif val == nilArg then
val = nil
end
return i + 1, val
end, nil, 0
end