// realizer.el - Universal syntactic realizer: GramSpec -> surface text. // // The realizer is now language-agnostic. It reads the "lang" field from the // GramSpec to resolve a language profile, then dispatches word order, question // formation, and morphology through the engine functions in grammar.el and // morphology.el. // // English remains the default (backward compatible) when no "lang" key is set. // // Realization pipeline per call: // 1. Extract lang code -> resolve profile // 2. Extract agent, predicate, patient, location, tense, aspect, intent // 3. Compute person/number from agent (English heuristic; other languages TBD) // 4. Build VP: morph_conjugate with profile -> get verb and auxiliary surface // 5. Choose question strategy from gram_question_strategy(profile) // 6. Order constituents via gram_order_constituents(subj, verb, obj, profile) // 7. Capitalize and terminate // // Depends on: morphology (morph_conjugate, agree_determiner) // grammar (gram_order_constituents, gram_question_strategy, // gram_build_vp, build_np, build_pp, slots_get) // language-profile (lang_from_code, lang_get, ...) // ── Agent agreement analysis ────────────────────────────────────────────────── // // Person and number are inferred from English pronouns. For other languages // the grammatical person/number should come from the Engram vocabulary node // for the subject; here we use a heuristic that is correct for English and // passable for languages where the same pronoun strings are used. fn agent_person(agent: String) -> String { if str_eq(agent, "I") { return "first" } if str_eq(agent, "me") { return "first" } if str_eq(agent, "we") { return "first" } if str_eq(agent, "us") { return "first" } if str_eq(agent, "you") { return "second" } // Romance target-language subject pronouns (translate.el sets these). if str_eq(agent, "yo") { return "first" } if str_eq(agent, "eu") { return "first" } if str_eq(agent, "nosotros") { return "first" } if str_eq(agent, "nós") { return "first" } if str_eq(agent, "tú") { return "second" } if str_eq(agent, "tu") { return "second" } return "third" } fn agent_number(agent: String) -> String { if str_eq(agent, "I") { return "singular" } if str_eq(agent, "me") { return "singular" } if str_eq(agent, "he") { return "singular" } if str_eq(agent, "him") { return "singular" } if str_eq(agent, "she") { return "singular" } if str_eq(agent, "her") { return "singular" } if str_eq(agent, "it") { return "singular" } if str_eq(agent, "you") { return "singular" } if str_eq(agent, "we") { return "plural" } if str_eq(agent, "us") { return "plural" } if str_eq(agent, "they") { return "plural" } if str_eq(agent, "them") { return "plural" } // Romance target-language subject pronouns. if str_eq(agent, "yo") { return "singular" } if str_eq(agent, "eu") { return "singular" } if str_eq(agent, "tú") { return "singular" } if str_eq(agent, "tu") { return "singular" } if str_eq(agent, "él") { return "singular" } if str_eq(agent, "ella") { return "singular" } if str_eq(agent, "ele") { return "singular" } if str_eq(agent, "ela") { return "singular" } if str_eq(agent, "nosotros") { return "plural" } if str_eq(agent, "nós") { return "plural" } if str_eq(agent, "ellos") { return "plural" } if str_eq(agent, "eles") { return "plural" } return "singular" } // ── NP realization ──────────────────────────────────────────────────────────── fn realize_np(referent: String, number: String) -> String { return referent } // ── VP realization ──────────────────────────────────────────────────────────── // // Returns [main_verb_surface, aux_surface_or_empty]. // Delegates conjugation to morph_conjugate with the language profile. fn realize_vp_lang(base_verb: String, tense: String, aspect: String, person: String, number: String, profile: [String]) -> [String] { let empty_aux: String = "" if str_eq(tense, "future") { // Future: modal "will" + base (English) or language-specific future marker. // For isolating/agglutinative languages the future marker is also the // base form (morph_conjugate returns base); the surface "will" only appears // for English because morph_conjugate("be", "future", ..., en_profile) = "will be". let code: String = lang_get(profile, "code") if str_eq(code, "en") { let result: [String] = native_list_empty() let result = native_list_append(result, base_verb) let result = native_list_append(result, "will") return result } // Other languages: conjugate normally (engine returns base form for // languages without loaded Engram suffix data). let surf: String = morph_conjugate(base_verb, tense, person, number, profile) let result: [String] = native_list_empty() let result = native_list_append(result, surf) let result = native_list_append(result, empty_aux) return result } if str_eq(aspect, "progressive") { let gerund: String = morph_conjugate(base_verb, "progressive", person, number, profile) let be_aux: String = morph_conjugate("be", tense, person, number, profile) let result: [String] = native_list_empty() let result = native_list_append(result, gerund) let result = native_list_append(result, be_aux) return result } if str_eq(aspect, "perfect") { let pp: String = morph_conjugate(base_verb, "perfect", person, number, profile) let have_form: String = morph_conjugate("have", tense, person, number, profile) let result: [String] = native_list_empty() let result = native_list_append(result, pp) let result = native_list_append(result, have_form) return result } let surf: String = morph_conjugate(base_verb, tense, person, number, profile) let result: [String] = native_list_empty() let result = native_list_append(result, surf) let result = native_list_append(result, empty_aux) return result } // ── Question formation ──────────────────────────────────────────────────────── // // Strategy is resolved from gram_question_strategy(profile): // // "do-support" (en) - insert conjugated "do" before subject; verb stays base. // "particle" (ja, hi, fi) - statement order + sentence-final question particle. // "intonation" (zh, es, ar, ru, sw) - statement order + "?" punctuation only. // "inversion" (fr, de) - subject-verb inversion. // realize_question_lang: build the question surface string for any language. // Returns the complete surface string (without final punctuation). fn realize_question_lang(predicate: String, tense: String, aspect: String, person: String, number: String, agent: String, patient: String, location: String, profile: [String]) -> String { let strategy: String = gram_question_strategy(profile) let code: String = lang_get(profile, "code") // ── do-support (English) ────────────────────────────────────────────────── if str_eq(strategy, "do-support") { if str_eq(aspect, "progressive") { let vp_pair: [String] = realize_vp_lang(predicate, tense, "progressive", person, number, profile) let gerund: String = native_list_get(vp_pair, 0) let be_aux: String = native_list_get(vp_pair, 1) let parts: [String] = native_list_empty() let parts = native_list_append(parts, be_aux) let parts = native_list_append(parts, agent) let parts = native_list_append(parts, gerund) if !str_eq(patient, "") { let parts = native_list_append(parts, patient) } if !str_eq(location, "") { let parts = native_list_append(parts, location) } return str_join(parts, " ") } if str_eq(aspect, "perfect") { let vp_pair: [String] = realize_vp_lang(predicate, tense, "perfect", person, number, profile) let pp: String = native_list_get(vp_pair, 0) let have_aux: String = native_list_get(vp_pair, 1) let parts: [String] = native_list_empty() let parts = native_list_append(parts, have_aux) let parts = native_list_append(parts, agent) let parts = native_list_append(parts, pp) if !str_eq(patient, "") { let parts = native_list_append(parts, patient) } if !str_eq(location, "") { let parts = native_list_append(parts, location) } return str_join(parts, " ") } // Simple: do-support if str_eq(predicate, "be") { let be_form: String = morph_conjugate("be", tense, person, number, profile) let parts: [String] = native_list_empty() let parts = native_list_append(parts, be_form) let parts = native_list_append(parts, agent) if !str_eq(patient, "") { let parts = native_list_append(parts, patient) } if !str_eq(location, "") { let parts = native_list_append(parts, location) } return str_join(parts, " ") } let do_form: String = morph_conjugate("do", tense, person, number, profile) let parts: [String] = native_list_empty() let parts = native_list_append(parts, do_form) let parts = native_list_append(parts, agent) let parts = native_list_append(parts, predicate) if !str_eq(patient, "") { let parts = native_list_append(parts, patient) } if !str_eq(location, "") { let parts = native_list_append(parts, location) } return str_join(parts, " ") } // ── particle (ja, hi, fi) ───────────────────────────────────────────────── // Build in statement order, then append the question particle. if str_eq(strategy, "particle") { let vp_pair: [String] = realize_vp_lang(predicate, tense, aspect, person, number, profile) let verb_s: String = native_list_get(vp_pair, 0) let aux_s: String = native_list_get(vp_pair, 1) let vp_str: String = gram_build_vp(verb_s, aux_s, profile) let core: String = gram_order_constituents(agent, vp_str, patient, profile) let loc_part: String = "" if !str_eq(location, "") { let loc_part = core + " " + location } else { let loc_part = core } // Language-specific question particles if str_eq(code, "ja") { return loc_part + " か" } if str_eq(code, "hi") { return loc_part + " क्या" } if str_eq(code, "fi") { return loc_part + "-ko" } return loc_part + "?" } // ── inversion (fr, de) ──────────────────────────────────────────────────── if str_eq(strategy, "inversion") { let vp_pair: [String] = realize_vp_lang(predicate, tense, aspect, person, number, profile) let verb_s: String = native_list_get(vp_pair, 0) let aux_s: String = native_list_get(vp_pair, 1) // Inversion: Verb-Subject-Object order let parts: [String] = native_list_empty() if !str_eq(aux_s, "") { let parts = native_list_append(parts, aux_s) } else { let parts = native_list_append(parts, verb_s) } let parts = native_list_append(parts, agent) if !str_eq(aux_s, "") { let parts = native_list_append(parts, verb_s) } if !str_eq(patient, "") { let parts = native_list_append(parts, patient) } if !str_eq(location, "") { let parts = native_list_append(parts, location) } return str_join(parts, " ") } // ── intonation (zh, es, ar, ru, sw) — statement order, "?" added by caller ─ let vp_pair: [String] = realize_vp_lang(predicate, tense, aspect, person, number, profile) let verb_s: String = native_list_get(vp_pair, 0) let aux_s: String = native_list_get(vp_pair, 1) let vp_str: String = gram_build_vp(verb_s, aux_s, profile) let core: String = gram_order_constituents(agent, vp_str, patient, profile) if !str_eq(location, "") { return core + " " + location } return core } // ── Capitalization and punctuation ──────────────────────────────────────────── fn capitalize_first(s: String) -> String { let n: Int = str_len(s) if n == 0 { return s } let first: String = str_slice(s, 0, 1) let rest: String = str_slice(s, 1, n) return str_to_upper(first) + rest } fn add_punct(s: String, intent: String) -> String { if str_eq(intent, "question") { return s + "?" } return s + "." } // ── Polarity-aware negation (SACRED field honored on the generation side) ───── // // Negation must never be dropped between comprehension and realization. The // meaning-spec carries an explicit "polarity" field ("aff"|"neg") and optional // "neg_word" (standalone negative adverb, e.g. "never"). English uses // do-support ("did not see") or preverbal adverb ("never fought"); copular "be" // takes post-verbal "not"; other languages get a preverbal negator particle. fn realize_negator(code: String) -> String { if str_eq(code, "es") { return "no" } if str_eq(code, "pt") { return "não" } if str_eq(code, "ca") { return "no" } if str_eq(code, "it") { return "non" } if str_eq(code, "fr") { return "ne" } if str_eq(code, "de") { return "nicht" } if str_eq(code, "ro") { return "nu" } return "not" } fn realize_assert_neg_en(predicate: String, tense: String, person: String, number: String, agent: String, patient: String, iobj: String, location: String, neg_word: String, profile: [String]) -> String { let parts: [String] = native_list_empty() let parts = native_list_append(parts, agent) if !str_eq(neg_word, "") { // adverbial negation: "I never fought the ocean." let verb_surf: String = morph_conjugate(predicate, tense, person, number, profile) let parts = native_list_append(parts, neg_word) let parts = native_list_append(parts, verb_surf) } else { if str_eq(predicate, "be") { // copular: "she was not a monster" let be_form: String = morph_conjugate("be", tense, person, number, profile) let parts = native_list_append(parts, be_form) let parts = native_list_append(parts, "not") } else { // do-support: "she did not see the man" let do_form: String = morph_conjugate("do", tense, person, number, profile) let parts = native_list_append(parts, do_form) let parts = native_list_append(parts, "not") let parts = native_list_append(parts, predicate) } } if !str_eq(patient, "") { let parts = native_list_append(parts, patient) } if !str_eq(iobj, "") { let parts = native_list_append(parts, "to") let parts = native_list_append(parts, iobj) } if !str_eq(location, "") { let parts = native_list_append(parts, location) } return str_join(parts, " ") } // ── Main realization entry point ────────────────────────────────────────────── fn realize_lang(form: [String], profile: [String]) -> String { let intent: String = slots_get(form, "intent") let agent: String = slots_get(form, "agent") let predicate: String = slots_get(form, "predicate") let patient: String = slots_get(form, "patient") let location: String = slots_get(form, "location") let tense_raw: String = slots_get(form, "tense") let aspect_raw: String= slots_get(form, "aspect") let tense: String = tense_raw if str_eq(tense, "") { let tense = "present" } let aspect: String = aspect_raw if str_eq(aspect, "") { let aspect = "simple" } let person: String = agent_person(agent) let number: String = agent_number(agent) // ── Command (imperative) ────────────────────────────────────────────────── if str_eq(intent, "command") { let parts: [String] = native_list_empty() let parts = native_list_append(parts, predicate) if !str_eq(patient, "") { let parts = native_list_append(parts, patient) } if !str_eq(location, "") { let parts = native_list_append(parts, location) } let sentence: String = str_join(parts, " ") return add_punct(capitalize_first(sentence), "command") } // ── Question ────────────────────────────────────────────────────────────── if str_eq(intent, "question") { let surface: String = realize_question_lang(predicate, tense, aspect, person, number, agent, patient, location, profile) return add_punct(capitalize_first(surface), "question") } // ── Assertion (declarative) ─────────────────────────────────────────────── let polarity: String = slots_get(form, "polarity") let neg_word: String = slots_get(form, "neg_word") let iobj: String = slots_get(form, "iobj") let code: String = lang_get(profile, "code") // Subordinate clause tail (SACRED completeness — the clause is carried, never // dropped): " ", e.g. "because he was a monster". let subord_conj: String = slots_get(form, "subord_conj") let subord_text: String = slots_get(form, "subord_text") let subord_tail: String = "" if !str_eq(subord_conj, "") { if !str_eq(subord_text, "") { let subord_tail = subord_conj + " " + subord_text } else { let subord_tail = subord_conj } } // Negative polarity: SACRED — never dropped. if str_eq(polarity, "neg") { if str_eq(code, "en") { let sentence: String = realize_assert_neg_en(predicate, tense, person, number, agent, patient, iobj, location, neg_word, profile) return add_punct(capitalize_first(sentence), "assert") } // Generic non-English: affirmative core with a preverbal negator particle. // SACRED: when a standalone negative adverb was carried (e.g. "nunca", // localized upstream from "never"), surface it rather than the generic // negator — the specific negation must never be flattened away. let neg_particle: String = realize_negator(code) if !str_eq(neg_word, "") { let neg_particle = neg_word } let vp_pair: [String] = realize_vp_lang(predicate, tense, aspect, person, number, profile) let verb_surf: String = native_list_get(vp_pair, 0) let aux_surf: String = native_list_get(vp_pair, 1) let vp_str: String = neg_particle + " " + gram_build_vp(verb_surf, aux_surf, profile) let core: String = gram_order_constituents(agent, vp_str, patient, profile) let parts: [String] = native_list_empty() let parts = native_list_append(parts, core) if !str_eq(iobj, "") { let parts = native_list_append(parts, "to") let parts = native_list_append(parts, iobj) } if !str_eq(location, "") { let parts = native_list_append(parts, location) } if !str_eq(subord_tail, "") { let parts = native_list_append(parts, subord_tail) } let sentence: String = str_join(parts, " ") return add_punct(capitalize_first(sentence), "assert") } // Affirmative. let vp_pair: [String] = realize_vp_lang(predicate, tense, aspect, person, number, profile) let verb_surf: String = native_list_get(vp_pair, 0) let aux_surf: String = native_list_get(vp_pair, 1) let vp_str: String = gram_build_vp(verb_surf, aux_surf, profile) let core: String = gram_order_constituents(agent, vp_str, patient, profile) let parts: [String] = native_list_empty() let parts = native_list_append(parts, core) if !str_eq(iobj, "") { let parts = native_list_append(parts, "to") let parts = native_list_append(parts, iobj) } if !str_eq(location, "") { let parts = native_list_append(parts, location) } if !str_eq(subord_tail, "") { let parts = native_list_append(parts, subord_tail) } let sentence: String = str_join(parts, " ") return add_punct(capitalize_first(sentence), "assert") } // realize: backward-compatible English entry point (original signature). fn realize(form: [String]) -> String { let lang_code: String = slots_get(form, "lang") if str_eq(lang_code, "") { return realize_lang(form, lang_default()) } return realize_lang(form, lang_from_code(lang_code)) }