Module:User:Benwing2/de-adjective

local export = {}

--[=[

Authorship:

]=]

--[=[

TERMINOLOGY:

-- "slot" = A particular combination of state/case/gender/number. Example slot names for adjectives are "mix_nom_m" (mixed nominative masculine singular), "sup_str_dat_p" (superlative strong dative plural) and "comp_pred" (comparative predicative). Each slot is filled with zero or more forms.

-- "form" = The declined German form representing the value of a given slot.

-- "lemma" = The dictionary form of a given German term. Generally the predicative, but may be the strong nominative masculine singular or other form. ]=]

local lang = require("Module:languages").getByCode("de") local m_links = require("Module:links") local m_table = require("Module:table") local m_string_utilities = require("Module:string utilities") local iut = require("Module:inflection utilities") local com = require("Module:de-common")

local u = mw.ustring.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 uupper = mw.ustring.upper

local OMITTED_E = u(0xFFF0)

-- 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 link_term(term, face) return m_links.full_link({ lang = lang, term = term }, face) end

local endings = { ["str"] = { ["m"] = {"er", "en", "em", "en"}, ["f"] = {"e", "er", "er", "e"}, ["n"] = {"es", "en", "em", "es"}, ["p"] = {"e", "er", "en", "e"}, },	["wk"] = { ["m"] = {"e", "en", "en", "en"}, ["f"] = {"e", "en", "en", "e"}, ["n"] = {"e", "en", "en", "e"}, ["p"] = {"en", "en", "en", "en"}, },	["mix"] = { ["m"] = {"er", "en", "en", "en"}, ["f"] = {"e", "en", "en", "e"}, ["n"] = {"es", "en", "en", "es"}, ["p"] = {"en", "en", "en", "en"}, }, }

local cases = { "nom", "gen", "dat", "acc" } local genders = { "m", "f", "n", "p" } local states = { "str", "wk", "mix" } local comps = { "", "comp", "sup" }

local adjective_slot_list_positive = { -- We generate the lemma into `the_lemma` because `lemma` is special-cased in iut.show_forms -- to hold the lemma string. {"the_lemma", "-"}, } local adjective_slot_list_comparative = { } local adjective_slot_list_superlative = { } for _, comp in ipairs(comps) do	local slot_list = comp == "" and adjective_slot_list_positive or		comp == "comp" and adjective_slot_list_comparative or		adjective_slot_list_superlative local compsup = comp ~= "" and comp .. "_" or "" for _, state in ipairs(states) do		for _, gender in ipairs(genders) do			local case_endings = endings[state][gender] for i, case in ipairs(cases) do local slot = compsup .. state .. "_" .. case .. "_" .. gender local comp_ending = comp == "comp" and "er" or comp == "sup" and "st" or "" local accel = "adj-form-" .. comp_ending .. case_endings[i] table.insert(slot_list, {slot, accel}) end end end table.insert(slot_list, {compsup .. "pred", "-"}) for _, gender in ipairs(genders) do table.insert(slot_list, {compsup .. "pred_" .. gender, "-"}) end end

local adjective_slot_set = {} local all_adjective_slot_list = {} local function add_slots(slot_list) for _, slot_accel in ipairs(slot_list) do		table.insert(all_adjective_slot_list, slot_accel) local slot, accel = unpack(slot_accel) if slot ~= "the_lemma" then adjective_slot_set[slot] = true end end end add_slots(adjective_slot_list_positive) add_slots(adjective_slot_list_comparative) add_slots(adjective_slot_list_superlative)

local function add(base, slot, stem, ending, footnotes) if not ending or base.suppress and base.suppress[ending] then return end local function do_combine_stem_ending(stem, ending) return rsub(stem, OMITTED_E, "") .. ending end

