This module needs documentation.
Please document this module by describing its purpose and usage on the documentation page.

local lang = require("Module:languages").getByCode("sl")

local export = {}

local u = mw.ustring.char
local GRAVE		= u(0x0300)
local ACUTE		= u(0x0301)
local MACRON	= u(0x0304)
local DGRAVE	= u(0x030F)
local INVBREVE	= u(0x0311)
local ACCENT = GRAVE .. ACUTE .. MACRON .. DGRAVE .. INVBREVE


-- Returns the accent diacritic and the number of syllables from the end that it was found (0=last syllable)
local function find_accent(form)
	form = mw.ustring.toNFD(form)
	local accent, rest = mw.ustring.match(form, "([" .. ACCENT .. "])(.-)$")
	if not accent then
		return nil
	end
	local _, count = mw.ustring.gsub(rest, "[aeiou]", "")
	return accent, count
end

local function matches_accents(form, accents)
	local a, p = find_accent(form)
	
	for _, accent in ipairs(accents) do
		if accent[1] == a and accent[2] == p then
			return true
		end
	end
	
	return false
end


local function matches_accents_multiple(forms, ending, accents)
	for _, form in ipairs(forms) do
		form = mw.ustring.gsub(form, ending, "")
		if not matches_accents(form, accents) then
			return false
		end
	end
	
	return true
end


-- Inflection functions

