Module:ckb-conj/sandbox

From Wiktionary, the free dictionary
Jump to navigation Jump to search

Sandbox version of Module:ckb-conj. Test using {{ckb-conj-trans/sandbox}} and {{ckb-conj-intrans/sandbox}}


local export = {}

local transliterate = require 'Module:ckb-translit'.tr

-- Auto-create subtables in "forms" for different parts of conjugation table
-- (simple past, present, imperative, etc.).
-- Each subtable contains up to six person-number forms.
local forms = setmetatable({}, {
	__index = function (self, key)
		if type(key) == "string" then
			local prefix = key:match("^%l+")
			if prefix == "ps" or prefix == "pr" or prefix == "impr" then
				local val = {}
				self[key] = val
				return val
			end
		end
	end,
})

-- Defines the order of person-number forms in the affixes supplied to add_affixes,
-- and the keys that are used in the table returned by add_affixes.
local person_number_combinations = { "1s", "2s", "3s", "1p", "2p", "3p" }

-- Adds a suffix (or prefix) or list of suffixes (or prefixes)
-- to a stem or set of stems for one or more person-number forms (to_what)
-- using a function (add_affix)
-- and returns a new set of forms.
	
local function add_affixes(to_what, affix, add_affix)
	local new_forms = {}
	
	local affix_is_table = type(affix) == 'table'
	
	-- If to_what consists of lowercase letters and _, it is the name of a subtable in "forms".
	if to_what:find('^[%l_]+$') then
		to_what = forms[to_what]
			or error("Field " .. to_what .. " not found in forms table.")
	-- Both to_what and affix are strings. They can just be concatenated.
	elseif not affix_is_table then
		error("No point using add_affixes to add unchangeable affix to unchangeable stem.")
	end
	local to_what_is_table = type(to_what) == "table"
	
	if not affix then
		error("affix is missing.") -- to_what already checked above.
	end
	
	local i = 0
	for _, person_number in ipairs(person_number_combinations) do
		i = i + 1
		local stem = not to_what_is_table and to_what or to_what[person_number]
		local affix = not affix_is_table and affix or affix[i]
		if stem and affix then
			new_forms[person_number] = add_affix(stem, affix)
		end
	end
	
	return new_forms
end

local function concat(a, b) return a .. b end
local function reverse_concat(a, b) return b .. a end

local function add_prefixes(to_what, prefix)
	local add_prefix = reverse_concat
	return add_affixes(to_what, prefix, add_prefix)
end

local function add_suffixes(to_what, suffix, use_suff_function)
	local add_suffix = use_suff_function and export.suf or concat
	return add_affixes(to_what, suffix, add_suffix)
end