if ending == "en" and (base.props.sync_n or base.props.sync_mn or base.props.sync_mns) then ending = "n" elseif ending == "em" and (base.props.sync_mn or base.props.sync_mns) then ending = "m" elseif ending == "es" and base.props.sync_mns then ending = "s" end footnotes = iut.combine_footnotes(base.footnotes, footnotes) local ending_obj = iut.combine_form_and_footnotes(ending, footnotes) iut.add_forms(base.forms, slot, stem, ending_obj, do_combine_stem_ending) end

local function decline(base, stem, compsup) for _, state in ipairs(states) do local prefix = compsup .. state .. "_"		for _, gender in ipairs(genders) do			for i, case in ipairs(cases) do add(base, prefix .. case .. "_" .. gender, stem, endings[state][gender][i]) end end end end

local function parse_indicator_spec(angle_bracket_spec, lemma, pagename) if lemma == "" then lemma = pagename end local base = {forms = {}, stems = {}, overrides = {}, props = {}} base.orig_lemma = lemma base.orig_lemma_no_links = m_links.remove_links(lemma) base.lemma = base.orig_lemma_no_links local inside = rmatch(angle_bracket_spec, "^<(.*)>$") assert(inside)

local function parse_err(msg) error(msg .. ": <" .. inside .. ">") end

--[=[	Parse a single override spec and return two values: the slot the override applies to and the override specs. The input is a list where the footnotes have been separated out, i.e. parse_balanced_segment_run(..., "[", "]") has already been called. ]=]	local function parse_override(segments) local part = segments[1] local slot, rest = rmatch(part, "^(.-):(.*)$") if not adjective_slot_set[slot] then parse_err("Unrecognized slot '" .. slot .. "' in override: '" .. table.concat(segments) .. "'") end segments[1] = rest return slot, com.fetch_specs(iut, segments, ":", "override", nil, parse_err) end

if inside ~= "" then local segments = iut.parse_balanced_segment_run(inside, "[", "]") local dot_separated_groups = iut.split_alternating_runs_and_strip_spaces(segments, "%.") for i, dot_separated_group in ipairs(dot_separated_groups) do			local part = dot_separated_group[1] if part == "comp" then part = "comp:+" end if rfind(part, "^comp:") or rfind(part, "^sup:") or rfind(part, "^stem:") then local spectype, rest = rmatch(part, "^(.-):(.*)$") if base[spectype] then parse_err("Can't specify value for '" .. spectype .. "' twice") end dot_separated_group[1] = rest base[spectype] = com.fetch_specs(iut, dot_separated_group, ":", spectype, nil, parse_err) elseif rfind(part, "^state:") then if #dot_separated_group > 1 then parse_err("Can't specify footnotes with 'state': '" .. table.concat(dot_separated_group) .. "'") end if base.state then parse_err("Can't specify value for 'state:' twice") end local state = rsub(part, "state:", "") if not m_table.contains(states, state) then parse_err("Unrecognized state '" .. state .. "', should be one of " .. table.concat(states, "/")) end base.state = state elseif rfind(part, "^suppress:") then if #dot_separated_group > 1 then parse_err("Can't specify footnotes with 'suppress': '" .. table.concat(dot_separated_group) .. "'") end if base.suppress then parse_err("Can't specify value for 'suppress:' twice") end part = rsub(part, "suppress:", "") local endings = rsplit(part, "%s*:%s*") local suppress = {} for _, ending in ipairs(endings) do					if ending ~= "e" and ending ~= "em" and ending ~= "en" and ending ~= "er" and ending ~= "es" then parse_err("Unrecognized ending '" .. ending .. "' in suppress: spec: '" .. table.concat(dot_separated_group) .. "'") end suppress[ending] = true end base.suppress = suppress elseif part:find(":") then local slot, override = parse_override(dot_separated_group) if base.overrides[slot] then parse_err("Can't specify override twice for slot '" .. slot .. "'") else base.overrides[slot] = override end elseif part == "" then if #dot_separated_group == 1 then parse_err("Blank indicator") end base.footnotes = com.fetch_footnotes(dot_separated_group, parse_err) elseif #dot_separated_group > 1 then parse_err("Footnotes only allowed with slot overrides, comp:, sup:, stem: or by themselves: '" .. table.concat(dot_separated_group) .. "'") elseif part == "ss" or part == "indecl" or part == "predonly" or				part == "sync_n" or part == "sync_mn" or part == "sync_mns" then if base.props[part] then parse_err("Can't specify '" .. part .. "' twice") end base.props[part] = true else parse_err("Unrecognized indicator '" .. part .. "'") end end end return base end

