@manifesto-ai/compiler 1.6.1 → 1.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 (185) hide show
  1. package/README.md +64 -16
  2. package/dist/chunk-DJY6BFGK.js +74 -0
  3. package/dist/chunk-DJY6BFGK.js.map +1 -0
  4. package/dist/chunk-QP2LGMBA.js +4522 -0
  5. package/dist/chunk-QP2LGMBA.js.map +1 -0
  6. package/dist/chunk-QXLPDCLA.js +33 -0
  7. package/dist/chunk-QXLPDCLA.js.map +1 -0
  8. package/dist/esbuild.d.ts +8 -0
  9. package/dist/esbuild.js +14 -0
  10. package/dist/esbuild.js.map +1 -0
  11. package/dist/index.d.ts +2710 -11
  12. package/dist/index.js +2189 -43
  13. package/dist/index.js.map +1 -1
  14. package/dist/node-loader.d.ts +18 -0
  15. package/dist/node-loader.js +47 -0
  16. package/dist/node-loader.js.map +1 -0
  17. package/dist/rollup.d.ts +8 -0
  18. package/dist/rollup.js +14 -0
  19. package/dist/rollup.js.map +1 -0
  20. package/dist/rspack.d.ts +7 -0
  21. package/dist/rspack.js +14 -0
  22. package/dist/rspack.js.map +1 -0
  23. package/dist/unplugin-6wnvFiEo.d.ts +17 -0
  24. package/dist/vite.d.ts +8 -17
  25. package/dist/vite.js +13 -33
  26. package/dist/vite.js.map +1 -1
  27. package/dist/webpack.d.ts +8 -0
  28. package/dist/webpack.js +14 -0
  29. package/dist/webpack.js.map +1 -0
  30. package/package.json +42 -24
  31. package/dist/analyzer/index.d.ts +0 -6
  32. package/dist/analyzer/index.d.ts.map +0 -1
  33. package/dist/analyzer/index.js +0 -6
  34. package/dist/analyzer/index.js.map +0 -1
  35. package/dist/analyzer/scope.d.ts +0 -77
  36. package/dist/analyzer/scope.d.ts.map +0 -1
  37. package/dist/analyzer/scope.js +0 -296
  38. package/dist/analyzer/scope.js.map +0 -1
  39. package/dist/analyzer/validator.d.ts +0 -60
  40. package/dist/analyzer/validator.d.ts.map +0 -1
  41. package/dist/analyzer/validator.js +0 -439
  42. package/dist/analyzer/validator.js.map +0 -1
  43. package/dist/api/compile-mel.d.ts +0 -126
  44. package/dist/api/compile-mel.d.ts.map +0 -1
  45. package/dist/api/compile-mel.js +0 -129
  46. package/dist/api/compile-mel.js.map +0 -1
  47. package/dist/api/index.d.ts +0 -10
  48. package/dist/api/index.d.ts.map +0 -1
  49. package/dist/api/index.js +0 -9
  50. package/dist/api/index.js.map +0 -1
  51. package/dist/diagnostics/codes.d.ts +0 -25
  52. package/dist/diagnostics/codes.d.ts.map +0 -1
  53. package/dist/diagnostics/codes.js +0 -154
  54. package/dist/diagnostics/codes.js.map +0 -1
  55. package/dist/diagnostics/index.d.ts +0 -6
  56. package/dist/diagnostics/index.d.ts.map +0 -1
  57. package/dist/diagnostics/index.js +0 -6
  58. package/dist/diagnostics/index.js.map +0 -1
  59. package/dist/diagnostics/types.d.ts +0 -67
  60. package/dist/diagnostics/types.d.ts.map +0 -1
  61. package/dist/diagnostics/types.js +0 -58
  62. package/dist/diagnostics/types.js.map +0 -1
  63. package/dist/evaluation/context.d.ts +0 -91
  64. package/dist/evaluation/context.d.ts.map +0 -1
  65. package/dist/evaluation/context.js +0 -59
  66. package/dist/evaluation/context.js.map +0 -1
  67. package/dist/evaluation/evaluate-expr.d.ts +0 -24
  68. package/dist/evaluation/evaluate-expr.d.ts.map +0 -1
  69. package/dist/evaluation/evaluate-expr.js +0 -576
  70. package/dist/evaluation/evaluate-expr.js.map +0 -1
  71. package/dist/evaluation/evaluate-patch.d.ts +0 -123
  72. package/dist/evaluation/evaluate-patch.d.ts.map +0 -1
  73. package/dist/evaluation/evaluate-patch.js +0 -202
  74. package/dist/evaluation/evaluate-patch.js.map +0 -1
  75. package/dist/evaluation/evaluate-runtime-patch.d.ts +0 -86
  76. package/dist/evaluation/evaluate-runtime-patch.d.ts.map +0 -1
  77. package/dist/evaluation/evaluate-runtime-patch.js +0 -153
  78. package/dist/evaluation/evaluate-runtime-patch.js.map +0 -1
  79. package/dist/evaluation/index.d.ts +0 -15
  80. package/dist/evaluation/index.d.ts.map +0 -1
  81. package/dist/evaluation/index.js +0 -13
  82. package/dist/evaluation/index.js.map +0 -1
  83. package/dist/generator/index.d.ts +0 -7
  84. package/dist/generator/index.d.ts.map +0 -1
  85. package/dist/generator/index.js +0 -7
  86. package/dist/generator/index.js.map +0 -1
  87. package/dist/generator/ir.d.ts +0 -348
  88. package/dist/generator/ir.d.ts.map +0 -1
  89. package/dist/generator/ir.js +0 -709
  90. package/dist/generator/ir.js.map +0 -1
  91. package/dist/generator/lowering.d.ts +0 -11
  92. package/dist/generator/lowering.d.ts.map +0 -1
  93. package/dist/generator/lowering.js +0 -368
  94. package/dist/generator/lowering.js.map +0 -1
  95. package/dist/generator/normalizer.d.ts +0 -16
  96. package/dist/generator/normalizer.d.ts.map +0 -1
  97. package/dist/generator/normalizer.js +0 -181
  98. package/dist/generator/normalizer.js.map +0 -1
  99. package/dist/index.d.ts.map +0 -1
  100. package/dist/lexer/index.d.ts +0 -7
  101. package/dist/lexer/index.d.ts.map +0 -1
  102. package/dist/lexer/index.js +0 -7
  103. package/dist/lexer/index.js.map +0 -1
  104. package/dist/lexer/lexer.d.ts +0 -59
  105. package/dist/lexer/lexer.d.ts.map +0 -1
  106. package/dist/lexer/lexer.js +0 -433
  107. package/dist/lexer/lexer.js.map +0 -1
  108. package/dist/lexer/source-location.d.ts +0 -41
  109. package/dist/lexer/source-location.d.ts.map +0 -1
  110. package/dist/lexer/source-location.js +0 -33
  111. package/dist/lexer/source-location.js.map +0 -1
  112. package/dist/lexer/tokens.d.ts +0 -47
  113. package/dist/lexer/tokens.d.ts.map +0 -1
  114. package/dist/lexer/tokens.js +0 -73
  115. package/dist/lexer/tokens.js.map +0 -1
  116. package/dist/loader.d.ts +0 -23
  117. package/dist/loader.d.ts.map +0 -1
  118. package/dist/loader.js +0 -62
  119. package/dist/loader.js.map +0 -1
  120. package/dist/lowering/context.d.ts +0 -96
  121. package/dist/lowering/context.d.ts.map +0 -1
  122. package/dist/lowering/context.js +0 -42
  123. package/dist/lowering/context.js.map +0 -1
  124. package/dist/lowering/errors.d.ts +0 -84
  125. package/dist/lowering/errors.d.ts.map +0 -1
  126. package/dist/lowering/errors.js +0 -81
  127. package/dist/lowering/errors.js.map +0 -1
  128. package/dist/lowering/index.d.ts +0 -20
  129. package/dist/lowering/index.d.ts.map +0 -1
  130. package/dist/lowering/index.js +0 -13
  131. package/dist/lowering/index.js.map +0 -1
  132. package/dist/lowering/lower-expr.d.ts +0 -76
  133. package/dist/lowering/lower-expr.d.ts.map +0 -1
  134. package/dist/lowering/lower-expr.js +0 -351
  135. package/dist/lowering/lower-expr.js.map +0 -1
  136. package/dist/lowering/lower-patch.d.ts +0 -231
  137. package/dist/lowering/lower-patch.d.ts.map +0 -1
  138. package/dist/lowering/lower-patch.js +0 -146
  139. package/dist/lowering/lower-patch.js.map +0 -1
  140. package/dist/lowering/lower-runtime-patch.d.ts +0 -100
  141. package/dist/lowering/lower-runtime-patch.d.ts.map +0 -1
  142. package/dist/lowering/lower-runtime-patch.js +0 -49
  143. package/dist/lowering/lower-runtime-patch.js.map +0 -1
  144. package/dist/mel-module.d.ts +0 -13
  145. package/dist/mel-module.d.ts.map +0 -1
  146. package/dist/mel-module.js +0 -33
  147. package/dist/mel-module.js.map +0 -1
  148. package/dist/parser/ast.d.ts +0 -344
  149. package/dist/parser/ast.d.ts.map +0 -1
  150. package/dist/parser/ast.js +0 -24
  151. package/dist/parser/ast.js.map +0 -1
  152. package/dist/parser/index.d.ts +0 -7
  153. package/dist/parser/index.d.ts.map +0 -1
  154. package/dist/parser/index.js +0 -7
  155. package/dist/parser/index.js.map +0 -1
  156. package/dist/parser/parser.d.ts +0 -92
  157. package/dist/parser/parser.d.ts.map +0 -1
  158. package/dist/parser/parser.js +0 -892
  159. package/dist/parser/parser.js.map +0 -1
  160. package/dist/parser/precedence.d.ts +0 -44
  161. package/dist/parser/precedence.d.ts.map +0 -1
  162. package/dist/parser/precedence.js +0 -69
  163. package/dist/parser/precedence.js.map +0 -1
  164. package/dist/renderer/expr-node.d.ts +0 -172
  165. package/dist/renderer/expr-node.d.ts.map +0 -1
  166. package/dist/renderer/expr-node.js +0 -218
  167. package/dist/renderer/expr-node.js.map +0 -1
  168. package/dist/renderer/fragment.d.ts +0 -84
  169. package/dist/renderer/fragment.d.ts.map +0 -1
  170. package/dist/renderer/fragment.js +0 -172
  171. package/dist/renderer/fragment.js.map +0 -1
  172. package/dist/renderer/index.d.ts +0 -23
  173. package/dist/renderer/index.d.ts.map +0 -1
  174. package/dist/renderer/index.js +0 -27
  175. package/dist/renderer/index.js.map +0 -1
  176. package/dist/renderer/patch-op.d.ts +0 -82
  177. package/dist/renderer/patch-op.d.ts.map +0 -1
  178. package/dist/renderer/patch-op.js +0 -203
  179. package/dist/renderer/patch-op.js.map +0 -1
  180. package/dist/renderer/type-expr.d.ts +0 -61
  181. package/dist/renderer/type-expr.d.ts.map +0 -1
  182. package/dist/renderer/type-expr.js +0 -131
  183. package/dist/renderer/type-expr.js.map +0 -1
  184. package/dist/vite.d.ts.map +0 -1
  185. package/loader.cjs +0 -22
