Module:User:Surjection/izh-conj

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

This is a private module sandbox of Surjection, for their own experimentation. Items in this module may be added and removed at Surjection's discretion; do not rely on this module's stability.


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 frontalize(w, vh)
	if vh == "ä" then
		w = mw.ustring.gsub(w, "[aou]", { a = "ä", o = "ö", u = "y" })
	end
	return w
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 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(arg) do
		if type(s) == "table" then
			for _, v in ipairs(s) do
				table.insert(t, v)
			end
		elseif type(s) == "string" then
			table.insert(t, s)
		end
	end
	return t
end

local function gsub_all(t, p, q)
	if type(t) == "string" then
		return mw.ustring.gsub(t, p, q)
	end
	local r = {}
	for _, v in ipairs(t) do
		table.insert(r, mw.ustring.gsub(v, p, q))
	end
	return r
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 with_note(note, t)
	if not note then return t end
	if type(t) == "string" then
		return { { form = t, note = note } }
	end
	local r = {}
	for _, v in ipairs(t) do
		table.insert(r, { form = v, note = note })
	end
	return r
end

local function will_geminate(forms, finalc, finalv)
	if type(forms) == "string" then
		local stem = forms .. finalc .. finalv
		local gem = m_izh.guess_gemination(stem)
		if not gem then return stem end
		return gem .. finalv
	end
	local r = {}
	for _, form in ipairs(forms) do
		table.insert(r, will_geminate(form, finalc, finalv))
	end
	return r
end

local function geminate_backwards(c)
	if mw.ustring.match(c, m_izh.vowel .. m_izh.consonant .. m_izh.vowel .. "$") then
		local stem = mw.ustring.sub(c, 1, -3)
		local finalc = mw.ustring.sub(c, -2, -2)
		local finalv = mw.ustring.sub(c, -1, -1)
		return will_geminate(stem, finalc, finalv)
	elseif mw.ustring.match(c, m_izh.vowel .. m_izh.consonant .. m_izh.vowel .. m_izh.vowel .. "$") then
		local stem = mw.ustring.sub(c, 1, -4)
		local finalc = mw.ustring.sub(c, -3, -3)
		local finalv = mw.ustring.sub(c, -2, -2)
		local finalv2 = mw.ustring.sub(c, -1, -1)
		return will_geminate(stem, finalc, finalv) .. finalv2
	else
		return c
	end
end

local function will_geminate_backwards(forms, addv)
	if type(forms) == "string" then
		return geminate_backwards(forms) .. addv
	end
	local r = {}
	for _, form in ipairs(forms) do
		table.insert(r, will_geminate_backwards(form, addv))
	end
	return r
end

local function elongate_and_geminate(c)
	return elongate(geminate_backwards(c))
end

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

local function can_geminate(data, forms, finalc, finalv)
	if data.geminate == false then
		return append(forms, finalc .. finalv)
	end
	return will_geminate(data, forms, finalc, finalv)
end

local function chiefly_in_dialect(...)
	if #arg == 1 then
		return "Chiefly in the " .. arg[1] .. " dialect."
	elseif #arg > 1 then
		return "Chiefly in the " .. require("Module:table").serialCommaJoin(arg) .. " dialects."
	else
		return 1
	end
end

local function get_any(stems)
	if type(stems) == "string" then
		return stems
	elseif type(stems) == "table" then
		return stems[1]
	end
end

