Module:liv-decl
Appearance
- This module lacks a documentation subpage. Please create it.
- Useful links: subpage list • links • transclusions • testcases • sandbox
local export = {}
local m_str_utils = require("Module:string utilities")
local char = m_str_utils.char
local find = m_str_utils.find
local gsub = m_str_utils.gsub
local len = m_str_utils.len
local lower = m_str_utils.lower
local match = m_str_utils.match
local sub = m_str_utils.sub
local unpack = unpack or table.unpack -- Lua 5.2 compatibility
local upper = m_str_utils.upper
local lang = require("Module:languages").getByCode("liv")
local listToSet = require("Module:table").listToSet
-- Remove ending from word to get an inflection stem. ending can contain Lua pattern syntax.
local function get_stem(word, ending)
local fragment = match(word, ending .. "$")
if fragment then
return sub(word, 1, -len(fragment) - 1), fragment
end
error("Unexpected ending for this inflection type! Wrong type?")
end
-- Get value from list or fallback if empty/nil.
local function get_or(value, fallback)
return (value and #value > 0) and value or fallback
end
-- Return argument
local function identity(value)
return value
end
-- Combine strings or lists of strings to one list.
local function join(...)
local t = {}
for _, s in ipairs({ ... }) do
if type(s) == "table" then
for _, v in ipairs(s) do
table.insert(t, v)
end
elseif type(s) == "string" then
table.insert(t, s)
end
end
return t
end
-- Creates a function g(t, ...) which applies f(t, ...) if t is string,
-- and else applies f(t, ...) to all values in the table t.
local function apply_on_factory(f)
return function (t, ...)
if type(t) == "string" then
return (f(t, ...))
end
local r = {}
for _, v in ipairs(t) do
table.insert(r, (f(v, ...)))
end
return r
end
end
-- Apply f to a string or every string in a list of strings.
-- If f returns a table, add all strings from that table into the result.
-- Otherwise, if f returns a string, add the string into the result.
-- Returns the final result.
local function flat_map(t, f, ...)
local apply = apply_on_factory(f)
local applied = apply(t, ...)
if type(applied) == "string" then return applied end
return join(unpack(applied))
end
-- Apply gsub to string or list of strings.
local gsub_all = apply_on_factory(gsub)
-- Append text to string or list of strings.
local append = apply_on_factory(function (v, x)
return v .. x
end)
local function with_note(note, t)
if not note then return t end
if type(t) == "string" then
return { { form = t, note = note } }
end
local r = {}
for _, v in ipairs(t) do
table.insert(r, { form = v, note = note })
end
return r
end
local vowels = "aāeēiīoōuūäǟõȭȯȱǭöȫüṻ"
local apos = "’"
-- Append d/t to stem.
local append_dt = apply_on_factory(function (v)
return v .. (match(v, "[mnņptțksšzž]" .. apos .. "?$") and "t" or "d")
end)
local polyphthongs = {
["ie"] = true, ["ie’"] = true, ["uo"] = true, ["uo’"] = true,
["īe"] = true, ["ī’e"] = true, ["ūo"] = true, ["ū’o"] = true,
["iu"] = true, ["i’u"] = true, ["īu"] = true, ["ieu"] = true,
["ei"] = true, ["e’i"] = true, ["ēi"] = true, ["eu"] = true, ["e’u"] = true,
["äu"] = true, ["ä’u"] = true,
["õi"] = true, ["õ’i"] = true, ["ȭi"] = true, ["õu"] = true, ["õ’u"] = true,
["ȯi"] = true, ["ȯ’i"] = true, ["ȱi"] = true,
["ai"] = true, ["a’i"] = true, ["āi"] = true,
["ui"] = true, ["u’i"] = true, ["ūi"] = true,
["uoi"] = true, ["uo’i"] = true, ["ūoi"] = true, ["ū’oi"] = true,
["oi"] = true, ["o’i"] = true, ["ou"] = true, ["o’u"] = true,
["ǭi"] = true, ["ǭ’i"] = true,
}
-- Checks whether a stem is monosyllabic.
local function is_monosyllabic(stem)
local vowels = match(stem, "^[^"..vowels.."]*(["..vowels..apos.."]+)[^"..vowels.."]*$")
if not vowels then return false end
return polyphthongs[vowels] or len(gsub(vowels, apos, "")) == 1
end
-- Checks whether a stem ends in a vowel.
local function ends_in_vowel(stem)
return match(stem, "[" .. vowels .. "][" .. vowels .. apos .. "]*$")
end
-- Checks whether a vowel is short.
local function is_vowel_short(vowels)
vowels = gsub(vowels, apos, "")
return vowels == "ie" or vowels == "uo" or match(vowels, "^[aeiouäõȯöü]$")
end
-- Checks whether the final stem in a vowel is short.
local function is_final_vowel_short(stem)
local vowels = match(stem, "(["..vowels..apos.."]+)[^"..vowels.."]*$")
return (vowels and is_vowel_short(vowels)) or false
end
-- If the stem is monosyllabic, append mono; otherwise append poly.
local append_monopoly = apply_on_factory(function (stem, mono, poly)
return is_monosyllabic(stem) and stem .. mono or stem .. poly
end)
-- Drops a final long consonant.
local ungeminate_final = apply_on_factory(function (stem)
return gsub(stem, "([mnņptțkbdḑgfsšhvzžrŗjlļ])%1$", "%1")
end)
-- Geminates the final consonant if allowed.
local geminate_final = apply_on_factory(function (stem, ignore_prev_vowel)
local v, c = match(stem, "^[^" .. vowels .. "]*([" .. vowels .. "][" .. vowels .. apos .. "]*)([mnņptțkbdḑgfsšhvzžrŗjlļ])$")
if not v or not is_vowel_short(v) then return stem end
return gsub(stem, "([" .. vowels .. "][" .. vowels .. apos .. "]*)([mnņptțkbdḑgfsšhvzžrŗjlļ])$", "%1%2%2")
end)
-- Make allative from illative
local make_all_from_ill = apply_on_factory(function (ill, par_forms, dat_forms)
if match(ill, "z$") then
return gsub(ill, "z$", "l")
end
if match(ill, "zõ$") then
local append = false
if ill == par_forms or ill .. "n" == dat_forms then
append = true
else
if type(par_forms) == "table" then
for _, par in ipairs(par_forms) do
if ill == par then
append = true
break
end
end
end
if type(dat_forms) == "table" then
for _, dat in ipairs(dat_forms) do
if ill .. "n" == dat then
append = true
break
end
end
end
end
if not append then
return gsub(ill, apos .. "?zõ$", "lõ")
end
end
return ill .. "lõ"
end)
local palatalized_cons = {
["n"] = "ņ", ["t"] = "ț", ["d"] = "ḑ", ["r"] = "ŗ", ["l"] = "ļ",
["s"] = "š", ["z"] = "ž"
}
-- Palatalizes the final set of consonants.
function palatalize_final_cons(stem)
local stem = gsub(stem, "[^" .. vowels .. "]+$", function (f)
return gsub(f, "[dlnrstz]", palatalized_cons)
end)
return gsub(stem, "[țḑ][šž]", { ["țš"] = "tš", ["ḑž"] = "dž" })
end
local DEPALATALIZE_BLOCKER = char(0xE801)
local depalatalized_cons = {
["ņ"] = "n", ["ț"] = "t", ["ḑ"] = "d", ["ŗ"] = "r", ["ļ"] = "l",
["š"] = DEPALATALIZE_BLOCKER.."s", ["ž"] = DEPALATALIZE_BLOCKER.."z"
}
-- Depalatalizes the final set of consonants.
function depalatalize_final_cons(stem)
local stem = gsub(stem, "[^" .. vowels .. "]+$", function (f)
return gsub(f, "[ḑļņŗšțž]", depalatalized_cons)
end)
stem = gsub(stem, "[td]"..DEPALATALIZE_BLOCKER.."[sz]",
{ ["t"..DEPALATALIZE_BLOCKER.."s"] = "tš",
["d"..DEPALATALIZE_BLOCKER.."z"] = "dž" })
return gsub(stem, DEPALATALIZE_BLOCKER, "")
end
local vowel_short_to_long = {
-- TODO some of these are probably wrong
["a"] = "ā", ["ai"] = "āi", ["au"] = "ā",
["ä"] = "ǟ", ["äi"] = "ǟi", ["äu"] = "ǟ",
["e"] = "ē", ["ei"] = "ēi", ["eu"] = "ē",
["i"] = "ī", ["iu"] = "ī",
["o"] = "ō", ["oi"] = "ōi", ["ou"] = "ō",
["ȯ"] = "ȱ", ["ȯi"] = "ȱi", ["ȯu"] = "ȱ",
["õ"] = "ȭ", ["õi"] = "ȭi", ["õu"] = "ȭ",
["u"] = "ū", ["ui"] = "ūi",
["ie"] = "īe", ["ieu"] = "īe",
["uo"] = "ūo", ["uoi"] = "ūoi",
}
local vowel_short_to_long_no_i = {
["ai"] = "ā", ["äi"] = "ǟ", ["ei"] = "ē",
["oi"] = "ō", ["ȯi"] = "ȱ", ["õi"] = "ȭ", ["ui"] = "ū",
}
-- Vowel short -> long conversion
local function do_vowel_short_to_long(stem, no_i)
return gsub(stem,
"([" .. vowels .. "][" .. vowels .. apos .. "]*)([^" .. vowels .. "]*)$",
function (v, c)
if no_i and vowel_short_to_long_no_i[v] then
return vowel_short_to_long_no_i[v] .. c
end
return (vowel_short_to_long[v] or v) .. c
end)
end
local vowel_long_to_short = {
-- TODO some of these are probably wrong
["ā"] = "a", ["ǟ"] = "ä", ["ē"] = "e", ["ī"] = "i",
["ō"] = "o", ["ȱ"] = "ȯ", ["ȭ"] = "õ", ["ū"] = "u",
["īe"] = "ie", ["ūo"] = "uo", ["ǭ"] = "a",
}
local vowel_long_to_short2 = {
-- TODO some of these are probably wrong
["āi"] = "ai", ["ǟi"] = "äi", ["ēi"] = "ei",
["ōi"] = "oi", ["ȱi"] = "ȯi", ["ȭi"] = "õi", ["ūi"] = "ui",
["ūoi"] = "uoi",
["āu"] = "au", ["ǟu"] = "äu", ["ēu"] = "eu", ["īu"] = "iu",
["ōu"] = "ou", ["ȱu"] = "ȯu", ["ȭu"] = "õu",
}
-- Vowel long -> short conversion
local function do_vowel_long_to_short(stem, suffix)
stem = gsub(stem,
"([" .. vowels .. "][" .. vowels .. apos .. "]*)([^" .. vowels .. "]*)$",
function (v, c)
if vowel_long_to_short[v] then
return vowel_long_to_short[v] .. (suffix or "") .. c
end
return (vowel_long_to_short2[v] or v) .. c
end)
return stem
end
-- Add apostrophe to make stem broken tone
local function make_broken(stem)
if find(stem, apos) then return stem end
-- Find first vowel
local i, _, v = find(stem, "([" .. vowels .. "]+)")
if not i then return stem end
if match(v, "^ie") or match(v, "^uo") then
-- Apostrophe after short ie or uo
i = i + 1
else
-- Apostrophe after first vowel
end
return sub(stem, 1, i) .. apos .. sub(stem, i + 1)
end
-- Remove apostrophe to make stem plain tone
local function make_plain(stem)
return gsub(stem, apos, "")
end
-- Return z or ž for illative
local function get_illative_z(stem)
return match(stem, "[šž][^" .. vowels .. "]*[" .. vowels .. "]*$") and "z" or "ž"
end
local OPT_ILL_Z = char(0xE800)
local function handle_opt_ill_z(form)
if match(form, OPT_ILL_Z .. "$") then
form = gsub(form, OPT_ILL_Z, "")
return { form, form .. "z" }
else
return form
end
end
local function make_inessive_forms(result)
if result["sg_ill"] then
-- handle OPT_ILL_Z
result["sg_ill"] = flat_map(result["sg_ill"], handle_opt_ill_z)
end
if result["sg_ela"] then
-- sg_ela -> sg_ine by removing t
result["sg_ine"] = gsub_all(result["sg_ela"], "t(õ?)$", "%1")
end
if result["pl_ela"] then
-- pl_ela -> pl_ine by removing t
result["pl_ine"] = gsub_all(result["pl_ela"], "t(i?)$", "%1")
end
return result
end
-- Livonian nominal stems
-- nsg: nominative singular
-- gsg: genitive singular
-- psg: partitive singular
-- dsg: (= psg) dative singular (without -n)
-- inssg: (= dsg) instructive singular (without -ks)
-- ilsg: illative singular (use OPT_ILL_Z for optional z suffix)
-- elsg: elative singular (without -st(õ))
-- npl: (= gsg) nominative plural
-- gpl: (= npl) genitive plural
-- ppl: partitive plural (without -i)
-- dpl: (= gpl) dative plural (without -n)
-- inspl: (= dpl) instructive plural (without -ks)
-- ilpl: illative plural
-- elpl: elative plural
--
local function make_forms(stems)
local result
local nsg = stems.nsg
local gsg = stems.gsg
local psg = stems.psg
local dsg = stems.dsg or psg
local inssg = stems.inssg or dsg
local ilsg = stems.ilsg
local elsg = stems.elsg
local npl = stems.npl or gsg
local gpl = stems.gpl or npl
local ppl = stems.ppl
local ppl = stems.ppl
local dpl = stems.dpl or gpl
local inspl = stems.inspl or dpl
local ilpl = stems.ilpl
local elpl = stems.elpl
local result = { }
result["sg_nom"] = nsg
result["sg_gen"] = gsg
result["sg_par"] = psg
result["sg_dat"] = append(dsg, "n")
result["sg_ins"] = append(inssg, "ks")
result["sg_ill"] = ilsg
result["sg_ela"] = append_monopoly(gsub_all(elsg, "ss$", "s"), "stõ", "st")
-- sg_ela s -> š
result["sg_ela"] = gsub_all(result["sg_ela"], "([ņțḑŗļ])s(tõ?)$", "%1š%2")
result["pl_nom"] = npl
result["pl_gen"] = gpl
result["pl_par"] = append(ppl, "i")
result["pl_dat"] = append(dpl, "n")
result["pl_ins"] = append(inspl, "ks")
result["pl_ill"] = ilpl
result["pl_ela"] = elpl
return make_inessive_forms(result)
end
local function postprocess(data, result)
if data.has_ad then
result["sg_ade"] = gsub_all(result["sg_dat"], "n$", "l")
-- result["sg_all"] = make_all_from_ill(result["sg_ill"], result["sg_par"], result["sg_dat"])
result["sg_all"] = append(result["sg_ade"], "õ")
result["sg_abl"] = append(result["sg_ade"], "d")
end
if data.prefix and #data.prefix > 0 then
local prefix = data.prefix
for k, v in pairs(result) do
result[k] = gsub_all(v, "^", prefix)
end
end
if data.suffix and #data.suffix > 0 then
local suffix = data.suffix
for k, v in pairs(result) do
result[k] = gsub_all(v, "$", suffix)
end
end
if data.no_singular then
for k, v in pairs(result) do
if k:match("^sg_") then
result[k] = nil
end
end
end
if data.no_plural then
for k, v in pairs(result) do
if k:match("^pl_") then
result[k] = nil
end
end
end
if data.capitalize then
local prefix = data.prefix
for k, v in pairs(result) do
result[k] = gsub_all(v, "^%l", upper)
end
end
return result
end
-- inflection classes begin
local inflections = {}
local manual_infls = {
[1] = make_inessive_forms{
["sg_nom"] = "mis",
["sg_gen"] = "mis",
["sg_par"] = { "midā", "mis" },
["sg_dat"] = "missõn",
["sg_ins"] = "missõks",
["sg_ill"] = "missõ",
["sg_ela"] = "missõst",
},
[2] = make_inessive_forms{
["sg_nom"] = "jegā",
["sg_gen"] = "jegā",
["sg_par"] = "jegā",
["sg_dat"] = "jegān",
["sg_ins"] = "jegāks",
["sg_ill"] = "je’ggõ",
["sg_ela"] = "jegāst",
},
[3] = make_inessive_forms{
["sg_nom"] = "mū", ["pl_nom"] = "munt",
["sg_gen"] = "mū", ["pl_gen"] = "munt",
["sg_par"] = "mūdõ", ["pl_par"] = "mūḑi",
["sg_dat"] = "mūn", ["pl_dat"] = "muntõn",
["sg_ins"] = "mūkõks", ["pl_ins"] = "muntkõks",
["sg_ill"] = "mū’zõ", ["pl_ill"] = "mū’ži",
["sg_ela"] = "mūstõ", ["pl_ela"] = "mūšti",
},
[4] = make_inessive_forms{
["sg_nom"] = "se", ["pl_nom"] = "ne",
["sg_gen"] = "sīe", ["pl_gen"] = "nänt",
["sg_par"] = "siedā", ["pl_par"] = "nēḑi",
["sg_dat"] = "sīen", ["pl_dat"] = "näntõn",
["sg_ins"] = "sīekõks", ["pl_ins"] = "näntkõks",
["sg_ill"] = "sī’ezõ", ["pl_ill"] = "nē’ži",
["sg_ela"] = "sīestõ", ["pl_ela"] = "nēšti",
},
[5] = make_inessive_forms{
["sg_nom"] = { "tämā", "ta" }, ["pl_nom"] = { "ne", "nämād" },
["sg_gen"] = "tä’m", ["pl_gen"] = "nänt",
["sg_par"] = "tǟnda", ["pl_par"] = "nēḑi",
["sg_dat"] = "tä’mmõn", ["pl_dat"] = "näntõn",
["sg_ins"] = "tä’mkõks", ["pl_ins"] = "näntkõks",
["sg_ill"] = "tä’mmõ"..OPT_ILL_Z, ["pl_ill"] = "nē’ži",
["sg_ela"] = "tä’mstõ", ["pl_ela"] = "nēšti",
},
[6] = make_inessive_forms{
["sg_nom"] = { "minā", "ma" }, ["pl_nom"] = { "mēg", "meg" },
["sg_gen"] = "mi’n", ["pl_gen"] = "mä’d",
["sg_par"] = "mīnda", ["pl_par"] = "mēḑi",
["sg_dat"] = { "mi’nnõn", "mi’n" }, ["pl_dat"] = { "mä’ddõn", "mä’n" },
["sg_ins"] = "mi’nkõks", ["pl_ins"] = "mä’dkõks",
["sg_ill"] = "mi’nnõ"..OPT_ILL_Z, ["pl_ill"] = "mē’ži",
["sg_ela"] = "mi’nstõ", ["pl_ela"] = "mēšti",
},
[7] = make_inessive_forms{
["sg_nom"] = { "sinā", "sa" }, ["pl_nom"] = { "tēg", "teg" },
["sg_gen"] = "si’n", ["pl_gen"] = "tä’d",
["sg_par"] = "sīnda", ["pl_par"] = "tēḑi",
["sg_dat"] = { "si’nnõn", "si’n" }, ["pl_dat"] = { "tä’ddõn", "tä’n" },
["sg_ins"] = "si’nkõks", ["pl_ins"] = "tä’dkõks",
["sg_ill"] = "si’nnõ"..OPT_ILL_Z, ["pl_ill"] = "tē’ži",
["sg_ela"] = "si’nstõ", ["pl_ela"] = "tēšti",
},
[8] = make_inessive_forms{
["sg_nom"] = "kis", ["pl_nom"] = { "kis", "kīend" },
["sg_gen"] = { "kīen", "kīnga" }, ["pl_gen"] = "kīend",
["sg_par"] = { "kīenta", "kīenda" }, ["pl_par"] = "kīendi",
["sg_dat"] = { "kīen", "kīngan" }, ["pl_dat"] = "kīendõn",
["sg_ins"] = { "kīenkõks", "kīngaks" }, ["pl_ins"] = "kīendõks",
["sg_ill"] = "kīenõ", ["pl_ill"] = "kīeniž",
["sg_ela"] = "kīenstõ", ["pl_ela"] = "kīenšti",
},
[9] = make_inessive_forms{
["sg_nom"] = "ī’ž", ["pl_nom"] = "eņtšõd",
["sg_gen"] = "eņtš", ["pl_gen"] = "eņtšõd",
["sg_par"] = "ēņtšta", ["pl_par"] = "eņtšidi",
["sg_dat"] = "eņtšõn", ["pl_dat"] = "eņtšõdõn",
["sg_ins"] = "eņtšõks", ["pl_ins"] = "eņtšõdõks",
["sg_ill"] = "eņtšõ"..OPT_ILL_Z, ["pl_ill"] = "eņtšiz",
["sg_ela"] = "eņtšõst", ["pl_ela"] = "eņtšist",
},
[10] = make_inessive_forms{
["sg_nom"] = "midāgõd", ["pl_nom"] = "midāgõd",
["sg_gen"] = "midāgõd", ["pl_gen"] = "midāgõd",
["sg_par"] = "midāgõd", ["pl_par"] = "midāgidi",
["sg_dat"] = "midāgõn", ["pl_dat"] = "midāgõdõn",
["sg_ins"] = "midāgõks", ["pl_ins"] = "midāgõdõks",
["sg_ill"] = "midāgõ"..OPT_ILL_Z, ["pl_ill"] = "midāgiž",
["sg_ela"] = "midāgõst", ["pl_ela"] = "midāgist",
},
[11] = make_inessive_forms{
["sg_nom"] = "mits", ["pl_nom"] = "mitsmõd",
["sg_gen"] = "mits", ["pl_gen"] = "mitsmõd",
["sg_par"] = "mits", ["pl_par"] = "mitsmidi",
["sg_dat"] = "mitsõn", ["pl_dat"] = "mitsmõdõn",
["sg_ins"] = "mitsõks", ["pl_ins"] = "mitsmõdõks",
["sg_ill"] = "mitsõ"..OPT_ILL_Z, ["pl_ill"] = "mitsmiž",
["sg_ela"] = "mitsõs", ["pl_ela"] = "mitsmist",
},
}
-- Handles types 1-11
local function infl_manual(typeno, data)
return manual_infls[typeno]
end
for i = 1, 11 do inflections[i] = infl_manual end
-- Handles types 12-17
local function infl_monosyllabic(typeno, data)
local lemma = data.title
local stem = get_stem(lemma, data.no_singular and "d" or "")
local pl2 = stem
if typeno == 14 or typeno == 15 or typeno == 17 then
-- Adjust plural stem vowel
pl2 = gsub(pl2, "[" .. vowels .. "]+$", {
["ǟ"] = "ē", ["īe"] = "ē", ["ei"] = "ē"
})
end
return make_forms {
nsg = stem,
gsg = stem,
psg = typeno <= 15 and stem .. "dõ" or stem .. "õ",
dsg = typeno <= 15 and stem or stem .. "õ",
inssg = typeno <= 15 and stem .. "kõ" or stem .. "õ",
ilsg = typeno <= 15 and make_broken(stem) .. "zõ" or stem .. "õ",
elsg = typeno <= 15 and stem or stem .. "õ",
npl = stem .. "d",
gpl = stem .. "d",
ppl = pl2 .. "ḑ",
dpl = stem .. "dõ",
inspl = typeno <= 15 and stem .. "dkõ" or stem .. "dõ",
ilpl = (typeno <= 15 and make_broken(pl2) or pl2) .. "ži",
elpl = pl2 .. "šti",
}
end
for i = 12, 17 do inflections[i] = infl_monosyllabic end
-- Nominal types within 18-54 that introduce diphthongs of this type into stems from long vowels
local bisyllabic_a_diphthongize = {
[21] = "i", [22] = "i", [23] = "i", [37] = "i", [47] = "i",
[24] = "u", [38] = "u", [48] = "u",
}
-- Nominal types within 18-54 with broken tone in the other stem
local bisyllabic_a_stem2_broken = listToSet({
18, 19, 20, 25, 26, 39, 40, 49,
})
-- Nominal types within 18-54 with gemination in the other stem
local bisyllabic_a_stem2_gem = listToSet({
18, 19, 25, 26, 27, 28, 29, 39, 41, 43, 44, 45, 50, 54,
})
-- Handles types 18-54
local function infl_bisyllabic_a_final(typeno, data)
local lemma = data.title
local stem, a
if data.no_singular and typeno == 54 then
stem = get_stem(lemma, "õd")
stem = ungeminate_final(stem)
a = "a"
else
stem = data.no_singular and get_stem(lemma, "d") or lemma
stem, a = get_stem(stem, "[" .. vowels .. "]")
end
-- Two stems, called stem (nominative) and stem2 (partitive)
-- Forms mixed from the two.
-- Modify the stem-final vowel
local stem2 = do_vowel_long_to_short(stem, bisyllabic_a_diphthongize[typeno])
if typeno == 22 or typeno == 45 then
-- puoi- > pȯi-, puol- > pȯl-
stem2 = gsub(stem2, "uo(i?)([^" .. vowels .. "]*)$", "ȯ%1%2")
elseif typeno == 47 then
-- uišk- > uisk-
stem2 = gsub(stem2, "iš([^" .. vowels .. "]*)$", "is%1")
end
if bisyllabic_a_stem2_broken[typeno] then
stem2 = make_broken(stem2)
end
-- Plural stem
local pl2
local ppl
if typeno < 39 then
pl2 = stem2
if typeno == 19 then
-- a'm- -> ä'm-
pl2 = gsub(stem2, "%f[" .. vowels .. "]a([^" .. vowels .. "]*)$", "ä%1")
elseif typeno == 25 or typeno == 29 or typeno == 32 then
-- pie’ž- -> pe’ž-
ppl = gsub(stem2, "%f[" .. vowels .. "]ie([^" .. vowels .. "]*)$", "e%1")
elseif typeno == 35 then
-- käņg- -> keņg-
pl2 = gsub(stem2, "%f[" .. vowels .. "]ä([^" .. vowels .. "]*)$", "e%1")
end
if typeno >= 34 then
-- silm- > siļm-
pl2 = palatalize_final_cons(pl2)
end
ppl = ppl or pl2
if typeno >= 33 then
ppl = ppl
elseif match(ppl, "st$") then
ppl = gsub(ppl, "st", "št")
elseif match(ppl, "[sš]$") then
ppl = palatalize_final_cons(ungeminate_final(ppl)) .. "t"
elseif match(ppl, "[kpt]$") then
ppl = palatalize_final_cons(ungeminate_final(ppl)) .. "ț"
else
ppl = palatalize_final_cons(ungeminate_final(ppl)) .. "ḑ"
end
pl2 = make_plain(pl2)
else
pl2 = stem
end
if bisyllabic_a_stem2_gem[typeno] then
stem2 = geminate_final(stem2)
end
local ilpl, elpl
if typeno <= 20 then
ilpl = palatalize_final_cons(make_broken(pl2)) .. "ži"
elpl = palatalize_final_cons(make_broken(pl2)) .. "šti"
elseif typeno <= 24 then
ilpl = palatalize_final_cons(pl2) .. "ži"
elpl = palatalize_final_cons(pl2) .. "šti"
elseif typeno == 33 then
ilpl = { pl2 .. "ži", stem .. "iž" }
elpl = { pl2 .. "šti", stem .. "ist" }
elseif 34 <= typeno and typeno <= 35 then
ilpl = { palatalize_final_cons(pl2) .. "ži", stem .. "iž" }
elpl = { palatalize_final_cons(pl2) .. "šti", stem .. "ist" }
else
local ii = is_final_vowel_short(stem) and "ī" or "i"
ilpl = stem .. ii .. get_illative_z(stem)
elpl = stem .. ii .. "st"
end
if typeno == 54 then
-- 54 is too different from everything else
return make_forms {
nsg = stem .. a,
gsg = stem .. a,
psg = stem2 .. "õ",
dsg = stem .. a,
inssg = stem2 .. "õ",
ilsg = stem2 .. "õ",
elsg = stem .. a,
npl = stem2 .. "õd",
ppl = stem2 .. "id",
dpl = stem2 .. "õdõ",
ilpl = stem2 .. "iž",
elpl = stem2 .. "ist",
}
end
return make_forms {
nsg = stem .. a,
gsg = stem .. a,
psg = stem2 .. (typeno == 53 and "i" or "õ"),
dsg = stem .. a,
inssg = stem .. a,
ilsg = stem2 .. "õ",
elsg = stem .. a,
npl = stem .. a .. "d",
ppl = ppl or stem .. (is_final_vowel_short(stem) and "īd" or "id"),
dpl = stem .. a .. "dõ",
ilpl = ilpl,
elpl = elpl,
}
end
for i = 18, 54 do inflections[i] = infl_bisyllabic_a_final end
-- Handles types 55-58
local function infl_bisyllabic_a_final_invariant(typeno, data)
local lemma = data.title
local stem = data.no_singular and get_stem(lemma, "d") or lemma
local a
stem, a = get_stem(stem, "[" .. vowels .. "]")
-- One stem.
local psg
if typeno == 55 then
psg = stem .. "õ"
elseif typeno == 56 then
psg = stem .. a
else
psg = stem .. a .. "zt"
end
local ilsg
if typeno == 55 then
ilsg = stem .. "õ"
else
ilsg = stem .. a .. "z"
end
local pl = stem .. ((is_final_vowel_short(stem) and typeno >= 57) and "ī" or "i")
return make_forms {
nsg = stem .. a,
gsg = stem .. a,
psg = psg,
dsg = stem .. a,
ilsg = ilsg,
elsg = stem .. a,
npl = stem .. a .. "d",
ppl = pl .. "d",
dpl = stem .. a .. "dõ",
ilpl = pl .. (typeno == 58 and "z" or "ž"),
elpl = pl .. "st",
}
end
for i = 55, 58 do inflections[i] = infl_bisyllabic_a_final_invariant end
-- Nominal types within 59-114 with length variation between stems
local bisyllabic_v_stem2_lenvar = listToSet({
63, 67, 70
})
-- Nominal types within 59-114 with a broken tone in the nominative singular
local bisyllabic_v_stem2_broken_nom_sg = listToSet({
59, 60, 64, 72, 73, 74, 75, 76, 81, 82, 83, 84, 85, 86, 87, 88, 89
})
-- Nominal types within 59-114 with -ž in the nominative singular and -d- in the stem
local bisyllabic_v_zh_d = listToSet({
86, 87, 88, 112, 113
})
-- Nominal types within 59-114 that introduce diphthongs of this type into stems from long vowels
local bisyllabic_v_stem2_diphthongize = {
[107] = "i", [108] = "i", [109] = "i",
[93] = "u", [98] = "u", [106] = "u", [112] = "u",
}
-- Nominal types within 59-114 that ban gemination of the stem
local bisyllabic_v_no_gem_stem = listToSet({
60, 75, 93, 98, 107, 108, 109
})
-- Nominal types within 59-114 that always have a long ī in the plural stem
local bisyllabic_v_always_plural_ii = listToSet({
60, 75
})
-- Nominal types within 59-114 that have palatalization in nom.sg. only
local bisyllabic_v_palatalized_nom_sg = listToSet({
78, 89, 96, 110, 111, 112, 113
})
-- Handles types 59-114 except 71, 90, 91
local function infl_bisyllabic_v_final(typeno, data)
local lemma = data.title
local stem, stem2
-- Final stem vowel.
local pl_v
if typeno <= 71 then
pl_v = "i"
elseif typeno <= 91 then
pl_v = "ū"
else
pl_v = "õ"
end
local lenvar = bisyllabic_v_stem2_lenvar[typeno] or typeno >= 92
local nsg
-- Two stems, the nominative stem and plural stem stem2.
if data.no_singular then
stem2 = get_stem(lemma, "d")
if pl_v == "i" then
stem2 = get_stem(stem2, "[iī]")
else
stem2 = get_stem(stem2, pl_v)
end
stem = stem2
if lenvar then
stem = do_vowel_long_to_short(stem2, bisyllabic_v_stem2_diphthongize[typeno])
end
if typeno == 83 then
-- mier- > mer-
stem = gsub(stem, "%f[" .. vowels .. "]ie([^" .. vowels .. "]*)$", "e%1")
elseif typeno == 95 or typeno == 109 then
-- puort- > pȯrt-
stem = gsub(stem, "%f[" .. vowels .. "]uo([^" .. vowels .. "]*)$", "ȯ%1")
end
if bisyllabic_v_stem2_broken_nom_sg[typeno] then
stem = make_broken(stem)
end
if typeno == 108 or typeno == 109 then
stem = gsub(stem, "š$", "s")
end
if bisyllabic_v_zh_d[typeno] then
stem = gsub(stem, "d$", "ž")
if typeno == 87 then
-- käd- > ked-
stem = gsub(stem, "%f[" .. vowels .. "]ä([^" .. vowels .. "]*)$", "e%1")
elseif typeno == 88 then
-- vied- > ved-
stem = gsub(stem, "%f[" .. vowels .. "]ie([^" .. vowels .. "]*)$", "e%1")
end
end
if bisyllabic_v_palatalized_nom_sg[typeno] then
stem = palatalize_final_cons(stem)
end
else
stem = lemma
if bisyllabic_v_zh_d[typeno] then
nsg = stem
stem = get_stem(stem, "ž") .. "d"
if typeno == 87 then
-- ked- > käd-
stem = gsub(stem, "%f[" .. vowels .. "]e([^" .. vowels .. "]*)$", "ä%1")
elseif typeno == 88 then
-- ved- > vied-
stem = gsub(stem, "%f[" .. vowels .. "]e([^" .. vowels .. "]*)$", "ie%1")
end
if bisyllabic_v_palatalized_nom_sg[typeno] then
stem = depalatalize_final_cons(stem)
end
elseif bisyllabic_v_palatalized_nom_sg[typeno] then
nsg = stem
stem = depalatalize_final_cons(stem)
elseif typeno == 83 then
-- me'r- -> mie'r-
nsg = stem
stem = gsub(stem, "%f[" .. vowels .. "]e([^" .. vowels .. "]*)$", "ie%1")
elseif typeno == 101 then
-- täm -> tam-
nsg = stem
stem = gsub(stem, "%f[" .. vowels .. "]ä([^" .. vowels .. "]*)$", "a%1")
end
stem2 = stem
if bisyllabic_v_stem2_broken_nom_sg[typeno] then
stem2 = make_plain(stem2)
end
if lenvar then
stem2 = do_vowel_short_to_long(stem2, typeno >= 107)
end
if typeno == 83 then
-- mer- -> mier-
stem2 = gsub(stem2, "%f[" .. vowels .. "]e([^" .. vowels .. "]*)$", "ie%1")
elseif typeno == 95 or typeno == 109 then
-- pȱrt- -> pūort-
stem2 = gsub(stem2, "%f[" .. vowels .. "]ȱ(i?[^" .. vowels .. "]*)$", "ūo%1")
elseif typeno == 100 or typeno == 101 or typeno == 104 then
-- tām- -> tǭm-
stem2 = gsub(stem2, "%f[" .. vowels .. "]ā([^" .. vowels .. "]*)$", "ǭ%1")
end
if typeno == 108 or typeno == 109 then
stem2 = gsub(stem2, "s$", "š")
end
if typeno == 97 then
stem2 = gsub(stem2, "t$", "")
end
end
nsg = nsg or stem
local gemstem = geminate_final(stem)
-- Partitive singular.
local psg
if (81 <= typeno and typeno <= 89) or (110 <= typeno and typeno <= 114) then
psg = stem
if typeno ~= 84 then
psg = make_plain(psg)
end
if not (84 <= typeno and typeno <= 89) then
psg = do_vowel_short_to_long(psg)
end
if match(psg, "d$") or typeno == 84 then
psg = gsub(psg, "d$", "") .. "t"
elseif typeno == 110 then
psg = gsub(psg, "g$", "") .. "t"
elseif typeno <= 83 then
psg = psg .. "d"
else
psg = psg .. "t"
end
psg = gsub(psg, "md$", "nd")
if typeno <= 83 or typeno >= 110 then
psg = psg .. "a"
elseif typeno == 84 then
psg = psg .. "õ"
else
psg = psg .. "ā"
end
else
psg = gemstem .. "õ"
end
-- Instructive singular.
local inssg
if typeno <= 60 or typeno == 64 or (72 <= typeno and typeno <= 76)
or (81 <= typeno and typeno <= 94)
or (96 <= typeno and typeno <= 97)
or (110 <= typeno and typeno <= 114) then
if match(stem, "k$") then
inssg = stem .. "õ"
else
inssg = stem .. "kõ"
end
else
inssg = gemstem .. "õ"
end
-- Elative singular.
local elsg
if (68 <= typeno and typeno <= 71) or typeno == 80
or typeno == 89 or (105 <= typeno and typeno <= 109) then
elsg = gemstem .. "õ"
elseif typeno == 114 then
elsg = gsub(gemstem, "z$", "") .. "gõ"
else
elsg = stem
end
-- Nominative plural.
local pl2 = stem2 .. ((is_final_vowel_short(stem2) or bisyllabic_v_always_plural_ii[typeno]) and "ī" or "i")
local npl = (pl_v == "i" and pl2 or stem2 .. pl_v) .. "d"
-- Partitive plural.
local ppl
if typeno == 72 or typeno == 92 then
ppl = stem .. "ḑ"
elseif typeno == 73 or typeno == 93 then
ppl = palatalize_final_cons(stem) .. "ḑ"
elseif typeno == 83 then
ppl = palatalize_final_cons(make_plain(nsg)) .. "ḑ"
elseif 86 <= typeno and typeno <= 89 then
ppl = geminate_final(nsg)
elseif 110 <= typeno and typeno <= 113 then
ppl = nsg
else
ppl = pl2 .. "d"
end
-- Illative/elative plural.
if 87 <= typeno and typeno <= 89 then
pl2 = make_plain(nsg)
pl2 = pl2 .. (is_final_vowel_short(pl2) and "ī" or "i")
end
local z = get_illative_z(pl2)
local ilpl
local elpl
if 72 <= typeno and typeno <= 75 then
ilpl = palatalize_final_cons(stem) .. z .. "i"
elseif 112 <= typeno and typeno <= 113 then
ilpl = palatalize_final_cons(nsg) .. "iz"
else
ilpl = pl2 .. z
end
if 112 <= typeno and typeno <= 113 then
elpl = palatalize_final_cons(gsub(stem, "d$", "ž")) .. "ist"
elseif (72 <= typeno and typeno <= 75) or (110 <= typeno and typeno <= 111) then
elpl = palatalize_final_cons(stem) .. "šti"
elseif typeno == 83 then
elpl = palatalize_final_cons(nsg) .. "šti"
elseif (81 <= typeno and typeno <= 84) then
elpl = make_broken(stem) .. "šti"
else
elpl = pl2 .. "st"
end
return make_forms {
nsg = nsg,
gsg = stem,
psg = psg,
dsg = gemstem .. "õ",
inssg = inssg,
ilsg = gemstem .. (typeno == 114 and "gõ" or "õ"),
elsg = elsg,
npl = npl,
ppl = ppl,
dpl = npl .. "õ",
ilpl = ilpl,
elpl = elpl,
}
end
for i = 59, 114 do inflections[i] = infl_bisyllabic_v_final end
inflections[71] = function (typeno, data)
local lemma = data.title
local stem = lemma
if data.no_singular then stem = get_stem(stem, "d") end
return make_forms {
nsg = stem,
gsg = stem,
psg = stem,
dsg = stem,
ilsg = stem .. OPT_ILL_Z,
elsg = stem,
npl = stem .. "d",
ppl = stem .. "d",
dpl = stem .. "dõ",
ilpl = stem .. "ž",
elpl = stem .. "sti",
}
end
inflections[90] = function (typeno, data)
local lemma = data.title
local stem = lemma
if data.no_singular then stem = get_stem(stem, "d") end
local stempl = gsub(stem, "[" .. vowels .. "]$", "ī")
return make_forms {
nsg = stem,
gsg = stem,
psg = stem,
dsg = stem,
ilsg = stem .. OPT_ILL_Z,
elsg = stem,
npl = stem .. "d",
ppl = stempl .. "d",
dpl = stem .. "dõ",
ilpl = stempl .. "ž",
elpl = stempl .. "st",
}
end
inflections[91] = function (typeno, data)
local lemma = data.title
local stem = lemma
if data.no_singular then stem = get_stem(stem, "d") end
return make_forms {
nsg = stem,
gsg = stem,
psg = stem,
dsg = stem,
ilsg = stem .. OPT_ILL_Z,
elsg = stem,
npl = stem .. "d",
ppl = stem .. "d",
dpl = stem .. "dõ",
ilpl = stem .. "iž",
elpl = stem .. "ist",
}
end
-- Handles types 115-121
local function infl_bisyllabic_v_final_v(typeno, data)
local lemma = data.title
local stem, v
if data.no_singular then
stem = get_stem(lemma, "d")
stem, v = get_stem(stem, "õ")
else
stem, v = get_stem(lemma, "õ?")
end
local stemv = stem .. "õ"
local psg
if typeno >= 118 then
psg = stemv
elseif typeno == 117 then
psg = gsub(stem, "d[" .. vowels .. "]g$", "") .. "ta"
else
psg = gsub(do_vowel_short_to_long(stem), "([^" .. vowels .. "])g", "%1") .. (typeno == 116 and "ța" or "ta")
end
return make_forms {
nsg = lemma,
gsg = lemma,
psg = psg,
dsg = stemv,
ilsg = stemv .. (#v > 0 and OPT_ILL_Z or ""),
elsg = stemv,
npl = stemv .. "d",
ppl = stem .. "id",
dpl = stemv .. "dõ",
ilpl = stem .. "i" .. get_illative_z(stem),
elpl = stem .. "ist",
}
end
for i = 115, 121 do inflections[i] = infl_bisyllabic_v_final_v end
-- Handles types 122-150
local function infl_cons_misc(typeno, data)
local lemma = data.title
local stem = lemma
-- No gemination for 131
local possibly_geminate_final = typeno == 131 and identity or geminate_final
if data.no_singular then
stem = ungeminate_final(get_stem(stem, "õ?d"))
if typeno == 127 or typeno == 146 or typeno == 147 then
stem = palatalize_final_cons(stem)
end
if typeno == 146 or typeno == 150 then
-- tǟ’d- > tē’d-
stem = gsub(stem, "%f[" .. vowels .. "]ǟ(" .. apos .. "?)([^" .. vowels .. "]*)$", "ē%1%2")
elseif typeno == 147 then
-- lī’ed- > lē’d-
stem = gsub(stem, "%f[" .. vowels .. "]ī(" .. apos .. "?)e([^" .. vowels .. "]*)$", "ē%1%2")
end
if typeno >= 148 then
stem = get_stem(stem, "d")
if typeno >= 149 then
stem = palatalize_final_cons(stem)
end
stem = stem .. "tš"
end
end
local nsg = stem
if typeno == 127 or typeno == 146 or typeno == 147 then
stem = depalatalize_final_cons(stem)
elseif typeno >= 148 then
stem = get_stem(stem, "tš")
if typeno >= 149 then
stem = depalatalize_final_cons(stem)
end
stem = stem .. "d"
end
-- Genitive and partitive singular
local stemv
local gsg
local psg
if 137 <= typeno and typeno <= 139 then
stemv = gsub(stem, "[dt]$", "") .. "õ"
gsg = typeno == 139 and stem or { stem, stemv }
psg = stem .. "õ"
elseif typeno >= 146 then
if typeno == 146 or typeno == 150 then
-- tē’d- > tǟ’d-
stem = gsub(stem, "%f[" .. vowels .. "]ē(" .. apos .. "?)([^" .. vowels .. "]*)$", "ǟ%1%2")
elseif typeno == 147 then
-- lē’d- > lī’ed-
stem = gsub(stem, "%f[" .. vowels .. "]ē(" .. apos .. "?)([^" .. vowels .. "]*)$", "ī%1e%2")
end
stemv = stem .. "õ"
psg = stem .. "tõ"
else
stemv = possibly_geminate_final(stem) .. "õ"
psg = stemv
end
gsg = gsg or stem
-- Dative and instrumental singular
local dsg, inssg
if typeno == 139 then
dsg, inssg = stem .. "õ", stemv
elseif typeno <= 145 then
dsg, inssg = stemv, stemv
elseif typeno <= 147 then
dsg, inssg = stemv, stem .. "kõ"
else
dsg, inssg = stem .. "õ", stem .. "kõ"
end
-- Partitive plural
local ppl
if typeno <= 124 then
ppl = stem .. "ḑ"
elseif typeno == 127 then
ppl = possibly_geminate_final(do_vowel_short_to_long(stem)) .. "id"
elseif 137 <= typeno and typeno <= 139 then
local nsg_no_t = gsub(nsg, "[td]$", "")
ppl = nsg_no_t .. "id"
elseif typeno >= 146 then
ppl = nsg
else
ppl = possibly_geminate_final(stem) .. "id"
end
-- Illative singular
local ilsg
if typeno == 139 then
ilsg = stem .. "õ"
else
ilsg = stemv
end
-- Elative singular
local elsg
if typeno <= 134 or typeno >= 146 then
elsg = stem
else
elsg = stemv
end
-- Illative and elative plural
local plstem, ilpl, elpl
if typeno <= 124 then
plstem = stem
ilpl = nsg .. get_illative_z(nsg) .. "i"
elpl = nsg .. "šti"
elseif 137 <= typeno and typeno <= 139 then
local nsg_no_t = gsub(nsg, "[td]$", "")
plstem = stemv
ilpl = possibly_geminate_final(nsg_no_t) .. "i" .. get_illative_z(nsg_no_t)
elpl = possibly_geminate_final(nsg_no_t) .. "ist"
elseif 148 <= typeno and typeno <= 149 then
plstem = stemv
ilpl = possibly_geminate_final(stem) .. "i" .. get_illative_z(stem)
elpl = possibly_geminate_final(stem) .. "ist"
else
plstem = stemv
ilpl = possibly_geminate_final(nsg) .. "i" .. get_illative_z(nsg)
elpl = possibly_geminate_final(nsg) .. "ist"
end
return make_forms {
nsg = nsg,
gsg = gsg,
psg = psg,
dsg = dsg,
inssg = inssg,
ilsg = ilsg,
elsg = elsg,
npl = plstem .. "d",
ppl = ppl,
dpl = plstem .. "dõ",
inspl = plstem .. ((typeno == 123 or typeno == 124) and "dkõ" or "dõ"),
ilpl = ilpl,
elpl = elpl,
}
end
for i = 122, 150 do inflections[i] = infl_cons_misc end
-- Handles types 151-156
local function infl_cons_final_m(typeno, data)
local lemma = data.title
local stem
local c
if data.no_singular then
stem = get_stem(lemma, "õd")
stem, c = get_stem(stem, "[^" .. vowels .. "]")
stem = ungeminate_final(stem)
if typeno >= 153 then
stem = gsub(stem, c .. "$", "õ" .. c)
end
else
stem, c = get_stem(lemma, "[^" .. vowels .. "]")
end
local stem1m = stem .. c
local stem1mg
if typeno <= 152 then
stem1mg = geminate_final(stem1m)
else
stem1mg = stem1m
end
local stem1mv = stem1mg .. "õ"
local stem2m
if typeno <= 152 then
stem2m = stem1mg
else
stem2m = gsub(stem, "[" .. vowels .. "]+$", "")
if typeno == 153 then
stem2m = make_broken(stem2m)
elseif typeno >= 155 then
stem2m = do_vowel_long_to_short(stem2m, typeno == 156 and "i" or "")
end
stem2m = stem2m .. "m"
end
return make_forms {
nsg = stem1m,
gsg = stem1m,
psg = append_monopoly(stem1m, "tõ", "t"),
dsg = stem1mv,
inssg = typeno <= 152 and stem1m .. "kõ" or stem1mv,
ilsg = stem1mv,
elsg = typeno <= 152 and stem1m or stem1mv,
npl = stem2m .. "õd",
ppl = stem2m .. "id",
dpl = stem2m .. "õdõ",
ilpl = stem2m .. "i" .. get_illative_z(stem2m),
elpl = stem2m .. "ist",
}
end
for i = 151, 156 do inflections[i] = infl_cons_final_m end
-- Handles types 157-162
local function infl_cons_final_c_invariant(typeno, data)
local lemma = data.title
local stem = lemma
if data.no_singular and typeno < 161 then
stem = get_stem(stem, "õd")
end
-- Elative singular
local elsg
if typeno >= 161 then
elsg = gsub(lemma, "d$", "")
elseif typeno == 157 then
elsg = lemma .. "õ"
else
elsg = lemma
end
local bare
if typeno >= 161 then
bare = gsub(lemma, "õd$", "")
else
bare = stem
end
return make_forms {
nsg = stem,
gsg = stem,
psg = append_monopoly(stem, "tõ", "t"),
dsg = bare .. "õ",
ilsg = bare .. (typeno >= 161 and "õz" or "õ"),
elsg = elsg,
npl = bare .. "õd",
ppl = bare .. "id",
dpl = (typeno >= 161 and stem .. "õ" or stem .. "õdõ"),
ilpl = bare .. "iž",
elpl = bare .. "ist",
}
end
for i = 157, 162 do inflections[i] = infl_cons_final_c_invariant end
-- Handles types 163-165
local function infl_cons_final_z_nd(typeno, data)
local lemma = data.title
local stem
if data.no_singular then
stem = get_stem(lemma, "ndõd")
else
stem = get_stem(lemma, "z")
end
local stem_nd = gsub(stem, "n$", "") .. "nd"
local stem_ndv = stem_nd .. "õ"
return make_forms {
nsg = stem .. "z",
gsg = stem_nd,
psg = stem_nd .. "t",
dsg = stem_ndv,
ilsg = stem_ndv,
elsg = stem_ndv,
npl = stem_ndv .. "d",
ppl = stem_nd .. "id",
dpl = stem_ndv .. "dõ",
ilpl = stem_nd .. "i" .. get_illative_z(stem_nd),
elpl = stem_nd .. "ist",
}
end
for i = 163, 165 do inflections[i] = infl_cons_final_z_nd end
-- Nominal types within 166-185 that introduce diphthongs of this type into stems from long vowels
local cons_final_z_diphthongize = {
[176] = "i", [177] = "u"
}
-- Handles types 166-185
local function infl_cons_final_z(typeno, data)
local lemma = data.title
local stem
if data.no_singular then
local v
stem, v = get_stem(lemma, "d")
if typeno >= 170 then
stem, v = get_stem(stem, "[aāõ]")
if typeno <= 178 then
stem = ungeminate_final(stem)
end
if 173 <= typeno and typeno <= 178 then
stem = do_vowel_short_to_long(stem)
if typeno == 175 then
-- pāļ- > pǭļ-
stem = gsub(stem, "%f[" .. vowels .. "]ā(" .. apos .. "?)([^" .. vowels .. "]*)$", "ǭ%2")
elseif typeno == 178 then
-- pȱrz- > pūor-
stem = gsub(stem, "%f[" .. vowels .. "]ȱ(" .. apos .. "?)([^" .. vowels .. "]*)$", "ū%1o%2")
stem = gsub(stem, "z$", "")
end
end
stem = stem .. v
end
else
stem = get_stem(lemma, "z")
end
local a
if typeno <= 167 then
-- Special case 166, 167
local stemv = make_broken(stem)
local stemvg = geminate_final(stemv)
local plstem = stemv
if typeno == 166 then
plstem = gsub(plstem, "%f[" .. vowels .. "]ī(" .. apos .. "?)e([^" .. vowels .. "]*)$", "ē%1%2")
end
return make_forms {
nsg = stem .. "z",
gsg = stemv,
psg = append_monopoly(stem, "ztõ", "zt"),
dsg = gsub(stemvg, "([^" .. vowels .. "])$", "%1õ"),
inssg = stemv .. "kõ",
ilsg = typeno == 166 and stemv .. "zõ" or stemvg .. "õ",
elsg = stemv,
npl = stemv .. "d",
ppl = plstem .. "ḑ",
dpl = stemv .. "dõ",
inspl = stemv .. "dkõ",
ilpl = plstem .. get_illative_z(plstem) .. "i",
elpl = plstem .. "šti",
}
end
stem, a = get_stem(stem, "[aāõ]")
-- Two stems: stem (nominative) and stem2 (illative).
local stem2
if typeno <= 169 then
stem2 = make_broken(stem)
elseif typeno >= 179 then
stem2 = stem
else
stem2 = stem
if 173 <= typeno and typeno <= 178 then
stem2 = do_vowel_long_to_short(stem2, cons_final_z_diphthongize[typeno])
if typeno == 178 then
-- puor- > pȯrz-
stem2 = gsub(stem2, "%f[" .. vowels .. "]uo(" .. apos .. "?)([^" .. vowels .. "]*)$", "ȯ%1%2")
stem2 = gsub(stem2, "r$", "rz")
end
end
stem2 = geminate_final(stem2)
end
local stem1a = stem .. a
local stem2v = stem2 .. "õ"
local stempl = typeno <= 172 and stem .. "ī" or stem2 .. "i"
return make_forms {
nsg = stem1a .. "z",
gsg = typeno == 168 and stem1a or stem2v,
psg = stem1a .. "zt",
dsg = typeno <= 170 and stem1a or stem2v,
ilsg = stem2v .. OPT_ILL_Z,
elsg = typeno <= 172 and stem1a or stem2v,
npl = (typeno <= 169 and stem1a or stem2v) .. "d",
ppl = stempl .. "d",
dpl = (typeno <= 169 and stem1a or stem2v) .. "dõ",
ilpl = stempl .. get_illative_z(stempl),
elpl = stempl .. "st",
}
end
for i = 166, 185 do inflections[i] = infl_cons_final_z end
-- Nominal types within 186-202 that have ī in the stem for oblique forms.
local cons_i_iz_long_i = listToSet({
192, 193, 194, 195, 198
})
-- Handles types 186-202
local function infl_cons_i_iz(typeno, data)
local lemma = data.title
local stem, i
stem = lemma
if data.no_singular then
if match(stem, "zt$") then
stem = get_stem(stem, "zt")
else
stem = get_stem(stem, "d")
end
end
stem, i = get_stem(stem, "[iī]")
local stem2
-- Two stems: nominative (stem) and genitive (stem2)
if 192 <= typeno and typeno <= 195 then
stem2 = ungeminate_final(make_plain(stem))
elseif 196 <= typeno and typeno <= 197 then
stem2 = do_vowel_short_to_long(stem)
else
stem2 = stem
end
local ii = cons_i_iz_long_i[typeno] and "ī" or "i"
-- Partitive singular
local psg
if typeno == 191 then
psg = do_vowel_short_to_long(stem) .. "izta"
elseif typeno <= 189 or typeno >= 201 then
psg = { stem2 .. ii .. "zt", stem2 .. ii .. "t" }
else
psg = stem2 .. ii .. "zt"
end
-- Elative singular
local elsg
if typeno == 190 then
elsg = stem2 .. ii
elseif typeno == 186 or typeno == 188 or typeno == 189 or typeno == 191 then
elsg = { stem2 .. ii .. "zõ", stem2 .. ii }
else
elsg = stem2 .. ii .. "zõ"
end
local dpl_base = stem .. i .. "zt"
local ilpl_base = stem2 .. ii .. "ž"
local stems = {
nsg = stem .. i,
gsg = stem2 .. ii .. "z",
psg = psg,
dsg = typeno == 190 and (stem2 .. ii) or (stem2 .. ii .. "zõ"),
ilsg = stem2 .. ii .. "zõ",
elsg = elsg,
npl = stem .. i .. "zt",
ppl = stem2 .. ii .. "ž",
dpl = dpl_base .. "õ",
inspl = dpl_base .. (typeno == 191 and "kõ" or "õ"),
ilpl = ilpl_base .. "i" .. get_illative_z(ilpl_base),
elpl = ilpl_base .. "ist",
}
if typeno == 187 or typeno == 190 then
stems.npl = stem .. ii .. "d"
stems.ppl = stem .. ii .. "d"
stems.dpl = stem .. ii .. "dõ"
stems.inspl = stem .. ii .. "dõ"
stems.ilpl = ilpl_base
stems.elpl = stem .. "isti"
elseif typeno <= 189 then
stems.npl = join(stems.npl, stem .. ii .. "d")
stems.ppl = join(stems.ppl, stem .. ii .. "d")
stems.dpl = join(stems.dpl, stem .. ii .. "dõ")
stems.inspl = join(stems.inspl, stem .. ii .. "dõ")
stems.ilpl = join(stems.ilpl, ilpl_base .. (typeno == 186 and "i" or ""))
stems.elpl = join(stems.elpl, stem .. "isti")
end
return make_forms(stems)
end
for i = 186, 202 do inflections[i] = infl_cons_i_iz end
-- Handles types 203-209
local function infl_cons_z_ks(typeno, data)
local lemma = data.title
local stem = lemma
if data.no_singular then
stem = get_stem(stem, "t")
end
local stemv = stem .. "õ"
local stempl = palatalize_final_cons(stem)
if typeno == 204 then
-- nȭŗkõ- > nȭŗki-
stempl = gsub(stempl, "%f[" .. vowels .. "]õ([^" .. vowels .. "]*)$", "i%1")
end
return make_forms {
nsg = stem,
gsg = stem,
psg = stem .. "t",
dsg = stemv,
ilsg = stemv,
elsg = stemv,
npl = stem .. "t",
ppl = stempl,
dpl = (typeno == 209 and stempl or stem) .. "tõ",
ilpl = stempl .. "i" .. get_illative_z(stempl),
elpl = stempl .. "ist",
}
end
for i = 203, 209 do inflections[i] = infl_cons_z_ks end
-- Nominal types within 210-223: nom->gen consonant alternations
local cons_mono_i_cons_altern = {
[217] = { "kš", "d" },
[218] = { "kš", "d" },
[219] = { "ž", "d" },
}
-- Nominal types within 210-223: vowel alternations
local cons_mono_i_vowel_altern = {
[211] = { "ä", "a" },
[215] = { "ē", "īe" },
[217] = { "i", "ī" },
[218] = { "a", "ǭ" },
[220] = { "ē", "īe" },
[223] = { "ē", "ǟ" },
}
-- Nominal types within 210-223 with plain/broken tone alternations
local cons_mono_i_plain_broken = listToSet({
217, 218
})
-- Nominal types within 210-223 with -kõ- in the instructive singular.
local cons_mono_i_inssg_k = listToSet({
213, 214, 215, 216, 217, 218, 219, 220, 221, 223
})
-- Handles types 210-223
local function infl_cons_mono_i(typeno, data)
local lemma = data.title
-- Two stems: stem (nominative singular, some plural forms) and stem2
local stem
if data.no_singular then
if 217 <= typeno and typeno <= 219 then
stem = lemma
else
stem = get_stem(lemma, "[dt]")
end
if cons_mono_i_plain_broken[typeno] then
stem = make_plain(stem)
end
if cons_mono_i_cons_altern[typeno] then
local c1, c2 = unpack(cons_mono_i_cons_altern[typeno])
stem = get_stem(stem, c2) .. c1
elseif typeno ~= 212 and typeno ~= 222 then
stem = palatalize_final_cons(stem)
end
if cons_mono_i_vowel_altern[typeno] then
local v1, v2 = unpack(cons_mono_i_vowel_altern[typeno])
stem = gsub(stem, "%f[" .. vowels .. "]" .. v2 .. "([^" .. vowels .. "]*)$", v1 .. "%1")
end
else
stem = lemma
end
local stem2 = stem
if cons_mono_i_cons_altern[typeno] then
local c1, c2 = unpack(cons_mono_i_cons_altern[typeno])
stem2 = get_stem(stem2, c1) .. c2
else
stem2 = depalatalize_final_cons(stem2)
end
if cons_mono_i_vowel_altern[typeno] then
local v1, v2 = unpack(cons_mono_i_vowel_altern[typeno])
stem2 = gsub(stem2, "%f[" .. vowels .. "]" .. v1 .. "([^" .. vowels .. "]*)$", v2 .. "%1")
end
if cons_mono_i_plain_broken[typeno] then
stem2 = make_broken(stem2)
end
-- Partitive singular
local psg
if typeno <= 212 then
psg = stem2 .. "tā"
elseif typeno == 213 then
psg = do_vowel_short_to_long(make_plain(stem2)) .. "da"
elseif typeno <= 216 then
psg = stem2 .. "dõ"
else
psg = stem2 .. "tõ"
end
-- Plural forms
local nsg = stem
if typeno ~= 212 and typeno ~= 222 then
stem = palatalize_final_cons(stem)
end
local stemdpl
if typeno <= 212 then
stemdpl = stem2 .. "t"
elseif typeno <= 215 or typeno >= 220 then
stemdpl = stem2 .. "d"
else
stemdpl = stem2
end
-- Partitive plural
local steminspl = typeno == 212 and stemdpl or stemdpl .. "k"
local plstem = typeno == 212 and stemdpl or stem
local pl_i = typeno <= 211 and "ī" or "i"
local ppl
if typeno == 212 then
ppl = palatalize_final_cons(stem2) .. "t"
elseif typeno == 213 then
ppl = plstem .. "ḑ"
else
ppl = plstem
end
-- Illative plural
local ilpl
if typeno == 213 then
ilpl = make_plain(plstem) .. "ī"
elseif typeno == 217 or typeno == 218 then
ilpl = stem2 .. "i"
else
ilpl = plstem .. pl_i
end
-- Elative plural
local elpl
if typeno <= 212 or typeno == 219 then
elpl = plstem .. pl_i .. "st"
elseif typeno == 217 or typeno == 218 then
elpl = stem2 .. "šti"
else
elpl = plstem .. "šti"
end
return make_forms {
nsg = nsg,
gsg = stem2,
psg = psg,
dsg = geminate_final(stem2) .. "õ",
inssg = cons_mono_i_inssg_k[typeno] and stem2 .. "kõ" or geminate_final(stem2) .. "õ",
ilsg = geminate_final(stem2) .. "õ",
elsg = typeno <= 212 and stem2 .. "õ" or stem2,
npl = ungeminate_final(stem2 .. (typeno <= 212 and "t" or "d")),
ppl = ppl,
dpl = stemdpl .. "õ",
inspl = steminspl .. "õ",
ilpl = ilpl .. get_illative_z(ilpl),
elpl = elpl,
}
end
for i = 210, 223 do inflections[i] = infl_cons_mono_i end
-- Nominal types within 224-242 with -õ- before the elative ending
local cons_poly_elsg_vowel = listToSet({
226, 227, 228, 229, 230, 232, 233, 234, 235, 236, 237, 238
})
-- Nominal types within 224-242 with -õ- > -i- in some plural endings
local cons_poly_pl_i = listToSet({
229, 230
})
-- Nominal types within 224-242 with -õ- > -i- and palatalization in some plural endings
local cons_poly_pl_i_pal = listToSet({
226, 227, 228, 232, 233, 234, 235, 236, 241
})
-- Handles types 224-242
local function infl_cons_poly(typeno, data)
local lemma = data.title
local nsg = lemma
local stem, z
if data.no_singular then
stem = get_stem(lemma, "d")
z = ""
else
stem, z = get_stem(lemma, "[zž]?")
end
local plstem = stem
if typeno == 232 then
stem = depalatalize_final_cons(stem)
end
if cons_poly_pl_i_pal[typeno] then
plstem = gsub(plstem, "%f[" .. vowels .. "]õ([^" .. vowels .. "]*)$", "i%1")
plstem = palatalize_final_cons(plstem)
elseif cons_poly_pl_i[typeno] then
plstem = gsub(plstem, "%f[" .. vowels .. "]õ([^" .. vowels .. "]*)$", "i%1")
end
return make_forms {
nsg = nsg,
gsg = stem,
psg = stem .. (typeno >= 229 and z .. "t" or "t"),
dsg = typeno == 224 and stem or stem .. "õ",
ilsg = stem .. "õ",
elsg = cons_poly_elsg_vowel[typeno] and stem .. "õ" or stem,
npl = stem .. "d",
ppl = typeno <= 225 and plstem .. "ḑ" or plstem,
dpl = stem .. "dõ",
inspl = stem .. (typeno <= 225 and "dkõ" or "dõ"),
ilpl = typeno <= 225 and plstem .. get_illative_z(plstem) .. "i" or plstem .. "i" .. get_illative_z(plstem),
elpl = typeno <= 225 and plstem .. "šti" or plstem .. "ist",
}
end
for i = 224, 242 do inflections[i] = infl_cons_poly end
-- inflection classes end
local decl_table_base = [=[
!
! singular <small>({{l|liv|ikšlu’g}})</small>
! plural <small>({{l|liv|pǟgiņlu’g}})</small>
|-
! nominative <small>({{l|liv|nominatīv}})</small>
| {{{sg_nom}}}
| {{{pl_nom}}}
|-
! genitive <small>({{l|liv|genitīv}})</small>
| {{{sg_gen}}}
| {{{pl_gen}}}
|-
! partitive <small>({{l|liv|partitīv}})</small>
| {{{sg_par}}}
| {{{pl_par}}}
|-
! dative <small>({{l|liv|datīv}})</small>
| {{{sg_dat}}}
| {{{pl_dat}}}
|-
! instrumental <small>({{l|liv|instrumentāl}})</small>
| {{{sg_ins}}}
| {{{pl_ins}}}
|-
! illative <small>({{l|liv|illatīv}})</small>
| {{{sg_ill}}}
| {{{pl_ill}}}
|-
! inessive <small>({{l|liv|inesīv}})</small>
| {{{sg_ine}}}
| {{{pl_ine}}}
|-
! elative <small>({{l|liv|elatīv}})</small>
| {{{sg_ela}}}
| {{{pl_ela}}}
]=]
local decl_table_ad = [=[
|-
! allative <small>({{l|liv|allatīv}})</small>
| {{{sg_all}}}
| {{{pl_all}}}
|-
! adessive <small>({{l|liv|adesīv}})</small>
| {{{sg_ade}}}
| {{{pl_ade}}}
|-
! ablative <small>({{l|liv|ablatīv}})</small>
| {{{sg_abl}}}
| {{{pl_abl}}}
]=]
local function tag(text)
return require("Module:script utilities").tag_text(text, lang, nil, "term")
end
local function link(text, prefix, suffix)
if prefix and find(prefix, "%[%[") then
if not find(text, "%[%[") then
text = "[[" .. text .. "]]"
end
return require("Module:script utilities").tag_text(require("Module:links").language_link{ term = (prefix and prefix or "") .. text, lang = lang } .. (suffix and suffix or ""), lang)
else
return require("Module:script utilities").tag_text((prefix and prefix or "") .. require("Module:links").language_link{ term = text, lang = lang } .. (suffix and suffix or ""), lang)
end
end
local function mention(text)
return require("Module:links").full_link({ term = text, lang = lang }, "term")
end
local function mention_with_gloss(text, gloss)
return require("Module:links").full_link({ term = text, lang = lang, gloss = gloss }, "term")
end
local function help_tooltip(text)
return "<sup>" .. tostring(mw.html.create("span"):attr("style", "cursor:help"):attr("title", text):wikitext("?")) .. "</sup>"
end
local function note_reference(note)
if note then
return "<sup>" .. note .. ")</sup>"
else
return ""
end
end
local function note_text(reference, text)
return note_reference(reference) .. " " .. text
end
-- extract notes from forms into a list and replace by their index
local function format_notes_for_form(data, form)
local note = form.note
if note then
local index = data.notes_reverse[note]
if index then
form.note = index
else
index = tostring(#data.notes + 1)
table.insert(data.notes, note)
data.notes_reverse[note] = index
form.note = index
end
end
end
local function format_notes(data, forms)
data.notes = {}
data.notes_reverse = {}
for k, v in pairs(forms) do
if type(v) == "table" then
if v[1] then
for _, form in ipairs(v) do
if type(form) == "table" then
format_notes_for_form(data, form)
end
end
else
format_notes_for_form(data, v)
end
end
end
data.notes_reverse = nil
end
local commabelow = char(0x326)
local function normalize(word)
word = gsub(word, "[ţ']", { ["ţ"] = "ț", ["'"] = "’" })
word = gsub(word, "d"..commabelow, "ḑ")
word = gsub(word, "_", " ")
return word
end
function export.raw(inflected_part, infl_type, word_prefix, args)
if not infl_type then error("inflection class not specified") end
args = args or {}
local infl = inflections[infl_type] or error("unsupported inflection type")
inflected_part = normalize(inflected_part)
local data = { title = inflected_part, args = args, prefix = word_prefix }
if args["n"] then
if args["n"] == "s" or args["n"] == "sg" then
data.no_plural = true
elseif args["n"] == "p" or args["n"] == "pl" then
data.no_singular = true
end
elseif args["sg"] then
data.no_plural = true
elseif args["pl"] then
data.no_singular = true
end
if args["ad"] then
data.has_ad = true
end
local forms = infl(infl_type, data)
postprocess(data, forms)
return forms
end
local function parse_inflections(args, title)
local infl_type = args[1]
if not infl_type then error("inflection class not specified") end
local infl_types = {}
for itype in infl_type:gmatch("[^/]+") do
local itypeno = tonumber(itype)
if not itypeno then error("inflection types must be numbers") end
table.insert(infl_types, itypeno)
end
local function make_data(prefix, lemma)
return { title = lemma, args = args, prefix = prefix }
end
local infl_datas
if not args[2] then
args[2] = title
end
local respelled = ""
local word_prefix = ""
local word_suffix = args["suffix"]
infl_datas = {}
local i = 2
while args[i] do
local normarg = normalize(args[i])
if match(normarg, "^%s*$") then
if not match(respelled, "^%s*$") then
table.insert(infl_datas, make_data(word_prefix, respelled))
end
word_prefix = ""
else
word_prefix = word_prefix .. respelled
end
respelled = normalize(args[i])
i = i + 1
end
table.insert(infl_datas, make_data(word_prefix, respelled))
if #infl_types ~= #infl_datas then
error("Different number of inflection types and inflectable parts specified")
end
return infl_types, infl_datas
end
local function combine_forms(infl_results)
if #infl_results <= 1 then return infl_results[1] end
local final_result = {}
local function find_next(form, result, index)
if index > #infl_results then
if not final_result[form] then final_result[form] = {} end
table.insert(final_result[form], result)
else
local v = infl_results[index][form]
if v == nil then
-- do nothing
elseif type(v) == "string" then
find_next(form, result .. v, index + 1)
else
for _, f in ipairs(v) do
if f then
find_next(form, result .. f, index + 1)
end
end
end
end
end
for form, _ in pairs(infl_results[1]) do
find_next(form, "", 1)
end
return final_result
end
function export.show(frame)
local args = frame:getParent().args
local title = args["title"] or mw.loadData("Module:headword/data").pagename
local infl_types, infl_datas = parse_inflections(args, title)
local word_suffix = args["suffix"]
if word_suffix then
infl_datas[#infl_datas].suffix = word_suffix
end
local joined = {}
for _, data in ipairs(infl_datas) do
table.insert(joined, (data.prefix or "") .. data.title)
end
joined = table.concat(joined)
if lang:stripDiacritics(joined) ~= title then
error("Respelling does not match title")
end
for _, data in ipairs(infl_datas) do
if match(data.title, "^%u%U") then
data.capitalize = true
data.title = gsub(data.title, "^%u", lower)
end
end
local categories = {}
local all_data = {}
if args["n"] then
if args["n"] == "s" or args["n"] == "sg" then
all_data.no_plural = true
elseif args["n"] == "p" or args["n"] == "pl" then
all_data.no_singular = true
end
elseif args["sg"] then
all_data.no_plural = true
elseif args["pl"] then
all_data.no_singular = true
end
if args["ad"] then
all_data.has_ad = true
end
local inflection_results = {}
for index, data in ipairs(infl_datas) do
for k, v in pairs(all_data) do
data[k] = v
end
local infl_type = infl_types[index]
local infl = inflections[infl_type] or error("unsupported inflection type " .. infl_type)
local forms = infl(infl_type, data)
postprocess(data, forms)
format_notes(data, forms)
table.insert(inflection_results, forms)
end
local forms = combine_forms(inflection_results)
word_suffix = word_suffix or ""
local table_title = "Declension of " .. mention(joined .. word_suffix) .. " ([[Appendix:Livonian declension#" .. infl_types[#infl_types] .. "|" .. infl_types[#infl_types] .. "]])"
local function repl(form)
local prefix = ""
local suffix = ""
if find(form, "^%^") then
local value = forms[sub(form, 2)]
if type(value) == "table" and value[1] then
return value[1]
elseif type(value) == "string" and #value > 0 then
return value
else
return "—"
end
end
if find(form, "%$") then
local excl = find(form, "%$")
prefix = sub(form, 1, excl - 1)
form = sub(form, excl + 1)
end
if find(form, "@") then
local excl = find(form, "@")
suffix = sub(form, excl + 1)
form = sub(form, 1, excl - 1)
end
local value = forms[form]
if type(value) == "table" and value[1] then
local result = {}
for _, f in ipairs(value) do
table.insert(result, link(f, prefix, suffix))
end
return table.concat(result, "<br/>")
elseif type(value) == "string" and #value > 0 then
return link(value, prefix, suffix)
else
return "—"
end
end
local function process_text(text)
local result = gsub(text, "{{{([^%}]+)}}}", repl)
result = gsub(result, "{{l|liv|([^}]-)}}", link)
result = gsub(result, "{{m|liv|([^|}]-)||([^}]-)}}", mention_with_gloss)
result = gsub(result, "{{m|liv||([^}]-)}}", tag)
result = gsub(result, "{{m|liv|([^}]-)}}", mention)
return result
end
local notes = {}
local builtin_notes = {}
for index, note in ipairs(builtin_notes) do
table.insert(notes, note_text(tostring(#notes + 1), process_text(note)))
end
for _, data in ipairs(infl_datas) do
for index, note in ipairs(data.notes) do
table.insert(notes, note_text(tostring(#notes + 1), note))
end
end
notes = table.concat(notes, "<br />")
--if mw.title.getCurrentTitle().namespace == 0 then
-- table.insert(categories, "Livonian " .. infl_type .. "-type nominals")
--end
local decl_table = decl_table_base
if all_data.has_ad then
decl_table = decl_table .. decl_table_ad
end
local result = process_text(decl_table)
return require("Module:inflection table").inflection_table(frame, {
title = table_title,
palette = "teal",
tall = "yes",
notes = notes,
}, result) .. require("Module:utilities").format_categories(categories, lang)
end
return export