Saltar al contenido
Ridgun
Español

23 El Libro de Ridgun

La lib fmt — Formateador Tabular Canónico 2D y Resaltador de Sintaxis en 9 Formatos

23.1. ¿Por qué existe la lib fmt? (El problema real y la filosofía Ridgun)

«¿Por qué necesito una lib fmt escrita desde cero en Ridgun puro en lugar de enlazar una librería de C de toda la vida?»

Esa es la primera pregunta que se hace cualquier ingeniero de sistemas al llegar a fmt. Y la respuesta resume toda la filosofía de ridgun-libs:

Seamos sinceros: la belleza del código Ridgun reside en sus columnas tabulares perfectamente alineadas (::, =, |, ->, --), pero alinear espacios a mano o exportar código coloreado para terminal, HTML y LaTeX sin una herramienta dedicada es tedioso.

La lib fmt es el motor oficial de formateo tabular 2D y resaltado léxico de Ridgun: alinea firmas fn ::, ecuaciones, guardas | y comentarios --, y exporta a 9 formatos de salida (FmtPlain, FmtTty, FmtTrueColor, FmtHtmlInline, FmtHtmlCss, FmtMarkdown, FmtPango, FmtLatex, FmtRtf).

En un ecosistema tradicional, resolver las tareas del dominio FMT implica arrastrar dependencias externas en C, lidiar con punteros crudos, conversiones opacas de tipos, excepciones no verificadas o pausas impredecibles del recolector de basura. En Ridgun, la lib fmt (src/main/ridgun/lib/fmt.rg) aborda el problema con cuatro principios innegociables:

  1. Declara import fmt (o import fmt as alias) al inicio del archivo: cada lib define su espacio de nombres module :: fmt y en modo --strict las funciones multi-palabra se invocan siempre con espacios naturales.
  2. Encadena tus tuberías de izquierda a derecha con ->: escribe entrada paso uno -> paso dos -> resultado, usa máscaras (+ _ _ +) para desestructurar secuencias y omite _ = en sentencias secuenciales (o descarta con -> ()).
  3. Recursión de cola con TCO (Tail-Call Optimization): todos los recorridos internos de fmt se compilan a bucles nativos en $O(1)$ espacio de pila.
  4. Memoria determinista (RMM1 / RMM2): cada estructura intermedia se libera en el instante exacto en que termina su última lectura, sin Garbage Collector.

23.2. Artefactos nativos, importación y catálogo completo de la API de fmt

En ridgun-libs, fmt es una lib de primera clase ubicada en src/main/ridgun/lib/fmt.rg (dominio FMT). Al compilar con stable bundle, se empaqueta en tres artefactos nativos:

ArtefactoRutaPropósito
Bundle Ridguntarget/bundles/fmt.rglibDistribución e importación directa con import fmt
Archivo compiladotarget/fmt.rgcArtefacto intermedio verificado por ridgunc
Objeto compartido ELF64target/libfmt.soBiblioteca dinámica nativa sin dependencias de C ni libc

Cada lib declara su propio espacio de nombres con module :: fmt: basta con escribir import fmt (o import fmt as alias) en el encabezado y llamar a sus funciones con espacios naturales (mi funcion x) y tuberías -> (x mi funcion -> resultado).

23.2.1. Resumen de familias funcionales de fmt

Firma / Función / TipoQué hace y cuándo usarla
fmt source / fmt source withFormatea código fuente Ridgun usando la alineación tabular 2D canónica
fmt checkDevuelve True si el código ya cumple el formato tabular canónico de fmt source
fmt render / fmt render withFormatea y colorea el código hacia cualquiera de los 9 formatos FmtTarget
fmt tokenize lineTokeniza una línea en TokKeyword, TokType, TokOperator, TokString, TokNumber, TokComment

23.2.2. Catálogo exhaustivo de tipos y firmas en src/main/ridgun/lib/fmt.rg

A continuación tienes el inventario completo de tipos algebraicos (type), operadores (op ::) y firmas de funciones (fn ::) definidos en src/main/ridgun/lib/fmt.rg (7 tipos, 0 operadores y 166 funciones):

Tipos algebraicos y registros (type) de fmt:

