Pergi ke kandungan

Modul:eu-noun

Daripada Wikikamus

local export = {}

local m_str_utils = require("Module:string utilities")
local m_table = require("Module:table")
local m_com = require("Module:eu-common")

local lang = require("Module:languages").getByCode("eu")
local rfind = m_str_utils.find
local rsub = m_str_utils.gsub
local rsplit = m_str_utils.split

-- Table-generating functions
-- st: default table (indefinite, singular, plural and proximal plural columns; single animacy)
-- st-sg: two columns (indefinite and singular) and a single animacy. The instrumental indefinite is shown.
-- st-pl: three columns (indefinite, plural and proximal plural) and a single animacy. All indefinite forms are shown.
-- st-both: four columns (indefinite, singular, plural and proximal plural), two animacies
-- st-both-pl: three columns (indefinite, plural and proximal plural), two animacies

-- Tables for proper nouns:
-- ind: one column (indefinite) and a single animacy
-- ind-both: one column (indefinite) and rows for two animacies
-- ind-sg: two columns (indefinite and singular) and a single animacy. The indefinite column shows the absolutive, partitive and prolative only.
-- ind-pl: two columns (indefinite and singular) and a single animacy. The indefinite column shows the absolutive, partitive and prolative only.

local function generate_from_basic_table(basic_code, nums_remove, cleanup_indef, headers)
	--Generate a table by modifying the basic tables
	--we remove:
	--	slots with data-accel-col="[nums_remove]"
	--	headers present in the variable <headers>
	--if cleanup_indef is not nil, we show a nil value in the specified rows of the indefinite column
	
	local clean_lines = {}
	local search_headers = m_table.listToSet(headers)
	for line in basic_code:gmatch("[^\r\n]+") do
	    if not rfind(line, 'data%-accel%-col="[' .. nums_remove .. ']"') and not search_headers[line] then
	    	if cleanup_indef then
		    	if rfind(line, 'data%-accel%-col="1"') and not m_com.rfind_multiple(line, cleanup_indef) then
		    		table.insert(clean_lines, "| —")
		    	else
		    		table.insert(clean_lines, line)
		    	end
		    else
		    	table.insert(clean_lines, line)
		    end
	    end
	end
	return table.concat(clean_lines, "\n") .. "\n"
end