function export.manual(frame)
	local names = {"inf", "1|s|pres", "3|s|pres", "3|p|pres", "2|s|impr", "2|p|impr", "pres|actv|ptcp", "pres|actv|converb", "m|s|l-ptcp", "f|s|l-ptcp", "n|s|l-ptcp", "supine", "past|pasv|ptcp", "past|actv|converb", "vnoun", "short|inf"}
	local params = {
		["accent"] = {list = true},
	}
	
	for _, val in ipairs(names) do
		params[(val:gsub("|", "_"))] = {list = true}
	end
	
	params["inf"].required = true
	
	local args = require("Module:parameters").process(frame:getParent().args, params)
	
	if #args["short_inf"] == 0 then
		require("Module:debug").track("sl-verbs/needs short")
	end
	
	for _, val in ipairs(args["short_inf"]) do
		if not require("Module:sl-common").has_accents(val) then
			require("Module:debug").track("sl-verbs/needs short")
		end
	end
	
	if #args["accent"] == 0 then
		require("Module:debug").track("sl-verbs/needs accent")
	end
	
	local data = {
		forms = {},
		info = "",
		categories = {},
	}
	
	local inf_na = (lang:makeEntryName(args["inf"][1] or "foo"))
	data.info = {}
	
	for _, pres in ipairs(#args["1_s_pres"] > 0 and args["1_s_pres"] or args["3_s_pres"]) do
		local pres_na = (lang:makeEntryName((pres:gsub("m$", ""))))
		
		if mw.ustring.gsub(pres_na, "a$", "ati") == inf_na then
			if not data.info["-ati -am"] then
				data.info["-ati -am"] = true
				table.insert(data.info, "-ati -am")
			end
		elseif mw.ustring.gsub(pres_na, "i$", "iti") == inf_na then
			if not data.info["-iti -im"] then
				data.info["-iti -im"] = true
				table.insert(data.info, "-iti -im")
			end
		elseif mw.ustring.gsub(pres_na, "i$", "eti") == inf_na then
			if not data.info["-eti -im"] then
				data.info["-eti -im"] = true
				table.insert(data.info, "-eti -im")
			end
		elseif mw.ustring.gsub(pres_na, "i$", "ati") == inf_na then
			if not data.info["-ati -im"] then
				data.info["-ati -im"] = true
				table.insert(data.info, "-ati -im")
			end
		elseif mw.ustring.gsub(pres_na, "ne$", "niti") == inf_na then
			if not data.info["-niti -nem"] then
				data.info["-niti -nem"] = true
				table.insert(data.info, "-niti -nem")
			end
		elseif mw.ustring.gsub(inf_na, "[eo]vati$", "uje") == pres_na then
			if not data.info["-ovati -ujem"] then
				data.info["-ovati -ujem"] = true
				table.insert(data.info, "-ovati -ujem")
			end
		elseif mw.ustring.gsub(pres_na, "([aeiou])je$", "%1ti") == inf_na or mw.ustring.gsub(pres_na, "oje$", "eti") == inf_na then
			if not data.info["vowel + -ti -jem"] then
				data.info["vowel + -ti -jem"] = true
				table.insert(data.info, "vowel + -ti -jem")
			end
		elseif mw.ustring.gsub(pres_na, "([aeiou])je$", "%1jati") == inf_na then
			if not data.info["-Vjati -Vjem"] then
				data.info["-Vjati -Vjem"] = true
				table.insert(data.info, "-Vjati -Vjem")
			end
		elseif require("Module:sl-common").t((mw.ustring.gsub(pres_na, "e$", ""))) .. "i" == inf_na or mw.ustring.gsub(inf_na, "lesti$", "olze") == pres_na or mw.ustring.gsub(inf_na, "reči$", "rže") == pres_na then
			if not data.info["obstruent + -ti -em"] then
				data.info["obstruent + -ti -em"] = true
				table.insert(data.info, "obstruent + -ti -em")
			end
		elseif mw.ustring.find(inf_na, "ati$") and require("Module:sl-common").iotation((mw.ustring.gsub(inf_na, "ati$", ""))) .. "e" == pres_na then
			if not data.info["-Cati -Cjem"] then
				data.info["-Cati -Cjem"] = true
				table.insert(data.info, "-Cati -Cjem")
			end
		elseif mw.ustring.gsub(pres_na, "[ae]?([lr])j?e$", "%1eti") == inf_na or mw.ustring.gsub(pres_na, "[ae]?[mn]j?e$", "eti") == inf_na or mw.ustring.find(inf_na, "uti$") and mw.ustring.gsub(inf_na, "uti$", "ove") == pres_na then
			if not data.info["sonorant + -ti -(j)em"] then
				data.info["sonorant + -ti -(j)em"] = true
				table.insert(data.info, "sonorant + -ti -(j)em")
			end
		elseif mw.ustring.find(inf_na, "[aeiou]ti$") and mw.ustring.find(pres_na, "e$") then
			if mw.ustring.find(inf_na, "ati$") and mw.ustring.gsub(inf_na, "ati$", "e") == pres_na then
				require("Module:debug").track("sl-verbs/-ati -em")
			elseif mw.ustring.find(inf_na, "u?vati$") and mw.ustring.gsub(inf_na, "u?vati$", "uje") == pres_na then
				require("Module:debug").track("sl-verbs/-vati -ujem")
			elseif mw.ustring.find(inf_na, "lati$") and mw.ustring.gsub(inf_na, "lati$", "olje") == pres_na then
				require("Module:debug").track("sl-verbs/-lati -oljem")
			elseif mw.ustring.find(inf_na, "ati$") and mw.ustring.gsub(inf_na, "ati$", "ane") == pres_na then
				require("Module:debug").track("sl-verbs/-ati -anem")
			elseif mw.ustring.find(inf_na, "gnati$") and mw.ustring.gsub(inf_na, "gnati$", "žene") == pres_na then
				require("Module:debug").track("sl-verbs/-gnati -ženem")
			elseif mw.ustring.gsub(pres_na, "erj?e$", "rati") == inf_na then
				require("Module:debug").track("sl-verbs/-rati -er(j)em")
			elseif mw.ustring.find(inf_na, "vati$") and mw.ustring.gsub(inf_na, "vati$", "ove") == pres_na then
				require("Module:debug").track("sl-verbs/-vati -ovem")
			elseif mw.ustring.find(inf_na, "eti$") and mw.ustring.gsub(inf_na, "eti$", "e") == pres_na then
				require("Module:debug").track("sl-verbs/-eti -em")
			elseif mw.ustring.find(inf_na, "eti$") and mw.ustring.gsub(inf_na, "eti$", "eve") == pres_na then
				require("Module:debug").track("sl-verbs/-eti -evem")
			elseif mw.ustring.find(inf_na, "iti$") and mw.ustring.gsub(inf_na, "ti$", "de") == pres_na then
				require("Module:debug").track("sl-verbs/-iti -idem")
			else
				require("Module:debug").track("sl-verbs/other")
			end
		else
			require("Module:debug").track("sl-verbs/other")
			
			if mw.ustring.find(inf_na, "ati$") and mw.ustring.gsub(inf_na, "ati$", "oji") == pres_na then
				require("Module:debug").track("sl-verbs/-ati -ojim")
			elseif mw.ustring.find(inf_na, "eti$") and mw.ustring.gsub(inf_na, "eti$", "a") == pres_na then
				require("Module:debug").track("sl-verbs/-eti -am")
			elseif mw.ustring.find(inf_na, "jti$") and mw.ustring.gsub(inf_na, "ti$", "de") == pres_na then
				require("Module:debug").track("sl-verbs/-jti -jdem")
			end
		end
	end
	
	for key, val in ipairs(data.info) do
		table.insert(data.categories, lang:getCanonicalName() .. " verbs in " .. val)
		
		for key2, val2 in ipairs(args["accent"]) do
			if val2:find("^[abc]$") then
				args["accent"][key2] = "<abbr title=\"accent pattern\">AP</abbr> ''" .. val2 .. "''"
				val2 = "accent pattern " .. val2
			elseif val2 == "circ" then
				val2 = "circumflex"
				args["accent"][key2] = val2
			end
			
			table.insert(data.categories, lang:getCanonicalName() .. " verbs in " .. val .. " (" .. val2 .. ")")
		end
		
		val = val:gsub("-[a-zčšž()]+", function(t) return require("Module:links").full_link({lang = lang, alt = t}, "term") end)
		val = val:gsub("V", "<abbr title=\"vowel\">V</abbr>"):gsub("C", "<abbr title=\"consonant\">C</abbr>"):gsub("R", "<abbr title=\"sonorant\">R</abbr>")
		data.info[key] = val
	end
	
	if #data.info > 0 then
		data.info = mw.getContentLanguage():ucfirst(table.concat(data.info, " or "))
		
		if #args["accent"] > 0 then
			data.info = data.info .. " (" .. table.concat(args["accent"], " or ") .. ")"
		end
	else
		data.info = ""
	end
	
	data.forms = require("Module:auto-subtable")()
	
	for _, val in ipairs(names) do
		local forms = args[(val:gsub("|", "_"))]
		
		if forms[1] then
			if val == "n|s|l-ptcp" then
				for _, form in ipairs(forms) do
					local base, count = form:gsub("o$", "")
					local end_accent = false
					
					if count == 0 then
						base, count = form:gsub("ȍ$", "")
						end_accent = true
					end
					
					if count == 0 then
						error("The neuter singular l-participle must end in -o")
					end
					
					table.insert(data.forms["n|s|l-ptcp"], base .. "o" .. (end_accent and DGRAVE or ""))
					table.insert(data.forms["m|d|l-ptcp"], base .. "a" .. (end_accent and DGRAVE or ""))
					table.insert(data.forms["f|d|l-ptcp"], base .. "i" .. (end_accent and DGRAVE or ""))
					table.insert(data.forms["n|d|l-ptcp"], base .. "i" .. (end_accent and DGRAVE or ""))
					table.insert(data.forms["m|p|l-ptcp"], base .. "i" .. (end_accent and DGRAVE or ""))
					table.insert(data.forms["f|p|l-ptcp"], base .. "e" .. (end_accent and DGRAVE or ""))
					table.insert(data.forms["n|p|l-ptcp"], base .. "a" .. (end_accent and DGRAVE or ""))
				end
			elseif val == "1|s|pres" then
				for _, form in ipairs(forms) do
					local base, count = form:gsub("m$", "")
					
					if count == 0 then
						error("The first-person singular present tense must end in -m")
					end
					
					table.insert(data.forms["1|s|pres"], base .. "m")
					table.insert(data.forms["2|s|pres"], base .. "š")
					table.insert(data.forms["3|s|pres"], base)
					table.insert(data.forms["1|d|pres"], base:gsub("ȅ$", "é") .. "va")
					table.insert(data.forms["2|d|pres"], base:gsub("ȅ$", "é") .. "ta")
					table.insert(data.forms["3|d|pres"], base:gsub("ȅ$", "é") .. "ta")
					table.insert(data.forms["1|p|pres"], base:gsub("ȅ$", "é") .. "mo")
					table.insert(data.forms["2|p|pres"], base:gsub("ȅ$", "é") .. "te")
					table.insert(data.forms["3|p|pres"], base:gsub("ȅ$", "é") .. "jo")
				end
			elseif val == "3|s|pres" then
				if #args["1_s_pres"] > 0 or #args["3_p_pres"] > 0 then
					error("The 3_s_pres parameter can only be used with impersonal verbs, which cannot have a 1_s_pres or 3_p_pres parameter")
				end
				
				for _, form in ipairs(forms) do
					table.insert(data.forms["3|s|pres"], form)
				end
				
				data.impersonal = true
			elseif val == "3|p|pres" then
				for _, form in ipairs(forms) do
					table.insert(data.forms["3|p|pres"], form)
				end
			elseif val == "2|p|impr" then
				for _, form in ipairs(forms) do
					local base, count = form:gsub("te$", "")
					
					if count == 0 then
						error("The second-person plural imperative must end in -te")
					end
					
					table.insert(data.forms["1|d|impr"], base .. "va")
					table.insert(data.forms["2|d|impr"], base .. "ta")
					table.insert(data.forms["1|p|impr"], base .. "mo")
					table.insert(data.forms["2|p|impr"], base .. "te")
				end
			else
				data.forms[val] = forms
			end
		end
	end
	
	data.forms:un_auto_subtable()
	
	return make_table(data)
end


function export.biti(frame)
	local params = {
	}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)
	
	local data = {
		forms = {},
		info = "athematic, irregular, suppletive",
		categories = {lang:getCanonicalName() .. " athematic verbs", lang:getCanonicalName() .. " irregular verbs", lang:getCanonicalName() .. " suppletive verbs"},
		has_neg = true,
		has_futr = true,
	}
	
	data.forms["inf"] = {"bíti"}
	data.forms["short|inf"] = {"bȉt"}
	data.forms["pres|actv|ptcp"] = {"bijọ̄č"}
	data.forms["cond"] = {"bȉ"}
	
	data.forms["m|s|l-ptcp"] = {"bȋł"}
	data.forms["f|s|l-ptcp"] = {"bilȁ"}
	data.forms["n|s|l-ptcp"] = {"bilọ̑", "bilȍ"}
	data.forms["m|d|l-ptcp"] = {"bilȁ"}
	data.forms["f|d|l-ptcp"] = {"bilȉ"}
	data.forms["n|d|l-ptcp"] = {"bilȉ"}
	data.forms["m|p|l-ptcp"] = {"bilȋ", "bilȉ"}
	data.forms["f|p|l-ptcp"] = {"bilȅ"}
	data.forms["n|p|l-ptcp"] = {"bilȁ"}
	
	data.forms["1|s|pres"] = {"sȅm"}
	data.forms["2|s|pres"] = {"sȉ"}
	data.forms["3|s|pres"] = {"jȅ"}
	data.forms["1|d|pres"] = {"svȁ"}
	data.forms["2|d|pres"] = {"stȁ"}
	data.forms["3|d|pres"] = {"stȁ"}
	data.forms["1|p|pres"] = {"smȍ"}
	data.forms["2|p|pres"] = {"stȅ"}
	data.forms["3|p|pres"] = {"sȍ"}
	
	data.forms["neg|1|s|pres"] = {"nísem"}
	data.forms["neg|2|s|pres"] = {"nísi"}
	data.forms["neg|3|s|pres"] = {"ní"}
	data.forms["neg|1|d|pres"] = {"nísva"}
	data.forms["neg|2|d|pres"] = {"nísta"}
	data.forms["neg|3|d|pres"] = {"nísta"}
	data.forms["neg|1|p|pres"] = {"nísmo"}
	data.forms["neg|2|p|pres"] = {"níste"}
	data.forms["neg|3|p|pres"] = {"níso"}
	
	data.forms["1|s|futr"] = {"bọ̑m"}
	data.forms["2|s|futr"] = {"bọ̑š"}
	data.forms["3|s|futr"] = {"bọ̑"}
	data.forms["1|d|futr"] = {"bọ̑va"}
	data.forms["2|d|futr"] = {"bọ̑sta"}
	data.forms["3|d|futr"] = {"bọ̑sta"}
	data.forms["1|p|futr"] = {"bọ̑mo"}
	data.forms["2|p|futr"] = {"bọ̑ste"}
	data.forms["3|p|futr"] = {"bọ̑do", "bọ̑jo"}
	
	data.forms["2|s|impr"] = {"bọ́di"}
	data.forms["1|d|impr"] = {"bọ́dite", "bodȋte"}
	data.forms["2|d|impr"] = {"bọ́dita", "bodȋta"}
	data.forms["1|p|impr"] = {"bọ́dimo", "bodȋmo"}
	data.forms["2|p|impr"] = {"bọ́dite", "bodȋte"}
	
	return make_table(data)
