private static bool MergeModulus(ExpressionBase left, ExpressionBase right, out ExpressionBase result)
        {
            // if either side is a float, convert both to float
            if (left.Type == ExpressionType.FloatConstant || right.Type == ExpressionType.FloatConstant)
            {
                if (!ConvertToFloat(ref left, ref right, out result))
                {
                    return(false);
                }

                if (((FloatConstantExpression)right).Value == 0.0)
                {
                    result = new ParseErrorExpression("Division by zero");
                    return(false);
                }

                result = new FloatConstantExpression(((FloatConstantExpression)left).Value % ((FloatConstantExpression)right).Value);
                return(true);
            }

            if (left.Type == ExpressionType.IntegerConstant && right.Type == ExpressionType.IntegerConstant)
            {
                if (((IntegerConstantExpression)right).Value == 0)
                {
                    result = new ParseErrorExpression("Division by zero");
                    return(false);
                }

                result = new IntegerConstantExpression(((IntegerConstantExpression)left).Value % ((IntegerConstantExpression)right).Value);
                return(true);
            }

            result = new ParseErrorExpression("Cannot modulus expressions");
            return(false);
        }
        private static bool MergeAddition(ExpressionBase left, ExpressionBase right, out ExpressionBase result)
        {
            // if either side is a string, combine to a larger string
            if (left.Type == ExpressionType.StringConstant || right.Type == ExpressionType.StringConstant)
            {
                var builder = new StringBuilder();
                left.AppendStringLiteral(builder);
                right.AppendStringLiteral(builder);

                result = new StringConstantExpression(builder.ToString());
                return(true);
            }

            // if either side is a float, convert both to float
            if (left.Type == ExpressionType.FloatConstant || right.Type == ExpressionType.FloatConstant)
            {
                if (!ConvertToFloat(ref left, ref right, out result))
                {
                    return(false);
                }

                result = new FloatConstantExpression(((FloatConstantExpression)left).Value + ((FloatConstantExpression)right).Value);
                return(true);
            }

            if (left.Type == ExpressionType.IntegerConstant && right.Type == ExpressionType.IntegerConstant)
            {
                result = new IntegerConstantExpression(((IntegerConstantExpression)left).Value + ((IntegerConstantExpression)right).Value);
                return(true);
            }

            result = new ParseErrorExpression("Cannot add expressions");
            return(false);
        }
Exemple #3
0
        protected static bool ConvertToFloat(ref ExpressionBase left, ref ExpressionBase right, out ExpressionBase result)
        {
            left = FloatConstantExpression.ConvertFrom(left);
            if (left.Type != ExpressionType.FloatConstant)
            {
                result = left;
                return(false);
            }

            right = FloatConstantExpression.ConvertFrom(right);
            if (right.Type != ExpressionType.FloatConstant)
            {
                result = right;
                return(false);
            }

            result = null;
            return(true);
        }
        private static bool IsMultiple(ExpressionBase left, ExpressionBase right)
        {
            var leftInteger  = left as IntegerConstantExpression;
            var rightInteger = right as IntegerConstantExpression;

            if (leftInteger != null && rightInteger != null)
            {
                return((leftInteger.Value % rightInteger.Value) == 0);
            }

            var leftFloat  = FloatConstantExpression.ConvertFrom(left) as FloatConstantExpression;
            var rightFloat = FloatConstantExpression.ConvertFrom(right) as FloatConstantExpression;

            if (leftFloat == null || rightFloat == null)
            {
                return(false);
            }

            return((leftFloat.Value % rightFloat.Value) == 0.0f);
        }
        /// <summary>
        /// Attempts to convert an expression to a <see cref="FloatConstantExpression"/>.
        /// </summary>
        /// <param name="expression">The expression to convert.</param>
        /// <returns>The converted expression, or a <see cref="ParseErrorExpression"/> if the expression could not be converted.</returns>
        public static ExpressionBase ConvertFrom(ExpressionBase expression)
        {
            FloatConstantExpression floatExpression;

            switch (expression.Type)
            {
            case ExpressionType.FloatConstant:
                return(expression);

            case ExpressionType.IntegerConstant:
                floatExpression = new FloatConstantExpression((float)((IntegerConstantExpression)expression).Value);
                break;

            default:
                return(new ParseErrorExpression("Cannot convert to float", expression));
            }

            expression.CopyLocation(floatExpression);
            return(floatExpression);
        }
        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));
        }
