1+ using System . Buffers ;
12using BlazorDatasheet . Formula . Core . Interpreter . Parsing ;
23using BlazorDatasheet . Formula . Core . Interpreter . References ;
34using SyntaxTree = BlazorDatasheet . Formula . Core . Interpreter . Parsing . SyntaxTree ;
@@ -13,7 +14,8 @@ public class Evaluator
1314
1415 private readonly record struct EvalContext (
1516 FormulaEvaluationOptions Options ,
16- FormulaExecutionContext ExecutionContext ) ;
17+ FormulaExecutionContext ExecutionContext ,
18+ FormulaCallerInfo ? Caller ) ;
1719
1820 public Evaluator ( IEnvironment environment )
1921 {
@@ -25,11 +27,13 @@ public Evaluator(IEnvironment environment)
2527 }
2628
2729 public CellValue Evaluate ( CellFormula cellFormula , FormulaExecutionContext ? executionContext = null ,
28- FormulaEvaluationOptions ? options = null )
30+ FormulaEvaluationOptions ? options = null ,
31+ FormulaCallerInfo ? caller = null )
2932 {
3033 var ctx = new EvalContext (
3134 options ?? FormulaEvaluationOptions . Default ,
32- executionContext ?? new FormulaExecutionContext ( ) ) ;
35+ executionContext ?? new FormulaExecutionContext ( ) ,
36+ caller ) ;
3337 return DoEvaluate ( cellFormula , ctx ) ;
3438 }
3539
@@ -46,7 +50,7 @@ private CellValue DoEvaluate(CellFormula formula, EvalContext ctx)
4650 /// Evaluates a syntax tree
4751 /// </summary>
4852 internal CellValue Evaluate ( SyntaxTree tree ) =>
49- EvaluateTree ( tree , new EvalContext ( FormulaEvaluationOptions . Default , new FormulaExecutionContext ( ) ) ) ;
53+ EvaluateTree ( tree , new EvalContext ( FormulaEvaluationOptions . Default , new FormulaExecutionContext ( ) , null ) ) ;
5054
5155 private CellValue EvaluateTree ( SyntaxTree tree , EvalContext ctx )
5256 {
@@ -99,9 +103,9 @@ private CellValue EvaluateExpression(Expression expression, EvalContext ctx)
99103
100104 private CellValue EvaluateNamedExpression ( VariableExpression expression )
101105 {
102- if ( ! _environment . VariableExists ( expression . NameToken . Value ) )
106+ if ( ! _environment . TryGetVariable ( expression . NameToken . Value , out var value ) )
103107 return CellValue . Error ( ErrorType . Ref ) ;
104- return _environment . GetVariable ( expression . NameToken . Value ) ;
108+ return value ;
105109 }
106110
107111 private CellValue EvaluateArrayConstantExpression ( ArrayConstantExpression expression )
@@ -157,7 +161,10 @@ private CellValue EvaluateCellReference(CellReference cellReference, EvalContext
157161 if ( ctx . ExecutionContext . TryGetExecutedValue ( formula , out var result ) )
158162 return result ;
159163
160- return DoEvaluate ( formula , ctx ) ;
164+ return DoEvaluate ( formula , new EvalContext (
165+ ctx . Options ,
166+ ctx . ExecutionContext ,
167+ new FormulaCallerInfo ( cellReference . RowIndex , cellReference . ColIndex , cellReference . SheetName ) ) ) ;
161168 }
162169
163170 private CellValue EvaluateRangeReference ( RangeReference reference )
@@ -181,30 +188,45 @@ private CellValue EvaluateFunctionCall(FunctionExpression node, EvalContext ctx)
181188 return CellValue . Error ( ErrorType . Na , "Incorrect number of function arguments" ) ;
182189 }
183190
184- int paramIndex = 0 ;
185- int argIndex = 0 ;
191+ var acceptsErrors = func . AcceptsErrors ;
192+ var callMetaData = new FunctionCallMetaData (
193+ ctx . Caller ? . RowIndex ,
194+ ctx . Caller ? . ColIndex ,
195+ ctx . Caller ? . SheetName ) ;
196+ CellValue [ ] ? rentedArgs = nArgsProvided == 0 ? null : ArrayPool < CellValue > . Shared . Rent ( nArgsProvided ) ;
197+ Span < CellValue > convertedArgs = nArgsProvided == 0
198+ ? Span < CellValue > . Empty
199+ : rentedArgs . AsSpan ( 0 , nArgsProvided ) ;
200+
201+ try
202+ {
203+ int paramIndex = 0 ;
204+ int argIndex = 0 ;
186205
187- CellValue [ ] convertedArgs = new CellValue [ nArgsProvided ] ;
206+ while ( paramIndex < paramDefinitions . Length &&
207+ argIndex < nArgsProvided )
208+ {
209+ var paramDefinition = paramDefinitions [ paramIndex ] ;
210+ var arg = EvaluateExpression ( node . Args [ argIndex ] , ctx ) ;
188211
189- while ( paramIndex < paramDefinitions . Length &&
190- argIndex < nArgsProvided )
191- {
192- var paramDefinition = paramDefinitions [ paramIndex ] ;
193- var arg = EvaluateExpression ( node . Args [ argIndex ] , ctx ) ;
212+ convertedArgs [ argIndex ] = _parameterConverter . ConvertVal ( arg , paramDefinition . Type ) ;
194213
195- convertedArgs [ argIndex ] = _parameterConverter . ConvertVal ( arg , paramDefinition . Type ) ;
214+ if ( convertedArgs [ argIndex ] . IsError ( ) && ! acceptsErrors )
215+ return convertedArgs [ argIndex ] ;
196216
197- if ( convertedArgs [ argIndex ] . IsError ( ) && ! func . AcceptsErrors )
198- return convertedArgs [ argIndex ] ;
217+ if ( IsConsumable ( paramDefinition ) )
218+ paramIndex ++ ;
199219
200- if ( IsConsumable ( paramDefinition ) )
201- paramIndex ++ ;
220+ argIndex ++ ;
221+ }
202222
203- argIndex ++ ;
223+ return func . Invoke ( convertedArgs [ ..nArgsProvided ] , callMetaData ) ;
224+ }
225+ finally
226+ {
227+ if ( rentedArgs != null )
228+ ArrayPool < CellValue > . Shared . Return ( rentedArgs , clearArray : true ) ;
204229 }
205-
206- var funcResult = func . Invoke ( convertedArgs ) ;
207- return funcResult ;
208230 }
209231
210232 private bool IsConsumable ( ParameterDefinition param )
0 commit comments