Module:grc-decl

Definition from Wiktionary, the free dictionary
Jump to: navigation, search

This module is the backend to {{grc-decl}} and {{grc-adecl}}.

Submodules[edit]

Module:grc-decl/decl contains functions that determine the declension class, generate the inflected forms, and retrieves the correct forms of the article.

Module:grc-decl/table generates the table using the inflected forms, the forms of the article (if any), and the dialect and |titleapp= parameters.

Module:grc-decl/params contains the lists of parameters used by {{grc-decl}} and {{grc-adecl}}.

Module:grc-decl/decl/data contains functions that return the forms of a given declension type, modifying the raw paradigms or the stems as necessary.

Module:grc-decl/decl/staticdata contains the data used to determine the declension class based on the nominative and genitive (for nouns) or the masculine and feminine or neuter (for adjectives).

Module:grc-decl/decl/staticdata/paradigms contains raw paradigms for declension classes, as well as any variations with a different accent on the ending.

Module:grc-decl/decl/staticdata/dialects contains data for dialect groups.

Testcases[edit]


local export = {}

local module_path = 'Module:grc-decl'

local m_grc_decl_table = require(module_path .. '/table')
local m_grc_decl_decl = require(module_path .. '/decl')
local m_params = mw.loadData(module_path .. "/params")

local function check_track_arg(argI, arg)
	require('libraryUtil').checkType("track", argI, arg, "string")
end

local function track(template, code)
	check_track_arg(1, template)
	if code then
		check_track_arg(2, code)
		require("Module:debug").track(template .. "/" .. code)
	else
		return function(code)
			check_track_arg(1, code)
			require("Module:debug").track(template .. "/" .. code)
		end
	end
end

local function handle_unrecognized_args(unrecognized_args, adjective)
	local track = track(adjective and 'grc-adecl' or 'grc-decl')
	
	-- Next returns nil if table is empty.
	if next(unrecognized_args) then
		track("unrecognized args")
		
		local unrecognized_list = require("Module:table").keysToList(unrecognized_args)
		
		local agreement = ""
		if #unrecognized_list > 1 then
			agreement = "s"
		end
		
		mw.log("unrecognized arg" .. agreement .. ": " .. table.concat(unrecognized_list, ", ") ..
				"; see Module:grc-decl/params for a full list of recognized args")
	end
end

local function swap_args(args, suffix)
	--This function has undefined behavior if both <arg> and <arg><suffix> are
	--specified; use e.g. <arg>1 and <arg>2 instead.
	local args_ = args
	args = {}
	for code, value in pairs(args_) do
		if type(code) == 'number' then
			args[code] = value
		else
			-- Removes suffix from the end of string keys.
			args[mw.ustring.gsub(code, suffix .. '$', '')] = value
		end
	end
end

local function get_gender_number(form_param, is_adjective)
	local new_form = mw.ustring.gsub(form_param, '[SDP]', { S = '-sing', D = '-dual', P = '-plur' })
	if not new_form:match('full') and
			not new_form:match('sing') and
			not new_form:match('dual') and
			not new_form:match('plur') then
		new_form = new_form .. '-full'
	end
	--[[
		Returns tables containing all genders and numbers.
		For instance, for nouns that are variably masculine or feminine:
			args.gender		{ "M", "F", ["M"] = true, ["F"] = true }
			args.number		{ "S", "D", "P", ["S"] = true, ["D"] = true, ["P"] = true }
		Not sure if the sequential entries are needed.
	]]
	local modified_form = new_form:gsub("full", "SDP")
	
	-- Convert sing, dual, plur to S, D, P.
	modified_form = modified_form:gsub('(%l)%l+', mw.ustring.upper)
	-- Remove non-uppercase characters
	modified_form = modified_form:gsub('%U', '')
	
	-- Find contiguous gender abbreviations.
	local genders = modified_form:match("[MFN]+")
	
	if is_adjective and genders then
		error("Adjectives cannot have gender specified in the form parameter.")
	end
	
	-- Find contiguous number abbreviations.
	local numbers = modified_form:match("[SDP]+")
	
	if genders then
		genders = mw.text.split(genders, "")
		for i, gender in pairs(genders) do
			if gender == "" then
				genders[i] = nil
			elseif type(gender) == "string" then
				genders[gender] = true
			end
		end
		if genders.N and ( genders.M or genders.F ) then
			error("A noun cannot be neuter and another gender at the same time.")
		end
	else
		genders = {}
	end
	if numbers then
		numbers = mw.text.split(numbers, "")
		for i, number in pairs(numbers) do
			if number == "" then
				numbers[i] = nil
			elseif type(number) == "string" then
				numbers[number] = true
			end
		end
		if numbers.S and numbers.D and numbers.P then numbers.F = true end
	else
		numbers = {}
	end
	
	return new_form, genders, numbers
