Module:he-verb
Appearance
Documentation for this module may be created at Module:he-verb/doc
--[=[
Reference:
Input parameters:
1: binyan abbreviation
p: first root letter
a: second root letter
l: third root letter
Root letters may be prefixed with ':' to include them literally, in which case they will not be
parsed as hollow or weak and no dageshes will be added to or removed from them. Any of the
final form codes or intermediate data below can also be given explicitly in the input.
Binyan abbreviations:
pa: pa`al
pi: pi`el
po: po`el/polel
pu: pu`al
hif: hif`il
huf: huf`al
nif: nif`al
hit: hitpa`el
hitpo: hitpo`el/hitpolel
hitpu: hitpu`al *rare modern coinage
Tense abbreviations:
inf: to-infinitive
imp: imperative
fut: future (a.k.a. imperfect or prefix conjugation)
pres: present (a.k.a. active participle)
past: past (a.k.a. perfect or suffix conjugation)
noun: action noun
pp: passive participle
Gender abbreviations:
s: singular *first person only
p: plural *first person only
ms: masculine singular
fs: feminine singular
mp: masculine plural
fp: feminine plural
Person abbreviations:
1: first person
2: second person
3: third person
Exhaustive list of final form codes:
inf
noun *optional
pp *optional
imp_ms
imp_fs
imp_mp
imp_fp *obsolete
fut_1s
fut_2ms *always equal to fut_3fs
fut_2fs
fut_3ms
fut_3fs *always equal to fut_2ms
fut_1p
fut_2mp
fut_2fp *obsolete and always equal to fut_3fp
fut_3mp
fut_3fp *obsolete and always equal to fut_2fp
past_1s
past_2ms
past_2fs
past_3ms
past_3fs
past_1p
past_2mp
past_2fp
past_3mp
past_3fp *obsolete before Biblical Hebrew, therefore equal to past_3mp
pres_ms
pres_fs
pres_mp
pres_fp
Intermediate data:
root_p
root_a
root_l
gem *whether to treat as geminate
imp_pre_stem
imp_prs_stem
fut_gem
fut_char *characteristic vowel [a,i,u], pa`al only (default: u)
fut_pre_stem
fut_prs_stem
fut_1sp_stem
fut_mid_stem
fut_fin_stem
fut_suf_stem
fut_ffp_stem
pres_gem
pres_stem
past_gem
past_char *characteristic vowel [a,i,u], pa`al only (default: a)
past_stem
past_3_stem
past_2p_stem
hit_assim *assimilation or metathesis of the t- prefix in hitpa`el
]=]
local m_utilities = require("Module:utilities")
local m_links = require("Module:links")
local m_strutils = require("Module:string utilities")
local export = {}
local get_stems_for = {}
local lang = require("Module:languages").getLanguageByCode("he")
-- The main entry point.
-- This is the only function that can be invoked from a template.
function export.show(frame)
local args = frame:getParent().args
local binyan = args[1] or frame.args[1] or error("Binyan has not been specified. Please pass parameter 1 to the module invocation or parent template.")
PAGENAME = mw.title.getCurrentTitle().text
NAMESPACE = mw.title.getCurrentTitle().nsText
local categories = {}
parse_roots(args)
if binyan == "-" then
-- do nothing, stems are given explicitly
elseif get_stems_for[binyan] then
get_stems_for[binyan](args, categories)
else
error("Unknown binyan code '" .. binyan .. "'")
end
conjugate(args) -- finishes conjugation based on stems from get_stems_for[binyan]
args["notes"] = args["notes"] or ""
args["notes"] = "# Uncommon in Modern Hebrew.\n"
if args["bot"] or "" ~= "" then
return make_bot_list(forms, sep ~= "")
else
return make_table(args, title) .. m_utilities.format_categories(categories, lang)
end
end
local convert_root_char = {
["א"] = "א",
["ב"] = "ב",
["בּ"] = "ב", -- remove dagesh
["ג"] = "ג",
["גּ"] = "ג", -- remove dagesh
["ד"] = "ד",
["דּ"] = "ד", -- remove dagesh
["ה"] = "י", -- make hollow
["הּ"] = "ה", -- remove mappiq
["ו"] = "ו",
["ז"] = "ז",
["ח"] = "ח",
["ט"] = "ט",
["י"] = "י",
["כ"] = "כ",
["כּ"] = "כ", -- remove dagesh
["ך"] = "כ", -- normalize final
["ךּ"] = "כ", -- remove dagesh, normalize final
["ל"] = "ל",
["מ"] = "מ",
["ם"] = "מ", -- normalize final
["נ"] = "נ",
["ן"] = "נ", -- normalize final
["ס"] = "ס",
["ע"] = "ע",
["פ"] = "פ",
["פּ"] = "פ", -- remove dagesh
["ף"] = "פ", -- normalize final
["ףּ"] = "פ", -- remove dagesh, normalize final
["צ"] = "צ",
["ץ"] = "צ", -- normalize final
["ק"] = "ק",
["ר"] = "ר",
["ש"] = "שׁ", -- assume shin
["שׁ"] = "שׁ", -- shin
["שׂ"] = "שׂ", -- sin
["ת"] = "ת",
["תּ"] = "ת", -- remove dagesh
}
local hit_assim_table = {
["שׁ"] = "שְׁתּ",
["שׂ"] = "שְׂתּ",
["ס"] = "סְתּ",
["ז"] = "זְדּ",
["צ"] = "צְט",
["ת"] = "תּ",
["ד"] = "דּ",
["ט"] = "טּ",
}
local forms_initial = {
["ב"] = "בּ",
["ג"] = "גּ",
["ד"] = "דּ",
["כ"] = "כּ",
["פ"] = "פּ",
["ת"] = "תּ",
}
local non_doubling_letters = {
["א"] = true,
["ה"] = false,
["ח"] = false,
["ע"] = false,
["ר"] = true,
}
local forms_final = {
["ה"] = "הַּ",
["ח"] = "חַ",
["כ"] = "ךְ",
["מ"] = "ם",
["נ"] = "ן",
["ע"] = "עַ",
["פ"] = "ף",
["צ"] = "ץ",
}
local forms_final_a = {
["ה"] = "הּ",
["כ"] = "ךְ",
["מ"] = "ם",
["נ"] = "ן",
["פ"] = "ף",
["צ"] = "ץ",
}
local lengthen_vowel = {
["ִ"] = "ֵ",
["ֻ"] = "ֹ",
["ַ"] = "ָ",
}
function gen_link(x)
if type(x) == "table" then
local pg = lang:makeEntryName(x[1])
if pg == lang:makeEntryName(x[2]) then
return m_links.full_link(pg, x[2], lang, "Hebr", nil, nil, {}, PAGENAME)
else
return m_links.full_link(pg, pg .. " \\ " .. x[2], lang, "Hebr", nil, nil, {}, PAGENAME)
end
else
if x == "-" then
return "—" -- m-dash
else
return m_links.full_link(x, nil, lang, "Hebr", nil, nil, {}, PAGENAME)
end
end
end
function process_args(args)
for key, value in pairs(args) do
local i = mw.ustring.find(value, "\\")
if i then
args[key] = {mw.ustring.sub(value, 1, i - 1), mw.ustring.sub(value, i + 1)}
end
end
end
function append_parts_2(a, b)
if type(a) == "table" then
if type(b) == "table" then
return {a[1] .. b[1], a[2] .. b[2]}
else
return {a[1] .. lang:makeEntryName(b), a[2] .. b}
end
else
if type(b) == "table" then
return {lang:makeEntryName(a) .. b[1], a .. b[2]}
else
return a .. b
end
end
end
function append_parts(a, ...)
for _, b in ipairs({...}) do
a = append_parts_2(a, b)
end
return a
end
function ends_in_shva(x)
if type(x) == "table" then
x = x[2]
end
return mw.ustring.sub(x, -1) == "ְ"
end
function get_form_initial(letter)
if mw.ustring.sub(letter, 1, 1) == ":" then
return mw.ustring.sub(letter, 2)
else
return forms_initial[letter] or letter
end
end
function get_form_medial(letter)
if mw.ustring.sub(letter, 1, 1) == ":" then
return mw.ustring.sub(letter, 2)
else
return letter
end
end
function get_form_double(letter, vowel)
vowel = vowel or ""
if mw.ustring.sub(letter, 1, 1) == ":" then
return vowel .. mw.ustring.sub(letter, 2)
else
local lengthen = non_doubling_letters[letter]
if lengthen == nil then
return vowel .. letter .. "ּ"
elseif lengthen then
return (lengthen_vowel[vowel] or vowel) .. letter
else
return vowel .. letter
end
end
end
function get_form_final(letter)
if mw.ustring.sub(letter, 1, 1) == ":" then
return mw.ustring.sub(letter, 2)
else
return forms_final[letter] or letter
end
end
function get_form_final_a(letter)
if mw.ustring.sub(letter, 1, 1) == ":" then
return mw.ustring.sub(letter, 2)
else
return forms_final_a[letter] or letter
end
end
function infer_hit_assim(args)
if not args["hit_assim"] then
local p = args["root_p"]
args["hit_assim"] = hit_assim_table[p] or ("תְ" .. get_form_initial(p))
end
end
function parse_roots(args)
for _, x in ipairs({"p", "a", "l"}) do
if not args[x] then
error("Missing root letter '" .. x .. "'.")
end
local root_x = "root_" .. x
if not args[root_x] then
if mw.ustring.sub(args[x], 1, 1) == ":" then
args[root_x] = args[x]
else
args[root_x] = convert_root_char[args[x]]
if not args[root_x] then
error("Unrecognized root letter '" .. args[x] .. "'.")
end
end
end
end
end
function conjugate(args)
if not args["imp_ms"] then
args["imp_ms"] = append_parts(args["imp_pre_stem"], args["fut_mid_stem"], args["fut_fin_stem"])
end
if not args["imp_fs"] then
args["imp_fs"] = append_parts(args["imp_prs_stem"] or args["imp_pre_stem"], args["fut_mid_stem"], args["fut_suf_stem"], "ִי")
end
if not args["imp_mp"] then
args["imp_mp"] = append_parts(args["imp_prs_stem"] or args["imp_pre_stem"], args["fut_mid_stem"], args["fut_suf_stem"], "וּ")
end
if not args["imp_fp"] then
args["imp_fp"] = append_parts(args["imp_pre_stem"], args["fut_mid_stem"], args["fut_ffp_stem"], "נָה")
end
if not args["fut_1s"] then
args["fut_1s"] = append_parts("א", args["fut_1sp_stem"] or args["fut_pre_stem"], args["fut_mid_stem"], args["fut_fin_stem"])
end
if not args["fut_2ms"] then
args["fut_2ms"] = append_parts("תּ", args["fut_pre_stem"], args["fut_mid_stem"], args["fut_fin_stem"])
end
if not args["fut_2fs"] then
args["fut_2fs"] = append_parts("תּ", args["fut_prs_stem"] or args["fut_pre_stem"], args["fut_mid_stem"], args["fut_suf_stem"], "ִי")
end
if not args["fut_3ms"] then
args["fut_3ms"] = append_parts("י", args["fut_pre_stem"], args["fut_mid_stem"], args["fut_fin_stem"])
end
if not args["fut_3fs"] then
args["fut_3fs"] = args["fut_2ms"]
end
if not args["fut_1p"] then
args["fut_1p"] = append_parts("נ", args["fut_pre_stem"], args["fut_mid_stem"], args["fut_fin_stem"])
end
if not args["fut_2mp"] then
args["fut_2mp"] = append_parts("תּ", args["fut_prs_stem"] or args["fut_pre_stem"], args["fut_mid_stem"], args["fut_suf_stem"], "וּ")
end
if not args["fut_2fp"] then
args["fut_2fp"] = append_parts("תּ", args["fut_pre_stem"], args["fut_mid_stem"], args["fut_ffp_stem"], "נָה")
end
if not args["fut_3mp"] then
args["fut_3mp"] = append_parts("י", args["fut_prs_stem"] or args["fut_pre_stem"], args["fut_mid_stem"], args["fut_suf_stem"], "וּ")
end
if not args["fut_3fp"] then
args["fut_3fp"] = append_parts("תּ", args["fut_pre_stem"], args["fut_mid_stem"], args["fut_ffp_stem"], "נָה")
end
if not args["pres_ms"] then
args["pres_ms"] = args["pres_stem"]
end
if not args["pres_fs"] then
args["pres_fs"] = append_parts(args["pres_stem"], "ָה")
end
if not args["pres_mp"] then
args["pres_mp"] = append_parts(args["pres_stem"], "ִים")
end
if not args["pres_fp"] then
args["pres_fp"] = append_parts(args["pres_stem"], "וֹת")
end
local dagesh = args["past_stem"] and ends_in_shva(args["past_stem"])
args["past_2p_stem"] = args["past_2p_stem"] or args["past_stem"]
local dagesh_2p = args["past_2p_stem"] and ends_in_shva(args["past_2p_stem"]) -- should be the same, but who knows...
if not args["past_1s"] then
args["past_1s"] = append_parts(args["past_stem"], dagesh and "תִּי" or "תִי")
end
if not args["past_2ms"] then
args["past_2ms"] = append_parts(args["past_stem"], dagesh and "תָּ" or "תָ")
end
if not args["past_2fs"] then
args["past_2fs"] = append_parts(args["past_stem"], dagesh and "תְּ" or "ת")
end
if not args["past_3ms"] then
args["past_3ms"] = args["past_3_stem"]
end
if not args["past_3fs"] then
args["past_3fs"] = append_parts(args["past_3_stem"], "ָה")
end
if not args["past_1p"] then
args["past_1p"] = append_parts(args["past_stem"], "נוּ")
end
if not args["past_2mp"] then
args["past_2mp"] = append_parts(args["past_2p_stem"], dagesh_2p and "תֶּם" or "תֶם")
end
if not args["past_2fp"] then
args["past_2fp"] = append_parts(args["past_2p_stem"], dagesh_2p and "תֶּן" or "תֶן")
end
if not args["past_3mp"] then
args["past_3mp"] = append_parts(args["past_3_stem"], "וּ")
end
if not args["past_3fp"] then
args["past_3fp"] = args["past_3mp"]
end
args["inf"] = args["inf"] or "-"
args["heading"] = "Conjugation table for " .. gen_link(args["past_3ms"])
end
local gutturals = {
["א"] = true,
["ה"] = true,
["ח"] = true,
["ע"] = true,
}
local char_vowel = {
["a"] = "ַ",
["i"] = "ִ",
["u"] = {"ו", "ֹ"},
}
local char_vowel_closed = {
["a"] = "ַ",
["i"] = "ַ",
["u"] = {"ו", "ֹ"},
}
get_stems_for["pa"] = function(args, categories)
local root_p = args["root_p"]
local root_a = args["root_a"]
local root_l = args["root_l"]
args["past_char"] = args["past_char"] or "a"
args["fut_char"] = args["fut_char"] or (gutturals[args["root_l"]] and "a") or "u"
local past_char = args["past_char"]
local fut_char = args["fut_char"]
if false then
-- reserved for special cases
elseif false then
-- reserved for special cases
else
args["inf"] = args["inf"] or append_parts("לִ", get_form_medial(root_p), "ְ", get_form_initial(root_a), {"ו", "ֹ"}, get_form_final(root_l))
args["noun"] = args["noun"] or append_parts(get_form_initial(root_p), "ְ", get_form_medial(root_a), "ִי", get_form_medial(root_l), "ָה")
args["pp"] = args["pp"] or append_parts(get_form_initial(root_p), "ָ", get_form_medial(root_a), "וּ", get_form_final(root_l))
args["imp_pre_stem"] = args["imp_pre_stem"] or append_parts(get_form_initial(root_p), "ְ", get_form_medial(root_a))
args["imp_prs_stem"] = args["imp_prs_stem"] or append_parts(get_form_initial(root_p), "ִ", get_form_medial(root_a))
args["fut_pre_stem"] = args["fut_pre_stem"] or append_parts("ִ", get_form_medial(root_p), "ְ", get_form_initial(root_a))
args["fut_1sp_stem"] = args["fut_1sp_stem"] or append_parts("ֶ", get_form_medial(root_p), "ְ", get_form_initial(root_a))
args["fut_mid_stem"] = args["fut_mid_stem"] or ""
args["fut_fin_stem"] = args["fut_fin_stem"] or append_parts(char_vowel[fut_char], fut_char == "a" and get_form_final_a(root_l) or get_form_final(root_l))
args["fut_suf_stem"] = args["fut_suf_stem"] or append_parts("ְ", get_form_medial(root_l))
args["fut_ffp_stem"] = args["fut_ffp_stem"] or append_parts(char_vowel[fut_char], get_form_medial(root_l), "ְ")
args["pres_stem"] = args["pres_stem"] or append_parts(get_form_initial(root_p), "וֹ", get_form_medial(root_a), "ְ", get_form_medial(root_l))
args["pres_ms"] = args["pres_ms"] or append_parts(get_form_initial(root_p), "וֹ", get_form_medial(root_a), "ֵ", get_form_final(root_l))
args["pres_fs"] = args["pres_fs"] or append_parts(get_form_initial(root_p), "וֹ", get_form_medial(root_a), "ֶ", get_form_medial(root_l), "ֶת")
args["past_3ms"] = args["past_3ms"] or append_parts(get_form_initial(root_p), "ָ", get_form_medial(root_a), char_vowel[past_char], past_char == "a" and get_form_final_a(root_l) or get_form_final(root_l))
args["past_stem"] = args["past_stem"] or append_parts(get_form_initial(root_p), "ָ", get_form_medial(root_a), char_vowel_closed[past_char], get_form_medial(root_l), "ְ")
args["past_2p_stem"] = args["past_2p_stem"] or append_parts(get_form_initial(root_p), "ְ", get_form_medial(root_a), char_vowel_closed[past_char], get_form_medial(root_l), "ְ")
args["past_3_stem"] = args["past_3_stem"] or append_parts(get_form_initial(root_p), "ָ", get_form_medial(root_a), "ְ", get_form_medial(root_l))
end
-- error("Binyan pa`al is not yet implemented.")
end
get_stems_for["pi"] = function(args, categories)
error("Binyan pi`el is not yet implemented.")
end
get_stems_for["po"] = function(args, categories)
error("Binyan po`el is not yet implemented.")
end
get_stems_for["pu"] = function(args, categories)
error("Binyan pu`al is not yet implemented.")
end
get_stems_for["hif"] = function(args, categories)
error("Binyan hif`il is not yet implemented.")
end
get_stems_for["huf"] = function(args, categories)
error("Binyan huf`al is not yet implemented.")
end
get_stems_for["nif"] = function(args, categories)
error("Binyan nif`al is not yet implemented.")
end
get_stems_for["hit"] = function(args, categories)
infer_hit_assim(args)
error("Binyan hitpa`el is not yet implemented.")
end
get_stems_for["hitpo"] = function(args, categories)
infer_hit_assim(args)
error("Binyan hitpo`el is not yet implemented.")
end
get_stems_for["hitpu"] = function(args, categories)
infer_hit_assim(args)
error("Binyan hitpu`al is not yet implemented.")
end
local form_names = {
["inf"] = true,
["noun"] = true,
["pp"] = true,
["imp_ms"] = true,
["imp_fs"] = true,
["imp_mp"] = true,
["imp_fp"] = true,
["fut_1s"] = true,
["fut_2ms"] = true,
["fut_2fs"] = true,
["fut_3ms"] = true,
["fut_3fs"] = true,
["fut_1p"] = true,
["fut_2mp"] = true,
["fut_2fp"] = true,
["fut_3mp"] = true,
["fut_3fp"] = true,
["past_1s"] = true,
["past_2ms"] = true,
["past_2fs"] = true,
["past_3ms"] = true,
["past_3fs"] = true,
["past_1p"] = true,
["past_2mp"] = true,
["past_2fp"] = true,
["past_3mp"] = true,
["past_3fp"] = true,
["pres_ms"] = true,
["pres_fs"] = true,
["pres_mp"] = true,
["pres_fp"] = true,
}
function make_table(args)
for key, _ in pairs(form_names) do
args[key] = args[key] and gen_link(args[key])
end
args["non_finite"] = m_strutils.format(non_finite["inf"], args["inf"])
if args["noun"] then
args["non_finite"] = args["non_finite"] .. m_strutils.format(non_finite["noun"], args["noun"])
end
if args["pp"] then
args["non_finite"] = args["non_finite"] .. m_strutils.format(non_finite["pp"], args["pp"])
end
return m_strutils.format(table_template, args)
end
local table_template = [===[
<div class="NavFrame" style="width:100%m">
<div class="NavHead" align="left">{heading}</div>
<div class="NavContent" align="center">
<table border="1" color="#cdcdcd" style="margin:1em; border-collapse:collapse; line-height:2em; border:2px solid #000000; background:#fdfdfd; text-align:center" cellpadding="10" class="inflection-table">
<!-- note: widths of individual columns are controlled by the present-tense row -->
<tr>
<th scope='row' colspan="2" style="background:#E4C0CF;border-right:2px solid">non-finite forms</th>
<td colspan="4" style="text-align:left">
<ul>{non_finite}</ul>
</td>
</tr>
<tr style="border-top:2px solid">
<th colspan="2" style="background:#E4C0CF;border-right:2px solid">finite forms</th>
<th scope='col' style="background:#C0CFE4">masculine<br/>singular</th>
<th scope='col' style="background:#C0CFE4">feminine<br/>singular</th>
<th scope='col' style="background:#C0CFE4">masculine<br/>plural</th>
<th scope='col' style="background:#C0CFE4">feminine<br/>plural</th>
</tr>
<tr style="border-top:2px solid">
<th scope='row' rowspan="3" style="background:#E2E4C0">past</th>
<th scope='row' style="background:#C0CFE4;border-right:2px solid">first person</th>
<td colspan="2">{past_1s}</td>
<td colspan="2">{past_1p}</td>
</tr>
<tr>
<th scope='row' style="background:#C0CFE4;border-right:2px solid">second person</th>
<td>{past_2ms}</td>
<td>{past_2fs}</td>
<td>{past_2mp}</td>
<td>{past_2fp}</td>
</tr>
<tr>
<th scope='row' style="background:#C0CFE4;border-right:2px solid">third person</th>
<td>{past_3ms}</td>
<td>{past_3fs}</td>
<td colspan="2">{past_3mp}</td>
</tr>
<tr style="border-top:2px solid">
<th scope='row' style="background:#E2E4C0" width="16%">present</th>
<th scope='row' style="background:#C0CFE4;border-right:2px solid" width="16%">all persons</th>
<td width="17%">{pres_ms}</td>
<td width="17%">{pres_fs}</td>
<td width="17%">{pres_mp}</td>
<td width="17%">{pres_fp}</td>
</tr>
<tr style="border-top:2px solid">
<th scope='row' rowspan="3" style="background:#E2E4C0">future</th>
<th scope='row' style="background:#C0CFE4;border-right:2px solid">first person</th>
<td colspan="2">{fut_1s}</td>
<td colspan="2">{fut_1p}</td>
</tr>
<tr>
<th scope='row' style="background:#C0CFE4;border-right:2px solid">second person</th>
<td>{fut_2ms}</td>
<td>{fut_2fs}</td>
<td>{fut_2mp}</td>
<td>{fut_2fp}</td>
</tr>
<tr>
<th scope='row' style="background:#C0CFE4;border-right:2px solid">third person</th>
<td>{fut_3ms}</td>
<td>{fut_3fs}</td>
<td>{fut_3mp}</td>
<td>{fut_3fp}</td>
</tr>
<tr style="border-top:2px solid">
<th scope='row' style="background:#E2E4C0">imperative</th>
<th scope='row' style="background:#C0CFE4;border-right:2px solid">second person</th>
<td>{imp_ms}</td>
<td>{imp_fs}</td>
<td>{imp_mp}</td>
<td>{imp_fp}</td>
</tr>
<tr style="border-top:2px solid">
<th scope='row' colspan="2" style="background:#E4C0CF;border-right:2px solid">notes</th>
<td colspan="4" style="text-align:left">
{notes}
</td>
</tr>
</table>
</div>
</div>
]===]
local non_finite = {
["inf"] = "<li>'''to-infinitive:''' {inf}</li>",
["noun"] = "<li>'''action noun:''' {noun}</li>",
["pp"] = "<li>'''passive participle:''' {pp}</li>",
}
function make_table(args)
for key, _ in pairs(form_names) do
args[key] = args[key] and gen_link(args[key])
end
args["non_finite"] = m_strutils.format(non_finite["inf"], args)
if args["noun"] then
args["non_finite"] = args["non_finite"] .. m_strutils.format(non_finite["noun"], args)
end
if args["pp"] then
args["non_finite"] = args["non_finite"] .. m_strutils.format(non_finite["pp"], args)
end
return m_strutils.format(table_template, args)
end
return export