tdf#128425 Add Excel2021 function XMATCH to Calc

https://issues.oasis-open.org/browse/OFFICE-4155

Change-Id: I7791ab873cf62ce882feba75dc0d722bc5990f9a
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163260
Tested-by: Jenkins
Reviewed-by: Balazs Varga <balazs.varga.extern@allotropia.de>
This commit is contained in:
Balazs Varga
2024-02-18 23:13:01 +01:00
parent 3e0f6665e3
commit b36ecef07a
18 changed files with 3988 additions and 28 deletions
+6
View File
@@ -266,6 +266,7 @@ const std::pair<const char *, int> RID_STRLIST_FUNCTION_NAMES_ENGLISH_ODFF[] =
{ "INDIRECT" , SC_OPCODE_INDIRECT },
{ "ADDRESS" , SC_OPCODE_ADDRESS },
{ "MATCH" , SC_OPCODE_MATCH },
{ "COM.MICROSOFT.XMATCH" , SC_OPCODE_X_MATCH },
{ "COUNTBLANK" , SC_OPCODE_COUNT_EMPTY_CELLS },
{ "COUNTIF" , SC_OPCODE_COUNT_IF },
{ "SUMIF" , SC_OPCODE_SUM_IF },
@@ -714,6 +715,7 @@ const std::pair<const char *, int> RID_STRLIST_FUNCTION_NAMES_ENGLISH_OOXML[] =
{ "INDIRECT" , SC_OPCODE_INDIRECT },
{ "ADDRESS" , SC_OPCODE_ADDRESS },
{ "MATCH" , SC_OPCODE_MATCH },
{ "_xlfn.XMATCH" , SC_OPCODE_X_MATCH },
{ "COUNTBLANK" , SC_OPCODE_COUNT_EMPTY_CELLS },
{ "COUNTIF" , SC_OPCODE_COUNT_IF },
{ "SUMIF" , SC_OPCODE_SUM_IF },
@@ -1165,6 +1167,7 @@ const std::pair<const char *, int> RID_STRLIST_FUNCTION_NAMES_ENGLISH_PODF[] =
{ "INDIRECT" , SC_OPCODE_INDIRECT },
{ "ADDRESS" , SC_OPCODE_ADDRESS },
{ "MATCH" , SC_OPCODE_MATCH },
{ "XMATCH" , SC_OPCODE_X_MATCH },
{ "COUNTBLANK" , SC_OPCODE_COUNT_EMPTY_CELLS },
{ "COUNTIF" , SC_OPCODE_COUNT_IF },
{ "SUMIF" , SC_OPCODE_SUM_IF },
@@ -1617,6 +1620,7 @@ const std::pair<const char *, int> RID_STRLIST_FUNCTION_NAMES_ENGLISH_API[] =
{ "INDIRECT" , SC_OPCODE_INDIRECT },
{ "ADDRESS" , SC_OPCODE_ADDRESS },
{ "MATCH" , SC_OPCODE_MATCH },
{ "XMATCH" , SC_OPCODE_X_MATCH },
{ "COUNTBLANK" , SC_OPCODE_COUNT_EMPTY_CELLS },
{ "COUNTIF" , SC_OPCODE_COUNT_IF },
{ "SUMIF" , SC_OPCODE_SUM_IF },
@@ -2067,6 +2071,7 @@ const std::pair<const char *, int> RID_STRLIST_FUNCTION_NAMES_ENGLISH[] =
{ "INDIRECT" , SC_OPCODE_INDIRECT },
{ "ADDRESS" , SC_OPCODE_ADDRESS },
{ "MATCH" , SC_OPCODE_MATCH },
{ "XMATCH" , SC_OPCODE_X_MATCH },
{ "COUNTBLANK" , SC_OPCODE_COUNT_EMPTY_CELLS },
{ "COUNTIF" , SC_OPCODE_COUNT_IF },
{ "SUMIF" , SC_OPCODE_SUM_IF },
@@ -2498,6 +2503,7 @@ const std::pair<TranslateId, int> RID_STRLIST_FUNCTION_NAMES[] =
{ NC_("RID_STRLIST_FUNCTION_NAMES", "INDIRECT") , SC_OPCODE_INDIRECT },
{ NC_("RID_STRLIST_FUNCTION_NAMES", "ADDRESS") , SC_OPCODE_ADDRESS },
{ NC_("RID_STRLIST_FUNCTION_NAMES", "MATCH") , SC_OPCODE_MATCH },
{ NC_("RID_STRLIST_FUNCTION_NAMES", "XMATCH") , SC_OPCODE_X_MATCH },
{ NC_("RID_STRLIST_FUNCTION_NAMES", "COUNTBLANK") , SC_OPCODE_COUNT_EMPTY_CELLS },
{ NC_("RID_STRLIST_FUNCTION_NAMES", "COUNTIF") , SC_OPCODE_COUNT_IF },
{ NC_("RID_STRLIST_FUNCTION_NAMES", "SUMIF") , SC_OPCODE_SUM_IF },
+1 -1
View File
@@ -399,7 +399,7 @@
#define SC_OPCODE_ISPMT 386
#define SC_OPCODE_HYPERLINK 387
#define SC_OPCODE_X_LOOKUP 388
// free: 389
#define SC_OPCODE_X_MATCH 389
#define SC_OPCODE_GET_PIVOT_DATA 390
#define SC_OPCODE_EUROCONVERT 391
#define SC_OPCODE_NUMBERVALUE 392
+2
View File
@@ -307,6 +307,7 @@ enum OpCode : sal_uInt16
ocIndirect = SC_OPCODE_INDIRECT,
ocAddress = SC_OPCODE_ADDRESS,
ocMatch = SC_OPCODE_MATCH,
ocXMatch = SC_OPCODE_X_MATCH,
ocCountEmptyCells = SC_OPCODE_COUNT_EMPTY_CELLS,
ocCountIf = SC_OPCODE_COUNT_IF,
ocSumIf = SC_OPCODE_SUM_IF,
@@ -790,6 +791,7 @@ inline std::string OpCodeEnumToString(OpCode eCode)
case ocIndirect: return "Indirect";
case ocAddress: return "Address";
case ocMatch: return "Match";
case ocXMatch: return "XMatch";
case ocCountEmptyCells: return "CountEmptyCells";
case ocCountIf: return "CountIf";
case ocSumIf: return "SumIf";
+1
View File
@@ -74,6 +74,7 @@ https://docs.oasis-open.org/office/OpenDocument/v1.3/os/part4-formula/OpenDocume
* HLOOKUP
* LOOKUP
* MATCH
* XMATCH
* VLOOKUP
* XLOOKUP
* Mathematical Functions
+1
View File
@@ -594,5 +594,6 @@ inline constexpr OUString HID_FUNC_FOURIER = u"SC_HID_FUNC_FOURIER"_ustr;
inline constexpr OUString HID_FUNC_RAND_NV = u"SC_HID_FUNC_RAND_NV"_ustr;
inline constexpr OUString HID_FUNC_RANDBETWEEN_NV = u"SC_HID_FUNC_RANDBETWEEN_NV"_ustr;
inline constexpr OUString HID_FUNC_XLOOKUP_MS = u"SC_HID_FUNC_XLOOKUP_MS"_ustr;
inline constexpr OUString HID_FUNC_XMATCH_MS = u"SC_HID_FUNC_XMATCH_MS"_ustr;
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+14
View File
@@ -3443,6 +3443,20 @@ const TranslateId SC_OPCODE_MATCH_ARY[] =
NC_("SC_OPCODE_MATCH", "Type can take the value 1 (first column array ascending), 0 (exact match or wildcard or regular expression match) or -1 (first column array descending) and determines the criteria to be used for comparison purposes.")
};
// -=*# Resource for function XMATCH #*=-
const TranslateId SC_OPCODE_X_MATCH_ARY[] =
{
NC_("SC_OPCODE_X_MATCH", "Defines a relative position in an array or range of cells after comparing values."),
NC_("SC_OPCODE_X_MATCH", "Search criterion"),
NC_("SC_OPCODE_X_MATCH", "The value to be used for comparison."),
NC_("SC_OPCODE_X_MATCH", "Search Array"),
NC_("SC_OPCODE_X_MATCH", "The array or range to search."),
NC_("SC_OPCODE_X_MATCH", "Match Mode"),
NC_("SC_OPCODE_X_MATCH", "0, -1, 1 or 2 "), // TODO : add explanation of values
NC_("SC_OPCODE_X_MATCH", "Search Mode"),
NC_("SC_OPCODE_X_MATCH", "1, -1, 2 or -2 ") // TODO : add explanation of values
};
// -=*# Resource for function OFFSET #*=-
const TranslateId SC_OPCODE_OFFSET_ARY[] =
{
+1 -1
View File
@@ -78,7 +78,7 @@ public:
ScFunctionListObj::ScFunctionListObj()
: UnoApiTest("/sc/qa/extras/testdocuments")
, XElementAccess(cppu::UnoType<uno::Sequence<beans::PropertyValue>>::get())
, XIndexAccess(396)
, XIndexAccess(397)
, XNameAccess("IF")
, XServiceInfo("stardiv.StarCalc.ScFunctionListObj", "com.sun.star.sheet.FunctionDescriptions")
{
File diff suppressed because one or more lines are too long
+1
View File
@@ -2924,6 +2924,7 @@ CPPUNIT_TEST_FIXTURE(Test, testFunctionLists)
"STYLE",
"VLOOKUP",
"XLOOKUP",
"XMATCH",
nullptr
};
+1
View File
@@ -676,6 +676,7 @@ ScFunctionList::ScFunctionList( bool bEnglishFunctionNames )
{ SC_OPCODE_ISPMT, ENTRY(SC_OPCODE_ISPMT_ARY), 0, ID_FUNCTION_GRP_FINANCIAL, HID_FUNC_ISPMT, 4, { 0, 0, 0, 0 }, 0 },
{ SC_OPCODE_HYPERLINK, ENTRY(SC_OPCODE_HYPERLINK_ARY), 0, ID_FUNCTION_GRP_TABLE, HID_FUNC_HYPERLINK, 2, { 0, 1 }, 0 },
{ SC_OPCODE_X_LOOKUP, ENTRY(SC_OPCODE_X_LOOKUP_ARY), 0, ID_FUNCTION_GRP_TABLE, HID_FUNC_XLOOKUP_MS, 6, { 0, 0, 0, 1, 1, 1 }, 0 },
{ SC_OPCODE_X_MATCH, ENTRY(SC_OPCODE_X_MATCH_ARY), 0, ID_FUNCTION_GRP_TABLE, HID_FUNC_XMATCH_MS, 4, { 0, 0, 1, 1 }, 0 },
{ SC_OPCODE_GET_PIVOT_DATA, ENTRY(SC_OPCODE_GET_PIVOT_DATA_ARY), 0, ID_FUNCTION_GRP_TABLE, HID_FUNC_GETPIVOTDATA, VAR_ARGS+2, { 0, 0, 1 }, 0 },
{ SC_OPCODE_EUROCONVERT, ENTRY(SC_OPCODE_EUROCONVERT_ARY), 0, ID_FUNCTION_GRP_MATH, HID_FUNC_EUROCONVERT, 5, { 0, 0, 0, 1, 1 }, 0 },
{ SC_OPCODE_NUMBERVALUE, ENTRY(SC_OPCODE_NUMBERVALUE_ARY), 0, ID_FUNCTION_GRP_TEXT, HID_FUNC_NUMBERVALUE, 3, { 0, 1, 1 }, 0 },
+21 -18
View File
@@ -206,8 +206,8 @@ void ScQueryCellIteratorBase< accessType, queryType >::PerformQuery()
if ( aCell.isEmpty())
return;
// XLookUp: Forward/asc/backward/desc search for best fit value, except if we have an exact match
if (nSearchOpCode == SC_OPCODE_X_LOOKUP &&
// XLookUp/XMatch: Forward/asc/backward/desc search for best fit value, except if we have an exact match
if ((nSearchOpCode == SC_OPCODE_X_LOOKUP || nSearchOpCode == SC_OPCODE_X_MATCH) &&
(rEntry.eOp == SC_LESS_EQUAL || rEntry.eOp == SC_GREATER_EQUAL) &&
(nBestFitCol != nCol || nBestFitRow != nRow))
{
@@ -315,8 +315,8 @@ void ScQueryCellIteratorBase< accessType, queryType >::InitPos()
// non-matching position using SC_LESS and the start position
// is the one after it.
lastRow = nRow;
// BinarySearch() looks for the first match for XLOOKUP
if (nSearchOpCode != SC_OPCODE_X_LOOKUP)
// BinarySearch() looks for the first match for XLOOKUP/XMATCH
if (nSearchOpCode != SC_OPCODE_X_LOOKUP && nSearchOpCode != SC_OPCODE_X_MATCH)
{
ScQueryOp saveOp = op;
op = SC_LESS;
@@ -342,7 +342,8 @@ void ScQueryCellIteratorBase< accessType, queryType >::InitPos()
if( BinarySearch( nCol ))
lastRow = nRow;
}
AccessBase::InitPosFinish(beforeRow, lastRow, (nSearchOpCode == SC_OPCODE_X_LOOKUP));
AccessBase::InitPosFinish(beforeRow, lastRow,
(nSearchOpCode == SC_OPCODE_X_LOOKUP || nSearchOpCode == SC_OPCODE_X_MATCH));
}
}
@@ -546,9 +547,9 @@ bool ScQueryCellIteratorBase< accessType, queryType >::BinarySearch( SCCOL col,
{
if (fLastInRangeValue <= nCellVal)
{
if (nSearchOpCode == SC_OPCODE_X_LOOKUP &&
nSortedBinarySearch != nSearchbDesc &&
fLastInRangeValue == nCellVal && aIndexer.getLowIndex() != i)
if ((nSearchOpCode == SC_OPCODE_X_LOOKUP || nSearchOpCode == SC_OPCODE_X_MATCH) &&
nSortedBinarySearch != nSearchbDesc && fLastInRangeValue == nCellVal &&
aIndexer.getLowIndex() != i)
bDone = true;
else
{
@@ -596,9 +597,9 @@ bool ScQueryCellIteratorBase< accessType, queryType >::BinarySearch( SCCOL col,
aCellStr);
if (nTmp <= 0)
{
if (nSearchOpCode == SC_OPCODE_X_LOOKUP &&
nSortedBinarySearch != nSearchbDesc &&
nTmp == 0 && aIndexer.getLowIndex() != i)
if ((nSearchOpCode == SC_OPCODE_X_LOOKUP || nSearchOpCode == SC_OPCODE_X_MATCH) &&
nSortedBinarySearch != nSearchbDesc && nTmp == 0 &&
aIndexer.getLowIndex() != i)
bDone = true;
else
{
@@ -672,8 +673,8 @@ bool ScQueryCellIteratorBase< accessType, queryType >::BinarySearch( SCCOL col,
{
found = i;
nLastInRange = i;
if (nSearchOpCode == SC_OPCODE_X_LOOKUP && (nSortedBinarySearch == nSearchbAscd &&
(rEntry.eOp == SC_LESS_EQUAL || rEntry.eOp == SC_EQUAL)))
if ((nSearchOpCode == SC_OPCODE_X_LOOKUP || nSearchOpCode == SC_OPCODE_X_MATCH) &&
(nSortedBinarySearch == nSearchbAscd && (rEntry.eOp == SC_LESS_EQUAL || rEntry.eOp == SC_EQUAL)))
bDone = true;
else // But keep searching to find the last matching one.
nLo = nMid + 1;
@@ -753,8 +754,9 @@ bool ScQueryCellIterator< accessType >::FindEqualOrSortedLastInRange( SCCOL& nFo
nFoundCol = rDoc.MaxCol()+1;
nFoundRow = rDoc.MaxRow()+1;
if (nSearchOpCode == SC_OPCODE_X_LOOKUP && nSortedBinarySearch == nBinarySearchDisabled)
SetStopOnMismatch( false ); // assume not sorted keys for XLookup
if ((nSearchOpCode == SC_OPCODE_X_LOOKUP || nSearchOpCode == SC_OPCODE_X_MATCH) &&
nSortedBinarySearch == nBinarySearchDisabled)
SetStopOnMismatch( false ); // assume not sorted keys for XLookup/XMatch
else
SetStopOnMismatch( true ); // assume sorted keys
@@ -767,8 +769,8 @@ bool ScQueryCellIterator< accessType >::FindEqualOrSortedLastInRange( SCCOL& nFo
(bLiteral || maParam.GetEntry(0).GetQueryItem().meType == ScQueryEntry::ByValue) &&
(maParam.GetEntry(0).eOp == SC_LESS_EQUAL || maParam.GetEntry(0).eOp == SC_GREATER_EQUAL);
// assume not sorted properly if we are using XLookup with forward or backward search
if (bBinary && nSearchOpCode == SC_OPCODE_X_LOOKUP &&
// assume not sorted properly if we are using XLookup/XMatch with forward or backward search
if (bBinary && (nSearchOpCode == SC_OPCODE_X_LOOKUP || nSearchOpCode == SC_OPCODE_X_MATCH) &&
nSortedBinarySearch == nBinarySearchDisabled)
bBinary = false;
@@ -862,7 +864,8 @@ bool ScQueryCellIterator< accessType >::FindEqualOrSortedLastInRange( SCCOL& nFo
}
}
}
if ( IsEqualConditionFulfilled() && nSearchOpCode != SC_OPCODE_X_LOOKUP )
if (IsEqualConditionFulfilled() && (nSearchOpCode != SC_OPCODE_X_LOOKUP &&
nSearchOpCode != SC_OPCODE_X_MATCH))
{
// Position on last equal entry, except for XLOOKUP,
// which looking for the first equal entry
+2 -1
View File
@@ -541,7 +541,7 @@ private:
inline void TreatDoubleError( double& rVal );
// Lookup using ScLookupCache, @returns true if found and result address
bool LookupQueryWithCache( ScAddress & o_rResultPos, const ScQueryParam & rParam,
const ScComplexRefData* refData, sal_Int8 nSearchMode, sal_Int16 nOpCode ) const;
const ScComplexRefData* refData, sal_Int8 nSearchMode, sal_uInt16 nOpCode ) const;
void ScIfJump();
void ScIfError( bool bNAonly );
@@ -671,6 +671,7 @@ private:
void ScRow();
void ScSheet();
void ScMatch();
void ScXMatch();
void IterateParametersIf( ScIterFuncIf );
void ScCountIf();
void ScSumIf();
+176 -4
View File
@@ -5075,6 +5075,178 @@ void ScInterpreter::ScMatch()
PushIllegalParameter();
}
void ScInterpreter::ScXMatch()
{
sal_uInt8 nParamCount = GetByte();
if (!MustHaveParamCount(nParamCount, 2, 4))
return;
VectorSearchArguments vsa;
vsa.nSearchOpCode = SC_OPCODE_X_MATCH;
// get search mode
if (nParamCount == 4)
{
sal_Int16 k = GetInt16();
if (k >= -2 && k <= 2 && k != 0)
vsa.eSearchMode = static_cast<SearchMode>(k);
else
{
PushIllegalParameter();
return;
}
}
else
vsa.eSearchMode = searchfwd;
// get match mode
if (nParamCount >= 3)
{
sal_Int16 k = GetInt16();
if (k >= -1 && k <= 2)
vsa.eMatchMode = static_cast<MatchMode>(k);
else
{
PushIllegalParameter();
return;
}
}
else
vsa.eMatchMode = exactorNA;
// get vector to be searched
switch (GetStackType())
{
case svSingleRef:
{
PopSingleRef(vsa.nCol1, vsa.nRow1, vsa.nTab1);
vsa.nCol2 = vsa.nCol1;
vsa.nRow2 = vsa.nRow1;
vsa.pMatSrc = nullptr;
}
break;
case svDoubleRef:
{
vsa.pMatSrc = nullptr;
SCTAB nTab2 = 0;
PopDoubleRef(vsa.nCol1, vsa.nRow1, vsa.nTab1, vsa.nCol2, vsa.nRow2, nTab2);
if (vsa.nTab1 != nTab2 || (vsa.nCol1 != vsa.nCol2 && vsa.nRow1 != vsa.nRow2))
{
PushIllegalParameter();
return;
}
}
break;
case svMatrix:
case svExternalDoubleRef:
{
if (GetStackType() == svMatrix)
vsa.pMatSrc = PopMatrix();
else
PopExternalDoubleRef(vsa.pMatSrc);
if (!vsa.pMatSrc)
{
PushIllegalParameter();
return;
}
}
break;
default:
PushIllegalParameter();
return;
}
// get search value
if (nGlobalError == FormulaError::NONE)
{
switch (GetStackType())
{
case svDouble:
{
vsa.isStringSearch = false;
vsa.fSearchVal = GetDouble();
}
break;
case svString:
{
vsa.isStringSearch = true;
vsa.sSearchStr = GetString();
}
break;
case svDoubleRef:
case svSingleRef:
{
ScAddress aAdr;
if (!PopDoubleRefOrSingleRef(aAdr))
{
PushInt(0);
return;
}
ScRefCellValue aCell(mrDoc, aAdr);
if (aCell.hasNumeric())
{
vsa.isStringSearch = false;
vsa.fSearchVal = GetCellValue(aAdr, aCell);
}
else
{
vsa.isStringSearch = true;
GetCellString(vsa.sSearchStr, aCell);
}
}
break;
case svExternalSingleRef:
{
ScExternalRefCache::TokenRef pToken;
PopExternalSingleRef(pToken);
if (nGlobalError != FormulaError::NONE)
{
PushError(nGlobalError);
return;
}
if (pToken->GetType() == svDouble)
{
vsa.isStringSearch = false;
vsa.fSearchVal = pToken->GetDouble();
}
else
{
vsa.isStringSearch = true;
vsa.sSearchStr = pToken->GetString();
}
}
break;
case svExternalDoubleRef:
case svMatrix:
{
ScMatValType nType = GetDoubleOrStringFromMatrix(
vsa.fSearchVal, vsa.sSearchStr);
vsa.isStringSearch = ScMatrix::IsNonValueType(nType);
}
break;
default:
{
PushIllegalParameter();
return;
}
}
// execute search
if (SearchVectorForValue(vsa))
PushDouble(vsa.nIndex);
else
{
if (vsa.isResultNA)
PushNA();
else
return; // error occurred and has already been pushed
}
}
else
PushIllegalParameter();
}
namespace {
bool isCellContentEmpty( const ScRefCellValue& rCell )
@@ -10741,8 +10913,8 @@ bool ScInterpreter::SearchVectorForValue( VectorSearchArguments& vsa )
break;
case wildcard :
// this mode can only used with XLOOKUP
if ( vsa.nSearchOpCode == SC_OPCODE_X_LOOKUP )
// this mode can only used with XLOOKUP/XMATCH
if ( vsa.nSearchOpCode == SC_OPCODE_X_LOOKUP || vsa.nSearchOpCode == SC_OPCODE_X_MATCH )
{
rEntry.eOp = SC_EQUAL;
if ( vsa.isStringSearch )
@@ -10833,7 +11005,7 @@ bool ScInterpreter::SearchVectorForValue( VectorSearchArguments& vsa )
static bool lcl_LookupQuery( ScAddress & o_rResultPos, ScDocument& rDoc, ScInterpreterContext& rContext,
const ScQueryParam & rParam, const ScQueryEntry & rEntry, const ScFormulaCell* cell,
const ScComplexRefData* refData, sal_Int8 nSearchMode, sal_Int16 nOpCode )
const ScComplexRefData* refData, sal_Int8 nSearchMode, sal_uInt16 nOpCode )
{
if (rEntry.eOp != SC_EQUAL)
{
@@ -10952,7 +11124,7 @@ static SCROW lcl_getPrevRowWithEmptyValueLookup( const ScLookupCache& rCache,
bool ScInterpreter::LookupQueryWithCache( ScAddress & o_rResultPos,
const ScQueryParam & rParam, const ScComplexRefData* refData,
sal_Int8 nSearchMode, sal_Int16 nOpCode ) const
sal_Int8 nSearchMode, sal_uInt16 nOpCode ) const
{
bool bFound = false;
const ScQueryEntry& rEntry = rParam.GetEntry(0);
+1
View File
@@ -4317,6 +4317,7 @@ StackVar ScInterpreter::Interpret()
case ocIndirect : ScIndirect(); break;
case ocAddress : ScAddressFunc(); break;
case ocMatch : ScMatch(); break;
case ocXMatch : ScXMatch(); break;
case ocCountEmptyCells : ScCountEmptyCells(); break;
case ocCountIf : ScCountIf(); break;
case ocSumIf : ScSumIf(); break;
+2 -1
View File
@@ -264,7 +264,8 @@ const ScParameterClassification::RawData ScParameterClassification::pRawData[] =
{ ocVarS, {{ Reference }, 1, Value }},
{ ocWhitespace, {{ Bounds }, 0, Bounds }},
{ ocWorkday_MS, {{ Value, Value, Value, Reference }, 0, Value }},
{ ocXLookup, {{ Value, ReferenceOrForceArray, ReferenceOrForceArray, Value, Value, Value }, 0, Value }},
{ ocXLookup, {{ Value, ReferenceOrForceArray, ReferenceOrForceArray, Value, Value, Value }, 0, Reference }},
{ ocXMatch, {{ Value, ReferenceOrForceArray, Value, Value }, 0, Value }},
{ ocXor, {{ Reference }, 1, Value }},
{ ocZTest, {{ Reference, Value, Value }, 0, Value }},
{ ocZTest_MS, {{ Reference, Value, Value }, 0, Value }},
+1
View File
@@ -1388,6 +1388,7 @@ void ScTokenArray::CheckToken( const FormulaToken& r )
case ocCount2:
case ocVLookup:
case ocXLookup:
case ocXMatch:
case ocSLN:
case ocIRR:
case ocMIRR:
+2 -1
View File
@@ -601,7 +601,8 @@ const XclFunctionInfo saFuncTable_2016[] =
*/
const XclFunctionInfo saFuncTable_2021[] =
{
EXC_FUNCENTRY_V_VR( ocXLookup, 3, 6, 0, "XLOOKUP" )
EXC_FUNCENTRY_V_VR( ocXLookup, 3, 6, 0, "XLOOKUP" ),
EXC_FUNCENTRY_V_VR( ocXMatch, 2, 4, 0, "XMATCH" )
};
+2 -1
View File
@@ -875,7 +875,8 @@ const FunctionData saFuncTable2016[] =
/* FIXME: BIFF?? function identifiers available? Where to obtain? */
const FunctionData saFuncTable2021[] =
{
{ "COM.MICROSOFT.XLOOKUP", "XLOOKUP", NOID, NOID, 3, 6, V, { VR, VA, VR }, FuncFlags::MACROCALL_NEW }
{ "COM.MICROSOFT.XLOOKUP", "XLOOKUP", NOID, NOID, 3, 6, R, { VR, VA, VR }, FuncFlags::MACROCALL_NEW },
{ "COM.MICROSOFT.XMATCH", "XMATCH", NOID, NOID, 2, 4, V, { VR, VA }, FuncFlags::MACROCALL_NEW }
};