@open-rap/compiler 0.0.0-stage → 0.1.1

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 (227) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +21 -2
  3. package/dist/agent/server.d.ts +35 -0
  4. package/dist/agent/server.js +408 -0
  5. package/dist/agent/server.js.map +1 -0
  6. package/dist/authoring/abapgit.d.ts +38 -0
  7. package/dist/authoring/abapgit.js +242 -0
  8. package/dist/authoring/abapgit.js.map +1 -0
  9. package/dist/authoring/catalog.d.ts +48 -0
  10. package/dist/authoring/catalog.js +117 -0
  11. package/dist/authoring/catalog.js.map +1 -0
  12. package/dist/authoring/floorplan.d.ts +28 -0
  13. package/dist/authoring/floorplan.js +31 -0
  14. package/dist/authoring/floorplan.js.map +1 -0
  15. package/dist/authoring/generate.d.ts +57 -0
  16. package/dist/authoring/generate.js +630 -0
  17. package/dist/authoring/generate.js.map +1 -0
  18. package/dist/authoring/mcp.d.ts +15 -0
  19. package/dist/authoring/mcp.js +52 -0
  20. package/dist/authoring/mcp.js.map +1 -0
  21. package/dist/authoring/new.d.ts +35 -0
  22. package/dist/authoring/new.js +389 -0
  23. package/dist/authoring/new.js.map +1 -0
  24. package/dist/bdef/ast.d.ts +249 -0
  25. package/dist/bdef/ast.js +3 -0
  26. package/dist/bdef/ast.js.map +1 -0
  27. package/dist/bdef/lexer.d.ts +105 -0
  28. package/dist/bdef/lexer.js +148 -0
  29. package/dist/bdef/lexer.js.map +1 -0
  30. package/dist/bdef/parser.d.ts +22 -0
  31. package/dist/bdef/parser.js +1012 -0
  32. package/dist/bdef/parser.js.map +1 -0
  33. package/dist/build.d.ts +26 -0
  34. package/dist/build.js +62 -0
  35. package/dist/build.js.map +1 -0
  36. package/dist/cds/adapter.d.ts +91 -0
  37. package/dist/cds/adapter.js +381 -0
  38. package/dist/cds/adapter.js.map +1 -0
  39. package/dist/cds/expression-ast.d.ts +65 -0
  40. package/dist/cds/expression-ast.js +330 -0
  41. package/dist/cds/expression-ast.js.map +1 -0
  42. package/dist/cli.d.ts +9 -0
  43. package/dist/cli.js +485 -0
  44. package/dist/cli.js.map +1 -0
  45. package/dist/dcl/parser.d.ts +59 -0
  46. package/dist/dcl/parser.js +338 -0
  47. package/dist/dcl/parser.js.map +1 -0
  48. package/dist/ddic/catalog.d.ts +17 -0
  49. package/dist/ddic/catalog.js +211 -0
  50. package/dist/ddic/catalog.js.map +1 -0
  51. package/dist/ddic/cds-types.d.ts +47 -0
  52. package/dist/ddic/cds-types.js +131 -0
  53. package/dist/ddic/cds-types.js.map +1 -0
  54. package/dist/ddic/table-source.d.ts +70 -0
  55. package/dist/ddic/table-source.js +500 -0
  56. package/dist/ddic/table-source.js.map +1 -0
  57. package/dist/ddic/xml.d.ts +65 -0
  58. package/dist/ddic/xml.js +201 -0
  59. package/dist/ddic/xml.js.map +1 -0
  60. package/dist/dev.d.ts +128 -0
  61. package/dist/dev.js +434 -0
  62. package/dist/dev.js.map +1 -0
  63. package/dist/diagnostics.d.ts +33 -0
  64. package/dist/diagnostics.js +53 -0
  65. package/dist/diagnostics.js.map +1 -0
  66. package/dist/gen/abap/derived-types.d.ts +26 -0
  67. package/dist/gen/abap/derived-types.js +323 -0
  68. package/dist/gen/abap/derived-types.js.map +1 -0
  69. package/dist/gen/abap/eml.d.ts +118 -0
  70. package/dist/gen/abap/eml.js +362 -0
  71. package/dist/gen/abap/eml.js.map +1 -0
  72. package/dist/gen/abap/enums.d.ts +13 -0
  73. package/dist/gen/abap/enums.js +74 -0
  74. package/dist/gen/abap/enums.js.map +1 -0
  75. package/dist/gen/abap/framework-http.d.ts +14 -0
  76. package/dist/gen/abap/framework-http.js +1049 -0
  77. package/dist/gen/abap/framework-http.js.map +1 -0
  78. package/dist/gen/abap/framework-query.d.ts +14 -0
  79. package/dist/gen/abap/framework-query.js +225 -0
  80. package/dist/gen/abap/framework-query.js.map +1 -0
  81. package/dist/gen/abap/framework-utils.d.ts +29 -0
  82. package/dist/gen/abap/framework-utils.js +3707 -0
  83. package/dist/gen/abap/framework-utils.js.map +1 -0
  84. package/dist/gen/abap/framework.d.ts +12 -0
  85. package/dist/gen/abap/framework.js +480 -0
  86. package/dist/gen/abap/framework.js.map +1 -0
  87. package/dist/gen/abap/generate.d.ts +40 -0
  88. package/dist/gen/abap/generate.js +238 -0
  89. package/dist/gen/abap/generate.js.map +1 -0
  90. package/dist/gen/abap/rewrite.d.ts +82 -0
  91. package/dist/gen/abap/rewrite.js +957 -0
  92. package/dist/gen/abap/rewrite.js.map +1 -0
  93. package/dist/gen/abap/shadow.d.ts +25 -0
  94. package/dist/gen/abap/shadow.js +175 -0
  95. package/dist/gen/abap/shadow.js.map +1 -0
  96. package/dist/gen/abap/tokens.d.ts +33 -0
  97. package/dist/gen/abap/tokens.js +87 -0
  98. package/dist/gen/abap/tokens.js.map +1 -0
  99. package/dist/gen/app/index.d.ts +25 -0
  100. package/dist/gen/app/index.js +322 -0
  101. package/dist/gen/app/index.js.map +1 -0
  102. package/dist/gen/csdl.d.ts +11 -0
  103. package/dist/gen/csdl.js +562 -0
  104. package/dist/gen/csdl.js.map +1 -0
  105. package/dist/gen/deploy.d.ts +12 -0
  106. package/dist/gen/deploy.js +53 -0
  107. package/dist/gen/deploy.js.map +1 -0
  108. package/dist/gen/docs/index.d.ts +35 -0
  109. package/dist/gen/docs/index.js +267 -0
  110. package/dist/gen/docs/index.js.map +1 -0
  111. package/dist/gen/docs/markdown.d.ts +23 -0
  112. package/dist/gen/docs/markdown.js +187 -0
  113. package/dist/gen/docs/markdown.js.map +1 -0
  114. package/dist/gen/docs/site.d.ts +17 -0
  115. package/dist/gen/docs/site.js +106 -0
  116. package/dist/gen/docs/site.js.map +1 -0
  117. package/dist/gen/keycloak.d.ts +21 -0
  118. package/dist/gen/keycloak.js +90 -0
  119. package/dist/gen/keycloak.js.map +1 -0
  120. package/dist/gen/launchpad/index.d.ts +48 -0
  121. package/dist/gen/launchpad/index.js +302 -0
  122. package/dist/gen/launchpad/index.js.map +1 -0
  123. package/dist/gen/launchpad/ui.d.ts +14 -0
  124. package/dist/gen/launchpad/ui.js +350 -0
  125. package/dist/gen/launchpad/ui.js.map +1 -0
  126. package/dist/gen/mcp.d.ts +23 -0
  127. package/dist/gen/mcp.js +244 -0
  128. package/dist/gen/mcp.js.map +1 -0
  129. package/dist/gen/sql-expressions.d.ts +12 -0
  130. package/dist/gen/sql-expressions.js +136 -0
  131. package/dist/gen/sql-expressions.js.map +1 -0
  132. package/dist/gen/sql.d.ts +38 -0
  133. package/dist/gen/sql.js +612 -0
  134. package/dist/gen/sql.js.map +1 -0
  135. package/dist/gen/ui/index.d.ts +7 -0
  136. package/dist/gen/ui/index.js +27 -0
  137. package/dist/gen/ui/index.js.map +1 -0
  138. package/dist/gen/ui/layout.d.ts +230 -0
  139. package/dist/gen/ui/layout.js +511 -0
  140. package/dist/gen/ui/layout.js.map +1 -0
  141. package/dist/gen/ui/static.d.ts +55 -0
  142. package/dist/gen/ui/static.js +2901 -0
  143. package/dist/gen/ui/static.js.map +1 -0
  144. package/dist/gen/ui/views.d.ts +10 -0
  145. package/dist/gen/ui/views.js +511 -0
  146. package/dist/gen/ui/views.js.map +1 -0
  147. package/dist/gen/vendor.d.ts +23 -0
  148. package/dist/gen/vendor.js +68 -0
  149. package/dist/gen/vendor.js.map +1 -0
  150. package/dist/gen/xml.d.ts +9 -0
  151. package/dist/gen/xml.js +42 -0
  152. package/dist/gen/xml.js.map +1 -0
  153. package/dist/index.d.ts +20 -0
  154. package/dist/index.js +20 -0
  155. package/dist/index.js.map +1 -0
  156. package/dist/input/project.d.ts +50 -0
  157. package/dist/input/project.js +128 -0
  158. package/dist/input/project.js.map +1 -0
  159. package/dist/ir/access-controls.d.ts +11 -0
  160. package/dist/ir/access-controls.js +148 -0
  161. package/dist/ir/access-controls.js.map +1 -0
  162. package/dist/ir/authorizations.d.ts +25 -0
  163. package/dist/ir/authorizations.js +178 -0
  164. package/dist/ir/authorizations.js.map +1 -0
  165. package/dist/ir/behaviors.d.ts +16 -0
  166. package/dist/ir/behaviors.js +548 -0
  167. package/dist/ir/behaviors.js.map +1 -0
  168. package/dist/ir/builder.d.ts +20 -0
  169. package/dist/ir/builder.js +505 -0
  170. package/dist/ir/builder.js.map +1 -0
  171. package/dist/ir/config.d.ts +25 -0
  172. package/dist/ir/config.js +130 -0
  173. package/dist/ir/config.js.map +1 -0
  174. package/dist/ir/dictionary.d.ts +54 -0
  175. package/dist/ir/dictionary.js +328 -0
  176. package/dist/ir/dictionary.js.map +1 -0
  177. package/dist/ir/entities.d.ts +58 -0
  178. package/dist/ir/entities.js +676 -0
  179. package/dist/ir/entities.js.map +1 -0
  180. package/dist/ir/expressions.d.ts +33 -0
  181. package/dist/ir/expressions.js +327 -0
  182. package/dist/ir/expressions.js.map +1 -0
  183. package/dist/ir/handlers.d.ts +63 -0
  184. package/dist/ir/handlers.js +398 -0
  185. package/dist/ir/handlers.js.map +1 -0
  186. package/dist/ir/number-ranges.d.ts +24 -0
  187. package/dist/ir/number-ranges.js +74 -0
  188. package/dist/ir/number-ranges.js.map +1 -0
  189. package/dist/ir/seed.d.ts +23 -0
  190. package/dist/ir/seed.js +78 -0
  191. package/dist/ir/seed.js.map +1 -0
  192. package/dist/ir/service.d.ts +21 -0
  193. package/dist/ir/service.js +96 -0
  194. package/dist/ir/service.js.map +1 -0
  195. package/dist/launchpad/config.d.ts +47 -0
  196. package/dist/launchpad/config.js +321 -0
  197. package/dist/launchpad/config.js.map +1 -0
  198. package/dist/launchpad/workspace.d.ts +48 -0
  199. package/dist/launchpad/workspace.js +166 -0
  200. package/dist/launchpad/workspace.js.map +1 -0
  201. package/dist/srvd/parser.d.ts +36 -0
  202. package/dist/srvd/parser.js +193 -0
  203. package/dist/srvd/parser.js.map +1 -0
  204. package/dist/standard/data.d.ts +18 -0
  205. package/dist/standard/data.js +534 -0
  206. package/dist/standard/data.js.map +1 -0
  207. package/dist/standard/index.d.ts +36 -0
  208. package/dist/standard/index.js +507 -0
  209. package/dist/standard/index.js.map +1 -0
  210. package/dist/version.d.ts +2 -0
  211. package/dist/version.js +4 -0
  212. package/dist/version.js.map +1 -0
  213. package/docs/AGENTS.md +79 -0
  214. package/docs/ANNOTATIONS.md +76 -0
  215. package/docs/DECISIONS.md +1554 -0
  216. package/docs/DEPLOYMENT.md +113 -0
  217. package/docs/DIAGNOSTICS.md +116 -0
  218. package/docs/FEATURES.md +287 -0
  219. package/docs/GUIDE.md +560 -0
  220. package/docs/KNOWN_GAPS.md +216 -0
  221. package/docs/MCP.md +84 -0
  222. package/docs/PLAN.md +690 -0
  223. package/docs/README.md +148 -0
  224. package/docs/REMOTE_APIS.md +121 -0
  225. package/docs/ROADMAP.md +35 -0
  226. package/docs/UTILITIES.md +95 -0
  227. package/package.json +49 -3
