// 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, ...) import "language-profile.el" import "morphology.el" // ── 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" } 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" } 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 + "." } // ── 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 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(location, "") { let parts = native_list_append(parts, location) } 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)) }