local function make_table(data, tbl_type)
	local function repl(param)
		local accel = true
		local no_store = false
		
		if param == "info" then
			return mw.getContentLanguage():ucfirst(data.info or "")
		elseif string.sub(param, 1, 1) == "!" then
			no_store = true
			param = string.sub(param, 2)
		elseif string.sub(param, 1, 1) == "#" then
			accel = false
			param = string.sub(param, 2)
		end
		
		local forms = data.forms[param]
		
		if not forms then
			return "&mdash;"
		end
		
		local ret = {}
		
		for key, subform in ipairs(forms) do
			table.insert(ret, require("Module:links").full_link({lang = lang, term = subform, accel = accel and {form = param, lemma = data.lemma, no_store = no_store} or nil}))
		end
		
		return table.concat(ret, ", ")
	end
	
	local wikicode = mw.getCurrentFrame():expandTemplate{ 
		title = 'inflection-table-top', 
		args = {
			title = '{{{info}}}',
			tall = 'yes',
			palette = 'blue'
		}
	}
	
	-- Basic elements for constructing the tables
	local basic_table = [=[
! 
! indefinite
! singular
! plural
! proximal plural
|-
]=]

	local basic_table_both_anims = [=[
! colspan="2"|
! indefinite
! singular
! plural
! proximal plural
]=]

	local row = [=[
|-
! TENSENAME
| data-accel-col="1" | {{{TENSEABBR|indef}}}
| data-accel-col="2" | {{{TENSEABBR|s}}}
| data-accel-col="3" | {{{TENSEABBR|p}}}	
| data-accel-col="4" | {{{TENSEABBR|prox|p}}}	
]=]

	local row_colspan = [=[
|-
! colspan="2"| TENSENAME
| data-accel-col="1" | {{{TENSEABBR|indef}}}
| data-accel-col="2" | {{{TENSEABBR|s}}}
| data-accel-col="3" | {{{TENSEABBR|p}}}
| data-accel-col="4" | {{{TENSEABBR|prox|p}}}
]=]
	
	local row_rowspan = [=[
|-
! rowspan="2"| TENSENAME
! class="secondary" | <abbr title="animate">anim.</abbr>
| data-accel-col="1" | {{{TENSEABBR|animate|indef}}}
| data-accel-col="2" | {{{TENSEABBR|animate|s}}}
| data-accel-col="3" | {{{TENSEABBR|animate|p}}}
| data-accel-col="4" | {{{TENSEABBR|animate|prox|p}}}
|-
! class="secondary" | <abbr title="inanimate">inan.</abbr>
| data-accel-col="1" | {{{TENSEABBR|inanimate|indef}}}
| data-accel-col="2" | {{{TENSEABBR|inanimate|s}}}
| data-accel-col="3" | {{{TENSEABBR|inanimate|p}}}	
| data-accel-col="4" | {{{TENSEABBR|inanimate|prox|p}}}	
]=]

	--Here we generate the two most basic tables (three columns, all tenses). We will generate other tables from them.
	tense_abbrs = {
    	{"absv", "absolutive"}, {"erg", "ergative"}, {"dat", "dative"}, {"gen", "genitive"}, {"com", "comitative"}, {"caus", "causative"}, {"ben", "benefactive"}, {"ins", "instrumental"}, 
    	{"ine", "innesive"},{"loc", "locative"}, {"all", "allative"}, {"ter", "terminative"}, {"directive", "directive"}, {"destinative", "destinative"}, {"abl", "ablative"}, 
    	{"par", "partitive"}, {"pro", "prolative"}
	}
	dual_tenses = m_table.listToSet({"ine", "loc", "all", "ter", "directive", "destinative", "abl"})

	for _, pair in ipairs(tense_abbrs) do
		basic_table = basic_table .. m_com.rsub_multiple(row, {"TENSENAME", "TENSEABBR"}, {pair[2], pair[1]})
		if dual_tenses[pair[1]] then
			basic_table_both_anims = basic_table_both_anims .. m_com.rsub_multiple(row_rowspan, {"TENSENAME", "TENSEABBR"}, {pair[2], pair[1]})
		else
			basic_table_both_anims = basic_table_both_anims .. m_com.rsub_multiple(row_colspan, {"TENSENAME", "TENSEABBR"}, {pair[2], pair[1]})
		end
	end
	
	--generate the table code
	local tbl_refs = {
		st             = basic_table,
		["st-both"]    = basic_table_both_anims,
		["st-both-pl"] = {basic_table_both_anims, "2", nil, {"! singular"}},
		["st-sg"]      = {basic_table, "34", {"absv", "ins", "par", "pro"}, {"! plural", "! proximal plural"}},
		["st-pl"]      = {basic_table, "2", nil, {"! singular"}},
		ind            = {basic_table, "234", nil, {"! singular", "! plural", "! proximal plural"}},
		["ind-sg"]     = {basic_table, "34", {"absv", "par", "pro"}, {"! plural", "! proximal plural"}},
		["ind-pl"]     = {basic_table, "24", {"absv", "par", "pro"}, {"! singular", "! proximal plural"}},
		["ind-both"]   = {basic_table_both_anims, "234", nil, {"! singular", "! plural", "! proximal plural"}}
	}
	local tbl_val = tbl_refs[tbl_type]
	if not tbl_val then
		error("Unsupported table type: '" .. tbl_type .. "'.")
	elseif type(tbl_val) == "table" then
		wikicode = wikicode .. generate_from_basic_table(unpack(tbl_val))
	else
		wikicode = wikicode .. tbl_val
	end
	
	--Close the table
	wikicode = wikicode .. mw.getCurrentFrame():expandTemplate{title = 'inflection-table-bottom', args = (data.notes and {notes = data.notes}) or nil}

	return mw.ustring.gsub(wikicode, "{{{[#!]?([a-z0-9|]+)}}}", repl) .. require("Module:utilities").format_categories(data.categories, lang)
end

