1pub mod abend;
5pub use rt::calendar;
6pub use rt::cics;
7pub use rt::codec;
8pub use rt::digest;
9pub use rt::evidence;
10pub use compile::collating;
11pub use compile::declaratives;
12pub mod edit;
13pub use rt::files;
14pub use compile::layout;
15pub mod le;
16pub use rt::lir;
17pub use compile::linage;
18pub mod loader;
19pub mod lower;
20pub mod machine;
21pub use rt::module;
22pub mod oo;
23pub use compile::picture;
24pub mod printer;
25pub mod report;
26use compile::sort;
27pub mod sql;
28pub use rt::strings;
29pub mod terminal;
30#[cfg(test)]
31mod testing;
32pub use rt::tn3270;
33pub mod unit;
34pub mod vm;
35
36pub use compile::{Compiled, EntryPoint, compile, compile_at, compile_time, entry_points};
37pub(crate) use compile::{procedure, procedure_from, section_end};
38pub use machine::{Abend, Ending};
39
40use abend::AbendCode;
41use unit::AddProgram;
42use std::io::{BufRead, Write};
43use syntax::Pos;
44
45pub trait Execute {
47 fn run(&self, out: &mut dyn Write, err: &mut dyn Write) -> Result<Ending, Abend>;
48
49 fn run_with(&self, dds: files::Dds, out: &mut dyn Write, err: &mut dyn Write) -> Result<Ending, Abend>;
51
52 fn execute<'w>(
55 &self,
56 library: unit::Library,
57 dds: files::Dds,
58 sysin: Option<Box<dyn BufRead + 'w>>,
59 clock: unit::Clock,
60 out: &'w mut dyn Write,
61 err: &'w mut dyn Write,
62 ) -> Result<(Ending, i16), Abend>;
63
64 #[allow(clippy::too_many_arguments)]
66 fn execute_with<'w>(
67 &self,
68 library: unit::Library,
69 dds: files::Dds,
70 sysin: Option<Box<dyn BufRead + 'w>>,
71 clock: unit::Clock,
72 database: Option<&'w mut (dyn sql::Database + '_)>,
73 out: &'w mut dyn Write,
74 err: &'w mut dyn Write,
75 ) -> Result<(Ending, i16), Abend>;
76
77 #[allow(clippy::too_many_arguments)]
80 fn execute_observed<'w>(
81 &self,
82 library: unit::Library,
83 dds: files::Dds,
84 sysin: Option<Box<dyn BufRead + 'w>>,
85 clock: unit::Clock,
86 database: Option<&'w mut (dyn sql::Database + '_)>,
87 out: &'w mut dyn Write,
88 err: &'w mut dyn Write,
89 observer: Option<unit::Observer<'w>>,
90 ) -> Result<(Ending, i16), Abend>;
91
92 #[allow(clippy::too_many_arguments)]
96 fn execute_main<'w>(
97 &self,
98 library: unit::Library,
99 dds: files::Dds,
100 sysin: Option<Box<dyn BufRead + 'w>>,
101 clock: unit::Clock,
102 database: Option<&'w mut (dyn sql::Database + '_)>,
103 out: &'w mut dyn Write,
104 err: &'w mut dyn Write,
105 observer: Option<unit::Observer<'w>>,
106 parm: &str,
107 ) -> Result<(Ending, i16), Abend>;
108
109 #[allow(clippy::too_many_arguments)]
112 fn execute_kept<'w>(
113 &self,
114 library: unit::Library,
115 dds: files::Dds,
116 sysin: Option<Box<dyn BufRead + 'w>>,
117 clock: unit::Clock,
118 database: Option<&'w mut (dyn sql::Database + '_)>,
119 out: &'w mut dyn Write,
120 err: &'w mut dyn Write,
121 observer: Option<unit::Observer<'w>>,
122 kept: &mut Option<unit::Remains>,
123 ) -> Result<(Ending, i16), Abend>;
124
125 fn execute_cics<'w>(
129 &self,
130 library: unit::Library,
131 dds: files::Dds,
132 task: cics::Task,
133 clock: unit::Clock,
134 out: &'w mut dyn Write,
135 err: &'w mut dyn Write,
136 ) -> Result<(Ending, cics::Task), Abend>;
137
138 #[allow(clippy::too_many_arguments)]
142 fn execute_cics_with<'w>(
143 &self,
144 library: unit::Library,
145 dds: files::Dds,
146 task: cics::Task,
147 clock: unit::Clock,
148 database: Option<&'w mut (dyn sql::Database + '_)>,
149 out: &'w mut dyn Write,
150 err: &'w mut dyn Write,
151 ) -> Result<(Ending, cics::Task), Abend>;
152
153 #[allow(clippy::too_many_arguments)]
156 fn execute_cics_observed<'w>(
157 &self,
158 library: unit::Library,
159 dds: files::Dds,
160 task: cics::Task,
161 clock: unit::Clock,
162 database: Option<&'w mut (dyn sql::Database + '_)>,
163 out: &'w mut dyn Write,
164 err: &'w mut dyn Write,
165 observer: Option<unit::Observer<'w>>,
166 ) -> Result<(Ending, cics::Task), Abend>;
167}
168
169impl Execute for Compiled {
170 fn run(&self, out: &mut dyn Write, err: &mut dyn Write) -> Result<Ending, Abend> {
171 self.run_with(files::Dds::default(), out, err)
172 }
173
174 fn run_with(&self, dds: files::Dds, out: &mut dyn Write, err: &mut dyn Write) -> Result<Ending, Abend> {
175 self.execute(unit::Library::default(), dds, None, unit::Clock::System, out, err).map(|(ending, _)| ending)
176 }
177
178 fn execute<'w>(
179 &self,
180 library: unit::Library,
181 dds: files::Dds,
182 sysin: Option<Box<dyn BufRead + 'w>>,
183 clock: unit::Clock,
184 out: &'w mut dyn Write,
185 err: &'w mut dyn Write,
186 ) -> Result<(Ending, i16), Abend> {
187 self.execute_with(library, dds, sysin, clock, None, out, err)
188 }
189
190 fn execute_with<'w>(
191 &self,
192 library: unit::Library,
193 dds: files::Dds,
194 sysin: Option<Box<dyn BufRead + 'w>>,
195 clock: unit::Clock,
196 database: Option<&'w mut (dyn sql::Database + '_)>,
197 out: &'w mut dyn Write,
198 err: &'w mut dyn Write,
199 ) -> Result<(Ending, i16), Abend> {
200 self.execute_observed(library, dds, sysin, clock, database, out, err, None)
201 }
202
203 fn execute_observed<'w>(
204 &self,
205 library: unit::Library,
206 dds: files::Dds,
207 sysin: Option<Box<dyn BufRead + 'w>>,
208 clock: unit::Clock,
209 database: Option<&'w mut (dyn sql::Database + '_)>,
210 out: &'w mut dyn Write,
211 err: &'w mut dyn Write,
212 observer: Option<unit::Observer<'w>>,
213 ) -> Result<(Ending, i16), Abend> {
214 run_main(self, library, dds, sysin, clock, database, out, err, observer, None, &mut None)
215 }
216
217 fn execute_main<'w>(
218 &self,
219 library: unit::Library,
220 dds: files::Dds,
221 sysin: Option<Box<dyn BufRead + 'w>>,
222 clock: unit::Clock,
223 database: Option<&'w mut (dyn sql::Database + '_)>,
224 out: &'w mut dyn Write,
225 err: &'w mut dyn Write,
226 observer: Option<unit::Observer<'w>>,
227 parm: &str,
228 ) -> Result<(Ending, i16), Abend> {
229 run_main(self, library, dds, sysin, clock, database, out, err, observer, Some(parm), &mut None)
230 }
231
232 fn execute_kept<'w>(
233 &self,
234 library: unit::Library,
235 dds: files::Dds,
236 sysin: Option<Box<dyn BufRead + 'w>>,
237 clock: unit::Clock,
238 database: Option<&'w mut (dyn sql::Database + '_)>,
239 out: &'w mut dyn Write,
240 err: &'w mut dyn Write,
241 observer: Option<unit::Observer<'w>>,
242 kept: &mut Option<unit::Remains>,
243 ) -> Result<(Ending, i16), Abend> {
244 run_main(self, library, dds, sysin, clock, database, out, err, observer, None, kept)
245 }
246
247 fn execute_cics<'w>(
248 &self,
249 library: unit::Library,
250 dds: files::Dds,
251 task: cics::Task,
252 clock: unit::Clock,
253 out: &'w mut dyn Write,
254 err: &'w mut dyn Write,
255 ) -> Result<(Ending, cics::Task), Abend> {
256 self.execute_cics_with(library, dds, task, clock, None, out, err)
257 }
258
259 fn execute_cics_with<'w>(
260 &self,
261 library: unit::Library,
262 dds: files::Dds,
263 task: cics::Task,
264 clock: unit::Clock,
265 database: Option<&'w mut (dyn sql::Database + '_)>,
266 out: &'w mut dyn Write,
267 err: &'w mut dyn Write,
268 ) -> Result<(Ending, cics::Task), Abend> {
269 self.execute_cics_observed(library, dds, task, clock, database, out, err, None)
270 }
271
272 fn execute_cics_observed<'w>(
273 &self,
274 library: unit::Library,
275 dds: files::Dds,
276 mut task: cics::Task,
277 clock: unit::Clock,
278 database: Option<&'w mut (dyn sql::Database + '_)>,
279 out: &'w mut dyn Write,
280 err: &'w mut dyn Write,
281 observer: Option<unit::Observer<'w>>,
282 ) -> Result<(Ending, cics::Task), Abend> {
283 oo::refuse_to_run(&self.program)?;
284 let mut run_unit = unit::RunUnit::new(library, dds, None, clock, out, err);
285 run_unit.observer = observer;
286 run_unit.sql = database.map(sql::Session::new);
287 let me = run_unit.add(None, &self.program, self.layout.size as usize);
288 run_unit.eib = run_unit.push_temporary(&[0; cics::EIB_LEN]);
289 let commarea = task.commarea.take();
290 let length = commarea.as_ref().map_or(0, Vec::len);
291 let commarea = commarea.map(|c| run_unit.push_temporary(&c));
292 run_unit.cics = Some(task);
293 let ending = machine::Machine::activation(self, me, &mut run_unit, true).and_then(|mut m| {
294 m.begin_task(commarea, length);
295 m.run_level()
296 });
297 let settled = run_unit.sql.as_mut().map_or(Ok(()), |s| s.end_task(&self.program.id, ending.is_ok()).map(drop));
298 let mut closed = run_unit.close_all();
299 for (name, f) in run_unit.cics_files.drain() {
300 if let Err(e) = f.close() {
301 closed = closed.and(Err(format!("closing CICS file {name}: {e}")));
302 }
303 }
304 let mut task = run_unit.cics.take().unwrap_or_default();
305 if let Err(e) = task.flush_td(self.options.code_page()) {
306 closed = closed.and(Err(format!("writing transient data: {e}")));
307 }
308 let ending = ending.map_err(|a| match a.code {
309 AbendCode::Check(_) | AbendCode::Protection => Abend { message: format!("{} ({}, which CICS reports as ASRA)", a.message, a.code), code: AbendCode::Cics("ASRA".into()), pos: a.pos, file: a.file },
310 _ => a,
311 })?;
312 settled.map_err(|a| Abend { code: a.code.into(), message: a.message, pos: Pos::default(), file: None })?;
313 closed.map_err(|m| Abend { code: AbendCode::Ironwork, message: m, pos: Pos::default(), file: None })?;
314 Ok((ending, task))
315 }
316}
317
318#[allow(clippy::too_many_arguments)]
321fn run_main<'w>(
322 compiled: &Compiled,
323 library: unit::Library,
324 dds: files::Dds,
325 sysin: Option<Box<dyn BufRead + 'w>>,
326 clock: unit::Clock,
327 database: Option<&'w mut (dyn sql::Database + '_)>,
328 out: &'w mut dyn Write,
329 err: &'w mut dyn Write,
330 observer: Option<unit::Observer<'w>>,
331 parm: Option<&str>,
332 kept: &mut Option<unit::Remains>,
333) -> Result<(Ending, i16), Abend> {
334 oo::refuse_to_run(&compiled.program)?;
335 let statements = library.trace_statements.clone();
336 let mut run_unit = unit::RunUnit::new(library, dds, sysin, clock, out, err);
337 run_unit.observer = observer;
338 run_unit.statements = statements;
339 run_unit.sql = database.map(sql::Session::new);
340 let me = run_unit.add(None, &compiled.program, compiled.layout.size as usize);
341 let parm = parm.map(|p| run_unit.push_temporary(&rt::le::parm::parameter_area(rt::le::parm::program_arguments(p), compiled.options.code_page())));
342 let ending = machine::Machine::activation(compiled, me, &mut run_unit, true).and_then(|mut m| {
343 if parm.is_some() {
344 m.bind(&[parm]);
345 }
346 m.run_procedure()
347 });
348 let settled = run_unit.sql.as_mut().map_or(Ok(()), |s| s.settle(&compiled.program.id, ending.is_ok()).map(drop));
349 let closed = run_unit.close_all();
350 *kept = Some(unit::Remains::of(&run_unit));
351 let ending = ending?;
352 settled.map_err(|a| Abend { code: a.code.into(), message: a.message, pos: Pos::default(), file: None })?;
353 closed.map_err(|m| Abend { code: AbendCode::Ironwork, message: m, pos: Pos::default(), file: None })?;
354 Ok((ending, run_unit.return_code()))
355}
356
357#[cfg(test)]
358mod tests;