// surface-profile.el - Surface profile data and accessors. // // THE NATIVE EFFERENT SEAM: surface = a pluggable PROFILE, using the exact same // slot-map mechanism as language-profile.el. A language profile tells the // realizer HOW to shape a natural-language surface (word order, morphology); a // SURFACE profile tells the realizer WHICH surface to project meaning onto // (markdown, docx, html, plain, or a non-text medium like symbolic music). // // The generalization is exact: realize_lang(form, profile) already renders a // SemForm parameterized by a [String] profile read via lang_get. Surface is one // more axis of that same profile vector. One frame (sem_frame), one plan step // (sem_to_spec), one render (realize) — the surface is DATA, not a code path, // precisely as language is data. Adding a surface means adding a profile, no // engine change. This is the multimodal projector, native: geometry -> any // surface, the efferent twin of ingest. // // Surface slot keys: // surface - "markdown" | "docx" | "html" | "plain" | "midi" | "image" // modality - "text" | "audio" | "image" | "video" // media_type - MIME type of the emitted surface // head_open - string prepended to a heading (e.g. "## " for markdown) // head_close - string appended to a heading (e.g. "" for markdown, "" for html) // emph_open - string opening emphasis (e.g. "*") // emph_close - string closing emphasis (e.g. "*") // item_mark - list-item marker (e.g. "- ") // para_sep - paragraph separator (e.g. "\n\n") // // For a TEXT modality the render composes these markers around the surface that // the EXISTING realizer produces (realize_lang / sem_realize). For a non-text // modality (audio/image) the profile declares modality + media_type and the // render dispatches to the medium projector, which reads the SAME frame's // geometry (its intent/affect/structure) and projects it onto sound or pixels — // deterministic-from-meaning, nothing invented. That dispatch point is where a // music profile or image profile conforms, native, no parallel layer. // -- Constructor ------------------------------------------------------------- fn surface_profile(surface: String, modality: String, media_type: String, head_open: String, head_close: String, emph_open: String, emph_close: String, item_mark: String, para_sep: String) -> [String] { let r: [String] = native_list_empty() let r = native_list_append(r, "surface") let r = native_list_append(r, surface) let r = native_list_append(r, "modality") let r = native_list_append(r, modality) let r = native_list_append(r, "media_type") let r = native_list_append(r, media_type) let r = native_list_append(r, "head_open") let r = native_list_append(r, head_open) let r = native_list_append(r, "head_close") let r = native_list_append(r, head_close) let r = native_list_append(r, "emph_open") let r = native_list_append(r, emph_open) let r = native_list_append(r, "emph_close") let r = native_list_append(r, emph_close) let r = native_list_append(r, "item_mark") let r = native_list_append(r, item_mark) let r = native_list_append(r, "para_sep") let r = native_list_append(r, para_sep) return r } // -- Accessor (same convention as lang_get; standalone so this is a leaf) ----- fn surface_get(profile: [String], key: String) -> String { let n: Int = native_list_len(profile) let i: Int = 0 while i < n - 1 { let k: String = native_list_get(profile, i) if str_eq(k, key) { return native_list_get(profile, i + 1) } let i = i + 2 } return "" } fn surface_is_text(profile: [String]) -> Bool { return str_eq(surface_get(profile, "modality"), "text") } // -- Built-in TEXT surface profiles ------------------------------------------ // Markdown: headings with "## ", emphasis with "*", "- " list items. fn surface_profile_markdown() -> [String] { return surface_profile("markdown", "text", "text/markdown", "## ", "", "*", "*", "- ", "\n\n") } // Plain text: no markup at all — headings become bare uppercase-free lines. fn surface_profile_plain() -> [String] { return surface_profile("plain", "text", "text/plain", "", "", "", "", " - ", "\n\n") } // HTML: block-level heading/emphasis tags. fn surface_profile_html() -> [String] { return surface_profile("html", "text", "text/html", "