@elaraai/east 0.0.1-beta.3 → 0.0.1-beta.31

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 (191) hide show
  1. package/LICENSE.md +15 -666
  2. package/README.md +30 -8
  3. package/dist/src/analyze.d.ts +3 -0
  4. package/dist/src/analyze.d.ts.map +1 -1
  5. package/dist/src/analyze.js +76 -15
  6. package/dist/src/analyze.js.map +1 -1
  7. package/dist/src/ast.d.ts +37 -33
  8. package/dist/src/ast.d.ts.map +1 -1
  9. package/dist/src/ast_to_ir.d.ts +6 -0
  10. package/dist/src/ast_to_ir.d.ts.map +1 -1
  11. package/dist/src/ast_to_ir.js +135 -101
  12. package/dist/src/ast_to_ir.js.map +1 -1
  13. package/dist/src/builtins.d.ts +1 -1
  14. package/dist/src/builtins.d.ts.map +1 -1
  15. package/dist/src/builtins.js +32 -0
  16. package/dist/src/builtins.js.map +1 -1
  17. package/dist/src/comparison.d.ts.map +1 -1
  18. package/dist/src/comparison.js +12 -4
  19. package/dist/src/comparison.js.map +1 -1
  20. package/dist/src/compile.d.ts +26 -1
  21. package/dist/src/compile.d.ts.map +1 -1
  22. package/dist/src/compile.js +388 -257
  23. package/dist/src/compile.js.map +1 -1
  24. package/dist/src/datetime_format/types.d.ts +23 -23
  25. package/dist/src/eastir.d.ts +4 -0
  26. package/dist/src/eastir.d.ts.map +1 -1
  27. package/dist/src/eastir.js +27 -7
  28. package/dist/src/eastir.js.map +1 -1
  29. package/dist/src/error.d.ts +12 -1
  30. package/dist/src/error.d.ts.map +1 -1
  31. package/dist/src/error.js +31 -1
  32. package/dist/src/error.js.map +1 -1
  33. package/dist/src/expr/array.d.ts +109 -1
  34. package/dist/src/expr/array.d.ts.map +1 -1
  35. package/dist/src/expr/array.js +204 -44
  36. package/dist/src/expr/array.js.map +1 -1
  37. package/dist/src/expr/ast.d.ts +1 -1
  38. package/dist/src/expr/ast.d.ts.map +1 -1
  39. package/dist/src/expr/ast.js +16 -28
  40. package/dist/src/expr/ast.js.map +1 -1
  41. package/dist/src/expr/asyncfunction.js +1 -1
  42. package/dist/src/expr/asyncfunction.js.map +1 -1
  43. package/dist/src/expr/blob.d.ts +73 -1
  44. package/dist/src/expr/blob.d.ts.map +1 -1
  45. package/dist/src/expr/blob.js +97 -7
  46. package/dist/src/expr/blob.js.map +1 -1
  47. package/dist/src/expr/block.d.ts +232 -12
  48. package/dist/src/expr/block.d.ts.map +1 -1
  49. package/dist/src/expr/block.js +646 -140
  50. package/dist/src/expr/block.js.map +1 -1
  51. package/dist/src/expr/boolean.d.ts +44 -0
  52. package/dist/src/expr/boolean.d.ts.map +1 -1
  53. package/dist/src/expr/boolean.js +57 -5
  54. package/dist/src/expr/boolean.js.map +1 -1
  55. package/dist/src/expr/datetime.d.ts +135 -0
  56. package/dist/src/expr/datetime.d.ts.map +1 -1
  57. package/dist/src/expr/datetime.js +183 -33
  58. package/dist/src/expr/datetime.js.map +1 -1
  59. package/dist/src/expr/dict.d.ts +42 -0
  60. package/dist/src/expr/dict.d.ts.map +1 -1
  61. package/dist/src/expr/dict.js +105 -55
  62. package/dist/src/expr/dict.js.map +1 -1
  63. package/dist/src/expr/expr.d.ts +1 -1
  64. package/dist/src/expr/expr.d.ts.map +1 -1
  65. package/dist/src/expr/expr.js.map +1 -1
  66. package/dist/src/expr/float.d.ts +153 -0
  67. package/dist/src/expr/float.d.ts.map +1 -1
  68. package/dist/src/expr/float.js +190 -16
  69. package/dist/src/expr/float.js.map +1 -1
  70. package/dist/src/expr/function.d.ts +7 -2
  71. package/dist/src/expr/function.d.ts.map +1 -1
  72. package/dist/src/expr/function.js +1 -1
  73. package/dist/src/expr/function.js.map +1 -1
  74. package/dist/src/expr/index.d.ts +202 -2
  75. package/dist/src/expr/index.d.ts.map +1 -1
  76. package/dist/src/expr/index.js +207 -2
  77. package/dist/src/expr/index.js.map +1 -1
  78. package/dist/src/expr/integer.d.ts +180 -0
  79. package/dist/src/expr/integer.d.ts.map +1 -1
  80. package/dist/src/expr/integer.js +188 -17
  81. package/dist/src/expr/integer.js.map +1 -1
  82. package/dist/src/expr/libs/blob.js +2 -2
  83. package/dist/src/expr/libs/blob.js.map +1 -1
  84. package/dist/src/expr/libs/integer.d.ts +19 -0
  85. package/dist/src/expr/libs/integer.d.ts.map +1 -1
  86. package/dist/src/expr/libs/integer.js +47 -0
  87. package/dist/src/expr/libs/integer.js.map +1 -1
  88. package/dist/src/expr/libs/string.js +1 -1
  89. package/dist/src/expr/libs/string.js.map +1 -1
  90. package/dist/src/expr/recursive.d.ts +83 -0
  91. package/dist/src/expr/recursive.d.ts.map +1 -0
  92. package/dist/src/expr/recursive.js +99 -0
  93. package/dist/src/expr/recursive.js.map +1 -0
  94. package/dist/src/expr/ref.js +3 -3
  95. package/dist/src/expr/ref.js.map +1 -1
  96. package/dist/src/expr/set.d.ts +44 -2
  97. package/dist/src/expr/set.d.ts.map +1 -1
  98. package/dist/src/expr/set.js +97 -47
  99. package/dist/src/expr/set.js.map +1 -1
  100. package/dist/src/expr/string.d.ts +134 -0
  101. package/dist/src/expr/string.d.ts.map +1 -1
  102. package/dist/src/expr/string.js +172 -22
  103. package/dist/src/expr/string.js.map +1 -1
  104. package/dist/src/expr/struct.d.ts +1 -1
  105. package/dist/src/expr/struct.d.ts.map +1 -1
  106. package/dist/src/expr/struct.js +1 -1
  107. package/dist/src/expr/struct.js.map +1 -1
  108. package/dist/src/expr/types.d.ts +7 -6
  109. package/dist/src/expr/types.d.ts.map +1 -1
  110. package/dist/src/expr/variant.d.ts +123 -1
  111. package/dist/src/expr/variant.d.ts.map +1 -1
  112. package/dist/src/expr/variant.js +66 -2
  113. package/dist/src/expr/variant.js.map +1 -1
  114. package/dist/src/fuzz.d.ts +36 -2
  115. package/dist/src/fuzz.d.ts.map +1 -1
  116. package/dist/src/fuzz.js +344 -77
  117. package/dist/src/fuzz.js.map +1 -1
  118. package/dist/src/index.d.ts +1 -0
  119. package/dist/src/index.d.ts.map +1 -1
  120. package/dist/src/index.js +1 -0
  121. package/dist/src/index.js.map +1 -1
  122. package/dist/src/internal.d.ts +12 -0
  123. package/dist/src/internal.d.ts.map +1 -1
  124. package/dist/src/internal.js +13 -0
  125. package/dist/src/internal.js.map +1 -1
  126. package/dist/src/ir.d.ts +1551 -1505
  127. package/dist/src/ir.d.ts.map +1 -1
  128. package/dist/src/ir.js +49 -34
  129. package/dist/src/ir.js.map +1 -1
  130. package/dist/src/location.d.ts +30 -10
  131. package/dist/src/location.d.ts.map +1 -1
  132. package/dist/src/location.js +70 -28
  133. package/dist/src/location.js.map +1 -1
  134. package/dist/src/patch/apply.d.ts +15 -0
  135. package/dist/src/patch/apply.d.ts.map +1 -0
  136. package/dist/src/patch/apply.js +380 -0
  137. package/dist/src/patch/apply.js.map +1 -0
  138. package/dist/src/patch/compose.d.ts +15 -0
  139. package/dist/src/patch/compose.d.ts.map +1 -0
  140. package/dist/src/patch/compose.js +480 -0
  141. package/dist/src/patch/compose.js.map +1 -0
  142. package/dist/src/patch/diff.d.ts +15 -0
  143. package/dist/src/patch/diff.d.ts.map +1 -0
  144. package/dist/src/patch/diff.js +328 -0
  145. package/dist/src/patch/diff.js.map +1 -0
  146. package/dist/src/patch/fuzz.d.ts +73 -0
  147. package/dist/src/patch/fuzz.d.ts.map +1 -0
  148. package/dist/src/patch/fuzz.js +159 -0
  149. package/dist/src/patch/fuzz.js.map +1 -0
  150. package/dist/src/patch/index.d.ts +18 -0
  151. package/dist/src/patch/index.d.ts.map +1 -0
  152. package/dist/src/patch/index.js +20 -0
  153. package/dist/src/patch/index.js.map +1 -0
  154. package/dist/src/patch/invert.d.ts +15 -0
  155. package/dist/src/patch/invert.d.ts.map +1 -0
  156. package/dist/src/patch/invert.js +302 -0
  157. package/dist/src/patch/invert.js.map +1 -0
  158. package/dist/src/patch/type_of_patch.d.ts +17 -0
  159. package/dist/src/patch/type_of_patch.d.ts.map +1 -0
  160. package/dist/src/patch/type_of_patch.js +143 -0
  161. package/dist/src/patch/type_of_patch.js.map +1 -0
  162. package/dist/src/patch/types.d.ts +166 -0
  163. package/dist/src/patch/types.d.ts.map +1 -0
  164. package/dist/src/patch/types.js +69 -0
  165. package/dist/src/patch/types.js.map +1 -0
  166. package/dist/src/platform.d.ts +6 -0
  167. package/dist/src/platform.d.ts.map +1 -1
  168. package/dist/src/serialization/beast.d.ts.map +1 -1
  169. package/dist/src/serialization/beast.js +53 -18
  170. package/dist/src/serialization/beast.js.map +1 -1
  171. package/dist/src/serialization/beast2.d.ts +39 -3
  172. package/dist/src/serialization/beast2.d.ts.map +1 -1
  173. package/dist/src/serialization/beast2.js +241 -18
  174. package/dist/src/serialization/beast2.js.map +1 -1
  175. package/dist/src/serialization/csv.d.ts +139 -0
  176. package/dist/src/serialization/csv.d.ts.map +1 -0
  177. package/dist/src/serialization/csv.js +615 -0
  178. package/dist/src/serialization/csv.js.map +1 -0
  179. package/dist/src/serialization/index.d.ts +2 -1
  180. package/dist/src/serialization/index.d.ts.map +1 -1
  181. package/dist/src/serialization/index.js +2 -1
  182. package/dist/src/serialization/index.js.map +1 -1
  183. package/dist/src/type_of_type.d.ts +45 -34
  184. package/dist/src/type_of_type.d.ts.map +1 -1
  185. package/dist/src/type_of_type.js +62 -1
  186. package/dist/src/type_of_type.js.map +1 -1
  187. package/dist/src/types.d.ts +8 -8
  188. package/dist/src/types.d.ts.map +1 -1
  189. package/dist/src/types.js +4 -4
  190. package/dist/src/types.js.map +1 -1
  191. package/package.json +4 -5
