Module:LuaCall

From David's Wiki
\( \newcommand{\P}[]{\unicode{xB6}} \newcommand{\AA}[]{\unicode{x212B}} \newcommand{\empty}[]{\emptyset} \newcommand{\O}[]{\emptyset} \newcommand{\Alpha}[]{Α} \newcommand{\Beta}[]{Β} \newcommand{\Epsilon}[]{Ε} \newcommand{\Iota}[]{Ι} \newcommand{\Kappa}[]{Κ} \newcommand{\Rho}[]{Ρ} \newcommand{\Tau}[]{Τ} \newcommand{\Zeta}[]{Ζ} \newcommand{\Mu}[]{\unicode{x039C}} \newcommand{\Chi}[]{Χ} \newcommand{\Eta}[]{\unicode{x0397}} \newcommand{\Nu}[]{\unicode{x039D}} \newcommand{\Omicron}[]{\unicode{x039F}} \DeclareMathOperator{\sgn}{sgn} \def\oiint{\mathop{\vcenter{\mathchoice{\huge\unicode{x222F}\,}{\unicode{x222F}}{\unicode{x222F}}{\unicode{x222F}}}\,}\nolimits} \def\oiiint{\mathop{\vcenter{\mathchoice{\huge\unicode{x2230}\,}{\unicode{x2230}}{\unicode{x2230}}{\unicode{x2230}}}\,}\nolimits} \)

Documentation for this module may be created at Module:LuaCall/doc

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 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.
--
-- 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}} will return results of mw.logObject('a', 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)
	local func = get(frame.args[1])
	local args = {}
	for n, v in ipairs(frame.args) do
		if n > 1 then
			table.insert(args, tonumberOrString(v))
		end
	end
	return func(unpack(args))
end

--[[
------------------------------------------------------------------------------------
-- 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

return p