local function generate_default_stem(base) if base.props.ss then return rsub(base.lemma, "ß$", "ss") end if base.lemma:find("e$") then return rsub(base.lemma, "e$", "") end return rsub(base.lemma, "([ai])bel$", "%1b" .. OMITTED_E .. "l") end

local function generate_default_comp(base, stem) return stem .. "er" end

local function generate_default_sup(base, stem) if rfind(stem, OMITTED_E .. "[lmnr]$") then -- If we omitted -e- in the stem, put it back. E.g. simpel, stem simpl-, comparative -- simpler, superlative simpelst-, or abgeschlossen, comparative abgeschlossener or -- abgeschlossner, superlative just abgeschlossenst-. local non_ending, ending = rmatch(stem, "^(.*)" .. OMITTED_E .. "([lmnr])$") if base.props.ss then -- abgeschlossen -> abgeschloßner -> abgeschlossenst (pre-1996 spelling) non_ending = rsub(non_ending, "ß$", "ss") end return non_ending .. "e" .. ending .. "st" elseif rfind(stem, "gr[oö]ß$") or rfind(stem, "gr[oö]ss$") then -- Write this way so we can be called either on positive or comparative stem. return stem .. "t" elseif rfind(stem, "h[oö]h$") then -- hoch, ranghoch, etc. -- Write this way so we can be called either on positive or comparative stem. return rsub(stem, "..$", "öchst") elseif rfind(stem, "n[aä]h$") then -- nah, äquatornah, bahnhofsnah, bodennah, citynah, hautnah (has no comp in dewikt), -- körpernah, zeitnah, etc. -- NOTE: erdnah, praxisnah can be either regular (like froh below) or following nah. -- Write this way so we can be called either on positive or comparative stem. return rsub(stem, "..$", "ächst") elseif rfind(stem, "[aeiouäöü]h$") then -- froh, farbenfroh, lebensfroh, schadenfroh, früh, jäh (has only jähest in dewikt), rauh, -- roh, weh, zäh return {stem .. "st", stem .. "est"} elseif rfind(stem, "e[rl]?nd$") then -- Present participles; non-present-participles like elend, behend/behende, horrend need special-casing return stem .. "st" elseif rfind(stem, "[^wi]e[rl]?t$") then -- Most adjectives in -et, -elt, -ert (past participles specifically), but not adjectives in -iert, -ielt or		-- non-past-participles in -wert; other non-past-participles like alert, inert, concret, discret, -- obsolet need special-casing return stem .. "st" elseif rfind(stem, "[^e]igt$") then -- Most adjectives in -igt (past participles specifically), but not adjectives in -eigt such as abgeneigt; -- exceptions like gewitzigt, gerechtfertigt need special-casing return stem .. "st" elseif rfind(stem, "[ae][iuwy]$") then -- Those ending in diphthongs can take either -est -or -st (scheu, neu, schlau, frei, blau/blaw, etc.) return {stem .. "est", stem .. "st"} elseif rfind(stem, "[szxßdt]$") then if base.props.ss and rfind(stem, "ß$") then return rsub(stem, ".$", "ssest") end return stem .. "est" elseif rfind(stem, "sk$") then -- burlesk, chevaleresk, dantesk, grotesk, pittoresk, pythonesk; also brüsk, promisk return stem .. "est" elseif rfind(stem, "[^i]sch$") then -- Adjectives in -sch where it is not an adjective-forming ending typically can take either -est or -st; examples -- are barsch, falsch, fesch, forsch/nassforsch, frisch/taufrisch, harsch, -- keusch/unkeusch, lasch, morsch, rasch, wirsch/unwirsch; maybe krüsch/krütsch? -- (dewikt says sup. only krüschst, Duden says only krüschest); a few can take only -est per dewikt -- deutsch/süddeutsch/teutsch, hübsch, krosch, resch, rösch -- Cases where -sch without -isch occurs that is an adjective-forming ending need special-casing, e.g.		-- figelinsch return {stem .. "est", stem .. "st"} else return stem .. "st" end end

