Module:amf-nominal

From Wiktionary, the free dictionary
Jump to navigation Jump to search

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