local export = {}
local m_para = require("Module:parameters")
local amf = require("Module:languages").getByCode("amf")
local m_link = require("Module:links")
local m_util = require("Module:amf-utilities")
local DATA = mw.loadData("Module:headword/data")
local NAMESPACE = DATA.page.namespace
local PAGENAME = DATA.pagename
export.show_table = require("Module:amf-nominal/table")
-- useful regexes and replacement tables
local r = {}
r.C = "[bBcCdDgGhjklmnNpqrsStwxyzQ]"
r.V = "[aeiouEO]"
r.add_n_table = {
b = "mm", -- náabi > námmo
B = "mB", -- atáɓ > atámɓa
D = "nD", -- tuɗí > tunɗó
j = "N", -- cʼagáj > cʼagáɲo
k = "ng", -- gerák > gerángo
l = "ll", -- afála > afállo
m = "mm", -- qáami > qámmo
n = "nn", -- ooní > onnó
p = "mm", -- galáp > galámmo
q = "nq", -- tubáqe > tubánqo
r = "rr", -- kurí > kurró
S = "N", -- gaʔásh > gaʔáɲo
t = "nn", -- qootí > qonnó
z = "nn", -- maz > mánno
-- missing: cCdgGhNswxyQ
}
local genders = { "", "m", "f", "f2", "pl" }
local cases = { "nom", "obl", "acc", "gen", "dat", "aff", "ins", "loc", "ine", "ade", "all1", "all2", "abl", "com" }
local function combine(g,c)
return g .. (g ~= "" and "_" or "") .. c
end
-- see [[Module:amf-nominal/testcases]]
-- only accepts vowel stem
function export.make_masculine(syl)
syl = mw.clone(syl)
local n = #syl
syl.accent = n -- move accent to last syllable
syl.falling = true -- make the accent falling
if not syl[n]:match("^"..r.C.."[aeio]$") then
error("Word must end in -a, -e, -i, or -o.")
end
syl[n] = syl[n]:gsub("[aeio]$",{e="E",i="E",o="O"}) -- P5
-- regressive vowel harmony; blocked by "i" (MP5)
for i=n-1,1,-1 do
if syl[i]:match("i") then break end
syl[i] = syl[i]:gsub("[eo]",{e="E",o="O"})
end
return syl
end
-- clip the last vowel (tesíɓe > *tesíɓ)
-- keeps the accent position even if it is at the end
function export.truncate_vowel(syl)
syl = mw.clone(syl)
local n = #syl
local cons,vow = syl[n]:match("^("..r.C..")([aeio])$")
syl[n] = nil
syl[n-1] = syl[n-1] .. cons
return syl
end
-- see [[Module:amf-nominal/testcases]]
-- add -no to a consonant stem (panáq > panánqo)
-- shorten the (new) penultimate syllable (yíir > yírro)
function export.make_feminine(syl)
syl = mw.clone(syl)
local n = #syl
local onst,nucl,coda = syl[n]:match("("..r.C.."?)("..r.V.."+)("..r.C..")$")
if nucl:sub(1,1) == nucl:sub(2,2) then
nucl = nucl:sub(1,1)
end
local with_n = r.add_n_table[coda] or error("Unrecognised pattern: " .. m_util.combine(syl))
syl[n] = onst..nucl..(with_n:sub(-2,-2))
syl[n+1] = (with_n:sub(-1,-1)).."o"
return syl
end
-- generates pl_nom from f_nom
local function make_pl(data)
data.pl_nom = mw.clone(data.f_nom)
local n = #data.pl_nom
data.pl_nom[n] = data.pl_nom[n]:gsub("o$","a",1)
end
export.inflect = {}
export.inflect["1"] = function(data)
data.m_nom = export.make_masculine(data.nom)
data.f_nom = "no"
data.pl_nom = "na"
data.f_obl = "n"
end
export.inflect["2"] = function(data)
data.m_nom = export.make_masculine(data.nom)
data.f_nom = export.make_feminine(export.truncate_vowel(data.nom))
make_pl(data)
data.f_obl = "n"
end
export.inflect["3"] = function(data)
local n = #data.nom
data.m_nom = mw.clone(data.nom)
local rest,coda = data.nom[n]:match("^(.+)("..r.C..")$")
data.m_nom[n] = rest
data.m_nom[n+1] = coda .. "a"
data.m_nom = export.make_masculine(data.m_nom)
data.f_nom = export.make_feminine(data.nom)
make_pl(data)
data.f_obl = "in"
end
-- vowel lowering observed in two out of two samples
export.inflect["4i"] = function(data)
data.m_nom = mw.clone(data.nom)
data.m_nom[2] = "ta"
data.m_nom = export.make_masculine(data.m_nom)
data.f_nom = "no"
-- vowel lowering
data.pl_nom = mw.clone(data.nom)
data.pl_nom[1] = data.pl_nom[1]:gsub("([eo])%1",{ee="EE",oo="OO"})
data.pl_nom[2] = "na"
data.f_obl = "n"
end
export.inflect["4a"] = function(data)
end
export.inflect["4a/"] = function(data)
end
export.inflect["4b"] = function(data)
end
export.inflect["4b/"] = function(data)
end
export.inflect["5a"] = function(data)
end
export.inflect["5b"] = function(data)
end
export.inflect["6"] = function(data)
end
local function determine_pattern(syl)
local last = syl[#syl]
if last:sub(-1,-1):match(r.C) then
return "3"
elseif #syl == 1 and syl[1]:match("^"..r.C.."?"..r.V.."+$") then
return "4i"
end
error("Please specify the declension type.")
end
local pattern_display = {
["1"] = "1",
["2"] = "2",
["3"] = "3",
["4i"] = "4 – inanimate",
["4a"] = "4 – animate",
["4a/"] = "4 – animate",
["4b"] = "4 – animate",
["4b/"] = "4 – animate",
["5a"] = "5",
["5b"] = "5",
["6"] = "6",
}
function export.show(frame)
local args = m_para.process(frame:getParent().args,{
[1] = {},
pagename = (NAMESPACE == "Template") and {} or nil,
})
local pagename = args.pagename or PAGENAME
local data = {}
data.nom = m_util.syllabify(pagename) -- store the base form in data.nom
if args[1] == '3' or args[1] == '4i' then
error("Invalid declension pattern.")
end
local pattern = args[1] or determine_pattern(data.nom)
local fem2 = pattern == "4"
data.title = '<i>' .. pagename .. '</i> (Declension ' .. pattern_display[pattern] .. ')'
export.inflect[pattern](data)
mw.logObject(data)
for _,g in ipairs(genders) do
for _,c in ipairs(cases) do
local curr = data[combine(g,c)]
if curr then
if type(curr) == "string" then -- a simple suffix
data[combine(g,c)] = pagename .. curr
elseif type(curr[1]) == "string" then -- one form
data[combine(g,c)] = m_util.combine(curr)
else
for i,syl in ipairs(curr) do
curr[i] = m_util.combine(i)
end
data[combine(g,c)] = table.concat(", ")
end
end
end
end
local res = export.show_table(fem2):gsub('{{{([^{}]+)}}}', data)
return res
end
return export