Exemple #7
0
        private static ExpressionBase ParseClauseCore(PositionalTokenizer tokenizer)
        {
            ExpressionBase clause;

            switch (tokenizer.NextChar)
            {
            case '!':
                tokenizer.Advance();
                clause = ParseClause(tokenizer);
                if (clause.Type == ExpressionType.ParseError)
                {
                    return(clause);
                }

                return(new ConditionalExpression(null, ConditionalOperation.Not, clause));

            case '(':
                if (AnonymousUserFunctionDefinitionExpression.IsAnonymousParameterList(tokenizer))
                {
                    return(AnonymousUserFunctionDefinitionExpression.ParseAnonymous(tokenizer));
                }

                tokenizer.Advance();
                clause = ExpressionBase.Parse(tokenizer);
                if (clause.Type == ExpressionType.ParseError)
                {
                    return(clause);
                }

                if (tokenizer.NextChar != ')')
                {
                    if (tokenizer.NextChar == '\0')
                    {
                        return(ParseError(tokenizer, "No closing parenthesis found"));
                    }

                    return(ParseError(tokenizer, "Expected closing parenthesis, found: " + tokenizer.NextChar));
                }

                clause.IsLogicalUnit = true;
                tokenizer.Advance();

                return(clause);

            case '"':
                try
                {
                    var stringValue = tokenizer.ReadQuotedString().ToString();
                    return(new StringConstantExpression(stringValue));
                }
                catch (InvalidOperationException ex)
                {
                    return(ParseError(tokenizer, ex.Message));
                }

            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                return(ParseNumber(tokenizer, true));

            case '-':
                var tokenStart = tokenizer.Location;
                tokenizer.Advance();
                if (tokenizer.NextChar >= '0' && tokenizer.NextChar <= '9')
                {
                    var result   = ParseNumber(tokenizer, false);
                    var tokenEnd = result.Location.End;
                    switch (result.Type)
                    {
                    case ExpressionType.IntegerConstant:
                        result = new IntegerConstantExpression(-((IntegerConstantExpression)result).Value);
                        break;

                    case ExpressionType.FloatConstant:
                        result = new FloatConstantExpression(-((FloatConstantExpression)result).Value);
                        break;

                    default:
                        return(result);
                    }

                    result.Location = new TextRange(tokenStart, tokenEnd);
                    return(result);
                }
                return(ParseError(tokenizer, "Minus without value", tokenStart.Line, tokenStart.Column));

            case '{':
                tokenizer.Advance();
                return(DictionaryExpression.Parse(tokenizer));

            case '[':
                tokenizer.Advance();
                return(ParseArray(tokenizer));

            default:
                var line       = tokenizer.Line;
                var column     = tokenizer.Column;
                var identifier = tokenizer.ReadIdentifier();
                if (identifier.IsEmpty)
                {
                    var error = ParseError(tokenizer, "Unexpected character: " + tokenizer.NextChar);
                    tokenizer.Advance();
                    return(error);
                }

                SkipWhitespace(tokenizer);

                if (identifier == "return")
                {
                    clause = ExpressionBase.Parse(tokenizer);
                    if (clause.Type == ExpressionType.ParseError)
                    {
                        return(clause);
                    }

                    return(new ReturnExpression(new KeywordExpression(identifier.ToString(), line, column), clause));
                }

                if (identifier == "function")
                {
                    return(UserFunctionDefinitionExpression.Parse(tokenizer, line, column));
                }
                if (identifier == "for")
                {
                    return(ForExpression.Parse(tokenizer, line, column));
                }
                if (identifier == "if")
                {
                    return(IfExpression.Parse(tokenizer, line, column));
                }

                if (identifier == "true")
                {
                    return(new BooleanConstantExpression(true, line, column));
                }
                if (identifier == "false")
                {
                    return(new BooleanConstantExpression(false, line, column));
                }

                if (tokenizer.NextChar == '(')
                {
                    tokenizer.Advance();

                    var parameters = new List <ExpressionBase>();
                    ParseParameters(tokenizer, parameters);

                    var functionCall = new FunctionCallExpression(new FunctionNameExpression(identifier.ToString(), line, column), parameters);
                    functionCall.Location = new TextRange(line, column, tokenizer.Line, tokenizer.Column - 1);
                    return(functionCall);
                }

                if (tokenizer.NextChar == '[')
                {
                    IndexedVariableExpression parent = null;

                    do
                    {
                        tokenizer.Advance();

                        var index = ExpressionBase.Parse(tokenizer);
                        if (index.Type == ExpressionType.ParseError)
                        {
                            return(index);
                        }

                        SkipWhitespace(tokenizer);
                        if (tokenizer.NextChar != ']')
                        {
                            return(ParseError(tokenizer, "Expecting closing bracket after index"));
                        }
                        tokenizer.Advance();
                        SkipWhitespace(tokenizer);

                        if (parent != null)
                        {
                            parent = new IndexedVariableExpression(parent, index);
                        }
                        else
                        {
                            parent = new IndexedVariableExpression(new VariableExpression(identifier.ToString(), line, column), index);
                        }
                    } while (tokenizer.NextChar == '[');

                    return(parent);
                }

                return(new VariableExpression(identifier.ToString(), line, column));
            }
        }
