Module:Lua call/sandbox: Difference between revisions
+ |
sync |
||
Line 6: | Line 6: | ||
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 |
||
--if tonumber(v) then v=tonumber(v) end |
|||
_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 |
||
-- debuglog=debuglog..k.."="..v.."</nowiki><br /><nowiki>" |
|||
end |
end |
||
for k,v in pairs(frame.args or {}) do |
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 |
_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 |
||
--- http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#string.format |
--- http://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual#string.format |
||
Line 37: | Line 33: | ||
if type(reserved_call)~="function" then |
if type(reserved_call)~="function" then |
||
return tostring(reserved_call) |
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))} |
else reserved_output={reserved_call(unpack(reserved_value))} |
||
return reserved_output[reserved_return or 1] |
return reserved_output[reserved_return or 1] |
||
Line 43: | Line 38: | ||
end |
end |
||
local function |
local function tonumberOrString(v) |
||
return tonumber(v) or v:gsub("^\\", "", 1) |
|||
local v0 = 123 |
|||
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 = {} |
|||
local function callWithTonumberOrStringOnPairs(f, ...) |
|||
for k, v in pairs(o) do |
|||
local args = {} |
|||
p[k] = function(frame) |
|||
for _, v in ... do |
|||
local args = frame.args |
|||
table.insert(args, tonumberOrString(v)) |
|||
mw.log(unpack(args)) |
|||
mw.logObject(args) |
|||
for _, v in ipairs(args) do |
|||
mw.log(_, v) |
|||
args[_] = tonumber(v) or v:gsub("^\\", "", 1) |
|||
end |
|||
mw.log(#args) |
|||
mw.log(unpack(args)) |
|||
mw.logObject(args) |
|||
return (v(unpack(args))) |
|||
end |
|||
end |
end |
||
return (f(unpack(args))) |
|||
p.f0 = function (frame) return f0() end |
|||
end |
|||
p.v0 = function (frame) return v0 end |
|||
p.f = function (frame) return f() end |
|||
p.v = function (frame) return v end |
|||
p.f2 = function (frame) return f2() end |
|||
--[[ |
|||
return p |
|||
------------------------------------------------------------------------------------ |
|||
-- 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 |
end |
||
p.f0 = function (frame) return f0() end |
|||
p.v0 = function (frame) return v0 end |
|||
p.f = function (frame) return f() end |
|||
p.v = function (frame) return v end |
|||
p.f2 = function (frame) return f2() end |
|||
local function f() end |
|||
local v = 123 |
|||
--p.f0() |
|||
--p.f() |
|||
--p.f2() |
|||
local function get(s) |
|||
p.sub = p.import(mw.ustring).sub |
|||
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 func |
|||
local offset |
|||
if frame.args[1] ~= nil then |
|||
local m = require('Module:' .. frame.args[1]) |
|||
if frame.args[2] ~= nil then |
|||
func = m[frame.args[2]] |
|||
frame.args = frame:getParent().args |
|||
offset = 0 |
|||
else |
|||
frame.args = frame:getParent().args |
|||
func = m[frame.args[1]] |
|||
offset = 1 |
|||
end |
|||
else |
|||
frame.args = frame:getParent().args |
|||
func = require('Module:' .. frame.args[1])[frame.args[2]] |
|||
offset = 2 |
|||
end |
|||
local args = {} |
|||
for _, v in ipairsAtOffset(frame.args, offset) do |
|||
table.insert(args, v) |
|||
end |
|||
frame.args = args |
|||
return func(frame) |
|||
end |
|||
return p |
return p |
Revision as of 19:13, 15 December 2021
![]() | This is the module sandbox page for Module:Lua call (diff). See also the companion subpage for test cases (run). |
![]() | This module is rated as alpha. It is ready for third-party input, and may be used on a few pages to see if problems arise, but should be watched. Suggestions for new features or changes in their input and output mechanisms are welcome. |
This module allows you to call any one single preinstalled Lua function, so that you don't need to write a module for one desired feature.
Usage
Main
{{#invoke:LuaCall|main|arbitrary variables|parameters|functioncall}}
The arbitrary variables are any key of your choice =
any value of your choice. Values are interpreted as strings unless tonumber(value)
isn't nil
, i.e. numbers should be converted to the numeric type. No effort is made to interpret tables.
The parameters all begin with reserved_
, which arbitrary variable should use.
reserved_return
sets which output from the function you want, and defaults to 1. For example, setting it to 2 for mw.ustring.gsub will return the number of replacements made.reserved_debug
- nonzero value forces display of a not particularly useful debug text
The functioncall is written as some.function.name(a,b,c)
where some.function.name means something in the Extension:Scribunto/Lua reference manual and a,b,c are the arbitrary variable names you've chosen.
Examples
Main
{{#invoke:LuaCall|main|a=test |b=7|string.rep(a,b)}}
→ test test test test test test test{{#invoke:LuaCall|main|pattern=(%a)|replace=%1.|string=I can't get no satisfaction|mw.ustring.gsub(string,pattern,replace)|reserved_return=1}}
→ I. c.a.n.'t. g.e.t. n.o. s.a.t.i.s.f.a.c.t.i.o.n.{{#invoke:LuaCall|main|pattern=(%a)|replace=%1.|string=I can't get no satisfaction|mw.ustring.gsub(string,pattern,replace)|reserved_return=2}}
→ 22{{#invoke:LuaCall|main|value=1.4512|math.ceil(value)}}
→ 2{{#invoke:LuaCall|main|value=1.4512|math.modf(value)}}
→ 1{{#invoke:LuaCall|main|value=1.4512|math.modf(value)|reserved_return=2}}
→ 0.4512{{#invoke:LuaCall|main|mw.text.nowiki(s)|s={{URL|1=https://www.Amazon.com/}}}}
→ <span class="url">[https://www.Amazon.com/ www<wbr/>.amazon<wbr/>.com]</span>
Call
{{#invoke:LuaCall|call|string.format|%04x|127}}
→ 007f{{#invoke:LuaCall|call|math.modf|1.4512}}
→ 1{{#invoke:LuaCall|call|math.modf|1.4512|return=2}}
→ 1
Errors
The module may generate script errors — whenever your call is not valid Lua code, you see the error you would normally have. For example,
{{#invoke:LuaCall|main|value=1.4512|math.fmod(value)}}
→
Lua error in Module:Lua_call at line 36: bad argument #2 to 'reserved_call' (number expected, got no value).
because the second value is lacking. No effort is made to trap these.
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 func
local offset
if frame.args[1] ~= nil then
local m = require('Module:' .. frame.args[1])
if frame.args[2] ~= nil then
func = m[frame.args[2]]
frame.args = frame:getParent().args
offset = 0
else
frame.args = frame:getParent().args
func = m[frame.args[1]]
offset = 1
end
else
frame.args = frame:getParent().args
func = require('Module:' .. frame.args[1])[frame.args[2]]
offset = 2
end
local args = {}
for _, v in ipairsAtOffset(frame.args, offset) do
table.insert(args, v)
end
frame.args = args
return func(frame)
end
return p