Module:snon-headword: Difference between revisions

From Linguifex
Jump to navigation Jump to search
No edit summary
No edit summary
 
Line 362: Line 362:
end
end


-- Included "pres" explicitly for backwards compat. if needed, but retaining past, stative, future.
process_verb_form("pres", "ir", "present")
process_verb_form("pres", "ir", "present")
process_verb_form("past", "adhir", "past")
process_verb_form("past", "adhir", "past")
process_verb_form("stat", "adhist", "stative")
process_verb_form("imp", "adhist", "imperative")
process_verb_form("fut", "ist", "future")
process_verb_form("fut", "ist", "future")
end
end
Line 374: Line 373:
["pres"] = {list = true, disallow_holes = true},
["pres"] = {list = true, disallow_holes = true},
["past"] = {list = true, disallow_holes = true},
["past"] = {list = true, disallow_holes = true},
["stat"] = {list = true, disallow_holes = true},
["imp"] = {list = true, disallow_holes = true},
["fut"] = {list = true, disallow_holes = true},
["fut"] = {list = true, disallow_holes = true},
["irr"] = {type = "boolean"},
["irr"] = {type = "boolean"},

Latest revision as of 18:58, 12 May 2026



local export = {}
local pos_functions = {}

local m_links = require("Module:links")
local m_table = require("Module:table")
local m_en_util = require("Module:en-utilities")
local m_hw_util = require("Module:headword utilities")

local lang = require("Module:languages").getByCode("snon")
local langname = lang:getCanonicalName()

local pagename = mw.loadData("Module:headword/data").pagename

local suffix_categories = {
	["adjectives"] = true,
	["adverbs"] = true,
	["nouns"] = true,
	["verbs"] = true,
}

local function glossary_link(...)
	return m_hw_util.glossary_link(...)
end

local function insert_inflection(data, terms, label, accel)
	m_hw_util.insert_inflection {
		headdata = data,
		terms = terms,
		label = label,
		accel = accel and {form = accel} or nil,
	}
end

-- The main entry point.
function export.show(frame)
	local poscat = frame.args[1] or error("Part of speech has not been specified. Please pass parameter 1 to the module invocation.")
	local parargs = frame:getParent().args

	local params = {
		["head"] = {list = true, disallow_holes = true},
		["nomut"] = {type = "boolean"},
	}

	if pos_functions[poscat] then
		for key, val in pairs(pos_functions[poscat].params) do
			params[key] = val
		end
	end

	local args = require("Module:parameters").process(parargs, params)

	local heads = args.head
	if #heads == 0 then
		heads = {pagename}
	end

	local data = {
		lang = lang,
		pos_category = poscat,
		categories = {},
		heads = heads,
		genders = {},
		inflections = {},
		pagename = pagename,
	}

	if pos_functions[poscat] then
		pos_functions[poscat].func(args, data)
	end

	return require("Module:headword").full_headword(data)
end

-----------------------------------------------------------------------------------------
--                                          Nouns                                      --
-----------------------------------------------------------------------------------------

local allowed_genders = m_table.listToSet{
	"m", "f", "mf", "mfbysense", "mfequiv", "gneut", "n",
	"m-p", "f-p", "mf-p", "mfbysense-p", "mfequiv-p", "gneut-p", "n-p",
	"m-s", "f-s", "mf-s", "mfbysense-s", "mfequiv-s", "gneut-s", "n-s",
	"?", "?-p", "?-s"
}

-- Extensible table for default plural endings by gender
local default_plural_endings = {
	m = "ar",
	f = "ir",
	-- Easily add more later, e.g., n = "ur"
}

local function validate_genders(genders)
	for _, g in ipairs(genders) do
		if type(g) == "table" then
			g = g.spec
		end
		if not allowed_genders[g] then
			error("Unrecognized gender: " .. g)
		end
	end
end

-- Extracts the base gender ("m", "f", etc.) ignoring number suffixes like "-p" or "-s"
local function get_base_gender(g)
	if type(g) == "table" then g = g.spec end
	g = g:gsub("%-p$", ""):gsub("%-s$", "")
	if g == "mf" then return {"m", "f"} end
	if default_plural_endings[g] then return {g} end
	return {}
end

