formula/source/core/api/FormulaCompiler.cxx | 64 ++++++++++++++++++++++++++++ sc/qa/unit/ucalc.hxx | 2 sc/qa/unit/ucalc_formula.cxx | 36 +++++++++++++++ sc/source/core/tool/compiler.cxx | 36 +++++++++++++++ 4 files changed, 137 insertions(+), 1 deletion(-)
New commits: commit 3c15daa2a11d675a37b2d75a3f9952cfd60b3e98 Author: Luboš Luňák <l.lu...@collabora.com> AuthorDate: Tue Jul 17 11:38:40 2018 +0200 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Tue Jul 31 16:00:45 2018 +0200 even more implicit intersection computation This extends 60c5ca1b87 to do implicit intersection while generating RPN code for even more opcodes. This will serve as a basis for making it possible to know when ScGroupTokenConverter can convert svDoubleRef to a matrix without the problems mentioned in its convert() method. Change-Id: I8dfeefc026418bd5644bd266ad94c31f670e811c Reviewed-on: https://gerrit.libreoffice.org/57958 Tested-by: Jenkins Reviewed-by: Michael Meeks <michael.me...@collabora.com> diff --git a/formula/source/core/api/FormulaCompiler.cxx b/formula/source/core/api/FormulaCompiler.cxx index 964c38cdb69d..8e79e5ca68dd 100644 --- a/formula/source/core/api/FormulaCompiler.cxx +++ b/formula/source/core/api/FormulaCompiler.cxx @@ -1873,6 +1873,11 @@ void FormulaCompiler::UnaryLine() FormulaTokenRef p = mpToken; NextToken(); UnaryLine(); + if (mbComputeII && IsIIOpCode(p->GetOpCode())) + { + FormulaToken** pArg = pCode - 1; + HandleIIOpCode(p->GetOpCode(), p->GetInForceArray(), &pArg, 1); + } PutCode( p ); } else @@ -1884,6 +1889,11 @@ void FormulaCompiler::PostOpLine() UnaryLine(); while ( mpToken->GetOpCode() == ocPercentSign ) { // this operator _follows_ its operand + if (mbComputeII && IsIIOpCode(mpToken->GetOpCode())) + { + FormulaToken** pArg = pCode - 1; + HandleIIOpCode(mpToken->GetOpCode(), mpToken->GetInForceArray(), &pArg, 1); + } PutCode( mpToken ); NextToken(); } @@ -1895,8 +1905,17 @@ void FormulaCompiler::PowLine() while (mpToken->GetOpCode() == ocPow) { FormulaTokenRef p = mpToken; + bool bDoIICompute = mbComputeII && IsIIOpCode(p->GetOpCode()); + FormulaToken** pArgArray[2]; + if (bDoIICompute) + pArgArray[0] = pCode - 1; // Add first argument NextToken(); PostOpLine(); + if (bDoIICompute) + { + pArgArray[1] = pCode - 1; // Add second argument + HandleIIOpCode(p->GetOpCode(), p->GetInForceArray(), pArgArray, 2); + } PutCode(p); } } @@ -1907,8 +1926,17 @@ void FormulaCompiler::MulDivLine() while (mpToken->GetOpCode() == ocMul || mpToken->GetOpCode() == ocDiv) { FormulaTokenRef p = mpToken; + bool bDoIICompute = mbComputeII && IsIIOpCode(p->GetOpCode()); + FormulaToken** pArgArray[2]; + if (bDoIICompute) + pArgArray[0] = pCode - 1; // Add first argument NextToken(); PowLine(); + if (bDoIICompute) + { + pArgArray[1] = pCode - 1; // Add second argument + HandleIIOpCode(p->GetOpCode(), p->GetInForceArray(), pArgArray, 2); + } PutCode(p); } } @@ -1919,8 +1947,17 @@ void FormulaCompiler::AddSubLine() while (mpToken->GetOpCode() == ocAdd || mpToken->GetOpCode() == ocSub) { FormulaTokenRef p = mpToken; + bool bDoIICompute = mbComputeII && IsIIOpCode(p->GetOpCode()); + FormulaToken** pArgArray[2]; + if (bDoIICompute) + pArgArray[0] = pCode - 1; // Add first argument NextToken(); MulDivLine(); + if (bDoIICompute) + { + pArgArray[1] = pCode - 1; // Add second argument + HandleIIOpCode(p->GetOpCode(), p->GetInForceArray(), pArgArray, 2); + } PutCode(p); } } @@ -1931,8 +1968,17 @@ void FormulaCompiler::ConcatLine() while (mpToken->GetOpCode() == ocAmpersand) { FormulaTokenRef p = mpToken; + bool bDoIICompute = mbComputeII && IsIIOpCode(p->GetOpCode()); + FormulaToken** pArgArray[2]; + if (bDoIICompute) + pArgArray[0] = pCode - 1; // Add first argument NextToken(); AddSubLine(); + if (bDoIICompute) + { + pArgArray[1] = pCode - 1; // Add second argument + HandleIIOpCode(p->GetOpCode(), p->GetInForceArray(), pArgArray, 2); + } PutCode(p); } } @@ -1943,8 +1989,17 @@ void FormulaCompiler::CompareLine() while (mpToken->GetOpCode() >= ocEqual && mpToken->GetOpCode() <= ocGreaterEqual) { FormulaTokenRef p = mpToken; + bool bDoIICompute = mbComputeII && IsIIOpCode(p->GetOpCode()); + FormulaToken** pArgArray[2]; + if (bDoIICompute) + pArgArray[0] = pCode - 1; // Add first argument NextToken(); ConcatLine(); + if (bDoIICompute) + { + pArgArray[1] = pCode - 1; // Add second argument + HandleIIOpCode(p->GetOpCode(), p->GetInForceArray(), pArgArray, 2); + } PutCode(p); } } @@ -1963,8 +2018,17 @@ OpCode FormulaCompiler::Expression() { FormulaTokenRef p = mpToken; mpToken->SetByte( 2 ); // 2 parameters! + bool bDoIICompute = mbComputeII && IsIIOpCode(p->GetOpCode()); + FormulaToken** pArgArray[2]; + if (bDoIICompute) + pArgArray[0] = pCode - 1; // Add first argument NextToken(); CompareLine(); + if (bDoIICompute) + { + pArgArray[1] = pCode - 1; // Add second argument + HandleIIOpCode(p->GetOpCode(), p->GetInForceArray(), pArgArray, 2); + } PutCode(p); } return mpToken->GetOpCode(); diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx index e2c778a01dda..1d46b3d50800 100644 --- a/sc/qa/unit/ucalc.hxx +++ b/sc/qa/unit/ucalc.hxx @@ -148,6 +148,7 @@ public: void testFormulaCompilerImplicitIntersection1ParamNoChange(); void testFormulaCompilerImplicitIntersection1ParamWithChange(); void testFormulaCompilerImplicitIntersection1NoGroup(); + void testFormulaCompilerImplicitIntersectionOperators(); void testFormulaRefUpdate(); void testFormulaRefUpdateRange(); void testFormulaRefUpdateSheets(); @@ -579,6 +580,7 @@ public: CPPUNIT_TEST(testFormulaCompilerImplicitIntersection1ParamNoChange); CPPUNIT_TEST(testFormulaCompilerImplicitIntersection1ParamWithChange); CPPUNIT_TEST(testFormulaCompilerImplicitIntersection1NoGroup); + CPPUNIT_TEST(testFormulaCompilerImplicitIntersectionOperators); CPPUNIT_TEST(testFormulaRefUpdate); CPPUNIT_TEST(testFormulaRefUpdateRange); CPPUNIT_TEST(testFormulaRefUpdateSheets); diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx index a3b0125c9beb..3b69bce3049f 100644 --- a/sc/qa/unit/ucalc_formula.cxx +++ b/sc/qa/unit/ucalc_formula.cxx @@ -1426,6 +1426,42 @@ void Test::testFormulaCompilerImplicitIntersection1NoGroup() m_pDoc->DeleteTab(0); } +void Test::testFormulaCompilerImplicitIntersectionOperators() +{ + struct TestCase + { + OUString formula[3]; + double result[3]; + }; + + m_pDoc->InsertTab(0, "Test"); + sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on. + + m_pDoc->SetValue(2, 0, 0, 5); // C1 + m_pDoc->SetValue(2, 1, 0, 4); // C2 + m_pDoc->SetValue(2, 2, 0, 3); // C3 + m_pDoc->SetValue(3, 0, 0, 1); // D1 + m_pDoc->SetValue(3, 1, 0, 2); // D2 + m_pDoc->SetValue(3, 2, 0, 3); // D3 + + TestCase tests[] = + { + { OUString("=C:C/D:D"), OUString("=C:C/D:D"), OUString("=C:C/D:D"), 5, 2, 1 }, + { OUString("=C1:C2/D1:D2"), OUString("=C2:C3/D2:D3"), OUString("=C3:C4/D3:D4"), 5, 2, 1 } + }; + + for (const TestCase& test : tests) + { + for(int i = 0; i < 2; ++i ) + m_pDoc->SetString(ScAddress(4,i,0), test.formula[i]); // E1-3 + for(int i = 0; i < 2; ++i ) + CPPUNIT_ASSERT_EQUAL_MESSAGE(OUString( test.formula[i] + " result incorrect in row " + OUString::number(i+1)).toUtf8().getStr(), + test.result[i], m_pDoc->GetValue(ScAddress(4,i,0))); + } + + m_pDoc->DeleteTab(0); +} + void Test::testFormulaRefUpdate() { m_pDoc->InsertTab(0, "Formula"); diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx index 5a9de437077e..ab5920a61aed 100644 --- a/sc/source/core/tool/compiler.cxx +++ b/sc/source/core/tool/compiler.cxx @@ -5800,8 +5800,14 @@ formula::ParamClass ScCompiler::GetForceArrayParameter( const formula::FormulaTo bool ScCompiler::IsIIOpCode(OpCode nOpCode) const { - if (nOpCode == ocSumIf || nOpCode == ocAverageIf || (nOpCode >= SC_OPCODE_START_1_PAR && nOpCode < SC_OPCODE_STOP_1_PAR)) + if (nOpCode == ocSumIf || nOpCode == ocAverageIf || (nOpCode >= SC_OPCODE_START_1_PAR && nOpCode < SC_OPCODE_STOP_1_PAR) + || (nOpCode >= SC_OPCODE_START_BIN_OP && nOpCode < SC_OPCODE_STOP_UN_OP + && nOpCode != ocIntersect && nOpCode != ocUnion && nOpCode != ocRange + && nOpCode != ocAnd && nOpCode != ocOr && nOpCode != ocXor ) + || nOpCode == ocPercentSign) + { return true; + } return false; } @@ -5862,6 +5868,34 @@ void ScCompiler::HandleIIOpCode(OpCode nOpCode, formula::ParamClass eClass, Form ReplaceDoubleRefII(pppToken[0]); } + else if (nOpCode >= SC_OPCODE_START_BIN_OP && nOpCode < SC_OPCODE_STOP_BIN_OP) + { + assert(nOpCode != ocIntersect && nOpCode != ocUnion && nOpCode != ocRange); + + if (nNumParams != 2) + return; + + if (eClass == formula::ForceArray || mbMatrixFlag) + return; + + // Convert only if the other parameter is not a matrix nor an array (which would force the result to be a matrix). + if ((*pppToken[0])->GetType() == svDoubleRef && (*pppToken[1])->GetType() != svMatrix && (*pppToken[1])->IsInForceArray()) + ReplaceDoubleRefII(pppToken[0]); + if ((*pppToken[1])->GetType() == svDoubleRef && (*pppToken[0])->GetType() != svMatrix && (*pppToken[0])->IsInForceArray()) + ReplaceDoubleRefII(pppToken[1]); + } + else if ((nOpCode >= SC_OPCODE_START_UN_OP && nOpCode < SC_OPCODE_STOP_UN_OP) + || nOpCode == ocPercentSign) + { + if (nNumParams != 1) + return; + + if (eClass == formula::ForceArray || mbMatrixFlag) + return; + + if ((*pppToken[0])->GetType() == svDoubleRef) + ReplaceDoubleRefII(pppToken[0]); + } } void ScCompiler::ReplaceDoubleRefII(FormulaToken** ppDoubleRefTok) _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits