math-expression-compiler 4.3.1 → 4.4.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/README.md +8 -17
- package/package.json +7 -7
- package/dist/index.d.ts +0 -813
- package/dist/index.js +0 -2246
package/dist/index.js
DELETED
|
@@ -1,2246 +0,0 @@
|
|
|
1
|
-
import { exhaustiveGuard } from "@esposter/shared";
|
|
2
|
-
import { err, ok } from "neverthrow";
|
|
3
|
-
//#region src/models/function/MathExpressionFunctionName.ts
|
|
4
|
-
let MathExpressionFunctionName = /* @__PURE__ */ function(MathExpressionFunctionName) {
|
|
5
|
-
MathExpressionFunctionName["CTranspose"] = "ctranspose";
|
|
6
|
-
MathExpressionFunctionName["Factorial"] = "factorial";
|
|
7
|
-
MathExpressionFunctionName["UnaryMinus"] = "unaryMinus";
|
|
8
|
-
MathExpressionFunctionName["UnaryPlus"] = "unaryPlus";
|
|
9
|
-
return MathExpressionFunctionName;
|
|
10
|
-
}({});
|
|
11
|
-
//#endregion
|
|
12
|
-
//#region src/models/function/MathExpressionParameterType.ts
|
|
13
|
-
let MathExpressionParameterType = /* @__PURE__ */ function(MathExpressionParameterType) {
|
|
14
|
-
MathExpressionParameterType["Any"] = "any";
|
|
15
|
-
MathExpressionParameterType["List"] = "list";
|
|
16
|
-
MathExpressionParameterType["Number"] = "number";
|
|
17
|
-
return MathExpressionParameterType;
|
|
18
|
-
}({});
|
|
19
|
-
//#endregion
|
|
20
|
-
//#region src/models/parser/MathExpressionGrammarRule.ts
|
|
21
|
-
let MathExpressionGrammarRule = /* @__PURE__ */ function(MathExpressionGrammarRule) {
|
|
22
|
-
MathExpressionGrammarRule["Assignment"] = "Assignment";
|
|
23
|
-
MathExpressionGrammarRule["Binary"] = "Binary";
|
|
24
|
-
MathExpressionGrammarRule["Conditional"] = "Conditional";
|
|
25
|
-
MathExpressionGrammarRule["DivisionBeforeProduct"] = "DivisionBeforeProduct";
|
|
26
|
-
MathExpressionGrammarRule["ImplicitProduct"] = "ImplicitProduct";
|
|
27
|
-
MathExpressionGrammarRule["LeftHand"] = "LeftHand";
|
|
28
|
-
MathExpressionGrammarRule["Nullish"] = "Nullish";
|
|
29
|
-
MathExpressionGrammarRule["Percentage"] = "Percentage";
|
|
30
|
-
MathExpressionGrammarRule["Power"] = "Power";
|
|
31
|
-
MathExpressionGrammarRule["Symbol"] = "Symbol";
|
|
32
|
-
MathExpressionGrammarRule["Unary"] = "Unary";
|
|
33
|
-
return MathExpressionGrammarRule;
|
|
34
|
-
}({});
|
|
35
|
-
//#endregion
|
|
36
|
-
//#region src/models/parser/MathExpressionTokenType.ts
|
|
37
|
-
let MathExpressionTokenType = /* @__PURE__ */ function(MathExpressionTokenType) {
|
|
38
|
-
MathExpressionTokenType["Delimiter"] = "delimiter";
|
|
39
|
-
MathExpressionTokenType["Null"] = "null";
|
|
40
|
-
MathExpressionTokenType["Number"] = "number";
|
|
41
|
-
MathExpressionTokenType["Symbol"] = "symbol";
|
|
42
|
-
MathExpressionTokenType["Unknown"] = "unknown";
|
|
43
|
-
return MathExpressionTokenType;
|
|
44
|
-
}({});
|
|
45
|
-
//#endregion
|
|
46
|
-
//#region src/models/shared/MathExpressionError.ts
|
|
47
|
-
var MathExpressionError = class extends Error {
|
|
48
|
-
constructor(message) {
|
|
49
|
-
super(message);
|
|
50
|
-
this.name = "MathExpressionError";
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
//#endregion
|
|
54
|
-
//#region src/models/shared/MathExpressionLogicalOperator.ts
|
|
55
|
-
let MathExpressionLogicalOperator = /* @__PURE__ */ function(MathExpressionLogicalOperator) {
|
|
56
|
-
MathExpressionLogicalOperator["And"] = "and";
|
|
57
|
-
MathExpressionLogicalOperator["Nullish"] = "nullish";
|
|
58
|
-
MathExpressionLogicalOperator["Or"] = "or";
|
|
59
|
-
return MathExpressionLogicalOperator;
|
|
60
|
-
}({});
|
|
61
|
-
//#endregion
|
|
62
|
-
//#region src/models/shared/MathExpressionNodeType.ts
|
|
63
|
-
let MathExpressionNodeType = /* @__PURE__ */ function(MathExpressionNodeType) {
|
|
64
|
-
MathExpressionNodeType["Assignment"] = "assignment";
|
|
65
|
-
MathExpressionNodeType["Binary"] = "binary";
|
|
66
|
-
MathExpressionNodeType["Call"] = "call";
|
|
67
|
-
MathExpressionNodeType["Comparison"] = "comparison";
|
|
68
|
-
MathExpressionNodeType["Conditional"] = "conditional";
|
|
69
|
-
MathExpressionNodeType["Group"] = "group";
|
|
70
|
-
MathExpressionNodeType["List"] = "list";
|
|
71
|
-
MathExpressionNodeType["Logical"] = "logical";
|
|
72
|
-
MathExpressionNodeType["Name"] = "name";
|
|
73
|
-
MathExpressionNodeType["Number"] = "number";
|
|
74
|
-
MathExpressionNodeType["Percentage"] = "percentage";
|
|
75
|
-
MathExpressionNodeType["Unary"] = "unary";
|
|
76
|
-
return MathExpressionNodeType;
|
|
77
|
-
}({});
|
|
78
|
-
//#endregion
|
|
79
|
-
//#region src/services/compiler/MathExpressionBitwiseAbsorptionMap.ts
|
|
80
|
-
const MathExpressionBitwiseAbsorptionMap = {
|
|
81
|
-
bitAnd: {
|
|
82
|
-
absorbs: 0,
|
|
83
|
-
result: 0
|
|
84
|
-
},
|
|
85
|
-
bitOr: {
|
|
86
|
-
absorbs: -1,
|
|
87
|
-
result: -1
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
//#endregion
|
|
91
|
-
//#region src/services/compiler/node/compileAssignment.ts
|
|
92
|
-
const compileAssignment = (node, context) => {
|
|
93
|
-
const slot = context.assignedSlots.get(node.name) ?? 0;
|
|
94
|
-
const compiledValue = context.compile(node.value);
|
|
95
|
-
return {
|
|
96
|
-
evaluate: (values, locals) => {
|
|
97
|
-
const value = compiledValue.evaluate(values, locals);
|
|
98
|
-
locals[slot] = value;
|
|
99
|
-
return value;
|
|
100
|
-
},
|
|
101
|
-
isConstant: false
|
|
102
|
-
};
|
|
103
|
-
};
|
|
104
|
-
//#endregion
|
|
105
|
-
//#region src/services/compiler/constants.ts
|
|
106
|
-
const NO_VALUES = [];
|
|
107
|
-
const NO_LOCALS = [];
|
|
108
|
-
const ADDITIVE_NAMES = ["add", "subtract"];
|
|
109
|
-
//#endregion
|
|
110
|
-
//#region src/services/compiler/checkIsPercentageExpression.ts
|
|
111
|
-
const checkIsPercentageExpression = (node) => {
|
|
112
|
-
if (node.type === "percentage") return true;
|
|
113
|
-
if (node.type !== "binary") return false;
|
|
114
|
-
if (!ADDITIVE_NAMES.includes(node.name)) return false;
|
|
115
|
-
return checkIsPercentageExpression(node.left) && checkIsPercentageExpression(node.right);
|
|
116
|
-
};
|
|
117
|
-
//#endregion
|
|
118
|
-
//#region src/services/function/constants.ts
|
|
119
|
-
const MATH_EXPRESSION_RELATIVE_TOLERANCE = 1e-12;
|
|
120
|
-
const MATH_EXPRESSION_ABSOLUTE_TOLERANCE = 1e-15;
|
|
121
|
-
const SQRT_PI = Math.sqrt(Math.PI);
|
|
122
|
-
const BERNOULLI_CLOSED_FORM_INDEX = 54;
|
|
123
|
-
const MAXIMUM_DIGITS = 15;
|
|
124
|
-
const MAXIMUM_STIRLING_WORK = 4e6;
|
|
125
|
-
const MILLER_RABIN_BASES = [
|
|
126
|
-
2n,
|
|
127
|
-
3n,
|
|
128
|
-
5n,
|
|
129
|
-
7n,
|
|
130
|
-
11n,
|
|
131
|
-
13n,
|
|
132
|
-
17n,
|
|
133
|
-
19n,
|
|
134
|
-
23n,
|
|
135
|
-
29n,
|
|
136
|
-
31n,
|
|
137
|
-
37n
|
|
138
|
-
];
|
|
139
|
-
const REFINEMENT_STEPS = 4;
|
|
140
|
-
const LOW_TAIL_COEFFICIENTS = [
|
|
141
|
-
3.43273939e-7,
|
|
142
|
-
-35233877e-13,
|
|
143
|
-
-439150654e-14,
|
|
144
|
-
.00021858087,
|
|
145
|
-
-.00125372503,
|
|
146
|
-
-.00417768164,
|
|
147
|
-
.246640727,
|
|
148
|
-
1.50140941
|
|
149
|
-
];
|
|
150
|
-
const HIGH_TAIL_COEFFICIENTS = [
|
|
151
|
-
.000100950558,
|
|
152
|
-
.00134934322,
|
|
153
|
-
-.00367342844,
|
|
154
|
-
.00573950773,
|
|
155
|
-
-.0076224613,
|
|
156
|
-
.00943887047,
|
|
157
|
-
1.00167406,
|
|
158
|
-
2.83297682
|
|
159
|
-
];
|
|
160
|
-
const OVERFLOW_ARGUMENT = 171.35;
|
|
161
|
-
const LAST_FACTORIAL_ARGUMENT = 171;
|
|
162
|
-
const STIRLING_THRESHOLD = 15;
|
|
163
|
-
const STIRLING_TERMS = [
|
|
164
|
-
1 / 12,
|
|
165
|
-
-1 / 360,
|
|
166
|
-
1 / 1260,
|
|
167
|
-
-1 / 1680,
|
|
168
|
-
1 / 1188,
|
|
169
|
-
-691 / 360360,
|
|
170
|
-
1 / 156
|
|
171
|
-
];
|
|
172
|
-
const EULER_MACLAURIN_COEFFICIENTS = [
|
|
173
|
-
1 / 12,
|
|
174
|
-
-1 / 720,
|
|
175
|
-
1 / 30240,
|
|
176
|
-
-1 / 1209600,
|
|
177
|
-
1 / 47900160,
|
|
178
|
-
-691 / 1307674368e3,
|
|
179
|
-
1 / 74724249600,
|
|
180
|
-
-3617 / 0x25e8dffc150000
|
|
181
|
-
];
|
|
182
|
-
const SUMMATION_LIMIT = 10;
|
|
183
|
-
//#endregion
|
|
184
|
-
//#region src/services/function/checkIsNearlyEqual.ts
|
|
185
|
-
const checkIsNearlyEqual = (left, right) => {
|
|
186
|
-
if (Number.isNaN(left) || Number.isNaN(right)) return false;
|
|
187
|
-
if (!Number.isFinite(left) || !Number.isFinite(right)) return left === right;
|
|
188
|
-
if (left === right) return true;
|
|
189
|
-
const tolerance = Math.max(MATH_EXPRESSION_RELATIVE_TOLERANCE * Math.max(Math.abs(left), Math.abs(right)), MATH_EXPRESSION_ABSOLUTE_TOLERANCE);
|
|
190
|
-
return Math.abs(left - right) <= tolerance;
|
|
191
|
-
};
|
|
192
|
-
//#endregion
|
|
193
|
-
//#region src/services/function/checkIsLarger.ts
|
|
194
|
-
const checkIsLarger = (left, right) => left > right && !checkIsNearlyEqual(left, right);
|
|
195
|
-
//#endregion
|
|
196
|
-
//#region src/services/function/computeModularPower.ts
|
|
197
|
-
const computeModularPower = (base, exponent, modulus) => {
|
|
198
|
-
let result = 1n;
|
|
199
|
-
let square = base % modulus;
|
|
200
|
-
let remaining = exponent;
|
|
201
|
-
while (remaining > 0n) {
|
|
202
|
-
if (remaining % 2n === 1n) result = result * square % modulus;
|
|
203
|
-
square = square * square % modulus;
|
|
204
|
-
remaining /= 2n;
|
|
205
|
-
}
|
|
206
|
-
return result;
|
|
207
|
-
};
|
|
208
|
-
//#endregion
|
|
209
|
-
//#region src/services/function/checkIsMillerRabinPassing.ts
|
|
210
|
-
const checkIsMillerRabinPassing = (candidate, base, oddPart, twos) => {
|
|
211
|
-
const minusOne = candidate - 1n;
|
|
212
|
-
let power = computeModularPower(base, oddPart, candidate);
|
|
213
|
-
if (power === 1n || power === minusOne) return true;
|
|
214
|
-
for (let round = 1; round < twos; round++) {
|
|
215
|
-
power = power * power % candidate;
|
|
216
|
-
if (power === minusOne) return true;
|
|
217
|
-
}
|
|
218
|
-
return false;
|
|
219
|
-
};
|
|
220
|
-
//#endregion
|
|
221
|
-
//#region src/services/function/checkIsPrime.ts
|
|
222
|
-
const checkIsPrime = (value) => {
|
|
223
|
-
if (!Number.isInteger(value) || value < 2 || value > Number.MAX_SAFE_INTEGER) return false;
|
|
224
|
-
const candidate = BigInt(value);
|
|
225
|
-
for (const base of MILLER_RABIN_BASES) {
|
|
226
|
-
if (candidate === base) return true;
|
|
227
|
-
if (candidate % base === 0n) return false;
|
|
228
|
-
}
|
|
229
|
-
let oddPart = candidate - 1n;
|
|
230
|
-
let twos = 0;
|
|
231
|
-
while (oddPart % 2n === 0n) {
|
|
232
|
-
oddPart /= 2n;
|
|
233
|
-
twos++;
|
|
234
|
-
}
|
|
235
|
-
return MILLER_RABIN_BASES.every((base) => checkIsMillerRabinPassing(candidate, base, oddPart, twos));
|
|
236
|
-
};
|
|
237
|
-
//#endregion
|
|
238
|
-
//#region src/services/function/checkIsSmaller.ts
|
|
239
|
-
const checkIsSmaller = (left, right) => left < right && !checkIsNearlyEqual(left, right);
|
|
240
|
-
//#endregion
|
|
241
|
-
//#region src/services/function/computeBellNumber.ts
|
|
242
|
-
const computeBellNumber = (index) => {
|
|
243
|
-
if (!Number.isInteger(index) || index < 0) return null;
|
|
244
|
-
let row = [1];
|
|
245
|
-
for (let step = 1; step <= index; step++) {
|
|
246
|
-
const next = [row.at(-1) ?? 0];
|
|
247
|
-
for (const above of row) next.push((next.at(-1) ?? 0) + above);
|
|
248
|
-
if (next[0] === Number.POSITIVE_INFINITY) return Number.POSITIVE_INFINITY;
|
|
249
|
-
row = next;
|
|
250
|
-
}
|
|
251
|
-
return row[0] ?? NaN;
|
|
252
|
-
};
|
|
253
|
-
//#endregion
|
|
254
|
-
//#region src/services/function/computeBernoulliNumber.ts
|
|
255
|
-
const computeBernoulliNumber = (index) => {
|
|
256
|
-
if (index === 1) return -.5;
|
|
257
|
-
if (index > 1 && index % 2 === 1) return 0;
|
|
258
|
-
if (index >= 54) {
|
|
259
|
-
let product = 1;
|
|
260
|
-
for (let factor = 1; factor <= index && Number.isFinite(product); factor++) product *= factor / (2 * Math.PI);
|
|
261
|
-
return index / 2 % 2 === 1 ? 2 * product : -2 * product;
|
|
262
|
-
}
|
|
263
|
-
const numbers = [1];
|
|
264
|
-
for (let current = 1; current <= index; current++) {
|
|
265
|
-
let sum = 0;
|
|
266
|
-
let binomial = 1;
|
|
267
|
-
for (let previous = 0; previous < current; previous++) {
|
|
268
|
-
sum += binomial * (numbers[previous] ?? 0);
|
|
269
|
-
binomial = binomial * (current + 1 - previous) / (previous + 1);
|
|
270
|
-
}
|
|
271
|
-
numbers.push(-sum / (current + 1));
|
|
272
|
-
}
|
|
273
|
-
return numbers[index] ?? NaN;
|
|
274
|
-
};
|
|
275
|
-
//#endregion
|
|
276
|
-
//#region src/services/function/computeBitwiseAnd.ts
|
|
277
|
-
const computeBitwiseAnd = (left, right) => left & right;
|
|
278
|
-
//#endregion
|
|
279
|
-
//#region src/services/function/computeBitwiseOr.ts
|
|
280
|
-
const computeBitwiseOr = (left, right) => left | right;
|
|
281
|
-
//#endregion
|
|
282
|
-
//#region src/services/function/computeCombinations.ts
|
|
283
|
-
const computeCombinations = (available, chosen) => {
|
|
284
|
-
const smaller = Math.min(chosen, available - chosen);
|
|
285
|
-
let result = 1;
|
|
286
|
-
for (let step = 1; step <= smaller; step++) {
|
|
287
|
-
result = result * (available - smaller + step) / step;
|
|
288
|
-
if (result > Number.MAX_VALUE) return Number.POSITIVE_INFINITY;
|
|
289
|
-
}
|
|
290
|
-
return Math.round(result);
|
|
291
|
-
};
|
|
292
|
-
//#endregion
|
|
293
|
-
//#region src/services/function/computeCatalan.ts
|
|
294
|
-
const computeCatalan = (index) => {
|
|
295
|
-
if (!Number.isInteger(index) || index < 0) return null;
|
|
296
|
-
return Math.round(computeCombinations(2 * index, index) / (index + 1));
|
|
297
|
-
};
|
|
298
|
-
//#endregion
|
|
299
|
-
//#region src/services/function/computeComparison.ts
|
|
300
|
-
const computeComparison = (left, right) => {
|
|
301
|
-
if (checkIsNearlyEqual(left, right)) return 0;
|
|
302
|
-
return left > right ? 1 : -1;
|
|
303
|
-
};
|
|
304
|
-
//#endregion
|
|
305
|
-
//#region src/services/function/computeCompositions.ts
|
|
306
|
-
const computeCompositions = (total, parts) => {
|
|
307
|
-
if (!Number.isInteger(total) || !Number.isInteger(parts) || parts < 1 || parts > total) return null;
|
|
308
|
-
return computeCombinations(total - 1, parts - 1);
|
|
309
|
-
};
|
|
310
|
-
//#endregion
|
|
311
|
-
//#region src/services/function/computeDotProduct.ts
|
|
312
|
-
const computeDotProduct = (left, right) => {
|
|
313
|
-
if (left.length !== right.length) return null;
|
|
314
|
-
return left.reduce((total, value, index) => total + value * (right[index] ?? NaN), 0);
|
|
315
|
-
};
|
|
316
|
-
//#endregion
|
|
317
|
-
//#region src/services/function/computeSum.ts
|
|
318
|
-
const computeSum = (values) => values.length === 0 ? 0 : values.reduce((total, value) => total + value);
|
|
319
|
-
//#endregion
|
|
320
|
-
//#region src/services/function/computeCorrelation.ts
|
|
321
|
-
const computeCorrelation = (left, right) => {
|
|
322
|
-
if (left.length !== right.length) return null;
|
|
323
|
-
const count = left.length;
|
|
324
|
-
const sumLeft = computeSum(left);
|
|
325
|
-
const sumRight = computeSum(right);
|
|
326
|
-
const sumProducts = computeDotProduct(left, right) ?? NaN;
|
|
327
|
-
const sumLeftSquares = computeSum(left.map((value) => value ** 2));
|
|
328
|
-
const sumRightSquares = computeSum(right.map((value) => value ** 2));
|
|
329
|
-
return (count * sumProducts - sumLeft * sumRight) / Math.sqrt((count * sumLeftSquares - sumLeft ** 2) * (count * sumRightSquares - sumRight ** 2));
|
|
330
|
-
};
|
|
331
|
-
//#endregion
|
|
332
|
-
//#region src/services/function/computeDeterminant.ts
|
|
333
|
-
const computeDeterminant = (values) => {
|
|
334
|
-
if (values.length === 0) return 1;
|
|
335
|
-
return values.length === 1 ? values[0] ?? null : null;
|
|
336
|
-
};
|
|
337
|
-
//#endregion
|
|
338
|
-
//#region src/services/function/computePointToLine2D.ts
|
|
339
|
-
const computePointToLine2D = (point, line) => {
|
|
340
|
-
const [x = NaN, y = NaN] = point;
|
|
341
|
-
const [a = NaN, b = NaN, c = NaN] = line;
|
|
342
|
-
return Math.abs(a * x + b * y + c) / Math.hypot(a, b);
|
|
343
|
-
};
|
|
344
|
-
//#endregion
|
|
345
|
-
//#region src/services/function/computePointToLine3D.ts
|
|
346
|
-
const computePointToLine3D = (point, line) => {
|
|
347
|
-
const [x = NaN, y = NaN, z = NaN] = point;
|
|
348
|
-
const [x0 = NaN, y0 = NaN, z0 = NaN, a = NaN, b = NaN, c = NaN] = line;
|
|
349
|
-
const first = (y0 - y) * c - (z0 - z) * b;
|
|
350
|
-
const second = (z0 - z) * a - (x0 - x) * c;
|
|
351
|
-
const third = (x0 - x) * b - (y0 - y) * a;
|
|
352
|
-
return Math.hypot(first, second, third) / Math.hypot(a, b, c);
|
|
353
|
-
};
|
|
354
|
-
//#endregion
|
|
355
|
-
//#region src/services/function/computeDistance.ts
|
|
356
|
-
const computeDistance = (point, other) => {
|
|
357
|
-
if (point.length === 2 && other.length === 3) return computePointToLine2D(point, other);
|
|
358
|
-
if (point.length === 3 && other.length === 6) return computePointToLine3D(point, other);
|
|
359
|
-
if (point.length !== other.length || point.length === 0) return null;
|
|
360
|
-
let total = 0;
|
|
361
|
-
for (const [index, value] of point.entries()) {
|
|
362
|
-
const difference = value - (other[index] ?? NaN);
|
|
363
|
-
total = difference * difference + total;
|
|
364
|
-
}
|
|
365
|
-
return Math.sqrt(total);
|
|
366
|
-
};
|
|
367
|
-
//#endregion
|
|
368
|
-
//#region src/services/function/computeErf.ts
|
|
369
|
-
const SERIES_LIMIT = 3;
|
|
370
|
-
const CONTINUED_FRACTION_DEPTH = 80;
|
|
371
|
-
const computeErf = (value) => {
|
|
372
|
-
if (Number.isNaN(value)) return NaN;
|
|
373
|
-
const magnitude = Math.abs(value);
|
|
374
|
-
const sign = value < 0 ? -1 : 1;
|
|
375
|
-
if (magnitude < SERIES_LIMIT) {
|
|
376
|
-
const squared = magnitude * magnitude;
|
|
377
|
-
let term = magnitude;
|
|
378
|
-
let total = magnitude;
|
|
379
|
-
for (let index = 1; index < 200; index++) {
|
|
380
|
-
term *= 2 * squared / (2 * index + 1);
|
|
381
|
-
total += term;
|
|
382
|
-
if (term < total * 1e-17) break;
|
|
383
|
-
}
|
|
384
|
-
return sign * 2 * Math.exp(-squared) * total / SQRT_PI;
|
|
385
|
-
}
|
|
386
|
-
let fraction = magnitude;
|
|
387
|
-
for (let index = CONTINUED_FRACTION_DEPTH; index >= 1; index--) fraction = magnitude + index / 2 / fraction;
|
|
388
|
-
return sign * (1 - Math.exp(-magnitude * magnitude) / SQRT_PI / fraction);
|
|
389
|
-
};
|
|
390
|
-
//#endregion
|
|
391
|
-
//#region src/services/function/computePolynomial.ts
|
|
392
|
-
const computePolynomial = (leading, coefficients, variable) => {
|
|
393
|
-
let polynomial = leading;
|
|
394
|
-
for (const coefficient of coefficients) polynomial = coefficient + polynomial * variable;
|
|
395
|
-
return polynomial;
|
|
396
|
-
};
|
|
397
|
-
//#endregion
|
|
398
|
-
//#region src/services/function/computeInitialGuess.ts
|
|
399
|
-
const computeInitialGuess = (value) => {
|
|
400
|
-
const weight = -Math.log((1 - value) * (1 + value));
|
|
401
|
-
if (weight < 5) return computePolynomial(2.81022636e-8, LOW_TAIL_COEFFICIENTS, weight - 2.5) * value;
|
|
402
|
-
return computePolynomial(-.000200214257, HIGH_TAIL_COEFFICIENTS, Math.sqrt(weight) - 3) * value;
|
|
403
|
-
};
|
|
404
|
-
//#endregion
|
|
405
|
-
//#region src/services/function/computeErfInverse.ts
|
|
406
|
-
const computeErfInverse = (value) => {
|
|
407
|
-
if (Number.isNaN(value) || value < -1 || value > 1) return NaN;
|
|
408
|
-
if (value === 1) return Number.POSITIVE_INFINITY;
|
|
409
|
-
if (value === -1) return Number.NEGATIVE_INFINITY;
|
|
410
|
-
let estimate = computeInitialGuess(value);
|
|
411
|
-
for (let step = 0; step < 4; step++) {
|
|
412
|
-
const slope = 2 / SQRT_PI * Math.exp(-estimate * estimate);
|
|
413
|
-
estimate -= (computeErf(estimate) - value) / slope;
|
|
414
|
-
}
|
|
415
|
-
return estimate;
|
|
416
|
-
};
|
|
417
|
-
//#endregion
|
|
418
|
-
//#region src/services/function/computeStirlingLogGamma.ts
|
|
419
|
-
const computeStirlingLogGamma = (value) => {
|
|
420
|
-
const inverse = 1 / value;
|
|
421
|
-
const squared = inverse * inverse;
|
|
422
|
-
let power = inverse;
|
|
423
|
-
let series = 0;
|
|
424
|
-
for (const term of STIRLING_TERMS) {
|
|
425
|
-
series += term * power;
|
|
426
|
-
power *= squared;
|
|
427
|
-
}
|
|
428
|
-
return (value - .5) * Math.log(value) - value + .5 * Math.log(2 * Math.PI) + series;
|
|
429
|
-
};
|
|
430
|
-
//#endregion
|
|
431
|
-
//#region src/services/function/computeLogGammaOfPositive.ts
|
|
432
|
-
const computeLogGammaOfPositive = (value) => {
|
|
433
|
-
let shifted = value;
|
|
434
|
-
let product = 1;
|
|
435
|
-
while (shifted < 15) {
|
|
436
|
-
product *= shifted;
|
|
437
|
-
shifted += 1;
|
|
438
|
-
}
|
|
439
|
-
return {
|
|
440
|
-
logGamma: computeStirlingLogGamma(shifted),
|
|
441
|
-
product
|
|
442
|
-
};
|
|
443
|
-
};
|
|
444
|
-
//#endregion
|
|
445
|
-
//#region src/services/function/computeProductOfRange.ts
|
|
446
|
-
const computeProductOfRange = (first, last) => {
|
|
447
|
-
if (last < first) return 1;
|
|
448
|
-
if (last === first) return last;
|
|
449
|
-
const middle = Math.floor((first + last) / 2);
|
|
450
|
-
return computeProductOfRange(first, middle) * computeProductOfRange(middle + 1, last);
|
|
451
|
-
};
|
|
452
|
-
//#endregion
|
|
453
|
-
//#region src/services/function/computeGamma.ts
|
|
454
|
-
const computeGamma = (value) => {
|
|
455
|
-
if (Number.isNaN(value)) return NaN;
|
|
456
|
-
if (Number.isInteger(value)) {
|
|
457
|
-
if (value <= 0 || value > 171) return Number.POSITIVE_INFINITY;
|
|
458
|
-
return computeProductOfRange(1, value - 1);
|
|
459
|
-
}
|
|
460
|
-
if (value < .5) return Math.PI / (Math.sin(Math.PI * value) * computeGamma(1 - value));
|
|
461
|
-
if (value >= 171.35) return Number.POSITIVE_INFINITY;
|
|
462
|
-
const { logGamma, product } = computeLogGammaOfPositive(value);
|
|
463
|
-
return Math.exp(logGamma) / product;
|
|
464
|
-
};
|
|
465
|
-
//#endregion
|
|
466
|
-
//#region src/services/function/computeFactorial.ts
|
|
467
|
-
const computeFactorial = (value) => {
|
|
468
|
-
if (value < 0) return null;
|
|
469
|
-
return computeGamma(value + 1);
|
|
470
|
-
};
|
|
471
|
-
//#endregion
|
|
472
|
-
//#region src/services/function/computeHypotenuse.ts
|
|
473
|
-
const computeHypotenuse = (values) => {
|
|
474
|
-
let largest = 0;
|
|
475
|
-
let total = 0;
|
|
476
|
-
for (const value of values) {
|
|
477
|
-
const magnitude = Math.abs(value);
|
|
478
|
-
if (largest < magnitude) {
|
|
479
|
-
const ratio = largest / magnitude;
|
|
480
|
-
total = total * (ratio * ratio) + 1;
|
|
481
|
-
largest = magnitude;
|
|
482
|
-
} else if (magnitude > 0) {
|
|
483
|
-
const ratio = magnitude === largest ? 1 : magnitude / largest;
|
|
484
|
-
total += ratio * ratio;
|
|
485
|
-
} else total += magnitude;
|
|
486
|
-
}
|
|
487
|
-
return largest * Math.sqrt(total);
|
|
488
|
-
};
|
|
489
|
-
//#endregion
|
|
490
|
-
//#region src/services/function/computeGreatestCommonDivisor.ts
|
|
491
|
-
const computeGreatestCommonDivisor = (left, right) => right === 0 ? Math.abs(left) : computeGreatestCommonDivisor(right, left % right);
|
|
492
|
-
//#endregion
|
|
493
|
-
//#region src/services/function/computeIntegerGreatestCommonDivisor.ts
|
|
494
|
-
const computeIntegerGreatestCommonDivisor = (values) => {
|
|
495
|
-
if (!values.every((value) => Number.isInteger(value))) return null;
|
|
496
|
-
return values.reduce((total, value) => computeGreatestCommonDivisor(total, value), 0);
|
|
497
|
-
};
|
|
498
|
-
//#endregion
|
|
499
|
-
//#region src/services/function/computeInverseCoth.ts
|
|
500
|
-
const computeInverseCoth = (value) => {
|
|
501
|
-
const magnitude = Math.abs(value);
|
|
502
|
-
if (magnitude < 1) return NaN;
|
|
503
|
-
if (magnitude === 1) return value * Number.POSITIVE_INFINITY;
|
|
504
|
-
return Math.sign(value) * .5 * Math.log1p(2 / (magnitude - 1));
|
|
505
|
-
};
|
|
506
|
-
//#endregion
|
|
507
|
-
//#region src/services/function/computeKullbackLeibler.ts
|
|
508
|
-
const computeKullbackLeibler = (distribution, reference) => {
|
|
509
|
-
if (distribution.length !== reference.length) return null;
|
|
510
|
-
const distributionSum = computeSum(distribution);
|
|
511
|
-
const referenceSum = computeSum(reference);
|
|
512
|
-
if (distributionSum === 0 || referenceSum === 0) return null;
|
|
513
|
-
const normalizedDistribution = distribution.map((value) => value / distributionSum);
|
|
514
|
-
const normalizedReference = reference.map((value) => value / referenceSum);
|
|
515
|
-
return computeSum(normalizedDistribution.map((value, index) => value * Math.log(value / (normalizedReference[index] ?? NaN))));
|
|
516
|
-
};
|
|
517
|
-
//#endregion
|
|
518
|
-
//#region src/services/function/computeLeastCommonMultiple.ts
|
|
519
|
-
const computeLeastCommonMultiple = (left, right) => {
|
|
520
|
-
if (!Number.isInteger(left) || !Number.isInteger(right)) return null;
|
|
521
|
-
const divisor = computeGreatestCommonDivisor(left, right);
|
|
522
|
-
return divisor === 0 ? 0 : Math.abs(left * right / divisor);
|
|
523
|
-
};
|
|
524
|
-
//#endregion
|
|
525
|
-
//#region src/services/function/computeListComparison.ts
|
|
526
|
-
const computeListComparison = (left, right) => {
|
|
527
|
-
for (const [index, value] of left.entries()) {
|
|
528
|
-
const other = right[index];
|
|
529
|
-
if (other === void 0) return 1;
|
|
530
|
-
const comparison = computeComparison(value, other);
|
|
531
|
-
if (comparison !== 0) return comparison;
|
|
532
|
-
}
|
|
533
|
-
return left.length < right.length ? -1 : 0;
|
|
534
|
-
};
|
|
535
|
-
//#endregion
|
|
536
|
-
//#region src/services/function/computeLogarithm.ts
|
|
537
|
-
const computeLogarithm = (value, base) => base === void 0 ? Math.log(value) : Math.log(value) / Math.log(base);
|
|
538
|
-
//#endregion
|
|
539
|
-
//#region src/services/function/computeLogGamma.ts
|
|
540
|
-
const computeLogGamma = (value) => {
|
|
541
|
-
if (Number.isNaN(value) || value < 0) return NaN;
|
|
542
|
-
if ([0, Number.POSITIVE_INFINITY].includes(value)) return Number.POSITIVE_INFINITY;
|
|
543
|
-
if ([1, 2].includes(value)) return 0;
|
|
544
|
-
const { logGamma, product } = computeLogGammaOfPositive(value);
|
|
545
|
-
return logGamma - Math.log(product);
|
|
546
|
-
};
|
|
547
|
-
//#endregion
|
|
548
|
-
//#region src/services/function/computeMean.ts
|
|
549
|
-
const computeMean = (values) => computeSum(values) / values.length;
|
|
550
|
-
//#endregion
|
|
551
|
-
//#region src/services/function/compareNumbers.ts
|
|
552
|
-
const compareNumbers = (left, right) => left - right;
|
|
553
|
-
//#endregion
|
|
554
|
-
//#region src/services/function/computeMedian.ts
|
|
555
|
-
const computeMedian = (values) => {
|
|
556
|
-
const sorted = values.toSorted(compareNumbers);
|
|
557
|
-
const middle = Math.floor(sorted.length / 2);
|
|
558
|
-
if (sorted.length % 2 === 1) return sorted[middle] ?? NaN;
|
|
559
|
-
return ((sorted[middle - 1] ?? NaN) + (sorted[middle] ?? NaN)) / 2;
|
|
560
|
-
};
|
|
561
|
-
//#endregion
|
|
562
|
-
//#region src/services/function/computeMedianAbsoluteDeviation.ts
|
|
563
|
-
const computeMedianAbsoluteDeviation = (values) => {
|
|
564
|
-
const center = computeMedian(values);
|
|
565
|
-
return computeMedian(values.map((value) => Math.abs(value - center)));
|
|
566
|
-
};
|
|
567
|
-
//#endregion
|
|
568
|
-
//#region src/services/function/computeModulo.ts
|
|
569
|
-
const computeModulo = (dividend, divisor) => {
|
|
570
|
-
if (divisor === 0) return dividend;
|
|
571
|
-
if (!Number.isFinite(dividend) || !Number.isFinite(divisor)) return NaN;
|
|
572
|
-
if (Number.isInteger(dividend) && Number.isInteger(divisor)) {
|
|
573
|
-
const remainder = dividend % divisor;
|
|
574
|
-
if (remainder === 0) return 0;
|
|
575
|
-
return Math.sign(remainder) === Math.sign(divisor) ? remainder : remainder + divisor;
|
|
576
|
-
}
|
|
577
|
-
const quotient = dividend / divisor;
|
|
578
|
-
if (checkIsNearlyEqual(quotient, Math.round(quotient))) return 0;
|
|
579
|
-
return dividend - divisor * Math.floor(quotient);
|
|
580
|
-
};
|
|
581
|
-
//#endregion
|
|
582
|
-
//#region src/services/function/computeModularInverse.ts
|
|
583
|
-
const computeModularInverse = (value, modulus) => {
|
|
584
|
-
if (!Number.isInteger(value) || !Number.isInteger(modulus) || modulus === 0) return null;
|
|
585
|
-
let remainder = value;
|
|
586
|
-
let nextRemainder = modulus;
|
|
587
|
-
let coefficient = 0;
|
|
588
|
-
let previousCoefficient = 1;
|
|
589
|
-
while (nextRemainder !== 0) {
|
|
590
|
-
const quotient = Math.floor(remainder / nextRemainder);
|
|
591
|
-
[coefficient, previousCoefficient] = [previousCoefficient - quotient * coefficient, coefficient];
|
|
592
|
-
[remainder, nextRemainder] = [nextRemainder, remainder - quotient * nextRemainder];
|
|
593
|
-
}
|
|
594
|
-
if ((remainder < 0 ? -remainder : remainder) !== 1) return NaN;
|
|
595
|
-
const inverse = computeModulo(remainder < 0 ? -previousCoefficient : previousCoefficient, modulus);
|
|
596
|
-
return inverse < 0 ? inverse + modulus : inverse;
|
|
597
|
-
};
|
|
598
|
-
//#endregion
|
|
599
|
-
//#region src/services/function/computeMultinomial.ts
|
|
600
|
-
const computeMultinomial = (parts) => {
|
|
601
|
-
if (!parts.every((part) => Number.isInteger(part) && part > 0)) return null;
|
|
602
|
-
let result = 1;
|
|
603
|
-
let running = 0;
|
|
604
|
-
for (const part of parts) {
|
|
605
|
-
running += part;
|
|
606
|
-
result *= computeCombinations(running, part);
|
|
607
|
-
}
|
|
608
|
-
return result;
|
|
609
|
-
};
|
|
610
|
-
//#endregion
|
|
611
|
-
//#region src/services/function/computeNorm.ts
|
|
612
|
-
const computeNorm = (values) => {
|
|
613
|
-
if (values.length === 0) return 0;
|
|
614
|
-
if (values.length === 1) return Math.abs(values[0] ?? NaN);
|
|
615
|
-
return Math.sqrt(computeSum(values.map((value) => value * value)));
|
|
616
|
-
};
|
|
617
|
-
//#endregion
|
|
618
|
-
//#region src/services/function/computeNthRoot.ts
|
|
619
|
-
const computeNthRoot = (value, root) => {
|
|
620
|
-
const isInverse = root < 0;
|
|
621
|
-
const degree = Math.abs(root);
|
|
622
|
-
if (degree === 0) return null;
|
|
623
|
-
if (value < 0 && degree % 2 !== 1) return null;
|
|
624
|
-
if (value === 0) return isInverse ? Number.POSITIVE_INFINITY : 0;
|
|
625
|
-
if (!Number.isFinite(value)) return isInverse ? 0 : value;
|
|
626
|
-
let result = Math.abs(value) ** (1 / degree);
|
|
627
|
-
const rounded = Math.round(result);
|
|
628
|
-
if (Number.isInteger(degree) && rounded ** degree === Math.abs(value)) result = rounded;
|
|
629
|
-
if (value < 0) result = -result;
|
|
630
|
-
return isInverse ? 1 / result : result;
|
|
631
|
-
};
|
|
632
|
-
//#endregion
|
|
633
|
-
//#region src/services/function/computePartitionSelect.ts
|
|
634
|
-
const computePartitionSelect = (values, index) => {
|
|
635
|
-
if (!Number.isInteger(index) || index < 0 || index >= values.length) return null;
|
|
636
|
-
return values.toSorted(compareNumbers)[index] ?? null;
|
|
637
|
-
};
|
|
638
|
-
//#endregion
|
|
639
|
-
//#region src/services/function/computePermutations.ts
|
|
640
|
-
const computePermutations = (available, chosen) => {
|
|
641
|
-
if (!Number.isInteger(available) || !Number.isInteger(chosen) || chosen < 0 || chosen > available) return null;
|
|
642
|
-
let result = 1;
|
|
643
|
-
for (let factor = available - chosen + 1; factor <= available; factor++) {
|
|
644
|
-
result *= factor;
|
|
645
|
-
if (result > Number.MAX_VALUE) return Number.POSITIVE_INFINITY;
|
|
646
|
-
}
|
|
647
|
-
return result;
|
|
648
|
-
};
|
|
649
|
-
//#endregion
|
|
650
|
-
//#region src/services/function/scaleList.ts
|
|
651
|
-
const scaleList = (list, scalar) => list.map((element) => element * scalar);
|
|
652
|
-
//#endregion
|
|
653
|
-
//#region src/services/function/multiplyPair.ts
|
|
654
|
-
const multiplyPair = (left, right) => {
|
|
655
|
-
if (typeof left === "number" && typeof right === "number") return left * right;
|
|
656
|
-
if (typeof left === "number" && Array.isArray(right)) return scaleList(right, left);
|
|
657
|
-
if (Array.isArray(left) && typeof right === "number") return scaleList(left, right);
|
|
658
|
-
if (Array.isArray(left) && Array.isArray(right)) return computeDotProduct(left, right);
|
|
659
|
-
return null;
|
|
660
|
-
};
|
|
661
|
-
//#endregion
|
|
662
|
-
//#region src/services/function/computeProduct.ts
|
|
663
|
-
const computeProduct = (values) => {
|
|
664
|
-
let total = 1;
|
|
665
|
-
for (const value of values) {
|
|
666
|
-
if (total === null) return null;
|
|
667
|
-
total = multiplyPair(total, value);
|
|
668
|
-
}
|
|
669
|
-
return typeof total === "number" ? total : null;
|
|
670
|
-
};
|
|
671
|
-
//#endregion
|
|
672
|
-
//#region src/services/function/computeQuantile.ts
|
|
673
|
-
const computeQuantile = (values, probability, isSorted) => {
|
|
674
|
-
if (values.length === 0 || probability < 0 || probability > 1) return null;
|
|
675
|
-
const ordered = isSorted ? values : values.toSorted(compareNumbers);
|
|
676
|
-
const index = probability * (ordered.length - 1);
|
|
677
|
-
const integerPart = Math.floor(index);
|
|
678
|
-
if (Number.isInteger(index)) return ordered[integerPart] ?? NaN;
|
|
679
|
-
const fraction = index % 1;
|
|
680
|
-
return (ordered[integerPart] ?? NaN) * (1 - fraction) + (ordered[integerPart + 1] ?? NaN) * fraction;
|
|
681
|
-
};
|
|
682
|
-
//#endregion
|
|
683
|
-
//#region src/services/function/computeStirlingColumn.ts
|
|
684
|
-
const computeStirlingColumn = (count, parts) => {
|
|
685
|
-
const column = Array.from({ length: parts + 1 }, (_element, index) => index === 0 ? 1 : 0);
|
|
686
|
-
for (let step = 1; step <= count; step++) {
|
|
687
|
-
for (let part = parts; part >= 1; part--) column[part] = part * (column[part] ?? 0) + (column[part - 1] ?? 0);
|
|
688
|
-
column[0] = 0;
|
|
689
|
-
}
|
|
690
|
-
return column[parts] ?? 0;
|
|
691
|
-
};
|
|
692
|
-
//#endregion
|
|
693
|
-
//#region src/services/function/computeStirlingDiagonal.ts
|
|
694
|
-
const computeStirlingDiagonal = (count, index) => {
|
|
695
|
-
const diagonal = Array.from({ length: index + 1 }, (_element, position) => position === 0 ? 1 : 0);
|
|
696
|
-
for (let step = 1; step <= count; step++) for (let position = Math.min(step, index); position >= 1; position--) diagonal[position] = (step - position) * (diagonal[position - 1] ?? 0) + (diagonal[position] ?? 0);
|
|
697
|
-
return diagonal[index] ?? 0;
|
|
698
|
-
};
|
|
699
|
-
//#endregion
|
|
700
|
-
//#region src/services/function/computeStirlingSecondKind.ts
|
|
701
|
-
const computeStirlingSecondKind = (count, parts) => {
|
|
702
|
-
if (!Number.isInteger(count) || !Number.isInteger(parts) || count < 0 || parts < 0 || parts > count) return null;
|
|
703
|
-
if (parts === 0) return count === 0 ? 1 : 0;
|
|
704
|
-
if (parts === count) return 1;
|
|
705
|
-
const band = Math.min(parts, count - parts);
|
|
706
|
-
if (count * band > 4e6) return null;
|
|
707
|
-
return band === parts ? computeStirlingColumn(count, parts) : computeStirlingDiagonal(count, count - parts);
|
|
708
|
-
};
|
|
709
|
-
//#endregion
|
|
710
|
-
//#region src/services/shared/checkIsTruthy.ts
|
|
711
|
-
const checkIsTruthy = (value) => value !== 0 && !Number.isNaN(value);
|
|
712
|
-
//#endregion
|
|
713
|
-
//#region src/services/function/computeTruthyCount.ts
|
|
714
|
-
const computeTruthyCount = (values) => values.filter((value) => checkIsTruthy(value)).length;
|
|
715
|
-
//#endregion
|
|
716
|
-
//#region src/services/function/computeVariance.ts
|
|
717
|
-
const computeVariance = (values) => {
|
|
718
|
-
if (values.length === 1) return Number.isFinite(values[0] ?? NaN) ? 0 : NaN;
|
|
719
|
-
const average = computeMean(values);
|
|
720
|
-
return computeSum(values.map((value) => (value - average) ** 2)) / (values.length - 1);
|
|
721
|
-
};
|
|
722
|
-
//#endregion
|
|
723
|
-
//#region src/services/function/computeExtreme.ts
|
|
724
|
-
const computeExtreme = (values, initial, checkIsPreferred) => {
|
|
725
|
-
let extreme = initial;
|
|
726
|
-
for (const value of values) {
|
|
727
|
-
if (Number.isNaN(value)) return NaN;
|
|
728
|
-
if (checkIsPreferred(value, extreme)) extreme = value;
|
|
729
|
-
}
|
|
730
|
-
return extreme;
|
|
731
|
-
};
|
|
732
|
-
//#endregion
|
|
733
|
-
//#region src/services/function/computeVectorNorm.ts
|
|
734
|
-
const computeVectorNorm = (values, power) => {
|
|
735
|
-
if (Number.isNaN(power)) return null;
|
|
736
|
-
const magnitudes = values.map((value) => Math.abs(value));
|
|
737
|
-
if (Math.abs(power) === Number.POSITIVE_INFINITY) {
|
|
738
|
-
const [first] = magnitudes;
|
|
739
|
-
if (first === void 0) return 0;
|
|
740
|
-
return computeExtreme(magnitudes, first, power > 0 ? checkIsLarger : checkIsSmaller);
|
|
741
|
-
}
|
|
742
|
-
if (checkIsNearlyEqual(power, 0)) return Number.POSITIVE_INFINITY;
|
|
743
|
-
return computeSum(magnitudes.map((magnitude) => magnitude ** power)) ** (1 / power);
|
|
744
|
-
};
|
|
745
|
-
//#endregion
|
|
746
|
-
//#region src/services/function/computeSummedZeta.ts
|
|
747
|
-
const computeSummedZeta = (value) => {
|
|
748
|
-
let total = 0;
|
|
749
|
-
for (let integer = 1; integer < 10; integer++) total += integer ** -value;
|
|
750
|
-
total += 10 ** (1 - value) / (value - 1) + .5 * 10 ** -value;
|
|
751
|
-
let rising = value;
|
|
752
|
-
for (let index = 1; index <= EULER_MACLAURIN_COEFFICIENTS.length; index++) {
|
|
753
|
-
const coefficient = EULER_MACLAURIN_COEFFICIENTS[index - 1] ?? 0;
|
|
754
|
-
total += coefficient * rising * 10 ** (-value - 2 * index + 1);
|
|
755
|
-
rising *= (value + 2 * index - 1) * (value + 2 * index);
|
|
756
|
-
}
|
|
757
|
-
return total;
|
|
758
|
-
};
|
|
759
|
-
//#endregion
|
|
760
|
-
//#region src/services/function/computeZeta.ts
|
|
761
|
-
const computeZeta = (value) => {
|
|
762
|
-
if (value === Number.POSITIVE_INFINITY) return 1;
|
|
763
|
-
if (!Number.isFinite(value)) return NaN;
|
|
764
|
-
if (value === 1) return NaN;
|
|
765
|
-
if (value === 0) return -.5;
|
|
766
|
-
if (value > 0) return computeSummedZeta(value);
|
|
767
|
-
if (Number.isInteger(value) && value % 2 === 0) return 0;
|
|
768
|
-
if (1 - value >= 171.35) {
|
|
769
|
-
const sine = Math.sin(Math.PI * value / 2);
|
|
770
|
-
const logMagnitude = value * Math.LN2 + (value - 1) * Math.log(Math.PI) + Math.log(Math.abs(sine)) + computeLogGamma(1 - value) + Math.log(computeSummedZeta(1 - value));
|
|
771
|
-
return Math.sign(sine) * Math.exp(logMagnitude);
|
|
772
|
-
}
|
|
773
|
-
return 2 ** value * Math.PI ** (value - 1) * Math.sin(Math.PI * value / 2) * computeGamma(1 - value) * computeSummedZeta(1 - value);
|
|
774
|
-
};
|
|
775
|
-
//#endregion
|
|
776
|
-
//#region src/services/function/signature/createNumericCompute.ts
|
|
777
|
-
const createNumericCompute = (compute) => (values) => compute(values.flat());
|
|
778
|
-
//#endregion
|
|
779
|
-
//#region src/services/function/signature/createSignature.ts
|
|
780
|
-
const createSignature = (parameters, minArity, maxArity, compute, scalarCompute = {}) => ({
|
|
781
|
-
compute,
|
|
782
|
-
maxArity,
|
|
783
|
-
minArity,
|
|
784
|
-
parameters,
|
|
785
|
-
...scalarCompute
|
|
786
|
-
});
|
|
787
|
-
//#endregion
|
|
788
|
-
//#region src/services/function/signature/createNumberSignature.ts
|
|
789
|
-
const createNumberSignature = (minArity, maxArity, compute, scalarCompute) => createSignature(["number"], minArity, maxArity, createNumericCompute(compute), scalarCompute);
|
|
790
|
-
//#endregion
|
|
791
|
-
//#region src/services/function/signature/createRangedSignatures.ts
|
|
792
|
-
const createRangedSignatures = (minArity, maxArity, compute, scalarCompute) => [createNumberSignature(minArity, maxArity, compute, scalarCompute)];
|
|
793
|
-
//#endregion
|
|
794
|
-
//#region src/services/function/signature/createBinarySignatures.ts
|
|
795
|
-
const createBinarySignatures = (compute) => createRangedSignatures(2, 2, (values) => compute(values[0] ?? NaN, values[1] ?? NaN), { computeBinary: compute });
|
|
796
|
-
//#endregion
|
|
797
|
-
//#region src/services/function/signature/createBitwisePair.ts
|
|
798
|
-
const createBitwisePair = (absorbing, compute) => (left, right) => {
|
|
799
|
-
if (left === absorbing) return absorbing;
|
|
800
|
-
if (!Number.isInteger(left) || !Number.isInteger(right)) return null;
|
|
801
|
-
return compute(left, right);
|
|
802
|
-
};
|
|
803
|
-
//#endregion
|
|
804
|
-
//#region src/services/function/signature/createBitwiseFold.ts
|
|
805
|
-
const createBitwiseFold = (absorbing, compute) => {
|
|
806
|
-
const computePair = createBitwisePair(absorbing, compute);
|
|
807
|
-
return (values) => values.slice(1).reduce((result, value) => result === null ? null : computePair(result, value), values[0] ?? NaN);
|
|
808
|
-
};
|
|
809
|
-
//#endregion
|
|
810
|
-
//#region src/services/function/shiftDecimalPlaces.ts
|
|
811
|
-
const shiftDecimalPlaces = (value, places) => {
|
|
812
|
-
if (!Number.isFinite(value)) return value;
|
|
813
|
-
const [mantissa = "", exponent = "0"] = value.toExponential().split("e");
|
|
814
|
-
return Number(`${mantissa}e${Number(exponent) + places}`);
|
|
815
|
-
};
|
|
816
|
-
//#endregion
|
|
817
|
-
//#region src/services/function/roundToDigits.ts
|
|
818
|
-
const roundToDigits = (rounder, value, digits) => {
|
|
819
|
-
if (!Number.isInteger(digits) || digits < 0 || digits > 15) return null;
|
|
820
|
-
if (!Number.isFinite(value)) return value;
|
|
821
|
-
if (Number.isInteger(value)) return value + 0;
|
|
822
|
-
if (digits === 0) return rounder(value) + 0;
|
|
823
|
-
return shiftDecimalPlaces(rounder(shiftDecimalPlaces(value, digits)), -digits);
|
|
824
|
-
};
|
|
825
|
-
//#endregion
|
|
826
|
-
//#region src/services/function/signature/createDigitSignatures.ts
|
|
827
|
-
const createDigitSignatures = (rounder) => createRangedSignatures(1, 2, (values) => {
|
|
828
|
-
const [value = NaN, digits = 0] = values;
|
|
829
|
-
return roundToDigits(rounder, value, digits);
|
|
830
|
-
}, {
|
|
831
|
-
computeBinary: (value, digits) => roundToDigits(rounder, value, digits),
|
|
832
|
-
computeUnary: (value) => roundToDigits(rounder, value, 0)
|
|
833
|
-
});
|
|
834
|
-
//#endregion
|
|
835
|
-
//#region src/services/function/signature/createNonEmptyCompute.ts
|
|
836
|
-
const createNonEmptyCompute = (compute) => (values) => values.length === 0 ? null : compute(values);
|
|
837
|
-
//#endregion
|
|
838
|
-
//#region src/services/function/signature/createListSignature.ts
|
|
839
|
-
const createListSignature = (compute) => createSignature(["list"], 1, 1, createNumericCompute(compute));
|
|
840
|
-
//#endregion
|
|
841
|
-
//#region src/services/function/signature/createVariadicSignatures.ts
|
|
842
|
-
const createVariadicSignatures = (minArity, compute, computeBinary) => [createNumberSignature(minArity, Number.POSITIVE_INFINITY, compute, { computeBinary })];
|
|
843
|
-
//#endregion
|
|
844
|
-
//#region src/services/function/signature/createSpreadSignatures.ts
|
|
845
|
-
const createSpreadSignatures = (minArity, compute) => [...createVariadicSignatures(minArity, compute), createListSignature(compute)];
|
|
846
|
-
//#endregion
|
|
847
|
-
//#region src/services/function/signature/createExtremeSignatures.ts
|
|
848
|
-
const createExtremeSignatures = (checkIsPreferred) => createSpreadSignatures(1, createNonEmptyCompute((values) => computeExtreme(values, values[0] ?? NaN, checkIsPreferred)));
|
|
849
|
-
//#endregion
|
|
850
|
-
//#region src/services/function/signature/createSingletonListSignature.ts
|
|
851
|
-
const createSingletonListSignature = (compute) => createListSignature((values) => values.length === 1 ? compute(values[0] ?? NaN) : null);
|
|
852
|
-
//#endregion
|
|
853
|
-
//#region src/services/function/signature/createUnarySignatures.ts
|
|
854
|
-
const createUnarySignatures = (compute) => createRangedSignatures(1, 1, (values) => compute(values[0] ?? NaN), { computeUnary: compute });
|
|
855
|
-
//#endregion
|
|
856
|
-
//#region src/services/function/signature/createIdentitySignatures.ts
|
|
857
|
-
const createIdentitySignatures = () => [...createUnarySignatures((value) => value), createSingletonListSignature((value) => value)];
|
|
858
|
-
//#endregion
|
|
859
|
-
//#region src/services/function/signature/createIntegerBinarySignatures.ts
|
|
860
|
-
const createIntegerBinarySignatures = (compute) => createBinarySignatures((left, right) => Number.isInteger(left) && Number.isInteger(right) ? compute(left, right) : null);
|
|
861
|
-
//#endregion
|
|
862
|
-
//#region src/services/function/signature/createIntegerUnarySignatures.ts
|
|
863
|
-
const createIntegerUnarySignatures = (compute) => createUnarySignatures((value) => Number.isInteger(value) ? compute(value) : null);
|
|
864
|
-
//#endregion
|
|
865
|
-
//#region src/services/function/signature/createListFirstCompute.ts
|
|
866
|
-
const createListFirstCompute = (compute) => (values) => compute(values.slice(0, 1).flat(), values.slice(1).flat());
|
|
867
|
-
//#endregion
|
|
868
|
-
//#region src/services/function/signature/createListPairCompute.ts
|
|
869
|
-
const createListPairCompute = (compute) => (values) => compute(values.slice(0, 1).flat(), values.slice(1, 2).flat());
|
|
870
|
-
//#endregion
|
|
871
|
-
//#region src/services/function/signature/createListPairSignature.ts
|
|
872
|
-
const createListPairSignature = (compute) => createSignature(["list", "list"], 2, 2, createListPairCompute(compute));
|
|
873
|
-
//#endregion
|
|
874
|
-
//#region src/services/function/signature/createOrderedListSignatures.ts
|
|
875
|
-
const createOrderedListSignatures = (compute) => {
|
|
876
|
-
const computePair = createListPairCompute(compute);
|
|
877
|
-
return [
|
|
878
|
-
["number", "list"],
|
|
879
|
-
["list", "number"],
|
|
880
|
-
["list", "list"]
|
|
881
|
-
].map((parameters) => createSignature(parameters, 2, 2, computePair));
|
|
882
|
-
};
|
|
883
|
-
//#endregion
|
|
884
|
-
//#region src/services/shared/toNumber.ts
|
|
885
|
-
const toNumber = (flag) => flag ? 1 : 0;
|
|
886
|
-
//#endregion
|
|
887
|
-
//#region src/services/function/MathExpressionFunctionMap.ts
|
|
888
|
-
const MathExpressionFunctionMap = {
|
|
889
|
-
abs: createUnarySignatures(Math.abs),
|
|
890
|
-
acos: createUnarySignatures(Math.acos),
|
|
891
|
-
acosh: createUnarySignatures(Math.acosh),
|
|
892
|
-
acot: createUnarySignatures((value) => Math.atan(1 / value)),
|
|
893
|
-
acoth: createUnarySignatures(computeInverseCoth),
|
|
894
|
-
acsc: createUnarySignatures((value) => Math.asin(1 / value)),
|
|
895
|
-
acsch: createUnarySignatures((value) => Math.asinh(1 / value)),
|
|
896
|
-
add: createVariadicSignatures(2, computeSum, (left, right) => left + right),
|
|
897
|
-
addScalar: createBinarySignatures((left, right) => left + right),
|
|
898
|
-
and: createVariadicSignatures(1, (values) => toNumber(values.every((value) => checkIsTruthy(value)))),
|
|
899
|
-
arg: createUnarySignatures((value) => Number.isNaN(value) ? NaN : value < 0 ? Math.PI : 0),
|
|
900
|
-
asec: createUnarySignatures((value) => Math.acos(1 / value)),
|
|
901
|
-
asech: createUnarySignatures((value) => Math.acosh(1 / value)),
|
|
902
|
-
asin: createUnarySignatures(Math.asin),
|
|
903
|
-
asinh: createUnarySignatures(Math.asinh),
|
|
904
|
-
atan: createUnarySignatures(Math.atan),
|
|
905
|
-
atan2: createBinarySignatures((left, right) => Math.atan2(left, right)),
|
|
906
|
-
atanh: createUnarySignatures(Math.atanh),
|
|
907
|
-
bellNumbers: createUnarySignatures(computeBellNumber),
|
|
908
|
-
bernoulli: createUnarySignatures((value) => Number.isInteger(value) && value >= 0 ? computeBernoulliNumber(value) : null),
|
|
909
|
-
bitAnd: createVariadicSignatures(2, createBitwiseFold(0, computeBitwiseAnd), createBitwisePair(0, computeBitwiseAnd)),
|
|
910
|
-
bitNot: createIntegerUnarySignatures((value) => ~value),
|
|
911
|
-
bitOr: createVariadicSignatures(2, createBitwiseFold(-1, computeBitwiseOr), createBitwisePair(-1, computeBitwiseOr)),
|
|
912
|
-
bitXor: createIntegerBinarySignatures((left, right) => left ^ right),
|
|
913
|
-
boolean: createRangedSignatures(0, 1, (values) => values.length === 0 ? 0 : toNumber(checkIsTruthy(values[0] ?? 0))),
|
|
914
|
-
catalan: createUnarySignatures(computeCatalan),
|
|
915
|
-
cbrt: createUnarySignatures(Math.cbrt),
|
|
916
|
-
ceil: createDigitSignatures(Math.ceil),
|
|
917
|
-
clone: createUnarySignatures((value) => value),
|
|
918
|
-
combinations: createBinarySignatures((available, chosen) => Number.isInteger(available) && Number.isInteger(chosen) && chosen >= 0 && chosen <= available ? computeCombinations(available, chosen) : null),
|
|
919
|
-
combinationsWithRep: createBinarySignatures((available, chosen) => Number.isInteger(available) && Number.isInteger(chosen) && available >= 1 && chosen >= 0 ? computeCombinations(available + chosen - 1, chosen) : null),
|
|
920
|
-
compare: createBinarySignatures(computeComparison),
|
|
921
|
-
compareNatural: [...createBinarySignatures(computeComparison), ...createOrderedListSignatures(computeListComparison)],
|
|
922
|
-
composition: createBinarySignatures(computeCompositions),
|
|
923
|
-
conj: createUnarySignatures((value) => value),
|
|
924
|
-
corr: [createListPairSignature(computeCorrelation)],
|
|
925
|
-
cos: createUnarySignatures(Math.cos),
|
|
926
|
-
cosh: createUnarySignatures(Math.cosh),
|
|
927
|
-
cot: createUnarySignatures((value) => 1 / Math.tan(value)),
|
|
928
|
-
coth: createUnarySignatures((value) => 1 / Math.tanh(value)),
|
|
929
|
-
count: [createListSignature((values) => values.length)],
|
|
930
|
-
csc: createUnarySignatures((value) => 1 / Math.sin(value)),
|
|
931
|
-
csch: createUnarySignatures((value) => 1 / Math.sinh(value)),
|
|
932
|
-
cube: createUnarySignatures((value) => value * value * value),
|
|
933
|
-
deepEqual: [
|
|
934
|
-
...createBinarySignatures((left, right) => toNumber(checkIsNearlyEqual(left, right))),
|
|
935
|
-
createListPairSignature((left, right) => toNumber(left.length === right.length && left.every((value, index) => checkIsNearlyEqual(value, right[index] ?? NaN)))),
|
|
936
|
-
createSignature(["number", "list"], 2, 2, () => toNumber(false)),
|
|
937
|
-
createSignature(["list", "number"], 2, 2, () => toNumber(false))
|
|
938
|
-
],
|
|
939
|
-
det: [...createUnarySignatures((value) => value), createListSignature(computeDeterminant)],
|
|
940
|
-
distance: [createListPairSignature(computeDistance)],
|
|
941
|
-
divide: createBinarySignatures((left, right) => left / right),
|
|
942
|
-
divideScalar: createBinarySignatures((left, right) => left / right),
|
|
943
|
-
dot: [createListPairSignature(computeDotProduct)],
|
|
944
|
-
dotDivide: createBinarySignatures((left, right) => left / right),
|
|
945
|
-
dotMultiply: createBinarySignatures((left, right) => left * right),
|
|
946
|
-
dotPow: createBinarySignatures((left, right) => left ** right),
|
|
947
|
-
equal: createBinarySignatures((left, right) => toNumber(checkIsNearlyEqual(left, right))),
|
|
948
|
-
equalScalar: createBinarySignatures((left, right) => toNumber(checkIsNearlyEqual(left, right))),
|
|
949
|
-
erf: createUnarySignatures(computeErf),
|
|
950
|
-
erfinv: createUnarySignatures(computeErfInverse),
|
|
951
|
-
exp: createUnarySignatures(Math.exp),
|
|
952
|
-
expm1: createUnarySignatures(Math.expm1),
|
|
953
|
-
fix: createDigitSignatures(Math.trunc),
|
|
954
|
-
floor: createDigitSignatures(Math.floor),
|
|
955
|
-
gamma: createUnarySignatures(computeGamma),
|
|
956
|
-
gcd: createSpreadSignatures(2, (values) => values.length < 2 ? null : computeIntegerGreatestCommonDivisor(values)),
|
|
957
|
-
hypot: createSpreadSignatures(1, computeHypotenuse),
|
|
958
|
-
im: createUnarySignatures(() => 0),
|
|
959
|
-
inv: createUnarySignatures((value) => 1 / value),
|
|
960
|
-
invmod: createBinarySignatures(computeModularInverse),
|
|
961
|
-
isBounded: [...createUnarySignatures((value) => toNumber(Number.isFinite(value))), createListSignature((values) => toNumber(values.every((value) => Number.isFinite(value))))],
|
|
962
|
-
isFinite: createUnarySignatures((value) => toNumber(Number.isFinite(value))),
|
|
963
|
-
isInteger: createUnarySignatures((value) => toNumber(Number.isInteger(value))),
|
|
964
|
-
isNaN: createUnarySignatures((value) => toNumber(Number.isNaN(value))),
|
|
965
|
-
isNegative: createUnarySignatures((value) => toNumber(value < 0)),
|
|
966
|
-
isPositive: createUnarySignatures((value) => toNumber(value > 0)),
|
|
967
|
-
isPrime: createUnarySignatures((value) => toNumber(checkIsPrime(value))),
|
|
968
|
-
isZero: createUnarySignatures((value) => toNumber(value === 0)),
|
|
969
|
-
kldivergence: [createListPairSignature(computeKullbackLeibler)],
|
|
970
|
-
larger: createBinarySignatures((left, right) => toNumber(checkIsLarger(left, right))),
|
|
971
|
-
largerEq: createBinarySignatures((left, right) => toNumber(left >= right || checkIsNearlyEqual(left, right))),
|
|
972
|
-
lcm: createVariadicSignatures(2, (values) => {
|
|
973
|
-
const [first = NaN, ...rest] = values;
|
|
974
|
-
return rest.reduce((total, value) => total === null ? null : computeLeastCommonMultiple(total, value), first);
|
|
975
|
-
}),
|
|
976
|
-
leftShift: createIntegerBinarySignatures((left, right) => left << right),
|
|
977
|
-
lgamma: createUnarySignatures(computeLogGamma),
|
|
978
|
-
log: createRangedSignatures(1, 2, (values) => computeLogarithm(values[0] ?? NaN, values[1])),
|
|
979
|
-
log1p: createRangedSignatures(1, 2, (values) => {
|
|
980
|
-
const [value = NaN, base] = values;
|
|
981
|
-
return base === void 0 ? Math.log1p(value) : Math.log1p(value) / Math.log(base);
|
|
982
|
-
}),
|
|
983
|
-
log2: createUnarySignatures(Math.log2),
|
|
984
|
-
log10: createUnarySignatures(Math.log10),
|
|
985
|
-
mad: createSpreadSignatures(1, createNonEmptyCompute(computeMedianAbsoluteDeviation)),
|
|
986
|
-
["ctranspose"]: createUnarySignatures((value) => value),
|
|
987
|
-
["factorial"]: createUnarySignatures(computeFactorial),
|
|
988
|
-
["unaryMinus"]: createUnarySignatures((value) => -value),
|
|
989
|
-
["unaryPlus"]: createUnarySignatures((value) => value),
|
|
990
|
-
max: createExtremeSignatures(checkIsLarger),
|
|
991
|
-
mean: createSpreadSignatures(1, createNonEmptyCompute(computeMean)),
|
|
992
|
-
median: createSpreadSignatures(1, createNonEmptyCompute(computeMedian)),
|
|
993
|
-
min: createExtremeSignatures(checkIsSmaller),
|
|
994
|
-
mod: createBinarySignatures(computeModulo),
|
|
995
|
-
multinomial: [createListSignature(computeMultinomial)],
|
|
996
|
-
multiply: [
|
|
997
|
-
...createVariadicSignatures(2, (values) => values.reduce((total, value) => total * value, 1), (left, right) => left * right),
|
|
998
|
-
createListPairSignature(computeDotProduct),
|
|
999
|
-
createSignature(["any"], 2, Number.POSITIVE_INFINITY, computeProduct)
|
|
1000
|
-
],
|
|
1001
|
-
multiplyScalar: createBinarySignatures((left, right) => left * right),
|
|
1002
|
-
norm: [
|
|
1003
|
-
...createRangedSignatures(1, 1, computeNorm),
|
|
1004
|
-
createListSignature(computeNorm),
|
|
1005
|
-
createSignature(["list", "number"], 2, 2, createListFirstCompute((list, [power = NaN]) => computeVectorNorm(list, power)))
|
|
1006
|
-
],
|
|
1007
|
-
not: createUnarySignatures((value) => toNumber(!checkIsTruthy(value))),
|
|
1008
|
-
nthRoot: createRangedSignatures(1, 2, (values) => computeNthRoot(values[0] ?? NaN, values[1] ?? 2)),
|
|
1009
|
-
nullish: createVariadicSignatures(1, (values) => values[0] ?? NaN),
|
|
1010
|
-
number: createRangedSignatures(0, 1, (values) => values.length === 0 ? 0 : values[0] ?? NaN),
|
|
1011
|
-
numeric: createUnarySignatures((value) => value),
|
|
1012
|
-
or: createVariadicSignatures(1, (values) => toNumber(computeTruthyCount(values) > 0)),
|
|
1013
|
-
partitionSelect: [createSignature(["list", "number"], 2, 2, createListFirstCompute((list, [index = NaN]) => computePartitionSelect(list, index)))],
|
|
1014
|
-
permutations: createRangedSignatures(1, 2, (values) => {
|
|
1015
|
-
const [available = NaN, chosen = available] = values;
|
|
1016
|
-
return computePermutations(available, chosen);
|
|
1017
|
-
}),
|
|
1018
|
-
pinv: createUnarySignatures((value) => value === 0 ? 0 : 1 / value),
|
|
1019
|
-
pow: createBinarySignatures((left, right) => left ** right),
|
|
1020
|
-
prod: createSpreadSignatures(1, createNonEmptyCompute((values) => values.reduce((total, value) => total * value, 1))),
|
|
1021
|
-
quantileSeq: [createSignature(["list", "number"], 2, 3, createListFirstCompute((list, [probability = NaN, sorted = 0]) => computeQuantile(list, probability, checkIsTruthy(sorted))))],
|
|
1022
|
-
re: createUnarySignatures((value) => value),
|
|
1023
|
-
rightArithShift: createIntegerBinarySignatures((left, right) => left >> right),
|
|
1024
|
-
rightLogShift: createIntegerBinarySignatures((left, right) => left >>> right),
|
|
1025
|
-
round: createDigitSignatures((value) => Math.sign(value) * Math.round(Math.abs(value))),
|
|
1026
|
-
sec: createUnarySignatures((value) => 1 / Math.cos(value)),
|
|
1027
|
-
sech: createUnarySignatures((value) => 1 / Math.cosh(value)),
|
|
1028
|
-
setIsSubset: [createListPairSignature((left, right) => toNumber(left.every((value) => right.includes(value))))],
|
|
1029
|
-
setMultiplicity: [createSignature(["number", "list"], 2, 2, createListFirstCompute(([value = NaN], list) => list.filter((element) => element === value).length))],
|
|
1030
|
-
setSize: [createListSignature((values) => values.length)],
|
|
1031
|
-
sign: createUnarySignatures(Math.sign),
|
|
1032
|
-
sin: createUnarySignatures(Math.sin),
|
|
1033
|
-
sinh: createUnarySignatures(Math.sinh),
|
|
1034
|
-
smaller: createBinarySignatures((left, right) => toNumber(checkIsSmaller(left, right))),
|
|
1035
|
-
smallerEq: createBinarySignatures((left, right) => toNumber(left <= right || checkIsNearlyEqual(left, right))),
|
|
1036
|
-
sqrt: createUnarySignatures(Math.sqrt),
|
|
1037
|
-
square: createUnarySignatures((value) => value * value),
|
|
1038
|
-
squeeze: createIdentitySignatures(),
|
|
1039
|
-
std: createSpreadSignatures(1, createNonEmptyCompute((values) => Math.sqrt(computeVariance(values)))),
|
|
1040
|
-
stirlingS2: createBinarySignatures(computeStirlingSecondKind),
|
|
1041
|
-
subtract: createBinarySignatures((left, right) => left - right),
|
|
1042
|
-
subtractScalar: createBinarySignatures((left, right) => left - right),
|
|
1043
|
-
sum: createSpreadSignatures(1, computeSum),
|
|
1044
|
-
tan: createUnarySignatures(Math.tan),
|
|
1045
|
-
tanh: createUnarySignatures(Math.tanh),
|
|
1046
|
-
trace: createIdentitySignatures(),
|
|
1047
|
-
transpose: createIdentitySignatures(),
|
|
1048
|
-
unequal: createBinarySignatures((left, right) => toNumber(!checkIsNearlyEqual(left, right))),
|
|
1049
|
-
variance: createSpreadSignatures(1, createNonEmptyCompute(computeVariance)),
|
|
1050
|
-
xor: createVariadicSignatures(1, (values) => toNumber(computeTruthyCount(values) % 2 === 1), (left, right) => toNumber(checkIsTruthy(left) !== checkIsTruthy(right))),
|
|
1051
|
-
zeta: createUnarySignatures(computeZeta)
|
|
1052
|
-
};
|
|
1053
|
-
//#endregion
|
|
1054
|
-
//#region src/services/shared/getOwnValue.ts
|
|
1055
|
-
const getOwnValue = (record, key) => Object.hasOwn(record, key) ? record[key] : void 0;
|
|
1056
|
-
//#endregion
|
|
1057
|
-
//#region src/services/shared/getMathExpressionSignatures.ts
|
|
1058
|
-
const getMathExpressionSignatures = (name) => getOwnValue(MathExpressionFunctionMap, name);
|
|
1059
|
-
//#endregion
|
|
1060
|
-
//#region src/services/compiler/getMathExpressionScalarCompute.ts
|
|
1061
|
-
const getMathExpressionScalarCompute = (name, key) => {
|
|
1062
|
-
const signature = getMathExpressionSignatures(name)?.[0];
|
|
1063
|
-
if (signature === void 0) return () => null;
|
|
1064
|
-
const scalarCompute = signature[key];
|
|
1065
|
-
if (scalarCompute !== void 0) return scalarCompute;
|
|
1066
|
-
return (...values) => signature.compute(values);
|
|
1067
|
-
};
|
|
1068
|
-
//#endregion
|
|
1069
|
-
//#region src/services/compiler/node/compileBinary.ts
|
|
1070
|
-
const compileBinary = (node, context) => {
|
|
1071
|
-
const { left, name, right } = node;
|
|
1072
|
-
const compiledLeft = context.compile(left);
|
|
1073
|
-
if (ADDITIVE_NAMES.includes(name) && right.type === "percentage" && !checkIsPercentageExpression(left)) {
|
|
1074
|
-
const compiledPercent = context.compile(right.operand);
|
|
1075
|
-
const sign = name === "add" ? 1 : -1;
|
|
1076
|
-
const evaluate = (values, locals) => {
|
|
1077
|
-
const base = compiledLeft.evaluate(values, locals);
|
|
1078
|
-
const percent = compiledPercent.evaluate(values, locals);
|
|
1079
|
-
if (base === null || percent === null) return null;
|
|
1080
|
-
return base + sign * base * (percent / 100);
|
|
1081
|
-
};
|
|
1082
|
-
return {
|
|
1083
|
-
evaluate,
|
|
1084
|
-
isConstant: compiledLeft.isConstant && compiledPercent.isConstant
|
|
1085
|
-
};
|
|
1086
|
-
}
|
|
1087
|
-
const compiledRight = context.compile(right);
|
|
1088
|
-
const compute = getMathExpressionScalarCompute(name, "computeBinary");
|
|
1089
|
-
const absorption = MathExpressionBitwiseAbsorptionMap[name];
|
|
1090
|
-
const evaluate = (values, locals) => {
|
|
1091
|
-
const leftValue = compiledLeft.evaluate(values, locals);
|
|
1092
|
-
if (leftValue === null) return null;
|
|
1093
|
-
if (absorption?.absorbs === leftValue) return absorption.result;
|
|
1094
|
-
const rightValue = compiledRight.evaluate(values, locals);
|
|
1095
|
-
if (rightValue === null) return null;
|
|
1096
|
-
return compute(leftValue, rightValue);
|
|
1097
|
-
};
|
|
1098
|
-
return {
|
|
1099
|
-
evaluate,
|
|
1100
|
-
isConstant: compiledLeft.isConstant && compiledRight.isConstant
|
|
1101
|
-
};
|
|
1102
|
-
};
|
|
1103
|
-
//#endregion
|
|
1104
|
-
//#region src/services/compiler/compileList.ts
|
|
1105
|
-
const compileList = (elements, context) => {
|
|
1106
|
-
const compiledElements = elements.map((element) => context.compile(element));
|
|
1107
|
-
return {
|
|
1108
|
-
evaluate: (values, locals) => {
|
|
1109
|
-
const numbers = [];
|
|
1110
|
-
for (const element of compiledElements) {
|
|
1111
|
-
const elementValue = element.evaluate(values, locals);
|
|
1112
|
-
if (elementValue === null) return null;
|
|
1113
|
-
numbers.push(elementValue);
|
|
1114
|
-
}
|
|
1115
|
-
return numbers;
|
|
1116
|
-
},
|
|
1117
|
-
isConstant: compiledElements.every((element) => element.isConstant)
|
|
1118
|
-
};
|
|
1119
|
-
};
|
|
1120
|
-
//#endregion
|
|
1121
|
-
//#region src/services/compiler/compileArgument.ts
|
|
1122
|
-
const compileArgument = (node, context) => {
|
|
1123
|
-
if (node.type === "list") return compileList(node.elements, context);
|
|
1124
|
-
return context.compile(node);
|
|
1125
|
-
};
|
|
1126
|
-
//#endregion
|
|
1127
|
-
//#region src/services/shared/getMathExpressionParameterType.ts
|
|
1128
|
-
const getMathExpressionParameterType = (node) => node.type === "list" ? "list" : "number";
|
|
1129
|
-
//#endregion
|
|
1130
|
-
//#region src/services/shared/checkIsMatchingKind.ts
|
|
1131
|
-
const checkIsMatchingKind = (parameterType, argumentType) => parameterType === "any" || parameterType === argumentType;
|
|
1132
|
-
//#endregion
|
|
1133
|
-
//#region src/services/shared/getParameterType.ts
|
|
1134
|
-
const getParameterType = (signature, index) => signature.parameters[Math.min(index, signature.parameters.length - 1)];
|
|
1135
|
-
//#endregion
|
|
1136
|
-
//#region src/services/shared/checkIsMatching.ts
|
|
1137
|
-
const checkIsMatching = (signature, parameterTypes) => parameterTypes.length >= signature.minArity && parameterTypes.length <= signature.maxArity && parameterTypes.every((parameterType, index) => checkIsMatchingKind(getParameterType(signature, index), parameterType));
|
|
1138
|
-
//#endregion
|
|
1139
|
-
//#region src/services/shared/matchMathExpressionSignature.ts
|
|
1140
|
-
const matchMathExpressionSignature = (signatures, parameterTypes) => signatures.find((signature) => checkIsMatching(signature, parameterTypes));
|
|
1141
|
-
//#endregion
|
|
1142
|
-
//#region src/services/compiler/node/compileCall.ts
|
|
1143
|
-
const compileCall = (node, context) => {
|
|
1144
|
-
const signatures = getMathExpressionSignatures(node.name);
|
|
1145
|
-
const parameterTypes = node.arguments.map((argument) => getMathExpressionParameterType(argument));
|
|
1146
|
-
const signature = matchMathExpressionSignature(signatures ?? [], parameterTypes);
|
|
1147
|
-
const compute = signature?.compute ?? (() => null);
|
|
1148
|
-
const computeUnary = signature?.computeUnary;
|
|
1149
|
-
const computeBinary = signature?.computeBinary;
|
|
1150
|
-
const compiledArguments = node.arguments.map((argument) => compileArgument(argument, context));
|
|
1151
|
-
const isConstant = compiledArguments.every((argument) => argument.isConstant);
|
|
1152
|
-
const [first, second] = compiledArguments;
|
|
1153
|
-
if (compiledArguments.length === 1 && first !== void 0) return {
|
|
1154
|
-
evaluate: (values, locals) => {
|
|
1155
|
-
const firstValue = first.evaluate(values, locals);
|
|
1156
|
-
if (firstValue === null) return null;
|
|
1157
|
-
if (computeUnary !== void 0 && typeof firstValue === "number") return computeUnary(firstValue);
|
|
1158
|
-
return compute([firstValue]);
|
|
1159
|
-
},
|
|
1160
|
-
isConstant
|
|
1161
|
-
};
|
|
1162
|
-
if (compiledArguments.length === 2 && first !== void 0 && second !== void 0) return {
|
|
1163
|
-
evaluate: (values, locals) => {
|
|
1164
|
-
const firstValue = first.evaluate(values, locals);
|
|
1165
|
-
if (firstValue === null) return null;
|
|
1166
|
-
const secondValue = second.evaluate(values, locals);
|
|
1167
|
-
if (secondValue === null) return null;
|
|
1168
|
-
if (computeBinary !== void 0 && typeof firstValue === "number" && typeof secondValue === "number") return computeBinary(firstValue, secondValue);
|
|
1169
|
-
return compute([firstValue, secondValue]);
|
|
1170
|
-
},
|
|
1171
|
-
isConstant
|
|
1172
|
-
};
|
|
1173
|
-
return {
|
|
1174
|
-
evaluate: (values, locals) => {
|
|
1175
|
-
const argumentValues = [];
|
|
1176
|
-
for (const argument of compiledArguments) {
|
|
1177
|
-
const argumentValue = argument.evaluate(values, locals);
|
|
1178
|
-
if (argumentValue === null) return null;
|
|
1179
|
-
argumentValues.push(argumentValue);
|
|
1180
|
-
}
|
|
1181
|
-
return compute(argumentValues);
|
|
1182
|
-
},
|
|
1183
|
-
isConstant
|
|
1184
|
-
};
|
|
1185
|
-
};
|
|
1186
|
-
//#endregion
|
|
1187
|
-
//#region src/services/compiler/node/compileComparison.ts
|
|
1188
|
-
const compileComparison = (node, context) => {
|
|
1189
|
-
const compiledOperands = node.operands.map((operand) => context.compile(operand));
|
|
1190
|
-
const computes = node.names.map((name) => getMathExpressionScalarCompute(name, "computeBinary"));
|
|
1191
|
-
const evaluate = (values, locals) => {
|
|
1192
|
-
let left = compiledOperands[0]?.evaluate(values, locals) ?? null;
|
|
1193
|
-
let result = 1;
|
|
1194
|
-
for (const [index, compute] of computes.entries()) {
|
|
1195
|
-
const right = compiledOperands[index + 1]?.evaluate(values, locals) ?? null;
|
|
1196
|
-
if (left === null || right === null) return null;
|
|
1197
|
-
result = compute(left, right);
|
|
1198
|
-
if (result !== 1) return result;
|
|
1199
|
-
left = right;
|
|
1200
|
-
}
|
|
1201
|
-
return result;
|
|
1202
|
-
};
|
|
1203
|
-
return {
|
|
1204
|
-
evaluate,
|
|
1205
|
-
isConstant: compiledOperands.every((operand) => operand.isConstant)
|
|
1206
|
-
};
|
|
1207
|
-
};
|
|
1208
|
-
//#endregion
|
|
1209
|
-
//#region src/services/compiler/node/compileConditional.ts
|
|
1210
|
-
const compileConditional = (node, context) => {
|
|
1211
|
-
const compiledCondition = context.compile(node.condition);
|
|
1212
|
-
const compiledWhenTrue = context.compile(node.whenTrue);
|
|
1213
|
-
const compiledWhenFalse = context.compile(node.whenFalse);
|
|
1214
|
-
const evaluate = (values, locals) => {
|
|
1215
|
-
const test = compiledCondition.evaluate(values, locals);
|
|
1216
|
-
if (test === null) return null;
|
|
1217
|
-
return checkIsTruthy(test) ? compiledWhenTrue.evaluate(values, locals) : compiledWhenFalse.evaluate(values, locals);
|
|
1218
|
-
};
|
|
1219
|
-
return {
|
|
1220
|
-
evaluate,
|
|
1221
|
-
isConstant: compiledCondition.isConstant && compiledWhenTrue.isConstant && compiledWhenFalse.isConstant
|
|
1222
|
-
};
|
|
1223
|
-
};
|
|
1224
|
-
//#endregion
|
|
1225
|
-
//#region src/services/compiler/node/compileGroup.ts
|
|
1226
|
-
const compileGroup = (node, context) => context.compile(node.operand);
|
|
1227
|
-
//#endregion
|
|
1228
|
-
//#region src/services/compiler/node/compileListNode.ts
|
|
1229
|
-
const compileListNode = () => ({
|
|
1230
|
-
evaluate: () => null,
|
|
1231
|
-
isConstant: false
|
|
1232
|
-
});
|
|
1233
|
-
//#endregion
|
|
1234
|
-
//#region src/services/compiler/node/compileLogical.ts
|
|
1235
|
-
const compileLogical = (node, context) => {
|
|
1236
|
-
const compiledLeft = context.compile(node.left);
|
|
1237
|
-
if (node.operator === "nullish") return compiledLeft;
|
|
1238
|
-
const compiledRight = context.compile(node.right);
|
|
1239
|
-
const isConstant = compiledLeft.isConstant && compiledRight.isConstant;
|
|
1240
|
-
switch (node.operator) {
|
|
1241
|
-
case "and": return {
|
|
1242
|
-
evaluate: (values, locals) => {
|
|
1243
|
-
const leftValue = compiledLeft.evaluate(values, locals);
|
|
1244
|
-
if (leftValue === null) return null;
|
|
1245
|
-
if (!checkIsTruthy(leftValue)) return 0;
|
|
1246
|
-
const rightValue = compiledRight.evaluate(values, locals);
|
|
1247
|
-
return rightValue === null ? null : toNumber(checkIsTruthy(rightValue));
|
|
1248
|
-
},
|
|
1249
|
-
isConstant
|
|
1250
|
-
};
|
|
1251
|
-
case "or": return {
|
|
1252
|
-
evaluate: (values, locals) => {
|
|
1253
|
-
const leftValue = compiledLeft.evaluate(values, locals);
|
|
1254
|
-
if (leftValue === null) return null;
|
|
1255
|
-
if (checkIsTruthy(leftValue)) return 1;
|
|
1256
|
-
const rightValue = compiledRight.evaluate(values, locals);
|
|
1257
|
-
return rightValue === null ? null : toNumber(checkIsTruthy(rightValue));
|
|
1258
|
-
},
|
|
1259
|
-
isConstant
|
|
1260
|
-
};
|
|
1261
|
-
default: return exhaustiveGuard(node.operator);
|
|
1262
|
-
}
|
|
1263
|
-
};
|
|
1264
|
-
//#endregion
|
|
1265
|
-
//#region src/services/shared/MathExpressionConstantMap.ts
|
|
1266
|
-
const MathExpressionConstantMap = {
|
|
1267
|
-
E: Math.E,
|
|
1268
|
-
e: Math.E,
|
|
1269
|
-
false: 0,
|
|
1270
|
-
Infinity: Number.POSITIVE_INFINITY,
|
|
1271
|
-
LN2: Math.LN2,
|
|
1272
|
-
LN10: Math.LN10,
|
|
1273
|
-
LOG2E: Math.LOG2E,
|
|
1274
|
-
LOG10E: Math.LOG10E,
|
|
1275
|
-
NaN: NaN,
|
|
1276
|
-
phi: (1 + Math.sqrt(5)) / 2,
|
|
1277
|
-
PI: Math.PI,
|
|
1278
|
-
pi: Math.PI,
|
|
1279
|
-
SQRT1_2: Math.SQRT1_2,
|
|
1280
|
-
SQRT2: Math.SQRT2,
|
|
1281
|
-
tau: 2 * Math.PI,
|
|
1282
|
-
true: 1
|
|
1283
|
-
};
|
|
1284
|
-
//#endregion
|
|
1285
|
-
//#region src/services/compiler/getMathExpressionConstant.ts
|
|
1286
|
-
const getMathExpressionConstant = (name) => getOwnValue(MathExpressionConstantMap, name);
|
|
1287
|
-
//#endregion
|
|
1288
|
-
//#region src/services/compiler/node/compileName.ts
|
|
1289
|
-
const compileName = (node, context) => {
|
|
1290
|
-
const slot = context.assignedSlots.get(node.name);
|
|
1291
|
-
if (slot !== void 0) return {
|
|
1292
|
-
evaluate: (_values, locals) => locals[slot] ?? null,
|
|
1293
|
-
isConstant: false
|
|
1294
|
-
};
|
|
1295
|
-
const index = context.variableIndices.get(node.name);
|
|
1296
|
-
if (index !== void 0) return {
|
|
1297
|
-
evaluate: (values) => values[index] ?? NaN,
|
|
1298
|
-
isConstant: false
|
|
1299
|
-
};
|
|
1300
|
-
const constant = getMathExpressionConstant(node.name);
|
|
1301
|
-
return {
|
|
1302
|
-
evaluate: () => constant ?? null,
|
|
1303
|
-
isConstant: true
|
|
1304
|
-
};
|
|
1305
|
-
};
|
|
1306
|
-
//#endregion
|
|
1307
|
-
//#region src/services/compiler/node/compileNumber.ts
|
|
1308
|
-
const compileNumber = (node) => {
|
|
1309
|
-
const { value } = node;
|
|
1310
|
-
return {
|
|
1311
|
-
evaluate: () => value,
|
|
1312
|
-
isConstant: true
|
|
1313
|
-
};
|
|
1314
|
-
};
|
|
1315
|
-
//#endregion
|
|
1316
|
-
//#region src/services/compiler/node/compilePercentage.ts
|
|
1317
|
-
const compilePercentage = (node, context) => {
|
|
1318
|
-
const compiledOperand = context.compile(node.operand);
|
|
1319
|
-
return {
|
|
1320
|
-
evaluate: (values, locals) => {
|
|
1321
|
-
const operandValue = compiledOperand.evaluate(values, locals);
|
|
1322
|
-
return operandValue === null ? null : operandValue / 100;
|
|
1323
|
-
},
|
|
1324
|
-
isConstant: compiledOperand.isConstant
|
|
1325
|
-
};
|
|
1326
|
-
};
|
|
1327
|
-
//#endregion
|
|
1328
|
-
//#region src/services/compiler/node/compileUnary.ts
|
|
1329
|
-
const compileUnary = (node, context) => {
|
|
1330
|
-
const compute = getMathExpressionScalarCompute(node.name, "computeUnary");
|
|
1331
|
-
const compiledOperand = context.compile(node.operand);
|
|
1332
|
-
return {
|
|
1333
|
-
evaluate: (values, locals) => {
|
|
1334
|
-
const operandValue = compiledOperand.evaluate(values, locals);
|
|
1335
|
-
return operandValue === null ? null : compute(operandValue);
|
|
1336
|
-
},
|
|
1337
|
-
isConstant: compiledOperand.isConstant
|
|
1338
|
-
};
|
|
1339
|
-
};
|
|
1340
|
-
//#endregion
|
|
1341
|
-
//#region src/services/compiler/MathExpressionNodeCompileMap.ts
|
|
1342
|
-
const MathExpressionNodeCompileMap = {
|
|
1343
|
-
["assignment"]: compileAssignment,
|
|
1344
|
-
["binary"]: compileBinary,
|
|
1345
|
-
["call"]: compileCall,
|
|
1346
|
-
["comparison"]: compileComparison,
|
|
1347
|
-
["conditional"]: compileConditional,
|
|
1348
|
-
["group"]: compileGroup,
|
|
1349
|
-
["list"]: compileListNode,
|
|
1350
|
-
["logical"]: compileLogical,
|
|
1351
|
-
["name"]: compileName,
|
|
1352
|
-
["number"]: compileNumber,
|
|
1353
|
-
["percentage"]: compilePercentage,
|
|
1354
|
-
["unary"]: compileUnary
|
|
1355
|
-
};
|
|
1356
|
-
//#endregion
|
|
1357
|
-
//#region src/services/shared/getMathExpressionChildren.ts
|
|
1358
|
-
const getMathExpressionChildren = (node) => {
|
|
1359
|
-
switch (node.type) {
|
|
1360
|
-
case "assignment": return [node.value];
|
|
1361
|
-
case "binary":
|
|
1362
|
-
case "logical": return [node.left, node.right];
|
|
1363
|
-
case "call": return node.arguments;
|
|
1364
|
-
case "comparison": return node.operands;
|
|
1365
|
-
case "conditional": return [
|
|
1366
|
-
node.condition,
|
|
1367
|
-
node.whenTrue,
|
|
1368
|
-
node.whenFalse
|
|
1369
|
-
];
|
|
1370
|
-
case "group":
|
|
1371
|
-
case "percentage":
|
|
1372
|
-
case "unary": return [node.operand];
|
|
1373
|
-
case "list": return node.elements;
|
|
1374
|
-
case "name":
|
|
1375
|
-
case "number": return [];
|
|
1376
|
-
default: return exhaustiveGuard(node);
|
|
1377
|
-
}
|
|
1378
|
-
};
|
|
1379
|
-
//#endregion
|
|
1380
|
-
//#region src/services/compiler/collectMathExpressionAssignedNames.ts
|
|
1381
|
-
const collectMathExpressionAssignedNames = (node, names) => {
|
|
1382
|
-
if (node.type === "assignment") names.add(node.name);
|
|
1383
|
-
for (const child of getMathExpressionChildren(node)) collectMathExpressionAssignedNames(child, names);
|
|
1384
|
-
};
|
|
1385
|
-
//#endregion
|
|
1386
|
-
//#region src/services/compiler/compileMathExpressionNode.ts
|
|
1387
|
-
const compileMathExpressionNode = (node, context) => {
|
|
1388
|
-
const compileOfType = MathExpressionNodeCompileMap[node.type];
|
|
1389
|
-
const compiled = compileOfType(node, context);
|
|
1390
|
-
if (!compiled.isConstant) return compiled;
|
|
1391
|
-
const value = compiled.evaluate(NO_VALUES, NO_LOCALS);
|
|
1392
|
-
return {
|
|
1393
|
-
evaluate: () => value,
|
|
1394
|
-
isConstant: true
|
|
1395
|
-
};
|
|
1396
|
-
};
|
|
1397
|
-
//#endregion
|
|
1398
|
-
//#region src/services/compiler/getMathExpressionOuterValue.ts
|
|
1399
|
-
const getMathExpressionOuterValue = (outer, values) => {
|
|
1400
|
-
if (outer.variableIndex !== void 0) return values[outer.variableIndex] ?? NaN;
|
|
1401
|
-
return outer.constant ?? null;
|
|
1402
|
-
};
|
|
1403
|
-
//#endregion
|
|
1404
|
-
//#region src/services/compiler/compileMathExpression.ts
|
|
1405
|
-
const compileMathExpression = (node, variableNames) => {
|
|
1406
|
-
const assignedNames = /* @__PURE__ */ new Set();
|
|
1407
|
-
collectMathExpressionAssignedNames(node, assignedNames);
|
|
1408
|
-
const assignedSlots = new Map(Array.from(assignedNames, (name, slot) => [name, slot]));
|
|
1409
|
-
const variableIndices = new Map(variableNames.map((name, index) => [name, index]));
|
|
1410
|
-
const context = {
|
|
1411
|
-
assignedSlots,
|
|
1412
|
-
compile: (child) => compileMathExpressionNode(child, context),
|
|
1413
|
-
variableIndices
|
|
1414
|
-
};
|
|
1415
|
-
const compiled = context.compile(node);
|
|
1416
|
-
const outerBindings = Array.from(assignedNames, (name) => ({
|
|
1417
|
-
constant: getMathExpressionConstant(name),
|
|
1418
|
-
variableIndex: variableIndices.get(name)
|
|
1419
|
-
}));
|
|
1420
|
-
return (values) => {
|
|
1421
|
-
const locals = outerBindings.length === 0 ? NO_LOCALS : outerBindings.map((outer) => getMathExpressionOuterValue(outer, values));
|
|
1422
|
-
return compiled.evaluate(values, locals) ?? NaN;
|
|
1423
|
-
};
|
|
1424
|
-
};
|
|
1425
|
-
//#endregion
|
|
1426
|
-
//#region src/services/names/walkNode.ts
|
|
1427
|
-
const walkNode = (node, bound, free) => {
|
|
1428
|
-
switch (node.type) {
|
|
1429
|
-
case "assignment":
|
|
1430
|
-
walkNode(node.value, bound, free);
|
|
1431
|
-
bound.add(node.name);
|
|
1432
|
-
return;
|
|
1433
|
-
case "binary": {
|
|
1434
|
-
walkNode(node.left, bound, free);
|
|
1435
|
-
const rightBound = Object.hasOwn(MathExpressionBitwiseAbsorptionMap, node.name) ? new Set(bound) : bound;
|
|
1436
|
-
walkNode(node.right, rightBound, free);
|
|
1437
|
-
return;
|
|
1438
|
-
}
|
|
1439
|
-
case "call":
|
|
1440
|
-
case "group":
|
|
1441
|
-
case "list":
|
|
1442
|
-
case "number":
|
|
1443
|
-
case "percentage":
|
|
1444
|
-
case "unary":
|
|
1445
|
-
for (const child of getMathExpressionChildren(node)) walkNode(child, bound, free);
|
|
1446
|
-
return;
|
|
1447
|
-
case "comparison": {
|
|
1448
|
-
let chainBound = bound;
|
|
1449
|
-
for (const [index, operand] of node.operands.entries()) {
|
|
1450
|
-
if (index === 2) chainBound = new Set(bound);
|
|
1451
|
-
walkNode(operand, chainBound, free);
|
|
1452
|
-
}
|
|
1453
|
-
return;
|
|
1454
|
-
}
|
|
1455
|
-
case "conditional": {
|
|
1456
|
-
walkNode(node.condition, bound, free);
|
|
1457
|
-
const whenTrueBound = new Set(bound);
|
|
1458
|
-
const whenFalseBound = new Set(bound);
|
|
1459
|
-
walkNode(node.whenTrue, whenTrueBound, free);
|
|
1460
|
-
walkNode(node.whenFalse, whenFalseBound, free);
|
|
1461
|
-
for (const name of whenTrueBound) if (whenFalseBound.has(name)) bound.add(name);
|
|
1462
|
-
return;
|
|
1463
|
-
}
|
|
1464
|
-
case "logical":
|
|
1465
|
-
walkNode(node.left, bound, free);
|
|
1466
|
-
if (node.operator !== "nullish") walkNode(node.right, new Set(bound), free);
|
|
1467
|
-
return;
|
|
1468
|
-
case "name":
|
|
1469
|
-
if (!bound.has(node.name)) free.add(node.name);
|
|
1470
|
-
return;
|
|
1471
|
-
default: return exhaustiveGuard(node);
|
|
1472
|
-
}
|
|
1473
|
-
};
|
|
1474
|
-
//#endregion
|
|
1475
|
-
//#region src/services/names/getMathExpressionNames.ts
|
|
1476
|
-
const getMathExpressionNames = (node) => {
|
|
1477
|
-
const bound = /* @__PURE__ */ new Set();
|
|
1478
|
-
const free = /* @__PURE__ */ new Set();
|
|
1479
|
-
walkNode(node, bound, free);
|
|
1480
|
-
return [...free].filter((name) => getMathExpressionConstant(name) === void 0);
|
|
1481
|
-
};
|
|
1482
|
-
//#endregion
|
|
1483
|
-
//#region src/services/parser/MathExpressionBinaryOperatorMap.ts
|
|
1484
|
-
const MathExpressionBinaryOperatorMap = {
|
|
1485
|
-
"!=": {
|
|
1486
|
-
name: "unequal",
|
|
1487
|
-
power: 7,
|
|
1488
|
-
type: "comparison"
|
|
1489
|
-
},
|
|
1490
|
-
"%": {
|
|
1491
|
-
name: "mod",
|
|
1492
|
-
power: 10,
|
|
1493
|
-
type: "binary"
|
|
1494
|
-
},
|
|
1495
|
-
"&": {
|
|
1496
|
-
name: "bitAnd",
|
|
1497
|
-
power: 6,
|
|
1498
|
-
type: "binary"
|
|
1499
|
-
},
|
|
1500
|
-
"*": {
|
|
1501
|
-
name: "multiply",
|
|
1502
|
-
power: 10,
|
|
1503
|
-
type: "binary"
|
|
1504
|
-
},
|
|
1505
|
-
"+": {
|
|
1506
|
-
name: "add",
|
|
1507
|
-
power: 9,
|
|
1508
|
-
type: "binary"
|
|
1509
|
-
},
|
|
1510
|
-
"-": {
|
|
1511
|
-
name: "subtract",
|
|
1512
|
-
power: 9,
|
|
1513
|
-
type: "binary"
|
|
1514
|
-
},
|
|
1515
|
-
".*": {
|
|
1516
|
-
name: "dotMultiply",
|
|
1517
|
-
power: 10,
|
|
1518
|
-
type: "binary"
|
|
1519
|
-
},
|
|
1520
|
-
"./": {
|
|
1521
|
-
name: "dotDivide",
|
|
1522
|
-
power: 10,
|
|
1523
|
-
type: "binary"
|
|
1524
|
-
},
|
|
1525
|
-
"/": {
|
|
1526
|
-
name: "divide",
|
|
1527
|
-
power: 10,
|
|
1528
|
-
type: "binary"
|
|
1529
|
-
},
|
|
1530
|
-
"<": {
|
|
1531
|
-
name: "smaller",
|
|
1532
|
-
power: 7,
|
|
1533
|
-
type: "comparison"
|
|
1534
|
-
},
|
|
1535
|
-
"<<": {
|
|
1536
|
-
name: "leftShift",
|
|
1537
|
-
power: 8,
|
|
1538
|
-
type: "binary"
|
|
1539
|
-
},
|
|
1540
|
-
"<=": {
|
|
1541
|
-
name: "smallerEq",
|
|
1542
|
-
power: 7,
|
|
1543
|
-
type: "comparison"
|
|
1544
|
-
},
|
|
1545
|
-
"==": {
|
|
1546
|
-
name: "equal",
|
|
1547
|
-
power: 7,
|
|
1548
|
-
type: "comparison"
|
|
1549
|
-
},
|
|
1550
|
-
">": {
|
|
1551
|
-
name: "larger",
|
|
1552
|
-
power: 7,
|
|
1553
|
-
type: "comparison"
|
|
1554
|
-
},
|
|
1555
|
-
">=": {
|
|
1556
|
-
name: "largerEq",
|
|
1557
|
-
power: 7,
|
|
1558
|
-
type: "comparison"
|
|
1559
|
-
},
|
|
1560
|
-
">>": {
|
|
1561
|
-
name: "rightArithShift",
|
|
1562
|
-
power: 8,
|
|
1563
|
-
type: "binary"
|
|
1564
|
-
},
|
|
1565
|
-
">>>": {
|
|
1566
|
-
name: "rightLogShift",
|
|
1567
|
-
power: 8,
|
|
1568
|
-
type: "binary"
|
|
1569
|
-
},
|
|
1570
|
-
"^|": {
|
|
1571
|
-
name: "bitXor",
|
|
1572
|
-
power: 5,
|
|
1573
|
-
type: "binary"
|
|
1574
|
-
},
|
|
1575
|
-
and: {
|
|
1576
|
-
operator: "and",
|
|
1577
|
-
power: 3,
|
|
1578
|
-
type: "logical"
|
|
1579
|
-
},
|
|
1580
|
-
mod: {
|
|
1581
|
-
name: "mod",
|
|
1582
|
-
power: 10,
|
|
1583
|
-
type: "binary"
|
|
1584
|
-
},
|
|
1585
|
-
or: {
|
|
1586
|
-
operator: "or",
|
|
1587
|
-
power: 1,
|
|
1588
|
-
type: "logical"
|
|
1589
|
-
},
|
|
1590
|
-
xor: {
|
|
1591
|
-
name: "xor",
|
|
1592
|
-
power: 2,
|
|
1593
|
-
type: "binary"
|
|
1594
|
-
},
|
|
1595
|
-
"|": {
|
|
1596
|
-
name: "bitOr",
|
|
1597
|
-
power: 4,
|
|
1598
|
-
type: "binary"
|
|
1599
|
-
}
|
|
1600
|
-
};
|
|
1601
|
-
//#endregion
|
|
1602
|
-
//#region src/services/parser/MathExpressionOperatorMap.ts
|
|
1603
|
-
const MathExpressionOperatorMap = {
|
|
1604
|
-
["Nullish"]: { "??": "nullish" },
|
|
1605
|
-
["Power"]: {
|
|
1606
|
-
".^": "dotPow",
|
|
1607
|
-
"^": "pow"
|
|
1608
|
-
},
|
|
1609
|
-
["Unary"]: {
|
|
1610
|
-
"+": "unaryPlus",
|
|
1611
|
-
"-": "unaryMinus",
|
|
1612
|
-
not: "not",
|
|
1613
|
-
"~": "bitNot"
|
|
1614
|
-
}
|
|
1615
|
-
};
|
|
1616
|
-
//#endregion
|
|
1617
|
-
//#region src/services/parser/constants.ts
|
|
1618
|
-
const MAX_MATH_EXPRESSION_DEPTH = 64;
|
|
1619
|
-
const PLACEHOLDER = {
|
|
1620
|
-
type: "number",
|
|
1621
|
-
value: NaN
|
|
1622
|
-
};
|
|
1623
|
-
//#endregion
|
|
1624
|
-
//#region src/services/parser/failMathExpressionAt.ts
|
|
1625
|
-
const failMathExpressionAt = (state, message, column) => {
|
|
1626
|
-
if (state.error !== null) return;
|
|
1627
|
-
state.error = new MathExpressionError(`${message} (char ${column})`);
|
|
1628
|
-
};
|
|
1629
|
-
//#endregion
|
|
1630
|
-
//#region src/services/parser/getMathExpressionColumn.ts
|
|
1631
|
-
const getMathExpressionColumn = (state) => state.index - state.token.length + 1;
|
|
1632
|
-
//#endregion
|
|
1633
|
-
//#region src/services/parser/failMathExpression.ts
|
|
1634
|
-
const failMathExpression = (state, message) => failMathExpressionAt(state, message, getMathExpressionColumn(state));
|
|
1635
|
-
//#endregion
|
|
1636
|
-
//#region src/services/parser/checkCanMathExpressionNest.ts
|
|
1637
|
-
const checkCanMathExpressionNest = (state) => {
|
|
1638
|
-
if (state.depth < 64) return true;
|
|
1639
|
-
failMathExpression(state, `Formula nests deeper than 64 levels`);
|
|
1640
|
-
return false;
|
|
1641
|
-
};
|
|
1642
|
-
//#endregion
|
|
1643
|
-
//#region src/services/parser/checkIsToken.ts
|
|
1644
|
-
const checkIsToken = (state, token) => state.token === token;
|
|
1645
|
-
//#endregion
|
|
1646
|
-
//#region src/services/parser/token/checkIsDigitCharacter.ts
|
|
1647
|
-
const checkIsDigitCharacter = (character) => character >= "0" && character <= "9";
|
|
1648
|
-
//#endregion
|
|
1649
|
-
//#region src/services/parser/token/constants.ts
|
|
1650
|
-
const DELIMITERS_OF_THREE = /* @__PURE__ */ new Set([">>>"]);
|
|
1651
|
-
const DELIMITERS_OF_TWO = /* @__PURE__ */ new Set([
|
|
1652
|
-
"!=",
|
|
1653
|
-
".*",
|
|
1654
|
-
"./",
|
|
1655
|
-
".^",
|
|
1656
|
-
"<<",
|
|
1657
|
-
"<=",
|
|
1658
|
-
"==",
|
|
1659
|
-
">=",
|
|
1660
|
-
">>",
|
|
1661
|
-
"??",
|
|
1662
|
-
"^|"
|
|
1663
|
-
]);
|
|
1664
|
-
const DELIMITERS_OF_ONE = /* @__PURE__ */ new Set([
|
|
1665
|
-
"!",
|
|
1666
|
-
"%",
|
|
1667
|
-
"&",
|
|
1668
|
-
"'",
|
|
1669
|
-
"(",
|
|
1670
|
-
")",
|
|
1671
|
-
"*",
|
|
1672
|
-
"+",
|
|
1673
|
-
",",
|
|
1674
|
-
"-",
|
|
1675
|
-
"/",
|
|
1676
|
-
":",
|
|
1677
|
-
"<",
|
|
1678
|
-
"=",
|
|
1679
|
-
">",
|
|
1680
|
-
"?",
|
|
1681
|
-
"[",
|
|
1682
|
-
"]",
|
|
1683
|
-
"^",
|
|
1684
|
-
"|",
|
|
1685
|
-
"~"
|
|
1686
|
-
]);
|
|
1687
|
-
const FIRST_CHARACTERS_OF_THREE = new Set(Array.from(DELIMITERS_OF_THREE, (delimiter) => delimiter.charAt(0)));
|
|
1688
|
-
const FIRST_CHARACTERS_OF_TWO = new Set(Array.from(DELIMITERS_OF_TWO, (delimiter) => delimiter.charAt(0)));
|
|
1689
|
-
const NAMED_DELIMITERS = /* @__PURE__ */ new Set([
|
|
1690
|
-
"and",
|
|
1691
|
-
"in",
|
|
1692
|
-
"mod",
|
|
1693
|
-
"not",
|
|
1694
|
-
"or",
|
|
1695
|
-
"to",
|
|
1696
|
-
"xor"
|
|
1697
|
-
]);
|
|
1698
|
-
const DECIMAL_MARK_OPERATOR_FOLLOWERS = /* @__PURE__ */ new Set([
|
|
1699
|
-
"*",
|
|
1700
|
-
"/",
|
|
1701
|
-
"^"
|
|
1702
|
-
]);
|
|
1703
|
-
const WORD_START_REGEX = /^[\p{L}_$]$/u;
|
|
1704
|
-
const WORD_CHARACTER_REGEX = /^[\p{L}\p{Nd}_$]$/u;
|
|
1705
|
-
//#endregion
|
|
1706
|
-
//#region src/services/parser/token/checkIsWordStartCharacter.ts
|
|
1707
|
-
const checkIsWordStartCharacter = (character) => {
|
|
1708
|
-
if (character >= "") return WORD_START_REGEX.test(character);
|
|
1709
|
-
return character >= "a" && character <= "z" || character >= "A" && character <= "Z" || character === "_" || character === "$";
|
|
1710
|
-
};
|
|
1711
|
-
//#endregion
|
|
1712
|
-
//#region src/services/parser/token/getMathExpressionCharacter.ts
|
|
1713
|
-
const getMathExpressionCharacter = (state, offset) => state.source.charAt(state.index + offset);
|
|
1714
|
-
//#endregion
|
|
1715
|
-
//#region src/services/parser/token/readMathExpressionDelimiter.ts
|
|
1716
|
-
const readMathExpressionDelimiter = (state) => {
|
|
1717
|
-
const character = getMathExpressionCharacter(state, 0);
|
|
1718
|
-
let length = 0;
|
|
1719
|
-
if (FIRST_CHARACTERS_OF_THREE.has(character) && DELIMITERS_OF_THREE.has(state.source.slice(state.index, state.index + 3))) length = 3;
|
|
1720
|
-
else if (FIRST_CHARACTERS_OF_TWO.has(character) && DELIMITERS_OF_TWO.has(state.source.slice(state.index, state.index + 2))) length = 2;
|
|
1721
|
-
else if (DELIMITERS_OF_ONE.has(character)) length = 1;
|
|
1722
|
-
if (length === 0) return 0;
|
|
1723
|
-
state.token = state.source.slice(state.index, state.index + length);
|
|
1724
|
-
state.index += length;
|
|
1725
|
-
state.tokenType = "delimiter";
|
|
1726
|
-
if (["(", "["].includes(state.token)) state.nestingLevel++;
|
|
1727
|
-
if ([")", "]"].includes(state.token)) state.nestingLevel--;
|
|
1728
|
-
return length;
|
|
1729
|
-
};
|
|
1730
|
-
//#endregion
|
|
1731
|
-
//#region src/services/parser/token/MathExpressionRadixMap.ts
|
|
1732
|
-
const MathExpressionRadixMap = {
|
|
1733
|
-
b: {
|
|
1734
|
-
digit: /^[01]$/u,
|
|
1735
|
-
radix: 2
|
|
1736
|
-
},
|
|
1737
|
-
o: {
|
|
1738
|
-
digit: /^[0-7]$/u,
|
|
1739
|
-
radix: 8
|
|
1740
|
-
},
|
|
1741
|
-
x: {
|
|
1742
|
-
digit: /^[0-9a-fA-F]$/u,
|
|
1743
|
-
radix: 16
|
|
1744
|
-
}
|
|
1745
|
-
};
|
|
1746
|
-
//#endregion
|
|
1747
|
-
//#region src/services/parser/token/takeMathExpressionMatching.ts
|
|
1748
|
-
const takeMathExpressionMatching = (state, checkCharacter) => {
|
|
1749
|
-
const start = state.index;
|
|
1750
|
-
while (checkCharacter(getMathExpressionCharacter(state, 0))) state.index++;
|
|
1751
|
-
return state.source.slice(start, state.index);
|
|
1752
|
-
};
|
|
1753
|
-
//#endregion
|
|
1754
|
-
//#region src/services/parser/token/readRadixNumber.ts
|
|
1755
|
-
const readRadixNumber = (state, prefix, baseDigits) => {
|
|
1756
|
-
const checkBaseDigit = (character) => baseDigits.test(character);
|
|
1757
|
-
state.index += 2;
|
|
1758
|
-
let digits = takeMathExpressionMatching(state, checkBaseDigit);
|
|
1759
|
-
if (digits === "") {
|
|
1760
|
-
state.index--;
|
|
1761
|
-
state.token = "0";
|
|
1762
|
-
state.tokenType = "number";
|
|
1763
|
-
return;
|
|
1764
|
-
}
|
|
1765
|
-
if (getMathExpressionCharacter(state, 0) === ".") {
|
|
1766
|
-
state.index++;
|
|
1767
|
-
digits += `.${takeMathExpressionMatching(state, checkBaseDigit)}`;
|
|
1768
|
-
}
|
|
1769
|
-
let wordSize = "";
|
|
1770
|
-
if (getMathExpressionCharacter(state, 0) === "i" && checkIsDigitCharacter(getMathExpressionCharacter(state, 1))) {
|
|
1771
|
-
state.index++;
|
|
1772
|
-
wordSize = `i${takeMathExpressionMatching(state, checkIsDigitCharacter)}`;
|
|
1773
|
-
}
|
|
1774
|
-
state.token = `0${prefix}${digits}${wordSize}`;
|
|
1775
|
-
state.tokenType = "number";
|
|
1776
|
-
};
|
|
1777
|
-
//#endregion
|
|
1778
|
-
//#region src/services/parser/token/checkIsDecimalMark.ts
|
|
1779
|
-
const checkIsDecimalMark = (character, nextCharacter) => character === "." && !DECIMAL_MARK_OPERATOR_FOLLOWERS.has(nextCharacter);
|
|
1780
|
-
//#endregion
|
|
1781
|
-
//#region src/services/parser/token/failExponent.ts
|
|
1782
|
-
const failExponent = (state, text) => {
|
|
1783
|
-
state.token = text;
|
|
1784
|
-
failMathExpression(state, `Digit expected, got "${getMathExpressionCharacter(state, 0)}"`);
|
|
1785
|
-
};
|
|
1786
|
-
//#endregion
|
|
1787
|
-
//#region src/services/parser/token/takeExponent.ts
|
|
1788
|
-
const takeExponent = (state, text) => {
|
|
1789
|
-
const exponentMarker = getMathExpressionCharacter(state, 0);
|
|
1790
|
-
if (!["e", "E"].includes(exponentMarker)) return text;
|
|
1791
|
-
const afterMarker = getMathExpressionCharacter(state, 1);
|
|
1792
|
-
if (checkIsDecimalMark(afterMarker, getMathExpressionCharacter(state, 2))) {
|
|
1793
|
-
state.index++;
|
|
1794
|
-
failExponent(state, text);
|
|
1795
|
-
return text;
|
|
1796
|
-
}
|
|
1797
|
-
if (!checkIsDigitCharacter(afterMarker) && !["+", "-"].includes(afterMarker)) return text;
|
|
1798
|
-
state.index++;
|
|
1799
|
-
let exponent = "e";
|
|
1800
|
-
if (["+", "-"].includes(afterMarker)) {
|
|
1801
|
-
exponent += afterMarker;
|
|
1802
|
-
state.index++;
|
|
1803
|
-
}
|
|
1804
|
-
if (!checkIsDigitCharacter(getMathExpressionCharacter(state, 0))) {
|
|
1805
|
-
const partial = text + exponent;
|
|
1806
|
-
failExponent(state, partial);
|
|
1807
|
-
return partial;
|
|
1808
|
-
}
|
|
1809
|
-
const taken = text + exponent + takeMathExpressionMatching(state, checkIsDigitCharacter);
|
|
1810
|
-
if (checkIsDecimalMark(getMathExpressionCharacter(state, 0), getMathExpressionCharacter(state, 1))) failExponent(state, taken);
|
|
1811
|
-
return taken;
|
|
1812
|
-
};
|
|
1813
|
-
//#endregion
|
|
1814
|
-
//#region src/services/parser/token/readMathExpressionNumber.ts
|
|
1815
|
-
const readMathExpressionNumber = (state) => {
|
|
1816
|
-
const prefix = getMathExpressionCharacter(state, 1);
|
|
1817
|
-
const radixEntry = MathExpressionRadixMap[prefix];
|
|
1818
|
-
if (getMathExpressionCharacter(state, 0) === "0" && radixEntry !== void 0) {
|
|
1819
|
-
readRadixNumber(state, prefix, radixEntry.digit);
|
|
1820
|
-
return;
|
|
1821
|
-
}
|
|
1822
|
-
const start = state.index;
|
|
1823
|
-
takeMathExpressionMatching(state, checkIsDigitCharacter);
|
|
1824
|
-
if (getMathExpressionCharacter(state, 0) === ".") {
|
|
1825
|
-
state.index++;
|
|
1826
|
-
takeMathExpressionMatching(state, checkIsDigitCharacter);
|
|
1827
|
-
}
|
|
1828
|
-
state.token = takeExponent(state, state.source.slice(start, state.index));
|
|
1829
|
-
state.tokenType = "number";
|
|
1830
|
-
};
|
|
1831
|
-
//#endregion
|
|
1832
|
-
//#region src/services/parser/token/checkIsWordCharacter.ts
|
|
1833
|
-
const checkIsWordCharacter = (character) => {
|
|
1834
|
-
if (character >= "") return WORD_CHARACTER_REGEX.test(character);
|
|
1835
|
-
return checkIsWordStartCharacter(character) || checkIsDigitCharacter(character);
|
|
1836
|
-
};
|
|
1837
|
-
//#endregion
|
|
1838
|
-
//#region src/services/parser/token/readMathExpressionWord.ts
|
|
1839
|
-
const readMathExpressionWord = (state) => {
|
|
1840
|
-
state.token = takeMathExpressionMatching(state, checkIsWordCharacter);
|
|
1841
|
-
state.tokenType = NAMED_DELIMITERS.has(state.token) ? "delimiter" : "symbol";
|
|
1842
|
-
};
|
|
1843
|
-
//#endregion
|
|
1844
|
-
//#region src/services/parser/token/skipMathExpressionSpaces.ts
|
|
1845
|
-
const skipMathExpressionSpaces = (state) => {
|
|
1846
|
-
while (state.index < state.source.length) {
|
|
1847
|
-
const character = getMathExpressionCharacter(state, 0);
|
|
1848
|
-
if ([
|
|
1849
|
-
" ",
|
|
1850
|
-
" ",
|
|
1851
|
-
"\xA0"
|
|
1852
|
-
].includes(character) || character === "\n" && state.nestingLevel > 0) state.index++;
|
|
1853
|
-
else if (character === "#") while (state.index < state.source.length && getMathExpressionCharacter(state, 0) !== "\n") state.index++;
|
|
1854
|
-
else break;
|
|
1855
|
-
}
|
|
1856
|
-
};
|
|
1857
|
-
//#endregion
|
|
1858
|
-
//#region src/services/parser/getMathExpressionToken.ts
|
|
1859
|
-
const getMathExpressionToken = (state) => {
|
|
1860
|
-
state.token = "";
|
|
1861
|
-
state.tokenType = "null";
|
|
1862
|
-
skipMathExpressionSpaces(state);
|
|
1863
|
-
if (state.index >= state.source.length || state.error !== null) return;
|
|
1864
|
-
const character = getMathExpressionCharacter(state, 0);
|
|
1865
|
-
const next = getMathExpressionCharacter(state, 1);
|
|
1866
|
-
if (checkIsDigitCharacter(character) || character === "." && checkIsDigitCharacter(next)) readMathExpressionNumber(state);
|
|
1867
|
-
else if (checkIsWordStartCharacter(character)) readMathExpressionWord(state);
|
|
1868
|
-
else if (readMathExpressionDelimiter(state) === 0) {
|
|
1869
|
-
state.token = character;
|
|
1870
|
-
state.index++;
|
|
1871
|
-
state.tokenType = "unknown";
|
|
1872
|
-
}
|
|
1873
|
-
};
|
|
1874
|
-
//#endregion
|
|
1875
|
-
//#region src/services/parser/rule/parseAssignment.ts
|
|
1876
|
-
const parseAssignment = (state, parse) => {
|
|
1877
|
-
if (!checkCanMathExpressionNest(state)) return PLACEHOLDER;
|
|
1878
|
-
state.depth++;
|
|
1879
|
-
const left = parse(state, "Conditional");
|
|
1880
|
-
let node = left;
|
|
1881
|
-
if (state.error === null && checkIsToken(state, "=")) if (left.type === "name") {
|
|
1882
|
-
getMathExpressionToken(state);
|
|
1883
|
-
const value = parse(state, "Assignment");
|
|
1884
|
-
node = {
|
|
1885
|
-
name: left.name,
|
|
1886
|
-
type: "assignment",
|
|
1887
|
-
value
|
|
1888
|
-
};
|
|
1889
|
-
} else failMathExpression(state, "Invalid left hand side of assignment operator =");
|
|
1890
|
-
state.depth--;
|
|
1891
|
-
return node;
|
|
1892
|
-
};
|
|
1893
|
-
//#endregion
|
|
1894
|
-
//#region src/services/parser/createBinaryNode.ts
|
|
1895
|
-
const createBinaryNode = (left, name, right) => ({
|
|
1896
|
-
left,
|
|
1897
|
-
name,
|
|
1898
|
-
right,
|
|
1899
|
-
type: "binary"
|
|
1900
|
-
});
|
|
1901
|
-
//#endregion
|
|
1902
|
-
//#region src/services/parser/createLogicalNode.ts
|
|
1903
|
-
const createLogicalNode = (left, operator, right) => ({
|
|
1904
|
-
left,
|
|
1905
|
-
operator,
|
|
1906
|
-
right,
|
|
1907
|
-
type: "logical"
|
|
1908
|
-
});
|
|
1909
|
-
//#endregion
|
|
1910
|
-
//#region src/services/parser/createBinaryOperation.ts
|
|
1911
|
-
const createBinaryOperation = (left, operator, right) => {
|
|
1912
|
-
if (operator.type === "logical") return createLogicalNode(left, operator.operator, right);
|
|
1913
|
-
if (operator.type === "binary") return createBinaryNode(left, operator.name, right);
|
|
1914
|
-
if (left.type === "comparison") {
|
|
1915
|
-
left.names.push(operator.name);
|
|
1916
|
-
left.operands.push(right);
|
|
1917
|
-
return left;
|
|
1918
|
-
}
|
|
1919
|
-
return {
|
|
1920
|
-
names: [operator.name],
|
|
1921
|
-
operands: [left, right],
|
|
1922
|
-
type: "comparison"
|
|
1923
|
-
};
|
|
1924
|
-
};
|
|
1925
|
-
//#endregion
|
|
1926
|
-
//#region src/services/parser/parseBinaryOperators.ts
|
|
1927
|
-
const parseBinaryOperators = (state, parse, minimumPower) => {
|
|
1928
|
-
let node = parse(state, "ImplicitProduct");
|
|
1929
|
-
let operator = getOwnValue(MathExpressionBinaryOperatorMap, state.token);
|
|
1930
|
-
while (state.error === null && operator !== void 0 && operator.power >= minimumPower) {
|
|
1931
|
-
getMathExpressionToken(state);
|
|
1932
|
-
const right = parseBinaryOperators(state, parse, operator.power + 1);
|
|
1933
|
-
node = createBinaryOperation(node, operator, right);
|
|
1934
|
-
operator = getOwnValue(MathExpressionBinaryOperatorMap, state.token);
|
|
1935
|
-
}
|
|
1936
|
-
return node;
|
|
1937
|
-
};
|
|
1938
|
-
//#endregion
|
|
1939
|
-
//#region src/services/parser/rule/parseBinary.ts
|
|
1940
|
-
const parseBinary = (state, parse) => parseBinaryOperators(state, parse, 0);
|
|
1941
|
-
//#endregion
|
|
1942
|
-
//#region src/services/parser/rule/parseConditional.ts
|
|
1943
|
-
const parseConditional = (state, parse) => {
|
|
1944
|
-
const condition = parse(state, "Binary");
|
|
1945
|
-
if (state.error !== null || !checkIsToken(state, "?")) return condition;
|
|
1946
|
-
getMathExpressionToken(state);
|
|
1947
|
-
if (checkIsToken(state, ":")) {
|
|
1948
|
-
failMathExpression(state, "The true-expression of a conditional operator may not be empty");
|
|
1949
|
-
return PLACEHOLDER;
|
|
1950
|
-
}
|
|
1951
|
-
const whenTrue = parse(state, "Assignment");
|
|
1952
|
-
if (state.error === null && !checkIsToken(state, ":")) failMathExpression(state, "False part of conditional expression expected");
|
|
1953
|
-
if (state.error !== null) return PLACEHOLDER;
|
|
1954
|
-
getMathExpressionToken(state);
|
|
1955
|
-
return {
|
|
1956
|
-
condition,
|
|
1957
|
-
type: "conditional",
|
|
1958
|
-
whenFalse: parse(state, "Conditional"),
|
|
1959
|
-
whenTrue
|
|
1960
|
-
};
|
|
1961
|
-
};
|
|
1962
|
-
//#endregion
|
|
1963
|
-
//#region src/services/parser/checkIsSignedNumber.ts
|
|
1964
|
-
const checkIsSignedNumber = (node) => {
|
|
1965
|
-
if (node.type === "number") return true;
|
|
1966
|
-
return node.type === "unary" && (node.name === "unaryMinus" || node.name === "unaryPlus") && node.operand.type === "number";
|
|
1967
|
-
};
|
|
1968
|
-
//#endregion
|
|
1969
|
-
//#region src/services/parser/rule/parseDivisionBeforeProduct.ts
|
|
1970
|
-
const parseDivisionBeforeProduct = (state, parse) => {
|
|
1971
|
-
const dividend = parse(state, "Percentage");
|
|
1972
|
-
if (state.error !== null || !checkIsToken(state, "/") || !checkIsSignedNumber(dividend)) return dividend;
|
|
1973
|
-
const snapshot = { ...state };
|
|
1974
|
-
getMathExpressionToken(state);
|
|
1975
|
-
const isNumber = state.tokenType === "number";
|
|
1976
|
-
if (isNumber) getMathExpressionToken(state);
|
|
1977
|
-
if (isNumber && state.error === null && (state.tokenType === "symbol" || checkIsToken(state, "("))) {
|
|
1978
|
-
Object.assign(state, snapshot);
|
|
1979
|
-
getMathExpressionToken(state);
|
|
1980
|
-
return createBinaryNode(dividend, MathExpressionBinaryOperatorMap["/"].name, parse(state, "Percentage"));
|
|
1981
|
-
}
|
|
1982
|
-
Object.assign(state, snapshot);
|
|
1983
|
-
return dividend;
|
|
1984
|
-
};
|
|
1985
|
-
//#endregion
|
|
1986
|
-
//#region src/services/parser/checkIsOperatorOperand.ts
|
|
1987
|
-
const checkIsOperatorOperand = (node) => {
|
|
1988
|
-
if (node.type === "unary") return node.name !== "factorial";
|
|
1989
|
-
return node.type === "binary" || node.type === "comparison" || node.type === "logical";
|
|
1990
|
-
};
|
|
1991
|
-
//#endregion
|
|
1992
|
-
//#region src/services/parser/rule/parseImplicitProduct.ts
|
|
1993
|
-
const parseImplicitProduct = (state, parse) => {
|
|
1994
|
-
let node = parse(state, "DivisionBeforeProduct");
|
|
1995
|
-
let last = node;
|
|
1996
|
-
while (state.error === null) {
|
|
1997
|
-
if (!(state.tokenType === "symbol" || checkIsToken(state, "(") || state.tokenType === "number" && last.type !== "number" && !checkIsOperatorOperand(last))) break;
|
|
1998
|
-
last = parse(state, "DivisionBeforeProduct");
|
|
1999
|
-
node = createBinaryNode(node, MathExpressionBinaryOperatorMap["*"].name, last);
|
|
2000
|
-
}
|
|
2001
|
-
return node;
|
|
2002
|
-
};
|
|
2003
|
-
//#endregion
|
|
2004
|
-
//#region src/services/parser/rule/parseLeftHand.ts
|
|
2005
|
-
const parseLeftHand = (state, parse) => {
|
|
2006
|
-
let node = parse(state, "Symbol");
|
|
2007
|
-
while (state.error === null && (checkIsToken(state, "!") || checkIsToken(state, "'"))) {
|
|
2008
|
-
const name = checkIsToken(state, "!") ? "factorial" : "ctranspose";
|
|
2009
|
-
getMathExpressionToken(state);
|
|
2010
|
-
node = {
|
|
2011
|
-
name,
|
|
2012
|
-
operand: node,
|
|
2013
|
-
type: "unary"
|
|
2014
|
-
};
|
|
2015
|
-
}
|
|
2016
|
-
return node;
|
|
2017
|
-
};
|
|
2018
|
-
//#endregion
|
|
2019
|
-
//#region src/services/parser/rule/parseNullish.ts
|
|
2020
|
-
const parseNullish = (state, parse) => {
|
|
2021
|
-
const operators = MathExpressionOperatorMap["Nullish"];
|
|
2022
|
-
let node = parse(state, "LeftHand");
|
|
2023
|
-
let operator = getOwnValue(operators, state.token);
|
|
2024
|
-
while (state.error === null && operator !== void 0) {
|
|
2025
|
-
getMathExpressionToken(state);
|
|
2026
|
-
const right = parse(state, "LeftHand");
|
|
2027
|
-
node = createLogicalNode(node, operator, right);
|
|
2028
|
-
operator = getOwnValue(operators, state.token);
|
|
2029
|
-
}
|
|
2030
|
-
return node;
|
|
2031
|
-
};
|
|
2032
|
-
//#endregion
|
|
2033
|
-
//#region src/services/parser/checkIsNameToken.ts
|
|
2034
|
-
const checkIsNameToken = (state) => state.tokenType === "symbol" || state.tokenType === "delimiter" && getMathExpressionSignatures(state.token) !== void 0;
|
|
2035
|
-
//#endregion
|
|
2036
|
-
//#region src/services/parser/checkIsUnaryStart.ts
|
|
2037
|
-
const checkIsUnaryStart = (state) => state.tokenType === "number" || checkIsNameToken(state) || checkIsToken(state, "(") || getOwnValue(MathExpressionOperatorMap["Unary"], state.token) !== void 0;
|
|
2038
|
-
//#endregion
|
|
2039
|
-
//#region src/services/parser/rule/parsePercentage.ts
|
|
2040
|
-
const parsePercentage = (state, parse) => {
|
|
2041
|
-
const node = parse(state, "Unary");
|
|
2042
|
-
if (state.error !== null || !checkIsToken(state, "%")) return node;
|
|
2043
|
-
const snapshot = { ...state };
|
|
2044
|
-
getMathExpressionToken(state);
|
|
2045
|
-
if (state.error === null && !checkIsToken(state, "+") && !checkIsToken(state, "-") && checkIsUnaryStart(state)) {
|
|
2046
|
-
Object.assign(state, snapshot);
|
|
2047
|
-
return node;
|
|
2048
|
-
}
|
|
2049
|
-
return {
|
|
2050
|
-
operand: node,
|
|
2051
|
-
type: "percentage"
|
|
2052
|
-
};
|
|
2053
|
-
};
|
|
2054
|
-
//#endregion
|
|
2055
|
-
//#region src/services/parser/rule/parsePower.ts
|
|
2056
|
-
const parsePower = (state, parse) => {
|
|
2057
|
-
const base = parse(state, "Nullish");
|
|
2058
|
-
const name = getOwnValue(MathExpressionOperatorMap["Power"], state.token);
|
|
2059
|
-
if (state.error !== null || name === void 0) return base;
|
|
2060
|
-
getMathExpressionToken(state);
|
|
2061
|
-
const exponent = parse(state, "Unary");
|
|
2062
|
-
return createBinaryNode(base, name, exponent);
|
|
2063
|
-
};
|
|
2064
|
-
//#endregion
|
|
2065
|
-
//#region src/services/parser/computeNumberLiteral.ts
|
|
2066
|
-
const computeNumberLiteral = (token) => {
|
|
2067
|
-
const radixEntry = MathExpressionRadixMap[token.charAt(1)];
|
|
2068
|
-
if (!token.startsWith("0") || radixEntry === void 0) return Number(token);
|
|
2069
|
-
const { radix } = radixEntry;
|
|
2070
|
-
const [digits = "", wordSize] = token.slice(2).split("i");
|
|
2071
|
-
const [integerDigits = "", fractionDigits = ""] = digits.split(".");
|
|
2072
|
-
let value = 0;
|
|
2073
|
-
for (const digit of integerDigits) value = value * radix + Number.parseInt(digit, radix);
|
|
2074
|
-
let scale = 1 / radix;
|
|
2075
|
-
for (const digit of fractionDigits) {
|
|
2076
|
-
value += Number.parseInt(digit, radix) * scale;
|
|
2077
|
-
scale /= radix;
|
|
2078
|
-
}
|
|
2079
|
-
if (wordSize === void 0) return value;
|
|
2080
|
-
const bits = Number(wordSize);
|
|
2081
|
-
if (value > 2 ** bits - 1) return null;
|
|
2082
|
-
return value >= 2 ** (bits - 1) ? value - 2 ** bits : value;
|
|
2083
|
-
};
|
|
2084
|
-
//#endregion
|
|
2085
|
-
//#region src/services/parser/getArgumentCountText.ts
|
|
2086
|
-
const getArgumentCountText = (count) => `${count} ${count === 1 ? "argument" : "arguments"}`;
|
|
2087
|
-
//#endregion
|
|
2088
|
-
//#region src/services/parser/getMathExpressionArityMessage.ts
|
|
2089
|
-
const getMathExpressionArityMessage = (name, minArity, maxArity) => {
|
|
2090
|
-
if (maxArity === Number.POSITIVE_INFINITY) return `"${name}" takes at least ${getArgumentCountText(minArity)}`;
|
|
2091
|
-
if (minArity === maxArity) return `"${name}" takes ${getArgumentCountText(minArity)}`;
|
|
2092
|
-
return `"${name}" takes ${minArity} or ${maxArity} arguments`;
|
|
2093
|
-
};
|
|
2094
|
-
//#endregion
|
|
2095
|
-
//#region src/services/parser/getMathExpressionSignatureError.ts
|
|
2096
|
-
const getMathExpressionSignatureError = (name, signatures, parameterTypes) => {
|
|
2097
|
-
const count = parameterTypes.length;
|
|
2098
|
-
if (signatures.filter((signature) => count >= signature.minArity && count <= signature.maxArity).length === 0) return getMathExpressionArityMessage(name, Math.min(...signatures.map((signature) => signature.minArity)), Math.max(...signatures.map((signature) => signature.maxArity)));
|
|
2099
|
-
if (parameterTypes.includes("list")) return `"${name}" does not take a list argument`;
|
|
2100
|
-
return `"${name}" takes a list argument`;
|
|
2101
|
-
};
|
|
2102
|
-
//#endregion
|
|
2103
|
-
//#region src/services/parser/parseSequence.ts
|
|
2104
|
-
const parseSequence = (state, closing, parseItem) => {
|
|
2105
|
-
const nodes = [];
|
|
2106
|
-
if (checkIsToken(state, closing)) return nodes;
|
|
2107
|
-
while (state.error === null) {
|
|
2108
|
-
nodes.push(parseItem(state));
|
|
2109
|
-
if (!checkIsToken(state, ",")) break;
|
|
2110
|
-
getMathExpressionToken(state);
|
|
2111
|
-
}
|
|
2112
|
-
if (state.error === null && !checkIsToken(state, closing)) failMathExpression(state, closing === ")" ? "Parenthesis ) expected" : "Parenthesis ] expected");
|
|
2113
|
-
return nodes;
|
|
2114
|
-
};
|
|
2115
|
-
//#endregion
|
|
2116
|
-
//#region src/services/parser/parseList.ts
|
|
2117
|
-
const parseList = (state, parse) => {
|
|
2118
|
-
getMathExpressionToken(state);
|
|
2119
|
-
const elements = parseSequence(state, "]", (item) => parse(item, "Assignment"));
|
|
2120
|
-
if (state.error !== null) return PLACEHOLDER;
|
|
2121
|
-
getMathExpressionToken(state);
|
|
2122
|
-
return {
|
|
2123
|
-
elements,
|
|
2124
|
-
type: "list"
|
|
2125
|
-
};
|
|
2126
|
-
};
|
|
2127
|
-
//#endregion
|
|
2128
|
-
//#region src/services/parser/parseArgument.ts
|
|
2129
|
-
const parseArgument = (state, parse) => checkIsToken(state, "[") ? parseList(state, parse) : parse(state, "Assignment");
|
|
2130
|
-
//#endregion
|
|
2131
|
-
//#region src/services/parser/parseCall.ts
|
|
2132
|
-
const parseCall = (state, name, column, parse) => {
|
|
2133
|
-
const signatures = getMathExpressionSignatures(name);
|
|
2134
|
-
if (signatures === void 0) {
|
|
2135
|
-
failMathExpressionAt(state, `Unknown function "${name}"`, column);
|
|
2136
|
-
return PLACEHOLDER;
|
|
2137
|
-
}
|
|
2138
|
-
getMathExpressionToken(state);
|
|
2139
|
-
const argumentNodes = parseSequence(state, ")", (argument) => parseArgument(argument, parse));
|
|
2140
|
-
if (state.error !== null) return PLACEHOLDER;
|
|
2141
|
-
getMathExpressionToken(state);
|
|
2142
|
-
const parameterTypes = argumentNodes.map((argument) => getMathExpressionParameterType(argument));
|
|
2143
|
-
if (matchMathExpressionSignature(signatures, parameterTypes) === void 0) {
|
|
2144
|
-
failMathExpressionAt(state, getMathExpressionSignatureError(name, signatures, parameterTypes), column);
|
|
2145
|
-
return PLACEHOLDER;
|
|
2146
|
-
}
|
|
2147
|
-
return {
|
|
2148
|
-
arguments: argumentNodes,
|
|
2149
|
-
name,
|
|
2150
|
-
type: "call"
|
|
2151
|
-
};
|
|
2152
|
-
};
|
|
2153
|
-
//#endregion
|
|
2154
|
-
//#region src/services/parser/rule/parseSymbol.ts
|
|
2155
|
-
const parseSymbol = (state, parse) => {
|
|
2156
|
-
if (state.tokenType === "number") {
|
|
2157
|
-
const value = computeNumberLiteral(state.token);
|
|
2158
|
-
if (value === null) {
|
|
2159
|
-
failMathExpression(state, `String "${state.token.split("i")[0]}" is out of range`);
|
|
2160
|
-
getMathExpressionToken(state);
|
|
2161
|
-
return PLACEHOLDER;
|
|
2162
|
-
}
|
|
2163
|
-
getMathExpressionToken(state);
|
|
2164
|
-
return {
|
|
2165
|
-
type: "number",
|
|
2166
|
-
value
|
|
2167
|
-
};
|
|
2168
|
-
}
|
|
2169
|
-
if (checkIsNameToken(state)) {
|
|
2170
|
-
const name = state.token;
|
|
2171
|
-
const column = getMathExpressionColumn(state);
|
|
2172
|
-
const isSymbol = state.tokenType === "symbol";
|
|
2173
|
-
getMathExpressionToken(state);
|
|
2174
|
-
if (checkIsToken(state, "(")) return parseCall(state, name, column, parse);
|
|
2175
|
-
if (isSymbol) return {
|
|
2176
|
-
name,
|
|
2177
|
-
type: "name"
|
|
2178
|
-
};
|
|
2179
|
-
}
|
|
2180
|
-
if (checkIsToken(state, "(")) {
|
|
2181
|
-
getMathExpressionToken(state);
|
|
2182
|
-
const operand = parse(state, "Assignment");
|
|
2183
|
-
if (state.error === null && !checkIsToken(state, ")")) failMathExpression(state, "Parenthesis ) expected");
|
|
2184
|
-
if (state.error !== null) return PLACEHOLDER;
|
|
2185
|
-
getMathExpressionToken(state);
|
|
2186
|
-
return {
|
|
2187
|
-
operand,
|
|
2188
|
-
type: "group"
|
|
2189
|
-
};
|
|
2190
|
-
}
|
|
2191
|
-
failMathExpression(state, checkIsToken(state, "") ? "Unexpected end of expression" : "Value expected");
|
|
2192
|
-
return PLACEHOLDER;
|
|
2193
|
-
};
|
|
2194
|
-
//#endregion
|
|
2195
|
-
//#region src/services/parser/rule/parseUnary.ts
|
|
2196
|
-
const parseUnary = (state, parse) => {
|
|
2197
|
-
const name = getOwnValue(MathExpressionOperatorMap["Unary"], state.token);
|
|
2198
|
-
if (name === void 0) return parse(state, "Power");
|
|
2199
|
-
if (!checkCanMathExpressionNest(state)) return PLACEHOLDER;
|
|
2200
|
-
getMathExpressionToken(state);
|
|
2201
|
-
state.depth++;
|
|
2202
|
-
const operand = parse(state, "Unary");
|
|
2203
|
-
state.depth--;
|
|
2204
|
-
return {
|
|
2205
|
-
name,
|
|
2206
|
-
operand,
|
|
2207
|
-
type: "unary"
|
|
2208
|
-
};
|
|
2209
|
-
};
|
|
2210
|
-
//#endregion
|
|
2211
|
-
//#region src/services/parser/MathExpressionRuleParserMap.ts
|
|
2212
|
-
const MathExpressionRuleParserMap = {
|
|
2213
|
-
["Assignment"]: parseAssignment,
|
|
2214
|
-
["Binary"]: parseBinary,
|
|
2215
|
-
["Conditional"]: parseConditional,
|
|
2216
|
-
["DivisionBeforeProduct"]: parseDivisionBeforeProduct,
|
|
2217
|
-
["ImplicitProduct"]: parseImplicitProduct,
|
|
2218
|
-
["LeftHand"]: parseLeftHand,
|
|
2219
|
-
["Nullish"]: parseNullish,
|
|
2220
|
-
["Percentage"]: parsePercentage,
|
|
2221
|
-
["Power"]: parsePower,
|
|
2222
|
-
["Symbol"]: parseSymbol,
|
|
2223
|
-
["Unary"]: parseUnary
|
|
2224
|
-
};
|
|
2225
|
-
//#endregion
|
|
2226
|
-
//#region src/services/parser/parseMathExpressionRule.ts
|
|
2227
|
-
const parseMathExpressionRule = (state, rule) => MathExpressionRuleParserMap[rule](state, parseMathExpressionRule);
|
|
2228
|
-
//#endregion
|
|
2229
|
-
//#region src/services/parser/parseMathExpression.ts
|
|
2230
|
-
const parseMathExpression = (formula) => {
|
|
2231
|
-
const state = {
|
|
2232
|
-
depth: 0,
|
|
2233
|
-
error: null,
|
|
2234
|
-
index: 0,
|
|
2235
|
-
nestingLevel: 0,
|
|
2236
|
-
source: formula,
|
|
2237
|
-
token: "",
|
|
2238
|
-
tokenType: "null"
|
|
2239
|
-
};
|
|
2240
|
-
getMathExpressionToken(state);
|
|
2241
|
-
const node = parseMathExpressionRule(state, "Assignment");
|
|
2242
|
-
if (state.error === null && !checkIsToken(state, "")) failMathExpression(state, state.tokenType === "delimiter" ? `Unexpected operator ${state.token}` : `Unexpected part "${state.token}"`);
|
|
2243
|
-
return state.error === null ? ok(node) : err(state.error);
|
|
2244
|
-
};
|
|
2245
|
-
//#endregion
|
|
2246
|
-
export { ADDITIVE_NAMES, BERNOULLI_CLOSED_FORM_INDEX, DECIMAL_MARK_OPERATOR_FOLLOWERS, DELIMITERS_OF_ONE, DELIMITERS_OF_THREE, DELIMITERS_OF_TWO, EULER_MACLAURIN_COEFFICIENTS, FIRST_CHARACTERS_OF_THREE, FIRST_CHARACTERS_OF_TWO, HIGH_TAIL_COEFFICIENTS, LAST_FACTORIAL_ARGUMENT, LOW_TAIL_COEFFICIENTS, MATH_EXPRESSION_ABSOLUTE_TOLERANCE, MATH_EXPRESSION_RELATIVE_TOLERANCE, MAXIMUM_DIGITS, MAXIMUM_STIRLING_WORK, MAX_MATH_EXPRESSION_DEPTH, MILLER_RABIN_BASES, MathExpressionBinaryOperatorMap, MathExpressionBitwiseAbsorptionMap, MathExpressionConstantMap, MathExpressionError, MathExpressionFunctionMap, MathExpressionFunctionName, MathExpressionGrammarRule, MathExpressionLogicalOperator, MathExpressionNodeCompileMap, MathExpressionNodeType, MathExpressionOperatorMap, MathExpressionParameterType, MathExpressionRadixMap, MathExpressionRuleParserMap, MathExpressionTokenType, NAMED_DELIMITERS, NO_LOCALS, NO_VALUES, OVERFLOW_ARGUMENT, PLACEHOLDER, REFINEMENT_STEPS, SQRT_PI, STIRLING_TERMS, STIRLING_THRESHOLD, SUMMATION_LIMIT, WORD_CHARACTER_REGEX, WORD_START_REGEX, checkCanMathExpressionNest, checkIsDecimalMark, checkIsDigitCharacter, checkIsLarger, checkIsMatching, checkIsMatchingKind, checkIsMillerRabinPassing, checkIsNameToken, checkIsNearlyEqual, checkIsOperatorOperand, checkIsPercentageExpression, checkIsPrime, checkIsSignedNumber, checkIsSmaller, checkIsToken, checkIsTruthy, checkIsUnaryStart, checkIsWordCharacter, checkIsWordStartCharacter, collectMathExpressionAssignedNames, compareNumbers, compileArgument, compileAssignment, compileBinary, compileCall, compileComparison, compileConditional, compileGroup, compileList, compileListNode, compileLogical, compileMathExpression, compileMathExpressionNode, compileName, compileNumber, compilePercentage, compileUnary, computeBellNumber, computeBernoulliNumber, computeBitwiseAnd, computeBitwiseOr, computeCatalan, computeCombinations, computeComparison, computeCompositions, computeCorrelation, computeDeterminant, computeDistance, computeDotProduct, computeErf, computeErfInverse, computeExtreme, computeFactorial, computeGamma, computeGreatestCommonDivisor, computeHypotenuse, computeInitialGuess, computeIntegerGreatestCommonDivisor, computeInverseCoth, computeKullbackLeibler, computeLeastCommonMultiple, computeListComparison, computeLogGamma, computeLogGammaOfPositive, computeLogarithm, computeMean, computeMedian, computeMedianAbsoluteDeviation, computeModularInverse, computeModularPower, computeModulo, computeMultinomial, computeNorm, computeNthRoot, computeNumberLiteral, computePartitionSelect, computePermutations, computePointToLine2D, computePointToLine3D, computePolynomial, computeProduct, computeProductOfRange, computeQuantile, computeStirlingColumn, computeStirlingDiagonal, computeStirlingLogGamma, computeStirlingSecondKind, computeSum, computeSummedZeta, computeTruthyCount, computeVariance, computeVectorNorm, computeZeta, createBinaryNode, createBinaryOperation, createBinarySignatures, createBitwiseFold, createBitwisePair, createDigitSignatures, createExtremeSignatures, createIdentitySignatures, createIntegerBinarySignatures, createIntegerUnarySignatures, createListFirstCompute, createListPairCompute, createListPairSignature, createListSignature, createLogicalNode, createNonEmptyCompute, createNumberSignature, createNumericCompute, createOrderedListSignatures, createRangedSignatures, createSignature, createSingletonListSignature, createSpreadSignatures, createUnarySignatures, createVariadicSignatures, failExponent, failMathExpression, failMathExpressionAt, getArgumentCountText, getMathExpressionArityMessage, getMathExpressionCharacter, getMathExpressionChildren, getMathExpressionColumn, getMathExpressionConstant, getMathExpressionNames, getMathExpressionOuterValue, getMathExpressionParameterType, getMathExpressionScalarCompute, getMathExpressionSignatureError, getMathExpressionSignatures, getMathExpressionToken, getOwnValue, getParameterType, matchMathExpressionSignature, multiplyPair, parseArgument, parseAssignment, parseBinary, parseBinaryOperators, parseCall, parseConditional, parseDivisionBeforeProduct, parseImplicitProduct, parseLeftHand, parseList, parseMathExpression, parseMathExpressionRule, parseNullish, parsePercentage, parsePower, parseSequence, parseSymbol, parseUnary, readMathExpressionDelimiter, readMathExpressionNumber, readMathExpressionWord, readRadixNumber, roundToDigits, scaleList, shiftDecimalPlaces, skipMathExpressionSpaces, takeExponent, takeMathExpressionMatching, toNumber, walkNode };
|