Pendokumenan untuk modul ini boleh diciptakan di Modul:grc-decl/decl/doc

local module_path = 'Module:grc-decl/decl'

local m_decl_static_data = mw.loadData(module_path .. '/staticdata')
local m_paradigms = mw.loadData(module_path .. '/staticdata/paradigms')
local m_dialect_groups = mw.loadData(module_path .. '/staticdata/dialects')
local m_decl_data = require(module_path .. '/data')
local m_dialects = mw.loadData('Module:grc:Dialects')
local m_accent = require('Module:grc-accent')

local export = {
	inflections = m_decl_data.inflections,
	adjinflections = m_decl_data.adjinflections,
	adjinflections_con = m_decl_data.adjinflections_con,
}

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

local function add_forms(args)
	if args.decl_type:match('irreg') then
		for k, v in pairs(args.ctable) do
			if k:match('[NGDAV][SDP]') then
				args.ctable[k] = args[k] or args.stem[v]
			end
		end
	else
		--add stem to forms
		local join_suffix = function(stem_num)
			return args.stem[tonumber(stem_num)]
		end
		
		for k, v in pairs(args.ctable) do
			if k:match('[NGDAV][SDP]') then -- only format case-number forms
				args.ctable[k] = mw.ustring.gsub(v, '%d', join_suffix)
				if args.dial == 'les' then
					args.ctable[k] = m_accent.antepenult(args.ctable[k])
				end
			end
		end
	end
end

--[=[
	Gets stem-ending combinations from [[Module:grc-decl/data]]
	and [[Module:grc-decl/staticdata]]. Called a single time to get forms
	of a noun, and two or three times by make_decl_adj for each of the genders
	of an adjective.
]=]
function export.make_decl(args, decl, root)
	if not export.inflections[decl] then
		error('unrecognized inflection type ' .. decl)
	end
	-- mw.log(root, decl)
	
	args.stem = { m_accent.ult(root), m_accent.penult(root), root }
	if not mw.ustring.match(decl, '^3rd.+p[ra]x') and not mw.ustring.match(decl, 'prx') then
		args.stem[2] = m_accent.circ(root)
	end
	
	export.inflections[decl](args)
	args.gender[1] = args.gender[1] or args.ctable['g']
	args.declheader = args.declheader or args.ctable['decl']
	add_forms(args)
end

-- Constructs an adverb, comparative, and superlative.
function export.make_acs(args)
	if export.adjinflections_con[args.decl_type] and not args.form:match('open') then
		if args.decl_type:match('3rd%-εσ%-adj') then
			args.atable.comp = args.root .. 'έστερος'
		else
			args.atable.comp = args.root .. 'εώτερος' -- I assume—though I can't find examples
		end
		args.atable.super = mw.ustring.sub(args.atable.comp, 1, -5) .. 'ᾰτος'
	elseif args.decl_type == '1&2-alp-prx' and mw.ustring.sub(args.root, -3) == 'τερ' then
		args.atable.comp = '(' .. args.atable['MNS'] .. ')'
		args.atable.super = mw.ustring.gsub(args.atable.comp, 'τερος$', 'τᾰτος')
		args.atable.adv = args.atable['NNS']
		args.comp = nil
	elseif args.decl_type == '1&2-alp-prx' and mw.ustring.sub(args.root, -3) == 'τᾰτ' then
		args.atable.super = '(' .. args.atable['MNS'] .. ')'
		args.atable.comp = mw.ustring.gsub(args.atable.super, 'τᾰτος$', 'τερος')
		args.atable.adv = args.atable['NNP']
		args.super = nil
	elseif args.decl_type:match('ups') then
		args.atable.comp = args.root .. 'ῠ́τερος'
	elseif args.decl_type == '1&3-οτ' then
		args.atable.comp = nil
		args.atable.super = nil
	elseif args.decl_type == '1&3-ᾰν-pax' then
		args.atable.comp = args.root .. 'ᾰ́ντερος'
	elseif args.decl_type == '1&3-εν-pax' then
		args.atable.comp = args.root .. 'έντερος'
	elseif args.decl_type == '1&3-εντ-pax' then
		args.atable.comp = args.root .. 'έστερος' -- hopefully this is general?
	elseif mw.ustring.match(args.decl_type, 'ντ') then
		args.atable.comp = nil --participles
		args.atable.super = nil
	elseif args.decl_type:match('cons') then
		if mw.ustring.match(args.root, 'ον$') then
			args.atable.comp = args.root .. 'έστερος'
		elseif mw.ustring.match(args.root, 'εσ$') then
			args.atable.comp = mw.ustring.sub(args.root, 1, -3) .. 'έστερος'
		else
			args.atable.comp = nil --not really regular afaict
			args.atable.super = nil
		end
	elseif ((m_accent.circ(args.root) == m_accent.ult(args.root)) or args.decl_type:match('att')) and not args.hp then
		args.atable.comp = args.root .. 'ώτερος'
	else
		args.atable.comp = args.root .. 'ότερος'
	end
	args.atable.adv = args.adv or args.atable.adv or mw.ustring.gsub(mw.ustring.gsub(args.atable.MGP, 'ν$', 'ς'), 'ν<', 'ς<')
	args.atable.comp = args.comp or args.atable.comp
	args.atable.super = args.super or args.atable.super or (args.atable.comp and mw.ustring.gsub(args.atable.comp, 'ερος$', 'ᾰτος'))
