Module:la-headword

Hello, you have come here looking for the meaning of the word Module:la-headword. In DICTIOUS you will not only get to know all the dictionary meanings for the word Module:la-headword, but we will also tell you about its etymology, its characteristics and you will know how to say Module:la-headword in singular and plural. Everything you need to know about the word Module:la-headword you have here. The definition of the word Module:la-headword will help you to be more precise and correct when speaking or writing your texts. Knowing the definition ofModule:la-headword, as well as those of other words, enriches your vocabulary and provides you with more and better linguistic resources.

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

-- TODO: handle "-old" subtypes generally, appending "in Old Latin", where terms have additional OL inflections.

local export = {}
local pos_functions = {}

local string_utilities = "Module:string utilities"
local table_module = "Module:table"
local utilities_module = "Module:utilities"

local concat = table.concat
local form_is_empty = require("Module:la-utilities").form_is_empty
local insert = table.insert
local remove = table.remove
local umatch = mw.ustring.match

local lang = require("Module:languages").getByCode("la")
local NAMESPACE = mw.title.getCurrentTitle().namespace
local PAGENAME = mw.loadData("Module:headword/data").pagename

local legal_gender = {
	 = true,
	 = true,
	 = true,
	 = true,
	 = true,
}

local declension_to_english = {
	 = "first",
	 = "second",
	 = "third",
	 = "fourth",
	 = "fifth",
}

local gender_names = {
	 = "masculine",
	 = "feminine",
	 = "neuter",
	 = "unknown gender",
	 = "unattested gender",
}

local function deep_equals(...)
	deep_equals = require(table_module).deepEquals
	return deep_equals(...)
end

local function get_plaintext(...)
	get_plaintext = require(utilities_module).get_plaintext
	return get_plaintext(...)
end

local function insert_if_not(...)
	insert_if_not = require(table_module).insertIfNot
	return insert_if_not(...)
end

local function invert(...)
	invert = require(table_module).invert
	return invert(...)
end

local function keys_to_list(...)
	keys_to_list = require(table_module).keysToList
	return keys_to_list(...)
end

local function pattern_escape(...)
	pattern_escape = require(string_utilities).pattern_escape
	return pattern_escape(...)
end

local function serial_comma_join(...)
	serial_comma_join = require(table_module).serialCommaJoin
	return serial_comma_join(...)
end

local function split(...)
	split = require(string_utilities).split
	return split(...)
end

local function ulower(...)
	ulower = require(string_utilities).lower
	return ulower(...)
end

local function format(array, concatenater)
	if #array == 0 then
		return ""
	end
	local concatenated = concat(array, concatenater)
	if concatenated == "" then
		return ""
	elseif concatenated:sub(-1) == "'" then
		concatenated = concatenated .. " "
	end
	return "; ''" .. concatenated .. "''"
end

local function glossary_link(anchor, text)
	text = text or anchor
	return "]"
end

local function make_link(page, display, face, accel)
	return require("Module:links").full_link({term = page, alt = display, lang = lang, accel = accel}, face)
end

-- The main entry point.
-- This is the only function that can be invoked from a template.
function export.show(frame)
	local iargs = require("Module:parameters").process(frame.args, {
		 = {required = true},
		 = true,
		 = true,
	})
	local args = frame:getParent().args
	local poscat = iargs
	local def = iargs.def
	local suff_type = iargs.suff_type
	local postype = nil
	if suff_type then
		postype = poscat .. '-' .. suff_type
	else
		postype = poscat
	end

	local data = {lang = lang, categories = {}, heads = {}, genders = {}, inflections = {}}
	local infl_classes = {}
	local title = {}
	local postscript = {}

	if poscat == "suffixes" then
		insert_if_not(data.categories, "Latin " .. suff_type .. "-forming suffixes")
	end

	if pos_functions then
		local new_poscat = pos_functions(def, args, data, infl_classes, title, postscript)
		if new_poscat then
			poscat = new_poscat
		end
	end

	if NAMESPACE == 118 then -- Reconstruction:
		data.pos_category = "reconstructed " .. poscat
		data.nolink = true
	else
		data.pos_category = poscat
	end

	postscript = concat(postscript, ", ")

	return
		require("Module:headword").full_headword(data)
		.. format(infl_classes, "/")
		.. format(title, ", ")
		.. (postscript ~= "" and " (" .. postscript .. ")" or "")
