Module:ine-verbs

From Wiktionary, the free dictionary
Jump to navigation Jump to search
This module needs documentation.
Please document this module by describing its purpose and usage on the documentation page.

local m_utilities = require("Module:utilities")
local m_links = require("Module:links")
local m_common = require("Module:ine-common")

local export = {}

local lang = require("Module:languages").getByCode("ine-pro")

local endings = {
	["actv_pri"] = {
		["1sg"] = {athem = {"mi"}, them = {"h₂"}},
		["2sg"] = {"si"},
		["3sg"] = {"ti"},
		["1du"] = {"wós"},
		["2du"] = {"tés"},
		["3du"] = {"tés"},
		["1pl"] = {"mós"},
		["2pl"] = {"té"},
		["3pl"] = {{stressed = "énti", unstressed = "n̥ti"}},
		},
	
	["actv_sec"] = {
		["1sg"] = {"m̥"},
		["2sg"] = {"s"},
		["3sg"] = {"t"},
		["1du"] = {"wé"},
		["2du"] = {"tóm"},
		["3du"] = {"tā́m"},
		["1pl"] = {"mé"},
		["2pl"] = {"té"},
		["3pl"] = {{stressed = "ént", unstressed = "n̥t"}},
		},
	
	["actv_impr"] = {
		["2sg"] = {athem = {"", "dʰí"}, them = {""}},
		["3sg"] = {"tu"},
		["2du"] = {"tóm"},
		["3du"] = {"tā́m"},
		["2pl"] = {"té"},
		["3pl"] = {{stressed = "éntu", unstressed = "n̥tu"}},
		},
	
	["midl_pri"] = {
		["1sg"] = {"h₂ér"},
		["2sg"] = {"th₂ér"},
		["3sg"] = {athem = {"tór", "ór"}, them = {"tór"}},
		["1du"] = {"wósdʰh₂"},
		["2du"] = "?",
		["3du"] = "?",
		["1pl"] = {"mósdʰh₂"},
		["2pl"] = {"dʰh₂wé"},
		["3pl"] = {"rór", "n̥tór"},
		},
	
	["midl_sec"] = {
		["1sg"] = {"h₂é"},
		["2sg"] = {"th₂é"},
		["3sg"] = {athem = {"tó", "ó"}, them = {"tó"}},
		["1du"] = {"wédʰh₂"},
		["2du"] = "?",
		["3du"] = "?",
		["1pl"] = {"médʰh₂"},
		["2pl"] = {"dʰh₂wé"},
		["3pl"] = {"ró", "n̥tó"},
		},
	
	["midl_impr"] = {
		["2sg"] = {"só"},
		["3sg"] = "?",
		["2du"] = "?",
		["3du"] = "?",
		["2pl"] = {"dʰh₂wé"},
		["3pl"] = "?",
		},
	
	["stative"] = {
		["1sg"] = {"h₂e"},
		["2sg"] = {"th₂e"},
		["3sg"] = {"e"},
		["1du"] = {"wé"},
		["2du"] = "?",
		["3du"] = "?",
		["1pl"] = {"mé"},
		["2pl"] = {"é"},
		["3pl"] = {"ḗr"},
		},
}

local them_vowel = {
	["1sg"] = "ó",
	["2sg"] = "é",
	["3sg"] = "é",
	["1du"] = "ó",
	["2du"] = "é",
	["3du"] = "é",
	["1pl"] = "ó",
	["2pl"] = "é",
	["3pl"] = "ó",
}


local function inflect(data, prefix, endings, stem1, stem2)
	stem2 = stem2 or stem1
	
	-- Is the stem thematic?
	local them = mw.clone(them_vowel)
	
	if mw.ustring.find(stem1, "[eoēōéóḗṓ]$") then
		if mw.ustring.find(stem1, "[ēōḗṓ]$") then
			for key, val in pairs(them) do
				them[key] = m_common.lengthen(val)
			end
		end
		
		if mw.ustring.find(stem1, "[eoēō]$") then
			for key, val in pairs(them) do
				them[key] = m_common.destress(val)
			end
		end
		
		stem1 = mw.ustring.gsub(stem1, "[eoēōéóḗṓ]$", "")
		stem2 = stem1
	else
		for key, val in pairs(them) do
			them[key] = ""
		end
	end
	
	-- Go over each person-number combination
	for p, pendings in pairs(endings) do
		if pendings == "?" then
			data.forms[prefix .. "_" .. p] = {"?"}
		elseif pendings then
			data.forms[prefix .. "_" .. p] = {}
			
			if pendings.athem then
				if them[p] == "" then
					pendings = pendings.athem
				else
					pendings = pendings.them
				end
			end
			
			for _, pending in ipairs(pendings) do
				local stem = stem1
				
				-- Use stem2 if the ending can be stressed, stem1 otherwise
				if pending.stressed or mw.ustring.find(pending, "[áéíĺḿńóŕúḗṓ́]") then
					stem = stem2
				end
				
				local ending
				local ending_unstr
				
				-- Thematic endings are never stressed
				if them[p] ~= "" then
					ending = pending.unstressed or m_common.destress(pending.stressed or pending)
				else
					ending = pending.stressed or pending
					ending_unstr = pending.unstressed
				end
				
				table.insert(data.forms[prefix .. "_" .. p], m_common.add_ending(stem .. them[p], ending, ending_unstr))
			end
		end
	end
