@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,1017 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
import { toEastTypeValue } from "./type_of_type.js";
|
|
6
|
+
import { isVariant, variant } from "./containers/variant.js";
|
|
7
|
+
export function isFor(type, typeCtx = []) {
|
|
8
|
+
// Convert EastType to EastTypeValue if necessary
|
|
9
|
+
if (!isVariant(type)) {
|
|
10
|
+
type = toEastTypeValue(type);
|
|
11
|
+
}
|
|
12
|
+
if (type.type === "Never") {
|
|
13
|
+
return (_x, _y, _ctx) => { throw new Error(`Attempted to compare values of type .Never`); };
|
|
14
|
+
}
|
|
15
|
+
else if (type.type === "Null") {
|
|
16
|
+
return (_x, _y, _ctx) => true;
|
|
17
|
+
}
|
|
18
|
+
else if (type.type === "Boolean") {
|
|
19
|
+
return (x, y, _ctx) => x === y;
|
|
20
|
+
}
|
|
21
|
+
else if (type.type === "Integer") {
|
|
22
|
+
return (x, y, _ctx) => x === y;
|
|
23
|
+
}
|
|
24
|
+
else if (type.type === "Float") {
|
|
25
|
+
return (x, y, _ctx) => Number.isNaN(x) ? Number.isNaN(y) : x === y; // Note Object.is can fail for different NaN representations
|
|
26
|
+
}
|
|
27
|
+
else if (type.type === "String") {
|
|
28
|
+
return (x, y, _ctx) => x === y;
|
|
29
|
+
}
|
|
30
|
+
else if (type.type === "DateTime") {
|
|
31
|
+
return (x, y, _ctx) => x.valueOf() === y.valueOf();
|
|
32
|
+
}
|
|
33
|
+
else if (type.type === "Blob") {
|
|
34
|
+
// in our type system blobs are immutable (i.e. not reference types), so we must compare by value here
|
|
35
|
+
return (x, y, _ctx) => {
|
|
36
|
+
if (x.length !== y.length)
|
|
37
|
+
return false;
|
|
38
|
+
for (let i = 0; i < x.length; i++) {
|
|
39
|
+
if (x[i] !== y[i])
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
else if (type.type === "Ref") {
|
|
46
|
+
// mutable types are compared by identity
|
|
47
|
+
return (x, y, _ctx) => Object.is(x, y);
|
|
48
|
+
}
|
|
49
|
+
else if (type.type === "Array") {
|
|
50
|
+
// mutable types are compared by identity
|
|
51
|
+
return (x, y, _ctx) => Object.is(x, y);
|
|
52
|
+
}
|
|
53
|
+
else if (type.type === "Set") {
|
|
54
|
+
// mutable types are compared by identity
|
|
55
|
+
return (x, y, _ctx) => Object.is(x, y);
|
|
56
|
+
}
|
|
57
|
+
else if (type.type === "Dict") {
|
|
58
|
+
// mutable types are compared by identity
|
|
59
|
+
return (x, y, _ctx) => Object.is(x, y);
|
|
60
|
+
}
|
|
61
|
+
else if (type.type === "Struct") {
|
|
62
|
+
// const field_comparers = type.value.map(({ name, type }) => [name, isFor(type, typeCtx)] as const);
|
|
63
|
+
const field_comparers = [];
|
|
64
|
+
const ret = (x, y, ctx) => {
|
|
65
|
+
for (const [k, comparer] of field_comparers) {
|
|
66
|
+
if (!comparer(x[k], y[k], ctx)) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return true;
|
|
71
|
+
};
|
|
72
|
+
typeCtx.push(ret);
|
|
73
|
+
for (const field of type.value) {
|
|
74
|
+
field_comparers.push([field.name, isFor(field.type, typeCtx)]);
|
|
75
|
+
}
|
|
76
|
+
typeCtx.pop();
|
|
77
|
+
return ret;
|
|
78
|
+
}
|
|
79
|
+
else if (type.type === "Variant") {
|
|
80
|
+
const case_comparers = {};
|
|
81
|
+
const ret = (x, y, ctx) => {
|
|
82
|
+
if (x.type !== y.type)
|
|
83
|
+
return false;
|
|
84
|
+
return case_comparers[x.type](x.value, y.value, ctx);
|
|
85
|
+
};
|
|
86
|
+
typeCtx.push(ret);
|
|
87
|
+
for (const { name, type: caseType } of type.value) {
|
|
88
|
+
case_comparers[name] = isFor(caseType, typeCtx);
|
|
89
|
+
}
|
|
90
|
+
typeCtx.pop();
|
|
91
|
+
return ret;
|
|
92
|
+
}
|
|
93
|
+
else if (type.type === "Recursive") {
|
|
94
|
+
const ret = typeCtx[typeCtx.length - Number(type.value)];
|
|
95
|
+
if (ret === undefined) {
|
|
96
|
+
throw new Error(`Internal error: Recursive type context not found`);
|
|
97
|
+
}
|
|
98
|
+
return ret;
|
|
99
|
+
}
|
|
100
|
+
else if (type.type === "Function") {
|
|
101
|
+
throw new Error(`Attempted to compare values of type .Function`);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
throw new Error(`Unhandled type ${type.type}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
export function equalFor(type, typeCtx = []) {
|
|
108
|
+
// Convert EastType to EastTypeValue if necessary
|
|
109
|
+
if (!isVariant(type)) {
|
|
110
|
+
type = toEastTypeValue(type);
|
|
111
|
+
}
|
|
112
|
+
if (type.type === "Never") {
|
|
113
|
+
return (_x, _y, _ctx) => { throw new Error(`Attempted to compare values of type .Never`); };
|
|
114
|
+
}
|
|
115
|
+
else if (type.type === "Null") {
|
|
116
|
+
return (_x, _y, _ctx) => true;
|
|
117
|
+
}
|
|
118
|
+
else if (type.type === "Boolean") {
|
|
119
|
+
return (x, y, _ctx) => x === y;
|
|
120
|
+
}
|
|
121
|
+
else if (type.type === "Integer") {
|
|
122
|
+
return (x, y, _ctx) => x === y;
|
|
123
|
+
}
|
|
124
|
+
else if (type.type === "Float") {
|
|
125
|
+
return (x, y, _ctx) => Number.isNaN(x) ? Number.isNaN(y) : Object.is(x, y);
|
|
126
|
+
}
|
|
127
|
+
else if (type.type === "String") {
|
|
128
|
+
return (x, y, _ctx) => x === y;
|
|
129
|
+
}
|
|
130
|
+
else if (type.type === "DateTime") {
|
|
131
|
+
return (x, y, _ctx) => x.valueOf() === y.valueOf();
|
|
132
|
+
}
|
|
133
|
+
else if (type.type === "Blob") {
|
|
134
|
+
return (x, y, _ctx) => {
|
|
135
|
+
if (x.length !== y.length)
|
|
136
|
+
return false;
|
|
137
|
+
for (let i = 0; i < x.length; i++) {
|
|
138
|
+
if (x[i] !== y[i])
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
return true;
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
else if (type.type === "Ref") {
|
|
145
|
+
let value_comparer;
|
|
146
|
+
const ret = (x, y, ctx) => {
|
|
147
|
+
// Fast path
|
|
148
|
+
if (Object.is(x, y))
|
|
149
|
+
return true;
|
|
150
|
+
// Create context if needed (top-level call)
|
|
151
|
+
if (!ctx) {
|
|
152
|
+
ctx = new Map();
|
|
153
|
+
}
|
|
154
|
+
// Check if we've visited this pair
|
|
155
|
+
const xSet = ctx.get(x);
|
|
156
|
+
if (xSet?.has(y)) {
|
|
157
|
+
return true; // Cycle - we're re-encountering this pair
|
|
158
|
+
}
|
|
159
|
+
// Mark as visited
|
|
160
|
+
let visitedSet = ctx.get(x);
|
|
161
|
+
if (!visitedSet) {
|
|
162
|
+
visitedSet = new Set();
|
|
163
|
+
ctx.set(x, visitedSet);
|
|
164
|
+
}
|
|
165
|
+
visitedSet.add(y);
|
|
166
|
+
// Now do the actual comparison
|
|
167
|
+
return value_comparer(x.value, y.value, ctx);
|
|
168
|
+
};
|
|
169
|
+
typeCtx.push(ret);
|
|
170
|
+
value_comparer = equalFor(type.value, typeCtx);
|
|
171
|
+
typeCtx.pop();
|
|
172
|
+
return ret;
|
|
173
|
+
}
|
|
174
|
+
else if (type.type === "Array") {
|
|
175
|
+
let value_comparer;
|
|
176
|
+
const ret = (x, y, ctx) => {
|
|
177
|
+
// Fast path
|
|
178
|
+
if (Object.is(x, y))
|
|
179
|
+
return true;
|
|
180
|
+
// Create context if needed (top-level call)
|
|
181
|
+
if (!ctx) {
|
|
182
|
+
ctx = new Map();
|
|
183
|
+
}
|
|
184
|
+
// Check if we've visited this pair
|
|
185
|
+
const xSet = ctx.get(x);
|
|
186
|
+
if (xSet?.has(y)) {
|
|
187
|
+
return true; // Cycle - we're re-encountering this pair
|
|
188
|
+
}
|
|
189
|
+
// Mark as visited
|
|
190
|
+
let visitedSet = ctx.get(x);
|
|
191
|
+
if (!visitedSet) {
|
|
192
|
+
visitedSet = new Set();
|
|
193
|
+
ctx.set(x, visitedSet);
|
|
194
|
+
}
|
|
195
|
+
visitedSet.add(y);
|
|
196
|
+
// Now do the actual comparison
|
|
197
|
+
if (x.length !== y.length)
|
|
198
|
+
return false;
|
|
199
|
+
for (let i = 0; i < x.length; i++) {
|
|
200
|
+
if (!value_comparer(x[i], y[i], ctx)) {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return true;
|
|
205
|
+
};
|
|
206
|
+
typeCtx.push(ret);
|
|
207
|
+
value_comparer = equalFor(type.value, typeCtx);
|
|
208
|
+
typeCtx.pop();
|
|
209
|
+
return ret;
|
|
210
|
+
}
|
|
211
|
+
else if (type.type === "Set") {
|
|
212
|
+
return (x, y, _ctx) => {
|
|
213
|
+
if (x.size !== y.size)
|
|
214
|
+
return false;
|
|
215
|
+
for (const xk of x) {
|
|
216
|
+
if (!y.has(xk))
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
return true;
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
else if (type.type === "Dict") {
|
|
223
|
+
let value_comparer;
|
|
224
|
+
const ret = (x, y, ctx) => {
|
|
225
|
+
// Fast path
|
|
226
|
+
if (Object.is(x, y))
|
|
227
|
+
return true;
|
|
228
|
+
// Create context if needed (top-level call)
|
|
229
|
+
if (!ctx) {
|
|
230
|
+
ctx = new Map();
|
|
231
|
+
}
|
|
232
|
+
// Check if we've visited this pair
|
|
233
|
+
const xSet = ctx.get(x);
|
|
234
|
+
if (xSet?.has(y)) {
|
|
235
|
+
return true; // Cycle - we're re-encountering this pair
|
|
236
|
+
}
|
|
237
|
+
// Mark as visited
|
|
238
|
+
let visitedSet = ctx.get(x);
|
|
239
|
+
if (!visitedSet) {
|
|
240
|
+
visitedSet = new Set();
|
|
241
|
+
ctx.set(x, visitedSet);
|
|
242
|
+
}
|
|
243
|
+
visitedSet.add(y);
|
|
244
|
+
// Now do the actual comparison
|
|
245
|
+
if (x.size !== y.size)
|
|
246
|
+
return false;
|
|
247
|
+
for (const [xk, xv] of x) {
|
|
248
|
+
if (!y.has(xk))
|
|
249
|
+
return false;
|
|
250
|
+
const yv = y.get(xk);
|
|
251
|
+
if (!value_comparer(xv, yv, ctx))
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
return true;
|
|
255
|
+
};
|
|
256
|
+
typeCtx.push(ret);
|
|
257
|
+
value_comparer = equalFor(type.value.value, typeCtx);
|
|
258
|
+
typeCtx.pop();
|
|
259
|
+
return ret;
|
|
260
|
+
}
|
|
261
|
+
else if (type.type === "Struct") {
|
|
262
|
+
const field_comparers = [];
|
|
263
|
+
const ret = (x, y, ctx) => {
|
|
264
|
+
// Check for cycles (needed for recursive types that can create circular references)
|
|
265
|
+
if (!ctx) {
|
|
266
|
+
ctx = new Map();
|
|
267
|
+
}
|
|
268
|
+
// Check if we've visited this pair
|
|
269
|
+
const xSet = ctx.get(x);
|
|
270
|
+
if (xSet?.has(y)) {
|
|
271
|
+
return true; // Cycle - we're re-encountering this pair
|
|
272
|
+
}
|
|
273
|
+
// Mark as visited
|
|
274
|
+
let visitedSet = ctx.get(x);
|
|
275
|
+
if (!visitedSet) {
|
|
276
|
+
visitedSet = new Set();
|
|
277
|
+
ctx.set(x, visitedSet);
|
|
278
|
+
}
|
|
279
|
+
visitedSet.add(y);
|
|
280
|
+
// Compare fields
|
|
281
|
+
for (const [k, comparer] of field_comparers) {
|
|
282
|
+
if (!comparer(x[k], y[k], ctx)) {
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return true;
|
|
287
|
+
};
|
|
288
|
+
typeCtx.push(ret);
|
|
289
|
+
for (const field of type.value) {
|
|
290
|
+
field_comparers.push([field.name, equalFor(field.type, typeCtx)]);
|
|
291
|
+
}
|
|
292
|
+
typeCtx.pop();
|
|
293
|
+
return ret;
|
|
294
|
+
}
|
|
295
|
+
else if (type.type === "Variant") {
|
|
296
|
+
const case_comparers = {};
|
|
297
|
+
const ret = (x, y, ctx) => {
|
|
298
|
+
if (x.type !== y.type)
|
|
299
|
+
return false;
|
|
300
|
+
// Check for cycles (needed for recursive types)
|
|
301
|
+
if (!ctx) {
|
|
302
|
+
ctx = new Map();
|
|
303
|
+
}
|
|
304
|
+
const xSet = ctx.get(x);
|
|
305
|
+
if (xSet?.has(y)) {
|
|
306
|
+
return true; // Cycle
|
|
307
|
+
}
|
|
308
|
+
let visitedSet = ctx.get(x);
|
|
309
|
+
if (!visitedSet) {
|
|
310
|
+
visitedSet = new Set();
|
|
311
|
+
ctx.set(x, visitedSet);
|
|
312
|
+
}
|
|
313
|
+
visitedSet.add(y);
|
|
314
|
+
return case_comparers[x.type](x.value, y.value, ctx);
|
|
315
|
+
};
|
|
316
|
+
typeCtx.push(ret);
|
|
317
|
+
for (const { name, type: caseType } of type.value) {
|
|
318
|
+
case_comparers[name] = equalFor(caseType, typeCtx);
|
|
319
|
+
}
|
|
320
|
+
typeCtx.pop();
|
|
321
|
+
return ret;
|
|
322
|
+
}
|
|
323
|
+
else if (type.type === "Recursive") {
|
|
324
|
+
const ret = typeCtx[typeCtx.length - Number(type.value)];
|
|
325
|
+
if (ret === undefined) {
|
|
326
|
+
throw new Error(`Internal error: Recursive type context not found`);
|
|
327
|
+
}
|
|
328
|
+
return ret;
|
|
329
|
+
}
|
|
330
|
+
else if (type.type === "Function") {
|
|
331
|
+
throw new Error(`Attempted to compare values of type .Function`);
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
throw new Error(`Unhandled type ${type.type}`);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
export function notEqualFor(type, typeCtx = []) {
|
|
338
|
+
const equal = equalFor(type, typeCtx);
|
|
339
|
+
return (x, y, ctx) => !equal(x, y, ctx);
|
|
340
|
+
// // Convert EastType to EastTypeValue if necessary
|
|
341
|
+
// if (!isVariant(type)) {
|
|
342
|
+
// type = toEastTypeValue(type);
|
|
343
|
+
// }
|
|
344
|
+
// if (type.type === "Never") {
|
|
345
|
+
// return (_x: unknown, _y: unknown) => { throw new Error(`Attempted to compare values of type .Never`)};
|
|
346
|
+
// } else if (type.type === "Null") {
|
|
347
|
+
// return (_x: null, _y: null) => false;
|
|
348
|
+
// } else if (type.type === "Boolean") {
|
|
349
|
+
// return (x: boolean, y: boolean) => x !== y;
|
|
350
|
+
// } else if (type.type === "Integer") {
|
|
351
|
+
// return (x: bigint, y: bigint) => x !== y;
|
|
352
|
+
// } else if (type.type === "Float") {
|
|
353
|
+
// return (x: number, y: number) => Number.isNaN(x) ? !Number.isNaN(y) : !Object.is(x, y);
|
|
354
|
+
// } else if (type.type === "String") {
|
|
355
|
+
// return (x: string, y: string) => x !== y;
|
|
356
|
+
// } else if (type.type === "DateTime") {
|
|
357
|
+
// return (x: Date, y: Date) => x.valueOf() !== y.valueOf();
|
|
358
|
+
// } else if (type.type === "Blob") {
|
|
359
|
+
// return (x: Uint8Array, y: Uint8Array) => {
|
|
360
|
+
// if (x.length !== y.length) return true;
|
|
361
|
+
// for (let i = 0; i < x.length; i++) {
|
|
362
|
+
// if (x[i] !== y[i]) return true;
|
|
363
|
+
// }
|
|
364
|
+
// return false;
|
|
365
|
+
// }
|
|
366
|
+
// } else if (type.type === "Array") {
|
|
367
|
+
// const eq = equalFor(type as EastTypeValue, typeCtx);
|
|
368
|
+
// return (x: any[], y: any[], ctx?: ValueContext) => !eq(x, y, ctx);
|
|
369
|
+
// } else if (type.type === "Set") {
|
|
370
|
+
// return (x: Set<any>, y: Set<any>) => {
|
|
371
|
+
// if (x.size !== y.size) return true;
|
|
372
|
+
// for (const xk of x) {
|
|
373
|
+
// if (!y.has(xk)) return true;
|
|
374
|
+
// }
|
|
375
|
+
// return false;
|
|
376
|
+
// }
|
|
377
|
+
// } else if (type.type === "Dict") {
|
|
378
|
+
// const eq = equalFor(type as EastTypeValue, typeCtx);
|
|
379
|
+
// return (x: Map<any, any>, y: Map<any, any>, ctx?: ValueContext) => !eq(x, y, ctx);
|
|
380
|
+
// } else if (type.type === "Struct") {
|
|
381
|
+
// const field_comparers: [string, (x: any, y: any, ctx?: ValueContext) => boolean][] = [];
|
|
382
|
+
// const ret = (x: Record<string, any>, y: Record<string, any>, ctx?: ValueContext) => {
|
|
383
|
+
// for (const [k, comparer] of field_comparers) {
|
|
384
|
+
// if (comparer(x[k], y[k], ctx)) return true;
|
|
385
|
+
// }
|
|
386
|
+
// return false;
|
|
387
|
+
// }
|
|
388
|
+
// typeCtx.push(ret);
|
|
389
|
+
// for (const field of type.value) {
|
|
390
|
+
// field_comparers.push([field.name, notEqualFor(field.type, typeCtx)] as const);
|
|
391
|
+
// }
|
|
392
|
+
// typeCtx.pop();
|
|
393
|
+
// return ret;
|
|
394
|
+
// } else if (type.type === "Variant") {
|
|
395
|
+
// const case_comparers: Record<string, (x: any, y: any, ctx?: ValueContext) => boolean> = {};
|
|
396
|
+
// const ret = (x: variant, y: variant, ctx?: ValueContext) => {
|
|
397
|
+
// if (x.type !== y.type) return true;
|
|
398
|
+
// return case_comparers[x.type]!(x.value, y.value, ctx);
|
|
399
|
+
// };
|
|
400
|
+
// typeCtx.push(ret);
|
|
401
|
+
// for (const { name, type: caseType } of type.value) {
|
|
402
|
+
// case_comparers[name] = notEqualFor(caseType, typeCtx);
|
|
403
|
+
// }
|
|
404
|
+
// typeCtx.pop();
|
|
405
|
+
// return ret;
|
|
406
|
+
// } else if (type.type === "Recursive") {
|
|
407
|
+
// const ret = typeCtx[typeCtx.length - Number(type.value)];
|
|
408
|
+
// if (ret === undefined) {
|
|
409
|
+
// throw new Error(`Internal error: Recursive type context not found`);
|
|
410
|
+
// }
|
|
411
|
+
// return ret;
|
|
412
|
+
// } else if (type.type === "Function") {
|
|
413
|
+
// throw new Error(`Attempted to compare values of type .Function`);
|
|
414
|
+
// } else {
|
|
415
|
+
// throw new Error(`Unhandled type ${(type satisfies never as EastTypeValue).type}`);
|
|
416
|
+
// }
|
|
417
|
+
}
|
|
418
|
+
export function lessFor(type, typeCtx = []) {
|
|
419
|
+
const cmp = compareFor(type, typeCtx);
|
|
420
|
+
return (x, y, ctx) => cmp(x, y, ctx) === -1;
|
|
421
|
+
// // Convert EastType to EastTypeValue if necessary
|
|
422
|
+
// if (!isVariant(type)) {
|
|
423
|
+
// type = toEastTypeValue(type);
|
|
424
|
+
// }
|
|
425
|
+
// if (type.type === "Never") {
|
|
426
|
+
// return (_x: unknown, _y: unknown) => { throw new Error(`Attempted to compare values of type .Never`)};
|
|
427
|
+
// } else if (type.type === "Null") {
|
|
428
|
+
// return (_x: null, _y: null) => false;
|
|
429
|
+
// } else if (type.type === "Boolean") {
|
|
430
|
+
// return (x: boolean, y: boolean) => x < y;
|
|
431
|
+
// } else if (type.type === "Integer") {
|
|
432
|
+
// return (x: bigint, y: bigint) => x < y;
|
|
433
|
+
// } else if (type.type === "Float") {
|
|
434
|
+
// return (x: number, y: number) => {
|
|
435
|
+
// if (Number.isNaN(y)) return !Number.isNaN(x);
|
|
436
|
+
// if (Object.is(x, -0) && Object.is(y, 0)) return true;
|
|
437
|
+
// if (Object.is(x, 0) && Object.is(y, -0)) return false;
|
|
438
|
+
// return x < y;
|
|
439
|
+
// };
|
|
440
|
+
// } else if (type.type === "String") {
|
|
441
|
+
// return (x: string, y: string) => x < y;
|
|
442
|
+
// } else if (type.type === "DateTime") {
|
|
443
|
+
// return (x: Date, y: Date) => x.valueOf() < y.valueOf();
|
|
444
|
+
// } else if (type.type === "Blob") {
|
|
445
|
+
// return (x: Uint8Array, y: Uint8Array) => {
|
|
446
|
+
// const length = x.length < y.length ? x.length : y.length;
|
|
447
|
+
// for (let i = 0; i < length; i++) {
|
|
448
|
+
// if (x[i]! < y[i]!) return true;
|
|
449
|
+
// if (x[i]! > y[i]!) return false;
|
|
450
|
+
// }
|
|
451
|
+
// return x.length < y.length;
|
|
452
|
+
// }
|
|
453
|
+
// } else if (type.type === "Array") {
|
|
454
|
+
// const cmp = compareFor(type as EastTypeValue, typeCtx);
|
|
455
|
+
// return (x: any[], y: any[], ctx?: ValueContext) => cmp(x, y, ctx) === -1;
|
|
456
|
+
// } else if (type.type === "Set") {
|
|
457
|
+
// const key_comparer = compareFor(type.value, []);
|
|
458
|
+
// return (x: Set<any>, y: Set<any>) => {
|
|
459
|
+
// // co-iterate the two sets (assume they are sorted)
|
|
460
|
+
// const yiterator = y.keys();
|
|
461
|
+
// for (const xk of x) {
|
|
462
|
+
// const yresult = yiterator.next();
|
|
463
|
+
// if (yresult.done) return false; // if y runs out first, x is greater than y
|
|
464
|
+
// const yk = yresult.value;
|
|
465
|
+
// const c = key_comparer(xk, yk);
|
|
466
|
+
// if (c !== 0) return c === -1;
|
|
467
|
+
// }
|
|
468
|
+
// // x ran out first, check if y has more elements
|
|
469
|
+
// return !yiterator.next().done;
|
|
470
|
+
// }
|
|
471
|
+
// } else if (type.type === "Dict") {
|
|
472
|
+
// const cmp = compareFor(type as EastTypeValue, typeCtx);
|
|
473
|
+
// return (x: Map<any, any>, y: Map<any, any>, ctx?: ValueContext) => cmp(x, y, ctx) === -1;
|
|
474
|
+
// } else if (type.type === "Struct") {
|
|
475
|
+
// const field_comparers: [string, (x: any, y: any, ctx?: ValueContext) => boolean][] = [];
|
|
476
|
+
// const ret = (x: Record<string, any>, y: Record<string, any>, ctx?: ValueContext) => {
|
|
477
|
+
// for (const [k, comparer] of field_comparers) {
|
|
478
|
+
// if (comparer(x[k], y[k], ctx)) return true;
|
|
479
|
+
// if (comparer(y[k], x[k], ctx)) return false;
|
|
480
|
+
// }
|
|
481
|
+
// return false;
|
|
482
|
+
// };
|
|
483
|
+
// typeCtx.push(ret);
|
|
484
|
+
// for (const field of type.value) {
|
|
485
|
+
// field_comparers.push([field.name, lessFor(field.type, typeCtx)] as const);
|
|
486
|
+
// }
|
|
487
|
+
// typeCtx.pop();
|
|
488
|
+
// return ret;
|
|
489
|
+
// } else if (type.type === "Variant") {
|
|
490
|
+
// const case_comparers: Record<string, (x: any, y: any, ctx?: ValueContext) => boolean> = {};
|
|
491
|
+
// const ret = (x: variant, y: variant, ctx?: ValueContext) => {
|
|
492
|
+
// if (x.type < y.type) return true;
|
|
493
|
+
// if (x.type > y.type) return false;
|
|
494
|
+
// return case_comparers[x.type]!(x.value, y.value, ctx);
|
|
495
|
+
// };
|
|
496
|
+
// typeCtx.push(ret);
|
|
497
|
+
// for (const { name, type: caseType } of type.value) {
|
|
498
|
+
// case_comparers[name] = lessFor(caseType, typeCtx);
|
|
499
|
+
// }
|
|
500
|
+
// typeCtx.pop();
|
|
501
|
+
// return ret;
|
|
502
|
+
// } else if (type.type === "Recursive") {
|
|
503
|
+
// const ret = typeCtx[typeCtx.length - Number(type.value)];
|
|
504
|
+
// if (ret === undefined) {
|
|
505
|
+
// throw new Error(`Internal error: Recursive type context not found`);
|
|
506
|
+
// }
|
|
507
|
+
// return ret;
|
|
508
|
+
// } else if (type.type === "Function") {
|
|
509
|
+
// throw new Error(`Attempted to compare values of type .Function`);
|
|
510
|
+
// } else {
|
|
511
|
+
// throw new Error(`Unhandled type ${(type satisfies never as EastTypeValue).type}`);
|
|
512
|
+
// }
|
|
513
|
+
}
|
|
514
|
+
export function lessEqualFor(type, typeCtx = []) {
|
|
515
|
+
const cmp = compareFor(type, typeCtx);
|
|
516
|
+
return (x, y, ctx) => cmp(x, y, ctx) !== 1;
|
|
517
|
+
// // Convert EastType to EastTypeValue if necessary
|
|
518
|
+
// if (!isVariant(type)) {
|
|
519
|
+
// type = toEastTypeValue(type);
|
|
520
|
+
// }
|
|
521
|
+
// if (type.type === "Never") {
|
|
522
|
+
// return (_x: unknown, _y: unknown) => { throw new Error(`Attempted to compare values of type .Never`)};
|
|
523
|
+
// } else if (type.type === "Null") {
|
|
524
|
+
// return (_x: null, _y: null) => true;
|
|
525
|
+
// } else if (type.type === "Boolean") {
|
|
526
|
+
// return (x: boolean, y: boolean) => x <= y;
|
|
527
|
+
// } else if (type.type === "Integer") {
|
|
528
|
+
// return (x: bigint, y: bigint) => x <= y;
|
|
529
|
+
// } else if (type.type === "Float") {
|
|
530
|
+
// return (x: number, y: number) => Number.isNaN(y) ? true : x <= y;
|
|
531
|
+
// } else if (type.type === "String") {
|
|
532
|
+
// return (x: string, y: string) => x <= y;
|
|
533
|
+
// } else if (type.type === "DateTime") {
|
|
534
|
+
// return (x: Date, y: Date) => x.valueOf() <= y.valueOf();
|
|
535
|
+
// } else if (type.type === "Blob") {
|
|
536
|
+
// return (x: Uint8Array, y: Uint8Array) => {
|
|
537
|
+
// const length = x.length < y.length ? x.length : y.length;
|
|
538
|
+
// for (let i = 0; i < length; i++) {
|
|
539
|
+
// if (x[i]! < y[i]!) return true;
|
|
540
|
+
// if (x[i]! > y[i]!) return false;
|
|
541
|
+
// }
|
|
542
|
+
// return x.length <= y.length;
|
|
543
|
+
// }
|
|
544
|
+
// } else if (type.type === "Array") {
|
|
545
|
+
// const cmp = compareFor(type as EastTypeValue, typeCtx);
|
|
546
|
+
// return (x: any[], y: any[], ctx?: ValueContext) => cmp(x, y, ctx) <= 0;
|
|
547
|
+
// } else if (type.type === "Set") {
|
|
548
|
+
// const key_comparer = compareFor(type.value, []);
|
|
549
|
+
// return (x: Set<any>, y: Set<any>) => {
|
|
550
|
+
// // co-iterate the two sets (assume they are sorted)
|
|
551
|
+
// const yiterator = y.keys();
|
|
552
|
+
// for (const xk of x) {
|
|
553
|
+
// const yresult = yiterator.next();
|
|
554
|
+
// if (yresult.done) return false; // if y runs out first, x is greater than y
|
|
555
|
+
// const yk = yresult.value;
|
|
556
|
+
// const c = key_comparer(xk, yk);
|
|
557
|
+
// if (c !== 0) return c === -1;
|
|
558
|
+
// }
|
|
559
|
+
// // x ran out first, x <= y if y has same size or more elements
|
|
560
|
+
// return true;
|
|
561
|
+
// }
|
|
562
|
+
// } else if (type.type === "Dict") {
|
|
563
|
+
// const cmp = compareFor(type as EastTypeValue, typeCtx);
|
|
564
|
+
// return (x: Map<any, any>, y: Map<any, any>, ctx?: ValueContext) => cmp(x, y, ctx) <= 0;
|
|
565
|
+
// } else if (type.type === "Struct") {
|
|
566
|
+
// const field_comparers: [string, (x: any, y: any, ctx?: ValueContext) => boolean][] = [];
|
|
567
|
+
// const ret = (x: Record<string, any>, y: Record<string, any>, ctx?: ValueContext) => {
|
|
568
|
+
// for (const [k, comparer] of field_comparers) {
|
|
569
|
+
// if (comparer(x[k], y[k], ctx)) return true;
|
|
570
|
+
// if (comparer(y[k], x[k], ctx)) return false;
|
|
571
|
+
// }
|
|
572
|
+
// return true;
|
|
573
|
+
// };
|
|
574
|
+
// typeCtx.push(ret);
|
|
575
|
+
// for (const field of type.value) {
|
|
576
|
+
// field_comparers.push([field.name, lessFor(field.type, typeCtx)] as const);
|
|
577
|
+
// }
|
|
578
|
+
// typeCtx.pop();
|
|
579
|
+
// return ret;
|
|
580
|
+
// } else if (type.type === "Variant") {
|
|
581
|
+
// const case_comparers: Record<string, (x: any, y: any, ctx?: ValueContext) => boolean> = {};
|
|
582
|
+
// const ret = (x: variant, y: variant, ctx?: ValueContext) => {
|
|
583
|
+
// if (x.type < y.type) return true;
|
|
584
|
+
// if (x.type > y.type) return false;
|
|
585
|
+
// return case_comparers[x.type]!(x.value, y.value, ctx);
|
|
586
|
+
// };
|
|
587
|
+
// typeCtx.push(ret);
|
|
588
|
+
// for (const { name, type: caseType } of type.value) {
|
|
589
|
+
// case_comparers[name] = lessEqualFor(caseType, typeCtx);
|
|
590
|
+
// }
|
|
591
|
+
// typeCtx.pop();
|
|
592
|
+
// return ret;
|
|
593
|
+
// } else if (type.type === "Recursive") {
|
|
594
|
+
// const ret = typeCtx[typeCtx.length - Number(type.value)];
|
|
595
|
+
// if (ret === undefined) {
|
|
596
|
+
// throw new Error(`Internal error: Recursive type context not found`);
|
|
597
|
+
// }
|
|
598
|
+
// return ret;
|
|
599
|
+
// } else if (type.type === "Function") {
|
|
600
|
+
// throw new Error(`Attempted to compare values of type .Function`);
|
|
601
|
+
// } else {
|
|
602
|
+
// throw new Error(`Unhandled type ${(type satisfies never as EastTypeValue).type}`);
|
|
603
|
+
// }
|
|
604
|
+
}
|
|
605
|
+
export function greaterEqualFor(type, typeCtx = []) {
|
|
606
|
+
const cmp = compareFor(type, typeCtx);
|
|
607
|
+
return (x, y, ctx) => cmp(x, y, ctx) !== -1;
|
|
608
|
+
// // Convert EastType to EastTypeValue if necessary
|
|
609
|
+
// if (!isVariant(type)) {
|
|
610
|
+
// type = toEastTypeValue(type);
|
|
611
|
+
// }
|
|
612
|
+
// if (type.type === "Never") {
|
|
613
|
+
// return (_x: unknown, _y: unknown) => { throw new Error(`Attempted to compare values of type .Never`)};
|
|
614
|
+
// } else if (type.type === "Null") {
|
|
615
|
+
// return (_x: null, _y: null) => true;
|
|
616
|
+
// } else if (type.type === "Boolean") {
|
|
617
|
+
// return (x: boolean, y: boolean) => x >= y;
|
|
618
|
+
// } else if (type.type === "Integer") {
|
|
619
|
+
// return (x: bigint, y: bigint) => x >= y;
|
|
620
|
+
// } else if (type.type === "Float") {
|
|
621
|
+
// return (x: number, y: number) => Number.isNaN(x) ? true : x >= y;
|
|
622
|
+
// } else if (type.type === "String") {
|
|
623
|
+
// return (x: string, y: string) => x >= y;
|
|
624
|
+
// } else if (type.type === "DateTime") {
|
|
625
|
+
// return (x: Date, y: Date) => x.valueOf() >= y.valueOf();
|
|
626
|
+
// } else if (type.type === "Blob") {
|
|
627
|
+
// return (x: Uint8Array, y: Uint8Array) => {
|
|
628
|
+
// const length = x.length < y.length ? x.length : y.length;
|
|
629
|
+
// for (let i = 0; i < length; i++) {
|
|
630
|
+
// if (x[i]! < y[i]!) return false;
|
|
631
|
+
// if (x[i]! > y[i]!) return true;
|
|
632
|
+
// }
|
|
633
|
+
// return x.length >= y.length;
|
|
634
|
+
// }
|
|
635
|
+
// } else if (type.type === "Array") {
|
|
636
|
+
// const cmp = compareFor(type as EastTypeValue, typeCtx);
|
|
637
|
+
// return (x: any[], y: any[], ctx?: ValueContext) => cmp(x, y, ctx) >= 0;
|
|
638
|
+
// } else if (type.type === "Set") {
|
|
639
|
+
// const key_comparer = compareFor(type.value, []);
|
|
640
|
+
// return (x: Set<any>, y: Set<any>) => {
|
|
641
|
+
// // co-iterate the two sets (assume they are sorted)
|
|
642
|
+
// const yiterator = y.keys();
|
|
643
|
+
// for (const xk of x) {
|
|
644
|
+
// const yresult = yiterator.next();
|
|
645
|
+
// if (yresult.done) return true; // if y is a prefix of x, x is greater than y
|
|
646
|
+
// const yk = yresult.value;
|
|
647
|
+
// const c = key_comparer(xk, yk);
|
|
648
|
+
// if (c !== 0) return c === 1;
|
|
649
|
+
// }
|
|
650
|
+
// // we know x.size >= y.size here
|
|
651
|
+
// return true;
|
|
652
|
+
// }
|
|
653
|
+
// } else if (type.type === "Dict") {
|
|
654
|
+
// const cmp = compareFor(type as EastTypeValue, typeCtx);
|
|
655
|
+
// return (x: Map<any, any>, y: Map<any, any>, ctx?: ValueContext) => cmp(x, y, ctx) >= 0;
|
|
656
|
+
// } else if (type.type === "Struct") {
|
|
657
|
+
// const field_comparers: [string, (x: any, y: any, ctx?: ValueContext) => boolean][] = [];
|
|
658
|
+
// const ret = (x: Record<string, any>, y: Record<string, any>, ctx?: ValueContext) => {
|
|
659
|
+
// for (const [k, comparer] of field_comparers) {
|
|
660
|
+
// if (comparer(x[k], y[k], ctx)) return true;
|
|
661
|
+
// if (comparer(y[k], x[k], ctx)) return false;
|
|
662
|
+
// }
|
|
663
|
+
// return true;
|
|
664
|
+
// };
|
|
665
|
+
// typeCtx.push(ret);
|
|
666
|
+
// for (const field of type.value) {
|
|
667
|
+
// field_comparers.push([field.name, greaterFor(field.type, typeCtx)] as const);
|
|
668
|
+
// }
|
|
669
|
+
// typeCtx.pop();
|
|
670
|
+
// return ret;
|
|
671
|
+
// } else if (type.type === "Variant") {
|
|
672
|
+
// const case_comparers: Record<string, (x: any, y: any, ctx?: ValueContext) => boolean> = {};
|
|
673
|
+
// const ret = (x: variant, y: variant, ctx?: ValueContext) => {
|
|
674
|
+
// if (x.type < y.type) return false;
|
|
675
|
+
// if (x.type > y.type) return true;
|
|
676
|
+
// return case_comparers[x.type]!(x.value, y.value, ctx);
|
|
677
|
+
// };
|
|
678
|
+
// typeCtx.push(ret);
|
|
679
|
+
// for (const { name, type: caseType } of type.value) {
|
|
680
|
+
// case_comparers[name] = greaterEqualFor(caseType, typeCtx);
|
|
681
|
+
// }
|
|
682
|
+
// typeCtx.pop();
|
|
683
|
+
// return ret;
|
|
684
|
+
// } else if (type.type === "Recursive") {
|
|
685
|
+
// const ret = typeCtx[typeCtx.length - Number(type.value)];
|
|
686
|
+
// if (ret === undefined) {
|
|
687
|
+
// throw new Error(`Internal error: Recursive type context not found`);
|
|
688
|
+
// }
|
|
689
|
+
// return ret;
|
|
690
|
+
// } else if (type.type === "Function") {
|
|
691
|
+
// throw new Error(`Attempted to compare values of type .Function`);
|
|
692
|
+
// } else {
|
|
693
|
+
// throw new Error(`Unhandled type ${(type satisfies never as EastTypeValue).type}`);
|
|
694
|
+
// }
|
|
695
|
+
}
|
|
696
|
+
export function greaterFor(type, typeCtx = []) {
|
|
697
|
+
const cmp = compareFor(type, typeCtx);
|
|
698
|
+
return (x, y, ctx) => cmp(x, y, ctx) === 1;
|
|
699
|
+
// // Convert EastType to EastTypeValue if necessary
|
|
700
|
+
// if (!isVariant(type)) {
|
|
701
|
+
// type = toEastTypeValue(type);
|
|
702
|
+
// }
|
|
703
|
+
// if (type.type === "Never") {
|
|
704
|
+
// return (_x: unknown, _y: unknown) => { throw new Error(`Attempted to compare values of type .Never`)};
|
|
705
|
+
// } else if (type.type === "Null") {
|
|
706
|
+
// return (_x: null, _y: null) => false;
|
|
707
|
+
// } else if (type.type === "Boolean") {
|
|
708
|
+
// return (x: boolean, y: boolean) => x > y;
|
|
709
|
+
// } else if (type.type === "Integer") {
|
|
710
|
+
// return (x: bigint, y: bigint) => x > y;
|
|
711
|
+
// } else if (type.type === "Float") {
|
|
712
|
+
// return (x: number, y: number) => Number.isNaN(x) ? !Number.isNaN(y) : x > y;
|
|
713
|
+
// } else if (type.type === "String") {
|
|
714
|
+
// return (x: string, y: string) => x > y;
|
|
715
|
+
// } else if (type.type === "DateTime") {
|
|
716
|
+
// return (x: Date, y: Date) => x.valueOf() > y.valueOf();
|
|
717
|
+
// } else if (type.type === "Blob") {
|
|
718
|
+
// return (x: Uint8Array, y: Uint8Array) => {
|
|
719
|
+
// const length = x.length < y.length ? x.length : y.length;
|
|
720
|
+
// for (let i = 0; i < length; i++) {
|
|
721
|
+
// if (x[i]! < y[i]!) return false;
|
|
722
|
+
// if (x[i]! > y[i]!) return true;
|
|
723
|
+
// }
|
|
724
|
+
// return x.length > y.length;
|
|
725
|
+
// }
|
|
726
|
+
// } else if (type.type === "Array") {
|
|
727
|
+
// const cmp = compareFor(type as EastTypeValue, typeCtx);
|
|
728
|
+
// return (x: any[], y: any[], ctx?: ValueContext) => cmp(x, y, ctx) === 1;
|
|
729
|
+
// } else if (type.type === "Set") {
|
|
730
|
+
// const key_comparer = compareFor(type.value, []);
|
|
731
|
+
// return (x: Set<any>, y: Set<any>) => {
|
|
732
|
+
// // co-iterate the two sets (assume they are sorted)
|
|
733
|
+
// const yiterator = y.keys();
|
|
734
|
+
// for (const xk of x) {
|
|
735
|
+
// const yresult = yiterator.next();
|
|
736
|
+
// if (yresult.done) return true; // if y is a prefix of x, x is greater than y
|
|
737
|
+
// const yk = yresult.value;
|
|
738
|
+
// const c = key_comparer(xk, yk);
|
|
739
|
+
// if (c !== 0) return c === 1;
|
|
740
|
+
// }
|
|
741
|
+
// // we know x.size >= y.size here
|
|
742
|
+
// return x.size > y.size;
|
|
743
|
+
// }
|
|
744
|
+
// } else if (type.type === "Dict") {
|
|
745
|
+
// const cmp = compareFor(type as EastTypeValue, typeCtx);
|
|
746
|
+
// return (x: Map<any, any>, y: Map<any, any>, ctx?: ValueContext) => cmp(x, y, ctx) === 1;
|
|
747
|
+
// } else if (type.type === "Struct") {
|
|
748
|
+
// const field_comparers: [string, (x: any, y: any, ctx?: ValueContext) => boolean][] = [];
|
|
749
|
+
// const ret = (x: Record<string, any>, y: Record<string, any>, ctx?: ValueContext) => {
|
|
750
|
+
// for (const [k, comparer] of field_comparers) {
|
|
751
|
+
// if (comparer(x[k], y[k], ctx)) return true;
|
|
752
|
+
// if (comparer(y[k], x[k], ctx)) return false;
|
|
753
|
+
// }
|
|
754
|
+
// return false;
|
|
755
|
+
// };
|
|
756
|
+
// typeCtx.push(ret);
|
|
757
|
+
// for (const field of type.value) {
|
|
758
|
+
// field_comparers.push([field.name, greaterFor(field.type, typeCtx)] as const);
|
|
759
|
+
// }
|
|
760
|
+
// typeCtx.pop();
|
|
761
|
+
// return ret;
|
|
762
|
+
// } else if (type.type === "Variant") {
|
|
763
|
+
// const case_comparers: Record<string, (x: any, y: any, ctx?: ValueContext) => boolean> = {};
|
|
764
|
+
// const ret = (x: variant, y: variant, ctx?: ValueContext) => {
|
|
765
|
+
// if (x.type < y.type) return false;
|
|
766
|
+
// if (x.type > y.type) return true;
|
|
767
|
+
// return case_comparers[x.type]!(x.value, y.value, ctx);
|
|
768
|
+
// };
|
|
769
|
+
// typeCtx.push(ret);
|
|
770
|
+
// for (const { name, type: caseType } of type.value) {
|
|
771
|
+
// case_comparers[name] = greaterFor(caseType, typeCtx);
|
|
772
|
+
// }
|
|
773
|
+
// typeCtx.pop();
|
|
774
|
+
// return ret;
|
|
775
|
+
// } else if (type.type === "Recursive") {
|
|
776
|
+
// const ret = typeCtx[typeCtx.length - Number(type.value)];
|
|
777
|
+
// if (ret === undefined) {
|
|
778
|
+
// throw new Error(`Internal error: Recursive type context not found`);
|
|
779
|
+
// }
|
|
780
|
+
// return ret;
|
|
781
|
+
// } else if (type.type === "Function") {
|
|
782
|
+
// throw new Error(`Attempted to compare values of type .Function`);
|
|
783
|
+
// } else {
|
|
784
|
+
// throw new Error(`Unhandled type ${(type satisfies never as EastTypeValue).type}`);
|
|
785
|
+
// }
|
|
786
|
+
}
|
|
787
|
+
export function compareFor(type, typeCtx = []) {
|
|
788
|
+
// Convert EastType to EastTypeValue if necessary
|
|
789
|
+
if (!isVariant(type)) {
|
|
790
|
+
type = toEastTypeValue(type);
|
|
791
|
+
}
|
|
792
|
+
if (type.type === "Never") {
|
|
793
|
+
return (_x, _y, _ctx) => { throw new Error(`Attempted to compare values of type .Never`); };
|
|
794
|
+
}
|
|
795
|
+
else if (type.type === "Null") {
|
|
796
|
+
return (_x, _y, _ctx) => 0;
|
|
797
|
+
}
|
|
798
|
+
else if (type.type === "Boolean") {
|
|
799
|
+
return (x, y, _ctx) => x ? (y ? 0 : 1) : (y ? -1 : 0);
|
|
800
|
+
}
|
|
801
|
+
else if (type.type === "Integer") {
|
|
802
|
+
return (x, y, _ctx) => x < y ? -1 : (x > y ? 1 : 0);
|
|
803
|
+
}
|
|
804
|
+
else if (type.type === "Float") {
|
|
805
|
+
return (x, y, _ctx) => {
|
|
806
|
+
if (Number.isNaN(x))
|
|
807
|
+
return Number.isNaN(y) ? 0 : 1;
|
|
808
|
+
if (Number.isNaN(y))
|
|
809
|
+
return -1;
|
|
810
|
+
if (Object.is(x, -0) && Object.is(y, 0))
|
|
811
|
+
return -1;
|
|
812
|
+
if (Object.is(x, 0) && Object.is(y, -0))
|
|
813
|
+
return 1;
|
|
814
|
+
return x < y ? -1 : (x > y ? 1 : 0);
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
else if (type.type === "String") {
|
|
818
|
+
return (x, y, _ctx) => x < y ? -1 : (x > y ? 1 : 0);
|
|
819
|
+
}
|
|
820
|
+
else if (type.type === "DateTime") {
|
|
821
|
+
return (x, y, _ctx) => x.valueOf() < y.valueOf() ? -1 : (x.valueOf() > y.valueOf() ? 1 : 0);
|
|
822
|
+
}
|
|
823
|
+
else if (type.type === "Blob") {
|
|
824
|
+
return (x, y, _ctx) => {
|
|
825
|
+
const length = x.length < y.length ? x.length : y.length;
|
|
826
|
+
for (let i = 0; i < length; i++) {
|
|
827
|
+
if (x[i] < y[i])
|
|
828
|
+
return -1;
|
|
829
|
+
if (x[i] > y[i])
|
|
830
|
+
return 1;
|
|
831
|
+
}
|
|
832
|
+
return x.length < y.length ? -1 : (x.length > y.length ? 1 : 0);
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
else if (type.type === "Ref") {
|
|
836
|
+
let value_comparer;
|
|
837
|
+
const ret = (x, y, ctx) => {
|
|
838
|
+
// Fast path
|
|
839
|
+
if (Object.is(x, y))
|
|
840
|
+
return 0;
|
|
841
|
+
// Create context if needed (top-level call)
|
|
842
|
+
if (!ctx) {
|
|
843
|
+
ctx = new Map();
|
|
844
|
+
}
|
|
845
|
+
// Check if we've visited this pair
|
|
846
|
+
const xSet = ctx.get(x);
|
|
847
|
+
if (xSet?.has(y)) {
|
|
848
|
+
return 0; // Cycle - we're re-encountering this pair
|
|
849
|
+
}
|
|
850
|
+
// Mark as visited
|
|
851
|
+
let visitedSet = ctx.get(x);
|
|
852
|
+
if (!visitedSet) {
|
|
853
|
+
visitedSet = new Set();
|
|
854
|
+
ctx.set(x, visitedSet);
|
|
855
|
+
}
|
|
856
|
+
visitedSet.add(y);
|
|
857
|
+
// Now do the actual comparison
|
|
858
|
+
return value_comparer(x.value, y.value, ctx);
|
|
859
|
+
};
|
|
860
|
+
typeCtx.push(ret);
|
|
861
|
+
value_comparer = compareFor(type.value, typeCtx);
|
|
862
|
+
typeCtx.pop();
|
|
863
|
+
return ret;
|
|
864
|
+
}
|
|
865
|
+
else if (type.type === "Array") {
|
|
866
|
+
let value_comparer;
|
|
867
|
+
const ret = (x, y, ctx) => {
|
|
868
|
+
// Fast path
|
|
869
|
+
if (Object.is(x, y))
|
|
870
|
+
return 0;
|
|
871
|
+
// Create context if needed (top-level call)
|
|
872
|
+
if (!ctx) {
|
|
873
|
+
ctx = new Map();
|
|
874
|
+
}
|
|
875
|
+
// Check if we've visited this pair
|
|
876
|
+
const xSet = ctx.get(x);
|
|
877
|
+
if (xSet?.has(y)) {
|
|
878
|
+
return 0; // Cycle - we're re-encountering this pair
|
|
879
|
+
}
|
|
880
|
+
// Mark as visited
|
|
881
|
+
let visitedSet = ctx.get(x);
|
|
882
|
+
if (!visitedSet) {
|
|
883
|
+
visitedSet = new Set();
|
|
884
|
+
ctx.set(x, visitedSet);
|
|
885
|
+
}
|
|
886
|
+
visitedSet.add(y);
|
|
887
|
+
// Now do the actual comparison
|
|
888
|
+
const length = x.length < y.length ? x.length : y.length;
|
|
889
|
+
for (let i = 0; i < length; i++) {
|
|
890
|
+
const c = value_comparer(x[i], y[i], ctx);
|
|
891
|
+
if (c !== 0)
|
|
892
|
+
return c;
|
|
893
|
+
}
|
|
894
|
+
return x.length > y.length ? 1 : x.length < y.length ? -1 : 0;
|
|
895
|
+
};
|
|
896
|
+
typeCtx.push(ret);
|
|
897
|
+
value_comparer = compareFor(type.value, typeCtx);
|
|
898
|
+
typeCtx.pop();
|
|
899
|
+
return ret;
|
|
900
|
+
}
|
|
901
|
+
else if (type.type === "Set") {
|
|
902
|
+
// Set keys cannot contain mutable containers, so no cycles possible
|
|
903
|
+
const key_comparer = compareFor(type.value, typeCtx);
|
|
904
|
+
return (x, y, _ctx) => {
|
|
905
|
+
// Fast path
|
|
906
|
+
if (Object.is(x, y))
|
|
907
|
+
return 0;
|
|
908
|
+
// co-iterate the two sets (assume they are sorted)
|
|
909
|
+
const yiterator = y.keys();
|
|
910
|
+
for (const xk of x) {
|
|
911
|
+
const yresult = yiterator.next();
|
|
912
|
+
if (yresult.done)
|
|
913
|
+
return 1; // if y runs out first, x is greater than y
|
|
914
|
+
const yk = yresult.value;
|
|
915
|
+
const c = key_comparer(xk, yk); // keys are standalone, no ctx needed
|
|
916
|
+
if (c !== 0)
|
|
917
|
+
return c;
|
|
918
|
+
}
|
|
919
|
+
// x ran out first, compare sizes: if y has more elements, x < y
|
|
920
|
+
return yiterator.next().done ? 0 : -1;
|
|
921
|
+
};
|
|
922
|
+
}
|
|
923
|
+
else if (type.type === "Dict") {
|
|
924
|
+
// Dict keys cannot contain mutable containers, but values can
|
|
925
|
+
const key_comparer = compareFor(type.value.key, typeCtx);
|
|
926
|
+
let value_comparer;
|
|
927
|
+
const ret = (x, y, ctx) => {
|
|
928
|
+
// Fast path
|
|
929
|
+
if (Object.is(x, y))
|
|
930
|
+
return 0;
|
|
931
|
+
// Create context if needed (top-level call)
|
|
932
|
+
if (!ctx) {
|
|
933
|
+
ctx = new Map();
|
|
934
|
+
}
|
|
935
|
+
// Check if we've visited this pair
|
|
936
|
+
const xSet = ctx.get(x);
|
|
937
|
+
if (xSet?.has(y)) {
|
|
938
|
+
return 0; // Cycle - we're re-encountering this pair
|
|
939
|
+
}
|
|
940
|
+
// Mark as visited
|
|
941
|
+
let visitedSet = ctx.get(x);
|
|
942
|
+
if (!visitedSet) {
|
|
943
|
+
visitedSet = new Set();
|
|
944
|
+
ctx.set(x, visitedSet);
|
|
945
|
+
}
|
|
946
|
+
visitedSet.add(y);
|
|
947
|
+
// Now do the actual comparison
|
|
948
|
+
// co-iterate the two maps (assume they are sorted by key)
|
|
949
|
+
const yiterator = y.entries();
|
|
950
|
+
for (const [xk, xv] of x) {
|
|
951
|
+
const yresult = yiterator.next();
|
|
952
|
+
if (yresult.done)
|
|
953
|
+
return 1; // if y is a prefix of x, x is greater than y
|
|
954
|
+
const [yk, yv] = yresult.value;
|
|
955
|
+
const kc = key_comparer(xk, yk); // keys are standalone, no ctx needed
|
|
956
|
+
if (kc !== 0)
|
|
957
|
+
return kc;
|
|
958
|
+
const vc = value_comparer(xv, yv, ctx); // values can have cycles
|
|
959
|
+
if (vc !== 0)
|
|
960
|
+
return vc;
|
|
961
|
+
}
|
|
962
|
+
// x ran out first, compare sizes: if y has more elements, x < y
|
|
963
|
+
return yiterator.next().done ? 0 : -1;
|
|
964
|
+
};
|
|
965
|
+
typeCtx.push(ret);
|
|
966
|
+
value_comparer = compareFor(type.value.value, typeCtx);
|
|
967
|
+
typeCtx.pop();
|
|
968
|
+
return ret;
|
|
969
|
+
}
|
|
970
|
+
else if (type.type === "Struct") {
|
|
971
|
+
const field_comparers = [];
|
|
972
|
+
const ret = (x, y, ctx) => {
|
|
973
|
+
for (const [k, comparer] of field_comparers) {
|
|
974
|
+
const c = comparer(x[k], y[k], ctx);
|
|
975
|
+
if (c !== 0)
|
|
976
|
+
return c;
|
|
977
|
+
}
|
|
978
|
+
return 0;
|
|
979
|
+
};
|
|
980
|
+
typeCtx.push(ret);
|
|
981
|
+
for (const field of type.value) {
|
|
982
|
+
field_comparers.push([field.name, compareFor(field.type, typeCtx)]);
|
|
983
|
+
}
|
|
984
|
+
typeCtx.pop();
|
|
985
|
+
return ret;
|
|
986
|
+
}
|
|
987
|
+
else if (type.type === "Variant") {
|
|
988
|
+
const case_comparers = {};
|
|
989
|
+
const ret = (x, y, ctx) => {
|
|
990
|
+
if (x.type < y.type)
|
|
991
|
+
return -1;
|
|
992
|
+
if (x.type > y.type)
|
|
993
|
+
return 1;
|
|
994
|
+
return case_comparers[x.type](x.value, y.value, ctx);
|
|
995
|
+
};
|
|
996
|
+
typeCtx.push(ret);
|
|
997
|
+
for (const { name, type: caseType } of type.value) {
|
|
998
|
+
case_comparers[name] = compareFor(caseType, typeCtx);
|
|
999
|
+
}
|
|
1000
|
+
typeCtx.pop();
|
|
1001
|
+
return ret;
|
|
1002
|
+
}
|
|
1003
|
+
else if (type.type === "Recursive") {
|
|
1004
|
+
const ret = typeCtx[typeCtx.length - Number(type.value)];
|
|
1005
|
+
if (ret === undefined) {
|
|
1006
|
+
throw new Error(`Internal error: Recursive type context not found`);
|
|
1007
|
+
}
|
|
1008
|
+
return ret;
|
|
1009
|
+
}
|
|
1010
|
+
else if (type.type === "Function") {
|
|
1011
|
+
throw new Error(`Attempted to compare values of type .Function`);
|
|
1012
|
+
}
|
|
1013
|
+
else {
|
|
1014
|
+
throw new Error(`Unhandled type ${type.type}`);
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
//# sourceMappingURL=comparison.js.map
|