type FmtTarget = FmtPlain | FmtTty | FmtTrueColor | FmtHtmlInline | FmtHtmlCss | FmtMarkdown | FmtPango | FmtLatex | FmtRtf
type FmtTheme = FmtThemeNone | FmtThemeDark | FmtThemeLight
type FmtConfig = indent_width: Int, max_align_params: Int, max_line_width: Int, is_aligned: Bool, target_format: FmtTarget, color_theme: FmtTheme
type FmtToken = FmtTok String Int
type FmtSig = NoSig | SigInfo String [String] String String [Int] Int Int
type FmtClause = NoClause | ClauseInfo [String] Bool String
type FmtWhereBind = NoWhereBind | WhereBindInfo String String
#Función / Firma (fn ::)Tipo de Retorno
1fn :: default fmt configFmtConfig
2fn :: fmt config Int Int Int Bool FmtTarget FmtThemeFmtConfig
3fn :: fmt max Int IntInt
4fn :: fmt str list len [String]Int
5fn :: fmt str head [String]String
6fn :: fmt int at [Int] IntInt
7fn :: fmt spaces IntString
8fn :: fmt is hspace IntBool
9fn :: fmt leading indent loop String Int IntInt
10fn :: fmt leading indent StringInt
11fn :: fmt trim left loop String Int IntString
12fn :: fmt trim left StringString
13fn :: fmt trim right loop String IntString
14fn :: fmt trim right StringString
15fn :: fmt trim StringString
16fn :: fmt split raw lines loop String Int Int Int Int [String][String]
17fn :: fmt split raw lines String[String]
18fn :: fmt join lines [String]String
19fn :: fmt skip quoted String Int Int IntInt
20fn :: fmt find comment col String Int IntInt
21fn :: fmt strip comment StringString
22fn :: fmt strip comment at String IntString
23fn :: fmt extract comment StringString
24fn :: fmt extract comment at String IntString
25fn :: fmt skip hspace String Int IntInt
26fn :: fmt scan group end String Int Int IntInt
27fn :: fmt scan word end String Int Int IntInt
28fn :: fmt scan token end String Int Int IntInt
29fn :: fmt scan tokens loop String Int Int [FmtToken][FmtToken]
30fn :: fmt scan tokens at String Int Int [FmtToken][FmtToken]
31fn :: fmt scan tokens at step String Int Int [FmtToken] Int[FmtToken]
32fn :: fmt scan tokens String[FmtToken]
33fn :: fmt split sig arrow [FmtToken] [String](Bool, [String], String, Int)
34fn :: fmt is sig type tok StringBool
35fn :: fmt all type toks [String]Bool
36fn :: fmt is bare fn lhs [String]Bool
37fn :: fmt infer bare kind [String]String
38fn :: fmt parse sig line StringFmtSig
39fn :: fmt parse sig tokens Int String String [FmtToken]FmtSig
40fn :: fmt finish bare sig parse String String (Bool, [String], String, Int)FmtSig
41fn :: fmt finish sig parse String String String (Bool, [String], String, Int)FmtSig
42fn :: fmt append comment String StringString
43fn :: fmt has fat arrow [FmtToken]Bool
44fn :: fmt is top decl line StringBool
45fn :: fmt is top decl toks Int String [FmtToken]Bool
46fn :: fmt op tokens match [String] [String]Bool
47fn :: fmt is bare kind StringBool
48fn :: fmt sig base col StringInt
49fn :: fmt sig base col from FmtSigInt
50fn :: fmt clause matches sig String [String] [String]Bool
51fn :: fmt split clause eq [FmtToken] [String]([String], Bool, Int)
52fn :: fmt next nonblank is guard [String]Bool
53fn :: fmt check guard line String [String]Bool
54fn :: fmt parse clause line FmtSig String BoolFmtClause
55fn :: fmt parse clause clean String [String] String String String BoolFmtClause
56fn :: fmt check clause split String [String] String Bool ([String], Bool, Int)FmtClause
57fn :: fmt build clause info String [String] Bool IntFmtClause
58fn :: fmt find where arrow [FmtToken]Int
59fn :: fmt parse where line String BoolFmtWhereBind
60fn :: fmt parse where clean String String StringFmtWhereBind
61fn :: fmt build where bind String String IntFmtWhereBind
62fn :: fmt check where nonempty String StringFmtWhereBind
63fn :: fmt map str lens [String][Int]
64fn :: fmt slot width Int IntInt
65fn :: fmt max widths [Int] [String][Int]
66fn :: fmt build col starts [Int] Int[Int]
67fn :: fmt end col [Int] IntInt
68fn :: fmt scan group widths FmtSig [String] [Int] Int Bool Int([Int], Int)
69fn :: fmt scan group step FmtSig String [String] [Int] Int Bool Int FmtClause FmtWhereBind([Int], Int)
70fn :: fmt compute group geometry FmtSig [String] FmtConfigFmtSig
71fn :: fmt count op params [String]Int
72fn :: fmt count sig params String [String]Int
73fn :: fmt finish group geometry String [String] String String ([Int], Int) FmtConfigFmtSig
74fn :: fmt select group geometry String [String] String String [Int] Int Int Int Int FmtConfigFmtSig
75fn :: fmt pad lhs tokens [String] [Int] Int StringString
76fn :: fmt sig prefix String StringString
77fn :: fmt format sig line FmtSigString
78fn :: fmt format clause line FmtSig [String] Bool StringString
79fn :: fmt finish clause rhs String Bool String Int IntString
80fn :: fmt format where line FmtSig String String IntString
81fn :: fmt line opens block StringBool
82fn :: fmt check block opener String IntBool
83fn :: fmt line closes block StringBool
84fn :: fmt guard indent Int Int Int String IntInt
85fn :: fmt guard indent clean Int Int Int String String IntInt
86fn :: fmt format group body FmtSig [String] Int String Bool FmtConfig[String]
87fn :: fmt format group line FmtSig String String String Int [String] Int String Bool FmtConfig FmtClause FmtWhereBind[String]
88fn :: fmt format guard line FmtSig String Int [String] Int String FmtConfig Int[String]
89fn :: fmt next body indent Int String IntInt
90fn :: fmt next body indent clean Int String String IntInt
91fn :: fmt indent body line Int String String IntString
92fn :: fmt take group lines [String] [String]([String], [String])
93fn :: fmt format top lines [String] Int String FmtConfig[String]
94fn :: fmt dispatch top line String [String] Int String FmtConfig FmtSig[String]
95fn :: fmt run sig group FmtSig ([String], [String]) FmtConfig[String]
96fn :: fmt format non sig top String [String] Int String FmtConfig[String]
97fn :: fmt is digit IntBool
98fn :: fmt is upper IntBool
99fn :: fmt is lower IntBool
100fn :: fmt is ident char IntBool
101fn :: fmt is keyword StringBool
102fn :: fmt is logic op StringBool
103fn :: fmt is bool lit StringBool
104fn :: fmt classify word String BoolString
105fn :: fmt escape html loop String Int Int StringString
106fn :: fmt escape html StringString
107fn :: fmt escape latex loop String Int Int StringString
108fn :: fmt escape latex StringString
109fn :: fmt escape rtf loop String Int Int StringString
110fn :: fmt escape rtf StringString
111fn :: fmt escape for target String FmtTargetString
112fn :: fmt cat css class StringString
113fn :: fmt cat ansi16 StringString
114fn :: fmt cat rgb String FmtThemeString
115fn :: fmt cat hex String FmtThemeString
116fn :: fmt cat is bold StringBool
117fn :: fmt cat rtf idx StringString
118fn :: fmt span css String StringString
119fn :: fmt span tty String StringString
120fn :: fmt span truecolor String String BoolString
121fn :: fmt span html inline String String BoolString
122fn :: fmt span pango String String BoolString
123fn :: fmt span latex String String BoolString
124fn :: fmt span rtf String String BoolString
125fn :: fmt render span String String FmtTarget FmtThemeString
126fn :: fmt scan ident end String Int IntInt
127fn :: fmt scan space end String Int IntInt
128fn :: fmt find close brace String Int IntInt
129fn :: fmt render nonempty String String FmtTarget FmtThemeString
130fn :: fmt highlight dquote brace String Int Int Int Int FmtTarget FmtTheme StringString
131fn :: fmt highlight dquote loop String Int Int Int FmtTarget FmtTheme StringString
132fn :: fmt multi op at String Int IntString
133fn :: fmt is single op IntBool
134fn :: fmt comment cat StringString
135fn :: fmt hl space step String Int Int Bool FmtTarget FmtTheme String IntString
136fn :: fmt hl dquote step String Int Int FmtTarget FmtTheme String IntString
137fn :: fmt hl squote step String Int Int FmtTarget FmtTheme String IntString
138fn :: fmt hl pragma step String Int Int FmtTarget FmtTheme String IntString
139fn :: fmt hl mop step String Int Int FmtTarget FmtTheme String StringString
140fn :: fmt hl ident step String Int Int Bool FmtTarget FmtTheme String IntString
141fn :: fmt highlight line loop String Int Int Bool FmtTarget FmtTheme StringString
142fn :: fmt line starts clause StringBool
143fn :: fmt map tok strs [FmtToken][String]
144fn :: fmt highlight line String FmtTarget FmtThemeString
145fn :: fmt highlight lines [String] FmtTarget FmtTheme[String]
146fn :: fmt join rtf lines [String]String
147fn :: fmt html pre open FmtThemeString
148fn :: fmt rtf colortbl FmtThemeString
149fn :: fmt wrap target doc [String] FmtTarget FmtThemeString
150fn :: fmt html stylesheet FmtThemeString
151fn :: fmt source with config String FmtConfigString
152fn :: format ridgun source StringString
153fn :: fmt to tty with theme String FmtThemeString
154fn :: fmt to tty StringString
155fn :: fmt to truecolor with theme String FmtThemeString
156fn :: fmt to truecolor StringString
157fn :: fmt to html with theme String FmtThemeString
158fn :: fmt to html StringString
159fn :: fmt to html css StringString
160fn :: fmt to markdown StringString
161fn :: fmt to pango with theme String FmtThemeString
162fn :: fmt to pango StringString
163fn :: fmt to latex with theme String FmtThemeString
164fn :: fmt to latex StringString
165fn :: fmt to rtf with theme String FmtThemeString
166fn :: fmt to rtf StringString

