Module:sa-verb

From Wiktionary, the free dictionary
Jump to navigation Jump to search

See Template:sa-conj


local export = {}

local m_para = 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 sa_verb_data = require("Module:sa-verb/data")
local SLP_to_IAST = require("Module:sa-utilities/translit/SLP1-to-IAST")
local IAST_to_SLP = require("Module:sa-utilities/translit/IAST-to-SLP1")
local sa_utils = require("Module:sa-utilities")
local sa_utils_translit = require("Module:sa-utilities/translit")
local columns = require("Module:columns")
local PAGENAME = mw.title.getCurrentTitle().text

local gsub = mw.ustring.gsub
local match = mw.ustring.match
local split = mw.text.split

local names = {
	["pres"] = "Present",
	["impf"] = "Imperfect",
	["fut"] = "Future",
	["pfut"] = "Periphrastic Future",
	["cond"] = "Conditional",
	["aor"] = "Aorist",
	["bene"] = "Benedictive/Precative",
	["perf"] = "Perfect",
	["pperf"] = "Periphrastic Perfect",
	["indic"] = "Indicative",
	["imper"] = "Imperative",
	["optat"] = "Optative/Potential",
	["subj"] = "Subjunctive",
	["inj"] = "Injunctive",
	["part"] = "Participles",
	["inf"] = "Infinitive",
	["gerund"] = "Gerund",
	["gerundive_mn"] = "Masculine/Neuter Gerundive",
	["gerundive_f"] = "Feminine Gerundive",
	["part_mn"] = "Masculine/Neuter Past Passive Participle",
	["part_f"] = "Feminine Past Passive Participle",
	["part_av_mn"] = "Masculine/Neuter Past Active Participle",
	["part_av_f"] = "Feminine Past Active Participle",
	["nonf"] = "Nonfinite Forms"
}

