631 lines
27 KiB
EmacsLisp
631 lines
27 KiB
EmacsLisp
// morphology-hi.el - Hindi morphology for the NLG engine.
|
|
//
|
|
// Implements Hindi noun declension (direct and oblique cases), postpositional
|
|
// particles, verb stem extraction, tense conjugation, and genitive agreement.
|
|
//
|
|
// Hindi is a fusional/agglutinative hybrid, SOV, pro-drop, with Devanagari script.
|
|
//
|
|
// Key facts:
|
|
// - 2 genders: masculine (m), feminine (f)
|
|
// - 2 numbers: singular (sg), plural (pl)
|
|
// - 2 main cases: direct (nominative/accusative) and oblique (before postpositions)
|
|
// - Verbs agree with subject in gender and number
|
|
// - No articles
|
|
//
|
|
// Conventions used throughout:
|
|
// gender: "m" | "f"
|
|
// number: "sg" | "pl"
|
|
// case: "direct" | "oblique"
|
|
// tense: "present" | "past" | "future"
|
|
// person: "1" | "2" | "3"
|
|
//
|
|
// Depends on: morphology.el (str_eq, str_len, str_slice, str_ends_with,
|
|
// str_drop_last)
|
|
|
|
// ── String helpers ────────────────────────────────────────────────────────────
|
|
|
|
fn hi_str_ends(s: String, suf: String) -> Bool {
|
|
return str_ends_with(s, suf)
|
|
}
|
|
|
|
fn hi_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 hi_str_last_char(s: String) -> String {
|
|
let n: Int = str_len(s)
|
|
if n == 0 {
|
|
return ""
|
|
}
|
|
return str_slice(s, n - 1, n)
|
|
}
|
|
|
|
// ── Gender inference ──────────────────────────────────────────────────────────
|
|
//
|
|
// Heuristic from the noun's final Devanagari character.
|
|
// Masculine: typically ends in आ (aa), or a consonant cluster
|
|
// Feminine: typically ends in ई (ii), ि (i-matra), or other endings
|
|
//
|
|
// This is an approximation — gender is inherent to each noun and not always
|
|
// predictable. The caller should supply gender explicitly when known.
|
|
//
|
|
// Common feminine endings: "ी" (long ii), "ि" (short i matra in some forms),
|
|
// "न" (like बहन), "त" (like रात), "ट" (like बात)
|
|
// Common masculine endings: "ा" (aa matra), consonants generally
|
|
|
|
fn hi_gender(noun: String) -> String {
|
|
// Long ii ending — strongly feminine
|
|
if hi_str_ends(noun, "ी") { return "f" }
|
|
// aa matra ending — strongly masculine
|
|
if hi_str_ends(noun, "ा") { return "m" }
|
|
// Known feminine words by ending
|
|
if hi_str_ends(noun, "न") {
|
|
// बहन (sister), दुकान (shop) — feminine; but also many masc.
|
|
// Default feminine for -न common feminine nouns
|
|
return "f"
|
|
}
|
|
if hi_str_ends(noun, "त") { return "f" } // रात, बात, बात
|
|
if hi_str_ends(noun, "ट") { return "f" } // बात (variant spellings)
|
|
if hi_str_ends(noun, "श") { return "m" } // आकाश etc.
|
|
// Specific common words
|
|
if str_eq(noun, "लड़का") { return "m" }
|
|
if str_eq(noun, "लड़की") { return "f" }
|
|
if str_eq(noun, "आदमी") { return "m" }
|
|
if str_eq(noun, "औरत") { return "f" }
|
|
if str_eq(noun, "घर") { return "m" }
|
|
if str_eq(noun, "मेज़") { return "f" }
|
|
if str_eq(noun, "किताब") { return "f" }
|
|
if str_eq(noun, "पानी") { return "m" }
|
|
if str_eq(noun, "दूध") { return "m" }
|
|
if str_eq(noun, "हाथ") { return "m" }
|
|
if str_eq(noun, "आँख") { return "f" }
|
|
if str_eq(noun, "बच्चा") { return "m" }
|
|
if str_eq(noun, "बच्ची") { return "f" }
|
|
if str_eq(noun, "काम") { return "m" }
|
|
if str_eq(noun, "बात") { return "f" }
|
|
if str_eq(noun, "दिन") { return "m" }
|
|
if str_eq(noun, "रात") { return "f" }
|
|
if str_eq(noun, "देश") { return "m" }
|
|
if str_eq(noun, "भाषा") { return "f" }
|
|
if str_eq(noun, "जगह") { return "f" }
|
|
if str_eq(noun, "समय") { return "m" }
|
|
if str_eq(noun, "साल") { return "m" }
|
|
// Default to masculine
|
|
return "m"
|
|
}
|
|
|
|
// ── Masculine noun declension ─────────────────────────────────────────────────
|
|
//
|
|
// Two patterns:
|
|
// (A) Ends in -आ (ा matra): लड़का, बच्चा, घोड़ा — vowel-final type
|
|
// direct sg: base (लड़का)
|
|
// direct pl: stem + े (लड़के)
|
|
// oblique sg: stem + े (लड़के)
|
|
// oblique pl: stem + ों (लड़कों)
|
|
//
|
|
// (B) Consonant-final or other: आदमी, घर, हाथ, दिन — invariant type
|
|
// direct sg: base
|
|
// direct pl: base (no change in direct plural for most)
|
|
// oblique sg: base (no change)
|
|
// oblique pl: base + ों (घरों, हाथों, दिनों)
|
|
// Exception: आदमी (masc ending -ī): acts like (B) in direct but
|
|
// oblique pl uses ों drop the ī: आदमियों
|
|
|
|
fn hi_masc_aa_stem(noun: String) -> String {
|
|
// Strip trailing ा (aa matra, 3 UTF-8 bytes in Devanagari — but El strings
|
|
// are Unicode so we drop the last character which is ा)
|
|
return hi_str_drop_last(noun, 1)
|
|
}
|
|
|
|
fn hi_noun_direct_m(noun: String, number: String) -> String {
|
|
if hi_str_ends(noun, "ा") {
|
|
// Pattern A: aa-final masculine
|
|
if str_eq(number, "sg") { return noun }
|
|
// pl: replace ा with े
|
|
return hi_masc_aa_stem(noun) + "े"
|
|
}
|
|
// Pattern B: invariant direct forms
|
|
return noun
|
|
}
|
|
|
|
fn hi_noun_oblique_m(noun: String, number: String) -> String {
|
|
if hi_str_ends(noun, "ा") {
|
|
// Pattern A
|
|
let stem: String = hi_masc_aa_stem(noun)
|
|
if str_eq(number, "sg") { return stem + "े" }
|
|
return stem + "ों"
|
|
}
|
|
// Pattern B: consonant-final or ī-final
|
|
// आदमी and similar ī-final masculines: oblique pl inserts य
|
|
if hi_str_ends(noun, "ी") {
|
|
if str_eq(number, "sg") { return noun }
|
|
// oblique pl: drop ी, add ियों
|
|
let stem: String = hi_str_drop_last(noun, 1)
|
|
return stem + "ियों"
|
|
}
|
|
// Default consonant-final masculines
|
|
if str_eq(number, "sg") { return noun }
|
|
return noun + "ों"
|
|
}
|
|
|
|
// ── Feminine noun declension ──────────────────────────────────────────────────
|
|
//
|
|
// Two patterns:
|
|
// (A) Ends in -ई/-ी (long ii): लड़की, बच्ची
|
|
// direct sg: base (लड़की)
|
|
// direct pl: stem + ियाँ (लड़कियाँ)
|
|
// oblique sg: base (लड़की)
|
|
// oblique pl: stem + ियों (लड़कियों)
|
|
//
|
|
// (B) Consonant-final or other: मेज़, रात, किताब, बात, औरत, भाषा
|
|
// direct sg: base (मेज़)
|
|
// direct pl: base + ें (मेज़ें, किताबें)
|
|
// oblique sg: base
|
|
// oblique pl: base + ों (मेज़ों, किताबों)
|
|
|
|
fn hi_noun_direct_f(noun: String, number: String) -> String {
|
|
if hi_str_ends(noun, "ी") {
|
|
// Pattern A: ii-final feminine
|
|
if str_eq(number, "sg") { return noun }
|
|
let stem: String = hi_str_drop_last(noun, 1)
|
|
return stem + "ियाँ"
|
|
}
|
|
// Pattern B: other feminine
|
|
if str_eq(number, "sg") { return noun }
|
|
// Direct plural: add ें
|
|
return noun + "ें"
|
|
}
|
|
|
|
fn hi_noun_oblique_f(noun: String, number: String) -> String {
|
|
if hi_str_ends(noun, "ी") {
|
|
// Pattern A
|
|
if str_eq(number, "sg") { return noun }
|
|
let stem: String = hi_str_drop_last(noun, 1)
|
|
return stem + "ियों"
|
|
}
|
|
// Pattern B
|
|
if str_eq(number, "sg") { return noun }
|
|
return noun + "ों"
|
|
}
|
|
|
|
// ── Unified noun declension entry points ──────────────────────────────────────
|
|
|
|
// hi_noun_direct: direct case form (nominative/bare accusative).
|
|
fn hi_noun_direct(noun: String, gender: String, number: String) -> String {
|
|
if str_eq(gender, "m") { return hi_noun_direct_m(noun, number) }
|
|
if str_eq(gender, "f") { return hi_noun_direct_f(noun, number) }
|
|
return noun
|
|
}
|
|
|
|
// hi_noun_oblique: oblique case form (before postpositions).
|
|
fn hi_noun_oblique(noun: String, gender: String, number: String) -> String {
|
|
if str_eq(gender, "m") { return hi_noun_oblique_m(noun, number) }
|
|
if str_eq(gender, "f") { return hi_noun_oblique_f(noun, number) }
|
|
return noun
|
|
}
|
|
|
|
// ── Postpositional particles ──────────────────────────────────────────────────
|
|
//
|
|
// Hindi marks grammatical relations with postpositions that follow the oblique
|
|
// noun. The genitive postposition agrees with the possessed noun's gender and
|
|
// number — use hi_agree_genitive for that case.
|
|
//
|
|
// case values:
|
|
// "nominative" — no postposition (direct case subject)
|
|
// "accusative_animate"— को (ko) — animate direct objects
|
|
// "dative" — को (ko)
|
|
// "genitive" — का/की/के — use hi_agree_genitive instead
|
|
// "locative_in" — में (meṃ — in)
|
|
// "locative_on" — पर (par — on)
|
|
// "instrumental" — से (se — with/by)
|
|
// "ablative" — से (se — from)
|
|
// "comitative" — के साथ (ke saath — with/together with)
|
|
// "benefactive" — के लिए (ke liye — for)
|
|
|
|
fn hi_postposition(gram_case: String) -> String {
|
|
if str_eq(gram_case, "nominative") { return "" }
|
|
if str_eq(gram_case, "accusative_animate") { return "को" }
|
|
if str_eq(gram_case, "dative") { return "को" }
|
|
if str_eq(gram_case, "genitive") { return "का" } // base; use hi_agree_genitive
|
|
if str_eq(gram_case, "locative_in") { return "में" }
|
|
if str_eq(gram_case, "locative_on") { return "पर" }
|
|
if str_eq(gram_case, "instrumental") { return "से" }
|
|
if str_eq(gram_case, "ablative") { return "से" }
|
|
if str_eq(gram_case, "comitative") { return "के साथ" }
|
|
if str_eq(gram_case, "benefactive") { return "के लिए" }
|
|
return ""
|
|
}
|
|
|
|
// hi_agree_genitive: return the genitive postposition (का/की/के) that agrees
|
|
// with the gender and number of the POSSESSED noun (not the possessor).
|
|
//
|
|
// possessed_gender: "m" | "f"
|
|
// possessed_number: "sg" | "pl"
|
|
//
|
|
// m sg → का (kaa)
|
|
// f sg → की (kii)
|
|
// m pl → के (ke)
|
|
// f pl → की (kii)
|
|
|
|
fn hi_agree_genitive(possessed_gender: String, possessed_number: String) -> String {
|
|
if str_eq(possessed_gender, "f") { return "की" }
|
|
if str_eq(possessed_number, "pl") { return "के" }
|
|
return "का"
|
|
}
|
|
|
|
// ── Verb stem extraction ──────────────────────────────────────────────────────
|
|
//
|
|
// Most Hindi infinitives end in -ना (naa). Stripping it gives the verb stem.
|
|
// Examples: खाना → खा, जाना → जा, करना → कर, देखना → देख
|
|
//
|
|
// Irregulars that do not follow this pattern return a hardcoded stem.
|
|
|
|
fn hi_verb_stem(infinitive: String) -> String {
|
|
// Irregular stems
|
|
if str_eq(infinitive, "होना") { return "हो" }
|
|
if str_eq(infinitive, "करना") { return "कर" }
|
|
if str_eq(infinitive, "जाना") { return "जा" }
|
|
if str_eq(infinitive, "आना") { return "आ" }
|
|
if str_eq(infinitive, "देना") { return "दे" }
|
|
if str_eq(infinitive, "लेना") { return "ले" }
|
|
if str_eq(infinitive, "देखना") { return "देख" }
|
|
if str_eq(infinitive, "कहना") { return "कह" }
|
|
if str_eq(infinitive, "जानना") { return "जान" }
|
|
if str_eq(infinitive, "चाहना") { return "चाह" }
|
|
if str_eq(infinitive, "खाना") { return "खा" }
|
|
if str_eq(infinitive, "पीना") { return "पी" }
|
|
if str_eq(infinitive, "सोना") { return "सो" }
|
|
if str_eq(infinitive, "लिखना") { return "लिख" }
|
|
if str_eq(infinitive, "पढ़ना") { return "पढ़" }
|
|
if str_eq(infinitive, "बोलना") { return "बोल" }
|
|
if str_eq(infinitive, "चलना") { return "चल" }
|
|
if str_eq(infinitive, "बैठना") { return "बैठ" }
|
|
if str_eq(infinitive, "उठना") { return "उठ" }
|
|
if str_eq(infinitive, "मिलना") { return "मिल" }
|
|
if str_eq(infinitive, "रहना") { return "रह" }
|
|
if str_eq(infinitive, "सुनना") { return "सुन" }
|
|
if str_eq(infinitive, "समझना") { return "समझ" }
|
|
if str_eq(infinitive, "मानना") { return "मान" }
|
|
if str_eq(infinitive, "बनाना") { return "बना" }
|
|
if str_eq(infinitive, "लाना") { return "ला" }
|
|
if str_eq(infinitive, "भेजना") { return "भेज" }
|
|
if str_eq(infinitive, "खोलना") { return "खोल" }
|
|
if str_eq(infinitive, "बंद करना") { return "बंद कर" }
|
|
// Generic: strip trailing ना (last character)
|
|
if hi_str_ends(infinitive, "ना") {
|
|
return hi_str_drop_last(infinitive, 1)
|
|
// Note: ना is two Unicode chars (न + ा) but as a suffix pattern
|
|
// we want to strip the last char 'ा' and keep 'न' — however the
|
|
// actual Devanagari suffix ना is a single syllable grapheme cluster.
|
|
// str_drop_last drops the last Unicode codepoint.
|
|
// ना = न (na) + ा (aa-matra): str_drop_last(s,1) drops ा, leaving न at end.
|
|
// We need to drop 2 codepoints (न and ा = ना) to get the true stem.
|
|
}
|
|
return infinitive
|
|
}
|
|
|
|
// hi_verb_stem_clean: correctly strips -ना (2 Unicode codepoints: न + ा matra)
|
|
fn hi_verb_stem_clean(infinitive: String) -> String {
|
|
// Irregulars first
|
|
if str_eq(infinitive, "होना") { return "हो" }
|
|
if str_eq(infinitive, "करना") { return "कर" }
|
|
if str_eq(infinitive, "जाना") { return "जा" }
|
|
if str_eq(infinitive, "आना") { return "आ" }
|
|
if str_eq(infinitive, "देना") { return "दे" }
|
|
if str_eq(infinitive, "लेना") { return "ले" }
|
|
if str_eq(infinitive, "देखना") { return "देख" }
|
|
if str_eq(infinitive, "कहना") { return "कह" }
|
|
if str_eq(infinitive, "जानना") { return "जान" }
|
|
if str_eq(infinitive, "चाहना") { return "चाह" }
|
|
if str_eq(infinitive, "खाना") { return "खा" }
|
|
if str_eq(infinitive, "पीना") { return "पी" }
|
|
if str_eq(infinitive, "सोना") { return "सो" }
|
|
if str_eq(infinitive, "लिखना") { return "लिख" }
|
|
if str_eq(infinitive, "पढ़ना") { return "पढ़" }
|
|
if str_eq(infinitive, "बोलना") { return "बोल" }
|
|
if str_eq(infinitive, "चलना") { return "चल" }
|
|
if str_eq(infinitive, "बैठना") { return "बैठ" }
|
|
if str_eq(infinitive, "उठना") { return "उठ" }
|
|
if str_eq(infinitive, "मिलना") { return "मिल" }
|
|
if str_eq(infinitive, "रहना") { return "रह" }
|
|
if str_eq(infinitive, "सुनना") { return "सुन" }
|
|
if str_eq(infinitive, "समझना") { return "समझ" }
|
|
if str_eq(infinitive, "मानना") { return "मान" }
|
|
if str_eq(infinitive, "बनाना") { return "बना" }
|
|
if str_eq(infinitive, "लाना") { return "ला" }
|
|
if str_eq(infinitive, "भेजना") { return "भेज" }
|
|
if str_eq(infinitive, "खोलना") { return "खोल" }
|
|
// Strip ना = 2 codepoints
|
|
if hi_str_ends(infinitive, "ना") {
|
|
return hi_str_drop_last(infinitive, 2)
|
|
}
|
|
return infinitive
|
|
}
|
|
|
|
// ── Present tense habitual conjugation ───────────────────────────────────────
|
|
//
|
|
// Structure: stem + aspect-suffix + auxiliary
|
|
//
|
|
// Aspect suffixes (agree with SUBJECT gender/number):
|
|
// m sg: ता (taa)
|
|
// f sg: ती (tii)
|
|
// m pl: ते (te)
|
|
// f pl: ती (tii)
|
|
//
|
|
// Auxiliary हो/है/हैं (am/is/are) agreed with person and number:
|
|
// 1sg: हूँ (huuṃ)
|
|
// 2sg: हो (ho) [informal], हैं (haiṃ) [formal]
|
|
// 3sg: है (hai)
|
|
// 1pl: हैं (haiṃ)
|
|
// 2pl: हो (ho) [informal], हैं (haiṃ) [formal]
|
|
// 3pl: हैं (haiṃ)
|
|
|
|
fn hi_present_aspect(gender: String, number: String) -> String {
|
|
if str_eq(gender, "f") { return "ती" }
|
|
if str_eq(number, "pl") { return "ते" }
|
|
return "ता"
|
|
}
|
|
|
|
fn hi_aux_present(person: String, number: String) -> String {
|
|
if str_eq(person, "1") {
|
|
if str_eq(number, "sg") { return "हूँ" }
|
|
return "हैं"
|
|
}
|
|
if str_eq(person, "2") {
|
|
if str_eq(number, "sg") { return "हो" }
|
|
return "हो"
|
|
}
|
|
// third person
|
|
if str_eq(number, "sg") { return "है" }
|
|
return "हैं"
|
|
}
|
|
|
|
// ── Past tense conjugation ────────────────────────────────────────────────────
|
|
//
|
|
// Simple past suffix agrees with subject (when object has no को).
|
|
// stem + past-suffix:
|
|
// m sg: आ (aa) e.g. खाया (khaayaa)
|
|
// f sg: ई (ii) e.g. खाई (khaaii)
|
|
// m pl: ए (e) e.g. खाए (khaae)
|
|
// f pl: ईं (iiṃ) e.g. खाईं (khaaiṃ)
|
|
//
|
|
// Many verb stems ending in a vowel undergo contraction — the irregulars table
|
|
// handles known cases; otherwise stem + suffix is concatenated.
|
|
|
|
fn hi_past_suffix(gender: String, number: String) -> String {
|
|
if str_eq(gender, "m") {
|
|
if str_eq(number, "sg") { return "आ" }
|
|
return "ए"
|
|
}
|
|
// feminine
|
|
if str_eq(number, "sg") { return "ई" }
|
|
return "ईं"
|
|
}
|
|
|
|
// Past tense irregulars — full past form returned for known verb+gender+number.
|
|
fn hi_past_irregular(stem: String, gender: String, number: String) -> String {
|
|
// होना (ho): था/थी/थे/थीं
|
|
if str_eq(stem, "हो") {
|
|
if str_eq(gender, "m") {
|
|
if str_eq(number, "sg") { return "था" }
|
|
return "थे"
|
|
}
|
|
if str_eq(number, "sg") { return "थी" }
|
|
return "थीं"
|
|
}
|
|
// जाना (jaa): गया/गई/गए/गईं
|
|
if str_eq(stem, "जा") {
|
|
if str_eq(gender, "m") {
|
|
if str_eq(number, "sg") { return "गया" }
|
|
return "गए"
|
|
}
|
|
if str_eq(number, "sg") { return "गई" }
|
|
return "गईं"
|
|
}
|
|
// करना (kar): किया/की/किए/कीं
|
|
if str_eq(stem, "कर") {
|
|
if str_eq(gender, "m") {
|
|
if str_eq(number, "sg") { return "किया" }
|
|
return "किए"
|
|
}
|
|
if str_eq(number, "sg") { return "की" }
|
|
return "कीं"
|
|
}
|
|
// देना (de): दिया/दी/दिए/दीं
|
|
if str_eq(stem, "दे") {
|
|
if str_eq(gender, "m") {
|
|
if str_eq(number, "sg") { return "दिया" }
|
|
return "दिए"
|
|
}
|
|
if str_eq(number, "sg") { return "दी" }
|
|
return "दीं"
|
|
}
|
|
// लेना (le): लिया/ली/लिए/लीं
|
|
if str_eq(stem, "ले") {
|
|
if str_eq(gender, "m") {
|
|
if str_eq(number, "sg") { return "लिया" }
|
|
return "लिए"
|
|
}
|
|
if str_eq(number, "sg") { return "ली" }
|
|
return "लीं"
|
|
}
|
|
// आना (aa): आया/आई/आए/आईं
|
|
if str_eq(stem, "आ") {
|
|
if str_eq(gender, "m") {
|
|
if str_eq(number, "sg") { return "आया" }
|
|
return "आए"
|
|
}
|
|
if str_eq(number, "sg") { return "आई" }
|
|
return "आईं"
|
|
}
|
|
// खाना (khaa): खाया/खाई/खाए/खाईं
|
|
if str_eq(stem, "खा") {
|
|
if str_eq(gender, "m") {
|
|
if str_eq(number, "sg") { return "खाया" }
|
|
return "खाए"
|
|
}
|
|
if str_eq(number, "sg") { return "खाई" }
|
|
return "खाईं"
|
|
}
|
|
// पीना (pii): पिया/पी/पिए/पीं
|
|
if str_eq(stem, "पी") {
|
|
if str_eq(gender, "m") {
|
|
if str_eq(number, "sg") { return "पिया" }
|
|
return "पिए"
|
|
}
|
|
if str_eq(number, "sg") { return "पी" }
|
|
return "पीं"
|
|
}
|
|
// No irregular match
|
|
return ""
|
|
}
|
|
|
|
// ── Future tense conjugation ──────────────────────────────────────────────────
|
|
//
|
|
// Future: stem + future-suffix (fused person+gender+number)
|
|
//
|
|
// 1sg m: ऊँगा (uuṃgaa) 1sg f: ऊँगी (uuṃgii)
|
|
// 2sg m: ओगे (oge) 2sg f: ओगी (ogii)
|
|
// 3sg m: एगा (egaa) 3sg f: एगी (egii)
|
|
// 1pl m: एंगे (eṃge) 1pl f: एंगी (eṃgii)
|
|
// 2pl m: ओगे (oge) 2pl f: ओगी (ogii)
|
|
// 3pl m: एंगे (eṃge) 3pl f: एंगी (eṃgii)
|
|
|
|
fn hi_future_suffix(person: String, number: String, gender: String) -> String {
|
|
if str_eq(person, "1") {
|
|
if str_eq(number, "sg") {
|
|
if str_eq(gender, "f") { return "ऊँगी" }
|
|
return "ऊँगा"
|
|
}
|
|
if str_eq(gender, "f") { return "एंगी" }
|
|
return "एंगे"
|
|
}
|
|
if str_eq(person, "2") {
|
|
if str_eq(gender, "f") { return "ओगी" }
|
|
return "ओगे"
|
|
}
|
|
// third person
|
|
if str_eq(number, "sg") {
|
|
if str_eq(gender, "f") { return "एगी" }
|
|
return "एगा"
|
|
}
|
|
if str_eq(gender, "f") { return "एंगी" }
|
|
return "एंगे"
|
|
}
|
|
|
|
// ── Tense suffix (aspect suffix only, without auxiliary) ─────────────────────
|
|
//
|
|
// For callers that need just the aspect suffix to construct compound tenses.
|
|
|
|
fn hi_tense_suffix(tense: String, gender: String, number: String) -> String {
|
|
if str_eq(tense, "present") { return hi_present_aspect(gender, number) }
|
|
if str_eq(tense, "past") { return hi_past_suffix(gender, number) }
|
|
// future uses hi_future_suffix (includes person)
|
|
return ""
|
|
}
|
|
|
|
// ── होना (honaa — to be) special handling ────────────────────────────────────
|
|
//
|
|
// होना is deeply irregular. Its forms are used as auxiliaries throughout.
|
|
//
|
|
// present: हूँ/हो/है/हैं (via hi_aux_present)
|
|
// past: था/थी/थे/थीं (via hi_past_irregular)
|
|
// future: होऊँगा/होओगे/होएगा etc. (stem हो + future suffix)
|
|
|
|
fn hi_hona_present(person: String, number: String) -> String {
|
|
return hi_aux_present(person, number)
|
|
}
|
|
|
|
fn hi_hona_past(gender: String, number: String) -> String {
|
|
if str_eq(gender, "m") {
|
|
if str_eq(number, "sg") { return "था" }
|
|
return "थे"
|
|
}
|
|
if str_eq(number, "sg") { return "थी" }
|
|
return "थीं"
|
|
}
|
|
|
|
// ── Full verb conjugation ─────────────────────────────────────────────────────
|
|
//
|
|
// hi_conjugate: conjugate a Hindi verb.
|
|
//
|
|
// verb: Hindi infinitive in Devanagari (e.g. "खाना", "जाना", "करना")
|
|
// tense: "present" | "past" | "future"
|
|
// person: "1" | "2" | "3"
|
|
// gender: "m" | "f" (subject gender)
|
|
// number: "sg" | "pl"
|
|
//
|
|
// Returns the complete inflected verb string (including auxiliary where needed).
|
|
|
|
fn hi_conjugate(verb: String, tense: String, person: String, gender: String, number: String) -> String {
|
|
let stem: String = hi_verb_stem_clean(verb)
|
|
|
|
// होना — fully irregular
|
|
if str_eq(verb, "होना") {
|
|
if str_eq(tense, "present") { return hi_hona_present(person, number) }
|
|
if str_eq(tense, "past") { return hi_hona_past(gender, number) }
|
|
// future: होऊँगा etc.
|
|
return "हो" + hi_future_suffix(person, number, gender)
|
|
}
|
|
|
|
if str_eq(tense, "present") {
|
|
let aspect: String = hi_present_aspect(gender, number)
|
|
let aux: String = hi_aux_present(person, number)
|
|
return stem + aspect + " " + aux
|
|
}
|
|
|
|
if str_eq(tense, "past") {
|
|
let irreg: String = hi_past_irregular(stem, gender, number)
|
|
if !str_eq(irreg, "") {
|
|
return irreg
|
|
}
|
|
return stem + hi_past_suffix(gender, number)
|
|
}
|
|
|
|
if str_eq(tense, "future") {
|
|
return stem + hi_future_suffix(person, number, gender)
|
|
}
|
|
|
|
// Unknown tense: return infinitive
|
|
return verb
|
|
}
|
|
|
|
// ── Noun phrase construction helpers ─────────────────────────────────────────
|
|
|
|
// hi_noun_with_post: return the oblique noun form followed by its postposition.
|
|
// Use for all cases that require an oblique form (dative, locative, etc.).
|
|
//
|
|
// noun: Devanagari noun string
|
|
// gender: "m" | "f"
|
|
// number: "sg" | "pl"
|
|
// case: postposition case key (see hi_postposition)
|
|
|
|
fn hi_noun_with_post(noun: String, gender: String, number: String, gram_case: String) -> String {
|
|
let post: String = hi_postposition(gram_case)
|
|
if str_eq(post, "") {
|
|
// Nominative: use direct form
|
|
return hi_noun_direct(noun, gender, number)
|
|
}
|
|
let oblique: String = hi_noun_oblique(noun, gender, number)
|
|
return oblique + " " + post
|
|
}
|
|
|
|
// hi_genitive_phrase: "X का/की/के Y" — possessive phrase.
|
|
// possessor and possessed are bare noun strings; the function computes all
|
|
// inflections and agreement automatically.
|
|
//
|
|
// possessor_gender/number: gender and number of the possessor noun
|
|
// possessed_gender/number: gender and number of the possessed noun (drives agreement)
|
|
|
|
fn hi_genitive_phrase(possessor: String, possessor_gender: String, possessor_number: String,
|
|
possessed: String, possessed_gender: String, possessed_number: String) -> String {
|
|
let obl: String = hi_noun_oblique(possessor, possessor_gender, possessor_number)
|
|
let gen: String = hi_agree_genitive(possessed_gender, possessed_number)
|
|
let poss: String = hi_noun_direct(possessed, possessed_gender, possessed_number)
|
|
return obl + " " + gen + " " + poss
|
|
}
|