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

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 (190) 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 +52 -13
  6. package/dist/src/analyze.js.map +1 -1
  7. package/dist/src/ast.d.ts +34 -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 +134 -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 +374 -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.map +1 -1
  26. package/dist/src/eastir.js +21 -5
  27. package/dist/src/eastir.js.map +1 -1
  28. package/dist/src/error.d.ts +12 -1
  29. package/dist/src/error.d.ts.map +1 -1
  30. package/dist/src/error.js +31 -1
  31. package/dist/src/error.js.map +1 -1
  32. package/dist/src/expr/array.d.ts +109 -1
  33. package/dist/src/expr/array.d.ts.map +1 -1
  34. package/dist/src/expr/array.js +204 -44
  35. package/dist/src/expr/array.js.map +1 -1
  36. package/dist/src/expr/ast.d.ts +1 -1
  37. package/dist/src/expr/ast.d.ts.map +1 -1
  38. package/dist/src/expr/ast.js +16 -28
  39. package/dist/src/expr/ast.js.map +1 -1
  40. package/dist/src/expr/asyncfunction.js +1 -1
  41. package/dist/src/expr/asyncfunction.js.map +1 -1
  42. package/dist/src/expr/blob.d.ts +73 -1
  43. package/dist/src/expr/blob.d.ts.map +1 -1
  44. package/dist/src/expr/blob.js +97 -7
  45. package/dist/src/expr/blob.js.map +1 -1
  46. package/dist/src/expr/block.d.ts +206 -8
  47. package/dist/src/expr/block.d.ts.map +1 -1
  48. package/dist/src/expr/block.js +623 -136
  49. package/dist/src/expr/block.js.map +1 -1
  50. package/dist/src/expr/boolean.d.ts +44 -0
  51. package/dist/src/expr/boolean.d.ts.map +1 -1
  52. package/dist/src/expr/boolean.js +57 -5
  53. package/dist/src/expr/boolean.js.map +1 -1
  54. package/dist/src/expr/datetime.d.ts +135 -0
  55. package/dist/src/expr/datetime.d.ts.map +1 -1
  56. package/dist/src/expr/datetime.js +183 -33
  57. package/dist/src/expr/datetime.js.map +1 -1
  58. package/dist/src/expr/dict.d.ts +42 -0
  59. package/dist/src/expr/dict.d.ts.map +1 -1
  60. package/dist/src/expr/dict.js +105 -55
  61. package/dist/src/expr/dict.js.map +1 -1
  62. package/dist/src/expr/expr.d.ts +1 -1
  63. package/dist/src/expr/expr.d.ts.map +1 -1
  64. package/dist/src/expr/expr.js.map +1 -1
  65. package/dist/src/expr/float.d.ts +153 -0
  66. package/dist/src/expr/float.d.ts.map +1 -1
  67. package/dist/src/expr/float.js +190 -16
  68. package/dist/src/expr/float.js.map +1 -1
  69. package/dist/src/expr/function.d.ts +7 -2
  70. package/dist/src/expr/function.d.ts.map +1 -1
  71. package/dist/src/expr/function.js +1 -1
  72. package/dist/src/expr/function.js.map +1 -1
  73. package/dist/src/expr/index.d.ts +202 -2
  74. package/dist/src/expr/index.d.ts.map +1 -1
  75. package/dist/src/expr/index.js +207 -2
  76. package/dist/src/expr/index.js.map +1 -1
  77. package/dist/src/expr/integer.d.ts +180 -0
  78. package/dist/src/expr/integer.d.ts.map +1 -1
  79. package/dist/src/expr/integer.js +188 -17
  80. package/dist/src/expr/integer.js.map +1 -1
  81. package/dist/src/expr/libs/blob.js +2 -2
  82. package/dist/src/expr/libs/blob.js.map +1 -1
  83. package/dist/src/expr/libs/integer.d.ts +19 -0
  84. package/dist/src/expr/libs/integer.d.ts.map +1 -1
  85. package/dist/src/expr/libs/integer.js +47 -0
  86. package/dist/src/expr/libs/integer.js.map +1 -1
  87. package/dist/src/expr/libs/string.js +1 -1
  88. package/dist/src/expr/libs/string.js.map +1 -1
  89. package/dist/src/expr/recursive.d.ts +83 -0
  90. package/dist/src/expr/recursive.d.ts.map +1 -0
  91. package/dist/src/expr/recursive.js +99 -0
  92. package/dist/src/expr/recursive.js.map +1 -0
  93. package/dist/src/expr/ref.js +3 -3
  94. package/dist/src/expr/ref.js.map +1 -1
  95. package/dist/src/expr/set.d.ts +44 -2
  96. package/dist/src/expr/set.d.ts.map +1 -1
  97. package/dist/src/expr/set.js +97 -47
  98. package/dist/src/expr/set.js.map +1 -1
  99. package/dist/src/expr/string.d.ts +134 -0
  100. package/dist/src/expr/string.d.ts.map +1 -1
  101. package/dist/src/expr/string.js +172 -22
  102. package/dist/src/expr/string.js.map +1 -1
  103. package/dist/src/expr/struct.d.ts +1 -1
  104. package/dist/src/expr/struct.d.ts.map +1 -1
  105. package/dist/src/expr/struct.js +1 -1
  106. package/dist/src/expr/struct.js.map +1 -1
  107. package/dist/src/expr/types.d.ts +7 -6
  108. package/dist/src/expr/types.d.ts.map +1 -1
  109. package/dist/src/expr/variant.d.ts +123 -1
  110. package/dist/src/expr/variant.d.ts.map +1 -1
  111. package/dist/src/expr/variant.js +66 -2
  112. package/dist/src/expr/variant.js.map +1 -1
  113. package/dist/src/fuzz.d.ts +36 -2
  114. package/dist/src/fuzz.d.ts.map +1 -1
  115. package/dist/src/fuzz.js +344 -77
  116. package/dist/src/fuzz.js.map +1 -1
  117. package/dist/src/index.d.ts +1 -0
  118. package/dist/src/index.d.ts.map +1 -1
  119. package/dist/src/index.js +1 -0
  120. package/dist/src/index.js.map +1 -1
  121. package/dist/src/internal.d.ts +12 -0
  122. package/dist/src/internal.d.ts.map +1 -1
  123. package/dist/src/internal.js +13 -0
  124. package/dist/src/internal.js.map +1 -1
  125. package/dist/src/ir.d.ts +1547 -1505
  126. package/dist/src/ir.d.ts.map +1 -1
  127. package/dist/src/ir.js +49 -34
  128. package/dist/src/ir.js.map +1 -1
  129. package/dist/src/location.d.ts +30 -10
  130. package/dist/src/location.d.ts.map +1 -1
  131. package/dist/src/location.js +70 -28
  132. package/dist/src/location.js.map +1 -1
  133. package/dist/src/patch/apply.d.ts +15 -0
  134. package/dist/src/patch/apply.d.ts.map +1 -0
  135. package/dist/src/patch/apply.js +380 -0
  136. package/dist/src/patch/apply.js.map +1 -0
  137. package/dist/src/patch/compose.d.ts +15 -0
  138. package/dist/src/patch/compose.d.ts.map +1 -0
  139. package/dist/src/patch/compose.js +480 -0
  140. package/dist/src/patch/compose.js.map +1 -0
  141. package/dist/src/patch/diff.d.ts +15 -0
  142. package/dist/src/patch/diff.d.ts.map +1 -0
  143. package/dist/src/patch/diff.js +328 -0
  144. package/dist/src/patch/diff.js.map +1 -0
  145. package/dist/src/patch/fuzz.d.ts +73 -0
  146. package/dist/src/patch/fuzz.d.ts.map +1 -0
  147. package/dist/src/patch/fuzz.js +159 -0
  148. package/dist/src/patch/fuzz.js.map +1 -0
  149. package/dist/src/patch/index.d.ts +18 -0
  150. package/dist/src/patch/index.d.ts.map +1 -0
  151. package/dist/src/patch/index.js +20 -0
  152. package/dist/src/patch/index.js.map +1 -0
  153. package/dist/src/patch/invert.d.ts +15 -0
  154. package/dist/src/patch/invert.d.ts.map +1 -0
  155. package/dist/src/patch/invert.js +302 -0
  156. package/dist/src/patch/invert.js.map +1 -0
  157. package/dist/src/patch/type_of_patch.d.ts +17 -0
  158. package/dist/src/patch/type_of_patch.d.ts.map +1 -0
  159. package/dist/src/patch/type_of_patch.js +143 -0
  160. package/dist/src/patch/type_of_patch.js.map +1 -0
  161. package/dist/src/patch/types.d.ts +166 -0
  162. package/dist/src/patch/types.d.ts.map +1 -0
  163. package/dist/src/patch/types.js +69 -0
  164. package/dist/src/patch/types.js.map +1 -0
  165. package/dist/src/platform.d.ts +6 -0
  166. package/dist/src/platform.d.ts.map +1 -1
  167. package/dist/src/serialization/beast.d.ts.map +1 -1
  168. package/dist/src/serialization/beast.js +53 -18
  169. package/dist/src/serialization/beast.js.map +1 -1
  170. package/dist/src/serialization/beast2.d.ts +39 -3
  171. package/dist/src/serialization/beast2.d.ts.map +1 -1
  172. package/dist/src/serialization/beast2.js +241 -18
  173. package/dist/src/serialization/beast2.js.map +1 -1
  174. package/dist/src/serialization/csv.d.ts +139 -0
  175. package/dist/src/serialization/csv.d.ts.map +1 -0
  176. package/dist/src/serialization/csv.js +615 -0
  177. package/dist/src/serialization/csv.js.map +1 -0
  178. package/dist/src/serialization/index.d.ts +2 -1
  179. package/dist/src/serialization/index.d.ts.map +1 -1
  180. package/dist/src/serialization/index.js +2 -1
  181. package/dist/src/serialization/index.js.map +1 -1
  182. package/dist/src/type_of_type.d.ts +45 -34
  183. package/dist/src/type_of_type.d.ts.map +1 -1
  184. package/dist/src/type_of_type.js +62 -1
  185. package/dist/src/type_of_type.js.map +1 -1
  186. package/dist/src/types.d.ts +8 -8
  187. package/dist/src/types.d.ts.map +1 -1
  188. package/dist/src/types.js +4 -4
  189. package/dist/src/types.js.map +1 -1
  190. 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.)
