c2cd5e01e1
El SDK CI - dev / build-and-test (pull_request) Successful in 3m34s
elb.el: - Auto-detect Homebrew OpenSSL (-L$(brew --prefix openssl)/lib) so -lssl resolves on macOS without manual flags; no-op on Linux - Add -include elp-c-decls.h when present in out_dir: resolves undeclared cross-module calls in packages like ELP that lack explicit imports ELP source: - Add import "morphology.el" to all 29 language morphology modules - Add language module imports to morphology.el (all langs it dispatches to) These were missing since ELP was originally built as a monolithic unit
641 lines
28 KiB
EmacsLisp
641 lines
28 KiB
EmacsLisp
// 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)
|
||
}
|