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, Count, DebugId, IntExpr, Operand, PlaceId, RefMod, StorePlan, SymId};
7use crate::vocab::Figurative;
8use crate::{codec_enum, codec_struct};
9use zarch::hfp::Precision;
10
11#[derive(Clone, Copy, Debug, PartialEq, Eq)]
12pub enum MovePlan {
13    Alnum { image: Image, justified: bool },
14    AlnumEdited { image: Image, edit: u32, positions: u32 },
15    National(NationalFrom),
16    Numeric { from: NumericFrom, store: StorePlan },
17    Float { from: FloatFrom, precision: Precision },
18    Address,
19    Index,
20    Refused(AbendId),
21}
22
23#[derive(Clone, Copy, Debug, PartialEq, Eq)]
24pub enum Image {
25    Bytes,
26    All,
27    Figurative,
28    Digits { digits: u32 },
29    /// A numeric, floating-point or pointer sender's own bytes as stored, once it has been read.
30    Stored,
31}
32
33#[derive(Clone, Copy, Debug, PartialEq, Eq)]
34pub enum NationalFrom {
35    Units,
36    Decoded,
37    Figurative,
38}
39
40#[derive(Clone, Copy, Debug, PartialEq, Eq)]
41pub enum NumericFrom {
42    Value,
43    /// NUMPROC(PFD), packed to packed of the same kind and scale: the bytes.
44    PackedCopy,
45    Float,
46    Zero,
47    /// A figurative other than ZERO, or an ALL literal: bytes filled, not converted.
48    Fill,
49    /// Alphanumeric bytes read as an unsigned zoned integer of their length.
50    Zoned,
51    DeEdit { edit: u32, digits: u32, scale: u32 },
52}
53
54#[derive(Clone, Copy, Debug, PartialEq, Eq)]
55pub enum FloatFrom {
56    Float,
57    Fixed,
58    Zero,
59}
60
61/// INITIALIZE of one item: each elementary item the walk reaches, every occurrence listed.
62#[derive(Clone, Debug, PartialEq, Eq)]
63pub struct InitPlan {
64    pub fields: Vec<InitField>,
65}
66
67/// SPACE, ZERO or NULL, as the walker gives the item's kind, moved into `len` bytes at `offset` from
68/// the target's start.
69#[derive(Clone, Copy, Debug, PartialEq, Eq)]
70pub struct InitField {
71    pub offset: u32,
72    pub len: u32,
73    pub value: Figurative,
74    pub store: MovePlan,
75}
76
77/// DISPLAY's items, each shown as the walker shows its kind, then a newline unless NO ADVANCING.
78#[derive(Clone, Debug, PartialEq, Eq)]
79pub struct DisplayPlan<P = PlaceId, O = Operand> {
80    pub items: Vec<DisplayItem<P, O>>,
81    pub no_advancing: bool,
82}
83
84#[derive(Clone, Copy, Debug, PartialEq, Eq)]
85pub enum DisplayItem<P = PlaceId, O = Operand> {
86    /// Groups, alphanumeric, zoned and edited items: the storage in the program's code page.
87    Bytes(P),
88    National(P),
89    /// Packed and binary items: the value's last `digits` digits, which for COMP-5 or TRUNC(BIN)
90    /// are as many as the item's halfword, fullword or doubleword holds.
91    Digits { place: P, digits: u32, signed: bool },
92    /// Floating-point, pointer, index and object-reference items: the place, then the abend.
93    Refused { place: P, abend: AbendId },
94    /// A literal or figurative constant as DISPLAY shows it; a numeric literal as written, its decimal
95    /// point the program's.
96    Text(SymId),
97    /// FUNCTION, LENGTH OF or ADDRESS OF, by the value's kind.
98    Value(O),
99}
100
101/// SEARCH ALL's binary search. The op returns Arm(0) on an occurrence whose keys equal their WHEN
102/// terms, for a Branch on the whole condition, and Arm(1) when the search ends without one.
103#[derive(Clone, Debug, PartialEq, Eq)]
104pub struct SearchAllPlan<P = PlaceId, V = Comparand, N = Count> {
105    /// The table's first index, stored by `store` at each occurrence tried.
106    pub index: P,
107    pub store: StorePlan,
108    pub count: N,
109    /// The keys the WHEN condition tests for equality, in the table's KEY order.
110    pub keys: Vec<SearchKey<V>>,
111}
112
113/// `key` as the WHEN term names it, and the `value` it must equal.
114#[derive(Clone, Copy, Debug, PartialEq, Eq)]
115pub struct SearchKey<V = Comparand> {
116    pub ascending: bool,
117    pub key: V,
118    pub value: V,
119    pub how: Compare,
120}
121
122/// FUNCTION, as the walker evaluates it: each argument in turn, as a comparison evaluates an
123/// operand or expression; then, when the values the arguments give number outside `func.arity()`,
124/// `arity`'s abend (lowering leaves `arity` None where they cannot); then the function, which for
125/// CHAR, INTEGER-OF-DATE, DATE-OF-INTEGER and RANDOM evaluates its first argument again as
126/// `integer`, and for NATIONAL-OF with two arguments its second; last, on an alphanumeric result,
127/// `refmod`'s start and length. `refmod.check` is always false: the walker checks a function's
128/// reference modification against its result whatever SSRANGE says.
129///
130/// HEX-OF, BIT-OF and BYTE-LENGTH read a `Load` argument's bytes as stored, and any other
131/// argument's value as DISPLAY would hold it. WHEN-COMPILED reads `ProgramOptions.when_compiled`.
132#[derive(Clone, Debug, PartialEq, Eq)]
133pub struct FunctionPlan {
134    pub func: Func,
135    pub args: Vec<Argument>,
136    pub integer: Option<IntExpr>,
137    /// TRIM's LEADING or TRAILING.
138    pub side: Option<TrimSide>,
139    pub refmod: Option<RefMod>,
140    pub arity: Option<AbendId>,
141    pub at: DebugId,
142}
143
144/// A FUNCTION argument: one value, or the elements of a table written with ALL subscripts.
145#[derive(Clone, Debug, PartialEq, Eq)]
146pub enum Argument {
147    Value(Comparand),
148    /// `element` is the table as written, each ALL subscript 1. Each `(position, count)` is an ALL
149    /// subscript's position among the place's subscripts and its occurrences. The counts are
150    /// evaluated first, left to right; then, unless one is zero, each element with its ALL
151    /// subscripts set, the rightmost varying fastest, is evaluated and read as `Load` reads it.
152    All { element: PlaceId, all: Vec<(u32, Count)> },
153}
154
155/// One row per intrinsic function: its variant, its tag in a load module, its name, and the
156/// fewest and most arguments it takes. Adding a function is adding its row.
157macro_rules! functions {
158    ($($variant:ident = $tag:literal, $name:literal, $min:literal ..= $max:expr;)*) => {
159        #[derive(Clone, Copy, Debug, PartialEq, Eq)]
160        pub enum Func {
161            $($variant,)*
162        }
163
164        impl Func {
165            pub const ALL: &'static [Func] = &[$(Func::$variant,)*];
166
167            pub fn name(self) -> &'static str {
168                match self {
169                    $(Func::$variant => $name,)*
170                }
171            }
172
173            pub fn named(name: &str) -> Option<Func> {
174                match name {
175                    $($name => Some(Func::$variant),)*
176                    _ => None,
177                }
178            }
179
180            /// The argument counts the function takes.
181            pub fn arity(self) -> ::core::ops::RangeInclusive<usize> {
182                match self {
183                    $(Func::$variant => $min..=$max,)*
184                }
185            }
186        }
187
188        codec_enum!(Func { $($variant = $tag,)* });
189    };
190}
191
192functions! {
193    Char = 0, "CHAR", 1..=1;
194    Ord = 1, "ORD", 1..=1;
195    NationalOf = 2, "NATIONAL-OF", 1..=2;
196    Length = 3, "LENGTH", 1..=1;
197    UpperCase = 4, "UPPER-CASE", 1..=1;
198    LowerCase = 5, "LOWER-CASE", 1..=1;
199    Reverse = 6, "REVERSE", 1..=1;
200    CurrentDate = 7, "CURRENT-DATE", 0..=0;
201    Numval = 8, "NUMVAL", 1..=2;
202    NumvalC = 9, "NUMVAL-C", 1..=2;
203    Trim = 10, "TRIM", 1..=1;
204    Mod = 11, "MOD", 2..=2;
205    Rem = 12, "REM", 2..=2;
206    Integer = 13, "INTEGER", 1..=1;
207    IntegerPart = 14, "INTEGER-PART", 1..=1;
208    Abs = 15, "ABS", 1..=1;
209    Min = 16, "MIN", 1..=usize::MAX;
210    Max = 17, "MAX", 1..=usize::MAX;
211    IntegerOfDate = 18, "INTEGER-OF-DATE", 1..=1;
212    DateOfInteger = 19, "DATE-OF-INTEGER", 1..=1;
213    Random = 20, "RANDOM", 0..=1;
214    Acos = 21, "ACOS", 1..=1;
215    Annuity = 22, "ANNUITY", 2..=2;
216    Asin = 23, "ASIN", 1..=1;
217    Atan = 24, "ATAN", 1..=1;
218    BitOf = 25, "BIT-OF", 1..=1;
219    BitToChar = 26, "BIT-TO-CHAR", 1..=1;
220    ByteLength = 27, "BYTE-LENGTH", 1..=1;
221    Cos = 28, "COS", 1..=1;
222    DateToYyyymmdd = 29, "DATE-TO-YYYYMMDD", 1..=2;
223    DayOfInteger = 30, "DAY-OF-INTEGER", 1..=1;
224    DayToYyyyddd = 31, "DAY-TO-YYYYDDD", 1..=2;
225    DisplayOf = 32, "DISPLAY-OF", 1..=2;
226    E = 33, "E", 0..=0;
227    Exp = 34, "EXP", 1..=1;
228    Exp10 = 35, "EXP10", 1..=1;
229    Factorial = 36, "FACTORIAL", 1..=1;
230    FormattedCurrentDate = 37, "FORMATTED-CURRENT-DATE", 1..=1;
231    FormattedDate = 38, "FORMATTED-DATE", 2..=2;
232    FormattedDatetime = 39, "FORMATTED-DATETIME", 3..=4;
233    FormattedTime = 40, "FORMATTED-TIME", 2..=3;
234    HexOf = 41, "HEX-OF", 1..=1;
235    HexToChar = 42, "HEX-TO-CHAR", 1..=1;
236    IntegerOfDay = 43, "INTEGER-OF-DAY", 1..=1;
237    IntegerOfFormattedDate = 44, "INTEGER-OF-FORMATTED-DATE", 2..=2;
238    Log = 45, "LOG", 1..=1;
239    Log10 = 46, "LOG10", 1..=1;
240    Mean = 47, "MEAN", 1..=usize::MAX;
241    Median = 48, "MEDIAN", 1..=usize::MAX;
242    Midrange = 49, "MIDRANGE", 1..=usize::MAX;
243    NumvalF = 50, "NUMVAL-F", 1..=1;
244    OrdMax = 51, "ORD-MAX", 1..=usize::MAX;
245    OrdMin = 52, "ORD-MIN", 1..=usize::MAX;
246    Pi = 53, "PI", 0..=0;
247    PresentValue = 54, "PRESENT-VALUE", 2..=usize::MAX;
248    Range = 55, "RANGE", 1..=usize::MAX;
249    SecondsFromFormattedTime = 56, "SECONDS-FROM-FORMATTED-TIME", 2..=2;
250    SecondsPastMidnight = 57, "SECONDS-PAST-MIDNIGHT", 0..=0;
251    Sign = 58, "SIGN", 1..=1;
252    Sin = 59, "SIN", 1..=1;
253    Sqrt = 60, "SQRT", 1..=1;
254    StandardDeviation = 61, "STANDARD-DEVIATION", 1..=usize::MAX;
255    Sum = 62, "SUM", 1..=usize::MAX;
256    Tan = 63, "TAN", 1..=1;
257    TestDateYyyymmdd = 64, "TEST-DATE-YYYYMMDD", 1..=1;
258    TestDayYyyyddd = 65, "TEST-DAY-YYYYDDD", 1..=1;
259    TestFormattedDatetime = 66, "TEST-FORMATTED-DATETIME", 2..=2;
260    TestNumval = 67, "TEST-NUMVAL", 1..=1;
261    TestNumvalC = 68, "TEST-NUMVAL-C", 1..=2;
262    TestNumvalF = 69, "TEST-NUMVAL-F", 1..=1;
263    Uuid4 = 70, "UUID4", 0..=0;
264    Variance = 71, "VARIANCE", 1..=usize::MAX;
265    YearToYyyy = 72, "YEAR-TO-YYYY", 1..=2;
266    WhenCompiled = 73, "WHEN-COMPILED", 0..=0;
267    Ulength = 74, "ULENGTH", 1..=1;
268    Upos = 75, "UPOS", 2..=2;
269    Usubstr = 76, "USUBSTR", 3..=3;
270    Usupplementary = 77, "USUPPLEMENTARY", 1..=1;
271    Uvalid = 78, "UVALID", 1..=1;
272    Uwidth = 79, "UWIDTH", 2..=2;
273    CombinedDatetime = 80, "COMBINED-DATETIME", 2..=2;
274    ContentOf = 81, "CONTENT-OF", 1..=1;
275}
276
277#[derive(Clone, Copy, Debug, PartialEq, Eq)]
278pub enum TrimSide {
279    Leading,
280    Trailing,
281}
282
283/// `args` and `returning` carry each Java type signature. The op evaluates the method name, then the
284/// receiver, then each argument, and returns Arm(1) when no method matches and ON EXCEPTION is
285/// written, Arm(0) otherwise, or Next when neither phrase is written. `returning` is moved by the
286/// kind of the value the method returns.
287#[derive(Clone, Debug, PartialEq, Eq)]
288pub struct InvokePlan<P = PlaceId, O = Operand, S = SymId> {
289    pub receiver: Receiver<P, S>,
290    pub method: MethodName<P, S>,
291    pub args: Vec<(O, S)>,
292    pub returning: Option<(P, S)>,
293    pub on_exception: bool,
294    pub not_on_exception: bool,
295}
296
297/// `Class` is a REPOSITORY class-name: `name` as written, which messages give, and `external`, which
298/// finds the class.
299#[derive(Clone, Copy, Debug, PartialEq, Eq)]
300pub enum Receiver<P = PlaceId, S = SymId> {
301    SelfRef,
302    Super,
303    Class { name: S, external: S },
304    Object(P),
305}
306
307#[derive(Clone, Copy, Debug, PartialEq, Eq)]
308pub enum MethodName<P = PlaceId, S = SymId> {
309    New,
310    Named(S),
311    Dynamic(P),
312}
313
314codec_enum!(MovePlan {
315    Alnum { image, justified } = 0,
316    AlnumEdited { image, edit, positions } = 1,
317    National(from) = 2,
318    Numeric { from, store } = 3,
319    Float { from, precision } = 4,
320    Address = 5,
321    Index = 6,
322    Refused(abend) = 7,
323});
324codec_enum!(Image { Bytes = 0, All = 1, Figurative = 2, Digits { digits } = 3, Stored = 4 });
325codec_enum!(NationalFrom { Units = 0, Decoded = 1, Figurative = 2 });
326codec_enum!(NumericFrom {
327    Value = 0,
328    PackedCopy = 1,
329    Float = 2,
330    Zero = 3,
331    Fill = 4,
332    Zoned = 5,
333    DeEdit { edit, digits, scale } = 6,
334});
335codec_enum!(FloatFrom { Float = 0, Fixed = 1, Zero = 2 });
336codec_struct!(InitPlan { fields });
337codec_struct!(InitField { offset, len, value, store });
338codec_struct!(DisplayPlan { items, no_advancing });
339codec_enum!(DisplayItem {
340    Bytes(place) = 0,
341    National(place) = 1,
342    Digits { place, digits, signed } = 2,
343    Refused { place, abend } = 3,
344    Text(text) = 4,
345    Value(value) = 5,
346});
347codec_struct!(SearchAllPlan { index, store, count, keys });
348codec_struct!(SearchKey { ascending, key, value, how });
349codec_struct!(FunctionPlan { func, args, integer, side, refmod, arity, at });
350codec_enum!(Argument { Value(value) = 0, All { element, all } = 1 });
351codec_enum!(TrimSide { Leading = 0, Trailing = 1 });
352codec_struct!(InvokePlan { receiver, method, args, returning, on_exception, not_on_exception });
353codec_enum!(Receiver { SelfRef = 0, Super = 1, Class { name, external } = 2, Object(place) = 3 });
354codec_enum!(MethodName { New = 0, Named(name) = 1, Dynamic(place) = 2 });