Implements {{amf-ndecl}}
. Inflection data stored in Module:amf-nominal/data.
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 = ""
r.V = ""
r.add_n = {
= "n",
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
}
r.add_t = {
= "t",
b = "tt", -- zóbo > zɔttâ
l = "lt", -- ukulí > ukultâ
r = "rt", -- góro > gortóno
S = "St", -- gaʔásh > gaʔashtóno
y = "it", -- gáya > gaitâ
}
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
local case_suffix = {
acc = "ɗan",
gen = {"sa", "isa"},
dat = "na", -- qánte, nánte
aff = "kal", -- ~xal
ins = "ka", -- ~xa
loc = "te", -- te
ine = {"r", "ir"}, -- "ir" is inferred
ade = "bar",
all1 = "dar",
all2 = "shet", -- shette also
abl = {"rra", "irra"}, -- "irra" is inferred
com = "be", -- bet, bette also
}
-- see ]
-- 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:match("^"..r.C.."$") then
error("Word must end in -a, -e, -i, or -o.")
end
syl = syl:gsub("$",{e="E",i="E",o="O"}) -- P5
-- regressive vowel harmony; blocked by "i" (MP5)
for i=n-1,1,-1 do
if syl:match("i") then break end
syl = syl:gsub("",{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:match("^("..r.C..")()$")
if cons then
syl = nil
syl = syl .. cons
end
return syl
end
-- see ]
-- add a syllable (CV) to a consonant stem, and apply the phonetic rules
-- e.g. panáq + no > panánqo
-- e.g. zób + ta > zótta
-- shorten the (new) penultimate syllable (e.g. yíir + no > yírro)
function export.attach_CV(syl,C,V)
syl = mw.clone(syl)
local n = #syl
local onst,nucl,coda = syl:match("("..r.C.."?)("..r.V.."+)("..r.C.."?)$")
if nucl:sub(1,1) == nucl:sub(2,2) and coda ~= "" then
nucl = nucl:sub(1,1)
end
local assimilated = r or error("Unrecognised pattern: " .. m_util.combine(syl))
syl = onst..nucl..(assimilated:sub(-2,-2))
syl = (assimilated:sub(-1,-1))..V
return syl
end
function export.make_feminine(syl)
return export.attach_CV(syl,"n","o")
end
function export.make_f2(data)
if data.f2_nom then
return nil
end
data.f2_nom = export.attach_CV(export.truncate_vowel(data.nom),"t","o")
local n = #data.f2_nom
data.f2_nom.accent = n
data.f2_obl = mw.clone(data.f2_nom)
data.f2_nom = "no"
data.f2_obl = data.f2_obl.."n"
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 = data.pl_nom:gsub("o$","a",1)
end
export.inflect = {}
export.inflect = 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 = 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 = function(data)
local n = #data.nom
data.m_nom = mw.clone(data.nom)
local rest,coda = data.nom:match("^(.+)("..r.C..")$")
data.m_nom = rest
data.m_nom = 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 = function(data)
data.m_nom = mw.clone(data.nom)
data.m_nom = "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 = data.pl_nom:gsub("()%1",{ee="EE",oo="OO"})
data.pl_nom = "na"
data.f_obl = "n"
end
local function inflect_4(data)
local n = #data.nom
if data.nom:match("") then
data.truncated = mw.clone(data.nom)
data.m_nom = mw.clone(data.nom)
data.m_nom = "ta"
else
data.truncated = export.truncate_vowel(data.nom)
data.m_nom = export.attach_CV(data.truncated,"t","a")
end
data.m_nom = export.make_masculine(data.m_nom) -- ukultâ
data.fem2 = true
data.f_obl = "n"
end
export.inflect = function(data)
inflect_4(data)
data.f_nom = "no"
data.pl_nom = "na"
end
export.inflect = function(data)
export.inflect(data)
data.m_nom = {data.m_nom, export.make_masculine(data.nom)}
end
export.inflect = function(data)
inflect_4(data)
data.f_nom = export.attach_CV(data.truncated,"n","o")
make_pl(data)
end
export.inflect = function(data)
export.inflect(data)
data.m_nom = {data.m_nom, export.make_masculine(data.nom)}
end
local function inflect_5(data)
local n = #data.nom
data.f_nom = mw.clone(data.nom)
data.f_nom = "no"
make_pl(data)
-- for f_obl, the pattern seems to be that if final syllable of f_nom
-- is accented, then the (originally) penultimate syllable breaks if
-- it's a diphthong
data.f_obl = mw.clone(data.f_nom)
if data.f_obl.accent == n then
local onset,nucl = data.f_obl:match("^("..r.C.."?)("..r.V.."+)$")
if #nucl == 2 and nucl:sub(1,1) ~= nucl:sub(2,2) then
data.f_obl = onset..nucl:sub(1,1)
data.f_obl = nucl:sub(2,2).."n"
else
data.f_obl = onset..nucl.."n"
data.f_obl = nil
data.f_obl.accent = (n>2) and (n-1) or 0
end
else
data.f_obl = data.f_obl.."n"
data.f_obl = nil
end
end
export.inflect = function(data)
inflect_5(data)
data.m_nom = mw.clone(data.nom)
local n = #data.nom
data.m_nom = data.m_nom:gsub("i$","a")
data.m_nom = export.make_masculine(data.m_nom)
end
export.inflect = function(data)
inflect_5(data)
data.m_nom = export.make_masculine(data.nom)
end
export.inflect = function(data)
data.nom = data.pagename
end
-- m_obl does not exist, but the circumflex changes to acute in other cases
-- e.g. hattâ = tree:M; hattá-sa = tree:M-gen
function export.make_m_obl(data)
if data.m_obl then
return nil
end
data.m_obl = mw.clone(data.m_nom)
if type(data.m_obl) == "string" then
data.m_obl.falling = false
else
for i=1,#data.m_obl do
data.m_obl.falling = false
end
end
end
function export.combine_nom_obl(data)
for _,g in ipairs(genders) do
for _,c in ipairs({"nom","obl"}) do
local gc = combine(g,c)
local curr = data
if curr then
if data.pattern ~= "6" then
if type(curr) == "string" then -- a simple suffix
if data.pattern:sub(1,1) ~= "5" then
data = data.pagename .. curr
end
elseif type(curr) == "string" then -- one form
data = m_util.combine(curr)
else
for i,syl in ipairs(curr) do
curr = m_util.combine(syl)
end
data = table.concat(curr, ", ")
end
else
if curr:match(",") then
data = mw.text.split(curr,",",true)
end
end
end
end
end
end
function export.make_cases(data)
-- only f_obl and f2_obl exist but we make the other obl to make the rest of the code easier
data.obl = mw.clone(data.nom)
data.pl_obl = mw.clone(data.pl_nom)
local function attach_suffix(original,suffix)
if suffix:sub(1,1) == "b" then
original = original:gsub("n$","m")
end
return original .. suffix
end
-- make other cases
local function make_one_case(g,c,suffix)
local source = data
if not source then
return nil
elseif type(source) == "string" then
data = attach_suffix(source,suffix)
else
data = {}
for i=1,#source do
data = attach_suffix(source,suffix)
end
end
end
for i=3,#cases do
local case = cases
local v_suffix, c_suffix
if type(case_suffix) == "string" then
v_suffix = case_suffix
c_suffix = case_suffix
else
v_suffix = case_suffix
c_suffix = case_suffix
end
for _,g in ipairs(genders) do
local suffix = (data.pattern == "3" and g == "" and c_suffix or v_suffix)
make_one_case(g,case,suffix)
end
end
end
function export.delete_forms(data)
if data.modifier == "m" then
data.extra = "masculine only"
for _,c in ipairs(cases) do
data = "—"
end
elseif data.modifier == "f" then
data.extra = "feminine only"
for _,c in ipairs(cases) do
data = "—"
end
elseif data.modifier == "sg" then
data.extra = "singular only"
data.category = "]"
for _,c in ipairs(cases) do
data = "—"
end
end
for _,g in ipairs(genders) do
for _,c in ipairs(cases) do
data = data or "?"
end
end
end
local function determine_pattern(data)
local new_data = mw.loadData("Module:amf-nominal/data")
if new_data then
for key,val in pairs(new_data) do
data = val
end
return new_data.pattern
end
local syl = data.nom
if syl:sub(-1,-1):match(r.C) then
return "3"
elseif #syl == 1 and syl:match("^"..r.C.."?"..r.V.."+$") then
return "4i"
end
error("Please specify the declension type.")
end
local pattern_display = {
= "1",
= "2",
= "3",
= "4 – inanimate",
= "4 – animate",
= "4 – animate",
= "4 – animate",
= "4 – animate",
= "5",
= "5",
= "6",
}
local auto_patterns = {
= true, = true, = true, = true, = true
}
function export.show(frame)
local args = m_para.process(frame:getParent().args,{
= {},
= {},
pagename = (NAMESPACE == "Template" or NAMESPACE == "User") and {} or nil,
})
local pagename = args.pagename or PAGENAME
if pagename == "hámar" then
pagename = "hámari"
end
local data = {}
data.pagename = pagename
data.modifier = args
if args == "f2" then
data.fem2 = true
end
data.nom = m_util.syllabify(pagename) -- store the base form in data.nom
if auto_patterns] then
error("Declension " .. args .. " does not need to be specified.")
end
local pattern = args or determine_pattern(data)
data.pattern = pattern
export.inflect(data)
if data.fem2 then
export.make_f2(data)
end
export.make_m_obl(data)
export.combine_nom_obl(data)
export.make_cases(data)
if pagename == "hámari" then
pagename = "hámar"
data.nom = "hámar"
end
for _,g in ipairs(genders) do
for _,c in ipairs(cases) do
local gc = combine(g,c)
local val = data
if val and type(val) == "table" then
data = table.concat(val, ", ")
end
end
end
export.delete_forms(data)
data.title = '<i>' .. pagename .. '</i> (Declension ' .. pattern_display
.. (data.extra and ", ''"..data.extra.."''" or "") .. ')'
local res = export.show_table(data.fem2):gsub('{{{(+)}}}', data)
return res .. (data.category or "")
end
return export