end


function export.dati(frame)
	local params = {
		[1] = {default = ""},
	}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)
	
	local data = {
		forms = {},
		info = "athematic",
		categories = {lang:getCanonicalName() .. " athematic verbs"},
	}
	
	data.forms["inf"] = {args[1] .. "dáti"}
	data.forms["short|inf"] = {args[1] .. "dȁt"}
	data.forms["supine"] = {args[1] .. "dȃt"}
	data.forms["past|pasv|ptcp"] = {args[1] .. "dán"}
	
	data.forms["m|s|l-ptcp"] = {args[1] .. "dȃł"}
	data.forms["f|s|l-ptcp"] = {args[1] .. "dála"}
	data.forms["n|s|l-ptcp"] = {args[1] .. "dȃlo"}
	data.forms["m|d|l-ptcp"] = {args[1] .. "dȃla"}
	data.forms["f|d|l-ptcp"] = {args[1] .. "dȃli"}
	data.forms["n|d|l-ptcp"] = {args[1] .. "dȃli"}
	data.forms["m|p|l-ptcp"] = {args[1] .. "dȃli"}
	data.forms["f|p|l-ptcp"] = {args[1] .. "dȃle"}
	data.forms["n|p|l-ptcp"] = {args[1] .. "dȃla"}
	
	data.forms["1|s|pres"] = {args[1] .. "dám"}
	data.forms["2|s|pres"] = {args[1] .. "dáš"}
	data.forms["3|s|pres"] = {args[1] .. "dá"}
	data.forms["1|d|pres"] = {args[1] .. "dáva"}
	data.forms["2|d|pres"] = {args[1] .. "dásta", args[1] ~= "" and args[1] .. "dáta" or nil}
	data.forms["3|d|pres"] = {args[1] .. "dásta"}
	data.forms["1|p|pres"] = {args[1] .. "dámo"}
	data.forms["2|p|pres"] = {args[1] .. "dáste", args[1] ~= "" and args[1] .. "dáte" or nil}
	data.forms["3|p|pres"] = {args[1] .. "dájo", args[1] ..  "dadọ́", args[1] ..  "dadẹ́"}
	
	data.forms["2|s|impr"] = {args[1] .. "dȁj"}
	data.forms["1|d|impr"] = {args[1] .. "dȃjva"}
	data.forms["2|d|impr"] = {args[1] .. "dȃjta"}
	data.forms["1|p|impr"] = {args[1] .. "dȃjmo"}
	data.forms["2|p|impr"] = {args[1] .. "dȃjte"}
	
	return make_table(data)
