Module:Grc-decl/decl/data

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

local m_decl_static_data = mw.loadData(module_path .. '/classes') local m_paradigms = mw.loadData(module_path .. '/staticdata/paradigms') local m_dialect_groups = mw.loadData(module_path .. '/staticdata/dialects') local m_table = require('Module:table') local m_accent = require('Module:grc-accent') local m_links = require('Module:links') local check_type = require('libraryUtil').checkType local grc = require('Module:languages').getByCode('grc') local grk_pro = require('Module:languages').getByCode('grk-pro')

local usub = mw.ustring.sub local to_NFC = mw.ustring.toNFC local to_NFD = mw.ustring.toNFD local get_codepoint = mw.ustring.codepoint

-- Basic string functions can be used when the pattern doesn't contain any -- quantifiers or sets. local ufind = mw.ustring.find local umatch = mw.ustring.match

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

local function ine(var) if var == '' then return nil else return var end end

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

local function mention(alt) return m_links.full_link({ alt = alt, lang = grc }, 'term') end

local function proto_mention(alt) return m_links.full_link({ alt = alt, lang = grk_pro }, 'term') end

local dental_lookup = { ['τ'] = '*-ts', ['δ'] = '*-ds', ['θ'] = '*-tʰs', }

-- Copy tables loaded with mw.loadData, removing metatables. local function deepcopy(orig) return m_table.deepcopy(orig, true) end

-- Return one of the three options, or an error message. -- suffix is true if args[1] does not contain an accent mark and begins in a hyphen. local function accent_switch(accent_term, if_oxytone, if_perispomenon, otherwise, error_message, unaccented_suffix) local value -- accent_term can be nil if this is a paradigm for an unaccented_suffix. check_type('accent_term', 1, accent_term, 'string', unaccented_suffix) if accent_term == 'oxytone' then value = if_oxytone elseif accent_term == 'perispomenon' then value = if_perispomenon else value = otherwise end return value or error_message and error(error_message) end

local function uncontracted_error(contracted, dialect, nom_ending) if contracted == false and (dialect == 'att' or dialect == 'koi' or dialect == 'byz') then --Special:WhatLinksHere/Template:tracking/grc-decl/uncontracted error require('Module:debug').track('grc-decl/uncontracted error') mw.log('In the Attic, Koine, or Byzantine dialects, nouns in ' ..			quote(nom_ending) .. ' are contracted. Remove ' ..			quote('con') .. ' from the ' ..			quote('form') .. ' parameter or change the dialect.') end end

local function nonrecessive_error(accent_term, error_message) if accent_term == 'oxytone' or accent_term == 'perispomenon' then error(error_message) end end

local function some(t, func) for _, item in ipairs(t) do		if func(item) then return true end end return false end

local function dial_condition(actual_dialect, dialect1, dialect2) if not actual_dialect then return false end if type(dialect1) == "string" then return actual_dialect == dialect1 or			dialect2 and actual_dialect == dialect2 or			m_dialect_groups[dialect1] and m_dialect_groups[dialect1][actual_dialect] elseif type(dialect1) == "table" then return some(dialect1, function(dialect)				return dial_condition(actual_dialect, dialect)			end) end end

local function dial_form_multi(args, forms, dialects) local actual_dialect = args.dial if not actual_dialect then return end local ctable = args.ctable -- Forms is an array of tables containing individual forms in	-- the same dialect or dialects: -- { , } -- Dialects is a sequence of strings or tables: -- " "	--		or -- { " ", " ", ... }	if dialects then if dial_condition(actual_dialect, dialects) then for _, form in ipairs(forms) do				if type(form[2]) == 'string' then ctable[form[1]] = form[2] end end end -- Forms is a sequence of tables: -- { ,, } --		or -- { ,, { , , ... } }	elseif type(forms) == 'table' then for _, form_data in ipairs(forms) do			if dial_condition(actual_dialect, form_data[3]) and type(form_data[2]) == 'string' then ctable[form_data[1]] = form_data[2] end end end end

local function dial_form(args, f, suffix, dialect1, dialect2) if dial_condition(args.dial, dialect1, dialect2) then args.ctable[f] = suffix end end

-- Should Aeolic be moved here? local function dial_forms_first(args) dial_form_multi(args, {			{ 'GD', '$αι(ῐ)ν/$ῃῐν' },			{ 'GP', '$ᾱ́ων/$έ͜ων/$ῶν' },			{ 'DP', '$ῃσῐ(ν)/$ῃς/$αις' },		},		'epi') dial_form_multi(args, {		{ 'GP', '$έων/$ῶν', 'ion' },		{ 'DS', '$η', 'boi' }, -- 104.3		{ 'DS', '$αι', { 'ara', 'ele' } },		{ 'DS', '$ᾱ', { 'the', 'les' } },		{ 'GD', '$αίαιρ', 'ele' },		{ 'GP', '$έων/$ῶν', 'ion' }, -- 104.6		{ 'GP', '$ᾶν', 'nonIA' },		{ 'GP', '$ᾱ́ων', 'boi' },		{ 'DP', '$ῃσῐ(ν)', 'ion' }, -- 104.7, ato must be dealt with separately		{ 'DP', '$αισῐ(ν)', 'les' },		{ 'DP', '$ᾱσῐ(ν)', 'ato' },		{ 'DP', '$ῃσῐ(ν)', 'ion' },		{ 'AP', '$ᾰς', 'buck78' }, -- 104.8		{ 'AP', '$ᾰνς', { 'kre', 'arg' } },		{ 'AP', '$αις', 'les' },		{ 'AP', '$αιρ', 'ele' }, }) end

