gioser

tawasuyu/brahman

Rust 459TOML 177Markdown 49JSON 176207 Definitions

feat(charka): SET ... TO TRUE — escribir nombres de condición (88)

La cara de escritura de los nombres de condición de COBOL: si
IF ES-VALIDO los lee, SET ES-VALIDO TO TRUE los escribe.

- IR: Stmt::SetTrue { conditions }.
- Parser: SET cond-1 cond-2 ... TO TRUE. Otras formas de SET
  (índices, TO FALSE) caen a Stmt::Unknown.
- Codegen y shadow: SET cond TO TRUE asigna a su dato padre el valor
  del 88 (un MOVE del valor a la variable).
- Corpus: programa nuevo 16-bandera (cambia banderas de texto y de
  número con SET). Verificado: el intérprete sombra y el crate
  compilado por scaffold dan la misma salida.

Tests: charka-ir 29, charka-codegen 23, charka-shadow 21. fmt +
clippy limpios.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

82ba0b7a1a04b7ff2d7e2175ac74766da0d16066 · by sergio · (5 months ago) · parent fa65f2020 · browse the tree at this commit

Semantic delta · 8

crates/modules/charka/charka-codegen/src/lib.rs

crates/modules/charka/charka-codegen/src/stmt.rs

crates/modules/charka/charka-ir/src/ast.rs

  • signature changed enum Stmt pub

crates/modules/charka/charka-ir/src/lib.rs

crates/modules/charka/charka-ir/src/stmt.rs

crates/modules/charka/charka-shadow/src/interp.rs

12 files · +115 −4

diff --git a/crates/modules/charka/SDD.md b/crates/modules/charka/SDD.md
index 611bf3d..6dda34e 100644
--- a/crates/modules/charka/SDD.md
+++ b/crates/modules/charka/SDD.md
@@ -86,8 +86,8 @@ Tercera etapa: `Program` → `Ir`. Aquí se parsea cada `Sentence` cruda
 - `Procedure { name, body: Vec<Stmt> }`. `Stmt` cubre `Move`,
   `Display`, `Accept`, `Compute`, `Add`/`Subtract`/`Multiply`/`Divide`,
   `If`, `Evaluate`, `StringConcat`, `Unstring`, `Inspect`,
-  `Initialize`, `Perform`, `GoTo`, `StopRun`, `Goback`, `Exit`,
-  `Continue`.
+  `Initialize`, `SetTrue`, `Perform`, `GoTo`, `StopRun`, `Goback`,
+  `Exit`, `Continue`.
 - `Expr` — expresiones aritméticas con precedencia y paréntesis (Pratt:
   `+ -` < `* /` < `**` der.). `Cond` — comparaciones (símbolo o forma
   palabra) unidas por `AND`/`OR`/`NOT`, más nombres de condición
@@ -108,6 +108,8 @@ Tercera etapa: `Program` → `Ir`. Aquí se parsea cada `Sentence` cruda
 - `INITIALIZE` — resetea un dato (o todos los elementales de un grupo)
   a su valor por defecto. El `model` registra los grupos y sus
   miembros (`DataModel::groups`).
+- `SET cond... TO TRUE` — la cara de escritura de los nombres de
+  condición (nivel 88): asigna a su dato padre el valor del 88.
 - Fuera de alcance v1: E/S de ficheros, CICS, SQL embebido.
 
 ## charka-runtime
@@ -179,8 +181,8 @@ que corre el `Ir` directamente sobre `charka-runtime`, sin compilar.
 
 ## El corpus
 
-`crates/modules/charka/corpus/` — 15 programas COBOL graduados
-(`01-hola` … `15-resetear`), cada uno con su `.expected`. Ejercita el
+`crates/modules/charka/corpus/` — 16 programas COBOL graduados
+(`01-hola` … `16-bandera`), cada uno con su `.expected`. Ejercita el
 pipeline completo de punta a punta. Ver su `README.md`.
 
 ## La CLI