-- Form-generating function
function export.generate_forms(noun, animacy, overrides, pos)
	local data = {
		forms = {},
		info = "Deklesi ",
		categories = {},
		notes = "",
	}
	local lemma = noun
	local definiteness = ""
	
	--Handle overrides
	local e_dip_ins = (overrides["md"] or overrides["gau"]) and "e" or "" --monosyllabic terms ending in a dipthong get an epenthetic -e- in the indefinite instrumental (deiez, not *deiz)
	local e_gau = overrides["gau"] and "e" or "" --gau (and its derivatives) get an epenthetic -e- in the singular local cases
	
	--Proper-noun overrides
	if overrides["sg-def"] then
		if not rfind(noun, "a$") then
			lemma = noun .. "a"
		end
		definiteness = " def-sg"
	elseif overrides["pl-def"] then
		if not rfind(noun, "a$") then
			lemma = noun .. "ak"
		else
			lemma = lemma .. "k"
		end
		definiteness = " def-pl"
	end
	
	--Declension info. FIXME: orthographic vowel/consonant overrides missing
	local anim_words = {an = "anim", ["in"] = "inan", both = "anim/inan"}
	local anim_word = anim_words[animacy]
	if pos == "adj" then
		anim_word = "kata sifat"
	elseif pos == "num" then
		anim_word = "kata bilangan"
	elseif pos == "det" then
		anim_word = "determiner"
	end
	
	data.info = data.info .. require("Module:links").full_link({lang = lang, alt = lemma}, "term") .. " <small>(" .. anim_word .. definiteness .. " "
	
	--plural/singular only?
	if overrides["sg"] then
		data.info = data.info .. "sg-only "
	elseif overrides["pl"] then
		if pos == "det" then
			data.info = data.info .. "pl "
		else
			data.info = data.info .. "pl-only "
		end
	end
	
	--stem type. Note that acronyms that aren't spelled out are treated like any other word (but FAGOR -> FAGORek, not *FAGORrek)
	local ending_A = false
	local ending_JKXZ = false
	if rfind(noun, "[jkxzJKXZ]$") and overrides["ini"] then
		data.info = data.info .. "a-stem" --initialisms whose final letter ends in -a. We include <jkxz> as they might occur in mixed-case initialisms.
		ending_JKXZ = true
	elseif rfind(noun, "ah?$") then
		data.info = data.info .. "a-stem"
	elseif rfind(noun, "A$") then
		data.info = data.info .. "a-stem"
		ending_A = true
	elseif rfind(noun, "[eiouwyEIOUWY]h?$") or overrides["ini"] then --word-final w and y are treated as vowels. Word-final <h> is mute.
		data.info = data.info .. "V-stem"
	elseif overrides["tap"] then
		data.info = data.info .. "ɾ-stem"
	else
		data.info = data.info .. "C-stem"
	end
	--insert notes if needed
	local notes_data = {}
	local note_number = 0
	local function add_note_number()
	    note_number = note_number + 1
	    data.info = data.info .. "<sup>" .. tostring(note_number) .. "</sup>"
	end
	local function add_note(text) table.insert(notes_data, text) end
	local func
	local word_acr = overrides["acr"] and "akronim fonetik" or "sesuatu inisialisme"
	if overrides["acr"] or overrides["ini"] then
		add_note_number()
		if pos ~= "proper" then
			if ending_A then
				add_note(
					"Perkataan ini merupakan " .. word_acr .. " yang berakhir pada " .. mw.getCurrentFrame():expandTemplate{title = 'IPAchar', args = {"/a/"}} .. ". Dalam bentuk jamak " .. 
					mw.getCurrentFrame():expandTemplate{title = 'angbr', args = {"A"}} .. " dikekalkan dalam teks dan ucapan.")
			else
				if overrides["acr"] then
					add_note("Perkataan ini ialah akronim fonetik. Deklesinya teratur.")
				else
					if ending_JKXZ then
						add_note("This is an initialism whose final letter ends in " .. mw.getCurrentFrame():expandTemplate{title = 'IPAchar', args = {"/a/"}} .. 
							". The definite article is written (but not pronounced) separately.")
					else
						add_note("This is an initialism whose final letter ends in a vowel other than " .. mw.getCurrentFrame():expandTemplate{title = 'IPAchar', args = {"/a/"}} .. 
							". The declension is regular.")
					end
				end
			end
		else
			add_note("This is " .. word_acr .. ". The declension is regular")
		end
	else
		if rfind(noun, "[aeiou]h$") or rfind(noun, "[wy]$") or overrides["ophyph"] or overrides["orthv"] or overrides["orthc"] then
			add_note("Optionally, case suffixes can be separated from the root with a hyphen.")
			add_note_number()
		end
		if overrides["orthv"] then
			add_note("Words ending in a written vowel but pronounced with a final consonant follow consonant declension in speech but vowel declension in writing.")
			add_note_number()
		end
		if overrides["orthc"] then
			add_note("Words ending in a written consonant but pronounced with a final vowel follow vowel declension in speech but consonant declension in writing.")
			add_note_number()
		end
		if rfind(noun, "ah$") and pos ~= "proper" then
			add_note("The article is added separately in the singular and the " .. mw.getCurrentFrame():expandTemplate{title = 'angbr', args = {"-ah"}} .. " is kept in the plural.")
			add_note_number()
		end
		if pos == "num" and (noun == "hiru" or noun == "lau") then
			add_note("Plural forms in the first column are used when the numeral functions as a noun, while those in the second are used when it functions as a pronoun.")
			add_note_number()
		end
	end
	--Note about hamaseiz/hamaseiez
	if pos == "num" and rfind(noun, "sei") and noun ~= "sei" then
		add_note("The instrumental indefinite of this numeral hasn't been standardized. The ending " .. 
			mw.getCurrentFrame():expandTemplate{title = 'm', args = {"eu", "", "-eiz"}} .. " can also be found.")
		--add_note_number() the superscript number should go in the form itself
	end
	data.info = data.info .. ")</small>"
	
	--Epenthetic e and r
	local e, r, a_s = "e", "r", "a"
	if rfind(noun, "[aeiouwyAEIOUWY]h?$") or overrides["ini"] then
		e = ""
	else
		r = ""
	end
	
	-- This is needed in acronyms like PDA (PDA + -a = PDA, not *PDAa)
	if rfind(noun, "A$") then
		a_s = ""
	end
	
	--add base form and prolative before changing -r to -rr
	data.forms["absv|indef"] = {noun}
	if rfind(noun, "t[szx]$") then
		data.forms["pro|indef"] = {(rsub(noun, "t([szx])$", "%1tzat"))}
	else
		data.forms["pro|indef"] = {noun .. "tzat"}
	end
	
	--double r if needed
	if rfind(noun, "r$") and not (overrides["tap"] or overrides["hyph"]) then
		noun = noun .. "r"
	end
	
	--nouns in -a
	local base_def = rfind(noun, "a$") and rsub(noun, "a$", "") or noun

	--nouns with compulsory hyphen
	if overrides["hyph"] then
		noun = noun .. "-"
	end

	--generate the forms
	function get_forms(def_stem)
		inflected = {}
		--absolutive
		inflected["absv|s"] = {def_stem .. a_s}
		inflected["absv|p"] = {def_stem .. a_s .. "k"}
		inflected["absv|prox|p"] = {def_stem .. "ok"}
		--ergative
		inflected["erg|indef"] = {noun .. e .. "k"}
		inflected["erg|s"] = {def_stem .. a_s .. "k"}
		inflected["erg|p"] = {def_stem .. "ek"}
		inflected["erg|prox|p"] = {def_stem .. "ok"}
		--dative
		inflected["dat|indef"] = {noun .. r .. "i"}
		inflected["dat|s"] = {def_stem .. a_s .. "ri"}
		inflected["dat|p"] = {def_stem .. "ei"}
		inflected["dat|prox|p"] = {def_stem .. "oi"}
		--comitative
		inflected["com|indef"] = {noun .. r .. "ekin"}
		inflected["com|s"] = {def_stem .. a_s .. "rekin"}
		inflected["com|p"] = {def_stem .. "ekin"}
		inflected["com|prox|p"] = {def_stem .. "okin"}
		--instrumental	
		inflected["ins|indef"] = {noun .. e .. e_dip_ins ..  "z"}
		inflected["ins|s"] = {def_stem .. a_s .. "z"}
		inflected["ins|p"] = {def_stem .. "ez"}
		inflected["ins|prox|p"] = {def_stem .. "otaz"}
		
		--add inanimate/animate flags
		local an_flag
		local in_flag = (animacy == "both") and "|inanimate" or ""
		single_anim_cases = m_table.listToSet({"gen", "caus", "ben"})
		
		--cases derived from the genitive (plus the genitive itself)
		local gen_cases = {gen = "", caus = "gatik", ben = "tzat", ine = "gan", all = "gana", ter = "ganaino", directive = "ganantz", destinative = "ganako", abl = "gandik"}
		for case, suf in pairs(gen_cases) do
			an_flag = (animacy == "both" and not single_anim_cases[case]) and "|animate" or ""
			inflected[case .. an_flag .. "|indef"] = {noun .. r .. "en" .. suf}
			inflected[case .. an_flag .. "|s"] = {def_stem .. a_s .. "ren" .. suf}
			inflected[case .. an_flag .. "|p"] = {def_stem .. "en" .. suf}
			inflected[case .. an_flag .. "|prox|p"] = {def_stem .. "on" .. suf}
		end
		
		--cases with the infix -ta- in the indefinite (inanimate only). We'll overwrite the previous ones if necessary
		local inan_cases = {ine = "n", loc = "ko", all = "ra", ter = "raino", directive = "rantz", destinative = "rako", abl = "tik"}
		local altform_cases = m_table.listToSet({"loc", "all", "ter", "directive", "destinative", "abl"})
		local cases_e_last = m_table.listToSet({"abl", "loc"})
		local a
		local ta = (pos == "proper") and "" or "ta"
		if animacy ~= "an" then
			for case, suf in pairs(inan_cases) do
				a = (case == "ine" and not rfind(noun, "[aA]$")) and "a" or ""
				inflected[case .. in_flag .. "|indef"] = {noun .. e .. ta .. suf}
				inflected[case .. in_flag .. "|s"] = {noun .. e .. e_gau .. a .. suf}
				inflected[case .. in_flag .. "|p"] = {def_stem .. "eta" .. suf}
				inflected[case .. in_flag .. "|prox|p"] = {def_stem .. "ota" .. suf}
				-- Place nouns ending in certain consonants can have forms with and without -e-
				if overrides["topo"] and altform_cases[case] then 
					local alt_loc_base = rsub(noun, "rr$", "r")
					local form_w_e = noun .. e .. suf
					local form_wo_e = alt_loc_base .. suf
					form_wo_e = m_com.rsub_multiple(form_wo_e, {"([nl])ko$", "([nl])tik$", "tzko", "tztik"}, {"%1go", "%1dik", "zko", "ztik"})
					if cases_e_last[case] then
						inflected[case .. in_flag .. "|indef"] = {form_wo_e, form_w_e}
					elseif rfind(noun, "r$") then --only in words like Eibar, Elgoibar...
						inflected[case .. in_flag .. "|indef"] = {form_w_e, form_wo_e}
					end
				end
			end	
		end
		
		--partitive
		inflected["par|indef"] = {noun .. r .. "ik"}
		
		return inflected
	end

	for k, v in pairs(get_forms(base_def)) do data.forms[k] = v end
	
	--extra plural forms (numerals [[hiru]] and [[lau]])
	if (noun == "hiru" or noun == "lau") and pos == "num" then
		local extra_forms = get_forms(noun .. "r")
		for k, v in pairs(extra_forms) do
			if rfind(k, "|p") then
				for _, val in ipairs(v) do
		            table.insert(data.forms[k], val)
		        end
			end
		end
	end
	
	--generate notes
	data.notes = next(notes_data) and "<small>" .. m_com.generate_notes_text(notes_data) .. "</small>" or nil

	return data