local function process(data, result)
	local A = data.vh
	-- present stem (strong, weak)
	local pres_s = result.stem_pres_s or result.stem_pres
	local pres_w = result.stem_pres_w or result.stem_pres
	-- past stem (strong, weak)
	local past_s = result.stem_past_s or result.stem_past
	local past_w = result.stem_past_w or result.stem_past
	-- present passive stem
	local pres_v = result.stem_pres_v
	-- past passive stem
	local past_v = result.stem_past_v
	-- 1st infinitive stem
	local inf1 = result.stem_inf1 or pres_s
	-- 2nd infinitive
	local inf2 = result.stem_inf2 or pres_s
	-- 3rd infinitive / 3rd person stem
	local inf3 = result.stem_inf3 or pres_s
	-- conditional stem
	local cond = result.stem_cond or append(gsub_all(pres_s, "[ei]$", ""), "i")
	-- imperative stem
	local impr = result.stem_impr or pres_s
	-- potential stem
	local potn = result.stem_potn or append(pres_s, "n")
	-- present participle stem
	local pres_p = result.stem_pres_p or pres_s 
	-- past participle stem
	local past_p = result.stem_past_p or append(pres_s, "n")
	-- present third-person singular stem 
	local pres_3sg = result.stem_pres_3sg or inf3
	if pres_3sg ~= geminate_backwards(pres_3sg) then
		result.geminate = true
	end

	result.pres_part = append(pres_p, "v" .. A)
	result.pres_pasv_part = append(past_v, A .. "v" .. A)
	result.past_part = gsub_all(append(past_p, "t"), "([lnprs])[lnprs]t$", "%1t")
	result.past_part_pl = append(past_p, "eet")
	result.past_pasv_part = append(past_v, frontalize("u", A))

	result.pres_pasv = append(pres_v, A .. A)
	result.pres_1sg = append(pres_w, "n")
	result.pres_2sg = append(pres_w, "t")
	result.pres_3sg = append(elongate_and_geminate_all(pres_3sg), result.monosyllabic and "p" or nil)
	result.pres_1pl = append(pres_w, "mm" .. A)
	result.pres_2pl = append(pres_w, "tt" .. A)
	result.pres_3pl = join(
		not result.monosyllabic and with_note(chiefly_in_dialect("Soikkola"),
			append(result.pres_3sg, "t")),
		with_note(not result.monosyllabic and chiefly_in_dialect("Ala-Laukaa"),
			append(pres_s, "v" .. A .. "t")),
		result.pres_pasv)
	result.pres_conn = pres_w
	result.pres_pasv_conn = append(pres_v, A)

	result.past_pasv = append(past_v, "ii")
	result.past_1sg = append(past_w, "n")
	result.past_2sg = append(past_w, "t")
	if result.has_short_past_2sg then
		result.past_2sg = join(result.past_2sg, with_note(chiefly_in_dialect("Soikkola"), append(elongate_and_geminate_all(get_stem(past_w, "si")), "st")))
	end
	result.past_3sg = past_s
	result.past_1pl = append(past_w, "mm" .. A)
	result.past_2pl = append(past_w, "tt" .. A)
	result.past_3pl = join(
		not result.monosyllabic and with_note(chiefly_in_dialect("Soikkola"),
			append(elongate_and_geminate_all(result.past_3sg), "t")),
		with_note(not result.monosyllabic and chiefly_in_dialect("Ala-Laukaa"),
			append(past_s, "v" .. A .. "t")),
		result.past_pasv)
	result.past_conn = result.past_part
	result.past_conn_pl = result.past_part_pl
	result.past_pasv_conn = result.past_pasv_part

	result.cond_pasv = append(past_v, A .. "is")
	result.cond_1sg = append(cond, "sin")
	result.cond_2sg = join(append(cond, "sit"), with_note(chiefly_in_dialect("Soikkola"), append(elongate_and_geminate_all(cond), "st")))
	result.cond_3sg = append(cond, "s")
	result.cond_1pl = append(cond, "simm" .. A)
	result.cond_2pl = append(cond, "sitt" .. A)
	result.cond_3pl = join(
		with_note(chiefly_in_dialect("Soikkola"), append(cond, "siit")),
		with_note(chiefly_in_dialect("Ala-Laukaa"), append(cond, "siv" .. A .. "t")),
		result.cond_pasv)
	result.cond_conn = result.cond_3sg
	result.cond_pasv_conn = result.cond_pasv

	result.impr_pasv = append(will_geminate(past_v .. A, "k", frontalize("o", A)), frontalize("o", A))
	result.impr_2sg = pres_w
	result.impr_3sg = append(will_geminate(impr, "k", frontalize("o", A)), frontalize("o", A))
	result.impr_2pl = append(will_geminate(impr, "k", A), A)
	result.impr_3pl = append(result.impr_3sg, "t")
	result.impr_conn = append(impr, frontalize("ko", A))
	result.impr_pasv_conn = append(past_v, frontalize("ako", A))

	result.potn_pasv = will_geminate_backwards(append(past_v, frontalize("ano", A)), frontalize("o", A))
	result.potn_1sg = append(potn, "en")
	result.potn_2sg = append(potn, "et")
	result.potn_3sg = will_geminate_backwards(append(potn, frontalize("o", A)), frontalize("o", A))
	result.potn_1pl = append(potn, "emm" .. A)
	result.potn_2pl = append(potn, "ett" .. A)
	result.potn_3pl = append(result.potn_3sg, "t")
	result.potn_conn = append(potn, "e")
	result.potn_pasv_conn = append(past_v, A .. "ne")

	result.inf1 = { data.title }
	if m_izh.guess_elongation(get_any(inf2) .. "e") then
		inf2 = append(inf2, "e")
		if mw.ustring.match(inf2, m_izh.vowel .. m_izh.vowel .. "$") then
			inf2 = mw.ustring.sub(inf2, 1, -2) .. "jee"
		else
			inf2 = inf2 .. "e"
		end
	else
		-- potentially geminate
		inf2 = will_geminate_backwards(inf2, "e")
	end
	result.inf2_ine = append(inf2, "s")
	result.inf2_ins = append(inf2, "n")
	result.inf3_ill = append(will_geminate(inf3, "m", A), A)
	result.inf3_ine = append(inf3, "m" .. A .. (m_izh.guess_elongation(inf3 .. "m" .. A) and A or "") .. "s")
	result.inf3_ela = append(inf3, "m" .. A .. "st")
	result.inf3_abe = append(inf3, "m" .. A .. "t" .. A)
	result.inf4_nom = append(will_geminate(inf3, "m", "i"), "in")
	result.inf4_par = join(append(inf3, "mist" .. A), append(inf3, "mist"))

	if result.short_past_3sg then
		result.past_3sg = gsub_all(result.past_3sg, "i$", "")
	end

	-- cleanup virtual syllable breaks
	for k, v in pairs(result) do
		if type(v) == "string" then
			result[k] = mw.ustring.gsub(v, m_izh.virtual_syllable_break, "")
		elseif type(v) == "table" then
			for i, f in ipairs(v) do
				if type(f) == "table" and f.form then
					f.form = mw.ustring.gsub(f.form, m_izh.virtual_syllable_break, "")
				elseif type(f) == "string" then
					v[i] = mw.ustring.gsub(f, m_izh.virtual_syllable_break, "")
				end
			end
		end
	end
	return result