end

--[=[
	Need to check if the chosen dialect actually has forms defined for it.
	
	[[Special:WhatLinksHere/Template:tracking/grc-decl/dialect alias]]
	[[Special:WhatLinksHere/Template:tracking/grc-decl/hom to epi]]
	
	Tracking for particular dialects:
	[[Special:WhatLinksHere/Template:tracking/grc-decl/dial/att]]
	[[Special:WhatLinksHere/Template:tracking/grc-decl/dial/ion]]
	[[Special:WhatLinksHere/Template:tracking/grc-decl/dial/epi]]
	...
]=]
local function handle_dialect(dialect, adjective)
	local track = track(adjective and 'grc-adecl' or 'grc-decl')
	
	if not dialect then
		track('no dialect')
		return nil
	end
	
	local m_dialects = require("Module:grc:Dialects")
	local alias_of = m_dialects.aliases[dialect]
	if alias_of then
		track('dialect alias')
		dialect = alias_of
	end
	
	if dialect == 'hom' then
		track('hom to epi')
		dialect = 'epi'
	end
	
	track('dial/' .. dialect)
	
	return dialect
end

local function handle_unmarked_length(arg1, arg2, adjective)
	old_arg1, old_arg2 = arg1, arg2
	if arg2 and arg2 then
		local m_accent = require("Module:grc-accent")
		local standard_diacritics = require("Module:grc-utilities").standardDiacritics
		if arg1 == 'irreg' or arg1 == 'indecl' then
			arg2 = m_accent.mark_implied_length(standard_diacritics(arg2))
		else
			arg1, arg2 = m_accent.harmonize_length(standard_diacritics(arg1), standard_diacritics(arg2))
		end
	end
	
	local track = track(adjective and 'grc-adecl' or 'grc-decl')
	
	--[=[
	[[Special:WhatLinksHere/Template:tracking/grc-decl/length marked on arg1]]
	[[Special:WhatLinksHere/Template:tracking/grc-decl/length marked on arg2]]
	[[Special:WhatLinksHere/Template:tracking/grc-adecl/length marked on arg1]]
	[[Special:WhatLinksHere/Template:tracking/grc-adecl/length marked on arg2]]
	]=]
	if old_arg1 and arg1 ~= mw.ustring.toNFD(old_arg1) then
		track('length marked on arg1')
	end
	
	if old_arg2 and arg2 ~= mw.ustring.toNFD(old_arg2) then
		track('length marked on arg2')
	end
	
	return arg1, arg2
end

local function get_noun_args(args)
	local params = m_params.noun_params
	
	if args[1] == 'irreg' then
		if args.form:match('N') then
			params = m_params.irreg_N_noun_params
		else
			params = m_params.irreg_noun_params
		end
	end
	
	local args, unrecognized_args = require("Module:parameters").process(args, params, true)
	
	args.adjective = false
	
	handle_unrecognized_args(unrecognized_args, args.adjective)
	args[1], args[2] = handle_unmarked_length(args[1], args[2], args.adjective)
	args.dial = handle_dialect(args.dial, args.adjective)
	args.form, args.gender, args.number = get_gender_number(args.form, args.adjective)
	
	args.categories = {}
	return args
end

local function get_adj_args(args)
	local params = m_params.adj_params
	
	if args[1] == 'irreg' then
		params = m_params.irreg_adj_params
	end
	
	local args, unrecognized_args = require("Module:parameters").process(args, params, true)
	
	args.adjective = true
	
	if args.hp then
		track('grc-adecl', 'hp')
	end
	handle_unrecognized_args(unrecognized_args, args.adjective)
	args[1], args[2] = handle_unmarked_length(args[1], args[2], args.adjective)
	args.dial = handle_dialect(args.dial, args.adjective)
	args.form, args.gender, args.number = get_gender_number(args.form, args.adjective)
	
	args.atable, args.categories = {}, {}
	args.atable.adv, args.atable.comp, args.atable.super = nil, nil, nil
	return args
end

