Skip to content

Commit 3c3f0a7

Browse files
authored
Merge pull request #363 from tatuylonen/zerozerozero
Greek wiktionary uses '0', '00' and '000' as parameters
2 parents c40eb85 + a1da120 commit 3c3f0a7

File tree

6 files changed

+165
-20
lines changed

6 files changed

+165
-20
lines changed

src/wikitextprocessor/core.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,7 +1212,7 @@ def expand_args(coded: str, argmap: TemplateArgs) -> str:
12121212
expand_args(args[0], argmap), parent, True
12131213
).strip()
12141214
self.expand_stack.pop()
1215-
if k.isdigit():
1215+
if k.isdigit() and int(k) > 0:
12161216
k = int(k)
12171217
else:
12181218
k = re.sub(r"\s+", " ", k).strip()
@@ -1428,7 +1428,7 @@ def expander(arg: str) -> str:
14281428
# https://en.wikipedia.org/wiki/Help:Template
14291429
# (but not around unnamed parameters)
14301430
k, arg = m2.groups()
1431-
if k.isdigit():
1431+
if k.isdigit() and int(k) > 0:
14321432
k = int(k)
14331433
else:
14341434
self.expand_stack.append("ARGNAME")

src/wikitextprocessor/lua/_sandbox_phase2.lua

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,37 @@ assert(_new_loadData ~= nil)
1010

1111
local function frame_args_index(new_args, key)
1212
-- print("frame_args_index", key)
13-
local i = tonumber(key)
14-
if key ~= "inf" and key ~= "nan" and i ~= nil then
15-
key = i
16-
end
1713
local v = new_args._orig[key]
1814
if v == nil then
19-
return nil
15+
local i = tonumber(key)
16+
if i ~= nil then
17+
key = i
18+
else
19+
return nil
20+
end
21+
v = new_args._orig[key]
22+
if v == nil then
23+
return nil
24+
end
2025
end
2126
if not new_args._preprocessed[key] then
2227
local frame = new_args._frame
23-
v = frame:preprocess(v)
28+
if type(v) == "userdata" then
29+
-- Python tuple in luaexec.call_lua_sandbox.make_frame()
30+
local is_named = v[1]
31+
v = frame:preprocess(v[0])
32+
-- https://en.wikipedia.org/wiki/Help:Template#Whitespace_handling
33+
if is_named then
34+
v = v:match "^%s*(.-)%s*$"
35+
end
36+
else
37+
v = frame:preprocess(v)
38+
end
2439
-- Cache preprocessed value so we only preprocess each argument once
2540
new_args._preprocessed[key] = true
2641
new_args._orig[key] = v
2742
end
28-
-- print("frame_args_index", key, "->", v)
43+
-- print("frame_args_index", key, "->", "'"..v.."'")
2944
return v
3045
end
3146

src/wikitextprocessor/lua/mw.lua

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,90 @@ function mw.clone(v)
8383
end
8484