local function process_spec(base, destforms, slot, specs, base_stem, form_default) local function do_form_default(form) local retval = form_default(base, form) if type(retval) ~= "table" then retval = {retval} end return retval end specs = specs or 	for _, spec in ipairs(specs) do		local forms if spec.form == "-" then -- Skip "-"; effectively, no forms get inserted into output.comp. elseif spec.form == "+" then forms = iut.flatmap_forms(base_stem, do_form_default) elseif rfind(spec.form, "^%+") then local ending = rsub(spec.form, "^%+", "") forms = iut.map_forms(base_stem, function(form) return form .. ending end) elseif spec.form == "^" then forms = iut.flatmap_forms(base_stem, function(form) return do_form_default(com.apply_umlaut(form)) end) elseif rfind(spec.form, "^%^") then local ending = rsub(spec.form, "^%^", "") forms = iut.map_forms(base_stem, function(form) return com.apply_umlaut(form) .. ending end) elseif spec.form == "-e" then forms = iut.flatmap_forms(base_stem, function(form)				local non_ending, ending = rmatch(form, "^(.*)e([lmnr])$")				if not non_ending then					error("Can't use '-e' with stem '" .. form .. "'; should end in -el, -em, -en or -er")				end				if base.props.ss then					non_ending = rsub(non_ending, "ss$", "ß")				end				return do_form_default(non_ending .. OMITTED_E .. ending)			end) else iut.insert_form(destforms, slot, spec) end if forms then forms = iut.convert_to_general_list_form(forms, spec.footnotes) iut.insert_forms(destforms, slot, forms) end end end

local function detect_indicator_spec(alternant_multiword_spec, base) -- First generate the stem(s), substituting + with the default formed from the lemma. process_spec(base, base.stems, "stem", base.stem, ,	  function(base, stem) return stem end)

-- Next process the superative, if specified. We do this first so that if there is a superative and no -- comparative specified, we add a comparative; but if sup:- is given, we don't add a comparative. if base.sup then process_spec(base, base.stems, "sup", base.sup, base.stems.stem, generate_default_sup) if base.stems.sup and not base.comp then base.comp = end end -- Next process the comparative, if specified (or defaulted because a superlative was specified). if base.comp then process_spec(base, base.stems, "comp", base.comp, base.stems.stem, generate_default_comp) end -- Next, if comparative specified but not superlative, derive the superlative(s) from the comparative(s). if base.stems.comp and not base.sup then local sups = iut.flatmap_forms(base.stems.comp, function(form)			if not rfind(form, "er$") then				error("Don't know how to derive superlative from comparative '" .. form .. "' because it doesn't end in -er; specify the superlative explicitly using sup:...")			end			local retval = generate_default_sup(base, rsub(form, "er$", ""))			if type(retval) ~= "table" then				retval = {retval}			end			return retval		end) iut.insert_forms(base.stems, "sup", sups) end

-- Make sure all alternants agree in having a comparative and/or superlative. for _, compsup in ipairs { {"comp", "has_comp", "comparative"}, {"sup", "has_sup", "superlative"} } do		local stem, altprop, desc = unpack(compsup) local has_stem = not not base.stems[stem] if alternant_multiword_spec.props[altprop] == nil then alternant_multiword_spec.props[altprop] = has_stem elseif alternant_multiword_spec.props[altprop] ~= has_stem then error("If one alternant has a " .. desc .. ", all must") end end