23.3. Explorando fmt a fondo: Ejemplos paso a paso de cada funcionalidad

No basta con ver la tabla de firmas: vamos a explorar cada una de las funcionalidades de la lib fmt mediante ejemplos progresivos y ejecutables en Ridgun. Empezaremos por las dos recetas tabulares de uso cotidiano y después recorreremos en detalle todos los escenarios funcionales, transformaciones y casos límite verificados en src/test/ridgun/test fmt.rg.

23.3.1. Ejemplo 1: Flujo principal en estilo tabular con fmt

Observa cómo en Ridgun los signos = y los pasos de transformación con fmt quedan alineados como una tabla limpia, sin variables mutables innecesarias ni efectos laterales ocultos:

import fmt

fn :: formatear y verificar String => String Bool
      formatear y verificar codigo =
        codigo fmt ridgun -> limpio
        limpio fmt check ridgun -> es_ok
        (limpio, es_ok)

23.3.2. Ejemplo 2: Composición segura y manejo de casos de borde

Toda función de la lib fmt está diseñada para componerse con guardas booleanas | y con el resto de las 32 libs de ridgun-libs:

import fmt

fn :: exportar bloque html String => String
      exportar bloque html codigo =
        fmt highlight ridgun codigo FmtHtmlCss

23.3.3. Ejemplo 3: Alineación tabular canónica (fmt ridgun, fmt ridgun with) de firmas =>, cláusulas =, enlaces -> y comentarios --

