@@ -111,7 +111,7 @@ internal static object ExecutePivotFieldFormula(RpnOptimizedDependencyChain depC
111111 {
112112 var formula = new RpnFormula ( null , 0 , 0 ) ;
113113 formula . SetFormula ( tokens , depChain ) ;
114- return AddChainForFormula ( depChain , formula , options , false ) . Result ;
114+ return CalculateFormulaChain ( depChain , formula , options , false ) . Result ;
115115 }
116116
117117 private static void ExecuteChain ( RpnOptimizedDependencyChain depChain , ExcelRangeBase range , ExcelCalculationOption options , bool writeToCell )
@@ -129,7 +129,7 @@ private static void ExecuteChain(RpnOptimizedDependencyChain depChain, ExcelRang
129129 {
130130 if ( GetFormula ( depChain , ws , fs . Row , fs . Column , fs . Value , ref f ) )
131131 {
132- AddChainForFormula ( depChain , f , options , writeToCell ) ;
132+ CalculateFormulaChain ( depChain , f , options , writeToCell ) ;
133133 }
134134 }
135135 catch ( CircularReferenceException )
@@ -263,7 +263,7 @@ private static void ExecuteName(RpnOptimizedDependencyChain depChain, ExcelNamed
263263 if ( string . IsNullOrEmpty ( name . NameFormula ) == false )
264264 {
265265 var f = GetNameFormula ( depChain , ws , depChain . _parsingContext . ExcelDataProvider . GetName ( name ) , 1 , 1 ) ;
266- AddChainForFormula ( depChain , f , options , writeToCell ) ;
266+ CalculateFormulaChain ( depChain , f , options , writeToCell ) ;
267267 }
268268 else if ( ws != null && name . IsValidRowCol ( ) )
269269 {
@@ -287,7 +287,7 @@ private static object ExecuteChain(RpnOptimizedDependencyChain depChain, ExcelWo
287287 var f = new RpnFormula ( ws , cell . Row , cell . Column ) ;
288288 depChain . _parsingContext . CurrentCell = new FormulaCellAddress ( ws ? . Index ?? - 1 , - 1 , 0 ) ;
289289 f . SetFormula ( formula , depChain ) ;
290- return AddChainForFormula ( depChain , f , options , writeToCell ) . Result ;
290+ return CalculateFormulaChain ( depChain , f , options , writeToCell ) . Result ;
291291 }
292292 catch ( CircularReferenceException )
293293 {
@@ -307,7 +307,7 @@ private static object ExecuteChain(RpnOptimizedDependencyChain depChain, ExcelWo
307307 var f = new RpnFormula ( ws , 0 , 0 ) ;
308308 f . SetFormula ( formula , depChain ) ;
309309 f . _row = - 1 ;
310- return AddChainForFormula ( depChain , f , options , writeToCell ) . Result ;
310+ return CalculateFormulaChain ( depChain , f , options , writeToCell ) . Result ;
311311 }
312312 catch ( CircularReferenceException )
313313 {
@@ -401,32 +401,29 @@ private static RpnFormula GetNameFormula(RpnOptimizedDependencyChain depChain, E
401401
402402 internal static CompileResult ExecutePartialFormula ( RpnOptimizedDependencyChain depChain , RpnFormula f , ExcelCalculationOption options , bool writeToCell )
403403 {
404- return AddChainForFormula ( depChain , f , options , writeToCell ) ;
404+ return CalculateFormulaChain ( depChain , f , options , writeToCell ) ;
405405 }
406406
407- internal static CompileResult ExecutePartialFormula ( RpnOptimizedDependencyChain depChain , RpnFormula f , ExcelCalculationOption options , bool writeToCell , VariableStorageScope scope )
408- {
409- return AddChainForFormula ( depChain , f , options , writeToCell , scope ) ;
410- }
411-
412- private static CompileResult AddChainForFormula ( RpnOptimizedDependencyChain depChain , RpnFormula f , ExcelCalculationOption options , bool writeToCell , VariableStorageScope scope = null )
407+ private static CompileResult CalculateFormulaChain ( RpnOptimizedDependencyChain depChain , RpnFormula f , ExcelCalculationOption options , bool writeToCell , int depChainPos = - 1 )
413408 {
414409 FormulaRangeAddress [ ] addresses ;
415- //FormulaRangeAddress address = null;
416410 RangeHashset rd = AddOrGetRDFromWsIx ( depChain , f . _ws == null ? - 1 : f . _ws . IndexInList ) ;
417411 object v = null ;
418412 bool hasLogger = depChain . _parsingContext . Parser . Logger != null ;
419- rd ? . Merge ( f . _row , f . _column ) ;
420- var followChain = options . FollowDependencyChain ;
421- depChain . StartOfChain ( ) ;
413+ var followChain = options . FollowDependencyChain && depChainPos == - 1 ;
414+ if ( depChainPos == - 1 )
415+ {
416+ rd ? . Merge ( f . _row , f . _column ) ;
417+ depChain . StartOfChain ( ) ;
418+ }
422419 ExecuteFormula :
423420 try
424421 {
425422 SetCurrentCell ( depChain , f ) ;
426423 var ws = f . _ws ;
427424 if ( f . _tokenIndex < f . _tokens . Count )
428425 {
429- addresses = ExecuteNextToken ( depChain , f , followChain ) ;
426+ addresses = ExecuteNextToken ( depChain , f , followChain || depChain . _formulaStack . Count > 0 ) ;
430427 if ( f . _tokenIndex < f . _tokens . Count )
431428 {
432429 if ( addresses == null && f . _expressions . ContainsKey ( f . _tokenIndex ) && f . _expressions [ f . _tokenIndex ] . ExpressionType == ExpressionType . NameValue )
@@ -485,7 +482,7 @@ private static CompileResult AddChainForFormula(RpnOptimizedDependencyChain depC
485482
486483 if ( cr != null && ( writeToCell || depChain . _formulaStack . Count > 0 ) ) // If calculating single cell via the FormulaParser.Parse method we should not write to the cells
487484 {
488- SetValueToWorkbook ( depChain , f , rd , cr ) ;
485+ SetValueToWorkbook ( depChain , f , rd , cr , options , ref depChainPos ) ;
489486 }
490487
491488 if ( hasLogger )
@@ -690,7 +687,7 @@ private static void CheckAndClearRichData(RpnFormula f)
690687 }
691688 f . _ws . _metadataStore . Clear ( f . _row , f . _column , 1 , 1 ) ;
692689 }
693- private static void SetValueToWorkbook ( RpnOptimizedDependencyChain depChain , RpnFormula f , RangeHashset rd , CompileResult cr )
690+ private static void SetValueToWorkbook ( RpnOptimizedDependencyChain depChain , RpnFormula f , RangeHashset rd , CompileResult cr , ExcelCalculationOption options , ref int insertDepChainPos )
694691 {
695692 if ( cr . DataType == DataType . LambdaCalculation )
696693 {
@@ -727,8 +724,7 @@ private static void SetValueToWorkbook(RpnOptimizedDependencyChain depChain, Rpn
727724 var dirtyRange = ArrayFormulaOutput . FillDynamicArrayFromRangeInfo ( f , ri , rd , depChain ) ;
728725 if ( dirtyRange != null && dirtyRange . Length > 0 )
729726 {
730-
731- RecalculateDirtyCells ( dirtyRange , depChain , rd ) ;
727+ RecalculateDirtyCells ( dirtyRange , depChain , rd , options ) ;
732728 }
733729 }
734730 else //Set implicit intersection
@@ -746,7 +742,7 @@ private static void SetValueToWorkbook(RpnOptimizedDependencyChain depChain, Rpn
746742 var dirtyRange = ArrayFormulaOutput . FillDynamicArraySingleValue ( f , cr , rd , depChain ) ;
747743 if ( dirtyRange != null && dirtyRange . Length > 0 )
748744 {
749- RecalculateDirtyCells ( dirtyRange , depChain , rd ) ;
745+ RecalculateDirtyCells ( dirtyRange , depChain , rd , options ) ;
750746 }
751747 depChain . HasAnyArrayFormula = true ;
752748 }
@@ -769,8 +765,21 @@ private static void SetValueToWorkbook(RpnOptimizedDependencyChain depChain, Rpn
769765 {
770766 if ( f . _arrayIndex != - 1 )
771767 {
772- var sf = f . _ws . _sharedFormulas [ f . _arrayIndex ] ;
773- f . _ws . SetValueInner ( sf . StartRow , sf . StartCol , sf . EndRow , sf . EndCol , cr . ResultValue ?? 0D ) ;
768+ if ( ( f . _flags & FormulaFlags . IsDynamic ) == FormulaFlags . IsDynamic )
769+ {
770+ var dirtyRange = ArrayFormulaOutput . FillDynamicArraySingleValue ( f , cr , rd , depChain ) ;
771+ if ( dirtyRange != null && dirtyRange . Length > 0 )
772+ {
773+ RecalculateDirtyCells ( dirtyRange , depChain , rd , options ) ;
774+ }
775+ depChain . HasAnyArrayFormula = true ;
776+
777+ }
778+ else
779+ {
780+ var sf = f . _ws . _sharedFormulas [ f . _arrayIndex ] ;
781+ f . _ws . SetValueInner ( sf . StartRow , sf . StartCol , sf . EndRow , sf . EndCol , cr . ResultValue ?? 0D ) ;
782+ }
774783 }
775784 else
776785 {
@@ -785,74 +794,82 @@ private static void SetValueToWorkbook(RpnOptimizedDependencyChain depChain, Rpn
785794 }
786795 }
787796 }
788- depChain . DependencyChain . Add ( f . CellId ) ;
797+
798+ if ( insertDepChainPos < 0 )
799+ {
800+ depChain . DependencyChain . Add ( f . CellId ) ;
801+ }
802+ else if ( depChain . _formulaStack . Count > 0 )
803+ {
804+ depChain . DependencyChain . Insert ( ++ insertDepChainPos , f . CellId ) ;
805+ }
789806 }
790807 }
791-
792- private static void RecalculateDirtyCells ( SimpleAddress [ ] dirtyRange , RpnOptimizedDependencyChain depChain , RangeHashset rd )
808+ private static void RecalculateDirtyCells ( SimpleAddress [ ] dirtyRange , RpnOptimizedDependencyChain depChain , RangeHashset rd , ExcelCalculationOption options )
793809 {
810+ if ( depChain . _isInRecalculateDirtyCells ) return ; //EPPlus will not recalculate dirty cells while recalculating other dirty cells to avoid stack overflow.
794811 var dirtyCells = dirtyRange . ToList ( ) ;
795812 if ( depChain . FormulaRangeReferences . ContainsKey ( depChain . _parsingContext . CurrentWorksheet . IndexInList ) )
796813 {
797814 var qt = depChain . FormulaRangeReferences [ depChain . _parsingContext . CurrentWorksheet . IndexInList ] ;
798815 int fromIx = int . MaxValue ;
799- int toIx = int . MinValue ;
816+ // int toIx = int.MinValue;
800817 foreach ( var a in dirtyRange )
801818 {
802819 var ir = qt . GetIntersectingRangeItems ( new QuadRange ( a . FromRow , a . FromCol , a . ToRow , a . ToCol ) ) ;
803820 if ( ir . Count > 0 )
804821 {
805822 foreach ( var r in ir . Select ( x => x . Value ) . Distinct ( ) )
806823 {
824+ ExcelAddressBase . SplitCellId ( r , out int sheet , out int row , out int col ) ;
825+
807826 var ix = depChain . DependencyChain . IndexOf ( r ) ;
808827 if ( ix < 0 ) continue ;
809828 if ( ix < fromIx )
810829 {
811830 fromIx = ix ;
812831 }
813- var ixEnd = depChain . _startOfChain . BinarySearch ( ix + 1 ) ;
814832
815- if ( ixEnd < 0 )
833+ if ( fromIx == 0 )
816834 {
817- ixEnd = ~ ixEnd ;
818- }
819-
820- if ( ixEnd - 1 > toIx )
821- {
822- toIx = ixEnd - 1 ;
835+ break ;
823836 }
824837 }
825838 }
839+ if ( fromIx == 0 )
840+ {
841+ break ;
842+ }
826843 }
827844
828845 if ( fromIx != int . MaxValue )
829846 {
830-
831- for ( int i = fromIx ; i <= toIx ; i ++ )
847+ depChain . _isInRecalculateDirtyCells = true ;
848+ var dcCount = depChain . DependencyChain . Count ;
849+ var cc = depChain . _parsingContext . CurrentCell ;
850+ for ( int i = fromIx ; i < dcCount ; i ++ )
832851 {
833852 ExcelCellBase . SplitCellId ( depChain . DependencyChain [ i ] , out int sheetId , out int row , out int col ) ;
834-
835853 RpnFormula f = null ;
836854 var ws = depChain . _parsingContext . Package . Workbook . GetWorksheetByIndexInList ( sheetId ) ;
837855 var v = ws . _formulas . GetValue ( row , col ) ;
838856
839857 if ( GetFormula ( depChain , ws , row , col , v , ref f ) )
840858 {
841- ReCalculateFormula ( f , depChain , rd ) ;
859+ f . ClearCache ( depChain ) ;
860+ CalculateFormulaChain ( depChain , f , options , true , i ) ;
861+ if ( depChain . DependencyChain . Count > dcCount )
862+ {
863+ i += depChain . DependencyChain . Count - dcCount ;
864+ dcCount = depChain . DependencyChain . Count ;
865+ }
842866 }
843867 }
868+ depChain . _isInRecalculateDirtyCells = false ;
844869 }
845870
846871 }
847872 }
848- private static void ReCalculateFormula ( RpnFormula f , RpnOptimizedDependencyChain depChain , RangeHashset rd )
849- {
850- f . _tokenIndex = 0 ;
851- f . ClearCache ( ) ;
852- ExecuteNextToken ( depChain , f , false ) ;
853- var e = f . _expressionStack . Pop ( ) ;
854- SetValueToWorkbook ( depChain , f , rd , e . Compile ( ) ) ;
855- }
856873 private static void MergeToRd ( RangeHashset rd , int fromRow , int fromCol , int rangePos , CellStoreEnumerator < object > fe , bool atEnd )
857874 {
858875
@@ -1161,7 +1178,7 @@ private static FormulaRangeAddress[] ExecuteNextToken(RpnOptimizedDependencyChai
11611178 var nameAddress = ne . GetAddress ( ) ;
11621179 if ( nameAddress == null )
11631180 {
1164- if ( string . IsNullOrEmpty ( ne . _name ? . Formula ) == false )
1181+ if ( returnAddresses && string . IsNullOrEmpty ( ne . _name ? . Formula ) == false )
11651182 {
11661183 return null ;
11671184 }
@@ -1273,7 +1290,7 @@ private static FormulaRangeAddress[] ExecuteNextToken(RpnOptimizedDependencyChai
12731290 f . LambdaSettings . LambdaStackNumbers . Push ( s . Count ) ;
12741291 f . LambdaSettings . NumberOfLambdaVariables . Push ( clc . NumberOfVariables ) ;
12751292 }
1276- if ( r . Address != null && returnAddresses )
1293+ if ( r . Address != null )
12771294 {
12781295 if ( ( f . _funcStack . Count == 0 || ShouldIgnoreAddress ( f . _funcStack . Peek ( ) ) == false ) && r . Address != null )
12791296 {
@@ -1303,7 +1320,7 @@ private static FormulaRangeAddress[] ExecuteNextToken(RpnOptimizedDependencyChai
13031320 case TokenType . Operator :
13041321 ApplyOperator ( depChain . _parsingContext , t , f ) ;
13051322
1306- if ( s . Count > 0 && s . Peek ( ) . Status == ExpressionStatus . IsAddress && ( f . _funcStack . Count == 0 || ShouldIgnoreAddress ( f . _funcStack . Peek ( ) ) == false ) )
1323+ if ( returnAddresses && s . Count > 0 && s . Peek ( ) . Status == ExpressionStatus . IsAddress && ( f . _funcStack . Count == 0 || ShouldIgnoreAddress ( f . _funcStack . Peek ( ) ) == false ) )
13071324 {
13081325 var cr = s . Peek ( ) . Compile ( ) ;
13091326 if ( cr . Address != null )
0 commit comments