end

local function process_num_type(numtype, categories)
	if numtype == "card" then
		insert_if_not(categories, "Latin cardinal numbers")
	elseif numtype == "ord" then
		insert_if_not(categories, "Latin ordinal numbers")
	elseif numtype == "frac" then
		insert_if_not(categories, "Latin fractional numbers")
	elseif numtype == "dist" then
		insert_if_not(categories, "Latin distributive numbers")
	elseif numtype == "mul" then
		insert_if_not(categories, "Latin multiplicative numbers")
	elseif numtype == "coll" then
		insert_if_not(categories, "Latin collective numbers")
	elseif numtype then
		error("Unrecognized numeral type '" .. numtype .. "'")
	end
end

local function normalize_derivation(deriv, deriv_label)
	if not deriv then
		return nil
	end
	local deriv1 = deriv
	if not deriv1 or deriv1 == "-" then
		return deriv1
	end
	deriv.label = glossary_link(deriv_label)
	return deriv
end

local function nouns(pos, def, args, data, infl_classes, title)
	local is_num = pos == "numerals"
	local is_pn = false
	if pos == "proper nouns" then
		is_pn = true
		pos = "nouns"
	end
	local decldata = require("Module:la-nominal").do_generate_noun_forms(args, pos, "headword", def, is_num)
	local lemma = decldata.overriding_lemma
	-- TODO: modify the headword line if the slot isn't the expected one.
	if #lemma == 0 then
		for slot in require("Module:la-nominal").iter_potential_noun_lemma_slots() do
			local potential_lemma = decldata.forms
			if not form_is_empty(potential_lemma) then
				if decldata.unattested then
					potential_lemma = "*" .. potential_lemma
				end
				lemma = potential_lemma
				break
			end
		end
	end

	data.heads = lemma
	-- Since we always set data.heads to the lemma and specification of the lemma is mandatory in {{la-noun}}, there aren't
	-- really any redundant heads.
	data.no_redundant_head_cat = true
	data.id = decldata.id
	
	local genders = decldata.overriding_genders
	if #genders == 0 then
		if decldata.gender then
			genders = {ulower(decldata.gender)}
		elseif not is_num then
			error("No gender explicitly specified in headword template using g=, and can't infer gender from lemma spec")
		end
	end

	local categories = data.categories
	if is_num then
		process_num_type(decldata.num_type, categories)
	end

	if decldata.indecl then
		insert(data.inflections, {label = glossary_link("indeclinable")})
		insert_if_not(categories, "Latin indeclinable " .. decldata.pos)

		for _, g in ipairs(genders) do
			local gender = g:match("^(.*)%-$")
			if not gender then
				gender = g
			end
			if not legal_gender then
				error("Gender “" .. gender .. "” is not a valid Latin gender.")
			end
			insert(data.genders, g)
			insert_if_not(categories, "Latin " .. gender_names .. " indeclinable " .. decldata.pos)
		end
	else
		local is_irreg = false
		local is_indecl = false
		local is_decl = false
		local has_multiple_decls = false
		local has_multiple_variants = false
		-- flatten declension specs
		local decls = {}

		for _, g in ipairs(genders) do
			if not legal_gender then
				error("Gender “" .. g .. "” is not a valid Latin gender.")
			elseif decldata.num == "pl" then
				g = g .. "-p"
			elseif decldata.num == "sg" then
				g = g .. "-s"
			end
			insert(data.genders, g)
		end

		local function process_decl(decl_list, props)
			local headword_decl = props.headword_decl
			-- skip adjectival declensions
			if headword_decl:match("+$") then
				return
			elseif props.decl == "irreg" then
				is_irreg = true
				headword_decl = headword_decl:match("^irreg/(.*)$") or headword_decl
				local irreg_decls = split(headword_decl, ",")
				if #irreg_decls > 1 then
					has_multiple_decls = true
				end
				for _, d in ipairs(irreg_decls) do
					if d == "indecl" or d == "0" then
						is_indecl = true
					else
						is_decl = true
					end
					insert_if_not(decl_list, d)
				end
			else
				if headword_decl == "indecl" or headword_decl == "0" then
					is_indecl = true
				else
					is_decl = true
				end
				insert_if_not(decl_list, headword_decl)
			end
		end

		for _, props in ipairs(decldata.propses) do
			if props.headword_decl then
				process_decl(decls, props)
			else
				local alternant_decls = {}
				for _, alternant in ipairs(props) do
					for _, single_props in ipairs(alternant) do
						process_decl(alternant_decls, single_props)
					end
				end
				if #alternant_decls > 1 then
					has_multiple_decls = true
				elseif #decls > 1 then
					has_multiple_variants = true
				end
				for _, d in ipairs(alternant_decls) do
					insert_if_not(decls, d)
				end
			end
		end

		if is_indecl and is_decl then
			has_multiple_decls = true
		end
		if has_multiple_decls then
			insert_if_not(categories, "Latin " .. decldata.pos .. " with multiple declensions")
		end
		if has_multiple_variants then
			insert_if_not(categories, "Latin " .. decldata.pos .. " with multiple variants of a single declension")
		end
		if is_irreg then
			insert(title, glossary_link("irregular"))
			insert_if_not(categories, "Latin irregular " .. decldata.pos)
			for _, g in ipairs(genders) do
				insert_if_not(categories, "Latin " .. gender_names .. " irregular " .. decldata.pos)
			end
		end

		if is_indecl then
			if is_decl then
				insert(title, glossary_link("indeclinable"))
			else
				insert(data.inflections, {label = glossary_link("indeclinable")})
			end
			insert_if_not(categories, "Latin indeclinable " .. decldata.pos)
			for _, g in ipairs(genders) do
				insert_if_not(categories, "Latin " .. gender_names .. " indeclinable " .. decldata.pos)
			end
		end

		if #decls > 1 then
			insert(title, "variously declined")
		end

		for _, decl in ipairs(decls) do
			if not (decl == "0" or decl == "indecl" or decl == "sgpl" or decl == "irreg") then
				local decl_class = declension_to_english
				if not decl_class then
					error("Internal error: declension '" .. decl .. "' not recognized")
				end
				insert(title, "]")
				insert_if_not(categories, "Latin " .. decl_class .. " declension " .. decldata.pos)
				for _, g in ipairs(genders) do
					insert_if_not(categories, "Latin " .. gender_names .. " " .. decldata.pos .. " in the " .. decl_class .. " declension")
				end
			end
		end

		local lemma_num = decldata.num == "pl" and "pl" or "sg"
		if NAMESPACE == 118 then -- Reconstruction:
			-- For reconstructed nouns:
			if data.genders == 'n' and lemma_num == 'sg' then
				-- singular neuter nouns give a plural
				local pl = decldata.forms
				if pl and pl ~= "" and #pl > 0 then
					pl.label = "plural"
					insert(data.inflections, pl)
				end
			else
				-- all others give an oblique
				local obl = decldata.forms
				if obl and obl ~= "" and #obl > 0 then
					obl.label = "oblique"
					insert(data.inflections, obl)
				end
			end
		else
			local gen = decldata.forms
			if (decldata.unattested) then
				gen = '*' .. gen
				data.nolink = true
			end
			if gen and gen ~= "" and gen ~= "—" and #gen > 0 then
				if is_decl then
					-- Skip displaying the genitive for nouns that are only
					-- indeclinable. But we do display it for nouns like Abrahām
					-- and Ādām that can be either indeclinable or declined.
					gen.label = "genitive"
					insert(data.inflections, gen)
				end
			else
				insert(data.inflections, {label = "no genitive"})
				insert_if_not(categories, "Latin " .. decldata.pos .. " with no genitive singular")
			end
		end
	end

	local m = normalize_derivation(decldata.m, "masculine")
	if m and m ~= "-" then
		insert(data.inflections, m)
	end

	local f = normalize_derivation(decldata.f, "feminine")
	if f and f ~= "-" then
		insert(data.inflections, f)
	end

	for _, cat in ipairs(decldata.categories) do
		insert_if_not(categories, cat)
	end

	for _, cat in ipairs(decldata.cat) do
		insert_if_not(categories, "Latin " .. cat)
	end
	
	return is_pn and decldata.pos == "nouns" and "proper nouns" or decldata.pos
