tawasuyu

tawasuyu/brahman

Rust 230TOML 69JSON 14HTML 12901 Definiciones

⎇ 2728698f5ef15234be868988d5c330ef6c0f2533 docs/changelog/charka.md Markdown · 305 líneas · 15.4 KB Historia crudo

feat(charka): INSPECT — contar y reemplazar caracteres 2728698f5 · sergio ·

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): INSPECT — contar y reemplazar caracteres
7
8El verbo de COBOL para analizar y limpiar campos de texto.
9
10- IR: `Stmt::Inspect { target, op }` con `InspectOp::TallyingForAll`
11  (cuenta apariciones y las suma a un contador) y
12  `InspectOp::ReplacingAll` (reemplaza apariciones).
13- Parser: `INSPECT t TALLYING n FOR ALL lit` y
14  `INSPECT t REPLACING ALL a BY b`. Una forma no soportada cae a
15  `Stmt::Unknown`.
16- Codegen: `TALLYING` → `str::matches(..).count()`; `REPLACING` →
17  `str::replace`.
18- Shadow: el intérprete cuenta / reemplaza el texto.
19- Corpus: programa nuevo `13-inspeccion`. Verificado: el intérprete
20  sombra y el crate compilado dan la misma salida.
21- Alcance v1: `TALLYING FOR ALL` y `REPLACING ALL`; sin `LEADING`,
22  `FIRST`, `CHARACTERS`, `BEFORE`/`AFTER`.
23
24### feat(charka): STRING y UNSTRING — manejo de cadenas
25
26Dos verbos comunes de COBOL para construir y partir cadenas.
27
28- IR: `Stmt::StringConcat { sources, into }` y
29  `Stmt::Unstring { source, delimiter, into }`.
30- Parser: `STRING a b DELIMITED BY SIZE INTO t END-STRING` y
31  `UNSTRING s DELIMITED BY d INTO a b c END-UNSTRING`.
32- Codegen: `STRING` → `format!` concatenado; `UNSTRING` → un bloque
33  que parte con `str::split` y reparte los trozos.
34- Shadow: el intérprete concatena / parte el texto y lo reparte.
35- Corpus: programa nuevo `12-cadenas`. Verificado: el intérprete
36  sombra y el crate compilado dan la misma salida.
37- Alcance v1: `STRING` con `DELIMITED BY SIZE` (los demás
38  delimitadores se ignoran); sin `WITH POINTER` ni `ON OVERFLOW`.
39
40### feat(charka): OCCURS — tablas y referencias con subíndice
41
42Los arrays de COBOL, que antes el transpilador descartaba en silencio.
43Atraviesa el pipeline entero.
44
45- Parser: la cláusula `OCCURS n [TIMES]` se captura en `DataItem`.
46- IR: `Operand::Indexed { name, index }` — una referencia `ELEM(I)`.
47  El subíndice es 1-based, como COBOL. Los destinos de los statements
48  pasan de `Vec<String>` a `Vec<Operand>`, así que se puede escribir a
49  un elemento de tabla (`MOVE x TO ELEM(I)`, `COMPUTE ELEM(I) = ...`).
50  `Field` del modelo gana `occurs: Option<u32>`.
51- Codegen: un campo `OCCURS` se emite como `Vec<Num>`/`Vec<Text>`,
52  inicializado con `vec![..; n]`; una referencia con subíndice indexa
53  el vector (1-based → 0-based).
54- Shadow: en el intérprete todo campo es un vector — un escalar es de
55  longitud 1, una tabla de `n`; las referencias se resuelven a
56  `(nombre, índice)`.
57- Corpus: programa nuevo `11-tabla` (llena una tabla con cuadrados y
58  los suma). Verificado: el intérprete sombra y el crate compilado por
59  `scaffold` dan ambos `SUMA DE CUADRADOS = 000055`.
60- Alcance v1: `OCCURS` en datos elementales, una dimensión, subíndice
61  de un solo operando. Fuera: `OCCURS` de grupo, multidimensional,
62  `OCCURS DEPENDING ON`.
63
64### feat(charka): nombres de condición (nivel 88) + modelo de datos compartido
65
66`IF ES-VALIDO` — los nombres de condición de COBOL, que antes el
67transpilador evaluaba siempre como `false`. Y, de paso, se elimina una
68duplicación: la resolución del modelo de datos.
69
70- `charka-ir` gana un módulo `model`: `resolve_data(&[DataItem]) ->
71  DataModel` aplana el árbol de datos a campos elementales (`Field` con
72  `FieldKind`) y a nombres de condición (`ConditionName`). El `Ir`
73  ahora lleva un campo `model`. Es la fuente única de verdad sobre la
74  clasificación de PICTURE.
75- `charka-codegen` y `charka-shadow` consumen `ir.model` en vez de
76  reimplementar cada uno la clasificación numérico/alfanumérico, el
77  ancho de PICTURE y la normalización de `VALUE`. `charka-codegen` ya
78  no depende de `charka-bcd`.
79- `Cond::Named` (un nivel 88) se resuelve a `padre = valor`: el codegen
80  emite la comparación, el intérprete sombra la evalúa.
81- Corregido de paso: un dato con hijos de nivel 88 (p. ej.
82  `01 WS-FLAG PIC X. 88 ES-SI VALUE 'Y'.`) antes se perdía como si
83  fuera un grupo; ahora se reconoce como campo elemental.
84- Corpus: programa nuevo `10-condicion` (un semáforo con 88 de texto y
85  de número, en `IF` e `IF/ELSE`). Verificado: intérprete y crate
86  compilado dan la misma salida.
87
88### feat(charka): EVALUATE — el case de COBOL
89
90`EVALUATE` atraviesa el pipeline entero — antes el parser lo guardaba
91crudo como `Stmt::Unknown`.
92
93- IR: `Stmt::Evaluate { subject, whens, other }` con
94  `WhenBranch { values, body }`. Varios `WHEN` apilados comparten
95  cuerpo; `WHEN OTHER` es el caso por defecto.
96- Parser: `EVALUATE subject WHEN v1 WHEN v2 ... [WHEN OTHER ...]
97  END-EVALUATE`.
98- Codegen: lo baja a una cadena `if / else if / else` — una rama se
99  elige si el sujeto es igual a alguno de sus valores; sin caída.
100- Shadow: el intérprete evalúa el sujeto y ejecuta la primera rama
101  cuyos valores casen, o el `WHEN OTHER`.
102- Corpus: programa nuevo `09-evaluar` (un `EVALUATE` por valor anidado
103  en un `PERFORM VARYING`, con `WHEN` apilados y `WHEN OTHER`).
104  Verificado: intérprete sombra y crate compilado dan la misma salida.
105- Alcance v1: `EVALUATE` por igualdad de valor; no la forma
106  `EVALUATE TRUE` con condiciones ni los rangos `THRU`.
107
108### feat(charka): PERFORM VARYING — el bucle con variable de control
109
110El bucle más usado de COBOL, que antes el parser degradaba a un
111`PERFORM` vacío. Ahora atraviesa el pipeline entero.
112
113- IR: `PerformControl::Varying { var, from, by, until }`.
114- Parser: reconoce `PERFORM VARYING var FROM x BY y UNTIL cond` en
115  línea (`END-PERFORM`) y fuera de línea (`PERFORM párrafo VARYING …`).
116- Codegen: emite `var = from; while !(until) { cuerpo; var += by; }`.
117- Shadow: el intérprete inicializa la variable, evalúa la condición
118  antes de cada vuelta e incrementa al final.
119- Corpus: programa nuevo `08-varying` (suma 1..10 con `PERFORM
120  VARYING`). Verificado: el intérprete sombra y el crate compilado por
121  `scaffold` dan ambos `SUMA 1 A 10 = 00055`.
122
123### feat(charka): CLI del transpilador — transpile / scaffold / run / check
124
125App nueva `crates/apps/charka` — el binario `charka`, que vuelve usable
126el pipeline desde la terminal. Cuatro comandos:
127
128- `transpile <in.cob> [-o out.rs]` — emite el código Rust (a un archivo
129  o a la salida estándar).
130- `scaffold <in.cob> -o <dir>` — genera un crate Rust completo
131  (`Cargo.toml` + `src/main.rs`) que depende de `charka-runtime` y
132  compila tal cual.
133- `run <in.cob>` — ejecuta el programa con el intérprete sombra y
134  muestra su salida, sin compilar nada.
135- `check <in.cob> -e <esperado>` — ejecuta y diferencia la salida
136  contra un archivo esperado; reporta las líneas que difieren.
137
138Avisa de los verbos COBOL que aún no se transpilan. Verificado de
139punta a punta contra el corpus: `scaffold` de `06-nomina` genera un
140crate que compila y produce la misma salida que el intérprete sombra —
141las dos rutas de ejecución concuerdan. 4 tests; fmt + clippy limpios.
142
143### feat(charka-shadow): validador en sombra + corpus COBOL
144
145Crate nuevo `crates/modules/charka/charka-shadow` y un corpus de prueba
146`crates/modules/charka/corpus/` — el pipeline COBOL→Rust queda
147completo y validado de punta a punta.
148
149- `charka-shadow` certifica que el transpilador preserva la semántica
150  del COBOL original con una **ejecución sombra**: un intérprete que
151  corre el `Ir` directamente sobre `charka-runtime`, sin compilar nada.
152  Es una segunda ruta de ejecución, independiente del código que emite
153  `charka-codegen`.
154- `interpret(&Ir) -> Outcome` ejecuta el IR y captura las líneas de
155  `DISPLAY`; `run_source(&str)` corre el pipeline completo (lexer →
156  parser → IR → intérprete).
157- Tope de pasos (`Halt::StepLimit`): un bucle que no termina se corta
158  en vez de colgar la ejecución.
159- **Corpus**: 7 programas COBOL de complejidad graduada — `01-hola`
160  (un `DISPLAY`), `02-aritmetica` (`ADD`/`SUBTRACT`/`MULTIPLY`),
161  `03-condicional` (`IF`/`ELSE`), `04-bucle` (`PERFORM TIMES`),
162  `05-factorial` (`PERFORM UNTIL`), `06-nomina` (grupos, `COMPUTE` con
163  paréntesis, `ROUNDED`, `V99`), `07-clasificar` (`IF` anidado, `AND`).
164  Cada uno con su `.expected` verificada a mano.
165- 11 tests: los 7 programas del corpus + fuente vacío, `STOP RUN`,
166  corte por tope de pasos y propagación de error de léxico.
167
168### feat(charka-codegen): emisión de Rust desde el IR
169
170Crate nuevo `crates/modules/charka/charka-codegen` — la etapa final del
171pipeline. `generate(&Ir) -> String` produce un fuente Rust (un
172`main.rs`) que, compilado contra `charka-runtime`, ejecuta la lógica
173del programa COBOL.
174
175- Un `struct Program` con un campo por cada dato elemental — `Num`
176  para los numéricos, `Text` para los alfanuméricos; `Program::new()`
177  los inicializa desde sus cláusulas `VALUE`.
178- Un método `p_<párrafo>(&mut self)` por cada párrafo del PROCEDURE;
179  `run()` los encadena en orden (el «caer» de COBOL); `main()`
180  construye el `Program` y lo corre.
181- Cada `Stmt` → código Rust: `MOVE`→`.store`/`.fill`,
182  `DISPLAY`→`println!`, `COMPUTE` y la aritmética → expresiones
183  `Decimal`, `IF`→`if`/`else`, `PERFORM`→ llamada de método / `for` /
184  `while`, `GO TO`→ llamada + `return`, `STOP RUN`→`process::exit`.
185- Tolerante: lo no transpilable (`Stmt::Unknown`, un dato sin resolver,
186  el operador `**`) se emite como comentario `// charka:`; el código
187  generado siempre compila.
188- Saneado de identificadores COBOL→Rust (incl. choques con keywords).
189- Verificado de punta a punta: un programa COBOL de demostración
190  transpila a Rust que compila contra `charka-runtime` y produce la
191  salida esperada (`COMPUTE`, `IF`, `PERFORM`, `DISPLAY`).
192- 14 tests del fuente emitido; fuera de alcance v1: grupos como campo,
193  `REDEFINES`, `OCCURS`, `PERFORM ... THRU` como rango, E/S.
194
195### feat(charka-runtime): soporte de ejecución — campos Num y Text
196
197Crate nuevo `crates/modules/charka/charka-runtime` — el soporte que los
198programas COBOL transpilados enlazan. `charka-codegen` no emitirá Rust
199autónomo: emitirá Rust que llama a esta biblioteca.
200
201- `Num` — campo numérico (`PIC 9(5)V99`): un `Decimal` conformado a su
202  `Picture`. `store` trunca a la escala declarada; `store_rounded`
203  redondea; al desbordar la parte entera conserva los dígitos de bajo
204  orden (el `ON SIZE ERROR` de COBOL sin cláusula). `display` da los
205  dígitos con relleno de ceros y signo si corresponde.
206- `Text` — campo alfanumérico (`PIC X(n)`) de longitud fija: `store`
207  justifica a la izquierda y rellena con espacios o trunca; `fill`
208  mueve las constantes figurativas (`SPACES`, `ZEROS`).
209- `cobol_text_cmp` — comparación alfanumérica que rellena el más corto
210  con espacios.
211- Reexporta `Decimal`/`Picture`/`Rounding` de `charka-bcd`.
212- Construido antes que `charka-codegen` (la nota de orden del plan los
213  listaba al revés): el codegen emite contra esta API, así que el
214  runtime debe existir primero — y se verifica solo, sin el codegen.
215- 17 tests: campo en cero, `VALUE` inicial, truncado y redondeo,
216  desbordamiento que conserva bajo orden, magnitud sin signo y signo
217  con signo, justificación y relleno de texto, `fill`, comparación.
218
219### feat(charka-ir): representación intermedia — statements tipados
220
221Crate nuevo `crates/modules/charka/charka-ir` — la tercera etapa del
222pipeline: `Program` → `Ir`. El PROCEDURE division pasa de sentencias
223con tokens crudos a un árbol de instrucciones tipadas.
224
225- `lower(&Program) -> Ir` — total y tolerante: nunca falla.
226- `Ir { program_id, data, procedures }`. El modelo de datos (la DATA
227  division) pasa tal cual — sirve de tabla de símbolos.
228- `Stmt` cubre `MOVE`, `DISPLAY`, `ACCEPT`, `COMPUTE`, `ADD`,
229  `SUBTRACT`, `MULTIPLY`, `DIVIDE`, `IF`/`ELSE`/`END-IF`, `PERFORM`
230  (fuera de línea, en línea, `TIMES`, `UNTIL`), `GO TO`, `STOP RUN`,
231  `GOBACK`, `EXIT`, `CONTINUE`.
232- Expresiones de `COMPUTE` con precedencia y paréntesis (`+ -` <
233  `* /` < `**` asociativo a derecha). Condiciones de `IF`/`UNTIL` con
234  comparadores en forma símbolo (`= < > <= >= <>`) o palabra
235  (`EQUAL TO`, `GREATER THAN`...), `AND`/`OR`/`NOT` y nombres de
236  condición (datos de nivel 88).
237- COBOL no termina los statements con un símbolo: el parser delimita
238  las listas de operandos con palabras "frontera" (verbos,
239  terminadores `END-*`/`ELSE`, conectores `TO`/`GIVING`/`BY`...).
240- Un verbo no soportado se conserva como `Stmt::Unknown { verb,
241  tokens }` — el lowering nunca aborta.
242- Fuera de alcance v1: `EVALUATE`, `STRING`/`UNSTRING`, E/S de
243  ficheros, `PERFORM VARYING`, CICS, SQL embebido.
244- 17 tests: MOVE simple y multi-destino, DISPLAY con figurativas,
245  precedencia de COMPUTE, flag ROUNDED, ADD in-place vs GIVING,
246  SUBTRACT, DIVIDE BY/INTO, IF/ELSE, condiciones con AND, nombre de
247  condición, PERFORM párrafo/TIMES/UNTIL en línea, varios statements
248  en una sentencia, verbo desconocido, programa completo.
249
250### feat(charka-parser): parser COBOL'85 → AST
251
252Crate nuevo `crates/modules/charka/charka-parser` — la segunda etapa del
253pipeline: `Vec<Token>` → `Program` (AST). Alcance v1: el esqueleto del
254programa.
255
256- `parse(&[Token]) -> Result<Program, ParseError>`. El AST: `Program`
257  (`program_id`, `data`, `paragraphs`), `DataItem`, `Paragraph`,
258  `Sentence`.
259- Particiona el flujo de tokens en las cuatro divisiones por sus
260  encabezados (`X DIVISION`); de la IDENTIFICATION extrae el
261  `PROGRAM-ID`.
262- **DATA division** → árbol de `DataItem`: número de nivel, nombre,
263  cláusula `PICTURE` reensamblada (`S9` `(` `5` `)` `V99` →
264  `S9(5)V99`) y `VALUE`. Anida por número de nivel — 01 y 77 son
265  raíces, 88 cuelga del ítem precedente.
266- **PROCEDURE division** → `Vec<Paragraph>`, cada párrafo con sus
267  `Sentence` (tokens crudos; sin parseo a nivel de statement, eso es
268  `charka-ir`). Las sentencias previas al primer encabezado van a un
269  párrafo implícito de nombre "".
270- Parser tolerante: salta encabezados de `SECTION`, entradas `FD`/`SD`
271  y cláusulas de datos que no sean `PICTURE`/`VALUE`. `ParseError` sólo
272  ante un número de nivel inválido o un dato sin nombre.
273- 15 tests: PROGRAM-ID (forma larga y `ID` corta), ítems planos y
274  anidados, reensamblado de PICTURE, variantes de VALUE, niveles 88,
275  `FILLER`, párrafos y párrafo implícito, encabezado de sección,
276  programa completo de punta a punta, nivel inválido.
277
278### feat(charka-lexer): tokenizador de COBOL
279
280Crate nuevo `crates/modules/charka/charka-lexer` — la primera etapa del
281pipeline del transpilador: texto COBOL → secuencia de `Token`.
282
283- **Lexer deliberadamente tonto**: no conoce keywords ni la cláusula
284  `PICTURE`; emite `Word` para todo identificador y deja la
285  clasificación al parser.
286- Tokens: `Word` (palabras COBOL con guiones internos), `Number`
287  (literal sin signo), `String` (comillas dobladas colapsadas),
288  `Period` (el `.` terminador), `Symbol` (paréntesis, separadores y
289  operadores `+ - * / ** = < > <= >= <>`).
290- Dos formatos de fuente: **fijo** (la tarjeta de 80 columnas — cols
291  1-6 secuencia, 7 indicadora, 8-72 código, 73-80 identificación) y
292  **libre**. Comentarios por la columna indicadora (`*`/`/`) o por `*`
293  inicial en formato libre.
294- Cada `Token` lleva línea y columna 1-based; `LexError` tipado
295  (literal sin cerrar, carácter inesperado).
296- Limitación v1 documentada: no soporta continuación de literales entre
297  líneas (indicador `-`). Subconjunto COBOL'85, el hito intermedio.
298- 17 tests: sentencias, palabras con guiones, literales y comillas
299  dobladas, números vs terminador, operadores, ambos formatos,
300  tracking de posición, errores.
301
302### feat(charka-bcd): aritmética decimal con semántica COBOL
303
304(Pre-existente.) `Picture` + `Decimal` de punto fijo exacto — ver el
305SDD 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): INSPECT — contar y reemplazar caracteres

