feat(charka): PERFORM ... THRU como rango real de párrafos
PERFORM A THRU C ejecuta A, B y C; antes el transpilador sólo ejecutaba A (lo marcaba como aproximado). - charka-codegen: Symbols registra ahora los párrafos en orden con su nombre de método; Symbols::build toma el Ir completo. paragraph_range(name, thru) da los métodos del rango; emit_perform emite la llamada a cada uno. - charka-shadow: run_paragraph_range ejecuta los párrafos de name a thru inclusive. - Corpus: programa nuevo 17-rangopar (PERFORM PASO-A THRU PASO-C sobre tres párrafos). Verificado: el intérprete sombra y el crate compilado por scaffold dan la misma salida. Tests: charka-codegen 24, charka-shadow 22. fmt + clippy limpios. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -391,7 +391,9 @@ impl<'a> Machine<'a> {
|
||||
/// él termina esa pasada, no el programa.
|
||||
fn run_target(&mut self, target: &'a PerformTarget) -> Flow {
|
||||
let flow = match target {
|
||||
PerformTarget::Paragraph { name, .. } => self.run_paragraph(name),
|
||||
PerformTarget::Paragraph { name, thru } => {
|
||||
self.run_paragraph_range(name, thru.as_deref())
|
||||
}
|
||||
PerformTarget::Inline(body) => self.exec_block(body),
|
||||
};
|
||||
match flow {
|
||||
@@ -411,6 +413,34 @@ impl<'a> Machine<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Ejecuta el rango de párrafos de `name` a `thru` inclusive (el
|
||||
/// `PERFORM name THRU thru`); sólo `name` si `thru` es `None`.
|
||||
fn run_paragraph_range(&mut self, name: &str, thru: Option<&str>) -> Flow {
|
||||
let Some(&start) = self.para_index.get(&name.to_uppercase()) else {
|
||||
return Flow::Normal;
|
||||
};
|
||||
let end = match thru {
|
||||
Some(t) => self
|
||||
.para_index
|
||||
.get(&t.to_uppercase())
|
||||
.copied()
|
||||
.unwrap_or(start),
|
||||
None => start,
|
||||
};
|
||||
let (lo, hi) = if start <= end {
|
||||
(start, end)
|
||||
} else {
|
||||
(end, start)
|
||||
};
|
||||
let ir = self.ir;
|
||||
for i in lo..=hi {
|
||||
if let Flow::Stop = self.exec_block(&ir.procedures[i].body) {
|
||||
return Flow::Stop;
|
||||
}
|
||||
}
|
||||
Flow::Normal
|
||||
}
|
||||
|
||||
/// Resuelve una referencia a dato (escalar o elemento de tabla) a
|
||||
/// su nombre y un índice 0-based. `None` si no es una referencia.
|
||||
fn resolve(&self, op: &Operand) -> Option<(String, usize)> {
|
||||
|
||||
@@ -125,6 +125,7 @@ mod tests {
|
||||
corpus_test!(corpus_14_clasifica, "14-clasifica");
|
||||
corpus_test!(corpus_15_resetear, "15-resetear");
|
||||
corpus_test!(corpus_16_bandera, "16-bandera");
|
||||
corpus_test!(corpus_17_rangopar, "17-rangopar");
|
||||
|
||||
#[test]
|
||||
fn empty_source_runs_clean() {
|
||||
|
||||
Reference in New Issue
Block a user