summaryrefslogtreecommitdiff
path: root/indra/newview/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/scripts')
-rw-r--r--indra/newview/scripts/lua/mapargs.lua67
-rw-r--r--indra/newview/scripts/lua/test_mapargs.lua68
2 files changed, 135 insertions, 0 deletions
diff --git a/indra/newview/scripts/lua/mapargs.lua b/indra/newview/scripts/lua/mapargs.lua
new file mode 100644
index 0000000000..78e691d8bc
--- /dev/null
+++ b/indra/newview/scripts/lua/mapargs.lua
@@ -0,0 +1,67 @@
+-- Allow a calling function to be passed a mix of positional arguments with
+-- keyword arguments. Reference them as fields of a table.
+-- Don't use this for a function that can accept a single table argument.
+-- mapargs() assumes that a single table argument means its caller was called
+-- with f{table constructor} syntax, and maps that table to the specified names.
+-- Usage:
+-- function f(...)
+-- local a = mapargs({'a1', 'a2', 'a3'}, ...)
+-- ... a.a1 ... etc.
+-- end
+-- f(10, 20, 30) -- a.a1 == 10, a.a2 == 20, a.a3 == 30
+-- f{10, 20, 30} -- a.a1 == 10, a.a2 == 20, a.a3 == 30
+-- f{a3=300, a1=100} -- a.a1 == 100, a.a2 == nil, a.a3 == 300
+-- f{1, a3=3} -- a.a1 == 1, a.a2 == nil, a.a3 == 3
+-- f{a3=3, 1} -- a.a1 == 1, a.a2 == nil, a.a3 == 3
+local function mapargs(names, ...)
+ local args = table.pack(...)
+ local posargs = {}
+ local keyargs = {}
+ -- For a mixed table, no Lua operation will reliably tell you how many
+ -- array items it contains, if there are any holes. Track that by hand.
+ -- We must be able to handle f(1, nil, 3) calls.
+ local maxpos = 0
+ if not (args.n == 1 and type(args[1]) == 'table') then
+ -- If caller passes more than one argument, or if the first argument
+ -- is not a table, then it's classic positional function-call syntax:
+ -- f(first, second, etc.). In that case we need not bother teasing
+ -- apart positional from keyword arguments.
+ posargs = args
+ maxpos = args.n
+ else
+ -- Single table argument implies f{mixed} syntax.
+ -- Tease apart positional arguments from keyword arguments.
+ for k, v in pairs(args[1]) do
+ if type(k) == 'number' then
+ posargs[k] = v
+ maxpos = math.max(maxpos, k)
+ else
+ if table.find(names, k) == nil then
+ error('unknown keyword argument ' .. tostring(k))
+ end
+ keyargs[k] = v
+ end
+ end
+ end
+
+ -- keyargs already has keyword arguments in place, just fill in positionals
+ args = keyargs
+ -- Don't exceed the number of parameter names. Loop explicitly over every
+ -- index value instead of using ipairs() so we can support holes (nils) in
+ -- posargs.
+ for i = 1, math.min(#names, maxpos) do
+ if posargs[i] ~= nil then
+ -- As in Python, make it illegal to pass an argument both positionally
+ -- and by keyword. This implementation permits func(17, first=nil), a
+ -- corner case about which I don't particularly care.
+ if args[names[i]] ~= nil then
+ error(string.format('parameter %s passed both positionally and by keyword',
+ tostring(names[i])))
+ end
+ args[names[i]] = posargs[i]
+ end
+ end
+ return args
+end
+
+return mapargs
diff --git a/indra/newview/scripts/lua/test_mapargs.lua b/indra/newview/scripts/lua/test_mapargs.lua
new file mode 100644
index 0000000000..999a57acb4
--- /dev/null
+++ b/indra/newview/scripts/lua/test_mapargs.lua
@@ -0,0 +1,68 @@
+local mapargs = require 'mapargs'
+local inspect = require 'inspect'
+
+function tabfunc(...)
+ local a = mapargs({'a1', 'a2', 'a3'}, ...)
+ print(inspect(a))
+end
+
+print('----------')
+print('f(10, 20, 30)')
+tabfunc(10, 20, 30)
+print('f(10, nil, 30)')
+tabfunc(10, nil, 30)
+print('f{10, 20, 30}')
+tabfunc{10, 20, 30}
+print('f{10, nil, 30}')
+tabfunc{10, nil, 30}
+print('f{a3=300, a1=100}')
+tabfunc{a3=300, a1=100}
+print('f{1, a3=3}')
+tabfunc{1, a3=3}
+print('f{a3=3, 1}')
+tabfunc{a3=3, 1}
+print('----------')
+
+if false then
+ -- the code below was used to explore ideas that became mapargs()
+ mixed = { '[1]', nil, '[3]', abc='[abc]', '[3]', def='[def]' }
+ local function showtable(desc, t)
+ print(string.format('%s (len %s)\n%s', desc, #t, inspect(t)))
+ end
+ showtable('mixed', mixed)
+
+ print('ipairs(mixed)')
+ for k, v in ipairs(mixed) do
+ print(string.format('[%s] = %s', k, tostring(v)))
+ end
+
+ print('table.pack(mixed)')
+ print(inspect(table.pack(mixed)))
+
+ local function nilarg(desc, a, b, c)
+ print(desc)
+ print('a = ' .. tostring(a))
+ print('b = ' .. tostring(b))
+ print('c = ' .. tostring(c))
+ end
+
+ nilarg('nilarg(1)', 1)
+ nilarg('nilarg(1, nil, 3)', 1, nil, 3)
+
+ local function nilargs(desc, ...)
+ args = table.pack(...)
+ showtable(desc, args)
+ end
+
+ nilargs('nilargs{a=1, b=2, c=3}', {a=1, b=2, c=3})
+ nilargs('nilargs(1, 2, 3)', 1, 2, 3)
+ nilargs('nilargs(1, nil, 3)', 1, nil, 3)
+ nilargs('nilargs{1, 2, 3}', {1, 2, 3})
+ nilargs('nilargs{1, nil, 3}', {1, nil, 3})
+
+ print('table.unpack({1, nil, 3})')
+ a, b, c = table.unpack({1, nil, 3})
+ print('a = ' .. tostring(a))
+ print('b = ' .. tostring(b))
+ print('c = ' .. tostring(c))
+end