ဝိက်ရှေန်နရဳ mnwwiktionary https://mnw.wiktionary.org/wiki/%E1%80%9D%E1%80%AD%E1%80%80%E1%80%BA%E1%80%9B%E1%80%BE%E1%80%B1%E1%80%94%E1%80%BA%E1%80%94%E1%80%9B%E1%80%B3:%E1%80%99%E1%80%AF%E1%80%80%E1%80%BA%E1%80%9C%E1%80%AD%E1%80%80%E1%80%BA%E1%80%90%E1%80%99%E1%80%BA MediaWiki 1.47.0-wmf.22 case-sensitive မဳဒဳယာ တၟေင် ဓရီုကျာ ညးလွပ် ညးလွပ် ဓရီုကျာ ဝိက်ရှေန်နရဳ ဝိက်ရှေန်နရဳ ဓရီုကျာ ဝှာင် ဝှာင် ဓရီုကျာ မဳဒဳယာဝဳကဳ မဳဒဳယာဝဳကဳ ဓရီုကျာ ထာမ်ပလိက် ထာမ်ပလိက် ဓရီုကျာ ရီု ရီု ဓရီုကျာ ကဏ္ဍ ကဏ္ဍ ဓရီုကျာ အဆက်လက္ကရဴ အဆက်လက္ကရဴ ဓရီုကျာ ကာရန် ကာရန် ဓရီုကျာ အဘိဓာန် အဘိဓာန် ဓရီုကျာ ဗီုပြၚ်သိုၚ်တၟိ ဗီုပြၚ်သိုၚ်တၟိ ဓရီုကျာ TimedText TimedText talk မဝ်ဂျူ မဝ်ဂျူ ဓရီုကျာ Event Event talk မဝ်ဂျူ:gl-reinteg-verb 828 66896 402291 87440 2026-10-03T08:19:22Z 咽頭べさ 33 402291 Scribunto text/plain --[=[ This module implements {{gl-reinteg-conj}} and provides the underlying conjugation functions for {{gl-reinteg-verb}}, as well as for {{gl-verb}} when invoked with |reinteg=1. The actual formatting of both {{gl-reinteg-verb}} and {{gl-verb}} happens in [[Module:gl-headword]]. This module uses the [[Appendix:Reintegrationism|reintegrationist]] norm for Galician spelling. See also [[Module:gl-verb]], which implements the standard norm. Authorship: Ben Wing <benwing2>, MedK <medk1> ]=] local export = {} --[=[ TERMINOLOGY: -- "slot" = A particular combination of tense/mood/person/number/etc. Example slot names for verbs are "pres_1s" (present indicative first-person singular), "pres_sub_2s" (present subjunctive second-person singular) "impf_sub_3p" (imperfect subjunctive third-person plural). Each slot is filled with zero or more forms. -- "form" = The conjugated Galician form representing the value of a given slot. -- "lemma" = The dictionary form of a given Galician term. For Galician, always the infinitive. ]=] --[=[ FIXME: --]=] local lang = require("Module:languages").getByCode("gl") local m_string_utilities = require("Module:string utilities") local m_links = require("Module:links") local m_table = require("Module:table") local iut = require("Module:inflection utilities") local put = require("Module:parse utilities") local com = require("Module:gl-reinteg-common") local force_cat = false -- set to true for debugging local check_for_red_links = false -- set to false for debugging local rfind = mw.ustring.find local rmatch = mw.ustring.match local rsplit = mw.text.split local rsub = com.rsub local u = mw.ustring.char local unpack = unpack or table.unpack -- Lua 5.2 compatibility local function link_term(term) return m_links.full_link({ lang = lang, term = term }, "term") end local V = com.V -- vowel regex class local AV = com.AV -- accented vowel regex class local C = com.C -- consonant regex class local AC = u(0x0301) -- acute = ́ local TEMPC1 = u(0xFFF1) -- temporary character used for consonant substitutions local TEMP_MESOCLITIC_INSERTION_POINT = u(0xFFF2) -- temporary character used to mark the mesoclitic insertion point -- Variant codes and the like. -- NOTE: These codes should be *PREFIXED* onto stems and *SUFFIXED* onto endings. That way they won't interfere in the -- operation of combine_stem_ending(). -- -- GL_TYPE = "Galician-type", PT_TYPE = "Portuguese-type". GL_TYPE stems cannot combine with PT_TYPE endings and -- vice-versa. GL_ONLY_TYPE = "Galician-only type"; GL_ONLY_TYPE stems can only combine with endings specifically -- marked as GL_TYPE. local GL_TYPE = u(0xFFF3) local GL_ONLY_TYPE = u(0xFFF4) local PT_TYPE = u(0xFFF5) -- ALTVAR = Less-recommended variants listed at the bottom of the Estraviz conjugation tables rather than in the main -- table. We list these in the main table but with a footnote indicating they are less-recommended alternatives, and -- italicize them to visually set them apart. local ALTVAR = u(0xFFF6) local GL_ALTVAR = GL_TYPE .. ALTVAR local GL_ONLY_ALTVAR = GL_ONLY_TYPE .. ALTVAR local var_codes_no_altvar = GL_TYPE .. GL_ONLY_TYPE .. PT_TYPE local all_var_codes = var_codes_no_altvar .. ALTVAR local var_code_c = "[" .. all_var_codes .. "]" local var_code_no_altvar_c = "[" .. var_codes_no_altvar .. "]" local not_var_code_c = "[^" .. all_var_codes .. "]" -- Export variant codes for use in [[Module:pt-gl-inflections]]. export.GL_TYPE = GL_TYPE export.GL_ONLY_TYPE = GL_ONLY_TYPE export.PT_TYPE = PT_TYPE export.ALTVAR = ALTVAR local short_pp_footnote = "[usually used with auxiliary verbs " .. link_term("ser") .. " and " .. link_term("estar") .. "]" local long_pp_footnote = "[usually used with auxiliary verbs " .. link_term("haver") .. " and " .. link_term("ter") .. "]" --[=[ Vowel alternations: <i-e>: 'i' in pres1s and the whole present subjunctive; 'e' elsewhere when stressed. Generally 'e' otherwise when unstressed. E.g. [[sentir]], [[conseguir]] (the latter additionally with 'gu-g' alternation). <u-o>: 'u' in pres1s and the whole present subjunctive; 'o' elsewhere when stressed. Either 'o' or 'u' otherwise when unstressed. E.g. [[dormir]], [[subir]]. <i>: 'i' whenever stressed (in the present singular and third plural) and throughout the whole present subjunctive. Otherwise 'e'. E.g. [[progredir]], [[premir]]. <u>: 'u' whenever stressed (in the present singular and third plural) and throughout the whole present subjunctive. Otherwise 'o'. E.g. [[polir]], [[extorquir]] (the latter also <u-o>). <í>: The last 'i' of the stem (excluding stem-final 'i') becomes 'í' when stressed. E.g.: * [[proibir]] ('proíbo, proíbe(s), proíbem, proíba(s), proíbam') * [[faiscar]] ('faísco, faísca(s), faíscam, faísque(s), faísquem' also with 'c-qu' alternation) * [[homogeneizar]] ('homogeneízo', etc.) * [[mobiliar]] ('mobílio', etc.; note here the final -i is ignored when determining which vowel to stress) * [[tuitar]] ('tuíto', etc.) <ú>: The last 'u' of the stem (excluding stem-final 'u') becomes 'ú' when stressed. E.g.: * [[reunir]] ('reúno, reúne(s), reúnem, reúna(s), reúnam') * [[esmiuçar]] ('esmiúço, esmiúça(s), esmiúça, esmiúce(s), esmiúcem' also with 'ç-c' alternation) * [[reusar]] ('reúso, reúsa(s), reúsa, reúse(s), reúsem') * [[saudar]] ('saúdo, saúda(s), saúda, saúde(s), saúdem') ]=] local vowel_alternants = m_table.listToSet({"i-e", "i", "í", "u-o", "u", "ú", "ei", "+"}) local vowel_alternant_to_desc = { ["i-e"] = "''i-e'' alternation in present singular", ["i"] = "''e'' becomes ''i'' when stressed", ["í"] = "''i'' becomes ''í'' when stressed", ["u-o"] = "''u-o'' alternation in present singular", ["u"] = "''o'' becomes ''u'' when stressed", ["ú"] = "''u'' becomes ''ú'' when stressed", ["ei"] = "''i'' becomes ''ei'' when stressed", } local vowel_alternant_to_cat = { ["i-e"] = "i-e alternation in present singular", ["i"] = "e becoming i when stressed", ["í"] = "i becoming í when stressed", ["u-o"] = "u-o alternation in present singular", ["u"] = "o becoming u when stressed", ["ú"] = "u becoming ú when stressed", ["ei"] = "i becoming ei when stressed", } local all_persons_numbers = { ["1s"] = "1|s", ["2s"] = "2|s", ["3s"] = "3|s", ["1p"] = "1|p", ["2p"] = "2|p", ["3p"] = "3|p", } local person_number_list = {"1s", "2s", "3s", "1p", "2p", "3p"} local imp_person_number_list = {"2s", "3s", "1p", "2p", "3p"} local neg_imp_person_number_list = {"2s", "3s", "1p", "2p", "3p"} person_number_to_reflexive_pronoun = { ["1s"] = "me", ["2s"] = "te", ["3s"] = "se", ["1p"] = "nos", ["2p"] = "vos", ["3p"] = "se", } local indicator_flags = m_table.listToSet { "no_pres_stressed", "no_pres1_and_sub", "only3s", "only3sp", "only3p", "pp_inv", "irreg", "no_built_in", "e_ei_cat", } -- Remove any variant codes e.g. GL_TYPE, PT_TYPE, ALTVAR. Needs to be called from [[Module:gl-reinteg-headword]] on the -- output of do_generate_forms(). `keep_altvar` leaves ALTVAR; used in the `canonicalize` function of show_forms() -- because we then process and remove it in `generate_forms`. FIXME: Use metadata for this once it's supported in -- [[Module:inflection utilities]]. function export.remove_variant_codes(form, keep_altvar) return rsub(form, keep_altvar and var_code_no_altvar_c or var_code_c, "") end -- Initialize all the slots for which we generate forms. local function add_slots(alternant_multiword_spec) -- "Basic" slots: All slots that go into the regular table (not the reflexive form-of table). alternant_multiword_spec.verb_slots_basic = { {"infinitive", "inf"}, {"infinitive_linked", "inf"}, {"gerund", "ger"}, {"short_pp_ms", "short|m|s|past|part"}, {"short_pp_fs", "short|f|s|past|part"}, {"short_pp_mp", "short|m|p|past|part"}, {"short_pp_fp", "short|f|p|past|part"}, {"pp_ms", "m|s|past|part"}, {"pp_fs", "f|s|past|part"}, {"pp_mp", "m|p|past|part"}, {"pp_fp", "f|p|past|part"}, } -- Special slots used to handle non-reflexive parts of reflexive verbs in {{gl-reinteg-verb form of}}. For example, -- for a reflexive-only verb like [[arrepender-se]], we want to be able to use {{gl-reinteg-verb form of}} on -- [[arrependa]] (which should mention that it is a part of 'me arrependa', first-person singular present -- subjunctive, and 'se arrependa', third-person singular present subjunctive) or on [[arrependemos]] (which should -- mention that it is a part of 'arrependemo-nos', first-person plural present indicative or preterite). Similarly, -- we want to use {{gl-reinteg-verb form of}} on [[arrependendo]] (which should mention that it is a part of -- 'se ... arrependendo', syntactic variant of [[arrependendo-se]], which is the gerund of [[arrepender-se]]). To -- do this, we need to be able to map non-reflexive parts like [[arrependa]], [[arrependemos]], [[arrependendo]], -- etc. to their reflexive equivalent(s), to the tag(s) of the equivalent(s), and, in the case of forms like -- [[arrependendo]], [[arrepender]] and imperatives, to the separated syntactic variant of the verb+clitic -- combination. We do this by creating slots for the non-reflexive part equivalent of each basic reflexive slot, -- and for the separated syntactic-variant equivalent of each basic reflexive slot that is formed of verb+clitic. -- We use slots in this way to deal with multiword lemmas. Note that we run into difficulties mapping between -- reflexive verbs, non-reflexive part equivalents, and separated syntactic variants if a slot contains more than -- one form. To handle this, if there are the same number of forms in two slots we're trying to match up, we assume -- the forms match one-to-one; otherwise we don't match up the two slots (which means {{gl-reinteg-verb form of}} won't -- work in this case, but such a case is extremely rare and not worth worrying about). Alternatives that handle -- this "properly" are significantly more complicated and require non-trivial modifications to -- [[Module:inflection utilities]]. local need_special_verb_form_of_slots = alternant_multiword_spec.source_template == "gl-reinteg-verb form of" and alternant_multiword_spec.refl if need_special_verb_form_of_slots then alternant_multiword_spec.verb_slots_reflexive_verb_form_of = { {"infinitive_non_reflexive", "-"}, {"infinitive_variant", "-"}, {"gerund_non_reflexive", "-"}, {"gerund_variant", "-"}, } else alternant_multiword_spec.verb_slots_reflexive_verb_form_of = {} end -- Add entries for a slot with person/number variants. -- `verb_slots` is the table to add to. -- `slot_prefix` is the prefix of the slot, typically specifying the tense/aspect. -- `tag_suffix` is a string listing the set of inflection tags to add after the person/number tags. -- `person_number_list` is a list of the person/number slot suffixes to add to `slot_prefix`. local function add_personal_slot(verb_slots, slot_prefix, tag_suffix, person_number_list) for _, persnum in ipairs(person_number_list) do local persnum_tag = all_persons_numbers[persnum] local slot = slot_prefix .. "_" .. persnum local accel = persnum_tag .. "|" .. tag_suffix table.insert(verb_slots, {slot, accel}) end end -- Add a personal slot (i.e. a slot with person/number variants) to `verb_slots_basic`. local function add_basic_personal_slot(slot_prefix, tag_suffix, person_number_list, no_special_verb_form_of_slot) add_personal_slot(alternant_multiword_spec.verb_slots_basic, slot_prefix, tag_suffix, person_number_list) -- Add special slots for handling non-reflexive parts of reflexive verbs in {{gl-reinteg-verb form of}}. -- See comment above in `need_special_verb_form_of_slots`. if need_special_verb_form_of_slots and not no_special_verb_form_of_slot then for _, persnum in ipairs(person_number_list) do local persnum_tag = all_persons_numbers[persnum] local basic_slot = slot_prefix .. "_" .. persnum local accel = persnum_tag .. "|" .. tag_suffix table.insert(alternant_multiword_spec.verb_slots_reflexive_verb_form_of, {basic_slot .. "_non_reflexive", "-"}) end end end add_basic_personal_slot("pres", "pres|ind", person_number_list) add_basic_personal_slot("impf", "impf|ind", person_number_list) add_basic_personal_slot("pret", "pret|ind", person_number_list) add_basic_personal_slot("plup", "plup|ind", person_number_list) add_basic_personal_slot("fut", "fut|ind", person_number_list) add_basic_personal_slot("cond", "cond", person_number_list) add_basic_personal_slot("pres_sub", "pres|sub", person_number_list) add_basic_personal_slot("impf_sub", "impf|sub", person_number_list) add_basic_personal_slot("fut_sub", "fut|sub", person_number_list) add_basic_personal_slot("imp", "imp", imp_person_number_list) add_basic_personal_slot("pers_inf", "pers|inf", person_number_list) -- Don't need special non-reflexive-part slots because the negative imperative is multiword, of which the -- individual words are 'nom' + subjunctive. add_basic_personal_slot("neg_imp", "neg|imp", neg_imp_person_number_list, "no special verb form of") -- Don't need special non-reflexive-part slots because we don't want [[arrependendo]] mapping to [[arrependendo-me]] -- (only [[arrependendo-se]]) or [[arrepender]] mapping to [[arrepender-me]] (only [[arrepender-se]]). add_basic_personal_slot("infinitive", "inf", person_number_list, "no special verb form of") add_basic_personal_slot("gerund", "ger", person_number_list, "no special verb form of") -- Generate the list of all slots. alternant_multiword_spec.all_verb_slots = {} for _, slot_and_accel in ipairs(alternant_multiword_spec.verb_slots_basic) do table.insert(alternant_multiword_spec.all_verb_slots, slot_and_accel) end for _, slot_and_accel in ipairs(alternant_multiword_spec.verb_slots_reflexive_verb_form_of) do table.insert(alternant_multiword_spec.all_verb_slots, slot_and_accel) end alternant_multiword_spec.verb_slots_basic_map = {} for _, slotaccel in ipairs(alternant_multiword_spec.verb_slots_basic) do local slot, accel = unpack(slotaccel) alternant_multiword_spec.verb_slots_basic_map[slot] = accel end end local overridable_stems = {} local function allow_multiple_values(separated_groups, data) local retvals = {} for _, separated_group in ipairs(separated_groups) do local footnotes = data.fetch_footnotes(separated_group) local retval = {form = separated_group[1], footnotes = footnotes} table.insert(retvals, retval) end return retvals end local function simple_choice(choices) return function(separated_groups, data) if #separated_groups > 1 then data.parse_err("For spec '" .. data.prefix .. ":', only one value currently allowed") end if #separated_groups[1] > 1 then data.parse_err("For spec '" .. data.prefix .. ":', no footnotes currently allowed") end local choice = separated_groups[1][1] if not m_table.contains(choices, choice) then data.parse_err("For spec '" .. data.prefix .. ":', saw value '" .. choice .. "' but expected one of '" .. table.concat(choices, ",") .. "'") end return choice end end for _, overridable_stem in ipairs { "pres_unstressed", "pres_stressed", "pres1_and_sub", -- Don't include pres1; use pres_1s if you need to override just that form "impf", "full_impf", {"pret_conj", simple_choice({"irreg", "ar", "er", "ir"}) }, "pret_base", "pret", "gl_short_pret", "pt_pret_1s", "pt_pret_3s", "fut", "cond", "pres_sub_stressed", "pres_sub_unstressed", {"sub_conj", simple_choice({"ar", "er"}) }, "plup", "impf_sub", "fut_sub", "pers_inf", "pp", "short_pp", } do if type(overridable_stem) == "string" then overridable_stems[overridable_stem] = allow_multiple_values else local stem, validator = unpack(overridable_stem) overridable_stems[stem] = validator end end -- Useful as the value of the `match` property of a built-in verb. `main_verb_spec` is a Lua pattern that should match -- the non-prefixed part of a verb, and `prefix_specs` is a list of Lua patterns that should match the prefixed part of -- a verb. If a prefix spec is preceded by ^, it must match exactly at the beginning of the verb; otherwise, additional -- prefixes (e.g. re-, des-) may precede. Return the prefix and main verb. local function match_against_verbs(main_verb_spec, prefix_specs) return function(verb) for _, prefix_spec in ipairs(prefix_specs) do if prefix_spec:find("^%^") then -- must match exactly prefix_spec = prefix_spec:gsub("^%^", "") if prefix_spec == "" then -- We can't use the second branch of the if-else statement because an empty () returns the current position -- in rmatch(). local main_verb = rmatch(verb, "^(" .. main_verb_spec .. ")$") if main_verb then return "", main_verb end else local prefix, main_verb = rmatch(verb, "^(" .. prefix_spec .. ")(" .. main_verb_spec .. ")$") if prefix then return prefix, main_verb end end else local prefix, main_verb = rmatch(verb, "^(.*" .. prefix_spec .. ")(" .. main_verb_spec .. ")$") if prefix then return prefix, main_verb end end end return nil end end --[=[ Built-in (usually irregular) conjugations. Each entry is processed in turn and consists of an object with two fields: 1. match=: Specifies the built-in verbs that match this object. 2. forms=: Specifies the built-in stems and forms for these verbs. The value of match= is either a string beginning with "^" (match only the specified verb), a string not beginning with "^" (match any verb ending in that string), or a function that is passed in the verb and should return the prefix of the verb if it matches, otherwise nil. The function match_against_verbs() is provided to facilitate matching a set of verbs with a common ending and specific prefixes (e.g. [[ter]] and [[ater]] but not [[abater]], etc.). The value of forms= is a table specifying stems and individual override forms. Each key of the table names either a stem (e.g. `pres_stressed`), a stem property (e.g. `vowel_alt`) or an individual override form (e.g. `pres_1s`). Each value of a stem can either be a string (a single stem), a list of strings, or a list of objects of the form {form = STEM, footnotes = {FOONOTES}}. Each value of an individual override should be of exactly the same form except that the strings specify full forms rather than stems. The values of a stem property depend on the specific property but are generally strings or booleans. In order to understand how the stem specifications work, it's important to understand the phonetic modifications done by combine_stem_ending(). In general, the complexities of predictable prefix, stem and ending modifications are all handled in this function. In particular: 1. Spelling-based modifications (c/z, g/gu, gu/gü, g/j) occur automatically as appropriate for the ending. 2. If the stem begins with an acute accent, the accent is moved onto the last vowel of the prefix (for handling verbs in -uar such as [[minguar]], pres_3s 'míngua'). 3. If the ending begins with a double asterisk, this is a signal to conditionally delete the accent on the last letter of the stem. "Conditionally" means we don't do it if the last two letters would form a diphthong without the accent on the second one (e.g. in [[sair]], with stem 'saí'); but as an exception, we do delete the accent in stems ending in -guí, -quí (e.g. in [[conseguir]]) because in this case the ui isn't a diphthong. 4. If the ending begins with an asterisk, this is a signal to delete the accent on the last letter of the stem, e.g. fizé -> fizermos. Unlike for **, this removal is unconditional, so we get e.g. 'sairmos' not #'saírmos'. 5. If ending begins with i, it must get an accent after an unstressed vowel (in some but not all cases) to prevent the two merging into a diphthong. See combine_stem_ending() for specifics. The following stems are recognized: -- pres_unstressed: The present indicative unstressed stem (1p, 2p). Also controls the imperative 2p and gerund. Defaults to the infinitive stem (minus the ending -ar/-er/-ir/-or). -- pres_stressed: The present indicative stressed stem (1s, 2s, 3s, 3p). Also controls the imperative 2s. Default is empty if indicator `no_pres_stressed`, else a vowel alternation if such an indicator is given (e.g. `ue`, `ì`), else the infinitive stem. -- pres1_and_sub: Overriding stem for 1s present indicative and the entire subjunctive. Only set by irregular verbs and by the indicators `no_pres_stressed` (e.g. [[precaver]]) and `no_pres1_and_sub` (since verbs of this sort, e.g. [[puir]], are missing the entire subjunctive as well as the 1s present indicative). Used by many irregular verbs, e.g. [[caber]], verbs in '-air', [[dizer]], [[ter]], [[valer]], etc. Some verbs set this and then supply an override for the pres_1sg if it's irregular, e.g. [[saber]], with irregular subjunctive stem "saib-" and special 1s present indicative "sei". -- pres1: Special stem for 1s present indicative. Normally, do not set this explicitly. If you need to specify an irregular 1s present indicative, use the form override pres_1s= to specify the entire form. Defaults to pres1_and_sub if given, else pres_stressed. -- pres_sub_unstressed: The present subjunctive unstressed stem (1p, 2p). Defaults to pres1_and_sub if given, else the infinitive stem. -- pres_sub_stressed: The present subjunctive stressed stem (1s, 2s, 3s, 1p). Defaults to pres1. -- sub_conj: Determines the set of endings used in the subjunctive. Should be one of "ar" or "er". -- impf: The imperfect stem (not including the -av-/-i- stem suffix, which is determined by the conjugation). Defaults to the infinitive stem. -- full_impf: The full imperfect stem missing only the endings (-a, -as, -am, etc.). Used for verbs with irregular imperfects such as [[ser]], [[ter]], [[vir]] and [[pôr]]. Needs to include an accent on the stressed vowel, which will automatically be removed when not needed. -- pret_conj: Determines the set of endings used in the preterite. Should be one of "ar", "er", "ir" or "irreg". Defaults to the conjugation as determined from the infinitive. When pret_conj == "irreg", `pret` is used, otherwise `pret_base`. -- pret_base: The preterite stem (not including the -a-/-e-/-i- stem suffix). Defaults to the infinitive stem. Only used when pret_conj ~= "irreg". -- pret: The full preterite stem missing only the endings (-ste, -mos, etc.). Needs to include the accent on the final vowel that occurs in some forms, e.g. 'figé' for [[fazer]], 'fô' for [[ser]]; the accent will automatically be removed when not needed. Only used for verbs with irregular preterites (pret_conj == "irreg") such as [[fazer]], [[poder]], [[trazer]], etc. The pret_1s and pret_3s are handled using the gl_short_pret stem instead for "Galician"-ending forms (pret_1s '-em', pret_3s '-o') and using pt_pret_1s and pt_pret_3s for "Portuguese"-ending forms. Defaults to `pret_base` + the accented conjugation vowel. -- gl_short_pret: The short preterite stem, used with "Galician" 1s and 3s endings (pret_1s '-em', pret_3s '-o'). Only used with irregular preterites (pret_conj == "irreg"). Normally derived from gl_pret by deleting the final vowel, and doesn't need to be given explicitly. -- pt_pret_1s: The "Portuguese" pret_1s form. In addition to this, the "Galician" pret_1s form will be included, formed from gl_short_pret by adding '-em'. Does not need to be given if an override for pret_1s is supplied. -- pt_pret_3s: The "Portuguese" pret_3s form. In addition to this, the "Galician" pret_3s form will be included, formed from gl_short_pret by adding '-o' (which may cause the preceding consonant to shift to preserve the sound). Does not need to be given if an override for pret_3s is supplied. -- fut: The future stem. Defaults to the infinitive stem + the unaccented conjugation vowel. -- cond: The conditional stem. Defaults to `fut`. -- impf_sub: The imperfect subjunctive stem. Needs to include the accent on the final vowel that occurs in some forms; see `pret` for more information. Defaults to `pret`. -- fut_sub: The future subjunctive stem. Needs to include the accent on the final vowel that occurs in some forms; see `gl_pret` for more information. Defaults to the merger of `gl_pret` and `pt_pret`. -- plup: The pluperfect stem. Needs to include the accent on the final vowel that occurs in some forms; see `pret` for more information. Defaults to `pret`. -- pers_inf: The personal infinitive stem. Defaults to the infinitive stem + the accented conjugation vowel. -- pp: The masculine singular past participle. Default is based on the verb conjugation: infinitive stem + '-ado' for -ar verbs, otherwise infinitive stem + '-ido'. -- short_pp: The short masculine singular past participle, for verbs with such a form. No default. -- pp_inv: `true` if the past participle exists only in the masculine singular. ]=] local built_in_conjugations = { -------------------------------------------------------------------------------------------- -- -ar -- -------------------------------------------------------------------------------------------- -- Verbs not needing entries here: -- -- (1) Verbs with short past participles: need to specify the short pp explicitly. -- -- aceitar: use <short_pp:aceite> -- anexar, completar, expressar, expulsar, findar, fritar, ganhar, gastar, limpar, pagar, pasmar, pegar, soltar: -- use <short_pp:anexo> etc. -- assentar: use <short_pp:assente> -- entregar: use <short_pp:entregue> -- enxugar: use <short_pp:enxuto> -- matar: use <short_pp:morto> -- -- (2) Verbs with orthographic consonant alternations: handled automatically. -- -- -car (brincar, buscar, pecar, trancar, etc.): automatically handled in combine_stem_ending() -- -çar (alcançar, começar, laçar): automatically handled in combine_stem_ending() -- -gar (apagar, cegar, esmagar, largar, navegar, resmungar, sugar, etc.): automatically handled in combine_stem_ending() -- -- (3) Verbs with vowel alternations: need to specify the alternation explicitly unless it always happens, in -- which case it's handled automatically through an entry below. -- -- esmiuçar changing to esmiúço: use <ú> -- faiscar changing to faísco: use <í> -- -iar changing to -eio (ansiar, incendiar, mediar, odiar, remediar, etc.): use <ei> -- -izar changing to -ízo (ajuizar, enraizar, homogeneizar, plebeizar, etc.): use <í> -- mobiliar changing to mobílio: use <í> -- reusar changing to reúso: use <ú> -- saudar changing to saúdo: use <ú> -- tuitar/retuitar changing to (re)tuíto: use <í> { -- dar, desdar match = match_against_verbs("dar", {"^", "^des", "^re"}), forms = { pres_1s = "dou", pres_2s = "dás", pres_3s = "dá", -- damos, dades/dais regular pres_3p = {GL_TYPE .. "dam", PT_TYPE .. "dão"}, pret_conj = "irreg", pret = "dé", pret_1s = "dei", pret_3s = "deu", pres_sub_1s = "dê", pres_sub_2s = "dês", pres_sub_3s = "dê", -- demos, dedes/deis regular pres_sub_3p = {GL_TYPE .. "dem", PT_TYPE .. "deem"}, irreg = true, } }, { -- -ear (frear, nomear, semear, etc.) match = "ear", forms = { pres_stressed = {"ei", GL_ALTVAR .. "e"}, e_ei_cat = true, } }, { -- estar match = match_against_verbs("estar", {"^", "sob", "sobr"}), forms = { pres_1s = "estou", pres_2s = "estás", pres_3s = "está", pres_3p = {GL_TYPE .. "estám", PT_TYPE .. "estão"}, pres1_and_sub = "estej", -- only for subjunctive as we override pres_1s sub_conj = "er", pret_conj = "irreg", pret = "estivé", pt_pret_1s = "estive", pt_pret_3s = "esteve", -- [[sobestar]], [[sobrestar]] are transitive so they have fully inflected past participles pp_inv = function(base, prefix) return prefix == "" end, irreg = true, } }, -------------------------------------------------------------------------------------------- -- -er -- -------------------------------------------------------------------------------------------- -- Verbs not needing entries here: -- -- precaver: use <no_pres_stressed> -- -cer (verbs in -ecer, descer, vencer, etc.): automatically handled in combine_stem_ending() -- -ger (proteger, reger, etc.): automatically handled in combine_stem_ending() -- -guer (erguer/reerguer/soerguer): automatically handled in combine_stem_ending() { -- benzer match = "benzer", forms = {short_pp = "bento"} }, { -- caber match = "caber", forms = { pres1_and_sub = "caib", pret_conj = "irreg", pret = "coubé", pt_pret_1s = "coube", pt_pret_3s = "coube", irreg = true, } }, { -- crer, descrer match = "crer", forms = { pres_2s = "crês", pres_3s = "crê", pres_2p = "credes", pres_3p = {GL_TYPE .. "crem", PT_TYPE .. "creem"}, pres1_and_sub = {"crei", GL_ALTVAR .. "cre"}, irreg = true, } }, { -- dizer, bendizer, condizer, contradizer, desdizer, maldizer, predizer, etc. match = "dizer", forms = { -- use 'digu' because we're in a front environment; if we use 'dig', we'll get '#dijo' pres1_and_sub = "digu", pres_2s = {GL_TYPE .. "dis", PT_TYPE .. "dizes"}, pres_3s = {GL_TYPE .. "di", PT_TYPE .. "diz"}, pres_3p = {GL_TYPE .. "dim", PT_TYPE .. "dizem"}, pret_conj = "irreg", pret = {GL_TYPE .. "dixé", PT_TYPE .. "dissé"}, pt_pret_1s = "disse", pt_pret_3s = "disse", pp = "dito", fut = "dir", irreg = true, } }, { -- eleger, reeleger match = "eleger", forms = {short_pp = "eleito"} }, { -- acender, prender; not desprender, etc. match = match_against_verbs("ender", {"^ac", "^pr"}), forms = {short_pp = "eso"} }, { -- fazer, afazer, contrafazer, desfazer, liquefazer, perfazer, putrefazer, rarefazer, refazer, satisfazer, tumefazer match = "fazer", forms = { -- use 'fagu' because we're in a front environment; if we use 'fag', we'll get '#fajo' pres1_and_sub = {GL_TYPE .. "fagu", PT_TYPE .. "faç"}, pres_2s = {GL_TYPE .. "fás", PT_TYPE .. "fazes"}, pres_3s = {GL_TYPE .. "fai", PT_TYPE .. "faz"}, pres_3p = {GL_TYPE .. "fam", PT_TYPE .. "fazem"}, pret_conj = "irreg", pret = {GL_TYPE .. "figé", PT_TYPE .. "fizé", GL_ONLY_ALTVAR .. "fizé"}, pt_pret_1s = "fiz", pt_pret_3s = "fez", pp = "feito", fut = "far", irreg = true, } }, { match = "^haver", forms = { pres_1s = "hei", pres_2s = "hás", pres_3s = {"há", {form = GL_ALTVAR .. "hai", footnotes = {"[also impersonal]"}}}, pres_3p = {GL_TYPE .. "ham", PT_TYPE .. "hão"}, pres1_and_sub = "haj", -- only for subjunctive as we override pres_1s pret_conj = "irreg", pret = "houvé", pt_pret_1s = "houve", pt_pret_3s = "houve", imp_2s = "há", irreg = true, } }, -- reaver below under r- { -- jazer, adjazer match = "jazer", forms = { pres_3s = "jaz", irreg = true, } }, { -- ler, reler, tresler; not excel(l)er, valer, etc. match = match_against_verbs("ler", {"^", "^re", "tres"}), forms = { pres_2s = "lês", pres_3s = "lê", pres_2p = "ledes", pres_3p = {GL_TYPE .. "lem", PT_TYPE .. "leem"}, pres1_and_sub = {"lei", GL_ALTVAR .. "le"}, irreg = true, } }, { -- morrer, desmorrer match = "morrer", forms = {short_pp = "morto"} }, { -- moer, but not remoer match = "^moer", forms = { pres_2s = "móis", pres_3s = "mói", -- impf -ía etc., pret_1s -oí and pp -oído handled automatically in combine_stem_ending() pres1_and_sub = {"mo", GL_ALTVAR .. "moi"}, short_pp = "mudo", irreg = true, } }, { -- doer, remoer, roer/corroer, soer match = "oer", forms = { pres_2s = "óis", pres_3s = "ói", -- impf -ía etc., pret_1s -oí and pp -oído handled automatically in combine_stem_ending() pres1_and_sub = {"o", GL_ALTVAR .. "oi"}, irreg = true, } }, { -- perder match = "perder", forms = { -- use 'perqu' because we're in a front environment; if we use 'perc', we'll get '#perço' -- we don't tag these forms GL_TYPE or PT_TYPE because both occur with both endings -ais/-ades pres1_and_sub = {"perd", "perqu"}, irreg = true, } }, { -- poder match = "poder", forms = { pres1_and_sub = {GL_TYPE .. "pod", PT_TYPE .. "poss"}, pret_conj = "irreg", pret = "pudé", pt_pret_1s = "pude", pt_pret_3s = "pôde", irreg = true, } }, { -- prazer, aprazer, comprazer, desprazer -- FIXME: comprazer also has regular preterite match = "prazer", forms = { pres_3s = "praz", pret_conj = "irreg", pret = "prouvé", pt_pret_1s = "prouve", pt_pret_3s = "prouve", only3sp = function(base, prefix) return prefix == "a" end, imp_2s = {GL_TYPE .. "praze", PT_TYPE .. "praz"}, irreg = true, } }, -- prover below, just below ver { -- requerer; must precede querer match = "requerer", forms = { pres_3s = "requer", pres1_and_sub = "requeir", imp_2s = {"requer"}, -- regular preterite, unlike [[querer]] irreg = true, } }, { -- querer, desquerer, malquerer match = "querer", forms = { pres_1s = "quero", pres_3s = "quer", pres1_and_sub = "queir", -- only for subjunctive as we override pres_1s pret_conj = "irreg", pret = {GL_TYPE .. "quigé", PT_TYPE .. "quisé"}, pt_pret_1s = "quis", pt_pret_3s = "quis", irreg = true, } }, { match = "reaver", forms = { pres_1s = "reei", pres_2s = "reás", pres_3s = "reá", pres_3p = {GL_TYPE .. "ream", PT_TYPE .. "reão"}, pres1_and_sub = "reaj", -- only for subjunctive as we override pres_1s pret_conj = "irreg", pret = "reouvé", pt_pret_1s = "reouve", pt_pret_3s = "reouve", irreg = true, } }, { -- saber, ressaber match = "saber", forms = { pres_1s = "sei", pres1_and_sub = "saib", -- only for subjunctive as we override pres_1s pret_conj = "irreg", pret = "soubé", pt_pret_1s = "soube", pt_pret_3s = "soube", irreg = true, } }, { -- escrever/reescrever, circunscrever, descrever/redescrever, inscrever, prescrever, proscrever, subscrever, -- transcrever, others? match = "screver", forms = { pp = "scrito", irreg = true, } }, { -- suspender match = "suspender", forms = {short_pp = "suspenso"} }, { match = "^ser", forms = { pres_1s = "sou", pres_2s = "és", pres_3s = "é", pres_1p = "somos", pres_2p = {GL_TYPE .. "sodes", PT_TYPE .. "sois"}, pres_3p = {GL_TYPE .. "som", PT_TYPE .. "são"}, pres1_and_sub = "sej", -- only for subjunctive as we override pres_1s full_impf = "ér", pret_conj = "irreg", pret = "fô", pret_1s = {GL_TYPE .. "fum", PT_TYPE .. "fui"}, pret_3s = "foi", imp_2s = "sê", imp_2p = "sede", pp_inv = true, irreg = true, } }, { -- We want to match abster, conter, deter, etc. but not abater, cometer, etc. No way to avoid listing each verb. match = match_against_verbs("ter", {"abs", "^a", "con", "de", "entre", "man", "ob", "^re", "sus", "^"}), forms = { -- FIXME, Estraviz says 'contens', 'detens' etc. but that may be a typo pres_2s = function(base, prefix) return {GL_TYPE .. "tés", PT_TYPE .. (prefix == "" and "tens" or "téns")} end, -- FIXME, Estraviz says 'contem', 'detem' etc. but that may be a typo pres_3s = function(base, prefix) return prefix == "" and "tem" or "tém" end, pres_2p = "tendes", pres_3p = {GL_TYPE .. "tenhem", PT_TYPE .. "têm", GL_ALTVAR .. "tém"}, pres1_and_sub = "tenh", full_impf = "tính", pret_conj = "irreg", pret = "tivé", pt_pret_1s = "tive", pt_pret_3s = "teve", irreg = true, } }, { match = "trazer", forms = { -- use 'tragu' because we're in a front environment; if we use 'trag', we'll get '#trajo' pres1_and_sub = "tragu", pres_3s = "traz", pret_conj = "irreg", pret = "trouxé", pt_pret_1s = "trouxe", pt_pret_3s = "trouxe", fut = "trar", irreg = true, } }, { match = "traguer", forms = { pret_conj = "irreg", pret = "trouxé", pt_pret_1s = "trouxe", pt_pret_3s = "trouxe", irreg = true, } }, { -- valer, desvaler, equivaler match = "valer", forms = { pres1_and_sub = "valh", irreg = true, } }, { -- We want to match antever etc. but not absolver, atrever etc. No way to avoid listing each verb. match = match_against_verbs("ver", {"ante", "entre", "pre", "^re", "^"}), forms = { pres_2s = "vês", pres_3s = "vê", pres_2p = "vedes", pres_3p = function(base, prefix) return {GL_TYPE .. (prefix == "" and "vem" or "vêm"), PT_TYPE .. "veem"} end, pres1_and_sub = "vej", pret_conj = "irreg", pret = "ví", pret_1s = {GL_TYPE .. "vim", PT_TYPE .. "vi"}, pret_3s = "viu", pp = "visto", irreg = true, } }, { -- [[prover]] and [[desprover]] have regular preterite and past participle match = "prover", forms = { pres_2s = "provês", pres_3s = "provê", -- FIXME: Estraviz says 'provem' but that may be a typo pres_2p = "provedes", pres_3p = {GL_TYPE .. "provêm", PT_TYPE .. "proveem"}, pres1_and_sub = "provej", irreg = true, } }, { -- volver, devolver, envolver, revolver, etc. match = "volver", forms = {short_pp = "volto"}, }, -------------------------------------------------------------------------------------------- -- -ir -- -------------------------------------------------------------------------------------------- -- Verbs not needing entries here: -- -- abolir: use <u-o> -- barrir: use <only3sp> -- carpir, colorir, demolir: use <no_pres1_and_sub> -- descolorir: use <no_pres1_and_sub> -- delir, espavorir, falir, florir, remir, renhir: use <no_pres_stressed> -- empedernir: use <i-e> -- transir: regular -- aspergir, despir, flectir/deflectir/genuflectir/genufletir/reflectir/refletir, mentir/desmentir, -- sentir/assentir/consentir/dissentir/pressentir/ressentir, convergir/divergir, aderir/adherir, -- ferir/auferir/conferir/deferir/desferir/diferir/differir/inferir/interferir/preferir/proferir/referir/transferir, -- gerir/digerir/ingerir/sugerir, preterir, competir/repetir, servir, advertir/animadvertir/divertir, -- vestir/investir/revestir/travestir, seguir/conseguir/desconseguir/desseguir/perseguir/prosseguir: use <i-e> -- inerir: use <i-e> -- compelir/expelir/impelir/repelir: use <i-e> -- dormir, engolir, tossir, subir, acudir/sacudir, fugir, sumir/consumir (NOT assumir/presumir/resumir): use <u-o> -- polir/repolir: use <u> -- premir: use <i> -- extorquir/retorquir: <u-o,u> -- agredir/progredir/regredir/transgredir: use <i> -- denegrir, prevenir: use <i> -- eclodir: use <u-o> -- cerzir: use <i-e> -- proibir/coibir: use <í> -- reunir: use <ú> -- parir/malparir: use <no_pres_stressed> -- explodir/implodir: use <u-o> -- -- -cir alternations (aducir, ressarcir): automatically handled in combine_stem_ending() -- -gir alternations (agir, dirigir, exigir): automatically handled in combine_stem_ending() -- -guir alternations (e.g. conseguir): automatically handled in combine_stem_ending() -- -quir alternations (e.g. extorquir): automatically handled in combine_stem_ending() { -- verbs in -air (cair, sair, trair and derivatives: decair/descair/recair, sobres(s)air, -- abstrair/atrair/contrair/distrair/extrair/protrair/retrair/subtrair) match = "air", forms = { pres1_and_sub = "ai", pres_2s = "ais", pres_3s = "ai", -- all occurrences of accented í in endings handled in combine_stem_ending() irreg = true, } }, { -- abrir/desabrir/reabrir match = "abrir", forms = {pp = "aberto"} }, { -- cobrir/descobrir/encobrir/recobrir/redescobrir match = "cobrir", forms = {vowel_alt = "u-o", pp = "coberto"} }, { -- conduzir, produzir, reduzir, traduzir, etc.; luzir, reluzir, tremeluzir match = "uzir", forms = { pres_3s = "uz", -- FIXME, is this correct? imp_2s = "uze", irreg = true, } }, { -- pedir, desimpedir, despedir, espedir, expedir, impedir -- medir -- comedir match = match_against_verbs("edir", {"m", "p"}), forms = { pres1_and_sub = {GL_TYPE .. "id", PT_TYPE .. "eç"}, irreg = true, } }, { -- frigir match = "frigir", forms = {vowel_alt = "i-e", short_pp = "frito"}, }, { -- inserir match = "inserir", forms = {vowel_alt = "i-e"}, }, { -- ir match = "^ir", forms = { pres_1s = "vou", pres_2s = {GL_TYPE .. "vás", PT_TYPE .. "vais"}, pres_3s = "vai", pres_1p = {GL_TYPE .. "imos", PT_TYPE .. "vamos"}, pres_2p = "ides", pres_3p = {GL_TYPE .. "vam", PT_TYPE .. "vão"}, pres_sub_1s = {GL_TYPE .. "vaia", PT_TYPE .. "vá"}, pres_sub_2s = {GL_TYPE .. "vaias", PT_TYPE .. "vás"}, pres_sub_3s = {GL_TYPE .. "vaia", PT_TYPE .. "vá"}, pres_sub_1p = {GL_TYPE .. "vaiamos", PT_TYPE .. "vamos"}, pres_sub_2p = {GL_TYPE .. "vaiades", PT_TYPE .. "vades"}, pres_sub_3p = {GL_TYPE .. "vaiam", PT_TYPE .. "vão"}, pret_conj = "irreg", pret = "fô", pret_1s = {GL_TYPE .. "fum", PT_TYPE .. "fui"}, pret_3s = "foi", irreg = true, } }, { -- emergir, imergir, submergir match = "mergir", forms = {vowel_alt = "i-e", short_pp = "merso"}, }, { match = "ouvir", forms = { pres1_and_sub = {"ouç", ALTVAR .. "oiç"}, irreg = true, } }, { -- exprimir, imprimir, comprimir (but not descomprimir per Priberam), deprimir, oprimir/opprimir (but not reprimir, -- suprimir/supprimir per Priberam) match = match_against_verbs("primir", {"^com", "ex", "im", "de", "^o", "op"}), forms = {short_pp = "presso"} }, { -- rir, sorrir match = match_against_verbs("rir", {"^", "sor"}), forms = { pres_2s = "ris", pres_3s = "ri", pres_2p = "rides", pres_3p = {GL_TYPE .. "rim", PT_TYPE .. "riem"}, pres1_and_sub = "ri", irreg = true, } }, { -- distinguir, extinguir match = "tinguir", forms = { short_pp = "tinto", -- gu/g alternations handled in combine_stem_ending() } }, { -- verbs in -truir (construir, destruir, reconstruir) but not obstruir/desobstruir, instruir, which are handled -- by the default -uir handler below match = match_against_verbs("struir", {"con", "de"}), forms = { pres_2s = {"stróis", ALTVAR .. "struis"}, pres_3s = {"strói", ALTVAR .. "strui"}, pres_3p = {"stroem", ALTVAR .. "struem"}, -- all occurrences of accented í in endings handled in combine_stem_ending() irreg = true, } }, { -- remaining verbs in -uir (concluir/excluir/incluir/concruir/concruyr, abluir/diluir, afluir/fluir/influir, -- aluir, anuir, atribuir/contribuir/distribuir/redistribuir/retribuir/substituir, coevoluir/evoluir, -- constituir/destituir/instituir/reconstituir/restituir, derruir, diminuir, estatuir, fruir/usufruir, imbuir, -- imiscuir, poluir, possuir, puir, pruir, ruir -- FIXME: old module lists short pp incluso for incluir that can't be verified, ask about this -- FIXME: handle -uyr verbs? match = function(verb) -- Don't match -guir verbs (e.g. [[seguir]], [[conseguir]]) or -quir verbs (e.g. [[extorquir]]) if verb:find("guir$") or verb:find("quir$") then return nil else return match_against_verbs("uir", {""})(verb) end end, forms = { pres_2s = "uis", pres_3s = "ui", -- all occurrences of accented í in endings handled in combine_stem_ending() irreg = true, } }, { -- We want to match advir, convir, devir, etc. but not ouvir, servir, etc. No way to avoid listing each verb. match = match_against_verbs("vir", {"ad", "^a", "con", "contra", "de", "^desa", "inter", "pro", "^re", "sobre", "^"}), forms = { -- FIXME, Estraviz says 'convens', 'devens' etc. but that may be a typo pres_2s = function(base, prefix) return {GL_TYPE .. "vés", PT_TYPE .. (prefix == "" and "vens" or "véns")} end, -- FIXME, Estraviz says 'convem', 'devem' etc. but that may be a typo pres_3s = function(base, prefix) return prefix == "" and "vem" or "vém" end, pres_2p = "vindes", pres_3p = {GL_TYPE .. "venhem", PT_TYPE .. "vêm", GL_ALTVAR .. "vém"}, pres1_and_sub = "venh", full_impf = "vính", pret_conj = "irreg", pret = {GL_TYPE .. "vinhé", PT_TYPE .. "vié"}, pret_1s = "vim", pret_3s = {GL_TYPE .. "véu", PT_TYPE .. "veio"}, pp = {"vindo", "vido"}, irreg = true, } }, -------------------------------------------------------------------------------------------- -- misc -- -------------------------------------------------------------------------------------------- { -- pôr, antepor, apor, compor/decompor/descompor, contrapor, depor, dispor, expor, impor, interpor, justapor, -- opor, pospor, propor, repor, sobrepor, supor/pressupor, transpor, decompor, others? match = "p[oô]r", forms = { pres1_and_sub = "ponh", pres_2s = {GL_TYPE .. "pós", PT_TYPE .. "pões", GL_ALTVAR .. "pons"}, pres_3s = {GL_TYPE .. "pom", PT_TYPE .. "põe"}, pres_1p = "pomos", pres_2p = "pondes", pres_3p = {GL_TYPE .. "ponhem", PT_TYPE .. "põem", GL_ALTVAR .. "póm"}, full_impf = "púnh", pret_conj = "irreg", pret = {GL_TYPE .. "pugé", PT_TYPE .. "pusé"}, pt_pret_1s = "pus", pt_pret_3s = "pôs", pers_inf = "po", gerund = "pondo", pp = "posto", irreg = true, } }, } local function skip_slot(base, slot, allow_overrides) if not allow_overrides and (base.basic_overrides[slot] or base.refl and base.basic_reflexive_only_overrides[slot]) then -- Skip any slots for which there are overrides. return true end if base.only3s and (slot:find("^pp_f") or slot:find("^pp_mp")) then -- diluviar, atardecer, neviscar; impersonal verbs have only masc sing pp return true end if not slot:find("[123]") then -- Don't skip non-personal slots. return false end if base.nofinite then return true end if (base.only3s or base.only3sp or base.only3p) and (slot:find("^imp_") or slot:find("^neg_imp_")) then return true end if base.only3s and not slot:find("3s") then -- diluviar, atardecer, neviscar return true end if base.only3sp and not slot:find("3[sp]") then -- atañer, concernir return true end if base.only3p and not slot:find("3p") then -- [[caer cuatro gotas]], [[caer chuzos de punta]], [[entrarle los siete males]] return true end return false end -- Apply vowel alternations to stem. local function apply_vowel_alternations(stem, alternations) local alternation_stems = {} local saw_pres1_and_sub = false local saw_pres_stressed = false -- Process alternations other than +. for _, altobj in ipairs(alternations) do local alt = altobj.form local pres1_and_sub, pres_stressed, err -- Treat final -gu, -qu as a consonant, so the previous vowel can alternate (e.g. conseguir -> consigo). -- This means a verb in -guar can't have a u-ú alternation but I don't think there are any verbs like that. stem = rsub(stem, "([gq])u$", "%1" .. TEMPC1) if alt == "+" then -- do nothing yet elseif alt == "ei" then local before_last_vowel = rmatch(stem, "^(.*)i$") if not before_last_vowel then err = "stem should end in -i" else pres1_and_sub = nil pres_stressed = before_last_vowel .. "ei" end else local before_last_vowel, last_vowel, after_last_vowel = rmatch(stem, "^(.*)(" .. V .. ")(.-[ui])$") if not before_last_vowel then before_last_vowel, last_vowel, after_last_vowel = rmatch(stem, "^(.*)(" .. V .. ")(.-)$") end if alt == "i-e" then if last_vowel == "e" or last_vowel == "i" then pres1_and_sub = before_last_vowel .. "i" .. after_last_vowel if last_vowel == "i" then pres_stressed = before_last_vowel .. "e" .. after_last_vowel end else err = "should have -e- or -i- as the last vowel" end elseif alt == "i" then if last_vowel == "e" then pres1_and_sub = before_last_vowel .. "i" .. after_last_vowel pres_stressed = pres1_and_sub else err = "should have -e- as the last vowel" end elseif alt == "u-o" then if last_vowel == "o" or last_vowel == "u" then pres1_and_sub = before_last_vowel .. "u" .. after_last_vowel if last_vowel == "u" then pres_stressed = before_last_vowel .. "o" .. after_last_vowel end else err = "should have -o- or -u- as the last vowel" end elseif alt == "u" then if last_vowel == "o" then pres1_and_sub = before_last_vowel .. "u" .. after_last_vowel pres_stressed = pres1_and_sub else err = "should have -o- as the last vowel" end elseif alt == "í" then if last_vowel == "i" then pres_stressed = before_last_vowel .. "í" .. after_last_vowel else err = "should have -i- as the last vowel" end elseif alt == "ú" then if last_vowel == "u" then pres_stressed = before_last_vowel .. "ú" .. after_last_vowel else err = "should have -u- as the last vowel" end else error("Internal error: Unrecognized vowel alternation '" .. alt .. "'") end end if pres1_and_sub then pres1_and_sub = {form = pres1_and_sub:gsub(TEMPC1, "u"), footnotes = altobj.footnotes} saw_pres1_and_sub = true end if pres_stressed then pres_stressed = {form = pres_stressed:gsub(TEMPC1, "u"), footnotes = altobj.footnotes} saw_pres_stressed = true end table.insert(alternation_stems, { altobj = altobj, pres1_and_sub = pres1_and_sub, pres_stressed = pres_stressed, err = err }) end -- Now do +. We check to see which stems are used by other alternations and specify those so any footnotes are -- properly attached. for _, alternation_stem in ipairs(alternation_stems) do if alternation_stem.altobj.form == "+" then local stemobj = {form = stem, footnotes = alternation_stem.altobj.footnotes} alternation_stem.pres1_and_sub = saw_pres1_and_sub and stemobj or nil alternation_stem.pres_stressed = saw_pres_stressed and stemobj or nil end end return alternation_stems end -- Add the `stem` to the `ending` for the given `slot` and apply any phonetic modifications. -- WARNING: This function is written very carefully; changes to it can easily have unintended consequences. local function combine_stem_ending(base, slot, prefix, stem, ending, dont_include_prefix) -- If the stem begins with an acute accent, this is a signal to move the accent onto the last vowel of the prefix. -- Cf. míngua of minguar. if stem:find("^" .. AC) then stem = rsub(stem, "^" .. AC, "") if dont_include_prefix then error("Internal error: Can't handle acute accent at beginning of stem if dont_include_prefix is given") end prefix = rsub(prefix, "([aeiouyAEIOUY])([^aeiouyAEIOUY]*)$", "%1" .. AC .. "%2") end -- Use the full stem for checking for -gui ending and such, because 'stem' is just 'u' for [[arguir]], -- [[delinquir]]. local full_stem = prefix .. stem -- Include the prefix in the stem unless dont_include_prefix is given (used for the past participle stem). if not dont_include_prefix then stem = full_stem end -- If the ending begins with a double asterisk, this is a signal to conditionally delete the accent on the last letter -- of the stem. "Conditionally" means we don't do it if the last two letters would form a diphthong without the accent -- on the second one (e.g. in [[sair]], with stem 'saí'); but as an exception, we do delete the accent in stems -- ending in -guí, -quí (e.g. in [[conseguir]]) because in this case the ui isn't a diphthong. if ending:find("^%*%*") then ending = rsub(ending, "^%*%*", "") if rfind(full_stem, "[gq]uí$") or not rfind(full_stem, V .. "[íú]$") then stem = com.remove_final_accent(stem) end end -- If the ending begins with an asterisk, this is a signal to delete the accent on the last letter of the stem. -- E.g. fizé -> fizermos. Unlike for **, this removal is unconditional, so we get e.g. 'sairmos' not #'saírmos'. if ending:find("^%*") then ending = rsub(ending, "^%*", "") stem = com.remove_final_accent(stem) end -- If ending begins with i, it must get an accent after an unstressed vowel (in some but not all cases) to prevent -- the two merging into a diphthong: -- * cair -> -- * pres: caímos, caís; -- * impf: all forms (caí-); -- * pret: caí (but not caim), caíste (but not caiu), caímos, caístes, caíram; -- * plup: all forms (caír-); -- * impf_sub: all forms (caíss-); -- * fut_sub: caíres, caírem (but not cair, cairmos, cairdes) -- * pp: caído (but not gerund caindo) -- * atribuir, other verbs in -uir -> same pattern as for cair etc. -- * roer -> -- * pret: roí (but not roim) -- * impf: all forms (roí-) -- * pp: roído -- Don't let variant codes derail the following checks. Note that variant codes are properly added to the end of -- the ending, so checks against the beginning of the ending work even in their presence, but not checks against -- the full ending. local cleaned_ending = export.remove_variant_codes(ending) if cleaned_ending:find("^i") and full_stem:find("[aeiou]$") and not full_stem:find("[gq]u$") and not cleaned_ending:find("^i[rum]$") and cleaned_ending ~= "indo" and not cleaned_ending:find("^ir[md]") then ending = ending:gsub("^i", "í") end -- Spelling changes in the stem; it depends on whether the stem given is the pre-front-vowel or -- pre-back-vowel variant, as indicated by `frontback`. We want these front-back spelling changes to happen -- between stem and ending, not between prefix and stem; the prefix may not have the same "front/backness" -- as the stem. local is_front = rfind(ending, "^[eiéíê]") if base.frontback == "front" and not is_front then stem = stem:gsub("c$", "ç") -- conhecer -> conheço, vencer -> venço, descer -> desço stem = stem:gsub("g$", "j") -- proteger -> protejo, fugir -> fujo stem = stem:gsub("gu$", "g") -- distinguir -> distingo, conseguir -> consigo stem = stem:gsub("qu$", "c") -- extorquir -> exturco stem = stem:gsub("([gq])ü$", "%1u") -- argüir (superseded) -> arguo, delinqüir (superseded) -> delinquo elseif base.frontback == "back" and is_front then -- The following changes are all superseded so we don't do them: -- averiguar -> averigüei, minguar -> mingüei; antiquar -> antiqüei, apropinquar -> apropinqüei -- stem = stem:gsub("([gq])u$", "%1ü") stem = stem:gsub("g$", "gu") -- cargar -> carguei, apagar -> apaguei stem = stem:gsub("c$", "qu") -- marcar -> marquei stem = stem:gsub("ç$", "c") -- começar -> comecei -- j does not go to g here; desejar -> deseje not #desege end local retval = stem .. ending if retval:find(GL_TYPE) and retval:find(PT_TYPE) or retval:find(GL_ONLY_TYPE) and not retval:find(GL_TYPE) then -- Reject clashes in "Galician"-type and "Portuguese"-type forms, e.g. '#vós dixéreis' or '#vós dissérades'. return nil end return retval end local function add3(base, slot, stems, endings, footnotes, allow_overrides) if skip_slot(base, slot, allow_overrides) then return end local function do_combine_stem_ending(stem, ending) return combine_stem_ending(base, slot, base.prefix, stem, ending) end iut.add_forms(base.forms, slot, stems, endings, do_combine_stem_ending, nil, nil, footnotes) end local function insert_form(base, slot, form) if not skip_slot(base, slot) then iut.insert_form(base.forms, slot, form) end end local function insert_forms(base, slot, forms) if not skip_slot(base, slot) then iut.insert_forms(base.forms, slot, forms) end end local function add_single_stem_tense(base, slot_pref, stems, s1, s2, s3, p1, p2, p3) local function addit(slot, ending) add3(base, slot_pref .. "_" .. slot, stems, ending) end addit("1s", s1) addit("2s", s2) addit("3s", s3) addit("1p", p1) addit("2p", p2) addit("3p", p3) end local function construct_stems(base, vowel_alt) local stems = {} stems.pres_unstressed = base.stems.pres_unstressed or base.inf_stem stems.pres_stressed = -- If no_pres_stressed given, pres_stressed stem should be empty so no forms are generated. base.no_pres_stressed and {} or base.stems.pres_stressed or vowel_alt.pres_stressed or base.inf_stem stems.pres1_and_sub = -- If no_pres_stressed given, the entire subjunctive is missing. base.no_pres_stressed and {} or -- If no_pres1_and_sub given, pres1 and entire subjunctive are missing. base.no_pres1_and_sub and {} or base.stems.pres1_and_sub or vowel_alt.pres1_and_sub or nil stems.pres1 = base.stems.pres1 or stems.pres1_and_sub or stems.pres_stressed stems.impf = base.stems.impf or base.inf_stem stems.full_impf = base.stems.full_impf stems.pret_base = base.stems.pret_base or base.inf_stem stems.pret_conj = base.stems.pret_conj or base.conj stems.pret = base.stems.pret or iut.map_forms(iut.convert_to_general_list_form(stems.pret_base), function(form) return form .. base.conj_vowel end) stems.gl_short_pret = base.stems.gl_short_pret or iut.map_forms(iut.convert_to_general_list_form(stems.pret), function(form) return rsub(form, com.V .. "$", "") end) stems.pt_pret_1s = base.stems.pt_pret_1s stems.pt_pret_3s = base.stems.pt_pret_3s stems.fut = base.stems.fut or base.inf_stem .. base.conj stems.cond = base.stems.cond or stems.fut stems.pres_sub_stressed = base.stems.pres_sub_stressed or stems.pres1 stems.pres_sub_unstressed = base.stems.pres_sub_unstressed or stems.pres1_and_sub or stems.pres_unstressed stems.sub_conj = base.stems.sub_conj or base.conj stems.plup = base.stems.plup or stems.pret stems.impf_sub = base.stems.impf_sub or stems.pret stems.fut_sub = base.stems.fut_sub or stems.pret stems.pers_inf = base.stems.pers_inf or base.inf_stem .. base.conj_vowel stems.pp = base.stems.pp or base.conj == "ar" and combine_stem_ending(base, "pp_ms", base.prefix, base.inf_stem, "ado", "dont include prefix") or -- use combine_stem_ending esp. so we get roído, caído, etc. combine_stem_ending(base, "pp_ms", base.prefix, base.inf_stem, "ido", "dont include prefix") stems.pp_ms = stems.pp local function masc_to_fem(form) if rfind(form, "o$") then return rsub(form, "o$", "a") else return form end end stems.pp_fs = iut.map_forms(iut.convert_to_general_list_form(stems.pp_ms), masc_to_fem) if base.stems.short_pp then stems.short_pp_ms = base.stems.short_pp stems.short_pp_fs = iut.map_forms(iut.convert_to_general_list_form(stems.short_pp_ms), masc_to_fem) end base.this_stems = stems end local function add_present_indic(base) local stems = base.this_stems local function addit(slot, stems, ending) add3(base, "pres_" .. slot, stems, ending) end local s2, s3, p1, p2, p3 if base.conj == "ar" then s2, s3, p1, p2, p3 = "as", "a", "amos", {"ades" .. GL_TYPE, "ais" .. PT_TYPE}, "am" elseif base.conj == "er" or base.conj == "or" then -- verbs in -por have the present overridden s2, s3, p1, p2, p3 = "es", "e", "emos", {"edes" .. GL_TYPE, "eis" .. PT_TYPE}, "em" elseif base.conj == "ir" then s2, s3, p1, p2, p3 = "es", "e", "imos", {"ides" .. GL_TYPE, "is" .. PT_TYPE}, "em" else error("Internal error: Unrecognized conjugation " .. base.conj) end addit("1s", stems.pres1, "o") addit("2s", stems.pres_stressed, s2) addit("3s", stems.pres_stressed, s3) addit("1p", stems.pres_unstressed, p1) addit("2p", stems.pres_unstressed, p2) addit("3p", stems.pres_stressed, p3) end local function add_present_subj(base) local stems = base.this_stems local function addit(slot, stems, ending) add3(base, "pres_sub_" .. slot, stems, ending) end local s1, s2, s3, p1, p2, p3 if stems.sub_conj == "ar" then s1, s2, s3, p1, p2, p3 = "e", "es", "e", "emos", {"edes" .. GL_TYPE, "eis" .. PT_TYPE}, "em" else s1, s2, s3, p1, p2, p3 = "a", "as", "a", "amos", {"ades" .. GL_TYPE, "ais" .. PT_TYPE}, "am" end addit("1s", stems.pres_sub_stressed, s1) addit("2s", stems.pres_sub_stressed, s2) addit("3s", stems.pres_sub_stressed, s3) addit("1p", stems.pres_sub_unstressed, p1) addit("2p", stems.pres_sub_unstressed, p2) addit("3p", stems.pres_sub_stressed, p3) end local function add_finite_non_present(base) local stems = base.this_stems local function add_tense(slot, stem, s1, s2, s3, p1, p2, p3) add_single_stem_tense(base, slot, stem, s1, s2, s3, p1, p2, p3) end -- * at the beginning of the ending means to remove an accent from the last vowel of the imperfect stem. if stems.full_impf then add_tense("impf", stems.full_impf, "*a", "*as", "*a", "amos", {"ades" .. GL_TYPE, "eis" .. PT_TYPE, "ais" .. GL_ALTVAR}, "*am") elseif base.conj == "ar" then add_tense("impf", stems.impf, "ava", "avas", "ava", "ávamos", {"ávades" .. GL_TYPE, "áveis" .. PT_TYPE, "ávais" .. GL_ALTVAR}, "avam") else add_tense("impf", stems.impf, "ia", "ias", "ia", "íamos", {"íades" .. GL_TYPE, "íeis" .. PT_TYPE, "íais" .. GL_ALTVAR}, "iam") end -- * at the beginning of the ending means to remove a final accent from the preterite stem. if stems.pret_conj == "irreg" then add_tense("pret", stems.gl_short_pret, "em" .. GL_TYPE, nil, "o" .. GL_TYPE) add_tense("pret", stems.pret, nil, {"*ste", "*che" .. GL_ALTVAR}, nil, "*mos", "*stes", {"rom" .. GL_TYPE, "*ram" .. PT_TYPE}) add_tense("pret", stems.pt_pret_1s, PT_TYPE) add_tense("pret", stems.pt_pret_3s, nil, nil, PT_TYPE) elseif stems.pret_conj == "ar" then add_tense("pret", stems.pret_base, "ei", {"aste", "ache" .. GL_ALTVAR}, "ou", "amos", "astes", {"árom" .. GL_TYPE, "aram" .. PT_TYPE}) elseif stems.pret_conj == "er" then add_tense("pret", stems.pret_base, {"im" .. GL_TYPE, "i" .. PT_TYPE}, {"este", "eche" .. GL_ALTVAR}, "eu", "emos", "estes", {"êrom" .. GL_TYPE, "eram" .. PT_TYPE}) else add_tense("pret", stems.pret_base, {"im" .. GL_TYPE, "i" .. PT_TYPE}, {"iste", "iche" .. GL_ALTVAR}, "iu", "imos", "istes", {"írom" .. GL_TYPE, "iram" .. PT_TYPE}) end -- * at the beginning of the ending means to remove a final accent from the stem. -- ** is similar but is "conditional" on a consonant preceding the final vowel. add_tense("plup", stems.plup, "**ra", "**ras", "**ra", "ramos", {"rades" .. GL_TYPE, "reis" .. PT_TYPE, "rais" .. GL_ALTVAR}, "**ram") add_tense("impf_sub", stems.impf_sub, "**sse", "**sses", "**sse", "ssemos", {"ssedes" .. GL_TYPE, "sseis" .. PT_TYPE}, "**ssem") add_tense("fut_sub", stems.fut_sub, "*r", "**res", "*r", "*rmos", "*rdes", "**rem") if base.refl then local mark = TEMP_MESOCLITIC_INSERTION_POINT add_tense("fut", stems.fut, {"ei" .. GL_TYPE, mark .. "ei" .. PT_TYPE}, {"ás" .. GL_TYPE, mark .. "ás" .. PT_TYPE}, {"á" .. GL_TYPE, mark .. "á" .. PT_TYPE}, {"emos" .. GL_TYPE, mark .. "emos" .. PT_TYPE}, {"edes" .. GL_TYPE, mark .. "eis" .. PT_TYPE}, {"ám" .. GL_TYPE, mark .. "ão" .. PT_TYPE} ) add_tense("cond", stems.cond, {"ia" .. GL_TYPE, mark .. "ia" .. PT_TYPE}, {"ias" .. GL_TYPE, mark .. "ias" .. PT_TYPE}, {"ia" .. GL_TYPE, mark .. "ia" .. PT_TYPE}, {"íamos" .. GL_TYPE, mark .. "íamos" .. PT_TYPE}, -- FIXME, is GL_ALTVAR correct for the mesoclitic variant of -íais? {"íades" .. GL_TYPE, mark .. "íeis" .. PT_TYPE, "íais" .. GL_ALTVAR, mark .. "íais" .. GL_ALTVAR}, {"iam" .. GL_TYPE, mark .. "iam" .. PT_TYPE}) else -- Don't insert forms with the mesoclitic insertion point to avoid duplication in non-reflexive verbs. add_tense("fut", stems.fut, "ei", "ás", "á", "emos", {"edes" .. GL_TYPE, "eis" .. PT_TYPE}, {"ám" .. GL_TYPE, "ão" .. PT_TYPE}) add_tense("cond", stems.cond, "ia", "ias", "ia", "íamos", -- FIXME, is GL_ALTVAR correct for the mesoclitic variant of -íais? {"íades" .. GL_TYPE, "íeis" .. PT_TYPE, "íais" .. GL_ALTVAR}, "iam") end -- Different stems for different parts of the personal infinitive to correctly handle forms of [[sair]] and [[pôr]]. add_tense("pers_inf", base.non_prefixed_verb, "", nil, "") add_tense("pers_inf", stems.pers_inf, nil, "**res", nil, "*rmos", "*rdes", "**rem") end local function add_non_finite_forms(base) local stems = base.this_stems local function addit(slot, stems, ending, footnotes) add3(base, slot, stems, ending, footnotes) end insert_form(base, "infinitive", {form = base.verb}) -- Also insert "infinitive + reflexive pronoun" combinations if we're handling a reflexive verb. See comment below for -- "gerund + reflexive pronoun" combinations. if base.refl then for _, persnum in ipairs(person_number_list) do insert_form(base, "infinitive_" .. persnum, {form = base.verb}) end end -- verbs in -por have the gerund overridden local ger_ending = base.conj == "ar" and "ando" or base.conj == "er" and "endo" or "indo" addit("gerund", stems.pres_unstressed, ger_ending) -- Also insert "gerund + reflexive pronoun" combinations if we're handling a reflexive verb. We insert exactly the same -- form as for the bare gerund; later on in add_reflexive_or_fixed_clitic_to_forms(), we add the appropriate clitic -- pronouns. It's important not to do this for non-reflexive verbs, because in that case, the clitic pronouns won't be -- added, and {{gl-reinteg-verb form of}} will wrongly consider all these combinations as possible inflections of the bare -- gerund. Thanks to [[User:JeffDoozan]] for this bug fix. if base.refl then for _, persnum in ipairs(person_number_list) do addit("gerund_" .. persnum, stems.pres_unstressed, ger_ending) end end -- Skip the long/short past participle footnotes if called from {{gl-reinteg-verb}} so they don't show in the headword. local long_pp_footnotes = stems.short_pp_ms and base.alternant_multiword_spec.source_template ~= "gl-reinteg-verb" and {long_pp_footnote} or nil addit("pp_ms", stems.pp_ms, "", long_pp_footnotes) if not base.pp_inv then addit("pp_fs", stems.pp_fs, "", long_pp_footnotes) addit("pp_mp", stems.pp_ms, "s", long_pp_footnotes) addit("pp_fp", stems.pp_fs, "s", long_pp_footnotes) end if stems.short_pp_ms then local short_pp_footnotes = stems.short_pp_ms and base.alternant_multiword_spec.source_template ~= "gl-reinteg-verb" and {short_pp_footnote} or nil addit("short_pp_ms", stems.short_pp_ms, "", short_pp_footnotes) if not base.pp_inv then addit("short_pp_fs", stems.short_pp_fs, "", short_pp_footnotes) addit("short_pp_mp", stems.short_pp_ms, "s", short_pp_footnotes) addit("short_pp_fp", stems.short_pp_fs, "s", short_pp_footnotes) end end end local function copy_forms_to_imperatives(base) -- Copy pres3s to imperative since they are almost always the same. insert_forms(base, "imp_2s", iut.map_forms(base.forms.pres_3s, function(form) return form end)) if not skip_slot(base, "imp_2p") then -- Copy pres2p to imperative 2p minus -s since they are almost always the same. -- But not if there's an override, to avoid possibly throwing an error. insert_forms(base, "imp_2p", iut.map_forms(base.forms.pres_2p, function(form) local form_no_s, var_codes = rmatch(form, "^(.*)s(" .. var_code_c .. "*)$") if not form_no_s then error("Can't derive second-person plural imperative from second-person plural present indicative " .. "because form '" .. form .. "' doesn't end in -s") end return form_no_s .. var_codes end)) end -- Copy subjunctives to imperatives, unless there's an override for the given slot (as with the imp_1p of [[ir]]). for _, persnum in ipairs({"3s", "1p", "3p"}) do local from = "pres_sub_" .. persnum local to = "imp_" .. persnum insert_forms(base, to, iut.map_forms(base.forms[from], function(form) return form end)) end end local function process_slot_overrides(base, filter_slot, reflexive_only) local overrides = reflexive_only and base.basic_reflexive_only_overrides or base.basic_overrides for slot, forms in pairs(overrides) do if not filter_slot or filter_slot(slot) then add3(base, slot, forms, "", nil, "allow overrides") end end end -- Prefix `form` with `clitic`, adding fixed text `between` between them. Add links as appropriate unless the user -- requested no links. Check whether form already has brackets (as will be the case if the form has a fixed clitic). local function prefix_clitic_to_form(base, clitic, between, form) if base.alternant_multiword_spec.args.noautolinkverb then return clitic .. between .. form else local clitic_pref = "[[" .. clitic .. "]]" .. between if form:find("%[%[") then return clitic_pref .. form else return clitic_pref .. "[[" .. form .. "]]" end end end -- Add the appropriate clitic pronouns in `clitics` to the forms in `base_slot`. `store_cliticized_form` is a function -- of three arguments (clitic, formobj, cliticized_form) and should store the cliticized form for the specified clitic -- and form object. local function suffix_clitic_to_forms(base, base_slot, clitics, store_cliticized_form) if not base.forms[base_slot] then -- This can happen, e.g. in only3s/only3sp/only3p verbs. return end local autolink = not base.alternant_multiword_spec.args.noautolinkverb for _, formobj in ipairs(base.forms[base_slot]) do for _, clitic in ipairs(clitics) do local cliticized_form if formobj.form:find(TEMP_MESOCLITIC_INSERTION_POINT) then -- mesoclisis in future and conditional local infinitive, suffix = rmatch(formobj.form, "^(.*)" .. TEMP_MESOCLITIC_INSERTION_POINT .. "(.*)$") if not infinitive then error("Internal error: Can't find mesoclitic insertion point in slot '" .. base_slot .. "', form '" .. formobj.form .. "'") end local full_form = infinitive .. suffix if autolink and not infinitive:find("%[%[") then infinitive = "[[" .. infinitive .. "]]" end cliticized_form = autolink and infinitive .. "-[[" .. clitic .. "]]-[[" .. full_form .. "|" .. suffix .. "]]" or infinitive .. "-" .. clitic .. "-" .. suffix else local clitic_suffix = autolink and "-[[" .. clitic .. "]]" or "-" .. clitic local form_needs_link = autolink and not formobj.form:find("%[%[") if base_slot:find("1p$") then -- Final -s disappears: arrependíamos + nos -> arrependíamo-nos, etc. cliticized_form = formobj.form:gsub("s$", "") if form_needs_link then cliticized_form = "[[" .. formobj.form .. "|" .. cliticized_form .. "]]" end else cliticized_form = formobj.form if form_needs_link then cliticized_form = "[[" .. cliticized_form .. "]]" end end cliticized_form = cliticized_form .. clitic_suffix end store_cliticized_form(clitic, formobj, cliticized_form) end end end -- Add a reflexive pronoun or fixed clitic (FIXME: not working), as appropriate to the base forms that were generated. -- `do_joined` means to do only the forms where the pronoun is joined to the end of the form; otherwise, do only the -- forms where it is not joined and precedes the form. local function add_reflexive_or_fixed_clitic_to_forms(base, do_reflexive, do_joined) for _, slotaccel in ipairs(base.alternant_multiword_spec.verb_slots_basic) do local slot, accel = unpack(slotaccel) local clitic if not do_reflexive then clitic = base.clitic elseif slot:find("[123]") then local persnum = slot:match("^.*_(.-)$") clitic = person_number_to_reflexive_pronoun[persnum] else clitic = "se" end if base.forms[slot] then if do_reflexive and slot:find("^pp_") or slot == "infinitive_linked" then -- do nothing with reflexive past participles or with infinitive linked (handled at the end) elseif slot:find("^neg_imp_") then error("Internal error: Should not have forms set for negative imperative at this stage") else local slot_has_suffixed_clitic = not slot:find("_sub") -- Maybe generate non-reflexive parts and separated syntactic variants for use in -- {{gl-reinteg-verb form of}}. See comment in add_slots() above `need_special_verb_form_of_slots`. -- Check for do_joined so we only run this code once. if do_reflexive and do_joined and base.alternant_multiword_spec.source_template == "gl-reinteg-verb form of" and -- Skip personal variants of infinitives and gerunds so we don't think [[arrependendo]] is a -- non-reflexive equivalent of [[arrependendo-me]]. not slot:find("infinitive_") and not slot:find("gerund_") then -- Clone the forms because we will be destructively modifying them just below, adding the reflexive -- pronoun. insert_forms(base, slot .. "_non_reflexive", mw.clone(base.forms[slot])) if slot_has_suffixed_clitic then insert_forms(base, slot .. "_variant", iut.map_forms(base.forms[slot], function(form) return prefix_clitic_to_form(base, clitic, " ... ", form) end)) end end if slot_has_suffixed_clitic then if do_joined then suffix_clitic_to_forms(base, slot, {clitic}, function(clitic, formobj, cliticized_form) formobj.form = cliticized_form end ) end elseif not do_joined then -- Add clitic as separate word before all other forms. for _, form in ipairs(base.forms[slot]) do form.form = prefix_clitic_to_form(base, clitic, " ", form.form) end end end end end end local function handle_infinitive_linked(base) -- Compute linked versions of potential lemma slots, for use in {{gl-reinteg-verb}}. -- We substitute the original lemma (before removing links) for forms that -- are the same as the lemma, if the original lemma has links. for _, slot in ipairs({"infinitive"}) do insert_forms(base, slot .. "_linked", iut.map_forms(base.forms[slot], function(form) if form == base.lemma and rfind(base.linked_lemma, "%[%[") then return base.linked_lemma else return form end end)) end end local function generate_negative_imperatives(base) -- Copy subjunctives to negative imperatives, preceded by "nom". for _, persnum in ipairs(neg_imp_person_number_list) do local from = "pres_sub_" .. persnum local to = "neg_imp_" .. persnum insert_forms(base, to, iut.map_forms(base.forms[from], function(form) if base.alternant_multiword_spec.args.noautolinkverb then return "nom " .. form elseif form:find("%[%[") then -- already linked, e.g. when reflexive return "[[nom]] " .. form else return "[[nom]] [[" .. form .. "]]" end end)) end end -- Process specs given by the user using 'addnote[SLOTSPEC][FOOTNOTE][FOOTNOTE][...]'. local function process_addnote_specs(base) for _, spec in ipairs(base.addnote_specs) do for _, slot_spec in ipairs(spec.slot_specs) do slot_spec = "^" .. slot_spec .. "$" for slot, forms in pairs(base.forms) do if rfind(slot, slot_spec) then -- To save on memory, side-effect the existing forms. for _, form in ipairs(forms) do form.footnotes = iut.combine_footnotes(form.footnotes, spec.footnotes) end end end end end end local function add_missing_links_to_forms(base) -- Any forms without links should get them now. Redundant ones will be stripped later. for slot, forms in pairs(base.forms) do for _, form in ipairs(forms) do if not form.form:find("%[%[") then form.form = "[[" .. form.form .. "]]" end end end end -- Remove special characters added to future and conditional forms to indicate mesoclitic insertion points. local function remove_mesoclitic_insertion_points(base) for slot, forms in pairs(base.forms) do if slot:find("^fut_") or slot:find("^cond_") then for _, form in ipairs(forms) do form.form = form.form:gsub(TEMP_MESOCLITIC_INSERTION_POINT, "") end end end end -- If called from {{gl-reinteg-verb}}, remove less-recommended variants; otherwise add a footnote indicating they are -- less recommended, and sort them last. local function process_altvar_forms(base) for slot, forms in pairs(base.forms) do -- As an optimization, check if there are any less-recommended forms and don't do anything if not. local saw_altvar = false for _, form in ipairs(forms) do if form.form:find(ALTVAR) then saw_altvar = true break end end if saw_altvar then if base.alternant_multiword_spec.source_template == "gl-reinteg-verb" then base.forms[slot] = iut.flatmap_forms(base.forms[slot], function(form) if form:find(ALTVAR) then return {} else return {form} end end) else local existing_forms = base.forms[slot] base.forms[slot] = {} for _, formobj in ipairs(existing_forms) do if not formobj.form:find(ALTVAR) then iut.insert_form(base.forms, slot, formobj) end end for _, formobj in ipairs(existing_forms) do if formobj.form:find(ALTVAR) then formobj.footnotes = iut.combine_footnotes(formobj.footnotes, {"[less recommended]"}) iut.insert_form(base.forms, slot, formobj) end end end end end end local function conjugate_verb(base) for _, vowel_alt in ipairs(base.vowel_alt_stems) do construct_stems(base, vowel_alt) add_present_indic(base) add_present_subj(base) end add_finite_non_present(base) add_non_finite_forms(base) -- do non-reflexive non-imperative slot overrides process_slot_overrides(base, function(slot) return not slot:find("^imp_") and not slot:find("^neg_imp_") end) -- This should happen after process_slot_overrides() in case a derived slot is based on an override -- (as with the imp_3s of [[dar]], [[estar]]). copy_forms_to_imperatives(base) -- do non-reflexive positive imperative slot overrides process_slot_overrides(base, function(slot) return slot:find("^imp_") end) -- We need to add joined reflexives, then joined and non-joined clitics, then non-joined reflexives, so we get -- [[arrepende-te]] but [[nom]] [[te]] [[arrependas]]. if base.refl then add_reflexive_or_fixed_clitic_to_forms(base, "do reflexive", "do joined") process_slot_overrides(base, nil, "do reflexive") -- do reflexive-only slot overrides add_reflexive_or_fixed_clitic_to_forms(base, "do reflexive", false) end -- This should happen after add_reflexive_or_fixed_clitic_to_forms() so negative imperatives get the reflexive pronoun -- and clitic in them. generate_negative_imperatives(base) -- do non-reflexive negative imperative slot overrides -- FIXME: What about reflexive negative imperatives? process_slot_overrides(base, function(slot) return slot:find("^neg_imp_") end) -- This should happen before add_missing_links_to_forms() so that the comparison `form == base.lemma` -- in handle_infinitive_linked() works correctly and compares unlinked forms to unlinked forms. handle_infinitive_linked(base) process_addnote_specs(base) if not base.alternant_multiword_spec.args.noautolinkverb then add_missing_links_to_forms(base) end remove_mesoclitic_insertion_points(base) process_altvar_forms(base) end local function parse_indicator_spec(angle_bracket_spec) -- Store the original angle bracket spec so we can reconstruct the overall conj spec with the lemma(s) in them. local base = { angle_bracket_spec = angle_bracket_spec, user_basic_overrides = {}, user_stems = {}, addnote_specs = {}, } local function parse_err(msg) error(msg .. ": " .. angle_bracket_spec) end local function fetch_footnotes(separated_group) 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 inside = angle_bracket_spec:match("^<(.*)>$") assert(inside) if inside == "" then return base end local segments = put.parse_balanced_segment_run(inside, "[", "]") local dot_separated_groups = put.split_alternating_runs(segments, "%.") for i, dot_separated_group in ipairs(dot_separated_groups) do local first_element = dot_separated_group[1] if first_element == "addnote" then local spec_and_footnotes = fetch_footnotes(dot_separated_group) if #spec_and_footnotes < 2 then parse_err("Spec with 'addnote' should be of the form 'addnote[SLOTSPEC][FOOTNOTE][FOOTNOTE][...]'") end local slot_spec = table.remove(spec_and_footnotes, 1) local slot_spec_inside = rmatch(slot_spec, "^%[(.*)%]$") if not slot_spec_inside then parse_err("Internal error: slot_spec " .. slot_spec .. " should be surrounded with brackets") end local slot_specs = rsplit(slot_spec_inside, ",") -- FIXME: Here, [[Module:it-verb]] called strip_spaces(). Generally we don't do this. Should we? table.insert(base.addnote_specs, {slot_specs = slot_specs, footnotes = spec_and_footnotes}) elseif indicator_flags[first_element] then if #dot_separated_group > 1 then parse_err("No footnotes allowed with '" .. first_element .. "' spec") end if base[first_element] then parse_err("Spec '" .. first_element .. "' specified twice") end base[first_element] = true elseif rfind(first_element, ":") then local colon_separated_groups = put.split_alternating_runs(dot_separated_group, "%s*:%s*") local first_element = colon_separated_groups[1][1] if #colon_separated_groups[1] > 1 then parse_err("Can't attach footnotes directly to '" .. first_element .. "' spec; attach them to the " .. "colon-separated values following the initial colon") end if overridable_stems[first_element] then if base.user_stems[first_element] then parse_err("Overridable stem '" .. first_element .. "' specified twice") end table.remove(colon_separated_groups, 1) base.user_stems[first_element] = overridable_stems[first_element](colon_separated_groups, {prefix = first_element, base = base, parse_err = parse_err, fetch_footnotes = fetch_footnotes}) else -- assume a basic override; we validate further later when the possible slots are available if base.user_basic_overrides[first_element] then parse_err("Basic override '" .. first_element .. "' specified twice") end table.remove(colon_separated_groups, 1) base.user_basic_overrides[first_element] = allow_multiple_values(colon_separated_groups, {prefix = first_element, base = base, parse_err = parse_err, fetch_footnotes = fetch_footnotes}) end else local comma_separated_groups = put.split_alternating_runs(dot_separated_group, "%s*,%s*") for j = 1, #comma_separated_groups do local alt = comma_separated_groups[j][1] if not vowel_alternants[alt] then if #comma_separated_groups == 1 then parse_err("Unrecognized spec or vowel alternant '" .. alt .. "'") else parse_err("Unrecognized vowel alternant '" .. alt .. "'") end end if base.vowel_alt then for _, existing_alt in ipairs(base.vowel_alt) do if existing_alt.form == alt then parse_err("Vowel alternant '" .. alt .. "' specified twice") end end else base.vowel_alt = {} end table.insert(base.vowel_alt, {form = alt, footnotes = fetch_footnotes(comma_separated_groups[j])}) end end end return base end -- Normalize all lemmas, substituting the pagename for blank lemmas and adding links to multiword lemmas. local function normalize_all_lemmas(alternant_multiword_spec, head) -- (1) Add links to all before and after text. Remember the original text so we can reconstruct the verb spec later. if not alternant_multiword_spec.args.noautolinktext then iut.add_links_to_before_and_after_text(alternant_multiword_spec, "remember original") end -- (2) Remove any links from the lemma, but remember the original form -- so we can use it below in the 'lemma_linked' form. iut.map_word_specs(alternant_multiword_spec, function(base) if base.lemma == "" then base.lemma = head end base.user_specified_lemma = base.lemma base.lemma = m_links.remove_links(base.lemma) local refl_verb = base.lemma local verb, refl = rmatch(refl_verb, "^(.-)%-(se)$") if not verb then verb, refl = refl_verb, nil end base.user_specified_verb = verb base.refl = refl base.verb = base.user_specified_verb local linked_lemma if alternant_multiword_spec.args.noautolinkverb or base.user_specified_lemma:find("%[%[") then linked_lemma = base.user_specified_lemma elseif base.refl then -- Reconstruct the linked lemma with separate links around base verb and reflexive pronoun. linked_lemma = base.user_specified_verb == base.verb and "[[" .. base.user_specified_verb .. "]]" or "[[" .. base.verb .. "|" .. base.user_specified_verb .. "]]" linked_lemma = linked_lemma .. (refl and "-[[" .. refl .. "]]" or "") else -- Add links to the lemma so the user doesn't specifically need to, since we preserve -- links in multiword lemmas and include links in non-lemma forms rather than allowing -- the entire form to be a link. linked_lemma = iut.add_links(base.user_specified_lemma) end base.linked_lemma = linked_lemma end) end local function detect_indicator_spec(base) if (base.only3s and 1 or 0) + (base.only3sp and 1 or 0) + (base.only3p and 1 or 0) > 1 then error("Only one of 'only3s', 'only3sp' and 'only3p' can be specified") end base.forms = {} base.stems = {} base.basic_overrides = {} base.basic_reflexive_only_overrides = {} if not base.no_built_in then for _, built_in_conj in ipairs(built_in_conjugations) do if type(built_in_conj.match) == "function" then base.prefix, base.non_prefixed_verb = built_in_conj.match(base.verb) elseif built_in_conj.match:find("^%^") and rsub(built_in_conj.match, "^%^", "") == base.verb then -- begins with ^, for exact match, and matches base.prefix, base.non_prefixed_verb = "", base.verb else base.prefix, base.non_prefixed_verb = rmatch(base.verb, "^(.*)(" .. built_in_conj.match .. ")$") end if base.prefix then -- we found a built-in verb for stem, forms in pairs(built_in_conj.forms) do if type(forms) == "function" then forms = forms(base, base.prefix) end if stem:find("^refl_") then stem = stem:gsub("^refl_", "") if not base.alternant_multiword_spec.verb_slots_basic_map[stem] then error("Internal error: setting for 'refl_" .. stem .. "' does not refer to a basic verb slot") end base.basic_reflexive_only_overrides[stem] = forms elseif base.alternant_multiword_spec.verb_slots_basic_map[stem] then -- an individual form override of a basic form base.basic_overrides[stem] = forms else base.stems[stem] = forms end end break end end end -- Override built-in-verb stems and overrides with user-specified ones. for stem, values in pairs(base.user_stems) do base.stems[stem] = values end for override, values in pairs(base.user_basic_overrides) do if not base.alternant_multiword_spec.verb_slots_basic_map[override] then error("Unrecognized override '" .. override .. "': " .. base.angle_bracket_spec) end base.basic_overrides[override] = values end base.prefix = base.prefix or "" base.non_prefixed_verb = base.non_prefixed_verb or base.verb local inf_stem, suffix = rmatch(base.non_prefixed_verb, "^(.*)([aeioô]r)$") if not inf_stem then error("Unrecognized infinitive: " .. base.verb) end base.inf_stem = inf_stem suffix = suffix == "ôr" and "or" or suffix base.conj = suffix base.conj_vowel = suffix == "ar" and "á" or suffix == "ir" and "í" or "ê" base.frontback = suffix == "ar" and "back" or "front" if base.stems.vowel_alt then -- built-in verb with specified vowel alternation if base.vowel_alt then error(base.verb .. " is a recognized built-in verb, and should not have vowel alternations specified with it") end base.vowel_alt = iut.convert_to_general_list_form(base.stems.vowel_alt) end -- Propagate built-in-verb indicator flags to `base` and combine with user-specified flags. for indicator_flag, _ in pairs(indicator_flags) do base[indicator_flag] = base[indicator_flag] or base.stems[indicator_flag] end -- Convert vowel alternation indicators into stems. local vowel_alt = base.vowel_alt or {{form = "+"}} base.vowel_alt_stems = apply_vowel_alternations(base.inf_stem, vowel_alt) for _, vowel_alt_stems in ipairs(base.vowel_alt_stems) do if vowel_alt_stems.err then error("To use '" .. vowel_alt_stems.altobj.form .. "', present stem '" .. base.prefix .. base.inf_stem .. "' " .. vowel_alt_stems.err) end end end local function detect_all_indicator_specs(alternant_multiword_spec) -- Propagate some settings up; some are used internally, others by [[Module:gl-headword]]. iut.map_word_specs(alternant_multiword_spec, function(base) -- Internal indicator flags. Do these before calling detect_indicator_spec() because add_slots() uses them. for _, prop in ipairs { "refl", "clitic" } do if base[prop] then alternant_multiword_spec[prop] = true end end base.alternant_multiword_spec = alternant_multiword_spec end) add_slots(alternant_multiword_spec) alternant_multiword_spec.vowel_alt = {} iut.map_word_specs(alternant_multiword_spec, function(base) detect_indicator_spec(base) -- User-specified indicator flags. Do these after calling detect_indicator_spec() because the latter may set these -- indicators for built-in verbs. for prop, _ in pairs(indicator_flags) do if base[prop] then alternant_multiword_spec[prop] = true end end -- Vowel alternants. Do these after calling detect_indicator_spec() because the latter sets base.vowel_alt for -- built-in verbs. if base.vowel_alt then for _, altobj in ipairs(base.vowel_alt) do m_table.insertIfNot(alternant_multiword_spec.vowel_alt, altobj.form) end end end) end local function add_categories_and_annotation(alternant_multiword_spec, base, multiword_lemma) local function insert_ann(anntype, value) m_table.insertIfNot(alternant_multiword_spec.annotation[anntype], value) end local function insert_cat(cat, also_when_multiword) -- Don't place multiword terms in categories like 'Galician verbs ending in -ar' to avoid spamming the -- categories with such terms. if also_when_multiword or not multiword_lemma then -- m_table.insertIfNot(alternant_multiword_spec.categories, "Galician " .. cat) end end if check_for_red_links and alternant_multiword_spec.source_template == "gl-reinteg-conj" and multiword_lemma then for _, slot_and_accel in ipairs(alternant_multiword_spec.all_verb_slots) do local slot = slot_and_accel[1] local forms = base.forms[slot] local must_break = false if forms then for _, form in ipairs(forms) do if not form.form:find("%[%[") then local title = mw.title.new(form.form) if title and not title.exists then -- insert_cat("verbs with red links in their inflection tables") must_break = true break end end end end if must_break then break end end end if(base.conj == "or") then -- insert_cat("verbs ending in -er") else -- insert_cat("verbs ending in -" .. base.conj) end if base.irreg then insert_ann("irreg", "irregular") -- insert_cat("irregular verbs") else insert_ann("irreg", "regular") end if base.only3s then insert_ann("defective", "impersonal") -- insert_cat("impersonal verbs") elseif base.only3sp then insert_ann("defective", "third-person only") -- insert_cat("third-person-only verbs") elseif base.only3p then insert_ann("defective", "third-person plural only") -- insert_cat("third-person-plural-only verbs") elseif base.no_pres_stressed or base.no_pres1_and_sub then insert_ann("defective", "defective") -- insert_cat("defective verbs") else insert_ann("defective", "regular") end if base.stems.short_pp then insert_ann("short_pp", "irregular short past participle") -- insert_cat("verbs with irregular short past participle") else insert_ann("short_pp", "regular") end if base.clitic then -- insert_cat("verbs with lexical clitics") end if base.refl then -- insert_cat("reflexive verbs") end if base.e_ei_cat then insert_ann("vowel_alt", "''e'' may become ''ei'' when stressed") -- insert_cat("verbs with e becoming ei when stressed") elseif not base.vowel_alt then insert_ann("vowel_alt", "non-alternating") else for _, alt in ipairs(base.vowel_alt) do if alt.form == "+" then insert_ann("vowel_alt", "non-alternating") else insert_ann("vowel_alt", vowel_alternant_to_desc[alt.form]) -- insert_cat("verbs with " .. vowel_alternant_to_cat[alt.form]) end end end local cons_alt = base.stems.cons_alt if cons_alt == nil then if base.conj == "ar" then if base.inf_stem:find("ç$") then cons_alt = "c-ç" elseif base.inf_stem:find("c$") then cons_alt = "c-qu" elseif base.inf_stem:find("g$") then cons_alt = "g-gu" end else if base.no_pres_stressed or base.no_pres1_and_sub then cons_alt = nil -- no e.g. c-ç alternation in this case elseif base.inf_stem:find("c$") then cons_alt = "c-ç" elseif base.inf_stem:find("qu$") then cons_alt = "c-qu" elseif base.inf_stem:find("g$") then cons_alt = "g-j" elseif base.inf_stem:find("gu$") then cons_alt = "g-gu" end end end if cons_alt then local desc = cons_alt .. " alternation" insert_ann("cons_alt", desc) -- insert_cat("verbs with " .. desc) else insert_ann("cons_alt", "non-alternating") end end -- Compute the categories to add the verb to, as well as the annotation to display in the -- conjugation title bar. We combine the code to do these functions as both categories and -- title bar contain similar information. local function compute_categories_and_annotation(alternant_multiword_spec) alternant_multiword_spec.categories = {} local ann = {} alternant_multiword_spec.annotation = ann ann.irreg = {} ann.short_pp = {} ann.defective = {} ann.vowel_alt = {} ann.cons_alt = {} local multiword_lemma = false for _, form in ipairs(alternant_multiword_spec.forms.infinitive) do if form.form:find(" ") then multiword_lemma = true break end end iut.map_word_specs(alternant_multiword_spec, function(base) add_categories_and_annotation(alternant_multiword_spec, base, multiword_lemma) end) local ann_parts = {} local irreg = table.concat(ann.irreg, " or ") if irreg ~= "" and irreg ~= "regular" then table.insert(ann_parts, irreg) end local short_pp = table.concat(ann.short_pp, " or ") if short_pp ~= "" and short_pp ~= "regular" then table.insert(ann_parts, short_pp) end local defective = table.concat(ann.defective, " or ") if defective ~= "" and defective ~= "regular" then table.insert(ann_parts, defective) end local vowel_alt = table.concat(ann.vowel_alt, " or ") if vowel_alt ~= "" and vowel_alt ~= "non-alternating" then table.insert(ann_parts, vowel_alt) end local cons_alt = table.concat(ann.cons_alt, " or ") if cons_alt ~= "" and cons_alt ~= "non-alternating" then table.insert(ann_parts, cons_alt) end alternant_multiword_spec.annotation = table.concat(ann_parts, "; ") end local function show_forms(alternant_multiword_spec) local lemmas = alternant_multiword_spec.forms.infinitive alternant_multiword_spec.lemmas = lemmas -- save for later use in make_table() if alternant_multiword_spec.forms.short_pp_ms then alternant_multiword_spec.has_short_pp = true end local reconstructed_verb_spec = iut.reconstruct_original_spec(alternant_multiword_spec) local function transform_accel_obj(slot, formobj, accel_obj) -- No accelerators for negative imperatives, which are always multiword and derived directly from the -- present subjunctive. if slot:find("^neg_imp") then return nil end if accel_obj then if slot:find("^pp_") then accel_obj.form = slot elseif slot == "gerund" then accel_obj.form = "reinteg-gerund-" .. reconstructed_verb_spec else accel_obj.form = "reinteg-verb-form-" .. reconstructed_verb_spec end end return accel_obj end -- Italicize less-recommended forms. local function generate_link(data) local formval_for_link = data.form.formval_for_link if formval_for_link:find(ALTVAR) then formval_for_link = formval_for_link:gsub(ALTVAR, "") return m_links.full_link({lang = lang, term = formval_for_link, tr = "-", accel = data.form.accel_obj}, "term") .. iut.get_footnote_text(data.form.footnotes, data.footnote_obj) end end local props = { lang = lang, lemmas = lemmas, transform_accel_obj = transform_accel_obj, canonicalize = function(form) return export.remove_variant_codes(form, "keep altvar") end, generate_link = generate_link, slot_list = alternant_multiword_spec.verb_slots_basic, } iut.show_forms(alternant_multiword_spec.forms, props) alternant_multiword_spec.footnote_basic = alternant_multiword_spec.forms.footnote end local notes_template = [=[ <div class="roa-footnote-outer-div" style="width:100%;"> <div class="roa-footnote-inner-div"> {footnote} </div></div> ]=] local basic_table = [=[ {description}<div class="NavFrame"> <div class="NavHead" align=center>&nbsp; &nbsp; သမ္ဗန္ဓမကလေၚ်လုပ်အဝေါၚ်မွဲဝါဆေၚ်စပ်ကဵု {title} (ဗဵုရံၚ် [[:en:Appendix:Reintegrationism]])</div> <div class="NavContent" align="left"> {\op}| class="roa-inflection-table" data-toggle-category="inflection" |- ! class="roa-person-number-header" rowspan="2" | ! class="roa-person-number-header" colspan="3" | ကိုန်ဨကဝုစ် ! class="roa-person-number-header" colspan="3" | ကိုန်ဗဟုဝစ် |- ! class="roa-person-number-header" style="width:12.5%" | ပူဂဵုပထမ<br />(<<eu>>) ! class="roa-person-number-header" style="width:12.5%" | ပူဂဵုဒုတိယ<br />(<<ti>> / <<tu>>) ! class="roa-person-number-header" style="width:12.5%" | ပူဂဵုတတိယ<br />(<<ele>> / <<ela>> / <<você>>) ! class="roa-person-number-header" style="width:12.5%" | ပူဂဵုပထမ<br />(<<nós>>) ! class="roa-person-number-header" style="width:12.5%" | ပူဂဵုဒုတိယ<br />(<<vós>>) ! class="roa-person-number-header" style="width:12.5%" | ပူဂဵုတတိယ<br />(<<eles>> / <<elas>> / <<vocês>>) |- ! class="roa-nonfinite-header" colspan="7" | ''<span title="infinitivo">ကြိယာဟွံကၠောံ</span>'' |- ! class="roa-nonfinite-header" | '''<span title="infinitivo impessoal">ဟွံဆေၚ်စပ်ပရေၚ်ပူဂဵု</span>''' | colspan="6" | {infinitive} |- ! class="roa-nonfinite-header" | '''<span title="infinitivo flexionado">ပရေၚ်ပူဂဵု</span>''' | {pers_inf_1s} | {pers_inf_2s} | {pers_inf_3s} | {pers_inf_1p} | {pers_inf_2p} | {pers_inf_3p} |- ! class="roa-nonfinite-header" colspan="7" | ''<span title="gerúndio">ကြိယာစၞးနာမ်</span>'' |- | class="roa-nonfinite-header" | | colspan="6" | {gerund} |-{pp_clause} ! class="roa-indicative-left-rail" colspan="7" | ''<span title="indicativo">ပရေၚ်စၞောန်ထ္ၜး</span>'' |- ! class="roa-indicative-left-rail" | <span title="presente">ပစ္စုပ္ပန်</span> | {pres_1s} | {pres_2s} | {pres_3s} | {pres_1p} | {pres_2p} | {pres_3p} |- ! class="roa-indicative-left-rail" | <span title="pretérito imperfeito">ဟွံဍိုက်ပေၚ်</span> | {impf_1s} | {impf_2s} | {impf_3s} | {impf_1p} | {impf_2p} | {impf_3p} |- ! class="roa-indicative-left-rail" | <span title="pretérito perfeito">ကာလအတိက်</span> | {pret_1s} | {pret_2s} | {pret_3s} | {pret_1p} | {pret_2p} | {pret_3p} |- ! class="roa-indicative-left-rail" | <span title="pretérito mais-que-perfeito simples">ဗီုပြၚ်မဍိုက်ပေၚ်</span> | {plup_1s} | {plup_2s} | {plup_3s} | {plup_1p} | {plup_2p} | {plup_3p} |- ! class="roa-indicative-left-rail" | <span title="futuro do presente">အနာဂတ်</span> | {fut_1s} | {fut_2s} | {fut_3s} | {fut_1p} | {fut_2p} | {fut_3p} |- ! class="roa-indicative-left-rail" | <span title="condicional">တၚ်မကၞာတ်လဝ်စေဝ်ပၞောန်</span> | {cond_1s} | {cond_2s} | {cond_3s} | {cond_1p} | {cond_2p} | {cond_3p} |- ! class="roa-subjunctive-left-rail" colspan="7" | ''<span title="conjuntivo">အရေဝ်နိဒါန်</span>'' |- ! class="roa-subjunctive-left-rail" | <span title=" presente do conjuntivo">ပစ္စုပ္ပန်</span> | {pres_sub_1s} | {pres_sub_2s} | {pres_sub_3s} | {pres_sub_1p} | {pres_sub_2p} | {pres_sub_3p} |- ! class="roa-subjunctive-left-rail" | <span title="pretérito imperfeito do conjuntivo">ဟွံဍိုက်ပေၚ်</span> | {impf_sub_1s} | {impf_sub_2s} | {impf_sub_3s} | {impf_sub_1p} | {impf_sub_2p} | {impf_sub_3p} |- ! class="roa-subjunctive-left-rail" | <span title="futuro do conjuntivo">အနာဂတ်</span> | {fut_sub_1s} | {fut_sub_2s} | {fut_sub_3s} | {fut_sub_1p} | {fut_sub_2p} | {fut_sub_3p} |- ! class="roa-imperative-left-rail" colspan="7" | ''<span title="imperativo">ပါဲဗလေတ်ဟွံဗၠး</span>'' |- ! class="roa-imperative-left-rail" | <span title="imperativo afirmativo">တၚ်ဂလာန်ဗိုန်ဗတ်</span> | rowspan="2" | | {imp_2s} | {imp_3s} | {imp_1p} | {imp_2p} | {imp_3p} |- ! class="roa-imperative-left-rail" | <span title="imperativo negativo">ဗဳဇဂကူ</span> (<<nom>>) | {neg_imp_2s} | {neg_imp_3s} | {neg_imp_1p} | {neg_imp_2p} | {neg_imp_3p} |{\cl}{notes_clause}</div></div> ]=] local double_pp_template = [=[ ! class="roa-nonfinite-header" colspan="7" | ''<span title="particípio irregular">လုပ်ကၠောန်စွံလဝ်နကဵုအတိက်ဗွဲမဓမၠေံ</span>'' |- ! class="roa-nonfinite-header" | ပုလ္လိၚ် | colspan="3" | {short_pp_ms} | colspan="3" | {short_pp_mp} |- ! class="roa-nonfinite-header" | ဣတ္တိလိၚ် | colspan="3" | {short_pp_fs} | colspan="3" | {short_pp_fp} |- ! class="roa-nonfinite-header" colspan="7" | ''<span title="particípio regular">လုပ်ကၠောန်စွံလဝ်နကဵုအတိက်ဗွဲမဂပ်လံ</span>'' |- ! class="roa-nonfinite-header" | ပုလ္လိၚ် | colspan="3" | {pp_ms} | colspan="3" | {pp_mp} |- ! class="roa-nonfinite-header" | ဣတ္တိလိၚ် | colspan="3" | {pp_fs} | colspan="3" | {pp_fp} |-]=] local single_pp_template = [=[ ! class="roa-nonfinite-header" colspan="7" | ''<span title="particípio passado">လုပ်ကၠောန်စွံလဝ်နကဵုအတိက်</span>'' |- ! class="roa-nonfinite-header" | ပုလ္လိၚ် | colspan="3" | {pp_ms} | colspan="3" | {pp_mp} |- ! class="roa-nonfinite-header" | ဣတ္တိလိၚ် | colspan="3" | {pp_fs} | colspan="3" | {pp_fp} |-]=] local function make_table(alternant_multiword_spec) local forms = alternant_multiword_spec.forms forms.title = link_term(alternant_multiword_spec.lemmas[1].form) if alternant_multiword_spec.annotation ~= "" then forms.title = forms.title .. " (" .. alternant_multiword_spec.annotation .. ")" end forms.description = "" -- Format the table. forms.footnote = alternant_multiword_spec.footnote_basic forms.notes_clause = forms.footnote ~= "" and m_string_utilities.format(notes_template, forms) or "" -- has_short_pp is computed in show_forms(). local pp_template = alternant_multiword_spec.has_short_pp and double_pp_template or single_pp_template forms.pp_clause = m_string_utilities.format(pp_template, forms) local table_with_pronouns = rsub(basic_table, "<<(.-)>>", link_term) return require("Module:TemplateStyles")("Module:roa-verb/style.css") .. m_string_utilities.format(table_with_pronouns, forms) end -- Externally callable function to parse and conjugate a verb given user-specified arguments. -- Return value is WORD_SPEC, an object where the conjugated forms are in `WORD_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(args, source_template, headword_head) local PAGENAME = mw.loadData("Module:headword/data").pagename local function in_template_space() return mw.title.getCurrentTitle().nsText == "ထာမ်ပလိက်" end -- Determine the verb spec we're being asked to generate the conjugation of. This may be taken from the -- current page title or the value of |pagename=; but not when called from {{gl-reinteg-verb form of}}, where the -- page title is a non-lemma form. Note that the verb spec may omit the infinitive; e.g. it may be "<i-e>". -- For this reason, we use the value of `pagename` computed here down below, when calling normalize_all_lemmas(). local pagename = source_template ~= "gl-reinteg-verb form of" and args.pagename or PAGENAME local head = headword_head or pagename local arg1 = args[1] if not arg1 then if (pagename == "gl-reinteg-conj" or pagename == "gl-reinteg-verb") and in_template_space() then arg1 = "traguer" elseif pagename == "gl-reinteg-verb form of" and in_template_space() then arg1 = "amar" else arg1 = "<>" end end -- When called from {{gl-reinteg-verb form of}}, determine the non-lemma form whose inflections we're being asked to -- determine. This normally comes from the page title or the value of |pagename=. local verb_form_of_form if source_template == "gl-reinteg-verb form of" then verb_form_of_form = args.pagename if not verb_form_of_form then if PAGENAME == "gl-reinteg-verb form of" and in_template_space() then verb_form_of_form = "ame" else verb_form_of_form = PAGENAME end end end local incorporated_headword_head_into_lemma = false if arg1:find("^<.*>$") then -- missing lemma if head:find(" ") then -- If multiword lemma, try to add arg spec after the first word. -- Try to preserve the brackets in the part after the verb, but don't do it -- if there aren't the same number of left and right brackets in the verb -- (which means the verb was linked as part of a larger expression). local refl_clitic_verb, post = rmatch(head, "^(.-)( .*)$") local left_brackets = rsub(refl_clitic_verb, "[^%[]", "") local right_brackets = rsub(refl_clitic_verb, "[^%]]", "") if #left_brackets == #right_brackets then arg1 = iut.remove_redundant_links(refl_clitic_verb) .. arg1 .. post incorporated_headword_head_into_lemma = true else -- Try again using the form without links. local linkless_head = m_links.remove_links(head) if linkless_head:find(" ") then refl_clitic_verb, post = rmatch(linkless_head, "^(.-)( .*)$") arg1 = refl_clitic_verb .. arg1 .. post else error("Unable to incorporate <...> spec into explicit head due to a multiword linked verb or " .. "unbalanced brackets; please include <> explicitly: " .. arg1) end end else -- Will be incorporated through `head` below in the call to normalize_all_lemmas(). incorporated_headword_head_into_lemma = true end end local function split_bracketed_runs_into_words(bracketed_runs) return put.split_alternating_runs(bracketed_runs, " ", "preserve splitchar") end local parse_props = { parse_indicator_spec = parse_indicator_spec, -- Split words only on spaces, not on hyphens, because that messes up reflexive verb parsing. split_bracketed_runs_into_words = split_bracketed_runs_into_words, allow_default_indicator = true, allow_blank_lemma = true, } local alternant_multiword_spec = iut.parse_inflected_text(arg1, parse_props) alternant_multiword_spec.pos = pos or "ကြိယာ" alternant_multiword_spec.args = args alternant_multiword_spec.source_template = source_template alternant_multiword_spec.verb_form_of_form = verb_form_of_form alternant_multiword_spec.incorporated_headword_head_into_lemma = incorporated_headword_head_into_lemma normalize_all_lemmas(alternant_multiword_spec, head) detect_all_indicator_specs(alternant_multiword_spec) local inflect_props = { slot_list = alternant_multiword_spec.all_verb_slots, inflect_word_spec = conjugate_verb, get_variants = function(form) return rsub(form, not_var_code_c, "") end, -- We add links around the generated verbal forms rather than allow the entire multiword -- expression to be a link, so ensure that user-specified links get included as well. include_user_specified_links = true, } iut.inflect_multiword_or_alternant_multiword_spec(alternant_multiword_spec, inflect_props) -- Remove redundant brackets around entire forms. for slot, forms in pairs(alternant_multiword_spec.forms) do for _, form in ipairs(forms) do form.form = iut.remove_redundant_links(form.form) end end compute_categories_and_annotation(alternant_multiword_spec) if args.json and source_template == "gl-reinteg-conj" then -- Remove variant codes to avoid causing problems with bots. for slot, forms in pairs(alternant_multiword_spec.forms) do for _, form in ipairs(forms) do form.form = export.remove_variant_codes(form.form) end end return require("Module:JSON").toJSON(alternant_multiword_spec.forms) end return alternant_multiword_spec end -- Entry point for {{gl-reinteg-conj}}. Template-callable function to parse and conjugate a verb given -- user-specified arguments and generate a displayable table of the conjugated forms. function export.show(frame) local parent_args = frame:getParent().args local params = { [1] = {}, ["noautolinktext"] = {type = "boolean"}, ["noautolinkverb"] = {type = "boolean"}, ["pagename"] = {}, -- for testing/documentation pages ["json"] = {type = "boolean"}, -- for bot use } local args = require("Module:parameters").process(parent_args, params) local alternant_multiword_spec = export.do_generate_forms(parent_args, "gl-reinteg-conj") if type(alternant_multiword_spec) == "string" then -- JSON return value return alternant_multiword_spec end show_forms(alternant_multiword_spec) return make_table(alternant_multiword_spec) .. require("Module:utilities").format_categories(alternant_multiword_spec.categories, lang, nil, nil, force_cat) end return export 12pbrm97dk1qg4s0o2pc1tmetr26x56 မဝ်ဂျူ:gl-reinteg-verb/documentation 828 66897 402290 398519 2026-10-03T08:03:49Z 咽頭べさ 33 402290 wikitext text/x-wiki {{documentation needed}}<!-- Replace this with a short description of the purpose of the module, and how to use it. --> <includeonly> [[ကဏ္ဍ:မဝ်ဂျူပွမပြံၚ်လှာဲဂၠဳသဳယျာန်ဂမၠိုၚ်]] </includeonly> 00bgwgo670hbjxmfpomkkiqfm6dw4op မဝ်ဂျူ:gl-verb 828 108339 402287 148510 2026-10-03T07:58:44Z 咽頭べさ 33 402287 Scribunto text/plain --[=[ This module implements {{gl-conj}} and provides the underlying conjugation functions for {{gl-verb}} (whose actual formatting is done in [[Module:gl-headword]]). This module uses the standard norm for Galician spelling. See also [[Module:gl-reinteg-verb]], which implements the reintegrationist norm. Authorship: Ben Wing <benwing2> ]=] local export = {} --[=[ TERMINOLOGY: -- "slot" = A particular combination of tense/mood/person/number/etc. Example slot names for verbs are "pres_1s" (present indicative first-person singular), "pres_sub_2s" (present subjunctive second-person singular) "impf_sub_3p" (imperfect subjunctive third-person plural). Each slot is filled with zero or more forms. -- "form" = The conjugated Galician form representing the value of a given slot. -- "lemma" = The dictionary form of a given Galician term. For Galician, always the infinitive. ]=] --[=[ FIXME: --]=] local lang = require("Module:languages").getByCode("gl") local m_string_utilities = require("Module:string utilities") local m_links = require("Module:links") local m_table = require("Module:table") local iut = require("Module:inflection utilities") local put = require("Module:parse utilities") local com = require("Module:gl-common") local force_cat = false -- set to true for debugging local check_for_red_links = false -- set to false for debugging local rfind = mw.ustring.find local rmatch = mw.ustring.match local rsplit = mw.text.split local rsub = com.rsub local u = mw.ustring.char local unpack = unpack or table.unpack -- Lua 5.2 compatibility local function link_term(term, display) return m_links.full_link({ lang = lang, term = term, alt = display }, "term") end local V = com.V -- vowel regex class local AV = com.AV -- accented vowel regex class local C = com.C -- consonant regex class local TEMPC1 = u(0xFFF1) -- temporary character used for consonant substitutions local short_pp_footnote = "[usually used with auxiliary verbs " .. link_term("ser") .. " and " .. link_term("estar") .. "]" local long_pp_footnote = "[usually used with auxiliary verbs " .. link_term("haber") .. " and " .. link_term("ter") .. "]" --[=[ Vowel alternations: <i-e>: 'i' in pres1s, imp2s and the whole present subjunctive; 'e' elsewhere when stressed. Generally 'e' otherwise when unstressed. E.g. [[sentir]], [[conseguir]] (the latter additionally with 'gu-g' alternation). <u-o>: 'u' in pres1s, imp2s and the whole present subjunctive; 'o' elsewhere when stressed. Generally 'u' otherwise when unstressed. E.g. [[durmir]], [[subir]]. <i>: 'i' whenever stressed (in the present singular and third plural) and throughout the whole present subjunctive. Otherwise 'e'. E.g. [[vestir]], [[pedir]]. <u>: 'u' whenever stressed (in the present singular and third plural) and throughout the whole present subjunctive. Otherwise 'o'. There may be no such verbs in standard Galician. <í>: The last 'i' of the stem) becomes 'í' when stressed. E.g.: * [[faiscar]] (only3sp; faísca, faíscan, faísque, faísquen' also with 'c-qu' alternation), [[acainzar]], [[avaiñar]], [[cainzar]], [[caiñar]], [[desenvaiñar]], [[envaiñar]], [[arremuiñar]], [[arrepuiñar]], [[arruinar]], [[cuincar]], [[cuiñar]], [[muiñar]] * verbs in -eizar and -aizar, e.g. [[europeizar]] ('europeízo, europeíce', etc. also with 'z-c' alternation) * [[desenraizar]], [[enraizar]], [[hebraizar]], [[xudaizar]] * [[europeizar]], [[homoxeneizar]] * some verbs in -uizar: * [[enxuizar]] (enxuízo, enxuíza, enxuíce, enxuícen, also with 'z-c' alternation), [[axuizar]] * but not any in -guizar ([[arreguizar]], [[desgaleguizar]], [[empreguizar]], [[esguizar]], [[espreguizar]], [[galeguizar]]) or -quizar ([[catequizar]], [[esnaquizar]], [[xerarquizar]]) * none in -aiar? * not [[abraiar]], [[achaiar]], [[alfaiar]], [[amaiar]], [[arraiar]], [[atalaiar]], [[desmaiar]], [[encaiar]], [[engraiar]], [[ensaiar]], [[espraiar]], [[faiar]], [[laiar]], [[maiar]], [[raiar]], [[salaiar]] * unknown: [[craiar]] * some verbs in -biar: * [[adobiar]], [[asubiar]], [[espabiar]] * but not [[arrubiar]], [[asoberbiar]] /e/?, [[cambiar]], [[descambiar]], [[enrabiar]], [[ensoberbiar]] /e/?, [[entibiar]], [[gabiar]], [[gobiar]] /ɔ/, [[intercambiar]], [[rabiar]], [[recambiar]], [[sarabiar]] (only3s), [[turbiar]] * none in -ciar: * not [[acariciar]], [[agraciar]], [[anunciar]], [[apreciar]] /e/?, [[asociar]] /ɔ/, [[auspiciar]], [[autofinanciar]], [[aviciar]], [[axenciar]] /ɛ/, [[beneficiar]], [[comerciar]] /ɛ/, [[concienciar]] /ɛ/, [[conferenciar]] /e/?, [[congraciar]], [[denunciar]], [[depreciar]] /e/?, [[desasociar]] /ɔ/, [[desenviciar]], [[desgraciar]], [[desperdiciar]], [[diferenciar]] /e/?, [[dilixenciar]] /e/?, [[disociar]] /ɔ/, [[distanciar]], [[divorciar]] /ɔ/, [[enranciar]], [[ensuciar]], [[enunciar]], [[enviciar]], [[escanciar]], [[especiar]] /?/, [[evidenciar]] /e/?, [[financiar]], [[graciar]], [[influenciar]] /e/?, [[iniciar]], [[licenciar]] /ɛ/, [[maliciar]], [[negociar]] /ɔ/, [[oficiar]], [[potenciar]] /e/?, [[prenunciar]], [[presenciar]] /e/?, [[pronunciar]], [[propiciar]], [[quintaesenciar]] /e/?, [[reiniciar]], [[renunciar]], [[reverenciar]] /e/?, [[saciar]], [[sentenciar]] /e/?, [[silenciar]] /e/?, [[viciar]] * some verbs in -diar: * [[adiar]], [[vadiar]] * but not [[asediar]] /ɛ/, [[compendiar]] /ɛ/, [[custodiar]] /ɔ/, [[deslendiar]] /e/?, [[entremediar]] /e/?, [[estipendiar]] /e/?, [[fastidiar]], [[incendiar]] /e/?, [[insidiar]], [[irradiar]], [[mediar]] /e/?, [[odiar]] /ɔ/, [[parodiar]] /ɔ/, [[preludiar]], [[radiar]], [[remediar]] /ɛ/, [[repudiar]], [[salmodiar]] /ɔ/, [[subsidiar]], [[vilipendiar]] /ɛ/ * some verbs in -fiar: * [[afiar]], [[confiar]], [[desafiar]], [[desconfiar]], [[desenfiar]], [[enfiar]], [[esfiar]], [[esgrafiar]], [[fiar]], [[porfiar]], probably [[sobrefiar]] (not indicated) * but not [[atrofiar]] /ɔ/, [[hipertrofiar]] /ɔ/ * verbs in -guiar: * [[guiar]], [[radioguiar]], [[teleguiar]] * verbs in -hiar: * [[chiar]], [[rechiar]], [[rechouchiar]] * some verbs in -liar: * [[aliar]] (alío, alía, alíe, alíen), [[ampliar]], [[avaliar]], [[desliar]], [[liar]] * but not [[afiliar]] (afilio, afilia, afilie, afilien), [[auxiliar]], [[conciliar]], [[defoliar]], [[domiciliar]], [[escoliar]], [[espoliar]], [[exfoliar]], [[exiliar]], [[interfoliar]], [[reconciliar]] * [[paliar]] goes both ways: 'palio/palío', 'palia/palía', 'palie/palíe', 'palien/palíen' * unknown: [[represaliar]] * some verbs in -miar: * [[gurrumiar]], [[miar]] * but not [[agremiar]], [[amomiar]], [[encomiar]], [[premiar]], [[rumiar]] * some verbs in -niar: * [[agoniar]], [[desagoniar]] * but not [[calumniar]], [[conxeniar]], [[herniar]], [[miniar]] * none in -oiar? * not [[aboiar]] /ɔ/, [[acoiar]] /ɔ/, [[apoiar]] /o/, [[arroiar]] /o/ (only3s), [[choiar]]/[[enchoiar]] /ɔ/, [[enxoiar]] /ɔ/, [[loiar]] /o/ * some verbs in -piar: * [[arrepiar]], [[espiar]], [[expiar]], [[piar]] * but not [[apropiar]], [[copiar]], [[expropiar]], [[fotocopiar]], [[lurpiar]], [[principiar]], [[recopiar]], [[tapiar]], [[xerocopiar]] * some verbs in -quiar: * [[esquiar]], [[maquiar]], [[remaquiar]], [[tosquiar]] * but not [[obsequiar]] * unknown: [[franquiar]] * some verbs in -riar: * [[arrefriar]], [[arriar]], [[avariar]], [[criar]], [[desvariar]], [[enriar]], [[escagarriar]], [[estriar]], [[malcriar]], [[recriar]], [[variar]] * but not [[anguriar]], [[asalariar]], [[cariar]] (only3sp), [[contrariar]], [[desmemoriar]], [[expatriar]], [[gloriar]], [[historiar]], [[inventariar]], [[inxuriar]], [[leriar]], [[repatriar]], [[seriar]], [[vangloriar]] * some verbs in -siar: * [[fantasiar]] * but not [[anestesiar]], [[extasiar]] * [[ansiar]] goes both ways: 'ansio/ansío', 'ansia/ansía', 'ansie/ansíe', 'ansien/ansíen' * some verbs in -tiar: * [[amnistiar]], [[desenfastiar]], [[enfastiar]] * but not [[angustiar]], [[sitiar]] * some verbs in -viar: * [[ataviar]], [[aviar]], [[desataviar]], [[desviar]], [[enviar]], [[extraviar]], [[reenviar]] * but not [[abreviar]], [[agraviar]], [[aliviar]], [[desagraviar]], [[diluviar]] (only3s), [[obviar]] * some verbs in -xiar: * [[vixiar]] * but not [[asfixiar]], [[colexiar]] /e/, [[contaxiar]], [[desprestixiar]], [[eloxiar]], [[plaxiar]], [[presaxiar]], [[prestixiar]], [[privilexiar]] /e/, [[refuxiar]] <ú>: The last 'u' of the stem becomes 'ú' when stressed. E.g.: * [[reunir]] ('reúno, reúne(s), reúnem, reúna(s), reúnan') * [[esmiuzar]] ('esmiúzo, esmiúza(s), esmiúza, esmiúce(s), esmiúcen' also with 'z-c' alternation) * [[saudar]] ('saúdo, saúda(s), saúda, saúde(s), saúden') * [[auñar]], [[desembaular]], [[embaular]] * [[afiuzar]], [[desafiuzar]], [[desmiudar]], [[desmiuzar]], [[enviuvar]], [[esmiuzar]] but not [[triunfar]] * NOTE: It seems most or all verbs in -uar other than in -guar, -quar have stressed ú, so we make it the default. ]=] local vowel_alternants = m_table.listToSet({"i-e", "i", "í", "u-o", "u", "ú", "+"}) local vowel_alternant_to_desc = { ["i-e"] = "''i-e'' alternation in present singular", ["i"] = "''e'' becomes ''i'' when stressed", ["í"] = "''i'' becomes ''í'' when stressed", ["u-o"] = "''u-o'' alternation in present singular", ["u"] = "''o'' becomes ''u'' when stressed", ["ú"] = "''u'' becomes ''ú'' when stressed", } local vowel_alternant_to_cat = { ["i-e"] = "i-e alternation in present singular", ["i"] = "e becoming i when stressed", ["í"] = "i becoming í when stressed", ["u-o"] = "u-o alternation in present singular", ["u"] = "o becoming u when stressed", ["ú"] = "u becoming ú when stressed", } local all_persons_numbers = { ["1s"] = "1|s", ["2s"] = "2|s", ["3s"] = "3|s", ["1p"] = "1|p", ["2p"] = "2|p", ["3p"] = "3|p", } local person_number_list = {"1s", "2s", "3s", "1p", "2p", "3p"} local imp_person_number_list = {"2s", "3s", "1p", "2p", "3p"} local neg_imp_person_number_list = {"2s", "3s", "1p", "2p", "3p"} person_number_to_reflexive_pronoun = { ["1s"] = "me", ["2s"] = "te", ["3s"] = "se", ["1p"] = "nos", ["2p"] = "vos", ["3p"] = "se", } local indicator_flags = m_table.listToSet { "no_pres_stressed", "no_pres1_and_sub", "only3s", "only3sp", "only3p", "noimp", "pp_inv", "irreg", "no_built_in", } -- Initialize all the slots for which we generate forms. local function add_slots(alternant_multiword_spec) -- "Basic" slots: All slots that go into the regular table (not the reflexive form-of table). alternant_multiword_spec.verb_slots_basic = { {"infinitive", "inf"}, {"infinitive_linked", "inf"}, {"gerund", "ger"}, {"short_pp_ms", "short|m|s|past|part"}, {"short_pp_fs", "short|f|s|past|part"}, {"short_pp_mp", "short|m|p|past|part"}, {"short_pp_fp", "short|f|p|past|part"}, {"pp_ms", "m|s|past|part"}, {"pp_fs", "f|s|past|part"}, {"pp_mp", "m|p|past|part"}, {"pp_fp", "f|p|past|part"}, } -- Special slots used to handle non-reflexive parts of reflexive verbs in {{gl-verb form of}}. For example, for a -- reflexive-only verb like [[arrepentirse]], we want to be able to use {{gl-verb form of}} on [[arrepinta]] (which -- should mention that it is a part of 'me arrepinta', first-person singular present subjunctive, and -- 'se arrepinta', third-person singular present subjunctive) or on [[arrepentimos]] (which should mention that it -- is a part of 'arrepentímonos', first-person plural present indicative or preterite). Similarly, we want to use -- {{gl-verb form of}} on [[arrepentindo]] (which should mention that it is a part of 'se ... arrepentindo', -- syntactic variant of [[arrepentíndose]], which is the gerund of [[arrepentirse]]). To do this, we need to be -- able to map non-reflexive parts like [[arrepinta]], [[arrepentimos]], [[arrepentindo]], etc. to their reflexive -- equivalent(s), to the tag(s) of the equivalent(s), and, in the case of forms like [[arrepentindo]], -- [[arrepentir]] and imperatives, to the separated syntactic variant of the verb+clitic combination. We do this by -- creating slots for the non-reflexive part equivalent of each basic reflexive slot, and for the separated -- syntactic-variant equivalent of each basic reflexive slot that is formed of verb+clitic. We use slots in this -- way to deal with multiword lemmas. Note that we run into difficulties mapping between reflexive verbs, -- non-reflexive part equivalents, and separated syntactic variants if a slot contains more than one form. To -- handle this, if there are the same number of forms in two slots we're trying to match up, we assume the forms -- match one-to-one; otherwise we don't match up the two slots (which means {{gl-verb form of}} won't work in this -- case, but such a case is extremely rare and not worth worrying about). Alternatives that handle this "properly" -- are significantly more complicated and require non-trivial modifications to [[Module:inflection utilities]]. local need_special_verb_form_of_slots = alternant_multiword_spec.source_template == "gl-verb form of" and alternant_multiword_spec.refl if need_special_verb_form_of_slots then alternant_multiword_spec.verb_slots_reflexive_verb_form_of = { {"infinitive_non_reflexive", "-"}, {"infinitive_variant", "-"}, {"gerund_non_reflexive", "-"}, {"gerund_variant", "-"}, } else alternant_multiword_spec.verb_slots_reflexive_verb_form_of = {} end -- Add entries for a slot with person/number variants. -- `verb_slots` is the table to add to. -- `slot_prefix` is the prefix of the slot, typically specifying the tense/aspect. -- `tag_suffix` is a string listing the set of inflection tags to add after the person/number tags. -- `person_number_list` is a list of the person/number slot suffixes to add to `slot_prefix`. local function add_personal_slot(verb_slots, slot_prefix, tag_suffix, person_number_list) for _, persnum in ipairs(person_number_list) do local persnum_tag = all_persons_numbers[persnum] local slot = slot_prefix .. "_" .. persnum local accel = persnum_tag .. "|" .. tag_suffix table.insert(verb_slots, {slot, accel}) end end -- Add a personal slot (i.e. a slot with person/number variants) to `verb_slots_basic`. local function add_basic_personal_slot(slot_prefix, tag_suffix, person_number_list, no_special_verb_form_of_slot) add_personal_slot(alternant_multiword_spec.verb_slots_basic, slot_prefix, tag_suffix, person_number_list) -- Add special slots for handling non-reflexive parts of reflexive verbs in {{gl-verb form of}}. -- See comment above in `need_special_verb_form_of_slots`. if need_special_verb_form_of_slots and not no_special_verb_form_of_slot then for _, persnum in ipairs(person_number_list) do local persnum_tag = all_persons_numbers[persnum] local basic_slot = slot_prefix .. "_" .. persnum local accel = persnum_tag .. "|" .. tag_suffix table.insert(alternant_multiword_spec.verb_slots_reflexive_verb_form_of, {basic_slot .. "_non_reflexive", "-"}) end end end add_basic_personal_slot("pres", "pres|ind", person_number_list) add_basic_personal_slot("impf", "impf|ind", person_number_list) add_basic_personal_slot("pret", "pret|ind", person_number_list) add_basic_personal_slot("plup", "plup|ind", person_number_list) add_basic_personal_slot("fut", "fut|ind", person_number_list) add_basic_personal_slot("cond", "cond", person_number_list) add_basic_personal_slot("pres_sub", "pres|sub", person_number_list) add_basic_personal_slot("impf_sub", "impf|sub", person_number_list) add_basic_personal_slot("fut_sub", "fut|sub", person_number_list) add_basic_personal_slot("imp", "imp", imp_person_number_list) add_basic_personal_slot("pers_inf", "pers|inf", person_number_list) -- Don't need special non-reflexive-part slots because the negative imperative is multiword, of which the -- individual words are 'non' + subjunctive. add_basic_personal_slot("neg_imp", "neg|imp", neg_imp_person_number_list, "no special verb form of") -- Don't need special non-reflexive-part slots because we don't want [[arrependendo]] mapping to [[arrependendo-me]] -- (only [[arrependendo-se]]) or [[arrepender]] mapping to [[arrepender-me]] (only [[arrepender-se]]). add_basic_personal_slot("infinitive", "inf", person_number_list, "no special verb form of") add_basic_personal_slot("gerund", "ger", person_number_list, "no special verb form of") -- Generate the list of all slots. alternant_multiword_spec.all_verb_slots = {} for _, slot_and_accel in ipairs(alternant_multiword_spec.verb_slots_basic) do table.insert(alternant_multiword_spec.all_verb_slots, slot_and_accel) end for _, slot_and_accel in ipairs(alternant_multiword_spec.verb_slots_reflexive_verb_form_of) do table.insert(alternant_multiword_spec.all_verb_slots, slot_and_accel) end alternant_multiword_spec.verb_slots_basic_map = {} for _, slotaccel in ipairs(alternant_multiword_spec.verb_slots_basic) do local slot, accel = unpack(slotaccel) alternant_multiword_spec.verb_slots_basic_map[slot] = accel end end local overridable_stems = {} local function allow_multiple_values(separated_groups, data) local retvals = {} for _, separated_group in ipairs(separated_groups) do local footnotes = data.fetch_footnotes(separated_group) local retval = {form = separated_group[1], footnotes = footnotes} table.insert(retvals, retval) end return retvals end local function simple_choice(choices) return function(separated_groups, data) if #separated_groups > 1 then data.parse_err("For spec '" .. data.prefix .. ":', only one value currently allowed") end if #separated_groups[1] > 1 then data.parse_err("For spec '" .. data.prefix .. ":', no footnotes currently allowed") end local choice = separated_groups[1][1] if not m_table.contains(choices, choice) then data.parse_err("For spec '" .. data.prefix .. ":', saw value '" .. choice .. "' but expected one of '" .. table.concat(choices, ",") .. "'") end return choice end end for _, overridable_stem in ipairs { "pres_unstressed", "pres_stressed", "pres1_and_sub", -- Don't include pres1; use pres_1s if you need to override just that form "impf", "full_impf", {"pret_conj", simple_choice({"irreg", "ar", "er", "ir"}) }, "pret_base", "pret", "short_pret", "fut", "cond", "pres_sub_stressed", "pres_sub_unstressed", {"sub_conj", simple_choice({"ar", "er"}) }, "plup", "impf_sub", "fut_sub", "pers_inf", "pp", "short_pp", } do if type(overridable_stem) == "string" then overridable_stems[overridable_stem] = allow_multiple_values else local stem, validator = unpack(overridable_stem) overridable_stems[stem] = validator end end -- Useful as the value of the `match` property of a built-in verb. `main_verb_spec` is a Lua pattern that should match -- the non-prefixed part of a verb, and `prefix_specs` is a list of Lua patterns that should match the prefixed part of -- a verb. If a prefix spec is preceded by ^, it must match exactly at the beginning of the verb; otherwise, additional -- prefixes (e.g. re-, des-) may precede. Return the prefix and main verb. local function match_against_verbs(main_verb_spec, prefix_specs) return function(verb) for _, prefix_spec in ipairs(prefix_specs) do if prefix_spec:find("^%^") then -- must match exactly prefix_spec = prefix_spec:gsub("^%^", "") if prefix_spec == "" then -- We can't use the second branch of the if-else statement because an empty () returns the current position -- in rmatch(). local main_verb = rmatch(verb, "^(" .. main_verb_spec .. ")$") if main_verb then return "", main_verb end else local prefix, main_verb = rmatch(verb, "^(" .. prefix_spec .. ")(" .. main_verb_spec .. ")$") if prefix then return prefix, main_verb end end else local prefix, main_verb = rmatch(verb, "^(.*" .. prefix_spec .. ")(" .. main_verb_spec .. ")$") if prefix then return prefix, main_verb end end end return nil end end --[=[ Built-in (usually irregular) conjugations. Each entry is processed in turn and consists of an object with two fields: 1. match=: Specifies the built-in verbs that match this object. 2. forms=: Specifies the built-in stems and forms for these verbs. The value of match= is either a string beginning with "^" (match only the specified verb), a string not beginning with "^" (match any verb ending in that string), or a function that is passed in the verb and should return the prefix of the verb if it matches, otherwise nil. The function match_against_verbs() is provided to facilitate matching a set of verbs with a common ending and specific prefixes (e.g. [[ter]] and [[ater]] but not [[abater]], etc.). The value of forms= is a table specifying stems and individual override forms. Each key of the table names either a stem (e.g. `pres_stressed`), a stem property (e.g. `vowel_alt`) or an individual override form (e.g. `pres_1s`). Each value of a stem can either be a string (a single stem), a list of strings, or a list of objects of the form {form = STEM, footnotes = {FOONOTES}}. Each value of an individual override should be of exactly the same form except that the strings specify full forms rather than stems. The values of a stem property depend on the specific property but are generally strings or booleans. In order to understand how the stem specifications work, it's important to understand the phonetic modifications done by combine_stem_ending(). In general, the complexities of predictable prefix, stem and ending modifications are all handled in this function. In particular: 1. Spelling-based modifications (c/z, g/gu, gu/gü, g/j) occur automatically as appropriate for the ending. 2. If the stem begins with an acute accent, the accent is moved onto the last vowel of the prefix (for handling verbs in -uar such as [[minguar]], pres_3s 'míngua'). 3. If the ending begins with a double asterisk, this is a signal to conditionally delete the accent on the last letter of the stem. "Conditionally" means we don't do it if the last two letters would form a diphthong without the accent on the second one (e.g. in [[sair]], with stem 'saí'); but as an exception, we do delete the accent in stems ending in -guí, -quí (e.g. in [[conseguir]]) because in this case the ui isn't a diphthong. 4. If the ending begins with an asterisk, this is a signal to delete the accent on the last letter of the stem, e.g. fizé -> fizermos. Unlike for **, this removal is unconditional, so we get e.g. 'sairmos' not #'saírmos'. 5. If ending begins with i, it must get an accent after an unstressed vowel (in some but not all cases) to prevent the two merging into a diphthong. See combine_stem_ending() for specifics. The following stems are recognized: -- pres_unstressed: The present indicative unstressed stem (1p, 2p). Also controls the imperative 2p and gerund. Defaults to the infinitive stem (minus the ending -ar/-er/-ir/-or). -- pres_stressed: The present indicative stressed stem (1s, 2s, 3s, 3p). Also controls the imperative 2s. Default is empty if indicator `no_pres_stressed`, else a vowel alternation if such an indicator is given (e.g. `ue`, `ì`), else the infinitive stem. -- pres1_and_sub: Overriding stem for 1s present indicative and the entire subjunctive. Only set by irregular verbs and by the indicators `no_pres_stressed` (e.g. [[precaver]]) and `no_pres1_and_sub` (since verbs of this sort, e.g. [[puir]], are missing the entire subjunctive as well as the 1s present indicative). Used by many irregular verbs, e.g. [[caber]], verbs in '-air', [[dizer]], [[ter]], [[valer]], etc. Some verbs set this and then supply an override for the pres_1s if it's irregular, e.g. [[saber]], with irregular subjunctive stem "saib-" and special 1s present indicative "sei". -- pres1: Special stem for 1s present indicative. Normally, do not set this explicitly. If you need to specify an irregular 1s present indicative, use the form override pres_1s= to specify the entire form. Defaults to pres1_and_sub if given, else pres_stressed. -- pres_sub_unstressed: The present subjunctive unstressed stem (1p, 2p). Defaults to pres1_and_sub if given, else the infinitive stem. -- pres_sub_stressed: The present subjunctive stressed stem (1s, 2s, 3s, 1p). Defaults to pres1. -- sub_conj: Determines the set of endings used in the subjunctive. Should be one of "ar" or "er". -- impf: The imperfect stem (not including the -av-/-i- stem suffix, which is determined by the conjugation). Defaults to the infinitive stem. -- full_impf: The full imperfect stem missing only the endings (-a, -as, -am, etc.). Used for verbs with irregular imperfects such as [[ser]], [[ter]], [[vir]] and [[pór]]. -- pret_conj: Determines the set of endings used in the preterite. Should be one of "ar", "er", "ir" or "irreg". Defaults to the conjugation as determined from the infinitive. When pret_conj == "irreg", `pret` is used, otherwise `pret_base`. -- pret_base: The preterite stem (not including the -a-/-e-/-i- stem suffix). Defaults to the infinitive stem. Only used when pret_conj ~= "irreg". -- pret: The full preterite stem missing only the endings (-ste, -mos, etc.), e.g. 'fige', 'fo'. Only used for verbs with irregular preterites (pret_conj == "irreg") such as [[facer]], [[poder]], [[traer]], etc. The pret_1s and pret_3s are handled using the short_pret stem instead (pret_1s '-en', pret_3s '-o'). Defaults to `pret_base` + the conjugation vowel. -- short_pret: The short preterite stem, used with 1s and 3s endings (pret_1s '-en', pret_3s '-o'). Only used with irregular preterites (pret_conj == "irreg"). Normally derived from pret by deleting the final vowel, and doesn't need to be given explicitly. -- fut: The future stem. Defaults to the infinitive stem + the conjugation vowel. -- cond: The conditional stem. Defaults to `fut`. -- impf_sub: The imperfect subjunctive stem. Defaults to `pret`. -- fut_sub: The future subjunctive stem. Defaults to `pret`. -- plup: The pluperfect stem. Defaults to `pret`. -- pers_inf: The personal infinitive stem. Defaults to the infinitive stem + the conjugation vowel. -- pp: The masculine singular past participle. Default is based on the verb conjugation: infinitive stem + '-ado' for -ar verbs, otherwise infinitive stem + '-ido'. -- short_pp: The short masculine singular past participle, for verbs with such a form. No default. -- pp_inv: `true` if the past participle exists only in the masculine singular. ]=] local built_in_conjugations = { -------------------------------------------------------------------------------------------- -- -ar -- -------------------------------------------------------------------------------------------- -- Verbs not needing entries here: -- -- (1) Verbs with short past participles: need to specify the short pp explicitly. -- -- aceitar: use <short_pp:aceite> -- anexar, completar, expressar, expulsar, findar, fritar, ganhar, gastar, limpar, pagar, pasmar, pegar, soltar: -- use <short_pp:anexo> etc. -- assentar: use <short_pp:assente> -- entregar: use <short_pp:entregue> -- enxugar: use <short_pp:enxuto> -- matar: use <short_pp:morto> -- -- (2) Verbs with orthographic consonant alternations: handled automatically. -- -- -car (brincar, buscar, pecar, trancar, etc.): automatically handled in combine_stem_ending() -- -zar (alcanzar, comezar, lazar): automatically handled in combine_stem_ending() -- -gar (apagar, cegar, esmagar, largar, navegar, resmungar, sugar, etc.): automatically handled in combine_stem_ending() -- -guar (iguar, minguar): automatically handled in combine_stem_ending() -- -- (3) Verbs with vowel alternations: need to specify the alternation explicitly unless it always happens, in -- which case it's handled automatically through an entry below. -- -- esmiuzar changing to esmiúzo: use <ú> -- faiscar changing to faísco: use <í> -- -izar changing to -ízo (ajuizar, enraizar, homogeneizar, plebeizar, etc.): use <í> -- reusar changing to reúso: use <ú> -- saudar changing to saúdo: use <ú> -- tuitar/retuitar changing to (re)tuíto: use <í> { -- dar match = "^dar", -- [[desdar]] doesn't seem to exist; [[redar]] is regular and unrelated to [[dar]] forms = { pres_1s = "dou", pres_2s = "dás", pres_3s = "dá", pres_3p = "dán#", pres1_and_sub = "de", -- only for subjunctive as we override pres_1s sub_conj = "er", pret_conj = "irreg", pret = "de", pret_1s = "dei", pret_3s = "deu", -- /dɛw/ irreg = true, } }, { -- estar match = "^estar", -- [[sobestar]] and [[sobrestar]] seem not to exist forms = { pres_1s = "estou", pres_2s = "estás", pres_3s = "está", pres_3p = "están", pres1_and_sub = "este", -- only for subjunctive as we override pres_1s sub_conj = "er", pret_conj = "irreg", pret = "estive", pp_inv = true, -- no [[sobestar]] or [[sobrestar]], which would be transitive irreg = true, } }, { -- verbs in -uar but not -guar match = function(verb) if verb:find("guar$") then return nil else return match_against_verbs("uar", {""})(verb) end end, forms = { vowel_alt = "ú", } }, -------------------------------------------------------------------------------------------- -- -er -- -------------------------------------------------------------------------------------------- -- Verbs not needing entries here: -- -- -cer (verbs in -ecer, vencer, etc.): automatically handled in combine_stem_ending() -- -guer (erguer/soerguer): automatically handled in combine_stem_ending() { -- must be listed before -aer match = "^traer", forms = { -- all occurrences of accented í and ï in endings handled in combine_stem_ending() pres1_and_sub = "trai", pret_conj = "irreg", pret = "trouxe", irreg = true, } }, { -- verbs in -aer (caer, raer, debaer, degraer, esvaer and derivatives of traer, but not traer itself: -- acaer/decaer/recaer, -- abstraer/atraer/contraer/descontraer/detraer/distraer/extraer/maltraer/retraer/retrotraer/subtraer) match = "aer", forms = { -- all occurrences of accented í and ï in endings handled in combine_stem_ending() pres1_and_sub = "ai", irreg = true, } }, { -- caber match = "caber", forms = { pres1_and_sub = "caib", pret_conj = "irreg", pret = "coube", irreg = true, } }, { -- crer, descrer match = "crer", forms = { pres1_and_sub = "cre", pres_2s = "crés#", pres_3s = "cré#", pres_3p = "crén#", -- regular except the lack of accent in base verb pret_1p = "crín#", irreg = true, } }, { -- acender, prender/aprender; not comprender/desprender/reprender, etc. match = match_against_verbs("ender", {"^ac", "^pr", "^apr"}), forms = {short_pp = "eso"}, }, { -- erguer; but not soerguer match = "^erguer", forms = {short_pp = "ergueito"}, }, { -- facer, afacer, contrafacer, desafacer, desfacer, perfacer, rarefacer, refacer, satisfacer, tumefacer match = "facer", forms = { -- use 'fagu' because we're in a front environment; if we use 'fag', we'll get '#faxo' pres1_and_sub = "fagu", pres_2s = "fás#", pres_3s = "fai", pres_3p = "fán#", pret_conj = "irreg", pret = "fixe", pp = "feito", fut = "far", irreg = true, cons_alt = false, -- avoid claiming we have a c-z alternation } }, { match = "^haber", forms = { pres_1s = "hei", pres_2s = "has", pres_3s = {"ha", "hai"}, pres_3p = "han", pres1_and_sub = "hax", -- only for subjunctive as we override pres_1s pret_conj = "irreg", pret = "hoube", noimp = true, irreg = true, } }, { -- ler, reler, trasler; not escoller, expeler, valer, etc. match = match_against_verbs("ler", {"^", "^re", "tras"}), forms = { pres1_and_sub = "le", pres_2s = "lés#", pres_3s = "lé#", pres_3p = "lén#", -- regular except the lack of accent in base verb pret_1p = "lín#", irreg = true, } }, { -- morrer, premorrer match = "morrer", forms = {pp = "morto"}, }, { -- nacer; but not renacer match = "^nacer", forms = {short_pp = "nado"}, }, { -- moer, but not remoer match = "^moer", forms = { -- all occurrences of accented í and ï in endings handled in combine_stem_ending() pres1_and_sub = "moi", short_pp = "mudo", -- the main table says 'mundo' but the page for [[mundo]] says 'mudo' is "máis recomendable" irreg = true, } }, { -- choer/deschoer, doer/condoer, remoer, proer, roer/corroer match = "oer", forms = { -- all occurrences of accented í and ï in endings handled in combine_stem_ending() pres1_and_sub = "oi", irreg = true, } }, { -- coller, toller and derivatives (acoller, desacoller, desencoller, encoller, entrecoller, escoller, recoller; -- destoller, entretoller) match = "oller", forms = {short_pp = "olleito"}, }, { -- poder match = "poder", forms = { pres1_and_sub = "poid", -- only for subjunctive as we override pres_1s pres_1s = "podo", -- /ɔ/ pret_conj = "irreg", pret = "puide", irreg = true, } }, { -- poñer, antepoñer, apoñer/desapoñer, arrepoñer, compoñer/descompoñer/recompoñer, contrapoñer, depoñer, -- dispoñer/indispoñer/predispoñer, empoñer, expoñer/sobreexpoñer/subexpoñer, impoñer/reimpoñer, interpoñer, -- opoñer, pospoñer, propoñer, repoñer, sobrepoñer, superpoñer, supoñer/presupoñer, traspoñer, xustapoñer match = "poñer", forms = { pres_2s = "pós#", pres_3s = "pón#", pret_conj = "irreg", pret = "puxe", pp = "posto", irreg = true, } }, { -- pracer, but not apracer, compracer, descompracer, despracer match = "^pracer", forms = { pret_conj = "irreg", pret = "prougue", irreg = true, } }, -- prover below, just below ver { -- querer match = "querer", forms = { pres1_and_sub = "queir", -- only for subjunctive as we override pres_1s pres_1s = "quero", -- /ɛ/ pret_conj = "irreg", pret = "quixe", irreg = true, } }, { -- romper; but not corromper, interromper, irromper or prorromper match = "^romper", forms = {short_pp = "roto"}, }, { -- saber, ressaber match = "saber", forms = { pres_1s = "sei", pres1_and_sub = "saib", -- only for subjunctive as we override pres_1s pret_conj = "irreg", pret = "soube", irreg = true, } }, { -- absolver, disolver, resolver match = "solver", forms = {short_pp = "solto"}, }, { -- suspender; but not others in -pender match = "suspender", forms = {short_pp = "suspenso"}, }, { match = "^ser", forms = { pres_1s = "son", pres_2s = "es", pres_3s = "é", pres_1p = "somos", pres_2p = "sodes", pres_3p = "son", pres1_and_sub = "sex", -- only for subjunctive as we override pres_1s full_impf = "er", pret_conj = "irreg", pret = "fo", pret_1s = "fun", pret_2s = "fuches", pret_3s = "foi", imp_2s = "sé", imp_2p = "sede", irreg = true, } }, { -- We want to match abster, conter, deter, etc. but not abater, cometer, etc. No way to avoid listing each verb. match = match_against_verbs("ter", {"abs", "^a", "con", "de", "entre", "man", "ob", "^re", "sos", "^"}), forms = { pres_2s = "tés#", pres_3s = "tén#", pres_2p = {"tendes", "tedes"}, pres_3p = "teñen", pres1_and_sub = "teñ", full_impf = "tiñ", pret_conj = "irreg", pret = "tive", irreg = true, } }, -- traer listed above at the beginning of the -er verbs { -- valer, equivaler match = "valer", forms = { pres1_and_sub = "vall", irreg = true, } }, { -- We want to match antever etc. but not absolver, atrever etc. No way to avoid listing each verb. -- NOTE: [[rever]] has two meanings, one with regular conjugation. Use <no_built_in> for this one. match = match_against_verbs("ver", {"entre", "pre", "^re", "^"}), forms = { pres_2s = "vés#", pres_3s = "vé#", pres_3p = "vén#", pres1_and_sub = "vex", pret_conj = "irreg", pret = "vi", pret_1s = "vín#", pret_3s = "viu", pp = "visto", irreg = true, } }, { -- [[prover]] has regular preterite and past participle match = "^prover", forms = { pres_2s = "provés", pres_3s = "prové", pres_3p = "provén", pres1_and_sub = "provex", short_pp = "provisto", irreg = true, } }, { -- [[desprover]] has its own conjugation match = "^desprover", forms = { pres_2s = "desprovés", pres_3s = "desprové", pres_3p = "desprovén", pres1_and_sub = "desprove", short_pp = "desprovisto", irreg = true, } }, { -- volver, avolver/desenvolver/devolver/envolver/revolver match = "volver", forms = {short_pp = "volto"}, }, -------------------------------------------------------------------------------------------- -- -ir -- -------------------------------------------------------------------------------------------- -- Verbs not needing entries here: -- -- subir (NOT rubir), acudir/sacudir (NOT escudir, aludir/eludir), urdir/desurdir, xurdir/rexurdir, -- engulir, pulir, bulir/rebulir, ulir, mulir (NOT escapulir), durmir, sumir/consumir/ensumir (NOT -- asumir/reasumir/presumir/resumir/subsumir), cuspir/chuspir, sufrir, tusir, xunguir/conxunguir/desxunguir, -- munguir, fuxir/muxir/ruxir: use <u-o> -- [NOTE: imp_2s durme, consume/sume] -- sosubir/susubir: use <u-o>? (archaic, not in RAG dictionary) -- abolir: use <no_pres_stressed> -- descolorir: use <no_pres_stressed> -- empedernir: use <no_pres_stressed> -- espir/despir, refletir, adherir, pedir/desapedir/despedir/expedir/impedir/reexpedir, medir/comedir/descomedir, -- aferir/conferir/deferir/diferir/inferir/interferir/preferir/proferir/referir/transferir, -- dixerir/enxerir/suxerir, preterir, competir/repetir, advertir/divertir, vestir/investir/revestir/travestir, -- agredir/transgredir, espelir: use <i> -- mentir/desmentir, sentir/asentir/consentir/disentir/presentir/resentir, ferir (but no derivatives), servir, -- seguir/conseguir/perseguir/proseguir: use <i-e> -- [NOTE: imp_2s minte] -- denegrir: use <i.only3sp> -- prohibir/coibir: regular -- cumprir: use <no_built_in> in the meaning "fulfill" -- reunir: use <ú> -- argüír/redargüír: use <ú>? -- -- -cir alternations (aducir, resarcir): automatically handled in combine_stem_ending() -- -guir alternations (e.g. conseguir, cinguir, xunguir, tinguir): automatically handled in combine_stem_ending() -- -quir alternations (e.g. delinquir): automatically handled in combine_stem_ending() -- -güír alternations (e.g. argüír): automatically handled in combine_stem_ending() { -- saír/sobresaír match = "aír", forms = { pres1_and_sub = "ai", -- all occurrences of accented í and ï in endings handled in combine_stem_ending() irreg = true, } }, { -- abrir/desabrir/reabrir match = "abrir", forms = {pp = "aberto"}, }, { -- aflixir match = "aflixir", -- FIXME: should this be {pp = {"aflicto", "aflixido"}}? forms = {short_pp = "aflicto"}, }, { -- cubrir/descubrir/encubrir/recubrir/redescubrir match = "cubrir", forms = {vowel_alt = "u-o", pp = "coberto"}, }, { -- cumprir (only in the meaning "to be necessary"; otherwise use <no_built_in>) match = "^cumprir", forms = { -- We could create a <u-ó> just for this verb but that seems overkill unless another such verb appears pres_stressed = "cómpr", pres1_and_sub = "cumpr", }, }, { -- dicir, bendicir, contradicir, desdicir, maldicir, predicir -- FIXME: bendicir and maldicir can also be entirely regular. This could be handled like this: -- ((bendicir<>,bendicir<no_built_in>)) match = "dicir", forms = { -- use 'digu' because we're in a front environment; if we use 'dig', we'll get '#dijo' pres1_and_sub = "digu", pres_2s = "dís#", pres_3s = "dí#", pres_3p = "dín#", pret_conj = "irreg", pret = "dixe", pp = function(base, prefix) return (prefix == "" or prefix == "des" or prefix == "pre") and "dito" or {"dito", "dicido"} end, pp = "dito", fut = "dir", irreg = true, cons_alt = false, -- avoid claiming we have a c-z alternation } }, { -- elixir, reelixir match = "elixir", -- FIXME: should this be {pp = {"electo", "elixido"}}? forms = {short_pp = "electo"}, }, { -- frixir/sofrixir, fritir/sofritir match = "fri[xt]ir", forms = {short_pp = "frito"}, }, { -- inserir, reinserir match = "inserir", forms = { vowel_alt = "i", short_pp = "inserto", }, }, { -- ir match = "^ir", forms = { pres_1s = "vou", pres_2s = "vas", pres_3s = "vai", pres_1p = "imos", pres_2p = "ides", pres_3p = "van", pres1_and_sub = "vai", -- only for subjunctive as we override pres_1s pret_conj = "irreg", pret = "fo", pret_1s = "fun", pret_2s = "fuches", pret_3s = "foi", imp_1p = "vamos", irreg = true, } }, { -- oír, desoír, entreoír match = "oír", forms = { -- all occurrences of accented í and ï in endings handled in combine_stem_ending() pres1_and_sub = "oi", -- /ɔ/ irreg = true, } }, { match = "ouvir", forms = { pres1_and_sub = "ouz", irreg = true, } }, { -- parir, malparir match = "parir", forms = { pres1_and_sub = "pair", irreg = true, } }, { -- imprimir/reimprimir/sobreimprimir, but not comprimir/descomprimir, deprimir, oprimir, reprimir, suprimir match = "imprimir", forms = {short_pp = "impreso"} }, { -- rir, sorrir match = match_against_verbs("rir", {"^", "sor"}), forms = { pres_2s = "ris#", pres_3s = "ri#", pres_3p = "rin#", pret_1s = "rin#", -- regular except the lack of accent in base verb pres1_and_sub = "rí", irreg = true, } }, { -- adscribir, circunscribir, describir, escribir/reescribir, inscribir, prescribir, proscribir, sobrescribir, -- subscribir, transcribir match = "scribir", forms = { pp = "scrito", irreg = true, } }, { -- concluír/recluír; not excluír/incluír/ocluír match = match_against_verbs("cluír", {"con", "re"}), forms = { -- all occurrences of accented í and ï in endings handled in combine_stem_ending() vowel_alt = "ú", short_pp = "cluso", } }, { -- posuír; not desposuír match = "^posuír", forms = { -- all occurrences of accented í and ï in endings handled in combine_stem_ending() vowel_alt = "ú", short_pp = "poseso", } }, { -- remaining verbs in -uír (excluír/incluír/ocluír, diluír, -- afluír/confluír/difluír/fluír/efluír/influír/refluír, atuír/desatuír, -- atribuír/contribuír/distribuír/redistribuír/retribuír/substituír, -- constituír/destituír/instituír/prostituír/reconstituír/restituír, -- construír/desobstruír/destruír/instruír/obstruír/reconstruír, derruír, -- desposuír, diminuír, luír/esluír, estatuír, imbuír, inmiscuír, intuír, puír, pruír) match = "[uü]ír", -- this won't match -guir verbs (e.g. [[conseguir]]) or -quir verbs (e.g. [[delinquir]]) forms = { -- all occurrences of accented í and ï in endings handled in combine_stem_ending() vowel_alt = "ú", } }, { -- We want to match advir, convir, devir, etc. but not ouvir, servir, etc. No way to avoid listing each verb. match = match_against_verbs("vir", {"ad", "^a", "con", "contra", "de", "^desa", "inter", "pre", "pro", "sobre", "^"}), forms = { pres_2s = "vés", pres_3s = "vén", pres_2p = {"vindes", "vides"}, pres_3p = "veñen", pres1_and_sub = "veñ", full_impf = "viñ", pret_conj = "irreg", pret = "viñe", pret_1s = "vín#", pret_3s = "veu", pp = {"vindo", "vido"}, -- FIXME! The following is as in the RAG tables but may be a typo and should be vén for [[vir]] like pres_3s imp_2s = "vén#", irreg = true, } }, -------------------------------------------------------------------------------------------- -- misc -- -------------------------------------------------------------------------------------------- { -- pór, antepor, apor/desapor, arrepor, compor/descompor/recompor, contrapor, depor, dispor/indispor/predispor, -- empor, expor/sobreexpor/subexpor, impor/reimpor, interpor, opor, pospor, propor, repor, sobrepor, -- superpor, supor/presupor, traspor, xustapor match = "p[oó]r", forms = { pres_2s = "pós#", pres_3s = "pón#", pres_1p = "pomos", pres_2p = "pondes", pres_3p = "pón#", pres1_and_sub = "poñ", full_impf = "puñ", pret_conj = "irreg", pret = "puxe", fut = "por", pers_inf = "po", pers_inf_1s = function(base, prefix) return prefix == "" and "pór" or "por" end, pers_inf_3s = function(base, prefix) return prefix == "" and "pór" or "por" end, gerund = "pondo", pp = "posto", irreg = true, } }, } local function skip_slot(base, slot, allow_overrides) if not allow_overrides and (base.basic_overrides[slot] or base.refl and base.basic_reflexive_only_overrides[slot]) then -- Skip any slots for which there are overrides. return true end if base.only3s and (slot:find("^pp_f") or slot:find("^pp_mp")) then -- diluviar, atardecer, neviscar; impersonal verbs have only masc sing pp return true end if not slot:find("[123]") then -- Don't skip non-personal slots. return false end if base.nofinite then return true end if (base.noimp or base.only3s or base.only3sp or base.only3p) and (slot:find("^imp_") or slot:find("^neg_imp_")) then return true end if base.only3s and not slot:find("3s") then -- diluviar, atardecer, neviscar return true end if base.only3sp and not slot:find("3[sp]") then -- atañer, concernir return true end if base.only3p and not slot:find("3p") then -- [[caer cuatro gotas]], [[caer chuzos de punta]], [[entrarle los siete males]] return true end return false end -- Apply vowel alternations to stem. local function apply_vowel_alternations(stem, alternations) local alternation_stems = {} local saw_pres1_and_sub = false local saw_pres_stressed = false local saw_imp2s_override = false local origstem = stem -- Treat final -gu, -qu as a consonant, so the previous vowel can alternate (e.g. conseguir -> consigo). -- This means a verb in -guar can't have a u-ú alternation but I don't think there are any verbs like that. stem = rsub(stem, "([gq])u$", "%1" .. TEMPC1) -- Process alternations other than +. for _, altobj in ipairs(alternations) do local alt = altobj.form local pres1_and_sub, pres_stressed, imp2s_override, err if alt == "+" then -- do nothing yet else local before_last_vowel, last_vowel, after_last_vowel = rmatch(stem, "^(.*)(" .. V .. ")(.-)$") if alt == "i-e" then if last_vowel == "e" or last_vowel == "i" then pres1_and_sub = before_last_vowel .. "i" .. after_last_vowel imp2s_override = pres1_and_sub if last_vowel == "i" then pres_stressed = before_last_vowel .. "e" .. after_last_vowel end else err = "should have -e- or -i- as the last vowel" end elseif alt == "i" then if last_vowel == "e" then pres1_and_sub = before_last_vowel .. "i" .. after_last_vowel pres_stressed = pres1_and_sub else err = "should have -e- as the last vowel" end elseif alt == "u-o" then if last_vowel == "o" or last_vowel == "u" then pres1_and_sub = before_last_vowel .. "u" .. after_last_vowel imp2s_override = pres1_and_sub if last_vowel == "u" then pres_stressed = before_last_vowel .. "o" .. after_last_vowel end else err = "should have -o- or -u- as the last vowel" end elseif alt == "u" then if last_vowel == "o" then pres1_and_sub = before_last_vowel .. "u" .. after_last_vowel pres_stressed = pres1_and_sub else err = "should have -o- as the last vowel" end elseif alt == "í" then if last_vowel == "i" then pres_stressed = before_last_vowel .. "í" .. after_last_vowel else err = "should have -i- as the last vowel" end elseif alt == "ú" then if last_vowel == "u" or last_vowel == "ü" then pres_stressed = before_last_vowel .. "ú" .. after_last_vowel else err = "should have -u- or -ü- as the last vowel" end else error("Internal error: Unrecognized vowel alternation '" .. alt .. "'") end end local function unapply_u_mod(val) if val then return {form = val:gsub(TEMPC1, "u"), footnotes = altobj.footnotes}, true else return nil, false end end pres1_and_sub, saw_pres1_and_sub = unapply_u_mod(pres1_and_sub) pres_stressed, saw_pres_stressed = unapply_u_mod(pres_stressed) imp2s_override, saw_imp2s_override = unapply_u_mod(imp2s_override) table.insert(alternation_stems, { altobj = altobj, pres1_and_sub = pres1_and_sub, pres_stressed = pres_stressed, imp2s_override = imp2s_override, err = err }) end -- Now do +. We check to see which stems are used by other alternations and specify those so any footnotes are -- properly attached. for _, alternation_stem in ipairs(alternation_stems) do if alternation_stem.altobj.form == "+" then local stemobj = {form = origstem, footnotes = alternation_stem.altobj.footnotes} alternation_stem.pres1_and_sub = saw_pres1_and_sub and stemobj or nil alternation_stem.pres_stressed = saw_pres_stressed and stemobj or nil alternation_stem.imp2s_override = saw_imp2s_override and stemobj or nil end end return alternation_stems end -- Add the `stem` to the `ending` for the given `slot` and apply any phonetic modifications. -- WARNING: This function is written very carefully; changes to it can easily have unintended consequences. local function combine_stem_ending(base, slot, prefix, stem, ending, dont_include_prefix) -- If the ending begins with an acute accent, it goes after the last vowel, but we don't have to do anything. -- Use the full stem for checking for -gui ending and such, because 'stem' is just 'u' for [[arguir]], -- [[delinquir]]. local full_stem = prefix .. stem -- Include the prefix in the stem unless dont_include_prefix is given (used for the past participle stem). if not dont_include_prefix then stem = full_stem end -- If ending begins with i, it must get an accent after a/o/u to prevent the two merging into a diphthong: -- caer -> caíches, caído; doer -> doíches, doído; concluír -> concluíches, concluído. if ending:find("^i") and stem:find("[aouü]$") and not stem:find("[gq]u$") then -- Special case for impf_1p/impf_2p, where the i is unstressed and changes into ï. FIXME: Maybe we should be -- checking the slot value instead. if ending == "iamos" or ending == "iades" then ending = ending:gsub("^i", "ï") else ending = ending:gsub("^i", "í") end end -- Spelling changes in the stem; it depends on whether the stem given is the pre-front-vowel or -- pre-back-vowel variant, as indicated by `frontback`. We want these front-back spelling changes to happen -- between stem and ending, not between prefix and stem; the prefix may not have the same "front/backness" -- as the stem. local is_front = rfind(ending, "^[eiéíï]") if base.frontback == "front" and not is_front then stem = stem:gsub("c$", "z") -- coñecer -> coñezo, vencer -> venzo, inmiscir -> inmiszo stem = stem:gsub("gu$", "g") -- distinguir -> distingo, conseguir -> consigo stem = stem:gsub("qu$", "c") -- delinquir -> delinco stem = stem:gsub("gü$", "gu") -- argüír -> arguamos elseif base.frontback == "back" and is_front then stem = stem:gsub("gu$", "gü") -- iguar -> igüei stem = stem:gsub("g$", "gu") -- cargar -> carguei, apagar -> apaguei stem = stem:gsub("c$", "qu") -- marcar -> marquei stem = rsub(stem, "z$", "c") -- aderezar -> aderecei end local retval = stem .. ending if retval:find("#$") then -- remove final accent if no prefix retval = retval:gsub("#$", "") if prefix == "" then retval = com.remove_final_accent(retval) end end return retval end local function add3(base, slot, stems, endings, footnotes, allow_overrides) if skip_slot(base, slot, allow_overrides) then return end local function do_combine_stem_ending(stem, ending) return combine_stem_ending(base, slot, base.prefix, stem, ending) end iut.add_forms(base.forms, slot, stems, endings, do_combine_stem_ending, nil, nil, footnotes) end local function insert_form(base, slot, form) if not skip_slot(base, slot) then iut.insert_form(base.forms, slot, form) end end local function insert_forms(base, slot, forms) if not skip_slot(base, slot) then iut.insert_forms(base.forms, slot, forms) end end local function add_single_stem_tense(base, slot_pref, stems, s1, s2, s3, p1, p2, p3) local function addit(slot, ending) add3(base, slot_pref .. "_" .. slot, stems, ending) end addit("1s", s1) addit("2s", s2) addit("3s", s3) addit("1p", p1) addit("2p", p2) addit("3p", p3) end local function construct_stems(base, vowel_alt, imp_only) local stems = {} if imp_only then stems.imp2s_override = -- If no_pres_stressed given, there should be no imp_2s. not base.no_pres_stressed and ( base.stems.imp2s_override or vowel_alt.imp2s_override or nil) or nil base.this_stems = stems return end local function combine(slot, stem, ending) return combine_stem_ending(base, slot, base.prefix, stem, ending, "dont include prefix") end stems.pres_unstressed = base.stems.pres_unstressed or base.inf_stem stems.pres_stressed = -- If no_pres_stressed given, pres_stressed stem should be empty so no forms are generated. base.no_pres_stressed and {} or base.stems.pres_stressed or vowel_alt.pres_stressed or base.inf_stem stems.pres1_and_sub = -- If no_pres_stressed given, the entire subjunctive is missing. base.no_pres_stressed and {} or -- If no_pres1_and_sub given, pres1 and entire subjunctive are missing. base.no_pres1_and_sub and {} or base.stems.pres1_and_sub or vowel_alt.pres1_and_sub or nil stems.pres1 = base.stems.pres1 or stems.pres1_and_sub or stems.pres_stressed stems.impf = base.stems.impf or base.inf_stem stems.full_impf = base.stems.full_impf stems.pret_base = base.stems.pret_base or base.inf_stem stems.pret_conj = base.stems.pret_conj or base.conj stems.pret = base.stems.pret or iut.map_forms(iut.convert_to_general_list_form(stems.pret_base), -- use combine_stem_ending esp. so we get saíra etc. function(form) return combine("pret", form, base.conj_vowel) end) stems.short_pret = base.stems.gl_short_pret or iut.map_forms(iut.convert_to_general_list_form(stems.pret), function(form) return rsub(form, com.V .. "$", "") end) stems.fut = base.stems.fut or base.inf_stem .. base.conj stems.cond = base.stems.cond or stems.fut stems.pres_sub_stressed = base.stems.pres_sub_stressed or stems.pres1 stems.pres_sub_unstressed = base.stems.pres_sub_unstressed or stems.pres1_and_sub or stems.pres_unstressed stems.sub_conj = base.stems.sub_conj or base.conj stems.plup = base.stems.plup or stems.pret -- Needed for plup_1p and plup_2p if there's an accent in the regular pluperfect stem (as for [[saír]]). stems.plup_unstressed = iut.map_forms(iut.convert_to_general_list_form(stems.plup), com.remove_final_accent) stems.impf_sub = base.stems.impf_sub or stems.pret -- Needed for impf_sub_1p and impf_sub_2p. We can't just add an acute accent because there may already be one -- (as for [[saír]]). stems.impf_sub_antepenult_stressed = iut.map_forms(iut.convert_to_general_list_form(stems.impf_sub), com.add_final_accent) stems.fut_sub = base.stems.fut_sub or stems.pret -- use combine_stem_ending esp. so we get saír, saírmos, etc. stems.pers_inf = base.stems.pers_inf or combine("pers_inf", base.inf_stem, base.conj_vowel) -- use combine_stem_ending esp. so we get roído, caído, etc. stems.pp = base.stems.pp or combine("pp_ms", base.inf_stem, base.conj == "ar" and "ado" or "ido") stems.pp_ms = stems.pp local function masc_to_fem(form) if rfind(form, "o$") then return rsub(form, "o$", "a") else return form end end stems.pp_fs = iut.map_forms(iut.convert_to_general_list_form(stems.pp_ms), masc_to_fem) if base.stems.short_pp then stems.short_pp_ms = base.stems.short_pp stems.short_pp_fs = iut.map_forms(iut.convert_to_general_list_form(stems.short_pp_ms), masc_to_fem) end base.this_stems = stems end local function add_present_indic(base) local stems = base.this_stems local function addit(slot, stems, ending) add3(base, "pres_" .. slot, stems, ending) end local s2, s3, p1, p2, p3 if base.conj == "ar" then s2, s3, p1, p2, p3 = "as", "a", "amos", "ades", "an" elseif base.conj == "er" or base.conj == "or" then -- verbs in -por have the present overridden s2, s3, p1, p2, p3 = "es", "e", "emos", "edes", "en" elseif base.conj == "ir" then s2, s3, p1, p2, p3 = "es", "e", "imos", "ides", "en" else error("Internal error: Unrecognized conjugation " .. base.conj) end addit("1s", stems.pres1, "o") addit("2s", stems.pres_stressed, s2) addit("3s", stems.pres_stressed, s3) addit("1p", stems.pres_unstressed, p1) addit("2p", stems.pres_unstressed, p2) addit("3p", stems.pres_stressed, p3) end local function add_present_subj(base) local stems = base.this_stems local function addit(slot, stems, ending) add3(base, "pres_sub_" .. slot, stems, ending) end local s1, s2, s3, p1, p2, p3 if stems.sub_conj == "ar" then s1, s2, s3, p1, p2, p3 = "e", "es", "e", "emos", "edes", "en" else s1, s2, s3, p1, p2, p3 = "a", "as", "a", "amos", "ades", "an" end addit("1s", stems.pres_sub_stressed, s1) addit("2s", stems.pres_sub_stressed, s2) addit("3s", stems.pres_sub_stressed, s3) addit("1p", stems.pres_sub_unstressed, p1) addit("2p", stems.pres_sub_unstressed, p2) addit("3p", stems.pres_sub_stressed, p3) end local function add_finite_non_present(base) local stems = base.this_stems local function add_tense(slot, stem, s1, s2, s3, p1, p2, p3) add_single_stem_tense(base, slot, stem, s1, s2, s3, p1, p2, p3) end if stems.full_impf then add_tense("impf", stems.full_impf, "a", "as", "a", "amos", "ades", "an") elseif base.conj == "ar" then add_tense("impf", stems.impf, "aba", "abas", "aba", "abamos", "abades", "aban") else add_tense("impf", stems.impf, "ía", "ías", "ía", "iamos", "iades", "ían") end if stems.pret_conj == "irreg" then add_tense("pret", stems.short_pret, "en", nil, "o") add_tense("pret", stems.pret, nil, "ches", nil, "mos", "stes", "ron") elseif stems.pret_conj == "ar" then add_tense("pret", stems.pret_base, "ei", "aches", "ou", "amos", "astes", "aron") elseif stems.pret_conj == "er" then add_tense("pret", stems.pret_base, "ín", "iches", "eu", "emos", "estes", "eron") else add_tense("pret", stems.pret_base, "ín", "iches", "iu", "imos", "istes", "iron") end add_tense("plup", stems.plup, "ra", "ras", "ra", nil, nil, "ran") add_tense("plup", stems.plup_unstressed, nil, nil, nil, "ramos", "rades", nil) add_tense("impf_sub", stems.impf_sub, "se", "ses", "se", nil, nil, "sen") add_tense("impf_sub", stems.impf_sub_antepenult_stressed, nil, nil, nil, "semos", "sedes", nil) add_tense("fut_sub", stems.fut_sub, "r", "res", "r", "rmos", "rdes", "ren") add_tense("fut", stems.fut, "ei", "ás", "á", "emos", "edes", "án") add_tense("cond", stems.cond, "ía", "ías", "ía", "iamos", "iades", "ían") -- [[pór]] needs overrides of the pers_inf_1s and pers_inf_3s. add_tense("pers_inf", stems.pers_inf, "r", "res", "r", "rmos", "rdes", "ren") end local function add_non_finite_forms(base) local stems = base.this_stems local function addit(slot, stems, ending, footnotes) add3(base, slot, stems, ending, footnotes) end insert_form(base, "infinitive", {form = base.verb}) -- Also insert "infinitive + reflexive pronoun" combinations if we're handling a reflexive verb. See comment below -- for "gerund + reflexive pronoun" combinations. if base.refl then for _, persnum in ipairs(person_number_list) do insert_form(base, "infinitive_" .. persnum, {form = base.verb}) end end -- verbs in -por have the gerund overridden local ger_ending = base.conj == "ar" and "ando" or base.conj == "er" and "endo" or "indo" addit("gerund", stems.pres_unstressed, ger_ending) -- Also insert "gerund + reflexive pronoun" combinations if we're handling a reflexive verb. We insert exactly the -- same form as for the bare gerund; later on in add_reflexive_or_fixed_clitic_to_forms(), we add the appropriate -- clitic pronouns. It's important not to do this for non-reflexive verbs, because in that case, the clitic -- pronouns won't be added, and {{gl-verb form of}} will wrongly consider all these combinations as possible -- inflections of the bare gerund. Thanks to [[User:JeffDoozan]] for this bug fix. if base.refl then for _, persnum in ipairs(person_number_list) do addit("gerund_" .. persnum, stems.pres_unstressed, ger_ending) end end -- Skip the long/short past participle footnotes if called from {{gl-verb}} so they don't show in the headword. local long_pp_footnotes = stems.short_pp_ms and base.alternant_multiword_spec.source_template ~= "gl-verb" and {long_pp_footnote} or nil addit("pp_ms", stems.pp_ms, "", long_pp_footnotes) if not base.pp_inv then addit("pp_fs", stems.pp_fs, "", long_pp_footnotes) addit("pp_mp", stems.pp_ms, "s", long_pp_footnotes) addit("pp_fp", stems.pp_fs, "s", long_pp_footnotes) end if stems.short_pp_ms then local short_pp_footnotes = stems.short_pp_ms and base.alternant_multiword_spec.source_template ~= "gl-verb" and {short_pp_footnote} or nil addit("short_pp_ms", stems.short_pp_ms, "", short_pp_footnotes) if not base.pp_inv then addit("short_pp_fs", stems.short_pp_fs, "", short_pp_footnotes) addit("short_pp_mp", stems.short_pp_ms, "s", short_pp_footnotes) addit("short_pp_fp", stems.short_pp_fs, "s", short_pp_footnotes) end end end local function add_imperatives(base) for _, vowel_alt in ipairs(base.vowel_alt_stems) do construct_stems(base, vowel_alt, "imp only") local stems = base.this_stems if stems.imp2s_override then add3(base, "imp_2s", stems.imp2s_override, base.conj == "ar" and "a" or "e") else -- Copy pres3s to imperative since they are almost always the same. insert_forms(base, "imp_2s", iut.map_forms(base.forms.pres_3s, function(form) return form end)) end end if not skip_slot(base, "imp_2p") then -- Copy pres2p to imperative 2p minus -s since they are almost always the same. -- But not if there's an override, to avoid possibly throwing an error. insert_forms(base, "imp_2p", iut.map_forms(base.forms.pres_2p, function(form) local form_no_s = rmatch(form, "^(.*)s$") if not form_no_s then error("Can't derive second-person plural imperative from second-person plural present indicative " .. "because form '" .. form .. "' doesn't end in -s") end return form_no_s end)) end -- Copy subjunctives to imperatives, unless there's an override for the given slot (as with the imp_1p of [[ir]]). for _, persnum in ipairs({"3s", "1p", "3p"}) do local from = "pres_sub_" .. persnum local to = "imp_" .. persnum insert_forms(base, to, iut.map_forms(base.forms[from], function(form) return form end)) end end local function process_slot_overrides(base, filter_slot, reflexive_only) local overrides = reflexive_only and base.basic_reflexive_only_overrides or base.basic_overrides for slot, forms in pairs(overrides) do if not filter_slot or filter_slot(slot) then add3(base, slot, forms, "", nil, "allow overrides") end end end -- Prefix `form` with `clitic`, adding fixed text `between` between them. Add links as appropriate unless the user -- requested no links. Check whether form already has brackets (as will be the case if the form has a fixed clitic). local function prefix_clitic_to_form(base, clitic, between, form) if base.alternant_multiword_spec.args.noautolinkverb then return clitic .. between .. form else local clitic_pref = "[[" .. clitic .. "]]" .. between if form:find("%[%[") then return clitic_pref .. form else return clitic_pref .. "[[" .. form .. "]]" end end end -- Add the appropriate clitic pronouns in `clitics` to the forms in `base_slot`. `store_cliticized_form` is a function -- of three arguments (clitic, formobj, cliticized_form) and should store the cliticized form for the specified clitic -- and form object. local function suffix_clitic_to_forms(base, base_slot, clitics, store_cliticized_form) if not base.forms[base_slot] then -- This can happen, e.g. in only3s/only3sp/only3p verbs. return end for _, formobj in ipairs(base.forms[base_slot]) do -- Figure out the correct accenting of the verb when a clitic pronoun is attached to it. We may need to -- add or remove an accent mark: -- (1) No accent mark currently, none needed: infinitive sentar -> sentarse; imperative singular ten -> tente; -- (2) Accent mark currently, still needed: infinitive concluír -> concluírse; -- (3) No accent mark currently, accent needed: imperative singular sinte -> síntete; -- (4) Accent mark currently, not needed: third singular sentirá -> sentirase, imperative singular dá -> date. local syllables = com.syllabify(formobj.form) local sylno = com.stressed_syllable(syllables) table.insert(syllables, "lo") -- arbitrary stand-in local needs_accent = com.accent_needed(syllables, sylno) if needs_accent then syllables[sylno] = com.add_accent_to_syllable(syllables[sylno]) else syllables[sylno] = com.remove_accent_from_syllable(syllables[sylno]) end table.remove(syllables) -- remove added clitic pronoun local reaccented_form = table.concat(syllables) for _, clitic in ipairs(clitics) do local cliticized_form -- Some further special cases. if base_slot:find("_1p$") and clitic == "nos" then -- Final -s disappears: sintamos + nos -> sintámonos cliticized_form = reaccented_form:gsub("s$", "") .. clitic elseif clitic:find("^[oa]s?$") then if reaccented_form:find("[rs]$") then cliticized_form = reaccented_form:gsub("[rs]$", "l") .. clitic elseif reaccented_form:find(V .. "[iu]$") then cliticized_form = reaccented_form .. "n" .. clitic else cliticized_form = reaccented_form .. clitic end else cliticized_form = reaccented_form .. clitic end store_cliticized_form(clitic, formobj, cliticized_form) end end end -- Add a reflexive pronoun or fixed clitic (FIXME: not working), as appropriate to the base forms that were generated. -- `do_joined` means to do only the forms where the pronoun is joined to the end of the form; otherwise, do only the -- forms where it is not joined and precedes the form. local function add_reflexive_or_fixed_clitic_to_forms(base, do_reflexive, do_joined) for _, slotaccel in ipairs(base.alternant_multiword_spec.verb_slots_basic) do local slot, accel = unpack(slotaccel) local clitic if not do_reflexive then clitic = base.clitic elseif slot:find("[123]") then local persnum = slot:match("^.*_(.-)$") clitic = person_number_to_reflexive_pronoun[persnum] else clitic = "se" end if base.forms[slot] then if do_reflexive and slot:find("^pp_") or slot == "infinitive_linked" then -- do nothing with reflexive past participles or with infinitive linked (handled at the end) elseif slot:find("^neg_imp_") then error("Internal error: Should not have forms set for negative imperative at this stage") else local slot_has_suffixed_clitic = not slot:find("_sub") -- Maybe generate non-reflexive parts and separated syntactic variants for use in -- {{gl-verb form of}}. See comment in add_slots() above `need_special_verb_form_of_slots`. -- Check for do_joined so we only run this code once. if do_reflexive and do_joined and base.alternant_multiword_spec.source_template == "gl-verb form of" and -- Skip personal variants of infinitives and gerunds so we don't think [[arrependendo]] is a -- non-reflexive equivalent of [[arrependendo-me]]. not slot:find("infinitive_") and not slot:find("gerund_") then -- Clone the forms because we will be destructively modifying them just below, adding the reflexive -- pronoun. insert_forms(base, slot .. "_non_reflexive", mw.clone(base.forms[slot])) if slot_has_suffixed_clitic then insert_forms(base, slot .. "_variant", iut.map_forms(base.forms[slot], function(form) return prefix_clitic_to_form(base, clitic, " ... ", form) end)) end end if slot_has_suffixed_clitic then if do_joined then suffix_clitic_to_forms(base, slot, {clitic}, function(clitic, formobj, cliticized_form) formobj.form = cliticized_form end ) end elseif not do_joined then -- Add clitic as separate word before all other forms. for _, form in ipairs(base.forms[slot]) do form.form = prefix_clitic_to_form(base, clitic, " ", form.form) end end end end end end local function handle_infinitive_linked(base) -- Compute linked versions of potential lemma slots, for use in {{gl-verb}}. -- We substitute the original lemma (before removing links) for forms that -- are the same as the lemma, if the original lemma has links. for _, slot in ipairs({"infinitive"}) do insert_forms(base, slot .. "_linked", iut.map_forms(base.forms[slot], function(form) if form == base.lemma and rfind(base.linked_lemma, "%[%[") then return base.linked_lemma else return form end end)) end end local function generate_negative_imperatives(base) -- Copy subjunctives to negative imperatives, preceded by "non". for _, persnum in ipairs(neg_imp_person_number_list) do local from = "pres_sub_" .. persnum local to = "neg_imp_" .. persnum insert_forms(base, to, iut.map_forms(base.forms[from], function(form) if base.alternant_multiword_spec.args.noautolinkverb then return "non " .. form elseif form:find("%[%[") then -- already linked, e.g. when reflexive return "[[non]] " .. form else return "[[non]] [[" .. form .. "]]" end end)) end end -- Process specs given by the user using 'addnote[SLOTSPEC][FOOTNOTE][FOOTNOTE][...]'. local function process_addnote_specs(base) for _, spec in ipairs(base.addnote_specs) do for _, slot_spec in ipairs(spec.slot_specs) do slot_spec = "^" .. slot_spec .. "$" for slot, forms in pairs(base.forms) do if rfind(slot, slot_spec) then -- To save on memory, side-effect the existing forms. for _, form in ipairs(forms) do form.footnotes = iut.combine_footnotes(form.footnotes, spec.footnotes) end end end end end end local function add_missing_links_to_forms(base) -- Any forms without links should get them now. Redundant ones will be stripped later. for slot, forms in pairs(base.forms) do for _, form in ipairs(forms) do if not form.form:find("%[%[") then form.form = "[[" .. form.form .. "]]" end end end end local function conjugate_verb(base) for _, vowel_alt in ipairs(base.vowel_alt_stems) do construct_stems(base, vowel_alt) add_present_indic(base) add_present_subj(base) end add_finite_non_present(base) add_non_finite_forms(base) -- do non-reflexive non-imperative slot overrides process_slot_overrides(base, function(slot) return not slot:find("^imp_") and not slot:find("^neg_imp_") end) -- This should happen after process_slot_overrides() in case a derived slot is based on an override -- (as with the imp_3s of [[dar]], [[estar]]). add_imperatives(base) -- do non-reflexive positive imperative slot overrides process_slot_overrides(base, function(slot) return slot:find("^imp_") end) -- We need to add joined reflexives, then joined and non-joined clitics, then non-joined reflexives, so we get -- [[arrepéndete]] but [[non]] [[te]] [[arrependas]]. if base.refl then add_reflexive_or_fixed_clitic_to_forms(base, "do reflexive", "do joined") process_slot_overrides(base, nil, "do reflexive") -- do reflexive-only slot overrides add_reflexive_or_fixed_clitic_to_forms(base, "do reflexive", false) end -- This should happen after add_reflexive_or_fixed_clitic_to_forms() so negative imperatives get the reflexive pronoun -- and clitic in them. generate_negative_imperatives(base) -- do non-reflexive negative imperative slot overrides -- FIXME: What about reflexive negative imperatives? process_slot_overrides(base, function(slot) return slot:find("^neg_imp_") end) -- This should happen before add_missing_links_to_forms() so that the comparison `form == base.lemma` -- in handle_infinitive_linked() works correctly and compares unlinked forms to unlinked forms. handle_infinitive_linked(base) process_addnote_specs(base) if not base.alternant_multiword_spec.args.noautolinkverb then add_missing_links_to_forms(base) end end local function parse_indicator_spec(angle_bracket_spec) -- Store the original angle bracket spec so we can reconstruct the overall conj spec with the lemma(s) in them. local base = { angle_bracket_spec = angle_bracket_spec, user_basic_overrides = {}, user_stems = {}, addnote_specs = {}, } local function parse_err(msg) error(msg .. ": " .. angle_bracket_spec) end local function fetch_footnotes(separated_group) 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 inside = angle_bracket_spec:match("^<(.*)>$") assert(inside) if inside == "" then return base end local segments = put.parse_balanced_segment_run(inside, "[", "]") local dot_separated_groups = put.split_alternating_runs(segments, "%.") for i, dot_separated_group in ipairs(dot_separated_groups) do local first_element = dot_separated_group[1] if first_element == "addnote" then local spec_and_footnotes = fetch_footnotes(dot_separated_group) if #spec_and_footnotes < 2 then parse_err("Spec with 'addnote' should be of the form 'addnote[SLOTSPEC][FOOTNOTE][FOOTNOTE][...]'") end local slot_spec = table.remove(spec_and_footnotes, 1) local slot_spec_inside = rmatch(slot_spec, "^%[(.*)%]$") if not slot_spec_inside then parse_err("Internal error: slot_spec " .. slot_spec .. " should be surrounded with brackets") end local slot_specs = rsplit(slot_spec_inside, ",") -- FIXME: Here, [[Module:it-verb]] called strip_spaces(). Generally we don't do this. Should we? table.insert(base.addnote_specs, {slot_specs = slot_specs, footnotes = spec_and_footnotes}) elseif indicator_flags[first_element] then if #dot_separated_group > 1 then parse_err("No footnotes allowed with '" .. first_element .. "' spec") end if base[first_element] then parse_err("Spec '" .. first_element .. "' specified twice") end base[first_element] = true elseif rfind(first_element, ":") then local colon_separated_groups = put.split_alternating_runs(dot_separated_group, "%s*:%s*") local first_element = colon_separated_groups[1][1] if #colon_separated_groups[1] > 1 then parse_err("Can't attach footnotes directly to '" .. first_element .. "' spec; attach them to the " .. "colon-separated values following the initial colon") end if overridable_stems[first_element] then if base.user_stems[first_element] then parse_err("Overridable stem '" .. first_element .. "' specified twice") end table.remove(colon_separated_groups, 1) base.user_stems[first_element] = overridable_stems[first_element](colon_separated_groups, {prefix = first_element, base = base, parse_err = parse_err, fetch_footnotes = fetch_footnotes}) else -- assume a basic override; we validate further later when the possible slots are available if base.user_basic_overrides[first_element] then parse_err("Basic override '" .. first_element .. "' specified twice") end table.remove(colon_separated_groups, 1) base.user_basic_overrides[first_element] = allow_multiple_values(colon_separated_groups, {prefix = first_element, base = base, parse_err = parse_err, fetch_footnotes = fetch_footnotes}) end else local comma_separated_groups = put.split_alternating_runs(dot_separated_group, "%s*,%s*") for j = 1, #comma_separated_groups do local alt = comma_separated_groups[j][1] if not vowel_alternants[alt] then if #comma_separated_groups == 1 then parse_err("Unrecognized spec or vowel alternant '" .. alt .. "'") else parse_err("Unrecognized vowel alternant '" .. alt .. "'") end end if base.vowel_alt then for _, existing_alt in ipairs(base.vowel_alt) do if existing_alt.form == alt then parse_err("Vowel alternant '" .. alt .. "' specified twice") end end else base.vowel_alt = {} end table.insert(base.vowel_alt, {form = alt, footnotes = fetch_footnotes(comma_separated_groups[j])}) end end end return base end -- Normalize all lemmas, substituting the pagename for blank lemmas and adding links to multiword lemmas. local function normalize_all_lemmas(alternant_multiword_spec, head) -- (1) Add links to all before and after text. Remember the original text so we can reconstruct the verb spec later. if not alternant_multiword_spec.args.noautolinktext then iut.add_links_to_before_and_after_text(alternant_multiword_spec, "remember original") end -- (2) Remove any links from the lemma, but remember the original form -- so we can use it below in the 'lemma_linked' form. iut.map_word_specs(alternant_multiword_spec, function(base) if base.lemma == "" then base.lemma = head end base.user_specified_lemma = base.lemma base.lemma = m_links.remove_links(base.lemma) local refl_verb = base.lemma local verb, refl = rmatch(refl_verb, "^(.-)(se)$") if not verb then verb, refl = refl_verb, nil end base.user_specified_verb = verb base.refl = refl base.verb = base.user_specified_verb local linked_lemma if alternant_multiword_spec.args.noautolinkverb or base.user_specified_lemma:find("%[%[") then linked_lemma = base.user_specified_lemma elseif base.refl then -- Reconstruct the linked lemma with separate links around base verb, reflexive pronoun and clitic. linked_lemma = base.user_specified_verb == base.verb and "[[" .. base.user_specified_verb .. "]]" or "[[" .. base.verb .. "|" .. base.user_specified_verb .. "]]" linked_lemma = linked_lemma .. (refl and "[[" .. refl .. "]]" or "") else -- Add links to the lemma so the user doesn't specifically need to, since we preserve -- links in multiword lemmas and include links in non-lemma forms rather than allowing -- the entire form to be a link. linked_lemma = iut.add_links(base.user_specified_lemma) end base.linked_lemma = linked_lemma end) end local function detect_indicator_spec(base) if (base.only3s and 1 or 0) + (base.only3sp and 1 or 0) + (base.only3p and 1 or 0) > 1 then error("Only one of 'only3s', 'only3sp' and 'only3p' can be specified") end base.forms = {} base.stems = {} base.basic_overrides = {} base.basic_reflexive_only_overrides = {} if not base.no_built_in then for _, built_in_conj in ipairs(built_in_conjugations) do if type(built_in_conj.match) == "function" then base.prefix, base.non_prefixed_verb = built_in_conj.match(base.verb) elseif built_in_conj.match:find("^%^") and rsub(built_in_conj.match, "^%^", "") == base.verb then -- begins with ^, for exact match, and matches base.prefix, base.non_prefixed_verb = "", base.verb else base.prefix, base.non_prefixed_verb = rmatch(base.verb, "^(.*)(" .. built_in_conj.match .. ")$") end if base.prefix then -- we found a built-in verb for stem, forms in pairs(built_in_conj.forms) do if type(forms) == "function" then forms = forms(base, base.prefix) end if stem:find("^refl_") then stem = stem:gsub("^refl_", "") if not base.alternant_multiword_spec.verb_slots_basic_map[stem] then error("Internal error: setting for 'refl_" .. stem .. "' does not refer to a basic verb slot") end base.basic_reflexive_only_overrides[stem] = forms elseif base.alternant_multiword_spec.verb_slots_basic_map[stem] then -- an individual form override of a basic form base.basic_overrides[stem] = forms else base.stems[stem] = forms end end break end end end -- Override built-in-verb stems and overrides with user-specified ones. for stem, values in pairs(base.user_stems) do base.stems[stem] = values end for override, values in pairs(base.user_basic_overrides) do if not base.alternant_multiword_spec.verb_slots_basic_map[override] then error("Unrecognized override '" .. override .. "': " .. base.angle_bracket_spec) end base.basic_overrides[override] = values end base.prefix = base.prefix or "" base.non_prefixed_verb = base.non_prefixed_verb or base.verb local inf_stem, suffix = rmatch(base.non_prefixed_verb, "^(.*)([aeiíoó]r)$") if not inf_stem then error("Unrecognized infinitive: " .. base.verb) end base.inf_stem = inf_stem suffix = suffix == "ór" and "or" or suffix == "ír" and "ir" or suffix base.conj = suffix base.conj_vowel = suffix == "ar" and "a" or suffix == "ir" and "i" or "e" base.frontback = suffix == "ar" and "back" or "front" if base.stems.vowel_alt then -- built-in verb with specified vowel alternation if base.vowel_alt then error(base.verb .. " is a recognized built-in verb, and should not have vowel alternations specified with it") end base.vowel_alt = iut.convert_to_general_list_form(base.stems.vowel_alt) end -- Propagate built-in-verb indicator flags to `base` and combine with user-specified flags. for indicator_flag, _ in pairs(indicator_flags) do base[indicator_flag] = base[indicator_flag] or base.stems[indicator_flag] end -- Convert vowel alternation indicators into stems. local vowel_alt = base.vowel_alt or {{form = "+"}} base.vowel_alt_stems = apply_vowel_alternations(base.inf_stem, vowel_alt) for _, vowel_alt_stems in ipairs(base.vowel_alt_stems) do if vowel_alt_stems.err then error("To use '" .. vowel_alt_stems.altobj.form .. "', present stem '" .. base.prefix .. base.inf_stem .. "' " .. vowel_alt_stems.err) end end end local function detect_all_indicator_specs(alternant_multiword_spec) -- Propagate some settings up; some are used internally, others by [[Module:gl-headword]]. iut.map_word_specs(alternant_multiword_spec, function(base) -- Internal indicator flags. Do these before calling detect_indicator_spec() because add_slots() uses them. for _, prop in ipairs { "refl", "clitic" } do if base[prop] then alternant_multiword_spec[prop] = true end end base.alternant_multiword_spec = alternant_multiword_spec end) add_slots(alternant_multiword_spec) alternant_multiword_spec.vowel_alt = {} iut.map_word_specs(alternant_multiword_spec, function(base) detect_indicator_spec(base) -- User-specified indicator flags. Do these after calling detect_indicator_spec() because the latter may set these -- indicators for built-in verbs. for prop, _ in pairs(indicator_flags) do if base[prop] then alternant_multiword_spec[prop] = true end end -- Vowel alternants. Do these after calling detect_indicator_spec() because the latter sets base.vowel_alt for -- built-in verbs. if base.vowel_alt then for _, altobj in ipairs(base.vowel_alt) do m_table.insertIfNot(alternant_multiword_spec.vowel_alt, altobj.form) end end end) end local function add_categories_and_annotation(alternant_multiword_spec, base, multiword_lemma) local function insert_ann(anntype, value) m_table.insertIfNot(alternant_multiword_spec.annotation[anntype], value) end local function insert_cat(cat, also_when_multiword) -- Don't place multiword terms in categories like 'Galician verbs ending in -ar' to avoid spamming the -- categories with such terms. if also_when_multiword or not multiword_lemma then -- m_table.insertIfNot(alternant_multiword_spec.categories, "Galician " .. cat) end end if check_for_red_links and alternant_multiword_spec.source_template == "gl-conj" and multiword_lemma then for _, slot_and_accel in ipairs(alternant_multiword_spec.all_verb_slots) do local slot = slot_and_accel[1] local forms = base.forms[slot] local must_break = false if forms then for _, form in ipairs(forms) do if not form.form:find("%[%[") then local title = mw.title.new(form.form) if title and not title.exists then -- insert_cat("verbs with red links in their inflection tables") must_break = true break end end end end if must_break then break end end end if(base.conj == "or") then -- insert_cat("verbs ending in -er") else -- insert_cat("verbs ending in -" .. base.conj) end if base.irreg then insert_ann("irreg", "irregular") -- insert_cat("irregular verbs") else insert_ann("irreg", "regular") end if base.only3s then insert_ann("defective", "impersonal") -- insert_cat("impersonal verbs") elseif base.only3sp then insert_ann("defective", "third-person only") -- insert_cat("third-person-only verbs") elseif base.only3p then insert_ann("defective", "third-person plural only") -- insert_cat("third-person-plural-only verbs") elseif base.no_pres_stressed or base.no_pres1_and_sub then insert_ann("defective", "defective") -- insert_cat("defective verbs") else insert_ann("defective", "regular") end if base.stems.short_pp then insert_ann("short_pp", "irregular short past participle") -- insert_cat("verbs with irregular short past participle") else insert_ann("short_pp", "regular") end if base.clitic then -- insert_cat("verbs with lexical clitics") end if base.refl then -- insert_cat("reflexive verbs") end if not base.vowel_alt then insert_ann("vowel_alt", "non-alternating") else for _, alt in ipairs(base.vowel_alt) do if alt.form == "+" then insert_ann("vowel_alt", "non-alternating") else insert_ann("vowel_alt", vowel_alternant_to_desc[alt.form]) insert_cat("verbs with " .. vowel_alternant_to_cat[alt.form]) end end end local cons_alt = base.stems.cons_alt if cons_alt == nil then if base.conj == "ar" then if base.inf_stem:find("z$") then cons_alt = "c-z" elseif base.inf_stem:find("c$") then cons_alt = "c-qu" elseif base.inf_stem:find("g$") then cons_alt = "g-gu" elseif base.inf_stem:find("gu$") then cons_alt = "gu-gü" end else if base.no_pres_stressed or base.no_pres1_and_sub then cons_alt = nil -- no e.g. c-z alternation in this case elseif base.inf_stem:find("c$") then cons_alt = "c-z" elseif base.inf_stem:find("qu$") then cons_alt = "c-qu" elseif base.inf_stem:find("gu$") then cons_alt = "g-gu" elseif base.inf_stem:find("gü$") then cons_alt = "gu-gü" end end end if cons_alt then local desc = cons_alt .. " alternation" insert_ann("cons_alt", desc) insert_cat("verbs with " .. desc) else insert_ann("cons_alt", "non-alternating") end end -- Compute the categories to add the verb to, as well as the annotation to display in the -- conjugation title bar. We combine the code to do these functions as both categories and -- title bar contain similar information. local function compute_categories_and_annotation(alternant_multiword_spec) alternant_multiword_spec.categories = {} local ann = {} alternant_multiword_spec.annotation = ann ann.irreg = {} ann.short_pp = {} ann.defective = {} ann.vowel_alt = {} ann.cons_alt = {} local multiword_lemma = false for _, form in ipairs(alternant_multiword_spec.forms.infinitive) do if form.form:find(" ") then multiword_lemma = true break end end iut.map_word_specs(alternant_multiword_spec, function(base) add_categories_and_annotation(alternant_multiword_spec, base, multiword_lemma) end) local ann_parts = {} local irreg = table.concat(ann.irreg, " or ") if irreg ~= "" and irreg ~= "regular" then table.insert(ann_parts, irreg) end local short_pp = table.concat(ann.short_pp, " or ") if short_pp ~= "" and short_pp ~= "regular" then table.insert(ann_parts, short_pp) end local defective = table.concat(ann.defective, " or ") if defective ~= "" and defective ~= "regular" then table.insert(ann_parts, defective) end local vowel_alt = table.concat(ann.vowel_alt, " or ") if vowel_alt ~= "" and vowel_alt ~= "non-alternating" then table.insert(ann_parts, vowel_alt) end local cons_alt = table.concat(ann.cons_alt, " or ") if cons_alt ~= "" and cons_alt ~= "non-alternating" then table.insert(ann_parts, cons_alt) end alternant_multiword_spec.annotation = table.concat(ann_parts, "; ") end local function show_forms(alternant_multiword_spec) local lemmas = alternant_multiword_spec.forms.infinitive alternant_multiword_spec.lemmas = lemmas -- save for later use in make_table() if alternant_multiword_spec.forms.short_pp_ms then alternant_multiword_spec.has_short_pp = true end local reconstructed_verb_spec = iut.reconstruct_original_spec(alternant_multiword_spec) local function transform_accel_obj(slot, formobj, accel_obj) -- No accelerators for negative imperatives, which are always multiword and derived directly from the -- present subjunctive. if slot:find("^neg_imp") then return nil end if accel_obj then if slot:find("^pp_") then accel_obj.form = slot elseif slot == "gerund" then accel_obj.form = "gerund-" .. reconstructed_verb_spec else accel_obj.form = "verb-form-" .. reconstructed_verb_spec end end return accel_obj end local props = { lang = lang, lemmas = lemmas, transform_accel_obj = transform_accel_obj, slot_list = alternant_multiword_spec.verb_slots_basic, } iut.show_forms(alternant_multiword_spec.forms, props) alternant_multiword_spec.footnote_basic = alternant_multiword_spec.forms.footnote end local notes_template = [=[ <div class="roa-footnote-outer-div" style="width:100%;"> <div class="roa-footnote-inner-div"> {footnote} </div></div> ]=] local basic_table = [=[ {description}<div class="NavFrame"> <div class="NavHead" align=center>&nbsp; &nbsp; သမ္ဗန္ဓဆေၚ်စပ်ကဵု {title}</div> <div class="NavContent" align="left"> {\op}| class="roa-inflection-table" data-toggle-category="inflection" |- ! class="roa-person-number-header" rowspan="2" | ! class="roa-person-number-header" colspan="3" | ကိုန်ဨကဝုစ် ! class="roa-person-number-header" colspan="3" | Plural |- ! class="roa-person-number-header" style="width:12.5%" | ပူဂဵုပထမ<br />(<<eu>>) ! class="roa-person-number-header" style="width:12.5%" | ပူဂဵုဒုတိယ<br />(<<ti>>) ! class="roa-person-number-header" style="width:12.5%" | ပူဂဵုတတိယ<br />(<<el>> / <<ela>> / <<vostede|Vde.>>) ! class="roa-person-number-header" style="width:12.5%" | ပူဂဵုပထမ<br />(<<nós>>) ! class="roa-person-number-header" style="width:12.5%" | ပူဂဵုတတိယ<br />(<<vós>>) ! class="roa-person-number-header" style="width:12.5%" | ပူဂဵုတတိယ<br />(<<eles>> / <<elas>> / <<vostedes|Vdes.>>) |- ! class="roa-nonfinite-header" colspan="7" | ''<span title="infinitivo">ကြိယာဟွံကၠောံ</span>'' |- ! class="roa-nonfinite-header" | '''<span title="infinitivo impersoal">ဟွံဆေၚ်စပ်ပရေၚ်ပူဂဵု</span>''' | colspan="6" | {infinitive} |- ! class="roa-nonfinite-header" | '''<span title="infinitivo conxugado">ပရေၚ်ပူဂဵု</span>''' | {pers_inf_1s} | {pers_inf_2s} | {pers_inf_3s} | {pers_inf_1p} | {pers_inf_2p} | {pers_inf_3p} |- ! class="roa-nonfinite-header" colspan="7" | ''<span title="xerundio">ကြိယာစၞးနာမ်</span>'' |- | class="roa-nonfinite-header" | | colspan="6" | {gerund} |-{pp_clause} ! class="roa-indicative-left-rail" colspan="7" | ''<span title="indicativo">ပရေၚ်စၞောန်ထ္ၜး</span>'' |- ! class="roa-indicative-left-rail" | <span title="presente">ပစ္စုပ္ပန်</span> | {pres_1s} | {pres_2s} | {pres_3s} | {pres_1p} | {pres_2p} | {pres_3p} |- ! class="roa-indicative-left-rail" | <span title="pretérito imperfecto">ဟွံဍိုက်ပေၚ်</span> | {impf_1s} | {impf_2s} | {impf_3s} | {impf_1p} | {impf_2p} | {impf_3p} |- ! class="roa-indicative-left-rail" | <span title="pretérito perfecto">ကာလအတိက်</span> | {pret_1s} | {pret_2s} | {pret_3s} | {pret_1p} | {pret_2p} | {pret_3p} |- ! class="roa-indicative-left-rail" | <span title="pretérito pluscuamperfecto">ဗီုပြၚ်မဍိုက်ပေၚ်</span> | {plup_1s} | {plup_2s} | {plup_3s} | {plup_1p} | {plup_2p} | {plup_3p} |- ! class="roa-indicative-left-rail" | <span title="futuro do presente">အနာဂတ်</span> | {fut_1s} | {fut_2s} | {fut_3s} | {fut_1p} | {fut_2p} | {fut_3p} |- ! class="roa-indicative-left-rail" | <span title="condicional">တၚ်မကၞာတ်လဝ်စေဝ်ပၞောန်</span> | {cond_1s} | {cond_2s} | {cond_3s} | {cond_1p} | {cond_2p} | {cond_3p} |- ! class="roa-subjunctive-left-rail" colspan="7" | ''<span title="subxuntivo">အရေဝ်နိဒါန်</span>'' |- ! class="roa-subjunctive-left-rail" | <span title=" presente do subxuntivo">ပစ္စုပ္ပန်</span> | {pres_sub_1s} | {pres_sub_2s} | {pres_sub_3s} | {pres_sub_1p} | {pres_sub_2p} | {pres_sub_3p} |- ! class="roa-subjunctive-left-rail" | <span title="pretérito imperfecto do subxuntivo">ဟွံဍိုက်ပေၚ်</span> | {impf_sub_1s} | {impf_sub_2s} | {impf_sub_3s} | {impf_sub_1p} | {impf_sub_2p} | {impf_sub_3p} |- ! class="roa-subjunctive-left-rail" | <span title="futuro do subxuntivo">အနာဂတ်</span> | {fut_sub_1s} | {fut_sub_2s} | {fut_sub_3s} | {fut_sub_1p} | {fut_sub_2p} | {fut_sub_3p} |- ! class="roa-imperative-left-rail" colspan="7" | ''<span title="imperativo">ပါဲဗလေတ်ဟွံဗၠး</span>'' |- ! class="roa-imperative-left-rail" | <span title="imperativo afirmativo">တၚ်ဂလာန်ဗိုန်ဗတ်</span> | rowspan="2" | | {imp_2s} | {imp_3s} | {imp_1p} | {imp_2p} | {imp_3p} |- ! class="roa-imperative-left-rail" | <span title="imperativo negativo">ဗဳဇဂကူ</span> (<<non>>) | {neg_imp_2s} | {neg_imp_3s} | {neg_imp_1p} | {neg_imp_2p} | {neg_imp_3p} |{\cl}{notes_clause}</div></div> ]=] local double_pp_template = [=[ ! class="roa-nonfinite-header" colspan="7" | ''<span title="participio irregular">လုပ်ကၠောန်စွံလဝ်နကဵုအတိက်ဗွဲမဓမၠေံ</span>'' |- ! class="roa-nonfinite-header" | ပုလ္လိၚ် | colspan="3" | {short_pp_ms} | colspan="3" | {short_pp_mp} |- ! class="roa-nonfinite-header" | ဣတ္တိလိၚ် | colspan="3" | {short_pp_fs} | colspan="3" | {short_pp_fp} |- ! class="roa-nonfinite-header" colspan="7" | ''<span title="participio regular">လုပ်ကၠောန်စွံလဝ်နကဵုအတိက်ဗွဲမဂပ်လံ</span>'' |- ! class="roa-nonfinite-header" | ပုလ္လိၚ် | colspan="3" | {pp_ms} | colspan="3" | {pp_mp} |- ! class="roa-nonfinite-header" | ဣတ္တိလိၚ် | colspan="3" | {pp_fs} | colspan="3" | {pp_fp} |-]=] local single_pp_template = [=[ ! class="roa-nonfinite-header" colspan="7" | ''<span title="participio pasado">လုပ်ကၠောန်စွံလဝ်နကဵုအတိက်</span>'' |- ! class="roa-nonfinite-header" | ပုလ္လိၚ် | colspan="3" | {pp_ms} | colspan="3" | {pp_mp} |- ! class="roa-nonfinite-header" | ဣတ္တိလိၚ် | colspan="3" | {pp_fs} | colspan="3" | {pp_fp} |-]=] local function make_table(alternant_multiword_spec) local forms = alternant_multiword_spec.forms forms.title = link_term(alternant_multiword_spec.lemmas[1].form) if alternant_multiword_spec.annotation ~= "" then forms.title = forms.title .. " (" .. alternant_multiword_spec.annotation .. ")" end forms.description = "" -- Format the table. forms.footnote = alternant_multiword_spec.footnote_basic forms.notes_clause = forms.footnote ~= "" and m_string_utilities.format(notes_template, forms) or "" -- has_short_pp is computed in show_forms(). local pp_template = alternant_multiword_spec.has_short_pp and double_pp_template or single_pp_template forms.pp_clause = m_string_utilities.format(pp_template, forms) local table_with_pronouns = rsub(basic_table, "<<([^<>|]-)|([^<>|]-)>>", link_term) local table_with_pronouns = rsub(table_with_pronouns, "<<(.-)>>", link_term) return require("Module:TemplateStyles")("Module:roa-verb/style.css") .. m_string_utilities.format(table_with_pronouns, forms) end -- Externally callable function to parse and conjugate a verb given user-specified arguments. -- Return value is WORD_SPEC, an object where the conjugated forms are in `WORD_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(args, source_template, headword_head) local PAGENAME = mw.loadData("Module:headword/data").pagename local function in_template_space() return mw.title.getCurrentTitle().nsText == "ထာမ်ပလိက်" end -- Determine the verb spec we're being asked to generate the conjugation of. This may be taken from the -- current page title or the value of |pagename=; but not when called from {{gl-verb form of}}, where the -- page title is a non-lemma form. Note that the verb spec may omit the infinitive; e.g. it may be "<i-e>". -- For this reason, we use the value of `pagename` computed here down below, when calling normalize_all_lemmas(). local pagename = source_template ~= "gl-verb form of" and args.pagename or PAGENAME local head = headword_head or pagename local arg1 = args[1] if not arg1 then if (pagename == "gl-conj" or pagename == "gl-verb") and in_template_space() then arg1 = "paliar<í,+>" elseif pagename == "gl-verb form of" and in_template_space() then arg1 = "amar" else arg1 = "<>" end end -- When called from {{gl-verb form of}}, determine the non-lemma form whose inflections we're being asked to -- determine. This normally comes from the page title or the value of |pagename=. local verb_form_of_form if source_template == "gl-verb form of" then verb_form_of_form = args.pagename if not verb_form_of_form then if PAGENAME == "gl-verb form of" and in_template_space() then verb_form_of_form = "ame" else verb_form_of_form = PAGENAME end end end local incorporated_headword_head_into_lemma = false if arg1:find("^<.*>$") then -- missing lemma if head:find(" ") then -- If multiword lemma, try to add arg spec after the first word. -- Try to preserve the brackets in the part after the verb, but don't do it -- if there aren't the same number of left and right brackets in the verb -- (which means the verb was linked as part of a larger expression). local refl_clitic_verb, post = rmatch(head, "^(.-)( .*)$") local left_brackets = rsub(refl_clitic_verb, "[^%[]", "") local right_brackets = rsub(refl_clitic_verb, "[^%]]", "") if #left_brackets == #right_brackets then arg1 = iut.remove_redundant_links(refl_clitic_verb) .. arg1 .. post incorporated_headword_head_into_lemma = true else -- Try again using the form without links. local linkless_head = m_links.remove_links(head) if linkless_head:find(" ") then refl_clitic_verb, post = rmatch(linkless_head, "^(.-)( .*)$") arg1 = refl_clitic_verb .. arg1 .. post else error("Unable to incorporate <...> spec into explicit head due to a multiword linked verb or " .. "unbalanced brackets; please include <> explicitly: " .. arg1) end end else -- Will be incorporated through `head` below in the call to normalize_all_lemmas(). incorporated_headword_head_into_lemma = true end end local function split_bracketed_runs_into_words(bracketed_runs) return put.split_alternating_runs(bracketed_runs, " ", "preserve splitchar") end local parse_props = { parse_indicator_spec = parse_indicator_spec, -- Split words only on spaces, not on hyphens, because that messes up reflexive verb parsing. split_bracketed_runs_into_words = split_bracketed_runs_into_words, allow_default_indicator = true, allow_blank_lemma = true, } local alternant_multiword_spec = iut.parse_inflected_text(arg1, parse_props) alternant_multiword_spec.pos = pos or "ကြိယာ" alternant_multiword_spec.args = args alternant_multiword_spec.source_template = source_template alternant_multiword_spec.verb_form_of_form = verb_form_of_form alternant_multiword_spec.incorporated_headword_head_into_lemma = incorporated_headword_head_into_lemma normalize_all_lemmas(alternant_multiword_spec, head) detect_all_indicator_specs(alternant_multiword_spec) local inflect_props = { slot_list = alternant_multiword_spec.all_verb_slots, inflect_word_spec = conjugate_verb, -- We add links around the generated verbal forms rather than allow the entire multiword -- expression to be a link, so ensure that user-specified links get included as well. include_user_specified_links = true, } iut.inflect_multiword_or_alternant_multiword_spec(alternant_multiword_spec, inflect_props) -- Remove redundant brackets around entire forms. for slot, forms in pairs(alternant_multiword_spec.forms) do for _, form in ipairs(forms) do form.form = iut.remove_redundant_links(form.form) end end compute_categories_and_annotation(alternant_multiword_spec) if args.json and source_template == "gl-conj" then return require("Module:JSON").toJSON(alternant_multiword_spec.forms) end return alternant_multiword_spec end -- Entry point for {{gl-conj}}. Template-callable function to parse and conjugate a verb given -- user-specified arguments and generate a displayable table of the conjugated forms. function export.show(frame) local parent_args = frame:getParent().args local params = { [1] = {}, ["noautolinktext"] = {type = "boolean"}, ["noautolinkverb"] = {type = "boolean"}, ["pagename"] = {}, -- for testing/documentation pages ["json"] = {type = "boolean"}, -- for bot use } local args = require("Module:parameters").process(parent_args, params) local alternant_multiword_spec = export.do_generate_forms(args, "gl-conj") if type(alternant_multiword_spec) == "string" then -- JSON return value return alternant_multiword_spec end show_forms(alternant_multiword_spec) return make_table(alternant_multiword_spec) .. require("Module:utilities").format_categories(alternant_multiword_spec.categories, lang, nil, nil, force_cat) end return export si4jp0is9895kbp5jtkebc606z76tqh 402292 402287 2026-10-03T08:20:42Z 咽頭べさ 33 402292 Scribunto text/plain --[=[ This module implements {{gl-conj}} and provides the underlying conjugation functions for {{gl-verb}} (whose actual formatting is done in [[Module:gl-headword]]). This module uses the standard norm for Galician spelling. See also [[Module:gl-reinteg-verb]], which implements the reintegrationist norm. Authorship: Ben Wing <benwing2> ]=] local export = {} --[=[ TERMINOLOGY: -- "slot" = A particular combination of tense/mood/person/number/etc. Example slot names for verbs are "pres_1s" (present indicative first-person singular), "pres_sub_2s" (present subjunctive second-person singular) "impf_sub_3p" (imperfect subjunctive third-person plural). Each slot is filled with zero or more forms. -- "form" = The conjugated Galician form representing the value of a given slot. -- "lemma" = The dictionary form of a given Galician term. For Galician, always the infinitive. ]=] --[=[ FIXME: --]=] local lang = require("Module:languages").getByCode("gl") local m_string_utilities = require("Module:string utilities") local m_links = require("Module:links") local m_table = require("Module:table") local iut = require("Module:inflection utilities") local put = require("Module:parse utilities") local com = require("Module:gl-common") local force_cat = false -- set to true for debugging local check_for_red_links = false -- set to false for debugging local rfind = mw.ustring.find local rmatch = mw.ustring.match local rsplit = mw.text.split local rsub = com.rsub local u = mw.ustring.char local unpack = unpack or table.unpack -- Lua 5.2 compatibility local function link_term(term, display) return m_links.full_link({ lang = lang, term = term, alt = display }, "term") end local V = com.V -- vowel regex class local AV = com.AV -- accented vowel regex class local C = com.C -- consonant regex class local TEMPC1 = u(0xFFF1) -- temporary character used for consonant substitutions local short_pp_footnote = "[usually used with auxiliary verbs " .. link_term("ser") .. " and " .. link_term("estar") .. "]" local long_pp_footnote = "[usually used with auxiliary verbs " .. link_term("haber") .. " and " .. link_term("ter") .. "]" --[=[ Vowel alternations: <i-e>: 'i' in pres1s, imp2s and the whole present subjunctive; 'e' elsewhere when stressed. Generally 'e' otherwise when unstressed. E.g. [[sentir]], [[conseguir]] (the latter additionally with 'gu-g' alternation). <u-o>: 'u' in pres1s, imp2s and the whole present subjunctive; 'o' elsewhere when stressed. Generally 'u' otherwise when unstressed. E.g. [[durmir]], [[subir]]. <i>: 'i' whenever stressed (in the present singular and third plural) and throughout the whole present subjunctive. Otherwise 'e'. E.g. [[vestir]], [[pedir]]. <u>: 'u' whenever stressed (in the present singular and third plural) and throughout the whole present subjunctive. Otherwise 'o'. There may be no such verbs in standard Galician. <í>: The last 'i' of the stem) becomes 'í' when stressed. E.g.: * [[faiscar]] (only3sp; faísca, faíscan, faísque, faísquen' also with 'c-qu' alternation), [[acainzar]], [[avaiñar]], [[cainzar]], [[caiñar]], [[desenvaiñar]], [[envaiñar]], [[arremuiñar]], [[arrepuiñar]], [[arruinar]], [[cuincar]], [[cuiñar]], [[muiñar]] * verbs in -eizar and -aizar, e.g. [[europeizar]] ('europeízo, europeíce', etc. also with 'z-c' alternation) * [[desenraizar]], [[enraizar]], [[hebraizar]], [[xudaizar]] * [[europeizar]], [[homoxeneizar]] * some verbs in -uizar: * [[enxuizar]] (enxuízo, enxuíza, enxuíce, enxuícen, also with 'z-c' alternation), [[axuizar]] * but not any in -guizar ([[arreguizar]], [[desgaleguizar]], [[empreguizar]], [[esguizar]], [[espreguizar]], [[galeguizar]]) or -quizar ([[catequizar]], [[esnaquizar]], [[xerarquizar]]) * none in -aiar? * not [[abraiar]], [[achaiar]], [[alfaiar]], [[amaiar]], [[arraiar]], [[atalaiar]], [[desmaiar]], [[encaiar]], [[engraiar]], [[ensaiar]], [[espraiar]], [[faiar]], [[laiar]], [[maiar]], [[raiar]], [[salaiar]] * unknown: [[craiar]] * some verbs in -biar: * [[adobiar]], [[asubiar]], [[espabiar]] * but not [[arrubiar]], [[asoberbiar]] /e/?, [[cambiar]], [[descambiar]], [[enrabiar]], [[ensoberbiar]] /e/?, [[entibiar]], [[gabiar]], [[gobiar]] /ɔ/, [[intercambiar]], [[rabiar]], [[recambiar]], [[sarabiar]] (only3s), [[turbiar]] * none in -ciar: * not [[acariciar]], [[agraciar]], [[anunciar]], [[apreciar]] /e/?, [[asociar]] /ɔ/, [[auspiciar]], [[autofinanciar]], [[aviciar]], [[axenciar]] /ɛ/, [[beneficiar]], [[comerciar]] /ɛ/, [[concienciar]] /ɛ/, [[conferenciar]] /e/?, [[congraciar]], [[denunciar]], [[depreciar]] /e/?, [[desasociar]] /ɔ/, [[desenviciar]], [[desgraciar]], [[desperdiciar]], [[diferenciar]] /e/?, [[dilixenciar]] /e/?, [[disociar]] /ɔ/, [[distanciar]], [[divorciar]] /ɔ/, [[enranciar]], [[ensuciar]], [[enunciar]], [[enviciar]], [[escanciar]], [[especiar]] /?/, [[evidenciar]] /e/?, [[financiar]], [[graciar]], [[influenciar]] /e/?, [[iniciar]], [[licenciar]] /ɛ/, [[maliciar]], [[negociar]] /ɔ/, [[oficiar]], [[potenciar]] /e/?, [[prenunciar]], [[presenciar]] /e/?, [[pronunciar]], [[propiciar]], [[quintaesenciar]] /e/?, [[reiniciar]], [[renunciar]], [[reverenciar]] /e/?, [[saciar]], [[sentenciar]] /e/?, [[silenciar]] /e/?, [[viciar]] * some verbs in -diar: * [[adiar]], [[vadiar]] * but not [[asediar]] /ɛ/, [[compendiar]] /ɛ/, [[custodiar]] /ɔ/, [[deslendiar]] /e/?, [[entremediar]] /e/?, [[estipendiar]] /e/?, [[fastidiar]], [[incendiar]] /e/?, [[insidiar]], [[irradiar]], [[mediar]] /e/?, [[odiar]] /ɔ/, [[parodiar]] /ɔ/, [[preludiar]], [[radiar]], [[remediar]] /ɛ/, [[repudiar]], [[salmodiar]] /ɔ/, [[subsidiar]], [[vilipendiar]] /ɛ/ * some verbs in -fiar: * [[afiar]], [[confiar]], [[desafiar]], [[desconfiar]], [[desenfiar]], [[enfiar]], [[esfiar]], [[esgrafiar]], [[fiar]], [[porfiar]], probably [[sobrefiar]] (not indicated) * but not [[atrofiar]] /ɔ/, [[hipertrofiar]] /ɔ/ * verbs in -guiar: * [[guiar]], [[radioguiar]], [[teleguiar]] * verbs in -hiar: * [[chiar]], [[rechiar]], [[rechouchiar]] * some verbs in -liar: * [[aliar]] (alío, alía, alíe, alíen), [[ampliar]], [[avaliar]], [[desliar]], [[liar]] * but not [[afiliar]] (afilio, afilia, afilie, afilien), [[auxiliar]], [[conciliar]], [[defoliar]], [[domiciliar]], [[escoliar]], [[espoliar]], [[exfoliar]], [[exiliar]], [[interfoliar]], [[reconciliar]] * [[paliar]] goes both ways: 'palio/palío', 'palia/palía', 'palie/palíe', 'palien/palíen' * unknown: [[represaliar]] * some verbs in -miar: * [[gurrumiar]], [[miar]] * but not [[agremiar]], [[amomiar]], [[encomiar]], [[premiar]], [[rumiar]] * some verbs in -niar: * [[agoniar]], [[desagoniar]] * but not [[calumniar]], [[conxeniar]], [[herniar]], [[miniar]] * none in -oiar? * not [[aboiar]] /ɔ/, [[acoiar]] /ɔ/, [[apoiar]] /o/, [[arroiar]] /o/ (only3s), [[choiar]]/[[enchoiar]] /ɔ/, [[enxoiar]] /ɔ/, [[loiar]] /o/ * some verbs in -piar: * [[arrepiar]], [[espiar]], [[expiar]], [[piar]] * but not [[apropiar]], [[copiar]], [[expropiar]], [[fotocopiar]], [[lurpiar]], [[principiar]], [[recopiar]], [[tapiar]], [[xerocopiar]] * some verbs in -quiar: * [[esquiar]], [[maquiar]], [[remaquiar]], [[tosquiar]] * but not [[obsequiar]] * unknown: [[franquiar]] * some verbs in -riar: * [[arrefriar]], [[arriar]], [[avariar]], [[criar]], [[desvariar]], [[enriar]], [[escagarriar]], [[estriar]], [[malcriar]], [[recriar]], [[variar]] * but not [[anguriar]], [[asalariar]], [[cariar]] (only3sp), [[contrariar]], [[desmemoriar]], [[expatriar]], [[gloriar]], [[historiar]], [[inventariar]], [[inxuriar]], [[leriar]], [[repatriar]], [[seriar]], [[vangloriar]] * some verbs in -siar: * [[fantasiar]] * but not [[anestesiar]], [[extasiar]] * [[ansiar]] goes both ways: 'ansio/ansío', 'ansia/ansía', 'ansie/ansíe', 'ansien/ansíen' * some verbs in -tiar: * [[amnistiar]], [[desenfastiar]], [[enfastiar]] * but not [[angustiar]], [[sitiar]] * some verbs in -viar: * [[ataviar]], [[aviar]], [[desataviar]], [[desviar]], [[enviar]], [[extraviar]], [[reenviar]] * but not [[abreviar]], [[agraviar]], [[aliviar]], [[desagraviar]], [[diluviar]] (only3s), [[obviar]] * some verbs in -xiar: * [[vixiar]] * but not [[asfixiar]], [[colexiar]] /e/, [[contaxiar]], [[desprestixiar]], [[eloxiar]], [[plaxiar]], [[presaxiar]], [[prestixiar]], [[privilexiar]] /e/, [[refuxiar]] <ú>: The last 'u' of the stem becomes 'ú' when stressed. E.g.: * [[reunir]] ('reúno, reúne(s), reúnem, reúna(s), reúnan') * [[esmiuzar]] ('esmiúzo, esmiúza(s), esmiúza, esmiúce(s), esmiúcen' also with 'z-c' alternation) * [[saudar]] ('saúdo, saúda(s), saúda, saúde(s), saúden') * [[auñar]], [[desembaular]], [[embaular]] * [[afiuzar]], [[desafiuzar]], [[desmiudar]], [[desmiuzar]], [[enviuvar]], [[esmiuzar]] but not [[triunfar]] * NOTE: It seems most or all verbs in -uar other than in -guar, -quar have stressed ú, so we make it the default. ]=] local vowel_alternants = m_table.listToSet({"i-e", "i", "í", "u-o", "u", "ú", "+"}) local vowel_alternant_to_desc = { ["i-e"] = "''i-e'' alternation in present singular", ["i"] = "''e'' becomes ''i'' when stressed", ["í"] = "''i'' becomes ''í'' when stressed", ["u-o"] = "''u-o'' alternation in present singular", ["u"] = "''o'' becomes ''u'' when stressed", ["ú"] = "''u'' becomes ''ú'' when stressed", } local vowel_alternant_to_cat = { ["i-e"] = "i-e alternation in present singular", ["i"] = "e becoming i when stressed", ["í"] = "i becoming í when stressed", ["u-o"] = "u-o alternation in present singular", ["u"] = "o becoming u when stressed", ["ú"] = "u becoming ú when stressed", } local all_persons_numbers = { ["1s"] = "1|s", ["2s"] = "2|s", ["3s"] = "3|s", ["1p"] = "1|p", ["2p"] = "2|p", ["3p"] = "3|p", } local person_number_list = {"1s", "2s", "3s", "1p", "2p", "3p"} local imp_person_number_list = {"2s", "3s", "1p", "2p", "3p"} local neg_imp_person_number_list = {"2s", "3s", "1p", "2p", "3p"} person_number_to_reflexive_pronoun = { ["1s"] = "me", ["2s"] = "te", ["3s"] = "se", ["1p"] = "nos", ["2p"] = "vos", ["3p"] = "se", } local indicator_flags = m_table.listToSet { "no_pres_stressed", "no_pres1_and_sub", "only3s", "only3sp", "only3p", "noimp", "pp_inv", "irreg", "no_built_in", } -- Initialize all the slots for which we generate forms. local function add_slots(alternant_multiword_spec) -- "Basic" slots: All slots that go into the regular table (not the reflexive form-of table). alternant_multiword_spec.verb_slots_basic = { {"infinitive", "inf"}, {"infinitive_linked", "inf"}, {"gerund", "ger"}, {"short_pp_ms", "short|m|s|past|part"}, {"short_pp_fs", "short|f|s|past|part"}, {"short_pp_mp", "short|m|p|past|part"}, {"short_pp_fp", "short|f|p|past|part"}, {"pp_ms", "m|s|past|part"}, {"pp_fs", "f|s|past|part"}, {"pp_mp", "m|p|past|part"}, {"pp_fp", "f|p|past|part"}, } -- Special slots used to handle non-reflexive parts of reflexive verbs in {{gl-verb form of}}. For example, for a -- reflexive-only verb like [[arrepentirse]], we want to be able to use {{gl-verb form of}} on [[arrepinta]] (which -- should mention that it is a part of 'me arrepinta', first-person singular present subjunctive, and -- 'se arrepinta', third-person singular present subjunctive) or on [[arrepentimos]] (which should mention that it -- is a part of 'arrepentímonos', first-person plural present indicative or preterite). Similarly, we want to use -- {{gl-verb form of}} on [[arrepentindo]] (which should mention that it is a part of 'se ... arrepentindo', -- syntactic variant of [[arrepentíndose]], which is the gerund of [[arrepentirse]]). To do this, we need to be -- able to map non-reflexive parts like [[arrepinta]], [[arrepentimos]], [[arrepentindo]], etc. to their reflexive -- equivalent(s), to the tag(s) of the equivalent(s), and, in the case of forms like [[arrepentindo]], -- [[arrepentir]] and imperatives, to the separated syntactic variant of the verb+clitic combination. We do this by -- creating slots for the non-reflexive part equivalent of each basic reflexive slot, and for the separated -- syntactic-variant equivalent of each basic reflexive slot that is formed of verb+clitic. We use slots in this -- way to deal with multiword lemmas. Note that we run into difficulties mapping between reflexive verbs, -- non-reflexive part equivalents, and separated syntactic variants if a slot contains more than one form. To -- handle this, if there are the same number of forms in two slots we're trying to match up, we assume the forms -- match one-to-one; otherwise we don't match up the two slots (which means {{gl-verb form of}} won't work in this -- case, but such a case is extremely rare and not worth worrying about). Alternatives that handle this "properly" -- are significantly more complicated and require non-trivial modifications to [[Module:inflection utilities]]. local need_special_verb_form_of_slots = alternant_multiword_spec.source_template == "gl-verb form of" and alternant_multiword_spec.refl if need_special_verb_form_of_slots then alternant_multiword_spec.verb_slots_reflexive_verb_form_of = { {"infinitive_non_reflexive", "-"}, {"infinitive_variant", "-"}, {"gerund_non_reflexive", "-"}, {"gerund_variant", "-"}, } else alternant_multiword_spec.verb_slots_reflexive_verb_form_of = {} end -- Add entries for a slot with person/number variants. -- `verb_slots` is the table to add to. -- `slot_prefix` is the prefix of the slot, typically specifying the tense/aspect. -- `tag_suffix` is a string listing the set of inflection tags to add after the person/number tags. -- `person_number_list` is a list of the person/number slot suffixes to add to `slot_prefix`. local function add_personal_slot(verb_slots, slot_prefix, tag_suffix, person_number_list) for _, persnum in ipairs(person_number_list) do local persnum_tag = all_persons_numbers[persnum] local slot = slot_prefix .. "_" .. persnum local accel = persnum_tag .. "|" .. tag_suffix table.insert(verb_slots, {slot, accel}) end end -- Add a personal slot (i.e. a slot with person/number variants) to `verb_slots_basic`. local function add_basic_personal_slot(slot_prefix, tag_suffix, person_number_list, no_special_verb_form_of_slot) add_personal_slot(alternant_multiword_spec.verb_slots_basic, slot_prefix, tag_suffix, person_number_list) -- Add special slots for handling non-reflexive parts of reflexive verbs in {{gl-verb form of}}. -- See comment above in `need_special_verb_form_of_slots`. if need_special_verb_form_of_slots and not no_special_verb_form_of_slot then for _, persnum in ipairs(person_number_list) do local persnum_tag = all_persons_numbers[persnum] local basic_slot = slot_prefix .. "_" .. persnum local accel = persnum_tag .. "|" .. tag_suffix table.insert(alternant_multiword_spec.verb_slots_reflexive_verb_form_of, {basic_slot .. "_non_reflexive", "-"}) end end end add_basic_personal_slot("pres", "pres|ind", person_number_list) add_basic_personal_slot("impf", "impf|ind", person_number_list) add_basic_personal_slot("pret", "pret|ind", person_number_list) add_basic_personal_slot("plup", "plup|ind", person_number_list) add_basic_personal_slot("fut", "fut|ind", person_number_list) add_basic_personal_slot("cond", "cond", person_number_list) add_basic_personal_slot("pres_sub", "pres|sub", person_number_list) add_basic_personal_slot("impf_sub", "impf|sub", person_number_list) add_basic_personal_slot("fut_sub", "fut|sub", person_number_list) add_basic_personal_slot("imp", "imp", imp_person_number_list) add_basic_personal_slot("pers_inf", "pers|inf", person_number_list) -- Don't need special non-reflexive-part slots because the negative imperative is multiword, of which the -- individual words are 'non' + subjunctive. add_basic_personal_slot("neg_imp", "neg|imp", neg_imp_person_number_list, "no special verb form of") -- Don't need special non-reflexive-part slots because we don't want [[arrependendo]] mapping to [[arrependendo-me]] -- (only [[arrependendo-se]]) or [[arrepender]] mapping to [[arrepender-me]] (only [[arrepender-se]]). add_basic_personal_slot("infinitive", "inf", person_number_list, "no special verb form of") add_basic_personal_slot("gerund", "ger", person_number_list, "no special verb form of") -- Generate the list of all slots. alternant_multiword_spec.all_verb_slots = {} for _, slot_and_accel in ipairs(alternant_multiword_spec.verb_slots_basic) do table.insert(alternant_multiword_spec.all_verb_slots, slot_and_accel) end for _, slot_and_accel in ipairs(alternant_multiword_spec.verb_slots_reflexive_verb_form_of) do table.insert(alternant_multiword_spec.all_verb_slots, slot_and_accel) end alternant_multiword_spec.verb_slots_basic_map = {} for _, slotaccel in ipairs(alternant_multiword_spec.verb_slots_basic) do local slot, accel = unpack(slotaccel) alternant_multiword_spec.verb_slots_basic_map[slot] = accel end end local overridable_stems = {} local function allow_multiple_values(separated_groups, data) local retvals = {} for _, separated_group in ipairs(separated_groups) do local footnotes = data.fetch_footnotes(separated_group) local retval = {form = separated_group[1], footnotes = footnotes} table.insert(retvals, retval) end return retvals end local function simple_choice(choices) return function(separated_groups, data) if #separated_groups > 1 then data.parse_err("For spec '" .. data.prefix .. ":', only one value currently allowed") end if #separated_groups[1] > 1 then data.parse_err("For spec '" .. data.prefix .. ":', no footnotes currently allowed") end local choice = separated_groups[1][1] if not m_table.contains(choices, choice) then data.parse_err("For spec '" .. data.prefix .. ":', saw value '" .. choice .. "' but expected one of '" .. table.concat(choices, ",") .. "'") end return choice end end for _, overridable_stem in ipairs { "pres_unstressed", "pres_stressed", "pres1_and_sub", -- Don't include pres1; use pres_1s if you need to override just that form "impf", "full_impf", {"pret_conj", simple_choice({"irreg", "ar", "er", "ir"}) }, "pret_base", "pret", "short_pret", "fut", "cond", "pres_sub_stressed", "pres_sub_unstressed", {"sub_conj", simple_choice({"ar", "er"}) }, "plup", "impf_sub", "fut_sub", "pers_inf", "pp", "short_pp", } do if type(overridable_stem) == "string" then overridable_stems[overridable_stem] = allow_multiple_values else local stem, validator = unpack(overridable_stem) overridable_stems[stem] = validator end end -- Useful as the value of the `match` property of a built-in verb. `main_verb_spec` is a Lua pattern that should match -- the non-prefixed part of a verb, and `prefix_specs` is a list of Lua patterns that should match the prefixed part of -- a verb. If a prefix spec is preceded by ^, it must match exactly at the beginning of the verb; otherwise, additional -- prefixes (e.g. re-, des-) may precede. Return the prefix and main verb. local function match_against_verbs(main_verb_spec, prefix_specs) return function(verb) for _, prefix_spec in ipairs(prefix_specs) do if prefix_spec:find("^%^") then -- must match exactly prefix_spec = prefix_spec:gsub("^%^", "") if prefix_spec == "" then -- We can't use the second branch of the if-else statement because an empty () returns the current position -- in rmatch(). local main_verb = rmatch(verb, "^(" .. main_verb_spec .. ")$") if main_verb then return "", main_verb end else local prefix, main_verb = rmatch(verb, "^(" .. prefix_spec .. ")(" .. main_verb_spec .. ")$") if prefix then return prefix, main_verb end end else local prefix, main_verb = rmatch(verb, "^(.*" .. prefix_spec .. ")(" .. main_verb_spec .. ")$") if prefix then return prefix, main_verb end end end return nil end end --[=[ Built-in (usually irregular) conjugations. Each entry is processed in turn and consists of an object with two fields: 1. match=: Specifies the built-in verbs that match this object. 2. forms=: Specifies the built-in stems and forms for these verbs. The value of match= is either a string beginning with "^" (match only the specified verb), a string not beginning with "^" (match any verb ending in that string), or a function that is passed in the verb and should return the prefix of the verb if it matches, otherwise nil. The function match_against_verbs() is provided to facilitate matching a set of verbs with a common ending and specific prefixes (e.g. [[ter]] and [[ater]] but not [[abater]], etc.). The value of forms= is a table specifying stems and individual override forms. Each key of the table names either a stem (e.g. `pres_stressed`), a stem property (e.g. `vowel_alt`) or an individual override form (e.g. `pres_1s`). Each value of a stem can either be a string (a single stem), a list of strings, or a list of objects of the form {form = STEM, footnotes = {FOONOTES}}. Each value of an individual override should be of exactly the same form except that the strings specify full forms rather than stems. The values of a stem property depend on the specific property but are generally strings or booleans. In order to understand how the stem specifications work, it's important to understand the phonetic modifications done by combine_stem_ending(). In general, the complexities of predictable prefix, stem and ending modifications are all handled in this function. In particular: 1. Spelling-based modifications (c/z, g/gu, gu/gü, g/j) occur automatically as appropriate for the ending. 2. If the stem begins with an acute accent, the accent is moved onto the last vowel of the prefix (for handling verbs in -uar such as [[minguar]], pres_3s 'míngua'). 3. If the ending begins with a double asterisk, this is a signal to conditionally delete the accent on the last letter of the stem. "Conditionally" means we don't do it if the last two letters would form a diphthong without the accent on the second one (e.g. in [[sair]], with stem 'saí'); but as an exception, we do delete the accent in stems ending in -guí, -quí (e.g. in [[conseguir]]) because in this case the ui isn't a diphthong. 4. If the ending begins with an asterisk, this is a signal to delete the accent on the last letter of the stem, e.g. fizé -> fizermos. Unlike for **, this removal is unconditional, so we get e.g. 'sairmos' not #'saírmos'. 5. If ending begins with i, it must get an accent after an unstressed vowel (in some but not all cases) to prevent the two merging into a diphthong. See combine_stem_ending() for specifics. The following stems are recognized: -- pres_unstressed: The present indicative unstressed stem (1p, 2p). Also controls the imperative 2p and gerund. Defaults to the infinitive stem (minus the ending -ar/-er/-ir/-or). -- pres_stressed: The present indicative stressed stem (1s, 2s, 3s, 3p). Also controls the imperative 2s. Default is empty if indicator `no_pres_stressed`, else a vowel alternation if such an indicator is given (e.g. `ue`, `ì`), else the infinitive stem. -- pres1_and_sub: Overriding stem for 1s present indicative and the entire subjunctive. Only set by irregular verbs and by the indicators `no_pres_stressed` (e.g. [[precaver]]) and `no_pres1_and_sub` (since verbs of this sort, e.g. [[puir]], are missing the entire subjunctive as well as the 1s present indicative). Used by many irregular verbs, e.g. [[caber]], verbs in '-air', [[dizer]], [[ter]], [[valer]], etc. Some verbs set this and then supply an override for the pres_1s if it's irregular, e.g. [[saber]], with irregular subjunctive stem "saib-" and special 1s present indicative "sei". -- pres1: Special stem for 1s present indicative. Normally, do not set this explicitly. If you need to specify an irregular 1s present indicative, use the form override pres_1s= to specify the entire form. Defaults to pres1_and_sub if given, else pres_stressed. -- pres_sub_unstressed: The present subjunctive unstressed stem (1p, 2p). Defaults to pres1_and_sub if given, else the infinitive stem. -- pres_sub_stressed: The present subjunctive stressed stem (1s, 2s, 3s, 1p). Defaults to pres1. -- sub_conj: Determines the set of endings used in the subjunctive. Should be one of "ar" or "er". -- impf: The imperfect stem (not including the -av-/-i- stem suffix, which is determined by the conjugation). Defaults to the infinitive stem. -- full_impf: The full imperfect stem missing only the endings (-a, -as, -am, etc.). Used for verbs with irregular imperfects such as [[ser]], [[ter]], [[vir]] and [[pór]]. -- pret_conj: Determines the set of endings used in the preterite. Should be one of "ar", "er", "ir" or "irreg". Defaults to the conjugation as determined from the infinitive. When pret_conj == "irreg", `pret` is used, otherwise `pret_base`. -- pret_base: The preterite stem (not including the -a-/-e-/-i- stem suffix). Defaults to the infinitive stem. Only used when pret_conj ~= "irreg". -- pret: The full preterite stem missing only the endings (-ste, -mos, etc.), e.g. 'fige', 'fo'. Only used for verbs with irregular preterites (pret_conj == "irreg") such as [[facer]], [[poder]], [[traer]], etc. The pret_1s and pret_3s are handled using the short_pret stem instead (pret_1s '-en', pret_3s '-o'). Defaults to `pret_base` + the conjugation vowel. -- short_pret: The short preterite stem, used with 1s and 3s endings (pret_1s '-en', pret_3s '-o'). Only used with irregular preterites (pret_conj == "irreg"). Normally derived from pret by deleting the final vowel, and doesn't need to be given explicitly. -- fut: The future stem. Defaults to the infinitive stem + the conjugation vowel. -- cond: The conditional stem. Defaults to `fut`. -- impf_sub: The imperfect subjunctive stem. Defaults to `pret`. -- fut_sub: The future subjunctive stem. Defaults to `pret`. -- plup: The pluperfect stem. Defaults to `pret`. -- pers_inf: The personal infinitive stem. Defaults to the infinitive stem + the conjugation vowel. -- pp: The masculine singular past participle. Default is based on the verb conjugation: infinitive stem + '-ado' for -ar verbs, otherwise infinitive stem + '-ido'. -- short_pp: The short masculine singular past participle, for verbs with such a form. No default. -- pp_inv: `true` if the past participle exists only in the masculine singular. ]=] local built_in_conjugations = { -------------------------------------------------------------------------------------------- -- -ar -- -------------------------------------------------------------------------------------------- -- Verbs not needing entries here: -- -- (1) Verbs with short past participles: need to specify the short pp explicitly. -- -- aceitar: use <short_pp:aceite> -- anexar, completar, expressar, expulsar, findar, fritar, ganhar, gastar, limpar, pagar, pasmar, pegar, soltar: -- use <short_pp:anexo> etc. -- assentar: use <short_pp:assente> -- entregar: use <short_pp:entregue> -- enxugar: use <short_pp:enxuto> -- matar: use <short_pp:morto> -- -- (2) Verbs with orthographic consonant alternations: handled automatically. -- -- -car (brincar, buscar, pecar, trancar, etc.): automatically handled in combine_stem_ending() -- -zar (alcanzar, comezar, lazar): automatically handled in combine_stem_ending() -- -gar (apagar, cegar, esmagar, largar, navegar, resmungar, sugar, etc.): automatically handled in combine_stem_ending() -- -guar (iguar, minguar): automatically handled in combine_stem_ending() -- -- (3) Verbs with vowel alternations: need to specify the alternation explicitly unless it always happens, in -- which case it's handled automatically through an entry below. -- -- esmiuzar changing to esmiúzo: use <ú> -- faiscar changing to faísco: use <í> -- -izar changing to -ízo (ajuizar, enraizar, homogeneizar, plebeizar, etc.): use <í> -- reusar changing to reúso: use <ú> -- saudar changing to saúdo: use <ú> -- tuitar/retuitar changing to (re)tuíto: use <í> { -- dar match = "^dar", -- [[desdar]] doesn't seem to exist; [[redar]] is regular and unrelated to [[dar]] forms = { pres_1s = "dou", pres_2s = "dás", pres_3s = "dá", pres_3p = "dán#", pres1_and_sub = "de", -- only for subjunctive as we override pres_1s sub_conj = "er", pret_conj = "irreg", pret = "de", pret_1s = "dei", pret_3s = "deu", -- /dɛw/ irreg = true, } }, { -- estar match = "^estar", -- [[sobestar]] and [[sobrestar]] seem not to exist forms = { pres_1s = "estou", pres_2s = "estás", pres_3s = "está", pres_3p = "están", pres1_and_sub = "este", -- only for subjunctive as we override pres_1s sub_conj = "er", pret_conj = "irreg", pret = "estive", pp_inv = true, -- no [[sobestar]] or [[sobrestar]], which would be transitive irreg = true, } }, { -- verbs in -uar but not -guar match = function(verb) if verb:find("guar$") then return nil else return match_against_verbs("uar", {""})(verb) end end, forms = { vowel_alt = "ú", } }, -------------------------------------------------------------------------------------------- -- -er -- -------------------------------------------------------------------------------------------- -- Verbs not needing entries here: -- -- -cer (verbs in -ecer, vencer, etc.): automatically handled in combine_stem_ending() -- -guer (erguer/soerguer): automatically handled in combine_stem_ending() { -- must be listed before -aer match = "^traer", forms = { -- all occurrences of accented í and ï in endings handled in combine_stem_ending() pres1_and_sub = "trai", pret_conj = "irreg", pret = "trouxe", irreg = true, } }, { -- verbs in -aer (caer, raer, debaer, degraer, esvaer and derivatives of traer, but not traer itself: -- acaer/decaer/recaer, -- abstraer/atraer/contraer/descontraer/detraer/distraer/extraer/maltraer/retraer/retrotraer/subtraer) match = "aer", forms = { -- all occurrences of accented í and ï in endings handled in combine_stem_ending() pres1_and_sub = "ai", irreg = true, } }, { -- caber match = "caber", forms = { pres1_and_sub = "caib", pret_conj = "irreg", pret = "coube", irreg = true, } }, { -- crer, descrer match = "crer", forms = { pres1_and_sub = "cre", pres_2s = "crés#", pres_3s = "cré#", pres_3p = "crén#", -- regular except the lack of accent in base verb pret_1p = "crín#", irreg = true, } }, { -- acender, prender/aprender; not comprender/desprender/reprender, etc. match = match_against_verbs("ender", {"^ac", "^pr", "^apr"}), forms = {short_pp = "eso"}, }, { -- erguer; but not soerguer match = "^erguer", forms = {short_pp = "ergueito"}, }, { -- facer, afacer, contrafacer, desafacer, desfacer, perfacer, rarefacer, refacer, satisfacer, tumefacer match = "facer", forms = { -- use 'fagu' because we're in a front environment; if we use 'fag', we'll get '#faxo' pres1_and_sub = "fagu", pres_2s = "fás#", pres_3s = "fai", pres_3p = "fán#", pret_conj = "irreg", pret = "fixe", pp = "feito", fut = "far", irreg = true, cons_alt = false, -- avoid claiming we have a c-z alternation } }, { match = "^haber", forms = { pres_1s = "hei", pres_2s = "has", pres_3s = {"ha", "hai"}, pres_3p = "han", pres1_and_sub = "hax", -- only for subjunctive as we override pres_1s pret_conj = "irreg", pret = "hoube", noimp = true, irreg = true, } }, { -- ler, reler, trasler; not escoller, expeler, valer, etc. match = match_against_verbs("ler", {"^", "^re", "tras"}), forms = { pres1_and_sub = "le", pres_2s = "lés#", pres_3s = "lé#", pres_3p = "lén#", -- regular except the lack of accent in base verb pret_1p = "lín#", irreg = true, } }, { -- morrer, premorrer match = "morrer", forms = {pp = "morto"}, }, { -- nacer; but not renacer match = "^nacer", forms = {short_pp = "nado"}, }, { -- moer, but not remoer match = "^moer", forms = { -- all occurrences of accented í and ï in endings handled in combine_stem_ending() pres1_and_sub = "moi", short_pp = "mudo", -- the main table says 'mundo' but the page for [[mundo]] says 'mudo' is "máis recomendable" irreg = true, } }, { -- choer/deschoer, doer/condoer, remoer, proer, roer/corroer match = "oer", forms = { -- all occurrences of accented í and ï in endings handled in combine_stem_ending() pres1_and_sub = "oi", irreg = true, } }, { -- coller, toller and derivatives (acoller, desacoller, desencoller, encoller, entrecoller, escoller, recoller; -- destoller, entretoller) match = "oller", forms = {short_pp = "olleito"}, }, { -- poder match = "poder", forms = { pres1_and_sub = "poid", -- only for subjunctive as we override pres_1s pres_1s = "podo", -- /ɔ/ pret_conj = "irreg", pret = "puide", irreg = true, } }, { -- poñer, antepoñer, apoñer/desapoñer, arrepoñer, compoñer/descompoñer/recompoñer, contrapoñer, depoñer, -- dispoñer/indispoñer/predispoñer, empoñer, expoñer/sobreexpoñer/subexpoñer, impoñer/reimpoñer, interpoñer, -- opoñer, pospoñer, propoñer, repoñer, sobrepoñer, superpoñer, supoñer/presupoñer, traspoñer, xustapoñer match = "poñer", forms = { pres_2s = "pós#", pres_3s = "pón#", pret_conj = "irreg", pret = "puxe", pp = "posto", irreg = true, } }, { -- pracer, but not apracer, compracer, descompracer, despracer match = "^pracer", forms = { pret_conj = "irreg", pret = "prougue", irreg = true, } }, -- prover below, just below ver { -- querer match = "querer", forms = { pres1_and_sub = "queir", -- only for subjunctive as we override pres_1s pres_1s = "quero", -- /ɛ/ pret_conj = "irreg", pret = "quixe", irreg = true, } }, { -- romper; but not corromper, interromper, irromper or prorromper match = "^romper", forms = {short_pp = "roto"}, }, { -- saber, ressaber match = "saber", forms = { pres_1s = "sei", pres1_and_sub = "saib", -- only for subjunctive as we override pres_1s pret_conj = "irreg", pret = "soube", irreg = true, } }, { -- absolver, disolver, resolver match = "solver", forms = {short_pp = "solto"}, }, { -- suspender; but not others in -pender match = "suspender", forms = {short_pp = "suspenso"}, }, { match = "^ser", forms = { pres_1s = "son", pres_2s = "es", pres_3s = "é", pres_1p = "somos", pres_2p = "sodes", pres_3p = "son", pres1_and_sub = "sex", -- only for subjunctive as we override pres_1s full_impf = "er", pret_conj = "irreg", pret = "fo", pret_1s = "fun", pret_2s = "fuches", pret_3s = "foi", imp_2s = "sé", imp_2p = "sede", irreg = true, } }, { -- We want to match abster, conter, deter, etc. but not abater, cometer, etc. No way to avoid listing each verb. match = match_against_verbs("ter", {"abs", "^a", "con", "de", "entre", "man", "ob", "^re", "sos", "^"}), forms = { pres_2s = "tés#", pres_3s = "tén#", pres_2p = {"tendes", "tedes"}, pres_3p = "teñen", pres1_and_sub = "teñ", full_impf = "tiñ", pret_conj = "irreg", pret = "tive", irreg = true, } }, -- traer listed above at the beginning of the -er verbs { -- valer, equivaler match = "valer", forms = { pres1_and_sub = "vall", irreg = true, } }, { -- We want to match antever etc. but not absolver, atrever etc. No way to avoid listing each verb. -- NOTE: [[rever]] has two meanings, one with regular conjugation. Use <no_built_in> for this one. match = match_against_verbs("ver", {"entre", "pre", "^re", "^"}), forms = { pres_2s = "vés#", pres_3s = "vé#", pres_3p = "vén#", pres1_and_sub = "vex", pret_conj = "irreg", pret = "vi", pret_1s = "vín#", pret_3s = "viu", pp = "visto", irreg = true, } }, { -- [[prover]] has regular preterite and past participle match = "^prover", forms = { pres_2s = "provés", pres_3s = "prové", pres_3p = "provén", pres1_and_sub = "provex", short_pp = "provisto", irreg = true, } }, { -- [[desprover]] has its own conjugation match = "^desprover", forms = { pres_2s = "desprovés", pres_3s = "desprové", pres_3p = "desprovén", pres1_and_sub = "desprove", short_pp = "desprovisto", irreg = true, } }, { -- volver, avolver/desenvolver/devolver/envolver/revolver match = "volver", forms = {short_pp = "volto"}, }, -------------------------------------------------------------------------------------------- -- -ir -- -------------------------------------------------------------------------------------------- -- Verbs not needing entries here: -- -- subir (NOT rubir), acudir/sacudir (NOT escudir, aludir/eludir), urdir/desurdir, xurdir/rexurdir, -- engulir, pulir, bulir/rebulir, ulir, mulir (NOT escapulir), durmir, sumir/consumir/ensumir (NOT -- asumir/reasumir/presumir/resumir/subsumir), cuspir/chuspir, sufrir, tusir, xunguir/conxunguir/desxunguir, -- munguir, fuxir/muxir/ruxir: use <u-o> -- [NOTE: imp_2s durme, consume/sume] -- sosubir/susubir: use <u-o>? (archaic, not in RAG dictionary) -- abolir: use <no_pres_stressed> -- descolorir: use <no_pres_stressed> -- empedernir: use <no_pres_stressed> -- espir/despir, refletir, adherir, pedir/desapedir/despedir/expedir/impedir/reexpedir, medir/comedir/descomedir, -- aferir/conferir/deferir/diferir/inferir/interferir/preferir/proferir/referir/transferir, -- dixerir/enxerir/suxerir, preterir, competir/repetir, advertir/divertir, vestir/investir/revestir/travestir, -- agredir/transgredir, espelir: use <i> -- mentir/desmentir, sentir/asentir/consentir/disentir/presentir/resentir, ferir (but no derivatives), servir, -- seguir/conseguir/perseguir/proseguir: use <i-e> -- [NOTE: imp_2s minte] -- denegrir: use <i.only3sp> -- prohibir/coibir: regular -- cumprir: use <no_built_in> in the meaning "fulfill" -- reunir: use <ú> -- argüír/redargüír: use <ú>? -- -- -cir alternations (aducir, resarcir): automatically handled in combine_stem_ending() -- -guir alternations (e.g. conseguir, cinguir, xunguir, tinguir): automatically handled in combine_stem_ending() -- -quir alternations (e.g. delinquir): automatically handled in combine_stem_ending() -- -güír alternations (e.g. argüír): automatically handled in combine_stem_ending() { -- saír/sobresaír match = "aír", forms = { pres1_and_sub = "ai", -- all occurrences of accented í and ï in endings handled in combine_stem_ending() irreg = true, } }, { -- abrir/desabrir/reabrir match = "abrir", forms = {pp = "aberto"}, }, { -- aflixir match = "aflixir", -- FIXME: should this be {pp = {"aflicto", "aflixido"}}? forms = {short_pp = "aflicto"}, }, { -- cubrir/descubrir/encubrir/recubrir/redescubrir match = "cubrir", forms = {vowel_alt = "u-o", pp = "coberto"}, }, { -- cumprir (only in the meaning "to be necessary"; otherwise use <no_built_in>) match = "^cumprir", forms = { -- We could create a <u-ó> just for this verb but that seems overkill unless another such verb appears pres_stressed = "cómpr", pres1_and_sub = "cumpr", }, }, { -- dicir, bendicir, contradicir, desdicir, maldicir, predicir -- FIXME: bendicir and maldicir can also be entirely regular. This could be handled like this: -- ((bendicir<>,bendicir<no_built_in>)) match = "dicir", forms = { -- use 'digu' because we're in a front environment; if we use 'dig', we'll get '#dijo' pres1_and_sub = "digu", pres_2s = "dís#", pres_3s = "dí#", pres_3p = "dín#", pret_conj = "irreg", pret = "dixe", pp = function(base, prefix) return (prefix == "" or prefix == "des" or prefix == "pre") and "dito" or {"dito", "dicido"} end, pp = "dito", fut = "dir", irreg = true, cons_alt = false, -- avoid claiming we have a c-z alternation } }, { -- elixir, reelixir match = "elixir", -- FIXME: should this be {pp = {"electo", "elixido"}}? forms = {short_pp = "electo"}, }, { -- frixir/sofrixir, fritir/sofritir match = "fri[xt]ir", forms = {short_pp = "frito"}, }, { -- inserir, reinserir match = "inserir", forms = { vowel_alt = "i", short_pp = "inserto", }, }, { -- ir match = "^ir", forms = { pres_1s = "vou", pres_2s = "vas", pres_3s = "vai", pres_1p = "imos", pres_2p = "ides", pres_3p = "van", pres1_and_sub = "vai", -- only for subjunctive as we override pres_1s pret_conj = "irreg", pret = "fo", pret_1s = "fun", pret_2s = "fuches", pret_3s = "foi", imp_1p = "vamos", irreg = true, } }, { -- oír, desoír, entreoír match = "oír", forms = { -- all occurrences of accented í and ï in endings handled in combine_stem_ending() pres1_and_sub = "oi", -- /ɔ/ irreg = true, } }, { match = "ouvir", forms = { pres1_and_sub = "ouz", irreg = true, } }, { -- parir, malparir match = "parir", forms = { pres1_and_sub = "pair", irreg = true, } }, { -- imprimir/reimprimir/sobreimprimir, but not comprimir/descomprimir, deprimir, oprimir, reprimir, suprimir match = "imprimir", forms = {short_pp = "impreso"} }, { -- rir, sorrir match = match_against_verbs("rir", {"^", "sor"}), forms = { pres_2s = "ris#", pres_3s = "ri#", pres_3p = "rin#", pret_1s = "rin#", -- regular except the lack of accent in base verb pres1_and_sub = "rí", irreg = true, } }, { -- adscribir, circunscribir, describir, escribir/reescribir, inscribir, prescribir, proscribir, sobrescribir, -- subscribir, transcribir match = "scribir", forms = { pp = "scrito", irreg = true, } }, { -- concluír/recluír; not excluír/incluír/ocluír match = match_against_verbs("cluír", {"con", "re"}), forms = { -- all occurrences of accented í and ï in endings handled in combine_stem_ending() vowel_alt = "ú", short_pp = "cluso", } }, { -- posuír; not desposuír match = "^posuír", forms = { -- all occurrences of accented í and ï in endings handled in combine_stem_ending() vowel_alt = "ú", short_pp = "poseso", } }, { -- remaining verbs in -uír (excluír/incluír/ocluír, diluír, -- afluír/confluír/difluír/fluír/efluír/influír/refluír, atuír/desatuír, -- atribuír/contribuír/distribuír/redistribuír/retribuír/substituír, -- constituír/destituír/instituír/prostituír/reconstituír/restituír, -- construír/desobstruír/destruír/instruír/obstruír/reconstruír, derruír, -- desposuír, diminuír, luír/esluír, estatuír, imbuír, inmiscuír, intuír, puír, pruír) match = "[uü]ír", -- this won't match -guir verbs (e.g. [[conseguir]]) or -quir verbs (e.g. [[delinquir]]) forms = { -- all occurrences of accented í and ï in endings handled in combine_stem_ending() vowel_alt = "ú", } }, { -- We want to match advir, convir, devir, etc. but not ouvir, servir, etc. No way to avoid listing each verb. match = match_against_verbs("vir", {"ad", "^a", "con", "contra", "de", "^desa", "inter", "pre", "pro", "sobre", "^"}), forms = { pres_2s = "vés", pres_3s = "vén", pres_2p = {"vindes", "vides"}, pres_3p = "veñen", pres1_and_sub = "veñ", full_impf = "viñ", pret_conj = "irreg", pret = "viñe", pret_1s = "vín#", pret_3s = "veu", pp = {"vindo", "vido"}, -- FIXME! The following is as in the RAG tables but may be a typo and should be vén for [[vir]] like pres_3s imp_2s = "vén#", irreg = true, } }, -------------------------------------------------------------------------------------------- -- misc -- -------------------------------------------------------------------------------------------- { -- pór, antepor, apor/desapor, arrepor, compor/descompor/recompor, contrapor, depor, dispor/indispor/predispor, -- empor, expor/sobreexpor/subexpor, impor/reimpor, interpor, opor, pospor, propor, repor, sobrepor, -- superpor, supor/presupor, traspor, xustapor match = "p[oó]r", forms = { pres_2s = "pós#", pres_3s = "pón#", pres_1p = "pomos", pres_2p = "pondes", pres_3p = "pón#", pres1_and_sub = "poñ", full_impf = "puñ", pret_conj = "irreg", pret = "puxe", fut = "por", pers_inf = "po", pers_inf_1s = function(base, prefix) return prefix == "" and "pór" or "por" end, pers_inf_3s = function(base, prefix) return prefix == "" and "pór" or "por" end, gerund = "pondo", pp = "posto", irreg = true, } }, } local function skip_slot(base, slot, allow_overrides) if not allow_overrides and (base.basic_overrides[slot] or base.refl and base.basic_reflexive_only_overrides[slot]) then -- Skip any slots for which there are overrides. return true end if base.only3s and (slot:find("^pp_f") or slot:find("^pp_mp")) then -- diluviar, atardecer, neviscar; impersonal verbs have only masc sing pp return true end if not slot:find("[123]") then -- Don't skip non-personal slots. return false end if base.nofinite then return true end if (base.noimp or base.only3s or base.only3sp or base.only3p) and (slot:find("^imp_") or slot:find("^neg_imp_")) then return true end if base.only3s and not slot:find("3s") then -- diluviar, atardecer, neviscar return true end if base.only3sp and not slot:find("3[sp]") then -- atañer, concernir return true end if base.only3p and not slot:find("3p") then -- [[caer cuatro gotas]], [[caer chuzos de punta]], [[entrarle los siete males]] return true end return false end -- Apply vowel alternations to stem. local function apply_vowel_alternations(stem, alternations) local alternation_stems = {} local saw_pres1_and_sub = false local saw_pres_stressed = false local saw_imp2s_override = false local origstem = stem -- Treat final -gu, -qu as a consonant, so the previous vowel can alternate (e.g. conseguir -> consigo). -- This means a verb in -guar can't have a u-ú alternation but I don't think there are any verbs like that. stem = rsub(stem, "([gq])u$", "%1" .. TEMPC1) -- Process alternations other than +. for _, altobj in ipairs(alternations) do local alt = altobj.form local pres1_and_sub, pres_stressed, imp2s_override, err if alt == "+" then -- do nothing yet else local before_last_vowel, last_vowel, after_last_vowel = rmatch(stem, "^(.*)(" .. V .. ")(.-)$") if alt == "i-e" then if last_vowel == "e" or last_vowel == "i" then pres1_and_sub = before_last_vowel .. "i" .. after_last_vowel imp2s_override = pres1_and_sub if last_vowel == "i" then pres_stressed = before_last_vowel .. "e" .. after_last_vowel end else err = "should have -e- or -i- as the last vowel" end elseif alt == "i" then if last_vowel == "e" then pres1_and_sub = before_last_vowel .. "i" .. after_last_vowel pres_stressed = pres1_and_sub else err = "should have -e- as the last vowel" end elseif alt == "u-o" then if last_vowel == "o" or last_vowel == "u" then pres1_and_sub = before_last_vowel .. "u" .. after_last_vowel imp2s_override = pres1_and_sub if last_vowel == "u" then pres_stressed = before_last_vowel .. "o" .. after_last_vowel end else err = "should have -o- or -u- as the last vowel" end elseif alt == "u" then if last_vowel == "o" then pres1_and_sub = before_last_vowel .. "u" .. after_last_vowel pres_stressed = pres1_and_sub else err = "should have -o- as the last vowel" end elseif alt == "í" then if last_vowel == "i" then pres_stressed = before_last_vowel .. "í" .. after_last_vowel else err = "should have -i- as the last vowel" end elseif alt == "ú" then if last_vowel == "u" or last_vowel == "ü" then pres_stressed = before_last_vowel .. "ú" .. after_last_vowel else err = "should have -u- or -ü- as the last vowel" end else error("Internal error: Unrecognized vowel alternation '" .. alt .. "'") end end local function unapply_u_mod(val) if val then return {form = val:gsub(TEMPC1, "u"), footnotes = altobj.footnotes}, true else return nil, false end end pres1_and_sub, saw_pres1_and_sub = unapply_u_mod(pres1_and_sub) pres_stressed, saw_pres_stressed = unapply_u_mod(pres_stressed) imp2s_override, saw_imp2s_override = unapply_u_mod(imp2s_override) table.insert(alternation_stems, { altobj = altobj, pres1_and_sub = pres1_and_sub, pres_stressed = pres_stressed, imp2s_override = imp2s_override, err = err }) end -- Now do +. We check to see which stems are used by other alternations and specify those so any footnotes are -- properly attached. for _, alternation_stem in ipairs(alternation_stems) do if alternation_stem.altobj.form == "+" then local stemobj = {form = origstem, footnotes = alternation_stem.altobj.footnotes} alternation_stem.pres1_and_sub = saw_pres1_and_sub and stemobj or nil alternation_stem.pres_stressed = saw_pres_stressed and stemobj or nil alternation_stem.imp2s_override = saw_imp2s_override and stemobj or nil end end return alternation_stems end -- Add the `stem` to the `ending` for the given `slot` and apply any phonetic modifications. -- WARNING: This function is written very carefully; changes to it can easily have unintended consequences. local function combine_stem_ending(base, slot, prefix, stem, ending, dont_include_prefix) -- If the ending begins with an acute accent, it goes after the last vowel, but we don't have to do anything. -- Use the full stem for checking for -gui ending and such, because 'stem' is just 'u' for [[arguir]], -- [[delinquir]]. local full_stem = prefix .. stem -- Include the prefix in the stem unless dont_include_prefix is given (used for the past participle stem). if not dont_include_prefix then stem = full_stem end -- If ending begins with i, it must get an accent after a/o/u to prevent the two merging into a diphthong: -- caer -> caíches, caído; doer -> doíches, doído; concluír -> concluíches, concluído. if ending:find("^i") and stem:find("[aouü]$") and not stem:find("[gq]u$") then -- Special case for impf_1p/impf_2p, where the i is unstressed and changes into ï. FIXME: Maybe we should be -- checking the slot value instead. if ending == "iamos" or ending == "iades" then ending = ending:gsub("^i", "ï") else ending = ending:gsub("^i", "í") end end -- Spelling changes in the stem; it depends on whether the stem given is the pre-front-vowel or -- pre-back-vowel variant, as indicated by `frontback`. We want these front-back spelling changes to happen -- between stem and ending, not between prefix and stem; the prefix may not have the same "front/backness" -- as the stem. local is_front = rfind(ending, "^[eiéíï]") if base.frontback == "front" and not is_front then stem = stem:gsub("c$", "z") -- coñecer -> coñezo, vencer -> venzo, inmiscir -> inmiszo stem = stem:gsub("gu$", "g") -- distinguir -> distingo, conseguir -> consigo stem = stem:gsub("qu$", "c") -- delinquir -> delinco stem = stem:gsub("gü$", "gu") -- argüír -> arguamos elseif base.frontback == "back" and is_front then stem = stem:gsub("gu$", "gü") -- iguar -> igüei stem = stem:gsub("g$", "gu") -- cargar -> carguei, apagar -> apaguei stem = stem:gsub("c$", "qu") -- marcar -> marquei stem = rsub(stem, "z$", "c") -- aderezar -> aderecei end local retval = stem .. ending if retval:find("#$") then -- remove final accent if no prefix retval = retval:gsub("#$", "") if prefix == "" then retval = com.remove_final_accent(retval) end end return retval end local function add3(base, slot, stems, endings, footnotes, allow_overrides) if skip_slot(base, slot, allow_overrides) then return end local function do_combine_stem_ending(stem, ending) return combine_stem_ending(base, slot, base.prefix, stem, ending) end iut.add_forms(base.forms, slot, stems, endings, do_combine_stem_ending, nil, nil, footnotes) end local function insert_form(base, slot, form) if not skip_slot(base, slot) then iut.insert_form(base.forms, slot, form) end end local function insert_forms(base, slot, forms) if not skip_slot(base, slot) then iut.insert_forms(base.forms, slot, forms) end end local function add_single_stem_tense(base, slot_pref, stems, s1, s2, s3, p1, p2, p3) local function addit(slot, ending) add3(base, slot_pref .. "_" .. slot, stems, ending) end addit("1s", s1) addit("2s", s2) addit("3s", s3) addit("1p", p1) addit("2p", p2) addit("3p", p3) end local function construct_stems(base, vowel_alt, imp_only) local stems = {} if imp_only then stems.imp2s_override = -- If no_pres_stressed given, there should be no imp_2s. not base.no_pres_stressed and ( base.stems.imp2s_override or vowel_alt.imp2s_override or nil) or nil base.this_stems = stems return end local function combine(slot, stem, ending) return combine_stem_ending(base, slot, base.prefix, stem, ending, "dont include prefix") end stems.pres_unstressed = base.stems.pres_unstressed or base.inf_stem stems.pres_stressed = -- If no_pres_stressed given, pres_stressed stem should be empty so no forms are generated. base.no_pres_stressed and {} or base.stems.pres_stressed or vowel_alt.pres_stressed or base.inf_stem stems.pres1_and_sub = -- If no_pres_stressed given, the entire subjunctive is missing. base.no_pres_stressed and {} or -- If no_pres1_and_sub given, pres1 and entire subjunctive are missing. base.no_pres1_and_sub and {} or base.stems.pres1_and_sub or vowel_alt.pres1_and_sub or nil stems.pres1 = base.stems.pres1 or stems.pres1_and_sub or stems.pres_stressed stems.impf = base.stems.impf or base.inf_stem stems.full_impf = base.stems.full_impf stems.pret_base = base.stems.pret_base or base.inf_stem stems.pret_conj = base.stems.pret_conj or base.conj stems.pret = base.stems.pret or iut.map_forms(iut.convert_to_general_list_form(stems.pret_base), -- use combine_stem_ending esp. so we get saíra etc. function(form) return combine("pret", form, base.conj_vowel) end) stems.short_pret = base.stems.gl_short_pret or iut.map_forms(iut.convert_to_general_list_form(stems.pret), function(form) return rsub(form, com.V .. "$", "") end) stems.fut = base.stems.fut or base.inf_stem .. base.conj stems.cond = base.stems.cond or stems.fut stems.pres_sub_stressed = base.stems.pres_sub_stressed or stems.pres1 stems.pres_sub_unstressed = base.stems.pres_sub_unstressed or stems.pres1_and_sub or stems.pres_unstressed stems.sub_conj = base.stems.sub_conj or base.conj stems.plup = base.stems.plup or stems.pret -- Needed for plup_1p and plup_2p if there's an accent in the regular pluperfect stem (as for [[saír]]). stems.plup_unstressed = iut.map_forms(iut.convert_to_general_list_form(stems.plup), com.remove_final_accent) stems.impf_sub = base.stems.impf_sub or stems.pret -- Needed for impf_sub_1p and impf_sub_2p. We can't just add an acute accent because there may already be one -- (as for [[saír]]). stems.impf_sub_antepenult_stressed = iut.map_forms(iut.convert_to_general_list_form(stems.impf_sub), com.add_final_accent) stems.fut_sub = base.stems.fut_sub or stems.pret -- use combine_stem_ending esp. so we get saír, saírmos, etc. stems.pers_inf = base.stems.pers_inf or combine("pers_inf", base.inf_stem, base.conj_vowel) -- use combine_stem_ending esp. so we get roído, caído, etc. stems.pp = base.stems.pp or combine("pp_ms", base.inf_stem, base.conj == "ar" and "ado" or "ido") stems.pp_ms = stems.pp local function masc_to_fem(form) if rfind(form, "o$") then return rsub(form, "o$", "a") else return form end end stems.pp_fs = iut.map_forms(iut.convert_to_general_list_form(stems.pp_ms), masc_to_fem) if base.stems.short_pp then stems.short_pp_ms = base.stems.short_pp stems.short_pp_fs = iut.map_forms(iut.convert_to_general_list_form(stems.short_pp_ms), masc_to_fem) end base.this_stems = stems end local function add_present_indic(base) local stems = base.this_stems local function addit(slot, stems, ending) add3(base, "pres_" .. slot, stems, ending) end local s2, s3, p1, p2, p3 if base.conj == "ar" then s2, s3, p1, p2, p3 = "as", "a", "amos", "ades", "an" elseif base.conj == "er" or base.conj == "or" then -- verbs in -por have the present overridden s2, s3, p1, p2, p3 = "es", "e", "emos", "edes", "en" elseif base.conj == "ir" then s2, s3, p1, p2, p3 = "es", "e", "imos", "ides", "en" else error("Internal error: Unrecognized conjugation " .. base.conj) end addit("1s", stems.pres1, "o") addit("2s", stems.pres_stressed, s2) addit("3s", stems.pres_stressed, s3) addit("1p", stems.pres_unstressed, p1) addit("2p", stems.pres_unstressed, p2) addit("3p", stems.pres_stressed, p3) end local function add_present_subj(base) local stems = base.this_stems local function addit(slot, stems, ending) add3(base, "pres_sub_" .. slot, stems, ending) end local s1, s2, s3, p1, p2, p3 if stems.sub_conj == "ar" then s1, s2, s3, p1, p2, p3 = "e", "es", "e", "emos", "edes", "en" else s1, s2, s3, p1, p2, p3 = "a", "as", "a", "amos", "ades", "an" end addit("1s", stems.pres_sub_stressed, s1) addit("2s", stems.pres_sub_stressed, s2) addit("3s", stems.pres_sub_stressed, s3) addit("1p", stems.pres_sub_unstressed, p1) addit("2p", stems.pres_sub_unstressed, p2) addit("3p", stems.pres_sub_stressed, p3) end local function add_finite_non_present(base) local stems = base.this_stems local function add_tense(slot, stem, s1, s2, s3, p1, p2, p3) add_single_stem_tense(base, slot, stem, s1, s2, s3, p1, p2, p3) end if stems.full_impf then add_tense("impf", stems.full_impf, "a", "as", "a", "amos", "ades", "an") elseif base.conj == "ar" then add_tense("impf", stems.impf, "aba", "abas", "aba", "abamos", "abades", "aban") else add_tense("impf", stems.impf, "ía", "ías", "ía", "iamos", "iades", "ían") end if stems.pret_conj == "irreg" then add_tense("pret", stems.short_pret, "en", nil, "o") add_tense("pret", stems.pret, nil, "ches", nil, "mos", "stes", "ron") elseif stems.pret_conj == "ar" then add_tense("pret", stems.pret_base, "ei", "aches", "ou", "amos", "astes", "aron") elseif stems.pret_conj == "er" then add_tense("pret", stems.pret_base, "ín", "iches", "eu", "emos", "estes", "eron") else add_tense("pret", stems.pret_base, "ín", "iches", "iu", "imos", "istes", "iron") end add_tense("plup", stems.plup, "ra", "ras", "ra", nil, nil, "ran") add_tense("plup", stems.plup_unstressed, nil, nil, nil, "ramos", "rades", nil) add_tense("impf_sub", stems.impf_sub, "se", "ses", "se", nil, nil, "sen") add_tense("impf_sub", stems.impf_sub_antepenult_stressed, nil, nil, nil, "semos", "sedes", nil) add_tense("fut_sub", stems.fut_sub, "r", "res", "r", "rmos", "rdes", "ren") add_tense("fut", stems.fut, "ei", "ás", "á", "emos", "edes", "án") add_tense("cond", stems.cond, "ía", "ías", "ía", "iamos", "iades", "ían") -- [[pór]] needs overrides of the pers_inf_1s and pers_inf_3s. add_tense("pers_inf", stems.pers_inf, "r", "res", "r", "rmos", "rdes", "ren") end local function add_non_finite_forms(base) local stems = base.this_stems local function addit(slot, stems, ending, footnotes) add3(base, slot, stems, ending, footnotes) end insert_form(base, "infinitive", {form = base.verb}) -- Also insert "infinitive + reflexive pronoun" combinations if we're handling a reflexive verb. See comment below -- for "gerund + reflexive pronoun" combinations. if base.refl then for _, persnum in ipairs(person_number_list) do insert_form(base, "infinitive_" .. persnum, {form = base.verb}) end end -- verbs in -por have the gerund overridden local ger_ending = base.conj == "ar" and "ando" or base.conj == "er" and "endo" or "indo" addit("gerund", stems.pres_unstressed, ger_ending) -- Also insert "gerund + reflexive pronoun" combinations if we're handling a reflexive verb. We insert exactly the -- same form as for the bare gerund; later on in add_reflexive_or_fixed_clitic_to_forms(), we add the appropriate -- clitic pronouns. It's important not to do this for non-reflexive verbs, because in that case, the clitic -- pronouns won't be added, and {{gl-verb form of}} will wrongly consider all these combinations as possible -- inflections of the bare gerund. Thanks to [[User:JeffDoozan]] for this bug fix. if base.refl then for _, persnum in ipairs(person_number_list) do addit("gerund_" .. persnum, stems.pres_unstressed, ger_ending) end end -- Skip the long/short past participle footnotes if called from {{gl-verb}} so they don't show in the headword. local long_pp_footnotes = stems.short_pp_ms and base.alternant_multiword_spec.source_template ~= "gl-verb" and {long_pp_footnote} or nil addit("pp_ms", stems.pp_ms, "", long_pp_footnotes) if not base.pp_inv then addit("pp_fs", stems.pp_fs, "", long_pp_footnotes) addit("pp_mp", stems.pp_ms, "s", long_pp_footnotes) addit("pp_fp", stems.pp_fs, "s", long_pp_footnotes) end if stems.short_pp_ms then local short_pp_footnotes = stems.short_pp_ms and base.alternant_multiword_spec.source_template ~= "gl-verb" and {short_pp_footnote} or nil addit("short_pp_ms", stems.short_pp_ms, "", short_pp_footnotes) if not base.pp_inv then addit("short_pp_fs", stems.short_pp_fs, "", short_pp_footnotes) addit("short_pp_mp", stems.short_pp_ms, "s", short_pp_footnotes) addit("short_pp_fp", stems.short_pp_fs, "s", short_pp_footnotes) end end end local function add_imperatives(base) for _, vowel_alt in ipairs(base.vowel_alt_stems) do construct_stems(base, vowel_alt, "imp only") local stems = base.this_stems if stems.imp2s_override then add3(base, "imp_2s", stems.imp2s_override, base.conj == "ar" and "a" or "e") else -- Copy pres3s to imperative since they are almost always the same. insert_forms(base, "imp_2s", iut.map_forms(base.forms.pres_3s, function(form) return form end)) end end if not skip_slot(base, "imp_2p") then -- Copy pres2p to imperative 2p minus -s since they are almost always the same. -- But not if there's an override, to avoid possibly throwing an error. insert_forms(base, "imp_2p", iut.map_forms(base.forms.pres_2p, function(form) local form_no_s = rmatch(form, "^(.*)s$") if not form_no_s then error("Can't derive second-person plural imperative from second-person plural present indicative " .. "because form '" .. form .. "' doesn't end in -s") end return form_no_s end)) end -- Copy subjunctives to imperatives, unless there's an override for the given slot (as with the imp_1p of [[ir]]). for _, persnum in ipairs({"3s", "1p", "3p"}) do local from = "pres_sub_" .. persnum local to = "imp_" .. persnum insert_forms(base, to, iut.map_forms(base.forms[from], function(form) return form end)) end end local function process_slot_overrides(base, filter_slot, reflexive_only) local overrides = reflexive_only and base.basic_reflexive_only_overrides or base.basic_overrides for slot, forms in pairs(overrides) do if not filter_slot or filter_slot(slot) then add3(base, slot, forms, "", nil, "allow overrides") end end end -- Prefix `form` with `clitic`, adding fixed text `between` between them. Add links as appropriate unless the user -- requested no links. Check whether form already has brackets (as will be the case if the form has a fixed clitic). local function prefix_clitic_to_form(base, clitic, between, form) if base.alternant_multiword_spec.args.noautolinkverb then return clitic .. between .. form else local clitic_pref = "[[" .. clitic .. "]]" .. between if form:find("%[%[") then return clitic_pref .. form else return clitic_pref .. "[[" .. form .. "]]" end end end -- Add the appropriate clitic pronouns in `clitics` to the forms in `base_slot`. `store_cliticized_form` is a function -- of three arguments (clitic, formobj, cliticized_form) and should store the cliticized form for the specified clitic -- and form object. local function suffix_clitic_to_forms(base, base_slot, clitics, store_cliticized_form) if not base.forms[base_slot] then -- This can happen, e.g. in only3s/only3sp/only3p verbs. return end for _, formobj in ipairs(base.forms[base_slot]) do -- Figure out the correct accenting of the verb when a clitic pronoun is attached to it. We may need to -- add or remove an accent mark: -- (1) No accent mark currently, none needed: infinitive sentar -> sentarse; imperative singular ten -> tente; -- (2) Accent mark currently, still needed: infinitive concluír -> concluírse; -- (3) No accent mark currently, accent needed: imperative singular sinte -> síntete; -- (4) Accent mark currently, not needed: third singular sentirá -> sentirase, imperative singular dá -> date. local syllables = com.syllabify(formobj.form) local sylno = com.stressed_syllable(syllables) table.insert(syllables, "lo") -- arbitrary stand-in local needs_accent = com.accent_needed(syllables, sylno) if needs_accent then syllables[sylno] = com.add_accent_to_syllable(syllables[sylno]) else syllables[sylno] = com.remove_accent_from_syllable(syllables[sylno]) end table.remove(syllables) -- remove added clitic pronoun local reaccented_form = table.concat(syllables) for _, clitic in ipairs(clitics) do local cliticized_form -- Some further special cases. if base_slot:find("_1p$") and clitic == "nos" then -- Final -s disappears: sintamos + nos -> sintámonos cliticized_form = reaccented_form:gsub("s$", "") .. clitic elseif clitic:find("^[oa]s?$") then if reaccented_form:find("[rs]$") then cliticized_form = reaccented_form:gsub("[rs]$", "l") .. clitic elseif reaccented_form:find(V .. "[iu]$") then cliticized_form = reaccented_form .. "n" .. clitic else cliticized_form = reaccented_form .. clitic end else cliticized_form = reaccented_form .. clitic end store_cliticized_form(clitic, formobj, cliticized_form) end end end -- Add a reflexive pronoun or fixed clitic (FIXME: not working), as appropriate to the base forms that were generated. -- `do_joined` means to do only the forms where the pronoun is joined to the end of the form; otherwise, do only the -- forms where it is not joined and precedes the form. local function add_reflexive_or_fixed_clitic_to_forms(base, do_reflexive, do_joined) for _, slotaccel in ipairs(base.alternant_multiword_spec.verb_slots_basic) do local slot, accel = unpack(slotaccel) local clitic if not do_reflexive then clitic = base.clitic elseif slot:find("[123]") then local persnum = slot:match("^.*_(.-)$") clitic = person_number_to_reflexive_pronoun[persnum] else clitic = "se" end if base.forms[slot] then if do_reflexive and slot:find("^pp_") or slot == "infinitive_linked" then -- do nothing with reflexive past participles or with infinitive linked (handled at the end) elseif slot:find("^neg_imp_") then error("Internal error: Should not have forms set for negative imperative at this stage") else local slot_has_suffixed_clitic = not slot:find("_sub") -- Maybe generate non-reflexive parts and separated syntactic variants for use in -- {{gl-verb form of}}. See comment in add_slots() above `need_special_verb_form_of_slots`. -- Check for do_joined so we only run this code once. if do_reflexive and do_joined and base.alternant_multiword_spec.source_template == "gl-verb form of" and -- Skip personal variants of infinitives and gerunds so we don't think [[arrependendo]] is a -- non-reflexive equivalent of [[arrependendo-me]]. not slot:find("infinitive_") and not slot:find("gerund_") then -- Clone the forms because we will be destructively modifying them just below, adding the reflexive -- pronoun. insert_forms(base, slot .. "_non_reflexive", mw.clone(base.forms[slot])) if slot_has_suffixed_clitic then insert_forms(base, slot .. "_variant", iut.map_forms(base.forms[slot], function(form) return prefix_clitic_to_form(base, clitic, " ... ", form) end)) end end if slot_has_suffixed_clitic then if do_joined then suffix_clitic_to_forms(base, slot, {clitic}, function(clitic, formobj, cliticized_form) formobj.form = cliticized_form end ) end elseif not do_joined then -- Add clitic as separate word before all other forms. for _, form in ipairs(base.forms[slot]) do form.form = prefix_clitic_to_form(base, clitic, " ", form.form) end end end end end end local function handle_infinitive_linked(base) -- Compute linked versions of potential lemma slots, for use in {{gl-verb}}. -- We substitute the original lemma (before removing links) for forms that -- are the same as the lemma, if the original lemma has links. for _, slot in ipairs({"infinitive"}) do insert_forms(base, slot .. "_linked", iut.map_forms(base.forms[slot], function(form) if form == base.lemma and rfind(base.linked_lemma, "%[%[") then return base.linked_lemma else return form end end)) end end local function generate_negative_imperatives(base) -- Copy subjunctives to negative imperatives, preceded by "non". for _, persnum in ipairs(neg_imp_person_number_list) do local from = "pres_sub_" .. persnum local to = "neg_imp_" .. persnum insert_forms(base, to, iut.map_forms(base.forms[from], function(form) if base.alternant_multiword_spec.args.noautolinkverb then return "non " .. form elseif form:find("%[%[") then -- already linked, e.g. when reflexive return "[[non]] " .. form else return "[[non]] [[" .. form .. "]]" end end)) end end -- Process specs given by the user using 'addnote[SLOTSPEC][FOOTNOTE][FOOTNOTE][...]'. local function process_addnote_specs(base) for _, spec in ipairs(base.addnote_specs) do for _, slot_spec in ipairs(spec.slot_specs) do slot_spec = "^" .. slot_spec .. "$" for slot, forms in pairs(base.forms) do if rfind(slot, slot_spec) then -- To save on memory, side-effect the existing forms. for _, form in ipairs(forms) do form.footnotes = iut.combine_footnotes(form.footnotes, spec.footnotes) end end end end end end local function add_missing_links_to_forms(base) -- Any forms without links should get them now. Redundant ones will be stripped later. for slot, forms in pairs(base.forms) do for _, form in ipairs(forms) do if not form.form:find("%[%[") then form.form = "[[" .. form.form .. "]]" end end end end local function conjugate_verb(base) for _, vowel_alt in ipairs(base.vowel_alt_stems) do construct_stems(base, vowel_alt) add_present_indic(base) add_present_subj(base) end add_finite_non_present(base) add_non_finite_forms(base) -- do non-reflexive non-imperative slot overrides process_slot_overrides(base, function(slot) return not slot:find("^imp_") and not slot:find("^neg_imp_") end) -- This should happen after process_slot_overrides() in case a derived slot is based on an override -- (as with the imp_3s of [[dar]], [[estar]]). add_imperatives(base) -- do non-reflexive positive imperative slot overrides process_slot_overrides(base, function(slot) return slot:find("^imp_") end) -- We need to add joined reflexives, then joined and non-joined clitics, then non-joined reflexives, so we get -- [[arrepéndete]] but [[non]] [[te]] [[arrependas]]. if base.refl then add_reflexive_or_fixed_clitic_to_forms(base, "do reflexive", "do joined") process_slot_overrides(base, nil, "do reflexive") -- do reflexive-only slot overrides add_reflexive_or_fixed_clitic_to_forms(base, "do reflexive", false) end -- This should happen after add_reflexive_or_fixed_clitic_to_forms() so negative imperatives get the reflexive pronoun -- and clitic in them. generate_negative_imperatives(base) -- do non-reflexive negative imperative slot overrides -- FIXME: What about reflexive negative imperatives? process_slot_overrides(base, function(slot) return slot:find("^neg_imp_") end) -- This should happen before add_missing_links_to_forms() so that the comparison `form == base.lemma` -- in handle_infinitive_linked() works correctly and compares unlinked forms to unlinked forms. handle_infinitive_linked(base) process_addnote_specs(base) if not base.alternant_multiword_spec.args.noautolinkverb then add_missing_links_to_forms(base) end end local function parse_indicator_spec(angle_bracket_spec) -- Store the original angle bracket spec so we can reconstruct the overall conj spec with the lemma(s) in them. local base = { angle_bracket_spec = angle_bracket_spec, user_basic_overrides = {}, user_stems = {}, addnote_specs = {}, } local function parse_err(msg) error(msg .. ": " .. angle_bracket_spec) end local function fetch_footnotes(separated_group) 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 inside = angle_bracket_spec:match("^<(.*)>$") assert(inside) if inside == "" then return base end local segments = put.parse_balanced_segment_run(inside, "[", "]") local dot_separated_groups = put.split_alternating_runs(segments, "%.") for i, dot_separated_group in ipairs(dot_separated_groups) do local first_element = dot_separated_group[1] if first_element == "addnote" then local spec_and_footnotes = fetch_footnotes(dot_separated_group) if #spec_and_footnotes < 2 then parse_err("Spec with 'addnote' should be of the form 'addnote[SLOTSPEC][FOOTNOTE][FOOTNOTE][...]'") end local slot_spec = table.remove(spec_and_footnotes, 1) local slot_spec_inside = rmatch(slot_spec, "^%[(.*)%]$") if not slot_spec_inside then parse_err("Internal error: slot_spec " .. slot_spec .. " should be surrounded with brackets") end local slot_specs = rsplit(slot_spec_inside, ",") -- FIXME: Here, [[Module:it-verb]] called strip_spaces(). Generally we don't do this. Should we? table.insert(base.addnote_specs, {slot_specs = slot_specs, footnotes = spec_and_footnotes}) elseif indicator_flags[first_element] then if #dot_separated_group > 1 then parse_err("No footnotes allowed with '" .. first_element .. "' spec") end if base[first_element] then parse_err("Spec '" .. first_element .. "' specified twice") end base[first_element] = true elseif rfind(first_element, ":") then local colon_separated_groups = put.split_alternating_runs(dot_separated_group, "%s*:%s*") local first_element = colon_separated_groups[1][1] if #colon_separated_groups[1] > 1 then parse_err("Can't attach footnotes directly to '" .. first_element .. "' spec; attach them to the " .. "colon-separated values following the initial colon") end if overridable_stems[first_element] then if base.user_stems[first_element] then parse_err("Overridable stem '" .. first_element .. "' specified twice") end table.remove(colon_separated_groups, 1) base.user_stems[first_element] = overridable_stems[first_element](colon_separated_groups, {prefix = first_element, base = base, parse_err = parse_err, fetch_footnotes = fetch_footnotes}) else -- assume a basic override; we validate further later when the possible slots are available if base.user_basic_overrides[first_element] then parse_err("Basic override '" .. first_element .. "' specified twice") end table.remove(colon_separated_groups, 1) base.user_basic_overrides[first_element] = allow_multiple_values(colon_separated_groups, {prefix = first_element, base = base, parse_err = parse_err, fetch_footnotes = fetch_footnotes}) end else local comma_separated_groups = put.split_alternating_runs(dot_separated_group, "%s*,%s*") for j = 1, #comma_separated_groups do local alt = comma_separated_groups[j][1] if not vowel_alternants[alt] then if #comma_separated_groups == 1 then parse_err("Unrecognized spec or vowel alternant '" .. alt .. "'") else parse_err("Unrecognized vowel alternant '" .. alt .. "'") end end if base.vowel_alt then for _, existing_alt in ipairs(base.vowel_alt) do if existing_alt.form == alt then parse_err("Vowel alternant '" .. alt .. "' specified twice") end end else base.vowel_alt = {} end table.insert(base.vowel_alt, {form = alt, footnotes = fetch_footnotes(comma_separated_groups[j])}) end end end return base end -- Normalize all lemmas, substituting the pagename for blank lemmas and adding links to multiword lemmas. local function normalize_all_lemmas(alternant_multiword_spec, head) -- (1) Add links to all before and after text. Remember the original text so we can reconstruct the verb spec later. if not alternant_multiword_spec.args.noautolinktext then iut.add_links_to_before_and_after_text(alternant_multiword_spec, "remember original") end -- (2) Remove any links from the lemma, but remember the original form -- so we can use it below in the 'lemma_linked' form. iut.map_word_specs(alternant_multiword_spec, function(base) if base.lemma == "" then base.lemma = head end base.user_specified_lemma = base.lemma base.lemma = m_links.remove_links(base.lemma) local refl_verb = base.lemma local verb, refl = rmatch(refl_verb, "^(.-)(se)$") if not verb then verb, refl = refl_verb, nil end base.user_specified_verb = verb base.refl = refl base.verb = base.user_specified_verb local linked_lemma if alternant_multiword_spec.args.noautolinkverb or base.user_specified_lemma:find("%[%[") then linked_lemma = base.user_specified_lemma elseif base.refl then -- Reconstruct the linked lemma with separate links around base verb, reflexive pronoun and clitic. linked_lemma = base.user_specified_verb == base.verb and "[[" .. base.user_specified_verb .. "]]" or "[[" .. base.verb .. "|" .. base.user_specified_verb .. "]]" linked_lemma = linked_lemma .. (refl and "[[" .. refl .. "]]" or "") else -- Add links to the lemma so the user doesn't specifically need to, since we preserve -- links in multiword lemmas and include links in non-lemma forms rather than allowing -- the entire form to be a link. linked_lemma = iut.add_links(base.user_specified_lemma) end base.linked_lemma = linked_lemma end) end local function detect_indicator_spec(base) if (base.only3s and 1 or 0) + (base.only3sp and 1 or 0) + (base.only3p and 1 or 0) > 1 then error("Only one of 'only3s', 'only3sp' and 'only3p' can be specified") end base.forms = {} base.stems = {} base.basic_overrides = {} base.basic_reflexive_only_overrides = {} if not base.no_built_in then for _, built_in_conj in ipairs(built_in_conjugations) do if type(built_in_conj.match) == "function" then base.prefix, base.non_prefixed_verb = built_in_conj.match(base.verb) elseif built_in_conj.match:find("^%^") and rsub(built_in_conj.match, "^%^", "") == base.verb then -- begins with ^, for exact match, and matches base.prefix, base.non_prefixed_verb = "", base.verb else base.prefix, base.non_prefixed_verb = rmatch(base.verb, "^(.*)(" .. built_in_conj.match .. ")$") end if base.prefix then -- we found a built-in verb for stem, forms in pairs(built_in_conj.forms) do if type(forms) == "function" then forms = forms(base, base.prefix) end if stem:find("^refl_") then stem = stem:gsub("^refl_", "") if not base.alternant_multiword_spec.verb_slots_basic_map[stem] then error("Internal error: setting for 'refl_" .. stem .. "' does not refer to a basic verb slot") end base.basic_reflexive_only_overrides[stem] = forms elseif base.alternant_multiword_spec.verb_slots_basic_map[stem] then -- an individual form override of a basic form base.basic_overrides[stem] = forms else base.stems[stem] = forms end end break end end end -- Override built-in-verb stems and overrides with user-specified ones. for stem, values in pairs(base.user_stems) do base.stems[stem] = values end for override, values in pairs(base.user_basic_overrides) do if not base.alternant_multiword_spec.verb_slots_basic_map[override] then error("Unrecognized override '" .. override .. "': " .. base.angle_bracket_spec) end base.basic_overrides[override] = values end base.prefix = base.prefix or "" base.non_prefixed_verb = base.non_prefixed_verb or base.verb local inf_stem, suffix = rmatch(base.non_prefixed_verb, "^(.*)([aeiíoó]r)$") if not inf_stem then error("Unrecognized infinitive: " .. base.verb) end base.inf_stem = inf_stem suffix = suffix == "ór" and "or" or suffix == "ír" and "ir" or suffix base.conj = suffix base.conj_vowel = suffix == "ar" and "a" or suffix == "ir" and "i" or "e" base.frontback = suffix == "ar" and "back" or "front" if base.stems.vowel_alt then -- built-in verb with specified vowel alternation if base.vowel_alt then error(base.verb .. " is a recognized built-in verb, and should not have vowel alternations specified with it") end base.vowel_alt = iut.convert_to_general_list_form(base.stems.vowel_alt) end -- Propagate built-in-verb indicator flags to `base` and combine with user-specified flags. for indicator_flag, _ in pairs(indicator_flags) do base[indicator_flag] = base[indicator_flag] or base.stems[indicator_flag] end -- Convert vowel alternation indicators into stems. local vowel_alt = base.vowel_alt or {{form = "+"}} base.vowel_alt_stems = apply_vowel_alternations(base.inf_stem, vowel_alt) for _, vowel_alt_stems in ipairs(base.vowel_alt_stems) do if vowel_alt_stems.err then error("To use '" .. vowel_alt_stems.altobj.form .. "', present stem '" .. base.prefix .. base.inf_stem .. "' " .. vowel_alt_stems.err) end end end local function detect_all_indicator_specs(alternant_multiword_spec) -- Propagate some settings up; some are used internally, others by [[Module:gl-headword]]. iut.map_word_specs(alternant_multiword_spec, function(base) -- Internal indicator flags. Do these before calling detect_indicator_spec() because add_slots() uses them. for _, prop in ipairs { "refl", "clitic" } do if base[prop] then alternant_multiword_spec[prop] = true end end base.alternant_multiword_spec = alternant_multiword_spec end) add_slots(alternant_multiword_spec) alternant_multiword_spec.vowel_alt = {} iut.map_word_specs(alternant_multiword_spec, function(base) detect_indicator_spec(base) -- User-specified indicator flags. Do these after calling detect_indicator_spec() because the latter may set these -- indicators for built-in verbs. for prop, _ in pairs(indicator_flags) do if base[prop] then alternant_multiword_spec[prop] = true end end -- Vowel alternants. Do these after calling detect_indicator_spec() because the latter sets base.vowel_alt for -- built-in verbs. if base.vowel_alt then for _, altobj in ipairs(base.vowel_alt) do m_table.insertIfNot(alternant_multiword_spec.vowel_alt, altobj.form) end end end) end local function add_categories_and_annotation(alternant_multiword_spec, base, multiword_lemma) local function insert_ann(anntype, value) m_table.insertIfNot(alternant_multiword_spec.annotation[anntype], value) end local function insert_cat(cat, also_when_multiword) -- Don't place multiword terms in categories like 'Galician verbs ending in -ar' to avoid spamming the -- categories with such terms. if also_when_multiword or not multiword_lemma then -- m_table.insertIfNot(alternant_multiword_spec.categories, "Galician " .. cat) end end if check_for_red_links and alternant_multiword_spec.source_template == "gl-conj" and multiword_lemma then for _, slot_and_accel in ipairs(alternant_multiword_spec.all_verb_slots) do local slot = slot_and_accel[1] local forms = base.forms[slot] local must_break = false if forms then for _, form in ipairs(forms) do if not form.form:find("%[%[") then local title = mw.title.new(form.form) if title and not title.exists then -- insert_cat("verbs with red links in their inflection tables") must_break = true break end end end end if must_break then break end end end if(base.conj == "or") then -- insert_cat("verbs ending in -er") else -- insert_cat("verbs ending in -" .. base.conj) end if base.irreg then insert_ann("irreg", "irregular") -- insert_cat("irregular verbs") else insert_ann("irreg", "regular") end if base.only3s then insert_ann("defective", "impersonal") -- insert_cat("impersonal verbs") elseif base.only3sp then insert_ann("defective", "third-person only") -- insert_cat("third-person-only verbs") elseif base.only3p then insert_ann("defective", "third-person plural only") -- insert_cat("third-person-plural-only verbs") elseif base.no_pres_stressed or base.no_pres1_and_sub then insert_ann("defective", "defective") -- insert_cat("defective verbs") else insert_ann("defective", "regular") end if base.stems.short_pp then insert_ann("short_pp", "irregular short past participle") -- insert_cat("verbs with irregular short past participle") else insert_ann("short_pp", "regular") end if base.clitic then -- insert_cat("verbs with lexical clitics") end if base.refl then -- insert_cat("reflexive verbs") end if not base.vowel_alt then insert_ann("vowel_alt", "non-alternating") else for _, alt in ipairs(base.vowel_alt) do if alt.form == "+" then insert_ann("vowel_alt", "non-alternating") else insert_ann("vowel_alt", vowel_alternant_to_desc[alt.form]) insert_cat("verbs with " .. vowel_alternant_to_cat[alt.form]) end end end local cons_alt = base.stems.cons_alt if cons_alt == nil then if base.conj == "ar" then if base.inf_stem:find("z$") then cons_alt = "c-z" elseif base.inf_stem:find("c$") then cons_alt = "c-qu" elseif base.inf_stem:find("g$") then cons_alt = "g-gu" elseif base.inf_stem:find("gu$") then cons_alt = "gu-gü" end else if base.no_pres_stressed or base.no_pres1_and_sub then cons_alt = nil -- no e.g. c-z alternation in this case elseif base.inf_stem:find("c$") then cons_alt = "c-z" elseif base.inf_stem:find("qu$") then cons_alt = "c-qu" elseif base.inf_stem:find("gu$") then cons_alt = "g-gu" elseif base.inf_stem:find("gü$") then cons_alt = "gu-gü" end end end if cons_alt then local desc = cons_alt .. " alternation" insert_ann("cons_alt", desc) insert_cat("verbs with " .. desc) else insert_ann("cons_alt", "non-alternating") end end -- Compute the categories to add the verb to, as well as the annotation to display in the -- conjugation title bar. We combine the code to do these functions as both categories and -- title bar contain similar information. local function compute_categories_and_annotation(alternant_multiword_spec) alternant_multiword_spec.categories = {} local ann = {} alternant_multiword_spec.annotation = ann ann.irreg = {} ann.short_pp = {} ann.defective = {} ann.vowel_alt = {} ann.cons_alt = {} local multiword_lemma = false for _, form in ipairs(alternant_multiword_spec.forms.infinitive) do if form.form:find(" ") then multiword_lemma = true break end end iut.map_word_specs(alternant_multiword_spec, function(base) add_categories_and_annotation(alternant_multiword_spec, base, multiword_lemma) end) local ann_parts = {} local irreg = table.concat(ann.irreg, " or ") if irreg ~= "" and irreg ~= "regular" then table.insert(ann_parts, irreg) end local short_pp = table.concat(ann.short_pp, " or ") if short_pp ~= "" and short_pp ~= "regular" then table.insert(ann_parts, short_pp) end local defective = table.concat(ann.defective, " or ") if defective ~= "" and defective ~= "regular" then table.insert(ann_parts, defective) end local vowel_alt = table.concat(ann.vowel_alt, " or ") if vowel_alt ~= "" and vowel_alt ~= "non-alternating" then table.insert(ann_parts, vowel_alt) end local cons_alt = table.concat(ann.cons_alt, " or ") if cons_alt ~= "" and cons_alt ~= "non-alternating" then table.insert(ann_parts, cons_alt) end alternant_multiword_spec.annotation = table.concat(ann_parts, "; ") end local function show_forms(alternant_multiword_spec) local lemmas = alternant_multiword_spec.forms.infinitive alternant_multiword_spec.lemmas = lemmas -- save for later use in make_table() if alternant_multiword_spec.forms.short_pp_ms then alternant_multiword_spec.has_short_pp = true end local reconstructed_verb_spec = iut.reconstruct_original_spec(alternant_multiword_spec) local function transform_accel_obj(slot, formobj, accel_obj) -- No accelerators for negative imperatives, which are always multiword and derived directly from the -- present subjunctive. if slot:find("^neg_imp") then return nil end if accel_obj then if slot:find("^pp_") then accel_obj.form = slot elseif slot == "gerund" then accel_obj.form = "gerund-" .. reconstructed_verb_spec else accel_obj.form = "verb-form-" .. reconstructed_verb_spec end end return accel_obj end local props = { lang = lang, lemmas = lemmas, transform_accel_obj = transform_accel_obj, slot_list = alternant_multiword_spec.verb_slots_basic, } iut.show_forms(alternant_multiword_spec.forms, props) alternant_multiword_spec.footnote_basic = alternant_multiword_spec.forms.footnote end local notes_template = [=[ <div class="roa-footnote-outer-div" style="width:100%;"> <div class="roa-footnote-inner-div"> {footnote} </div></div> ]=] local basic_table = [=[ {description}<div class="NavFrame"> <div class="NavHead" align=center>&nbsp; &nbsp; သမ္ဗန္ဓဆေၚ်စပ်ကဵု {title}</div> <div class="NavContent" align="left"> {\op}| class="roa-inflection-table" data-toggle-category="inflection" |- ! class="roa-person-number-header" rowspan="2" | ! class="roa-person-number-header" colspan="3" | ကိုန်ဨကဝုစ် ! class="roa-person-number-header" colspan="3" | ကိုန်ဗဟုဝစ် |- ! class="roa-person-number-header" style="width:12.5%" | ပူဂဵုပထမ<br />(<<eu>>) ! class="roa-person-number-header" style="width:12.5%" | ပူဂဵုဒုတိယ<br />(<<ti>>) ! class="roa-person-number-header" style="width:12.5%" | ပူဂဵုတတိယ<br />(<<el>> / <<ela>> / <<vostede|Vde.>>) ! class="roa-person-number-header" style="width:12.5%" | ပူဂဵုပထမ<br />(<<nós>>) ! class="roa-person-number-header" style="width:12.5%" | ပူဂဵုတတိယ<br />(<<vós>>) ! class="roa-person-number-header" style="width:12.5%" | ပူဂဵုတတိယ<br />(<<eles>> / <<elas>> / <<vostedes|Vdes.>>) |- ! class="roa-nonfinite-header" colspan="7" | ''<span title="infinitivo">ကြိယာဟွံကၠောံ</span>'' |- ! class="roa-nonfinite-header" | '''<span title="infinitivo impersoal">ဟွံဆေၚ်စပ်ပရေၚ်ပူဂဵု</span>''' | colspan="6" | {infinitive} |- ! class="roa-nonfinite-header" | '''<span title="infinitivo conxugado">ပရေၚ်ပူဂဵု</span>''' | {pers_inf_1s} | {pers_inf_2s} | {pers_inf_3s} | {pers_inf_1p} | {pers_inf_2p} | {pers_inf_3p} |- ! class="roa-nonfinite-header" colspan="7" | ''<span title="xerundio">ကြိယာစၞးနာမ်</span>'' |- | class="roa-nonfinite-header" | | colspan="6" | {gerund} |-{pp_clause} ! class="roa-indicative-left-rail" colspan="7" | ''<span title="indicativo">ပရေၚ်စၞောန်ထ္ၜး</span>'' |- ! class="roa-indicative-left-rail" | <span title="presente">ပစ္စုပ္ပန်</span> | {pres_1s} | {pres_2s} | {pres_3s} | {pres_1p} | {pres_2p} | {pres_3p} |- ! class="roa-indicative-left-rail" | <span title="pretérito imperfecto">ဟွံဍိုက်ပေၚ်</span> | {impf_1s} | {impf_2s} | {impf_3s} | {impf_1p} | {impf_2p} | {impf_3p} |- ! class="roa-indicative-left-rail" | <span title="pretérito perfecto">ကာလအတိက်</span> | {pret_1s} | {pret_2s} | {pret_3s} | {pret_1p} | {pret_2p} | {pret_3p} |- ! class="roa-indicative-left-rail" | <span title="pretérito pluscuamperfecto">ဗီုပြၚ်မဍိုက်ပေၚ်</span> | {plup_1s} | {plup_2s} | {plup_3s} | {plup_1p} | {plup_2p} | {plup_3p} |- ! class="roa-indicative-left-rail" | <span title="futuro do presente">အနာဂတ်</span> | {fut_1s} | {fut_2s} | {fut_3s} | {fut_1p} | {fut_2p} | {fut_3p} |- ! class="roa-indicative-left-rail" | <span title="condicional">တၚ်မကၞာတ်လဝ်စေဝ်ပၞောန်</span> | {cond_1s} | {cond_2s} | {cond_3s} | {cond_1p} | {cond_2p} | {cond_3p} |- ! class="roa-subjunctive-left-rail" colspan="7" | ''<span title="subxuntivo">အရေဝ်နိဒါန်</span>'' |- ! class="roa-subjunctive-left-rail" | <span title=" presente do subxuntivo">ပစ္စုပ္ပန်</span> | {pres_sub_1s} | {pres_sub_2s} | {pres_sub_3s} | {pres_sub_1p} | {pres_sub_2p} | {pres_sub_3p} |- ! class="roa-subjunctive-left-rail" | <span title="pretérito imperfecto do subxuntivo">ဟွံဍိုက်ပေၚ်</span> | {impf_sub_1s} | {impf_sub_2s} | {impf_sub_3s} | {impf_sub_1p} | {impf_sub_2p} | {impf_sub_3p} |- ! class="roa-subjunctive-left-rail" | <span title="futuro do subxuntivo">အနာဂတ်</span> | {fut_sub_1s} | {fut_sub_2s} | {fut_sub_3s} | {fut_sub_1p} | {fut_sub_2p} | {fut_sub_3p} |- ! class="roa-imperative-left-rail" colspan="7" | ''<span title="imperativo">ပါဲဗလေတ်ဟွံဗၠး</span>'' |- ! class="roa-imperative-left-rail" | <span title="imperativo afirmativo">တၚ်ဂလာန်ဗိုန်ဗတ်</span> | rowspan="2" | | {imp_2s} | {imp_3s} | {imp_1p} | {imp_2p} | {imp_3p} |- ! class="roa-imperative-left-rail" | <span title="imperativo negativo">ဗဳဇဂကူ</span> (<<non>>) | {neg_imp_2s} | {neg_imp_3s} | {neg_imp_1p} | {neg_imp_2p} | {neg_imp_3p} |{\cl}{notes_clause}</div></div> ]=] local double_pp_template = [=[ ! class="roa-nonfinite-header" colspan="7" | ''<span title="participio irregular">လုပ်ကၠောန်စွံလဝ်နကဵုအတိက်ဗွဲမဓမၠေံ</span>'' |- ! class="roa-nonfinite-header" | ပုလ္လိၚ် | colspan="3" | {short_pp_ms} | colspan="3" | {short_pp_mp} |- ! class="roa-nonfinite-header" | ဣတ္တိလိၚ် | colspan="3" | {short_pp_fs} | colspan="3" | {short_pp_fp} |- ! class="roa-nonfinite-header" colspan="7" | ''<span title="participio regular">လုပ်ကၠောန်စွံလဝ်နကဵုအတိက်ဗွဲမဂပ်လံ</span>'' |- ! class="roa-nonfinite-header" | ပုလ္လိၚ် | colspan="3" | {pp_ms} | colspan="3" | {pp_mp} |- ! class="roa-nonfinite-header" | ဣတ္တိလိၚ် | colspan="3" | {pp_fs} | colspan="3" | {pp_fp} |-]=] local single_pp_template = [=[ ! class="roa-nonfinite-header" colspan="7" | ''<span title="participio pasado">လုပ်ကၠောန်စွံလဝ်နကဵုအတိက်</span>'' |- ! class="roa-nonfinite-header" | ပုလ္လိၚ် | colspan="3" | {pp_ms} | colspan="3" | {pp_mp} |- ! class="roa-nonfinite-header" | ဣတ္တိလိၚ် | colspan="3" | {pp_fs} | colspan="3" | {pp_fp} |-]=] local function make_table(alternant_multiword_spec) local forms = alternant_multiword_spec.forms forms.title = link_term(alternant_multiword_spec.lemmas[1].form) if alternant_multiword_spec.annotation ~= "" then forms.title = forms.title .. " (" .. alternant_multiword_spec.annotation .. ")" end forms.description = "" -- Format the table. forms.footnote = alternant_multiword_spec.footnote_basic forms.notes_clause = forms.footnote ~= "" and m_string_utilities.format(notes_template, forms) or "" -- has_short_pp is computed in show_forms(). local pp_template = alternant_multiword_spec.has_short_pp and double_pp_template or single_pp_template forms.pp_clause = m_string_utilities.format(pp_template, forms) local table_with_pronouns = rsub(basic_table, "<<([^<>|]-)|([^<>|]-)>>", link_term) local table_with_pronouns = rsub(table_with_pronouns, "<<(.-)>>", link_term) return require("Module:TemplateStyles")("Module:roa-verb/style.css") .. m_string_utilities.format(table_with_pronouns, forms) end -- Externally callable function to parse and conjugate a verb given user-specified arguments. -- Return value is WORD_SPEC, an object where the conjugated forms are in `WORD_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(args, source_template, headword_head) local PAGENAME = mw.loadData("Module:headword/data").pagename local function in_template_space() return mw.title.getCurrentTitle().nsText == "ထာမ်ပလိက်" end -- Determine the verb spec we're being asked to generate the conjugation of. This may be taken from the -- current page title or the value of |pagename=; but not when called from {{gl-verb form of}}, where the -- page title is a non-lemma form. Note that the verb spec may omit the infinitive; e.g. it may be "<i-e>". -- For this reason, we use the value of `pagename` computed here down below, when calling normalize_all_lemmas(). local pagename = source_template ~= "gl-verb form of" and args.pagename or PAGENAME local head = headword_head or pagename local arg1 = args[1] if not arg1 then if (pagename == "gl-conj" or pagename == "gl-verb") and in_template_space() then arg1 = "paliar<í,+>" elseif pagename == "gl-verb form of" and in_template_space() then arg1 = "amar" else arg1 = "<>" end end -- When called from {{gl-verb form of}}, determine the non-lemma form whose inflections we're being asked to -- determine. This normally comes from the page title or the value of |pagename=. local verb_form_of_form if source_template == "gl-verb form of" then verb_form_of_form = args.pagename if not verb_form_of_form then if PAGENAME == "gl-verb form of" and in_template_space() then verb_form_of_form = "ame" else verb_form_of_form = PAGENAME end end end local incorporated_headword_head_into_lemma = false if arg1:find("^<.*>$") then -- missing lemma if head:find(" ") then -- If multiword lemma, try to add arg spec after the first word. -- Try to preserve the brackets in the part after the verb, but don't do it -- if there aren't the same number of left and right brackets in the verb -- (which means the verb was linked as part of a larger expression). local refl_clitic_verb, post = rmatch(head, "^(.-)( .*)$") local left_brackets = rsub(refl_clitic_verb, "[^%[]", "") local right_brackets = rsub(refl_clitic_verb, "[^%]]", "") if #left_brackets == #right_brackets then arg1 = iut.remove_redundant_links(refl_clitic_verb) .. arg1 .. post incorporated_headword_head_into_lemma = true else -- Try again using the form without links. local linkless_head = m_links.remove_links(head) if linkless_head:find(" ") then refl_clitic_verb, post = rmatch(linkless_head, "^(.-)( .*)$") arg1 = refl_clitic_verb .. arg1 .. post else error("Unable to incorporate <...> spec into explicit head due to a multiword linked verb or " .. "unbalanced brackets; please include <> explicitly: " .. arg1) end end else -- Will be incorporated through `head` below in the call to normalize_all_lemmas(). incorporated_headword_head_into_lemma = true end end local function split_bracketed_runs_into_words(bracketed_runs) return put.split_alternating_runs(bracketed_runs, " ", "preserve splitchar") end local parse_props = { parse_indicator_spec = parse_indicator_spec, -- Split words only on spaces, not on hyphens, because that messes up reflexive verb parsing. split_bracketed_runs_into_words = split_bracketed_runs_into_words, allow_default_indicator = true, allow_blank_lemma = true, } local alternant_multiword_spec = iut.parse_inflected_text(arg1, parse_props) alternant_multiword_spec.pos = pos or "ကြိယာ" alternant_multiword_spec.args = args alternant_multiword_spec.source_template = source_template alternant_multiword_spec.verb_form_of_form = verb_form_of_form alternant_multiword_spec.incorporated_headword_head_into_lemma = incorporated_headword_head_into_lemma normalize_all_lemmas(alternant_multiword_spec, head) detect_all_indicator_specs(alternant_multiword_spec) local inflect_props = { slot_list = alternant_multiword_spec.all_verb_slots, inflect_word_spec = conjugate_verb, -- We add links around the generated verbal forms rather than allow the entire multiword -- expression to be a link, so ensure that user-specified links get included as well. include_user_specified_links = true, } iut.inflect_multiword_or_alternant_multiword_spec(alternant_multiword_spec, inflect_props) -- Remove redundant brackets around entire forms. for slot, forms in pairs(alternant_multiword_spec.forms) do for _, form in ipairs(forms) do form.form = iut.remove_redundant_links(form.form) end end compute_categories_and_annotation(alternant_multiword_spec) if args.json and source_template == "gl-conj" then return require("Module:JSON").toJSON(alternant_multiword_spec.forms) end return alternant_multiword_spec end -- Entry point for {{gl-conj}}. Template-callable function to parse and conjugate a verb given -- user-specified arguments and generate a displayable table of the conjugated forms. function export.show(frame) local parent_args = frame:getParent().args local params = { [1] = {}, ["noautolinktext"] = {type = "boolean"}, ["noautolinkverb"] = {type = "boolean"}, ["pagename"] = {}, -- for testing/documentation pages ["json"] = {type = "boolean"}, -- for bot use } local args = require("Module:parameters").process(parent_args, params) local alternant_multiword_spec = export.do_generate_forms(args, "gl-conj") if type(alternant_multiword_spec) == "string" then -- JSON return value return alternant_multiword_spec end show_forms(alternant_multiword_spec) return make_table(alternant_multiword_spec) .. require("Module:utilities").format_categories(alternant_multiword_spec.categories, lang, nil, nil, force_cat) end return export 9iv8w30l8n31jp3aspu7a9nz9t1po5c မဳဒဳယာဝဳကဳ:Sitenotice 8 299406 402286 2026-10-02T15:48:26Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "-<div style="padding:10px;padding-right: 0px;"> <div class="mp-index" style="border: solid #AABBDD 3px; background-color:#E9F3FF; padding:10px;"> <div style="border-bottom: 1px solid #AAAAAA;font-size:150%;padding-bottom:2px"><span style="float:left;margin-top:-20px;margin-left:-20px;"></span>Warning and Prohibition/မဒေံါကဵုသတိ</div> {| border="0" style="padding:0; width:100%; float:center; text-..." 402286 wikitext text/x-wiki -<div style="padding:10px;padding-right: 0px;"> <div class="mp-index" style="border: solid #AABBDD 3px; background-color:#E9F3FF; padding:10px;"> <div style="border-bottom: 1px solid #AAAAAA;font-size:150%;padding-bottom:2px"><span style="float:left;margin-top:-20px;margin-left:-20px;"></span>Warning and Prohibition/မဒေံါကဵုသတိ</div> {| border="0" style="padding:0; width:100%; float:center; text-align:center;margin-bottom:10px;font-size:110%" | style="width:50%" |<span style="color:red;"><big>The security of Mon Wiktionary and to reduce the workload of Mon Wiktionary maintainers (I, [[User talk:咽頭べさ|Dr.Intobesa]]) a Mon language maintainer, have decided that editing/creating pages, editing/creating modules, editing/creating templates using an anonymous IP address whose identity is unknown is not permitted. If you wish to editing/creating pages, editing/creating modules, editing/creating templates, please [[Special:UserLogin|log in]] or [[Special:CreateAccount|create account]]. If you perform such unauthorized actions, your IP address will be permanently blocked from Mon Wiktionary. ဝဳကဳအဘိဓာန်မန်သွက်ဂွံလလံသွာကဵုညးမမၚ်မွဲဝဳကဳအဘိဓာန်မန်သွက်ဂွံက မၠောန်သက်သာသာ်ဂှ်ဟေၚ်ရ၊ ရပ်စပ်ဌာန်ဒၞာဲ IP တုဲ ပ လေဝ်ဒါန်/ခၞံဗဒှ်မုက်လိက်၊ ပ လေဝ်ဒါန်/ခၞံဗဒှ်မဝ်ဂျူ၊ ပ လေဝ်ဒါန်/ခၞံဗဒှ်ထာမ်ပလိက်ဟွံမိက်ကဵုအ ခေါၚ်ညးမရပ်စပ်ဌာန်ဒၞာဲ IP ဟွံတီကၠးညးဂှ်နကဵုညးမမၚ်မွဲဘာသာမန် (အဲနာဲ၊ [[User talk:咽頭べさ|ဒံက်တာအိန်တဝ်ဘာသ]])ဖျေံဗ္ကန်လဝ်ဟေၚ်ရ။ ယဝ်ရနွံပၟိက်မိက်ဂွံအ ခေါၚ်ပ လေဝ်ဒါန်/ခၞံဗဒှ်မုက်လိက်၊ ပ လေဝ်ဒါန်/ခၞံဗဒှ်မဝ်ဂျူ၊ ပ လေဝ်ဒါန်/ခၞံဗဒှ်ထာမ်ပလိက်တှ်ေ၊ သ္ပဂုန်တုဲ [[Special:UserLogin|လုပ်အကံက်]] ဝါ [[Special:CreateAccount|ခၞံဗဒှ်အကံက်]]ညိ။ ယဝ်အရာဟွံကဵုလဝ်အ ခေါၚ်ကၠောန်ပွဏောၚ်တှ်ေဌာန်ဒၞာဲ IP ဒးဒုၚ်တၟာတ်ထောံနူဝဳကဳအဘိဓာန်မန်တဏအ်လၟိုန်ကာလ ဏောၚ်။</big></span> |} </div></div> svcfy4c4d000ar8629xyte4pgawenov ကဏ္ဍ:မဝ်ဂျူပွမပြံၚ်လှာဲဂၠဳသဳယျာန်ဂမၠိုၚ် 14 299407 402288 2026-10-03T07:59:53Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:မဝ်ဂျူဂၠဳသဳယျာန်ဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်ဂၠဳသဳယျာန်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:မဝ်ဂျူဗီုအပြံၚ်အလှာဲဝေါဟာဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ဂ]]" 402288 wikitext text/x-wiki [[ကဏ္ဍ:မဝ်ဂျူဂၠဳသဳယျာန်ဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်ဂၠဳသဳယျာန်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ်]][[ကဏ္ဍ:မဝ်ဂျူဗီုအပြံၚ်အလှာဲဝေါဟာဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ဂ]] 8jpqwn2dbuhpo6dkr1nv3em837efj8o ကဏ္ဍ:ထာမ်ပလိက်ဂၠဳသဳယျာန်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဂမၠိုၚ် 14 299408 402289 2026-10-03T08:01:15Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ထာမ်ပလိက်ဂၠဳသဳယျာန်ဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ဂ]]" 402289 wikitext text/x-wiki [[ကဏ္ဍ:ထာမ်ပလိက်ဂၠဳသဳယျာန်ဂမၠိုၚ်]][[ကဏ္ဍ:ထာမ်ပလိက်အပြံၚ်အလှာဲပ္တဝ်ထ္ၜးပမာဏဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|ဂ]] hqpxpq02dcay63rvcj6wplk84hwiu0f afazer 0 299409 402293 2026-10-03T09:14:46Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ပဝ်တူဂြဳ== ===ဗွဟ်ရမ္သာၚ်=== {{pt-IPA|afazêr}} ===ကြိယာ=== {{pt-verb}} # သကဵုမံၚ်လၟိုန်။ =====သမ္ဗန္ဓ===== {{pt-conj}} ===ဗွဟ်ရမ္သာၚ်=== {{pt-IPA|afazêrh}} * {{hyph|pt|a|fa|zer}} ===နာမ်=== {{pt-noun|m}} # မလှေက်မလှံၚ်၊ တာလျိုၚ်ကမၠောန..." 402293 wikitext text/x-wiki ==ပဝ်တူဂြဳ== ===ဗွဟ်ရမ္သာၚ်=== {{pt-IPA|afazêr}} ===ကြိယာ=== {{pt-verb}} # သကဵုမံၚ်လၟိုန်။ =====သမ္ဗန္ဓ===== {{pt-conj}} ===ဗွဟ်ရမ္သာၚ်=== {{pt-IPA|afazêrh}} * {{hyph|pt|a|fa|zer}} ===နာမ်=== {{pt-noun|m}} # မလှေက်မလှံၚ်၊ တာလျိုၚ်ကမၠောန်။ #: {{syn|pt|encargo|tarefa}} 1tm2812ca50gygx8x5rzc0loffuskly afazeres 0 299410 402294 2026-10-03T09:16:02Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ပဝ်တူဂြဳ== ===ကြိယာ=== {{head|pt|verb form}} # {{pt-verb form of|afazer}} ===နာမ်=== {{head|pt|noun form|g=m}} # {{plural of|pt|afazer}}" 402294 wikitext text/x-wiki ==ပဝ်တူဂြဳ== ===ကြိယာ=== {{head|pt|verb form}} # {{pt-verb form of|afazer}} ===နာမ်=== {{head|pt|noun form|g=m}} # {{plural of|pt|afazer}} sij0g59b8gtpmcy2giqh549avuchfhe afaço 0 299411 402295 2026-10-03T09:16:47Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ပဝ်တူဂြဳ== ===ကြိယာ=== {{head|pt|verb form}} # {{pt-verb form of|afazer}}" 402295 wikitext text/x-wiki ==ပဝ်တူဂြဳ== ===ကြိယာ=== {{head|pt|verb form}} # {{pt-verb form of|afazer}} dto05di4rzfnetzz9wikq5f528uhs32 afiz 0 299412 402296 2026-10-03T09:17:01Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "==ပဝ်တူဂြဳ== ===ကြိယာ=== {{head|pt|verb form}} # {{pt-verb form of|afazer}}" 402296 wikitext text/x-wiki ==ပဝ်တူဂြဳ== ===ကြိယာ=== {{head|pt|verb form}} # {{pt-verb form of|afazer}} dto05di4rzfnetzz9wikq5f528uhs32 afeito 0 299413 402297 2026-10-03T09:27:52Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{also|afeitó}} ==အေက်သတဝ်ရေန်== ===ကြိယာ=== {{head|ast|verb form}} # {{inflection of|ast|afeitar||1|s|pres|indc}} ==ဂၠဳသဳယျာန်== ===နိရုတ်=== ဝေါဟာကၠုၚ်နူ {{inh|gl|roa-opt|afeito}} ===ဗွဟ်ရမ္သာၚ်=== * {{IPA|gl|[aˈfejtʊ]}} ===နာမဝိသေသန=== {{gl-adj}} # မဒှ်ဒၟံၚ်..." 402297 wikitext text/x-wiki {{also|afeitó}} ==အေက်သတဝ်ရေန်== ===ကြိယာ=== {{head|ast|verb form}} # {{inflection of|ast|afeitar||1|s|pres|indc}} ==ဂၠဳသဳယျာန်== ===နိရုတ်=== ဝေါဟာကၠုၚ်နူ {{inh|gl|roa-opt|afeito}} ===ဗွဟ်ရမ္သာၚ်=== * {{IPA|gl|[aˈfejtʊ]}} ===နာမဝိသေသန=== {{gl-adj}} # မဒှ်ဒၟံၚ်ခိုက်အလိုက်၊ ဆေၚ်စပ်ကဵုပရေၚ်မရပ်စပ်။ ===ကြိယာဝိသေသန=== {{gl-adv}} # ပရေၚ်မတုဲဒှ်သ္ဂးဖဵု။ ===ကြိယာ=== {{gl-pp}} # {{past participle of|gl|afacer}} # {{gl-verb form of|afeitar}} ==မဳရာန်ဒါက်== ===ဗွဟ်ရမ္သာၚ်=== {{mwl-pr}} ===နာမဝိသေသန=== {{mwl-adj}} # မဒှ်ဒၟံၚ်ခိုက်အလိုက်၊ ဆေၚ်စပ်ကဵုပရေၚ်မရပ်စပ်။ ===ကြိယာ=== {{head|mwl|verb form}} # {{past participle of|mwl|afazer}} ==ပဝ်တူဂြဳ== ===ဗွဟ်ရမ္သာၚ်=== * {{rhymes|pt|ejtu|s=3}} ===ကြိယာ=== {{pt-pp}} # {{past participle of|pt|afazer}} # {{pt-verb form of|afeitar}} ==သ္ပုၚ်== ===ဗွဟ်ရမ္သာၚ်=== {{es-pr}} ===ကြိယာ=== {{head|es|verb form}} # {{es-verb form of|afeitar}} 7unkliaumke5a4tyf3qtle2upqri74m ထာမ်ပလိက်:mwl-adj 10 299414 402298 2026-10-03T09:31:10Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "<includeonly>{{#invoke:mwl-headword|show|နာမဝိသေသန}}</includeonly><noinclude>{{documentation}}</noinclude>" 402298 wikitext text/x-wiki <includeonly>{{#invoke:mwl-headword|show|နာမဝိသေသန}}</includeonly><noinclude>{{documentation}}</noinclude> chq5obybacidef3whhk52hdm7akuwqo ထာမ်ပလိက်:mwl-adj/documentation 10 299415 402299 2026-10-03T09:32:07Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} Use this template to show the inflection of Mirandese adjectives. The template adds the entry to [[:Category:Mirandese adjectives]]. As with other Wiktionary part of speech templates, '''please do not use <code>subst:</code>'''. {{isAccelerated}} ==Parameters== {| class=wikitable !Parameter !Meaning ! Default value (if left unspecified) ! Notes |- | ''head'' | headword | Page title. | Thi..." 402299 wikitext text/x-wiki {{documentation subpage}} Use this template to show the inflection of Mirandese adjectives. The template adds the entry to [[:Category:Mirandese adjectives]]. As with other Wiktionary part of speech templates, '''please do not use <code>subst:</code>'''. {{isAccelerated}} ==Parameters== {| class=wikitable !Parameter !Meaning ! Default value (if left unspecified) ! Notes |- | ''head'' | headword | Page title. | This is to allow links in the headword for multi-word terms. |- |''f'' | Feminine singular | Uses smart algorithm to generate feminine. | |- |''pl'' | Plural | Uses smart algorithm to generate plural. | Provides a default for ''mpl'' and ''fpl'' (below). |- | ''mpl'' | Masculine plural | Same as ''pl'' parameter if set, or uses smart algorithm to pluralize the headword. | |- | ''fpl'' | Feminine plural | Same as ''pl'' parameter if set, or uses smart algorithm to pluralize the feminine. |- | ''pl2'' | Alternative plural | Not set by default. Used if an adjective has two possible plurals. | |} {{hwcat}} 8e0zd9umjn5960v36nifzhyfyh46llb ကဏ္ဍ:ထာမ်ပလိက်လာၚ်က္ဍိုပ်မအရေဝ်မဳရာန်ဒါက်ဂမၠိုၚ် 14 299416 402300 2026-10-03T09:34:23Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ထာမ်ပလိက်မဳရာန်ဒါက်ဂမၠိုၚ်]][[ကဏ္ဍ:လာၚ်က္ဍိုပ်မအရေဝ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|မ]]" 402300 wikitext text/x-wiki [[ကဏ္ဍ:ထာမ်ပလိက်မဳရာန်ဒါက်ဂမၠိုၚ်]][[ကဏ္ဍ:လာၚ်က္ဍိုပ်မအရေဝ်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|မ]] dxkiv05rzah27omuptpaelc1lv8k6o4 ကဏ္ဍ:ထာမ်ပလိက်မဳရာန်ဒါက်ဂမၠိုၚ် 14 299417 402301 2026-10-03T09:35:28Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[ကဏ္ဍ:ဘာသာမဳရာန်ဒါက်][[ကဏ္ဍ:ထာမ်ပလိက်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|မ]]" 402301 wikitext text/x-wiki [[ကဏ္ဍ:ဘာသာမဳရာန်ဒါက်][[ကဏ္ဍ:ထာမ်ပလိက်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|မ]] dk3wkt2imtp1w9x1ikwey7dg2hs4uxf 402302 402301 2026-10-03T09:38:55Z 咽頭べさ 33 402302 wikitext text/x-wiki [[ကဏ္ဍ:ဘာသာမဳရာန်ဒါက်]][[ကဏ္ဍ:ထာမ်ပလိက်ဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|မ]] iopm22wq3twhi34l0mpi4rowxl7htgb ထာမ်ပလိက်:mwl-pr 10 299418 402303 2026-10-03T09:39:55Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "<includeonly>{{#invoke:mwl-pron|show_pr}}</includeonly><noinclude>{{documentation}}</noinclude>" 402303 wikitext text/x-wiki <includeonly>{{#invoke:mwl-pron|show_pr}}</includeonly><noinclude>{{documentation}}</noinclude> 7i2i6dm3gggf8coxlwt95z8coc3qbs5 ထာမ်ပလိက်:mwl-pr/documentation 10 299419 402304 2026-10-03T09:40:53Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "{{documentation subpage}} {{uses lua|mwl-pron}} This template generates the pronunciation section of a Mirandese term, including rhymes and hyphenation, as well as (if manually specified) audio files and homophones. Note that this template will output a single pronunciation per spelling, so variant pronunciations have to be added manually to the template (see below) and/or in another page whose spelling reflects tha..." 402304 wikitext text/x-wiki {{documentation subpage}} {{uses lua|mwl-pron}} This template generates the pronunciation section of a Mirandese term, including rhymes and hyphenation, as well as (if manually specified) audio files and homophones. Note that this template will output a single pronunciation per spelling, so variant pronunciations have to be added manually to the template (see below) and/or in another page whose spelling reflects that pronunciation. ==Usage== ===Quick reference=== {|class="wikitable" ! Page ! Example ! Comment |- | rowspan=2| {{m|mwl|paçpalhaç}} || <code><nowiki>{{mwl-pr}}</nowiki></code> || Most of the time, no parameters are needed. |- | colspan=2 | {{mwl-pr|pagename=paçpalhaç}} <!--FIXME: any examples of this |- | rowspan=2| {{m|mwl|WORD}} || <code><nowiki>{{mwl-pr|RESPELLING}}</nowiki></code> || If the automatically generated pronunciation is incorrect, use a respelling to indicate the correct pronunciation. |- | colspan=2| {{mwl-pr|esistencia|pagename=existencia}}--> |- | rowspan=2| {{m|mwl|açpuis}} | <code><nowiki>{{mwl-pr|+<audio:LL-Q13330 (mwl)-MdMV or Emdy idk-Açpuis.wav>}}</nowiki></code> | Added an audio pronunciation. No special respelling is needed so we use {{code|+}}. |- | colspan=2 | {{mwl-pr|+<audio:LL-Q13330 (mwl)-MdMV or Emdy idk-Açpuis.wav>|pagename=açpuis}} |} ==Parameters== The allowed parameters are as follows: ; {{para|1}}, {{para|2}}, ... : Specify a line of pronunciation. ; {{para|rhyme}} : Specify one or more comma-separated rhymes that apply to all pronunciations and are displayed below all of them, without additional indentation. : Inline modifiers can be specified with {{code|<rhyme:...>}}. Use this when there are multiple lines of pronunciations, to avoid additional indentation. ; {{para|hyph}} : Specify one or more comma-separated hyphenations that apply to all pronunciations and are displayed below all of them, without additional indentation. : Inline modifiers can be specified with {{code|<hyph:...>}}. Use this when there are multiple lines of pronunciations, to avoid additional indentation. ; {{para|hmp}} : Specify one or more comma-separated homophones that apply to all pronunciations and are displayed below all of them, without additional indentation. : Inline modifiers can be specified with {{code|<hmp:...>}}. Use this when there are multiple lines of pronunciations, to avoid additional indentation. ; {{para|audio}}, {{para|audio2}}, {{para|audio3}}, ... : Specify one or more audio files that apply to all pronunciations and are displayed below all of them, without additional indentation. : Inline modifiers can be specified with {{code|<audio:...>}} (only one audio per modifier). Use this when there are multiple lines of pronunciations, to avoid additional indentation. ; {{para|pagename}} : Explicitly specify the pagename, for testing purposes and for use on documentation pages. {{tcat}} ii307jr6r4antom0evskmhv34lf0gcy မဝ်ဂျူ:mwl-pron 828 299420 402305 2026-10-03T09:43:05Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "--[=[ This module implements the template {{mwl-pr}}. Adapted from [[Module:es-pronunc]] by [[User:Benwing2]] ]=] local export = {} local m_IPA = require("Module:IPA") local m_str_utils = require("Module:string utilities") local m_table = require("Module:table") local audio_module = "Module:audio" local decorations_module = "Module:decorations" local headword_data_module = "Module:headword/data" local homophones_mo..." 402305 Scribunto text/plain --[=[ This module implements the template {{mwl-pr}}. Adapted from [[Module:es-pronunc]] by [[User:Benwing2]] ]=] local export = {} local m_IPA = require("Module:IPA") local m_str_utils = require("Module:string utilities") local m_table = require("Module:table") local audio_module = "Module:audio" local decorations_module = "Module:decorations" local headword_data_module = "Module:headword/data" local homophones_module = "Module:homophones" local hyphenation_module = "Module:hyphenation" local parameters_module = "Module:parameters" local parse_utilities_module = "Module:parse utilities" local rhymes_module = "Module:rhymes" --[=[ About styles, dialects and isoglosses: In this module only two dialects are recognized, each corresponding to an isogloss. The recognized isoglosses/dialects are: -- central -- sendinese A "style" here is a set of dialects (two at most) that pronounce a given word in a given fashion. A "style spec" restricts the output to certain styles (e.g. {{mwl-pr|+<style:sendinese>}} in a Sendinese-only word) ]=] local lang = require("Module:languages").getByCode("mwl") local u = m_str_utils.char local rfind = m_str_utils.find local rsubn = m_str_utils.gsub local rsplit = m_str_utils.split local ulower = m_str_utils.lower local ulen = m_str_utils.len local unfd = mw.ustring.toNFD local unfc = mw.ustring.toNFC local AC = u(0x0301) -- acute = ́ local GR = u(0x0300) -- grave = ̀ local CFLEX = u(0x0302) -- circumflex = ̂ local TILDE = u(0x0303) -- tilde = ̃ local DIA = u(0x0308) -- diaeresis = ̈ local CED = u(0x0327) --cedilla local DENT = u(0x032A) --dental symbol local NONSYL = u(0x032F) --non-syllabic vowel local SYLDIV = u(0xFFF0) -- used to represent a user-specific syllable divider (.) so we won't change it local vowel = "aeiouAEIOUɐãẽĩõũẼÕ" -- vowels local V = "[" .. vowel .. "]" -- vowel class local accent = AC .. GR .. CFLEX local accent_c = "[" .. accent .. "]" local stress = AC .. CFLEX local stress_c = "[" .. AC .. CFLEX .. "]" local ipa_stress = "ˈˌ" local ipa_stress_c = "[" .. ipa_stress .. "]" local sylsep = "%-." .. SYLDIV -- hyphen included for syllabifying from spelling local sylsep_c = "[" .. sylsep .. "]" local wordsep = "# " local separator_not_wordsep = accent .. ipa_stress .. sylsep local separator = separator_not_wordsep .. wordsep local separator_c = "[" .. separator .. "]" local C = "[^" .. vowel .. separator .. "]" -- consonant class local T = "[^" .. vowel .. "lrɾjw" .. separator .. "]" -- obstruent or nasal local unstressed_words = m_table.listToSet({ --FIXME: add more unstressed words "a", "an", "en", "ne", "cun", "de", "des", "pra", "por", "sin", --prepositions "la", "las", --articles "pul", "cul", "nel",--article+preposition contractions "i" }) -- 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 -- apply rsub() repeatedly until no change local function rsub_repeatedly(term, foo, bar) while true do local new_term = rsub(term, foo, bar) if new_term == term then return term end term = new_term end end local function decompose(text) -- decompose everything but ũ, ç and ü text = unfd(text) text = rsub(text, ".[" .. TILDE .. DIA .. CED .. "]", { ["u" .. TILDE] = "ũ", ["U" .. TILDE] = "Ũ", ["u" .. DIA] = "ü", ["U" .. DIA] = "Ü", ["C" .. CED] = "Ç", ["c" .. CED] = "ç" }) return text end local function split_on_comma(term) if not term then return nil end if term:find(",%s") then return require(parse_utilities_module).split_on_comma(term) elseif term:find(",") then return rsplit(term, ",") else return {term} end end local function construct_default_differences(dialect) if dialect == "central" then return false end return nil end -- Main syllable-division algorithm. Can be called either directly on spelling (when hyphenating) or after -- non-trivial processing of respelling in the direction of pronunciation (when generating pronunciation). local function syllabify_from_spelling_or_pronun(text, is_spelling) -- Part 1: Divide before the last consonant in a cluster of consonants between vowels. -- Then move the syllable division marker leftwards over clusters that -- can form onsets. text = rsub_repeatedly(text, "(" .. V .. accent_c .. "*)(" .. C .. V .. ")", "%1.%2") text = rsub_repeatedly(text, "(" .. V .. accent_c .. "*" .. C .. "+)(" .. C .. V .. ")", "%1.%2") -- NOTE: When run on pronun, we have already eliminated c and v, but not when run on spelling. -- When run on pronun, don't include r, which at this point represents the trill. local cluster_r = is_spelling and "rɾ" or "ɾ" -- Don't divide Cl or Cr where C is a stop or fricative, except for dl. --FIXME text = rsub(text, "([pbfvkctgɡ])%.([l" .. cluster_r .. "])", ".%1%2") text = text:gsub("d%.([" .. cluster_r .. "])", ".d%1") -- Part 2: Divide hiatuses. text = rsub_repeatedly(text, "([uU]" .. accent_c .. "*)([eɛEu])", "%1.%2") text = rsub_repeatedly(text, "([iI]" .. accent_c .. "*)([ioɔO])", "%1.%2") text = rsub_repeatedly(text, "(i" .. accent_c .. "*)u", "%1.u") text = rsub(text, "ku%.En%.ta", "kuEn.ta") --but don't divide cin.quen.ta --Fix V.[jw]V -> V[jw].V (note that we're using the symbols <jw> already) text = rsub_repeatedly(text, "(" .. V ..accent_c .. "*)%.([jw])(" .. V .. ")", "%1%2.%3") return text end local function syllabify_from_spelling(text) text = decompose(text) -- start at FFF1 because FFF0 is used for SYLDIV -- Temporary replacements for characters we want treated as default consonants. The C and related consonant regexes -- treat all unknown characters as consonants. local TEMP_I = u(0xFFF1) local TEMP_U = u(0xFFF2) local TEMP_GH = u(0xFFF3) local TEMP_GH_CAPS = u(0xFFF4) local TEMP_NH = u(0x0400) local TEMP_NH_CAPS = u(0x0401) local TEMP_LH = u(0xFFFB) local TEMP_LH_CAPS = u(0xFFFC) local TEMP_QU = u(0xFFF9) local TEMP_QU_CAPS = u(0xFFF5) local TEMP_GU = u(0xFFF6) local TEMP_GU_CAPS = u(0xFFF7) local TEMP_J = u(0xFFF9) local TEMP_J_CAPS = u(0xFFFA) -- Change user-specified . into SYLDIV so we don't shuffle it around when dividing into syllables. text = rsub(text, "gh", TEMP_GH) text = rsub(text, "Gh", TEMP_GH_CAPS) text = rsub(text, "j", TEMP_J) text = rsub(text, "J", TEMP_J_CAPS) text = rsub(text, "nh", TEMP_NH) text = rsub(text, "Nh", TEMP_NH_CAPS) text = rsub(text, "lh", TEMP_LH) text = rsub(text, "Lh", TEMP_LH_CAPS) text = rsub(text, "qu(" .. V .. ")", TEMP_QU .. "%1") text = rsub(text, "Qu(" .. V .. ")", TEMP_QU_CAPS .. "%1") text = rsub(text, "gu(" .. V .. ")", TEMP_GU .. "%1") text = rsub(text, "Gu(" .. V .. ")", TEMP_GU_CAPS .. "%1") text = text:gsub("%.", SYLDIV) local vowel_to_glide = { ["i"] = TEMP_I, ["u"] = TEMP_U } text = rsub_repeatedly(text, "(.*" .. V .. accent_c .. "*)([iu])(" .. V .. ")", function (v1, iu, v2) return v1 .. "." .. vowel_to_glide[iu] .. v2 end ) text = syllabify_from_spelling_or_pronun(text, "is spelling") --restore everything back text = text:gsub(SYLDIV, ".") text = text:gsub("%." .. TEMP_I, TEMP_I .. ".") text = text:gsub("%." .. TEMP_U, TEMP_U .. ".") text = text:gsub(TEMP_I, "i") text = text:gsub(TEMP_J, "j") text = text:gsub(TEMP_J_CAPS, "J") text = text:gsub(TEMP_U, "u") text = text:gsub(TEMP_GH, "gh") text = text:gsub(TEMP_GH_CAPS, "Gh") text = text:gsub(TEMP_NH, "nh") text = text:gsub(TEMP_NH_CAPS, "Nh") text = text:gsub(TEMP_LH, "lh") text = text:gsub(TEMP_LH_CAPS, "Lh") text = text:gsub(TEMP_QU, "qu") text = text:gsub(TEMP_QU_CAPS, "Qu") text = text:gsub(TEMP_GU, "gu") text = text:gsub(TEMP_GU_CAPS, "Gu") text = unfc(text) return text end export.syllabify_from_spelling = syllabify_from_spelling --Used elsewhere, maybe this should be moved to [[Module:mwl-common]]? -- Generate the IPA of a given respelling, where a respelling is the representation of the pronunciation of a given -- Mirandese term using Mirandese spelling conventions. function export.IPA(text, dialect, phonetic) local central = dialect == "central" local sendinese_different = false text = ulower(text or mw.loadData("Module:headword/data").pagename) -- decompose everything but ũ, ç and ü text = decompose(text) -- convert commas and en/en dashes to IPA foot boundaries text = rsub(text, "%s*[,–—]%s*", " | ") -- question mark or exclamation point in the middle of a sentence -> IPA foot boundary text = rsub(text, "([^%s])%s*[¡!¿?]%s*([^%s])", "%1 | %2") -- canonicalize multiple spaces and remove leading and trailing spaces local function canon_spaces(text) text = rsub(text, "%s+", " ") text = rsub(text, "^ ", "") text = rsub(text, " $", "") return text end text = canon_spaces(text) -- Make prefixes unstressed unless they have an explicit stress marker; also make certain -- monosyllabic words unstressed. local words = rsplit(text, " ") for i, word in ipairs(words) do if rfind(word, "%-$") and not rfind(word, accent_c) or unstressed_words[word] then -- add GR to the last vowel not the first one words[i] = rsub(word, "^(.*" .. V .. ")", "%1" .. GR) --words ending in -ie elseif rfind(word, "ie$") and not rfind(word, accent_c) then words[i] = rsub(word, "ie$", "i" .. AC .. "e") end end text = table.concat(words, " ") -- Convert hyphens to spaces, to handle [[Austria-Hungría]], [[franco-italiano]], etc. text = rsub(text, "%-", " ") -- canonicalize multiple spaces again, which may have been introduced by hyphens text = canon_spaces(text) -- now eliminate punctuation text = rsub(text, "[¡!¿?']", "") -- put # at word beginning and end and double ## at text/foot boundary beginning/end text = rsub(text, " | ", "# | #") text = "##" .. rsub(text, " ", "# #") .. "##" -- handling of irregular spellings text = rsub(text, "cinquenta", "cincuenta") --handling of ũ (this is a rare character that appears when nasal u is in a hiatus) text = rsub(text, "ũ", "uñ") --handling of <e> and <o> text = rsub(text, "e" .. CFLEX, "e" .. AC) text = rsub(text, "o" .. CFLEX, "o" .. AC) --c, ç, s, z, ch. Internally we'll use S, Z, ć for s̺, z̺, t͡ʃ text = rsub(text, "s", "S") text = rsub(text, "(" .. V .. ")S(" .. V .. ")", "%1Z%2") text = rsub(text, "SS", "S") text = rsub(text, "ç", "s") text = rsub(text, "c([ie])", "s%1") text = rsub(text, "ch", "ć") --g, q text = rsub(text, "g([ie])", "ʒ%1") text = rsub(text, "gu([ie])", "g%1") text = rsub(text, "gü([ie])", "gu%1") --it's actually /w/, but we will use <u> to keep the syllabification function simpler text = rsub(text, "qu([ie])", "k%1") text = rsub(text, "qua", "kua") --do we need Sendinese? if rfind(text, "uo") or rfind(text, "ie") or rfind(text, "#ye#") then sendinese_different = true end if not central then text = rsub(text, "#ye#", "#yi#") end --digraphs text = rsub(text, "nh", "ɲ") text = rsubb(text, "lh", "ʎ") text = rsub(text, "#p([st])", "#%1") text = rsub(text, "x", "ʃ") text = rsub(text, "gh", "x") --used in some loanwords from Spanish text = rsub(text, "[cjrvy]", { ["c"] = "k", ["j"] = "ʒ", ["r"] = "ɾ", ["v"] = "b", ["y"] = "j"}) --treat the articles l/ls as a special case text = rsub(text, "#l([S]?)#", "#L%1#") -- trill or flap ɾ text = rsub(text, "ɾɾ", "r") text = rsub(text, "#ɾ", "#r") text = rsub(text, "(" .. C .. ")ɾ", "%1r") text = rsub(text, "([bkfgpt])r", "%1ɾ") --other double consonants text = rsub(text, "(" .. C .. ")%1", "%1") --assimilation of sibilants -- θ, s, S before voiced consonants local voiced = "mnɲbdgʎl" local r = "ɾr" local tovoiced = { ["S"] = "Z", ["s"] = "z", ["ʃ"] = "ʒ", } local function voice(sound, following) return tovoiced[sound] .. following end text = rsub(text, "([Ssʃ])(" .. separator_c .. "*[" .. voiced .. r .. "])", voice) -- convert i/u between vowels to glide local vowel_to_glide = { ["i"] = "j", ["u"] = "w" } text = rsub_repeatedly(text, "(.*" .. V .. accent_c .. "*)([iu])(" .. V .. ")", function (v1, iu, v2) return v1 .. vowel_to_glide[iu] .. v2 end ) --syllable division text = syllabify_from_spelling_or_pronun(text, false) --vowel reduction local function sendinese_vowels(syl, stressed) if stressed then if rfind(syl, "[^#aeou][iu]") then return true end else if rfind(syl, "e[mn]") then return true end end return false end local function reduce_vowels(syllables) for i = 1, #syllables do local is_syllable_stressed = rfind(syllables[i], "ˈ") if sendinese_vowels(syllables[i], is_syllable_stressed) then sendinese_different = true end --Changes that apply to all syllables syllables[i] = rsub(syllables[i], "a([mn])", "ɐ%1") --Changes that apply to unstressed syllables if not is_syllable_stressed then syllables[i] = rsub(syllables[i], "ou", "û") syllables[i] = rsub(syllables[i], "o", "u") if phonetic then syllables[i] = rsub(syllables[i], "a", "ɐ") syllables[i] = rsub(syllables[i], "ɐl", "al") --there's no reduction if followed by /l/ in the same syllable syllables[i] = rsub(syllables[i], "ei", "ê") syllables[i] = rsub(syllables[i], "e", "ɨ") syllables[i] = central and rsub(syllables[i], "ɨ([mn])", "ɐ%1") or syllables[i] end syllables[i] = rsub(syllables[i], "û", "ou") syllables[i] = rsub(syllables[i], "ê", "ei") --Changes that apply to stressed syllables else if not central and phonetic then --FIXME: this should probably happen in the phonemic transcription too syllables[i] = rsub(syllables[i], "([^#aeou])([iu])", "%1ɨ%2") end end end end --diphthongs text = rsub(text, "i([ae])", "j%1") text = rsub(text, "u([aeo])", "w%1") --e only in cinquenta -- add accents local accent_to_stress_mark = { [AC] = "ˈ", [GR] = ""} local function accent_word(word, syllables) -- Now stress the word. If any accent exists in the word (including ` indicating an unaccented word), -- put the stress mark(s) at the beginning of the indicated syllable(s). Otherwise, apply the default -- stress rule. if rfind(word, accent_c) then for i = 1, #syllables do syllables[i] = rsub(syllables[i], "^(.*)(" .. accent_c .. ")(.*)$", function(pre, accent, post) return accent_to_stress_mark[accent] .. pre .. post end ) end else -- Default stress rule. Words without vowels (e.g. IPA foot boundaries) don't get stress. -- Final-stressed words ending in -ç, -n, -l, -r, -i, -u, -is, -us don't need an explicit stress marker if #syllables > 1 and (rfind(word, "[snlɾiu]#*$") or rfind(word, "[iu]S#*$")) or #syllables == 1 and rfind(word, V) then syllables[#syllables] = "ˈ" .. syllables[#syllables] elseif #syllables > 1 then syllables[#syllables - 1] = "ˈ" .. syllables[#syllables - 1] end end end local words = rsplit(text, " ") for j, word in ipairs(words) do -- accentuation local syllables = rsplit(word, "%.") if rfind(word, "men%.te#") then local mente_syllables -- Words ends in -mente (converted above to ménti); add a stress to the preceding portion mente_syllables = {} mente_syllables[2] = table.remove(syllables) mente_syllables[1] = table.remove(syllables) accent_word(table.concat(syllables, "."), syllables) accent_word(table.concat(mente_syllables, "."), mente_syllables) table.insert(syllables, mente_syllables[1]) table.insert(syllables, mente_syllables[2]) else if rfind(word, "i" .. AC .. "e#") then local ie = central and "i" .. AC .. ".(e)#" or "je" .. AC .. "#" syllables[#syllables] = rsub(syllables[#syllables], "i" .. AC .. "e#", ie) end accent_word(word, syllables) end reduce_vowels(syllables) -- Reconstruct the word and make all primary stresses but the last one be secondary words[j] = table.concat(syllables, ".") words[j] = rsub_repeatedly(words[j], "ˈ(.+)ˈ", "ˌ%1ˈ") end text = table.concat(words, " ") text = rsub(text, "%-", "") -- suppress syllable mark before IPA stress indicator text = rsub(text, "%.(" .. ipa_stress_c .. ")", "%1") -- apply dialectal variations if not central then text = rsub(text, "je", "i") text = rsub(text, "wo", "u") end --phonetic transcription if phonetic then --definite article text = rsub(text, "L", "(ɐ)l") -- velarization of syllable-final /l/ text = rsub(text, "l([%.#ˈˌ])", "ɫ%1") -- fricative vs. stop allophones; first convert stops to fricatives, then back to stops -- after nasals and sometimes after l local stop_to_fricative = { ["b"] = "β", ["d"] = "ð", ["g"] = "ɣ" } local fricative_to_stop = { ["β"] = "b", ["ð"] = "d", ["ɣ"] = "g" } text = rsub(text, "[bdg]", stop_to_fricative) text = rsub(text, "([mnɲ]" .. separator_c .. "*)([βɣ])", function(nasal, fricative) return nasal .. fricative_to_stop[fricative] end ) text = rsub(text, "([lɫʎmnɲ]" .. separator_c .. "*)([ð])", function(nasal_l, fricative) return nasal_l .. fricative_to_stop[fricative] end ) text = rsub(text, "(##" .. ipa_stress_c .. "*)([βɣð])", function(stress, fricative) return stress .. fricative_to_stop[fricative] end ) text = rsub(text, "[td]", { ["t"] = "t̪", ["d"] = "d̪" }) -- lateral assimilation before consonants text = rsub(text, "([lɫ])(" .. separator_c .. "*[td])", "%1" .. DENT .. "%2") -- voiced fricatives are actually approximants text = rsub(text, "([βðɣ])", "%1̞") -- value of the dipthong <ei> = /ej/ text = rsub(text, "ei", "ɐi") --palatalization of -ingo/a -ico/a in Sendinese if rfind(text, "ɨin%.g[ɐu]#") or rfind(text, "ɨi%.k[ɐu]#") then sendinese_different = true end if not central then text = rsub(text, "ɨin%.g([ɐu])#", "ɨin.gʲ%1#") text = rsub(text, "ɨi%.k([ɐu])#", "ɨi.kʲ%1#") end end --final conversions local final_conversions = { ["h"] = "", ["ć"] = "t͡ʃ", ["g"] = "ɡ", ["s"] = "s̻", ["z"] = "z̻", ["S"] = "s̺", ["Z"] = "z̺", } text = rsub(text, "[hćgszSZ]", final_conversions) --nasalization and semivowels text = rsub(text, "([aɐɨeou])i[mn]", "%1" .. TILDE .. "j" .. TILDE) text = rsub(text, "([aeio])u[mn]", "%1" .. TILDE .. "w" .. TILDE) text = rsub(text, "([ɐaeoɨiu])[mn]", "%1" .. TILDE) text = rsub(text, "([aɐɨeou])i", "%1j") --"%1i" .. NONSYL) if we prefer the non-syllabic vowel notation text = rsub(text, "([aeiɨo])u", "%1w") --"%1w" .. NONSYL) if rfind(text, "o" .. TILDE .. "#") then sendinese_different = true end if phonetic then text = rsub(text, TILDE .. "#", TILDE .. "ŋ#") text = rsub(text, "u%.ñ", "u" .. TILDE .. ".ŋ") if not central then --Sendinese final /õ/ is realized as [ɐ̃w̃] text = rsub(text, "o" .. TILDE .. "ŋ#", "ɐ" .. TILDE .. "w" .. TILDE .. "#") end else text = rsub(text, "L", "(a)l") text = rsub(text, "u%.ñ", "u" .. TILDE .. ".") end text = rsub(text, "#", "") text = unfc(text) -- mark /wo/ and /je/ explicitly (this is for the rhymes) text = rsub(text, "wo", "wO") text = rsub(text, "je", "jE") text = rsub(text, "wõ", "wÕ") text = rsub(text, "jẽ", "jẼ") local ret = { text = text, differences = (dialect == "central") and sendinese_different or nil, } return ret end -- Remove the special characters E and O (+ their nasal counterparts) local function cleanup_pron(text) text = rsub(text, "E", "e") text = rsub(text, "O", "o") text = rsub(text, "Ẽ", "ẽ") text = rsub(text, "Õ", "õ") return text end -- For bot usage; {{#invoke:es-pronunc|IPA_string|SPELLING|style=STYLE|phonetic=PHONETIC}} -- where -- -- 1. SPELLING is the word or respelling to generate pronunciation for; -- 2. required parameter style= indicates the pronunciation style to generate -- (e.g. "distincion-yeismo" for distinción+yeísmo, as is common in Spain; -- see the comment above export.IPA() above for the full list); -- 3. phonetic=1 specifies to generate the phonetic rather than phonemic pronunciation; function export.IPA_string(frame) local iparams = { [1] = {}, ["style"] = {required = true}, ["phonetic"] = {type = "boolean"}, } local iargs = require(parameters_module).process(frame.args, iparams) local retval = export.IPA(iargs[1], iargs.style, iargs.phonetic) return retval.text end -- Generate all relevant dialect pronunciations and group into styles. See the comment above about dialects and styles. -- A "pronunciation" here could be for example the IPA phonemic/phonetic representation of the term or the IPA form of -- the rhyme that the term belongs to. If `style_spec` is nil, this generates all styles for all dialects, but -- `style_spec` can also be a style spec such as "sendinese" or "central" (see comment above) to restrict the -- output. `dodialect` is a function of two arguments, `ret` and `dialect`, where `ret` is the return-value table (see -- below), and `dialect` is a string naming a particular dialect, such as "central" or "sendinese". -- `dodialect` should side-effect the `ret` table by adding an entry to `ret.pronun` for the dialect in question. -- -- The return value is a table of the form -- -- { -- pronun = {DIALECT = {PRONUN, PRONUN, ...}, DIALECT = {PRONUN, PRONUN, ...}, ...}, -- expressed_styles = {STYLE, STYLE, ...}, -- } -- -- where: -- 1. DIALECT is a string such as "central" naming a specific dialect. -- 2. PRONUN is a table describing a particular pronunciation. If the dialect is "central", there should be -- a field in this table named `differences`, but where other fields may vary depending on the type of pronunciation -- (e.g. phonemic/phonetic or rhyme). See below for the form of the PRONUN table for phonemic/phonetic pronunciation -- vs. rhyme and the form of the `differences` field. -- 3. STYLE is a table of the form {tag = "TAG", pronun = {PRONUN, PRONUN, ...}}. The tag of the style group is the text -- displayed before the pronunciation, such as "Central" or "Sendinese". It can have the special value of `false` to indicate -- that no tag text is to be displayed. -- -- The PRONUN table has the following form for the full phonemic/phonetic pronunciation: -- -- { -- phonemic = "PHONEMIC", -- phonetic = "PHONETIC", -- differences = {FLAG = BOOLEAN, FLAG = BOOLEAN, ...}, -- } -- -- Here, `phonemic` is the phonemic pronunciation (displayed as /.../) and `phonetic` is the phonetic pronunciation -- (displayed as [...]). -- -- The PRONUN table has the following form for the rhyme pronunciation: -- -- { -- rhyme = "RHYME_PRONUN", -- num_syl = {NUM, NUM, ...}, -- q = nil or {QUALIFIER, QUALIFIER, ...}, -- differences = {FLAG = BOOLEAN, FLAG = BOOLEAN, ...}, -- } -- -- Here, `rhyme` is a phonemic pronunciation such as "as̻" for [[paçpalhaç]], -- and `num_syl` is a list of the possible numbers of syllables for the term(s) that have this rhyme -- (e.g. {3} for [[paçpalhaç]]. `num_syl` is used to generate syllable-count categories such as -- [[Category:Rhymes:Mirandese/el/3 syllables]] in addition to [[Category:Rhymes:Mirandese/el]]. `num_syl` may be nil to -- suppress the generation of syllable-count categories; this is typically the case with multiword terms. -- `q`, if non-nil, comes from the user using the syntax. -- -- The value of the `differences` field in the PRONUN table (which, as noted above, only needs to be present for the -- "central" dialect, and otherwise should be nil) is a table containing flags indicating whether and how -- the per-dialect pronunciations differ. This is an optimization to avoid having to generate all six dialectal -- pronunciations and compare them. It has the following form: -- local function express_all_styles(style_spec, dodialect) local ret = { pronun = {}, expressed_styles = {}, } -- Add a style object that represents a particular style to `ret.expressed_styles`. -- `tag` is the tag text to be used. -- `dialect_name` is the dialect that this style represents, and whose pronunciation is stored in -- the style object. local function express_style(tag, dialect_name) -- If style specified, make sure it matches the requested style. local style_matches if not style_spec then style_matches = true else if dialect_name == style_spec then style_matches = true end if negate then style_matches = not style_matches end end if not style_matches then return end -- Fetch the representative dialect's pronunciation if not already present. if not ret.pronun[dialect_name] then dodialect(ret, dialect_name) end -- Insert the new style. table.insert(ret.expressed_styles, { tag = tag, pronun = ret.pronun[dialect_name], }) end -- For each type of difference, figure out if the difference exists in any of the given respellings. We do this by -- generating the pronunciation for the dialect "central", for each respelling. In the process of -- generating the pronunciation for a given respelling, it computes how the other dialects for that respelling -- differ. Then we take the union of these differences across the respellings. dodialect(ret, "central") local differences = false for _, pronun in ipairs(ret.pronun["central"]) do if pronun.differences == true then differences = true end end -- Now, based on the observed differences, figure out how to combine the individual dialects into styles and -- style groups. if not differences then express_style(false, "central") else express_style("Central", "central") express_style("Sendinese", "sendinese") end return ret end local function format_all_styles(expressed_styles, format_style) for i, style in ipairs(expressed_styles) do style.formatted = format_style(style.tag, style.pronun, i == 1) end local lines = {} for i, style in ipairs(expressed_styles) do table.insert(lines, style.formatted) end return table.concat(lines, "\n") end local function dodialect_pronun(args, ret, dialect) ret.pronun[dialect] = {} for i, term in ipairs(args.terms) do local phonemic, phonetic, differences if term.raw then phonemic = term.raw_phonemic phonetic = term.raw_phonetic differences = construct_default_differences(dialect) else phonemic = export.IPA(term.term, dialect, false) phonetic = export.IPA(term.term, dialect, true) differences = phonemic.differences phonemic = phonemic.text phonetic = phonetic.text end ret.pronun[dialect][i] = { raw = term.raw, phonemic = phonemic, phonetic = phonetic, refs = term.refs, q = term.q, qq = term.qq, a = term.a, aa = term.aa, differences = differences, } end end local function generate_pronun(args) local function this_dodialect_pronun(ret, dialect) dodialect_pronun(args, ret, dialect) end local ret = express_all_styles(args.style, this_dodialect_pronun) local function format_style(tag, pronuns, is_first) local pronunciations = {} local formatted_pronuns = {} local function ins(formatted_part) table.insert(formatted_pronuns, formatted_part) end -- Loop through each pronunciation. For each one, add the phonemic and phonetic versions to `pronunciations`, -- for formatting by [[Module:IPA]], and also create an approximation of the formatted version so that we can -- compute the appropriate width of the HTML switcher div box that holds the different per-dialect variants. -- NOTE: The code below constructs the formatted approximation out-of-order in some cases but that doesn't -- currently matter because we assume all characters have the same width. If we change the width computation -- in a way that requires the correct order, we need changes to the code below. for j, pronun in ipairs(pronuns) do -- Add tag to left qualifiers if first one -- FIXME: Consider using accent qualifier for the tag instead. local aas = pronun.aa if j == #pronuns and tag then if aas then aas = m_table.deepCopy(aas) table.insert(aas, tag) else aas = {tag} end end local first_pronun = #pronunciations + 1 if not pronun.phonemic and not pronun.phonetic then error("Internal error: Saw neither phonemic nor phonetic pronunciation") end if pronun.phonemic then -- missing if 'raw:[...]' given -- don't display syllable division markers in phonemic local slash_pron = "/" .. cleanup_pron(pronun.phonemic:gsub("%.", "")) .. "/" table.insert(pronunciations, { pron = slash_pron, }) ins(slash_pron) end if pronun.phonetic then -- missing if 'raw:/.../' given local bracket_pron = "[" .. cleanup_pron(pronun.phonetic) .. "]" table.insert(pronunciations, { pron = bracket_pron, }) ins(bracket_pron) end local last_pronun = #pronunciations if pronun.q then pronunciations[first_pronun].q = pronun.q end if pronun.a then pronunciations[first_pronun].a = pronun.a end if j > 1 then pronunciations[first_pronun].separator = ", " ins(", ") end if pronun.qq then pronunciations[last_pronun].qq = pronun.qq end if aas then pronunciations[last_pronun].aa = aas end if pronun.q or pronun.qq or pronun.a or aas then ins(require(decorations_module).format_decorations { lang = lang, text = "", q = pronun.q, qq = pronun.qq, a = pronun.a, aa = aas, }) end if pronun.refs then pronunciations[last_pronun].refs = pronun.refs -- Approximate the reference using a footnote notation. This will be slightly inaccurate if there are -- more than nine references but that is rare. ins(string.rep("[1]", #pronun.refs)) end if first_pronun ~= last_pronun then pronunciations[last_pronun].separator = " " ins(" ") end end local bullet = string.rep("*", args.bullets) .. " " -- Here we construct the formatted line in `formatted`. local pre = is_first and args.pre and args.pre .. " " or "" local post = is_first and args.post and " " .. args.post or "" local formatted = bullet .. pre .. m_IPA.format_IPA_full { lang = lang, items = pronunciations, separator = "" } .. post return formatted end ret.text = format_all_styles(ret.expressed_styles, format_style) return ret end local function parse_respelling(respelling, pagename, parse_err) local raw_respelling = respelling:match("^raw:(.*)$") if raw_respelling then local raw_phonemic, raw_phonetic = raw_respelling:match("^/(.*)/ %[(.*)%]$") if not raw_phonemic then raw_phonemic = raw_respelling:match("^/(.*)/$") end if not raw_phonemic then raw_phonetic = raw_respelling:match("^%[(.*)%]$") end if not raw_phonemic and not raw_phonetic then parse_err(("Unable to parse raw respelling '%s', should be one of /.../, [...] or /.../ [...]") :format(raw_respelling)) end return { raw = true, raw_phonemic = raw_phonemic, raw_phonetic = raw_phonetic, } end if respelling == "+" then respelling = pagename end return {term = respelling} end -- Return the number of syllables of a phonemic representation, which should have syllable dividers in it but no -- hyphens. local function get_num_syl_from_phonemic(phonemic) -- Maybe we should just count vowels instead of the below code. phonemic = rsub(phonemic, "|", " ") -- remove IPA foot boundaries local words = rsplit(phonemic, " +") for i, word in ipairs(words) do -- IPA stress marks are syllable divisions if between characters; otherwise just remove. word = rsub(word, "(.)[ˌˈ](.)", "%1.%2") word = rsub(word, "[ˌˈ]", "") words[i] = word end -- There should be a syllable boundary between words. phonemic = table.concat(words, ".") return ulen(rsub(phonemic, "[^.]", "")) + 1 end -- Get the rhyme by truncating everything up through the last stress mark + any following consonants, and remove -- syllable boundary markers. local function convert_phonemic_to_rhyme(phonemic) -- NOTE: This works because the phonemic vowels are just [aeiou] possibly with diacritics that are separate -- Unicode chars. If we want to handle things like ɛ or ɔ we need to add them to `vowel`. return rsub(rsub(phonemic, ".*[ˌˈ]", ""), "^[^" .. vowel .. "]*", ""):gsub("%.", ""):gsub("t͡ʃ", "tʃ") end local function split_syllabified_spelling(spelling) return rsplit(spelling, "%.") end -- "Align" syllabification to original spelling by matching character-by-character, allowing for extra syllable and -- accent markers in the syllabification. If we encounter an extra syllable marker (.), we allow and keep it. If we -- encounter an extra accent marker in the syllabification, we drop it. In any other case, we return nil indicating -- the alignment failed. local function align_syllabification_to_spelling(syllab, spelling) local result = {} local syll_chars = rsplit(decompose(syllab), "") local spelling_chars = rsplit(decompose(spelling), "") local i = 1 local j = 1 while i <= #syll_chars or j <= #spelling_chars do local ci = syll_chars[i] local cj = spelling_chars[j] if ci == cj then table.insert(result, ci) i = i + 1 j = j + 1 elseif ci == "." then table.insert(result, ci) i = i + 1 elseif ci == AC or ci == GR or ci == CFLEX or ci == DIA then -- skip character i = i + 1 else -- non-matching character return nil end end if i <= #syll_chars or j <= #spelling_chars then -- left-over characters on one side or the other return nil end return unfc(table.concat(result)) end local function generate_hyph_obj(term) return {syllabification = term, hyph = split_syllabified_spelling(term)} end -- Word should already be decomposed. local function word_has_vowels(word) if word == "l" or word == "ls" then return true end return rfind(word, V) end local function all_words_have_vowels(term) local words = rsplit(decompose(term), "[ %-]") for i, word in ipairs(words) do -- Allow empty word; this occurs with prefixes and suffixes. if word ~= "" and not word_has_vowels(word) then return false end end return true end local function should_generate_rhyme_from_respelling(term) local words = rsplit(decompose(term), " +") return #words == 1 and -- no if multiple words not words[1]:find(".%-.") and -- no if word is composed of hyphenated parts (e.g. [[Austria-Hungría]]) not words[1]:find("%-$") and -- no if word is a prefix not (words[1]:find("^%-") and words[1]:find(CFLEX)) and -- no if word is an unstressed suffix word_has_vowels(words[1]) -- no if word has no vowels (e.g. a single letter) end local function should_generate_rhyme_from_ipa(ipa) return not ipa:find("%s") and word_has_vowels(decompose(ipa)) end local function dodialect_specified_rhymes(rhymes, hyphs, parsed_respellings, rhyme_ret, dialect) rhyme_ret.pronun[dialect] = {} for _, rhyme in ipairs(rhymes) do local num_syl = rhyme.num_syl local no_num_syl = false -- If user explicitly gave the rhyme but didn't explicitly specify the number of syllables, try to take it from -- the hyphenation. if not num_syl then num_syl = {} for _, hyph in ipairs(hyphs) do if should_generate_rhyme_from_respelling(hyph.syllabification) then local this_num_syl = 1 + ulen(rsub(hyph.syllabification, "[^.]", "")) m_table.insertIfNot(num_syl, this_num_syl) else no_num_syl = true break end end if no_num_syl or #num_syl == 0 then num_syl = nil end end -- If that fails and term is single-word, try to take it from the phonemic. if not no_num_syl and not num_syl then for _, parsed in ipairs(parsed_respellings) do for dialect, pronun in pairs(parsed.pronun.pronun[dialect]) do -- Check that pronun.phonemic exists (it may not if raw phonetic-only pronun is given). if pronun.phonemic then if not should_generate_rhyme_from_ipa(pronun.phonemic) then no_num_syl = true break end -- Count number of syllables by looking at syllable boundaries (including stress marks). local this_num_syl = get_num_syl_from_phonemic(pronun.phonemic) m_table.insertIfNot(num_syl, this_num_syl) end end if no_num_syl then break end end if no_num_syl or #num_syl == 0 then num_syl = nil end end table.insert(rhyme_ret.pronun[dialect], { rhyme = rhyme.rhyme, num_syl = num_syl, q = rhyme.q, differences = construct_default_differences(dialect), }) end end local q_qq_inline_modifier_spec = { store = "insert-flattened", type = "qualifier", } local a_aa_inline_modifier_spec = { store = "insert-flattened", type = "labels", } local ref_inline_modifier_spec = { store = "insert-flattened", item_dest = "refs", type = "references", } -- Parse a pronunciation modifier in `arg`, the argument portion in an inline modifier (after the prefix), which -- specifies a pronunciation property such as rhyme, hyphenation/syllabification, homophones or audio. The argument -- can itself have inline modifiers, e.g. <audio:Foo.ogg<a:Central>>. The allowed inline modifiers are specified -- by `param_mods` (of the format expected by `parse_inline_modifiers()`); in addition to any modifiers specified -- there, the modifiers <q:...>, <qq:...>, <a:...>, <aa:...> and <ref:...> are always accepted (and can be repeated). -- `generate_obj` and `parse_err` are like in `parse_inline_modifiers()` and specify respectively a function to -- generate the object into which modifier properties are stored given the non-modifier part of the argument, and -- a function to generate an error message (given the message). Normally, a comma-separated list of pronunciation -- properties is accepted and parsed, where each element in the list can have its own inline modifiers and where -- no spaces are allowed next to the commas in order for them to be recognized as separators. If `no_split_on_comma` -- is given, only a single pronunciation property is accepted. In all cases, however, the return value is a list -- of property objects (when `no_split_on_comma` is given, the return value is a one-element list). local function parse_pron_modifier(arg, parse_err, generate_obj, param_mods, no_split_on_comma) if arg:find("<") then param_mods.q = q_qq_inline_modifier_spec param_mods.qq = q_qq_inline_modifier_spec param_mods.a = a_aa_inline_modifier_spec param_mods.aa = a_aa_inline_modifier_spec param_mods.ref = ref_inline_modifier_spec local retval = require(parse_utilities_module).parse_inline_modifiers(arg, { param_mods = param_mods, generate_obj = generate_obj, parse_err = parse_err, splitchar = not no_split_on_comma and "," or nil, }) if no_split_on_comma then retval = {retval} end return retval elseif no_split_on_comma then return {generate_obj(arg)} else local retval = {} for _, term in ipairs(split_on_comma(arg)) do table.insert(retval, generate_obj(term)) end return retval end end local function parse_rhyme(arg, parse_err) local function generate_obj(term) return {rhyme = term} end local param_mods = { s = { item_dest = "num_syl", type = "number", sublist = true, }, } return parse_pron_modifier(arg, parse_err, generate_obj, param_mods) end local function parse_hyph(arg, parse_err) -- None other than decorations local param_mods = {} return parse_pron_modifier(arg, parse_err, generate_hyph_obj, param_mods) end local function parse_homophone(arg, parse_err) local function generate_obj(term) return {term = term} end local param_mods = { t = { -- [[Module:links]] expects the gloss in "gloss". item_dest = "gloss", }, gloss = {}, -- No tr=, ts=, or sc=; doesn't make sense for Spanish. pos = {}, alt = {}, lit = {}, id = {}, g = { -- [[Module:links]] expects the genders in "genders". item_dest = "genders", sublist = true, }, } return parse_pron_modifier(arg, parse_err, generate_obj, param_mods) end local function generate_audio_obj(arg) local file, caption = arg:match("^(.-)%s*#%s*(.*)$") file = file or arg return {file = file, caption = caption} end local function parse_audio(arg, parse_err) local param_mods = { IPA = { sublist = true, }, text = {}, t = { item_dest = "gloss", }, -- No tr=, ts=, or sc=; doesn't make sense for Spanish. gloss = {}, pos = {}, -- No alt=; text= already goes in alt=. lit = {}, -- No id=; text= already goes in alt= and isn't normally linked. g = { item_dest = "genders", sublist = true, }, bad = {}, } -- Don't split on comma because some filenames have embedded commas not followed by a space -- (typically followed by an underscore). local retvals = parse_pron_modifier(arg, parse_err, generate_audio_obj, param_mods, "no split on comma") local retval = retvals[1] retval.lang = lang local textobj = require(audio_module).construct_audio_textobj(retval) retval.text = textobj retval.gloss = nil retval.pos = nil retval.lit = nil retval.genders = nil return retval end -- External entry point for {{es-pr}}. function export.show_pr(frame) local params = { [1] = {list = true}, ["rhyme"] = {convert = parse_rhyme}, ["hyph"] = {convert = parse_hyph}, ["hmp"] = {convert = parse_homophone}, ["audio"] = {list = true}, ["pagename"] = {}, } local parargs = frame:getParent().args local args = require(parameters_module).process(parargs, params) local pagename = args.pagename or mw.loadData(headword_data_module).pagename -- Parse the arguments. local respellings = #args[1] > 0 and args[1] or {"+"} local parsed_respellings = {} local overall_rhyme = args.rhyme local overall_hyph = args.hyph local overall_hmp = args.hmp local overall_audio if args.audio then -- We can't specify parse_audio() as a `convert` function because it needs access to `pagename` (i.e. another -- parameter). overall_audio = {} for i, audio in ipairs(args.audio) do local function parse_err(msg) error(("%s: parameter audio%s=%s"):format(msg, i == 1 and "" or i, audio)) end local parsed_audio = parse_audio(audio, parse_err, pagename) table.insert(overall_audio, parsed_audio) end end for i, respelling in ipairs(respellings) do if respelling:find("<") then local param_mods = { pre = { overall = true }, post = { overall = true }, style = { overall = true }, bullets = { overall = true, type = "number", }, rhyme = { overall = true, store = "insert-flattened", convert = parse_rhyme, }, hyph = { overall = true, store = "insert-flattened", convert = parse_hyph, }, hmp = { overall = true, store = "insert-flattened", convert = parse_homophone, }, audio = { overall = true, store = "insert", convert = function(arg, parse_err) return parse_audio(arg, parse_err, pagename) end, }, ref = ref_inline_modifier_spec, q = q_qq_inline_modifier_spec, qq = q_qq_inline_modifier_spec, a = a_aa_inline_modifier_spec, aa = a_aa_inline_modifier_spec, } local parsed = require(parse_utilities_module).parse_inline_modifiers(respelling, { paramname = i, param_mods = param_mods, generate_obj = function(term, parse_err) return parse_respelling(term, pagename, parse_err) end, splitchar = ",", outer_container = { audio = {}, rhyme = {}, hyph = {}, hmp = {} } }) if not parsed.bullets then parsed.bullets = 1 end table.insert(parsed_respellings, parsed) else local termobjs = {} local function parse_err(msg) error(msg .. ": " .. i .. "=" .. respelling) end for _, term in ipairs(split_on_comma(respelling)) do table.insert(termobjs, parse_respelling(term, pagename, parse_err)) end table.insert(parsed_respellings, { terms = termobjs, audio = {}, rhyme = {}, hyph = {}, hmp = {}, bullets = 1, }) end end if overall_hyph then local hyphs = {} for _, hyph in ipairs(overall_hyph) do if hyph.syllabification == "+" then hyph.syllabification = syllabify_from_spelling(pagename) hyph.hyph = split_syllabified_spelling(hyph.syllabification) elseif hyph.syllabification == "-" then overall_hyph = {} break end end end -- Loop over individual respellings, processing each. for _, parsed in ipairs(parsed_respellings) do parsed.pronun = generate_pronun(parsed) local no_auto_rhyme = false for _, term in ipairs(parsed.terms) do if term.raw then if not should_generate_rhyme_from_ipa(term.raw_phonemic or term.raw_phonetic) then no_auto_rhyme = true break end elseif not should_generate_rhyme_from_respelling(term.term) then no_auto_rhyme = true break end end if #parsed.hyph == 0 then if not overall_hyph and all_words_have_vowels(pagename) then for _, term in ipairs(parsed.terms) do if not term.raw then local syllabification = syllabify_from_spelling(term.term) local aligned_syll = align_syllabification_to_spelling(syllabification, pagename) if aligned_syll then m_table.insertIfNot(parsed.hyph, generate_hyph_obj(aligned_syll)) end end end end else for _, hyph in ipairs(parsed.hyph) do if hyph.syllabification == "+" then hyph.syllabification = syllabify_from_spelling(pagename) hyph.hyph = split_syllabified_spelling(hyph.syllabification) elseif hyph.syllabification == "-" then parsed.hyph = {} break end end end -- Generate the rhymes. local function dodialect_rhymes_from_pronun(rhyme_ret, dialect) rhyme_ret.pronun[dialect] = {} -- It's possible the pronunciation for a passed-in dialect was never generated. -- In this case we need to generate the missing overall pronunciation ourselves -- since we need it to generate the dialect-specific rhyme pronunciation. if not parsed.pronun.pronun[dialect] then dodialect_pronun(parsed, parsed.pronun, dialect) end for _, pronun in ipairs(parsed.pronun.pronun[dialect]) do -- We should have already excluded multiword terms and terms without vowels from rhyme generation (see -- `no_auto_rhyme` below). But make sure to check that pronun.phonemic exists (it may not if raw -- phonetic-only pronun is given). if pronun.phonemic then -- Count number of syllables by looking at syllable boundaries (including stress marks). local num_syl = get_num_syl_from_phonemic(pronun.phonemic) -- Get the rhyme by truncating everything up through the last stress mark + any following -- consonants, and remove syllable boundary markers. local rhyme = convert_phonemic_to_rhyme(pronun.phonemic) local saw_already = false for _, existing in ipairs(rhyme_ret.pronun[dialect]) do if existing.rhyme == rhyme then saw_already = true -- We already saw this rhyme but possibly with a different number of syllables. m_table.insertIfNot(existing.num_syl, num_syl) break end end if not saw_already then local rhyme_diffs = false if dialect == "central" then if rfind(rhyme, "[EẼOÕ]") then rhyme_diffs = true end end table.insert(rhyme_ret.pronun[dialect], { rhyme = cleanup_pron(rhyme), num_syl = {num_syl}, differences = rhyme_diffs, }) end end end end if #parsed.rhyme == 0 then if overall_rhyme or no_auto_rhyme then parsed.rhyme = nil else parsed.rhyme = express_all_styles(parsed.style, dodialect_rhymes_from_pronun) end else local no_rhyme = false for _, rhyme in ipairs(parsed.rhyme) do if rhyme.rhyme == "-" then no_rhyme = true break end end if no_rhyme then parsed.rhyme = nil else local function this_dodialect(rhyme_ret, dialect) return dodialect_specified_rhymes(parsed.rhyme, parsed.hyph, {parsed}, rhyme_ret, dialect) end parsed.rhyme = express_all_styles(parsed.style, this_dodialect) end end end if overall_rhyme then local no_overall_rhyme = false for _, orhyme in ipairs(overall_rhyme) do if orhyme.rhyme == "-" then no_overall_rhyme = true break end end if no_overall_rhyme then overall_rhyme = nil else local all_hyphs if overall_hyph then all_hyphs = overall_hyph else all_hyphs = {} for _, parsed in ipairs(parsed_respellings) do for _, hyph in ipairs(parsed.hyph) do m_table.insertIfNot(all_hyphs, hyph) end end end local function dodialect_overall_rhyme(rhyme_ret, dialect) return dodialect_specified_rhymes(overall_rhyme, all_hyphs, parsed_respellings, rhyme_ret, dialect) end overall_rhyme = express_all_styles(parsed.style, dodialect_overall_rhyme) end end -- If all sets of pronunciations have the same rhymes, display them only once at the bottom. -- Otherwise, display rhymes beneath each set, indented. local first_rhyme_ret local all_rhyme_sets_eq = true for j, parsed in ipairs(parsed_respellings) do if j == 1 then first_rhyme_ret = parsed.rhyme elseif not m_table.deepEquals(first_rhyme_ret, parsed.rhyme) then all_rhyme_sets_eq = false break end end local function format_rhyme(rhyme_ret, num_bullets) local function format_rhyme_style(tag, pronuns, is_first) local pronunciations = {} local rhymes = {} for _, pronun in ipairs(pronuns) do table.insert(rhymes, pronun) end local data = { lang = lang, rhymes = rhymes, aa = tag and {tag} or nil, } local bullet = string.rep("*", num_bullets) .. " " local formatted = bullet .. require(rhymes_module).format_rhymes(data) return formatted end return format_all_styles(rhyme_ret.expressed_styles, format_rhyme_style) end -- If all sets of pronunciations have the same hyphenations, display them only once at the bottom. -- Otherwise, display hyphenations beneath each set, indented. local first_hyphs local all_hyph_sets_eq = true for j, parsed in ipairs(parsed_respellings) do if j == 1 then first_hyphs = parsed.hyph elseif not m_table.deepEquals(first_hyphs, parsed.hyph) then all_hyph_sets_eq = false break end end local function format_hyphenations(hyphs, num_bullets) local hyphtext = require(hyphenation_module).format_hyphenations { lang = lang, hyphs = hyphs, caption = "Syllabification" } return string.rep("*", num_bullets) .. " " .. hyphtext end -- If all sets of pronunciations have the same homophones, display them only once at the bottom. -- Otherwise, display homophones beneath each set, indented. local first_hmps local all_hmp_sets_eq = true for j, parsed in ipairs(parsed_respellings) do if j == 1 then first_hmps = parsed.hmp elseif not m_table.deepEquals(first_hmps, parsed.hmp) then all_hmp_sets_eq = false break end end local function format_homophones(hmps, num_bullets) local hmptext = require(homophones_module).format_homophones { lang = lang, homophones = hmps } return string.rep("*", num_bullets) .. " " .. hmptext end local function format_audio(audios, num_bullets) local ret = {} for i, audio in ipairs(audios) do local text = require(audio_module).format_audio(audio) table.insert(ret, string.rep("*", num_bullets) .. " " .. text) end return table.concat(ret, "\n") end local textparts = {} local min_num_bullets = math.huge for j, parsed in ipairs(parsed_respellings) do if parsed.bullets < min_num_bullets then min_num_bullets = parsed.bullets end if j > 1 then table.insert(textparts, "\n") end table.insert(textparts, parsed.pronun.text) if #parsed.audio > 0 then table.insert(textparts, "\n") -- If only one pronunciation set, add the audio with the same number of bullets, otherwise -- indent audio by one more bullet. table.insert(textparts, format_audio(parsed.audio, #parsed_respellings == 1 and parsed.bullets or parsed.bullets + 1)) end if not all_rhyme_sets_eq and parsed.rhyme then table.insert(textparts, "\n") table.insert(textparts, format_rhyme(parsed.rhyme, parsed.bullets + 1)) end if not all_hyph_sets_eq and #parsed.hyph > 0 then table.insert(textparts, "\n") table.insert(textparts, format_hyphenations(parsed.hyph, parsed.bullets + 1)) end if not all_hmp_sets_eq and #parsed.hmp > 0 then table.insert(textparts, "\n") table.insert(textparts, format_homophones(parsed.hmp, parsed.bullets + 1)) end end if overall_audio and #overall_audio > 0 then table.insert(textparts, "\n") table.insert(textparts, format_audio(overall_audio, min_num_bullets)) end if all_rhyme_sets_eq and first_rhyme_ret then table.insert(textparts, "\n") table.insert(textparts, format_rhyme(first_rhyme_ret, min_num_bullets)) end if overall_rhyme then table.insert(textparts, "\n") table.insert(textparts, format_rhyme(overall_rhyme, min_num_bullets)) end if all_hyph_sets_eq and #first_hyphs > 0 then table.insert(textparts, "\n") table.insert(textparts, format_hyphenations(first_hyphs, min_num_bullets)) end if overall_hyph and #overall_hyph > 0 then table.insert(textparts, "\n") table.insert(textparts, format_hyphenations(overall_hyph, min_num_bullets)) end if all_hmp_sets_eq and #first_hmps > 0 then table.insert(textparts, "\n") table.insert(textparts, format_homophones(first_hmps, min_num_bullets)) end if overall_hmp and #overall_hmp > 0 then table.insert(textparts, "\n") table.insert(textparts, format_homophones(overall_hmp, min_num_bullets)) end return table.concat(textparts) end return export 419jl48voqw8ipti0ur6lvcz6qlod6f မဝ်ဂျူ:mwl-pron/documentation 828 299421 402306 2026-10-03T09:44:55Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "This module is not to be directly used. It is used by [[Template:mwl-pr]], see there for usage. <includeonly> {{module cat|mwl}} </includeonly>" 402306 wikitext text/x-wiki This module is not to be directly used. It is used by [[Template:mwl-pr]], see there for usage. <includeonly> {{module cat|mwl}} </includeonly> amd4fegf1wzvut6l0269q00k2qzr2pk 402307 402306 2026-10-03T09:45:44Z 咽頭べさ 33 咽頭べさ ပြံင်ပဆုဲလဝ် မုက်လိက် [[မဝ်ဂျူ:mwl-pron/doc]] ဇရေင် [[မဝ်ဂျူ:mwl-pron/documentation]] သီုကဵု ဟွံဂွံ ဂိုင်စွံလဝ် မကလေင်ပညုင် 402306 wikitext text/x-wiki This module is not to be directly used. It is used by [[Template:mwl-pr]], see there for usage. <includeonly> {{module cat|mwl}} </includeonly> amd4fegf1wzvut6l0269q00k2qzr2pk ကဏ္ဍ:မဝ်ဂျူမဳရာန်ဒါက်ဂမၠိုၚ် 14 299422 402308 2026-10-03T09:48:59Z 咽頭べさ 33 ခၞံကၠောန်လဝ် မုက်လိက် နကု "[[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာမဳရာန်ဒါက်|မဳရာန်ဒါက်]] » '''..." 402308 wikitext text/x-wiki [[:ကဏ္ဍ:ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်|ဒၞာဲလုပ်အဝေါၚ်ကဵုပၟိက်]] » [[:ကဏ္ဍ:အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်|အရေဝ်ဘာသာအိုတ်သီုဂမၠိုၚ်]] » [[:ကဏ္ဍ:ဘာသာမဳရာန်ဒါက်|မဳရာန်ဒါက်]] » '''မဝ်ဂျူဂမၠိုၚ်''' :[[:ကဏ္ဍ:မဝ်ဂျူဂမၠိုၚ်|မဝ်ဂျူ]]ဘာသာမဳရာန်ဒါက်၊ မနွံကဵုလုပ်အဝေါၚ်ကုဒ် Lua နကဵုမကၠောန်ဗဒှ် ကဵု မစဳရေၚ်ယဵုဒုၚ်သ္ပမာန်ဂမၠိုၚ်။ [[ကဏ္ဍ:ဘာသာမဳရာန်ဒါက်]][[ကဏ္ဍ:မဝ်ဂျူဗက်အလိုက်အရေဝ်ဘာသာဂမၠိုၚ်|မ]] d8caq3rtl4b2577eg7q0j1qam4z178e