end

--[=[
	Interprets the table for the adjective's inflection type
	in [[Module:grc-decl/decl/staticdata]].
]=]
function export.make_decl_adj(args, ct)
	--[[
		Two possibilities, with the indices of the table of endings
		and the stem augmentation that they use:
			- masculine–feminine (1, a1), neuter (2, a2)
			- masculine (1, a1), feminine (2, a2), neuter (3, a1)
	]]
	-- Masculine or masculine and feminine forms.
	export.make_decl(args, ct[1], args.root .. (ct.a1 or ''))
	for k, v in pairs(args.ctable) do
		args.atable['M' .. k] = v
	end
	-- Feminine or neuter forms.
	if ct[2] then
		export.make_decl(args, ct[2], args.fstem or (args.root .. (ct.a2 or '')))
		for k, v in pairs(args.ctable) do
			args.atable['F' .. k] = v
		end
	end
	export.make_decl(args, ct[3], args.root .. (ct.a1 or ''))
	for k, v in pairs(args.ctable) do
		args.atable['N' .. k] = v
	end
	args.ctable = nil
	export.make_acs(args)
	args.adeclheader = ct.adeclheader or 'Declension'
end

function export.get_decl(args)
	if args[1] == 'indecl' then
		if not args[2] then error("Specify the indeclinable form in the 2nd parameter.") end
		args.decl_type, args.root = 'indecl', ''
		return
	elseif args[1] == 'irreg' then
		if args.gender[1] == "N" then
			args.decl_type, args.root = 'irregN', ''
		else
			args.decl_type, args.root = 'irreg', ''
		end
		return
	end
	
	if not args[1] or not args[2] then error("Use the 1st and 2nd parameters for the nominative and genitive singular.") end
	args[1] = mw.ustring.toNFD(args[1])
	args[2] = mw.ustring.toNFD(args[2])
	
	local nomstrip = m_accent.strip_tone(args[1])
	local genstrip = m_accent.strip_tone(args[2])
	if not mw.ustring.match(args[1], 'ῠς?$') then
		genstrip = mw.ustring.gsub(genstrip, 'εος$', 'ους')
		genstrip = mw.ustring.gsub(genstrip, 'α[̆]ος$', 'ως')
	end
	
	local nom_match, decl_type, root, nom, gen
	for i = 5, 1, -1 do
		local NS = mw.ustring.sub(nomstrip, -i)
		local decl = m_decl_static_data.infl_info[NS]
		if type(decl) == "string" then
			decl = m_decl_static_data.infl_info[decl]
		end
		
		if decl then
			nom_match = decl
			root = mw.ustring.sub(nomstrip, 1, -(1 + mw.ustring.len(NS)))
			nom = NS
			
			for i = 6, 1, -1 do
				local GS = mw.ustring.sub(genstrip, -i)
				local name = decl[GS]
				if name then
					decl_type = name
					gen = GS
					break
				end
			end
			
			if decl_type then
				-- mw.log(nomstrip, nom, genstrip, gen, decl_type)
				break
			end
		end
	end
	
	if decl_type and root then
		-- This could be simplified by writing a new function in [[Module:grc-accent]].
		mw.log("actual form: " .. args[1], "ult: " .. m_accent.ult(nomstrip), "circ: " .. m_accent.circ(nomstrip), "pencirc: " .. m_accent.pencirc(nomstrip), "antepenult: " .. m_accent.antepenult(nomstrip), "penult: " .. m_accent.penult(nomstrip))
		local suffix = '-prx'
		if m_accent.ult(nomstrip) == args[1] then
			suffix = ''
		elseif m_accent.circ(nomstrip) == args[1] then
			suffix = '-con'
		elseif m_accent.pencirc(nomstrip) == args[1] and export.inflections[decl_type .. '-pax'] then
			suffix = '-pax'
		elseif m_accent.antepenult(nomstrip) == args[1] then
			suffix = '-prx'
		elseif m_accent.penult(nomstrip) == args[1] then -- we have a word someone didn't put a breve on
			suffix = '-pax'
		end
		
		decl_type = decl_type .. suffix
		args.decl_type, args.root = decl_type, root
		
		return
	elseif mw.ustring.match(genstrip, 'ος$') then
		local suffix = '-prx'
		if m_accent.circ(nomstrip) == args[1] or m_accent.ult(nomstrip) == args[1] then
			suffix = ''
		elseif m_accent.pencirc(nomstrip) == args[1] then
			suffix = '-pax'
		end
		local root = mw.ustring.sub(genstrip, 1, -3)
		if args.gender[1] == "N" or (mw.ustring.match(root, 'α[̆̄]τ$') and not (args.gender[1] == "M" and args.gender[2] == "F")) then
			args.decl_type, args.root = '3rd-N-cons' .. suffix, root
		else
			args.decl_type, args.root = '3rd-cons' .. suffix, root
		end
		
		return
	end
	
	if nom_match then
		local gens = {}
		for gen, name in pairs(nom_match) do
			table.insert(gens, quote("-" .. gen))
		end
		local agreement = { "A declension was", " ", " does" }
		if #gens > 1 then
			agreement = { "Declensions were", "s ", " do" }
		end
		gens = table.concat(gens, ", ")
		
		error(agreement[1] .. " found that matched the ending of the nominative form " .. quote(args[1]) ..
				", but the genitive ending" .. agreement[2] .. gens ..
				agreement[3] .. " not match the genitive form " .. quote(args[2]) .. ".")
	else
		for nom, gens in pairs(m_decl_static_data.ambig_forms) do
			for gen, _ in pairs(gens) do
				if mw.ustring.match(args[1], nom .. "$") and mw.ustring.match(args[2], gen .. "$") then
					error("No declension found for nominative " .. quote(args[1]) .. " and genitive " .. quote(args[2]) ..
							". There are two declensions with nominative " .. quote("-" .. nom) ..
							" and genitive " .. quote("-" .. gen) ..
							". To indicate which one you mean, mark the vowel length of the endings with a macron or breve.")
				end
			end
		end
		
		error("Can’t find a declension type for nominative " .. quote(args[1]) .. " and genitive " .. quote(args[2]) .. ".")
	end