El verbo de COBOL para analizar y limpiar campos de texto.

feat(charka): STRING y UNSTRING — manejo de cadenas

Dos verbos comunes de COBOL para construir y partir cadenas.

feat(charka): OCCURS — tablas y referencias con subíndice

Los arrays de COBOL, que antes el transpilador descartaba en silencio. Atraviesa el pipeline entero.

feat(charka): nombres de condición (nivel 88) + modelo de datos compartido

IF ES-VALIDO — los nombres de condición de COBOL, que antes el transpilador evaluaba siempre como false. Y, de paso, se elimina una duplicación: la resolución del modelo de datos.

feat(charka): EVALUATE — el case de COBOL

EVALUATE atraviesa el pipeline entero — antes el parser lo guardaba crudo como Stmt::Unknown.

feat(charka): PERFORM VARYING — el bucle con variable de control

El bucle más usado de COBOL, que antes el parser degradaba a un PERFORM vacío. Ahora atraviesa el pipeline entero.

feat(charka): CLI del transpilador — transpile / scaffold / run / check

App nueva crates/apps/charka — el binario charka, que vuelve usable el pipeline desde la terminal. Cuatro comandos:

Avisa de los verbos COBOL que aún no se transpilan. Verificado de punta a punta contra el corpus: scaffold de 06-nomina genera un crate que compila y produce la misma salida que el intérprete sombra — las dos rutas de ejecución concuerdan. 4 tests; fmt + clippy limpios.

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.

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.

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.

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.

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.

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.

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.