Module:LuaCall: Difference between revisions
Jump to navigation
Jump to search
Content deleted Content added
This module is complicated enough as is. You don't need to add even more tangential functions, when p.call was working perfectly fine for months |
Note: Since imported from Wikipedia, this is licensed as Creative Commons Attribution-ShareAlike License 4.0. |
||
(6 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
-- Imported from Wikipedia |
|||
-- Licensed as CC BY-SA 4.0 |
|||
-- See edit history for attribution |
|||
local p={} |
local p={} |
||
function p.main(frame) |
function p.main(frame) |
||
local parent=frame.getParent(frame) or {} |
local parent = frame.getParent(frame) or {} |
||
local reserved_value={} |
local reserved_value = {} |
||
local reserved_function,reserved_contents |
local reserved_function, reserved_contents |
||
for k,v in pairs(parent.args or {}) do |
for k, v in pairs(parent.args or {}) do |
||
_G[k]=tonumber(v) or v -- transfer every parameter directly to the global variable table |
_G[k] = tonumber(v) or v -- transfer every parameter directly to the global variable table |
||
end |
end |
||
for k,v in pairs(frame.args or {}) do |
for k, v in pairs(frame.args or {}) do |
||
_G[k]=tonumber(v) or v -- transfer every parameter directly to the global variable table |
_G[k] = tonumber(v) or v -- transfer every parameter directly to the global variable table |
||
end |
end |
||
--- Alas Scribunto does NOT implement coroutines, according to |
--- Alas Scribunto does NOT implement coroutines, according to |
||
Line 15: | Line 18: | ||
--- this will not stop us from trying to implement one single lousy function call |
--- this will not stop us from trying to implement one single lousy function call |
||
if _G[1] then |
if _G[1] then |
||
reserved_function,reserved_contents=mw.ustring.match(_G[1],"^%s*(%a[^%s%(]*)%(([^%)]*)%)%s*$") |
reserved_function, reserved_contents = mw.ustring.match(_G[1], "^%s*(%a[^%s%(]*)%(([^%)]*)%)%s*$") |
||
end |
end |
||
if reserved_contents then |
if reserved_contents then |
||
local reserved_counter=0 |
local reserved_counter = 0 |
||
repeat |
repeat |
||
reserved_counter=reserved_counter+1 |
reserved_counter = reserved_counter + 1 |
||
reserved_value[reserved_counter]=_G[mw.ustring.match(reserved_contents,"([^%,]+)")] |
reserved_value[reserved_counter] = _G[mw.ustring.match(reserved_contents, "([^%,]+)")] |
||
reserved_contents=mw.ustring.match(reserved_contents,"[^%,]+,(.*)$") |
reserved_contents = mw.ustring.match(reserved_contents, "[^%,]+,(.*)$") |
||
until not reserved_contents |
until not reserved_contents |
||
end |
end |
||
local reserved_arraypart=_G |
local reserved_arraypart = _G |
||
while mw.ustring.match(reserved_function,"%.") do |
while mw.ustring.match(reserved_function, "%.") do |
||
reserved_functionpart,reserved_function=mw.ustring.match(reserved_function,"^(%a[^%.]*)%.(.*)$") |
reserved_functionpart, reserved_function = mw.ustring.match(reserved_function, "^(%a[^%.]*)%.(.*)$") |
||
reserved_arraypart=reserved_arraypart[reserved_functionpart] |
reserved_arraypart = reserved_arraypart[reserved_functionpart] |
||
end |
end |
||
local reserved_call=reserved_arraypart[reserved_function] |
local reserved_call = reserved_arraypart[reserved_function] |
||
if type(reserved_call)~="function" then |
if type(reserved_call) ~= "function" then |
||
return tostring(reserved_call) |
return tostring(reserved_call) |
||
⚫ | |||
reserved_output = {reserved_call(unpack(reserved_value))} |
|||
return reserved_output[reserved_return or 1] |
return reserved_output[reserved_return or 1] |
||
end |
end |
||
Line 144: | Line 148: | ||
--]] |
--]] |
||
function p.invoke(frame) |
function p.invoke(frame) |
||
⚫ | |||
local func |
|||
-- get module and function names from parent args if not provided |
|||
local offset |
|||
local pfargs = setmetatable({frame.args[1], frame.args[2]}, {__index = table}) |
|||
if not pfargs[1] then |
|||
local m = require('Module:' .. frame.args[1]) |
|||
pfargs[1], usedpargs[1] = pframe.args[1], true |
|||
if frame.args[2] ~= nil then |
|||
if not pfargs[2] then |
|||
pfargs[2], usedpargs[2] = pframe.args[2], true |
|||
⚫ | |||
offset = 0 |
|||
⚫ | |||
frame.args = frame:getParent().args |
|||
func = m[frame.args[1]] |
|||
offset = 1 |
|||
end |
end |
||
elseif not pfargs[2] then |
|||
else |
|||
pfargs[2], usedpargs[1] = pframe.args[1], true |
|||
frame.args = frame:getParent().args |
|||
func = require('Module:' .. frame.args[1])[frame.args[2]] |
|||
offset = 2 |
|||
end |
end |
||
-- repack sequential args |
|||
local args = {} |
|||
for |
for i, v in ipairs(pframe.args) do |
||
if not usedpargs[i] then |
|||
pfargs:insert(v) |
|||
usedpargs[i] = true |
|||
end |
|||
end |
|||
-- copy other args |
|||
for k, v in pairs(pframe.args) do |
|||
if not pfargs[k] and not usedpargs[k] then |
|||
pfargs[k], usedpargs[k] = v, true |
|||
end |
|||
end |
end |
||
-- #invoke off parent frame so the new frame has the same parent |
|||
frame.args = args |
|||
return pframe:callParserFunction{name = '#invoke', args = pfargs} |
|||
return func(frame) |
|||
end |
end |
||
Latest revision as of 09:25, 6 August 2024
Documentation for this module may be created at Module:LuaCall/doc
-- Imported from Wikipedia
-- Licensed as CC BY-SA 4.0
-- See edit history for attribution
local p={}
function p.main(frame)
local parent = frame.getParent(frame) or {}
local reserved_value = {}
local reserved_function, reserved_contents
for k, v in pairs(parent.args or {}) do
_G[k] = tonumber(v) or v -- transfer every parameter directly to the global variable table
end
for k, v in pairs(frame.args or {}) do
_G[k] = tonumber(v) or v -- transfer every parameter directly to the global variable table
end
--- Alas Scribunto does NOT implement coroutines, according to
--- http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#string.format
--- this will not stop us from trying to implement one single lousy function call
if _G[1] then
reserved_function, reserved_contents = mw.ustring.match(_G[1], "^%s*(%a[^%s%(]*)%(([^%)]*)%)%s*$")
end
if reserved_contents then
local reserved_counter = 0
repeat
reserved_counter = reserved_counter + 1
reserved_value[reserved_counter] = _G[mw.ustring.match(reserved_contents, "([^%,]+)")]
reserved_contents = mw.ustring.match(reserved_contents, "[^%,]+,(.*)$")
until not reserved_contents
end
local reserved_arraypart = _G
while mw.ustring.match(reserved_function, "%.") do
reserved_functionpart, reserved_function = mw.ustring.match(reserved_function, "^(%a[^%.]*)%.(.*)$")
reserved_arraypart = reserved_arraypart[reserved_functionpart]
end
local reserved_call = reserved_arraypart[reserved_function]
if type(reserved_call) ~= "function" then
return tostring(reserved_call)
else
reserved_output = {reserved_call(unpack(reserved_value))}
return reserved_output[reserved_return or 1]
end
end
local function tonumberOrString(v)
return tonumber(v) or v:gsub("^\\", "", 1)
end
local function callWithTonumberOrStringOnPairs(f, ...)
local args = {}
for _, v in ... do
table.insert(args, tonumberOrString(v))
end
return (f(unpack(args)))
end
--[[
------------------------------------------------------------------------------------
-- ipairsAtOffset
-- This is an iterator for arrays. It can be used like ipairs, but with
-- specified i as first index to iterate. i is an offset from 1
--
------------------------------------------------------------------------------------
--]]
local function ipairsAtOffset(t, i)
local f, s, i0 = ipairs(t)
return f, s, i0+i
end
local function get(s)
local G = _G; for _ in mw.text.gsplit(
mw.text.trim(s, '%s'), '%s*%.%s*'
) do
G = G[_]
end
return G
end
--[[
------------------------------------------------------------------------------------
-- call
--
-- This function is usually useful for debugging template parameters.
-- Prefix parameter with backslash (\) to force interpreting parameter as string.
-- The leading backslash will be removed before passed to Lua function.
--
-- Example:
-- {{#invoke:LuaCall|call|mw.log|a|1|2|3}} will return results of mw.log('a', 1, 2, 3)
-- {{#invoke:LuaCall|call|mw.logObject|\a|321|\321| \321 }} will return results of mw.logObject('a', 321, '321', ' \\321 ')
--
-- This example show the debugging to see which Unicode characters are allowed in template parameters,
-- {{#invoke:LuaCall|call|mw.ustring.codepoint|{{#invoke:LuaCall|call|mw.ustring.char|0x0061}}}} return 97
-- {{#invoke:LuaCall|call|mw.ustring.codepoint|{{#invoke:LuaCall|call|mw.ustring.char|0x0000}}}} return 65533
-- {{#invoke:LuaCall|call|mw.ustring.codepoint|{{#invoke:LuaCall|call|mw.ustring.char|0x0001}}}} return 65533
-- {{#invoke:LuaCall|call|string.format|0x%04x|{{#invoke:LuaCall|call|mw.ustring.codepoint|{{#invoke:LuaCall|call|mw.ustring.char|0x0002}}}}}} return 0xfffd
-- {{#invoke:LuaCall|call|string.format|0x%04x|{{#invoke:LuaCall|call|mw.ustring.codepoint|{{#invoke:LuaCall|call|mw.ustring.char|0x007e}}}}}} return 0x007e
-- {{#invoke:LuaCall|call|string.format|0x%04x|{{#invoke:LuaCall|call|mw.ustring.codepoint|{{#invoke:LuaCall|call|mw.ustring.char|0x007f}}}}}} return 0x007f
-- {{#invoke:LuaCall|call|string.format|0x%04x|{{#invoke:LuaCall|call|mw.ustring.codepoint|{{#invoke:LuaCall|call|mw.ustring.char|0x0080}}}}}} return 0x0080
-- {{#invoke:LuaCall|call|string.format|0x%04x|{{#invoke:LuaCall|call|mw.ustring.codepoint|{{#invoke:LuaCall|call|mw.ustring.char|0x00a0}}}}}} return 0x00a0
--
------------------------------------------------------------------------------------
--]]
function p.call(frame)
return callWithTonumberOrStringOnPairs(get(frame.args[1]),
ipairsAtOffset(frame.args, 1)
)
end
--local TableTools = require('Module:TableTools')
--[[
------------------------------------------------------------------------------------
-- get
--
-- Example:
-- {{#invoke:LuaCall|get| math.pi }} will return value of math.pi
-- {{#invoke:LuaCall|get|math|pi}} will return value of math.pi
-- {{#invoke:LuaCall|get| math |pi}} will return value of _G[' math '].pi
-- {{#invoke:LuaCall|get|_G| math.pi }} will return value of _G[' math.pi ']
-- {{#invoke:LuaCall|get|obj.a.5.c}} will return value of obj.a['5'].c
-- {{#invoke:LuaCall|get|obj|a|5|c}} will return value of obj.a[5].c
--
------------------------------------------------------------------------------------
--]]
function p.get(frame)
-- #frame.args always return 0, regardless of number of unnamed
-- template parameters, so check manually instead
if frame.args[2] == nil then
-- not do tonumber() for this args style,
-- always treat it as string,
-- so 'obj.1' will mean obj['1'] rather obj[1]
return get(frame.args[1])
else
local G = _G
for _, v in ipairs(frame.args) do
G = G[tonumberOrString(v)]
end
return G
end
end
--[[
------------------------------------------------------------------------------------
-- invoke
--
-- This function is used by Template:Invoke
--
------------------------------------------------------------------------------------
--]]
function p.invoke(frame)
local pframe, usedpargs = frame:getParent(), {}
-- get module and function names from parent args if not provided
local pfargs = setmetatable({frame.args[1], frame.args[2]}, {__index = table})
if not pfargs[1] then
pfargs[1], usedpargs[1] = pframe.args[1], true
if not pfargs[2] then
pfargs[2], usedpargs[2] = pframe.args[2], true
end
elseif not pfargs[2] then
pfargs[2], usedpargs[1] = pframe.args[1], true
end
-- repack sequential args
for i, v in ipairs(pframe.args) do
if not usedpargs[i] then
pfargs:insert(v)
usedpargs[i] = true
end
end
-- copy other args
for k, v in pairs(pframe.args) do
if not pfargs[k] and not usedpargs[k] then
pfargs[k], usedpargs[k] = v, true
end
end
-- #invoke off parent frame so the new frame has the same parent
return pframe:callParserFunction{name = '#invoke', args = pfargs}
end
return p