Skip to main content

ironwork_rt/lir/
flow.rs

1//! Control flow (lir.md §8): ops, terminators, PERFORM ranges and the VM's frames.
2
3use super::{
4    AbendId, ArithId, BlockId, CallId, CicsId, CondId, DebugId, DisplayId, ExprId, FileOpId, InitId, InspectId, IntExpr,
5    InvokeId, MovePlan, Operand, ParaId, PlaceId, RangeId, ReleaseId, ReportOp, ReturnId, SearchAllId, SortId, SqlId,
6    StepPlan, StringId, TempId, UnstringId,
7};
8use crate::abend::Ending;
9use crate::vocab::AcceptFrom;
10use crate::{codec_enum, codec_struct};
11
12#[derive(Clone, Debug, PartialEq, Eq)]
13pub enum Op {
14    Move { from: Operand, to: PlaceId, plan: MovePlan },
15    Initialize { target: PlaceId, plan: InitId },
16    Arith(ArithId),
17    SetAddress { record: u16, address: Operand },
18    SetUpDown { target: PlaceId, by: IntExpr, down: bool, plan: StepPlan },
19    /// PERFORM VARYING's increment: `var` located, then each place of `prepass`, then `var + by`
20    /// computed and stored.
21    Step { var: PlaceId, by: ExprId, plan: StepPlan, prepass: Vec<PlaceId> },
22    /// SEARCH's index steps, SORT-RETURN.
23    SetInt { target: PlaceId, value: IntExpr },
24    Inspect(InspectId),
25    String(StringId),
26    Unstring(UnstringId),
27    SearchAll(SearchAllId),
28    /// Raises the PERFORM and CALL depth, abending past 100.
29    Nest,
30    Unnest(u8),
31    SetTemp(TempId, IntExpr),
32    DecTemp(TempId),
33    Display(DisplayId),
34    Accept { target: PlaceId, from: AcceptFrom, plan: MovePlan },
35    File(FileOpId),
36    Call(CallId),
37    Cancel(Operand),
38    Sort(SortId),
39    Release(ReleaseId),
40    Return(ReturnId),
41    Report(ReportOp),
42    Invoke(InvokeId),
43    Cics(CicsId),
44    Sql(SqlId),
45    /// ALTER: from now on control reaching paragraph `para` goes to `to`. The alter table lives as
46    /// long as the program's WORKING-STORAGE.
47    Alter { para: ParaId, to: ParaId },
48    /// Control reaching a paragraph of segment `priority`: when that differs from the segment
49    /// register and is 50 or more, the alter entries of the segment's paragraphs are cleared. The
50    /// register then holds `priority`.
51    EnterSegment(u8),
52    /// A PERFORM range completed: the register goes back to the PERFORM's own segment, clearing
53    /// nothing.
54    SetSegment(u8),
55}
56
57/// What an op tells the VM.
58#[derive(Clone, Copy, Debug, PartialEq, Eq)]
59pub enum Step {
60    Next,
61    /// The handler a service selected, for the block's `Select`.
62    Arm(u8),
63    /// A transfer a service chose at run time: HANDLE CONDITION, HANDLE ABEND.
64    GoTo(ParaId),
65    End(Ending),
66}
67
68#[derive(Clone, Debug, PartialEq, Eq)]
69pub enum Terminator {
70    Jump(BlockId),
71    Branch { cond: CondId, then: BlockId, otherwise: BlockId },
72    /// On the `Arm` the block's last op returned.
73    Select(Vec<BlockId>),
74    /// Leaves a paragraph for `next`, which may be one past the last; a PERFORM range may complete here.
75    ParagraphEnd { next: ParaId },
76    GoTo(ParaId),
77    /// GO TO … DEPENDING ON: `targets[k − 1]` for k in range, taken as a `GoTo`; else `otherwise`.
78    Switch { value: IntExpr, targets: Vec<ParaId>, otherwise: BlockId },
79    /// An out-of-line PERFORM: push a frame and enter the range; `ret` runs when it completes.
80    PerformEnter { range: RangeId, ret: BlockId },
81    /// Nothing in the run unit's first program, GOBACK in any other.
82    ExitProgram { next: BlockId },
83    End(Ending),
84    Abend(AbendId),
85    /// The entry of a paragraph an ALTER names: a `GoTo` of the target the alter table holds for
86    /// `para`, or `Jump(otherwise)` while it holds none.
87    AlteredGoTo { para: ParaId, otherwise: BlockId },
88}
89
90#[derive(Clone, Copy, Debug, PartialEq, Eq)]
91pub struct Range {
92    pub first: ParaId,
93    pub last: ParaId,
94    pub kind: RangeKind,
95}
96
97#[derive(Clone, Copy, Debug, PartialEq, Eq)]
98pub enum RangeKind {
99    Perform,
100    SortProcedure,
101    UseBeforeReporting,
102}
103
104/// An active range: `ret` runs when it completes, and its paragraphs run at `depth`. `temps` are the
105/// TIMES counters of the statements that run under it, by `TempId`: a paragraph can PERFORM itself,
106/// and each activation counts its own.
107#[derive(Clone, Debug, PartialEq, Eq)]
108pub struct Frame {
109    pub first: ParaId,
110    pub last: ParaId,
111    pub kind: FrameKind,
112    pub ret: BlockId,
113    pub depth: u32,
114    pub temps: Vec<i64>,
115}
116
117/// Main is the program's own run and holds every paragraph.
118#[derive(Clone, Copy, Debug, PartialEq, Eq)]
119pub enum FrameKind {
120    Main,
121    Perform,
122    SortProcedure,
123    UseBeforeReporting { at: DebugId },
124}
125
126codec_enum!(Op {
127    Move { from, to, plan } = 0,
128    Initialize { target, plan } = 1,
129    Arith(id) = 2,
130    SetAddress { record, address } = 3,
131    SetUpDown { target, by, down, plan } = 4,
132    Step { var, by, plan, prepass } = 5,
133    SetInt { target, value } = 6,
134    Inspect(id) = 7,
135    String(id) = 8,
136    Unstring(id) = 9,
137    SearchAll(id) = 10,
138    Nest = 11,
139    Unnest(n) = 12,
140    SetTemp(temp, value) = 13,
141    DecTemp(temp) = 14,
142    Display(id) = 15,
143    Accept { target, from, plan } = 16,
144    File(id) = 17,
145    Call(id) = 18,
146    Cancel(name) = 19,
147    Sort(id) = 20,
148    Release(id) = 21,
149    Return(id) = 22,
150    Report(op) = 23,
151    Invoke(id) = 24,
152    Cics(id) = 25,
153    Sql(id) = 26,
154    Alter { para, to } = 27,
155    EnterSegment(priority) = 28,
156    SetSegment(priority) = 29,
157});
158codec_enum!(Step { Next = 0, Arm(arm) = 1, GoTo(para) = 2, End(ending) = 3 });
159codec_enum!(Terminator {
160    Jump(block) = 0,
161    Branch { cond, then, otherwise } = 1,
162    Select(arms) = 2,
163    ParagraphEnd { next } = 3,
164    GoTo(para) = 4,
165    Switch { value, targets, otherwise } = 5,
166    PerformEnter { range, ret } = 6,
167    ExitProgram { next } = 7,
168    End(ending) = 8,
169    Abend(abend) = 9,
170    AlteredGoTo { para, otherwise } = 10,
171});
172codec_struct!(Range { first, last, kind });
173codec_enum!(RangeKind { Perform = 0, SortProcedure = 1, UseBeforeReporting = 2 });
174codec_struct!(Frame { first, last, kind, ret, depth, temps });
175codec_enum!(FrameKind { Main = 0, Perform = 1, SortProcedure = 2, UseBeforeReporting { at } = 3 });