local export = {}
--[=[
Authorship: Aryaman Arora <AryamanA> based on work by 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 Marathi form representing the value of a given slot.
-- "lemma" = The dictionary form of a given Marathi term. Generally the direct
masculine singular infinitive, but may occasionally be another form if
that form is missing.
]=]
--[=[
FIXME:
]=]
local lang = require("Module:languages").getByCode("mr")
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:mr-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 = {
}
local irreg_subj = {
}
local irreg_polite_imp = {
}
local verb_slots_impers = {
inf = "inf",
stem = "stem",
compl = "compl",
pros = "pros",
inc = "inc",
desid = "desid",
}
local verb_slots_pers = {
subj_neg = "subj_neg",
}
-- 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
verb_slots = tag_suffix == "-" and "-" or "n|s|" .. tag_suffix
verb_slots = tag_suffix == "-" and "-" or "n|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"}
else
return {"1s", "2s", "3s", "1p", "2p", "3p"}
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", "n"}) 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_personal("ind_hab", "hab|ind")
add_slot_personal("ind_hab_neg", "hab|ind|neg")
add_slot_gendered_personal("ind_perf", "perf|ind")
add_slot_gendered_personal("ind_perf_neg", "perf|ind|neg")
add_slot_gendered("subj", "subj")
add_slot_gendered_personal("prs_prog", "prs|prog")
add_slot_personal("prs_prog_neg", "prs|prog|neg")
add_slot_gendered_personal("pst_prog", "pst|prog")
add_slot_gendered_personal("pst_prog_neg", "pst|prog|neg")
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
-- 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
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, n_s, n_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)
add(base, stem, translit_stem, slot_prefix .. "_ns", n_s, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_np", n_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, s2, s3, p1, p2, p3, 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 .. "_2s", s2, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_3s", s3, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_1p", p1, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_2p", p2, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_3p", p3, 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, s2m, s3m, p1m, p2m, p3m, s1f, s2f, s3f, p1f, p2f, p3f, s1n, s2n, s3n, p1n, p2n, p3n, 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 .. "_2sm", s2m, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_3sm", s3m, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_1pm", p1m, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_2pm", p2m, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_3pm", p3m, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_1sf", s1f, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_2sf", s2f, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_3sf", s3f, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_1pf", p1f, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_2pf", p2f, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_3pf", p3f, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_1sn", s1n, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_2sn", s2n, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_3sn", s3n, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_1pn", p1n, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_2pn", p2n, footnotes)
add(base, stem, translit_stem, slot_prefix .. "_3pn", p3n, 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", "णं")
add(base, base.stem, base.stem_translit, "compl", UU .. "न")
add(base, base.stem, base.stem_translit, "pros", "णार")
add(base, base.stem, base.stem_translit, "inc", UU)
add(base, base.stem, base.stem_translit, "desid", AA .. "यला")
add_conj_gendered_personal(base, "ind_hab", nil, nil, "तो", "तोस", "तो", "तो", "ता", "तात", "ते", "तेस", "ते", "तो", "ता", "तात", nil, nil, "ते", "तो", "ता", "तात")
add_conj_personal(base, "ind_hab_neg", nil, nil, "त नाही", "त नाहीस", "त नाही", "त नाही", "त नाही", "त नाहीत")
add(base, base.stem, base.stem_translit, "ind_hab_3sn", "तं")
add_conj_gendered_personal(base, "ind_perf", nil, nil, "लो", "लास", "ला", "लो", "ला", "ले", "ले", "लीस", "ली", "लो", "ला", "ल्या", nil, nil, "ले", nil, nil, "ली")
add(base, base.stem, base.stem_translit, "ind_perf_3sn", "लं")
add(base, base.stem, base.stem_translit, "ind_perf_2pm", "लात")
add(base, base.stem, base.stem_translit, "ind_perf_2pf", "लात")
add_conj_gendered_personal(base, "ind_perf_neg", nil, nil, "लो नाही", "ला नाहीस", "ला नाही", "लो नाही", "ला नाहीत", "ले नाहीत", "ले नाही", "ली नाहीस", "ली नाही", "लो नाही", "ला नाहीत", "ल्या नाहीत", nil, nil, "ले नाही", nil, nil, "ली नाहीत")
add(base, base.stem, base.stem_translit, "ind_perf_neg_3sn", "लं नाही")
add_conj_gendered(base, "subj", nil, nil, AA .. "वा", AA .. "वे", AA .. "वी", AA .. "व्या", AA .. "वे", AA .. "वी")
add(base, base.stem, base.stem_translit, "subj_mp", AA .. "वेत")
add(base, base.stem, base.stem_translit, "subj_fp", AA .. "व्यात")
add(base, base.stem, base.stem_translit, "subj_ns", AA .. "वं")
add(base, base.stem, base.stem_translit, "subj_np", AA .. "वीत")
add(base, base.stem, base.stem_translit, "subj_neg", UU .. " नए")
add_conj_gendered_personal(base, "prs_prog", nil, nil, "तो आहे", "तो आहेस", "तो आहे", "तो आहोत", "ता आहात", "ता आहेत", "ते आहे", "ते आहेस", "ते आहे", "तो आहोत", "ता आहात", "ता आहेत", nil, nil, "ते आहे", "तो आहोत", "ता आहात", "ता आहेत")
-- add_conj_gendered_personal(base, "prs_prog", nil, nil, "तोय", "तोयस", "तोय", "तोय", "ताय", "तायत", "त्येय", "त्येस", "त्येय", "तोय", "ताय", "तायत", nil, nil, "तंय", "तोय", "ताय", "तायत")
add_conj_personal(base, "prs_prog_neg", nil, nil, "त नाहीये", "त नाहीयेस", "त नाहीये", "त नाहीयोत", "त नाहीयात", "त नाहीयेत")
add_conj_gendered_personal(base, "pst_prog", nil, nil, "त होतो", "त होतास", "त होता", "त होतो", "त होता", "त होते", "त होते", "त होतीस", "त होती", "त होतो", "त होता", "त होत्या", nil, nil, "त होते", nil, nil, "त होती")
add(base, base.stem, base.stem_translit, "pst_prog_3sn", "त होतं")
add_conj_gendered_personal(base, "pst_prog_neg", nil, nil, "त नव्हतो", "त नव्हतास", "त नव्हता", "त नव्हतो", "त नव्हता", "त नव्हते", "त नव्हते", "त नव्हतीस", "त नव्हती", "त नव्हतो", "त नव्हता", "त नव्हत्या", nil, nil, "त नव्हते", nil, nil, "त नव्हती")
add(base, base.stem, base.stem_translit, "pst_prog_neg_3sn", "त नव्हतं")
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, "Marathi " .. 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" style="display: table;">
<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"
|-
| 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 | ''Completive''
| colspan="100%" | {compl}
|-
| class="hi-tense-aspect-cell" colspan=2 | ''Prospective''
| colspan="100%" | {pros}
|-
| class="hi-tense-aspect-cell" colspan=2 | ''Inceptive''
| colspan="100%" | {inc}
|-
| class="hi-tense-aspect-cell" colspan=2 | ''Desiderative''
| colspan="100%" | {desid}
|{\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="mr" class="Deva">]</span>
| '''2<sup>nd</sup> intimate'''<br><span lang="mr" class="Deva">]</span>
| '''3<sup>rd</sup>'''<br><span lang="mr" class="Deva">]/]</span>
| '''1<sup>st</sup>'''<br><span lang="mr" class="Deva">]/]</span>
| '''2<sup>nd</sup>'''<br><span lang="mr" class="Deva">]</span>
| '''3<sup>rd</sup>'''<br><span lang="mr" 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" style="display: table;>
<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"
|-
| class="hi-sec-div" rowspan=1 colspan=100% | ''Non-Aspectual''
{person_number_header}
|-
| class="hi-tense-aspect-cell" rowspan=4 colspan=1 | Subjunctive
| class="hi-polarity-cell" rowspan=3 colspan=1 | +
| class="hi-mf-cell" | {m}
| colspan=3 | {subj_ms}
| colspan=3 | {subj_mp}
|-
| class="hi-mf-cell" | {f}
| colspan=3 | {subj_fs}
| colspan=3 | {subj_fp}
|-
| class="hi-mf-cell" | {n}
|
|
| {subj_ns}
|
|
| {subj_np}
|-
| class="hi-polarity-cell" rowspan=1 colspan=1 | –
| class="hi-mf-cell" | {mfn}
| colspan=6 | {subj_neg}
|-
| class="hi-sec-div" rowspan=1 colspan=100% | ''Perfective''
|-
| class="hi-tense-aspect-cell" rowspan=6 colspan=1 | Unmarked
| class="hi-polarity-cell" rowspan=3 colspan=1 | +
| class="hi-mf-cell" | {m}
| {ind_perf_1sm}
| {ind_perf_2sm}
| {ind_perf_3sm}
| {ind_perf_1pm}
| {ind_perf_2pm}
| {ind_perf_3pm}
|- class="hi-row-f"
| class="hi-mf-cell" | {f}
| {ind_perf_1sf}
| {ind_perf_2sf}
| {ind_perf_3sf}
| {ind_perf_1pf}
| {ind_perf_2pf}
| {ind_perf_3pf}
|- class="hi-row-f"
| class="hi-mf-cell" | {n}
|
|
| {ind_perf_3sn}
|
|
| {ind_perf_3pn}
|-
| class="hi-polarity-cell" rowspan=3 colspan=1 | –
| class="hi-mf-cell" | {m}
| {ind_perf_neg_1sm}
| {ind_perf_neg_2sm}
| {ind_perf_neg_3sm}
| {ind_perf_neg_1pm}
| {ind_perf_neg_2pm}
| {ind_perf_neg_3pm}
|- class="hi-row-f"
| class="hi-mf-cell" | {f}
| {ind_perf_neg_1sf}
| {ind_perf_neg_2sf}
| {ind_perf_neg_3sf}
| {ind_perf_neg_1pf}
| {ind_perf_neg_2pf}
| {ind_perf_neg_3pf}
|- class="hi-row-f"
| class="hi-mf-cell" | {n}
|
|
| {ind_perf_neg_3sn}
|
|
| {ind_perf_neg_3pn}
|-
| class="hi-sec-div" rowspan=1 colspan=100% | ''Imperfective''
|-
| class="hi-tense-aspect-cell" rowspan=4 colspan=1 | {HAB}
| class="hi-polarity-cell" rowspan=3 colspan=1 | +
| class="hi-mf-cell" | {m}
| {ind_hab_1sm}
| {ind_hab_2sm}
| {ind_hab_3sm}
| rowspan = 2 | {ind_hab_1pm}
| rowspan = 2 | {ind_hab_2pm}
| rowspan = 3 | {ind_hab_3pm}
|- class="hi-row-f"
| class="hi-mf-cell" | {f}
| {ind_hab_1sf}
| {ind_hab_2sf}
| {ind_hab_3sf}
|- class="hi-row-f"
| class="hi-mf-cell" | {n}
|
|
| {ind_hab_3sn}
|
|
|-
| class="hi-polarity-cell" rowspan=1 colspan=1 | –
| class="hi-mf-cell" | {mfn}
| {ind_hab_neg_1s}
| {ind_hab_neg_2s}
| {ind_hab_neg_3s}
| {ind_hab_neg_1p}
| {ind_hab_neg_2p}
| {ind_hab_neg_3p}
|-
| class="hi-tense-aspect-cell" rowspan=4 colspan=1 | {PRS}
| class="hi-polarity-cell" rowspan=3 colspan=1 | +
| class="hi-mf-cell" | {m}
| {prs_prog_1sm}
| {prs_prog_2sm}
| {prs_prog_3sm}
| rowspan=2 | {prs_prog_1pm}
| rowspan=2 | {prs_prog_2pm}
| rowspan=3 | {prs_prog_3pm}
|- class="hi-row-f"
| class="hi-mf-cell" | {f}
| {prs_prog_1sf}
| {prs_prog_2sf}
| {prs_prog_3sf}
|- class="hi-row-f"
| class="hi-mf-cell" | {n}
|
|
| {prs_prog_3sn}
|
|
|-
| class="hi-polarity-cell" rowspan=1 colspan=1 | –
| class="hi-mf-cell" | {mfn}
| {prs_prog_neg_1s}
| {prs_prog_neg_2s}
| {prs_prog_neg_3s}
| {prs_prog_neg_1p}
| {prs_prog_neg_2p}
| {prs_prog_neg_3p}
|-
| class="hi-tense-aspect-cell" rowspan=6 colspan=1 | {PST}
| class="hi-polarity-cell" rowspan=3 colspan=1 | +
| class="hi-mf-cell" | {m}
| {pst_prog_1sm}
| {pst_prog_2sm}
| {pst_prog_3sm}
| {pst_prog_1pm}
| {pst_prog_2pm}
| {pst_prog_3pm}
|- class="hi-row-f"
| class="hi-mf-cell" | {f}
| {pst_prog_1sf}
| {pst_prog_2sf}
| {pst_prog_3sf}
| {pst_prog_1pf}
| {pst_prog_2pf}
| {pst_prog_3pf}
|- class="hi-row-f"
| class="hi-mf-cell" | {n}
|
|
| {pst_prog_3sn}
|
|
| {pst_prog_3pn}
|-
| class="hi-polarity-cell" rowspan=3 colspan=1 | —
| class="hi-mf-cell" | {m}
| {pst_prog_neg_1sm}
| {pst_prog_neg_2sm}
| {pst_prog_neg_3sm}
| {pst_prog_neg_1pm}
| {pst_prog_neg_2pm}
| {pst_prog_neg_3pm}
|- class="hi-row-f"
| class="hi-mf-cell" | {f}
| {pst_prog_neg_1sf}
| {pst_prog_neg_2sf}
| {pst_prog_neg_3sf}
| {pst_prog_neg_1pf}
| {pst_prog_neg_2pf}
| {pst_prog_neg_3pf}
|- class="hi-row-f"
| class="hi-mf-cell" | {n}
|
|
| {pst_prog_neg_3sn}
|
|
| {pst_prog_neg_3pn}
{reversed_person_number_header}|{\cl}{notes_clause}</div></div>]=]
local pres_impf_table = =]
local pres_impf_table_missing = =]
local presum_table = =]
local combined_subj = =]
local split_subj = =]
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.n = make_gender_abbr("feminine gender", "n")
forms.mfn = forms.m .. " " .. forms.f .. " " .. forms.n
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.HAB = make_tense_aspect_abbr("Habitual", "HAB")
forms.PERF = make_tense_aspect_abbr("Perfect", "PERF")
forms.SUBJ = make_tense_aspect_abbr("Subjunctive", "SUBJ")
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
-- Implementation of template 'hi-verb cat'.
-- NOTE: Not currently used.
function export.catboiler(frame)
local SUBPAGENAME = mw.title.getCurrentTitle().subpageText
local params = {
= {},
}
local args = m_para.process(frame:getParent().args, params)
local function get_pos()
local pos = rmatch(SUBPAGENAME, "^Marathi.- (*)s ")
if not pos then
pos = rmatch(SUBPAGENAME, "^Marathi.- (*)s$")
end
if not pos then
error("Invalid category name, should be e.g. \"Marathi verbs with ...\" or \"Marathi ... verbs\"")
end
return pos
end
local function get_sort_key()
local pos, sort_key = rmatch(SUBPAGENAME, "^Marathi.- (*)s with (.*)$")
if sort_key then
return sort_key
end
pos, sort_key = rmatch(SUBPAGENAME, "^Marathi (*)s (.*)$")
if sort_key then
return sort_key
end
return rsub(SUBPAGENAME, "^Marathi ", "")
end
local cats = {}, pos
-- Insert the category CAT (a string) into the categories. String will
-- have "Marathi " prepended and ~ substituted for the plural part of speech.
local function insert(cat, atbeg)
local fullcat = "Marathi " .. rsub(cat, "~", pos .. "s")
if atbeg then
table.insert(cats, 1, fullcat)
else
table.insert(cats, fullcat)
end
end
local maintext
while true do
if args then
maintext = "~ " .. args
pos = get_pos()
break
end
error("Unrecognized Marathi verb category name")
end
insert("~|" .. get_sort_key(), "at beginning")
local categories = {}
for _, cat in ipairs(cats) do
table.insert(categories, "]")
end
return "This category contains Marathi " .. rsub(maintext, "~", pos .. "s")
.. "\n" ..
mw.getCurrentFrame():expandTemplate{title="mr-categoryTOC", args={}}
.. table.concat(categories, "")
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 = {
= {},
title = {},
}
if from_headword then
params = {list = true}
params = {}
end
local args = m_para.process(parent_args, params)
local PAGENAME = mw.title.getCurrentTitle().text
if not args then
if PAGENAME == "mr-conj" then
args = def or "ऐकणे"
else
args = PAGENAME
-- If pagename has spaces in it, add links around each word
if args:find(" ") then
args = ", " ", "]] ]"
end
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
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_spec, include_props)
local ins_text = {}
for slot, _ in pairs(verb_slots_with_linked) do
local formtext = iut.concat_forms_in_slot(alternant_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_spec = export.do_generate_forms(parent_args)
return concat_forms(alternant_spec, include_props)
end
return export