end


function export.hoteti(frame)
	local params = {
	}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)
	
	local data = {
		forms = {},
		info = "irregular",
		categories = {lang:getCanonicalName() .. " irregular verbs"},
		has_neg = true,
	}
	
	data.forms["inf"] = {"hotẹ́ti"}
	data.forms["short|inf"] = {"hotȅt", "hotẹ̑t"}
	data.forms["vnoun"] = {"hoténje"}
	data.forms["pres|actv|ptcp"] = {"hotȅč"}
	data.forms["past|pasv|ptcp"] = {"hotȅn"}
	
	data.forms["m|s|l-ptcp"] = {"hóteł"}
	data.forms["f|s|l-ptcp"] = {"hotẹ̄la"}
	data.forms["n|s|l-ptcp"] = {"hotẹ́lo"}
	data.forms["m|d|l-ptcp"] = {"hotẹ́la"}
	data.forms["f|d|l-ptcp"] = {"hotẹ́li"}
	data.forms["n|d|l-ptcp"] = {"hotẹ́li"}
	data.forms["m|p|l-ptcp"] = {"hotẹ́li"}
	data.forms["f|p|l-ptcp"] = {"hotẹ́le"}
	data.forms["n|p|l-ptcp"] = {"hotẹ́la"}
	
	data.forms["1|s|pres"] = {"họ́čem", "čȅm"}
	data.forms["2|s|pres"] = {"họ́češ", "čȅš"}
	data.forms["3|s|pres"] = {"họ́če", "čȅ"}
	data.forms["1|d|pres"] = {"họ́čeva", "čéva", "čvȁ"}
	data.forms["2|d|pres"] = {"họ́četa", "čéta", "čtȁ"}
	data.forms["3|d|pres"] = {"họ́četa", "čéta", "čtȁ"}
	data.forms["1|p|pres"] = {"họ́čemo", "čémo", "čmȍ"}
	data.forms["2|p|pres"] = {"họ́čete", "čéte", "čtȅ"}
	data.forms["3|p|pres"] = {"họ́čejo", "čéjo", "čjȍ"}
	
	data.forms["neg|1|s|pres"] = {"nọ́čem", "néčem"}
	data.forms["neg|2|s|pres"] = {"nọ́češ", "néčeš"}
	data.forms["neg|3|s|pres"] = {"nọ́če", "néče"}
	data.forms["neg|1|d|pres"] = {"nọ́čeva", "néčeva"}
	data.forms["neg|2|d|pres"] = {"nọ́četa", "néčeta"}
	data.forms["neg|3|d|pres"] = {"nọ́četa", "néčeta"}
	data.forms["neg|1|p|pres"] = {"nọ́čemo", "néčemo"}
	data.forms["neg|2|p|pres"] = {"nọ́čete", "néčete"}
	data.forms["neg|3|p|pres"] = {"nọ́čejo", "néčejo"}
	
	data.forms["2|s|impr"] = {"hóti"}
	data.forms["1|d|impr"] = {"hotȋte"}
	data.forms["2|d|impr"] = {"hotȋta"}
	data.forms["1|p|impr"] = {"hotȋmo"}
	data.forms["2|p|impr"] = {"hotȋte"}
	
	return make_table(data)
