@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.
- package/LICENSE.md +682 -0
- package/README.md +276 -0
- package/dist/src/analyze.d.ts +95 -0
- package/dist/src/analyze.d.ts.map +1 -0
- package/dist/src/analyze.js +1110 -0
- package/dist/src/analyze.js.map +1 -0
- package/dist/src/ast.d.ts +263 -0
- package/dist/src/ast.d.ts.map +1 -0
- package/dist/src/ast.js +151 -0
- package/dist/src/ast.js.map +1 -0
- package/dist/src/ast_to_ir.d.ts +24 -0
- package/dist/src/ast_to_ir.d.ts.map +1 -0
- package/dist/src/ast_to_ir.js +834 -0
- package/dist/src/ast_to_ir.js.map +1 -0
- package/dist/src/builtins.d.ts +18 -0
- package/dist/src/builtins.d.ts.map +1 -0
- package/dist/src/builtins.js +1105 -0
- package/dist/src/builtins.js.map +1 -0
- package/dist/src/comparison.d.ts +28 -0
- package/dist/src/comparison.d.ts.map +1 -0
- package/dist/src/comparison.js +1017 -0
- package/dist/src/comparison.js.map +1 -0
- package/dist/src/compile.d.ts +22 -0
- package/dist/src/compile.d.ts.map +1 -0
- package/dist/src/compile.js +3260 -0
- package/dist/src/compile.js.map +1 -0
- package/dist/src/containers/ref.d.ts +106 -0
- package/dist/src/containers/ref.d.ts.map +1 -0
- package/dist/src/containers/ref.js +100 -0
- package/dist/src/containers/ref.js.map +1 -0
- package/dist/src/containers/sortedmap.d.ts +165 -0
- package/dist/src/containers/sortedmap.d.ts.map +1 -0
- package/dist/src/containers/sortedmap.js +237 -0
- package/dist/src/containers/sortedmap.js.map +1 -0
- package/dist/src/containers/sortedset.d.ts +185 -0
- package/dist/src/containers/sortedset.d.ts.map +1 -0
- package/dist/src/containers/sortedset.js +312 -0
- package/dist/src/containers/sortedset.js.map +1 -0
- package/dist/src/containers/variant.d.ts +131 -0
- package/dist/src/containers/variant.d.ts.map +1 -0
- package/dist/src/containers/variant.js +68 -0
- package/dist/src/containers/variant.js.map +1 -0
- package/dist/src/datetime_format/parse.d.ts +50 -0
- package/dist/src/datetime_format/parse.d.ts.map +1 -0
- package/dist/src/datetime_format/parse.js +908 -0
- package/dist/src/datetime_format/parse.js.map +1 -0
- package/dist/src/datetime_format/print.d.ts +35 -0
- package/dist/src/datetime_format/print.d.ts.map +1 -0
- package/dist/src/datetime_format/print.js +157 -0
- package/dist/src/datetime_format/print.js.map +1 -0
- package/dist/src/datetime_format/tokenize.d.ts +76 -0
- package/dist/src/datetime_format/tokenize.d.ts.map +1 -0
- package/dist/src/datetime_format/tokenize.js +271 -0
- package/dist/src/datetime_format/tokenize.js.map +1 -0
- package/dist/src/datetime_format/types.d.ts +99 -0
- package/dist/src/datetime_format/types.d.ts.map +1 -0
- package/dist/src/datetime_format/types.js +103 -0
- package/dist/src/datetime_format/types.js.map +1 -0
- package/dist/src/datetime_format/validate.d.ts +51 -0
- package/dist/src/datetime_format/validate.d.ts.map +1 -0
- package/dist/src/datetime_format/validate.js +208 -0
- package/dist/src/datetime_format/validate.js.map +1 -0
- package/dist/src/default.d.ts +21 -0
- package/dist/src/default.d.ts.map +1 -0
- package/dist/src/default.js +82 -0
- package/dist/src/default.js.map +1 -0
- package/dist/src/eastir.d.ts +33 -0
- package/dist/src/eastir.d.ts.map +1 -0
- package/dist/src/eastir.js +92 -0
- package/dist/src/eastir.js.map +1 -0
- package/dist/src/error.d.ts +13 -0
- package/dist/src/error.d.ts.map +1 -0
- package/dist/src/error.js +8 -0
- package/dist/src/error.js.map +1 -0
- package/dist/src/expr/array.d.ts +1711 -0
- package/dist/src/expr/array.d.ts.map +1 -0
- package/dist/src/expr/array.js +1805 -0
- package/dist/src/expr/array.js.map +1 -0
- package/dist/src/expr/ast.d.ts +17 -0
- package/dist/src/expr/ast.d.ts.map +1 -0
- package/dist/src/expr/ast.js +302 -0
- package/dist/src/expr/ast.js.map +1 -0
- package/dist/src/expr/blob.d.ts +141 -0
- package/dist/src/expr/blob.d.ts.map +1 -0
- package/dist/src/expr/blob.js +198 -0
- package/dist/src/expr/blob.js.map +1 -0
- package/dist/src/expr/block.d.ts +201 -0
- package/dist/src/expr/block.d.ts.map +1 -0
- package/dist/src/expr/block.js +1505 -0
- package/dist/src/expr/block.js.map +1 -0
- package/dist/src/expr/boolean.d.ts +207 -0
- package/dist/src/expr/boolean.d.ts.map +1 -0
- package/dist/src/expr/boolean.js +261 -0
- package/dist/src/expr/boolean.js.map +1 -0
- package/dist/src/expr/datetime.d.ts +544 -0
- package/dist/src/expr/datetime.d.ts.map +1 -0
- package/dist/src/expr/datetime.js +980 -0
- package/dist/src/expr/datetime.js.map +1 -0
- package/dist/src/expr/dict.d.ts +1242 -0
- package/dist/src/expr/dict.d.ts.map +1 -0
- package/dist/src/expr/dict.js +1492 -0
- package/dist/src/expr/dict.js.map +1 -0
- package/dist/src/expr/expr.d.ts +95 -0
- package/dist/src/expr/expr.d.ts.map +1 -0
- package/dist/src/expr/expr.js +171 -0
- package/dist/src/expr/expr.js.map +1 -0
- package/dist/src/expr/float.d.ts +357 -0
- package/dist/src/expr/float.d.ts.map +1 -0
- package/dist/src/expr/float.js +637 -0
- package/dist/src/expr/float.js.map +1 -0
- package/dist/src/expr/function.d.ts +46 -0
- package/dist/src/expr/function.d.ts.map +1 -0
- package/dist/src/expr/function.js +58 -0
- package/dist/src/expr/function.js.map +1 -0
- package/dist/src/expr/index.d.ts +450 -0
- package/dist/src/expr/index.d.ts.map +1 -0
- package/dist/src/expr/index.js +423 -0
- package/dist/src/expr/index.js.map +1 -0
- package/dist/src/expr/integer.d.ts +256 -0
- package/dist/src/expr/integer.d.ts.map +1 -0
- package/dist/src/expr/integer.js +311 -0
- package/dist/src/expr/integer.js.map +1 -0
- package/dist/src/expr/libs/array.d.ts +106 -0
- package/dist/src/expr/libs/array.d.ts.map +1 -0
- package/dist/src/expr/libs/array.js +140 -0
- package/dist/src/expr/libs/array.js.map +1 -0
- package/dist/src/expr/libs/blob.d.ts +42 -0
- package/dist/src/expr/libs/blob.d.ts.map +1 -0
- package/dist/src/expr/libs/blob.js +70 -0
- package/dist/src/expr/libs/blob.js.map +1 -0
- package/dist/src/expr/libs/datetime.d.ts +479 -0
- package/dist/src/expr/libs/datetime.d.ts.map +1 -0
- package/dist/src/expr/libs/datetime.js +624 -0
- package/dist/src/expr/libs/datetime.js.map +1 -0
- package/dist/src/expr/libs/dict.d.ts +66 -0
- package/dist/src/expr/libs/dict.d.ts.map +1 -0
- package/dist/src/expr/libs/dict.js +77 -0
- package/dist/src/expr/libs/dict.js.map +1 -0
- package/dist/src/expr/libs/float.d.ts +299 -0
- package/dist/src/expr/libs/float.d.ts.map +1 -0
- package/dist/src/expr/libs/float.js +564 -0
- package/dist/src/expr/libs/float.js.map +1 -0
- package/dist/src/expr/libs/integer.d.ts +228 -0
- package/dist/src/expr/libs/integer.d.ts.map +1 -0
- package/dist/src/expr/libs/integer.js +398 -0
- package/dist/src/expr/libs/integer.js.map +1 -0
- package/dist/src/expr/libs/set.d.ts +59 -0
- package/dist/src/expr/libs/set.d.ts.map +1 -0
- package/dist/src/expr/libs/set.js +69 -0
- package/dist/src/expr/libs/set.js.map +1 -0
- package/dist/src/expr/libs/string.d.ts +71 -0
- package/dist/src/expr/libs/string.d.ts.map +1 -0
- package/dist/src/expr/libs/string.js +75 -0
- package/dist/src/expr/libs/string.js.map +1 -0
- package/dist/src/expr/never.d.ts +15 -0
- package/dist/src/expr/never.d.ts.map +1 -0
- package/dist/src/expr/never.js +12 -0
- package/dist/src/expr/never.js.map +1 -0
- package/dist/src/expr/null.d.ts +15 -0
- package/dist/src/expr/null.d.ts.map +1 -0
- package/dist/src/expr/null.js +12 -0
- package/dist/src/expr/null.js.map +1 -0
- package/dist/src/expr/ref.d.ts +103 -0
- package/dist/src/expr/ref.d.ts.map +1 -0
- package/dist/src/expr/ref.js +131 -0
- package/dist/src/expr/ref.js.map +1 -0
- package/dist/src/expr/regex_validation.d.ts +25 -0
- package/dist/src/expr/regex_validation.d.ts.map +1 -0
- package/dist/src/expr/regex_validation.js +130 -0
- package/dist/src/expr/regex_validation.js.map +1 -0
- package/dist/src/expr/set.d.ts +1071 -0
- package/dist/src/expr/set.d.ts.map +1 -0
- package/dist/src/expr/set.js +1137 -0
- package/dist/src/expr/set.js.map +1 -0
- package/dist/src/expr/string.d.ts +414 -0
- package/dist/src/expr/string.d.ts.map +1 -0
- package/dist/src/expr/string.js +683 -0
- package/dist/src/expr/string.js.map +1 -0
- package/dist/src/expr/struct.d.ts +48 -0
- package/dist/src/expr/struct.d.ts.map +1 -0
- package/dist/src/expr/struct.js +65 -0
- package/dist/src/expr/struct.js.map +1 -0
- package/dist/src/expr/types.d.ts +68 -0
- package/dist/src/expr/types.d.ts.map +1 -0
- package/dist/src/expr/types.js +6 -0
- package/dist/src/expr/types.js.map +1 -0
- package/dist/src/expr/variant.d.ts +137 -0
- package/dist/src/expr/variant.d.ts.map +1 -0
- package/dist/src/expr/variant.js +105 -0
- package/dist/src/expr/variant.js.map +1 -0
- package/dist/src/fuzz.d.ts +80 -0
- package/dist/src/fuzz.d.ts.map +1 -0
- package/dist/src/fuzz.js +300 -0
- package/dist/src/fuzz.js.map +1 -0
- package/dist/src/index.d.ts +21 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +21 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/internal.d.ts +36 -0
- package/dist/src/internal.d.ts.map +1 -0
- package/dist/src/internal.js +11 -0
- package/dist/src/internal.js.map +1 -0
- package/dist/src/ir.d.ts +1571 -0
- package/dist/src/ir.d.ts.map +1 -0
- package/dist/src/ir.js +56 -0
- package/dist/src/ir.js.map +1 -0
- package/dist/src/location.d.ts +48 -0
- package/dist/src/location.d.ts.map +1 -0
- package/dist/src/location.js +62 -0
- package/dist/src/location.js.map +1 -0
- package/dist/src/platform.d.ts +21 -0
- package/dist/src/platform.d.ts.map +1 -0
- package/dist/src/platform.js +8 -0
- package/dist/src/platform.js.map +1 -0
- package/dist/src/serialization/beast.d.ts +39 -0
- package/dist/src/serialization/beast.d.ts.map +1 -0
- package/dist/src/serialization/beast.js +555 -0
- package/dist/src/serialization/beast.js.map +1 -0
- package/dist/src/serialization/beast2-stream.d.ts +38 -0
- package/dist/src/serialization/beast2-stream.d.ts.map +1 -0
- package/dist/src/serialization/beast2-stream.js +665 -0
- package/dist/src/serialization/beast2-stream.js.map +1 -0
- package/dist/src/serialization/beast2.d.ts +41 -0
- package/dist/src/serialization/beast2.d.ts.map +1 -0
- package/dist/src/serialization/beast2.js +489 -0
- package/dist/src/serialization/beast2.js.map +1 -0
- package/dist/src/serialization/binary-utils.d.ts +151 -0
- package/dist/src/serialization/binary-utils.d.ts.map +1 -0
- package/dist/src/serialization/binary-utils.js +929 -0
- package/dist/src/serialization/binary-utils.js.map +1 -0
- package/dist/src/serialization/east.d.ts +84 -0
- package/dist/src/serialization/east.d.ts.map +1 -0
- package/dist/src/serialization/east.js +1802 -0
- package/dist/src/serialization/east.js.map +1 -0
- package/dist/src/serialization/index.d.ts +11 -0
- package/dist/src/serialization/index.d.ts.map +1 -0
- package/dist/src/serialization/index.js +12 -0
- package/dist/src/serialization/index.js.map +1 -0
- package/dist/src/serialization/json.d.ts +36 -0
- package/dist/src/serialization/json.d.ts.map +1 -0
- package/dist/src/serialization/json.js +849 -0
- package/dist/src/serialization/json.js.map +1 -0
- package/dist/src/type_of_type.d.ts +115 -0
- package/dist/src/type_of_type.d.ts.map +1 -0
- package/dist/src/type_of_type.js +362 -0
- package/dist/src/type_of_type.js.map +1 -0
- package/dist/src/types.d.ts +648 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +1631 -0
- package/dist/src/types.js.map +1 -0
- 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
|