示例#1
0
        /// <summary>
        /// Rebalances this expression based on the precendence of operators.
        /// </summary>
        internal override ExpressionBase Rebalance()
        {
            if (!Right.IsLogicalUnit)
            {
                var mathematicRight = Right as MathematicExpression;
                if (mathematicRight != null && !(Left is StringConstantExpression))
                {
                    // multiply and divide should happen before add or subtract.
                    // at the same priority, they should happen left-to-right.
                    if (GetPriority(Operation) >= GetPriority(mathematicRight.Operation))
                    {
                        var newLeft = new MathematicExpression(Left, Operation, mathematicRight.Left);
                        newLeft = newLeft.Rebalance() as MathematicExpression;
                        return(new MathematicExpression(newLeft, mathematicRight.Operation, mathematicRight.Right));
                    }
                }

                var comparisonRight = Right as ComparisonExpression;
                if (comparisonRight != null)
                {
                    return(Rebalance(comparisonRight));
                }

                var conditionalRight = Right as ConditionalExpression;
                if (conditionalRight != null)
                {
                    return(Rebalance(conditionalRight));
                }
            }

            return(base.Rebalance());
        }
示例#2
0
 /// <summary>
 /// Reverses application of the specified operation and amount to the provided <paramref name="value"/>.
 /// </summary>
 /// <param name="value">The value to modify.</param>
 /// <returns>The modified value.</returns>
 public int Remove(int value)
 {
     return(Apply(value, MathematicExpression.GetOppositeOperation(Operation), Amount));
 }
示例#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 left;

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

            ExpressionBase right;

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

            var integerLeft  = left as IntegerConstantExpression;
            var integerRight = right as IntegerConstantExpression;

            switch (Operation)
            {
            case MathematicOperation.Add:
                var stringLeft  = left as StringConstantExpression;
                var stringRight = right as StringConstantExpression;
                if (stringLeft != null)
                {
                    if (stringRight != null)
                    {
                        result = new StringConstantExpression(stringLeft.Value + stringRight.Value);
                        return(true);
                    }

                    if (integerRight != null)
                    {
                        result = new StringConstantExpression(stringLeft.Value + integerRight.Value.ToString());
                        return(true);
                    }
                }
                else if (stringRight != null)
                {
                    if (integerLeft != null)
                    {
                        result = new StringConstantExpression(integerLeft.Value.ToString() + stringRight.Value);
                        return(true);
                    }
                }

                // prefer constants on right
                if (integerLeft != null && integerRight == null)
                {
                    var temp = left;
                    left         = right;
                    right        = temp;
                    integerRight = integerLeft;
                    integerLeft  = null;
                }

                if (integerRight != null)
                {
                    if (integerRight.Value == 0)     // anything plus 0 is itself
                    {
                        result = left;
                        return(true);
                    }

                    if (integerLeft != null)
                    {
                        result = new IntegerConstantExpression(integerLeft.Value + integerRight.Value);
                        return(true);
                    }
                }
                break;

            case MathematicOperation.Subtract:
                if (integerRight != null)
                {
                    if (integerRight.Value == 0)     // anything minus 0 is itself
                    {
                        result = left;
                        return(true);
                    }

                    if (integerLeft != null)
                    {
                        result = new IntegerConstantExpression(integerLeft.Value - integerRight.Value);
                        return(true);
                    }
                }

                break;

            case MathematicOperation.Multiply:
                // prefer constants on right
                if (integerLeft != null && integerRight == null)
                {
                    var temp = left;
                    left         = right;
                    right        = temp;
                    integerRight = integerLeft;
                    integerLeft  = null;
                }

                if (integerRight != null)
                {
                    if (integerRight.Value == 0)     // anything times 0 is 0
                    {
                        result = right;
                        return(true);
                    }

                    if (integerRight.Value == 1)     // anything times 1 is itself
                    {
                        result = left;
                        return(true);
                    }

                    if (integerLeft != null)
                    {
                        result = new IntegerConstantExpression(integerLeft.Value * integerRight.Value);
                        return(true);
                    }
                }
                break;

            case MathematicOperation.Divide:
                if (integerRight != null)
                {
                    if (integerRight.Value == 0)     // division by 0 is impossible
                    {
                        result = new ParseErrorExpression("division by zero", this);
                        return(false);
                    }

                    if (integerRight.Value == 1)     // anything divided by 1 is itself
                    {
                        result = left;
                        return(true);
                    }

                    if (integerLeft != null)
                    {
                        result = new IntegerConstantExpression(integerLeft.Value / integerRight.Value);
                        return(true);
                    }
                }
                break;

            case MathematicOperation.Modulus:
                if (integerRight != null)
                {
                    if (integerRight.Value == 0)     // division by 0 is impossible
                    {
                        result = new ParseErrorExpression("division by zero", this);
                        return(false);
                    }

                    if (integerRight.Value == 1)     // anything modulus 1 is 0
                    {
                        result = new IntegerConstantExpression(0);
                        return(true);
                    }

                    if (integerLeft != null)
                    {
                        result = new IntegerConstantExpression(integerLeft.Value % integerRight.Value);
                        return(true);
                    }
                }
                break;
            }

            var mathematic = new MathematicExpression(left, Operation, right);

            mathematic.Line   = Line;
            mathematic.Column = Column;
            result            = mathematic;
            return(true);
        }