end

function export.eventive(frame)
	local params = {
		[1] = {required = true},
		[2] = {},
		["v"] = {},
		}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)
	
	if mw.title.getCurrentTitle().nsText == "Template" then
		args[1] = args[1] or (frame.args[1] == "impf" and "linékʷ" or "léykʷ")
		args[2] = args[2] or (frame.args[2] == "impf" and "linkʷ" or "likʷ")
	end
	
	args[2] = args[2] or args[1]
	
	local data = {forms = {}, title = nil, categories = {}}
	data.info = (frame.args[1] == "impf" and "Imperfective" or "Perfective")
	
	if mw.ustring.find(args[1], "[eoéó]$") then
		data.info = data.info .. ", thematic"
	else
		data.info = data.info .. ", athematic"
	end
	
	data.v = args["v"]
	
	if data.v == "actv" then
		data.info = data.info .. ", active only"
	elseif data.v == "midl" then
		data.info = data.info .. ", middle only"
	end
	
	local subj_stem, opta_stem1, opta_stem2
	
	-- Is the stem thematic?
	if mw.ustring.find(args[1], "[eoéó]$") then
		subj_stem = mw.ustring.gsub(args[1], "([eoéó])$", {["e"] = "ē", ["o"] = "ō", ["é"] = "ḗ", ["o"] = "ṓ"})
		opta_stem1 = mw.ustring.gsub(args[1], "([eoéó])$", {["e"] = "oyh₁", ["o"] = "oyh₁", ["é"] = "óyh₁", ["o"] = "óyh₁"})
		opta_stem2 = opta_stem1
	else
		subj_stem = args[1] .. "e"
		opta_stem1 = m_common.add_ending(args[2], "yéh₁")
		opta_stem2 = m_common.add_ending(args[2], "ih₁")
	end
	
	-- Create the forms
	if frame.args[1] == "impf" then
		data.tenses = true
		
		inflect(data, "pres_indc_actv", endings["actv_pri"], args[1], args[2])
		inflect(data, "past_indc_actv", endings["actv_sec"], args[1], args[2])
		
		inflect(data, "pres_indc_midl", endings["midl_pri"], args[2], args[2])
		inflect(data, "past_indc_midl", endings["midl_sec"], args[2], args[2])
		
		local suffix_type
		
		if mw.ustring.find(args[1], "[eoéó]$") then
			if mw.ustring.find(mw.ustring.sub(args[1], 1, -2), "[eoéó]") then
				if mw.ustring.find(args[1], "o.+éye$") then
					--Removed, redundant to [[:Category:Proto-Indo-European words suffixed with *-éyeti]]
					--suffix_type = " eye-causative/iterative"
				elseif mw.ustring.find(args[1], "é.+ye$") then
					suffix_type = " ye-present"
				elseif mw.ustring.find(args[1], "[eo].+yé$") then
					suffix_type = " ye-denominative"
				elseif mw.ustring.find(args[1], "é.+dʰh₁e$") then
					suffix_type = " dʰh₁e-present"
				else
					suffix_type = " root thematic"
				end
			else
				if mw.ustring.find(args[1], "sḱé$") then
					suffix_type = " sḱe-present"
				elseif mw.ustring.find(args[1], "syé$") then
					suffix_type = " sye-desiderative"
				elseif mw.ustring.find(args[1], "yé$") then
					suffix_type = " zero-grade ye-present"
				elseif mw.ustring.find(args[1], "í.+e$") then
					suffix_type = " i-reduplicated root thematic"
				else
					suffix_type = " zero-grade root thematic"
				end
			end
		else
			if mw.ustring.find(args[1], "éh₁$") then
				suffix_type = " eh₁-stative"
			elseif mw.ustring.find(args[1], "néw$") then
				suffix_type = " nu-present"
			elseif mw.ustring.find(args[1], "né") and not mw.ustring.find(args[2], "né") then
				suffix_type = " nasal-infixed present"
			elseif mw.ustring.find(args[1], "í.+e.+") and not mw.ustring.find(args[2], "í.+e.+") then
				suffix_type = " i-reduplicated root athematic"
			elseif mw.ustring.find(args[1], "é.+e.+") and not mw.ustring.find(args[2], "é.+e.+") then
				suffix_type = " reduplicated root athematic"
			elseif mw.ustring.find(args[1], "ḗ") then
				suffix_type = " lengthened-grade root athematic"
			else
				suffix_type = " root athematic"
			end
		end
		
		if suffix_type then
			table.insert(data.categories, lang:getCanonicalName() .. suffix_type .. " verbs")
		end
	else
		inflect(data, "indc_actv", endings["actv_sec"], args[1], args[2])
		
		inflect(data, "indc_midl", endings["midl_sec"], args[2], args[2])
		
		local suffix_type = {}

		if mw.ustring.find(args[1], "[eoéó]$") then
			if not mw.ustring.find(mw.ustring.sub(args[1], 1, -2), "[eoéó]") then
				suffix_type = " zero-grade root thematic aorist"
			elseif mw.ustring.find(args[1], "é.+e$") and mw.ustring.find(args[2], "é.+e$") then
				suffix_type = " reduplicated root thematic aorist"
			else			
				suffix_type = " root thematic aorist"
			end
		else
			if mw.ustring.find(args[1], "ḗ.+s$") then
				suffix_type = " s-aorist"
			elseif not mw.ustring.find(args[1], "[eoéó]") then
				suffix_type = " zero-grade root athematic aorist"
			elseif mw.ustring.find(args[1], "é.+") and mw.ustring.find(args[2], "é.+") then
				suffix_type = " reduplicated root athematic aorist"
			else
				suffix_type = " root athematic aorist"
			end
		end
		
		table.insert(data.categories, lang:getCanonicalName() .. suffix_type .. " verbs")
	
	end
	
	inflect(data, "impr_actv", endings["actv_impr"], args[1], args[2])
	inflect(data, "subj_actv", endings["actv_pri"], subj_stem)
	inflect(data, "opta_actv", endings["actv_sec"], opta_stem1, opta_stem2)
	
	inflect(data, "impr_midl", endings["midl_impr"], args[2], args[2])
	inflect(data, "subj_midl", endings["midl_pri"], subj_stem)
	inflect(data, "opta_midl", endings["midl_sec"], opta_stem2, opta_stem2)
	
	local o_grade = mw.ustring.gsub(args[2], "[eé]$", {["e"] = "o", ["é"] = "ó"})
	data.forms["actv_ptcp"] = {m_common.add_ending(o_grade, "ónts", "n̥ts")}
	data.forms["midl_ptcp"] = {m_common.add_ending(o_grade, "m̥h₁nós")}

	return make_table(data)