end

----------------------------------------------
----------------------------------------------

local function get_overrides(s, pos)
    if type(s) ~= "string" then
    	return {}
    end
    --List the allowed indicators
    local allowed = m_table.listToSet({"in", "an", "both", "pl", "sg", "pr", "topo", "gau", "md", "tap", "orthv", "orthc", "ini", "acr", "ophyph"})
    if pos == "adj" then
    	allowed = m_table.listToSet({"md", "tap", "orthv", "orthc", "ophyph"})
    elseif pos == "num" then
    	allowed = m_table.listToSet({"md"})
    elseif pos == "det" then
    	allowed = m_table.listToSet({"pl", "md", "tap"})
    end
    --Split the input and check for duplicates and unallowed indicators
    local parts, seen = rsplit(s, "%."), {}
    for _, part in ipairs(parts) do
        if seen[part] then
            error("Duplicate property: '" .. part .. "'.")
        end
        if not (allowed[part] or rfind(part, "^b:")) then
            error("The property '" .. part .. "' isn't supported.")
        end
        seen[part] = true
    end
    return m_table.listToSet(parts)
end

local function get_animacy(overrides)
	local anim_count = 0
	local valid_anim = m_table.listToSet({"an", "in", "both"})
	local result
	for part, _ in pairs(overrides) do
		if valid_anim[part] then
	        anim_count = anim_count + 1
	        result = part
	    end
	end
	if anim_count ~= 1 then
	    error("Exactly one of 'an', 'in', or 'both' must be provided")
	end
	return result
