A module that may handle an Ancient Greek–specific form-of template, with features missing from {{inflection of}}
. Or perhaps the features can be integrated into Module:form of.
Desired features:
local export = {}
local m_fun = require("Module:fun")
local m_table = require("Module:table")
local list_to_set = m_table.listToSet
local invert = m_table.invert
local keys_to_list = m_table.keysToList
local function quote(text)
return "“" .. tostring(text) .. "”"
end
local old_error = error
local function error(msg, level)
msg = string.gsub(msg, "'", "’")
old_error(msg, level)
end
local function errorf(...)
error(string.format(...), 3)
end
local info = setmetatable({}, {
__index = function(self, key)
local val = { type = key }
self = val
return val
end
})
local label_info = {
= info.person, = info.person, = info.person,
singular = info.number, dual = info.number, plural = info.number,
present = info.tense, future = info.tense, perfect = info.tense,
aorist = info.tense, imperfect = info.tense, pluperfect = info.tense,
= info.tense,
indicative = info.mood, subjunctive = info.mood, optative = info.mood,
imperative = info.mood, infinitive = info.nonfinite, participle = info.nonfinite,
active = info.voice, middle = info.voice, mediopassive = info.voice, passive = info.voice,
nominative = info.case, vocative = info.case, accusative = info.case,
genitive = info.case, dative = info.case,
masculine = info.gender, feminine = info.gender, neuter = info.gender,
m = info.gender, f = info.gender, n = info.gender,
}
local abbreviations = {
s = "singular", d = "dual", p = "plural",
= "first person", = "second person", = "third person",
pres = "present", aor = "aorist", fut = "future", imperf = "imperfect",
perf = "perfect", plup = "pluperfect",
ind = "indicative", subj = "subjunctive", opt = "optative",
imp = "imperative", inf = "infinitive", part = "participle",
act = "active", mid = "middle", mp = "mediopassive", pass = "passive",
masc = "masculine", nom = "nominative",
m = "masculine", f = "feminine", n = "neuter",
}
local valid_categories = {
verb = list_to_set{ "person", "number", "tense", "mood", "voice", "nonfinite" },
adjective = list_to_set{ "gender", "case", "number" },
noun = list_to_set{ "number", "case" },
participle = list_to_set{ "gender", "case", "number", "tense", "voice" }, -- or treat as verb?
infinitive = list_to_set{ "tense", "voice" }, -- or treat as verb?
}
valid_categories.pronoun = valid_categories.noun -- Some pronouns have gender, some don't.
valid_categories.demonstrative = valid_categories.adjective
-- No one part of speech has all these categories, but this order should hold true
-- for all of them.
local master_order = invert{ "gender", "case", "person", "number", "tense", "mood", "voice", "nonfinite" }
local function unrecognized_POS_error(POS)
return error("The part of speech " .. quote(POS) .. " does not have a set of valid inflectional categories.", 3)
end
function export.validate_labels(category_map, POS)
local validation = valid_categories or unrecognized_POS_error(POS)
local invalid_labels = m_fun.filter(
function(_, category)
return not validation
end,
category_map)
local first_key = next(invalid_labels)
if first_key then
local agreement = next(invalid_labels, first_key) and { "ies", "are" } or { "y", "is" }
errorf("The categor%s %s %s not used by the part of speech %s.",
agreement, table.concat(m_fun.map(quote, keys_to_list(invalid_labels)), ", "), agreement, quote(POS))
end
end
function export.resolve_abbr(labels)
return m_fun.map(function(label)
return abbreviations or abbreviations or label
end,
labels)
end
-- After resolution of abbreviations.
-- Creates map from inflectional category to label:
-- { "masculine", "nominative", "singular" }
-- ↓
-- { gender = "masculine", case = "nominative", number = "singular" }
-- If there are two labels belonging to the same inflectional category,
-- throws an error.
local function make_category_map(labels)
local category_map = {}
local conflicts = {}
for _, label in ipairs(labels) do
local type = label_info and label_info.type
if not type then
error("The label " .. quote(label) .. " is not in the list of labels.")
end
if category_map then
if not conflicts then
conflicts = { category_map }
end
table.insert(conflicts, label)
end
category_map = label
end
if next(conflicts) then
conflicts = m_fun.mapIter(function(conflict, category)
return ("%s: %s"):format(quote(category), table.concat(m_fun.map(quote, conflict), ", "))
end,
pairs(conflicts))
error(string.format("There were multiple labels belonging to the same categor%s: %s.",
conflicts and "ies" or "y",
table.concat(conflicts, "; ")))
end
return category_map
end
local function capitalize(str)
return string.gsub(str, "^.", string.upper)
end
local get_position = require("Module:memoize")(function (label)
return master_order.type] or
mw.log("no position for label " .. quote(label) .. " of type " .. quote(label_info.type) .. ".")
end)
local function comp(label1, label2)
return get_position(label1) < get_position(label2)
end
function export.sort(labels, POS)
table.sort(labels, comp)
return labels
end
function export.process(labels, POS)
labels = export.resolve_abbr(labels)
local category_map = make_category_map(labels, POS)
if POS == "verb" then
if category_map.nonfinite then
POS, category_map.nonfinite = category_map.nonfinite, nil
end
end
export.validate_labels(category_map, POS)
export.sort(labels)
return labels
end
function export.show(frame)
local params = {
= { list = true },
pos = {}
}
local args = require("Module:parameters").process(frame.args, params)
local labels = args
local POS = args.pos
return table.concat(export.process(labels, POS), ", ")
end
return export