En este ejemplo práctico exploramos de forma exhaustiva cómo se comporta fmt en este bloque funcional, incluyendo entradas estándar, combinaciones de parámetros y valores frontera:

fn :: test fmt canonical alignment and config => ()
      test fmt canonical alignment and config =
        nl = char from code 10
        raw_src = "fn :: add Int Int => Int" + nl + "add x y = x + y" + nl + "add 0 y_long = y_long" + nl
        expected_2d = "fn :: add Int Int    => Int" + nl + "      add x   y      =  x + y" + nl + "      add 0   y_long =  y_long" + nl
        out_2d = format ridgun source raw_src
        assert str eq out_2d expected_2d "AC1: canonical 2D tabular alignment"

        -- Unaligned config (`is_aligned = False`) uses single-space separation
        cfg_unaligned = fmt config 2 4 80 False FmtPlain FmtThemeNone
        out_unaligned = fmt source with config raw_src cfg_unaligned
        expected_unaligned = "fn :: add Int Int => Int" + nl + "      add x y = x + y" + nl + "      add 0 y_long = y_long" + nl
        assert str eq out_unaligned expected_unaligned "AC1: unaligned FmtConfig"

        -- Guard and `where` alignment with custom indent_width = 4
        guard_src = "fn :: clamp Int => Int" + nl + "clamp x" + nl + "| x < 0 = 0" + nl + "| otherwise = x" + nl + "where" + nl + "lo -> 0" + nl
        cfg_ind4 = fmt config 4 4 80 True FmtPlain FmtThemeNone
        out_ind4 = fmt source with config guard_src cfg_ind4
        assert true (str contains out_ind4 "          | x < 0 = 0") "AC1: custom indent_width = 4 guard indentation"
        assert true (str contains out_ind4 "              lo -> 0") "AC1: custom indent_width = 4 where binding alignment"
        ()

