Module:ArgParse

From Fallen London Wiki

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

local p = {}

-- raw wikitext
local function page_contents(page, namespace)
	local title = mw.title.new(page, namespace)
	return title:getContent()
end 

local function strip_whitespaces(s)
	local result = '' .. s 
	while result:sub(1, 1):match('%s') do 
		result = result:sub(2)
	end 
	while result:sub(-1, -1):match('%s') do 
		result = result:sub(1, -2)
	end 
	return result
end

-- Iterates over template arguments.
local function template_args(wikitext)
	local argc = 0 
	local pos = 1
	return function()
		local argname = nil 
		local argval = '' 
		local context = {}
		-- skip whitespace symbols
		while wikitext:sub(pos, pos):match('%s') do 
		    pos = pos + 1 
		end 
		if wikitext:sub(pos, pos + 1) == '}}' then 
		    return nil
		end 
		if wikitext:sub(pos, pos) ~= '|' then 
		    -- error 
		    return nil
		end 
		pos = pos + 1
		-- parse the entry 
		local is_potential_name = true 
		local nowiki = 0
		local _
		while true do 
		    local skip = false -- there is no continue
			if #context == 0 and wikitext:sub(pos, pos + 1) == '}}' then 
				break 
		    end 
		    if #context == 0 and wikitext:sub(pos, pos) == '|' then 
		        break 
		    end 
		    if not skip and wikitext:sub(pos):find('<%s*nowiki%s*>') == 1 then 
		    	table.insert(context, '<nowiki>')
		    	argval = argval + '<nowiki>'
		    	_, pos = wikitext:find('<%s*nowiki%s*>', pos)
		    	pos = pos + 1
		    	nowiki = nowiki + 1
		    	skip = true
		    end
		    if nowiki == 0 and not skip and not argname and is_potential_name and #context == 0 and wikitext:sub(pos, pos) == '=' then 
		        argname = argval 
		        argval = '' 
		        pos = pos + 1 
		        skip = true
		    end 
		    if nowiki == 0 and not skip and wikitext:sub(pos, pos + 1) == '{{' then 
		        table.insert(context, '{{')
		        argval = argval .. '{{' 
		        pos = pos + 2 
		        is_potential_name = false
		        skip = true
		    end 
		    if nowiki == 0 and not skip and wikitext:sub(pos, pos + 1) == '[[' then 
		        table.insert(context, '[[')
		        argval = argval .. '[[' 
		        pos = pos + 2 
		        is_potential_name = false
		        skip = true
		    end 
		    if not skip and wikitext:sub(pos):find('</%s*nowiki%s*>') == 1 and context[#context]== '<nowiki>' then 
		        table.remove(context)
		        argval = argval .. '</nowiki>' 
		        _, pos = wikitext:find('</%s*nowiki%s*>', pos)
		        pos = pos + 1
		        nowiki = nowiki - 1
		        skip = true
		    end
		    if nowiki == 0 and not skip and wikitext:sub(pos, pos + 1) == '}}' and context[#context]== '{{' then 
		        table.remove(context)
		        argval = argval .. '}}' 
		        pos = pos + 2 
		        skip = true
		    end
		    if nowiki == 0 and not skip and wikitext:sub(pos, pos + 1) == ']]' and context[#context]== '[[' then 
		        table.remove(context)
		        argval = argval .. ']]' 
		        pos = pos + 2 
		        skip = true
		    end 
		    if not skip then
			    argval = argval .. wikitext:sub(pos, pos)
		    	pos = pos + 1
		    end
		end
		argval = strip_whitespaces(argval)
		if argname then 
			argname = strip_whitespaces(argname)
		    return argname, argval 
		else 
		    argc = argc + 1 
		    return '' .. argc, argval
		end
	end
end

--[[
    {{#invoke:ArgParse|value|page|template|parameter|<default=>}}
    Finds the first occurrence of template `template` in `page`;
    returns the value set to `parameter`, or `default`.
]]
function p.value(frame)
	local page = frame.args[1]
	local template = frame.args[2]
	local parameter = frame.args[3]
	local default = frame.args[4] or '' 
	
	local wikitext = page_contents(page, '')
	if wikitext == nil then
		return default
	end
	
	local template_pat = '[' .. string.upper(template:sub(1, 1)) .. string.lower(template:sub(1, 1)) .. ']' .. template:sub(2)
	
	local _, pos = wikitext:find('{{%s*' .. template_pat .. '%s*[|}]')
	if pos == nil then
		return default
	end
	wikitext = wikitext:sub(pos)
	
	for argname, argval in template_args(wikitext) do 
		if argname == parameter then 
			return frame:preprocess(argval)
		end
	end
	
	return default
end

return p