@portll/cobolwork 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/README.md +89 -26
  2. package/STABILITY.md +76 -0
  3. package/bin/cobolwork.mjs +56 -14
  4. package/lib/baseline.mjs +9 -0
  5. package/lib/bms.mjs +21 -7
  6. package/lib/build.mjs +133 -53
  7. package/lib/capabilities.mjs +13 -11
  8. package/lib/cics-commands.mjs +501 -9
  9. package/lib/compliance.mjs +11 -0
  10. package/lib/consequence.mjs +17 -0
  11. package/lib/control-reuse.mjs +113 -0
  12. package/lib/control-workers.mjs +161 -0
  13. package/lib/control.mjs +77 -4
  14. package/lib/dataflow.mjs +402 -152
  15. package/lib/db2/cursor.mjs +15 -0
  16. package/lib/db2/read.mjs +170 -0
  17. package/lib/db2/rules.mjs +77 -0
  18. package/lib/db2/stmt/alter.mjs +473 -0
  19. package/lib/db2/stmt/grant.mjs +125 -0
  20. package/lib/db2/stmt/index.mjs +141 -0
  21. package/lib/db2/stmt/misc.mjs +325 -0
  22. package/lib/db2/stmt/routine.mjs +564 -0
  23. package/lib/db2/stmt/storage.mjs +146 -0
  24. package/lib/db2/stmt/table.mjs +540 -0
  25. package/lib/db2/stmt/view.mjs +146 -0
  26. package/lib/diff.mjs +17 -5
  27. package/lib/equivalence.mjs +44 -5
  28. package/lib/evidence/cli.mjs +26 -7
  29. package/lib/evidence/record.mjs +16 -6
  30. package/lib/evidence/seal.mjs +17 -0
  31. package/lib/evidence/store.mjs +44 -15
  32. package/lib/evidence/timestamp.mjs +83 -0
  33. package/lib/evidence/verify.mjs +120 -42
  34. package/lib/exec-reading.mjs +51 -0
  35. package/lib/execution.mjs +3 -2
  36. package/lib/explain.mjs +2 -0
  37. package/lib/exploitability.mjs +11 -2
  38. package/lib/hlasm/asm/data.mjs +128 -0
  39. package/lib/hlasm/asm/listing.mjs +43 -0
  40. package/lib/hlasm/asm/output.mjs +45 -0
  41. package/lib/hlasm/asm/sections.mjs +161 -0
  42. package/lib/hlasm/asm/symbols.mjs +78 -0
  43. package/lib/hlasm/exec.mjs +27 -0
  44. package/lib/hlasm/expr.mjs +167 -0
  45. package/lib/hlasm/instr.mjs +73 -0
  46. package/lib/hlasm/locate.mjs +333 -0
  47. package/lib/hlasm/macro/authorization.mjs +146 -0
  48. package/lib/hlasm/macro/datasets.mjs +107 -0
  49. package/lib/hlasm/macro/io.mjs +162 -0
  50. package/lib/hlasm/macro/le.mjs +53 -0
  51. package/lib/hlasm/macro/linkage.mjs +143 -0
  52. package/lib/hlasm/macro/operator.mjs +77 -0
  53. package/lib/hlasm/macro/program.mjs +184 -0
  54. package/lib/hlasm/macro/recovery.mjs +85 -0
  55. package/lib/hlasm/macro/storage.mjs +167 -0
  56. package/lib/hlasm/macro/structured.mjs +131 -0
  57. package/lib/hlasm/model.mjs +97 -0
  58. package/lib/hlasm/mvs38.mjs +47 -0
  59. package/lib/hlasm/operands.mjs +59 -0
  60. package/lib/hlasm/optable.mjs +61 -0
  61. package/lib/hlasm/read.mjs +130 -0
  62. package/lib/hlasm.mjs +44 -7
  63. package/lib/ims/dli.mjs +37 -0
  64. package/lib/ims/macro/dbd.mjs +299 -0
  65. package/lib/ims/macro/psb.mjs +286 -0
  66. package/lib/ims/model.mjs +149 -0
  67. package/lib/ims/operands.mjs +23 -0
  68. package/lib/ims/read.mjs +37 -0
  69. package/lib/ims/rules.mjs +135 -0
  70. package/lib/inventory.mjs +10 -7
  71. package/lib/ironwork-ids.mjs +24 -0
  72. package/lib/ironwork.mjs +20 -13
  73. package/lib/kernel/pds-archive.mjs +256 -0
  74. package/lib/kernel/registry.mjs +32 -23
  75. package/lib/kernel/shared-pass.mjs +163 -0
  76. package/lib/kernel/source-tree.mjs +104 -36
  77. package/lib/kernel/version-key.mjs +17 -0
  78. package/lib/layout.mjs +26 -31
  79. package/lib/options.mjs +26 -4
  80. package/lib/parser.mjs +136 -17
  81. package/lib/pli/cursor.mjs +15 -0
  82. package/lib/pli/expr.mjs +101 -0
  83. package/lib/pli/include.mjs +82 -0
  84. package/lib/pli/layout.mjs +125 -0
  85. package/lib/pli/lex.mjs +198 -0
  86. package/lib/pli/program.mjs +280 -0
  87. package/lib/pli/rules/based.mjs +95 -0
  88. package/lib/pli/rules/conditions.mjs +68 -0
  89. package/lib/pli/rules/entry.mjs +130 -0
  90. package/lib/pli/rules/index.mjs +24 -0
  91. package/lib/pli/rules/preprocessor.mjs +55 -0
  92. package/lib/pli/statements.mjs +130 -0
  93. package/lib/pli/stmt/alloc.mjs +45 -0
  94. package/lib/pli/stmt/assignment.mjs +56 -0
  95. package/lib/pli/stmt/call.mjs +104 -0
  96. package/lib/pli/stmt/conditions.mjs +94 -0
  97. package/lib/pli/stmt/control.mjs +219 -0
  98. package/lib/pli/stmt/declare.mjs +149 -0
  99. package/lib/pli/stmt/exec.mjs +55 -0
  100. package/lib/pli/stmt/io.mjs +239 -0
  101. package/lib/pli/stmt/misc.mjs +4 -0
  102. package/lib/pli/stmt/preprocessor.mjs +242 -0
  103. package/lib/pli/stmt/procedure.mjs +258 -0
  104. package/lib/pli/stmt/stream.mjs +283 -0
  105. package/lib/pli/storage.mjs +129 -0
  106. package/lib/policy.mjs +6 -0
  107. package/lib/precompile-check.mjs +124 -0
  108. package/lib/precompile-cics.mjs +8 -4
  109. package/lib/reach.mjs +11 -2
  110. package/lib/revision.json +1 -1
  111. package/lib/sarif.mjs +44 -3
  112. package/lib/scan.mjs +28 -12
  113. package/lib/sets/abend.mjs +82 -8
  114. package/lib/sets/build.mjs +43 -37
  115. package/lib/sets/cics.mjs +20 -38
  116. package/lib/sets/compile.mjs +46 -18
  117. package/lib/sets/copybook.mjs +5 -3
  118. package/lib/sets/crypto.mjs +5 -3
  119. package/lib/sets/ddl.mjs +36 -0
  120. package/lib/sets/flow.mjs +32 -8
  121. package/lib/sets/hidden.mjs +5 -3
  122. package/lib/sets/hlasm.mjs +124 -8
  123. package/lib/sets/ims.mjs +139 -0
  124. package/lib/sets/log.mjs +11 -9
  125. package/lib/sets/opaque.mjs +27 -7
  126. package/lib/sets/pli.mjs +40 -0
  127. package/lib/sets/priv.mjs +5 -3
  128. package/lib/sets/recon.mjs +5 -3
  129. package/lib/sets/secrets.mjs +112 -0
  130. package/lib/sets/semantics.mjs +8 -3
  131. package/lib/sets/web.mjs +39 -23
  132. package/lib/site.mjs +10 -0
  133. package/lib/sources.mjs +80 -20
  134. package/lib/statement-cursor.mjs +67 -0
  135. package/lib/verify.mjs +3 -2
  136. package/lib/version.mjs +6 -0
  137. package/package.json +3 -2
  138. package/rules/compliance-cobit2019.json +520 -5
  139. package/rules/compliance-dora.json +509 -5
  140. package/rules/compliance-ffiec.json +505 -1
  141. package/rules/compliance-nist80053.json +557 -1
  142. package/rules/gitleaks-mainframe.toml +46 -15
  143. package/rules/hlasm-instructions.json +2396 -0
  144. package/rules/hlasm-optables.json +8024 -0
  145. package/schema/cobolwork-baseline.schema.json +36 -0
  146. package/schema/cobolwork-build-provenance.schema.json +187 -0
  147. package/schema/cobolwork-build.schema.json +382 -0
  148. package/schema/cobolwork-capabilities.schema.json +239 -0
  149. package/schema/cobolwork-diff.schema.json +217 -0
  150. package/schema/cobolwork-evidence.schema.json +161 -0
  151. package/schema/cobolwork-execution.schema.json +53 -0
  152. package/schema/cobolwork-explain.schema.json +360 -0
  153. package/schema/cobolwork-finding.schema.json +465 -0
  154. package/schema/cobolwork-flow.schema.json +465 -0
  155. package/schema/cobolwork-gate.schema.json +211 -0
  156. package/schema/cobolwork-inventory.schema.json +206 -0
  157. package/schema/cobolwork-parse.schema.json +105 -0
  158. package/schema/cobolwork-reach.schema.json +74 -0
  159. package/schema/cobolwork-report.schema.json +559 -0
  160. package/schema/cobolwork-witness.schema.json +107 -0
  161. package/schema/cobolwork.baseline.schema.json +101 -0
  162. package/schema/cobolwork.policy.schema.json +7 -0
  163. package/schema/cobolwork.site.schema.json +116 -0
@@ -0,0 +1,242 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // Parser for PL/I preprocessor statements (kind PREPROCESSOR), which begin with the op '%'.
3
+ import { cursor } from '../cursor.mjs';
4
+ import { parseExpression, parseReference } from '../expr.mjs';
5
+
6
+ export const parsers = {
7
+ PREPROCESSOR: (c, stmt, ctx) => {
8
+ const node = { kind: 'PREPROCESSOR', units: [] };
9
+ if (!c.isOp('%')) c.fail("'%'");
10
+ c.next();
11
+
12
+ const labelTok = c.peek();
13
+ if (labelTok && labelTok.t === 'word' && c.isOp(':', 1)) {
14
+ c.next();
15
+ c.next();
16
+ node.label = labelTok.u;
17
+ }
18
+
19
+ if (c.done()) { node.directive = 'NULL'; return node; }
20
+ const dirTok = c.peek();
21
+ if (!dirTok || dirTok.t !== 'word') c.fail('a directive word');
22
+ // %X = expression assigns a preprocessor variable.
23
+ if (c.isOp('=', 1)) {
24
+ c.next();
25
+ c.next();
26
+ return { ...node, directive: 'ASSIGN', names: [dirTok.u], value: parseExpression(c) };
27
+ }
28
+ c.next();
29
+ node.directive = dirTok.u;
30
+
31
+ switch (node.directive) {
32
+ case 'INCLUDE':
33
+ case 'XINCLUDE': {
34
+ // A member is a name, a quoted name, or ddname(member) naming the library it is read from.
35
+ node.members = [];
36
+ for (;;) {
37
+ const t = c.next();
38
+ if (t && t.t === 'lit') node.members.push({ name: t.v, library: null });
39
+ else if (t && t.t === 'word' && c.isOp('(')) {
40
+ const s2 = cursor(c.group());
41
+ const m = s2.next();
42
+ if (!m || (m.t !== 'word' && m.t !== 'lit') || !s2.done()) c.fail('a member name in the library reference');
43
+ node.members.push({ name: m.u ?? m.v, library: t.u });
44
+ } else if (t && t.t === 'word') node.members.push({ name: t.u, library: null });
45
+ else c.fail('a member name');
46
+ if (!c.op(',')) break;
47
+ }
48
+ break;
49
+ }
50
+ case 'DCL':
51
+ case 'DECLARE': {
52
+ node.names = [];
53
+ while (!c.done()) {
54
+ if (c.isOp(',')) c.next();
55
+ const nameTok = c.expectWord(undefined);
56
+ node.names.push(nameTok.u);
57
+ while (!c.done()) {
58
+ const t = c.peek();
59
+ if (t.t === 'word') {
60
+ c.next();
61
+ } else if (t.t === 'op' && t.v === '(') {
62
+ c.group();
63
+ } else if (t.t === 'op' && t.v === ',') {
64
+ break;
65
+ } else {
66
+ break;
67
+ }
68
+ }
69
+ }
70
+ break;
71
+ }
72
+ case 'IF': {
73
+ const expr = parseExpression(c, { stopOps: ['%'] });
74
+ node.value = expr;
75
+ if (c.isOp('%') && c.isWord('THEN', 1)) {
76
+ c.next();
77
+ c.next();
78
+ const unitToks = c.drain();
79
+ if (unitToks.length) {
80
+ const sub = ctx.subStatement(stmt, unitToks);
81
+ const res = ctx.parseStatement(sub);
82
+ node.units.push(res);
83
+ }
84
+ } else {
85
+ c.fail('%THEN');
86
+ }
87
+ break;
88
+ }
89
+ case 'ELSE': {
90
+ const unitToks = c.drain();
91
+ if (unitToks.length) {
92
+ const sub = ctx.subStatement(stmt, unitToks);
93
+ const res = ctx.parseStatement(sub);
94
+ node.units.push(res);
95
+ }
96
+ break;
97
+ }
98
+ case 'DO':
99
+ case 'END':
100
+ case 'PAGE':
101
+ case 'NOPRINT':
102
+ case 'PUSH':
103
+ case 'POP':
104
+ case 'PRINT':
105
+ case 'ITERATE':
106
+ case 'LEAVE':
107
+ case 'INSCAN':
108
+ case 'XINSCAN':
109
+ case 'PROCESS': {
110
+ if (node.directive === 'PROCESS') {
111
+ while (!c.done()) c.next();
112
+ }
113
+ break;
114
+ }
115
+ case 'SKIP': {
116
+ if (c.isOp('(')) {
117
+ c.group();
118
+ }
119
+ break;
120
+ }
121
+ case 'NOTE': {
122
+ if (c.isOp('(')) {
123
+ c.group();
124
+ }
125
+ break;
126
+ }
127
+ case 'ACTIVATE':
128
+ case 'ACT':
129
+ case 'DEACTIVATE':
130
+ case 'DEACT': {
131
+ node.names = [];
132
+ while (!c.done()) {
133
+ if (c.isWord()) {
134
+ const t = c.next();
135
+ if (t.u === 'RESCAN' || t.u === 'NORESCAN') {
136
+ node.rescan = t.u === 'RESCAN';
137
+ } else {
138
+ node.names.push(t.u);
139
+ }
140
+ } else if (c.isOp(',')) {
141
+ c.next();
142
+ } else {
143
+ c.fail('a name or RESCAN/NORESCAN');
144
+ }
145
+ }
146
+ break;
147
+ }
148
+ case 'GO':
149
+ case 'GOTO': {
150
+ if (c.isWord('TO')) c.next();
151
+ const label = c.expectWord(undefined);
152
+ node.label = label.u;
153
+ break;
154
+ }
155
+ case 'RETURN': {
156
+ if (c.isOp('(')) {
157
+ const inner = c.group();
158
+ const s = cursor(inner);
159
+ node.value = parseExpression(s);
160
+ if (!s.done()) s.fail('the end of the argument');
161
+ }
162
+ break;
163
+ }
164
+ case 'REPLACE': {
165
+ const name = c.expectWord(undefined);
166
+ node.names = [name.u];
167
+ if (!c.isWord('BY')) c.fail('BY');
168
+ c.next();
169
+ node.value = parseExpression(c);
170
+ break;
171
+ }
172
+ case 'PROCEDURE':
173
+ case 'PROC': {
174
+ if (c.isOp('(')) {
175
+ const params = c.items();
176
+ node.params = params.map(p => {
177
+ const s = cursor(p);
178
+ const ref = parseReference(s);
179
+ if (!s.done()) s.fail('the end of the parameter');
180
+ return ref;
181
+ });
182
+ }
183
+ while (!c.done()) {
184
+ const t = c.peek();
185
+ if (t.t === 'word') {
186
+ if (t.u === 'STATEMENT') {
187
+ c.next();
188
+ node.statement = true;
189
+ } else if (t.u === 'RETURNS') {
190
+ c.next();
191
+ c.expectOp('(');
192
+ const retTok = c.expectWord(undefined);
193
+ c.expectOp(')');
194
+ node.returns = retTok.u;
195
+ } else {
196
+ c.next();
197
+ }
198
+ } else if (t.t === 'op' && t.v === '(') {
199
+ c.group();
200
+ } else {
201
+ c.fail('STATEMENT or RETURNS');
202
+ }
203
+ }
204
+ break;
205
+ }
206
+ case 'SELECT':
207
+ case 'WHEN':
208
+ case 'OTHERWISE': {
209
+ if (node.directive === 'WHEN') {
210
+ if (c.isOp('(')) {
211
+ const inner = c.group();
212
+ const s = cursor(inner);
213
+ node.value = parseExpression(s);
214
+ if (!s.done()) s.fail('the end of the condition');
215
+ }
216
+ const unitToks = c.drain();
217
+ if (unitToks.length) {
218
+ const sub = ctx.subStatement(stmt, unitToks);
219
+ const res = ctx.parseStatement(sub);
220
+ node.units.push(res);
221
+ }
222
+ } else if (node.directive === 'OTHERWISE') {
223
+ const unitToks = c.drain();
224
+ if (unitToks.length) {
225
+ const sub = ctx.subStatement(stmt, unitToks);
226
+ const res = ctx.parseStatement(sub);
227
+ node.units.push(res);
228
+ }
229
+ }
230
+ break;
231
+ }
232
+ default: {
233
+ const rest = c.drain();
234
+ node.toks = rest;
235
+ break;
236
+ }
237
+ }
238
+
239
+ if (!c.done()) c.fail('the end of the statement');
240
+ return node;
241
+ }
242
+ };
@@ -0,0 +1,258 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // Parsers for PL/I PROCEDURE, ENTRY, PACKAGE, BEGIN, and END statements.
3
+
4
+ const PROC_OPTIONS = new Set([
5
+ 'RECURSIVE', 'NONRECURSIVE', 'REORDER', 'ORDER', 'EXTERNAL', 'EXT',
6
+ 'CHARGRAPHIC', 'NOCHARGRAPHIC', 'REDUCIBLE', 'IRREDUCIBLE'
7
+ ]);
8
+
9
+ const BEGIN_OPTIONS = new Set([
10
+ 'ORDER', 'REORDER', 'CHARGRAPHIC', 'NOCHARGRAPHIC'
11
+ ]);
12
+
13
+ function parseNameList(c, failMsg) {
14
+ const items = c.items();
15
+ const names = [];
16
+ for (const item of items) {
17
+ if (item.length === 1 && item[0].t === 'op' && item[0].v === '*') {
18
+ names.push('*');
19
+ } else if (item.length === 1 && item[0].t === 'word') {
20
+ names.push(item[0].u);
21
+ } else {
22
+ c.fail(failMsg);
23
+ }
24
+ }
25
+ return names;
26
+ }
27
+
28
+ function parseOptionsList(c) {
29
+ const items = c.items();
30
+ const options = [];
31
+ for (const item of items) {
32
+ if (item.length === 0) continue;
33
+ const first = item[0];
34
+ if (first.t !== 'word') {
35
+ c.fail('an option name');
36
+ }
37
+ const opt = { name: first.u, args: null };
38
+ let i = 1;
39
+ if (i < item.length && item[i].t === 'op' && item[i].v === '(') {
40
+ const start = i;
41
+ let depth = 0;
42
+ for (; i < item.length; i++) {
43
+ if (item[i].t === 'op' && item[i].v === '(') depth++;
44
+ else if (item[i].t === 'op' && item[i].v === ')') {
45
+ depth--;
46
+ if (depth === 0) { i++; break; }
47
+ }
48
+ }
49
+ if (depth !== 0) {
50
+ c.fail("matching ')'");
51
+ }
52
+ opt.args = item.slice(start + 1, i - 1);
53
+ }
54
+ if (i < item.length) {
55
+ c.fail('end of option');
56
+ }
57
+ options.push(opt);
58
+ }
59
+ return options;
60
+ }
61
+
62
+ function parseProcedure(c, stmt) {
63
+ c.expectWord(['PROCEDURE', 'PROC']);
64
+ const name = stmt.labels.length ? stmt.labels[stmt.labels.length - 1].name : null;
65
+ const node = {
66
+ kind: 'PROCEDURE',
67
+ name,
68
+ params: [],
69
+ options: [],
70
+ returns: null,
71
+ recursive: false,
72
+ external: null,
73
+ order: null
74
+ };
75
+
76
+ if (c.isOp('(')) {
77
+ const items = c.items();
78
+ for (const item of items) {
79
+ if (item.length === 1 && item[0].t === 'word') {
80
+ node.params.push(item[0].u);
81
+ } else {
82
+ c.fail('a parameter name');
83
+ }
84
+ }
85
+ }
86
+
87
+ while (!c.done()) {
88
+ if (c.isWord('OPTIONS')) {
89
+ c.next();
90
+ if (!c.isOp('(')) c.fail("'('");
91
+ node.options.push(...parseOptionsList(c));
92
+ } else if (c.isWord('RETURNS')) {
93
+ c.next();
94
+ if (!c.isOp('(')) c.fail("'('");
95
+ node.returns = c.group();
96
+ } else if (c.isWord(['RECURSIVE', 'NONRECURSIVE'])) {
97
+ const t = c.next();
98
+ node.recursive = t.u === 'RECURSIVE';
99
+ } else if (c.isWord(['ORDER', 'REORDER'])) {
100
+ const t = c.next();
101
+ node.order = t.u;
102
+ } else if (c.isWord(['EXTERNAL', 'EXT'])) {
103
+ c.next();
104
+ if (c.isOp('(')) {
105
+ const inner = c.group();
106
+ if (inner.length === 1 && inner[0].t === 'lit') {
107
+ node.external = inner[0].v;
108
+ } else if (inner.length === 1 && inner[0].t === 'word') {
109
+ node.external = inner[0].u;
110
+ } else {
111
+ c.fail("a name or literal");
112
+ }
113
+ } else {
114
+ node.external = true;
115
+ }
116
+ } else if (c.isWord(['CHARGRAPHIC', 'NOCHARGRAPHIC', 'REDUCIBLE', 'IRREDUCIBLE'])) {
117
+ const t = c.next();
118
+ node.options.push({ name: t.u, args: null });
119
+ } else {
120
+ c.fail('a PROCEDURE option');
121
+ }
122
+ }
123
+
124
+ return node;
125
+ }
126
+
127
+ function parseEntry(c, stmt) {
128
+ c.expectWord('ENTRY');
129
+ const name = stmt.labels.length ? stmt.labels[stmt.labels.length - 1].name : null;
130
+ const node = {
131
+ kind: 'ENTRY',
132
+ name,
133
+ params: [],
134
+ options: [],
135
+ returns: null,
136
+ recursive: false,
137
+ external: null,
138
+ order: null
139
+ };
140
+
141
+ if (c.isOp('(')) {
142
+ const items = c.items();
143
+ for (const item of items) {
144
+ if (item.length === 1 && item[0].t === 'word') {
145
+ node.params.push(item[0].u);
146
+ } else {
147
+ c.fail('a parameter name');
148
+ }
149
+ }
150
+ }
151
+
152
+ while (!c.done()) {
153
+ if (c.isWord('RETURNS')) {
154
+ c.next();
155
+ if (!c.isOp('(')) c.fail("'('");
156
+ node.returns = c.group();
157
+ } else if (c.isWord('OPTIONS')) {
158
+ c.next();
159
+ if (!c.isOp('(')) c.fail("'('");
160
+ node.options.push(...parseOptionsList(c));
161
+ } else if (c.isWord(['EXTERNAL', 'EXT'])) {
162
+ c.next();
163
+ if (c.isOp('(')) {
164
+ const inner = c.group();
165
+ if (inner.length === 1 && inner[0].t === 'lit') {
166
+ node.external = inner[0].v;
167
+ } else if (inner.length === 1 && inner[0].t === 'word') {
168
+ node.external = inner[0].u;
169
+ } else {
170
+ c.fail("a name or literal");
171
+ }
172
+ } else {
173
+ node.external = true;
174
+ }
175
+ } else {
176
+ c.fail('an ENTRY option');
177
+ }
178
+ }
179
+
180
+ return node;
181
+ }
182
+
183
+ function parsePackage(c, stmt) {
184
+ c.expectWord('PACKAGE');
185
+ const name = stmt.labels.length ? stmt.labels[stmt.labels.length - 1].name : null;
186
+ const node = {
187
+ kind: 'PACKAGE',
188
+ name,
189
+ exports: null,
190
+ reserves: null,
191
+ options: []
192
+ };
193
+
194
+ while (!c.done()) {
195
+ if (c.isWord('EXPORTS')) {
196
+ c.next();
197
+ if (!c.isOp('(')) c.fail("'('");
198
+ node.exports = parseNameList(c, 'an export name');
199
+ } else if (c.isWord('RESERVES')) {
200
+ c.next();
201
+ if (!c.isOp('(')) c.fail("'('");
202
+ node.reserves = parseNameList(c, 'a reserve name');
203
+ } else if (c.isWord('OPTIONS')) {
204
+ c.next();
205
+ if (!c.isOp('(')) c.fail("'('");
206
+ node.options.push(...parseOptionsList(c));
207
+ } else {
208
+ c.fail('a PACKAGE option');
209
+ }
210
+ }
211
+
212
+ return node;
213
+ }
214
+
215
+ function parseBegin(c, stmt) {
216
+ c.expectWord('BEGIN');
217
+ const node = {
218
+ kind: 'BEGIN',
219
+ options: []
220
+ };
221
+
222
+ while (!c.done()) {
223
+ if (c.isWord(['OPTIONS', 'ORDER', 'REORDER', 'CHARGRAPHIC', 'NOCHARGRAPHIC'])) {
224
+ const t = c.next();
225
+ if (t.u === 'OPTIONS') {
226
+ if (!c.isOp('(')) c.fail("'('");
227
+ node.options.push(...parseOptionsList(c));
228
+ } else {
229
+ node.options.push({ name: t.u, args: null });
230
+ }
231
+ } else {
232
+ c.fail('a BEGIN option');
233
+ }
234
+ }
235
+
236
+ return node;
237
+ }
238
+
239
+ function parseEnd(c, stmt) {
240
+ c.expectWord('END');
241
+ let label = null;
242
+ if (!c.done()) {
243
+ if (c.isWord()) {
244
+ label = c.next().u;
245
+ } else {
246
+ c.fail('a label or end of statement');
247
+ }
248
+ }
249
+ return { kind: 'END', label };
250
+ }
251
+
252
+ export const parsers = {
253
+ PROCEDURE: parseProcedure,
254
+ ENTRY: parseEntry,
255
+ PACKAGE: parsePackage,
256
+ BEGIN: parseBegin,
257
+ END: parseEnd
258
+ };