local tenses = {
	["pres"] = {
		["moods"] = { "indic", "imper", "optat", "subj", "part" },
		["voices"] = { "av", "mv" }
	},
	["impf"] = {
		["moods"] = { "indic" },
		["voices"] = { "av", "mv" }
	},
	["fut"] = {
		["moods"] = { "indic", "part" },
		["voices"] = { "av", "mv" }
	},
	["pfut"] = {
		["moods"] = { "indic" },
		["voices"] = { "av", "mv" }
	},
	["cond"] = {
		["moods"] = { "indic" },
		["voices"] = { "av", "mv" }
	},
	["aor"] = {
		["moods"] = { "indic", "inj", "subj" },
		["voices"] = { "av", "mv" }
	},
	["bene"] = {
		["moods"] = { "optat" },
		["voices"] = { "av", "mv" }
	},
	["perf"] = {
		["moods"] = { "indic", "part" },
		["voices"] = { "av", "mv" }
	},
	["nonf"] = {
		["moods"] = { "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 = {
    [1] = "¹",
    [2] = "²",
    [3] = "³",
    [4] = "⁴",
    [5] = "⁵",
    [6] = "⁶",
    [7] = "⁷",
    [8] = "⁸",
    [9] = "⁹",
    [0] = "⁰"
}

local function to_super(num)
    local annotation = gsub(num, ".", super_nums)
    return annotation
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[form_note]) ~= "number" then
            table.insert(data.form_notes_out, form_note)
            data.form_notes[form_note] = #data.form_notes_out
        end
        table.insert(output, to_super(data.form_notes[form_note]))
    end
    return table.concat(output)
end

local function make_header(args, data, title_models, sc_cache)
    local width = 70
    local title = names[args.tense] .. ": " .. title_models

    local header = {
        '{| class="inflection-table vsSwitcher" data-toggle-category="inflection" style="background:#F9F9F9; text-align:center; border: 1px solid #CCC; width: ' ..
            width .. 'em"\n'
    }
    table.insert(header, '|- style="background: #d9ebff;"\n')
    table.insert(
        header,
        '! class="vsToggleElement" style="text-align: left;" colspan="' .. args.colspan .. '" | ' .. title .. "\n"
    )
    table.insert(header, '|- class="vsHide"\n')
    table.insert(header, '! style="background:#eff7ff" rowspan="2" |\n')

    table.insert(header, '! colspan="3" style="background:#eff7ff" | Active\n')
    
    if args.tense == "pfut" then
    	table.insert(header, '! colspan="3" style="background:#eff7ff" | Middle\n')
    else
    	table.insert(header, '! colspan="3" style="background:#eff7ff" | Mediopassive\n')
	end

    table.insert(header, '|- class="vsHide"\n')
    local size = 2
    for i = 1, size, 1 do
        table.insert(header, '! style="background:#eff7ff" | Singular\n')
        table.insert(header, '! style="background:#eff7ff" | Dual\n')
        table.insert(header, '! style="background:#eff7ff" | Plural\n')
    end

    return table.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[arg_tag] then
        forms = mw.text.split(args[arg_tag], "%s*[,]%s*")
    else
        forms = data.forms[tag]
    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
		if match(form, "[¹²³⁴⁵⁶⁷⁸⁹]$") then
			extra_note_tag = gsub(form, "^.+(.)$", "%1")
			form = gsub(form, ".$", "")
		else
			extra_note_tag = ""
		end
		
		local form_note_tag = get_form_note_tags(forms["note" .. i] or {}, data)
		if form == "" then -- in case of form reduced to zero by 'novedic' parameter
			-- do nothing
		elseif form == "-" then
			table.insert(links, form)
			table.insert(trs, form)
		else
        	table.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
    		)
        	table.insert(trs, SLP_to_IAST.tr(form) .. form_note_tag .. extra_note_tag)
        end
    end

    return table.concat {
        "| ",
        "colspan = ",
        col_span,
        " | ",
        table.concat(links, " / "),
        "<br/>",
        m_script_utils.tag_translit(table.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
            table.insert(output, "* " .. general_note)
        end
        for i, form_note in ipairs(data.form_notes_out) do
            table.insert(output, "* " .. to_super(i) .. form_note)
        end
        for _, note in ipairs(args.note) do
            table.insert(output, "* " .. note)
        end
        return table.concat(output, "\n") .. "\n"
    else
        return ""
    end
end

local function make_nonf_table(args, data, output, sc_cache)
    local moods = tenses[args.tense].moods
    if data.forms["part_mn"] ~= "-" and data.forms["part_mn"] ~= nil then
	    data.forms["part_av_mn"] = { data.forms["part_mn"][1] .. "vat" } -- these two formed directly from the given forms always
	    data.forms["part_av_f"] = { data.forms["part_mn"][1] .. "vatī" }
	else
		data.forms["part_av_mn"] = { "-" }
		data.forms["part_av_f"] = { "-" }
	end
    local title_models = ""
        local arg_before = false
        local tag = moods[1]
        local arg_tag = moods[1]
        local forms
        if args[arg_tag] then
            forms = mw.text.split(args[arg_tag], "%s*[,]%s*")
        else
            forms = data.forms[tag]
        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(
                    {
                        term = nil,
                        alt = sc_cache.reverse_tr(title_lem),
                        tr = SLP_to_IAST.tr(title_lem),
                        lang = lang,
                        sc = sc_cache.sc
                    }
                )
        end
        local title = names[args.tense] .. ": " .. title_models
        table.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')
        table.insert(
            output,
            '{| class="inflection-table vsSwitcher" data-toggle-category="inflection" style="background:#F9F9F9; text-align:center; border: 1px solid #CCC; width: 40em"\n'
        )
        table.insert(output, '|- style="background: #d9ebff;"\n')
        table.insert(output, '! class="vsToggleElement" style="text-align: left;" colspan="4" | ' .. title .. "\n")
        table.insert(output, '|- class="vsHide"\n')
        table.insert(output, '! style="background:#eff7ff" |\n')

        table.insert(output, '! colspan="2" style="background:#eff7ff" | Undeclinable\n')
        table.insert(output, '|- class="vsHide"\n')
        for _, mood in ipairs(moods) do
            if mood == "gerundive_mn" then
                table.insert(output, '! style="background:#eff7ff" |\n')
                table.insert(output, '! colspan="2" style="background:#eff7ff" | Participles\n')
                table.insert(output, '|- class="vsHide"\n')
            end
            table.insert(output, '! style="background-color:#eff7ff;" | ' .. names[mood] .. "\n")
            local tag = mood
            local arg_tag = mood
            table.insert(output, make_cell(args, data, tag, arg_tag, sc_cache, 1))
            table.insert(output, '|- class="vsHide"\n')
        end
        table.insert(output, format_notes(args, data))
        table.insert(output, "|}")
        if not args.nocat and #data.categories > 0 then
            table.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[args.tense].moods
    local tag = moods[1] .. "_" .. voice .. "_3_s"
    local arg_tag = moods[1] .. "_" .. voice .. "_3_s"
    local forms
    if args[arg_tag] then
        forms = mw.text.split(args[arg_tag], "%s*[,]%s*")
    else
        forms = data.forms[tag]
    end
    if #title_models > 0 then
        table.insert(title_models, ", ")
    end
    for i, title_lem in ipairs(forms or {"-"}) do
    	title_lem = sc_cache.tr(title_lem)
        if i > 1 then
            table.insert(title_models, " or ")
        end
        title_lem = gsub(title_lem, 'V', 'f')
		title_lem = gsub(title_lem, "Z", "x")
		title_lem = gsub(title_lem, "[¹²³⁴⁵⁶⁷⁸⁹]", "")
        table.insert(title_models, 
            m_links.full_link(
                {
                    term = nil,
                    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)
	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[args.tense].moods
    end

    if args.tense == "nonf" then
    	table.insert(data.categories, "Sanskrit verbs with nonfinite forms")
        return make_nonf_table(args, data, output, sc_cache)
    end
	
    local voices = tenses[args.tense].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

    table.insert(output, make_header(args, data, table.concat(title_models, ""), sc_cache))
    table.insert(output, '|- class="vsHide"\n')

    for _, mood in ipairs(moods) do
        table.insert(output, '! style="background:#eff7ff" colspan="' .. args.colspan .. '" | ' .. names[mood] .. "\n")
        table.insert(output, '|- class="vsHide"\n')
        if mood == "part" then
            table.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
                table.insert(output, make_cell(args, data, tag, arg_tag, sc_cache, 3, voice))
            end
        else
            for i, person_pair in ipairs(people) do
                local person, person_name = person_pair[1], person_pair[2]
                table.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
                        table.insert(output, make_cell(args, data, tag, arg_tag, sc_cache, 1, voice))
                    end
                end
                table.insert(output, '|- class="vsHide"\n')
            end
        end
    end

    table.insert(output, format_notes(args, data))
    table.insert(output, "|}")
    if not args.nocat and #data.categories > 0 then
        table.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[1]
	local sc_cache = get_sc_details(args)
    if not sc_cache then
    	return "Module failed on page "
    end
    
	local output = {}
	local splitted = mw.text.split(frame.args[1], ",")
	if args.b then table.insert(output, "<ul>") end
	for i, form in ipairs(splitted) do
		if i > 1 and not args.b and not args.csv then table.insert(output, "<br/>") end
		if i > 1 and args.csv then table.insert(output, ", ") end
		if args.b then table.insert(output, "<li>") end
		slp = sc_cache.tr(form)
		if require("Module:scripts").findBestScriptWithoutLang(form):getCode() == "Latn" then
			tr = form
		else
			tr = nil
		end
		table.insert(
            output,
            m_links.full_link({term = sc_cache.reverse_tr(slp), tr = tr, lang = lang, sc = sc_cache.sc})
        )
        if args.b then table.insert(output, "</li>") end
	end
	if args.b then table.insert(output, "</ul>") end
	return table.concat(output)
end

function add_form_to_output(output, form, tense, sc_cache)
	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|...}}:
		-- [[Thread:User talk:CodeCat/MewBot adding lang to column templates]]
		return term:find("<span")
	end
	
	if term_already_linked(form) then
		table.insert(output, form)
	else
		slp = sc_cache.tr(form)
		local tr = nil
		if require("Module:scripts").findBestScriptWithoutLang(form):getCode() == "Latn" then
			tr = form
		end
		local pos = nil
		if tense ~= nil then
			pos = '<span class="ib-content qualifier-content">' .. tense .. '</span>'
		end
		table.insert(
            output,
            m_links.full_link({term = sc_cache.reverse_tr(slp), tr = tr, pos = pos, lang = lang, sc = sc_cache.sc})
        )
    end
end

function add_root_deriv(output, param, tense, sc_cache)
	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|...}}:
		-- [[Thread:User talk:CodeCat/MewBot adding lang to column templates]]
		return term:find("<span")
	end
	
	if term_already_linked(param) then
		add_form_to_output(output, param, tense, sc_cache)
	else
		local splitted = mw.text.split(param, ",")
		for i, form in ipairs(splitted) do
			add_form_to_output(output, form, tense, sc_cache)
		end
	end
