See Template:sa-conj
local export = {}
local m_params = require("Module:parameters")
local m_links = require("Module:links")
local m_utils = require("Module:utilities")
local lang = require("Module:languages").getByCode("sa")
local m_script_utils = require("Module:script utilities")
local m_str_utils = require("Module:string utilities")
local sa_verb_data = require("Module:sa-verb/data")
local SLP_to_IAST = require("Module:sa-utilities/translit/SLP1-to-IAST")
local sa_utils = require("Module:sa-utilities")
local sa_utils_translit = require("Module:sa-utilities/translit")
local columns = require("Module:columns")
local PAGENAME = mw.loadData("Module:headword/data").pagename
local concat = table.concat
local gsplit = m_str_utils.gsplit
local gsub = string.gsub
local insert = table.insert
local match = string.match
local split = m_str_utils.split
local ugsub = mw.ustring.gsub
local umatch = mw.ustring.match
local names = {
= "Present",
= "Imperfect",
= "Future",
= "Periphrastic Future",
= "Conditional",
= "Aorist",
= "Benedictive/Precative",
= "Perfect",
= "Periphrastic Perfect",
= "Indicative",
= "Imperative",
= "Optative/Potential",
= "Subjunctive",
= "Injunctive",
= "Participles",
= "Infinitive",
= "Gerund",
= "Masculine/Neuter Gerundive",
= "Feminine Gerundive",
= "Masculine/Neuter Past Passive Participle",
= "Feminine Past Passive Participle",
= "Masculine/Neuter Past Active Participle",
= "Feminine Past Active Participle",
= "Nonfinite Forms"
}
local tenses = {
= {
= { "indic", "imper", "optat", "subj", "part" },
= { "av", "mv" }
},
= {
= { "indic" },
= { "av", "mv" }
},
= {
= { "indic", "part" },
= { "av", "mv" }
},
= {
= { "indic" },
= { "av", "mv" }
},
= {
= { "indic" },
= { "av", "mv" }
},
= {
= { "indic", "inj", "subj" },
= { "av", "mv" }
},
= {
= { "optat" },
= { "av", "mv" }
},
= {
= { "indic", "part" },
= { "av", "mv" }
},
= {
= { "inf", "gerund", "gerundive_mn", "gerundive_f", "part_mn", "part_f", "part_av_mn", "part_av_f" }
}
}
local numbers = {"1_s", "2_s", "3_s", "1_d", "2_d", "3_d", "1_p", "2_p", "3_p"}
local super_nums = {
= "¹",
= "²",
= "³",
= "⁴",
= "⁵",
= "⁶",
= "⁷",
= "⁸",
= "⁹",
= "⁰"
}
local function to_super(num)
return (gsub(num, ".*", super_nums))
end
local function get_form_note_tags(form_notes, data)
local output = {}
if type(form_notes) ~= "table" then
form_notes = {form_notes}
end
for _, form_note in ipairs(form_notes) do
if type(data.form_notes) ~= "number" then
insert(data.form_notes_out, form_note)
data.form_notes = #data.form_notes_out
end
insert(output, to_super(data.form_notes))
end
return concat(output)
end
local function make_header(args, title_models)
local title = names .. ": " .. title_models
local header = {
'{| class="inflection-table vsSwitcher" data-toggle-category="inflection" style="background:#F9F9F9; text-align:center; border: 1px solid #CCC; width: 100%;"\n'
}
insert(header, '|- style="background: #d9ebff;"\n')
insert(
header,
'! class="vsToggleElement" style="text-align: left;" colspan="' .. args.colspan .. '" | ' .. title .. "\n"
)
insert(header, '|- class="vsHide"\n')
insert(header, '! style="background:#eff7ff" rowspan="2" |\n')
insert(header, '! colspan="3" style="background:#eff7ff" | Active\n')
if args.tense == "pfut" then
insert(header, '! colspan="3" style="background:#eff7ff" | Middle\n')
else
insert(header, '! colspan="3" style="background:#eff7ff" | Mediopassive\n')
end
insert(header, '|- class="vsHide"\n')
for _ = 1, 2 do
insert(header, '! style="background:#eff7ff" | Singular\n')
insert(header, '! style="background:#eff7ff" | Dual\n')
insert(header, '! style="background:#eff7ff" | Plural\n')
end
return concat(header)
end
local function make_cell(args, data, tag, arg_tag, sc_cache, col_span, voice)
local forms, links, trs = {}, {}, {}
if (not match(args.n, "a") and voice == "av") or (not match(args.n, "m") and voice == "mv") or (not match(args.n, "p") and voice == "pv") then
forms = {"-"}
elseif args then
forms = split(args, "%s*,%s*")
else
forms = data.forms
end
if not forms then
return "| -\n"
end
for i, form in ipairs(forms) do
form = sc_cache.tr(form)
form = gsub(form, 'V', 'f')
form = gsub(form, "Z", "x")
-- a superscript number at the end of manually added forms should not be part of the (linked) form
local extra_note_tag = ""
if umatch(form, "$") then
extra_note_tag = ugsub(form, "^.+(.)$", "%1")
form = gsub(form, ".*$", "")
end
local form_note_tag = get_form_note_tags(forms or {}, data)
if form == "" then -- in case of form reduced to zero by 'novedic' parameter
-- do nothing
elseif form == "-" then
insert(links, form)
insert(trs, form)
else
insert(
links,
m_links.full_link({term = sc_cache.reverse_tr(form), tr = "-", lang = lang, sc = sc_cache.sc}) ..
form_note_tag .. extra_note_tag
)
insert(trs, SLP_to_IAST.tr(form) .. form_note_tag .. extra_note_tag)
end
end
return concat {
"| ",
"colspan = ",
col_span,
" | ",
concat(links, " / "),
"<br/>",
m_script_utils.tag_translit(concat(trs, " / "), lang, "default", 'style="color: #888;"'),
"\n"
}
end
local function format_notes(args, data)
local output = {
'|- class="vsHide"',
'| style="background-color:#eff7ff; font-style:italic;border-top:double #888;" | Notes',
'| style="text-align:left;border-top:double #888;" colspan="' .. args.colspan .. '" |'
}
if #data.form_notes_out > 0 or #data.general_notes > 0 or #args.note > 0 then
for _, general_note in ipairs(data.general_notes) do
insert(output, "* " .. general_note)
end
for i, form_note in ipairs(data.form_notes_out) do
insert(output, "* " .. to_super(i) .. form_note)
end
for _, note in ipairs(args.note) do
insert(output, "* " .. note)
end
return concat(output, "\n") .. "\n"
else
return ""
end
end
local function make_nonf_table(args, data, output, sc_cache)
local moods = tenses.moods
local part_mn = data.forms
if part_mn ~= "-" and part_mn ~= nil then
local part_av_mn, part_av_f = {}, {}
for _, form in ipairs(part_mn) do
insert(part_av_mn, form .. "vat") -- these two formed directly from the given forms always
insert(part_av_f, form .. "vatī")
end
data.forms = part_av_mn
data.forms = part_av_f
else
data.forms = { "-" }
data.forms = { "-" }
end
local title_models = ""
local tag = moods
local arg_tag = moods
local forms
if args then
forms = split(args, "%s*,%s*")
else
forms = data.forms
end
for i, title_lem in ipairs(forms) do
title_lem = sc_cache.tr(title_lem)
title_lem = gsub(title_lem, 'V', 'f')
title_lem = gsub(title_lem, "Z", "x")
if i > 1 then
title_models = title_models .. " or "
end
title_models =
title_models ..
m_links.full_link(
{
alt = sc_cache.reverse_tr(title_lem),
tr = SLP_to_IAST.tr(title_lem),
lang = lang,
sc = sc_cache.sc
}
)
end
local title = names .. ": " .. title_models
insert(output, 'Forms of Sanskrit verbs are numerous and complicated. The following conjugation shows only a subset of all forms and should be treated as a guide. \n')
insert(
output,
'{| class="inflection-table vsSwitcher" data-toggle-category="inflection" style="background:#F9F9F9; text-align:center; border: 1px solid #CCC; width: 40em"\n'
)
insert(output, '|- style="background: #d9ebff;"\n')
insert(output, '! class="vsToggleElement" style="text-align: left;" colspan="4" | ' .. title .. "\n")
insert(output, '|- class="vsHide"\n')
insert(output, '! style="background:#eff7ff" |\n')
insert(output, '! colspan="2" style="background:#eff7ff" | Undeclinable\n')
insert(output, '|- class="vsHide"\n')
for _, mood in ipairs(moods) do
if mood == "gerundive_mn" then
insert(output, '! style="background:#eff7ff" |\n')
insert(output, '! colspan="2" style="background:#eff7ff" | Participles\n')
insert(output, '|- class="vsHide"\n')
end
insert(output, '! style="background-color:#eff7ff;" | ' .. names .. "\n")
local tag = mood
local arg_tag = mood
insert(output, make_cell(args, data, tag, arg_tag, sc_cache, 1))
insert(output, '|- class="vsHide"\n')
end
insert(output, format_notes(args, data))
insert(output, "|}")
if not args.nocat and #data.categories > 0 then
insert(output, m_utils.format_categories(data.categories, lang))
end
return output
end
local function make_voice(title_models, args, data, sc_cache, voice)
local moods = tenses.moods
local tag = moods .. "_" .. voice .. "_3_s"
local arg_tag = moods .. "_" .. voice .. "_3_s"
local forms
if args then
forms = split(args, "%s*,%s*")
else
forms = data.forms
end
if #title_models > 0 then
insert(title_models, ", ")
end
for i, title_lem in ipairs(forms or {"-"}) do
title_lem = sc_cache.tr(title_lem)
if i > 1 then
insert(title_models, " or ")
end
title_lem = gsub(title_lem, 'V', 'f')
title_lem = gsub(title_lem, "Z", "x")
title_lem = ugsub(title_lem, "", "")
insert(title_models,
m_links.full_link(
{
alt = sc_cache.reverse_tr(title_lem),
tr = SLP_to_IAST.tr(title_lem),
lang = lang,
sc = sc_cache.sc
}
)
)
end
end
local function make_table_verb(args, data, output, sc_cache)
local moods
if args.tense == "pres" and args.novedic == true then
moods = { "indic", "imper", "optat", "part" }
elseif args.tense == "aor" and args.novedic == true then
moods = { "indic", "inj" }
else
moods = tenses.moods
end
if args.tense == "nonf" then
insert(data.categories, "Sanskrit verbs with nonfinite forms")
return make_nonf_table(args, data, output, sc_cache)
end
local voices = tenses.voices
local numbers = {"s", "d", "p"}
local people = {{"3", "Third"}, {"2", "Second"}, {"1", "First"}}
local title_models = {}
if match(args.n, "a") then
make_voice(title_models, args, data, sc_cache, "av")
end
if match(args.n, "m") then
make_voice(title_models, args, data, sc_cache, "mv")
end
if match(args.n, "p") then
make_voice(title_models, args, data, sc_cache, "pv")
end
insert(output, make_header(args, concat(title_models, "")))
insert(output, '|- class="vsHide"\n')
for _, mood in ipairs(moods) do
insert(output, '! style="background:#eff7ff" colspan="' .. args.colspan .. '" | ' .. names .. "\n")
insert(output, '|- class="vsHide"\n')
if mood == "part" then
insert(output, '| style="background-color:#eff7ff; font-style:italic;" | \n')
for _, voice in ipairs(voices) do
local tag = mood .. "_" .. voice
local arg_tag = mood .. "_" .. voice
insert(output, make_cell(args, data, tag, arg_tag, sc_cache, 3, voice))
end
else
for _, person_pair in ipairs(people) do
local person, person_name = person_pair, person_pair
insert(output, '| style="background-color:#eff7ff; font-style:italic;" | ' .. person_name .. "\n")
for _, voice in ipairs(voices) do
for _, number in ipairs(numbers) do
local tag = mood .. "_" .. voice .. "_" .. person .. "_" .. number
local arg_tag = mood .. "_" .. voice .. "_" .. person .. "_" .. number
insert(output, make_cell(args, data, tag, arg_tag, sc_cache, 1, voice))
end
end
insert(output, '|- class="vsHide"\n')
end
end
end
insert(output, format_notes(args, data))
insert(output, "|}")
if not args.nocat and #data.categories > 0 then
insert(output, m_utils.format_categories(data.categories, lang))
end
return output
end
local function get_sc_details(args)
local sc, scCode
if args.sc then
sc = require("Module:scripts").getByCode(args.sc)
scCode = args.sc
else
sc = lang:findBestScript(args.lemma)
scCode = sc:getCode()
if scCode == "None" then
sc = lang:findBestScript(PAGENAME)
scCode = sc:getCode()
if scCode == "None" then
-- error("Script code was not specified or detected.")
-- Suppress; this fixes issues where docs pages get errors
return get_sc_details({sc = "Deva"})
end
end
end
local tr, reverse_tr = sa_utils_translit.retrieve_tr_modules(scCode)
return {tr = tr, reverse_tr = reverse_tr, sc = sc, scCode = scCode}
end
--[=[Splits a string by commas and displays
]=]
function export.split(frame)
local args = frame.args
args.lemma = args
local sc_cache = get_sc_details(args)
if not sc_cache then
return "Module failed on page "
end
local output = {}
local splitted = split(frame.args, ",")
if args.b then insert(output, "<ul>") end
for i, form in ipairs(splitted) do
if i > 1 and not args.b and not args.csv then insert(output, "<br/>") end
if i > 1 and args.csv then insert(output, ", ") end
if args.b then insert(output, "<li>") end
local slp = sc_cache.tr(form)
local tr
if require("Module:scripts").findBestScriptWithoutLang(form):getCode() == "Latn" then
tr = form
end
insert(
output,
m_links.full_link({term = sc_cache.reverse_tr(slp), tr = tr, lang = lang, sc = sc_cache.sc})
)
if args.b then insert(output, "</li>") end
end
if args.b then insert(output, "</ul>") end
return concat(output)
end
local function term_already_linked(term)
-- This function is copied from Module:columns, and probably needs to be updated whenever that one is
-- FIXME: "<span" is an ugly hack to prevent double-linking of terms already run through {{l|...}}:
-- ]
return term:find("<span", nil, true) and true or false
end
function add_form_to_output(col_args, form, tense, sc_cache)
if term_already_linked(form) then
insert(col_args, form)
return
end
local slp = sc_cache.tr(form)
local tr
if require("Module:scripts").findBestScriptWithoutLang(form):getCode() == "Latn" then
tr = "<tr:" .. form .. ">"
end
local qq
if tense ~= nil then
qq = "<qq:" .. tense .. ">"
end
insert(col_args, ("%s%s%s"):format(sc_cache.reverse_tr(slp), tr or "", qq or ""))
end
function add_root_deriv(col_args, param, tense, sc_cache)
if term_already_linked(param) then
add_form_to_output(col_args, param, tense, sc_cache)
else
for form in gsplit(param, ",") do
add_form_to_output(col_args, form, tense, sc_cache)
end
end
end
function handle_deriv_param(col_args, args, param_name, tense, sc_cache)
if args ~= nil then
local pos = args or tense
add_root_deriv(col_args, args, pos, sc_cache)
local i = 2
while args ~= nil do
pos = args or tense
add_root_deriv(col_args, args, pos, sc_cache)
i = i + 1
end
end
end
function export.rootderiv(frame)
local iargs = frame.args
local args = frame:getParent().args
local output = '\n; Primary Verbal Forms\n'
local sc_cache = get_sc_details(args)
if not sc_cache then
return "Module failed on page "
end
-- if args == nil then return "Module failed on page - no present tense" end
local col_args = {"sa"}
handle_deriv_param(col_args, args, "pres", "Present", sc_cache)
handle_deriv_param(col_args, args, "opt", "Optative Mood", sc_cache)
handle_deriv_param(col_args, args, "imper", "Imperative Mood", sc_cache)
handle_deriv_param(col_args, args, "impf", "Imperfect", sc_cache)
handle_deriv_param(col_args, args, "fut", "Future", sc_cache)
handle_deriv_param(col_args, args, "pfut", "Periphrastic Future", sc_cache)
handle_deriv_param(col_args, args, "cond", "Conditional", sc_cache)
handle_deriv_param(col_args, args, "aor", "Aorist", sc_cache)
handle_deriv_param(col_args, args, "bene", "Benedictive", sc_cache)
handle_deriv_param(col_args, args, "perf", "Perfect", sc_cache)
handle_deriv_param(col_args, args, "pperf", "Periphrastic Perfect", sc_cache)
output = output .. columns.display_from(iargs, col_args)
col_args = {"sa"}
handle_deriv_param(col_args, args, "pass", "Passive", sc_cache)
handle_deriv_param(col_args, args, "pass_aor", "Passive Aorist", sc_cache)
handle_deriv_param(col_args, args, "caus", "Causative", sc_cache)
handle_deriv_param(col_args, args, "caus_aor", "Causative Aorist", sc_cache)
handle_deriv_param(col_args, args, "pass_caus", "Passive of Causative", sc_cache)
handle_deriv_param(col_args, args, "pass_aor_caus", "Passive Aorist of Causative", sc_cache)
handle_deriv_param(col_args, args, "desid", "Desiderative", sc_cache)
handle_deriv_param(col_args, args, "desid_aor", "Desiderative Aorist", sc_cache)
handle_deriv_param(col_args, args, "desid_fut", "Desiderative Future", sc_cache)
handle_deriv_param(col_args, args, "pass_desid", "Passive of Desiderative", sc_cache)
handle_deriv_param(col_args, args, "caus_desid", "Causative of Desiderative", sc_cache)
handle_deriv_param(col_args, args, "desid_caus", "Desiderative of Causative", sc_cache)
handle_deriv_param(col_args, args, "desid_desid", "Desiderative of Desiderative", sc_cache)
handle_deriv_param(col_args, args, "intens", "Intensive", sc_cache)
handle_deriv_param(col_args, args, "int", "Intensive", sc_cache)
handle_deriv_param(col_args, args, "freq", "Intensive", sc_cache)
handle_deriv_param(col_args, args, "int_perf", "Intensive Perfect", sc_cache)
handle_deriv_param(col_args, args, "caus_int", "Causative of Intensive", sc_cache)
handle_deriv_param(col_args, args, "desid_int", "Desiderative of Intensive", sc_cache)
if col_args ~= nil then
output = output .. '\n; Secondary Forms\n'
output = output .. columns.display_from(iargs, col_args)
end
col_args = {"sa"}
handle_deriv_param(col_args, args, "ppp", "Past Participle", sc_cache)
handle_deriv_param(col_args, args, "mpp", "Mediopassive Participle", sc_cache)
handle_deriv_param(col_args, args, "ap", "Active Participle", sc_cache)
handle_deriv_param(col_args, args, "inf", "Infinitive", sc_cache)
handle_deriv_param(col_args, args, "gerund", "Gerund", sc_cache)
handle_deriv_param(col_args, args, "gerundive", "Gerundive", sc_cache)
handle_deriv_param(col_args, args, "caus_ppp", "Causative Past Participle", sc_cache)
handle_deriv_param(col_args, args, "caus_inf", "Causative Infinitive", sc_cache)
handle_deriv_param(col_args, args, "caus_gerund", "Causative Gerund", sc_cache)
handle_deriv_param(col_args, args, "caus_gerundive", "Causative Gerundive", sc_cache)
handle_deriv_param(col_args, args, "desid_part", "Desiderative Participle", sc_cache)
handle_deriv_param(col_args, args, "desid_gerundive", "Desiderative Gerundive", sc_cache)
handle_deriv_param(col_args, args, "desid_caus_part", "Desiderative Participle of Causative", sc_cache)
handle_deriv_param(col_args, args, "desid_part_caus", "Desiderative Participle of Causative", sc_cache)
handle_deriv_param(col_args, args, "int_inf", "Intensive Infinitive", sc_cache)
if col_args ~= nil then
output = output .. '\n; Non-Finite Forms\n'
output = output .. columns.display_from(iargs, col_args)
end
local n_args = {"sa"}
local v_args = {"sa"}
local switched_to_verbs = false
for _, v in ipairs(args) do
v = ugsub(v, "^%s*(.-)%s*$", "%1")
if v == "/" then
switched_to_verbs = true
else
if switched_to_verbs then add_form_to_output(v_args, v, nil, sc_cache)
else add_form_to_output(n_args, v, nil, sc_cache) end
end
end
if n_args ~= nil then
output = output .. '\n; Derived Nominal Forms\n'
output = output .. columns.display_from(iargs, n_args)
end
if v_args ~= nil then
output = output .. '\n; Prefixed Root Forms\n'
output = output .. columns.display_from(iargs, v_args)
end
return output
end
function export.show(frame)
local boolean_default_true = {type = "boolean", default = true}
local boolean_default_false = {type = "boolean", default = false}
local params = {
lemma = {default = PAGENAME},
n = {default = "amp"},
sc = true,
= {required = true},
= {alias_of = "lemma"},
= true,
= true,
auto_sandhi = boolean_default_true,
set = boolean_default_false, -- set vs anit roots
novedic = boolean_default_false, -- disable extra Vedic forms
note = {list = true},
o = boolean_default_false,
mono = boolean_default_false, -- internal sandhi arg
j_to_z = boolean_default_false, -- internal sandhi arg
h_to_g = boolean_default_false, -- internal sandhi arg
ambig_final = true, -- internal sandhi arg (in practice only when final '-ś' becomes 'k' as in 'ádrāk')
diaspirate = boolean_default_false, -- internal sandhi arg
no_syncope = boolean_default_false, -- internal sandhi arg
accent_override = boolean_default_false, -- internal sandhi arg
no_retroflex_root_s = boolean_default_true, -- internal sandhi arg; default = true only for verbs
aor = true, -- aorist class (if not automatically detected)
class = true, -- present class (if not automatically detected)
extra_1p_stem = true, -- stem for 1p if different from 3p and (e.g.) 2p
inj_strong_stem = true, -- injunctive strong stem in case of root starting with vowel, or prefixed verbs
inj_weak_stem = true, -- injunctive weak stem in case of root starting with vowel, or prefixed verbs
}
for tense, tense_l in pairs(tenses) do
if tense == "nonf" then
for _, mood in pairs(tense_l) do
params = true
end
else
for _, mood in pairs(tense_l) do
for _, voice in pairs(tense_l) do
if mood == "part" then
params = true
else
for _, number in pairs(numbers) do
params = true
end
end
end
end
end
end
local args = m_params.process(frame:getParent().args, params)
local data = {
forms = {},
categories = {},
form_notes = {},
form_notes_out = {},
general_notes = {}
}
local sc_cache = get_sc_details(args)
if not sc_cache then
return "Module failed on page "
end
args.lemma = sc_cache.tr(args.lemma)
args.has_accent = umatch(args.lemma, sa_utils.accent)
if args ~= nil then args = sc_cache.tr(args) end
if args ~= nil then args = sc_cache.tr(args) end
local output = {}
args.tense = args
-- conjugate(args, data)
args.colspan = 7
args.n = gsub(args.n, "p", "")
args.strong_lemma = args.lemma -- split(args.lemma, ",")
args.weak_lemma = args -- and split(args, ",")
args.passive_lemma = args -- and split(args, ",")
if not args.o then
sa_verb_data(args, data)
end
if args.tense == "pfut" then
if args.n ~= "a" then
data.general_notes = {"The middle forms of the periphrastic future rarely occur."}
end
elseif args.tense == "aor" and args.weak_lemma and match(args.strong_lemma, "At$") and match(args.weak_lemma, "ta") then
data.general_notes = {"The mediopassive root-aorist and the subjunctive are only used in Vedic Sanskrit."}
elseif (args.tense == "pres" or args.tense == "aor") and args.novedic == false then
data.general_notes = {"The subjunctive is only used in Vedic Sanskrit."}
end
make_table_verb(args, data, output, sc_cache)
return concat(output)
end
return export