1mod arith;
4mod call;
5mod class;
6mod codec;
7mod collating;
8mod debug;
9mod file;
10mod flow;
11mod markup;
12mod payload;
13mod place;
14mod print;
15mod scope;
16mod sort;
17mod sql;
18mod text;
19mod value;
20
21pub use arith::{ArithPlan, ArithStep, Mode, RemainderPlan, StepPlan, StorePlan, UpDown};
22pub use call::{CallArg, CallPlan, CallTarget, EntryPoint, FunctionDefinition, LeService, UserArgument, UserFunctionPlan};
23pub use class::{Class, ClassPart, Method};
24pub use collating::{Collating, Sequence};
25pub use debug::Debug;
26pub use file::{
27 Access, Advance, AssignItem, Carriage, FileDesc, FileOp, FileVerb, FromMove, IndexKeys, Linage, Organization, Phrase, RecordDepending,
28 RecordSpan, RelativeKey, Spacing, StartKey, StartRel,
29};
30pub use markup::{
31 Ccsid, Convert, Flag, Indicator, JsonGenerate, JsonLeaf, JsonNode, JsonParse, JsonValue, Marker, Markup, Named, NumberInto, ParseLeaf, ParseNode, ParseValue,
32 SetTo, XmlForm, XmlGenerate, XmlNode, XmlParse, XmlRegister, XmlValue,
33};
34pub use flow::{Declaratives, Frame, FrameKind, Op, Range, RangeKind, Resume, ReturnPoint, Returns, Step, Terminator};
35pub use crate::cics::CicsCommand;
36pub use crate::report::{ReportOp, Writer as ReportWriter};
37pub use payload::{
38 Argument, DisplayItem, DisplayPlan, FloatFrom, Func, FunctionPlan, Image, InitField, InitPlan, InitValue,
39 InvokePlan, MethodName, MovePlan, NationalFrom, NumericFrom, PlaceNumcheck, Receiver, SearchAllPlan, SearchKey, SenderCheck, TrimSide,
40};
41pub use place::{Base, Odo, Place, RefMod, Subscript};
42pub use print::{Code, Listing};
43pub use scope::{Binding, Global, GlobalAt, Scope, Section, SharedFile};
44pub use sort::{FileSort, ReleasePlan, ReturnPlan, SortIo, SortKey, SortKeys, SortPlan, TableSort};
45pub use sql::{HostPlace, SqlEntry, SqlStatement, Sqlca, SqlcaField};
46pub use text::{
47 Bound, Chars, ConvertTable, Converting, DelimiterIn, InspectPhrase, InspectPlan, Inspected, Replacement,
48 StringPlan, StringSource, UnstringInto, UnstringPlan,
49};
50pub use value::{ByteClass, Compare, Comparand, Cond, Const, Count, Expr, IntExpr, Operand, SignTest, SqlTest};
51
52use crate::abend::AbendCode;
53use crate::{codec_enum, codec_struct};
54use crate::picture::Sym;
55use crate::storage::Kind;
56
57pub type BlockId = u32;
58pub type ParaId = u32;
59pub type RangeId = u32;
60pub type PlaceId = u32;
61pub type ExprId = u32;
62pub type CondId = u32;
63pub type ConstId = u32;
64pub type SymId = u32;
65pub type DebugId = u32;
66pub type AbendId = u32;
67pub type TempId = u16;
69pub type SqlId = u32;
70pub type ArithId = u32;
71pub type InitId = u32;
72pub type DisplayId = u32;
73pub type InspectId = u32;
74pub type StringId = u32;
75pub type UnstringId = u32;
76pub type SearchAllId = u32;
77pub type FunctionId = u32;
78pub type UserFunctionId = u32;
79pub type FileOpId = u32;
80pub type CallId = u32;
81pub type SortId = u32;
82pub type ReleaseId = u32;
83pub type ReturnId = u32;
84pub type InvokeId = u32;
85pub type CicsId = u32;
86pub type MarkupId = u32;
87
88#[derive(Clone, Debug, PartialEq, Eq)]
89pub struct Program {
90 pub id: SymId,
91 pub options: ProgramOptions,
92 pub initial: bool,
93 pub recursive: bool,
94 pub storage: Storage,
95 pub items: Vec<Item>,
96 pub paragraphs: Vec<Paragraph>,
97 pub procedure_start: ParaId,
99 pub ranges: Vec<Range>,
100 pub blocks: Vec<Block>,
101 pub places: Vec<Place>,
102 pub exprs: Vec<Expr>,
103 pub conds: Vec<Cond>,
104 pub consts: Vec<Const>,
105 pub plans: Plans,
106 pub services: Services,
107 pub sql: Vec<SqlEntry>,
108 pub abends: Vec<AbendText>,
109 pub edits: Vec<Edit>,
110 pub symbols: Vec<String>,
111 pub debug: Debug,
112}
113
114#[derive(Clone, Debug, PartialEq, Eq)]
115pub struct ProgramOptions {
116 pub options: numeric::Options,
117 pub ssrange: bool,
118 pub cards: Vec<String>,
120 pub collating: Collating,
121 pub decimal_point_comma: bool,
124 pub numval_currency: String,
126 pub when_compiled: Option<CompileTime>,
129}
130
131#[derive(Clone, Debug, PartialEq, Eq)]
134pub struct Edit {
135 pub syms: Vec<Sym>,
136 pub currency: String,
137}
138
139#[derive(Clone, Copy, Debug, PartialEq, Eq)]
142pub struct CompileTime {
143 pub seconds: i64,
144 pub hundredths: u32,
145 pub source: TimeSource,
146}
147
148#[derive(Clone, Copy, Debug, PartialEq, Eq)]
149pub enum TimeSource {
150 SourceDateEpoch,
152 Clock,
153}
154
155impl CompileTime {
156 pub const LATEST: i64 = 253_402_300_799;
158}
159
160#[derive(Clone, Debug, Default, PartialEq, Eq)]
161pub struct Storage {
162 pub size: u32,
163 pub image: Vec<u8>,
165 pub local_image: Vec<u8>,
166 pub init_reports: Vec<SymId>,
168 pub init_abend: Option<AbendId>,
169 pub linkage: Vec<u32>,
171 pub using: Vec<u16>,
172 pub returning: Option<u16>,
173 pub file_areas: Vec<(u32, u32)>,
175 pub parmcheck: Option<(u32, u32)>,
177}
178
179#[derive(Clone, Debug, PartialEq, Eq)]
181pub struct Item {
182 pub name: Option<SymId>,
183 pub level: u8,
184 pub parent: Option<u32>,
185 pub offset: u32,
186 pub size: u32,
187 pub occurs: u32,
188 pub dims: Vec<(u32, u32)>,
190 pub kind: Kind,
191 pub local: bool,
192 pub linkage: Option<u16>,
193 pub redefines: Option<SymId>,
194 pub depending_on: Option<u32>,
196 pub keys: Vec<(bool, u32)>,
198 pub at: DebugId,
199}
200
201#[derive(Clone, Debug, PartialEq, Eq)]
204pub struct AbendText {
205 pub code: AbendCode,
206 pub message: SymId,
207 pub at: Option<DebugId>,
208}
209
210#[derive(Clone, Copy, Debug, PartialEq, Eq)]
211pub struct Paragraph {
212 pub name: SymId,
213 pub is_section: bool,
214 pub entry: BlockId,
215 pub section_end: ParaId,
217 pub priority: u8,
219 pub at: DebugId,
220 pub abandoned: Option<AbendId>,
223}
224
225#[derive(Clone, Debug, PartialEq, Eq)]
226pub struct Block {
227 pub ops: Vec<Op>,
228 pub end: Terminator,
229}
230
231#[derive(Clone, Debug, Default, PartialEq, Eq)]
233pub struct Plans {
234 pub arith: Vec<ArithPlan>,
235 pub init: Vec<InitPlan>,
236 pub display: Vec<DisplayPlan>,
237 pub inspect: Vec<InspectPlan>,
238 pub string: Vec<StringPlan>,
239 pub unstring: Vec<UnstringPlan>,
240 pub search_all: Vec<SearchAllPlan>,
241 pub function: Vec<FunctionPlan>,
242}
243
244#[derive(Clone, Debug, Default, PartialEq, Eq)]
245pub struct Services {
246 pub file_ops: Vec<FileOp>,
247 pub files: Vec<FileDesc>,
248 pub calls: Vec<CallPlan>,
249 pub sorts: Vec<SortPlan>,
250 pub releases: Vec<ReleasePlan>,
251 pub returns: Vec<ReturnPlan>,
252 pub invokes: Vec<InvokePlan>,
253 pub cics: Vec<CicsCommand>,
254 pub sqlca: Sqlca,
255 pub entries: Vec<EntryPoint>,
257 pub class: Option<Box<Class>>,
259 pub user_functions: Vec<UserFunctionPlan>,
261 pub function: Option<FunctionDefinition>,
263 pub declaratives: Declaratives,
264 pub markup: Vec<Markup>,
266 pub report: ReportWriter,
268 pub scope: Scope,
270}
271
272impl crate::module::codec::Encode for Program {
275 fn encode(&self, w: &mut crate::module::codec::Writer) {
276 let Program { id, options, initial, recursive, storage, items, paragraphs, procedure_start, ranges, blocks, places, exprs, conds, consts, plans, services, sql, abends, edits, symbols, debug } = self;
277 id.encode(w);
278 options.encode(w);
279 initial.encode(w);
280 recursive.encode(w);
281 storage.encode(w);
282 items.encode(w);
283 paragraphs.encode(w);
284 procedure_start.encode(w);
285 ranges.encode(w);
286 blocks.encode(w);
287 places.encode(w);
288 exprs.encode(w);
289 conds.encode(w);
290 consts.encode(w);
291 plans.encode(w);
292 services.encode(w);
293 sql.encode(w);
294 abends.encode(w);
295 edits.encode(w);
296 symbols.encode(w);
297 debug.encode(w);
298 let assigned: Vec<(u32, AssignItem)> = services.files.iter().enumerate().filter_map(|(k, f)| Some((k as u32, f.assign_item?))).collect();
299 assigned.encode(w);
300 }
301}
302
303impl crate::module::codec::Decode for Program {
304 fn decode(r: &mut crate::module::codec::Reader<'_>) -> Result<Self, crate::module::ModuleError> {
305 use crate::module::codec::Decode;
306 let at = r.position();
307 let mut program = Program {
308 id: Decode::decode(r)?,
309 options: Decode::decode(r)?,
310 initial: Decode::decode(r)?,
311 recursive: Decode::decode(r)?,
312 storage: Decode::decode(r)?,
313 items: Decode::decode(r)?,
314 paragraphs: Decode::decode(r)?,
315 procedure_start: Decode::decode(r)?,
316 ranges: Decode::decode(r)?,
317 blocks: Decode::decode(r)?,
318 places: Decode::decode(r)?,
319 exprs: Decode::decode(r)?,
320 conds: Decode::decode(r)?,
321 consts: Decode::decode(r)?,
322 plans: Decode::decode(r)?,
323 services: Decode::decode(r)?,
324 sql: Decode::decode(r)?,
325 abends: Decode::decode(r)?,
326 edits: Decode::decode(r)?,
327 symbols: Decode::decode(r)?,
328 debug: Decode::decode(r)?,
329 };
330 for (k, item) in Vec::<(u32, AssignItem)>::decode(r)? {
331 let file = program.services.files.get_mut(k as usize).ok_or_else(|| r.malformed(at, format!("an assign item for file {k}")))?;
332 file.assign_item = Some(item);
333 }
334 program_valid(&program).map_err(|reason| r.malformed(at, reason))?;
335 Ok(program)
336 }
337}
338codec_struct!(ProgramOptions { options, ssrange, cards, collating, decimal_point_comma, numval_currency, when_compiled });
339codec_struct!(Edit { syms, currency });
340codec_struct!(CompileTime { seconds, hundredths, source } check compile_time_valid);
341codec_enum!(TimeSource { SourceDateEpoch = 0, Clock = 1 });
342codec_struct!(Storage {
343 size, image, local_image, init_reports, init_abend, linkage, using, returning, file_areas, parmcheck,
344} check storage_valid);
345codec_struct!(Item {
346 name, level, parent, offset, size, occurs, dims, kind, local, linkage, redefines, depending_on, keys, at,
347});
348codec_struct!(AbendText { code, message, at });
349codec_struct!(Paragraph { name, is_section, entry, section_end, priority, at, abandoned });
350codec_struct!(Block { ops, end });
351codec_struct!(Plans { arith, init, display, inspect, string, unstring, search_all, function });
352codec_struct!(Services {
353 file_ops, files, calls, sorts, releases, returns, invokes, cics, sqlca, entries, class, user_functions, function, declaratives, markup, report, scope,
354});
355
356pub(crate) fn program_valid(program: &Program) -> Result<(), String> {
357 sql::table_valid(&program.sql, &program.symbols)
358}
359
360fn compile_time_valid(t: &CompileTime) -> Result<(), String> {
361 let whole = t.source == TimeSource::SourceDateEpoch && t.hundredths != 0;
362 if !(0..=CompileTime::LATEST).contains(&t.seconds) || t.hundredths > 99 || whole {
363 return Err(format!("a compile time of {} seconds and {} hundredths from {:?}", t.seconds, t.hundredths, t.source));
364 }
365 Ok(())
366}
367
368fn storage_valid(storage: &Storage) -> Result<(), String> {
369 if u32::try_from(storage.image.len()) != Ok(storage.size) {
370 return Err(format!("an image of {} bytes for a slab of {}", storage.image.len(), storage.size));
371 }
372 match storage.parmcheck {
373 Some((offset, len)) if offset.checked_add(len).is_none_or(|end| end > storage.size) => Err(format!("a PARMCHECK buffer at {offset} for {len} in a slab of {}", storage.size)),
374 _ => Ok(()),
375 }
376}