end

local function ungeminate(data, result, strong, weak, stem)
	if data.geminate ~= false and mw.ustring.len(strong) == 1 then
		-- gemination
		local final = strong
		if final == "j" then
			final = "i"
		end
		
		if mw.ustring.match(stem, final .. "$") then
			result.geminate = true
			return get_stem(stem, final)
		end
	end
	return stem
end

-- inflection classes begin
local inflections = {}

inflections["ampua"] = 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")
	local vh = data.vh
	local final = mw.ustring.sub(word, -2, -2)
	local stem = ungeminate(data, result, strong, weak, get_stem(word, strong .. final .. vh))

	if strong ~= "" and weak == "" then weak = m_izh.virtual_syllable_break end
	result.stem_pres_s = stem .. strong .. final
	result.stem_pres_w = stem .. weak .. final
	result.stem_past_s = stem .. strong .. final .. "i"
	result.stem_past_w = stem .. weak .. final .. "i"
	result.stem_pres_v = stem .. weak .. final .. "t"
	result.stem_past_v = stem .. weak .. final .. "tt"
	
	result.grade = make_gradation(strong, weak)
	return process(data, result)
end

inflections["kirjuttaa"] = function (data)
	local result = { typeno = "2" }
	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")
	local vh = data.vh
	local stem = ungeminate(data, result, strong, weak, get_stem(word, frontalize(strong .. "aa", vh)))

	if strong ~= "" and weak == "" then weak = m_izh.virtual_syllable_break end
	result.stem_pres_s = stem .. strong .. vh
	result.stem_pres_w = stem .. weak .. vh
	result.stem_past_s = stem .. strong .. "i"
	result.stem_past_w = stem .. weak .. "i"
	result.stem_pres_v = stem .. weak .. "et"
	result.stem_past_v = stem .. weak .. "ett"
	
	result.grade = make_gradation(strong, weak)
	return process(data, result)
end

inflections["kyntää"] = function (data)
	local result = { typeno = "3" }
	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")
	local vh = data.vh
	local stem = get_stem(word, frontalize(strong .. "aa", vh))

	result.stem_pres_s = stem .. strong .. vh
	result.stem_pres_w = stem .. weak .. vh
	result.stem_past = stem .. "nsi"
	result.stem_pres_v = stem .. weak .. "et"
	result.stem_past_v = stem .. weak .. "ett"
	
	result.grade = make_gradation(strong, weak)
	return process(data, result)
end

inflections["antaa"] = function (data)
	local result = { typeno = "4" }
	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")
	local vh = data.vh
	local stem = ungeminate(data, result, strong, weak, get_stem(word, frontalize(strong .. "aa", vh)))

	result.stem_pres_s = stem .. strong .. vh
	result.stem_pres_w = stem .. weak .. vh
	result.stem_past_s = stem .. strong .. frontalize("oi", vh)
	result.stem_past_w = stem .. weak .. frontalize("oi", vh)
	result.stem_pres_v = stem .. weak .. "et"
	result.stem_past_v = stem .. weak .. "ett"
	
	result.grade = make_gradation(strong, weak)
	return process(data, result)
end

inflections["laskia"] = function (data)
	local result = { typeno = "5" }
	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")
	local vh = data.vh
	local stem = ungeminate(data, result, strong, weak, get_stem(word, frontalize(strong .. "ia", vh)))

	result.stem_pres_s = stem .. strong .. "e"
	result.stem_pres_w = stem .. weak .. "e"
	result.stem_past_s = stem .. strong .. "i"
	result.stem_past_w = stem .. weak .. "i"
	result.stem_pres_v = stem .. weak .. "et"
	result.stem_past_v = stem .. weak .. "ett"
	result.stem_inf2 = stem .. strong .. "i"
	result.stem_inf3 = stem .. strong .. frontalize("o", vh)
	
	result.grade = make_gradation(strong, weak)
	return process(data, result)
end

inflections["tuntia"] = function (data)
	local result = { typeno = "6" }
	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")
	local vh = data.vh
	local stem = ungeminate(data, result, strong, weak, get_stem(word, frontalize(strong .. "ia", vh)))

	local past_stem = {
		["nt"] = "ns",
		["ht"] = "ks"
	}

	result.stem_pres_s = stem .. strong .. "e"
	result.stem_pres_w = stem .. weak .. "e"
	result.stem_past = stem .. (past_stem[strong] or error("The tuntia type is not supported for this verb")) .. "i"
	result.stem_pres_v = stem .. weak .. "et"
	result.stem_past_v = stem .. weak .. "ett"
	result.stem_inf2 = stem .. strong .. "i"
	result.stem_inf3 = stem .. strong .. frontalize("o", vh)
	
	result.grade = make_gradation(strong, weak)
	return process(data, result)
end

