@bilig/formula 0.1.2 → 0.1.3
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/builtins/placeholder.d.ts +2 -2
- package/dist/builtins/text-format-builtins.d.ts +14 -0
- package/dist/builtins/text-format-builtins.js +537 -0
- package/dist/builtins/text-format-builtins.js.map +1 -0
- package/dist/builtins/text-search-builtins.d.ts +21 -0
- package/dist/builtins/text-search-builtins.js +469 -0
- package/dist/builtins/text-search-builtins.js.map +1 -0
- package/dist/builtins/text.js +31 -968
- package/dist/builtins/text.js.map +1 -1
- package/dist/js-evaluator-array-special-calls.d.ts +28 -0
- package/dist/js-evaluator-array-special-calls.js +340 -0
- package/dist/js-evaluator-array-special-calls.js.map +1 -0
- package/dist/js-evaluator-context-special-calls.d.ts +24 -0
- package/dist/js-evaluator-context-special-calls.js +156 -0
- package/dist/js-evaluator-context-special-calls.js.map +1 -0
- package/dist/js-evaluator-types.d.ts +117 -0
- package/dist/js-evaluator-types.js +2 -0
- package/dist/js-evaluator-types.js.map +1 -0
- package/dist/js-evaluator.d.ts +3 -100
- package/dist/js-evaluator.js +42 -492
- package/dist/js-evaluator.js.map +1 -1
- package/package.json +6 -6
package/dist/js-evaluator.js
CHANGED
|
@@ -3,6 +3,8 @@ import { indexToColumn, parseCellAddress, parseRangeAddress } from "./addressing
|
|
|
3
3
|
import { getBuiltin, hasBuiltin } from "./builtins.js";
|
|
4
4
|
import { getLookupBuiltin } from "./builtins/lookup.js";
|
|
5
5
|
import { evaluateGroupBy, evaluatePivotBy } from "./group-pivot-evaluator.js";
|
|
6
|
+
import { evaluateArraySpecialCall } from "./js-evaluator-array-special-calls.js";
|
|
7
|
+
import { evaluateContextSpecialCall } from "./js-evaluator-context-special-calls.js";
|
|
6
8
|
import { isArrayValue, scalarFromEvaluationResult, } from "./runtime-values.js";
|
|
7
9
|
import { rewriteSpecialCall } from "./special-call-rewrites.js";
|
|
8
10
|
function emptyValue() {
|
|
@@ -540,29 +542,6 @@ function coerceOptionalTrimModeArgument(value, fallback) {
|
|
|
540
542
|
function isCellValueError(value) {
|
|
541
543
|
return typeof value === "object" && value !== null && "tag" in value;
|
|
542
544
|
}
|
|
543
|
-
function indexOfWithMatchMode(text, delimiter, startIndex, matchMode) {
|
|
544
|
-
if (matchMode === 1) {
|
|
545
|
-
return text.toLowerCase().indexOf(delimiter.toLowerCase(), startIndex);
|
|
546
|
-
}
|
|
547
|
-
return text.indexOf(delimiter, startIndex);
|
|
548
|
-
}
|
|
549
|
-
function splitTextByDelimiter(text, delimiter, matchMode) {
|
|
550
|
-
if (delimiter === "") {
|
|
551
|
-
return [text];
|
|
552
|
-
}
|
|
553
|
-
const parts = [];
|
|
554
|
-
let cursor = 0;
|
|
555
|
-
while (cursor <= text.length) {
|
|
556
|
-
const found = indexOfWithMatchMode(text, delimiter, cursor, matchMode);
|
|
557
|
-
if (found === -1) {
|
|
558
|
-
parts.push(text.slice(cursor));
|
|
559
|
-
break;
|
|
560
|
-
}
|
|
561
|
-
parts.push(text.slice(cursor, found));
|
|
562
|
-
cursor = found + delimiter.length;
|
|
563
|
-
}
|
|
564
|
-
return parts;
|
|
565
|
-
}
|
|
566
545
|
function makeArrayStack(rows, cols, values) {
|
|
567
546
|
return { kind: "array", rows, cols, values };
|
|
568
547
|
}
|
|
@@ -628,9 +607,6 @@ function aggregateRangeSubset(functionArg, subset, context, totalSet) {
|
|
|
628
607
|
const result = builtin(...subset);
|
|
629
608
|
return isArrayValue(result) ? scalarFromEvaluationResult(result) : result;
|
|
630
609
|
}
|
|
631
|
-
function isTrimRangeEmptyCell(value) {
|
|
632
|
-
return value.tag === ValueTag.Empty;
|
|
633
|
-
}
|
|
634
610
|
function applyLambda(lambdaValue, args, context) {
|
|
635
611
|
if (lambdaValue.kind !== "lambda") {
|
|
636
612
|
return stackScalar(lambdaValue.kind === "scalar" && lambdaValue.value.tag === ValueTag.Error
|
|
@@ -649,67 +625,6 @@ function applyLambda(lambdaValue, args, context) {
|
|
|
649
625
|
}
|
|
650
626
|
function evaluateSpecialCall(callee, rawArgs, context, argRefs = []) {
|
|
651
627
|
switch (callee) {
|
|
652
|
-
case "ROW": {
|
|
653
|
-
if (rawArgs.length > 1) {
|
|
654
|
-
return stackScalar(error(ErrorCode.Value));
|
|
655
|
-
}
|
|
656
|
-
const row = referenceRowNumber(argRefs[0], context);
|
|
657
|
-
return stackScalar(row === undefined ? error(ErrorCode.Value) : numberValue(row));
|
|
658
|
-
}
|
|
659
|
-
case "COLUMN": {
|
|
660
|
-
if (rawArgs.length > 1) {
|
|
661
|
-
return stackScalar(error(ErrorCode.Value));
|
|
662
|
-
}
|
|
663
|
-
const column = referenceColumnNumber(argRefs[0], context);
|
|
664
|
-
return stackScalar(column === undefined ? error(ErrorCode.Value) : numberValue(column));
|
|
665
|
-
}
|
|
666
|
-
case "ISOMITTED": {
|
|
667
|
-
if (rawArgs.length !== 1) {
|
|
668
|
-
return stackScalar(error(ErrorCode.Value));
|
|
669
|
-
}
|
|
670
|
-
return stackScalar({ tag: ValueTag.Boolean, value: rawArgs[0]?.kind === "omitted" });
|
|
671
|
-
}
|
|
672
|
-
case "FORMULATEXT": {
|
|
673
|
-
if (rawArgs.length !== 1) {
|
|
674
|
-
return stackScalar(error(ErrorCode.Value));
|
|
675
|
-
}
|
|
676
|
-
const address = referenceTopLeftAddress(argRefs[0]);
|
|
677
|
-
const sheetName = referenceSheetName(argRefs[0], context);
|
|
678
|
-
if (!address || !sheetName) {
|
|
679
|
-
return stackScalar(error(ErrorCode.Ref));
|
|
680
|
-
}
|
|
681
|
-
const formula = context.resolveFormula?.(sheetName, address);
|
|
682
|
-
return stackScalar(formula
|
|
683
|
-
? stringValue(formula.startsWith("=") ? formula : `=${formula}`)
|
|
684
|
-
: error(ErrorCode.NA));
|
|
685
|
-
}
|
|
686
|
-
case "FORMULA": {
|
|
687
|
-
if (rawArgs.length !== 1) {
|
|
688
|
-
return stackScalar(error(ErrorCode.Value));
|
|
689
|
-
}
|
|
690
|
-
const address = referenceTopLeftAddress(argRefs[0]);
|
|
691
|
-
const sheetName = referenceSheetName(argRefs[0], context);
|
|
692
|
-
if (!address || !sheetName) {
|
|
693
|
-
return stackScalar(error(ErrorCode.Ref));
|
|
694
|
-
}
|
|
695
|
-
const formula = context.resolveFormula?.(sheetName, address);
|
|
696
|
-
return stackScalar(formula
|
|
697
|
-
? stringValue(formula.startsWith("=") ? formula : `=${formula}`)
|
|
698
|
-
: error(ErrorCode.NA));
|
|
699
|
-
}
|
|
700
|
-
case "PHONETIC": {
|
|
701
|
-
if (rawArgs.length !== 1) {
|
|
702
|
-
return stackScalar(error(ErrorCode.Value));
|
|
703
|
-
}
|
|
704
|
-
const target = rawArgs[0];
|
|
705
|
-
if (target.kind === "scalar") {
|
|
706
|
-
return stackScalar(stringValue(toStringValue(target.value)));
|
|
707
|
-
}
|
|
708
|
-
if (target.kind === "range") {
|
|
709
|
-
return stackScalar(stringValue(toStringValue(target.values[0] ?? emptyValue())));
|
|
710
|
-
}
|
|
711
|
-
return stackScalar(error(ErrorCode.Value));
|
|
712
|
-
}
|
|
713
628
|
case "GETPIVOTDATA": {
|
|
714
629
|
if (rawArgs.length < 2 || (rawArgs.length - 2) % 2 !== 0) {
|
|
715
630
|
return stackScalar(error(ErrorCode.Value));
|
|
@@ -840,106 +755,6 @@ function evaluateSpecialCall(callee, rawArgs, context, argRefs = []) {
|
|
|
840
755
|
};
|
|
841
756
|
return stackScalar(context.resolveMultipleOperations?.(request) ?? error(ErrorCode.Ref));
|
|
842
757
|
}
|
|
843
|
-
case "CHOOSE": {
|
|
844
|
-
if (rawArgs.length < 2) {
|
|
845
|
-
return stackScalar(error(ErrorCode.Value));
|
|
846
|
-
}
|
|
847
|
-
const indexValue = isSingleCellValue(rawArgs[0]);
|
|
848
|
-
const choice = indexValue ? toNumber(indexValue) : undefined;
|
|
849
|
-
if (choice === undefined || !Number.isFinite(choice)) {
|
|
850
|
-
return stackScalar(error(ErrorCode.Value));
|
|
851
|
-
}
|
|
852
|
-
const truncated = Math.trunc(choice);
|
|
853
|
-
if (truncated < 1 || truncated >= rawArgs.length) {
|
|
854
|
-
return stackScalar(error(ErrorCode.Value));
|
|
855
|
-
}
|
|
856
|
-
return cloneStackValue(rawArgs[truncated]);
|
|
857
|
-
}
|
|
858
|
-
case "SHEET": {
|
|
859
|
-
if (rawArgs.length > 1) {
|
|
860
|
-
return stackScalar(error(ErrorCode.Value));
|
|
861
|
-
}
|
|
862
|
-
if (rawArgs.length === 0) {
|
|
863
|
-
const index = sheetIndexByName(context.sheetName, context);
|
|
864
|
-
return stackScalar(index === undefined ? error(ErrorCode.NA) : numberValue(index));
|
|
865
|
-
}
|
|
866
|
-
if (argRefs[0]) {
|
|
867
|
-
const index = sheetIndexByName(referenceSheetName(argRefs[0], context) ?? context.sheetName, context);
|
|
868
|
-
return stackScalar(index === undefined ? error(ErrorCode.NA) : numberValue(index));
|
|
869
|
-
}
|
|
870
|
-
const scalar = isSingleCellValue(rawArgs[0]);
|
|
871
|
-
if (scalar?.tag !== ValueTag.String) {
|
|
872
|
-
return stackScalar(error(ErrorCode.NA));
|
|
873
|
-
}
|
|
874
|
-
const index = sheetIndexByName(scalar.value, context);
|
|
875
|
-
return stackScalar(index === undefined ? error(ErrorCode.NA) : numberValue(index));
|
|
876
|
-
}
|
|
877
|
-
case "SHEETS": {
|
|
878
|
-
if (rawArgs.length > 1) {
|
|
879
|
-
return stackScalar(error(ErrorCode.Value));
|
|
880
|
-
}
|
|
881
|
-
if (rawArgs.length === 0) {
|
|
882
|
-
return stackScalar(numberValue(sheetNames(context).length));
|
|
883
|
-
}
|
|
884
|
-
if (argRefs[0]) {
|
|
885
|
-
return stackScalar(numberValue(1));
|
|
886
|
-
}
|
|
887
|
-
const scalar = isSingleCellValue(rawArgs[0]);
|
|
888
|
-
if (scalar?.tag !== ValueTag.String) {
|
|
889
|
-
return stackScalar(error(ErrorCode.NA));
|
|
890
|
-
}
|
|
891
|
-
return stackScalar(sheetIndexByName(scalar.value, context) === undefined
|
|
892
|
-
? error(ErrorCode.NA)
|
|
893
|
-
: numberValue(1));
|
|
894
|
-
}
|
|
895
|
-
case "CELL": {
|
|
896
|
-
if (rawArgs.length < 1 || rawArgs.length > 2) {
|
|
897
|
-
return stackScalar(error(ErrorCode.Value));
|
|
898
|
-
}
|
|
899
|
-
const infoType = isSingleCellValue(rawArgs[0]);
|
|
900
|
-
if (infoType?.tag !== ValueTag.String) {
|
|
901
|
-
return stackScalar(error(ErrorCode.Value));
|
|
902
|
-
}
|
|
903
|
-
const ref = rawArgs.length === 2 ? argRefs[1] : currentCellReference(context);
|
|
904
|
-
if (!ref) {
|
|
905
|
-
return stackScalar(error(ErrorCode.Value));
|
|
906
|
-
}
|
|
907
|
-
const normalizedInfoType = infoType.value.trim().toLowerCase();
|
|
908
|
-
switch (normalizedInfoType) {
|
|
909
|
-
case "address": {
|
|
910
|
-
const address = absoluteAddress(ref, context);
|
|
911
|
-
return stackScalar(address ? stringValue(address) : error(ErrorCode.Value));
|
|
912
|
-
}
|
|
913
|
-
case "row": {
|
|
914
|
-
const row = referenceRowNumber(ref, context);
|
|
915
|
-
return stackScalar(row === undefined ? error(ErrorCode.Value) : numberValue(row));
|
|
916
|
-
}
|
|
917
|
-
case "col": {
|
|
918
|
-
const column = referenceColumnNumber(ref, context);
|
|
919
|
-
return stackScalar(column === undefined ? error(ErrorCode.Value) : numberValue(column));
|
|
920
|
-
}
|
|
921
|
-
case "contents": {
|
|
922
|
-
const address = referenceTopLeftAddress(ref);
|
|
923
|
-
const sheetName = referenceSheetName(ref, context);
|
|
924
|
-
if (!address || !sheetName) {
|
|
925
|
-
return stackScalar(error(ErrorCode.Value));
|
|
926
|
-
}
|
|
927
|
-
return stackScalar(context.resolveCell(sheetName, address));
|
|
928
|
-
}
|
|
929
|
-
case "type": {
|
|
930
|
-
const address = referenceTopLeftAddress(ref);
|
|
931
|
-
const sheetName = referenceSheetName(ref, context);
|
|
932
|
-
if (!address || !sheetName) {
|
|
933
|
-
return stackScalar(error(ErrorCode.Value));
|
|
934
|
-
}
|
|
935
|
-
return stackScalar(stringValue(cellTypeCode(context.resolveCell(sheetName, address))));
|
|
936
|
-
}
|
|
937
|
-
case "filename":
|
|
938
|
-
return stackScalar(stringValue(""));
|
|
939
|
-
default:
|
|
940
|
-
return stackScalar(error(ErrorCode.Value));
|
|
941
|
-
}
|
|
942
|
-
}
|
|
943
758
|
case "INDIRECT": {
|
|
944
759
|
if (rawArgs.length < 1 || rawArgs.length > 2) {
|
|
945
760
|
return stackScalar(error(ErrorCode.Value));
|
|
@@ -989,312 +804,47 @@ function evaluateSpecialCall(callee, rawArgs, context, argRefs = []) {
|
|
|
989
804
|
const resolvedName = context.resolveName?.(normalizedRefText);
|
|
990
805
|
return stackScalar(resolvedName ?? error(ErrorCode.Ref));
|
|
991
806
|
}
|
|
992
|
-
case "EXPAND": {
|
|
993
|
-
if (rawArgs.length < 2 || rawArgs.length > 4) {
|
|
994
|
-
return stackScalar(error(ErrorCode.Value));
|
|
995
|
-
}
|
|
996
|
-
const source = toRangeLike(rawArgs[0]);
|
|
997
|
-
const rows = coerceOptionalPositiveIntegerArgument(rawArgs[1], source.rows);
|
|
998
|
-
const cols = coerceOptionalPositiveIntegerArgument(rawArgs[2], source.cols);
|
|
999
|
-
if (isCellValueError(rows)) {
|
|
1000
|
-
return stackScalar(rows);
|
|
1001
|
-
}
|
|
1002
|
-
if (isCellValueError(cols)) {
|
|
1003
|
-
return stackScalar(cols);
|
|
1004
|
-
}
|
|
1005
|
-
const padArgument = rawArgs[3];
|
|
1006
|
-
const padValue = padArgument === undefined
|
|
1007
|
-
? error(ErrorCode.NA)
|
|
1008
|
-
: (() => {
|
|
1009
|
-
const scalar = isSingleCellValue(padArgument);
|
|
1010
|
-
return scalar ?? error(ErrorCode.Value);
|
|
1011
|
-
})();
|
|
1012
|
-
if (padValue.tag === ValueTag.Error && padArgument !== undefined) {
|
|
1013
|
-
const scalar = isSingleCellValue(padArgument);
|
|
1014
|
-
if (!scalar) {
|
|
1015
|
-
return stackScalar(error(ErrorCode.Value));
|
|
1016
|
-
}
|
|
1017
|
-
}
|
|
1018
|
-
if (rows < source.rows || cols < source.cols) {
|
|
1019
|
-
return stackScalar(error(ErrorCode.Value));
|
|
1020
|
-
}
|
|
1021
|
-
const values = [];
|
|
1022
|
-
for (let row = 0; row < rows; row += 1) {
|
|
1023
|
-
for (let col = 0; col < cols; col += 1) {
|
|
1024
|
-
values.push(row < source.rows && col < source.cols ? getRangeCell(source, row, col) : padValue);
|
|
1025
|
-
}
|
|
1026
|
-
}
|
|
1027
|
-
return makeArrayStack(rows, cols, values);
|
|
1028
|
-
}
|
|
1029
|
-
case "TEXTSPLIT": {
|
|
1030
|
-
if (rawArgs.length < 2 || rawArgs.length > 6) {
|
|
1031
|
-
return stackScalar(error(ErrorCode.Value));
|
|
1032
|
-
}
|
|
1033
|
-
const text = coerceScalarTextArgument(rawArgs[0]);
|
|
1034
|
-
const columnDelimiter = coerceScalarTextArgument(rawArgs[1]);
|
|
1035
|
-
const rowDelimiter = rawArgs[2] === undefined ? undefined : coerceScalarTextArgument(rawArgs[2]);
|
|
1036
|
-
const ignoreEmpty = coerceOptionalBooleanArgument(rawArgs[3], false);
|
|
1037
|
-
const matchMode = coerceOptionalMatchModeArgument(rawArgs[4], 0);
|
|
1038
|
-
if (isCellValueError(text)) {
|
|
1039
|
-
return stackScalar(text);
|
|
1040
|
-
}
|
|
1041
|
-
if (isCellValueError(columnDelimiter)) {
|
|
1042
|
-
return stackScalar(columnDelimiter);
|
|
1043
|
-
}
|
|
1044
|
-
if (rowDelimiter !== undefined && isCellValueError(rowDelimiter)) {
|
|
1045
|
-
return stackScalar(rowDelimiter);
|
|
1046
|
-
}
|
|
1047
|
-
if (isCellValueError(ignoreEmpty)) {
|
|
1048
|
-
return stackScalar(ignoreEmpty);
|
|
1049
|
-
}
|
|
1050
|
-
if (isCellValueError(matchMode)) {
|
|
1051
|
-
return stackScalar(matchMode);
|
|
1052
|
-
}
|
|
1053
|
-
if (columnDelimiter === "" && rowDelimiter === undefined) {
|
|
1054
|
-
return stackScalar(error(ErrorCode.Value));
|
|
1055
|
-
}
|
|
1056
|
-
const padArgument = rawArgs[5];
|
|
1057
|
-
const padValue = padArgument === undefined
|
|
1058
|
-
? error(ErrorCode.NA)
|
|
1059
|
-
: (() => {
|
|
1060
|
-
const scalar = isSingleCellValue(padArgument);
|
|
1061
|
-
return scalar ?? error(ErrorCode.Value);
|
|
1062
|
-
})();
|
|
1063
|
-
if (padArgument !== undefined && !isSingleCellValue(padArgument)) {
|
|
1064
|
-
return stackScalar(error(ErrorCode.Value));
|
|
1065
|
-
}
|
|
1066
|
-
const rowSlices = rowDelimiter === undefined || rowDelimiter === ""
|
|
1067
|
-
? [text]
|
|
1068
|
-
: splitTextByDelimiter(text, rowDelimiter, matchMode);
|
|
1069
|
-
const matrix = rowSlices.map((rowSlice) => {
|
|
1070
|
-
const parts = columnDelimiter === ""
|
|
1071
|
-
? [rowSlice]
|
|
1072
|
-
: splitTextByDelimiter(rowSlice, columnDelimiter, matchMode);
|
|
1073
|
-
const filtered = ignoreEmpty ? parts.filter((part) => part !== "") : parts;
|
|
1074
|
-
return filtered.length === 0 ? [] : filtered;
|
|
1075
|
-
});
|
|
1076
|
-
const rows = Math.max(matrix.length, 1);
|
|
1077
|
-
const cols = Math.max(1, ...matrix.map((row) => row.length));
|
|
1078
|
-
const values = [];
|
|
1079
|
-
for (let rowIndex = 0; rowIndex < rows; rowIndex += 1) {
|
|
1080
|
-
const row = matrix[rowIndex] ?? [];
|
|
1081
|
-
for (let colIndex = 0; colIndex < cols; colIndex += 1) {
|
|
1082
|
-
values.push(colIndex < row.length ? stringValue(row[colIndex]) : padValue);
|
|
1083
|
-
}
|
|
1084
|
-
}
|
|
1085
|
-
return makeArrayStack(rows, cols, values);
|
|
1086
|
-
}
|
|
1087
|
-
case "TRIMRANGE": {
|
|
1088
|
-
if (rawArgs.length < 1 || rawArgs.length > 3) {
|
|
1089
|
-
return stackScalar(error(ErrorCode.Value));
|
|
1090
|
-
}
|
|
1091
|
-
const source = toRangeLike(rawArgs[0]);
|
|
1092
|
-
const trimRows = coerceOptionalTrimModeArgument(rawArgs[1], 3);
|
|
1093
|
-
const trimCols = coerceOptionalTrimModeArgument(rawArgs[2], 3);
|
|
1094
|
-
if (isCellValueError(trimRows)) {
|
|
1095
|
-
return stackScalar(trimRows);
|
|
1096
|
-
}
|
|
1097
|
-
if (isCellValueError(trimCols)) {
|
|
1098
|
-
return stackScalar(trimCols);
|
|
1099
|
-
}
|
|
1100
|
-
let startRow = 0;
|
|
1101
|
-
let endRow = source.rows - 1;
|
|
1102
|
-
let startCol = 0;
|
|
1103
|
-
let endCol = source.cols - 1;
|
|
1104
|
-
const trimLeadingRows = trimRows === 1 || trimRows === 3;
|
|
1105
|
-
const trimTrailingRows = trimRows === 2 || trimRows === 3;
|
|
1106
|
-
const trimLeadingCols = trimCols === 1 || trimCols === 3;
|
|
1107
|
-
const trimTrailingCols = trimCols === 2 || trimCols === 3;
|
|
1108
|
-
if (trimLeadingRows) {
|
|
1109
|
-
while (startRow <= endRow) {
|
|
1110
|
-
let hasNonEmpty = false;
|
|
1111
|
-
for (let col = 0; col < source.cols; col += 1) {
|
|
1112
|
-
if (!isTrimRangeEmptyCell(getRangeCell(source, startRow, col))) {
|
|
1113
|
-
hasNonEmpty = true;
|
|
1114
|
-
break;
|
|
1115
|
-
}
|
|
1116
|
-
}
|
|
1117
|
-
if (hasNonEmpty) {
|
|
1118
|
-
break;
|
|
1119
|
-
}
|
|
1120
|
-
startRow += 1;
|
|
1121
|
-
}
|
|
1122
|
-
}
|
|
1123
|
-
if (trimTrailingRows) {
|
|
1124
|
-
while (endRow >= startRow) {
|
|
1125
|
-
let hasNonEmpty = false;
|
|
1126
|
-
for (let col = 0; col < source.cols; col += 1) {
|
|
1127
|
-
if (!isTrimRangeEmptyCell(getRangeCell(source, endRow, col))) {
|
|
1128
|
-
hasNonEmpty = true;
|
|
1129
|
-
break;
|
|
1130
|
-
}
|
|
1131
|
-
}
|
|
1132
|
-
if (hasNonEmpty) {
|
|
1133
|
-
break;
|
|
1134
|
-
}
|
|
1135
|
-
endRow -= 1;
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
|
-
if (startRow > endRow) {
|
|
1139
|
-
return makeArrayStack(1, 1, [emptyValue()]);
|
|
1140
|
-
}
|
|
1141
|
-
if (trimLeadingCols) {
|
|
1142
|
-
while (startCol <= endCol) {
|
|
1143
|
-
let hasNonEmpty = false;
|
|
1144
|
-
for (let row = startRow; row <= endRow; row += 1) {
|
|
1145
|
-
if (!isTrimRangeEmptyCell(getRangeCell(source, row, startCol))) {
|
|
1146
|
-
hasNonEmpty = true;
|
|
1147
|
-
break;
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
if (hasNonEmpty) {
|
|
1151
|
-
break;
|
|
1152
|
-
}
|
|
1153
|
-
startCol += 1;
|
|
1154
|
-
}
|
|
1155
|
-
}
|
|
1156
|
-
if (trimTrailingCols) {
|
|
1157
|
-
while (endCol >= startCol) {
|
|
1158
|
-
let hasNonEmpty = false;
|
|
1159
|
-
for (let row = startRow; row <= endRow; row += 1) {
|
|
1160
|
-
if (!isTrimRangeEmptyCell(getRangeCell(source, row, endCol))) {
|
|
1161
|
-
hasNonEmpty = true;
|
|
1162
|
-
break;
|
|
1163
|
-
}
|
|
1164
|
-
}
|
|
1165
|
-
if (hasNonEmpty) {
|
|
1166
|
-
break;
|
|
1167
|
-
}
|
|
1168
|
-
endCol -= 1;
|
|
1169
|
-
}
|
|
1170
|
-
}
|
|
1171
|
-
if (startCol > endCol) {
|
|
1172
|
-
return makeArrayStack(1, 1, [emptyValue()]);
|
|
1173
|
-
}
|
|
1174
|
-
const rows = endRow - startRow + 1;
|
|
1175
|
-
const cols = endCol - startCol + 1;
|
|
1176
|
-
const values = [];
|
|
1177
|
-
for (let row = startRow; row <= endRow; row += 1) {
|
|
1178
|
-
for (let col = startCol; col <= endCol; col += 1) {
|
|
1179
|
-
values.push(getRangeCell(source, row, col));
|
|
1180
|
-
}
|
|
1181
|
-
}
|
|
1182
|
-
return makeArrayStack(rows, cols, values);
|
|
1183
|
-
}
|
|
1184
|
-
case "MAKEARRAY": {
|
|
1185
|
-
if (rawArgs.length !== 3) {
|
|
1186
|
-
return stackScalar(error(ErrorCode.Value));
|
|
1187
|
-
}
|
|
1188
|
-
const rows = toPositiveInteger(rawArgs[0]);
|
|
1189
|
-
const cols = toPositiveInteger(rawArgs[1]);
|
|
1190
|
-
if (rows === undefined || cols === undefined) {
|
|
1191
|
-
return stackScalar(error(ErrorCode.Value));
|
|
1192
|
-
}
|
|
1193
|
-
const lambda = rawArgs[2];
|
|
1194
|
-
const values = [];
|
|
1195
|
-
for (let row = 1; row <= rows; row += 1) {
|
|
1196
|
-
for (let col = 1; col <= cols; col += 1) {
|
|
1197
|
-
const result = applyLambda(lambda, [
|
|
1198
|
-
stackScalar({ tag: ValueTag.Number, value: row }),
|
|
1199
|
-
stackScalar({ tag: ValueTag.Number, value: col }),
|
|
1200
|
-
], context);
|
|
1201
|
-
const scalar = isSingleCellValue(result);
|
|
1202
|
-
if (!scalar) {
|
|
1203
|
-
return stackScalar(error(ErrorCode.Value));
|
|
1204
|
-
}
|
|
1205
|
-
values.push(scalar);
|
|
1206
|
-
}
|
|
1207
|
-
}
|
|
1208
|
-
return { kind: "array", rows, cols, values };
|
|
1209
|
-
}
|
|
1210
|
-
case "MAP": {
|
|
1211
|
-
if (rawArgs.length < 2) {
|
|
1212
|
-
return stackScalar(error(ErrorCode.Value));
|
|
1213
|
-
}
|
|
1214
|
-
const lambda = rawArgs[rawArgs.length - 1];
|
|
1215
|
-
const inputs = rawArgs.slice(0, -1);
|
|
1216
|
-
const shape = getBroadcastShape(inputs);
|
|
1217
|
-
if (!shape) {
|
|
1218
|
-
return stackScalar(error(ErrorCode.Value));
|
|
1219
|
-
}
|
|
1220
|
-
const ranges = inputs.map(toRangeLike);
|
|
1221
|
-
const values = [];
|
|
1222
|
-
for (let row = 0; row < shape.rows; row += 1) {
|
|
1223
|
-
for (let col = 0; col < shape.cols; col += 1) {
|
|
1224
|
-
const lambdaArgs = ranges.map((range) => stackScalar(getRangeCell(range, Math.min(row, range.rows - 1), Math.min(col, range.cols - 1))));
|
|
1225
|
-
const result = applyLambda(lambda, lambdaArgs, context);
|
|
1226
|
-
const scalar = isSingleCellValue(result);
|
|
1227
|
-
if (!scalar) {
|
|
1228
|
-
return stackScalar(error(ErrorCode.Value));
|
|
1229
|
-
}
|
|
1230
|
-
values.push(scalar);
|
|
1231
|
-
}
|
|
1232
|
-
}
|
|
1233
|
-
return { kind: "array", rows: shape.rows, cols: shape.cols, values };
|
|
1234
|
-
}
|
|
1235
|
-
case "BYROW":
|
|
1236
|
-
case "BYCOL": {
|
|
1237
|
-
if (rawArgs.length !== 2) {
|
|
1238
|
-
return stackScalar(error(ErrorCode.Value));
|
|
1239
|
-
}
|
|
1240
|
-
const source = toRangeLike(rawArgs[0]);
|
|
1241
|
-
const lambda = rawArgs[1];
|
|
1242
|
-
const values = [];
|
|
1243
|
-
if (callee === "BYROW") {
|
|
1244
|
-
for (let row = 0; row < source.rows; row += 1) {
|
|
1245
|
-
const rowValues = [];
|
|
1246
|
-
for (let col = 0; col < source.cols; col += 1) {
|
|
1247
|
-
rowValues.push(getRangeCell(source, row, col));
|
|
1248
|
-
}
|
|
1249
|
-
const result = applyLambda(lambda, [{ kind: "range", values: rowValues, rows: 1, cols: source.cols, refKind: "cells" }], context);
|
|
1250
|
-
const scalar = isSingleCellValue(result);
|
|
1251
|
-
if (!scalar) {
|
|
1252
|
-
return stackScalar(error(ErrorCode.Value));
|
|
1253
|
-
}
|
|
1254
|
-
values.push(scalar);
|
|
1255
|
-
}
|
|
1256
|
-
return { kind: "array", rows: source.rows, cols: 1, values };
|
|
1257
|
-
}
|
|
1258
|
-
for (let col = 0; col < source.cols; col += 1) {
|
|
1259
|
-
const colValues = [];
|
|
1260
|
-
for (let row = 0; row < source.rows; row += 1) {
|
|
1261
|
-
colValues.push(getRangeCell(source, row, col));
|
|
1262
|
-
}
|
|
1263
|
-
const result = applyLambda(lambda, [{ kind: "range", values: colValues, rows: source.rows, cols: 1, refKind: "cells" }], context);
|
|
1264
|
-
const scalar = isSingleCellValue(result);
|
|
1265
|
-
if (!scalar) {
|
|
1266
|
-
return stackScalar(error(ErrorCode.Value));
|
|
1267
|
-
}
|
|
1268
|
-
values.push(scalar);
|
|
1269
|
-
}
|
|
1270
|
-
return { kind: "array", rows: 1, cols: source.cols, values };
|
|
1271
|
-
}
|
|
1272
|
-
case "REDUCE":
|
|
1273
|
-
case "SCAN": {
|
|
1274
|
-
if (rawArgs.length !== 2 && rawArgs.length !== 3) {
|
|
1275
|
-
return stackScalar(error(ErrorCode.Value));
|
|
1276
|
-
}
|
|
1277
|
-
const hasInitial = rawArgs.length === 3;
|
|
1278
|
-
let accumulator = hasInitial ? cloneStackValue(rawArgs[0]) : stackScalar(emptyValue());
|
|
1279
|
-
const source = toRangeLike(rawArgs[hasInitial ? 1 : 0]);
|
|
1280
|
-
const lambda = rawArgs[hasInitial ? 2 : 1];
|
|
1281
|
-
const scanValues = [];
|
|
1282
|
-
for (const cell of source.values) {
|
|
1283
|
-
accumulator = applyLambda(lambda, [accumulator, stackScalar(cell)], context);
|
|
1284
|
-
if (callee === "SCAN") {
|
|
1285
|
-
const scalar = isSingleCellValue(accumulator);
|
|
1286
|
-
if (!scalar) {
|
|
1287
|
-
return stackScalar(error(ErrorCode.Value));
|
|
1288
|
-
}
|
|
1289
|
-
scanValues.push(scalar);
|
|
1290
|
-
}
|
|
1291
|
-
}
|
|
1292
|
-
return callee === "SCAN"
|
|
1293
|
-
? { kind: "array", rows: source.rows, cols: source.cols, values: scanValues }
|
|
1294
|
-
: accumulator;
|
|
1295
|
-
}
|
|
1296
807
|
default:
|
|
1297
|
-
return
|
|
808
|
+
return (evaluateContextSpecialCall(callee, rawArgs, context, argRefs, {
|
|
809
|
+
error,
|
|
810
|
+
emptyValue,
|
|
811
|
+
numberValue,
|
|
812
|
+
stringValue,
|
|
813
|
+
stackScalar,
|
|
814
|
+
cloneStackValue,
|
|
815
|
+
toNumber,
|
|
816
|
+
toStringValue,
|
|
817
|
+
isSingleCellValue,
|
|
818
|
+
currentCellReference,
|
|
819
|
+
referenceSheetName,
|
|
820
|
+
referenceTopLeftAddress,
|
|
821
|
+
referenceRowNumber,
|
|
822
|
+
referenceColumnNumber,
|
|
823
|
+
absoluteAddress,
|
|
824
|
+
cellTypeCode,
|
|
825
|
+
sheetNames,
|
|
826
|
+
sheetIndexByName,
|
|
827
|
+
}) ??
|
|
828
|
+
evaluateArraySpecialCall(callee, rawArgs, context, {
|
|
829
|
+
error,
|
|
830
|
+
emptyValue,
|
|
831
|
+
numberValue,
|
|
832
|
+
stringValue,
|
|
833
|
+
stackScalar,
|
|
834
|
+
toRangeLike,
|
|
835
|
+
getRangeCell,
|
|
836
|
+
getBroadcastShape,
|
|
837
|
+
makeArrayStack,
|
|
838
|
+
applyLambda,
|
|
839
|
+
toPositiveInteger,
|
|
840
|
+
coerceScalarTextArgument,
|
|
841
|
+
coerceOptionalBooleanArgument,
|
|
842
|
+
coerceOptionalMatchModeArgument,
|
|
843
|
+
coerceOptionalPositiveIntegerArgument,
|
|
844
|
+
coerceOptionalTrimModeArgument,
|
|
845
|
+
isCellValueError,
|
|
846
|
+
isSingleCellValue,
|
|
847
|
+
}));
|
|
1298
848
|
}
|
|
1299
849
|
}
|
|
1300
850
|
function lowerNode(node, plan) {
|