if base.props.predonly then base.props.indecl = true end if base.overrides.pred and base.overrides.pred[1].form == "-" then base.props.nopred = true end if base.props.predonly and base.props.nopred then error("Can't be both 'predonly' and 'pred:-'") end

-- Make sure all alternants agree in 'state' if specified. local stateval = base.state or false if alternant_multiword_spec.state == nil then alternant_multiword_spec.state = stateval elseif alternant_multiword_spec.state ~= stateval then error("All alternants must agree in the value of 'state', if specified") end

-- Make sure all alternants agree in various properties. for _, propdesc in ipairs { {"indecl"}, {"nopred", "pred:-"}, {"predonly"} } do		local prop, desc = unpack(propdesc) desc = desc or prop local val = not not base.props[prop] if alternant_multiword_spec.props[prop] == nil then alternant_multiword_spec.props[prop] = val elseif alternant_multiword_spec.props[prop] ~= val then error("If one alternant specifies '" .. desc .. "', all must") end end end

local function detect_all_indicator_specs(alternant_multiword_spec) iut.map_word_specs(alternant_multiword_spec, function(base)		detect_indicator_spec(alternant_multiword_spec, base)	end) end

local function process_slot_overrides(base) for slot, overrides in pairs(base.overrides) do		local origforms = base.forms[slot] base.forms[slot] = nil process_spec(base, base.forms, slot, overrides, origforms, function(base, form) return form end) end end

local function decline_adjective(base) decline(base, base.stems.stem, "") if base.stems.comp then decline(base, base.stems.comp, "comp_") end if base.stems.sup then decline(base, base.stems.sup, "sup_") end add(base, "the_lemma", base.orig_lemma, "") add(base, "pred", base.lemma, "") if base.stems.comp and not base.props.nopred then add(base, "comp_pred", base.stems.comp, "") end if base.stems.sup and not base.props.nopred then add(base, "sup_pred", iut.map_forms(base.stems.sup, function(form) if not rfind(form, "[%[%]]") then form = "" .. form .. "en" elseif rfind(form, "%]%]$") then form = rsub(form, "%]%]$", "en]]") else form = form .. "en" end return "am " .. form end), "") end process_slot_overrides(base) end

-- Compute the categories to add the adjective to, as well as the annotation to display in the -- declension 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) alternant_multiword_spec.categories = {} local function insert(cattype) cattype = rsub(cattype, "~", alternant_multiword_spec.pos) m_table.insertIfNot(alternant_multiword_spec.categories, "German " .. cattype) end local annotation local annparts = {} if not alternant_multiword_spec.props.has_comp then table.insert(annparts, "uncomparable") insert("uncomparable ~") end if not alternant_multiword_spec.forms.pred then table.insert(annparts, "no predicate") insert("~ without predicate") end alternant_multiword_spec.annotation = table.concat(annparts, ", ") end

local function show_forms(alternant_multiword_spec) local lemmas = alternant_multiword_spec.forms.the_lemma or {}

local function add_pronouns_and_articles(slot, link) if rfind(slot, "pred_m$") then return link_term("er ist") .. " " .. link elseif rfind(slot, "pred_f$") then return link_term("sie ist") .. " " .. link elseif rfind(slot, "pred_n$") then return link_term("es ist") .. " " .. link elseif rfind(slot, "pred_p$") then return link_term("sie sind") .. " " .. link elseif rfind(slot, "wk_") then local case, gender = rmatch(slot, ".*wk_(.*)_([mfnp])$") return link_term(com.articles[gender]["def_" .. case]) .. " " .. link elseif rfind(slot, "mix_") then local case, gender = rmatch(slot, ".*mix_(.*)_([mfnp])$") return link_term(com.articles[gender]["ind_" .. case]) .. " " .. link else return link end end

local function join_spans(slot, spans) return table.concat(spans, " ") end