local function dial_forms_first_oxy(args) dial_form_multi(args, {			{ 'DP', '$ῇσῐ(ν)/$ῇς/$αῖς' },			{ 'GD', '$αῖ(ῐ)ν/$ῇῐν' },			{ 'GP', '$ᾱ́ων/$έ͜ων/$ῶν' },		},		'epi') dial_form_multi(args, {		{ 'DS', '$η', 'boi' }, -- 104.3		{ 'DS', '$αι', { 'ara', 'ele' } },		{ 'DS', '$ᾱ', { 'the', 'les' } },

{ 'GP', '$έων/$ῶν', 'ion' }, -- 104.6 { 'GP', '$ᾶν', 'nonIA' }, { 'GP', '$ᾱ́ων', 'boi' },

{ 'DP', '$ῃσῐ(ν)', 'ion' }, -- 104.7, ato must be dealt with separately { 'DP', '$αισῐ(ν)', 'les' }, { 'DP', '$ᾶσῐ(ν)', 'ato' },

{ 'AP', '$ᾰς', 'buck78' }, -- 104.8 { 'AP', '$ᾰνς', { 'kre', 'arg' } }, { 'AP', '$αις', 'les' }, { 'AP', '$αιρ', 'ele' },

{ 'GD', '$αίαιρ', 'ele' }, }) end

export.inflections['1st-alp'] = function(args) local suffix = accent_switch(args.accent.term, '', '_con', '_pax', nil, args.suffix) args.ctable = deepcopy(m_paradigms['alp' .. suffix]) if args.accent.term == 'oxytone' then dial_forms_first_oxy(args) else if args.adjective then args.ctable['GP'] = '$ων' end if args.accent.term ~= 'perispomenon' then dial_forms_first(args) end end end

