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
557 lines
22 KiB
EmacsLisp
557 lines
22 KiB
EmacsLisp
// morphology-non.el - Old Norse morphology for the NLG engine.
|
|
//
|
|
// Implements Old Norse verb conjugation and noun declension for the ca. 700-1100 CE
|
|
// period. Designed as a companion to morphology.el and called by the engine when
|
|
// the language profile code is "non".
|
|
//
|
|
// Language profile: code=non, name=Old Norse, morph_type=fusional, word_order=V2,
|
|
// question_strategy=inversion, script=latin, family=germanic.
|
|
//
|
|
// Verb conjugation covered:
|
|
// Tenses: present, past
|
|
// Persons: first/second/third x singular/plural (slots 0-5)
|
|
// Classes: weak (-a infinitive: -aði past), and a set of common strong/irregular verbs
|
|
// Irregulars: vera (be), hafa (have), ganga (go), sjá (see), segja (say),
|
|
// koma (come)
|
|
// Canonical map: "be" -> "vera"
|
|
//
|
|
// Noun declension covered:
|
|
// Strong masculine a-stem (like "armr")
|
|
// Strong feminine ō-stem (like "gör")
|
|
// Strong neuter a-stem (like "land")
|
|
// Cases: nominative, accusative, genitive, dative
|
|
// Numbers: singular, plural
|
|
// Definite suffix: appended to the declined form (masc -inn/-ins/-inum, neut -it)
|
|
//
|
|
// Depends on: morphology.el (str_ends_with, str_len, str_slice, str_eq)
|
|
|
|
// ── String helpers ─────────────────────────────────────────────────────────────
|
|
|
|
import "morphology.el"
|
|
fn non_str_ends(s: String, suf: String) -> Bool {
|
|
return str_ends_with(s, suf)
|
|
}
|
|
|
|
fn non_drop(s: String, n: Int) -> String {
|
|
let len: Int = str_len(s)
|
|
if n >= len { return "" }
|
|
return str_slice(s, 0, len - n)
|
|
}
|
|
|
|
fn non_last(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 x number to a 0-based paradigm slot.
|
|
// 0 = 1st singular (ek)
|
|
// 1 = 2nd singular (þú)
|
|
// 2 = 3rd singular (hann/hon/þat)
|
|
// 3 = 1st plural (vér)
|
|
// 4 = 2nd plural (þér)
|
|
// 5 = 3rd plural (þeir/þær/þau)
|
|
|
|
fn non_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
|
|
if str_eq(number, "singular") { return 2 }
|
|
return 5
|
|
}
|
|
|
|
// ── Irregular verb tables ──────────────────────────────────────────────────────
|
|
//
|
|
// Each irregular verb has a present and past paradigm of six forms (slots 0-5).
|
|
|
|
fn non_vera_present(slot: Int) -> String {
|
|
if slot == 0 { return "em" }
|
|
if slot == 1 { return "ert" }
|
|
if slot == 2 { return "er" }
|
|
if slot == 3 { return "erum" }
|
|
if slot == 4 { return "eruð" }
|
|
return "eru"
|
|
}
|
|
|
|
fn non_vera_past(slot: Int) -> String {
|
|
if slot == 0 { return "var" }
|
|
if slot == 1 { return "vart" }
|
|
if slot == 2 { return "var" }
|
|
if slot == 3 { return "vórum" }
|
|
if slot == 4 { return "vóruð" }
|
|
return "vóru"
|
|
}
|
|
|
|
fn non_hafa_present(slot: Int) -> String {
|
|
if slot == 0 { return "hefi" }
|
|
if slot == 1 { return "hefr" }
|
|
if slot == 2 { return "hefr" }
|
|
if slot == 3 { return "höfum" }
|
|
if slot == 4 { return "hafið" }
|
|
return "hafa"
|
|
}
|
|
|
|
fn non_hafa_past(slot: Int) -> String {
|
|
if slot == 0 { return "hafða" }
|
|
if slot == 1 { return "hafðir" }
|
|
if slot == 2 { return "hafði" }
|
|
if slot == 3 { return "höfðum" }
|
|
if slot == 4 { return "höfðuð" }
|
|
return "höfðu"
|
|
}
|
|
|
|
fn non_ganga_present(slot: Int) -> String {
|
|
if slot == 0 { return "geng" }
|
|
if slot == 1 { return "gengr" }
|
|
if slot == 2 { return "gengr" }
|
|
if slot == 3 { return "göngum" }
|
|
if slot == 4 { return "gangið" }
|
|
return "ganga"
|
|
}
|
|
|
|
fn non_ganga_past(slot: Int) -> String {
|
|
if slot == 0 { return "gekk" }
|
|
if slot == 1 { return "gekkt" }
|
|
if slot == 2 { return "gekk" }
|
|
if slot == 3 { return "gengum" }
|
|
if slot == 4 { return "genguð" }
|
|
return "gengu"
|
|
}
|
|
|
|
fn non_sja_present(slot: Int) -> String {
|
|
if slot == 0 { return "sé" }
|
|
if slot == 1 { return "sér" }
|
|
if slot == 2 { return "sér" }
|
|
if slot == 3 { return "séum" }
|
|
if slot == 4 { return "séið" }
|
|
return "sjá"
|
|
}
|
|
|
|
fn non_sja_past(slot: Int) -> String {
|
|
if slot == 0 { return "sá" }
|
|
if slot == 1 { return "sást" }
|
|
if slot == 2 { return "sá" }
|
|
if slot == 3 { return "sám" }
|
|
if slot == 4 { return "sáð" }
|
|
return "sáu"
|
|
}
|
|
|
|
fn non_segja_present(slot: Int) -> String {
|
|
if slot == 0 { return "segi" }
|
|
if slot == 1 { return "segir" }
|
|
if slot == 2 { return "segir" }
|
|
if slot == 3 { return "segjum" }
|
|
if slot == 4 { return "segið" }
|
|
return "segja"
|
|
}
|
|
|
|
fn non_segja_past(slot: Int) -> String {
|
|
if slot == 0 { return "sagði" }
|
|
if slot == 1 { return "sagðir" }
|
|
if slot == 2 { return "sagði" }
|
|
if slot == 3 { return "sögðum" }
|
|
if slot == 4 { return "sögðuð" }
|
|
return "sögðu"
|
|
}
|
|
|
|
fn non_koma_present(slot: Int) -> String {
|
|
if slot == 0 { return "kem" }
|
|
if slot == 1 { return "kemr" }
|
|
if slot == 2 { return "kemr" }
|
|
if slot == 3 { return "komum" }
|
|
if slot == 4 { return "komið" }
|
|
return "koma"
|
|
}
|
|
|
|
fn non_koma_past(slot: Int) -> String {
|
|
if slot == 0 { return "kom" }
|
|
if slot == 1 { return "komt" }
|
|
if slot == 2 { return "kom" }
|
|
if slot == 3 { return "komum" }
|
|
if slot == 4 { return "komuð" }
|
|
return "komu"
|
|
}
|
|
|
|
// ── Canonical verb mapping ─────────────────────────────────────────────────────
|
|
//
|
|
// Maps English semantic labels to Old Norse infinitives so the semantic layer
|
|
// can request forms without knowing the target language lexeme.
|
|
|
|
fn non_map_canonical(verb: String) -> String {
|
|
if str_eq(verb, "be") { return "vera" }
|
|
if str_eq(verb, "have") { return "hafa" }
|
|
if str_eq(verb, "go") { return "ganga" }
|
|
if str_eq(verb, "see") { return "sjá" }
|
|
if str_eq(verb, "say") { return "segja" }
|
|
if str_eq(verb, "come") { return "koma" }
|
|
return verb
|
|
}
|
|
|
|
// ── Weak verb conjugation ──────────────────────────────────────────────────────
|
|
//
|
|
// Weak verbs (infinitive ending in -a) form the productive conjugation class.
|
|
//
|
|
// Present tense (stem = drop final -a from infinitive):
|
|
// Sg: 1st stem + -a 2nd stem + -ar 3rd stem + -ar
|
|
// Pl: 1st stem + -um 2nd stem + -ið 3rd stem + -a
|
|
//
|
|
// Past tense (suffix -aði- inserted after stem):
|
|
// Sg: 1st stem + -aði 2nd stem + -aðir 3rd stem + -aði
|
|
// Pl: 1st stem + -uðum 2nd stem + -uðuð 3rd stem + -uðu
|
|
|
|
fn non_weak_present(stem: String, slot: Int) -> String {
|
|
if slot == 0 { return stem + "a" }
|
|
if slot == 1 { return stem + "ar" }
|
|
if slot == 2 { return stem + "ar" }
|
|
if slot == 3 { return stem + "um" }
|
|
if slot == 4 { return stem + "ið" }
|
|
return stem + "a"
|
|
}
|
|
|
|
fn non_weak_past(stem: String, slot: Int) -> String {
|
|
if slot == 0 { return stem + "aði" }
|
|
if slot == 1 { return stem + "aðir" }
|
|
if slot == 2 { return stem + "aði" }
|
|
if slot == 3 { return stem + "uðum" }
|
|
if slot == 4 { return stem + "uðuð" }
|
|
return stem + "uðu"
|
|
}
|
|
|
|
// ── non_conjugate: main conjugation entry point ───────────────────────────────
|
|
//
|
|
// verb: Old Norse infinitive (e.g. "kalla", "vera") or English canonical label
|
|
// tense: "present" | "past"
|
|
// person: "first" | "second" | "third"
|
|
// number: "singular" | "plural"
|
|
//
|
|
// Returns the inflected form. Unknown tenses fall back to the infinitive rather
|
|
// than crashing.
|
|
|
|
fn non_conjugate(verb: String, tense: String, person: String, number: String) -> String {
|
|
let v: String = non_map_canonical(verb)
|
|
let slot: Int = non_slot(person, number)
|
|
|
|
// ── Irregulars ────────────────────────────────────────────────────────────
|
|
|
|
if str_eq(v, "vera") {
|
|
if str_eq(tense, "present") { return non_vera_present(slot) }
|
|
if str_eq(tense, "past") { return non_vera_past(slot) }
|
|
return v
|
|
}
|
|
|
|
if str_eq(v, "hafa") {
|
|
if str_eq(tense, "present") { return non_hafa_present(slot) }
|
|
if str_eq(tense, "past") { return non_hafa_past(slot) }
|
|
return v
|
|
}
|
|
|
|
if str_eq(v, "ganga") {
|
|
if str_eq(tense, "present") { return non_ganga_present(slot) }
|
|
if str_eq(tense, "past") { return non_ganga_past(slot) }
|
|
return v
|
|
}
|
|
|
|
if str_eq(v, "sjá") {
|
|
if str_eq(tense, "present") { return non_sja_present(slot) }
|
|
if str_eq(tense, "past") { return non_sja_past(slot) }
|
|
return v
|
|
}
|
|
|
|
if str_eq(v, "segja") {
|
|
if str_eq(tense, "present") { return non_segja_present(slot) }
|
|
if str_eq(tense, "past") { return non_segja_past(slot) }
|
|
return v
|
|
}
|
|
|
|
if str_eq(v, "koma") {
|
|
if str_eq(tense, "present") { return non_koma_present(slot) }
|
|
if str_eq(tense, "past") { return non_koma_past(slot) }
|
|
return v
|
|
}
|
|
|
|
// ── Regular weak verb (-a infinitive) ────────────────────────────────────
|
|
//
|
|
// If the verb ends in -a, strip it to get the stem and apply weak endings.
|
|
// Otherwise fall back to returning the base form unchanged.
|
|
|
|
if non_str_ends(v, "a") {
|
|
let stem: String = non_drop(v, 1)
|
|
if str_eq(tense, "present") { return non_weak_present(stem, slot) }
|
|
if str_eq(tense, "past") { return non_weak_past(stem, slot) }
|
|
return v
|
|
}
|
|
|
|
// Unknown verb form: return the infinitive unchanged
|
|
return v
|
|
}
|
|
|
|
// ── Strong masculine a-stem declension ("armr" — arm) ─────────────────────────
|
|
//
|
|
// The paradigm below uses "armr" as the exemplar. The caller passes the full
|
|
// nominative singular (including the -r ending); the oblique stem is derived
|
|
// by stripping -r (or -ur) from the nominative.
|
|
//
|
|
// Singular: nom armr acc arm gen arms dat armi
|
|
// Plural: nom armar acc arma gen arma dat örmum
|
|
//
|
|
// The dative plural -örmum involves u-umlaut of the root vowel. Because umlaut
|
|
// depends on the root vowel in complex ways, the module stores the dative plural
|
|
// stem separately: for "armr" it is "örm". For unknown nouns we approximatehere
|
|
// by returning the nominative plural (armar) rather than crashing.
|
|
|
|
fn non_decline_masc(noun: String, gram_case: String, number: String) -> String {
|
|
// Derive oblique stem by dropping the nominative -r ending if present.
|
|
let stem: String = noun
|
|
if non_str_ends(noun, "r") {
|
|
let stem = non_drop(noun, 1)
|
|
}
|
|
|
|
// Hard-code the known exemplar "armr" fully, including the umlauted dat pl.
|
|
if str_eq(noun, "armr") {
|
|
if str_eq(number, "singular") {
|
|
if str_eq(gram_case, "nominative") { return "armr" }
|
|
if str_eq(gram_case, "accusative") { return "arm" }
|
|
if str_eq(gram_case, "genitive") { return "arms" }
|
|
if str_eq(gram_case, "dative") { return "armi" }
|
|
return "armr"
|
|
}
|
|
if str_eq(gram_case, "nominative") { return "armar" }
|
|
if str_eq(gram_case, "accusative") { return "arma" }
|
|
if str_eq(gram_case, "genitive") { return "arma" }
|
|
if str_eq(gram_case, "dative") { return "örmum" }
|
|
return "armar"
|
|
}
|
|
|
|
// Generic strong masculine a-stem: use stripped stem + endings.
|
|
// Dative plural umlaut is approximated as nominative plural (safe fallback).
|
|
if str_eq(number, "singular") {
|
|
if str_eq(gram_case, "nominative") { return stem + "r" }
|
|
if str_eq(gram_case, "accusative") { return stem }
|
|
if str_eq(gram_case, "genitive") { return stem + "s" }
|
|
if str_eq(gram_case, "dative") { return stem + "i" }
|
|
return stem + "r"
|
|
}
|
|
if str_eq(gram_case, "nominative") { return stem + "ar" }
|
|
if str_eq(gram_case, "accusative") { return stem + "a" }
|
|
if str_eq(gram_case, "genitive") { return stem + "a" }
|
|
if str_eq(gram_case, "dative") { return stem + "um" }
|
|
return stem + "ar"
|
|
}
|
|
|
|
// ── Strong feminine ō-stem declension ("gör" — gear) ─────────────────────────
|
|
//
|
|
// ō-stem feminines have a distinct set of endings. The stem is the nominative
|
|
// singular form itself (no case suffix in nom sg for this class, though some
|
|
// nouns add -ar in nom/acc pl).
|
|
//
|
|
// Singular: nom gör acc görvar gen görvar dat görvi
|
|
// Plural: nom görvar acc görvar gen görva dat görvum
|
|
|
|
fn non_decline_fem(noun: String, gram_case: String, number: String) -> String {
|
|
// Use "gör" as the fully specified exemplar.
|
|
if str_eq(noun, "gör") {
|
|
if str_eq(number, "singular") {
|
|
if str_eq(gram_case, "nominative") { return "gör" }
|
|
if str_eq(gram_case, "accusative") { return "görvar" }
|
|
if str_eq(gram_case, "genitive") { return "görvar" }
|
|
if str_eq(gram_case, "dative") { return "görvi" }
|
|
return "gör"
|
|
}
|
|
if str_eq(gram_case, "nominative") { return "görvar" }
|
|
if str_eq(gram_case, "accusative") { return "görvar" }
|
|
if str_eq(gram_case, "genitive") { return "görva" }
|
|
if str_eq(gram_case, "dative") { return "görvum" }
|
|
return "görvar"
|
|
}
|
|
|
|
// Generic ō-stem feminine: noun base + endings (approximate).
|
|
if str_eq(number, "singular") {
|
|
if str_eq(gram_case, "nominative") { return noun }
|
|
if str_eq(gram_case, "accusative") { return noun + "var" }
|
|
if str_eq(gram_case, "genitive") { return noun + "var" }
|
|
if str_eq(gram_case, "dative") { return noun + "vi" }
|
|
return noun
|
|
}
|
|
if str_eq(gram_case, "nominative") { return noun + "var" }
|
|
if str_eq(gram_case, "accusative") { return noun + "var" }
|
|
if str_eq(gram_case, "genitive") { return noun + "va" }
|
|
if str_eq(gram_case, "dative") { return noun + "vum" }
|
|
return noun + "var"
|
|
}
|
|
|
|
// ── Strong neuter a-stem declension ("land" — land) ──────────────────────────
|
|
//
|
|
// Neuter a-stems show no ending in nom/acc sg and u-umlaut in the dative plural.
|
|
//
|
|
// Singular: nom land acc land gen lands dat landi
|
|
// Plural: nom lönd acc lönd gen landa dat löndum
|
|
|
|
fn non_decline_neut(noun: String, gram_case: String, number: String) -> String {
|
|
if str_eq(noun, "land") {
|
|
if str_eq(number, "singular") {
|
|
if str_eq(gram_case, "nominative") { return "land" }
|
|
if str_eq(gram_case, "accusative") { return "land" }
|
|
if str_eq(gram_case, "genitive") { return "lands" }
|
|
if str_eq(gram_case, "dative") { return "landi" }
|
|
return "land"
|
|
}
|
|
if str_eq(gram_case, "nominative") { return "lönd" }
|
|
if str_eq(gram_case, "accusative") { return "lönd" }
|
|
if str_eq(gram_case, "genitive") { return "landa" }
|
|
if str_eq(gram_case, "dative") { return "löndum" }
|
|
return "lönd"
|
|
}
|
|
|
|
// Generic strong neuter a-stem (no umlaut approximated — falls back to base).
|
|
if str_eq(number, "singular") {
|
|
if str_eq(gram_case, "nominative") { return noun }
|
|
if str_eq(gram_case, "accusative") { return noun }
|
|
if str_eq(gram_case, "genitive") { return noun + "s" }
|
|
if str_eq(gram_case, "dative") { return noun + "i" }
|
|
return noun
|
|
}
|
|
if str_eq(gram_case, "nominative") { return noun }
|
|
if str_eq(gram_case, "accusative") { return noun }
|
|
if str_eq(gram_case, "genitive") { return noun + "a" }
|
|
if str_eq(gram_case, "dative") { return noun + "um" }
|
|
return noun
|
|
}
|
|
|
|
// ── Gender detection heuristic ─────────────────────────────────────────────────
|
|
//
|
|
// Old Norse gender must ideally be supplied by the lexicon. As a heuristic:
|
|
// ends in -r (after removing) and root looks consonant-final -> masculine
|
|
// ends in no case suffix (just the root vowel) -> try feminine
|
|
// monosyllabic root without final r -> neuter
|
|
//
|
|
// The module uses a simplified approach: known exemplars are routed to their
|
|
// specific paradigm; everything else defaults to strong masculine.
|
|
|
|
fn non_detect_gender(noun: String) -> String {
|
|
if str_eq(noun, "land") { return "neuter" }
|
|
if str_eq(noun, "gör") { return "feminine" }
|
|
// Default: masculine
|
|
return "masculine"
|
|
}
|
|
|
|
// ── non_decline: main declension entry point ──────────────────────────────────
|
|
//
|
|
// noun: nominative singular Old Norse noun (e.g. "armr", "land", "gör")
|
|
// gram_case: "nominative" | "accusative" | "genitive" | "dative"
|
|
// number: "singular" | "plural"
|
|
//
|
|
// Returns the inflected form. Falls back to nominative singular on unknown input.
|
|
|
|
fn non_decline(noun: String, gram_case: String, number: String) -> String {
|
|
let gender: String = non_detect_gender(noun)
|
|
|
|
if str_eq(gender, "masculine") { return non_decline_masc(noun, gram_case, number) }
|
|
if str_eq(gender, "feminine") { return non_decline_fem(noun, gram_case, number) }
|
|
if str_eq(gender, "neuter") { return non_decline_neut(noun, gram_case, number) }
|
|
|
|
// Fallback
|
|
return noun
|
|
}
|
|
|
|
// ── Definite suffix table ──────────────────────────────────────────────────────
|
|
//
|
|
// Old Norse expresses definiteness via a suffix enclitic attached to the end of
|
|
// the inflected noun form (not a separate article). The suffix agrees with gender
|
|
// and case.
|
|
//
|
|
// Masculine singular: nom -inn gen -ins dat -inum acc -inn
|
|
// Neuter singular: nom -it gen -ins dat -inu acc -it
|
|
// Feminine singular: nom -in gen -innar dat -inni acc -ina
|
|
// Plural (all genders): nom/acc -inir (masc), -in (neut), -inar (fem)
|
|
// — simplified to -in for plural in this module.
|
|
|
|
fn non_def_suffix_masc(gram_case: String, number: String) -> String {
|
|
if str_eq(number, "singular") {
|
|
if str_eq(gram_case, "nominative") { return "inn" }
|
|
if str_eq(gram_case, "genitive") { return "ins" }
|
|
if str_eq(gram_case, "dative") { return "inum" }
|
|
if str_eq(gram_case, "accusative") { return "inn" }
|
|
return "inn"
|
|
}
|
|
// plural
|
|
if str_eq(gram_case, "nominative") { return "inir" }
|
|
if str_eq(gram_case, "accusative") { return "ina" }
|
|
if str_eq(gram_case, "genitive") { return "anna" }
|
|
if str_eq(gram_case, "dative") { return "unum" }
|
|
return "inir"
|
|
}
|
|
|
|
fn non_def_suffix_neut(gram_case: String, number: String) -> String {
|
|
if str_eq(number, "singular") {
|
|
if str_eq(gram_case, "nominative") { return "it" }
|
|
if str_eq(gram_case, "genitive") { return "ins" }
|
|
if str_eq(gram_case, "dative") { return "inu" }
|
|
if str_eq(gram_case, "accusative") { return "it" }
|
|
return "it"
|
|
}
|
|
// plural
|
|
if str_eq(gram_case, "nominative") { return "in" }
|
|
if str_eq(gram_case, "accusative") { return "in" }
|
|
if str_eq(gram_case, "genitive") { return "anna" }
|
|
if str_eq(gram_case, "dative") { return "unum" }
|
|
return "in"
|
|
}
|
|
|
|
fn non_def_suffix_fem(gram_case: String, number: String) -> String {
|
|
if str_eq(number, "singular") {
|
|
if str_eq(gram_case, "nominative") { return "in" }
|
|
if str_eq(gram_case, "genitive") { return "innar" }
|
|
if str_eq(gram_case, "dative") { return "inni" }
|
|
if str_eq(gram_case, "accusative") { return "ina" }
|
|
return "in"
|
|
}
|
|
// plural
|
|
if str_eq(gram_case, "nominative") { return "inar" }
|
|
if str_eq(gram_case, "accusative") { return "inar" }
|
|
if str_eq(gram_case, "genitive") { return "anna" }
|
|
if str_eq(gram_case, "dative") { return "innar" }
|
|
return "inar"
|
|
}
|
|
|
|
// ── non_noun_phrase: noun phrase builder ──────────────────────────────────────
|
|
//
|
|
// Old Norse definiteness is expressed through a suffix enclitic, not a separate
|
|
// article. For indefinite nouns the declined form is returned as-is.
|
|
//
|
|
// noun: nominative singular Old Norse noun (e.g. "armr", "land")
|
|
// gram_case: "nominative" | "accusative" | "genitive" | "dative"
|
|
// number: "singular" | "plural"
|
|
// definite: "true" | "false" (string comparison)
|
|
//
|
|
// Returns the complete noun phrase string.
|
|
|
|
fn non_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String {
|
|
let base: String = non_decline(noun, gram_case, number)
|
|
|
|
if !str_eq(definite, "true") { return base }
|
|
|
|
// Append the appropriate definite suffix.
|
|
let gender: String = non_detect_gender(noun)
|
|
|
|
if str_eq(gender, "masculine") {
|
|
return base + non_def_suffix_masc(gram_case, number)
|
|
}
|
|
if str_eq(gender, "neuter") {
|
|
return base + non_def_suffix_neut(gram_case, number)
|
|
}
|
|
if str_eq(gender, "feminine") {
|
|
return base + non_def_suffix_fem(gram_case, number)
|
|
}
|
|
|
|
// Fallback: append generic -inn
|
|
return base + "inn"
|
|
}
|