local function process_args(args)
	local track = track(args.adjective and 'grc-adecl' or 'grc-decl')
	
	--[=[
	[[Special:WhatLinksHere/Template:tracking/grc-decl/manual-breve]]
	[[Special:WhatLinksHere/Template:tracking/grc-decl/dial]]
	[[Special:WhatLinksHere/Template:tracking/grc-decl/dialtilde]]
	[[Special:WhatLinksHere/Template:tracking/grc-decl/titleapp]]
	[[Special:WhatLinksHere/Template:tracking/grc-adecl/manual-breve]]
	[[Special:WhatLinksHere/Template:tracking/grc-adecl/dial]]
	[[Special:WhatLinksHere/Template:tracking/grc-adecl/dialtilde]]
	[[Special:WhatLinksHere/Template:tracking/grc-adecl/titleapp]]
	]=]
	
	if mw.ustring.find(args.root, '˘') then
		track('manual-breve')
	end
	if args.dial then
		track('dial')
	end
	if args.dial and args.dial:match('~') then
		track('dialtilde')
		args.dial = nil
	end
	if args.titleapp then
		track('titleapp')
	end
	
	args.form_cache = {}
	
	for _, v in ipairs({ 'titleapp', 'titleapp1', 'titleapp2' }) do
		if args[v] then
			args[v] = mw.text.split(args[v], '%s*[/,]%s*')
		else
			args[v] = {}
		end
	end
	
	for _, v in ipairs({ 'notes', 'notes1', 'notes2' }) do
		if args[v] then
			args['user_' .. v] = args[v] --convert 'notes' to 'user_notes'
			args[v] = {}
		else
			args[v] = {}
		end
	end
end

--[=[
-- This function is an entry point for testing noun functionality only
-- ]=]
function export.test_decl(frame)
	local args = get_noun_args(frame)
	m_grc_decl_decl.get_decl(args)
	process_args(args)
	m_grc_decl_decl.make_decl(args, args.form:match('open') and args.decl_type .. '-open' or args.decl_type , args.root)
	return args
end


local function uncontracted_condition(args)
	return args.dial == 'ion' or args.dial == 'epi' or args.dial ~= 'att' and not args.form:match('con')
end

local function contracted_condition(args)
	return args.dial ~= 'ion' and args.dial ~= 'epi' and not args.form:match('open')
end

function export.decl(frame)
	local args = get_noun_args(frame:getParent().args)
	m_grc_decl_decl.get_decl(args)
	process_args(args)
	
	if mw.ustring.sub(args.root, 1, 1) == '-' and not args.form:match('[MFN]') then
		args.form = args.form .. 'X'
	end
	if mw.ustring.match(args.decl_type, '2nd') and not mw.ustring.match(args.decl_type, 'N') and not args.form:match('[MFN]') then
		table.insert(args.categories, 'Ancient Greek second-declension nouns without gender specified')
	end
	
	if mw.ustring.match(args.decl_type, 'κλῆς') or mw.ustring.match(args.decl_type, '[ᾰε]σ') then
		local out = {}
		
		if uncontracted_condition(args) then
			args.titleapp = {}
			swap_args(args, 1)
			table.insert(args.titleapp, 'uncontracted')
			m_grc_decl_decl.make_decl(args, mw.ustring.match(args.decl_type, 'κλῆς') and args.decl_type or args.decl_type .. '-open', args.root)
			args.article = m_grc_decl_decl.infl_art(args)
			table.insert(out, m_grc_decl_table.make_table(args))
		end
		
		if contracted_condition(args) then
			args.titleapp = {}
			swap_args(args, 2)
			table.insert(args.titleapp, '[[Appendix:Ancient Greek contraction|contracted]]')
			m_grc_decl_decl.make_decl(args, args.decl_type, args.root)
			args.article = m_grc_decl_decl.infl_art(args)
			
			table.insert(out, m_grc_decl_table.make_table(args))
		end
		return table.concat(out, '\n')
	else
		m_grc_decl_decl.make_decl(args, args.decl_type, args.root)
		args.article = m_grc_decl_decl.infl_art(args)
		return m_grc_decl_table.make_table(args)
	end
end

--[=[
-- This function is an entry point for testing adjective functionality only
-- ]=]
function export.test_adecl(frame)
	local args = get_adj_args(frame)
	m_grc_decl_decl.get_decl_adj(args)
	process_args(args)
	args.act = m_grc_decl_decl.adjinflections[args.decl_type]
	m_grc_decl_decl.make_decl_adj(args, m_grc_decl_decl.adjinflections[args.decl_type])
	return args