end

function export.get_decl_adj(args)
	if args[1] == 'irreg' then
		args.decl_type, args.root = 'irreg', ''
		return
	end
	
	if not args[1] then error("Use the 1st and 2nd parameters for the masculine and feminine/neuter nominative singular or 3rd declension stem.") end
	args[1] = mw.ustring.toNFD(args[1])
	if args[2] then
		args[2] = mw.ustring.toNFD(args[2])
	end
	
	local mstrip = m_accent.strip_tone(args[1])
	local fstrip
	if args[2] then
		fstrip = m_accent.strip_tone(args[2])
	end
	
	if not args[2] then
		local suffix = '-prx'
		if args[1] == m_accent.ult(mstrip) then
			suffix = ''
		elseif args[1] == m_accent.pencirc(mstrip) then
			suffix = '-pax'
		end
		args.decl_type, args.root = '3rd-cons' .. suffix, mstrip
		if not export.adjinflections[args.decl_type] then
			error('Unrecognized inflection type ' .. args.decl_type)
		end
		return
	end
	
	-- See if last three or two characters of masc have an entry.
	local masc, decl
	for i = 3, 2, -1 do
		local ending = mw.ustring.sub(mstrip, -i)
		local data = m_decl_static_data.infl_info_adj[ending]
		if data then
			masc = ending
			decl = data
			break
		end
	end
	
	-- Allows redirecting, so that macrons or breves can be omitted for instance.
	if type(decl) == "string" then
		decl = m_decl_static_data.infl_info_adj[decl]
	end
	
	if decl then
		-- Look for a feminine ending that matches the end of the feminine form.
		local fem, name
		for feminine, decl_name in pairs(decl) do
			if mw.ustring.match(fstrip, feminine .. '$') then
				fem = feminine
				name = mw.ustring.gsub(decl_name, "%d$", "")
				break
			end
		end
		
		if fem then
			if name == '1&2-alp-con' and mw.ustring.match(fstrip, 'ουσα$') then
				name = '1&3-ουντ'
			end
			
			local suffix = '-prx'
			if args[1] == m_accent.ult(mstrip) then
				suffix = ''
			elseif args[1] == m_accent.circ(mstrip) then
				suffix = '-con'
			elseif args[1] == m_accent.pencirc(mstrip) and name ~= '3rd-εσ-adj' then
				suffix = '-pax'
			elseif name == '3rd-εσ-adj' and args[2] == m_accent.pencirc(fstrip) then
				suffix = '-prp'
			end
			args.decl_type, args.root = name .. suffix, mw.ustring.sub(mstrip, 1, -1 - mw.ustring.len(masc))
			if not export.adjinflections[args.decl_type] then
				error('Unrecognized inflection type ' .. args.decl_type)
			end
			return
		else
			local fems = {}
			local is_neuter = false
			for fem, name in pairs(decl) do
				if fem == "ον" then
					is_neuter = true
				end
				table.insert(fems, quote("-" .. fem))
			end
			fems = table.concat(fems, ", ")
			local agreement = { "A declension was", " ", " does" }
			if #fems > 1 then
				agreement = { "Declensions were", "s ", " do" }
			end
			error(agreement[1] .. " found that matched the ending of the masculine " .. quote(args[1]) ..
					", but the corresponding feminine" .. (is_neuter and " and neuter" or "") .. " ending" .. agreement[2] .. fems ..
					agreement[3] .. " not match the feminine " .. quote(args[2]) .. ".")
		end
	end
	error("Can’t find a declension type for masculine " .. quote(args[1]) .. " and feminine " .. quote(args[2]) .. ".")
