예제 #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)
        {
            var expressionScope = new InterpreterScope(scope)
            {
                Context = this
            };
            ExpressionBase value;

            if (!Value.ReplaceVariables(expressionScope, out value))
            {
                result = value;
                return(false);
            }

            result = new AssignmentExpression(Variable, value);
            CopyLocation(result);
            return(true);
        }
예제 #2
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);
                }
            }
        }
예제 #3
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;

            if (!Value.ReplaceVariables(scope, out value))
            {
                result = value;
                return(false);
            }

            result = new ReturnExpression(value);
            CopyLocation(result);
            return(true);
        }
예제 #4
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));
        }
예제 #5
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));
        }
예제 #6
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);
        }
예제 #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)
        {
            if (_fullyExpanded)
            {
                result = this;
                return(true);
            }

            bool hasTrue   = false;
            bool hasFalse  = false;
            bool isChanged = false;

            var updatedConditions = new List <ExpressionBase>(_conditions.Count);

            for (int i = 0; i < _conditions.Count; ++i)
            {
                if (!_conditions[i].ReplaceVariables(scope, out result))
                {
                    return(false);
                }

                // can eliminate true/false now, but not things that evaluate to true/false.
                // (like always_true or always_false) as those may be used to generate explicit alt groups.
                var booleanExpression = result as BooleanConstantExpression;
                if (booleanExpression != null)
                {
                    if (booleanExpression.Value)
                    {
                        hasTrue = true;

                        if (Operation == ConditionalOperation.And)
                        {
                            isChanged = true;
                            continue;
                        }
                    }
                    else
                    {
                        hasFalse = true;

                        if (Operation == ConditionalOperation.Or)
                        {
                            isChanged = true;
                            continue;
                        }
                    }
                }

                isChanged |= !ReferenceEquals(result, _conditions[i]);
                updatedConditions.Add(result);
            }

            bool?logicalResult = null;

            switch (Operation)
            {
            case ConditionalOperation.Not:
                if (hasTrue)
                {
                    logicalResult = false;
                }
                else if (hasFalse)
                {
                    logicalResult = true;
                }
                else
                {
                    result = InvertExpression(updatedConditions[0]);
                    if (result.Type == ExpressionType.ParseError)
                    {
                        return(false);
                    }

                    CopyLocation(result);

                    // InvertExpression may distribute Nots to subnodes, recurse
                    return(result.ReplaceVariables(scope, out result));
                }
                break;

            case ConditionalOperation.Or:
                if (hasTrue)
                {
                    // anything or true is true
                    logicalResult = true;
                }
                else if (hasFalse && updatedConditions.Count == 0)
                {
                    // all conditions were false, entire condition is false
                    logicalResult = false;
                }
                break;

            case ConditionalOperation.And:
                if (hasFalse)
                {
                    // anything and false is false
                    logicalResult = false;
                }
                if (hasTrue && updatedConditions.Count == 0)
                {
                    // all conditions were true, entire condition is true
                    logicalResult = true;
                }
                break;
            }

            if (logicalResult == true)
            {
                result = new BooleanConstantExpression(true);
            }
            else if (logicalResult == false)
            {
                result = new BooleanConstantExpression(false);
            }
            else
            {
                // merge with nested logic when possible
                for (int i = updatedConditions.Count - 1; i >= 0; i--)
                {
                    var conditionalExpression = updatedConditions[i] as ConditionalExpression;
                    if (conditionalExpression != null && conditionalExpression.Operation == Operation)
                    {
                        updatedConditions.RemoveAt(i);
                        updatedConditions.InsertRange(i, conditionalExpression._conditions);
                        isChanged = true;
                    }
                }

                if (!isChanged)
                {
                    _fullyExpanded = true;
                    result         = this;
                    return(true);
                }
                else
                {
                    var newConditionalExpression = new ConditionalExpression(Operation, updatedConditions);
                    newConditionalExpression._fullyExpanded = true;
                    result = newConditionalExpression;
                }
            }

            CopyLocation(result);
            return(true);
        }