Blob Blame History Raw
From f270d113e354aa608a2efa641691167a504c6539 Mon Sep 17 00:00:00 2001
Message-Id: <f270d113e354aa608a2efa641691167a504c6539.1328721514.git.erack@redhat.com>
From: Eike Rathke <erack@erack.de>
Date: Wed, 8 Feb 2012 10:28:46 -0500
Subject: [PATCH] fdo#40378 compile defined names that had unresolveds during
 load
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="------------erAck-patch-parts"

This is a multi-part message in MIME format.
--------------erAck-patch-parts
Content-Type: text/plain; charset=UTF-8; format=fixed
Content-Transfer-Encoding: 8bit


Dependencies of defined names must not depend on the order in which they
are inserted during file load. In a second step compile defined names
that had unresolved names during load, and only those.

Signed-off-by: Kohei Yoshida <kohei.yoshida@suse.com>
---
 sc/inc/compiler.hxx              |   11 +++-
 sc/inc/rangenam.hxx              |   25 +++++--
 sc/source/core/data/document.cxx |    3 +
 sc/source/core/data/table2.cxx   |    3 +
 sc/source/core/tool/compiler.cxx |   11 ++--
 sc/source/core/tool/rangenam.cxx |  131 ++++++++++++++++++++++++++------------
 sc/source/ui/view/viewfunc.cxx   |    2 +-
 7 files changed, 129 insertions(+), 57 deletions(-)


--------------erAck-patch-parts
Content-Type: text/x-patch; name="0001-fdo-40378-compile-defined-names-that-had-unresolveds.patch"
Content-Transfer-Encoding: 8bit
Content-Disposition: attachment; filename="0001-fdo-40378-compile-defined-names-that-had-unresolveds.patch"

diff --git a/sc/inc/compiler.hxx b/sc/inc/compiler.hxx
index 5fcc6dc..6947460 100644
--- a/sc/inc/compiler.hxx
+++ b/sc/inc/compiler.hxx
@@ -227,6 +227,13 @@ public:
         ENCODE_NEVER,
     };
 
+    enum ExtendedErrorDetection
+    {
+        EXTENDED_ERROR_DETECTION_NONE = 0,      // no error on unknown symbols, default (interpreter handles it)
+        EXTENDED_ERROR_DETECTION_NAME_BREAK,    // name error on unknown symbols and break, pCode incomplete
+        EXTENDED_ERROR_DETECTION_NAME_NO_BREAK  // name error on unknown symbols, don't break, continue
+    };
+
     struct Convention
     {
         const formula::FormulaGrammar::AddressConvention meConv;
@@ -327,8 +334,8 @@ private:
     sal_Int32   mnRangeOpPosInSymbol;       // if and where a range operator is in symbol
     const Convention *pConv;
     EncodeUrlMode   meEncodeUrlMode;
+    ExtendedErrorDetection  meExtendedErrorDetection;
     bool        mbCloseBrackets;            // whether to close open brackets automatically, default TRUE
-    bool        mbExtendedErrorDetection;
     bool        mbRewind;                   // whether symbol is to be rewound to some step during lexical analysis
 
     sal_Bool   NextNewToken(bool bInArray = false);
@@ -413,7 +420,7 @@ public:
 
     void            CreateStringFromXMLTokenArray( String& rFormula, String& rFormulaNmsp );
 
-    void            SetExtendedErrorDetection( bool bVal ) { mbExtendedErrorDetection = bVal; }
+    void            SetExtendedErrorDetection( ExtendedErrorDetection eVal ) { meExtendedErrorDetection = eVal; }
 
     sal_Bool            IsCorrected() { return bCorrected; }
     const String&   GetCorrectedFormula() { return aCorrectedFormula; }
diff --git a/sc/inc/rangenam.hxx b/sc/inc/rangenam.hxx
index 7417094..56c0544 100644
--- a/sc/inc/rangenam.hxx
+++ b/sc/inc/rangenam.hxx
@@ -75,18 +75,22 @@ private:
     String			aName;
     String          aUpperName;         // #i62977# for faster searching (aName is never modified after ctor)
     ScTokenArray*	pCode;
-    ScAddress   	aPos;
-    RangeType		eType;
-    ScDocument* 	pDoc;
-    sal_uInt16			nIndex;
-    sal_Bool			bModified;			// is set/cleared by UpdateReference
-
-    // max row and column to use for wrapping of references.  If -1 use the 
+    ScAddress       aPos;
+    RangeType       eType;
+    ScDocument*     pDoc;
+    formula::FormulaGrammar::Grammar    eTempGrammar;   // needed for unresolved XML compiles
+    sal_uInt16      nIndex;
+    sal_Bool            bModified;          // is set/cleared by UpdateReference
+
+    // max row and column to use for wrapping of references.  If -1 use the
     // application's default.
     SCROW           mnMaxRow;
     SCCOL           mnMaxCol;
 
     ScRangeData( sal_uInt16 nIndex );
+
+    void CompileRangeData( const String& rSymbol, bool bSetError );
+
 public:
     typedef ::std::map<sal_uInt16, sal_uInt16> IndexMap;
 
@@ -161,6 +165,8 @@ public:
     SCROW GetMaxRow() const;
     SC_DLLPUBLIC void SetMaxCol(SCCOL nCol);
     SCCOL GetMaxCol() const;
+
+    void            CompileUnresolvedXML();
 };
 
 inline sal_Bool ScRangeData::HasType( RangeType nType ) const