local function copy_predicate_forms(compsup) for _, gender in ipairs(genders) do alternant_multiword_spec.forms[compsup .. "pred_" .. gender] = alternant_multiword_spec.forms[compsup .. "pred"] end end copy_predicate_forms("") copy_predicate_forms("comp_") copy_predicate_forms("sup_")

local props = { lang = lang, lemmas = lemmas, transform_link = add_pronouns_and_articles, join_spans = join_spans, }	props.slot_list = adjective_slot_list_positive iut.show_forms(alternant_multiword_spec.forms, props) alternant_multiword_spec.footnote_positive = alternant_multiword_spec.forms.footnote if alternant_multiword_spec.props.has_comp then props.slot_list = adjective_slot_list_comparative iut.show_forms(alternant_multiword_spec.forms, props) alternant_multiword_spec.footnote_comparative = alternant_multiword_spec.forms.footnote end if alternant_multiword_spec.props.has_sup then props.slot_list = adjective_slot_list_superlative iut.show_forms(alternant_multiword_spec.forms, props) alternant_multiword_spec.footnote_superlative = alternant_multiword_spec.forms.footnote end end

local single_state_table_spec = [=[ ! style="background:#COLOR" | nominative ! style="background:#COLOR" | genitive ! style="background:#COLOR" | dative ! style="background:#COLOR" | accusative ]=]
 * {COMPSUPSTATE_nom_m}
 * {COMPSUPSTATE_nom_f}
 * {COMPSUPSTATE_nom_n}
 * {COMPSUPSTATE_nom_p}
 * {COMPSUPSTATE_gen_m}
 * {COMPSUPSTATE_gen_f}
 * {COMPSUPSTATE_gen_n}
 * {COMPSUPSTATE_gen_p}
 * {COMPSUPSTATE_dat_m}
 * {COMPSUPSTATE_dat_f}
 * {COMPSUPSTATE_dat_n}
 * {COMPSUPSTATE_dat_p}
 * {COMPSUPSTATE_acc_m}
 * {COMPSUPSTATE_acc_f}
 * {COMPSUPSTATE_acc_n}
 * {COMPSUPSTATE_acc_p}

local function make_table(alternant_multiword_spec) if alternant_multiword_spec.props.indecl then if alternant_multiword_spec.props.predonly then return "Indeclinable, predicative-only." elseif alternant_multiword_spec.props.nopred then return "Indeclinable, no predicative." else return "Indeclinable." end end

local forms = alternant_multiword_spec.forms

