Module:gmh-verb
Jump to navigation
Jump to search
- This module lacks a documentation subpage. Please create it.
- Useful links: subpage list • links • transclusions • testcases • sandbox
local export = {}
--[=[
Authorship: Zhnka
]=]
--[=[
TERMINOLOGY:
-- "slot" = A particular combination of tense/mood/person/number/etc.
Example slot names for verbs are "pres_1s" (present first singular) and
"subc_subii_3p" (subordinate-clause subjunctive II third plural).
Each slot is filled with zero or more forms.
-- "form" = The conjugated German form representing the value of a given slot.
-- "lemma" = The dictionary form of a given German term. For German, always the infinitive.
]=]
--[=[
FIXME:
1. Handle fensterln. (DONE)
2. Handle spie- past tense of speien. (DONE)
3. Make sure rathen, verheirathen work. (DONE)
4. Modify einfix to better handle managen, framen. (DONE)
5. Use variant codes so variant imperatives with and without -e match up in conjoined verbs e.g. [[ausschneiden und einfügen]].
6. In conjoined verbs e.g. [[ausschneiden und einfügen]], don't repeat auxiliaries.
--]=]
local lang = require("Module:languages").getByCode("gmh")
local m_string_utilities = require("Module:string utilities")
local m_links = require("Module:links")
local m_table = require("Module:table")
local iut = require("Module:inflection utilities")
local rfind = mw.ustring.find
local rmatch = mw.ustring.match
local rsplit = mw.text.split
local function link_term(term, face)
return m_links.full_link({ lang = lang, term = term }, face)
end
local vowel = "aeiouyäëïöüÿáéíóúýàèìòùỳāēīōūŷãẽĩõũỹâêîôû"
local vowel_c = "[" .. vowel .. "]"
local not_vowel_c = "[^" .. vowel .. "]"
local function ends_in_dt(stem)
return stem:find("[dt]h?$")
end
local inseparable_prefixes = {
"be", "emp", "ent", "er", "ge", "miss", "miß", "ver", "zer",
-- can also be separable
"durch", "hinter", "über", "um", "unter", "voll", "wider", "wieder",
}
local all_persons_numbers = {
["1s"] = "1|s",
["2s"] = "2|s",
["3s"] = "3|s",
["1p"] = "1|p",
["2p"] = "2|p",
["3p"] = "3|p",
}
local person_number_list = { "1s", "2s", "3s", "1p", "2p", "3p", }
local persnum_to_index = {}
for k, v in pairs(person_number_list) do
persnum_to_index[v] = k
end
local imp_person_number_list = { "2s", "2p", }
local verb_slots_basic = {
{"infinitive", "inf"},
{"infinitive_linked", "inf"},
{"ger_gen", "ger|gen"},
{"ger_dat", "ger|dat"},
{"pres_part", "pres|part"},
{"perf_part", "perf|part"},
{"zu_infinitive", "zu"}, -- will be handled specially by [[Module:accel/de]]
{"aux", "-"},
}
local verb_slots_subordinate_clause = {
}
local verb_slots_composed = {
}
-- Add entries for a slot with person/number variants.
-- `verb_slots` is the table to add to.
-- `slot_prefix` is the prefix of the slot, typically specifying the tense/aspect.
-- `tag_suffix` is the set of inflection tags to add after the person/number tags,
-- or "-" to use "-" as the inflection tags (which indicates that no accelerator entry
-- should be generated).
local function add_slot_personal(verb_slots, slot_prefix, tag_suffix)
for persnum, persnum_tag in pairs(all_persons_numbers) do
local slot = slot_prefix .. "_" .. persnum
if tag_suffix == "-" then
table.insert(verb_slots, {slot, "-"})
else
table.insert(verb_slots, {slot, persnum_tag .. "|" .. tag_suffix})
end
end
end
add_slot_personal(verb_slots_basic, "pres", "pres")
add_slot_personal(verb_slots_basic, "subi", "sub|I")
add_slot_personal(verb_slots_basic, "pret", "pret")
add_slot_personal(verb_slots_basic, "subii", "sub|II")
table.insert(verb_slots_basic, {"imp_2s", "s|imp"})
table.insert(verb_slots_basic, {"imp_2p", "p|imp"})
add_slot_personal(verb_slots_subordinate_clause, "subc_pres", "dep|pres")
add_slot_personal(verb_slots_subordinate_clause, "subc_subi", "dep|sub|I")
add_slot_personal(verb_slots_subordinate_clause, "subc_pret", "dep|pret")
add_slot_personal(verb_slots_subordinate_clause, "subc_subii", "dep|sub|II")
add_slot_personal(verb_slots_composed, "perf_ind", "-")
add_slot_personal(verb_slots_composed, "perf_sub", "-")
add_slot_personal(verb_slots_composed, "plup_ind", "-")
add_slot_personal(verb_slots_composed, "plup_sub", "-")
table.insert(verb_slots_composed, {"futi_inf", "-"})
add_slot_personal(verb_slots_composed, "futi_subi", "-")
add_slot_personal(verb_slots_composed, "futi_ind", "-")
add_slot_personal(verb_slots_composed, "futi_subii", "-")
table.insert(verb_slots_composed, {"futii_inf", "-"})
add_slot_personal(verb_slots_composed, "futii_subi", "-")
add_slot_personal(verb_slots_composed, "futii_ind", "-")
add_slot_personal(verb_slots_composed, "futii_subii", "-")
local all_verb_slots = {}
for _, slot_and_accel in ipairs(verb_slots_basic) do
table.insert(all_verb_slots, slot_and_accel)
end
for _, slot_and_accel in ipairs(verb_slots_subordinate_clause) do
table.insert(all_verb_slots, slot_and_accel)
end
for _, slot_and_accel in ipairs(verb_slots_composed) do
table.insert(all_verb_slots, slot_and_accel)
end
local pronouns = { "ich", "du", "ër", "wir", "ir", "sie", }
irreg_verbs = {
["hān"] = {
["pres"] = { "hān", "hāst", "hāt", "hān", "hāt", "hānt", },
["pret"] = { "habete", "habetest", "habete", "habeten", "habetet", "habeten", },
["subi"] = { "habe", "habest", "habe", "haben", "habet", "haben", },
["subii"] = { "habete", "habetest", "habete", "habeten", "habetet", "habeten", },
["imp"] = { "habe", "habet", },
["presp"] = "hānde",
["pp"] = "habet",
["gergen"] = {"hānnes", "hānes"},
["gerdat"] = {"hānne", "hāne"},
},
["sīn"] = {
["pres"] = { "bin", "bist", "ist", "birn", "birt", "sint", },
["pret"] = { "was", "wære", "was", "wāren", "wāret", "wāren", },
["subi"] = { "sī", "sīst", "sī", "sīn", "sīt", "sīn", },
["subii"] = { "wære", "wærest", "wære", "wæren", "wæret", "wæren", },
["imp"] = { {"wis", "bis"}, "sīt", },
["presp"] = {"sīnde", "wësende"},
["pp"] = "wësen",
["gergen"] = {"sīnnes", "sīnes", "wësennes", "wësenes"},
["gerdat"] = {"sīnne", "sīne", "wësenne", "wësene"},
},
["tuon"] = {
["pres"] = { "tuon", "tuost", "tuot", "tuon", "tuot", "tuont", },
["pret"] = { "tëte", "tæte", "tëte", "tæten", "tætet", "tæten", },
["subi"] = { "tuo", "tuost", "tuo", "tuon", "tuot", "tuon", },
["subii"] = { "tæte", "tætest", "tæte", "tæten", "tætet", "tæten", },
["imp"] = { "tuo", "tuot", },
["presp"] = "tuonde",
["pp"] = "tān",
["gergen"] = {"tuonnes", "tuones"},
["gerdat"] = {"tuonne", "tuone"},
},
["lān"] = {
["pres"] = { "lān", "lāst", "lāt", "lān", "lāt", "lānt", },
["pret"] = { "lie", "lieȥest", "lie", "lieȥen", "lieȥet", "lieȥen", },
["subi"] = { "lāȥe", "lāȥest", "lāȥe", "lāȥen", "lāȥet", "lāȥen", },
["subii"] = { "lieȥe", "lieȥest", "lieȥe", "lieȥen", "lieȥet", "lieȥen", },
["imp"] = { "lā", "lāt", },
["presp"] = "lāȥende",
["pp"] = "lān",
["gergen"] = {"lānnes", "lānes"},
["gerdat"] = {"lānne", "lāne"},
},
["gān"] = {
["pres"] = { "gān", "gāst", "gāt", "gān", "gāt", "gānt", },
["pret"] = { "gienc", "gienge", "gienc", "giengen", "gienget", "giengen", },
["subi"] = { "gē", "gēst", "gē", "gēn", "gēt", "gēn", },
["subii"] = { "gienge", "giengest", "gienge", "giengen", "gienget", "giengen", },
["imp"] = { "gā", "gāt", },
["presp"] = "gānde",
["pp"] = {"gān", "gangen"},
["gergen"] = {"gānnes", "gānes"},
["gerdat"] = {"gānne", "gāne"},
},
["stān"] = {
["pres"] = { "stān", "stāst", "stāt", "stān", "stāt", "stānt", },
["pret"] = { "stuont", "stüende", "stuont", "stuonden", "stuondet", "stuonden", },
["subi"] = { "stē", "stēst", "stē", "stēn", "stēt", "stēn", },
["subii"] = { "stüende", "stüendest", "stüende", "stüenden", "stüendet", "stüenden", },
["imp"] = { "stā", "stāt", },
["presp"] = "stānde",
["pp"] = {"stān", "standen"},
["gergen"] = {"stānnes", "stānes"},
["gerdat"] = {"stānne", "stāne"},
},
["wellen"] = {
["pres"] = { "wil", "wilt", "wil", "wellen", "wellet", "wellen", },
["pret"] = { "wolte", "woltest", "wolte", "wolten", "woltet", "wolten", },
["subi"] = { "welle", "wellest", "welle", "wellen", "wellet", "wellen", },
["subii"] = { "wolte", "woltest", "wolte", "wolten", "woltet", "wolten", },
["imp"] = { "", "", },
["presp"] = "wellende",
["pp"] = "wolt",
["gergen"] = {"wellennes", "wellenes"},
["gerdat"] = {"wellenne", "wellene"},
},
["süln"] = {
["pres"] = { "sol", "solt", "sol", "sulen", "sulet", "sulen", },
["pret"] = {
{"wurde", {form = "ward", footnotes = {"[archaic]"}}},
{"wurdest", {form = "wardst", footnotes = {"[archaic]"}}},
{"wurde", {form = "ward", footnotes = {"[archaic]"}}},
"wurden",
"wurdet",
"wurden",
},
["subi"] = { "sul", "sule", "sul", "suln", "sulet", "suln", },
["subii"] = { {"sölte", "sölde"}, {"söltest", "söldest"}, {"sölte", "sölde"}, {"sölten", "sölden"}, {"söltet", "söldet"}, {"sölten", "sölden"}, },
["imp"] = { {"werd", "werde"}, "werdet", },
["presp"] = "werdend",
["pp"] = "worden",
},
}
local sin_forms = {
["sīn"] = {"mīn", "dīn", "sīn", "unser", "iuwer", "ir"},
["sīne"] = {"mīne", "dīne", "sīne", "unsere", "iuwere", "ire"},
["sīnen"] = {"mīnen", "dīnen", "sīnen", "unseren", "iuweren", "iren"},
["sīnem"] = {"mīnem", "dīnem", "sīnem", "unserem", "iuwerem", "irem"},
["sīner"] = {"mīner", "dīner", "sīner", "unserer", "iuwerer", "irer"},
["sīnes"] = {"mīnes", "dīnes", "sīnes", "unseres", "iuweres", "ires"},
["sīniu"] = {"mīniu", "dīniu", "sīniu", "unseriu", "iuweriu", "iriu"},
["sīneȥ"] = {"mīneȥ", "dīneȥ", "sīneȥ", "unseres", "iuwereȥ", "ireȥ"},
}
local sich_forms = {
["accpron"] = {"mich", "dich", "sich", "unsich", "euch", "sich"},
["datpron"] = {"mir", "dir", "im", "uns", "eu", "in"},
}
local function skip_slot(base, slot)
if not slot:find("[123]") then
-- Don't skip non-personal slots.
return false
end
if base.nofinite then
return true
end
if base.only3s and not slot:find("3s") or
base.only3sp and not slot:find("3[sp]") then
return true
end
return false
end
local function strip_spaces(text)
return text:gsub("^%s*(.-)%s*", "%1")
end
local function escape_sin_sich_indicators(arg1)
if not arg1:find("pron>") then
return arg1
end
local segments = iut.parse_balanced_segment_run(arg1, "<", ">")
-- Loop over every other segment. The even-numbered segments are angle-bracket specs while
-- the odd-numbered segments are the text between them.
for i = 2, #segments - 1, 2 do
if segments[i] == "<accpron>" then
segments[i] = "⦃⦃accpron⦄⦄"
elseif segments[i] == "<datpron>" then
segments[i] = "⦃⦃datpron⦄⦄"
elseif segments[i] == "<pron>" then
segments[i] = "⦃⦃pron⦄⦄"
end
end
return table.concat(segments)
end
local function undo_escape_form(form)
-- assign to var to throw away second value
local newform = form:gsub("⦃⦃", "<"):gsub("⦄⦄", ">")
return newform
end
local function remove_sin_sich_indicators(form)
-- assign to var to throw away second value
local newform = form:gsub("⦃⦃.-⦄⦄", "")
return newform
end
local function replace_sin_sich_indicators(slot, form)
if not form:find("⦃") then
return form
end
local persnum = slot:match("^.*_([123][sp])$")
local index
if persnum then
index = persnum_to_index[persnum]
else
index = 3
end
form = form:gsub("sich(%]*)⦃⦃accpron⦄⦄", function(brackets)
return sich_forms.accpron[index] .. brackets
end)
form = form:gsub("sich(%]*)⦃⦃datpron⦄⦄", function(brackets)
return sich_forms.datpron[index] .. brackets
end)
form = form:gsub("(sine?[mnrs]?)(%]*)⦃⦃pron⦄⦄", function(sin_form, brackets)
if sin_forms[sin_form] then
return sin_forms[sin_form][index] .. brackets
else
error("Unrecognized sin-form '" .. sin_form .. "' in slot " .. slot .. ": " .. undo_escape_form(form))
end
end)
form = form:gsub("sīn%]%](e?[mnrsȥ]?)⦃⦃pron⦄⦄", function(sin_ending, brackets)
local sin_form = "sīn" .. sin_ending
if sin_forms[sin_form] then
return sin_forms["sīn"][index] .. "|" .. sin_forms[sin_form][index] .. "]]"
else
error("Unrecognized sīn-form '" .. sin_form .. "' in slot " .. slot .. ": " .. undo_escape_form(form))
end
end)
if form:find("⦃⦃") or form:find("⦄⦄") then
error("Unrecognized pronoun substitution in slot " .. slot .. ": " .. undo_escape_form(form))
end
return form
end
local function combine_stem_ending(slot, stem, ending)
local ending_with_pound = ending .. "#"
if ending_with_pound:find("^st[ #]") then
if rfind(stem, "[sxzȥ]$") then
ending = ending:gsub("^s", "")
elseif stem:find("st$") then
-- bersten
ending = ending:gsub("^st", "")
end
elseif ending_with_pound:find("^t[ #]") and stem:find("th?$") then
ending = ending:gsub("^t", "")
end
return replace_sin_sich_indicators(slot, stem .. ending)
end
local function add(base, slot, stems, endings, footnotes)
if skip_slot(base, slot) then
return
end
local function do_combine_stem_ending(stem, ending)
return combine_stem_ending(slot, stem, ending)
end
iut.add_forms(base.forms, slot, stems, endings, do_combine_stem_ending, nil, nil,
iut.combine_footnotes(footnotes, base.all_footnotes))
end
local function add_multi(base, slot, stems_and_endings, footnotes)
if skip_slot(base, slot) then
return
end
local function do_combine_stem_ending(stem, ending)
return combine_stem_ending(slot, stem, ending)
end
iut.add_multiple_forms(base.forms, slot, stems_and_endings, do_combine_stem_ending, nil, nil,
iut.combine_footnotes(footnotes, base.all_footnotes))
end
local function add3(base, slot, stems1, stems2, endings, footnotes)
return add_multi(base, slot, {stems1, stems2, endings})
end
local function add4(base, slot, stems1, stems2, stems3, endings, footnotes)
return add_multi(base, slot, {stems1, stems2, stems3, endings})
end
local function add5(base, slot, stems1, stems2, stems3, stems4, endings, footnotes)
return add_multi(base, slot, {stems1, stems2, stems3, stems4, endings})
end
local function add_zu_infinitive(base)
if base.any_pre_pref then
local zu
if base.pre_pref == "" or base.pre_pref:find(" $") then
zu = "zu "
else
zu = "zu"
end
add(base, "zu_infinitive", base.pre_pref .. zu, base.bare_infinitive)
end
end
local function add_present(base, pretpres)
local stems = base.infstem
local stems23 = base.pres_23 or stems
local function doadd(slot_pref, form_pref)
-- Do forms based off the infinitive stem.
for _, stemform in ipairs(stems) do
prefixed_stem = form_pref .. stemform.form
local function addit(slot, stem, ending, footnotes)
add(base, slot_pref .. slot, stem, ending .. (slot_pref == "" and base.post_pref or ""),
iut.combine_footnotes(footnotes, stemform.footnotes))
end
-- plural present indicative
if base.unstressed_el_er or base.unstressed_erl then
addit("pres_1p", prefixed_stem, "n")
addit("pres_2p", prefixed_stem, "t")
addit("pres_3p", prefixed_stem, "nt")
else
addit("pres_1p", prefixed_stem, "en")
addit("pres_2p", prefixed_stem, "et")
addit("pres_3p", prefixed_stem, "ent")
end
-- subjunctive I
if base.unstressed_el_er then
addit("subi_1s", prefixed_stem, "")
addit("subi_2s", prefixed_stem, "st")
addit("subi_3s", prefixed_stem, "")
addit("subi_2p", prefixed_stem, "t")
else
addit("subi_1s", prefixed_stem, "e")
addit("subi_2s", prefixed_stem, "est")
addit("subi_3s", prefixed_stem, "e")
addit("subi_2p", prefixed_stem, "et")
end
if base.unstressed_el_er then
addit("subi_1p", prefixed_stem, "n")
addit("subi_3p", prefixed_stem, "n")
else
addit("subi_1p", prefixed_stem, "en")
addit("subi_3p", prefixed_stem, "en")
end
if slot_pref == "" and not pretpres then
if base.unstressed_el_er then
addit("imp_2p", prefixed_stem, "t")
else
addit("imp_2p", prefixed_stem, "et")
end
end
end
-- Do forms based off of pres23 stem (also includes pres_1sg in preterite-present verbs).
for _, stem23form in ipairs(stems23) do
local prefixed_stem23 = form_pref .. stem23form.form
if not base.pres_23 then
for _, class in ipairs(base.verb_types) do
if class:find("^2$") then
prefixed_stem23 = prefixed_stem:gsub("(ie)(" .. not_vowel_c .. "*)$", "iu%2")
elseif class:find("^3$") then
prefixed_stem23 = prefixed_stem:gsub("(ë)(" .. not_vowel_c .. "*)$", "i%2")
elseif class:find("^[45]$") then
prefixed_stem23 = prefixed_stem:gsub("(ë)(" .. not_vowel_c .. "*)$", "i%2")
prefixed_stem23 = prefixed_stem23:gsub("(e)(" .. not_vowel_c .. "*)$", "i%2")
prefixed_stem_komen = prefixed_stem:gsub("(o)(" .. not_vowel_c .. "*)$", "u%2")
elseif class:find("^6$") then
prefixed_stem_only23 = prefixed_stem:gsub("(a)(" .. not_vowel_c .. "*)$", "e%2")
elseif class:find("^7$") then
prefixed_stem232 = prefixed_stem:gsub("(a)(" .. not_vowel_c .. "*)$", "e%2")
prefixed_stem232 = prefixed_stem232:gsub("(ā)(" .. not_vowel_c .. "*)$", "æ%2")
end
end
end
local function addit(slot, stem, ending, footnotes)
add(base, slot_pref .. slot, stem, ending .. (slot_pref == "" and base.post_pref or ""),
iut.combine_footnotes(footnotes, stem23form.footnotes))
end
if pretpres then
-- Totally different code for preterite-present singular and imperative.
addit("pres_1s", prefixed_stem23, "")
addit("pres_2s", prefixed_stem23, "st")
addit("pres_3s", prefixed_stem23, "")
if slot_pref == "" and base.base_verb == "wiȥȥen" then
addit("imp_2s", "weiȥ", "")
-- dewikt mentions 'wisset' as an alternative, but not in Duden
addit("imp_2p", "wiȥȥ", "et")
end
else
-- present 2/3 singular
if base.unstressed_el_er or prefixed_stem23:find("[iī]$") then
addit("pres_1s", prefixed_stem23, "")
addit("pres_2s", prefixed_stem_only23 or prefixed_stem23, "st")
addit("pres_3s", prefixed_stem_only23 or prefixed_stem23, "t")
else
addit("pres_1s", prefixed_stem23, "e")
addit("pres_2s", prefixed_stem_only23 or prefixed_stem23, "est")
addit("pres_3s", prefixed_stem_only23 or prefixed_stem23, "et")
end
if prefixed_stem232 and prefixed_stem232 ~= prefixed_stem and base.unstressed_el_er then
addit("pres_2s", prefixed_stem232, "st")
addit("pres_3s", prefixed_stem232, "t")
elseif prefixed_stem232 and prefixed_stem232 ~= prefixed_stem then
addit("pres_2s", prefixed_stem232, "est")
addit("pres_3s", prefixed_stem232, "et")
end
if prefixed_stem_komen and prefixed_stem_komen ~= prefixed_stem then
addit("pres_1s", prefixed_stem_komen, "e")
addit("pres_2s", prefixed_stem_komen, "est")
addit("pres_3s", prefixed_stem_komen, "et")
addit("subi_1s", prefixed_stem_komen, "e")
addit("subi_2s", prefixed_stem_komen, "est")
addit("subi_3s", prefixed_stem_komen, "e")
end
-- imperative singular; this may or may not be based off the pres23 stem
-- Specifically, if the pres23 stem is different from the infinitive stem and does not have an ä or ö
-- in it ([[fahren]], er [[fährt]] but imperative [[fahr]]/[[fahre]]; [[stoßen]], er [[stößt]] but
-- imperative [[stoß]]/[[stoße]]), use it. Don't add -e unless '.longimp' is given (for [[sehen]], with
-- imperatives [[sieh]] and [[siehe]]; but normally [[geben]] with imperative only [[gib]], similarly
-- for [[treten]], [[gelten]], [[bergen]], [[etc.]]). In all other cases, use the infinitive stem, and
-- under normal circumstances include two variants, without -e and with -e. We include only the variant
-- with -e if '.e' is given ([[atmen]], [[zeichnen]], etc.), and we include only the variant without -e
-- if '.shortimp' is given (unclear if this is needed for any verb).
if slot_pref == "" then
if base.unstressed_el_er then
addit("imp_2s", prefixed_stem23, "")
elseif base.weak_past then
addit("imp_2s", prefixed_stem23, "e")
else
local prefixed_stem23 = prefixed_stem23:gsub("g$", "c")
local prefixed_stem23 = prefixed_stem23:gsub("b$", "p")
local prefixed_stem23 = prefixed_stem23:gsub("d$", "t")
local prefixed_stem_imp = prefixed_stem23:gsub("v$", "f")
local double_consonant = prefixed_stem23:match("(.)$")
if prefixed_stem23:match("^.*(.)$") == prefixed_stem23:match("^.*(.).$") then
prefixed_stem_imp = prefixed_stem_imp:match("^(.*).$")
end
addit("imp_2s", prefixed_stem_imp, "")
end
end
end
end
end
-- Do the basic forms
doadd("", "")
-- Also do the subordinate clause forms if any alternants have a prefix.
if base.any_pre_pref then
doadd("subc_", base.pre_pref)
end
-- Do the miscellaneous non-finite forms
add3(base, "ger_gen", base.pre_pref, base.bare_infinitive, {"nes", "es"})
add3(base, "ger_dat", base.pre_pref, base.bare_infinitive, {"ne", "e"})
add3(base, "pres_part", base.pre_pref, base.bare_infinitive, "de")
add_zu_infinitive(base)
end
function add_past_or_subii(base, pretpres)
local past_stems = base.past
function doadd(slot_pref, form_pref)
-- Do forms based off the infinitive stem.
for _, stemform in ipairs(past_stems) do
local past = form_pref .. stemform.form
local ends_in_e = past:find("e$")
local function addit(slot, stem, ending, footnotes)
add(base, slot_pref .. slot, stem, ending .. (slot_pref == "" and base.post_pref or ""),
iut.combine_footnotes(footnotes, stemform.footnotes))
end
if base.past_sub then
for _, pastsubb in ipairs(base.past_sub) do
past_sub_base = form_pref .. pastsubb.form
end
end
if base.past_plural then
for _, pastplurall in ipairs(base.past_plural) do
past_plural_base = form_pref .. pastplurall.form
end
end
past_less = past:gsub("g$", "c")
past_less = past_less:gsub("b$", "p")
past_less = past_less:gsub("d$", "t")
past_less = past_less:gsub("v$", "f")
if past_less:match("^.*(.)$") == past_less:match("^.*(.).$") then
past_less = past_less:match("^(.*).$")
end
if not base.past_sub then
for _, class in ipairs(base.verb_types) do
if class:find("^1$") then
past_sub = past:gsub("(ei)(" .. not_vowel_c .. "*)$", "i%2")
past_sub = past_sub:gsub("(ē)(" .. not_vowel_c .. "*)$", "i%2")
past_plural = past_sub
elseif class:find("^2$") then
past_sub = past:gsub("(ou)(" .. not_vowel_c .. "*)$", "ü%2")
past_plural = past:gsub("(ou)(" .. not_vowel_c .. "*)$", "u%2")
past_sub = past_sub:gsub("(ō)(" .. not_vowel_c .. "*)$", "ü%2")
past_plural = past_plural:gsub("(ō)(" .. not_vowel_c .. "*)$", "u%2")
elseif class:find("^3$") then
past_sub = past:gsub("(a)(" .. not_vowel_c .. "*)$", "ü%2")
past_plural = past:gsub("(a)(" .. not_vowel_c .. "*)$", "u%2")
elseif class:find("^[45]$") then
past_sub = past:gsub("(a)(" .. not_vowel_c .. "*)$", "æ%2")
past_plural = past:gsub("(a)(" .. not_vowel_c .. "*)$", "ā%2")
elseif class:find("^6$") then
past_sub = past:gsub("(uo)(" .. not_vowel_c .. "*)$", "üe%2")
end
end
end
local final_past_sub = past_sub_base or past_sub or past
local final_past_plural = past_plural_base or past_plural or past
if not ends_in_e then
addit("pret_1s", past_less, "")
addit("pret_3s", past_less, "")
if base.unstressed_el_er then
addit("pret_1p", final_past_plural, "n")
addit("pret_2p", final_past_plural, "t")
addit("pret_3p", final_past_plural, "n")
else
addit("pret_1p", final_past_plural, "en")
addit("pret_2p", final_past_plural, "et")
addit("pret_3p", final_past_plural, "en")
end
if base.unstressed_el_er then
addit("pret_2s", final_past_sub, "")
addit("subii_1s", final_past_sub, "")
addit("subii_2s", final_past_sub, "st")
addit("subii_3s", final_past_sub, "")
addit("subii_1p", final_past_sub, "n")
addit("subii_2p", final_past_sub, "t")
addit("subii_3p", final_past_sub, "n")
else
addit("pret_2s", final_past_sub, "e")
addit("subii_1s", final_past_sub, "e")
addit("subii_2s", final_past_sub, "est")
addit("subii_3s", final_past_sub, "e")
addit("subii_1p", final_past_sub, "en")
addit("subii_2p", final_past_sub, "et")
addit("subii_3p", final_past_sub, "en")
end
else
addit("pret_1s", base.past, "")
addit("pret_2s", base.past, "st")
addit("pret_3s", base.past, "")
addit("pret_1p", base.past_plural or past_plural or past, "n")
addit("pret_2p", base.past_plural or past_plural or past, "t")
addit("pret_3p", base.past_plural or past_plural or past, "n")
addit("subii_1s", base.past_sub or past_sub or past, "")
addit("subii_2s", base.past_sub or past_sub or past, "st")
addit("subii_3s", base.past_sub or past_sub or past, "")
addit("subii_1p", base.past_sub or past_sub or past, "n")
addit("subii_2p", base.past_sub or past_sub or past, "t")
addit("subii_3p", base.past_sub or past_sub or past, "n")
end
end
end
-- Do the basic forms
doadd("", "")
-- Also do the subordinate clause forms if any alternants have a prefix.
if base.any_pre_pref then
doadd("subc_", base.pre_pref)
end
-- Do the miscellaneous non-finite forms
add3(base, "pres_part", base.pre_pref, base.bare_infinitive, "de")
add_zu_infinitive(base)
end
local conjs = {}
local conjprops = {}
conjs["normal"] = function(base)
add_present(base)
add_past_or_subii(base)
end
conjs["pretpres"] = function(base)
add_present(base, "pretpres")
add_past_or_subii(base)
end
conjs["irreg"] = function(base)
local function doadd(slot_pref)
local function addit(slot, forms, footnotes)
if slot_pref == "" then
add3(base, slot, base.insep_prefix, forms, base.post_pref, footnotes)
else
add(base, slot_pref .. slot, base.pre_pref .. base.insep_prefix, forms, footnotes)
end
end
-- Do present, preterite, subjunctive I and II.
for _, slot_tense in ipairs({"pres", "pret", "subi", "subii"}) do
for index, forms in ipairs(base.irregverbobj[slot_tense]) do
local persnum = person_number_list[index]
local footnotes
addit(slot_tense .. "_" .. persnum, forms, footnotes)
end
end
-- Do imperative.
if slot_pref == "" then
for index, forms in ipairs(base.irregverbobj["imp"]) do
local persnum = imp_person_number_list[index]
addit("imp_" .. persnum, forms)
end
end
end
-- Do the basic forms
doadd("")
-- Also do the subordinate clause forms if any alternants have a prefix.
if base.any_pre_pref then
doadd("subc_")
end
-- Do the miscellaneous non-finite forms
iut.add_multiple_forms(base, "pp", {base.ge_prefix, base.insep_prefix, base.irregverbobj["pp"]},
-- We don't want to use combine_stem_ending because we want sin-sich indicators to be left alone,
-- so they get replaced later when constructing composed forms.
function(stem, ending) return stem .. ending end)
add(base, "perf_part", base.pre_pref, base.pp)
-- only [[werden]] by itself; not [[loswerden]], [[fertigwerden]], etc.
if base.lemma == "süln" then
iut.insert_form(base.forms, "perf_part", {form = "worden", footnotes = {"[as an auxiliary]"}})
end
add(base, "pres_part", base.pre_pref .. base.insep_prefix, base.irregverbobj["presp"])
add(base, "ger_gen", base.pre_pref .. base.insep_prefix, base.irregverbobj["gergen"])
add(base, "ger_dat", base.pre_pref .. base.insep_prefix, base.irregverbobj["gerdat"])
add_zu_infinitive(base)
end
local function add_composed_forms(base)
local forms = base.forms
local function add_composed(tense_mood, index, persnum, auxforms, participle, suffix, footnotes)
local pers_auxforms = iut.convert_to_general_list_form(auxforms[index])
local linked_pers_auxforms = iut.map_forms(pers_auxforms, function(form) return "[[" .. form .. "]] " end)
add4(base, tense_mood .. "_" .. persnum, linked_pers_auxforms, "[[" .. base.pre_pref, participle, "]]" .. suffix, footnotes)
end
local function add_composed_perf(tense_mood, index, persnum, han_auxforms, sin_auxforms, han_suffix, sin_suffix)
for _, auxform in ipairs(base.aux) do
if auxform.form == "hān" then
add_composed(tense_mood, index, persnum, han_auxforms, base.pp, han_suffix, auxform.footnotes)
end
if auxform.form == "sīn" then
add_composed(tense_mood, index, persnum, sin_auxforms, base.pp, sin_suffix, auxform.footnotes)
end
end
end
local han_forms = irreg_verbs["hān"]
local sin_forms = irreg_verbs["sīn"]
local suln_forms = irreg_verbs["süln"]
for index, persnum in ipairs(person_number_list) do
add_composed_perf("perf_ind", index, persnum, han_forms["pres"], sin_forms["pres"], "", "")
add_composed_perf("perf_sub", index, persnum, han_forms["subi"], sin_forms["subi"], "", "")
add_composed_perf("plup_ind", index, persnum, han_forms["pret"], sin_forms["pret"], "", "")
add_composed_perf("plup_sub", index, persnum, han_forms["subii"], sin_forms["subii"], "", "")
for _, mood in ipairs({"ind", "subi", "subii"}) do
local tense = mood == "ind" and "pres" or mood
add_composed("futi_" .. mood, index, persnum, suln_forms[tense], base.bare_infinitive, "")
add_composed_perf("futii_" .. mood, index, persnum, suln_forms[tense], suln_forms[tense], " [[hān]]", " [[sīn]]")
end
end
add3(base, "futi_inf", "[[" .. base.pre_pref, base.bare_infinitive, "]] [[süln]]")
add5(base, "futii_inf", "[[" .. base.pre_pref, base.pp, "]] [[", base.aux, "]] [[süln]]")
end
local function handle_derived_slots(base)
-- Compute linked versions of potential lemma slots, for use in {{de-verb}}.
-- We substitute the original lemma (before removing links) for forms that
-- are the same as the lemma, if the original lemma has links.
for _, slot in ipairs({"infinitive"}) do
iut.insert_forms(base.forms, slot .. "_linked", iut.map_forms(base.forms[slot], function(form)
if form == base.lemma and rfind(base.linked_lemma, "%[%[") then
return base.linked_lemma
else
return form
end
end))
end
end
local function conjugate_verb(base)
if not conjs[base.conj] then
error("Internal error: Unrecognized conjugation type '" .. base.conj .. "'")
end
conjs[base.conj](base)
add_composed_forms(base)
-- No overrides implemented currently.
-- process_slot_overrides(base)
handle_derived_slots(base)
end
local function parse_indicator_spec(angle_bracket_spec)
local base = {}
local function parse_err(msg)
error(msg .. ": " .. angle_bracket_spec)
end
local function fetch_footnotes(separated_group)
local footnotes
for j = 2, #separated_group - 1, 2 do
if separated_group[j + 1] ~= "" then
parse_err("Extraneous text after bracketed footnotes: '" .. table.concat(separated_group) .. "'")
end
if not footnotes then
footnotes = {}
end
table.insert(footnotes, separated_group[j])
end
return footnotes
end
local function fetch_specs(comma_separated_group, transform_form)
if not comma_separated_group then
return {{}}
end
local specs = {}
local colon_separated_groups = iut.split_alternating_runs(comma_separated_group, ":")
for _, colon_separated_group in ipairs(colon_separated_groups) do
local form = colon_separated_group[1]
if transform_form then
form = transform_form(form)
end
table.insert(specs, {form = form, footnotes = fetch_footnotes(colon_separated_group)})
end
return specs
end
local inside = angle_bracket_spec:match("^<(.*)>$")
assert(inside)
if inside == "" then
return base
end
local segments = iut.parse_balanced_segment_run(inside, "[", "]")
local dot_separated_groups = iut.split_alternating_runs(segments, "%.")
for i, dot_separated_group in ipairs(dot_separated_groups) do
local comma_separated_groups = iut.split_alternating_runs(dot_separated_group, "%s*[,#]%s*", "preserve splitchar")
local first_element = comma_separated_groups[1][1]
if first_element == "hān" or first_element == "sīn" then
for j = 1, #comma_separated_groups, 2 do
if j > 1 and strip_spaces(comma_separated_groups[j - 1][1]) ~= "," then
parse_err("Separator of # not allowed with hān or sīn")
end
local aux = comma_separated_groups[j][1]
if aux ~= "hān" and aux ~= "sīn" then
parse_err("Unrecognized auxiliary '" .. aux .. "'")
end
if base.aux then
for _, existing_aux in ipairs(base.aux) do
if existing_aux.form == aux then
parse_err("Auxiliary '" .. aux .. "' specified twice")
end
end
else
base.aux = {}
end
table.insert(base.aux, {form = aux, footnotes = fetch_footnotes(comma_separated_groups[j])})
end
elseif first_element == "-ge" or first_element == "+ge" then
for j = 1, #comma_separated_groups, 2 do
if j > 1 and strip_spaces(comma_separated_groups[j - 1][1]) ~= "," then
parse_err("Separator of # not allowed with +ge or -ge")
end
local prefix = comma_separated_groups[j][1]
if prefix ~= "+ge" and prefix ~= "-ge" then
parse_err("Unrecognized ge- prefix '" .. prefix .. "'")
end
local ge_prefix
if prefix == "+ge" then
ge_prefix = "ge"
else
ge_prefix = ""
end
if base.ge_prefix then
for _, existing_prefix in ipairs(base.ge_prefix) do
if existing_prefix.form == ge_prefix then
parse_err("Ge- prefix '" .. prefix .. "' specified twice")
end
end
else
base.ge_prefix = {}
end
table.insert(base.ge_prefix, {form = ge_prefix, footnotes = fetch_footnotes(comma_separated_groups[j])})
end
elseif #comma_separated_groups > 1 then
-- principal parts specified
if base.past then
parse_err("Can't specify principal parts twice")
end
local parts = {}
assert(#comma_separated_groups[2] == 1)
local past_index
local first_separator = strip_spaces(comma_separated_groups[2][1])
if first_separator == "#" then
-- present 3rd singular specified
base.pres_23 = fetch_specs(comma_separated_groups[1], function(form)
local stem
if base.conj == "pretpres" then
stem = form
else
stem = form:match("^(.-)%-$")
if not stem then
stem = form:match("^(.-)e?t$")
end
end
if stem then
return stem
else
parse_err("Present 3sg form '" .. form .. "' should end in - (for the stem) or -t")
end
end)
past_index = 3
else
past_index = 1
end
base.past = fetch_specs(comma_separated_groups[past_index], function(form)
return form
end)
if #comma_separated_groups < past_index + 2 then
parse_err("Missing past participle spec")
end
assert(#comma_separated_groups[past_index + 1] == 1)
if strip_spaces(comma_separated_groups[past_index + 1][1]) ~= "," then
parse_err("Only first separator can be a #")
end
base.pp = fetch_specs(comma_separated_groups[past_index + 2], function(form)
if form:find("[ndt]$") then
return form
else
parse_err("Past participle '" .. form .. "' should end in -n, -t, or -d")
end
end)
if #comma_separated_groups > past_index + 2 then
assert(#comma_separated_groups[past_index + 3] == 1)
if strip_spaces(comma_separated_groups[past_index + 3][1]) ~= "," then
parse_err("Only first separator can be a #")
end
base.past_sub = fetch_specs(comma_separated_groups[past_index + 4], function(form)
local stem = form:match("^(.-)e$")
if not stem then
parse_err("Past subjunctive '" .. form .. "' should end in -e")
end
return stem
end)
end
if #comma_separated_groups > past_index + 4 then
assert(#comma_separated_groups[past_index + 4] == 1)
base.past_plural = fetch_specs(comma_separated_groups[past_index + 6], function(form)
return form
end)
if #comma_separated_groups > past_index + 6 then
parse_err("Too many specs given")
end
end
elseif first_element == "pretpres" or first_element == "irreg" then
if #comma_separated_groups[1] > 1 then
parse_err("No footnotes allowed with '" .. first_element .. "' spec")
end
if base.conj then
parse_err("Conjugation specified as '" .. first_element .. "' but already specified or autodetermined as '" .. base.conj .. "'")
end
base.conj = first_element
elseif first_element == "shortimp" or first_element == "longimp" or
first_element == "only3s" or first_element == "only3sp" or
first_element == "nofinite" then
if #comma_separated_groups[1] > 1 then
parse_err("No footnotes allowed with '" .. first_element .. "' spec")
end
base[first_element] = true
elseif first_element == "" or first_element == "inf" then
local footnotes = fetch_footnotes(comma_separated_groups[1])
if not footnotes then
parse_err("Empty spec and 'inf' spec without footnotes not allowed")
end
if first_element == "inf" then
base.infstem_footnotes = footnotes
else
base.all_footnotes = footnotes
end
else
parse_err("Unrecognized spec '" .. comma_separated_groups[1][1] .. "'")
end
end
return base
end
-- Normalize all lemmas, splitting off separable prefixes and substituting the pagename for blank lemmas.
local function normalize_all_lemmas(alternant_multiword_spec, from_headword)
local any_pre_pref
iut.map_word_specs(alternant_multiword_spec, function(base)
if base.lemma == "" then
local PAGENAME = mw.title.getCurrentTitle().text
base.lemma = PAGENAME
end
if base.lemma:find("_") and not base.lemma:find("%[%[") then
-- If lemma is multiword and has no links, add links automatically.
base.lemma= "[[" .. base.lemma:gsub("_", "]]_[[") .. "]]"
end
base.orig_lemma = base.lemma
base.orig_lemma_no_links = m_links.remove_links(base.lemma)
-- Normalize the linked lemma by removing dot, underscore, and <pron> and such indicators.
base.linked_lemma = remove_sin_sich_indicators(base.lemma:gsub("%.", ""):gsub("_", " "))
base.lemma = m_links.remove_links(base.linked_lemma)
local lemma = base.orig_lemma_no_links
base.pre_pref, base.post_pref = "", ""
local prefix, verb = lemma:match("^(.*)_(.-)$")
if prefix then
prefix = prefix:gsub("_", " ") -- in case of multiple preceding words
base.pre_pref = base.pre_pref .. prefix .. " "
base.post_pref = base.post_pref .. " " .. prefix
else
verb = lemma
end
prefix, base.base_verb = verb:match("^(.*)%.(.-)$")
if prefix then
-- There may be multiple separable prefixes (e.g. [[wiedergutmachen]], ich mache wieder gut)
base.pre_pref = base.pre_pref .. prefix:gsub("%.", "")
base.post_pref = base.post_pref .. " " .. prefix:gsub("%.", " ")
else
base.base_verb = verb
end
if base.pre_pref ~= "" then
any_pre_pref = true
end
if base.only3s then
alternant_multiword_spec.only3s = true
end
if base.only3sp then
alternant_multiword_spec.only3sp = true
end
-- Remove <pron> indicators and such.
local reconstructed_lemma = remove_sin_sich_indicators(base.pre_pref .. base.base_verb)
if reconstructed_lemma ~= base.lemma then
error("Internal error: Raw lemma '" .. base.lemma .. "' differs from reconstructed lemma '" .. reconstructed_lemma .. "'")
end
base.from_headword = from_headword
end)
if any_pre_pref then
iut.map_word_specs(alternant_multiword_spec, function(base)
base.any_pre_pref = true
end)
end
if alternant_multiword_spec.only3s then
iut.map_word_specs(alternant_multiword_spec, function(base)
if not base.only3s then
error("If some alternants specify 'only3s', all must")
end
end)
end
if alternant_multiword_spec.only3sp then
iut.map_word_specs(alternant_multiword_spec, function(base)
if not base.only3sp then
error("If some alternants specify 'only3sp', all must")
end
end)
end
end
local function detect_verb_type(base, verb_types)
local this_verb_types = {}
local function set_verb_type()
base.verb_types = this_verb_types
if verb_types then
for _, verb_type in ipairs(this_verb_types) do
m_table.insertIfNot(verb_types, verb_type)
end
end
end
if base.conj == "pretpres" then
m_table.insertIfNot(this_verb_types, "pretpres")
set_verb_type()
return
elseif base.conj == "irreg" then
m_table.insertIfNot(this_verb_types, "irreg")
set_verb_type()
return
end
local infstem = m_table.deepcopy(base.infstem)
local past = m_table.deepcopy(base.past)
local pp = m_table.deepcopy(base.pp)
local past_sub = m_table.deepcopy(base.past_sub)
local past_plural = m_table.deepcopy(base.past_plural)
local function matches_forms(forms, expected, ending_to_chop)
expected = expected:gsub("C", not_vowel_c) .. "$"
local seen = false
for _, form in ipairs(forms) do
local stem
if ending_to_chop then
stem = rmatch(form.form, "^(.*)" .. ending_to_chop .. "$")
else
stem = form.form
end
if stem and rfind("#" .. stem, expected) then
seen = true
form.seen = form.seen or "maybe"
end
end
return seen
end
local function reset_maybes(forms, value)
for _, form in ipairs(forms) do
if form.seen == "maybe" then
form.seen = value
end
end
end
local function reset_all_maybes(value)
reset_maybes(infstem, value)
reset_maybes(past, value)
reset_maybes(pp, value)
end
local function has_unseen_weak_pp()
for _, form in ipairs(pp) do
if not form.seen and form.form:find("[dt]$") then
return true
end
end
return false
end
local function has_unseen_strong_pp()
for _, form in ipairs(pp) do
if not form.seen and form.form:find("n$") then
return true
end
end
return false
end
local function check(verbtype, infre, pastre, ppre, exclude)
if exclude then
for _, form in ipairs(infstem) do
if exclude(form.form) then
return
end
end
end
if matches_forms(infstem, infre) and
matches_forms(past, pastre) and
matches_forms(pp, ppre, "[elr]n") then
m_table.insertIfNot(this_verb_types, verbtype)
reset_all_maybes(true)
else
reset_all_maybes(false)
end
end
local function check_strong()
check("1", "CīC*", "CeiC*", "CiC*")
check("1", "CīC*", "CēC*", "CiC*")
check("2", "CieC*", "CouC*", "CoC*")
check("2", "CūC*", "CouC*", "CoC*")
check("2", "CiuwC*", "CouC*", "CūwC*")
check("2", "CieC*", "CōC*", "CoC*")
local function exclude_helfen(form)
return rfind(form, vowel_c .. "[lr]" .. not_vowel_c .. "$")
end
check("3", "CiC*", "CaC*", "CuC*")
check("3", "Cë[lr]C*", "Ca[lr]C*", "Co[lr]C*")
if not check("3", "Cë[lr]C*", "Ca[lr]C*", "Co[lr]C*") then
check("4", "C[ëeo]C*", "CaC*", "CoC*", exclude_helfen)
end
check("4", "kom", "quam", "kom")
check("5", "C*[ëi]C*", "C*aC*", "C*ëC*")
check("6", "C[aëe]C*", "CuoC*", "C[ao]C*")
check("7", "C[aā]C*", "CieC*", "C[aā]C*")
check("7", "C[aäe]C*", "CiC*", "CaC*")
check("7", "Ce[iy]C*", "CieC*", "Ce[iy]C*")
check("7", "CauC*", "CieC*", "CauC*")
check("7", "CoC*", "CieC*", "CoC*")
check("7", "CuC*", "CieC*", "CuC*")
check("7", "CouC*", "CieC*", "CouC*")
check("7", "CuoC*", "CieC*", "CuoC*")
end
for _, form in ipairs(past) do
local past_stem = form.form:match("^(.*)te$")
if past_stem then
if matches_forms(infstem, "#" .. past_stem) then
-- Need to run matches_forms() on all possibilities even if earlier ones match,
-- to mark the seen forms correctly.
local matches_pp = matches_forms(pp, "#" .. past_stem .. "et")
matches_pp = matches_forms(pp, "#ge" .. past_stem .. "et") or matches_pp
if matches_pp then
m_table.insertIfNot(this_verb_types, "weak")
form.seen = true
base.weak_past = true
reset_all_maybes(true)
else
reset_all_maybes(false)
end
end
end
if not form.seen and form.form:find("ete$") then
if matches_forms(infstem, "#" .. past_stem:gsub("e$", "")) then
-- Need to run matches_forms() on all possibilities even if earlier ones match,
-- to mark the seen forms correctly.
local matches_pp = matches_forms(pp, "#" .. past_stem .. "t")
matches_pp = matches_forms(pp, "#ge" .. past_stem .. "t") or matches_pp
matches_pp = matches_forms(pp, "#" .. past_stem .. "d") or matches_pp
matches_pp = matches_forms(pp, "#ge" .. past_stem .. "d") or matches_pp
if matches_pp then
m_table.insertIfNot(this_verb_types, "weak")
form.seen = true
reset_all_maybes(true)
else
reset_all_maybes(false)
end
end
end
if past_stem and not form.seen then
if not has_unseen_weak_pp() and has_unseen_strong_pp() then
m_table.insertIfNot(this_verb_types, "mixed")
else
m_table.insertIfNot(this_verb_types, "irregweak")
end
matches_forms(pp, "#" .. past_stem .. "t")
matches_forms(pp, "#ge" .. past_stem .. "t")
form.seen = true
reset_all_maybes(true)
base.weak_past = true
end
if not form.seen then
check_strong()
end
if not form.seen then
if not has_unseen_strong_pp() and has_unseen_weak_pp() then
m_table.insertIfNot(this_verb_types, "mixed")
else
m_table.insertIfNot(this_verb_types, "irregstrong")
end
end
end
for _, form in ipairs(pp) do
if not form.seen then
if form.form:find("n$") then
if m_table.contains(this_verb_types, "strong") then
m_table.insertIfNot(this_verb_types, "irregstrong")
elseif m_table.contains(this_verb_types, "weak") then
m_table.insertIfNot(this_verb_types, "mixed")
end
elseif form.form:find("[dt]$") then
if m_table.contains(this_verb_types, "weak") then
m_table.insertIfNot(this_verb_types, "irregweak")
elseif m_table.contains(this_verb_types, "strong") then
m_table.insertIfNot(this_verb_types, "mixed")
end
end
end
end
base.verb_types = this_verb_types
if verb_types then
for _, verb_type in ipairs(this_verb_types) do
m_table.insertIfNot(verb_types, verb_type)
end
end
set_verb_type()
end
local function detect_indicator_spec(base)
base.forms = {}
base.aux = base.aux or {{form = "hān"}}
base.bare_infinitive = {{form = base.base_verb, footnotes = base.infstem_footnotes}}
if base.base_verb == "sīn" then
add(base, "infinitive", base.pre_pref, {"sīn", "wësen"})
else
add(base, "infinitive", base.pre_pref, base.bare_infinitive)
end
if base.only3s and base.only3sp then
error("'only3s' and 'only3sp' cannot both be specified")
end
if base.conj == "irreg" then
for irregverb, verbobj in pairs(irreg_verbs) do
base.insep_prefix = base.base_verb:match("^(.-)" .. irregverb .. "$")
if base.insep_prefix then
base.irregverb = irregverb
base.irregverbobj = verbobj
if not base.ge_prefix then
if base.insep_prefix ~= "" then
base.ge_prefix = {{form = ""}}
else
base.ge_prefix = {{form = "ge"}}
end
end
return
end
end
error("Unrecognized irregular base verb '" .. base.base_verb .. "'")
end
-- The following applies to everything but 'irreg' verbs.
local infstem, infroot = base.base_verb:match("^((.*)[lr])n$")
if infstem then
base.unstressed_el_er = true
else
infstem, infroot = base.base_verb:match("^((.*)erl)n$")
if infstem then
base.unstressed_erl = true
else
infstem = base.base_verb:match("^(.*)en$")
infroot = infstem
if not infstem then
error("Unrecognized infinitive, should end in -en, -ln or -rn: '" .. base.base_verb .. "'")
end
end
end
base.infstem = {{form = infstem, footnotes = base.infstem_footnotes}}
if not base.conj then
base.conj = "normal"
end
if base.conj == "normal" then
local weak_past
if not base.past then
if base.unstressed_el_er then
weak_past = infstem .. "t"
else
weak_past = infstem .. "et"
end
base.past = {{form = weak_past .. "e"}}
base.weak_past = true
end
if not base.pp then
if not weak_past then
error("Internal error: past was explicitly given but not past participle")
end
if not base.ge_prefix then
local no_ge
for _, insep_prefix in ipairs(inseparable_prefixes) do
-- There must be a vowel following the inseparable prefix; excludes beben, bechern, belfern, bellen, bessern,
-- beten, betteln, betten, erben, erden, ernten, erzen, entern, gecken, gehren, gellen, gerben, geten, missen,
-- zergen, zerren, etc.
if rfind(infroot, "^" .. insep_prefix .. ".*" .. vowel_c .. ".*") and
-- Exclude cases like beigen, beichten, beugen, beulen, geifern; this also wrongly excludes
-- beirren, which needs -ge.
not rfind(infroot, "^[bg]e[iu]" .. not_vowel_c .. "*$") then
no_ge = true
break
end
-- Check for -ier preceded by a vowel (excludes bieren, frieren, gieren, schmieren, stieren, zieren, etc.)
if not base.unstressed_el_er and not base.unstressed_erl and rfind(infroot, "^.*" .. vowel_c .. ".*ier$") then
no_ge = true
break
end
end
if no_ge then
base.ge_prefix = {{form = ""}}
else
base.ge_prefix = {{form = "ge"}}
end
end
base.pp = iut.map_forms(base.ge_prefix, function(form)
return form .. base.base_verb:gsub("n$", "") .. "t"
end)
end
else
if not base.pp then
error("For '" .. base.conj .. "' type verbs, past participle must be explicitly given")
end
end
add(base, "perf_part", base.pre_pref, base.pp)
end
local function detect_all_indicator_specs(alternant_multiword_spec)
iut.map_word_specs(alternant_multiword_spec, function(base)
detect_indicator_spec(base)
detect_verb_type(base)
end)
end
-- Set the overall auxiliary or auxiliaries. We can't do this using the normal inflection
-- code as it will produce e.g. '[[haben]] und [[haben]]' for conjoined verbs.
local function compute_auxiliary(alternant_multiword_spec)
iut.map_word_specs(alternant_multiword_spec, function(base)
iut.insert_forms(alternant_multiword_spec.forms, "aux", base.aux)
end)
end
function export.process_verb_classes(classes)
local class_descs = {}
local cats = {}
local function insert_desc(desc)
m_table.insertIfNot(class_descs, desc)
end
local function insert_cat(cat)
m_table.insertIfNot(cats, "Middle High German " .. cat)
end
for _, class in ipairs(classes) do
if class == "weak" then
insert_desc("class 2 [[Appendix:Glossary#weak verb|weak]]")
insert_cat("weak verbs")
insert_cat("class 2 weak verbs")
elseif class == "irregweak" then
insert_desc("class 1 [[Appendix:Glossary#weak verb|weak]]")
insert_cat("weak verbs")
insert_cat("class 1 weak verbs")
elseif class == "pretpres" then
insert_desc("[[Appendix:Glossary#preterite-present verb|preterite-present]]")
insert_cat("preterite-present verbs")
elseif class == "irreg" then
insert_desc("[[Appendix:Glossary#irregular|irregular]]")
insert_cat("irregular verbs")
elseif class == "mixed" then
insert_desc("mixed")
insert_cat("mixed verbs")
elseif class == "irregstrong" then
insert_desc("[[Appendix:Glossary#irregular|irregular]] [[Appendix:Glossary#strong verb|strong]]")
insert_cat("strong verbs")
insert_cat("irregular strong verbs")
elseif class:find("^[1-7]$") then
insert_desc("class " .. class .. " [[Appendix:Glossary#strong verb|strong]]")
insert_cat("strong verbs")
insert_cat("class " .. class .. " strong verbs")
else
error("Unrecognized verb class '" .. class .. "'")
end
end
return class_descs, cats
end
local function add_categories_and_annotation(alternant_multiword_spec, base, from_headword, manual)
local function insert_cat(full_cat)
m_table.insertIfNot(alternant_multiword_spec.categories, full_cat)
end
if not from_headword then
for _, slot_and_accel in ipairs(all_verb_slots) do
local slot = slot_and_accel[1]
local forms = base.forms[slot]
local must_break = false
if forms then
for _, form in ipairs(forms) do
if not form.form:find("%[%[") then
local title = mw.title.new(form.form)
if title and not title.exists then
must_break = true
break
end
end
end
end
if must_break then
break
end
end
end
if manual then
return
end
local class_descs, cats = export.process_verb_classes(base.verb_types)
for _, desc in ipairs(class_descs) do
m_table.insertIfNot(alternant_multiword_spec.verb_types, desc)
end
-- Don't place multiword terms in categories like 'German class 4 strong verbs' to avoid spamming the
-- categories with such terms.
if from_headword and not base.lemma:find(" ") then
for _, cat in ipairs(cats) do
insert_cat(cat)
end
end
for _, aux in ipairs(base.aux) do
m_table.insertIfNot(alternant_multiword_spec.auxiliaries, link_term(aux.form, "term"))
if from_headword and not base.lemma:find(" ") then -- see above
insert_cat("Middle High German verbs using " .. aux.form .. " as auxiliary")
-- Set flags for use below in adding 'Middle High German verbs using hān and sīn as auxiliary'
alternant_multiword_spec["saw_" .. aux.form] = true
end
end
end
-- Compute the categories to add the verb to, as well as the annotation to display in the
-- conjugation title bar. We combine the code to do these functions as both categories and
-- title bar contain similar information.
local function compute_categories_and_annotation(alternant_multiword_spec, from_headword, manual)
alternant_multiword_spec.categories = {}
alternant_multiword_spec.verb_types = {}
alternant_multiword_spec.auxiliaries = {}
iut.map_word_specs(alternant_multiword_spec, function(base)
add_categories_and_annotation(alternant_multiword_spec, base, from_headword)
end)
if manual then
alternant_multiword_spec.annotation = ""
return
end
local ann_parts = {}
table.insert(ann_parts, table.concat(alternant_multiword_spec.verb_types, " or "))
if #alternant_multiword_spec.auxiliaries > 0 then
table.insert(ann_parts, ", auxiliary " .. table.concat(alternant_multiword_spec.auxiliaries, " or "))
end
if from_headword and alternant_multiword_spec.saw_han and alternant_multiword_spec.saw_sin then
m_table.insertIfNot(alternant_multiword_spec.categories, "Middle High German verbs using hān and sīn as auxiliary")
end
alternant_multiword_spec.annotation = table.concat(ann_parts)
end
local function show_forms(alternant_multiword_spec)
local lemmas = iut.map_forms(alternant_multiword_spec.forms.infinitive,
remove_sin_sich_indicators)
alternant_multiword_spec.lemmas = lemmas -- save for later use in make_table()
local linked_pronouns = {}
for index, pronoun in ipairs(pronouns) do
-- use 'es' instead of 'er' for 3s-only verbs
if index == 3 and alternant_multiword_spec.only3s then
linked_pronouns[index] = link_term("es")
else
linked_pronouns[index] = link_term(pronoun)
end
end
dass = link_term("dass") .. " "
local function generate_link(data)
local link = m_links.full_link {
lang = lang, term = data.form.formval_for_link, tr = "-", accel = data.form.accel_obj
}
local footnote_text = iut.get_footnote_text(data.form.footnotes, data.footnote_obj)
local persnum = data.slot:match("^imp_(2[sp])$")
if persnum then
link = link .. " (" .. linked_pronouns[persnum_to_index[persnum]] .. ")"
else
persnum = data.slot:match("^.*_([123][sp])$")
if persnum then
link = linked_pronouns[persnum_to_index[persnum]] .. " " .. link
end
if data.slot:find("^subc_") then
link = dass .. link
end
end
return link .. footnote_text
end
local function join_spans(data)
if data.slot == "aux" then
return table.concat(data.formval_spans, " or ")
else
return table.concat(data.formval_spans, "<br />")
end
end
local props = {
lang = lang,
lemmas = lemmas,
generate_link = generate_link,
join_spans = join_spans,
}
props.slot_list = verb_slots_basic
iut.show_forms(alternant_multiword_spec.forms, props)
alternant_multiword_spec.footnote_basic = alternant_multiword_spec.forms.footnote
props.slot_list = verb_slots_subordinate_clause
iut.show_forms(alternant_multiword_spec.forms, props)
alternant_multiword_spec.footnote_subordinate_clause = alternant_multiword_spec.forms.footnote
props.slot_list = verb_slots_composed
iut.show_forms(alternant_multiword_spec.forms, props)
alternant_multiword_spec.footnote_composed = alternant_multiword_spec.forms.footnote
end
local notes_template = [=[
<div style="width:100%;text-align:left;background:#d9ebff">
<div style="display:inline-block;text-align:left;padding-left:1em;padding-right:1em">
{footnote}
</div></div>
]=]
local basic_table = [=[
<div class="NavFrame" style="">
<div class="NavHead" style="">Conjugation of {title}</div>
<div class="NavContent">
{\op}| border="1px solid #000000" style="border-collapse:collapse; background:#fafafa; text-align:center; width:100%" class="inflection-table"
|-
! colspan="2" style="background:#d0d0d0" | <span title="Infinitiv">infinitive</span>
| colspan="4" | {infinitive}
|-
! colspan="2" style="background:#d0d0d0" | <span title="Genitive gerund">genitive gerund</span>
| colspan="4" | {ger_gen}
|-
! colspan="2" style="background:#d0d0d0" | <span title="Dative gerund">dative gerund</span>
| colspan="4" | {ger_dat}
|-
! colspan="2" style="background:#d0d0d0" | <span title="Partizip I (Partizip Präsens)">present participle</span>
| colspan="4" | {pres_part}
|-
! colspan="2" style="background:#d0d0d0" | <span title="Partizip II (Partizip Perfekt)">past participle</span>
| colspan="4" | {perf_part}
|-
! colspan="2" style="background:#d0d0d0" | <span title="Hilfsverb">auxiliary</span>
| colspan="4" | {aux}
|-
| rowspan="2" style="background:#a0ade3" |
! colspan="2" style="background:#a0ade3" | <span title="Indikativ">indicative</span>
| rowspan="2" style="background:#a0ade3" |
! colspan="2" style="background:#a0ade3" | <span title="Konjunktiv">subjunctive</span>
|-
! style="background:#a0ade3" | singular
! style="background:#a0ade3" | plural
! style="background:#a0ade3" | singular
! style="background:#a0ade3" | plural
|-
! rowspan="3" style="background:#c0cfe4; width:7em" | <span title="Präsens">present</span>
| {pres_1s}
| {pres_1p}
! rowspan="3" style="background:#c0cfe4; width:7em" | <span title="Konjunktiv I (Konjunktiv Präsens)">i</span>
| {subi_1s}
| {subi_1p}
|-
| {pres_2s}
| {pres_2p}
| {subi_2s}
| {subi_2p}
|-
| {pres_3s}
| {pres_3p}
| {subi_3s}
| {subi_3p}
|-
| colspan="6" style="background:#d5d5d5; height: .25em" |
|-
! rowspan="3" style="background:#c0cfe4" | <span title="Präteritum">preterite</span>
| {pret_1s}
| {pret_1p}
! rowspan="3" style="background:#c0cfe4" | <span title="Konjunktiv II (Konjunktiv Präteritum)">ii</span>
| {subii_1s}
| {subii_1p}
|-
| {pret_2s}
| {pret_2p}
| {subii_2s}
| {subii_2p}
|-
| {pret_3s}
| {pret_3p}
| {subii_3s}
| {subii_3p}
|-
| colspan="6" style="background:#d5d5d5; height: .25em" |
|-
! style="background:#c0cfe4" | <span title="Imperativ">imperative</span>
| {imp_2s}
| {imp_2p}
| colspan="3" style="background:#e0e0e0" |
|{\cl}{notes_clause}</div></div>
]=]
local subordinate_clause_table = [=[
<div class="NavFrame" style="">
<div class="NavHead" style="">Subordinate-clause forms of {title}</div>
<div class="NavContent">
{\op}| border="1px solid #000000" style="border-collapse:collapse; background:#fafafa; text-align:center; width:100%" class="inflection-table"
|-
| style="background:#a0ade3" |
! colspan="2" style="background:#a0ade3" | <span title="Indikativ">indicative</span>
| style="background:#a0ade3" |
! colspan="2" style="background:#a0ade3" | <span title="Konjunktiv">subjunctive</span>
|-
! rowspan="3" style="background:#c0cfe4; width:7em" | <span title="Präsens">present</span>
| {subc_pres_1s}
| {subc_pres_1p}
! rowspan="3" style="background:#c0cfe4; width:7em" | <span title="Konjunktiv I (Konjunktiv Präsens)">i</span>
| {subc_subi_1s}
| {subc_subi_1p}
|-
| {subc_pres_2s}
| {subc_pres_2p}
| {subc_subi_2s}
| {subc_subi_2p}
|-
| {subc_pres_3s}
| {subc_pres_3p}
| {subc_subi_3s}
| {subc_subi_3p}
|-
| colspan="6" style="background:#d5d5d5; height: .25em" |
|-
! rowspan="3" style="background:#c0cfe4" | <span title="Präteritum">preterite</span>
| {subc_pret_1s}
| {subc_pret_1p}
! rowspan="3" style="background:#c0cfe4" | <span title="Konjunktiv II (Konjunktiv Präteritum)">ii</span>
| {subc_subii_1s}
| {subc_subii_1p}
|-
| {subc_pret_2s}
| {subc_pret_2p}
| {subc_subii_2s}
| {subc_subii_2p}
|-
| {subc_pret_3s}
| {subc_pret_3p}
| {subc_subii_3s}
| {subc_subii_3p}
|{\cl}{notes_clause}</div></div>
]=]
local composed_table = [=[
<div class="NavFrame" style="">
<div class="NavHead" style="">Composed forms of {title}</div>
<div class="NavContent">
{\op}| border="1px solid #000000" style="border-collapse:collapse; background:#fafafa; text-align:center; width:100%" class="inflection-table"
|-
! colspan="6" style="background:#99cc99" | <span title="Perfekt">perfect</span>
|-
! style="background:#99cc99" |
! style="background:#99cc99" | singular
! style="background:#99cc99" | plural
! style="background:#99cc99" |
! style="background:#99cc99" | singular
! style="background:#99cc99" | plural
|-
! rowspan="3" style="background:#cfedcc; width:7em" | <span title="Indikativ">indicative</span>
| {perf_ind_1s}
| {perf_ind_1p}
! rowspan="3" style="background:#cfedcc; width:7em" | <span title="Konjunktiv">subjunctive</span>
| {perf_sub_1s}
| {perf_sub_1p}
|-
| {perf_ind_2s}
| {perf_ind_2p}
| {perf_sub_2s}
| {perf_sub_2p}
|-
| {perf_ind_3s}
| {perf_ind_3p}
| {perf_sub_3s}
| {perf_sub_3p}
|-
! colspan="6" style="background:#99CC99" | <span title="Plusquamperfekt">pluperfect</span>
|-
! rowspan="3" style="background:#cfedcc" | <span title="Indikativ">indicative</span>
| {plup_ind_1s}
| {plup_ind_1p}
! rowspan="3" style="background:#cfedcc" | <span title="Konjunktiv">subjunctive</span>
| {plup_sub_1s}
| {plup_sub_1p}
|-
| {plup_ind_2s}
| {plup_ind_2p}
| {plup_sub_2s}
| {plup_sub_2p}
|-
| {plup_ind_3s}
| {plup_ind_3p}
| {plup_sub_3s}
| {plup_sub_3p}
|-
! colspan="6" style="background:#9999DF" | <span title="Futur I">future i</span>
|-
! rowspan="3" style="background:#ccccff" | <span title="Infinitiv">infinitive</span>
| rowspan="3" colspan="2" | {futi_inf}
! rowspan="3" style="background:#ccccff" | <span title="Konjunktiv I (Konjunktiv Präsens)">subjunctive i</span>
| {futi_subi_1s}
| {futi_subi_1p}
|-
| {futi_subi_2s}
| {futi_subi_2p}
|-
| {futi_subi_3s}
| {futi_subi_3p}
|-
! colspan="6" style="background:#d5d5d5; height: .25em" |
|-
! rowspan="3" style="background:#ccccff" | <span title="Indikativ">indicative</span>
| {futi_ind_1s}
| {futi_ind_1p}
! rowspan="3" style="background:#ccccff" | <span title="Konjunktiv II (Konjunktiv Präteritum)">subjunctive ii</span>
| {futi_subii_1s}
| {futi_subii_1p}
|-
| {futi_ind_2s}
| {futi_ind_2p}
| {futi_subii_2s}
| {futi_subii_2p}
|-
| {futi_ind_3s}
| {futi_ind_3p}
| {futi_subii_3s}
| {futi_subii_3p}
|-
! colspan="6" style="background:#9999DF" | <span title="Futur II">future ii</span>
|-
! rowspan="3" style="background:#ccccff" | <span title="Infinitiv">infinitive</span>
| rowspan="3" colspan="2" | {futii_inf}
! rowspan="3" style="background:#ccccff" | <span title="Konjunktiv I (Konjunktiv Präsens)">subjunctive i</span>
| {futii_subi_1s}
| {futii_subi_1p}
|-
| {futii_subi_2s}
| {futii_subi_2p}
|-
| {futii_subi_3s}
| {futii_subi_3p}
|-
! colspan="6" style="background:#d5d5d5; height: .25em" |
|-
! rowspan="3" style="background:#ccccff" | <span title="Indikativ">indicative</span>
| {futii_ind_1s}
| {futii_ind_1p}
! rowspan="3" style="background:#ccccff" | <span title="Konjunktiv II (Konjunktiv Präteritum)">subjunctive ii</span>
| {futii_subii_1s}
| {futii_subii_1p}
|-
| {futii_ind_2s}
| {futii_ind_2p}
| {futii_subii_2s}
| {futii_subii_2p}
|-
| {futii_ind_3s}
| {futii_ind_3p}
| {futii_subii_3s}
| {futii_subii_3p}
|{\cl}{notes_clause}</div></div>]=]
local function make_table(alternant_multiword_spec)
local forms = alternant_multiword_spec.forms
forms.title = link_term(alternant_multiword_spec.lemmas[1].form, "term")
if alternant_multiword_spec.annotation ~= "" then
forms.title = forms.title .. " (" .. alternant_multiword_spec.annotation .. ")"
end
-- Maybe format the subordinate clause table.
local formatted_subordinate_clause_table
if forms.subc_pres_3s ~= "—" then -- use 3s in case of only3s verb
forms.zu_infinitive_table = m_string_utilities.format(zu_infinitive_table, forms)
forms.footnote = alternant_multiword_spec.footnote_subordinate_clause
forms.notes_clause = forms.footnote ~= "" and m_string_utilities.format(notes_template, forms) or ""
formatted_subordinate_clause_table = m_string_utilities.format(subordinate_clause_table, forms)
else
forms.zu_infinitive_table = ""
formatted_subordinate_clause_table = ""
end
-- Format the basic table.
forms.footnote = alternant_multiword_spec.footnote_basic
forms.notes_clause = forms.footnote ~= "" and m_string_utilities.format(notes_template, forms) or ""
local formatted_basic_table = m_string_utilities.format(basic_table, forms)
-- Format the composed table.
forms.footnote = alternant_multiword_spec.footnote_composed
forms.notes_clause = forms.footnote ~= "" and m_string_utilities.format(notes_template, forms) or ""
local formatted_composed_table = m_string_utilities.format(composed_table, forms)
-- Paste them together.
return formatted_basic_table .. formatted_subordinate_clause_table .. formatted_composed_table
end
-- Externally callable function to parse and conjugate a verb given user-specified arguments.
-- Return value is WORD_SPEC, an object where the conjugated forms are in `WORD_SPEC.forms`
-- for each slot. If there are no values for a slot, the slot key will be missing. The value
-- for a given slot is a list of objects {form=FORM, footnotes=FOOTNOTES}.
function export.do_generate_forms(parent_args, from_headword, def)
local params = {
[1] = {},
}
if from_headword then
params["lemma"] = {list = true}
params["id"] = {}
end
local args = require("Module:parameters").process(parent_args, params)
local PAGENAME = mw.title.getCurrentTitle().text
if not args[1] then
if PAGENAME == "gmh-conj" or PAGENAME == "gmh-verb" then
args[1] = def or "gëben<gab,gegëben.hān>"
else
args[1] = PAGENAME
-- If pagename has spaces in it, add links around each word
if args[1]:find(" ") then
args[1] = "[[" .. args[1]:gsub(" ", "]] [[") .. "]]"
end
end
end
local parse_props = {
parse_indicator_spec = parse_indicator_spec,
lang = lang,
allow_default_indicator = true,
allow_blank_lemma = true,
}
local escaped_arg1 = escape_sin_sich_indicators(args[1])
local alternant_multiword_spec = iut.parse_inflected_text(escaped_arg1, parse_props)
alternant_multiword_spec.pos = pos or "verbs"
alternant_multiword_spec.args = args
normalize_all_lemmas(alternant_multiword_spec, from_headword)
detect_all_indicator_specs(alternant_multiword_spec)
local inflect_props = {
slot_list = all_verb_slots,
lang = lang,
inflect_word_spec = conjugate_verb,
-- We add links around the generated verbal forms rather than allow the entire multiword
-- expression to be a link, so ensure that user-specified links get included as well.
include_user_specified_links = true,
}
iut.inflect_multiword_or_alternant_multiword_spec(alternant_multiword_spec, inflect_props)
compute_auxiliary(alternant_multiword_spec)
compute_categories_and_annotation(alternant_multiword_spec, from_headword)
return alternant_multiword_spec
end
-- Entry point for {{de-conj}}. Template-callable function to parse and conjugate a verb given
-- user-specified arguments and generate a displayable table of the conjugated forms.
function export.show(frame)
local parent_args = frame:getParent().args
local alternant_multiword_spec = export.do_generate_forms(parent_args)
show_forms(alternant_multiword_spec)
return make_table(alternant_multiword_spec) .. require("Module:utilities").format_categories(alternant_multiword_spec.categories, lang)
end
-- Concatenate all forms of all slots into a single string of the form
-- "SLOT=FORM,FORM,...|SLOT=FORM,FORM,...|...". Embedded pipe symbols (as might occur
-- in embedded links) are converted to <!>. If INCLUDE_PROPS is given, also include
-- additional properties (currently, none). This is for use by bots.
local function concat_forms(alternant_multiword_spec, include_props)
local ins_text = {}
for _, slot_and_accel in ipairs(all_verb_slots) do
local slot = slot_and_accel[1]
local formtext = iut.concat_forms_in_slot(alternant_multiword_spec.forms[slot])
if formtext then
table.insert(ins_text, slot .. "=" .. formtext)
end
end
if include_props then
local verb_types = {}
iut.map_word_specs(alternant_multiword_spec, function(base)
detect_verb_type(base, verb_types)
end)
table.insert(ins_text, "class=" .. table.concat(verb_types, ","))
end
return table.concat(ins_text, "|")
end
local numbered_params = {
-- required params
[1] = "infinitive",
[2] = "pres_part",
[3] = "perf_part",
[4] = "aux",
[5] = "pres_1s",
[6] = "pres_2s",
[7] = "pres_3s",
[8] = "pres_1p",
[9] = "pres_2p",
[10] = "pres_3p",
[11] = "pret_1s",
[12] = "pret_2s",
[13] = "pret_3s",
[14] = "pret_1p",
[15] = "pret_2p",
[16] = "pret_3p",
[17] = "subi_1s",
[18] = "subi_2s",
[19] = "subi_3s",
[20] = "subi_1p",
[21] = "subi_2p",
[22] = "subi_3p",
[23] = "subii_1s",
[24] = "subii_2s",
[25] = "subii_3s",
[26] = "subii_1p",
[27] = "subii_2p",
[28] = "subii_3p",
[29] = "imp_2s",
[30] = "imp_2p",
-- [31] formerly the 2nd variant of imp_2s; now no longer allowed (use comma-separated 29=)
-- [32] formerly indicated whether the 2nd variant of imp_2s was present
-- optional params
[33] = "subc_pres_1s",
[34] = "subc_pres_2s",
[35] = "subc_pres_3s",
[36] = "subc_pres_1p",
[37] = "subc_pres_2p",
[38] = "subc_pres_3p",
[39] = "subc_pret_1s",
[40] = "subc_pret_2s",
[41] = "subc_pret_3s",
[42] = "subc_pret_1p",
[43] = "subc_pret_2p",
[44] = "subc_pret_3p",
[45] = "subc_subi_1s",
[46] = "subc_subi_2s",
[47] = "subc_subi_3s",
[48] = "subc_subi_1p",
[49] = "subc_subi_2p",
[50] = "subc_subi_3p",
[51] = "subc_subii_1s",
[52] = "subc_subii_2s",
[53] = "subc_subii_3s",
[54] = "subc_subii_1p",
[55] = "subc_subii_2p",
[56] = "subc_subii_3p",
[57] = "zu_infinitive",
}
local max_required_param = 30
-- Externally callable function to parse and conjugate a verb where all forms are given manually.
-- Return value is WORD_SPEC, an object where the conjugated forms are in `WORD_SPEC.forms`
-- for each slot. If there are no values for a slot, the slot key will be missing. The value
-- for a given slot is a list of objects {form=FORM, footnotes=FOOTNOTES}.
function export.do_generate_forms_manual(parent_args)
local params = {
["generate_forms"] = {type = "boolean"},
}
for paramnum, _ in pairs(numbered_params) do
params[paramnum] = {required = paramnum <= max_required_param}
end
local args = require("Module:parameters").process(parent_args, params)
local base = {
forms = {},
manual = true,
}
local function process_numbered_param(paramnum)
local argval = args[paramnum]
if paramnum == 4 then
if argval == "h" then
base.aux = {{form = "hān"}}
elseif argval == "s" then
base.aux = {{form = "sīn"}}
elseif argval == "hs" then
base.aux = {{form = "hān"}, {form = "sīn"}}
elseif argval == "sh" then
base.aux = {{form = "sīn"}, {form = "hān"}}
elseif not argval then
error("Missing auxiliary in 4=")
else
error("Unrecognized auxiliary 4=" .. argval)
end
elseif argval and argval ~= "-" then
local split_vals = rsplit(argval, "%s*,%s*")
for _, val in ipairs(split_vals) do
-- FIXME! This won't work with commas or brackets in footnotes.
-- To fix this, use functions from [[Module:inflection utilities]].
local form, footnote = val:match("^(.-)%s*(%[[^%]%[]-%])$")
local footnotes
if form then
footnotes = {footnote}
else
form = val
end
local slot = numbered_params[paramnum]
--if slot:find("subii") then
-- local subii_footnotes = get_subii_note(base)
-- footnotes = iut.combine_footnotes(subii_footnotes, footnotes)
--end
iut.insert_form(base.forms, slot, {form = form, footnotes = footnotes})
end
end
end
-- Do the infinitive first as we need to reference it in subjunctive II footnotes.
process_numbered_param(1)
for paramnum, _ in pairs(numbered_params) do
if paramnum ~= 1 then
process_numbered_param(paramnum)
end
end
add_composed_forms(base)
compute_categories_and_annotation(base, nil, "manual")
return base, args.generate_forms
end
-- Entry point for {{de-conj-table}}. Template-callable function to parse and conjugate a verb given
-- manually-specified inflections and generate a displayable table of the conjugated forms.
function export.show_manual(frame)
local parent_args = frame:getParent().args
local base, generate_forms = export.do_generate_forms_manual(parent_args)
if generate_forms then
return concat_forms(base)
end
show_forms(base)
return make_table(base) .. require("Module:utilities").format_categories(base.categories, lang)
end
-- Template-callable function to parse and conjugate a verb given user-specified arguments and return
-- the forms as a string "SLOT=FORM,FORM,...|SLOT=FORM,FORM,...|...". Embedded pipe symbols (as might
-- occur in embedded links) are converted to <!>. If |include_props=1 is given, also include
-- additional properties (currently, none). This is for use by bots.
function export.generate_forms(frame)
local include_props = frame.args["include_props"]
local parent_args = frame:getParent().args
local alternant_multiword_spec = export.do_generate_forms(parent_args)
return concat_forms(alternant_multiword_spec, include_props)
end
return export