Module:conjugaisons/tense-generators
Ce module est une dépendance du module conjugaisons. Il définit des fonctions qui permet de générer les flexions des verbes du français.
Plus de détails à venir.
La documentation de ce module est générée par le modèle {{Documentation module}}.
Elle est incluse depuis la page Module:conjugaisons/tense-generators/Documentation. Veuillez placer les catégories sur cette page-là.
Les éditeurs peuvent travailler dans le bac à sable (créer).
Voir les statistiques d'appel depuis le wikicode sur l'outil wstat et les appels depuis d'autres modules.
local m_model = require("Module:conjugaisons/data-model")
local p = {}
--- Conjugation of the "avoir" auxiliary verb.
local avoirConj = {
infinitif = {
present = "avoir",
},
participe = {
present = "ayant",
passe = "eu",
},
indicatif = {
present = { "ai", "as", "a", "avons", "avez", "ont" },
imparfait = { "avais", "avais", "avait", "avions", "aviez", "avaient" },
passeSimple = { "eus", "eus", "eut", "eûmes", "eûtes", "eurent" },
futur = { "aurai", "auras", "aura", "aurons", "aurez", "auront" },
},
subjonctif = {
present = { "aie", "aies", "ait", "ayons", "ayez", "aient" },
imparfait = { "eusse", "eusses", "eût", "eussions", "eussiez", "eussent" }
},
conditionnel = {
present = { "aurais", "aurais", "aurait", "aurions", "auriez", "auraient" }
},
imperatif = {
present = { "aie", "ayons", "ayez" }
},
}
--- Conjugation of the "être" auxiliary verb.
local etreConj = {
infinitif = {
present = "être",
},
participe = {
present = "étant",
passe = "été",
},
indicatif = {
present = { "suis", "es", "est", "sommes", "êtes", "sont" },
imparfait = { "étais", "étais", "était", "étions", "étiez", "étaient" },
passeSimple = { "fus", "fus", "fut", "fûmes", "fûtes", "furent" },
futur = { "serai", "seras", "sera", "serons", "serez", "seront" },
},
subjonctif = {
present = { "sois", "sois", "soit", "soyons", "soyez", "soient" },
imparfait = { "fusse", "fusses", "fût", "fussions", "fussiez", "fussent" }
},
conditionnel = {
present = { "serais", "serais", "serait", "serions", "seriez", "seraient" }
},
imperatif = {
present = { "sois", "soyons", "soyez" }
},
}
--- For group-1 verbs ending in "-eler/-eter", mutate the root in "-ell-/-ett-" instead of "-èl-/-èt-".
local MUTATION_DOUBLE_CONS = "double consonne"
--- For group-1 verbs ending in "-ayer", keep the "y" instead of mutating it to "i" before silent endings.
local MUTATION_AYER_YE = "ayer-ye"
--- For group-2 verbs ending in "-ïr", replace the "ï" by a "i" for the 3 singular persons of indicative
--- and the singular imperative present.
local MUTATION_I = "ï-i"
--- All available root mutation types.
p.mutationTypes = {
MUTATION_DOUBLE_CONS,
MUTATION_AYER_YE,
MUTATION_I,
}
--- All available template group-3 verb endings, indexed by the template verb.
p.group3Templates = mw.loadData("Module:conjugaisons/group3-templates")
--- Sentinel object representing an empty value in tables
local NULL = {}
--- Instanciate a new verb table containing empty values for all simple tenses.
--- @return table A new empty template.
local function createEmptyTemplate()
return {
infinitif = {
present = NULL,
},
participe = {
present = NULL,
passe = NULL,
},
indicatif = {
present = { NULL, NULL, NULL, NULL, NULL, NULL },
imparfait = { NULL, NULL, NULL, NULL, NULL, NULL },
passeSimple = { NULL, NULL, NULL, NULL, NULL, NULL },
futur = { NULL, NULL, NULL, NULL, NULL, NULL },
},
subjonctif = {
present = { NULL, NULL, NULL, NULL, NULL, NULL },
imparfait = { NULL, NULL, NULL, NULL, NULL, NULL },
},
conditionnel = {
present = { NULL, NULL, NULL, NULL, NULL, NULL },
},
imperatif = {
present = { NULL, NULL, NULL },
},
}
end
--- Generate a list of group-1 verb endings of the form `<firstLetter><consonants>er`.
--- @param firstLetter string The first letter.
--- @param consonants string[] The list of consonnants to generate endings with.
--- @return string[] The list of generated endings.
local function generateGroup1Endings(firstLetter, consonants)
local endings = {}
for _, c in ipairs(consonants) do
endings[firstLetter .. c .. "er"] = c
end
return endings
end
--- The list of all available group-1 endings of the form `e<consonants>er`.
local eCONSer_verbs = generateGroup1Endings("e", {
"c",
"d",
"g",
"l",
"m",
"n",
"p",
"r",
"s",
"t",
"v",
"vr",
})
--- The list of all available group-1 endings of the form `é<consonants>er`.
local eacuteCONSer_verbs = generateGroup1Endings("é", {
"b",
"br",
"c",
"ch",
"cr",
"d",
"fl",
"g",
"gn",
"gr",
"gu",
"j",
"l",
"m",
"n",
"p",
"qu",
"r",
"s",
"t",
"tr",
"v",
"vr",
})
--- Raise an error for the given mutation type.
--- @param mutationType string The mutation type.
local function invalidMutationType(mutationType)
error(mw.ustring.format('Valeur invalide pour le paramètre « mutation » ("%s").', mutationType))
end
--- Check whether the given string starts with an "a", "â" or "o".
--- @param s string The string to check.
--- @return boolean True if the string starts with "a", "â" or "o", false otherwise.
local function startsWithAO(s)
local firstLetter = mw.ustring.sub(s, 1, 1)
return firstLetter == "a" or firstLetter == "â" or firstLetter == "o"
end
--- Check whether the given group-1 ending is silent.
--- @param ending string The ending to check.
--- @return boolean True if the ending is silent, false otherwise.
local function isGroup1EndingSilent(ending)
return ending == "e" or ending == "es" or ending == "ent"
end
--- Generate the simple tense forms of the given group-1 verb.
--- @param infinitive string The infinitive form of the verb.
--- @param rootMapper function Optional. A function that, given the verb’s root and an ending,
--- builds the associated verb form.
--- @param infinitiveMapper function Optional. A function that, given a verb’s ending,
--- builds the associated verb form based on its infinitive.
--- @return table A table containing all simple tense forms of the verb.
local function generateGroup1Forms_(infinitive, rootMapper, infinitiveMapper)
rootMapper = rootMapper or function(root, ending)
return root .. ending
end
infinitiveMapper = infinitiveMapper or function(ending)
return infinitive .. ending
end
local root = mw.ustring.sub(infinitive, 1, -3)
return {
infinitif = {
present = infinitive,
},
participe = {
present = rootMapper(root, "ant"),
passe = rootMapper(root, "é"),
},
indicatif = {
present = {
rootMapper(root, "e"),
rootMapper(root, "es"),
rootMapper(root, "e"),
rootMapper(root, "ons"),
rootMapper(root, "ez"),
rootMapper(root, "ent")
},
imparfait = {
rootMapper(root, "ais"),
rootMapper(root, "ais"),
rootMapper(root, "ait"),
rootMapper(root, "ions"),
rootMapper(root, "iez"),
rootMapper(root, "aient")
},
passeSimple = {
rootMapper(root, "ai"),
rootMapper(root, "as"),
rootMapper(root, "a"),
rootMapper(root, "âmes"),
rootMapper(root, "âtes"),
rootMapper(root, "èrent")
},
futur = {
infinitiveMapper("ai"),
infinitiveMapper("as"),
infinitiveMapper("a"),
infinitiveMapper("ons"),
infinitiveMapper("ez"),
infinitiveMapper("ont")
},
},
subjonctif = {
present = {
rootMapper(root, "e"),
rootMapper(root, "es"),
rootMapper(root, "e"),
rootMapper(root, "ions"),
rootMapper(root, "iez"),
rootMapper(root, "ent")
},
imparfait = {
rootMapper(root, "asse"),
rootMapper(root, "asses"),
rootMapper(root, "ât"),
rootMapper(root, "assions"),
rootMapper(root, "assiez"),
rootMapper(root, "assent")
}
},
conditionnel = {
present = {
infinitiveMapper("ais"),
infinitiveMapper("ais"),
infinitiveMapper("ait"),
infinitiveMapper("ions"),
infinitiveMapper("iez"),
infinitiveMapper("aient")
}
},
imperatif = {
present = {
rootMapper(root, "e"),
rootMapper(root, "ons"),
rootMapper(root, "ez")
}
},
}
end
--- Mutate the given group-1 verb root according to the given ending.
--- @param root string The verb’s root.
--- @param ending string A verb ending.
--- @return string The mutated root if it ends in "g" or "c", the argument root otherwise.
local function mutateRoot_cer_ger(root, ending)
local lastLetter = mw.ustring.sub(root, -1)
if lastLetter ~= "g" and lastLetter ~= "c" then
return root
end
local mutation = lastLetter == "g" and "ge" or "ç"
return startsWithAO(ending) and (mw.ustring.sub(root, 1, -2) .. mutation) or root
end
--- Generate the simple tense forms of the given group-1 verb ending in `[cg]er`.
--- @param infinitive string The infinitive form of the verb.
--- @return table A table containing all simple tense forms of the verb.
local function generateGroup1Forms_cer_ger(infinitive)
return generateGroup1Forms_(infinitive, function(root, ending)
return mutateRoot_cer_ger(root, ending) .. ending
end)
end
--- Generate the simple tense forms of the given group-1 verb ending in `[eè]<consonant(s)>er`.
--- @param infinitive string The infinitive form of the verb.
--- @param consonants string The consonant(s) that precede the mutating "e".
--- @param doubleConsonant boolean True to double the consonant instead of mutating the "e/é" into an "è".
--- @return table A table containing all simple tense forms of the verb.
local function generateGroup1Forms_eCONSer(infinitive, consonants, doubleConsonant)
if doubleConsonant and consonants ~= "l" and consonants ~= "t" then
invalidMutationType(MUTATION_DOUBLE_CONS)
end
local base = mw.ustring.sub(infinitive, 1, -4 - mw.ustring.len(consonants))
local mutatedRoot = base .. (doubleConsonant and ("e" .. consonants) or "è") .. consonants
return generateGroup1Forms_(infinitive, function(root, ending)
return mutateRoot_cer_ger(isGroup1EndingSilent(ending) and mutatedRoot or root, ending) .. ending
end, function(ending)
return mutatedRoot .. "er" .. ending
end)
end
--- Generate the simple tense forms of the given group-1 verb ending in `[aeou]yer`.
--- @param infinitive string The infinitive form of the verb.
--- @param mutateYe boolean If the verb ends in "-ayer" and this argument is true the "y"
--- in the root is mutated as "i" before neutral endings.
--- @return table A table containing all simple tense forms of the verb.
local function generateGroup1Forms_yer(infinitive, mutateYe)
local base = mw.ustring.sub(infinitive, 1, -4)
local vowel = mw.ustring.sub(base, -1)
local mutatedRoot
if mutateYe and vowel ~= "a" then
invalidMutationType(MUTATION_AYER_YE)
end
if vowel == "a" and mutateYe or vowel == "e" then
mutatedRoot = base .. "y"
else
mutatedRoot = base .. "i"
end
return generateGroup1Forms_(infinitive, function(root, ending)
return (isGroup1EndingSilent(ending) and mutatedRoot or root) .. ending
end, function(ending)
return mutatedRoot .. "er" .. ending
end)
end
--- Generate the simple tense forms of the given group-1 verb ending in "envoyer".
--- @param infinitive string The infinitive form of the verb.
--- @return table A table containing all simple tense forms of the verb.
local function generateGroup1Forms_envoyer(infinitive)
local mutatedRoot = mw.ustring.sub(infinitive, 1, -4) .. "i"
local mutatedInfinitiveRoot = mw.ustring.sub(infinitive, 1, -5) .. "err"
return generateGroup1Forms_(infinitive, function(root, ending)
return (isGroup1EndingSilent(ending) and mutatedRoot or root) .. ending
end, function(ending)
return mutatedInfinitiveRoot .. ending
end)
end
--- Generate the simple tense forms of the given group-1 verb.
--- @param infinitive string The infinitive form of the verb.
--- @param mutationType string The type of mutation to apply to the verb’s root instead of the default one.
--- @return table A table containing all simple tense forms of the verb.
--- @see [[Conjugaison:français/Premier groupe]] for exceptions.
function p.generateGroup1Forms(infinitive, mutationType)
if mutationType and mutationType ~= MUTATION_DOUBLE_CONS and mutationType ~= MUTATION_AYER_YE then
invalidMutationType(mutationType)
end
local last4 = mw.ustring.sub(infinitive, -4)
local last5 = mw.ustring.sub(infinitive, -5)
local consonants = eCONSer_verbs[last4] or eCONSer_verbs[last5]
if consonants then
if mutationType and mutationType ~= MUTATION_DOUBLE_CONS then
invalidMutationType(mutationType)
end
local doubleConsonant = (consonants == "l" or consonants == "t") and mutationType == MUTATION_DOUBLE_CONS
return generateGroup1Forms_eCONSer(infinitive, consonants, doubleConsonant)
end
if mutationType and mutationType == MUTATION_DOUBLE_CONS then
invalidMutationType(mutationType)
end
if mw.ustring.sub(infinitive, -7) == "envoyer" then
if mutationType then
invalidMutationType(mutationType)
end
return generateGroup1Forms_envoyer(infinitive)
end
local last3 = mw.ustring.sub(infinitive, -3)
if last3 == "yer" then
if mutationType and mutationType ~= MUTATION_AYER_YE then
invalidMutationType(mutationType)
end
return generateGroup1Forms_yer(infinitive, mutationType == MUTATION_AYER_YE)
end
if mutationType then
invalidMutationType(mutationType)
end
consonants = eacuteCONSer_verbs[last4] or eacuteCONSer_verbs[last5]
if consonants then
return generateGroup1Forms_eCONSer(infinitive, consonants)
end
if last3 == "cer" or last3 == "ger" then
return generateGroup1Forms_cer_ger(infinitive)
end
return generateGroup1Forms_(infinitive)
end
--- Generate the simple tense forms of the given group-2 verb.
--- @param infinitive string The infinitive form of the verb.
--- @param dropDiaeresis boolean Whether to drop the "ï"
--- for the 3 singular persons of indicative and imperative present.
--- @return table A table containing all simple tense forms of the verb.
--- @see [[Conjugaison:français/Deuxième groupe]] for exceptions.
function p.generateGroup2Forms(infinitive, dropDiaeresis)
local root = mw.ustring.sub(infinitive, 1, -3)
local hasDiaeresis = mw.ustring.sub(infinitive, -2) == "ïr"
if not hasDiaeresis and dropDiaeresis then
invalidMutationType(MUTATION_I)
end
local i = hasDiaeresis and "ï" or "i"
local iCirc = hasDiaeresis and "ï" or "î"
return {
infinitif = {
present = infinitive,
},
participe = {
present = root .. i .. "ssant",
passe = root .. i,
},
indicatif = {
present = {
root .. (dropDiaeresis and "is" or (i .. "s")),
root .. (dropDiaeresis and "is" or (i .. "s")),
root .. (dropDiaeresis and "it" or (i .. "t")),
root .. i .. "ssons",
root .. i .. "ssez",
root .. i .. "ssent"
},
imparfait = {
root .. i .. "ssais",
root .. i .. "ssais",
root .. i .. "ssait",
root .. i .. "ssions",
root .. i .. "ssiez",
root .. i .. "ssaient"
},
passeSimple = {
root .. i .. "s",
root .. i .. "s",
root .. i .. "t",
root .. iCirc .. "mes",
root .. iCirc .. "tes",
root .. i .. "rent"
},
futur = {
infinitive .. "ai",
infinitive .. "as",
infinitive .. "a",
infinitive .. "ons",
infinitive .. "ez",
infinitive .. "ont"
},
},
subjonctif = {
present = {
root .. i .. "sse",
root .. i .. "sses",
root .. i .. "sse",
root .. i .. "ssions",
root .. i .. "ssiez",
root .. i .. "ssent"
},
imparfait = {
root .. i .. "sse",
root .. i .. "sses",
root .. iCirc .. "t",
root .. i .. "ssions",
root .. i .. "ssiez",
root .. i .. "ssent"
}
},
conditionnel = {
present = {
infinitive .. "ais",
infinitive .. "ais",
infinitive .. "ait",
infinitive .. "ions",
infinitive .. "iez",
infinitive .. "aient"
}
},
imperatif = {
present = {
root .. (dropDiaeresis and "is" or (i .. "s")),
root .. i .. "ssons",
root .. i .. "ssez"
}
},
}
end
--- Looks for the group-3 template whose ending has the longest match with the given infinitive.
--- @param infinitive string The infinitive form of the verb.
--- @return table|nil The group-3 template that matched the best, or nil if none matched.
local function longestMatchingGroup3Template(infinitive)
local longestMatch
local longestMatchLength = 0
for _, template in pairs(p.group3Templates) do
if not template.ignore_auto then
local len = mw.ustring.len(template.ending)
if mw.ustring.find(infinitive, template.ending .. "$") and (not longestMatch or longestMatchLength < len) then
longestMatch = template
longestMatchLength = len
end
end
end
return longestMatch
end
--- Generate the simple tense forms of the given group-3 verb.
--- @param infinitive string The infinitive form of the verb.
--- @param templateVerb string|nil The verb the given one should be conjugated like.
--- @param spec VerbSpec A VerbSpec object.
--- @return table A table containing all simple tense forms of the verb.
--- @see [[Conjugaison:français/Troisième groupe]] for sub-types.
function p.generateGroup3Forms(infinitive, templateVerb, spec)
local template
if templateVerb then
if not p.group3Templates[templateVerb] then
error(mw.ustring.format('Modèle de verbe inconnu : "%s"', templateVerb))
end
template = p.group3Templates[templateVerb]
if mw.ustring.sub(infinitive, -mw.ustring.len(template.ending)) ~= template.ending then
error(mw.ustring.format('Le verbe "%s" ne se termine pas par "%s"', infinitive, template.ending))
end
elseif p.group3Templates[infinitive] then
template = p.group3Templates[infinitive]
else
template = longestMatchingGroup3Template(infinitive)
end
if not template then
error(mw.ustring.format('Aucun modèle de conjugaison trouvé pour le verbe "%s"', infinitive))
end
local root = mw.ustring.sub(infinitive, 1, -mw.ustring.len(template.ending) - 1)
local forms = {}
for mode, tenses in pairs(template.endings) do
forms[mode] = {}
-- TODO remove disabled forms
for tense, tenseEndings in pairs(tenses) do
if type(tenseEndings) == "string" then
local formSpec = spec.modeSpecs[mode].tenseSpecs[tense].formSpecs[1]
if formSpec.status == m_model.DISABLED then
forms[mode][tense] = NULL
end
forms[mode][tense] = formSpec.form or (root .. tenseEndings)
else
forms[mode][tense] = {}
for i, ending in ipairs(tenseEndings) do
local formSpec = spec.modeSpecs[mode].tenseSpecs[tense].formSpecs[i]
if formSpec.status == m_model.DISABLED then
table.insert(forms[mode][tense], NULL)
end
table.insert(forms[mode][tense], formSpec.form or (root .. ending))
end
end
end
end
return forms
end
--- Generate a compound tense using the given auxiliary verb table and past participle.
--- @param auxTable table A table containing flexions of the auxiliary verb.
--- @param pastParticiple string The past participle.
--- @param spec TenseSpec A VerbSpec object.
--- @return table A table containing the generated compound tense.
local function generateCompoundTense(auxTable, pastParticiple, spec, mode, tense)
local res = {}
for i, t in ipairs(auxTable) do
if spec[mode].status == m_model.DISABLED
or spec[mode].tenses[tense].status == m_model.DISABLED
or spec.formSpecs[i].status == m_model.DISABLED then
table.insert(res, NULL)
else
table.insert(res, t .. " " .. pastParticiple)
end
end
return res
end
--- Complete the given verb table by generating compound tenses with the given auxiliary verb table.
--- @param verbTable table A table containing flexions of the verb for all simple tenses.
--- @param spec VerbSpec A VerbSpec object.
local function completeTable(verbTable, spec)
local auxTable = spec.auxEtre and etreConj or avoirConj
verbTable.auxiliaire = auxTable.infinitif.present
if verbTable.participe.present ~= NULL then
verbTable.gerondif = {
present = verbTable.participe.present,
}
if verbTable.participe.passe ~= NULL then
verbTable.gerondif.passe = auxTable.participe.present .. " " .. verbTable.participe.passe
end
end
if verbTable.participe.passe ~= NULL then
verbTable.infinitif.passe = auxTable.infinitif.present .. " " .. verbTable.participe.passe
verbTable.indicatif.passeCompose = generateCompoundTense(auxTable.indicatif.present, verbTable.participe.passe, spec, "indicatif", "passeCompose")
verbTable.indicatif.plusQueParfait = generateCompoundTense(auxTable.indicatif.imparfait, verbTable.participe.passe, spec, "indicatif", "plusQueParfait")
verbTable.indicatif.passeAnterieur = generateCompoundTense(auxTable.indicatif.passeSimple, verbTable.participe.passe, spec, "indicatif", "passeAnterieur")
verbTable.indicatif.futurAnterieur = generateCompoundTense(auxTable.indicatif.futur, verbTable.participe.passe, spec, "indicatif", "futurAnterieur")
verbTable.subjonctif.passe = generateCompoundTense(auxTable.subjonctif.present, verbTable.participe.passe, spec, "subjonctif", "passe")
verbTable.subjonctif.plusQueParfait = generateCompoundTense(auxTable.subjonctif.imparfait, verbTable.participe.passe, spec, "subjonctif", "plusQueParfait")
verbTable.conditionnel.passe = generateCompoundTense(auxTable.conditionnel.present, verbTable.participe.passe, spec, "conditionnel", "passe")
verbTable.imperatif.passe = generateCompoundTense(auxTable.imperatif.present, verbTable.participe.passe, spec, "imperatif", "passe")
end
end
--- Generate all compound tenses and create a new Verb object from the given template.
--- @param template table A table containing the forms for simple tenses.
--- @param spec VerbSpec A VerbSpec object.
--- @return Verb The generated Verb object.
local function populateVerb(template, spec)
completeTable(template, spec)
local verb = m_model.newVerb(spec)
-- TODO populate
return verb
end
--- Retroactively apply the given spec to a template, removing all forms that are disabled in that spec.
--- @param template table A table containing the forms for simple tenses.
--- @param spec VerbSpec A VerbSpec object.
local function applySpec(template, spec)
-- TODO
end
--- Generate the simple tense forms of the given verb.
--- @param infinitive string The infinitive form of the verb.
--- @param group3 boolean If true, the verb will be classified as belonging to group 3.
--- @param mutationType string The type of mutation to apply to the verb’s root instead of the default one.
--- @param template string|nil For group-3 verbs, the verb the given one should be conjugated like.
--- @param spec VerbSpec A VerbSpec object.
--- @return (Verb, number|nil) A populated Verb object, and the verb’s group or nil if it could not be determined.
function p.generateFlexions(infinitive, group3, mutationType, template, spec)
if mutationType and template then
error("Les paramètres « mutation » et « modèle » ne peuvent pas être spécifiés en même temps.")
end
if infinitive == "être" then
if mutationType then
invalidMutationType(mutationType)
end
-- Special case to avoid unnecessary checks
return populateVerb(etreConj, spec), 3
end
if infinitive == "avoir" then
if mutationType then
invalidMutationType(mutationType)
end
-- Special case to avoid unnecessary checks
return populateVerb(avoirConj, spec), 3
end
local ending = mw.ustring.sub(infinitive, -2)
if not group3 and (ending == "ir" or ending == "ïr") then
if mutationType and mutationType ~= MUTATION_I then
invalidMutationType(mutationType)
end
local forms = p.generateGroup2Forms(infinitive, mutationType == MUTATION_I)
applySpec(forms, spec)
return populateVerb(forms, spec), 2
end
if mutationType and mutationType == MUTATION_I then
invalidMutationType(mutationType)
end
if not group3 and ending == "er" then
local forms = p.generateGroup1Forms(infinitive, mutationType)
applySpec(forms, spec)
return populateVerb(forms, spec), 1
end
if mutationType and mutationType == MUTATION_DOUBLE_CONS or mutationType == MUTATION_AYER_YE then
invalidMutationType(mutationType)
end
if template == "-" then
local template_ = createEmptyTemplate()
template_.infinitif.present = infinitive
-- TODO populate template
return populateVerb(template_, spec), 3
end
return populateVerb(p.generateGroup3Forms(infinitive, template, spec), spec), 3
end
return p