local table_spec = (alternant_multiword_spec.state and -- Single-state table [=[ {title}{annotation} {\op}| border="1px solid #cdcdcd" style="border-collapse:collapse; background:#FEFEFE; width:100%;" class="inflection-table" ! rowspan="2" style="background:#C0C0C0" | number & gender ! colspan="3" style="background:#C0C0C0" | singular ! style="background:#C0C0C0" | plural ! style="background:#C0C0C0" | masculine ! style="background:#C0C0C0" | feminine ! style="background:#C0C0C0" | neuter ! style="background:#C0C0C0" | all genders ]=] .. rsub(rsub(single_state_table_spec, "COLOR", "efefff"), "STATE", alternant_multiword_spec.state) .. [=[
 * {\cl}{notes_clause} ]=]

or not alternant_multiword_spec.args.truncate and

-- Normal (non-truncated) table [=[ {title}{annotation} {\op}| border="1px solid #cdcdcd" style="border-collapse:collapse; background:#FEFEFE; width:100%" class="inflection-table" ! colspan="2" rowspan="2" style="background:#C0C0C0" | number & gender ! colspan="3" style="background:#C0C0C0" | singular ! style="background:#C0C0C0" | plural ! style="background:#C0C0C0" | masculine ! style="background:#C0C0C0" | feminine ! style="background:#C0C0C0" | neuter ! style="background:#C0C0C0" | all genders ! colspan="2" style="background:#EEEEB0" | predicative ! rowspan="4" style="background:#c0cfe4" | strong declension (without article) ]=] .. rsub(rsub(single_state_table_spec, "COLOR", "c0cfe4"), "STATE", "str") .. [=[ ! rowspan="4" style="background:#c0e4c0" | weak declension (with definite article) ]=] .. rsub(rsub(single_state_table_spec, "COLOR", "c0e4c0"), "STATE", "wk") .. [=[ ! rowspan="4" style="background:#e4d4c0" | mixed declension (with indefinite article) ]=] .. rsub(rsub(single_state_table_spec, "COLOR", "e4d4c0"), "STATE", "mix") .. [=[
 * {COMPSUPpred_m}
 * {COMPSUPpred_f}
 * {COMPSUPpred_n}
 * {COMPSUPpred_p}
 * {\cl}{notes_clause} ]=]

or

-- Truncated table, for the documentation page where otherwise we'd hit the template expand limit [=[ {title}{annotation} {\op}| border="1px solid #cdcdcd" style="border-collapse:collapse; background:#FEFEFE; width:100%" class="inflection-table" ! colspan="2" rowspan="2" style="background:#C0C0C0" | number & gender ! colspan="3" style="background:#C0C0C0" | singular ! style="background:#C0C0C0" | plural ! style="background:#C0C0C0" | masculine ! style="background:#C0C0C0" | feminine ! style="background:#C0C0C0" | neuter ! style="background:#C0C0C0" | all genders ! colspan="2" style="background:#EEEEB0" | predicative ! rowspan="2" style="background:#c0cfe4" | strong declension (without article) ! style="background:#c0cfe4" | nominative ! style="background:#c0cfe4" | ... ! rowspan="2" style="background:#c0e4c0" | weak declension (with definite article) ! style="background:#c0e4c0" | nominative ! style="background:#c0e4c0" | ... ! rowspan="2" style="background:#e4d4c0" | mixed declension (with indefinite article) ! style="background:#e4d4c0" | nominative ! style="background:#e4d4c0" | ...
 * {COMPSUPpred_m}
 * {COMPSUPpred_f}
 * {COMPSUPpred_n}
 * {COMPSUPpred_p}
 * {COMPSUPstr_nom_m}
 * {COMPSUPstr_nom_f}
 * {COMPSUPstr_nom_n}
 * {COMPSUPstr_nom_p}
 * colspan="4" | ...
 * {COMPSUPwk_nom_m}
 * {COMPSUPwk_nom_f}
 * {COMPSUPwk_nom_n}
 * {COMPSUPwk_nom_p}
 * colspan="4" | ...
 * {COMPSUPmix_nom_m}
 * {COMPSUPmix_nom_f}
 * {COMPSUPmix_nom_n}
 * {COMPSUPmix_nom_p}
 * colspan="4" | ...
 * {\cl}{notes_clause} ]=])

local notes_template = [===[ {footnote} ]===]

local ital_lemma = '' .. forms.lemma .. ""

local annotation = alternant_multiword_spec.annotation if annotation == "" then forms.annotation = "" else forms.annotation = " (" .. annotation .. " )" end

-- Format the positive table. local positive_table_spec = rsub(table_spec, "COMPSUP", "") forms.title = "Positive forms of " .. ital_lemma forms.footnote = alternant_multiword_spec.footnote_positive forms.notes_clause = forms.footnote ~= "" and m_string_utilities.format(notes_template, forms) or "" local positive_table = m_string_utilities.format(positive_table_spec, forms)

-- Maybe format the comparative table. local comparative_table = "" if alternant_multiword_spec.props.has_comp then local comparative_table_spec = rsub(table_spec, "COMPSUP", "comp_") forms.title = "Comparative forms of " .. ital_lemma forms.footnote = alternant_multiword_spec.footnote_comparative forms.notes_clause = forms.footnote ~= "" and m_string_utilities.format(notes_template, forms) or "" comparative_table = m_string_utilities.format(comparative_table_spec, forms) end