示例#4
0
        /// <summary>
        /// Moves the IntegerConstant (if present) to be the Right operand of the root node.
        /// </summary>
        /// <remarks>Combines nodes where possible.</remarks>
        internal static MathematicExpression BubbleUpIntegerConstant(MathematicExpression mathematic)
        {
            var priority = GetPriority(mathematic.Operation);

            var mathematicLeft = mathematic.Left as MathematicExpression;

            if (mathematicLeft != null)
            {
                if (GetPriority(mathematicLeft.Operation) == priority)
                {
                    mathematic.Left = mathematicLeft = BubbleUpIntegerConstant(mathematicLeft);
                    if (mathematicLeft.Right is IntegerConstantExpression)
                    {
                        if (mathematic.Right is IntegerConstantExpression)
                        {
                            return(mathematic);
                        }

                        mathematic.Left     = mathematicLeft.Left;
                        mathematicLeft.Left = BubbleUpIntegerConstant(mathematic);
                        mathematic          = mathematicLeft;
                    }
                }
            }

            var mathematicRight = mathematic.Right as MathematicExpression;

            if (mathematicRight != null)
            {
                if (GetPriority(mathematicRight.Operation) == priority)
                {
                    mathematic.Right = mathematicRight = BubbleUpIntegerConstant(mathematicRight);
                    if (mathematicRight.Right is IntegerConstantExpression)
                    {
                        if (mathematic.Operation == MathematicOperation.Add)
                        {
                            mathematic.Right     = mathematicRight.Left;
                            mathematicRight.Left = BubbleUpIntegerConstant(mathematic);
                            mathematic           = mathematicRight;
                        }
                        else if (mathematic.Operation == MathematicOperation.Subtract)
                        {
                            mathematic.Right      = mathematicRight.Left;
                            mathematicRight.Left  = BubbleUpIntegerConstant(mathematic);
                            mathematicRight.Right = new IntegerConstantExpression(-((IntegerConstantExpression)mathematicRight.Right).Value);
                            mathematic            = mathematicRight;
                        }
                    }
                }
            }

            if (mathematic.Right is IntegerConstantExpression)
            {
                mathematicLeft = mathematic.Left as MathematicExpression;
                if (mathematicLeft != null && GetPriority(mathematicLeft.Operation) == priority &&
                    mathematicLeft.Right is IntegerConstantExpression)
                {
                    ExpressionBase result;

                    mathematic.Left = mathematicLeft.Right;
                    if (MergeOperands(mathematic.Left, mathematic.Operation, mathematic.Right, out result))
                    {
                        mathematicLeft.Right = result;

                        if (MergeOperands(mathematicLeft.Left, mathematicLeft.Operation, mathematicLeft.Right, out result))
                        {
                            mathematicLeft = (MathematicExpression)result;
                        }

                        mathematic = mathematicLeft;
                    }
                }
            }

            var integer = mathematic.Left as IntegerConstantExpression;

            if (integer != null)
            {
                switch (mathematic.Operation)
                {
                case MathematicOperation.Add:
                case MathematicOperation.Multiply:
                    // switch the order so the constant is on the right
                    mathematic = new MathematicExpression(mathematic.Right, mathematic.Operation, mathematic.Left);
                    break;

                case MathematicOperation.Subtract:
                    if (integer.Value == 0)
                    {
                        break;
                    }

                    // change "N - func" to "0 - func + N" so N is on the right. the 0 will be optimized out later
                    mathematic = new MathematicExpression(
                        new MathematicExpression(new IntegerConstantExpression(0), MathematicOperation.Subtract, mathematic.Right),
                        MathematicOperation.Add,
                        integer);
                    break;

                default:
                    break;
                }
            }

            return(mathematic);
        }
