示例#1
0
        /// <summary>
        /// Replaces the variables in the expression with values from <paramref name="scope"/>.
        /// </summary>
        /// <param name="scope">The scope object containing variable values.</param>
        /// <param name="result">[out] The new expression containing the replaced variables.</param>
        /// <returns><c>true</c> if substitution was successful, <c>false</c> if something went wrong, in which case <paramref name="result"/> will likely be a <see cref="ParseErrorExpression"/>.</returns>
        public override bool ReplaceVariables(InterpreterScope scope, out ExpressionBase result)
        {
            // FunctionDefinition.ReplaceVariables is called when evaluating a function for an assignment.
            // For user functions (see UserFunctionDefinition.ReplaceVariables) - it will just evaluate the
            // function call and return the result. Several internal functions have very special Evaluate
            // handling that should not be executed when defining variables. Those functions rely on this
            // behavior to just evaluate the parameters without calling Evaluate. There are some built-in
            // functions that should call Evaluate when ReplaceVariables is called. They will override
            // ReplaceVariables to do that.
            var parameters = new ExpressionBase[Parameters.Count];
            int i          = 0;

            foreach (var parameterName in Parameters)
            {
                // do a direct lookup here. calling GetParameter will discard the VariableReference
                // and we want to preserve those for now.
                var parameter = scope.GetVariable(parameterName.Name);
                if (parameter == null)
                {
                    result = new ParseErrorExpression("No value provided for " + parameterName.Name + " parameter", parameterName);
                    return(false);
                }

                parameters[i++] = parameter;
            }

            result = new FunctionCallExpression(Name.Name, parameters);
            CopyLocation(result);
            return(true);
        }
示例#2
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();
            }
        }
示例#3
0
        protected FunctionDefinitionExpression GetFunctionParameter(InterpreterScope scope, string name, out ExpressionBase parseError)
        {
            var parameter = scope.GetVariable(name);

            if (parameter == null)
            {
                parseError = new ParseErrorExpression("No value provided for " + name + " parameter");
                return(null);
            }

            var functionDefinition = parameter as FunctionDefinitionExpression;

            if (functionDefinition == null)
            {
                var functionReference = parameter as FunctionReferenceExpression;
                if (functionReference == null)
                {
                    parseError = new ParseErrorExpression(name + " must be a function reference");
                    return(null);
                }

                functionDefinition = scope.GetFunction(functionReference.Name);
                if (functionDefinition == null)
                {
                    parseError = new ParseErrorExpression("Undefined function: " + functionReference.Name);
                    return(null);
                }
            }

            parseError = null;
            return(functionDefinition);
        }
示例#4
0
        /// <summary>
        /// Gets the variable reference from the <paramref name="scope"/> or <see cref="DefaultParameters"/> collections.
        /// </summary>
        /// <param name="scope">The scope.</param>
        /// <param name="name">The name of the parameter.</param>
        /// <param name="parseError">[out] The error that occurred.</param>
        /// <returns>The variable reference, or <c>null</c> if an error occurred.</b></returns>
        protected VariableReferenceExpression GetReferenceParameter(InterpreterScope scope, string name, out ExpressionBase parseError)
        {
            var parameter = scope.GetVariable(name);

            if (parameter == null)
            {
                parseError = new ParseErrorExpression("No value provided for " + name + " parameter");
                return(null);
            }

            var typedParameter = parameter as VariableReferenceExpression;

            if (typedParameter == null)
            {
                var originalParameter = LocateParameter(scope, name);
                if (originalParameter != null)
                {
                    parameter = originalParameter;
                }

                parseError = new ParseErrorExpression(name + " is not a reference", parameter);
                return(null);
            }

            parseError = null;
            return(typedParameter);
        }
示例#5
0
        private void GetContainerIndex(InterpreterScope scope, out ExpressionBase container, out ExpressionBase index)
        {
            if (Index.Type == ExpressionType.FunctionCall)
            {
                var expression = (FunctionCallExpression)Index;
                if (!expression.ReplaceVariables(scope, out index))
                {
                    container = index;
                    return;
                }
            }
            else if (!Index.ReplaceVariables(scope, out index))
            {
                container = index;
                return;
            }

            var indexed = Variable as IndexedVariableExpression;

            if (indexed != null)
            {
                indexed.ReplaceVariables(scope, out container);
                return;
            }

            container = scope.GetVariable(Variable.Name);
            if (container == null)
            {
                container = new UnknownVariableParseErrorExpression("Unknown variable: " + Variable.Name, Variable);
                return;
            }

            var variableReference = container as VariableReferenceExpression;

            if (variableReference != null)
            {
                container = variableReference.Expression;
            }

            var array = container as ArrayExpression;

            if (array != null)
            {
                var intIndex = index as IntegerConstantExpression;
                if (intIndex == null)
                {
                    container = new ParseErrorExpression("Index does not evaluate to an integer constant", index);
                }
                else if (intIndex.Value < 0 || intIndex.Value >= array.Entries.Count)
                {
                    container = new ParseErrorExpression(String.Format("Index {0} not in range 0-{1}", intIndex.Value, array.Entries.Count - 1), index);
                }
            }
        }