end

--[[
	Returns a table containing the inflected forms of the article,
	to be placed before each inflected noun form.
]]
function export.infl_art(args)
	if args.dial == 'epi' or args.adjective or args.form:match('X') then
		return {}
	end
	
	local art = {}
	local arttable
	
	if args.gender[1] then
		arttable = m_paradigms.art_att[args.gender[1]]
	else
		error('Gender not specified.')
	end
	for code, suffix in pairs(arttable) do
		if (args.gender[1] == "M" and args.gender[2] == "F") and m_paradigms.art_att.M[code] ~= m_paradigms.art_att.F[code] then
			art[code] = m_paradigms.art_att.M[code] .. ', ' .. m_paradigms.art_att.F[code]
		else
			art[code] = suffix
		end
	end
	
	if args.gender[1] == 'F' then
		if m_dialect_groups['nonIA'][args.dial] then
			art['NS'] = 'ᾱ̔' -- 104.1-4
			art['GS'] = 'τᾶς'
			art['DS'] = 'τᾷ'
			art['AS'] = 'τᾱ̀ν'
		end
		
		if args.dial == 'the' or args.dial == 'les' then
			art['DS'] = 'τᾶ' -- 39
		elseif args.dial == 'boi' or args.dial == 'ara' or args.dial == 'ele' then
			art['DS'] = 'ται' -- 104.3
		end
		
		if m_dialect_groups['nonIA'][args.dial] then
			art['GP'] = 'τᾶν' -- 104.6
		end
		
		if args.dial == 'ato' then
			art['DP'] = 'τῆσῐ(ν)' -- 104.7
		elseif args.dial == 'ion' then
			art['DP'] = 'τῇσῐ(ν)' -- 104.7
		end
		
		if m_dialect_groups['buck78'][args.dial] then
			art['AP'] = 'τᾰ̀ς' -- 104.8
		elseif args.dial == 'kre' or args.dial == 'arg' then
			art['AP'] = 'τὰνς'
		elseif args.dial == 'les' then
			art['AP'] = 'ταῖς'
		elseif args.dial == 'ele' then
			art['AP'] = 'ταὶρ'
		end
		
		if args.dial == 'kre' or args.dial == 'les' or args.dial == 'kyp' then
			art['NS'] = 'ᾱ̓' -- 57
			art['NP'] = 'αἰ'
		elseif args.dial == 'ele' then
			art['NS'] = 'ᾱ̓'
			art['NP'] = 'ταὶ'
		elseif args.dial == 'boi' then
			art['NP'] = 'τὴ' -- 104.5
		elseif m_dialect_groups['west'][args.dial] then --boeotian is covered above
			art['NP'] = 'ταὶ'
		end
	elseif args.gender[1] == 'M' or args.gender[1] == 'N' then
		if args.dial == 'the' then
			art['GS'] = 'τοῖ' -- 106.1
			art['DS'] = 'τοῦ' -- 23
			art['ND'] = 'τοὺ'
			art['GP'] = 'τοῦν'
		end
		
		if args.dial == 'les' then
			art['DS'] = 'τῶ' -- 106.2
		elseif args.dial == 'boi' or args.dial == 'ara' or args.dial == 'ele' or args.dial == 'eub' then
			art['DS'] = 'τοι' -- 106.2
		end
		
		if args.dial == 'ato' or args.dial == 'ion' then
			art['DP'] = 'τοῖσῐ(ν)' -- 106.4
		end
		
		if args.gender[1] == 'M' then
			if m_dialect_groups['buck78'][args.dial] then
				art['AP'] = 'τὸς' -- 106.5
			elseif args.dial == 'kre' or args.dial == 'arg' then
				art['AP'] = 'τὸνς'
			elseif args.dial == 'les' then
				art['AP'] = 'τοῖς'
			elseif args.dial == 'ele' then
				art['AP'] = 'τοὶρ'
			elseif m_dialect_groups['severe'][args.dial] or args.dial == 'boi' then
				art['AP'] = 'τὼς'
			end
			
			if args.dial == 'kre' or args.dial == 'les' or args.dial == 'kyp' then
				art['NS'] = 'ὀ' -- 57
				art['NP'] = 'οἰ'
			elseif args.dial == 'ele' then
				art['NS'] = 'ὀ'
				art['NP'] = 'τοὶ'
			elseif m_dialect_groups['west'][args.dial] or args.dial == 'boi' then
				art['NP'] = 'τοὶ'
			end
		end
		
		if args.dial == 'ele' then
			art['GD'] = 'τοίοις'
			--		elseif args.dial == 'ara' then
			--			art['GD'] = 'τοιυν'
		end
	end
	
	return art