示例#5
0
        private static bool MergeNonConstantMathematic(MathematicExpression mathematicLeft, MathematicOperation operation, ExpressionBase right, out ExpressionBase result)
        {
            var left = mathematicLeft.Right;

            result = null;

            var            newLeft      = mathematicLeft.Left;
            var            newOperation = mathematicLeft.Operation;
            ExpressionBase newRight;

            switch (mathematicLeft.Operation)
            {
            case MathematicOperation.Add:
                if (operation == MathematicOperation.Add)
                {
                    // (a + 3) + 2 => a + (3 + 2)
                    if (!MergeAddition(left, right, out newRight))
                    {
                        result = newRight;
                        return(false);
                    }
                }
                else if (operation == MathematicOperation.Subtract)
                {
                    if (IsGreater(left, right))
                    {
                        // (a + 3) - 2 => a + (3 - 2)
                        if (!MergeSubtraction(left, right, out newRight))
                        {
                            result = newRight;
                            return(false);
                        }
                    }
                    else
                    {
                        // (a + 2) - 3 => a - (3 - 2)
                        if (!MergeSubtraction(right, left, out newRight))
                        {
                            result = newRight;
                            return(false);
                        }

                        newOperation = MathematicOperation.Subtract;
                    }
                }
                else
                {
                    return(false);
                }
                break;

            case MathematicOperation.Subtract:
                if (operation == MathematicOperation.Add)
                {
                    if (IsGreater(left, right))
                    {
                        // (a - 3) + 2 => a - (3 - 2)
                        if (!MergeSubtraction(left, right, out newRight))
                        {
                            result = newRight;
                            return(false);
                        }
                    }
                    else
                    {
                        // (a - 2) + 3 => a + (3 - 2)
                        if (!MergeSubtraction(right, left, out newRight))
                        {
                            result = newRight;
                            return(false);
                        }

                        newOperation = MathematicOperation.Add;
                    }
                }
                else if (operation == MathematicOperation.Subtract)
                {
                    // (a - 3) - 2 => a - (3 + 2)
                    if (!MergeAddition(left, right, out newRight))
                    {
                        result = newRight;
                        return(false);
                    }
                }
                else
                {
                    return(false);
                }
                break;

            case MathematicOperation.Multiply:
                switch (operation)
                {
                case MathematicOperation.Multiply:
                    // (a * 3) * 2 => a * (3 * 2)
                    if (!MergeMultiplication(left, right, out newRight))
                    {
                        result = newRight;
                        return(false);
                    }
                    break;

                case MathematicOperation.Divide:
                    if (left.Type == ExpressionType.FloatConstant)
                    {
                        right = FloatConstantExpression.ConvertFrom(right);
                        if (right.Type == ExpressionType.ParseError)
                        {
                            return(false);
                        }
                    }
                    else if (right.Type == ExpressionType.FloatConstant)
                    {
                        left = FloatConstantExpression.ConvertFrom(left);
                        if (left.Type == ExpressionType.ParseError)
                        {
                            return(false);
                        }
                    }
                    else
                    {
                        // (a * 8) / 4 => a * (8 / 4) => a * 2

                        // can only merge these if the constant on the left is a multiple of the constant on the right
                        if (!IsMultiple(left, right))
                        {
                            return(false);
                        }
                    }

                    if (!MergeDivision(left, right, out newRight))
                    {
                        result = newRight;
                        return(false);
                    }
                    break;

                case MathematicOperation.Modulus:
                    // (a * 8) % 4 => a % 4
                    // can only merge these if the constant on the left is a multiple of the constant on the right
                    if (!IsMultiple(left, right))
                    {
                        return(false);
                    }

                    newRight     = right;
                    newOperation = MathematicOperation.Modulus;
                    break;

                default:
                    return(false);
                }
                break;

            case MathematicOperation.Divide:
                if (operation == MathematicOperation.Divide)
                {
                    // (a / 3) / 2 => a / (3 * 2)
                    var multiplication = new MathematicExpression(left, MathematicOperation.Multiply, right);
                    if (!MergeMultiplication(left, right, out newRight))
                    {
                        result = newRight;
                        return(false);
                    }
                }
                else if (operation == MathematicOperation.Multiply)
                {
                    if (left.Type == ExpressionType.FloatConstant || right.Type == ExpressionType.FloatConstant)
                    {
                        // (a / 3.0) * 2.0 => a * (2.0 / 3.0)
                        if (!MergeDivision(right, left, out newRight))
                        {
                            result = newRight;
                            return(false);
                        }

                        newOperation = MathematicOperation.Multiply;
                    }
                    else
                    {
                        // (a / 3) * 2 => a * (2 / 3)

                        // when integer division is performed first, the result may be floored before applying
                        // the multiplication, so don't automatically merge them.
                        return(false);
                    }
                }
                else
                {
                    return(false);
                }
                break;

            case MathematicOperation.BitwiseAnd:
                // (a & 12) & 5 => a & (12 & 5)
                if (operation != MathematicOperation.BitwiseAnd)
                {
                    return(false);
                }

                if (!MergeBitwiseAnd(left, right, out newRight))
                {
                    result = newRight;
                    return(false);
                }
                break;

            default:
                return(false);
            }

            return(MergeOperands(newLeft, newOperation, newRight, out result));
        }