-- Maybe format the superlative table. local superlative_table = "" if alternant_multiword_spec.props.has_sup then local superlative_table_spec = rsub(table_spec, "COMPSUP", "sup_") forms.title = "Superlative forms of " .. ital_lemma forms.footnote = alternant_multiword_spec.footnote_superlative forms.notes_clause = forms.footnote ~= "" and m_string_utilities.format(notes_template, forms) or "" superlative_table = m_string_utilities.format(superlative_table_spec, forms) end

-- Paste them together. return positive_table .. comparative_table .. superlative_table end

-- Externally callable function to parse and decline a noun given user-specified arguments. -- Return value is ALTERNANT_MULTIWORD_SPEC, an object where the declined forms are in `ALTERNANT_MULTIWORD_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, footnotes=FOOTNOTES}. function export.do_generate_forms(parent_args, pos, from_headword, def) local params = { [1] = {},		pagename = {}, -- If truncate=1 is specified, truncate the tables to reduce the template expansion size, -- for use on documentation and test pages. truncate = {type = "boolean"}, }	if from_headword or pretend_from_headword then params["head"] = {list = true} params["id"] = {} params["sort"] = {} params["splithyph"] = {type = "boolean"} params["nolinkhead"] = {type = "boolean"} params["new"] = {type = "boolean"} end

local args = require("Module:parameters").process(parent_args, params)

if not args[1] then if mw.title.getCurrentTitle.text == "de-adecl" then args[1] = def or "lang" else args[1] = "" end end local arg1 = args[1] local need_surrounding_angle_brackets = true -- Check whether we need to add <...> around the argument. If the -- argument has no < in it, we definitely do. Otherwise, we need to	-- parse the balanced [...] and <...> and add <...> only if there isn't	-- a top-level <...>. We check for [...] because there might be angle -- brackets inside of them (HTML tags in qualifiers or <> and	-- such in references). if arg1:find("<") then local segments = iut.parse_multi_delimiter_balanced_segment_run(arg1, {{"<", ">"}, {"[", "]"}}) for i = 2, #segments, 2 do			if segments[i]:find("^<.*>$") then need_surrounding_angle_brackets = false break end end end if need_surrounding_angle_brackets then arg1 = "<" .. arg1 .. ">"	end

local function do_parse_indicator_spec(angle_bracket_spec, lemma) local pagename = args.pagename or mw.title.getCurrentTitle.text return parse_indicator_spec(angle_bracket_spec, lemma, pagename) end

local parse_props = { parse_indicator_spec = do_parse_indicator_spec, allow_default_indicator = true, allow_blank_lemma = true, }	local alternant_multiword_spec = iut.parse_inflected_text(arg1, parse_props) alternant_multiword_spec.pos = pos or "adjectives" alternant_multiword_spec.args = args alternant_multiword_spec.forms = {} alternant_multiword_spec.props = {} detect_all_indicator_specs(alternant_multiword_spec) local inflect_props = { lang = lang, skip_slot = function(slot) return false end, slot_list = all_adjective_slot_list, inflect_word_spec = decline_adjective, }	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. Template-callable function to parse and decline -- an adjective given user-specified arguments and generate a displayable table -- of the declined forms. function export.show(frame) local parent_args = frame:getParent.args local alternant_spec = export.do_generate_forms(parent_args) show_forms(alternant_spec) return make_table(alternant_spec) .. require("Module:utilities").format_categories(alternant_spec.categories, lang) end

-- Concatenate all forms of all slots into a single string of the form "SLOT=FORM,FORM,...|SLOT=FORM,FORM,...|...". -- 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 _, slotaccel in pairs(adjective_slot_list) do		local slot, accel = unpack(slotaccel) local formtext = iut.concat_forms_in_slot(alternant_spec.forms[slot]) if formtext then table.insert(ins_text, slot .. "=" .. formtext) end end return table.concat(ins_text, "|") end

-- Template-callable function to parse and decline an adjective 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["include_props"] 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