@affino/datagrid-formula-engine 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +38 -0
- package/dist/analysis/index.d.ts +2 -0
- package/dist/analysis/index.d.ts.map +1 -0
- package/dist/analysis/index.js +1 -0
- package/dist/analysis/types.d.ts +44 -0
- package/dist/analysis/types.d.ts.map +1 -0
- package/dist/analysis/types.js +1 -0
- package/dist/contracts.d.ts +177 -0
- package/dist/contracts.d.ts.map +1 -0
- package/dist/contracts.js +140 -0
- package/dist/coreTypes.d.ts +2 -0
- package/dist/coreTypes.d.ts.map +1 -0
- package/dist/coreTypes.js +1 -0
- package/dist/dependency/index.d.ts +2 -0
- package/dist/dependency/index.d.ts.map +1 -0
- package/dist/dependency/index.js +1 -0
- package/dist/evaluators/columnar.d.ts +6 -0
- package/dist/evaluators/columnar.d.ts.map +1 -0
- package/dist/evaluators/columnar.js +39 -0
- package/dist/evaluators/index.d.ts +5 -0
- package/dist/evaluators/index.d.ts.map +1 -0
- package/dist/evaluators/index.js +4 -0
- package/dist/evaluators/interpreter.d.ts +6 -0
- package/dist/evaluators/interpreter.d.ts.map +1 -0
- package/dist/evaluators/interpreter.js +156 -0
- package/dist/evaluators/jit.d.ts +7 -0
- package/dist/evaluators/jit.d.ts.map +1 -0
- package/dist/evaluators/jit.js +158 -0
- package/dist/evaluators/shared.d.ts +36 -0
- package/dist/evaluators/shared.d.ts.map +1 -0
- package/dist/evaluators/shared.js +242 -0
- package/dist/evaluators/vector.d.ts +6 -0
- package/dist/evaluators/vector.d.ts.map +1 -0
- package/dist/evaluators/vector.js +228 -0
- package/dist/formulaEngine/compile.d.ts +2 -0
- package/dist/formulaEngine/compile.d.ts.map +1 -0
- package/dist/formulaEngine/compile.js +1 -0
- package/dist/formulaEngine/core.d.ts +2 -0
- package/dist/formulaEngine/core.d.ts.map +1 -0
- package/dist/formulaEngine/core.js +1 -0
- package/dist/formulaEngine/evaluators.d.ts +2 -0
- package/dist/formulaEngine/evaluators.d.ts.map +1 -0
- package/dist/formulaEngine/evaluators.js +1 -0
- package/dist/formulaEngine/index.d.ts +5 -0
- package/dist/formulaEngine/index.d.ts.map +1 -0
- package/dist/formulaEngine/index.js +2 -0
- package/dist/formulaExecutionPlan.d.ts +2 -0
- package/dist/formulaExecutionPlan.d.ts.map +1 -0
- package/dist/formulaExecutionPlan.js +1 -0
- package/dist/graph/executionPlan.d.ts +66 -0
- package/dist/graph/executionPlan.d.ts.map +1 -0
- package/dist/graph/executionPlan.js +534 -0
- package/dist/graph/index.d.ts +2 -0
- package/dist/graph/index.d.ts.map +1 -0
- package/dist/graph/index.js +3 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/runtime/compile.d.ts +7 -0
- package/dist/runtime/compile.d.ts.map +1 -0
- package/dist/runtime/compile.js +453 -0
- package/dist/runtime/evaluators.d.ts +5 -0
- package/dist/runtime/evaluators.d.ts.map +1 -0
- package/dist/runtime/evaluators.js +6 -0
- package/dist/runtime/index.d.ts +3 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +2 -0
- package/dist/runtime/types.d.ts +63 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +1 -0
- package/dist/syntax/analysis.d.ts +14 -0
- package/dist/syntax/analysis.d.ts.map +1 -0
- package/dist/syntax/analysis.js +159 -0
- package/dist/syntax/ast.d.ts +18 -0
- package/dist/syntax/ast.d.ts.map +1 -0
- package/dist/syntax/ast.js +54 -0
- package/dist/syntax/core.d.ts +4 -0
- package/dist/syntax/core.d.ts.map +1 -0
- package/dist/syntax/core.js +1 -0
- package/dist/syntax/functionGroups/advancedFunctions.d.ts +2 -0
- package/dist/syntax/functionGroups/advancedFunctions.d.ts.map +1 -0
- package/dist/syntax/functionGroups/advancedFunctions.js +252 -0
- package/dist/syntax/functionGroups/dateFunctions.d.ts +2 -0
- package/dist/syntax/functionGroups/dateFunctions.d.ts.map +1 -0
- package/dist/syntax/functionGroups/dateFunctions.js +144 -0
- package/dist/syntax/functionGroups/logicFunctions.d.ts +2 -0
- package/dist/syntax/functionGroups/logicFunctions.d.ts.map +1 -0
- package/dist/syntax/functionGroups/logicFunctions.js +140 -0
- package/dist/syntax/functionGroups/numericFunctions.d.ts +2 -0
- package/dist/syntax/functionGroups/numericFunctions.d.ts.map +1 -0
- package/dist/syntax/functionGroups/numericFunctions.js +268 -0
- package/dist/syntax/functionGroups/textFunctions.d.ts +2 -0
- package/dist/syntax/functionGroups/textFunctions.d.ts.map +1 -0
- package/dist/syntax/functionGroups/textFunctions.js +118 -0
- package/dist/syntax/functionHelpers.d.ts +45 -0
- package/dist/syntax/functionHelpers.d.ts.map +1 -0
- package/dist/syntax/functionHelpers.js +553 -0
- package/dist/syntax/functions.d.ts +9 -0
- package/dist/syntax/functions.d.ts.map +1 -0
- package/dist/syntax/functions.js +139 -0
- package/dist/syntax/index.d.ts +10 -0
- package/dist/syntax/index.d.ts.map +1 -0
- package/dist/syntax/index.js +7 -0
- package/dist/syntax/legacy.d.ts +29 -0
- package/dist/syntax/legacy.d.ts.map +1 -0
- package/dist/syntax/legacy.js +188 -0
- package/dist/syntax/optimizer.d.ts +6 -0
- package/dist/syntax/optimizer.d.ts.map +1 -0
- package/dist/syntax/optimizer.js +362 -0
- package/dist/syntax/parser.d.ts +7 -0
- package/dist/syntax/parser.d.ts.map +1 -0
- package/dist/syntax/parser.js +239 -0
- package/dist/syntax/tokenizer.d.ts +14 -0
- package/dist/syntax/tokenizer.d.ts.map +1 -0
- package/dist/syntax/tokenizer.js +852 -0
- package/dist/syntax/types.d.ts +120 -0
- package/dist/syntax/types.d.ts.map +1 -0
- package/dist/syntax/types.js +1 -0
- package/dist/syntax/values.d.ts +25 -0
- package/dist/syntax/values.d.ts.map +1 -0
- package/dist/syntax/values.js +270 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { DataGridFormulaEvaluationError } from "../syntax/ast.js";
|
|
2
|
+
import { normalizeFormulaFunctionName } from "../syntax/functions.js";
|
|
3
|
+
import { areFormulaValuesEqual, coerceFormulaValueToNumber, compareFormulaValues, createFormulaRuntimeError, findFormulaErrorValue, formulaNumberIsTruthy, isFormulaErrorValue, isFormulaValuePresent, normalizeFormulaValue, } from "../syntax/values.js";
|
|
4
|
+
import { ZERO_FORMULA_NODE } from "./shared.js";
|
|
5
|
+
function compileFormulaAstEvaluatorForToken(root, functionRegistry, resolveIdentifierToken, getFunctionContext) {
|
|
6
|
+
var _a, _b, _c;
|
|
7
|
+
const compileChild = (node) => {
|
|
8
|
+
return compileFormulaAstEvaluatorForToken(node, functionRegistry, resolveIdentifierToken, getFunctionContext);
|
|
9
|
+
};
|
|
10
|
+
if (root.kind === "number")
|
|
11
|
+
return () => root.value;
|
|
12
|
+
if (root.kind === "literal")
|
|
13
|
+
return () => root.value;
|
|
14
|
+
if (root.kind === "identifier") {
|
|
15
|
+
const token = resolveIdentifierToken(root.name);
|
|
16
|
+
if (typeof token === "undefined")
|
|
17
|
+
return () => 0;
|
|
18
|
+
return readTokenValue => normalizeFormulaValue(readTokenValue(token));
|
|
19
|
+
}
|
|
20
|
+
if (root.kind === "call") {
|
|
21
|
+
const normalizedFunctionName = normalizeFormulaFunctionName(root.name);
|
|
22
|
+
const functionDefinition = functionRegistry.get(normalizedFunctionName);
|
|
23
|
+
if (!functionDefinition) {
|
|
24
|
+
throw new DataGridFormulaEvaluationError(createFormulaRuntimeError("FUNCTION_UNKNOWN", `Unknown function '${root.name}'.`, { functionName: normalizedFunctionName }));
|
|
25
|
+
}
|
|
26
|
+
if (normalizedFunctionName === "IF") {
|
|
27
|
+
const conditionEvaluator = compileChild((_a = root.args[0]) !== null && _a !== void 0 ? _a : ZERO_FORMULA_NODE);
|
|
28
|
+
const trueEvaluator = compileChild((_b = root.args[1]) !== null && _b !== void 0 ? _b : ZERO_FORMULA_NODE);
|
|
29
|
+
const falseEvaluator = compileChild((_c = root.args[2]) !== null && _c !== void 0 ? _c : ZERO_FORMULA_NODE);
|
|
30
|
+
return (readTokenValue) => {
|
|
31
|
+
const conditionValue = conditionEvaluator(readTokenValue);
|
|
32
|
+
if (isFormulaErrorValue(conditionValue))
|
|
33
|
+
return conditionValue;
|
|
34
|
+
return formulaNumberIsTruthy(conditionValue) ? trueEvaluator(readTokenValue) : falseEvaluator(readTokenValue);
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
if (normalizedFunctionName === "IFS") {
|
|
38
|
+
const pairEvaluators = root.args.map(arg => compileChild(arg));
|
|
39
|
+
return (readTokenValue) => {
|
|
40
|
+
for (let index = 0; index < pairEvaluators.length; index += 2) {
|
|
41
|
+
const conditionEvaluator = pairEvaluators[index];
|
|
42
|
+
const valueEvaluator = pairEvaluators[index + 1];
|
|
43
|
+
const conditionValue = conditionEvaluator ? conditionEvaluator(readTokenValue) : 0;
|
|
44
|
+
if (isFormulaErrorValue(conditionValue))
|
|
45
|
+
return conditionValue;
|
|
46
|
+
if (!formulaNumberIsTruthy(conditionValue))
|
|
47
|
+
continue;
|
|
48
|
+
return valueEvaluator ? valueEvaluator(readTokenValue) : 0;
|
|
49
|
+
}
|
|
50
|
+
return 0;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
if (normalizedFunctionName === "COALESCE") {
|
|
54
|
+
const argEvaluators = root.args.map(arg => compileChild(arg));
|
|
55
|
+
return (readTokenValue) => {
|
|
56
|
+
for (const evaluator of argEvaluators) {
|
|
57
|
+
const value = evaluator(readTokenValue);
|
|
58
|
+
if (isFormulaValuePresent(value))
|
|
59
|
+
return value;
|
|
60
|
+
}
|
|
61
|
+
return 0;
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
const argEvaluators = root.args.map(arg => compileChild(arg));
|
|
65
|
+
return (readTokenValue) => {
|
|
66
|
+
const args = new Array(argEvaluators.length);
|
|
67
|
+
for (let index = 0; index < argEvaluators.length; index += 1) {
|
|
68
|
+
const evaluator = argEvaluators[index];
|
|
69
|
+
args[index] = evaluator ? evaluator(readTokenValue) : null;
|
|
70
|
+
}
|
|
71
|
+
const formulaError = findFormulaErrorValue(args);
|
|
72
|
+
if (formulaError)
|
|
73
|
+
return formulaError;
|
|
74
|
+
try {
|
|
75
|
+
return normalizeFormulaValue(functionDefinition.compute(args, getFunctionContext === null || getFunctionContext === void 0 ? void 0 : getFunctionContext()));
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
throw new DataGridFormulaEvaluationError(createFormulaRuntimeError("EVAL_ERROR", error instanceof Error ? error.message : String(error !== null && error !== void 0 ? error : "Function evaluation failed."), { functionName: functionDefinition.name }));
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
if (root.kind === "unary") {
|
|
83
|
+
const valueEvaluator = compileChild(root.value);
|
|
84
|
+
return readTokenValue => {
|
|
85
|
+
const value = valueEvaluator(readTokenValue);
|
|
86
|
+
if (isFormulaErrorValue(value))
|
|
87
|
+
return value;
|
|
88
|
+
if (root.operator === "-")
|
|
89
|
+
return -coerceFormulaValueToNumber(value);
|
|
90
|
+
if (root.operator === "+")
|
|
91
|
+
return coerceFormulaValueToNumber(value);
|
|
92
|
+
return formulaNumberIsTruthy(value) ? 0 : 1;
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
const leftEvaluator = compileChild(root.left);
|
|
96
|
+
const rightEvaluator = compileChild(root.right);
|
|
97
|
+
if (root.operator === "AND") {
|
|
98
|
+
return (readTokenValue) => {
|
|
99
|
+
const left = leftEvaluator(readTokenValue);
|
|
100
|
+
if (isFormulaErrorValue(left))
|
|
101
|
+
return left;
|
|
102
|
+
if (!formulaNumberIsTruthy(left))
|
|
103
|
+
return 0;
|
|
104
|
+
const right = rightEvaluator(readTokenValue);
|
|
105
|
+
if (isFormulaErrorValue(right))
|
|
106
|
+
return right;
|
|
107
|
+
return formulaNumberIsTruthy(right) ? 1 : 0;
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
if (root.operator === "OR") {
|
|
111
|
+
return (readTokenValue) => {
|
|
112
|
+
const left = leftEvaluator(readTokenValue);
|
|
113
|
+
if (isFormulaErrorValue(left))
|
|
114
|
+
return left;
|
|
115
|
+
if (formulaNumberIsTruthy(left))
|
|
116
|
+
return 1;
|
|
117
|
+
const right = rightEvaluator(readTokenValue);
|
|
118
|
+
if (isFormulaErrorValue(right))
|
|
119
|
+
return right;
|
|
120
|
+
return formulaNumberIsTruthy(right) ? 1 : 0;
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
if (root.operator === "+")
|
|
124
|
+
return readTokenValue => coerceFormulaValueToNumber(leftEvaluator(readTokenValue)) + coerceFormulaValueToNumber(rightEvaluator(readTokenValue));
|
|
125
|
+
if (root.operator === "-")
|
|
126
|
+
return readTokenValue => coerceFormulaValueToNumber(leftEvaluator(readTokenValue)) - coerceFormulaValueToNumber(rightEvaluator(readTokenValue));
|
|
127
|
+
if (root.operator === "*")
|
|
128
|
+
return readTokenValue => coerceFormulaValueToNumber(leftEvaluator(readTokenValue)) * coerceFormulaValueToNumber(rightEvaluator(readTokenValue));
|
|
129
|
+
if (root.operator === "/") {
|
|
130
|
+
return (readTokenValue) => {
|
|
131
|
+
const right = coerceFormulaValueToNumber(rightEvaluator(readTokenValue));
|
|
132
|
+
if (right === 0) {
|
|
133
|
+
throw new DataGridFormulaEvaluationError(createFormulaRuntimeError("DIV_ZERO", "Division by zero.", { operator: "/" }));
|
|
134
|
+
}
|
|
135
|
+
const left = coerceFormulaValueToNumber(leftEvaluator(readTokenValue));
|
|
136
|
+
return left / right;
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
if (root.operator === ">")
|
|
140
|
+
return readTokenValue => (compareFormulaValues(leftEvaluator(readTokenValue), rightEvaluator(readTokenValue)) > 0 ? 1 : 0);
|
|
141
|
+
if (root.operator === "<")
|
|
142
|
+
return readTokenValue => (compareFormulaValues(leftEvaluator(readTokenValue), rightEvaluator(readTokenValue)) < 0 ? 1 : 0);
|
|
143
|
+
if (root.operator === ">=")
|
|
144
|
+
return readTokenValue => (compareFormulaValues(leftEvaluator(readTokenValue), rightEvaluator(readTokenValue)) >= 0 ? 1 : 0);
|
|
145
|
+
if (root.operator === "<=")
|
|
146
|
+
return readTokenValue => (compareFormulaValues(leftEvaluator(readTokenValue), rightEvaluator(readTokenValue)) <= 0 ? 1 : 0);
|
|
147
|
+
if (root.operator === "==")
|
|
148
|
+
return readTokenValue => (areFormulaValuesEqual(leftEvaluator(readTokenValue), rightEvaluator(readTokenValue)) ? 1 : 0);
|
|
149
|
+
return readTokenValue => (areFormulaValuesEqual(leftEvaluator(readTokenValue), rightEvaluator(readTokenValue)) ? 0 : 1);
|
|
150
|
+
}
|
|
151
|
+
export function compileFormulaAstEvaluator(root, functionRegistry, resolveIdentifierToken, getFunctionContext) {
|
|
152
|
+
return compileFormulaAstEvaluatorForToken(root, functionRegistry, resolveIdentifierToken, getFunctionContext);
|
|
153
|
+
}
|
|
154
|
+
export function compileFormulaAstTokenIndexEvaluator(root, functionRegistry, resolveIdentifierTokenIndex) {
|
|
155
|
+
return compileFormulaAstEvaluatorForToken(root, functionRegistry, resolveIdentifierTokenIndex);
|
|
156
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DataGridComputedDependencyToken } from "../coreTypes.js";
|
|
2
|
+
import type { DataGridFormulaBatchEvaluator, DataGridFormulaColumnarBatchEvaluator, DataGridFormulaEvaluator, DataGridFormulaFunctionRuntime } from "../runtime/types.js";
|
|
3
|
+
import { type DataGridFormulaAstNode } from "../syntax/ast.js";
|
|
4
|
+
export declare function compileFormulaAstEvaluatorJit(root: DataGridFormulaAstNode, functionRegistry: ReadonlyMap<string, DataGridFormulaFunctionRuntime>, resolveIdentifierTokenIndex: (identifier: string) => number | undefined, dependencyTokens: readonly DataGridComputedDependencyToken[]): DataGridFormulaEvaluator;
|
|
5
|
+
export declare function compileFormulaAstBatchEvaluatorJit(root: DataGridFormulaAstNode, functionRegistry: ReadonlyMap<string, DataGridFormulaFunctionRuntime>, resolveIdentifierTokenIndex: (identifier: string) => number | undefined): DataGridFormulaBatchEvaluator;
|
|
6
|
+
export declare function compileFormulaAstColumnarBatchEvaluatorJit(root: DataGridFormulaAstNode, functionRegistry: ReadonlyMap<string, DataGridFormulaFunctionRuntime>, resolveIdentifierTokenIndex: (identifier: string) => number | undefined): DataGridFormulaColumnarBatchEvaluator;
|
|
7
|
+
//# sourceMappingURL=jit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jit.d.ts","sourceRoot":"","sources":["../../src/evaluators/jit.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,iBAAiB,CAAA;AACtE,OAAO,KAAK,EACV,6BAA6B,EAC7B,qCAAqC,EACrC,wBAAwB,EACxB,8BAA8B,EAC/B,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AAwG9D,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,sBAAsB,EAC5B,gBAAgB,EAAE,WAAW,CAAC,MAAM,EAAE,8BAA8B,CAAC,EACrE,2BAA2B,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,EACvE,gBAAgB,EAAE,SAAS,+BAA+B,EAAE,GAC3D,wBAAwB,CAwB1B;AAED,wBAAgB,kCAAkC,CAChD,IAAI,EAAE,sBAAsB,EAC5B,gBAAgB,EAAE,WAAW,CAAC,MAAM,EAAE,8BAA8B,CAAC,EACrE,2BAA2B,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,GACtE,6BAA6B,CA2B/B;AAED,wBAAgB,0CAA0C,CACxD,IAAI,EAAE,sBAAsB,EAC5B,gBAAgB,EAAE,WAAW,CAAC,MAAM,EAAE,8BAA8B,CAAC,EACrE,2BAA2B,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,GACtE,qCAAqC,CA2BvC"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import {} from "../syntax/ast.js";
|
|
2
|
+
import { normalizeFormulaFunctionName } from "../syntax/functions.js";
|
|
3
|
+
import { buildJitReadValueBody, canInlineBuiltinFunction, createFormulaJitRuntimeHelpers, ZERO_FORMULA_NODE, } from "./shared.js";
|
|
4
|
+
function compileFormulaAstToJitExpression(root, options) {
|
|
5
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
6
|
+
if (root.kind === "number")
|
|
7
|
+
return Number.isFinite(root.value) ? String(root.value) : "0";
|
|
8
|
+
if (root.kind === "literal") {
|
|
9
|
+
if (root.value === null)
|
|
10
|
+
return "null";
|
|
11
|
+
if (root.value instanceof Date)
|
|
12
|
+
return `new Date(${root.value.getTime()})`;
|
|
13
|
+
if (typeof root.value === "string")
|
|
14
|
+
return JSON.stringify(root.value);
|
|
15
|
+
if (typeof root.value === "boolean")
|
|
16
|
+
return root.value ? "true" : "false";
|
|
17
|
+
return Number.isFinite(root.value) ? String(root.value) : "0";
|
|
18
|
+
}
|
|
19
|
+
if (root.kind === "identifier") {
|
|
20
|
+
const tokenIndex = options.resolveIdentifierTokenIndex(root.name);
|
|
21
|
+
if (typeof tokenIndex !== "number")
|
|
22
|
+
return "null";
|
|
23
|
+
return `readValue(${tokenIndex})`;
|
|
24
|
+
}
|
|
25
|
+
if (root.kind === "call") {
|
|
26
|
+
const normalizedFunctionName = normalizeFormulaFunctionName(root.name);
|
|
27
|
+
if (normalizedFunctionName === "IF") {
|
|
28
|
+
const condition = compileFormulaAstToJitExpression((_a = root.args[0]) !== null && _a !== void 0 ? _a : ZERO_FORMULA_NODE, options);
|
|
29
|
+
const whenTrue = compileFormulaAstToJitExpression((_b = root.args[1]) !== null && _b !== void 0 ? _b : ZERO_FORMULA_NODE, options);
|
|
30
|
+
const whenFalse = compileFormulaAstToJitExpression((_c = root.args[2]) !== null && _c !== void 0 ? _c : ZERO_FORMULA_NODE, options);
|
|
31
|
+
return `(toBoolean(${condition}) ? (${whenTrue}) : (${whenFalse}))`;
|
|
32
|
+
}
|
|
33
|
+
if (normalizedFunctionName === "IFS") {
|
|
34
|
+
const conditions = [];
|
|
35
|
+
for (let index = 0; index < root.args.length; index += 2) {
|
|
36
|
+
const conditionExpression = compileFormulaAstToJitExpression((_d = root.args[index]) !== null && _d !== void 0 ? _d : ZERO_FORMULA_NODE, options);
|
|
37
|
+
const valueExpression = compileFormulaAstToJitExpression((_e = root.args[index + 1]) !== null && _e !== void 0 ? _e : ZERO_FORMULA_NODE, options);
|
|
38
|
+
conditions.push(`if (toBoolean(${conditionExpression})) { return (${valueExpression}) }`);
|
|
39
|
+
}
|
|
40
|
+
return `(() => { ${conditions.join("; ")}; return 0 })()`;
|
|
41
|
+
}
|
|
42
|
+
if (normalizedFunctionName === "COALESCE") {
|
|
43
|
+
const checks = root.args.map((arg, index) => {
|
|
44
|
+
const expression = compileFormulaAstToJitExpression(arg, options);
|
|
45
|
+
const variableName = `coalesceValue${index}`;
|
|
46
|
+
return `const ${variableName} = (${expression}); if (isPresent(${variableName})) { return ${variableName} }`;
|
|
47
|
+
});
|
|
48
|
+
return `(() => { ${checks.join("; ")}; return 0 })()`;
|
|
49
|
+
}
|
|
50
|
+
if (options.canInlineBuiltin(normalizedFunctionName)) {
|
|
51
|
+
if (normalizedFunctionName === "ABS") {
|
|
52
|
+
const valueExpression = compileFormulaAstToJitExpression((_f = root.args[0]) !== null && _f !== void 0 ? _f : ZERO_FORMULA_NODE, options);
|
|
53
|
+
return `Math.abs(toNumber(${valueExpression}))`;
|
|
54
|
+
}
|
|
55
|
+
if (normalizedFunctionName === "ROUND") {
|
|
56
|
+
const valueExpression = compileFormulaAstToJitExpression((_g = root.args[0]) !== null && _g !== void 0 ? _g : ZERO_FORMULA_NODE, options);
|
|
57
|
+
const digitsExpression = compileFormulaAstToJitExpression((_h = root.args[1]) !== null && _h !== void 0 ? _h : ZERO_FORMULA_NODE, options);
|
|
58
|
+
return `round(toNumber(${valueExpression}), toNumber(${digitsExpression}))`;
|
|
59
|
+
}
|
|
60
|
+
if (normalizedFunctionName === "MIN") {
|
|
61
|
+
if (root.args.length === 0)
|
|
62
|
+
return "0";
|
|
63
|
+
const minArgs = root.args.map(arg => `toNumber(${compileFormulaAstToJitExpression(arg, options)})`).join(", ");
|
|
64
|
+
return `Math.min(${minArgs})`;
|
|
65
|
+
}
|
|
66
|
+
if (normalizedFunctionName === "MAX") {
|
|
67
|
+
if (root.args.length === 0)
|
|
68
|
+
return "0";
|
|
69
|
+
const maxArgs = root.args.map(arg => `toNumber(${compileFormulaAstToJitExpression(arg, options)})`).join(", ");
|
|
70
|
+
return `Math.max(${maxArgs})`;
|
|
71
|
+
}
|
|
72
|
+
if (normalizedFunctionName === "SUM") {
|
|
73
|
+
if (root.args.length === 0)
|
|
74
|
+
return "0";
|
|
75
|
+
return `(${root.args.map(arg => `toNumber(${compileFormulaAstToJitExpression(arg, options)})`).join(" + ")})`;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const args = root.args.map(arg => compileFormulaAstToJitExpression(arg, options)).join(", ");
|
|
79
|
+
return `callFunction(${JSON.stringify(normalizedFunctionName)}, [${args}])`;
|
|
80
|
+
}
|
|
81
|
+
if (root.kind === "unary") {
|
|
82
|
+
const valueExpression = compileFormulaAstToJitExpression(root.value, options);
|
|
83
|
+
if (root.operator === "-")
|
|
84
|
+
return `(-toNumber(${valueExpression}))`;
|
|
85
|
+
if (root.operator === "+")
|
|
86
|
+
return `(+toNumber(${valueExpression}))`;
|
|
87
|
+
return `(toBoolean(${valueExpression}) ? 0 : 1)`;
|
|
88
|
+
}
|
|
89
|
+
const leftExpression = compileFormulaAstToJitExpression(root.left, options);
|
|
90
|
+
const rightExpression = compileFormulaAstToJitExpression(root.right, options);
|
|
91
|
+
if (root.operator === "AND")
|
|
92
|
+
return `((toBoolean(${leftExpression}) && toBoolean(${rightExpression})) ? 1 : 0)`;
|
|
93
|
+
if (root.operator === "OR")
|
|
94
|
+
return `((toBoolean(${leftExpression}) || toBoolean(${rightExpression})) ? 1 : 0)`;
|
|
95
|
+
if (root.operator === "+")
|
|
96
|
+
return `(toNumber(${leftExpression}) + toNumber(${rightExpression}))`;
|
|
97
|
+
if (root.operator === "-")
|
|
98
|
+
return `(toNumber(${leftExpression}) - toNumber(${rightExpression}))`;
|
|
99
|
+
if (root.operator === "*")
|
|
100
|
+
return `(toNumber(${leftExpression}) * toNumber(${rightExpression}))`;
|
|
101
|
+
if (root.operator === "/")
|
|
102
|
+
return `divide(toNumber(${leftExpression}), toNumber(${rightExpression}))`;
|
|
103
|
+
if (root.operator === ">")
|
|
104
|
+
return `(compare(${leftExpression}, ${rightExpression}) > 0 ? 1 : 0)`;
|
|
105
|
+
if (root.operator === "<")
|
|
106
|
+
return `(compare(${leftExpression}, ${rightExpression}) < 0 ? 1 : 0)`;
|
|
107
|
+
if (root.operator === ">=")
|
|
108
|
+
return `(compare(${leftExpression}, ${rightExpression}) >= 0 ? 1 : 0)`;
|
|
109
|
+
if (root.operator === "<=")
|
|
110
|
+
return `(compare(${leftExpression}, ${rightExpression}) <= 0 ? 1 : 0)`;
|
|
111
|
+
if (root.operator === "==")
|
|
112
|
+
return `(equals(${leftExpression}, ${rightExpression}) ? 1 : 0)`;
|
|
113
|
+
return `(equals(${leftExpression}, ${rightExpression}) ? 0 : 1)`;
|
|
114
|
+
}
|
|
115
|
+
export function compileFormulaAstEvaluatorJit(root, functionRegistry, resolveIdentifierTokenIndex, dependencyTokens) {
|
|
116
|
+
const expression = compileFormulaAstToJitExpression(root, {
|
|
117
|
+
resolveIdentifierTokenIndex,
|
|
118
|
+
canInlineBuiltin: functionName => canInlineBuiltinFunction(functionName, functionRegistry),
|
|
119
|
+
});
|
|
120
|
+
const { toNumber, toBoolean, isPresent, compare, equals, callFunction, divide, round } = createFormulaJitRuntimeHelpers(functionRegistry);
|
|
121
|
+
const createEvaluator = new Function("toNumber", "toBoolean", "isPresent", "compare", "equals", "callFunction", "divide", "round", "dependencyTokens", `return function evaluate(readTokenValue) {
|
|
122
|
+
${buildJitReadValueBody("single")}
|
|
123
|
+
return (${expression})
|
|
124
|
+
}`);
|
|
125
|
+
return createEvaluator(toNumber, toBoolean, isPresent, compare, equals, callFunction, divide, round, dependencyTokens);
|
|
126
|
+
}
|
|
127
|
+
export function compileFormulaAstBatchEvaluatorJit(root, functionRegistry, resolveIdentifierTokenIndex) {
|
|
128
|
+
const expression = compileFormulaAstToJitExpression(root, {
|
|
129
|
+
resolveIdentifierTokenIndex,
|
|
130
|
+
canInlineBuiltin: functionName => canInlineBuiltinFunction(functionName, functionRegistry),
|
|
131
|
+
});
|
|
132
|
+
const { toNumber, toBoolean, isPresent, compare, equals, callFunction, divide, round } = createFormulaJitRuntimeHelpers(functionRegistry);
|
|
133
|
+
const createEvaluator = new Function("toNumber", "toBoolean", "isPresent", "compare", "equals", "callFunction", "divide", "round", `return function evaluateBatch(contextsCount, readTokenByIndex) {
|
|
134
|
+
const output = new Array(contextsCount)
|
|
135
|
+
for (let contextIndex = 0; contextIndex < contextsCount; contextIndex += 1) {
|
|
136
|
+
${buildJitReadValueBody("batch")}
|
|
137
|
+
output[contextIndex] = (${expression})
|
|
138
|
+
}
|
|
139
|
+
return output
|
|
140
|
+
}`);
|
|
141
|
+
return createEvaluator(toNumber, toBoolean, isPresent, compare, equals, callFunction, divide, round);
|
|
142
|
+
}
|
|
143
|
+
export function compileFormulaAstColumnarBatchEvaluatorJit(root, functionRegistry, resolveIdentifierTokenIndex) {
|
|
144
|
+
const expression = compileFormulaAstToJitExpression(root, {
|
|
145
|
+
resolveIdentifierTokenIndex,
|
|
146
|
+
canInlineBuiltin: functionName => canInlineBuiltinFunction(functionName, functionRegistry),
|
|
147
|
+
});
|
|
148
|
+
const { toNumber, toBoolean, isPresent, compare, equals, callFunction, divide, round } = createFormulaJitRuntimeHelpers(functionRegistry);
|
|
149
|
+
const createEvaluator = new Function("toNumber", "toBoolean", "isPresent", "compare", "equals", "callFunction", "divide", "round", `return function evaluateColumnarBatch(contextsCount, tokenColumns) {
|
|
150
|
+
const output = new Array(contextsCount)
|
|
151
|
+
for (let contextIndex = 0; contextIndex < contextsCount; contextIndex += 1) {
|
|
152
|
+
${buildJitReadValueBody("columnar")}
|
|
153
|
+
output[contextIndex] = (${expression})
|
|
154
|
+
}
|
|
155
|
+
return output
|
|
156
|
+
}`);
|
|
157
|
+
return createEvaluator(toNumber, toBoolean, isPresent, compare, equals, callFunction, divide, round);
|
|
158
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { DataGridFormulaValue } from "../coreTypes.js";
|
|
2
|
+
import { type DataGridFormulaFunctionRuntime } from "../runtime/types.js";
|
|
3
|
+
import { type DataGridFormulaAstNode, type DataGridFormulaOperator } from "../syntax/ast.js";
|
|
4
|
+
export declare const ZERO_FORMULA_NODE: DataGridFormulaAstNode;
|
|
5
|
+
export declare const NON_INLINEABLE_BUILTIN_FUNCTIONS: Set<string>;
|
|
6
|
+
export type DataGridFormulaFusedColumnKernel = (contextsCount: number, tokenColumns: readonly (readonly unknown[])[]) => DataGridFormulaValue[];
|
|
7
|
+
export type DataGridFormulaVectorColumnKernel = (contextsCount: number, tokenColumns: readonly (readonly unknown[])[]) => DataGridFormulaValue[];
|
|
8
|
+
export declare function createFormulaConstantColumnKernel(value: DataGridFormulaValue): DataGridFormulaVectorColumnKernel;
|
|
9
|
+
export declare function createFormulaIdentifierColumnKernel(tokenIndex: number | undefined): DataGridFormulaVectorColumnKernel;
|
|
10
|
+
export interface DataGridFormulaRowIndexSelection {
|
|
11
|
+
indexes: readonly number[];
|
|
12
|
+
count: number;
|
|
13
|
+
}
|
|
14
|
+
export declare function createFormulaArrayFilled(contextsCount: number, value: DataGridFormulaValue): DataGridFormulaValue[];
|
|
15
|
+
export declare function sliceTokenColumnsByIndexes(tokenColumns: readonly (readonly unknown[])[], rowIndexes: readonly number[] | DataGridFormulaRowIndexSelection): unknown[][];
|
|
16
|
+
export declare function evaluateVectorKernelForIndexes(kernel: DataGridFormulaVectorColumnKernel, tokenColumns: readonly (readonly unknown[])[], rowIndexes: readonly number[] | DataGridFormulaRowIndexSelection): DataGridFormulaValue[];
|
|
17
|
+
export declare function createSequentialRowIndexes(contextsCount: number): number[];
|
|
18
|
+
export declare function evaluateFormulaUnaryOperator(operator: "-" | "+" | "NOT", value: DataGridFormulaValue): DataGridFormulaValue;
|
|
19
|
+
export declare function evaluateFormulaBinaryOperator(operator: DataGridFormulaOperator, left: DataGridFormulaValue, right: DataGridFormulaValue): DataGridFormulaValue;
|
|
20
|
+
export declare function createFormulaUnaryColumnKernel(valueKernel: DataGridFormulaVectorColumnKernel, operator: "-" | "+" | "NOT"): DataGridFormulaVectorColumnKernel;
|
|
21
|
+
export declare function createFormulaBinaryColumnKernel(leftKernel: DataGridFormulaVectorColumnKernel, rightKernel: DataGridFormulaVectorColumnKernel, operator: DataGridFormulaOperator): DataGridFormulaVectorColumnKernel;
|
|
22
|
+
export interface DataGridFormulaJitRuntimeHelpers {
|
|
23
|
+
toNumber: (value: DataGridFormulaValue) => number;
|
|
24
|
+
toBoolean: (value: DataGridFormulaValue) => boolean;
|
|
25
|
+
isPresent: (value: DataGridFormulaValue) => boolean;
|
|
26
|
+
compare: (left: DataGridFormulaValue, right: DataGridFormulaValue) => number;
|
|
27
|
+
equals: (left: DataGridFormulaValue, right: DataGridFormulaValue) => boolean;
|
|
28
|
+
callFunction: (functionName: string, args: readonly DataGridFormulaValue[]) => DataGridFormulaValue;
|
|
29
|
+
divide: (left: number, right: number) => number;
|
|
30
|
+
round: (value: number, digits: number) => number;
|
|
31
|
+
}
|
|
32
|
+
export type DataGridFormulaJitReadValueMode = "single" | "batch" | "columnar";
|
|
33
|
+
export declare function buildJitReadValueBody(mode: DataGridFormulaJitReadValueMode): string;
|
|
34
|
+
export declare function createFormulaJitRuntimeHelpers(functionRegistry: ReadonlyMap<string, DataGridFormulaFunctionRuntime>): DataGridFormulaJitRuntimeHelpers;
|
|
35
|
+
export declare function canInlineBuiltinFunction(functionName: string, functionRegistry: ReadonlyMap<string, DataGridFormulaFunctionRuntime>): boolean;
|
|
36
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/evaluators/shared.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import {} from "../runtime/types.js";
|
|
2
|
+
import { DATAGRID_DEFAULT_FORMULA_FUNCTIONS } from "../syntax/functions.js";
|
|
3
|
+
import { DataGridFormulaEvaluationError, createFormulaSourceSpan, } from "../syntax/ast.js";
|
|
4
|
+
import { areFormulaValuesEqual, coerceFormulaValueToBoolean, coerceFormulaValueToNumber, compareFormulaValues, createFormulaRuntimeError, findFormulaErrorValue, formulaNumberIsTruthy, isFormulaErrorValue, isFormulaValuePresent, normalizeFormulaValue, } from "../syntax/values.js";
|
|
5
|
+
export const ZERO_FORMULA_NODE = {
|
|
6
|
+
kind: "number",
|
|
7
|
+
value: 0,
|
|
8
|
+
span: createFormulaSourceSpan(0, 0),
|
|
9
|
+
};
|
|
10
|
+
export const NON_INLINEABLE_BUILTIN_FUNCTIONS = new Set([
|
|
11
|
+
"ARRAY",
|
|
12
|
+
"AVG",
|
|
13
|
+
"CONCAT",
|
|
14
|
+
"COUNT",
|
|
15
|
+
"INDEX",
|
|
16
|
+
"IN",
|
|
17
|
+
"LEN",
|
|
18
|
+
"MATCH",
|
|
19
|
+
"MAX",
|
|
20
|
+
"MIN",
|
|
21
|
+
"RANGE",
|
|
22
|
+
"SUM",
|
|
23
|
+
"TABLE",
|
|
24
|
+
"XLOOKUP",
|
|
25
|
+
]);
|
|
26
|
+
export function createFormulaConstantColumnKernel(value) {
|
|
27
|
+
return (contextsCount) => createFormulaArrayFilled(contextsCount, value);
|
|
28
|
+
}
|
|
29
|
+
export function createFormulaIdentifierColumnKernel(tokenIndex) {
|
|
30
|
+
if (typeof tokenIndex !== "number") {
|
|
31
|
+
return (contextsCount) => createFormulaArrayFilled(contextsCount, null);
|
|
32
|
+
}
|
|
33
|
+
return (contextsCount, tokenColumns) => {
|
|
34
|
+
const output = new Array(contextsCount);
|
|
35
|
+
const column = tokenColumns[tokenIndex];
|
|
36
|
+
for (let contextIndex = 0; contextIndex < contextsCount; contextIndex += 1) {
|
|
37
|
+
output[contextIndex] = normalizeFormulaValue(column ? column[contextIndex] : undefined);
|
|
38
|
+
}
|
|
39
|
+
return output;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function isFormulaRowIndexSelection(rowIndexes) {
|
|
43
|
+
return !Array.isArray(rowIndexes);
|
|
44
|
+
}
|
|
45
|
+
export function createFormulaArrayFilled(contextsCount, value) {
|
|
46
|
+
const output = new Array(contextsCount);
|
|
47
|
+
for (let contextIndex = 0; contextIndex < contextsCount; contextIndex += 1) {
|
|
48
|
+
output[contextIndex] = value;
|
|
49
|
+
}
|
|
50
|
+
return output;
|
|
51
|
+
}
|
|
52
|
+
export function sliceTokenColumnsByIndexes(tokenColumns, rowIndexes) {
|
|
53
|
+
const indexes = isFormulaRowIndexSelection(rowIndexes) ? rowIndexes.indexes : rowIndexes;
|
|
54
|
+
const count = isFormulaRowIndexSelection(rowIndexes) ? rowIndexes.count : rowIndexes.length;
|
|
55
|
+
return tokenColumns.map((column) => {
|
|
56
|
+
const subset = new Array(count);
|
|
57
|
+
for (let index = 0; index < count; index += 1) {
|
|
58
|
+
const rowIndex = indexes[index];
|
|
59
|
+
subset[index] = typeof rowIndex === "number" ? column === null || column === void 0 ? void 0 : column[rowIndex] : undefined;
|
|
60
|
+
}
|
|
61
|
+
return subset;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
export function evaluateVectorKernelForIndexes(kernel, tokenColumns, rowIndexes) {
|
|
65
|
+
const count = isFormulaRowIndexSelection(rowIndexes) ? rowIndexes.count : rowIndexes.length;
|
|
66
|
+
if (count === 0) {
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
return kernel(count, sliceTokenColumnsByIndexes(tokenColumns, rowIndexes));
|
|
70
|
+
}
|
|
71
|
+
export function createSequentialRowIndexes(contextsCount) {
|
|
72
|
+
const rowIndexes = new Array(contextsCount);
|
|
73
|
+
for (let index = 0; index < contextsCount; index += 1) {
|
|
74
|
+
rowIndexes[index] = index;
|
|
75
|
+
}
|
|
76
|
+
return rowIndexes;
|
|
77
|
+
}
|
|
78
|
+
export function evaluateFormulaUnaryOperator(operator, value) {
|
|
79
|
+
if (isFormulaErrorValue(value)) {
|
|
80
|
+
return value;
|
|
81
|
+
}
|
|
82
|
+
if (operator === "-") {
|
|
83
|
+
return -coerceFormulaValueToNumber(value);
|
|
84
|
+
}
|
|
85
|
+
if (operator === "+") {
|
|
86
|
+
return coerceFormulaValueToNumber(value);
|
|
87
|
+
}
|
|
88
|
+
return formulaNumberIsTruthy(value) ? 0 : 1;
|
|
89
|
+
}
|
|
90
|
+
export function evaluateFormulaBinaryOperator(operator, left, right) {
|
|
91
|
+
const formulaError = findFormulaErrorValue([left, right]);
|
|
92
|
+
if (formulaError) {
|
|
93
|
+
return formulaError;
|
|
94
|
+
}
|
|
95
|
+
if (operator === "+") {
|
|
96
|
+
return coerceFormulaValueToNumber(left) + coerceFormulaValueToNumber(right);
|
|
97
|
+
}
|
|
98
|
+
if (operator === "-") {
|
|
99
|
+
return coerceFormulaValueToNumber(left) - coerceFormulaValueToNumber(right);
|
|
100
|
+
}
|
|
101
|
+
if (operator === "*") {
|
|
102
|
+
return coerceFormulaValueToNumber(left) * coerceFormulaValueToNumber(right);
|
|
103
|
+
}
|
|
104
|
+
if (operator === "/") {
|
|
105
|
+
const divisor = coerceFormulaValueToNumber(right);
|
|
106
|
+
if (divisor === 0) {
|
|
107
|
+
throw new DataGridFormulaEvaluationError(createFormulaRuntimeError("DIV_ZERO", "Division by zero.", { operator: "/" }));
|
|
108
|
+
}
|
|
109
|
+
return coerceFormulaValueToNumber(left) / divisor;
|
|
110
|
+
}
|
|
111
|
+
if (operator === ">") {
|
|
112
|
+
return compareFormulaValues(left, right) > 0 ? 1 : 0;
|
|
113
|
+
}
|
|
114
|
+
if (operator === "<") {
|
|
115
|
+
return compareFormulaValues(left, right) < 0 ? 1 : 0;
|
|
116
|
+
}
|
|
117
|
+
if (operator === ">=") {
|
|
118
|
+
return compareFormulaValues(left, right) >= 0 ? 1 : 0;
|
|
119
|
+
}
|
|
120
|
+
if (operator === "<=") {
|
|
121
|
+
return compareFormulaValues(left, right) <= 0 ? 1 : 0;
|
|
122
|
+
}
|
|
123
|
+
if (operator === "==") {
|
|
124
|
+
return areFormulaValuesEqual(left, right) ? 1 : 0;
|
|
125
|
+
}
|
|
126
|
+
if (operator === "!=") {
|
|
127
|
+
return areFormulaValuesEqual(left, right) ? 0 : 1;
|
|
128
|
+
}
|
|
129
|
+
throw new Error(`Unsupported non-scalar binary operator '${operator}'.`);
|
|
130
|
+
}
|
|
131
|
+
export function createFormulaUnaryColumnKernel(valueKernel, operator) {
|
|
132
|
+
return (contextsCount, tokenColumns) => {
|
|
133
|
+
var _a;
|
|
134
|
+
const values = valueKernel(contextsCount, tokenColumns);
|
|
135
|
+
const output = new Array(contextsCount);
|
|
136
|
+
for (let contextIndex = 0; contextIndex < contextsCount; contextIndex += 1) {
|
|
137
|
+
const value = (_a = values[contextIndex]) !== null && _a !== void 0 ? _a : null;
|
|
138
|
+
output[contextIndex] = evaluateFormulaUnaryOperator(operator, value);
|
|
139
|
+
}
|
|
140
|
+
return output;
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
export function createFormulaBinaryColumnKernel(leftKernel, rightKernel, operator) {
|
|
144
|
+
return (contextsCount, tokenColumns) => {
|
|
145
|
+
var _a, _b;
|
|
146
|
+
const leftValues = leftKernel(contextsCount, tokenColumns);
|
|
147
|
+
const rightValues = rightKernel(contextsCount, tokenColumns);
|
|
148
|
+
const output = new Array(contextsCount);
|
|
149
|
+
for (let contextIndex = 0; contextIndex < contextsCount; contextIndex += 1) {
|
|
150
|
+
const left = (_a = leftValues[contextIndex]) !== null && _a !== void 0 ? _a : null;
|
|
151
|
+
const right = (_b = rightValues[contextIndex]) !== null && _b !== void 0 ? _b : null;
|
|
152
|
+
output[contextIndex] = evaluateFormulaBinaryOperator(operator, left, right);
|
|
153
|
+
}
|
|
154
|
+
return output;
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
export function buildJitReadValueBody(mode) {
|
|
158
|
+
const readRawExpression = mode === "single"
|
|
159
|
+
? `const token = dependencyTokens[tokenIndex]\n const raw = readTokenValue(token)`
|
|
160
|
+
: mode === "batch"
|
|
161
|
+
? `const raw = readTokenByIndex(contextIndex, tokenIndex)`
|
|
162
|
+
: `const column = tokenColumns[tokenIndex]\n const raw = column ? column[contextIndex] : undefined`;
|
|
163
|
+
return `const readValue = (tokenIndex) => {
|
|
164
|
+
${readRawExpression}
|
|
165
|
+
if (raw === null || typeof raw === "undefined") {
|
|
166
|
+
return null
|
|
167
|
+
}
|
|
168
|
+
if (raw instanceof Date) {
|
|
169
|
+
const rawTime = raw.getTime()
|
|
170
|
+
return Number.isNaN(rawTime) ? null : raw
|
|
171
|
+
}
|
|
172
|
+
const rawType = typeof raw
|
|
173
|
+
if (rawType === "number") {
|
|
174
|
+
return Number.isFinite(raw) ? raw : 0
|
|
175
|
+
}
|
|
176
|
+
if (rawType === "string" || rawType === "boolean") {
|
|
177
|
+
return raw
|
|
178
|
+
}
|
|
179
|
+
if (rawType === "object" && raw && raw.kind === "error" && typeof raw.code === "string" && typeof raw.message === "string") {
|
|
180
|
+
return raw
|
|
181
|
+
}
|
|
182
|
+
if (rawType === "bigint") {
|
|
183
|
+
return Number(raw)
|
|
184
|
+
}
|
|
185
|
+
return null
|
|
186
|
+
}`;
|
|
187
|
+
}
|
|
188
|
+
export function createFormulaJitRuntimeHelpers(functionRegistry) {
|
|
189
|
+
const divide = (left, right) => {
|
|
190
|
+
if (right === 0) {
|
|
191
|
+
throw new DataGridFormulaEvaluationError(createFormulaRuntimeError("DIV_ZERO", "Division by zero.", { operator: "/" }));
|
|
192
|
+
}
|
|
193
|
+
return left / right;
|
|
194
|
+
};
|
|
195
|
+
const callFunction = (functionName, args) => {
|
|
196
|
+
const functionDefinition = functionRegistry.get(functionName);
|
|
197
|
+
if (!functionDefinition) {
|
|
198
|
+
throw new DataGridFormulaEvaluationError(createFormulaRuntimeError("FUNCTION_UNKNOWN", `Unknown function '${functionName}'.`, { functionName }));
|
|
199
|
+
}
|
|
200
|
+
try {
|
|
201
|
+
const formulaError = findFormulaErrorValue(args);
|
|
202
|
+
if (formulaError) {
|
|
203
|
+
return formulaError;
|
|
204
|
+
}
|
|
205
|
+
return normalizeFormulaValue(functionDefinition.compute(args));
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
throw new DataGridFormulaEvaluationError(createFormulaRuntimeError("EVAL_ERROR", error instanceof Error ? error.message : String(error !== null && error !== void 0 ? error : "Function evaluation failed."), { functionName: functionDefinition.name }));
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
const toNumber = (value) => coerceFormulaValueToNumber(value);
|
|
212
|
+
const toBoolean = (value) => coerceFormulaValueToBoolean(value);
|
|
213
|
+
const isPresent = (value) => isFormulaValuePresent(value);
|
|
214
|
+
const compare = (left, right) => compareFormulaValues(left, right);
|
|
215
|
+
const equals = (left, right) => areFormulaValuesEqual(left, right);
|
|
216
|
+
const round = (value, digits) => {
|
|
217
|
+
const safeDigits = Math.max(0, Math.trunc(digits));
|
|
218
|
+
const factor = 10 ** safeDigits;
|
|
219
|
+
return Math.round(value * factor) / factor;
|
|
220
|
+
};
|
|
221
|
+
return {
|
|
222
|
+
toNumber,
|
|
223
|
+
toBoolean,
|
|
224
|
+
isPresent,
|
|
225
|
+
compare,
|
|
226
|
+
equals,
|
|
227
|
+
callFunction,
|
|
228
|
+
divide,
|
|
229
|
+
round,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
export function canInlineBuiltinFunction(functionName, functionRegistry) {
|
|
233
|
+
if (NON_INLINEABLE_BUILTIN_FUNCTIONS.has(functionName)) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
const defaultDefinition = DATAGRID_DEFAULT_FORMULA_FUNCTIONS[functionName];
|
|
237
|
+
const runtimeDefinition = functionRegistry.get(functionName);
|
|
238
|
+
if (!defaultDefinition || !runtimeDefinition) {
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
return runtimeDefinition.compute === defaultDefinition.compute;
|
|
242
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { DataGridFormulaColumnarBatchEvaluator } from "../runtime/types.js";
|
|
2
|
+
import { type DataGridFormulaAstNode } from "../syntax/ast.js";
|
|
3
|
+
import { type DataGridFormulaVectorColumnKernel } from "./shared.js";
|
|
4
|
+
export declare function compileFormulaAstVectorColumnKernel(root: DataGridFormulaAstNode, resolveIdentifierTokenIndex: (identifier: string) => number | undefined): DataGridFormulaVectorColumnKernel | null;
|
|
5
|
+
export declare function compileFormulaAstColumnarBatchEvaluatorVector(root: DataGridFormulaAstNode, resolveIdentifierTokenIndex: (identifier: string) => number | undefined): DataGridFormulaColumnarBatchEvaluator | null;
|
|
6
|
+
//# sourceMappingURL=vector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vector.d.ts","sourceRoot":"","sources":["../../src/evaluators/vector.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qCAAqC,EAAE,MAAM,qBAAqB,CAAA;AAChF,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AAO9D,OAAO,EAQL,KAAK,iCAAiC,EAEvC,MAAM,aAAa,CAAA;AAapB,wBAAgB,mCAAmC,CACjD,IAAI,EAAE,sBAAsB,EAC5B,2BAA2B,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,GACtE,iCAAiC,GAAG,IAAI,CAsO1C;AAED,wBAAgB,6CAA6C,CAC3D,IAAI,EAAE,sBAAsB,EAC5B,2BAA2B,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,GACtE,qCAAqC,GAAG,IAAI,CAI9C"}
|