@@ -64,9 +64,9 @@ private bool ProcessFunctionCall()
6464 if ( Text [ i ] == ',' )
6565 {
6666 var subExpression = new SubExpression ( _parentExpression , _buffer . ToString ( ) ) ;
67- subExpression . Compute ( true ) ;
67+ subExpression . Compute ( ) ;
6868
69- var param = _parentExpression . StringToDouble ( subExpression . Text ) ;
69+ var param = _parentExpression . StringToDouble ( subExpression . Text , out _ ) ;
7070 foundNull = foundNull || param == null ;
7171 if ( param != null )
7272 {
@@ -88,9 +88,9 @@ private bool ProcessFunctionCall()
8888 }
8989
9090 var subExpression = new SubExpression ( _parentExpression , _buffer . ToString ( ) ) ;
91- subExpression . Compute ( true ) ;
91+ subExpression . Compute ( ) ;
9292
93- var param = _parentExpression . StringToDouble ( subExpression . Text ) ;
93+ var param = _parentExpression . StringToDouble ( subExpression . Text , out _ ) ;
9494 foundNull = foundNull || param == null ;
9595 parameters . Add ( param ?? 0 ) ;
9696 break ;
@@ -105,20 +105,20 @@ private bool ProcessFunctionCall()
105105
106106 if ( foundNull )
107107 {
108- StorePlaceholder ( functionStartIndex , functionEndIndex , null ) ;
108+ StorePlaceholder ( functionStartIndex , functionEndIndex , null , true ) ;
109109 return true ;
110110 }
111111 else if ( Utility . IsNativeFunction ( foundFunction ) )
112112 {
113113 double functionResult = Utility . ComputeNativeFunction ( foundFunction , parameters . ToArray ( ) ) ;
114- StorePlaceholder ( functionStartIndex , functionEndIndex , functionResult ) ;
114+ StorePlaceholder ( functionStartIndex , functionEndIndex , functionResult , true ) ;
115115 }
116116 else
117117 {
118118 if ( _parentExpression . ExpressionFunctions . TryGetValue ( foundFunction , out var customFunction ) )
119119 {
120120 var functionResult = customFunction . Invoke ( parameters . ToArray ( ) ) ?? _parentExpression . Options . DefaultNullValue ;
121- StorePlaceholder ( functionStartIndex , functionEndIndex , functionResult ) ;
121+ StorePlaceholder ( functionStartIndex , functionEndIndex , functionResult , true ) ;
122122 }
123123 else
124124 {
@@ -132,57 +132,54 @@ private bool ProcessFunctionCall()
132132 return false ;
133133 }
134134
135- internal string Compute ( bool isCacheable )
135+ internal string Compute ( )
136136 {
137137 TruncateParenthesizes ( ) ;
138138
139139 //Process all function calls from right-to-left.
140- while ( true )
140+ while ( ProcessFunctionCall ( ) )
141141 {
142- if ( ProcessFunctionCall ( ) )
143- {
144- isCacheable = false ;
145- }
146- else
147- {
148- break ;
149- }
150142 }
151143
144+ bool isAnyUserVariableDerived = false ;
145+
152146 while ( true )
153147 {
154148 int operatorIndex ;
155149
156150 //Pre-first-order:
157151 while ( ( operatorIndex = GetFreestandingNotOperation ( out _ ) ) != - 1 )
158152 {
159- var rightValue = GetRightValue ( operatorIndex + 1 , out int outParsedLength , out bool isOperationCacheable ) ;
153+ var rightValue = GetRightValue ( operatorIndex + 1 , out int outParsedLength , out bool isUserVariableDerived ) ;
154+ isAnyUserVariableDerived = isAnyUserVariableDerived || isUserVariableDerived ;
160155 int ? calculatedResult = rightValue == null ? null : ( rightValue == 0 ) ? 1 : 0 ;
161-
162- StorePlaceholder ( operatorIndex , operatorIndex + outParsedLength , calculatedResult ) ;
156+ StorePlaceholder ( operatorIndex , operatorIndex + outParsedLength , calculatedResult , isUserVariableDerived ) ;
163157 }
164158
165159 //First order operations:
166160 operatorIndex = GetIndexOfOperation ( Utility . FirstOrderOperations , out string operation ) ;
167161 if ( operatorIndex > 0 )
168162 {
169- CollapseRightAndLeft ( operation , operatorIndex ) ;
163+ CollapseRightAndLeft ( operation , operatorIndex , out bool isUserVariableDerived ) ;
164+ isAnyUserVariableDerived = isAnyUserVariableDerived || isUserVariableDerived ;
170165 continue ;
171166 }
172167
173168 //Second order operations:
174169 operatorIndex = GetIndexOfOperation ( Utility . SecondOrderOperations , out operation ) ;
175170 if ( operatorIndex > 0 )
176171 {
177- CollapseRightAndLeft ( operation , operatorIndex ) ;
172+ CollapseRightAndLeft ( operation , operatorIndex , out bool isUserVariableDerived ) ;
173+ isAnyUserVariableDerived = isAnyUserVariableDerived || isUserVariableDerived ;
178174 continue ;
179175 }
180176
181177 //Third order operations:
182178 operatorIndex = GetIndexOfOperation ( Utility . ThirdOrderOperations , out operation ) ;
183179 if ( operatorIndex > 0 )
184180 {
185- CollapseRightAndLeft ( operation , operatorIndex ) ;
181+ CollapseRightAndLeft ( operation , operatorIndex , out bool isUserVariableDerived ) ;
182+ isAnyUserVariableDerived = isAnyUserVariableDerived || isUserVariableDerived ;
186183 continue ;
187184 }
188185
@@ -195,12 +192,12 @@ internal string Compute(bool isCacheable)
195192 return Text ;
196193 }
197194
198- return _parentExpression . State . StorePlaceholderCacheItem ( _parentExpression . StringToDouble ( Text ) ) ;
195+ return _parentExpression . State . StorePlaceholderCacheItem ( _parentExpression . StringToDouble ( Text , out _ ) ) ;
199196 }
200197
201- internal void StorePlaceholder ( int startIndex , int endIndex , double ? value )
198+ internal void StorePlaceholder ( int startIndex , int endIndex , double ? value , bool isUserVariableDerived )
202199 {
203- var cacheKey = _parentExpression . State . StorePlaceholderCacheItem ( value ) ;
200+ var cacheKey = _parentExpression . State . StorePlaceholderCacheItem ( value , isUserVariableDerived ) ;
204201 Text = _parentExpression . ReplaceRange ( Text , startIndex , endIndex , cacheKey ) ;
205202 }
206203
@@ -219,17 +216,19 @@ internal void TruncateParenthesizes()
219216 /// Gets the numbers to the left and right of an operator.
220217 /// Returns FALSE when NULL is found for either value.
221218 /// </summary>
222- private void CollapseRightAndLeft ( string operation , int operationBeginIndex )
219+ private void CollapseRightAndLeft ( string operation , int operationBeginIndex , out bool isUserVariableDerived )
223220 {
224- var left = GetLeftValue ( operationBeginIndex , out int leftParsedLength , out bool isLeftCacheable ) ;
225- var right = GetRightValue ( operationBeginIndex + operation . Length , out int rightParsedLength , out bool isRightCacheable ) ;
221+ var left = GetLeftValue ( operationBeginIndex , out int leftParsedLength , out bool isLeftUserVariableDerived ) ;
222+ var right = GetRightValue ( operationBeginIndex + operation . Length , out int rightParsedLength , out bool isRightUserVariableDerived ) ;
226223
227224 var beginPosition = operationBeginIndex - leftParsedLength ;
228225 var endPosition = operationBeginIndex + rightParsedLength + ( operation . Length - 1 ) ;
229226
227+ isUserVariableDerived = isLeftUserVariableDerived || isRightUserVariableDerived ;
228+
230229 if ( _parentExpression . State . TryGetComputedStep ( out ComputedStepItem cachedObj ) )
231230 {
232- StorePlaceholder ( cachedObj . BeginPosition , cachedObj . EndPosition , cachedObj . ParsedValue ) ;
231+ StorePlaceholder ( cachedObj . BeginPosition , cachedObj . EndPosition , cachedObj . ParsedValue , isUserVariableDerived ) ;
233232 }
234233 else
235234 {
@@ -240,8 +239,8 @@ private void CollapseRightAndLeft(string operation, int operationBeginIndex)
240239 result = Utility . ComputePrivative ( left ?? 0 , operation , right ?? 0 ) ;
241240 }
242241
243- StorePlaceholder ( beginPosition , endPosition , result ) ;
244- if ( isLeftCacheable && isRightCacheable )
242+ StorePlaceholder ( beginPosition , endPosition , result , isUserVariableDerived ) ;
243+ if ( ! isLeftUserVariableDerived && ! isRightUserVariableDerived )
245244 {
246245 var parsedNumber = new ComputedStepItem
247246 {
@@ -258,12 +257,12 @@ private void CollapseRightAndLeft(string operation, int operationBeginIndex)
258257 }
259258 }
260259
261- private double ? GetLeftValue ( int operationIndex , out int outParsedLength , out bool isCacheable )
260+ private double ? GetLeftValue ( int operationIndex , out int outParsedLength , out bool isUserVariableDerived )
262261 {
263262 if ( _parentExpression . State . TryGetScanStep ( out var cachedObj ) )
264263 {
265264 outParsedLength = cachedObj . Length ;
266- isCacheable = true ;
265+ isUserVariableDerived = false ;
267266 return cachedObj . Value ;
268267 }
269268 else
@@ -283,7 +282,7 @@ private void CollapseRightAndLeft(string operation, int operationBeginIndex)
283282 outParsedLength = ( operationIndex - i ) - 1 ;
284283 var cacheKey = span . Slice ( operationIndex - outParsedLength + 1 , outParsedLength - 2 ) ;
285284 var cachedItem = _parentExpression . State . GetPlaceholderCacheItem ( cacheKey ) ;
286- isCacheable = ! cachedItem . IsVariable ;
285+ isUserVariableDerived = cachedItem . IsUserVariableDerived ;
287286 _parentExpression . State . IncrementScanStep ( ) ;
288287 return cachedItem . ComputedValue ;
289288 }
@@ -307,8 +306,7 @@ private void CollapseRightAndLeft(string operation, int operationBeginIndex)
307306 }
308307
309308 outParsedLength = ( operationIndex - i ) - 1 ;
310- isCacheable = true ;
311- var result = _parentExpression . StringToDouble ( span . Slice ( operationIndex - outParsedLength , outParsedLength ) ) ;
309+ var result = _parentExpression . StringToDouble ( span . Slice ( operationIndex - outParsedLength , outParsedLength ) , out isUserVariableDerived ) ;
312310
313311 _parentExpression . State . StoreScanStep ( new ScanStepItem
314312 {
@@ -321,12 +319,12 @@ private void CollapseRightAndLeft(string operation, int operationBeginIndex)
321319 }
322320 }
323321
324- private double ? GetRightValue ( int endOfOperationIndex , out int outParsedLength , out bool isCacheable )
322+ private double ? GetRightValue ( int endOfOperationIndex , out int outParsedLength , out bool isUserVariableDerived )
325323 {
326324 if ( _parentExpression . State . TryGetScanStep ( out var cachedObj ) )
327325 {
328326 outParsedLength = cachedObj . Length ;
329- isCacheable = true ;
327+ isUserVariableDerived = false ;
330328 return cachedObj . Value ;
331329 }
332330 else
@@ -345,7 +343,7 @@ private void CollapseRightAndLeft(string operation, int operationBeginIndex)
345343 i ++ ;
346344 outParsedLength = i ;
347345 var cachedItem = _parentExpression . State . GetPlaceholderCacheItem ( span . Slice ( 1 , i - 2 ) ) ;
348- isCacheable = ! cachedItem . IsVariable ;
346+ isUserVariableDerived = cachedItem . IsUserVariableDerived ;
349347 _parentExpression . State . IncrementScanStep ( ) ;
350348 return cachedItem . ComputedValue ;
351349 }
@@ -362,8 +360,7 @@ private void CollapseRightAndLeft(string operation, int operationBeginIndex)
362360 }
363361
364362 outParsedLength = i ;
365- isCacheable = true ;
366- var result = _parentExpression . StringToDouble ( span . Slice ( 0 , i ) ) ;
363+ var result = _parentExpression . StringToDouble ( span . Slice ( 0 , i ) , out isUserVariableDerived ) ;
367364
368365 _parentExpression . State . StoreScanStep ( new ScanStepItem
369366 {
0 commit comments