Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/wikitextprocessor/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1212,7 +1212,7 @@ def expand_args(coded: str, argmap: TemplateArgs) -> str:
expand_args(args[0], argmap), parent, True
).strip()
self.expand_stack.pop()
if k.isdigit():
if k.isdigit() and int(k) > 0:
k = int(k)
else:
k = re.sub(r"\s+", " ", k).strip()
Expand Down Expand Up @@ -1428,7 +1428,7 @@ def expander(arg: str) -> str:
# https://en.wikipedia.org/wiki/Help:Template
# (but not around unnamed parameters)
k, arg = m2.groups()
if k.isdigit():
if k.isdigit() and int(k) > 0:
k = int(k)
else:
self.expand_stack.append("ARGNAME")
Expand Down
29 changes: 22 additions & 7 deletions src/wikitextprocessor/lua/_sandbox_phase2.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,37 @@ assert(_new_loadData ~= nil)

local function frame_args_index(new_args, key)
-- print("frame_args_index", key)
local i = tonumber(key)
if key ~= "inf" and key ~= "nan" and i ~= nil then
key = i
end
local v = new_args._orig[key]
if v == nil then
return nil
local i = tonumber(key)
if i ~= nil then
key = i
else
return nil
end
v = new_args._orig[key]
if v == nil then
return nil
end
end
if not new_args._preprocessed[key] then
local frame = new_args._frame
v = frame:preprocess(v)
if type(v) == "userdata" then
-- Python tuple in luaexec.call_lua_sandbox.make_frame()
local is_named = v[1]
v = frame:preprocess(v[0])
-- https://en.wikipedia.org/wiki/Help:Template#Whitespace_handling
if is_named then
v = v:match "^%s*(.-)%s*$"
end
else
v = frame:preprocess(v)
end
-- Cache preprocessed value so we only preprocess each argument once
new_args._preprocessed[key] = true
new_args._orig[key] = v
end
-- print("frame_args_index", key, "->", v)
-- print("frame_args_index", key, "->", "'"..v.."'")
return v
end

Expand Down
85 changes: 84 additions & 1 deletion src/wikitextprocessor/lua/mw.lua
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,90 @@ function mw.clone(v)
end

function mw.dumpObject(obj)
print("mw.dumpObject", obj)
-- https://github.com/wikimedia/mediawiki-extensions-Scribunto/blob/184216759e22635bd25a0844e6f68979ecf7bc2a/includes/Engines/LuaCommon/lualib/mw.lua#L551
local doneTable = {}
local doneObj = {}
local ct = {}
local function sorter( a, b )
local ta, tb = type( a ), type( b )
if ta ~= tb then
return ta < tb
end
if ta == 'string' or ta == 'number' then
return a < b
end
if ta == 'boolean' then
return tostring( a ) < tostring( b )
end
return false -- Incomparable
end
local function _dumpObject( object, indent, expandTable )
local tp = type( object )
if tp == 'number' or tp == 'nil' or tp == 'boolean' then
return tostring( object )
elseif tp == 'string' then
return string.format( "%q", object )
elseif tp == 'table' then
if not doneObj[object] then
local s = tostring( object )
if string.sub(s, 1, 6) == 'table:' then -- this line changed
ct[tp] = ( ct[tp] or 0 ) + 1
doneObj[object] = 'table#' .. ct[tp]
else
doneObj[object] = s
doneTable[object] = true
end
end
if doneTable[object] or not expandTable then
return doneObj[object]
end
doneTable[object] = true