23.3.4. Ejemplo 4: Resaltado léxico ANSI de 16 colores y TrueColor de 24 bits con detección automática de TTY y NO_COLOR

En este ejemplo práctico exploramos de forma exhaustiva cómo se comporta fmt en este bloque funcional, incluyendo entradas estándar, combinaciones de parámetros y valores frontera:

fn :: test fmt terminal highlighting tty and truecolor => ()
      test fmt terminal highlighting tty and truecolor =
        nl = char from code 10
        esc = char from code 27
        interp_tok = (char from code 123) + "name" + (char from code 125)
        sample = "-- @implements FR-FMT-001" + nl + "-- comment line" + nl + "fn :: greet String => String" + nl + "greet name = \"Hello " + interp_tok + "\" + (int_to_str 0x2A)" + nl

        tty_dark = fmt to tty sample
        assert true (str contains tty_dark (esc + "[1;32m-- @implements FR-FMT-001" + esc + "[0m")) "AC2: TTY pragma highlight"
        assert true (str contains tty_dark (esc + "[90m-- comment line" + esc + "[0m")) "AC2: TTY comment highlight"
        assert true (str contains tty_dark (esc + "[1;35mfn" + esc + "[0m")) "AC2: TTY keyword highlight"
        assert true (str contains tty_dark (esc + "[1;34mgreet" + esc + "[0m")) "AC2: TTY function name highlight"
        assert true (str contains tty_dark (esc + "[33mString" + esc + "[0m")) "AC2: TTY type highlight"
        assert true (str contains tty_dark (esc + "[36m" + interp_tok + esc + "[0m")) "AC2: TTY string interpolation highlight"
        assert true (str contains tty_dark (esc + "[36m0x2A" + esc + "[0m")) "AC2: TTY hex number highlight"

        tty_none = fmt to tty with theme sample FmtThemeNone
        assert false (str contains tty_none esc) "AC2: FmtThemeNone emits no ANSI escape codes"

        tc_dark = fmt to truecolor sample
        assert true (str contains tc_dark (esc + "[1;38;2;198;120;221mfn" + esc + "[0m")) "AC2: TrueColor dark keyword RGB"
        assert true (str contains tc_dark (esc + "[1;38;2;97;175;239mgreet" + esc + "[0m")) "AC2: TrueColor dark function RGB"

        tc_light = fmt to truecolor with theme sample FmtThemeLight
        assert true (str contains tc_light (esc + "[1;38;2;166;38;164mfn" + esc + "[0m")) "AC2: TrueColor light keyword RGB"
        ()

23.3.5. Ejemplo 5: Exportación de documentos resaltados a HTML5 (<pre><code>), Pango Markup, LaTeX, RTF y SVG vectorial

En este ejemplo práctico exploramos de forma exhaustiva cómo se comporta fmt en este bloque funcional, incluyendo entradas estándar, combinaciones de parámetros y valores frontera:

fn :: test fmt enriched document targets => ()
      test fmt enriched document targets =
        nl = char from code 10
        src = "fn :: cmp Int Int => Bool" + nl + "cmp a b = a < b AND b > 0" + nl

        -- 1. Inline HTML
        html_out = fmt to html src
        assert true (str starts with html_out "<pre class=\"ridgun-code\"") "AC3: HTML inline wrapper"
        assert true (str contains html_out "<span style=\"color:#c678dd;font-weight:bold\">fn</span>") "AC3: HTML inline keyword span"
        assert true (str contains html_out "&lt;") "AC3: HTML escapes < operator"
        assert true (str contains html_out "&gt;") "AC3: HTML escapes > operator"

        -- 2. CSS-class HTML + Stylesheet
        css_html = fmt to html css src
        assert true (str contains css_html "<span class=\"rg-kw\">fn</span>") "AC3: HTML CSS keyword class"
        assert true (str contains css_html "<span class=\"rg-fn\">cmp</span>") "AC3: HTML CSS function class"
        assert true (str contains css_html "<span class=\"rg-type\">Int</span>") "AC3: HTML CSS type class"
        assert true (str contains css_html "<span class=\"rg-logic\">AND</span>") "AC3: HTML CSS logic operator class"
        sheet_dark = fmt html stylesheet FmtThemeDark
        sheet_light = fmt html stylesheet FmtThemeLight
        assert true (str contains sheet_dark ".rg-kw") "AC3: Dark CSS stylesheet"
        assert true (str contains sheet_light "#fafafa") "AC3: Light CSS stylesheet"

        -- 3. Markdown
        md_out = fmt to markdown src
        assert true (str starts with md_out ("

-- 4. Pango Markup pango_out = fmt to pango src _ = assert true (str starts with pango_out ("<tt>" + nl)) "AC3: Pango <tt> wrapper" _ = assert true (str contains pango_out "<span foreground="#c678dd" weight="bold">fn</span>") "AC3: Pango span markup"

-- 5. LaTeX Verbatim latex_out = fmt to latex src _ = assert true (str contains latex_out "Verbatim") "AC3: LaTeX Verbatim environment" _ = assert true (str contains latex_out "textcolor[HTML]") "AC3: LaTeX textcolor macro"

-- 6. RTF rtf_out = fmt to rtf src _ = assert true (str contains rtf_out "rtf1") "AC3: RTF header" _ = assert true (str contains rtf_out "colortbl") "AC3: RTF color table" _ = assert true (str contains rtf_out "\cf1\b fn") "AC3: RTF bold color span" ()


---

## 23.4. Bajo el capó: cómo está construida `fmt` en Ridgun puro (`src/main/ridgun/lib/fmt.rg`)

Una de las mayores ventajas de `ridgun-libs` es que **no hay cajas negras en C**. Puedes abrir `src/main/ridgun/lib/fmt.rg` y leer exactamente cómo está implementada cada operación usando *pattern matching*, árboles de guardas `|` / `|.` y recursión de cola (TCO). Veamos las piezas clave de su implementación real:

### 23.4.1. Implementación interna: Configuration Constructors

Fíjate en cómo `fmt.rg` estructura las firmas `fn :: ... => ...` primero y resuelve cada caso mediante ecuaciones alineadas y llamadas de cola:

module :: fmt

fn :: default fmt config => FmtConfig default fmt config = FmtConfig 2 4 80 True FmtPlain FmtThemeNone

fn :: fmt config Int Int Int Bool FmtTarget FmtTheme => FmtConfig fmt config indent_w max_params max_w aligned target theme = FmtConfig (fmt max 1 indent_w) (fmt max 0 max_params) (fmt max 20 max_w) aligned target theme


### 23.4.2. Implementación interna: Signature Parsing (`fn ::` / `op ::`)

Fíjate en cómo `fmt.rg` estructura las firmas `fn :: ... => ...` primero y resuelve cada caso mediante ecuaciones alineadas y llamadas de cola:

fn :: fmt split sig arrow [FmtToken] [String] => (Bool, [String], String, Int) fmt split sig arrow [] _ = (False, [], "", 0) fmt split sig arrow ((FmtTok tok col):rest) lhs_acc | tok == "=>" OR tok == "->" = (True, lhs_acc, tok, col) | otherwise = fmt split sig arrow rest (lhs_acc :: [tok])

fn :: fmt is sig type tok String => Bool fmt is sig type tok "" = False fmt is sig type tok tok = ch = str char at tok 0 (ch >= 65 AND ch <= 90) OR ch == 91 OR ch == 40

fn :: fmt all type toks [String] => Bool fmt all type toks [] = True fmt all type toks (t:rest) | fmt is sig type tok t = fmt all type toks rest | otherwise = False

fn :: fmt is bare fn lhs [String] => Bool fmt is bare fn lhs (first_w:rest) | NOT (fmt is sig type tok first_w) = fmt all type toks rest fmt is bare fn lhs _ = False

fn :: fmt infer bare kind [String] => String fmt infer bare kind lhs_strs | fmt is bare fn lhs lhs_strs = "bare_fn" | otherwise = "bare_op"

fn :: fmt parse sig line String => FmtSig fmt parse sig line line = clean = fmt strip comment line cmt = fmt extract comment line toks = fmt scan tokens clean fmt parse sig tokens (fmt leading indent line) clean cmt toks

fn :: fmt parse sig tokens Int String String [FmtToken] => FmtSig fmt parse sig tokens _ clean cmt ((FmtTok kind ):(FmtTok "::" ):rest) | kind == "fn" OR kind == "op" = fmt finish sig parse clean cmt kind (fmt split sig arrow rest []) fmt parse sig tokens 0 clean cmt ((FmtTok w col):rest) | w == "type" OR w == "expand" OR w == "import" OR w == "global" OR w == "context" OR w == "shared" OR w == "hardware" OR (str starts with w "@") OR (str starts with w "--") OR (str starts with w "|") = NoSig | otherwise = fmt finish bare sig parse clean cmt (fmt split sig arrow ([FmtTok w col] :: rest) []) fmt parse sig tokens _ _ _ _ = NoSig

fn :: fmt finish bare sig parse String String (Bool, [String], String, Int) => FmtSig fmt finish bare sig parse _ _ (False, , , ) = NoSig fmt finish bare sig parse _ (True, [], , ) = NoSig fmt finish bare sig parse clean cmt (True, lhs_strs, arrow_s, arrow_col) | arrow_s == "=>" = fmt finish sig parse clean cmt (fmt infer bare kind lhs_strs) (True, lhs_strs, arrow_s, arrow_col) | otherwise = NoSig


### 23.4.3. Implementación interna: Lexical Token Classification & Syntax Highlighting

Fíjate en cómo `fmt.rg` estructura las firmas `fn :: ... => ...` primero y resuelve cada caso mediante ecuaciones alineadas y llamadas de cola:

fn :: fmt is digit Int => Bool fmt is digit c = c >= 48 and c <= 57

fn :: fmt is upper Int => Bool fmt is upper c = c >= 65 and c <= 90

fn :: fmt is lower Int => Bool fmt is lower c = c >= 97 and c <= 122

fn :: fmt is ident char Int => Bool fmt is ident char c = (fmt is upper c) or (fmt is lower c) or (fmt is digit c) or c == 95

fn :: fmt is keyword String => Bool fmt is keyword w = w == "fn" or w == "op" or w == "type" or w == "expand" or w == "import" or w == "module" or w == "where" or w == "otherwise" or w == "with" or w == "do" or w == "mut" or w == "in" or w == "agent" or w == "send" or w == "to" or w == "receive" or w == "from" or w == "try" or w == "stop" or w == "timeout" or w == "global" or w == "context" or w == "shared" or w == "hardware" or w == "atomic" or w == "region" or w == "limit" or w == "map" or w == "filter" or w == "fold"

fn :: fmt is logic op String => Bool fmt is logic op w = w == "AND" or w == "OR" or w == "XOR" or w == "NOT" or w == "and" or w == "or" or w == "xor" or w == "not" or w == "shl" or w == "shr" or w == "rotr" or w == "rotl"

fn :: fmt is bool lit String => Bool fmt is bool lit w = w == "True" or w == "False"

fn :: fmt classify word String Bool => String fmt classify word "" _ = "plain" fmt classify word w in_fn = | fmt is keyword w = "keyword" | fmt is logic op w = "logic" | fmt is bool lit w = "bool" | fmt is upper (str char at w 0) = "type" | fmt is digit (str char at w 0) = "number" | in_fn = "function" | otherwise = "plain"


### 23.4.4. Implementación interna: Public Entry Points

Fíjate en cómo `fmt.rg` estructura las firmas `fn :: ... => ...` primero y resuelve cada caso mediante ecuaciones alineadas y llamadas de cola:

fn :: fmt source with config String FmtConfig => String fmt source with config src cfg = src fmt split raw lines -> raw_lines fmt format top lines raw_lines 0 "" cfg -> formatted_lines cfg target_format -> target cfg color_theme -> theme fmt highlight lines formatted_lines target theme -> highlighted fmt wrap target doc highlighted target theme

fn :: format ridgun source String => String format ridgun source src = fmt source with config src (default fmt config)

fn :: fmt to tty with theme String FmtTheme => String fmt to tty with theme src theme = fmt source with config src (FmtConfig 2 4 80 True FmtTty theme)

fn :: fmt to tty String => String fmt to tty src = fmt to tty with theme src FmtThemeDark

fn :: fmt to truecolor with theme String FmtTheme => String fmt to truecolor with theme src theme = fmt source with config src (FmtConfig 2 4 80 True FmtTrueColor theme)

fn :: fmt to truecolor String => String fmt to truecolor src = fmt to truecolor with theme src FmtThemeDark

fn :: fmt to html with theme String FmtTheme => String fmt to html with theme src theme = fmt source with config src (FmtConfig 2 4 80 True FmtHtmlInline theme)

fn :: fmt to html String => String fmt to html src = fmt to html with theme src FmtThemeDark

fn :: fmt to html css String => String fmt to html css src = fmt source with config src (FmtConfig 2 4 80 True FmtHtmlCss FmtThemeDark)

fn :: fmt to markdown String => String fmt to markdown src = fmt source with config src (FmtConfig 2 4 80 True FmtMarkdown FmtThemeNone)

fn :: fmt to pango with theme String FmtTheme => String fmt to pango with theme src theme = fmt source with config src (FmtConfig 2 4 80 True FmtPango theme)

fn :: fmt to pango String => String fmt to pango src = fmt to pango with theme src FmtThemeDark

fn :: fmt to latex with theme String FmtTheme => String fmt to latex with theme src theme = fmt source with config src (FmtConfig 2 4 80 True FmtLatex theme)

fn :: fmt to latex String => String fmt to latex src = fmt to latex with theme src FmtThemeDark

fn :: fmt to rtf with theme String FmtTheme => String fmt to rtf with theme src theme = fmt source with config src (FmtConfig 2 4 80 True FmtRtf theme)

fn :: fmt to rtf String => String fmt to rtf src = fmt to rtf with theme src FmtThemeDark


---

## 23.5. Garantías algorítmicas, memoria `RMM1`/`RMM2` y las 5 Reglas de Oro de `fmt`

- **Garantía algorítmica y de seguridad**: Idempotencia estricta (`fmt source (fmt source s) == fmt source s`) y preservación del 100 % de los tokens semánticos.
- **Complejidad de pila $O(1)$ con TCO**: Todos los bucles recursivos en `src/main/ridgun/lib/fmt.rg` están en posición de cola, por lo que `ridgunc` los compila a saltos nativos sin crecimiento de pila.
- **Memoria determinista (`RMM1`/`RMM2`)**: Cero pausas de recolector de basura; todas las estructuras intermedias se liberan de forma determinista al salir del ámbito.
- **Verificación continua**: Probada exhaustivamente con `stable check` y la suite automatizada `src/test/ridgun/test fmt.rg`.

### Las 5 Reglas de Oro al programar con `fmt`

1. **Declara `import fmt` al inicio del archivo** y aprovecha la equivalencia entre espacios y guiones bajos para que tu código se lea como prosa.
2. **Alinea tus tuberías de datos con `=`**: encadena las llamadas a `fmt` en pasos con nombre propio y deja que `stable format` alinee las columnas.
3. **Aprovecha las funciones totales de `fmt` en tus guardas `|`**: comprueba los valores de retorno o desenvuelve los ADTs con *pattern matching* en lugar de asumir que la entrada externa siempre es válida.
4. **Evita copiar grandes estructuras si solo necesitas consultar un campo**: recuerda que en `RMM2` los argumentos de entrada no incrementan ni decrementan contadores (`+0` / `-0`).
5. **Combina `fmt` con `test` (`import test`)**: escribe siempre aserciones con `assert equals` o `assert true` para fijar los invariantes de tu dominio.

---

En el **Capítulo 24** pasaremos a explorar en profundidad la lib **`cli`** (La lib `cli` — Banderas, Opciones, Barrera `--`, Subcomandos y Variables de Entorno).