@elaraai/east 0.0.1-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (251) hide show
  1. package/LICENSE.md +682 -0
  2. package/README.md +276 -0
  3. package/dist/src/analyze.d.ts +95 -0
  4. package/dist/src/analyze.d.ts.map +1 -0
  5. package/dist/src/analyze.js +1110 -0
  6. package/dist/src/analyze.js.map +1 -0
  7. package/dist/src/ast.d.ts +263 -0
  8. package/dist/src/ast.d.ts.map +1 -0
  9. package/dist/src/ast.js +151 -0
  10. package/dist/src/ast.js.map +1 -0
  11. package/dist/src/ast_to_ir.d.ts +24 -0
  12. package/dist/src/ast_to_ir.d.ts.map +1 -0
  13. package/dist/src/ast_to_ir.js +834 -0
  14. package/dist/src/ast_to_ir.js.map +1 -0
  15. package/dist/src/builtins.d.ts +18 -0
  16. package/dist/src/builtins.d.ts.map +1 -0
  17. package/dist/src/builtins.js +1105 -0
  18. package/dist/src/builtins.js.map +1 -0
  19. package/dist/src/comparison.d.ts +28 -0
  20. package/dist/src/comparison.d.ts.map +1 -0
  21. package/dist/src/comparison.js +1017 -0
  22. package/dist/src/comparison.js.map +1 -0
  23. package/dist/src/compile.d.ts +22 -0
  24. package/dist/src/compile.d.ts.map +1 -0
  25. package/dist/src/compile.js +3260 -0
  26. package/dist/src/compile.js.map +1 -0
  27. package/dist/src/containers/ref.d.ts +106 -0
  28. package/dist/src/containers/ref.d.ts.map +1 -0
  29. package/dist/src/containers/ref.js +100 -0
  30. package/dist/src/containers/ref.js.map +1 -0
  31. package/dist/src/containers/sortedmap.d.ts +165 -0
  32. package/dist/src/containers/sortedmap.d.ts.map +1 -0
  33. package/dist/src/containers/sortedmap.js +237 -0
  34. package/dist/src/containers/sortedmap.js.map +1 -0
  35. package/dist/src/containers/sortedset.d.ts +185 -0
  36. package/dist/src/containers/sortedset.d.ts.map +1 -0
  37. package/dist/src/containers/sortedset.js +312 -0
  38. package/dist/src/containers/sortedset.js.map +1 -0
  39. package/dist/src/containers/variant.d.ts +131 -0
  40. package/dist/src/containers/variant.d.ts.map +1 -0
  41. package/dist/src/containers/variant.js +68 -0
  42. package/dist/src/containers/variant.js.map +1 -0
  43. package/dist/src/datetime_format/parse.d.ts +50 -0
  44. package/dist/src/datetime_format/parse.d.ts.map +1 -0
  45. package/dist/src/datetime_format/parse.js +908 -0
  46. package/dist/src/datetime_format/parse.js.map +1 -0
  47. package/dist/src/datetime_format/print.d.ts +35 -0
  48. package/dist/src/datetime_format/print.d.ts.map +1 -0
  49. package/dist/src/datetime_format/print.js +157 -0
  50. package/dist/src/datetime_format/print.js.map +1 -0
  51. package/dist/src/datetime_format/tokenize.d.ts +76 -0
  52. package/dist/src/datetime_format/tokenize.d.ts.map +1 -0
  53. package/dist/src/datetime_format/tokenize.js +271 -0
  54. package/dist/src/datetime_format/tokenize.js.map +1 -0
  55. package/dist/src/datetime_format/types.d.ts +99 -0
  56. package/dist/src/datetime_format/types.d.ts.map +1 -0
  57. package/dist/src/datetime_format/types.js +103 -0
  58. package/dist/src/datetime_format/types.js.map +1 -0
  59. package/dist/src/datetime_format/validate.d.ts +51 -0
  60. package/dist/src/datetime_format/validate.d.ts.map +1 -0
  61. package/dist/src/datetime_format/validate.js +208 -0
  62. package/dist/src/datetime_format/validate.js.map +1 -0
  63. package/dist/src/default.d.ts +21 -0
  64. package/dist/src/default.d.ts.map +1 -0
  65. package/dist/src/default.js +82 -0
  66. package/dist/src/default.js.map +1 -0
  67. package/dist/src/eastir.d.ts +33 -0
  68. package/dist/src/eastir.d.ts.map +1 -0
  69. package/dist/src/eastir.js +92 -0
  70. package/dist/src/eastir.js.map +1 -0
  71. package/dist/src/error.d.ts +13 -0
  72. package/dist/src/error.d.ts.map +1 -0
  73. package/dist/src/error.js +8 -0
  74. package/dist/src/error.js.map +1 -0
  75. package/dist/src/expr/array.d.ts +1711 -0
  76. package/dist/src/expr/array.d.ts.map +1 -0
  77. package/dist/src/expr/array.js +1805 -0
  78. package/dist/src/expr/array.js.map +1 -0
  79. package/dist/src/expr/ast.d.ts +17 -0
  80. package/dist/src/expr/ast.d.ts.map +1 -0
  81. package/dist/src/expr/ast.js +302 -0
  82. package/dist/src/expr/ast.js.map +1 -0
  83. package/dist/src/expr/blob.d.ts +141 -0
  84. package/dist/src/expr/blob.d.ts.map +1 -0
  85. package/dist/src/expr/blob.js +198 -0
  86. package/dist/src/expr/blob.js.map +1 -0
  87. package/dist/src/expr/block.d.ts +201 -0
  88. package/dist/src/expr/block.d.ts.map +1 -0
  89. package/dist/src/expr/block.js +1505 -0
  90. package/dist/src/expr/block.js.map +1 -0
  91. package/dist/src/expr/boolean.d.ts +207 -0
  92. package/dist/src/expr/boolean.d.ts.map +1 -0
  93. package/dist/src/expr/boolean.js +261 -0
  94. package/dist/src/expr/boolean.js.map +1 -0
  95. package/dist/src/expr/datetime.d.ts +544 -0
  96. package/dist/src/expr/datetime.d.ts.map +1 -0
  97. package/dist/src/expr/datetime.js +980 -0
  98. package/dist/src/expr/datetime.js.map +1 -0
  99. package/dist/src/expr/dict.d.ts +1242 -0
  100. package/dist/src/expr/dict.d.ts.map +1 -0
  101. package/dist/src/expr/dict.js +1492 -0
  102. package/dist/src/expr/dict.js.map +1 -0
  103. package/dist/src/expr/expr.d.ts +95 -0
  104. package/dist/src/expr/expr.d.ts.map +1 -0
  105. package/dist/src/expr/expr.js +171 -0
  106. package/dist/src/expr/expr.js.map +1 -0
  107. package/dist/src/expr/float.d.ts +357 -0
  108. package/dist/src/expr/float.d.ts.map +1 -0
  109. package/dist/src/expr/float.js +637 -0
  110. package/dist/src/expr/float.js.map +1 -0
  111. package/dist/src/expr/function.d.ts +46 -0
  112. package/dist/src/expr/function.d.ts.map +1 -0
  113. package/dist/src/expr/function.js +58 -0
  114. package/dist/src/expr/function.js.map +1 -0
  115. package/dist/src/expr/index.d.ts +450 -0
  116. package/dist/src/expr/index.d.ts.map +1 -0
  117. package/dist/src/expr/index.js +423 -0
  118. package/dist/src/expr/index.js.map +1 -0
  119. package/dist/src/expr/integer.d.ts +256 -0
  120. package/dist/src/expr/integer.d.ts.map +1 -0
  121. package/dist/src/expr/integer.js +311 -0
  122. package/dist/src/expr/integer.js.map +1 -0
  123. package/dist/src/expr/libs/array.d.ts +106 -0
  124. package/dist/src/expr/libs/array.d.ts.map +1 -0
  125. package/dist/src/expr/libs/array.js +140 -0
  126. package/dist/src/expr/libs/array.js.map +1 -0
  127. package/dist/src/expr/libs/blob.d.ts +42 -0
  128. package/dist/src/expr/libs/blob.d.ts.map +1 -0
  129. package/dist/src/expr/libs/blob.js +70 -0
  130. package/dist/src/expr/libs/blob.js.map +1 -0
  131. package/dist/src/expr/libs/datetime.d.ts +479 -0
  132. package/dist/src/expr/libs/datetime.d.ts.map +1 -0
  133. package/dist/src/expr/libs/datetime.js +624 -0
  134. package/dist/src/expr/libs/datetime.js.map +1 -0
  135. package/dist/src/expr/libs/dict.d.ts +66 -0
  136. package/dist/src/expr/libs/dict.d.ts.map +1 -0
  137. package/dist/src/expr/libs/dict.js +77 -0
  138. package/dist/src/expr/libs/dict.js.map +1 -0
  139. package/dist/src/expr/libs/float.d.ts +299 -0
  140. package/dist/src/expr/libs/float.d.ts.map +1 -0
  141. package/dist/src/expr/libs/float.js +564 -0
  142. package/dist/src/expr/libs/float.js.map +1 -0
  143. package/dist/src/expr/libs/integer.d.ts +228 -0
  144. package/dist/src/expr/libs/integer.d.ts.map +1 -0
  145. package/dist/src/expr/libs/integer.js +398 -0
  146. package/dist/src/expr/libs/integer.js.map +1 -0
  147. package/dist/src/expr/libs/set.d.ts +59 -0
  148. package/dist/src/expr/libs/set.d.ts.map +1 -0
  149. package/dist/src/expr/libs/set.js +69 -0
  150. package/dist/src/expr/libs/set.js.map +1 -0
  151. package/dist/src/expr/libs/string.d.ts +71 -0
  152. package/dist/src/expr/libs/string.d.ts.map +1 -0
  153. package/dist/src/expr/libs/string.js +75 -0
  154. package/dist/src/expr/libs/string.js.map +1 -0
  155. package/dist/src/expr/never.d.ts +15 -0
  156. package/dist/src/expr/never.d.ts.map +1 -0
  157. package/dist/src/expr/never.js +12 -0
  158. package/dist/src/expr/never.js.map +1 -0
  159. package/dist/src/expr/null.d.ts +15 -0
  160. package/dist/src/expr/null.d.ts.map +1 -0
  161. package/dist/src/expr/null.js +12 -0
  162. package/dist/src/expr/null.js.map +1 -0
  163. package/dist/src/expr/ref.d.ts +103 -0
  164. package/dist/src/expr/ref.d.ts.map +1 -0
  165. package/dist/src/expr/ref.js +131 -0
  166. package/dist/src/expr/ref.js.map +1 -0
  167. package/dist/src/expr/regex_validation.d.ts +25 -0
  168. package/dist/src/expr/regex_validation.d.ts.map +1 -0
  169. package/dist/src/expr/regex_validation.js +130 -0
  170. package/dist/src/expr/regex_validation.js.map +1 -0
  171. package/dist/src/expr/set.d.ts +1071 -0
  172. package/dist/src/expr/set.d.ts.map +1 -0
  173. package/dist/src/expr/set.js +1137 -0
  174. package/dist/src/expr/set.js.map +1 -0
  175. package/dist/src/expr/string.d.ts +414 -0
  176. package/dist/src/expr/string.d.ts.map +1 -0
  177. package/dist/src/expr/string.js +683 -0
  178. package/dist/src/expr/string.js.map +1 -0
  179. package/dist/src/expr/struct.d.ts +48 -0
  180. package/dist/src/expr/struct.d.ts.map +1 -0
  181. package/dist/src/expr/struct.js +65 -0
  182. package/dist/src/expr/struct.js.map +1 -0
  183. package/dist/src/expr/types.d.ts +68 -0
  184. package/dist/src/expr/types.d.ts.map +1 -0
  185. package/dist/src/expr/types.js +6 -0
  186. package/dist/src/expr/types.js.map +1 -0
  187. package/dist/src/expr/variant.d.ts +137 -0
  188. package/dist/src/expr/variant.d.ts.map +1 -0
  189. package/dist/src/expr/variant.js +105 -0
  190. package/dist/src/expr/variant.js.map +1 -0
  191. package/dist/src/fuzz.d.ts +80 -0
  192. package/dist/src/fuzz.d.ts.map +1 -0
  193. package/dist/src/fuzz.js +300 -0
  194. package/dist/src/fuzz.js.map +1 -0
  195. package/dist/src/index.d.ts +21 -0
  196. package/dist/src/index.d.ts.map +1 -0
  197. package/dist/src/index.js +21 -0
  198. package/dist/src/index.js.map +1 -0
  199. package/dist/src/internal.d.ts +36 -0
  200. package/dist/src/internal.d.ts.map +1 -0
  201. package/dist/src/internal.js +11 -0
  202. package/dist/src/internal.js.map +1 -0
  203. package/dist/src/ir.d.ts +1571 -0
  204. package/dist/src/ir.d.ts.map +1 -0
  205. package/dist/src/ir.js +56 -0
  206. package/dist/src/ir.js.map +1 -0
  207. package/dist/src/location.d.ts +48 -0
  208. package/dist/src/location.d.ts.map +1 -0
  209. package/dist/src/location.js +62 -0
  210. package/dist/src/location.js.map +1 -0
  211. package/dist/src/platform.d.ts +21 -0
  212. package/dist/src/platform.d.ts.map +1 -0
  213. package/dist/src/platform.js +8 -0
  214. package/dist/src/platform.js.map +1 -0
  215. package/dist/src/serialization/beast.d.ts +39 -0
  216. package/dist/src/serialization/beast.d.ts.map +1 -0
  217. package/dist/src/serialization/beast.js +555 -0
  218. package/dist/src/serialization/beast.js.map +1 -0
  219. package/dist/src/serialization/beast2-stream.d.ts +38 -0
  220. package/dist/src/serialization/beast2-stream.d.ts.map +1 -0
  221. package/dist/src/serialization/beast2-stream.js +665 -0
  222. package/dist/src/serialization/beast2-stream.js.map +1 -0
  223. package/dist/src/serialization/beast2.d.ts +41 -0
  224. package/dist/src/serialization/beast2.d.ts.map +1 -0
  225. package/dist/src/serialization/beast2.js +489 -0
  226. package/dist/src/serialization/beast2.js.map +1 -0
  227. package/dist/src/serialization/binary-utils.d.ts +151 -0
  228. package/dist/src/serialization/binary-utils.d.ts.map +1 -0
  229. package/dist/src/serialization/binary-utils.js +929 -0
  230. package/dist/src/serialization/binary-utils.js.map +1 -0
  231. package/dist/src/serialization/east.d.ts +84 -0
  232. package/dist/src/serialization/east.d.ts.map +1 -0
  233. package/dist/src/serialization/east.js +1802 -0
  234. package/dist/src/serialization/east.js.map +1 -0
  235. package/dist/src/serialization/index.d.ts +11 -0
  236. package/dist/src/serialization/index.d.ts.map +1 -0
  237. package/dist/src/serialization/index.js +12 -0
  238. package/dist/src/serialization/index.js.map +1 -0
  239. package/dist/src/serialization/json.d.ts +36 -0
  240. package/dist/src/serialization/json.d.ts.map +1 -0
  241. package/dist/src/serialization/json.js +849 -0
  242. package/dist/src/serialization/json.js.map +1 -0
  243. package/dist/src/type_of_type.d.ts +115 -0
  244. package/dist/src/type_of_type.d.ts.map +1 -0
  245. package/dist/src/type_of_type.js +362 -0
  246. package/dist/src/type_of_type.js.map +1 -0
  247. package/dist/src/types.d.ts +648 -0
  248. package/dist/src/types.d.ts.map +1 -0
  249. package/dist/src/types.js +1631 -0
  250. package/dist/src/types.js.map +1 -0
  251. package/package.json +87 -0