--[=[	Only difference from "1st-alp-pax" and "1st-eta-pax" is that because of the "-prx", Module:grc-decl/decl doesn't shift the accent to the end of the stem in all forms. Used only in 1st-and-2nd-declension adjectives. ]=] -- export.inflections['1st-alp-prx'] = export.inflections['1st-alp-pax']

-- export.inflections['1st-eta-prx'] = export.inflections['1st-eta-pax']

export.inflections['1st-eta'] = function(args) local suffix = accent_switch(args.accent.term, '', '_con', '_pax', nil, args.suffix) args.ctable = deepcopy(m_paradigms['eta' .. suffix]) if args.accent.term == 'oxytone' then dial_form(args, 'DP', '$ῆσῐ(ν)', 'ato') -- Assuming this applies for perispomenon as well as oxytone. dial_forms_first_oxy(args) elseif args.accent.term ~= 'perispomenon' then if args.adjective then args.ctable['GP'] = '$ων' end dial_form(args, 'DP', '$ησῐ(ν)', 'ato') dial_forms_first(args) end end

-- Always recessive, except in adjectives or derivatives of them. local function short_alpha(code) return function(args) if code == 'als' then -- Ionic and Epic have eta, not alpha, in all forms except the -- nominative and accusative singular. if args.dial == 'ion' or args.dial == 'epi' then mw.logObject(args, 'args') short_alpha('ets')(args) return end elseif code ~= 'ets' then error('Invalid code ' .. tostring(code)) end local accent_on_ultima = args.adjective and '_prx' or nil local suffix = accent_switch(args.accent.term,			accent_on_ultima, accent_on_ultima, '_prx',			'First-declension feminine nouns with nominative singular in ' ..				'short alpha must have recessive accent.', args.suffix) args.ctable = deepcopy(m_paradigms[code .. suffix]) dial_forms_first(args) if code == 'als' then dial_form(args, 'DP', '$ᾱσῐ(ν)', 'ato') else dial_form(args, 'DP', '$ησῐ(ν)', 'ato') end end end

export.inflections['1st-als'] = short_alpha('als')

export.inflections['1st-ets'] = short_alpha('ets')

export.inflections['1st-M-alp'] = function(args) local suffix = accent_switch(args.accent.term, nil, '_con', '_pax',		'Oxytone masculine first declension not supported.', args.suffix) args.ctable = deepcopy(m_paradigms['M_alp' .. suffix]) if args.accent.term ~= 'perispomenon' then dial_forms_first(args) dial_form_multi(args, {			{ 'GS', '$ᾱο/$ε͜ω/$ω', 'epi' },			{ 'GS', '$εω/$ω', 'ion' },			{ 'GS', '$ᾱ', 'nonIA' },			{ 'GS', '$ᾱο', 'boi' },			{ 'GS', '$ᾱυ', 'ark' }, }) end end

export.inflections['1st-M-eta'] = function(args) local suffix = accent_switch(args.accent.term, '', '_con', '_pax', nil, args.suffix) args.ctable = deepcopy(m_paradigms['M_eta' .. suffix]) -- ἰδιώτης, genitive singular ἰδιώτεω, not *ἰδιωτέω, -- at least in Herodotus 1.123. if args.dial == 'ion' or args.dial == 'epi' then args.synaeresis = true end if args.accent.term == 'oxytone' then dial_forms_first_oxy(args) dial_form_multi(args, {			{ 'GS', '$ᾶο/$έ͜ω/$ῶ', 'epi' },			{ 'GS', '$έω/$ῶ', 'ion' },			{ 'GS', '$ᾶ', 'nonIA' },			{ 'GS', '$ᾶο', 'boi' },			{ 'GS', '$ᾶυ', 'ark' }, }) elseif args.accent.term ~= 'perispomenon' then dial_forms_first(args) dial_form_multi(args, {			{ 'GS', '$ᾱο/$ε͜ω/$ω', 'epi' },			{ 'GS', '$εω/$ω', 'ion' },			{ 'GS', '$ᾱ', 'nonIA' },			{ 'GS', '$ᾱο', 'boi' },			{ 'GS', '$ᾱυ', 'ark' }, }) end if args['voc'] == 'α' or usub(args.stem, -1) == 'τ' then args.ctable['VS'] = '$ᾰ' end end

local function dial_forms_second(args) dial_form_multi(args, {			{ 'GS', '$ου/$οῖο/$οιο/$όο/$οο' },			{ 'GD', '$οιῐν' },			{ 'DP', '$οισῐ(ν)/$οις' },		},		'epi') dial_form_multi(args, {		{ 'GS', '$οιο', 'dor' },		{ 'GS', '$οι', 'the' }, -- 106.1		{ 'GS', '$ω', 'severe', 'boi' },		{ 'GS', '$ων', 'kyp' },		{ 'DS', '$ω', 'les' }, -- 106.2		{ 'DS', '$ου', 'the' },		{ 'DS', '$οι', { 'ele', 'boi' } },		{ 'DS', '$οι', { 'ara', 'eub' } },		{ 'DP', '$οισῐ(ν)/$οις', { 'ato', 'ion' } }, -- 106.4		{ 'DP', '$οισῐ(ν)', 'les' },		{ 'AP', '$ως', 'severe' }, -- 106.5		{ 'AP', '$ος', 'buck78' },		{ 'AP', '$ονς', { 'kre', 'arg' } },		{ 'AP', '$οις', 'les' },		{ 'AP', '$οιρ', 'ele' },		{ 'GD', '$οίοιρ', 'ele' }, -- 106.6		{ 'ND', '$ου', 'the' }, -- 23		{ 'GP', '$ουν', 'the' }, }) end

local function dial_forms_second_oxy(args) dial_form_multi(args, {			{ 'GS', '$οῦ/$οῖο/$όο' },			{ 'GD', '$οῖῐν' },			{ 'DP', '$οῖσῐ(ν)/$οῖς' },		},		'epi') dial_form_multi(args, {		{ 'GS', '$οῖο', 'dor' },		{ 'GS', '$οῖ', 'the' }, -- 106.1		{ 'GS', '$ῶ', 'severe', 'boi' },		{ 'GS', '$ῶν', 'kyp' },		{ 'DS', '$ω', 'les' }, -- 106.2		{ 'DS', '$οῦ', 'the' },		{ 'DS', '$οῖ', { 'ele', 'boi' } },		{ 'DS', '$οῖ', { 'ara', 'eub' } },		{ 'DP', '$οῖσῐ(ν)/$οῖς', { 'ato', 'ion' } }, -- 106.4		{ 'DP', '$οισῐ(ν)', 'les' },		{ 'AP', '$ώς', 'severe' }, -- 106.5		{ 'AP', '$ός', 'buck78' },		{ 'AP', '$όνς', { 'kre', 'arg' } },		{ 'AP', '$οίς', 'les' },		{ 'AP', '$οίρ', 'ele' },		{ 'GD', '$οίοιρ', 'ele' }, -- 106.6		{ 'ND', '$ού', 'the' }, -- 23		{ 'GP', '$οῦν', 'the' }, }) end

-- For nouns like λόγος and ἔργον. local function second_basic(gender) return function(args) local suffix = accent_switch(args.accent.term, '', nil, '_prx',			'Perispomenon basic second-declension nouns not supported.', args.suffix) args.ctable = deepcopy(m_paradigms['second' .. (gender or '') .. suffix]) if args.accent.term == 'oxytone' then dial_forms_second_oxy(args) else dial_forms_second(args) end end end

export.inflections['2nd'] = second_basic

export.inflections['2nd-N'] = second_basic('_N')

local function second_contracted(gender) return function(args) local suffix = accent_switch(args.accent.term, nil, '', '_pax',			'Oxytone contracted second-declension nouns are not supported.', args.suffix) if gender == '_N' and suffix == '_pax' then error('Paroxytone contracted neuter second-declension nouns are not supported') end args.ctable = deepcopy(m_paradigms['second' .. (gender or '') .. '_con' .. suffix]) end end

export.inflections['2nd-con'] = second_contracted

export.inflections['2nd-N-con'] = second_contracted('_N', true)

local function second_Attic(gender) return function(args) local suffix = accent_switch(args.accent.term, '', '_con', '_prx', nil, args.suffix) if gender == '_N' and suffix == '_con' then error('Perispomenon Attic declension neuter nouns are not supported.') end args.force_antepenult = true args.ctable = deepcopy(m_paradigms['second' .. (gender or '') .. '_att' .. suffix]) end end

export.inflections['2nd-att'] = second_Attic

export.inflections['2nd-N-att'] = second_Attic('_N')

--	In order:		- vowel before ντ at end of stem, or declension category		- masculine nominative singular ending		- neuter nominative singular ending		- segment preceding ῐ in dative plural local nt = { ['ο'] = { 'ων', 'ον', 'ουσ' },			-- ἔχων (ἔχω) ['1&3-ουντ'] = { 'ους', 'ον', 'ουσ' },	-- δούς (δίδωμι) ['ου'] = { 'ων', 'ουν', 'ουσ' },		-- ποιῶν (ποιέω), δηλῶν (δηλόω) ['ε'] = { 'εις', 'εν', 'εισ' },			-- θείς (τίθημι), ἀχθείς (ἄγω) ['ω'] = { 'ων', 'ων', 'ωσ' },			-- ζῶν (ζάω) }

-- Get nominative singular and dative plural (minus ῐ(ν)) for ντ-stems. local function handle_nt(base, decl_type, gender, is_neuter, is_neuter_noun, is_adjective, arg1, arg2) local NS, DP	local m_data = mw.loadData('Module:grc-utilities/data') base = to_NFD(base) -- Here we must match α, ε, ο, υ, ω, or ου (with any number of	-- diacritics) followed by ντ. local whole_match, vowel, diacritic = umatch(base,		'((ου)(' .. m_data.combining_diacritic .. '*)ντ)$') if not whole_match then whole_match, vowel, diacritic = umatch(base,			'(([αεουω])(' .. m_data.combining_diacritic .. '*)ντ)$') end if not whole_match then error('Something is wrong with the stem ' .. base .. '.') end local nom_base = base:gsub(whole_match, '') -- Declension type has priority over vowel because δούς (δοντ-) and -- λαβών (λαβόντ-) have the same stem vowel, but different masculine -- nominative singulars. local data = nt[decl_type] or nt[vowel] if data then if is_adjective then NS = nom_base .. (is_neuter and data[2] or data[1]) end DP = nom_base .. data[3] else local macron, breve = m_data.diacritics.macron, m_data.diacritics.breve if diacritic == macron or diacritic == breve or diacritic == '' then if vowel then local intermediate_base = nom_base .. vowel DP = intermediate_base .. macron .. 'σ' if is_adjective then if is_neuter then NS = intermediate_base .. breve .. 'ν' else NS = intermediate_base .. macron .. 'ς' end end else error('Failed to generate nominative singular and dative plural for ' ..					quote(arg1) .. ', ' .. quote(arg2) .. '.') end else error('Invalid diacritic ' ..				(type(diacritic) == 'string' and string.format("U+%X", get_codepoint(diacritic)) or tostring(diacritic)) ..				') in the stem ' .. base .. '.')		end	end	if not adjective and not gender[1] then		gender[1] = 'M'		gender.M = true	end	return NS, DP end local finals = {	['β'] = 'ψ',	['γ'] = 'ξ',	['κ'] = 'ξ',	['κτ'] = 'ξ',	['π'] = 'ψ',	['φ'] = 'ψ',	['χ'] = 'ξ',	--	['τ'] = ,	['δ'] = ,	['θ'] = ,	-- }

local function new_gender(gender) return { gender, [gender] = true } end

-- is_neuter: boolean -- accent_alternating: boolean local function third_nom(args, is_neuter, accent_alternating) -- strings local arg1, arg2, base = args[1], args[2], to_NFC(args.stem) local ctable = args.ctable -- output local NS, DS, AS, DP = ctable.NS, ctable.DS, ctable.AS, ctable.DP	-- boolean local adjective = args.adjective -- tables local gender, notes = args.gender, args.notes --	local notes = {		labial = 'Nominative singular ' ..			mention('-ψ') ..			(('φβ'):find(last1) and ' is a neutralization of ' or ' is a respelling of ') ..			mention(last1) ..			' + the nominative singular suffix ' ..			mention('-ς') .. '.',		velar_dental = 'Nominative singular ' ..			mention('-ξ') ..			' is a neutralization of ' ..			mention(last2) ..			' + the nominative singular suffix ' ..			mention('-ς') .. '.',		'Nominative singular ' ..			mention('-ξ') ..			(umatch('χγ', last1) and ' is a neutralization of ' or ' is a respelling of ') ..			mention(last1) ..			' + the nominative singular suffix ' ..			mention('-ς') .. '.'	}	-- local identifying_ending local chars, char2 = umatch(base, '(.(.))$') -- '[πβφκγχρνσω]$', '[κν]τ$', '[τδθ]' if chars == 'ντ' or chars == 'κτ' then identifying_ending = chars else identifying_ending = char2 end local NS_ending = finals[identifying_ending] if NS_ending then NS = base:gsub(identifying_ending .. "$", NS_ending) DP = NS	end if not (NS or DP) then local decl_type = args.decl_type local last1, last2 = usub(base, -1), usub(base, -2) local nom_base = usub(base, 1, -2) local is_neuter_noun = is_neuter and not adjective if identifying_ending == 'ντ' then -- May also add gender. NS, DP = handle_nt(base, decl_type, gender, is_neuter,				is_neuter_noun, adjective, arg1, arg2) elseif ('τδθ'):find(identifying_ending) then DP = nom_base .. 'σ' if not adjective then if usub(base, -3) == 'τητ' or ('δθ'):find(last1) then if not gender[1] then gender = new_gender('F') end elseif last2 == 'ητ' or last2 == 'ωτ' then if not gender[1] then gender = new_gender('M') end elseif last2 == 'ᾰτ' or last2 == 'ᾱτ' then if not gender[1] then gender = new_gender('N') end end end if is_neuter then if last2 == 'οτ' then NS = nom_base .. 'ς' else NS = nom_base end else if last2 == 'οτ' then NS = base:gsub('οτ', 'ως') else NS = nom_base .. 'ς' end end if arg1:find('ς$') then table.insert(notes,					'Nominative singular ' ..							mention('-ς') ..							' arose by reduction of the original cluster ' ..							proto_mention(dental_lookup[last1]) .. '.') end elseif ('ρν'):find(identifying_ending) then local vowel = usub(base, -2, -2) if last1 == 'ρ' then DP = base .. 'σ' else DP = nom_base .. 'σ' end if is_neuter then NS = base elseif vowel == 'ε' then NS = usub(base, 1, -3) .. 'η' .. last1 elseif vowel == 'ο' then NS = usub(base, 1, -3) .. 'ω' .. last1 elseif vowel == 'ῑ' then --ῥίς etc. NS = nom_base .. 'ς' elseif (vowel == 'ᾰ' and gender[1] ~= 'N') then NS = usub(base, 1, -3) .. 'ᾱς' else NS = base end local last3 = usub(base, -3) if last3 == 'γον' or last3 == 'δον' then gender[1] = gender[1] or 'F'			elseif ufind(last2, '[ᾰᾱα]ρ') then gender[1] = gender[1] or 'N'			else gender[1] = gender[1] or 'M'			end elseif identifying_ending == 'σ' then DP = base if is_neuter_noun then NS = nom_base .. 'ς' else NS = usub(base, 1, -3) .. 'ης' end DS = '$ῐ̈' elseif identifying_ending == 'ω' then -- m_paradigms.lp_prx.NS is nil. Is the condition correct? if NS == m_paradigms.lp_prx.NS then DS = nom_base .. 'ῳ/$ῐ̈' AS = '$/$ᾰ' else DS = '$ῐ̈́' AS = '$/$ᾰ́' end DP = nom_base .. 'ωσ' NS = nom_base .. 'ως' gender[1] = gender[1] or 'M'		else error('Stem does not end in a consonant: ' .. base) end end -- This overrides any assignment done above. Better to improve the code -- above or prevent it from assigning NS. if not adjective then NS = arg1 end if DP then if accent_alternating then DP = DP .. 'ῐ́(ν)' else DP = DP .. 'ῐ(ν)' end end ctable.DS, ctable.AS = DS, AS	ctable.NS, ctable.DP = NS, DP	args.gender = gender end

local function dial_forms_third(args) if not args.ctable.DP then require('Module:debug').track('grc-decl/no dative plural') mw.log("no DP: " .. args[1] .. ", " .. args[2]) end dial_form_multi(args, {			{ 'DP', args.ctable['DP'] and args.ctable['DP'] .. '/$εσσῐ(ν)/$εσῐ(ν)' or '$εσσῐ(ν)/$εσῐ(ν)' },			{ 'GD', '$οιῐν' },		},		'epi') dial_form_multi(args, {		{ 'DP', '$εσσῐ(ν)', 'dor' },		{ 'AS', '$ᾰν', 'kyp' },		{ 'DP', '$εσσῐ(ν)', { 'les', 'the' } },		{ 'DP', '$εσσῐ(ν)', 'boi' },		{ 'DP', '$οις', { 'lok', 'ele' } },		{ 'AP', '$ες', { 'ark', 'ele' } },		{ 'AP', '$ᾰς/$ᾰνς', 'kre' }, }) end

local function dial_forms_third_oxy(args) dial_form_multi(args, {			{ 'GD', '$οῖῐν' },			{ 'DP', args.ctable['DP'] and args.ctable['DP'] .. '/$εσσῐ(ν)/$εσῐ(ν)' or '$εσσῐ(ν)/$εσῐ(ν)' },		},		'epi') dial_form_multi(args, {		{ 'DP', '$εσσῐ(ν)', 'dor' },		{ 'AS', '$ᾰν', 'kyp' },		{ 'DP', '$εσσῐ(ν)', { 'les', 'the' } },		{ 'DP', '$εσσῐ(ν)', 'boi' },		{ 'DP', '$οῖς', { 'lok', 'ele' } },		{ 'AP', '$ες', { 'ark', 'ele' } },		{ 'AP', '$ᾰς/$ᾰνς', 'kre' }, }) end

-- For instance, μείζων. local function third_comparative(args, neuter) local short_stem, count = args.stem:gsub('ον$', '') if count ~= 1 then error('Stem failure.') end if neuter then dial_form(args, 'NP', '$ᾰ/' .. short_stem .. 'ω', 'att') else dial_form_multi(args, {				{ 'AS', '$ᾰ/' .. short_stem .. 'ω'},				{ 'NP', '$ες/' .. short_stem .. 'ους' },				{ 'AP', '$ᾰς/' .. short_stem .. 'ους' },			}, 'att') end end

-- These nouns are monosyllabic, but unlike most they do not accent the ending -- of the genitive–dative dual and genitive plural: παίδων, not *παιδῶν. local monosyllabic_exceptions = { ['παῖς'] = true, ['δμώς'] = true, ['θώς'] = true, ['Τρώς'] = true, ['δᾴς'] = true, ['φῶς'] = true, ['οὖς'] = true, } -- Other exceptions: contracted forms like ἔαρος > ἦρος (not *ἠρός). -- The source for this is Smyth § 252. local function third(neuter) return function (args) if args.decl_type:find('ντ$') and m_accent.syllables(args[1], 'eq', 1) then -- Special:WhatLinksHere/Template:tracking/grc-decl/monosyllabic nt require('Module:debug').track('grc-decl/monosyllabic nt') end -- This tracks monosyllabic nouns or adjectives that have alternating accent -- position. Masculine and neuter participles (with stems in -ντ) and -- suffixes do not. local accent_alternating = not (args.suffix or args.stem:find('ντ$')) and m_accent.syllables(args[1], 'eq', 1) args.accent_alternating = accent_alternating local accent_on_ultima = accent_alternating and '' or '_prx' local suffix = accent_switch(args.accent.term, accent_on_ultima, accent_on_ultima, '_prx', nil, args.suffix) args.ctable = deepcopy(m_paradigms[(neuter and 'N_' or '') .. 'lp' .. suffix]) if not (args.NS and args.DP) then third_nom(args, neuter, accent_alternating) end if args.comparative then third_comparative(args, neuter) end if not neuter then local last_two = usub(args.stem, -2) if last_two == 'ῐδ' or last_two == 'ῐτ' or last_two == 'ῑθ' then if args.accent.term ~= 'oxytone' then dial_form(args, 'AS', args.ctable['AS'], 'epi', 'ion') -- i.e. -χάριν; also poetic args.ctable['AS'] = args['AS'] or usub(args.stem, 1, -2) .. 'ν' end args.ctable['VS'] = args['VS'] or usub(args.stem, 1, -2) elseif last_two == 'ντ' and (args.decl_type == '1&3-εσσ' or not args.adjective) then args.ctable['VS'] = args['VS'] or usub(args.stem, 1, -2) elseif args.accent.term ~= 'oxytone' and args.accent.term ~= 'perispomenon' and ufind(args.stem, '[ρν]$') then args.ctable['VS'] = args['VS'] or args.stem -- What's an example of this? elseif usub(args.stem, -1) == 'ε' then args.ctable['VS'] = args['VS'] or args.stem .. 'ς' end if args.accent.term == 'perispomenon' then args.ctable['NS'] = args[1] end end if accent_alternating then dial_forms_third_oxy(args) if monosyllabic_exceptions[to_NFC(args[1])] then -- Remove accent marks: that is, make the form be accented on the -- stem. args.ctable.GD = m_accent.strip_tone(args.ctable.GD) args.ctable.GP = m_accent.strip_tone(args.ctable.GP) end else dial_forms_third(args) end end end

export.inflections['3rd-cons'] = third(false) export.inflections['3rd-N-cons'] = third(true)

local function dial_forms_es(args, neuter) dial_form_multi(args, {		{ 'GS', '$εος', { 'nonIA' } },		{ 'GS', '$ιος', 'buck9' },		{ 'GS', '$εος/$ευς', { 'ion', 'epi' } },		{ 'DS', '$ει/$εῐ̈', { 'epi', 'ion' } },		{ 'ND', '$ει/$εε', { 'ion', 'epi' } },		{ 'GD', '$έοιν', { 'nonIA', 'ion' } },		{ 'GD', '$ίοιν', 'buck9' },		{ 'NP', neuter and '$εᾰ' or '$εις/$εες', { 'ion', 'epi' } },		{ 'GP', '$έων', { 'nonIA', 'ion', 'epi' } },		{ 'GP', '$ίων', 'buck9' }, }) if not neuter then dial_form_multi(args, {			{ 'AS', '$εᾰ', { 'nonIA', 'ion', 'epi' } },			{ 'AP', '$εᾰς', { 'nonIA', 'ion', 'epi' } },			{ 'AP', '$ιᾰς', 'buck9' }, }) end end

local function dial_forms_es_oxy(args, neuter) dial_form_multi(args, {		{ 'GS', '$έος', 'nonIA' },		{ 'GS', '$ίος', 'buck9' },		{ 'GS', '$έος/$εῦς', { 'ion', 'epi' } },		{ 'DS', '$εῖ/$έῐ̈', { 'epi', 'ion' } },		{ 'ND', '$εῖ/$έε', { 'ion', 'epi' } },		{ 'GD', '$έοιν', { 'nonIA', 'ion' } },		{ 'GD', '$ίοιν', 'buck9' },		{ 'NP', neuter and '$έᾰ' or '$εῖς/$έες', { 'ion', 'epi' } },		{ 'GP', '$έων', { 'nonIA', 'ion', 'epi' } },		{ 'GP', '$ίων', 'buck9' }, }) if not neuter then dial_form_multi(args, {			{ 'AS', '$έᾰ', { 'nonIA', 'ion', 'epi' } },			{ 'AS', '$ίᾰ', 'buck9' },			{ 'AP', '$έᾰς', { 'nonIA', 'ion', 'epi' } },			{ 'AP', '$ίᾰς', 'buck9' }, }) end end

-- Adjectives with these endings have persistent accent (Smyth 292c): -- εὐώδης, εὐῶδες. local persistent_es = { ['ώδης'] = true, ['ώλης'] = true, ['ώρης'] = true, ['ήρης'] = true, }

-- How to deal with τριήρων, not *τριηρῶν (Smyth 264)? local function es_adj(gender_code, open) return function(args) uncontracted_error(args.contracted or not open, args.dial, '-ης') local suffix = accent_switch(args.accent.term, '', nil, '_prx',			'Perispomenon third-declension forms in -ης not supported.', args.suffix) args.ctable = deepcopy(m_paradigms[(gender_code or ) .. 'es_adj' ..			suffix .. (open and '_open' or )]) -- Most adjectives of this type have recessive accent. Set accent to -- antepenult. if not args.suffix and not persistent_es[to_NFC(usub(args[1], -4))] then args.accent.position = -3 end if args.accent.term == 'oxytone' then dial_forms_es_oxy(args, gender_code == 'N_') else dial_forms_es(args, gender_code == 'N_') end if gender_code ~= 'N_' then dial_form(args, 'NS', '$εῖς', 'boi', 'the') end end end

export.inflections['3rd-εσ'] = es_adj

export.inflections['3rd-N-εσ'] = es_adj('N_')

export.inflections['3rd-εσ-open'] = es_adj(nil, true)

export.inflections['3rd-N-εσ-open'] = es_adj('N_', true)

local function neuter_os(open) return function(args) nonrecessive_error(args.accent.term,			'Third-declension neuter nouns in -ος must be accented recessively') uncontracted_error(args.contracted or not open, args.dial, '-ος') args.ctable = deepcopy(m_paradigms['N_es_prx' .. (open and '_open' or '')]) dial_forms_es(args, true) end end

export.inflections['3rd-N-ος'] = neuter_os

export.inflections['3rd-N-ος-open'] = neuter_os(true)

local function neuter_as(open) return function(args) nonrecessive_error(args.accent.term,			'Third-declension neuter nouns in -ας must be accented recessively') uncontracted_error(args.contracted or not open, args.dial, '-ᾰς') args.ctable = deepcopy(m_paradigms['N_as_prx' .. (open and '_open' or '')]) end end

export.inflections['3rd-N-ᾰσ'] = neuter_as

export.inflections['3rd-N-ᾰσ-open'] = neuter_as(true)

local function kles(open) return function(args) local dialect = args.dial uncontracted_error(args.contracted or not open, dialect, '-κλης') if dialect == 'ion' or dialect == 'epi' then open = true end args.ctable = deepcopy(m_paradigms['kles' .. (open and '_open' or '')]) args.number = { 'S', S = true } args.recessive_VS = true if open then dial_form_multi(args, {					{ 'GS', '$κλῆος/$κλέος' },					{ 'DS', '$κλῆῐ̈/$κλέῐ̈' },					{ 'AS', '$κλῆᾰ/$κλέᾱ' },				},				{ 'epi', 'ion' }) else dial_form_multi(args, {				{ 'GS', '$κλέος', 'nonIA' },				{ 'GS', '$κλεῖος', 'boi' }, }) end end end export.inflections['3rd-κλῆς'] = kles

export.inflections['3rd-κλῆς-open'] = kles(true)

-- Needs dialectal forms. local function weak_i(gender_code) return function(args) nonrecessive_error(args.accent.term,			'Third-declension nouns with stem in short ῐ must be accented recessively.') args.ctable = deepcopy(m_paradigms[(gender_code or '') .. 'weak_i_prx']) args.synaeresis = true -- Or Ionic or both? dial_form_multi(args, {				{ 'DS', '$ει/$εῐ̈' },				{ 'ND', '$ει/$εε' },				{ 'NP', '$εις/$εες' },			},			'epi') end end

export.inflections['3rd-weak-ι'] = weak_i

export.inflections['3rd-N-weak-ι'] = weak_i('N_')

local function dial_forms_weak_u(args, neuter) dial_form_multi(args, {		{ 'GS', '$έος', { 'epi', 'ion' } },		{ 'GD', '$έοιῐν', 'epi' },		{ 'DP', '$έεσσῐ(ν)/$έεσῐ(ν)/$εσῐ(ν)', 'epi' },		{ 'DP', '$έεσσῐ(ν)', 'dor' }}) if args.adjective then args.ctable['GS'] = '$έος' args.ctable['ND'] = '$έε' end if not neuter then dial_form_multi(args, {			{ 'NP', '$έες', 'epi' }, -- What about nonIA and ion?			{ 'AP', '$έᾰς', { 'nonIA', 'ion', 'epi' } }, }) end end

local function dial_forms_weak_u_prx(args, neuter) dial_form_multi(args, {		{ 'GS', '$εος', { 'epi', 'ion' } },		{ 'GD', '$έοιῐν', 'epi' },		{ 'DP', '$έεσσῐ(ν)/$έεσῐ(ν)/$εσῐ(ν)', 'epi' },		{ 'DP', '$έεσσῐ(ν)', 'dor' }, }) if args.adjective then args.ctable['GS'] = '$εος' args.ctable['ND'] = '$εε' args.ctable['GP'] = '$έων' end if not neuter then dial_form_multi(args, {			{ 'NP', '$εες' },			{ 'AP', '$εᾰς' },		}, 'epi') end end

local function weak_u (gender) return function(args) local suffix = accent_switch(args.accent.term, '', nil, '_prx', nil, args.suffix) args.ctable = deepcopy(m_paradigms[(gender or '') .. 'weak_u' .. suffix]) if not args.adjective then args.synaeresis = true end local neuter = gender == 'N_' if args.accent.term == 'oxytone' then dial_forms_weak_u(args, neuter) else dial_forms_weak_u_prx(args, neuter) end end end

export.inflections['3rd-weak-υ'] = weak_u

export.inflections['3rd-N-weak-υ'] = weak_u('N_')

export.inflections['3rd-pure-ι'] = function(args) nonrecessive_error("Nouns in -ῐς cannot be accented on the ultima") args.ctable = deepcopy(m_paradigms.pure_i_prx) dial_form_multi(args, {			{ 'GS', '$ῐος/$ηος' },			{ 'DS', '$ῐῐ/$ῑ/$ηῐ̈/$ει' },			{ 'GD', '$ῐ́οιῐν' },			{ 'NP', '$ῐες/$ηες' },			{ 'DP', '$ῐ́εσσῐ(ν)/$εσῐ(ν)/$ῐσῐ(ν)' },			{ 'AP', '$ῐᾰς/$ηᾰς/$ῑς' },		},		'epi') dial_form(args, 'DP', '$ῐ́εσσῐ(ν)', 'dor') end

export.inflections['3rd-N-pure-ι-prx'] = function(args) args.ctable = deepcopy(m_paradigms.N_pure_i_prx) end export.inflections['3rd-N-pure-ι-pax'] = export.inflections['3rd-N-pure-ι-prx']

local function pure_u_short(gender_code) return function(args) -- No error message needed. local suffix = accent_switch(args.accent.term, '', nil, '_prx', nil, args.suffix) if gender_code == 'N_' and args.accent.term == 'oxytone' then error('Neuter nouns in short -ῠ must be accented recessively.') end args.ctable = deepcopy(m_paradigms[(gender_code or '') .. 'pure_u' .. suffix]) dial_form_multi(args, {				{ 'GD', '$ῠ́οιῐν' },				{ 'DP', '$ῠ́εσσῐ(ν)/$ῠσῐ(ν)/$ῠσσῐ(ν)' },			},			'epi') dial_form(args, 'DP', '$ῠ́εσσῐ(ν)', 'dor') end end export.inflections['3rd-pure-υ'] = pure_u_short

export.inflections['3rd-N-pure-υ'] = pure_u_short('N_')

export.inflections['3rd-pure-υ-long'] = function(args) local suffix = accent_switch(args.accent.term, '', '_con', '_prx', nil, args.suffix) args.ctable = deepcopy(m_paradigms['pure_u_long' .. suffix]) dial_form(args, 'DP', '$ῠ́εσσῐ(ν)', 'dor') dial_form_multi(args, {			{ 'DP', accent_switch(args.accent.term, '$ῠ́εσσῐ(ν)/$ῠσῐ(ν)/$ῠσσῐ(ν)', '$ῠ́εσσῐ(ν)', '$ῠ́εσσῐ(ν)/$ῡσῐ(ν)/$ῡσσῐ(ν)', nil, args.suffix) },			{ 'GD', '$ῠ́οιῐν' },		},		'epi') end

local function third_eus(contracted) return function(args) -- Maybe only Attic actually? local dialect = args.dial if contracted and not (dialect == 'att' or dialect == 'koi' or dialect == 'byz') then error('Only Attic, Koine, or Byzantine Greek have contracted declined forms for nouns in -ευς.') end if dialect == 'kyp' or dialect == 'boi' then args.ctable = deepcopy(m_paradigms.eus_hwos) elseif dialect == 'les' or dialect == 'epi' then args.ctable = deepcopy(m_paradigms.eus_hos) dial_form_multi(args, {					{ 'GS', '$ῆος/$έος' },					{ 'DS', '$ῆῐ̈/$έῐ̈' },					{ 'AS', '$ῆᾰ/$έᾰ' },					{ 'GD', '$ήοιῐν' },					{ 'DP', '$ήεσσῐ(ν)/$εῦσῐ(ν)' },				},				'epi') elseif dialect == 'the' or dialect == 'ele' then args.ctable = deepcopy(m_paradigms.eus_eios) else if contracted then args.ctable = deepcopy(m_paradigms.eus_con) table.insert(args.titleapp, 'contracted') else args.ctable = deepcopy(m_paradigms.eus) end dial_form_multi(args, {				{ 'DP', '$έεσσῐ(ν)', 'dor' }, -- this is somewhat conjectured				{ 'GS', '$έος', { 'nonIA', 'ion' } },				{ 'DS', '$εῖ', 'att' },				{ 'AS', '$έᾰ', { 'nonIA', 'ion' } },				{ 'AS', '$ῆ', { 'doric', 'del' } },				{ 'AS', '$έᾰ', { 'lok', 'kre' } },				{ 'NP', '$έες/$εῖς', 'ion' },				{ 'NP', '$εῖς', 'nonIA' },				{ 'NP', '$ῆς', { 'koa', 'lak' } },				{ 'NP', '$ῆς', 'ara' },				{ 'NP', '$έες', 'kre' },				{ 'NP', '$εῖς', 'late' },				{ 'AP', '$έᾰς', { 'nonIA', 'ion' } },				{ 'NS', '$ής', 'ara' },				{ 'AS', '$ήν', 'ara' }, }) --				Contraction only for nouns with vowel before -ευς. local diacritics = mw.loadData('Module:grc-utilities/data').diacritics local macron, breve = diacritics.macron, diacritics.breve if ufind(args.stem, '[αεηιουω][' .. macron .. breve .. ']?$') then dial_form_multi(args, {						{ 'GS', '$έως/$ῶς' },						{ 'AS', '$έᾱ/$ᾶ' },						{ 'GP', '$έων/$ῶν' },						{ 'AP', '$έᾱς/$ᾶς' },					},					'att') table.insert(args.notes, 'The first form is uncontracted, the second contracted.') elseif contracted then error('Forms with a stem ending in ' ..						require('Module:grc-utilities').tag(usub(args.stem, -1)) ..						' do not have contracted forms.') end end end end

export.inflections['3rd-ευς'] = third_eus(false)

export.inflections['3rd-ευς-con'] = third_eus(true)

export.inflections['3rd-οι'] = function(args) args.ctable = deepcopy(m_paradigms.oi) args.number = { 'S', S = true } dial_form_multi(args, {		{ 'GS', '$ῶς', 'sever' },		{ 'AS', '$οῦν', 'ion' }, }) end

-- irregular masculine or feminine nouns export.inflections['irreg'] = function(args) local params = m_decl_static_data.irregular.noun.masculine_feminine if args.gender.N then return export.inflections['irregN'](args) end local noun = not args.adjective -- Would DP (dual–plural) ever be used? local number = args.number local param_code if number.F then param_code = 'full' elseif number.S then if number.P then param_code = 'SP' else param_code = 'S'		end elseif number.D then if number.P then param_code = 'DP' else param_code = 'D'		end elseif number.P then param_code = 'P'	else error('Could not decide which table of forms to use.') end local forms = params[param_code] args.declheader = 'irreg' local ctable = {} local found_forms = false for i = 2, args.maxindex do		local code = forms[i] local arg1 = ine(args[i]) if code then local arg2 = ine(args[code]) if arg1 and arg2 then error('Two forms specified for ' .. code .. ': ' .. arg1 .. ' and ' .. arg2 '.') end local number_code = code:sub(2, 2) if arg1 or arg2 then if number[number_code] then found_forms = true else error('The number ' .. number_code .. ' is not specified in the form parameter.') end end ctable[code] = arg1 or arg2 elseif arg1 then local abbr = { S = 'singular', D = 'dual', P = 'plural', }			local numbers = require('Module:table').serialCommaJoin(require('Module:fun').map(function(code) return abbr[code] or code end, number),				{ dontTag = true }) local singular = not number[2] error('Parameter ' .. i .. ' has been given, but only ' .. #forms ..				' parameters are needed because the number' .. (singular and '' or 's') ..				' specified in the form parameter ' .. (singular and 'is ' or 'are ') ..				 numbers .. '.') end end if not found_forms then error('No displayable forms found.') end args.ctable = ctable end

-- irregular neuter nouns export.inflections['irregN'] = function(args) --neuter irregular nouns local params = m_decl_static_data.irregular.noun.neuter local number = args.number local param_code if number.F then param_code = 'full' elseif number.P then if number.S then param_code = 'SP' elseif number.D then param_code = 'DP' else param_code = 'P'		end elseif number.D then param_code = 'D'	elseif number.S then param_code = 'S'	else error('Could not decide which table of forms to use.') end local forms = params[param_code] local ctable = {} for i = 2, args.maxindex do		local code = forms[i] local arg1 = args[i] if code then local arg2 = args[code] if arg1 and arg2 then error('Two forms given for form ' .. code .. ': ' .. arg1 ..					' in parameter ' .. i .. ' and ' .. arg2 ..					' in parameter ' .. code ..					'. Choose one or put both in the same parameter separated by slashes.') end ctable[code] = arg1 or arg2 elseif arg1 then error('Parameter ' .. i .. ', ' .. arg1 .. ', does not have a case and number assigned to it.') end end for form, source in pairs(forms.redirects) do		ctable[form] = args[form] or ctable[source] end args.ctable = ctable end

-- irregular adjectives export.inflections['irreg-adj'] = function(args) local params = m_decl_static_data.irregular.adjective local number = args.number local param_code if number.F then param_code = 'full' elseif number.P then if number.S then param_code = 'SP' else param_code = 'P'		end elseif number.S then param_code = 'S'	else error('Could not decide which table of forms to use.') end local forms = params[param_code] local atable = {} for i = 2, args.maxindex do		local code = forms[i] local arg1 = ine(args[i]) if code then local arg2 = ine(args[code]) if arg1 and arg2 then error('Two forms given for form ' .. code .. ': ' .. arg1 ..					' in parameter ' .. i .. ' and ' .. arg2 ..					' in parameter ' .. code ..					'. Choose one or put both in the same parameter separated by slashes.') end atable[code] = arg1 or arg2 else if arg1 then error('No gender, case, and number assigned to parameter ' ..						i .. ': ' .. tostring(arg1) .. '. Only ' ..						#forms .. ' parameters are needed.') end end end for form, source in pairs(forms.redirects) do		atable[form] = args[form] or atable[source] end if number.D then for target_case, source_case in pairs { A = 'N', V = 'N', D = 'G' } do			for _, gender in ipairs { 'M', 'F', 'N' } do local target = gender .. target_case .. 'D' atable[target] = args[target] or atable[target] or atable[gender .. source_case .. 'D'] local target = gender .. 'VP' atable[target] = args[target] or atable[target] or atable[gender .. 'NP'] end end end args.atable = atable end

export.inflections['indecl'] = function(args) args.ctable = deepcopy(m_paradigms.indecl) args.stem = { args[2] } end

return export