Skip to main content

ironwork_numeric/
assumptions.rs

1#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2pub enum Oracle {
3    /// A bare-metal instruction run under Hercules settles it.
4    Hercules,
5    /// Only a program compiled by Enterprise COBOL, on the pinned target, settles it.
6    EnterpriseCobol,
7}
8
9#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10pub enum Basis {
11    /// Stated in IBM's documentation and checked against its text.
12    Documented,
13    /// Stated in IBM's documentation, but written here from memory of it: check against the manual.
14    Recalled,
15    /// Not stated anywhere; the documentation leaves it to the generated code.
16    Chosen,
17}
18
19#[derive(Clone, Copy, Debug)]
20pub struct Assumption {
21    pub id: &'static str,
22    pub claim: &'static str,
23    pub basis: Basis,
24    pub oracle: Oracle,
25}
26
27pub const HFP_EXTENDED_LOW_HALF: &str = "M1";
28pub const HFP_FROM_FIXED_TRUNCATES: &str = "M2";
29pub const INTERMEDIATE_TABLE: &str = "C1";
30pub const TRUNC_OPT_IS_BINARY: &str = "C2";
31pub const PFD_MOVES_BYTES: &str = "C3";
32pub const PFD_COMPARES_LOGICALLY: &str = "C4";
33pub const FLOAT_FROM_DECIMAL: &str = "C5";
34pub const FLOAT_TO_DECIMAL: &str = "C6";
35pub const FLOAT_NARROWING_TRUNCATES: &str = "C7";
36pub const LE_MASKS_UNDERFLOW: &str = "C8";
37pub const PREFERRED_RESULT_SIGNS: &str = "C9";
38pub const ZONED_BY_PACK: &str = "C10";
39pub const CCSID_TABLES: &str = "C11";
40pub const WORKING_STORAGE_LAYOUT: &str = "C12";
41pub const NOPFD_REPAIRS_UNSIGNED_INPUT: &str = "C13";
42pub const DISPLAY_OF_NONDISPLAY_NUMERIC: &str = "C14";
43pub const ACCEPT_AT_END: &str = "C15";
44pub const CONTENT_LITERAL_ZONED: &str = "C16";
45pub const KEYED_FILE_STATUS: &str = "C17";
46pub const ALTERNATE_KEY_ORDER: &str = "C18";
47pub const FAILED_READ_LOSES_POSITION: &str = "C19";
48pub const START_COMPARES_SHORTER: &str = "C20";
49pub const REWRITE_SHARED_ALTERNATE: &str = "C21";
50pub const CICS_FRESH_STORAGE: &str = "C22";
51pub const CICS_CALEN_RESTORED: &str = "C23";
52pub const CICS_HANDLE_ABEND_CATCHES_CONDITIONS: &str = "C24";
53pub const CICS_LENGTH_DEFAULTS_TO_INTO: &str = "C25";
54pub const CICS_PROGRAM_CHECK_IS_ASRA: &str = "C26";
55pub const CICS_BROWSE_SKIP: &str = "C27";
56pub const BMS_RECEIVE_NULLS: &str = "C28";
57pub const BMS_INPUT_JUSTIFY: &str = "C29";
58pub const BMS_EXTENDED_ORDER: &str = "C30";
59pub const BMS_CONSTANTS_UNVERIFIED: &str = "C31";
60pub const BMS_SEND_DATA_CHOICE: &str = "C32";
61pub const CICS_INITIAL_AID: &str = "C33";
62
63pub const ASSUMPTIONS: &[Assumption] = &[
64    Assumption {
65        id: HFP_EXTENDED_LOW_HALF,
66        claim: "An extended HFP result's low half carries the high characteristic minus 14, modulo 128, and is all zero when the value is all zero bits (SA22-7832-14, HFP extended format, p. 18-4)",
67        basis: Basis::Documented,
68        oracle: Oracle::Hercules,
69    },
70    Assumption {
71        id: HFP_FROM_FIXED_TRUNCATES,
72        claim: "CONVERT FROM FIXED to HFP truncates the hexadecimal digits the precision cannot hold",
73        basis: Basis::Recalled,
74        oracle: Oracle::Hercules,
75    },
76    Assumption {
77        id: INTERMEDIATE_TABLE,
78        claim: "Intermediate results carry i and d places up to 30 digits (31 under ARITH(EXTEND)); beyond that, N-d and d when d <= dmax, else i and N-i when i+dmax <= N, else N-dmax and dmax; digits beyond are truncated",
79        basis: Basis::Recalled,
80        oracle: Oracle::EnterpriseCobol,
81    },
82    Assumption {
83        id: TRUNC_OPT_IS_BINARY,
84        claim: "Under TRUNC(OPT) a binary receiver whose value exceeds its PICTURE is truncated at the halfword, fullword or doubleword, as under TRUNC(BIN)",
85        basis: Basis::Chosen,
86        oracle: Oracle::EnterpriseCobol,
87    },
88    Assumption {
89        id: PFD_MOVES_BYTES,
90        claim: "Under NUMPROC(PFD) a MOVE between packed items of the same length and scale copies the bytes, so a non-preferred sign passes through; under NOPFD the receiver gets the preferred sign",
91        basis: Basis::Chosen,
92        oracle: Oracle::EnterpriseCobol,
93    },
94    Assumption {
95        id: PFD_COMPARES_LOGICALLY,
96        claim: "Under NUMPROC(PFD) two packed items of the same length and scale compare byte by byte, so X'1F' and X'1C' differ",
97        basis: Basis::Chosen,
98        oracle: Oracle::EnterpriseCobol,
99    },
100    Assumption {
101        id: FLOAT_FROM_DECIMAL,
102        claim: "A fixed-point decimal m with s decimal places becomes HFP as CONVERT FROM FIXED of m, then an HFP divide by 10^s",
103        basis: Basis::Chosen,
104        oracle: Oracle::EnterpriseCobol,
105    },
106    Assumption {
107        id: FLOAT_TO_DECIMAL,
108        claim: "An HFP value moved to a fixed-point receiver is its exact value truncated at the receiver's scale, or rounded half away from zero under ROUNDED",
109        basis: Basis::Chosen,
110        oracle: Oracle::EnterpriseCobol,
111    },
112    Assumption {
113        id: FLOAT_NARROWING_TRUNCATES,
114        claim: "A floating-point intermediate stored into a narrower COMP-1 or COMP-2 keeps its high-order part (truncation), not LOAD ROUNDED",
115        basis: Basis::Chosen,
116        oracle: Oracle::EnterpriseCobol,
117    },
118    Assumption {
119        id: LE_MASKS_UNDERFLOW,
120        claim: "Language Environment runs COBOL with the HFP exponent-underflow and significance masks off, so both yield a true zero",
121        basis: Basis::Chosen,
122        oracle: Oracle::EnterpriseCobol,
123    },
124    Assumption {
125        id: PREFERRED_RESULT_SIGNS,
126        claim: "Arithmetic results take the preferred sign under either NUMPROC setting: C or D for a signed item, F for an unsigned one",
127        basis: Basis::Recalled,
128        oracle: Oracle::EnterpriseCobol,
129    },
130    Assumption {
131        id: ZONED_BY_PACK,
132        claim: "A zoned operand enters arithmetic as PACK leaves it: zones other than the sign's are discarded, so an embedded space is a zero digit",
133        basis: Basis::Chosen,
134        oracle: Oracle::EnterpriseCobol,
135    },
136    Assumption {
137        id: CCSID_TABLES,
138        claim: "The compiler's conversion to UTF-16 for each carried CCSID is ICU's ibm-* table for it, byte for byte",
139        basis: Basis::Chosen,
140        oracle: Oracle::EnterpriseCobol,
141    },
142    Assumption {
143        id: WORKING_STORAGE_LAYOUT,
144        claim: "Each 01 and 77 item of WORKING-STORAGE starts on an 8-byte boundary in source order, and storage without a VALUE starts as X'00'",
145        basis: Basis::Chosen,
146        oracle: Oracle::EnterpriseCobol,
147    },
148    Assumption {
149        id: NOPFD_REPAIRS_UNSIGNED_INPUT,
150        claim: "Under NUMPROC(NOPFD) an unsigned packed or zoned operand's sign is forced to X'F' before use, so no sign makes it a data exception; under PFD it is used as it stands",
151        basis: Basis::Chosen,
152        oracle: Oracle::EnterpriseCobol,
153    },
154    Assumption {
155        id: DISPLAY_OF_NONDISPLAY_NUMERIC,
156        claim: "DISPLAY shows a packed or binary item as zoned digits of its PICTURE, with the sign overpunched on the last digit when the item is signed; a COMP-5 item, or any binary item under TRUNC(BIN), shows its whole binary value in 5, 10, or 19 (signed) or 20 digits for a halfword, fullword or doubleword",
157        basis: Basis::Chosen,
158        oracle: Oracle::EnterpriseCobol,
159    },
160    Assumption {
161        id: ACCEPT_AT_END,
162        claim: "ACCEPT from SYSIN at its end leaves the receiving item unchanged and the run continues",
163        basis: Basis::Chosen,
164        oracle: Oracle::EnterpriseCobol,
165    },
166    Assumption {
167        id: CONTENT_LITERAL_ZONED,
168        claim: "A numeric literal passed BY CONTENT arrives as zoned decimal of its own digits, the sign overpunched when negative",
169        basis: Basis::Chosen,
170        oracle: Oracle::EnterpriseCobol,
171    },
172    Assumption {
173        id: KEYED_FILE_STATUS,
174        claim: "Indexed and relative files report 02 for a shared alternate key, 14 for a record number too long for the RELATIVE KEY on sequential READ, 21 for a sequential WRITE whose key is not above the last (equal included) or a REWRITE that changed the key, 22 duplicate, 23 not found, 24 a record number below 1 or too long for the RELATIVE KEY on WRITE, 43 REWRITE or DELETE with no READ just before, 46 READ NEXT with no next record, and 47, 48, 49 for the wrong open mode",
175        basis: Basis::Recalled,
176        oracle: Oracle::EnterpriseCobol,
177    },
178    Assumption {
179        id: ALTERNATE_KEY_ORDER,
180        claim: "Records sharing an alternate key come back in the order they were written; a record REWRITTEN with a new alternate key goes after the others with it",
181        basis: Basis::Recalled,
182        oracle: Oracle::EnterpriseCobol,
183    },
184    Assumption {
185        id: FAILED_READ_LOSES_POSITION,
186        claim: "A random READ that finds no record leaves no next record, so READ NEXT then gives 46",
187        basis: Basis::Chosen,
188        oracle: Oracle::EnterpriseCobol,
189    },
190    Assumption {
191        id: START_COMPARES_SHORTER,
192        claim: "START compares the key with its operand over the shorter of the two, left to right, as bytes",
193        basis: Basis::Recalled,
194        oracle: Oracle::EnterpriseCobol,
195    },
196    Assumption {
197        id: CICS_FRESH_STORAGE,
198        claim: "A COBOL program reached by EXEC CICS LINK or XCTL starts with fresh WORKING-STORAGE each time, unlike one reached by CALL",
199        basis: Basis::Recalled,
200        oracle: Oracle::EnterpriseCobol,
201    },
202    Assumption {
203        id: CICS_CALEN_RESTORED,
204        claim: "EIBCALEN is the linked program's COMMAREA length while it runs and the caller's again after the LINK returns",
205        basis: Basis::Chosen,
206        oracle: Oracle::EnterpriseCobol,
207    },
208    Assumption {
209        id: CICS_HANDLE_ABEND_CATCHES_CONDITIONS,
210        claim: "HANDLE ABEND LABEL receives control when a condition nothing handles would abend the task (AEIx), and is cancelled by being taken",
211        basis: Basis::Recalled,
212        oracle: Oracle::EnterpriseCobol,
213    },
214    Assumption {
215        id: CICS_LENGTH_DEFAULTS_TO_INTO,
216        claim: "READ, READNEXT, READPREV, READQ TS and READQ TD without LENGTH take the INTO item's length as the limit, so a longer record raises LENGERR",
217        basis: Basis::Recalled,
218        oracle: Oracle::EnterpriseCobol,
219    },
220    Assumption {
221        id: CICS_PROGRAM_CHECK_IS_ASRA,
222        claim: "A program check (S0C4, S0C7 and the like) in a CICS task ends it with transaction abend ASRA",
223        basis: Basis::Recalled,
224        oracle: Oracle::EnterpriseCobol,
225    },
226    Assumption {
227        id: CICS_BROWSE_SKIP,
228        claim: "READNEXT after the program changed RIDFLD to a key the browse is not at continues from the first record at or after the new RIDFLD (skip-sequential)",
229        basis: Basis::Recalled,
230        oracle: Oracle::EnterpriseCobol,
231    },
232    Assumption {
233        id: BMS_RECEIVE_NULLS,
234        claim: "RECEIVE MAP sets the input map to nulls, then fills only the fields the operator modified; a field erased to empty gets F = X'80' and L = 0",
235        basis: Basis::Recalled,
236        oracle: Oracle::EnterpriseCobol,
237    },
238    Assumption {
239        id: BMS_INPUT_JUSTIFY,
240        claim: "Input data lands left-justified and blank-filled unless JUSTIFY says otherwise, and a NUM field right-justified and zero-filled, the defaults IBM documents for JUSTIFY",
241        basis: Basis::Recalled,
242        oracle: Oracle::EnterpriseCobol,
243    },
244    Assumption {
245        id: BMS_EXTENDED_ORDER,
246        claim: "A field's extended attribute bytes in the symbolic map follow its A byte in the order COLOR, PS, HILIGHT, VALIDN, OUTLINE, SOSI, TRANSP",
247        basis: Basis::Chosen,
248        oracle: Oracle::EnterpriseCobol,
249    },
250    Assumption {
251        id: BMS_CONSTANTS_UNVERIFIED,
252        claim: "DFHNULL is X'00', and DFHBMPEM, DFHBMPNL, DFHBMPFF and DFHBMPCR are X'19', X'15', X'0C' and X'0D'",
253        basis: Basis::Recalled,
254        oracle: Oracle::EnterpriseCobol,
255    },
256    Assumption {
257        id: BMS_SEND_DATA_CHOICE,
258        claim: "SEND MAP without MAPONLY or DATAONLY sends a field's symbolic data when its first byte is not X'00', else the map's INITIAL, and a non-null A byte replaces ATTRB",
259        basis: Basis::Recalled,
260        oracle: Oracle::EnterpriseCobol,
261    },
262    Assumption {
263        id: CICS_INITIAL_AID,
264        claim: "A task started by terminal input sees that input's AID in EIBAID before any RECEIVE",
265        basis: Basis::Recalled,
266        oracle: Oracle::EnterpriseCobol,
267    },
268    Assumption {
269        id: REWRITE_SHARED_ALTERNATE,
270        claim: "REWRITE gives 02 whenever another record shares one of the record's alternate keys that allow duplicates, whether or not that key changed",
271        basis: Basis::Chosen,
272        oracle: Oracle::EnterpriseCobol,
273    },
274];
275
276pub fn get(id: &str) -> &'static Assumption {
277    ASSUMPTIONS.iter().find(|a| a.id == id).unwrap_or_else(|| panic!("no assumption {id}"))
278}
279
280#[cfg(test)]
281mod tests {
282    use super::*;
283
284    #[test]
285    fn ids_are_unique() {
286        let mut ids: Vec<_> = ASSUMPTIONS.iter().map(|a| a.id).collect();
287        ids.sort();
288        ids.dedup();
289        assert_eq!(ids.len(), ASSUMPTIONS.len());
290    }
291}