function export.main(frame)
	local PAGENAME = mw.title.getCurrentTitle().text
	local NAMESPACE = mw.title.getCurrentTitle().nsText
	
	local verb_type = frame.args["type"]
		or error('No value passed to the "type" parameter')
	
	local params = {
		["pr-stem"] = {},
		[1] = { alias_of = "pr-stem" },
		["infinitive"] = { default = PAGENAME },
		[2] = { alias_of = "infinitive" },
		["ps-stem"] = {},
		["suf"] = { default = "" },
	}
	local args, unrecognized_args =
		require "Module:parameters".process(frame:getParent().args, params, true)
	
	if next(unrecognized_args) then
		mw.log("Unrecognized args: "
			.. table.concat(require "Module:table".keysToList(unrecognized_args), ", "))
	end

	local infinitive = args["infinitive"]
	local ps_stem = args["ps-stem"] or mw.ustring.sub(infinitive, 1, -2)
	local pr_stem = args["pr-stem"]
	local suf = args["suf"]
	
	local pr_active_participle_nosuf = export.suf(ps_stem, 'وو')
	local pr_active_participle = pr_active_participle_nosuf .. suf
	
	local i = ''; if not export.isVowelStem(ps_stem) then i = 'ِ' end
	local ps_stem_i = ps_stem .. i

	forms["infinitive"] = infinitive
	forms["ps_stem"] = ps_stem
	forms["pr_stem"] = pr_stem

	if verb_type == "intransitive" then
		-- simple past
		forms["ps"] = add_suffixes(ps_stem, { 'ِم', 'یت', '', 'ین', 'ِن' }, true)

		-- past habitual
		forms["ps_impf"] = add_prefixes("ps", 'دە')

		-- present perfect
		forms["pr_pf"] = add_suffixes(pr_active_participle_nosuf,
			{ 'ِم', 'یت', '', 'ین', 'ِن' }, true)
		forms["pr_pf"] = add_suffixes("pr_pf", 'ە')

		if suf and suf ~= "" then
			forms["pr_pf"]["3s"] = forms["pr_pf"]["3s"] .. 'ت'
			forms["pr_pf"] = add_suffixes("pr_pf", suf)
		end

		-- past perfect
		forms["ps_pf"] = add_suffixes(ps_stem_i, { 'بووم', 'بوویت', 'بوو', 'بووین', 'بوون' })

		-- past subjunctive
		-- TODO: add forms for other dialects
		forms["ps_subj"] = add_suffixes(ps_stem_i, { 'بِم', 'بیت', 'بێت', 'بین', 'بِن' })

	elseif verb_type == "transitive" then
		-- simple past
		forms["ps"] = add_suffixes(ps_stem, { 'ِم', 'ِت', 'ی', 'مان', 'تان', 'یان' }, true)

		-- past habitual
		forms["ps_impf"] = add_prefixes(ps_stem, { 'دەم', 'دەت', 'دەی', 'دەمان', 'دەتان', 'دەیان' })

		-- present perfect
		forms["pr_pf"] = add_suffixes(pr_active_participle_nosuf,
			{ 'ِم', 'ِت', 'ی', 'مان', 'تان', 'یان' }, true)

		forms["pr_pf"] = add_suffixes("pr_pf", 'ە' .. suf)

		-- past perfect
		forms["ps_pf"] = add_suffixes(ps_stem_i, { 'بووم', 'بووت', 'بووی', 'بوومان', 'بووتان', 'بوویان' })

		-- past subjunctive
		forms["ps_subj"] = add_suffixes(ps_stem_i,
			{ 'بێتِم', 'بێتِت', 'بێتی', 'بێتمان', 'بێتتان', 'بێتیان' }, true)
		forms["ps_subj"] = add_suffixes("ps_subj", suf)
	else
		error('Indicate verb type (pass "transitive" or "intransitive" to the '
			.. '"type" parameter)')
	end

	-- past progressive
	forms["ps_prog"] = add_prefixes("ps_impf",
		{ 'خەریک بووم ', 'خەریک بووی ', 'خەریک بوو ', 'خەریک بووین ', 'خەریک بوون ', 'خەریک بوون ' })
	-- 3p, 'خەریک بوون ', will only be displayed in table for transitive verb.

	forms["pr"] = add_suffixes(pr_stem, { 'ِم', 'یت', 'ێت', 'ین', 'ِن' }, true)

	-- present subjunctive
	-- TODO: ب (bi) should be omitted in some compound verbs, optional in others
	forms["pr_subj"] = add_prefixes("pr", 'بِ')
	forms["pr_subj"] = add_suffixes("pr_subj", suf, true)

	-- present
	-- TODO: ئە (a) for Sulaymani dialect
	forms["pr"] = add_prefixes("pr", 'دە')
	forms["pr"] = add_suffixes("pr", suf, true)

	-- present progressive
	forms["pr_prog"] = add_prefixes("pr", { 'خەریکِم ', 'خەریکی ', 'خەریکە ', 'خەریکین ', 'خەریکِن ' })

	-- imperative
	forms["impr"] = add_suffixes(pr_stem, { nil, nil, nil, 'ین', 'ِن' }, true)
	if mw.ustring.sub(ps_stem, -2) == 'وو' then
		forms["impr"]["2s"] = pr_stem .. 'ۆ'
	elseif mw.ustring.sub(infinitive, -3) == 'ردن' then
		forms["impr"]["2s"] = pr_stem
	else
		forms["impr"]["2s"] = export.suf(pr_stem, 'ە')
	end

	forms["impr"] = add_prefixes("impr", 'بِ')

	-- it is sometimes unpredictable
	if args["2s-impr"] then forms["impr"]["2s"] = args["2s-impr"] end

	-- TODO: conditional mood
	
	local function pronouns(mood)
		local attributes = ('class="ku-Arab pronoun mood" lang="ckb"')
			:gsub('mood', mood)
		
		return ([[
! attributes | من
! attributes | تۆ
! attributes | ئەو
! attributes | ئێمە
! attributes | ئێوە
! attributes | ئەوان
]]):gsub('attributes', attributes)
	end

	local text = [=[<div class="NavFrame ckb-conj">
<div class="NavHead">Conjugation</div>
<div class="NavContent">
{| class="inflection-table"
|-
! class="nonfinite-header" | infinitive
| {{{infinitive}}}
! class="nonfinite-header" | past stem
| {{{ps_stem}}}
! class="nonfinite-header" | present stem
| {{{pr_stem}}}
|-
! rowspan="2" class="person-header" | person
! colspan="3" class="number-header" | singular
! colspan="3" class="number-header" | plural
|-
! class="person-header" | first
! class="person-header" | second
! class="person-header" | third
! class="person-header" | first
! class="person-header" | second
! class="person-header" | third
|-
! class="indicative" | indicative
]=]
.. pronouns('indicative') .. [=[
|-
! class="indicative" | simple <br /> past
| {{{1s_ps}}} || {{{2s_ps}}} || {{{3s_ps}}}
| {{{1p_ps}}} || {{{2p_ps}}} || {{{3p_ps}}}
|-
! class="indicative" | present
| {{{1s_pr}}} || {{{2s_pr}}} || {{{3s_pr}}}
| {{{1p_pr}}} || colspan="2" | {{{2p_pr}}}
|-
! class="indicative" | past <br /> imperfect <small>(habitual, progressive)</small>
| {{{1s_ps_impf}}} || {{{2s_ps_impf}}} || {{{3s_ps_impf}}}
| {{{1p_ps_impf}}} || {{{2p_ps_impf}}} || {{{3p_ps_impf}}}
|-
! class="indicative" | past <br /> progressive
| {{{1s_ps_prog}}} || {{{2s_ps_prog}}} || {{{3s_ps_prog}}}
| {{{1p_ps_prog}}} || {{{2p_ps_prog}}} || {{{3p_ps_prog}}}
|-
! class="indicative" | present <br /> progressive
| {{{1s_pr_prog}}} || {{{2s_pr_prog}}} || {{{3s_pr_prog}}}
| {{{1p_pr_prog}}} || colspan="2" | {{{2p_pr_prog}}}
|-
! class="indicative" | past <br /> perfect
| {{{1s_ps_pf}}} || {{{2s_ps_pf}}} || {{{3s_ps_pf}}}
| {{{1p_ps_pf}}} || {{{2p_ps_pf}}} || {{{3p_ps_pf}}}
|-
! class="indicative" | present <br /> perfect
| {{{1s_pr_pf}}} || {{{2s_pr_pf}}} || {{{3s_pr_pf}}}
| {{{1p_pr_pf}}} || {{{2p_pr_pf}}} || {{{3p_pr_pf}}}
|-
! class="subjunctive" | subjunctive
]=]
.. pronouns('subjunctive') .. [=[
|-
! class="subjunctive" | past
| {{{1s_ps_subj}}} || {{{2s_ps_subj}}} || {{{3s_ps_subj}}}
| {{{1p_ps_subj}}} || {{{2p_ps_subj}}} || {{{3p_ps_subj}}}
|-
! class="subjunctive" | present
| {{{1s_pr_subj}}} || {{{2s_pr_subj}}} || {{{3s_pr_subj}}}
| {{{1p_pr_subj}}} || colspan="2" | {{{2p_pr_subj}}}
|-
! rowspan="2" class="imperative" | imperative
! class="pronoun imperative" | —
! class="ku-Arab pronoun imperative" lang="ckb" | تۆ
! class="pronoun imperative" | —
! class="ku-Arab pronoun imperative" lang="ckb" | ئێمە
! class="ku-Arab pronoun imperative" lang="ckb" | ئێوە
! class="pronoun imperative" | —
|-
| || {{{2s_impr}}} ||
| {{{1p_impr}}} || {{{2p_impr}}} ||
|}
</div>
</div>
]=]

	if verb_type == 'intransitive' then
		text = text:gsub('| {{{(2p_(p[^}]+))}}} || {{{3p_p[^}]+}}}',
			function (first_code, suffix)
				if suffix == 'ps' or suffix == 'ps_impf' or suffix == 'ps_prog'
						or suffix == 'ps_pf' or suffix == 'pr_pf'
						or suffix == 'ps_subj' then
					return ('| colspan="2" | {{{%s}}}'):format(first_code)
				end
			end)
	end
	
	text = text:gsub('{{{([^}]+)}}}', export.link)
	
	return text .. mw.getCurrentFrame():extensionTag{
		name = "templatestyles", args = { src = "Module:ckb-conj/style.css" }
	}
