1use super::Condition;
7use crate::lir::{Operand, ParaId, PlaceId, SymId};
8use crate::module::ModuleError;
9use crate::module::codec::{Decode, Encode, Reader, Writer};
10use crate::{codec_enum, codec_struct};
11
12#[derive(Clone, Copy, Debug, PartialEq, Eq)]
15pub enum Datum<P = PlaceId, O = Operand, S = SymId> {
16 Place(P),
17 Value(O),
18 Text(S),
19 Bare,
20}
21
22pub type Opt<P = PlaceId, O = Operand, S = SymId> = Option<Datum<P, O, S>>;
24
25#[derive(Clone, Debug, PartialEq, Eq)]
26pub struct CicsCommand<P = PlaceId, O = Operand, S = SymId> {
27 pub name: S,
29 pub command: Cics<P, O, S>,
30 pub resp: Resp<P, O, S>,
31}
32
33#[derive(Clone, Debug, PartialEq, Eq)]
35pub struct Resp<P = PlaceId, O = Operand, S = SymId> {
36 pub resp: Opt<P, O, S>,
37 pub resp2: Opt<P, O, S>,
38 pub nohandle: bool,
39}
40
41#[derive(Clone, Debug, PartialEq, Eq)]
43pub enum Cics<P = PlaceId, O = Operand, S = SymId> {
44 File { verb: FileControl, file: Opt<P, O, S>, options: FileOptions<P, O, S> },
45 Return { transid: Opt<P, O, S>, commarea: Opt<P, O, S>, length: Opt<P, O, S> },
46 Link(Transfer<P, O, S>),
47 Xctl(Transfer<P, O, S>),
48 Abend { abcode: Opt<P, O, S>, cancel: bool },
49 HandleCondition(Vec<(Condition, Option<ParaId>)>),
51 IgnoreCondition(Vec<Condition>),
52 PushHandle,
53 PopHandle,
54 HandleAbend { program: bool, label: Option<ParaId>, reset: bool },
56 HandleAid,
57 SendMap { map: Opt<P, O, S>, mapset: Opt<P, O, S>, from: Opt<P, O, S>, maponly: bool, dataonly: bool, cursor: Opt<P, O, S>, control: Control },
58 ReceiveMap { map: Opt<P, O, S>, mapset: Opt<P, O, S>, into: Opt<P, O, S>, set: Opt<P, O, S> },
59 SendControl { cursor: Opt<P, O, S>, control: Control },
60 Receive(Record<P, O, S>),
61 Asktime { abstime: Opt<P, O, S> },
62 Formattime { abstime: Opt<P, O, S>, datesep: Opt<P, O, S>, timesep: Opt<P, O, S>, outputs: Vec<(S, Datum<P, O, S>)> },
64 Assign(Assign<P, O, S>),
65 Getmain { flength: Opt<P, O, S>, length: Opt<P, O, S>, initimg: Opt<P, O, S>, set: Opt<P, O, S> },
66 Freemain,
67 Enq,
68 Deq,
69 Delay,
70 Syncpoint { rollback: bool },
72 Address { eib: Opt<P, O, S>, commarea: Opt<P, O, S>, cwa: Opt<P, O, S>, twa: Opt<P, O, S> },
73 SendText { from: Opt<P, O, S>, length: Opt<P, O, S> },
74 WriteOperator { text: Opt<P, O, S>, textlength: Opt<P, O, S> },
75 WriteqTs { queue: Opt<P, O, S>, from: Opt<P, O, S>, length: Opt<P, O, S>, rewrite: bool, item: Opt<P, O, S>, numitems: Opt<P, O, S> },
76 ReadqTs { queue: Opt<P, O, S>, next: bool, item: Opt<P, O, S>, numitems: Opt<P, O, S>, record: Record<P, O, S> },
77 DeleteqTs { queue: Opt<P, O, S> },
78 WriteqTd { queue: Opt<P, O, S>, from: Opt<P, O, S>, length: Opt<P, O, S> },
79 ReadqTd { queue: Opt<P, O, S>, record: Record<P, O, S> },
80 DeleteqTd { queue: Opt<P, O, S> },
81 Unsupported,
83}
84
85#[derive(Clone, Copy, Debug, PartialEq, Eq)]
86pub enum FileControl {
87 Read,
88 Write,
89 Rewrite,
90 Delete,
91 Unlock,
92 Startbr,
93 Resetbr,
94 Readnext,
95 Readprev,
96 Endbr,
97}
98
99#[derive(Clone, Debug, PartialEq, Eq)]
100pub struct FileOptions<P = PlaceId, O = Operand, S = SymId> {
101 pub ridfld: Opt<P, O, S>,
102 pub keylength: Opt<P, O, S>,
103 pub reqid: Opt<P, O, S>,
104 pub from: Opt<P, O, S>,
105 pub numrec: Opt<P, O, S>,
106 pub record: Record<P, O, S>,
107 pub generic: bool,
108 pub rrn: bool,
109 pub gteq: bool,
110 pub equal: bool,
111 pub update: bool,
112}
113
114#[derive(Clone, Debug, PartialEq, Eq)]
117pub struct Record<P = PlaceId, O = Operand, S = SymId> {
118 pub into: Opt<P, O, S>,
119 pub set: Opt<P, O, S>,
120 pub length: Opt<P, O, S>,
121}
122
123#[derive(Clone, Debug, PartialEq, Eq)]
125pub struct Transfer<P = PlaceId, O = Operand, S = SymId> {
126 pub program: Opt<P, O, S>,
127 pub commarea: Opt<P, O, S>,
128 pub length: Opt<P, O, S>,
129}
130
131#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
133pub struct Control {
134 pub erase: bool,
135 pub freekb: bool,
136 pub alarm: bool,
137 pub frset: bool,
138}
139
140#[derive(Clone, Debug, PartialEq, Eq)]
142pub struct Assign<P = PlaceId, O = Operand, S = SymId> {
143 pub applid: Opt<P, O, S>,
144 pub sysid: Opt<P, O, S>,
145 pub userid: Opt<P, O, S>,
146 pub netname: Opt<P, O, S>,
147 pub facility: Opt<P, O, S>,
148 pub startcode: Opt<P, O, S>,
149 pub abcode: Opt<P, O, S>,
150 pub program: Opt<P, O, S>,
151 pub cwaleng: Opt<P, O, S>,
152 pub twaleng: Opt<P, O, S>,
153}
154
155impl<P, O, S> Cics<P, O, S> {
156 pub fn name(&self) -> &'static str {
158 match self {
159 Self::File { verb, .. } => verb.name(),
160 Self::Return { .. } => "RETURN",
161 Self::Link(_) => "LINK",
162 Self::Xctl(_) => "XCTL",
163 Self::Abend { .. } => "ABEND",
164 Self::HandleCondition(_) => "HANDLE CONDITION",
165 Self::IgnoreCondition(_) => "IGNORE CONDITION",
166 Self::PushHandle => "PUSH HANDLE",
167 Self::PopHandle => "POP HANDLE",
168 Self::HandleAbend { .. } => "HANDLE ABEND",
169 Self::HandleAid => "HANDLE AID",
170 Self::SendMap { .. } => "SEND MAP",
171 Self::ReceiveMap { .. } => "RECEIVE MAP",
172 Self::SendControl { .. } => "SEND CONTROL",
173 Self::Receive(_) => "RECEIVE",
174 Self::Asktime { .. } => "ASKTIME",
175 Self::Formattime { .. } => "FORMATTIME",
176 Self::Assign(_) => "ASSIGN",
177 Self::Getmain { .. } => "GETMAIN",
178 Self::Freemain => "FREEMAIN",
179 Self::Enq => "ENQ",
180 Self::Deq => "DEQ",
181 Self::Delay => "DELAY",
182 Self::Syncpoint { .. } => "SYNCPOINT",
183 Self::Address { .. } => "ADDRESS",
184 Self::SendText { .. } => "SEND TEXT",
185 Self::WriteOperator { .. } => "WRITE OPERATOR",
186 Self::WriteqTs { .. } => "WRITEQ TS",
187 Self::ReadqTs { .. } => "READQ TS",
188 Self::DeleteqTs { .. } => "DELETEQ TS",
189 Self::WriteqTd { .. } => "WRITEQ TD",
190 Self::ReadqTd { .. } => "READQ TD",
191 Self::DeleteqTd { .. } => "DELETEQ TD",
192 Self::Unsupported => "unsupported",
193 }
194 }
195}
196
197pub trait Handles<P, O, S> {
200 type Place;
201 type Value;
202 type Text;
203 type Error;
204 fn place(&mut self, place: P) -> Result<Self::Place, Self::Error>;
205 fn value(&mut self, value: O) -> Result<Self::Value, Self::Error>;
206 fn text(&mut self, text: S) -> Result<Self::Text, Self::Error>;
207}
208
209type Mapped<H, P, O, S, T> = Result<T, <H as Handles<P, O, S>>::Error>;
210type DatumOf<H, P, O, S> = Datum<<H as Handles<P, O, S>>::Place, <H as Handles<P, O, S>>::Value, <H as Handles<P, O, S>>::Text>;
211type OptOf<H, P, O, S> = Option<DatumOf<H, P, O, S>>;
212type CommandOf<H, P, O, S> = CicsCommand<<H as Handles<P, O, S>>::Place, <H as Handles<P, O, S>>::Value, <H as Handles<P, O, S>>::Text>;
213type CicsOf<H, P, O, S> = Cics<<H as Handles<P, O, S>>::Place, <H as Handles<P, O, S>>::Value, <H as Handles<P, O, S>>::Text>;
214type RecordOf<H, P, O, S> = Record<<H as Handles<P, O, S>>::Place, <H as Handles<P, O, S>>::Value, <H as Handles<P, O, S>>::Text>;
215type TransferOf<H, P, O, S> = Transfer<<H as Handles<P, O, S>>::Place, <H as Handles<P, O, S>>::Value, <H as Handles<P, O, S>>::Text>;
216
217impl<P, O, S> Datum<P, O, S> {
218 pub fn map<H: Handles<P, O, S>>(self, h: &mut H) -> Mapped<H, P, O, S, DatumOf<H, P, O, S>> {
219 Ok(match self {
220 Self::Place(p) => Datum::Place(h.place(p)?),
221 Self::Value(o) => Datum::Value(h.value(o)?),
222 Self::Text(s) => Datum::Text(h.text(s)?),
223 Self::Bare => Datum::Bare,
224 })
225 }
226}
227
228fn opt<P, O, S, H: Handles<P, O, S>>(o: Opt<P, O, S>, h: &mut H) -> Mapped<H, P, O, S, OptOf<H, P, O, S>> {
229 o.map(|d| d.map(h)).transpose()
230}
231
232impl<P, O, S> CicsCommand<P, O, S> {
233 pub fn map<H: Handles<P, O, S>>(self, h: &mut H) -> Mapped<H, P, O, S, CommandOf<H, P, O, S>> {
235 let name = h.text(self.name)?;
236 let command = self.command.map(h)?;
237 let resp = Resp { resp: opt(self.resp.resp, h)?, resp2: opt(self.resp.resp2, h)?, nohandle: self.resp.nohandle };
238 Ok(CicsCommand { name, command, resp })
239 }
240}
241
242impl<P, O, S> Record<P, O, S> {
243 fn map<H: Handles<P, O, S>>(self, h: &mut H) -> Mapped<H, P, O, S, RecordOf<H, P, O, S>> {
244 Ok(Record { into: opt(self.into, h)?, set: opt(self.set, h)?, length: opt(self.length, h)? })
245 }
246}
247
248impl<P, O, S> Transfer<P, O, S> {
249 fn map<H: Handles<P, O, S>>(self, h: &mut H) -> Mapped<H, P, O, S, TransferOf<H, P, O, S>> {
250 Ok(Transfer { program: opt(self.program, h)?, commarea: opt(self.commarea, h)?, length: opt(self.length, h)? })
251 }
252}
253
254impl<P, O, S> Cics<P, O, S> {
255 fn map<H: Handles<P, O, S>>(self, h: &mut H) -> Mapped<H, P, O, S, CicsOf<H, P, O, S>> {
256 Ok(match self {
257 Self::File { verb, file, options: o } => Cics::File {
258 verb,
259 file: opt(file, h)?,
260 options: FileOptions {
261 ridfld: opt(o.ridfld, h)?,
262 keylength: opt(o.keylength, h)?,
263 reqid: opt(o.reqid, h)?,
264 from: opt(o.from, h)?,
265 numrec: opt(o.numrec, h)?,
266 record: o.record.map(h)?,
267 generic: o.generic,
268 rrn: o.rrn,
269 gteq: o.gteq,
270 equal: o.equal,
271 update: o.update,
272 },
273 },
274 Self::Return { transid, commarea, length } => Cics::Return { transid: opt(transid, h)?, commarea: opt(commarea, h)?, length: opt(length, h)? },
275 Self::Link(t) => Cics::Link(t.map(h)?),
276 Self::Xctl(t) => Cics::Xctl(t.map(h)?),
277 Self::Abend { abcode, cancel } => Cics::Abend { abcode: opt(abcode, h)?, cancel },
278 Self::HandleCondition(labels) => Cics::HandleCondition(labels),
279 Self::IgnoreCondition(conditions) => Cics::IgnoreCondition(conditions),
280 Self::PushHandle => Cics::PushHandle,
281 Self::PopHandle => Cics::PopHandle,
282 Self::HandleAbend { program, label, reset } => Cics::HandleAbend { program, label, reset },
283 Self::HandleAid => Cics::HandleAid,
284 Self::SendMap { map, mapset, from, maponly, dataonly, cursor, control } => {
285 Cics::SendMap { map: opt(map, h)?, mapset: opt(mapset, h)?, from: opt(from, h)?, maponly, dataonly, cursor: opt(cursor, h)?, control }
286 }
287 Self::ReceiveMap { map, mapset, into, set } => Cics::ReceiveMap { map: opt(map, h)?, mapset: opt(mapset, h)?, into: opt(into, h)?, set: opt(set, h)? },
288 Self::SendControl { cursor, control } => Cics::SendControl { cursor: opt(cursor, h)?, control },
289 Self::Receive(record) => Cics::Receive(record.map(h)?),
290 Self::Asktime { abstime } => Cics::Asktime { abstime: opt(abstime, h)? },
291 Self::Formattime { abstime, datesep, timesep, outputs } => {
292 let (abstime, datesep, timesep) = (opt(abstime, h)?, opt(datesep, h)?, opt(timesep, h)?);
293 let outputs = outputs.into_iter().map(|(name, d)| Ok((h.text(name)?, d.map(h)?))).collect::<Result<_, _>>()?;
294 Cics::Formattime { abstime, datesep, timesep, outputs }
295 }
296 Self::Assign(a) => Cics::Assign(Assign {
297 applid: opt(a.applid, h)?,
298 sysid: opt(a.sysid, h)?,
299 userid: opt(a.userid, h)?,
300 netname: opt(a.netname, h)?,
301 facility: opt(a.facility, h)?,
302 startcode: opt(a.startcode, h)?,
303 abcode: opt(a.abcode, h)?,
304 program: opt(a.program, h)?,
305 cwaleng: opt(a.cwaleng, h)?,
306 twaleng: opt(a.twaleng, h)?,
307 }),
308 Self::Getmain { flength, length, initimg, set } => Cics::Getmain { flength: opt(flength, h)?, length: opt(length, h)?, initimg: opt(initimg, h)?, set: opt(set, h)? },
309 Self::Freemain => Cics::Freemain,
310 Self::Enq => Cics::Enq,
311 Self::Deq => Cics::Deq,
312 Self::Delay => Cics::Delay,
313 Self::Syncpoint { rollback } => Cics::Syncpoint { rollback },
314 Self::Address { eib, commarea, cwa, twa } => Cics::Address { eib: opt(eib, h)?, commarea: opt(commarea, h)?, cwa: opt(cwa, h)?, twa: opt(twa, h)? },
315 Self::SendText { from, length } => Cics::SendText { from: opt(from, h)?, length: opt(length, h)? },
316 Self::WriteOperator { text, textlength } => Cics::WriteOperator { text: opt(text, h)?, textlength: opt(textlength, h)? },
317 Self::WriteqTs { queue, from, length, rewrite, item, numitems } => {
318 Cics::WriteqTs { queue: opt(queue, h)?, from: opt(from, h)?, length: opt(length, h)?, rewrite, item: opt(item, h)?, numitems: opt(numitems, h)? }
319 }
320 Self::ReadqTs { queue, next, item, numitems, record } => {
321 Cics::ReadqTs { queue: opt(queue, h)?, next, item: opt(item, h)?, numitems: opt(numitems, h)?, record: record.map(h)? }
322 }
323 Self::DeleteqTs { queue } => Cics::DeleteqTs { queue: opt(queue, h)? },
324 Self::WriteqTd { queue, from, length } => Cics::WriteqTd { queue: opt(queue, h)?, from: opt(from, h)?, length: opt(length, h)? },
325 Self::ReadqTd { queue, record } => Cics::ReadqTd { queue: opt(queue, h)?, record: record.map(h)? },
326 Self::DeleteqTd { queue } => Cics::DeleteqTd { queue: opt(queue, h)? },
327 Self::Unsupported => Cics::Unsupported,
328 })
329 }
330
331 pub fn labels(&self) -> Vec<ParaId> {
333 match self {
334 Self::HandleCondition(labels) => labels.iter().filter_map(|&(_, p)| p).collect(),
335 Self::HandleAbend { label, .. } => label.iter().copied().collect(),
336 _ => Vec::new(),
337 }
338 }
339}
340
341impl FileControl {
342 pub fn name(self) -> &'static str {
343 match self {
344 Self::Read => "READ",
345 Self::Write => "WRITE",
346 Self::Rewrite => "REWRITE",
347 Self::Delete => "DELETE",
348 Self::Unlock => "UNLOCK",
349 Self::Startbr => "STARTBR",
350 Self::Resetbr => "RESETBR",
351 Self::Readnext => "READNEXT",
352 Self::Readprev => "READPREV",
353 Self::Endbr => "ENDBR",
354 }
355 }
356}
357
358impl Encode for Condition {
360 fn encode(&self, w: &mut Writer) {
361 w.leb(*self as u64);
362 }
363}
364
365impl Decode for Condition {
366 fn decode(r: &mut Reader<'_>) -> Result<Self, ModuleError> {
367 let at = r.position();
368 let tag = r.leb()?;
369 usize::try_from(tag).ok().and_then(|i| Condition::ALL.get(i).copied()).ok_or_else(|| r.malformed(at, format!("Condition has no tag {tag}")))
370 }
371}
372
373codec_enum!(Datum { Place(place) = 0, Value(value) = 1, Text(text) = 2, Bare = 3 });
374codec_struct!(CicsCommand { name, command, resp });
375codec_struct!(Resp { resp, resp2, nohandle });
376codec_enum!(Cics {
377 File { verb, file, options } = 0,
378 Return { transid, commarea, length } = 1,
379 Link(transfer) = 2,
380 Xctl(transfer) = 3,
381 Abend { abcode, cancel } = 4,
382 HandleCondition(handlers) = 5,
383 IgnoreCondition(conditions) = 6,
384 PushHandle = 7,
385 PopHandle = 8,
386 HandleAbend { program, label, reset } = 9,
387 HandleAid = 10,
388 SendMap { map, mapset, from, maponly, dataonly, cursor, control } = 11,
389 ReceiveMap { map, mapset, into, set } = 12,
390 SendControl { cursor, control } = 13,
391 Receive(record) = 14,
392 Asktime { abstime } = 15,
393 Formattime { abstime, datesep, timesep, outputs } = 16,
394 Assign(assign) = 17,
395 Getmain { flength, length, initimg, set } = 18,
396 Freemain = 19,
397 Enq = 20,
398 Deq = 21,
399 Delay = 22,
400 Syncpoint { rollback } = 23,
401 Address { eib, commarea, cwa, twa } = 24,
402 SendText { from, length } = 25,
403 WriteOperator { text, textlength } = 26,
404 WriteqTs { queue, from, length, rewrite, item, numitems } = 27,
405 ReadqTs { queue, next, item, numitems, record } = 28,
406 DeleteqTs { queue } = 29,
407 WriteqTd { queue, from, length } = 30,
408 ReadqTd { queue, record } = 31,
409 DeleteqTd { queue } = 32,
410 Unsupported = 33,
411});
412codec_enum!(FileControl {
413 Read = 0,
414 Write = 1,
415 Rewrite = 2,
416 Delete = 3,
417 Unlock = 4,
418 Startbr = 5,
419 Resetbr = 6,
420 Readnext = 7,
421 Readprev = 8,
422 Endbr = 9,
423});
424codec_struct!(FileOptions { ridfld, keylength, reqid, from, numrec, record, generic, rrn, gteq, equal, update });
425codec_struct!(Record { into, set, length });
426codec_struct!(Transfer { program, commarea, length });
427codec_struct!(Control { erase, freekb, alarm, frset });
428codec_struct!(Assign { applid, sysid, userid, netname, facility, startcode, abcode, program, cwaleng, twaleng });