@@ -211,6 +217,11 @@ public:
     void UpdateTranspose(const ScRange& rSource, const ScAddress& rDest);
     void UpdateGrow(const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY);
 
+    /** Compile those names that couldn't be resolved during loading and
+        inserting because they may have referred a name that was inserted later.
+     */
+    void CompileUnresolvedXML();
+
     SC_DLLPUBLIC const_iterator begin() const;
     SC_DLLPUBLIC const_iterator end() const;
     SC_DLLPUBLIC iterator begin();
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index e85ba1f..6f3fec0 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -3154,6 +3154,9 @@ void ScDocument::CompileXML()
     DBG_ASSERT( !pAutoNameCache, "AutoNameCache already set" );
     pAutoNameCache = new ScAutoNameCache( this );
 
+    if (pRangeName)
+        pRangeName->CompileUnresolvedXML();
+
     for (SCTAB i=0; i<=MAXTAB; i++)
         if (pTab[i]) pTab[i]->CompileXML( aProgress );
 
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index 7d7d554..b9c58ce 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -1297,6 +1297,9 @@ void ScTable::CompileAll()
 
 void ScTable::CompileXML( ScProgress& rProgress )
 {
+    if (mpRangeName)
+        mpRangeName->CompileUnresolvedXML();
+
     for (SCCOL i=0; i <= MAXCOL; i++)
     {
         aCol[i].CompileXML( rProgress );
diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx
index 9f39358..a4938f1 100644
--- a/sc/source/core/tool/compiler.cxx
+++ b/sc/source/core/tool/compiler.cxx
@@ -1741,8 +1741,8 @@ ScCompiler::ScCompiler( ScDocument* pDocument, const ScAddress& rPos,ScTokenArra
         mnRangeOpPosInSymbol(-1),
         pConv( pConvOOO_A1 ),
         meEncodeUrlMode( ENCODE_BY_GRAMMAR ),
+        meExtendedErrorDetection( EXTENDED_ERROR_DETECTION_NONE ),
         mbCloseBrackets( true ),
-        mbExtendedErrorDetection( false ),
         mbRewind( false )
 {
     nMaxTab = pDoc ? pDoc->GetTableCount() - 1 : 0;
@@ -1757,8 +1757,8 @@ ScCompiler::ScCompiler( ScDocument* pDocument, const ScAddress& rPos)
         mnRangeOpPosInSymbol(-1),
         pConv( pConvOOO_A1 ),
         meEncodeUrlMode( ENCODE_BY_GRAMMAR ),
+        meExtendedErrorDetection( EXTENDED_ERROR_DETECTION_NONE ),
         mbCloseBrackets( true ),
-        mbExtendedErrorDetection( false ),
         mbRewind( false )
 {
     nMaxTab = pDoc ? pDoc->GetTableCount() - 1 : 0;
@@ -3623,11 +3623,12 @@ sal_Bool ScCompiler::NextNewToken( bool bInArray )
 
     } while (mbRewind);
 
-    if ( mbExtendedErrorDetection )
+    if ( meExtendedErrorDetection != EXTENDED_ERROR_DETECTION_NONE )
     {
-        // set an error and end compilation
+        // set an error
         SetError( errNoName );
-        return false;
+        if (meExtendedErrorDetection == EXTENDED_ERROR_DETECTION_NAME_BREAK)
+            return false;   // end compilation
     }
 
     // Provide single token information and continue. Do not set an error, that
diff --git a/sc/source/core/tool/rangenam.cxx b/sc/source/core/tool/rangenam.cxx
index b648d1a..2b9ca3b 100644
--- a/sc/source/core/tool/rangenam.cxx
+++ b/sc/source/core/tool/rangenam.cxx
@@ -72,36 +72,19 @@ ScRangeData::ScRangeData( ScDocument* pDok,
                 aName		( rName ),
                 aUpperName  ( ScGlobal::pCharClass->upper( rName ) ),
                 pCode		( NULL ),
-                aPos		( rAddress ),
-                eType		( nType ),
-                pDoc		( pDok ),
-                nIndex		( 0 ),
-                bModified	( false ),
+                aPos        ( rAddress ),
+                eType       ( nType ),
+                pDoc        ( pDok ),
+                eTempGrammar( eGrammar ),
+                nIndex      ( 0 ),
+                bModified   ( false ),
                 mnMaxRow    (-1),
                 mnMaxCol    (-1)
 {
     if (rSymbol.Len() > 0)
-    {
-        ScCompiler aComp( pDoc, aPos );
-        aComp.SetGrammar(eGrammar);
-        pCode = aComp.CompileString( rSymbol );
-        if( !pCode->GetCodeError() )
-        {
-            pCode->Reset();
-            FormulaToken* p = pCode->GetNextReference();
-            if( p )// genau eine Referenz als erstes
-            {
-                if( p->GetType() == svSingleRef )
-                    eType = eType | RT_ABSPOS;
-                else
-                    eType = eType | RT_ABSAREA;
-            }
-            // ggf. den Fehlercode wg. unvollstaendiger Formel setzen!
-            // Dies ist fuer die manuelle Eingabe
-            aComp.CompileTokenArray();
-            pCode->DelRPN();
-        }
-    }
+        CompileRangeData( rSymbol, pDoc->IsImportingXML());
+        // Let the compiler set an error on unknown names for a subsequent
+        // CompileUnresolvedXML().
     else
     {
         // #i63513#/#i65690# don't leave pCode as NULL.
@@ -120,11 +103,12 @@ ScRangeData::ScRangeData( ScDocument* pDok,
                 aName		( rName ),
                 aUpperName  ( ScGlobal::pCharClass->upper( rName ) ),
                 pCode		( new ScTokenArray( rArr ) ),
-                aPos		( rAddress ),
-                eType		( nType ),
-                pDoc		( pDok ),
-                nIndex		( 0 ),
-                bModified	( false ),
+                aPos        ( rAddress ),
+                eType       ( nType ),
+                pDoc        ( pDok ),
+                eTempGrammar( FormulaGrammar::GRAM_UNSPECIFIED ),
+                nIndex      ( 0 ),
+                bModified   ( false ),
                 mnMaxRow    (-1),
                 mnMaxCol    (-1)
 {
@@ -148,11 +132,12 @@ ScRangeData::ScRangeData( ScDocument* pDok,
                 aName		( rName ),
                 aUpperName  ( ScGlobal::pCharClass->upper( rName ) ),
                 pCode		( new ScTokenArray() ),
-                aPos		( rTarget ),
-                eType		( RT_NAME ),
-                pDoc		( pDok ),
-                nIndex		( 0 ),
-                bModified	( false ),
+                aPos        ( rTarget ),
+                eType       ( RT_NAME ),
+                pDoc        ( pDok ),
+                eTempGrammar( FormulaGrammar::GRAM_UNSPECIFIED ),
+                nIndex      ( 0 ),
+                bModified   ( false ),
                 mnMaxRow    (-1),
                 mnMaxCol    (-1)
 {
@@ -171,11 +156,12 @@ ScRangeData::ScRangeData(const ScRangeData& rScRangeData) :
     aName 	(rScRangeData.aName),
     aUpperName  (rScRangeData.aUpperName),
     pCode		(rScRangeData.pCode ? rScRangeData.pCode->Clone() : new ScTokenArray()),		// echte Kopie erzeugen (nicht copy-ctor)
-    aPos		(rScRangeData.aPos),
-    eType		(rScRangeData.eType),
-    pDoc		(rScRangeData.pDoc),
-    nIndex   	(rScRangeData.nIndex),
-    bModified	(rScRangeData.bModified),
+    aPos        (rScRangeData.aPos),
+    eType       (rScRangeData.eType),
+    pDoc        (rScRangeData.pDoc),
+    eTempGrammar(rScRangeData.eTempGrammar),
+    nIndex      (rScRangeData.nIndex),
+    bModified   (rScRangeData.bModified),
     mnMaxRow    (rScRangeData.mnMaxRow),
     mnMaxCol    (rScRangeData.mnMaxCol)
 {}
@@ -185,9 +171,63 @@ ScRangeData::~ScRangeData()
     delete pCode;
 }
 
+void ScRangeData::CompileRangeData( const String& rSymbol, bool bSetError )
+{
+    if (eTempGrammar == FormulaGrammar::GRAM_UNSPECIFIED)
+    {
+        OSL_FAIL( "ScRangeData::CompileRangeData: unspecified grammar");
+        // Anything is almost as bad as this, but we might have the best choice
+        // if not loading documents.
+        eTempGrammar = FormulaGrammar::GRAM_NATIVE;
+    }
+
+    ScCompiler aComp( pDoc, aPos );
+    aComp.SetGrammar( eTempGrammar);
+    if (bSetError)
+        aComp.SetExtendedErrorDetection( ScCompiler::EXTENDED_ERROR_DETECTION_NAME_NO_BREAK);
+    ScTokenArray* pNewCode = aComp.CompileString( rSymbol );
+    ::std::auto_ptr<ScTokenArray> pOldCode( pCode);     // old pCode will be deleted
+    pCode = pNewCode;
+    if( !pCode->GetCodeError() )
+    {
+        pCode->Reset();
+        FormulaToken* p = pCode->GetNextReference();
+        if( p )
+        {
+            // first token is a reference
+            /* FIXME: wouldn't that need a check if it's exactly one reference? */
+            if( p->GetType() == svSingleRef )
+                eType = eType | RT_ABSPOS;
+            else
+                eType = eType | RT_ABSAREA;
+        }
+        // For manual input set an error for an incomplete formula.
+        if (!pDoc->IsImportingXML())
+        {
+            aComp.CompileTokenArray();
+            pCode->DelRPN();
+        }
+    }
+}
+
+void ScRangeData::CompileUnresolvedXML()
+{
+    if (pCode->GetCodeError() == errNoName)
+    {
+        // Reconstruct the symbol/formula and then recompile.
+        String aSymbol;
+        ScCompiler aComp( pDoc, aPos, *pCode);
+        aComp.SetGrammar( eTempGrammar);
+        aComp.CreateStringFromTokenArray( aSymbol);
+        // Don't let the compiler set an error for unknown names on final
+        // compile, errors are handled by the interpreter thereafter.
+        CompileRangeData( aSymbol, false);
+    }
+}
+
 void ScRangeData::GuessPosition()
 {
-    //	setzt eine Position, mit der alle relative Referenzen bei CalcAbsIfRel
+    //  setzt eine Position, mit der alle relative Referenzen bei CalcAbsIfRel
     //	ohne Fehler verabsolutiert werden koennen
 
     DBG_ASSERT(aPos == ScAddress(), "die Position geht jetzt verloren");
@@ -802,6 +842,13 @@ void ScRangeName::UpdateGrow(const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY)
         itr->UpdateGrow(rArea, nGrowX, nGrowY);
 }
 
+void ScRangeName::CompileUnresolvedXML()
+{
+    DataType::iterator itr = maData.begin(), itrEnd = maData.end();
+    for (; itr != itrEnd; ++itr)
+        itr->CompileUnresolvedXML();
+}
+
 ScRangeName::const_iterator ScRangeName::begin() const
 {
     return maData.begin();
diff --git a/sc/source/ui/view/viewfunc.cxx b/sc/source/ui/view/viewfunc.cxx
index f0f05b1..2cb3fe0 100644
--- a/sc/source/ui/view/viewfunc.cxx
+++ b/sc/source/ui/view/viewfunc.cxx
@@ -482,7 +482,7 @@ void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab, const String& rS
             aComp.SetAutoCorrection( sal_True );
             if ( rString.GetChar(0) == '+' || rString.GetChar(0) == '-' )
             {
-                aComp.SetExtendedErrorDetection( true );
+                aComp.SetExtendedErrorDetection( ScCompiler::EXTENDED_ERROR_DETECTION_NAME_BREAK );
             }
             String aFormula( rString );
             ScTokenArray* pArr;

--------------erAck-patch-parts--