Module:he-verb

Hello, you have come here looking for the meaning of the word Module:he-verb. In DICTIOUS you will not only get to know all the dictionary meanings for the word Module:he-verb, but we will also tell you about its etymology, its characteristics and you will know how to say Module:he-verb in singular and plural. Everything you need to know about the word Module:he-verb you have here. The definition of the word Module:he-verb will help you to be more precise and correct when speaking or writing your texts. Knowing the definition ofModule:he-verb, as well as those of other words, enriches your vocabulary and provides you with more and better linguistic resources.

This module is used to create inflection tables for Hebrew verbs. It is currently under construction.


--[=[

TODO:
    - Implement support for hollow roots in nif`al.
    - Implement support for geminate roots in pa`al and nif`al.
    - Implement smarter ktiv male spellings.
    - Implement support for mixed binyanim (such as for ניגש and יכול).
    - Implement support for alternative forms.

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
        poal: po`al/polal
        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
        imp_mid_stem
        imp_fin_stem
        imp_suf_stem
        imp_ffp_stem

        fut_gem
        fut_char *characteristic vowel , 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_short *if not empty, use the pa`el-present, pa`al only
        pres_stem

        past_gem
        past_char *characteristic vowel , pa`al only (default: a)
        past_pre_stem
        past_2p_pre_stem
        past_stem
        past_3_stem
        past_3ms_stem
        past_3fs_stem
        past_2p_stem

]=]

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").getByCode("he")

local convert_root_char = {
     = "א",
     = "ב",
     = "בּ", -- always hard
     = "בֿ", -- always soft
     = "ג",
     = "גּ", -- always hard
     = "גֿ", -- always soft
     = "ד",
     = "דּ", -- always hard
     = "דֿ", -- always soft
     = "ה",
     = "ו",
     = "ז",
     = "ח",
     = "ט",
     = "י",
     = "כ",
     = "כּ", -- always hard
     = "כֿ", -- always soft
     = "ל",
     = "מ",
     = "נ",
     = "ס",
     = "ע",
     = "פ",
     = "פּ", -- always hard
     = "פֿ", -- always soft
     = "צ",
     = "ק",
     = "ר",
     = "שׁ", -- assume shin
     = "שׁ", -- shin
     = "שׂ", -- sin
     = "ת",
     = "תּ", -- always hard
     = "תֿ", -- always soft
}

local convert_final_root_char = {
     = "י", -- make defective
     = "ה", -- remove mappiq
     = "י", -- make defective
     = "כ", -- normalize final
     = "כּ", -- always hard, normalize final
     = "כֿ", -- always soft, normalize final
     = "מ", -- normalize final
     = "נ", -- normalize final
     = "פ", -- normalize final
     = "פּ", -- always hard, normalize final
     = "פֿ", -- always soft, normalize final
     = "צ", -- normalize final
}

local forms_itp = {
     = "שְׁתּ",
     = "שְׂתּ",
     = "סְתּ",
     = "זְדּ",
     = "צְט",
     = {"ית", "תּ"},
     = {"יד", "דּ"},
     = {"יט", "טּ"},
}

local forms_etp = {
     = "תּ",
     = "דּ",
     = "טּ",
}

local forms = {
     = "ב",
     = "ג",
     = "ד",
     = "כ",
     = "פ",
     = "ת",
}

local forms_initial = {
     = "בּ",
     = "גּ",
     = "דּ",
     = "כּ",
     = "פּ",
     = "תּ",
}

local non_doubling_letters = {
     = 1,
     = 2,
     = 3,
     = 2,
     = 1,
}

local forms_final_furtive = {
     = "הַּ",
     = "חַ",
     = "עַ",
}

local forms_final = {
     = "הּ",
     = "ךְ",
     = "ךְּ",
     = "ךְ",
     = "ם",
     = "ן",
     = "ף",
     = "ף",
     = "ץ",
}

local short_gem_vowel = {
     = "ַ",
     = {"י", "ִ"},
     = {"ו", "ֻ"},
     = "ֶ",
     = {"ו", "ָ"},
}

local lengthened_gem_vowel = {
     = "ָ",
     = {"י", "ֵ"},
     = {"ו", "ֹ"},
     = {"י", "ֵ"},
     = {"ו", "ֹ"},
}

local mixed_gem_vowel = {
     = "ַ",
     = {"י", "ִ"},
     = {"ו", "ֹ"},
     = "ֶ",
     = {"ו", "ֹ"},
}

local stressed_gem_vowel = {
     = "ַ",
     = "ֵ",
     = {"ו", "ֹ"},
     = "ֵ",
     = {"ו", "ֹ"},
}

local doubling_type = {
     = lengthened_gem_vowel,
     = mixed_gem_vowel,
     = short_gem_vowel,
}

local gutturals = {
     = true,
     = true,
     = true,
     = true,
}

local char_vowel = {
     = "ַ",
     = "ֵ",
     = {"ו", "ֹ"},
     = "ָ",
     = "ִי",
     = "וּ",
     = "ֵ",
     = "וֹ",
}

local char_vowel_open = {
     = "ָ",
     = "ֵ",
     = {"ו", "ֹ"},
     = "ָ",
     = "ִי",
     = "וּ",
     = "ֵ",
     = "וֹ",
}

local char_vowel_short = {
     = "ַ",
     = "ֵ",
     = {"ו", "ֹ"},
     = "ַ",
     = "ֵ",
     = {"ו", "ֹ"},
     = "ֵ",
     = {"ו", "ֹ"},
}

local char_vowel_open_short = {
     = "ָ",
     = "ֵ",
     = {"ו", "ֹ"},
     = "ָ",
     = "ֵ",
     = {"ו", "ֹ"},
     = "ֵ",
     = {"ו", "ֹ"},
}

local char_vowel_closed = {
     = "ַ",
     = "ַ",
     = {"ו", "ֹ"},
     = "ַ",
     = "ַ",
     = {"ו", "ֹ"},
     = "ַ",
     = {"ו", "ֹ"},
}

local char_vowel_unstressed = {
     = "ַ",
     = "ַ",
     = {"ו", "ָ"},
     = "ַ",
     = "ַ",
     = {"ו", "ָ"},
     = "ַ",
     = {"ו", "ָ"},
}

local char_vowel_open_fp = {
     = "ֶ",
     = "ֶ",
     = {"ו", "ֹ"},
     = "ֶ",
     = "ֶ",
     = {"ו", "ֹ"},
     = "ֶ",
     = {"ו", "ֹ"},
}

local char_vowel_reduce = {
     = nil,
     = nil,
     = nil,
     = "ָ",
     = "ִי",
     = "וּ",
     = "ֵ",
     = "וֹ",
}

local chataf_vowel = {
     = "ֲ",
     = "ֱ",
     = {"ו", "ֳ"},
}

local monophthongize = {
     = "ֵי",
     = "וֹ",
}

local function gen_link(x)
    if type(x) == "table" then
        local pg = (lang:makeEntryName(x))
        if pg == (lang:makeEntryName(x)) then
            return m_links.full_link({lang = lang, term = pg, alt = x})
        else
            return m_links.full_link({lang = lang, term = pg, alt = pg .. " / " .. x})
        end
    else
        if x == "-" then
            return "—" -- m-dash
        else
            return m_links.full_link({lang = lang, term = x})
        end
    end
end

local function process_args(args)
    for key, value in pairs(args) do
        local i = mw.ustring.find(value, "")
        if i then
            args = {mw.ustring.sub(value, 1, i - 1), mw.ustring.sub(value, i + 1)}
        end
    end
end

local function append_parts_2(a, b)
    if type(a) == "table" then
        if type(b) == "table" then
            return {a .. b, a .. b}
        else
            return {a .. (lang:makeEntryName(b)), a .. b}
        end
    else
        if type(b) == "table" then
            return {(lang:makeEntryName(a)) .. b, a .. b}
        else
            return a .. b
        end
    end
end

local function append_parts(a, ...)
    for _, b in ipairs({...}) do
        a = append_parts_2(a, b)
    end
    return a
end

local function equal(a, b)
    if type(a) == "table" then
        return type(b) == "table" and a == b and a == b
    else
        return a == b
    end
end

local function attach_t(x, novowel, assim_t)
    local is_table = (type(x) == "table")
    local wv = is_table and x or x
    if mw.ustring.sub(wv, -2) == "תְ" then
        if is_table then
            return {x .. "ת", mw.ustring.sub(wv, 1, -2) .. (novowel and "ְּ" or "ּ")}
        else
            return append_parts(mw.ustring.sub(wv, 1, -2), {"ת", (novowel and "ְּ" or "ּ")})
        end
    elseif assim_t and mw.ustring.sub(wv, -2) == "נְ" and (not is_table or mw.ustring.sub(x, -1) == "נ") then
        if is_table then
            return {mw.ustring.sub(x, 1, -2) .. "ת", mw.ustring.sub(wv, 1, -3) .. (novowel and "תְּ" or "תּ")}
        else
            return mw.ustring.sub(wv, 1, -3) .. (novowel and "תְּ" or "תּ")
        end
    else
        local dagesh = (mw.ustring.sub(wv, -1) == "ְ")
        return append_parts(x, dagesh and (novowel and "תְּ" or "תּ") or "ת")
    end
end

local function attach_n(x)
    local is_table = (type(x) == "table")
    local wv = is_table and x or x
    if mw.ustring.sub(wv, -2) == "נְ" then
        if is_table then
            return {x, mw.ustring.sub(wv, 1, -2) .. "ּ"}
        else
            return mw.ustring.sub(wv, 1, -2) .. "ּ"
        end
    else
        return append_parts(x, "נ")
    end
end

local function get_form_initial(letter)
    if type(letter) == "table" then
        return letter
    elseif mw.ustring.sub(letter, 1, 1) == ":" then
        return mw.ustring.sub(letter, 2)
    else
        return forms_initial or forms or letter
    end
end

local function get_form_itp(letter)
    return forms_itp or append_parts("תְ", get_form_initial(letter))
end

local function get_form_etp(letter)
    return forms_etp or forms_itp or append_parts("תְ", get_form_initial(letter))
end

local function get_form_medial(letter)
    if type(letter) == "table" then
        return letter
    elseif mw.ustring.sub(letter, 1, 1) == ":" then
        return mw.ustring.sub(letter, 2)
    else
        return forms or letter
    end
end

local dagesh_or_rafe = { = true,  = true}
local function add_dagesh(letter)
    if type(letter) == "table" then
        return letter
    elseif mw.ustring.sub(letter, 1, 1) == ":" then
        return get_form_medial(letter)
    elseif non_doubling_letters or dagesh_or_rafe then
        return get_form_medial(letter)
    else -- TODO: Handle geresh
        return get_form_medial(letter) .. "ּ"
    end
end

local function get_form_double(letter, vowel, force_lengthening, stressed)
    local lengthen = non_doubling_letters
    if force_lengthening then lengthen = lengthen and 1 end
    if stressed then
        vowel = vowel and (lengthen and vowel == "a" and "ָ" or stressed_gem_vowel) or ""
    else
        vowel = vowel and (lengthen and doubling_type or short_gem_vowel) or ""
    end
    return append_parts(vowel, add_dagesh(letter))
end

local function get_form_final(letter, char)
    if type(letter) == "table" then
        return letter
    elseif mw.ustring.sub(letter, 1, 1) == ":" then
        return mw.ustring.sub(letter, 2)
    else
        return (char ~= "a" and char ~= "A" and forms_final_furtive) or forms_final or forms or letter
    end
end

local function get_elet_ending(letter)
    if letter == "א" then
        return "ֵאת"
    else
        local vowel = gutturals and "ַ" or "ֶ"
        return append_parts(vowel, get_form_medial(letter), vowel, "ת")
    end
end

local function ends_in_guttural(letter)
    if type(letter) == "table" then
        letter = letter
    end
    return gutturals
end

local function shva_na(letter, vowel)
    return ends_in_guttural(letter) and chataf_vowel or "ְ"
end

local function reduce(char, chataf)
    return char_vowel_reduce or chataf and "ֲ" or "ְ"
end

local letters     = ""
local not_letters = ""
local modifiers   = "?"
local separators  = "?"
local root_regex  = "(" .. letters .. modifiers .. ")" .. separators

local function parse_root_part(part, last)
    if mw.ustring.sub(part, 1, 1) == ":" then
        return part
    end
    local letters = {}
    local len = 0
    local subber = function(letter)
        table.insert(letters, letter)
        len = len + 1
        return ""
    end
    local scraps = mw.ustring.gsub(part, root_regex, subber)
    if scraps ~= "" then
        return ":" .. part
    end
    if len < 1 then
        return nil
    elseif len == 1 then
        return part
    else
        local ret = ""
        for i, letter in ipairs(letters) do
            local letterx = last and i == len and convert_final_root_char or convert_root_char
            if not letterx then
                error("Unrecognized root letter '" .. letter .. "'.")
            end
            ret = append_parts(ret, get_form_medial(letterx), i == len and "" or "ְ")
        end
        if type(ret) == "table" then
            return ret
        else
            return ":" .. ret
        end
    end
end

local function parse_root(args)
    if args == "" then args = nil end
    if args == "" then args = nil end
    if args == "" then args = nil end
    if args then
        args = args or parse_root_part(args)
        args = args or parse_root_part(args)
        args = args or parse_root_part(args, true)
    elseif args then
        local radicals = {}
        local len = 0
        local subber = function(radical)
            table.insert(radicals, radical)
            len = len + 1
            return ""
        end
        local scraps = mw.ustring.gsub(args, root_regex, subber)
        if scraps ~= "" then
            error("Unrecognized characters in root.")
        end
        if len < 3 then
            error("Root must have at least three letters.")
        elseif len == 3 then
            args = args or radicals
            args = args or radicals
            args = args or radicals
        elseif len == 4 then
            args = args or radicals
            args = args or radicals
            args = args or radicals
            args = args or radicals
        elseif len > 4 then
            error("Roots with more than four letters must be explicitly delimited.")
        end
    end
end

local function convert_root(args)
    for _, x in ipairs({"p", "a", "a2", "l"}) do
        if args then
            local root_x = "root_" .. x
            if not args then
                if mw.ustring.sub(args, 1, 1) == ":" then
                    args = args
                else
                    args = x == "l" and convert_final_root_char] or convert_root_char]
                    if not args then
                        error("Unrecognized root letter '" .. args .. "'.")
                    end
                end
            end
        end
    end
    if args then
        local a = append_parts(get_form_medial(args), "ְ", get_form_initial(args))
        if type(a) ~= "table" then
            a = ":" .. a
        end
        args = a
        args = nil
    end
end

local function conjugate(args)
    args = args or args
    args = args or args
    args = args or args
    args = args or args
    args = args or args
    args = args or args
    local fp_long = args and args ~= "-"
    if fp_long then
        args = append_parts(args or args, "ֶי")
        args = append_parts(args or args, "ֶי")
    end
    if args ~= "-" then
        if not args then
            args = append_parts(args, args, args)
        end
        if not args then
            args = append_parts(args or args, args, args, "ִי")
        end
        if not args then
            args = append_parts(args or args, args, args, "וּ")
        end
        if not args then
            args = append_parts(fp_long and (args or args) or args, args, attach_n(fp_long and args or args), "ָה")
        end
    end

    if args ~= "-" then
        if not args then
            args = append_parts("א", args or args, args, args)
        end
        if not args then
            args = append_parts("תּ", args, args, args)
        end
        if not args then
            args = append_parts("תּ", args or args, args, args, "ִי")
        end
        if not args then
            args = append_parts("י", args, args, args)
        end
        if not args then
            args = args
        end
        if not args then
            args = append_parts("נ", args, args, args)
        end
        if not args then
            args = append_parts("תּ", args or args, args, args, "וּ")
        end
        if not args then
            args = append_parts("תּ", fp_long and (args or args) or args, args, attach_n(fp_long and args or args), "ָה")
        end
        if not args then
            args = append_parts("י", args or args, args, args, "וּ")
        end
        if not args then
            args = append_parts("תּ", fp_long and (args or args) or args, args, attach_n(fp_long and args or args), "ָה")
        end
    end

    if args ~= "-" then
        args = args or ""
        args = args or args
        if not args then
            args = append_parts(args, args)
        end
        if not args then
            args = args or append_parts(args, "ָה")
            args = append_parts(args, args)
        end
        if not args then
            args = append_parts(args, args, "ִים")
        end
        if not args then
            args = append_parts(args, args, "וֹת")
        end
    end

    if args ~= "-" then
        args = args or ""
        args = args or args
        local past_long = args and args ~= "-"
        if past_long then
            args = append_parts(args or args or args, "וֹ")
            args = args
            args = args or args == "י" and args or args
        else
            args = args or args
        end
        local assim_t = args and args ~= "-"
        if not args then
            args = append_parts(past_long and args or args, attach_t(args, false, assim_t), "ִי")
        end
        if not args then
            args = append_parts(past_long and args or args, attach_t(args, false, assim_t), "ָ")
        end
        if not args then
            args = append_parts(past_long and args or args, attach_t(args, true, assim_t))
        end
        if not args then
            args = append_parts(args, args)
        end
        if not args then
            args = append_parts(args or args or args, args or args, "ָה")
        end
        if not args then
            args = append_parts(past_long and args or args, attach_n(args), "וּ")
        end
        if not args then
            args = append_parts(past_long and args or args, attach_t(args, false, assim_t), "ֶם")
        end
        if not args then
            args = append_parts(past_long and args or args, attach_t(args, false, assim_t), "ֶן")
        end
        if not args then
            args = append_parts(past_long and args or args, attach_t(args, false, assim_t), "ֶם")
        end
        if not args then
            args = append_parts(past_long and args or args, attach_t(args, false, assim_t), "ֶן")
        end
        if not args then
            args = append_parts(args or args, args, "וּ")
        end
        if not args then
            args = args
        end
    end

    args = args or "-"

    args = "Conjugation of " .. gen_link(args) .. " (see also ])"
end

local function get_imp_stem_endings(args, root_l, char, chataf, keep_long_vowel, guttural_force_patach)
    if root_l == "א" then
        args = args or append_parts(keep_long_vowel and char_vowel_open or char_vowel_open_short, "א")
        args = args or append_parts(reduce(char, chataf), "א")
        args = args or append_parts(char_vowel_open_fp, "א")
        args = args or append_parts(char == "a" and char_vowel_open or reduce(char, chataf), "א")
    elseif root_l == "י" then
        args = args or "ֵה"
        args = args or ""
        args = args or "ֶי"
    else
        args = args or append_parts(keep_long_vowel and char_vowel or guttural_force_patach and gutturals and "ַ" or char_vowel_short, get_form_final(root_l, guttural_force_patach and (not keep_long_vowel) and gutturals and "a" or char))
        args = args or append_parts(reduce(char, chataf), get_form_medial(root_l))
        args = args or append_parts(gutturals and "ַ" or char_vowel_short, get_form_medial(root_l), "ְ")
        args = args or append_parts(char == "a" and char_vowel_open or reduce(char, chataf), get_form_medial(root_l))
    end
end

local function get_fut_stem_endings(args, root_l, char, chataf)
    if root_l == "א" then
        args = args or append_parts(char_vowel_open, "א")
        args = args or append_parts(reduce(char, chataf), "א")
        args = args or append_parts(char_vowel_open_fp, "א")
        args = args or append_parts(char == "a" and char_vowel_open or reduce(char, chataf), "א")
    elseif root_l == "י" then
        args = args or "ֶה"
        args = args or ""
        args = args or "ֶי"
    else
        args = args or append_parts(char_vowel, get_form_final(root_l, char))
        args = args or append_parts(reduce(char, chataf), get_form_medial(root_l))
        args = args or append_parts(gutturals and "ַ" or char_vowel_short, get_form_medial(root_l), "ְ")
        args = args or append_parts(char == "a" and char_vowel_open or reduce(char, chataf), get_form_medial(root_l))
    end
end

local function get_pres_stem_endings(args, root_l, char, chataf, use_elet, use_et)
    if root_l == "י" then
        args = args or "ֶה"
        args = args or ""
        if use_et then
            args = args or "ֵית"
        end
    else
        args = args or append_parts(char_vowel_open, get_form_final(root_l, char))
        args = args or append_parts(char == "a" and char_vowel_open or reduce(char, chataf), get_form_medial(root_l))
        if use_elet then
            args = args or get_elet_ending(root_l)
        end
    end
end

local function get_past_stem_endings(args, root_l, char, chataf, kca, use_e)
    if root_l == "א" then
        args = args or append_parts(kca and char_vowel_open or "ֵ", "א")
        args = args or append_parts(char_vowel_open, "א")
        args = args or append_parts(reduce(char, chataf), "א")
        args = args or append_parts(char == "a" and char_vowel_open or reduce(char, chataf), "א")
    elseif root_l == "י" then
        args = args or use_e and "ֵי" or "ִי"
        args = args or "ָה"
        args = args or append_parts(reduce("a", chataf), "ת")
        args = args or ""
    else
        args = args or append_parts(char_vowel_closed, get_form_medial(root_l), "ְ")
        args = args or append_parts(char_vowel_unstressed, get_form_medial(root_l), "ְ")
        args = args or append_parts(char_vowel, get_form_final(root_l, char))
        args = args or append_parts(reduce(char, chataf), get_form_medial(root_l))
        args = args or append_parts(char == "a" and char_vowel_open or reduce(char, chataf), get_form_medial(root_l))
    end
end

local function get_imp_stem_endings_gem(args, root_l, char)
    if root_l == "א" then
        args = args or append_parts(char == "a" and "ָ" or stressed_gem_vowel, "א")
        args = args or append_parts(char == "a" and "ָ" or stressed_gem_vowel, "א")
        args = args or append_parts(char ~= "u" and char ~= "o" and "ֶ" or stressed_gem_vowel, "א")
    else
        args = args or append_parts(stressed_gem_vowel, get_form_final(root_l, char))
        args = args or get_form_double(root_l, char, true, true)
        args = args or append_parts(gutturals and "ַ" or stressed_gem_vowel, get_form_medial(root_l), "ְ")
        args = args or get_form_double(root_l, char, true)
    end
end

local function get_fut_stem_endings_gem(args, root_l, char)
    if root_l == "א" then
        args = args or append_parts(char == "a" and "ָ" or stressed_gem_vowel, "א")
        args = args or get_form_double("א", char)
        args = args or append_parts(char ~= "u" and char ~= "o" and "ֶ" or stressed_gem_vowel, "א")
    else
        args = args or append_parts(stressed_gem_vowel, get_form_final(root_l, char))
        args = args or get_form_double(root_l, char, true, true)
        args = args or append_parts(gutturals and "ַ" or stressed_gem_vowel, get_form_medial(root_l), "ְ")
        args = args or get_form_double(root_l, char, true)
    end
end

local function get_pres_stem_endings_gem(args, root_l, char, short_a)
    if root_l == "א" then
        args = args or append_parts(char == "a" and "ָ" or stressed_gem_vowel, "א")
        args = args or get_form_double("א", char)
    else
        args = args or append_parts(char == "a" and (not short_a) and "ָ" or stressed_gem_vowel, get_form_final(root_l, char))
        args = args or get_form_double(root_l, char, true)
    end
end

local function get_past_stem_endings_gem(args, root_l, char)
    if root_l == "א" then
        args = args or append_parts(char == "a" and "ָ" or stressed_gem_vowel, "א")
        args = args or append_parts(char == "a" and "ָ" or stressed_gem_vowel, "א")
        args = args or get_form_double("א", char)
    else
        args = args or append_parts((char == "u" or char == "o") and {"ו", "ֹ"} or "ַ", get_form_medial(root_l), "ְ")
        args = args or append_parts((char == "u" or char == "o") and {"ו", "ָ"} or "ַ", get_form_medial(root_l), "ְ")
        args = args or append_parts(stressed_gem_vowel, get_form_final(root_l, char))
        args = args or get_form_double(root_l, char, true, true)
        args = args or get_form_double(root_l, char, true)
    end
end

get_stems_for = function(args, categories)
    local root_p = args
    local root_a = args
    local root_l = args

    if args ~= "-" then
        local past_char = args or "A"
        local fut_char = args or (root_a == "י" and "I") or "U"
        local imp_char = args or fut_char
        local inf_char = args or fut_char
        local pres_char = args or past_char
        local prefix_vowel = (fut_char == "O" and past_char == "O" and args ~= "-") and "ֵ" or "ָ"

        args = args or append_parts("ל", prefix_vowel, get_form_medial(root_p), char_vowel, get_form_final(root_l, inf_char))
        args = args or append_parts(get_form_initial(root_p), "ִי", get_form_medial(root_l), "ָה")

        args = args or get_form_initial(root_p)
        args = args or append_parts(prefix_vowel, get_form_medial(root_p))
        args = args or append_parts("ְ", get_form_medial(root_p))
        args = args or ""
        get_imp_stem_endings(args, root_l, imp_char, gutturals, true)
        get_fut_stem_endings(args, root_l, fut_char, gutturals)

        args = args or get_form_initial(root_p)
        get_pres_stem_endings(args, root_l, pres_char, gutturals, false, false)

        args = args or get_form_initial(root_p)
        get_past_stem_endings(args, root_l, past_char, gutturals, true, false)
    elseif false then
        -- reserved for special cases
    else
        local past_char = args or "a"
        local fut_char = args
        local imp_char = args
        local inf_char = args
        local pres_char = args

        local if_ = nil
        local ef_ = nil
        local suf_if_ = nil
        if args ~= "-" then
            fut_char = fut_char or ((args ~= "-" or gutturals) and "a") or "u"
            if_ = get_form_double(root_a, "i", true)
            ef_ = get_form_double(root_a, "e", true)
        elseif args ~= "-" then
            if root_p == "א" then
                fut_char = fut_char or "a"
                if_ = append_parts("ֹא", get_form_medial(root_a))
                ef_ = append_parts({"ו", "ֹ"}, get_form_medial(root_a))
            else
                fut_char = fut_char or (gutturals and root_l ~= "א" and "a") or "i"
                if_ = append_parts("ֵ", get_form_medial(root_a))
            end
        elseif monophthongize then
            fut_char = fut_char or "a"
            if_ = append_parts("ִי", get_form_medial(root_a))
        elseif gutturals then
            fut_char = fut_char or ((gutturals or gutturals) and "a") or "u"
            local v1 = (root_p == "א" or (root_l == "י" and root_p ~= "ע") or (root_l ~= "י" and fut_char == "a")) and "ֶ" or "ַ"
            if args then
                if root_a == "י" then v1 = "ִ" end
                if_ = append_parts(v1, get_form_medial(root_p), "ְ", get_form_initial(root_a))
                ef_ = append_parts("ֶ", get_form_medial(root_p), "ְ", get_form_initial(root_a))
            else
                local v2 = v1 == "ֶ" and "ֱ" or "ֲ"
                if_ = append_parts(v1, get_form_medial(root_p), v2, get_form_medial(root_a))
                ef_ = append_parts("ֶ", get_form_medial(root_p), "ֱ", get_form_medial(root_a))
                suf_if_ = append_parts(v1, get_form_medial(root_p), v1, get_form_medial(root_a))
            end
        else
            fut_char = fut_char or ((gutturals or gutturals) and "a") or "u"
            if_ = append_parts("ִ", get_form_medial(root_p), "ְ", get_form_initial(root_a))
            ef_ = append_parts("ֶ", get_form_medial(root_p), "ְ", get_form_initial(root_a))
        end

        local inf_if_ = nil
        local p_ = nil
        if args ~= "-" and root_p ~= "א" then
            inf_char = inf_char or "i"
            imp_char = imp_char or fut_char
            args = args or append_parts("לָ", get_form_medial(root_a), get_elet_ending(root_l))
            p_ = get_form_initial(root_a)
        elseif gutturals then
            inf_char = inf_char or "u"
            imp_char = imp_char or (root_p == "א" and args ~= "-" and (((gutturals or gutturals) and "a") or "u")) or fut_char
            local v1 = (root_p == "א" or (root_l ~= "י" and inf_char == "a")) and "ֶ" or "ַ"
            if args then
                if root_a == "י" then v1 = "ִ" end
                inf_if_ = append_parts(v1, get_form_medial(root_p), "ְ", get_form_initial(root_a))
            else
                local v2 = v1 == "ֶ" and "ֱ" or "ֲ"
                inf_if_ = append_parts(v1, get_form_medial(root_p), v2, get_form_medial(root_a))
            end
            p_ = append_parts(get_form_initial(root_p), root_p == "א" and "ֱ" or "ֲ", get_form_medial(root_a))
            if root_l ~= "י" and root_p == "א" and gutturals then
                args = args or append_parts(get_form_initial(root_p), "ֶ", get_form_medial(root_a))
                args = args or append_parts("ֱ", get_form_medial(root_l))
            end
        else
            inf_char = inf_char or "u"
            imp_char = imp_char or fut_char
            inf_if_ = if_
            p_ = append_parts(get_form_initial(root_p), shva_na(root_p), get_form_medial(root_a))
        end

        args = args or append_parts("ל", inf_if_, root_l == "י" and "וֹת" or append_parts(char_vowel, get_form_final(root_l, inf_char)))
        args = args or append_parts(get_form_initial(root_p), shva_na(root_p), get_form_medial(root_a), "ִי", root_l == "י" and "ּ" or get_form_medial(root_l), "ָה")
        args = args or append_parts(get_form_initial(root_p), "ָ", get_form_medial(root_a), "וּ", get_form_final(root_l, "U"))

        args = args or p_
        if root_l ~= "י" and (args == "-" or root_p == "א") then
            if gutturals then
                args = args or append_parts(get_form_initial(root_p), "ַ", get_form_medial(root_a))
                if imp_char ~= "u" and imp_char ~= "i" then
                    args = args or args
                end
                args = args or append_parts("ֲ", get_form_medial(root_l))
            else
                args = args or append_parts(get_form_initial(root_p), "ִ", get_form_medial(root_a))
            end
        end
        args = args or if_
        args = args or ef_
        if root_l ~= "י" then
            args = args or suf_if_
        end
        args = args or ""
        get_imp_stem_endings(args, root_l, imp_char, ends_in_guttural(root_a))
        get_fut_stem_endings(args, root_l, fut_char, ends_in_guttural(root_a))

        if args and args ~= "" then
            -- pa`el
            args = args or append_parts(get_form_initial(root_p), "ָ", get_form_medial(root_a))
            if root_l ~= "י" then
                args = args or append_parts(get_form_initial(root_p), shva_na(root_p), get_form_medial(root_a))
            end
            get_pres_stem_endings(args, root_l, pres_char or "E", ends_in_guttural(root_a), false, false)
        else
            -- po`el
            args = args or append_parts(get_form_initial(root_p), "וֹ", get_form_medial(root_a))
            get_pres_stem_endings(args, root_l, pres_char or "i", ends_in_guttural(root_a), true, false)
        end

        args = args or append_parts(get_form_initial(root_p), "ָ", get_form_medial(root_a))
        args = args or append_parts(get_form_initial(root_p), shva_na(root_p), get_form_medial(root_a))
        if past_char == "i" or past_char == "u" then
            args = args or append_parts(get_form_initial(root_p), gutturals and "ַ" or "ִ", get_form_medial(root_a))
        end
        get_past_stem_endings(args, root_l, past_char, ends_in_guttural(root_a), true, false)
    end
end

get_stems_for = function(args, categories)
    local root_p = args
    local root_a = args
    local root_l = args
    local past_char = args or "i"
    local fut_char = args or "i"
    local imp_char = args or fut_char
    local inf_char = args or fut_char
    local pres_char = args or "i"

    if false then
        -- reserved for special cases
    elseif false then
        -- reserved for special cases
    else
        args = args or append_parts("לְ", get_form_medial(root_p), get_form_double(root_a, "a"), root_l == "י" and "וֹת" or append_parts(char_vowel, get_form_final(root_l, inf_char)))
        args = args or append_parts(get_form_initial(root_p), get_form_double(root_a, "i"), "וּ", get_form_final(root_l, "U"))

        args = args or append_parts(get_form_initial(root_p), get_form_double(root_a, "a"))
        args = args or append_parts("ְ", get_form_medial(root_p), get_form_double(root_a, "a"))
        args = args or append_parts("ֲ", get_form_medial(root_p), get_form_double(root_a, "a"))
        args = args or ""
        get_imp_stem_endings(args, root_l, imp_char, ends_in_guttural(root_a))
        get_fut_stem_endings(args, root_l, fut_char, ends_in_guttural(root_a))

        args = args or append_parts("מְ", get_form_medial(root_p), get_form_double(root_a, "a"))
        get_pres_stem_endings(args, root_l, pres_char, ends_in_guttural(root_a), true, false)

        args = args or append_parts(get_form_initial(root_p), get_form_double(root_a, "i"))
        get_past_stem_endings(args, root_l, past_char, ends_in_guttural(root_a), false, false)
    end
end

get_stems_for = function(args, categories)
    local root_p = args
    local root_a = args == "-" and args or args
    local root_l = args
    local past_char = args or "i"
    local fut_char = args or "i"
    local imp_char = args or fut_char
    local inf_char = args or fut_char
    local pres_char = args or "i"

    if false then
        -- reserved for special cases
    elseif false then
        -- reserved for special cases
    else
        args = args or append_parts("לְ", get_form_medial(root_p), "וֹ", get_form_medial(root_a), root_l == "י" and "וֹת" or append_parts(char_vowel, get_form_final(root_l, inf_char)))
        -- args = args or append_parts(get_form_initial(root_p), "וֹ", get_form_medial(root_a), shva_na(root_a), get_form_medial(root_l), "וּת")
        args = args or append_parts(get_form_initial(root_p), "ִי", get_form_medial(root_a), "וּ", get_form_final(root_l, "U"))

        args = args or append_parts(get_form_initial(root_p), "וֹ", get_form_medial(root_a))
        args = args or append_parts("ְ", get_form_medial(root_p), "וֹ", get_form_medial(root_a))
        args = args or append_parts("ֲ", get_form_medial(root_p), "וֹ", get_form_medial(root_a))
        args = args or ""
        get_imp_stem_endings(args, root_l, imp_char, ends_in_guttural(root_a))
        get_fut_stem_endings(args, root_l, fut_char, ends_in_guttural(root_a))

        args = args or append_parts("מְ", get_form_medial(root_p), "וֹ", get_form_medial(root_a))
        get_pres_stem_endings(args, root_l, pres_char, ends_in_guttural(root_a), true, false)

        args = args or append_parts(get_form_initial(root_p), "וֹ", get_form_medial(root_a))
        get_past_stem_endings(args, root_l, past_char, ends_in_guttural(root_a), false, false)
    end
end

get_stems_for = function(args, categories)
    local root_p = args
    local root_a = args
    local root_l = args
    local past_char = args or "a"
    local fut_char = args or "a"
    local pres_char = args or "a"

    if false then
        -- reserved for special cases
    elseif false then
        -- reserved for special cases
    else
        args = args or "-"
        args = args or append_parts("ְ", get_form_medial(root_p), get_form_double(root_a, "u"))
        args = args or append_parts("ֲ", get_form_medial(root_p), get_form_double(root_a, "u"))
        args = args or ""
        get_fut_stem_endings(args, root_l, fut_char, ends_in_guttural(root_a))

        args = args or append_parts("מְ", get_form_medial(root_p), get_form_double(root_a, "u"))
        get_pres_stem_endings(args, root_l, pres_char, ends_in_guttural(root_a), true, false)

        args = args or append_parts(get_form_initial(root_p), get_form_double(root_a, "u"))
        get_past_stem_endings(args, root_l, past_char, ends_in_guttural(root_a), false, true)
    end
end

get_stems_for = function(args, categories)
    local root_p = args
    local root_a = args == "-" and args or args
    local root_l = args
    local past_char = args or "a"
    local fut_char = args or "a"
    local pres_char = args or "a"

    if false then
        -- reserved for special cases
    elseif false then
        -- reserved for special cases
    else
        args = args or "-"
        args = args or append_parts("ְ", get_form_medial(root_p), "וֹ", get_form_medial(root_a))
        args = args or append_parts("ֲ", get_form_medial(root_p), "וֹ", get_form_medial(root_a))
        args = args or ""
        get_fut_stem_endings(args, root_l, fut_char, ends_in_guttural(root_a))

        args = args or append_parts("מְ", get_form_medial(root_p), "וֹ", get_form_medial(root_a))
        get_pres_stem_endings(args, root_l, pres_char, ends_in_guttural(root_a), true, false)

        args = args or append_parts(get_form_initial(root_p), "וֹ", get_form_medial(root_a))
        get_past_stem_endings(args, root_l, past_char, ends_in_guttural(root_a), false, true)
    end
end

get_stems_for = function(args, categories)
    local root_p = args
    local root_a = args
    local root_l = args
    local past_char = args or args ~= "-" and "i" or "I"
    local fut_char = args or args ~= "-" and "i" or "I"
    local imp_char = args or fut_char
    local inf_char = args or fut_char
    local pres_char = args or args ~= "-" and "i" or "I"

    if args ~= "-" then
        args = args or append_parts("לְהָ", get_form_medial(root_p), char_vowel, get_form_final(root_l, inf_char))
        args = args or append_parts(gutturals and "הֶ" or "הֲ", get_form_medial(root_p), "ָ", get_form_medial(root_l), "ָה")

        args = args or append_parts("הָ", get_form_medial(root_p))
        args = args or append_parts("ָ", get_form_medial(root_p))
        args = args or append_parts(gutturals and "הַ" or "הֲ", get_form_medial(root_p))
        args = args or append_parts("ְ", get_form_medial(root_p))
        args = args or ""
        get_imp_stem_endings(args, root_l, imp_char, gutturals, false, true)
        get_fut_stem_endings(args, root_l, fut_char, gutturals)

        args = args or append_parts("מֵ", get_form_medial(root_p))
        args = args or append_parts("מְ", get_form_medial(root_p))
        get_pres_stem_endings(args, root_l, pres_char, gutturals, false, false)

        args = args or append_parts("הֵ", get_form_medial(root_p))
        args = args or append_parts(gutturals and "הַ" or "הֲ", get_form_medial(root_p))
        get_past_stem_endings(args, root_l, past_char, gutturals, false, true)
    elseif args ~= "-" then
        args = args or append_parts("לְהָ", get_form_medial(root_p), char_vowel, get_form_final(root_l, inf_char))
        --- args = args or append_parts(gutturals and (non_doubling_letters and "הֶ" or "הַ") or "הֲ", get_form_medial(root_p), get_form_double(root_l, "a", true), "ָה")
        args = args or append_parts(gutturals and "הֶ" or "הֲ", get_form_medial(root_p), "ָ", get_form_medial(root_l), "ָה")

        args = args or append_parts("הָ", get_form_medial(root_p))
        args = args or append_parts("ָ", get_form_medial(root_p))
        args = args or append_parts(gutturals and "הַ" or "הֲ", get_form_medial(root_p))
        args = args or append_parts("ְ", get_form_medial(root_p))
        args = args or ""
        get_imp_stem_endings_gem(args, root_l, imp_char)
        get_fut_stem_endings_gem(args, root_l, fut_char)

        args = args or append_parts("מֵ", get_form_medial(root_p))
        args = args or append_parts("מְ", get_form_medial(root_p))
        get_pres_stem_endings_gem(args, root_l, pres_char)

        args = args or append_parts("הֵ", get_form_medial(root_p))
        args = args or append_parts(gutturals and "הַ" or "הֲ", get_form_medial(root_p))
        get_past_stem_endings_gem(args, root_l, past_char)
    elseif false then
        -- reserved for special cases
    else
        local af_ = nil
        local if_ = nil
        if args ~= "-" then
            af_ = append_parts(gutturals and "ָ" or "ַ", add_dagesh(root_a))
            if_ = append_parts(gutturals and "ֵ" or "ִ", add_dagesh(root_a))
        elseif monophthongize then
            af_ = append_parts(monophthongize, get_form_medial(root_a))
            if_ = af_
        elseif gutturals then
            if args then
                af_ = append_parts("ַ", get_form_medial(root_p), "ְ", get_form_initial(root_a))
                if_ = append_parts("ֶ", get_form_medial(root_p), "ְ", get_form_initial(root_a))
            else
                af_ = append_parts("ַ", get_form_medial(root_p), "ֲ", get_form_medial(root_a))
                if_ = append_parts("ֶ", get_form_medial(root_p), "ֱ", get_form_medial(root_a))
            end
        else
            af_ = append_parts("ַ", get_form_medial(root_p), "ְ", get_form_initial(root_a))
            if_ = append_parts(root_a == "א" and root_l == "י" and "ֶ" or "ִ", get_form_medial(root_p), "ְ", get_form_initial(root_a))
        end

        args = args or append_parts("לְה", af_, root_l == "י" and "וֹת" or append_parts(char_vowel, get_form_final(root_l, inf_char)))
        args = args or append_parts("ה", af_, "ָ", get_form_medial(root_l), "ָה")

        args = args or append_parts("ה", af_)
        args = args or af_
        args = args or ""
        get_imp_stem_endings(args, root_l, imp_char, ends_in_guttural(root_a), false, args ~= "-")
        get_fut_stem_endings(args, root_l, fut_char, ends_in_guttural(root_a))

        args = args or append_parts("מ", af_)
        get_pres_stem_endings(args, root_l, pres_char, ends_in_guttural(root_a), false, false)

        args = args or append_parts("ה", if_)
        get_past_stem_endings(args, root_l, past_char, ends_in_guttural(root_a), false, true)
    end
end

get_stems_for = function(args, categories)
    local root_p = args
    local root_a = args
    local root_l = args
    local past_char = args or "a"
    local fut_char = args or "a"
    local pres_char = args or "a"

    if args ~= "-" then
        args = args or "-"
        args = args or append_parts("וּ", get_form_medial(root_p))
        args = args or ""
        get_fut_stem_endings(args, root_l, fut_char, gutturals)

        args = args or append_parts("מוּ", get_form_medial(root_p))
        get_pres_stem_endings(args, root_l, pres_char, gutturals, true, true)

        args = args or append_parts("הוּ", get_form_medial(root_p))
        get_past_stem_endings(args, root_l, past_char, gutturals, false, true)
    elseif args ~= "-" then
        args = args or "-"
        args = args or append_parts("וּ", get_form_medial(root_p))
        args = args or ""
        get_fut_stem_endings_gem(args, root_l, fut_char)

        args = args or append_parts("מוּ", get_form_medial(root_p))
        get_pres_stem_endings_gem(args, root_l, pres_char)

        args = args or append_parts("הוּ", get_form_medial(root_p))
        get_past_stem_endings_gem(args, root_l, past_char)
    elseif false then
        -- reserved for special cases
    else
        local uf_ = nil
        if args ~= "-" then
            uf_ = append_parts({"ו", "ֻ"}, add_dagesh(root_a))
        elseif monophthongize then
            uf_ = append_parts("וּ", get_form_medial(root_a))
        elseif gutturals then
            if args then
                uf_ = append_parts({"ו", "ֻ"}, get_form_medial(root_p), "ְ", get_form_initial(root_a))
            else
                uf_ = append_parts({"ו", "ָ"}, get_form_medial(root_p), "ֳ", get_form_medial(root_a))
            end
        else
            uf_ = append_parts({"ו", "ֻ"}, get_form_medial(root_p), "ְ", get_form_initial(root_a))
        end

        args = args or "-"
        args = args or uf_
        args = args or ""
        get_fut_stem_endings(args, root_l, fut_char, ends_in_guttural(root_a))

        args = args or append_parts("מ", uf_)
        get_pres_stem_endings(args, root_l, pres_char, ends_in_guttural(root_a), true, true)

        args = args or append_parts("ה", uf_)
        get_past_stem_endings(args, root_l, past_char, ends_in_guttural(root_a), false, true)
    end
end

get_stems_for = function(args, categories)
    local root_p = args
    local root_a = args
    local root_l = args
    local past_char = args or "a"
    local fut_char = args or gutturals and root_l ~= "א" and "a" or "i"
    local imp_char = args or fut_char
    local inf_char = args or fut_char
    local pres_char = args or "a"

    if false then
        -- reserved for special cases
    elseif false then
        -- reserved for special cases
    else
        local if_ = nil
        local suf_if_ = nil
        if args ~= "-" then
            if_ = get_form_double(root_a, "i")
        elseif monophthongize then
            if_ = append_parts(monophthongize, get_form_medial(root_a))
        elseif gutturals then
            local v1 = root_p == "ע" and root_l == "י" and "ַ" or "ֶ"
            if args then
                if_ = append_parts(v1, get_form_medial(root_p), "ְ", get_form_initial(root_a))
            else
                local v2 = v1 == "ַ" and "ֲ" or "ֱ"
                if_ = append_parts(v1, get_form_medial(root_p), v2, get_form_medial(root_a))
                suf_if_ = append_parts(v1, get_form_medial(root_p), v1, get_form_medial(root_a))
            end
        else
            if_ = append_parts("ִ", get_form_medial(root_p), "ְ", get_form_initial(root_a))
        end

        args = args or append_parts("לְה", get_form_double(root_p, "i", true), "ָ", get_form_medial(root_a), root_l == "י" and "וֹת" or append_parts(char_vowel, get_form_final(root_l, inf_char)))
        if root_l == "י" then
            args = args or append_parts("ה", get_form_double(root_p, "i", true), "ָ", get_form_medial(root_a), "וּת")
        else
            args = args or append_parts("ה", get_form_double(root_p, "i", true), "ָ", get_form_medial(root_a), shva_na(root_a), get_form_medial(root_l), "וּת")
        end

        args = args or append_parts("ה", get_form_double(root_p, "i", true), "ָ", get_form_medial(root_a))
        args = args or append_parts(get_form_double(root_p, "i", true), "ָ", get_form_medial(root_a))
        args = args or append_parts(get_form_double(root_p, "e", true), "ָ", get_form_medial(root_a))
        args = args or ""
        get_imp_stem_endings(args, root_l, imp_char, ends_in_guttural(root_a))
        get_fut_stem_endings(args, root_l, fut_char, ends_in_guttural(root_a))

        args = args or append_parts("נ", if_)
        get_pres_stem_endings(args, root_l, pres_char, ends_in_guttural(root_a), true, true)

        args = args or append_parts("נ", if_)
        if suf_if_ then
            local pres_stem_name = root_l == "י" and "past_3fs_pre_stem" or "past_3_pre_stem"
            args = args or append_parts("נ", suf_if_)
        end
        get_past_stem_endings(args, root_l, past_char, ends_in_guttural(root_a), false, true)
    end
end

get_stems_for = function(args, categories)
    local itp = get_form_itp(args)
    local etp = get_form_etp(args)
    local root_a = args
    local root_l = args
    local past_char = args or "i"
    local fut_char = args or "i"
    local imp_char = args or fut_char
    local inf_char = args or fut_char
    local pres_char = args or "i"

    if false then
        -- reserved for special cases
    elseif false then
        -- reserved for special cases
    else
        args = args or append_parts("לְהִ", itp, get_form_double(root_a, "a"), root_l == "י" and "וֹת" or append_parts(char_vowel, get_form_final(root_l, inf_char)))
        if root_l == "י" then
            args = args or append_parts("הִ", itp, get_form_double(root_a, "a"), "וּת")
        else
            args = args or append_parts("הִ", itp, get_form_double(root_a, "a"), shva_na(root_a), get_form_medial(root_l), "וּת")
        end

        args = args or append_parts("הִ", itp, get_form_double(root_a, "a"))
        args = args or append_parts("ִ", itp, get_form_double(root_a, "a"))
        args = args or append_parts("ֶ", etp, get_form_double(root_a, "a"))
        args = args or ""
        get_imp_stem_endings(args, root_l, imp_char, ends_in_guttural(root_a))
        get_fut_stem_endings(args, root_l, fut_char, ends_in_guttural(root_a))

        args = args or append_parts("מִ", itp, get_form_double(root_a, "a"))
        get_pres_stem_endings(args, root_l, pres_char, ends_in_guttural(root_a), true, false)

        args = args or append_parts("הִ", itp, get_form_double(root_a, "a"))
        get_past_stem_endings(args, root_l, past_char, ends_in_guttural(root_a), false, true)
    end
end

get_stems_for = function(args, categories)
    local itp = get_form_itp(args)
    local etp = get_form_etp(args)
    local root_a = args == "-" and args or args
    local root_l = args
    local past_char = args or "i"
    local fut_char = args or "i"
    local imp_char = args or fut_char
    local inf_char = args or fut_char
    local pres_char = args or "i"

    if false then
        -- reserved for special cases
    elseif false then
        -- reserved for special cases
    else
        args = args or append_parts("לְהִ", itp, "וֹ", get_form_medial(root_a), root_l == "י" and "וֹת" or append_parts(char_vowel, get_form_final(root_l, inf_char)))
        if root_l == "י" then
            args = args or append_parts("הִ", itp, "וֹ", get_form_medial(root_a), "וּת")
        else
            args = args or append_parts("הִ", itp, "וֹ", get_form_medial(root_a), shva_na(root_a), get_form_medial(root_l), "וּת")
        end

        args = args or append_parts("הִ", itp, "וֹ", get_form_medial(root_a))
        args = args or append_parts("ִ", itp, "וֹ", get_form_medial(root_a))
        args = args or append_parts("ֶ", etp, "וֹ", get_form_medial(root_a))
        args = args or ""
        get_imp_stem_endings(args, root_l, imp_char, ends_in_guttural(root_a))
        get_fut_stem_endings(args, root_l, fut_char, ends_in_guttural(root_a))

        args = args or append_parts("מִ", itp, "וֹ", get_form_medial(root_a))
        get_pres_stem_endings(args, root_l, pres_char, ends_in_guttural(root_a), true, false)

        args = args or append_parts("הִ", itp, "וֹ", get_form_medial(root_a))
        get_past_stem_endings(args, root_l, past_char, ends_in_guttural(root_a), false, true)
    end
end

get_stems_for = function(args, categories)
    error("Binyan hitpu`al is not yet implemented.")
end

local form_names = {
         = true,
         = true,
         = true,

         = true,
         = true,
         = true,
         = true,

         = true,
         = true,
         = true,
         = true,
         = true,
         = true,
         = true,
         = true,
         = true,
         = true,

         = true,
         = true,
         = true,
         = true,
         = true,
         = true,
         = true,
         = true,
         = true,
         = true,

         = true,
         = true,
         = true,
         = true,
}

local optional_forms = {
         = true,
         = true,
         = true,
}

local table_template = [===[<div>
<div class="NavFrame" style="display:inline-block">
<div class="NavHead" align="left">{heading}&emsp;</div>
<div class="NavContent" align="center">
{\op}| border="1" color="#cdcdcd" style="width:100%;border-collapse:collapse;line-height:2em;border:2px solid #000000;background:#fdfdfd;text-align:center" class="inflection-table"
! scope='row' colspan="2" style="background:#E4C0CF;border-right:2px solid" | non-finite forms
| colspan="4" style="text-align:left" |
{non_finite}
|- style="border-top:2px solid"
! colspan="2" rowspan="2" style="background:#E4C0CF;border-right:2px solid" | finite forms
! scope='col' colspan="2" style="background:#C0CFE4" | singular
! scope='col' colspan="2" style="background:#C0CFE4" | plural
|-
! scope='col' style="background:#C0CFE4" | m.
! scope='col' style="background:#C0CFE4" | f.
! scope='col' style="background:#C0CFE4" | m.
! scope='col' style="background:#C0CFE4" | f.
|- style="border-top:2px solid"
! scope='row' rowspan="3" style="background:#E2E4C0;width:1px" | past
! scope='row' style="background:#C0CFE4;border-right:2px solid;width:1px" | first
| colspan="2" | {past_1s} || colspan="2" | {past_1p}
|-
! scope='row' style="background:#C0CFE4;border-right:2px solid" | second
| {past_2ms} || {past_2fs} || {past_2mp}{2p_tag} || {past_2fp}{2p_tag}
|-
! scope='row' style="background:#C0CFE4;border-right:2px solid" | third
| {past_3ms} || {past_3fs} || colspan="2" | {past_3mp}
|- style="border-top:2px solid"
! scope='row' colspan="2" style="background:#E2E4C0;border-right:2px solid" | present
| {pres_ms} || {pres_fs} || {pres_mp} || {pres_fp}
|- style="border-top:2px solid"
! scope='row' rowspan="3" style="background:#E2E4C0" | future
! scope='row' style="background:#C0CFE4;border-right:2px solid" | first
| colspan="2" | {fut_1s} || colspan="2" | {fut_1p}
|-
! scope='row' style="background:#C0CFE4;border-right:2px solid" | second
| {fut_2ms} || {fut_2fs} || {fut_2mp} || {fut_2fp}{fp_tag}
|-
! scope='row' style="background:#C0CFE4;border-right:2px solid" | third
| {fut_3ms} || {fut_3fs} || {fut_3mp} || {fut_3fp}{fp_tag}
|- style="border-top:2px solid"
! scope='row' colspan="2" style="background:#E2E4C0;border-right:2px solid" | imperative
| {imp_ms} || {imp_fs} || {imp_mp} || {imp_fp}{fp_tag}
|- style="border-top:2px solid"
! scope='row' colspan="2" style="background:#E4C0CF;border-right:2px solid" | notes
| colspan="4" style="text-align:left;word-wrap:break-word;width:1px;padding-right:1em" |
{notes}
|{\cl}
</div></div></div>]===]

local non_finite = {
     = "* '''to-infinitive:''' {inf}\n",
     = "* '''action noun:''' {noun}\n",
     = "* '''passive participle:''' {pp}\n",
}

local function make_table(args)
    for key, _ in pairs(form_names) do
        args = args and gen_link(args) or (not optional_forms) and "—"
    end
    args = m_strutils.format(non_finite, args)
    if args then
        args = args .. m_strutils.format(non_finite, args)
    end
    if args then
        args = args .. m_strutils.format(non_finite, args)
    end
    return m_strutils.format(table_template, args)
end

local function track(binyan, args)
    local sub = nil
    local hollow = args ~= "-"
    local assim = args ~= "-"
    local elide = args ~= "-" and binyan == "pa" -- elide is only relevant to pa`al I think
    local geminate = args ~= "-"
    if binyan == "pa" or binyan == "nif" or binyan == "hif" or binyan == "huf" then
        if hollow then
            if assim or elide or geminate then
                sub = "?"
            else
                sub = "hollow"
            end
        elseif elide then
            if geminate then
                sub = "?"
            elseif assim then
                sub = "assim+elide"
            else
                sub = "elide"
            end
        elseif geminate then
            if assim then
                sub = "geminate+assim"
            else
                sub = "geminate"
            end
        elseif assim then
            sub = "assim"
        end
    end
    local m_debug = require('Module:debug')
    m_debug.track("he-conj/" .. binyan .. (sub and ("/" .. sub) or ""))
    if sub == "?" then
        m_debug.track("he-conj/incompatible-combination")
    end
    if args and args ~= "-" then
        m_debug.track("he-conj/past_long")
    end
    if args and args ~= "-" then
        m_debug.track("he-conj/fp_long")
    end
end

local function track_page(lemma)
    local namespace = mw.title.getCurrentTitle().nsText
    if namespace == "" then
        local pagename = mw.title.getCurrentTitle().text

        local is_table = (type(lemma) == "table")
        local male = (lang:makeEntryName(is_table and lemma or lemma))

        if pagename ~= male then
            local haser = (lang:makeEntryName(is_table and lemma or lemma))

            local m_debug = require('Module:debug')
            if pagename ~= haser then
                m_debug.track("he-conj/not_at_lemma")
            else
                m_debug.track("he-conj/at_haser_spelling")
            end
        end
    end
end

-- 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 or frame.args 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_root(args)
    convert_root(args)

    local root_p = args
    local root_a = args
    local root_l = args

    if not (root_p and root_a and root_l) then
        error("Missing root letters.")
    end

    args = args or ((root_a == "י" or root_a == "ו") and root_l ~= "י" and "+") or "-"
    args = args or ((root_a == root_l) and root_l ~= "י" and "+") or "-"
    args = args or (args == "-" and args == "-" and root_p == "נ" and not gutturals and "+") or "-"
    args = args or (args and (args ~= "-" == "-" or root_p == "י" or root_p == "ו") and root_l ~= "י" and "+") or "-"

    track(binyan, args)

    if binyan == "-" then
        -- do nothing, stems are given explicitly
    elseif get_stems_for then
        get_stems_for(args, categories)
    else
        error("Unknown binyan code '" .. binyan .. "'")
    end

    conjugate(args) -- finishes conjugation based on stems from get_stems_for

    local pre_notes = ""
    if args and not equal(args, args) then
        args = "<sup>1</sup>"
        args = "<sup>2</sup>"
        pre_notes = pre_notes .. "# Pronounced " .. gen_link(args) .. " and " .. gen_link(args) .. " in informal Modern Hebrew.\n# Rare in Modern Hebrew.\n"
    else
        args = ""
        args = "<sup>1</sup>"
        pre_notes = pre_notes .. "# Rare in Modern Hebrew.\n"
    end
    args = pre_notes .. (args or "")

    if args or "" ~= "" then
        return make_bot_list(forms, sep ~= "")
    else
        track_page(args)
        return make_table(args, title) .. m_utilities.format_categories(categories, lang)
    end
end

return export