end

function export.suf(word, suf)
	local last_letter = mw.ustring.sub(word, -1)

	if export.isVowelStem(word) then
		if suf == 'ِم' then
			return word .. 'م'
		elseif suf == 'ِت' then
			return word .. 'ت'
		elseif suf == 'ێت' then
			if last_letter == 'ە' then
				return mw.ustring.sub(word, 1, -2) .. 'ات'
			elseif last_letter == 'ۆ' then
				return mw.ustring.sub(word, 1, -2) .. 'ات'
			elseif last_letter == 'ێ' then
				return word .. 'ت'
			else
				return word .. 'ێت'
			end
		elseif suf == 'ین' then
			return word .. 'ین'
		elseif suf == 'ِن' then
			return word .. 'ن'
		elseif suf == 'وو' and mw.ustring.sub(word, -2) ~= 'وو' then
			return word .. 'و'
		end
	end
	
	return word .. suf
end

export.isVowelStem = require "Module:fun".memoize(function (word)
	local last_letter = mw.ustring.sub(word, -1)

	return last_letter == 'ا' or last_letter == 'ی' -- later
			or last_letter == 'و' -- later
			or last_letter == 'ێ' or last_letter == 'ۆ' or last_letter == 'ە'
end)

function export.link(form_code)
	-- Parse a code such as 1s_ps into 1s and ps, and then retrieve forms["ps"]["1s"].
	local number_person, tense_aspect_mood = form_code:match("^(%d%l)_(.+)$")
	local form
	if number_person and tense_aspect_mood then
		form = forms[tense_aspect_mood] and forms[tense_aspect_mood][number_person]
	else
		form = forms[form_code]
	end
	
	if not form then
		mw.log('Form ' .. form_code .. ' for ' .. tostring(forms.infinitive)
			.. ' not found.')
		return ''
	end
	
	local auto_tr = transliterate(form)
	
	return '<span class="ku-Arab" lang="ckb">[[' .. form .. '#Central Kurdish|'
		.. form .. ']]</span><br /><span lang="">' .. auto_tr .. '</span>'
end

return export