end


function export.iti(frame)
	local params = {
	}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)
	
	local data = {
		forms = {},
		info = "athematic, suppletive",
		categories = {lang:getCanonicalName() .. " athematic verbs", lang:getCanonicalName() .. " suppletive verbs"},
		has_futr = true,
	}
	
	data.forms["inf"] = {"īti"}
	data.forms["pres|actv|ptcp"] = {"gredọ̄č"}
	
	data.forms["m|s|l-ptcp"] = {"šə̏ł"}
	data.forms["f|s|l-ptcp"] = {"šlȁ"}
	data.forms["n|s|l-ptcp"] = {"šlȍ"}
	data.forms["m|d|l-ptcp"] = {"šlȁ"}
	data.forms["f|d|l-ptcp"] = {"šlȉ"}
	data.forms["n|d|l-ptcp"] = {"šlȉ"}
	data.forms["m|p|l-ptcp"] = {"šlȉ"}
	data.forms["f|p|l-ptcp"] = {"šlȅ"}
	data.forms["n|p|l-ptcp"] = {"šlȁ"}
	
	data.forms["1|s|pres"] = {"grẹ́m", "grȅm"}
	data.forms["2|s|pres"] = {"grẹ́š", "grȅš"}
	data.forms["3|s|pres"] = {"grẹ́", "grȅ"}
	data.forms["1|d|pres"] = {"grẹ́va", "gréva"}
	data.forms["2|d|pres"] = {"grẹ́sta", "grésta"}
	data.forms["3|d|pres"] = {"grẹ́sta", "grésta"}
	data.forms["1|p|pres"] = {"grẹ́mo", "grémo"}
	data.forms["2|p|pres"] = {"grẹ́ste", "gréste"}
	data.forms["3|p|pres"] = {"gredọ́", "gredȍ", "gréjo"}
	
	data.forms["1|s|futr"] = {"pọ́jdem"}
	data.forms["2|s|futr"] = {"pọ́jdeš"}
	data.forms["3|s|futr"] = {"pọ́jde"}
	data.forms["1|d|futr"] = {"pọ́jdeva"}
	data.forms["2|d|futr"] = {"pọ́jdeta"}
	data.forms["3|d|futr"] = {"pọ́jdeta"}
	data.forms["1|p|futr"] = {"pọ́jdemo"}
	data.forms["2|p|futr"] = {"pọ́jdete"}
	data.forms["3|p|futr"] = {"pọ́jdejo"}
	
	data.forms["2|s|impr"] = {"pọ̄jdi"}
	data.forms["1|d|impr"] = {"pọ̄jdiva", "pojdȋva"}
	data.forms["2|d|impr"] = {"pọ̄jdita", "pojdȋta"}
	data.forms["1|p|impr"] = {"pọ̄jdimo", "pojdȋmo"}
	data.forms["2|p|impr"] = {"pọ̄jdite", "pojdȋte"}
	
	return make_table(data)