end

pos_functions = function(def, args, data, infl_classes, title)
	return nouns("nouns", def, args, data, infl_classes, title)
end

pos_functions = function(def, args, data, infl_classes, title)
	return nouns("proper nouns", def, args, data, infl_classes, title)
end

pos_functions = function(def, args, data, infl_classes, title)
	return nouns("suffixes", def, args, data, infl_classes, title)
end

pos_functions = function(def, args, data, infl_classes, title)
	return nouns("numerals", def, args, data, infl_classes, title)
end

function export.verb_title(title, typeinfo, lemma_forms)
	local conj = typeinfo.conj
	local irreg_processing = typeinfo.irreg
	local subtypes = typeinfo.subtypes

	local first_lemma = ""
	if #lemma_forms > 0 then
		first_lemma = require("Module:links").remove_links(lemma_forms)
	end

	if conj == "1st" then
		insert(title, "]")
	elseif conj == "2nd" then
		insert(title, "]")
	elseif conj == "3rd" then
		insert(title, "]")
	elseif conj == "3rd-io" then
		insert(title, ("] %s-variant"):format(make_link(nil, "iō", "term")))
	elseif conj == "4th" then
		insert(title, "]")
	elseif conj == "irreg" then -- sum
		insert(title, "]")
	end
	if subtypes.highlydef then -- āiō, inquam
		insert(title, "highly ]")
	end
	if subtypes.suppl then -- sum, volō
		insert(title, "]")
	end
	if subtypes then -- decet
		insert(title, "]-only")
	elseif subtypes.impers then -- decet, advesperāscit (also nopass)
		insert(title, "]")
	end
	if subtypes.depon then -- dēmōlior, calvor (also noperf)
		insert(title, "]")
	end
	if subtypes.perfaspres then -- meminī, ōdī
		insert(title, "no ] stem")
		-- If semidepon is set, only the active forms are affected.
		local voice = subtypes.semidepon and "] " or ""
		insert(title, ("] %sforms have ] %smeaning"):format(voice, voice))
		-- Clarify that deponency can only apply to the perfect.
		if subtypes.semidepon then -- ōdī
			insert(title, "] in the ]")
		end
		if subtypes.optsemidepon then
			insert(title, "optionally ] in the ]")
		end
	else
		if subtypes.semidepon then -- fīdō, gaudeō
			insert(title, "]")
		end
		if subtypes.optsemidepon then -- audeō, placeō, soleō, pudeō
			insert(title, "optionally ]")
		end
	end
	if subtypes.imponly then -- cedo, apage
		insert(title, "]-only")
	end
	if subtypes.nopass then -- coacēscō
		insert(title, "no ]")
	end
	
	local stems = {}
	if subtypes.nopres then -- coepī; perfaspres already handles this above
		insert(stems, "]")
	end
	if subtypes.noperf then
		insert(stems, "]")
	end
	if subtypes.nosup or subtypes.supfutractvonly then
		insert(stems, "]")
	end
	if #stems > 0 then
		local extra = subtypes.supfutractvonly and " except in the ] ] ]"
		insert(title, ("no %s stem%s%s"):format(serial_comma_join(stems, {conj = "or"}), #stems > 1 and "s" or "", extra or ""))
	end
	if subtypes.nofut then -- soleō
		insert(title, "no ]")
	end
	if subtypes.pass3only then -- praefundō
		insert(title, "]-only in the ]")
	elseif subtypes.passimpers then -- abambulō
		local msg = "] in the ]"
		if subtypes.passimpersold then -- possum
			msg = msg .. " in ]"
		end
		insert(title, msg)
	end
	if subtypes.noimp then -- volō
		insert(title, "no ]")
	end
	if irreg_processing and umatch(first_lemma, "dcō$") then -- dīcō
		insert(title, "] short ]")
	end
	if subtypes.nofutractvptc and not subtypes.nosup then -- fīō
		insert(title, "no ] ] ]")
	end
	if not (subtypes.nopres or subtypes.perfaspres or subtypes.imponly) then
		if subtypes.noinf then -- inquam
			insert(title, "no ]")
		end
		if subtypes.noger then -- libet
			insert(title, "no ]")
		end
	end
	if subtypes.shorta then -- dō
		insert(title, ("] short %s in most forms"):format(make_link(nil, "ă", "term")))
	end
	if irreg_processing then
		if first_lemma:match("edō$") then -- edō
			insert(title, "] alternative forms")
		elseif first_lemma:match("fīō$") then -- fīō
			insert(title, "] long " .. make_link(nil, "ī", "term"))
		end
	end
end

pos_functions = function(def, args, data, infl_classes, title)
	local m_la_verb = require("Module:la-verb")
	local def1, def2
	if def then
		def1, def2 = def:match("^(.-):(.*)$")
	end
	local conjdata, typeinfo = m_la_verb.make_data(args, true, def1, def2)
	local lemma_forms = conjdata.overriding_lemma
	if not lemma_forms or #lemma_forms == 0 then
		lemma_forms = m_la_verb.get_lemma_forms(conjdata, true)
	end
	data.heads = lemma_forms
	-- Since we always set data.heads to the lemma and specification of the lemma is mandatory in {{la-verb}}, there aren't
	-- really any redundant heads.
	data.no_redundant_head_cat = true
	data.id = conjdata.id
	
	local perf_only = false

	local function insert_inflection(infl, label)
		infl.label = label
		insert(data.inflections, infl)
	end

	local inf = m_la_verb.get_valid_forms(conjdata.forms)
	if #inf > 0 then
		insert_inflection(inf, "present infinitive")
	else
		inf = m_la_verb.get_valid_forms(conjdata.forms)
		if #inf > 0 then
			perf_only = true
			insert_inflection(inf, "perfect infinitive")
		end
	end

	if not perf_only then
		local perf = m_la_verb.get_valid_forms(conjdata.forms)
		if #perf == 0 then
			perf = m_la_verb.get_valid_forms(conjdata.forms)
		end
		if #perf > 0 then
			insert_inflection(perf, "perfect active")
		end
	end

	local subtypes = typeinfo.subtypes
	if not (subtypes.depon or subtypes.semidepon) then
		local sup = m_la_verb.get_valid_forms(conjdata.forms)
		if #sup > 0 then
			insert_inflection(sup, "supine")
		else
			local fap = m_la_verb.get_valid_forms(conjdata.forms)
			if #fap > 0 then
				insert_inflection(fap, "future active participle")
			end
		end
	end

	export.verb_title(title, typeinfo, lemma_forms)
end

pos_functions = pos_functions

local function attested_form(decldata, index)
	local form
	if (decldata.unattested) then
		form = { { term = '*' .. decldata.forms, nolink = true } }
	else
		form = decldata.forms
	end
	return form
end

local function degree_derivations(comp, sup, data)
	local inflections = data.inflections
	if not (comp or sup) then
		return
	elseif (not comp or comp == "-") and (not sup or sup == "-") then
		insert(inflections, {label = "not ]"})
		insert_if_not(data.categories, "Latin uncomparable adverbs")
		return
	elseif comp == "-" then
		insert(inflections, {label = "no ]"})
	elseif comp then
		insert(inflections, comp)
	end
	if sup == "-" then
		insert(inflections, {label = "no ]"})
	elseif sup then
		insert(inflections, sup)
	end
end

local function adjectives(pos, def, args, data, infl_classes)
	local is_num = pos == "numerals"
	local decldata = require("Module:la-nominal").do_generate_adj_forms(args, pos, "headword", nil, def)
	local lemma = decldata.overriding_lemma
	-- TODO: modify the headword line if the slot isn't the expected one.
	if #lemma == 0 then
		for slot in require("Module:la-nominal").iter_potential_adj_lemma_slots() do
			local potential_lemma = decldata.forms
			if not form_is_empty(potential_lemma) then
				if decldata.unattested then
					potential_lemma = "*" .. potential_lemma
				end
				lemma = potential_lemma
				break
			end
		end
	end

	data.heads = lemma
	-- Since we always set data.heads to the lemma and specification of the lemma is mandatory in {{la-noun}}, there aren't
	-- really any redundant heads.
	data.no_redundant_head_cat = true
	data.id = decldata.id

	local categories = data.categories
	if is_num then
		process_num_type(decldata.num_type, categories)
	end

	if decldata.num == "pl" then
		insert_if_not(categories, "Latin plural-only " .. decldata.pos)
	end

	if decldata.indecl then
		insert(data.inflections, {label = glossary_link("indeclinable")})

		if decldata.pos == "participles" then
			if lemma:match("um$") then
				insert_if_not(categories, "Latin perfect participles")
			end
		end
	else
		local lemma_num = decldata.num == "pl" and "pl" or "sg"
		local masc = decldata.forms
		local fem = attested_form(decldata, "nom_" .. lemma_num .. "_f")
		local neut = attested_form(decldata, "nom_" .. lemma_num .. "_n")
		local gen = attested_form(decldata, "gen_" .. lemma_num .. "_m")
		local acc = attested_form(decldata, "acc_" .. lemma_num .. "_m")
	
		if decldata.pos == "participles" then
			local masc1 = masc
			if masc1:sub(-5) == "ūrus" then
				insert_if_not(categories, "Latin future active participles")
			elseif masc1:sub(-4) == "ndus" then
				-- FIXME, should rename to "Latin gerundives")
				insert_if_not(categories, "Latin future passive participles")
			else
				local masc1_final2 = masc1:sub(-2)
				if masc1_final2 == "us" then
					insert_if_not(categories, "Latin perfect participles")
				elseif masc1_final2 == "ns" then
					insert_if_not(categories, "Latin present participles")
				else
					error("Unrecognized participle ending: " .. masc1)
				end
			end
		end
	
		-- We display the inflections in three different ways to mimic the
		-- old way of doing things:
		--
		-- 1. If masc and fem are different, show masc, fem and neut.
		-- 2. Otherwise, if masc and neut are different, show masc and neut.
		-- 3. Otherwise, show masc nominative and masc genitive.
		if not form_is_empty(fem) and not deep_equals(masc, fem) then
			fem.label = "feminine"
			insert(data.inflections, fem)
			if not form_is_empty(neut) then
				neut.label = "neuter"
				insert(data.inflections, neut)
			end
		elseif not form_is_empty(neut) and not deep_equals(masc, neut) then
			neut.label = "neuter"
			insert(data.inflections, neut)
		elseif not form_is_empty(gen) then
			gen.label = "genitive"
			insert(data.inflections, gen)
		elseif not form_is_empty(acc) then
			acc.label = "accusative"
			insert(data.inflections, acc)
		end

		insert(infl_classes, decldata.title)
	end

	local comp = normalize_derivation(decldata.comp, "comparative")
	local sup = normalize_derivation(decldata.sup, "superlative")
	degree_derivations(comp, sup, data)

	local adv = normalize_derivation(decldata.adv, "adverb")
	if adv and adv ~= "-" then
		insert(data.inflections, adv)
	end

	for _, cat in ipairs(decldata.categories) do
		insert_if_not(categories, cat)
	end

	for _, cat in ipairs(decldata.cat) do
		insert_if_not(categories, "Latin " .. cat)
	end
	
	return decldata.pos
end

pos_functions = function(def, args, data, infl_classes, title)
	return adjectives("adjectives", def, args, data, infl_classes, title)
end

pos_functions = function(def, args, data, infl_classes, title)
	return adjectives("participles", def, args, data, infl_classes, title)
end

pos_functions = function(def, args, data, infl_classes, title)
	return adjectives("determiners", def, args, data, infl_classes, title)
end

pos_functions = function(def, args, data, infl_classes, title)
	return adjectives("pronouns", def, args, data, infl_classes, title)
end

pos_functions = function(def, args, data, infl_classes, title)
	return adjectives("suffixes", def, args, data, infl_classes, title)
end

pos_functions = function(def, args, data, infl_classes, title)
	return adjectives("numerals", def, args, data, infl_classes, title)
end

pos_functions = function(def, args, data)
	local sublist = {sublist = "/"}
	args = require("Module:parameters").process(args, {
		 = {alias_of = "head", list = false},
		 = {alias_of = "comp"},
		 = {alias_of = "sup"},
		 = {list = true, required = true},
		 = sublist,
		 = sublist,
		 = true,
	})
	data.heads = args.head
	data.no_redundant_head_cat = true -- since head= is required
	data.id = args.id
	local comp, sup = args.comp, args.sup
	local irreg = false

	if comp then
		if comp == "-" then
			comp = "-"
		elseif comp == nil then
			comp = nil
		else
			comp.label = glossary_link("comparative")
			comp = args.comp
			irreg = true
		end
	end
	if sup then
		if sup == "-" then
			sup = "-"
		elseif sup == nil then
			sup = nil
		else
			sup.label = glossary_link("superlative")
			sup = args.sup
			irreg = true
		end
	end

	local categories = data.categories
	if irreg then
		insert_if_not(categories, "Latin irregular adverbs")
	end

	if not (comp or sup) then
		local default_comp = {label = glossary_link("comparative")}
		local default_sup = {label = glossary_link("superlative")}
		for _, head in ipairs(args.head) do
			local stem = nil
			for _, suff in ipairs{"iter", "nter", "ter", "er", "iē", "ē", "im", "ō"} do
				stem = head:match("(.*)" .. pattern_escape(suff) .. "$")
				if stem ~= nil then
					if suff == "nter" then
						stem = stem .. "nt"
						suff = "er"
					end
					insert(default_comp, stem .. "ius")
					insert(default_sup, stem .. "issimē")
					break
				end
			end
			if not stem then
				error("Unrecognized adverb type, recognized types are “-ē”, “-er”, “-ter”, “-iter”, “-im”, or “-ō” or specify irregular forms or “-” if incomparable.")
			end
		end
		comp = comp or default_comp
		sup = sup or default_sup
	end

	degree_derivations(comp, sup, data)
end

pos_functions = pos_functions

local function get_forms(forms)
	if #forms == 0 then
		return nil
	end
	local i, attested = 1, false
	while true do
		local form = forms
		if form == nil then
			return forms, attested
		elseif form == "-" then
			remove(forms, i)
		else
			if not (attested or get_plaintext(form):sub(1, 1) == "*") then
				attested = true
			end
			i = i + 1
		end
	end
end

local function degree(pos, deg, pos_func, other_arg, other_label, args, data, infl_classes)
	local list = {list = true}
	args = require("Module:parameters").process(args, {
		 = {alias_of = "head", list = false},
		 = list,
		 = list,
		 = list,
		 = true,
	})
	data.no_redundant_head_cat = #args.head == 0
	-- Set default manually so we can tell whether the user specified head=.
	if #args.head == 0 then
		args.head = {PAGENAME}
	end
	data.heads = args.head
	data.id = args.id

	insert(data.inflections, {label = deg})
	
	if pos_func then
		pos_func(args, data, infl_classes)
	end

	local positive, positive_attested = get_forms(args.positive)

	if positive then
		if not positive_attested then
			insert(data.categories, "Latin " .. deg .. "-only " .. pos)
		end
		if #positive > 0 then
			args.positive.label = "positive"
			insert(data.inflections, args.positive)
		else
			insert(data.inflections, {label = "no positive form"})
		end
	end

	local other = get_forms(args)
	if other then
		if #other > 0 then
			args.label = other_label
			insert(data.inflections, args)
		else
			insert(data.inflections, {label = "no " .. other_label .. " form"})
		end
	end

	-- If a lemma, return the primary part of speech ("adjectives" or
	-- "adverbs"), so that the term is categorized in "Latin adjectives" or
	-- "Latin adverbs". Otherwise, return nothing, so that the term goes in the
	-- relevant non-lemma category (e.g. "Latin comparative adjectives"), and
	-- into "Latin non-lemma forms".
	if positive and not positive_attested then
		return pos
	end
end

local function comp_adj(args, data, infl_classes)
	insert(infl_classes, "]")
	local n = {label = "neuter"}
	for _, head in ipairs(args.head) do
		local neuter = head:gsub("or$", "us")
		insert(n, neuter)
	end
	insert(data.inflections, n)
end

pos_functions = function(def, args, data, infl_classes, title)
	return degree("adjectives", "comparative", comp_adj, "sup", "superlative", args, data, infl_classes)
end

pos_functions = function(def, args, data, infl_classes, title)
	return degree("adverbs", "comparative", nil, "sup", "superlative", args, data, infl_classes)
end

local function sup_adj(args, data, infl_classes)
	insert(infl_classes, "]")
	insert(infl_classes, "]")
	local f, n = {label = "feminine"}, {label = "neuter"}
	for _, head in ipairs(args.head) do
		local stem = head:gsub("us$", "")
		insert(f, stem .. "a")
		insert(n, stem .. "um")
	end
	insert(data.inflections, f)
	insert(data.inflections, n)
end

pos_functions = function(def, args, data, infl_classes, title)
	return degree("adjectives", "superlative", sup_adj, "comp", "comparative", args, data, infl_classes)
end

pos_functions = function(def, args, data, infl_classes, title)
	return degree("adverbs", "superlative", nil, "comp", "comparative", args, data, infl_classes)
end

local function adpositions(pos, def, args, data, infl_classes, title, postscript)
	local cases = invert(require("Module:la-utilities").cases)

	args = require("Module:parameters").process(args, {
		 = {alias_of = "head", list = false},
		 = {list = true, set = keys_to_list(cases)},
		 = {list = true, required = true},
		 = true,
	})

	-- Case names are supplied in numbered arguments, optionally preceded by
	-- headwords.
	cases = args
	for i = 1, #cases do
		for j = i + 1, #cases do
			if cases == cases then
				error("Duplicate case")
			end
		end
		local case = cases
		local appendix_link = glossary_link(case)
		if i == 1 then
			appendix_link = "+ " .. appendix_link
		end
		insert(postscript, appendix_link)
		insert_if_not(data.categories, "Latin " .. case .. " " .. pos)
	end

	data.heads = args.head
	data.no_redundant_head_cat = true -- since head= is required
	data.id = args.id
end

pos_functions = function(...)
	return adpositions("prepositions", ...)
end

pos_functions = function(...)
	return adpositions("postpositions", ...)
end

pos_functions = function(def, args, data)
	args = require("Module:parameters").process(args, {
		 = {required = true, default = "labōrandum"}, -- headword
		 = true, -- gerundive
	})

	data.heads = {args}
	data.no_redundant_head_cat = true -- since 1= is required and goes into data.heads
	insert(data.inflections, {label = "]"})
	local stem = args:match("^(.*)um$")
	if not stem then
		error("Unrecognized gerund ending: " .. stem)
	end
	if args == "-" then
		insert(data.inflections, {label = "no ]"})
	else
		insert(data.inflections, { = args or stem .. "us", label = "]"})
	end
end

local function non_lemma_forms(def, args, data)
	args = require("Module:parameters").process(args, {
		 = {required = true, default = def}, -- headword or cases
		 = {list = true, require_index = true},
		 = {list = true},
		 = true,
	})

	local heads = {args}
	for _, head in ipairs(args.head) do
		insert(heads, head)
	end
	data.heads = heads
	data.no_redundant_head_cat = true -- since 1= is required and goes into data.heads
	data.genders = args.g
	data.id = args.id
end

pos_functions = non_lemma_forms
pos_functions = non_lemma_forms
pos_functions = non_lemma_forms
pos_functions = non_lemma_forms
pos_functions = non_lemma_forms
pos_functions = non_lemma_forms
pos_functions = non_lemma_forms
pos_functions = non_lemma_forms
pos_functions = non_lemma_forms
pos_functions = non_lemma_forms

return export