local p = {}
local format = string.format
local gsub = mw.ustring.gsub
local trim = mw.text.trim
local upper = mw.ustring.upper
local prepattern = "%[(%w+)%|(.*)%|(.*)%|(.*)%]"
local pattern = "%%(%w+)%%"
local function subst(formatStr, args)
local function testArgs(test, equals, ifexists, ifnot)
local value = args[test] or ''
if equals ~= '' then
return value == equals and ifexists or ifnot
else
return value ~= '' and ifexists or ifnot
end
end
local preprocessed = gsub(formatStr, prepattern, testArgs)
local parsedStr = gsub(preprocessed, pattern, args)
return trim(parsedStr)
end
local function ifexists(name, form)
if name == '' then return false end
local namespaceModule = mw.loadData('Module:Road data/parser/namespace')
local namespace = namespaceModule[form] or 0
local title = mw.title.new(name, namespace);
return title.exists
end
local function parser(formatStr, args, form)
if type(formatStr) ~= "table" then
return subst(formatStr, args)
elseif formatStr.hook then
-- Requires: Parser hook must have hook field.
local hook = formatStr.hook
local hooksModule = require "Module:Road data/parser/hooks"
local hookFunction = hooksModule[hook] or error("Hook '" .. hook .. "' does not exist", 0)
return parser(hookFunction(formatStr, args), args, form)
elseif formatStr.arg or formatStr.default then
-- Requires: Switch table must have
-- arg or default fields
-- but not hook field.
local arg = args[formatStr.arg or "route"]
if formatStr[arg] then return parser(formatStr[arg], args, form) end
if not formatStr.default then return '' end
local defaultValue = parser(formatStr.default, args, form)
if formatStr.ifexists then
if ifexists(defaultValue, form) then return defaultValue end
return formatStr.otherwise and parser(formatStr.otherwise, args, form) or ''
else
return defaultValue
end
else
-- Process each table element
local result = {}
for i,entry in ipairs(formatStr) do
result[i] = parser(entry, args, form)
end
return result
end
end
local function getTypeData(module, type, form)
local success, moduleData = pcall(mw.loadData, module)
if not success then return '' end
local typeTable = moduleData[type] or moduleData['']
local defaultTable = moduleData[''] or {}
if typeTable then
local alias = typeTable.alias
if alias then
local aliasedModule = "Module:Road data/strings/" .. alias.module
local aliasedType = alias.type
return getTypeData(aliasedModule, aliasedType, form)
end
return typeTable[form] or defaultTable[form] or ''
else
return ''
end
end
local function formatString(args, form, path, kind)
local stateCountries = {USA = true, CAN = true}
local state = upper(args.state or '')
local country
if args.country then
country = upper(args.country)
else
local countryModule = mw.loadData("Module:Road data/countrymask")
country = countryModule[state] or 'UNK'
end
local typeArg = kind or args.type
local module
if path then
module = path
elseif stateCountries[country] and state ~= '' then
module = format("Module:Road data/strings/%s/%s", country, state)
else
module = format("Module:Road data/strings/%s", country)
end
return getTypeData(module, typeArg, form)
end
function p.parser(args, form, path, kind)
local formatStr = formatString(args, form, path, kind)
if not formatStr or formatStr == '' then return nil end
return parser(formatStr, args, form)
end
return p