Module:vot-conj

local export = {} local m_vot = require("Module:vot")

local function get_stem(word, ending) local fragment = mw.ustring.match(word, ending .. "$") if fragment then return mw.ustring.sub(word, 1, -mw.ustring.len(fragment) - 1), fragment 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", ["õ"] = "e" }) end return w end

local function reduce(w) return select(2, m_vot.guess_reduction(w)) end

local function get_e(vh) return (vh == "ä") and "e" or "õ" end

local function get_or(value, fallback) return (value and #value > 0) and value or fallback 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 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 geminate(t) local gem = m_vot.guess_gemination(t) if gem then return gem .. mw.ustring.sub(t, -1) else return t	end end

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

local function do_action(data, t, action) if type(forms) == "table" then local r = {} for _, form in ipairs(forms) do			table.insert(r, do_action(data, form, action)) end return r	end return action(t) 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 extract_grade(data, strong, weak, stem) if data.geminate ~= false then if mw.ustring.match(strong, "^" .. m_vot.consonant .. m_vot.palatalize .. "?$") then -- gemination local final = strong if mw.ustring.match(stem, final .. final .. "$") then data.geminate = true stem = get_stem(stem, final) end elseif strong == "ts" and mw.ustring.match(stem, "tts$") then -- gemination data.geminate = true stem = get_stem(stem, "tts") .. "ts" elseif strong == "tš" and mw.ustring.match(stem, "ttš$") then -- gemination data.geminate = true stem = get_stem(stem, "ttš") .. "tš" end end return get_stem(stem, strong) end

local function unreduce_one(x) return ({["õ"] = "a", ["e"] = "ä"})[x] or x end

local function make_i_stem(stem, strong, weak, final, s)	if mw.ustring.find(strong, "t$") and not mw.ustring.find(weak, "t$") and mw.ustring.find(final, "[eõ]") then if mw.ustring.find(weak, "[hlnr]$") then return stem .. mw.ustring.sub(weak, 1, 1) .. s		else return stem .. s		end end return stem .. (s == "z" and weak or strong) end

local function lengthen(t) if mw.ustring.find(t, m_vot.vowel .. "$") and not mw.ustring.find(t, m_vot.vowel .. m_vot.vowel .. "$") then return t .. mw.ustring.sub(t, -1) else return t	end end

local function postprocess(form, stem_split, do_not_reduce, stem_syl_count) form = do_not_reduce and form or m_vot.apply_reduction(form, stem_split, nil, nil, stem_syl_count) return form end

local function process(data) local A = data.vh	local E = (A == "ä") and "e" or "õ" local O = (A == "ä") and "ö" or "o" local U = (A == "ä") and "ü" or "u"

-- present stem (strong, weak) local pres_s = data.stem_pres_s or data.stem_pres local pres_w = data.stem_pres_w or data.stem_pres -- past stem (strong, weak) local past_s = data.stem_past_s or data.stem_past local past_w = data.stem_past_w or data.stem_past -- present passive stem local pasv = data.stem_pasv or append(gsub_all(pres_w, m_vot.vowel .. "$", ""), "t") -- 2nd infinitive local inf2 = data.stem_inf2 or pres_s -- conditional stem local cond = data.stem_cond or gsub_all(past_s, "i$", "") -- imperative stem local impr = data.stem_impr or (pres_w .. "k") -- past active participle stem local ptcp_a = data.stem_ptcp_a or append(pres_s, "n") -- past passive participle stem local ptcp_p = data.stem_ptcp_p or pasv

local result = { }

result.pres_part = with_note("also used as the agent noun", append(pres_s, "j" .. A)) result.past_part = append(ptcp_a, U)	result.past_pasv_part = append(ptcp_p, U)

result.pres_pasv = append(pasv, A)	result.pres_1sg = append(pres_w, "n") result.pres_2sg = append(pres_w, "d") result.pres_3sg = append(pres_w, "b") result.pres_1pl = append(pres_w, "mm" .. A) result.pres_2pl = append(pres_w, "tt" .. A)	result.pres_3pl = result.pres_pasv result.pres_conn = pres_w result.pres_pasv_conn = append(pasv, A)

result.past_1sg = append(past_w, "n") result.past_2sg = append(past_w, "d") result.past_3sg = past_s result.past_1pl = append(past_w, "mm" .. A) result.past_2pl = append(past_w, "tt" .. A)	result.past_pasv = append(ptcp_p, "ii") result.past_3pl = result.past_pasv

result.cond_1sg = append(cond, "izin") result.cond_2sg = append(cond, "izid") result.cond_3sg = append(cond, "izʹ") result.cond_1pl = append(cond, "izimm" .. A) result.cond_2pl = append(cond, "izitt" .. A) result.cond_pasv = append(ptcp_p, A .. "izʹ") result.cond_3pl = result.cond_pasv

result.impr_2sg = result.pres_conn result.impr_3sg = append(impr, "o") result.impr_2pl = append(impr, "a") result.impr_3pl = append(impr, "od")

result.inf1 = lengthen(data.title) result.inf2_ill = append(inf2, "m" .. A .. A) result.inf2_ine = append(inf2, "m" .. A .. "z") result.inf2_ela = append(inf2, "m" .. A .. "ss" .. E) result.inf2_abe = append(inf2, "m" .. A .. "tt" .. E)

-- cleanup virtual syllable breaks and do reductions data.infl_root_split = m_vot.split_syllables(data.infl_root) --local stem_syl_count = #m_vot.split_syllables(pres_s) local stem_syl_count = #data.infl_root_split for k, v in pairs(result) do		local do_not_reduce = {["pres_3pl"] = true, ["pres_pasv"] = true, ["impr_2pl"] = true} if type(v) == "string" then result[k] = postprocess(mw.ustring.gsub(v, m_vot.virtual_syllable_break, ""), data.infl_root_split, do_not_reduce[k], stem_syl_count) elseif type(v) == "table" then for i, f in ipairs(v) do				if type(f) == "table" and f.form then f.form = postprocess(mw.ustring.gsub(f.form, m_vot.virtual_syllable_break, ""), data.infl_root_split, do_not_reduce[k], stem_syl_count) elseif type(f) == "string" then v[i] = postprocess(mw.ustring.gsub(f, m_vot.virtual_syllable_break, ""), data.infl_root_split, do_not_reduce[k], stem_syl_count) end end end end return result end

-- inflection classes begin local inflections = {}

inflections["saavvõ"] = function (data) data.typeno = "I" local word = data.title local vh = data.vh

local stem = get_stem(word, "[" .. vh .. get_e(vh) .. "]") local stem_short local final_cons if mw.ustring.find(stem, "dʹdʹ$") then stem = mw.ustring.sub(stem, 1, -5) .. "i" final_cons = "j" elseif mw.ustring.find(stem, "jj$") then stem = mw.ustring.sub(stem, 1, -3) final_cons = "jj" elseif mw.ustring.find(stem, "j$") then stem = mw.ustring.sub(stem, 1, -2) final_cons = "j" elseif mw.ustring.find(stem, "[^aäeiõouüö][aäeiõouüö]vv$") then stem_short = get_stem(stem, "vv") stem = stem_short .. mw.ustring.sub(stem, -3, -3) final_cons = "vv" else stem = get_stem(stem, "vv") final_cons = "vv" end stem_short = stem_short or stem local final_pres = get_or(data.args[1], nil) local final_past = mw.ustring.sub(stem, -2, -2) final_past = get_or(data.args[2], final_past == "ö" and "e" or final_past)

if final_pres then data.stem_pres = mw.ustring.sub(stem, 1, -3) .. final_pres .. final_pres else data.stem_pres = stem end data.stem_past = mw.ustring.sub(stem, 1, -3) .. final_past .. "i"

data.stem_pasv = stem_short .. final_cons data.stem_cond = data.stem_past .. "s" .. get_e(vh) data.stem_inf2 = stem data.stem_ptcp_p = stem .. "t" data.grade = make_gradation(strong, weak) data.infl_root = stem return process(data) end

inflections["kuttsua"] = function (data) data.typeno = "II-1" local word = data.title local vh = data.vh	local strong = data.args[1] or error("must specify strong grade") local weak = data.args[2] or error("must specify weak grade")

--if strong ~= "" and weak == "" then weak = m_vot.virtual_syllable_break end local final = data.args[3] or mw.ustring.sub(word, -2, -2) local stem = get_stem(word, final == vh and vh or (final .. "[" .. vh .. get_e(vh) .. "]"))	stem = extract_grade(data, strong, weak, stem)

data.stem_pres = stem .. weak .. final data.stem_pres_s = stem .. strong .. final data.stem_past_s = stem .. strong .. final data.stem_past_w = stem .. strong .. final .. "zi" data.stem_pasv = stem .. weak .. (final == vh and get_e(vh) or final) .. "t" data.stem_ptcp_a = stem .. strong .. final .. "nn" data.stem_ptcp_p = stem .. weak .. (final == vh and get_e(vh) or final) .. "tt" data.stem_inf2 = stem .. strong .. final data.stem_impr = stem .. strong .. final .. "g" data.grade = make_gradation(strong, weak) data.infl_root = stem return process(data) end

inflections["alkua"] = function (data) data.typeno = "II-2" local word = data.title local vh = data.vh	local strong = data.args[1] or error("must specify strong grade") local weak = data.args[2] or error("must specify weak grade")

--if strong ~= "" and weak == "" then weak = m_vot.virtual_syllable_break end local final = mw.ustring.sub(word, -2, -2) local stem = get_stem(word, strong .. final .. "[" .. vh .. get_e(vh) .. "]")

data.stem_pres = stem .. weak .. final data.stem_pres_s = stem .. strong .. final data.stem_past_s = stem .. strong .. final data.stem_past_w = stem .. weak .. final .. "zi" data.stem_pasv = stem .. weak .. final .. "t" data.stem_ptcp_a = stem .. strong .. final .. "nn" data.stem_ptcp_p = stem .. weak .. final .. "t" data.stem_inf2 = stem .. strong .. final data.stem_impr = stem .. strong .. final .. "g" data.grade = make_gradation(strong, weak) data.infl_root = stem return process(data) end

inflections["tuntõa"] = function (data) data.typeno = "III-1" local word = data.title local vh = data.vh	local strong = data.args[1] or error("must specify strong grade") local weak = data.args[2] or error("must specify weak grade") local e = get_e(vh)

--if strong ~= "" and weak == "" then weak = m_vot.virtual_syllable_break end local stem = get_stem(word, strong .. "[" .. vh .. e .. "i]" .. vh .. "?") local final = get_or(data.args[3], vh) local final_pasv = mw.ustring.find(final, "[aä]") and frontalize("õ", vh) or final

data.stem_pres = stem .. weak .. final data.stem_pres_s = stem .. strong .. final data.stem_past_s = make_i_stem(stem, strong, weak, e, "s") .. "i" data.stem_past_w = make_i_stem(stem, strong, weak, e, "z") .. "i" data.stem_pasv = stem .. weak .. final_pasv .. "t" data.stem_ptcp_a = stem .. strong .. final .. "nn" data.stem_ptcp_p = stem .. weak .. final_pasv .. "tt" data.stem_cond = stem .. strong .. final data.stem_impr = stem .. strong .. final .. "g" data.stem_inf2 = stem .. strong .. final data.grade = make_gradation(strong, weak) data.infl_root = stem return process(data) end

local function get_type3_past_ending(stem, final, vh) if vh == "a" and final == "a" and mw.ustring.find(stem, "a") then return "õ" else return "i" end end

inflections["õssa"] = function (data) data.typeno = "III-2" local word = data.title local vh = data.vh	local strong = data.args[1] or error("must specify strong grade") local weak = data.args[2] or error("must specify weak grade") local e = get_e(vh)

--if strong ~= "" and weak == "" then weak = m_vot.virtual_syllable_break end local final = get_or(data.args[3], vh) local final_pasv = mw.ustring.find(final, "[aä]") and frontalize("õ", vh) or final local stem = get_stem(word, "[" .. vh .. e .. "i]" .. vh .. "?") stem = extract_grade(data, strong, weak, stem)

data.stem_pres = stem .. weak .. final data.stem_pres_s = stem .. strong .. final data.stem_past_s = make_i_stem(stem, strong, weak, e, "s") .. "i" data.stem_past_w = make_i_stem(stem, strong, weak, e, "z") .. "i" data.stem_pasv = stem .. weak .. final_pasv .. "t" data.stem_ptcp_a = stem .. strong .. final .. "nn" data.stem_ptcp_p = stem .. weak .. final_pasv .. "tt" data.stem_cond = stem .. strong .. final data.stem_impr = stem .. strong .. final .. "g" data.stem_inf2 = stem .. strong .. final data.grade = make_gradation(strong, weak) data.infl_root = stem return process(data) end

inflections["täätä"] = function (data) data.typeno = "III-2" local word = data.title local vh = data.vh	local strong = "t" local weak = "" local e = get_e(vh)

--if strong ~= "" and weak == "" then weak = m_vot.virtual_syllable_break end local stem = get_stem(word, strong .. "[" .. vh .. e .. "i]" .. vh .. "?") local final = get_or(data.args[3], vh) local final_pasv = mw.ustring.find(final, "[aä]") and frontalize("õ", vh) or final

data.stem_pres = stem data.stem_pres_s = stem .. "t" .. final data.stem_past_s = make_i_stem(stem, "t", weak, e, "s") .. "i" data.stem_past_w = make_i_stem(stem, "t", weak, e, "z") .. "i" data.stem_pasv = stem .. "j" .. final_pasv .. "t" data.stem_ptcp_a = stem .. "t" .. final .. "nn" data.stem_ptcp_p = stem .. "j" .. final_pasv .. "tt" data.stem_cond = stem .. "t" .. final data.stem_impr = stem .. "t" .. final .. "g" data.stem_inf2 = stem .. "t" .. final data.grade = make_gradation(strong, weak) data.infl_root = stem return process(data) end

inflections["anta"] = function (data) data.typeno = "III-3" local word = data.title local vh = data.vh	local strong = data.args[1] or error("must specify strong grade") local weak = data.args[2] or error("must specify weak grade") local e = get_e(vh)

--if strong ~= "" and weak == "" then weak = m_vot.virtual_syllable_break end local stem = get_stem(word, "[" .. vh .. e .. "i]" .. vh .. "?") stem = extract_grade(data, strong, weak, stem) local final = get_or(data.args[3], vh) local final_pasv = mw.ustring.find(final, "[aä]") and frontalize("õ", vh) or final

data.stem_pres = stem .. weak .. final data.stem_pres_s = stem .. strong .. final data.stem_past_s = make_i_stem(stem, strong, weak, final, "s") .. "i" data.stem_past_w = make_i_stem(stem, strong, weak, final, "z") .. "i" data.stem_pasv = stem .. weak .. final_pasv .. "t" data.stem_ptcp_a = stem .. strong .. final .. "nn" data.stem_ptcp_p = stem .. weak .. final_pasv .. "tt" data.stem_cond = stem .. strong .. (final == "i" and "" or final) data.stem_impr = stem .. strong .. final .. "g" data.stem_inf2 = stem .. strong .. final data.grade = make_gradation(strong, weak) data.infl_root = stem return process(data) end

inflections["ellä"] = function (data) data.typeno = "III-4" local word = data.title local vh = data.vh	local strong = data.args[1] or error("must specify strong grade") local weak = data.args[2] or error("must specify weak grade") local e = get_e(vh)

--if strong ~= "" and weak == "" then weak = m_vot.virtual_syllable_break end local stem = get_stem(word, "[" .. vh .. e .. "i]" .. vh .. "?") stem = extract_grade(data, strong, weak, stem) local final = get_or(data.args[3], vh) local final_pasv = mw.ustring.find(final, "[aä]") and frontalize("õ", vh) or final

local past_ending = get_type3_past_ending(stem, final, vh)

data.stem_pres = stem .. weak .. final data.stem_pres_s = stem .. strong .. final data.stem_past_s = make_i_stem(stem, strong, weak, final, "s") .. past_ending data.stem_past_w = make_i_stem(stem, strong, weak, final, "z") .. past_ending data.stem_pasv = stem .. weak .. final_pasv .. "t" data.stem_ptcp_a = stem .. strong .. final .. "nn" data.stem_ptcp_p = stem .. weak .. final_pasv .. "tt" data.stem_cond = stem .. strong .. final data.stem_impr = stem .. strong .. final .. "g" data.stem_inf2 = stem .. strong .. final data.grade = make_gradation(strong, weak) data.infl_root = stem return process(data) end

inflections["vasatõ"] = function (data) data.typeno = "IV" local word = data.title local vh = data.vh	local weak = data.args[1] or error("must specify weak grade") local strong = data.args[2] or error("must specify strong grade")

--if strong ~= "" and weak == "" then weak = m_vot.virtual_syllable_break end local cons = mw.ustring.sub(word, -2, -2) local stem, final if cons == "t" then final = unreduce_one(mw.ustring.sub(word, -3, -3)) stem = get_stem(word, weak .. m_vot.vowel .. "t[aäõe]?") elseif cons == "s" then final = mw.ustring.sub(word, -4, -4) stem = mw.ustring.gsub(get_stem(word, final .. "ss[aäõe]?"), final .. "$", "") final = unreduce_one(final) else error("Unrecognized infinitive for type IV") end final = get_or(data.args[3], final)

local strong_stem = stem .. strong .. final local weak_stem = stem .. weak .. final local u = frontalize("u", vh) local do_geminate = data.geminate == nil and (final == vh) or data.geminate

data.stem_pres = do_geminate and (geminate(stem .. strong .. final) .. final) or strong_stem data.stem_past_s = strong_stem .. "zi" data.stem_past_w = strong_stem .. "zi" data.stem_pasv = weak_stem .. cons .. (cons == "s" and cons or "") data.stem_impr = weak_stem .. cons .. "k" data.stem_cond = mw.ustring.gsub(reduce(strong_stem), "i$", "") data.stem_ptcp_a = weak_stem .. "nn" data.stem_ptcp_p = weak_stem .. cons .. "t" data.stem_inf2 = data.stem_pres data.grade = make_gradation(strong, weak) data.infl_root = stem return process(data) end

inflections["tehä"] = function (data) data.typeno = "V-1" local word = data.title local vh = data.vh local stem = get_stem(word, "h" .. vh) local e = get_e(vh)

data.stem_pres = stem .. e	data.stem_past_s = stem .. "tši" data.stem_past_w = stem .. "i" data.stem_pasv = stem .. "ht" data.stem_impr = stem .. "hk" data.stem_cond = stem .. "tše" data.stem_ptcp_a = stem .. "hn" data.stem_ptcp_p = data.stem_pasv data.stem_inf2 = stem .. "tš" .. e	data.grade = make_gradation(strong, weak) data.infl_root = stem return process(data) end

inflections["pesse"] = function (data) data.typeno = "V-2" local word = data.title local vh = data.vh	local cons = mw.ustring.sub(word, -2, -2) local e = get_e(vh) local stem = get_stem(word, "ss[" .. vh .. e .. "]")

local cons2 = cons == "s" and "z" or cons

data.stem_pres = stem .. cons2 .. e	data.stem_past_s = stem .. cons .. "i" data.stem_past_w = stem .. cons2 .. "i" data.stem_pasv = stem .. cons .. cons data.stem_cond = stem .. cons .. e	data.stem_impr = stem .. cons .. "k" data.stem_ptcp_a = stem .. (cons == "s" and "zn" or cons .. cons) data.stem_ptcp_p = stem .. cons .. "t" data.stem_inf2 = stem .. cons .. e	data.grade = make_gradation(strong, weak) data.infl_root = stem return process(data) end

inflections["joossõ"] = function (data) data.typeno = "V-2" local word = data.title local vh = data.vh	local cons = mw.ustring.sub(word, -2, -2) local e = get_e(vh) local stem = get_stem(word, "ss[" .. vh .. e .. "]") local stemh = mw.ustring.sub(stem, 1, -2) .. "h"

data.stem_pres = stemh .. "z" .. e	data.stem_past_s = stemh .. "si" data.stem_past_w = stemh .. "zi" data.stem_pasv = stem .. "ss" data.stem_cond = stemh .. "s" .. e	data.stem_impr = stem .. "sk" data.stem_ptcp_a = stem .. "zn" data.stem_ptcp_p = stem .. "ss" data.stem_inf2 = stemh .. "s" .. e	data.grade = make_gradation(strong, weak) data.infl_root = stem return process(data) end

inflections["tullõ"] = function (data) data.typeno = "V-3" local word = data.title local vh = data.vh	local e = get_e(vh) local weak = data.args[1] or error("must specify weak grade") local strong = data.args[2] or error("must specify strong grade") local cons = mw.ustring.sub(word, -2, -2) local stem = get_stem(word, "[lnr][lnr][" .. vh .. e .. "]") local final = get_or(data.args[3], mw.ustring.sub(stem, -1, -1)) stem = get_stem(stem, weak .. m_vot.vowel) local strong_stem = stem .. strong .. final local weak_stem = stem .. weak .. final

if cons == "r" or mw.ustring.find(stem, m_vot.vowel) then data.stem_pres = strong_stem .. cons .. e	else local pres = strong_stem if mw.ustring.find(pres, m_vot.vowel .. "$") and not mw.ustring.find(pres, m_vot.vowel .. m_vot.vowel .. "$") then pres = pres .. mw.ustring.sub(pres, -1) end if mw.ustring.find(strong_stem, "[uy]$") then data.stem_pres = strong_stem .. e		else data.stem_pres = pres end data.stem_pres_s = strong_stem .. cons .. e	end data.stem_past_s = strong_stem .. cons .. "i" data.stem_past_w = weak_stem .. cons .. "i" data.stem_pasv = weak_stem .. cons .. cons data.stem_cond = strong_stem .. cons .. e	data.stem_impr = weak_stem .. cons .. "k" data.stem_ptcp_a = weak_stem .. cons .. cons data.stem_ptcp_p = weak_stem .. cons .. "t" data.stem_inf2 = strong_stem .. cons .. e	data.grade = make_gradation(strong, weak) data.infl_root = stem return process(data) end

inflections["ootõllõ"] = function (data) data.typeno = "V-4" local word = data.title local vh = data.vh	local e = get_e(vh) local weak = data.args[1] or error("must specify weak grade") local strong = data.args[2] or error("must specify strong grade") local cons = mw.ustring.sub(word, -2, -2) local stem = get_stem(word, "[lnr][lnr][" .. vh .. e .. "]") local final = get_or(data.args[3], mw.ustring.sub(stem, -1, -1)) stem = get_stem(stem, weak .. m_vot.vowel) local strong_stem = stem .. strong .. final local weak_stem = stem .. weak .. final

data.stem_pres = strong_stem data.stem_pres_s = strong_stem .. cons .. e	data.stem_past_s = strong_stem .. cons .. "i" data.stem_past_w = strong_stem .. cons .. "i" data.stem_pasv = weak_stem .. cons .. cons data.stem_cond = strong_stem .. cons .. vh data.stem_impr = weak_stem .. cons .. "k" data.stem_ptcp_a = weak_stem .. cons .. cons data.stem_ptcp_p = weak_stem .. cons .. "t" data.stem_inf2 = strong_stem data.grade = make_gradation(strong, weak) data.infl_root = stem return process(data) end

inflections["apatõ"] = function (data) data.typeno = "V-5" local word = data.title local vh = data.vh	local e = get_e(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 = data.args[3] or error("must specify final stem vowel") local stem = get_stem(word, "t[" .. vh .. e .. "]") stem = get_stem(stem, weak .. m_vot.vowel) local strong_stem = stem .. strong .. final local weak_stem = stem .. weak .. final

data.stem_pres = strong_stem .. "n" .. e	data.stem_past_s = strong_stem .. "ni" data.stem_past_w = strong_stem .. "ni" data.stem_pasv = weak_stem .. "t" data.stem_cond = strong_stem .. "n" .. e	data.stem_impr = strong_stem .. "tk" data.stem_ptcp_a = weak_stem .. "nn" data.stem_ptcp_p = data.stem_pasv data.stem_inf2 = strong_stem .. "n" .. e	data.grade = make_gradation(strong, weak) data.infl_root = stem return process(data) 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:35em;"| Conjugation of ! colspan=6 style="width:10em;" | Indicative ! colspan=3 style="width:10em;" | Present ! colspan=3 style="width:10em;" | Perfect ! 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 ! style="width:11em; background:rgb(80%,80%,100%)" | 1st singular ! style="width:11em; background:rgb(80%,80%,100%)" | 1st singular ! style="width:11em; background:rgb(80%,80%,100%)" | 2nd singular ! style="width:11em; background:rgb(80%,80%,100%)" | 2nd singular ! style="width:11em; background:rgb(80%,80%,100%)" | 3rd singular ! style="width:11em; background:rgb(80%,80%,100%)" | 3rd singular ! style="width:11em; background:rgb(80%,80%,100%)" | 1st plural ! style="width:11em; background:rgb(80%,80%,100%)" | 1st plural ! style="width:11em; background:rgb(80%,80%,100%)" | 2nd plural ! style="width:11em; background:rgb(80%,80%,100%)" | 2nd plural ! style="width:11em; background:rgb(80%,80%,100%)" | 3rd plural ! style="width:11em; background:rgb(80%,80%,100%)" | 3rd plural ! style="width:11em; background:rgb(80%,80%,100%)" | impersonal ! style="width:11em; background:rgb(80%,80%,100%)" | impersonal ! colspan=3 style="width:11em;" | Imperfect ! colspan=3 style="width:11em;" | Pluperfect ! 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 ! style="width:11em; background:rgb(80%,80%,100%)" | 1st singular ! style="width:11em; background:rgb(80%,80%,100%)" | 1st singular ! style="width:11em; background:rgb(80%,80%,100%)" | 2nd singular ! style="width:11em; background:rgb(80%,80%,100%)" | 2nd singular ! style="width:11em; background:rgb(80%,80%,100%)" | 3rd singular ! style="width:11em; background:rgb(80%,80%,100%)" | 3rd singular ! style="width:11em; background:rgb(80%,80%,100%)" | 1st plural ! style="width:11em; background:rgb(80%,80%,100%)" | 1st plural ! style="width:11em; background:rgb(80%,80%,100%)" | 2nd plural ! style="width:11em; background:rgb(80%,80%,100%)" | 2nd plural ! style="width:11em; background:rgb(80%,80%,100%)" | 3rd plural ! style="width:11em; background:rgb(80%,80%,100%)" | 3rd plural ! style="width:11em; background:rgb(80%,80%,100%)" | impersonal ! style="width:11em; background:rgb(80%,80%,100%)" | impersonal ! colspan=6 style="width:11em;" | Conditional ! colspan=3 style="width:11em;" | Present ! colspan=3 style="width:11em;" | Perfect ! 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 ! style="width:11em; background:rgb(80%,80%,100%)" | 1st singular ! style="width:11em; background:rgb(80%,80%,100%)" | 1st singular ! style="width:11em; background:rgb(80%,80%,100%)" | 2nd singular ! style="width:11em; background:rgb(80%,80%,100%)" | 2nd singular ! style="width:11em; background:rgb(80%,80%,100%)" | 3rd singular ! style="width:11em; background:rgb(80%,80%,100%)" | 3rd singular ! style="width:11em; background:rgb(80%,80%,100%)" | 1st plural ! style="width:11em; background:rgb(80%,80%,100%)" | 1st plural ! style="width:11em; background:rgb(80%,80%,100%)" | 2nd plural ! style="width:11em; background:rgb(80%,80%,100%)" | 2nd plural ! style="width:11em; background:rgb(80%,80%,100%)" | 3rd plural ! style="width:11em; background:rgb(80%,80%,100%)" | 3rd plural ! style="width:11em; background:rgb(80%,80%,100%)" | impersonal ! style="width:11em; background:rgb(80%,80%,100%)" | impersonal ! colspan=6 style="width:11em;" | Imperative ! colspan=3 style="width:11em;" | Present ! colspan=3 rowspan="9" | ! style="width:11em;" | ! style="width:11em; background:rgb(90%,90%,100%)" | positive ! style="width:11em; background:rgb(90%,90%,100%)" | negative ! style="width:11em; background:rgb(80%,80%,100%)" | 1st singular ! style="width:11em; background:rgb(80%,80%,100%)" | 2nd singular ! style="width:11em; background:rgb(80%,80%,100%)" | 3rd singular ! style="width:11em; background:rgb(80%,80%,100%)" | 1st plural ! style="width:11em; background:rgb(80%,80%,100%)" | 2nd plural ! style="width:11em; background:rgb(80%,80%,100%)" | 3rd plural ! style="width:11em; background:rgb(80%,80%,100%)" | impersonal ! colspan=6 style="width:11em;" | Nominal forms ! colspan=3 style="width:11em;" | Infinitives ! colspan=3 style="width:11em;" | Participles ! 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 ! colspan=2 style="width:11em; background:rgb(80%,80%,100%)" | 1st ! style="width:11em; background:rgb(80%,80%,100%)" | present ! rowspan=4 style="width:11em; background:rgb(80%,80%,100%)" | 2nd ! style="width:11em; background:rgb(90%,90%,100%)" | illative ! style="width:11em; background:rgb(80%,80%,100%)" | past ! style="width:11em; background:rgb(90%,90%,100%)" | inessive ! style="width:11em; background:rgb(90%,90%,100%)" | elative ! style="width:11em; background:rgb(90%,90%,100%)" | abessive
 * - class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(80%,80%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * colspan=3 rowspan=3 style="font-size:smaller;" |
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * - class="vsHide" style="background:rgb(95%,95%,100%);vertical-align:top;"
 * }]=]
 * }]=]

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