diff --git a/crates/modules/charka/charka-codegen/src/lib.rs b/crates/modules/charka/charka-codegen/src/lib.rs
index 92cffc0..0b5ffd2 100644
--- a/crates/modules/charka/charka-codegen/src/lib.rs
+++ b/crates/modules/charka/charka-codegen/src/lib.rs
@@ -427,6 +427,18 @@ mod tests {
         assert!(out.contains("self.ws_b.fill(' ');"));
     }
 
+    #[test]
+    fn set_to_true_moves_the_88_value() {
+        let out = gen("DATA DIVISION.\n\
+             WORKING-STORAGE SECTION.\n\
+             01 WS-F PIC X VALUE 'N'.\n\
+                88 LISTO VALUE 'S'.\n\
+             PROCEDURE DIVISION.\n\
+             MAIN.\n\
+                 SET LISTO TO TRUE.\n");
+        assert!(out.contains("self.ws_f.store(\"S\");"));
+    }
+
     #[test]
     fn empty_program_still_compiles_shape() {
         let out = gen("");
diff --git a/crates/modules/charka/charka-codegen/src/stmt.rs b/crates/modules/charka/charka-codegen/src/stmt.rs
index 3542dba..9bbf22d 100644
--- a/crates/modules/charka/charka-codegen/src/stmt.rs
+++ b/crates/modules/charka/charka-codegen/src/stmt.rs
@@ -87,6 +87,7 @@ pub(crate) fn emit_stmt(em: &mut Emitter, sym: &Symbols, stmt: &Stmt) {
         } => emit_unstring(em, sym, source, delimiter, into),
         Stmt::Inspect { target, op } => emit_inspect(em, sym, target, op),
         Stmt::Initialize { targets } => emit_initialize(em, sym, targets),
+        Stmt::SetTrue { conditions } => emit_set_true(em, sym, conditions),
         Stmt::Perform(p) => emit_perform(em, sym, p),
         Stmt::GoTo { target } => {
             em.line(&format!(
@@ -492,6 +493,21 @@ fn emit_initialize(em: &mut Emitter, sym: &Symbols, targets: &[Operand]) {
     }
 }
 
+/// `SET cond... TO TRUE` — asigna a cada dato padre el valor que hace
+/// verdadero su nombre de condición (nivel 88).
+fn emit_set_true(em: &mut Emitter, sym: &Symbols, conditions: &[String]) {
+    for name in conditions {
+        match sym.condition(name) {
+            Some(cn) => {
+                let target = Operand::Data(cn.parent.clone());
+                let value = cn.value.clone();
+                emit_move(em, sym, &value, std::slice::from_ref(&target));
+            }
+            None => em.line(&format!("// charka: condición 88 no resuelta — {name}")),
+        }
+    }
+}
+
 /// Resetea un campo completo (escalar o tabla entera).
 fn emit_reset(em: &mut Emitter, sym: &Symbols, name: &str) {
     let Some(f) = sym.lookup(name) else {
diff --git a/crates/modules/charka/charka-ir/src/ast.rs b/crates/modules/charka/charka-ir/src/ast.rs
index 77e6238..5492dc1 100644
--- a/crates/modules/charka/charka-ir/src/ast.rs
+++ b/crates/modules/charka/charka-ir/src/ast.rs
@@ -188,6 +188,9 @@ pub enum Stmt {
     /// `INITIALIZE targets...` — pone cada dato (o grupo) en su valor
     /// por defecto: 0 los numéricos, espacios los alfanuméricos.
     Initialize { targets: Vec<Operand> },
+    /// `SET cond-name... TO TRUE` — hace verdaderos esos nombres de
+    /// condición (nivel 88): asigna a su dato padre el valor del 88.
+    SetTrue { conditions: Vec<String> },
     /// `PERFORM ...` — ver [`Perform`].
     Perform(Perform),
     /// `GO TO target`
diff --git a/crates/modules/charka/charka-ir/src/lib.rs b/crates/modules/charka/charka-ir/src/lib.rs
index 93a29c6..b1bd14c 100644
--- a/crates/modules/charka/charka-ir/src/lib.rs
+++ b/crates/modules/charka/charka-ir/src/lib.rs
@@ -460,6 +460,17 @@ mod tests {
         }
     }
 
+    #[test]
+    fn set_to_true_parses() {
+        let b = body("SET ACTIVO LISTO TO TRUE.");
+        match &b[0] {
+            Stmt::SetTrue { conditions } => {
+                assert_eq!(conditions, &vec!["ACTIVO".to_string(), "LISTO".to_string()]);
+            }
+            other => panic!("se esperaba SET, vino {other:?}"),
+        }
+    }
+
     #[test]
     fn several_statements_in_one_sentence() {
         let b = body("MOVE 1 TO X DISPLAY X STOP RUN.");
diff --git a/crates/modules/charka/charka-ir/src/stmt.rs b/crates/modules/charka/charka-ir/src/stmt.rs
index ca570d6..b364b91 100644
--- a/crates/modules/charka/charka-ir/src/stmt.rs
+++ b/crates/modules/charka/charka-ir/src/stmt.rs
@@ -45,6 +45,7 @@ fn parse_one_stmt(c: &mut Cursor, stops: &[&str]) -> Stmt {
         "UNSTRING" => parse_unstring(c),
         "INSPECT" => parse_inspect(c),
         "INITIALIZE" => parse_initialize(c),
+        "SET" => parse_set(c),
         "PERFORM" => parse_perform(c),
         "GO" => parse_goto(c),
         "STOP" => parse_stop(c),
@@ -391,6 +392,24 @@ fn parse_unstring(c: &mut Cursor) -> Stmt {
     }
 }
 
+fn parse_set(c: &mut Cursor) -> Stmt {
+    c.bump(); // SET
+    let mut conditions = Vec::new();
+    while let Some(name) = parse_one_name(c) {
+        conditions.push(name);
+    }
+    // La v1 sólo modela `SET ... TO TRUE`.
+    if c.eat_word("TO") && c.eat_word("TRUE") {
+        Stmt::SetTrue { conditions }
+    } else {
+        skip_to_stmt_boundary(c);
+        Stmt::Unknown {
+            verb: "SET".to_string(),
+            tokens: Vec::new(),
+        }
+    }
+}
+
 fn parse_initialize(c: &mut Cursor) -> Stmt {
     c.bump(); // INITIALIZE
     let mut rounded = false;
diff --git a/crates/modules/charka/charka-shadow/src/interp.rs b/crates/modules/charka/charka-shadow/src/interp.rs
index 7bf19f6..d0d83fb 100644
--- a/crates/modules/charka/charka-shadow/src/interp.rs
+++ b/crates/modules/charka/charka-shadow/src/interp.rs
@@ -312,6 +312,14 @@ impl<'a> Machine<'a> {
                 }
                 Flow::Normal
             }
+            Stmt::SetTrue { conditions } => {
+                for name in conditions {
+                    if let Some(cn) = self.conditions.get(&name.to_uppercase()).cloned() {
+                        self.do_move(&cn.value, &Operand::Data(cn.parent));
+                    }
+                }
+                Flow::Normal
+            }
             Stmt::Perform(p) => self.exec_perform(p),
             Stmt::GoTo { target } => {
                 // Aproximación: ejecuta el destino y sale del párrafo.
diff --git a/crates/modules/charka/charka-shadow/src/lib.rs b/crates/modules/charka/charka-shadow/src/lib.rs
index 55c84fb..3404d63 100644
--- a/crates/modules/charka/charka-shadow/src/lib.rs
+++ b/crates/modules/charka/charka-shadow/src/lib.rs
@@ -124,6 +124,7 @@ mod tests {
     corpus_test!(corpus_13_inspeccion, "13-inspeccion");
     corpus_test!(corpus_14_clasifica, "14-clasifica");
     corpus_test!(corpus_15_resetear, "15-resetear");
+    corpus_test!(corpus_16_bandera, "16-bandera");
 
     #[test]
     fn empty_source_runs_clean() {
diff --git a/crates/modules/charka/corpus/16-bandera.cob b/crates/modules/charka/corpus/16-bandera.cob
new file mode 100644
index 0000000..ad59764
--- /dev/null
+++ b/crates/modules/charka/corpus/16-bandera.cob
@@ -0,0 +1,22 @@
+* corpus charka — nivel 5: SET de nombres de condición (nivel 88)
+IDENTIFICATION DIVISION.
+PROGRAM-ID. BANDERA.
+DATA DIVISION.
+WORKING-STORAGE SECTION.
+01 WS-ESTADO   PIC X VALUE 'N'.
+   88 ACTIVO   VALUE 'S'.
+   88 INACTIVO VALUE 'N'.
+01 WS-NIVEL    PIC 9(1) VALUE 0.
+   88 NIVEL-MAX VALUE 9.
+PROCEDURE DIVISION.
+MAIN.
+    IF INACTIVO
+        DISPLAY 'EMPIEZA INACTIVO'
+    END-IF.
+    SET ACTIVO TO TRUE.
+    IF ACTIVO
+        DISPLAY 'AHORA ACTIVO'
+    END-IF.
+    SET NIVEL-MAX TO TRUE.
+    DISPLAY 'NIVEL = ' WS-NIVEL.
+    STOP RUN.
diff --git a/crates/modules/charka/corpus/16-bandera.expected b/crates/modules/charka/corpus/16-bandera.expected
new file mode 100644
index 0000000..1aaf27a
--- /dev/null
+++ b/crates/modules/charka/corpus/16-bandera.expected
@@ -0,0 +1,3 @@
+EMPIEZA INACTIVO
+AHORA ACTIVO
+NIVEL = 9
diff --git a/crates/modules/charka/corpus/README.md b/crates/modules/charka/corpus/README.md
index 2c118d6..4a20837 100644
--- a/crates/modules/charka/corpus/README.md
+++ b/crates/modules/charka/corpus/README.md
@@ -24,6 +24,7 @@ salida correcta, una línea por `DISPLAY`.
 | `13-inspeccion`     | 6     | `INSPECT` — contar (`TALLYING`) y reemplazar       |
 | `14-clasifica`      | 6     | `EVALUATE TRUE` y rangos `WHEN ... THRU`           |
 | `15-resetear`       | 6     | `INITIALIZE` — resetear datos y grupos             |
+| `16-bandera`        | 5     | `SET` de nombres de condición (nivel 88) a `TRUE`  |
 
 ## Formato
 
diff --git a/docs/changelog/charka.md b/docs/changelog/charka.md
index c72a843..5445c36 100644
--- a/docs/changelog/charka.md
+++ b/docs/changelog/charka.md
@@ -3,6 +3,19 @@
 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): SET ... TO TRUE — escribir nombres de condición (88)
+
+La cara de escritura de los nombres de condición de COBOL: si `IF
+ES-VALIDO` los lee, `SET ES-VALIDO TO TRUE` los escribe.
+
+- IR: `Stmt::SetTrue { conditions }`.
+- Parser: `SET cond-1 cond-2 ... TO TRUE`. Otras formas de `SET`
+  (índices, `TO FALSE`) caen a `Stmt::Unknown`.
+- Codegen y shadow: `SET cond TO TRUE` asigna a su dato padre el valor
+  del 88 (un `MOVE` del valor a la variable).
+- Corpus: programa nuevo `16-bandera` (cambia banderas de texto y de
+  número con `SET`). Verificado en ambas rutas.
+
 ### feat(charka): INITIALIZE — resetear datos y grupos
 
 El verbo de COBOL para volver un dato (o un registro entero) a su