Skip to main content

ironwork_exec/machine/
report.rs

1//! INITIATE, GENERATE, TERMINATE and SUPPRESS PRINTING, whose semantics are `rt::report`: the
2//! reports and DETAIL groups they name, and the SOURCE, SUM and CONTROL operands the walker
3//! evaluates for it.
4
5use super::*;
6use crate::files::Format;
7use rt::lir::Spacing;
8use rt::report::{ReportFile, ReportHost, ReportOp, UseEnd};
9use std::io::Write;
10use syntax::report::ReportStmt;
11
12impl<'p> Machine<'p, '_, '_> {
13    pub(super) fn report_statement(&mut self, s: &'p ReportStmt) -> R<Flow> {
14        let writer = self.report_writer;
15        let run = |m: &mut Self, op, pos| rt::report::run(m, writer, op, pos);
16        let ended = match s {
17            ReportStmt::Initiate { reports, pos } | ReportStmt::Terminate { reports, pos } => {
18                let mut ended = None;
19                for n in reports {
20                    let ri = self.report_named(n, *pos)? as u32;
21                    let op = if matches!(s, ReportStmt::Initiate { .. }) { ReportOp::Initiate(ri) } else { ReportOp::Terminate(ri) };
22                    ended = run(self, op, *pos)?;
23                    if ended.is_some() {
24                        break;
25                    }
26                }
27                ended
28            }
29            ReportStmt::Generate { name, qualifier, pos } => {
30                let (ri, detail) = crate::report::generate_target(&writer.reports, name, qualifier.as_deref())
31                    .ok_or_else(|| Abend::ironwork(format!("GENERATE {name}: no such DETAIL group or report"), *pos))?;
32                run(self, ReportOp::Generate { report: ri as u32, detail: detail.map(|d| d as u32) }, *pos)?
33            }
34            ReportStmt::Suppress { pos } => run(self, ReportOp::Suppress, *pos)?,
35        };
36        Ok(match ended {
37            Some(e) => Flow::End(e),
38            None => Flow::Next,
39        })
40    }
41
42    fn report_named(&self, name: &str, pos: Pos) -> R<usize> {
43        self.report_writer.reports.iter().position(|r| r.name == name).ok_or_else(|| Abend::ironwork(format!("{name} is not a report of this program"), pos))
44    }
45}
46
47impl<'p> ReportHost<'p, Expr, Ref, Literal> for Machine<'p, '_, '_> {
48    fn value(&mut self, expr: &Expr, pos: Pos) -> R<Val> {
49        self.expr_value(expr, pos)
50    }
51
52    fn operand(&mut self, expr: &Expr, pos: Pos) -> Option<R<(Val, Option<Loc>)>> {
53        match expr {
54            Expr::Operand(op) => Some(self.operand_with_loc(op, pos)),
55            _ => None,
56        }
57    }
58
59    fn literal(&mut self, value: &Literal, pos: Pos) -> R<Val> {
60        self.literal_value(value, pos)
61    }
62
63    fn item(&self, item: usize) -> Loc {
64        let it = &self.layout.items[item];
65        Loc { offset: self.base + it.offset as usize, len: it.size as usize, kind: it.kind, item }
66    }
67
68    fn store_value(&mut self, dest: Loc, value: Val, rounded: bool, keep_on_size_error: bool, pos: Pos) -> R<bool> {
69        Machine::store_value(self, dest, value, rounded, keep_on_size_error, pos)
70    }
71
72    fn store_checked(&mut self, dest: Loc, value: &Fixed, pos: Pos) -> R<bool> {
73        self.store_fixed_checked(dest, value, false, true, pos)
74    }
75
76    fn report_file(&mut self, k: usize) -> ReportFile {
77        ReportFile {
78            area: self.area(k),
79            variable: self.unit.programs[self.me].files[k].as_ref().is_some_and(|f| f.format == Format::Variable),
80            reserved: self.carriage[k].is_some_and(|c| c.reserved),
81            record_min: self.program.files[k].record_min,
82        }
83    }
84
85    fn write_line(&mut self, k: usize, loc: Loc, space: Spacing, pos: Pos) -> R<()> {
86        self.write_stream(k, loc, false, space, pos)
87    }
88
89    fn use_before_reporting(&mut self, (first, last): (usize, usize), pos: Pos) -> R<UseEnd> {
90        self.nest(pos)?;
91        self.uses.arrival = declaratives::Arrival::Use;
92        let flow = self.run_paragraphs(first, last);
93        self.unit.depth -= 1;
94        Ok(match flow? {
95            Flow::End(e) => UseEnd::End(e),
96            Flow::GoTo(_) => UseEnd::GoTo,
97            leaving @ (Flow::Resume(..) | Flow::Return(_)) => {
98                self.uses.leaving = Some(leaving);
99                UseEnd::Left
100            }
101            _ => UseEnd::Completed,
102        })
103    }
104
105    fn err(&mut self) -> &mut dyn Write {
106        &mut *self.unit.err
107    }
108}