end

function export.stative(frame)
	local params = {
		[1] = {required = true},
		[2] = {},
		}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)
	
	if mw.title.getCurrentTitle().nsText == "Template" then
		args[1] = args[1] or "lelóykʷ"
		args[2] = args[2] or "lelikʷ"
	end
	
	args[2] = args[2] or args[1]
	
	local data = {forms = {}, title = nil, categories = {}}
	data.info = "Stative"
	data.v = "actv"
	
	local subj_stem, opta_stem1, opta_stem2
	
	-- Is the stem thematic?
	if mw.ustring.find(args[1], "[eoéó]$") then
		error("Stative verbs must be athematic.")
	else
		subj_stem = mw.ustring.gsub(args[1], "ó", "é") .. "e"
		opta_stem1 = m_common.add_ending(args[2], "yéh₁")
		opta_stem2 = m_common.add_ending(args[2], "ih₁")
	end
	
	-- Create the forms
	inflect(data, "indc_actv", endings["stative"], args[1], args[2])
	inflect(data, "impr_actv", endings["actv_impr"], args[1], args[2])
	inflect(data, "subj_actv", endings["actv_pri"], subj_stem)
	inflect(data, "opta_actv", endings["actv_sec"], opta_stem1, opta_stem2)
	
	data.forms["actv_ptcp"] = {m_common.add_ending(args[2], "wṓs")}
	
	local suffix_type = {}

	if mw.ustring.find(args[1], "e.+ó.+") and not mw.ustring.find(args[2], "e.+ó.+") then
		suffix_type = " reduplicated root perfect"
	else
		suffix_type = " root perfect"
	end
	
	table.insert(data.categories, lang:getCanonicalName() .. suffix_type .. " verbs")

	return make_table(data)
end

