Skip to main content

ironwork_syntax/
ast.rs

1use crate::Pos;
2
3mod oo;
4pub use oo::*;
5
6#[derive(Clone, Debug, Default, PartialEq, Eq)]
7pub struct Program {
8    pub id: String,
9    /// Options from CBL and PROCESS cards, in the order written.
10    pub options: Vec<String>,
11    /// PROGRAM-ID ... IS INITIAL: WORKING-STORAGE starts afresh on every CALL.
12    pub initial: bool,
13    pub recursive: bool,
14    pub working_storage: Vec<DataEntry>,
15    /// LOCAL-STORAGE: fresh for every activation of the program.
16    pub local_storage: Vec<DataEntry>,
17    pub linkage: Vec<DataEntry>,
18    /// PROCEDURE DIVISION USING: the LINKAGE items the caller's arguments address.
19    pub using: Vec<Param>,
20    pub returning: Option<String>,
21    pub paragraphs: Vec<Paragraph>,
22    /// Files declared by SELECT and described by FD, with their record descriptions.
23    pub files: Vec<FileDecl>,
24    /// The program's source file, then each COPY member, as positions index them.
25    pub sources: Vec<String>,
26    /// EXEC blocks in the DATA DIVISION: SQL declarations, cursors and DECLARE SECTION markers.
27    pub exec_declarations: Vec<ExecBlock>,
28    /// The REPORT SECTION, and the DECLARATIVES that serve it.
29    pub report_writer: crate::report::ReportWriter,
30    /// The DECLARATIVES' USE AFTER EXCEPTION/ERROR and USE FOR DEBUGGING procedures.
31    pub declaratives: Declaratives,
32    /// The REPOSITORY's classes, and for a class definition or a method what it is.
33    pub oo: Option<Box<Oo>>,
34    pub environment: Environment,
35    /// The PROGRAM-IDs of the programs it directly contains.
36    pub nested: Vec<String>,
37}
38
39#[derive(Clone, Debug, PartialEq, Eq)]
40pub struct Param {
41    pub by_value: bool,
42    pub name: String,
43}
44
45#[derive(Clone, Copy, Debug, PartialEq, Eq)]
46pub enum Organization {
47    Sequential,
48    LineSequential,
49    Indexed,
50    Relative,
51}
52
53#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
54pub enum Access {
55    #[default]
56    Sequential,
57    Random,
58    Dynamic,
59}
60
61#[derive(Clone, Debug, PartialEq, Eq)]
62pub struct FileDecl {
63    pub name: String,
64    /// The DD name ASSIGN gives, with any `UT-S-` style prefix removed.
65    pub assign: String,
66    pub organization: Organization,
67    pub access: Access,
68    pub record_key: Option<Ref>,
69    /// ALTERNATE RECORD KEY items, and whether each allows duplicates.
70    pub alternate_keys: Vec<(Ref, bool)>,
71    pub relative_key: Option<Ref>,
72    pub optional: bool,
73    pub status: Option<Ref>,
74    /// RECORDING MODE: F, V, U or S.
75    pub recording: Option<char>,
76    pub record_min: Option<u32>,
77    pub record_max: Option<u32>,
78    pub records: Vec<DataEntry>,
79    /// FD ... REPORT IS: the reports written to the file.
80    pub reports: Vec<String>,
81    /// FD ... LINAGE: the logical page. An SD's is read and dropped, as IBM ignores it.
82    pub linage: Option<Linage>,
83    /// Described by SD: a sort or merge file, which needs no data set.
84    pub sort: bool,
85    pub pos: Pos,
86}
87
88/// LINAGE IS lines [WITH FOOTING AT footing] [LINES AT TOP top] [LINES AT BOTTOM bottom].
89#[derive(Clone, Debug, PartialEq, Eq)]
90pub struct Linage {
91    pub lines: LinageValue,
92    pub footing: Option<LinageValue>,
93    pub top: Option<LinageValue>,
94    pub bottom: Option<LinageValue>,
95}
96
97#[derive(Clone, Debug, PartialEq, Eq)]
98pub enum LinageValue {
99    /// The digits as written, whose count sizes LINAGE-COUNTER.
100    Integer(String),
101    Data(Ref),
102}
103
104pub use rt::vocab::OpenMode;
105
106#[derive(Clone, Debug, PartialEq, Eq)]
107pub enum Advancing {
108    Lines { before: bool, count: Expr },
109    Page { before: bool },
110    /// A mnemonic-name of SPECIAL-NAMES, with the environment-name it stands for: C01 to C12,
111    /// CSP, S01 to S05 or AFP-5A.
112    Mnemonic { before: bool, name: String, environment: String },
113}
114
115impl Advancing {
116    pub fn before(&self) -> bool {
117        match self {
118            Self::Lines { before, .. } | Self::Page { before } | Self::Mnemonic { before, .. } => *before,
119        }
120    }
121}
122
123#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
124pub enum Usage {
125    #[default]
126    Display,
127    Binary,
128    /// COMP-5: binary, never truncated to the PICTURE.
129    NativeBinary,
130    Packed,
131    Float1,
132    Float2,
133    National,
134    Pointer,
135    Index,
136    ObjectReference,
137    /// FUNCTION-POINTER or PROCEDURE-POINTER.
138    ProgramPointer,
139}
140
141pub use rt::vocab::{SignClause, SignPosition};
142
143#[derive(Clone, Debug, PartialEq, Eq)]
144pub struct DataEntry {
145    pub level: u8,
146    /// None for FILLER or an unnamed entry.
147    pub name: Option<String>,
148    pub picture: Option<String>,
149    /// None when no USAGE is written; the item then inherits its group's.
150    pub usage: Option<Usage>,
151    pub value: Option<Literal>,
152    pub redefines: Option<String>,
153    /// OCCURS: the number of occurrences, or the most of them for OCCURS DEPENDING ON.
154    pub occurs: Option<u32>,
155    /// OCCURS ... DEPENDING ON: the item that holds how many occurrences there are.
156    pub depending_on: Option<Ref>,
157    pub sign: Option<SignClause>,
158    pub justified: bool,
159    pub sync: bool,
160    pub blank_when_zero: bool,
161    /// OCCURS ... INDEXED BY: the index names the table declares.
162    pub indexed_by: Vec<String>,
163    /// OCCURS ... ASCENDING/DESCENDING KEY: each key and whether it ascends, for SEARCH ALL.
164    pub keys: Vec<(bool, Ref)>,
165    /// Level 88: the values that make the condition true.
166    /// Each value, or the low and high ends of a THRU range.
167    pub condition_values: Vec<(Literal, Option<Literal>)>,
168    /// Level 88 WHEN SET TO FALSE: the value SET ... TO FALSE stores.
169    pub false_value: Option<Literal>,
170    /// Level 66 RENAMES: the item renamed, or the first and last of a THRU range.
171    pub renames: Option<(Ref, Option<Ref>)>,
172    /// USAGE OBJECT REFERENCE class-name: the class; None for a universal reference.
173    pub object_class: Option<String>,
174    pub pos: Pos,
175}
176
177pub use rt::vocab::Figurative;
178
179#[derive(Clone, Debug, PartialEq, Eq)]
180pub enum Literal {
181    Alnum(String),
182    Hex(Vec<u8>),
183    National(String),
184    /// As written: optional sign, digits, optional decimal point.
185    Number(String),
186    Figurative(Figurative),
187    All(Box<Literal>),
188}
189
190/// A paragraph, or a section header holding the statements before the section's first paragraph.
191#[derive(Clone, Debug, PartialEq, Eq)]
192pub struct Paragraph {
193    pub name: String,
194    pub statements: Vec<Stmt>,
195    /// The section the paragraph belongs to, or the section's own name for its header.
196    pub section: Option<String>,
197    pub is_section: bool,
198    /// The section's priority-number, 0 when it has none: 50 to 99 is an independent segment.
199    pub priority: u8,
200    pub pos: Pos,
201}
202
203/// A procedure name as written, with the section that qualifies it.
204#[derive(Clone, Debug, PartialEq, Eq)]
205pub struct ProcName {
206    pub name: String,
207    pub section: Option<String>,
208}
209
210/// USE AFTER EXCEPTION/ERROR and USE FOR DEBUGGING sections; USE BEFORE REPORTING ones are the
211/// Report Writer's.
212#[derive(Clone, Debug, Default, PartialEq, Eq)]
213pub struct Declaratives {
214    pub errors: Vec<UseAfterError>,
215    pub debugging: Vec<UseForDebugging>,
216}
217
218/// A USE AFTER STANDARD EXCEPTION/ERROR PROCEDURE section.
219#[derive(Clone, Debug, PartialEq, Eq)]
220pub struct UseAfterError {
221    /// The section's header among the program's paragraphs.
222    pub section: usize,
223    pub global: bool,
224    pub on: ErrorUse,
225    pub pos: Pos,
226}
227
228/// The files an EXCEPTION/ERROR procedure serves: those it names, or those open in one mode.
229#[derive(Clone, Debug, PartialEq, Eq)]
230pub enum ErrorUse {
231    Files(Vec<String>),
232    Mode(OpenMode),
233}
234
235/// A USE FOR DEBUGGING section, which runs before each procedure it names.
236#[derive(Clone, Debug, PartialEq, Eq)]
237pub struct UseForDebugging {
238    pub section: usize,
239    /// Empty for ALL PROCEDURES.
240    pub procedures: Vec<ProcName>,
241    pub pos: Pos,
242}
243
244#[derive(Clone, Copy, Debug, PartialEq, Eq)]
245pub enum ExitKind {
246    Plain,
247    Paragraph,
248    Section,
249    Perform,
250    PerformCycle,
251}
252
253#[derive(Clone, Debug, PartialEq, Eq)]
254pub enum Subject {
255    Bool(bool),
256    Expr(Expr),
257    Cond(Cond),
258}
259
260#[derive(Clone, Debug, PartialEq, Eq)]
261pub enum Object {
262    Any,
263    Bool(bool),
264    Cond(Cond),
265    Value { not: bool, from: Expr, thru: Option<Expr> },
266}
267
268/// One WHEN group: any of its alternatives, each with an object per subject, selects the body.
269#[derive(Clone, Debug, PartialEq, Eq)]
270pub struct When {
271    pub alternatives: Vec<Vec<Object>>,
272    pub body: Vec<Stmt>,
273}
274
275#[derive(Clone, Debug, PartialEq, Eq)]
276pub struct Ref {
277    pub name: String,
278    pub qualifiers: Vec<String>,
279    pub subscripts: Vec<Expr>,
280    pub refmod: Option<RefMod>,
281    pub pos: Pos,
282}
283
284#[derive(Clone, Debug, PartialEq, Eq)]
285pub struct RefMod {
286    pub start: Box<Expr>,
287    pub length: Option<Box<Expr>>,
288}
289
290#[derive(Clone, Debug, PartialEq, Eq)]
291pub struct FunctionCall {
292    pub name: String,
293    pub args: Vec<Expr>,
294    /// A keyword argument, as in FUNCTION TRIM(X LEADING).
295    pub modifier: Option<String>,
296    pub refmod: Option<RefMod>,
297    pub pos: Pos,
298}
299
300#[derive(Clone, Debug, PartialEq, Eq)]
301pub enum Operand {
302    Ref(Ref),
303    Literal(Literal),
304    Function(FunctionCall),
305    LengthOf(Ref),
306    AddressOf(Ref),
307}
308
309pub use rt::vocab::{AcceptFrom, BinOp, RelOp};
310
311#[derive(Clone, Debug, PartialEq, Eq)]
312pub enum Expr {
313    Operand(Operand),
314    Neg(Box<Expr>),
315    Bin(Box<Expr>, BinOp, Box<Expr>),
316}
317
318#[derive(Clone, Copy, Debug, PartialEq, Eq)]
319pub enum Class {
320    Numeric,
321    Alphabetic,
322    Positive,
323    Negative,
324    Zero,
325}
326
327#[derive(Clone, Debug, PartialEq, Eq)]
328pub enum Cond {
329    Rel(Expr, RelOp, Expr),
330    Class(Expr, Class),
331    Name(Ref),
332    /// After AND or OR, a bare name that is either a condition-name or the object of an
333    /// abbreviated relation; which one depends on what the name resolves to.
334    NameOrRel { subject: Expr, op: RelOp, name: Ref },
335    Not(Box<Cond>),
336    And(Box<Cond>, Box<Cond>),
337    Or(Box<Cond>, Box<Cond>),
338}
339
340#[derive(Clone, Debug, PartialEq, Eq)]
341pub struct Target {
342    pub r: Ref,
343    pub rounded: bool,
344}
345
346#[derive(Clone, Debug, PartialEq, Eq)]
347pub struct Varying {
348    pub var: Ref,
349    pub from: Expr,
350    pub by: Expr,
351    pub until: Cond,
352}
353
354#[derive(Clone, Debug, PartialEq, Eq)]
355pub enum Loop {
356    Once,
357    Times(Expr),
358    Until { cond: Cond, test_after: bool },
359    /// VARYING, and each AFTER phrase, outermost first.
360    Varying { varying: Box<Varying>, after: Vec<Varying>, test_after: bool },
361}
362
363#[derive(Clone, Debug, PartialEq, Eq)]
364pub enum Stmt {
365    Move { from: Operand, to: Vec<Ref>, pos: Pos },
366    Compute { targets: Vec<Target>, expr: Expr, size_error: Option<SizeError>, pos: Pos },
367    /// ADD, SUBTRACT, MULTIPLY and DIVIDE, reduced to their arithmetic.
368    Arith(Box<Arith>),
369    If { cond: Cond, then: Vec<Stmt>, otherwise: Vec<Stmt>, pos: Pos },
370    PerformInline { body: Vec<Stmt>, repeat: Loop, pos: Pos },
371    PerformProc { from: ProcName, thru: Option<ProcName>, repeat: Loop, pos: Pos },
372    Evaluate { subjects: Vec<Subject>, whens: Vec<When>, other: Vec<Stmt>, pos: Pos },
373    Display { items: Vec<Operand>, no_advancing: bool, pos: Pos },
374    Open { files: Vec<(OpenMode, String)>, pos: Pos },
375    Close { files: Vec<String>, pos: Pos },
376    Read(Box<ReadStmt>),
377    Write { record: Ref, from: Option<Operand>, advancing: Option<Advancing>, invalid: Handlers, end_of_page: Handlers, pos: Pos },
378    Rewrite { record: Ref, from: Option<Operand>, invalid: Handlers, pos: Pos },
379    Delete { file: String, invalid: Handlers, pos: Pos },
380    Start { file: String, key: Option<(RelOp, Ref)>, invalid: Handlers, pos: Pos },
381    Initialize { targets: Vec<Ref>, pos: Pos },
382    /// GO TO; with no target, the altered GO TO that only an ALTER gives one.
383    GoTo { target: Option<ProcName>, pos: Pos },
384    /// GO TO ... DEPENDING ON: the procedure the item's value numbers, or on when none does.
385    GoToDepending { targets: Vec<ProcName>, on: Ref, pos: Pos },
386    /// ALTER: each paragraph whose GO TO is to go instead to the procedure paired with it.
387    Alter { pairs: Vec<(ProcName, ProcName)>, pos: Pos },
388    /// ENTRY: where a CALL of `name` begins, and the LINKAGE items its USING list addresses.
389    Entry { name: String, using: Vec<Param>, pos: Pos },
390    Goback { pos: Pos },
391    /// EXIT PROGRAM: returns from a called program; in the first program it does nothing.
392    ExitProgram { pos: Pos },
393    Call(Box<Call>),
394    Cancel { targets: Vec<Operand>, pos: Pos },
395    Set { set: SetStmt, pos: Pos },
396    Accept { target: Ref, from: AcceptFrom, pos: Pos },
397    String(Box<StringStmt>),
398    Unstring(Box<Unstring>),
399    Inspect(Box<Inspect>),
400    Search(Box<Search>),
401    /// NEXT SENTENCE: control passes to the statement after the next separator period.
402    NextSentence,
403    /// A separator period in the PROCEDURE DIVISION: where NEXT SENTENCE resumes.
404    SentenceEnd,
405    Exec(Box<ExecBlock>),
406    Report(Box<crate::report::ReportStmt>),
407    Invoke(Box<Invoke>),
408    ExitMethod { pos: Pos },
409    Sorting(Box<Sorting>),
410    StopRun { pos: Pos },
411    Continue,
412    Exit { kind: ExitKind, pos: Pos },
413}
414
415#[derive(Clone, Debug, PartialEq, Eq)]
416pub struct SizeError {
417    pub on: Vec<Stmt>,
418    pub not_on: Vec<Stmt>,
419}
420
421#[derive(Clone, Copy, Debug, PartialEq, Eq)]
422pub enum ArithVerb {
423    Add,
424    Subtract,
425    Multiply,
426    Divide,
427}
428
429/// One arithmetic statement: `targets` each receive `expr`, which is written in terms of the
430/// statement's operands and, for the forms without GIVING, the target itself (`Operand::Ref` of
431/// the target, placed by the parser).
432#[derive(Clone, Debug, PartialEq, Eq)]
433pub struct Arith {
434    pub verb: ArithVerb,
435    pub computations: Vec<(Target, Expr)>,
436    pub remainder: Option<(Target, Expr, Expr)>,
437    pub size_error: Option<SizeError>,
438    pub pos: Pos,
439}
440
441#[derive(Clone, Copy, Debug, PartialEq, Eq)]
442pub enum ArgMode {
443    Reference,
444    Content,
445    Value,
446}
447
448/// One CALL argument; `value` is None for OMITTED.
449#[derive(Clone, Debug, PartialEq, Eq)]
450pub struct Arg {
451    pub mode: ArgMode,
452    pub value: Option<Operand>,
453}
454
455#[derive(Clone, Debug, PartialEq, Eq)]
456pub struct Call {
457    pub target: Operand,
458    pub using: Vec<Arg>,
459    pub returning: Option<Ref>,
460    pub on_exception: Option<Vec<Stmt>>,
461    pub not_on_exception: Option<Vec<Stmt>>,
462    pub pos: Pos,
463}
464
465#[derive(Clone, Debug, PartialEq, Eq)]
466pub enum SetStmt {
467    ConditionTrue(Vec<Ref>),
468    /// SET condition-names TO FALSE: each conditional variable gets its WHEN SET TO FALSE value.
469    ConditionFalse(Vec<Ref>),
470    /// SET targets TO value: an index or integer to a number, a pointer to ADDRESS OF, NULL or another pointer.
471    To { targets: Vec<Ref>, value: Operand },
472    /// SET ADDRESS OF targets TO pointer.
473    AddressOf { targets: Vec<Ref>, value: Operand },
474    UpDown { targets: Vec<Ref>, down: bool, by: Expr },
475}
476
477#[derive(Clone, Debug, PartialEq, Eq)]
478pub enum Delimiter {
479    Size,
480    By(Operand),
481}
482
483#[derive(Clone, Debug, PartialEq, Eq)]
484pub struct StringStmt {
485    pub sources: Vec<(Operand, Delimiter)>,
486    pub into: Ref,
487    pub pointer: Option<Ref>,
488    pub on_overflow: Option<Vec<Stmt>>,
489    pub not_on_overflow: Option<Vec<Stmt>>,
490    pub pos: Pos,
491}
492
493#[derive(Clone, Debug, PartialEq, Eq)]
494pub struct UnstringInto {
495    pub target: Ref,
496    pub delimiter_in: Option<Ref>,
497    pub count_in: Option<Ref>,
498}
499
500#[derive(Clone, Debug, PartialEq, Eq)]
501pub struct Unstring {
502    pub source: Ref,
503    /// Each delimiter, and whether ALL makes a run of it one delimiter.
504    pub delimiters: Vec<(bool, Operand)>,
505    pub into: Vec<UnstringInto>,
506    pub pointer: Option<Ref>,
507    pub tallying: Option<Ref>,
508    pub on_overflow: Option<Vec<Stmt>>,
509    pub not_on_overflow: Option<Vec<Stmt>>,
510    pub pos: Pos,
511}
512
513/// BEFORE or AFTER INITIAL value: where in the inspected item a phrase applies.
514#[derive(Clone, Debug, PartialEq, Eq)]
515pub struct Bound {
516    pub after: bool,
517    pub value: Operand,
518}
519
520pub use rt::vocab::InspectMode;
521
522/// One TALLYING or REPLACING phrase. `pattern` is None for CHARACTERS; `by` is None for TALLYING.
523#[derive(Clone, Debug, PartialEq, Eq)]
524pub struct InspectPhrase {
525    pub mode: InspectMode,
526    pub pattern: Option<Operand>,
527    pub by: Option<Operand>,
528    pub counter: Option<Ref>,
529    pub bounds: Vec<Bound>,
530}
531
532#[derive(Clone, Debug, PartialEq, Eq)]
533pub struct Inspect {
534    pub target: Ref,
535    pub tallying: Vec<InspectPhrase>,
536    pub replacing: Vec<InspectPhrase>,
537    pub converting: Option<(Operand, Operand, Vec<Bound>)>,
538    pub pos: Pos,
539}
540
541#[derive(Clone, Debug, PartialEq, Eq)]
542pub struct Search {
543    pub table: Ref,
544    pub all: bool,
545    pub varying: Option<Ref>,
546    pub at_end: Option<Vec<Stmt>>,
547    pub whens: Vec<(Cond, Vec<Stmt>)>,
548    pub pos: Pos,
549}
550
551#[derive(Clone, Copy, Debug, PartialEq, Eq)]
552pub enum ExecKind {
553    Sql,
554    Cics,
555    Dli,
556    Other,
557}
558
559#[derive(Clone, Debug, PartialEq, Eq)]
560pub enum ExecArg {
561    Operand(Operand),
562    /// An argument that is not data: a paragraph for HANDLE CONDITION, or text that did not parse.
563    Text(String),
564}
565
566/// An EXEC ... END-EXEC block, read but not translated.
567#[derive(Clone, Debug, PartialEq, Eq)]
568pub struct ExecBlock {
569    pub kind: ExecKind,
570    /// The command: SELECT, INCLUDE, DECLARE CURSOR, LINK, SEND MAP and so on.
571    pub command: String,
572    /// CICS options, each with its argument.
573    pub options: Vec<(String, Option<ExecArg>)>,
574    /// SQL host variables and indicator variables.
575    pub host_variables: Vec<Ref>,
576    /// The typed SQL statement, for EXEC SQL.
577    pub sql: Option<crate::sql::Sql>,
578    pub text: String,
579    pub pos: Pos,
580}
581
582impl ExecBlock {
583    /// Whether the block only declares, so a precompiler turns it into data or nothing.
584    pub fn declarative(&self) -> bool {
585        self.kind == ExecKind::Sql
586            && matches!(self.command.as_str(), "INCLUDE" | "BEGIN DECLARE SECTION" | "END DECLARE SECTION" | "WHENEVER" | "DECLARE CURSOR" | "DECLARE TABLE" | "DECLARE STATEMENT")
587    }
588}
589
590/// The statements of an ON phrase (AT END, INVALID KEY, ...) and of its NOT ON phrase.
591#[derive(Clone, Debug, Default, PartialEq, Eq)]
592pub struct Handlers {
593    pub on: Option<Vec<Stmt>>,
594    pub not_on: Option<Vec<Stmt>>,
595}
596
597#[derive(Clone, Debug, PartialEq, Eq)]
598pub struct ReadStmt {
599    pub file: String,
600    /// READ NEXT or PREVIOUS: the next record by the key of reference, even under dynamic access.
601    pub next: bool,
602    pub previous: bool,
603    pub into: Option<Ref>,
604    /// READ ... KEY IS: the key of reference for a random read.
605    pub key: Option<Ref>,
606    pub at_end: Handlers,
607    pub invalid: Handlers,
608    pub pos: Pos,
609}
610
611/// What an ALPHABET clause relates its alphabet-name to.
612#[derive(Clone, Debug, PartialEq, Eq)]
613pub enum Alphabet {
614    Ebcdic,
615    Native,
616    Standard1,
617    Standard2,
618    /// A collating sequence of the program's own, lowest position first.
619    Literal(Vec<AlphabetEntry>),
620}
621
622impl Alphabet {
623    pub fn name(&self) -> &'static str {
624        match self {
625            Self::Ebcdic => "EBCDIC",
626            Self::Native => "NATIVE",
627            Self::Standard1 => "STANDARD-1",
628            Self::Standard2 => "STANDARD-2",
629            Self::Literal(_) => "literal",
630        }
631    }
632}
633
634/// One literal of an ALPHABET clause: its characters in successive positions, a THROUGH range of
635/// characters in successive positions, or characters that ALSO share one position.
636#[derive(Clone, Debug, PartialEq, Eq)]
637pub enum AlphabetEntry {
638    Literal(Literal),
639    Through(Literal, Literal),
640    Also(Vec<Literal>),
641}
642
643/// ENVIRONMENT DIVISION clauses beyond SELECT that the program's meaning depends on.
644#[derive(Clone, Debug, Default, PartialEq, Eq)]
645pub struct Environment {
646    /// SPECIAL-NAMES ALPHABET: each alphabet-name and what it is.
647    pub alphabets: Vec<(String, Alphabet)>,
648    /// OBJECT-COMPUTER PROGRAM COLLATING SEQUENCE.
649    pub collating_sequence: Option<String>,
650    /// I-O-CONTROL SAME RECORD AREA and SAME AREA clauses, each with the files it names.
651    pub same_record_areas: Vec<Vec<String>>,
652    pub same_areas: Vec<Vec<String>>,
653    /// SPECIAL-NAMES entries naming a printer channel, space suppression, a punch pocket or AFP:
654    /// each mnemonic-name and its environment-name.
655    pub mnemonics: Vec<(String, String)>,
656    /// SOURCE-COMPUTER ... WITH DEBUGGING MODE: debugging lines and USE FOR DEBUGGING sections are
657    /// compiled rather than read as comments.
658    pub debugging_mode: bool,
659    /// SPECIAL-NAMES DECIMAL-POINT IS COMMA: the comma and the period exchange roles in PICTURE
660    /// character-strings, numeric literals and the arguments of NUMVAL and NUMVAL-C.
661    pub decimal_point_comma: bool,
662}
663
664#[derive(Clone, Debug, PartialEq, Eq)]
665pub enum Sorting {
666    Sort(SortStmt),
667    Release { record: Ref, from: Option<Operand>, pos: Pos },
668    Return { file: String, into: Option<Ref>, at_end: Handlers, pos: Pos },
669}
670
671/// SORT or MERGE of an SD file, or SORT of a table (no input or output then).
672#[derive(Clone, Debug, PartialEq, Eq)]
673pub struct SortStmt {
674    pub merge: bool,
675    /// The SD file, or the table.
676    pub subject: Ref,
677    /// Each key and whether it ascends, most significant first.
678    pub keys: Vec<(bool, Ref)>,
679    pub duplicates: bool,
680    pub collating: Option<String>,
681    pub input: Option<SortIo>,
682    pub output: Option<SortIo>,
683    pub pos: Pos,
684}
685
686/// USING or GIVING files, or an input or output procedure.
687#[derive(Clone, Debug, PartialEq, Eq)]
688pub enum SortIo {
689    Files(Vec<String>),
690    Procedure { from: ProcName, thru: Option<ProcName> },
691}
692