feat(charka): PICTURE de edición — Z, coma de millares y punto decimal
El formateo de informes de COBOL: supresión de ceros a la izquierda, coma de millares e inserción del punto decimal. Rebanada vertical. - charka-lexer: el punto separador exige un espacio detrás; un punto pegado a un carácter (ZZ9.99) ya no es terminador, sino símbolo — el parser lo reensambla dentro de la cláusula PICTURE. - charka-runtime: format_edited(valor, pic) — 9, Z, coma, punto, B. - charka-ir: Field::edit guarda la PICTURE; el campo es texto. - charka-codegen / charka-shadow: MOVE a un campo de edición pasa por format_edited antes de almacenar. - Corpus: 19-reporte. Sombra y crate compilado dan la misma salida. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -474,6 +474,21 @@ mod tests {
|
||||
assert!(out.contains("self.file_arch.close();"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn edited_field_is_text_and_move_formats_it() {
|
||||
let out = gen("DATA DIVISION.\n\
|
||||
WORKING-STORAGE SECTION.\n\
|
||||
01 WS-N PIC 9(5).\n\
|
||||
01 WS-E PIC Z,ZZ9.99.\n\
|
||||
PROCEDURE DIVISION.\n\
|
||||
MAIN.\n\
|
||||
MOVE WS-N TO WS-E.\n");
|
||||
// El campo de edición se materializa como texto de presentación.
|
||||
assert!(out.contains("ws_e: Text,"));
|
||||
// El MOVE pasa por `format_edited` con la PICTURE de edición.
|
||||
assert!(out.contains("self.ws_e.store(&format_edited(self.ws_n.value(), \"Z,ZZ9.99\"));"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_program_still_compiles_shape() {
|
||||
let out = gen("");
|
||||
|
||||
@@ -8,7 +8,8 @@ use charka_ir::{
|
||||
|
||||
use crate::emit::Emitter;
|
||||
use crate::expr::{
|
||||
emit_cond, emit_expr, field_ref, figurative_fill, operand_decimal, operand_display, operand_str,
|
||||
emit_cond, emit_expr, field_ref, figurative_fill, operand_decimal, operand_display,
|
||||
operand_str, rust_str,
|
||||
};
|
||||
use crate::sym::{paragraph_method, FieldKind, Symbols};
|
||||
|
||||
@@ -136,6 +137,21 @@ fn emit_store(em: &mut Emitter, sym: &Symbols, target: &Operand, value: &str, ro
|
||||
|
||||
fn emit_move(em: &mut Emitter, sym: &Symbols, from: &Operand, to: &[Operand]) {
|
||||
for t in to {
|
||||
// Un destino con PICTURE de edición formatea el valor numérico.
|
||||
if let Operand::Data(name) = t {
|
||||
if let Some(pic) = sym.lookup(name).and_then(|f| f.edit.clone()) {
|
||||
let ident = sym
|
||||
.lookup(name)
|
||||
.map(|f| f.ident.clone())
|
||||
.unwrap_or_default();
|
||||
em.line(&format!(
|
||||
"self.{ident}.store(&format_edited({}, {}));",
|
||||
operand_decimal(sym, from),
|
||||
rust_str(&pic)
|
||||
));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
match field_ref(sym, t) {
|
||||
Some((lref, FieldKind::Num { .. })) => {
|
||||
em.line(&format!("{lref}.store({});", operand_decimal(sym, from)));
|
||||
|
||||
@@ -22,6 +22,8 @@ pub(crate) struct Field {
|
||||
pub init: String,
|
||||
/// Si es una tabla (`OCCURS n`), su número de elementos.
|
||||
pub occurs: Option<u32>,
|
||||
/// Si es un campo de edición, su PICTURE.
|
||||
pub edit: Option<String>,
|
||||
}
|
||||
|
||||
/// Un fichero del programa generado.
|
||||
@@ -62,6 +64,7 @@ impl Symbols {
|
||||
kind: f.kind,
|
||||
init: f.init.clone(),
|
||||
occurs: f.occurs,
|
||||
edit: f.edit.clone(),
|
||||
})
|
||||
.collect();
|
||||
dedup_idents(&mut fields);
|
||||
|
||||
Reference in New Issue
Block a user