@@ -0,0 +1,1012 @@
1
+ /**
2
+ * Chevrotain grammar of behavior definitions (decision D1).
3
+ *
4
+ * The grammar covers managed and projection BDEFs without draft. Statements it does not know are
5
+ * still recognized as "unknown" (up to the next `;` or a balanced `{ … }` block), so that the IR
6
+ * builder can report them precisely instead of failing with an opaque syntax error.
7
+ */
8
+ import { EmbeddedActionsParser } from "chevrotain";
9
+ import { allTokens, Any, bdefLexer, Colon, Comma, Dot, DotDot, Equals, Integer, K, LBracket, LCurly, LParen, Name, RBracket, RCurly, RParen, Semicolon, Star, StringLiteral, } from "./lexer.js";
10
+ function locOf(token) {
11
+ return { line: token?.startLine ?? 0, column: token?.startColumn ?? 0 };
12
+ }
13
+ /** Robust during the grammar recording phase, where OR() returns undefined. */
14
+ /** The image of a token; during the grammar recording phase tokens are placeholders. */
15
+ const img = (token) => (typeof token?.image === "string" ? token.image : "");
16
+ const isWord = (token, word) => img(token).toLowerCase() === word;
17
+ const lowerImage = (token) => img(token).toLowerCase();
18
+ function nameOf(token) {
19
+ return { text: img(token), loc: locOf(token) };
20
+ }
21
+ class BdefParser extends EmbeddedActionsParser {
22
+ source = "";
23
+ constructor() {
24
+ super(allTokens, { recoveryEnabled: false, maxLookahead: 2 });
25
+ this.performSelfAnalysis();
26
+ }
27
+ setSource(source) {
28
+ this.source = source;
29
+ }
30
+ textBetween(first, last) {
31
+ if (first === undefined || last === undefined || first.endOffset === undefined || last.endOffset === undefined) {
32
+ return "";
33
+ }
34
+ return this.source.substring(first.startOffset, last.endOffset + 1).replace(/\s+/g, " ").trim();
35
+ }
36
+ // -------------------------------------------------------------------------------------------
37
+ // top level
38
+ bdef = this.RULE("bdef", () => {
39
+ const headers = [];
40
+ const behaviors = [];
41
+ const others = [];
42
+ this.MANY(() => {
43
+ this.OR({
44
+ IGNORE_AMBIGUITIES: true,
45
+ DEF: [
46
+ {
47
+ GATE: () => isWord(this.LA(2), "behavior") || (isWord(this.LA(2), "root") && isWord(this.LA(3), "behavior")),
48
+ ALT: () => {
49
+ const behavior = this.SUBRULE(this.behavior);
50
+ this.ACTION(() => behaviors.push(behavior));
51
+ },
52
+ },
53
+ {
54
+ ALT: () => {
55
+ const header = this.SUBRULE(this.header);
56
+ this.ACTION(() => {
57
+ if (header.kind === "unknown" && /^(define|extend)\b/i.test(header.text)) {
58
+ others.push({ text: header.text, loc: header.loc });
59
+ }
60
+ else {
61
+ headers.push(header);
62
+ }
63
+ });
64
+ },
65
+ },
66
+ ],
67
+ });
68
+ });
69
+ return { headers, behaviors, others };
70
+ });
71
+ header = this.RULE("header", () => {
72
+ const start = locOf(this.LA(1));
73
+ return this.OR({
74
+ IGNORE_AMBIGUITIES: true,
75
+ DEF: [
76
+ {
77
+ ALT: () => {
78
+ const type = this.OR1([
79
+ { ALT: () => this.CONSUME(K.managed) },
80
+ { ALT: () => this.CONSUME(K.unmanaged) },
81
+ { ALT: () => this.CONSUME(K.abstract) },
82
+ { ALT: () => this.CONSUME(K.projection) },
83
+ { ALT: () => this.CONSUME(K.interface) },
84
+ ]);
85
+ // managed with additional save / with unmanaged save [with full data] [and cleanup]
86
+ let saving;
87
+ this.OPTION7(() => {
88
+ this.CONSUME2(K.with);
89
+ const variant = this.OR7([
90
+ { ALT: () => this.CONSUME(K.additional) },
91
+ { ALT: () => this.CONSUME1(K.unmanaged) },
92
+ ]);
93
+ this.CONSUME(K.save);
94
+ let fullData = false;
95
+ this.MANY7({
96
+ GATE: () => ["and", "cleanup", "full", "data"].includes(lowerImage(this.LA(1))) || (isWord(this.LA(1), "with") && isWord(this.LA(2), "full")),
97
+ DEF: () => {
98
+ if (lowerImage(this.CONSUME7(Name)) === "full") {
99
+ fullData = true;
100
+ }
101
+ },
102
+ });
103
+ saving = { variant: isWord(variant, "additional") ? "additional" : "unmanaged", fullData };
104
+ });
105
+ let className;
106
+ let unique = false;
107
+ this.OPTION(() => {
108
+ this.CONSUME(K.implementation);
109
+ this.CONSUME(K.in);
110
+ this.CONSUME(K.class);
111
+ className = nameOf(this.CONSUME(Name));
112
+ this.OPTION1(() => {
113
+ this.CONSUME(K.unique);
114
+ unique = true;
115
+ });
116
+ });
117
+ this.CONSUME(Semicolon);
118
+ const item = { kind: "implementation", type: lowerImage(type), unique, loc: start };
119
+ if (className !== undefined) {
120
+ item.className = className;
121
+ }
122
+ if (saving !== undefined) {
123
+ item.saving = saving;
124
+ }
125
+ return item;
126
+ },
127
+ },
128
+ {
129
+ ALT: () => {
130
+ this.CONSUME(K.strict);
131
+ let version = 1;
132
+ this.OPTION2(() => {
133
+ this.CONSUME(LParen);
134
+ const v = this.CONSUME(Integer);
135
+ this.CONSUME(RParen);
136
+ version = Number.parseInt(img(v), 10);
137
+ });
138
+ this.CONSUME1(Semicolon);
139
+ return { kind: "strict", version, loc: start };
140
+ },
141
+ },
142
+ {
143
+ ALT: () => {
144
+ this.CONSUME(K.with);
145
+ let collaborative = false;
146
+ this.OPTION9(() => {
147
+ this.CONSUME(K.collaborative);
148
+ collaborative = true;
149
+ });
150
+ this.CONSUME(K.draft);
151
+ this.CONSUME2(Semicolon);
152
+ return collaborative ? { kind: "withDraft", collaborative: true, loc: start } : { kind: "withDraft", loc: start };
153
+ },
154
+ },
155
+ {
156
+ ALT: () => {
157
+ this.CONSUME1(K.with);
158
+ this.CONSUME(K.privileged);
159
+ this.CONSUME(K.mode);
160
+ let disabling;
161
+ this.OPTION3(() => {
162
+ this.CONSUME(K.disabling);
163
+ disabling = nameOf(this.CONSUME1(Name));
164
+ });
165
+ this.CONSUME3(Semicolon);
166
+ return disabling === undefined ? { kind: "privilegedMode", loc: start } : { kind: "privilegedMode", disabling, loc: start };
167
+ },
168
+ },
169
+ {
170
+ ALT: () => {
171
+ this.CONSUME(K.foreign);
172
+ this.CONSUME(K.entity);
173
+ const name = nameOf(this.CONSUME2(Name));
174
+ this.CONSUME4(Semicolon);
175
+ return { kind: "foreignEntity", name, loc: start };
176
+ },
177
+ },
178
+ {
179
+ ALT: () => {
180
+ this.CONSUME(K.use);
181
+ const words = [];
182
+ this.AT_LEAST_ONE(() => {
183
+ words.push(lowerImage(this.CONSUME3(Name)));
184
+ });
185
+ this.CONSUME5(Semicolon);
186
+ return { kind: "use", what: words.join(" "), loc: start };
187
+ },
188
+ },
189
+ {
190
+ ALT: () => {
191
+ const text = this.SUBRULE(this.unknownStatement);
192
+ return { kind: "unknown", text, loc: start };
193
+ },
194
+ },
195
+ ],
196
+ });
197
+ });
198
+ /**
199
+ * Tokens up to the next `;` (consumed) or up to the end of a balanced `{ … }` block (followed by
200
+ * an optional `;`): a block ends a statement, as in `determine action x { … }`.
201
+ */
202
+ unknownStatement = this.RULE("unknownStatement", () => {
203
+ const first = this.LA(1);
204
+ let last;
205
+ this.OR([
206
+ {
207
+ ALT: () => {
208
+ this.AT_LEAST_ONE(() => {
209
+ last = this.CONSUME(Any);
210
+ });
211
+ this.OPTION(() => {
212
+ last = this.SUBRULE(this.braceBlock);
213
+ });
214
+ },
215
+ },
216
+ { ALT: () => { last = this.SUBRULE1(this.braceBlock); } },
217
+ ]);
218
+ this.OPTION1(() => {
219
+ last = this.CONSUME(Semicolon);
220
+ });
221
+ return this.ACTION(() => this.textBetween(first, last));
222
+ });
223
+ braceBlock = this.RULE("braceBlock", () => {
224
+ this.CONSUME(LCurly);
225
+ this.MANY(() => {
226
+ this.OR([
227
+ { ALT: () => this.CONSUME(Any) },
228
+ { ALT: () => this.CONSUME(Semicolon) },
229
+ { ALT: () => this.SUBRULE(this.braceBlock) },
230
+ ]);
231
+ });
232
+ return this.CONSUME(RCurly);
233
+ });
234
+ // -------------------------------------------------------------------------------------------
235
+ // define behavior for
236
+ behavior = this.RULE("behavior", () => {
237
+ const start = locOf(this.CONSUME(K.define));
238
+ let root = false;
239
+ this.OPTION(() => {
240
+ this.CONSUME(K.root);
241
+ root = true;
242
+ });
243
+ this.CONSUME(K.behavior);
244
+ this.CONSUME(K.for);
245
+ const entity = nameOf(this.CONSUME(Name));
246
+ let alias;
247
+ this.OPTION1(() => {
248
+ this.CONSUME(K.alias);
249
+ alias = nameOf(this.CONSUME1(Name));
250
+ });
251
+ const options = [];
252
+ this.MANY(() => {
253
+ const option = this.SUBRULE(this.entityOption);
254
+ this.ACTION(() => {
255
+ const previous = options[options.length - 1];
256
+ if (option.kind === "unknown" && previous?.kind === "unknown") {
257
+ previous.text = `${previous.text} ${option.text}`;
258
+ }
259
+ else {
260
+ options.push(option);
261
+ }
262
+ });
263
+ });
264
+ this.CONSUME(LCurly);
265
+ const items = [];
266
+ this.MANY1(() => {
267
+ const item = this.SUBRULE(this.bodyItem);
268
+ this.ACTION(() => items.push(item));
269
+ });
270
+ this.CONSUME(RCurly);
271
+ this.OPTION2(() => this.CONSUME(Semicolon));
272
+ const behavior = { root, entity, options, items, loc: start };
273
+ if (alias !== undefined) {
274
+ behavior.alias = alias;
275
+ }
276
+ return behavior;
277
+ });
278
+ entityOption = this.RULE("entityOption", () => {
279
+ const start = locOf(this.LA(1));
280
+ return this.OR({
281
+ IGNORE_AMBIGUITIES: true,
282
+ DEF: [
283
+ {
284
+ ALT: () => {
285
+ this.CONSUME(K.persistent);
286
+ this.CONSUME(K.table);
287
+ return { kind: "persistentTable", table: nameOf(this.CONSUME(Name)), loc: start };
288
+ },
289
+ },
290
+ {
291
+ ALT: () => {
292
+ this.CONSUME(K.draft);
293
+ this.CONSUME1(K.table);
294
+ return { kind: "draftTable", table: nameOf(this.CONSUME1(Name)), loc: start };
295
+ },
296
+ },
297
+ {
298
+ ALT: () => {
299
+ this.CONSUME(K.lock);
300
+ this.CONSUME(K.master);
301
+ let unmanaged = false;
302
+ this.OPTION(() => {
303
+ this.CONSUME(K.unmanaged);
304
+ unmanaged = true;
305
+ });
306
+ return { kind: "lockMaster", unmanaged, loc: start };
307
+ },
308
+ },
309
+ {
310
+ ALT: () => {
311
+ this.CONSUME1(K.lock);
312
+ this.CONSUME(K.dependent);
313
+ let by;
314
+ this.OPTION1(() => {
315
+ this.CONSUME(K.by);
316
+ by = nameOf(this.CONSUME2(Name));
317
+ });
318
+ this.OPTION2(() => this.SUBRULE(this.parenthesized));
319
+ return by === undefined ? { kind: "lockDependent", loc: start } : { kind: "lockDependent", by, loc: start };
320
+ },
321
+ },
322
+ {
323
+ ALT: () => {
324
+ this.CONSUME(K.authorization);
325
+ this.CONSUME1(K.master);
326
+ const values = this.SUBRULE1(this.parenthesized);
327
+ return { kind: "authorizationMaster", values, loc: start };
328
+ },
329
+ },
330
+ {
331
+ ALT: () => {
332
+ this.CONSUME1(K.authorization);
333
+ this.CONSUME1(K.dependent);
334
+ let by;
335
+ this.OPTION3(() => {
336
+ this.CONSUME1(K.by);
337
+ by = nameOf(this.CONSUME3(Name));
338
+ });
339
+ return by === undefined ? { kind: "authorizationDependent", loc: start } : { kind: "authorizationDependent", by, loc: start };
340
+ },
341
+ },
342
+ {
343
+ ALT: () => {
344
+ this.CONSUME(K.etag);
345
+ this.CONSUME2(K.master);
346
+ return { kind: "etagMaster", field: nameOf(this.CONSUME4(Name)), loc: start };
347
+ },
348
+ },
349
+ {
350
+ ALT: () => {
351
+ this.CONSUME1(K.etag);
352
+ this.CONSUME2(K.dependent);
353
+ let by;
354
+ this.OPTION4(() => {
355
+ this.CONSUME2(K.by);
356
+ by = nameOf(this.CONSUME5(Name));
357
+ });
358
+ return by === undefined ? { kind: "etagDependent", loc: start } : { kind: "etagDependent", by, loc: start };
359
+ },
360
+ },
361
+ {
362
+ ALT: () => {
363
+ this.CONSUME(K.total);
364
+ this.CONSUME2(K.etag);
365
+ return { kind: "totalEtag", field: nameOf(this.CONSUME6(Name)), loc: start };
366
+ },
367
+ },
368
+ {
369
+ ALT: () => {
370
+ this.CONSUME(K.early);
371
+ this.CONSUME(K.numbering);
372
+ return { kind: "earlyNumbering", loc: start };
373
+ },
374
+ },
375
+ {
376
+ ALT: () => {
377
+ this.CONSUME(K.late);
378
+ this.CONSUME1(K.numbering);
379
+ let inPlace = false;
380
+ this.OPTION5(() => {
381
+ this.CONSUME(K.in);
382
+ this.CONSUME(K.place);
383
+ inPlace = true;
384
+ });
385
+ return { kind: "lateNumbering", inPlace, loc: start };
386
+ },
387
+ },
388
+ {
389
+ ALT: () => {
390
+ this.CONSUME(K.implementation);
391
+ this.CONSUME1(K.in);
392
+ this.CONSUME(K.class);
393
+ const className = nameOf(this.CONSUME7(Name));
394
+ let unique = false;
395
+ this.OPTION6(() => {
396
+ this.CONSUME(K.unique);
397
+ unique = true;
398
+ });
399
+ return { kind: "implementationInClass", className, unique, loc: start };
400
+ },
401
+ },
402
+ {
403
+ ALT: () => {
404
+ this.CONSUME(K.with);
405
+ const variant = this.OR1([
406
+ { ALT: () => this.CONSUME(K.additional) },
407
+ { ALT: () => this.CONSUME1(K.unmanaged) },
408
+ ]);
409
+ this.CONSUME(K.save);
410
+ // "and cleanup", "with full data"
411
+ let fullData = false;
412
+ this.MANY({
413
+ GATE: () => ["and", "cleanup", "full", "data"].includes(lowerImage(this.LA(1))) || (isWord(this.LA(1), "with") && isWord(this.LA(2), "full")),
414
+ DEF: () => {
415
+ if (lowerImage(this.CONSUME8(Name)) === "full") {
416
+ fullData = true;
417
+ }
418
+ },
419
+ });
420
+ return { kind: "withSave", variant: isWord(variant, "additional") ? "additional" : "unmanaged", fullData, loc: start };
421
+ },
422
+ },
423
+ {
424
+ ALT: () => {
425
+ this.CONSUME(K.use);
426
+ this.CONSUME3(K.etag);
427
+ return { kind: "useEtag", loc: start };
428
+ },
429
+ },
430
+ {
431
+ ALT: () => {
432
+ const token = this.CONSUME(Any);
433
+ return { kind: "unknown", text: img(token), loc: start };
434
+ },
435
+ },
436
+ ],
437
+ });
438
+ });
439
+ /** `( a, b : c )`: the words, `name:value` for pairs. */
440
+ parenthesized = this.RULE("parenthesized", () => {
441
+ const values = [];
442
+ this.CONSUME(LParen);
443
+ this.MANY_SEP({
444
+ SEP: Comma,
445
+ DEF: () => {
446
+ const option = this.SUBRULE(this.optionItem);
447
+ this.ACTION(() => values.push(option.value === undefined ? option.name : `${option.name}:${option.value}`));
448
+ },
449
+ });
450
+ this.CONSUME(RParen);
451
+ return values;
452
+ });
453
+ optionItem = this.RULE("optionItem", () => {
454
+ const first = this.CONSUME(Name);
455
+ let value;
456
+ this.OPTION(() => {
457
+ this.CONSUME(Colon);
458
+ value = lowerImage(this.CONSUME1(Name));
459
+ });
460
+ const option = { name: lowerImage(first), loc: locOf(first) };
461
+ if (value !== undefined) {
462
+ option.value = value;
463
+ }
464
+ return option;
465
+ });
466
+ operationOptions = this.RULE("operationOptions", () => {
467
+ const options = [];
468
+ this.CONSUME(LParen);
469
+ this.MANY_SEP({
470
+ SEP: Comma,
471
+ DEF: () => {
472
+ const option = this.SUBRULE(this.optionItem);
473
+ this.ACTION(() => options.push(option));
474
+ },
475
+ });
476
+ this.CONSUME(RParen);
477
+ return options;
478
+ });
479
+ // -------------------------------------------------------------------------------------------
480
+ // entity body
481
+ bodyItem = this.RULE("bodyItem", () => {
482
+ return this.OR({
483
+ IGNORE_AMBIGUITIES: true,
484
+ DEF: [
485
+ { ALT: () => this.SUBRULE(this.operation) },
486
+ { ALT: () => this.SUBRULE(this.useItem) },
487
+ { ALT: () => this.SUBRULE(this.association) },
488
+ { ALT: () => this.SUBRULE(this.fieldItem) },
489
+ { ALT: () => this.SUBRULE(this.determination) },
490
+ { ALT: () => this.SUBRULE(this.validation) },
491
+ { ALT: () => this.SUBRULE(this.action) },
492
+ { ALT: () => this.SUBRULE(this.mapping) },
493
+ { ALT: () => this.SUBRULE(this.sideEffects) },
494
+ {
495
+ ALT: () => {
496
+ const start = locOf(this.LA(1));
497
+ const what = this.OR1([
498
+ { ALT: () => img(this.CONSUME(K.draft)) },
499
+ { ALT: () => img(this.CONSUME(K.event)) },
500
+ { ALT: () => `${img(this.CONSUME(K.determine))} ${img(this.CONSUME(K.action))}` },
501
+ ]);
502
+ const text = this.SUBRULE(this.unknownStatement);
503
+ const word = typeof what === "string" ? what : "";
504
+ return { kind: "unsupported", what: word.toLowerCase(), text: `${word} ${typeof text === "string" ? text : ""}`, loc: start };
505
+ },
506
+ },
507
+ {
508
+ ALT: () => {
509
+ const start = locOf(this.LA(1));
510
+ const text = this.SUBRULE1(this.unknownStatement);
511
+ return { kind: "unknown", text, loc: start };
512
+ },
513
+ },
514
+ ],
515
+ });
516
+ });
517
+ operation = this.RULE("operation", () => {
518
+ const start = locOf(this.LA(1));
519
+ let internal = false;
520
+ this.OPTION(() => {
521
+ this.CONSUME(K.internal);
522
+ internal = true;
523
+ });
524
+ const op = this.OR([
525
+ { ALT: () => this.CONSUME(K.create) },
526
+ { ALT: () => this.CONSUME(K.update) },
527
+ { ALT: () => this.CONSUME(K.delete) },
528
+ ]);
529
+ let options = [];
530
+ this.OPTION1(() => {
531
+ options = this.SUBRULE(this.operationOptions);
532
+ });
533
+ this.CONSUME(Semicolon);
534
+ return { kind: "operation", op: lowerImage(op), internal, options, loc: start };
535
+ });
536
+ useItem = this.RULE("useItem", () => {
537
+ const start = locOf(this.CONSUME(K.use));
538
+ return this.OR([
539
+ {
540
+ ALT: () => {
541
+ const op = this.OR1([
542
+ { ALT: () => this.CONSUME(K.create) },
543
+ { ALT: () => this.CONSUME(K.update) },
544
+ { ALT: () => this.CONSUME(K.delete) },
545
+ ]);
546
+ let options = [];
547
+ this.OPTION(() => {
548
+ options = this.SUBRULE(this.operationOptions);
549
+ });
550
+ this.CONSUME(Semicolon);
551
+ return { kind: "useOperation", op: lowerImage(op), options, loc: start };
552
+ },
553
+ },
554
+ {
555
+ ALT: () => {
556
+ const kind = this.OR2([
557
+ { ALT: () => this.CONSUME(K.action) },
558
+ { ALT: () => this.CONSUME(K.function) },
559
+ ]);
560
+ const name = nameOf(this.CONSUME(Name));
561
+ let alias;
562
+ this.OPTION1({
563
+ GATE: () => isWord(this.LA(1), "as"),
564
+ DEF: () => {
565
+ this.CONSUME1(Name);
566
+ alias = nameOf(this.CONSUME2(Name));
567
+ },
568
+ });
569
+ this.OPTION2(() => {
570
+ this.CONSUME(K.external);
571
+ this.CONSUME(StringLiteral);
572
+ });
573
+ this.CONSUME1(Semicolon);
574
+ const item = { kind: "useAction", actionKind: isWord(kind, "function") ? "function" : "action", name, loc: start };
575
+ if (alias !== undefined) {
576
+ item.alias = alias;
577
+ }
578
+ return item;
579
+ },
580
+ },
581
+ {
582
+ ALT: () => {
583
+ this.CONSUME(K.association);
584
+ const name = nameOf(this.CONSUME3(Name));
585
+ let create = false;
586
+ let withDraft = false;
587
+ this.OR3([
588
+ {
589
+ ALT: () => {
590
+ this.CONSUME(LCurly);
591
+ this.MANY(() => {
592
+ this.OR4([
593
+ {
594
+ ALT: () => {
595
+ this.CONSUME1(K.create);
596
+ this.OPTION3(() => this.SUBRULE1(this.operationOptions));
597
+ this.CONSUME2(Semicolon);
598
+ create = true;
599
+ },
600
+ },
601
+ {
602
+ ALT: () => {
603
+ this.CONSUME(K.with);
604
+ this.CONSUME(K.draft);
605
+ this.CONSUME3(Semicolon);
606
+ withDraft = true;
607
+ },
608
+ },
609
+ ]);
610
+ });
611
+ this.CONSUME(RCurly);
612
+ },
613
+ },
614
+ { ALT: () => this.CONSUME4(Semicolon) },
615
+ ]);
616
+ return { kind: "useAssociation", name, create, withDraft, loc: start };
617
+ },
618
+ },
619
+ ]);
620
+ });
621
+ association = this.RULE("association", () => {
622
+ const start = locOf(this.LA(1));
623
+ let internal = false;
624
+ this.OPTION(() => {
625
+ this.CONSUME(K.internal);
626
+ internal = true;
627
+ });
628
+ this.CONSUME(K.association);
629
+ const name = nameOf(this.CONSUME(Name));
630
+ let abbreviation;
631
+ this.OPTION1(() => {
632
+ this.CONSUME(K.abbreviation);
633
+ abbreviation = nameOf(this.CONSUME1(Name));
634
+ });
635
+ let create;
636
+ let withDraft = false;
637
+ this.OR([
638
+ {
639
+ ALT: () => {
640
+ this.CONSUME(LCurly);
641
+ this.MANY(() => {
642
+ this.OR1([
643
+ {
644
+ ALT: () => {
645
+ let createInternal = false;
646
+ this.OPTION2(() => {
647
+ this.CONSUME1(K.internal);
648
+ createInternal = true;
649
+ });
650
+ this.CONSUME(K.create);
651
+ let options = [];
652
+ this.OPTION3(() => {
653
+ options = this.SUBRULE(this.operationOptions);
654
+ });
655
+ this.CONSUME(Semicolon);
656
+ create = { internal: createInternal, options };
657
+ },
658
+ },
659
+ {
660
+ ALT: () => {
661
+ this.CONSUME(K.with);
662
+ this.CONSUME(K.draft);
663
+ this.CONSUME1(Semicolon);
664
+ withDraft = true;
665
+ },
666
+ },
667
+ ]);
668
+ });
669
+ this.CONSUME(RCurly);
670
+ },
671
+ },
672
+ { ALT: () => this.CONSUME2(Semicolon) },
673
+ ]);
674
+ const item = { kind: "association", name, internal, withDraft, loc: start };
675
+ if (abbreviation !== undefined) {
676
+ item.abbreviation = abbreviation;
677
+ }
678
+ if (create !== undefined) {
679
+ item.create = create;
680
+ }
681
+ return item;
682
+ });
683
+ fieldItem = this.RULE("fieldItem", () => {
684
+ const start = locOf(this.CONSUME(K.field));
685
+ const characteristics = [];
686
+ this.CONSUME(LParen);
687
+ this.AT_LEAST_ONE_SEP({
688
+ SEP: Comma,
689
+ DEF: () => {
690
+ const option = this.SUBRULE(this.optionItem);
691
+ this.ACTION(() => characteristics.push({ text: option.value === undefined ? option.name : `${option.name}:${option.value}`, loc: option.loc }));
692
+ },
693
+ });
694
+ this.CONSUME(RParen);
695
+ const fields = [];
696
+ this.AT_LEAST_ONE_SEP1({
697
+ SEP: Comma,
698
+ DEF: () => {
699
+ fields.push(nameOf(this.CONSUME(Name)));
700
+ },
701
+ });
702
+ this.CONSUME(Semicolon);
703
+ return { kind: "field", characteristics, fields, loc: start };
704
+ });
705
+ triggers = this.RULE("triggers", () => {
706
+ const triggers = { create: false, update: false, delete: false, fields: [] };
707
+ this.CONSUME(LCurly);
708
+ this.MANY(() => {
709
+ this.OR([
710
+ {
711
+ ALT: () => {
712
+ this.CONSUME(K.create);
713
+ this.CONSUME(Semicolon);
714
+ triggers.create = true;
715
+ },
716
+ },
717
+ {
718
+ ALT: () => {
719
+ this.CONSUME(K.update);
720
+ this.CONSUME1(Semicolon);
721
+ triggers.update = true;
722
+ },
723
+ },
724
+ {
725
+ ALT: () => {
726
+ this.CONSUME(K.delete);
727
+ this.CONSUME2(Semicolon);
728
+ triggers.delete = true;
729
+ },
730
+ },
731
+ {
732
+ ALT: () => {
733
+ this.CONSUME(K.field);
734
+ this.AT_LEAST_ONE_SEP({
735
+ SEP: Comma,
736
+ DEF: () => {
737
+ const first = this.CONSUME(Name);
738
+ let text = img(first);
739
+ this.MANY1(() => {
740
+ this.CONSUME(Dot);
741
+ text += `.${img(this.CONSUME1(Name))}`;
742
+ });
743
+ triggers.fields.push({ text, loc: locOf(first) });
744
+ },
745
+ });
746
+ this.CONSUME3(Semicolon);
747
+ },
748
+ },
749
+ ]);
750
+ });
751
+ this.CONSUME(RCurly);
752
+ return triggers;
753
+ });
754
+ determination = this.RULE("determination", () => {
755
+ const start = locOf(this.LA(1));
756
+ let internal = false;
757
+ this.OPTION(() => {
758
+ this.CONSUME(K.internal);
759
+ internal = true;
760
+ });
761
+ this.CONSUME(K.determination);
762
+ const name = nameOf(this.CONSUME(Name));
763
+ this.CONSUME(K.on);
764
+ const on = this.OR([
765
+ { ALT: () => this.CONSUME(K.modify) },
766
+ { ALT: () => this.CONSUME(K.save) },
767
+ ]);
768
+ const triggers = this.SUBRULE(this.triggers);
769
+ this.OPTION1(() => this.CONSUME(Semicolon));
770
+ return { kind: "determination", name, on: isWord(on, "save") ? "save" : "modify", internal, triggers, loc: start };
771
+ });
772
+ validation = this.RULE("validation", () => {
773
+ const start = locOf(this.CONSUME(K.validation));
774
+ const name = nameOf(this.CONSUME(Name));
775
+ this.CONSUME(K.on);
776
+ this.CONSUME(K.save);
777
+ const triggers = this.SUBRULE(this.triggers);
778
+ this.OPTION(() => this.CONSUME(Semicolon));
779
+ return { kind: "validation", name, on: "save", triggers, loc: start };
780
+ });
781
+ cardinality = this.RULE("cardinality", () => {
782
+ this.CONSUME(LBracket);
783
+ const bound = () => this.OR([
784
+ { ALT: () => Number.parseInt(this.CONSUME(Integer).image, 10) },
785
+ { ALT: () => { this.CONSUME(Star); return "*"; } },
786
+ ]);
787
+ const min = bound();
788
+ let max = min;
789
+ this.OPTION(() => {
790
+ this.CONSUME(DotDot);
791
+ max = this.OR1([
792
+ { ALT: () => Number.parseInt(this.CONSUME1(Integer).image, 10) },
793
+ { ALT: () => { this.CONSUME1(Star); return "*"; } },
794
+ ]);
795
+ });
796
+ this.CONSUME(RBracket);
797
+ return { min: min === "*" ? 0 : min, max };
798
+ });
799
+ action = this.RULE("action", () => {
800
+ const start = locOf(this.LA(1));
801
+ let internal = false;
802
+ let isStatic = false;
803
+ let factory = false;
804
+ this.MANY(() => {
805
+ this.OR([
806
+ { ALT: () => { this.CONSUME(K.internal); internal = true; } },
807
+ { ALT: () => { this.CONSUME(K.static); isStatic = true; } },
808
+ { ALT: () => { this.CONSUME(K.factory); factory = true; } },
809
+ ]);
810
+ });
811
+ const kind = this.OR1([
812
+ { ALT: () => this.CONSUME(K.action) },
813
+ { ALT: () => this.CONSUME(K.function) },
814
+ ]);
815
+ let options = [];
816
+ this.OPTION(() => {
817
+ options = this.SUBRULE(this.operationOptions);
818
+ });
819
+ const name = nameOf(this.CONSUME(Name));
820
+ let external;
821
+ this.OPTION1(() => {
822
+ this.CONSUME(K.external);
823
+ external = img(this.CONSUME(StringLiteral)).slice(1, -1);
824
+ });
825
+ let parameter;
826
+ this.OPTION2(() => {
827
+ this.CONSUME(K.parameter);
828
+ parameter = nameOf(this.CONSUME1(Name));
829
+ });
830
+ let result;
831
+ let factoryCardinality;
832
+ this.OPTION3(() => {
833
+ this.OR2([
834
+ {
835
+ ALT: () => {
836
+ this.CONSUME(K.result);
837
+ let selective = false;
838
+ this.OPTION4(() => {
839
+ this.CONSUME(K.selective);
840
+ selective = true;
841
+ });
842
+ const cardinality = this.SUBRULE(this.cardinality);
843
+ let entityKeyword = false;
844
+ this.OPTION5(() => {
845
+ this.CONSUME(K.entity);
846
+ entityKeyword = true;
847
+ });
848
+ const entity = nameOf(this.CONSUME2(Name));
849
+ result = { selective, cardinality, entity, entityKeyword };
850
+ },
851
+ },
852
+ { ALT: () => { factoryCardinality = this.SUBRULE1(this.cardinality); } },
853
+ ]);
854
+ });
855
+ // default value functions and similar blocks: `{ default function … ; }`
856
+ this.OPTION6(() => this.SUBRULE(this.braceBlock));
857
+ this.OPTION7(() => this.CONSUME(Semicolon));
858
+ const item = {
859
+ kind: "action",
860
+ actionKind: isWord(kind, "function") ? "function" : "action",
861
+ name,
862
+ internal,
863
+ static: isStatic,
864
+ factory,
865
+ options,
866
+ loc: start,
867
+ };
868
+ if (external !== undefined) {
869
+ item.external = external;
870
+ }
871
+ if (parameter !== undefined) {
872
+ item.parameter = parameter;
873
+ }
874
+ if (result !== undefined) {
875
+ item.result = result;
876
+ }
877
+ if (factoryCardinality !== undefined) {
878
+ item.factoryCardinality = factoryCardinality;
879
+ }
880
+ return item;
881
+ });
882
+ mapping = this.RULE("mapping", () => {
883
+ const start = locOf(this.CONSUME(K.mapping));
884
+ this.CONSUME(K.for);
885
+ const table = nameOf(this.CONSUME(Name));
886
+ let corresponding = false;
887
+ this.OPTION(() => {
888
+ this.CONSUME(K.corresponding);
889
+ corresponding = true;
890
+ });
891
+ // "control <structure>" and other additions before the block
892
+ this.MANY({
893
+ GATE: () => this.LA(1).tokenType !== LCurly,
894
+ DEF: () => this.CONSUME(Any),
895
+ });
896
+ const pairs = [];
897
+ this.OR([
898
+ {
899
+ ALT: () => {
900
+ this.CONSUME(LCurly);
901
+ this.MANY1(() => {
902
+ const field = nameOf(this.CONSUME1(Name));
903
+ this.CONSUME(Equals);
904
+ const column = nameOf(this.CONSUME2(Name));
905
+ this.MANY2(() => this.CONSUME1(Any));
906
+ this.CONSUME(Semicolon);
907
+ pairs.push({ field, column });
908
+ });
909
+ this.CONSUME(RCurly);
910
+ this.OPTION1(() => this.CONSUME1(Semicolon));
911
+ },
912
+ },
913
+ { ALT: () => this.CONSUME2(Semicolon) },
914
+ ]);
915
+ return { kind: "mapping", table, corresponding, pairs, loc: start };
916
+ });
917
+ sideEffects = this.RULE("sideEffects", () => {
918
+ const start = locOf(this.CONSUME(K.side));
919
+ this.CONSUME(K.effects);
920
+ this.CONSUME(LCurly);
921
+ const items = [];
922
+ this.MANY(() => {
923
+ const tokens = [];
924
+ this.AT_LEAST_ONE(() => tokens.push(this.CONSUME(Any)));
925
+ this.CONSUME(Semicolon);
926
+ this.ACTION(() => {
927
+ const item = interpretSideEffect(tokens);
928
+ if (item !== undefined) {
929
+ items.push(item);
930
+ }
931
+ });
932
+ });
933
+ this.CONSUME(RCurly);
934
+ this.OPTION(() => this.CONSUME1(Semicolon));
935
+ return { kind: "sideEffects", items, loc: start };
936
+ });
937
+ }
938
+ /** `field A affects field B, entity _X, messages;` and `action a affects …`. */
939
+ function interpretSideEffect(tokens) {
940
+ const words = tokens.map((t) => t.image);
941
+ const lower = words.map((w) => w.toLowerCase());
942
+ const affects = lower.indexOf("affects");
943
+ if (affects < 2 || tokens[0] === undefined) {
944
+ return undefined;
945
+ }
946
+ let trigger;
947
+ if (lower[0] === "determine" && lower[1] === "action" && tokens[2] !== undefined) {
948
+ trigger = { kind: "determineAction", name: nameOf(tokens[2]) };
949
+ }
950
+ else if ((lower[0] === "field" || lower[0] === "action") && tokens[1] !== undefined) {
951
+ trigger = { kind: lower[0], name: nameOf(tokens[1]) };
952
+ }
953
+ else {
954
+ return undefined;
955
+ }
956
+ const targets = [];
957
+ const rest = words.slice(affects + 1).join(" ").split(/\s*,\s*/);
958
+ for (const part of rest) {
959
+ const [kind, ...path] = part.trim().split(/\s+/);
960
+ const k = (kind ?? "").toLowerCase();
961
+ if (k === "field" || k === "entity") {
962
+ targets.push({ kind: k, path: path.join("").replace(/\s/g, "") });
963
+ }
964
+ else if (k === "messages") {
965
+ targets.push({ kind: "messages", path: "" });
966
+ }
967
+ else if (k === "permissions") {
968
+ targets.push({ kind: "permissions", path: path.join(" ") });
969
+ }
970
+ else if (k !== "") {
971
+ targets.push({ kind: "unknown", path: part.trim() });
972
+ }
973
+ }
974
+ return { trigger, targets, loc: locOf(tokens[0]) };
975
+ }
976
+ let parserInstance;
977
+ /** Parses a BDEF source. Returns the AST, or the lexing/parsing errors with their positions. */
978
+ export function parseBdef(source) {
979
+ const lexed = bdefLexer.tokenize(source);
980
+ const errors = lexed.errors.map((e) => ({
981
+ message: `unexpected character "${source.substr(e.offset, e.length)}"`,
982
+ line: e.line ?? 0,
983
+ column: e.column ?? 0,
984
+ }));
985
+ if (errors.length > 0) {
986
+ return { errors };
987
+ }
988
+ parserInstance ??= new BdefParser();
989
+ const parser = parserInstance;
990
+ parser.setSource(source);
991
+ parser.input = lexed.tokens;
992
+ const ast = parser.bdef();
993
+ for (const e of parser.errors) {
994
+ const token = e.token;
995
+ const found = token.tokenType.name === "EOF" ? "end of file" : `"${token.image}"`;
996
+ errors.push({
997
+ message: `syntax error at ${found}: ${simplifyChevrotainMessage(e.message)}`,
998
+ line: Number.isFinite(token.startLine) ? token.startLine : lastLine(source),
999
+ column: Number.isFinite(token.startColumn) ? token.startColumn : 1,
1000
+ });
1001
+ }
1002
+ return errors.length > 0 ? { errors } : { ast, errors };
1003
+ }
1004
+ function lastLine(source) {
1005
+ return source.split("\n").length;
1006
+ }
1007
+ function simplifyChevrotainMessage(message) {
1008
+ return message.replace(/\s+/g, " ").replace(/<K_([a-z]+)>/g, "'$1'").replace(/<([A-Za-z]+)>/g, "$1").trim();
1009
+ }
1010
+ /** Exposed for tests: the token types, to check the grammar is LL(k) without ambiguity reports. */
1011
+ export const bdefTokenTypes = allTokens;
1012
+ //# sourceMappingURL=parser.js.map