@@ -3,9 +3,9 @@
3
3
  * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
4
  */
5
5
  import {} from "../ast.js";
6
- import { get_location, printLocation } from "../location.js";
6
+ import { get_location, printLocations } from "../location.js";
7
7
  import { FunctionType, isSubtype, NullType, printType, isTypeEqual, StringType, NeverType, VariantType, BooleanType, TypeUnion, IntegerType, StructType, ArrayType, AsyncFunctionType } from "../types.js";
8
- import { AstSymbol, Expr } from "./expr.js";
8
+ import { AstSymbol, Expr, TypeSymbol } from "./expr.js";
9
9
  import { NeverExpr } from "./never.js";
10
10
  import { NullExpr } from "./null.js";
11
11
  import { BooleanExpr } from "./boolean.js";
@@ -19,11 +19,14 @@ import { SetExpr } from "./set.js";
19
19
  import { DictExpr } from "./dict.js";
20
20
  import { StructExpr } from "./struct.js";
21
21
  import { VariantExpr } from "./variant.js";
22
- import { createFunctionExpr } from "./function.js";
22
+ import { RecursiveExpr } from "./recursive.js";
23
+ import { createFunctionExpr, FunctionExpr } from "./function.js";
23
24
  import { valueOrExprToAst, valueOrExprToAstTyped } from "./ast.js";
24
25
  import { toEastTypeValue } from "../type_of_type.js";
26
+ import { isVariant } from "../containers/variant.js";
25
27
  import { RefExpr } from "./ref.js";
26
- import { createAsyncFunctionExpr } from "./asyncfunction.js";
28
+ import { AsyncFunctionExpr, createAsyncFunctionExpr } from "./asyncfunction.js";
29
+ import { PatchType } from "../patch/index.js";
27
30
  /** A factory function to help build `Expr` from AST.
28
31
  * We inject this into each concrete `Expr` type so they can create new expressions recursively, without having circular dependencies between JavaScript modules.
29
32
  */
@@ -72,14 +75,8 @@ export function fromAst(ast) {
72
75
  return new VariantExpr(ast.type.cases, ast, fromAst);
73
76
  }
74
77
  else if (type === "Recursive") {
75
- // Automatically unwrap a recursive type to give access to the node data
76
- const as_ast = {
77
- ast_type: "UnwrapRecursive",
78
- type: ast.type.node,
79
- location: ast.location,
80
- value: ast,
81
- };
82
- return fromAst(as_ast);
78
+ // Return RecursiveExpr to preserve the RecursiveType wrapper for TypeOf
79
+ return new RecursiveExpr(ast.type.node, ast, fromAst);
83
80
  }
84
81
  else if (type === "Function") {
85
82
  return createFunctionExpr(ast.type.inputs, ast.type.output, ast, fromAst);
@@ -88,9 +85,29 @@ export function fromAst(ast) {
88
85
  return createAsyncFunctionExpr(ast.type.inputs, ast.type.output, ast, fromAst);
89
86
  }
90
87
  else {
91
- throw new Error(`fromAst not implemented for type ${printType(ast.type)} at ${printLocation(ast.location)}`);
88
+ throw new Error(`fromAst not implemented for type ${printType(ast.type)} at ${printLocations(ast.location)}`);
92
89
  }
93
90
  }
