summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/formula/FormulaCompiler.hxx5
-rw-r--r--sc/inc/compiler.hxx3
-rw-r--r--sc/qa/unit/data/xlsx/tdf137543.xlsxbin5277 -> 9458 bytes
-rw-r--r--sc/qa/unit/subsequent_export_test2.cxx5
-rw-r--r--sc/source/core/tool/compiler.cxx60
5 files changed, 63 insertions, 10 deletions
diff --git a/include/formula/FormulaCompiler.hxx b/include/formula/FormulaCompiler.hxx
index d70dcb4c09d8..11a49f4680a0 100644
--- a/include/formula/FormulaCompiler.hxx
+++ b/include/formula/FormulaCompiler.hxx
@@ -424,7 +424,10 @@ protected:
{
bool bInLambdaFunction = false;
short nBracketPos = 0;
- } mLambda;
+ short nParaPos = 0;
+ short nParaCount = 3; // minimum required parameter count: 3
+ std::unordered_set<OUString> aNameSet;
+ } m_aLambda;
public:
enum InitSymbols
diff --git a/sc/inc/compiler.hxx b/sc/inc/compiler.hxx
index e95e5ee78e31..ba53dbb9cb83 100644
--- a/sc/inc/compiler.hxx
+++ b/sc/inc/compiler.hxx
@@ -331,6 +331,7 @@ private:
bool NextNewToken(bool bInArray);
bool ToUpperAsciiOrI18nIsAscii( OUString& rUpper, const OUString& rOrg ) const;
+ short GetPossibleParaCount( const std::u16string_view& rLambdaFormula ) const;
virtual void SetError(FormulaError nError) override;
@@ -359,7 +360,7 @@ private:
bool ParsePredetectedErrRefReference( const OUString& rName, const OUString* pErrRef );
bool ParseMacro( const OUString& );
bool ParseNamedRange( const OUString&, bool onlyCheck = false );
- bool ParseLambdaFuncName( const OUString&, bool bLambdaFunction = false );
+ bool ParseLambdaFuncName( const OUString& );
bool ParseExternalNamedRange( const OUString& rSymbol, bool& rbInvalidExternalNameRange );
bool ParseDBRange( const OUString& );
bool ParseColRowName( const OUString& );
diff --git a/sc/qa/unit/data/xlsx/tdf137543.xlsx b/sc/qa/unit/data/xlsx/tdf137543.xlsx
index 16801b21a2e1..2a0854755a33 100644
--- a/sc/qa/unit/data/xlsx/tdf137543.xlsx
+++ b/sc/qa/unit/data/xlsx/tdf137543.xlsx
Binary files differ
diff --git a/sc/qa/unit/subsequent_export_test2.cxx b/sc/qa/unit/subsequent_export_test2.cxx
index 1ae4d22fc441..81ad2857269c 100644
--- a/sc/qa/unit/subsequent_export_test2.cxx
+++ b/sc/qa/unit/subsequent_export_test2.cxx
@@ -1323,6 +1323,11 @@ CPPUNIT_TEST_FIXTURE(ScExportTest2, testTdf137543XLSX)
assertXPathContent(
pSheet, "/x:worksheet/x:sheetData/x:row/x:c/x:f"_ostr,
u"_xlfn.LET(_xlpm.first,15,_xlpm.second,10,SUM(_xlpm.first,_xlpm.second))"_ustr);
+
+ // test with an unknown (for Calc) function inside the LET function
+ assertXPathContent(
+ pSheet, "/x:worksheet/x:sheetData/x:row[3]/x:c[5]/x:f"_ostr,
+ u"_xlfn.LET(_xlpm.first,B5:E15,_xlfn.chooserows(_xlpm.first, 1, 3, 5, 7, 9, 11))"_ustr);
}
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx
index 98a91f133674..738ed67fc9b9 100644
--- a/sc/source/core/tool/compiler.cxx
+++ b/sc/source/core/tool/compiler.cxx
@@ -3653,13 +3653,22 @@ bool ScCompiler::ParseNamedRange( const OUString& rUpperName, bool onlyCheck )
return false;
}
-bool ScCompiler::ParseLambdaFuncName( const OUString& aOrg, bool bLambdaFunction )
+bool ScCompiler::ParseLambdaFuncName( const OUString& aOrg )
{
- if (bLambdaFunction && !aOrg.isEmpty())
+ if (m_aLambda.bInLambdaFunction && !aOrg.isEmpty())
{
OUString aName = aOrg;
if (aOrg.startsWithIgnoreAsciiCase(u"_xlpm."))
aName = aName.copy(6);
+
+ if (m_aLambda.nParaPos % 2 == 1 && m_aLambda.nParaCount > m_aLambda.nParaPos)
+ m_aLambda.aNameSet.insert(aName);
+ else
+ {
+ // should already exist the name
+ if (m_aLambda.aNameSet.find(aName) == m_aLambda.aNameSet.end())
+ return false;
+ }
svl::SharedString aSS = rDoc.GetSharedStringPool().intern(aName);
maRawToken.SetStringName(aSS.getData(), aSS.getDataIgnoreCase());
return true;
@@ -4362,6 +4371,36 @@ bool ScCompiler::ToUpperAsciiOrI18nIsAscii( OUString& rUpper, const OUString& rO
}
}
+short ScCompiler::GetPossibleParaCount( const std::u16string_view& rLambdaFormula ) const
+{
+ sal_Unicode cSep = mxSymbols->getSymbolChar(ocSep);
+ sal_Unicode cOpen = mxSymbols->getSymbolChar(ocOpen);
+ sal_Unicode cClose = mxSymbols->getSymbolChar(ocClose);
+ sal_Unicode cArrayOpen = mxSymbols->getSymbolChar(ocArrayOpen);
+ sal_Unicode cArrayClose = mxSymbols->getSymbolChar(ocArrayClose);
+ short nBrackets = 0;
+
+ short nCount = std::count_if(rLambdaFormula.begin(), rLambdaFormula.end(),
+ [&](sal_Unicode c) {
+ if (c == cOpen || c == cArrayOpen || c == '[') {
+ nBrackets++;
+ return false;
+ }
+ else if (c == cClose || c == cArrayClose || c == ']') {
+ nBrackets--;
+ return false;
+ }
+ else {
+ if (nBrackets == 1)
+ return c == cSep;
+ else
+ return false;
+ }
+ });
+
+ return static_cast<short>(nCount + 1);
+}
+
bool ScCompiler::NextNewToken( bool bInArray )
{
if (!maPendingOpCodes.empty())
@@ -4629,7 +4668,7 @@ Label_Rewind:
if (bMayBeFuncName && ParseOpCode2( aUpper ))
return true;
- if (ParseLambdaFuncName(aOrg, mLambda.bInLambdaFunction))
+ if (ParseLambdaFuncName( aOrg ))
return true;
} while (mbRewind);
@@ -4764,8 +4803,10 @@ std::unique_ptr<ScTokenArray> ScCompiler::CompileString( const OUString& rFormul
{
if (eLastOp == ocLet)
{
- mLambda.bInLambdaFunction = true;
- mLambda.nBracketPos = nBrackets;
+ m_aLambda.bInLambdaFunction = true;
+ m_aLambda.nBracketPos = nBrackets;
+ m_aLambda.nParaPos++;
+ m_aLambda.nParaCount = GetPossibleParaCount(rFormula.subView(nSrcPos - 1));
}
++nBrackets;
@@ -4792,10 +4833,10 @@ std::unique_ptr<ScTokenArray> ScCompiler::CompileString( const OUString& rFormul
else
{
nBrackets--;
- if (mLambda.bInLambdaFunction && mLambda.nBracketPos == nBrackets)
+ if (m_aLambda.bInLambdaFunction && m_aLambda.nBracketPos == nBrackets)
{
- mLambda.bInLambdaFunction = false;
- mLambda.nBracketPos = nBrackets;
+ m_aLambda.bInLambdaFunction = false;
+ m_aLambda.nBracketPos = nBrackets;
}
}
if (bUseFunctionStack && nFunction)
@@ -4806,6 +4847,9 @@ std::unique_ptr<ScTokenArray> ScCompiler::CompileString( const OUString& rFormul
{
if (bUseFunctionStack)
++pFunctionStack[ nFunction ].nSep;
+
+ if (m_aLambda.bInLambdaFunction && m_aLambda.nBracketPos + 1 == nBrackets)
+ m_aLambda.nParaPos++;
}
break;
case ocArrayOpen: