⎇ 634a43006ac4257288af40320b5360e9f157ab09
crates/modules/charka/charka-runtime/src/lib.rs
Ñawpa willay
Pi imata llamkarqan
ch'uya
feat(charka): PICTURE de edición — Z, coma de millares y punto decimal
1//! `charka-runtime` — el soporte de ejecución de los programas COBOL
2//! transpilados.
3//!
4//! Lo que `charka-codegen` emite no es Rust autónomo: es Rust que
5//! enlaza contra esta biblioteca. Aquí viven los tipos que dan a un
6//! programa transpilado la semántica de COBOL en tiempo de ejecución:
7//!
8//! - [`Num`] — un campo numérico (`PIC 9(5)V99`): un [`Decimal`] de
9//! punto fijo conformado a su [`Picture`]. Toda asignación trunca a
10//! la escala y al tamaño declarados, como el `MOVE` de COBOL.
11//! - [`Text`] — un campo alfanumérico (`PIC X(20)`) de longitud fija:
12//! toda asignación justifica a la izquierda y rellena o trunca.
13//!
14//! La aritmética decimal exacta la aporta `charka-bcd`, cuyos tipos
15//! ([`Decimal`], [`Picture`], [`Rounding`]) se reexportan para que el
16//! código generado sólo necesite `use charka_runtime::*;`.
17
18#![forbid(unsafe_code)]
19
20mod edited;
21mod file;
22mod num;
23mod text;
24
25pub use charka_bcd::{Decimal, Picture, Rounding};
26pub use edited::format_edited;
27pub use file::CobFile;
28pub use num::Num;
29pub use text::Text;
30
31use std::cmp::Ordering;
32
33/// Compara dos campos alfanuméricos con la semántica de COBOL: el más
34/// corto se considera rellenado con espacios a la derecha, de modo que
35/// `"AB"` y `"AB "` son iguales.
36pub fn cobol_text_cmp(a: &str, b: &str) -> Ordering {
37 let n = a.chars().count().max(b.chars().count());
38 let padded = |s: &str| -> Vec<char> {
39 let mut v: Vec<char> = s.chars().collect();
40 while v.len() < n {
41 v.push(' ');
42 }
43 v
44 };
45 padded(a).cmp(&padded(b))
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51
52 #[test]
53 fn text_cmp_orders_lexically() {
54 assert_eq!(cobol_text_cmp("ABC", "ABD"), Ordering::Less);
55 assert_eq!(cobol_text_cmp("ABD", "ABC"), Ordering::Greater);
56 assert_eq!(cobol_text_cmp("ABC", "ABC"), Ordering::Equal);
57 }
58
59 #[test]
60 fn text_cmp_pads_the_shorter_with_spaces() {
61 assert_eq!(cobol_text_cmp("AB", "AB "), Ordering::Equal);
62 assert_eq!(cobol_text_cmp("AB", "ABC"), Ordering::Less);
63 }
64
65 #[test]
66 fn fields_compose_for_generated_code() {
67 // Un mini-programa transpilado a mano: WS-CT crece, WS-MSG fijo.
68 let mut ws_ct = Num::with_value(Picture::new(3, 0, false), "0");
69 ws_ct.store(ws_ct.value().add(&Decimal::from_integer(5)));
70 assert_eq!(ws_ct.display(), "005");
71
72 let mut ws_msg = Text::new(10);
73 ws_msg.store("LISTO");
74 assert_eq!(ws_msg.as_str(), "LISTO ");
75 }
76}