Module:LuaCall: Difference between revisions

From Test Wiki
Jump to navigation Jump to search
Content deleted Content added
fix bug, local function must be placed before import call
This entire function is out of scope: the purpose of this module is to provide an interpreter for Lua callable via #invoke, not to provide functions to other modules
Line 40: Line 40:
return reserved_output[reserved_return or 1]
return reserved_output[reserved_return or 1]
end
end
end

local function tonumberOrString(v)
return tonumber(v) or v:gsub("^\\", "", 1)
end

local function tonumberOrStringOnPairs(f, s, i)
local args = {}
for _, v in f, s, i do
--table.insert(args, tonumber(v) or v:gsub("^\\", "", 1))
table.insert(args, tonumberOrString(v))
end
return args
end

-- This function is modified from https://en.wikipedia.org/wiki/Module:Ustring?oldid=885619921
-- All frame's arguments are coerced as number type if possible. If you wish for something to remain a string, you can simply escape it by insert \ at the beginning of the string.
function p.import(o)
local p = {}

for k, v in pairs(o) do if type(v)~='function' then p[k]=v else
p[k] = function(frame)
--local args = {}
--for _, v in ipairs(frame.args) do
-- --table.insert(args, tonumber(v) or v:gsub("^\\", "", 1))
-- table.insert(args, tonumberOrString(v))
--end
--return (v(unpack(args)))
return (v(unpack(
tonumberOrStringOnPairs(ipairs(frame.args))
)))
end
end
end

return p
end
end



Revision as of 12:35, 8 March 2019

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
        --if tonumber(v) then v=tonumber(v) end
        _G[k]=tonumber(v) or v -- transfer every parameter directly to the global variable table
        -- debuglog=debuglog..k.."="..v.."</nowiki><br /><nowiki>"
    end
    for k,v in pairs(frame.args or {}) do
        --if tonumber(v) then v=tonumber(v) end       
        _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)
    elseif reserved_debug or not reserved_function then return mw.text.nowiki(debuglog)
    else reserved_output={reserved_call(unpack(reserved_value))}
        return reserved_output[reserved_return or 1]
    end
end

-- ipairsAt()/ipairsAtOffset() will be proposed to be placed in [[Module:TableTools]]
--[[
------------------------------------------------------------------------------------
-- ipairsAt
--
-- This is an iterator for arrays. It can be used like ipairs, but with
-- specified i as first index to iterate.
--
--    for i,v in p.ipairsAt(t, 3) do body end
--
-- will iterate over the pairs (3,t[3]),(4,t[4]),..., up to the first
-- integer key absent from the table.
--
-- Note: The following is an example to do range iteration from 3 to j
--
--    for i,v in p.ipairsAt(t, 3) do if i>j then break end; body end
--
------------------------------------------------------------------------------------
--]]
local function ipairsAt(t, i)
	--return ipairsAtOffset(t, i-1)
	-- This may be less overhead than return ipairsAtOffset() above
	local f, s, i0 = ipairs(t)
	return f, s, i0+i-1
end

--[[
------------------------------------------------------------------------------------
-- ipairsAtOffset
--
-- Like ipairsAt(), except that it treat argument i as offset from 1
--
------------------------------------------------------------------------------------
--]]
local function ipairsAtOffset(t, i)
	local f, s, i0 = ipairs(t)
	return f, s, i0+i
end

local function iIteratorsAtOffset(t, i)
	local f, s, i0 = ipairs(t)
	return function (s, i)
		local i, v = f(s, i); return v
	end, s, i0+i
end

-- like ipairs() except that it return only value, rather than key/value pair
-- on each iteration
local function iIterators(t) return iIteratorsAtOffset(t, 0) 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
--
-- 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)
--
------------------------------------------------------------------------------------
--]]
function p.call(frame)
	--local f = mw.text.trim(frame.args[1], '%s')
	--local args = {}
	--for _, v in ipairsAtOffset(frame.args, 1) do
	--	--table.insert(args, tonumber(v) or v:gsub("^\\", "", 1))
	--	table.insert(args, tonumberOrString(v))
	--end
	local args = tonumberOrStringOnPairs(ipairsAtOffset(frame.args, 1))
	--local G = _G
	--for _ in mw.text.gsplit(
	--	mw.text.trim(frame.args[1], '%s'), '%s*%.%s*'
	--) do
	--	G = G[_]
	--end
	return (get(frame.args[1])(unpack(args)))
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 use length() instead
	if TableTools.length(frame.args) == 1 then
		-- not do tonumber() for this args style,
		-- always treat it as string,
		-- so 'obj.1' will mean obj['1'] rather obj[1]
		--local G = _G; for _ in mw.text.gsplit(
		--	mw.text.trim(frame.args[1], '%s'), '%s*%.%s*'
		--) do
		--	G = G[_]
		--end
		--return G
		return get(frame.args[1])
	else
		--local args = {}
		local G = _G
		for _, v in ipairs(frame.args) do
			--table.insert(args, tonumber(v) or v:gsub("^\\", "", 1))
			--G = G[tonumber(v) or v:gsub("^\\", "", 1)]
			G = G[tonumberOrString(v)]
		end
		--local G = _G; for _, v in ipairs(args) do
		--	G = G[v]
		--end
		return G
	end
end

return p