မာတိကာသို့ ခုန်သွားရန်

မဝ်ဂျူ:grc-headword

နူ ဝိက်ရှေန်နရဳ

This module generates the content of many Ancient Greek headword-line templates: {{grc-verb}}, {{grc-verb form}}, {{grc-noun}}, {{grc-noun form}}, {{grc-proper noun}}, {{grc-proper noun form}}, {{grc-adj-1&2}}, {{grc-adj-2nd}}, {{grc-adj-1&3}}, {{grc-adj-3rd}}, {{grc-adjective form}}, {{grc-part-1&2}}, {{grc-part-1&3}}, {{grc-adverb}}, {{grc-num}}, {{grc-preposition}}, {{grc-particle}}, {{grc-pronoun form}}.

This module tracks the monophthongs α, ι, υ (a, i, u) without macrons, breves, circumflexes, or iota subscripts (◌̄, ◌̆, ◌͂, ◌ͅ) with the tracking template grc-headword/ambig, so that length can be marked as policy requires, and it categorizes all Ancient Greek words into categories for accent type, such as Ancient Greek oxytone terms.

Experimentation on new features is done in Module:grc-headword/sandbox.


local export = {}

local fun_module = "Module:fun"
local grc_accent_module = "Module:grc-accent"
local grc_utilities_module = "Module:grc-utilities"
local headword_module = "Module:headword"
local parameters_module = "Module:parameters"
local table_module = "Module:table"
local table_find_module = "Module:table/find"
local table_list_to_set_module = "Module:table/listToSet"
local table_shallow_copy_module = "Module:table/shallowCopy"

local lang = require("Module:languages").getByCode("grc")
local sc = require("Module:scripts").getByCode("Polyt")
local canonical_name = lang:getCanonicalName()

local NAMESPACE = mw.title.getCurrentTitle().nsText
local PAGENAME = mw.loadData("Module:headword/data").pagename
local MAINSPACE = NAMESPACE == ""

local reconstructed_prefix = NAMESPACE == "Reconstruction" and "reconstructed " or ""

local concat = table.concat
local insert = table.insert
local remove = table.remove
local toNFD = mw.ustring.toNFD
local umatch = mw.ustring.match

local function find_ambig(...)
	find_ambig = require(grc_accent_module).find_ambig
	return find_ambig(...)
end

local function full_headword(...)
	full_headword = require(headword_module).full_headword
	return full_headword(...)
end

local function get_accent_term(...)
	get_accent_term = require(grc_accent_module).get_accent_term
	return get_accent_term(...)
end

local function list_to_set(...)
	list_to_set = require(table_list_to_set_module)
	return list_to_set(...)
end

local function map(...)
	map = require(fun_module).map
	return map(...)
end

local function process_params(...)
	process_params = require(parameters_module).process
	return process_params(...)
end

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

local function shallow_copy(...)
	shallow_copy = require(table_shallow_copy_module)
	return shallow_copy(...)
end

local function table_find(...)
	table_find = require(table_find_module)
	return table_find(...)
end

local function tokenize(...)
	tokenize = require(grc_utilities_module).tokenize
	return tokenize(...)
end

local pos_functions = {}

local legal_declension = {
	["first"] = true,
	["second"] = true,
	["Attic"] = true,
	["third"] = true,
	["irregular"] = true,
}
local legal_declension_mnw_map = {
	["first"] = "ပထမ",
	["second"] = "ဒုတိယ",
	["Attic"] = "အာက်ဒေတ်",
	["third"] = "တတိယ",
	["irregular"] = "ဟွံတဝ်ဟွံညဳသာ",
}
-- Also used to validate genders.
local gender_names = {
	["m"]	= "ပုလ္လိၚ်",
	["m-s"] = "ပုလ္လိၚ်",
	["m-d"] = "ပုလ္လိၚ်",
	["m-p"] = "ပုလ္လိၚ်",
	["f"]	= "ဣတ္တိလိၚ်",
	["f-s"] = "ဣတ္တိလိၚ်",
	["f-d"] = "ဣတ္တိလိၚ်",
	["f-p"] = "ဣတ္တိလိၚ်",
	["n"]	= "နပုလ္လိၚ်",
	["n-s"] = "နပုလ္လိၚ်",
	["n-d"] = "နပုလ္လိၚ်",
	["n-p"] = "နပုလ္လိၚ်",
	["?"]	= "ဟွံတီကၠးလိၚ်",
	["?-s"] = "ဟွံတီကၠးလိၚ်",
	["?-d"] = "ဟွံတီကၠးလိၚ်",
	["?-p"] = "ဟွံတီကၠးလိၚ်",
}

