1# Changelog — charka
2
3Transpilador COBOL → Rust. El módulo más grande del ecosistema (Fase D
4del plan macro) — el parser COBOL completo es un esfuerzo multi-mes.
5
6### feat(charka-shadow): validador en sombra + corpus COBOL
7
8Crate nuevo `crates/modules/charka/charka-shadow` y un corpus de prueba
9`crates/modules/charka/corpus/` — el pipeline COBOL→Rust queda
10completo y validado de punta a punta.
11
12- `charka-shadow` certifica que el transpilador preserva la semántica
13 del COBOL original con una **ejecución sombra**: un intérprete que
14 corre el `Ir` directamente sobre `charka-runtime`, sin compilar nada.
15 Es una segunda ruta de ejecución, independiente del código que emite
16 `charka-codegen`.
17- `interpret(&Ir) -> Outcome` ejecuta el IR y captura las líneas de
18 `DISPLAY`; `run_source(&str)` corre el pipeline completo (lexer →
19 parser → IR → intérprete).
20- Tope de pasos (`Halt::StepLimit`): un bucle que no termina se corta
21 en vez de colgar la ejecución.
22- **Corpus**: 7 programas COBOL de complejidad graduada — `01-hola`
23 (un `DISPLAY`), `02-aritmetica` (`ADD`/`SUBTRACT`/`MULTIPLY`),
24 `03-condicional` (`IF`/`ELSE`), `04-bucle` (`PERFORM TIMES`),
25 `05-factorial` (`PERFORM UNTIL`), `06-nomina` (grupos, `COMPUTE` con
26 paréntesis, `ROUNDED`, `V99`), `07-clasificar` (`IF` anidado, `AND`).
27 Cada uno con su `.expected` verificada a mano.
28- 11 tests: los 7 programas del corpus + fuente vacío, `STOP RUN`,
29 corte por tope de pasos y propagación de error de léxico.
30
31### feat(charka-codegen): emisión de Rust desde el IR
32
33Crate nuevo `crates/modules/charka/charka-codegen` — la etapa final del
34pipeline. `generate(&Ir) -> String` produce un fuente Rust (un
35`main.rs`) que, compilado contra `charka-runtime`, ejecuta la lógica
36del programa COBOL.
37
38- Un `struct Program` con un campo por cada dato elemental — `Num`
39 para los numéricos, `Text` para los alfanuméricos; `Program::new()`
40 los inicializa desde sus cláusulas `VALUE`.
41- Un método `p_<párrafo>(&mut self)` por cada párrafo del PROCEDURE;
42 `run()` los encadena en orden (el «caer» de COBOL); `main()`
43 construye el `Program` y lo corre.
44- Cada `Stmt` → código Rust: `MOVE`→`.store`/`.fill`,
45 `DISPLAY`→`println!`, `COMPUTE` y la aritmética → expresiones
46 `Decimal`, `IF`→`if`/`else`, `PERFORM`→ llamada de método / `for` /
47 `while`, `GO TO`→ llamada + `return`, `STOP RUN`→`process::exit`.
48- Tolerante: lo no transpilable (`Stmt::Unknown`, un dato sin resolver,
49 el operador `**`) se emite como comentario `// charka:`; el código
50 generado siempre compila.
51- Saneado de identificadores COBOL→Rust (incl. choques con keywords).
52- Verificado de punta a punta: un programa COBOL de demostración
53 transpila a Rust que compila contra `charka-runtime` y produce la
54 salida esperada (`COMPUTE`, `IF`, `PERFORM`, `DISPLAY`).
55- 14 tests del fuente emitido; fuera de alcance v1: grupos como campo,
56 `REDEFINES`, `OCCURS`, `PERFORM ... THRU` como rango, E/S.
57
58### feat(charka-runtime): soporte de ejecución — campos Num y Text
59
60Crate nuevo `crates/modules/charka/charka-runtime` — el soporte que los
61programas COBOL transpilados enlazan. `charka-codegen` no emitirá Rust
62autónomo: emitirá Rust que llama a esta biblioteca.
63
64- `Num` — campo numérico (`PIC 9(5)V99`): un `Decimal` conformado a su
65 `Picture`. `store` trunca a la escala declarada; `store_rounded`
66 redondea; al desbordar la parte entera conserva los dígitos de bajo
67 orden (el `ON SIZE ERROR` de COBOL sin cláusula). `display` da los
68 dígitos con relleno de ceros y signo si corresponde.
69- `Text` — campo alfanumérico (`PIC X(n)`) de longitud fija: `store`
70 justifica a la izquierda y rellena con espacios o trunca; `fill`
71 mueve las constantes figurativas (`SPACES`, `ZEROS`).
72- `cobol_text_cmp` — comparación alfanumérica que rellena el más corto
73 con espacios.
74- Reexporta `Decimal`/`Picture`/`Rounding` de `charka-bcd`.
75- Construido antes que `charka-codegen` (la nota de orden del plan los
76 listaba al revés): el codegen emite contra esta API, así que el
77 runtime debe existir primero — y se verifica solo, sin el codegen.
78- 17 tests: campo en cero, `VALUE` inicial, truncado y redondeo,
79 desbordamiento que conserva bajo orden, magnitud sin signo y signo
80 con signo, justificación y relleno de texto, `fill`, comparación.
81
82### feat(charka-ir): representación intermedia — statements tipados
83
84Crate nuevo `crates/modules/charka/charka-ir` — la tercera etapa del
85pipeline: `Program` → `Ir`. El PROCEDURE division pasa de sentencias
86con tokens crudos a un árbol de instrucciones tipadas.
87
88- `lower(&Program) -> Ir` — total y tolerante: nunca falla.
89- `Ir { program_id, data, procedures }`. El modelo de datos (la DATA
90 division) pasa tal cual — sirve de tabla de símbolos.
91- `Stmt` cubre `MOVE`, `DISPLAY`, `ACCEPT`, `COMPUTE`, `ADD`,
92 `SUBTRACT`, `MULTIPLY`, `DIVIDE`, `IF`/`ELSE`/`END-IF`, `PERFORM`
93 (fuera de línea, en línea, `TIMES`, `UNTIL`), `GO TO`, `STOP RUN`,
94 `GOBACK`, `EXIT`, `CONTINUE`.
95- Expresiones de `COMPUTE` con precedencia y paréntesis (`+ -` <
96 `* /` < `**` asociativo a derecha). Condiciones de `IF`/`UNTIL` con
97 comparadores en forma símbolo (`= < > <= >= <>`) o palabra
98 (`EQUAL TO`, `GREATER THAN`...), `AND`/`OR`/`NOT` y nombres de
99 condición (datos de nivel 88).
100- COBOL no termina los statements con un símbolo: el parser delimita
101 las listas de operandos con palabras "frontera" (verbos,
102 terminadores `END-*`/`ELSE`, conectores `TO`/`GIVING`/`BY`...).
103- Un verbo no soportado se conserva como `Stmt::Unknown { verb,
104 tokens }` — el lowering nunca aborta.
105- Fuera de alcance v1: `EVALUATE`, `STRING`/`UNSTRING`, E/S de
106 ficheros, `PERFORM VARYING`, CICS, SQL embebido.
107- 17 tests: MOVE simple y multi-destino, DISPLAY con figurativas,
108 precedencia de COMPUTE, flag ROUNDED, ADD in-place vs GIVING,
109 SUBTRACT, DIVIDE BY/INTO, IF/ELSE, condiciones con AND, nombre de
110 condición, PERFORM párrafo/TIMES/UNTIL en línea, varios statements
111 en una sentencia, verbo desconocido, programa completo.
112
113### feat(charka-parser): parser COBOL'85 → AST
114
115Crate nuevo `crates/modules/charka/charka-parser` — la segunda etapa del
116pipeline: `Vec<Token>` → `Program` (AST). Alcance v1: el esqueleto del
117programa.
118
119- `parse(&[Token]) -> Result<Program, ParseError>`. El AST: `Program`
120 (`program_id`, `data`, `paragraphs`), `DataItem`, `Paragraph`,
121 `Sentence`.
122- Particiona el flujo de tokens en las cuatro divisiones por sus
123 encabezados (`X DIVISION`); de la IDENTIFICATION extrae el
124 `PROGRAM-ID`.
125- **DATA division** → árbol de `DataItem`: número de nivel, nombre,
126 cláusula `PICTURE` reensamblada (`S9` `(` `5` `)` `V99` →
127 `S9(5)V99`) y `VALUE`. Anida por número de nivel — 01 y 77 son
128 raíces, 88 cuelga del ítem precedente.
129- **PROCEDURE division** → `Vec<Paragraph>`, cada párrafo con sus
130 `Sentence` (tokens crudos; sin parseo a nivel de statement, eso es
131 `charka-ir`). Las sentencias previas al primer encabezado van a un
132 párrafo implícito de nombre "".
133- Parser tolerante: salta encabezados de `SECTION`, entradas `FD`/`SD`
134 y cláusulas de datos que no sean `PICTURE`/`VALUE`. `ParseError` sólo
135 ante un número de nivel inválido o un dato sin nombre.
136- 15 tests: PROGRAM-ID (forma larga y `ID` corta), ítems planos y
137 anidados, reensamblado de PICTURE, variantes de VALUE, niveles 88,
138 `FILLER`, párrafos y párrafo implícito, encabezado de sección,
139 programa completo de punta a punta, nivel inválido.
140
141### feat(charka-lexer): tokenizador de COBOL
142
143Crate nuevo `crates/modules/charka/charka-lexer` — la primera etapa del
144pipeline del transpilador: texto COBOL → secuencia de `Token`.
145
146- **Lexer deliberadamente tonto**: no conoce keywords ni la cláusula
147 `PICTURE`; emite `Word` para todo identificador y deja la
148 clasificación al parser.
149- Tokens: `Word` (palabras COBOL con guiones internos), `Number`
150 (literal sin signo), `String` (comillas dobladas colapsadas),
151 `Period` (el `.` terminador), `Symbol` (paréntesis, separadores y
152 operadores `+ - * / ** = < > <= >= <>`).
153- Dos formatos de fuente: **fijo** (la tarjeta de 80 columnas — cols
154 1-6 secuencia, 7 indicadora, 8-72 código, 73-80 identificación) y
155 **libre**. Comentarios por la columna indicadora (`*`/`/`) o por `*`
156 inicial en formato libre.
157- Cada `Token` lleva línea y columna 1-based; `LexError` tipado
158 (literal sin cerrar, carácter inesperado).
159- Limitación v1 documentada: no soporta continuación de literales entre
160 líneas (indicador `-`). Subconjunto COBOL'85, el hito intermedio.
161- 17 tests: sentencias, palabras con guiones, literales y comillas
162 dobladas, números vs terminador, operadores, ambos formatos,
163 tracking de posición, errores.
164
165### feat(charka-bcd): aritmética decimal con semántica COBOL
166
167(Pre-existente.) `Picture` + `Decimal` de punto fijo exacto — ver el
168SDD del módulo. 22 tests.
charka.md
Changelog — charka
Transpilador COBOL → Rust. El módulo más grande del ecosistema (Fase D
del plan macro) — el parser COBOL completo es un esfuerzo multi-mes.
feat(charka-shadow): validador en sombra + corpus COBOL
Crate nuevo crates/modules/charka/charka-shadow y un corpus de prueba
crates/modules/charka/corpus/ — el pipeline COBOL→Rust queda
completo y validado de punta a punta.
charka-shadow certifica que el transpilador preserva la semántica
del COBOL original con una ejecución sombra: un intérprete que
corre el Ir directamente sobre charka-runtime, sin compilar nada.
Es una segunda ruta de ejecución, independiente del código que emite
charka-codegen.
interpret(&Ir) -> Outcome ejecuta el IR y captura las líneas de
DISPLAY; run_source(&str) corre el pipeline completo (lexer →
parser → IR → intérprete).
- Tope de pasos (
Halt::StepLimit): un bucle que no termina se corta
en vez de colgar la ejecución.
- Corpus: 7 programas COBOL de complejidad graduada —
01-hola
(un DISPLAY), 02-aritmetica (ADD/SUBTRACT/MULTIPLY),
03-condicional (IF/ELSE), 04-bucle (PERFORM TIMES),
05-factorial (PERFORM UNTIL), 06-nomina (grupos, COMPUTE con
paréntesis, ROUNDED, V99), 07-clasificar (IF anidado, AND).
Cada uno con su .expected verificada a mano.
- 11 tests: los 7 programas del corpus + fuente vacío,
STOP RUN,
corte por tope de pasos y propagación de error de léxico.
feat(charka-codegen): emisión de Rust desde el IR
Crate nuevo crates/modules/charka/charka-codegen — la etapa final del
pipeline. generate(&Ir) -> String produce un fuente Rust (un
main.rs) que, compilado contra charka-runtime, ejecuta la lógica
del programa COBOL.
- Un
struct Program con un campo por cada dato elemental — Num
para los numéricos, Text para los alfanuméricos; Program::new()
los inicializa desde sus cláusulas VALUE.
- Un método
p_<párrafo>(&mut self) por cada párrafo del PROCEDURE;
run() los encadena en orden (el «caer» de COBOL); main()
construye el Program y lo corre.
- Cada
Stmt → código Rust: MOVE→.store/.fill,
DISPLAY→println!, COMPUTE y la aritmética → expresiones
Decimal, IF→if/else, PERFORM→ llamada de método / for /
while, GO TO→ llamada + return, STOP RUN→process::exit.
- Tolerante: lo no transpilable (
Stmt::Unknown, un dato sin resolver,
el operador **) se emite como comentario // charka:; el código
generado siempre compila.
- Saneado de identificadores COBOL→Rust (incl. choques con keywords).
- Verificado de punta a punta: un programa COBOL de demostración
transpila a Rust que compila contra
charka-runtime y produce la
salida esperada (COMPUTE, IF, PERFORM, DISPLAY).
- 14 tests del fuente emitido; fuera de alcance v1: grupos como campo,
REDEFINES, OCCURS, PERFORM ... THRU como rango, E/S.
feat(charka-runtime): soporte de ejecución — campos Num y Text
Crate nuevo crates/modules/charka/charka-runtime — el soporte que los
programas COBOL transpilados enlazan. charka-codegen no emitirá Rust
autónomo: emitirá Rust que llama a esta biblioteca.
Num — campo numérico (PIC 9(5)V99): un Decimal conformado a su
Picture. store trunca a la escala declarada; store_rounded
redondea; al desbordar la parte entera conserva los dígitos de bajo
orden (el ON SIZE ERROR de COBOL sin cláusula). display da los
dígitos con relleno de ceros y signo si corresponde.
Text — campo alfanumérico (PIC X(n)) de longitud fija: store
justifica a la izquierda y rellena con espacios o trunca; fill
mueve las constantes figurativas (SPACES, ZEROS).
cobol_text_cmp — comparación alfanumérica que rellena el más corto
con espacios.
- Reexporta
Decimal/Picture/Rounding de charka-bcd.
- Construido antes que
charka-codegen (la nota de orden del plan los
listaba al revés): el codegen emite contra esta API, así que el
runtime debe existir primero — y se verifica solo, sin el codegen.
- 17 tests: campo en cero,
VALUE inicial, truncado y redondeo,
desbordamiento que conserva bajo orden, magnitud sin signo y signo
con signo, justificación y relleno de texto, fill, comparación.
feat(charka-ir): representación intermedia — statements tipados
Crate nuevo crates/modules/charka/charka-ir — la tercera etapa del
pipeline: Program → Ir. El PROCEDURE division pasa de sentencias
con tokens crudos a un árbol de instrucciones tipadas.
lower(&Program) -> Ir — total y tolerante: nunca falla.
Ir { program_id, data, procedures }. El modelo de datos (la DATA
division) pasa tal cual — sirve de tabla de símbolos.
Stmt cubre MOVE, DISPLAY, ACCEPT, COMPUTE, ADD,
SUBTRACT, MULTIPLY, DIVIDE, IF/ELSE/END-IF, PERFORM
(fuera de línea, en línea, TIMES, UNTIL), GO TO, STOP RUN,
GOBACK, EXIT, CONTINUE.
- Expresiones de
COMPUTE con precedencia y paréntesis (+ - <
* / < ** asociativo a derecha). Condiciones de IF/UNTIL con
comparadores en forma símbolo (= < > <= >= <>) o palabra
(EQUAL TO, GREATER THAN...), AND/OR/NOT y nombres de
condición (datos de nivel 88).
- COBOL no termina los statements con un símbolo: el parser delimita
las listas de operandos con palabras "frontera" (verbos,
terminadores
END-*/ELSE, conectores TO/GIVING/BY...).
- Un verbo no soportado se conserva como
Stmt::Unknown { verb, tokens } — el lowering nunca aborta.
- Fuera de alcance v1:
EVALUATE, STRING/UNSTRING, E/S de
ficheros, PERFORM VARYING, CICS, SQL embebido.
- 17 tests: MOVE simple y multi-destino, DISPLAY con figurativas,
precedencia de COMPUTE, flag ROUNDED, ADD in-place vs GIVING,
SUBTRACT, DIVIDE BY/INTO, IF/ELSE, condiciones con AND, nombre de
condición, PERFORM párrafo/TIMES/UNTIL en línea, varios statements
en una sentencia, verbo desconocido, programa completo.
feat(charka-parser): parser COBOL'85 → AST
Crate nuevo crates/modules/charka/charka-parser — la segunda etapa del
pipeline: Vec<Token> → Program (AST). Alcance v1: el esqueleto del
programa.
parse(&[Token]) -> Result<Program, ParseError>. El AST: Program
(program_id, data, paragraphs), DataItem, Paragraph,
Sentence.
- Particiona el flujo de tokens en las cuatro divisiones por sus
encabezados (
X DIVISION); de la IDENTIFICATION extrae el
PROGRAM-ID.
- DATA division → árbol de
DataItem: número de nivel, nombre,
cláusula PICTURE reensamblada (S9 ( 5 ) V99 →
S9(5)V99) y VALUE. Anida por número de nivel — 01 y 77 son
raíces, 88 cuelga del ítem precedente.
- PROCEDURE division →
Vec<Paragraph>, cada párrafo con sus
Sentence (tokens crudos; sin parseo a nivel de statement, eso es
charka-ir). Las sentencias previas al primer encabezado van a un
párrafo implícito de nombre "".
- Parser tolerante: salta encabezados de
SECTION, entradas FD/SD
y cláusulas de datos que no sean PICTURE/VALUE. ParseError sólo
ante un número de nivel inválido o un dato sin nombre.
- 15 tests: PROGRAM-ID (forma larga y
ID corta), ítems planos y
anidados, reensamblado de PICTURE, variantes de VALUE, niveles 88,
FILLER, párrafos y párrafo implícito, encabezado de sección,
programa completo de punta a punta, nivel inválido.
feat(charka-lexer): tokenizador de COBOL
Crate nuevo crates/modules/charka/charka-lexer — la primera etapa del
pipeline del transpilador: texto COBOL → secuencia de Token.
- Lexer deliberadamente tonto: no conoce keywords ni la cláusula
PICTURE; emite Word para todo identificador y deja la
clasificación al parser.
- Tokens:
Word (palabras COBOL con guiones internos), Number
(literal sin signo), String (comillas dobladas colapsadas),
Period (el . terminador), Symbol (paréntesis, separadores y
operadores + - * / ** = < > <= >= <>).
- Dos formatos de fuente: fijo (la tarjeta de 80 columnas — cols
1-6 secuencia, 7 indicadora, 8-72 código, 73-80 identificación) y
libre. Comentarios por la columna indicadora (
*//) o por *
inicial en formato libre.
- Cada
Token lleva línea y columna 1-based; LexError tipado
(literal sin cerrar, carácter inesperado).
- Limitación v1 documentada: no soporta continuación de literales entre
líneas (indicador
-). Subconjunto COBOL'85, el hito intermedio.
- 17 tests: sentencias, palabras con guiones, literales y comillas
dobladas, números vs terminador, operadores, ambos formatos,
tracking de posición, errores.
feat(charka-bcd): aritmética decimal con semántica COBOL
(Pre-existente.) Picture + Decimal de punto fijo exacto — ver el
SDD del módulo. 22 tests.