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 flow;
10mod payload;
11mod place;
12mod sql;
13mod text;
14mod value;
15
16pub use arith::{ArithPlan, ArithStep, Mode, RemainderPlan, StepPlan, StorePlan};
17pub use call::{CallArg, CallPlan, CallTarget, EntryPoint, LeService};
18pub use class::{Class, ClassPart, Method};
19pub use collating::{Collating, Sequence};
20pub use debug::Debug;
21pub use flow::{Frame, FrameKind, Op, Range, RangeKind, Step, Terminator};
22pub use payload::{
23    CicsCommand, DisplayItem, DisplayPlan, FileDesc, FileOp, FloatFrom, Func, FunctionPlan, Image, InitField, InitPlan,
24    InvokePlan, MethodName, MovePlan, NationalFrom, NumericFrom, Receiver, ReleasePlan, ReportOp, ReturnPlan,
25    SearchAllPlan, SearchKey, SortPlan, TrimSide,
26};
27pub use place::{Base, Odo, Place, RefMod, Subscript};
28pub use sql::{HostPlace, SqlEntry, SqlStatement, Sqlca, SqlcaField};
29pub use text::{
30    Bound, Chars, ConvertTable, Converting, DelimiterIn, InspectPhrase, InspectPlan, Replacement, StringPlan,
31    StringSource, UnstringInto, UnstringPlan,
32};
33pub use value::{ByteClass, Compare, Comparand, Cond, Const, Count, Expr, IntExpr, Operand, SignTest, SqlTest};
34
35use crate::abend::AbendCode;
36use crate::codec_struct;
37use crate::picture::Sym;
38use crate::storage::Kind;
39
40pub type BlockId = u32;
41pub type ParaId = u32;
42pub type RangeId = u32;
43pub type PlaceId = u32;
44pub type ExprId = u32;
45pub type CondId = u32;
46pub type ConstId = u32;
47pub type SymId = u32;
48pub type DebugId = u32;
49pub type AbendId = u32;
50/// A PERFORM TIMES counter, held in the frame the statement runs under (`Frame.temps`).
51pub type TempId = u16;
52pub type SqlId = u32;
53pub type ArithId = u32;
54pub type InitId = u32;
55pub type DisplayId = u32;
56pub type InspectId = u32;
57pub type StringId = u32;
58pub type UnstringId = u32;
59pub type SearchAllId = u32;
60pub type FunctionId = u32;
61pub type FileOpId = u32;
62pub type CallId = u32;
63pub type SortId = u32;
64pub type ReleaseId = u32;
65pub type ReturnId = u32;
66pub type InvokeId = u32;
67pub type CicsId = u32;
68
69#[derive(Clone, Debug, PartialEq, Eq)]
70pub struct Program {
71    pub id: SymId,
72    pub options: ProgramOptions,
73    pub initial: bool,
74    pub recursive: bool,
75    pub storage: Storage,
76    pub items: Vec<Item>,
77    pub paragraphs: Vec<Paragraph>,
78    /// The first paragraph after DECLARATIVES, where a run starts.
79    pub procedure_start: ParaId,
80    pub ranges: Vec<Range>,
81    pub blocks: Vec<Block>,
82    pub places: Vec<Place>,
83    pub exprs: Vec<Expr>,
84    pub conds: Vec<Cond>,
85    pub consts: Vec<Const>,
86    pub plans: Plans,
87    pub services: Services,
88    pub sql: Vec<SqlEntry>,
89    pub abends: Vec<AbendText>,
90    pub edits: Vec<Vec<Sym>>,
91    pub symbols: Vec<String>,
92    pub debug: Debug,
93}
94
95#[derive(Clone, Debug, PartialEq, Eq)]
96pub struct ProgramOptions {
97    pub options: numeric::Options,
98    pub ssrange: bool,
99    /// The CBL and PROCESS cards as written.
100    pub cards: Vec<String>,
101    pub collating: Collating,
102}
103
104#[derive(Clone, Debug, Default, PartialEq, Eq)]
105pub struct Storage {
106    pub size: u32,
107    /// The slab and LOCAL-STORAGE as VALUE clauses leave them.
108    pub image: Vec<u8>,
109    pub local_image: Vec<u8>,
110    /// What VALUE initialization prints (TRUNC(OPT) reports), and its abend.
111    pub init_reports: Vec<SymId>,
112    pub init_abend: Option<AbendId>,
113    /// Each LINKAGE record's size; USING and RETURNING as record ordinals.
114    pub linkage: Vec<u32>,
115    pub using: Vec<u16>,
116    pub returning: Option<u16>,
117    /// Offset and size of each file's record area in the slab.
118    pub file_areas: Vec<(u32, u32)>,
119}
120
121/// A data item for `dump` and a debugger; no executor reads it.
122#[derive(Clone, Debug, PartialEq, Eq)]
123pub struct Item {
124    pub name: Option<SymId>,
125    pub level: u8,
126    pub parent: Option<u32>,
127    pub offset: u32,
128    pub size: u32,
129    pub occurs: u32,
130    /// Stride and count of each OCCURS on the item and its ancestors, outermost first.
131    pub dims: Vec<(u32, u32)>,
132    pub kind: Kind,
133    pub local: bool,
134    pub linkage: Option<u16>,
135    pub redefines: Option<SymId>,
136    /// The OCCURS DEPENDING ON object's item index.
137    pub depending_on: Option<u32>,
138    /// Each key's item index, true for ASCENDING.
139    pub keys: Vec<(bool, u32)>,
140    pub at: DebugId,
141}
142
143/// `at` is None where the op or terminator that raises the abend gives its position, and the data
144/// entry's for `Storage.init_abend`.
145#[derive(Clone, Debug, PartialEq, Eq)]
146pub struct AbendText {
147    pub code: AbendCode,
148    pub message: SymId,
149    pub at: Option<DebugId>,
150}
151
152#[derive(Clone, Copy, Debug, PartialEq, Eq)]
153pub struct Paragraph {
154    pub name: SymId,
155    pub is_section: bool,
156    pub entry: BlockId,
157    /// The last paragraph of its section.
158    pub section_end: ParaId,
159    /// Its section's priority-number, 0 for none; 50 or more is an independent segment.
160    pub priority: u8,
161    pub at: DebugId,
162}
163
164#[derive(Clone, Debug, PartialEq, Eq)]
165pub struct Block {
166    pub ops: Vec<Op>,
167    pub end: Terminator,
168}
169
170/// The plan tables ops index; a MOVE's plan sits in its op.
171#[derive(Clone, Debug, Default, PartialEq, Eq)]
172pub struct Plans {
173    pub arith: Vec<ArithPlan>,
174    pub init: Vec<InitPlan>,
175    pub display: Vec<DisplayPlan>,
176    pub inspect: Vec<InspectPlan>,
177    pub string: Vec<StringPlan>,
178    pub unstring: Vec<UnstringPlan>,
179    pub search_all: Vec<SearchAllPlan>,
180    pub function: Vec<FunctionPlan>,
181}
182
183#[derive(Clone, Debug, Default, PartialEq, Eq)]
184pub struct Services {
185    pub file_ops: Vec<FileOp>,
186    pub files: Vec<FileDesc>,
187    pub calls: Vec<CallPlan>,
188    pub sorts: Vec<SortPlan>,
189    pub releases: Vec<ReleasePlan>,
190    pub returns: Vec<ReturnPlan>,
191    pub invokes: Vec<InvokePlan>,
192    pub cics: Vec<CicsCommand>,
193    pub sqlca: Sqlca,
194    /// The ENTRY statements, in source order, which a CALL of their names enters.
195    pub entries: Vec<EntryPoint>,
196    /// A class definition's data and methods; None for any other program.
197    pub class: Option<Box<Class>>,
198}
199
200codec_struct!(Program {
201    id, options, initial, recursive, storage, items, paragraphs, procedure_start, ranges, blocks, places, exprs,
202    conds, consts, plans, services, sql, abends, edits, symbols, debug,
203} check program_valid);
204codec_struct!(ProgramOptions { options, ssrange, cards, collating });
205codec_struct!(Storage {
206    size, image, local_image, init_reports, init_abend, linkage, using, returning, file_areas,
207} check storage_valid);
208codec_struct!(Item {
209    name, level, parent, offset, size, occurs, dims, kind, local, linkage, redefines, depending_on, keys, at,
210});
211codec_struct!(AbendText { code, message, at });
212codec_struct!(Paragraph { name, is_section, entry, section_end, priority, at });
213codec_struct!(Block { ops, end });
214codec_struct!(Plans { arith, init, display, inspect, string, unstring, search_all, function });
215codec_struct!(Services { file_ops, files, calls, sorts, releases, returns, invokes, cics, sqlca, entries, class });
216
217pub(crate) fn program_valid(program: &Program) -> Result<(), String> {
218    sql::table_valid(&program.sql, &program.symbols)
219}
220
221fn storage_valid(storage: &Storage) -> Result<(), String> {
222    if u32::try_from(storage.image.len()) == Ok(storage.size) {
223        Ok(())
224    } else {
225        Err(format!("an image of {} bytes for a slab of {}", storage.image.len(), storage.size))
226    }
227}