2005-09-05 Miguel de Icaza <miguel@novell.com>
[mono.git] / mcs / bmcs / expression.cs
index 20352c216f88f74d221fd000e122fed4ca125085..d8562f5155e6527a8d43bf1bdd13b2e67e33cd9d 100644 (file)
@@ -1942,12 +1942,16 @@ namespace Mono.CSharp {
                static string OperName (Operator oper)
                {
                        switch (oper){
+                       case Operator.Exponentiation:
+                               return "^";
                        case Operator.Multiply:
                                return "*";
                        case Operator.Division:
                                return "/";
+                       case Operator.IntegerDivision:
+                               return "\\";
                        case Operator.Modulus:
-                               return "%";
+                               return "Mod";
                        case Operator.Addition:
                                return "+";
                        case Operator.Subtraction:
@@ -1965,15 +1969,17 @@ namespace Mono.CSharp {
                        case Operator.GreaterThanOrEqual:
                                return ">=";
                        case Operator.Equality:
-                               return "==";
+                               return "=";
                        case Operator.Inequality:
-                               return "!=";
+                               return "<>";
+                       case Operator.Like:
+                               return "Like";
                        case Operator.BitwiseAnd:
-                               return "&";
+                               return "And";
                        case Operator.BitwiseOr:
-                               return "|";
+                               return "Or";
                        case Operator.ExclusiveOr:
-                               return "^";
+                               return "Xor";
                        case Operator.LogicalOrElse:
                                return "OrElse";
                        case Operator.LogicalAndAlso:
@@ -2256,6 +2262,7 @@ namespace Mono.CSharp {
                void CheckShiftArguments (EmitContext ec)
                {
                        Expression e;
+                       Type assumed_target_type = right.Type;
 
                        e = Convert.ImplicitVBConversion (ec, right, TypeManager.int32_type, Location);
                        if (e == null){
@@ -2273,7 +2280,8 @@ namespace Mono.CSharp {
                                }
 
                                left = target_left_expr;
-                       }
+                       } else if (left.Type == TypeManager.null_type)
+                               left  = Convert.ImplicitVBConversion (ec, left, assumed_target_type, Location);
 
                        type = left.Type;
 
@@ -2293,6 +2301,45 @@ namespace Mono.CSharp {
                        right = new Binary (Binary.Operator.BitwiseAnd, right, new IntLiteral (mask), loc);
                        right = right.DoResolve (ec);
                }
+
+               void CheckIsArguments (EmitContext ec)
+               {
+                               Type l = left.Type;
+                               Type r = right.Type;
+                               Type = TypeManager.bool_type;
+                               
+                               bool left_is_null = left is NullLiteral;
+                               bool right_is_null = right is NullLiteral;
+
+                               if (left_is_null || right_is_null)
+                                       return;
+
+                               if (l.IsValueType || r.IsValueType) {
+                                       Error_OperatorCannotBeApplied ();
+                                       return;
+                               }
+
+                               
+                               if (l == r)
+                                       return; 
+                                       
+                               if (l.IsSubclassOf (r) || r.IsSubclassOf (l))
+                                       return; 
+
+                               if (!(Convert.WideningStandardConversionExists (ec, left, right.Type) ||
+                                     Convert.WideningStandardConversionExists (ec, right, left.Type))){
+                                       Error_OperatorCannotBeApplied ();
+                                       return;
+                               }
+
+                               if (left.Type != TypeManager.object_type)
+                                       left = new EmptyCast (left, TypeManager.object_type);
+                               if (right.Type != TypeManager.object_type)
+                                       right = new EmptyCast (right, TypeManager.object_type);
+
+                               return;
+               }
+
                
 #if false
                Expression ResolveOperator (EmitContext ec)
@@ -3068,6 +3115,7 @@ namespace Mono.CSharp {
                                opcode = OpCodes.Shl;
                                break;
 
+                       case Operator.Is:
                        case Operator.Equality:
                                opcode = OpCodes.Ceq;
                                break;
@@ -3138,6 +3186,8 @@ namespace Mono.CSharp {
                        Type l = left.Type;
                        Type r = right.Type;
 
+                       //Console.WriteLine (OperName (oper) +"< "+  l + ", " + r + ">");
+
                        errors = Report.Errors;
                        ret_expr = HandleObjectOperands (ec);
                        if (Report.Errors > errors)
@@ -3207,11 +3257,19 @@ namespace Mono.CSharp {
                        if (IsShortCircuitedLogicalExpression)
                                return this;
 
+                       if (oper == Operator.Like) {
+                               Type = TypeManager.bool_type;
+                               Expression compare_mode = new EnumConstant (new IntConstant ((int) RootContext.StringComparisonMode), 
+                                                                     typeof (Microsoft.VisualBasic.CompareMethod));                                    
+                               return new HelperMethodInvocation (ec, Location, TypeManager.bool_type, TypeManager.msvbcs_stringtype_strlike_string_string_comparemethod, left, right, compare_mode);
+                       }
+
 
                        //
                        // Step 0: String concatenation (because overloading will get this wrong)
                        //
-                       if (oper == Operator.Addition){
+                       if (oper == Operator.Addition || oper == Operator.Concatenation){
+
                                //
                                // If any of the arguments is a string, cast to string
                                //
@@ -3220,13 +3278,8 @@ namespace Mono.CSharp {
                                if (left is StringConstant && right is StringConstant)
                                        return new StringConstant (((StringConstant) left).Value + ((StringConstant) right).Value);
 
-                               if (l == TypeManager.string_type || r == TypeManager.string_type) {
+                               if (Type == TypeManager.string_type) {
 
-                                       if (r == TypeManager.void_type || l == TypeManager.void_type) {
-                                               Error_OperatorCannotBeApplied ();
-                                               return null;
-                                       }
-                                       
                                        // try to fold it in on the left
                                        if (left is StringConcat) {
 
@@ -3272,7 +3325,7 @@ namespace Mono.CSharp {
                        Expression target_left_expr = left;
                        Expression target_right_expr = right;
 
-                       if (IsShortCircuitedLogicalExpression)
+                       if (IsShortCircuitedLogicalExpression || IsExpression)
                                return null;
 
                        if (l != TypeManager.object_type && r != TypeManager.object_type)
@@ -3352,18 +3405,33 @@ namespace Mono.CSharp {
                                return;
                        }
 
+                       if (IsExpression) {
+                               CheckIsArguments (ec);
+                               return;
+                       }
+
                        while (true) {
                                ++step;
+
+                               if (step > 10)
+                                       throw new Exception ("FIXME: An Infinite loop when resolving <" + l + "> " + OperName (oper) + " <" + r + ">");
                                
-                               // Console.WriteLine ("STEP " + step + ":");
-                               // Console.WriteLine ("         left => " + target_left_expr_type + " right => " + target_right_expr_type);
+                               //Console.WriteLine ("          STEP " + step + ":");
+                               //Console.WriteLine ("          " + "<" + target_left_expr_type + ", " + target_right_expr_type + ">");
                                
                                if ((target_left_expr_type == target_right_expr_type) && 
                                    IsOperatorDefinedForType (target_left_expr_type)) {
-                                       left = target_left_expr;
-                                       right = target_right_expr;
-                                       type = target_left_expr_type;
-                                       break;
+
+                                       if (target_left_expr_type == TypeManager.null_type) {
+                                               target_left_expr = target_right_expr = new IntConstant (0);
+                                               Type = TypeManager.int32_type;
+                                               return;
+                                       } else {
+                                               left = target_left_expr;
+                                               right = target_right_expr;
+                                               type = target_left_expr_type;
+                                               return;
+                                       }
                                }
 
                                if ( !IsOperatorDefinedForType (target_left_expr_type)) {
@@ -3390,6 +3458,10 @@ namespace Mono.CSharp {
                                        continue;
                                }
 
+                               if (target_left_expr_type == TypeManager.null_type ||
+                                       target_right_expr_type == TypeManager.null_type)
+                                       break;
+
                                if (target_left_expr_type == TypeManager.string_type) {
                                        Type target_type;
                                        if (target_right_expr_type == TypeManager.date_type)
@@ -3436,15 +3508,19 @@ namespace Mono.CSharp {
                                        continue;
                                }
 
-                               if ( !DoOperandPromotions(ec, target_left_expr, target_right_expr)) {
-                                       Error_OperatorCannotBeApplied();
-                                       return;
-                               }
+                               break;
                        }
+
+                       if ( !DoOperandPromotions(ec, target_left_expr, target_right_expr))
+                               Error_OperatorCannotBeApplied();
+
+                       return;
                }       
 
                bool IsOperatorDefinedForType (Type t)
                {
+                       if (t == TypeManager.null_type)
+                               return true;
                
                        switch (oper) {
 
@@ -3469,6 +3545,12 @@ namespace Mono.CSharp {
 
                                break;
 
+                       case Operator.LogicalAndAlso:
+                       case Operator.LogicalOrElse:
+                               if (t == TypeManager.bool_type)
+                                       return true;
+                               break;
+
                        case Operator.RightShift:
                        case Operator.LeftShift:
 
@@ -3570,6 +3652,12 @@ namespace Mono.CSharp {
                        if (t1 == t2)
                                return t1;
 
+                       if(t1 == TypeManager.null_type)
+                               return t2;
+
+                       if (t2 == TypeManager.null_type)
+                               return t1;
+
                        if (t1 == TypeManager.date_type || t1 == TypeManager.char_type) {
                                if (t2 == TypeManager.string_type)
                                        return t2;
@@ -3607,6 +3695,9 @@ namespace Mono.CSharp {
                        
                        Type target_type = GetWiderOfTypes(l, r);
 
+                       //Console.WriteLine ("          DoingOperandPromotions");
+                       //Console.WriteLine ("         left => " + l + " right => " + r);
+                       //Console.WriteLine ("          target_type => " + target_type);
 
                        if (target_type == null) {
                                throw new Exception ("Types " + l + " " + r +" cannot be compared");
@@ -3673,6 +3764,12 @@ namespace Mono.CSharp {
                        }
                }
 
+               bool IsExpression {
+                       get {
+                               return (oper == Operator.Is);
+                       }
+               }
+
                MethodInfo HelperMethod {
                        get {
                                MethodInfo helper_method = null;