571 lines
24 KiB
EmacsLisp
571 lines
24 KiB
EmacsLisp
// morphology-egy.el - Ancient Egyptian (Middle Egyptian) morphology for the NLG engine.
|
||
//
|
||
// Implements Middle Egyptian verb conjugation (sdm=f / sdm.n=f paradigm),
|
||
// noun number marking, suffix pronouns, and noun phrase assembly.
|
||
// Designed as a companion to morphology.el; called when language code is "egy".
|
||
//
|
||
// Language profile: code=egy, name=Ancient Egyptian, morph_type=agglutinative,
|
||
// word_order=SVO (Middle Egyptian nominal sentences), question_strategy=particle,
|
||
// script=hieroglyphic (transliterated here as ASCII), family=afro-asiatic-egyptian.
|
||
//
|
||
// Script note: Classical transliteration uses special characters (ꜣ ꜥ ḥ ḫ ẖ š q ṯ ḏ).
|
||
// This engine uses a safe ASCII mapping:
|
||
// A = ꜣ (aleph/glottal stop) a = ꜥ (ayin)
|
||
// H = ḥ (h with dot) x = ḫ (velar fricative)
|
||
// X = ẖ (emphatic h) sh = š (sh sound)
|
||
// q = q (emphatic k) T = ṯ (tj sound)
|
||
// D = ḏ (dj sound)
|
||
// This mapping keeps all string literals ASCII-safe for the El runtime.
|
||
//
|
||
// Grammatical notes (Middle Egyptian, ca. 2000–1300 BCE):
|
||
// - Aspectual system: Imperfective (sdm=f), Perfective (sdm.n=f), Prospective
|
||
// - "tense" labels used here: "present" (imperfective), "past" (perfective),
|
||
// "future" (prospective/sdm.xr=f), "infinitive"
|
||
// - Two grammatical genders: masculine (unmarked) and feminine (suffix -t)
|
||
// - Number: singular (unmarked), dual (-wy masc / -ty fem), plural (-w masc / -wt fem)
|
||
// - No case endings — syntactic role expressed by word order and prepositions
|
||
// - No definite/indefinite article in Middle Egyptian (Late Egyptian introduced pꜣ/tꜣ/nꜣ)
|
||
// - Zero copula: adjectival predicates need no verb "to be" ("nfr sw" = "he is good")
|
||
// - Suffix pronouns attach directly to the verb stem with = (e.g. sdm=f "he hears")
|
||
//
|
||
// Persons/numbers covered (suffix pronoun paradigm):
|
||
// person: "first" | "second" | "third"
|
||
// gender: "m" | "f" (relevant for 2sg, 3sg; 1sg and plurals often unmarked)
|
||
// number: "singular" | "dual" | "plural"
|
||
//
|
||
// Verbs covered (ASCII transliteration → gloss):
|
||
// wnn — to be/exist (copular auxiliary)
|
||
// rdi / di — to give
|
||
// mAA — to see
|
||
// Dd — to say
|
||
// Sm — to go
|
||
// iri — to do / make
|
||
// sdm — to hear (the paradigm verb for the sdm=f construction)
|
||
//
|
||
// Canonical English → Egyptian mapping:
|
||
// "be" → wnn / zero copula "give" → rdi
|
||
// "see" → mAA "say" → Dd
|
||
// "go" → Sm "do" → iri
|
||
// "make" → iri "hear" → sdm
|
||
//
|
||
// Depends on: morphology.el (str_eq, str_len, str_slice, str_ends_with)
|
||
|
||
// ── String helpers ──────────────────────────────────────────────────────────────
|
||
|
||
fn egy_str_ends(s: String, suf: String) -> Bool {
|
||
return str_ends_with(s, suf)
|
||
}
|
||
|
||
fn egy_str_len(s: String) -> Int {
|
||
return str_len(s)
|
||
}
|
||
|
||
fn egy_drop(s: String, n: Int) -> String {
|
||
let len: Int = str_len(s)
|
||
if n >= len { return "" }
|
||
return str_slice(s, 0, len - n)
|
||
}
|
||
|
||
fn egy_last_char(s: String) -> String {
|
||
let n: Int = str_len(s)
|
||
if n == 0 { return "" }
|
||
return str_slice(s, n - 1, n)
|
||
}
|
||
|
||
// ── Person/number slot ──────────────────────────────────────────────────────────
|
||
//
|
||
// Maps person × gender × number to a 0-based index used in paradigm tables.
|
||
// Egyptian suffix pronouns distinguish gender in 2nd and 3rd person singular.
|
||
//
|
||
// Slot layout:
|
||
// 0 = 1sg (=i)
|
||
// 1 = 2sg masc (=k)
|
||
// 2 = 2sg fem (=T)
|
||
// 3 = 3sg masc (=f)
|
||
// 4 = 3sg fem (=s)
|
||
// 5 = 1pl (=n)
|
||
// 6 = 2pl (=Tn)
|
||
// 7 = 3pl (=sn)
|
||
// 8 = 1du / 2du / 3du (=sny — simplified; dual pronouns are rare in sources)
|
||
//
|
||
// Dual falls through to slot 8 (a single dual pronoun slot for all persons).
|
||
|
||
fn egy_slot(person: String, number: String) -> Int {
|
||
if str_eq(number, "dual") { return 8 }
|
||
if str_eq(person, "first") {
|
||
if str_eq(number, "plural") { return 5 }
|
||
return 0
|
||
}
|
||
if str_eq(person, "second") {
|
||
if str_eq(number, "plural") { return 6 }
|
||
return 1
|
||
}
|
||
// third person
|
||
if str_eq(number, "plural") { return 7 }
|
||
return 3
|
||
}
|
||
|
||
// egy_slot_with_gender: slot variant that factors in gender for 2sg and 3sg.
|
||
|
||
fn egy_slot_with_gender(person: String, gender: String, number: String) -> Int {
|
||
if str_eq(number, "dual") { return 8 }
|
||
if str_eq(person, "first") {
|
||
if str_eq(number, "plural") { return 5 }
|
||
return 0
|
||
}
|
||
if str_eq(person, "second") {
|
||
if str_eq(number, "plural") { return 6 }
|
||
if str_eq(gender, "f") { return 2 }
|
||
return 1
|
||
}
|
||
// third person
|
||
if str_eq(number, "plural") { return 7 }
|
||
if str_eq(gender, "f") { return 4 }
|
||
return 3
|
||
}
|
||
|
||
// ── Suffix pronouns ─────────────────────────────────────────────────────────────
|
||
//
|
||
// Egyptian suffix pronouns attach to verbs, nouns, and prepositions.
|
||
// Written with = before the pronoun in transliteration (e.g. =f = "his / he").
|
||
//
|
||
// Standard Middle Egyptian paradigm:
|
||
// 1sg: =i ("I / me / my")
|
||
// 2sg m: =k ("you / your" masc)
|
||
// 2sg f: =T ("you / your" fem, ṯ in classical)
|
||
// 3sg m: =f ("he / him / his")
|
||
// 3sg f: =s ("she / her")
|
||
// 1pl: =n ("we / us / our")
|
||
// 2pl: =Tn ("you all / your" plural)
|
||
// 3pl: =sn ("they / them / their")
|
||
// dual: =sny (simplified dual — rare in Middle Egyptian texts)
|
||
|
||
fn egy_conjugate_pronoun(person: String, number: String) -> String {
|
||
let slot: Int = egy_slot(person, number)
|
||
if slot == 0 { return "=i" }
|
||
if slot == 1 { return "=k" }
|
||
if slot == 5 { return "=n" }
|
||
if slot == 6 { return "=Tn" }
|
||
if slot == 7 { return "=sn" }
|
||
if slot == 8 { return "=sny" }
|
||
// slots 2–4 need gender; default to masc for slot 3
|
||
return "=f"
|
||
}
|
||
|
||
fn egy_suffix_pronoun(slot: Int) -> String {
|
||
if slot == 0 { return "=i" }
|
||
if slot == 1 { return "=k" }
|
||
if slot == 2 { return "=T" }
|
||
if slot == 3 { return "=f" }
|
||
if slot == 4 { return "=s" }
|
||
if slot == 5 { return "=n" }
|
||
if slot == 6 { return "=Tn" }
|
||
if slot == 7 { return "=sn" }
|
||
// dual (slot 8)
|
||
return "=sny"
|
||
}
|
||
|
||
// ── Copula detection ────────────────────────────────────────────────────────────
|
||
//
|
||
// In Middle Egyptian the verb "to be" as predicate is often omitted in the
|
||
// present (zero copula for adjective predicates). The auxiliary wnn is used
|
||
// for existence / substantive "to be" and in subordinate clauses.
|
||
// Canonical English label "be" maps to zero copula in the present.
|
||
|
||
fn egy_is_copula(verb: String) -> Bool {
|
||
if str_eq(verb, "wnn") { return true }
|
||
if str_eq(verb, "be") { return true }
|
||
return false
|
||
}
|
||
|
||
// ── Copula conjugation ──────────────────────────────────────────────────────────
|
||
//
|
||
// Present ("imperfective"): zero copula for adjectival predicate — return "".
|
||
// The auxiliary iw...wnn is used in certain syntactic environments but the
|
||
// bare zero is the canonical Middle Egyptian form.
|
||
// Past ("perfective"): wnn.n (with perfective suffix .n)
|
||
// Future ("prospective"): wnn.xr (prospective form, simplified)
|
||
|
||
fn egy_conjugate_copula(tense: String, slot: Int) -> String {
|
||
if str_eq(tense, "present") { return "" }
|
||
if str_eq(tense, "past") {
|
||
return "wnn.n" + egy_suffix_pronoun(slot)
|
||
}
|
||
if str_eq(tense, "future") {
|
||
return "wnn.xr" + egy_suffix_pronoun(slot)
|
||
}
|
||
if str_eq(tense, "infinitive") { return "wnn" }
|
||
// Default: zero copula
|
||
return ""
|
||
}
|
||
|
||
// ── Irregular verb: rdi / di (to give) ─────────────────────────────────────────
|
||
//
|
||
// rdi is the full form; di is the common abbreviated written form.
|
||
// Imperfective (present): di=f (3sg m), with full pronoun for other persons.
|
||
// Perfective (past): di.n=f
|
||
// Prospective (future): di.xr=f
|
||
// Infinitive: rdi
|
||
|
||
fn egy_rdi_present(slot: Int) -> String {
|
||
return "di" + egy_suffix_pronoun(slot)
|
||
}
|
||
|
||
fn egy_rdi_past(slot: Int) -> String {
|
||
return "di.n" + egy_suffix_pronoun(slot)
|
||
}
|
||
|
||
fn egy_rdi_future(slot: Int) -> String {
|
||
return "di.xr" + egy_suffix_pronoun(slot)
|
||
}
|
||
|
||
// ── Irregular verb: mAA (to see) ───────────────────────────────────────────────
|
||
//
|
||
// mAA is a geminated root (m-AA).
|
||
// Present: mAA=f; Past: mAA.n=f; Future: mAA.xr=f
|
||
|
||
fn egy_mAA_present(slot: Int) -> String {
|
||
return "mAA" + egy_suffix_pronoun(slot)
|
||
}
|
||
|
||
fn egy_mAA_past(slot: Int) -> String {
|
||
return "mAA.n" + egy_suffix_pronoun(slot)
|
||
}
|
||
|
||
fn egy_mAA_future(slot: Int) -> String {
|
||
return "mAA.xr" + egy_suffix_pronoun(slot)
|
||
}
|
||
|
||
// ── Irregular verb: Dd (to say) ─────────────────────────────────────────────────
|
||
//
|
||
// Present: Dd=f; Past: Dd.n=f; Future: Dd.xr=f
|
||
// Infinitive: Dd
|
||
|
||
fn egy_Dd_present(slot: Int) -> String {
|
||
return "Dd" + egy_suffix_pronoun(slot)
|
||
}
|
||
|
||
fn egy_Dd_past(slot: Int) -> String {
|
||
return "Dd.n" + egy_suffix_pronoun(slot)
|
||
}
|
||
|
||
fn egy_Dd_future(slot: Int) -> String {
|
||
return "Dd.xr" + egy_suffix_pronoun(slot)
|
||
}
|
||
|
||
// ── Irregular verb: Sm (to go) ─────────────────────────────────────────────────
|
||
//
|
||
// Present: Sm=f; Past: Sm.n=f; Future: Sm.xr=f
|
||
// (Note: the verb Smt "to go" appears in texts; Sm is the most common short form.)
|
||
|
||
fn egy_Sm_present(slot: Int) -> String {
|
||
return "Sm" + egy_suffix_pronoun(slot)
|
||
}
|
||
|
||
fn egy_Sm_past(slot: Int) -> String {
|
||
return "Sm.n" + egy_suffix_pronoun(slot)
|
||
}
|
||
|
||
fn egy_Sm_future(slot: Int) -> String {
|
||
return "Sm.xr" + egy_suffix_pronoun(slot)
|
||
}
|
||
|
||
// ── Irregular verb: iri (to do / make) ─────────────────────────────────────────
|
||
//
|
||
// iri has a contracted 3-radical stem ir- before pronouns.
|
||
// Present: ir=f; Past: ir.n=f; Future: ir.xr=f
|
||
// Infinitive: iri
|
||
|
||
fn egy_iri_present(slot: Int) -> String {
|
||
return "ir" + egy_suffix_pronoun(slot)
|
||
}
|
||
|
||
fn egy_iri_past(slot: Int) -> String {
|
||
return "ir.n" + egy_suffix_pronoun(slot)
|
||
}
|
||
|
||
fn egy_iri_future(slot: Int) -> String {
|
||
return "ir.xr" + egy_suffix_pronoun(slot)
|
||
}
|
||
|
||
// ── Regular verb: sdm (to hear) ────────────────────────────────────────────────
|
||
//
|
||
// sdm (to hear) is the paradigm verb used in grammar textbooks to illustrate
|
||
// all Egyptian verb forms. The sdm=f construction names the imperfective suffix
|
||
// verb pattern itself.
|
||
// Present: sdm=f; Past: sdm.n=f; Future: sdm.xr=f
|
||
// Infinitive: sdm
|
||
|
||
fn egy_sdm_present(slot: Int) -> String {
|
||
return "sdm" + egy_suffix_pronoun(slot)
|
||
}
|
||
|
||
fn egy_sdm_past(slot: Int) -> String {
|
||
return "sdm.n" + egy_suffix_pronoun(slot)
|
||
}
|
||
|
||
fn egy_sdm_future(slot: Int) -> String {
|
||
return "sdm.xr" + egy_suffix_pronoun(slot)
|
||
}
|
||
|
||
// ── Known-verb dispatcher ───────────────────────────────────────────────────────
|
||
//
|
||
// Returns the inflected form for a known verb, or "" if unknown.
|
||
// Accepts both canonical English labels and Egyptian transliterations.
|
||
|
||
fn egy_known_verb(verb: String, tense: String, slot: Int) -> String {
|
||
// ── rdi / di — to give ───────────────────────────────────────────────────────
|
||
if str_eq(verb, "rdi") {
|
||
if str_eq(tense, "present") { return egy_rdi_present(slot) }
|
||
if str_eq(tense, "past") { return egy_rdi_past(slot) }
|
||
if str_eq(tense, "future") { return egy_rdi_future(slot) }
|
||
if str_eq(tense, "infinitive") { return "rdi" }
|
||
return egy_rdi_present(slot)
|
||
}
|
||
if str_eq(verb, "di") {
|
||
if str_eq(tense, "present") { return egy_rdi_present(slot) }
|
||
if str_eq(tense, "past") { return egy_rdi_past(slot) }
|
||
if str_eq(tense, "future") { return egy_rdi_future(slot) }
|
||
if str_eq(tense, "infinitive") { return "rdi" }
|
||
return egy_rdi_present(slot)
|
||
}
|
||
if str_eq(verb, "give") {
|
||
if str_eq(tense, "present") { return egy_rdi_present(slot) }
|
||
if str_eq(tense, "past") { return egy_rdi_past(slot) }
|
||
if str_eq(tense, "future") { return egy_rdi_future(slot) }
|
||
if str_eq(tense, "infinitive") { return "rdi" }
|
||
return egy_rdi_present(slot)
|
||
}
|
||
|
||
// ── mAA — to see ─────────────────────────────────────────────────────────────
|
||
if str_eq(verb, "mAA") {
|
||
if str_eq(tense, "present") { return egy_mAA_present(slot) }
|
||
if str_eq(tense, "past") { return egy_mAA_past(slot) }
|
||
if str_eq(tense, "future") { return egy_mAA_future(slot) }
|
||
if str_eq(tense, "infinitive") { return "mAA" }
|
||
return egy_mAA_present(slot)
|
||
}
|
||
if str_eq(verb, "see") {
|
||
if str_eq(tense, "present") { return egy_mAA_present(slot) }
|
||
if str_eq(tense, "past") { return egy_mAA_past(slot) }
|
||
if str_eq(tense, "future") { return egy_mAA_future(slot) }
|
||
if str_eq(tense, "infinitive") { return "mAA" }
|
||
return egy_mAA_present(slot)
|
||
}
|
||
|
||
// ── Dd — to say ──────────────────────────────────────────────────────────────
|
||
if str_eq(verb, "Dd") {
|
||
if str_eq(tense, "present") { return egy_Dd_present(slot) }
|
||
if str_eq(tense, "past") { return egy_Dd_past(slot) }
|
||
if str_eq(tense, "future") { return egy_Dd_future(slot) }
|
||
if str_eq(tense, "infinitive") { return "Dd" }
|
||
return egy_Dd_present(slot)
|
||
}
|
||
if str_eq(verb, "say") {
|
||
if str_eq(tense, "present") { return egy_Dd_present(slot) }
|
||
if str_eq(tense, "past") { return egy_Dd_past(slot) }
|
||
if str_eq(tense, "future") { return egy_Dd_future(slot) }
|
||
if str_eq(tense, "infinitive") { return "Dd" }
|
||
return egy_Dd_present(slot)
|
||
}
|
||
|
||
// ── Sm — to go ───────────────────────────────────────────────────────────────
|
||
if str_eq(verb, "Sm") {
|
||
if str_eq(tense, "present") { return egy_Sm_present(slot) }
|
||
if str_eq(tense, "past") { return egy_Sm_past(slot) }
|
||
if str_eq(tense, "future") { return egy_Sm_future(slot) }
|
||
if str_eq(tense, "infinitive") { return "Sm" }
|
||
return egy_Sm_present(slot)
|
||
}
|
||
if str_eq(verb, "go") {
|
||
if str_eq(tense, "present") { return egy_Sm_present(slot) }
|
||
if str_eq(tense, "past") { return egy_Sm_past(slot) }
|
||
if str_eq(tense, "future") { return egy_Sm_future(slot) }
|
||
if str_eq(tense, "infinitive") { return "Sm" }
|
||
return egy_Sm_present(slot)
|
||
}
|
||
|
||
// ── iri — to do / make ───────────────────────────────────────────────────────
|
||
if str_eq(verb, "iri") {
|
||
if str_eq(tense, "present") { return egy_iri_present(slot) }
|
||
if str_eq(tense, "past") { return egy_iri_past(slot) }
|
||
if str_eq(tense, "future") { return egy_iri_future(slot) }
|
||
if str_eq(tense, "infinitive") { return "iri" }
|
||
return egy_iri_present(slot)
|
||
}
|
||
if str_eq(verb, "do") {
|
||
if str_eq(tense, "present") { return egy_iri_present(slot) }
|
||
if str_eq(tense, "past") { return egy_iri_past(slot) }
|
||
if str_eq(tense, "future") { return egy_iri_future(slot) }
|
||
if str_eq(tense, "infinitive") { return "iri" }
|
||
return egy_iri_present(slot)
|
||
}
|
||
if str_eq(verb, "make") {
|
||
if str_eq(tense, "present") { return egy_iri_present(slot) }
|
||
if str_eq(tense, "past") { return egy_iri_past(slot) }
|
||
if str_eq(tense, "future") { return egy_iri_future(slot) }
|
||
if str_eq(tense, "infinitive") { return "iri" }
|
||
return egy_iri_present(slot)
|
||
}
|
||
|
||
// ── sdm — to hear ────────────────────────────────────────────────────────────
|
||
if str_eq(verb, "sdm") {
|
||
if str_eq(tense, "present") { return egy_sdm_present(slot) }
|
||
if str_eq(tense, "past") { return egy_sdm_past(slot) }
|
||
if str_eq(tense, "future") { return egy_sdm_future(slot) }
|
||
if str_eq(tense, "infinitive") { return "sdm" }
|
||
return egy_sdm_present(slot)
|
||
}
|
||
if str_eq(verb, "hear") {
|
||
if str_eq(tense, "present") { return egy_sdm_present(slot) }
|
||
if str_eq(tense, "past") { return egy_sdm_past(slot) }
|
||
if str_eq(tense, "future") { return egy_sdm_future(slot) }
|
||
if str_eq(tense, "infinitive") { return "sdm" }
|
||
return egy_sdm_present(slot)
|
||
}
|
||
|
||
// Verb not in table
|
||
return ""
|
||
}
|
||
|
||
// ── Regular verb conjugation ────────────────────────────────────────────────────
|
||
//
|
||
// For verbs not in the explicit table, apply the productive suffix-verb pattern:
|
||
// Present (imperfective sdm=f): stem + pronoun suffix
|
||
// Past (perfective sdm.n=f): stem + ".n" + pronoun suffix
|
||
// Future (prospective sdm.xr=f): stem + ".xr" + pronoun suffix
|
||
// Infinitive: stem unchanged
|
||
//
|
||
// This covers the vast majority of strong (sound) verb roots.
|
||
|
||
fn egy_regular_present(stem: String, slot: Int) -> String {
|
||
return stem + egy_suffix_pronoun(slot)
|
||
}
|
||
|
||
fn egy_regular_past(stem: String, slot: Int) -> String {
|
||
return stem + ".n" + egy_suffix_pronoun(slot)
|
||
}
|
||
|
||
fn egy_regular_future(stem: String, slot: Int) -> String {
|
||
return stem + ".xr" + egy_suffix_pronoun(slot)
|
||
}
|
||
|
||
// ── egy_conjugate: main conjugation entry point ─────────────────────────────────
|
||
//
|
||
// verb: Egyptian verb (ASCII transliteration) or English canonical label
|
||
// tense: "present" | "past" | "future" | "infinitive"
|
||
// person: "first" | "second" | "third"
|
||
// number: "singular" | "dual" | "plural"
|
||
//
|
||
// Returns:
|
||
// - "" for present copula (zero copula — caller omits the verb)
|
||
// - inflected form (stem + .n + suffix, etc.) for all other cases
|
||
// - verb + regular suffix for unknown verbs (productive fallback)
|
||
|
||
fn egy_conjugate(verb: String, tense: String, person: String, number: String) -> String {
|
||
let slot: Int = egy_slot(person, number)
|
||
|
||
// Handle copula (wnn / "be")
|
||
if egy_is_copula(verb) {
|
||
return egy_conjugate_copula(tense, slot)
|
||
}
|
||
|
||
// Try the known-verb table
|
||
let known: String = egy_known_verb(verb, tense, slot)
|
||
if !str_eq(known, "") {
|
||
return known
|
||
}
|
||
|
||
// Infinitive: return unchanged
|
||
if str_eq(tense, "infinitive") { return verb }
|
||
|
||
// Regular verb: apply productive sdm=f / sdm.n=f pattern
|
||
if str_eq(tense, "present") { return egy_regular_present(verb, slot) }
|
||
if str_eq(tense, "past") { return egy_regular_past(verb, slot) }
|
||
if str_eq(tense, "future") { return egy_regular_future(verb, slot) }
|
||
|
||
// Unknown tense: return verb unchanged as safe fallback
|
||
return verb
|
||
}
|
||
|
||
// ── Noun number marking ─────────────────────────────────────────────────────────
|
||
//
|
||
// Middle Egyptian nouns are invariant for case — syntactic role is expressed by
|
||
// word order and prepositions, not noun endings. Number is marked by suffix:
|
||
//
|
||
// Singular: base form (no suffix)
|
||
// Dual: masc + wy / fem + ty (wy and ty in ASCII transliteration)
|
||
// Plural: masc + w / fem + wt
|
||
//
|
||
// Many common nouns have suppletive or irregular plurals (recorded in the
|
||
// vocabulary layer). This function implements the productive regular pattern.
|
||
//
|
||
// gram_case: accepted for API symmetry but has no effect (Egyptian is caseless).
|
||
|
||
fn egy_decline(noun: String, gram_case: String, number: String) -> String {
|
||
if str_eq(number, "singular") { return noun }
|
||
if str_eq(number, "dual") {
|
||
// Feminine dual: if noun ends in t (feminine marker), replace with ty
|
||
if egy_str_ends(noun, "t") {
|
||
let stem: String = egy_drop(noun, 1)
|
||
return stem + "ty"
|
||
}
|
||
return noun + "wy"
|
||
}
|
||
// Plural
|
||
if egy_str_ends(noun, "t") {
|
||
// Feminine noun: add wt
|
||
return noun + "wt"
|
||
}
|
||
// Masculine noun: add w
|
||
return noun + "w"
|
||
}
|
||
|
||
// ── Feminine derivation ─────────────────────────────────────────────────────────
|
||
//
|
||
// egy_fem: derive the feminine form of a noun or adjective by appending -t.
|
||
//
|
||
// In Middle Egyptian, the feminine gender marker is the suffix -t (written with
|
||
// the bread-loaf hieroglyph, Gardiner X1). If the base already ends in -t the
|
||
// form is returned unchanged to avoid double-suffixing.
|
||
|
||
fn egy_fem(noun: String) -> String {
|
||
if egy_str_ends(noun, "t") { return noun }
|
||
return noun + "t"
|
||
}
|
||
|
||
// ── Noun phrase assembly ────────────────────────────────────────────────────────
|
||
//
|
||
// egy_noun_phrase: return the surface form of a noun phrase.
|
||
//
|
||
// noun: base noun (ASCII transliteration)
|
||
// gram_case: passed for API symmetry; has no effect (Egyptian is caseless)
|
||
// number: "singular" | "dual" | "plural"
|
||
// definite: "true" | "false" — Middle Egyptian has no article; parameter accepted
|
||
// for API symmetry. Late Egyptian pꜣ/tꜣ/nꜣ articles are not implemented
|
||
// here (they would require knowing the gender of each noun).
|
||
//
|
||
// Returns the noun in its correct number form.
|
||
|
||
fn egy_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String {
|
||
return egy_decline(noun, gram_case, number)
|
||
}
|
||
|
||
// ── Canonical verb mapping ──────────────────────────────────────────────────────
|
||
//
|
||
// egy_map_canonical: map cross-lingual English canonical verb labels to their
|
||
// Middle Egyptian equivalents before dispatching to egy_conjugate.
|
||
|
||
fn egy_map_canonical(verb: String) -> String {
|
||
if str_eq(verb, "be") { return "wnn" }
|
||
if str_eq(verb, "give") { return "rdi" }
|
||
if str_eq(verb, "see") { return "mAA" }
|
||
if str_eq(verb, "say") { return "Dd" }
|
||
if str_eq(verb, "go") { return "Sm" }
|
||
if str_eq(verb, "do") { return "iri" }
|
||
if str_eq(verb, "make") { return "iri" }
|
||
if str_eq(verb, "hear") { return "sdm" }
|
||
// Unknown: return as-is; egy_conjugate will apply the regular pattern
|
||
return verb
|
||
}
|