end
	
local lang = require("Module:languages").getByCode("grc")
local function tag(text)
	return require("Module:script utilities").tag_text("-" .. text, lang)
end

local function print_detection_table(detection_table, labels, noun)
	local out = {}
	
	for key1, value1 in pairs(detection_table) do
		table.insert(out, "\n* " .. labels[1] .. " " .. tag(key1))
		if type(value1) == "string" then
			table.insert(out, " &rarr; " .. tag(value1))
		elseif type(value1) == "table" then
			for key2, value2 in pairs(value1) do
				mw.log(mw.ustring.len(key1), mw.ustring.len(key2))
				table.insert(out, "\n** " .. (noun and labels[2] or key2 == "ον" and "neuter" or "feminine") .. " " .. tag(key2) .. ": " .. value2)
				if noun then
					table.insert(out, " (" .. (m_decl_static_data.conversion[value2] or "?") .. ")")
				end
			end
		end
	end
	
	return out
end
	

function export.show_noun_categories(frame)
	local out = print_detection_table(m_decl_static_data.infl_info, { "nominative", "genitive" }, true)
	
	return table.concat(out)
end


function export.show_adj_categories(frame)
	local out = print_detection_table(m_decl_static_data.infl_info_adj, { "masculine", "feminine or neuter" })
	
	return table.concat(out)
end

return export