This module is used as the backend for Template:hi-conj.
local export = {}
--[=[
Authorship: Ben Wing <benwing2>
]=]
--[=[
TERMINOLOGY:
-- "slot" = A particular combination of person/number/gender/tense/etc.
Example slot names for verbs are "inf_mp" (masculine plural infinitive),
"prog" (undeclined progressive form), "pfv_ind_fut_2sm" (second-person singular
masculine perfective indicative future). Each slot is filled with zero or
more forms.
-- "form" = The conjugated Hindi form representing the value of a given slot.
-- "lemma" = The dictionary form of a given Hindi term. Generally the direct
masculine singular infinitive, but may occasionally be another form if
that form is missing.
]=]
--[=[
FIXME:
1. (DONE) If rearrangement for syncretism stays, need to change accelerators.
2. (DONE) In add_slot_gendered(), for participles, potentially put back obl|m|s for -e form accelerators.
3. (DONE) Split adjectival participle into perfective and habitual.
4. (DONE) Some errors in future intimate imperatives of पीना, देना, लेना.
5. Stop generating 3s and 3p forms (same as 2s and 1p forms, respectively) except for imperatives;
rename 3s -> 23s and 1p -> 13p.
6. (DONE) Add alternative (regular) perfective participle of जाना; footnote that
it only works with auxiliary जाना and occasionally करना in the habitual.
7. (DONE) Fix forms listed in imperative footnote for verbs like सीना, छूना.
8. (DONE) Remove fut2 forms (= to presumptive) from होना.
9. (DONE) Contrafactual -> PST only.
10. (DONE) In verbs like हिलना-डुलना, suffixes -गा and -वाला should occur only once.
11. (DONE) Indicative future of छूना should be छुऊँगा (maybe along with छूँगा?).
12. Merge cases where Devanagari spelling occurs twice with different translits.
13. (DONE) Add "rare" footnote for हूजिए.
14. (DONE) Add future tense to presumptive forms for non-aspectual and progressive.
15. (DONE) Remove first -गा in 3p fut imp of हिलना-डुलना.
16. (DONE) What is the progressive of हिलना-डुलना? Currently I have हिलते-हिलते-दुलते-दुलते.
(It's just हिलते-डलते; fixed.)
17. (DONE) Do verbs like खाना have alternative perfective participles खाये, खायी, खायीं?
(Yes, made the default with a y-footnote.)
18. (DONE) Should 2pl pres imperative in -o be -yo after -i? If so, is -o an alternative form?
(Yes and yes, but the -y- is normally pronounced, so alternative form not listed.)
19. (DONE) Should we change the label of non-होना non-aspectual subjunctives to FUT only not PRES/FUT?
(Yes. Done.)
FIXES NEEDING DISCUSSING:
2. Should we remove subjunctive forms of imperatives and convert them to a footnote?
6. Are forms like पिइयो (पीना) and जिइयो (जीना) are correct, and should forms
like पियो and जियो be used instead or as alternatives?
7. Should we have distinct colors for masc/fem/combined rows or should they be a single color?
]=]
local lang = require("Module:languages").getByCode("hi")
local m_table = require("Module:table")
local m_links = require("Module:links")
local m_string_utilities = require("Module:string utilities")
local m_script_utilities = require("Module:script utilities")
local iut = require("Module:inflection utilities")
local m_para = require("Module:parameters")
local com = require("Module:hi-common")
local u = require("Module:string/char")
local rsplit = mw.text.split
local rfind = mw.ustring.find
local rmatch = mw.ustring.match
local rgmatch = mw.ustring.gmatch
local rsubn = mw.ustring.gsub
local ulen = mw.ustring.len
local usub = mw.ustring.sub
local uupper = mw.ustring.upper
local ulower = mw.ustring.lower
-- vowel diacritics; don't display nicely on their own
local M = u(0x0901)
local N = u(0x0902)
local AA = u(0x093e)
local AI = u(0x0948)
local AU = u(0x094c)
local E = u(0x0947)
local EN = E .. N
local I = u(0x093f)
local II = u(0x0940)
local IIN = II .. N
local O = u(0x094b)
local U = u(0x0941)
local UU = u(0x0942)
local UUM = UU .. M
local R = u(0x0943)
local VIRAMA = u(0x094d)
local TILDE = u(0x0303)
-- version of rsubn() that discards all but the first return value
local function rsub(term, foo, bar)
local retval = rsubn(term, foo, bar)
return retval
end
-- version of rsubn() that returns a 2nd argument boolean indicating whether
-- a substitution was made.
local function rsubb(term, foo, bar)
local retval, nsubs = rsubn(term, foo, bar)
return retval, nsubs > 0
end
local function tag_text(text)
return m_script_utilities.tag_text(text, lang)
end
local function term_link(hi, tr)
return m_links.full_link({term = hi, tr = tr, lang = lang}, "term")
end
local irreg_perf = {
= "की",
= "ग*", -- this is a special sign to request independent endings in some cases
= "ली",
= "दी",
= "हु",
}
local irreg_subj = {
= "द",
= "ल",
}
local irreg_polite_imp = {
= {"कीज", "कर"},
= "लीज",
= "दीज",
= "पीज",
= {"हो", {form = "हूज", footnotes = {""}}},
}
local verb_slots_impers = {
inf = "inf",
inf_obl = "obl|inf",
stem = "stem",
conj = "conj|form",
prog = "prog|form",
}
local verb_slots_pers = {
}
-- Add entries for a slot with only gender/number variants.
-- `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 gender/number tags,
-- or "-" to use "-" as the inflection tags (which indicates that no accelerator entry
-- should be generated); and `verb_slots` is the table (personal or impersonal) to
-- add the entries to.
local function add_slot_gendered(slot_prefix, tag_suffix, verb_slots)
verb_slots = verb_slots or verb_slots_pers
verb_slots = tag_suffix == "-" and "-" or "m|s|" .. tag_suffix
verb_slots = tag_suffix == "-" and "-" or "m|p|" .. tag_suffix
verb_slots = tag_suffix == "-" and "-" or "f|s|" .. tag_suffix
verb_slots = tag_suffix == "-" and "-" or "f|p|" .. tag_suffix
end
-- Same as add_slot_gendered() but specifically for participles. This changes the inflection
-- tags used, because the masculine singular entry is really only for direct masculine singular,
-- and the masculine plural entry is also for oblique masculine singular.
local function add_slot_gendered_part(slot_prefix, tag_suffix, verb_slots)
verb_slots = verb_slots or verb_slots_pers
verb_slots = tag_suffix == "-" and "-" or "dir|m|s|" .. tag_suffix
verb_slots = tag_suffix == "-" and "-" or "m|p|" .. tag_suffix .. "|;|obl|m|s|" .. tag_suffix
verb_slots = tag_suffix == "-" and "-" or "f|s|" .. tag_suffix
verb_slots = tag_suffix == "-" and "-" or "f|p|" .. tag_suffix
end
-- Compute the inflection tags associated with a given person/number/gender combination.
local function personal_tags(slot_prefix, tag_suffix, persnum, gender)
gender = gender and gender .. "|" or ""
local suffix = gender .. tag_suffix
if persnum == "2s" then -- only for imperatives
return "2|s|intim|" .. suffix
elseif persnum == "23s" then
return "2|s|intim|" .. suffix .. "|;|3|s|" .. suffix
elseif persnum == "13p" then
return "13|p|" .. suffix .. "|;|2|formal|" .. suffix
elseif persnum == "2p" then
return "2|fam|" .. suffix
elseif persnum == "3p" then -- only for imperatives
return "3|p|" .. suffix .. "|;|2|formal|" .. suffix
else
-- 1s, 3s or 1p
return persnum:gsub("^(.)(.)$", "%1|%2") .. "|" .. suffix
end
end
-- Return the possible person/number combinations given the slot prefix.
local function persnum_values(slot_prefix)
if slot_prefix:find("^imp_") then
return {"2s", "2p", "3p"}
else
return {"1s", "23s", "13p", "2p"}
end
end
-- Add entries for a slot with only person/number variants. See `add_slot_gendered()`.
local function add_slot_personal(slot_prefix, tag_suffix, verb_slots)
verb_slots = verb_slots or verb_slots_pers
for _, persnum in ipairs(persnum_values(slot_prefix)) do
local slot = slot_prefix .. "_" .. persnum
if tag_suffix == "-" then
verb_slots = "-"
else
verb_slots = personal_tags(slot_prefix, tag_suffix, persnum)
end
end
end
-- Add entries for a slot with person/number/gender variants. See `add_slot_gendered()`.
local function add_slot_gendered_personal(slot_prefix, tag_suffix, verb_slots)
verb_slots = verb_slots or verb_slots_pers
for _, persnum in ipairs(persnum_values(slot_prefix)) do
for _, gender in ipairs({"m", "f"}) do
local slot = slot_prefix .. "_" .. persnum .. gender
if tag_suffix == "-" then
verb_slots = "-"
else
verb_slots = personal_tags(slot_prefix, tag_suffix, persnum, gender)
end
end
end
end
add_slot_gendered_part("inf", "inf|part", verb_slots_impers)
add_slot_gendered_part("hab", "hab|part", verb_slots_impers)
add_slot_gendered_part("pfv", "pfv|part", verb_slots_impers)
add_slot_gendered_part("agent", "prospective//agentive|part", verb_slots_impers)
add_slot_gendered_part("adj_pfv", "-", verb_slots_impers)
add_slot_gendered_part("adj_hab", "-", verb_slots_impers)
add_slot_personal("ind_pres", "pres|ind") -- only for होना
add_slot_gendered("ind_impf", "impf|ind") -- only for होना
add_slot_gendered("ind_perf", "perf|ind")
add_slot_gendered_personal("ind_fut", "fut|ind")
add_slot_gendered_personal("presum", "presumptive")
add_slot_personal("subj_pres", "pres|subj") -- only for होना
add_slot_personal("subj_fut", "fut|subj")
add_slot_gendered("cfact", "cfact")
add_slot_personal("imp_pres", "pres|imp")
add_slot_personal("imp_fut", "fut|imp")
add_slot_gendered_personal("hab_ind_pres", "-")
add_slot_gendered("hab_ind_past", "-")
add_slot_gendered_personal("hab_presum", "-")
add_slot_gendered_personal("hab_subj", "-")
add_slot_gendered("hab_cfact", "-")
for _, mood in ipairs({"pfv", "prog"}) do
add_slot_gendered_personal(mood .. "_ind_pres", "-")
add_slot_gendered(mood .. "_ind_past", "-")
add_slot_gendered_personal(mood .. "_ind_fut", "-")
add_slot_gendered_personal(mood .. "_presum", "-")
add_slot_gendered_personal(mood .. "_subj_pres", "-")
add_slot_gendered_personal(mood .. "_subj_fut", "-")
add_slot_gendered(mood .. "_cfact", "-")
end
verb_slots_impers = verb_slots_impers
local all_verb_slots = {}
for k, v in pairs(verb_slots_impers) do
all_verb_slots = v
end
for k, v in pairs(verb_slots_pers) do
all_verb_slots = v
end
local function fut_subj_ye_note(slot, link, ending)
if rfind(slot, "^ind_fut") then
return {"[the forms " .. link("येगा") .. ", " .. link("येंगे") .. ", " ..
link("येगी") .. " and " .. link("येंगी") .. " can also be spelled without the ''y'': " ..
link("एगा") .. ", " .. link("एँगे") .. ", " .. link("एगी") .. " and " .. link("एँगी") .. "]"}
elseif rfind(slot, "^subj") then
return {"[the forms " .. link("ये") .. " and " .. link("यें") ..
" can also be spelled without the ''y'': " .. link("ए") .. " and " .. link("एँ") .. "]"}
else
error("Internal error: Don't know what to do with ending " .. ending .. " for slot " .. slot)
end
end
local function pfv_ye_yi_note(link)
return {"[the participles " .. link("ये") .. ", " .. link("यी") .. " and " .. link("यीं") ..
" can also be spelled without the ''y'': " .. link("ए") .. ", " .. link("ई") ..
" and " .. link("ईं") .. "]"}
end
-- Add one inflected form to `base.forms`, specifically to the list of forms associated with
-- the slot `slot` in the table in `base.forms`. Each element of the list is an object of the
-- form {form=FORM, translit=TRANSLIT, footnotes=FOOTNOTES}, where TRANSLIT is missing if no
-- manual translit needs to be given and FOOTNOTES is missing if there aren't any footnotes.
-- If FOOTNOTES is present it is a list of footnotes, where each footnote is e.g. "",
-- i.e. surrounded by brackets, with the first character lowercase and no final period.
-- (The brackets are automatically removed, the first character capitalized and a final period added.)
--
-- `stem` is the Devanagari stem to add the ending to.
-- `translit_stem` is the transliteration of `stem`, or nil to use the default transliteration.
-- `ending` is the Devanagari ending to add to the stem, possibly with sandhi changes to the
-- stem or ending.
-- `footnotes` is a list of associated footnotes in the same format as FOOTNOTES above, or nil.
-- `double_word` if given causes the resulting form to be doubled with a hyphen in between the two
-- parts, for use with the progressive form (e.g. करते-करते of verb करना).
local function add(base, stem, translit_stem, slot, ending, footnotes, double_word)
local function doadd(new_stem, new_translit_stem, new_ending, slot_footnotes)
new_ending = new_ending or ending
if new_ending and base.notlast then
-- If we're not the last verb in a multiword expression, chop off
-- anything after a space. This is to handle verbs like ],
-- which have e.g. nonaspectual subjunctive 1sg masc हिलूँ-डुलूँ
-- but perfective future indicative 1sg masc हिला-डुला हूँगा. Also, there
-- are some special cases:
-- (1) the conjunctive form should be e.g. हिल-डुलकर or हिल-डुलके
-- (2) the future indicative should be e.g. 1sg हिलूँ-डुलूँगा
-- (3) the future imperative 3pl should be e.g. हिलिये-डुलियेगा
-- (4) the agentive should be e.g. हिलने-डुलनेवाला
if slot == "conj" then
new_ending = ""
elseif slot:find("^ind_fut") then
new_ending = rsub(new_ending, "ग.$", "") -- गा, गे or गी
elseif slot == "imp_fut_3p" then
new_ending = rsub(new_ending, "गा$", "")
elseif slot:find("^agent") then
new_ending = rsub(new_ending, "वाल." .. N .. "?$", "") -- वाला, वाले, वाली, वालीं
else
new_ending = rsub(new_ending, " .*", "")
end
end
com.add_form(base, new_stem or stem, new_translit_stem or translit_stem, slot,
new_ending, iut.combine_footnotes(slot_footnotes, footnotes), "link words", double_word)
end
if ending then
if rfind(stem, "$") then
-- Implement sandhi changes after stem ending in -ī or -i.
local stem_butlast, translit_stem_butlast =
com.strip_ending_from_stem(stem, translit_stem, rfind(stem, II .. "$") and II or I)
local ending_first = usub(ending, 1, 1)
if ending_first == E then
local form_stem = stem_butlast .. I
local form_tr = translit_stem_butlast and translit_stem_butlast .. "i"
local function link(form_ending)
return term_link(form_stem .. form_ending, form_tr and form_tr .. (lang:transliterate(form_ending)))
end
local y_footnote
if slot:find("pfv") or slot:find("perf") then
y_footnote = {"[the participle " .. link("ये") ..
" can also be spelled without the ''y'': " .. link("ए") .. "]"}
else
y_footnote = fut_subj_ye_note(slot, link, ending)
end
doadd(form_stem .. "य", form_tr and form_tr .. "y", nil, y_footnote)
return
elseif ending_first == II then
doadd(stem_butlast, translit_stem_butlast)
return
elseif ending_first ~= I and rfind(ending_first, "") then
doadd(stem_butlast .. I .. "य", translit_stem_butlast and translit_stem_butlast .. "iy")
return
end
elseif rfind(stem, "$") then
-- Implement sandhi changes after stem ending in -ū or -u.
local stem_butlast, translit_stem_butlast = com.strip_ending_from_stem(stem, translit_stem,
rfind(stem, UU .. "$") and UU or U)
local ending_first = usub(ending, 1, 1)
if rfind(ending_first, "") then
doadd(stem_butlast .. U, translit_stem_butlast and translit_stem_butlast .. "u")
return
end
elseif rfind(stem, "$") and rfind(ending, "^" .. AA) then
-- Implement sandhi changes after stem ending in -ā or -o and an ending beginning in -ā (always a
-- perfective participle).
doadd(stem .. "य", translit_stem and translit_stem .. "y")
return
elseif rfind(stem, "$") then
local function link(form_ending)
return term_link(stem .. form_ending, translit_stem and translit_stem .. (lang:transliterate(form_ending)))
end
local y_footnote
-- Implement sandhi changes after stem ending in -ā and a perfective participle ending beginning in
-- -e, -ī or -ī̃, or a future or subjunctive form beginning in -e.
if slot:find("pfv") or slot:find("perf") then
y_footnote = pfv_ye_yi_note(link)
elseif rfind(ending, "^" .. E) then
y_footnote = fut_subj_ye_note(slot, link, ending)
end
if y_footnote then
doadd(stem .. "य", translit_stem and translit_stem .. "y", nil, y_footnote)
return
end
elseif rfind(stem, "$") then
-- Implement sandhi changes after stem ending in -e and a perfective participle ending beginning in
-- -ā, -e, -ī or -ī̃.
if slot:find("pfv") or slot:find("perf") then
local function link(form_ending)
return term_link(stem .. form_ending, translit_stem and translit_stem .. (lang:transliterate(form_ending)))
end
local y_footnote = {"[the participles " .. link("या") .. ", " .. link("ये") .. ", " .. link("यी") ..
" and " .. link("यीं") .. " can also be spelled without the ''y'': " ..
link("आ") .. ", " .. link("ए") .. ", " .. link("ई") .. " and " .. link("ईं") .. "]"}
doadd(stem .. "य", translit_stem and translit_stem .. "y", nil, y_footnote)
return
end
elseif rfind(stem, "%*$") then
-- Special hacks for ग(य)-, perfective stem of जाना.
local stem_butlast, translit_stem_butlast =
com.strip_ending_from_stem(stem, translit_stem, "%*")
if ending:find("^" .. E) or ending:find("^" .. II) then
local function link(form_ending)
return term_link(stem_butlast .. form_ending,
translit_stem and translit_stem .. (lang:transliterate(form_ending)))
end
local y_footnote = pfv_ye_yi_note(link)
-- Use full translit_stem rather than stripping off the final 'a' that should be there.
-- Need to specify independent endings (diacritic endings get converted to independent ones after
-- an explicit vowel, but here there is no explicit vowel).
doadd(stem_butlast, translit_stem,
ending:find("^" .. E) and rsub(ending, "^" .. E, "ए") or rsub(ending, "^" .. II, "ई"),
y_footnote)
-- doadd(stem_butlast .. "य", translit_stem and translit_stem .. "y")
else
doadd(stem_butlast .. "य", translit_stem and translit_stem .. "y")
end
return
end
end
doadd()
end
-- Add the conjugation for a tense/aspect row with gender/number variants only.
local function add_conj_gendered(base, slot_prefix, stem, translit_stem, m_s, m_p, f_s, f_p, footnotes)
if not stem then
stem = base.stem
translit_stem = base.stem_translit
end
add(base, stem, translit_stem, slot_prefix .. "_ms", m_s, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_mp", m_p, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_fs", f_s, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_fp", f_p, footnotes)
end
-- Add the conjugation for a tense/aspect row with person/number variants only.
local function add_conj_personal(base, slot_prefix, stem, translit_stem, s1, s23, p13, p2, footnotes)
if not stem then
stem = base.stem
translit_stem = base.stem_translit
end
add(base, stem, translit_stem, slot_prefix .. "_1s", s1, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_23s", s23, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_13p", p13, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_2p", p2, footnotes)
end
-- Add the conjugation for a tense/aspect row with person/number/gender variants.
local function add_conj_gendered_personal(base, slot_prefix, stem, translit_stem,
s1m, s23m, p13m, p2m, s1f, s23f, p13f, p2f, footnotes)
if not stem then
stem = base.stem
translit_stem = base.stem_translit
end
add(base, stem, translit_stem, slot_prefix .. "_1sm", s1m, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_23sm", s23m, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_13pm", p13m, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_2pm", p2m, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_1sf", s1f, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_23sf", s23f, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_13pf", p13f, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_2pf", p2f, footnotes)
end
local function handle_derived_slots_and_overrides(base)
-- No overrides implemented currently.
-- process_slot_overrides(base)
-- Compute linked versions of potential lemma slots, for use in {{hi-verb}}.
-- We substitute the original lemma (before removing links) for forms that
-- are the same as the lemma, if the original lemma has links.
-- (NOTE: Not currently used by {{hi-verb}}.)
for _, slot in ipairs({"inf_ms"}) do
iut.insert_forms(base.forms, slot .. "_linked", iut.map_forms(base.forms, function(form, translit)
if form == base.orig_lemma_no_links and translit == base.lemma_translit
and rfind(base.orig_lemma, "%[%[") then
return base.orig_lemma, base.lemma_translit
else
return form, translit
end
end))
end
end
local conjs = {}
local conjprops = {}
conjs = function(base)
local function fetch_irreg(irreg_table)
if irreg_table then
local stem = irreg_table
return stem, nil
else
return base.stem, base.stem_translit
end
end
local perf, trperf = fetch_irreg(irreg_perf)
local subj, trsubj = fetch_irreg(irreg_subj)
local polite_imp, tr_polite_imp = fetch_irreg(irreg_polite_imp)
-- Undeclined forms
add(base, base.stem, base.stem_translit, "stem", "")
add(base, base.stem, base.stem_translit, "inf", "ना")
add(base, base.stem, base.stem_translit, "inf_obl", "ने")
add(base, base.stem, base.stem_translit, "conj", "कर")
add(base, base.stem, base.stem_translit, "conj", "के")
-- Normally progressive form is doubled (e.g. करते-करते), but not in multiword
-- expressions like हिलना-डुलना.
add(base, base.stem, base.stem_translit, "prog", "ते", nil, not base.multiword)
-- Participles
add_conj_gendered(base, "inf", nil, nil, "ना", "ने", "नी", "नीं")
add_conj_gendered(base, "hab", nil, nil, "ता", "ते", "ती", "तीं")
add_conj_gendered(base, "pfv", perf, trperf, AA, E, II, IIN)
if base.stem == "जा" then
add_conj_gendered(base, "pfv", "जा", nil, AA, E, II, IIN,
{"[only with the copula " .. term_link("जाना") ..
" and (in the habitual aspect only) with the auxiliary verb " .. term_link("करना") .. "]"})
end
add_conj_gendered(base, "agent", nil, nil, "नेवाला", "नेवाले", "नेवाली", "नेवालीं")
add_conj_gendered(base, "adj_pfv", perf, trperf, AA .. " हुआ", E .. " हुए", II .. " हुई", II .. " हुईं")
add_conj_gendered(base, "adj_hab", nil, nil, "ता हुआ", "ते हुए", "ती हुई", "ती हुईं")
-- Non-aspectual
add_conj_gendered(base, "ind_perf", perf, trperf, AA, E, II, IIN)
add_conj_gendered_personal(base, "ind_fut", subj, trsubj,
UUM .. "गा", E .. "गा", EN .. "गे", O .. "गे",
UUM .. "गी", E .. "गी", EN .. "गी", O .. "गी")
if base.stem == "हो" then
add_conj_gendered_personal(base, "presum", "", "",
"हूँगा", "होगा", "होंगे", "होगे",
"हूँगी", "होगी", "होंगी", "होगी")
add_conj_personal(base, "ind_pres", "", "", "हूँ", "है", "हैं", "हो")
add_conj_gendered(base, "ind_impf", "थ", "th", AA, E, II, IIN)
add_conj_personal(base, "subj_pres", "", "", "हूँ", "हो", "हों", "हो")
end
add_conj_personal(base, "subj_fut", subj, trsubj, UUM, E, EN, O)
add_conj_gendered(base, "cfact", nil, nil, "ता", "ते", "ती", "तीं")
add(base, base.stem, base.stem_translit, "imp_pres_2s", "")
add(base, subj, trsubj, "imp_pres_2p", O)
add(base, subj, trsubj, "imp_fut_2s", I .. "यो")
add(base, base.stem, base.stem_translit, "imp_fut_2p", "ना")
-- There may be more than one possible polite imperative stem, particularly for
-- irregular verbs. Loop over them.
if type(polite_imp) ~= "table" or polite_imp.form then
polite_imp = {polite_imp}
end
if tr_polite_imp and type(tr_polite_imp) ~= "table" then
tr_polite_imp = {tr_polite_imp}
end
for i, polimp in ipairs(polite_imp) do
local tr_polimp = tr_polite_imp and tr_polite_imp
local imp_footnote
if polimp.form then
imp_footnote = polimp.footnotes
polimp = polimp.form
end
-- Implement sandhi changes after stem ending in -ī or -ū, before ending in i-.
-- FIXME: Merge these with the sandhi code in add().
local sandhi_polimp, sandhi_tr_polimp
if rfind(polimp, II .. "$") then
sandhi_polimp, sandhi_tr_polimp = com.strip_ending_from_stem(polimp, tr_polimp, II)
sandhi_polimp = sandhi_polimp .. I
sandhi_tr_polimp = sandhi_tr_polimp and sandhi_tr_polimp .. "i" or nil
elseif rfind(polimp, UU .. "$") then
sandhi_polimp, sandhi_tr_polimp = com.strip_ending_from_stem(polimp, tr_polimp, UU)
sandhi_polimp = sandhi_polimp .. U
sandhi_tr_polimp = sandhi_tr_polimp and sandhi_tr_polimp .. "u" or nil
else
sandhi_polimp, sandhi_tr_polimp = polimp, tr_polimp
end
local function link_i(form_ending)
return term_link(sandhi_polimp .. I .. form_ending,
sandhi_tr_polimp and sandhi_tr_polimp .. "i" .. (lang:transliterate(form_ending)))
end
local y_footnote = {
"[the forms " .. link_i("ये") .. " and " .. link_i("येगा") .. " can also be spelled without the ''y'': " ..
link_i("ए") .. " and " .. link_i("एगा") .. "]"}
local all_footnotes = iut.combine_footnotes(imp_footnote, y_footnote)
add(base, polimp, tr_polimp, "imp_pres_3p", I .. "ये", all_footnotes)
add(base, polimp, tr_polimp, "imp_fut_3p", I .. "येगा", all_footnotes)
end
-- Habitual
add_conj_gendered_personal(base, "hab_ind_pres", nil, nil,
"ता हूँ", "ता है", "ते हैं", "ते हो",
"ती हूँ", "ती है", "ती हैं", "ती हो")
add_conj_gendered(base, "hab_ind_past", nil, nil, "ता था", "ते थे", "ती थी", "ती थीं")
add_conj_gendered_personal(base, "hab_presum", nil, nil,
"ता हूँगा", "ता होगा", "ते होंगे", "ते होगे",
"ती हूँगी", "ती होगी", "ती होंगी", "ती होगी")
add_conj_gendered_personal(base, "hab_subj", nil, nil,
"ता हूँ", "ता हो", "ते हों", "ते हो",
"ती हूँ", "ती हो", "ती हों", "ती हो")
add_conj_gendered(base, "hab_cfact", nil, nil,
"ता होता", "ते होते", "ती होती", "ती होतीं")
-- Perfective
add_conj_gendered_personal(base, "pfv_ind_pres", perf, trperf,
AA .. " हूँ", AA .. " है", E .. " हैं", E .. " हो",
II .. " हूँ", II .. " है", II .. " हैं", II .. " हो")
add_conj_gendered(base, "pfv_ind_past", perf, trperf,
AA .. " था", E .. " थे", II .. " थी", II .. " थीं")
add_conj_gendered_personal(base, "pfv_ind_fut", perf, trperf,
AA .. " हूँगा", AA .. " होगा", E .. " होंगे", E .. " होगे",
II .. " हूँगी", II .. " होगी", II .. " होंगी", II .. " होगी")
add_conj_gendered_personal(base, "pfv_presum", perf, trperf,
AA .. " हूँगा", AA .. " होगा", E .. " होंगे", E .. " होगे",
II .. " हूँगी", II .. " होगी", II .. " होंगी", II .. " होगी")
add_conj_gendered_personal(base, "pfv_subj_pres", perf, trperf,
AA .. " हूँ", AA .. " हो", E .. " हों", E .. " हो",
II .. " हूँ", II .. " हो", II .. " हों", II .. " हो")
add_conj_gendered_personal(base, "pfv_subj_fut", perf, trperf,
AA .. " होऊँ", AA .. " होए", E .. " होएँ", E .. " होओ",
II .. " होऊँ", II .. " होए", II .. " होएँ", II .. " होओ")
add_conj_gendered(base, "pfv_cfact", perf, trperf, AA .. " होता", E .. " होते", II .. " होती", II .. " होतीं")
-- Progressive
add_conj_gendered_personal(base, "prog_ind_pres", nil, nil,
" रहा हूँ", " रहा है", " रहे हैं", " रहे हो",
" रही हूँ", " रही है", " रही हैं", " रही हो")
add_conj_gendered(base, "prog_ind_past", nil, nil,
" रहा था", " रहे थे", " रही थी", " रही थीं")
add_conj_gendered_personal(base, "prog_ind_fut", nil, nil,
" रहा हूँगा", " रहा होगा", " रहे होंगे", " रहे होगे",
" रही हूँगी", " रही होगी", " रही होंगी", " रही होगी")
add_conj_gendered_personal(base, "prog_presum", nil, nil,
" रहा हूँगा", " रहा होगा", " रहे होंगे", " रहे होगे",
" रही हूँगी", " रही होगी", " रही होंगी", " रही होगी")
add_conj_gendered_personal(base, "prog_subj_pres", nil, nil,
" रहा हूँ", " रहा हो", " रहे हों", " रहे हो",
" रही हूँ", " रही हो", " रही हों", " रही हो")
add_conj_gendered_personal(base, "prog_subj_fut", nil, nil,
" रहा होऊँ", " रहा होए", " रहे होएँ", " रहे होओ",
" रही होऊँ", " रही होए", " रही होएँ", " रही होओ")
add_conj_gendered(base, "prog_cfact", nil, nil, " रहा होता", " रहे होते", " रही होती", " रही होतीं")
end
--[=[
Parse an indicator spec (text consisting of angle brackets and zero or more
dot-separated indicators within them). Return value is an object of the form
{
forms = {}, -- forms for a single spec alternant; see `forms` below
-- The following additional fields are added by other functions:
orig_lemma = "ORIGINAL-LEMMA", -- as given by the user or taken from pagename
orig_lemma_no_links = "ORIGINAL-LEMMA-NO-LINKS", -- links removed
lemma = "LEMMA", -- `orig_lemma_no_links`, converted to singular form if plural
phon_lemma = "LEMMA-PHONETIC-RESPELLING", -- as specified by the user; may be missing
lemma_translit = "LEMMA-TRANSLIT", -- translit of phon_lemma (if present)
forms = {
SLOT = {
{
form = "FORM",
footnotes = {"FOOTNOTE", "FOOTNOTE", ...} -- may be missing
},
...
},
...
},
conj = "CONJ", -- declension, e.g. "normal" (the only one currently implemented)
}
]=]
local function parse_indicator_spec(angle_bracket_spec)
local inside = rmatch(angle_bracket_spec, "^<(.*)>$")
assert(inside)
local base = {overrides = {}, forms = {}}
if inside ~= "" then
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
-- No indicators allowed currently.
local part = dot_separated_group
error("Unrecognized indicator '" .. part .. "': '" .. inside .. "'")
end
end
return base
end
local function detect_indicator_spec(base)
base.conj = "normal"
base.stem, base.stem_translit = com.strip_ending(base, "ना")
end
local function detect_all_indicator_specs(alternant_multiword_spec)
iut.map_word_specs(alternant_multiword_spec, function(base)
detect_indicator_spec(base)
end)
-- Set notlast=true on verbs that aren't the last one in a multiword expression, and
-- multiword=true on all verbs in multiword expressions (as well as at top level), so
-- we can properly handle verbs like ].
for i, alternant_or_word_spec in ipairs(alternant_multiword_spec.alternant_or_word_specs) do
if alternant_or_word_spec.alternants then
for _, multiword_spec in ipairs(alternant_or_word_spec.alternants) do
for j, word_spec in ipairs(multiword_spec.word_specs) do
if j < #multiword_spec.word_specs then
word_spec.notlast = true
end
if #multiword_spec.word_specs > 1 then
word_spec.multiword = true
alternant_multiword_spec.multiword = true
end
end
end
else
if i < #alternant_multiword_spec.alternant_or_word_specs then
alternant_or_word_spec.notlast = true
end
if #alternant_multiword_spec.alternant_or_word_specs > 1 then
alternant_or_word_spec.multiword = true
alternant_multiword_spec.multiword = true
end
end
end
end
local function conjugate_verb(base)
if not conjs then
error("Internal error: Unrecognized conjugation type '" .. base.conj .. "'")
end
conjs(base)
if base.multiword then
-- See comment in add_variant_codes() for the purpose of this.
com.add_variant_codes(base)
end
handle_derived_slots_and_overrides(base)
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)
local cats = {}
local function insert(cattype)
cattype = rsub(cattype, "~", alternant_multiword_spec.pos)
m_table.insertIfNot(cats, "Hindi " .. cattype)
end
local annotation
if alternant_multiword_spec.manual then
alternant_multiword_spec.annotation = ""
else
local function do_word_spec(base)
if base.lemma_translit and (lang:transliterate(base.lemma)) ~= base.lemma_translit then
insert("~ with phonetic respelling")
end
end
iut.map_word_specs(alternant_multiword_spec, function(base)
do_word_spec(base)
end)
end
alternant_multiword_spec.categories = cats
end
-- Convert forms from their list/object form (see the comments to add() for how this works)
-- to strings that can be directly filled into the table. Approximately, each form is converted
-- to a formatted link with accelerators and the results are concatenated, followed by an newline
-- and then the formatted transliterations.
local function show_forms(alternant_multiword_spec)
local lemmas = alternant_multiword_spec.forms.inf_ms or {}
local props = {
lemmas = lemmas,
slot_table = verb_slots_impers,
lang = lang,
include_translit = true,
}
if alternant_multiword_spec.multiword then
-- Remove variant codes that were added to ensure only parallel variants in
-- multiword expressions like ] get generated. See com.add_variant_codes()
-- for more information.
props.canonicalize = function(form)
return com.remove_variant_codes(form)
end
end
iut.show_forms(alternant_multiword_spec.forms, props)
alternant_multiword_spec.forms.footnote_impers = alternant_multiword_spec.forms.footnote
props.slot_table = verb_slots_pers
iut.show_forms(alternant_multiword_spec.forms, props)
alternant_multiword_spec.forms.footnote_pers = alternant_multiword_spec.forms.footnote
end
-- Generate the conjugation table. This should be called after show_forms() has converted
-- each form to a formatted string.
local function make_table(alternant_multiword_spec)
local table_spec_impersonal = [=[
<div class="NavFrame">
<div class="NavHead hi-table-title" style="background: #d9ebff;">Impersonal forms of {inf_raw}</div>
<div class="NavContent">
{\op}| class="inflection-table inflection-hi inflection-verb" data-toggle-category="inflection" style="width:100%"
|-
! class="hi-tense-aspect-cell" colspan=100% | ''Undeclined''
|-
! class="hi-tense-aspect-cell" colspan=2 | ''Stem''
| colspan="100%" | {stem}
|-
! class="hi-tense-aspect-cell" colspan=2 | ''Infinitive''
| colspan="100%" | {inf}
|-
! class="hi-tense-aspect-cell" colspan=2 | ''Oblique Infinitive''
| colspan="100%" | {inf_obl}
|-
! class="hi-tense-aspect-cell" colspan=2 | ''Conjunctive''
| colspan="100%" | {conj}
|-
! class="hi-tense-aspect-cell" colspan=2 | ''Progressive''
| colspan="100%" | {prog}
|-
! class="hi-tense-aspect-cell" colspan=100% | ''Participles''
|-
|- class="hi-part-gender-number-header"
| class="hi-tense-aspect-cell" colspan=2 |
! {dir} {m} {s}
! {m} {p}<br />{obl} {m} {s}
! {f} {s}
! {f} {p}
|-
! class="hi-tense-aspect-cell" colspan=2 | ''Infinitive''
| {inf_ms}
| {inf_mp}
| {inf_fs}
| {inf_fp}
|-
! class="hi-tense-aspect-cell" colspan=2 | ''Habitual''
| {hab_ms}
| {hab_mp}
| {hab_fs}
| {hab_fp}
|-
! class="hi-tense-aspect-cell" colspan=2 | ''Perfective''
| {pfv_ms}
| {pfv_mp}
| {pfv_fs}
| {pfv_fp}
|-
! class="hi-tense-aspect-cell" colspan=2 | ''Prospective<br>Agentive''
| {agent_ms}
| {agent_mp}
| {agent_fs}
| {agent_fp}
|-
! class="hi-tense-aspect-cell" rowspan=2 | ''Adjectival''
! class="hi-tense-aspect-cell" | ''Perfective''
| {adj_pfv_ms}
| {adj_pfv_mp}
| {adj_pfv_fs}
| {adj_pfv_fp}
|-
! class="hi-tense-aspect-cell" | ''Habitual''
| {adj_hab_ms}
| {adj_hab_mp}
| {adj_hab_fs}
| {adj_hab_fp}
|{\cl}{notes_clause}</div></div>]=]
local person_number_header_two_row = [=[
|- class="hi-table-header"
| rowspan=2 |
| rowspan=2 |
| class="hi-mf-cell" rowspan=2 |
]=]
local person_number_header_sg_pl_headers = [=[
! colspan=3 | '''Singular'''
! colspan=3 | '''Plural'''
]=]
local person_number_header_table_div = [=[
|- class="hi-table-header"
]=]
local person_number_header_pers_num_headers = [=[
! '''1<sup>st</sup>'''<br><span lang="hi" class="Deva">]</span>
! '''2<sup>nd</sup>'''<br><span lang="hi" class="Deva">]</span>
! '''3<sup>rd</sup>'''<br><span lang="hi" class="Deva">]/], ]/]</span>
! '''2<sup>nd</sup>'''<br><span lang="hi" class="Deva">]</span>
! '''1<sup>st</sup>'''<br><span lang="hi" class="Deva">]</span>
! '''3<sup>rd</sup>, 2<sup>nd</sup>'''<br><span lang="hi" class="Deva">]/]/], ]</span>
]=]
-- Regular person-number header used at the top of the table and in the middle.
local person_number_header =
person_number_header_table_div .. person_number_header_two_row .. person_number_header_sg_pl_headers ..
person_number_header_table_div .. person_number_header_pers_num_headers
-- Reversed person-number header used at the bottom of the table. "Reversed" means that
-- the two rows are in reversed order; but internally we can't switch the order of everything
-- (e.g. the double-row cells at the left side), so we need to break up the header into multiple
-- parts and only reverse certain parts.
local reversed_person_number_header =
person_number_header_table_div .. person_number_header_two_row .. person_number_header_pers_num_headers ..
person_number_header_table_div .. person_number_header_sg_pl_headers
local table_spec_personal = [=[
<div class="NavFrame">
<div class="NavHead hi-table-title" style="background: #d9ebff;">Personal forms of {inf_raw}</div>
<div class="NavContent">
{\op}| class="inflection-table inflection-hi inflection-verb" data-toggle-category="inflection" style="width:100%"
|-
! class="hi-sec-div" rowspan=1 colspan=100% | ''Non-Aspectual''
{person_number_header}{pres_impf_table}! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | {PERF}
! class="hi-mf-cell" | {m}
| colspan=3 | {ind_perf_ms}
| colspan=3 | {ind_perf_mp}
|- class="hi-row-f"
! class="hi-mf-cell" | {f}
| colspan=4 | {ind_perf_fs}
| colspan=2 | {ind_perf_fp}
|- class="hi-row-m"
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | {FUT}
! class="hi-mf-cell" | {m}
| {ind_fut_1sm}
| colspan=2 | {ind_fut_23sm}
| {ind_fut_2pm}
| colspan=2 | {ind_fut_13pm}
|- class="hi-row-f"
! class="hi-mf-cell" | {f}
| {ind_fut_1sf}
| colspan=2 | {ind_fut_23sf}
| {ind_fut_2pf}
| colspan=2 | {ind_fut_13pf}
{presum_table}{subj_table}
|- class="hi-row-m"
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | ''Contrafactual''
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | {PST}
! class="hi-mf-cell" | {m}
| colspan=3 | {cfact_ms}
| colspan=3 | {cfact_mp}
|- class="hi-row-f"
! class="hi-mf-cell" | {f}
| colspan=4 | {cfact_fs}
| colspan=2 | {cfact_fp}
|-
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | ''Imperative''
! class="hi-tense-aspect-cell" rowspan=1 colspan=1 | {PRS}
! class="hi-mf-cell" | {mf}
|
| {imp_pres_2s}
|
| {imp_pres_2p}
|
| {imp_pres_3p}
|-
! class="hi-tense-aspect-cell" rowspan=1 colspan=1 | {FUT}
! class="hi-mf-cell" | {mf}
|
| {imp_fut_2s}
|
| {imp_fut_2p}
|
| {imp_fut_3p}
|-
! class="hi-sec-div" rowspan=1 colspan=100% | ''Habitual Aspect''
|- class="hi-row-m"
! class="hi-tense-aspect-cell" rowspan=4 colspan=1 | ''Indicative''
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | {PRS}
! class="hi-mf-cell" | {m}
| {hab_ind_pres_1sm}
| colspan=2 | {hab_ind_pres_23sm}
| {hab_ind_pres_2pm}
| colspan=2 | {hab_ind_pres_13pm}
|- class="hi-row-f"
! class="hi-mf-cell" | {f}
| {hab_ind_pres_1sf}
| colspan=2 | {hab_ind_pres_23sf}
| {hab_ind_pres_2pf}
| colspan=2 | {hab_ind_pres_13pf}
|- class="hi-row-m"
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | {PST}
! class="hi-mf-cell" | {m}
| colspan=3 | {hab_ind_past_ms}
| colspan=3 | {hab_ind_past_mp}
|- class="hi-row-f"
! class="hi-mf-cell" | {f}
| colspan=4 | {hab_ind_past_fs}
| colspan=2 | {hab_ind_past_fp}
|- class="hi-row-m"
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | ''Presumptive''
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | {PRS_PST}
! class="hi-mf-cell" | {m}
| {hab_presum_1sm}
| colspan=2 | {hab_presum_23sm}
| {hab_presum_2pm}
| colspan=2 | {hab_presum_13pm}
|- class="hi-row-f"
! class="hi-mf-cell" | {f}
| {hab_presum_1sf}
| colspan=2 | {hab_presum_23sf}
| {hab_presum_2pf}
| colspan=2 | {hab_presum_13pf}
|- class="hi-row-m"
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | ''Subjunctive''
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | {PRS}
! class="hi-mf-cell" | {m}
| {hab_subj_1sm}
| colspan=2 | {hab_subj_23sm}
| {hab_subj_2pm}
| colspan=2 | {hab_subj_13pm}
|- class="hi-row-f"
! class="hi-mf-cell" | {f}
| {hab_subj_1sf}
| colspan=2 | {hab_subj_23sf}
| {hab_subj_2pf}
| colspan=2 | {hab_subj_13pf}
|- class="hi-row-m"
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | ''Contrafactual''
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | {PST}
! class="hi-mf-cell" | {m}
| colspan=3 | {hab_cfact_ms}
| colspan=3 | {hab_cfact_mp}
|- class="hi-row-f"
! class="hi-mf-cell" | {f}
| colspan=4 | {hab_cfact_fs}
| colspan=2 | {hab_cfact_fp}
|-
! class="hi-sec-div" rowspan=1 colspan=100% | ''Perfective Aspect''
{person_number_header}|- class="hi-row-m"
! class="hi-tense-aspect-cell" rowspan=6 colspan=1 | ''Indicative''
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | {PRS}
! class="hi-mf-cell" | {m}
| {pfv_ind_pres_1sm}
| colspan=2 | {pfv_ind_pres_23sm}
| {pfv_ind_pres_2pm}
| colspan=2 | {pfv_ind_pres_13pm}
|- class="hi-row-f"
! class="hi-mf-cell" | {f}
| {pfv_ind_pres_1sf}
| colspan=2 | {pfv_ind_pres_23sf}
| {pfv_ind_pres_2pf}
| colspan=2 | {pfv_ind_pres_13pf}
|- class="hi-row-m"
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | {PST}
! class="hi-mf-cell" | {m}
| colspan=3 | {pfv_ind_past_ms}
| colspan=3 | {pfv_ind_past_mp}
|- class="hi-row-f"
! class="hi-mf-cell" | {f}
| colspan=4 | {pfv_ind_past_fs}
| colspan=2 | {pfv_ind_past_fp}
|- class="hi-row-m"
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | {FUT}
! class="hi-mf-cell" | {m}
| {pfv_ind_fut_1sm}
| colspan=2 | {pfv_ind_fut_23sm}
| {pfv_ind_fut_2pm}
| colspan=2 | {pfv_ind_fut_13pm}
|- class="hi-row-f"
! class="hi-mf-cell" | {f}
| {pfv_ind_fut_1sf}
| colspan=2 | {pfv_ind_fut_23sf}
| {pfv_ind_fut_2pf}
| colspan=2 | {pfv_ind_fut_13pf}
|- class="hi-row-m"
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | ''Presumptive''
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | {PRS_PST}
! class="hi-mf-cell" | {m}
| {pfv_presum_1sm}
| colspan=2 | {pfv_presum_23sm}
| {pfv_presum_2pm}
| colspan=2 | {pfv_presum_13pm}
|- class="hi-row-f"
! class="hi-mf-cell" | {f}
| {pfv_presum_1sf}
| colspan=2 | {pfv_presum_23sf}
| {pfv_presum_2pf}
| colspan=2 | {pfv_presum_13pf}
|- class="hi-row-m"
! class="hi-tense-aspect-cell" rowspan=4 colspan=1 | ''Subjunctive''
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | {PRS}
! class="hi-mf-cell" | {m}
| {pfv_subj_pres_1sm}
| colspan=2 | {pfv_subj_pres_23sm}
| {pfv_subj_pres_2pm}
| colspan=2 | {pfv_subj_pres_13pm}
|- class="hi-row-f"
! class="hi-mf-cell" | {f}
| {pfv_subj_pres_1sf}
| colspan=2 | {pfv_subj_pres_23sf}
| {pfv_subj_pres_2pf}
| colspan=2 | {pfv_subj_pres_13pf}
|- class="hi-row-m"
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | {FUT}
! class="hi-mf-cell" | {m}
| {pfv_subj_fut_1sm}
| colspan=2 | {pfv_subj_fut_23sm}
| {pfv_subj_fut_2pm}
| colspan=2 | {pfv_subj_fut_13pm}
|- class="hi-row-f"
! class="hi-mf-cell" | {f}
| {pfv_subj_fut_1sf}
| colspan=2 | {pfv_subj_fut_23sf}
| {pfv_subj_fut_2pf}
| colspan=2 | {pfv_subj_fut_13pf}
|- class="hi-row-m"
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | ''Contrafactual''
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | {PST}
! class="hi-mf-cell" | {m}
| colspan=3 | {pfv_cfact_ms}
| colspan=3 | {pfv_cfact_mp}
|- class="hi-row-f"
! class="hi-mf-cell" | {f}
| colspan=4 | {pfv_cfact_fs}
| colspan=2 | {pfv_cfact_fp}
|-
! class="hi-sec-div" rowspan=1 colspan=100% | ''Progressive Aspect''
|- class="hi-row-m"
! class="hi-tense-aspect-cell" rowspan=6 colspan=1 | ''Indicative''
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | {PRS}
! class="hi-mf-cell" | {m}
| {prog_ind_pres_1sm}
| colspan=2 | {prog_ind_pres_23sm}
| {prog_ind_pres_2pm}
| colspan=2 | {prog_ind_pres_13pm}
|- class="hi-row-f"
! class="hi-mf-cell" | {f}
| {prog_ind_pres_1sf}
| colspan=2 | {prog_ind_pres_23sf}
| {prog_ind_pres_2pf}
| colspan=2 | {prog_ind_pres_13pf}
|- class="hi-row-m"
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | {PST}
! class="hi-mf-cell" | {m}
| colspan=3 | {prog_ind_past_ms}
| colspan=3 | {prog_ind_past_mp}
|- class="hi-row-f"
! class="hi-mf-cell" | {f}
| colspan=4 | {prog_ind_past_fs}
| colspan=2 | {prog_ind_past_fp}
|- class="hi-row-m"
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | {FUT}
! class="hi-mf-cell" | {m}
| {prog_ind_fut_1sm}
| colspan=2 | {prog_ind_fut_23sm}
| {prog_ind_fut_2pm}
| colspan=2 | {prog_ind_fut_13pm}
|- class="hi-row-f"
! class="hi-mf-cell" | {f}
| {prog_ind_fut_1sf}
| colspan=2 | {prog_ind_fut_23sf}
| {prog_ind_fut_2pf}
| colspan=2 | {prog_ind_fut_13pf}
|- class="hi-row-m"
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | ''Presumptive''
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | {PRS_PST_FUT}
! class="hi-mf-cell" | {m}
| {prog_presum_1sm}
| colspan=2 | {prog_presum_23sm}
| {prog_presum_2pm}
| colspan=2 | {prog_presum_13pm}
|- class="hi-row-f"
! class="hi-mf-cell" | {f}
| {prog_presum_1sf}
| colspan=2 | {prog_presum_23sf}
| {prog_presum_2pf}
| colspan=2 | {prog_presum_13pf}
|- class="hi-row-m"
! class="hi-tense-aspect-cell" rowspan=4 colspan=1 | ''Subjunctive''
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | {PRS}
! class="hi-mf-cell" | {m}
| {prog_subj_pres_1sm}
| colspan=2 | {prog_subj_pres_23sm}
| {prog_subj_pres_2pm}
| colspan=2 | {prog_subj_pres_13pm}
|- class="hi-row-f"
! class="hi-mf-cell" | {f}
| {prog_subj_pres_1sf}
| colspan=2 | {prog_subj_pres_23sf}
| {prog_subj_pres_2pf}
| colspan=2 | {prog_subj_pres_13pf}
|- class="hi-row-m"
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | {FUT}
! class="hi-mf-cell" | {m}
| {prog_subj_fut_1sm}
| colspan=2 | {prog_subj_fut_23sm}
| {prog_subj_fut_2pm}
| colspan=2 | {prog_subj_fut_13pm}
|- class="hi-row-f"
! class="hi-mf-cell" | {f}
| {prog_subj_fut_1sf}
| colspan=2 | {prog_subj_fut_23sf}
| {prog_subj_fut_2pf}
| colspan=2 | {prog_subj_fut_13pf}
|- class="hi-row-m"
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | ''Contrafactual''
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | {PST}
! class="hi-mf-cell" | {m}
| colspan=3 | {prog_cfact_ms}
| colspan=3 | {prog_cfact_mp}
|- class="hi-row-f"
! class="hi-mf-cell" | {f}
| colspan=4 | {prog_cfact_fs}
| colspan=2 | {prog_cfact_fp}
{reversed_person_number_header}|{\cl}{notes_clause}</div></div>]=]
local pres_impf_table = [=[
|-
! class="hi-tense-aspect-cell" rowspan=7 colspan=1 | ''Indicative''
! class="hi-tense-aspect-cell" rowspan=1 colspan=1 | {PRS}
! class="hi-mf-cell" | {mf}
| {ind_pres_1s}
| colspan=2 | {ind_pres_23s}
| {ind_pres_2p}
| colspan=2 | {ind_pres_13p}
|- class="hi-row-m"
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | {IMPF}
! class="hi-mf-cell" | {m}
| colspan=3 | {ind_impf_ms}
| colspan=3 | {ind_impf_mp}
|- class="hi-row-f"
! class="hi-mf-cell" | {f}
| colspan=4 | {ind_impf_fs}
| colspan=2 | {ind_impf_fp}
|- class="hi-row-m"
]=]
local pres_impf_table_missing = [=[
|- class="hi-row-m"
! class="hi-tense-aspect-cell" rowspan=4 colspan=1 | ''Indicative''
]=]
local presum_table = [=[
|- class="hi-row-m"
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | ''Presumptive''
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | {PRS_PST_FUT}
! class="hi-mf-cell" | {m}
| {presum_1sm}
| colspan=2 | {presum_23sm}
| {presum_2pm}
| colspan=2 | {presum_13pm}
|- class="hi-row-f"
! class="hi-mf-cell" | {f}
| {presum_1sf}
| colspan=2 | {presum_23sf}
| {presum_2pf}
| colspan=2 | {presum_13pf}
]=]
local combined_subj = [=[
|-
! class="hi-tense-aspect-cell" rowspan=1 colspan=1 | ''Subjunctive''
! class="hi-tense-aspect-cell" rowspan=1 colspan=1 | {FUT}
! class="hi-mf-cell" | {mf}
| {subj_fut_1s}
| colspan=2 | {subj_fut_23s}
| {subj_fut_2p}
| colspan=2 | {subj_fut_13p}]=]
local split_subj = [=[
|-
! class="hi-tense-aspect-cell" rowspan=2 colspan=1 | ''Subjunctive''
! class="hi-tense-aspect-cell" rowspan=1 colspan=1 | {PRS}
! class="hi-mf-cell" | {mf}
| {subj_pres_1s}
| colspan=2 | {subj_pres_23s}
| {subj_pres_2p}
| colspan=2 | {subj_pres_13p}
|-
! class="hi-tense-aspect-cell" rowspan=1 colspan=1 | {FUT}
! class="hi-mf-cell" | {mf}
| {subj_fut_1s}
| colspan=2 | {subj_fut_23s}
| {subj_fut_2p}
| colspan=2 | {subj_fut_13p}]=]
local notes_template = [===[
<div class="hi-footnote-outer-div">
<div class="hi-footnote-inner-div">
{footnote}
</div></div>
]===]
local forms = alternant_multiword_spec.forms
local function make_gender_abbr(title, text)
return '<span class="gender"><abbr title="' .. title .. '">' .. text .. '</abbr></span>'
end
local function make_tense_aspect_abbr(title, text)
local template = [=[
''<abbr style="font-variant: small-caps; text-transform: lowercase;" title="{title}">{text}</abbr>'']=]
return m_string_utilities.format(template, {title = title, text = text})
end
forms.m = make_gender_abbr("masculine gender", "m")
forms.f = make_gender_abbr("feminine gender", "f")
forms.mf = forms.m .. "<br />" .. forms.f
forms.s = make_gender_abbr("singular number", "s")
forms.p = make_gender_abbr("plural number", "p")
forms.dir = make_gender_abbr("direct", "dir")
forms.obl = make_gender_abbr("oblique", "obl")
forms.PERF = make_tense_aspect_abbr("Perfect", "PERF")
forms.IMPF = make_tense_aspect_abbr("Imperfect", "IMPF")
forms.PST = make_tense_aspect_abbr("Past", "PST")
forms.FUT = make_tense_aspect_abbr("Future", "FUT")
forms.PRS = make_tense_aspect_abbr("Present", "PRS")
forms.PRS_FUT = make_tense_aspect_abbr("Present/Future", "PRS<br />FUT")
forms.PRS_PST = make_tense_aspect_abbr("Present/Past", "PRS<br />PST")
forms.PRS_PST_FUT = make_tense_aspect_abbr("Present/Past/Future", "PRS<br />PST<br />FUT")
forms.inf_raw = tag_text(forms.lemma)
-- Now format the impersonal table.
forms.footnote = forms.footnote_impers
forms.notes_clause = forms.footnote ~= "" and
m_string_utilities.format(notes_template, forms) or ""
local formatted_table_impers = m_string_utilities.format(table_spec_impersonal, forms)
-- Now format the personal table.
forms.footnote = forms.footnote_pers
forms.notes_clause = forms.footnote ~= "" and
m_string_utilities.format(notes_template, forms) or ""
if forms.ind_pres_1s ~= "—" then -- होना
forms.subj_table = m_string_utilities.format(split_subj, forms)
forms.pres_impf_table = m_string_utilities.format(pres_impf_table, forms)
forms.presum_table = m_string_utilities.format(presum_table, forms)
else
forms.subj_table = m_string_utilities.format(combined_subj, forms)
forms.pres_impf_table = pres_impf_table_missing
forms.presum_table = ""
end
forms.person_number_header = person_number_header
forms.reversed_person_number_header = reversed_person_number_header
local formatted_table_pers = m_string_utilities.format(table_spec_personal, forms)
-- Concatenate both.
return require("Module:TemplateStyles")("Module:hi-verb/style.css") .. formatted_table_impers .. formatted_table_pers
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, translit=TRANSLIT, footnotes=FOOTNOTES}.
function export.do_generate_forms(parent_args, pos, from_headword, def)
local params = {
= {template_default = def or "करना"},
title = {},
pagename = {},
}
if from_headword then
params = {list = true}
params = {}
end
local args = m_para.process(parent_args, params)
local pagename = args.pagename or mw.loadData("Module:headword/data").pagename
if not args then
args = pagename
-- If pagename has spaces in it, add links around each word
if args:find(" ") then
args = ", " ", "]] ]"
end
end
local parse_props = {
parse_indicator_spec = parse_indicator_spec,
lang = lang,
transliterate_respelling = com.transliterate_respelling,
allow_default_indicator = true,
allow_blank_lemma = true,
}
local alternant_multiword_spec = iut.parse_inflected_text(args, parse_props)
alternant_multiword_spec.title = args.title
alternant_multiword_spec.pos = pos or "verbs"
alternant_multiword_spec.args = args
alternant_multiword_spec.pagename = pagename
com.normalize_all_lemmas(alternant_multiword_spec)
detect_all_indicator_specs(alternant_multiword_spec)
local inflect_props = {
slot_table = all_verb_slots,
lang = lang,
inflect_word_spec = conjugate_verb,
-- Return the variant code that was added to ensure only parallel variants in
-- multiword expressions like ] get generated. See com.add_variant_codes()
-- for more information.
get_variants = alternant_multiword_spec.multiword and com.get_variants or nil,
-- 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_categories_and_annotation(alternant_multiword_spec)
return alternant_multiword_spec
end
-- Entry point for {{hi-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,...|...". Each FORM is either a string in Devanagari or
-- (if manual translit is present) a specification of the form "FORM//TRANSLIT" where FORM is the
-- Devanagari representation of the form and TRANSLIT its manual transliteration. 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, _ in pairs(all_verb_slots) do
local formtext = iut.concat_forms_in_slot(alternant_multiword_spec.forms)
if formtext then
table.insert(ins_text, slot .. "=" .. formtext)
end
end
return table.concat(ins_text, "|")
end
-- Template-callable function to parse and conjugate a verb given user-specified arguments and return
-- the forms as a string of the same form as documented in concat_forms() above.
function export.generate_forms(frame)
local include_props = frame.args
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