Exemple #8
0
        private static ExpressionBase ParseNumber(PositionalTokenizer tokenizer, bool isUnsigned)
        {
            int    line      = tokenizer.Line;
            int    column    = tokenizer.Column;
            int    endLine   = line;
            int    endColumn = column;
            uint   value;
            string number = "";

            if (tokenizer.Match("0x"))
            {
                while (Char.IsDigit(tokenizer.NextChar) || (tokenizer.NextChar >= 'A' && tokenizer.NextChar <= 'F') || (tokenizer.NextChar >= 'a' && tokenizer.NextChar <= 'f'))
                {
                    number += tokenizer.NextChar;

                    endLine   = tokenizer.Line;
                    endColumn = tokenizer.Column;
                    tokenizer.Advance();
                }

                if (!UInt32.TryParse(number, System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.CurrentCulture, out value))
                {
                    return(new ParseErrorExpression("Number too large"));
                }
            }
            else
            {
                while (Char.IsDigit(tokenizer.NextChar))
                {
                    number += tokenizer.NextChar;

                    endLine   = tokenizer.Line;
                    endColumn = tokenizer.Column;
                    tokenizer.Advance();
                }

                if (tokenizer.NextChar == '.')
                {
                    number += tokenizer.NextChar;
                    tokenizer.Advance();

                    while (Char.IsDigit(tokenizer.NextChar))
                    {
                        number += tokenizer.NextChar;

                        endLine   = tokenizer.Line;
                        endColumn = tokenizer.Column;
                        tokenizer.Advance();
                    }

                    float floatValue;
                    if (!float.TryParse(number, System.Globalization.NumberStyles.AllowDecimalPoint, System.Globalization.CultureInfo.InvariantCulture, out floatValue))
                    {
                        return(new ParseErrorExpression("Number too large"));
                    }

                    var floatExpression = new FloatConstantExpression(floatValue);
                    floatExpression.Location = new TextRange(line, column, endLine, endColumn);
                    return(floatExpression);
                }

                if (!UInt32.TryParse(number, out value))
                {
                    return(new ParseErrorExpression("Number too large"));
                }
            }

            if (value > Int32.MaxValue && !isUnsigned)
            {
                return(new ParseErrorExpression("Number too large"));
            }

            var integerExpression = new IntegerConstantExpression((int)value);

            integerExpression.Location = new TextRange(line, column, endLine, endColumn);
            return(integerExpression);
        }