@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,1137 @@
|
|
|
1
|
+
import { get_location } from "../location.js";
|
|
2
|
+
import { SetType, BooleanType, FunctionType, IntegerType, NullType, NeverType, DictType, printType, FloatType, isTypeEqual, ArrayType, VariantType } from "../types.js";
|
|
3
|
+
import { valueOrExprToAst, valueOrExprToAstTyped } from "./ast.js";
|
|
4
|
+
import { AstSymbol, Expr, TypeSymbol } from "./expr.js";
|
|
5
|
+
import { none, some } from "../containers/variant.js";
|
|
6
|
+
/**
|
|
7
|
+
* Expression representing set (sorted unique collection) values and operations.
|
|
8
|
+
*
|
|
9
|
+
* SetExpr provides methods for working with sorted sets including membership testing, insertion,
|
|
10
|
+
* deletion, iteration, mapping, filtering, set operations (union, intersection, difference), and
|
|
11
|
+
* aggregation operations. Sets maintain their elements sorted by key using East's total ordering
|
|
12
|
+
* and guarantee uniqueness.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* // Creating and manipulating sets
|
|
17
|
+
* const buildSet = East.function([ArrayType(StringType)], SetType(StringType), ($, items) => {
|
|
18
|
+
* const uniqueItems = Expr.from(new Set(), SetType(StringType));
|
|
19
|
+
* $(items.forEach(($, item) => {
|
|
20
|
+
* $(uniqueItems.tryInsert(item));
|
|
21
|
+
* }));
|
|
22
|
+
* $.return(uniqueItems);
|
|
23
|
+
* });
|
|
24
|
+
* const compiled = East.compile(buildSet.toIR(), []);
|
|
25
|
+
* compiled(["apple", "banana", "apple", "cherry"]); // Set(["apple", "banana", "cherry"])
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* // Set operations
|
|
31
|
+
* const unionSets = East.function([SetType(IntegerType), SetType(IntegerType)], SetType(IntegerType), ($, set1, set2) => {
|
|
32
|
+
* $.return(set1.union(set2));
|
|
33
|
+
* });
|
|
34
|
+
* const compiled = East.compile(unionSets.toIR(), []);
|
|
35
|
+
* compiled(new Set([1n, 2n, 3n]), new Set([3n, 4n, 5n])); // Set([1n, 2n, 3n, 4n, 5n])
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export class SetExpr extends Expr {
|
|
39
|
+
key_type;
|
|
40
|
+
constructor(key_type, ast, createExpr) {
|
|
41
|
+
super(ast.type, ast, createExpr);
|
|
42
|
+
this.key_type = key_type;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Returns the number of elements in the set.
|
|
46
|
+
*
|
|
47
|
+
* @returns An IntegerExpr representing the count of elements
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* const getSize = East.function([SetType(StringType)], IntegerType, ($, set) => {
|
|
52
|
+
* $.return(set.size());
|
|
53
|
+
* });
|
|
54
|
+
* const compiled = East.compile(getSize.toIR(), []);
|
|
55
|
+
* compiled(new Set(["a", "b", "c"])); // 3n
|
|
56
|
+
* compiled(new Set()); // 0n
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
size() {
|
|
60
|
+
return Expr.fromAst({
|
|
61
|
+
ast_type: "Builtin",
|
|
62
|
+
type: IntegerType,
|
|
63
|
+
location: get_location(2),
|
|
64
|
+
builtin: "SetSize",
|
|
65
|
+
type_parameters: [this.key_type],
|
|
66
|
+
arguments: [this[AstSymbol]],
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Checks if an element exists in the set.
|
|
71
|
+
*
|
|
72
|
+
* @param key - The element to search for
|
|
73
|
+
* @returns A BooleanExpr that is true if the element exists, false otherwise
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts
|
|
77
|
+
* const hasElement = East.function([SetType(StringType), StringType], BooleanType, ($, set, element) => {
|
|
78
|
+
* $.return(set.has(element));
|
|
79
|
+
* });
|
|
80
|
+
* const compiled = East.compile(hasElement.toIR(), []);
|
|
81
|
+
* const set = new Set(["a", "b", "c"]);
|
|
82
|
+
* compiled(set, "b"); // true
|
|
83
|
+
* compiled(set, "d"); // false
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
has(key) {
|
|
87
|
+
const valueAst = valueOrExprToAstTyped(key, this.key_type);
|
|
88
|
+
return Expr.fromAst({
|
|
89
|
+
ast_type: "Builtin",
|
|
90
|
+
type: BooleanType,
|
|
91
|
+
location: get_location(2),
|
|
92
|
+
builtin: "SetHas",
|
|
93
|
+
type_parameters: [this.key_type],
|
|
94
|
+
arguments: [this[AstSymbol], valueAst],
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Inserts a new element into the set.
|
|
99
|
+
*
|
|
100
|
+
* @param key - The element to insert
|
|
101
|
+
* @returns A NullExpr
|
|
102
|
+
*
|
|
103
|
+
* @throws East runtime error if the element already exists in the set
|
|
104
|
+
*
|
|
105
|
+
* @see {@link tryInsert} for a version that doesn't error on duplicates
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```ts
|
|
109
|
+
* const insertElement = East.function([SetType(StringType), StringType], NullType, ($, set, element) => {
|
|
110
|
+
* $(set.insert(element));
|
|
111
|
+
* $.return(null);
|
|
112
|
+
* });
|
|
113
|
+
* const compiled = East.compile(insertElement.toIR(), []);
|
|
114
|
+
* const set = new Set(["a", "b"]);
|
|
115
|
+
* compiled(set, "c"); // set now has Set(["a", "b", "c"])
|
|
116
|
+
* // compiled(set, "a") would throw error (duplicate element)
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
insert(key) {
|
|
120
|
+
const location = get_location(2);
|
|
121
|
+
const keyAst = valueOrExprToAstTyped(key, this.key_type);
|
|
122
|
+
return Expr.fromAst({
|
|
123
|
+
ast_type: "Builtin",
|
|
124
|
+
type: NullType,
|
|
125
|
+
location,
|
|
126
|
+
builtin: "SetInsert",
|
|
127
|
+
type_parameters: [this.key_type],
|
|
128
|
+
arguments: [this[AstSymbol], keyAst],
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Tries to insert an element into the set, returning whether it was inserted.
|
|
133
|
+
*
|
|
134
|
+
* @param key - The element to insert
|
|
135
|
+
* @returns A BooleanExpr that is true if the element was inserted, false if it already existed
|
|
136
|
+
*
|
|
137
|
+
* @see {@link insert} for a version that errors on duplicates
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```ts
|
|
141
|
+
* const tryInsertElement = East.function([SetType(StringType), StringType], BooleanType, ($, set, element) => {
|
|
142
|
+
* $.return(set.tryInsert(element));
|
|
143
|
+
* });
|
|
144
|
+
* const compiled = East.compile(tryInsertElement.toIR(), []);
|
|
145
|
+
* const set = new Set(["a", "b"]);
|
|
146
|
+
* compiled(set, "c"); // true (set now has Set(["a", "b", "c"]))
|
|
147
|
+
* compiled(set, "a"); // false (element already exists, set unchanged)
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
tryInsert(key) {
|
|
151
|
+
const keyAst = valueOrExprToAstTyped(key, this.key_type);
|
|
152
|
+
return Expr.fromAst({
|
|
153
|
+
ast_type: "Builtin",
|
|
154
|
+
type: BooleanType,
|
|
155
|
+
location: get_location(2),
|
|
156
|
+
builtin: "SetTryInsert",
|
|
157
|
+
type_parameters: [this.key_type],
|
|
158
|
+
arguments: [this[AstSymbol], keyAst],
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Deletes an element from the set.
|
|
163
|
+
*
|
|
164
|
+
* @param key - The element to delete
|
|
165
|
+
* @returns A NullExpr
|
|
166
|
+
*
|
|
167
|
+
* @throws East runtime error if the element does not exist
|
|
168
|
+
*
|
|
169
|
+
* @see {@link tryDelete} for a version that doesn't error on missing elements
|
|
170
|
+
* @see {@link clear} to remove all elements
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* ```ts
|
|
174
|
+
* const deleteElement = East.function([SetType(StringType), StringType], NullType, ($, set, element) => {
|
|
175
|
+
* $(set.delete(element));
|
|
176
|
+
* $.return(null);
|
|
177
|
+
* });
|
|
178
|
+
* const compiled = East.compile(deleteElement.toIR(), []);
|
|
179
|
+
* const set = new Set(["a", "b", "c"]);
|
|
180
|
+
* compiled(set, "b"); // set now has Set(["a", "c"])
|
|
181
|
+
* // compiled(set, "d") would throw error (element not found)
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
delete(key) {
|
|
185
|
+
const location = get_location(2);
|
|
186
|
+
const keyAst = valueOrExprToAstTyped(key, this.key_type);
|
|
187
|
+
return Expr.fromAst({
|
|
188
|
+
ast_type: "Builtin",
|
|
189
|
+
type: NullType,
|
|
190
|
+
location,
|
|
191
|
+
builtin: "SetDelete",
|
|
192
|
+
type_parameters: [this.key_type],
|
|
193
|
+
arguments: [this[AstSymbol], keyAst],
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Tries to delete an element from the set, returning whether it was deleted.
|
|
198
|
+
*
|
|
199
|
+
* @param key - The element to delete
|
|
200
|
+
* @returns A BooleanExpr that is true if the element was deleted, false if it didn't exist
|
|
201
|
+
*
|
|
202
|
+
* @see {@link delete} for a version that errors on missing elements
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* ```ts
|
|
206
|
+
* const tryDeleteElement = East.function([SetType(StringType), StringType], BooleanType, ($, set, element) => {
|
|
207
|
+
* $.return(set.tryDelete(element));
|
|
208
|
+
* });
|
|
209
|
+
* const compiled = East.compile(tryDeleteElement.toIR(), []);
|
|
210
|
+
* const set = new Set(["a", "b", "c"]);
|
|
211
|
+
* compiled(set, "b"); // true (set now has Set(["a", "c"]))
|
|
212
|
+
* compiled(set, "d"); // false (element not found, set unchanged)
|
|
213
|
+
* ```
|
|
214
|
+
*/
|
|
215
|
+
tryDelete(key) {
|
|
216
|
+
const keyAst = valueOrExprToAstTyped(key, this.key_type);
|
|
217
|
+
return Expr.fromAst({
|
|
218
|
+
ast_type: "Builtin",
|
|
219
|
+
type: BooleanType,
|
|
220
|
+
location: get_location(2),
|
|
221
|
+
builtin: "SetTryDelete",
|
|
222
|
+
type_parameters: [this.key_type],
|
|
223
|
+
arguments: [this[AstSymbol], keyAst],
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Removes all elements from the set.
|
|
228
|
+
*
|
|
229
|
+
* @returns A NullExpr
|
|
230
|
+
*
|
|
231
|
+
* @see {@link delete} or {@link tryDelete} to remove individual elements
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* ```ts
|
|
235
|
+
* const clearSet = East.function([SetType(StringType)], NullType, ($, set) => {
|
|
236
|
+
* $(set.clear());
|
|
237
|
+
* $.return(null);
|
|
238
|
+
* });
|
|
239
|
+
* const compiled = East.compile(clearSet.toIR(), []);
|
|
240
|
+
* const set = new Set(["a", "b", "c"]);
|
|
241
|
+
* compiled(set); // set is now Set([])
|
|
242
|
+
* ```
|
|
243
|
+
*/
|
|
244
|
+
clear() {
|
|
245
|
+
return Expr.fromAst({
|
|
246
|
+
ast_type: "Builtin",
|
|
247
|
+
type: NullType,
|
|
248
|
+
location: get_location(2),
|
|
249
|
+
builtin: "SetClear",
|
|
250
|
+
type_parameters: [this.key_type],
|
|
251
|
+
arguments: [this[AstSymbol]],
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Unions another set into this one in place.
|
|
256
|
+
*
|
|
257
|
+
* @param other - The set whose elements to add to this set
|
|
258
|
+
* @returns A NullExpr
|
|
259
|
+
*
|
|
260
|
+
* @see {@link union} for a version that returns a new set
|
|
261
|
+
*
|
|
262
|
+
* @example
|
|
263
|
+
* ```ts
|
|
264
|
+
* const unionInPlace = East.function([SetType(IntegerType), SetType(IntegerType)], NullType, ($, set1, set2) => {
|
|
265
|
+
* $(set1.unionInPlace(set2));
|
|
266
|
+
* $.return(null);
|
|
267
|
+
* });
|
|
268
|
+
* const compiled = East.compile(unionInPlace.toIR(), []);
|
|
269
|
+
* const set1 = new Set([1n, 2n, 3n]);
|
|
270
|
+
* const set2 = new Set([3n, 4n, 5n]);
|
|
271
|
+
* compiled(set1, set2); // set1 now has Set([1n, 2n, 3n, 4n, 5n])
|
|
272
|
+
* ```
|
|
273
|
+
*/
|
|
274
|
+
unionInPlace(other) {
|
|
275
|
+
const otherAst = valueOrExprToAstTyped(other, this[TypeSymbol]);
|
|
276
|
+
return Expr.fromAst({
|
|
277
|
+
ast_type: "Builtin",
|
|
278
|
+
type: NullType,
|
|
279
|
+
location: get_location(2),
|
|
280
|
+
builtin: "SetUnionInPlace",
|
|
281
|
+
type_parameters: [this.key_type],
|
|
282
|
+
arguments: [this[AstSymbol], otherAst],
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Returns the union of two sets (all elements from both sets).
|
|
287
|
+
*
|
|
288
|
+
* @param other - The set to union with this set
|
|
289
|
+
* @returns A new SetExpr containing all elements from both sets
|
|
290
|
+
*
|
|
291
|
+
* @see {@link unionInPlace} to modify this set in place
|
|
292
|
+
*
|
|
293
|
+
* @example
|
|
294
|
+
* ```ts
|
|
295
|
+
* const unionSets = East.function([SetType(IntegerType), SetType(IntegerType)], SetType(IntegerType), ($, set1, set2) => {
|
|
296
|
+
* $.return(set1.union(set2));
|
|
297
|
+
* });
|
|
298
|
+
* const compiled = East.compile(unionSets.toIR(), []);
|
|
299
|
+
* compiled(new Set([1n, 2n, 3n]), new Set([3n, 4n, 5n])); // Set([1n, 2n, 3n, 4n, 5n])
|
|
300
|
+
* ```
|
|
301
|
+
*/
|
|
302
|
+
union(other) {
|
|
303
|
+
const otherAst = valueOrExprToAstTyped(other, this[TypeSymbol]);
|
|
304
|
+
return Expr.fromAst({
|
|
305
|
+
ast_type: "Builtin",
|
|
306
|
+
type: this[TypeSymbol],
|
|
307
|
+
location: get_location(2),
|
|
308
|
+
builtin: "SetUnion",
|
|
309
|
+
type_parameters: [this.key_type],
|
|
310
|
+
arguments: [this[AstSymbol], otherAst],
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Returns the intersection of two sets (elements common to both).
|
|
315
|
+
*
|
|
316
|
+
* @param other - The set to intersect with this set
|
|
317
|
+
* @returns A new SetExpr containing only elements present in both sets
|
|
318
|
+
*
|
|
319
|
+
* @example
|
|
320
|
+
* ```ts
|
|
321
|
+
* const intersectSets = East.function([SetType(IntegerType), SetType(IntegerType)], SetType(IntegerType), ($, set1, set2) => {
|
|
322
|
+
* $.return(set1.intersection(set2));
|
|
323
|
+
* });
|
|
324
|
+
* const compiled = East.compile(intersectSets.toIR(), []);
|
|
325
|
+
* compiled(new Set([1n, 2n, 3n]), new Set([2n, 3n, 4n])); // Set([2n, 3n])
|
|
326
|
+
* ```
|
|
327
|
+
*/
|
|
328
|
+
intersection(other) {
|
|
329
|
+
const otherAst = valueOrExprToAstTyped(other, this[TypeSymbol]);
|
|
330
|
+
return Expr.fromAst({
|
|
331
|
+
ast_type: "Builtin",
|
|
332
|
+
type: this[TypeSymbol],
|
|
333
|
+
location: get_location(2),
|
|
334
|
+
builtin: "SetIntersect",
|
|
335
|
+
type_parameters: [this.key_type],
|
|
336
|
+
arguments: [this[AstSymbol], otherAst],
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Returns the difference between two sets (elements in this set but not in the other).
|
|
341
|
+
*
|
|
342
|
+
* @param other - The set to subtract from this set
|
|
343
|
+
* @returns A new SetExpr containing elements in this set but not in the other
|
|
344
|
+
*
|
|
345
|
+
* @example
|
|
346
|
+
* ```ts
|
|
347
|
+
* const diffSets = East.function([SetType(IntegerType), SetType(IntegerType)], SetType(IntegerType), ($, set1, set2) => {
|
|
348
|
+
* $.return(set1.difference(set2));
|
|
349
|
+
* });
|
|
350
|
+
* const compiled = East.compile(diffSets.toIR(), []);
|
|
351
|
+
* compiled(new Set([1n, 2n, 3n]), new Set([2n, 3n, 4n])); // Set([1n])
|
|
352
|
+
* ```
|
|
353
|
+
*/
|
|
354
|
+
difference(other) {
|
|
355
|
+
const otherAst = valueOrExprToAstTyped(other, this[TypeSymbol]);
|
|
356
|
+
return Expr.fromAst({
|
|
357
|
+
ast_type: "Builtin",
|
|
358
|
+
type: this[TypeSymbol],
|
|
359
|
+
location: get_location(2),
|
|
360
|
+
builtin: "SetDiff",
|
|
361
|
+
type_parameters: [this.key_type],
|
|
362
|
+
arguments: [this[AstSymbol], otherAst],
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Returns the symmetric difference between two sets (elements in either set but not in both).
|
|
367
|
+
*
|
|
368
|
+
* @param other - The set to compute symmetric difference with
|
|
369
|
+
* @returns A new SetExpr containing elements in either set but not in both
|
|
370
|
+
*
|
|
371
|
+
* @example
|
|
372
|
+
* ```ts
|
|
373
|
+
* const symDiffSets = East.function([SetType(IntegerType), SetType(IntegerType)], SetType(IntegerType), ($, set1, set2) => {
|
|
374
|
+
* $.return(set1.symmetricDifference(set2));
|
|
375
|
+
* });
|
|
376
|
+
* const compiled = East.compile(symDiffSets.toIR(), []);
|
|
377
|
+
* compiled(new Set([1n, 2n, 3n]), new Set([2n, 3n, 4n])); // Set([1n, 4n])
|
|
378
|
+
* ```
|
|
379
|
+
*/
|
|
380
|
+
symmetricDifference(other) {
|
|
381
|
+
const otherAst = valueOrExprToAstTyped(other, this[TypeSymbol]);
|
|
382
|
+
return Expr.fromAst({
|
|
383
|
+
ast_type: "Builtin",
|
|
384
|
+
type: this[TypeSymbol],
|
|
385
|
+
location: get_location(2),
|
|
386
|
+
builtin: "SetSymDiff",
|
|
387
|
+
type_parameters: [this.key_type],
|
|
388
|
+
arguments: [this[AstSymbol], otherAst],
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Checks if this set is a subset of another set (all elements in this set are in the other).
|
|
393
|
+
*
|
|
394
|
+
* @param other - The set to check against
|
|
395
|
+
* @returns A BooleanExpr that is true if this set is a subset of the other
|
|
396
|
+
*
|
|
397
|
+
* @example
|
|
398
|
+
* ```ts
|
|
399
|
+
* const checkSubset = East.function([SetType(IntegerType), SetType(IntegerType)], BooleanType, ($, set1, set2) => {
|
|
400
|
+
* $.return(set1.isSubsetOf(set2));
|
|
401
|
+
* });
|
|
402
|
+
* const compiled = East.compile(checkSubset.toIR(), []);
|
|
403
|
+
* compiled(new Set([1n, 2n]), new Set([1n, 2n, 3n])); // true
|
|
404
|
+
* compiled(new Set([1n, 4n]), new Set([1n, 2n, 3n])); // false
|
|
405
|
+
* ```
|
|
406
|
+
*/
|
|
407
|
+
isSubsetOf(other) {
|
|
408
|
+
const otherAst = valueOrExprToAstTyped(other, this[TypeSymbol]);
|
|
409
|
+
return Expr.fromAst({
|
|
410
|
+
ast_type: "Builtin",
|
|
411
|
+
type: BooleanType,
|
|
412
|
+
location: get_location(2),
|
|
413
|
+
builtin: "SetIsSubset",
|
|
414
|
+
type_parameters: [this.key_type],
|
|
415
|
+
arguments: [this[AstSymbol], otherAst],
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Checks if this set is a superset of another set (all elements in the other set are in this set).
|
|
420
|
+
*
|
|
421
|
+
* @param other - The set to check against
|
|
422
|
+
* @returns A BooleanExpr that is true if this set is a superset of the other
|
|
423
|
+
*
|
|
424
|
+
* @example
|
|
425
|
+
* ```ts
|
|
426
|
+
* const checkSuperset = East.function([SetType(IntegerType), SetType(IntegerType)], BooleanType, ($, set1, set2) => {
|
|
427
|
+
* $.return(set1.isSupersetOf(set2));
|
|
428
|
+
* });
|
|
429
|
+
* const compiled = East.compile(checkSuperset.toIR(), []);
|
|
430
|
+
* compiled(new Set([1n, 2n, 3n]), new Set([1n, 2n])); // true
|
|
431
|
+
* compiled(new Set([1n, 2n]), new Set([1n, 2n, 3n])); // false
|
|
432
|
+
* ```
|
|
433
|
+
*/
|
|
434
|
+
isSupersetOf(other) {
|
|
435
|
+
const otherAst = valueOrExprToAstTyped(other, this[TypeSymbol]);
|
|
436
|
+
return Expr.fromAst({
|
|
437
|
+
ast_type: "Builtin",
|
|
438
|
+
type: BooleanType,
|
|
439
|
+
location: get_location(2),
|
|
440
|
+
builtin: "SetIsSubset",
|
|
441
|
+
type_parameters: [this.key_type],
|
|
442
|
+
arguments: [otherAst, this[AstSymbol]], // Note: arguments swapped for superset
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Checks if this set is disjoint from another set (no common elements).
|
|
447
|
+
*
|
|
448
|
+
* @param other - The set to check against
|
|
449
|
+
* @returns A BooleanExpr that is true if the sets have no elements in common
|
|
450
|
+
*
|
|
451
|
+
* @example
|
|
452
|
+
* ```ts
|
|
453
|
+
* const checkDisjoint = East.function([SetType(IntegerType), SetType(IntegerType)], BooleanType, ($, set1, set2) => {
|
|
454
|
+
* $.return(set1.isDisjointFrom(set2));
|
|
455
|
+
* });
|
|
456
|
+
* const compiled = East.compile(checkDisjoint.toIR(), []);
|
|
457
|
+
* compiled(new Set([1n, 2n]), new Set([3n, 4n])); // true
|
|
458
|
+
* compiled(new Set([1n, 2n]), new Set([2n, 3n])); // false
|
|
459
|
+
* ```
|
|
460
|
+
*/
|
|
461
|
+
isDisjointFrom(other) {
|
|
462
|
+
const otherAst = valueOrExprToAstTyped(other, this[TypeSymbol]);
|
|
463
|
+
return Expr.fromAst({
|
|
464
|
+
ast_type: "Builtin",
|
|
465
|
+
type: BooleanType,
|
|
466
|
+
location: get_location(2),
|
|
467
|
+
builtin: "SetIsDisjoint",
|
|
468
|
+
type_parameters: [this.key_type],
|
|
469
|
+
arguments: [this[AstSymbol], otherAst],
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Creates a shallow copy of the set.
|
|
474
|
+
*
|
|
475
|
+
* @returns A new SetExpr containing the same elements
|
|
476
|
+
*
|
|
477
|
+
* @example
|
|
478
|
+
* ```ts
|
|
479
|
+
* const copySet = East.function([SetType(StringType)], SetType(StringType), ($, set) => {
|
|
480
|
+
* $.return(set.copy());
|
|
481
|
+
* });
|
|
482
|
+
* const compiled = East.compile(copySet.toIR(), []);
|
|
483
|
+
* const set = new Set(["a", "b", "c"]);
|
|
484
|
+
* const copy = compiled(set); // Set(["a", "b", "c"])
|
|
485
|
+
* // Modifying copy doesn't affect set
|
|
486
|
+
* ```
|
|
487
|
+
*/
|
|
488
|
+
copy() {
|
|
489
|
+
// Note that keys are immutable so shallow and deep copy are the same
|
|
490
|
+
return Expr.fromAst({
|
|
491
|
+
ast_type: "Builtin",
|
|
492
|
+
type: this[TypeSymbol],
|
|
493
|
+
location: get_location(2),
|
|
494
|
+
builtin: "SetCopy",
|
|
495
|
+
type_parameters: [this.key_type],
|
|
496
|
+
arguments: [this[AstSymbol]],
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Filters the set using a predicate function.
|
|
501
|
+
*
|
|
502
|
+
* @param pred - Function that returns true to keep an element, false to discard it
|
|
503
|
+
* @returns A new SetExpr containing only elements for which the predicate returned true
|
|
504
|
+
*
|
|
505
|
+
* @example
|
|
506
|
+
* ```ts
|
|
507
|
+
* const filterEven = East.function([SetType(IntegerType)], SetType(IntegerType), ($, set) => {
|
|
508
|
+
* $.return(set.filter(($, x) => x.modulo(2n).equal(0n)));
|
|
509
|
+
* });
|
|
510
|
+
* const compiled = East.compile(filterEven.toIR(), []);
|
|
511
|
+
* compiled(new Set([1n, 2n, 3n, 4n, 5n, 6n])); // Set([2n, 4n, 6n])
|
|
512
|
+
* ```
|
|
513
|
+
*/
|
|
514
|
+
filter(pred) {
|
|
515
|
+
const predExpr = Expr.from(pred, FunctionType([this.key_type], BooleanType, null));
|
|
516
|
+
return Expr.fromAst({
|
|
517
|
+
ast_type: "Builtin",
|
|
518
|
+
type: this[TypeSymbol],
|
|
519
|
+
location: get_location(2),
|
|
520
|
+
builtin: "SetFilter",
|
|
521
|
+
type_parameters: [this.key_type],
|
|
522
|
+
arguments: [this[AstSymbol], Expr.ast(predExpr)],
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
filterMap(fn) {
|
|
526
|
+
let fnExpr;
|
|
527
|
+
if (typeof fn === "function") {
|
|
528
|
+
fnExpr = Expr.function([this.key_type], undefined, fn);
|
|
529
|
+
}
|
|
530
|
+
else {
|
|
531
|
+
fnExpr = fn;
|
|
532
|
+
}
|
|
533
|
+
const fnType = fnExpr[TypeSymbol];
|
|
534
|
+
const returnType = fnType.output;
|
|
535
|
+
// Extract V2 from the option type
|
|
536
|
+
if (returnType.type !== "Variant" || !("some" in returnType.cases)) {
|
|
537
|
+
throw new Error(`filterMap function must return an option type (variant with 'none' and 'some'), got ${printType(returnType)}`);
|
|
538
|
+
}
|
|
539
|
+
const valueType = returnType.cases.some;
|
|
540
|
+
return Expr.fromAst({
|
|
541
|
+
ast_type: "Builtin",
|
|
542
|
+
type: DictType(this.key_type, valueType),
|
|
543
|
+
location: get_location(2),
|
|
544
|
+
builtin: "SetFilterMap",
|
|
545
|
+
type_parameters: [this.key_type, valueType],
|
|
546
|
+
arguments: [this[AstSymbol], Expr.ast(fnExpr)],
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
firstMap(fn) {
|
|
550
|
+
const fnAst = valueOrExprToAstTyped(fn, FunctionType([this.key_type], undefined, null));
|
|
551
|
+
const returnType = fnAst.type.output;
|
|
552
|
+
if (returnType.type !== "Variant") {
|
|
553
|
+
throw new Error(`Expected Function to return an Option type, got ${printType(returnType)}`);
|
|
554
|
+
}
|
|
555
|
+
if (!Object.keys(returnType.cases).every(k => k === "none" || k === "some")) {
|
|
556
|
+
throw new Error(`Expected Function to return an Option type, got ${printType(returnType)}`);
|
|
557
|
+
}
|
|
558
|
+
const someType = returnType.cases["some"] ?? NeverType;
|
|
559
|
+
return Expr.fromAst({
|
|
560
|
+
ast_type: "Builtin",
|
|
561
|
+
type: returnType,
|
|
562
|
+
location: get_location(2),
|
|
563
|
+
builtin: "SetFirstMap",
|
|
564
|
+
type_parameters: [this.key_type, someType],
|
|
565
|
+
arguments: [this[AstSymbol], fnAst],
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* Iterates over each element in the set, applying a function to each.
|
|
570
|
+
*
|
|
571
|
+
* @param fn - Function to apply to each element
|
|
572
|
+
* @returns A NullExpr
|
|
573
|
+
*
|
|
574
|
+
* @example
|
|
575
|
+
* ```ts
|
|
576
|
+
* const printElements = East.function([SetType(StringType)], NullType, ($, set) => {
|
|
577
|
+
* $(set.forEach(($, element) => {
|
|
578
|
+
* // In a real platform, you could use a platform function to log
|
|
579
|
+
* }));
|
|
580
|
+
* $.return(null);
|
|
581
|
+
* });
|
|
582
|
+
* const compiled = East.compile(printElements.toIR(), []);
|
|
583
|
+
* compiled(new Set(["a", "b", "c"])); // Iterates over all elements
|
|
584
|
+
* ```
|
|
585
|
+
*/
|
|
586
|
+
forEach(fn) {
|
|
587
|
+
const fnExpr = Expr.function([this.key_type], undefined, fn);
|
|
588
|
+
const fnType = fnExpr[TypeSymbol];
|
|
589
|
+
const returnType = fnType.output;
|
|
590
|
+
return Expr.fromAst({
|
|
591
|
+
ast_type: "Builtin",
|
|
592
|
+
type: NullType,
|
|
593
|
+
location: get_location(2),
|
|
594
|
+
builtin: "SetForEach",
|
|
595
|
+
type_parameters: [this.key_type, returnType],
|
|
596
|
+
arguments: [this[AstSymbol], Expr.ast(fnExpr)],
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
map(fn) {
|
|
600
|
+
let fnExpr;
|
|
601
|
+
if (typeof fn === "function") {
|
|
602
|
+
fnExpr = Expr.function([this.key_type], undefined, fn);
|
|
603
|
+
}
|
|
604
|
+
else {
|
|
605
|
+
fnExpr = fn;
|
|
606
|
+
}
|
|
607
|
+
const fnType = fnExpr[TypeSymbol];
|
|
608
|
+
const returnType = fnType.output;
|
|
609
|
+
return Expr.fromAst({
|
|
610
|
+
ast_type: "Builtin",
|
|
611
|
+
type: DictType(this.key_type, returnType),
|
|
612
|
+
location: get_location(2),
|
|
613
|
+
builtin: "SetMap",
|
|
614
|
+
type_parameters: [this.key_type, returnType],
|
|
615
|
+
arguments: [this[AstSymbol], Expr.ast(fnExpr)],
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
mapReduce(mapFn, combineFn) {
|
|
619
|
+
const mapAst = valueOrExprToAstTyped(mapFn, FunctionType([this.key_type], undefined, null));
|
|
620
|
+
const mapType = mapAst.type.output;
|
|
621
|
+
const combineAst = valueOrExprToAstTyped(combineFn, FunctionType([mapType, mapType], mapType, null));
|
|
622
|
+
return Expr.fromAst({
|
|
623
|
+
ast_type: "Builtin",
|
|
624
|
+
type: mapType,
|
|
625
|
+
location: get_location(2),
|
|
626
|
+
builtin: "SetMapReduce",
|
|
627
|
+
type_parameters: [this.key_type, mapType],
|
|
628
|
+
arguments: [this[AstSymbol], mapAst, combineAst],
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* Reduces the set to a single value using an accumulator function.
|
|
633
|
+
*
|
|
634
|
+
* @param fn - Function accepting (accumulator, element) and returning the new accumulator value
|
|
635
|
+
* @param init - Initial value for the accumulator
|
|
636
|
+
* @returns The final accumulated value
|
|
637
|
+
*
|
|
638
|
+
* @see {@link mapReduce} for a version that projects elements before combining
|
|
639
|
+
*
|
|
640
|
+
* @example
|
|
641
|
+
* ```ts
|
|
642
|
+
* const sumSet = East.function([SetType(IntegerType)], IntegerType, ($, set) => {
|
|
643
|
+
* $.return(set.reduce(($, acc, element) => acc.add(element), 0n));
|
|
644
|
+
* });
|
|
645
|
+
* const compiled = East.compile(sumSet.toIR(), []);
|
|
646
|
+
* compiled(new Set([1n, 2n, 3n, 4n])); // 10n
|
|
647
|
+
* ```
|
|
648
|
+
*/
|
|
649
|
+
reduce(fn, init) {
|
|
650
|
+
const initAst = valueOrExprToAst(init);
|
|
651
|
+
const returnType = initAst.type;
|
|
652
|
+
const fnExpr = Expr.from(fn, FunctionType([returnType, this.key_type], returnType, null));
|
|
653
|
+
return Expr.fromAst({
|
|
654
|
+
ast_type: "Builtin",
|
|
655
|
+
type: returnType,
|
|
656
|
+
location: get_location(2),
|
|
657
|
+
builtin: "SetReduce",
|
|
658
|
+
type_parameters: [this.key_type, returnType],
|
|
659
|
+
arguments: [this[AstSymbol], Expr.ast(fnExpr), initAst],
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
toArray(fn) {
|
|
663
|
+
let fnExpr;
|
|
664
|
+
if (fn === undefined) {
|
|
665
|
+
// Identity function
|
|
666
|
+
fnExpr = Expr.function([this.key_type], this.key_type, ($, key) => key);
|
|
667
|
+
}
|
|
668
|
+
else if (typeof fn === "function") {
|
|
669
|
+
fnExpr = Expr.function([this.key_type], undefined, fn);
|
|
670
|
+
}
|
|
671
|
+
else {
|
|
672
|
+
fnExpr = fn;
|
|
673
|
+
}
|
|
674
|
+
const fnType = fnExpr[TypeSymbol];
|
|
675
|
+
const returnType = fnType.output;
|
|
676
|
+
return Expr.fromAst({
|
|
677
|
+
ast_type: "Builtin",
|
|
678
|
+
type: ArrayType(returnType),
|
|
679
|
+
location: get_location(2),
|
|
680
|
+
builtin: "SetToArray",
|
|
681
|
+
type_parameters: [this.key_type, returnType],
|
|
682
|
+
arguments: [this[AstSymbol], Expr.ast(fnExpr)],
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
toSet(keyFn) {
|
|
686
|
+
let keyFnAst;
|
|
687
|
+
if (keyFn !== undefined) {
|
|
688
|
+
let fnExpr;
|
|
689
|
+
if (typeof keyFn === "function") {
|
|
690
|
+
fnExpr = Expr.function([this.key_type], undefined, keyFn);
|
|
691
|
+
}
|
|
692
|
+
else {
|
|
693
|
+
fnExpr = keyFn;
|
|
694
|
+
}
|
|
695
|
+
keyFnAst = Expr.ast(fnExpr);
|
|
696
|
+
}
|
|
697
|
+
else {
|
|
698
|
+
// Identity function
|
|
699
|
+
const identityFunction = Expr.function([this.key_type], this.key_type, ($, key) => key);
|
|
700
|
+
keyFnAst = Expr.ast(identityFunction);
|
|
701
|
+
}
|
|
702
|
+
const keyType = keyFnAst.type.output;
|
|
703
|
+
return Expr.fromAst({
|
|
704
|
+
ast_type: "Builtin",
|
|
705
|
+
type: SetType(keyType),
|
|
706
|
+
location: get_location(2),
|
|
707
|
+
builtin: "SetToSet",
|
|
708
|
+
type_parameters: [this.key_type, this.key_type],
|
|
709
|
+
arguments: [this[AstSymbol], keyFnAst],
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
toDict(keyFn, valueFn, onConflictFn) {
|
|
713
|
+
const keyFnAst = valueOrExprToAstTyped(keyFn ?? ((_$, x, i) => i), FunctionType([this.key_type], undefined, null));
|
|
714
|
+
const keyType = keyFnAst.type.output;
|
|
715
|
+
const valueFnAst = valueOrExprToAstTyped(valueFn ?? ((_$, x) => x), FunctionType([this.key_type], undefined, null));
|
|
716
|
+
const valueType = valueFnAst.type.output;
|
|
717
|
+
let onConflictAst;
|
|
718
|
+
if (onConflictFn === undefined) {
|
|
719
|
+
const location = get_location(2);
|
|
720
|
+
const onConflictFunction = Expr.function([valueType, valueType, keyType], valueType, ($, existing, value, key) => $.error(Expr.str `Cannot insert duplicate key ${key} into dict`, location));
|
|
721
|
+
onConflictAst = Expr.ast(onConflictFunction);
|
|
722
|
+
}
|
|
723
|
+
else {
|
|
724
|
+
onConflictAst = valueOrExprToAstTyped(onConflictFn, FunctionType([valueType, valueType, keyType], valueType, null));
|
|
725
|
+
}
|
|
726
|
+
return Expr.fromAst({
|
|
727
|
+
ast_type: "Builtin",
|
|
728
|
+
type: DictType(keyType, valueType),
|
|
729
|
+
location: get_location(2),
|
|
730
|
+
builtin: "SetToDict",
|
|
731
|
+
type_parameters: [this.key_type, keyType, valueType],
|
|
732
|
+
arguments: [this[AstSymbol], keyFnAst, valueFnAst, onConflictAst],
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
flattenToArray(fn) {
|
|
736
|
+
const fnAst = valueOrExprToAstTyped(fn, FunctionType([this.key_type], undefined, null));
|
|
737
|
+
const returnType = fnAst.type.output;
|
|
738
|
+
if (returnType.type !== "Array") {
|
|
739
|
+
throw new Error(`Expected Function to return an Array type, got ${printType(returnType)}`);
|
|
740
|
+
}
|
|
741
|
+
const elementType = returnType.value;
|
|
742
|
+
return Expr.fromAst({
|
|
743
|
+
ast_type: "Builtin",
|
|
744
|
+
type: ArrayType(elementType),
|
|
745
|
+
location: get_location(2),
|
|
746
|
+
builtin: "SetFlattenToArray",
|
|
747
|
+
type_parameters: [this.key_type, elementType],
|
|
748
|
+
arguments: [this[AstSymbol], fnAst],
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
flattenToSet(fn) {
|
|
752
|
+
const fnAst = valueOrExprToAstTyped(fn, FunctionType([this.key_type], undefined, null));
|
|
753
|
+
const returnType = fnAst.type.output;
|
|
754
|
+
if (returnType.type !== "Set") {
|
|
755
|
+
throw new Error(`Expected Function to return a Set type, got ${printType(returnType)}`);
|
|
756
|
+
}
|
|
757
|
+
const elementType = returnType.key;
|
|
758
|
+
return Expr.fromAst({
|
|
759
|
+
ast_type: "Builtin",
|
|
760
|
+
type: SetType(elementType),
|
|
761
|
+
location: get_location(2),
|
|
762
|
+
builtin: "SetFlattenToSet",
|
|
763
|
+
type_parameters: [this.key_type, elementType],
|
|
764
|
+
arguments: [this[AstSymbol], fnAst],
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
flattenToDict(fn, onConflictFn) {
|
|
768
|
+
const fnAst = valueOrExprToAstTyped(fn, FunctionType([this.key_type], undefined, null));
|
|
769
|
+
const returnType = fnAst.type.output;
|
|
770
|
+
if (returnType.type !== "Dict") {
|
|
771
|
+
throw new Error(`Expected Function to return a Dict type, got ${printType(returnType)}`);
|
|
772
|
+
}
|
|
773
|
+
const keyType = returnType.key;
|
|
774
|
+
const valueType = returnType.value;
|
|
775
|
+
let onConflictAst;
|
|
776
|
+
if (onConflictFn === undefined) {
|
|
777
|
+
const location = get_location(2);
|
|
778
|
+
const onConflictFunction = Expr.function([valueType, valueType, keyType], valueType, ($, existing, value, key) => $.error(Expr.str `Cannot insert duplicate key ${key} into dict`, location));
|
|
779
|
+
onConflictAst = Expr.ast(onConflictFunction);
|
|
780
|
+
}
|
|
781
|
+
else {
|
|
782
|
+
onConflictAst = valueOrExprToAstTyped(onConflictFn, FunctionType([valueType, valueType, keyType], valueType, null));
|
|
783
|
+
}
|
|
784
|
+
return Expr.fromAst({
|
|
785
|
+
ast_type: "Builtin",
|
|
786
|
+
type: DictType(keyType, valueType),
|
|
787
|
+
location: get_location(2),
|
|
788
|
+
builtin: "SetFlattenToDict",
|
|
789
|
+
type_parameters: [this.key_type, keyType, valueType],
|
|
790
|
+
arguments: [this[AstSymbol], fnAst, onConflictAst],
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
groupReduce(keyFn, initFn, reduceFn) {
|
|
794
|
+
const keyFnAst = valueOrExprToAstTyped(keyFn, FunctionType([this.key_type], undefined, null));
|
|
795
|
+
const keyType = keyFnAst.type.output;
|
|
796
|
+
const initFnAst = valueOrExprToAstTyped(initFn, FunctionType([keyType], undefined, null));
|
|
797
|
+
const initType = initFnAst.type.output;
|
|
798
|
+
const reduceFnAst = valueOrExprToAstTyped(reduceFn, FunctionType([initType, this.key_type], initType, null));
|
|
799
|
+
return Expr.fromAst({
|
|
800
|
+
ast_type: "Builtin",
|
|
801
|
+
type: DictType(keyType, initType),
|
|
802
|
+
location: get_location(2),
|
|
803
|
+
builtin: "SetGroupFold",
|
|
804
|
+
type_parameters: [this.key_type, keyType, initType],
|
|
805
|
+
arguments: [this[AstSymbol], keyFnAst, initFnAst, reduceFnAst],
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
groupToArrays(keyFn, valueFn) {
|
|
809
|
+
const keyFnAst = valueOrExprToAstTyped(keyFn, FunctionType([this.key_type], undefined, null));
|
|
810
|
+
const valueFnAst = valueOrExprToAstTyped(valueFn ?? ((_$, x) => x), FunctionType([this.key_type], undefined, null));
|
|
811
|
+
const keyFnExpr = Expr.fromAst(keyFnAst);
|
|
812
|
+
const valueFnExpr = Expr.fromAst(valueFnAst);
|
|
813
|
+
const valueType = valueFnAst.type.output;
|
|
814
|
+
return this.groupReduce(((_$, key) => keyFnExpr(key)), ((_$, _groupKey) => Expr.from([], ArrayType(valueType))), (($, acc, key) => {
|
|
815
|
+
const val = valueFnExpr(key);
|
|
816
|
+
$(acc.pushLast(val));
|
|
817
|
+
return acc;
|
|
818
|
+
}));
|
|
819
|
+
}
|
|
820
|
+
groupToSets(keyFn, valueFn) {
|
|
821
|
+
const keyFnAst = valueOrExprToAstTyped(keyFn, FunctionType([this.key_type], undefined, null));
|
|
822
|
+
const valueFnAst = valueOrExprToAstTyped(valueFn ?? ((_$, x) => x), FunctionType([this.key_type], undefined, null));
|
|
823
|
+
const keyFnExpr = Expr.fromAst(keyFnAst);
|
|
824
|
+
const valueFnExpr = Expr.fromAst(valueFnAst);
|
|
825
|
+
const valueType = valueFnAst.type.output;
|
|
826
|
+
return this.groupReduce(((_$, key) => keyFnExpr(key)), ((_$, _groupKey) => Expr.from(new Set(), SetType(valueType))), (($, acc, key) => {
|
|
827
|
+
const val = valueFnExpr(key);
|
|
828
|
+
$(acc.tryInsert(val));
|
|
829
|
+
return acc;
|
|
830
|
+
}));
|
|
831
|
+
}
|
|
832
|
+
groupToDicts(keyFn, keyFn2, valueFn, combineFn) {
|
|
833
|
+
const keyFnAst = valueOrExprToAstTyped(keyFn, FunctionType([this.key_type], undefined, null));
|
|
834
|
+
const keyFn2Ast = valueOrExprToAstTyped(keyFn2, FunctionType([this.key_type], undefined, null));
|
|
835
|
+
const valueFnAst = valueOrExprToAstTyped(valueFn ?? ((_$, x) => x), FunctionType([this.key_type], undefined, null));
|
|
836
|
+
const keyFnExpr = Expr.fromAst(keyFnAst);
|
|
837
|
+
const keyFn2Expr = Expr.fromAst(keyFn2Ast);
|
|
838
|
+
const valueFnExpr = Expr.fromAst(valueFnAst);
|
|
839
|
+
const key2Type = keyFn2Ast.type.output;
|
|
840
|
+
const valueType = valueFnAst.type.output;
|
|
841
|
+
if (combineFn !== undefined) {
|
|
842
|
+
// With conflict resolution - use tryGet + match to check existence, then insert or combine
|
|
843
|
+
const combineFnAst = valueOrExprToAstTyped(combineFn, FunctionType([valueType, valueType], valueType, null));
|
|
844
|
+
const combineFnExpr = Expr.fromAst(combineFnAst);
|
|
845
|
+
return this.groupReduce(((_$, key) => keyFnExpr(key)), ((_$, _key) => Expr.from(new Map(), DictType(key2Type, valueType))), (($, dict, key) => {
|
|
846
|
+
const innerKey = keyFn2Expr(key);
|
|
847
|
+
const val = valueFnExpr(key);
|
|
848
|
+
$.match(dict.tryGet(innerKey), {
|
|
849
|
+
some: ($, existing) => {
|
|
850
|
+
const combined = combineFnExpr(existing, val);
|
|
851
|
+
$(dict.update(innerKey, combined));
|
|
852
|
+
},
|
|
853
|
+
none: ($) => {
|
|
854
|
+
$(dict.insert(innerKey, val));
|
|
855
|
+
}
|
|
856
|
+
});
|
|
857
|
+
return dict;
|
|
858
|
+
}));
|
|
859
|
+
}
|
|
860
|
+
else {
|
|
861
|
+
// Without conflict resolution - use insert (errors on duplicate)
|
|
862
|
+
return this.groupReduce(((_$, key) => keyFnExpr(key)), ((_$, _key) => Expr.from(new Map(), DictType(key2Type, valueType))), (($, dict, key) => {
|
|
863
|
+
const innerKey = keyFn2Expr(key);
|
|
864
|
+
const val = valueFnExpr(key);
|
|
865
|
+
$(dict.insert(innerKey, val));
|
|
866
|
+
return dict;
|
|
867
|
+
}));
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
groupSize(keyFn) {
|
|
871
|
+
const keyFnAst = valueOrExprToAstTyped(keyFn ?? ((_$, x) => x), FunctionType([this.key_type], undefined, null));
|
|
872
|
+
return this.toDict(((_$, key) => Expr.fromAst(keyFnAst)(key)), ((_$) => 1n), ((_$, a, b) => a.add(b)));
|
|
873
|
+
}
|
|
874
|
+
groupEvery(keyFn, predFn) {
|
|
875
|
+
const keyFnAst = valueOrExprToAstTyped(keyFn, FunctionType([this.key_type], undefined, null));
|
|
876
|
+
const predFnAst = valueOrExprToAstTyped(predFn, FunctionType([this.key_type], BooleanType, null));
|
|
877
|
+
return this.groupReduce(((_$, key) => Expr.fromAst(keyFnAst)(key)), (() => true), ((_$, acc, key) => {
|
|
878
|
+
const pred = Expr.fromAst(predFnAst)(key);
|
|
879
|
+
return acc.and(() => pred);
|
|
880
|
+
}));
|
|
881
|
+
}
|
|
882
|
+
groupSome(keyFn, predFn) {
|
|
883
|
+
const keyFnAst = valueOrExprToAstTyped(keyFn, FunctionType([this.key_type], undefined, null));
|
|
884
|
+
const predFnAst = valueOrExprToAstTyped(predFn, FunctionType([this.key_type], BooleanType, null));
|
|
885
|
+
return this.groupReduce(((_$, key) => Expr.fromAst(keyFnAst)(key)), (() => false), ((_$, acc, key) => {
|
|
886
|
+
const pred = Expr.fromAst(predFnAst)(key);
|
|
887
|
+
return acc.or(() => pred);
|
|
888
|
+
}));
|
|
889
|
+
}
|
|
890
|
+
groupSum(keyFn, valueFn) {
|
|
891
|
+
const keyFnAst = valueOrExprToAstTyped(keyFn, FunctionType([this.key_type], undefined, null));
|
|
892
|
+
const valueFnAst = valueOrExprToAstTyped(valueFn ?? ((_$, x) => x), FunctionType([this.key_type], undefined, null));
|
|
893
|
+
const valueType = valueFnAst.type.output;
|
|
894
|
+
const isInteger = isTypeEqual(valueType, IntegerType);
|
|
895
|
+
const isFloat = isTypeEqual(valueType, FloatType);
|
|
896
|
+
if (!isInteger && !isFloat) {
|
|
897
|
+
throw new Error(`Can only perform groupSum on Integer or Float values, got ${printType(valueType)}`);
|
|
898
|
+
}
|
|
899
|
+
return this.toDict(((_$, key) => Expr.fromAst(keyFnAst)(key)), ((_$, key) => Expr.fromAst(valueFnAst)(key)), ((_$, a, b) => a.add(b)));
|
|
900
|
+
}
|
|
901
|
+
groupMean(keyFn, valueFn) {
|
|
902
|
+
const keyFnAst = valueOrExprToAstTyped(keyFn, FunctionType([this.key_type], undefined, null));
|
|
903
|
+
const valueFnAst = valueOrExprToAstTyped(valueFn ?? ((_$, x) => x), FunctionType([this.key_type], undefined, null));
|
|
904
|
+
const valueType = valueFnAst.type.output;
|
|
905
|
+
const isInteger = isTypeEqual(valueType, IntegerType);
|
|
906
|
+
const isFloat = isTypeEqual(valueType, FloatType);
|
|
907
|
+
if (!isInteger && !isFloat) {
|
|
908
|
+
throw new Error(`Can only perform groupMean on Integer or Float values, got ${printType(valueType)}`);
|
|
909
|
+
}
|
|
910
|
+
return this.toDict(((_$, key) => Expr.fromAst(keyFnAst)(key)), ((_$, key) => {
|
|
911
|
+
const val = Expr.fromAst(valueFnAst)(key);
|
|
912
|
+
return { sum: isInteger ? val.toFloat() : val, count: 1n };
|
|
913
|
+
}), ((_$, a, b) => ({ sum: a.sum.add(b.sum), count: a.count.add(b.count) }))).map(((_$, v) => v.sum.divide(v.count.toFloat())));
|
|
914
|
+
}
|
|
915
|
+
// Common reducers are provided, based on reduce
|
|
916
|
+
/**
|
|
917
|
+
* Returns true if all elements satisfy a condition (or are true for boolean sets).
|
|
918
|
+
*
|
|
919
|
+
* @param fn - Optional predicate function to test each element (required for non-boolean sets)
|
|
920
|
+
* @returns A BooleanExpr that is true if all elements pass the test, false otherwise
|
|
921
|
+
*
|
|
922
|
+
* @remarks
|
|
923
|
+
* - Empty sets always return true
|
|
924
|
+
* - Short-circuits on the first false element for efficiency
|
|
925
|
+
* - For boolean sets, the function parameter can be omitted
|
|
926
|
+
*
|
|
927
|
+
* @see {@link some} to check if at least one element satisfies the condition
|
|
928
|
+
*
|
|
929
|
+
* @example
|
|
930
|
+
* ```ts
|
|
931
|
+
* // Check if all numbers are positive
|
|
932
|
+
* const allPositive = East.function([SetType(IntegerType)], BooleanType, ($, numbers) => {
|
|
933
|
+
* $.return(numbers.every(($, n) => n.greaterThan(0n)));
|
|
934
|
+
* });
|
|
935
|
+
* const compiled = East.compile(allPositive.toIR(), []);
|
|
936
|
+
* compiled(new Set([1n, 2n, 3n])); // true
|
|
937
|
+
* compiled(new Set([1n, -2n, 3n])); // false
|
|
938
|
+
* compiled(new Set([])); // true (empty set)
|
|
939
|
+
* ```
|
|
940
|
+
*
|
|
941
|
+
* @example
|
|
942
|
+
* ```ts
|
|
943
|
+
* // For boolean sets, no function needed
|
|
944
|
+
* const allTrue = East.function([SetType(BooleanType)], BooleanType, ($, flags) => {
|
|
945
|
+
* $.return(flags.every());
|
|
946
|
+
* });
|
|
947
|
+
* const compiled = East.compile(allTrue.toIR(), []);
|
|
948
|
+
* compiled(new Set([true, true])); // true
|
|
949
|
+
* compiled(new Set([true, false])); // false
|
|
950
|
+
* ```
|
|
951
|
+
*/
|
|
952
|
+
every(fn) {
|
|
953
|
+
if (fn === undefined) {
|
|
954
|
+
if (!isTypeEqual(this.key_type, BooleanType)) {
|
|
955
|
+
throw new Error(`Can only perform every on set of booleans, got ${printType(this.key_type)}`);
|
|
956
|
+
}
|
|
957
|
+
// Short-circuit on first false value - use explicit function AST to avoid type inference issues
|
|
958
|
+
const optionType = VariantType({ none: NullType, some: NullType });
|
|
959
|
+
const paramVariable = {
|
|
960
|
+
ast_type: "Variable",
|
|
961
|
+
type: this.key_type,
|
|
962
|
+
location: get_location(2),
|
|
963
|
+
mutable: false,
|
|
964
|
+
};
|
|
965
|
+
// Check if boolean is NOT true, then return some(null) to stop, otherwise return none to continue
|
|
966
|
+
const notCondition = {
|
|
967
|
+
ast_type: "Builtin",
|
|
968
|
+
type: BooleanType,
|
|
969
|
+
location: get_location(2),
|
|
970
|
+
builtin: "BooleanNot",
|
|
971
|
+
type_parameters: [],
|
|
972
|
+
arguments: [paramVariable]
|
|
973
|
+
};
|
|
974
|
+
const checkFnAst = {
|
|
975
|
+
ast_type: "Function",
|
|
976
|
+
type: FunctionType([this.key_type], optionType, []),
|
|
977
|
+
location: get_location(2),
|
|
978
|
+
parameters: [paramVariable],
|
|
979
|
+
body: {
|
|
980
|
+
ast_type: "IfElse",
|
|
981
|
+
type: optionType,
|
|
982
|
+
location: get_location(2),
|
|
983
|
+
ifs: [{
|
|
984
|
+
predicate: notCondition,
|
|
985
|
+
body: { ast_type: "Variant", type: optionType, location: get_location(2), case: "some", value: { ast_type: "Value", type: NullType, location: get_location(2), value: null } }
|
|
986
|
+
}],
|
|
987
|
+
else_body: { ast_type: "Variant", type: optionType, location: get_location(2), case: "none", value: { ast_type: "Value", type: NullType, location: get_location(2), value: null } }
|
|
988
|
+
}
|
|
989
|
+
};
|
|
990
|
+
const result = Expr.fromAst({
|
|
991
|
+
ast_type: "Builtin",
|
|
992
|
+
type: optionType,
|
|
993
|
+
location: get_location(2),
|
|
994
|
+
builtin: "SetFirstMap",
|
|
995
|
+
type_parameters: [this.key_type, NullType],
|
|
996
|
+
arguments: [this[AstSymbol], checkFnAst],
|
|
997
|
+
});
|
|
998
|
+
return Expr.match(result, { some: () => false, none: () => true });
|
|
999
|
+
}
|
|
1000
|
+
const fnAst = valueOrExprToAstTyped(fn, FunctionType([this.key_type], BooleanType, null));
|
|
1001
|
+
// Short-circuit on first false value
|
|
1002
|
+
const result = this.firstMap(($, k) => {
|
|
1003
|
+
const result = Expr.fromAst(fnAst)(k);
|
|
1004
|
+
return result.not().ifElse(() => some(null), () => none);
|
|
1005
|
+
});
|
|
1006
|
+
return Expr.match(result, { some: () => false, none: () => true });
|
|
1007
|
+
}
|
|
1008
|
+
/**
|
|
1009
|
+
* Returns true if at least one element satisfies a condition (or is true for boolean sets).
|
|
1010
|
+
*
|
|
1011
|
+
* @param fn - Optional predicate function to test each element (required for non-boolean sets)
|
|
1012
|
+
* @returns A BooleanExpr that is true if any element passes the test, false otherwise
|
|
1013
|
+
*
|
|
1014
|
+
* @remarks
|
|
1015
|
+
* - Empty sets always return false
|
|
1016
|
+
* - Short-circuits on the first true element for efficiency
|
|
1017
|
+
* - For boolean sets, the function parameter can be omitted
|
|
1018
|
+
*
|
|
1019
|
+
* @see {@link every} to check if all elements satisfy the condition
|
|
1020
|
+
*
|
|
1021
|
+
* @example
|
|
1022
|
+
* ```ts
|
|
1023
|
+
* // Check if any number is negative
|
|
1024
|
+
* const hasNegative = East.function([SetType(IntegerType)], BooleanType, ($, numbers) => {
|
|
1025
|
+
* $.return(numbers.some(($, n) => n.lessThan(0n)));
|
|
1026
|
+
* });
|
|
1027
|
+
* const compiled = East.compile(hasNegative.toIR(), []);
|
|
1028
|
+
* compiled(new Set([1n, 2n, 3n])); // false
|
|
1029
|
+
* compiled(new Set([1n, -2n, 3n])); // true
|
|
1030
|
+
* compiled(new Set([])); // false (empty set)
|
|
1031
|
+
* ```
|
|
1032
|
+
*
|
|
1033
|
+
* @example
|
|
1034
|
+
* ```ts
|
|
1035
|
+
* // For boolean sets, no function needed
|
|
1036
|
+
* const anyTrue = East.function([SetType(BooleanType)], BooleanType, ($, flags) => {
|
|
1037
|
+
* $.return(flags.some());
|
|
1038
|
+
* });
|
|
1039
|
+
* const compiled = East.compile(anyTrue.toIR(), []);
|
|
1040
|
+
* compiled(new Set([false, false])); // false
|
|
1041
|
+
* compiled(new Set([false, true])); // true
|
|
1042
|
+
* ```
|
|
1043
|
+
*/
|
|
1044
|
+
some(fn) {
|
|
1045
|
+
if (fn === undefined) {
|
|
1046
|
+
if (!isTypeEqual(this.key_type, BooleanType)) {
|
|
1047
|
+
throw new Error(`Can only perform some on set of booleans, got ${printType(this.key_type)}`);
|
|
1048
|
+
}
|
|
1049
|
+
// Short-circuit on first true value - use explicit function AST to avoid type inference issues
|
|
1050
|
+
const optionType = VariantType({ none: NullType, some: NullType });
|
|
1051
|
+
const paramVariable = {
|
|
1052
|
+
ast_type: "Variable",
|
|
1053
|
+
type: this.key_type,
|
|
1054
|
+
location: get_location(2),
|
|
1055
|
+
mutable: false,
|
|
1056
|
+
};
|
|
1057
|
+
// Check if boolean is true, then return some(null) to stop, otherwise return none to continue
|
|
1058
|
+
const checkFnAst = {
|
|
1059
|
+
ast_type: "Function",
|
|
1060
|
+
type: FunctionType([this.key_type], optionType, []),
|
|
1061
|
+
location: get_location(2),
|
|
1062
|
+
parameters: [paramVariable],
|
|
1063
|
+
body: {
|
|
1064
|
+
ast_type: "IfElse",
|
|
1065
|
+
type: optionType,
|
|
1066
|
+
location: get_location(2),
|
|
1067
|
+
ifs: [{
|
|
1068
|
+
predicate: paramVariable,
|
|
1069
|
+
body: { ast_type: "Variant", type: optionType, location: get_location(2), case: "some", value: { ast_type: "Value", type: NullType, location: get_location(2), value: null } }
|
|
1070
|
+
}],
|
|
1071
|
+
else_body: { ast_type: "Variant", type: optionType, location: get_location(2), case: "none", value: { ast_type: "Value", type: NullType, location: get_location(2), value: null } }
|
|
1072
|
+
}
|
|
1073
|
+
};
|
|
1074
|
+
const result = Expr.fromAst({
|
|
1075
|
+
ast_type: "Builtin",
|
|
1076
|
+
type: optionType,
|
|
1077
|
+
location: get_location(2),
|
|
1078
|
+
builtin: "SetFirstMap",
|
|
1079
|
+
type_parameters: [this.key_type, NullType],
|
|
1080
|
+
arguments: [this[AstSymbol], checkFnAst],
|
|
1081
|
+
});
|
|
1082
|
+
return Expr.match(result, { some: () => true, none: () => false });
|
|
1083
|
+
}
|
|
1084
|
+
const fnAst = valueOrExprToAstTyped(fn, FunctionType([this.key_type], BooleanType, null));
|
|
1085
|
+
// Short-circuit on first true value
|
|
1086
|
+
const result = this.firstMap(($, k) => {
|
|
1087
|
+
const result = Expr.fromAst(fnAst)(k);
|
|
1088
|
+
return result.ifElse(() => some(null), () => none);
|
|
1089
|
+
});
|
|
1090
|
+
return Expr.match(result, { some: () => true, none: () => false });
|
|
1091
|
+
}
|
|
1092
|
+
sum(fn) {
|
|
1093
|
+
if (fn === undefined) {
|
|
1094
|
+
if (!(isTypeEqual(this.key_type, IntegerType) || isTypeEqual(this.key_type, FloatType))) {
|
|
1095
|
+
throw new Error(`Can only perform sum on set of numbers (Integer or Float), got ${printType(this.key_type)}`);
|
|
1096
|
+
}
|
|
1097
|
+
const zero = isTypeEqual(this.key_type, IntegerType) ? 0n : 0.0;
|
|
1098
|
+
return this.reduce(($, previous, value) => previous.add(value), zero);
|
|
1099
|
+
}
|
|
1100
|
+
else {
|
|
1101
|
+
const fnAst = valueOrExprToAstTyped(fn, FunctionType([this.key_type], undefined, null));
|
|
1102
|
+
const returnType = fnAst.type.output;
|
|
1103
|
+
if (!(isTypeEqual(returnType, IntegerType) || isTypeEqual(returnType, FloatType))) {
|
|
1104
|
+
throw new Error(`Can only perform sum on array of numbers (Integer or Float), got ${printType(returnType)}`);
|
|
1105
|
+
}
|
|
1106
|
+
const zero = isTypeEqual(returnType, IntegerType) ? 0n : 0.0;
|
|
1107
|
+
return this.reduce(($, previous, key) => previous.add(Expr.fromAst(fnAst)(key)), zero);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
mean(fn) {
|
|
1111
|
+
if (fn === undefined) {
|
|
1112
|
+
if (isTypeEqual(this.key_type, IntegerType)) {
|
|
1113
|
+
return this.reduce(($, previous, value) => previous.add(value.toFloat()), 0.0).divide(this.size().toFloat());
|
|
1114
|
+
}
|
|
1115
|
+
else if (isTypeEqual(this.key_type, FloatType)) {
|
|
1116
|
+
return this.reduce(($, previous, value) => previous.add(value), 0.0).divide(this.size().toFloat());
|
|
1117
|
+
}
|
|
1118
|
+
else {
|
|
1119
|
+
throw new Error(`Can only perform mean on set of numbers (Integer or Float), got ${printType(this.key_type)}`);
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
else {
|
|
1123
|
+
const fnAst = valueOrExprToAstTyped(fn, FunctionType([this.key_type], undefined, null));
|
|
1124
|
+
const returnType = fnAst.type.output;
|
|
1125
|
+
if (isTypeEqual(returnType, IntegerType)) {
|
|
1126
|
+
return this.reduce(($, previous, key) => previous.add(Expr.fromAst(fnAst)(key).toFloat()), 0.0).divide(this.size().toFloat());
|
|
1127
|
+
}
|
|
1128
|
+
else if (isTypeEqual(returnType, FloatType)) {
|
|
1129
|
+
return this.reduce(($, previous, key) => previous.add(Expr.fromAst(fnAst)(key)), 0.0).divide(this.size().toFloat());
|
|
1130
|
+
}
|
|
1131
|
+
else {
|
|
1132
|
+
throw new Error(`Can only perform mean on set of numbers (Integer or Float), got ${printType(returnType)}`);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
//# sourceMappingURL=set.js.map
|