end

function export.main(frame)
	local args = frame:getParent().args
	
	-- add the lemma form
	local base = args.pagename or mw.title.getCurrentTitle().text
	
	--overrides
	local overrides = args[1] or nil
	local pos_hardcoded = frame.args.pos or nil
	local ort = get_overrides(overrides, pos_hardcoded)
	local pos = ort["pr"] and "proper" or nil
	if pos_hardcoded and pos then
		error("Can't specify 'pr' when the part of speech is an adjective or a numeral.")
	end
	pos = pos or pos_hardcoded
	
	--animacy (it can be hardcoded in the case of adjectives)
	local anim = ((pos == "num" or pos == "adj" or pos == "det") and "both") or get_animacy(ort)
	
	--check for incompatible overrides
	local incompat_pairs = {{"ini", "acr"}, {"orthv", "orthc"}, {"sg", "pl"}, {"md", "gau"}, {"tap", "md"}, {"tap", "gau"}, {"ophyph", "orthv"}, {"ophyph", "orthc"}}
	for _, p in ipairs(incompat_pairs) do
	    if ort[p[1]] and ort[p[2]] then
	        error(("Can't specify '%s' and '%s' at the same time."):format(p[1], p[2]))
	    end
	end
	if ort["tap"] and not rfind(base, "r$") then
		error("Can't specify 'tap' if the word doesn't end in -r.")
	elseif (rfind(base, "[aeiou]h$") or rfind(base, "[wy]$")) and ort["ophyph"] then
		error("The paramter 'ophyph' is not needed in words ending in -Vh, -y or -w, the note is added automatically.")
	elseif ort["topo"] and (pos ~= "proper" or anim == "an") then
		error("The paramter 'topo' can only be applied to inanimate proper nouns.")
	elseif ort["topo"] and not rfind(base, "[nlrsz]$") then
		error("Can't specify 'topo' to words not ending in -n, -l, -r, -s, -(t)z.")
	elseif ort["orthv"] and not rfind(base, "[aeiou]$") then
		error("The paramter 'orthv' can only be applied to words ending in an orthographic vowel (e.g. byte).")
	elseif ort["orthc"] and rfind(base, "[aeiou]$") then
		error("The paramter 'orthc' can only be applied to words ending in an orthographic consonant (e.g. Calais).")
	end
	
	--Proper noun overrides. If an indefinite form is manually provided, check that it is compatible with the page name
	local alt_base
	if pos == "proper" then
		if ort["sg"] or ort["pl"] then
			error("Can't specify 'sg' or 'pl' in proper nouns.")
		end
		for k, _ in pairs(ort) do
			if rfind(k, "^b:") then
				alt_base = rsub(k, "^b:", "")
				break
			end
		end
		--Check that the alt_base is plausible
		if alt_base then
			if rfind(alt_base, "r$") and not ort["tap"] then
				alt_base = alt_base .. "r"
			end
		
			if not rfind(alt_base, "a$") and (alt_base .. "a" == base) then
				ort["sg-def"] = true
			elseif not rfind(alt_base, "a$") and (alt_base .. "ak" == base) then
				ort["pl-def"] = true
			-- In the following two cases, the indefinite form ends with -a, so the definite forms are the same as the indefinite ones (which we don't show)
			elseif rfind(alt_base, "a$") and (alt_base == base) then --e.g. Dominikar Errepublika
				ort["sg-def"] = true
			elseif rfind(alt_base, "a$") and (alt_base .. "k" == base) then
				ort["pl-def"] = true
			else
				error("The definite form '" .. base .. "' doesn't match with the indefinite form '" .. alt_base .. "'.")
			end
			base = rsub(alt_base, "rr$", "r") --restore single -r
		end
	end
	
	--Handle acronyms
	local upper_case = "ABCÇDEFGHIJKLMNÑOPQRSTUVWXYZ"
	local is_acronym = rfind(base, "[" .. upper_case .. "]$")
	if is_acronym and not (ort["ini"] or ort["acr"]) then
		error("This word is either an acronym or an initialism but the required parameters were not specified.")
	elseif not is_acronym and (ort["ini"] or ort["acr"]) then -- Mixed-case acronyms get a hyphen 
		ort["hyph"] = true
	end
	
	--Generate the data
	local data = export.generate_forms(base, anim, ort, pos, hyphen)
	--Choose the table type
	local table_type = "st"
	if pos == "proper" or (pos == "det" and not ort["pl"]) then
		table_type = "ind"
	end
	if anim == "both" then
		table_type = table_type .. "-both"
	end
	if ort["pl"] or ort["pl-def"] then
		table_type = table_type .. "-pl"
	elseif ort["sg"] or ort["sg-def"] then
		table_type = table_type .. "-sg"
	end
	--Make the table
	return make_table(data, table_type)
end

return export