end


function export.jesti(frame)
	local params = {
		[1] = {default = ""},
		["past_pasv_ptcp"] = {type = "boolean"},
		["vnoun"] = {type = "boolean"},
	}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)
	
	local data = {
		forms = {},
		info = "athematic",
		categories = {lang:getCanonicalName() .. " athematic verbs"},
	}
	
	data.forms["inf"] = {args[1] .. "jẹ́sti"}
	data.forms["short|inf"] = {args[1] .. "jẹ̑st", args[1] .. "jȅst"}

	if args[1] == "" then
		data.forms["supine"] = {"jẹ̑st"}
		data.forms["pres|actv|ptcp"] = {"jedọ̄č"}
	else
		data.forms["supine"] = {args[1] .. "jȅst", args[1] .. "jẹ̑st"}
	end
	
	if args["past_pasv_ptcp"] then
		data.forms["past|pasv|ptcp"] = {args[1] .. "jẹ̑den"}
	end
	
	if args["vnoun"] then
		data.forms["vnoun"] = {args[1] .. "jẹ́denje"}
	end
	
	data.forms["m|s|l-ptcp"] = {args[1] .. "jẹ̑dəł"}
	data.forms["f|s|l-ptcp"] = {args[1] .. "jẹ́dla"}
	data.forms["n|s|l-ptcp"] = {args[1] .. "jẹ́dlo"}
	data.forms["m|d|l-ptcp"] = {args[1] .. "jẹ́dla"}
	data.forms["f|d|l-ptcp"] = {args[1] .. "jẹ́dli"}
	data.forms["n|d|l-ptcp"] = {args[1] .. "jẹ́dli"}
	data.forms["m|p|l-ptcp"] = {args[1] .. "jẹ́dli"}
	data.forms["f|p|l-ptcp"] = {args[1] .. "jẹ́dle"}
	data.forms["n|p|l-ptcp"] = {args[1] .. "jẹ́dla"}
	
	data.forms["1|s|pres"] = {args[1] .. "jẹ́m"}
	data.forms["2|s|pres"] = {args[1] .. "jẹ́š"}
	data.forms["3|s|pres"] = {args[1] .. "jẹ́"}
	data.forms["1|d|pres"] = {args[1] .. "jẹ́va"}
	data.forms["2|d|pres"] = {args[1] .. "jẹ́sta"}
	data.forms["3|d|pres"] = {args[1] .. "jẹ́sta"}
	data.forms["1|p|pres"] = {args[1] .. "jẹ́mo"}
	data.forms["2|p|pres"] = {args[1] .. "jẹ́ste"}
	data.forms["3|p|pres"] = {args[1] .. "jedọ́", args[1] .. "jéjo"}
	
	data.forms["2|s|impr"] = {args[1] .. "jȅj", "jẹ̑j"}
	data.forms["1|d|impr"] = {args[1] .. "jẹ̑jva"}
	data.forms["2|d|impr"] = {args[1] .. "jẹ̑jta"}
	data.forms["1|p|impr"] = {args[1] .. "jẹ̑jmo"}
	data.forms["2|p|impr"] = {args[1] .. "jẹ̑jte"}
	
	return make_table(data)
end


