Skip to main content

ironwork_rt/lir/
mod.rs

1//! The LIR of docs/lir.md: a program lowered once, which the VM runs and a load module holds.
2
3mod arith;
4mod call;
5mod class;
6mod codec;
7mod collating;
8mod debug;
9mod file;
10mod flow;
11mod markup;
12mod payload;
13mod place;
14mod sort;
15mod sql;
16mod text;
17mod value;
18
19pub use arith::{ArithPlan, ArithStep, Mode, RemainderPlan, StepPlan, StorePlan, UpDown};
20pub use call::{CallArg, CallPlan, CallTarget, EntryPoint, LeService};
21pub use class::{Class, ClassPart, Method};
22pub use collating::{Collating, Sequence};
23pub use debug::Debug;
24pub use file::{
25    Access, Advance, Carriage, FileDesc, FileOp, FileVerb, FromMove, IndexKeys, Linage, Organization, Phrase, RecordSpan,
26    RelativeKey, Spacing, StartKey, StartRel,
27};
28pub use markup::{
29    Ccsid, Convert, Flag, Indicator, JsonGenerate, JsonLeaf, JsonNode, JsonParse, JsonValue, Marker, Markup, Named, NumberInto, ParseLeaf, ParseNode, ParseValue,
30    SetTo, XmlForm, XmlGenerate, XmlNode, XmlParse, XmlRegister, XmlValue,
31};
32pub use flow::{Declaratives, Frame, FrameKind, Op, Range, RangeKind, Resume, ReturnPoint, Returns, Step, Terminator};
33pub use crate::cics::CicsCommand;
34pub use crate::report::{ReportOp, Writer as ReportWriter};
35pub use payload::{
36    Argument, DisplayItem, DisplayPlan, FloatFrom, Func, FunctionPlan, Image, InitField, InitPlan,
37    InvokePlan, MethodName, MovePlan, NationalFrom, NumericFrom, Receiver, SearchAllPlan, SearchKey, TrimSide,
38};
39pub use place::{Base, Odo, Place, RefMod, Subscript};
40pub use sort::{FileSort, ReleasePlan, ReturnPlan, SortIo, SortKey, SortKeys, SortPlan, TableSort};
41pub use sql::{HostPlace, SqlEntry, SqlStatement, Sqlca, SqlcaField};
42pub use text::{
43    Bound, Chars, ConvertTable, Converting, DelimiterIn, InspectPhrase, InspectPlan, Replacement, StringPlan,
44    StringSource, UnstringInto, UnstringPlan,
45};
46pub use value::{ByteClass, Compare, Comparand, Cond, Const, Count, Expr, IntExpr, Operand, SignTest, SqlTest};
47
48use crate::abend::AbendCode;
49use crate::{codec_enum, codec_struct};
50use crate::picture::Sym;
51use crate::storage::Kind;
52
53pub type BlockId = u32;
54pub type ParaId = u32;
55pub type RangeId = u32;
56pub type PlaceId = u32;
57pub type ExprId = u32;
58pub type CondId = u32;
59pub type ConstId = u32;
60pub type SymId = u32;
61pub type DebugId = u32;
62pub type AbendId = u32;
63/// A PERFORM TIMES counter, held in the frame the statement runs under (`Frame.temps`).
64pub type TempId = u16;
65pub type SqlId = u32;
66pub type ArithId = u32;
67pub type InitId = u32;
68pub type DisplayId = u32;
69pub type InspectId = u32;
70pub type StringId = u32;
71pub type UnstringId = u32;
72pub type SearchAllId = u32;
73pub type FunctionId = u32;
74pub type FileOpId = u32;
75pub type CallId = u32;
76pub type SortId = u32;
77pub type ReleaseId = u32;
78pub type ReturnId = u32;
79pub type InvokeId = u32;
80pub type CicsId = u32;
81pub type MarkupId = u32;
82
83#[derive(Clone, Debug, PartialEq, Eq)]
84pub struct Program {
85    pub id: SymId,
86    pub options: ProgramOptions,
87    pub initial: bool,
88    pub recursive: bool,
89    pub storage: Storage,
90    pub items: Vec<Item>,
91    pub paragraphs: Vec<Paragraph>,
92    /// The first paragraph after DECLARATIVES, where a run starts.
93    pub procedure_start: ParaId,
94    pub ranges: Vec<Range>,
95    pub blocks: Vec<Block>,
96    pub places: Vec<Place>,
97    pub exprs: Vec<Expr>,
98    pub conds: Vec<Cond>,
99    pub consts: Vec<Const>,
100    pub plans: Plans,
101    pub services: Services,
102    pub sql: Vec<SqlEntry>,
103    pub abends: Vec<AbendText>,
104    pub edits: Vec<Edit>,
105    pub symbols: Vec<String>,
106    pub debug: Debug,
107}
108
109#[derive(Clone, Debug, PartialEq, Eq)]
110pub struct ProgramOptions {
111    pub options: numeric::Options,
112    pub ssrange: bool,
113    /// The CBL and PROCESS cards as written.
114    pub cards: Vec<String>,
115    pub collating: Collating,
116    /// DECIMAL-POINT IS COMMA: numeric editing shows a comma for the decimal point, and the NUMVAL
117    /// and TEST-NUMVAL functions read one.
118    pub decimal_point_comma: bool,
119    /// The cs NUMVAL-C and TEST-NUMVAL-C take without argument-2 (assumption C102).
120    pub numval_currency: String,
121    /// What FUNCTION WHEN-COMPILED gives; None in a program that does not use it, so its module
122    /// does not depend on when it was compiled.
123    pub when_compiled: Option<CompileTime>,
124}
125
126/// An edited PICTURE's symbols, and the currency sign value its currency symbol stands for, empty
127/// when it has none.
128#[derive(Clone, Debug, PartialEq, Eq)]
129pub struct Edit {
130    pub syms: Vec<Sym>,
131    pub currency: String,
132}
133
134/// When the program was compiled, which FUNCTION WHEN-COMPILED gives: seconds since
135/// 1970-01-01T00:00:00Z and hundredths, and where the time came from.
136#[derive(Clone, Copy, Debug, PartialEq, Eq)]
137pub struct CompileTime {
138    pub seconds: i64,
139    pub hundredths: u32,
140    pub source: TimeSource,
141}
142
143#[derive(Clone, Copy, Debug, PartialEq, Eq)]
144pub enum TimeSource {
145    /// The build's SOURCE_DATE_EPOCH, whole seconds (reproducible-builds.org/specs/source-date-epoch).
146    SourceDateEpoch,
147    Clock,
148}
149
150impl CompileTime {
151    /// 9999-12-31T23:59:59Z, the last second WHEN-COMPILED's four-digit year can show.
152    pub const LATEST: i64 = 253_402_300_799;
153}
154
155#[derive(Clone, Debug, Default, PartialEq, Eq)]
156pub struct Storage {
157    pub size: u32,
158    /// The slab and LOCAL-STORAGE as VALUE clauses leave them.
159    pub image: Vec<u8>,
160    pub local_image: Vec<u8>,
161    /// What VALUE initialization prints (TRUNC(OPT) reports), and its abend.
162    pub init_reports: Vec<SymId>,
163    pub init_abend: Option<AbendId>,
164    /// Each LINKAGE record's size; USING and RETURNING as record ordinals.
165    pub linkage: Vec<u32>,
166    pub using: Vec<u16>,
167    pub returning: Option<u16>,
168    /// Offset and size of each file's record area in the slab.
169    pub file_areas: Vec<(u32, u32)>,
170}
171
172/// A data item for `dump` and a debugger; no executor reads it.
173#[derive(Clone, Debug, PartialEq, Eq)]
174pub struct Item {
175    pub name: Option<SymId>,
176    pub level: u8,
177    pub parent: Option<u32>,
178    pub offset: u32,
179    pub size: u32,
180    pub occurs: u32,
181    /// Stride and count of each OCCURS on the item and its ancestors, outermost first.
182    pub dims: Vec<(u32, u32)>,
183    pub kind: Kind,
184    pub local: bool,
185    pub linkage: Option<u16>,
186    pub redefines: Option<SymId>,
187    /// The OCCURS DEPENDING ON object's item index.
188    pub depending_on: Option<u32>,
189    /// Each key's item index, true for ASCENDING.
190    pub keys: Vec<(bool, u32)>,
191    pub at: DebugId,
192}
193
194/// `at` is None where the op or terminator that raises the abend gives its position, and the data
195/// entry's for `Storage.init_abend`.
196#[derive(Clone, Debug, PartialEq, Eq)]
197pub struct AbendText {
198    pub code: AbendCode,
199    pub message: SymId,
200    pub at: Option<DebugId>,
201}
202
203#[derive(Clone, Copy, Debug, PartialEq, Eq)]
204pub struct Paragraph {
205    pub name: SymId,
206    pub is_section: bool,
207    pub entry: BlockId,
208    /// The last paragraph of its section.
209    pub section_end: ParaId,
210    /// Its section's priority-number, 0 for none; 50 or more is an independent segment.
211    pub priority: u8,
212    pub at: DebugId,
213    /// On a paragraph that ends a range: the IRONWORK abend when control passes its end while it
214    /// holds the return point of a frame control left that cannot resume (C99).
215    pub abandoned: Option<AbendId>,
216}
217
218#[derive(Clone, Debug, PartialEq, Eq)]
219pub struct Block {
220    pub ops: Vec<Op>,
221    pub end: Terminator,
222}
223
224/// The plan tables ops index; a MOVE's plan sits in its op.
225#[derive(Clone, Debug, Default, PartialEq, Eq)]
226pub struct Plans {
227    pub arith: Vec<ArithPlan>,
228    pub init: Vec<InitPlan>,
229    pub display: Vec<DisplayPlan>,
230    pub inspect: Vec<InspectPlan>,
231    pub string: Vec<StringPlan>,
232    pub unstring: Vec<UnstringPlan>,
233    pub search_all: Vec<SearchAllPlan>,
234    pub function: Vec<FunctionPlan>,
235}
236
237#[derive(Clone, Debug, Default, PartialEq, Eq)]
238pub struct Services {
239    pub file_ops: Vec<FileOp>,
240    pub files: Vec<FileDesc>,
241    pub calls: Vec<CallPlan>,
242    pub sorts: Vec<SortPlan>,
243    pub releases: Vec<ReleasePlan>,
244    pub returns: Vec<ReturnPlan>,
245    pub invokes: Vec<InvokePlan>,
246    pub cics: Vec<CicsCommand>,
247    pub sqlca: Sqlca,
248    /// The ENTRY statements, in source order, which a CALL of their names enters.
249    pub entries: Vec<EntryPoint>,
250    /// A class definition's data and methods; None for any other program.
251    pub class: Option<Box<Class>>,
252    pub declaratives: Declaratives,
253    /// JSON GENERATE, JSON PARSE, XML GENERATE and XML PARSE, by `Op::Markup`.
254    pub markup: Vec<Markup>,
255}
256
257codec_struct!(Program {
258    id, options, initial, recursive, storage, items, paragraphs, procedure_start, ranges, blocks, places, exprs,
259    conds, consts, plans, services, sql, abends, edits, symbols, debug,
260} check program_valid);
261codec_struct!(ProgramOptions { options, ssrange, cards, collating, decimal_point_comma, numval_currency, when_compiled });
262codec_struct!(Edit { syms, currency });
263codec_struct!(CompileTime { seconds, hundredths, source } check compile_time_valid);
264codec_enum!(TimeSource { SourceDateEpoch = 0, Clock = 1 });
265codec_struct!(Storage {
266    size, image, local_image, init_reports, init_abend, linkage, using, returning, file_areas,
267} check storage_valid);
268codec_struct!(Item {
269    name, level, parent, offset, size, occurs, dims, kind, local, linkage, redefines, depending_on, keys, at,
270});
271codec_struct!(AbendText { code, message, at });
272codec_struct!(Paragraph { name, is_section, entry, section_end, priority, at, abandoned });
273codec_struct!(Block { ops, end });
274codec_struct!(Plans { arith, init, display, inspect, string, unstring, search_all, function });
275codec_struct!(Services { file_ops, files, calls, sorts, releases, returns, invokes, cics, sqlca, entries, class, declaratives, markup });
276
277pub(crate) fn program_valid(program: &Program) -> Result<(), String> {
278    sql::table_valid(&program.sql, &program.symbols)
279}
280
281fn compile_time_valid(t: &CompileTime) -> Result<(), String> {
282    let whole = t.source == TimeSource::SourceDateEpoch && t.hundredths != 0;
283    if !(0..=CompileTime::LATEST).contains(&t.seconds) || t.hundredths > 99 || whole {
284        return Err(format!("a compile time of {} seconds and {} hundredths from {:?}", t.seconds, t.hundredths, t.source));
285    }
286    Ok(())
287}
288
289fn storage_valid(storage: &Storage) -> Result<(), String> {
290    if u32::try_from(storage.image.len()) == Ok(storage.size) {
291        Ok(())
292    } else {
293        Err(format!("an image of {} bytes for a slab of {}", storage.image.len(), storage.size))
294    }
295}