end

function handle_deriv_param(output, frame, param_name, tense, sc_cache)
	if frame.args[param_name] ~= nil then
		local pos = frame.args[param_name .. "_pos"] or tense
		add_root_deriv(output, frame.args[param_name], pos, sc_cache)
		local i = 2
		while frame.args[param_name .. i] ~= nil do
			pos = frame.args[param_name .. i .. "_pos"] or tense
			add_root_deriv(output, frame.args[param_name .. i], pos, sc_cache)
			i = i + 1
		end
	end
end

function export.rootderiv(frame)
	frame.args = frame:getParent().args
	local output = '\n; Primary Verbal Forms\n'
	local sc_cache = get_sc_details(frame.args)
    if not sc_cache then
    	return "Module failed on page "
    end
	-- if frame.args["pres"] == nil then return "Module failed on page - no present tense" end
	
	local args = { [1] = "sa" }
	handle_deriv_param(args, frame, "pres", "Present", sc_cache)
	handle_deriv_param(args, frame, "opt", "Optative Mood", sc_cache)
	handle_deriv_param(args, frame, "imper", "Imperative Mood", sc_cache)
	handle_deriv_param(args, frame, "impf", "Imperfect", sc_cache)
	handle_deriv_param(args, frame, "fut", "Future", sc_cache)
	handle_deriv_param(args, frame, "pfut", "Periphrastic Future", sc_cache)
	handle_deriv_param(args, frame, "cond", "Conditional", sc_cache)
	handle_deriv_param(args, frame, "aor", "Aorist", sc_cache)
	handle_deriv_param(args, frame, "bene", "Benedictive", sc_cache)
	handle_deriv_param(args, frame, "perf", "Perfect", sc_cache)
	handle_deriv_param(args, frame, "pperf", "Periphrastic Perfect", sc_cache)
	output = output .. columns.display_from({ ["columns"] = 4 }, args, nil)
	
	args = { [1] = "sa" }
	handle_deriv_param(args, frame, "pass", "Passive", sc_cache)
	handle_deriv_param(args, frame, "pass_aor", "Passive Aorist", sc_cache)
	handle_deriv_param(args, frame, "caus", "Causative", sc_cache)
	handle_deriv_param(args, frame, "caus_aor", "Causative Aorist", sc_cache)
	handle_deriv_param(args, frame, "pass_caus", "Passive of Causative", sc_cache)
	handle_deriv_param(args, frame, "pass_aor_caus", "Passive Aorist of Causative", sc_cache)
	handle_deriv_param(args, frame, "desid", "Desiderative", sc_cache)
	handle_deriv_param(args, frame, "desid_aor", "Desiderative Aorist", sc_cache)
	handle_deriv_param(args, frame, "desid_fut", "Desiderative Future", sc_cache)
	handle_deriv_param(args, frame, "pass_desid", "Passive of Desiderative", sc_cache)
	handle_deriv_param(args, frame, "caus_desid", "Causative of Desiderative", sc_cache)
	handle_deriv_param(args, frame, "desid_caus", "Desiderative of Causative", sc_cache)
	handle_deriv_param(args, frame, "desid_desid", "Desiderative of Desiderative", sc_cache)
	handle_deriv_param(args, frame, "intens", "Intensive", sc_cache)
	handle_deriv_param(args, frame, "int", "Intensive", sc_cache)
	handle_deriv_param(args, frame, "freq", "Intensive", sc_cache)
	handle_deriv_param(args, frame, "int_perf", "Intensive Perfect", sc_cache)
	handle_deriv_param(args, frame, "caus_int", "Causative of Intensive", sc_cache)
	handle_deriv_param(args, frame, "desid_int", "Desiderative of Intensive", sc_cache)
	if args[2] ~= nil then 
		output = output .. '\n; Secondary Forms\n' 
		output = output .. columns.display_from({ ["columns"] = 4 }, args, nil)
	end
	
	args = { [1] = "sa" }
	handle_deriv_param(args, frame, "ppp", "Past Participle", sc_cache)
	handle_deriv_param(args, frame, "mpp", "Mediopassive Participle", sc_cache)
	handle_deriv_param(args, frame, "ap", "Active Participle", sc_cache)
	handle_deriv_param(args, frame, "inf", "Infinitive", sc_cache)
	handle_deriv_param(args, frame, "gerund", "Gerund", sc_cache)
	handle_deriv_param(args, frame, "gerundive", "Gerundive", sc_cache)
	handle_deriv_param(args, frame, "caus_ppp", "Causative Past Participle", sc_cache)
	handle_deriv_param(args, frame, "caus_inf", "Causative Infinitive", sc_cache)
	handle_deriv_param(args, frame, "caus_gerund", "Causative Gerund", sc_cache)
	handle_deriv_param(args, frame, "caus_gerundive", "Causative Gerundive", sc_cache)
	handle_deriv_param(args, frame, "desid_part", "Desiderative Participle", sc_cache)
	handle_deriv_param(args, frame, "desid_gerundive", "Desiderative Gerundive", sc_cache)
	handle_deriv_param(args, frame, "desid_caus_part", "Desiderative Participle of Causative", sc_cache)
	handle_deriv_param(args, frame, "desid_part_caus", "Desiderative Participle of Causative", sc_cache)
	handle_deriv_param(args, frame, "int_inf", "Intensive Infinitive", sc_cache)
	if args[2] ~= nil then 
		output = output .. '\n; Non-Finite Forms\n' 
		output = output .. columns.display_from({ ["columns"] = 4 }, args, nil)
	end
	
	local n_args = { [1] = "sa" }
	local v_args = { [1] = "sa" }
	local switched_to_verbs = false
	
	for k, v in ipairs(frame.args) do
		v = gsub(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[2] ~= nil then 
		output = output .. '\n; Derived Nominal Forms\n'
		output = output .. columns.display_from({ ["columns"] = 4 }, n_args, nil)
	end
	if v_args[2] ~= nil then 
		output = output .. '\n; Prefixed Root Forms\n'
		output = output .. columns.display_from({ ["columns"] = 4 }, v_args, nil)
	end
	return output
end

function export.show(frame)
    local params = {
        lemma = {default = PAGENAME},
        n = {default = "amp"},
        sc = {},
        [1] = {required = true},
        [2] = {alias_of = "lemma"},
        [3] = {},
        [4] = {},
        auto_sandhi = {default = true, type = "boolean"},
        set = {default = false, type = "boolean" }, -- set vs anit roots
        novedic = {default = false, type = "boolean" }, -- disable extra Vedic forms
        note = {list = true},
        o = {default = false, type = "boolean"},
        mono = {default = false, type = "boolean"}, -- internal sandhi arg
        j_to_z = {default = false, type = "boolean"}, -- internal sandhi arg
        h_to_g = {default = false, type = "boolean"}, -- internal sandhi arg
        ambig_final = {}, -- internal sandhi arg (in practice only when final '-ś' becomes 'k' as in 'ádrāk')
        diaspirate = {default = false, type = "boolean"}, -- internal sandhi arg
        no_syncope = {default = false, type = "boolean"}, -- internal sandhi arg
        accent_override = {default = false, type = "boolean"}, -- internal sandhi arg
        no_retroflex_root_s = {default = true, type = "boolean"}, -- internal sandhi arg; default = true only for verbs
        aor = {default = nil}, -- aorist class (if not automatically detected)
        class = {default = nil}, -- present class (if not automatically detected)
        extra_1p_stem = {default = nil}, -- stem for 1p if different from 3p and (e.g.) 2p
        inj_strong_stem = {default = nil}, -- injunctive strong stem in case of root starting with vowel, or prefixed verbs
        inj_weak_stem = {default = nil}, -- 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["moods"]) do
    			params[mood] = {}
    		end
    	else
    		for _, mood in pairs(tense_l["moods"]) do
    			for _, voice in pairs(tense_l["voices"]) do
    				if mood == "part" then
    					params[mood .. "_" .. voice] = {}
    				else
    					for _, number in pairs(numbers) do
    						params[mood .. "_" .. voice .. "_" .. number] = {}
    					end
    				end
    			end
    		end
    	end
    end
    
	local data = {
        forms = {},
        categories = {},
        decl_type = nil,
        form_notes = {},
        form_notes_out = {},
        general_notes = {}
    }
    local args = m_para.process(frame:getParent().args, params)
    
    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 = match(args.lemma, sa_utils.accent)
    
    if args[3] ~= nil then args[3] = sc_cache.tr(args[3]) end
    if args[4] ~= nil then args[4] = sc_cache.tr(args[4]) end

    local output = {}
    args.tense = args[1]
    -- conjugate(args, data)
    args.colspan = 7
    args.n = gsub(args.n, "p", "")
    
    args.strong_lemma = args.lemma -- split(args.lemma, ",")
    args.weak_lemma = args[3] -- and split(args[3], ",")
    args.passive_lemma = args[4] -- and split(args[4], ",")
    if not args.o then
    	sa_verb_data[args.tense](args, data)
    end
    
    if args.tense == "pfut" then
    	if args.n and args.n == "a" then
    	-- do nothing
    	else
			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, "[iI]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 table.concat(output)
end

return export