Ejemplo n.º 1
0
        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();
            }
        }
Ejemplo n.º 2
0
        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);
        }