@@ -0,0 +1,3260 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
+ */
5
+ import { Builtins } from "./builtins.js";
6
+ import { printLocationValue } from "./ir.js";
7
+ import { compareFor, equalFor, greaterEqualFor, greaterFor, isFor, lessEqualFor, lessFor, notEqualFor } from "./comparison.js";
8
+ import { printFor, parseFor } from "./serialization/east.js";
9
+ import { variant } from "./containers/variant.js";
10
+ import { EastError } from "./error.js";
11
+ import { SortedSet } from "./containers/sortedset.js";
12
+ import { SortedMap } from "./containers/sortedmap.js";
13
+ import { BufferWriter } from "./serialization/binary-utils.js";
14
+ import { decodeBeast2For, decodeBeastFor, encodeBeast2For, encodeBeastFor, fromJSONFor, toJSONFor } from "./serialization/index.js";
15
+ import { formatDateTime } from "./datetime_format/print.js";
16
+ import { parseDateTimeFormatted } from "./datetime_format/parse.js";
17
+ import { EastTypeValueType, isTypeValueEqual, isSubtypeValue, toEastTypeValue, expandTypeValue } from "./type_of_type.js";
18
+ import { ref } from "./containers/ref.js";
19
+ export { isTypeValueEqual };
20
+ export const printTypeValue = printFor(EastTypeValueType);
21
+ /** @internal Track iteration locks to prevent concurrent modification */
22
+ const iterationLocks = new WeakMap();
23
+ /** @internal Lock a collection for iteration (prevents size/keyset modifications) */
24
+ const lockForIteration = (obj) => {
25
+ iterationLocks.set(obj, (iterationLocks.get(obj) || 0) + 1);
26
+ };
27
+ /** @internal Unlock a collection after iteration */
28
+ const unlockForIteration = (obj) => {
29
+ const count = iterationLocks.get(obj) || 0;
30
+ if (count > 1) {
31
+ iterationLocks.set(obj, count - 1);
32
+ }
33
+ else {
34
+ iterationLocks.delete(obj);
35
+ }
36
+ };
37
+ /** @internal An exception throw for the purpose of early function return */
38
+ export class ReturnException {
39
+ value;
40
+ constructor(value) {
41
+ this.value = value;
42
+ }
43
+ }
44
+ /** @internal An exception throw for the purpose of early loop continue */
45
+ class ContinueException {
46
+ label;
47
+ constructor(label) {
48
+ this.label = label;
49
+ }
50
+ }
51
+ /** @internal An exception throw for the purpose of early loop break */
52
+ class BreakException {
53
+ label;
54
+ constructor(label) {
55
+ this.label = label;
56
+ }
57
+ }
58
+ /** Compile `IR` into a JavaScript function using a closure-compiler technique.
59
+ * This should execute faster than a simple tree-walking interpreter, but slower than hand-written Javascript.
60
+ *
61
+ * A "context" of the current variables in scope is given. For toplevel function IR, provide `{}`.
62
+ * A "platform" is provided with JavaScript functions to perform effects, like logging. If no effects are needed, simply provide `{}`.
63
+ *
64
+ * @internal
65
+ */
66
+ export function compile_internal(ir, ctx, platform, asyncPlatformFns, fresh_ctx = true, compilingNodes = new Set()) {
67
+ // Detect circular IR
68
+ if (compilingNodes.has(ir)) {
69
+ throw new Error(`Circular IR reference detected at ${printLocationValue(ir.value?.location || { file: "unknown", line: 0, column: 0 })}. `);
70
+ }
71
+ // Track this node (exception-safe with try-finally)
72
+ compilingNodes.add(ir);
73
+ try {
74
+ return compileNodeInternal(ir, ctx, platform, asyncPlatformFns, fresh_ctx, compilingNodes);
75
+ }
76
+ finally {
77
+ compilingNodes.delete(ir);
78
+ }
79
+ }
80
+ /** Internal helper that does the actual compilation work */
81
+ function compileNodeInternal(ir, ctx, platform, asyncPlatformFns, fresh_ctx, compilingNodes = new Set()) {
82
+ if (ir.type === "Value") {
83
+ if (ir.value.type.type !== ir.value.value.type) {
84
+ throw new Error(`Value node expected value of type .${ir.value.type.type} but got .${ir.value.value.type} at ${printLocationValue(ir.value.location)}`);
85
+ }
86
+ const v = ir.value.value.value;
87
+ return (_ctx) => v;
88
+ }
89
+ else if (ir.type === "Error") {
90
+ const message_compiled = compile_internal(ir.value.message, ctx, platform, asyncPlatformFns, false, compilingNodes);
91
+ const location = ir.value.location;
92
+ if (ir.value.isAsync) {
93
+ return async (ctx) => { throw new EastError(await message_compiled(ctx), { location: location }); };
94
+ }
95
+ else {
96
+ return (ctx) => { throw new EastError(message_compiled(ctx), { location: location }); };
97
+ }
98
+ }
99
+ else if (ir.type === "TryCatch") {
100
+ const try_body = compile_internal(ir.value.try_body, Object.create(ctx), platform, asyncPlatformFns, true, compilingNodes);
101
+ const new_ctx = Object.create(ctx);
102
+ const message_name = ir.value.message.value.name;
103
+ const stack_name = ir.value.stack.value.name;
104
+ new_ctx[message_name] = ir.value.message.value.type;
105
+ new_ctx[stack_name] = ir.value.stack.value.type;
106
+ const catch_body = compile_internal(ir.value.catch_body, new_ctx, platform, asyncPlatformFns, true, compilingNodes);
107
+ // Don't include finally unless necessary (Value nodes are effect free)
108
+ const finally_body = ir.value.finally_body.type === "Value" ? undefined : compile_internal(ir.value.finally_body, Object.create(ctx), platform, asyncPlatformFns, true, compilingNodes);
109
+ if (ir.value.isAsync) {
110
+ if (finally_body === undefined) {
111
+ return async (ctx) => {
112
+ try {
113
+ return await try_body(Object.create(ctx));
114
+ }
115
+ catch (e) {
116
+ if (e instanceof EastError) {
117
+ const new_ctx = Object.create(ctx);
118
+ new_ctx[message_name] = e.message;
119
+ new_ctx[stack_name] = e.location;
120
+ return await catch_body(new_ctx);
121
+ }
122
+ else {
123
+ throw (e);
124
+ }
125
+ }
126
+ };
127
+ }
128
+ else {
129
+ return async (ctx) => {
130
+ try {
131
+ return await try_body(Object.create(ctx));
132
+ }
133
+ catch (e) {
134
+ if (e instanceof EastError) {
135
+ const new_ctx = Object.create(ctx);
136
+ new_ctx[message_name] = e.message;
137
+ new_ctx[stack_name] = e.location;
138
+ return await catch_body(new_ctx);
139
+ }
140
+ else {
141
+ throw (e);
142
+ }
143
+ }
144
+ finally {
145
+ await finally_body(Object.create(ctx));
146
+ }
147
+ };
148
+ }
149
+ }
150
+ else {
151
+ if (finally_body === undefined) {
152
+ return (ctx) => {
153
+ try {
154
+ return try_body(Object.create(ctx));
155
+ }
156
+ catch (e) {
157
+ if (e instanceof EastError) {
158
+ const new_ctx = Object.create(ctx);
159
+ new_ctx[message_name] = e.message;
160
+ new_ctx[stack_name] = e.location;
161
+ return catch_body(new_ctx);
162
+ }
163
+ else {
164
+ throw (e);
165
+ }
166
+ }
167
+ };
168
+ }
169
+ else {
170
+ return (ctx) => {
171
+ try {
172
+ return try_body(Object.create(ctx));
173
+ }
174
+ catch (e) {
175
+ if (e instanceof EastError) {
176
+ const new_ctx = Object.create(ctx);
177
+ new_ctx[message_name] = e.message;
178
+ new_ctx[stack_name] = e.location;
179
+ return catch_body(new_ctx);
180
+ }
181
+ else {
182
+ throw (e);
183
+ }
184
+ }
185
+ finally {
186
+ finally_body(Object.create(ctx));
187
+ }
188
+ };
189
+ }
190
+ }
191
+ }
192
+ else if (ir.type === "Variable") {
193
+ const name = ir.value.name;
194
+ const ctx_type = ctx[name];
195
+ if (ctx_type === undefined) {
196
+ throw new Error(`Variable defined at ${printLocationValue(ir.value.location)} is not in scope at ${printLocationValue(ir.value.location)}`);
197
+ }
198
+ if (!isTypeValueEqual(ctx_type, ir.value.type)) {
199
+ throw new Error(`Variable defined at ${printLocationValue(ir.value.location)} has type ${printTypeValue(ctx_type)} but expected ${printTypeValue(ir.value.type)} at ${printLocationValue(ir.value.location)}`);
200
+ }
201
+ if (ir.value.mutable && ir.value.captured) {
202
+ return (ctx) => ctx[name].x;
203
+ }
204
+ else {
205
+ return (ctx) => ctx[name];
206
+ }
207
+ }
208
+ else if (ir.type === "Let") {
209
+ if (!isSubtypeValue(ir.value.value.value.type, ir.value.variable.value.type)) {
210
+ throw new Error(`Cannot initialize a variable defined at ${printLocationValue(ir.value.variable.value.location)} of type ${printTypeValue(ir.value.variable.value.type)} to a value of type ${printTypeValue(ir.value.value.value.type)} at ${printLocationValue(ir.value.location)}`);
211
+ }
212
+ const compiled_statement = compile_internal(ir.value.value, ctx, platform, asyncPlatformFns, false, compilingNodes);
213
+ const name = ir.value.variable.value.name;
214
+ ctx[name] = ir.value.variable.value.type;
215
+ if (ir.value.variable.value.mutable && ir.value.variable.value.captured) {
216
+ if (ir.value.isAsync) {
217
+ return async (ctx) => {
218
+ ctx[name] = { x: await compiled_statement(ctx) };
219
+ return null;
220
+ };
221
+ }
222
+ else {
223
+ return (ctx) => {
224
+ ctx[name] = { x: compiled_statement(ctx) };
225
+ return null;
226
+ };
227
+ }
228
+ }
229
+ else {
230
+ if (ir.value.isAsync) {
231
+ return async (ctx) => {
232
+ ctx[name] = await compiled_statement(ctx);
233
+ return null;
234
+ };
235
+ }
236
+ else {
237
+ return (ctx) => {
238
+ ctx[name] = compiled_statement(ctx);
239
+ return null;
240
+ };
241
+ }
242
+ }
243
+ }
244
+ else if (ir.type === "Assign") {
245
+ const name = ir.value.variable.value.name;
246
+ if (ctx[name] === undefined) {
247
+ throw new Error(`Attempting to reassign to a variable defined at ${printLocationValue(ir.value.variable.value.location)} which is not in scope at ${printLocationValue(ir.value.location)} at ${printLocationValue(ir.value.location)}`);
248
+ }
249
+ if (!isSubtypeValue(ir.value.value.value.type, ctx[name])) {
250
+ throw new Error(`Cannot reassign to a variable defined at ${printLocationValue(ir.value.variable.value.location)} of type ${printTypeValue(ir.value.variable.value.type)} to a value of type ${printTypeValue(ir.value.value.value.type)} at ${printLocationValue(ir.value.location)}`);
251
+ }
252
+ if (!ir.value.variable.value.mutable) {
253
+ throw new Error(`Cannot reassign const variable ${name} at ${printLocationValue(ir.value.location)}`);
254
+ }
255
+ const compiled_statement = compile_internal(ir.value.value, ctx, platform, asyncPlatformFns, false, compilingNodes);
256
+ if (ir.value.variable.value.mutable && ir.value.variable.value.captured) {
257
+ if (ir.value.isAsync) {
258
+ return async (ctx) => {
259
+ const value = await compiled_statement(ctx);
260
+ ctx[name].x = value;
261
+ return null;
262
+ };
263
+ }
264
+ else {
265
+ return (ctx) => {
266
+ const value = compiled_statement(ctx);
267
+ ctx[name].x = value;
268
+ return null;
269
+ };
270
+ }
271
+ }
272
+ else {
273
+ if (ir.value.isAsync) {
274
+ return async (ctx) => {
275
+ const value = await compiled_statement(ctx);
276
+ // We need to check in which prototype the variable lives
277
+ while (!Object.hasOwn(ctx, name))
278
+ ctx = Object.getPrototypeOf(ctx);
279
+ ctx[name] = value;
280
+ return null;
281
+ };
282
+ }
283
+ else {
284
+ return (ctx) => {
285
+ const value = compiled_statement(ctx);
286
+ // We need to check in which prototype the variable lives
287
+ while (!Object.hasOwn(ctx, name))
288
+ ctx = Object.getPrototypeOf(ctx);
289
+ ctx[name] = value;
290
+ return null;
291
+ };
292
+ }
293
+ }
294
+ }
295
+ else if (ir.type === "As") {
296
+ if (!isSubtypeValue(ir.value.value.value.type, ir.value.type)) {
297
+ throw new Error(`Cannot cast value of type ${printTypeValue(ir.value.value.value.type)} to type ${printTypeValue(ir.value.type)} at ${printLocationValue(ir.value.location)}`);
298
+ }
299
+ // in dynamically typed runtimes like Javascript, this is a no-op
300
+ // (for statically typed runtimes this assists in unifying types in branches)
301
+ return compile_internal(ir.value.value, ctx, platform, asyncPlatformFns, fresh_ctx, compilingNodes);
302
+ }
303
+ else if (ir.type === "UnwrapRecursive") {
304
+ // TODO there seems to be cases of Wrap / Unwrap that could be optimized away during compilation
305
+ if (!isTypeValueEqual(ir.value.value.value.type, ir.value.type)) {
306
+ throw new Error(`Cannot unwrap recursive value of type ${printTypeValue(ir.value.value.value.type)} to type ${printTypeValue(ir.value.type)} at ${printLocationValue(ir.value.location)}`);
307
+ }
308
+ // in dynamically typed runtimes like Javascript, this is a no-op
309
+ // (for statically typed runtimes this assists in e.g. typing a reference or pointer)
310
+ return compile_internal(ir.value.value, ctx, platform, asyncPlatformFns, fresh_ctx, compilingNodes);
311
+ }
312
+ else if (ir.type === "WrapRecursive") {
313
+ // TODO there seems to be cases of Wrap / Unwrap that could be optimized away during compilation
314
+ if (!isSubtypeValue(ir.value.value.value.type, ir.value.type)) {
315
+ throw new Error(`Cannot wrap value of type ${printTypeValue(ir.value.value.value.type)} to recursive type ${printTypeValue(ir.value.type)} at ${printLocationValue(ir.value.location)}`);
316
+ }
317
+ // in dynamically typed runtimes like Javascript, this is a no-op
318
+ // (for statically typed runtimes this assists in e.g. typing a heap allocation)
319
+ return compile_internal(ir.value.value, ctx, platform, asyncPlatformFns, false, compilingNodes);
320
+ }
321
+ else if (ir.type === "Function") {
322
+ if (ir.value.type.type !== "Function") {
323
+ throw new Error(`Expected Function type, got ${printTypeValue(ir.value.type)} at ${printLocationValue(ir.value.location)}`);
324
+ }
325
+ const ctx2 = {};
326
+ for (const variable of ir.value.captures) {
327
+ const ctx_type = ctx[variable.value.name];
328
+ if (ctx_type === undefined) {
329
+ throw new Error(`Captured variable defined at ${printLocationValue(variable.value.location)} is not in scope at ${printLocationValue(ir.value.location)}`);
330
+ }
331
+ if (!isTypeValueEqual(ctx_type, variable.value.type)) {
332
+ throw new Error(`Captured variable defined at ${printLocationValue(variable.value.location)} has type ${printTypeValue(ctx_type)} but expected ${printTypeValue(variable.value.type)} at ${printLocationValue(ir.value.location)}`);
333
+ }
334
+ ctx2[variable.value.name] = variable.value.type;
335
+ }
336
+ for (const parameter of ir.value.parameters) {
337
+ const parameter_name = parameter.value.name;
338
+ ctx2[parameter_name] = parameter.value.type;
339
+ }
340
+ // Function return values are covariant
341
+ // TODO what is the semantics here in a static language? Should we use `As` here?
342
+ // Note: this requires unreachability analysis to be correct, since early terminating programs might have a final statement that produces never
343
+ if (!isSubtypeValue(ir.value.body.value.type, ir.value.type.value.output)) {
344
+ throw new Error(`Expected Function to return type ${printTypeValue(ir.value.type.value.output)}, got ${printTypeValue(ir.value.body.value.type)} at ${printLocationValue(ir.value.location)}`);
345
+ }
346
+ const compiled_body = compile_internal(ir.value.body, ctx2, platform, asyncPlatformFns, true, compilingNodes);
347
+ const bodyIsAsync = ir.value.type.value.platforms.some(p => asyncPlatformFns.has(p));
348
+ const capture_names = ir.value.captures.map(v => v.value.name);
349
+ const parameter_names = ir.value.parameters.map(v => v.value.name);
350
+ return (ctx) => {
351
+ const ctx2 = {};
352
+ for (const name of capture_names) {
353
+ ctx2[name] = ctx[name];
354
+ }
355
+ // If body is async, create an async function that awaits internally
356
+ if (bodyIsAsync) {
357
+ return async (...args) => {
358
+ const ctx3 = { ...ctx2 };
359
+ parameter_names.forEach((name, i) => ctx3[name] = args[i]);
360
+ return await compiled_body(ctx3);
361
+ };
362
+ }
363
+ else {
364
+ return (...args) => {
365
+ const ctx3 = { ...ctx2 };
366
+ parameter_names.forEach((name, i) => ctx3[name] = args[i]);
367
+ return compiled_body(ctx3);
368
+ };
369
+ }
370
+ };
371
+ }
372
+ else if (ir.type === "Call") {
373
+ if (ir.value.function.value.type.type !== "Function") {
374
+ throw new Error(`Call expected Function, got ${printTypeValue(ir.value.function.value.type)} at ${printLocationValue(ir.value.location)}`);
375
+ }
376
+ if (ir.value.function.value.type.value.inputs.length !== ir.value.arguments.length) {
377
+ throw new Error(`Function expected ${ir.value.function.value.type.value.inputs.length} arguments, got ${ir.value.arguments.length} at ${printLocationValue(ir.value.location)}`);
378
+ }
379
+ for (const [i, t] of ir.value.function.value.type.value.inputs.entries()) {
380
+ // TODO what is the semantics here in a static language? Should we use `As` here?
381
+ if (!isSubtypeValue(t, ir.value.arguments[i].value.type)) {
382
+ throw new Error(`Function expected argument ${i + 1} of type ${printTypeValue(t)}, got ${printTypeValue(ir.value.arguments[i].value.type)} at ${printLocationValue(ir.value.location)}`);
383
+ }
384
+ }
385
+ const compiled_f = compile_internal(ir.value.function, ctx, platform, asyncPlatformFns, false, compilingNodes);
386
+ const compiled_args = ir.value.arguments.map(argument => compile_internal(argument, ctx, platform, asyncPlatformFns, false, compilingNodes));
387
+ const location = ir.value.location;
388
+ if (ir.value.function.value.type.value.isAsync) {
389
+ return async (ctx) => {
390
+ try {
391
+ const args = [];
392
+ for (const compiled_arg of compiled_args) {
393
+ args.push(await compiled_arg(ctx));
394
+ }
395
+ return (await compiled_f(ctx))(...args);
396
+ }
397
+ catch (e) {
398
+ if (e instanceof ReturnException) {
399
+ return e.value;
400
+ }
401
+ else if (e instanceof EastError) {
402
+ e.location.push(location); // The fact that we need to push the call location not the definition location means we need to handle this here
403
+ throw (e);
404
+ }
405
+ else if (e instanceof ContinueException) {
406
+ throw new Error(`continue failed to find label ${e.label} at ${printLocationValue(ir.value.location)}`);
407
+ }
408
+ else if (e instanceof BreakException) {
409
+ throw new Error(`break failed to find label ${e.label} at ${printLocationValue(ir.value.location)}`);
410
+ }
411
+ else {
412
+ throw (e);
413
+ }
414
+ }
415
+ };
416
+ }
417
+ else {
418
+ return (ctx) => {
419
+ try {
420
+ return compiled_f(ctx)(...compiled_args.map(arg => arg(ctx)));
421
+ }
422
+ catch (e) {
423
+ if (e instanceof ReturnException) {
424
+ return e.value;
425
+ }
426
+ else if (e instanceof EastError) {
427
+ e.location.push(location); // The fact that we need to push the call location not the definition location means we need to handle this here
428
+ throw (e);
429
+ }
430
+ else if (e instanceof ContinueException) {
431
+ throw new Error(`continue failed to find label ${e.label} at ${printLocationValue(ir.value.location)}`);
432
+ }
433
+ else if (e instanceof BreakException) {
434
+ throw new Error(`break failed to find label ${e.label} at ${printLocationValue(ir.value.location)}`);
435
+ }
436
+ else {
437
+ throw (e);
438
+ }
439
+ }
440
+ };
441
+ }
442
+ }
443
+ else if (ir.type === "IfElse") {
444
+ const ifs = [];
445
+ for (const { predicate, body } of ir.value.ifs) {
446
+ ifs.push({
447
+ predicate: compile_internal(predicate, ctx, platform, asyncPlatformFns, false, compilingNodes),
448
+ body: compile_internal(body, Object.create(ctx), platform, asyncPlatformFns, true, compilingNodes),
449
+ });
450
+ }
451
+ const else_body = compile_internal(ir.value.else_body, Object.create(ctx), platform, asyncPlatformFns, true, compilingNodes);
452
+ if (ir.value.isAsync) {
453
+ return async (ctx) => {
454
+ for (const { predicate, body } of ifs) {
455
+ if (await predicate(ctx)) {
456
+ return body(Object.create(ctx));
457
+ }
458
+ }
459
+ return else_body(Object.create(ctx));
460
+ };
461
+ }
462
+ else {
463
+ return (ctx) => {
464
+ for (const { predicate, body } of ifs) {
465
+ if (predicate(ctx)) {
466
+ return body(Object.create(ctx));
467
+ }
468
+ }
469
+ return else_body(Object.create(ctx));
470
+ };
471
+ }
472
+ }
473
+ else if (ir.type === "Match") {
474
+ const compiled_variant = compile_internal(ir.value.variant, ctx, platform, asyncPlatformFns, false, compilingNodes);
475
+ const compiled_cases = {};
476
+ const data_names = {};
477
+ for (const { case: k, variable, body } of ir.value.cases) {
478
+ const ctx2 = Object.create(ctx);
479
+ const data_name = variable.value.name;
480
+ data_names[k] = data_name;
481
+ ctx2[data_name] = variable.value.type;
482
+ compiled_cases[k] = compile_internal(body, ctx2, platform, asyncPlatformFns, true, compilingNodes);
483
+ }
484
+ if (ir.value.isAsync) {
485
+ return async (ctx) => {
486
+ const v = await compiled_variant(ctx);
487
+ const ctx2 = Object.create(ctx);
488
+ ctx2[data_names[v.type]] = v.value;
489
+ return compiled_cases[v.type](ctx2);
490
+ };
491
+ }
492
+ else {
493
+ return (ctx) => {
494
+ const v = compiled_variant(ctx);
495
+ const ctx2 = Object.create(ctx);
496
+ ctx2[data_names[v.type]] = v.value;
497
+ return compiled_cases[v.type](ctx2);
498
+ };
499
+ }
500
+ }
501
+ else if (ir.type === "While") {
502
+ const compiled_predicate = compile_internal(ir.value.predicate, ctx, platform, asyncPlatformFns, false, compilingNodes);
503
+ const ctx2 = Object.create(ctx);
504
+ const compiled_body = compile_internal(ir.value.body, ctx2, platform, asyncPlatformFns, true, compilingNodes);
505
+ const label = ir.value.label.name;
506
+ if (ir.value.isAsync) {
507
+ return async (ctx) => {
508
+ while (await compiled_predicate(ctx)) {
509
+ try {
510
+ const ctx2 = Object.create(ctx);
511
+ await compiled_body(ctx2);
512
+ }
513
+ catch (e) {
514
+ if (e instanceof ContinueException && e.label === label) {
515
+ continue;
516
+ }
517
+ else if (e instanceof BreakException && e.label === label) {
518
+ break;
519
+ }
520
+ else {
521
+ throw e;
522
+ }
523
+ }
524
+ }
525
+ return null;
526
+ };
527
+ }
528
+ else {
529
+ return (ctx) => {
530
+ while (compiled_predicate(ctx)) {
531
+ try {
532
+ const ctx2 = Object.create(ctx);
533
+ compiled_body(ctx2);
534
+ }
535
+ catch (e) {
536
+ if (e instanceof ContinueException && e.label === label) {
537
+ continue;
538
+ }
539
+ else if (e instanceof BreakException && e.label === label) {
540
+ break;
541
+ }
542
+ else {
543
+ throw e;
544
+ }
545
+ }
546
+ }
547
+ return null;
548
+ };
549
+ }
550
+ }
551
+ else if (ir.type === "ForArray") {
552
+ const value_type = expandTypeValue(ir.value.array.value.type).value;
553
+ const compiled_array = compile_internal(ir.value.array, ctx, platform, asyncPlatformFns, false, compilingNodes);
554
+ const ctx2 = Object.create(ctx);
555
+ const key_name = ir.value.key.value.name;
556
+ const value_name = ir.value.value.value.name;
557
+ ctx2[key_name] = variant("Integer", null);
558
+ ctx2[value_name] = value_type;
559
+ const compiled_body = compile_internal(ir.value.body, ctx2, platform, asyncPlatformFns, true, compilingNodes);
560
+ const label = ir.value.label.name;
561
+ if (ir.value.isAsync) {
562
+ return async (ctx) => {
563
+ const array = await compiled_array(ctx);
564
+ lockForIteration(array);
565
+ try {
566
+ for (const [key, value] of array.entries()) {
567
+ const ctx2 = Object.create(ctx);
568
+ ctx2[key_name] = BigInt(key);
569
+ ctx2[value_name] = value;
570
+ try {
571
+ await compiled_body(ctx2);
572
+ }
573
+ catch (e) {
574
+ if (e instanceof ContinueException && e.label === label) {
575
+ continue;
576
+ }
577
+ else if (e instanceof BreakException && e.label === label) {
578
+ break;
579
+ }
580
+ else {
581
+ throw e;
582
+ }
583
+ }
584
+ }
585
+ return null;
586
+ }
587
+ finally {
588
+ unlockForIteration(array);
589
+ }
590
+ };
591
+ }
592
+ else {
593
+ return (ctx) => {
594
+ const array = compiled_array(ctx);
595
+ lockForIteration(array);
596
+ try {
597
+ for (const [key, value] of array.entries()) {
598
+ const ctx2 = Object.create(ctx);
599
+ ctx2[key_name] = BigInt(key);
600
+ ctx2[value_name] = value;
601
+ try {
602
+ compiled_body(ctx2);
603
+ }
604
+ catch (e) {
605
+ if (e instanceof ContinueException && e.label === label) {
606
+ continue;
607
+ }
608
+ else if (e instanceof BreakException && e.label === label) {
609
+ break;
610
+ }
611
+ else {
612
+ throw e;
613
+ }
614
+ }
615
+ }
616
+ return null;
617
+ }
618
+ finally {
619
+ unlockForIteration(array);
620
+ }
621
+ };
622
+ }
623
+ }
624
+ else if (ir.type === "ForSet") {
625
+ const key_type = expandTypeValue(ir.value.set.value.type).value;
626
+ const compiled_set = compile_internal(ir.value.set, ctx, platform, asyncPlatformFns, false, compilingNodes);
627
+ const ctx2 = Object.create(ctx);
628
+ const key_name = ir.value.key.value.name;
629
+ ctx2[key_name] = key_type;
630
+ const compiled_body = compile_internal(ir.value.body, ctx2, platform, asyncPlatformFns, true, compilingNodes);
631
+ const label = ir.value.label.name;
632
+ if (ir.value.isAsync) {
633
+ return async (ctx) => {
634
+ const set = await compiled_set(ctx);
635
+ lockForIteration(set);
636
+ try {
637
+ for (const key of set) {
638
+ const ctx2 = Object.create(ctx);
639
+ ctx2[key_name] = key;
640
+ try {
641
+ await compiled_body(ctx2);
642
+ }
643
+ catch (e) {
644
+ if (e instanceof ContinueException && e.label === label) {
645
+ continue;
646
+ }
647
+ else if (e instanceof BreakException && e.label === label) {
648
+ break;
649
+ }
650
+ else {
651
+ throw e;
652
+ }
653
+ }
654
+ }
655
+ return null;
656
+ }
657
+ finally {
658
+ unlockForIteration(set);
659
+ }
660
+ };
661
+ }
662
+ else {
663
+ return (ctx) => {
664
+ const set = compiled_set(ctx);
665
+ lockForIteration(set);
666
+ try {
667
+ for (const key of set) {
668
+ const ctx2 = Object.create(ctx);
669
+ ctx2[key_name] = key;
670
+ try {
671
+ compiled_body(ctx2);
672
+ }
673
+ catch (e) {
674
+ if (e instanceof ContinueException && e.label === label) {
675
+ continue;
676
+ }
677
+ else if (e instanceof BreakException && e.label === label) {
678
+ break;
679
+ }
680
+ else {
681
+ throw e;
682
+ }
683
+ }
684
+ }
685
+ return null;
686
+ }
687
+ finally {
688
+ unlockForIteration(set);
689
+ }
690
+ };
691
+ }
692
+ }
693
+ else if (ir.type === "ForDict") {
694
+ const key_type = expandTypeValue(ir.value.dict.value.type).value.key;
695
+ const value_type = expandTypeValue(ir.value.dict.value.type).value.value;
696
+ const compiled_dict = compile_internal(ir.value.dict, ctx, platform, asyncPlatformFns, false, compilingNodes);
697
+ const ctx2 = Object.create(ctx);
698
+ const key_name = ir.value.key.value.name;
699
+ const value_name = ir.value.value.value.name;
700
+ ctx2[key_name] = key_type;
701
+ ctx2[value_name] = value_type;
702
+ const compiled_body = compile_internal(ir.value.body, ctx2, platform, asyncPlatformFns, true, compilingNodes);
703
+ const label = ir.value.label.name;
704
+ if (ir.value.isAsync) {
705
+ return async (ctx) => {
706
+ const dict = await compiled_dict(ctx);
707
+ lockForIteration(dict);
708
+ try {
709
+ for (const [key, value] of dict) {
710
+ const ctx2 = Object.create(ctx);
711
+ ctx2[key_name] = key;
712
+ ctx2[value_name] = value;
713
+ try {
714
+ await compiled_body(ctx2);
715
+ }
716
+ catch (e) {
717
+ if (e instanceof ContinueException && e.label === label) {
718
+ continue;
719
+ }
720
+ else if (e instanceof BreakException && e.label === label) {
721
+ break;
722
+ }
723
+ else {
724
+ throw e;
725
+ }
726
+ }
727
+ }
728
+ return null;
729
+ }
730
+ finally {
731
+ unlockForIteration(dict);
732
+ }
733
+ };
734
+ }
735
+ else {
736
+ return (ctx) => {
737
+ const dict = compiled_dict(ctx);
738
+ lockForIteration(dict);
739
+ try {
740
+ for (const [key, value] of dict) {
741
+ const ctx2 = Object.create(ctx);
742
+ ctx2[key_name] = key;
743
+ ctx2[value_name] = value;
744
+ try {
745
+ compiled_body(ctx2);
746
+ }
747
+ catch (e) {
748
+ if (e instanceof ContinueException && e.label === label) {
749
+ continue;
750
+ }
751
+ else if (e instanceof BreakException && e.label === label) {
752
+ break;
753
+ }
754
+ else {
755
+ throw e;
756
+ }
757
+ }
758
+ }
759
+ return null;
760
+ }
761
+ finally {
762
+ unlockForIteration(dict);
763
+ }
764
+ };
765
+ }
766
+ }
767
+ else if (ir.type === "Block") {
768
+ // The pattern of creating a new context (e.g. a function) and then immediately invoking a block (e.g. as the function body) is very common.
769
+ // Here we avoid creating a second context when possible, as an optimization.
770
+ if (fresh_ctx) {
771
+ let last_type = variant("Null", null);
772
+ const compiled_statements = [];
773
+ for (const statement of ir.value.statements) {
774
+ const compiled_statement = compile_internal(statement, ctx, platform, asyncPlatformFns, true, compilingNodes);
775
+ compiled_statements.push(compiled_statement);
776
+ last_type = statement.value.type;
777
+ }
778
+ if (!isSubtypeValue(last_type, ir.value.type)) {
779
+ throw new Error(`Block evaluates to type ${printTypeValue(last_type)} but expected ${printTypeValue(ir.value.type)} at ${printLocationValue(ir.value.location)}`);
780
+ }
781
+ if (ir.value.isAsync) {
782
+ return async (ctx) => {
783
+ let ret = null;
784
+ for (const statement of compiled_statements) {
785
+ ret = await statement(ctx);
786
+ }
787
+ return ret;
788
+ };
789
+ }
790
+ else {
791
+ return (ctx) => {
792
+ let ret = null;
793
+ for (const statement of compiled_statements) {
794
+ ret = statement(ctx);
795
+ }
796
+ return ret;
797
+ };
798
+ }
799
+ }
800
+ else {
801
+ const ctx2 = Object.create(ctx);
802
+ let last_type = variant("Null", null);
803
+ const compiled_statements = [];
804
+ for (const statement of ir.value.statements) {
805
+ const compiled_statement = compile_internal(statement, ctx2, platform, asyncPlatformFns, true, compilingNodes);
806
+ compiled_statements.push(compiled_statement);
807
+ last_type = statement.value.type;
808
+ }
809
+ if (!isSubtypeValue(last_type, ir.value.type)) {
810
+ throw new Error(`Block evaluates to type ${printTypeValue(last_type)} but expected ${printTypeValue(ir.value.type)} at ${printLocationValue(ir.value.location)}`);
811
+ }
812
+ if (ir.value.isAsync) {
813
+ return async (ctx) => {
814
+ const ctx2 = Object.create(ctx);
815
+ let ret = null;
816
+ for (const statement of compiled_statements) {
817
+ ret = await statement(ctx2);
818
+ }
819
+ return ret;
820
+ };
821
+ }
822
+ else {
823
+ return (ctx) => {
824
+ const ctx2 = Object.create(ctx);
825
+ let ret = null;
826
+ for (const statement of compiled_statements) {
827
+ ret = statement(ctx2);
828
+ }
829
+ return ret;
830
+ };
831
+ }
832
+ }
833
+ }
834
+ else if (ir.type === "GetField") {
835
+ if (ir.value.struct.value.type.type !== "Struct") {
836
+ throw new Error(`GetField expected Struct, got ${printTypeValue(ir.value.struct.value.type)} at ${printLocationValue(ir.value.location)}`);
837
+ }
838
+ const struct_field = expandTypeValue(ir.value.struct.value.type).value.find(f => f.name === ir.value.field);
839
+ if (!struct_field) {
840
+ throw new Error(`GetField field ${ir.value.field} not found in struct ${printTypeValue(ir.value.struct.value.type)} at ${printLocationValue(ir.value.location)}`);
841
+ }
842
+ if (!isTypeValueEqual(struct_field.type, ir.value.type)) {
843
+ throw new Error(`GetField expected to have type ${printTypeValue(ir.value.type)}, got ${printTypeValue(struct_field.type)} at ${printLocationValue(ir.value.location)}`);
844
+ }
845
+ const struct = compile_internal(ir.value.struct, ctx, platform, asyncPlatformFns, false, compilingNodes);
846
+ const field = ir.value.field;
847
+ if (ir.value.isAsync) {
848
+ return async (ctx) => (await struct(ctx))[field];
849
+ }
850
+ else {
851
+ return (ctx) => struct(ctx)[field];
852
+ }
853
+ }
854
+ else if (ir.type === "Struct") {
855
+ if (ir.value.type.type !== "Struct") {
856
+ throw new Error(`Expected Struct output type, got ${printTypeValue(ir.value.type)} at ${printLocationValue(ir.value.location)}`);
857
+ }
858
+ const fields = ir.value.fields.map((f, i) => {
859
+ const struct_field = expandTypeValue(ir.value.type).value[i];
860
+ if (!struct_field || struct_field.name !== f.name) {
861
+ throw new Error(`Struct field ${f.name} not found at position ${i} in struct type ${printTypeValue(ir.value.type)} at ${printLocationValue(ir.value.location)}`);
862
+ }
863
+ if (!isSubtypeValue(f.value.value.type, struct_field.type)) {
864
+ throw new Error(`Struct field ${f.name} expected to have type ${printTypeValue(struct_field.type)}, got ${printTypeValue(f.value.value.type)} at ${printLocationValue(ir.value.location)}`);
865
+ }
866
+ return compile_internal(f.value, ctx, platform, asyncPlatformFns, false, compilingNodes);
867
+ });
868
+ const keys = ir.value.fields.map(f => f.name);
869
+ if (ir.value.isAsync) {
870
+ return async (ctx) => {
871
+ const fs = [];
872
+ for (const [i, a] of fields.entries()) {
873
+ fs.push([keys[i], await a(ctx)]);
874
+ }
875
+ return Object.fromEntries(fs);
876
+ };
877
+ }
878
+ else {
879
+ return (ctx) => Object.fromEntries(fields.map((a, i) => [keys[i], a(ctx)]));
880
+ }
881
+ }
882
+ else if (ir.type === "Variant") {
883
+ if (ir.value.type.type !== "Variant") {
884
+ throw new Error(`Expected Variant output type, got ${printTypeValue(ir.value.type)} at ${printLocationValue(ir.value.location)}`);
885
+ }
886
+ const k = ir.value.case;
887
+ const variant_case = expandTypeValue(ir.value.type).value.find(c => c.name === k);
888
+ if (!variant_case) {
889
+ throw new Error(`Variant case ${k} not found in variant type ${printTypeValue(ir.value.type)} at ${printLocationValue(ir.value.location)}`);
890
+ }
891
+ if (!isSubtypeValue(ir.value.value.value.type, variant_case.type)) {
892
+ throw new Error(`Variant case ${k} expected to have type ${printTypeValue(variant_case.type)}, got ${printTypeValue(ir.value.value.value.type)} at ${printLocationValue(ir.value.location)}`);
893
+ }
894
+ const v = compile_internal(ir.value.value, ctx, platform, asyncPlatformFns, false, compilingNodes);
895
+ if (ir.value.isAsync) {
896
+ return async (ctx) => variant(k, await v(ctx));
897
+ }
898
+ else {
899
+ return (ctx) => variant(k, v(ctx));
900
+ }
901
+ }
902
+ else if (ir.type === "NewRef") {
903
+ if (ir.value.type.type !== "Ref") {
904
+ throw new Error(`Expected Ref output type, got ${printTypeValue(ir.value.type)} at ${printLocationValue(ir.value.location)}`);
905
+ }
906
+ if (!isSubtypeValue(ir.value.value.value.type, expandTypeValue(ir.value.type).value)) {
907
+ throw new Error(`NewRef value expected to have type ${printTypeValue(ir.value.type.value)}, got ${printTypeValue(ir.value.value.value.type)} at ${printLocationValue(ir.value.location)}`);
908
+ }
909
+ const value = compile_internal(ir.value.value, ctx, platform, asyncPlatformFns, false, compilingNodes);
910
+ if (ir.value.isAsync) {
911
+ return async (ctx) => ref(await value(ctx));
912
+ }
913
+ else {
914
+ return (ctx) => ref(value(ctx));
915
+ }
916
+ }
917
+ else if (ir.type === "NewArray") {
918
+ if (ir.value.type.type !== "Array") {
919
+ throw new Error(`Expected Array output type, got ${printTypeValue(ir.value.type)} at ${printLocationValue(ir.value.location)}`);
920
+ }
921
+ const values = ir.value.values.map(a => {
922
+ if (!isSubtypeValue(a.value.type, expandTypeValue(ir.value.type).value)) {
923
+ throw new Error(`NewArray element expected to have type ${printTypeValue(ir.value.type.value)}, got ${printTypeValue(a.value.type)} at ${printLocationValue(ir.value.location)}`);
924
+ }
925
+ return compile_internal(a, ctx, platform, asyncPlatformFns, false, compilingNodes);
926
+ });
927
+ if (ir.value.isAsync) {
928
+ return async (ctx) => {
929
+ let vals = [];
930
+ for (const a of values) {
931
+ vals.push(await a(ctx));
932
+ }
933
+ return vals;
934
+ };
935
+ }
936
+ else {
937
+ return (ctx) => values.map(a => a(ctx));
938
+ }
939
+ }
940
+ else if (ir.type === "NewSet") {
941
+ if (ir.value.type.type !== "Set") {
942
+ throw new Error(`Expected Set output type, got ${printTypeValue(ir.value.type)} at ${printLocationValue(ir.value.location)}`);
943
+ }
944
+ const values = ir.value.values.map(a => {
945
+ if (!isSubtypeValue(a.value.type, expandTypeValue(ir.value.type).value)) {
946
+ throw new Error(`NewSet element expected to have type ${printTypeValue(ir.value.type.value)}, got ${printTypeValue(a.value.type)} at ${printLocationValue(ir.value.location)}`);
947
+ }
948
+ return compile_internal(a, ctx, platform, asyncPlatformFns, false, compilingNodes);
949
+ });
950
+ const keyComparer = compareFor(ir.value.type.value);
951
+ if (ir.value.isAsync) {
952
+ return (ctx) => {
953
+ const keys = [];
954
+ for (const a of values) {
955
+ keys.push(a(ctx));
956
+ }
957
+ return new SortedSet(keys, keyComparer);
958
+ };
959
+ }
960
+ else {
961
+ return (ctx) => new SortedSet(values.map(a => a(ctx)), keyComparer);
962
+ }
963
+ }
964
+ else if (ir.type === "NewDict") {
965
+ if (ir.value.type.type !== "Dict") {
966
+ throw new Error(`Expected Dict output type, got ${printTypeValue(ir.value.type)} at ${printLocationValue(ir.value.location)}`);
967
+ }
968
+ const values = ir.value.values.map(({ key, value }) => {
969
+ if (!isSubtypeValue(key.value.type, expandTypeValue(ir.value.type).value.key)) {
970
+ throw new Error(`NewDict key expected to have type ${printTypeValue(ir.value.type.value.key)}, got ${printTypeValue(key.value.type)} at ${printLocationValue(ir.value.location)}`);
971
+ }
972
+ if (!isSubtypeValue(value.value.type, expandTypeValue(ir.value.type).value.value)) {
973
+ throw new Error(`NewDict value expected to have type ${printTypeValue(ir.value.type.value.value)}, got ${printTypeValue(value.value.type)} at ${printLocationValue(ir.value.location)}`);
974
+ }
975
+ return [compile_internal(key, ctx, platform, asyncPlatformFns, false, compilingNodes), compile_internal(value, ctx, platform, asyncPlatformFns, false, compilingNodes)];
976
+ });
977
+ const keyComparer = compareFor(ir.value.type.value.key);
978
+ if (ir.value.isAsync) {
979
+ return async (ctx) => {
980
+ const entries = [];
981
+ for (const [k, v] of values) {
982
+ entries.push([await k(ctx), await v(ctx)]);
983
+ }
984
+ return new SortedMap(entries, keyComparer);
985
+ };
986
+ }
987
+ else {
988
+ return (ctx) => new SortedMap(values.map(([k, v]) => [k(ctx), v(ctx)]), keyComparer);
989
+ }
990
+ }
991
+ else if (ir.type === "Return") {
992
+ if (ir.value.type.type !== "Never") {
993
+ throw new Error(`Return must have Never type, got ${printTypeValue(ir.value.type)} at ${printLocationValue(ir.value.location)}`);
994
+ }
995
+ // TODO pipe through return type context so we can check it here
996
+ const compiled_value = compile_internal(ir.value.value, ctx, platform, asyncPlatformFns, false, compilingNodes);
997
+ if (ir.value.isAsync) {
998
+ return async (ctx) => {
999
+ throw new ReturnException(await compiled_value(ctx));
1000
+ };
1001
+ }
1002
+ else {
1003
+ return (ctx) => {
1004
+ throw new ReturnException(compiled_value(ctx));
1005
+ };
1006
+ }
1007
+ }
1008
+ else if (ir.type === "Continue") {
1009
+ if (ir.value.type.type !== "Never") {
1010
+ throw new Error(`Continue must have Never type, got ${printTypeValue(ir.value.type)} at ${printLocationValue(ir.value.location)}`);
1011
+ }
1012
+ const label = ir.value.label;
1013
+ // TODO pipe through local label context so we can check it here
1014
+ return (_ctx) => {
1015
+ throw new ContinueException(label.name);
1016
+ };
1017
+ }
1018
+ else if (ir.type === "Break") {
1019
+ if (ir.value.type.type !== "Never") {
1020
+ throw new Error(`Break must have Never type, got ${printTypeValue(ir.value.type)} at ${printLocationValue(ir.value.location)}`);
1021
+ }
1022
+ const label = ir.value.label;
1023
+ // TODO pipe through local label context so we can check it here
1024
+ return (_ctx) => {
1025
+ throw new BreakException(label.name);
1026
+ };
1027
+ }
1028
+ else if (ir.type === "Builtin") {
1029
+ // TODO - I haven't dealt with builtins implementations yet
1030
+ // check types match
1031
+ let b = Builtins[ir.value.builtin];
1032
+ if (b === undefined) {
1033
+ throw new Error(`Builtin ${JSON.stringify(ir.value.builtin)} not found at ${printLocationValue(ir.value.location)}`);
1034
+ }
1035
+ if (b.type_parameters.length !== ir.value.type_parameters.length) {
1036
+ throw new Error(`Builtin ${JSON.stringify(ir.value.builtin)} expected ${b.type_parameters.length} type parameters, got ${ir.value.type_parameters.length} type parameters at ${printLocationValue(ir.value.location)}`);
1037
+ }
1038
+ if (b.inputs.length !== ir.value.arguments.length) {
1039
+ throw new Error(`Builtin ${JSON.stringify(ir.value.builtin)} expected ${b.inputs.length} arguments, got ${ir.value.arguments.length} arguments at ${printLocationValue(ir.value.location)}`);
1040
+ }
1041
+ const type_params = new Map(b.type_parameters.map((T, i) => [T, ir.value.type_parameters[i]]));
1042
+ let argsAsync = false;
1043
+ const args = ir.value.arguments.map((a, _i) => {
1044
+ // TODO these checks seem to fail for some builtins - particularly comparisons with recursive types
1045
+ // The issue appears to be that the type parameters in ir.value.type_parameters have been expanded too much
1046
+ // The Expr machinery and UnionType are possibly places to investigate why the identity of types is getting lost (or else we might need a more structural, not identity-based, approach to toEastTypeValue)
1047
+ // The failures here do not cause faults, but it might make life harder for a static compiler
1048
+ // const builtin_arg_type = b.inputs[i]!;
1049
+ // const expected_type = applyTypeParameters(toEastTypeValue(builtin_arg_type), type_params);
1050
+ // TODO what is the semantics here in a static language? Should we use `As` here?
1051
+ // if (!isSubtypeValue(a.value.type, expected_type)) {
1052
+ // throw new Error(`Argument ${i+1} to builtin ${JSON.stringify(ir.value.builtin)} with type parameters [${ir.value.type_parameters.map(t => printTypeValue(t)).join(", ")}] expected to have type ${printTypeValue(expected_type)}, got ${printTypeValue(a.value.type)} at ${printLocationValue(a.value.location)}`)
1053
+ // }
1054
+ if (a.value.isAsync) {
1055
+ argsAsync = true;
1056
+ }
1057
+ return compile_internal(a, ctx, platform, asyncPlatformFns, false, compilingNodes);
1058
+ });
1059
+ const expected_output_type = applyTypeParameters(typeof b.output === "string" ? b.output : toEastTypeValue(b.output), type_params);
1060
+ // TODO what is the semantics here in a static language? Should we use `As` here? What about variance?
1061
+ if (!isTypeValueEqual(ir.value.type, expected_output_type)) {
1062
+ throw new Error(`Builtin ${JSON.stringify(ir.value.builtin)} output type expected to have type ${printTypeValue(expected_output_type)}, got ${printTypeValue(ir.value.type)} at ${printLocationValue(ir.value.location)}`);
1063
+ }
1064
+ // Special optimization for regex builtins with literal pattern/flags
1065
+ if ((ir.value.builtin === "RegexContains" || ir.value.builtin === "RegexIndexOf" || ir.value.builtin === "RegexReplace") &&
1066
+ ir.value.arguments[1]?.type === "Value" &&
1067
+ ir.value.arguments[2]?.type === "Value") {
1068
+ if (ir.value.arguments[1].value.value.type !== "String") {
1069
+ throw new Error(`Regex builtin pattern argument must be String literal at ${printLocationValue(ir.value.arguments[1].value.location)}`);
1070
+ }
1071
+ if (ir.value.arguments[2].value.value.type !== "String") {
1072
+ throw new Error(`Regex builtin flags argument must be String literal at ${printLocationValue(ir.value.arguments[2].value.location)}`);
1073
+ }
1074
+ // Compile regex once at closure compilation time
1075
+ const pattern = ir.value.arguments[1].value.value.value;
1076
+ const flags = ir.value.arguments[2].value.value.value;
1077
+ const textArg = args[0]; // Already compiled text argument
1078
+ if (ir.value.builtin === "RegexContains") {
1079
+ const compiledRegex = new RegExp(pattern, flags);
1080
+ return (ctx) => compiledRegex.test(textArg(ctx));
1081
+ }
1082
+ else if (ir.value.builtin === "RegexIndexOf") {
1083
+ const compiledRegex = new RegExp(pattern, flags);
1084
+ return (ctx) => {
1085
+ const text = textArg(ctx);
1086
+ const codeUnitIndex = text.search(compiledRegex);
1087
+ if (codeUnitIndex === -1)
1088
+ return -1n;
1089
+ // Convert code unit index to codepoint index
1090
+ let codepointIndex = 0;
1091
+ let codeUnitPos = 0;
1092
+ for (const char of text) {
1093
+ if (codeUnitPos === codeUnitIndex) {
1094
+ return BigInt(codepointIndex);
1095
+ }
1096
+ codeUnitPos += char.length;
1097
+ codepointIndex++;
1098
+ }
1099
+ return -1n;
1100
+ };
1101
+ }
1102
+ else { // RegexReplace
1103
+ // Precompile regex with global flag for replaceAll semantics
1104
+ const globalFlags = flags.includes('g') ? flags : flags + 'g';
1105
+ const compiledRegex = new RegExp(pattern, globalFlags);
1106
+ // Check if replacement is also constant for full optimization
1107
+ if (ir.value.arguments[3]?.type === "Value") {
1108
+ if (ir.value.arguments[3].value.value.type !== "String") {
1109
+ throw new Error(`RegexReplace builtin replacement argument must be String literal at ${printLocationValue(ir.value.arguments[3].value.location)}`);
1110
+ }
1111
+ // FULL OPTIMIZATION: Pattern, flags, and replacement are all constant
1112
+ const replacement = ir.value.arguments[3].value.value.value;
1113
+ // Validate replacement string: only allow $$, $1-$9, and $<
1114
+ // This is stricter than JavaScript's native behavior but provides clear, consistent semantics
1115
+ // and avoids backend-specific features like $&, $`, $'
1116
+ let i = 0;
1117
+ while (i < replacement.length) {
1118
+ const char = replacement[i];
1119
+ if (char === '$') {
1120
+ i += char.length;
1121
+ let char2 = replacement[i];
1122
+ if (char2 === undefined) {
1123
+ return (_ctx) => { throw new EastError(`invalid regex replacement string: unescaped $ at end of string`, { location: ir.value.arguments[3].value.location }); };
1124
+ }
1125
+ else if (char2 === '$') {
1126
+ i += 1;
1127
+ }
1128
+ else if (char2 >= '1' && char2 <= '9') {
1129
+ i += 1;
1130
+ char2 = replacement[i];
1131
+ while (char2 !== undefined && char2 >= '0' && char2 <= '9') {
1132
+ i += 1;
1133
+ char2 = replacement[i];
1134
+ }
1135
+ }
1136
+ else if (char2 === '<') {
1137
+ // Scan until closing >
1138
+ i += 1;
1139
+ const init_i = i;
1140
+ char2 = replacement[i];
1141
+ while (true) {
1142
+ if (char2 === undefined) {
1143
+ return (_ctx) => { throw new EastError(`invalid regex replacement string: unterminated group name in $<...>`, { location: ir.value.arguments[3].value.location }); };
1144
+ }
1145
+ if (char2 === '>') {
1146
+ break;
1147
+ }
1148
+ if (!((char2 >= '0' && char2 <= '9') || (char2 >= 'a' && char2 <= 'z') || (char2 >= 'A' && char2 <= 'Z') || char2 === '_')) {
1149
+ return (_ctx) => { throw new EastError(`invalid regex replacement string: invalid character ${JSON.stringify(char2)} in group name in $<...>`, { location: ir.value.arguments[3].value.location }); };
1150
+ }
1151
+ i += 1;
1152
+ char2 = replacement[i];
1153
+ }
1154
+ if (i === init_i) {
1155
+ return (_ctx) => { throw new EastError(`invalid regex replacement string: empty group name in $<>`, { location: ir.value.arguments[3].value.location }); };
1156
+ }
1157
+ i += 1; // for closing >
1158
+ }
1159
+ else {
1160
+ return (_ctx) => { throw new EastError(`invalid regex replacement string: unescaped $ at $${char2}`, { location: ir.value.arguments[3].value.location }); };
1161
+ }
1162
+ }
1163
+ else {
1164
+ i += char.length;
1165
+ }
1166
+ }
1167
+ return (ctx) => {
1168
+ const text = textArg(ctx);
1169
+ return text.replaceAll(compiledRegex, replacement);
1170
+ };
1171
+ }
1172
+ else {
1173
+ // PARTIAL OPTIMIZATION: Pattern and flags constant, replacement dynamic
1174
+ const replacementArg = args[3];
1175
+ return (ctx) => {
1176
+ const text = textArg(ctx);
1177
+ const replacement = replacementArg(ctx);
1178
+ // Validate replacement string: only allow $$, $1-$9, and $<
1179
+ // This is stricter than JavaScript's native behavior but provides clear, consistent semantics
1180
+ // and avoids backend-specific features like $&, $`, $'
1181
+ let i = 0;
1182
+ while (i < replacement.length) {
1183
+ const char = replacement[i];
1184
+ if (char === '$') {
1185
+ i += char.length;
1186
+ let char2 = replacement[i];
1187
+ if (char2 === undefined) {
1188
+ throw new EastError(`invalid regex replacement string: unescaped $ at end of string`, { location: ir.value.arguments[3].value.location });
1189
+ }
1190
+ else if (char2 === '$') {
1191
+ i += 1;
1192
+ }
1193
+ else if (char2 >= '1' && char2 <= '9') {
1194
+ i += 1;
1195
+ char2 = replacement[i];
1196
+ while (char2 !== undefined && char2 >= '0' && char2 <= '9') {
1197
+ i += 1;
1198
+ char2 = replacement[i];
1199
+ }
1200
+ }
1201
+ else if (char2 === '<') {
1202
+ // Scan until closing >
1203
+ i += 1;
1204
+ const init_i = i;
1205
+ char2 = replacement[i];
1206
+ while (true) {
1207
+ if (char2 === undefined) {
1208
+ throw new EastError(`invalid regex replacement string: unterminated group name in $<...>`, { location: ir.value.arguments[3].value.location });
1209
+ }
1210
+ if (char2 === '>') {
1211
+ break;
1212
+ }
1213
+ if (!((char2 >= '0' && char2 <= '9') || (char2 >= 'a' && char2 <= 'z') || (char2 >= 'A' && char2 <= 'Z') || char2 === '_')) {
1214
+ throw new EastError(`invalid regex replacement string: invalid character ${JSON.stringify(char2)} in group name in $<...>`, { location: ir.value.arguments[3].value.location });
1215
+ }
1216
+ i += 1;
1217
+ char2 = replacement[i];
1218
+ }
1219
+ if (i === init_i) {
1220
+ throw new EastError(`invalid regex replacement string: empty group name in $<>`, { location: ir.value.arguments[3].value.location });
1221
+ }
1222
+ i += 1; // for closing >
1223
+ }
1224
+ else {
1225
+ throw new EastError(`invalid regex replacement string: unescaped $ at $${char2}`, { location: ir.value.arguments[3].value.location });
1226
+ }
1227
+ }
1228
+ else {
1229
+ i += char.length;
1230
+ }
1231
+ }
1232
+ return text.replaceAll(compiledRegex, replacement);
1233
+ };
1234
+ }
1235
+ }
1236
+ }
1237
+ const evaluator = builtin_evaluators[ir.value.builtin](ir.value.location, ...ir.value.type_parameters);
1238
+ if (argsAsync) {
1239
+ return async (ctx) => {
1240
+ const args_resolved = [];
1241
+ for (const a of args) {
1242
+ args_resolved.push(await a(ctx));
1243
+ }
1244
+ return evaluator(...args_resolved);
1245
+ };
1246
+ }
1247
+ else {
1248
+ return (ctx) => evaluator(...args.map(a => a(ctx)));
1249
+ }
1250
+ }
1251
+ else if (ir.type === "Platform") {
1252
+ // TODO check types match (would require having the platform's expected types here)
1253
+ let argsAsync = false;
1254
+ const args = ir.value.arguments.map(a => {
1255
+ if (a.value.isAsync) {
1256
+ argsAsync = true;
1257
+ }
1258
+ return compile_internal(a, ctx, platform, asyncPlatformFns, false, compilingNodes);
1259
+ });
1260
+ const evaluator = platform[ir.value.name];
1261
+ if (evaluator === undefined) {
1262
+ throw new Error(`Evaluator for platform function ${JSON.stringify(ir.value.name)} not found at ${printLocationValue(ir.value.location)}`);
1263
+ }
1264
+ if (argsAsync) {
1265
+ return async (ctx) => {
1266
+ const args_resolved = [];
1267
+ for (const a of args) {
1268
+ args_resolved.push(await a(ctx));
1269
+ }
1270
+ return evaluator(...args_resolved);
1271
+ };
1272
+ }
1273
+ else {
1274
+ return (ctx) => evaluator(...args.map(a => a(ctx)));
1275
+ }
1276
+ }
1277
+ else {
1278
+ throw new Error(`Unhandled IR type ${ir.type} at ${printLocationValue(ir.value.location)}`); // The `satisfies never` here ensures that this branch is unreachable if all IR types are handled
1279
+ }
1280
+ }
1281
+ /** Used to call a compiled function with the given arguments and handle errors within builtin functions */
1282
+ function call_function(location, compiled_f, ...args) {
1283
+ try {
1284
+ return compiled_f(...args);
1285
+ }
1286
+ catch (e) {
1287
+ if (e instanceof ReturnException) {
1288
+ return e.value;
1289
+ }
1290
+ else if (e instanceof EastError) {
1291
+ e.location.push(location); // The fact that we need to push the call location not the definition location means we need to handle this here
1292
+ throw (e);
1293
+ }
1294
+ else if (e instanceof ContinueException) {
1295
+ throw new Error(`continue failed to find label ${e.label} at ${printLocationValue(location)}`);
1296
+ }
1297
+ else if (e instanceof BreakException) {
1298
+ throw new Error(`break failed to find label ${e.label} at ${printLocationValue(location)}`);
1299
+ }
1300
+ else {
1301
+ throw (e);
1302
+ }
1303
+ }
1304
+ }
1305
+ /** @internal */
1306
+ const builtin_evaluators = {
1307
+ Is: (_location, T) => isFor(T),
1308
+ Equal: (_location, T) => equalFor(T),
1309
+ NotEqual: (_location, T) => notEqualFor(T),
1310
+ Less: (_location, T) => lessFor(T),
1311
+ LessEqual: (_location, T) => lessEqualFor(T),
1312
+ Greater: (_location, T) => greaterFor(T),
1313
+ GreaterEqual: (_location, T) => greaterEqualFor(T),
1314
+ BooleanNot: (_location) => (x) => !x,
1315
+ BooleanOr: (_location) => (x, y) => x || y,
1316
+ BooleanAnd: (_location) => (x, y) => x && y,
1317
+ BooleanXor: (_location) => (x, y) => x !== y,
1318
+ IntegerToFloat: (_location) => (x) => Number(x),
1319
+ IntegerNegate: (_location) => (x) => BigInt.asIntN(64, -x),
1320
+ IntegerAdd: (_location) => (x, y) => BigInt.asIntN(64, x + y),
1321
+ IntegerSubtract: (_location) => (x, y) => BigInt.asIntN(64, x - y),
1322
+ IntegerMultiply: (_location) => (x, y) => BigInt.asIntN(64, x * y),
1323
+ IntegerDivide: (_location) => (x, y) => x === 0n ? 0n : x / y,
1324
+ IntegerRemainder: (_location) => (x, y) => x === 0n ? 0n : x % y,
1325
+ IntegerPow: (_location) => (x, y) => y >= 0n ? BigInt.asIntN(64, x ** y) : 0n,
1326
+ IntegerAbs: (_location) => (x) => BigInt.asIntN(64, x < 0n ? -x : x),
1327
+ IntegerSign: (_location) => (x) => x > 0n ? 1n : x < 0n ? -1n : 0n,
1328
+ IntegerLog: (_location) => (value, base) => {
1329
+ if (value === 0n)
1330
+ return 0n;
1331
+ if (base <= 1n)
1332
+ return 0n; // Invalid base
1333
+ let abs_value = value < 0n ? -value : value;
1334
+ let result = 0n;
1335
+ while (abs_value >= base) {
1336
+ abs_value = abs_value / base;
1337
+ result = result + 1n;
1338
+ }
1339
+ return result;
1340
+ },
1341
+ FloatToInteger: (location) => (x) => {
1342
+ if (Number.isNaN(x))
1343
+ throw new EastError("Cannot convert NaN to integer", { location });
1344
+ if (x >= 9223372036854775808)
1345
+ throw new EastError("Float too high to convert to integer", { location });
1346
+ if (x < -9223372036854775808)
1347
+ throw new EastError("Float too low to convert to integer", { location });
1348
+ if (!Number.isInteger(x)) {
1349
+ throw new EastError("Cannot convert non-integer float to integer", { location });
1350
+ }
1351
+ return BigInt(x);
1352
+ },
1353
+ FloatNegate: (_location) => (x) => -x,
1354
+ FloatAdd: (_location) => (x, y) => x + y,
1355
+ FloatSubtract: (_location) => (x, y) => x - y,
1356
+ FloatMultiply: (_location) => (x, y) => x * y,
1357
+ FloatDivide: (_location) => (x, y) => x / y,
1358
+ FloatRemainder: (_location) => (x, y) => x % y,
1359
+ FloatPow: (_location) => (x, y) => x ** y,
1360
+ FloatAbs: (_location) => (x) => x < 0 ? -x : x,
1361
+ FloatSign: (_location) => (x) => x > 0 ? 1 : x < 0 ? -1 : 0, // What sign is NaN?
1362
+ FloatSqrt: (_location) => (value) => Math.sqrt(value),
1363
+ FloatLog: (_location) => (value) => Math.log(value),
1364
+ FloatExp: (_location) => (value) => Math.exp(value),
1365
+ FloatSin: (_location) => (value) => Math.sin(value),
1366
+ FloatCos: (_location) => (value) => Math.cos(value),
1367
+ FloatTan: (_location) => (value) => Math.tan(value),
1368
+ Print: (_location, T) => {
1369
+ return printFor(T);
1370
+ },
1371
+ Parse: (location, T) => {
1372
+ const p = parseFor(T);
1373
+ return (x) => {
1374
+ const result = p(x);
1375
+ if (result.success) {
1376
+ return result.value;
1377
+ }
1378
+ else {
1379
+ throw new EastError(`Failed to parse ${printTypeValue(T)} at ${result.position}: ${result.error}`, { location });
1380
+ }
1381
+ };
1382
+ },
1383
+ StringConcat: (_location) => (x, y) => x + y,
1384
+ StringRepeat: (_location) => (x, y) => y > 0n ? x.repeat(Number(y)) : "",
1385
+ StringLength: (_location) => (x) => {
1386
+ let len = 0;
1387
+ for (const _ of x)
1388
+ len++;
1389
+ return BigInt(len);
1390
+ },
1391
+ StringSubstring: (_location) => (x, from, to) => {
1392
+ // Convert bigint indices to numbers, handle forgiving semantics like JavaScript
1393
+ let fromNum = Number(from);
1394
+ let toNum = Number(to);
1395
+ // Handle negative indices and lengths (forgiving semantics)
1396
+ if (fromNum < 0)
1397
+ fromNum = 0;
1398
+ if (toNum < 0)
1399
+ toNum = 0;
1400
+ if (fromNum > toNum) {
1401
+ toNum = fromNum;
1402
+ }
1403
+ // Convert codepoint indices to code unit indices
1404
+ let codeUnitFrom = 0;
1405
+ let codeUnitTo = 0;
1406
+ let codepointIndex = 0;
1407
+ for (const char of x) {
1408
+ if (codepointIndex === fromNum) {
1409
+ codeUnitFrom = codeUnitTo;
1410
+ }
1411
+ if (codepointIndex === toNum) {
1412
+ break;
1413
+ }
1414
+ codeUnitTo += char.length;
1415
+ codepointIndex++;
1416
+ }
1417
+ // If 'from' is beyond string length, return empty string
1418
+ if (fromNum >= codepointIndex)
1419
+ return "";
1420
+ // If 'to' is beyond string length, use string end
1421
+ if (toNum > codepointIndex) {
1422
+ codeUnitTo = x.length;
1423
+ }
1424
+ return x.substring(codeUnitFrom, codeUnitTo);
1425
+ },
1426
+ StringUpperCase: (_location) => (x) => x.toUpperCase(),
1427
+ StringLowerCase: (_location) => (x) => x.toLowerCase(),
1428
+ StringSplit: (_location) => (x, delimiter) => {
1429
+ if (delimiter === "") {
1430
+ if (x === "") {
1431
+ // Split always returns at least one element
1432
+ return [""];
1433
+ }
1434
+ else {
1435
+ // Split into individual codepoints
1436
+ return [...x];
1437
+ }
1438
+ }
1439
+ return x.split(delimiter);
1440
+ },
1441
+ StringTrim: (_location) => (x) => x.trim(),
1442
+ StringTrimStart: (_location) => (x) => x.trimStart(),
1443
+ StringTrimEnd: (_location) => (x) => x.trimEnd(),
1444
+ StringStartsWith: (_location) => (x, prefix) => x.startsWith(prefix),
1445
+ StringEndsWith: (_location) => (x, suffix) => x.endsWith(suffix),
1446
+ StringContains: (_location) => (x, substring) => x.includes(substring),
1447
+ StringIndexOf: (_location) => (x, substring) => {
1448
+ const codeUnitIndex = x.indexOf(substring);
1449
+ if (codeUnitIndex === -1)
1450
+ return -1n;
1451
+ // Special case for empty substring - it's always found at position 0
1452
+ if (substring === "")
1453
+ return BigInt(codeUnitIndex);
1454
+ // Convert code unit index to codepoint index
1455
+ let codepointIndex = 0;
1456
+ let codeUnitPos = 0;
1457
+ for (const char of x) {
1458
+ if (codeUnitPos === codeUnitIndex) {
1459
+ return BigInt(codepointIndex);
1460
+ }
1461
+ codeUnitPos += char.length;
1462
+ codepointIndex++;
1463
+ }
1464
+ return -1n;
1465
+ },
1466
+ StringReplace: (_location) => (x, searchValue, replaceValue) => {
1467
+ // Replace all occurrences (like JavaScript's string.replaceAll with string)
1468
+ return x.replaceAll(searchValue, replaceValue);
1469
+ },
1470
+ RegexContains: (_location) => (text, pattern, flags) => {
1471
+ const regex = new RegExp(pattern, flags);
1472
+ return regex.test(text);
1473
+ },
1474
+ RegexIndexOf: (_location) => (text, pattern, flags) => {
1475
+ const regex = new RegExp(pattern, flags);
1476
+ const codeUnitIndex = text.search(regex);
1477
+ if (codeUnitIndex === -1)
1478
+ return -1n;
1479
+ // Convert code unit index to codepoint index
1480
+ let codepointIndex = 0;
1481
+ let codeUnitPos = 0;
1482
+ for (const char of text) {
1483
+ if (codeUnitPos === codeUnitIndex) {
1484
+ return BigInt(codepointIndex);
1485
+ }
1486
+ codeUnitPos += char.length;
1487
+ codepointIndex++;
1488
+ }
1489
+ return -1n;
1490
+ },
1491
+ RegexReplace: (location) => (text, pattern, flags, replacement) => {
1492
+ // Ensure global flag is set for replaceAll semantics
1493
+ const globalFlags = flags.includes('g') ? flags : flags + 'g';
1494
+ const regex = new RegExp(pattern, globalFlags);
1495
+ // Validate replacement string: only allow $$, $1-$9, and $<
1496
+ // This is stricter than JavaScript's native behavior but provides clear, consistent semantics
1497
+ // and avoids backend-specific features like $&, $`, $'
1498
+ let i = 0;
1499
+ while (i < replacement.length) {
1500
+ const char = replacement[i];
1501
+ if (char === '$') {
1502
+ i += char.length;
1503
+ let char2 = replacement[i];
1504
+ if (char2 === undefined) {
1505
+ throw new EastError(`invalid regex replacement string: unescaped $ at end of string`, { location });
1506
+ }
1507
+ else if (char2 === '$') {
1508
+ i += 1;
1509
+ }
1510
+ else if (char2 >= '1' && char2 <= '9') {
1511
+ i += 1;
1512
+ char2 = replacement[i];
1513
+ while (char2 !== undefined && char2 >= '0' && char2 <= '9') {
1514
+ i += 1;
1515
+ char2 = replacement[i];
1516
+ }
1517
+ }
1518
+ else if (char2 === '<') {
1519
+ // Scan until closing >
1520
+ i += 1;
1521
+ const init_i = i;
1522
+ char2 = replacement[i];
1523
+ while (true) {
1524
+ if (char2 === undefined) {
1525
+ throw new EastError(`invalid regex replacement string: unterminated group name in $<...>`, { location });
1526
+ }
1527
+ if (char2 === '>') {
1528
+ break;
1529
+ }
1530
+ if (!((char2 >= '0' && char2 <= '9') || (char2 >= 'a' && char2 <= 'z') || (char2 >= 'A' && char2 <= 'Z') || char2 === '_')) {
1531
+ throw new EastError(`invalid regex replacement string: invalid character ${JSON.stringify(char2)} in group name in $<...>`, { location });
1532
+ }
1533
+ i += 1;
1534
+ char2 = replacement[i];
1535
+ }
1536
+ if (i === init_i) {
1537
+ throw new EastError(`invalid regex replacement string: empty group name in $<>`, { location });
1538
+ }
1539
+ i += 1; // for closing >
1540
+ }
1541
+ else {
1542
+ throw new EastError(`invalid regex replacement string: unescaped $ at $${char2}`, { location });
1543
+ }
1544
+ }
1545
+ else {
1546
+ i += char.length;
1547
+ }
1548
+ }
1549
+ return text.replaceAll(regex, replacement);
1550
+ },
1551
+ StringEncodeUtf8: (_location) => {
1552
+ // do not add BOM for UTF-8
1553
+ const encoder = new TextEncoder();
1554
+ return (x) => {
1555
+ return encoder.encode(x);
1556
+ };
1557
+ },
1558
+ StringEncodeUtf16: (_location) => {
1559
+ // always use little-endian with BOM (most common in practice)
1560
+ return (x) => {
1561
+ const buffer = new BufferWriter();
1562
+ buffer.writeUint8(0xFF);
1563
+ buffer.writeUint8(0xFE);
1564
+ for (let i = 0; i < x.length; i++) {
1565
+ const codeUnit = x.charCodeAt(i);
1566
+ buffer.writeUint16LE(codeUnit);
1567
+ }
1568
+ return buffer.toUint8Array();
1569
+ };
1570
+ },
1571
+ StringParseJSON: (location, type) => {
1572
+ const fromJSON = fromJSONFor(type);
1573
+ return (x) => {
1574
+ let parsed;
1575
+ try {
1576
+ parsed = JSON.parse(x);
1577
+ }
1578
+ catch (e) {
1579
+ throw new EastError(`Failed to parse JSON: ${e.message}`, { location });
1580
+ }
1581
+ try {
1582
+ return fromJSON(parsed);
1583
+ }
1584
+ catch (e) {
1585
+ throw new EastError(`Failed to convert JSON to ${printTypeValue(type)}: ${e.message}`, { location });
1586
+ }
1587
+ };
1588
+ },
1589
+ StringPrintJSON: (_location, type) => {
1590
+ const toJSON = toJSONFor(type);
1591
+ return (x) => JSON.stringify(toJSON(x));
1592
+ },
1593
+ DateTimeGetYear: (_location) => (date) => BigInt(date.getUTCFullYear()),
1594
+ DateTimeGetMonth: (_location) => (date) => BigInt(date.getUTCMonth() + 1), // JavaScript months are 0-based, East uses 1-based
1595
+ DateTimeGetDayOfMonth: (_location) => (date) => BigInt(date.getUTCDate()),
1596
+ DateTimeGetHour: (_location) => (date) => BigInt(date.getUTCHours()),
1597
+ DateTimeGetMinute: (_location) => (date) => BigInt(date.getUTCMinutes()),
1598
+ DateTimeGetSecond: (_location) => (date) => BigInt(date.getUTCSeconds()),
1599
+ DateTimeGetDayOfWeek: (_location) => (date) => {
1600
+ const jsDay = date.getUTCDay(); // JavaScript: 0=Sunday, 1=Monday, ..., 6=Saturday
1601
+ return BigInt(jsDay === 0 ? 7 : jsDay); // ISO 8601: 1=Monday, 2=Tuesday, ..., 7=Sunday
1602
+ },
1603
+ DateTimeGetMillisecond: (_location) => (date) => BigInt(date.getUTCMilliseconds()),
1604
+ DateTimeAddMilliseconds: (_location) => (date, milliseconds) => new Date(date.getTime() + Number(milliseconds)),
1605
+ DateTimeDurationMilliseconds: (_location) => (date1, date2) => BigInt(date1.getTime() - date2.getTime()),
1606
+ DateTimeToEpochMilliseconds: (_location) => (date) => BigInt(date.getTime()),
1607
+ DateTimeFromEpochMilliseconds: (_location) => (milliseconds) => new Date(Number(milliseconds)),
1608
+ DateTimeFromComponents: (_location) => (year, month, day, hour, minute, second, millisecond) => new Date(Date.UTC(Number(year), Number(month) - 1, Number(day), Number(hour), Number(minute), Number(second), Number(millisecond))),
1609
+ DateTimePrintFormat: (_location) => (date, tokens) => {
1610
+ return formatDateTime(date, tokens);
1611
+ },
1612
+ DateTimeParseFormat: (location) => (str, tokens) => {
1613
+ const result = parseDateTimeFormatted(str, tokens);
1614
+ if (result.success) {
1615
+ return result.value;
1616
+ }
1617
+ else {
1618
+ throw new EastError(`Failed to parse datetime at position ${result.position}: ${result.error}`, { location });
1619
+ }
1620
+ },
1621
+ BlobSize: (_location) => (data) => BigInt(data.length),
1622
+ BlobGetUint8: (location) => (data, index) => {
1623
+ const i = Number(index);
1624
+ if (i < 0 || i >= data.length) {
1625
+ throw new EastError(`Blob index ${index} out of bounds`, { location });
1626
+ }
1627
+ else {
1628
+ return BigInt(data[i]);
1629
+ }
1630
+ },
1631
+ BlobDecodeUtf8: (location) => {
1632
+ const decoder = new TextDecoder('utf-8', { fatal: true });
1633
+ return (data) => {
1634
+ try {
1635
+ return decoder.decode(data);
1636
+ }
1637
+ catch {
1638
+ throw new EastError("Blob is not valid UTF-8", { location });
1639
+ }
1640
+ };
1641
+ },
1642
+ BlobDecodeUtf16: (location) => {
1643
+ const decoder_be = new TextDecoder('utf-16be', { fatal: true });
1644
+ const decoder_le = new TextDecoder('utf-16le', { fatal: true });
1645
+ return (data) => {
1646
+ try {
1647
+ if (data.length >= 2) {
1648
+ // Check for BOM
1649
+ if (data[0] === 0xFE && data[1] === 0xFF) {
1650
+ // Big-endian BOM
1651
+ return decoder_be.decode(data.subarray(2));
1652
+ }
1653
+ else if (data[0] === 0xFF && data[1] === 0xFE) {
1654
+ // Little-endian BOM
1655
+ return decoder_le.decode(data.subarray(2));
1656
+ }
1657
+ }
1658
+ // No BOM, default to little-endian (not unicode spec compliant, but more common in practice)
1659
+ return decoder_le.decode(data);
1660
+ }
1661
+ catch {
1662
+ throw new EastError("Blob is not valid UTF-16", { location });
1663
+ }
1664
+ };
1665
+ },
1666
+ BlobEncodeBeast: (_location, type) => {
1667
+ const encodeBeast = encodeBeastFor(type);
1668
+ return (value) => {
1669
+ return encodeBeast(value);
1670
+ };
1671
+ },
1672
+ BlobDecodeBeast: (location, type) => {
1673
+ const decodeBeast = decodeBeastFor(type);
1674
+ return (data) => {
1675
+ try {
1676
+ return decodeBeast(data);
1677
+ }
1678
+ catch (e) {
1679
+ throw new EastError(`Failed to decode Beast data: ${e.message}`, { location });
1680
+ }
1681
+ };
1682
+ },
1683
+ BlobEncodeBeast2: (_location, type) => {
1684
+ const encodeBeast2 = encodeBeast2For(type);
1685
+ return (value) => {
1686
+ return encodeBeast2(value);
1687
+ };
1688
+ },
1689
+ BlobDecodeBeast2: (location, type) => {
1690
+ const decodeBeast2 = decodeBeast2For(type);
1691
+ return (data) => {
1692
+ try {
1693
+ return decodeBeast2(data);
1694
+ }
1695
+ catch (e) {
1696
+ throw new EastError(`Failed to decode Beast2 data: ${e.message}`, { location });
1697
+ }
1698
+ };
1699
+ },
1700
+ RefGet: (_location, _T) => (ref) => {
1701
+ return ref.value;
1702
+ },
1703
+ RefUpdate: (location, _T) => (ref, value) => {
1704
+ if (Object.isFrozen(ref)) {
1705
+ throw new EastError("Cannot modify frozen Ref", { location });
1706
+ }
1707
+ ref.value = value;
1708
+ return null;
1709
+ },
1710
+ RefMerge: (location, _T) => (ref, value, merger) => {
1711
+ if (Object.isFrozen(ref)) {
1712
+ throw new EastError("Cannot modify frozen Ref", { location });
1713
+ }
1714
+ const new_value = call_function(location, merger, ref.value, value);
1715
+ ref.value = new_value;
1716
+ return null;
1717
+ },
1718
+ ArrayGenerate: (location, _T) => (size, f) => {
1719
+ const result = [];
1720
+ for (let i = 0n; i < size; i += 1n) {
1721
+ const v = call_function(location, f, i);
1722
+ result.push(v);
1723
+ }
1724
+ return result;
1725
+ },
1726
+ ArrayRange: (_location) => (start, end, step) => {
1727
+ const result = [];
1728
+ if (step === 0n) {
1729
+ return result; // empty array
1730
+ }
1731
+ else if (step > 0n) {
1732
+ for (let i = start; i < end; i += step) {
1733
+ result.push(i);
1734
+ }
1735
+ }
1736
+ else { // step < 0
1737
+ for (let i = start; i > end; i += step) {
1738
+ result.push(i);
1739
+ }
1740
+ }
1741
+ return result;
1742
+ },
1743
+ ArrayLinspace: (_location) => (start, end, size) => {
1744
+ const result = [];
1745
+ if (size <= 0n) {
1746
+ return result; // empty array
1747
+ }
1748
+ else if (size === 1n) {
1749
+ return [start];
1750
+ }
1751
+ else {
1752
+ const step = (end - start) / Number(size - 1n);
1753
+ for (let i = 0n; i < size; i += 1n) {
1754
+ result.push(start + Number(i) * step);
1755
+ }
1756
+ }
1757
+ return result;
1758
+ },
1759
+ ArraySize: (_location, _T) => (array) => BigInt(array.length),
1760
+ ArrayHas: (_location, _T) => (array, key) => {
1761
+ const i = Number(key);
1762
+ return i >= 0 && i < array.length;
1763
+ },
1764
+ ArrayGet: (location, _T) => (array, key) => {
1765
+ const i = Number(key);
1766
+ if (i < 0 || i >= array.length) {
1767
+ throw new EastError(`Array index ${key} out of bounds`, { location });
1768
+ }
1769
+ else {
1770
+ return array[i];
1771
+ }
1772
+ },
1773
+ ArrayGetOrDefault: (location, _T) => (array, key, defaultFn) => {
1774
+ const i = Number(key);
1775
+ if (i < 0 || i >= array.length) {
1776
+ return call_function(location, defaultFn, key);
1777
+ }
1778
+ else {
1779
+ return array[i];
1780
+ }
1781
+ },
1782
+ ArrayTryGet: (_location, _T) => (array, key) => {
1783
+ const i = Number(key);
1784
+ if (i < 0 || i >= array.length) {
1785
+ return variant("none", null);
1786
+ }
1787
+ else {
1788
+ return variant("some", array[i]);
1789
+ }
1790
+ },
1791
+ ArrayUpdate: (location, _T) => (array, key, value) => {
1792
+ if (Object.isFrozen(array)) {
1793
+ throw new EastError("Cannot modify frozen Array", { location });
1794
+ }
1795
+ const i = Number(key);
1796
+ if (i < 0 || i >= array.length) {
1797
+ throw new EastError(`Array index ${key} out of bounds`, { location });
1798
+ }
1799
+ else {
1800
+ array[i] = value;
1801
+ return null;
1802
+ }
1803
+ },
1804
+ ArrayMerge: (location, _T) => (array, key, value, merger) => {
1805
+ if (Object.isFrozen(array)) {
1806
+ throw new EastError("Cannot modify frozen Array", { location });
1807
+ }
1808
+ const i = Number(key);
1809
+ if (i < 0 || i >= array.length) {
1810
+ throw new EastError(`Array index ${key} out of bounds`, { location });
1811
+ }
1812
+ else {
1813
+ const new_value = call_function(location, merger, array[i], value, key);
1814
+ array[i] = new_value;
1815
+ return null;
1816
+ }
1817
+ },
1818
+ ArrayPushLast: (location, _T) => (array, value) => {
1819
+ if (Object.isFrozen(array)) {
1820
+ throw new EastError("Cannot modify frozen Array", { location });
1821
+ }
1822
+ if ((iterationLocks.get(array) || 0) > 0) {
1823
+ throw new EastError("Cannot modify Array during iteration", { location });
1824
+ }
1825
+ array.push(value);
1826
+ return null;
1827
+ },
1828
+ ArrayPopLast: (location, _T) => (array) => {
1829
+ if (Object.isFrozen(array)) {
1830
+ throw new EastError("Cannot modify frozen Array", { location });
1831
+ }
1832
+ if ((iterationLocks.get(array) || 0) > 0) {
1833
+ throw new EastError("Cannot modify Array during iteration", { location });
1834
+ }
1835
+ if (array.length === 0) {
1836
+ throw new EastError("Cannot pop from empty Array", { location });
1837
+ }
1838
+ else {
1839
+ return array.pop();
1840
+ }
1841
+ },
1842
+ ArrayPushFirst: (location, _T) => (array, value) => {
1843
+ if (Object.isFrozen(array)) {
1844
+ throw new EastError("Cannot modify frozen Array", { location });
1845
+ }
1846
+ if ((iterationLocks.get(array) || 0) > 0) {
1847
+ throw new EastError("Cannot modify Array during iteration", { location });
1848
+ }
1849
+ array.unshift(value);
1850
+ return null;
1851
+ },
1852
+ ArrayPopFirst: (location, _T) => (array) => {
1853
+ if (Object.isFrozen(array)) {
1854
+ throw new EastError("Cannot modify frozen Array", { location });
1855
+ }
1856
+ if ((iterationLocks.get(array) || 0) > 0) {
1857
+ throw new EastError("Cannot modify Array during iteration", { location });
1858
+ }
1859
+ if (array.length === 0) {
1860
+ throw new EastError("Cannot pop from empty Array", { location });
1861
+ }
1862
+ else {
1863
+ return array.shift();
1864
+ }
1865
+ },
1866
+ ArrayAppend: (location, _T) => (array, other) => {
1867
+ if (Object.isFrozen(array)) {
1868
+ throw new EastError("Cannot modify frozen Array", { location });
1869
+ }
1870
+ if ((iterationLocks.get(array) || 0) > 0) {
1871
+ throw new EastError("Cannot modify Array during iteration", { location });
1872
+ }
1873
+ array.push(...other);
1874
+ return null;
1875
+ },
1876
+ ArrayPrepend: (location, _T) => (array, other) => {
1877
+ if (Object.isFrozen(array)) {
1878
+ throw new EastError("Cannot modify frozen Array", { location });
1879
+ }
1880
+ if ((iterationLocks.get(array) || 0) > 0) {
1881
+ throw new EastError("Cannot modify Array during iteration", { location });
1882
+ }
1883
+ array.unshift(...other);
1884
+ return null;
1885
+ },
1886
+ ArrayMergeAll: (location, _T, _T2) => (array, other, merger) => {
1887
+ if (Object.isFrozen(array)) {
1888
+ throw new EastError("Cannot modify frozen Array", { location });
1889
+ }
1890
+ lockForIteration(array);
1891
+ lockForIteration(other);
1892
+ try {
1893
+ for (let i = 0; i < other.length; i++) {
1894
+ const key = BigInt(i);
1895
+ if (i < array.length) {
1896
+ const new_value = call_function(location, merger, array[i], other[i], key);
1897
+ array[i] = new_value;
1898
+ }
1899
+ else {
1900
+ throw new EastError(`Array index ${key} out of bounds`, { location });
1901
+ }
1902
+ }
1903
+ }
1904
+ finally {
1905
+ unlockForIteration(other);
1906
+ unlockForIteration(array);
1907
+ }
1908
+ return null;
1909
+ },
1910
+ ArrayClear: (location, _T) => (array) => {
1911
+ if (Object.isFrozen(array)) {
1912
+ throw new EastError("Cannot modify frozen Array", { location });
1913
+ }
1914
+ if ((iterationLocks.get(array) || 0) > 0) {
1915
+ throw new EastError("Cannot modify Array during iteration", { location });
1916
+ }
1917
+ array.length = 0;
1918
+ return null;
1919
+ },
1920
+ ArraySortInPlace: (location, T, T2) => (array, by) => {
1921
+ if (Object.isFrozen(array)) {
1922
+ throw new EastError("Cannot modify frozen Array", { location });
1923
+ }
1924
+ if ((iterationLocks.get(array) || 0) > 0) {
1925
+ throw new EastError("Cannot modify Array during iteration", { location });
1926
+ }
1927
+ lockForIteration(array);
1928
+ try {
1929
+ const cmp = compareFor(T2);
1930
+ array.sort((a, b) => {
1931
+ const projectedA = call_function(location, by, a);
1932
+ const projectedB = call_function(location, by, b);
1933
+ return cmp(projectedA, projectedB);
1934
+ });
1935
+ }
1936
+ finally {
1937
+ unlockForIteration(array);
1938
+ }
1939
+ return null;
1940
+ },
1941
+ ArrayReverseInPlace: (location, _T) => (array) => {
1942
+ if (Object.isFrozen(array)) {
1943
+ throw new EastError("Cannot modify frozen Array", { location });
1944
+ }
1945
+ if ((iterationLocks.get(array) || 0) > 0) {
1946
+ throw new EastError("Cannot modify Array during iteration", { location });
1947
+ }
1948
+ array.reverse();
1949
+ return null;
1950
+ },
1951
+ ArraySort: (location, T, T2) => (array, by) => {
1952
+ const cmp = compareFor(T2);
1953
+ const newArray = [...array];
1954
+ newArray.sort((a, b) => {
1955
+ const projectedA = call_function(location, by, a);
1956
+ const projectedB = call_function(location, by, b);
1957
+ return cmp(projectedA, projectedB);
1958
+ });
1959
+ return newArray;
1960
+ },
1961
+ ArrayReverse: (_location, _T) => (array) => {
1962
+ const newArray = [...array];
1963
+ newArray.reverse();
1964
+ return newArray;
1965
+ },
1966
+ ArrayIsSorted: (location, T, T2) => {
1967
+ const cmp = compareFor(T2);
1968
+ return (array, by) => {
1969
+ if (array.length < 2)
1970
+ return true;
1971
+ lockForIteration(array);
1972
+ try {
1973
+ let projectedPrev = call_function(location, by, array[0]);
1974
+ for (let i = 1; i < array.length; i++) {
1975
+ const projectedCurr = call_function(location, by, array[i]);
1976
+ if (cmp(projectedPrev, projectedCurr) > 0) {
1977
+ return false;
1978
+ }
1979
+ projectedPrev = projectedCurr;
1980
+ }
1981
+ }
1982
+ finally {
1983
+ unlockForIteration(array);
1984
+ }
1985
+ return true;
1986
+ };
1987
+ },
1988
+ ArrayFindSortedFirst: (location, T, T2) => {
1989
+ const cmp = compareFor(T2);
1990
+ return (array, key, by) => {
1991
+ let low = 0;
1992
+ let high = array.length;
1993
+ lockForIteration(array);
1994
+ try {
1995
+ while (low < high) {
1996
+ const mid = Math.floor((low + high) / 2);
1997
+ const projectedMid = call_function(location, by, array[mid]);
1998
+ if (cmp(projectedMid, key) < 0) {
1999
+ low = mid + 1;
2000
+ }
2001
+ else {
2002
+ high = mid;
2003
+ }
2004
+ }
2005
+ }
2006
+ finally {
2007
+ unlockForIteration(array);
2008
+ }
2009
+ return BigInt(low);
2010
+ };
2011
+ },
2012
+ ArrayFindSortedLast: (location, T, T2) => {
2013
+ const cmp = compareFor(T2);
2014
+ return (array, key, by) => {
2015
+ let low = 0;
2016
+ let high = array.length;
2017
+ lockForIteration(array);
2018
+ try {
2019
+ while (low < high) {
2020
+ const mid = Math.floor((low + high) / 2);
2021
+ const projectedMid = call_function(location, by, array[mid]);
2022
+ if (cmp(projectedMid, key) <= 0) {
2023
+ low = mid + 1;
2024
+ }
2025
+ else {
2026
+ high = mid;
2027
+ }
2028
+ }
2029
+ }
2030
+ finally {
2031
+ unlockForIteration(array);
2032
+ }
2033
+ return BigInt(low);
2034
+ };
2035
+ },
2036
+ ArrayFindSortedRange: (location, T, T2) => {
2037
+ const cmp = compareFor(T2);
2038
+ return (array, key, by) => {
2039
+ let lo = -1;
2040
+ let hi = array.length;
2041
+ lockForIteration(array);
2042
+ try {
2043
+ // Main search loop - find any equal element or determine the range doesn't exist
2044
+ while (lo < hi - 1) {
2045
+ const mid = Math.floor((lo + hi) / 2);
2046
+ const projectedMid = call_function(location, by, array[mid]);
2047
+ const cmpResult = cmp(projectedMid, key);
2048
+ if (cmpResult < 0) {
2049
+ lo = mid;
2050
+ }
2051
+ else if (cmpResult > 0) {
2052
+ hi = mid;
2053
+ }
2054
+ else {
2055
+ // Found an equal element! Now find the first and last positions
2056
+ // within the constrained range
2057
+ // Find first position in range [max(lo, -1), mid]
2058
+ let firstLo = Math.max(lo, -1);
2059
+ let firstHi = mid + 1;
2060
+ while (firstLo < firstHi - 1) {
2061
+ const firstMid = Math.floor((firstLo + firstHi) / 2);
2062
+ const projectedFirst = call_function(location, by, array[firstMid]);
2063
+ if (cmp(projectedFirst, key) < 0) {
2064
+ firstLo = firstMid;
2065
+ }
2066
+ else {
2067
+ firstHi = firstMid;
2068
+ }
2069
+ }
2070
+ // Find last position in range [mid, min(hi, array.length)]
2071
+ let lastLo = mid - 1;
2072
+ let lastHi = Math.min(hi, array.length);
2073
+ while (lastLo < lastHi - 1) {
2074
+ const lastMid = Math.floor((lastLo + lastHi) / 2);
2075
+ const projectedLast = call_function(location, by, array[lastMid]);
2076
+ if (cmp(projectedLast, key) <= 0) {
2077
+ lastLo = lastMid;
2078
+ }
2079
+ else {
2080
+ lastHi = lastMid;
2081
+ }
2082
+ }
2083
+ return { start: BigInt(firstLo + 1), end: BigInt(lastLo + 1) };
2084
+ }
2085
+ }
2086
+ }
2087
+ finally {
2088
+ unlockForIteration(array);
2089
+ }
2090
+ // No equal element found - return empty range
2091
+ return { start: BigInt(lo + 1), end: BigInt(lo + 1) };
2092
+ };
2093
+ },
2094
+ ArrayFindFirst: (location, T, T2) => {
2095
+ const cmp = compareFor(T2);
2096
+ return (array, value, by) => {
2097
+ lockForIteration(array);
2098
+ try {
2099
+ for (let i = 0; i < array.length; i++) {
2100
+ const projected = call_function(location, by, array[i]);
2101
+ if (cmp(projected, value) === 0) {
2102
+ return variant("some", BigInt(i));
2103
+ }
2104
+ }
2105
+ return variant("none", null);
2106
+ }
2107
+ finally {
2108
+ unlockForIteration(array);
2109
+ }
2110
+ };
2111
+ },
2112
+ ArrayConcat: (_location, _T) => (a1, a2) => {
2113
+ return [...a1, ...a2];
2114
+ },
2115
+ ArraySlice: (_location, _T) => (array, start, end) => {
2116
+ const startNum = Number(start);
2117
+ const endNum = Number(end);
2118
+ return array.slice(startNum, endNum);
2119
+ },
2120
+ ArrayGetKeys: (location, _T) => (array, keys, onMissing) => {
2121
+ return keys.map(k => {
2122
+ const i = Number(k);
2123
+ if (i < 0 || i >= array.length) {
2124
+ return call_function(location, onMissing, k);
2125
+ }
2126
+ else {
2127
+ return array[i];
2128
+ }
2129
+ });
2130
+ },
2131
+ ArrayForEach: (location, _T, _T2) => (array, f) => {
2132
+ lockForIteration(array);
2133
+ try {
2134
+ array.forEach((x, i) => {
2135
+ return call_function(location, f, x, BigInt(i));
2136
+ });
2137
+ return null;
2138
+ }
2139
+ finally {
2140
+ unlockForIteration(array);
2141
+ }
2142
+ },
2143
+ ArrayCopy: (_location, _T) => (array) => {
2144
+ return [...array];
2145
+ },
2146
+ ArrayMap: (location, _T, _T2) => (array, f) => {
2147
+ lockForIteration(array);
2148
+ try {
2149
+ return array.map((x, i) => {
2150
+ return call_function(location, f, x, BigInt(i));
2151
+ });
2152
+ }
2153
+ finally {
2154
+ unlockForIteration(array);
2155
+ }
2156
+ },
2157
+ ArrayFilter: (location, _T, _T2) => (array, f) => {
2158
+ lockForIteration(array);
2159
+ try {
2160
+ return array.filter((x, i) => {
2161
+ return call_function(location, f, x, BigInt(i));
2162
+ });
2163
+ }
2164
+ finally {
2165
+ unlockForIteration(array);
2166
+ }
2167
+ },
2168
+ ArrayFilterMap: (location, _T, _T2) => (array, f) => {
2169
+ lockForIteration(array);
2170
+ try {
2171
+ const result = [];
2172
+ for (let i = 0; i < array.length; i++) {
2173
+ const v = call_function(location, f, array[i], BigInt(i));
2174
+ if (v.type === "some") {
2175
+ result.push(v.value);
2176
+ }
2177
+ }
2178
+ return result;
2179
+ }
2180
+ finally {
2181
+ unlockForIteration(array);
2182
+ }
2183
+ },
2184
+ ArrayFirstMap: (location, _T, _T2) => (array, f) => {
2185
+ lockForIteration(array);
2186
+ try {
2187
+ for (let i = 0; i < array.length; i++) {
2188
+ const v = call_function(location, f, array[i], BigInt(i));
2189
+ if (v.type === "some") {
2190
+ return v;
2191
+ }
2192
+ }
2193
+ return variant("none", null);
2194
+ }
2195
+ finally {
2196
+ unlockForIteration(array);
2197
+ }
2198
+ },
2199
+ ArrayFold: (location, _T, _T2) => (array, init, f) => {
2200
+ lockForIteration(array);
2201
+ try {
2202
+ return array.reduce((acc, x, i) => {
2203
+ return call_function(location, f, acc, x, BigInt(i));
2204
+ }, init);
2205
+ }
2206
+ finally {
2207
+ unlockForIteration(array);
2208
+ }
2209
+ },
2210
+ ArrayMapReduce: (location, _T, _T2) => (array, mapFn, reduceFn) => {
2211
+ if (array.length === 0) {
2212
+ throw new EastError("Cannot reduce empty array with no initial value", { location });
2213
+ }
2214
+ lockForIteration(array);
2215
+ try {
2216
+ let acc = call_function(location, mapFn, array[0], 0n);
2217
+ for (let i = 1; i < array.length; i++) {
2218
+ const mapped = call_function(location, mapFn, array[i], BigInt(i));
2219
+ acc = call_function(location, reduceFn, acc, mapped);
2220
+ }
2221
+ return acc;
2222
+ }
2223
+ finally {
2224
+ unlockForIteration(array);
2225
+ }
2226
+ },
2227
+ ArrayStringJoin: (_location) => (x, y) => x.join(y),
2228
+ ArrayToSet: (location, _T, T2) => {
2229
+ const compare = compareFor(T2);
2230
+ return (array, f) => {
2231
+ lockForIteration(array);
2232
+ try {
2233
+ const result = new SortedSet([], compare);
2234
+ for (let i = 0; i < array.length; i++) {
2235
+ const v = call_function(location, f, array[i], BigInt(i));
2236
+ result.add(v);
2237
+ }
2238
+ return result;
2239
+ }
2240
+ finally {
2241
+ unlockForIteration(array);
2242
+ }
2243
+ };
2244
+ },
2245
+ ArrayToDict: (location, _T, K2, _T2) => {
2246
+ const compare = compareFor(K2);
2247
+ return (array, keyFn, valueFn, onConflict) => {
2248
+ const result = new SortedMap([], compare);
2249
+ lockForIteration(array);
2250
+ try {
2251
+ for (let i = 0; i < array.length; i++) {
2252
+ const v = array[i];
2253
+ const k = call_function(location, keyFn, v, BigInt(i));
2254
+ let val = call_function(location, valueFn, v, BigInt(i));
2255
+ const existing = result.get(k);
2256
+ if (existing === undefined) {
2257
+ result.set(k, val);
2258
+ }
2259
+ else {
2260
+ val = call_function(location, onConflict, existing, val, k);
2261
+ result.set(k, val);
2262
+ }
2263
+ }
2264
+ return result;
2265
+ }
2266
+ finally {
2267
+ unlockForIteration(array);
2268
+ }
2269
+ };
2270
+ },
2271
+ ArrayFlattenToArray: (location, _T) => (array, fn) => {
2272
+ return array.flatMap(v => {
2273
+ return call_function(location, fn, v);
2274
+ });
2275
+ },
2276
+ ArrayFlattenToSet: (location, _T, K2) => {
2277
+ const compare = compareFor(K2);
2278
+ return (array, fn) => {
2279
+ const result = new SortedSet([], compare);
2280
+ lockForIteration(array);
2281
+ try {
2282
+ for (const v of array) {
2283
+ const subset = call_function(location, fn, v);
2284
+ for (const k of subset) {
2285
+ result.add(k);
2286
+ }
2287
+ }
2288
+ return result;
2289
+ }
2290
+ finally {
2291
+ unlockForIteration(array);
2292
+ }
2293
+ };
2294
+ },
2295
+ ArrayFlattenToDict: (location, _T, K2, _T2) => {
2296
+ const compare = compareFor(K2);
2297
+ return (array, fn, onConflict) => {
2298
+ const result = new SortedMap([], compare);
2299
+ lockForIteration(array);
2300
+ try {
2301
+ for (const v of array) {
2302
+ const subdict = call_function(location, fn, v);
2303
+ for (const [k, val] of subdict.entries()) {
2304
+ const existing = result.get(k);
2305
+ if (existing === undefined) {
2306
+ result.set(k, val);
2307
+ }
2308
+ else {
2309
+ const new_val = call_function(location, onConflict, existing, val, k);
2310
+ result.set(k, new_val);
2311
+ }
2312
+ }
2313
+ }
2314
+ return result;
2315
+ }
2316
+ finally {
2317
+ unlockForIteration(array);
2318
+ }
2319
+ };
2320
+ },
2321
+ ArrayGroupFold: (location, _T, K2, _V2) => {
2322
+ const compare = compareFor(K2);
2323
+ return (array, keyFn, init, folder) => {
2324
+ const result = new SortedMap([], compare);
2325
+ lockForIteration(array);
2326
+ try {
2327
+ for (let i = 0; i < array.length; i++) {
2328
+ const v = array[i];
2329
+ const k = call_function(location, keyFn, v, BigInt(i));
2330
+ let existing = result.get(k);
2331
+ if (existing === undefined) {
2332
+ existing = call_function(location, init, k);
2333
+ }
2334
+ const new_val = call_function(location, folder, existing, v, BigInt(i));
2335
+ result.set(k, new_val);
2336
+ }
2337
+ return result;
2338
+ }
2339
+ finally {
2340
+ unlockForIteration(array);
2341
+ }
2342
+ };
2343
+ },
2344
+ SetGenerate: (location, K) => {
2345
+ const keyComparer = compareFor(K);
2346
+ return (size, keyFn, onConflict) => {
2347
+ const result = new SortedSet([], keyComparer);
2348
+ for (let i = 0n; i < size; i += 1n) {
2349
+ const k = call_function(location, keyFn, i);
2350
+ if (result.has(k)) {
2351
+ call_function(location, onConflict, k);
2352
+ }
2353
+ else {
2354
+ result.add(k);
2355
+ }
2356
+ }
2357
+ return result;
2358
+ };
2359
+ },
2360
+ SetSize: (_location, _K) => (s) => BigInt(s.size),
2361
+ SetHas: (_location, _K) => (s, key) => s.has(key),
2362
+ SetInsert: (location, K) => {
2363
+ const print = printFor(K);
2364
+ return (s, key) => {
2365
+ if (Object.isFrozen(s)) {
2366
+ throw new EastError("Cannot modify frozen Set", { location });
2367
+ }
2368
+ if ((iterationLocks.get(s) || 0) > 0) {
2369
+ throw new EastError("Cannot modify Set during iteration", { location });
2370
+ }
2371
+ const size_before = s.size;
2372
+ s.add(key);
2373
+ if (s.size === size_before) {
2374
+ throw new EastError(`Set already contains key ${print(key)}`, { location });
2375
+ }
2376
+ return null;
2377
+ };
2378
+ },
2379
+ SetTryInsert: (location, _K) => (s, key) => {
2380
+ if (Object.isFrozen(s)) {
2381
+ throw new EastError("Cannot modify frozen Set", { location });
2382
+ }
2383
+ if ((iterationLocks.get(s) || 0) > 0) {
2384
+ throw new EastError("Cannot modify Set during iteration", { location });
2385
+ }
2386
+ const size_before = s.size;
2387
+ s.add(key);
2388
+ return s.size > size_before;
2389
+ },
2390
+ SetDelete: (location, K) => {
2391
+ const print = printFor(K);
2392
+ return (s, key) => {
2393
+ if (Object.isFrozen(s)) {
2394
+ throw new EastError("Cannot modify frozen Set", { location });
2395
+ }
2396
+ if ((iterationLocks.get(s) || 0) > 0) {
2397
+ throw new EastError("Cannot modify Set during iteration", { location });
2398
+ }
2399
+ if (!s.delete(key)) {
2400
+ throw new EastError(`Set does not contain key ${print(key)}`, { location });
2401
+ }
2402
+ return null;
2403
+ };
2404
+ },
2405
+ SetTryDelete: (location, _K) => (s, key) => {
2406
+ if (Object.isFrozen(s)) {
2407
+ throw new EastError("Cannot modify frozen Set", { location });
2408
+ }
2409
+ if ((iterationLocks.get(s) || 0) > 0) {
2410
+ throw new EastError("Cannot modify Set during iteration", { location });
2411
+ }
2412
+ return s.delete(key);
2413
+ },
2414
+ SetClear: (location, _K) => (s) => {
2415
+ if (Object.isFrozen(s)) {
2416
+ throw new EastError("Cannot modify frozen Set", { location });
2417
+ }
2418
+ if ((iterationLocks.get(s) || 0) > 0) {
2419
+ throw new EastError("Cannot modify Set during iteration", { location });
2420
+ }
2421
+ s.clear();
2422
+ return null;
2423
+ },
2424
+ SetUnionInPlace: (location, _K) => (s1, s2) => {
2425
+ if (Object.isFrozen(s1)) {
2426
+ throw new EastError("Cannot modify frozen Set", { location });
2427
+ }
2428
+ if ((iterationLocks.get(s1) || 0) > 0) {
2429
+ throw new EastError("Cannot modify Set during iteration", { location });
2430
+ }
2431
+ s2.forEach(v => s1.add(v));
2432
+ return null;
2433
+ },
2434
+ SetUnion: (_location, _K) => (s1, s2) => s1.union(s2),
2435
+ SetIntersect: (_location, _K) => (s1, s2) => s1.intersection(s2),
2436
+ SetDiff: (_location, _K) => (s1, s2) => s1.difference(s2),
2437
+ SetSymDiff: (_location, _K) => (s1, s2) => s1.symmetricDifference(s2),
2438
+ SetIsSubset: (_location, _K) => (s1, s2) => s1.isSubsetOf(s2),
2439
+ SetIsDisjoint: (_location, _K) => (s1, s2) => s1.isDisjointFrom(s2),
2440
+ SetCopy: (_location, K) => {
2441
+ const compare = compareFor(K);
2442
+ return (s) => {
2443
+ return new SortedSet([...s], compare);
2444
+ };
2445
+ },
2446
+ SetForEach: (location, _K, _T2) => (s, f) => {
2447
+ lockForIteration(s);
2448
+ try {
2449
+ s.forEach(x => {
2450
+ call_function(location, f, x);
2451
+ });
2452
+ return null;
2453
+ }
2454
+ finally {
2455
+ unlockForIteration(s);
2456
+ }
2457
+ },
2458
+ SetFilter: (location, K) => {
2459
+ const compare = compareFor(K);
2460
+ return (s, f) => {
2461
+ const result = new SortedSet([], compare);
2462
+ lockForIteration(s);
2463
+ try {
2464
+ s.forEach(x => {
2465
+ const keep = call_function(location, f, x);
2466
+ if (keep) {
2467
+ result.add(x);
2468
+ }
2469
+ });
2470
+ return result;
2471
+ }
2472
+ finally {
2473
+ unlockForIteration(s);
2474
+ }
2475
+ };
2476
+ },
2477
+ SetFilterMap: (location, K, _V2) => {
2478
+ const compare = compareFor(K);
2479
+ return (s, f) => {
2480
+ const result = new SortedMap([], compare);
2481
+ lockForIteration(s);
2482
+ try {
2483
+ s.forEach(k => {
2484
+ const v2 = call_function(location, f, k);
2485
+ if (v2.type === "some") {
2486
+ result.set(k, v2.value);
2487
+ }
2488
+ });
2489
+ return result;
2490
+ }
2491
+ finally {
2492
+ unlockForIteration(s);
2493
+ }
2494
+ };
2495
+ },
2496
+ SetFirstMap: (location, _K, _T2) => (s, f) => {
2497
+ lockForIteration(s);
2498
+ try {
2499
+ for (const k of s) {
2500
+ const v = call_function(location, f, k);
2501
+ if (v.type === "some") {
2502
+ return v;
2503
+ }
2504
+ }
2505
+ return variant("none", null);
2506
+ }
2507
+ finally {
2508
+ unlockForIteration(s);
2509
+ }
2510
+ },
2511
+ SetMapReduce: (location, _K, _T2) => (s, mapFn, reduceFn) => {
2512
+ if (s.size === 0) {
2513
+ throw new EastError("Cannot reduce empty set with no initial value", { location });
2514
+ }
2515
+ lockForIteration(s);
2516
+ try {
2517
+ const iterator = s[Symbol.iterator]();
2518
+ const first = iterator.next().value;
2519
+ let acc = call_function(location, mapFn, first);
2520
+ for (const k of iterator) {
2521
+ const mapped = call_function(location, mapFn, k);
2522
+ acc = call_function(location, reduceFn, acc, mapped);
2523
+ }
2524
+ return acc;
2525
+ }
2526
+ finally {
2527
+ unlockForIteration(s);
2528
+ }
2529
+ },
2530
+ SetMap: (location, K, _T2) => {
2531
+ const compare = compareFor(K);
2532
+ return (s, f) => {
2533
+ const result = new SortedMap([], compare);
2534
+ lockForIteration(s);
2535
+ try {
2536
+ s.forEach(x => {
2537
+ const v = call_function(location, f, x);
2538
+ result.set(x, v);
2539
+ });
2540
+ return result;
2541
+ }
2542
+ finally {
2543
+ unlockForIteration(s);
2544
+ }
2545
+ };
2546
+ },
2547
+ SetReduce: (location, _K, _T2) => (s, f, init) => {
2548
+ let acc = init;
2549
+ lockForIteration(s);
2550
+ try {
2551
+ for (const x of s) {
2552
+ acc = call_function(location, f, acc, x);
2553
+ }
2554
+ return acc;
2555
+ }
2556
+ finally {
2557
+ unlockForIteration(s);
2558
+ }
2559
+ },
2560
+ SetToArray: (location, _K, _T2) => (s, valueFn) => {
2561
+ const ret = [];
2562
+ lockForIteration(s);
2563
+ try {
2564
+ for (const k of s) {
2565
+ const v = call_function(location, valueFn, k);
2566
+ ret.push(v);
2567
+ }
2568
+ return ret;
2569
+ }
2570
+ finally {
2571
+ unlockForIteration(s);
2572
+ }
2573
+ },
2574
+ SetToSet: (location, K, K2) => {
2575
+ const compare = compareFor(K2);
2576
+ return (s, f) => {
2577
+ const result = new SortedSet([], compare);
2578
+ lockForIteration(s);
2579
+ try {
2580
+ for (const x of s) {
2581
+ const v = call_function(location, f, x);
2582
+ result.add(v);
2583
+ }
2584
+ ;
2585
+ return result;
2586
+ }
2587
+ finally {
2588
+ unlockForIteration(s);
2589
+ }
2590
+ };
2591
+ },
2592
+ SetToDict: (location, K, K2, _V2) => {
2593
+ const compare = compareFor(K2);
2594
+ return (s, keyFn, valueFn, onConflict) => {
2595
+ const result = new SortedMap([], compare);
2596
+ lockForIteration(s);
2597
+ try {
2598
+ for (const k of s) {
2599
+ const k2 = call_function(location, keyFn, k);
2600
+ let v2 = call_function(location, valueFn, k);
2601
+ const existing = result.get(k2);
2602
+ if (existing !== undefined) {
2603
+ v2 = call_function(location, onConflict, existing, v2, k2);
2604
+ result.set(k2, v2);
2605
+ }
2606
+ else {
2607
+ result.set(k2, v2);
2608
+ }
2609
+ }
2610
+ return result;
2611
+ }
2612
+ finally {
2613
+ unlockForIteration(s);
2614
+ }
2615
+ };
2616
+ },
2617
+ SetFlattenToArray: (location, _K, _T2) => (s, fn) => {
2618
+ const ret = [];
2619
+ lockForIteration(s);
2620
+ try {
2621
+ for (const k of s) {
2622
+ const subarray = call_function(location, fn, k);
2623
+ ret.push(...subarray);
2624
+ }
2625
+ return ret;
2626
+ }
2627
+ finally {
2628
+ unlockForIteration(s);
2629
+ }
2630
+ },
2631
+ SetFlattenToSet: (location, _K, K2) => {
2632
+ const compare = compareFor(K2);
2633
+ return (s, fn) => {
2634
+ const result = new SortedSet([], compare);
2635
+ lockForIteration(s);
2636
+ try {
2637
+ for (const k of s) {
2638
+ const subset = call_function(location, fn, k);
2639
+ for (const k2 of subset) {
2640
+ result.add(k2);
2641
+ }
2642
+ }
2643
+ return result;
2644
+ }
2645
+ finally {
2646
+ unlockForIteration(s);
2647
+ }
2648
+ };
2649
+ },
2650
+ SetFlattenToDict: (location, _K, K2, _V2) => {
2651
+ const compare = compareFor(K2);
2652
+ return (s, fn, onConflict) => {
2653
+ const result = new SortedMap([], compare);
2654
+ lockForIteration(s);
2655
+ try {
2656
+ for (const k of s) {
2657
+ const subdict = call_function(location, fn, k);
2658
+ for (const [k2, v2] of subdict.entries()) {
2659
+ const existing = result.get(k2);
2660
+ if (existing === undefined) {
2661
+ result.set(k2, v2);
2662
+ }
2663
+ else {
2664
+ const new_v2 = call_function(location, onConflict, existing, v2, k2);
2665
+ result.set(k2, new_v2);
2666
+ }
2667
+ }
2668
+ }
2669
+ return result;
2670
+ }
2671
+ finally {
2672
+ unlockForIteration(s);
2673
+ }
2674
+ };
2675
+ },
2676
+ SetGroupFold: (location, _K, K2, _T2) => {
2677
+ const compare = compareFor(K2);
2678
+ return (s, keyFn, init, folder) => {
2679
+ const result = new SortedMap([], compare);
2680
+ lockForIteration(s);
2681
+ try {
2682
+ for (const k of s) {
2683
+ const k2 = call_function(location, keyFn, k);
2684
+ let existing = result.get(k2);
2685
+ if (existing === undefined) {
2686
+ existing = call_function(location, init, k2);
2687
+ }
2688
+ const new_val = call_function(location, folder, existing, k);
2689
+ result.set(k2, new_val);
2690
+ }
2691
+ return result;
2692
+ }
2693
+ finally {
2694
+ unlockForIteration(s);
2695
+ }
2696
+ };
2697
+ },
2698
+ DictGenerate: (location, K, _V) => {
2699
+ const keyComparer = compareFor(K);
2700
+ return (size, keyFn, valueFn, onConflict) => {
2701
+ const result = new SortedMap([], keyComparer);
2702
+ for (let i = 0n; i < size; i += 1n) {
2703
+ const k = call_function(location, keyFn, i);
2704
+ const v = call_function(location, valueFn, i);
2705
+ const existing = result.get(k);
2706
+ if (existing !== undefined) {
2707
+ const v2 = call_function(location, onConflict, existing, v, k);
2708
+ result.set(k, v2);
2709
+ }
2710
+ else {
2711
+ result.set(k, v);
2712
+ }
2713
+ }
2714
+ return result;
2715
+ };
2716
+ },
2717
+ DictSize: (_location, _K, _V) => (d) => BigInt(d.size),
2718
+ DictHas: (_location, _K, _V) => (d, key) => d.has(key),
2719
+ DictGet: (location, K, _V) => {
2720
+ const print = printFor(K);
2721
+ return (d, key) => {
2722
+ const result = d.get(key);
2723
+ if (result === undefined) {
2724
+ throw new EastError(`Dict does not contain key ${print(key)}`, { location });
2725
+ }
2726
+ else {
2727
+ return result;
2728
+ }
2729
+ };
2730
+ },
2731
+ DictGetOrDefault: (location, _K, _V) => (d, key, onMissingFn) => {
2732
+ const result = d.get(key);
2733
+ if (result === undefined) {
2734
+ return call_function(location, onMissingFn, key);
2735
+ }
2736
+ else {
2737
+ return result;
2738
+ }
2739
+ },
2740
+ DictTryGet: (_location, _K, _V) => (d, key) => {
2741
+ const result = d.get(key);
2742
+ if (result === undefined) {
2743
+ return variant("none", null);
2744
+ }
2745
+ else {
2746
+ return variant("some", result);
2747
+ }
2748
+ },
2749
+ DictInsert: (location, K, _V) => {
2750
+ const print = printFor(K);
2751
+ return (d, key, value) => {
2752
+ if (Object.isFrozen(d)) {
2753
+ throw new EastError("Cannot modify frozen Dict", { location });
2754
+ }
2755
+ if ((iterationLocks.get(d) || 0) > 0) {
2756
+ throw new EastError("Cannot modify Dict during iteration", { location });
2757
+ }
2758
+ const existing = d.get(key);
2759
+ if (existing !== undefined) {
2760
+ throw new EastError(`Dict already contains key ${print(key)}`, { location });
2761
+ }
2762
+ else {
2763
+ d.set(key, value);
2764
+ }
2765
+ return null;
2766
+ };
2767
+ },
2768
+ DictGetOrInsert: (location, _K, _V) => (d, key, onMissing) => {
2769
+ if (Object.isFrozen(d)) {
2770
+ throw new EastError("Cannot modify frozen Dict", { location });
2771
+ }
2772
+ if ((iterationLocks.get(d) || 0) > 0) {
2773
+ throw new EastError("Cannot modify Dict during iteration", { location });
2774
+ }
2775
+ const existing = d.get(key);
2776
+ if (existing === undefined) {
2777
+ const newValue = call_function(location, onMissing, key);
2778
+ d.set(key, newValue);
2779
+ return newValue;
2780
+ }
2781
+ else {
2782
+ return existing;
2783
+ }
2784
+ },
2785
+ DictInsertOrUpdate: (location, _K, _V) => (d, key, value, onConflictFn) => {
2786
+ if (Object.isFrozen(d)) {
2787
+ throw new EastError("Cannot modify frozen Dict", { location });
2788
+ }
2789
+ if ((iterationLocks.get(d) || 0) > 0) {
2790
+ throw new EastError("Cannot modify Dict during iteration", { location });
2791
+ }
2792
+ const existing = d.get(key);
2793
+ if (existing !== undefined) {
2794
+ const result = call_function(location, onConflictFn, existing, value, key);
2795
+ d.set(key, result);
2796
+ }
2797
+ else {
2798
+ d.set(key, value);
2799
+ }
2800
+ return null;
2801
+ },
2802
+ DictUpdate: (location, K, _V) => {
2803
+ const print = printFor(K);
2804
+ return (d, key, value) => {
2805
+ if (Object.isFrozen(d)) {
2806
+ throw new EastError("Cannot modify frozen Dict", { location });
2807
+ }
2808
+ if (d.has(key)) {
2809
+ d.set(key, value);
2810
+ return null;
2811
+ }
2812
+ else {
2813
+ throw new EastError(`Dict does not contain key ${print(key)}`, { location });
2814
+ }
2815
+ };
2816
+ },
2817
+ DictSwap: (location, K, _V) => {
2818
+ const print = printFor(K);
2819
+ return (d, key, value) => {
2820
+ if (Object.isFrozen(d)) {
2821
+ throw new EastError("Cannot modify frozen Dict", { location });
2822
+ }
2823
+ let existing = d.get(key);
2824
+ if (existing === undefined) {
2825
+ throw new EastError(`Dict does not contain key ${print(key)}`, { location });
2826
+ }
2827
+ d.set(key, value);
2828
+ return existing;
2829
+ };
2830
+ },
2831
+ DictMerge: (location, _K, _V) => (d, key, value, mergeFn, initialFn) => {
2832
+ if (Object.isFrozen(d)) {
2833
+ throw new EastError("Cannot modify frozen Dict", { location });
2834
+ }
2835
+ if ((iterationLocks.get(d) || 0) > 0) {
2836
+ throw new EastError("Cannot modify Dict during iteration", { location });
2837
+ }
2838
+ let existing = d.get(key);
2839
+ if (existing === undefined) {
2840
+ existing = call_function(location, initialFn, key);
2841
+ }
2842
+ const new_value = call_function(location, mergeFn, existing, value, key);
2843
+ d.set(key, new_value);
2844
+ return null;
2845
+ },
2846
+ DictDelete: (location, K, _V) => {
2847
+ const print = printFor(K);
2848
+ return (d, key) => {
2849
+ if (Object.isFrozen(d)) {
2850
+ throw new EastError("Cannot modify frozen Dict", { location });
2851
+ }
2852
+ if ((iterationLocks.get(d) || 0) > 0) {
2853
+ throw new EastError("Cannot modify Dict during iteration", { location });
2854
+ }
2855
+ const existed = d.delete(key);
2856
+ if (!existed) {
2857
+ throw new EastError(`Dict does not contain key ${print(key)}`, { location });
2858
+ }
2859
+ return null;
2860
+ };
2861
+ },
2862
+ DictTryDelete: (location, _K, _V) => (d, key) => {
2863
+ if (Object.isFrozen(d)) {
2864
+ throw new EastError("Cannot modify frozen Dict", { location });
2865
+ }
2866
+ if ((iterationLocks.get(d) || 0) > 0) {
2867
+ throw new EastError("Cannot modify Dict during iteration", { location });
2868
+ }
2869
+ return d.delete(key);
2870
+ },
2871
+ DictPop: (location, K, _V) => {
2872
+ const print = printFor(K);
2873
+ return (d, key) => {
2874
+ if (Object.isFrozen(d)) {
2875
+ throw new EastError("Cannot modify frozen Dict", { location });
2876
+ }
2877
+ if ((iterationLocks.get(d) || 0) > 0) {
2878
+ throw new EastError("Cannot modify Dict during iteration", { location });
2879
+ }
2880
+ const existing = d.get(key);
2881
+ if (existing === undefined) {
2882
+ throw new EastError(`Dict does not contain key ${print(key)}`, { location });
2883
+ }
2884
+ else {
2885
+ d.delete(key);
2886
+ return existing;
2887
+ }
2888
+ };
2889
+ },
2890
+ DictClear: (location, _K, _V) => (d) => {
2891
+ if (Object.isFrozen(d)) {
2892
+ throw new EastError("Cannot modify frozen Dict", { location });
2893
+ }
2894
+ if ((iterationLocks.get(d) || 0) > 0) {
2895
+ throw new EastError("Cannot modify Dict during iteration", { location });
2896
+ }
2897
+ d.clear();
2898
+ return null;
2899
+ },
2900
+ DictUnionInPlace: (location, _K, _V) => (d1, d2, onConflict) => {
2901
+ if (Object.isFrozen(d1)) {
2902
+ throw new EastError("Cannot modify frozen Dict", { location });
2903
+ }
2904
+ if ((iterationLocks.get(d1) || 0) > 0) {
2905
+ throw new EastError("Cannot modify Dict during iteration", { location });
2906
+ }
2907
+ d2.forEach((v2, k) => {
2908
+ const v1 = d1.get(k);
2909
+ if (v1 === undefined) {
2910
+ d1.set(k, v2);
2911
+ }
2912
+ else {
2913
+ const new_value = call_function(location, onConflict, v1, v2, k);
2914
+ d1.set(k, new_value);
2915
+ }
2916
+ });
2917
+ return null;
2918
+ },
2919
+ DictMergeAll: (location, _K, _V) => (d1, d2, mergeFn, initialFn) => {
2920
+ if (Object.isFrozen(d1)) {
2921
+ throw new EastError("Cannot modify frozen Dict", { location });
2922
+ }
2923
+ if ((iterationLocks.get(d1) || 0) > 0) {
2924
+ throw new EastError("Cannot modify Dict during iteration", { location });
2925
+ }
2926
+ d2.forEach((v2, k) => {
2927
+ let v1 = d1.get(k);
2928
+ if (v1 === undefined) {
2929
+ v1 = call_function(location, initialFn, k);
2930
+ }
2931
+ const new_value = call_function(location, mergeFn, v1, v2, k);
2932
+ d1.set(k, new_value);
2933
+ });
2934
+ return null;
2935
+ },
2936
+ DictKeys: (_location, K, _V) => {
2937
+ const compare = compareFor(K);
2938
+ return (d) => {
2939
+ return new SortedSet([...d.keys()], compare);
2940
+ };
2941
+ },
2942
+ DictGetKeys: (location, K, _V) => {
2943
+ const compare = compareFor(K);
2944
+ return (d, keys, onMissing) => {
2945
+ const result = new SortedMap([], compare);
2946
+ for (const k of keys) {
2947
+ const v = d.get(k);
2948
+ if (v !== undefined) {
2949
+ result.set(k, v);
2950
+ }
2951
+ else {
2952
+ const new_v = call_function(location, onMissing, k);
2953
+ result.set(k, new_v);
2954
+ }
2955
+ }
2956
+ return result;
2957
+ };
2958
+ },
2959
+ DictForEach: (location, _K, _V, _T2) => (d, f) => {
2960
+ lockForIteration(d);
2961
+ try {
2962
+ d.forEach((v, k) => {
2963
+ call_function(location, f, v, k);
2964
+ });
2965
+ return null;
2966
+ }
2967
+ finally {
2968
+ unlockForIteration(d);
2969
+ }
2970
+ },
2971
+ DictCopy: (_location, K, _V) => {
2972
+ const compare = compareFor(K);
2973
+ return (d) => {
2974
+ return new SortedMap([...d], compare);
2975
+ };
2976
+ },
2977
+ DictMap: (location, K, _V, _V2) => {
2978
+ const compare = compareFor(K);
2979
+ return (d, f) => {
2980
+ const result = new SortedMap([], compare);
2981
+ lockForIteration(d);
2982
+ try {
2983
+ for (const [k, v] of d) {
2984
+ const v2 = call_function(location, f, v, k);
2985
+ result.set(k, v2);
2986
+ }
2987
+ return result;
2988
+ }
2989
+ finally {
2990
+ unlockForIteration(d);
2991
+ }
2992
+ };
2993
+ },
2994
+ DictFilter: (location, K, _V) => {
2995
+ const compare = compareFor(K);
2996
+ return (d, f) => {
2997
+ const result = new SortedMap([], compare);
2998
+ lockForIteration(d);
2999
+ try {
3000
+ for (const [k, v] of d) {
3001
+ const keep = call_function(location, f, v, k);
3002
+ if (keep) {
3003
+ result.set(k, v);
3004
+ }
3005
+ }
3006
+ return result;
3007
+ }
3008
+ finally {
3009
+ unlockForIteration(d);
3010
+ }
3011
+ };
3012
+ },
3013
+ DictFilterMap: (location, K, _V, _V2) => {
3014
+ const compare = compareFor(K);
3015
+ return (d, f) => {
3016
+ const result = new SortedMap([], compare);
3017
+ lockForIteration(d);
3018
+ try {
3019
+ for (const [k, v] of d) {
3020
+ const v2 = call_function(location, f, v, k);
3021
+ if (v2.type === "some") {
3022
+ result.set(k, v2.value);
3023
+ }
3024
+ }
3025
+ return result;
3026
+ }
3027
+ finally {
3028
+ unlockForIteration(d);
3029
+ }
3030
+ };
3031
+ },
3032
+ DictFirstMap: (location, _K, _V, _T2) => (d, f) => {
3033
+ lockForIteration(d);
3034
+ try {
3035
+ for (const [k, v] of d) {
3036
+ const result = call_function(location, f, v, k);
3037
+ if (result.type === "some") {
3038
+ return result;
3039
+ }
3040
+ }
3041
+ return variant("none", null);
3042
+ }
3043
+ finally {
3044
+ unlockForIteration(d);
3045
+ }
3046
+ },
3047
+ DictMapReduce: (location, _K, _V, _T2) => (d, mapFn, reduceFn) => {
3048
+ if (d.size === 0) {
3049
+ throw new EastError("Cannot reduce empty dictionary with no initial value", { location });
3050
+ }
3051
+ lockForIteration(d);
3052
+ try {
3053
+ const iterator = d[Symbol.iterator]();
3054
+ const first = iterator.next().value;
3055
+ let acc = call_function(location, mapFn, first[1], first[0]);
3056
+ for (const [k, v] of iterator) {
3057
+ const mapped = call_function(location, mapFn, v, k);
3058
+ acc = call_function(location, reduceFn, acc, mapped);
3059
+ }
3060
+ return acc;
3061
+ }
3062
+ finally {
3063
+ unlockForIteration(d);
3064
+ }
3065
+ },
3066
+ DictReduce: (location, _K, _V, _T2) => (d, f, init) => {
3067
+ let acc = init;
3068
+ lockForIteration(d);
3069
+ try {
3070
+ for (const [k, v] of d) {
3071
+ acc = call_function(location, f, acc, v, k);
3072
+ }
3073
+ return acc;
3074
+ }
3075
+ finally {
3076
+ unlockForIteration(d);
3077
+ }
3078
+ },
3079
+ DictToArray: (location, _K, _V, _T2) => (d, valueFn) => {
3080
+ const ret = [];
3081
+ lockForIteration(d);
3082
+ try {
3083
+ for (const [k, v] of d) {
3084
+ const v2 = call_function(location, valueFn, v, k);
3085
+ ret.push(v2);
3086
+ }
3087
+ return ret;
3088
+ }
3089
+ finally {
3090
+ unlockForIteration(d);
3091
+ }
3092
+ },
3093
+ DictToSet: (location, _K, _V, K2) => {
3094
+ const compare = compareFor(K2);
3095
+ return (d, fn) => {
3096
+ const result = new SortedSet([], compare);
3097
+ lockForIteration(d);
3098
+ try {
3099
+ for (const [k, v] of d) {
3100
+ const k2 = call_function(location, fn, v, k);
3101
+ result.add(k2);
3102
+ }
3103
+ return result;
3104
+ }
3105
+ finally {
3106
+ unlockForIteration(d);
3107
+ }
3108
+ };
3109
+ },
3110
+ DictToDict: (location, K, _V, K2, _V2) => {
3111
+ const compare = compareFor(K2);
3112
+ return (d, keyFn, valueFn, onConflict) => {
3113
+ const result = new SortedMap([], compare);
3114
+ lockForIteration(d);
3115
+ try {
3116
+ for (const [k, v] of d) {
3117
+ const k2 = call_function(location, keyFn, v, k);
3118
+ const v2 = call_function(location, valueFn, v, k);
3119
+ const existing = result.get(k2);
3120
+ if (existing !== undefined) {
3121
+ const v3 = call_function(location, onConflict, existing, v2, k2);
3122
+ result.set(k2, v3);
3123
+ }
3124
+ else {
3125
+ result.set(k2, v2);
3126
+ }
3127
+ }
3128
+ return result;
3129
+ }
3130
+ finally {
3131
+ unlockForIteration(d);
3132
+ }
3133
+ };
3134
+ },
3135
+ DictFlattenToArray: (location, _K, _V, _T2) => (d, fn) => {
3136
+ const ret = [];
3137
+ lockForIteration(d);
3138
+ try {
3139
+ for (const [k, v] of d.entries()) {
3140
+ const subarray = call_function(location, fn, v, k);
3141
+ for (const item of subarray) {
3142
+ ret.push(item);
3143
+ }
3144
+ }
3145
+ return ret;
3146
+ }
3147
+ finally {
3148
+ unlockForIteration(d);
3149
+ }
3150
+ },
3151
+ DictFlattenToSet: (location, _K, _V, K2) => {
3152
+ const compare = compareFor(K2);
3153
+ return (d, fn) => {
3154
+ const result = new SortedSet([], compare);
3155
+ lockForIteration(d);
3156
+ try {
3157
+ for (const [k, v] of d.entries()) {
3158
+ const subset = call_function(location, fn, v, k);
3159
+ for (const k2 of subset) {
3160
+ result.add(k2);
3161
+ }
3162
+ }
3163
+ return result;
3164
+ }
3165
+ finally {
3166
+ unlockForIteration(d);
3167
+ }
3168
+ };
3169
+ },
3170
+ DictFlattenToDict: (location, _K, _V, K2, _V2) => {
3171
+ const compare = compareFor(K2);
3172
+ return (d, fn, onConflict) => {
3173
+ const result = new SortedMap([], compare);
3174
+ lockForIteration(d);
3175
+ try {
3176
+ for (const [k, v] of d.entries()) {
3177
+ const subdict = call_function(location, fn, v, k);
3178
+ for (const [k2, v2] of subdict.entries()) {
3179
+ const existing = result.get(k2);
3180
+ if (existing === undefined) {
3181
+ result.set(k2, v2);
3182
+ }
3183
+ else {
3184
+ const new_v2 = call_function(location, onConflict, existing, v2, k2);
3185
+ result.set(k2, new_v2);
3186
+ }
3187
+ }
3188
+ }
3189
+ return result;
3190
+ }
3191
+ finally {
3192
+ unlockForIteration(d);
3193
+ }
3194
+ };
3195
+ },
3196
+ DictGroupFold: (location, _K, _V, K2, _T2) => {
3197
+ const compare = compareFor(K2);
3198
+ return (d, keyFn, init, folder) => {
3199
+ const result = new SortedMap([], compare);
3200
+ lockForIteration(d);
3201
+ try {
3202
+ for (const [k, v] of d.entries()) {
3203
+ const k2 = call_function(location, keyFn, v, k);
3204
+ let existing = result.get(k2);
3205
+ if (existing === undefined) {
3206
+ existing = call_function(location, init, k2);
3207
+ }
3208
+ const new_val = call_function(location, folder, existing, v, k);
3209
+ result.set(k2, new_val);
3210
+ }
3211
+ return result;
3212
+ }
3213
+ finally {
3214
+ unlockForIteration(d);
3215
+ }
3216
+ };
3217
+ },
3218
+ };
3219
+ /** @internal */
3220
+ export function applyTypeParameters(t, params) {
3221
+ if (typeof (t) === "string") {
3222
+ let ret = params.get(t);
3223
+ if (ret === undefined) {
3224
+ throw new Error(`Unable to find type parameter ${JSON.stringify(t)}`);
3225
+ }
3226
+ return ret;
3227
+ }
3228
+ else if (t.type === "Null" || t.type === "Boolean" || t.type === "Integer" || t.type === "Float" || t.type === "String" || t.type === "DateTime" || t.type === "Blob" || t.type === "Never") {
3229
+ return t;
3230
+ }
3231
+ else if (t.type === "Ref") {
3232
+ return variant("Ref", applyTypeParameters(t.value, params));
3233
+ }
3234
+ else if (t.type === "Array") {
3235
+ return variant("Array", applyTypeParameters(t.value, params));
3236
+ }
3237
+ else if (t.type === "Set") {
3238
+ return variant("Set", applyTypeParameters(t.value, params));
3239
+ }
3240
+ else if (t.type === "Dict") {
3241
+ return variant("Dict", { key: applyTypeParameters(t.value.key, params), value: applyTypeParameters(t.value.value, params) });
3242
+ }
3243
+ else if (t.type === "Struct") {
3244
+ return variant("Struct", t.value.map(({ name, type }) => ({ name, type: applyTypeParameters(type, params) })));
3245
+ }
3246
+ else if (t.type === "Variant") {
3247
+ return variant("Variant", t.value.map(({ name, type }) => ({ name, type: applyTypeParameters(type, params) })));
3248
+ }
3249
+ else if (t.type === "Recursive") {
3250
+ return t;
3251
+ }
3252
+ else if (t.type === "Function") {
3253
+ // TODO platforms?
3254
+ return variant("Function", { inputs: t.value.inputs.map(i => applyTypeParameters(i, params)), output: applyTypeParameters(t.value.output, params), platforms: [] });
3255
+ }
3256
+ else {
3257
+ throw new Error(`Unhandled type ${t.type}`);
3258
+ }
3259
+ }
3260
+ //# sourceMappingURL=compile.js.map