function export.vedeti(frame)
	local params = {
		[1] = {default = ""},
		["vnoun"] = {type = "boolean"},
	}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)
	
	local data = {
		forms = {},
		info = "athematic",
		categories = {lang:getCanonicalName() .. " athematic verbs"},
	}
	
	data.forms["inf"] = {args[1] .. "vẹ́deti"}
	data.forms["short|inf"] = {args[1] .. "vẹ́det"}
	
	if args[1] == "" then
		data.forms["pres|actv|ptcp"] = {"vedọ̄č"}
	end
	
	if args["vnoun"] then
		data.forms["vnoun"] = {args[1] .. "vẹ́denje"}
	end
	
	data.forms["m|s|l-ptcp"] = {args[1] .. "vẹ́deł"}
	data.forms["f|s|l-ptcp"] = {args[1] .. "vẹ̄dela"}
	data.forms["n|s|l-ptcp"] = {args[1] .. "vẹ́delo"}
	data.forms["m|d|l-ptcp"] = {args[1] .. "vẹ́dela"}
	data.forms["f|d|l-ptcp"] = {args[1] .. "vẹ́deli"}
	data.forms["n|d|l-ptcp"] = {args[1] .. "vẹ́deli"}
	data.forms["m|p|l-ptcp"] = {args[1] .. "vẹ́deli"}
	data.forms["f|p|l-ptcp"] = {args[1] .. "vẹ́dele"}
	data.forms["n|p|l-ptcp"] = {args[1] .. "vẹ́dela"}
	
	data.forms["1|s|pres"] = {args[1] .. "vẹ́m"}
	data.forms["2|s|pres"] = {args[1] .. "vẹ́š"}
	data.forms["3|s|pres"] = {args[1] .. "vẹ́"}
	data.forms["1|d|pres"] = {args[1] .. "vẹ́va"}
	data.forms["2|d|pres"] = {args[1] .. "vẹ́sta"}
	data.forms["3|d|pres"] = {args[1] .. "vẹ́sta"}
	data.forms["1|p|pres"] = {args[1] .. "vẹ́mo"}
	data.forms["2|p|pres"] = {args[1] .. "vẹ́ste"}
	data.forms["3|p|pres"] = {args[1] .. "véjo", args[1] .. "vedọ́"}
	
	data.forms["2|s|impr"] = {args[1] .. "vẹ́di"}
	data.forms["1|d|impr"] = {args[1] .. "vẹ́diva"}
	data.forms["2|d|impr"] = {args[1] .. "vẹ́dita"}
	data.forms["1|p|impr"] = {args[1] .. "vẹ́dimo"}
	data.forms["2|p|impr"] = {args[1] .. "vẹ́dite"}
	
	return make_table(data)
end

-- Helper functions
local function gcd(m, n)
    while n ~= 0 do
        local q = m
        m = n
        n = q % n
    end
    return m
end

local function lcm(m, n)
    return (m ~= 0 and n ~= 0) and m * n / gcd(m, n) or 0
end


