Module:LuaCall: Difference between revisions
From Test Wiki
Content deleted Content added
auto converting argument to number often lead to bug, ex. {{#invoke:LuaCall|call|mw.text.nowiki|0001}}, p.call_s is easier for user to use (and tend to produce less bug) than p.call when all argument is to be string |
Note: Since imported from Wikipedia, this is licensed as Creative Commons Attribution-ShareAlike License 4.0. |
||
| (5 intermediate revisions by 4 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 42: | Line 46: | ||
end |
end |
||
local function |
local function callWithTonumberOrStringOnPairs(f, ...) |
||
local args = {} |
local args = {} |
||
for _, v in ... do |
for _, v in ... do |
||
table.insert(args, |
table.insert(args, tonumberOrString(v)) |
||
end |
end |
||
return args |
return (f(unpack(args))) |
||
| ⚫ | |||
local function pairs2Array(...) |
|||
local args = {} |
|||
| ⚫ | |||
| ⚫ | |||
| ⚫ | |||
return args |
|||
end |
end |
||
| Line 79: | Line 75: | ||
end |
end |
||
return G |
return G |
||
| ⚫ | |||
local function call(s, args, ret) |
|||
| ⚫ | |||
return ({get(s)(unpack(args))})[tonumber(ret)] |
|||
end |
|||
return get(s)(unpack(args)) |
|||
end |
end |
||
| Line 113: | Line 102: | ||
--]] |
--]] |
||
function p.call(frame) |
function p.call(frame) |
||
return |
return callWithTonumberOrStringOnPairs(get(frame.args[1]), |
||
ipairsAtOffset(frame.args, 1) |
|||
frame.args['return'] |
|||
) |
|||
end |
|||
--[[ |
|||
------------------------------------------------------------------------------------ |
|||
-- call_n |
|||
-- |
|||
-- Like call(), but passing all arguments as number |
|||
------------------------------------------------------------------------------------ |
|||
--]] |
|||
function p.call_n(frame) |
|||
return call(frame.args[1], |
|||
pairs2ArrayWithFunc(tonumber, ipairsAtOffset(frame.args, 1)), |
|||
frame.args['return'] |
|||
) |
|||
end |
|||
--[[ |
|||
------------------------------------------------------------------------------------ |
|||
-- call_s |
|||
-- |
|||
-- Like call(), but passing all arguments as string (no conversion) |
|||
------------------------------------------------------------------------------------ |
|||
--]] |
|||
function p.call_s(frame) |
|||
-- unpack() not work on metatable |
|||
-- enclosing result in (), so that it will return only 1st element of result |
|||
--return (get(frame.args[1])(unpack(frame.args, 2))) |
|||
return call(frame.args[1], |
|||
pairs2Array(ipairsAtOffset(frame.args, 1)), |
|||
frame.args['return'] |
|||
) |
) |
||
end |
end |
||
| Line 191: | 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}) |
|||
| ⚫ | |||
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 |
|||
table.insert(args, v) |
|||
| ⚫ | |||
usedpargs[i] = true |
|||
| ⚫ | |||
| ⚫ | |||
-- copy other args |
|||
| ⚫ | |||
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 |
|||
frame.args = args |
|||
return pframe:callParserFunction{name = '#invoke', args = pfargs} |
|||
return func(frame) |
|||
end |
end |
||