// morphology-uga.el - Ugaritic morphology for the NLG engine. // πŽ€πŽŽπŽ—πŽš β€” Ugaritic, the language of the city-state of Ugarit. // // Implements Ugaritic verb conjugation (G-stem, suffix and prefix conjugations), // noun declension (three cases, gender, number, dual), and noun-phrase construction. // // Ugaritic is a Northwest Semitic language (ca. 1400–1200 BCE), written in a // 30-character alphabetic cuneiform. It is closely related to Biblical Hebrew // and Phoenician. We work in standard Latin transliteration: // ΚΌ = aleph (glottal stop) Κ» = ΚΏayin αΈ« = het Δ‘ = ghayin // αΉ― = thet αΊ“ = emphatic z Ε‘ = shin αΉ£ = tsade // // Language profile: // code=uga, name=Ugaritic, morph_type=semitic, word_order=VSO, // script=alphabetic cuneiform (transliterated), family=semitic/northwest-semitic // // Key grammatical facts: // - Semitic trilateral root system (nearly identical to Hebrew/Arabic) // - Grammatical gender: masculine / feminine // - Cases: nominative (-u), accusative (-a), genitive (-i) // (mirrors Akkadian but with shorter endings β€” no mimation in Ugaritic) // - Number: singular / plural / dual // - Dual: nom -āma, gen/acc -Δ“ma // - Verb tenses: // qtl (perfect, suffix conjugation) β€” completed action // yqtl (imperfect, prefix conjugation) β€” ongoing / future action // - Verb stems: G, D, Ε , N (this file: G-stem throughout) // - No separate definite article (unlike later Hebrew ha-) // - Copula: root kn (to be) // // Verb conjugation conventions: // person: "first" | "second" | "third" // gender: "m" | "f" // number: "singular" | "plural" // tense: "perfect" | "imperfect" // // Noun declension conventions: // gram_case: "nom" | "acc" | "gen" // number: "singular" | "plural" | "dual" // // Verbs covered (G-stem root, transliterated): // "kn" β€” to be (copula) // "hlk" β€” to go // "rΚΌy" β€” to see // "ΚΌmr" β€” to say // // Depends on: morphology.el (str_eq, str_len, str_slice, str_ends_with) // ── String helpers ───────────────────────────────────────────────────────────── import "morphology.el" fn uga_str_ends(s: String, suf: String) -> Bool { return str_ends_with(s, suf) } fn uga_str_len(s: String) -> Int { return str_len(s) } fn uga_str_drop_last(s: String, n: Int) -> String { let len: Int = str_len(s) if n >= len { return "" } return str_slice(s, 0, len - n) } // ── Slot index ───────────────────────────────────────────────────────────────── // // Maps person Γ— number to a 0-based slot index. // Gender is used separately for third-person disambiguation. // // Slot layout (6 primary cells, matching classic NW-Semitic paradigm): // 0 = 1sg (I) // 1 = 2sg (you sg β€” masc and fem conflate in many forms) // 2 = 3sg m (he) // 3 = 3sg f (she) // 4 = 1pl (we) // 5 = 3pl (they β€” masc default) fn uga_slot(person: String, number: String) -> Int { if str_eq(person, "first") { if str_eq(number, "plural") { return 4 } return 0 } if str_eq(person, "second") { return 1 } // third if str_eq(number, "plural") { return 5 } return 2 } // uga_slot_g: gender-sensitive slot for third-person singular. fn uga_slot_g(person: String, gender: String, number: String) -> Int { let base: Int = uga_slot(person, number) if str_eq(person, "third") { if str_eq(number, "singular") { if str_eq(gender, "f") { return 3 } } } return base } // ── Copula: kn β€” to be ──────────────────────────────────────────────────────── // // qtl (perfect): kāna (3sg m), kānat (3sg f), kānu (3pl) // yqtl (imperfect): yakΕ«nu (3sg m), takΕ«nu (3sg f / 2sg), ΚΌakΕ«nu (1sg) // // The root kn is a weak verb (hollow: middle w/y). The perfect stem is kāna-; // the imperfect stem is -kΕ«n-. fn uga_kn_perfect(slot: Int) -> String { if slot == 0 { return "kāntu" } // 1sg (kān- + suffix -tu) if slot == 1 { return "kānta" } // 2sg (-ta suffix) if slot == 2 { return "kāna" } // 3sg m (base) if slot == 3 { return "kānat" } // 3sg f (-at suffix) if slot == 4 { return "kānnu" } // 1pl (-nu suffix) return "kānu" // 3pl (-u suffix) } fn uga_kn_imperfect(slot: Int) -> String { if slot == 0 { return "ΚΌakΕ«nu" } // 1sg (ΚΌa- prefix) if slot == 1 { return "takΕ«nu" } // 2sg (ta- prefix) if slot == 2 { return "yakΕ«nu" } // 3sg m (ya- prefix) if slot == 3 { return "takΕ«nu" } // 3sg f (ta- prefix, same as 2sg) if slot == 4 { return "nakΕ«nu" } // 1pl (na- prefix) return "yakΕ«nuna" // 3pl (ya- + -Ε«na energic suffix) } fn uga_is_copula(verb: String) -> Bool { if str_eq(verb, "kn") { return true } if str_eq(verb, "kāna") { return true } if str_eq(verb, "be") { return true } return false } fn uga_conjugate_copula(tense: String, slot: Int) -> String { if str_eq(tense, "perfect") { return uga_kn_perfect(slot) } return uga_kn_imperfect(slot) } // ── hlk β€” to go ─────────────────────────────────────────────────────────────── // // Regular strong verb. Perfect stem: halak-; imperfect stem: -hluk-. fn uga_hlk_perfect(slot: Int) -> String { if slot == 0 { return "halaktu" } // 1sg if slot == 1 { return "halakta" } // 2sg if slot == 2 { return "halaka" } // 3sg m if slot == 3 { return "halakat" } // 3sg f if slot == 4 { return "halaknu" } // 1pl return "halaku" // 3pl } fn uga_hlk_imperfect(slot: Int) -> String { if slot == 0 { return "ΚΌahluku" } // 1sg if slot == 1 { return "tahluku" } // 2sg if slot == 2 { return "yahluku" } // 3sg m if slot == 3 { return "tahluku" } // 3sg f if slot == 4 { return "nahluku" } // 1pl return "yahlukuna" // 3pl } // ── rΚΌy β€” to see ────────────────────────────────────────────────────────────── // // Third-weak verb (final y). Perfect: raΚΌaya (3sg m); imperfect: yarʼā (3sg m). fn uga_ray_perfect(slot: Int) -> String { if slot == 0 { return "raΚΌaytu" } // 1sg if slot == 1 { return "raΚΌayta" } // 2sg if slot == 2 { return "raΚΌaya" } // 3sg m if slot == 3 { return "raΚΌayat" } // 3sg f if slot == 4 { return "raΚΌaynu" } // 1pl return "raΚΌayu" // 3pl } fn uga_ray_imperfect(slot: Int) -> String { if slot == 0 { return "ΚΌarʼā" } // 1sg if slot == 1 { return "tarʼā" } // 2sg if slot == 2 { return "yarʼā" } // 3sg m if slot == 3 { return "tarʼā" } // 3sg f if slot == 4 { return "narʼā" } // 1pl return "yarΚΌayna" // 3pl (fem plural ending for final-weak) } // ── ΚΌmr β€” to say ────────────────────────────────────────────────────────────── // // Strong verb. Perfect: ΚΌamara (3sg m); imperfect: yaΚΌmuru (3sg m). fn uga_amr_perfect(slot: Int) -> String { if slot == 0 { return "ΚΌamartu" } // 1sg if slot == 1 { return "ΚΌamarta" } // 2sg if slot == 2 { return "ΚΌamara" } // 3sg m if slot == 3 { return "ΚΌamarat" } // 3sg f if slot == 4 { return "ΚΌamarnu" } // 1pl return "ΚΌamaru" // 3pl } fn uga_amr_imperfect(slot: Int) -> String { if slot == 0 { return "ΚΌaΚΌmuru" } // 1sg if slot == 1 { return "taΚΌmuru" } // 2sg if slot == 2 { return "yaΚΌmuru" } // 3sg m if slot == 3 { return "taΚΌmuru" } // 3sg f if slot == 4 { return "naΚΌmuru" } // 1pl return "yaΚΌmuruna" // 3pl } // ── Generic G-stem paradigm (regular strong verbs) ──────────────────────────── // // For verbs not in the lookup table, apply the regular pattern. // Caller supplies the 3sg perfect form (qtl) and 3sg imperfect (yqtl) form. // We derive person forms by suffix/prefix substitution. fn uga_generic_perfect(base3sg: String, slot: Int) -> String { // Perfect suffixes: 1sg -tu, 2sg -ta, 3sg m βˆ…, 3sg f -at, 1pl -nu, 3pl -u if slot == 0 { return base3sg + "tu" } if slot == 1 { return base3sg + "ta" } if slot == 2 { return base3sg } if slot == 3 { return base3sg + "at" } if slot == 4 { return base3sg + "nu" } return base3sg + "u" } fn uga_generic_imperfect(base3sg: String, slot: Int) -> String { // Strip leading ya- to get the core, re-prefix per person. // This is a heuristic for display purposes when the stem is unknown. if slot == 0 { return "ΚΌa" + base3sg } if slot == 1 { return "ta" + base3sg } if slot == 2 { return "ya" + base3sg } if slot == 3 { return "ta" + base3sg } if slot == 4 { return "na" + base3sg } return "ya" + base3sg + "una" } // ── Known-verb dispatcher ───────────────────────────────────────────────────── fn uga_known_verb(verb: String, tense: String, slot: Int) -> String { // kn β€” to be if str_eq(verb, "kn") { return uga_conjugate_copula(tense, slot) } if str_eq(verb, "kāna") { return uga_conjugate_copula(tense, slot) } // hlk β€” to go if str_eq(verb, "hlk") { if str_eq(tense, "perfect") { return uga_hlk_perfect(slot) } return uga_hlk_imperfect(slot) } if str_eq(verb, "halaka") { if str_eq(tense, "perfect") { return uga_hlk_perfect(slot) } return uga_hlk_imperfect(slot) } // rΚΌy β€” to see if str_eq(verb, "rΚΌy") { if str_eq(tense, "perfect") { return uga_ray_perfect(slot) } return uga_ray_imperfect(slot) } if str_eq(verb, "raΚΌaya") { if str_eq(tense, "perfect") { return uga_ray_perfect(slot) } return uga_ray_imperfect(slot) } // ΚΌmr β€” to say if str_eq(verb, "ΚΌmr") { if str_eq(tense, "perfect") { return uga_amr_perfect(slot) } return uga_amr_imperfect(slot) } if str_eq(verb, "ΚΌamara") { if str_eq(tense, "perfect") { return uga_amr_perfect(slot) } return uga_amr_imperfect(slot) } return "" } // ── Main conjugation entry point ────────────────────────────────────────────── // // uga_conjugate: conjugate a Ugaritic verb (G-stem). // // verb: root (2–3 consonants, e.g. "kn", "hlk") or 3sg perfect citation form // tense: "perfect" | "imperfect" // person: "first" | "second" | "third" // number: "singular" | "plural" // // Returns: // - Inflected form for known verbs // - verb unchanged as safe fallback for unknown verbs fn uga_conjugate(verb: String, tense: String, person: String, number: String) -> String { let slot: Int = uga_slot(person, number) if uga_is_copula(verb) { return uga_conjugate_copula(tense, slot) } let known: String = uga_known_verb(verb, tense, slot) if !str_eq(known, "") { return known } return verb } // ── Noun declension ──────────────────────────────────────────────────────────── // // uga_decline: decline a Ugaritic noun for gram_case and number. // // Ugaritic case endings (no mimation β€” unlike Akkadian): // Masculine singular: // Nominative: -u (e.g. malku "king") // Accusative: -a (e.g. malka) // Genitive: -i (e.g. malki) // Masculine plural: // Nominative: -Ε«ma (e.g. malkΕ«ma) // Genitive/Accusative: -Δ«ma (e.g. malkΔ«ma) // Feminine singular (typically -atu base): // Nominative: -atu (e.g. malaktu) // Accusative: -ata (e.g. malakta) // Genitive: -ati (e.g. malakti) // Feminine plural: // Nominative: -ātu (e.g. malakātu) // Genitive/Accusative: -āti // Dual: // Nominative: -āma (e.g. malkāma) // Genitive/Accusative: -Δ“ma // // Strategy: strip the known nominative ending to get the bare stem, // then apply the requested ending. fn uga_strip_nom(noun: String) -> String { // Strip masc sg -u if uga_str_ends(noun, "u") { let len: Int = uga_str_len(noun) if len > 1 { return uga_str_drop_last(noun, 1) } } // Strip fem sg -atu if uga_str_ends(noun, "atu") { return uga_str_drop_last(noun, 3) } return noun } fn uga_is_fem(noun: String) -> Bool { if uga_str_ends(noun, "atu") { return true } if uga_str_ends(noun, "ata") { return true } if uga_str_ends(noun, "ati") { return true } if uga_str_ends(noun, "ātu") { return true } if uga_str_ends(noun, "āti") { return true } return false } fn uga_decline(noun: String, gram_case: String, number: String) -> String { let fem: Bool = uga_is_fem(noun) let stem: String = uga_strip_nom(noun) if str_eq(number, "dual") { if str_eq(gram_case, "nom") { return stem + "āma" } return stem + "Δ“ma" } if str_eq(number, "plural") { if fem { if str_eq(gram_case, "nom") { return stem + "ātu" } return stem + "āti" } // Masculine plural if str_eq(gram_case, "nom") { return stem + "Ε«ma" } return stem + "Δ«ma" } // Singular if fem { if str_eq(gram_case, "nom") { return stem + "atu" } if str_eq(gram_case, "acc") { return stem + "ata" } if str_eq(gram_case, "gen") { return stem + "ati" } return stem + "atu" } // Masculine singular if str_eq(gram_case, "nom") { return stem + "u" } if str_eq(gram_case, "acc") { return stem + "a" } if str_eq(gram_case, "gen") { return stem + "i" } return stem + "u" } // ── Noun phrase ──────────────────────────────────────────────────────────────── // // uga_noun_phrase: produce the surface noun phrase. // // Ugaritic has no separate definite article (unlike later Hebrew ha-). // Determination is expressed through word order, the construct chain (genitive), // and pronominal suffixes. The definite parameter is accepted for interface // uniformity but has no surface effect. // // noun: base noun (nominative singular form, e.g. "malku") // gram_case: "nom" | "acc" | "gen" // number: "singular" | "plural" | "dual" // definite: "true" | "false" (no surface effect in Ugaritic) fn uga_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String { return uga_decline(noun, gram_case, number) } // ── Canonical verb mapping ───────────────────────────────────────────────────── // // uga_map_canonical: map cross-lingual English canonical verb labels to // Ugaritic G-stem roots or citation forms. fn uga_map_canonical(verb: String) -> String { if str_eq(verb, "be") { return "kn" } if str_eq(verb, "go") { return "hlk" } if str_eq(verb, "see") { return "rΚΌy" } if str_eq(verb, "say") { return "ΚΌmr" } if str_eq(verb, "speak") { return "ΚΌmr" } return verb }