Hello, you have come here looking for the meaning of the word . In DICTIOUS you will not only get to know all the dictionary meanings for the word , but we will also tell you about its etymology, its characteristics and you will know how to say in singular and plural. Everything you need to know about the word you have here. The definition of the word will help you to be more precise and correct when speaking or writing your texts. Knowing the definition of, as well as those of other words, enriches your vocabulary and provides you with more and better linguistic resources.


local export = {}


--[=[

Authorship: <benwing2>

]=]

--[=[

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:User:Benwing2/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 = {
	 = {
		 = {"er", "en", "em", "en"},
		 = {"e", "er", "er", "e"},
		 = {"es", "en", "em", "es"},
		 = {"e", "er", "en", "e"},
	},
	 = {
		 = {"e", "en", "en", "en"},
		 = {"e", "en", "en", "e"},
		 = {"e", "en", "en", "e"},
		 = {"en", "en", "en", "en"},
	},
	 = {
		 = {"er", "en", "en", "en"},
		 = {"e", "en", "en", "e"},
		 = {"es", "en", "en", "es"},
		 = {"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
			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
				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 = 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 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)
			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
		local slot, rest = rmatch(part, "^(.-):(.*)$")
		if not adjective_slot_set then
			parse_err("Unrecognized slot '" .. slot .. "' in override: '" .. table.concat(segments) .. "'")
		end
		segments = 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
			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 then
					parse_err("Can't specify value for '" .. spectype .. "' twice")
				end
				dot_separated_group = rest
				base = 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 = true
				end
				base.suppress = suppress
			elseif part:find(":") then
				local slot, override = parse_override(dot_separated_group)
				if base.overrides then
					parse_err("Can't specify override twice for slot '" .. slot .. "'")
				else
					base.overrides = 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 then
					parse_err("Can't specify '" .. part .. "' twice")
				end
				base.props = 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, "()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 .. "$") then
		-- If we omitted -e- in the stem, put it back. E.g. ], stem ''simpl-'', comparative
		-- ''simpler'', superlative ''simpelst-'', or ], comparative ''abgeschlossener'' or
		-- ''abgeschlossner'', superlative just ''abgeschlossenst-''.
		local non_ending, ending = rmatch(stem, "^(.*)" .. OMITTED_E .. "()$")
		if base.props.ss then
			-- ] -> ''abgeschloßner'' -> ''abgeschlossenst'' (pre-1996 spelling)
			non_ending = rsub(non_ending, "ß$", "ss")
		end
		return non_ending .. "e" .. ending .. "st"
	elseif rfind(stem, "grß$") or rfind(stem, "grss$") then
		-- Write this way so we can be called either on positive or comparative stem.
		return stem .. "t"
	elseif rfind(stem, "hh$") then
		-- ], ], etc.
		-- Write this way so we can be called either on positive or comparative stem.
		return rsub(stem, "..$", "öchst")
	elseif rfind(stem, "nh$") then
		-- ], ], ], ], ], ] (has no comp in dewikt),
		-- ], ], etc.
		-- NOTE: ], ] can be either regular (like ] below) or following ].
		-- Write this way so we can be called either on positive or comparative stem.
		return rsub(stem, "..$", "ächst")
	elseif rfind(stem, "h$") then
		-- ], ], ], ], ], ] (has only jähest in dewikt), ],
		-- ], ], ]
		return {stem .. "st", stem .. "est"}
	elseif rfind(stem, "e?nd$") then
		-- Present participles; non-present-participles like ], ]/], ] need special-casing
		return stem .. "st"
	elseif rfind(stem, "e?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 ], ], ], ],
		-- ] need special-casing
		return stem .. "st"
	elseif rfind(stem, "igt$") then
		-- Most adjectives in -igt (past participles specifically), but not adjectives in -eigt such as ];
		-- exceptions like ], ] need special-casing
		return stem .. "st"
	elseif rfind(stem, "$") 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, "$") then
		if base.props.ss and rfind(stem, "ß$") then
			return rsub(stem, ".$", "ssest")
		end
		return stem .. "est"
	elseif rfind(stem, "sk$") then
		-- ], ], ], ], ], ]; also ], ]
		return stem .. "est"
	elseif rfind(stem, "sch$") then
		-- Adjectives in -sch where it is not an adjective-forming ending typically can take either -est or -st; examples
		-- are ], ], ], ]/], ]/], ],
		-- ]/], ], ], ], ]/]; maybe ]/]?
		-- (dewikt says sup. only ''krüschst'', Duden says only ''krüschest''); a few can take only -est per dewikt
		-- ]/]/], ], ], ], ]
		-- Cases where -sch without -isch occurs that is an adjective-forming ending need special-casing, e.g.
		-- ]
		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 {{form = "+"}}
	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()$")
				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, {{form = generate_default_stem(base)}},
	   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 = {{form = "+"}}
		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
		if alternant_multiword_spec.props == nil then
			alternant_multiword_spec.props = has_stem
		elseif alternant_multiword_spec.props ~= 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.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
		if alternant_multiword_spec.props == nil then
			alternant_multiword_spec.props = val
		elseif alternant_multiword_spec.props ~= 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
		base.forms = 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 = "]"
			elseif rfind(form, "%]%]$") then
				form = rsub(form, "%]%]$", "en]]")
			else
				form = form .. "en"
			end
			return "] " .. 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 generate_link(data)
		local slot = data.slot
		local link = m_links.full_link {
			lang = lang, term = data.form.formval_for_link, tr = "-", accel = data.form.accel_obj
		}
		local footnote_text = iut.get_footnote_text(data.form.footnotes, data.footnote_obj)
		link = link .. footnote_text

		if rfind(slot, "pred_m$") then
			return link_term("] ]") .. " " .. link
		elseif rfind(slot, "pred_f$") then
			return link_term("] ]") .. " " .. link
		elseif rfind(slot, "pred_n$") then
			return link_term("] ]") .. " " .. link
		elseif rfind(slot, "pred_p$") then
			return link_term("] ]") .. " " .. link
		elseif rfind(slot, "wk_") then
			local case, gender = rmatch(slot, ".*wk_(.*)_()$")
			return link_term(com.articles) .. " " .. link
		elseif rfind(slot, "mix_") then
			local case, gender = rmatch(slot, ".*mix_(.*)_()$")
			return link_term(com.articles) .. " " .. link
		else
			return link
		end
	end

	local function join_spans(data)
		return table.concat(data.formval_spans, "<br />")
	end

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

	local props = {
		lang = lang,
		lemmas = lemmas,
		generate_link = generate_link,
		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
| {COMPSUPSTATE_nom_m}
| {COMPSUPSTATE_nom_f}
| {COMPSUPSTATE_nom_n}
| {COMPSUPSTATE_nom_p}
|-
! style="background:#COLOR" | genitive
| {COMPSUPSTATE_gen_m}
| {COMPSUPSTATE_gen_f}
| {COMPSUPSTATE_gen_n}
| {COMPSUPSTATE_gen_p}
|-
! style="background:#COLOR" | dative
| {COMPSUPSTATE_dat_m}
| {COMPSUPSTATE_dat_f}
| {COMPSUPSTATE_dat_n}
| {COMPSUPSTATE_dat_p}
|-
! style="background:#COLOR" | accusative
| {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
[=[
<div class="NavFrame"style = "width:50%;">
<div class="NavHead" style="text-align: left;">{title}{annotation}</div>
<div class="NavContent">
{\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
! rowspan="2" style="background:#C0C0C0" | plural
|-
! style="background:#C0C0C0" | masculine
! style="background:#C0C0C0" | feminine
! style="background:#C0C0C0" | neuter
|-
]=] ..
rsub(rsub(single_state_table_spec, "COLOR", "efefff"), "STATE", alternant_multiword_spec.state) .. [=[
|{\cl}{notes_clause}</div></div>]=]

or not alternant_multiword_spec.args.truncate and

-- Normal (non-truncated) table
[=[
<div class="NavFrame">
<div class="NavHead" style="text-align: left">{title}{annotation}</div>
<div class="NavContent">
{\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
! rowspan="2" style="background:#C0C0C0" | plural
|-
! style="background:#C0C0C0" | masculine
! style="background:#C0C0C0" | feminine
! style="background:#C0C0C0" | neuter
|-
! colspan="2" style="background:#EEEEB0" | predicative
| {COMPSUPpred_m}
| {COMPSUPpred_f}
| {COMPSUPpred_n}
| {COMPSUPpred_p}
|-
! rowspan="4" style="background:#c0cfe4" | strong declension <br/> (without article)
]=] ..
rsub(rsub(single_state_table_spec, "COLOR", "c0cfe4"), "STATE", "str") .. [=[
! rowspan="4" style="background:#c0e4c0" | weak declension <br/> (with definite article)
]=] ..
rsub(rsub(single_state_table_spec, "COLOR", "c0e4c0"), "STATE", "wk") .. [=[
! rowspan="4" style="background:#e4d4c0" | mixed declension <br/> (with indefinite article)
]=] ..
rsub(rsub(single_state_table_spec, "COLOR", "e4d4c0"), "STATE", "mix") .. [=[
|{\cl}{notes_clause}</div></div>]=]

or

-- Truncated table, for the documentation page where otherwise we'd hit the template expand limit
[=[
<div class="NavFrame">
<div class="NavHead" style="text-align: left">{title}{annotation}</div>
<div class="NavContent">
{\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
! rowspan="2" style="background:#C0C0C0" | plural
|-
! style="background:#C0C0C0" | masculine
! style="background:#C0C0C0" | feminine
! style="background:#C0C0C0" | neuter
|-
! colspan="2" style="background:#EEEEB0" | predicative
| {COMPSUPpred_m}
| {COMPSUPpred_f}
| {COMPSUPpred_n}
| {COMPSUPpred_p}
|-
! rowspan="2" style="background:#c0cfe4" | strong declension <br/> (without article)
! style="background:#c0cfe4" | nominative
| {COMPSUPstr_nom_m}
| {COMPSUPstr_nom_f}
| {COMPSUPstr_nom_n}
| {COMPSUPstr_nom_p}
|-
! style="background:#c0cfe4" | ...
| colspan="4" | ...
|-
! rowspan="2" style="background:#c0e4c0" | weak declension <br/> (with definite article)
! style="background:#c0e4c0" | nominative
| {COMPSUPwk_nom_m}
| {COMPSUPwk_nom_f}
| {COMPSUPwk_nom_n}
| {COMPSUPwk_nom_p}
|-
! style="background:#c0e4c0" | ...
| colspan="4" | ...
|-
! rowspan="2" style="background:#e4d4c0" | mixed declension <br/> (with indefinite article)
! style="background:#e4d4c0" | nominative
| {COMPSUPmix_nom_m}
| {COMPSUPmix_nom_f}
| {COMPSUPmix_nom_n}
| {COMPSUPmix_nom_p}
|-
! style="background:#e4d4c0" | ...
| colspan="4" | ...
|{\cl}{notes_clause}</div></div>]=])

	local notes_template = [===[
<div style="width:100%;text-align:left;background:#d9ebff">
<div style="display:inline-block;text-align:left;padding-left:1em;padding-right:1em">
{footnote}
</div></div>
]===]

	local ital_lemma = '<i lang="de" class="Latn">' .. forms.lemma .. "</i>"

	local annotation = alternant_multiword_spec.annotation
	if annotation == "" then
		forms.annotation = ""
	else
		forms.annotation = " (<span style=\"font-size: smaller;\">" .. annotation .. "</span>)"
	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 = {
		 = {},
		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 = {list = true}
		params = {}
		params = {}
		params = {type = "boolean"}
		params = {type = "boolean"}
		params = {type = "boolean"}
	end

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

	if not args then
		if mw.title.getCurrentTitle().text == "de-adecl" then
			args = def or "lang<comp:^>"
		else
			args = ""
		end
	end
	local arg1 = args
	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 <<name:...>> 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: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 {{de-adecl}}. 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)
		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
	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