-- Make the table
function make_table(data)
	local function repl(param)
		local accel = false  -- Temporary
		local no_store = false
		
		if param == "info" then
			return mw.getContentLanguage():ucfirst(data.info or "")
		elseif string.sub(param, 1, 1) == "!" then
			no_store = true
			param = string.sub(param, 2)
		elseif string.sub(param, 1, 1) == "#" then
			accel = false
			param = string.sub(param, 2)
		end
		
		local forms = data.forms[param]
		
		if not forms or not forms[1] then
			return "&mdash;"
		end
		
		local ret = {}
		
		for key, subform in ipairs(forms) do
			table.insert(ret, require("Module:links").full_link({lang = lang, term = subform, accel = accel and {form = param, no_store = no_store} or nil}))
		end
		
		return table.concat(ret, ", ")
	end
	
	local names = {
		["1|s"] = "1st&nbsp;singular",
		["2|s"] = "2nd&nbsp;singular",
		["3|s"] = "3rd&nbsp;singular",
		["1|d"] = "1st&nbsp;dual",
		["2|d"] = "2nd&nbsp;dual",
		["3|d"] = "3rd&nbsp;dual",
		["1|p"] = "1st&nbsp;plural",
		["2|p"] = "2nd&nbsp;plural",
		["3|p"] = "3rd&nbsp;plural",
	}
	
	local num_cols = 2 + (data.has_neg and 1 or 0) + (data.has_futr and 1 or 0)
	local total_cols = lcm(num_cols, 6)
	
	local wikicode = {}
	
	table.insert(wikicode, [=[
{| class="inflection-table vsSwitcher" data-toggle-category="inflection" style="background: #F9F9F9; border: 1px solid #aaaaaa;"
|- style="background: #d9ebff; text-align: left;"
! class="vsToggleElement" colspan="]=] .. (total_cols + 1) .. [=[" | {{{info}}}
|- class="vsShow"
! style="min-width: 11em; background: #eff7ff;" | infinitive
| style="min-width: 11em;" colspan="]=] .. total_cols .. [=[" | {{{!inf}}}
|- class="vsShow"
! style="background: #eff7ff;" | ]=] .. (data.impersonal and "3rd" or "1st") .. [=[&nbsp;singular
| colspan="]=] .. total_cols .. [=[" | {{{!]=] .. (data.impersonal and "3" or "1") .. [=[|s|pres}}}
|- class="vsHide"
! style="background: #eff7ff;" | infinitive
| colspan="]=] .. (total_cols / 2) .. [=[" | {{{inf}}}
| colspan="]=] .. (total_cols / 2) .. [=[" | {{{short|inf}}}
|- class="vsHide"
! style="background: #eff7ff;" | supine
| colspan="]=] .. total_cols .. [=[" | {{{supine}}}
|- class="vsHide"
! style="background: #eff7ff;" | verbal&nbsp;noun
| colspan="]=] .. total_cols .. [=[" | {{{#vnoun}}}
|- class="vsHide" style="background: #d9ebff;"
!
! colspan="]=] .. (total_cols / 2) .. [=[" | participle
! colspan="]=] .. (total_cols / 2) .. [=[" | converb
|- class="vsHide"
! style="background: #eff7ff;" | present
| colspan="]=] .. (total_cols / 2) .. [=[" | {{{pres|actv|ptcp}}}
| colspan="]=] .. (total_cols / 2) .. [=[" | {{{pres|actv|converb}}}
|- class="vsHide"
! style="background: #eff7ff;" | past
| colspan="]=] .. (total_cols / 2) .. [=[" | {{{past|pasv|ptcp}}}
| colspan="]=] .. (total_cols / 2) .. [=[" | {{{past|actv|converb}}}
|- class="vsHide" style="background: #d9ebff;"
! style="min-width: 11em;" | l-participle
! colspan="]=] .. (total_cols / 3) .. [=[" style="min-width: 11em;" | masculine
! colspan="]=] .. (total_cols / 3) .. [=[" style="min-width: 11em;" | feminine
! colspan="]=] .. (total_cols / 3) .. [=[" style="min-width: 11em;" | neuter
|- class="vsHide"
! style="background: #eff7ff;" | singular
| colspan="]=] .. (total_cols / 3) .. [=[" | {{{m|s|l-ptcp}}}
| colspan="]=] .. (total_cols / 3) .. [=[" | {{{f|s|l-ptcp}}}
| colspan="]=] .. (total_cols / 3) .. [=[" | {{{n|s|l-ptcp}}}
|- class="vsHide"
! style="background: #eff7ff;" | dual
| colspan="]=] .. (total_cols / 3) .. [=[" | {{{m|d|l-ptcp}}}
| colspan="]=] .. (total_cols / 3) .. [=[" | {{{f|d|l-ptcp}}}
| colspan="]=] .. (total_cols / 3) .. [=[" | {{{n|d|l-ptcp}}}
|- class="vsHide"
! style="background: #eff7ff;" | plural
| colspan="]=] .. (total_cols / 3) .. [=[" | {{{m|p|l-ptcp}}}
| colspan="]=] .. (total_cols / 3) .. [=[" | {{{f|p|l-ptcp}}}
| colspan="]=] .. (total_cols / 3) .. [=[" | {{{n|p|l-ptcp}}}
|- class="vsHide" style="background: #d9ebff;"
!]=])

	table.insert(wikicode, "\n! colspan=\"" .. (total_cols / num_cols) .. "\" style=\"min-width: 11em;\" | present")
	
	if data.has_neg then
		table.insert(wikicode, "\n! colspan=\"" .. (total_cols / num_cols) .. "\" style=\"min-width: 11em;\" | present<br/>negative")
	end
	
	if data.has_futr then
		table.insert(wikicode, "\n! colspan=\"" .. (total_cols / num_cols) .. "\" style=\"min-width: 11em;\" | future")
	end
	
	table.insert(wikicode, "\n! colspan=\"" .. (total_cols / num_cols) .. "\" style=\"min-width: 11em;\" | imperative")
	
	for _, pn in ipairs({"1|s", "2|s", "3|s", "1|d", "2|d", "3|d", "1|p", "2|p", "3|p"}) do
		table.insert(wikicode, "\n|- class=\"vsHide\"")
		table.insert(wikicode, "\n! style=\"background: #eff7ff;\" | ")
		table.insert(wikicode, names[pn])
		
		table.insert(wikicode, "\n| colspan=\"" .. (total_cols / num_cols) .. "\" | {{{")
		table.insert(wikicode, pn)
		table.insert(wikicode, "|pres}}}")
		
		if data.has_neg then
			table.insert(wikicode, "\n| colspan=\"" .. (total_cols / num_cols) .. "\" | {{{neg|")
			table.insert(wikicode, pn)
			table.insert(wikicode, "|pres}}}")
		end
		
		if data.has_futr then
			table.insert(wikicode, "\n| colspan=\"" .. (total_cols / num_cols) .. "\" | {{{")
			table.insert(wikicode, pn)
			table.insert(wikicode, "|futr}}}")
		end
		
		table.insert(wikicode, "\n| colspan=\"" .. (total_cols / num_cols) .. "\" | {{{")
		table.insert(wikicode, pn)
		table.insert(wikicode, "|impr}}}")
	end
	
	table.insert(wikicode, "\n|}")
	
	return mw.ustring.gsub(table.concat(wikicode), "{{{([^}]+)}}}", repl) .. require("Module:utilities").format_categories(data.categories, lang)
end

return export