@@ -895,7 +1014,7 @@ export function platform(name, input_types, output_type) {
895
1014
  ast = {
896
1015
  ast_type: "As",
897
1016
  type: expectedType,
898
- location: get_location(2),
1017
+ location: get_location(),
899
1018
  value: ast,
900
1019
  };
901
1020
  }
@@ -904,8 +1023,9 @@ export function platform(name, input_types, output_type) {
904
1023
  return fromAst({
905
1024
  ast_type: "Platform",
906
1025
  type: output_type,
907
- location: get_location(2),
1026
+ location: get_location(),
908
1027
  name: name,
1028
+ type_parameters: [],
909
1029
  arguments: argAsts,
910
1030
  async: false,
911
1031
  });
@@ -984,7 +1104,7 @@ export function asyncPlatform(name, input_types, output_type) {
984
1104
  ast = {
985
1105
  ast_type: "As",
986
1106
  type: expectedType,
987
- location: get_location(2),
1107
+ location: get_location(),
988
1108
  value: ast,
989
1109
  };
990
1110
  }
@@ -993,8 +1113,9 @@ export function asyncPlatform(name, input_types, output_type) {
993
1113
  return fromAst({
994
1114
  ast_type: "Platform",
995
1115
  type: output_type,
996
- location: get_location(2),
1116
+ location: get_location(),
997
1117
  name: name,
1118
+ type_parameters: [],
998
1119
  arguments: argAsts,
999
1120
  async: true,
1000
1121
  });
@@ -1024,12 +1145,352 @@ export function asyncPlatform(name, input_types, output_type) {
1024
1145
  };
1025
1146
  return fn;
1026
1147
  }
1148
+ // Runtime type substitution function
1149
+ function applyTypeArgs(typeArgs, t) {
1150
+ if (typeof t === 'string') {
1151
+ const ret = typeArgs[t];
1152
+ if (ret === undefined) {
1153
+ throw new Error(`Unexpected type argument ${t}`);
1154
+ }
1155
+ return ret;
1156
+ }
1157
+ else if (t.type === "Ref") {
1158
+ return { type: "Ref", value: applyTypeArgs(typeArgs, t.value) };
1159
+ }
1160
+ else if (t.type === "Array") {
1161
+ return { type: "Array", value: applyTypeArgs(typeArgs, t.value) };
1162
+ }
1163
+ else if (t.type === "Set") {
1164
+ return { type: "Set", key: applyTypeArgs(typeArgs, t.key) };
1165
+ }
1166
+ else if (t.type === "Dict") {
1167
+ return { type: "Dict", key: applyTypeArgs(typeArgs, t.key), value: applyTypeArgs(typeArgs, t.value) };
1168
+ }
1169
+ else if (t.type === "Struct") {
1170
+ const newFields = {};
1171
+ for (const k in t.fields) {
1172
+ newFields[k] = applyTypeArgs(typeArgs, t.fields[k]);
1173
+ }
1174
+ return { type: "Struct", fields: newFields };
1175
+ }
1176
+ else if (t.type === "Variant") {
1177
+ const newCases = {};
1178
+ for (const k in t.cases) {
1179
+ newCases[k] = applyTypeArgs(typeArgs, t.cases[k]);
1180
+ }
1181
+ return { type: "Variant", cases: newCases };
1182
+ }
1183
+ else if (t.type === "Function") {
1184
+ const newInputs = t.inputs.map((inputType) => applyTypeArgs(typeArgs, inputType));
1185
+ const newOutput = applyTypeArgs(typeArgs, t.output);
1186
+ return { type: "Function", inputs: newInputs, output: newOutput };
1187
+ }
1188
+ else if (t.type === "Recursive") {
1189
+ if (t.node === undefined) {
1190
+ // RecursiveTypeMarker (self-reference) - leave alone
1191
+ return t;
1192
+ }
1193
+ return { type: "Recursive", node: applyTypeArgs(typeArgs, t.node) };
1194
+ }
1195
+ else {
1196
+ return t;
1197
+ }
1198
+ }
1199
+ /** Create a callable helper to invoke a generic (polymorphic) platform function.
1200
+ *
1201
+ * Generic platform functions allow you to define platform functions with type parameters,
1202
+ * similar to how builtins work. The type parameters are passed at call time and flow
1203
+ * through to the implementation.
1204
+ *
1205
+ * @param name - The name of the platform function
1206
+ * @param typeParams - Array of type parameter names (e.g., `["T", "U"]`)
1207
+ * @param inputs - Array of input types, can contain string placeholders like `"T"`
1208
+ * @param output - Output type, can be a string placeholder like `"T"`
1209
+ * @returns A callable function that creates Platform AST nodes when invoked
1210
+ *
1211
+ * @example
1212
+ * ```ts
1213
+ * // Define a generic log function
1214
+ * const log = East.genericPlatform(
1215
+ * "log",
1216
+ * ["T"],
1217
+ * ["T"], // Input is type parameter T
1218
+ * NullType
1219
+ * );
1220
+ *
1221
+ * // Use it in East code - type args as array, then value args
1222
+ * const myFunction = East.function([StringType], NullType, ($, s) => {
1223
+ * $(log([StringType], s));
1224
+ * });
1225
+ *
1226
+ * // Implementation receives type params as a factory
1227
+ * const platform = [
1228
+ * log.implement((T) => (value) => {
1229
+ * console.log(printFor(T)(value));
1230
+ * return null;
1231
+ * }),
1232
+ * ];
1233
+ * ```
1234
+ *
1235
+ * @example
1236
+ * ```ts
1237
+ * // Define a generic map function with 2 type parameters
1238
+ * const map = East.genericPlatform(
1239
+ * "map",
1240
+ * ["T", "U"],
1241
+ * ["T", FunctionType(["T"], "U")], // String placeholders in nested types
1242
+ * "U"
1243
+ * );
1244
+ *
1245
+ * // Call with type args array, then value arguments
1246
+ * map([StringType, IntegerType], myString, myMapperFn)
1247
+ * ```
1248
+ */
1249
+ export function genericPlatform(name, typeParams, inputs, output) {
1250
+ const numTypeParams = typeParams.length;
1251
+ const fn = (type_args, ...valueArgs) => {
1252
+ // Validate type args array
1253
+ if (!Array.isArray(type_args)) {
1254
+ throw new Error(`Generic platform function '${name}' expects type arguments as an array, ` +
1255
+ `got ${typeof type_args}`);
1256
+ }
1257
+ // Validate type args count
1258
+ if (type_args.length !== numTypeParams) {
1259
+ throw new Error(`Generic platform function '${name}' expects ${numTypeParams} type parameters, ` +
1260
+ `got ${type_args.length}`);
1261
+ }
1262
+ // Validate type args are EastTypes
1263
+ for (let i = 0; i < numTypeParams; i++) {
1264
+ const typeArg = type_args[i];
1265
+ if (!typeArg || typeof typeArg !== 'object' || !('type' in typeArg)) {
1266
+ throw new Error(`Generic platform function '${name}' expects type parameter ${i + 1} ` +
1267
+ `(${typeParams[i]}) to be an EastType`);
1268
+ }
1269
+ }
1270
+ // Build type argument map
1271
+ const typeArgMap = {};
1272
+ typeParams.forEach((param, idx) => {
1273
+ typeArgMap[param] = type_args[idx];
1274
+ });
1275
+ // Apply type substitution to get concrete input/output types
1276
+ const inputTypes = inputs.map(t => applyTypeArgs(typeArgMap, t));
1277
+ const outputType = applyTypeArgs(typeArgMap, output);
1278
+ // Validate value args count
1279
+ if (valueArgs.length !== inputTypes.length) {
1280
+ throw new Error(`Generic platform function '${name}' expects ${inputTypes.length} ` +
1281
+ `value arguments, got ${valueArgs.length}`);
1282
+ }
1283
+ // Convert value args to AST with type validation and implicit casts
1284
+ const argAsts = valueArgs.map((arg, index) => {
1285
+ const expectedType = inputTypes[index];
1286
+ let ast = valueOrExprToAstTyped(arg, expectedType);
1287
+ if (ast.type.type === "Never") {
1288
+ throw new Error(`Generic platform function ${name} argument ${index + 1} expected type ${printType(expectedType)}, got Never type`);
1289
+ }
1290
+ if (!isTypeEqual(ast.type, expectedType)) {
1291
+ if (!isSubtype(ast.type, expectedType)) {
1292
+ throw new Error(`Generic platform function ${name} argument ${index + 1} expected type ${printType(expectedType)}, got ${printType(ast.type)}`);
1293
+ }
1294
+ // Insert implicit cast
1295
+ ast = {
1296
+ ast_type: "As",
1297
+ type: expectedType,
1298
+ location: get_location(),
1299
+ value: ast,
1300
+ };
1301
+ }
1302
+ return ast;
1303
+ });
1304
+ // Create PlatformAST with type_parameters
1305
+ return fromAst({
1306
+ ast_type: "Platform",
1307
+ type: outputType,
1308
+ location: get_location(),
1309
+ name: name,
1310
+ type_parameters: type_args,
1311
+ arguments: argAsts,
1312
+ async: false,
1313
+ });
1314
+ };
1315
+ fn.implement = (factory) => {
1316
+ return {
1317
+ name,
1318
+ type_parameters: [...typeParams],
1319
+ inputs: [], // Computed at call time via inputsFn
1320
+ output: toEastTypeValue(NullType), // Placeholder
1321
+ inputsFn: (...tps) => {
1322
+ const typeArgMap = {};
1323
+ typeParams.forEach((param, idx) => {
1324
+ typeArgMap[param] = tps[idx];
1325
+ });
1326
+ return inputs.map(t => {
1327
+ if (typeof t === 'string')
1328
+ return typeArgMap[t];
1329
+ let result = applyTypeArgs(typeArgMap, t);
1330
+ if (!isVariant(result))
1331
+ result = toEastTypeValue(result);
1332
+ return result;
1333
+ });
1334
+ },
1335
+ outputsFn: (...tps) => {
1336
+ const typeArgMap = {};
1337
+ typeParams.forEach((param, idx) => {
1338
+ typeArgMap[param] = tps[idx];
1339
+ });
1340
+ if (typeof output === 'string')
1341
+ return typeArgMap[output];
1342
+ let result = applyTypeArgs(typeArgMap, output);
1343
+ if (!isVariant(result))
1344
+ result = toEastTypeValue(result);
1345
+ return result;
1346
+ },
1347
+ type: 'sync',
1348
+ fn: factory,
1349
+ };
1350
+ };
1351
+ return fn;
1352
+ }
1353
+ /** Create a callable helper to invoke an asynchronous generic (polymorphic) platform function.
1354
+ *
1355
+ * This is the async variant of `genericPlatform`. The implementation factory should return
1356
+ * an async function.
1357
+ *
1358
+ * @param name - The name of the platform function
1359
+ * @param typeParams - Array of type parameter names (e.g., `["T", "U"]`)
1360
+ * @param inputs - Array of input types, can contain string placeholders like `"T"`
1361
+ * @param output - Output type, can be a string placeholder like `"T"`
1362
+ * @returns A callable function that creates Platform AST nodes when invoked
1363
+ *
1364
+ * @see {@link genericPlatform} for synchronous generic platform functions
1365
+ *
1366
+ * @example
1367
+ * ```ts
1368
+ * // Define an async generic fetch function
1369
+ * const fetchAs = East.asyncGenericPlatform(
1370
+ * "fetchAs",
1371
+ * ["T"],
1372
+ * [StringType], // URL input
1373
+ * "T" // Returns parsed value of type T
1374
+ * );
1375
+ *
1376
+ * // Implementation receives type params and returns async function
1377
+ * const platform = [
1378
+ * fetchAs.implement((T) => async (url) => {
1379
+ * const response = await fetch(url);
1380
+ * return parseFor(T)(await response.text());
1381
+ * }),
1382
+ * ];
1383
+ * ```
1384
+ */
1385
+ export function asyncGenericPlatform(name, typeParams, inputs, output) {
1386
+ const numTypeParams = typeParams.length;
1387
+ const fn = (type_args, ...valueArgs) => {
1388
+ // Validate type args array
1389
+ if (!Array.isArray(type_args)) {
1390
+ throw new Error(`Generic platform function '${name}' expects type arguments as an array, ` +
1391
+ `got ${typeof type_args}`);
1392
+ }
1393
+ // Validate type args count
1394
+ if (type_args.length !== numTypeParams) {
1395
+ throw new Error(`Generic platform function '${name}' expects ${numTypeParams} type parameters, ` +
1396
+ `got ${type_args.length}`);
1397
+ }
1398
+ // Validate type args are EastTypes
1399
+ for (let i = 0; i < numTypeParams; i++) {
1400
+ const typeArg = type_args[i];
1401
+ if (!typeArg || typeof typeArg !== 'object' || !('type' in typeArg)) {
1402
+ throw new Error(`Generic platform function '${name}' expects type parameter ${i + 1} ` +
1403
+ `(${typeParams[i]}) to be an EastType`);
1404
+ }
1405
+ }
1406
+ // Build type argument map
1407
+ const typeArgMap = {};
1408
+ typeParams.forEach((param, idx) => {
1409
+ typeArgMap[param] = type_args[idx];
1410
+ });
1411
+ // Apply type substitution to get concrete input/output types
1412
+ const inputTypes = inputs.map(t => applyTypeArgs(typeArgMap, t));
1413
+ const outputType = applyTypeArgs(typeArgMap, output);
1414
+ // Validate value args count
1415
+ if (valueArgs.length !== inputTypes.length) {
1416
+ throw new Error(`Generic platform function '${name}' expects ${inputTypes.length} ` +
1417
+ `value arguments, got ${valueArgs.length}`);
1418
+ }
1419
+ // Convert value args to AST with type validation and implicit casts
1420
+ const argAsts = valueArgs.map((arg, index) => {
1421
+ const expectedType = inputTypes[index];
1422
+ let ast = valueOrExprToAstTyped(arg, expectedType);
1423
+ if (ast.type.type === "Never") {
1424
+ throw new Error(`Generic platform function ${name} argument ${index + 1} expected type ${printType(expectedType)}, got Never type`);
1425
+ }
1426
+ if (!isTypeEqual(ast.type, expectedType)) {
1427
+ if (!isSubtype(ast.type, expectedType)) {
1428
+ throw new Error(`Generic platform function ${name} argument ${index + 1} expected type ${printType(expectedType)}, got ${printType(ast.type)}`);
1429
+ }
1430
+ // Insert implicit cast
1431
+ ast = {
1432
+ ast_type: "As",
1433
+ type: expectedType,
1434
+ location: get_location(),
1435
+ value: ast,
1436
+ };
1437
+ }
1438
+ return ast;
1439
+ });
1440
+ // Create PlatformAST with type_parameters and async: true
1441
+ return fromAst({
1442
+ ast_type: "Platform",
1443
+ type: outputType,
1444
+ location: get_location(),
1445
+ name: name,
1446
+ type_parameters: type_args,
1447
+ arguments: argAsts,
1448
+ async: true,
1449
+ });
1450
+ };
1451
+ fn.implement = (factory) => {
1452
+ return {
1453
+ name,
1454
+ type_parameters: [...typeParams],
1455
+ inputs: [], // Computed at call time via inputsFn
1456
+ output: toEastTypeValue(NullType), // Placeholder
1457
+ inputsFn: (...tps) => {
1458
+ const typeArgMap = {};
1459
+ typeParams.forEach((param, idx) => {
1460
+ typeArgMap[param] = tps[idx];
1461
+ });
1462
+ return inputs.map(t => {
1463
+ if (typeof t === 'string')
1464
+ return typeArgMap[t];
1465
+ let result = applyTypeArgs(typeArgMap, t);
1466
+ if (!isVariant(result))
1467
+ result = toEastTypeValue(result);
1468
+ return result;
1469
+ });
1470
+ },
1471
+ outputsFn: (...tps) => {
1472
+ const typeArgMap = {};
1473
+ typeParams.forEach((param, idx) => {
1474
+ typeArgMap[param] = tps[idx];
1475
+ });
1476
+ if (typeof output === 'string')
1477
+ return typeArgMap[output];
1478
+ let result = applyTypeArgs(typeArgMap, output);
1479
+ if (!isVariant(result))
1480
+ result = toEastTypeValue(result);
1481
+ return result;
1482
+ },
1483
+ type: 'async',
1484
+ fn: factory,
1485
+ };
1486
+ };
1487
+ return fn;
1488
+ }
1027
1489
  export const BlockBuilder = (return_type) => {
1028
1490
  const statements = [];
1029
1491
  const $ = ((expr) => {
1030
1492
  const ast = Expr.ast(expr);
1031
1493
  statements.push(ast);
1032
- return expr;
1033
1494
  });
1034
1495
  $.statements = statements;
1035
1496
  $.type = () => {
@@ -1042,7 +1503,7 @@ export const BlockBuilder = (return_type) => {
1042
1503
  };
1043
1504
  $.const = ((value, type) => {
1044
1505
  if (isTypeEqual($.type(), NeverType)) {
1045
- throw new Error(`Unreachable statement detected at ${printLocation(get_location(2))}`);
1506
+ throw new Error(`Unreachable statement detected at ${printLocations(get_location())}`);
1046
1507
  }
1047
1508
  let ast;
1048
1509
  if (value instanceof Expr) {
@@ -1057,13 +1518,13 @@ export const BlockBuilder = (return_type) => {
1057
1518
  const variable = {
1058
1519
  ast_type: "Variable",
1059
1520
  type: type ?? ast.type,
1060
- location: get_location(2),
1521
+ location: get_location(),
1061
1522
  mutable: false,
1062
1523
  };
1063
1524
  statements.push({
1064
1525
  ast_type: "Let",
1065
1526
  type: NullType,
1066
- location: get_location(2),
1527
+ location: get_location(),
1067
1528
  variable,
1068
1529
  value: ast,
1069
1530
  });
@@ -1071,7 +1532,7 @@ export const BlockBuilder = (return_type) => {
1071
1532
  });
1072
1533
  $.let = ((value, type) => {
1073
1534
  if (isTypeEqual($.type(), NeverType)) {
1074
- throw new Error(`Unreachable statement detected at ${printLocation(get_location(2))}`);
1535
+ throw new Error(`Unreachable statement detected at ${printLocations(get_location())}`);
1075
1536
  }
1076
1537
  let ast;
1077
1538
  if (value instanceof Expr) {
@@ -1086,13 +1547,13 @@ export const BlockBuilder = (return_type) => {
1086
1547
  const variable = {
1087
1548
  ast_type: "Variable",
1088
1549
  type: type ?? ast.type,
1089
- location: get_location(2),
1550
+ location: get_location(),
1090
1551
  mutable: true,
1091
1552
  };
1092
1553
  statements.push({
1093
1554
  ast_type: "Let",
1094
1555
  type: NullType,
1095
- location: get_location(2),
1556
+ location: get_location(),
1096
1557
  variable,
1097
1558
  value: ast,
1098
1559
  });
@@ -1100,7 +1561,7 @@ export const BlockBuilder = (return_type) => {
1100
1561
  });
1101
1562
  $.assign = ((variable, value) => {
1102
1563
  if (isTypeEqual($.type(), NeverType)) {
1103
- throw new Error(`Unreachable statement detected at ${printLocation(get_location(2))}`);
1564
+ throw new Error(`Unreachable statement detected at ${printLocations(get_location())}`);
1104
1565
  }
1105
1566
  let v = Expr.ast(variable);
1106
1567
  // Handle RecursiveType variables which are auto-unwrapped by fromAst
@@ -1111,13 +1572,13 @@ export const BlockBuilder = (return_type) => {
1111
1572
  throw new Error("Can only assign to a variable");
1112
1573
  }
1113
1574
  if (!v.mutable) {
1114
- throw new Error(`Cannot assign to variable defined at ${printLocation(v.location)} defined as const`);
1575
+ throw new Error(`Cannot assign to variable defined at ${printLocations(v.location)} defined as const`);
1115
1576
  }
1116
1577
  const ast_value = value instanceof Expr ? Expr.ast(value) : valueOrExprToAstTyped(value, v.type);
1117
1578
  const ast = {
1118
1579
  ast_type: "Assign",
1119
1580
  type: NullType,
1120
- location: get_location(2),
1581
+ location: get_location(),
1121
1582
  variable: v,
1122
1583
  value: ast_value,
1123
1584
  };
@@ -1127,16 +1588,22 @@ export const BlockBuilder = (return_type) => {
1127
1588
  // TODO if/when we introduce recursion, can we somehow get benefit from the typing?
1128
1589
  $.return = (expr) => {
1129
1590
  if (isTypeEqual($.type(), NeverType)) {
1130
- throw new Error(`Unreachable statement detected at ${printLocation(get_location(2))}`);
1591
+ throw new Error(`Unreachable statement detected at ${printLocations(get_location())}`);
1131
1592
  }
1132
1593
  const expAst = expr instanceof Expr ? Expr.ast(expr) : valueOrExprToAst(expr);
1133
1594
  if (!isSubtype(expAst.type, return_type)) {
1134
1595
  throw new Error(`Return expected to have type ${printType(return_type)}, got ${printType(expAst.type)}`);
1135
1596
  }
1597
+ // Deduplicate: if the expression is already the last statement (e.g., from $()),
1598
+ // don't push it again - just wrap it in the Return
1599
+ const exprAstRef = expr instanceof Expr ? Expr.ast(expr) : null;
1600
+ if (exprAstRef !== null && statements.length > 0 && statements[statements.length - 1] === exprAstRef) {
1601
+ statements.pop();
1602
+ }
1136
1603
  const ast = {
1137
1604
  ast_type: "Return",
1138
1605
  type: NeverType,
1139
- location: get_location(2),
1606
+ location: get_location(),
1140
1607
  value: expAst
1141
1608
  };
1142
1609
  statements.push(ast);
@@ -1144,12 +1611,12 @@ export const BlockBuilder = (return_type) => {
1144
1611
  };
1145
1612
  $.break = (label) => {
1146
1613
  if (isTypeEqual($.type(), NeverType)) {
1147
- throw new Error(`Unreachable statement detected at ${printLocation(get_location(2))}`);
1614
+ throw new Error(`Unreachable statement detected at ${printLocations(get_location())}`);
1148
1615
  }
1149
1616
  const ast = {
1150
1617
  ast_type: "Break",
1151
1618
  type: NeverType,
1152
- location: get_location(2),
1619
+ location: get_location(),
1153
1620
  label,
1154
1621
  };
1155
1622
  statements.push(ast);
@@ -1157,12 +1624,12 @@ export const BlockBuilder = (return_type) => {
1157
1624
  };
1158
1625
  $.continue = (label) => {
1159
1626
  if (isTypeEqual($.type(), NeverType)) {
1160
- throw new Error(`Unreachable statement detected at ${printLocation(get_location(2))}`);
1627
+ throw new Error(`Unreachable statement detected at ${printLocations(get_location())}`);
1161
1628
  }
1162
1629
  const ast = {
1163
1630
  ast_type: "Continue",
1164
1631
  type: NeverType,
1165
- location: get_location(2),
1632
+ location: get_location(),
1166
1633
  label,
1167
1634
  };
1168
1635
  statements.push(ast);
@@ -1170,7 +1637,7 @@ export const BlockBuilder = (return_type) => {
1170
1637
  };
1171
1638
  $.if = (predicate, true_branch) => {
1172
1639
  if (isTypeEqual($.type(), NeverType)) {
1173
- throw new Error(`Unreachable statement detected at ${printLocation(get_location(2))}`);
1640
+ throw new Error(`Unreachable statement detected at ${printLocations(get_location())}`);
1174
1641
  }
1175
1642
  const predicateAst = predicate instanceof Expr ? Expr.ast(predicate) : valueOrExprToAstTyped(predicate, BooleanType);
1176
1643
  if (predicateAst.type.type !== "Boolean") {
@@ -1188,38 +1655,38 @@ export const BlockBuilder = (return_type) => {
1188
1655
  }
1189
1656
  let true_ast;
1190
1657
  if (true_stmts.length === 0) {
1191
- true_ast = { ast_type: "Value", type: NullType, location: get_location(2), value: null };
1658
+ true_ast = { ast_type: "Value", type: NullType, location: get_location(), value: null };
1192
1659
  }
1193
1660
  else if (true_stmts.length === 1 && isSubtype(true_stmts[0].type, NullType)) {
1194
1661
  true_ast = true_stmts[0];
1195
1662
  }
1196
1663
  else {
1197
1664
  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 });
1665
+ true_stmts.push({ ast_type: "Value", type: NullType, location: get_location(), value: null });
1199
1666
  }
1200
1667
  true_ast = {
1201
1668
  ast_type: "Block",
1202
1669
  type: true_stmts[true_stmts.length - 1].type,
1203
- location: get_location(2),
1670
+ location: get_location(),
1204
1671
  statements: true_stmts,
1205
1672
  };
1206
1673
  }
1207
1674
  const if_else_ast = {
1208
1675
  ast_type: "IfElse",
1209
1676
  type: NullType,
1210
- location: get_location(2),
1677
+ location: get_location(),
1211
1678
  ifs: [{
1212
1679
  predicate: Expr.ast(predicate),
1213
1680
  body: true_ast,
1214
1681
  }],
1215
- else_body: { ast_type: "Value", type: NullType, location: get_location(2), value: null },
1682
+ else_body: { ast_type: "Value", type: NullType, location: get_location(), value: null },
1216
1683
  };
1217
1684
  statements.push(if_else_ast);
1218
1685
  return new IfElseExpr(if_else_ast, return_type);
1219
1686
  };
1220
1687
  $.match = (variant, cases) => {
1221
1688
  if (isTypeEqual($.type(), NeverType)) {
1222
- throw new Error(`Unreachable statement detected at ${printLocation(get_location(2))}`);
1689
+ throw new Error(`Unreachable statement detected at ${printLocations(get_location())}`);
1223
1690
  }
1224
1691
  if (Expr.type(variant).type !== "Variant") {
1225
1692
  throw new Error(`match not defined over ${printType(Expr.type(variant))}`);
@@ -1231,11 +1698,11 @@ export const BlockBuilder = (return_type) => {
1231
1698
  const data_variable = {
1232
1699
  ast_type: "Variable",
1233
1700
  type: t,
1234
- location: get_location(2),
1701
+ location: get_location(),
1235
1702
  mutable: false,
1236
1703
  };
1237
1704
  if (f === undefined) {
1238
- cases_out[k] = { variable: data_variable, body: { ast_type: "Value", type: NullType, location: get_location(2), value: null } };
1705
+ cases_out[k] = { variable: data_variable, body: { ast_type: "Value", type: NullType, location: get_location(), value: null } };
1239
1706
  }
1240
1707
  else {
1241
1708
  const data = fromAst(data_variable);
@@ -1250,19 +1717,19 @@ export const BlockBuilder = (return_type) => {
1250
1717
  }
1251
1718
  let expr;
1252
1719
  if (stmts.length === 0) {
1253
- expr = { ast_type: "Value", type: NullType, location: get_location(2), value: null };
1720
+ expr = { ast_type: "Value", type: NullType, location: get_location(), value: null };
1254
1721
  }
1255
1722
  else if (stmts.length === 1 && isSubtype(stmts[0].type, NullType)) {
1256
1723
  expr = stmts[0];
1257
1724
  }
1258
1725
  else {
1259
1726
  if (!isSubtype(stmts[stmts.length - 1].type, NullType)) {
1260
- stmts.push({ ast_type: "Value", type: NullType, location: get_location(2), value: null });
1727
+ stmts.push({ ast_type: "Value", type: NullType, location: get_location(), value: null });
1261
1728
  }
1262
1729
  expr = {
1263
1730
  ast_type: "Block",
1264
1731
  type: stmts[stmts.length - 1].type,
1265
- location: get_location(2),
1732
+ location: get_location(),
1266
1733
  statements: stmts,
1267
1734
  };
1268
1735
  }
@@ -1273,7 +1740,7 @@ export const BlockBuilder = (return_type) => {
1273
1740
  const ast = {
1274
1741
  ast_type: "Match",
1275
1742
  type: out_type,
1276
- location: get_location(2),
1743
+ location: get_location(),
1277
1744
  variant: Expr.ast(variant),
1278
1745
  cases: cases_out,
1279
1746
  };
@@ -1282,13 +1749,13 @@ export const BlockBuilder = (return_type) => {
1282
1749
  };
1283
1750
  $.while = (predicate, body) => {
1284
1751
  if (isTypeEqual($.type(), NeverType)) {
1285
- throw new Error(`Unreachable statement detected at ${printLocation(get_location(2))}`);
1752
+ throw new Error(`Unreachable statement detected at ${printLocations(get_location())}`);
1286
1753
  }
1287
1754
  const predicateAst = predicate instanceof Expr ? Expr.ast(predicate) : valueOrExprToAstTyped(predicate, BooleanType);
1288
1755
  if (predicateAst.type.type !== "Boolean") {
1289
1756
  throw new Error(`while predicate expected to have type Boolean, got ${printType(predicateAst.type)}`);
1290
1757
  }
1291
- const label = { location: get_location(2) };
1758
+ const label = { location: get_location() };
1292
1759
  const $_body = BlockBuilder(return_type);
1293
1760
  const ret = body($_body, label);
1294
1761
  const stmts = $_body.statements;
@@ -1300,19 +1767,19 @@ export const BlockBuilder = (return_type) => {
1300
1767
  }
1301
1768
  let expr;
1302
1769
  if (stmts.length === 0) {
1303
- expr = { ast_type: "Value", type: NullType, location: get_location(2), value: null };
1770
+ expr = { ast_type: "Value", type: NullType, location: get_location(), value: null };
1304
1771
  }
1305
1772
  else if (stmts.length === 1 && isSubtype(stmts[0].type, NullType)) {
1306
1773
  expr = stmts[0];
1307
1774
  }
1308
1775
  else {
1309
1776
  if (!isSubtype(stmts[stmts.length - 1].type, NullType)) {
1310
- stmts.push({ ast_type: "Value", type: NullType, location: get_location(2), value: null });
1777
+ stmts.push({ ast_type: "Value", type: NullType, location: get_location(), value: null });
1311
1778
  }
1312
1779
  expr = {
1313
1780
  ast_type: "Block",
1314
1781
  type: stmts[stmts.length - 1].type,
1315
- location: get_location(2),
1782
+ location: get_location(),
1316
1783
  statements: stmts,
1317
1784
  };
1318
1785
  }
@@ -1322,7 +1789,7 @@ export const BlockBuilder = (return_type) => {
1322
1789
  const ast = {
1323
1790
  ast_type: "While",
1324
1791
  type: NullType,
1325
- location: get_location(2),
1792
+ location: get_location(),
1326
1793
  predicate: predicateAst,
1327
1794
  label,
1328
1795
  body: expr,
@@ -1332,24 +1799,24 @@ export const BlockBuilder = (return_type) => {
1332
1799
  };
1333
1800
  $.for = ((collection, body) => {
1334
1801
  if (isTypeEqual($.type(), NeverType)) {
1335
- throw new Error(`Unreachable statement detected at ${printLocation(get_location(2))}`);
1802
+ throw new Error(`Unreachable statement detected at ${printLocations(get_location())}`);
1336
1803
  }
1337
1804
  if (collection instanceof ArrayExpr) {
1338
1805
  const value_variable = {
1339
1806
  ast_type: "Variable",
1340
1807
  type: Expr.type(collection).value,
1341
- location: get_location(2),
1808
+ location: get_location(),
1342
1809
  mutable: false,
1343
1810
  };
1344
1811
  const value = fromAst(value_variable);
1345
1812
  const key_variable = {
1346
1813
  ast_type: "Variable",
1347
1814
  type: IntegerType,
1348
- location: get_location(2),
1815
+ location: get_location(),
1349
1816
  mutable: false,
1350
1817
  };
1351
1818
  const key = fromAst(key_variable);
1352
- const label = { location: get_location(2) };
1819
+ const label = { location: get_location() };
1353
1820
  const $ = BlockBuilder(return_type);
1354
1821
  const ret = body($, value, key, label);
1355
1822
  const stmts = $.statements;
@@ -1361,26 +1828,26 @@ export const BlockBuilder = (return_type) => {
1361
1828
  }
1362
1829
  let expr;
1363
1830
  if (stmts.length === 0) {
1364
- expr = { ast_type: "Value", type: NullType, location: get_location(2), value: null };
1831
+ expr = { ast_type: "Value", type: NullType, location: get_location(), value: null };
1365
1832
  }
1366
1833
  else if (stmts.length === 1 && isSubtype(stmts[0].type, NullType)) {
1367
1834
  expr = stmts[0];
1368
1835
  }
1369
1836
  else {
1370
1837
  if (!isSubtype(stmts[stmts.length - 1].type, NullType)) {
1371
- stmts.push({ ast_type: "Value", type: NullType, location: get_location(2), value: null });
1838
+ stmts.push({ ast_type: "Value", type: NullType, location: get_location(), value: null });
1372
1839
  }
1373
1840
  expr = {
1374
1841
  ast_type: "Block",
1375
1842
  type: stmts[stmts.length - 1].type,
1376
- location: get_location(2),
1843
+ location: get_location(),
1377
1844
  statements: stmts,
1378
1845
  };
1379
1846
  }
1380
1847
  const ast = {
1381
1848
  ast_type: "ForArray",
1382
1849
  type: NullType,
1383
- location: get_location(2),
1850
+ location: get_location(),
1384
1851
  label,
1385
1852
  array: Expr.ast(collection),
1386
1853
  key: key_variable,
@@ -1394,11 +1861,11 @@ export const BlockBuilder = (return_type) => {
1394
1861
  const key_variable = {
1395
1862
  ast_type: "Variable",
1396
1863
  type: Expr.type(collection).key,
1397
- location: get_location(2),
1864
+ location: get_location(),
1398
1865
  mutable: false,
1399
1866
  };
1400
1867
  const key = fromAst(key_variable);
1401
- const label = { location: get_location(2) };
1868
+ const label = { location: get_location() };
1402
1869
  const $ = BlockBuilder(return_type);
1403
1870
  const ret = body($, key, label);
1404
1871
  const stmts = $.statements;
@@ -1410,26 +1877,26 @@ export const BlockBuilder = (return_type) => {
1410
1877
  }
1411
1878
  let expr;
1412
1879
  if (stmts.length === 0) {
1413
- expr = { ast_type: "Value", type: NullType, location: get_location(2), value: null };
1880
+ expr = { ast_type: "Value", type: NullType, location: get_location(), value: null };
1414
1881
  }
1415
1882
  else if (stmts.length === 1 && isSubtype(stmts[0].type, NullType)) {
1416
1883
  expr = stmts[0];
1417
1884
  }
1418
1885
  else {
1419
1886
  if (!isSubtype(stmts[stmts.length - 1].type, NullType)) {
1420
- stmts.push({ ast_type: "Value", type: NullType, location: get_location(2), value: null });
1887
+ stmts.push({ ast_type: "Value", type: NullType, location: get_location(), value: null });
1421
1888
  }
1422
1889
  expr = {
1423
1890
  ast_type: "Block",
1424
1891
  type: stmts[stmts.length - 1].type,
1425
- location: get_location(2),
1892
+ location: get_location(),
1426
1893
  statements: stmts,
1427
1894
  };
1428
1895
  }
1429
1896
  const ast = {
1430
1897
  ast_type: "ForSet",
1431
1898
  type: NullType,
1432
- location: get_location(2),
1899
+ location: get_location(),
1433
1900
  label,
1434
1901
  set: Expr.ast(collection),
1435
1902
  key: key_variable,
@@ -1442,18 +1909,18 @@ export const BlockBuilder = (return_type) => {
1442
1909
  const value_variable = {
1443
1910
  ast_type: "Variable",
1444
1911
  type: Expr.type(collection).value,
1445
- location: get_location(2),
1912
+ location: get_location(),
1446
1913
  mutable: false,
1447
1914
  };
1448
1915
  const value = fromAst(value_variable);
1449
1916
  const key_variable = {
1450
1917
  ast_type: "Variable",
1451
1918
  type: Expr.type(collection).key,
1452
- location: get_location(2),
1919
+ location: get_location(),
1453
1920
  mutable: false,
1454
1921
  };
1455
1922
  const key = fromAst(key_variable);
1456
- const label = { location: get_location(2) };
1923
+ const label = { location: get_location() };
1457
1924
  const $ = BlockBuilder(return_type);
1458
1925
  const ret = body($, value, key, label);
1459
1926
  const stmts = $.statements;
@@ -1465,26 +1932,26 @@ export const BlockBuilder = (return_type) => {
1465
1932
  }
1466
1933
  let expr;
1467
1934
  if (stmts.length === 0) {
1468
- expr = { ast_type: "Value", type: NullType, location: get_location(2), value: null };
1935
+ expr = { ast_type: "Value", type: NullType, location: get_location(), value: null };
1469
1936
  }
1470
1937
  else if (stmts.length === 1 && isSubtype(stmts[0].type, NullType)) {
1471
1938
  expr = stmts[0];
1472
1939
  }
1473
1940
  else {
1474
1941
  if (!isSubtype(stmts[stmts.length - 1].type, NullType)) {
1475
- stmts.push({ ast_type: "Value", type: NullType, location: get_location(2), value: null });
1942
+ stmts.push({ ast_type: "Value", type: NullType, location: get_location(), value: null });
1476
1943
  }
1477
1944
  expr = {
1478
1945
  ast_type: "Block",
1479
1946
  type: stmts[stmts.length - 1].type,
1480
- location: get_location(2),
1947
+ location: get_location(),
1481
1948
  statements: stmts,
1482
1949
  };
1483
1950
  }
1484
1951
  const ast = {
1485
1952
  ast_type: "ForDict",
1486
1953
  type: NullType,
1487
- location: get_location(2),
1954
+ location: get_location(),
1488
1955
  label,
1489
1956
  dict: Expr.ast(collection),
1490
1957
  key: key_variable,
@@ -1500,10 +1967,10 @@ export const BlockBuilder = (return_type) => {
1500
1967
  });
1501
1968
  $.error = (message, location) => {
1502
1969
  if (isTypeEqual($.type(), NeverType)) {
1503
- throw new Error(`Unreachable statement detected at ${printLocation(get_location(2))}`);
1970
+ throw new Error(`Unreachable statement detected at ${printLocations(get_location())}`);
1504
1971
  }
1505
1972
  if (location === undefined) {
1506
- location = get_location(2);
1973
+ location = get_location();
1507
1974
  }
1508
1975
  const ast = {
1509
1976
  ast_type: "Error",
@@ -1516,7 +1983,7 @@ export const BlockBuilder = (return_type) => {
1516
1983
  };
1517
1984
  $.try = (body) => {
1518
1985
  if (isTypeEqual($.type(), NeverType)) {
1519
- throw new Error(`Unreachable statement detected at ${printLocation(get_location(2))}`);
1986
+ throw new Error(`Unreachable statement detected at ${printLocations(get_location())}`);
1520
1987
  }
1521
1988
  const $try = BlockBuilder(return_type);
1522
1989
  const ret = body($try);
@@ -1528,7 +1995,7 @@ export const BlockBuilder = (return_type) => {
1528
1995
  }
1529
1996
  }
1530
1997
  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 });
1998
+ try_stmts.push({ ast_type: "Value", type: NullType, location: get_location(), value: null });
1532
1999
  }
1533
2000
  let try_expr;
1534
2001
  if (try_stmts.length === 1) {
@@ -1538,7 +2005,7 @@ export const BlockBuilder = (return_type) => {
1538
2005
  try_expr = {
1539
2006
  ast_type: "Block",
1540
2007
  type: try_stmts[try_stmts.length - 1].type,
1541
- location: get_location(2),
2008
+ location: get_location(),
1542
2009
  statements: try_stmts,
1543
2010
  };
1544
2011
  }
@@ -1546,21 +2013,21 @@ export const BlockBuilder = (return_type) => {
1546
2013
  const message_variable = {
1547
2014
  ast_type: "Variable",
1548
2015
  type: StringType,
1549
- location: get_location(2),
2016
+ location: get_location(),
1550
2017
  mutable: false,
1551
2018
  };
1552
2019
  const stack_variable = {
1553
2020
  ast_type: "Variable",
1554
2021
  type: ArrayType(StructType({ filename: StringType, line: IntegerType, column: IntegerType })),
1555
- location: get_location(2),
2022
+ location: get_location(),
1556
2023
  mutable: false,
1557
2024
  };
1558
2025
  const try_catch_ast = {
1559
2026
  ast_type: "TryCatch",
1560
2027
  type: NullType,
1561
- location: get_location(2),
2028
+ location: get_location(),
1562
2029
  try_body: try_expr,
1563
- catch_body: { ast_type: "Value", type: NullType, location: get_location(2), value: null }, // will be updated later
2030
+ catch_body: { ast_type: "Value", type: NullType, location: get_location(), value: null }, // will be updated later
1564
2031
  message: message_variable,
1565
2032
  stack: stack_variable,
1566
2033
  };
@@ -1591,12 +2058,12 @@ class IfElseExpr extends NullExpr {
1591
2058
  }
1592
2059
  }
1593
2060
  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 });
2061
+ stmts.push({ ast_type: "Value", type: NullType, location: get_location(), value: null });
1595
2062
  }
1596
2063
  this[AstSymbol].else_body = stmts.length === 1 ? stmts[0] : {
1597
2064
  ast_type: "Block",
1598
2065
  type: stmts[stmts.length - 1].type,
1599
- location: get_location(2),
2066
+ location: get_location(),
1600
2067
  statements: stmts,
1601
2068
  };
1602
2069
  // propagate unreachable information
@@ -1637,14 +2104,14 @@ class IfElseExpr extends NullExpr {
1637
2104
  }
1638
2105
  }
1639
2106
  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 });
2107
+ stmts.push({ ast_type: "Value", type: NullType, location: get_location(), value: null });
1641
2108
  }
1642
2109
  this[AstSymbol].ifs.push({
1643
2110
  predicate: Expr.ast(predicate),
1644
2111
  body: stmts.length === 1 ? stmts[0] : {
1645
2112
  ast_type: "Block",
1646
2113
  type: stmts[stmts.length - 1].type,
1647
- location: get_location(2),
2114
+ location: get_location(),
1648
2115
  statements: stmts,
1649
2116
  },
1650
2117
  });
@@ -1669,7 +2136,7 @@ class TryCatchExpr extends NullExpr {
1669
2136
  /** Define the logic to follow when an error is caught. The error message and stack trace is provided. */
1670
2137
  catch(body) {
1671
2138
  if (this.catchCalled) {
1672
- throw new Error(`Cannot call .catch() more than once on the same try block at ${printLocation(get_location(2))}`);
2139
+ throw new Error(`Cannot call .catch() more than once on the same try block at ${printLocations(get_location())}`);
1673
2140
  }
1674
2141
  this.catchCalled = true;
1675
2142
  const $ = BlockBuilder(this.return_type);
@@ -1682,12 +2149,12 @@ class TryCatchExpr extends NullExpr {
1682
2149
  }
1683
2150
  }
1684
2151
  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 });
2152
+ stmts.push({ ast_type: "Value", type: NullType, location: get_location(), value: null });
1686
2153
  }
1687
2154
  this[AstSymbol].catch_body = stmts.length === 1 ? stmts[0] : {
1688
2155
  ast_type: "Block",
1689
2156
  type: stmts[stmts.length - 1].type,
1690
- location: get_location(2),
2157
+ location: get_location(),
1691
2158
  statements: stmts,
1692
2159
  };
1693
2160
  // Propagate unreachable information
@@ -1708,12 +2175,12 @@ class TryCatchExpr extends NullExpr {
1708
2175
  }
1709
2176
  }
1710
2177
  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 });
2178
+ stmts.push({ ast_type: "Value", type: NullType, location: get_location(), value: null });
1712
2179
  }
1713
2180
  this[AstSymbol].finally_body = stmts.length === 1 ? stmts[0] : {
1714
2181
  ast_type: "Block",
1715
2182
  type: stmts[stmts.length - 1].type,
1716
- location: get_location(2),
2183
+ location: get_location(),
1717
2184
  statements: stmts,
1718
2185
  };
1719
2186
  }
@@ -1737,6 +2204,26 @@ Object.assign(Expr, {
1737
2204
  greater,
1738
2205
  greaterEqual,
1739
2206
  is,
1740
- match: matchExpr
2207
+ match: matchExpr,
2208
+ // Comparison aliases
2209
+ equals,
2210
+ eq,
2211
+ notEquals,
2212
+ ne,
2213
+ lessThan,
2214
+ lt,
2215
+ lessThanOrEqual,
2216
+ lte,
2217
+ le,
2218
+ greaterThan,
2219
+ gt,
2220
+ greaterThanOrEqual,
2221
+ gte,
2222
+ ge,
2223
+ // Patch operations
2224
+ diff,
2225
+ applyPatch,
2226
+ composePatch,
2227
+ invertPatch,
1741
2228
  });
1742
2229
  //# sourceMappingURL=block.js.map