@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,834 @@
1
+ import { printLocationValue } from "./ir.js";
2
+ import { printLocation } from "./location.js";
3
+ import { toEastTypeValue } from "./type_of_type.js";
4
+ import { ArrayType, DictType, FunctionType, isSubtype, isTypeEqual, NeverType, NullType, printType, RefType, SetType, StructType, VariantType } from "./types.js";
5
+ import { variant } from "./containers/variant.js";
6
+ import { applyTypeParameters, Builtins } from "./builtins.js";
7
+ // TODO we should probably redo type checking exhaustively here?
8
+ function toLocationValue(location) {
9
+ return {
10
+ filename: location.filename,
11
+ line: BigInt(location.line),
12
+ column: BigInt(location.column),
13
+ };
14
+ }
15
+ /** Perform scope resolution and type checking on `AST`, produce `IR` ready for serialization, compilation or evaluation.
16
+ *
17
+ * @internal */
18
+ export function ast_to_ir(ast, ctx = { local_ctx: new Map(), parent_ctx: new Map(), captures: new Set(), loop_ctx: new Map(), n_vars: 0, n_loops: 0, inputs: [], output: NeverType }) {
19
+ try {
20
+ if (ast.ast_type === "Variable") {
21
+ if (ctx.local_ctx.has(ast)) {
22
+ return ctx.local_ctx.get(ast);
23
+ }
24
+ else {
25
+ if (ctx.parent_ctx.has(ast)) {
26
+ const ir = ctx.parent_ctx.get(ast);
27
+ ir.value.captured = true;
28
+ ctx.captures.add(ir);
29
+ return ir;
30
+ }
31
+ else {
32
+ throw new Error(`Variable defined at ${printLocation(ast.location)} not in scope`);
33
+ }
34
+ }
35
+ }
36
+ else if (ast.ast_type === "Let") {
37
+ let value = ast_to_ir(ast.value, ctx);
38
+ // Create a new variable
39
+ const variable = variant("Variable", {
40
+ type: toEastTypeValue(ast.variable.type),
41
+ name: `_${ctx.n_vars}`,
42
+ location: toLocationValue(ast.variable.location),
43
+ mutable: ast.variable.mutable,
44
+ captured: false,
45
+ });
46
+ // Insert As node if value type doesn't exactly match variable type
47
+ // This ensures the IR has exact types everywhere
48
+ if (!isTypeEqual(ast.value.type, ast.variable.type)) {
49
+ // Validate subtype relationship before inserting As node
50
+ // This catches type errors early at AST level
51
+ if (!isSubtype(ast.value.type, ast.variable.type)) {
52
+ throw new Error(`Cannot initialize variable of type ${printType(ast.variable.type)} ` +
53
+ `with value of type ${printType(ast.value.type)} at ${printLocation(ast.location)}`);
54
+ }
55
+ value = variant("As", {
56
+ type: toEastTypeValue(ast.variable.type),
57
+ value,
58
+ location: toLocationValue(ast.location),
59
+ });
60
+ }
61
+ ctx.n_vars += 1;
62
+ ctx.local_ctx.set(ast.variable, variable);
63
+ return variant("Let", {
64
+ type: toEastTypeValue(ast.type),
65
+ location: toLocationValue(ast.location),
66
+ variable,
67
+ value,
68
+ });
69
+ }
70
+ else if (ast.ast_type === "Assign") {
71
+ // Fetch the variable from context
72
+ const variable = ast_to_ir(ast.variable, ctx);
73
+ if (!variable.value.mutable) {
74
+ throw new Error(`Variable defined const at ${printLocationValue(variable.value.location)} is being reassigned at ${printLocation(ast.location)}`);
75
+ }
76
+ let value = ast_to_ir(ast.value, ctx);
77
+ // Get the variable's type from the IR node
78
+ const variableType = variable.value.type;
79
+ // Insert As node if value type doesn't exactly match variable type
80
+ // This ensures the IR has exact types everywhere
81
+ if (!isTypeEqual(ast.value.type, ast.variable.type)) {
82
+ // Validate subtype relationship before inserting As node
83
+ if (!isSubtype(ast.value.type, ast.variable.type)) {
84
+ throw new Error(`Cannot assign value of type ${printType(ast.value.type)} ` +
85
+ `to variable of type ${printType(ast.variable.type)} at ${printLocation(ast.location)}`);
86
+ }
87
+ value = variant("As", {
88
+ type: variableType,
89
+ value,
90
+ location: toLocationValue(ast.location),
91
+ });
92
+ }
93
+ return variant("Assign", {
94
+ type: toEastTypeValue(ast.type),
95
+ location: toLocationValue(ast.location),
96
+ variable,
97
+ value,
98
+ });
99
+ }
100
+ else if (ast.ast_type === "Block") {
101
+ const local_ctx = new Map([...ctx.local_ctx]);
102
+ const ctx2 = { ...ctx, local_ctx };
103
+ const statements = ast.statements.map(s => ast_to_ir(s, ctx2));
104
+ ctx.n_vars = ctx2.n_vars;
105
+ ctx.n_loops = ctx2.n_loops;
106
+ return variant("Block", {
107
+ type: toEastTypeValue(ast.type),
108
+ location: toLocationValue(ast.location),
109
+ statements,
110
+ });
111
+ }
112
+ else if (ast.ast_type === "Builtin") {
113
+ // We need to apply the type parameters to the builtin, and cast the arguments as needed
114
+ const builtin_name = ast.builtin;
115
+ const builtin_def = Builtins[builtin_name];
116
+ if (!builtin_def) {
117
+ throw new Error(`Unknown builtin function '${builtin_name}' at ${printLocation(ast.location)}`);
118
+ }
119
+ if (builtin_def.type_parameters.length !== ast.type_parameters.length) {
120
+ throw new Error(`Builtin function '${builtin_name}' expected ${builtin_def.type_parameters.length} type parameters, got ${ast.type_parameters.length} at ${printLocation(ast.location)}`);
121
+ }
122
+ const type_map = new Map(builtin_def.type_parameters.map((name, i) => [name, ast.type_parameters[i]]));
123
+ if (ast.arguments.length !== builtin_def.inputs.length) {
124
+ throw new Error(`Builtin function '${builtin_name}' expected ${builtin_def.inputs.length} arguments, got ${ast.arguments.length} at ${printLocation(ast.location)}`);
125
+ }
126
+ return variant("Builtin", {
127
+ type: toEastTypeValue(ast.type),
128
+ location: toLocationValue(ast.location),
129
+ builtin: ast.builtin,
130
+ type_parameters: ast.type_parameters.map(tp => toEastTypeValue(tp)),
131
+ arguments: ast.arguments.map((arg, i) => {
132
+ let arg_ir = ast_to_ir(arg, ctx);
133
+ const expectedType = applyTypeParameters(builtin_def.inputs[i], type_map, [], []);
134
+ // Special handling of FunctionType
135
+ if (expectedType.type === "Function") {
136
+ if (arg.type.type !== "Function") {
137
+ throw new Error(`Builtin ${builtin_name} with type parameters [${ast.type_parameters.map(tp => printType(tp)).join(", ")}] argument ${i} of type ${printType(arg.type)} is not compatible with expected type ${printType(expectedType)} at ${printLocation(ast.location)}`);
138
+ }
139
+ // Take the function argument's actual platform functions and populate here as a form of specialization
140
+ expectedType.platforms = arg.type.platforms;
141
+ }
142
+ // Now check type compatibility
143
+ if (arg.type.type !== "Never" && !isTypeEqual(arg.type, expectedType)) {
144
+ if (!isSubtype(arg.type, expectedType)) {
145
+ throw new Error(`Builtin ${builtin_name} with type parameters [${ast.type_parameters.map(tp => printType(tp)).join(", ")}] argument ${i} of type ${printType(arg.type)} is not compatible with expected type ${printType(expectedType)} at ${printLocation(ast.location)}`);
146
+ }
147
+ arg_ir = variant("As", {
148
+ type: toEastTypeValue(arg.type),
149
+ value: arg_ir,
150
+ location: toLocationValue(ast.location),
151
+ });
152
+ }
153
+ return arg_ir;
154
+ }),
155
+ });
156
+ }
157
+ else if (ast.ast_type === "Platform") {
158
+ return variant("Platform", {
159
+ type: toEastTypeValue(ast.type),
160
+ location: toLocationValue(ast.location),
161
+ name: ast.name,
162
+ arguments: ast.arguments.map(ast => ast_to_ir(ast, ctx)), // type equality handled at Expr/AST level
163
+ });
164
+ }
165
+ else if (ast.ast_type === "Struct") {
166
+ return variant("Struct", {
167
+ type: toEastTypeValue(ast.type),
168
+ location: toLocationValue(ast.location),
169
+ fields: Object.entries(ast.fields).map(([name, fieldAst]) => {
170
+ let value = ast_to_ir(fieldAst, ctx);
171
+ const expectedType = ast.type.fields[name];
172
+ if (!expectedType) {
173
+ throw new Error(`Struct type does not have field '${name}' at ${printLocation(ast.location)}`);
174
+ }
175
+ if (!isTypeEqual(fieldAst.type, expectedType)) {
176
+ if (isSubtype(fieldAst.type, expectedType)) {
177
+ value = variant("As", {
178
+ type: toEastTypeValue(expectedType),
179
+ value,
180
+ location: toLocationValue(ast.location),
181
+ });
182
+ }
183
+ else {
184
+ throw new Error(`Cannot assign field '${name}' of type ${printType(ast.type.fields[name])} ` +
185
+ `with value of type ${printType(fieldAst.type)} at ${printLocation(ast.location)}`);
186
+ }
187
+ }
188
+ return { name, value };
189
+ }),
190
+ });
191
+ }
192
+ else if (ast.ast_type === "GetField") {
193
+ return variant("GetField", {
194
+ type: toEastTypeValue(ast.type),
195
+ location: toLocationValue(ast.location),
196
+ struct: ast_to_ir(ast.struct, ctx),
197
+ field: ast.field,
198
+ });
199
+ }
200
+ else if (ast.ast_type === "Variant") {
201
+ const expectedType = ast.type.cases[ast.case];
202
+ let value = ast_to_ir(ast.value, ctx);
203
+ if (!isTypeEqual(ast.value.type, expectedType)) {
204
+ if (isSubtype(ast.value.type, expectedType)) {
205
+ value = variant("As", {
206
+ type: toEastTypeValue(expectedType),
207
+ value,
208
+ location: toLocationValue(ast.location),
209
+ });
210
+ }
211
+ else {
212
+ throw new Error(`Cannot assign case '${ast.case}' of type ${printType(expectedType)} ` +
213
+ `with value of type ${printType(ast.value.type)} at ${printLocation(ast.location)}`);
214
+ }
215
+ }
216
+ return variant("Variant", {
217
+ type: toEastTypeValue(ast.type),
218
+ location: toLocationValue(ast.location),
219
+ case: ast.case,
220
+ value,
221
+ });
222
+ }
223
+ else if (ast.ast_type === "Function") {
224
+ const parameters = ast.parameters.map(parameter => {
225
+ const param = variant("Variable", {
226
+ type: toEastTypeValue(parameter.type),
227
+ name: `_${ctx.n_vars}`,
228
+ location: toLocationValue(parameter.location),
229
+ mutable: parameter.mutable, // false...
230
+ captured: false,
231
+ });
232
+ ctx.n_vars += 1;
233
+ return param;
234
+ });
235
+ const local_ctx = new Map(parameters.map((parameter, i) => [ast.parameters[i], parameter]));
236
+ const parent_ctx = new Map([...ctx.local_ctx, ...ctx.parent_ctx]);
237
+ const captures = new Set();
238
+ const ctx2 = { local_ctx, parent_ctx, captures, loop_ctx: new Map(), n_vars: ctx.n_vars, n_loops: ctx.n_loops, inputs: ast.type.inputs, output: ast.type.output };
239
+ const body = ast_to_ir(ast.body, ctx2);
240
+ ctx.n_vars = ctx2.n_vars;
241
+ ctx.n_loops = ctx2.n_loops;
242
+ return variant("Function", {
243
+ type: toEastTypeValue(ast.type),
244
+ location: toLocationValue(ast.location),
245
+ parameters,
246
+ captures: [...captures],
247
+ body,
248
+ });
249
+ }
250
+ else if (ast.ast_type === "Call") {
251
+ // TODO - type equality could have been handled at Expr/AST level instead
252
+ return variant("Call", {
253
+ type: toEastTypeValue(ast.type),
254
+ location: toLocationValue(ast.location),
255
+ function: ast_to_ir(ast.function, ctx),
256
+ arguments: ast.arguments.map((argument, i) => {
257
+ let arg = ast_to_ir(argument, ctx);
258
+ const expectedType = ast.function.type.inputs[i];
259
+ if (!isTypeEqual(argument.type, expectedType)) {
260
+ if (!isSubtype(argument.type, expectedType)) {
261
+ throw new Error(`Argument ${i} of type ${printType(argument.type)} is not compatible with expected type ${printType(expectedType)} at ${printLocation(ast.location)}`);
262
+ }
263
+ arg = variant("As", {
264
+ type: toEastTypeValue(expectedType),
265
+ value: arg,
266
+ location: toLocationValue(ast.location),
267
+ });
268
+ }
269
+ return arg;
270
+ }),
271
+ });
272
+ }
273
+ else if (ast.ast_type === "NewRef") {
274
+ const valueType = ast.type.value;
275
+ let value = ast_to_ir(ast.value, ctx);
276
+ if (!isTypeEqual(ast.value.type, valueType)) {
277
+ if (!isSubtype(ast.value.type, valueType)) {
278
+ throw new Error(`Ref value of type ${printType(ast.value.type)} is not compatible with expected type ${printType(valueType)} at ${printLocation(ast.location)}`);
279
+ }
280
+ value = variant("As", {
281
+ type: toEastTypeValue(valueType),
282
+ value,
283
+ location: toLocationValue(ast.location),
284
+ });
285
+ }
286
+ return variant("NewRef", {
287
+ type: toEastTypeValue(ast.type),
288
+ location: toLocationValue(ast.location),
289
+ value,
290
+ });
291
+ }
292
+ else if (ast.ast_type === "NewArray") {
293
+ const valueType = ast.type.value;
294
+ return variant("NewArray", {
295
+ type: toEastTypeValue(ast.type),
296
+ location: toLocationValue(ast.location),
297
+ values: ast.values.map((v, i) => {
298
+ let value = ast_to_ir(v, ctx);
299
+ if (!isTypeEqual(v.type, valueType)) {
300
+ if (!isSubtype(v.type, valueType)) {
301
+ throw new Error(`Array value at entry ${i} of type ${printType(v.type)} is not compatible with expected type ${printType(valueType)} at ${printLocation(ast.location)}`);
302
+ }
303
+ value = variant("As", {
304
+ type: toEastTypeValue(valueType),
305
+ value,
306
+ location: toLocationValue(ast.location),
307
+ });
308
+ }
309
+ return value;
310
+ }),
311
+ });
312
+ }
313
+ else if (ast.ast_type === "NewSet") {
314
+ const keyType = ast.type.key;
315
+ return variant("NewSet", {
316
+ type: toEastTypeValue(ast.type),
317
+ location: toLocationValue(ast.location),
318
+ values: ast.values.map((k, i) => {
319
+ let key = ast_to_ir(k, ctx);
320
+ if (!isTypeEqual(k.type, keyType)) {
321
+ if (!isSubtype(k.type, keyType)) {
322
+ throw new Error(`Set key at entry ${i} of type ${printType(k.type)} is not compatible with expected type ${printType(keyType)} at ${printLocation(ast.location)}`);
323
+ }
324
+ key = variant("As", {
325
+ type: toEastTypeValue(keyType),
326
+ value: key,
327
+ location: toLocationValue(ast.location),
328
+ });
329
+ }
330
+ return key;
331
+ }),
332
+ });
333
+ }
334
+ else if (ast.ast_type === "NewDict") {
335
+ const keyType = ast.type.key;
336
+ const valueType = ast.type.value;
337
+ return variant("NewDict", {
338
+ type: toEastTypeValue(ast.type),
339
+ location: toLocationValue(ast.location),
340
+ values: ast.values.map(([k, v], i) => {
341
+ let key = ast_to_ir(k, ctx);
342
+ if (!isTypeEqual(k.type, keyType)) {
343
+ if (!isSubtype(k.type, keyType)) {
344
+ throw new Error(`Dict key at entry ${i} of type ${printType(k.type)} is not compatible with expected type ${printType(keyType)} at ${printLocation(ast.location)}`);
345
+ }
346
+ key = variant("As", {
347
+ type: toEastTypeValue(keyType),
348
+ value: key,
349
+ location: toLocationValue(ast.location),
350
+ });
351
+ }
352
+ let value = ast_to_ir(v, ctx);
353
+ if (!isTypeEqual(v.type, valueType)) {
354
+ if (!isSubtype(v.type, valueType)) {
355
+ throw new Error(`Dict value at entry ${i} of type ${printType(v.type)} is not compatible with expected type ${printType(valueType)} at ${printLocation(ast.location)}`);
356
+ }
357
+ value = variant("As", {
358
+ type: toEastTypeValue(valueType),
359
+ value,
360
+ location: toLocationValue(ast.location),
361
+ });
362
+ }
363
+ ;
364
+ return { key, value };
365
+ }),
366
+ });
367
+ }
368
+ else if (ast.ast_type === "IfElse") {
369
+ const ifs = ast.ifs.map(branch => {
370
+ const predicate = ast_to_ir(branch.predicate, ctx);
371
+ const ctx_branch = {
372
+ local_ctx: new Map([...ctx.local_ctx]),
373
+ parent_ctx: ctx.parent_ctx,
374
+ captures: ctx.captures,
375
+ loop_ctx: ctx.loop_ctx,
376
+ n_vars: ctx.n_vars,
377
+ n_loops: ctx.n_loops,
378
+ inputs: ctx.inputs,
379
+ output: ctx.output,
380
+ };
381
+ let branch_body = ast_to_ir(branch.body, ctx_branch);
382
+ ctx.n_vars = ctx_branch.n_vars;
383
+ ctx.n_loops = ctx_branch.n_loops;
384
+ if (branch.body.type.type !== "Never" && !isTypeEqual(branch.body.type, ast.type)) {
385
+ if (!isSubtype(branch.body.type, ast.type)) {
386
+ throw new Error(`If branch body of type ${printType(branch.body.type)} is not compatible with expected type ${printType(ast.type)} at ${printLocation(ast.location)}`);
387
+ }
388
+ branch_body = variant("As", {
389
+ type: toEastTypeValue(ast.type),
390
+ value: branch_body,
391
+ location: toLocationValue(ast.location),
392
+ });
393
+ }
394
+ return { predicate, body: branch_body };
395
+ });
396
+ const ctx_else = {
397
+ local_ctx: new Map([...ctx.local_ctx]),
398
+ parent_ctx: ctx.parent_ctx,
399
+ captures: ctx.captures,
400
+ loop_ctx: ctx.loop_ctx,
401
+ n_vars: ctx.n_vars,
402
+ n_loops: ctx.n_loops,
403
+ inputs: ctx.inputs,
404
+ output: ctx.output,
405
+ };
406
+ let else_body = ast_to_ir(ast.else_body, ctx_else);
407
+ ctx.n_vars = ctx_else.n_vars;
408
+ ctx.n_loops = ctx_else.n_loops;
409
+ if (ast.else_body.type.type !== "Never" && !isTypeEqual(ast.else_body.type, ast.type)) {
410
+ if (!isSubtype(ast.else_body.type, ast.type)) {
411
+ throw new Error(`Else branch body of type ${printType(ast.else_body.type)} is not compatible with expected type ${printType(ast.type)} at ${printLocation(ast.location)}`);
412
+ }
413
+ else_body = variant("As", {
414
+ type: toEastTypeValue(ast.type),
415
+ value: else_body,
416
+ location: toLocationValue(ast.location),
417
+ });
418
+ }
419
+ return variant("IfElse", {
420
+ type: toEastTypeValue(ast.type),
421
+ location: toLocationValue(ast.location),
422
+ ifs,
423
+ else_body,
424
+ });
425
+ }
426
+ else if (ast.ast_type === "Error") {
427
+ return variant("Error", {
428
+ type: variant("Never", null),
429
+ location: toLocationValue(ast.location),
430
+ message: ast_to_ir(ast.message, ctx),
431
+ });
432
+ }
433
+ else if (ast.ast_type === "TryCatch") {
434
+ const ctx_try = {
435
+ local_ctx: new Map([...ctx.local_ctx]),
436
+ parent_ctx: ctx.parent_ctx,
437
+ captures: ctx.captures,
438
+ loop_ctx: ctx.loop_ctx,
439
+ n_vars: ctx.n_vars,
440
+ n_loops: ctx.n_loops,
441
+ inputs: ctx.inputs,
442
+ output: ctx.output,
443
+ };
444
+ const try_body = ast_to_ir(ast.try_body, ctx_try);
445
+ ctx.n_vars = ctx_try.n_vars;
446
+ ctx.n_loops = ctx_try.n_loops;
447
+ // Create new variables for the catch message and stack
448
+ const message = variant("Variable", {
449
+ type: toEastTypeValue(ast.message.type),
450
+ name: `_${ctx.n_vars}`,
451
+ location: toLocationValue(ast.message.location),
452
+ mutable: ast.message.mutable, // false...
453
+ captured: false,
454
+ });
455
+ ctx.n_vars += 1;
456
+ const stack = variant("Variable", {
457
+ type: toEastTypeValue(ast.stack.type),
458
+ name: `_${ctx.n_vars}`,
459
+ location: toLocationValue(ast.stack.location),
460
+ mutable: ast.stack.mutable, // false...
461
+ captured: false,
462
+ });
463
+ ctx.n_vars += 1;
464
+ const ctx_catch = {
465
+ local_ctx: new Map([...ctx.local_ctx, [ast.message, message], [ast.stack, stack]]),
466
+ parent_ctx: ctx.parent_ctx,
467
+ captures: ctx.captures,
468
+ loop_ctx: ctx.loop_ctx,
469
+ n_vars: ctx.n_vars,
470
+ n_loops: ctx.n_loops,
471
+ inputs: ctx.inputs,
472
+ output: ctx.output,
473
+ };
474
+ const catch_body = ast_to_ir(ast.catch_body, ctx_catch);
475
+ ctx.n_vars = ctx_catch.n_vars;
476
+ ctx.n_loops = ctx_catch.n_loops;
477
+ // Process finally block if present
478
+ let finally_body;
479
+ if (ast.finally_body) {
480
+ const ctx_finally = {
481
+ local_ctx: new Map([...ctx.local_ctx]),
482
+ parent_ctx: ctx.parent_ctx,
483
+ captures: ctx.captures,
484
+ loop_ctx: ctx.loop_ctx,
485
+ n_vars: ctx.n_vars,
486
+ n_loops: ctx.n_loops,
487
+ inputs: ctx.inputs,
488
+ output: ctx.output,
489
+ };
490
+ finally_body = ast_to_ir(ast.finally_body, ctx_finally);
491
+ ctx.n_vars = ctx_finally.n_vars;
492
+ ctx.n_loops = ctx_finally.n_loops;
493
+ }
494
+ else {
495
+ finally_body = variant("Value", {
496
+ type: toEastTypeValue(NullType),
497
+ location: toLocationValue(ast.location),
498
+ value: variant("Null", null),
499
+ });
500
+ }
501
+ return variant("TryCatch", {
502
+ type: toEastTypeValue(ast.type),
503
+ location: toLocationValue(ast.location),
504
+ try_body,
505
+ catch_body,
506
+ message,
507
+ stack,
508
+ finally_body,
509
+ });
510
+ }
511
+ else if (ast.ast_type === "Value") {
512
+ const type = toEastTypeValue(ast.type);
513
+ let value;
514
+ if (ast.value === null) {
515
+ value = variant("Null", null);
516
+ }
517
+ else if (typeof ast.value === "boolean") {
518
+ value = variant("Boolean", ast.value);
519
+ }
520
+ else if (typeof ast.value === "bigint") {
521
+ value = variant("Integer", ast.value);
522
+ }
523
+ else if (typeof ast.value === "number") {
524
+ value = variant("Float", ast.value);
525
+ }
526
+ else if (typeof ast.value === "string") {
527
+ value = variant("String", ast.value);
528
+ }
529
+ else if (ast.value instanceof Date) {
530
+ value = variant("DateTime", new Date(ast.value));
531
+ }
532
+ else if (ast.value instanceof Uint8Array) {
533
+ value = variant("Blob", new Uint8Array(ast.value));
534
+ }
535
+ else {
536
+ throw new Error(`Unsupported literal value type: ${typeof ast.value} (expected ${printType(ast.type)})`);
537
+ }
538
+ if (type.type !== value.type) {
539
+ throw new Error(`Literal value type mismatch at ${printLocation(ast.location)}: expected .${type.type} but got .${value.type}`);
540
+ }
541
+ return variant("Value", {
542
+ type,
543
+ location: toLocationValue(ast.location),
544
+ value,
545
+ });
546
+ }
547
+ else if (ast.ast_type === "As") {
548
+ return variant("As", {
549
+ type: toEastTypeValue(ast.type),
550
+ location: toLocationValue(ast.location),
551
+ value: ast_to_ir(ast.value, ctx),
552
+ });
553
+ }
554
+ else if (ast.ast_type === "While") {
555
+ const predicate = ast_to_ir(ast.predicate, ctx);
556
+ const label = {
557
+ name: `_${ctx.n_loops}`,
558
+ location: toLocationValue(ast.label.location),
559
+ };
560
+ ctx.n_loops += 1;
561
+ const ctx2 = {
562
+ local_ctx: new Map([...ctx.local_ctx]),
563
+ parent_ctx: ctx.parent_ctx,
564
+ captures: ctx.captures,
565
+ loop_ctx: new Map([...ctx.loop_ctx, [ast.label, label]]),
566
+ n_vars: ctx.n_vars,
567
+ n_loops: ctx.n_loops,
568
+ inputs: ctx.inputs,
569
+ output: ctx.output,
570
+ };
571
+ const body = ast_to_ir(ast.body, ctx2);
572
+ ctx.n_vars = ctx2.n_vars;
573
+ ctx.n_loops = ctx2.n_loops;
574
+ return variant("While", {
575
+ type: variant("Null", null),
576
+ location: toLocationValue(ast.location),
577
+ label,
578
+ predicate,
579
+ body,
580
+ });
581
+ }
582
+ else if (ast.ast_type === "ForArray") {
583
+ const array = ast_to_ir(ast.array, ctx);
584
+ const label = {
585
+ name: `_${ctx.n_loops}`,
586
+ location: toLocationValue(ast.label.location),
587
+ };
588
+ ctx.n_loops += 1;
589
+ const value = variant("Variable", {
590
+ type: toEastTypeValue(ast.value.type),
591
+ name: `_${ctx.n_vars}`,
592
+ location: toLocationValue(ast.value.location),
593
+ mutable: ast.value.mutable, // false...
594
+ captured: false,
595
+ });
596
+ ctx.n_vars += 1;
597
+ const key = variant("Variable", {
598
+ type: toEastTypeValue(ast.key.type),
599
+ name: `_${ctx.n_vars}`,
600
+ location: toLocationValue(ast.key.location),
601
+ mutable: ast.key.mutable, // false...
602
+ captured: false,
603
+ });
604
+ ctx.n_vars += 1;
605
+ const ctx2 = {
606
+ local_ctx: new Map([...ctx.local_ctx, [ast.value, value], [ast.key, key]]),
607
+ parent_ctx: ctx.parent_ctx,
608
+ captures: ctx.captures,
609
+ loop_ctx: new Map([...ctx.loop_ctx, [ast.label, label]]),
610
+ n_vars: ctx.n_vars,
611
+ n_loops: ctx.n_loops,
612
+ inputs: ctx.inputs,
613
+ output: ctx.output,
614
+ };
615
+ const body = ast_to_ir(ast.body, ctx2);
616
+ ctx.n_vars = ctx2.n_vars;
617
+ ctx.n_loops = ctx2.n_loops;
618
+ return variant("ForArray", {
619
+ type: variant("Null", null),
620
+ location: toLocationValue(ast.location),
621
+ label,
622
+ key,
623
+ value,
624
+ array,
625
+ body,
626
+ });
627
+ }
628
+ else if (ast.ast_type === "ForSet") {
629
+ const set = ast_to_ir(ast.set, ctx);
630
+ const label = {
631
+ name: `_${ctx.n_loops}`,
632
+ location: toLocationValue(ast.label.location),
633
+ };
634
+ ctx.n_loops += 1;
635
+ const key = variant("Variable", {
636
+ type: toEastTypeValue(ast.key.type),
637
+ name: `_${ctx.n_vars}`,
638
+ location: toLocationValue(ast.key.location),
639
+ mutable: ast.key.mutable, // false...
640
+ captured: false,
641
+ });
642
+ ctx.n_vars += 1;
643
+ const ctx2 = {
644
+ local_ctx: new Map([...ctx.local_ctx, [ast.key, key]]),
645
+ parent_ctx: ctx.parent_ctx,
646
+ captures: ctx.captures,
647
+ loop_ctx: new Map([...ctx.loop_ctx, [ast.label, label]]),
648
+ n_vars: ctx.n_vars,
649
+ n_loops: ctx.n_loops,
650
+ inputs: ctx.inputs,
651
+ output: ctx.output,
652
+ };
653
+ const body = ast_to_ir(ast.body, ctx2);
654
+ ctx.n_vars = ctx2.n_vars;
655
+ ctx.n_loops = ctx2.n_loops;
656
+ return variant("ForSet", {
657
+ type: variant("Null", null),
658
+ location: toLocationValue(ast.location),
659
+ label,
660
+ key,
661
+ set,
662
+ body,
663
+ });
664
+ }
665
+ else if (ast.ast_type === "ForDict") {
666
+ const dict = ast_to_ir(ast.dict, ctx);
667
+ const label = {
668
+ name: `_${ctx.n_loops}`,
669
+ location: toLocationValue(ast.label.location),
670
+ };
671
+ ctx.n_loops += 1;
672
+ const value = variant("Variable", {
673
+ type: toEastTypeValue(ast.value.type),
674
+ name: `_${ctx.n_vars}`,
675
+ location: toLocationValue(ast.value.location),
676
+ mutable: ast.value.mutable, // false...
677
+ captured: false,
678
+ });
679
+ ctx.n_vars += 1;
680
+ const key = variant("Variable", {
681
+ type: toEastTypeValue(ast.key.type),
682
+ name: `_${ctx.n_vars}`,
683
+ location: toLocationValue(ast.key.location),
684
+ mutable: ast.key.mutable, // false...
685
+ captured: false,
686
+ });
687
+ ctx.n_vars += 1;
688
+ const ctx2 = {
689
+ local_ctx: new Map([...ctx.local_ctx, [ast.value, value], [ast.key, key]]),
690
+ parent_ctx: ctx.parent_ctx,
691
+ captures: ctx.captures,
692
+ loop_ctx: new Map([...ctx.loop_ctx, [ast.label, label]]),
693
+ n_vars: ctx.n_vars,
694
+ n_loops: ctx.n_loops,
695
+ inputs: ctx.inputs,
696
+ output: ctx.output,
697
+ };
698
+ const body = ast_to_ir(ast.body, ctx2);
699
+ ctx.n_vars = ctx2.n_vars;
700
+ ctx.n_loops = ctx2.n_loops;
701
+ return variant("ForDict", {
702
+ type: variant("Null", null),
703
+ location: toLocationValue(ast.location),
704
+ label,
705
+ key,
706
+ value,
707
+ dict,
708
+ body,
709
+ });
710
+ }
711
+ else if (ast.ast_type === "Match") {
712
+ const variant_expr = ast_to_ir(ast.variant, ctx);
713
+ const cases = [];
714
+ for (const [k, v] of Object.entries(ast.cases)) {
715
+ const variable = variant("Variable", {
716
+ type: toEastTypeValue(v.variable.type),
717
+ name: `_${ctx.n_vars}`,
718
+ location: toLocationValue(v.variable.location),
719
+ mutable: v.variable.mutable, // false...
720
+ captured: false,
721
+ });
722
+ ctx.n_vars += 1;
723
+ const ctx2 = {
724
+ local_ctx: new Map([...ctx.local_ctx, [v.variable, variable]]),
725
+ parent_ctx: ctx.parent_ctx,
726
+ captures: ctx.captures,
727
+ loop_ctx: ctx.loop_ctx,
728
+ n_vars: ctx.n_vars,
729
+ n_loops: ctx.n_loops,
730
+ inputs: ctx.inputs,
731
+ output: ctx.output,
732
+ };
733
+ let body = ast_to_ir(v.body, ctx2);
734
+ ctx.n_vars = ctx2.n_vars;
735
+ ctx.n_loops = ctx2.n_loops;
736
+ if (v.body.type.type !== "Never" && !isTypeEqual(v.body.type, ast.type)) {
737
+ if (!isSubtype(v.body.type, ast.type)) {
738
+ throw new Error(`Match case '${k}' body of type ${printType(v.body.type)} is not compatible with expected type ${printType(ast.type)} at ${printLocation(ast.location)}`);
739
+ }
740
+ body = variant("As", {
741
+ type: toEastTypeValue(ast.type),
742
+ value: body,
743
+ location: toLocationValue(ast.location),
744
+ });
745
+ }
746
+ cases.push({ case: k, variable, body });
747
+ }
748
+ return variant("Match", {
749
+ type: toEastTypeValue(ast.type),
750
+ location: toLocationValue(ast.location),
751
+ variant: variant_expr,
752
+ cases,
753
+ });
754
+ }
755
+ else if (ast.ast_type === "UnwrapRecursive") {
756
+ return variant("UnwrapRecursive", {
757
+ type: toEastTypeValue(ast.type),
758
+ location: toLocationValue(ast.location),
759
+ value: ast_to_ir(ast.value, ctx),
760
+ });
761
+ }
762
+ else if (ast.ast_type === "WrapRecursive") {
763
+ // Check if we're already converting this AST node -> circular reference
764
+ if (!ctx.recursiveASTs) {
765
+ ctx.recursiveASTs = new Set();
766
+ }
767
+ const existing = ctx.recursiveASTs.has(ast);
768
+ if (existing) {
769
+ throw new Error(`Circular reference detected when converting AST to IR at ${printLocation(ast.location)}`);
770
+ }
771
+ // Register before recursing (enables cycle detection)
772
+ ctx.recursiveASTs.add(ast);
773
+ // Create WrapRecursive IR node with placeholder
774
+ const wrapIR = variant("WrapRecursive", {
775
+ type: toEastTypeValue(ast.type),
776
+ location: toLocationValue(ast.location),
777
+ value: ast_to_ir(ast.value, ctx),
778
+ });
779
+ // The user may alias this AST value elsewhere in the tree, just not with a circular reference
780
+ ctx.recursiveASTs.delete(ast);
781
+ return wrapIR;
782
+ }
783
+ else if (ast.ast_type === "Break") {
784
+ const label = ctx.loop_ctx.get(ast.label);
785
+ if (label === undefined) {
786
+ throw new Error(`Label defined at ${printLocation(ast.label.location)} is not in scope at break at ${printLocation(ast.location)}`);
787
+ }
788
+ return variant("Break", {
789
+ type: variant("Never", null),
790
+ location: toLocationValue(ast.location),
791
+ label,
792
+ });
793
+ }
794
+ else if (ast.ast_type === "Continue") {
795
+ const label = ctx.loop_ctx.get(ast.label);
796
+ if (label === undefined) {
797
+ throw new Error(`Label defined at ${printLocation(ast.label.location)} is not in scope at continue at ${printLocation(ast.location)}`);
798
+ }
799
+ return variant("Continue", {
800
+ type: variant("Never", null),
801
+ location: toLocationValue(ast.location),
802
+ label,
803
+ });
804
+ }
805
+ else if (ast.ast_type === "Return") {
806
+ if (!isSubtype(ast.value.type, ctx.output)) {
807
+ throw new Error(`Attempted to return value of type ${printType(ast.value.type)} at ${printLocation(ast.location)}, but function expected return type of ${printType(ctx.output)}`);
808
+ }
809
+ return variant("Return", {
810
+ type: variant("Never", null),
811
+ location: toLocationValue(ast.location),
812
+ value: ast_to_ir(ast.value, ctx),
813
+ });
814
+ }
815
+ else {
816
+ throw new Error(`Cannot check ${ast.type}`);
817
+ }
818
+ }
819
+ catch (e) {
820
+ if (e instanceof Error) {
821
+ if (ast.ast_type === "Builtin") {
822
+ e.message += `\n at ${ast.ast_type} ${ast.builtin} node located at ${printLocation(ast.location)}`;
823
+ }
824
+ else if (ast.ast_type === "Platform") {
825
+ e.message += `\n at ${ast.ast_type} ${ast.name} node located at ${printLocation(ast.location)}`;
826
+ }
827
+ else {
828
+ e.message += `\n at ${ast.ast_type} node located at ${printLocation(ast.location)}`;
829
+ }
830
+ }
831
+ throw e;
832
+ }
833
+ }
834
+ //# sourceMappingURL=ast_to_ir.js.map