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