inflections["oppia"] = function (data)
	local result = { typeno = "7" }
	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")
	local vh = data.vh
	local stem = ungeminate(data, result, strong, weak, get_stem(word, frontalize(strong .. "ia", vh)))

	result.stem_pres_s = stem .. strong .. "i"
	result.stem_pres_w = stem .. weak .. "i"
	result.stem_past_s = stem .. strong .. "i"
	result.stem_past_w = stem .. weak .. "i"
	result.stem_pres_v = stem .. weak .. "it"
	result.stem_past_v = stem .. weak .. "itt"
	
	result.grade = make_gradation(strong, weak)
	return process(data, result)
end

inflections["voija"] = function (data)
	local result = { typeno = "8" }
	local word = data.title
	local vh = data.vh
	local stem = get_stem(word, frontalize("ja", vh))
	if #m_izh.split_syllables(stem) > 1 then error("Verb stem must be monosyllabic for the voija type") end

	result.stem_pres = stem
	result.stem_past = stem
	result.stem_pres_v = stem .. "j"
	result.stem_past_v = stem .. "t"
	result.stem_inf2 = stem .. "j"
	
	result.monosyllabic = true
	return process(data, result)
end

inflections["jäävvä"] = function (data)
	local result = { typeno = "9" }
	local word = data.title
	local vh = data.vh
	local stem = get_stem(word, frontalize("vva", vh))
	if #m_izh.split_syllables(stem) > 1 then error("Verb stem must be monosyllabic for the jäävvä type") end

	result.stem_pres = stem
	result.stem_past = mw.ustring.sub(stem, 1, -2) .. "i"
	result.stem_pres_v = stem .. "vv"
	result.stem_past_v = stem .. "t"
	result.stem_cond = result.stem_past
	result.stem_inf2 = stem .. "vv"
	
	result.monosyllabic = true
	return process(data, result)
end

inflections["käyvvä"] = function (data)
	local result = { typeno = "10" }
	local word = data.title
	local vh = data.vh
	local stem = get_stem(word, frontalize("vva", vh))
	if #m_izh.split_syllables(stem) > 1 then error("Verb stem must be monosyllabic for the käyvvä type") end

	result.stem_pres = stem
	result.stem_past = mw.ustring.sub(stem, 1, -2) .. "i"
	result.stem_pres_v = stem .. "vv"
	result.stem_past_v = stem .. "t"
	result.stem_cond = result.stem_past
	result.stem_inf2 = stem .. "vv"
	
	result.monosyllabic = true
	return process(data, result)
end

inflections["pessä"] = function (data)
	local result = { typeno = "11" }
	local word = data.title
	local vh = data.vh
	local stem = get_stem(word, frontalize("ssa", vh))

	result.stem_pres = stem .. "se"
	result.stem_past = stem .. "si"
	result.stem_pres_v = stem .. "ss"
	result.stem_past_v = stem .. "st"
	result.stem_inf3 = stem .. frontalize("so", vh)
	result.stem_potn = stem .. "ss"
	result.stem_impr = stem .. "s"
	result.stem_past_p = stem .. "ss"
	
	return process(data, result)
end

inflections["kuulla"] = function (data)
	local result = { typeno = "12" }
	local word = data.title
	local vh = data.vh
	local stem = get_stem(word, vh)
	local finalgem = mw.ustring.sub(stem, -2, -1)
	local finals = {
		["ll"] = "l",
		["nn"] = "n",
		["rr"] = "r"
	}
	local final = finals[finalgem] or error("Unsupported stem for kuulla")
	stem = get_stem(stem, finalgem)

	result.stem_pres = stem .. final .. "e"
	result.stem_past = stem .. final .. "i"
	result.stem_pres_v = stem .. finalgem
	result.stem_past_v = stem .. final .. "t"
	result.stem_inf2 = stem .. finalgem
	result.stem_inf3 = stem .. final .. frontalize("o", vh)
	result.stem_potn = stem .. finalgem
	result.stem_impr = stem .. final
	result.stem_past_p = stem .. finalgem
	
	return process(data, result)
end

inflections["valita"] = function (data)
	local result = { typeno = "13" }
	local word = data.title
	local vh = data.vh
	local stem = get_stem(word, frontalize("ta", vh))

	result.stem_pres = stem .. "tse"
	result.stem_past = stem .. "tsi"
	result.stem_pres_v = stem .. "t"
	result.stem_past_v = stem .. "tt"
	result.stem_inf2 = stem .. "t"
	result.stem_inf3 = stem .. frontalize("tso", vh)
	result.stem_potn = stem .. "nn"
	result.stem_impr = stem .. "t"
	result.stem_past_p = stem .. "n"
	
	return process(data, result)
end

inflections["joossa"] = function (data)
	local result = { typeno = "14" }
	local word = data.title
	local vh = data.vh
	local stem = get_stem(word, frontalize("ssa", vh))

	result.stem_pres = stem .. "kse"
	result.stem_past = stem .. "ksi"
	result.stem_pres_v = stem .. "ss"
	result.stem_past_v = stem .. "st"
	result.stem_inf2 = stem .. "ss"
	result.stem_inf3 = stem .. frontalize("kso", vh)
	result.stem_potn = stem .. "ss"
	result.stem_impr = stem .. "s"
	result.stem_past_p = stem .. "ss"
	
	return process(data, result)