8585
function mw.dumpObject(obj)
86-
print("mw.dumpObject", obj)
86+
-- https://github.com/wikimedia/mediawiki-extensions-Scribunto/blob/184216759e22635bd25a0844e6f68979ecf7bc2a/includes/Engines/LuaCommon/lualib/mw.lua#L551
87+
local doneTable = {}
88+
local doneObj = {}
89+
local ct = {}
90+
local function sorter( a, b )
91+
local ta, tb = type( a ), type( b )
92+
if ta ~= tb then
93+
return ta < tb
94+
end
95+
if ta == 'string' or ta == 'number' then
96+
return a < b
97+
end
98+
if ta == 'boolean' then
99+
return tostring( a ) < tostring( b )
100+
end
101+
return false -- Incomparable
102+
end
103+
local function _dumpObject( object, indent, expandTable )
104+
local tp = type( object )
105+
if tp == 'number' or tp == 'nil' or tp == 'boolean' then
106+
return tostring( object )
107+
elseif tp == 'string' then
108+
return string.format( "%q", object )
109+
elseif tp == 'table' then
110+
if not doneObj[object] then
111+
local s = tostring( object )
112+
if string.sub(s, 1, 6) == 'table:' then -- this line changed
113+
ct[tp] = ( ct[tp] or 0 ) + 1
114+
doneObj[object] = 'table#' .. ct[tp]
115+
else
116+
doneObj[object] = s
117+
doneTable[object] = true
118+
end
119+
end
120+
if doneTable[object] or not expandTable then
121+
return doneObj[object]
122+
end
123+
doneTable[object] = true
124+
125+
local ret = { doneObj[object], ' {\n' }
126+
local mt = getmetatable( object )
127+
local indentString = " "
128+
if mt then
129+
ret[#ret + 1] = string.rep( indentString, indent + 2 )
130+
ret[#ret + 1] = 'metatable = '
131+
ret[#ret + 1] = _dumpObject( mt, indent + 2, false )
132+
ret[#ret + 1] = "\n"
133+
end
134+
135+
local doneKeys = {}
136+
for key, value in ipairs( object ) do
137+
doneKeys[key] = true
138+
ret[#ret + 1] = string.rep( indentString, indent + 2 )
139+
ret[#ret + 1] = _dumpObject( value, indent + 2, true )
140+
ret[#ret + 1] = ',\n'
141+
end
142+
local keys = {}
143+
for key in pairs( object ) do
144+
if not doneKeys[key] then
145+
keys[#keys + 1] = key
146+
end
147+
end
148+
table.sort( keys, sorter )
149+
for i = 1, #keys do
150+
local key = keys[i]
151+
ret[#ret + 1] = string.rep( indentString, indent + 2 )
152+
ret[#ret + 1] = '['
153+
ret[#ret + 1] = _dumpObject( key, indent + 3, false )
154+
ret[#ret + 1] = '] = '
155+
ret[#ret + 1] = _dumpObject( object[key], indent + 2, true )
156+
ret[#ret + 1] = ",\n"
157+
end
158+
ret[#ret + 1] = string.rep( indentString, indent )
159+
ret[#ret + 1] = '}'
160+
return table.concat( ret )
161+
else
162+
if not doneObj[object] then
163+
ct[tp] = ( ct[tp] or 0 ) + 1
164+
doneObj[object] = tostring( object ) .. '#' .. ct[tp]
165+
end
166+
return doneObj[object]
167+
end
168+
end
169+
return _dumpObject( obj, 0, true )
87170
end
88171

89172
function mw.incrementExpensiveFunctionCount()

src/wikitextprocessor/luaexec.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ def recurse(x: Union[list, tuple, dict]) -> Any:
135135
# Convert numeric keys to integers and see if we can make it a
136136
# table with sequential integer keys.
137137
for k, v in list(x.items()):
138-
if k.isdigit():
138+
if k.isdigit() and int(k) > 0:
139139
del x[k]
140140
x[int(k)] = recurse(v)
141141
else:
@@ -429,29 +429,31 @@ def make_frame(
429429
frame_args = {}
430430
for k, arg in args.items():
431431
arg = re.sub(r"(?si)(<\s*noinclude\s*/\s*>|\n$)", "", arg)
432-
frame_args[k] = arg
432+
frame_args[k] = (arg, False)
433433
else:
434434
assert isinstance(args, (list, tuple))
435435
frame_args = {}
436436
num = 1
437437
for arg in args:
438438
# |-separated strings in {{templates|arg=value|...}}
439439
m = re.match(r"""(?s)^\s*([^<>="']+?)\s*=\s*(.*?)\s*$""", arg)
440-
if m:
441-
# Have argument name
440+
if m is not None:
441+
# named parameter
442442
k, arg = m.groups()
443-
if k.isdigit():
443+
if k.isdigit() and int(k) > 0:
444+
# Greek wiktionary uses '0', '00' and '000' as
445+
# parameter names...
444446
k = int(k)
445-
if k < 1 or k > 1000:
447+
if k > 1000:
446448
ctx.warning(
447-
f"Template argument index <1 or >1000: {k=!r}",
449+
f"Template argument index >1000: {k=!r}",
448450
sortid="luaexec/477/20230710",
449451
)
450452
k = 1000
451453
if num <= k:
452454
num = k + 1
453455
else:
454-
# No argument name
456+
# unnamed parameter
455457
k = num
456458
num += 1
457459
if k in frame_args:
@@ -465,7 +467,7 @@ def make_frame(
465467
# does not always like them (e.g., remove_links() in
466468
# Module:links).
467469
arg = re.sub(r"(?si)(<\s*noinclude\s*/\s*>|\n$)", "", arg)
468-
frame_args[k] = arg
470+
frame_args[k] = (arg, m is not None)
469471
frame_args_lt: "_LuaTable" = lua.table_from(frame_args) # type: ignore[union-attr]
470472

471473
def extensionTag(frame: "_LuaTable", *args: Any) -> str:

src/wikitextprocessor/parser.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,10 @@ def template_parameters(self) -> TemplateParameters:
632632
parameter_value = parameter[
633633
equal_sign_index + 1 :
634634
].strip()
635-
if parameter_name.isdigit(): # value contains "="
635+
if (
636+
parameter_name.isdigit()
637+
and int(parameter_name) > 0
638+
): # value contains "="
636639
parameter_name = int(parameter_name)
637640
is_named = False
638641
if len(parameter_value) > 0:

tests/test_lua.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,3 +598,45 @@ def test_mw_uri_anchorEncode(self):
598598
return export""",
599599
)
600600
self.assertEqual(self.wtp.expand("{{#invoke:test|test}}"), "**")
601+
602+
def test_el_zero_arg(self):
603+
# https://el.wiktionary.org/wiki/Πρότυπο:ετ
604+
# Unnamed template parameters and numbered parameters can only
605+
# be positive non-zero integers; zero or "00" or negative is a string
606+
self.wtp.start_page("θηλυκός")
607+
self.wtp.add_page(
608+
"Module:test",
609+
828,
610+
"""local export = {}
611+
function export.test(frame)
612+
return tostring(frame.args['0']) .. "|" ..
613+
--tostring(frame.args[0]) .. "|" ..
614+
tostring(frame.args['00']) .. "|" ..
615+
tostring(frame.args[1]) .. "|" ..
616+
tostring(frame.args[2]) .. "|" ..
617+
tostring(frame.args['named'])
618+
end
619+
return export""",
620+
)
621+
self.assertEqual(
622+
self.wtp.expand(
623+
"{{#invoke:test|test|0= 0 |00= 00 | first |2= second |named= named }}" # noqa: E501
624+
),
625+
"0|00| first |second|named",
626+
)
627+
628+
def test_el_strip_arg(self):
629+
self.wtp.start_page("θηλυκός")
630+
self.wtp.add_page(
631+
"Module:test",
632+
828,
633+
"""local export = {}
634+
function export.test(frame)
635+
return tostring(frame.args['foo'])
636+
end
637+
return export""",
638+
)
639+
self.assertEqual(
640+
self.wtp.expand("{{#invoke:test|test|foo= {{#if||}} {{#if||}} }}"),
641+
"",
642+
)

0 commit comments

Comments
 (0)