@@ -0,0 +1,4522 @@
1
+ // src/lexer/tokens.ts
2
+ var KEYWORDS = {
3
+ domain: "DOMAIN",
4
+ state: "STATE",
5
+ computed: "COMPUTED",
6
+ action: "ACTION",
7
+ effect: "EFFECT",
8
+ when: "WHEN",
9
+ once: "ONCE",
10
+ patch: "PATCH",
11
+ unset: "UNSET",
12
+ merge: "MERGE",
13
+ true: "TRUE",
14
+ false: "FALSE",
15
+ null: "NULL",
16
+ as: "AS",
17
+ available: "AVAILABLE",
18
+ // v0.3.2
19
+ fail: "FAIL",
20
+ // v0.3.2
21
+ stop: "STOP",
22
+ // v0.3.2
23
+ with: "WITH",
24
+ // v0.3.2
25
+ type: "TYPE",
26
+ // v0.3.3
27
+ import: "IMPORT",
28
+ from: "FROM",
29
+ export: "EXPORT"
30
+ };
31
+ var RESERVED_KEYWORDS = /* @__PURE__ */ new Set([
32
+ // Control flow (forbidden)
33
+ "function",
34
+ "var",
35
+ "let",
36
+ "const",
37
+ "if",
38
+ "else",
39
+ "for",
40
+ "while",
41
+ "do",
42
+ "switch",
43
+ "case",
44
+ "break",
45
+ "continue",
46
+ "return",
47
+ "throw",
48
+ "try",
49
+ "catch",
50
+ "finally",
51
+ "new",
52
+ "delete",
53
+ "instanceof",
54
+ "void",
55
+ // NOTE: "typeof" removed - now a MEL builtin function
56
+ // NOTE: "with" removed - now a MEL keyword in v0.3.2
57
+ "debugger",
58
+ "this",
59
+ "super",
60
+ "arguments",
61
+ "eval",
62
+ // Reserved for future
63
+ "async",
64
+ "await",
65
+ "yield",
66
+ "class",
67
+ "extends",
68
+ "interface",
69
+ "enum",
70
+ "namespace",
71
+ "module"
72
+ // NOTE: "type" removed - now a MEL keyword in v0.3.3
73
+ ]);
74
+ function isKeyword(lexeme) {
75
+ return lexeme in KEYWORDS;
76
+ }
77
+ function isReserved(lexeme) {
78
+ return RESERVED_KEYWORDS.has(lexeme);
79
+ }
80
+ function getKeywordKind(lexeme) {
81
+ return Object.hasOwn(KEYWORDS, lexeme) ? KEYWORDS[lexeme] : void 0;
82
+ }
83
+ function createToken(kind, lexeme, location, value) {
84
+ return { kind, lexeme, location, value };
85
+ }
86
+
87
+ // src/lexer/source-location.ts
88
+ function createPosition(line, column, offset) {
89
+ return { line, column, offset };
90
+ }
91
+ function createLocation(start, end, source) {
92
+ return { start, end, source };
93
+ }
94
+ function createPointLocation(pos, source) {
95
+ return { start: pos, end: pos, source };
96
+ }
97
+ function mergeLocations(a, b) {
98
+ return {
99
+ start: a.start.offset < b.start.offset ? a.start : b.start,
100
+ end: a.end.offset > b.end.offset ? a.end : b.end,
101
+ source: a.source ?? b.source
102
+ };
103
+ }
104
+
105
+ // src/lexer/lexer.ts
106
+ var Lexer = class {
107
+ source;
108
+ sourcePath;
109
+ tokens = [];
110
+ diagnostics = [];
111
+ // Current position
112
+ start = 0;
113
+ // Start of current token
114
+ current = 0;
115
+ // Current character
116
+ line = 1;
117
+ column = 1;
118
+ lineStart = 0;
119
+ // Offset of current line start
120
+ constructor(source, sourcePath) {
121
+ this.source = source;
122
+ this.sourcePath = sourcePath;
123
+ }
124
+ /**
125
+ * Tokenize the source code
126
+ */
127
+ tokenize() {
128
+ while (!this.isAtEnd()) {
129
+ this.start = this.current;
130
+ this.scanToken();
131
+ }
132
+ this.tokens.push(
133
+ createToken("EOF", "", this.currentLocation())
134
+ );
135
+ return {
136
+ tokens: this.tokens,
137
+ diagnostics: this.diagnostics
138
+ };
139
+ }
140
+ scanToken() {
141
+ const c = this.advance();
142
+ switch (c) {
143
+ // Single-character tokens
144
+ case "(":
145
+ this.addToken("LPAREN");
146
+ break;
147
+ case ")":
148
+ this.addToken("RPAREN");
149
+ break;
150
+ case "{":
151
+ this.addToken("LBRACE");
152
+ break;
153
+ case "}":
154
+ this.addToken("RBRACE");
155
+ break;
156
+ case "[":
157
+ this.addToken("LBRACKET");
158
+ break;
159
+ case "]":
160
+ this.addToken("RBRACKET");
161
+ break;
162
+ case ",":
163
+ this.addToken("COMMA");
164
+ break;
165
+ case ";":
166
+ this.addToken("SEMICOLON");
167
+ break;
168
+ case ".":
169
+ this.addToken("DOT");
170
+ break;
171
+ case "+":
172
+ this.addToken("PLUS");
173
+ break;
174
+ case "-":
175
+ this.addToken("MINUS");
176
+ break;
177
+ case "*":
178
+ this.addToken("STAR");
179
+ break;
180
+ case "%":
181
+ this.addToken("PERCENT");
182
+ break;
183
+ case ":":
184
+ this.addToken("COLON");
185
+ break;
186
+ // Two-character tokens
187
+ case "=":
188
+ this.addToken(this.match("=") ? "EQ_EQ" : "EQ");
189
+ break;
190
+ case "!":
191
+ this.addToken(this.match("=") ? "BANG_EQ" : "BANG");
192
+ break;
193
+ case "<":
194
+ this.addToken(this.match("=") ? "LT_EQ" : "LT");
195
+ break;
196
+ case ">":
197
+ this.addToken(this.match("=") ? "GT_EQ" : "GT");
198
+ break;
199
+ case "&":
200
+ if (this.match("&")) {
201
+ this.addToken("AMP_AMP");
202
+ } else {
203
+ this.error("Expected '&&' for logical AND");
204
+ }
205
+ break;
206
+ case "|":
207
+ if (this.match("|")) {
208
+ this.addToken("PIPE_PIPE");
209
+ } else {
210
+ this.addToken("PIPE");
211
+ }
212
+ break;
213
+ case "?":
214
+ this.addToken(this.match("?") ? "QUESTION_QUESTION" : "QUESTION");
215
+ break;
216
+ // Slash or comment
217
+ case "/":
218
+ if (this.match("/")) {
219
+ this.lineComment();
220
+ } else if (this.match("*")) {
221
+ this.blockComment();
222
+ } else {
223
+ this.addToken("SLASH");
224
+ }
225
+ break;
226
+ // Whitespace
227
+ case " ":
228
+ case "\r":
229
+ case " ":
230
+ break;
231
+ case "\n":
232
+ this.newline();
233
+ break;
234
+ // String literals
235
+ case '"':
236
+ this.string('"');
237
+ break;
238
+ case "'":
239
+ this.string("'");
240
+ break;
241
+ // System identifiers ($...)
242
+ case "$":
243
+ this.systemIdentifier();
244
+ break;
245
+ default:
246
+ if (this.isDigit(c)) {
247
+ this.number();
248
+ } else if (this.isAlpha(c)) {
249
+ this.identifier();
250
+ } else {
251
+ this.error(`Unexpected character '${c}'`);
252
+ }
253
+ }
254
+ }
255
+ // ============ Token Scanners ============
256
+ lineComment() {
257
+ while (this.peek() !== "\n" && !this.isAtEnd()) {
258
+ this.advance();
259
+ }
260
+ }
261
+ blockComment() {
262
+ const startLine = this.line;
263
+ const startColumn = this.column - 2;
264
+ while (!this.isAtEnd()) {
265
+ if (this.peek() === "*" && this.peekNext() === "/") {
266
+ this.advance();
267
+ this.advance();
268
+ return;
269
+ }
270
+ if (this.peek() === "\n") {
271
+ this.newline();
272
+ }
273
+ this.advance();
274
+ }
275
+ this.error(`Unterminated block comment starting at line ${startLine}:${startColumn}`);
276
+ }
277
+ string(quote) {
278
+ const startLine = this.line;
279
+ const startColumn = this.column - 1;
280
+ let value = "";
281
+ while (this.peek() !== quote && !this.isAtEnd()) {
282
+ if (this.peek() === "\n") {
283
+ this.error("Unterminated string literal");
284
+ return;
285
+ }
286
+ if (this.peek() === "\\") {
287
+ this.advance();
288
+ const escaped = this.advance();
289
+ switch (escaped) {
290
+ case "n":
291
+ value += "\n";
292
+ break;
293
+ case "r":
294
+ value += "\r";
295
+ break;
296
+ case "t":
297
+ value += " ";
298
+ break;
299
+ case "\\":
300
+ value += "\\";
301
+ break;
302
+ case "'":
303
+ value += "'";
304
+ break;
305
+ case '"':
306
+ value += '"';
307
+ break;
308
+ case "0":
309
+ value += "\0";
310
+ break;
311
+ default:
312
+ this.error(`Invalid escape sequence '\\${escaped}'`);
313
+ value += escaped;
314
+ }
315
+ } else {
316
+ value += this.advance();
317
+ }
318
+ }
319
+ if (this.isAtEnd()) {
320
+ this.error(`Unterminated string starting at line ${startLine}:${startColumn}`);
321
+ return;
322
+ }
323
+ this.advance();
324
+ this.addToken("STRING", value);
325
+ }
326
+ number() {
327
+ if (this.source[this.start] === "0" && (this.peek() === "x" || this.peek() === "X")) {
328
+ this.advance();
329
+ while (this.isHexDigit(this.peek())) {
330
+ this.advance();
331
+ }
332
+ const hexStr = this.source.slice(this.start + 2, this.current);
333
+ const value2 = parseInt(hexStr, 16);
334
+ this.addToken("NUMBER", value2);
335
+ return;
336
+ }
337
+ while (this.isDigit(this.peek())) {
338
+ this.advance();
339
+ }
340
+ if (this.peek() === "." && this.isDigit(this.peekNext())) {
341
+ this.advance();
342
+ while (this.isDigit(this.peek())) {
343
+ this.advance();
344
+ }
345
+ }
346
+ if (this.peek() === "e" || this.peek() === "E") {
347
+ this.advance();
348
+ if (this.peek() === "+" || this.peek() === "-") {
349
+ this.advance();
350
+ }
351
+ if (!this.isDigit(this.peek())) {
352
+ this.error("Invalid number: expected digits after exponent");
353
+ return;
354
+ }
355
+ while (this.isDigit(this.peek())) {
356
+ this.advance();
357
+ }
358
+ }
359
+ const value = parseFloat(this.source.slice(this.start, this.current));
360
+ this.addToken("NUMBER", value);
361
+ }
362
+ identifier() {
363
+ while (this.isAlphaNumeric(this.peek())) {
364
+ if (this.peek() === "$") {
365
+ this.advance();
366
+ this.error("'$' is forbidden in identifiers (MEL A17)");
367
+ continue;
368
+ }
369
+ this.advance();
370
+ }
371
+ const lexeme = this.source.slice(this.start, this.current);
372
+ if (lexeme.startsWith("__sys__")) {
373
+ this.error("'__sys__' prefix is reserved for compiler-generated identifiers (MEL A26)");
374
+ this.addToken("ERROR");
375
+ return;
376
+ }
377
+ if (isReserved(lexeme)) {
378
+ this.error(`'${lexeme}' is a reserved keyword and cannot be used`);
379
+ this.addToken("ERROR");
380
+ return;
381
+ }
382
+ const keywordKind = getKeywordKind(lexeme);
383
+ if (keywordKind) {
384
+ this.addToken(keywordKind);
385
+ } else {
386
+ this.addToken("IDENTIFIER");
387
+ }
388
+ }
389
+ systemIdentifier() {
390
+ if (!this.isAlpha(this.peek())) {
391
+ this.error("Expected identifier after '$'");
392
+ this.addToken("ERROR");
393
+ return;
394
+ }
395
+ while (this.isAlphaNumeric(this.peek())) {
396
+ this.advance();
397
+ }
398
+ const initialLexeme = this.source.slice(this.start, this.current);
399
+ if (initialLexeme === "$item") {
400
+ this.addToken("ITEM");
401
+ return;
402
+ }
403
+ if (initialLexeme === "$system" || initialLexeme === "$meta" || initialLexeme === "$input") {
404
+ while (this.peek() === "." && this.isAlpha(this.peekNext())) {
405
+ this.advance();
406
+ while (this.isAlphaNumeric(this.peek())) {
407
+ this.advance();
408
+ }
409
+ }
410
+ this.addToken("SYSTEM_IDENT");
411
+ return;
412
+ }
413
+ this.error(`Invalid system identifier '${initialLexeme}'. Expected $system.*, $meta.*, $input.*, or $item`);
414
+ this.addToken("ERROR");
415
+ }
416
+ // ============ Helpers ============
417
+ isAtEnd() {
418
+ return this.current >= this.source.length;
419
+ }
420
+ advance() {
421
+ const c = this.source[this.current];
422
+ this.current++;
423
+ this.column++;
424
+ return c;
425
+ }
426
+ peek() {
427
+ if (this.isAtEnd()) return "\0";
428
+ return this.source[this.current];
429
+ }
430
+ peekNext() {
431
+ if (this.current + 1 >= this.source.length) return "\0";
432
+ return this.source[this.current + 1];
433
+ }
434
+ match(expected) {
435
+ if (this.isAtEnd()) return false;
436
+ if (this.source[this.current] !== expected) return false;
437
+ this.current++;
438
+ this.column++;
439
+ return true;
440
+ }
441
+ newline() {
442
+ this.line++;
443
+ this.column = 1;
444
+ this.lineStart = this.current;
445
+ }
446
+ isDigit(c) {
447
+ return c >= "0" && c <= "9";
448
+ }
449
+ isHexDigit(c) {
450
+ return this.isDigit(c) || c >= "a" && c <= "f" || c >= "A" && c <= "F";
451
+ }
452
+ isAlpha(c) {
453
+ return c >= "a" && c <= "z" || c >= "A" && c <= "Z" || c === "_";
454
+ }
455
+ isAlphaNumeric(c) {
456
+ return this.isAlpha(c) || this.isDigit(c);
457
+ }
458
+ currentLocation() {
459
+ const startPos = this.positionAt(this.start);
460
+ const endPos = this.positionAt(this.current);
461
+ return createLocation(startPos, endPos, this.sourcePath);
462
+ }
463
+ positionAt(offset) {
464
+ let line = 1;
465
+ let lineStart = 0;
466
+ for (let i = 0; i < offset; i++) {
467
+ if (this.source[i] === "\n") {
468
+ line++;
469
+ lineStart = i + 1;
470
+ }
471
+ }
472
+ return createPosition(line, offset - lineStart + 1, offset);
473
+ }
474
+ addToken(kind, value) {
475
+ const lexeme = this.source.slice(this.start, this.current);
476
+ this.tokens.push(createToken(kind, lexeme, this.currentLocation(), value));
477
+ }
478
+ error(message) {
479
+ const location = this.currentLocation();
480
+ this.diagnostics.push({
481
+ severity: "error",
482
+ code: "MEL_LEXER",
483
+ message,
484
+ location,
485
+ source: this.getSourceLine(location.start.line)
486
+ });
487
+ }
488
+ getSourceLine(lineNumber) {
489
+ const lines = this.source.split("\n");
490
+ return lines[lineNumber - 1] ?? "";
491
+ }
492
+ };
493
+ function tokenize(source, sourcePath) {
494
+ const lexer = new Lexer(source, sourcePath);
495
+ return lexer.tokenize();
496
+ }
497
+
498
+ // src/parser/ast.ts
499
+ function isExprNode(node) {
500
+ const exprKinds = [
501
+ "literal",
502
+ "identifier",
503
+ "systemIdent",
504
+ "iterationVar",
505
+ "propertyAccess",
506
+ "indexAccess",
507
+ "functionCall",
508
+ "unary",
509
+ "binary",
510
+ "ternary",
511
+ "objectLiteral",
512
+ "arrayLiteral"
513
+ ];
514
+ return exprKinds.includes(node.kind);
515
+ }
516
+ function isStmtNode(node) {
517
+ const stmtKinds = ["when", "once", "onceIntent", "patch", "effect", "fail", "stop"];
518
+ return stmtKinds.includes(node.kind);
519
+ }
520
+
521
+ // src/parser/precedence.ts
522
+ var Precedence = /* @__PURE__ */ ((Precedence2) => {
523
+ Precedence2[Precedence2["NONE"] = 0] = "NONE";
524
+ Precedence2[Precedence2["TERNARY"] = 1] = "TERNARY";
525
+ Precedence2[Precedence2["NULLISH"] = 2] = "NULLISH";
526
+ Precedence2[Precedence2["OR"] = 3] = "OR";
527
+ Precedence2[Precedence2["AND"] = 4] = "AND";
528
+ Precedence2[Precedence2["EQUALITY"] = 5] = "EQUALITY";
529
+ Precedence2[Precedence2["COMPARISON"] = 6] = "COMPARISON";
530
+ Precedence2[Precedence2["ADDITIVE"] = 7] = "ADDITIVE";
531
+ Precedence2[Precedence2["MULTIPLICATIVE"] = 8] = "MULTIPLICATIVE";
532
+ Precedence2[Precedence2["UNARY"] = 9] = "UNARY";
533
+ Precedence2[Precedence2["CALL"] = 10] = "CALL";
534
+ Precedence2[Precedence2["ACCESS"] = 11] = "ACCESS";
535
+ return Precedence2;
536
+ })(Precedence || {});
537
+ function getBinaryPrecedence(kind) {
538
+ switch (kind) {
539
+ case "QUESTION":
540
+ return 1 /* TERNARY */;
541
+ case "QUESTION_QUESTION":
542
+ return 2 /* NULLISH */;
543
+ case "PIPE_PIPE":
544
+ return 3 /* OR */;
545
+ case "AMP_AMP":
546
+ return 4 /* AND */;
547
+ case "EQ_EQ":
548
+ case "BANG_EQ":
549
+ return 5 /* EQUALITY */;
550
+ case "LT":
551
+ case "LT_EQ":
552
+ case "GT":
553
+ case "GT_EQ":
554
+ return 6 /* COMPARISON */;
555
+ case "PLUS":
556
+ case "MINUS":
557
+ return 7 /* ADDITIVE */;
558
+ case "STAR":
559
+ case "SLASH":
560
+ case "PERCENT":
561
+ return 8 /* MULTIPLICATIVE */;
562
+ default:
563
+ return 0 /* NONE */;
564
+ }
565
+ }
566
+ function tokenToBinaryOp(kind) {
567
+ switch (kind) {
568
+ case "PLUS":
569
+ return "+";
570
+ case "MINUS":
571
+ return "-";
572
+ case "STAR":
573
+ return "*";
574
+ case "SLASH":
575
+ return "/";
576
+ case "PERCENT":
577
+ return "%";
578
+ case "EQ_EQ":
579
+ return "==";
580
+ case "BANG_EQ":
581
+ return "!=";
582
+ case "LT":
583
+ return "<";
584
+ case "LT_EQ":
585
+ return "<=";
586
+ case "GT":
587
+ return ">";
588
+ case "GT_EQ":
589
+ return ">=";
590
+ case "AMP_AMP":
591
+ return "&&";
592
+ case "PIPE_PIPE":
593
+ return "||";
594
+ case "QUESTION_QUESTION":
595
+ return "??";
596
+ default:
597
+ return null;
598
+ }
599
+ }
600
+ function isBinaryOp(kind) {
601
+ return getBinaryPrecedence(kind) !== 0 /* NONE */;
602
+ }
603
+ function isUnaryOp(kind) {
604
+ return kind === "BANG" || kind === "MINUS";
605
+ }
606
+ function isRightAssociative(kind) {
607
+ return kind === "QUESTION" || kind === "QUESTION_QUESTION";
608
+ }
609
+
610
+ // src/parser/parser.ts
611
+ var Parser = class {
612
+ tokens;
613
+ current = 0;
614
+ diagnostics = [];
615
+ constructor(tokens) {
616
+ this.tokens = tokens;
617
+ }
618
+ /**
619
+ * Parse tokens into an AST
620
+ */
621
+ parse() {
622
+ try {
623
+ const program = this.parseProgram();
624
+ return { program, diagnostics: this.diagnostics };
625
+ } catch (e) {
626
+ return { program: null, diagnostics: this.diagnostics };
627
+ }
628
+ }
629
+ // ============ Program Structure ============
630
+ parseProgram() {
631
+ const start = this.peek().location;
632
+ const imports = [];
633
+ while (this.check("IMPORT")) {
634
+ imports.push(this.parseImport());
635
+ }
636
+ const domain = this.parseDomain();
637
+ return {
638
+ kind: "program",
639
+ imports,
640
+ domain,
641
+ location: mergeLocations(start, domain.location)
642
+ };
643
+ }
644
+ parseImport() {
645
+ const start = this.consume("IMPORT", "Expected 'import'").location;
646
+ this.consume("LBRACE", "Expected '{' after 'import'");
647
+ const names = [];
648
+ do {
649
+ names.push(this.consume("IDENTIFIER", "Expected identifier").lexeme);
650
+ } while (this.match("COMMA"));
651
+ this.consume("RBRACE", "Expected '}' after import names");
652
+ this.consume("FROM", "Expected 'from' after import names");
653
+ const fromToken = this.consume("STRING", "Expected string after 'from'");
654
+ return {
655
+ kind: "import",
656
+ names,
657
+ from: fromToken.value,
658
+ location: mergeLocations(start, fromToken.location)
659
+ };
660
+ }
661
+ parseDomain() {
662
+ const start = this.consume("DOMAIN", "Expected 'domain'").location;
663
+ const name = this.consume("IDENTIFIER", "Expected domain name").lexeme;
664
+ this.consume("LBRACE", "Expected '{' after domain name");
665
+ const types = [];
666
+ while (this.check("TYPE") && !this.isAtEnd()) {
667
+ types.push(this.parseTypeDecl());
668
+ }
669
+ const members = [];
670
+ while (!this.check("RBRACE") && !this.isAtEnd()) {
671
+ if (this.check("TYPE")) {
672
+ types.push(this.parseTypeDecl());
673
+ } else {
674
+ const member = this.parseDomainMember();
675
+ if (member) members.push(member);
676
+ }
677
+ }
678
+ const end = this.consume("RBRACE", "Expected '}' to close domain").location;
679
+ return {
680
+ kind: "domain",
681
+ name,
682
+ types,
683
+ members,
684
+ location: mergeLocations(start, end)
685
+ };
686
+ }
687
+ /**
688
+ * v0.3.3: Parse type declaration
689
+ * Syntax: type Name = TypeExpr
690
+ */
691
+ parseTypeDecl() {
692
+ const start = this.consume("TYPE", "Expected 'type'").location;
693
+ const name = this.consume("IDENTIFIER", "Expected type name").lexeme;
694
+ this.consume("EQ", "Expected '=' after type name");
695
+ const typeExpr = this.parseTypeExpr();
696
+ return {
697
+ kind: "typeDecl",
698
+ name,
699
+ typeExpr,
700
+ location: mergeLocations(start, typeExpr.location)
701
+ };
702
+ }
703
+ parseDomainMember() {
704
+ if (this.check("STATE")) return this.parseState();
705
+ if (this.check("COMPUTED")) return this.parseComputed();
706
+ if (this.check("ACTION")) return this.parseAction();
707
+ this.error(`Unexpected token '${this.peek().lexeme}'. Expected 'state', 'computed', or 'action'.`);
708
+ this.advance();
709
+ return null;
710
+ }
711
+ // ============ State ============
712
+ parseState() {
713
+ const start = this.consume("STATE", "Expected 'state'").location;
714
+ this.consume("LBRACE", "Expected '{' after 'state'");
715
+ const fields = [];
716
+ while (!this.check("RBRACE") && !this.isAtEnd()) {
717
+ fields.push(this.parseStateField());
718
+ }
719
+ const end = this.consume("RBRACE", "Expected '}' to close state block").location;
720
+ return {
721
+ kind: "state",
722
+ fields,
723
+ location: mergeLocations(start, end)
724
+ };
725
+ }
726
+ parseStateField() {
727
+ const nameToken = this.consume("IDENTIFIER", "Expected field name");
728
+ this.consume("COLON", "Expected ':' after field name");
729
+ const typeExpr = this.parseTypeExpr();
730
+ let initializer;
731
+ if (this.match("EQ")) {
732
+ initializer = this.parseExpression();
733
+ }
734
+ return {
735
+ kind: "stateField",
736
+ name: nameToken.lexeme,
737
+ typeExpr,
738
+ initializer,
739
+ location: mergeLocations(
740
+ nameToken.location,
741
+ initializer?.location ?? typeExpr.location
742
+ )
743
+ };
744
+ }
745
+ // ============ Computed ============
746
+ parseComputed() {
747
+ const start = this.consume("COMPUTED", "Expected 'computed'").location;
748
+ const name = this.consume("IDENTIFIER", "Expected computed name").lexeme;
749
+ this.consume("EQ", "Expected '=' after computed name");
750
+ const expression = this.parseExpression();
751
+ return {
752
+ kind: "computed",
753
+ name,
754
+ expression,
755
+ location: mergeLocations(start, expression.location)
756
+ };
757
+ }
758
+ // ============ Action ============
759
+ parseAction() {
760
+ const start = this.consume("ACTION", "Expected 'action'").location;
761
+ const name = this.consume("IDENTIFIER", "Expected action name").lexeme;
762
+ this.consume("LPAREN", "Expected '(' after action name");
763
+ const params = [];
764
+ if (!this.check("RPAREN")) {
765
+ do {
766
+ params.push(this.parseParam());
767
+ } while (this.match("COMMA"));
768
+ }
769
+ this.consume("RPAREN", "Expected ')' after parameters");
770
+ let available;
771
+ if (this.match("AVAILABLE")) {
772
+ this.consume("WHEN", "Expected 'when' after 'available'");
773
+ available = this.parseExpression();
774
+ }
775
+ this.consume("LBRACE", "Expected '{' to start action body");
776
+ const body = [];
777
+ while (!this.check("RBRACE") && !this.isAtEnd()) {
778
+ const stmt = this.parseGuardedStmt();
779
+ if (stmt) body.push(stmt);
780
+ }
781
+ const end = this.consume("RBRACE", "Expected '}' to close action").location;
782
+ return {
783
+ kind: "action",
784
+ name,
785
+ params,
786
+ available,
787
+ body,
788
+ location: mergeLocations(start, end)
789
+ };
790
+ }
791
+ parseParam() {
792
+ const nameToken = this.consume("IDENTIFIER", "Expected parameter name");
793
+ this.consume("COLON", "Expected ':' after parameter name");
794
+ const typeExpr = this.parseTypeExpr();
795
+ return {
796
+ kind: "param",
797
+ name: nameToken.lexeme,
798
+ typeExpr,
799
+ location: mergeLocations(nameToken.location, typeExpr.location)
800
+ };
801
+ }
802
+ // ============ Statements ============
803
+ parseGuardedStmt() {
804
+ if (this.check("WHEN")) return this.parseWhenStmt();
805
+ if (this.check("ONCE")) return this.parseOnceStmt();
806
+ if (this.isOnceIntentContext()) return this.parseOnceIntentStmt();
807
+ const token = this.peek();
808
+ if (token.kind === "PATCH" || token.lexeme === "patch" || token.kind === "EFFECT" || token.lexeme === "effect" || token.kind === "FAIL" || token.lexeme === "fail" || token.kind === "STOP" || token.lexeme === "stop") {
809
+ this.error(
810
+ `'${token.lexeme}' must be inside a guard block (when, once, or onceIntent). Wrap it: when true { ${token.lexeme} ... }`
811
+ );
812
+ this.skipToRecoveryPoint();
813
+ return null;
814
+ }
815
+ this.error(`Unexpected token '${token.lexeme}'. Expected 'when', 'once', or 'onceIntent'.`);
816
+ this.advance();
817
+ return null;
818
+ }
819
+ /**
820
+ * Skip tokens until we reach a recovery point (closing brace, guard keyword, or EOF).
821
+ */
822
+ skipToRecoveryPoint() {
823
+ let braceDepth = 0;
824
+ while (!this.isAtEnd()) {
825
+ const t = this.peek();
826
+ if (t.kind === "LBRACE") {
827
+ braceDepth++;
828
+ this.advance();
829
+ continue;
830
+ }
831
+ if (t.kind === "RBRACE") {
832
+ if (braceDepth === 0) return;
833
+ braceDepth--;
834
+ this.advance();
835
+ continue;
836
+ }
837
+ if (braceDepth === 0 && (t.kind === "WHEN" || t.kind === "ONCE" || t.lexeme === "onceIntent")) {
838
+ return;
839
+ }
840
+ this.advance();
841
+ }
842
+ }
843
+ parseWhenStmt() {
844
+ const start = this.consume("WHEN", "Expected 'when'").location;
845
+ const condition = this.parseExpression();
846
+ this.consume("LBRACE", "Expected '{' after when condition");
847
+ const body = [];
848
+ while (!this.check("RBRACE") && !this.isAtEnd()) {
849
+ const stmt = this.parseInnerStmt();
850
+ if (stmt) body.push(stmt);
851
+ }
852
+ const end = this.consume("RBRACE", "Expected '}' to close when block").location;
853
+ return {
854
+ kind: "when",
855
+ condition,
856
+ body,
857
+ location: mergeLocations(start, end)
858
+ };
859
+ }
860
+ parseOnceStmt() {
861
+ const start = this.consume("ONCE", "Expected 'once'").location;
862
+ this.consume("LPAREN", "Expected '(' after 'once'");
863
+ const marker = this.parsePath();
864
+ this.consume("RPAREN", "Expected ')' after marker");
865
+ let condition;
866
+ if (this.match("WHEN")) {
867
+ condition = this.parseExpression();
868
+ }
869
+ this.consume("LBRACE", "Expected '{' to start once block");
870
+ const body = [];
871
+ while (!this.check("RBRACE") && !this.isAtEnd()) {
872
+ const stmt = this.parseInnerStmt();
873
+ if (stmt) body.push(stmt);
874
+ }
875
+ const end = this.consume("RBRACE", "Expected '}' to close once block").location;
876
+ return {
877
+ kind: "once",
878
+ marker,
879
+ condition,
880
+ body,
881
+ location: mergeLocations(start, end)
882
+ };
883
+ }
884
+ parseOnceIntentStmt() {
885
+ const startToken = this.consume("IDENTIFIER", "Expected 'onceIntent'");
886
+ let condition;
887
+ if (this.match("WHEN")) {
888
+ condition = this.parseExpression();
889
+ }
890
+ this.consume("LBRACE", "Expected '{' to start onceIntent block");
891
+ const body = [];
892
+ while (!this.check("RBRACE") && !this.isAtEnd()) {
893
+ const stmt = this.parseInnerStmt();
894
+ if (stmt) body.push(stmt);
895
+ }
896
+ const end = this.consume("RBRACE", "Expected '}' to close onceIntent block").location;
897
+ return {
898
+ kind: "onceIntent",
899
+ condition,
900
+ body,
901
+ location: mergeLocations(startToken.location, end)
902
+ };
903
+ }
904
+ parseInnerStmt() {
905
+ if (this.check("PATCH")) return this.parsePatchStmt();
906
+ if (this.check("EFFECT")) return this.parseEffectStmt();
907
+ if (this.check("WHEN")) return this.parseWhenStmt();
908
+ if (this.check("ONCE")) return this.parseOnceStmt();
909
+ if (this.isOnceIntentContext()) return this.parseOnceIntentStmt();
910
+ if (this.check("FAIL")) return this.parseFailStmt();
911
+ if (this.check("STOP")) return this.parseStopStmt();
912
+ this.error(`Unexpected token '${this.peek().lexeme}'. Expected 'patch', 'effect', 'when', 'once', 'onceIntent', 'fail', or 'stop'.`);
913
+ this.advance();
914
+ return null;
915
+ }
916
+ parsePatchStmt() {
917
+ const start = this.consume("PATCH", "Expected 'patch'").location;
918
+ const path = this.parsePath();
919
+ let op;
920
+ let value;
921
+ let end;
922
+ if (this.match("UNSET")) {
923
+ op = "unset";
924
+ end = this.previous().location;
925
+ } else if (this.match("MERGE")) {
926
+ op = "merge";
927
+ value = this.parseExpression();
928
+ end = value.location;
929
+ } else {
930
+ this.consume("EQ", "Expected '=', 'unset', or 'merge' after path");
931
+ op = "set";
932
+ value = this.parseExpression();
933
+ end = value.location;
934
+ }
935
+ return {
936
+ kind: "patch",
937
+ path,
938
+ op,
939
+ value,
940
+ location: mergeLocations(start, end)
941
+ };
942
+ }
943
+ parseEffectStmt() {
944
+ const start = this.consume("EFFECT", "Expected 'effect'").location;
945
+ let effectType = this.consume("IDENTIFIER", "Expected effect type").lexeme;
946
+ while (this.match("DOT")) {
947
+ effectType += "." + this.consume("IDENTIFIER", "Expected identifier after '.'").lexeme;
948
+ }
949
+ this.consume("LPAREN", "Expected '(' after effect type");
950
+ this.consume("LBRACE", "Expected '{' for effect arguments");
951
+ const args = [];
952
+ while (!this.check("RBRACE") && !this.isAtEnd()) {
953
+ args.push(this.parseEffectArg());
954
+ this.match("COMMA");
955
+ }
956
+ this.consume("RBRACE", "Expected '}' after effect arguments");
957
+ const end = this.consume("RPAREN", "Expected ')' to close effect").location;
958
+ return {
959
+ kind: "effect",
960
+ effectType,
961
+ args,
962
+ location: mergeLocations(start, end)
963
+ };
964
+ }
965
+ parseEffectArg() {
966
+ const nameToken = this.match("IDENTIFIER", "FAIL") ? this.previous() : this.consume("IDENTIFIER", "Expected argument name");
967
+ this.consume("COLON", "Expected ':' after argument name");
968
+ const isPath = ["into", "pass", "fail"].includes(nameToken.lexeme);
969
+ const value = isPath ? this.parsePath() : this.parseExpression();
970
+ return {
971
+ kind: "effectArg",
972
+ name: nameToken.lexeme,
973
+ value,
974
+ isPath,
975
+ location: mergeLocations(nameToken.location, value.location)
976
+ };
977
+ }
978
+ /**
979
+ * v0.3.2: Parse fail statement
980
+ * FailStmt ::= 'fail' StringLiteral ('with' Expr)?
981
+ */
982
+ parseFailStmt() {
983
+ const start = this.consume("FAIL", "Expected 'fail'").location;
984
+ const codeToken = this.consume("STRING", "Expected error code string after 'fail'");
985
+ const code = codeToken.value;
986
+ let message;
987
+ let end = codeToken.location;
988
+ if (this.match("WITH")) {
989
+ message = this.parseExpression();
990
+ end = message.location;
991
+ }
992
+ return {
993
+ kind: "fail",
994
+ code,
995
+ message,
996
+ location: mergeLocations(start, end)
997
+ };
998
+ }
999
+ /**
1000
+ * v0.3.2: Parse stop statement
1001
+ * StopStmt ::= 'stop' StringLiteral
1002
+ */
1003
+ parseStopStmt() {
1004
+ const start = this.consume("STOP", "Expected 'stop'").location;
1005
+ const reasonToken = this.consume("STRING", "Expected reason string after 'stop'");
1006
+ const reason = reasonToken.value;
1007
+ return {
1008
+ kind: "stop",
1009
+ reason,
1010
+ location: mergeLocations(start, reasonToken.location)
1011
+ };
1012
+ }
1013
+ // ============ Types ============
1014
+ parseTypeExpr() {
1015
+ let type = this.parseBaseType();
1016
+ if (this.check("PIPE")) {
1017
+ const types = [type];
1018
+ while (this.match("PIPE")) {
1019
+ types.push(this.parseBaseType());
1020
+ }
1021
+ type = {
1022
+ kind: "unionType",
1023
+ types,
1024
+ location: mergeLocations(types[0].location, types[types.length - 1].location)
1025
+ };
1026
+ }
1027
+ return type;
1028
+ }
1029
+ parseBaseType() {
1030
+ if (this.check("LBRACE")) {
1031
+ return this.parseObjectType();
1032
+ }
1033
+ if (this.check("STRING")) {
1034
+ const token = this.advance();
1035
+ return {
1036
+ kind: "literalType",
1037
+ value: token.value,
1038
+ location: token.location
1039
+ };
1040
+ }
1041
+ if (this.check("NUMBER")) {
1042
+ const token = this.advance();
1043
+ return {
1044
+ kind: "literalType",
1045
+ value: token.value,
1046
+ location: token.location
1047
+ };
1048
+ }
1049
+ if (this.check("TRUE") || this.check("FALSE")) {
1050
+ const token = this.advance();
1051
+ return {
1052
+ kind: "literalType",
1053
+ value: token.kind === "TRUE",
1054
+ location: token.location
1055
+ };
1056
+ }
1057
+ if (this.check("NULL")) {
1058
+ const token = this.advance();
1059
+ return {
1060
+ kind: "literalType",
1061
+ value: null,
1062
+ location: token.location
1063
+ };
1064
+ }
1065
+ const nameToken = this.consume("IDENTIFIER", "Expected type name");
1066
+ if (this.match("LT")) {
1067
+ if (nameToken.lexeme === "Array") {
1068
+ const elementType = this.parseTypeExpr();
1069
+ const end = this.consume("GT", "Expected '>' after array element type").location;
1070
+ return {
1071
+ kind: "arrayType",
1072
+ elementType,
1073
+ location: mergeLocations(nameToken.location, end)
1074
+ };
1075
+ } else if (nameToken.lexeme === "Record") {
1076
+ const keyType = this.parseTypeExpr();
1077
+ this.consume("COMMA", "Expected ',' between Record type parameters");
1078
+ const valueType = this.parseTypeExpr();
1079
+ const end = this.consume("GT", "Expected '>' after Record value type").location;
1080
+ return {
1081
+ kind: "recordType",
1082
+ keyType,
1083
+ valueType,
1084
+ location: mergeLocations(nameToken.location, end)
1085
+ };
1086
+ } else {
1087
+ this.error(`Unknown generic type '${nameToken.lexeme}'`);
1088
+ while (!this.check("GT") && !this.isAtEnd()) this.advance();
1089
+ this.match("GT");
1090
+ }
1091
+ }
1092
+ return {
1093
+ kind: "simpleType",
1094
+ name: nameToken.lexeme,
1095
+ location: nameToken.location
1096
+ };
1097
+ }
1098
+ /**
1099
+ * v0.3.3: Parse object type
1100
+ * Syntax: { field: Type, field?: Type, ... }
1101
+ */
1102
+ parseObjectType() {
1103
+ const start = this.consume("LBRACE", "Expected '{'").location;
1104
+ const fields = [];
1105
+ while (!this.check("RBRACE") && !this.isAtEnd()) {
1106
+ const nameToken = this.consume("IDENTIFIER", "Expected field name");
1107
+ const optional = this.match("QUESTION");
1108
+ this.consume("COLON", "Expected ':' after field name");
1109
+ const typeExpr = this.parseTypeExpr();
1110
+ fields.push({
1111
+ kind: "typeField",
1112
+ name: nameToken.lexeme,
1113
+ typeExpr,
1114
+ optional,
1115
+ location: mergeLocations(nameToken.location, typeExpr.location)
1116
+ });
1117
+ this.match("COMMA");
1118
+ }
1119
+ const end = this.consume("RBRACE", "Expected '}' to close object type").location;
1120
+ return {
1121
+ kind: "objectType",
1122
+ fields,
1123
+ location: mergeLocations(start, end)
1124
+ };
1125
+ }
1126
+ // ============ Expressions (Pratt Parser) ============
1127
+ parseExpression(minPrecedence = 0 /* NONE */) {
1128
+ let left = this.parsePrimary();
1129
+ while (true) {
1130
+ const precedence = getBinaryPrecedence(this.peek().kind);
1131
+ if (precedence <= minPrecedence) break;
1132
+ if (this.peek().kind === "QUESTION") {
1133
+ left = this.parseTernary(left);
1134
+ continue;
1135
+ }
1136
+ const op = tokenToBinaryOp(this.peek().kind);
1137
+ if (!op) break;
1138
+ this.advance();
1139
+ const nextPrecedence = isRightAssociative(this.previous().kind) ? precedence - 1 : precedence;
1140
+ const right = this.parseExpression(nextPrecedence);
1141
+ left = {
1142
+ kind: "binary",
1143
+ operator: op,
1144
+ left,
1145
+ right,
1146
+ location: mergeLocations(left.location, right.location)
1147
+ };
1148
+ }
1149
+ return left;
1150
+ }
1151
+ parseTernary(condition) {
1152
+ this.consume("QUESTION", "Expected '?'");
1153
+ const consequent = this.parseExpression();
1154
+ this.consume("COLON", "Expected ':' in ternary expression");
1155
+ const alternate = this.parseExpression(1 /* TERNARY */ - 1);
1156
+ return {
1157
+ kind: "ternary",
1158
+ condition,
1159
+ consequent,
1160
+ alternate,
1161
+ location: mergeLocations(condition.location, alternate.location)
1162
+ };
1163
+ }
1164
+ parsePrimary() {
1165
+ if (this.check("BANG") || this.check("MINUS") && this.isUnaryContext()) {
1166
+ const op = this.advance();
1167
+ const operand = this.parsePrimary();
1168
+ return {
1169
+ kind: "unary",
1170
+ operator: op.kind === "BANG" ? "!" : "-",
1171
+ operand,
1172
+ location: mergeLocations(op.location, operand.location)
1173
+ };
1174
+ }
1175
+ if (this.match("LPAREN")) {
1176
+ const expr = this.parseExpression();
1177
+ this.consume("RPAREN", "Expected ')' after expression");
1178
+ return expr;
1179
+ }
1180
+ if (this.check("LBRACE")) {
1181
+ return this.parseObjectLiteral();
1182
+ }
1183
+ if (this.check("LBRACKET")) {
1184
+ return this.parseArrayLiteral();
1185
+ }
1186
+ if (this.check("NUMBER")) {
1187
+ const token = this.advance();
1188
+ return {
1189
+ kind: "literal",
1190
+ value: token.value,
1191
+ literalType: "number",
1192
+ location: token.location
1193
+ };
1194
+ }
1195
+ if (this.check("STRING")) {
1196
+ const token = this.advance();
1197
+ return {
1198
+ kind: "literal",
1199
+ value: token.value,
1200
+ literalType: "string",
1201
+ location: token.location
1202
+ };
1203
+ }
1204
+ if (this.check("TRUE") || this.check("FALSE")) {
1205
+ const token = this.advance();
1206
+ return {
1207
+ kind: "literal",
1208
+ value: token.kind === "TRUE",
1209
+ literalType: "boolean",
1210
+ location: token.location
1211
+ };
1212
+ }
1213
+ if (this.check("NULL")) {
1214
+ const token = this.advance();
1215
+ return {
1216
+ kind: "literal",
1217
+ value: null,
1218
+ literalType: "null",
1219
+ location: token.location
1220
+ };
1221
+ }
1222
+ if (this.check("SYSTEM_IDENT")) {
1223
+ const token = this.advance();
1224
+ const path = token.lexeme.slice(1).split(".");
1225
+ return this.parsePostfix({
1226
+ kind: "systemIdent",
1227
+ path,
1228
+ location: token.location
1229
+ });
1230
+ }
1231
+ if (this.check("ITEM")) {
1232
+ const token = this.advance();
1233
+ return this.parsePostfix({
1234
+ kind: "iterationVar",
1235
+ name: "item",
1236
+ location: token.location
1237
+ });
1238
+ }
1239
+ if (this.check("MERGE") && this.peekNext()?.kind === "LPAREN") {
1240
+ const token = this.advance();
1241
+ return this.parseFunctionCall(token);
1242
+ }
1243
+ if (this.check("IDENTIFIER")) {
1244
+ const token = this.advance();
1245
+ if (this.check("LPAREN")) {
1246
+ return this.parseFunctionCall(token);
1247
+ }
1248
+ return this.parsePostfix({
1249
+ kind: "identifier",
1250
+ name: token.lexeme,
1251
+ location: token.location
1252
+ });
1253
+ }
1254
+ this.error(`Unexpected token '${this.peek().lexeme}'`);
1255
+ return {
1256
+ kind: "literal",
1257
+ value: null,
1258
+ literalType: "null",
1259
+ location: this.peek().location
1260
+ };
1261
+ }
1262
+ parseFunctionCall(nameToken) {
1263
+ this.consume("LPAREN", "Expected '(' for function call");
1264
+ const args = [];
1265
+ if (!this.check("RPAREN")) {
1266
+ do {
1267
+ args.push(this.parseExpression());
1268
+ } while (this.match("COMMA"));
1269
+ }
1270
+ const end = this.consume("RPAREN", "Expected ')' after arguments").location;
1271
+ return this.parsePostfix({
1272
+ kind: "functionCall",
1273
+ name: nameToken.lexeme,
1274
+ args,
1275
+ location: mergeLocations(nameToken.location, end)
1276
+ });
1277
+ }
1278
+ parsePostfix(expr) {
1279
+ while (true) {
1280
+ if (this.match("DOT")) {
1281
+ const prop = this.consume("IDENTIFIER", "Expected property name after '.'");
1282
+ expr = {
1283
+ kind: "propertyAccess",
1284
+ object: expr,
1285
+ property: prop.lexeme,
1286
+ location: mergeLocations(expr.location, prop.location)
1287
+ };
1288
+ } else if (this.match("LBRACKET")) {
1289
+ const index = this.parseExpression();
1290
+ const end = this.consume("RBRACKET", "Expected ']' after index").location;
1291
+ expr = {
1292
+ kind: "indexAccess",
1293
+ object: expr,
1294
+ index,
1295
+ location: mergeLocations(expr.location, end)
1296
+ };
1297
+ } else {
1298
+ break;
1299
+ }
1300
+ }
1301
+ return expr;
1302
+ }
1303
+ parseObjectLiteral() {
1304
+ const start = this.consume("LBRACE", "Expected '{'").location;
1305
+ const properties = [];
1306
+ while (!this.check("RBRACE") && !this.isAtEnd()) {
1307
+ const keyToken = this.consume("IDENTIFIER", "Expected property name");
1308
+ this.consume("COLON", "Expected ':' after property name");
1309
+ const value = this.parseExpression();
1310
+ properties.push({
1311
+ kind: "objectProperty",
1312
+ key: keyToken.lexeme,
1313
+ value,
1314
+ location: mergeLocations(keyToken.location, value.location)
1315
+ });
1316
+ if (!this.check("RBRACE")) {
1317
+ this.consume("COMMA", "Expected ',' between properties");
1318
+ }
1319
+ }
1320
+ const end = this.consume("RBRACE", "Expected '}' to close object").location;
1321
+ return {
1322
+ kind: "objectLiteral",
1323
+ properties,
1324
+ location: mergeLocations(start, end)
1325
+ };
1326
+ }
1327
+ parseArrayLiteral() {
1328
+ const start = this.consume("LBRACKET", "Expected '['").location;
1329
+ const elements = [];
1330
+ while (!this.check("RBRACKET") && !this.isAtEnd()) {
1331
+ elements.push(this.parseExpression());
1332
+ if (!this.check("RBRACKET")) {
1333
+ this.consume("COMMA", "Expected ',' between elements");
1334
+ }
1335
+ }
1336
+ const end = this.consume("RBRACKET", "Expected ']' to close array").location;
1337
+ return {
1338
+ kind: "arrayLiteral",
1339
+ elements,
1340
+ location: mergeLocations(start, end)
1341
+ };
1342
+ }
1343
+ // ============ Path ============
1344
+ parsePath() {
1345
+ const segments = [];
1346
+ const start = this.peek().location;
1347
+ const first = this.consume("IDENTIFIER", "Expected identifier");
1348
+ segments.push({
1349
+ kind: "propertySegment",
1350
+ name: first.lexeme,
1351
+ location: first.location
1352
+ });
1353
+ while (true) {
1354
+ if (this.match("DOT")) {
1355
+ const prop = this.consume("IDENTIFIER", "Expected property name");
1356
+ segments.push({
1357
+ kind: "propertySegment",
1358
+ name: prop.lexeme,
1359
+ location: prop.location
1360
+ });
1361
+ } else if (this.match("LBRACKET")) {
1362
+ const index = this.parseExpression();
1363
+ const end = this.consume("RBRACKET", "Expected ']'").location;
1364
+ segments.push({
1365
+ kind: "indexSegment",
1366
+ index,
1367
+ location: mergeLocations(index.location, end)
1368
+ });
1369
+ } else {
1370
+ break;
1371
+ }
1372
+ }
1373
+ const last = segments[segments.length - 1];
1374
+ return {
1375
+ kind: "path",
1376
+ segments,
1377
+ location: mergeLocations(start, last.location)
1378
+ };
1379
+ }
1380
+ // ============ Helpers ============
1381
+ isUnaryContext() {
1382
+ if (this.current === 0) return true;
1383
+ const prev = this.previous();
1384
+ const unaryPrecedingTokens = [
1385
+ "LPAREN",
1386
+ "LBRACKET",
1387
+ "LBRACE",
1388
+ "COMMA",
1389
+ "COLON",
1390
+ "EQ",
1391
+ "PLUS",
1392
+ "MINUS",
1393
+ "STAR",
1394
+ "SLASH",
1395
+ "PERCENT",
1396
+ "EQ_EQ",
1397
+ "BANG_EQ",
1398
+ "LT",
1399
+ "LT_EQ",
1400
+ "GT",
1401
+ "GT_EQ",
1402
+ "AMP_AMP",
1403
+ "PIPE_PIPE",
1404
+ "BANG",
1405
+ "QUESTION",
1406
+ "QUESTION_QUESTION"
1407
+ ];
1408
+ return unaryPrecedingTokens.includes(prev.kind);
1409
+ }
1410
+ peek() {
1411
+ return this.tokens[this.current];
1412
+ }
1413
+ peekNext() {
1414
+ if (this.current + 1 >= this.tokens.length) {
1415
+ return this.tokens[this.tokens.length - 1];
1416
+ }
1417
+ return this.tokens[this.current + 1];
1418
+ }
1419
+ previous() {
1420
+ return this.tokens[this.current - 1];
1421
+ }
1422
+ isAtEnd() {
1423
+ return this.peek().kind === "EOF";
1424
+ }
1425
+ advance() {
1426
+ if (!this.isAtEnd()) this.current++;
1427
+ return this.previous();
1428
+ }
1429
+ check(kind) {
1430
+ if (this.isAtEnd()) return false;
1431
+ return this.peek().kind === kind;
1432
+ }
1433
+ isOnceIntentContext() {
1434
+ if (!this.check("IDENTIFIER")) return false;
1435
+ const token = this.peek();
1436
+ if (token.lexeme !== "onceIntent") return false;
1437
+ const next = this.peekNext();
1438
+ return next.kind === "LBRACE" || next.kind === "WHEN";
1439
+ }
1440
+ match(...kinds) {
1441
+ for (const kind of kinds) {
1442
+ if (this.check(kind)) {
1443
+ this.advance();
1444
+ return true;
1445
+ }
1446
+ }
1447
+ return false;
1448
+ }
1449
+ consume(kind, message) {
1450
+ if (this.check(kind)) return this.advance();
1451
+ throw this.errorAtCurrent(message);
1452
+ }
1453
+ error(message) {
1454
+ this.diagnostics.push({
1455
+ severity: "error",
1456
+ code: "MEL_PARSER",
1457
+ message,
1458
+ location: this.previous().location
1459
+ });
1460
+ }
1461
+ errorAtCurrent(message) {
1462
+ this.diagnostics.push({
1463
+ severity: "error",
1464
+ code: "MEL_PARSER",
1465
+ message,
1466
+ location: this.peek().location
1467
+ });
1468
+ return new Error(message);
1469
+ }
1470
+ };
1471
+ function parse(tokens) {
1472
+ const parser = new Parser(tokens);
1473
+ return parser.parse();
1474
+ }
1475
+
1476
+ // src/analyzer/scope.ts
1477
+ var Scope = class {
1478
+ parent;
1479
+ symbols = /* @__PURE__ */ new Map();
1480
+ kind;
1481
+ constructor(kind, parent = null) {
1482
+ this.kind = kind;
1483
+ this.parent = parent;
1484
+ }
1485
+ /**
1486
+ * Define a new symbol in this scope
1487
+ */
1488
+ define(symbol) {
1489
+ this.symbols.set(symbol.name, symbol);
1490
+ }
1491
+ /**
1492
+ * Look up a symbol, searching parent scopes if not found
1493
+ */
1494
+ lookup(name) {
1495
+ const symbol = this.symbols.get(name);
1496
+ if (symbol) return symbol;
1497
+ return this.parent?.lookup(name);
1498
+ }
1499
+ /**
1500
+ * Check if a symbol is defined in this scope (not parent scopes)
1501
+ */
1502
+ isDefined(name) {
1503
+ return this.symbols.has(name);
1504
+ }
1505
+ };
1506
+ var ScopeAnalyzer = class {
1507
+ diagnostics = [];
1508
+ scopes = /* @__PURE__ */ new Map();
1509
+ currentScope = null;
1510
+ domainScope = null;
1511
+ /**
1512
+ * Analyze a MEL program
1513
+ */
1514
+ analyze(program) {
1515
+ this.diagnostics = [];
1516
+ this.scopes = /* @__PURE__ */ new Map();
1517
+ this.currentScope = null;
1518
+ this.domainScope = null;
1519
+ this.analyzeDomain(program.domain);
1520
+ return {
1521
+ scopes: this.scopes,
1522
+ diagnostics: this.diagnostics
1523
+ };
1524
+ }
1525
+ analyzeDomain(domain) {
1526
+ const scope = new Scope("domain");
1527
+ this.domainScope = scope;
1528
+ this.currentScope = scope;
1529
+ this.scopes.set("domain", scope);
1530
+ for (const member of domain.members) {
1531
+ if (member.kind === "state") {
1532
+ for (const field of member.fields) {
1533
+ this.defineSymbol({
1534
+ name: field.name,
1535
+ kind: "state",
1536
+ location: field.location
1537
+ });
1538
+ }
1539
+ } else if (member.kind === "computed") {
1540
+ this.defineSymbol({
1541
+ name: member.name,
1542
+ kind: "computed",
1543
+ location: member.location
1544
+ });
1545
+ } else if (member.kind === "action") {
1546
+ this.defineSymbol({
1547
+ name: member.name,
1548
+ kind: "action",
1549
+ location: member.location
1550
+ });
1551
+ }
1552
+ }
1553
+ for (const member of domain.members) {
1554
+ if (member.kind === "computed") {
1555
+ this.analyzeComputedExpr(member);
1556
+ } else if (member.kind === "action") {
1557
+ this.analyzeAction(member);
1558
+ }
1559
+ }
1560
+ }
1561
+ analyzeComputedExpr(computed) {
1562
+ this.analyzeExpr(computed.expression, "computed");
1563
+ }
1564
+ analyzeAction(action) {
1565
+ const scope = new Scope("action", this.domainScope);
1566
+ this.currentScope = scope;
1567
+ this.scopes.set(`action.${action.name}`, scope);
1568
+ for (const param of action.params) {
1569
+ scope.define({
1570
+ name: param.name,
1571
+ kind: "param",
1572
+ location: param.location
1573
+ });
1574
+ }
1575
+ for (const stmt of action.body) {
1576
+ this.analyzeStmt(stmt);
1577
+ }
1578
+ this.currentScope = this.domainScope;
1579
+ }
1580
+ analyzeStmt(stmt) {
1581
+ switch (stmt.kind) {
1582
+ case "when":
1583
+ this.analyzeExpr(stmt.condition, "action");
1584
+ for (const inner of stmt.body) {
1585
+ this.analyzeStmt(inner);
1586
+ }
1587
+ break;
1588
+ case "onceIntent":
1589
+ if (stmt.condition) {
1590
+ this.analyzeExpr(stmt.condition, "action");
1591
+ }
1592
+ for (const inner of stmt.body) {
1593
+ this.analyzeStmt(inner);
1594
+ }
1595
+ break;
1596
+ case "once":
1597
+ this.validatePath(stmt.marker);
1598
+ if (stmt.condition) {
1599
+ this.analyzeExpr(stmt.condition, "action");
1600
+ }
1601
+ for (const inner of stmt.body) {
1602
+ this.analyzeStmt(inner);
1603
+ }
1604
+ break;
1605
+ case "patch":
1606
+ this.validatePath(stmt.path);
1607
+ if (stmt.value) {
1608
+ this.analyzeExpr(stmt.value, "action");
1609
+ }
1610
+ break;
1611
+ case "effect":
1612
+ for (const arg of stmt.args) {
1613
+ if (arg.isPath) {
1614
+ this.validatePath(arg.value);
1615
+ } else {
1616
+ this.analyzeExpr(arg.value, "action");
1617
+ }
1618
+ }
1619
+ break;
1620
+ }
1621
+ }
1622
+ analyzeExpr(expr, context) {
1623
+ switch (expr.kind) {
1624
+ case "identifier":
1625
+ this.checkIdentifier(expr.name, expr.location, context);
1626
+ break;
1627
+ case "systemIdent":
1628
+ this.checkSystemIdent(expr.path, expr.location, context);
1629
+ break;
1630
+ case "propertyAccess":
1631
+ this.analyzeExpr(expr.object, context);
1632
+ break;
1633
+ case "indexAccess":
1634
+ this.analyzeExpr(expr.object, context);
1635
+ this.analyzeExpr(expr.index, context);
1636
+ break;
1637
+ case "functionCall":
1638
+ for (const arg of expr.args) {
1639
+ this.analyzeExpr(arg, context);
1640
+ }
1641
+ break;
1642
+ case "binary":
1643
+ this.analyzeExpr(expr.left, context);
1644
+ this.analyzeExpr(expr.right, context);
1645
+ break;
1646
+ case "unary":
1647
+ this.analyzeExpr(expr.operand, context);
1648
+ break;
1649
+ case "ternary":
1650
+ this.analyzeExpr(expr.condition, context);
1651
+ this.analyzeExpr(expr.consequent, context);
1652
+ this.analyzeExpr(expr.alternate, context);
1653
+ break;
1654
+ case "objectLiteral":
1655
+ for (const prop of expr.properties) {
1656
+ this.analyzeExpr(prop.value, context);
1657
+ }
1658
+ break;
1659
+ case "arrayLiteral":
1660
+ for (const elem of expr.elements) {
1661
+ this.analyzeExpr(elem, context);
1662
+ }
1663
+ break;
1664
+ case "iterationVar":
1665
+ break;
1666
+ case "literal":
1667
+ break;
1668
+ }
1669
+ }
1670
+ checkIdentifier(name, location, context) {
1671
+ const symbol = this.currentScope?.lookup(name);
1672
+ if (!symbol) {
1673
+ this.error(`Undefined identifier '${name}'`, location, "E_UNDEFINED");
1674
+ return;
1675
+ }
1676
+ if (context === "computed") {
1677
+ if (symbol.kind === "param") {
1678
+ this.error(
1679
+ `Cannot access parameter '${name}' in computed expression`,
1680
+ location,
1681
+ "E_INVALID_ACCESS"
1682
+ );
1683
+ }
1684
+ }
1685
+ }
1686
+ checkSystemIdent(path, location, context) {
1687
+ const [namespace, ...rest] = path;
1688
+ if (namespace === "system" && context === "computed") {
1689
+ this.error(
1690
+ `Cannot use $system.* in computed expressions (non-deterministic)`,
1691
+ location,
1692
+ "E001"
1693
+ );
1694
+ }
1695
+ if (namespace === "system") {
1696
+ const validKeys = ["uuid", "timestamp", "time.now", "random"];
1697
+ const key = rest.join(".");
1698
+ if (key && !validKeys.includes(key)) {
1699
+ this.error(
1700
+ `Invalid system value '$system.${key}'. Valid values: ${validKeys.join(", ")}`,
1701
+ location,
1702
+ "E003"
1703
+ );
1704
+ }
1705
+ }
1706
+ if (namespace === "meta") {
1707
+ const validKeys = ["intentId", "actionName", "timestamp"];
1708
+ const key = rest.join(".");
1709
+ if (key && !validKeys.includes(key)) {
1710
+ this.error(
1711
+ `Invalid meta value '$meta.${key}'. Valid values: ${validKeys.join(", ")}`,
1712
+ location,
1713
+ "E003"
1714
+ );
1715
+ }
1716
+ }
1717
+ }
1718
+ validatePath(path) {
1719
+ if (!path || !path.segments) return;
1720
+ const first = path.segments[0];
1721
+ if (first?.kind === "propertySegment") {
1722
+ const symbol = this.currentScope?.lookup(first.name);
1723
+ if (!symbol) {
1724
+ this.error(
1725
+ `Undefined identifier '${first.name}' in path`,
1726
+ path.location,
1727
+ "E_UNDEFINED"
1728
+ );
1729
+ }
1730
+ }
1731
+ }
1732
+ defineSymbol(symbol) {
1733
+ if (!this.currentScope) return;
1734
+ if (this.currentScope.isDefined(symbol.name)) {
1735
+ this.error(
1736
+ `Duplicate identifier '${symbol.name}'`,
1737
+ symbol.location,
1738
+ "E_DUPLICATE"
1739
+ );
1740
+ return;
1741
+ }
1742
+ this.currentScope.define(symbol);
1743
+ }
1744
+ error(message, location, code) {
1745
+ this.diagnostics.push({
1746
+ severity: "error",
1747
+ code,
1748
+ message,
1749
+ location
1750
+ });
1751
+ }
1752
+ };
1753
+ function analyzeScope(program) {
1754
+ const analyzer = new ScopeAnalyzer();
1755
+ return analyzer.analyze(program);
1756
+ }
1757
+
1758
+ // src/diagnostics/types.ts
1759
+ function createError(code, message, location, options) {
1760
+ return {
1761
+ severity: "error",
1762
+ code,
1763
+ message,
1764
+ location,
1765
+ ...options
1766
+ };
1767
+ }
1768
+ function createWarning(code, message, location, options) {
1769
+ return {
1770
+ severity: "warning",
1771
+ code,
1772
+ message,
1773
+ location,
1774
+ ...options
1775
+ };
1776
+ }
1777
+ function createInfo(code, message, location) {
1778
+ return {
1779
+ severity: "info",
1780
+ code,
1781
+ message,
1782
+ location
1783
+ };
1784
+ }
1785
+ function isError(diagnostic) {
1786
+ return diagnostic.severity === "error";
1787
+ }
1788
+ function hasErrors(diagnostics) {
1789
+ return diagnostics.some(isError);
1790
+ }
1791
+ function filterBySeverity(diagnostics, severity) {
1792
+ return diagnostics.filter((d) => d.severity === severity);
1793
+ }
1794
+
1795
+ // src/analyzer/validator.ts
1796
+ function createContext() {
1797
+ return {
1798
+ inAction: false,
1799
+ inGuard: false,
1800
+ guardDepth: 0,
1801
+ hasMarkerPatch: false,
1802
+ diagnostics: []
1803
+ };
1804
+ }
1805
+ var SemanticValidator = class {
1806
+ ctx = createContext();
1807
+ /**
1808
+ * Validate a MEL program
1809
+ */
1810
+ validate(program) {
1811
+ this.ctx = createContext();
1812
+ this.validateDomain(program.domain);
1813
+ return {
1814
+ valid: !this.ctx.diagnostics.some((d) => d.severity === "error"),
1815
+ diagnostics: this.ctx.diagnostics
1816
+ };
1817
+ }
1818
+ validateDomain(domain) {
1819
+ if (domain.name.startsWith("__")) {
1820
+ this.error(
1821
+ "Domain name cannot start with '__' (reserved prefix)",
1822
+ domain.location,
1823
+ "E_RESERVED_NAME"
1824
+ );
1825
+ }
1826
+ for (const member of domain.members) {
1827
+ switch (member.kind) {
1828
+ case "state":
1829
+ this.validateState(member);
1830
+ break;
1831
+ case "computed":
1832
+ this.validateExpr(member.expression, "computed");
1833
+ break;
1834
+ case "action":
1835
+ this.validateAction(member);
1836
+ break;
1837
+ }
1838
+ }
1839
+ }
1840
+ /**
1841
+ * v0.3.3: Validate state fields for W012 (anonymous object types)
1842
+ */
1843
+ validateState(state) {
1844
+ const seen = /* @__PURE__ */ new Map();
1845
+ for (const field of state.fields) {
1846
+ const prev = seen.get(field.name);
1847
+ if (prev) {
1848
+ this.error(
1849
+ `Duplicate state field '${field.name}'. First declared at line ${prev.start.line}`,
1850
+ field.location,
1851
+ "E_DUPLICATE_FIELD"
1852
+ );
1853
+ } else {
1854
+ seen.set(field.name, field.location);
1855
+ }
1856
+ this.validateStateField(field);
1857
+ }
1858
+ }
1859
+ /**
1860
+ * v0.3.3: Validate state field - check for anonymous object types (W012)
1861
+ */
1862
+ validateStateField(field) {
1863
+ this.checkAnonymousObjectType(field.typeExpr, field.location);
1864
+ }
1865
+ /**
1866
+ * v0.3.3: Check if a type expression contains anonymous object types
1867
+ * Issues W012 warning for inline object types in state fields
1868
+ */
1869
+ checkAnonymousObjectType(typeExpr, fieldLocation) {
1870
+ switch (typeExpr.kind) {
1871
+ case "objectType":
1872
+ this.ctx.diagnostics.push(
1873
+ createWarning(
1874
+ "W012",
1875
+ "Anonymous object type in state field. Use a named type declaration instead: type MyType = { ... }",
1876
+ typeExpr.location,
1877
+ {
1878
+ suggestion: "Define this type using 'type TypeName = { ... }' and reference it by name"
1879
+ }
1880
+ )
1881
+ );
1882
+ for (const f of typeExpr.fields) {
1883
+ this.checkAnonymousObjectType(f.typeExpr, fieldLocation);
1884
+ }
1885
+ break;
1886
+ case "arrayType":
1887
+ this.checkAnonymousObjectType(typeExpr.elementType, fieldLocation);
1888
+ break;
1889
+ case "recordType":
1890
+ this.checkAnonymousObjectType(typeExpr.keyType, fieldLocation);
1891
+ this.checkAnonymousObjectType(typeExpr.valueType, fieldLocation);
1892
+ break;
1893
+ case "unionType":
1894
+ for (const t of typeExpr.types) {
1895
+ this.checkAnonymousObjectType(t, fieldLocation);
1896
+ }
1897
+ break;
1898
+ }
1899
+ }
1900
+ validateAction(action) {
1901
+ this.ctx.inAction = true;
1902
+ if (action.available) {
1903
+ this.validateAvailableExpr(action.available);
1904
+ }
1905
+ for (const stmt of action.body) {
1906
+ this.validateGuardedStmt(stmt);
1907
+ }
1908
+ this.ctx.inAction = false;
1909
+ }
1910
+ /**
1911
+ * v0.3.3: Validate available expression is pure (E005)
1912
+ * No $system.*, no effects, no $input.*
1913
+ */
1914
+ validateAvailableExpr(expr) {
1915
+ switch (expr.kind) {
1916
+ case "systemIdent":
1917
+ if (expr.path[0] === "system") {
1918
+ this.error(
1919
+ "$system.* cannot be used in available condition (must be pure expression)",
1920
+ expr.location,
1921
+ "E005"
1922
+ );
1923
+ }
1924
+ if (expr.path[0] === "input") {
1925
+ this.error(
1926
+ "$input.* cannot be used in available condition (parameters not available at availability check)",
1927
+ expr.location,
1928
+ "E005"
1929
+ );
1930
+ }
1931
+ break;
1932
+ case "functionCall":
1933
+ for (const arg of expr.args) {
1934
+ this.validateAvailableExpr(arg);
1935
+ }
1936
+ break;
1937
+ case "binary":
1938
+ this.validateAvailableExpr(expr.left);
1939
+ this.validateAvailableExpr(expr.right);
1940
+ break;
1941
+ case "unary":
1942
+ this.validateAvailableExpr(expr.operand);
1943
+ break;
1944
+ case "ternary":
1945
+ this.validateAvailableExpr(expr.condition);
1946
+ this.validateAvailableExpr(expr.consequent);
1947
+ this.validateAvailableExpr(expr.alternate);
1948
+ break;
1949
+ case "propertyAccess":
1950
+ this.validateAvailableExpr(expr.object);
1951
+ break;
1952
+ case "indexAccess":
1953
+ this.validateAvailableExpr(expr.object);
1954
+ this.validateAvailableExpr(expr.index);
1955
+ break;
1956
+ case "objectLiteral":
1957
+ for (const prop of expr.properties) {
1958
+ this.validateAvailableExpr(prop.value);
1959
+ }
1960
+ break;
1961
+ case "arrayLiteral":
1962
+ for (const elem of expr.elements) {
1963
+ this.validateAvailableExpr(elem);
1964
+ }
1965
+ break;
1966
+ }
1967
+ }
1968
+ validateGuardedStmt(stmt) {
1969
+ switch (stmt.kind) {
1970
+ case "when":
1971
+ this.validateWhen(stmt);
1972
+ break;
1973
+ case "once":
1974
+ this.validateOnce(stmt);
1975
+ break;
1976
+ case "onceIntent":
1977
+ this.validateOnceIntent(stmt);
1978
+ break;
1979
+ case "patch":
1980
+ this.validatePatch(stmt);
1981
+ break;
1982
+ case "effect":
1983
+ this.validateEffect(stmt);
1984
+ break;
1985
+ }
1986
+ }
1987
+ validateWhen(stmt) {
1988
+ this.ctx.inGuard = true;
1989
+ this.ctx.guardDepth++;
1990
+ this.validateCondition(stmt.condition, "when");
1991
+ for (const inner of stmt.body) {
1992
+ this.validateGuardedStmt(inner);
1993
+ }
1994
+ this.ctx.guardDepth--;
1995
+ if (this.ctx.guardDepth === 0) {
1996
+ this.ctx.inGuard = false;
1997
+ }
1998
+ }
1999
+ validateOnce(stmt) {
2000
+ this.ctx.inGuard = true;
2001
+ this.ctx.guardDepth++;
2002
+ this.ctx.hasMarkerPatch = false;
2003
+ if (stmt.condition) {
2004
+ this.validateCondition(stmt.condition, "once");
2005
+ }
2006
+ for (const inner of stmt.body) {
2007
+ this.validateGuardedStmt(inner);
2008
+ }
2009
+ this.ctx.guardDepth--;
2010
+ if (this.ctx.guardDepth === 0) {
2011
+ this.ctx.inGuard = false;
2012
+ }
2013
+ }
2014
+ validateOnceIntent(stmt) {
2015
+ this.ctx.inGuard = true;
2016
+ this.ctx.guardDepth++;
2017
+ if (stmt.condition) {
2018
+ this.validateCondition(stmt.condition, "onceIntent");
2019
+ }
2020
+ for (const inner of stmt.body) {
2021
+ this.validateGuardedStmt(inner);
2022
+ }
2023
+ this.ctx.guardDepth--;
2024
+ if (this.ctx.guardDepth === 0) {
2025
+ this.ctx.inGuard = false;
2026
+ }
2027
+ }
2028
+ validatePatch(stmt) {
2029
+ if (!this.ctx.inGuard) {
2030
+ this.error(
2031
+ "Patch must be inside a guard (when, once, or onceIntent)",
2032
+ stmt.location,
2033
+ "E_UNGUARDED_PATCH"
2034
+ );
2035
+ }
2036
+ if (stmt.value) {
2037
+ this.validateExpr(stmt.value, "action");
2038
+ }
2039
+ }
2040
+ validateEffect(stmt) {
2041
+ if (!this.ctx.inGuard) {
2042
+ this.error(
2043
+ "Effect must be inside a guard (when, once, or onceIntent)",
2044
+ stmt.location,
2045
+ "E_UNGUARDED_EFFECT"
2046
+ );
2047
+ }
2048
+ for (const arg of stmt.args) {
2049
+ if (!arg.isPath) {
2050
+ this.validateExpr(arg.value, "action");
2051
+ }
2052
+ }
2053
+ }
2054
+ validateCondition(expr, guardType) {
2055
+ this.validateExpr(expr, "action");
2056
+ if (expr.kind === "literal" && typeof expr.value !== "boolean") {
2057
+ this.warn(
2058
+ `Condition in ${guardType} is a non-boolean literal. Consider using a boolean expression`,
2059
+ expr.location,
2060
+ "W_NON_BOOL_COND"
2061
+ );
2062
+ }
2063
+ }
2064
+ validateExpr(expr, context) {
2065
+ switch (expr.kind) {
2066
+ case "functionCall":
2067
+ this.validateFunctionCall(expr, context);
2068
+ break;
2069
+ case "binary":
2070
+ this.validateExpr(expr.left, context);
2071
+ this.validateExpr(expr.right, context);
2072
+ break;
2073
+ case "unary":
2074
+ this.validateExpr(expr.operand, context);
2075
+ break;
2076
+ case "ternary":
2077
+ this.validateExpr(expr.condition, context);
2078
+ this.validateExpr(expr.consequent, context);
2079
+ this.validateExpr(expr.alternate, context);
2080
+ break;
2081
+ case "propertyAccess":
2082
+ this.validateExpr(expr.object, context);
2083
+ break;
2084
+ case "indexAccess":
2085
+ this.validateExpr(expr.object, context);
2086
+ this.validateExpr(expr.index, context);
2087
+ break;
2088
+ case "objectLiteral":
2089
+ for (const prop of expr.properties) {
2090
+ this.validateExpr(prop.value, context);
2091
+ }
2092
+ break;
2093
+ case "arrayLiteral":
2094
+ for (const elem of expr.elements) {
2095
+ this.validateExpr(elem, context);
2096
+ }
2097
+ break;
2098
+ case "systemIdent":
2099
+ break;
2100
+ }
2101
+ }
2102
+ validateFunctionCall(expr, context) {
2103
+ const { name, args, location } = expr;
2104
+ if (["reduce", "fold", "foldl", "foldr", "scan"].includes(name)) {
2105
+ this.error(
2106
+ `Function '${name}' is forbidden. Use sum(), min(), max() for aggregation instead`,
2107
+ location,
2108
+ "E011"
2109
+ );
2110
+ }
2111
+ if (["sum", "min", "max"].includes(name) && args.length === 1) {
2112
+ if (context === "action") {
2113
+ this.error(
2114
+ `Primitive aggregation '${name}()' can only be used in computed expressions, not in actions`,
2115
+ location,
2116
+ "E009"
2117
+ );
2118
+ }
2119
+ const arg = args[0];
2120
+ if (arg.kind === "functionCall") {
2121
+ this.error(
2122
+ `Primitive aggregation '${name}()' does not allow composition. Use a direct reference, not '${arg.name}()'`,
2123
+ location,
2124
+ "E010"
2125
+ );
2126
+ }
2127
+ }
2128
+ switch (name) {
2129
+ // FDR-MEL-042: eq/neq on primitives only
2130
+ case "eq":
2131
+ case "neq":
2132
+ break;
2133
+ // FDR-MEL-026: len() on Array only
2134
+ case "len":
2135
+ // v0.3.3: sum() for array aggregation
2136
+ case "sum":
2137
+ if (args.length !== 1) {
2138
+ this.error(
2139
+ `Function '${name}' expects 1 argument, got ${args.length}`,
2140
+ location,
2141
+ "E_ARG_COUNT"
2142
+ );
2143
+ }
2144
+ break;
2145
+ // Binary functions need exactly 2 args
2146
+ case "add":
2147
+ case "sub":
2148
+ case "mul":
2149
+ case "div":
2150
+ case "mod":
2151
+ case "gt":
2152
+ case "gte":
2153
+ case "lt":
2154
+ case "lte":
2155
+ if (args.length !== 2) {
2156
+ this.error(
2157
+ `Function '${name}' expects 2 arguments, got ${args.length}`,
2158
+ location,
2159
+ "E_ARG_COUNT"
2160
+ );
2161
+ }
2162
+ break;
2163
+ // Unary functions need exactly 1 arg
2164
+ case "not":
2165
+ case "neg":
2166
+ case "abs":
2167
+ case "floor":
2168
+ case "ceil":
2169
+ case "round":
2170
+ case "sqrt":
2171
+ case "isNull":
2172
+ case "isNotNull":
2173
+ case "trim":
2174
+ case "lower":
2175
+ case "upper":
2176
+ case "strlen":
2177
+ case "keys":
2178
+ case "values":
2179
+ case "entries":
2180
+ case "first":
2181
+ case "last":
2182
+ case "typeof":
2183
+ case "toString":
2184
+ case "toNumber":
2185
+ case "toBoolean":
2186
+ case "reverse":
2187
+ case "unique":
2188
+ case "flat":
2189
+ case "fromEntries":
2190
+ if (args.length !== 1) {
2191
+ this.error(
2192
+ `Function '${name}' expects 1 argument, got ${args.length}`,
2193
+ location,
2194
+ "E_ARG_COUNT"
2195
+ );
2196
+ }
2197
+ break;
2198
+ // Binary functions need exactly 2 args
2199
+ case "pow":
2200
+ case "filter":
2201
+ case "map":
2202
+ case "find":
2203
+ case "every":
2204
+ case "some":
2205
+ case "at":
2206
+ case "includes":
2207
+ case "field":
2208
+ case "hasKey":
2209
+ case "pick":
2210
+ case "omit":
2211
+ case "startsWith":
2212
+ case "endsWith":
2213
+ case "strIncludes":
2214
+ case "indexOf":
2215
+ if (args.length !== 2) {
2216
+ this.error(
2217
+ `Function '${name}' expects 2 arguments, got ${args.length}`,
2218
+ location,
2219
+ "E_ARG_COUNT"
2220
+ );
2221
+ }
2222
+ break;
2223
+ // 2-3 arg functions
2224
+ case "slice":
2225
+ case "substring":
2226
+ case "substr":
2227
+ case "replace":
2228
+ if (args.length < 2 || args.length > 3) {
2229
+ this.error(
2230
+ `Function '${name}' expects 2-3 arguments, got ${args.length}`,
2231
+ location,
2232
+ "E_ARG_COUNT"
2233
+ );
2234
+ }
2235
+ break;
2236
+ // split(str, delimiter)
2237
+ case "split":
2238
+ if (args.length !== 2) {
2239
+ this.error(
2240
+ `Function '${name}' expects 2 arguments, got ${args.length}`,
2241
+ location,
2242
+ "E_ARG_COUNT"
2243
+ );
2244
+ }
2245
+ break;
2246
+ // Variadic functions (at least 1 arg)
2247
+ case "and":
2248
+ case "or":
2249
+ case "concat":
2250
+ case "min":
2251
+ case "max":
2252
+ case "merge":
2253
+ case "coalesce":
2254
+ case "append":
2255
+ if (args.length < 1) {
2256
+ this.error(
2257
+ `Function '${name}' expects at least 1 argument`,
2258
+ location,
2259
+ "E_ARG_COUNT"
2260
+ );
2261
+ }
2262
+ break;
2263
+ // Conditional needs exactly 3 args
2264
+ case "if":
2265
+ case "cond":
2266
+ if (args.length !== 3) {
2267
+ this.error(
2268
+ `Function '${name}' expects 3 arguments, got ${args.length}`,
2269
+ location,
2270
+ "E_ARG_COUNT"
2271
+ );
2272
+ }
2273
+ break;
2274
+ default:
2275
+ this.error(
2276
+ `Unknown function '${name}'. Check spelling or see MEL builtin function reference`,
2277
+ location,
2278
+ "E_UNKNOWN_FN"
2279
+ );
2280
+ break;
2281
+ }
2282
+ for (const arg of args) {
2283
+ this.validateExpr(arg, context);
2284
+ }
2285
+ }
2286
+ error(message, location, code) {
2287
+ this.ctx.diagnostics.push({
2288
+ severity: "error",
2289
+ code,
2290
+ message,
2291
+ location
2292
+ });
2293
+ }
2294
+ warn(message, location, code) {
2295
+ this.ctx.diagnostics.push({
2296
+ severity: "warning",
2297
+ code,
2298
+ message,
2299
+ location
2300
+ });
2301
+ }
2302
+ };
2303
+ function validateSemantics(program) {
2304
+ const validator = new SemanticValidator();
2305
+ return validator.validate(program);
2306
+ }
2307
+
2308
+ // src/generator/normalizer.ts
2309
+ function normalizeExpr(op, left, right) {
2310
+ switch (op) {
2311
+ // Arithmetic
2312
+ case "+":
2313
+ return { kind: "add", left, right };
2314
+ case "-":
2315
+ return { kind: "sub", left, right };
2316
+ case "*":
2317
+ return { kind: "mul", left, right };
2318
+ case "/":
2319
+ return { kind: "div", left, right };
2320
+ case "%":
2321
+ return { kind: "mod", left, right };
2322
+ // Comparison
2323
+ case "==":
2324
+ return { kind: "eq", left, right };
2325
+ case "!=":
2326
+ return { kind: "neq", left, right };
2327
+ case "<":
2328
+ return { kind: "lt", left, right };
2329
+ case "<=":
2330
+ return { kind: "lte", left, right };
2331
+ case ">":
2332
+ return { kind: "gt", left, right };
2333
+ case ">=":
2334
+ return { kind: "gte", left, right };
2335
+ // Logical
2336
+ case "&&":
2337
+ return { kind: "and", args: [left, right] };
2338
+ case "||":
2339
+ return { kind: "or", args: [left, right] };
2340
+ // Nullish coalescing
2341
+ case "??":
2342
+ return { kind: "coalesce", args: [left, right] };
2343
+ }
2344
+ }
2345
+ function normalizeFunctionCall(name, args) {
2346
+ switch (name) {
2347
+ // ============ Arithmetic ============
2348
+ case "add":
2349
+ return { kind: "add", left: args[0], right: args[1] };
2350
+ case "sub":
2351
+ return { kind: "sub", left: args[0], right: args[1] };
2352
+ case "mul":
2353
+ return { kind: "mul", left: args[0], right: args[1] };
2354
+ case "div":
2355
+ return { kind: "div", left: args[0], right: args[1] };
2356
+ case "mod":
2357
+ return { kind: "mod", left: args[0], right: args[1] };
2358
+ case "neg":
2359
+ return { kind: "neg", arg: args[0] };
2360
+ case "abs":
2361
+ return { kind: "abs", arg: args[0] };
2362
+ case "min":
2363
+ if (args.length === 1) {
2364
+ return { kind: "minArray", array: args[0] };
2365
+ }
2366
+ return { kind: "min", args };
2367
+ case "max":
2368
+ if (args.length === 1) {
2369
+ return { kind: "maxArray", array: args[0] };
2370
+ }
2371
+ return { kind: "max", args };
2372
+ // v0.3.2: sum array aggregation
2373
+ case "sum":
2374
+ return { kind: "sumArray", array: args[0] };
2375
+ case "floor":
2376
+ return { kind: "floor", arg: args[0] };
2377
+ case "ceil":
2378
+ return { kind: "ceil", arg: args[0] };
2379
+ case "round":
2380
+ return { kind: "round", arg: args[0] };
2381
+ case "sqrt":
2382
+ return { kind: "sqrt", arg: args[0] };
2383
+ case "pow":
2384
+ return { kind: "pow", base: args[0], exponent: args[1] };
2385
+ // ============ Comparison ============
2386
+ case "eq":
2387
+ return { kind: "eq", left: args[0], right: args[1] };
2388
+ case "neq":
2389
+ return { kind: "neq", left: args[0], right: args[1] };
2390
+ case "gt":
2391
+ return { kind: "gt", left: args[0], right: args[1] };
2392
+ case "gte":
2393
+ return { kind: "gte", left: args[0], right: args[1] };
2394
+ case "lt":
2395
+ return { kind: "lt", left: args[0], right: args[1] };
2396
+ case "lte":
2397
+ return { kind: "lte", left: args[0], right: args[1] };
2398
+ // ============ Logical ============
2399
+ case "and":
2400
+ return { kind: "and", args };
2401
+ case "or":
2402
+ return { kind: "or", args };
2403
+ case "not":
2404
+ return { kind: "not", arg: args[0] };
2405
+ // ============ Type Checking ============
2406
+ case "isNull":
2407
+ return { kind: "isNull", arg: args[0] };
2408
+ case "isNotNull":
2409
+ return { kind: "not", arg: { kind: "isNull", arg: args[0] } };
2410
+ case "typeof":
2411
+ return { kind: "typeof", arg: args[0] };
2412
+ case "coalesce":
2413
+ return { kind: "coalesce", args };
2414
+ // ============ String ============
2415
+ case "concat":
2416
+ return { kind: "concat", args };
2417
+ case "trim":
2418
+ return { kind: "trim", str: args[0] };
2419
+ case "lower":
2420
+ case "toLowerCase":
2421
+ return { kind: "toLowerCase", str: args[0] };
2422
+ case "upper":
2423
+ case "toUpperCase":
2424
+ return { kind: "toUpperCase", str: args[0] };
2425
+ case "strlen":
2426
+ case "strLen":
2427
+ return { kind: "strLen", str: args[0] };
2428
+ case "substr":
2429
+ case "substring":
2430
+ return args[2] ? { kind: "substring", str: args[0], start: args[1], end: args[2] } : { kind: "substring", str: args[0], start: args[1] };
2431
+ case "toString":
2432
+ return { kind: "toString", arg: args[0] };
2433
+ // ============ Collection ============
2434
+ case "len":
2435
+ case "length":
2436
+ return { kind: "len", arg: args[0] };
2437
+ case "at":
2438
+ return { kind: "at", array: args[0], index: args[1] };
2439
+ case "first":
2440
+ return { kind: "first", array: args[0] };
2441
+ case "last":
2442
+ return { kind: "last", array: args[0] };
2443
+ case "slice":
2444
+ return args[2] ? { kind: "slice", array: args[0], start: args[1], end: args[2] } : { kind: "slice", array: args[0], start: args[1] };
2445
+ case "includes":
2446
+ return { kind: "includes", array: args[0], item: args[1] };
2447
+ case "filter":
2448
+ return { kind: "filter", array: args[0], predicate: args[1] };
2449
+ case "map":
2450
+ return { kind: "map", array: args[0], mapper: args[1] };
2451
+ case "find":
2452
+ return { kind: "find", array: args[0], predicate: args[1] };
2453
+ case "every":
2454
+ return { kind: "every", array: args[0], predicate: args[1] };
2455
+ case "some":
2456
+ return { kind: "some", array: args[0], predicate: args[1] };
2457
+ case "append":
2458
+ return { kind: "append", array: args[0], items: args.slice(1) };
2459
+ // ============ Object ============
2460
+ case "keys":
2461
+ return { kind: "keys", obj: args[0] };
2462
+ case "values":
2463
+ return { kind: "values", obj: args[0] };
2464
+ case "entries":
2465
+ return { kind: "entries", obj: args[0] };
2466
+ case "merge":
2467
+ return { kind: "merge", objects: args };
2468
+ // ============ Conditional ============
2469
+ case "if":
2470
+ case "cond":
2471
+ return { kind: "if", cond: args[0], then: args[1], else: args[2] };
2472
+ // ============ Unknown Function ============
2473
+ default:
2474
+ return {
2475
+ kind: "object",
2476
+ fields: {
2477
+ __call: { kind: "lit", value: name },
2478
+ __args: { kind: "lit", value: args }
2479
+ }
2480
+ };
2481
+ }
2482
+ }
2483
+
2484
+ // src/generator/ir.ts
2485
+ import { hashSchemaSync, semanticPathToPatchPath, sha256Sync } from "@manifesto-ai/core";
2486
+ function createContext2(domainName) {
2487
+ return {
2488
+ domainName,
2489
+ stateFields: /* @__PURE__ */ new Set(),
2490
+ computedFields: /* @__PURE__ */ new Set(),
2491
+ actionParams: /* @__PURE__ */ new Map(),
2492
+ onceIntentCounters: /* @__PURE__ */ new Map(),
2493
+ currentAction: null,
2494
+ diagnostics: [],
2495
+ typeDefs: /* @__PURE__ */ new Map()
2496
+ };
2497
+ }
2498
+ function generate(program) {
2499
+ const ctx = createContext2(program.domain.name);
2500
+ collectFieldNames(program.domain, ctx);
2501
+ const types = generateTypes(program.domain, ctx);
2502
+ const state = generateState(program.domain, ctx);
2503
+ const computed = generateComputed(program.domain, ctx);
2504
+ const actions = generateActions(program.domain, ctx);
2505
+ if (ctx.diagnostics.some((d) => d.severity === "error")) {
2506
+ return {
2507
+ schema: null,
2508
+ diagnostics: ctx.diagnostics
2509
+ };
2510
+ }
2511
+ const schemaWithoutHash = {
2512
+ id: `mel:${program.domain.name.toLowerCase()}`,
2513
+ version: "1.0.0",
2514
+ types,
2515
+ state,
2516
+ computed,
2517
+ actions,
2518
+ meta: {
2519
+ name: program.domain.name
2520
+ }
2521
+ };
2522
+ const hash = computeHash(schemaWithoutHash);
2523
+ const schema = {
2524
+ ...schemaWithoutHash,
2525
+ hash
2526
+ };
2527
+ return {
2528
+ schema,
2529
+ diagnostics: ctx.diagnostics
2530
+ };
2531
+ }
2532
+ function collectFieldNames(domain, ctx) {
2533
+ for (const typeDecl of domain.types) {
2534
+ ctx.typeDefs.set(typeDecl.name, typeDecl);
2535
+ }
2536
+ for (const member of domain.members) {
2537
+ if (member.kind === "state") {
2538
+ for (const field of member.fields) {
2539
+ ctx.stateFields.add(field.name);
2540
+ }
2541
+ } else if (member.kind === "computed") {
2542
+ ctx.computedFields.add(member.name);
2543
+ }
2544
+ }
2545
+ }
2546
+ function generateTypes(domain, _ctx) {
2547
+ const types = {};
2548
+ for (const typeDecl of domain.types) {
2549
+ types[typeDecl.name] = {
2550
+ name: typeDecl.name,
2551
+ definition: typeExprToDefinition(typeDecl.typeExpr)
2552
+ };
2553
+ }
2554
+ return types;
2555
+ }
2556
+ function typeExprToDefinition(typeExpr) {
2557
+ switch (typeExpr.kind) {
2558
+ case "simpleType":
2559
+ if (["string", "number", "boolean", "null"].includes(typeExpr.name)) {
2560
+ return { kind: "primitive", type: typeExpr.name };
2561
+ }
2562
+ return { kind: "ref", name: typeExpr.name };
2563
+ case "arrayType":
2564
+ return {
2565
+ kind: "array",
2566
+ element: typeExprToDefinition(typeExpr.elementType)
2567
+ };
2568
+ case "recordType":
2569
+ return {
2570
+ kind: "record",
2571
+ key: typeExprToDefinition(typeExpr.keyType),
2572
+ value: typeExprToDefinition(typeExpr.valueType)
2573
+ };
2574
+ case "objectType":
2575
+ const fields = {};
2576
+ for (const field of typeExpr.fields) {
2577
+ fields[field.name] = {
2578
+ type: typeExprToDefinition(field.typeExpr),
2579
+ optional: field.optional
2580
+ };
2581
+ }
2582
+ return { kind: "object", fields };
2583
+ case "unionType":
2584
+ return {
2585
+ kind: "union",
2586
+ types: typeExpr.types.map(typeExprToDefinition)
2587
+ };
2588
+ case "literalType":
2589
+ return { kind: "literal", value: typeExpr.value };
2590
+ default:
2591
+ const _exhaustive = typeExpr;
2592
+ throw new Error(`Unknown type expression kind: ${typeExpr.kind}`);
2593
+ }
2594
+ }
2595
+ function generateState(domain, ctx) {
2596
+ const fields = {};
2597
+ for (const member of domain.members) {
2598
+ if (member.kind === "state") {
2599
+ for (const field of member.fields) {
2600
+ fields[field.name] = generateFieldSpec(field, ctx);
2601
+ }
2602
+ }
2603
+ }
2604
+ return { fields };
2605
+ }
2606
+ function generateFieldSpec(field, ctx) {
2607
+ const spec = typeExprToFieldSpec(field.typeExpr, ctx);
2608
+ const defaultValue = field.initializer ? evaluateInitializer(field.initializer, ctx) : void 0;
2609
+ return {
2610
+ ...spec,
2611
+ required: true,
2612
+ default: defaultValue
2613
+ };
2614
+ }
2615
+ function typeExprToFieldSpec(typeExpr, ctx) {
2616
+ switch (typeExpr.kind) {
2617
+ case "simpleType":
2618
+ switch (typeExpr.name) {
2619
+ case "string":
2620
+ return { type: "string", required: true };
2621
+ case "number":
2622
+ return { type: "number", required: true };
2623
+ case "boolean":
2624
+ return { type: "boolean", required: true };
2625
+ case "null":
2626
+ return { type: "null", required: true };
2627
+ default: {
2628
+ const typeDef = ctx.typeDefs.get(typeExpr.name);
2629
+ if (typeDef) {
2630
+ return typeExprToFieldSpec(typeDef.typeExpr, ctx);
2631
+ }
2632
+ return { type: "object", required: true };
2633
+ }
2634
+ }
2635
+ case "unionType": {
2636
+ const literals = [];
2637
+ let isLiteralUnion = true;
2638
+ let hasNull = false;
2639
+ for (const t of typeExpr.types) {
2640
+ if (t.kind === "literalType") {
2641
+ if (t.value === null) {
2642
+ hasNull = true;
2643
+ }
2644
+ literals.push(t.value);
2645
+ continue;
2646
+ }
2647
+ if (t.kind === "simpleType" && t.name === "null") {
2648
+ hasNull = true;
2649
+ literals.push(null);
2650
+ continue;
2651
+ }
2652
+ isLiteralUnion = false;
2653
+ }
2654
+ if (isLiteralUnion && literals.length > 0) {
2655
+ return { type: { enum: literals }, required: !hasNull };
2656
+ }
2657
+ if (hasNull) {
2658
+ for (const t of typeExpr.types) {
2659
+ if (t.kind !== "simpleType" || t.name !== "null") {
2660
+ const innerSpec = typeExprToFieldSpec(t, ctx);
2661
+ return { ...innerSpec, required: false };
2662
+ }
2663
+ }
2664
+ }
2665
+ for (const t of typeExpr.types) {
2666
+ if (t.kind !== "simpleType" || t.name !== "null") {
2667
+ return typeExprToFieldSpec(t, ctx);
2668
+ }
2669
+ }
2670
+ return { type: "null", required: true };
2671
+ }
2672
+ case "arrayType": {
2673
+ const itemSpec = typeExprToFieldSpec(typeExpr.elementType, ctx);
2674
+ return {
2675
+ type: "array",
2676
+ required: true,
2677
+ items: itemSpec
2678
+ };
2679
+ }
2680
+ case "recordType":
2681
+ return { type: "object", required: true };
2682
+ case "literalType":
2683
+ if (typeof typeExpr.value === "string") return { type: "string", required: true };
2684
+ if (typeof typeExpr.value === "number") return { type: "number", required: true };
2685
+ if (typeof typeExpr.value === "boolean") return { type: "boolean", required: true };
2686
+ return { type: "null", required: true };
2687
+ case "objectType": {
2688
+ const objectFields = {};
2689
+ for (const field of typeExpr.fields) {
2690
+ const fieldSpec = typeExprToFieldSpec(field.typeExpr, ctx);
2691
+ objectFields[field.name] = {
2692
+ ...fieldSpec,
2693
+ required: !field.optional
2694
+ };
2695
+ }
2696
+ return {
2697
+ type: "object",
2698
+ required: true,
2699
+ fields: objectFields
2700
+ };
2701
+ }
2702
+ }
2703
+ }
2704
+ function evaluateInitializer(expr, ctx) {
2705
+ switch (expr.kind) {
2706
+ case "literal":
2707
+ return expr.value;
2708
+ case "arrayLiteral":
2709
+ return expr.elements.map((e) => evaluateInitializer(e, ctx));
2710
+ case "objectLiteral": {
2711
+ const obj = {};
2712
+ for (const prop of expr.properties) {
2713
+ obj[prop.key] = evaluateInitializer(prop.value, ctx);
2714
+ }
2715
+ return obj;
2716
+ }
2717
+ default:
2718
+ return void 0;
2719
+ }
2720
+ }
2721
+ function generateComputed(domain, ctx) {
2722
+ const fields = {};
2723
+ for (const member of domain.members) {
2724
+ if (member.kind === "computed") {
2725
+ const expr = generateExpr(member.expression, ctx);
2726
+ const deps = extractDeps(expr);
2727
+ fields[member.name] = {
2728
+ deps,
2729
+ expr
2730
+ };
2731
+ }
2732
+ }
2733
+ return { fields };
2734
+ }
2735
+ function extractDeps(expr) {
2736
+ const deps = /* @__PURE__ */ new Set();
2737
+ function visit(node) {
2738
+ if (node.kind === "get") {
2739
+ deps.add(node.path);
2740
+ } else {
2741
+ for (const value of Object.values(node)) {
2742
+ if (typeof value === "object" && value !== null) {
2743
+ if (Array.isArray(value)) {
2744
+ for (const item of value) {
2745
+ if (typeof item === "object" && item !== null && "kind" in item) {
2746
+ visit(item);
2747
+ }
2748
+ }
2749
+ } else if ("kind" in value) {
2750
+ visit(value);
2751
+ }
2752
+ }
2753
+ }
2754
+ }
2755
+ }
2756
+ visit(expr);
2757
+ return Array.from(deps);
2758
+ }
2759
+ function generateActions(domain, ctx) {
2760
+ const actions = {};
2761
+ for (const member of domain.members) {
2762
+ if (member.kind === "action") {
2763
+ ctx.currentAction = member.name;
2764
+ ctx.onceIntentCounters.set(member.name, 0);
2765
+ const params = /* @__PURE__ */ new Set();
2766
+ for (const param of member.params) {
2767
+ params.add(param.name);
2768
+ }
2769
+ ctx.actionParams.set(member.name, params);
2770
+ const flow = generateFlow(member.body, ctx);
2771
+ let input;
2772
+ if (member.params.length > 0) {
2773
+ const inputFields = {};
2774
+ for (const param of member.params) {
2775
+ const fieldSpec = typeExprToFieldSpec(param.typeExpr, ctx);
2776
+ const inputField = {
2777
+ type: fieldSpec.type,
2778
+ required: fieldSpec.required ?? true
2779
+ };
2780
+ if (fieldSpec.type === "object" && fieldSpec.fields) {
2781
+ inputField.fields = fieldSpec.fields;
2782
+ }
2783
+ if (fieldSpec.type === "array" && fieldSpec.items) {
2784
+ inputField.items = fieldSpec.items;
2785
+ }
2786
+ inputFields[param.name] = inputField;
2787
+ }
2788
+ input = {
2789
+ type: "object",
2790
+ required: true,
2791
+ fields: inputFields
2792
+ };
2793
+ }
2794
+ let available;
2795
+ if (member.available) {
2796
+ available = generateExpr(member.available, ctx);
2797
+ }
2798
+ actions[member.name] = {
2799
+ flow,
2800
+ input,
2801
+ available
2802
+ };
2803
+ ctx.currentAction = null;
2804
+ }
2805
+ }
2806
+ return actions;
2807
+ }
2808
+ function generateFlow(stmts, ctx) {
2809
+ if (stmts.length === 0) {
2810
+ return { kind: "seq", steps: [] };
2811
+ }
2812
+ if (stmts.length === 1) {
2813
+ return generateStmt(stmts[0], ctx);
2814
+ }
2815
+ return {
2816
+ kind: "seq",
2817
+ steps: stmts.map((s) => generateStmt(s, ctx))
2818
+ };
2819
+ }
2820
+ function generateStmt(stmt, ctx) {
2821
+ switch (stmt.kind) {
2822
+ case "when":
2823
+ return generateWhen(stmt, ctx);
2824
+ case "once":
2825
+ return generateOnce(stmt, ctx);
2826
+ case "onceIntent":
2827
+ return generateOnceIntent(stmt, ctx);
2828
+ case "patch":
2829
+ return generatePatch(stmt, ctx);
2830
+ case "effect":
2831
+ return generateEffect(stmt, ctx);
2832
+ case "fail":
2833
+ return generateFail(stmt, ctx);
2834
+ case "stop":
2835
+ return generateStop(stmt, ctx);
2836
+ }
2837
+ }
2838
+ function generateWhen(stmt, ctx) {
2839
+ const cond = generateExpr(stmt.condition, ctx);
2840
+ const thenFlow = generateFlow(stmt.body, ctx);
2841
+ return {
2842
+ kind: "if",
2843
+ cond,
2844
+ then: thenFlow
2845
+ };
2846
+ }
2847
+ function generateOnce(stmt, ctx) {
2848
+ const markerPath = generatePath(stmt.marker, ctx);
2849
+ const intentIdExpr = { kind: "get", path: "meta.intentId" };
2850
+ let cond = {
2851
+ kind: "neq",
2852
+ left: { kind: "get", path: markerPath },
2853
+ right: intentIdExpr
2854
+ };
2855
+ if (stmt.condition) {
2856
+ const extraCond = generateExpr(stmt.condition, ctx);
2857
+ cond = {
2858
+ kind: "and",
2859
+ args: [cond, extraCond]
2860
+ };
2861
+ }
2862
+ const markerPatch = {
2863
+ kind: "patch",
2864
+ op: "set",
2865
+ path: toPatchPath(markerPath),
2866
+ value: intentIdExpr
2867
+ };
2868
+ const bodySteps = stmt.body.map((s) => generateStmt(s, ctx));
2869
+ return {
2870
+ kind: "if",
2871
+ cond,
2872
+ then: {
2873
+ kind: "seq",
2874
+ steps: [markerPatch, ...bodySteps]
2875
+ }
2876
+ };
2877
+ }
2878
+ function generateOnceIntent(stmt, ctx) {
2879
+ const actionName = ctx.currentAction ?? "unknown";
2880
+ const nextIndex = ctx.onceIntentCounters.get(actionName) ?? 0;
2881
+ ctx.onceIntentCounters.set(actionName, nextIndex + 1);
2882
+ const guardId = sha256Sync(`${actionName}:${nextIndex}:intent`);
2883
+ const guardPath = `$mel.guards.intent.${guardId}`;
2884
+ const intentIdExpr = { kind: "get", path: "meta.intentId" };
2885
+ let cond = {
2886
+ kind: "neq",
2887
+ left: { kind: "get", path: guardPath },
2888
+ right: intentIdExpr
2889
+ };
2890
+ if (stmt.condition) {
2891
+ const extraCond = generateExpr(stmt.condition, ctx);
2892
+ cond = {
2893
+ kind: "and",
2894
+ args: [cond, extraCond]
2895
+ };
2896
+ }
2897
+ const markerPatch = {
2898
+ kind: "patch",
2899
+ op: "merge",
2900
+ path: toPatchPath("$mel.guards.intent"),
2901
+ value: {
2902
+ kind: "object",
2903
+ fields: { [guardId]: intentIdExpr }
2904
+ }
2905
+ };
2906
+ const bodySteps = stmt.body.map((s) => generateStmt(s, ctx));
2907
+ return {
2908
+ kind: "if",
2909
+ cond,
2910
+ then: {
2911
+ kind: "seq",
2912
+ steps: [markerPatch, ...bodySteps]
2913
+ }
2914
+ };
2915
+ }
2916
+ function generatePatch(stmt, ctx) {
2917
+ const path = generatePath(stmt.path, ctx);
2918
+ const result = {
2919
+ kind: "patch",
2920
+ op: stmt.op,
2921
+ path: toPatchPath(path)
2922
+ };
2923
+ if (stmt.value) {
2924
+ result.value = generateExpr(stmt.value, ctx);
2925
+ }
2926
+ return result;
2927
+ }
2928
+ function generateEffect(stmt, ctx) {
2929
+ const params = {};
2930
+ for (const arg of stmt.args) {
2931
+ if (arg.isPath) {
2932
+ params[arg.name] = { kind: "lit", value: generatePath(arg.value, ctx) };
2933
+ } else {
2934
+ params[arg.name] = generateExpr(arg.value, ctx);
2935
+ }
2936
+ }
2937
+ return {
2938
+ kind: "effect",
2939
+ type: stmt.effectType,
2940
+ params
2941
+ };
2942
+ }
2943
+ function generateFail(stmt, ctx) {
2944
+ const result = {
2945
+ kind: "fail",
2946
+ code: stmt.code
2947
+ };
2948
+ if (stmt.message) {
2949
+ result.message = generateExpr(stmt.message, ctx);
2950
+ }
2951
+ return result;
2952
+ }
2953
+ function generateStop(stmt, ctx) {
2954
+ return {
2955
+ kind: "halt",
2956
+ reason: stmt.reason
2957
+ };
2958
+ }
2959
+ function escapePathSegment(segment) {
2960
+ return segment.replaceAll("\\", "\\\\").replaceAll(".", "\\.");
2961
+ }
2962
+ function joinPathPreserveEmptySegments(...segments) {
2963
+ return segments.map(escapePathSegment).join(".");
2964
+ }
2965
+ function generatePath(path, ctx) {
2966
+ const segments = [];
2967
+ for (const segment of path.segments) {
2968
+ if (segment.kind === "propertySegment") {
2969
+ segments.push(segment.name);
2970
+ } else {
2971
+ const indexExpr = generateExpr(segment.index, ctx);
2972
+ if (indexExpr.kind === "lit") {
2973
+ segments.push(String(indexExpr.value));
2974
+ } else {
2975
+ segments.push("*");
2976
+ }
2977
+ }
2978
+ }
2979
+ const first = segments[0];
2980
+ if (ctx.stateFields.has(first)) {
2981
+ return joinPathPreserveEmptySegments(...segments);
2982
+ }
2983
+ if (ctx.computedFields.has(first)) {
2984
+ return joinPathPreserveEmptySegments(...segments);
2985
+ }
2986
+ if (ctx.currentAction && ctx.actionParams.get(ctx.currentAction)?.has(first)) {
2987
+ return `input.${joinPathPreserveEmptySegments(...segments)}`;
2988
+ }
2989
+ return joinPathPreserveEmptySegments(...segments);
2990
+ }
2991
+ function toPatchPath(path) {
2992
+ return semanticPathToPatchPath(path);
2993
+ }
2994
+ function generateExpr(expr, ctx) {
2995
+ switch (expr.kind) {
2996
+ case "literal":
2997
+ return { kind: "lit", value: expr.value };
2998
+ case "identifier":
2999
+ return generateIdentifier(expr.name, ctx);
3000
+ case "systemIdent":
3001
+ return generateSystemIdent(expr.path, ctx);
3002
+ case "iterationVar":
3003
+ return { kind: "get", path: `$${expr.name}` };
3004
+ case "propertyAccess":
3005
+ return generatePropertyAccess(expr, ctx);
3006
+ case "indexAccess":
3007
+ return {
3008
+ kind: "at",
3009
+ array: generateExpr(expr.object, ctx),
3010
+ index: generateExpr(expr.index, ctx)
3011
+ };
3012
+ case "functionCall":
3013
+ return normalizeFunctionCall(
3014
+ expr.name,
3015
+ expr.args.map((a) => generateExpr(a, ctx))
3016
+ );
3017
+ case "binary":
3018
+ return normalizeExpr(
3019
+ expr.operator,
3020
+ generateExpr(expr.left, ctx),
3021
+ generateExpr(expr.right, ctx)
3022
+ );
3023
+ case "unary":
3024
+ if (expr.operator === "!") {
3025
+ return { kind: "not", arg: generateExpr(expr.operand, ctx) };
3026
+ } else {
3027
+ return { kind: "neg", arg: generateExpr(expr.operand, ctx) };
3028
+ }
3029
+ case "ternary":
3030
+ return {
3031
+ kind: "if",
3032
+ cond: generateExpr(expr.condition, ctx),
3033
+ then: generateExpr(expr.consequent, ctx),
3034
+ else: generateExpr(expr.alternate, ctx)
3035
+ };
3036
+ case "objectLiteral": {
3037
+ const fields = {};
3038
+ for (const prop of expr.properties) {
3039
+ fields[prop.key] = generateExpr(prop.value, ctx);
3040
+ }
3041
+ return { kind: "object", fields };
3042
+ }
3043
+ case "arrayLiteral":
3044
+ if (expr.elements.length === 0) {
3045
+ return { kind: "lit", value: [] };
3046
+ }
3047
+ const allLiterals = expr.elements.every((e) => e.kind === "literal");
3048
+ if (allLiterals) {
3049
+ return { kind: "lit", value: expr.elements.map((e) => e.value) };
3050
+ }
3051
+ return {
3052
+ kind: "append",
3053
+ array: { kind: "lit", value: [] },
3054
+ items: expr.elements.map((e) => generateExpr(e, ctx))
3055
+ };
3056
+ }
3057
+ }
3058
+ function generateIdentifier(name, ctx) {
3059
+ if (ctx.stateFields.has(name)) {
3060
+ return { kind: "get", path: name };
3061
+ }
3062
+ if (ctx.computedFields.has(name)) {
3063
+ return { kind: "get", path: name };
3064
+ }
3065
+ if (ctx.currentAction && ctx.actionParams.get(ctx.currentAction)?.has(name)) {
3066
+ return { kind: "get", path: `input.${name}` };
3067
+ }
3068
+ ctx.diagnostics.push({
3069
+ severity: "error",
3070
+ code: "E_UNKNOWN_IDENT",
3071
+ message: `Unknown identifier '${name}'`,
3072
+ location: { start: { line: 0, column: 0, offset: 0 }, end: { line: 0, column: 0, offset: 0 } }
3073
+ });
3074
+ return { kind: "get", path: name };
3075
+ }
3076
+ function generateSystemIdent(path, ctx) {
3077
+ const [namespace, ...rest] = path;
3078
+ switch (namespace) {
3079
+ case "system":
3080
+ return { kind: "get", path: `$system.${rest.join(".")}` };
3081
+ case "meta":
3082
+ return { kind: "get", path: `meta.${rest.join(".")}` };
3083
+ case "input":
3084
+ return { kind: "get", path: `input.${rest.join(".")}` };
3085
+ default:
3086
+ ctx.diagnostics.push({
3087
+ severity: "error",
3088
+ code: "E_INVALID_SYSTEM",
3089
+ message: `Invalid system identifier namespace '$${namespace}'`,
3090
+ location: { start: { line: 0, column: 0, offset: 0 }, end: { line: 0, column: 0, offset: 0 } }
3091
+ });
3092
+ return { kind: "lit", value: null };
3093
+ }
3094
+ }
3095
+ function generatePropertyAccess(expr, ctx) {
3096
+ const objectExpr = generateExpr(expr.object, ctx);
3097
+ if (objectExpr.kind === "get") {
3098
+ return { kind: "get", path: `${objectExpr.path}.${expr.property}` };
3099
+ }
3100
+ return {
3101
+ kind: "field",
3102
+ object: objectExpr,
3103
+ property: expr.property
3104
+ };
3105
+ }
3106
+ function computeHash(schema) {
3107
+ return hashSchemaSync(schema);
3108
+ }
3109
+
3110
+ // src/lowering/errors.ts
3111
+ var LoweringError = class extends Error {
3112
+ code;
3113
+ path;
3114
+ details;
3115
+ constructor(code, message, options) {
3116
+ super(message);
3117
+ this.name = "LoweringError";
3118
+ this.code = code;
3119
+ this.path = options?.path;
3120
+ this.details = options?.details;
3121
+ }
3122
+ };
3123
+ function invalidKindForContext(kind, context, path) {
3124
+ return new LoweringError(
3125
+ "INVALID_KIND_FOR_CONTEXT",
3126
+ `Node kind '${kind}' is not allowed in ${context} context`,
3127
+ { path, details: { kind, context } }
3128
+ );
3129
+ }
3130
+ function unknownCallFn(fn, path) {
3131
+ return new LoweringError(
3132
+ "UNKNOWN_CALL_FN",
3133
+ `Unknown function '${fn}' in call expression`,
3134
+ { path, details: { fn } }
3135
+ );
3136
+ }
3137
+ function invalidSysPath(sysPath, path) {
3138
+ return new LoweringError(
3139
+ "INVALID_SYS_PATH",
3140
+ `System path '${sysPath.join(".")}' is not allowed in Translator path`,
3141
+ { path, details: { sysPath } }
3142
+ );
3143
+ }
3144
+ function unsupportedBase(baseKind, path) {
3145
+ return new LoweringError(
3146
+ "UNSUPPORTED_BASE",
3147
+ `Unsupported base expression kind '${baseKind}'. Only var(item) is supported.`,
3148
+ { path, details: { baseKind } }
3149
+ );
3150
+ }
3151
+ function invalidShape(description, path) {
3152
+ return new LoweringError(
3153
+ "INVALID_SHAPE",
3154
+ `Invalid node shape: ${description}`,
3155
+ { path, details: { description } }
3156
+ );
3157
+ }
3158
+ function unknownNodeKind(kind, path) {
3159
+ return new LoweringError(
3160
+ "UNKNOWN_NODE_KIND",
3161
+ `Unknown expression node kind '${kind}'`,
3162
+ { path, details: { kind } }
3163
+ );
3164
+ }
3165
+
3166
+ // src/lowering/lower-expr.ts
3167
+ function lowerExprNode(input, ctx) {
3168
+ switch (input.kind) {
3169
+ case "lit":
3170
+ return lowerLit(input);
3171
+ case "var":
3172
+ return lowerVar(input, ctx);
3173
+ case "sys":
3174
+ return lowerSys(input, ctx);
3175
+ case "get":
3176
+ return lowerGet(input, ctx);
3177
+ case "call":
3178
+ return lowerCall(input, ctx);
3179
+ case "obj":
3180
+ return lowerObj(input, ctx);
3181
+ case "arr":
3182
+ return lowerArr(input, ctx);
3183
+ default:
3184
+ throw unknownNodeKind(input.kind);
3185
+ }
3186
+ }
3187
+ function lowerLit(input) {
3188
+ return { kind: "lit", value: input.value };
3189
+ }
3190
+ function lowerVar(input, ctx) {
3191
+ if (!ctx.allowItem) {
3192
+ throw invalidKindForContext("var", ctx.mode);
3193
+ }
3194
+ return { kind: "get", path: "$item" };
3195
+ }
3196
+ function lowerSys(input, ctx) {
3197
+ if (input.path.length === 0) {
3198
+ throw invalidSysPath(input.path);
3199
+ }
3200
+ const prefix = input.path[0];
3201
+ const allowedPrefixes = ctx.allowSysPaths?.prefixes ?? ["meta", "input"];
3202
+ if (!allowedPrefixes.includes(prefix)) {
3203
+ throw invalidSysPath(input.path);
3204
+ }
3205
+ const path = input.path.join(".");
3206
+ return { kind: "get", path };
3207
+ }
3208
+ function lowerGet(input, ctx) {
3209
+ const pathStr = input.path.map((seg) => seg.name).join(".");
3210
+ if (input.base === void 0) {
3211
+ return { kind: "get", path: pathStr };
3212
+ }
3213
+ if (input.base.kind === "var" && input.base.name === "item") {
3214
+ if (!ctx.allowItem) {
3215
+ throw invalidKindForContext("var", ctx.mode);
3216
+ }
3217
+ return { kind: "get", path: `$item.${pathStr}` };
3218
+ }
3219
+ throw unsupportedBase(input.base.kind);
3220
+ }
3221
+ function lowerCall(input, ctx) {
3222
+ const { fn, args } = input;
3223
+ if (isBinaryOp2(fn)) {
3224
+ if (args.length !== 2) {
3225
+ throw unknownCallFn(fn);
3226
+ }
3227
+ const [left, right] = args;
3228
+ return {
3229
+ kind: fn,
3230
+ left: lowerExprNode(left, ctx),
3231
+ right: lowerExprNode(right, ctx)
3232
+ };
3233
+ }
3234
+ if (isUnaryArgOp(fn)) {
3235
+ if (args.length !== 1) {
3236
+ throw unknownCallFn(fn);
3237
+ }
3238
+ return {
3239
+ kind: fn,
3240
+ arg: lowerExprNode(args[0], ctx)
3241
+ };
3242
+ }
3243
+ if (fn === "trim") {
3244
+ if (args.length !== 1) {
3245
+ throw unknownCallFn(fn);
3246
+ }
3247
+ return {
3248
+ kind: "trim",
3249
+ str: lowerExprNode(args[0], ctx)
3250
+ };
3251
+ }
3252
+ if (isArgsOp(fn)) {
3253
+ return {
3254
+ kind: fn,
3255
+ args: args.map((a) => lowerExprNode(a, ctx))
3256
+ };
3257
+ }
3258
+ if (fn === "if") {
3259
+ if (args.length !== 3) {
3260
+ throw unknownCallFn(fn);
3261
+ }
3262
+ return {
3263
+ kind: "if",
3264
+ cond: lowerExprNode(args[0], ctx),
3265
+ then: lowerExprNode(args[1], ctx),
3266
+ else: lowerExprNode(args[2], ctx)
3267
+ };
3268
+ }
3269
+ if (fn === "field") {
3270
+ if (args.length !== 2) {
3271
+ throw unknownCallFn(fn);
3272
+ }
3273
+ const object = lowerExprNode(args[0], ctx);
3274
+ const property = args[1];
3275
+ if (property.kind !== "lit" || typeof property.value !== "string") {
3276
+ throw unknownCallFn(fn);
3277
+ }
3278
+ return {
3279
+ kind: "field",
3280
+ object,
3281
+ property: property.value
3282
+ };
3283
+ }
3284
+ if (isArrayArgOp(fn)) {
3285
+ if (args.length !== 1) {
3286
+ throw unknownCallFn(fn);
3287
+ }
3288
+ return {
3289
+ kind: fn,
3290
+ array: lowerExprNode(args[0], ctx)
3291
+ };
3292
+ }
3293
+ if (isObjArgOp(fn)) {
3294
+ if (args.length !== 1) {
3295
+ throw unknownCallFn(fn);
3296
+ }
3297
+ return {
3298
+ kind: fn,
3299
+ obj: lowerExprNode(args[0], ctx)
3300
+ };
3301
+ }
3302
+ if (fn === "at") {
3303
+ if (args.length !== 2) {
3304
+ throw unknownCallFn(fn);
3305
+ }
3306
+ return {
3307
+ kind: "at",
3308
+ array: lowerExprNode(args[0], ctx),
3309
+ index: lowerExprNode(args[1], ctx)
3310
+ };
3311
+ }
3312
+ if (fn === "includes") {
3313
+ if (args.length !== 2) {
3314
+ throw unknownCallFn(fn);
3315
+ }
3316
+ return {
3317
+ kind: "includes",
3318
+ array: lowerExprNode(args[0], ctx),
3319
+ item: lowerExprNode(args[1], ctx)
3320
+ };
3321
+ }
3322
+ if (isPredicateOp(fn)) {
3323
+ if (args.length !== 2) {
3324
+ throw unknownCallFn(fn);
3325
+ }
3326
+ const predicateCtx = { ...ctx, allowItem: true };
3327
+ if (fn === "map") {
3328
+ return {
3329
+ kind: "map",
3330
+ array: lowerExprNode(args[0], ctx),
3331
+ mapper: lowerExprNode(args[1], predicateCtx)
3332
+ };
3333
+ }
3334
+ return {
3335
+ kind: fn,
3336
+ array: lowerExprNode(args[0], ctx),
3337
+ predicate: lowerExprNode(args[1], predicateCtx)
3338
+ };
3339
+ }
3340
+ if (fn === "slice") {
3341
+ if (args.length < 2 || args.length > 3) {
3342
+ throw unknownCallFn(fn);
3343
+ }
3344
+ const result = {
3345
+ kind: "slice",
3346
+ array: lowerExprNode(args[0], ctx),
3347
+ start: lowerExprNode(args[1], ctx)
3348
+ };
3349
+ if (args.length === 3) {
3350
+ result.end = lowerExprNode(args[2], ctx);
3351
+ }
3352
+ return result;
3353
+ }
3354
+ if (fn === "substring") {
3355
+ if (args.length < 2 || args.length > 3) {
3356
+ throw unknownCallFn(fn);
3357
+ }
3358
+ const result = {
3359
+ kind: "substring",
3360
+ str: lowerExprNode(args[0], ctx),
3361
+ start: lowerExprNode(args[1], ctx)
3362
+ };
3363
+ if (args.length === 3) {
3364
+ result.end = lowerExprNode(args[2], ctx);
3365
+ }
3366
+ return result;
3367
+ }
3368
+ if (fn === "append") {
3369
+ if (args.length < 1) {
3370
+ throw unknownCallFn(fn);
3371
+ }
3372
+ return {
3373
+ kind: "append",
3374
+ array: lowerExprNode(args[0], ctx),
3375
+ items: args.slice(1).map((a) => lowerExprNode(a, ctx))
3376
+ };
3377
+ }
3378
+ if (fn === "merge") {
3379
+ return {
3380
+ kind: "merge",
3381
+ objects: args.map((a) => lowerExprNode(a, ctx))
3382
+ };
3383
+ }
3384
+ throw unknownCallFn(fn);
3385
+ }
3386
+ function lowerObj(input, ctx) {
3387
+ const fields = {};
3388
+ for (const field of input.fields) {
3389
+ fields[field.key] = lowerExprNode(field.value, ctx);
3390
+ }
3391
+ return { kind: "object", fields };
3392
+ }
3393
+ function lowerArr(input, ctx) {
3394
+ const allLiterals = input.elements.every((e) => e.kind === "lit");
3395
+ if (allLiterals) {
3396
+ const values = input.elements.map(
3397
+ (e) => e.value
3398
+ );
3399
+ return { kind: "lit", value: values };
3400
+ }
3401
+ const loweredElements = input.elements.map((e) => lowerExprNode(e, ctx));
3402
+ if (loweredElements.length === 0) {
3403
+ return { kind: "lit", value: [] };
3404
+ }
3405
+ return {
3406
+ kind: "append",
3407
+ array: { kind: "lit", value: [] },
3408
+ items: loweredElements
3409
+ };
3410
+ }
3411
+ function isBinaryOp2(fn) {
3412
+ return [
3413
+ "eq",
3414
+ "neq",
3415
+ "gt",
3416
+ "gte",
3417
+ "lt",
3418
+ "lte",
3419
+ "add",
3420
+ "sub",
3421
+ "mul",
3422
+ "div",
3423
+ "mod"
3424
+ ].includes(fn);
3425
+ }
3426
+ function isUnaryArgOp(fn) {
3427
+ return ["not", "len", "typeof", "isNull"].includes(fn);
3428
+ }
3429
+ function isArgsOp(fn) {
3430
+ return ["and", "or", "concat", "coalesce"].includes(fn);
3431
+ }
3432
+ function isArrayArgOp(fn) {
3433
+ return ["first", "last"].includes(fn);
3434
+ }
3435
+ function isObjArgOp(fn) {
3436
+ return ["keys", "values", "entries"].includes(fn);
3437
+ }
3438
+ function isPredicateOp(fn) {
3439
+ return ["filter", "find", "every", "some", "map"].includes(fn);
3440
+ }
3441
+
3442
+ // src/lowering/lower-runtime-patch.ts
3443
+ function lowerRuntimePatches(patches, ctx) {
3444
+ return patches.map((patch) => lowerRuntimePatch(patch, ctx));
3445
+ }
3446
+ function lowerRuntimePatch(patch, ctx) {
3447
+ const condition = patch.condition ? lowerExprNode(patch.condition, ctx) : void 0;
3448
+ const value = patch.value ? lowerExprNode(patch.value, ctx) : void 0;
3449
+ return {
3450
+ condition,
3451
+ op: patch.op,
3452
+ path: lowerRuntimePath(patch.path, ctx),
3453
+ value
3454
+ };
3455
+ }
3456
+ function lowerRuntimePath(path, ctx) {
3457
+ return path.map((segment) => {
3458
+ if (segment.kind === "prop") {
3459
+ return segment;
3460
+ }
3461
+ return { kind: "expr", expr: lowerExprNode(segment.expr, ctx) };
3462
+ });
3463
+ }
3464
+
3465
+ // src/api/compile-mel-patch-collector.ts
3466
+ import { sha256Sync as sha256Sync2 } from "@manifesto-ai/core";
3467
+
3468
+ // src/api/compile-mel-patch-expr.ts
3469
+ function isSyntheticPatchCondition(condition) {
3470
+ return condition.kind === "literal" && condition.literalType === "boolean" && condition.value === true;
3471
+ }
3472
+ function toMelExpr(input) {
3473
+ switch (input.kind) {
3474
+ case "literal":
3475
+ return { kind: "lit", value: toMelPrimitive(input.value, input.literalType) };
3476
+ case "identifier":
3477
+ return {
3478
+ kind: "get",
3479
+ path: [{ kind: "prop", name: input.name }]
3480
+ };
3481
+ case "systemIdent":
3482
+ return { kind: "sys", path: input.path };
3483
+ case "iterationVar":
3484
+ return { kind: "var", name: input.name };
3485
+ case "propertyAccess": {
3486
+ const path = collectStaticMelExpr(input);
3487
+ if (path) {
3488
+ return path;
3489
+ }
3490
+ return {
3491
+ kind: "call",
3492
+ fn: "field",
3493
+ args: [toMelExpr(input.object), { kind: "lit", value: input.property }]
3494
+ };
3495
+ }
3496
+ case "indexAccess": {
3497
+ return {
3498
+ kind: "call",
3499
+ fn: "at",
3500
+ args: [toMelExpr(input.object), toMelExpr(input.index)]
3501
+ };
3502
+ }
3503
+ case "functionCall":
3504
+ return {
3505
+ kind: "call",
3506
+ fn: input.name,
3507
+ args: input.args.map(toMelExpr)
3508
+ };
3509
+ case "unary":
3510
+ if (input.operator === "!") {
3511
+ return {
3512
+ kind: "call",
3513
+ fn: "not",
3514
+ args: [toMelExpr(input.operand)]
3515
+ };
3516
+ }
3517
+ return {
3518
+ kind: "call",
3519
+ fn: "sub",
3520
+ args: [{ kind: "lit", value: 0 }, toMelExpr(input.operand)]
3521
+ };
3522
+ case "binary":
3523
+ return {
3524
+ kind: "call",
3525
+ fn: toMelBinaryOp(input.operator),
3526
+ args: [toMelExpr(input.left), toMelExpr(input.right)]
3527
+ };
3528
+ case "ternary":
3529
+ return {
3530
+ kind: "call",
3531
+ fn: "if",
3532
+ args: [
3533
+ toMelExpr(input.condition),
3534
+ toMelExpr(input.consequent),
3535
+ toMelExpr(input.alternate)
3536
+ ]
3537
+ };
3538
+ case "objectLiteral":
3539
+ return {
3540
+ kind: "obj",
3541
+ fields: input.properties.map((property) => ({
3542
+ key: property.key,
3543
+ value: toMelExpr(property.value)
3544
+ }))
3545
+ };
3546
+ case "arrayLiteral":
3547
+ return {
3548
+ kind: "arr",
3549
+ elements: input.elements.map(toMelExpr)
3550
+ };
3551
+ default:
3552
+ throw new Error(`Unsupported expression kind '${input.kind}'`);
3553
+ }
3554
+ }
3555
+ function toMelPrimitive(value, literalType) {
3556
+ if (literalType === "null") {
3557
+ return null;
3558
+ }
3559
+ if (literalType === "number") {
3560
+ if (typeof value === "number") {
3561
+ return value;
3562
+ }
3563
+ if (typeof value === "bigint") {
3564
+ return Number(value);
3565
+ }
3566
+ if (typeof value === "string" && value.length > 0) {
3567
+ const parsed = Number(value);
3568
+ if (!Number.isNaN(parsed)) {
3569
+ return parsed;
3570
+ }
3571
+ }
3572
+ throw new Error("Invalid number literal");
3573
+ }
3574
+ if (literalType === "string") {
3575
+ if (typeof value === "string") {
3576
+ return value;
3577
+ }
3578
+ throw new Error("Invalid string literal");
3579
+ }
3580
+ if (literalType === "boolean") {
3581
+ if (typeof value === "boolean") {
3582
+ return value;
3583
+ }
3584
+ throw new Error("Invalid boolean literal");
3585
+ }
3586
+ throw new Error("Unsupported literal type");
3587
+ }
3588
+ function collectStaticMelExpr(expr) {
3589
+ if (expr.kind === "identifier") {
3590
+ return { kind: "get", path: [{ kind: "prop", name: expr.name }] };
3591
+ }
3592
+ if (expr.kind === "iterationVar") {
3593
+ if (expr.name !== "item") {
3594
+ return null;
3595
+ }
3596
+ return { kind: "var", name: "item" };
3597
+ }
3598
+ if (expr.kind === "propertyAccess") {
3599
+ const basePath = collectStaticMelExpr(expr.object);
3600
+ if (!basePath) {
3601
+ return null;
3602
+ }
3603
+ return {
3604
+ kind: "call",
3605
+ fn: "field",
3606
+ args: [basePath, { kind: "lit", value: expr.property }]
3607
+ };
3608
+ }
3609
+ return null;
3610
+ }
3611
+ function toMelBinaryOp(op) {
3612
+ switch (op) {
3613
+ case "+":
3614
+ return "add";
3615
+ case "-":
3616
+ return "sub";
3617
+ case "*":
3618
+ return "mul";
3619
+ case "/":
3620
+ return "div";
3621
+ case "%":
3622
+ return "mod";
3623
+ case "==":
3624
+ return "eq";
3625
+ case "!=":
3626
+ return "neq";
3627
+ case "<":
3628
+ return "lt";
3629
+ case "<=":
3630
+ return "lte";
3631
+ case ">":
3632
+ return "gt";
3633
+ case ">=":
3634
+ return "gte";
3635
+ case "&&":
3636
+ return "and";
3637
+ case "||":
3638
+ return "or";
3639
+ case "??":
3640
+ return "coalesce";
3641
+ default:
3642
+ throw new Error(`Unsupported binary operator '${op}'`);
3643
+ }
3644
+ }
3645
+
3646
+ // src/api/compile-mel-patch-collector.ts
3647
+ var PatchStatementCollector = class {
3648
+ constructor(deps) {
3649
+ this.deps = deps;
3650
+ }
3651
+ conditionComposer = new ConditionComposer();
3652
+ collect(stmts, errors, context, parentCondition) {
3653
+ return this.collectPatchStatements(stmts, errors, context, parentCondition);
3654
+ }
3655
+ collectPatchStatements(stmts, errors, context, parentCondition) {
3656
+ const patchStatements = [];
3657
+ for (const stmt of stmts) {
3658
+ if (stmt.kind === "patch") {
3659
+ patchStatements.push({
3660
+ patch: stmt,
3661
+ condition: parentCondition
3662
+ });
3663
+ continue;
3664
+ }
3665
+ if (stmt.kind === "when") {
3666
+ let condition = parentCondition;
3667
+ try {
3668
+ condition = this.conditionComposer.and(
3669
+ parentCondition,
3670
+ this.deps.toMelExpr(stmt.condition)
3671
+ );
3672
+ } catch (error) {
3673
+ errors.push({
3674
+ severity: "error",
3675
+ code: "E_LOWER",
3676
+ message: error.message,
3677
+ location: this.deps.mapLocation(stmt.condition.location)
3678
+ });
3679
+ }
3680
+ const whenMarkerId = sha256Sync2(
3681
+ `${context.actionName}:${context.whenCounter}:when`
3682
+ );
3683
+ context.whenCounter += 1;
3684
+ const whenMarkerPath = {
3685
+ kind: "path",
3686
+ segments: [
3687
+ {
3688
+ kind: "propertySegment",
3689
+ name: "$mel",
3690
+ location: stmt.location
3691
+ },
3692
+ {
3693
+ kind: "propertySegment",
3694
+ name: "__whenGuards",
3695
+ location: stmt.location
3696
+ },
3697
+ {
3698
+ kind: "propertySegment",
3699
+ name: whenMarkerId,
3700
+ location: stmt.location
3701
+ }
3702
+ ],
3703
+ location: stmt.location
3704
+ };
3705
+ const whenMarkerExpr = pathToMelExpr(whenMarkerPath);
3706
+ const guardedBody = this.collectPatchStatements(
3707
+ stmt.body,
3708
+ errors,
3709
+ context,
3710
+ void 0
3711
+ ).map((statement) => ({
3712
+ patch: statement.patch,
3713
+ condition: this.conditionComposer.and(whenMarkerExpr, statement.condition)
3714
+ }));
3715
+ patchStatements.push(
3716
+ {
3717
+ patch: {
3718
+ kind: "patch",
3719
+ op: "set",
3720
+ path: whenMarkerPath,
3721
+ value: {
3722
+ kind: "literal",
3723
+ literalType: "boolean",
3724
+ value: true,
3725
+ location: stmt.location
3726
+ },
3727
+ location: stmt.location
3728
+ },
3729
+ condition
3730
+ },
3731
+ ...guardedBody,
3732
+ {
3733
+ patch: {
3734
+ kind: "patch",
3735
+ op: "unset",
3736
+ path: whenMarkerPath,
3737
+ location: stmt.location
3738
+ }
3739
+ }
3740
+ );
3741
+ continue;
3742
+ }
3743
+ if (stmt.kind === "once") {
3744
+ let condition = parentCondition;
3745
+ const markerExpr = pathToMelExpr(stmt.marker);
3746
+ const markerPath = stmt.marker;
3747
+ const markerLocation = stmt.location;
3748
+ let onceCondition = {
3749
+ kind: "call",
3750
+ fn: "neq",
3751
+ args: [markerExpr, { kind: "sys", path: ["meta", "intentId"] }]
3752
+ };
3753
+ if (stmt.condition) {
3754
+ try {
3755
+ onceCondition = this.conditionComposer.and(
3756
+ onceCondition,
3757
+ this.deps.toMelExpr(stmt.condition)
3758
+ ) ?? onceCondition;
3759
+ } catch (error) {
3760
+ errors.push({
3761
+ severity: "error",
3762
+ code: "E_LOWER",
3763
+ message: error.message,
3764
+ location: this.deps.mapLocation(stmt.condition.location)
3765
+ });
3766
+ }
3767
+ }
3768
+ condition = this.conditionComposer.and(parentCondition, onceCondition);
3769
+ const onceScopeMarkerId = sha256Sync2(
3770
+ `${context.actionName}:${context.onceCounter}:once`
3771
+ );
3772
+ context.onceCounter += 1;
3773
+ const onceScopeMarkerPath = {
3774
+ kind: "path",
3775
+ segments: [
3776
+ {
3777
+ kind: "propertySegment",
3778
+ name: "$mel",
3779
+ location: markerLocation
3780
+ },
3781
+ {
3782
+ kind: "propertySegment",
3783
+ name: "__onceScopeGuards",
3784
+ location: markerLocation
3785
+ },
3786
+ {
3787
+ kind: "propertySegment",
3788
+ name: onceScopeMarkerId,
3789
+ location: markerLocation
3790
+ }
3791
+ ],
3792
+ location: markerLocation
3793
+ };
3794
+ const onceScopeMarkerExpr = pathToMelExpr(onceScopeMarkerPath);
3795
+ const scopedBodyPatchStatements = this.collectPatchStatements(
3796
+ stmt.body,
3797
+ errors,
3798
+ context,
3799
+ onceScopeMarkerExpr
3800
+ );
3801
+ patchStatements.push(
3802
+ {
3803
+ patch: {
3804
+ kind: "patch",
3805
+ op: "set",
3806
+ path: onceScopeMarkerPath,
3807
+ value: {
3808
+ kind: "literal",
3809
+ literalType: "boolean",
3810
+ value: true,
3811
+ location: markerLocation
3812
+ },
3813
+ location: markerLocation
3814
+ },
3815
+ condition
3816
+ },
3817
+ {
3818
+ patch: {
3819
+ kind: "patch",
3820
+ op: "set",
3821
+ path: markerPath,
3822
+ value: {
3823
+ kind: "systemIdent",
3824
+ path: ["meta", "intentId"],
3825
+ location: markerLocation
3826
+ },
3827
+ location: markerLocation
3828
+ },
3829
+ condition: onceScopeMarkerExpr
3830
+ },
3831
+ ...scopedBodyPatchStatements,
3832
+ {
3833
+ patch: {
3834
+ kind: "patch",
3835
+ op: "unset",
3836
+ path: onceScopeMarkerPath,
3837
+ location: markerLocation
3838
+ },
3839
+ condition
3840
+ }
3841
+ );
3842
+ continue;
3843
+ }
3844
+ if (stmt.kind === "onceIntent") {
3845
+ const markerScopeId = sha256Sync2(
3846
+ `${context.actionName}:${context.onceCounter}:onceIntent`
3847
+ );
3848
+ context.onceCounter += 1;
3849
+ const markerScopePath = {
3850
+ kind: "path",
3851
+ segments: [
3852
+ {
3853
+ kind: "propertySegment",
3854
+ name: "$mel",
3855
+ location: stmt.location
3856
+ },
3857
+ {
3858
+ kind: "propertySegment",
3859
+ name: "__onceScopeGuards",
3860
+ location: stmt.location
3861
+ },
3862
+ {
3863
+ kind: "propertySegment",
3864
+ name: markerScopeId,
3865
+ location: stmt.location
3866
+ }
3867
+ ],
3868
+ location: stmt.location
3869
+ };
3870
+ const markerScopeExpr = pathToMelExpr(markerScopePath);
3871
+ const onceIntentGuardId = sha256Sync2(
3872
+ `${context.actionName}:${context.onceIntentCounter}:intent`
3873
+ );
3874
+ context.onceIntentCounter += 1;
3875
+ const markerLocation = stmt.location;
3876
+ const onceIntentGuardPath = {
3877
+ kind: "path",
3878
+ segments: [
3879
+ {
3880
+ kind: "propertySegment",
3881
+ name: "$mel",
3882
+ location: markerLocation
3883
+ },
3884
+ {
3885
+ kind: "propertySegment",
3886
+ name: "guards",
3887
+ location: markerLocation
3888
+ },
3889
+ {
3890
+ kind: "propertySegment",
3891
+ name: "intent",
3892
+ location: markerLocation
3893
+ },
3894
+ {
3895
+ kind: "propertySegment",
3896
+ name: onceIntentGuardId,
3897
+ location: markerLocation
3898
+ }
3899
+ ],
3900
+ location: markerLocation
3901
+ };
3902
+ let onceIntentCondition = {
3903
+ kind: "call",
3904
+ fn: "neq",
3905
+ args: [
3906
+ pathToMelExpr(onceIntentGuardPath),
3907
+ { kind: "sys", path: ["meta", "intentId"] }
3908
+ ]
3909
+ };
3910
+ if (stmt.condition) {
3911
+ try {
3912
+ onceIntentCondition = this.conditionComposer.and(
3913
+ onceIntentCondition,
3914
+ this.deps.toMelExpr(stmt.condition)
3915
+ ) ?? onceIntentCondition;
3916
+ } catch (error) {
3917
+ errors.push({
3918
+ severity: "error",
3919
+ code: "E_LOWER",
3920
+ message: error.message,
3921
+ location: this.deps.mapLocation(stmt.condition.location)
3922
+ });
3923
+ }
3924
+ }
3925
+ const condition = this.conditionComposer.and(parentCondition, onceIntentCondition);
3926
+ const onceIntentGuardMapPath = {
3927
+ kind: "path",
3928
+ segments: [
3929
+ {
3930
+ kind: "propertySegment",
3931
+ name: "$mel",
3932
+ location: markerLocation
3933
+ },
3934
+ {
3935
+ kind: "propertySegment",
3936
+ name: "guards",
3937
+ location: markerLocation
3938
+ },
3939
+ {
3940
+ kind: "propertySegment",
3941
+ name: "intent",
3942
+ location: markerLocation
3943
+ }
3944
+ ],
3945
+ location: markerLocation
3946
+ };
3947
+ const scopedBodyPatchStatements = this.collectPatchStatements(
3948
+ stmt.body,
3949
+ errors,
3950
+ context,
3951
+ markerScopeExpr
3952
+ );
3953
+ patchStatements.push(
3954
+ {
3955
+ patch: {
3956
+ kind: "patch",
3957
+ op: "set",
3958
+ path: markerScopePath,
3959
+ value: {
3960
+ kind: "literal",
3961
+ literalType: "boolean",
3962
+ value: true,
3963
+ location: markerLocation
3964
+ },
3965
+ location: markerLocation
3966
+ },
3967
+ condition
3968
+ },
3969
+ {
3970
+ patch: {
3971
+ kind: "patch",
3972
+ op: "merge",
3973
+ path: onceIntentGuardMapPath,
3974
+ value: {
3975
+ kind: "objectLiteral",
3976
+ properties: [
3977
+ {
3978
+ kind: "objectProperty",
3979
+ key: onceIntentGuardId,
3980
+ value: {
3981
+ kind: "systemIdent",
3982
+ path: ["meta", "intentId"],
3983
+ location: markerLocation
3984
+ },
3985
+ location: markerLocation
3986
+ }
3987
+ ],
3988
+ location: markerLocation
3989
+ },
3990
+ location: markerLocation
3991
+ },
3992
+ condition: markerScopeExpr
3993
+ },
3994
+ ...scopedBodyPatchStatements,
3995
+ {
3996
+ patch: {
3997
+ kind: "patch",
3998
+ op: "unset",
3999
+ path: markerScopePath,
4000
+ location: markerLocation
4001
+ },
4002
+ condition
4003
+ }
4004
+ );
4005
+ continue;
4006
+ }
4007
+ errors.push({
4008
+ severity: "error",
4009
+ code: "E_UNSUPPORTED_STMT",
4010
+ message: `Unsupported statement '${stmt.kind}' in patch text. Only patch statements are allowed.`,
4011
+ location: this.deps.mapLocation(stmt.location)
4012
+ });
4013
+ }
4014
+ return patchStatements;
4015
+ }
4016
+ };
4017
+ function compilePatchStmtToMelRuntime(patchStatement) {
4018
+ return {
4019
+ op: patchStatement.patch.op,
4020
+ path: toRuntimePatchPath(patchStatement.patch.path),
4021
+ ...patchStatement.condition ? { condition: patchStatement.condition } : void 0,
4022
+ ...patchStatement.patch.value ? { value: toMelExpr(patchStatement.patch.value) } : void 0
4023
+ };
4024
+ }
4025
+ function pathToMelExpr(path) {
4026
+ const segments = path.segments;
4027
+ let result;
4028
+ for (const segment of segments) {
4029
+ if (segment.kind === "propertySegment") {
4030
+ const prop = { kind: "prop", name: segment.name };
4031
+ if (!result) {
4032
+ result = { kind: "get", path: [prop] };
4033
+ } else {
4034
+ result = {
4035
+ kind: "call",
4036
+ fn: "field",
4037
+ args: [result, { kind: "lit", value: segment.name }]
4038
+ };
4039
+ }
4040
+ continue;
4041
+ }
4042
+ if (!result) {
4043
+ throw new Error("Path cannot start with index access in compileMelPatch guard.");
4044
+ }
4045
+ result = {
4046
+ kind: "call",
4047
+ fn: "at",
4048
+ args: [result, toMelExpr(segment.index)]
4049
+ };
4050
+ }
4051
+ if (!result) {
4052
+ throw new Error("Empty patch guard path.");
4053
+ }
4054
+ return result;
4055
+ }
4056
+ function toRuntimePatchPath(path) {
4057
+ return path.segments.map((segment) => {
4058
+ if (segment.kind === "propertySegment") {
4059
+ return { kind: "prop", name: segment.name };
4060
+ }
4061
+ return { kind: "expr", expr: toMelExpr(segment.index) };
4062
+ });
4063
+ }
4064
+ var ConditionComposer = class {
4065
+ and(lhs, rhs) {
4066
+ if (!lhs) {
4067
+ return rhs;
4068
+ }
4069
+ if (!rhs) {
4070
+ return lhs;
4071
+ }
4072
+ return {
4073
+ kind: "call",
4074
+ fn: "and",
4075
+ args: [lhs, rhs]
4076
+ };
4077
+ }
4078
+ };
4079
+
4080
+ // src/api/compile-mel-patch-location.ts
4081
+ var SYNTHETIC_PATCH_PREFIX_LINES = 3;
4082
+ var SYNTHETIC_PATCH_PREFIX_COLUMNS = 6;
4083
+ function computeLineStartOffsets(lines) {
4084
+ const offsets = [];
4085
+ let offset = 0;
4086
+ for (const line of lines) {
4087
+ offsets.push(offset);
4088
+ offset += line.length + 1;
4089
+ }
4090
+ return offsets;
4091
+ }
4092
+ function makePatchLocationMapper(patchLines, patchLineStarts) {
4093
+ return (location) => remapLocationToPatchSource(location, patchLines, patchLineStarts);
4094
+ }
4095
+ function remapDiagnosticsToPatchSource(diagnostics, patchLines, patchLineStarts) {
4096
+ return diagnostics.map((diagnostic) => remapDiagnosticToPatchSource(
4097
+ diagnostic,
4098
+ patchLines,
4099
+ patchLineStarts
4100
+ ));
4101
+ }
4102
+ function remapDiagnosticToPatchSource(diagnostic, patchLines, patchLineStarts) {
4103
+ return {
4104
+ ...diagnostic,
4105
+ location: remapLocationToPatchSource(
4106
+ diagnostic.location,
4107
+ patchLines,
4108
+ patchLineStarts
4109
+ )
4110
+ };
4111
+ }
4112
+ function remapLocationToPatchSource(location, patchLines, patchLineStarts) {
4113
+ return {
4114
+ ...location,
4115
+ start: remapPositionToPatchSource(location.start, patchLines, patchLineStarts),
4116
+ end: remapPositionToPatchSource(location.end, patchLines, patchLineStarts)
4117
+ };
4118
+ }
4119
+ function remapPositionToPatchSource(position, patchLines, patchLineStarts) {
4120
+ const patchLine = position.line - SYNTHETIC_PATCH_PREFIX_LINES;
4121
+ const patchLineCount = patchLines.length;
4122
+ const clampedPatchLine = Math.min(Math.max(patchLine, 1), patchLineCount);
4123
+ const sourceLineStart = patchLineStarts[clampedPatchLine - 1] ?? 0;
4124
+ const sourceLineText = patchLines[clampedPatchLine - 1] ?? "";
4125
+ const maxSourceColumn = Math.max(sourceLineText.length + 1, 1);
4126
+ const sourceColumn = Math.min(
4127
+ Math.max(position.column - SYNTHETIC_PATCH_PREFIX_COLUMNS, 1),
4128
+ maxSourceColumn
4129
+ );
4130
+ return {
4131
+ line: clampedPatchLine,
4132
+ column: sourceColumn,
4133
+ offset: Math.max(sourceLineStart + sourceColumn - 1, 0)
4134
+ };
4135
+ }
4136
+
4137
+ // src/api/compile-mel-patch.ts
4138
+ var SYNTHETIC_ACTION = "__compileMelPatch";
4139
+ var SYNTHETIC_DOMAIN = "__patchDomain";
4140
+ var SYNTHETIC_PATCH_INDENT = " ";
4141
+ function compileMelPatchText(melText, options) {
4142
+ const trace = [];
4143
+ const warnings = [];
4144
+ const errors = [];
4145
+ const patchLines = melText.split("\n");
4146
+ const patchLineStarts = computeLineStartOffsets(patchLines);
4147
+ const mapLocation = makePatchLocationMapper(patchLines, patchLineStarts);
4148
+ const syntheticMel = buildSyntheticPatchProgram(melText, SYNTHETIC_ACTION);
4149
+ const lexStart = performance.now();
4150
+ let tokens;
4151
+ try {
4152
+ const lexResult = tokenize(syntheticMel);
4153
+ tokens = lexResult.tokens;
4154
+ const lexErrors = remapDiagnosticsToPatchSource(
4155
+ lexResult.diagnostics.filter((d) => d.severity === "error"),
4156
+ patchLines,
4157
+ patchLineStarts
4158
+ );
4159
+ if (lexErrors.length > 0) {
4160
+ errors.push(...lexErrors);
4161
+ trace.push({
4162
+ phase: "lex",
4163
+ durationMs: performance.now() - lexStart,
4164
+ details: { tokenCount: tokens.length }
4165
+ });
4166
+ return { ops: [], trace, warnings, errors };
4167
+ }
4168
+ } catch (error) {
4169
+ errors.push({
4170
+ severity: "error",
4171
+ code: "E_LEX",
4172
+ message: error.message,
4173
+ location: {
4174
+ start: { line: 1, column: 1, offset: 0 },
4175
+ end: { line: 1, column: 1, offset: 0 }
4176
+ }
4177
+ });
4178
+ trace.push({ phase: "lex", durationMs: performance.now() - lexStart });
4179
+ return { ops: [], trace, warnings, errors };
4180
+ }
4181
+ trace.push({
4182
+ phase: "lex",
4183
+ durationMs: performance.now() - lexStart,
4184
+ details: { tokenCount: tokens.length }
4185
+ });
4186
+ const parseStart = performance.now();
4187
+ let program;
4188
+ try {
4189
+ const parseResult = parse(tokens);
4190
+ const parsedDiagnostics = remapDiagnosticsToPatchSource(
4191
+ parseResult.diagnostics,
4192
+ patchLines,
4193
+ patchLineStarts
4194
+ );
4195
+ const parseErrors = parsedDiagnostics.filter((d) => d.severity === "error");
4196
+ const parseWarnings = parsedDiagnostics.filter((d) => d.severity !== "error");
4197
+ if (parseErrors.length > 0) {
4198
+ errors.push(...parseErrors);
4199
+ warnings.push(...parseWarnings);
4200
+ trace.push({ phase: "parse", durationMs: performance.now() - parseStart });
4201
+ return { ops: [], trace, warnings, errors };
4202
+ }
4203
+ if (!parseResult.program) {
4204
+ errors.push({
4205
+ severity: "error",
4206
+ code: "E_PARSE",
4207
+ message: "Failed to parse MEL patch program",
4208
+ location: {
4209
+ start: { line: 1, column: 1, offset: 0 },
4210
+ end: { line: 1, column: 1, offset: 0 }
4211
+ }
4212
+ });
4213
+ warnings.push(...parseWarnings);
4214
+ trace.push({ phase: "parse", durationMs: performance.now() - parseStart });
4215
+ return { ops: [], trace, warnings, errors };
4216
+ }
4217
+ program = parseResult.program;
4218
+ warnings.push(...parseWarnings);
4219
+ } catch (error) {
4220
+ errors.push({
4221
+ severity: "error",
4222
+ code: "E_PARSE",
4223
+ message: error.message,
4224
+ location: {
4225
+ start: { line: 1, column: 1, offset: 0 },
4226
+ end: { line: 1, column: 1, offset: 0 }
4227
+ }
4228
+ });
4229
+ trace.push({ phase: "parse", durationMs: performance.now() - parseStart });
4230
+ return { ops: [], trace, warnings, errors };
4231
+ }
4232
+ trace.push({ phase: "parse", durationMs: performance.now() - parseStart });
4233
+ const analyzeStart = performance.now();
4234
+ const collectContext = {
4235
+ actionName: options.actionName,
4236
+ onceCounter: 0,
4237
+ onceIntentCounter: 0,
4238
+ whenCounter: 0
4239
+ };
4240
+ const action = program.domain.members.find(
4241
+ (member) => member.kind === "action" && member.name === SYNTHETIC_ACTION
4242
+ );
4243
+ if (!action) {
4244
+ errors.push({
4245
+ severity: "error",
4246
+ code: "E_ANALYZE",
4247
+ message: `Synthetic patch action '${SYNTHETIC_ACTION}' not found during parsing`,
4248
+ location: {
4249
+ start: { line: 1, column: 1, offset: 0 },
4250
+ end: { line: 1, column: 1, offset: 0 }
4251
+ }
4252
+ });
4253
+ trace.push({ phase: "analyze", durationMs: performance.now() - analyzeStart });
4254
+ return { ops: [], trace, warnings, errors };
4255
+ }
4256
+ const expectedActionEndLine = patchLines.length + SYNTHETIC_PATCH_PREFIX_LINES + 2;
4257
+ if (action.location.end.line !== expectedActionEndLine) {
4258
+ errors.push({
4259
+ severity: "error",
4260
+ code: "E_PATCH_WRAPPER",
4261
+ message: `Malformed synthetic patch wrapper for action '${SYNTHETIC_ACTION}'.`,
4262
+ location: mapLocation(action.location)
4263
+ });
4264
+ trace.push({ phase: "analyze", durationMs: performance.now() - analyzeStart });
4265
+ return { ops: [], trace, warnings, errors };
4266
+ }
4267
+ const [patchRoot] = action.body;
4268
+ if (!patchRoot || patchRoot.kind !== "when" || !isSyntheticPatchCondition(patchRoot.condition) || action.body.length !== 1) {
4269
+ errors.push({
4270
+ severity: "error",
4271
+ code: "E_PATCH_WRAPPER",
4272
+ message: `Malformed synthetic patch wrapper for action '${SYNTHETIC_ACTION}'.`,
4273
+ location: mapLocation(action.location)
4274
+ });
4275
+ trace.push({ phase: "analyze", durationMs: performance.now() - analyzeStart });
4276
+ return { ops: [], trace, warnings, errors };
4277
+ }
4278
+ const collector = new PatchStatementCollector({
4279
+ mapLocation,
4280
+ toMelExpr
4281
+ });
4282
+ const patchStatements = collector.collect(
4283
+ patchRoot.body,
4284
+ errors,
4285
+ collectContext,
4286
+ void 0
4287
+ );
4288
+ if (errors.length === 0 && melText.trim() !== "" && patchStatements.length === 0) {
4289
+ errors.push({
4290
+ severity: "error",
4291
+ code: "E_PATCH_WRAPPER",
4292
+ message: "Patch wrapper parsing produced no patch statements. The patch source may be malformed.",
4293
+ location: mapLocation(patchRoot.location)
4294
+ });
4295
+ }
4296
+ trace.push({
4297
+ phase: "analyze",
4298
+ durationMs: performance.now() - analyzeStart,
4299
+ details: { count: patchStatements.length }
4300
+ });
4301
+ if (errors.length > 0) {
4302
+ return { ops: [], trace, warnings, errors };
4303
+ }
4304
+ const lowerStart = performance.now();
4305
+ const loweringContext = {
4306
+ mode: "action",
4307
+ allowSysPaths: options.allowSysPaths ?? { prefixes: ["meta", "input"] },
4308
+ fnTableVersion: options.fnTableVersion ?? "1.0",
4309
+ actionName: options.actionName
4310
+ };
4311
+ const loweredOps = [];
4312
+ for (const patchStatement of patchStatements) {
4313
+ try {
4314
+ const melPatch = compilePatchStmtToMelRuntime(patchStatement);
4315
+ loweredOps.push(lowerRuntimePatch(melPatch, loweringContext));
4316
+ } catch (error) {
4317
+ if (error instanceof LoweringError) {
4318
+ errors.push({
4319
+ severity: "error",
4320
+ code: error.code,
4321
+ message: error.message,
4322
+ location: mapLocation(patchStatement.patch.location)
4323
+ });
4324
+ } else if (error instanceof Error) {
4325
+ errors.push({
4326
+ severity: "error",
4327
+ code: "E_LOWER",
4328
+ message: error.message,
4329
+ location: mapLocation(patchStatement.patch.location)
4330
+ });
4331
+ } else {
4332
+ errors.push({
4333
+ severity: "error",
4334
+ code: "E_LOWER",
4335
+ message: "Unknown lowering failure",
4336
+ location: mapLocation(patchStatement.patch.location)
4337
+ });
4338
+ }
4339
+ }
4340
+ }
4341
+ trace.push({
4342
+ phase: "lower",
4343
+ durationMs: performance.now() - lowerStart,
4344
+ details: { count: loweredOps.length }
4345
+ });
4346
+ if (errors.length > 0) {
4347
+ return { ops: [], trace, warnings, errors };
4348
+ }
4349
+ return {
4350
+ ops: loweredOps,
4351
+ trace,
4352
+ warnings,
4353
+ errors
4354
+ };
4355
+ }
4356
+ function buildSyntheticPatchProgram(melText, actionName) {
4357
+ const indentedPatchText = melText.split("\n").map((line) => `${SYNTHETIC_PATCH_INDENT}${line}`).join("\n");
4358
+ return [
4359
+ `domain ${SYNTHETIC_DOMAIN} {`,
4360
+ ` action ${actionName}() {`,
4361
+ " when true {",
4362
+ indentedPatchText,
4363
+ " }",
4364
+ " }",
4365
+ "}"
4366
+ ].join("\n");
4367
+ }
4368
+
4369
+ // src/api/compile-mel.ts
4370
+ function compileMelDomain(melText, options) {
4371
+ const trace = [];
4372
+ const warnings = [];
4373
+ const errors = [];
4374
+ const lexStart = performance.now();
4375
+ let tokens;
4376
+ try {
4377
+ const lexResult = tokenize(melText);
4378
+ tokens = lexResult.tokens;
4379
+ const lexErrors = lexResult.diagnostics.filter((d) => d.severity === "error");
4380
+ if (lexErrors.length > 0) {
4381
+ errors.push(...lexErrors);
4382
+ trace.push({ phase: "lex", durationMs: performance.now() - lexStart, details: { tokenCount: tokens.length } });
4383
+ return { schema: null, trace, warnings, errors };
4384
+ }
4385
+ const lexWarnings = lexResult.diagnostics.filter((d) => d.severity === "warning");
4386
+ warnings.push(...lexWarnings);
4387
+ } catch (e) {
4388
+ const error = e;
4389
+ errors.push({
4390
+ severity: "error",
4391
+ code: "E_LEX",
4392
+ message: error.message,
4393
+ location: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
4394
+ });
4395
+ trace.push({ phase: "lex", durationMs: performance.now() - lexStart });
4396
+ return { schema: null, trace, warnings, errors };
4397
+ }
4398
+ trace.push({ phase: "lex", durationMs: performance.now() - lexStart, details: { tokenCount: tokens.length } });
4399
+ const parseStart = performance.now();
4400
+ let ast;
4401
+ try {
4402
+ const parseResult = parse(tokens);
4403
+ const parseErrors = parseResult.diagnostics.filter((d) => d.severity === "error");
4404
+ if (parseErrors.length > 0) {
4405
+ errors.push(...parseErrors);
4406
+ trace.push({ phase: "parse", durationMs: performance.now() - parseStart });
4407
+ return { schema: null, trace, warnings, errors: capDiagnostics(errors) };
4408
+ }
4409
+ ast = parseResult.program;
4410
+ } catch (e) {
4411
+ const error = e;
4412
+ errors.push({
4413
+ severity: "error",
4414
+ code: "E_PARSE",
4415
+ message: error.message,
4416
+ location: { start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }
4417
+ });
4418
+ trace.push({ phase: "parse", durationMs: performance.now() - parseStart });
4419
+ return { schema: null, trace, warnings, errors };
4420
+ }
4421
+ trace.push({ phase: "parse", durationMs: performance.now() - parseStart });
4422
+ const analyzeStart = performance.now();
4423
+ const scopeResult = analyzeScope(ast);
4424
+ const validateResult = validateSemantics(ast);
4425
+ const analyzeErrors = [
4426
+ ...scopeResult.diagnostics.filter((d) => d.severity === "error"),
4427
+ ...validateResult.diagnostics.filter((d) => d.severity === "error")
4428
+ ];
4429
+ const analyzeWarnings = [
4430
+ ...scopeResult.diagnostics.filter((d) => d.severity === "warning"),
4431
+ ...validateResult.diagnostics.filter((d) => d.severity === "warning")
4432
+ ];
4433
+ warnings.push(...analyzeWarnings);
4434
+ trace.push({ phase: "analyze", durationMs: performance.now() - analyzeStart });
4435
+ if (analyzeErrors.length > 0) {
4436
+ errors.push(...analyzeErrors);
4437
+ return { schema: null, trace, warnings, errors };
4438
+ }
4439
+ const genStart = performance.now();
4440
+ const genResult = generate(ast);
4441
+ trace.push({ phase: "generate", durationMs: performance.now() - genStart });
4442
+ for (const diag of genResult.diagnostics) {
4443
+ if (diag.severity === "warning") {
4444
+ warnings.push(diag);
4445
+ } else {
4446
+ errors.push(diag);
4447
+ }
4448
+ }
4449
+ return {
4450
+ schema: genResult.schema,
4451
+ trace,
4452
+ warnings,
4453
+ errors: capDiagnostics(errors)
4454
+ };
4455
+ }
4456
+ var MAX_ERRORS = 10;
4457
+ function capDiagnostics(diagnostics) {
4458
+ if (diagnostics.length <= MAX_ERRORS) return diagnostics;
4459
+ const capped = diagnostics.slice(0, MAX_ERRORS);
4460
+ capped.push({
4461
+ severity: "error",
4462
+ code: "E_TOO_MANY",
4463
+ message: `... and ${diagnostics.length - MAX_ERRORS} more error(s). Fix the errors above first.`,
4464
+ location: { start: { line: 0, column: 0, offset: 0 }, end: { line: 0, column: 0, offset: 0 } }
4465
+ });
4466
+ return capped;
4467
+ }
4468
+ function compileMelPatch(melText, options) {
4469
+ return compileMelPatchText(melText, options);
4470
+ }
4471
+
4472
+ export {
4473
+ KEYWORDS,
4474
+ RESERVED_KEYWORDS,
4475
+ isKeyword,
4476
+ isReserved,
4477
+ getKeywordKind,
4478
+ createToken,
4479
+ createPosition,
4480
+ createLocation,
4481
+ createPointLocation,
4482
+ mergeLocations,
4483
+ Lexer,
4484
+ tokenize,
4485
+ isExprNode,
4486
+ isStmtNode,
4487
+ Precedence,
4488
+ getBinaryPrecedence,
4489
+ tokenToBinaryOp,
4490
+ isBinaryOp,
4491
+ isUnaryOp,
4492
+ isRightAssociative,
4493
+ Parser,
4494
+ parse,
4495
+ Scope,
4496
+ ScopeAnalyzer,
4497
+ analyzeScope,
4498
+ createError,
4499
+ createWarning,
4500
+ createInfo,
4501
+ isError,
4502
+ hasErrors,
4503
+ filterBySeverity,
4504
+ SemanticValidator,
4505
+ validateSemantics,
4506
+ normalizeExpr,
4507
+ normalizeFunctionCall,
4508
+ generate,
4509
+ LoweringError,
4510
+ invalidKindForContext,
4511
+ unknownCallFn,
4512
+ invalidSysPath,
4513
+ unsupportedBase,
4514
+ invalidShape,
4515
+ unknownNodeKind,
4516
+ lowerExprNode,
4517
+ lowerRuntimePatches,
4518
+ lowerRuntimePatch,
4519
+ compileMelDomain,
4520
+ compileMelPatch
4521
+ };
4522
+ //# sourceMappingURL=chunk-QP2LGMBA.js.map