Module:User:Benwing2/sa-decl


This is a private module sandbox of Benwing2, for their own experimentation. Items in this module may be added and removed at Benwing2's discretion; do not rely on this module's stability.


local export = {}

local m_para = require("Module:parameters")
local m_links = require("Module:links")
local m_scripts = require("Module:scripts")
local m_utils = require("Module:utilities")
local lang = require("Module:languages").getByCode("sa")
local m_script_utils = require("Module:script utilities")
local sa_decl_data = require("Module:User:Benwing2/sa-decl/data")
local SLP_to_IAST = require("Module:sa-utilities/translit/SLP1-to-IAST")
local sa_utils_translit = require("Module:sa-utilities/translit")
local PAGENAME = mw.title.getCurrentTitle().text

local sub = mw.ustring.sub
local gsub = mw.ustring.gsub
local match = mw.ustring.match
local len = mw.ustring.len

local accent = '[/\\]'

local genders = {
	m = 'Masculine', f = 'Feminine', n = 'Neuter',
}
local cases = {
	{'nom', 'Nominative'}, {'voc', 'Vocative'}, {'acc', 'Accusative'}, {'ins', 'Instrumental'},
	{'dat', 'Dative'}, {'abl', 'Ablative'}, {'gen', 'Genitive'}, {'loc', 'Locative'},
}

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, sc_cache)
	local width = '40'
	local title = genders[args.g] .. ' ' .. ' ' .. data.decl_type .. ' declension of ' ..
			m_links.full_link({term = nil, alt = sc_cache.reverse_tr(args.lemma), tr = SLP_to_IAST.tr(args.lemma), lang = lang, sc = sc_cache.sc})
	
	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="4" | ' .. title .. '\n')
	table.insert(header, '|- class="vsHide"\n')
	table.insert(header, '! style="background:#eff7ff" |\n')
	
	if args.n == 'sdp' then
		table.insert(header, '! style="background:#eff7ff" | Singular\n')
		table.insert(header, '! style="background:#eff7ff" | Dual\n')
		table.insert(header, '! style="background:#eff7ff" | Plural\n')
	elseif args.n == 's' then
		table.insert(header, '! style="background:#eff7ff" | Singular\n')
	elseif args.n == 'd' then
		table.insert(header, '! style="background:#eff7ff" | Dual\n')
	elseif args.n == 'p' then
		table.insert(header, '! style="background:#eff7ff" | Plural\n')
	end
	return table.concat(header)
end

local function make_cell(args, data, code, num, sc_cache)
	local tag = code .. '_' .. num
	local forms, links, trs = {}, {}, {}
	if args[tag] then
		forms = mw.text.split(sc_cache.tr(args[tag]), '%s*[,]%s*')
	else
		forms = data.forms[tag]
	end

	if not forms then
		error("Internal error: No forms for slot '" .. tag .. "'")
	end
	for i, form in ipairs(forms) do
		local form_note_tag = get_form_note_tags(forms['note' .. i] or {}, data)
		table.insert(links, m_links.full_link({ term = sc_cache.reverse_tr(form), tr = '-', lang = lang, sc = sc_cache.sc }) .. form_note_tag)
		table.insert(trs, SLP_to_IAST.tr(form) .. form_note_tag)
	end
	
	return table.concat {
		'| ',
		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=' .. len(args.n) .. ' |'
	}
	if #data.form_notes_out > 0 or #data.general_notes > 0 or #args.note > 0 then
		for i, form_note in ipairs(data.form_notes_out) do
			table.insert(output, '* ' .. to_super(i) .. form_note)
		end
		for _, general_note in ipairs(data.general_notes) do
			table.insert(output, '* ' .. general_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_table_noun(args, data, sc_cache)
	local output = {make_header(args, data, sc_cache)}
	for _, case in ipairs(cases) do
		local code, name = case[1], case[2]
		table.insert(output, '|- class="vsHide"\n')
		table.insert(output, '| style="background-color:#eff7ff; font-style:italic;" | ' .. name ..'\n')
		if args.n == 'sdp' then
			table.insert(output, make_cell(args, data, code, 's', sc_cache))
			table.insert(output, make_cell(args, data, code, 'd', sc_cache))
			table.insert(output, make_cell(args, data, code, 'p', sc_cache))
		elseif args.n == 's' then
			table.insert(output, make_cell(args, data, code, 's', sc_cache))
		elseif args.n == 'd' then
			table.insert(output, make_cell(args, data, code, 'd', sc_cache))
		elseif args.n == 'p' then
			table.insert(output, make_cell(args, data, code, 'p', sc_cache))
		end
	end
	table.insert(output, format_notes(args, data))
	table.insert(output, '|}')
	if #data.categories > 0 then
		table.insert(output, m_utils.format_categories(data.categories, lang))
	end
	return table.concat(output)
end

local function get_sc_details(args)
	local sc, scCode
	if args.sc then
		sc = m_scripts.getByCode(args.sc)
		scCode = args.sc
	else
		sc = m_scripts.findBestScript(args.lemma, lang)
		scCode = sc:getCode()
		if scCode == 'None' then
			sc = m_scripts.findBestScript(PAGENAME, lang)
			scCode = sc:getCode()
			if scCode == 'None' then
				error('Script code was not specified or detected.')
			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

function export.show(frame)
	local params = {
		lemma = {default = PAGENAME},
		decl = {default = nil},
		n = {default = 'sdp'},
		sc = {},
		[1] = {alias_of = 'lemma'},
		nom_s = {}, nom_d = {}, nom_p = {},
		acc_s = {}, acc_d = {}, acc_p = {},
		ins_s = {}, ins_d = {}, ins_p = {},
		dat_s = {}, dat_d = {}, dat_p = {},
		abl_s = {}, abl_d = {}, abl_p = {},
		gen_s = {}, gen_d = {}, gen_p = {},
		loc_s = {}, loc_d = {}, loc_p = {},
		voc_s = {}, voc_d = {}, voc_p = {},
		note = { list = true },
		root = { type = 'boolean' }, compound = { type = 'boolean' },
		r_stem_a = {},
		contract = { type = 'boolean' },
	}
	local data = {
		forms = {},
		categories = {},
		decl_type = nil,
		form_notes = {},
		form_notes_out = {},
		general_notes = {},
	}
	local args = m_para.process(frame:getParent().args, params)
	args.g = frame.args[1]
	
	local sc_cache = get_sc_details(args)
	
	args.lemma = sc_cache.tr(args.lemma)
	args.has_accent = match(args.lemma, accent)

	if args.decl == nil then
		for decl, decl_data in pairs(sa_decl_data) do
			if decl_data.detect(args) then
				sa_decl_data[decl](args, data)
				break
			end
		end
	end
	if data.decl_type == nil then
		error("No declension class could be detected. Please check the lemma form or specify the declension.")
	end

	return make_table_noun(args, data, sc_cache)
end

return export