Modul:inflection/units/ru-noun
A modult a Modul:inflection/units/ru-noun/doc lapon tudod dokumentálni
-- Inflection unit for Russian nouns
-- Version 2.0.38
-- Date: 2015-08-25
local dev_prefix = ''
-- dev_prefix = 'User:Vitalik/' -- comment this on active version
local export = {}
local _ = require('Module:' .. dev_prefix .. 'inflection-tools')
-- local lang = require("Module:languages").getByCode("ru")
-- local m_links = require("Module:links")
-- local strutils = require("Module:string utilities")
-- constants:
local unstressed = 1
local stressed = 2
function export.template(base, args)
return dev_prefix .. 'ru-decl-noun-table-z'
end
local function get_standard_endings()
return {
m = { -- masculine endings
hard = {
nom_sg = '',
gen_sg = 'а',
dat_sg = 'у',
ins_sg = 'ом',
nom_pl = 'ы',
gen_pl = {'ов', 'ов'}, -- possibly we can join them together again (m_hard_gen_pl stressed and unstressed)
},
soft = {
nom_sg = 'ь',
gen_sg = 'я',
dat_sg = 'ю',
ins_sg = {'ем', 'ём'},
nom_pl = 'и',
gen_pl = {'ей', 'ей'},
},
},
f = { -- feminine endings
hard = {
nom_sg = 'а',
gen_sg = 'ы',
dat_sg = 'е',
acc_sg = 'у',
ins_sg = 'ой',
nom_pl = 'ы',
gen_pl = {'', ''},
},
soft = {
nom_sg = 'я',
gen_sg = 'и',
dat_sg = {'е', 'е'},
acc_sg = 'ю',
ins_sg = {'ей', 'ёй'},
nom_pl = 'и',
gen_pl = {'ь', 'ей'},
},
},
n = { -- neuter endings
hard = {
nom_sg = 'о',
gen_sg = 'а',
dat_sg = 'у',
ins_sg = 'ом',
nom_pl = 'а',
gen_pl = {'', ''},
},
soft = {
nom_sg = 'е', -- was: {'е', 'ё'}
gen_sg = 'я',
dat_sg = 'ю',
ins_sg = {'ем', 'ём'},
nom_pl = 'я',
gen_pl = {'ь', 'ей'},
},
},
common = { -- common endings
hard = {
prp_sg = {'е', 'е'},
dat_pl = 'ам',
ins_pl = 'ами',
prp_pl = 'ах',
},
soft = {
prp_sg = {'е', 'е'},
dat_pl = 'ям',
ins_pl = 'ями',
prp_pl = 'ях',
},
}
}
end
local function get_stress_flags(stress_type)
return {
stem = {
sg = _.equals(stress_type, {"a", "c", "e"}) and stressed or unstressed,
acc_sg = _.equals(stress_type, {"a", "c", "e", "d'", "f'"}) and stressed or unstressed,
ins_sg = _.equals(stress_type, {"a", "c", "e", "b'", "f''"}) and stressed or unstressed,
pl = _.equals(stress_type, {"a", "d", "d'"}) and stressed or unstressed,
nom_pl = _.equals(stress_type, {"a", "d", "d'", "e", "f", "f'", "f''"}) and stressed or unstressed,
},
ending = {
sg = _.equals(stress_type, {"b", "b'", "d", "d'", "f", "f'", "f''"}) and stressed or unstressed,
acc_sg = _.equals(stress_type, {"b", "b'", "d", "f", "f''"}) and stressed or unstressed,
ins_sg = _.equals(stress_type, {"b", "d", "d'", "f", "f'"}) and stressed or unstressed,
pl = _.equals(stress_type, {"b", "b'", "c", "e", "f", "f'", "f''"}) and stressed or unstressed,
nom_pl = _.equals(stress_type, {"b", "b'", "c"}) and stressed or unstressed,
}
}
end
local function get_stem_type(z)
if _.endswith(z.stem, '[гкх]') then
z.stem_type = 'velar'
elseif _.endswith(z.stem, '[жчшщ]') then
z.stem_type = 'sibilant'
elseif _.endswith(z.stem, 'ц') then
z.stem_type = 'letter-ц'
elseif _.endswith(z.stem, {'[йь]', '[аоеёуыэюя]'}) then
z.stem_type = 'vowel'
elseif _.endswith(z.stem, 'и') then
z.stem_type = 'letter-и'
else
if z.gender == 'm' then
if z.stem == z.word or _.endswith(z.word, 'ы') then
z.stem_type = 'hard'
elseif _.endswith(z.word, 'путь') then
z.stem_type = 'm-3rd'
elseif _.endswith(z.word, 'ь') or _.endswith(z.word, 'и') then
z.stem_type = 'soft'
elseif _.endswith(z.word, 'а') then
z.gender = 'f'
z.stem_type = 'hard'
elseif _.endswith(z.word, 'я') then
z.gender = 'f'
z.stem_type = 'soft'
end
elseif z.gender == 'f' then
if _.endswith(z.word, 'а') or _.endswith(z.word, 'ы') then
z.stem_type = 'hard'
elseif _.endswith(z.word, 'я') or _.endswith(z.word, 'и') then
z.stem_type = 'soft'
elseif _.endswith(z.word, 'ь') then -- conflict in pl
z.stem_type = 'f-3rd'
end
elseif z.gender == 'n' then
if _.endswith(z.word, 'о') or _.endswith(z.word, 'а') then
z.stem_type = 'hard'
elseif _.endswith(z.word, 'е') or _.endswith(z.word, 'я') then
z.stem_type = 'soft'
elseif _.endswith(z.word, 'мя') or _.endswith(z.word, 'мена') then
z.stem_type = 'n-3rd'
end
end
end
if z.gender == 'm' then
if _.endswith(z.word, {'а', 'я'}) then
z.gender = 'f'
end
end
if z.gender == 'f' and z.stem_type == 'sibilant' and _.endswith(z.word, 'ь') then
z.stem_type = 'f-3rd-sibilant'
end
if z.stem_type == '' then
z.stem_type = 'hard'
end
end
local function change_endings_for_other_stem_types(z)
if _.equals(z.stem_type, {'velar', 'sibilant'}) then
-- Replace "ы" to "и"
z.e['f']['hard']['gen_sg'] = 'и'
z.e['m']['hard']['nom_pl'] = 'и'
z.e['f']['hard']['nom_pl'] = 'и'
end
if _.equals(z.stem_type, {'sibilant', 'letter-ц'}) then
-- Replace unstressed "о" to "е"
if z.stress_flags['ending']['sg'] == unstressed then
z.e['n']['hard']['nom_sg'] = 'е'
end
if z.stress_flags['ending']['ins_sg'] == unstressed then
z.e['m']['hard']['ins_sg'] = 'ем'
z.e['n']['hard']['ins_sg'] = 'ем'
z.e['f']['hard']['ins_sg'] = 'ей'
end
if z.stress_flags['ending']['pl'] == unstressed then
z.e['m']['hard']['gen_pl'] = {'ев', 'ев'} -- TODO: should we change stressed value here?
end
end
if _.equals(z.stem_type, 'sibilant') then
-- Replace "ов", "ев", "ёв" and null to "ей"
z.e['m']['hard']['gen_pl'] = {'ей', 'ей'}
z.e['n']['hard']['gen_pl'][stressed] = 'ей'
-- z.e['n']['hard']['gen_pl']_unstressed = '' this is just don't changed
z.e['f']['hard']['gen_pl'][stressed] = 'ей'
-- z.e['f']['hard']['gen_pl']_unstressed = '' this is just don't changed
end
if _.equals(z.stem_type, {'vowel', 'letter-и'}) then
-- Replace "ь" to "й"
z.e['m']['soft']['nom_sg'] = 'й'
z.e['n']['soft']['gen_pl'][unstressed] = 'й'
z.e['f']['soft']['gen_pl'][unstressed] = 'й'
end
if _.equals(z.stem_type, {'vowel', 'letter-и'}) then
-- Replace "ей" to "ев/ёв", and "ь,ей" to "й"
z.e['m']['soft']['gen_pl'] = {'ев', 'ёв'}
z.e['n']['soft']['gen_pl'] = {'й', 'й'}
z.e['f']['soft']['gen_pl'] = {'й', 'й'}
end
if _.equals(z.stem_type, 'letter-и') then
z.e['f']['soft']['dat_sg'][unstressed] = 'и'
z.e['common']['soft']['prp_sg'][unstressed] = 'и'
end
if _.equals(z.stem_type, 'm-3rd') then
z.e['m']['soft']['gen_sg'] = 'и'
z.e['m']['soft']['dat_sg'] = 'и'
z.e['common']['soft']['prp_sg'] = {'и', 'и'}
end
if _.equals(z.stem_type, {'f-3rd', 'f-3rd-sibilant'}) then
z.e['f']['soft']['nom_sg'] = 'ь'
z.e['f']['soft']['dat_sg'] = {'и', 'и'}
z.e['f']['soft']['acc_sg'] = 'ь'
z.e['f']['soft']['ins_sg'] = {'ью', 'ью'}
z.e['common']['soft']['prp_sg'] = {'и', 'и'}
z.e['f']['soft']['gen_pl'] = {'ей', 'ей'}
end
if _.equals(z.stem_type, 'f-3rd-sibilant') then
z.e['common']['soft']['dat_pl'] = 'ам'
z.e['common']['soft']['ins_pl'] = 'ами'
z.e['common']['soft']['prp_pl'] = 'ах'
end
end
local function apply_specific_1_2(z)
-- If we have specific (1) or (2)
if _.contains(z.specific, '%(1%)') then
z.e['m']['hard']['nom_pl'] = 'а'
z.e['m']['soft']['nom_pl'] = 'я'
z.e['n']['hard']['nom_pl'] = 'ы'
z.e['n']['soft']['nom_pl'] = 'и'
if _.equals(z.stem_type, {'velar', 'sibilant'}) then
-- Replace "ы" to "и"
z.e['n']['hard']['nom_pl'] = 'и'
end
end
if _.contains(z.specific, '%(2%)') then
z.e['m']['hard']['gen_pl'] = {'', ''}
z.e['m']['soft']['gen_pl'] = {'ь', 'ь'}
z.e['n']['hard']['gen_pl'] = {'ов', 'ов'}
z.e['n']['soft']['gen_pl'] = {'ев', 'ёв'}
z.e['f']['hard']['gen_pl'] = {'ей', 'ей'}
z.e['f']['soft']['gen_pl'] = {'ей', 'ей'}
if _.equals(z.stem_type, {'sibilant', 'letter-ц'}) then
-- Replace unstressed "о" to "е"
z.e['n']['hard']['gen_pl'][unstressed] = 'ев'
end
--[=[ Possibly we don't need this:
-- Replace "ов", "ев", "ёв" and null to "ей"
if z.stem_type = {'sibilant'}}
z.e['n']['hard']['gen_pl'] = {'ей', 'ей'}
z.e['m']['hard']['gen_pl'][stressed] = 'ей'
end
-- Replace "ь" to "й"
if z.stem_type = {'vowel', 'letter-и'}}
z.e['m']['soft']['gen_pl'][stressed] = {'й', 'й'}
end
-- Replace "ей" to "ев/ёв", and "ь,ей" to "й"
if z.stem_type = {'vowel', 'letter-и'}}
z.e['f']['soft']['gen_pl'][unstressed] = {'ев', 'ёв'}
z.e['m']['soft']['gen_pl'][stressed] = {'й', 'й'}
end
]=]--
end
end
local function choose(endings, case, type)
endings[case] = endings[case][type]
end
local function choose_stress_for_endings(z)
local s
s = z.stress_flags['ending']['sg']
choose(z.e['f']['soft'], 'dat_sg', s)
choose(z.e['common']['hard'], 'prp_sg', s)
choose(z.e['common']['soft'], 'prp_sg', s)
s = z.stress_flags['ending']['ins_sg']
choose(z.e['m']['soft'], 'ins_sg', s)
choose(z.e['n']['soft'], 'ins_sg', s)
choose(z.e['f']['soft'], 'ins_sg', s)
s = z.stress_flags['ending']['pl']
choose(z.e['m']['hard'], 'gen_pl', s)
choose(z.e['m']['soft'], 'gen_pl', s)
choose(z.e['n']['hard'], 'gen_pl', s)
choose(z.e['n']['soft'], 'gen_pl', s)
choose(z.e['f']['hard'], 'gen_pl', s)
choose(z.e['f']['soft'], 'gen_pl', s)
end
local function choose_endings_by_stem_type(z)
local base_stem_type
if _.equals(z.stem_type, {'hard', 'soft'}) then
base_stem_type = z.stem_type
elseif _.equals(z.stem_type, {'velar', 'sibilant', 'letter-ц'}) then
base_stem_type = 'hard'
elseif _.equals(z.stem_type, {'vowel', 'letter-и', 'm-3rd', 'f-3rd', 'f-3rd-sibilant'}) then
base_stem_type = 'soft'
else
return {error_msg = 'Unexpected internal error: Unknown stem type'}
end
for key, value in pairs(z.e['common'][base_stem_type]) do
z.e[z.gender][base_stem_type][key] = value
end
z.endings = z.e[z.gender][base_stem_type]
end
local function add_stress(endings, case)
endings[case] = _.replace(endings[case], '^({vowel})', '%1́ ')
end
local function apply_stress_type(z)
if z.stress_flags['stem']['sg'] == stressed then
z.stems['sg'] = z.stem_stressed
else
z.stems['sg'] = z.stem
add_stress(z.endings, 'nom_sg')
add_stress(z.endings, 'gen_sg')
add_stress(z.endings, 'dat_sg')
add_stress(z.endings, 'prp_sg')
end
if z.stress_flags['stem']['ins_sg'] == stressed then
z.stems['ins_sg'] = z.stem_stressed
else
z.stems['ins_sg'] = z.stem
add_stress(z.endings, 'ins_sg')
end
if z.gender == 'f' then
if z.stress_flags['stem']['acc_sg'] == stressed then
z.stems['acc_sg'] = z.stem_stressed
else
z.stems['acc_sg'] = z.stem
add_stress(z.endings, 'acc_sg')
end
end
if z.stress_flags['stem']['nom_pl'] == stressed then
z.stems['nom_pl'] = z.stem_stressed
else
z.stems['nom_pl'] = z.stem
add_stress(z.endings, 'nom_pl')
end
if z.stress_flags['stem']['pl'] == stressed then
z.stems['pl'] = z.stem_stressed
else
z.stems['pl'] = z.stem
add_stress(z.endings, 'gen_pl')
add_stress(z.endings, 'dat_pl')
add_stress(z.endings, 'ins_pl')
add_stress(z.endings, 'prp_pl')
end
end
local function apply_specific_degree(z)
-- If degree sign °
if _.endswith(z.word, '[ая]нин') and z.animacy == 'an' and z.word ~= 'семьянин' then
z.stems['pl'] = _.replace(z.stems['pl'], '([ая])ни́ н$', '%1́ н')
z.stems['pl'] = _.replace(z.stems['pl'], '([ая]́ ?н)ин$', '%1')
z.stems['nom_pl'] = _.replace(z.stems['nom_pl'], '([ая])ни́ н$', '%1́ н')
z.stems['nom_pl'] = _.replace(z.stems['nom_pl'], '([ая]́ ?н)ин$', '%1')
z.endings['nom_pl'] = 'е'
z.endings['gen_pl'] = ''
z.specific = z.specific .. '°'
end
if _.endswith(z.word, {'ёнок', 'онок', 'ёночек', 'оночек'}) then
if _.endswith(z.word, 'ёнок') then
z.stems['pl'] = _.replace(z.stems['pl'], 'ёнок$', 'я́т')
z.stems['nom_pl'] = _.replace(z.stems['nom_pl'], 'ёнок$', 'я́т')
end
if _.endswith(z.word, 'онок') then
z.stems['pl'] = _.replace(z.stems['pl'], 'о́нок$', 'а́т')
z.stems['nom_pl'] = _.replace(z.stems['nom_pl'], 'о́нок$', 'а́т')
end
if _.endswith(z.word, 'ёночек') then
z.stems['pl'] = _.replace(z.stems['pl'], 'ёночек$', 'я́тк')
z.stems['nom_pl'] = _.replace(z.stems['nom_pl'], 'ёночек$', 'я́тк')
end
if _.endswith(z.word, 'оночек') then
z.stems['pl'] = _.replace(z.stems['pl'], 'о́ночек$', 'а́тк')
z.stems['nom_pl'] = _.replace(z.stems['nom_pl'], 'о́ночек$', 'а́тк')
end
z.endings['nom_pl'] = z.e['f']['hard']['nom_pl']
z.endings['gen_pl'] = z.e['f']['hard']['gen_pl']
z.specific = z.specific .. '*'
z.specific = z.specific .. '°'
end
end
local function apply_specific_reducable(z)
if _.contains(z.specific, '%*') then
if z.gender == 'm' then
reduced = 'A'
elseif z.gender == 'n' then
reduced = 'B'
elseif z.gender == 'f' then
if _.equals(z.stem_type, {'f-3rd', 'f-3rd-sibilant'}) then
reduced = 'A'
else
reduced = 'B'
end
end
if reduced == 'A' then
reduced_letter = _.extract(z.word, '({vowel+ё}){consonant}+$')
if reduced_letter == 'о' then
z.stems['sg'] = _.replace(z.stems['sg'], 'о́ ?([^о]+)$', '%1')
if not _.equals(z.stem_type, {'f-3rd', 'f-3rd-sibilant'}) then
z.stems['ins_sg'] = _.replace(z.stems['ins_sg'], 'о́ ?([^о]+)$', '%1')
end
z.stems['pl'] = _.replace(z.stems['pl'], 'о́ ?([^о]+)$', '%1')
z.stems['nom_pl'] = _.replace(z.stems['nom_pl'], 'о́ ?([^о]+)$', '%1')
elseif _.equals(reduced_letter, {'е', 'ё'}) then
prev = _.extract(z.word, '(.)[её][^её]+$')
if _.contains(prev, '{vowel+ё}') then -- 1).
z.stems['sg'] = _.replace(z.stems['sg'], '[её]́ ?([^её]+)$', 'й%1')
if not _.equals(z.stem_type, {'f-3rd', 'f-3rd-sibilant'}) then
z.stems['ins_sg'] = _.replace(z.stems['ins_sg'], '[её]́ ?([^её]+)$', 'й%1')
end
z.stems['pl'] = _.replace(z.stems['pl'], '[её]́ ?([^её]+)$', 'й%1')
z.stems['nom_pl'] = _.replace(z.stems['nom_pl'], '[её]́ ?([^её]+)$', 'й%1')
elseif z.stem_type == 'vowel' -- 2) а).
or z.stem_type == 'velar' and _.contains(prev, '[^аеёиоуыэюяшжчщц]') -- 2) б).
or not _.equals(z.stem_type, {'vowel', 'velar'}) and prev == 'л' then -- 2) в).
z.stems['sg'] = _.replace(z.stems['sg'], '[её]́ ?([^её]*)$', 'ь%1')
if not _.equals(z.stem_type, {'f-3rd', 'f-3rd-sibilant'}) then
z.stems['ins_sg'] = _.replace(z.stems['ins_sg'], '[её]́ ?([^её]*)$', 'ь%1')
end
z.stems['pl'] = _.replace(z.stems['pl'], '[её]́ ?([^её]*)$', 'ь%1')
z.stems['nom_pl'] = _.replace(z.stems['nom_pl'], '[её]́ ?([^её]*)$', 'ь%1')
else -- 3).
z.stems['sg'] = _.replace(z.stems['sg'], '[её]́ ?([^её]*)$', '%1')
if not _.equals(z.stem_type, {'f-3rd', 'f-3rd-sibilant'}) then
z.stems['ins_sg'] = _.replace(z.stems['ins_sg'], '[её]́ ?([^её]*)$', '%1')
end
z.stems['pl'] = _.replace(z.stems['pl'], '[её]́ ?([^её]*)$', '%1')
z.stems['nom_pl'] = _.replace(z.stems['nom_pl'], '[её]́ ?([^её]*)$', '%1')
end
end
end -- reduced A
-- TODO: pcerhaps this line is redundant?
z.stems['gen_pl'] = z.stems['pl'] -- apply changes in stems['pl'] for stems['gen_pl']
if reduced == 'B' and
not (z.stem_type == 'soft' and _.equals(z.stress_type, {'b', 'f'}) -- we should ignore asterix for 2*b and 2*f (so to process it just like 2b or 2f)
or _.contains(z.specific, '(2)') and _.equals(z.stem_type, {'velar', 'letter-ц', 'vowel'})) -- and also the same for (2)-specific and 3,5,6 stem-types
then
if z.stem_type == 'vowel' then -- 1).
if _.equals(z.stress_type, {'b', 'c', 'e', 'f', "f'", "b'" }) then -- gen_pl ending stressed -- TODO: special vars for that
z.stems['gen_pl'] = _.replace(z.stems['gen_pl'], 'ь$', 'е́')
else
z.stems['gen_pl'] = _.replace(z.stems['gen_pl'], 'ь$', 'и')
end
elseif _.contains(z.stem, '[ьй]{consonant}$') then -- 2).
if z.stem_type == 'letter-ц' or _.equals(z.stress_type, {'a', 'd', "d'"}) then -- gen_pl ending unstressed -- TODO: special vars for that
z.stems['gen_pl'] = _.replace(z.stems['gen_pl'], '[ьй]({consonant})$', 'е%1')
else
z.stems['gen_pl'] = _.replace(z.stems['gen_pl'], '[ьй]({consonant})$', 'ё%1')
end
else -- 3).
prev = _.extract(z.stem, '(.){consonant}$')
if z.stem_type == 'velar' and _.contains(prev, '[^жшчщц]') -- 3). а).
or _.contains(prev, '[кгх]') then -- 3). б).
z.stems['gen_pl'] = _.replace(z.stems['gen_pl'], '(.)({consonant})$', '%1о%2')
else -- 3). в).
if z.stem_type == 'letter-ц' then
z.stems['gen_pl'] = _.replace(z.stems['gen_pl'], '(.)({consonant})$', '%1е%2')
else
if _.equals(z.stress_type, {'b', 'c', 'e', 'f', "f'", "b'" }) then -- gen_pl ending stressed -- TODO: special vars for that
if _.contains(prev, '[жшчщ]') then
z.stems['gen_pl'] = _.replace(z.stems['gen_pl'], '(.)({consonant})$', '%1о́%2')
else
z.stems['gen_pl'] = _.replace(z.stems['gen_pl'], '(.)({consonant})$', '%1ё%2')
end
else
z.stems['gen_pl'] = _.replace(z.stems['gen_pl'], '(.)({consonant})$', '%1е%2')
end
end
end
end
if z.stem_type == 'soft' and _.endswith(z.word, 'ня') and z.stress_type == 'a' then
z.endings['gen_pl'] = ''
end
end -- reduced B
end -- specific *
end
local function choose_accusative_forms(z, forms)
forms['acc_sg_in'] = ''
forms['acc_sg_an'] = ''
forms['acc_pl_in'] = ''
forms['acc_pl_an'] = ''
if z.gender == 'n' then
forms['acc_sg'] = forms['nom_sg']
elseif z.gender == 'm' then
if z.animacy == 'in' then
forms['acc_sg'] = forms['nom_sg']
elseif z.animacy == 'an' then
forms['acc_sg'] = forms['gen_sg']
else
forms['acc_sg_in'] = forms['nom_sg']
forms['acc_sg_an'] = forms['gen_sg']
end
elseif z.gender == 'f' then
if _.equals(z.stem_type, {'f-3rd', 'f-3rd-sibilant'}) then
forms['acc_sg'] = forms['nom_sg']
else
forms['acc_sg'] = z.stems['acc_sg'] .. z.endings['acc_sg']
end
end
if z.animacy == 'in' then
forms['acc_pl'] = forms['nom_pl']
elseif z.animacy == 'an' then
forms['acc_pl'] = forms['gen_pl']
else
forms['acc_pl_in'] = forms['nom_pl']
forms['acc_pl_an'] = forms['gen_pl']
end
end
function get_zaliznyak_index(z)
local stem_types = {
['hard'] = '1',
['soft'] = '2',
['velar'] = '3',
['sibilant'] = '4',
['letter-ц'] = '5',
['vowel'] = '6',
['letter-и'] = '7',
['m-3rd'] = '8',
['f-3rd'] = '8',
['f-3rd-sibilant'] = '8',
['n-3rd'] = '8',
}
local index = z.gender_animacy .. ' ' .. stem_types[z.stem_type]
if _.contains(z.specific, '°') then
index = index .. '°'
elseif _.contains(z.specific, '%*') then
index = index .. '*'
end
index = index .. _.replace(z.stress_type, "'", "'")
if _.contains(z.specific, '%(1%)') then
index = index .. '①'
end
if _.contains(z.specific, '%(2%)') then
index = index .. '②'
end
if _.contains(z.specific, '%(3%)') then
index = index .. '③'
end
if _.contains(z.specific, 'ё') then
index = index .. ', ё'
end
return index
end
function export.forms(base, args)
_.clear_stash()
_.add_stash('{vowel}', '[аеиоуыэюяАЕИОУЫЭЮЯ]')
_.add_stash('{vowel+ё}', '[аеёиоуыэюяАЕЁИОУЫЭЮЯ]')
_.add_stash('{consonant}', '[^аеёиоуыэюяАЕЁИОУЫЭЮЯ]')
local z = {}
z.e = get_standard_endings()
z.word_stressed = args['word_stressed']
if _.contains_several(z.word_stressed, '{vowel+ё}') and not _.contains(z.word_stressed, '[́ ё]') then
return {error_msg = 'Error in template {{ru-decl-noun-z}}: You should add stress mark for the argument "word_stressed"'}
end
z.word = _.replace(z.word_stressed, '́ ', '')
-- Parse "gender_animacy" argument and get values for "gender" and "animacy"'
z.gender_animacy = args['gender_animacy']
z.gender = _.extract(z.gender_animacy, '([mnf])%-[a-z]+')
z.animacy = _.extract(z.gender_animacy, '[mnf]%-([a-z]+)')
z.stress_type = args['stress_type']
if not _.equals(z.stress_type, {'a', 'b', "b'", 'c', 'd', "d'", 'e', 'f', "f'", "f''"}) then
return {error_msg = 'Error in template {{ru-decl-noun-z}}: Wrong value for the argument "stress_type"'}
end
z.stress_flags = get_stress_flags(z.stress_type)
z.specific = args['specific']
-- Remove ending (-а, -е, -ё, -о, -я, -й, -ь) to get stem
z.stem = _.replace(z.word, '[аеёояйьиы]$', '')
z.stem_stressed = _.replace(z.word_stressed, '[аеёиоыяйь]́ ?$', '')
-- Add stress to stem_stressed if stress is absent (i.e. there is only one syllable or stress was on the ending)
if not _.contains(z.stem_stressed, '[́ ё]') then
if _.equals(z.stress_type, {"f", "f'"}) then
z.stem_stressed = _.replace(z.stem_stressed, '^({consonant}*)({vowel})', '%1%2́ ')
else
-- if _.equals(stress_type, {'a', "b'", 'b', 'c', 'd', "d'", 'e'}) then
z.stem_stressed = _.replace(z.stem_stressed, '({vowel})({consonant}*)$', '%1́ %2')
end
-- TODO: process cases with * (stress on penultimate syllable)
end
-- Determination of stem type
get_stem_type(z)
-- Special changes in endings for velar, sibilant, vowel etc. stem types
change_endings_for_other_stem_types(z)
-- apply special cases (1) or (2) in specific
apply_specific_1_2(z)
-- Resolve stressed/unstressed cases of endings
choose_stress_for_endings(z)
if z.gender == 'n' and _.endswith(z.word, 'ё') then
z.e['n']['soft']['nom_sg'] = 'ё'
end
-- Choose endings by stem type and gender (either 'hard' or 'soft' key from changed "z.e")
choose_endings_by_stem_type(z)
-- If we have "ё" specific
if _.contains(z.specific, 'ё') then
z.stem_stressed = _.replace(z.stem_stressed, 'е́?([^е]*)$', 'ё%1')
end
z.stems = {}
apply_stress_type(z)
apply_specific_degree(z)
-- Changes for reduceable cases
z.stems['nom_sg'] = z.stems['sg'] -- *save* unchanged stem value for nominative singular
z.stems['gen_pl'] = z.stems['pl'] -- set default stem value for genitive plural
apply_specific_reducable(z)
-- If we have "ё" specific
if _.contains(z.specific, 'ё') and not _.contains(z.endings['gen_pl'], '{vowel+ё}') and not _.contains(z.stems['gen_pl'], 'ё') then
z.stems['gen_pl'] = _.replace(z.stems['gen_pl'], 'е́?([^е]*)$', 'ё%1')
z.specific = z.specific .. 'ё'
end
-- Generate forms
local forms = {
nom_sg = z.stems['nom_sg'] .. z.endings['nom_sg'],
gen_sg = z.stems['sg'] .. z.endings['gen_sg'],
dat_sg = z.stems['sg'] .. z.endings['dat_sg'],
acc_sg = '',
ins_sg = z.stems['ins_sg'] .. z.endings['ins_sg'],
prp_sg = z.stems['sg'] .. z.endings['prp_sg'],
nom_pl = z.stems['nom_pl'] .. z.endings['nom_pl'],
gen_pl = z.stems['gen_pl'] .. z.endings['gen_pl'],
dat_pl = z.stems['pl'] .. z.endings['dat_pl'],
acc_pl = '',
ins_pl = z.stems['pl'] .. z.endings['ins_pl'],
prp_pl = z.stems['pl'] .. z.endings['prp_pl'],
}
-- Add stress if there is no one
if _.contains_several(forms['nom_sg'], '{vowel}') and not _.contains(forms['nom_sg'], '[́ ё]') then
-- perhaps this is redundant for nom_sg?
forms['nom_sg'] = _.replace(forms['nom_sg'], '({vowel})({consonant}*)$', '%1́ %2')
end
if _.contains_several(forms['gen_pl'], '{vowel+ё}') and not _.contains(forms['gen_pl'], '[́ ё]') then
forms['gen_pl'] = _.replace(forms['gen_pl'], '({vowel})({consonant}*)$', '%1́ %2')
end
for key, value in pairs(forms) do
-- Remove stress if there is only one syllable
if _.contains_once(value, '{vowel+ё}') then
forms[key] = _.replace(value, '́ ', '')
end
-- Replace 'ё' with 'е' when unstressed
if _.contains_once(value, 'ё') and _.contains(value, '́ ') then
forms[key] = _.replace(value, 'ё', 'е')
end
end
choose_accusative_forms(z, forms)
-- partitive case
if args['par'] and args['par'] ~= '' then
forms['par'] = forms['dat_sg']
end
-- locative case
if args['loc'] and args['loc'] ~= '' then
loc = forms['dat_sg']
loc = _.replace(loc, '́ ', '')
loc = _.replace(loc, 'ё', 'е')
loc = _.replace(loc, '({vowel})({consonant}*)$', '%1́ %2')
forms['loc'] = loc
if args['loc'] == 'в' or args['loc'] == 'на' then
forms['loc_preposition'] = '(' .. args['loc'] .. ')'
else
forms['loc_preposition'] = '(в, на) '
end
end
forms['stem_type'] = z.stem_type -- for testcases
forms['stress_type'] = z.stress_type -- for categories
forms['index'] = get_zaliznyak_index(z)
forms['dev'] = dev_prefix
local keys = {
'nom_sg', 'gen_sg', 'dat_sg', 'acc_sg', 'ins_sg', 'prp_sg',
'nom_pl', 'gen_pl', 'dat_pl', 'acc_pl', 'ins_pl', 'prp_pl',
'voc', 'n', 'note',
}
for i, key in pairs(keys) do
if args[key] and args[key] ~= '' then
forms[key] = args[key]
end
--[=[ -- I think we don't need this here, let's do it in template
if form_key == 'nom_sg' then
if forms[form_key] and forms[form_key] ~= '' then
value = forms[form_key]
transliterated = lang:transliterate(m_links.remove_links(value))
link = m_links.full_link(value, nil, lang, nil, nil, nil, {tr = "-"}, false)
forms[form_key] = strutils.format("{link}<br/><span style='color: #888'>{transliterated}</span>", {link=link, transliterated=transliterated})
else
forms[form_key] = '—'
end
end
]=]--
end
return forms
end
return export