local ret = { doneObj[object], ' {\n' }
local mt = getmetatable( object )
local indentString = " "
if mt then
ret[#ret + 1] = string.rep( indentString, indent + 2 )
ret[#ret + 1] = 'metatable = '
ret[#ret + 1] = _dumpObject( mt, indent + 2, false )
ret[#ret + 1] = "\n"
end

local doneKeys = {}
for key, value in ipairs( object ) do
doneKeys[key] = true
ret[#ret + 1] = string.rep( indentString, indent + 2 )
ret[#ret + 1] = _dumpObject( value, indent + 2, true )
ret[#ret + 1] = ',\n'
end
local keys = {}
for key in pairs( object ) do
if not doneKeys[key] then
keys[#keys + 1] = key
end
end
table.sort( keys, sorter )
for i = 1, #keys do
local key = keys[i]
ret[#ret + 1] = string.rep( indentString, indent + 2 )
ret[#ret + 1] = '['
ret[#ret + 1] = _dumpObject( key, indent + 3, false )
ret[#ret + 1] = '] = '
ret[#ret + 1] = _dumpObject( object[key], indent + 2, true )
ret[#ret + 1] = ",\n"
end
ret[#ret + 1] = string.rep( indentString, indent )
ret[#ret + 1] = '}'
return table.concat( ret )
else
if not doneObj[object] then
ct[tp] = ( ct[tp] or 0 ) + 1
doneObj[object] = tostring( object ) .. '#' .. ct[tp]
end
return doneObj[object]
end
end
return _dumpObject( obj, 0, true )
end

function mw.incrementExpensiveFunctionCount()
Expand Down
20 changes: 11 additions & 9 deletions src/wikitextprocessor/luaexec.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ def recurse(x: Union[list, tuple, dict]) -> Any:
# Convert numeric keys to integers and see if we can make it a
# table with sequential integer keys.
for k, v in list(x.items()):
if k.isdigit():
if k.isdigit() and int(k) > 0:
del x[k]
x[int(k)] = recurse(v)
else:
Expand Down Expand Up @@ -429,29 +429,31 @@ def make_frame(
frame_args = {}
for k, arg in args.items():
arg = re.sub(r"(?si)(<\s*noinclude\s*/\s*>|\n$)", "", arg)
frame_args[k] = arg
frame_args[k] = (arg, False)
else:
assert isinstance(args, (list, tuple))
frame_args = {}
num = 1
for arg in args:
# |-separated strings in {{templates|arg=value|...}}
m = re.match(r"""(?s)^\s*([^<>="']+?)\s*=\s*(.*?)\s*$""", arg)
if m:
# Have argument name
if m is not None:
# named parameter
k, arg = m.groups()
if k.isdigit():
if k.isdigit() and int(k) > 0:
# Greek wiktionary uses '0', '00' and '000' as
# parameter names...
k = int(k)
if k < 1 or k > 1000:
if k > 1000:
ctx.warning(
f"Template argument index <1 or >1000: {k=!r}",
f"Template argument index >1000: {k=!r}",
sortid="luaexec/477/20230710",
)
k = 1000
if num <= k:
num = k + 1
else:
# No argument name
# unnamed parameter
k = num
num += 1
if k in frame_args:
Expand All @@ -465,7 +467,7 @@ def make_frame(
# does not always like them (e.g., remove_links() in
# Module:links).
arg = re.sub(r"(?si)(<\s*noinclude\s*/\s*>|\n$)", "", arg)
frame_args[k] = arg
frame_args[k] = (arg, m is not None)
frame_args_lt: "_LuaTable" = lua.table_from(frame_args) # type: ignore[union-attr]

def extensionTag(frame: "_LuaTable", *args: Any) -> str:
Expand Down
5 changes: 4 additions & 1 deletion src/wikitextprocessor/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -632,7 +632,10 @@ def template_parameters(self) -> TemplateParameters:
parameter_value = parameter[
equal_sign_index + 1 :
].strip()
if parameter_name.isdigit(): # value contains "="
if (
parameter_name.isdigit()
and int(parameter_name) > 0
): # value contains "="
parameter_name = int(parameter_name)
is_named = False
if len(parameter_value) > 0:
Expand Down
42 changes: 42 additions & 0 deletions tests/test_lua.py
Original file line number Diff line number Diff line change
Expand Up @@ -598,3 +598,45 @@ def test_mw_uri_anchorEncode(self):
return export""",
)
self.assertEqual(self.wtp.expand("{{#invoke:test|test}}"), "**")

def test_el_zero_arg(self):
# https://el.wiktionary.org/wiki/Πρότυπο:ετ
# Unnamed template parameters and numbered parameters can only
# be positive non-zero integers; zero or "00" or negative is a string
self.wtp.start_page("θηλυκός")
self.wtp.add_page(
"Module:test",
828,
"""local export = {}
function export.test(frame)
return tostring(frame.args['0']) .. "|" ..
--tostring(frame.args[0]) .. "|" ..
tostring(frame.args['00']) .. "|" ..
tostring(frame.args[1]) .. "|" ..
tostring(frame.args[2]) .. "|" ..
tostring(frame.args['named'])
end
return export""",
)
self.assertEqual(
self.wtp.expand(
"{{#invoke:test|test|0= 0 |00= 00 | first |2= second |named= named }}" # noqa: E501
),
"0|00| first |second|named",
)

def test_el_strip_arg(self):
self.wtp.start_page("θηλυκός")
self.wtp.add_page(
"Module:test",
828,
"""local export = {}
function export.test(frame)
return tostring(frame.args['foo'])
end
return export""",
)
self.assertEqual(
self.wtp.expand("{{#invoke:test|test|foo= {{#if||}} {{#if||}} }}"),
"",
)