Related: tdf#137543 - Add new LET function to Calc

Fix parsing name strings in Let function, so the invalid names
will be parsed as an ocBad - svString like before.

follow-up commit: 521a56d8d1e12b7471fda6b62b21d51776c9fbaf

Change-Id: If4645584500ffd85556695b12fa7c99eaa8f7662
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/168503
Tested-by: Jenkins
Reviewed-by: Balazs Varga <balazs.varga.extern@allotropia.de>
diff --git a/include/formula/FormulaCompiler.hxx b/include/formula/FormulaCompiler.hxx
index d70dcb4..11a49f4 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 e95e5ee..ba53dbb 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 16801b2..2a08547 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 1ae4d22..81ad285 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 98a91f1..738ed67 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: