// morphology-sux.el — Sumerian morphology for the NLG engine. // // Implements Sumerian noun declension, verb conjugation, and sentence // construction. Designed as a companion to morphology.el and called by // the engine when the language profile code is "sux". // // Language profile: code=sux, name=Sumerian, morph_type=agglutinative, // word_order=SOV, question_strategy=particle, script=latin_transliteration, // family=isolate (no known relatives). // // Typological overview: // Sumerian is the world's oldest attested written language, first recorded // in Uruk ca. 3500 BCE; active spoken use through ca. 2000 BCE; learned // scribal language to ca. 100 CE. It is a language isolate — unrelated to // any other known language family. // // ERGATIVITY: Sumerian is ergative-absolutive. The subject of a transitive // verb (the AGENT) takes the ergative case (-e). The subject of an // intransitive verb and the direct object of a transitive verb share the // same form: the ABSOLUTIVE (unmarked, no suffix). This is structurally // the opposite of nominative-accusative languages (like Latin or Greek) // where the subject of both transitive and intransitive verbs is marked the // same way. Example: lugal-e é mu-un-dù = "the king built the house", // where lugal-e = king-ERG (agent of transitive dù "build") and é = house-ABS // (patient, unmarked). // // NOUN CLASSES: animate (humans, gods) and inanimate (everything else). // Animate plurals use -ene; inanimate plurals use -a (collective). // // VERB CHAIN: Sumerian finite verbs are polysynthetic chains encoding: // (modal)(negation)(dimensional prefixes)(stem)(voice/causative)(suffixes) // The dimensional prefix chain includes pronominal agreement markers for // agent and patient. This module implements a simplified but linguistically // honest subset: perfective mu-/imperfective i- prefix + personal suffixes. // // KEY VERBS: Several high-frequency verbs have frozen citation forms. // The copula is often omitted in equational sentences; when present it is // usually the clitic -am₃ or the verb me "to be". // // TRANSLITERATION: Standard Assyriological transliteration uses subscript // numbers for sign disambiguation (dug₄, tum₂, am₃) written here with the // corresponding Unicode characters (dug4, tum2, am3 using ASCII where the // subscript forms are unavailable in string literals, or as ₄ etc. where // needed). Special characters: š (sh), ŋ (velar nasal), ĝ (= ŋ alternate), // ḫ (voiceless velar/uvular fricative). // // Cases implemented: // absolutive (∅), ergative (-e), genitive (-ak), dative (-ra), // locative (-a), ablative (-ta), comitative (-da), equative (-gin) // // Depends on: morphology.el (str_ends_with, str_len, str_slice, str_eq, // native_list_empty, native_list_append, native_list_get, native_list_len) // ── String helpers ───────────────────────────────────────────────────────────── import "morphology.el" fn sux_str_ends(s: String, suf: String) -> Bool { return str_ends_with(s, suf) } fn sux_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) } fn sux_str_last_char(s: String) -> String { let n: Int = str_len(s) if n == 0 { return "" } return str_slice(s, n - 1, n) } fn sux_str_last2(s: String) -> String { let n: Int = str_len(s) if n < 2 { return s } return str_slice(s, n - 2, n) } // ── Person/number slot ───────────────────────────────────────────────────────── // // Maps person × number to a 0-based index used in paradigm tables. // 0 = 1st singular (ĝe₂₆ / ĝa₂ "I") // 1 = 2nd singular (za-e "you") // 2 = 3rd singular (animate: a-ne "he/she"; inanimate implied) // 3 = 1st plural (me "we") // 4 = 2nd plural (me-zen "you (pl)") // 5 = 3rd plural (animate: a-ne-ne "they") // // Dual is not grammaticalised distinctly from plural in Sumerian verbal // morphology; dual inputs fall through to plural. fn sux_slot(person: String, number: String) -> Int { if str_eq(person, "first") { if str_eq(number, "singular") { return 0 } return 3 } if str_eq(person, "second") { if str_eq(number, "singular") { return 1 } return 4 } // third person if str_eq(number, "singular") { return 2 } return 5 } // ── Ergative personal suffixes ───────────────────────────────────────────────── // // These encode the AGENT of a transitive verb when it appears as a standalone // noun suffix (postposition on the nominal element in the ergative chain). // In practice the -e ergative postposition on nouns is more common; these // pronominal suffixes appear in the verbal chain. Provided here for the // pronominal agent agreement slot. // // Ergative suffixes on nominal phrases (the postposition form, not verbal): // 1sg: -(e)n 2sg: -(e)n 3sg animate: -e // 1pl: -enden 2pl: -enzen 3pl animate: -eš fn sux_ergative_suffix(person: String, number: String) -> String { if str_eq(person, "first") { if str_eq(number, "singular") { return "-en" } return "-enden" } if str_eq(person, "second") { if str_eq(number, "singular") { return "-en" } return "-enzen" } // third if str_eq(number, "singular") { return "-e" } return "-eš" } // ── Absolutive personal suffixes ────────────────────────────────────────────── // // The absolutive is the UNMARKED case in Sumerian ergative grammar. It is // used for: // (a) the single argument of an intransitive verb (= subject) // (b) the direct object of a transitive verb (= patient) // // There is no overt suffix on the noun in the absolutive. However, the VERB // agrees with the absolutive argument via a suffix in the verbal chain. // These are the verbal agreement suffixes for the absolutive participant: // 1sg: -en 2sg: -en 3sg: ∅ (null) 1pl: -enden 2pl: -enzen 3pl: ∅ fn sux_absolutive_suffix(person: String, number: String) -> String { if str_eq(person, "first") { if str_eq(number, "singular") { return "-en" } return "-enden" } if str_eq(person, "second") { if str_eq(number, "singular") { return "-en" } return "-enzen" } // third person: null agreement suffix for 3sg and 3pl return "" } // ── Canonical verb mapping ───────────────────────────────────────────────────── // // The semantic layer may pass English canonical labels. Map these to the // Sumerian citation stem (the base form as used in transliteration). fn sux_map_canonical(verb: String) -> String { if str_eq(verb, "be") { return "me" } if str_eq(verb, "say") { return "dug4" } if str_eq(verb, "go") { return "du" } if str_eq(verb, "see") { return "igi-bar" } if str_eq(verb, "do") { return "ak" } if str_eq(verb, "make") { return "ak" } if str_eq(verb, "bring") { return "tum2" } if str_eq(verb, "build") { return "dù" } if str_eq(verb, "give") { return "šum2" } if str_eq(verb, "know") { return "zu" } if str_eq(verb, "hear") { return "ĝeštug2 ĝar" } if str_eq(verb, "love") { return "ki-aĝ2" } if str_eq(verb, "sit") { return "tuš" } if str_eq(verb, "stand") { return "gub" } if str_eq(verb, "come") { return "ĝen" } if str_eq(verb, "eat") { return "gu7" } if str_eq(verb, "drink") { return "naĝ" } if str_eq(verb, "write") { return "sar" } return verb } // ── Verbal personal suffixes (simplified finite chain) ──────────────────────── // // In the simplified model the personal suffix encodes the absolutive argument // (the subject of intransitive verbs, or the patient of transitive verbs). // Full Sumerian verbal morphology is polysynthetic and beyond NLG scope; this // models the most productive layer: stem + absolutive agreement. // // Suffix paradigm: // slot 0 (1sg): -en slot 3 (1pl): -enden // slot 1 (2sg): -en slot 4 (2pl): -enzen // slot 2 (3sg): ∅ slot 5 (3pl): -eš fn sux_personal_suffix(slot: Int) -> String { if slot == 0 { return "en" } if slot == 1 { return "en" } if slot == 2 { return "" } if slot == 3 { return "enden" } if slot == 4 { return "enzen" } return "eš" } // ── Special: me (to be) ─────────────────────────────────────────────────────── // // The Sumerian copula "me" (to be) has several uses: // - As a full verb with personal endings in present: me-en (I am), me-en // (you are), ∅ / -am3 (he/she/it is — copula often omitted or realised as // the clitic -am3 attached to the predicate), me-en-dè (we are) // - As a predicative clitic: noun/adj + -am3 // - In past: ha-ma-an-me (he/she was — rare in NLG contexts) // // For NLG purposes: // present: use me + personal suffix; 3sg = omit entirely or "-am3" clitic // past: ba-me + personal suffix (archaic; approximate) fn sux_me_present(slot: Int) -> String { if slot == 0 { return "me-en" } if slot == 1 { return "me-en" } if slot == 2 { return "" } if slot == 3 { return "me-en-dè" } if slot == 4 { return "me-en-zè-en" } return "me-eš" } fn sux_me_past(slot: Int) -> String { if slot == 0 { return "ba-me-en" } if slot == 1 { return "ba-me-en" } if slot == 2 { return "ba-me" } if slot == 3 { return "ba-me-en-dè" } if slot == 4 { return "ba-me-en-zè-en" } return "ba-me-eš" } // ── Special: dug4/e (to say) ────────────────────────────────────────────────── // // "dug4" is the perfective stem; "e" is the imperfective/present stem. // Common finite forms: // present (imperfective): e + personal suffix; 3sg = e // past (perfective): mu-un-dug4 (3sg agent; simplified) fn sux_dug4_present(slot: Int) -> String { let suf: String = sux_personal_suffix(slot) if str_eq(suf, "") { return "e" } return "e-" + suf } fn sux_dug4_past(slot: Int) -> String { let suf: String = sux_personal_suffix(slot) if str_eq(suf, "") { return "mu-un-dug4" } return "mu-un-dug4-" + suf } // ── Special: du (to go) ─────────────────────────────────────────────────────── // // Intransitive motion verb. The agent is in the absolutive. // present (imperfective): i-du + personal suffix // past (perfective): mu-un-du + personal suffix (mu- on intransitive // when the agent is 3rd person; convention varies) fn sux_du_present(slot: Int) -> String { let suf: String = sux_personal_suffix(slot) if str_eq(suf, "") { return "i-du" } return "i-du-" + suf } fn sux_du_past(slot: Int) -> String { let suf: String = sux_personal_suffix(slot) if str_eq(suf, "") { return "mu-un-du" } return "mu-un-du-" + suf } // ── Special: igi bar (to see — "to open the eye") ──────────────────────────── // // A compound verb: igi (eye) + bar (to open/spread). The noun igi is the // incorporated object; bar is the finite verb element. // present: igi i-bar + personal suffix // past: igi mu-un-bar + personal suffix fn sux_igibar_present(slot: Int) -> String { let suf: String = sux_personal_suffix(slot) if str_eq(suf, "") { return "igi i-bar" } return "igi i-bar-" + suf } fn sux_igibar_past(slot: Int) -> String { let suf: String = sux_personal_suffix(slot) if str_eq(suf, "") { return "igi mu-un-bar" } return "igi mu-un-bar-" + suf } // ── Special: ak (to do / make) ─────────────────────────────────────────────── // // High-frequency transitive verb; forms the basis of many compound verbs. // present: i-ak + personal suffix // past: mu-un-ak + personal suffix fn sux_ak_present(slot: Int) -> String { let suf: String = sux_personal_suffix(slot) if str_eq(suf, "") { return "i-ak" } return "i-ak-" + suf } fn sux_ak_past(slot: Int) -> String { let suf: String = sux_personal_suffix(slot) if str_eq(suf, "") { return "mu-un-ak" } return "mu-un-ak-" + suf } // ── Special: tum2/de6 (to bring) ───────────────────────────────────────────── // // Motion verb with incorporated directionality. // present: i-tum2 + personal suffix // past: mu-un-tum2 + personal suffix fn sux_tum2_present(slot: Int) -> String { let suf: String = sux_personal_suffix(slot) if str_eq(suf, "") { return "i-tum2" } return "i-tum2-" + suf } fn sux_tum2_past(slot: Int) -> String { let suf: String = sux_personal_suffix(slot) if str_eq(suf, "") { return "mu-un-tum2" } return "mu-un-tum2-" + suf } // ── sux_conjugate: main conjugation entry point ─────────────────────────────── // // verb: Sumerian verb stem or English canonical label // tense: "present" | "past" // (Sumerian distinguishes imperfective/perfective aspect rather than // tense proper; "present" maps to imperfective i-, "past" to // perfective mu-) // person: "first" | "second" | "third" // number: "singular" | "plural" // // Returns the inflected finite verb form in standard transliteration. // Falls back to mu- + stem for unknown verbs (productive perfective prefix). // // Note on ergativity in the verb chain: the prefix mu- encodes that the // agent (ergative subject) is 3rd person in the prototypical case. Full // pronominal infixing in the dimensional prefix chain is not modelled here; // the returned forms represent the 3rd-person-agent baseline with personal // suffixes for the absolutive participant. fn sux_conjugate(verb: String, tense: String, person: String, number: String) -> String { let v: String = sux_map_canonical(verb) let slot: Int = sux_slot(person, number) // ── "me" — copula / to be ──────────────────────────────────────────────── if str_eq(v, "me") { if str_eq(tense, "present") { return sux_me_present(slot) } if str_eq(tense, "past") { return sux_me_past(slot) } return sux_me_present(slot) } // ── "dug4" — to say ────────────────────────────────────────────────────── if str_eq(v, "dug4") { if str_eq(tense, "present") { return sux_dug4_present(slot) } if str_eq(tense, "past") { return sux_dug4_past(slot) } return sux_dug4_past(slot) } // ── "du" — to go ───────────────────────────────────────────────────────── if str_eq(v, "du") { if str_eq(tense, "present") { return sux_du_present(slot) } if str_eq(tense, "past") { return sux_du_past(slot) } return sux_du_past(slot) } // ── "igi-bar" — to see ─────────────────────────────────────────────────── if str_eq(v, "igi-bar") { if str_eq(tense, "present") { return sux_igibar_present(slot) } if str_eq(tense, "past") { return sux_igibar_past(slot) } return sux_igibar_past(slot) } // ── "ak" — to do / make ────────────────────────────────────────────────── if str_eq(v, "ak") { if str_eq(tense, "present") { return sux_ak_present(slot) } if str_eq(tense, "past") { return sux_ak_past(slot) } return sux_ak_past(slot) } // ── "tum2" — to bring ──────────────────────────────────────────────────── if str_eq(v, "tum2") { if str_eq(tense, "present") { return sux_tum2_present(slot) } if str_eq(tense, "past") { return sux_tum2_past(slot) } return sux_tum2_past(slot) } // ── Regular fallback: prefix + stem + personal suffix ──────────────────── // // For verbs not listed above, apply the productive rule: // imperfective (present): i- + stem + suffix // perfective (past): mu- + stem + suffix // // The "un" infix after mu- is a 3rd-person animate patient marker that // appears with transitive verbs; we omit it in the generic fallback as we // cannot know transitivity without a lexicon. let suf: String = sux_personal_suffix(slot) if str_eq(tense, "present") { if str_eq(suf, "") { return "i-" + v } return "i-" + v + "-" + suf } // past / perfective if str_eq(suf, "") { return "mu-" + v } return "mu-" + v + "-" + suf } // ── Animacy detection ───────────────────────────────────────────────────────── // // Sumerian grammatical animacy (ANIMATE vs INANIMATE) is a binary noun class // distinction affecting plural formation and pronominal reference. Animate // nouns denote humans and deities; everything else is inanimate. // // Heuristic: check for known divine/human markers in the noun: // - dingir/diĝir prefix (divine determinative, written with sign AN: 𒀭) // - Ends in -ra, -en (lordly epithets) // - Known human occupational terms as exact matches // - Otherwise: inanimate // // This is necessarily approximate without a full lexicon. The function errs // toward inanimate (safer default for open-class nouns). fn sux_is_animate(noun: String) -> Bool { // Divine determinative in transliteration if sux_str_ends(noun, "diĝir") { return true } if sux_str_ends(noun, "dingir") { return true } // Common human roles if str_eq(noun, "lugal") { return true } // king if str_eq(noun, "nin") { return true } // lady/queen if str_eq(noun, "en") { return true } // lord if str_eq(noun, "ensi2") { return true } // ruler/governor if str_eq(noun, "dumu") { return true } // son/child if str_eq(noun, "dam") { return true } // spouse/wife if str_eq(noun, "ama") { return true } // mother if str_eq(noun, "ad") { return true } // father if str_eq(noun, "a2-dam") { return true } // wife (alternate) if str_eq(noun, "lu2") { return true } // man/person if str_eq(noun, "munus") { return true } // woman if str_eq(noun, "ur") { return true } // man (archaic) if str_eq(noun, "saĝ") { return true } // head → person (as noun) if str_eq(noun, "gudu4") { return true } // priest if str_eq(noun, "sanga") { return true } // temple administrator if str_eq(noun, "ugula") { return true } // overseer if str_eq(noun, "dub-sar") { return true } // scribe if str_eq(noun, "nar") { return true } // singer/musician if str_eq(noun, "sukkal") { return true } // minister/vizier // Check for divine name prefix d (determinative before proper names) if sux_str_ends(noun, "d-") { return true } // Otherwise: inanimate return false } // ── Case suffixes ───────────────────────────────────────────────────────────── // // Sumerian is ergative-absolutive. The cases below are postpositional clitics // attached to the last element of the noun phrase. // // absolutive: ∅ (unmarked — subject of intransitive, object of transitive) // ergative: -e (subject of transitive verb — the AGENT) // genitive: -ak (possession, association; often written -a(k) before consonant) // dative: -ra (indirect object, beneficiary, "for/to") // locative: -a (location "in/at/on"; -e before certain consonants) // ablative: -ta (source, separation "from") // comitative: -da (accompaniment "with") // equative: -gin (comparison "like/as") // // Note: in connected speech the genitive -ak loses its final -k before a // consonant; this simplification uses the full form throughout. fn sux_case_suffix(gram_case: String) -> String { if str_eq(gram_case, "absolutive") { return "" } if str_eq(gram_case, "ergative") { return "-e" } if str_eq(gram_case, "genitive") { return "-ak" } if str_eq(gram_case, "dative") { return "-ra" } if str_eq(gram_case, "locative") { return "-a" } if str_eq(gram_case, "ablative") { return "-ta" } if str_eq(gram_case, "comitative") { return "-da" } if str_eq(gram_case, "equative") { return "-gin" } // Terminative (-še3: "to/toward") — also attested if str_eq(gram_case, "terminative") { return "-še" } return "" } // ── sux_decline: noun declension ───────────────────────────────────────────── // // noun: base form of the noun (absolutive singular = citation form) // gram_case: one of the cases listed above // number: "singular" | "plural" // // Plural formation: // Animate nouns: base + -ene (e.g. lugal-ene "kings") // Inanimate nouns: base + -a (collective/inanimate plural; less common, // many inanimate nouns are not pluralised at all in Sumerian) // // The case suffix attaches AFTER the plural marker. // // Absolutive singular = the bare stem (no suffix added). fn sux_decline(noun: String, gram_case: String, number: String) -> String { let csuf: String = sux_case_suffix(gram_case) if str_eq(number, "singular") { // Absolutive singular: bare stem with no suffix at all if str_eq(gram_case, "absolutive") { return noun } // Strip the leading dash from the suffix for direct concatenation let suf_len: Int = str_len(csuf) let bare_suf: String = str_slice(csuf, 1, suf_len) return noun + bare_suf } // Plural let animate: Bool = sux_is_animate(noun) let plural_stem: String = "" if animate { let plural_stem = noun + "ene" } if !animate { let plural_stem = noun + "a" } if str_eq(gram_case, "absolutive") { return plural_stem } let suf_len2: Int = str_len(csuf) let bare_suf2: String = str_slice(csuf, 1, suf_len2) return plural_stem + bare_suf2 } // ── sux_noun_phrase: noun phrase builder ───────────────────────────────────── // // Sumerian has NO articles (definite or indefinite). Determinateness is // expressed through context, position, or the genitive construction. // The "definite" parameter is accepted for interface compatibility but is // ignored — the returned form is always the declined noun alone. // // noun: base (absolutive) form // gram_case: grammatical case string // number: "singular" | "plural" // definite: ignored (Sumerian has no articles) fn sux_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String { return sux_decline(noun, gram_case, number) } // ── sux_verb_chain: build the finite verbal complex ─────────────────────────── // // Constructs the full Sumerian SOV clause for a transitive or intransitive // predication. Sumerian word order is strict SOV. // // For TRANSITIVE sentences (ergative construction): // agent (in ergative case: noun + -e) + patient (absolutive) + verb // Example: lugal-e é mu-un-dù // king-ERG house-ABS built // "The king built the house." // // For INTRANSITIVE sentences: // agent (in absolutive case: bare noun) + verb // Example: lugal du // king-ABS went // "The king went." // // agent: the subject noun (base/absolutive form); ergative suffix applied here // verb: Sumerian verb stem or canonical English label // patient: patient noun (absolutive; pass "" for intransitive) // tense: "present" | "past" // // Note: this function handles third-person singular agreement throughout, which // is the most common narrative form in Sumerian texts. The conjugated verb // form uses sux_conjugate with "third"/"singular" for the absolutive agreement. fn sux_verb_chain(agent: String, verb: String, patient: String, tense: String) -> String { let conjugated: String = sux_conjugate(verb, tense, "third", "singular") // Intransitive: agent in absolutive + verb if str_eq(patient, "") { return agent + " " + conjugated } // Transitive: agent in ergative + patient in absolutive + verb // Apply ergative suffix directly (no leading dash needed — it is -e) let agent_erg: String = agent + "e" return agent_erg + " " + patient + " " + conjugated } // ── sux_realize_sentence: top-level sentence realizer ──────────────────────── // // Assembles a complete Sumerian sentence from semantic components. // // intent: "assert" | "question" | "describe" // agent: subject noun (base form) // predicate: verb stem / canonical label (for assert/question) OR // adjective/noun predicate (for describe / nominal sentence) // patient: object noun (base form); pass "" for intransitive or nominal sentence // tense: "present" | "past" // // ── assert (declarative transitive/intransitive) ───────────────────────────── // Builds the SOV verb chain using sux_verb_chain. // Ergative marking is applied to the agent when a patient is present. // Example: lugal-e é mu-un-dù "The king built the house." // // ── question ───────────────────────────────────────────────────────────────── // Sumerian polar questions are formed by appending the enclitic -a to the // verb (written -am₃ in some analyses; here "-a" on the verb complex). // Word order is unchanged (SOV retained). // Example: lugal-e é mu-un-dù-a? "Did the king build the house?" // // ── describe (nominal/equational sentence) ────────────────────────────────── // Sumerian equational sentences (X is Y) typically omit the copula entirely // or append -am₃ to the predicate nominal/adjective. // Form: agent + predicate + "-am3" // Example: lugal-am3 "He is a king." / lugal kalag-ga-am3 "The king is mighty." // // When a patient is provided in describe mode, it is treated as the predicate // complement: agent + patient-am3. fn sux_realize_sentence(intent: String, agent: String, predicate: String, patient: String, tense: String) -> String { if str_eq(intent, "assert") { return sux_verb_chain(agent, predicate, patient, tense) } if str_eq(intent, "question") { // Build the assertion first, then append the question enclitic -a let assertion: String = sux_verb_chain(agent, predicate, patient, tense) return assertion + "-a" } if str_eq(intent, "describe") { // Nominal/equational sentence: agent predicate/patient + copula clitic -am3 // When patient is given it serves as the predicate nominal if str_eq(patient, "") { return agent + " " + predicate + "-am3" } return agent + " " + patient + "-am3" } // Fallback: plain assertion return sux_verb_chain(agent, predicate, patient, tense) }