91
+ /**
92
+ * Compile a function expression into a JavaScript function.
93
+ *
94
+ * @param f the function expression to compile
95
+ * @param platform the platform functions available during compilation
96
+ * @returns the compiled function
97
+ */
98
+ export function compile(f, platform) {
99
+ return f.toIR().compile(platform);
100
+ }
101
+ /**
102
+ * Compile an async function expression into a JavaScript function.
103
+ *
104
+ * @param f the async function expression to compile
105
+ * @param platform the platform functions available during compilation
106
+ * @returns the compiled async function
107
+ */
108
+ export function compileAsync(f, platform) {
109
+ return f.toIR().compile(platform);
110
+ }
94
111
  export function from(value, type) {
95
112
  if (value instanceof Expr) {
96
113
  if (type) {
@@ -110,7 +127,7 @@ export function from(value, type) {
110
127
  const input_variables = inputs.map(i => ({
111
128
  ast_type: "Variable",
112
129
  type: i,
113
- location: get_location(3),
130
+ location: get_location(),
114
131
  mutable: false,
115
132
  }));
116
133
  const $ = BlockBuilder(output);
@@ -134,19 +151,19 @@ export function from(value, type) {
134
151
  let body_ast;
135
152
  if (isTypeEqual(output, NullType)) {
136
153
  if (statements.length === 0) {
137
- body_ast = { ast_type: "Value", type: NullType, location: get_location(2), value: null };
154
+ body_ast = { ast_type: "Value", type: NullType, location: get_location(), value: null };
138
155
  }
139
156
  else if (statements.length === 1 && isSubtype(statements[0].type, NullType)) {
140
157
  body_ast = statements[0];
141
158
  }
142
159
  else {
143
160
  if (!isSubtype(statements[statements.length - 1].type, NullType)) {
144
- statements.push({ ast_type: "Value", type: NullType, location: get_location(3), value: null });
161
+ statements.push({ ast_type: "Value", type: NullType, location: get_location(), value: null });
145
162
  }
146
163
  body_ast = {
147
164
  ast_type: "Block",
148
165
  type: statements[statements.length - 1].type,
149
- location: get_location(3),
166
+ location: get_location(),
150
167
  statements: statements,
151
168
  };
152
169
  }
@@ -168,7 +185,7 @@ export function from(value, type) {
168
185
  body_ast = {
169
186
  ast_type: "Block",
170
187
  type: statements[statements.length - 1].type,
171
- location: get_location(3),
188
+ location: get_location(),
172
189
  statements: statements,
173
190
  };
174
191
  }
@@ -179,7 +196,7 @@ export function from(value, type) {
179
196
  const ast = {
180
197
  ast_type: "Function",
181
198
  type: FunctionType(inputs, output),
182
- location: get_location(3),
199
+ location: get_location(),
183
200
  parameters: input_variables,
184
201
  body: body_ast,
185
202
  };
@@ -193,7 +210,7 @@ export function from(value, type) {
193
210
  const input_variables = inputs.map(i => ({
194
211
  ast_type: "Variable",
195
212
  type: i,
196
- location: get_location(3),
213
+ location: get_location(),
197
214
  mutable: false,
198
215
  }));
199
216
  const $ = BlockBuilder(output);
@@ -217,19 +234,19 @@ export function from(value, type) {
217
234
  let body_ast;
218
235
  if (isTypeEqual(output, NullType)) {
219
236
  if (statements.length === 0) {
220
- body_ast = { ast_type: "Value", type: NullType, location: get_location(2), value: null };
237
+ body_ast = { ast_type: "Value", type: NullType, location: get_location(), value: null };
221
238
  }
222
239
  else if (statements.length === 1 && isSubtype(statements[0].type, NullType)) {
223
240
  body_ast = statements[0];
224
241
  }
225
242
  else {
226
243
  if (!isSubtype(statements[statements.length - 1].type, NullType)) {
227
- statements.push({ ast_type: "Value", type: NullType, location: get_location(3), value: null });
244
+ statements.push({ ast_type: "Value", type: NullType, location: get_location(), value: null });
228
245
  }
229
246
  body_ast = {
230
247
  ast_type: "Block",
231
248
  type: statements[statements.length - 1].type,
232
- location: get_location(3),
249
+ location: get_location(),
233
250
  statements: statements,
234
251
  };
235
252
  }
@@ -251,7 +268,7 @@ export function from(value, type) {
251
268
  body_ast = {
252
269
  ast_type: "Block",
253
270
  type: statements[statements.length - 1].type,
254
- location: get_location(3),
271
+ location: get_location(),
255
272
  statements: statements,
256
273
  };
257
274
  }
@@ -262,7 +279,7 @@ export function from(value, type) {
262
279
  const ast = {
263
280
  ast_type: "AsyncFunction",
264
281
  type: FunctionType(inputs, output),
265
- location: get_location(3),
282
+ location: get_location(),
266
283
  parameters: input_variables,
267
284
  body: body_ast,
268
285
  };
@@ -275,7 +292,7 @@ export function func(input_types, output_type, body) {
275
292
  const parameters = input_types.map(i => ({
276
293
  ast_type: "Variable",
277
294
  type: i,
278
- location: get_location(2),
295
+ location: get_location(),
279
296
  mutable: false,
280
297
  }));
281
298
  const $ = BlockBuilder(output_type ?? NeverType);
@@ -292,7 +309,7 @@ export function func(input_types, output_type, body) {
292
309
  const ret_type = ret_ast.type;
293
310
  let body_ast;
294
311
  if (statements.length === 0) {
295
- body_ast = { ast_type: "Value", type: NullType, location: get_location(2), value: null };
312
+ body_ast = { ast_type: "Value", type: NullType, location: get_location(), value: null };
296
313
  }
297
314
  else if (statements.length === 1) {
298
315
  body_ast = statements[0];
@@ -301,7 +318,7 @@ export function func(input_types, output_type, body) {
301
318
  body_ast = {
302
319
  ast_type: "Block",
303
320
  type: statements[statements.length - 1].type,
304
- location: get_location(2),
321
+ location: get_location(),
305
322
  statements: statements,
306
323
  };
307
324
  }
@@ -311,7 +328,7 @@ export function func(input_types, output_type, body) {
311
328
  const ast = {
312
329
  ast_type: "Function",
313
330
  type: FunctionType(input_types, ret_type),
314
- location: get_location(2),
331
+ location: get_location(),
315
332
  parameters: parameters,
316
333
  body: body_ast,
317
334
  };
@@ -326,7 +343,7 @@ export function func(input_types, output_type, body) {
326
343
  }
327
344
  let body_ast;
328
345
  if (statements.length === 0) {
329
- body_ast = { ast_type: "Value", type: NullType, location: get_location(2), value: null };
346
+ body_ast = { ast_type: "Value", type: NullType, location: get_location(), value: null };
330
347
  }
331
348
  else if (statements.length === 1) {
332
349
  body_ast = statements[0];
@@ -335,7 +352,7 @@ export function func(input_types, output_type, body) {
335
352
  body_ast = {
336
353
  ast_type: "Block",
337
354
  type: statements[statements.length - 1].type,
338
- location: get_location(2),
355
+ location: get_location(),
339
356
  statements: statements,
340
357
  };
341
358
  }
@@ -346,7 +363,7 @@ export function func(input_types, output_type, body) {
346
363
  const ast = {
347
364
  ast_type: "Function",
348
365
  type: FunctionType(input_types, output_type),
349
- location: get_location(2),
366
+ location: get_location(),
350
367
  parameters: parameters,
351
368
  body: body_ast,
352
369
  };
@@ -357,7 +374,7 @@ export function asyncFunction(input_types, output_type, body) {
357
374
  const parameters = input_types.map(i => ({
358
375
  ast_type: "Variable",
359
376
  type: i,
360
- location: get_location(2),
377
+ location: get_location(),
361
378
  mutable: false,
362
379
  }));
363
380
  const $ = BlockBuilder(output_type ?? NeverType);
@@ -374,7 +391,7 @@ export function asyncFunction(input_types, output_type, body) {
374
391
  const ret_type = ret_ast.type;
375
392
  let body_ast;
376
393
  if (statements.length === 0) {
377
- body_ast = { ast_type: "Value", type: NullType, location: get_location(2), value: null };
394
+ body_ast = { ast_type: "Value", type: NullType, location: get_location(), value: null };
378
395
  }
379
396
  else if (statements.length === 1) {
380
397
  body_ast = statements[0];
@@ -383,7 +400,7 @@ export function asyncFunction(input_types, output_type, body) {
383
400
  body_ast = {
384
401
  ast_type: "Block",
385
402
  type: statements[statements.length - 1].type,
386
- location: get_location(2),
403
+ location: get_location(),
387
404
  statements: statements,
388
405
  };
389
406
  }
@@ -393,7 +410,7 @@ export function asyncFunction(input_types, output_type, body) {
393
410
  const ast = {
394
411
  ast_type: "AsyncFunction",
395
412
  type: AsyncFunctionType(input_types, ret_type),
396
- location: get_location(2),
413
+ location: get_location(),
397
414
  parameters: parameters,
398
415
  body: body_ast,
399
416
  };
@@ -408,7 +425,7 @@ export function asyncFunction(input_types, output_type, body) {
408
425
  }
409
426
  let body_ast;
410
427
  if (statements.length === 0) {
411
- body_ast = { ast_type: "Value", type: NullType, location: get_location(2), value: null };
428
+ body_ast = { ast_type: "Value", type: NullType, location: get_location(), value: null };
412
429
  }
413
430
  else if (statements.length === 1) {
414
431
  body_ast = statements[0];
@@ -417,7 +434,7 @@ export function asyncFunction(input_types, output_type, body) {
417
434
  body_ast = {
418
435
  ast_type: "Block",
419
436
  type: statements[statements.length - 1].type,
420
- location: get_location(2),
437
+ location: get_location(),
421
438
  statements: statements,
422
439
  };
423
440
  }
@@ -428,7 +445,7 @@ export function asyncFunction(input_types, output_type, body) {
428
445
  const ast = {
429
446
  ast_type: "AsyncFunction",
430
447
  type: AsyncFunctionType(input_types, output_type),
431
- location: get_location(2),
448
+ location: get_location(),
432
449
  parameters: parameters,
433
450
  body: body_ast,
434
451
  };
@@ -443,7 +460,7 @@ export function asyncFunction(input_types, output_type, body) {
443
460
  * ```
444
461
  */
445
462
  export function str(strings, ...expressions) {
446
- const location = get_location(2);
463
+ const location = get_location();
447
464
  // For simple strings, e.g: str`abc`
448
465
  if (strings.length === 1) {
449
466
  return fromAst({
@@ -559,7 +576,7 @@ export function str(strings, ...expressions) {
559
576
  let ret = {
560
577
  ast_type: "Value",
561
578
  type: StringType,
562
- location: get_location(2),
579
+ location: get_location(),
563
580
  value: strings[0],
564
581
  };
565
582
  for (let i = 1; i < strings.length; i++) {
@@ -654,7 +671,7 @@ export function block(body) {
654
671
  if (statements.length === 0) {
655
672
  return fromAst({
656
673
  ast_type: "Value",
657
- location: get_location(2),
674
+ location: get_location(),
658
675
  type: ret_type,
659
676
  value: null,
660
677
  });
@@ -665,7 +682,7 @@ export function block(body) {
665
682
  else {
666
683
  return fromAst({
667
684
  ast_type: "Block",
668
- location: get_location(2),
685
+ location: get_location(),
669
686
  type: ret_type,
670
687
  statements: statements,
671
688
  });
@@ -674,7 +691,7 @@ export function block(body) {
674
691
  /**
675
692
  * Create an East error expression
676
693
  */
677
- export function error(message, location = get_location(2)) {
694
+ export function error(message, location = get_location()) {
678
695
  const messageAst = message instanceof Expr ? Expr.ast(message) : valueOrExprToAstTyped(message, StringType);
679
696
  return fromAst({
680
697
  ast_type: "Error",
@@ -695,7 +712,7 @@ export function matchExpr(variant, handlers) {
695
712
  const data_variable = {
696
713
  ast_type: "Variable",
697
714
  type: t,
698
- location: get_location(2),
715
+ location: get_location(),
699
716
  mutable: false,
700
717
  };
701
718
  const ast = handler === undefined ? valueOrExprToAstTyped(null, NullType) : block($ => handler($, fromAst(data_variable)))[AstSymbol];
@@ -706,7 +723,7 @@ export function matchExpr(variant, handlers) {
706
723
  return fromAst({
707
724
  ast_type: "Match",
708
725
  type: out_type,
709
- location: get_location(2),
726
+ location: get_location(),
710
727
  variant: Expr.ast(variant),
711
728
  cases: cases_out,
712
729
  });
@@ -720,13 +737,13 @@ export function tryCatch(try_body, catch_body) {
720
737
  const message_variable = {
721
738
  ast_type: "Variable",
722
739
  type: StringType,
723
- location: get_location(2),
740
+ location: get_location(),
724
741
  mutable: false,
725
742
  };
726
743
  const stack_variable = {
727
744
  ast_type: "Variable",
728
745
  type: ArrayType(StructType({ filename: StringType, line: IntegerType, column: IntegerType })),
729
- location: get_location(2),
746
+ location: get_location(),
730
747
  mutable: false,
731
748
  };
732
749
  if (typeof catch_body !== "function") {
@@ -739,7 +756,7 @@ export function tryCatch(try_body, catch_body) {
739
756
  return fromAst({
740
757
  ast_type: "TryCatch",
741
758
  type: ret_type,
742
- location: get_location(2),
759
+ location: get_location(),
743
760
  try_body: Expr.ast(try_body),
744
761
  catch_body: catch_body_ast,
745
762
  message: message_variable,
@@ -752,7 +769,7 @@ export function equal(left, right) {
752
769
  return fromAst({
753
770
  ast_type: "Builtin",
754
771
  type: BooleanType,
755
- location: get_location(2),
772
+ location: get_location(),
756
773
  builtin: "Equal",
757
774
  type_parameters: [Expr.type(left)],
758
775
  arguments: [Expr.ast(left), rightAst],
@@ -764,7 +781,7 @@ export function notEqual(left, right) {
764
781
  return fromAst({
765
782
  ast_type: "Builtin",
766
783
  type: BooleanType,
767
- location: get_location(2),
784
+ location: get_location(),
768
785
  builtin: "NotEqual",
769
786
  type_parameters: [Expr.type(left)],
770
787
  arguments: [Expr.ast(left), rightAst],
@@ -776,7 +793,7 @@ export function less(left, right) {
776
793
  return fromAst({
777
794
  ast_type: "Builtin",
778
795
  type: BooleanType,
779
- location: get_location(2),
796
+ location: get_location(),
780
797
  builtin: "Less",
781
798
  type_parameters: [Expr.type(left)],
782
799
  arguments: [Expr.ast(left), rightAst],
@@ -788,7 +805,7 @@ export function lessEqual(left, right) {
788
805
  return fromAst({
789
806
  ast_type: "Builtin",
790
807
  type: BooleanType,
791
- location: get_location(2),
808
+ location: get_location(),
792
809
  builtin: "LessEqual",
793
810
  type_parameters: [Expr.type(left)],
794
811
  arguments: [Expr.ast(left), rightAst],
@@ -800,7 +817,7 @@ export function greater(left, right) {
800
817
  return fromAst({
801
818
  ast_type: "Builtin",
802
819
  type: BooleanType,
803
- location: get_location(2),
820
+ location: get_location(),
804
821
  builtin: "Greater",
805
822
  type_parameters: [Expr.type(left)],
806
823
  arguments: [Expr.ast(left), rightAst],
@@ -812,12 +829,43 @@ export function greaterEqual(left, right) {
812
829
  return fromAst({
813
830
  ast_type: "Builtin",
814
831
  type: BooleanType,
815
- location: get_location(2),
832
+ location: get_location(),
816
833
  builtin: "GreaterEqual",
817
834
  type_parameters: [Expr.type(left)],
818
835
  arguments: [Expr.ast(left), rightAst],
819
836
  });
820
837
  }
838
+ // ============================================================================
839
+ // Aliases for standalone comparison functions
840
+ // ============================================================================
841
+ /** Alias for {@link equal} */
842
+ export const equals = equal;
843
+ /** Alias for {@link equal} */
844
+ export const eq = equal;
845
+ /** Alias for {@link notEqual} */
846
+ export const notEquals = notEqual;
847
+ /** Alias for {@link notEqual} */
848
+ export const ne = notEqual;
849
+ /** Alias for {@link less} */
850
+ export const lessThan = less;
851
+ /** Alias for {@link less} */
852
+ export const lt = less;
853
+ /** Alias for {@link lessEqual} */
854
+ export const lessThanOrEqual = lessEqual;
855
+ /** Alias for {@link lessEqual} */
856
+ export const lte = lessEqual;
857
+ /** Alias for {@link lessEqual} */
858
+ export const le = lessEqual;
859
+ /** Alias for {@link greater} */
860
+ export const greaterThan = greater;
861
+ /** Alias for {@link greater} */
862
+ export const gt = greater;
863
+ /** Alias for {@link greaterEqual} */
864
+ export const greaterThanOrEqual = greaterEqual;
865
+ /** Alias for {@link greaterEqual} */
866
+ export const gte = greaterEqual;
867
+ /** Alias for {@link greaterEqual} */
868
+ export const ge = greaterEqual;
821
869
  /** Test if the first value is the same object the second.
822
870
  * For mutable collections, such as arrays, this means that they are the same object in memory.
823
871
  * For immutable data types, such as integers and strings, this is equivalent to equality.
@@ -827,7 +875,7 @@ export function is(left, right) {
827
875
  return fromAst({
828
876
  ast_type: "Builtin",
829
877
  type: BooleanType,
830
- location: get_location(2),
878
+ location: get_location(),
831
879
  builtin: "Is",
832
880
  type_parameters: [Expr.type(left)],
833
881
  arguments: [Expr.ast(left), rightAst],
@@ -839,12 +887,83 @@ export function print(value) {
839
887
  return fromAst({
840
888
  ast_type: "Builtin",
841
889
  type: StringType,
842
- location: get_location(2),
890
+ location: get_location(),
843
891
  builtin: "Print",
844
892
  type_parameters: [valueAst.type],
845
893
  arguments: [valueAst],
846
894
  });
847
895
  }
896
+ // ============================================================================
897
+ // Patch Operations
898
+ // ============================================================================
899
+ /** Compute the difference between two values of the same type.
900
+ * Returns a patch that, when applied to `before`, produces `after`.
901
+ */
902
+ export function diff(before, after) {
903
+ const beforeAst = Expr.ast(before);
904
+ const afterAst = Expr.ast(after);
905
+ const valueType = beforeAst.type;
906
+ const patchType = PatchType(valueType);
907
+ return fromAst({
908
+ ast_type: "Builtin",
909
+ type: patchType,
910
+ location: get_location(),
911
+ builtin: "Diff",
912
+ type_parameters: [valueType, patchType],
913
+ arguments: [beforeAst, afterAst],
914
+ });
915
+ }
916
+ /** Apply a patch to a value, producing the modified value.
917
+ * @throws East runtime error if the patch conflicts with the value (e.g., deleting a non-existent key)
918
+ */
919
+ export function applyPatch(value, patch) {
920
+ const valueAst = Expr.ast(value);
921
+ const patchAst = Expr.ast(patch);
922
+ const valueType = valueAst.type;
923
+ const patchType = patchAst.type;
924
+ return fromAst({
925
+ ast_type: "Builtin",
926
+ type: valueType,
927
+ location: get_location(),
928
+ builtin: "ApplyPatch",
929
+ type_parameters: [valueType, patchType],
930
+ arguments: [valueAst, patchAst],
931
+ });
932
+ }
933
+ /** Compose two patches into a single patch.
934
+ * The result is a patch that has the same effect as applying `first` then `second`.
935
+ * @throws East runtime error if the patches are incompatible (second expects different intermediate state)
936
+ */
937
+ export function composePatch(first, second, type) {
938
+ const firstAst = Expr.ast(first);
939
+ const secondAst = Expr.ast(second);
940
+ const valueType = type;
941
+ const patchType = PatchType(valueType);
942
+ return fromAst({
943
+ ast_type: "Builtin",
944
+ type: patchType,
945
+ location: get_location(),
946
+ builtin: "ComposePatch",
947
+ type_parameters: [valueType, patchType],
948
+ arguments: [firstAst, secondAst],
949
+ });
950
+ }
951
+ /** Invert a patch, producing a patch that undoes the original.
952
+ * Applying the inverted patch to the "after" value produces the "before" value.
953
+ */
954
+ export function invertPatch(patch, type) {
955
+ const patchAst = Expr.ast(patch);
956
+ const valueType = type;
957
+ const patchType = PatchType(valueType);
958
+ return fromAst({
959
+ ast_type: "Builtin",
960
+ type: patchType,
961
+ location: get_location(),
962
+ builtin: "InvertPatch",
963
+ type_parameters: [valueType, patchType],
964
+ arguments: [patchAst],
965
+ });
966
+ }
848
967
  /** Create a callable helper to invoke a synchronous platform function.
849
968
  *
850
969
  * Platform functions provide access to external capabilities (logging, I/O, database access, etc.)
@@ -853,6 +972,7 @@ export function print(value) {
853
972
  * @param name - The name of the platform function
854
973
  * @param input_types - Array of input parameter types for the platform function
855
974
  * @param output_type - The return type of the platform function
975
+ * @param options - Optional configuration for the platform function
856
976
  * @returns A callable function that creates Platform AST nodes when invoked
857
977
  *
858
978
  * @see {@link asyncPlatform} for defining asynchronous platform functions (that return `Promise`s)
@@ -870,13 +990,23 @@ const myFunction = East.function([], NullType, ($) => {
870
990
 
871
991
  // Provide the implementation when compiling
872
992
  const platform = [
873
- log.implement(false, (message: string) => console.log(message)),
993
+ log.implement((message: string) => console.log(message)),
874
994
  ];
875
995
  const compiled = myFunction.toIR().compile(platform);
876
996
  compiled(); // Logs "Hello, world!" to the console
997
+ * ```
998
+ *
999
+ * @example
1000
+ * ```ts
1001
+ // Define an optional platform function that may not be available
1002
+ const analytics = East.platform("analytics", [StringType], NullType, { optional: true });
1003
+
1004
+ // This compiles even without providing an analytics implementation
1005
+ // If called at runtime without implementation, it throws an error
877
1006
  * ```
878
1007
  */
879
- export function platform(name, input_types, output_type) {
1008
+ export function platform(name, input_types, output_type, options = {}) {
1009
+ const isOptional = options.optional ?? false;
880
1010
  const fn = (...args) => {
881
1011
  if (args.length !== input_types.length) {
882
1012
  throw new Error(`Platform function ${name} expected ${input_types.length} arguments, got ${args.length}`);
@@ -895,7 +1025,7 @@ export function platform(name, input_types, output_type) {
895
1025
  ast = {
896
1026
  ast_type: "As",
897
1027
  type: expectedType,
898
- location: get_location(2),
1028
+ location: get_location(),
899
1029
  value: ast,
900
1030
  };
901
1031
  }
@@ -904,10 +1034,12 @@ export function platform(name, input_types, output_type) {
904
1034
  return fromAst({
905
1035
  ast_type: "Platform",
906
1036
  type: output_type,
907
- location: get_location(2),
1037
+ location: get_location(),
908
1038
  name: name,
1039
+ type_parameters: [],
909
1040
  arguments: argAsts,
910
1041
  async: false,
1042
+ optional: isOptional,
911
1043
  });
912
1044
  };
913
1045
  fn.implement = (fnImpl) => {
@@ -943,6 +1075,7 @@ export function platform(name, input_types, output_type) {
943
1075
  * @param name - The name of the asynchronous platform function
944
1076
  * @param input_types - Array of input parameter types for the platform function
945
1077
  * @param output_type - The return type of the platform function
1078
+ * @param options - Optional configuration for the platform function
946
1079
  * @returns A callable function that creates Platform AST nodes when invoked
947
1080
  *
948
1081
  * @see {@link platform} for defining synchronous platform functions
@@ -962,10 +1095,11 @@ const platform = [
962
1095
  readFile.implement((filename: string) => fs.promises.readFile(filename, 'utf-8')),
963
1096
  ];
964
1097
  const compiled = myFunction.toIR().compile(platform);
965
- compiled(); // Logs "Hello, world!" to the console
1098
+ compiled(); // Returns file contents
966
1099
  * ```
967
1100
  */
968
- export function asyncPlatform(name, input_types, output_type) {
1101
+ export function asyncPlatform(name, input_types, output_type, options = {}) {
1102
+ const isOptional = options.optional ?? false;
969
1103
  const fn = (...args) => {
970
1104
  if (args.length !== input_types.length) {
971
1105
  throw new Error(`Platform function ${name} expected ${input_types.length} arguments, got ${args.length}`);
@@ -984,7 +1118,7 @@ export function asyncPlatform(name, input_types, output_type) {
984
1118
  ast = {
985
1119
  ast_type: "As",
986
1120
  type: expectedType,
987
- location: get_location(2),
1121
+ location: get_location(),
988
1122
  value: ast,
989
1123
  };
990
1124
  }
@@ -993,10 +1127,12 @@ export function asyncPlatform(name, input_types, output_type) {
993
1127
  return fromAst({
994
1128
  ast_type: "Platform",
995
1129
  type: output_type,
996
- location: get_location(2),
1130
+ location: get_location(),
997
1131
  name: name,
1132
+ type_parameters: [],
998
1133
  arguments: argAsts,
999
1134
  async: true,
1135
+ optional: isOptional,
1000
1136
  });
1001
1137
  };
1002
1138
  fn.implement = (fnImpl) => {
@@ -1024,12 +1160,356 @@ export function asyncPlatform(name, input_types, output_type) {
1024
1160
  };
1025
1161
  return fn;
1026
1162
  }
1163
+ // Runtime type substitution function
1164
+ function applyTypeArgs(typeArgs, t) {
1165
+ if (typeof t === 'string') {
1166
+ const ret = typeArgs[t];
1167
+ if (ret === undefined) {
1168
+ throw new Error(`Unexpected type argument ${t}`);
1169
+ }
1170
+ return ret;
1171
+ }
1172
+ else if (t.type === "Ref") {
1173
+ return { type: "Ref", value: applyTypeArgs(typeArgs, t.value) };
1174
+ }
1175
+ else if (t.type === "Array") {
1176
+ return { type: "Array", value: applyTypeArgs(typeArgs, t.value) };
1177
+ }
1178
+ else if (t.type === "Set") {
1179
+ return { type: "Set", key: applyTypeArgs(typeArgs, t.key) };
1180
+ }
1181
+ else if (t.type === "Dict") {
1182
+ return { type: "Dict", key: applyTypeArgs(typeArgs, t.key), value: applyTypeArgs(typeArgs, t.value) };
1183
+ }
1184
+ else if (t.type === "Struct") {
1185
+ const newFields = {};
1186
+ for (const k in t.fields) {
1187
+ newFields[k] = applyTypeArgs(typeArgs, t.fields[k]);
1188
+ }
1189
+ return { type: "Struct", fields: newFields };
1190
+ }
1191
+ else if (t.type === "Variant") {
1192
+ const newCases = {};
1193
+ for (const k in t.cases) {
1194
+ newCases[k] = applyTypeArgs(typeArgs, t.cases[k]);
1195
+ }
1196
+ return { type: "Variant", cases: newCases };
1197
+ }
1198
+ else if (t.type === "Function") {
1199
+ const newInputs = t.inputs.map((inputType) => applyTypeArgs(typeArgs, inputType));
1200
+ const newOutput = applyTypeArgs(typeArgs, t.output);
1201
+ return { type: "Function", inputs: newInputs, output: newOutput };
1202
+ }
1203
+ else if (t.type === "Recursive") {
1204
+ if (t.node === undefined) {
1205
+ // RecursiveTypeMarker (self-reference) - leave alone
1206
+ return t;
1207
+ }
1208
+ return { type: "Recursive", node: applyTypeArgs(typeArgs, t.node) };
1209
+ }
1210
+ else {
1211
+ return t;
1212
+ }
1213
+ }
1214
+ /** Create a callable helper to invoke a generic (polymorphic) platform function.
1215
+ *
1216
+ * Generic platform functions allow you to define platform functions with type parameters,
1217
+ * similar to how builtins work. The type parameters are passed at call time and flow
1218
+ * through to the implementation.
1219
+ *
1220
+ * @param name - The name of the platform function
1221
+ * @param typeParams - Array of type parameter names (e.g., `["T", "U"]`)
1222
+ * @param inputs - Array of input types, can contain string placeholders like `"T"`
1223
+ * @param output - Output type, can be a string placeholder like `"T"`
1224
+ * @returns A callable function that creates Platform AST nodes when invoked
1225
+ *
1226
+ * @example
1227
+ * ```ts
1228
+ * // Define a generic log function
1229
+ * const log = East.genericPlatform(
1230
+ * "log",
1231
+ * ["T"],
1232
+ * ["T"], // Input is type parameter T
1233
+ * NullType
1234
+ * );
1235
+ *
1236
+ * // Use it in East code - type args as array, then value args
1237
+ * const myFunction = East.function([StringType], NullType, ($, s) => {
1238
+ * $(log([StringType], s));
1239
+ * });
1240
+ *
1241
+ * // Implementation receives type params as a factory
1242
+ * const platform = [
1243
+ * log.implement((T) => (value) => {
1244
+ * console.log(printFor(T)(value));
1245
+ * return null;
1246
+ * }),
1247
+ * ];
1248
+ * ```
1249
+ *
1250
+ * @example
1251
+ * ```ts
1252
+ * // Define a generic map function with 2 type parameters
1253
+ * const map = East.genericPlatform(
1254
+ * "map",
1255
+ * ["T", "U"],
1256
+ * ["T", FunctionType(["T"], "U")], // String placeholders in nested types
1257
+ * "U"
1258
+ * );
1259
+ *
1260
+ * // Call with type args array, then value arguments
1261
+ * map([StringType, IntegerType], myString, myMapperFn)
1262
+ * ```
1263
+ */
1264
+ export function genericPlatform(name, typeParams, inputs, output, options = {}) {
1265
+ const numTypeParams = typeParams.length;
1266
+ const isOptional = options.optional ?? false;
1267
+ const fn = (type_args, ...valueArgs) => {
1268
+ // Validate type args array
1269
+ if (!Array.isArray(type_args)) {
1270
+ throw new Error(`Generic platform function '${name}' expects type arguments as an array, ` +
1271
+ `got ${typeof type_args}`);
1272
+ }
1273
+ // Validate type args count
1274
+ if (type_args.length !== numTypeParams) {
1275
+ throw new Error(`Generic platform function '${name}' expects ${numTypeParams} type parameters, ` +
1276
+ `got ${type_args.length}`);
1277
+ }
1278
+ // Validate type args are EastTypes
1279
+ for (let i = 0; i < numTypeParams; i++) {
1280
+ const typeArg = type_args[i];
1281
+ if (!typeArg || typeof typeArg !== 'object' || !('type' in typeArg)) {
1282
+ throw new Error(`Generic platform function '${name}' expects type parameter ${i + 1} ` +
1283
+ `(${typeParams[i]}) to be an EastType`);
1284
+ }
1285
+ }
1286
+ // Build type argument map
1287
+ const typeArgMap = {};
1288
+ typeParams.forEach((param, idx) => {
1289
+ typeArgMap[param] = type_args[idx];
1290
+ });
1291
+ // Apply type substitution to get concrete input/output types
1292
+ const inputTypes = inputs.map(t => applyTypeArgs(typeArgMap, t));
1293
+ const outputType = applyTypeArgs(typeArgMap, output);
1294
+ // Validate value args count
1295
+ if (valueArgs.length !== inputTypes.length) {
1296
+ throw new Error(`Generic platform function '${name}' expects ${inputTypes.length} ` +
1297
+ `value arguments, got ${valueArgs.length}`);
1298
+ }
1299
+ // Convert value args to AST with type validation and implicit casts
1300
+ const argAsts = valueArgs.map((arg, index) => {
1301
+ const expectedType = inputTypes[index];
1302
+ let ast = valueOrExprToAstTyped(arg, expectedType);
1303
+ if (ast.type.type === "Never") {
1304
+ throw new Error(`Generic platform function ${name} argument ${index + 1} expected type ${printType(expectedType)}, got Never type`);
1305
+ }
1306
+ if (!isTypeEqual(ast.type, expectedType)) {
1307
+ if (!isSubtype(ast.type, expectedType)) {
1308
+ throw new Error(`Generic platform function ${name} argument ${index + 1} expected type ${printType(expectedType)}, got ${printType(ast.type)}`);
1309
+ }
1310
+ // Insert implicit cast
1311
+ ast = {
1312
+ ast_type: "As",
1313
+ type: expectedType,
1314
+ location: get_location(),
1315
+ value: ast,
1316
+ };
1317
+ }
1318
+ return ast;
1319
+ });
1320
+ // Create PlatformAST with type_parameters
1321
+ return fromAst({
1322
+ ast_type: "Platform",
1323
+ type: outputType,
1324
+ location: get_location(),
1325
+ name: name,
1326
+ type_parameters: type_args,
1327
+ arguments: argAsts,
1328
+ async: false,
1329
+ optional: isOptional,
1330
+ });
1331
+ };
1332
+ fn.implement = (factory) => {
1333
+ return {
1334
+ name,
1335
+ type_parameters: [...typeParams],
1336
+ inputs: [], // Computed at call time via inputsFn
1337
+ output: toEastTypeValue(NullType), // Placeholder
1338
+ inputsFn: (...tps) => {
1339
+ const typeArgMap = {};
1340
+ typeParams.forEach((param, idx) => {
1341
+ typeArgMap[param] = tps[idx];
1342
+ });
1343
+ return inputs.map(t => {
1344
+ if (typeof t === 'string')
1345
+ return typeArgMap[t];
1346
+ let result = applyTypeArgs(typeArgMap, t);
1347
+ if (!isVariant(result))
1348
+ result = toEastTypeValue(result);
1349
+ return result;
1350
+ });
1351
+ },
1352
+ outputsFn: (...tps) => {
1353
+ const typeArgMap = {};
1354
+ typeParams.forEach((param, idx) => {
1355
+ typeArgMap[param] = tps[idx];
1356
+ });
1357
+ if (typeof output === 'string')
1358
+ return typeArgMap[output];
1359
+ let result = applyTypeArgs(typeArgMap, output);
1360
+ if (!isVariant(result))
1361
+ result = toEastTypeValue(result);
1362
+ return result;
1363
+ },
1364
+ type: 'sync',
1365
+ fn: factory,
1366
+ };
1367
+ };
1368
+ return fn;
1369
+ }
1370
+ /** Create a callable helper to invoke an asynchronous generic (polymorphic) platform function.
1371
+ *
1372
+ * This is the async variant of `genericPlatform`. The implementation factory should return
1373
+ * an async function.
1374
+ *
1375
+ * @param name - The name of the platform function
1376
+ * @param typeParams - Array of type parameter names (e.g., `["T", "U"]`)
1377
+ * @param inputs - Array of input types, can contain string placeholders like `"T"`
1378
+ * @param output - Output type, can be a string placeholder like `"T"`
1379
+ * @returns A callable function that creates Platform AST nodes when invoked
1380
+ *
1381
+ * @see {@link genericPlatform} for synchronous generic platform functions
1382
+ *
1383
+ * @example
1384
+ * ```ts
1385
+ * // Define an async generic fetch function
1386
+ * const fetchAs = East.asyncGenericPlatform(
1387
+ * "fetchAs",
1388
+ * ["T"],
1389
+ * [StringType], // URL input
1390
+ * "T" // Returns parsed value of type T
1391
+ * );
1392
+ *
1393
+ * // Implementation receives type params and returns async function
1394
+ * const platform = [
1395
+ * fetchAs.implement((T) => async (url) => {
1396
+ * const response = await fetch(url);
1397
+ * return parseFor(T)(await response.text());
1398
+ * }),
1399
+ * ];
1400
+ * ```
1401
+ */
1402
+ export function asyncGenericPlatform(name, typeParams, inputs, output, options = {}) {
1403
+ const numTypeParams = typeParams.length;
1404
+ const isOptional = options.optional ?? false;
1405
+ const fn = (type_args, ...valueArgs) => {
1406
+ // Validate type args array
1407
+ if (!Array.isArray(type_args)) {
1408
+ throw new Error(`Generic platform function '${name}' expects type arguments as an array, ` +
1409
+ `got ${typeof type_args}`);
1410
+ }
1411
+ // Validate type args count
1412
+ if (type_args.length !== numTypeParams) {
1413
+ throw new Error(`Generic platform function '${name}' expects ${numTypeParams} type parameters, ` +
1414
+ `got ${type_args.length}`);
1415
+ }
1416
+ // Validate type args are EastTypes
1417
+ for (let i = 0; i < numTypeParams; i++) {
1418
+ const typeArg = type_args[i];
1419
+ if (!typeArg || typeof typeArg !== 'object' || !('type' in typeArg)) {
1420
+ throw new Error(`Generic platform function '${name}' expects type parameter ${i + 1} ` +
1421
+ `(${typeParams[i]}) to be an EastType`);
1422
+ }
1423
+ }
1424
+ // Build type argument map
1425
+ const typeArgMap = {};
1426
+ typeParams.forEach((param, idx) => {
1427
+ typeArgMap[param] = type_args[idx];
1428
+ });
1429
+ // Apply type substitution to get concrete input/output types
1430
+ const inputTypes = inputs.map(t => applyTypeArgs(typeArgMap, t));
1431
+ const outputType = applyTypeArgs(typeArgMap, output);
1432
+ // Validate value args count
1433
+ if (valueArgs.length !== inputTypes.length) {
1434
+ throw new Error(`Generic platform function '${name}' expects ${inputTypes.length} ` +
1435
+ `value arguments, got ${valueArgs.length}`);
1436
+ }
1437
+ // Convert value args to AST with type validation and implicit casts
1438
+ const argAsts = valueArgs.map((arg, index) => {
1439
+ const expectedType = inputTypes[index];
1440
+ let ast = valueOrExprToAstTyped(arg, expectedType);
1441
+ if (ast.type.type === "Never") {
1442
+ throw new Error(`Generic platform function ${name} argument ${index + 1} expected type ${printType(expectedType)}, got Never type`);
1443
+ }
1444
+ if (!isTypeEqual(ast.type, expectedType)) {
1445
+ if (!isSubtype(ast.type, expectedType)) {
1446
+ throw new Error(`Generic platform function ${name} argument ${index + 1} expected type ${printType(expectedType)}, got ${printType(ast.type)}`);
1447
+ }
1448
+ // Insert implicit cast
1449
+ ast = {
1450
+ ast_type: "As",
1451
+ type: expectedType,
1452
+ location: get_location(),
1453
+ value: ast,
1454
+ };
1455
+ }
1456
+ return ast;
1457
+ });
1458
+ // Create PlatformAST with type_parameters and async: true
1459
+ return fromAst({
1460
+ ast_type: "Platform",
1461
+ type: outputType,
1462
+ location: get_location(),
1463
+ name: name,
1464
+ type_parameters: type_args,
1465
+ arguments: argAsts,
1466
+ async: true,
1467
+ optional: isOptional,
1468
+ });
1469
+ };
1470
+ fn.implement = (factory) => {
1471
+ return {
1472
+ name,
1473
+ type_parameters: [...typeParams],
1474
+ inputs: [], // Computed at call time via inputsFn
1475
+ output: toEastTypeValue(NullType), // Placeholder
1476
+ inputsFn: (...tps) => {
1477
+ const typeArgMap = {};
1478
+ typeParams.forEach((param, idx) => {
1479
+ typeArgMap[param] = tps[idx];
1480
+ });
1481
+ return inputs.map(t => {
1482
+ if (typeof t === 'string')
1483
+ return typeArgMap[t];
1484
+ let result = applyTypeArgs(typeArgMap, t);
1485
+ if (!isVariant(result))
1486
+ result = toEastTypeValue(result);
1487
+ return result;
1488
+ });
1489
+ },
1490
+ outputsFn: (...tps) => {
1491
+ const typeArgMap = {};
1492
+ typeParams.forEach((param, idx) => {
1493
+ typeArgMap[param] = tps[idx];
1494
+ });
1495
+ if (typeof output === 'string')
1496
+ return typeArgMap[output];
1497
+ let result = applyTypeArgs(typeArgMap, output);
1498
+ if (!isVariant(result))
1499
+ result = toEastTypeValue(result);
1500
+ return result;
1501
+ },
1502
+ type: 'async',
1503
+ fn: factory,
1504
+ };
1505
+ };
1506
+ return fn;
1507
+ }
1027
1508
  export const BlockBuilder = (return_type) => {
1028
1509
  const statements = [];
1029
1510
  const $ = ((expr) => {
1030
1511
  const ast = Expr.ast(expr);
1031
1512
  statements.push(ast);
1032
- return expr;
1033
1513
  });
1034
1514
  $.statements = statements;
1035
1515
  $.type = () => {
@@ -1042,7 +1522,7 @@ export const BlockBuilder = (return_type) => {
1042
1522
  };
1043
1523
  $.const = ((value, type) => {
1044
1524
  if (isTypeEqual($.type(), NeverType)) {
1045
- throw new Error(`Unreachable statement detected at ${printLocation(get_location(2))}`);
1525
+ throw new Error(`Unreachable statement detected at ${printLocations(get_location())}`);
1046
1526
  }
1047
1527
  let ast;
1048
1528
  if (value instanceof Expr) {
@@ -1057,13 +1537,13 @@ export const BlockBuilder = (return_type) => {
1057
1537
  const variable = {
1058
1538
  ast_type: "Variable",
1059
1539
  type: type ?? ast.type,
1060
- location: get_location(2),
1540
+ location: get_location(),
1061
1541
  mutable: false,
1062
1542
  };
1063
1543
  statements.push({
1064
1544
  ast_type: "Let",
1065
1545
  type: NullType,
1066
- location: get_location(2),
1546
+ location: get_location(),
1067
1547
  variable,
1068
1548
  value: ast,
1069
1549
  });
@@ -1071,7 +1551,7 @@ export const BlockBuilder = (return_type) => {
1071
1551
  });
1072
1552
  $.let = ((value, type) => {
1073
1553
  if (isTypeEqual($.type(), NeverType)) {
1074
- throw new Error(`Unreachable statement detected at ${printLocation(get_location(2))}`);
1554
+ throw new Error(`Unreachable statement detected at ${printLocations(get_location())}`);
1075
1555
  }
1076
1556
  let ast;
1077
1557
  if (value instanceof Expr) {
@@ -1086,13 +1566,13 @@ export const BlockBuilder = (return_type) => {
1086
1566
  const variable = {
1087
1567
  ast_type: "Variable",
1088
1568
  type: type ?? ast.type,
1089
- location: get_location(2),
1569
+ location: get_location(),
1090
1570
  mutable: true,
1091
1571
  };
1092
1572
  statements.push({
1093
1573
  ast_type: "Let",
1094
1574
  type: NullType,
1095
- location: get_location(2),
1575
+ location: get_location(),
1096
1576
  variable,
1097
1577
  value: ast,
1098
1578
  });
@@ -1100,7 +1580,7 @@ export const BlockBuilder = (return_type) => {
1100
1580
  });
1101
1581
  $.assign = ((variable, value) => {
1102
1582
  if (isTypeEqual($.type(), NeverType)) {
1103
- throw new Error(`Unreachable statement detected at ${printLocation(get_location(2))}`);
1583
+ throw new Error(`Unreachable statement detected at ${printLocations(get_location())}`);
1104
1584
  }
1105
1585
  let v = Expr.ast(variable);
1106
1586
  // Handle RecursiveType variables which are auto-unwrapped by fromAst
@@ -1111,13 +1591,13 @@ export const BlockBuilder = (return_type) => {
1111
1591
  throw new Error("Can only assign to a variable");
1112
1592
  }
1113
1593
  if (!v.mutable) {
1114
- throw new Error(`Cannot assign to variable defined at ${printLocation(v.location)} defined as const`);
1594
+ throw new Error(`Cannot assign to variable defined at ${printLocations(v.location)} defined as const`);
1115
1595
  }
1116
1596
  const ast_value = value instanceof Expr ? Expr.ast(value) : valueOrExprToAstTyped(value, v.type);
1117
1597
  const ast = {
1118
1598
  ast_type: "Assign",
1119
1599
  type: NullType,
1120
- location: get_location(2),
1600
+ location: get_location(),
1121
1601
  variable: v,
1122
1602
  value: ast_value,
1123
1603
  };
@@ -1127,16 +1607,22 @@ export const BlockBuilder = (return_type) => {
1127
1607
  // TODO if/when we introduce recursion, can we somehow get benefit from the typing?
1128
1608
  $.return = (expr) => {
1129
1609
  if (isTypeEqual($.type(), NeverType)) {
1130
- throw new Error(`Unreachable statement detected at ${printLocation(get_location(2))}`);
1610
+ throw new Error(`Unreachable statement detected at ${printLocations(get_location())}`);
1131
1611
  }
1132
1612
  const expAst = expr instanceof Expr ? Expr.ast(expr) : valueOrExprToAst(expr);
1133
1613
  if (!isSubtype(expAst.type, return_type)) {
1134
1614
  throw new Error(`Return expected to have type ${printType(return_type)}, got ${printType(expAst.type)}`);
1135
1615
  }
1616
+ // Deduplicate: if the expression is already the last statement (e.g., from $()),
1617
+ // don't push it again - just wrap it in the Return
1618
+ const exprAstRef = expr instanceof Expr ? Expr.ast(expr) : null;
1619
+ if (exprAstRef !== null && statements.length > 0 && statements[statements.length - 1] === exprAstRef) {
1620
+ statements.pop();
1621
+ }
1136
1622
  const ast = {
1137
1623
  ast_type: "Return",
1138
1624
  type: NeverType,
1139
- location: get_location(2),
1625
+ location: get_location(),
1140
1626
  value: expAst
1141
1627
  };
1142
1628
  statements.push(ast);
@@ -1144,12 +1630,12 @@ export const BlockBuilder = (return_type) => {
1144
1630
  };
1145
1631
  $.break = (label) => {
1146
1632
  if (isTypeEqual($.type(), NeverType)) {
1147
- throw new Error(`Unreachable statement detected at ${printLocation(get_location(2))}`);
1633
+ throw new Error(`Unreachable statement detected at ${printLocations(get_location())}`);
1148
1634
  }
1149
1635
  const ast = {
1150
1636
  ast_type: "Break",
1151
1637
  type: NeverType,
1152
- location: get_location(2),
1638
+ location: get_location(),
1153
1639
  label,
1154
1640
  };
1155
1641
  statements.push(ast);
@@ -1157,12 +1643,12 @@ export const BlockBuilder = (return_type) => {
1157
1643
  };
1158
1644
  $.continue = (label) => {
1159
1645
  if (isTypeEqual($.type(), NeverType)) {
1160
- throw new Error(`Unreachable statement detected at ${printLocation(get_location(2))}`);
1646
+ throw new Error(`Unreachable statement detected at ${printLocations(get_location())}`);
1161
1647
  }
1162
1648
  const ast = {
1163
1649
  ast_type: "Continue",
1164
1650
  type: NeverType,
1165
- location: get_location(2),
1651
+ location: get_location(),
1166
1652
  label,
1167
1653
  };
1168
1654
  statements.push(ast);
@@ -1170,7 +1656,7 @@ export const BlockBuilder = (return_type) => {
1170
1656
  };
1171
1657
  $.if = (predicate, true_branch) => {
1172
1658
  if (isTypeEqual($.type(), NeverType)) {
1173
- throw new Error(`Unreachable statement detected at ${printLocation(get_location(2))}`);
1659
+ throw new Error(`Unreachable statement detected at ${printLocations(get_location())}`);
1174
1660
  }
1175
1661
  const predicateAst = predicate instanceof Expr ? Expr.ast(predicate) : valueOrExprToAstTyped(predicate, BooleanType);
1176
1662
  if (predicateAst.type.type !== "Boolean") {
@@ -1188,38 +1674,38 @@ export const BlockBuilder = (return_type) => {
1188
1674
  }
1189
1675
  let true_ast;
1190
1676
  if (true_stmts.length === 0) {
1191
- true_ast = { ast_type: "Value", type: NullType, location: get_location(2), value: null };
1677
+ true_ast = { ast_type: "Value", type: NullType, location: get_location(), value: null };
1192
1678
  }
1193
1679
  else if (true_stmts.length === 1 && isSubtype(true_stmts[0].type, NullType)) {
1194
1680
  true_ast = true_stmts[0];
1195
1681
  }
1196
1682
  else {
1197
1683
  if (!isSubtype(true_stmts[true_stmts.length - 1].type, NullType)) {
1198
- true_stmts.push({ ast_type: "Value", type: NullType, location: get_location(2), value: null });
1684
+ true_stmts.push({ ast_type: "Value", type: NullType, location: get_location(), value: null });
1199
1685
  }
1200
1686
  true_ast = {
1201
1687
  ast_type: "Block",
1202
1688
  type: true_stmts[true_stmts.length - 1].type,
1203
- location: get_location(2),
1689
+ location: get_location(),
1204
1690
  statements: true_stmts,
1205
1691
  };
1206
1692
  }
1207
1693
  const if_else_ast = {
1208
1694
  ast_type: "IfElse",
1209
1695
  type: NullType,
1210
- location: get_location(2),
1696
+ location: get_location(),
1211
1697
  ifs: [{
1212
1698
  predicate: Expr.ast(predicate),
1213
1699
  body: true_ast,
1214
1700
  }],
1215
- else_body: { ast_type: "Value", type: NullType, location: get_location(2), value: null },
1701
+ else_body: { ast_type: "Value", type: NullType, location: get_location(), value: null },
1216
1702
  };
1217
1703
  statements.push(if_else_ast);
1218
1704
  return new IfElseExpr(if_else_ast, return_type);
1219
1705
  };
1220
1706
  $.match = (variant, cases) => {
1221
1707
  if (isTypeEqual($.type(), NeverType)) {
1222
- throw new Error(`Unreachable statement detected at ${printLocation(get_location(2))}`);
1708
+ throw new Error(`Unreachable statement detected at ${printLocations(get_location())}`);
1223
1709
  }
1224
1710
  if (Expr.type(variant).type !== "Variant") {
1225
1711
  throw new Error(`match not defined over ${printType(Expr.type(variant))}`);
@@ -1231,11 +1717,11 @@ export const BlockBuilder = (return_type) => {
1231
1717
  const data_variable = {
1232
1718
  ast_type: "Variable",
1233
1719
  type: t,
1234
- location: get_location(2),
1720
+ location: get_location(),
1235
1721
  mutable: false,
1236
1722
  };
1237
1723
  if (f === undefined) {
1238
- cases_out[k] = { variable: data_variable, body: { ast_type: "Value", type: NullType, location: get_location(2), value: null } };
1724
+ cases_out[k] = { variable: data_variable, body: { ast_type: "Value", type: NullType, location: get_location(), value: null } };
1239
1725
  }
1240
1726
  else {
1241
1727
  const data = fromAst(data_variable);
@@ -1250,19 +1736,19 @@ export const BlockBuilder = (return_type) => {
1250
1736
  }
1251
1737
  let expr;
1252
1738
  if (stmts.length === 0) {
1253
- expr = { ast_type: "Value", type: NullType, location: get_location(2), value: null };
1739
+ expr = { ast_type: "Value", type: NullType, location: get_location(), value: null };
1254
1740
  }
1255
1741
  else if (stmts.length === 1 && isSubtype(stmts[0].type, NullType)) {
1256
1742
  expr = stmts[0];
1257
1743
  }
1258
1744
  else {
1259
1745
  if (!isSubtype(stmts[stmts.length - 1].type, NullType)) {
1260
- stmts.push({ ast_type: "Value", type: NullType, location: get_location(2), value: null });
1746
+ stmts.push({ ast_type: "Value", type: NullType, location: get_location(), value: null });
1261
1747
  }
1262
1748
  expr = {
1263
1749
  ast_type: "Block",
1264
1750
  type: stmts[stmts.length - 1].type,
1265
- location: get_location(2),
1751
+ location: get_location(),
1266
1752
  statements: stmts,
1267
1753
  };
1268
1754
  }
@@ -1273,7 +1759,7 @@ export const BlockBuilder = (return_type) => {
1273
1759
  const ast = {
1274
1760
  ast_type: "Match",
1275
1761
  type: out_type,
1276
- location: get_location(2),
1762
+ location: get_location(),
1277
1763
  variant: Expr.ast(variant),
1278
1764
  cases: cases_out,
1279
1765
  };
@@ -1282,13 +1768,13 @@ export const BlockBuilder = (return_type) => {
1282
1768
  };
1283
1769
  $.while = (predicate, body) => {
1284
1770
  if (isTypeEqual($.type(), NeverType)) {
1285
- throw new Error(`Unreachable statement detected at ${printLocation(get_location(2))}`);
1771
+ throw new Error(`Unreachable statement detected at ${printLocations(get_location())}`);
1286
1772
  }
1287
1773
  const predicateAst = predicate instanceof Expr ? Expr.ast(predicate) : valueOrExprToAstTyped(predicate, BooleanType);
1288
1774
  if (predicateAst.type.type !== "Boolean") {
1289
1775
  throw new Error(`while predicate expected to have type Boolean, got ${printType(predicateAst.type)}`);
1290
1776
  }
1291
- const label = { location: get_location(2) };
1777
+ const label = { location: get_location() };
1292
1778
  const $_body = BlockBuilder(return_type);
1293
1779
  const ret = body($_body, label);
1294
1780
  const stmts = $_body.statements;
@@ -1300,19 +1786,19 @@ export const BlockBuilder = (return_type) => {
1300
1786
  }
1301
1787
  let expr;
1302
1788
  if (stmts.length === 0) {
1303
- expr = { ast_type: "Value", type: NullType, location: get_location(2), value: null };
1789
+ expr = { ast_type: "Value", type: NullType, location: get_location(), value: null };
1304
1790
  }
1305
1791
  else if (stmts.length === 1 && isSubtype(stmts[0].type, NullType)) {
1306
1792
  expr = stmts[0];
1307
1793
  }
1308
1794
  else {
1309
1795
  if (!isSubtype(stmts[stmts.length - 1].type, NullType)) {
1310
- stmts.push({ ast_type: "Value", type: NullType, location: get_location(2), value: null });
1796
+ stmts.push({ ast_type: "Value", type: NullType, location: get_location(), value: null });
1311
1797
  }
1312
1798
  expr = {
1313
1799
  ast_type: "Block",
1314
1800
  type: stmts[stmts.length - 1].type,
1315
- location: get_location(2),
1801
+ location: get_location(),
1316
1802
  statements: stmts,
1317
1803
  };
1318
1804
  }
@@ -1322,7 +1808,7 @@ export const BlockBuilder = (return_type) => {
1322
1808
  const ast = {
1323
1809
  ast_type: "While",
1324
1810
  type: NullType,
1325
- location: get_location(2),
1811
+ location: get_location(),
1326
1812
  predicate: predicateAst,
1327
1813
  label,
1328
1814
  body: expr,
@@ -1332,24 +1818,24 @@ export const BlockBuilder = (return_type) => {
1332
1818
  };
1333
1819
  $.for = ((collection, body) => {
1334
1820
  if (isTypeEqual($.type(), NeverType)) {
1335
- throw new Error(`Unreachable statement detected at ${printLocation(get_location(2))}`);
1821
+ throw new Error(`Unreachable statement detected at ${printLocations(get_location())}`);
1336
1822
  }
1337
1823
  if (collection instanceof ArrayExpr) {
1338
1824
  const value_variable = {
1339
1825
  ast_type: "Variable",
1340
1826
  type: Expr.type(collection).value,
1341
- location: get_location(2),
1827
+ location: get_location(),
1342
1828
  mutable: false,
1343
1829
  };
1344
1830
  const value = fromAst(value_variable);
1345
1831
  const key_variable = {
1346
1832
  ast_type: "Variable",
1347
1833
  type: IntegerType,
1348
- location: get_location(2),
1834
+ location: get_location(),
1349
1835
  mutable: false,
1350
1836
  };
1351
1837
  const key = fromAst(key_variable);
1352
- const label = { location: get_location(2) };
1838
+ const label = { location: get_location() };
1353
1839
  const $ = BlockBuilder(return_type);
1354
1840
  const ret = body($, value, key, label);
1355
1841
  const stmts = $.statements;
@@ -1361,26 +1847,26 @@ export const BlockBuilder = (return_type) => {
1361
1847
  }
1362
1848
  let expr;
1363
1849
  if (stmts.length === 0) {
1364
- expr = { ast_type: "Value", type: NullType, location: get_location(2), value: null };
1850
+ expr = { ast_type: "Value", type: NullType, location: get_location(), value: null };
1365
1851
  }
1366
1852
  else if (stmts.length === 1 && isSubtype(stmts[0].type, NullType)) {
1367
1853
  expr = stmts[0];
1368
1854
  }
1369
1855
  else {
1370
1856
  if (!isSubtype(stmts[stmts.length - 1].type, NullType)) {
1371
- stmts.push({ ast_type: "Value", type: NullType, location: get_location(2), value: null });
1857
+ stmts.push({ ast_type: "Value", type: NullType, location: get_location(), value: null });
1372
1858
  }
1373
1859
  expr = {
1374
1860
  ast_type: "Block",
1375
1861
  type: stmts[stmts.length - 1].type,
1376
- location: get_location(2),
1862
+ location: get_location(),
1377
1863
  statements: stmts,
1378
1864
  };
1379
1865
  }
1380
1866
  const ast = {
1381
1867
  ast_type: "ForArray",
1382
1868
  type: NullType,
1383
- location: get_location(2),
1869
+ location: get_location(),
1384
1870
  label,
1385
1871
  array: Expr.ast(collection),
1386
1872
  key: key_variable,
@@ -1394,11 +1880,11 @@ export const BlockBuilder = (return_type) => {
1394
1880
  const key_variable = {
1395
1881
  ast_type: "Variable",
1396
1882
  type: Expr.type(collection).key,
1397
- location: get_location(2),
1883
+ location: get_location(),
1398
1884
  mutable: false,
1399
1885
  };
1400
1886
  const key = fromAst(key_variable);
1401
- const label = { location: get_location(2) };
1887
+ const label = { location: get_location() };
1402
1888
  const $ = BlockBuilder(return_type);
1403
1889
  const ret = body($, key, label);
1404
1890
  const stmts = $.statements;
@@ -1410,26 +1896,26 @@ export const BlockBuilder = (return_type) => {
1410
1896
  }
1411
1897
  let expr;
1412
1898
  if (stmts.length === 0) {
1413
- expr = { ast_type: "Value", type: NullType, location: get_location(2), value: null };
1899
+ expr = { ast_type: "Value", type: NullType, location: get_location(), value: null };
1414
1900
  }
1415
1901
  else if (stmts.length === 1 && isSubtype(stmts[0].type, NullType)) {
1416
1902
  expr = stmts[0];
1417
1903
  }
1418
1904
  else {
1419
1905
  if (!isSubtype(stmts[stmts.length - 1].type, NullType)) {
1420
- stmts.push({ ast_type: "Value", type: NullType, location: get_location(2), value: null });
1906
+ stmts.push({ ast_type: "Value", type: NullType, location: get_location(), value: null });
1421
1907
  }
1422
1908
  expr = {
1423
1909
  ast_type: "Block",
1424
1910
  type: stmts[stmts.length - 1].type,
1425
- location: get_location(2),
1911
+ location: get_location(),
1426
1912
  statements: stmts,
1427
1913
  };
1428
1914
  }
1429
1915
  const ast = {
1430
1916
  ast_type: "ForSet",
1431
1917
  type: NullType,
1432
- location: get_location(2),
1918
+ location: get_location(),
1433
1919
  label,
1434
1920
  set: Expr.ast(collection),
1435
1921
  key: key_variable,
@@ -1442,18 +1928,18 @@ export const BlockBuilder = (return_type) => {
1442
1928
  const value_variable = {
1443
1929
  ast_type: "Variable",
1444
1930
  type: Expr.type(collection).value,
1445
- location: get_location(2),
1931
+ location: get_location(),
1446
1932
  mutable: false,
1447
1933
  };
1448
1934
  const value = fromAst(value_variable);
1449
1935
  const key_variable = {
1450
1936
  ast_type: "Variable",
1451
1937
  type: Expr.type(collection).key,
1452
- location: get_location(2),
1938
+ location: get_location(),
1453
1939
  mutable: false,
1454
1940
  };
1455
1941
  const key = fromAst(key_variable);
1456
- const label = { location: get_location(2) };
1942
+ const label = { location: get_location() };
1457
1943
  const $ = BlockBuilder(return_type);
1458
1944
  const ret = body($, value, key, label);
1459
1945
  const stmts = $.statements;
@@ -1465,26 +1951,26 @@ export const BlockBuilder = (return_type) => {
1465
1951
  }
1466
1952
  let expr;
1467
1953
  if (stmts.length === 0) {
1468
- expr = { ast_type: "Value", type: NullType, location: get_location(2), value: null };
1954
+ expr = { ast_type: "Value", type: NullType, location: get_location(), value: null };
1469
1955
  }
1470
1956
  else if (stmts.length === 1 && isSubtype(stmts[0].type, NullType)) {
1471
1957
  expr = stmts[0];
1472
1958
  }
1473
1959
  else {
1474
1960
  if (!isSubtype(stmts[stmts.length - 1].type, NullType)) {
1475
- stmts.push({ ast_type: "Value", type: NullType, location: get_location(2), value: null });
1961
+ stmts.push({ ast_type: "Value", type: NullType, location: get_location(), value: null });
1476
1962
  }
1477
1963
  expr = {
1478
1964
  ast_type: "Block",
1479
1965
  type: stmts[stmts.length - 1].type,
1480
- location: get_location(2),
1966
+ location: get_location(),
1481
1967
  statements: stmts,
1482
1968
  };
1483
1969
  }
1484
1970
  const ast = {
1485
1971
  ast_type: "ForDict",
1486
1972
  type: NullType,
1487
- location: get_location(2),
1973
+ location: get_location(),
1488
1974
  label,
1489
1975
  dict: Expr.ast(collection),
1490
1976
  key: key_variable,
@@ -1500,10 +1986,10 @@ export const BlockBuilder = (return_type) => {
1500
1986
  });
1501
1987
  $.error = (message, location) => {
1502
1988
  if (isTypeEqual($.type(), NeverType)) {
1503
- throw new Error(`Unreachable statement detected at ${printLocation(get_location(2))}`);
1989
+ throw new Error(`Unreachable statement detected at ${printLocations(get_location())}`);
1504
1990
  }
1505
1991
  if (location === undefined) {
1506
- location = get_location(2);
1992
+ location = get_location();
1507
1993
  }
1508
1994
  const ast = {
1509
1995
  ast_type: "Error",
@@ -1516,7 +2002,7 @@ export const BlockBuilder = (return_type) => {
1516
2002
  };
1517
2003
  $.try = (body) => {
1518
2004
  if (isTypeEqual($.type(), NeverType)) {
1519
- throw new Error(`Unreachable statement detected at ${printLocation(get_location(2))}`);
2005
+ throw new Error(`Unreachable statement detected at ${printLocations(get_location())}`);
1520
2006
  }
1521
2007
  const $try = BlockBuilder(return_type);
1522
2008
  const ret = body($try);
@@ -1528,7 +2014,7 @@ export const BlockBuilder = (return_type) => {
1528
2014
  }
1529
2015
  }
1530
2016
  if (try_stmts.length === 0 || !isSubtype(try_stmts[try_stmts.length - 1].type, NullType)) {
1531
- try_stmts.push({ ast_type: "Value", type: NullType, location: get_location(2), value: null });
2017
+ try_stmts.push({ ast_type: "Value", type: NullType, location: get_location(), value: null });
1532
2018
  }
1533
2019
  let try_expr;
1534
2020
  if (try_stmts.length === 1) {
@@ -1538,7 +2024,7 @@ export const BlockBuilder = (return_type) => {
1538
2024
  try_expr = {
1539
2025
  ast_type: "Block",
1540
2026
  type: try_stmts[try_stmts.length - 1].type,
1541
- location: get_location(2),
2027
+ location: get_location(),
1542
2028
  statements: try_stmts,
1543
2029
  };
1544
2030
  }
@@ -1546,21 +2032,21 @@ export const BlockBuilder = (return_type) => {
1546
2032
  const message_variable = {
1547
2033
  ast_type: "Variable",
1548
2034
  type: StringType,
1549
- location: get_location(2),
2035
+ location: get_location(),
1550
2036
  mutable: false,
1551
2037
  };
1552
2038
  const stack_variable = {
1553
2039
  ast_type: "Variable",
1554
2040
  type: ArrayType(StructType({ filename: StringType, line: IntegerType, column: IntegerType })),
1555
- location: get_location(2),
2041
+ location: get_location(),
1556
2042
  mutable: false,
1557
2043
  };
1558
2044
  const try_catch_ast = {
1559
2045
  ast_type: "TryCatch",
1560
2046
  type: NullType,
1561
- location: get_location(2),
2047
+ location: get_location(),
1562
2048
  try_body: try_expr,
1563
- catch_body: { ast_type: "Value", type: NullType, location: get_location(2), value: null }, // will be updated later
2049
+ catch_body: { ast_type: "Value", type: NullType, location: get_location(), value: null }, // will be updated later
1564
2050
  message: message_variable,
1565
2051
  stack: stack_variable,
1566
2052
  };
@@ -1591,12 +2077,12 @@ class IfElseExpr extends NullExpr {
1591
2077
  }
1592
2078
  }
1593
2079
  if (stmts.length === 0 || !isSubtype(stmts[stmts.length - 1].type, NullType)) {
1594
- stmts.push({ ast_type: "Value", type: NullType, location: get_location(2), value: null });
2080
+ stmts.push({ ast_type: "Value", type: NullType, location: get_location(), value: null });
1595
2081
  }
1596
2082
  this[AstSymbol].else_body = stmts.length === 1 ? stmts[0] : {
1597
2083
  ast_type: "Block",
1598
2084
  type: stmts[stmts.length - 1].type,
1599
- location: get_location(2),
2085
+ location: get_location(),
1600
2086
  statements: stmts,
1601
2087
  };
1602
2088
  // propagate unreachable information
@@ -1637,14 +2123,14 @@ class IfElseExpr extends NullExpr {
1637
2123
  }
1638
2124
  }
1639
2125
  if (stmts.length === 0 || !isSubtype(stmts[stmts.length - 1].type, NullType)) {
1640
- stmts.push({ ast_type: "Value", type: NullType, location: get_location(2), value: null });
2126
+ stmts.push({ ast_type: "Value", type: NullType, location: get_location(), value: null });
1641
2127
  }
1642
2128
  this[AstSymbol].ifs.push({
1643
2129
  predicate: Expr.ast(predicate),
1644
2130
  body: stmts.length === 1 ? stmts[0] : {
1645
2131
  ast_type: "Block",
1646
2132
  type: stmts[stmts.length - 1].type,
1647
- location: get_location(2),
2133
+ location: get_location(),
1648
2134
  statements: stmts,
1649
2135
  },
1650
2136
  });
@@ -1669,7 +2155,7 @@ class TryCatchExpr extends NullExpr {
1669
2155
  /** Define the logic to follow when an error is caught. The error message and stack trace is provided. */
1670
2156
  catch(body) {
1671
2157
  if (this.catchCalled) {
1672
- throw new Error(`Cannot call .catch() more than once on the same try block at ${printLocation(get_location(2))}`);
2158
+ throw new Error(`Cannot call .catch() more than once on the same try block at ${printLocations(get_location())}`);
1673
2159
  }
1674
2160
  this.catchCalled = true;
1675
2161
  const $ = BlockBuilder(this.return_type);
@@ -1682,12 +2168,12 @@ class TryCatchExpr extends NullExpr {
1682
2168
  }
1683
2169
  }
1684
2170
  if (stmts.length === 0 || !isSubtype(stmts[stmts.length - 1].type, NullType)) {
1685
- stmts.push({ ast_type: "Value", type: NullType, location: get_location(2), value: null });
2171
+ stmts.push({ ast_type: "Value", type: NullType, location: get_location(), value: null });
1686
2172
  }
1687
2173
  this[AstSymbol].catch_body = stmts.length === 1 ? stmts[0] : {
1688
2174
  ast_type: "Block",
1689
2175
  type: stmts[stmts.length - 1].type,
1690
- location: get_location(2),
2176
+ location: get_location(),
1691
2177
  statements: stmts,
1692
2178
  };
1693
2179
  // Propagate unreachable information
@@ -1708,12 +2194,12 @@ class TryCatchExpr extends NullExpr {
1708
2194
  }
1709
2195
  }
1710
2196
  if (stmts.length === 0 || !isSubtype(stmts[stmts.length - 1].type, NullType)) {
1711
- stmts.push({ ast_type: "Value", type: NullType, location: get_location(2), value: null });
2197
+ stmts.push({ ast_type: "Value", type: NullType, location: get_location(), value: null });
1712
2198
  }
1713
2199
  this[AstSymbol].finally_body = stmts.length === 1 ? stmts[0] : {
1714
2200
  ast_type: "Block",
1715
2201
  type: stmts[stmts.length - 1].type,
1716
- location: get_location(2),
2202
+ location: get_location(),
1717
2203
  statements: stmts,
1718
2204
  };
1719
2205
  }
@@ -1737,6 +2223,26 @@ Object.assign(Expr, {
1737
2223
  greater,
1738
2224
  greaterEqual,
1739
2225
  is,
1740
- match: matchExpr
2226
+ match: matchExpr,
2227
+ // Comparison aliases
2228
+ equals,
2229
+ eq,
2230
+ notEquals,
2231
+ ne,
2232
+ lessThan,
2233
+ lt,
2234
+ lessThanOrEqual,
2235
+ lte,
2236
+ le,
2237
+ greaterThan,
2238
+ gt,
2239
+ greaterThanOrEqual,
2240
+ gte,
2241
+ ge,
2242
+ // Patch operations
2243
+ diff,
2244
+ applyPatch,
2245
+ composePatch,
2246
+ invertPatch,
1741
2247
  });
1742
2248
  //# sourceMappingURL=block.js.map