local function link(text, prefix) return require("Module:script utilities").tag_text((prefix and prefix or "") .. require("Module:links").language_link{ term = text, lang = m_vot.lang }, m_vot.lang) end

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

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

local function note_reference(note) if note then return "" .. note .. ")"	else		return ""	end end

local function link_and_note(word_prefix, form, prefix) if type(form) == "table" then return link(word_prefix .. form.form, prefix) .. note_reference(form.note) else return link(word_prefix .. form, prefix) 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(data, form) local note = form.note if note then local index = data.notes_reverse[note] if index then form.note = index else index = tostring(#data.notes + 1) table.insert(data.notes, note) data.notes_reverse[note] = index form.note = index end end end

local function format_notes(data, forms) data.notes = {} data.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(data, form) end end else format_notes_for_form(data, v)			end end end data.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_vot.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_vot.guess_vowel_harmony(title) end

local original_title = title local prefix = args["prefix"]

if prefix then local prefix_len = mw.ustring.len(prefix) local split split, title = mw.ustring.sub(title, 1, prefix_len), mw.ustring.sub(title, prefix_len + 1) if #title == 0 or prefix ~= split then error("Prefix is too long or does not match title") end end

local data = { title = title, geminate = geminate, vh = vh, args = args, prefix = prefix } local word_prefix = prefix or "" local categories = {}

local forms = infl(data) format_notes(data, forms)

local function repl(form) local prefix = nil if form == "title" then return "'''" .. original_title .. "'''"		elseif form == "type" then if data.irregular then return "irregular" end local s = "type " .. data.typeno .. "/" .. mention(infl_type) if data.grade then s = s .. ", " .. data.grade else s = s .. ", " .. make_gradation(nil, nil) end if data.geminate then s = s .. ", gemination" end return s		elseif form == "notes" then local results = {} for index, note in ipairs(data.notes) do				table.insert(results, note_text(tostring(index), note)) end return table.concat(results, " ") elseif mw.ustring.find(form, "!") then local excl = mw.ustring.find(form, "!") prefix = mw.ustring.sub(form, 1, excl - 1) form = mw.ustring.sub(form, excl + 1) end local value = forms[form] if type(value) == "table" and value[1] then local result = {} for _, f in ipairs(value) do				table.insert(result, link_and_note(word_prefix, f, prefix)) end return table.concat(result, ", ") elseif type(value) == "string" and #value > 0 then return link_and_note(word_prefix, value, prefix) else return "&mdash;" end end

if mw.title.getCurrentTitle.namespace == 0 then table.insert(categories, "Votic " .. infl_type .. "-type verbs") end local result = mw.ustring.gsub(conj_table, "", repl) result = mw.ustring.gsub(result, "{{m|vot|([^}]-)}}", mention) return result .. require("Module:utilities").format_categories(categories, m_vot.lang) end

return export