end

function export.adecl(frame)
	local args = get_adj_args(frame:getParent().args)
	m_grc_decl_decl.get_decl_adj(args)
	process_args(args)
	
	if m_grc_decl_decl.adjinflections_con[args.decl_type] then
		local out = {}
		
		if uncontracted_condition(args) then
			args.titleapp, args.notes, args.categories = {}, {}, {}
			swap_args(args, 1)
			table.insert(args.titleapp, 'uncontracted')
			
			args.act = m_grc_decl_decl.adjinflections[args.decl_type]
			m_grc_decl_decl.make_decl_adj(args, m_grc_decl_decl.adjinflections[args.decl_type])
			table.insert(out, m_grc_decl_table.make_table_adj(args))
		end
		
		if contracted_condition(args) then
			args.titleapp, args.notes, args.categories = {}, {}, {}
			swap_args(args, 2)
			
			table.insert(args.titleapp, '[[Appendix:Ancient Greek contraction|contracted]]')
			
			args.act = m_grc_decl_decl.adjinflections_con[args.decl_type]
			m_grc_decl_decl.make_decl_adj(args, m_grc_decl_decl.adjinflections_con[args.decl_type])
			table.insert(out, m_grc_decl_table.make_table_adj(args))
		end
		return table.concat(out, '\n')
	else
		args.act = m_grc_decl_decl.adjinflections[args.decl_type]
		m_grc_decl_decl.make_decl_adj(args, m_grc_decl_decl.adjinflections[args.decl_type])
		return m_grc_decl_table.make_table_adj(args)
	end
end


local function tag(text)
	local lang = require("Module:languages").getByCode("grc")
	return require("Module:script utilities").tag_text(text, lang)
end

function export.show_noun_forms(frame)
	local args = get_noun_args(frame.args[1] and frame.args or frame:getParent().args)
	m_grc_decl_decl.get_decl(args)
	process_args(args)
	
	m_grc_decl_decl.make_decl(args, args.decl_type, args.root)
	
	-- mw.logObject(args)
	
	local inflections = args.ctable
	
	local cases = { "N", "A", "V", "G", "D" }
	local numbers = { "S", "D", "P" }
	
	local out = { "\n* " .. tag(args[1]) .. ", " .. tag(args[2]) }
	for i, number in pairs(numbers) do
		table.insert(out, "\n** ")
		local number_forms = {}
		
		for j, case in pairs(cases) do
			local code = case .. number
			local form = inflections[code]
			
			if form then
				table.insert(number_forms, tag(form))
			end
		end
		
		number_forms = table.concat(number_forms, ", ")
		
		table.insert(out, number_forms)
	end
	
	return table.concat(out)
end

function export.show_adj_forms(frame)
	local args = get_adj_args(frame.args[1] and frame.args or frame:getParent().args)
	m_grc_decl_decl.get_decl_adj(args)
	process_args(args)
	
	args.act = m_grc_decl_decl.adjinflections[args.decl_type]
	m_grc_decl_decl.make_decl_adj(args, m_grc_decl_decl.adjinflections[args.decl_type])
	
	-- mw.logObject(args)
	
	local function print(key, value)
		return key .. " = " .. "'" .. value .. "', "
	end
	
	local inflections = args.atable
	
	local genders = { "M", "F", "N" }
	local numbers = { "S", "D", "P" }
	local cases = { "N", "A", "V", "G", "D" }
	
	local out = {}
	
	table.insert(out, "{ '" .. args[1] .. "'")
	if args[2] then
		table.insert(out, ", '" .. args[2] .. "'")
	end
	table.insert(out, " },\n{")
	
	for _, gender in pairs(genders) do
		table.insert(out, "\n\t")
		for _, number in pairs(numbers) do
			for _, case in pairs(cases) do
				local code = gender .. case .. number
				local form = inflections[code]
				
				if form then
					table.insert(out, print(code, form))
				end
			end
		end
	end
	
	table.insert(out, "\n\t")
	
	local forms = { "adv", "comp", "super" }
	for _, form in pairs(forms) do
		if inflections[form] then
			table.insert(out, print(form, inflections[form]))
		end
	end
	
	table.insert(out, "\n},")
	
	return frame:extensionTag{ content = table.concat(out), name = "source", args = { lang = "lua" } }
end

return export