Mô đun:fr-verb
Giao diện
--[=[
Author: originally Kc kennylau; rewritten by Benwing
This implements {{fr-conj-auto}}. It uses the following submodules:
* [[Module:fr-verb/core]] (helper for generating conjugations)
* [[Module:fr-verb/pron]] (helper for generating pronunciations of conjugations)
* [[Module:fr-conj]] (for constructing the table wikicode given the forms)
* [[Module:fr-pron]] (for generating pronunciations of stems)
FIXME:
1. (DONE) Use ‿ to join reflexive pronouns.
2. montre-toi needs a schwa in it.
3. (DONE) 'etre' and 'avoir_or_etre' tables should be moved to the template call.
3a. (DONE) Make sure aux= is supported at the template level.
4. Implement 'aspirated h'; not all vowel-initial verbs have elision with
reflexive pronouns.
5. (REMOVED THE ARGUMENTS, NOT USED) Document the various override arguments.
6. Implement conjugation for -éyer.
7. (MAYBE? MAYBE NOT NECESSARY, {{fr-conj-ir}} doesn't seem to use it,
MAYBE ALREADY DONE IN THE HEADWORD CODE?) Implement sort= for sort key,
and handle most cases automatically (e.g. chérir with sort=cherir).
8. (DONE) Copy notes from {{fr-conj-ir}} to our conj["ir"].
9. (DONE) Lots of other conjugations needed. Consider generalizing existing code
so a minimal number of principal parts can be given and all the conjugation
and pronunciation derived.
10. (DONE) Convert remaining use of old templates to use {{fr-conj-auto}}.
11. (DONE) Figure out what the COMBINING flag in [[Module:fr-pron]] does and
remove it, including all calls from this module.
12. (ALREADY DONE) Support sevrer, two-stem e/è verb.
13. (DONE) Autodetect e-er verbs including eCer as well as eCler and eCrer verbs
like sevrer, and eguer/equer (if they exist). Make sure there aren't
verbs of this form that aren't e-er by looking for them in the list of
fr-conj-auto verbs that have an empty typ arg (possibly enough to look
at all fr-conj-auto verbs).
14. Check pronunciation of 'pleuvoir'. TLFi says /pløvwaʁ/, frwikt says /plœvwaʁ/.
15. (DONE) Check if -er-type conjugations of -aillir, -cueillir, braire are
correct.
16. (DONE) Fix notes for prefixed croitre/croître verbs, based on the old-style
templates.
17. (DONE) Implement impersonal and only-third verbs, including impers=
and onlythird=.
18. (DONE) Fix schwa in -ayer, -eyer pronunciation and check other uses of
ind_f() to see if they need a fut_stem_i.
19. Implement sort key in {{fr-verb}}. Should map accented letters to
unaccented letters and rearrange "se regarded" to "regarded, se" and
similarly for "s'infiltrer".
20. "se regarder" should have optional schwa in re-.
Remaining templates:
-- copier-coller: FIXME, eventually implement general support for verbs like this
--]=]
-- Table of exported functions.
local export = {}
-- Table of conjugation functions. The keys are verbal suffixes (e.g. "ir",
-- "iller") and the values are no-argument functions that apply to verbs whose
-- infinitive contains that suffix, unless the verb also matches a conjugation
-- corresponding to a longer suffix. The values take all info on the verb
-- from 'data' (see below) and set properties of 'data' to indicate the
-- verb forms and pronunciation.
local conj = {}
-- If not false, compare this module with new version of module to make
-- sure all conjugations and pronunciations are the same. If "error", issue
-- an error whenever they are different, with the contents of the error
-- indicating the different forms; otherwise, use the tracking category
-- [[Template:tracking/fr-verb/different-conj]] (see what links there to see
-- the differing verbs; there's also [[Template:tracking/fr-verb/same-conj]]
-- for the verbs that don't differ, which can be used to verify that all verbs
-- have been processed, as it takes awhile for this to happen).
local test_new_fr_verb_module = false
local m_core = require("Module:fr-verb/core")
local m_pron = require("Module:fr-verb/pron")
local m_links = require("Module:links")
local m_conj = require("Module:fr-conj")
local m_fr_pron = require("Module:fr-pron")
local lang = require("Module:languages").getByCode("fr")
local m_table = require("Module:table")
local m_utilities = require("Module:utilities")
local m_debug = require("Module:debug")
local u = mw.ustring.char
local rfind = mw.ustring.find
local rsubn = mw.ustring.gsub
local rmatch = mw.ustring.match
local rsplit = mw.text.split
local ulower = mw.ustring.lower
local uupper = mw.ustring.upper
local usub = mw.ustring.sub
local ulen = mw.ustring.len
local written_vowel = "aàâeéèêiîoôuûäëïöüÿ"
local written_cons_c = "[^%-" .. written_vowel .. "]"
local written_cons_no_y_c = "[^%-y" .. written_vowel .. "]"
local written_cons_no_cgy_c = "[^%-cgy" .. written_vowel .. "]"
local written_cons_no_cgyx_c = "[^%-cgyx" .. written_vowel .. "]"
local written_cons_no_lryx_c = "[^%-lryx" .. written_vowel .. "]"
-- 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
-- Map a function over one of the following:
-- (1) a single string (return value will be FUN(STRING))
-- (2) a list SEQ of either strings or tables of the form {"STEM", respelling="RESPELLING"}; the return value is a
-- list of calls to FUN, with one element per element in SEQ, flattened if DO_FLATMAP is specified and the return
-- value of FUN is a list; if an element of SEQ is a string, the corresponding return value will be FUN(STRING);
-- if an element of SEQ is a table of the above form, the corresponding return value will be FUN("STEM"), unless
-- third arg USE_RESPELLING is given, in which case the corresponding return value will be FUN("RESPELLING").
local function map(seq, fun, use_respelling, do_flatmap)
if type(seq) == "table" then
local ret = {}
for _, s in ipairs(seq) do
local single_stem_or_respelling
if type(s) == "table" then
if use_respelling then
assert(s.respelling)
s = s.respelling
else
s = s[1]
end
end
local retval = fun(s)
if do_flatmap and type(retval) == "table" then
for _, item in ipairs(retval) do
m_table.insertIfNot(ret, item)
end
else
m_table.insertIfNot(ret, retval)
end
end
return ret
else
-- store in separate var in case fun() has multiple retvals
local retval = fun(seq)
return retval
end
end
local function IPA(str)
return require("Module:IPA").format_IPA(nil, str)
end
local function pron(str)
return m_fr_pron.show(str, "v")
end
local function dopron(data, stem, suffix)
suffix = suffix or ""
return map(stem, function(s)
return pron((data and data.pronstem or "") .. s .. suffix)
end, "respelling", "flatmap")
end
local function setform(data, form, val, pron)
data.forms[form] = val
data.prons[form] = dopron(data, pron or val)
end
local function copyform(data, fromform, toform, newformval)
-- Need to clone objects when copying forms, otherwise we get duplicated prefixes added in case of
-- prefixed verbs.
data.forms[toform] = newformval or mw.clone(data.forms[fromform])
data.prons[toform] = mw.clone(data.prons[fromform])
end
local all_verb_props = {
"inf", "pp", "ppr",
"inf_nolink", "pp_nolink", "ppr_nolink",
"ind_p_1s", "ind_p_2s", "ind_p_3s", "ind_p_1p", "ind_p_2p", "ind_p_3p",
"ind_i_1s", "ind_i_2s", "ind_i_3s", "ind_i_1p", "ind_i_2p", "ind_i_3p",
"ind_ps_1s", "ind_ps_2s", "ind_ps_3s", "ind_ps_1p", "ind_ps_2p", "ind_ps_3p",
"ind_f_1s", "ind_f_2s", "ind_f_3s", "ind_f_1p", "ind_f_2p", "ind_f_3p",
"cond_p_1s", "cond_p_2s", "cond_p_3s", "cond_p_1p", "cond_p_2p", "cond_p_3p",
"sub_p_1s", "sub_p_2s", "sub_p_3s", "sub_p_1p", "sub_p_2p", "sub_p_3p",
"sub_pa_1s", "sub_pa_2s", "sub_pa_3s", "sub_pa_1p", "sub_pa_2p", "sub_pa_3p",
"imp_p_2s", "imp_p_1p", "imp_p_2p"
}
-- Table mapping verb suffixes to other verb suffixes that they are
-- conjugated the same as. Only required when there is a shorter-length
-- suffix of the verb that has a different conjugation (in this case,
-- 'naitre' and 'naître').
local alias = {
["connaitre"] = "aitre",
["connaître"] = "aître",
}
-- List of -ir verbs that do not take -iss- infix.
local ir_s = {
"dormir", "endormir", "redormir", "rendormir",
"partir", "départir", "repartir",
"sortir", "ressortir",
"sentir", "assentir", "consentir", "pressentir", "ressentir",
"mentir", "démentir",
"servir", "desservir", "resservir",
"repentir"
}
for _,key in ipairs(ir_s) do
ir_s[key] = true
end
local function link(term, alt)
return m_links.full_link({lang = lang, term = term, alt = alt}, "term")
end
-- Clone parent's args while also assigning nil to empty strings.
local function clone_args(frame)
local args = {}
for pname, param in pairs(frame:getParent().args) do
if param == "" then args[pname] = nil
else args[pname] = param
end
end
return args
end
local function track(page)
m_debug.track("fr-verb/" .. page)
return true
end
local function unsupported_pron(data)
if data.pron then
error("Pronunciation respelling (pron=) not supported for this verb")
end
end
-- Remove the expected ending ENDING from IPA pronunciation PRON (possibly
-- nil); error if ending not present.
local function strip_pron_ending(pron, ending)
if not pron then
return nil
end
return map(pron, function(val)
if not rfind(val, ending .. "$") then
error('Internal error: expected pronunciation "' .. val .. '" to end with "' .. ending .. '"')
end
return rsub(val, ending .. "$", "")
end)
end
-- Remove the expected ending ENDING from respelling pronunciation PRON
-- (possibly nil or a sequence); error if ending not present.
local function strip_respelling_ending(pron, ending)
if not pron then
return nil
end
return map(pron, function(val)
if not rfind(val, ending .. "$") then
error('Expected respelling "' .. val .. '" to end with "' .. ending .. '"')
end
return rsub(val, ending .. "$", "")
end)
end
-- Remove the expected beginning BEGINNING from respelling pronunciation PRON
-- (possibly nil); error if beginning not present. If SPLIT, split the value
-- of PRON on comma, strip the beginning from each component, and paste
-- together.
local function strip_respelling_beginning(pron, beginning, split)
if not pron then
return nil
end
if split then
local pronvals = rsplit(pron, ",")
local stripped_pronvals = {}
for _, pronval in ipairs(pronvals) do
table.insert(stripped_pronvals, strip_respelling_beginning(pronval, beginning))
end
return table.concat(stripped_pronvals, ",")
end
if not rfind(pron, "^" .. beginning) then
error('Expected respelling "' .. pron .. '" to begin with "' .. beginning .. '"')
end
return rsub(pron, "^" .. beginning, "")
end
-- Construct the pronunciation of all forms of an -er verb. PRONSTEM is the
-- pronunciation respelling of the stem (minus -er). If PRONSTEM_FINAL_FUT is
-- given, it is used in place of PRONSTEM for the forms without a pronounced
-- ending (i.e. 1s/2s/3s/3p present) and for the future and conditional; this
-- is used with two-stem verbs such as mener (with stems 'men' and 'mèn') and
-- céder (with stems 'céd' and 'cèd').
local function construct_er_pron(data, pronstem, pronstem_final_fut)
pronstem_final_fut = pronstem_final_fut or pronstem
pronstem = map(pronstem, function(stem) return data.pronstem .. stem end)
pronstem_final_fut = map(pronstem_final_fut, function(stem)
stem = data.pronstem .. stem
-- In pronstem_final_fut, convert é+C in the last syllable to è even if
-- the caller didn't do it. This is principally useful with pron=
-- specifications, so that e.g. pron=blésser,blèsser works.
stem = rsub(stem, "é(" .. written_cons_c .. "+)$", "è%1")
return rsub(stem, "é([gq]u)$", "è%1")
end)
local stem_final = dopron(nil, pronstem_final_fut, "e")
local stem_nonfinal = strip_pron_ending(dopron(nil, pronstem, "ez"), "e")
local stem_nonfinal_i = strip_pron_ending(dopron(nil, pronstem, "iez"), "je")
local stem_fut = strip_pron_ending(dopron(nil, pronstem_final_fut, "erez"), "e")
local stem_fut_i = strip_pron_ending(dopron(nil, pronstem_final_fut, "eriez"), "je")
return m_pron.er(data, stem_final, stem_nonfinal, stem_nonfinal_i,
stem_fut, stem_fut_i)
end
local function make_passe_simple(data, past_stem, er_past)
-- Passé simple
if er_past then
m_core.make_ind_ps_a(data, past_stem)
else
m_core.make_ind_ps(data, past_stem)
end
if past_stem ~= "—" then
local past_stem_pron = dopron(data, past_stem)
if er_past then
m_pron.ind_ps_a(data, past_stem_pron)
else
m_pron.ind_ps(data, past_stem_pron)
end
end
end
local function make_future_conditional(data, fut_stem)
-- Future/conditional
if not fut_stem then
fut_stem = rsub(data.forms.inf, "e$", "")
end
m_core.make_ind_f(data, fut_stem)
if fut_stem ~= "—" then
local fut_stem_pron = strip_pron_ending(dopron(data, fut_stem, "ez"), "e")
-- If the future stem ends in -er, the schwa is optional in -erez but
-- not in -eriez; examples are assaillir, cueillir, refaire, défaire,
-- contrefaire, méfaire (the latter four have the future pronounced
-- -fer-). Also, if the future stem ends in -Cr, there will be an
-- extra syllable inserted before -ions, -iez.
local fut_stem_pron_i = strip_pron_ending(dopron(data, fut_stem, "iez"), "je")
m_pron.ind_f(data, fut_stem_pron, fut_stem_pron_i)
end
end
-- Construct the conjugation and pronunciation of all forms of a non-er verb.
-- DATA holds the forms and pronunciations. The remaining args are stems:
--
-- * PRES_SG_STEM is used for pres indicative 1s/2s/3s and the imperative 2s;
-- * PRES_12P_STEM is used for pres indicative/imperative 1p/2p, the whole of the imperfect, the present participle,
-- and (unless PRES_SUBJ_STEM is given) the pres subjunctive 1p/2p;
-- * PRES_3P_STEM is used for pres indicative 3p and pres subjunctive 1s/2s/3s/3p;
-- * PAST_STEM is used for the past historic, the imperfect subjunctive and (unless PP is given) the past participle;
-- * FUT_STEM (which should end with 'r') is used for the future and conditional. If omitted, it is taken from the
-- infinitive minus any final -e.
-- * PP is the past participle. If omitted, if defaults to PAST_STEM.
-- * PRES_SUBJ_STEM if given overrides the present subjunctive stem.
-- * PRES_SUBJ_NONFINAL_STEM if given overrides the present subjunctive stem specifically for 1p/2p, defaulting to
-- PRES_SUBJ_STEM.
-- * ER_PRESENT, if true, specifies that the present singular follows an -er type of conjugation (endings -e, -es, -e
-- in place of -s, -s, -t). In this case, PRES_12P_STEM and PRES_3P_STEM are currently ignored. Normally, use
-- construct_non_er_conj_er_present() in place of this arg.
-- * ER_PAST, if true, specifies that the past historic and imperfect subjunctive follow an -er type of conjugation.
--
-- Any of the stem arguments may be "—" to indicate that it is missing, or a table, where each element can be a string
-- (a stem) or a table of the form {"STEM", RESPELLING="RESPELLING"}, specifying a stem to use for constructing the
-- verb forms and the corresponding respelling to use when constructing the pronunciation. This is used, for example,
-- in [[mourir]], [[courir]] and [[avoir]].
local function construct_non_er_conj(data, pres_sg_stem, pres_12p_stem, pres_3p_stem, past_stem, fut_stem, pp,
pres_subj_stem, pres_subj_nonfinal_stem, er_present, er_past)
if er_present then
m_core.make_ind_p_e(data, pres_sg_stem)
else
m_core.make_ind_p(data, pres_sg_stem, pres_12p_stem, pres_3p_stem)
end
-- Most of the time it works to add 's' to produce the 1sg (it doesn't
-- always work to use the stem directly, cf. apparais vs. apparai). But
-- this fails with stems ending in -er, e.g 'resser-' from 'resservir',
-- because the 'r' will be silent. In that case, we add 't' to produce
-- the 3sg. We can't always add 't' because that will fail with e.g.
-- 'ressen-' from 'ressentir', where the resulting '-ent' will be silent.
if pres_sg_stem ~= "—" then
if er_present then
local stem_final_pron = dopron(data, pres_sg_stem, "e")
local stem_nonfinal_pron = strip_pron_ending(dopron(data, pres_sg_stem, "ez"), "e")
local stem_nonfinal_i_pron = strip_pron_ending(dopron(data, pres_sg_stem, "iez"), "je")
m_pron.er(data, stem_final_pron, stem_nonfinal_pron,
stem_nonfinal_i_pron)
else
local pres_sg_stem_pron = map(pres_sg_stem, function(stem)
return rmatch(data.pronstem .. stem, "er$") and dopron(data, stem, "t") or dopron(data, stem, "s")
end, "respelling", "flatmap")
local pres_12p_stem_pron = strip_pron_ending(dopron(data, pres_12p_stem, "ez"), "e")
local pres_3p_stem_pron = dopron(data, pres_3p_stem, "e")
local pre_j_stem_pron = strip_pron_ending(dopron(data, pres_12p_stem, "iez"), "je")
m_pron.ind_p(data, pres_sg_stem_pron, pres_12p_stem_pron, pres_3p_stem_pron, pre_j_stem_pron)
end
end
make_passe_simple(data, past_stem, er_past)
make_future_conditional(data, fut_stem)
if pp then
data.forms.pp = pp
if pp ~= "—" then
data.prons.pp = dopron(data, pp)
end
end
if pres_subj_stem then
m_core.make_sub_p(data, pres_subj_stem, pres_subj_nonfinal_stem)
if pres_subj_stem ~= "—" then
local pres_subj_pron1 = dopron(data, pres_subj_stem, "e")
local pres_subj_pron2 = strip_pron_ending(dopron(data, pres_subj_nonfinal_stem or pres_subj_stem, "iez"), "je")
m_pron.sub_p(data, pres_subj_pron1, pres_subj_pron2)
end
end
end
-- Construct the conjugation and pronunciation of all forms of a non-er verb
-- with an -er type of present (singular -e, -es, -e). DATA holds the forms
-- and pronunciations. The remaining args are stems:
--
-- * PRES_STEM is used for the whole of the present as well as the imperfect
-- indicative;
-- * PAST_STEM is used for the past historic and past participle;
-- * FUT_STEM (which should end with 'r') is used for the future and
-- conditional. If omitted, it is taken from the infinitive minus final -e.
-- * PP is the past participle. If omitted, if defaults to PAST_STEM.
-- * PRES_SUBJ_STEM if given overrides the present subjunctive stem.
-- * PRES_SUBJ_NONFINAL_STEM if given overrides the present subjunctive stem
-- specifically for 1p/2p, defaulting to PRES_SUBJ_STEM.
--
-- Any of the stem arguments may actually be a table of stems.
local function construct_non_er_conj_er_present(data, pres_stem, past_stem,
fut_stem, pp, pres_subj_stem, pres_subj_nonfinal_stem)
-- Specify the pp explicitly, explicitly defaulting to the past_stem,
-- else it will end in -é.
construct_non_er_conj(data, pres_stem, nil, nil, past_stem, fut_stem,
pp or past_stem, pres_subj_stem, pres_subj_nonfinal_stem, "er-present")
end
local function impersonal_verb(data)
for _, k in ipairs(all_verb_props) do
if rmatch(k, "[12]") or rmatch(k, "3p") then
data.forms[k] = "—"
end
end
end
local function only_third_verb(data)
for _, k in ipairs(all_verb_props) do
if rmatch(k, "[12]") then
data.forms[k] = "—"
end
end
end
conj["er"] = function(data)
if data.stem == "all" then
data.stem = ""
data.pronstem = strip_respelling_ending(data.pron, "aller") or data.stem
conj["irreg-aller"](data)
data.forms.inf = "aller"
data.conjcat = "aller"
data.cat = "suppletive"
else
m_core.make_ind_p_e(data, "")
construct_er_pron(data, "")
data.group = 1
data.conjcat = "-er"
end
end
conj["cer"] = function(data)
m_core.make_ind_p_e(data, "c", "ç")
construct_er_pron(data, "c")
data.group = 1
data.conjcat = "-cer"
end
conj["ger"] = function(data)
m_core.make_ind_p_e(data, "g", "ge")
construct_er_pron(data, "g")
data.group = 1
data.conjcat = "-ger"
end
conj["ayer"] = function(data)
m_core.make_ind_p_e(data, {"ay", "ai"}, "ay", "ay")
construct_er_pron(data, "ay", {"ay", "ai"})
data.group = 1
data.conjcat = "-ayer"
end
conj["eyer"] = function(data)
m_core.make_ind_p_e(data, "ey")
construct_er_pron(data, "ey", "ey")
data.group = 1
data.conjcat = "-eyer"
end
conj["yer"] = function(data)
m_core.make_ind_p_e(data, "i", "y", "y")
construct_er_pron(data, "y", "i")
data.group = 1
data.conjcat = "-yer"
end
conj["xxer"] = function(data)
local newstem, consonant = rmatch(data.stem, "^(.*)e(" .. written_cons_c .. ")$")
if not consonant then
error("Stem '" .. data.stem .. "' should end with -e- + consonant")
end
data.forms.inf = "e" .. consonant .. "er" -- not xxer
local origstem = data.stem
data.stem = newstem
data.pronstem = strip_respelling_ending(data.pron, data.forms.inf) or data.stem
if rfind(origstem, "jet$") or rfind(origstem, "appel$") then
m_core.make_ind_p_e(data, "e" .. consonant .. consonant,
"e" .. consonant, "e" .. consonant)
else
m_core.make_ind_p_e(data, {"e" .. consonant .. consonant, "è" .. consonant},
"e" .. consonant, "e" .. consonant)
end
construct_er_pron(data, "e" .. consonant, "e" .. consonant .. consonant)
data.group = 1
data.conjcat = "-xxer"
end
conj["e-er"] = function(data)
local newstem, consonant = rmatch(data.stem, "^(.*)e(" .. written_cons_c .. "+)$")
if not consonant then
error("Stem '" .. data.stem .. "' should end with -e- + one or more consonants")
end
local stem = 'e' .. consonant
local stem2 = 'è' .. consonant
data.forms.inf = stem .. "er" -- not e-er
local origstem = data.stem
data.stem = newstem
data.pronstem = strip_respelling_ending(data.pron, data.forms.inf) or data.stem
m_core.make_ind_p_e(data, stem2, stem, stem)
construct_er_pron(data, stem, stem2)
data.group = 1
data.conjcat = "-e-er"
end
conj["ecer"] = function(data)
m_core.make_ind_p_e(data, "èc", "eç", "ec")
construct_er_pron(data, "ec", "èc")
data.group = 1
data.conjcat = "-e-er"
end
conj["eger"] = function(data)
m_core.make_ind_p_e(data, "èg", "ege", "eg")
construct_er_pron(data, "eg", "èg")
data.group = 1
data.conjcat = "-e-er"
end
conj["é-er"] = function(data)
local newstem, consonant = rmatch(data.stem, "^(.*)é(" .. written_cons_c .. "+)$")
if not consonant then
newstem, consonant = rmatch(data.stem, "^(.*)é([gq]u)$")
end
if not consonant then
error("Stem '" .. data.stem .. "' should end with -e- + one or more consonants")
end
local stem = 'é' .. consonant
local stem2 = 'è' .. consonant
data.forms.inf = stem .. "er" -- not é-er
local origstem = data.stem
data.stem = newstem
data.pronstem = strip_respelling_ending(data.pron, data.forms.inf) or data.stem
m_core.make_ind_p_e(data, stem2, stem, stem)
m_core.make_ind_f(data, {stem2 .. "er", stem .. "er"})
construct_er_pron(data, stem, stem2)
data.group = 1
data.conjcat = "-é-er"
end
conj["écer"] = function(data)
m_core.make_ind_p_e(data, "èc", "éç", "éc")
m_core.make_ind_f(data, {"écer", "ècer"})
construct_er_pron(data, "éc", "èc")
data.group = 1
data.conjcat = "-é-er"
end
conj["éger"] = function(data)
m_core.make_ind_p_e(data, "èg", "ége", "ég")
m_core.make_ind_f(data, {"éger", "èger"})
construct_er_pron(data, "ég", "èg")
data.group = 1
data.conjcat = "-é-er"
end
conj["ir-s"] = function(data)
local ending = usub(data.stem, -1, -1)
data.stem = usub(data.stem, 1, -2)
data.pronstem = strip_respelling_ending(data.pron, ending .. "ir") or data.stem
data.forms.inf = ending .. "ir"
construct_non_er_conj(data, "", ending, ending, ending .. "i")
data.conjcat = "-ir"
end
conj["ir-reg"] = function(data)
-- if ir-reg explicitly used in type argument (e.g. ressortir), inf will
-- be ir-reg by default with messed-up future
data.forms.inf = "ir"
construct_non_er_conj(data, "i", "iss", "iss", "i")
data.group = 2
data.conjcat = "-ir"
end
conj["ir"] = function(data)
if ir_s[data.stem.."ir"] then
conj["ir-s"](data)
else
conj["ir-reg"](data)
end
end
conj["ïr"] = function(data)
construct_non_er_conj(data, "ï", "ïss", "ïss", "ï")
data.group = 2
data.conjcat = "-ïr"
end
conj["haïr"] = function(data)
construct_non_er_conj(data, "hai", "haïss", "haïss", "haï")
data.conjcat = "haïr"
end
conj["ouïr"] = function(data)
construct_non_er_conj(data, {"ouï", "oi"}, {"ouïss", {"oy", respelling="oill"}},
{"ouïss", "oi"}, "ouï", {"ouïr", "oir", "orr"})
data.conjcat = "ouïr"
end
conj["asseoir"] = function(data)
construct_non_er_conj(data, {"assoi", "assied"}, {"assoy", "assey"},
{"assoi", "assey"}, "assi", {"assoir", "assiér"}, "assis")
data.conjcat = "seoir"
end
conj["surseoir"] = function(data)
-- Pronunciation in future/cond as if written sursoir- not surseoir-
construct_non_er_conj(data, "sursoi", "sursoy", "sursoi", "sursi", {{"surseoir", respelling="sursoir"}},
"sursis")
data.conjcat = "seoir"
end
conj["seoir"] = function(data)
construct_non_er_conj(data, "sied", "sey", "sié", "—", "siér")
only_third_verb(data)
setform(data, "ppr", {"séant", "seyant"})
data.conjcat = "seoir"
data.cat = "defective"
end
conj["bouillir"] = function(data)
construct_non_er_conj(data, "bou", "bouill", "bouill", "bouilli")
data.conjcat = "bouillir"
end
conj["enir"] = function(data)
construct_non_er_conj(data, "ien", "en", "ienn", "in", {{"iendr", respelling="iaindr"}}, "enu")
if usub(data.stem,-1) == "t" then
data.conjcat = "tenir"
else
data.conjcat = "venir"
end
end
local function ouvrir_ffrir(data, rir_prefix)
data.stem = data.stem .. rir_prefix
data.pronstem = data.pronstem .. rir_prefix
data.forms.inf = "rir"
construct_non_er_conj_er_present(data, "r", "ri", nil, "ert")
end
conj["ouvrir"] = function(data)
ouvrir_ffrir(data, "ouv")
end
conj["ffrir"] = function(data)
ouvrir_ffrir(data, "ff")
end
conj["quérir"] = function(data)
construct_non_er_conj(data, "quier", "quér", "quièr", "qui", "querr", "quis")
end
conj["aillir"] = function(data)
construct_non_er_conj_er_present(data, "aill", "ailli", {"aillir", "ailler"})
end
conj["chauvir"] = function(data)
construct_non_er_conj(data, "chauvi", {"chauv", "chauviss"},
{"chauv", "chauviss"}, "chauvi")
data.group = {2, 3}
end
conj["choir"] = function(data)
construct_non_er_conj(data, "choi", "choy", "choi", "chu",
data.stem == "é" and "choir" or {"choir", "cherr"})
m_core.clear_imp(data)
data.forms.ppr = "—"
if data.stem == "" then
-- FIXME! frwikt says 1p 2p of pres indic is rare, and likewise
-- all of the pres subj.
m_core.make_ind_i(data, "—")
-- FIXME! frwikt says future in cherr- is archaic, and archaic
-- conditional forms in cherr- exist as well.
m_core.make_cond_p(data, "choir")
m_pron.cond_p(data, dopron(data, "choir"))
m_core.make_sub_p(data, "—")
-- FIXME! frwikt does not say subjunctive past is missing other than
-- 3s.
m_core.make_sub_pa(data, "—")
data.forms.sub_pa_3s = "chût"
elseif data.stem == "dé" then
m_core.make_ind_i(data, "—")
-- FIXME! frwikt does not indicate 'chet' as an alternative. Based on
-- échoir, we'd expect 'chettent' as alternative as well.
setform(data, "ind_p_3s", {"choit", "chet"})
-- FIXME! frwikt lists rare ppr déchoyant.
elseif data.stem == "é" then
only_third_verb(data)
setform(data, "ind_p_3s", {"choit", "chet"})
-- FIXME! frwikt gives both échettent and échéent as alternatives,
-- but gives the pronunciation only of the first.
setform(data, "ind_p_3p", {"choient", "chettent"})
setform(data, "ppr", "chéant")
end
data.cat = "defective"
end
conj["cueillir"] = function(data)
construct_non_er_conj_er_present(data, "cueill", "cueilli", {"cueillir", "cueiller"})
end
conj["courir"] = function(data)
construct_non_er_conj(data, "cour", "cour", "cour", "couru", {{"courr", respelling="cour_r"}})
end
conj["falloir"] = function(data)
construct_non_er_conj(data, "fau", "fall", "fall", "fallu", "faudr", nil, "faill")
impersonal_verb(data)
data.cat = {"defective", "impersonal"}
end
conj["faillir"] = function(data)
if data.stem == "" then
construct_non_er_conj(data, "fau", "faill", "faill", "failli", {"faudr", "faillir"})
data.forms.ind_p_1s = "faux"
data.forms.ind_p_2s = "faux"
m_core.clear_imp(data)
data.cat = "defective"
else
-- frwikt doesn't include forms like -faillerai
construct_non_er_conj_er_present(data, "faill", "failli", "faillir")
end
end
conj["férir"] = function(data)
construct_non_er_conj(data, "—", "—", "—", "—", "—", "féru")
data.cat = "defective"
end
conj["fuir"] = function(data)
construct_non_er_conj(data, "fui", "fuy", "fui", "fui")
end
conj["gésir"] = function(data)
construct_non_er_conj(data, "gi", "gis", "gis", "—", "—", "—", "—")
data.forms.ind_p_3s = "gît"
m_core.clear_imp(data)
data.cat = "defective"
end
conj["re"] = function(data)
construct_non_er_conj(data, "", "", "", "i", nil, "u")
data.forms.ind_p_3s = ""
data.irregular = "no"
end
conj["cre"] = function(data)
construct_non_er_conj(data, "c", "qu", "qu", "qui", nil, "cu")
end
conj["pre"] = function(data)
construct_non_er_conj(data, "p", "p", "p", "pi", nil, "pu")
end
conj["crire"] = function(data)
construct_non_er_conj(data, "cri", "criv", "criv", "crivi", nil, "crit")
end
conj["rire"] = function(data)
construct_non_er_conj(data, "ri", "ri", "ri", "ri")
end
conj["uire"] = function(data)
construct_non_er_conj(data, "ui", "uis", "uis", "uisi", nil, "uit")
end
conj["nuire"] = function(data)
-- nuire has different pp from other -uire verbs
construct_non_er_conj(data, "nui", "nuis", "nuis", "nuisi", nil, "nui")
end
conj["aitre"] = function(data)
-- future stem must be nil here because we are called from conj["aître"]
construct_non_er_conj(data, "ai", "aiss", "aiss", "u", nil, "u")
end
conj["aître"] = function(data)
conj["aitre"](data)
data.forms.ind_p_3s = "aît"
end
conj["oître"] = function(data)
construct_non_er_conj(data, {{"oi", respelling="ai"}}, {{"oiss", respelling="aiss"}},
{{"oiss", respelling="aiss"}}, "u", {{"oîtr", respelling="aitr"}})
end
conj["indre"] = function(data)
construct_non_er_conj(data, "in", "ign", "ign", "igni", nil, "int")
end
conj["clure"] = function(data)
local pp
if data.stem == "in" or data.stem == "trans" or data.stem == "oc" then
pp = "clus"
end
construct_non_er_conj(data, "clu", "clu", "clu", "clu", nil, pp)
end
conj["raire"] = function(data) --braire, traire
construct_non_er_conj(data, "rai", "ray", "rai", "ray", nil, "rait", nil, nil, nil, "er past")
end
conj["clore"] = function(data)
construct_non_er_conj(data, "clo", "clos", "clos", "—", nil, "clos")
m_core.make_ind_i(data, "—") -- no imperfect
data.forms.ind_p_3s = "clôt"
data.cat = "defective"
end
conj["confire"] = function(data)
construct_non_er_conj(data, "confi", "confis", "confis", "confi", nil, "confit")
end
conj["suffire"] = function(data)
construct_non_er_conj(data, "suffi", "suffis", "suffis", "suffi")
end
conj["coudre"] = function(data)
construct_non_er_conj(data, "coud", "cous", "cous", "cousi", nil, "cousu")
end
conj["croire"] = function(data)
construct_non_er_conj(data, "croi", "croy", "croi", "cru")
end
conj["croitre"] = function(data)
if data.stem == "" then
construct_non_er_conj(data, "croî", "croiss", "croiss", "crû")
data.forms.ind_ps_1p = "crûmes"
data.forms.ind_ps_2p = "crûtes"
data.forms.sub_pa_3s = "crût"
else
construct_non_er_conj(data, "croi", "croiss", "croiss", "cru")
end
end
conj["croître"] = function(data)
if data.stem == "" or data.stem == "re" then
construct_non_er_conj(data, "croî", "croiss", "croiss", "crû")
else
construct_non_er_conj(data, "croi", "croiss", "croiss", "cru")
data.forms.ind_p_3s = "croît"
end
data.forms.ind_ps_1p = "crûmes"
data.forms.ind_ps_2p = "crûtes"
data.forms.sub_pa_3s = "crût"
end
conj["foutre"] = function(data)
construct_non_er_conj(data, "fou", "fout", "fout", "fouti", nil,
"foutu")
end
conj["soudre"] = function(data)
construct_non_er_conj(data, "sou", "solv", "solv", "solu", nil, "sous")
m_core.make_sub_pa(data, "—")
data.cat = "defective"
end
conj["résoudre"] = function(data)
construct_non_er_conj(data, "résou", "résolv", "résolv", "résolu")
end
conj["voir"] = function(data)
construct_non_er_conj(data, "voi", "voy", "voi", "vi", "verr", "vu")
end
conj["prévoir"] = function(data)
construct_non_er_conj(data, "prévoi", "prévoy", "prévoi", "prévi", nil,
"prévu")
end
conj["cevoir"] = function(data)
construct_non_er_conj(data, "çoi", "cev", "çoiv", "çu", "cevr")
end
conj["battre"] = function(data)
construct_non_er_conj(data, "bat", "batt", "batt", "batti", nil, "battu")
end
conj["circoncire"] = function(data)
construct_non_er_conj(data, "circonci", "circoncis", "circoncis",
"circonci", nil, "circoncis")
end
conj["lire"] = function(data)
construct_non_er_conj(data, "li", "lis", "lis", "lu")
end
conj["luire"] = function(data)
construct_non_er_conj(data, "lui", "luis", "luis", {"lui", "luisi"},
nil, "lui")
m_core.make_sub_pa(data, "luisi")
m_pron.sub_pa(data, dopron(data, "luisi"))
setform(data, "ind_ps_3s", "luit")
end
conj["maudire"] = function(data)
construct_non_er_conj(data, "maudi", "maudiss", "maudiss", "maudi",
nil, "maudit")
end
conj["mettre"] = function(data)
construct_non_er_conj(data, "met", "mett", "mett", "mi", nil, "mis")
end
conj["moudre"] = function(data)
construct_non_er_conj(data, "moud", "moul", "moul", "moulu")
end
conj["mouvoir"] = function(data)
construct_non_er_conj(data, "meu", "mouv", "meuv", "mu", "mouvr")
if data.stem == "" then
data.forms.pp = "mû"
end
end
conj["paitre"] = function(data)
construct_non_er_conj(data, "pai", "paiss", "paiss", "pu")
--data.cat = "defective" -- FIXME: Not true with pu as past participle?
end
conj["paître"] = function(data)
conj["paitre"](data)
data.forms.ind_p_3s = "paît"
end
conj["pleuvoir"] = function(data)
construct_non_er_conj(data, "pleu", "pleuv", "pleuv", "plu", "pleuvr")
if data.stem == "re" then
impersonal_verb(data)
data.cat = {"defective", "impersonal"}
else
only_third_verb(data)
data.cat = "defective"
end
end
conj["pourvoir"] = function(data)
construct_non_er_conj(data, "pourvoi", "pourvoy", "pourvoi", "pourvu")
end
conj["prendre"] = function(data)
construct_non_er_conj(data, "prend", "pren", "prenn", "pri", nil, "pris")
end
conj["faire"] = function(data)
construct_non_er_conj(data, "fai", {{"fais", respelling="fes"}}, {{"fais", respelling="fes"}}, "fi", "fer", "fait",
"fass")
setform(data, "ind_p_2p", "faites")
setform(data, "ind_p_3p", "font")
copyform(data, "ind_p_2p", "imp_p_2p")
end
conj["boire"] = function(data)
construct_non_er_conj(data, "boi", "buv", "boiv", "bu")
end
conj["devoir"] = function(data)
construct_non_er_conj(data, "doi", "dev", "doiv", "du", "devr")
if data.stem == "" then
data.forms.pp = "dû"
end
end
conj["avoir"] = function(data)
-- Need to specify a value for singular present to get proper pronunciation for present tense,
-- even though we override it.
construct_non_er_conj(data, "a", "av", "—", {{"eu", respelling="u"}}, {"aur", {"aur", respelling="ôr"}}, nil,
"ai", "ay")
setform(data, "ind_p_1s", "ai")
setform(data, "ind_p_2s", "as", "a")
setform(data, "ind_p_3s", "a")
setform(data, "ind_p_3p", "ont")
setform(data, "ppr", "ayant")
data.forms.sub_p_3s = "ait"
setform(data, "sub_p_1p", "ayons")
setform(data, "sub_p_2p", "ayez")
copyform(data, "sub_p_1s", "imp_p_2s")
copyform(data, "sub_p_1p", "imp_p_1p")
copyform(data, "sub_p_2p", "imp_p_2p")
end
conj["être"] = function(data)
construct_non_er_conj(data, "e", "ét", "—", "fu", "ser", "été", "soi", "soy")
setform(data, "ind_p_1s", "suis")
setform(data, "ind_p_2s", "es")
setform(data, "ind_p_3s", "est")
setform(data, "ind_p_1p", "sommes")
setform(data, "ind_p_2p", "êtes")
setform(data, "ind_p_3p", "sont")
setform(data, "sub_p_1s", "sois")
copyform(data, "sub_p_1s", "sub_p_2s")
copyform(data, "sub_p_1s", "sub_p_3s", "soit")
setform(data, "sub_p_1p", "soyons")
setform(data, "sub_p_2p", "soyez")
copyform(data, "sub_p_2s", "imp_p_2s")
copyform(data, "sub_p_1p", "imp_p_1p")
copyform(data, "sub_p_2p", "imp_p_2p")
end
conj["estre"] = function(data)
conj["être"](data)
for key,val in pairs(data.forms) do
data.forms[key] = map(val, function(form)
form = rsub(form, "[éê]", "es")
form = rsub(form, "û", "us")
form = rsub(form, "ai", "oi")
return form
end)
end
data.forms.ind_ps_1p = "fumes"
data.forms.sub_pa_3s = "fust"
data.forms.pp = "esté"
end
conj["naitre"] = function(data)
-- future stem must be nil here because we are called from conj["naître"]
construct_non_er_conj(data, "nai", "naiss", "naiss", "naqui", nil, "né")
end
conj["naître"] = function(data)
conj["naitre"](data)
data.forms.ind_p_3s = "naît"
end
conj["envoyer"] = function(data)
data.notes = "This verb is one of a few verbs that conjugate like " .. link("noyer") .. ", except in the future and conditional, where they conjugate like " .. link("voir") .. "."
m_core.make_ind_p_e(data, "envoi", "envoy", "envoy")
construct_er_pron(data, "envoy", "envoi")
make_future_conditional(data, "enverr")
data.group = 1
data.irregular = "yes"
end
conj["irreg-aller"] = function(data)
data.notes = "The verb ''{stem}aller'' has a unique and highly irregular conjugation. The second-person singular imperative ''[[va]]'' additionally combines with ''[[y]]'' to form ''[[vas-y]]'' instead of the expected ''va-y''."
-- Need to specify a value for singular present to get proper pronunciation for present tense,
-- even though we override it.
construct_non_er_conj(data, "va", "all", "—", "all", "ir", "allé", "aill", "all", nil, "er past")
setform(data, "ind_p_1s", "vais")
-- TLFi says /va/ even for 2s, not /vɑ/.
setform(data, "ind_p_2s", "vas", "va")
setform(data, "ind_p_3s", "va")
setform(data, "ind_p_3p", "vont")
copyform(data, "ind_p_3s", "imp_p_2s")
end
conj["dire"] = function(data)
construct_non_er_conj(data, "di", "dis", "dis", "di", nil, "dit")
if data.stem == "" or data.stem == "re" then
setform(data, "ind_p_2p", "dites")
copyform(data, "ind_p_2p", "imp_p_2p")
else
data.notes = "This verb is one of a group of " .. link("-re") .. " verbs all ending in ''-dire''. "
data.notes = data.notes .. "They are conjugated exactly like " .. link("dire") .. ", "
data.notes = data.notes .. "but with a different second-person plural indicative present (that is, like " .. link("confire") .. "). "
data.notes = data.notes .. "Members of this group include " .. link(data.stem == "contre" and "dédire" or "contredire") .. " and "
data.notes = data.notes .. link(data.stem == "inter" and "dédire" or "interdire") .. "."
end
end
conj["vivre"] = function(data)
construct_non_er_conj(data, "vi", "viv", "viv", "vécu")
end
conj["mourir"] = function(data)
construct_non_er_conj(data, "meur", "mour", "meur", "mouru", {{"mourr", respelling="mour_r"}}, "mort")
end
conj["savoir"] = function(data)
construct_non_er_conj(data, "sai", "sav", "sav", "su", {"saur", {"saur", respelling="sôr"}}, nil, "sach")
copyform(data, "sub_p_1s", "imp_p_2s") -- sache
setform(data, "imp_p_1p", "sachons")
setform(data, "imp_p_2p", "sachez")
setform(data, "ppr", "sachant")
end
conj["pouvoir"] = function(data)
construct_non_er_conj(data, "peu", "pouv", "peuv", "pu", "pourr", nil, "puiss")
data.forms.ind_p_1s = "peux"
data.forms.ind_p_2s = "peux"
m_core.clear_imp(data)
data.cat = "defective"
end
conj["ouloir"] = function(data) -- vouloir, revouloir, douloir
construct_non_er_conj(data, "eu", "oul", "eul", "oulu", "oudr", nil, "euill", "oul")
data.forms.ind_p_1s = "eux"
data.forms.ind_p_2s = "eux"
if data.stem == "v" then -- irregular imperative for vouloir
setform(data, "imp_p_2s", {"eux", "euille"})
setform(data, "imp_p_1p", {"oulons", "euillons"})
setform(data, "imp_p_2p", {"oulez", "euillez"})
else
data.forms.imp_p_2s = "eux"
end
end
conj["bruire"] = function(data)
construct_non_er_conj(data, "bruis", "bruiss", "bruiss", "brui")
end
conj["ensuivre"] = function(data)
data.notes = "This verb is [[defective]], and is only used in the "
.. "infinitive and the third-person singular and plural forms."
construct_non_er_conj(data, "ensui", "ensuiv", "ensuiv", "ensuivi")
only_third_verb(data)
data.cat = "defective"
end
conj["frire"] = function(data)
data.notes = "This verb is defective and it is not conjugated in certain"
.. " tenses and plural persons. Using " .. link("faire") ..
" '''frire''' is recommended."
construct_non_er_conj(data, "fri", "fris", "fris", "fri", nil, "frit")
-- clear subjunctive present and past
m_core.make_sub_pa(data, "—")
m_core.make_sub_p(data, "—")
-- clear plural forms
for _, k in ipairs(all_verb_props) do
if rmatch(k, "[123]p") then
data.forms[k] = "—"
end
end
data.cat = "defective"
end
conj["plaire"] = function(data)
data.notes = link("plaire") .. " and its derived verbs conjugate like "
.. link("taire") .. ", except that the third person singular of the "
.. "present indicative may take a circumflex on the 'i'."
construct_non_er_conj(data, "plai", "plais", "plais", "plu")
data.forms.ind_p_3s = {"plaît", "plait"}
end
conj["suivre"] = function(data)
construct_non_er_conj(data, "sui", "suiv", "suiv", "suivi")
end
conj["taire"] = function(data)
construct_non_er_conj(data, "tai", "tais", "tais", "tu")
end
conj["valoir"] = function(data)
construct_non_er_conj(data, "vau", "val", "val", "valu", "vaudr", nil,
data.stem == "pré" and "val" or "vaill", "val")
data.forms.ind_p_1s = "vaux"
data.forms.ind_p_2s = "vaux"
m_core.clear_imp(data)
data.cat = "defective"
end
conj["vêtir"] = function(data)
data.notes = "This is an irregular verb of the third conjugation. "
.. "Unlike regular -ir verbs, this conjugation does not include "
.. "the infix " .. link("-iss-") .. "."
construct_non_er_conj(data, "vêt", "vêt", "vêt", "vêti", nil, "vêtu")
end
local function call_conj(data, conjtyp, pronstem)
data.pronstem = pronstem or strip_respelling_ending(data.pron, data.forms.inf) or data.stem
conj[conjtyp](data)
end
-- Conjugate the verb according to the TYPE, which is either explicitly
-- specified by the caller of {{fr-conj-auto}} or derived automatically.
local function conjugate(data, typ)
data.forms.inf = typ
local future_stem = rsub(data.forms.inf, "e$", "")
m_core.make_ind_f(data, future_stem)
if typ == "xxer" or typ == "e-er" or typ == "é-er" then
call_conj(data, typ, strip_respelling_ending(data.pron, "er"))
return
end
if alias[typ] then
data.stem = data.stem .. rsub(typ, alias[typ] .. "$", "")
data.forms.inf = alias[typ]
call_conj(data, alias[typ])
elseif conj[typ] then
call_conj(data, typ)
elseif typ ~= "" then
error('The type "' .. typ .. '" is not recognized')
end
end
-- Autodetect the conjugation type and extract the preceding stem. We have
-- special handling for verbs in -éCer and -eCer for C = consonant. Otherwise,
-- the conjugation type is the longest suffix of the infinitive for which
-- there's an entry in conj[], and stem is the preceding text. (As an
-- exception, certain longer suffixes are mapped to the conjugation type of
-- shorter suffixes using alias[]. An example is 'connaitre', which conjugates
-- like '-aitre' verbs rather than like 'naitre' and its derivatives.) Note
-- that for many irregular verbs, the "stem" is actually the prefix, or empty
-- if the verb has no prefix.
local function auto(pagename, argstype, argsstem)
local stem
if argstype then
local tostrip
if argstype == "xxer" or argstype == "é-er" or argstype == "e-er" then
tostrip = "er"
else
tostrip = argstype
end
stem = argsstem or strip_respelling_ending(pagename, tostrip)
return stem, argstype
end
-- check for espérer, céder, etc.; exclude y so as not to be confused by [[acétyler]], [[déméthyler]];
-- exclude -écer, -éger, -éyer
stem = rmatch(pagename, "^(.*é" .. written_cons_no_y_c .. "*" .. written_cons_no_cgy_c .. ")er$")
if stem then
return stem, "é-er"
end
-- check for alléguer, disséquer, etc.
stem = rmatch(pagename, "^(.*é[gq]u)er$")
if stem then
return stem, "é-er"
end
-- check for acheter, etc.; exclude -exer, -ecer, -eger, -eyer
stem = rmatch(pagename, "^(.*e" .. written_cons_no_cgyx_c .. ")er$")
if stem then
return stem, "e-er"
end
-- check for sevrer, etc.; exclude -ller, -rrer, -rler (perler)
stem = rmatch(pagename, "^(.*e" .. written_cons_no_lryx_c .. "[lr])er$")
if stem then
return stem, "e-er"
end
stem = ""
local typ = pagename
while typ ~= "" do
if conj[typ] then break end
if alias[typ] then
stem = stem .. rsub(typ,alias[typ].."$","")
typ = alias[typ]
break
end
stem = stem .. rsub(typ,"^(.).*$","%1")
typ = rsub(typ,"^.","")
end
if typ == "" then
return "",""
end
return stem,typ
end
-- Append elements of TAB2 to the elements of TAB1, converting them to lists
-- as necessary.
local function append_tables(tab1, tab2)
for k, values in pairs(tab2) do
local t1 = tab1[k]
if type(t1) ~= "table" then
t1 = {t1}
end
if type(values) ~= "table" then
values = {values}
end
for _, val in ipairs(values) do
m_table.insertIfNot(t1, val)
end
tab1[k] = t1
end
end
local verb_prefix_to_type = {
{"les y en ", "lesyen"},
{"les en ", "lesen"},
{"s[’']en ", "reflen"},
{"se le ", "reflle"},
{"se la ", "reflla"},
{"se l[’']", "refll"},
{"se les y ", "refllesy"},
{"les y ", "lesy"},
{"se les ", "reflles"},
{"les ", "les"},
{"se l[’']y ", "reflly"},
{"l[’']y ", "l_y"},
{"l[’']en ", "l_en"},
{"l[’']", "l"},
{"le ", "le"},
{"la ", "la"},
{"s[’']y en ", "reflyen"},
{"y en ", "yen"},
{"en ", "en"},
{"s[’']y ", "refly"},
{"y ", "y"},
{"s[’']", "refl"},
{"se ", "refl"},
}
-- This is meant to be invoked by the module itself, or possibly by a
-- different version of the module (for comparing changes to see whether
-- they have an effect on conjugations or pronunciations).
function export.do_generate_forms(args)
local data
local stem = args[1] or ""
local typ = args[2] or ""
local argspron = args.pron
local prefix, preftype
local pagename_from_args
local PAGENAME = mw.title.getCurrentTitle().text
if stem == "" and typ == "" then
pagename_from_args = args.pagename or PAGENAME
else
error("Specifying 1= or 2= not supported any more; use type=, stem= and/or pagename=")
end
local argstype = args.type
if argstype == "" then argstype = nil; end
local argsstem = args.stem
if argsstem == "" then argsstem = nil; end
stem, typ = auto(pagename_from_args, argstype, argsstem)
-- expand + and [...] notations
if argspron then
local pronvals = rsplit(argspron, ",")
local expanded_pronvals = {}
for _, pronval in ipairs(pronvals) do
table.insert(expanded_pronvals, m_fr_pron.canonicalize_pron(pronval, pagename_from_args))
end
argspron = table.concat(expanded_pronvals, ",")
end
-- autodetect prefixed verbs
for _, pref_and_type in ipairs(verb_prefix_to_type) do
local pref, prefty = pref_and_type[1], pref_and_type[2]
if rfind(stem, "^" .. pref) then
stem = rsub(stem, "^" .. pref, "")
argspron = strip_respelling_beginning(argspron, pref, "split")
prefix = pref
preftype = prefty
break
end
end
local pronargs = argspron and rsplit(argspron, ",") or {false}
local all_forms, all_prons
for i = 1, #pronargs do
local pronarg = pronargs[i]
if pronarg == false then pronarg = nil end
data = {
prefix = prefix,
preftype = preftype,
stem = stem,
aux = "avoir",
pron = pronarg,
forms = {},
prons = {},
cat = {},
group = 3
}
conjugate(data, typ)
if type(data.cat) ~= "table" then
data.cat = {data.cat}
end
if i == 1 then
all_forms = data.forms
all_prons = data.prons
else
append_tables(all_forms, data.forms)
append_tables(all_prons, data.prons)
end
end
data.forms = all_forms
data.prons = all_prons
-- FIXME! From here on out we use the value of data.notes, data.stem
-- and data.cat as set/modified in the conjugation functions of the last
-- iteration of the loop above. As it happens, this doesn't matter
-- because we iterate over pronunciations keeping the stem and conjugation
-- type the same, but might matter one day if we break this assumption.
-- FIXME, allow all overrides
if args.inf then
data.forms.inf = args.inf
end
if args.archaic then
for k, v in pairs(data.forms) do
data.forms[k] = map(v, function(val)
val = rsub(val, "ai", "oi")
val = rsub(val, "â", "as")
return val end)
end
end
if args.impers or args.onlythird then
if data.notes then
data.notes = data.notes .. "\n"
else
data.notes = ""
end
table.insert(data.cat, "defective")
end
if args.impers then
data.notes = data.notes .. "This verb is impersonal and is conjugated only in the third-person singular."
impersonal_verb(data)
table.insert(data.cat, "impersonal")
elseif args.onlythird then
data.notes = data.notes .. "This verb is conjugated only in the third person."
only_third_verb(data)
end
if args.note then
if data.notes then
data.notes = data.notes .. "\n"
else
data.notes = ""
end
data.notes = data.notes .. args.note
end
if data.notes then data.notes = rsub(data.notes, "{stem}", data.stem) end
for key,val in pairs(data.forms) do
if type(val) == "table" then
for i,form in ipairs(val) do
if form ~= "—" then
if type(form) == "table" then
error(("Internal error: Saw table value for key '%s': %s"):format(key, mw.dumpObject(form)))
end
data.forms[key][i] = data.stem .. form
end
end
else
if val ~= "—" then
data.forms[key] = data.stem .. val
end
end
end
for _, pref_and_type in ipairs(verb_prefix_to_type) do
local pref, prefty = pref_and_type[1], pref_and_type[2]
if args[prefty] == "n" or args[prefty] == "no" then
if data.preftype == prefty then
data.preftype = nil
end
elseif args[prefty] then
data.preftype = prefty
end
end
if data.preftype then
for key, val in pairs(data.forms) do
m_core.pref_sufs[data.preftype](data, key, val)
end
end
local aux_prefix = data.prefix or ""
aux_prefix = rsub(aux_prefix, "l[ae] $", "l'")
if args.aux == "a" or args.aux == "avoir" then
data.aux = aux_prefix .. "avoir"
elseif args.aux == "e" or args.aux == "être" then
data.aux = aux_prefix .. "être"
elseif args.aux == "ae" or args.aux == "avoir,être" or args.aux == "avoir or être" then
data.aux = aux_prefix .. "avoir]] or [[être"
elseif args.aux then
error("Unrecognized value for aux=, should be 'a', 'e', 'ae', 'avoir', 'être', or 'avoir,être'")
end
data.forms.inf_nolink = data.forms.inf_nolink or data.forms.inf
data.forms.ppr_nolink = data.forms.ppr_nolink or data.forms.ppr
data.forms.pp_nolink = data.forms.pp_nolink or data.forms.pp
if not data.irregular then
if data.group == 1 or data.group == 2 then
data.irregular = "no"
else
data.irregular = "yes"
end
end
return data
end
function export.generate_forms(frame)
local args = clone_args(frame)
local data = export.do_generate_forms(args)
local retval = {}
for arraytype = 1, 2 do
local arrayname = arraytype == 1 and "forms" or "prons"
local array = data[arrayname]
for _, prop in ipairs(all_verb_props) do
local val = array[prop]
if type(val) ~= "table" then val = {val} end
local newval = {}
for _, form in ipairs(val) do
if not rmatch(form, "—") then
table.insert(newval, form)
end
end
-- Ignore pronunciation if dash present in form.
-- FIXME, we shouldn't generate the pronunciation at all in that
-- case, so we can support both dash and another form.
if arrayname == "prons" then
local val = data.forms[prop]
if type(val) == "string" then val = {val} end
local found_dash = false
for _, form in ipairs(val) do
if rmatch(form, "—") then
found_dash = true
break
end
end
if found_dash then
newval = {}
end
end
if #newval > 0 then
table.insert(retval, arrayname .. "." .. prop .. "=" .. table.concat(newval, ","))
end
end
end
return table.concat(retval, "|")
end
-- The main entry point.
-- This is the only function that can be invoked from a template.
function export.show(frame)
local args = clone_args(frame)
local args_clone
if test_new_fr_verb_module then
-- clone in case export.do_generate_forms() modifies args
-- (I don't think it does currently)
args_clone = mw.clone(args)
end
local data = export.do_generate_forms(args)
-- Test code to compare existing module to new one.
if test_new_fr_verb_module then
local m_new_fr_verb = require("Module:User:Benwing2/fr-verb")
local newdata = m_new_fr_verb.do_generate_forms(args_clone)
local difconj = false
local difforms = {}
for arraytype = 1, 2 do
local arrayname = arraytype == 1 and "forms" or "prons"
local array = data[arrayname]
local newarray = newdata[arrayname]
for _, prop in ipairs(all_verb_props) do
local val = array[prop]
local newval = newarray[prop]
-- deal with possible impedance mismatch between plain string
-- and list
if type(val) == "string" then val = {val} end
if type(newval) == "string" then newval = {newval} end
if not m_table.deepEquals(val, newval) then
if test_new_fr_verb_module == "error" then
table.insert(difforms, arrayname .. "." .. prop .. " " .. (val and table.concat(val, ",") or "nil") .. " || " .. (newval and table.concat(newval, ",") or "nil"))
end
difconj = true
end
end
end
if #difforms > 0 then
error(table.concat(difforms, "; "))
end
track(difconj and "different-conj" or "same-conj")
end
m_core.link(data)
local categories = {}
if data.aux == "être" then
table.insert(categories, "French verbs taking être as auxiliary")
elseif data.aux == "avoir]] or [[être" then
table.insert(categories, "French verbs taking avoir or être as auxiliary")
end
if data.conjcat then
table.insert(categories, "Động từ tiếng Pháp với chia động từ " .. data.conjcat)
end
for _, cat in ipairs(data.cat) do
table.insert(categories, "French " .. cat .. " verbs")
end
for _, group in ipairs(type(data.group) == "table" and data.group or {data.group}) do
if group == 1 then
table.insert(categories, "Động từ tiếng Pháp nhóm 1")
elseif group == 2 then
table.insert(categories, "Động từ tiếng Pháp nhóm 2")
else
table.insert(categories, "Động từ tiếng Pháp nhóm 3")
end
end
if data.irregular == "yes" then
table.insert(categories, "Động từ tiếng Pháp bất quy tắc")
end
return m_conj.make_table(data) .. m_utilities.format_categories(categories, lang)
end
return export