Skip to main content

ironwork_rt/lir/
payload.rs

1//! Statement payloads from lir.md §9: MOVE, INITIALIZE, DISPLAY, SEARCH ALL, FUNCTION and INVOKE.
2//! DISPLAY's, SEARCH ALL's, INVOKE's and those of `text`, `call` and `sql` are generic over the
3//! handles they name (semantics-library.md §9, C6): the LIR's ids by default, the walker's own
4//! references in the interpreter.
5
6use super::{AbendId, Comparand, Compare, ConstId, Count, DebugId, IntExpr, Operand, PlaceId, RefMod, StorePlan, SymId};
7use crate::store::LaxRedefinition;
8use crate::vocab::Figurative;
9use crate::{codec_enum, codec_struct};
10use zarch::hfp::Precision;
11
12#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13pub enum MovePlan {
14    Alnum { image: Image, justified: bool },
15    AlnumEdited { image: Image, edit: u32, positions: u32 },
16    National(NationalFrom),
17    Numeric { from: NumericFrom, store: StorePlan },
18    Float { from: FloatFrom, precision: Precision },
19    Address,
20    Index,
21    Refused(AbendId),
22    /// DBCS data or SPACE into a DBCS item, `edit` its PICTURE when it has B.
23    Dbcs { justified: bool, edit: Option<u32> },
24}
25
26#[derive(Clone, Copy, Debug, PartialEq, Eq)]
27pub enum Image {
28    Bytes,
29    All,
30    Figurative,
31    Digits { digits: u32 },
32    /// A numeric, floating-point or pointer sender's own bytes as stored, once it has been read.
33    Stored,
34}
35
36#[derive(Clone, Copy, Debug, PartialEq, Eq)]
37pub enum NationalFrom {
38    Units,
39    Decoded,
40    Figurative,
41    /// DBCS characters through the code page's DBCS component.
42    Dbcs,
43}
44
45#[derive(Clone, Copy, Debug, PartialEq, Eq)]
46pub enum NumericFrom {
47    /// The sender as a number; a zoned or packed sender through `store::move_sender`, which gives
48    /// digits that are not decimal as bytes to carry unchecked (C260).
49    Value,
50    /// NUMPROC(PFD), packed to packed of the same kind and scale: the bytes.
51    PackedCopy,
52    Float,
53    Zero,
54    /// A figurative other than ZERO, or an ALL literal: bytes filled, not converted.
55    Fill,
56    /// Alphanumeric bytes read as an unsigned zoned integer of their length; to a zoned or packed
57    /// integer without P scaling, the low halves of their last bytes, stored unchecked (C240).
58    Zoned,
59    DeEdit { edit: u32, digits: u32, scale: u32 },
60}
61
62#[derive(Clone, Copy, Debug, PartialEq, Eq)]
63pub enum FloatFrom {
64    Float,
65    Fixed,
66    Zero,
67}
68
69/// NUMCHECK's test of a MOVE's sending item, once the item is located and before it is read
70/// (`rt::store::numcheck_sender`).
71#[derive(Clone, Copy, Debug, PartialEq, Eq)]
72pub enum SenderCheck {
73    /// No test: no NUMCHECK, a sender that is not a data item, or a zoned sender ZON(LAX) exempts.
74    None,
75    /// The test `Operand::Load` makes of its item.
76    Item,
77    /// An alphanumeric or group sender moved to a numeric receiver: an unsigned integer's digits.
78    Integer,
79}
80
81/// NUMCHECK's facts of a reference, fixed when compiled (`compile::numcheck`): under ZON(LAX), what
82/// its item may hold because of the item its record redefines; and whether the compiler removed
83/// the test where this reference reads the item, having found it always fails.
84#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
85pub struct PlaceNumcheck {
86    pub lax: Option<LaxRedefinition>,
87    pub removed: bool,
88}
89
90/// INITIALIZE of one item: each elementary item the walk reaches, every occurrence listed, with
91/// FILLER and its phrases' choice of receivers and senders made. A reference-modified item is one
92/// field, which is the item as located.
93#[derive(Clone, Debug, PartialEq, Eq)]
94pub struct InitPlan {
95    pub fields: Vec<InitField>,
96}
97
98/// `value` moved into `len` bytes at `offset` from the target's start, by `store`, which was made
99/// for the kind the walker stores as; `scaling` is the item's PICTURE P positions.
100#[derive(Clone, Copy, Debug, PartialEq, Eq)]
101pub struct InitField {
102    pub offset: u32,
103    pub len: u32,
104    pub value: InitValue,
105    pub store: MovePlan,
106    pub scaling: u32,
107}
108
109/// What an INITIALIZE field is sent.
110#[derive(Clone, Copy, Debug, PartialEq, Eq)]
111pub enum InitValue {
112    /// SPACE, ZERO or NULL, as the walker gives the item's kind.
113    Default(Figurative),
114    /// The literal of the item's own VALUE clause.
115    Value(ConstId),
116    /// REPLACING's operand, read for each field it is sent to.
117    Replacing(Operand),
118}
119
120/// DISPLAY's items, each shown as the walker shows its kind, then a newline unless NO ADVANCING.
121#[derive(Clone, Debug, PartialEq, Eq)]
122pub struct DisplayPlan<P = PlaceId, O = Operand> {
123    pub items: Vec<DisplayItem<P, O>>,
124    pub no_advancing: bool,
125}
126
127/// Micro Focus's and GnuCOBOL's screen phrases on a DISPLAY or ACCEPT under `--compliance
128/// extended`: where on the screen, what is cleared before writing, and how an ACCEPT's field
129/// behaves.
130#[derive(Clone, Debug, PartialEq, Eq)]
131pub struct ScreenPlan {
132    pub at: ScreenPosition,
133    pub blank_screen: bool,
134    pub blank_line: bool,
135    pub erase_eol: bool,
136    pub erase_eos: bool,
137    pub update: bool,
138    pub secure: bool,
139}
140
141/// A field of a screen ACCEPT: the item it shows, the item the operator's entry goes to, and
142/// where it is.
143#[derive(Clone, Debug, PartialEq, Eq)]
144pub struct ScreenInput {
145    pub target: PlaceId,
146    pub field: PlaceId,
147    pub at: ScreenPosition,
148    pub update: bool,
149    pub secure: bool,
150}
151
152#[derive(Clone, Debug, PartialEq, Eq)]
153pub enum ScreenPosition {
154    Cursor,
155    /// AT's number: LLCC, or LLLCCC past 9999.
156    Combined(IntExpr),
157    /// LINE and COLUMN; column 1 without COLUMN, the cursor's line without LINE.
158    LineColumn { line: Option<IntExpr>, column: Option<IntExpr> },
159}
160
161#[derive(Clone, Copy, Debug, PartialEq, Eq)]
162pub enum DisplayItem<P = PlaceId, O = Operand> {
163    /// Groups, alphanumeric, zoned and edited items, and national items written elsewhere than the
164    /// console: the storage in the program's code page. A COMP-1 or COMP-2 item: its value in
165    /// external floating point (`display::float`).
166    Bytes(P),
167    /// A national item UPON CONSOLE: converted to the program's code page.
168    National(P),
169    /// Packed and binary items: the value's last `digits` digits, which for COMP-5 or TRUNC(BIN)
170    /// are as many as the item's halfword, fullword or doubleword holds.
171    Digits { place: P, digits: u32, signed: bool },
172    /// Pointer, index and object-reference items: the place, then the abend.
173    Refused { place: P, abend: AbendId },
174    /// A literal or figurative constant as DISPLAY shows it; a numeric literal as written, its decimal
175    /// point the program's.
176    Text(SymId),
177    /// FUNCTION, LENGTH OF or ADDRESS OF, by the value's kind, a national value unconverted; UPON
178    /// CONSOLE a national function's value is DISPLAY-OF's.
179    Value(O),
180}
181
182/// SEARCH ALL's binary search. The op returns Arm(0) on an occurrence whose keys equal their WHEN
183/// terms, for a Branch on the whole condition, and Arm(1) when the search ends without one.
184#[derive(Clone, Debug, PartialEq, Eq)]
185pub struct SearchAllPlan<P = PlaceId, V = Comparand, N = Count> {
186    /// The table's first index, stored by `store` at each occurrence tried.
187    pub index: P,
188    pub store: StorePlan,
189    pub count: N,
190    /// The keys the WHEN condition tests for equality, in the table's KEY order.
191    pub keys: Vec<SearchKey<V>>,
192}
193
194/// `key` as the WHEN term names it, and the `value` it must equal.
195#[derive(Clone, Copy, Debug, PartialEq, Eq)]
196pub struct SearchKey<V = Comparand> {
197    pub ascending: bool,
198    pub key: V,
199    pub value: V,
200    pub how: Compare,
201}
202
203/// FUNCTION, as the walker evaluates it: each argument in turn, as a comparison evaluates an
204/// operand or expression; then, when the values the arguments give number outside `func.arity()`,
205/// `arity`'s abend (lowering leaves `arity` None where they cannot); then the function, which for
206/// CHAR, INTEGER-OF-DATE, DATE-OF-INTEGER and RANDOM evaluates its first argument again as
207/// `integer`, and for NATIONAL-OF with two arguments its second; last, on an alphanumeric result,
208/// `refmod`'s start and length. `refmod.check` is always false: the walker checks a function's
209/// reference modification against its result whatever SSRANGE says.
210///
211/// HEX-OF, BIT-OF and BYTE-LENGTH read a `Load` argument's bytes as stored, and any other
212/// argument's value as DISPLAY would hold it. WHEN-COMPILED reads `ProgramOptions.when_compiled`.
213#[derive(Clone, Debug, PartialEq, Eq)]
214pub struct FunctionPlan {
215    pub func: Func,
216    pub args: Vec<Argument>,
217    pub integer: Option<IntExpr>,
218    /// TRIM's LEADING or TRAILING.
219    pub side: Option<TrimSide>,
220    pub refmod: Option<RefMod>,
221    pub arity: Option<AbendId>,
222    pub at: DebugId,
223}
224
225/// A FUNCTION argument: one value, or the elements of a table written with ALL subscripts.
226#[derive(Clone, Debug, PartialEq, Eq)]
227pub enum Argument {
228    Value(Comparand),
229    /// `element` is the table as written, each ALL subscript 1. Each `(position, count)` is an ALL
230    /// subscript's position among the place's subscripts and its occurrences. The counts are
231    /// evaluated first, left to right; then, unless one is zero, each element with its ALL
232    /// subscripts set, the rightmost varying fastest, is evaluated and read as `Load` reads it.
233    All { element: PlaceId, all: Vec<(u32, Count)> },
234}
235
236/// One row per intrinsic function: its variant, its tag in a load module, its name, and the
237/// fewest and most arguments it takes. Adding a function is adding its row.
238macro_rules! functions {
239    ($($variant:ident = $tag:literal, $name:literal, $min:literal ..= $max:expr;)*) => {
240        #[derive(Clone, Copy, Debug, PartialEq, Eq)]
241        pub enum Func {
242            $($variant,)*
243        }
244
245        impl Func {
246            pub const ALL: &'static [Func] = &[$(Func::$variant,)*];
247
248            pub fn name(self) -> &'static str {
249                match self {
250                    $(Func::$variant => $name,)*
251                }
252            }
253
254            pub fn named(name: &str) -> Option<Func> {
255                match name {
256                    $($name => Some(Func::$variant),)*
257                    _ => None,
258                }
259            }
260
261            /// The argument counts the function takes.
262            pub fn arity(self) -> ::core::ops::RangeInclusive<usize> {
263                match self {
264                    $(Func::$variant => $min..=$max,)*
265                }
266            }
267        }
268
269        codec_enum!(Func { $($variant = $tag,)* });
270    };
271}
272
273functions! {
274    Char = 0, "CHAR", 1..=1;
275    Ord = 1, "ORD", 1..=1;
276    NationalOf = 2, "NATIONAL-OF", 1..=2;
277    Length = 3, "LENGTH", 1..=1;
278    UpperCase = 4, "UPPER-CASE", 1..=1;
279    LowerCase = 5, "LOWER-CASE", 1..=1;
280    Reverse = 6, "REVERSE", 1..=1;
281    CurrentDate = 7, "CURRENT-DATE", 0..=0;
282    Numval = 8, "NUMVAL", 1..=2;
283    NumvalC = 9, "NUMVAL-C", 1..=2;
284    Trim = 10, "TRIM", 1..=1;
285    Mod = 11, "MOD", 2..=2;
286    Rem = 12, "REM", 2..=2;
287    Integer = 13, "INTEGER", 1..=1;
288    IntegerPart = 14, "INTEGER-PART", 1..=1;
289    Abs = 15, "ABS", 1..=1;
290    Min = 16, "MIN", 1..=usize::MAX;
291    Max = 17, "MAX", 1..=usize::MAX;
292    IntegerOfDate = 18, "INTEGER-OF-DATE", 1..=1;
293    DateOfInteger = 19, "DATE-OF-INTEGER", 1..=1;
294    Random = 20, "RANDOM", 0..=1;
295    Acos = 21, "ACOS", 1..=1;
296    Annuity = 22, "ANNUITY", 2..=2;
297    Asin = 23, "ASIN", 1..=1;
298    Atan = 24, "ATAN", 1..=1;
299    BitOf = 25, "BIT-OF", 1..=1;
300    BitToChar = 26, "BIT-TO-CHAR", 1..=1;
301    ByteLength = 27, "BYTE-LENGTH", 1..=1;
302    Cos = 28, "COS", 1..=1;
303    DateToYyyymmdd = 29, "DATE-TO-YYYYMMDD", 1..=2;
304    DayOfInteger = 30, "DAY-OF-INTEGER", 1..=1;
305    DayToYyyyddd = 31, "DAY-TO-YYYYDDD", 1..=2;
306    DisplayOf = 32, "DISPLAY-OF", 1..=2;
307    E = 33, "E", 0..=0;
308    Exp = 34, "EXP", 1..=1;
309    Exp10 = 35, "EXP10", 1..=1;
310    Factorial = 36, "FACTORIAL", 1..=1;
311    FormattedCurrentDate = 37, "FORMATTED-CURRENT-DATE", 1..=1;
312    FormattedDate = 38, "FORMATTED-DATE", 2..=2;
313    FormattedDatetime = 39, "FORMATTED-DATETIME", 3..=4;
314    FormattedTime = 40, "FORMATTED-TIME", 2..=3;
315    HexOf = 41, "HEX-OF", 1..=1;
316    HexToChar = 42, "HEX-TO-CHAR", 1..=1;
317    IntegerOfDay = 43, "INTEGER-OF-DAY", 1..=1;
318    IntegerOfFormattedDate = 44, "INTEGER-OF-FORMATTED-DATE", 2..=2;
319    Log = 45, "LOG", 1..=1;
320    Log10 = 46, "LOG10", 1..=1;
321    Mean = 47, "MEAN", 1..=usize::MAX;
322    Median = 48, "MEDIAN", 1..=usize::MAX;
323    Midrange = 49, "MIDRANGE", 1..=usize::MAX;
324    NumvalF = 50, "NUMVAL-F", 1..=1;
325    OrdMax = 51, "ORD-MAX", 1..=usize::MAX;
326    OrdMin = 52, "ORD-MIN", 1..=usize::MAX;
327    Pi = 53, "PI", 0..=0;
328    PresentValue = 54, "PRESENT-VALUE", 2..=usize::MAX;
329    Range = 55, "RANGE", 1..=usize::MAX;
330    SecondsFromFormattedTime = 56, "SECONDS-FROM-FORMATTED-TIME", 2..=2;
331    SecondsPastMidnight = 57, "SECONDS-PAST-MIDNIGHT", 0..=0;
332    Sign = 58, "SIGN", 1..=1;
333    Sin = 59, "SIN", 1..=1;
334    Sqrt = 60, "SQRT", 1..=1;
335    StandardDeviation = 61, "STANDARD-DEVIATION", 1..=usize::MAX;
336    Sum = 62, "SUM", 1..=usize::MAX;
337    Tan = 63, "TAN", 1..=1;
338    TestDateYyyymmdd = 64, "TEST-DATE-YYYYMMDD", 1..=1;
339    TestDayYyyyddd = 65, "TEST-DAY-YYYYDDD", 1..=1;
340    TestFormattedDatetime = 66, "TEST-FORMATTED-DATETIME", 2..=2;
341    TestNumval = 67, "TEST-NUMVAL", 1..=1;
342    TestNumvalC = 68, "TEST-NUMVAL-C", 1..=2;
343    TestNumvalF = 69, "TEST-NUMVAL-F", 1..=1;
344    Uuid4 = 70, "UUID4", 0..=0;
345    Variance = 71, "VARIANCE", 1..=usize::MAX;
346    YearToYyyy = 72, "YEAR-TO-YYYY", 1..=2;
347    WhenCompiled = 73, "WHEN-COMPILED", 0..=0;
348    Ulength = 74, "ULENGTH", 1..=1;
349    Upos = 75, "UPOS", 2..=2;
350    Usubstr = 76, "USUBSTR", 3..=3;
351    Usupplementary = 77, "USUPPLEMENTARY", 1..=1;
352    Uvalid = 78, "UVALID", 1..=1;
353    Uwidth = 79, "UWIDTH", 2..=2;
354    CombinedDatetime = 80, "COMBINED-DATETIME", 2..=2;
355    ContentOf = 81, "CONTENT-OF", 1..=1;
356    ModuleCallerId = 82, "MODULE-CALLER-ID", 0..=0;
357    ArgumentLength = 83, "ARGUMENT LENGTH", 1..=1;
358    StoredCharLength = 84, "STORED-CHAR-LENGTH", 1..=1;
359    HeapAllocate = 85, "HEAP ALLOCATE", 1..=1;
360    HeapFree = 86, "HEAP FREE", 1..=1;
361    Concatenate = 87, "CONCATENATE", 1..=usize::MAX;
362    ChainingArgument = 88, "CHAINING ARGUMENT", 2..=2;
363    CrtStatus = 89, "CRT STATUS", 0..=0;
364}
365
366#[derive(Clone, Copy, Debug, PartialEq, Eq)]
367pub enum TrimSide {
368    Leading,
369    Trailing,
370}
371
372/// `args` and `returning` carry each Java type signature. The op evaluates the method name, then the
373/// receiver, then each argument, and returns Arm(1) when no method matches and ON EXCEPTION is
374/// written, Arm(0) otherwise, or Next when neither phrase is written. `returning` is moved by the
375/// kind of the value the method returns.
376#[derive(Clone, Debug, PartialEq, Eq)]
377pub struct InvokePlan<P = PlaceId, O = Operand, S = SymId> {
378    pub receiver: Receiver<P, S>,
379    pub method: MethodName<P, S>,
380    pub args: Vec<(O, S)>,
381    pub returning: Option<(P, S)>,
382    pub on_exception: bool,
383    pub not_on_exception: bool,
384}
385
386/// `Class` is a REPOSITORY class-name: `name` as written, which messages give, and `external`, which
387/// finds the class.
388#[derive(Clone, Copy, Debug, PartialEq, Eq)]
389pub enum Receiver<P = PlaceId, S = SymId> {
390    SelfRef,
391    Super,
392    Class { name: S, external: S },
393    Object(P),
394}
395
396#[derive(Clone, Copy, Debug, PartialEq, Eq)]
397pub enum MethodName<P = PlaceId, S = SymId> {
398    New,
399    Named(S),
400    Dynamic(P),
401}
402
403codec_enum!(MovePlan {
404    Alnum { image, justified } = 0,
405    AlnumEdited { image, edit, positions } = 1,
406    National(from) = 2,
407    Numeric { from, store } = 3,
408    Float { from, precision } = 4,
409    Address = 5,
410    Index = 6,
411    Refused(abend) = 7,
412    Dbcs { justified, edit } = 8,
413});
414codec_enum!(Image { Bytes = 0, All = 1, Figurative = 2, Digits { digits } = 3, Stored = 4 });
415codec_enum!(NationalFrom { Units = 0, Decoded = 1, Figurative = 2, Dbcs = 3 });
416codec_enum!(NumericFrom {
417    Value = 0,
418    PackedCopy = 1,
419    Float = 2,
420    Zero = 3,
421    Fill = 4,
422    Zoned = 5,
423    DeEdit { edit, digits, scale } = 6,
424});
425codec_enum!(FloatFrom { Float = 0, Fixed = 1, Zero = 2 });
426codec_enum!(SenderCheck { None = 0, Item = 1, Integer = 2 });
427codec_struct!(PlaceNumcheck { lax, removed });
428codec_enum!(LaxRedefinition { Signed = 0, LeadingSpaces(spaces) = 1 });
429codec_struct!(InitPlan { fields });
430codec_struct!(InitField { offset, len, value, store, scaling });
431codec_enum!(InitValue { Default(value) = 0, Value(value) = 1, Replacing(value) = 2 });
432codec_struct!(DisplayPlan { items, no_advancing });
433codec_struct!(ScreenPlan { at, blank_screen, blank_line, erase_eol, erase_eos, update, secure });
434codec_struct!(ScreenInput { target, field, at, update, secure });
435codec_enum!(ScreenPosition { Cursor = 0, Combined(at) = 1, LineColumn { line, column } = 2 });
436codec_enum!(DisplayItem {
437    Bytes(place) = 0,
438    National(place) = 1,
439    Digits { place, digits, signed } = 2,
440    Refused { place, abend } = 3,
441    Text(text) = 4,
442    Value(value) = 5,
443});
444codec_struct!(SearchAllPlan { index, store, count, keys });
445codec_struct!(SearchKey { ascending, key, value, how });
446codec_struct!(FunctionPlan { func, args, integer, side, refmod, arity, at });
447codec_enum!(Argument { Value(value) = 0, All { element, all } = 1 });
448codec_enum!(TrimSide { Leading = 0, Trailing = 1 });
449codec_struct!(InvokePlan { receiver, method, args, returning, on_exception, not_on_exception });
450codec_enum!(Receiver { SelfRef = 0, Super = 1, Class { name, external } = 2, Object(place) = 3 });
451codec_enum!(MethodName { New = 0, Named(name) = 1, Dynamic(place) = 2 });