Example #1
0
        /// <summary>
        /// Evaluates this node and all its children
        /// </summary>
        /// <param name="scope">The scope of this expression</param>
        /// <returns></returns>
        public override Expression Evaluate(Scope scope)
        {
            // Evaluate operands
            leftOperand = leftOperand.Evaluate(scope);
            rightOperand = rightOperand.Evaluate(scope);

            // Check if both operands are of the same type
            if (leftOperand.returnType.ToCLRType() != rightOperand.returnType.ToCLRType())
            {
                // If not, check if left operand can be implicitely typecasted to right operand type
                if (leftOperand.returnType.IsCompatible(rightOperand.returnType))
                {
                    // Create implicit cast
                    CastExpression implicitCast = new CastExpression(rightOperand.returnType);
                    implicitCast.operand = leftOperand;

                    // Evaluate typecast for folding
                    this.leftOperand = implicitCast.Evaluate(scope);

                    // Set return type
                    this.returnType = rightOperand.returnType;
                }
                // If not, check if right operand can be implicitely typecasted to left operand type
                else if (rightOperand.returnType.IsCompatible(leftOperand.returnType))
                {
                    // Create implicit cast
                    CastExpression implicitCast = new CastExpression(leftOperand.returnType);
                    implicitCast.operand = rightOperand;

                    // Evaluate for folding
                    this.rightOperand = implicitCast.Evaluate(scope);

                    // Set return type
                    this.returnType = leftOperand.returnType;
                }
                else
                {
                    // Types are incompatible - issue error
                    Compiler.Compiler.errors.SemErr(t.line, t.col, "Incompatible types");
                    this.returnType = PrimitiveType.UNSUPPORTED;
                    return this;
                }
            }
            // If operands are of the same type
            else
            {
                // Set return type
                this.returnType = leftOperand.returnType;
            }

            // If operand is not arithmetic, overwrite return type
            if ((int)op >= 6)
            {
                this.returnType = PrimitiveType.BOOL;
            }

            // Check if operator and operands are compatible
            switch (op)
            {
                // Addition is accepted for strings and numeric types
                case BinaryOperator.Add:
                    // If type is not string, check if it is numerical
                    if (!leftOperand.returnType.Equals(PrimitiveType.STRING))
                    {
                        goto case BinaryOperator.Leq;
                    }
                    break;
                // Other arithmetic operators and comparisons (except equals and not equals) are accepted for numeric types
                case BinaryOperator.Sub:
                case BinaryOperator.Mul:
                case BinaryOperator.Div:
                case BinaryOperator.Gt:
                case BinaryOperator.Lt:
                case BinaryOperator.Geq:
                case BinaryOperator.Leq:
                    // Check if type is not integer or double
                    if (!leftOperand.returnType.Equals(PrimitiveType.INT) &&
                        !leftOperand.returnType.Equals(PrimitiveType.DOUBLE))
                    {
                        // Issue error
                        Compiler.Compiler.errors.SemErr(t.line, t.col, "Arithmetic operator can only be applied to numerical types");
                    }
                    break;
                // Modulo operator is accepted only for integer type
                case BinaryOperator.Rem:
                    // Check if type is not integer
                    if (!leftOperand.returnType.Equals(PrimitiveType.INT))
                    {
                        // Issue error
                        Compiler.Compiler.errors.SemErr(t.line, t.col, "Reminder operator can only be applied to integer type");
                    }
                    break;
                // Equality and non equality are accepted for all types
                case BinaryOperator.Eq:
                case BinaryOperator.Neq:
                    break;

                // Default case stands for logical operators
                default:
                    // Check if type is not boolean
                    if (!leftOperand.returnType.Equals(PrimitiveType.BOOL))
                    {
                        // Issue error
                        Compiler.Compiler.errors.SemErr(t.line, t.col, "Logical operator can only be applied to boolean type");
                    }
                    break;
            }

            // If both operands are constant expressions, perform constant folding
            if ((leftOperand is ConstantExpression) && (rightOperand is ConstantExpression))
            {
                // Compile time evaluation of expressions is done based on type and operator
                // If type is boolean
                if (leftOperand.returnType.Equals(PrimitiveType.BOOL))
                {
                    switch (op)
                    {
                        // Compute equality
                        case BinaryOperator.Eq:
                            // Cast values to bool, compare and create new constant expression
                            return new ConstantExpression(Primitive.Bool, (bool)(leftOperand as ConstantExpression).value ==
                                (bool)(rightOperand as ConstantExpression).value);
                        // Compute non-equality
                        case BinaryOperator.Neq:
                            // Same as exclusive or for boolean values
                            goto case BinaryOperator.Xor;
                        // Compute logical and
                        case BinaryOperator.And:
                            // Cast values to bool, apply operation and create constant expression
                            return new ConstantExpression(Primitive.Bool, (bool)(leftOperand as ConstantExpression).value &&
                                (bool)(rightOperand as ConstantExpression).value);
                        // Compute logical or
                        case BinaryOperator.Or:
                            // Cast values to bool, apply operation and create constant expression
                            return new ConstantExpression(Primitive.Bool, (bool)(leftOperand as ConstantExpression).value ||
                                (bool)(rightOperand as ConstantExpression).value);
                        // Compute logical exclusive or
                        case BinaryOperator.Xor:
                            // Cast values to bool, apply operation and create constant expression (xor is equivalent to a
                            // non-equality check)
                            return new ConstantExpression(Primitive.Bool, (bool)(leftOperand as ConstantExpression).value !=
                                (bool)(rightOperand as ConstantExpression).value);
                    }
                }
                // If type is double
                else if (leftOperand.returnType.Equals(PrimitiveType.DOUBLE))
                {
                    switch (op)
                    {
                        // Compute equality
                        case BinaryOperator.Eq:
                            // Cast values to double, apply operation and create constant (boolean) expression
                            return new ConstantExpression(Primitive.Bool, (double)(leftOperand as ConstantExpression).value ==
                                (double)(rightOperand as ConstantExpression).value);
                        // Compute non-equality
                        case BinaryOperator.Neq:
                            // Cast values to double, apply operation and create constant (boolean) expression
                            return new ConstantExpression(Primitive.Bool, (double)(leftOperand as ConstantExpression).value !=
                                (double)(rightOperand as ConstantExpression).value);
                        // Compute greater than
                        case BinaryOperator.Gt:
                            // Cast values to double, apply operation and create constant (boolean) expression
                            return new ConstantExpression(Primitive.Bool, (double)(leftOperand as ConstantExpression).value >
                                (double)(rightOperand as ConstantExpression).value);
                        // Compute greater than or equal to
                        case BinaryOperator.Geq:
                            // Cast values to double, apply operation and create constant (boolean) expression
                            return new ConstantExpression(Primitive.Bool, (double)(leftOperand as ConstantExpression).value >=
                                (double)(rightOperand as ConstantExpression).value);
                        // Compute less than
                        case BinaryOperator.Lt:
                            // Cast values to double, apply operation and create constant (boolean) expression
                            return new ConstantExpression(Primitive.Bool, (double)(leftOperand as ConstantExpression).value <
                                (double)(rightOperand as ConstantExpression).value);
                        // Compute less than or equal to
                        case BinaryOperator.Leq:
                            // Cast values to double, apply operation and create constant (boolean) expression
                            return new ConstantExpression(Primitive.Bool, (double)(leftOperand as ConstantExpression).value <=
                                (double)(rightOperand as ConstantExpression).value);

                        // Compute addition
                        case BinaryOperator.Add:
                            // Cast values to double, apply operation and create constant expression
                            return new ConstantExpression(Primitive.Double, ((double)(leftOperand as ConstantExpression).value +
                                (double)(rightOperand as ConstantExpression).value).ToString(NumberFormatInfo.InvariantInfo));
                        // Compute subtraction
                        case BinaryOperator.Sub:
                            // Cast values to double, apply operation and create constant expression
                            return new ConstantExpression(Primitive.Double, ((double)(leftOperand as ConstantExpression).value -
                                (double)(rightOperand as ConstantExpression).value).ToString(NumberFormatInfo.InvariantInfo));
                        // Compute multiplication
                        case BinaryOperator.Mul:
                            // Cast values to double, apply operation and create constant expression
                            return new ConstantExpression(Primitive.Double, ((double)(leftOperand as ConstantExpression).value *
                                (double)(rightOperand as ConstantExpression).value).ToString(NumberFormatInfo.InvariantInfo));
                        // Compute division
                        case BinaryOperator.Div:
                            // Cast values to double, apply operation and create constant expression
                            return new ConstantExpression(Primitive.Double, ((double)(leftOperand as ConstantExpression).value /
                                (double)(rightOperand as ConstantExpression).value).ToString(NumberFormatInfo.InvariantInfo));
                    }
                }
                // If type is integer
                else if (leftOperand.returnType.Equals(PrimitiveType.INT))
                {
                    switch (op)
                    {
                        // Compute equality
                        case BinaryOperator.Eq:
                            // Cast values to int, apply operation and create constant (boolean) expression
                            return new ConstantExpression(Primitive.Bool, (int)(leftOperand as ConstantExpression).value ==
                                (int)(rightOperand as ConstantExpression).value);
                        // Compute non-equality
                        case BinaryOperator.Neq:
                            // Cast values to int, apply operation and create constant (boolean) expression
                            return new ConstantExpression(Primitive.Bool, (int)(leftOperand as ConstantExpression).value !=
                                (int)(rightOperand as ConstantExpression).value);
                        // Compute greater than
                        case BinaryOperator.Gt:
                            // Cast values to int, apply operation and create constant (boolean) expression
                            return new ConstantExpression(Primitive.Bool, (int)(leftOperand as ConstantExpression).value >
                                (int)(rightOperand as ConstantExpression).value);
                        // Compute greater than or equal to
                        case BinaryOperator.Geq:
                            // Cast values to int, apply operation and create constant (boolean) expression
                            return new ConstantExpression(Primitive.Bool, (int)(leftOperand as ConstantExpression).value >=
                                (int)(rightOperand as ConstantExpression).value);
                        // Compute less than
                        case BinaryOperator.Lt:
                            // Cast values to int, apply operation and create constant (boolean) expression
                            return new ConstantExpression(Primitive.Bool, (int)(leftOperand as ConstantExpression).value <
                                (int)(rightOperand as ConstantExpression).value);
                        // Compute less than or equal to
                        case BinaryOperator.Leq:
                            // Cast values to int, apply operation and create constant (boolean) expression
                            return new ConstantExpression(Primitive.Bool, (int)(leftOperand as ConstantExpression).value <=
                                (int)(rightOperand as ConstantExpression).value);

                        // Compute addition
                        case BinaryOperator.Add:
                            // Cast values to int, apply operation and create constant expression
                            return new ConstantExpression(Primitive.Int, ((int)(leftOperand as ConstantExpression).value +
                                (int)(rightOperand as ConstantExpression).value).ToString(NumberFormatInfo.InvariantInfo));
                        // Compute subtraction
                        case BinaryOperator.Sub:
                            // Cast values to int, apply operation and create constant expression
                            return new ConstantExpression(Primitive.Int, ((int)(leftOperand as ConstantExpression).value -
                                (int)(rightOperand as ConstantExpression).value).ToString(NumberFormatInfo.InvariantInfo));
                        // Compute multiplication
                        case BinaryOperator.Mul:
                            // Cast values to int, apply operation and create constant expression
                            return new ConstantExpression(Primitive.Int, ((int)(leftOperand as ConstantExpression).value *
                                (int)(rightOperand as ConstantExpression).value).ToString(NumberFormatInfo.InvariantInfo));
                        // Compute division
                        case BinaryOperator.Div:
                            // Cast values to int, apply operation and create constant expression
                            return new ConstantExpression(Primitive.Int, ((int)(leftOperand as ConstantExpression).value /
                                (int)(rightOperand as ConstantExpression).value).ToString(NumberFormatInfo.InvariantInfo));
                        // Compute modulo
                        case BinaryOperator.Rem:
                            // Cast values to int, apply operation and create constant expression
                            return new ConstantExpression(Primitive.Int, ((int)(leftOperand as ConstantExpression).value %
                                (int)(rightOperand as ConstantExpression).value).ToString(NumberFormatInfo.InvariantInfo));
                    }
                }
                // If type is string
                else if (leftOperand.returnType.Equals(PrimitiveType.STRING))
                {
                    switch (op)
                    {
                        // Compute equality
                        case BinaryOperator.Eq:
                            // Convert values to string, apply operation and create constant (boolean) expression
                            return new ConstantExpression(Primitive.Bool, (leftOperand as ConstantExpression).value.ToString() ==
                                (rightOperand as ConstantExpression).value.ToString());
                        // Compute non-equality
                        case BinaryOperator.Neq:
                            // Convert values to string, apply operation and create constant (boolean) expression
                            return new ConstantExpression(Primitive.Bool, (leftOperand as ConstantExpression).value.ToString() !=
                                (rightOperand as ConstantExpression).value.ToString());

                        // Compute addition
                        case BinaryOperator.Add:
                            // Convert values to string, apply operation and create constant expression
                            return new ConstantExpression(Primitive.String, (leftOperand as ConstantExpression).value.ToString() +
                                (rightOperand as ConstantExpression).value.ToString());
                    }
                }
            }

            return this;
        }