local function quote(text)
	return "“" .. text .. "”"
end

local function format(array, concatenater)
	if not array[1] then
		return ""
	else
		return "; ''" .. concat(array, concatenater) .. "''"
	end
end
	
-- Process arg the way [[Module:parameters]] would.
local function process_arg(val)
	if val == "" then
		val = nil
	end
	if val then
		val = mw.text.trim(val)
	end
	return val
end

-- Returns true if text contains one character from the Greek and Coptic or
-- Greek Extended blocks.
local function contains_Greek(text)
	return umatch(text, "[" .. sc:getCharacters() .. "]") and true or false
end

-- A cheaper version of makeEntryName. Doesn't remove underties, which should
-- not appear in headwords, or convert curly apostrophes, spacing smooth
-- breathings, and spacing coronides to straight apostrophes.
local function remove_macron_breve(text)
	return toNFD(text):gsub("\204[\132\134]", "")
end

local function remove_links(text)
	if text:find("%[%[") then
		return (text
			:gsub("%[%[[^|]+|([^%]]+)%]%]", "%1")
			:gsub("%[%[([^%]]+)%]%]", "%1"))
	else
		return text
	end
end

local U = mw.ustring.char
local macron = U(0x304)
local breve = U(0x306)
local rough = U(0x314)
local smooth = U(0x313)
local diaeresis = U(0x308)
local acute = U(0x301)
local grave = U(0x300)
local circumflex = U(0x342)
local subscript = U(0x345)
local dbrevebelow = U(0x35C)
local diacritic_patt = concat{
	"[",
	macron, breve,
	rough, smooth, diaeresis,
	acute, grave, circumflex,
	subscript,
	"]"
}
local accent_patt = "[" .. acute .. grave .. circumflex .. "]"

-- Controls whether or not the headword can be provided in the first numbered parameter.
local function needs_headword(text)
	local lengthDiacritic = "[" .. macron .. breve .. circumflex .. subscript .. "]"
	local aiu_diacritic = "^([ΑαΙιΥυ])(" .. diacritic_patt .. "*)$"
	
	text = remove_links(text)
	
	-- If page name has straight apostrophe, a headword with curly apostrophe should be provided.
	if text:find("'") then
		return true
	end
	
	-- breaks the word into units
	for _, token in ipairs(tokenize(text)) do
		local vowel, diacritics = umatch(token, aiu_diacritic)
			
		if vowel and (diacritics == "" or
				not umatch(diacritics, lengthDiacritic)) then
			return true
		end
	end
		
	return false
end

-- Process numbered parameters before using [[Module:parameters]], as
-- [[Module:parameters]] converts several named parameters into arrays, which
-- makes them more difficult to manipulate.

