feat(charka): INSPECT — contar y reemplazar caracteres
El verbo de COBOL para analizar y limpiar campos de texto.
- IR: Stmt::Inspect { target, op } con InspectOp::TallyingForAll
(cuenta apariciones y las suma a un contador) y
InspectOp::ReplacingAll (reemplaza apariciones).
- Parser: INSPECT t TALLYING n FOR ALL lit y
INSPECT t REPLACING ALL a BY b. Una forma no soportada cae a
Stmt::Unknown.
- Codegen: TALLYING -> str::matches(..).count(); REPLACING ->
str::replace.
- Shadow: el intérprete cuenta / reemplaza el texto.
- Corpus: programa nuevo 13-inspeccion. Verificado: el intérprete
sombra y el crate compilado por scaffold dan la misma salida.
Alcance v1: TALLYING FOR ALL y REPLACING ALL; sin LEADING, FIRST,
CHARACTERS, BEFORE/AFTER.
Tests: charka-ir 26, charka-codegen 20, charka-shadow 18. fmt +
clippy limpios.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -8,8 +8,8 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use charka_ir::{
|
||||
BinOp, CmpOp, Cond, ConditionName, Expr, Figurative, Ir, Operand, Perform, PerformControl,
|
||||
PerformTarget, Stmt,
|
||||
BinOp, CmpOp, Cond, ConditionName, Expr, Figurative, InspectOp, Ir, Operand, Perform,
|
||||
PerformControl, PerformTarget, Stmt,
|
||||
};
|
||||
use charka_runtime::{cobol_text_cmp, Decimal, Rounding};
|
||||
|
||||
@@ -270,6 +270,33 @@ impl<'a> Machine<'a> {
|
||||
}
|
||||
Flow::Normal
|
||||
}
|
||||
Stmt::Inspect { target, op } => {
|
||||
match op {
|
||||
InspectOp::TallyingForAll { counter, search } => {
|
||||
let hay = self.eval_text(target);
|
||||
let needle = self.eval_text(search);
|
||||
let n = if needle.is_empty() {
|
||||
0
|
||||
} else {
|
||||
hay.matches(needle.as_str()).count()
|
||||
};
|
||||
let cur = self.eval_decimal(counter);
|
||||
self.store(counter, cur.add(&Decimal::from_integer(n as i128)), false);
|
||||
}
|
||||
InspectOp::ReplacingAll { from, to } => {
|
||||
let hay = self.eval_text(target);
|
||||
let f = self.eval_text(from);
|
||||
let t = self.eval_text(to);
|
||||
let new = if f.is_empty() {
|
||||
hay
|
||||
} else {
|
||||
hay.replace(f.as_str(), t.as_str())
|
||||
};
|
||||
self.store_text(target, &new);
|
||||
}
|
||||
}
|
||||
Flow::Normal
|
||||
}
|
||||
Stmt::Perform(p) => self.exec_perform(p),
|
||||
Stmt::GoTo { target } => {
|
||||
// Aproximación: ejecuta el destino y sale del párrafo.
|
||||
|
||||
@@ -121,6 +121,7 @@ mod tests {
|
||||
corpus_test!(corpus_10_condicion, "10-condicion");
|
||||
corpus_test!(corpus_11_tabla, "11-tabla");
|
||||
corpus_test!(corpus_12_cadenas, "12-cadenas");
|
||||
corpus_test!(corpus_13_inspeccion, "13-inspeccion");
|
||||
|
||||
#[test]
|
||||
fn empty_source_runs_clean() {
|
||||
|
||||
Reference in New Issue
Block a user