示例#6
0
        /// <summary>
        /// Gets the  parameter from the <paramref name="scope"/> or <see cref="DefaultParameters"/> collections.
        /// </summary>
        /// <param name="scope">The scope.</param>
        /// <param name="name">The name of the parameter.</param>
        /// <param name="parseError">[out] The error that occurred.</param>
        /// <returns>The parameter value, or <c>null</c> if an error occurred.</b></returns>
        protected ExpressionBase GetParameter(InterpreterScope scope, string name, out ExpressionBase parseError)
        {
            var parameter = scope.GetVariable(name);

            if (parameter == null)
            {
                parseError = new ParseErrorExpression("No value provided for " + name + " parameter");
                return(null);
            }

            parseError = null;
            return(parameter);
        }
示例#7
0
        /// <summary>
        /// Replaces the variables in the expression with values from <paramref name="scope" />.
        /// </summary>
        /// <param name="scope">The scope object containing variable values.</param>
        /// <param name="result">[out] The new expression containing the replaced variables.</param>
        /// <returns>
        ///   <c>true</c> if substitution was successful, <c>false</c> if something went wrong, in which case <paramref name="result" /> will likely be a <see cref="ParseErrorExpression" />.
        /// </returns>
        public override bool ReplaceVariables(InterpreterScope scope, out ExpressionBase result)
        {
            ExpressionBase value = scope.GetVariable(Name);

            if (value == null)
            {
                var func = scope.GetFunction(Name);
                if (func != null)
                {
                    // special wrapper for returning a function as a variable
                    result = new FunctionReferenceExpression(Name);
                    result.CopyLocation(this);
                    return(true);
                }

                result = new UnknownVariableParseErrorExpression("Unknown variable: " + Name, this);
                return(false);
            }

            return(value.ReplaceVariables(scope, out result));
        }
示例#8
0
        /// <summary>
        /// Replaces the variables in the expression with values from <paramref name="scope" />.
        /// </summary>
        /// <param name="scope">The scope object containing variable values.</param>
        /// <param name="result">[out] The new expression containing the replaced variables.</param>
        /// <returns>
        ///   <c>true</c> if substitution was successful, <c>false</c> if something went wrong, in which case <paramref name="result" /> will likely be a <see cref="ParseErrorExpression" />.
        /// </returns>
        public override bool ReplaceVariables(InterpreterScope scope, out ExpressionBase result)
        {
            ExpressionBase value = scope.GetVariable(Name);

            if (value == null)
            {
                var func = scope.GetFunction(Name);
                if (func != null)
                {
                    result = new ParseErrorExpression("Function used like a variable: " + Name, this);
                }
                else
                {
                    result = new ParseErrorExpression("Unknown variable: " + Name, this);
                }

                return(false);
            }

            return(value.ReplaceVariables(scope, out result));
        }
示例#9
0
        /// <summary>
        /// Gets a parameter from the <paramref name="scope"/> or <see cref="DefaultParameters"/> collections.
        /// </summary>
        /// <param name="scope">The scope.</param>
        /// <param name="name">The name of the parameter.</param>
        /// <param name="parseError">[out] The error that occurred.</param>
        /// <returns>The parameter value, or <c>null</c> if an error occurred.</b></returns>
        protected ExpressionBase GetParameter(InterpreterScope scope, string name, out ExpressionBase parseError)
        {
            var parameter = scope.GetVariable(name);

            if (parameter == null)
            {
                parseError = new ParseErrorExpression("No value provided for " + name + " parameter");
                return(null);
            }

            parseError = null;

            // if it's a variable reference, return the referenced object.
            if (parameter.Type == ExpressionType.VariableReference)
            {
                return(((VariableReferenceExpression)parameter).Expression);
            }

            // WARNING: variable references may still exist within a varargs object
            return(parameter);
        }
示例#10
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);
        }
