Module:tr-verb

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

-- WIP

local export = {}

local lang = require("Module:languages").getByCode("tr")
local m_links = require("Module:links")
local m_string_utilities = require("Module:string utilities")
local m_harmony = require("Module:tr-harmony")


local function escape_pattern(text)
    return text:gsub("([^%w])", "%%%1")
end

local function parts(str, separator)
    local pattern = "([^" .. escape_pattern(separator) .. "]*)"
	local unprocessed_start = 1
	return function ()
	    if unprocessed_start >= str:len() then return nil end
		local _, match_end, match = str:find(pattern, unprocessed_start)
		unprocessed_start = match_end + 2
		return match
	end
end

local function split(str, separator)
	local array = {}
	for part in parts(str, separator) do
		table.insert(array, part)
	end
	return array
end

function concat(tbl1, tbl2)
	local result = {}
	for i = 1, #tbl1 do
		result[#result + 1] = tbl1[i]
	end
	for i = 1, #tbl2 do
		result[#result + 1] = tbl2[i]
	end
	return result
end

-- Adapted from [[Module:tr-harmony]], TODO: perhaps merge back?
-- Special characters:
--   >   Preceeding consonant is softened if followed by a vowel
--   <   Preceeding vowel is deleted
function export.harmonize(underlying, aorist_vowel)
	local surface = ""
	
	underlying = mw.ustring.gsub(underlying, "[" .. m_harmony.vowels .. "]<", "")
	underlying = mw.ustring.gsub(underlying, "<", "")
	
	local previous_char = nil
	local previous_vowel = "i" -- for yiyor and diyor
	local soften = false
	
	local function add(c)
		if c == mw.ustring.upper(c) then
			error("unrecognized placeholder '" .. c .. "'")
		end
		
		if m_harmony.is_vowel(c) then
			if soften then
				surface = m_harmony.soften(surface)
			end
			previous_vowel = c
		end
		surface = surface .. c
		previous_char = c
		soften = false
	end
	
	for c in mw.ustring.gcodepoint(underlying) do
		c = mw.ustring.char(c)

		if c == "R" then -- aorist R
			if m_harmony.is_consonant(previous_char) then add(aorist_vowel) end
			add("r")
		elseif c == "Y" or c == "N" or c == "S" then -- intervocalic Y, N, S
			if m_harmony.is_vowel(previous_char) then add(string.lower(c)) end
		elseif c == "J" then -- interconsonantal I
			if m_harmony.is_consonant(previous_char) then add(m_harmony.get_4_way_harmony(previous_vowel)) end
		elseif c == "D" then -- d/t
			add(m_harmony.is_voiceless_consonant(previous_char) and "t" or "d")
		elseif c == "A" then -- 2-way
			add(m_harmony.get_2_way_harmony(previous_vowel))
		elseif c == "I" then -- 4-way
			add(m_harmony.get_4_way_harmony(previous_vowel))
		elseif c == ">" then -- consonant softening
			if m_harmony.is_consonant(previous_char) then soften = true end
		else
			add(c)
		end
	end
	
	return surface
end

local function guess_softness(stem_last_word)
	return stem_last_word == "git" or stem_last_word == "tat" or stem_last_word:find("et$")
end

local function guess_aorist_vowel(stem_last_word, soft)
	local monosyllabic = not stem_last_word:find("[" .. m_harmony.vowels .. "][^" .. m_harmony.vowels .. "]+[" .. m_harmony.vowels .. "]")
	local harmony
	if monosyllabic then
		if stem_last_word == "al" or stem_last_word == "bil" or stem_last_word == "bul" or stem_last_word == "den" or stem_last_word == "dur" or stem_last_word == "gel" or stem_last_word == "gör" or stem_last_word == "kal" or stem_last_word == "ol" or stem_last_word == "öl" or stem_last_word == "san" or stem_last_word == "var" or stem_last_word == "ver" or stem_last_word == "vur" or stem_last_word == "yen" then
			-- Exceptional monosyllabic 4-way harmony
			harmony = m_harmony.get_4_way_harmony
		else
			-- Regular monosyllabic 2-way harmony
			harmony = m_harmony.get_2_way_harmony
		end
	else
		if soft and stem_last_word:find("et$") then
			-- Exceptional polysyllabic 2-way harmony
			harmony = m_harmony.get_2_way_harmony
		else
			-- Regular polysyllabic 4-way harmony
			harmony = m_harmony.get_4_way_harmony
		end
	end
	return harmony(m_harmony.get_last_vowel(stem_last_word))
end

function export.is_includable_form(inflections)
	return true -- TODO
end

function export.get_link_generating_callback(tbl)
	return function (term, inflections)
		local accel = nil
		if export.is_includable_form(inflections) then
			accel = { form = "verb form" }
		end
		table[table.concat(inflections, "|")] = m_links.full_link({ term = term, lang = lang, accel = accel })
	end
end

function export.get_form_collecting_callback(tbl)
	return function (term, inflections)
		if export.is_includable_form(inflections) then
			table[term] = inflections
		end
	end
end

local function generate_form(form, inflections, aorist_vowel, callback)
	-- TODO: sort inflections
	local surface = export.harmonize(form, aorist_vowel)
	callback(surface, inflections)
end

local function prepend(base_form, base_inflections, tbl)
	local result = {}
	for form, inflections in pairs(tbl) do
		result[base_form .. form] = concat(base_inflections, inflections)
	end
	return result
end

function export.generate_forms(stem, aorist_vowel, callback)
	local function g(form, inflections, form_2, inflections_2)
		return generate_form(form .. form_2, concat(inflections, inflections_2), aorist_vowel, callback)
	end
	for form, inflections in pairs(prepend(stem, {}, { [""] = {}, ["mA"] = { "neg" } })) do -- polarity
		g(form, inflections, "mAk", { "inf" })
		-- TODO
	end
end

function export.format(template_args)
   	local params = {
		[1] = {},
		["soft"] = { type = "boolean" }, -- Whether softening of the stem occurs (usually deduced)
		["aorist"] = { type = "string" }, -- The aorist vowel (usually deduced)
	}
	local args = require("Module:parameters").process(template_args, params)

	local lemma = args[1] or mw.title.getCurrentTitle().text
	if mw.ustring.find(lemma, "%u") then error("Lemma cannot contain uppercase characters.") end
	if not mw.ustring.match(lemma, "m[ae]k$") then error("Lemma must end in -mak or -mek.") end
	if args["aorist"] and (mw.ustring.length(args["aorist"]) ~= 1 or not mw.ustring.find("aeıuiü", args["aorist"])) then error("Impossible aorist vowel.") end
	
	local stem = lemma:sub(1, -4)
	local stem_last_word = mw.ustring.match(stem, "(%w+)$")
	local stem_ends_with_vowel = m_harmony.ends_with_vowel(stem)
	local soft = nil
	local aorist_vowel = nil
	if stem_ends_with_vowel then
		if args["soft"] then error("Erroneous softening parameter; verb stem ends in an open syllable.") end
		if args["aorist"] then error("Erroneous aorist parameter; verb stem ends in an open syllable.") end
	else
		soft = args["soft"] or guess_softness(stem_last_word)
		aorist_vowel = args["aorist"] or guess_aorist_vowel(stem_last_word, soft)
	end
	
	if soft then
		stem = stem .. ">"
	end
	
	local forms = {}
	export.generate_forms(stem, aorist, export.get_link_generating_callback(forms))
	
	-- Table adapted from {{tr-conj-head}}
	local wikicode = [=[
<div class="NavFrame"><div class="NavHead">Conjugation of {{PAGENAME}} {{#if:{{{note|}}}|({{{note}}})|}}</div><div class="NavContent">
'''''Note:''' Actual conjugations can be more complex than tables below. Compound forms with the auxiliary {{m|tr|olmak}} not shown. See also [[Appendix:Turkish suffixes#Verbs]].''
{| style="background:#F9F9F9; text-align:center; width:100%" class="inflection-table"
|-
! colspan="9" style="background:#DEDEDE" | Positive declarative
|-
! colspan="9" |
|-
! colspan="3" style="background:#EFEFEF" | infinitive
| colspan=6 | {{{inf}}}}
|-
! colspan="9" style="background:#DEDEDE" | Negative declarative
|-
! colspan="9" |
|-
! colspan="3" style="background:#EFEFEF" | infinitive
| colspan=6 | {{{neg|inf}}}
|}</div></div>]=]
	return mw.ustring.gsub(wikicode, "{{{([^}]*)}}}", forms)
end

-- Entry point for {{tr-conj}}

function export.show(frame)
   	return export.format(frame:getParent().args)
end

return export