示例#6
0
        private static bool MergeOperands(ExpressionBase left, MathematicOperation operation, ExpressionBase right, out ExpressionBase result)
        {
            // ASSERT: expression tree has already been rebalanced and variables have been replaced

            if (!left.IsLiteralConstant)
            {
                // cannot combine non-constant, leave as is.
                if (right.IsLiteralConstant)
                {
                    // attempt to merge the right constant into the left mathematic expression
                    var mathematicLeft = left as MathematicExpression;
                    if (mathematicLeft != null && MergeNonConstantMathematic(mathematicLeft, operation, right, out result))
                    {
                        return(true);
                    }

                    // attempt to eliminate the right constant
                    if (MergeIdentity(left, operation, right, out result))
                    {
                        return(true);
                    }

                    if (result is ParseErrorExpression)
                    {
                        return(false);
                    }
                }
            }
            else if (!right.IsLiteralConstant)
            {
                // cannot combine non-constant. when possible, prefer constants on the right.
                switch (operation)
                {
                case MathematicOperation.Add:
                case MathematicOperation.Multiply:
                    if (MergeIdentity(right, operation, left, out result))
                    {
                        return(true);
                    }

                    if (result is ParseErrorExpression)
                    {
                        return(false);
                    }

                    var temp = left;
                    left  = right;
                    right = temp;
                    break;

                default:
                    // cannot swap
                    break;
                }
            }
            else
            {
                switch (operation)
                {
                case MathematicOperation.Add:
                    return(MergeAddition(left, right, out result));

                case MathematicOperation.Subtract:
                    return(MergeSubtraction(left, right, out result));

                case MathematicOperation.Multiply:
                    return(MergeMultiplication(left, right, out result));

                case MathematicOperation.Divide:
                    return(MergeDivision(left, right, out result));

                case MathematicOperation.Modulus:
                    return(MergeModulus(left, right, out result));

                case MathematicOperation.BitwiseAnd:
                    return(MergeBitwiseAnd(left, right, out result));
                }
            }

            result = new MathematicExpression(left, operation, right);
            return(true);
        }