local function do_noun(args, data, is_proper)
	local is_plurale_tantum = false
	local category_pos = m_en_util.singularize(data.pos_category)

	validate_genders(args[1])
	data.genders = args[1]
	
	-- Check for specific genders and pluralia tantum.
	local base_genders_present = {}
	for _, g in ipairs(args[1]) do
		if type(g) == "table" then
			g = g.spec
		end
		if g:find("-p$") then
			is_plurale_tantum = true
		end
		
		for _, bg in ipairs(get_base_gender(g)) do
			base_genders_present[bg] = true
		end
	end

	local lemma = data.pagename
	local plurals = {}
	
	if is_plurale_tantum then
		if args[2][1] then
			error("Can't specify plurals of plurale tantum " .. category_pos)
		end
	else
		plurals = m_hw_util.parse_term_list_with_modifiers {
			paramname = {2, "pl"},
			forms = args[2],
			splitchar = ",",
		}
		
		-- Check for special plural signals
		local mode = nil
		local pl1 = plurals[1]
		if pl1 and #pl1.term == 1 then
			mode = pl1.term
			if mode == "?" or mode == "!" or mode == "-" or mode == "~" then
				pl1.term = nil
				if next(pl1) then
					error(("Can't specify inline modifiers with plural code '%s'"):format(mode))
				end
				table.remove(plurals, 1)  -- Remove the mode parameter
			elseif mode ~= "+" and mode ~= "#" then
				error(("Unexpected plural code '%s'"):format(mode))
			end
		end
		
		if args.mut then
			local mutation = {
				["r"] = "radical", ["l"] = "lenite", ["e"] = "eclipse"
			}
			table.insert(data.inflections, {label = mutation[args.mut]})
		end
		
		if is_plurale_tantum then
			table.insert(data.inflections, {label = "sometimes " .. glossary_link("plural only") .. ", in variation"})
		end
		
		if mode == "?" then
			table.insert(data.categories, langname .. " " .. data.pos_category .. " with unknown or uncertain plurals")
		elseif mode == "!" then
			table.insert(data.inflections, {label = "plural not attested"})
			table.insert(data.categories, langname .. " " .. data.pos_category .. " with unattested plurals")
			if plurals[1] then
				error("Can't specify any plurals along with unattested plural code '!'")
			end
		elseif mode == "-" then
			table.insert(data.categories, langname .. " uncountable " .. data.pos_category)
			if plurals[1] then
				table.insert(data.inflections, {label = "usually " .. glossary_link("uncountable")})
				table.insert(data.categories, langname .. " countable " .. data.pos_category)
			else
				table.insert(data.inflections, {label = glossary_link("uncountable")})
			end
		else
			if not plurals[1] and not is_proper then
				plurals[1] = {term = "+"}
			end
			if mode == "~" then
				table.insert(data.inflections, {label = glossary_link("countable") .. " and " .. glossary_link("uncountable")})
				table.insert(data.categories, langname .. " uncountable " .. data.pos_category)
				table.insert(data.categories, langname .. " countable " .. data.pos_category)
			elseif plurals[1] then
				table.insert(data.categories, langname .. " countable " .. data.pos_category)
			else
				table.insert(data.categories, langname .. " uncountable " .. data.pos_category)
			end
		end

		local new_plurals = {}
		for _, pl in ipairs(plurals) do
			if pl.term == "+" then
				local generated_any = false
				-- Generate default plurals for all matched base genders
				for bg, _ in pairs(base_genders_present) do
					table.insert(new_plurals, {term = lemma .. default_plural_endings[bg]})
					generated_any = true
				end
				-- Fallback if no specific gender mapped
				if not generated_any then
					table.insert(new_plurals, {term = lemma .. "ar"}) 
				end
			else
				table.insert(new_plurals, pl)
			end
		end
		plurals = new_plurals

		insert_inflection(data, plurals, "plural", "p")

		if plurals[2] then
			table.insert(data.categories, langname .. " " .. data.pos_category .. " with multiple plurals")
		end
	end

	-- Generalized handler for other gendered forms with specific default suffixes
	local function process_gender_form(param, label, accel, default_suffix)
		local forms = m_hw_util.parse_term_list_with_modifiers {
			paramname = param,
			forms = args[param],
			splitchar = ",",
		}
		if forms[1] then
			local new_forms = {}
			for _, f in ipairs(forms) do
				if f.term == "+" and default_suffix then
					table.insert(new_forms, {term = lemma .. default_suffix})
				else
					table.insert(new_forms, f)
				end
			end
			insert_inflection(data, new_forms, label, accel)
		end
	end

	process_gender_form("m", "masculine", "m")
	process_gender_form("f", "feminine", "f")
	process_gender_form("mpl", "masculine plural", "m|p", default_plural_endings["m"])
	process_gender_form("fpl", "feminine plural", "f|p", default_plural_endings["f"])
	-- Extensible for new forms like neuter:
	-- process_gender_form("n", "neuter", "n")
	-- process_gender_form("npl", "neuter plural", "n|p", default_plural_endings["n"])
