@bilig/formula 0.1.0 → 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.
Files changed (30) hide show
  1. package/dist/builtins/lookup-hypothesis-builtins.d.ts +4 -5
  2. package/dist/builtins/lookup-hypothesis-builtins.js +393 -10
  3. package/dist/builtins/lookup-hypothesis-builtins.js.map +1 -1
  4. package/dist/builtins/lookup.js +3 -387
  5. package/dist/builtins/lookup.js.map +1 -1
  6. package/dist/builtins/placeholder.d.ts +2 -2
  7. package/dist/builtins/text-core-builtins.d.ts +12 -0
  8. package/dist/builtins/text-core-builtins.js +409 -0
  9. package/dist/builtins/text-core-builtins.js.map +1 -0
  10. package/dist/builtins/text-format-builtins.d.ts +14 -0
  11. package/dist/builtins/text-format-builtins.js +537 -0
  12. package/dist/builtins/text-format-builtins.js.map +1 -0
  13. package/dist/builtins/text-search-builtins.d.ts +21 -0
  14. package/dist/builtins/text-search-builtins.js +469 -0
  15. package/dist/builtins/text-search-builtins.js.map +1 -0
  16. package/dist/builtins/text.js +41 -1368
  17. package/dist/builtins/text.js.map +1 -1
  18. package/dist/js-evaluator-array-special-calls.d.ts +28 -0
  19. package/dist/js-evaluator-array-special-calls.js +340 -0
  20. package/dist/js-evaluator-array-special-calls.js.map +1 -0
  21. package/dist/js-evaluator-context-special-calls.d.ts +24 -0
  22. package/dist/js-evaluator-context-special-calls.js +156 -0
  23. package/dist/js-evaluator-context-special-calls.js.map +1 -0
  24. package/dist/js-evaluator-types.d.ts +117 -0
  25. package/dist/js-evaluator-types.js +2 -0
  26. package/dist/js-evaluator-types.js.map +1 -0
  27. package/dist/js-evaluator.d.ts +3 -100
  28. package/dist/js-evaluator.js +42 -492
  29. package/dist/js-evaluator.js.map +1 -1
  30. package/package.json +6 -6
@@ -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 undefined;
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) {