local function process_numbered_params(args, Greek_params, nonGreek_params)
	if not nonGreek_params then
		nonGreek_params = {false}
	end
	
	local max_Greek_param_index = #Greek_params
	
	-- Clone args table so that its values can be modified.
	args = shallow_copy(args)
	
	if args.head then
		-- [[Special:WhatLinksHere/Wiktionary:Tracking/grc-headword/head param]]
		require("Module:debug").track("grc-headword/head param")
	end
	
	local last_Greek_param_index = 0
	for i, arg in ipairs(args) do
		if arg == "-" or contains_Greek(arg) then
			last_Greek_param_index = i
		else
			break
		end
	end
	
	local head_in_arg1 = false
	
	if last_Greek_param_index == max_Greek_param_index then
		if not MAINSPACE or needs_headword(PAGENAME) then
			head_in_arg1 = true
		else
			-- If synizesis is shown via a double breve below, allow it anyway.
			local head = args[table_find(Greek_params, "head")]
			if head and head:find(dbrevebelow) then
				head_in_arg1 = true
			else
				error(("The pagename does not have ambiguous vowels, so there cannot be "
						.. max_Greek_param_index
						.. " numbered parameter%s. See template documentation for more details.")
						:format(max_Greek_param_index == 1 and "" or "s"))
			end
		end
	
	elseif last_Greek_param_index > max_Greek_param_index then
		error("Too many numbered parameters containing Greek text or hyphens. There can be at most "
				.. max_Greek_param_index .. ".")
	
	-- For indeclinable nouns: {{grc-noun|Ἰσρᾱήλ|m}}
	-- First parameter is headword if equal to pagename when macrons and breves are removed.
	elseif args[1] and remove_macron_breve(args[1]):gsub("’", "'") == toNFD(PAGENAME) then
		if args.head then
			error("Parameter 1 appears to be the headword, so the head parameter " .. quote(args.head) .. " is not needed.")
		end
		args.head, args[1] = args[1], nil
	
	else
		remove(Greek_params, 1) -- Remove "head" parameter.
	end
	
	local function _process_params(start_i, end_i, param_names)
		local i = 1 -- Index in the table of parameter names.
		for numbered = start_i, end_i do
			local named = param_names[i]
			i = i + 1
			
			if named then
				-- Process parameters, as they have not been processed by [[Module:parameters]].
				args[numbered], args[named] =
					process_arg(args[numbered]), process_arg(args[named])
			
			-- This should not happen, because the number of Greek parameters
			-- has already been checked.
			elseif args[numbered] then
				error("No purpose for parameter " .. numbered .. ".")
			end
				
			if args[numbered] then
				if named then
					-- This fixes an error caused by the kludgy way in which the
					-- numbered parameters of {{grc-preposition}} are handled.
					if numbered ~= named then
						if args[named] then
							error("Parameter " .. numbered .. " is not needed when parameter " .. named .. " is present.")
						end
						
						args[named], args[numbered] = args[numbered], nil
					end
				else
					error("Parameter " .. numbered .. ", " .. args[numbered] .. ", has no purpose.")
				end
			end
		end
	end
	
	_process_params(1, last_Greek_param_index, Greek_params)
	_process_params(last_Greek_param_index + 1, #Greek_params + #nonGreek_params, nonGreek_params)
	
	if args.head == "-" then
		error("The headword cannot be absent.")
	end
	
	return args
end

local function process_heads(data, poscat)
	data.no_redundant_head_cat = #data.heads == 0
	if #data.heads == 0 then
		local head = PAGENAME
		if NAMESPACE == "Reconstruction" then
			head = "*" .. head
		end
		insert(data.heads, head)
	end
	
	local suffix = data.heads[1]:find("^%*?%-") and true or false
	for i, head in ipairs(data.heads) do
		if suffix and head:sub(1, 1) ~= "-" then
			error("The first headword has a hyphen, so headword #" .. i ..
					", " .. quote(head) .. ", should as well.")
		end
		local accent = get_accent_term(head)
		if accent then
			insert(data.categories,
				("ဝေါဟာ%sအပိုၚ်အခြာ%sဂမၠိုၚ်"):format(canonical_name, accent))
		elseif not umatch(toNFD(head), accent_patt) then
			insert(data.categories,
				("မအရေဝ်ဝေါဟာ%sဗီုရမျာၚ်လက်သန်ဟွံဒးဂမၠိုၚ်"):format(canonical_name))
		else
			insert(data.categories,
				("မအရေဝ်ဝေါဟာ%sမနွံကဵုဗီုရမျာၚ်ပကတိဟွံသေၚ်"):format(canonical_name))
		end
		
		if MAINSPACE then
			local _, vowel_set = find_ambig(head, false)
			for vowel in pairs(vowel_set) do
				require("Module:debug").track {
					"grc-headword/ambig",
					"grc-headword/ambig/" .. vowel
				}
			end
			if not head:find(" ") and toNFD(head):find(grave) then
				error("Head #" .. i .. ", " .. quote(head) ..
					", contained a grave accent, but no space. Grave accent can only be used in multi-word terms.")
			end
		end
	end
	
	if suffix then
		data.pos_category = "အဆက်လက္ကရဴ"
		if not poscat:find "forms$" then
			
		end
	end
end

local function unlinked_form(label)
	return { label = label, { nolink = true, term = "—" } }
end

local function add_gender_form(inflections, gender_arg, gender_name, allow_blank_forms)
	if gender_arg[1] then
		if allow_blank_forms and not gender_arg[2] and gender_arg[1] == "-" then
			insert(inflections, unlinked_form(gender_name))
		else
			gender_arg.label = gender_name
			insert(inflections, gender_arg)
		end
	end
end

local function adj_and_part_forms(total_forms, args, inflections, allow_blank_forms)
	if total_forms == 2 then
		add_gender_form(inflections, args.f, "ဣတ္တိလိၚ်", allow_blank_forms)
	end
	
	add_gender_form(inflections, args.n, "နပုလ္လိၚ်", allow_blank_forms)
end

local function handle_degree_of_comparison(args, data, is_declined_form)
	if args.deg ~= nil then
		if args.deg == 'တုဲဒှ်' then
			data.pos_category = reconstructed_prefix .. "နာမဝိသေသနပတုပ်ရံၚ်"
		elseif args.deg == 'ညိည' then
			data.pos_category = reconstructed_prefix .. "သဒ္ဒာနာမဝိသေသန"
		else
			error('Adjective degree ' .. quote(args.deg) .. ' not recognized.')
		end
		
		if is_declined_form then
			data.pos_category = data.pos_category:gsub("နာမဝိသေသန", "ဗီုပြၚ်နာမဝိသေသန")
		end
	end
end

function export.show(frame)
	local args = frame:getParent().args
	
	local poscat = frame.args[1] or error("Part of speech has not been specified. Please pass parameter 1 to the module invocation.")
	local subclass = frame.args[2]
	
	local data = {
		lang = lang,
		pos_category = reconstructed_prefix .. poscat,
		categories = {}, heads = {}, genders = {}, inflections = {}
	}
	local appendix = {}
	
	if pos_functions[poscat] then
		pos_functions[poscat](args, data, appendix, poscat, subclass)
	end
	
	return full_headword(data) .. format(appendix, ", ")
end

function export.test(frame_args, parent_args, pagename)
	PAGENAME = pagename
	local poscat = frame_args[1] or error("Part of speech has not been specified. Please pass parameter 1 to the module invocation.")
	local subclass = frame_args[2]
	
	local data = {
		pos_category = reconstructed_prefix .. poscat,
		categories = {}, heads = {}, genders = {}, inflections = {}
	}
	local appendix = {}
	
	if pos_functions[poscat] then
		pos_functions[poscat](parent_args, data, appendix, poscat, subclass)
	end
	
	return data
end

pos_functions["နာမ်"] = function(args, data, appendix, poscat)
	args = process_numbered_params(args, { "head", "gen" }, { "g", "decl" })
	
	local list = {list = true}
	local params = {
		-- Numbered parameters 1, 2, 3, 4 handled above.
		head = list,
		gen = list,
		g = {list = true, default = "?"},
		dim = list,
		decl = list,
		sort = true, -- for [[Unsupported titles/Ancient Greek dish]]; please do not use otherwise
	}
	args = process_params(args, params)
	
	data.heads = args.head
	process_heads(data, "နာမ်")
	
	for _, g in ipairs(args.g) do
		local specs, suffix = g:match("^(.-)(%-.*)")
		if not specs then
			specs, suffix = g, ""
		end
		for ch in specs:gmatch(".") do
			g = ch .. suffix
			local gender_name = gender_names[g]
			if gender_name then
				insert(data.genders, g)
				insert(data.categories,
					("%s%s%sဂမၠိုၚ်"):format(poscat, gender_name, canonical_name))
			else
				error("Gender " .. quote(g) .. " is not an valid " .. canonical_name .. " gender.")
			end
		end
	end
	
	if not args.gen[1] then
		insert(data.inflections, { label = "[[အဆက်လက္ကရဴ:မသောၚ်ကၠးဝေါဟာ#indeclinable|သောၚ်ဟွံမာန်]]" })
		insert(data.categories,
			("%s သောၚ်ဟွံမာန် %s")
				:format(poscat, canonical_name))
		for _, g in ipairs(args.g) do
			local specs, suffix = g:match("^(.-)(%-.*)")
			if not specs then
				specs, suffix = g, ""
			end
			for ch in specs:gmatch(".") do
				g = ch .. suffix
				insert(data.categories,
					("%s %s သောၚ်ဟွံမာန် %s")
						:format(poscat, gender_names[g], canonical_name))
			end
		end
		if args.decl[1] then
			error("Declension class " .. quote(args.decl[1])
					.. " has been given, but no genitive form has been given, so the word cannot belong to a declension class.")
		end
	else
		if not args.gen[2] and args.gen[1] == "-" then
			insert(data.inflections, unlinked_form("genitive"))
		else
			args.gen.label = "ဗဳဇဂကူ"
			insert(data.inflections, args.gen)
		end
		
		if args.decl[2] then
			insert(data.inflections, { label = 'variously declined' })
			insert(data.categories,
				("%s %s with multiple declensions")
					:format(canonical_name, poscat))
		elseif not args.decl[1] then
			insert(appendix, "? declension")
		end
		
		for _, decl_class in ipairs(args.decl) do
			if legal_declension[decl_class] then
				local not_irregular = decl_class ~= "ခလံက်ခနက်"
				if not_irregular then
					insert(appendix,
						("[[Appendix:ဝေါဟာ%sလဟုတ်စှ်ေအလာန်%s|လဟုတ်စှ်ေအလာန်%s]]")
							:format(canonical_name, decl_class, decl_class))
					insert(data.categories,
						("%s%sမလဟုတ်စှ်ေအလာန်-%s")
							:format(poscat, canonical_name, decl_class))
				else
					insert(appendix,
						("မလဟုတ်စှ်ေအလာန်%s"):format(decl_class))
					insert(data.categories,
						("%sခလံက်ခနက်%s"):format(poscat, canonical_name))
				end
				
				if not_irregular then
					for _, g in ipairs(args.g) do
						local specs, suffix = g:match("^(.-)(%-.*)")
						if not specs then
							specs, suffix = g, ""
						end
						for ch in specs:gmatch(".") do
							g = ch .. suffix
							insert(data.categories,
								("%s%s%sနကဵုမဆေၚ်စပ်မလဟုတ်စှ်ေအလာန်%s")
									:format(poscat, gender_names[g], canonical_name, decl_class))
						end
					end
				end
			else
				error("Declension " .. quote(decl_class) .. " is not a legal " ..
					canonical_name .. " declension. Choose “ပထမ”, “ဒုတိယ”, “တတိယ”, or “ခလံက်ခနက်”.")
			end
		end
	end
	
	-- Check first-declension endings and gender.
	if args.decl[1] == "ပထမ" then
		local alpha = "α" .. mw.loadData("Module:grc-utilities/data").length.optional .. "[" .. acute .. circumflex .. "]?"
		local eta = "η[" .. acute .. circumflex .. "]?"
		
		local gender = args.g[1]
		local alpha_ending, eta_ending
		if gender == "f" then
			alpha_ending = alpha .. "$"
			eta_ending = eta .. "$"
		elseif gender == "m" then
			alpha_ending = alpha .. "ς$"
			eta_ending = eta .. "ς$"
		else
			gender = nil
			require("Module:debug").track("grc-noun/1st/incorrect or no gender")
		end
		
		if gender then
			for _, head in ipairs(data.heads) do
				head = toNFD(remove_links(head))
				if not (umatch(head, eta_ending) or umatch(head, alpha_ending)) then
					require("Module:debug").track("grc-noun/1st/" .. gender .. " with incorrect ending")
				end
			end
		end
	end
	
	if args.dim[1] then
		args.dim.label = "လဟုတ်စှ်ေ"
		insert(data.inflections, args.dim)
	end
end

pos_functions["နာမ်မကိတ်ညဳ"] = pos_functions["နာမ်"]

pos_functions["ကြိယာ"] = function(args, data)
	args = process_numbered_params(args, { "head" })

	local params = {
		head = {list = true}
	}
	local args = process_params(args, params)
	data.heads = args.head
	
	process_heads(data, "ကြိယာ")
end

pos_functions["ကြိယာဝိသေသန"] = function(args, data)
	args = process_numbered_params(args, { "head", "comp", "super" }, { "type" })
	
	local list = {list = true}
	local params = {
		head = list,
		comp = list,
		super = list,
		type = list,
	}
	local args = process_params(args, params)
	data.heads = args.head
	
	process_heads(data, "ကြိယာဝိသေသန")
	
	-- Show comparative and superlative. If comparative or superlative is absent
	-- while the other form is present, show "no comparative" or "no superlative".
	if args.comp[1] then
		args.comp.label = 'ပတုပ်ရံၚ်'
		insert(data.inflections, args.comp)
	elseif args.super[1] then
		insert(data.inflections, { label = 'ပတုပ်ရံၚ်ဟွံမာန်' })
	end
	if args.super[1] then
		args.super.label = 'သဒ္ဒာ'
		insert(data.inflections, args.super)
	elseif args.comp[1] then
		insert(data.inflections, { label = 'သဒ္ဒာဟွံသေၚ်' })
	end
	
	if args.type[1] then
		local adverb_types = list_to_set{
			"demonstrative", "indefinite", "interrogative", "relative",
		}
		
		for _, type in ipairs(args.type) do
			if adverb_types[type] then
				insert(data.categories, "ကြိယာဝိသေသန" ..  type .. canonical_name .. "ဂမၠိုၚ်")
			else
				error(quote(type) .. " is not a valid subcategory of adverb.")
			end
		end
	end
end

pos_functions["ဂၞန်သၚ်္ချာ"] = function(args, data)
	args = process_numbered_params(args, { "head", "f", "n" })
	
	local list = {list = true}
	local params = {
		head = list,
		f = list,
		n = list,
		car = list,
		ord = list,
		adv = list,
		coll = list,
	}
	local args = process_params(args, params)
	data.heads = args.head
	
	process_heads(data, "ဂၞန်သၚ်္ချာ")
	
	adj_and_part_forms(2, args, data.inflections, false)
	
	local num_type_names = {
		car = "cardinal", ord = "ordinal", adv = "adverbial", coll = "collective",
	}
	
	for _, num_type in ipairs { "car", "ord", "adv", "coll" } do
		if args[num_type][1] then
			args[num_type].label = num_type_names[num_type]
			insert(data.inflections, args[num_type])
		end
	end
end



pos_functions["လုပ်ကၠောန်စွံလဝ်"] = function(args, data, appendix, _, subclass)
	if subclass == "1&2" or subclass == "1&3" then
		pos_functions["part-" .. subclass](args, data, appendix)
	else
		error('Participle subclass ' .. quote(subclass) .. ' not recognized.')
	end
end

pos_functions["part-1&2"] = function(args, data, appendix)
	args = process_numbered_params(args, { "head", "f", "n" })
	
	local required_list = {required = true, list = true}
	local params = {
		-- Parameters 1, 2, and 3 handled above.
		head = {list = true},
		f = required_list,
		n = required_list,
	}
	local args = process_params(args, params)
	data.heads = args.head
	
	process_heads(data, "လုပ်ကၠောန်စွံလဝ်")
	
	insert(data.genders, "m")
	
	insert(appendix, "[[Appendix:ဝေါဟာ" .. canonical_name ..
			"လဟုတ်စှ်ေအလာန်ပထမ|ပထမ]]/[[Appendix:ဝေါဟာ" .. canonical_name ..
			"လဟုတ်စှ်ေအလာန်ဒုတိယ|လဟုတ်စှ်ေအလာန်ဒုတိယ]]")
	
	adj_and_part_forms(2, args, data.inflections, false)
end

pos_functions["part-1&3"] = function(args, data, appendix)
	args = process_numbered_params(args, { "head", "f", "n" })
	
	local required_list = {required = true, list = true}
	local params = {
		-- Parameters 1, 2, and 3 handled above.
		head = {list = true},
		f = required_list,
		n = required_list,
	}
	local args = process_params(args, params)
	data.heads = args.head
	
	process_heads(data, "လုပ်ကၠောန်စွံလဝ်")
	
	insert(data.genders, "m")
	
	insert(appendix, "[[Appendix:ဝေါဟာ" .. canonical_name ..
			"လဟုတ်စှ်ေအလာန်ပထမ|ပထမ]]/[[Appendix:ဝေါဟာ" .. canonical_name ..
			"လဟုတ်စှ်ေအလာန်တတိယ|လဟုတ်စှ်ေအလာန်တတိယ]]")
	
	adj_and_part_forms(2, args, data.inflections, false)
end

pos_functions["နာမဝိသေသန"] = function(args, data, appendix, _, subclass)
	local subclasses = {
		["1&2"] = true, ["1&3"] = true, ["2nd"] = true, ["3rd"] = true
	}
	
	if subclasses[subclass] then
		pos_functions["adj-" .. subclass](args, data, appendix)
	else
		error('Adjective subclass ' .. quote(subclass) .. ' not recognized.')
	end
end

pos_functions["adj-1&2"] = function(args, data, appendix)
	args = process_numbered_params(args, { "head", "f", "n" })
	
	local required_list = {required = true, list = true}
	local params = {
		-- Parameters 1, 2, and 3 handled above.
		head = {list = true},
		f = required_list,
		n = required_list,
		deg = true,
	}
	local args = process_params(args, params)
	data.heads = args.head
	
	process_heads(data, "နာမဝိသေသန")
	
	insert(data.genders, "m")
	
	insert(appendix, "[[Appendix:ဝေါဟာ" .. canonical_name ..
			"လဟုတ်စှ်ေအလာန်ပထမ|ပထမ]]/[[Appendix:ဝေါဟာ" .. canonical_name ..
			"လဟုတ်စှ်ေအလာန်ဒုတိယ|လဟုတ်စှ်ေအလာန်ဒုတိယ]]")
	
	handle_degree_of_comparison(args, data, false)
	
	adj_and_part_forms(2, args, data.inflections, true)
end

pos_functions["adj-1&3"] = function(args, data, appendix)
	args = process_numbered_params(args, { "head", "f", "n" })
	
	local required_list = {required = true, list = true}
	local params = {
		-- Parameters 1, 2, and 3 handled above.
		head = {list = true},
		f = required_list,
		n = required_list,
	}
	local args = process_params(args, params)
	data.heads = args.head
	
	process_heads(data, "နာမဝိသေသန")
	
	insert(data.genders, "m")
	
	insert(appendix, "[[Appendix:ဝေါဟာ" .. canonical_name ..
		"လဟုတ်စှ်ေအလာန်ပထမ|ပထမ]]/[[Appendix:ဝေါဟာ" .. canonical_name ..
		"လဟုတ်စှ်ေအလာန်တတိယ|လဟုတ်စှ်ေအလာန်တတိယ]]")
	
	adj_and_part_forms(2, args, data.inflections, true)
end

pos_functions["adj-2nd"] = function(args, data, appendix)
	args = process_numbered_params(args, { "head", "n" })
	
	local params = {
		-- Parameters 1 and 2 handled above.
		head = {list = true},
		n = {required = true, list = true},
	}
	local args = process_params(args, params)
	data.heads = args.head
	
	process_heads(data, "နာမဝိသေသန")
	
	insert(data.genders, "m")
	insert(data.genders, "f")
	
	insert(appendix, "[[Appendix:ဝေါဟာ" .. canonical_name .. "လဟုတ်စှ်ေအလာန်ဒုတိယ|လဟုတ်စှ်ေအလာန်ဒုတိယ]]")
	
	adj_and_part_forms(1, args, data.inflections, true)
end

pos_functions["adj-3rd"] = function(args, data, appendix)
	args = process_numbered_params(args, { "head", "n" })
	
	local params = {
		-- Parameters 1 and 2 handled above.
		head = {list = true},
		n = {required = true, list = true},
		deg = true,
	}
	local args = process_params(args, params)
	data.heads = args.head
	
	process_heads(data, "နာမဝိသေသန")
	
	insert(data.genders, "m")
	insert(data.genders, "f")
	
	insert(appendix, "[[Appendix:ဝေါဟာ" .. canonical_name .. "လဟုတ်စှ်ေအလာန်တတိယ|လဟုတ်စှ်ေအလာန်တတိယ]]")
	
	handle_degree_of_comparison(args, data, false)
	
	adj_and_part_forms(1, args, data.inflections, true)
end

local case_abbreviations = {
	nom = 'ဒုၚ်ယၟု',
	gen = 'ဗဳဇဂကူ',
	dat = 'ပြကမ္မကာရက',
	acc = 'ကမ္မကာရက',
	voc = 'မဆေၚ်ကဵုရမျာၚ်',
}

pos_functions["ဝိဘတ်"] = function(args, data, appendix)
	-- This allows up to 4 numbered parameters, which is the number of cases
	-- that can appear after prepositions.
	args = process_numbered_params(args, { "head" }, { 1, 2, 3 })
	
	local list = {list = true}
	local params = {
		[1] = list,
		head = list,
	}
	local args = process_params(args, params)
	data.heads = args.head
	
	process_heads(data, "ဝိဘတ်")
	
	if args[1][1] then
		local cases = {}
		for _, case in ipairs(args[1]) do
			if case_abbreviations[case] then
				
				insert(cases, "[[အဆက်လက္ကရဴ:မသောၚ်ကၠးဝေါဟာ#" .. case_abbreviations[case] .. "|" .. case_abbreviations[case] .. "]]")
			else
				error('Case abbreviation ' .. quote(case) ..
					' not recognized. Please choose from ' ..
					mw.text.listToText(map(
							quote,
							{ "gen", "dat", "acc" }
					)) .. '.'
				)
			end
		end
		insert(data.inflections, { label = 'governs the ' .. serial_comma_join(cases) })
	end
end

pos_functions["လုပ်ကၠောန်စွံလဝ်"] = function(args, data)
	args = process_numbered_params(args, { "head" })
	
	local boolean = {type = "boolean"}
	local params = {
		head = {list = true},
		disc = boolean,
		mod = boolean,
		inter = boolean,
		neg = boolean,
	}
	local args = process_params(args, params)
	data.heads = args.head
	
	process_heads(data, "လုပ်ကၠောန်စွံလဝ်")
	
	for _, item in ipairs{ { "disc", "discourse" }, { "mod", "modal" }, { "inter", "interrogative" }, { "neg", "negative" } } do
		if args[item[1]] then
			local descriptor = item[2]
			
			insert(data.inflections, { label = descriptor .. ' particle' })
		end
	end
end

local valid_pos

setmetatable(pos_functions, {
	__index = function (self, key)
		if not key:find(" forms$") then
			return nil
		end
		
		valid_pos = valid_pos or list_to_set{
			"နာမဝိသေသန", "ဖျေံလဝ်သန္နိဋ္ဌာန်", "နာမ်", "ဂၞန်သၚ်္ချာ", "လုပ်ကၠောန်စွံလဝ်",
			"နာမ်မကိတ်ညဳ", "ကြိယာ", "သဗ္ဗနာမ်",
			
		}
		
		local pos = key:match("^(.+) forms$")
		
		if not valid_pos[pos] then
			error ("No function for the POS " .. quote(key) .. ".")
		end
		
		-- POS function for "noun forms", "verb forms", etc.
		return function(args, data)
			args = process_numbered_params(args, { "head" },
				(pos == "နာမ်" or pos == "နာမ်မကိတ်ညဳ") and { "g" })
			
			local list = {list = true}
			local params = {
				head = list,
			}
			if pos == "နာမ်" or pos == "နာမ်မကိတ်ညဳ" then
				params.g = list
			elseif pos == "နာမဝိသေသန" then
				params.deg = true
			end
			local args = process_params(args, params)
			data.heads = args.head
			
			process_heads(data, key)
			
			if args.g then
				for _, g in ipairs(args.g) do
					local specs, suffix = g:match("^(.-)(%-.*)")
					if not specs then
						specs, suffix = g, ""
					end
					for ch in specs:gmatch(".") do
						g = ch .. suffix
						if gender_names[g] then
							insert(data.genders, g)
						else
							error("Gender " .. quote(g) .. " is not an valid " .. canonical_name .. " gender.")
						end
					end
				end
			end
			
			handle_degree_of_comparison(args, data, true)
			mw.logObject(data)
		end
	end
})

return export