end

inflections["valeta"] = function (data)
	local result = { typeno = "15" }
	local word = data.title
	local vh = data.vh
	local stem = get_stem(word, frontalize("ta", vh))
	local weak = data.args[1] or error("must specify weak grade")
	local strong = data.args[2] or error("must specify strong grade")
	local final = mw.ustring.sub(stem, -1, -1)
	stem = get_stem(stem, weak .. final)

	result.stem_pres = stem .. strong .. final .. "ne"
	result.stem_past = stem .. strong .. final .. "ni"
	result.stem_pres_v = stem .. weak .. final .. "t"
	result.stem_past_v = stem .. weak .. final .. "tt"
	result.stem_inf2 = stem .. weak .. final .. "t"
	result.stem_inf3 = stem .. strong .. final .. "n" .. frontalize("o", vh)
	result.stem_impr = stem .. weak .. final .. "t"
	result.stem_potn = stem .. weak .. final .. "n"
	result.stem_past_p = stem .. weak .. final .. "nn"
	
	result.grade = make_gradation(strong, weak)
	return process(data, result)
end

inflections["maata"] = function (data)
	local result = { typeno = "16" }
	local word = data.title
	local vh = data.vh
	local stem = get_stem(word, frontalize("ta", vh))
	local weak = data.args[1] or error("must specify weak grade")
	local strong = data.args[2] or error("must specify strong grade")
	local final = mw.ustring.sub(stem, -1, -1)
	stem = get_stem(stem, weak .. final)
	
	local gem = will_geminate(stem, strong, final)
	if gem ~= stem .. strong .. final then
		result.geminate = true
	end

	result.stem_pres = gem .. final
	result.stem_past = stem .. strong .. (final ~= "i" and final ~= "e" and final or "") .. "isi"
	result.stem_pres_v = stem .. weak .. final .. "t"
	result.stem_past_v = stem .. weak .. final .. "tt"
	result.stem_inf1 = stem .. strong .. final
	result.stem_inf2 = stem .. weak .. final .. "t"
	result.stem_inf3 = result.stem_pres_w
	result.stem_cond = stem .. strong .. final .. "j" .. vh .. "i"
	result.stem_impr = stem .. weak .. final .. "t"
	result.stem_potn = stem .. weak .. final .. "nn"
	result.stem_pres_p = result.stem_pres_w
	result.stem_past_p = stem .. weak .. final .. "nn"
	result.stem_pres_3sg = stem .. strong .. final .. "j" .. vh

	result.short_past_3sg = true
	result.has_short_past_2sg = true

	result.grade = make_gradation(strong, weak)
	return process(data, result)
end

inflections["hävetä"] = function (data)
	local result = { typeno = "16" }
	local word = data.title
	local vh = data.vh
	local stem = get_stem(word, frontalize("eta", vh))
	local weak = data.args[1] or error("must specify weak grade")
	local strong = data.args[2] or error("must specify strong grade")
	local final = "i"
	stem = get_stem(stem, weak)
	
	local gem = will_geminate(stem, strong, final)
	if gem ~= stem .. strong .. final then
		result.geminate = true
	end

	result.stem_pres = gem .. final
	result.stem_past = stem .. strong .. "isi"
	result.stem_pres_v = stem .. weak .. "et"
	result.stem_past_v = stem .. weak .. "ett"
	result.stem_inf1 = stem .. strong .. final
	result.stem_inf2 = stem .. weak .. "et"
	result.stem_inf3 = result.stem_pres_w
	result.stem_cond = stem .. strong .. final .. "j" .. vh .. "i"
	result.stem_impr = stem .. weak .. "et"
	result.stem_potn = stem .. weak .. "enn"
	result.stem_pres_p = result.stem_pres_w
	result.stem_past_p = stem .. weak .. "enn"
	result.stem_pres_3sg = stem .. strong .. final .. "j" .. vh

	result.short_past_3sg = true
	result.has_short_past_2sg = true

	result.grade = make_gradation(strong, weak)
	return process(data, result)
end

inflections["laskiissa"] = function (data)
	local result = { typeno = "17" }
	local word = data.title
	local vh = data.vh
	local stem = get_stem(word, frontalize("ssa", vh))
	local truncate = mw.ustring.sub(stem, 1, -2)

	result.stem_pres_s = stem
	result.stem_pres_w = stem
	result.stem_past = truncate .. "isi"
	result.stem_pres_v = stem .. "ss"
	result.stem_past_v = stem .. "st"
	result.stem_inf2 = stem .. "ss"
	result.stem_inf3 = stem
	result.stem_impr = stem .. "s"
	result.stem_potn = stem .. "ss"
	result.stem_cond = stem .. "ssi"
	result.stem_pres_p = stem
	result.stem_past_p = stem .. "ss"
	result.stem_pres_3sg = stem .. "j" .. vh
	
	result.short_past_3sg = true
	result.has_short_past_2sg = true
	return process(data, result)
end