end

local function get_noun_params(is_proper)
	return {
		[1] = {list = "g", disallow_holes = true, required = not is_proper, default = "?", type = "genders", flatten = true},
		[2] = {list = "pl", disallow_holes = true},
		["m"] = {list = true},
		["f"] = {list = true},
		["mpl"] = {list = true},
		["fpl"] = {list = true},
		["mut"] = {set = {"r", "l", "e"}}
	}
end

pos_functions["nouns"] = {
	params = get_noun_params(),
	func = do_noun,
}

pos_functions["proper nouns"] = {
	params = get_noun_params("is proper"),
	func = function(args, data)
		do_noun(args, data, "is proper noun")
	end,
}

-----------------------------------------------------------------------------------------
--                                 Adjectives                                          --
-----------------------------------------------------------------------------------------

local function do_adj(args, data)
	local lemma = data.pagename
	
	if args.inv then
		table.insert(data.inflections, {label = glossary_link("invariable")})
		table.insert(data.categories, langname .. " indeclinable " .. data.pos_category)
	else
		local function process_adj_form(param, default_suffix, label, accel)
			local forms = m_hw_util.parse_term_list_with_modifiers {
				paramname = param,
				forms = args[param],
				splitchar = ",",
			}
			if not forms[1] then
				forms = {{term = lemma .. default_suffix}}
			else
				local new_forms = {}
				for _, f in ipairs(forms) do
					if f.term == "+" then
						table.insert(new_forms, {term = lemma .. default_suffix})
					else
						table.insert(new_forms, f)
					end
				end
				forms = new_forms
			end
			insert_inflection(data, forms, label, accel)
		end

		process_adj_form("comp", "ar", "comparative", "comp")
		process_adj_form("sup", "ast", "superlative", "sup")
	end
end

pos_functions["adjectives"] = {
	params = {
		["comp"] = {list = true, disallow_holes = true},
		["sup"] = {list = true, disallow_holes = true},
		["inv"] = {type = "boolean"},
	},
	func = do_adj,
}

-----------------------------------------------------------------------------------------
--                                     Verbs                                           --
-----------------------------------------------------------------------------------------

local function do_verb(args, data)
	local lemma = data.pagename
	
	if args.irr then
		table.insert(data.categories, langname .. " irregular verbs")
	else
		local function process_verb_form(param, default_suffix, label)
			local forms = m_hw_util.parse_term_list_with_modifiers {
				paramname = param,
				forms = args[param],
				splitchar = ",",
			}
			if not forms[1] then
				forms = {{term = lemma .. default_suffix}}
			else
				local new_forms = {}
				for _, f in ipairs(forms) do
					if f.term == "+" then
						table.insert(new_forms, {term = lemma .. default_suffix})
					else
						table.insert(new_forms, f)
					end
				end
				forms = new_forms
			end
			insert_inflection(data, forms, label)
		end

		process_verb_form("pres", "ir", "present")
		process_verb_form("past", "adhir", "past")
		process_verb_form("imp", "adhist", "imperative")
		process_verb_form("fut", "ist", "future")
	end
end

pos_functions["verbs"] = {
	params = {
		["pres"] = {list = true, disallow_holes = true},
		["past"] = {list = true, disallow_holes = true},
		["imp"] = {list = true, disallow_holes = true},
		["fut"] = {list = true, disallow_holes = true},
		["irr"] = {type = "boolean"},
	},
	func = do_verb,
}

return export