@bilig/formula 0.1.82 → 0.1.84
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/dist/addressing.d.ts +6 -6
- package/dist/addressing.js +16 -16
- package/dist/addressing.js.map +1 -1
- package/dist/ast.d.ts +18 -18
- package/dist/binder-wasm-rules.d.ts +2 -2
- package/dist/binder-wasm-rules.js +677 -724
- package/dist/binder-wasm-rules.js.map +1 -1
- package/dist/binder.d.ts +2 -2
- package/dist/binder.js +133 -137
- package/dist/binder.js.map +1 -1
- package/dist/builtin-capabilities.d.ts +4 -4
- package/dist/builtin-capabilities.js +777 -816
- package/dist/builtin-capabilities.js.map +1 -1
- package/dist/builtins/complex.d.ts +3 -3
- package/dist/builtins/complex.js +20 -48
- package/dist/builtins/complex.js.map +1 -1
- package/dist/builtins/convert.d.ts +1 -1
- package/dist/builtins/convert.js +180 -181
- package/dist/builtins/convert.js.map +1 -1
- package/dist/builtins/datetime.d.ts +1 -1
- package/dist/builtins/datetime.js +60 -72
- package/dist/builtins/datetime.js.map +1 -1
- package/dist/builtins/distribution-builtins.d.ts +2 -2
- package/dist/builtins/distribution-builtins.js +62 -112
- package/dist/builtins/distribution-builtins.js.map +1 -1
- package/dist/builtins/distributions.js +17 -54
- package/dist/builtins/distributions.js.map +1 -1
- package/dist/builtins/financial-builtins.d.ts +2 -2
- package/dist/builtins/financial-builtins.js +9 -42
- package/dist/builtins/financial-builtins.js.map +1 -1
- package/dist/builtins/financial.js +4 -18
- package/dist/builtins/financial.js.map +1 -1
- package/dist/builtins/fixed-income-builtins.d.ts +2 -2
- package/dist/builtins/fixed-income-builtins.js +18 -60
- package/dist/builtins/fixed-income-builtins.js.map +1 -1
- package/dist/builtins/fixed-income.js +25 -96
- package/dist/builtins/fixed-income.js.map +1 -1
- package/dist/builtins/formatting.js +9 -9
- package/dist/builtins/formatting.js.map +1 -1
- package/dist/builtins/logical.d.ts +1 -1
- package/dist/builtins/logical.js +5 -5
- package/dist/builtins/logical.js.map +1 -1
- package/dist/builtins/lookup-array-shape-builtins.d.ts +3 -3
- package/dist/builtins/lookup-array-shape-builtins.js +8 -15
- package/dist/builtins/lookup-array-shape-builtins.js.map +1 -1
- package/dist/builtins/lookup-criteria-builtins.d.ts +2 -2
- package/dist/builtins/lookup-criteria-builtins.js +1 -1
- package/dist/builtins/lookup-criteria-builtins.js.map +1 -1
- package/dist/builtins/lookup-database-builtins.d.ts +2 -2
- package/dist/builtins/lookup-database-builtins.js +20 -24
- package/dist/builtins/lookup-database-builtins.js.map +1 -1
- package/dist/builtins/lookup-financial-builtins.d.ts +3 -3
- package/dist/builtins/lookup-financial-builtins.js +14 -30
- package/dist/builtins/lookup-financial-builtins.js.map +1 -1
- package/dist/builtins/lookup-hypothesis-builtins.d.ts +2 -2
- package/dist/builtins/lookup-hypothesis-builtins.js +23 -58
- package/dist/builtins/lookup-hypothesis-builtins.js.map +1 -1
- package/dist/builtins/lookup-matrix-builtins.d.ts +3 -3
- package/dist/builtins/lookup-matrix-builtins.js +5 -3
- package/dist/builtins/lookup-matrix-builtins.js.map +1 -1
- package/dist/builtins/lookup-order-statistics-builtins.d.ts +3 -3
- package/dist/builtins/lookup-order-statistics-builtins.js +18 -30
- package/dist/builtins/lookup-order-statistics-builtins.js.map +1 -1
- package/dist/builtins/lookup-reference-builtins.d.ts +2 -2
- package/dist/builtins/lookup-reference-builtins.js +10 -26
- package/dist/builtins/lookup-reference-builtins.js.map +1 -1
- package/dist/builtins/lookup-regression-builtins.d.ts +2 -2
- package/dist/builtins/lookup-regression-builtins.js +52 -69
- package/dist/builtins/lookup-regression-builtins.js.map +1 -1
- package/dist/builtins/lookup-sort-filter-builtins.d.ts +3 -3
- package/dist/builtins/lookup-sort-filter-builtins.js +5 -13
- package/dist/builtins/lookup-sort-filter-builtins.js.map +1 -1
- package/dist/builtins/lookup.d.ts +5 -5
- package/dist/builtins/lookup.js +61 -73
- package/dist/builtins/lookup.js.map +1 -1
- package/dist/builtins/math-builtins.d.ts +2 -2
- package/dist/builtins/math-builtins.js +11 -17
- package/dist/builtins/math-builtins.js.map +1 -1
- package/dist/builtins/numeric.d.ts +2 -2
- package/dist/builtins/numeric.js +2 -2
- package/dist/builtins/numeric.js.map +1 -1
- package/dist/builtins/placeholder.d.ts +1 -1
- package/dist/builtins/placeholder.js +505 -505
- package/dist/builtins/placeholder.js.map +1 -1
- package/dist/builtins/radix.d.ts +2 -2
- package/dist/builtins/radix.js +33 -39
- package/dist/builtins/radix.js.map +1 -1
- package/dist/builtins/statistical-builtins.d.ts +2 -2
- package/dist/builtins/statistical-builtins.js +29 -56
- package/dist/builtins/statistical-builtins.js.map +1 -1
- package/dist/builtins/statistics.d.ts +1 -1
- package/dist/builtins/statistics.js +3 -7
- package/dist/builtins/statistics.js.map +1 -1
- package/dist/builtins/text-core-builtins.d.ts +2 -2
- package/dist/builtins/text-core-builtins.js +110 -110
- package/dist/builtins/text-core-builtins.js.map +1 -1
- package/dist/builtins/text-format-builtins.d.ts +2 -2
- package/dist/builtins/text-format-builtins.js +109 -141
- package/dist/builtins/text-format-builtins.js.map +1 -1
- package/dist/builtins/text-search-builtins.d.ts +2 -2
- package/dist/builtins/text-search-builtins.js +37 -44
- package/dist/builtins/text-search-builtins.js.map +1 -1
- package/dist/builtins/text.d.ts +2 -2
- package/dist/builtins/text.js +19 -29
- package/dist/builtins/text.js.map +1 -1
- package/dist/builtins.d.ts +3 -3
- package/dist/builtins.js +55 -75
- package/dist/builtins.js.map +1 -1
- package/dist/compatibility.js +425 -430
- package/dist/compatibility.js.map +1 -1
- package/dist/compiler.d.ts +7 -7
- package/dist/compiler.js +212 -228
- package/dist/compiler.js.map +1 -1
- package/dist/external-function-adapter.d.ts +6 -6
- package/dist/external-function-adapter.js +3 -3
- package/dist/external-function-adapter.js.map +1 -1
- package/dist/formula-template-key.js +25 -26
- package/dist/formula-template-key.js.map +1 -1
- package/dist/generated/formula-inventory.js +3567 -3567
- package/dist/generated/formula-inventory.js.map +1 -1
- package/dist/group-pivot-evaluator.d.ts +2 -2
- package/dist/group-pivot-evaluator.js +27 -32
- package/dist/group-pivot-evaluator.js.map +1 -1
- package/dist/index.d.ts +20 -20
- package/dist/index.js +20 -20
- package/dist/index.js.map +1 -1
- package/dist/js-evaluator-array-special-calls.d.ts +3 -3
- package/dist/js-evaluator-array-special-calls.js +25 -34
- package/dist/js-evaluator-array-special-calls.js.map +1 -1
- package/dist/js-evaluator-context-special-calls.d.ts +2 -2
- package/dist/js-evaluator-context-special-calls.js +23 -27
- package/dist/js-evaluator-context-special-calls.js.map +1 -1
- package/dist/js-evaluator-reference-context.d.ts +2 -2
- package/dist/js-evaluator-reference-context.js +22 -24
- package/dist/js-evaluator-reference-context.js.map +1 -1
- package/dist/js-evaluator-workbook-special-calls.d.ts +2 -2
- package/dist/js-evaluator-workbook-special-calls.js +18 -24
- package/dist/js-evaluator-workbook-special-calls.js.map +1 -1
- package/dist/js-evaluator.d.ts +40 -40
- package/dist/js-evaluator.js +135 -147
- package/dist/js-evaluator.js.map +1 -1
- package/dist/js-plan-lowering.d.ts +2 -2
- package/dist/js-plan-lowering.js +103 -108
- package/dist/js-plan-lowering.js.map +1 -1
- package/dist/lexer.d.ts +1 -1
- package/dist/lexer.js +34 -43
- package/dist/lexer.js.map +1 -1
- package/dist/optimizer.d.ts +1 -1
- package/dist/optimizer.js +99 -108
- package/dist/optimizer.js.map +1 -1
- package/dist/parser.d.ts +1 -1
- package/dist/parser.js +129 -136
- package/dist/parser.js.map +1 -1
- package/dist/program-arena.js.map +1 -1
- package/dist/runtime-inventory.d.ts +2 -2
- package/dist/runtime-inventory.js +14 -20
- package/dist/runtime-inventory.js.map +1 -1
- package/dist/runtime-values.d.ts +4 -4
- package/dist/runtime-values.js +2 -2
- package/dist/runtime-values.js.map +1 -1
- package/dist/special-call-rewrites.d.ts +1 -1
- package/dist/special-call-rewrites.js +14 -18
- package/dist/special-call-rewrites.js.map +1 -1
- package/dist/translation.d.ts +7 -7
- package/dist/translation.js +323 -366
- package/dist/translation.js.map +1 -1
- package/package.json +2 -2
package/dist/js-evaluator.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { ErrorCode, ValueTag, formatErrorCode } from
|
|
2
|
-
import { parseRangeAddress } from
|
|
3
|
-
import { getBuiltin } from
|
|
4
|
-
import { getLookupBuiltin
|
|
5
|
-
import { evaluateArraySpecialCall } from
|
|
6
|
-
import { evaluateContextSpecialCall } from
|
|
7
|
-
import { absoluteAddress, cellTypeCode, currentCellReference, referenceColumnNumber, referenceRowNumber, referenceSheetName, referenceTopLeftAddress, sheetIndexByName, sheetNames, } from
|
|
8
|
-
import { evaluateWorkbookSpecialCall } from
|
|
9
|
-
import { lowerToPlan } from
|
|
10
|
-
import { isArrayValue, scalarFromEvaluationResult
|
|
11
|
-
export { lowerToPlan } from
|
|
1
|
+
import { ErrorCode, ValueTag, formatErrorCode } from '@bilig/protocol';
|
|
2
|
+
import { parseRangeAddress } from './addressing.js';
|
|
3
|
+
import { getBuiltin } from './builtins.js';
|
|
4
|
+
import { getLookupBuiltin } from './builtins/lookup.js';
|
|
5
|
+
import { evaluateArraySpecialCall } from './js-evaluator-array-special-calls.js';
|
|
6
|
+
import { evaluateContextSpecialCall } from './js-evaluator-context-special-calls.js';
|
|
7
|
+
import { absoluteAddress, cellTypeCode, currentCellReference, referenceColumnNumber, referenceRowNumber, referenceSheetName, referenceTopLeftAddress, sheetIndexByName, sheetNames, } from './js-evaluator-reference-context.js';
|
|
8
|
+
import { evaluateWorkbookSpecialCall } from './js-evaluator-workbook-special-calls.js';
|
|
9
|
+
import { lowerToPlan } from './js-plan-lowering.js';
|
|
10
|
+
import { isArrayValue, scalarFromEvaluationResult } from './runtime-values.js';
|
|
11
|
+
export { lowerToPlan } from './js-plan-lowering.js';
|
|
12
12
|
function emptyValue() {
|
|
13
13
|
return { tag: ValueTag.Empty };
|
|
14
14
|
}
|
|
@@ -39,11 +39,11 @@ function toNumber(value) {
|
|
|
39
39
|
function toStringValue(value) {
|
|
40
40
|
switch (value.tag) {
|
|
41
41
|
case ValueTag.Empty:
|
|
42
|
-
return
|
|
42
|
+
return '';
|
|
43
43
|
case ValueTag.Number:
|
|
44
44
|
return String(value.value);
|
|
45
45
|
case ValueTag.Boolean:
|
|
46
|
-
return value.value ?
|
|
46
|
+
return value.value ? 'TRUE' : 'FALSE';
|
|
47
47
|
case ValueTag.String:
|
|
48
48
|
return value.value;
|
|
49
49
|
case ValueTag.Error:
|
|
@@ -83,36 +83,36 @@ function popScalar(stack) {
|
|
|
83
83
|
if (!value) {
|
|
84
84
|
return error(ErrorCode.Value);
|
|
85
85
|
}
|
|
86
|
-
if (value.kind ===
|
|
86
|
+
if (value.kind === 'scalar') {
|
|
87
87
|
return value.value;
|
|
88
88
|
}
|
|
89
|
-
if (value.kind ===
|
|
89
|
+
if (value.kind === 'omitted') {
|
|
90
90
|
return error(ErrorCode.Value);
|
|
91
91
|
}
|
|
92
|
-
if (value.kind ===
|
|
92
|
+
if (value.kind === 'lambda') {
|
|
93
93
|
return error(ErrorCode.Value);
|
|
94
94
|
}
|
|
95
95
|
return value.values[0] ?? emptyValue();
|
|
96
96
|
}
|
|
97
97
|
function popArgument(stack) {
|
|
98
|
-
return stack.pop() ?? { kind:
|
|
98
|
+
return stack.pop() ?? { kind: 'scalar', value: error(ErrorCode.Value) };
|
|
99
99
|
}
|
|
100
100
|
function toEvaluationResult(value) {
|
|
101
101
|
if (!value) {
|
|
102
102
|
return error(ErrorCode.Value);
|
|
103
103
|
}
|
|
104
|
-
if (value.kind ===
|
|
104
|
+
if (value.kind === 'scalar') {
|
|
105
105
|
return value.value;
|
|
106
106
|
}
|
|
107
|
-
if (value.kind ===
|
|
107
|
+
if (value.kind === 'omitted') {
|
|
108
108
|
return error(ErrorCode.Value);
|
|
109
109
|
}
|
|
110
|
-
if (value.kind ===
|
|
110
|
+
if (value.kind === 'lambda') {
|
|
111
111
|
return error(ErrorCode.Value);
|
|
112
112
|
}
|
|
113
|
-
if (value.kind ===
|
|
113
|
+
if (value.kind === 'range') {
|
|
114
114
|
return {
|
|
115
|
-
kind:
|
|
115
|
+
kind: 'array',
|
|
116
116
|
rows: value.rows,
|
|
117
117
|
cols: value.cols,
|
|
118
118
|
values: value.values,
|
|
@@ -121,15 +121,15 @@ function toEvaluationResult(value) {
|
|
|
121
121
|
return value;
|
|
122
122
|
}
|
|
123
123
|
function cloneStackValue(value) {
|
|
124
|
-
if (value.kind ===
|
|
125
|
-
return { kind:
|
|
124
|
+
if (value.kind === 'scalar') {
|
|
125
|
+
return { kind: 'scalar', value: value.value };
|
|
126
126
|
}
|
|
127
|
-
if (value.kind ===
|
|
128
|
-
return { kind:
|
|
127
|
+
if (value.kind === 'omitted') {
|
|
128
|
+
return { kind: 'omitted' };
|
|
129
129
|
}
|
|
130
|
-
if (value.kind ===
|
|
130
|
+
if (value.kind === 'range') {
|
|
131
131
|
return {
|
|
132
|
-
kind:
|
|
132
|
+
kind: 'range',
|
|
133
133
|
values: value.values,
|
|
134
134
|
refKind: value.refKind,
|
|
135
135
|
rows: value.rows,
|
|
@@ -139,39 +139,39 @@ function cloneStackValue(value) {
|
|
|
139
139
|
...(value.end ? { end: value.end } : {}),
|
|
140
140
|
};
|
|
141
141
|
}
|
|
142
|
-
if (value.kind ===
|
|
142
|
+
if (value.kind === 'lambda') {
|
|
143
143
|
return {
|
|
144
|
-
kind:
|
|
144
|
+
kind: 'lambda',
|
|
145
145
|
params: [...value.params],
|
|
146
146
|
body: value.body,
|
|
147
147
|
scopes: cloneScopes(value.scopes),
|
|
148
148
|
};
|
|
149
149
|
}
|
|
150
|
-
return { kind:
|
|
150
|
+
return { kind: 'array', values: value.values, rows: value.rows, cols: value.cols };
|
|
151
151
|
}
|
|
152
152
|
function cloneScopes(scopes) {
|
|
153
153
|
return scopes.map((scope) => new Map([...scope.entries()].map(([name, value]) => [name, cloneStackValue(value)])));
|
|
154
154
|
}
|
|
155
155
|
function toRangeLike(value) {
|
|
156
|
-
if (value.kind ===
|
|
157
|
-
return { kind:
|
|
156
|
+
if (value.kind === 'omitted') {
|
|
157
|
+
return { kind: 'range', values: [error(ErrorCode.Value)], rows: 1, cols: 1, refKind: 'cells' };
|
|
158
158
|
}
|
|
159
|
-
if (value.kind ===
|
|
160
|
-
return { kind:
|
|
159
|
+
if (value.kind === 'lambda') {
|
|
160
|
+
return { kind: 'range', values: [error(ErrorCode.Value)], rows: 1, cols: 1, refKind: 'cells' };
|
|
161
161
|
}
|
|
162
|
-
if (value.kind ===
|
|
162
|
+
if (value.kind === 'range') {
|
|
163
163
|
return value;
|
|
164
164
|
}
|
|
165
|
-
if (value.kind ===
|
|
165
|
+
if (value.kind === 'array') {
|
|
166
166
|
return {
|
|
167
|
-
kind:
|
|
167
|
+
kind: 'range',
|
|
168
168
|
values: value.values,
|
|
169
169
|
rows: value.rows,
|
|
170
170
|
cols: value.cols,
|
|
171
|
-
refKind:
|
|
171
|
+
refKind: 'cells',
|
|
172
172
|
};
|
|
173
173
|
}
|
|
174
|
-
return { kind:
|
|
174
|
+
return { kind: 'range', values: [value.value], rows: 1, cols: 1, refKind: 'cells' };
|
|
175
175
|
}
|
|
176
176
|
function scalarBinary(operator, leftValue, rightValue) {
|
|
177
177
|
if (leftValue.tag === ValueTag.Error) {
|
|
@@ -180,29 +180,29 @@ function scalarBinary(operator, leftValue, rightValue) {
|
|
|
180
180
|
if (rightValue.tag === ValueTag.Error) {
|
|
181
181
|
return rightValue;
|
|
182
182
|
}
|
|
183
|
-
if (operator ===
|
|
183
|
+
if (operator === '&') {
|
|
184
184
|
return {
|
|
185
185
|
tag: ValueTag.String,
|
|
186
186
|
value: `${toStringValue(leftValue)}${toStringValue(rightValue)}`,
|
|
187
187
|
stringId: 0,
|
|
188
188
|
};
|
|
189
189
|
}
|
|
190
|
-
if ([
|
|
190
|
+
if (['+', '-', '*', '/', '^'].includes(operator)) {
|
|
191
191
|
const left = toNumber(leftValue);
|
|
192
192
|
const right = toNumber(rightValue);
|
|
193
193
|
if (left === undefined || right === undefined) {
|
|
194
194
|
return error(ErrorCode.Value);
|
|
195
195
|
}
|
|
196
|
-
if (operator ===
|
|
196
|
+
if (operator === '/' && right === 0) {
|
|
197
197
|
return error(ErrorCode.Div0);
|
|
198
198
|
}
|
|
199
|
-
const value = operator ===
|
|
199
|
+
const value = operator === '+'
|
|
200
200
|
? left + right
|
|
201
|
-
: operator ===
|
|
201
|
+
: operator === '-'
|
|
202
202
|
? left - right
|
|
203
|
-
: operator ===
|
|
203
|
+
: operator === '*'
|
|
204
204
|
? left * right
|
|
205
|
-
: operator ===
|
|
205
|
+
: operator === '/'
|
|
206
206
|
? left / right
|
|
207
207
|
: left ** right;
|
|
208
208
|
return { tag: ValueTag.Number, value };
|
|
@@ -213,21 +213,21 @@ function scalarBinary(operator, leftValue, rightValue) {
|
|
|
213
213
|
}
|
|
214
214
|
return {
|
|
215
215
|
tag: ValueTag.Boolean,
|
|
216
|
-
value: operator ===
|
|
216
|
+
value: operator === '='
|
|
217
217
|
? comparison === 0
|
|
218
|
-
: operator ===
|
|
218
|
+
: operator === '<>'
|
|
219
219
|
? comparison !== 0
|
|
220
|
-
: operator ===
|
|
220
|
+
: operator === '>'
|
|
221
221
|
? comparison > 0
|
|
222
|
-
: operator ===
|
|
222
|
+
: operator === '>='
|
|
223
223
|
? comparison >= 0
|
|
224
|
-
: operator ===
|
|
224
|
+
: operator === '<'
|
|
225
225
|
? comparison < 0
|
|
226
226
|
: comparison <= 0,
|
|
227
227
|
};
|
|
228
228
|
}
|
|
229
229
|
function evaluateBinary(operator, leftValue, rightValue) {
|
|
230
|
-
if (leftValue.kind ===
|
|
230
|
+
if (leftValue.kind === 'scalar' && rightValue.kind === 'scalar') {
|
|
231
231
|
return scalarBinary(operator, leftValue.value, rightValue.value);
|
|
232
232
|
}
|
|
233
233
|
const leftRange = toRangeLike(leftValue);
|
|
@@ -257,47 +257,45 @@ function evaluateBinary(operator, leftValue, rightValue) {
|
|
|
257
257
|
values.push(scalarBinary(operator, leftRange.values[leftIndex] ?? emptyValue(), rightRange.values[rightIndex] ?? emptyValue()));
|
|
258
258
|
}
|
|
259
259
|
}
|
|
260
|
-
return rows === 1 && cols === 1
|
|
261
|
-
? (values[0] ?? emptyValue())
|
|
262
|
-
: { kind: "array", values, rows, cols };
|
|
260
|
+
return rows === 1 && cols === 1 ? (values[0] ?? emptyValue()) : { kind: 'array', values, rows, cols };
|
|
263
261
|
}
|
|
264
262
|
function stackScalar(value) {
|
|
265
|
-
return { kind:
|
|
263
|
+
return { kind: 'scalar', value };
|
|
266
264
|
}
|
|
267
265
|
function normalizeScopeName(name) {
|
|
268
266
|
return name.toUpperCase();
|
|
269
267
|
}
|
|
270
268
|
function isSingleCellValue(value) {
|
|
271
|
-
if (value.kind ===
|
|
269
|
+
if (value.kind === 'scalar') {
|
|
272
270
|
return value.value;
|
|
273
271
|
}
|
|
274
|
-
if (value.kind ===
|
|
272
|
+
if (value.kind === 'omitted') {
|
|
275
273
|
return undefined;
|
|
276
274
|
}
|
|
277
|
-
if (value.kind ===
|
|
275
|
+
if (value.kind === 'lambda') {
|
|
278
276
|
return undefined;
|
|
279
277
|
}
|
|
280
278
|
return value.rows * value.cols === 1 ? (value.values[0] ?? emptyValue()) : undefined;
|
|
281
279
|
}
|
|
282
280
|
function toRangeArgument(value) {
|
|
283
|
-
if (value.kind ===
|
|
281
|
+
if (value.kind === 'scalar') {
|
|
284
282
|
return value.value;
|
|
285
283
|
}
|
|
286
|
-
if (value.kind ===
|
|
284
|
+
if (value.kind === 'omitted') {
|
|
287
285
|
return error(ErrorCode.Value);
|
|
288
286
|
}
|
|
289
|
-
if (value.kind ===
|
|
287
|
+
if (value.kind === 'lambda') {
|
|
290
288
|
return error(ErrorCode.Value);
|
|
291
289
|
}
|
|
292
290
|
return {
|
|
293
|
-
kind:
|
|
291
|
+
kind: 'range',
|
|
294
292
|
values: value.values,
|
|
295
|
-
refKind: value.kind ===
|
|
293
|
+
refKind: value.kind === 'range' ? value.refKind : 'cells',
|
|
296
294
|
rows: value.rows,
|
|
297
295
|
cols: value.cols,
|
|
298
|
-
...(value.kind ===
|
|
299
|
-
...(value.kind ===
|
|
300
|
-
...(value.kind ===
|
|
296
|
+
...(value.kind === 'range' && value.sheetName ? { sheetName: value.sheetName } : {}),
|
|
297
|
+
...(value.kind === 'range' && value.start ? { start: value.start } : {}),
|
|
298
|
+
...(value.kind === 'range' && value.end ? { end: value.end } : {}),
|
|
301
299
|
};
|
|
302
300
|
}
|
|
303
301
|
function toPositiveInteger(value) {
|
|
@@ -415,16 +413,16 @@ function coerceOptionalTrimModeArgument(value, fallback) {
|
|
|
415
413
|
}
|
|
416
414
|
}
|
|
417
415
|
function isCellValueError(value) {
|
|
418
|
-
return typeof value ===
|
|
416
|
+
return typeof value === 'object' && value !== null && 'tag' in value;
|
|
419
417
|
}
|
|
420
418
|
function makeArrayStack(rows, cols, values) {
|
|
421
|
-
return { kind:
|
|
419
|
+
return { kind: 'array', rows, cols, values };
|
|
422
420
|
}
|
|
423
421
|
function matrixFromStackValue(value) {
|
|
424
|
-
if (value.kind ===
|
|
422
|
+
if (value.kind === 'omitted' || value.kind === 'lambda') {
|
|
425
423
|
return undefined;
|
|
426
424
|
}
|
|
427
|
-
if (value.kind ===
|
|
425
|
+
if (value.kind === 'scalar') {
|
|
428
426
|
return { rows: 1, cols: 1, values: [value.value] };
|
|
429
427
|
}
|
|
430
428
|
return { rows: value.rows, cols: value.cols, values: value.values };
|
|
@@ -453,7 +451,7 @@ function vectorIntegerArgument(value) {
|
|
|
453
451
|
return values;
|
|
454
452
|
}
|
|
455
453
|
function aggregateRangeSubset(functionArg, subset, context, totalSet) {
|
|
456
|
-
if (functionArg.kind ===
|
|
454
|
+
if (functionArg.kind === 'lambda') {
|
|
457
455
|
const args = [makeArrayStack(Math.max(subset.length, 1), 1, [...subset])];
|
|
458
456
|
if (functionArg.params.length >= 2) {
|
|
459
457
|
args.push(makeArrayStack(Math.max(totalSet?.length ?? 0, 1), 1, [...(totalSet ?? [emptyValue()])]));
|
|
@@ -467,10 +465,10 @@ function aggregateRangeSubset(functionArg, subset, context, totalSet) {
|
|
|
467
465
|
}
|
|
468
466
|
const name = scalar.value.trim().toUpperCase();
|
|
469
467
|
if (subset.length === 0) {
|
|
470
|
-
if (name ===
|
|
468
|
+
if (name === 'SUM' || name === 'COUNT' || name === 'COUNTA') {
|
|
471
469
|
return numberValue(0);
|
|
472
470
|
}
|
|
473
|
-
if (name ===
|
|
471
|
+
if (name === 'AVERAGE' || name === 'AVG') {
|
|
474
472
|
return error(ErrorCode.Div0);
|
|
475
473
|
}
|
|
476
474
|
return numberValue(0);
|
|
@@ -483,20 +481,17 @@ function aggregateRangeSubset(functionArg, subset, context, totalSet) {
|
|
|
483
481
|
return isArrayValue(result) ? scalarFromEvaluationResult(result) : result;
|
|
484
482
|
}
|
|
485
483
|
function applyLambda(lambdaValue, args, context) {
|
|
486
|
-
if (lambdaValue.kind !==
|
|
487
|
-
return stackScalar(lambdaValue.kind ===
|
|
488
|
-
? lambdaValue.value
|
|
489
|
-
: error(ErrorCode.Value));
|
|
484
|
+
if (lambdaValue.kind !== 'lambda') {
|
|
485
|
+
return stackScalar(lambdaValue.kind === 'scalar' && lambdaValue.value.tag === ValueTag.Error ? lambdaValue.value : error(ErrorCode.Value));
|
|
490
486
|
}
|
|
491
487
|
if (args.length > lambdaValue.params.length) {
|
|
492
488
|
return stackScalar(error(ErrorCode.Value));
|
|
493
489
|
}
|
|
494
490
|
const parameterScope = new Map();
|
|
495
491
|
lambdaValue.params.forEach((name, index) => {
|
|
496
|
-
parameterScope.set(normalizeScopeName(name), index < args.length ? cloneStackValue(args[index]) : { kind:
|
|
492
|
+
parameterScope.set(normalizeScopeName(name), index < args.length ? cloneStackValue(args[index]) : { kind: 'omitted' });
|
|
497
493
|
});
|
|
498
|
-
return
|
|
499
|
-
stackScalar(error(ErrorCode.Value)));
|
|
494
|
+
return executePlan(lambdaValue.body, context, [...cloneScopes(lambdaValue.scopes), parameterScope]) ?? stackScalar(error(ErrorCode.Value));
|
|
500
495
|
}
|
|
501
496
|
function evaluateSpecialCall(callee, rawArgs, context, argRefs = []) {
|
|
502
497
|
switch (callee) {
|
|
@@ -565,22 +560,22 @@ function executePlan(plan, context, initialScopes = []) {
|
|
|
565
560
|
while (pc < plan.length) {
|
|
566
561
|
const instruction = plan[pc];
|
|
567
562
|
switch (instruction.opcode) {
|
|
568
|
-
case
|
|
569
|
-
stack.push({ kind:
|
|
563
|
+
case 'push-number':
|
|
564
|
+
stack.push({ kind: 'scalar', value: { tag: ValueTag.Number, value: instruction.value } });
|
|
570
565
|
break;
|
|
571
|
-
case
|
|
572
|
-
stack.push({ kind:
|
|
566
|
+
case 'push-boolean':
|
|
567
|
+
stack.push({ kind: 'scalar', value: { tag: ValueTag.Boolean, value: instruction.value } });
|
|
573
568
|
break;
|
|
574
|
-
case
|
|
569
|
+
case 'push-string':
|
|
575
570
|
stack.push({
|
|
576
|
-
kind:
|
|
571
|
+
kind: 'scalar',
|
|
577
572
|
value: { tag: ValueTag.String, value: instruction.value, stringId: 0 },
|
|
578
573
|
});
|
|
579
574
|
break;
|
|
580
|
-
case
|
|
581
|
-
stack.push({ kind:
|
|
575
|
+
case 'push-error':
|
|
576
|
+
stack.push({ kind: 'scalar', value: error(instruction.code) });
|
|
582
577
|
break;
|
|
583
|
-
case
|
|
578
|
+
case 'push-name':
|
|
584
579
|
{
|
|
585
580
|
let scopedValue;
|
|
586
581
|
for (let index = scopes.length - 1; index >= 0; index -= 1) {
|
|
@@ -593,27 +588,27 @@ function executePlan(plan, context, initialScopes = []) {
|
|
|
593
588
|
stack.push(scopedValue
|
|
594
589
|
? cloneStackValue(scopedValue)
|
|
595
590
|
: {
|
|
596
|
-
kind:
|
|
591
|
+
kind: 'scalar',
|
|
597
592
|
value: context.resolveName?.(instruction.name) ?? error(ErrorCode.Name),
|
|
598
593
|
});
|
|
599
594
|
}
|
|
600
595
|
break;
|
|
601
|
-
case
|
|
596
|
+
case 'push-cell':
|
|
602
597
|
stack.push({
|
|
603
|
-
kind:
|
|
598
|
+
kind: 'scalar',
|
|
604
599
|
value: context.resolveCell(instruction.sheetName ?? context.sheetName, instruction.address),
|
|
605
600
|
});
|
|
606
601
|
break;
|
|
607
|
-
case
|
|
602
|
+
case 'push-range':
|
|
608
603
|
{
|
|
609
604
|
const values = context.resolveRange(instruction.sheetName ?? context.sheetName, instruction.start, instruction.end, instruction.refKind);
|
|
610
605
|
let rows = values.length;
|
|
611
606
|
let cols = 1;
|
|
612
|
-
if (instruction.refKind ===
|
|
607
|
+
if (instruction.refKind === 'cells') {
|
|
613
608
|
try {
|
|
614
|
-
const sheetPrefix = instruction.sheetName ? `${instruction.sheetName}!` :
|
|
609
|
+
const sheetPrefix = instruction.sheetName ? `${instruction.sheetName}!` : '';
|
|
615
610
|
const range = parseRangeAddress(`${sheetPrefix}${instruction.start}:${instruction.end}`);
|
|
616
|
-
if (range.kind ===
|
|
611
|
+
if (range.kind === 'cells') {
|
|
617
612
|
rows = range.end.row - range.start.row + 1;
|
|
618
613
|
cols = range.end.col - range.start.col + 1;
|
|
619
614
|
}
|
|
@@ -625,7 +620,7 @@ function executePlan(plan, context, initialScopes = []) {
|
|
|
625
620
|
}
|
|
626
621
|
context.noteRangeMaterialization?.(values.length);
|
|
627
622
|
stack.push({
|
|
628
|
-
kind:
|
|
623
|
+
kind: 'range',
|
|
629
624
|
values,
|
|
630
625
|
refKind: instruction.refKind,
|
|
631
626
|
rows,
|
|
@@ -636,11 +631,11 @@ function executePlan(plan, context, initialScopes = []) {
|
|
|
636
631
|
});
|
|
637
632
|
}
|
|
638
633
|
break;
|
|
639
|
-
case
|
|
634
|
+
case 'lookup-exact-match': {
|
|
640
635
|
const lookupOperand = popArgument(stack);
|
|
641
636
|
const lookupValue = isSingleCellValue(lookupOperand);
|
|
642
637
|
if (!lookupValue) {
|
|
643
|
-
stack.push({ kind:
|
|
638
|
+
stack.push({ kind: 'scalar', value: error(ErrorCode.Value) });
|
|
644
639
|
break;
|
|
645
640
|
}
|
|
646
641
|
const sheetName = instruction.sheetName ?? context.sheetName;
|
|
@@ -658,10 +653,8 @@ function executePlan(plan, context, initialScopes = []) {
|
|
|
658
653
|
if (directMatch?.handled) {
|
|
659
654
|
context.noteExactLookupDirect?.();
|
|
660
655
|
stack.push({
|
|
661
|
-
kind:
|
|
662
|
-
value: directMatch.position === undefined
|
|
663
|
-
? error(ErrorCode.NA)
|
|
664
|
-
: { tag: ValueTag.Number, value: directMatch.position },
|
|
656
|
+
kind: 'scalar',
|
|
657
|
+
value: directMatch.position === undefined ? error(ErrorCode.NA) : { tag: ValueTag.Number, value: directMatch.position },
|
|
665
658
|
});
|
|
666
659
|
break;
|
|
667
660
|
}
|
|
@@ -673,7 +666,7 @@ function executePlan(plan, context, initialScopes = []) {
|
|
|
673
666
|
rows = instruction.endRow - instruction.startRow + 1;
|
|
674
667
|
cols = instruction.endCol - instruction.startCol + 1;
|
|
675
668
|
const rangeArg = {
|
|
676
|
-
kind:
|
|
669
|
+
kind: 'range',
|
|
677
670
|
values,
|
|
678
671
|
refKind: instruction.refKind,
|
|
679
672
|
rows,
|
|
@@ -682,23 +675,22 @@ function executePlan(plan, context, initialScopes = []) {
|
|
|
682
675
|
start: instruction.start,
|
|
683
676
|
end: instruction.end,
|
|
684
677
|
};
|
|
685
|
-
const lookupBuiltin = context.resolveLookupBuiltin?.(instruction.callee) ??
|
|
686
|
-
getLookupBuiltin(instruction.callee);
|
|
678
|
+
const lookupBuiltin = context.resolveLookupBuiltin?.(instruction.callee) ?? getLookupBuiltin(instruction.callee);
|
|
687
679
|
if (!lookupBuiltin) {
|
|
688
|
-
stack.push({ kind:
|
|
680
|
+
stack.push({ kind: 'scalar', value: error(ErrorCode.Name) });
|
|
689
681
|
break;
|
|
690
682
|
}
|
|
691
|
-
const result = instruction.callee ===
|
|
683
|
+
const result = instruction.callee === 'MATCH'
|
|
692
684
|
? lookupBuiltin(lookupValue, rangeArg, { tag: ValueTag.Number, value: 0 })
|
|
693
685
|
: lookupBuiltin(lookupValue, rangeArg, { tag: ValueTag.Number, value: 0 }, { tag: ValueTag.Number, value: instruction.searchMode });
|
|
694
|
-
stack.push(isArrayValue(result) ? result : { kind:
|
|
686
|
+
stack.push(isArrayValue(result) ? result : { kind: 'scalar', value: result });
|
|
695
687
|
break;
|
|
696
688
|
}
|
|
697
|
-
case
|
|
689
|
+
case 'lookup-approximate-match': {
|
|
698
690
|
const lookupOperand = popArgument(stack);
|
|
699
691
|
const lookupValue = isSingleCellValue(lookupOperand);
|
|
700
692
|
if (!lookupValue) {
|
|
701
|
-
stack.push({ kind:
|
|
693
|
+
stack.push({ kind: 'scalar', value: error(ErrorCode.Value) });
|
|
702
694
|
break;
|
|
703
695
|
}
|
|
704
696
|
const sheetName = instruction.sheetName ?? context.sheetName;
|
|
@@ -715,10 +707,8 @@ function executePlan(plan, context, initialScopes = []) {
|
|
|
715
707
|
});
|
|
716
708
|
if (directMatch?.handled) {
|
|
717
709
|
stack.push({
|
|
718
|
-
kind:
|
|
719
|
-
value: directMatch.position === undefined
|
|
720
|
-
? error(ErrorCode.NA)
|
|
721
|
-
: { tag: ValueTag.Number, value: directMatch.position },
|
|
710
|
+
kind: 'scalar',
|
|
711
|
+
value: directMatch.position === undefined ? error(ErrorCode.NA) : { tag: ValueTag.Number, value: directMatch.position },
|
|
722
712
|
});
|
|
723
713
|
break;
|
|
724
714
|
}
|
|
@@ -727,7 +717,7 @@ function executePlan(plan, context, initialScopes = []) {
|
|
|
727
717
|
const rows = instruction.endRow - instruction.startRow + 1;
|
|
728
718
|
const cols = instruction.endCol - instruction.startCol + 1;
|
|
729
719
|
const rangeArg = {
|
|
730
|
-
kind:
|
|
720
|
+
kind: 'range',
|
|
731
721
|
values,
|
|
732
722
|
refKind: instruction.refKind,
|
|
733
723
|
rows,
|
|
@@ -736,61 +726,60 @@ function executePlan(plan, context, initialScopes = []) {
|
|
|
736
726
|
start: instruction.start,
|
|
737
727
|
end: instruction.end,
|
|
738
728
|
};
|
|
739
|
-
const lookupBuiltin = context.resolveLookupBuiltin?.(instruction.callee) ??
|
|
740
|
-
getLookupBuiltin(instruction.callee);
|
|
729
|
+
const lookupBuiltin = context.resolveLookupBuiltin?.(instruction.callee) ?? getLookupBuiltin(instruction.callee);
|
|
741
730
|
if (!lookupBuiltin) {
|
|
742
|
-
stack.push({ kind:
|
|
731
|
+
stack.push({ kind: 'scalar', value: error(ErrorCode.Name) });
|
|
743
732
|
break;
|
|
744
733
|
}
|
|
745
734
|
const matchModeValue = { tag: ValueTag.Number, value: instruction.matchMode };
|
|
746
|
-
const result = instruction.callee ===
|
|
735
|
+
const result = instruction.callee === 'MATCH'
|
|
747
736
|
? lookupBuiltin(lookupValue, rangeArg, matchModeValue)
|
|
748
737
|
: lookupBuiltin(lookupValue, rangeArg, matchModeValue);
|
|
749
|
-
stack.push(isArrayValue(result) ? result : { kind:
|
|
738
|
+
stack.push(isArrayValue(result) ? result : { kind: 'scalar', value: result });
|
|
750
739
|
break;
|
|
751
740
|
}
|
|
752
|
-
case
|
|
741
|
+
case 'push-lambda':
|
|
753
742
|
stack.push({
|
|
754
|
-
kind:
|
|
743
|
+
kind: 'lambda',
|
|
755
744
|
params: [...instruction.params],
|
|
756
745
|
body: instruction.body,
|
|
757
746
|
scopes: cloneScopes(scopes),
|
|
758
747
|
});
|
|
759
748
|
break;
|
|
760
|
-
case
|
|
749
|
+
case 'unary': {
|
|
761
750
|
const value = popScalar(stack);
|
|
762
751
|
const numeric = toNumber(value);
|
|
763
752
|
stack.push({
|
|
764
|
-
kind:
|
|
753
|
+
kind: 'scalar',
|
|
765
754
|
value: numeric === undefined
|
|
766
755
|
? error(ErrorCode.Value)
|
|
767
|
-
: { tag: ValueTag.Number, value: instruction.operator ===
|
|
756
|
+
: { tag: ValueTag.Number, value: instruction.operator === '-' ? -numeric : numeric },
|
|
768
757
|
});
|
|
769
758
|
break;
|
|
770
759
|
}
|
|
771
|
-
case
|
|
760
|
+
case 'binary': {
|
|
772
761
|
const right = popArgument(stack);
|
|
773
762
|
const left = popArgument(stack);
|
|
774
763
|
const result = evaluateBinary(instruction.operator, left, right);
|
|
775
|
-
stack.push(isArrayValue(result) ? result : { kind:
|
|
764
|
+
stack.push(isArrayValue(result) ? result : { kind: 'scalar', value: result });
|
|
776
765
|
break;
|
|
777
766
|
}
|
|
778
|
-
case
|
|
767
|
+
case 'begin-scope':
|
|
779
768
|
scopes.push(new Map());
|
|
780
769
|
break;
|
|
781
|
-
case
|
|
770
|
+
case 'bind-name': {
|
|
782
771
|
const scope = scopes[scopes.length - 1];
|
|
783
772
|
if (!scope) {
|
|
784
|
-
stack.push({ kind:
|
|
773
|
+
stack.push({ kind: 'scalar', value: error(ErrorCode.Value) });
|
|
785
774
|
break;
|
|
786
775
|
}
|
|
787
776
|
scope.set(normalizeScopeName(instruction.name), cloneStackValue(popArgument(stack)));
|
|
788
777
|
break;
|
|
789
778
|
}
|
|
790
|
-
case
|
|
779
|
+
case 'end-scope':
|
|
791
780
|
scopes.pop();
|
|
792
781
|
break;
|
|
793
|
-
case
|
|
782
|
+
case 'call': {
|
|
794
783
|
const rawArgs = [];
|
|
795
784
|
for (let index = 0; index < instruction.argc; index += 1) {
|
|
796
785
|
rawArgs.unshift(popArgument(stack));
|
|
@@ -800,43 +789,42 @@ function executePlan(plan, context, initialScopes = []) {
|
|
|
800
789
|
stack.push(specialResult);
|
|
801
790
|
break;
|
|
802
791
|
}
|
|
803
|
-
const lookupBuiltin = context.resolveLookupBuiltin?.(instruction.callee) ??
|
|
804
|
-
getLookupBuiltin(instruction.callee);
|
|
792
|
+
const lookupBuiltin = context.resolveLookupBuiltin?.(instruction.callee) ?? getLookupBuiltin(instruction.callee);
|
|
805
793
|
if (lookupBuiltin) {
|
|
806
794
|
const args = [];
|
|
807
795
|
for (const rawArg of rawArgs) {
|
|
808
796
|
args.push(toRangeArgument(rawArg));
|
|
809
797
|
}
|
|
810
798
|
const result = lookupBuiltin(...args);
|
|
811
|
-
stack.push(isArrayValue(result) ? result : { kind:
|
|
799
|
+
stack.push(isArrayValue(result) ? result : { kind: 'scalar', value: result });
|
|
812
800
|
break;
|
|
813
801
|
}
|
|
814
802
|
const builtin = context.resolveBuiltin?.(instruction.callee) ?? getBuiltin(instruction.callee);
|
|
815
803
|
if (!builtin) {
|
|
816
|
-
stack.push({ kind:
|
|
804
|
+
stack.push({ kind: 'scalar', value: error(ErrorCode.Name) });
|
|
817
805
|
break;
|
|
818
806
|
}
|
|
819
807
|
const args = [];
|
|
820
808
|
for (const rawArg of rawArgs) {
|
|
821
|
-
if (rawArg.kind ===
|
|
809
|
+
if (rawArg.kind === 'scalar') {
|
|
822
810
|
args.push(rawArg.value);
|
|
823
811
|
continue;
|
|
824
812
|
}
|
|
825
|
-
if (rawArg.kind ===
|
|
813
|
+
if (rawArg.kind === 'omitted') {
|
|
826
814
|
args.push(error(ErrorCode.Value));
|
|
827
815
|
continue;
|
|
828
816
|
}
|
|
829
|
-
if (rawArg.kind ===
|
|
817
|
+
if (rawArg.kind === 'lambda') {
|
|
830
818
|
args.push(error(ErrorCode.Value));
|
|
831
819
|
continue;
|
|
832
820
|
}
|
|
833
821
|
args.push(...rawArg.values);
|
|
834
822
|
}
|
|
835
823
|
const result = builtin(...args);
|
|
836
|
-
stack.push(isArrayValue(result) ? result : { kind:
|
|
824
|
+
stack.push(isArrayValue(result) ? result : { kind: 'scalar', value: result });
|
|
837
825
|
break;
|
|
838
826
|
}
|
|
839
|
-
case
|
|
827
|
+
case 'invoke': {
|
|
840
828
|
const args = [];
|
|
841
829
|
for (let index = 0; index < instruction.argc; index += 1) {
|
|
842
830
|
args.unshift(popArgument(stack));
|
|
@@ -845,7 +833,7 @@ function executePlan(plan, context, initialScopes = []) {
|
|
|
845
833
|
stack.push(applyLambda(callee, args, context));
|
|
846
834
|
break;
|
|
847
835
|
}
|
|
848
|
-
case
|
|
836
|
+
case 'jump-if-false': {
|
|
849
837
|
const value = popScalar(stack);
|
|
850
838
|
if (value.tag === ValueTag.Error) {
|
|
851
839
|
return stackScalar(value);
|
|
@@ -856,10 +844,10 @@ function executePlan(plan, context, initialScopes = []) {
|
|
|
856
844
|
}
|
|
857
845
|
break;
|
|
858
846
|
}
|
|
859
|
-
case
|
|
847
|
+
case 'jump':
|
|
860
848
|
pc = instruction.target;
|
|
861
849
|
continue;
|
|
862
|
-
case
|
|
850
|
+
case 'return':
|
|
863
851
|
return stack.pop();
|
|
864
852
|
}
|
|
865
853
|
pc += 1;
|