2005-01-26 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
[mono.git] / mcs / mbas / cfold.cs
index 1c564ce3e4caea4cfd952da1c5ef418c9a8f9473..b211d2bf331ed4f3db74919e827e8807fea078f0 100644 (file)
@@ -9,7 +9,7 @@
 
 using System;
 
-namespace Mono.CSharp {
+namespace Mono.MonoBASIC {
 
        public class ConstantFold {
 
@@ -27,7 +27,7 @@ namespace Mono.CSharp {
                //   (uint, uint)
                //   (int, int)
                //
-               static void DoConstantNumericPromotions (Binary.Operator oper,
+               static void DoConstantNumericPromotions (EmitContext ec, Binary.Operator oper,
                                                         ref Constant left, ref Constant right,
                                                         Location loc)
                {
@@ -93,14 +93,62 @@ namespace Mono.CSharp {
                        } else if (left is UIntConstant || right is UIntConstant){
                                //
                                // If either operand is of type uint, and the other
-                               // operand is of type sbyte, short or int, othe operands are
+                               // operand is of type sbyte, short or int, the operands are
                                // converted to type long.
                                //
-                               if (!(left is UIntConstant))
-                                       left = left.ToUInt (loc);
-                               else if (!(right is UIntConstant))
-                                       right = right.ToUInt (loc);
+                               Constant match, other;
+                               if (left is UIntConstant){
+                                       other = right;
+                                       match = left;
+                               } else {
+                                       other = left;
+                                       match = right;
+                               }
+
+                               // Nothing to do.
+                               if (other is UIntConstant)
+                                       return;
+
+                               if (other is SByteConstant || other is ShortConstant ||
+                                   other is IntConstant){
+                                       left = left.ToLong (loc);
+                                       right = right.ToLong (loc);
+                               }
+
+                               return;
+                       } else if (left is EnumConstant || right is EnumConstant){
+                               //
+                               // If either operand is an enum constant, the other one must
+                               // be implicitly convertable to that enum's underlying type.
+                               //
+                               EnumConstant match;
+                               Constant other;
+                               if (left is EnumConstant){
+                                       other = right;
+                                       match = (EnumConstant) left;
+                               } else {
+                                       other = left;
+                                       match = (EnumConstant) right;
+                               }
+
+                               bool need_check = (other is EnumConstant) ||
+                                       ((oper != Binary.Operator.Addition) &&
+                                        (oper != Binary.Operator.Subtraction));
+
+                               if (need_check &&
+                                   !Expression.ImplicitConversionExists (ec, match, other.Type)) {
+                                       Expression.Error_CannotConvertImplicit (loc, match.Type, other.Type);
+                                       left = null;
+                                       right = null;
+                                       return;
+                               }
+
+                               if (left is EnumConstant)
+                                       left = ((EnumConstant) left).Child;
+                               if (right is EnumConstant)
+                                       right = ((EnumConstant) right).Child;
                                return;
+
                        } else {
                                //
                                // Force conversions to int32
@@ -147,10 +195,12 @@ namespace Mono.CSharp {
                                if (right is EnumConstant)
                                        right = ((EnumConstant) right).Child;
                        }
-                       
+
+                       Type wrap_as;
+                       Constant result = null;
                        switch (oper){
                        case Binary.Operator.BitwiseOr:
-                               DoConstantNumericPromotions (oper, ref left, ref right, loc);
+                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
                                if (left == null || right == null)
                                        return null;
                                
@@ -195,7 +245,7 @@ namespace Mono.CSharp {
                                break;
                                
                        case Binary.Operator.BitwiseAnd:
-                               DoConstantNumericPromotions (oper, ref left, ref right, loc);
+                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
                                if (left == null || right == null)
                                        return null;
                                
@@ -240,7 +290,7 @@ namespace Mono.CSharp {
                                break;
 
                        case Binary.Operator.ExclusiveOr:
-                               DoConstantNumericPromotions (oper, ref left, ref right, loc);
+                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
                                if (left == null || right == null)
                                        return null;
                                
@@ -285,7 +335,6 @@ namespace Mono.CSharp {
                                break;
 
                        case Binary.Operator.Addition:
-                               Constant result;
                                bool left_is_string = left is StringConstant;
                                bool right_is_string = right is StringConstant;
 
@@ -294,6 +343,7 @@ namespace Mono.CSharp {
                                // one is a string, and the other is not, then defer
                                // to runtime concatenation
                                //
+                               wrap_as = null;
                                if (left_is_string || right_is_string){
                                        if (left_is_string && right_is_string)
                                                return new StringConstant (
@@ -309,7 +359,6 @@ namespace Mono.CSharp {
                                //
                                // note that E operator + (E x, E y) is invalid
                                //
-                               Type wrap_as = null;
                                if (left is EnumConstant){
                                        if (right is EnumConstant){
                                                return null;
@@ -325,7 +374,7 @@ namespace Mono.CSharp {
                                }
 
                                result = null;
-                               DoConstantNumericPromotions (oper, ref left, ref right, loc);
+                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
                                if (left == null || right == null)
                                        return null;
 
@@ -409,7 +458,30 @@ namespace Mono.CSharp {
                                        return result;
 
                        case Binary.Operator.Subtraction:
-                               DoConstantNumericPromotions (oper, ref left, ref right, loc);
+                               //
+                               // handle "E operator - (E x, U y)"
+                               // handle "E operator - (Y y, E x)"
+                               // handle "U operator - (E x, E y)"
+                               //
+                               wrap_as = null;
+                               if (left is EnumConstant){
+                                       if (right is EnumConstant){
+                                               if (left.Type == right.Type)
+                                                       wrap_as = TypeManager.EnumToUnderlying (left.Type);
+                                               else
+                                                       return null;
+                                       }
+                                       if (((EnumConstant) left).Child.Type != right.Type)
+                                               return null;
+
+                                       wrap_as = left.Type;
+                               } else if (right is EnumConstant){
+                                       if (((EnumConstant) right).Child.Type != left.Type)
+                                               return null;
+                                       wrap_as = right.Type;
+                               }
+
+                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
                                if (left == null || right == null)
                                        return null;
 
@@ -424,7 +496,7 @@ namespace Mono.CSharp {
                                                        res = unchecked (((DoubleConstant) left).Value -
                                                                         ((DoubleConstant) right).Value);
                                                
-                                               return new DoubleConstant (res);
+                                               result = new DoubleConstant (res);
                                        } else if (left is FloatConstant){
                                                float res;
                                                
@@ -435,7 +507,7 @@ namespace Mono.CSharp {
                                                        res = unchecked (((FloatConstant) left).Value -
                                                                         ((FloatConstant) right).Value);
                                                
-                                               return new FloatConstant (res);
+                                               result = new FloatConstant (res);
                                        } else if (left is ULongConstant){
                                                ulong res;
                                                
@@ -446,7 +518,7 @@ namespace Mono.CSharp {
                                                        res = unchecked (((ULongConstant) left).Value -
                                                                         ((ULongConstant) right).Value);
                                                
-                                               return new ULongConstant (res);
+                                               result = new ULongConstant (res);
                                        } else if (left is LongConstant){
                                                long res;
                                                
@@ -457,7 +529,7 @@ namespace Mono.CSharp {
                                                        res = unchecked (((LongConstant) left).Value -
                                                                         ((LongConstant) right).Value);
                                                
-                                               return new LongConstant (res);
+                                               result = new LongConstant (res);
                                        } else if (left is UIntConstant){
                                                uint res;
                                                
@@ -468,7 +540,7 @@ namespace Mono.CSharp {
                                                        res = unchecked (((UIntConstant) left).Value -
                                                                         ((UIntConstant) right).Value);
                                                
-                                               return new UIntConstant (res);
+                                               result = new UIntConstant (res);
                                        } else if (left is IntConstant){
                                                int res;
 
@@ -479,17 +551,20 @@ namespace Mono.CSharp {
                                                        res = unchecked (((IntConstant) left).Value -
                                                                         ((IntConstant) right).Value);
 
-                                               return new IntConstant (res);
+                                               result = new IntConstant (res);
                                        } else {
                                                throw new Exception ( "Unexepected input: " + left);
                                        }
                                } catch (OverflowException){
                                        Error_CompileTimeOverflow (loc);
                                }
-                               break;
+                               if (wrap_as != null)
+                                       return new EnumConstant (result, wrap_as);
+                               else
+                                       return result;
                                
                        case Binary.Operator.Multiply:
-                               DoConstantNumericPromotions (oper, ref left, ref right, loc);
+                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
                                if (left == null || right == null)
                                        return null;
 
@@ -569,7 +644,7 @@ namespace Mono.CSharp {
                                break;
 
                        case Binary.Operator.Division:
-                               DoConstantNumericPromotions (oper, ref left, ref right, loc);
+                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
                                if (left == null || right == null)
                                        return null;
 
@@ -647,13 +722,13 @@ namespace Mono.CSharp {
                                        Error_CompileTimeOverflow (loc);
 
                                } catch (DivideByZeroException) {
-                                       Report.Error (020, loc, "Division by constant zero");
+                                       Report.Error (30542, loc, "Division by constant zero");
                                }
                                
                                break;
                                
                        case Binary.Operator.Modulus:
-                               DoConstantNumericPromotions (oper, ref left, ref right, loc);
+                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
                                if (left == null || right == null)
                                        return null;
 
@@ -822,7 +897,7 @@ namespace Mono.CSharp {
                                        
                                }
                                
-                               DoConstantNumericPromotions (oper, ref left, ref right, loc);
+                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
                                if (left == null || right == null)
                                        return null;
 
@@ -862,7 +937,7 @@ namespace Mono.CSharp {
                                                ((StringConstant) right).Value);
                                        
                                }
-                               DoConstantNumericPromotions (oper, ref left, ref right, loc);
+                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
                                if (left == null || right == null)
                                        return null;
 
@@ -891,7 +966,7 @@ namespace Mono.CSharp {
                                return new BoolConstant (bool_res);
 
                        case Binary.Operator.LessThan:
-                               DoConstantNumericPromotions (oper, ref left, ref right, loc);
+                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
                                if (left == null || right == null)
                                        return null;
 
@@ -920,7 +995,7 @@ namespace Mono.CSharp {
                                return new BoolConstant (bool_res);
                                
                        case Binary.Operator.GreaterThan:
-                               DoConstantNumericPromotions (oper, ref left, ref right, loc);
+                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
                                if (left == null || right == null)
                                        return null;
 
@@ -949,7 +1024,7 @@ namespace Mono.CSharp {
                                return new BoolConstant (bool_res);
 
                        case Binary.Operator.GreaterThanOrEqual:
-                               DoConstantNumericPromotions (oper, ref left, ref right, loc);
+                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
                                if (left == null || right == null)
                                        return null;
 
@@ -978,7 +1053,7 @@ namespace Mono.CSharp {
                                return new BoolConstant (bool_res);
 
                        case Binary.Operator.LessThanOrEqual:
-                               DoConstantNumericPromotions (oper, ref left, ref right, loc);
+                               DoConstantNumericPromotions (ec, oper, ref left, ref right, loc);
                                if (left == null || right == null)
                                        return null;