Module:roa-opt-verb
Appearance
- This module lacks a documentation subpage. Please create it.
- Useful links: subpage list • links • transclusions • testcases • sandbox
local export = {}
--[=[
Authorship: Ben Wing <benwing2>
]=]
--[=[
TERMINOLOGY:
-- "slot" = A particular combination of tense/mood/person/number/gender/etc.
Example slot names for verbs are "pres_1sg" (present first singular) and
"past_pasv_part_impers" (impersonal past passive participle).
Each slot is filled with zero or more forms.
-- "form" = The conjugated Old Galician-Portuguese form representing the value of a given slot.
-- "lemma" = The dictionary form of a given Old Galician-Portuguese term. Generally the infinitive,
but may occasionally be another form if the infinitive is missing.
]=]
local lang = require("Module:languages").getByCode("roa-opt")
local langname = lang:getCanonicalName()
local m_string_utilities = require("Module:string utilities")
local m_script_utilities = require("Module:script utilities")
local iut = require("Module:inflection utilities")
local put = require("Module:parse utilities")
local m_para = require("Module:parameters")
local m_links = require("Module:links")
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
-- 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 tag_text(text)
return m_script_utilities.tag_text(text, lang)
end
local function make_link(term)
return m_links.full_link({ lang = lang, term = term }, "term")
end
local verb_slots = {
{"infinitive", "inf"},
{"gerund", "ger"},
{"pp_ms", "past|part"},
{"pp_mp", "m|p|past|part"},
{"pp_fs", "f|s|past|part"},
{"pp_fp", "f|p|past|part"},
{"presp_s", "pres|part"},
{"presp_p", "p|pres|part"},
{"pres_1s", "1|s|pres|ind"},
{"pres_2s", "2|s|pres|ind"},
{"pres_3s", "3|s|pres|ind"},
{"pres_1p", "1|p|pres|ind"},
{"pres_2p", "2|p|pres|ind"},
{"pres_3p", "3|p|pres|ind"},
{"impf_1s", "1|s|impf|ind"},
{"impf_2s", "2|s|impf|ind"},
{"impf_3s", "3|s|impf|ind"},
{"impf_1p", "1|p|impf|ind"},
{"impf_2p", "2|p|impf|ind"},
{"impf_3p", "3|p|impf|ind"},
{"pret_1s", "1|s|pret|ind"},
{"pret_2s", "2|s|pret|ind"},
{"pret_3s", "3|s|pret|ind"},
{"pret_1p", "1|p|pret|ind"},
{"pret_2p", "2|p|pret|ind"},
{"pret_3p", "3|p|pret|ind"},
{"plup_1s", "1|s|plup|ind"},
{"plup_2s", "2|s|plup|ind"},
{"plup_3s", "3|s|plup|ind"},
{"plup_1p", "1|p|plup|ind"},
{"plup_2p", "2|p|plup|ind"},
{"plup_3p", "3|p|plup|ind"},
{"fut_1s", "1|s|fut|ind"},
{"fut_2s", "2|s|fut|ind"},
{"fut_3s", "3|s|fut|ind"},
{"fut_1p", "1|p|fut|ind"},
{"fut_2p", "2|p|fut|ind"},
{"fut_3p", "3|p|fut|ind"},
{"cond_1s", "1|s|cond"},
{"cond_2s", "2|s|cond"},
{"cond_3s", "3|s|cond"},
{"cond_1p", "1|p|cond"},
{"cond_2p", "2|p|cond"},
{"cond_3p", "3|p|cond"},
{"sub_1s", "1|s|pres|sub"},
{"sub_2s", "2|s|pres|sub"},
{"sub_3s", "3|s|pres|sub"},
{"sub_1p", "1|p|pres|sub"},
{"sub_2p", "2|p|pres|sub"},
{"sub_3p", "3|p|pres|sub"},
{"impfsub_1s", "1|s|impf|sub"},
{"impfsub_2s", "2|s|impf|sub"},
{"impfsub_3s", "3|s|impf|sub"},
{"impfsub_1p", "1|p|impf|sub"},
{"impfsub_2p", "2|p|impf|sub"},
{"impfsub_3p", "3|p|impf|sub"},
{"futsub_1s", "1|s|fut|sub"},
{"futsub_2s", "2|s|fut|sub"},
{"futsub_3s", "3|s|fut|sub"},
{"futsub_1p", "1|p|fut|sub"},
{"futsub_2p", "2|p|fut|sub"},
{"futsub_3p", "3|p|fut|sub"},
{"imp_2s", "2|s|imp"},
{"imp_3s", "3|s|imp"},
{"imp_1p", "1|p|imp"},
{"imp_2p", "2|p|imp"},
{"negimp_2s", "-"},
{"negimp_3s", "-"},
{"negimp_1p", "-"},
{"negimp_2p", "-"},
{"persinf_1s", "1|s|pers|inf"},
{"persinf_2s", "2|s|pers|inf"},
{"persinf_3s", "3|s|pers|inf"},
{"persinf_1p", "1|p|pers|inf"},
{"persinf_2p", "2|p|pers|inf"},
{"persinf_3p", "3|p|pers|inf"},
}
local function fetch_footnotes(separated_group, parse_err)
local footnotes
for j = 2, #separated_group - 1, 2 do
if separated_group[j + 1] ~= "" then
parse_err("Extraneous text after bracketed footnotes: '" .. table.concat(separated_group) .. "'")
end
if not footnotes then
footnotes = {}
end
table.insert(footnotes, separated_group[j])
end
return footnotes
end
local function process_overrides(forms, args)
for _, slotspec in ipairs(verb_slots) do
local slot, accel = unpack(slotspec)
if args[slot] then
if args[slot] ~= "-" and args[slot] ~= "—" then
local parse_err = put.make_parse_err(("%s=%s"):format(slot, args[slot]))
local segments = put.parse_balanced_segment_run(args[slot], "[", "]")
segments = put.rejoin_delimited_runs {
runs = segments,
delimiter_pattern = "^%[%[.*%]%]$"
}
local comma_separated_groups = put.split_alternating_runs_and_strip_spaces(segments, ",")
for _, comma_separated_group in ipairs(comma_separated_groups) do
local formobj = {}
formobj.form = comma_separated_group[1]
formobj.footnotes = fetch_footnotes(comma_separated_group, parse_err)
iut.insert_form(forms, slot, formobj)
end
end
end
end
end
local function process_derived_slots(alternant_multiword_spec)
if not alternant_multiword_spec.noimp then
local forms = alternant_multiword_spec.forms
for _, from_to in ipairs { { "sub_3s", "imp_3s" }, { "sub_1p", "imp_1p" } } do
local from, to = unpack(from_to)
if forms[from] then
iut.insert_forms(forms, to, forms[from])
end
end
for _, from_to in ipairs { { "sub_2s", "negimp_2s" }, { "sub_3s", "negimp_3s" },
{ "sub_1p", "negimp_1p" }, { "sub_2p", "negimp_2p" } } do
local from, to = unpack(from_to)
if forms[from] then
for _, formobj in ipairs(forms[from]) do
local form = formobj.form
local prefix = "[[non]] "
if form:find("^%*") then
prefix = "*" .. prefix
form = form:sub(2)
end
if not form:find("%[%[") then
form = "[[" .. form .. "]]"
end
form = prefix .. form
iut.insert_form(forms, to, {form = form, footnotes = formobj.footnotes})
end
end
end
end
end
local function process_aux(alternant_multiword_spec)
local auxparam = alternant_multiword_spec.aux or "haver-teer"
local haver = make_link("haver")
local next_note = 0
local aux_footnotes = {}
local function insert_and_get_footnote(footnote)
table.insert(aux_footnotes, footnote)
next_note = next_note + 1
return '<sup class="roa-red-superscript">' .. next_note .. "</sup>"
end
local aux_text
if auxparam == "-" then
aux_text = ""
else
local auxvals = rsplit(auxparam, "%-")
local aux_parts = {}
local saw_seer = false
local saw_haver = false
for _, aux in ipairs(auxvals) do
if aux == "haver" then
local note = insert_and_get_footnote("[its alternative spelling, " .. make_link("aver") ..
", can be used as well]")
table.insert(aux_parts, haver .. note)
saw_haver = true
elseif aux == "teer" then
local note = insert_and_get_footnote("[" .. make_link("teer") .. " and " .. make_link("ter") ..
" were used too, though all 3 were less common than forms of " .. haver .. "]")
table.insert(aux_parts, make_link("tẽer") .. note)
saw_haver = true
elseif aux == "seer" then
table.insert(aux_parts, make_link("seer"))
saw_seer = true
else
error((
"Unrecognized auxiliary '%s', should be 'haver', 'teer', 'seer' or a hyphen-separated combination"
):format(aux))
end
end
aux_text = table.concat(aux_parts, " or ")
if saw_seer or saw_haver then
table.insert(alternant_multiword_spec.categories, langname .. " verbs taking " .. (
saw_haver and saw_seer and "haver or seer" or saw_seer and "seer" or "haver") .. " as auxiliary")
end
end
alternant_multiword_spec.aux_text = aux_text
alternant_multiword_spec.aux_footnotes = aux_footnotes
end
local function show_forms(alternant_multiword_spec)
local function create_footnote_obj()
local obj = iut.create_footnote_obj()
iut.get_footnote_text(alternant_multiword_spec.aux_footnotes, obj)
return obj
end
local function generate_link(data)
local formobj = data.form
local form = formobj.form
local prefix = ""
if form:find("^%*") then
prefix = "*"
form = form:sub(2)
end
return prefix .. m_links.full_link { lang = lang, term = form, accel = formobj.accel_obj } ..
iut.get_footnote_text(formobj.footnotes, data.footnote_obj)
end
alternant_multiword_spec.lemmas = alternant_multiword_spec.forms.infinitive or {}
local props = {
lemmas = alternant_multiword_spec.lemmas,
create_footnote_obj = create_footnote_obj,
generate_link = generate_link,
slot_list = verb_slots,
lang = lang,
}
iut.show_forms(alternant_multiword_spec.forms, props)
end
local function make_spec(has_aux, has_footnotes)
return [=[
<div class="NavFrame">
<div class="NavHead">{title}{annotation}</div>
<div class="NavContent">
{\op}| class="roa-inflection-table" data-toggle-category="inflection"
|-
! colspan="2" {rowspan_if_aux} class="roa-nonfinite-header" | infinitive
! colspan="2" class="roa-nonfinite-header" | simple
| colspan="4" | {infinitive}
|-
]=] .. (not has_aux and "" or [=[
! colspan="2" class="roa-nonfinite-header" | compound
! colspan="4" class="roa-compound-row"| infinitive of {aux} + past participle
|-
]=]) .. [=[
! colspan="2" {rowspan_if_aux} class="roa-nonfinite-header" | gerund
! colspan="2" class="roa-nonfinite-header" | simple
| colspan="4" | {gerund}
|-
]=] .. (not has_aux and "" or [=[
! colspan="2" class="roa-nonfinite-header" | compound
! colspan="4" class="roa-compound-row"| gerund of {aux} + past participle
|-
]=]) .. [=[
! rowspan="3" colspan="2" class="roa-nonfinite-header" | past participle
| colspan="2" class="roa-nonfinite-header" |
! colspan="2" class="roa-nonfinite-header" | singular
! colspan="2" class="roa-nonfinite-header" | plural
|-
! colspan="2" class="roa-nonfinite-header" | masculine
| colspan="2" | {pp_ms}
| colspan="2" | {pp_mp}
|-
! colspan="2" class="roa-nonfinite-header" | feminine
| colspan="2" | {pp_fs}
| colspan="2" | {pp_fp}
|-
! colspan="4" class="roa-nonfinite-header" | present participle
| colspan="2" | {presp_s}
| colspan="2" | {presp_p}
|-
! colspan="2" rowspan="2" class="roa-person-number-header" | person
! colspan="3" class="roa-person-number-header" | singular
! colspan="3" class="roa-person-number-header" | plural
|-
! class="roa-person-number-header" style="width:12.5%;" | first
! class="roa-person-number-header" style="width:12.5%;" | second
! class="roa-person-number-header" style="width:12.5%;" | third
! class="roa-person-number-header" style="width:12.5%;" | first
! class="roa-person-number-header" style="width:12.5%;" | second
! class="roa-person-number-header" style="width:12.5%;" | third
|-
! class="roa-indicative-left-rail" colspan="2" | indicative mood
! class="roa-indicative-left-rail" | {eu}<br />{ei}
! class="roa-indicative-left-rail" | {tu}
! class="roa-indicative-left-rail" | {el}~{ele}<br />{ela}<br />{vossa_mercee}
! class="roa-indicative-left-rail" | {nos}<br />{nos_outros}<br />{nos_outras}
! class="roa-indicative-left-rail" | {vos}<br />{vos_outros}<br />{vos_outras}
! class="roa-indicative-left-rail" | {eles}<br />{elas}
|-
! rowspan="6" class="roa-indicative-left-rail" | simple<br />tenses
! class="roa-indicative-left-rail" | present
| {pres_1s}
| {pres_2s}
| {pres_3s}
| {pres_1p}
| {pres_2p}
| {pres_3p}
|-
! class="roa-indicative-left-rail" | imperfect
| {impf_1s}
| {impf_2s}
| {impf_3s}
| {impf_1p}
| {impf_2p}
| {impf_3p}
|-
! class="roa-indicative-left-rail" | preterite
| {pret_1s}
| {pret_2s}
| {pret_3s}
| {pret_1p}
| {pret_2p}
| {pret_3p}
|-
! class="roa-indicative-left-rail" | pluperfect
| {plup_1s}
| {plup_2s}
| {plup_3s}
| {plup_1p}
| {plup_2p}
| {plup_3p}
|-
! class="roa-indicative-left-rail" | future
| {fut_1s}
| {fut_2s}
| {fut_3s}
| {fut_1p}
| {fut_2p}
| {fut_3p}
|-
! class="roa-indicative-left-rail" | conditional
| {cond_1s}
| {cond_2s}
| {cond_3s}
| {cond_1p}
| {cond_2p}
| {cond_3p}
|-
]=] .. (not has_aux and "" or [=[
! rowspan="6" class="roa-indicative-left-rail" | compound<br />tenses
! class="roa-indicative-left-rail" | present perfect
! colspan="6" class="roa-compound-row" | present of {aux} + past participle
|-
! class="roa-indicative-left-rail" | present imperfect
! colspan="6" class="roa-compound-row" | imperfect of {aux} + past participle
|-
! class="roa-indicative-left-rail" | past anterior
! colspan="6" class="roa-compound-row" | preterite of {aux} + past participle
|-
! class="roa-indicative-left-rail" | pluperfect
! colspan="6" class="roa-compound-row" | simple pluperfect of {aux} + past participle
|-
! class="roa-indicative-left-rail" | future perfect
! colspan="6" class="roa-compound-row" | future of {aux} + past participle
|-
! class="roa-indicative-left-rail" | conditional perfect
! colspan="6" class="roa-compound-row" | conditional of {aux} + past participle
|-
]=]) .. [=[
! class="roa-subjunctive-left-rail" colspan="2" | subjunctive mood
! class="roa-subjunctive-left-rail" | {eu}<br />{ei}
! class="roa-subjunctive-left-rail" | {tu}
! class="roa-subjunctive-left-rail" | {el}~{ele}<br />{ela}<br />{vossa_mercee}
! class="roa-subjunctive-left-rail" | {nos}<br />{nos_outros}<br />{nos_outras}
! class="roa-subjunctive-left-rail" | {vos}<br />{vos_outros}<br />{vos_outras}
! class="roa-subjunctive-left-rail" | {eles}<br />{elas}
|-
! rowspan="3" class="roa-subjunctive-left-rail" | simple<br />tenses
! class="roa-subjunctive-left-rail" | present
| {sub_1s}
| {sub_2s}
| {sub_3s}
| {sub_1p}
| {sub_2p}
| {sub_3p}
|-
! class="roa-subjunctive-left-rail" | imperfect
| {impfsub_1s}
| {impfsub_2s}
| {impfsub_3s}
| {impfsub_1p}
| {impfsub_2p}
| {impfsub_3p}
|-
! class="roa-subjunctive-left-rail" | future
| {futsub_1s}
| {futsub_2s}
| {futsub_3s}
| {futsub_1p}
| {futsub_2p}
| {futsub_3p}
|-
]=] .. (not has_aux and "" or [=[
! rowspan="3" class="roa-subjunctive-left-rail" | compound<br />tenses
! class="roa-subjunctive-left-rail" | present perfect
! colspan="6" class="roa-compound-row" | present subjunctive of {aux} + past participle
|-
! class="roa-subjunctive-left-rail" | pluperfect
! colspan="6" class="roa-compound-row" | preterite subjunctive of {aux} + past participle
|-
! class="roa-subjunctive-left-rail" | future perfect
! colspan="6" class="roa-compound-row" | future subjunctive of {aux} + past participle
|-
]=]) .. [=[
! colspan="2" class="roa-imperative-left-rail" | imperative mood
! class="roa-imperative-left-rail" | —
! class="roa-imperative-left-rail" | {tu}
! class="roa-imperative-left-rail" | {vossa_mercee}
! class="roa-imperative-left-rail" | {nos}<br />{nos_outros}<br />{nos_outras}
! class="roa-imperative-left-rail" | {vos}<br />{vos_outros}<br />{vos_outras}
! class="roa-imperative-left-rail" | —
|-
! colspan="2" class="roa-imperative-left-rail" | affirmative
| —
| {imp_2s}
| {imp_3s}
| {imp_1p}
| {imp_2p}
| —
|-
! colspan="2" class="roa-imperative-left-rail" | negative
| —
| {negimp_2s}
| {negimp_3s}
| {negimp_1p}
| {negimp_2p}
| —
|-
! rowspan="2" colspan="2" class="roa-nonfinite-header" | personal infinitive
! class="roa-nonfinite-header" | {eu}<br />{ei}
! class="roa-nonfinite-header" | {tu}
! class="roa-nonfinite-header" | {el}~{ele}<br />{ela}<br />{vossa_mercee}
! class="roa-nonfinite-header" | {nos}<br />{nos_outros}<br />{nos_outras}
! class="roa-nonfinite-header" | {vos}<br />{vos_outros}<br />{vos_outras}
! class="roa-nonfinite-header" | {eles}<br />{elas}
|-
| {persinf_1s}
| {persinf_2s}
| {persinf_3s}
| {persinf_1p}
| {persinf_2p}
| {persinf_3p}
]=] .. (not has_footnotes and "" or [=[
|-
| colspan="10" align="left"|{footnote}
]=]) .. [=[|{\cl}</div></div>]=]
end
local function make_table(alternant_multiword_spec)
local forms = alternant_multiword_spec.forms
if alternant_multiword_spec.title then
forms.title = alternant_multiword_spec.title
else
local lemmaspec
if alternant_multiword_spec.lemmas[1] then
local lemmas = {}
for _, inf in ipairs(alternant_multiword_spec.lemmas) do
table.insert(lemmas, inf.form)
end
lemmaspec = table.concat(lemmas, ", ")
else
lemmaspec = "—"
end
forms.title = 'Conjugation of <i lang="roa-opt" class="Latn">' .. lemmaspec .. '</i>'
end
local ann_parts = {}
if alternant_multiword_spec.impers then
table.insert(ann_parts, "impersonal")
end
if alternant_multiword_spec.irreg then
table.insert(ann_parts, "irregular")
end
if ann_parts[1] then
forms.annotation = " (" .. table.concat(ann_parts, ", ") .. ")"
else
forms.annotation = ""
end
-- pronouns used in the table
forms.eu = tag_text("eu")
forms.ei = tag_text("ei")
forms.tu = tag_text("tu")
forms.el = tag_text("el")
forms.ele = tag_text("ele")
forms.ela = tag_text("ela")
forms.vossa_mercee = tag_text(alternant_multiword_spec.impers and "<s>vossa mercee</s>" or "vossa mercee")
forms.nos = tag_text("nos")
forms.nos_outros = tag_text("nos outros")
forms.nos_outras = tag_text("nos outras")
forms.vos = tag_text("vos")
forms.vos_outros = tag_text("vos outros")
forms.vos_outras = tag_text("vos outras")
forms.eles = tag_text("eles")
forms.elas = tag_text("elas")
local has_footnote = forms.footnote ~= ""
local has_aux = alternant_multiword_spec.aux_text ~= ""
local table_spec = make_spec(has_aux, has_footnote)
forms.rowspan_if_aux = has_aux and 'rowspan="2"' or ""
forms.aux = alternant_multiword_spec.aux_text
return require("Module:TemplateStyles")("Module:roa-verb/style.css") .. m_string_utilities.format(table_spec, forms)
end
-- Externally callable function to parse and conjugate a verb given user-specified arguments. Return value is
-- ALTERNANT_MULTIWORD_SPEC, an object where the conjugated 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_manual(parent_args)
local params = {
aux = {},
title = {},
irreg = {type = "boolean"},
impers = {type = "boolean"},
noimp = {type = "boolean"},
}
for _, slotspec in ipairs(verb_slots) do
local slot, accel = unpack(slotspec)
params[slot] = {}
end
local args = m_para.process(parent_args, params)
local alternant_multiword_spec = {
forms = {},
aux = args.aux,
title = args.title,
irreg = args.irreg,
impers = args.impers,
noimp = args.noimp,
categories = {},
}
if args.impers then
table.insert(alternant_multiword_spec.categories, langname .. " impersonal verbs")
end
if args.irreg then
table.insert(alternant_multiword_spec.categories, langname .. " irregular verbs")
end
process_overrides(alternant_multiword_spec.forms, args)
process_derived_slots(alternant_multiword_spec)
process_aux(alternant_multiword_spec)
return alternant_multiword_spec
end
-- Entry point for {{roa-opt-conj-manual}}. Template-callable function to parse and conjugate a verb given
-- manually-specified inflections and generate a displayable table of the conjugated forms.
function export.show_manual(frame)
local parent_args = frame:getParent().args
local alternant_multiword_spec = export.do_generate_forms_manual(parent_args)
show_forms(alternant_multiword_spec)
return make_table(alternant_multiword_spec) .. require("Module:utilities").format_categories(alternant_multiword_spec.categories, lang)
end
return export