inflections["praavihussa"] = function (data)
	local result = { typeno = "18" }
	local word = data.title
	local vh = data.vh
	local stem = get_stem(word, frontalize("ssa", vh))

	result.stem_pres = stem
	result.stem_past = stem .. "i"
	result.stem_pres_v = stem .. "ss"
	result.stem_past_v = stem .. "st"
	result.stem_inf2 = stem .. "ss"
	result.stem_impr = stem .. "s"
	result.stem_potn = stem .. "ss"
	result.stem_past_p = stem .. "ss"

	return process(data, result)
end

-- inflection classes end

local conj_table = [=[{| class="inflection-table vsSwitcher" data-toggle-category="conjugation" style="border:1px solid #CCCCFF;text-align:left;"
|-
! colspan=6 class="vsToggleElement" style="background:rgb(80%,80%,100%);text-align:left;width:30em;"| Conjugation of {{{title}}} (<span style="font-size:90%">{{{type}}}</span>)
|- class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
! colspan=6 style="width:10em;" | [[indicative mood|Indikativa]]
|- class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
! colspan=3 style="width:10em;" | [[present tense|Preesens]]
! colspan=3 style="width:10em;" | [[perfect|Perfekta]]
|- class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
! style="width:10em;" |
! style="width:13em; background:rgb(90%,90%,100%)" | positive
! style="width:13em; background:rgb(90%,90%,100%)" | negative
! style="width:10em;" |
! style="width:13em; background:rgb(90%,90%,100%)" | positive
! style="width:13em; background:rgb(90%,90%,100%)" | negative
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 1st singular
| {{{pres_1sg}}}
| en {{{pres_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 1st singular
| oon {{{past_part}}}
| en oo {{{past_part}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 2nd singular
| {{{pres_2sg}}}
| et {{{pres_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 2nd singular
| oot {{{past_part}}}
| et oo {{{past_part}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 3rd singular
| {{{pres_3sg}}}
| ei {{{pres_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 3rd singular
| ono {{{past_part}}}
| ei oo {{{past_part}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 1st plural
| {{{pres_1pl}}}
| emmä {{{pres_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 1st plural
| oomma {{{past_part_pl}}}
| emmä oo {{{past_part_pl}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 2nd plural
| {{{pres_2pl}}}
| että {{{pres_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 2nd plural
| ootta {{{past_part_pl}}}
| että oo {{{past_part_pl}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 3rd plural
| {{{pres_3pl}}}
| evät {{{pres_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 3rd plural
| ovat {{{past_part_pl}}}
| evät oo {{{past_part_pl}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | impersonal
| {{{pres_pasv}}}
| ei {{{pres_pasv_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | impersonal
| ono {{{past_pasv_part}}}
| ei oo {{{past_pasv_part}}}
|- class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
! colspan=3 style="width:11em;" | [[past tense|Imperfekta]]
! colspan=3 style="width:11em;" | [[pluperfect|Pluskvamperfekta]]
|- class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
! style="width:11em;" |
! style="width:11em; background:rgb(90%,90%,100%)" | positive
! style="width:11em; background:rgb(90%,90%,100%)" | negative
! style="width:11em;" |
! style="width:11em; background:rgb(90%,90%,100%)" | positive
! style="width:11em; background:rgb(90%,90%,100%)" | negative
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 1st singular
| {{{past_1sg}}}
| en {{{past_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 1st singular
| olin {{{past_part}}}
| en olt {{{past_part}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 2nd singular
| {{{past_2sg}}}
| et {{{past_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 2nd singular
| olit {{{past_part}}}
| et olt {{{past_part}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 3rd singular
| {{{past_3sg}}}
| ei {{{past_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 3rd singular
| oli {{{past_part}}}
| ei olt {{{past_part}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 1st plural
| {{{past_1pl}}}
| emmä {{{past_conn_pl}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 1st plural
| olimma {{{past_part_pl}}}
| emmä olleet {{{past_part_pl}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 2nd plural
| {{{past_2pl}}}
| että {{{past_conn_pl}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 2nd plural
| olitta {{{past_part_pl}}}
| että olleet {{{past_part_pl}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 3rd plural
| {{{past_3pl}}}
| evät {{{past_conn_pl}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 3rd plural
| olivat {{{past_part_pl}}}
| evät olleet {{{past_part_pl}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | impersonal
| {{{past_pasv}}}
| ei {{{past_pasv_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | impersonal
| oli {{{past_pasv_part}}}
| ei olt {{{past_pasv_part}}}
|- class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
! colspan=6 style="width:11em;" | [[conditional mood|Konditsionala]]
|- class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
! colspan=3 style="width:11em;" | [[present tense|Preesens]]
! colspan=3 style="width:11em;" | [[perfect|Perfekta]]
|- class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
! style="width:11em;" |
! style="width:11em; background:rgb(90%,90%,100%)" | positive
! style="width:11em; background:rgb(90%,90%,100%)" | negative
! style="width:11em;" |
! style="width:11em; background:rgb(90%,90%,100%)" | positive
! style="width:11em; background:rgb(90%,90%,100%)" | negative
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 1st singular
| {{{cond_1sg}}}
| en {{{cond_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 1st singular
| olisin {{{past_part}}}
| en olis {{{past_part}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 2nd singular
| {{{cond_2sg}}}
| et {{{cond_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 2nd singular
| olisit {{{past_part}}}
| et olis {{{past_part}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 3rd singular
| {{{cond_3sg}}}
| ei {{{cond_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 3rd singular
| olis {{{past_part}}}
| ei olis {{{past_part}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 1st plural
| {{{cond_1pl}}}
| emmä {{{cond_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 1st plural
| olisimma {{{past_part_pl}}}
| emmä olis {{{past_part_pl}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 2nd plural
| {{{cond_2pl}}}
| että {{{cond_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 2nd plural
| olisitta {{{past_part_pl}}}
| että olis {{{past_part_pl}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 3rd plural
| {{{cond_3pl}}}
| evät {{{cond_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 3rd plural
| olisivat {{{past_part_pl}}}
| evät olis {{{past_part_pl}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | impersonal
| {{{cond_pasv}}}
| ei {{{cond_pasv_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | impersonal
| olis {{{past_pasv_part}}}
| ei olis {{{past_pasv_part}}}
|- class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
! colspan=6 style="width:11em;" | [[imperative mood|Imperativa]]
|- class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
! colspan=3 style="width:11em;" | [[present tense|Preesens]]
! colspan=3 style="width:11em;" | [[perfect|Perfekta]]
|- class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
! style="width:11em;" |
! style="width:11em; background:rgb(90%,90%,100%)" | positive
! style="width:11em; background:rgb(90%,90%,100%)" | negative
! style="width:11em;" |
! style="width:11em; background:rgb(90%,90%,100%)" | positive
! style="width:11em; background:rgb(90%,90%,100%)" | negative
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 1st singular
| —
| —
! style="width:11em; background:rgb(80%,80%,100%)" | 1st singular
| —
| —
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 2nd singular
| {{{impr_2sg}}}
| elä {{{pres_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 2nd singular
| oo {{{past_part}}}
| elä oo {{{past_part}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 3rd singular
| {{{impr_3sg}}}
| elköö {{{impr_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 3rd singular
| olkoo {{{past_part}}}
| elköö olko {{{past_part}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 1st plural
| —
| —
! style="width:11em; background:rgb(80%,80%,100%)" | 1st plural
| —
| —
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 2nd plural
| {{{impr_2pl}}}
| elkää {{{impr_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 2nd plural
| olkaa {{{past_part_pl}}}
| elkää olko {{{past_part_pl}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 3rd plural
| {{{impr_3pl}}}
| elkööt {{{impr_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 3rd plural
| olkoot {{{past_part_pl}}}
| elkööt olko {{{past_part_pl}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | impersonal
| {{{impr_pasv}}}
| elköö {{{impr_pasv_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | impersonal
| olkoo {{{past_pasv_part}}}
| elköö olko {{{past_pasv_part}}}
|- class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
! colspan=6 style="width:11em;" | [[potential mood|Potentsiala]]
|- class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
! colspan=3 style="width:11em;" | [[present tense|Preesens]]
! colspan=3 style="width:11em;" | [[perfect|Perfekta]]
|- class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
! style="width:11em;" |
! style="width:11em; background:rgb(90%,90%,100%)" | positive
! style="width:11em; background:rgb(90%,90%,100%)" | negative
! style="width:11em;" |
! style="width:11em; background:rgb(90%,90%,100%)" | positive
! style="width:11em; background:rgb(90%,90%,100%)" | negative
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 1st singular
| {{{potn_1sg}}}
| en {{{potn_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 1st singular
| leenen {{{past_part}}}
| en leene {{{past_part}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 2nd singular
| {{{potn_2sg}}}
| et {{{potn_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 2nd singular
| leenet {{{past_part}}}
| et leene {{{past_part}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 3rd singular
| {{{potn_3sg}}}
| ei {{{potn_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 3rd singular
| leenöö {{{past_part}}}
| ei leene {{{past_part}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 1st plural
| {{{potn_1pl}}}
| emmä {{{potn_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 1st plural
| leenemmä {{{past_part_pl}}}
| emmä leene {{{past_part_pl}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 2nd plural
| {{{potn_2pl}}}
| että {{{potn_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 2nd plural
| leenettä {{{past_part_pl}}}
| että leene {{{past_part_pl}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | 3rd plural
| {{{potn_3pl}}}
| evät {{{potn_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | 3rd plural
| leenööt {{{past_part_pl}}}
| evät leene {{{past_part_pl}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(80%,80%,100%)" | impersonal
| {{{potn_pasv}}}
| ei {{{potn_pasv_conn}}}
! style="width:11em; background:rgb(80%,80%,100%)" | impersonal
| leenöö {{{past_pasv_part}}}
| ei leene {{{past_pasv_part}}}
|- class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
! colspan=6 style="width:11em;" | Nominal forms
|- class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
! colspan=3 style="width:11em;" | [[infinitive|Infinitivat]]
! colspan=3 style="width:11em;" | [[participle|Partisipat]]
|- class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
! colspan=2 style="width:11em;" |
! style="width:11em; background:rgb(90%,90%,100%)" |
! style="width:11em;" |
! style="width:11em; background:rgb(90%,90%,100%)" | active
! style="width:11em; background:rgb(90%,90%,100%)" | passive
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! colspan=2 style="width:11em; background:rgb(80%,80%,100%)" | 1st
| {{{inf1}}}
! style="width:11em; background:rgb(80%,80%,100%)" | present
| {{{pres_part}}}
| {{{pres_pasv_part}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! rowspan=2 style="width:11em; background:rgb(80%,80%,100%)" | 2nd
! style="width:11em; background:rgb(90%,90%,100%)" | inessive
| {{{inf2_ine}}}
! style="width:11em; background:rgb(80%,80%,100%)" | past
| {{{past_part}}}
| {{{past_pasv_part}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(90%,90%,100%)" | instructive
| {{{inf2_ins}}}
| colspan=3 rowspan=7 style="font-size:smaller;" | {{{notes}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! rowspan=4 style="width:11em; background:rgb(80%,80%,100%)" | 3rd
! style="width:11em; background:rgb(90%,90%,100%)" | illative
| {{{inf3_ill}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(90%,90%,100%)" | inessive
| {{{inf3_ine}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(90%,90%,100%)" | elative
| {{{inf3_ela}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(90%,90%,100%)" | abessive
| {{{inf3_abe}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! rowspan=4 style="width:11em; background:rgb(80%,80%,100%)" | 4th
! style="width:11em; background:rgb(90%,90%,100%)" | nominative
| {{{inf4_nom}}}
|- class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
! style="width:11em; background:rgb(90%,90%,100%)" | partitive
| {{{inf4_par}}}
|}]=]

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

local function tag(text)
	return require("Module:script utilities").tag_text(text, m_izh.lang, nil, "term")
end

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

local function help_tooltip(text)
	return "<sup>" .. tostring(mw.html.create("span"):attr("style", "cursor:help"):attr("title", text):wikitext("?")) .. "</sup>"
end

local function note_reference(note)
	if note then
		return "<sup>" .. note .. ")</sup>"
	else
		return ""
	end
end

local function link_and_note(form)
	if type(form) == "table" then
		return link(form.form) .. note_reference(form.note)
	else
		return link(form)
	end
end

local function note_text(reference, text)
	return note_reference(reference) .. " " .. text
end

-- extract notes from forms into a list and replace by their index
local function format_notes_for_form(forms, form)
	local note = form.note
	if note then
		local index = forms.notes_reverse[note]
		if index then
			form.note = index
		else
			index = tostring(#forms.notes + 1)
			table.insert(forms.notes, note)
			forms.notes_reverse[note] = index
			form.note = index
		end
	end
end

local function format_notes(forms)
	forms.notes = {}
	forms.notes_reverse = {}
	for k, v in pairs(forms) do
		if type(v) == "table" then
			if v[1] then
				for _, form in ipairs(v) do
					if type(form) == "table" then
						format_notes_for_form(forms, form)
					end
				end
			else
				format_notes_for_form(forms, v)
			end
		end
	end
	forms.notes_reverse = nil
end

function export.raw(word, infl_type, grad1, grad2, args)
	if not infl_type then error("inflection class not specified") end
	args = args or {}

	local infl = inflections[infl_type] or error("unsupported inflection type")
	local geminate, vh
	if args["g"] == "1" then
		geminate = true
	elseif args["g"] == "0" or args["g"] == "-" then
		geminate = false
	end
	
	if args["v"] then
		vh = args["v"]
		if vh ~= "a" and vh ~= "ä" then
			error("Invalid vowel harmony specification")
		end
	else
		vh = m_izh.guess_vowel_harmony(word)
	end

	args[1] = args[1] or grad1
	args[2] = args[2] or grad2
	local data = { title = word, geminate = geminate, vh = vh, args = args }
	return infl(data)
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, vh
	if args["g"] == "1" then
		geminate = true
	elseif args["g"] == "0" or args["g"] == "-" then
		geminate = false
	end
	
	if args["v"] then
		vh = args["v"]
		if vh ~= "a" and vh ~= "ä" then
			error("Invalid vowel harmony specification")
		end
	else
		vh = m_izh.guess_vowel_harmony(title)
	end

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

	local forms = infl(data)
	format_notes(forms)

	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
		elseif form == "notes" then
			local results = {}
			for index, note in ipairs(forms.notes) do
				table.insert(results, note_text(tostring(index), note))
			end
			table.insert(results, note_text("*",
				"For the imperative, the 2nd plural (" .. tag(forms.impr_2pl) .. ") may be used for the 3rd person as well."))
			table.insert(results, note_text("**",
				"The interrogative is formed by adding the suffix {{m|izh|-k}} ({{m|izh|-ka}}" .. help_tooltip("in back-vocalic stems, following the consonant -t") .. "/{{m|izh|-kä}}" .. help_tooltip("in front-vocalic stems, following the consonant -t") .. ") to the indicative, or {{m|izh|-kse}} to the potential."))
			return table.concat(results, "<br />")
		else
			local value = forms[form]
			if not value then
				return "&mdash;"
			elseif type(value) == "table" and value[1] then
				local result = {}
				for _, f in ipairs(value) do
					table.insert(result, link_and_note(f))
				end
				return table.concat(result, ", ")
			else
				return link_and_note(value)
			end
		end
	end

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

return export