local names = {
	["actv"] = "Active voice",
	["midl"] = "Middle voice",
	
	["indc"] = "Indicative",
	["pres_indc"] = "Present indicative",
	["past_indc"] = "Past indicative",
	["impr"] = "Imperative",
	["subj"] = "Subjunctive",
	["opta"] = "Optative",
	
	["1sg"] = "1st singular",
	["2sg"] = "2nd singular",
	["3sg"] = "3rd singular",
	["1du"] = "1st dual",
	["2du"] = "2nd dual",
	["3du"] = "3rd dual",
	["1pl"] = "1st plural",
	["2pl"] = "2nd plural",
	["3pl"] = "3rd plural",
}

-- Make the table
function make_table(data)
	local function show_form(form)
		if not form then
			return "—"
		end
		
		if type(form) ~= "table" then
			error("a non-table value was given in the list of inflected forms.")
		end
		
		local ret = {}
		
		for key, subform in ipairs(form) do
			table.insert(ret, m_links.full_link({lang = lang, alt = "*" .. subform}))
		end
		
		return table.concat(ret, ", ")
	end
	
	local function repl(param)
		if param == "lemma" then
			return m_links.full_link({lang = lang, alt = mw.title.getCurrentTitle().text}, "term")
		elseif param == "info" then
			return data.info or ""
		else
			return show_form(data.forms[param])
		end
	end
	
	local voices = data.v and {data.v} or {"actv", "midl"}
	local moods = data.tenses and {"pres_indc", "past_indc", "impr", "subj", "opta"} or {"indc", "impr", "subj", "opta"}
	
	local wikicode = {}
	
	table.insert(wikicode, "{| class=\"inflection-table vsSwitcher\" data-toggle-category=\"inflection\" style=\"background: #FAFAFA; border: 1px solid #d0d0d0; text-align: left;\" cellspacing=\"1\" cellpadding=\"2\"")
	table.insert(wikicode, "|- style=\"background: #CCCCFF;\"\n! class=\"vsToggleElement\" colspan=\"" .. (#moods + 1) .. "\" | {{{info}}}")
	table.insert(wikicode, "|- class=\"vsShow\" style=\"background: #F2F2FF;\"")
	table.insert(wikicode, "! style=\"min-width: 8em; background: #E6E6FF;\" | " .. names["3sg"] .. "\n| style=\"min-width: 11em;\" | {{{" .. (data.tenses and "pres_indc" or "indc") .. "_" .. (data.v or "actv") .. "_3sg}}}")
	table.insert(wikicode, "|- class=\"vsShow\" style=\"background: #F2F2FF;\"")
	table.insert(wikicode, "! style=\"min-width: 8em; background: #E6E6FF;\" | " .. names["3pl"] .. "\n| style=\"min-width: 11em;\" | {{{" .. (data.tenses and "pres_indc" or "indc") .. "_" .. (data.v or "actv") .. "_3pl}}}")
	
	for _, voice in ipairs(voices) do
		table.insert(wikicode, "|- class=\"vsHide\" style=\"background: #CCCCFF;\"\n! " .. names[voice])
		
		for _, mood in ipairs(moods) do
			table.insert(wikicode, "! style=\"min-width: 11em; background: #CCCCFF;\" | " .. names[mood])
		end
		
		for _, pn in ipairs({"1sg", "2sg", "3sg", "1du", "2du", "3du", "1pl", "2pl", "3pl"}) do
			table.insert(wikicode, "|- class=\"vsHide\" style=\"background-color: #F2F2FF;\"\n! style=\"min-width: 8em; background-color: #E6E6FF;\" | " .. names[pn])
			
			for _, mood in ipairs(moods) do
				table.insert(wikicode, "| {{{" .. mood .. "_" .. voice .. "_" .. pn .. "}}}")
			end
		end
		
		table.insert(wikicode, "|- class=\"vsHide\" style=\"background-color: #CCCCFF;\"\n| colspan=\"" .. (#moods + 1) .. "\" |")
		table.insert(wikicode, "|- class=\"vsHide\" style=\"background-color: #F2F2FF;\"\n! style=\"background-color: #E6E6FF;\" | Participle")
		table.insert(wikicode, "| {{{" .. voice .. "_ptcp}}}")
		table.insert(wikicode, "| style=\"background-color: #CCCCFF;\" colspan=\"" .. (#moods - 1) .. "\" |")
	end
	
	table.insert(wikicode, [=[|}]=])
	
	wikicode = table.concat(wikicode, "\n")
	
	return (mw.ustring.gsub(wikicode, "{{{([a-z0-9_]+)}}}", repl)) .. m_utilities.format_categories(data.categories, lang)
end

return export