diff options
-rw-r--r-- | include/formula/FormulaCompiler.hxx | 5 | ||||
-rw-r--r-- | sc/inc/compiler.hxx | 3 | ||||
-rw-r--r-- | sc/qa/unit/data/xlsx/tdf137543.xlsx | bin | 5277 -> 9458 bytes | |||
-rw-r--r-- | sc/qa/unit/subsequent_export_test2.cxx | 5 | ||||
-rw-r--r-- | sc/source/core/tool/compiler.cxx | 60 |
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 Binary files differindex 16801b21a2e1..2a0854755a33 100644 --- a/sc/qa/unit/data/xlsx/tdf137543.xlsx +++ b/sc/qa/unit/data/xlsx/tdf137543.xlsx 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: |