示例#11
0
        private bool Evaluate(InterpreterScope scope, bool inAssignment, out ExpressionBase result)
        {
            var functionDefinition = scope.GetFunction(FunctionName.Name);

            if (functionDefinition == null)
            {
                if (scope.GetVariable(FunctionName.Name) != null)
                {
                    result = new UnknownVariableParseErrorExpression(FunctionName.Name + " is not a function", FunctionName);
                }
                else
                {
                    result = new UnknownVariableParseErrorExpression("Unknown function: " + FunctionName.Name, FunctionName);
                }

                return(false);
            }

            var functionParametersScope = GetParameters(functionDefinition, scope, out result);

            if (functionParametersScope == null || result is ParseErrorExpression)
            {
                return(false);
            }

            if (functionParametersScope.Depth >= 100)
            {
                result = new ParseErrorExpression("Maximum recursion depth exceeded", this);
                return(false);
            }

            functionParametersScope.Context = this;
            if (inAssignment)
            {
                // in assignment, just replace variables
                functionDefinition.ReplaceVariables(functionParametersScope, out result);

                if (result.Type == ExpressionType.FunctionCall)
                {
                    // if the result is a function call, check for any variable references. it can't be marked
                    // as fully expanded if any variable references are present.
                    var functionCall = (FunctionCallExpression)result;
                    if (!functionCall.Parameters.Any(p => p is VariableReferenceExpression))
                    {
                        functionCall._fullyExpanded = true;
                    }

                    // if there was no change, also mark the source as fully expanded.
                    if (result == this)
                    {
                        _fullyExpanded = true;
                    }

                    // when expanding the parameters, a new functionCall object will be created without a name
                    // location. if that has happened, replace the temporary name object with the real one.
                    if (functionCall.FunctionName.Location.Start.Line == 0 && functionCall.FunctionName.Name == FunctionName.Name)
                    {
                        functionCall.FunctionName = FunctionName;
                    }
                }
            }
            else
            {
                // not in assignment, evaluate the function
                functionDefinition.Evaluate(functionParametersScope, out result);
            }

            var error = result as ParseErrorExpression;

            if (error != null)
            {
                if (error.Location.Start.Line == 0)
                {
                    this.CopyLocation(error);
                }
                result = ParseErrorExpression.WrapError(error, FunctionName.Name + " call failed", FunctionName);
                return(false);
            }

            return(true);
        }
示例#12
0
        internal DictionaryExpression.DictionaryEntry GetDictionaryEntry(InterpreterScope scope, out ExpressionBase result, bool create)
        {
            ExpressionBase index;

            if (Index.Type == ExpressionType.FunctionCall)
            {
                var expression = (FunctionCallExpression)Index;
                if (!expression.ReplaceVariables(scope, out index))
                {
                    result = index;
                    return(null);
                }
            }
            else if (!Index.ReplaceVariables(scope, out index))
            {
                result = index;
                return(null);
            }

            ExpressionBase value;
            var            indexed = Variable as IndexedVariableExpression;

            if (indexed != null)
            {
                var entry = indexed.GetDictionaryEntry(scope, out result, create);
                if (entry == null)
                {
                    return(null);
                }

                value = entry.Value;
            }
            else
            {
                var variable = Variable as VariableExpression;
                if (variable != null)
                {
                    value = scope.GetVariable(variable.Name);

                    if (value == null)
                    {
                        result = new ParseErrorExpression("Unknown variable: " + variable.Name, variable);
                        return(null);
                    }
                }
                else if (!Variable.ReplaceVariables(scope, out value))
                {
                    result = value;
                    return(null);
                }
            }

            var dict = value as DictionaryExpression;

            if (dict != null)
            {
                var entry = dict.Entries.FirstOrDefault(e => Object.Equals(e.Key, index));
                if (entry != null)
                {
                    result = dict;
                    return(entry);
                }

                if (create)
                {
                    entry = new DictionaryExpression.DictionaryEntry {
                        Key = index
                    };
                    dict.Entries.Add(entry);
                    result = dict;
                    return(entry);
                }

                var builder = new StringBuilder();
                builder.Append("No entry in dictionary for key: ");
                index.AppendString(builder);
                result = new ParseErrorExpression(builder.ToString(), Index);
            }
            else
            {
                var array = value as ArrayExpression;
                if (array != null)
                {
                    var intIndex = index as IntegerConstantExpression;
                    if (intIndex == null)
                    {
                        result = new ParseErrorExpression("Index does not evaluate to an integer constant", index);
                    }
                    else if (intIndex.Value < 0 || intIndex.Value >= array.Entries.Count)
                    {
                        result = new ParseErrorExpression(String.Format("Index {0} not in range 0-{1}", intIndex.Value, array.Entries.Count - 1), index);
                    }
                    else
                    {
                        result = array;
                        return(new ArrayDictionaryEntryWrapper {
                            Array = array, Key = index, Value = array.Entries[intIndex.Value]
                        });
                    }
                }
                else
                {
                    var builder = new StringBuilder();
                    builder.Append("Cannot index: ");
                    Variable.AppendString(builder);
                    builder.Append(" (");
                    builder.Append(value.Type);
                    builder.Append(')');
                    result = new ParseErrorExpression(builder.ToString(), Variable);
                }
            }

            return(null);
        }