示例#7
0
        private static ExpressionBase ParseMathematic(PositionalTokenizer tokenizer, ExpressionBase left, MathematicOperation operation, int joinerLine, int joinerColumn)
        {
            OperationPriority priority;

            switch (operation)
            {
            case MathematicOperation.Add:
                if (left is StringConstantExpression)
                {
                    priority = OperationPriority.AppendString;
                    break;
                }
                priority = OperationPriority.AddSubtract;
                break;

            case MathematicOperation.Subtract:
                priority = OperationPriority.AddSubtract;
                break;

            case MathematicOperation.Multiply:
            case MathematicOperation.Divide:
            case MathematicOperation.Modulus:
                priority = OperationPriority.MulDivMod;
                break;

            case MathematicOperation.BitwiseAnd:
                priority = OperationPriority.BitwiseAnd;
                break;

            default:
                return(new ParseErrorExpression("Unknown operator: " + operation));
            }

            var right = ParseExpression(tokenizer, priority);

            switch (right.Type)
            {
            case ExpressionType.ParseError:
                return(right);

            case ExpressionType.Comparison:     // will be rebalanced
            case ExpressionType.Conditional:    // will be rebalanced
            case ExpressionType.FloatConstant:
            case ExpressionType.FunctionCall:
            case ExpressionType.IntegerConstant:
            case ExpressionType.Mathematic:
            case ExpressionType.StringConstant:
            case ExpressionType.Variable:
                break;

            default:
                var expressionTokenizer = tokenizer as ExpressionTokenizer;
                if (expressionTokenizer != null)
                {
                    expressionTokenizer.QueueExpression(right);
                }

                right = new KeywordExpression(MathematicExpression.GetOperatorCharacter(operation).ToString(), joinerLine, joinerColumn);
                return(ParseError(tokenizer, "Incompatible mathematical operation", right));
            }

            if (priority == OperationPriority.AddSubtract)
            {
                var mathematicRight = right as MathematicExpression;
            }

            return(new MathematicExpression(left, operation, right));
        }
示例#8
0
        private static ExpressionBase ParseMathematic(PositionalTokenizer tokenizer, ExpressionBase left, MathematicOperation operation, int joinerLine, int joinerColumn)
        {
            var right = ExpressionBase.Parse(tokenizer);

            switch (right.Type)
            {
            case ExpressionType.ParseError:
                return(right);

            case ExpressionType.Comparison:
            case ExpressionType.Conditional:
            case ExpressionType.Dictionary:
            case ExpressionType.FunctionCall:
            case ExpressionType.IntegerConstant:
            case ExpressionType.Mathematic:
            case ExpressionType.StringConstant:
            case ExpressionType.Variable:
                break;

            default:
                ParseError(tokenizer, "incompatible mathematical operation", new KeywordExpression(MathematicExpression.GetOperatorCharacter(operation).ToString(), joinerLine, joinerColumn));
                break;
            }

            return(new MathematicExpression(left, operation, right));
        }