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    /// Where its PROGRAM-ID names it.
10    pub pos: Pos,
11    /// Options from CBL and PROCESS cards, in the order written.
12    pub options: Vec<String>,
13    /// PROGRAM-ID ... IS INITIAL, or once compiled the INITIAL option: WORKING-STORAGE starts
14    /// afresh on every CALL.
15    pub initial: bool,
16    pub recursive: bool,
17    /// PROGRAM-ID ... IS COMMON, for a program another contains.
18    pub common: bool,
19    pub working_storage: Vec<DataEntry>,
20    /// LOCAL-STORAGE: fresh for every activation of the program.
21    pub local_storage: Vec<DataEntry>,
22    pub linkage: Vec<DataEntry>,
23    /// The SCREEN SECTION's entries, as written.
24    pub screens: Vec<ScreenEntry>,
25    /// PROCEDURE DIVISION USING: the LINKAGE items the caller's arguments address.
26    pub using: Vec<Param>,
27    pub returning: Option<String>,
28    pub paragraphs: Vec<Paragraph>,
29    /// Files declared by SELECT and described by FD, with their record descriptions.
30    pub files: Vec<FileDecl>,
31    /// The program's source file, then each COPY member, as positions index them.
32    pub sources: Vec<String>,
33    /// EXEC blocks in the DATA DIVISION: SQL declarations, cursors and DECLARE SECTION markers.
34    pub exec_declarations: Vec<ExecBlock>,
35    /// The REPORT SECTION, and the DECLARATIVES that serve it.
36    pub report_writer: crate::report::ReportWriter,
37    /// The DECLARATIVES' USE AFTER EXCEPTION/ERROR and USE FOR DEBUGGING procedures.
38    pub declaratives: Declaratives,
39    /// The REPOSITORY's classes, and for a class definition or a method what it is.
40    pub oo: Option<Box<Oo>>,
41    pub environment: Environment,
42    /// The PROGRAM-IDs of the programs it directly contains.
43    pub nested: Vec<String>,
44    /// Special registers the PROCEDURE DIVISION names and no entry declares, which the compiler
45    /// declares: WHEN-COMPILED.
46    pub registers: Vec<String>,
47    /// The contained programs of its compilation a CALL from it reaches (Language Reference,
48    /// Conventions for program-names): those it directly contains, and each COMMON one that a
49    /// program containing it directly contains, but itself and those that contain it.
50    pub callable: Vec<String>,
51    /// The other contained programs of its compilation, and those containing it, which a CALL from
52    /// it does not reach.
53    pub hidden: Vec<String>,
54    /// For a separately compiled program, each name two of its programs share, where the second's
55    /// PROGRAM-ID is.
56    pub duplicates: Vec<(String, Pos)>,
57    /// The names a static CALL from it finds in its compilation: its source's separately compiled
58    /// programs and their ENTRY names, and in a bundle the other sources' programs.
59    pub linked: Vec<String>,
60    /// The programs that contain it, innermost first, with the names each declares GLOBAL.
61    pub containers: Vec<Container>,
62    /// The messages reading its source gave that did not stop the parse, in the order found.
63    pub messages: Vec<crate::Error>,
64    /// FUNCTION-ID in place of PROGRAM-ID: a user-defined function, or a prototype of one.
65    pub function: Option<Function>,
66    /// The user-defined functions it may invoke: those defined or prototyped before it in its
67    /// source, and a function itself.
68    pub prototypes: Vec<Prototype>,
69    /// The user-defined functions its REPOSITORY paragraph, or its outermost program's, names. One
70    /// with an intrinsic function's name is invoked by that name only where it is named here.
71    pub repository_functions: Vec<String>,
72}
73
74impl Program {
75    /// Whether FUNCTION `name` invokes an intrinsic function rather than a user-defined one.
76    pub fn intrinsic(&self, name: &str) -> bool {
77        is_intrinsic_name(name) && !self.repository_functions.iter().any(|f| f == name)
78    }
79}
80
81/// Whether `name` is an intrinsic function's name.
82pub fn is_intrinsic_name(name: &str) -> bool {
83    rt::intrinsic::FIRST.contains(&name) || rt::intrinsic::FUNCTIONS.contains(&name)
84}
85
86impl Program {
87    /// The name a CALL or a function invocation loads it by: a function's external name.
88    pub fn load_name(&self) -> &str {
89        self.function.as_ref().map_or(&self.id, |f| &f.external)
90    }
91
92    pub fn is_prototype(&self) -> bool {
93        self.function.as_ref().is_some_and(|f| f.prototype)
94    }
95}
96
97#[derive(Clone, Debug, PartialEq, Eq)]
98pub struct Function {
99    /// AS literal-1, else the function-name.
100    pub external: String,
101    /// IS PROTOTYPE: a description for invocations to be checked against, with no code.
102    pub prototype: bool,
103    pub pos: Pos,
104}
105
106/// A user-defined function as its definition or prototype describes it to an invocation.
107#[derive(Clone, Debug, PartialEq, Eq)]
108pub struct Prototype {
109    pub name: String,
110    pub external: String,
111    pub using: Vec<Param>,
112    pub returning: Option<String>,
113    pub linkage: Vec<DataEntry>,
114    /// The PICTURE notation of its definition: DECIMAL-POINT IS COMMA and the currency signs.
115    pub environment: Environment,
116    pub pos: Pos,
117}
118
119#[derive(Clone, Debug, PartialEq, Eq)]
120pub struct Param {
121    pub by_value: bool,
122    pub name: String,
123}
124
125#[derive(Clone, Copy, Debug, PartialEq, Eq)]
126pub enum Organization {
127    Sequential,
128    LineSequential,
129    Indexed,
130    Relative,
131}
132
133#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
134pub enum Access {
135    #[default]
136    Sequential,
137    Random,
138    Dynamic,
139}
140
141#[derive(Clone, Debug, PartialEq, Eq)]
142pub struct FileDecl {
143    pub name: String,
144    /// The DD name ASSIGN gives, with any `UT-S-` style prefix removed.
145    pub assign: String,
146    /// ASSIGN's target where it can be a data item holding the file's name at each OPEN. The
147    /// compile keeps it only where it is one, under `--compliance extended`.
148    pub assign_item: Option<AssignItem>,
149    pub organization: Organization,
150    pub access: Access,
151    pub record_key: Option<Ref>,
152    /// ALTERNATE RECORD KEY items, and whether each allows duplicates.
153    pub alternate_keys: Vec<(Ref, bool)>,
154    /// Micro Focus's split keys under `--compliance extended`, KEY IS name = item ...: the name a
155    /// record or alternate key above gives, and the items it joins, in order.
156    pub split_keys: Vec<(String, Vec<Ref>)>,
157    pub relative_key: Option<Ref>,
158    pub optional: bool,
159    pub status: Option<Ref>,
160    /// FILE STATUS's second data-name, for a VSAM file: the return, function and feedback codes.
161    pub vsam_status: Option<Ref>,
162    /// PASSWORD IS items, checked and of no effect, as files here have no passwords.
163    pub passwords: Vec<Ref>,
164    /// RECORDING MODE: F, V, U or S.
165    pub recording: Option<char>,
166    pub record_min: Option<u32>,
167    pub record_max: Option<u32>,
168    /// RECORD IS VARYING: `record_min` and `record_max` are its FROM and TO, each None when not
169    /// written (Language Reference SC27-8713-03, p. 187).
170    pub record_varying: bool,
171    /// RECORD IS VARYING ... DEPENDING ON: the item holding each record's length.
172    pub record_depending: Option<Ref>,
173    /// LABEL RECORD IS data-name: the names, which Enterprise COBOL resolves though it reads the
174    /// clause as comments.
175    pub label_records: Vec<Ref>,
176    pub records: Vec<DataEntry>,
177    /// FD ... REPORT IS: the reports written to the file.
178    pub reports: Vec<String>,
179    /// FD ... LINAGE: the logical page. An SD's is read and dropped, as IBM ignores it.
180    pub linage: Option<Linage>,
181    /// Described by SD: a sort or merge file, which needs no data set.
182    pub sort: bool,
183    pub external: bool,
184    pub global: bool,
185    /// For a GLOBAL file of a program containing this one, that program's PROGRAM-ID.
186    pub declared_in: Option<String>,
187    pub pos: Pos,
188}
189
190impl FileDecl {
191    /// The items split key `name` joins, where `name` is one of the file's split keys.
192    pub fn split_key(&self, name: &str) -> Option<&[Ref]> {
193        self.split_keys.iter().find(|(key, _)| key == name).map(|(_, pieces)| pieces.as_slice())
194    }
195}
196
197/// ASSIGN TO a name, or ASSIGN TO DYNAMIC or USING a data-name: Micro Focus and GnuCOBOL take a
198/// name that is a data item's, and the other two forms always, as the item holding the file's
199/// name (Enterprise COBOL's assignment-name is never a data item, Language Reference
200/// SC27-8713-03, ASSIGN clause).
201#[derive(Clone, Debug, PartialEq, Eq)]
202pub struct AssignItem {
203    pub reference: Ref,
204    /// DYNAMIC or USING was written.
205    pub explicit: bool,
206    /// Micro Focus's ASSIGN TO DISK name under `--compliance extended`: the item is declared for
207    /// the program where it declares none.
208    pub declared_if_missing: bool,
209}
210
211/// A program containing another, as the contained program sees it: its PROGRAM-ID, and the 01
212/// records and files it declares GLOBAL, each with what is subordinate to it.
213#[derive(Clone, Debug, Default, PartialEq, Eq)]
214pub struct Container {
215    pub id: String,
216    pub working_storage: Vec<DataEntry>,
217    pub local_storage: Vec<DataEntry>,
218    pub linkage: Vec<DataEntry>,
219    pub files: Vec<FileDecl>,
220}
221
222/// LINAGE IS lines [WITH FOOTING AT footing] [LINES AT TOP top] [LINES AT BOTTOM bottom].
223#[derive(Clone, Debug, PartialEq, Eq)]
224pub struct Linage {
225    pub lines: LinageValue,
226    pub footing: Option<LinageValue>,
227    pub top: Option<LinageValue>,
228    pub bottom: Option<LinageValue>,
229}
230
231#[derive(Clone, Debug, PartialEq, Eq)]
232pub enum LinageValue {
233    /// The digits as written, whose count sizes LINAGE-COUNTER.
234    Integer(String),
235    Data(Ref),
236}
237
238pub use rt::vocab::{Closing, OpenMode};
239
240#[derive(Clone, Debug, PartialEq, Eq)]
241pub enum Advancing {
242    Lines { before: bool, count: Expr },
243    Page { before: bool },
244    /// A mnemonic-name of SPECIAL-NAMES, with the environment-name it stands for: C01 to C12,
245    /// CSP, S01 to S05 or AFP-5A.
246    Mnemonic { before: bool, name: String, environment: String },
247}
248
249impl Advancing {
250    pub fn before(&self) -> bool {
251        match self {
252            Self::Lines { before, .. } | Self::Page { before } | Self::Mnemonic { before, .. } => *before,
253        }
254    }
255}
256
257#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
258pub enum Usage {
259    #[default]
260    Display,
261    Binary,
262    /// COMP-5: binary, never truncated to the PICTURE.
263    NativeBinary,
264    /// GnuCOBOL's and Micro Focus's BINARY-CHAR [SIGNED|UNSIGNED]: one byte of binary, no PICTURE.
265    BinaryChar { signed: bool },
266    /// Micro Focus's COMP-X: binary in the fewest bytes that hold the PICTURE's digits, or n bytes
267    /// for PIC X(n).
268    CompX,
269    Packed,
270    Float1,
271    Float2,
272    National,
273    /// DISPLAY-1: DBCS characters, two bytes each.
274    Dbcs,
275    Pointer,
276    Index,
277    ObjectReference,
278    /// FUNCTION-POINTER or PROCEDURE-POINTER.
279    ProgramPointer,
280}
281
282pub use rt::vocab::{SignClause, SignPosition};
283
284#[derive(Clone, Debug, PartialEq, Eq)]
285pub struct DataEntry {
286    pub level: u8,
287    /// None for FILLER or an unnamed entry.
288    pub name: Option<String>,
289    /// The name as the source spells it, where that is not all capitals: JSON and XML GENERATE
290    /// keep it.
291    pub spelled: Option<String>,
292    pub picture: Option<String>,
293    /// None when no USAGE is written; the item then inherits its group's.
294    pub usage: Option<Usage>,
295    pub value: Option<Literal>,
296    pub redefines: Option<String>,
297    /// OCCURS: the number of occurrences, or the most of them for OCCURS DEPENDING ON.
298    pub occurs: Option<u32>,
299    /// OCCURS ... DEPENDING ON: the fewest occurrences, 1 when no integer-1 TO is written
300    /// (Language Reference SC27-8713-03, p. 204).
301    pub occurs_min: Option<u32>,
302    /// OCCURS ... DEPENDING ON: the item that holds how many occurrences there are.
303    pub depending_on: Option<Ref>,
304    pub sign: Option<SignClause>,
305    pub justified: bool,
306    pub sync: bool,
307    pub blank_when_zero: bool,
308    /// OCCURS ... INDEXED BY: the index names the table declares.
309    pub indexed_by: Vec<String>,
310    /// OCCURS ... ASCENDING/DESCENDING KEY: each key and whether it ascends, for SEARCH ALL.
311    pub keys: Vec<(bool, Ref)>,
312    /// Level 88: the values that make the condition true.
313    /// Each value, or the low and high ends of a THRU range.
314    pub condition_values: Vec<(Literal, Option<Literal>)>,
315    /// Level 88 WHEN SET TO FALSE: the value SET ... TO FALSE stores.
316    pub false_value: Option<Literal>,
317    /// Level 66 RENAMES: the item renamed, or the first and last of a THRU range.
318    pub renames: Option<(Ref, Option<Ref>)>,
319    /// USAGE OBJECT REFERENCE class-name: the class; None for a universal reference.
320    pub object_class: Option<String>,
321    /// EXTERNAL, written on the entry or attained from its FD.
322    pub external: bool,
323    /// GLOBAL, written on the entry or attained from its FD.
324    pub global: bool,
325    /// ANY LENGTH, GnuCOBOL's and Micro Focus's parameter as long as its argument, read under
326    /// `--compliance extended`.
327    pub any_length: bool,
328    /// BASED, GnuCOBOL's and Micro Focus's item with no storage until SET ADDRESS OF gives it some,
329    /// read under `--compliance extended`.
330    pub based: bool,
331    pub pos: Pos,
332}
333
334pub use rt::vocab::Figurative;
335
336#[derive(Clone, Debug, PartialEq, Eq)]
337pub enum Literal {
338    Alnum(String),
339    Hex(Vec<u8>),
340    National(String),
341    /// G'...', or N'...' under NSYMBOL(DBCS): characters the code page's DBCS part encodes.
342    Dbcs(String),
343    /// As written: optional sign, digits, optional decimal point.
344    Number(String),
345    Figurative(Figurative),
346    All(Box<Literal>),
347}
348
349/// A paragraph, or a section header holding the statements before the section's first paragraph.
350#[derive(Clone, Debug, PartialEq, Eq)]
351pub struct Paragraph {
352    pub name: String,
353    pub statements: Vec<Stmt>,
354    /// The section the paragraph belongs to, or the section's own name for its header.
355    pub section: Option<String>,
356    pub is_section: bool,
357    /// The section's priority-number, 0 when it has none: 50 to 99 is an independent segment.
358    pub priority: u8,
359    pub pos: Pos,
360}
361
362/// A procedure name as written, with the section that qualifies it.
363#[derive(Clone, Debug, PartialEq, Eq)]
364pub struct ProcName {
365    pub name: String,
366    pub section: Option<String>,
367}
368
369/// USE AFTER EXCEPTION/ERROR and USE FOR DEBUGGING sections; USE BEFORE REPORTING ones are the
370/// Report Writer's.
371#[derive(Clone, Debug, Default, PartialEq, Eq)]
372pub struct Declaratives {
373    pub errors: Vec<UseAfterError>,
374    pub debugging: Vec<UseForDebugging>,
375}
376
377/// A USE AFTER STANDARD EXCEPTION/ERROR PROCEDURE section.
378#[derive(Clone, Debug, PartialEq, Eq)]
379pub struct UseAfterError {
380    /// The section's header among the program's paragraphs.
381    pub section: usize,
382    pub global: bool,
383    pub on: ErrorUse,
384    pub pos: Pos,
385}
386
387/// The files an EXCEPTION/ERROR procedure serves: those it names, or those open in one mode.
388#[derive(Clone, Debug, PartialEq, Eq)]
389pub enum ErrorUse {
390    Files(Vec<String>),
391    Mode(OpenMode),
392}
393
394/// A USE FOR DEBUGGING section, which runs before each procedure it names.
395#[derive(Clone, Debug, PartialEq, Eq)]
396pub struct UseForDebugging {
397    pub section: usize,
398    /// Empty for ALL PROCEDURES.
399    pub procedures: Vec<ProcName>,
400    pub pos: Pos,
401}
402
403#[derive(Clone, Copy, Debug, PartialEq, Eq)]
404pub enum ExitKind {
405    Plain,
406    Paragraph,
407    Section,
408    Perform,
409    PerformCycle,
410}
411
412#[derive(Clone, Debug, PartialEq, Eq)]
413pub enum Subject {
414    Bool(bool),
415    Expr(Expr),
416    Cond(Cond),
417}
418
419#[derive(Clone, Debug, PartialEq, Eq)]
420pub enum Object {
421    Any,
422    Bool(bool),
423    Cond(Cond),
424    Value { not: bool, from: Expr, thru: Option<Expr> },
425}
426
427/// One WHEN group: any of its alternatives, each with an object per subject, selects the body.
428#[derive(Clone, Debug, PartialEq, Eq)]
429pub struct When {
430    pub alternatives: Vec<Vec<Object>>,
431    pub body: Vec<Stmt>,
432}
433
434#[derive(Clone, Debug, PartialEq, Eq)]
435pub struct Ref {
436    pub name: String,
437    pub qualifiers: Vec<String>,
438    pub subscripts: Vec<Expr>,
439    pub refmod: Option<RefMod>,
440    pub pos: Pos,
441}
442
443#[derive(Clone, Debug, PartialEq, Eq)]
444pub struct RefMod {
445    pub start: Box<Expr>,
446    pub length: Option<Box<Expr>>,
447}
448
449#[derive(Clone, Debug, PartialEq, Eq)]
450pub struct FunctionCall {
451    pub name: String,
452    pub args: Vec<Expr>,
453    /// A keyword argument, as in FUNCTION TRIM(X LEADING).
454    pub modifier: Option<String>,
455    pub refmod: Option<RefMod>,
456    /// Each argument written as a table with ALL subscripts, as in FUNCTION SUM(T(ALL)): its index
457    /// and the positions of those subscripts, where its reference holds 1.
458    pub all_subscripts: Vec<(usize, Vec<usize>)>,
459    pub pos: Pos,
460}
461
462#[derive(Clone, Debug, PartialEq, Eq)]
463pub enum Operand {
464    Ref(Ref),
465    Literal(Literal),
466    Function(FunctionCall),
467    LengthOf(Ref),
468    AddressOf(Ref),
469}
470
471pub use rt::vocab::{AcceptFrom, BinOp, RelOp};
472
473#[derive(Clone, Debug, PartialEq, Eq)]
474pub enum Expr {
475    Operand(Operand),
476    Neg(Box<Expr>),
477    Bin(Box<Expr>, BinOp, Box<Expr>),
478}
479
480#[derive(Clone, Debug, PartialEq, Eq)]
481pub enum Class {
482    Numeric,
483    Alphabetic,
484    AlphabeticLower,
485    AlphabeticUpper,
486    /// Every two bytes a DBCS character, X'41' to X'FE' each, or the DBCS space.
487    Dbcs,
488    /// Every two bytes a DBCS character with a first byte X'41' to X'7E', or the DBCS space.
489    Kanji,
490    Positive,
491    Negative,
492    Zero,
493    /// A class-name of the SPECIAL-NAMES CLASS clause.
494    Named(String),
495}
496
497#[derive(Clone, Debug, PartialEq, Eq)]
498pub enum Cond {
499    Rel(Expr, RelOp, Expr),
500    Class(Expr, Class),
501    Name(Ref),
502    /// After AND or OR, a bare name that is either a condition-name or the object of an
503    /// abbreviated relation; which one depends on what the name resolves to. `negated` is a NOT
504    /// the relational operator carries, as in NOT =.
505    NameOrRel { subject: Expr, op: RelOp, negated: bool, name: Ref },
506    Not(Box<Cond>),
507    And(Box<Cond>, Box<Cond>),
508    Or(Box<Cond>, Box<Cond>),
509}
510
511#[derive(Clone, Debug, PartialEq, Eq)]
512pub struct Target {
513    pub r: Ref,
514    pub rounded: bool,
515}
516
517#[derive(Clone, Debug, PartialEq, Eq)]
518pub struct Varying {
519    pub var: Ref,
520    pub from: Expr,
521    pub by: Expr,
522    pub until: Cond,
523}
524
525#[derive(Clone, Debug, PartialEq, Eq)]
526pub enum Loop {
527    Once,
528    Times(Expr),
529    Until { cond: Cond, test_after: bool },
530    /// Micro Focus's and GnuCOBOL's FOREVER under `--compliance extended`: until EXIT PERFORM, GO
531    /// TO, GOBACK or STOP RUN leaves it.
532    Forever,
533    /// VARYING, and each AFTER phrase, outermost first.
534    Varying { varying: Box<Varying>, after: Vec<Varying>, test_after: bool },
535}
536
537#[derive(Clone, Debug, PartialEq, Eq)]
538pub enum Stmt {
539    Move { from: Operand, to: Vec<Ref>, pos: Pos },
540    Compute { targets: Vec<Target>, expr: Expr, size_error: Option<SizeError>, pos: Pos },
541    /// ADD, SUBTRACT, MULTIPLY and DIVIDE, reduced to their arithmetic.
542    Arith(Box<Arith>),
543    /// MOVE, ADD or SUBTRACT CORRESPONDING, which the compiler expands into a MOVE per pair of
544    /// corresponding items, or one ADD or SUBTRACT over them all.
545    Corresponding(Box<Corresponding>),
546    If { cond: Cond, then: Vec<Stmt>, otherwise: Vec<Stmt>, pos: Pos },
547    PerformInline { body: Vec<Stmt>, repeat: Loop, pos: Pos },
548    PerformProc { from: ProcName, thru: Option<ProcName>, repeat: Loop, pos: Pos },
549    Evaluate { subjects: Vec<Subject>, whens: Vec<When>, other: Vec<Stmt>, pos: Pos },
550    /// DISPLAY; `screen` holds Micro Focus's and GnuCOBOL's screen phrases, or UPON CRT, which
551    /// write the items on the screen instead of a device.
552    Display { items: Vec<Operand>, upon: Option<Upon>, no_advancing: bool, screen: Option<Box<ScreenPhrases>>, pos: Pos },
553    Open { files: Vec<(OpenMode, String)>, pos: Pos },
554    Close { files: Vec<(String, Option<Closing>)>, pos: Pos },
555    Read(Box<ReadStmt>),
556    Write { record: Ref, from: Option<Operand>, advancing: Option<Advancing>, invalid: Handlers, end_of_page: Handlers, pos: Pos },
557    Rewrite { record: Ref, from: Option<Operand>, invalid: Handlers, pos: Pos },
558    Delete { file: String, invalid: Handlers, pos: Pos },
559    /// Micro Focus's and GnuCOBOL's DELETE FILE under `--compliance extended`: each closed file's
560    /// data set removed.
561    DeleteFile { files: Vec<String>, pos: Pos },
562    Start { file: String, key: Option<(RelOp, Ref)>, invalid: Handlers, pos: Pos },
563    /// INITIALIZE; `with` holds its FILLER, VALUE, REPLACING and DEFAULT phrases, None without any.
564    Initialize { targets: Vec<Ref>, with: Option<Box<InitializeWith>>, pos: Pos },
565    /// GO TO; with no target, the altered GO TO that only an ALTER gives one.
566    GoTo { target: Option<ProcName>, pos: Pos },
567    /// GO TO ... DEPENDING ON: the procedure the item's value numbers, or on when none does.
568    GoToDepending { targets: Vec<ProcName>, on: Ref, pos: Pos },
569    /// ALTER: each paragraph whose GO TO is to go instead to the procedure paired with it.
570    Alter { pairs: Vec<(ProcName, ProcName)>, pos: Pos },
571    /// ENTRY: where a CALL of `name` begins, and the LINKAGE items its USING list addresses.
572    Entry { name: String, using: Vec<Param>, pos: Pos },
573    Goback { pos: Pos },
574    /// EXIT PROGRAM: returns from a called program; in the first program it does nothing.
575    ExitProgram { pos: Pos },
576    Call(Box<Call>),
577    Cancel { targets: Vec<Operand>, pos: Pos },
578    Set { set: SetStmt, pos: Pos },
579    /// ACCEPT; `exception` is the ON EXCEPTION phrases `--compliance extended` reads with
580    /// ARGUMENT-VALUE, and `screen` the screen phrases, or FROM CRT, that read the target from a
581    /// field of the screen.
582    Accept { target: Ref, from: AcceptFrom, exception: Handlers, screen: Option<Box<ScreenPhrases>>, pos: Pos },
583    String(Box<StringStmt>),
584    Unstring(Box<Unstring>),
585    Inspect(Box<Inspect>),
586    Search(Box<Search>),
587    /// NEXT SENTENCE: control passes to the statement after the next separator period.
588    NextSentence,
589    /// A separator period in the PROCEDURE DIVISION: where NEXT SENTENCE resumes.
590    SentenceEnd,
591    Exec(Box<ExecBlock>),
592    Report(Box<crate::report::ReportStmt>),
593    Invoke(Box<Invoke>),
594    JsonGenerate(Box<JsonGenerate>),
595    JsonParse(Box<JsonParse>),
596    XmlParse(Box<XmlParse>),
597    XmlGenerate(Box<XmlGenerate>),
598    ExitMethod { pos: Pos },
599    Sorting(Box<Sorting>),
600    StopRun { pos: Pos },
601    Continue { pos: Pos },
602    Exit { kind: ExitKind, pos: Pos },
603}
604
605#[derive(Clone, Debug, PartialEq, Eq)]
606pub struct SizeError {
607    pub on: Vec<Stmt>,
608    pub not_on: Vec<Stmt>,
609}
610
611#[derive(Clone, Copy, Debug, PartialEq, Eq)]
612pub enum ArithVerb {
613    Add,
614    Subtract,
615    Multiply,
616    Divide,
617}
618
619/// One arithmetic statement: `targets` each receive `expr`, which is written in terms of the
620/// statement's operands and, for the forms without GIVING, the target itself (`Operand::Ref` of
621/// the target, placed by the parser).
622#[derive(Clone, Debug, PartialEq, Eq)]
623pub struct Arith {
624    pub verb: ArithVerb,
625    pub computations: Vec<(Target, Expr)>,
626    pub remainder: Option<(Target, Expr, Expr)>,
627    pub size_error: Option<SizeError>,
628    pub pos: Pos,
629}
630
631#[derive(Clone, Copy, Debug, PartialEq, Eq)]
632pub enum CorrespondingVerb {
633    Move,
634    Add,
635    Subtract,
636}
637
638/// `from` is the sending group and `to` the receiving one; `rounded` and `size_error` are ADD's
639/// and SUBTRACT's.
640#[derive(Clone, Debug, PartialEq, Eq)]
641pub struct Corresponding {
642    pub verb: CorrespondingVerb,
643    pub from: Ref,
644    pub to: Ref,
645    pub rounded: bool,
646    pub size_error: Option<SizeError>,
647    pub pos: Pos,
648}
649
650#[derive(Clone, Copy, Debug, PartialEq, Eq)]
651pub enum ArgMode {
652    Reference,
653    Content,
654    Value,
655}
656
657/// One CALL argument; `value` is None for OMITTED.
658#[derive(Clone, Debug, PartialEq, Eq)]
659pub struct Arg {
660    pub mode: ArgMode,
661    pub value: Option<Operand>,
662}
663
664#[derive(Clone, Debug, PartialEq, Eq)]
665pub struct Call {
666    pub target: Operand,
667    pub using: Vec<Arg>,
668    pub returning: Option<Ref>,
669    pub on_exception: Option<Vec<Stmt>>,
670    pub not_on_exception: Option<Vec<Stmt>>,
671    pub pos: Pos,
672}
673
674#[derive(Clone, Debug, PartialEq, Eq)]
675pub enum SetStmt {
676    ConditionTrue(Vec<Ref>),
677    /// SET condition-names TO FALSE: each conditional variable gets its WHEN SET TO FALSE value.
678    ConditionFalse(Vec<Ref>),
679    /// SET targets TO value: an index or integer to a number, a pointer to ADDRESS OF, NULL or another pointer.
680    To { targets: Vec<Ref>, value: Operand },
681    /// SET procedure-pointers or function-pointers TO ENTRY, the entry named by a literal or identifier.
682    Entry { targets: Vec<Ref>, entry: Operand },
683    /// SET ADDRESS OF targets TO pointer.
684    AddressOf { targets: Vec<Ref>, value: Operand },
685    UpDown { targets: Vec<Ref>, down: bool, by: Expr },
686    /// SET mnemonic-names TO ON or OFF, each group in order: the UPSI switches the names stand for.
687    Switches(Vec<(Vec<Ref>, bool)>),
688}
689
690#[derive(Clone, Debug, PartialEq, Eq)]
691pub enum Delimiter {
692    Size,
693    By(Operand),
694}
695
696#[derive(Clone, Debug, PartialEq, Eq)]
697pub struct StringStmt {
698    pub sources: Vec<(Operand, Delimiter)>,
699    pub into: Ref,
700    pub pointer: Option<Ref>,
701    pub on_overflow: Option<Vec<Stmt>>,
702    pub not_on_overflow: Option<Vec<Stmt>>,
703    pub pos: Pos,
704}
705
706#[derive(Clone, Debug, PartialEq, Eq)]
707pub struct UnstringInto {
708    pub target: Ref,
709    pub delimiter_in: Option<Ref>,
710    pub count_in: Option<Ref>,
711}
712
713#[derive(Clone, Debug, PartialEq, Eq)]
714pub struct Unstring {
715    pub source: Ref,
716    /// Each delimiter, and whether ALL makes a run of it one delimiter.
717    pub delimiters: Vec<(bool, Operand)>,
718    pub into: Vec<UnstringInto>,
719    pub pointer: Option<Ref>,
720    pub tallying: Option<Ref>,
721    pub on_overflow: Option<Vec<Stmt>>,
722    pub not_on_overflow: Option<Vec<Stmt>>,
723    pub pos: Pos,
724}
725
726/// BEFORE or AFTER INITIAL value: where in the inspected item a phrase applies.
727#[derive(Clone, Debug, PartialEq, Eq)]
728pub struct Bound {
729    pub after: bool,
730    pub value: Operand,
731}
732
733pub use rt::vocab::InspectMode;
734
735/// One TALLYING or REPLACING phrase. `pattern` is None for CHARACTERS; `by` is None for TALLYING.
736#[derive(Clone, Debug, PartialEq, Eq)]
737pub struct InspectPhrase {
738    pub mode: InspectMode,
739    pub pattern: Option<Operand>,
740    pub by: Option<Operand>,
741    pub counter: Option<Ref>,
742    pub bounds: Vec<Bound>,
743}
744
745/// The categories INITIALIZE's VALUE and REPLACING phrases name (Language Reference SC27-8713-03,
746/// p. 350); EGCS is DBCS.
747#[derive(Clone, Copy, Debug, PartialEq, Eq)]
748pub enum DataCategory {
749    Alphabetic,
750    Alphanumeric,
751    AlphanumericEdited,
752    Dbcs,
753    National,
754    NationalEdited,
755    Numeric,
756    NumericEdited,
757    Utf8,
758}
759
760impl DataCategory {
761    pub const ALL: [Self; 9] = [
762        Self::Alphabetic,
763        Self::Alphanumeric,
764        Self::AlphanumericEdited,
765        Self::Dbcs,
766        Self::National,
767        Self::NationalEdited,
768        Self::Numeric,
769        Self::NumericEdited,
770        Self::Utf8,
771    ];
772
773    pub fn from_word(word: &str) -> Option<Self> {
774        Some(match word {
775            "ALPHABETIC" => Self::Alphabetic,
776            "ALPHANUMERIC" => Self::Alphanumeric,
777            "ALPHANUMERIC-EDITED" => Self::AlphanumericEdited,
778            "DBCS" | "EGCS" => Self::Dbcs,
779            "NATIONAL" => Self::National,
780            "NATIONAL-EDITED" => Self::NationalEdited,
781            "NUMERIC" => Self::Numeric,
782            "NUMERIC-EDITED" => Self::NumericEdited,
783            "UTF-8" => Self::Utf8,
784            _ => return None,
785        })
786    }
787
788    pub fn word(self) -> &'static str {
789        match self {
790            Self::Alphabetic => "ALPHABETIC",
791            Self::Alphanumeric => "ALPHANUMERIC",
792            Self::AlphanumericEdited => "ALPHANUMERIC-EDITED",
793            Self::Dbcs => "DBCS",
794            Self::National => "NATIONAL",
795            Self::NationalEdited => "NATIONAL-EDITED",
796            Self::Numeric => "NUMERIC",
797            Self::NumericEdited => "NUMERIC-EDITED",
798            Self::Utf8 => "UTF-8",
799        }
800    }
801}
802
803/// INITIALIZE's phrases. `value` lists the VALUE phrase's categories, every one for ALL TO VALUE.
804#[derive(Clone, Debug, Default, PartialEq, Eq)]
805pub struct InitializeWith {
806    pub filler: bool,
807    pub value: Vec<DataCategory>,
808    pub replacing: Vec<(DataCategory, Operand)>,
809    pub default: bool,
810}
811
812/// What an elementary receiver of INITIALIZE is sent.
813#[derive(Clone, Copy, Debug, PartialEq, Eq)]
814pub enum InitialValue<'a> {
815    /// The literal of the item's own VALUE clause.
816    Value,
817    Replacing(&'a Operand),
818    /// SPACE, ZERO or NULL, by the item's category.
819    Default,
820}
821
822impl InitializeWith {
823    /// Rules 1c and 2 of INITIALIZE (Language Reference SC27-8713-03, pp. 352-353) for an
824    /// elementary item of `category`, which `has_value` when its entry has a VALUE clause; None when
825    /// the item is not a receiver.
826    pub fn initial_value(&self, category: Option<DataCategory>, has_value: bool) -> Option<InitialValue<'_>> {
827        let named = |c: DataCategory| category == Some(c);
828        if has_value && self.value.iter().any(|&c| named(c)) {
829            return Some(InitialValue::Value);
830        }
831        if let Some((_, by)) = self.replacing.iter().find(|(c, _)| named(*c)) {
832            return Some(InitialValue::Replacing(by));
833        }
834        (self.default || self.value.is_empty() && self.replacing.is_empty()).then_some(InitialValue::Default)
835    }
836}
837
838/// `target` is a data item or, for TALLYING alone, a function's value.
839#[derive(Clone, Debug, PartialEq, Eq)]
840pub struct Inspect {
841    pub target: Operand,
842    pub tallying: Vec<InspectPhrase>,
843    pub replacing: Vec<InspectPhrase>,
844    pub converting: Option<(Operand, Operand, Vec<Bound>)>,
845    pub pos: Pos,
846}
847
848#[derive(Clone, Debug, PartialEq, Eq)]
849pub struct Search {
850    pub table: Ref,
851    pub all: bool,
852    pub varying: Option<Ref>,
853    pub at_end: Option<Vec<Stmt>>,
854    pub whens: Vec<(Cond, Vec<Stmt>)>,
855    pub pos: Pos,
856}
857
858#[derive(Clone, Copy, Debug, PartialEq, Eq)]
859pub enum ExecKind {
860    Sql,
861    Cics,
862    Dli,
863    Other,
864}
865
866#[derive(Clone, Debug, PartialEq, Eq)]
867pub enum ExecArg {
868    Operand(Operand),
869    /// An argument that is not data: a paragraph for HANDLE CONDITION, or text that did not parse.
870    Text(String),
871}
872
873/// An EXEC ... END-EXEC block, read but not translated.
874#[derive(Clone, Debug, PartialEq, Eq)]
875pub struct ExecBlock {
876    pub kind: ExecKind,
877    /// The command: SELECT, INCLUDE, DECLARE CURSOR, LINK, SEND MAP and so on.
878    pub command: String,
879    /// CICS options, each with its argument.
880    pub options: Vec<(String, Option<ExecArg>)>,
881    /// SQL host variables and indicator variables.
882    pub host_variables: Vec<Ref>,
883    /// The typed SQL statement, for EXEC SQL.
884    pub sql: Option<crate::sql::Sql>,
885    pub text: String,
886    pub pos: Pos,
887}
888
889impl ExecBlock {
890    /// Whether the block only declares, so a precompiler turns it into data or nothing.
891    pub fn declarative(&self) -> bool {
892        self.kind == ExecKind::Sql
893            && matches!(self.command.as_str(), "INCLUDE" | "BEGIN DECLARE SECTION" | "END DECLARE SECTION" | "WHENEVER" | "DECLARE CURSOR" | "DECLARE TABLE" | "DECLARE STATEMENT")
894    }
895}
896
897/// The statements of an ON phrase (AT END, INVALID KEY, ...) and of its NOT ON phrase.
898#[derive(Clone, Debug, Default, PartialEq, Eq)]
899pub struct Handlers {
900    pub on: Option<Vec<Stmt>>,
901    pub not_on: Option<Vec<Stmt>>,
902}
903
904#[derive(Clone, Debug, PartialEq, Eq)]
905pub struct ReadStmt {
906    pub file: String,
907    /// READ NEXT or PREVIOUS: the next record by the key of reference, even under dynamic access.
908    pub next: bool,
909    pub previous: bool,
910    pub into: Option<Ref>,
911    /// READ ... KEY IS: the key of reference for a random read.
912    pub key: Option<Ref>,
913    pub at_end: Handlers,
914    pub invalid: Handlers,
915    pub pos: Pos,
916}
917
918/// What an ALPHABET clause relates its alphabet-name to.
919#[derive(Clone, Debug, PartialEq, Eq)]
920pub enum Alphabet {
921    Ebcdic,
922    Native,
923    Standard1,
924    Standard2,
925    /// A collating sequence of the program's own, lowest position first.
926    Literal(Vec<AlphabetEntry>),
927}
928
929impl Alphabet {
930    pub fn name(&self) -> &'static str {
931        match self {
932            Self::Ebcdic => "EBCDIC",
933            Self::Native => "NATIVE",
934            Self::Standard1 => "STANDARD-1",
935            Self::Standard2 => "STANDARD-2",
936            Self::Literal(_) => "literal",
937        }
938    }
939}
940
941/// One literal of an ALPHABET clause: its characters in successive positions, a THROUGH range of
942/// characters in successive positions, or characters that ALSO share one position.
943#[derive(Clone, Debug, PartialEq, Eq)]
944pub enum AlphabetEntry {
945    Literal(Literal),
946    Through(Literal, Literal),
947    Also(Vec<Literal>),
948}
949
950/// ENVIRONMENT DIVISION clauses beyond SELECT that the program's meaning depends on.
951#[derive(Clone, Debug, Default, PartialEq, Eq)]
952pub struct Environment {
953    /// SPECIAL-NAMES ALPHABET: each alphabet-name and what it is.
954    pub alphabets: Vec<(String, Alphabet)>,
955    /// OBJECT-COMPUTER PROGRAM COLLATING SEQUENCE.
956    pub collating_sequence: Option<String>,
957    /// I-O-CONTROL SAME RECORD AREA and SAME AREA clauses, each with the files it names.
958    pub same_record_areas: Vec<Vec<String>>,
959    pub same_areas: Vec<Vec<String>>,
960    /// SPECIAL-NAMES entries naming a printer channel, space suppression, a punch pocket, AFP, or
961    /// a device ACCEPT or DISPLAY takes: each mnemonic-name and its environment-name.
962    pub mnemonics: Vec<(String, String)>,
963    /// SOURCE-COMPUTER ... WITH DEBUGGING MODE: debugging lines and USE FOR DEBUGGING sections are
964    /// compiled rather than read as comments.
965    pub debugging_mode: bool,
966    /// SPECIAL-NAMES DECIMAL-POINT IS COMMA: the comma and the period exchange roles in PICTURE
967    /// character-strings, numeric literals and the arguments of NUMVAL and NUMVAL-C.
968    pub decimal_point_comma: bool,
969    /// SPECIAL-NAMES CURRENCY SIGN clauses in order; none means the symbol and value $.
970    pub currency: Vec<CurrencySign>,
971    /// SPECIAL-NAMES UPSI-0 to UPSI-7 entries, a contained program's being its container's.
972    pub switches: Vec<Switch>,
973    /// SPECIAL-NAMES CLASS clauses, a contained program's being its container's.
974    pub classes: Vec<ClassClause>,
975}
976
977/// SPECIAL-NAMES CLASS class-name IS: each literal, or the two ends of a THROUGH range.
978#[derive(Clone, Debug, PartialEq, Eq)]
979pub struct ClassClause {
980    pub name: String,
981    pub members: Vec<(Literal, Option<Literal>)>,
982    pub pos: Pos,
983}
984
985/// A SPECIAL-NAMES entry for an UPSI switch: UPSI-`number` [IS mnemonic-name] with the
986/// condition-names of its ON and OFF status.
987#[derive(Clone, Debug, PartialEq, Eq)]
988pub struct Switch {
989    pub number: u8,
990    pub mnemonic: Option<String>,
991    pub on: Option<String>,
992    pub off: Option<String>,
993    pub pos: Pos,
994}
995
996/// Micro Focus's and GnuCOBOL's phrases that put a DISPLAY's items or an ACCEPT's field on the
997/// screen: where, what is cleared first, and how the field behaves. `attributes` keeps the others
998/// by name, as written.
999#[derive(Clone, Debug, Default, PartialEq, Eq)]
1000pub struct ScreenPhrases {
1001    pub at: Option<ScreenAt>,
1002    pub blank_screen: bool,
1003    pub blank_line: bool,
1004    pub erase_eol: bool,
1005    pub erase_eos: bool,
1006    pub update: bool,
1007    pub secure: bool,
1008    pub attributes: Vec<String>,
1009    /// An ACCEPT of a SCREEN SECTION's screen: the screen's name, and its TO and USING fields,
1010    /// which the compiler puts here. A positioned ACCEPT has neither, its one field its target.
1011    pub screen: Option<String>,
1012    pub inputs: Vec<ScreenInput>,
1013    pub pos: Pos,
1014}
1015
1016/// A TO or USING field of a screen: the item that shows it, as its PICTURE edits, the item that
1017/// takes the entry, and where it is.
1018#[derive(Clone, Debug, PartialEq, Eq)]
1019pub struct ScreenInput {
1020    pub field: Ref,
1021    pub target: Ref,
1022    pub line: u32,
1023    pub column: u32,
1024    pub update: bool,
1025    pub secure: bool,
1026}
1027
1028/// An entry of the SCREEN SECTION, as written.
1029#[derive(Clone, Debug, Default, PartialEq, Eq)]
1030pub struct ScreenEntry {
1031    pub level: u8,
1032    pub name: Option<String>,
1033    pub line: Option<ScreenPlace>,
1034    pub column: Option<ScreenPlace>,
1035    pub value: Option<Literal>,
1036    pub picture: Option<String>,
1037    pub from: Option<Operand>,
1038    pub to: Option<Ref>,
1039    pub using: Option<Ref>,
1040    pub blank_screen: bool,
1041    pub blank_line: bool,
1042    pub erase_eol: bool,
1043    pub erase_eos: bool,
1044    pub secure: bool,
1045    pub attributes: Vec<String>,
1046    pub pos: Pos,
1047}
1048
1049/// A SCREEN SECTION entry's LINE or COLUMN: a number, or PLUS or MINUS one relative to the entry
1050/// before.
1051#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1052pub enum ScreenPlace {
1053    At(u32),
1054    Plus(u32),
1055    Minus(u32),
1056}
1057
1058#[derive(Clone, Debug, PartialEq, Eq)]
1059pub enum ScreenAt {
1060    /// AT and four or six digits, or an item holding them: the line, then the column.
1061    Combined(Operand),
1062    LineColumn { line: Option<Operand>, column: Option<Operand> },
1063}
1064
1065/// DISPLAY's UPON phrase: the name as written, and the environment-name it stands for, a
1066/// SPECIAL-NAMES mnemonic-name's or the name itself.
1067#[derive(Clone, Debug, PartialEq, Eq)]
1068pub struct Upon {
1069    pub name: String,
1070    pub device: String,
1071}
1072
1073/// A CURRENCY SIGN clause: the currency sign value, and the PICTURE symbol that stands for it.
1074#[derive(Clone, Debug, PartialEq, Eq)]
1075pub struct CurrencySign {
1076    pub value: String,
1077    pub symbol: char,
1078    /// CURRENCY SIGN IS X'...': the literal's bytes, which the program's code page makes `value`,
1079    /// and `symbol` too when there is no PICTURE SYMBOL (`symbol` is [`HEX_SYMBOL`] until then).
1080    pub hex: Option<Vec<u8>>,
1081}
1082
1083/// The symbol of a hexadecimal CURRENCY SIGN without PICTURE SYMBOL before its code page decodes it.
1084pub const HEX_SYMBOL: char = '\0';
1085
1086#[derive(Clone, Debug, PartialEq, Eq)]
1087pub enum Sorting {
1088    Sort(SortStmt),
1089    Release { record: Ref, from: Option<Operand>, pos: Pos },
1090    Return { file: String, into: Option<Ref>, at_end: Handlers, pos: Pos },
1091}
1092
1093/// SORT or MERGE of an SD file, or SORT of a table (no input or output then).
1094#[derive(Clone, Debug, PartialEq, Eq)]
1095pub struct SortStmt {
1096    pub merge: bool,
1097    /// The SD file, or the table.
1098    pub subject: Ref,
1099    /// Each key and whether it ascends, most significant first.
1100    pub keys: Vec<(bool, Ref)>,
1101    pub duplicates: bool,
1102    pub collating: Option<String>,
1103    pub input: Option<SortIo>,
1104    pub output: Option<SortIo>,
1105    pub pos: Pos,
1106}
1107
1108/// USING or GIVING files, or an input or output procedure.
1109#[derive(Clone, Debug, PartialEq, Eq)]
1110pub enum SortIo {
1111    Files(Vec<String>),
1112    Procedure { from: ProcName, thru: Option<ProcName> },
1113}
1114
1115
1116/// JSON GENERATE (Language Reference SC27-8713-03, pp. 369-382).
1117#[derive(Clone, Debug, PartialEq, Eq)]
1118pub struct JsonGenerate {
1119    pub receiver: Ref,
1120    pub from: Ref,
1121    pub count: Option<Ref>,
1122    /// NAME OF item IS literal; `None` for OMITTED.
1123    pub names: Vec<(Ref, Option<Literal>)>,
1124    pub suppress: Vec<Suppression>,
1125    pub converting: Vec<(Ref, JsonConversion)>,
1126    pub indicating: Vec<NullIndicator>,
1127    pub encoding: Option<Encoding>,
1128    pub on_exception: Option<Vec<Stmt>>,
1129    pub not_on_exception: Option<Vec<Stmt>>,
1130    pub pos: Pos,
1131}
1132
1133/// A SUPPRESS phrase: an item, or EVERY item of a class (`Some(true)` NUMERIC, `Some(false)`
1134/// NONNUMERIC, `None` both) and, for XML GENERATE, of a form, suppressed always or only WHEN it
1135/// equals one of the figurative constants.
1136#[derive(Clone, Debug, PartialEq, Eq)]
1137pub enum Suppression {
1138    Item { item: Ref, when: Vec<Figurative> },
1139    Every { numeric: Option<bool>, form: Option<XmlForm>, when: Vec<Figurative> },
1140}
1141
1142/// A value that stands for true (CONVERTING ... TO JSON BOOLEAN) or for null (INDICATING): a
1143/// condition-name, or a one-character literal.
1144#[derive(Clone, Debug, PartialEq, Eq)]
1145pub enum Marker {
1146    Condition(Ref),
1147    Literal(Literal),
1148}
1149
1150#[derive(Clone, Debug, PartialEq, Eq)]
1151pub enum JsonConversion {
1152    Boolean(Marker),
1153    Null(Figurative),
1154}
1155
1156/// INDICATING item IS JSON NULL USING a condition-name of the indicator, or a literal IN it.
1157#[derive(Clone, Debug, PartialEq, Eq)]
1158pub struct NullIndicator {
1159    pub item: Ref,
1160    pub marker: Marker,
1161    pub indicator: Option<Ref>,
1162}
1163
1164#[derive(Clone, Debug, PartialEq, Eq)]
1165pub enum Encoding {
1166    Ccsid(Operand),
1167    FromCodepage,
1168}
1169
1170/// JSON PARSE (Language Reference SC27-8713-03, pp. 382-396).
1171#[derive(Clone, Debug, PartialEq, Eq)]
1172pub struct JsonParse {
1173    pub source: Ref,
1174    pub into: Ref,
1175    pub detail: bool,
1176    /// IGNORING JSON NULL FOR an item, or `None` FOR ALL.
1177    pub ignoring: Vec<Option<Ref>>,
1178    /// INDICATING item IS JSON NULL USING values, with IN and the indicator for two literals.
1179    pub indicating: Vec<(Ref, Flag, Option<Ref>)>,
1180    pub encoding: Option<Encoding>,
1181    /// NAME OF item IS literal; `None` for OMITTED.
1182    pub names: Vec<(Ref, Option<Literal>)>,
1183    pub suppress: Vec<Ref>,
1184    pub converting: Vec<(Ref, ParseConversion)>,
1185    pub on_exception: Option<Vec<Stmt>>,
1186    pub not_on_exception: Option<Vec<Stmt>>,
1187    pub pos: Pos,
1188}
1189
1190/// What a USING phrase of JSON PARSE sets for true, or for null, and for false, or not null: a
1191/// condition-name set to true or to its WHEN SET TO FALSE value, one of two condition-names set to
1192/// true, or one of two literals moved in.
1193#[derive(Clone, Debug, PartialEq, Eq)]
1194pub enum Flag {
1195    Condition(Ref),
1196    Conditions(Ref, Ref),
1197    Literals(Literal, Literal),
1198}
1199
1200#[derive(Clone, Debug, PartialEq, Eq)]
1201pub enum ParseConversion {
1202    Boolean(Box<Flag>),
1203    Null(Figurative),
1204}
1205
1206/// XML GENERATE (Language Reference SC27-8713-03, pp. 484-494).
1207#[derive(Clone, Debug, PartialEq, Eq)]
1208pub struct XmlGenerate {
1209    pub receiver: Ref,
1210    pub from: Ref,
1211    pub count: Option<Ref>,
1212    /// WITH ENCODING: the document's CCSID.
1213    pub encoding: Option<Operand>,
1214    pub declaration: bool,
1215    pub attributes: bool,
1216    pub namespace: Option<Operand>,
1217    pub prefix: Option<Operand>,
1218    pub names: Vec<(Ref, Literal)>,
1219    pub types: Vec<(Ref, XmlForm)>,
1220    pub suppress: Vec<Suppression>,
1221    pub on_exception: Option<Vec<Stmt>>,
1222    pub not_on_exception: Option<Vec<Stmt>>,
1223    pub pos: Pos,
1224}
1225
1226/// How XML GENERATE expresses an item: as an attribute or an element, or as its parent's content.
1227#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1228pub enum XmlForm {
1229    Attribute,
1230    Element,
1231    Content,
1232}
1233
1234/// XML PARSE under XMLPARSE(XMLSS) (Language Reference SC27-8713-03, pp. 489-494).
1235#[derive(Clone, Debug, PartialEq, Eq)]
1236pub struct XmlParse {
1237    pub document: Ref,
1238    /// WITH ENCODING: the document's CCSID.
1239    pub encoding: Option<Operand>,
1240    pub returning_national: bool,
1241    pub procedure: ProcName,
1242    pub thru: Option<ProcName>,
1243    pub on_exception: Option<Vec<Stmt>>,
1244    pub not_on_exception: Option<Vec<Stmt>>,
1245    pub pos: Pos,
1246}