Module:izh-decl-S

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

local export = {}

local m_izh = require("Module:izh")

local function get_stem(word, ending)
	if mw.ustring.match(word, ending .. "$") then
		return word:sub(1, #word - #ending)
	end
	error("Unexpected ending for this inflection type! Wrong type?")
end

local function elongate(stem, condition)
	if condition == nil or condition then
		-- already long?
		if mw.ustring.match(stem, m_izh.vowel .. m_izh.vowel .. "$") then
			for k, v in pairs(m_izh.vowel_sequences) do
				if mw.ustring.find(stem, v .. "$", pos) then
					return stem
				end
			end
		end
		return stem .. mw.ustring.sub(stem, -1)
	else
		return stem
	end
end

local function frontalize(w, vh)
	if vh == "ä" then
		w = mw.ustring.gsub(w, "[aou]", { a = "ä", o = "ö", u = "y" })
	end
	return w
end

local function geminate(c)
	if mw.ustring.match(c, m_izh.consonant .. m_izh.consonant .. "$") then
		return c
	end
	return c .. mw.ustring.sub(c, -1)
end

local function join(...)
	local t = {}
	for _, s in ipairs({...}) do
		if type(s) == "table" then
			for _, v in ipairs(s) do
				table.insert(t, v)
			end
		else
			table.insert(t, s)
		end
	end
	return t
end

local function append(t, x)
	if not x then return t end
	if type(t) == "string" then
		return t .. x
	end
	local r = {}
	for _, v in ipairs(t) do
		table.insert(r, v .. x)
	end
	return r
end

local function elongate_all(t)
	if type(t) == "string" then
		return elongate(t)
	end
	local r = {}
	for _, v in ipairs(t) do
		table.insert(r, elongate(v))
	end
	return r
end

local function make_gradation(s, w)
	if s == w then
		return "no gradation"
	else
		return s .. "-" .. w .. " gradation"
	end
end

local function get_geminated(data, w, fallback)
	if data.geminate == false then return fallback end
	if data.headword then
		local gemprefix = mw.ustring.len(data.title) - mw.ustring.len(data.headword)
		if gemprefix > 0 then
			local wp = mw.ustring.sub(w, 1, gemprefix)
			local wg = m_izh.guess_gemination(mw.ustring.sub(w, gemprefix + 1))
			if not wg then return fallback end
			return wp .. wg
		end
	end
	return m_izh.guess_gemination(w) or fallback
end

local function get_elongation(data, w)
	if data.elongate == false then return false end
	if data.headword then
		local gemprefix = mw.ustring.len(data.title) - mw.ustring.len(data.headword)
		if gemprefix > 0 then
			return m_izh.guess_elongation(mw.ustring.sub(w, gemprefix + 1))
		end
	end
	return m_izh.guess_elongation(w)
end

local function process(data, result, vh)
	local vh = data.vh
	-- genitive singular/plural stem
	local gs = result.stem_gs
	local gp = result.stem_gp
	-- nominative plural stem
	local np = result.stem_np or gs
	-- partitive singular/plural stem
	local ps = result.stem_ps
	local pp = result.stem_pp
	-- illative singular/plural stem
	local is = result.stem_is
	local ip = result.stem_ip
	-- allative singular/plural stem
	local as = result.stem_as or gs
	local ap = result.stem_ap or pp
	-- adessive singular/plural stem
	local es = result.stem_es or as
	local ep = result.stem_ep or ap
	-- essive singular/plural stem
	local xs = result.stem_xs or is
	local xp = result.stem_xp or ip

	if not data.no_singular then
		result["nom_sg"] = { data.title }
		result["gen_sg"] = append(gs, "n")
		result["par_sg"] = append(ps, vh)
		if result.par_short_ok then
			result["par_sg"] = join(result["par_sg"], ps)
		end
		if result.ill_short or result.ill_short_sg then
			result["ill_sg"] = append(is, result.ill_ending or result.ill_ending_sg or nil)
		else
			result["ill_sg"] = append(elongate_all(is), result.ill_ending or result.ill_ending_sg or nil)
		end
		result["ine_sg"] = append(es, "s")
		result["ela_sg"] = append(es, "st")
		result["all_sg"] = append(as, "lle")
		result["ade_sg"] = append(es, "l")
		result["abl_sg"] = append(es, "lt")
		result["tra_sg"] = append(es, "ks")
		result["ess_sg"] = append(xs, "n")
		result["exe_sg"] = append(xs, "nt")
	end

	if not data.no_plural then
		result["nom_pl"] = append(np, "t")
		result["gen_pl"] = append(gp, "n")
		result["par_pl"] = append(pp, vh)
		if result.ill_short then
			result["ill_pl"] = append(ip, result.ill_ending or result.ill_ending_pl or nil)
		else
			result["ill_pl"] = append(elongate_all(ip), result.ill_ending or result.ill_ending_pl or nil)
		end
		result["ine_pl"] = append(ep, "s")
		result["ela_pl"] = append(ep, "st")
		result["all_pl"] = append(ap, "lle")
		result["ade_pl"] = append(ep, "l")
		result["abl_pl"] = append(ep, "lt")
		result["tra_pl"] = append(ep, "ks")
		result["ess_pl"] = append(xp, "n")
		result["exe_pl"] = append(xp, "nt")
	end

	return result
end

local function guess_illative_weight(stem)
	local syllables = m_izh.split_syllables(stem)
	return #syllables % 2 == 1 and mw.ustring.find(stem, m_izh.vowel .. m_izh.vowel .. "$") and mw.ustring.sub(stem, -2, -2) ~= mw.ustring.sub(stem, -1, -1)
end

local function generate_hv_illative_forms(result, data, stems, weights, ending, short)
	local outputs = {}

	for i, stem in ipairs(stems) do
		local weight = weights[i]

		if not short then
			stem = elongate(stem)
		end

		if weight == nil then
			local guess = stem
			if data.headword then
				guess = mw.ustring.sub(guess, 1 + mw.ustring.len(data.title) - mw.ustring.len(data.headword))
			end
			weight = guess_illative_weight(guess)
		end

		if weight then
			table.insert(outputs, stem .. ending)
		else
			table.insert(outputs, stem)
		end
	end

	return outputs
end

-- -hV illative ending is only sometimes evident
local function generate_hv_illative(result, data, stem_s, weight_s, stem_p, weight_p)
	if not data.no_singular and stem_s then
		result["ill_sg"] = generate_hv_illative_forms(result, data, stem_s, weight_s, result.ill_ending_sg or result.ill_ending or "", result.ill_short_sg or result.ill_short)
	end

	if not data.no_plural and stem_p then
		result["ill_pl"] = generate_hv_illative_forms(result, data, stem_p, weight_p, result.ill_ending_pl or result.ill_ending or "", result.ill_short)
	end

	return result
end

-- inflection classes begin
local inflections = {}

inflections["kärpäin"] = function (data)
	local result = { typeno = "1" }
	local word = data.title
	local strong = data.args[1] or error("must specify strong grade")
	local weak = data.args[2] or error("must specify weak grade")
	if data.no_singular then
		word = get_stem(word, "iset") .. "in"
	end
	local final = mw.ustring.sub(word, -3, -3)
	local stem
	if mw.ustring.sub(word, -5, -5) == strong then
		stem = get_stem(word, strong .. strong .. final .. "in")
	else
		stem = get_stem(word, strong .. final .. "in")
	end
	local gem = get_stem(word, final .. "in")

	result.stem_gs = gem .. final .. "ise"
	result.stem_ps = stem .. weak .. final .. "ist"
	result.stem_is = stem .. strong .. final .. "ise"
	result.stem_es = stem .. strong .. final .. "isee"
	result.stem_xs = stem .. strong .. final .. "isee"
	
	result.stem_np = { gem .. final .. "ise", gem .. final .. "is" }
	result.stem_gp = stem .. strong .. final .. "isii"
	result.stem_pp = stem .. strong .. final .. "isi"
	result.stem_ip = stem .. strong .. final .. "isi"
	result.stem_ep = stem .. strong .. final .. "isii"
	result.stem_xp = stem .. strong .. final .. "isii"
	
	result.par_short_ok = true
	
	result.grade = make_gradation(strong, weak)
	result.geminate = gem ~= stem .. strong

	return process(data, result)
end

inflections["kolmas"] = function (data)
	local result = { typeno = "2" }
	local word = data.title
	if data.no_singular then -- plural title -> singular
		word = get_stem(word, "nnet") .. "s"
	end
	local stem = get_stem(word, "s")

	result.stem_gs = stem .. "nne"
	result.stem_ps = stem .. "tt"
	result.stem_is = stem .. "nte"
	result.stem_es = stem .. "nnee"
	result.stem_xs = stem .. "ntee"

	result.stem_np = stem .. "nne"
	result.stem_gp = stem .. "nsii"
	result.stem_pp = stem .. "nsi"
	result.stem_ip = stem .. "nsi"
	result.stem_ep = stem .. "nsii"
	result.stem_xp = stem .. "nsii"
	
	return process(data, result)
end


-- inflection classes end

local infl_table = [=[{| class="inflection-table vsSwitcher" data-toggle-category="declension" style="border:1px solid #CCCCFF"
|-
!colspan=3 class="vsToggleElement" style="width:35.5em; background:rgb(80%,80%,100%);text-align:left;"|Soikkola declension of {{{title}}} (<span style="font-size:90%">{{{type}}}</span>)
|- class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
! style="width:11em;" |
! style="width:12em;" | singular
! style="width:12em;" | plural
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;" |
! style="background:rgb(80%,80%,100%);width:11em" | nominative
|style="width:12em" |  {{{nom_sg}}}
|style="width:12em" |  {{{nom_pl}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;" |
! style="background:rgb(80%,80%,100%);" | genitive
|{{{gen_sg}}}
|{{{gen_pl}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;" |
! style="background:rgb(80%,80%,100%);" | partitive
|{{{par_sg}}}
|{{{par_pl}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;" |
! style="background:rgb(80%,80%,100%);" | illative
|{{{ill_sg}}}
|{{{ill_pl}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;" |
! style="background:rgb(80%,80%,100%);" | inessive
|{{{ine_sg}}}
|{{{ine_pl}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;" |
! style="background:rgb(80%,80%,100%);" | elative
|{{{ela_sg}}}
|{{{ela_pl}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;" |
! style="background:rgb(80%,80%,100%);" | allative
|{{{all_sg}}}
|{{{all_pl}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;" |
! style="background:rgb(80%,80%,100%);" | adessive
|{{{ade_sg}}}
|{{{ade_pl}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;" |
! style="background:rgb(80%,80%,100%);" | ablative
|{{{abl_sg}}}
|{{{abl_pl}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;" |
! style="background:rgb(80%,80%,100%);" | translative
|{{{tra_sg}}}
|{{{tra_pl}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;" |
! style="background:rgb(80%,80%,100%);" | essive
|{{{ess_sg}}}
|{{{ess_pl}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;" |
! style="background:rgb(80%,80%,100%);" | exessive<sup>1)</sup>
|{{{exe_sg}}}
|{{{exe_pl}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;" |
| colspan="3" style="background:rgb(80%,80%,100%);font-size:smaller" | <sup>1)</sup> obsolete <br /> <sup>*)</sup> the '''accusative''' corresponds with either the '''genitive''' (<span class="gender"><abbr title="singular number">sg</abbr></span>) or '''nominative''' (<span class="gender"><abbr title="plural number">pl</abbr></span>)
|}]=]

local function link(text)
	return require("Module:links").full_link{ term = text, lang = m_izh.lang }
end

local function mention(text)
	return require("Module:links").full_link({ term = text, lang = m_izh.lang }, "term")
end

function export.show(frame)
	local infl_type = frame.args[1] or error("inflection class not specified")
	local infl = inflections[infl_type] or error("unsupported inflection type")
	local args = frame:getParent().args
	local title = args["title"] or mw.title.getCurrentTitle().text

	local geminate, elongate, vh, headword
	if args["g"] == "1" then
		geminate = true
	elseif args["g"] == "0" or args["g"] == "-" then
		geminate = false
	else
		headword = args["g"]
		vh = m_izh.guess_vowel_harmony(headword or title)
	end
	
	if args["e"] == "1" then
		elongate = true
	elseif args["e"] == "0" or args["e"] == "-" then
		elongate = false
	else
		elongate = nil
	end
	
	if args["v"] then
		vh = args["v"]
		if vh ~= "a" and vh ~= "ä" then
			error("Invalid vowel harmony specification")
		end
	elseif not vh then
		vh = m_izh.guess_vowel_harmony(title)
	end

	local data = { title = title, headword = headword, geminate = geminate, elongate = elongate, vh = vh, args = args }

	if args["n"] then
		if args["n"] == "s" or args["n"] == "sg" then
			data.no_plural = true
		elseif args["n"] == "p" or args["n"] == "pl" then
			data.no_singular = true
		end
	end

	local forms = infl(data)

	local function repl(form)
		if form == "title" then
			return "'''" .. title .. "'''"
		elseif form == "type" then
			if forms.irregular then
				return "irregular"
			end
			local s = "type " .. forms.typeno .. "/" .. mention(infl_type)
			if forms.grade then
				s = s .. ", " .. forms.grade
			else
				s = s .. ", " .. make_gradation(nil, nil)
			end
			if forms.geminate then
				s = s .. ", gemination"
			end
			return s
		else
			local value = forms[form]
			if not value then
				return "&mdash;"
			elseif type(value) == "table" then
				local result = {}
				for _, f in ipairs(value) do
					table.insert(result, link(f))
				end
				return table.concat(result, ", ")
			else
				return link(value)
			end
		end
	end

	local result = mw.ustring.gsub(infl_table, "{{{([a-z0-9_:]+)}}}", repl)
	result = mw.ustring.gsub(result, "{{m|izh|([^}]-)}}", mention)
	return result
end

return export