public void CaptureVariables(InterpreterScope scope) { // Initialize a new scope object with a FunctionCall context so we can determine which // variables have to be captured. The FunctionCall context will only see the globals. var captureScope = new InterpreterScope(scope); captureScope.Context = new FunctionCallExpression("NonAnonymousFunction", new ExpressionBase[0]); var capturedVariables = new List <VariableReferenceExpression>(); var possibleDependencies = new HashSet <string>(); ((INestedExpressions)this).GetDependencies(possibleDependencies); foreach (var dependency in possibleDependencies) { if (captureScope.GetVariable(dependency) == null) { // the variable is not visible to the function scope. check to see if it's visible // in the calling scope. if it is, create a copy for the function call. var variable = scope.GetVariableReference(dependency); if (variable != null) { capturedVariables.Add(variable); } } } if (capturedVariables.Count > 0) { CapturedVariables = capturedVariables.ToArray(); } }
private static ExpressionBase GetParameter(InterpreterScope parameterScope, InterpreterScope scope, AssignmentExpression assignment) { ExpressionBase value = assignment.Value; var variable = value as VariableExpression; if (variable != null) { value = scope.GetVariable(variable.Name); if (value == null) { // could not find variable, fallback to VariableExpression.ReplaceVariables generating an error value = assignment.Value; } else { // when a parameter is assigned to a variable that is an array or dictionary, // assume it has already been evaluated and pass it by reference. this is magnitudes // more performant, and allows the function to modify the data in the container. if (value.Type == ExpressionType.Dictionary || value.Type == ExpressionType.Array) { value = scope.GetVariableReference(variable.Name); assignment.Value.CopyLocation(value); return(value); } } } if (value.IsConstant) { // already a basic type, do nothing } else if (value.Type == ExpressionType.FunctionDefinition) { var anonymousFunction = value as AnonymousUserFunctionDefinitionExpression; if (anonymousFunction != null) { anonymousFunction.CaptureVariables(parameterScope); } } else { bool isLogicalUnit = value.IsLogicalUnit; // not a basic type, evaluate it var assignmentScope = new InterpreterScope(scope) { Context = assignment }; if (!value.ReplaceVariables(assignmentScope, out value)) { var error = (ParseErrorExpression)value; return(new ParseErrorExpression("Invalid value for parameter: " + assignment.Variable.Name, assignment.Value) { InnerError = error }); } value.IsLogicalUnit = isLogicalUnit; assignment.Value.CopyLocation(value); } return(value); }