- Fixed baseline aligning calcs
[mono.git] / mcs / mbas / statement.cs
index c7b83fb875600a03717f473340f4dab734c2fbd4..de580cd2f01c40c5f683eb422f6d8f51f5cb0ee9 100644 (file)
@@ -4,6 +4,7 @@
 // Author:
 //   Miguel de Icaza (miguel@ximian.com)
 //   Martin Baulig (martin@gnome.org)
+//      Anirban Bhattacharjee (banirban@novell.com)
 //
 // (C) 2001, 2002 Ximian, Inc.
 //
@@ -14,7 +15,7 @@ using System.Reflection;
 using System.Reflection.Emit;
 using System.Diagnostics;
 
-namespace Mono.CSharp {
+namespace Mono.MonoBASIC {
 
        using System.Collections;
        
@@ -673,7 +674,7 @@ namespace Mono.CSharp {
                        } else {
                                if (Expr == null){
                                        Report.Error (126, loc, "An object of type `" +
-                                                     TypeManager.CSharpName (ec.ReturnType) + "' is " +
+                                                     TypeManager.MonoBASIC_Name (ec.ReturnType) + "' is " +
                                                      "expected for the return statement");
                                        return true;
                                }
@@ -936,7 +937,7 @@ namespace Mono.CSharp {
                                if ((t != TypeManager.exception_type) &&
                                    !t.IsSubclassOf (TypeManager.exception_type) &&
                                    !(expr is NullLiteral)) {
-                                       Report.Error (155, loc,
+                                       Report.Error (30665, loc,
                                                      "The type caught or thrown must be derived " +
                                                      "from System.Exception");
                                        return false;
@@ -1032,16 +1033,44 @@ namespace Mono.CSharp {
                {
                        ILGenerator ig = ec.ig;
 
-                       if (ec.InLoop == false && ec.Switch == null){
-                               Report.Error (139, loc, "No enclosing loop or switch to continue to");
-                               return false;
-                       }
+                       if (type != ExitType.SUB && type != ExitType.FUNCTION && 
+                               type != ExitType.PROPERTY && type != ExitType.TRY) {
+                               if (ec.InLoop == false && ec.Switch == null){
+                                       if (type == ExitType.FOR)
+                                               Report.Error (30096, loc, "No enclosing FOR loop to exit from");
+                                       if (type == ExitType.WHILE) \r
+                                               Report.Error (30097, loc, "No enclosing WHILE loop to exit from");
+                                       if (type == ExitType.DO)
+                                               Report.Error (30089, loc, "No enclosing DO loop to exit from");
+                                       if (type == ExitType.SELECT)
+                                               Report.Error (30099, loc, "No enclosing SELECT to exit from");
 
-                       if (ec.InTry || ec.InCatch)
-                               ig.Emit (OpCodes.Leave, ec.LoopEnd);
-                       else
-                               ig.Emit (OpCodes.Br, ec.LoopEnd);
+                                       return false;
+                               }
 
+                               if (ec.InTry || ec.InCatch)
+                                       ig.Emit (OpCodes.Leave, ec.LoopEnd);
+                               else
+                                       ig.Emit (OpCodes.Br, ec.LoopEnd);
+                       } else {                        
+                               if (ec.InFinally){
+                                       Report.Error (30393, loc, 
+                                               "Control can not leave the body of the finally block");
+                                       return false;
+                               }
+                       
+                               if (ec.InTry || ec.InCatch) {
+                                       if (!ec.HasReturnLabel) {
+                                               ec.ReturnLabel = ec.ig.DefineLabel ();
+                                               ec.HasReturnLabel = true;
+                                       }
+                                       ec.ig.Emit (OpCodes.Leave, ec.ReturnLabel);
+                               } else
+                                       ec.ig.Emit (OpCodes.Ret);
+
+                               return true; 
+                       }
+                       
                        return false;
                }
        }       
@@ -1273,7 +1302,7 @@ namespace Mono.CSharp {
                        set {
                                initialize_vector ();
 
-                               for (int i = 0; i < Math.Min (vector.Count, value.Count); i++)
+                               for (int i = 0; i < System.Math.Min (vector.Count, value.Count); i++)
                                        vector [i] = value [i];
                        }
                }
@@ -2506,7 +2535,7 @@ namespace Mono.CSharp {
 
                                        FieldInfo field = struct_info [i];
                                        Report.Error (171, loc,
-                                                     "Field `" + TypeManager.CSharpName (VariableType) +
+                                                     "Field `" + TypeManager.MonoBASIC_Name (VariableType) +
                                                      "." + field.Name + "' must be fully initialized " +
                                                      "before control leaves the constructor");
                                        return false;
@@ -2609,21 +2638,21 @@ namespace Mono.CSharp {
                //
                // Labels.  (label, block) pairs.
                //
-               Hashtable labels;
+               CaseInsensitiveHashtable labels;
 
                //
                // Keeps track of (name, type) pairs
                //
-               Hashtable variables;
+               CaseInsensitiveHashtable variables;
 
                //
                // Keeps track of constants
-               Hashtable constants;
+               CaseInsensitiveHashtable constants;
 
                //
                // Maps variable names to ILGenerator.LocalBuilders
                //
-               Hashtable local_builders;
+               CaseInsensitiveHashtable local_builders;
 
                bool used = false;
 
@@ -2703,7 +2732,7 @@ namespace Mono.CSharp {
                public bool AddLabel (string name, LabeledStatement target)
                {
                        if (labels == null)
-                               labels = new Hashtable ();
+                               labels = new CaseInsensitiveHashtable ();
                        if (labels.Contains (name))
                                return false;
                        
@@ -2751,7 +2780,7 @@ namespace Mono.CSharp {
                public void AddChildVariableName (string name)
                {
                        if (child_variable_names == null)
-                               child_variable_names = new Hashtable ();
+                               child_variable_names = new CaseInsensitiveHashtable ();
 
                        if (!child_variable_names.Contains (name))
                                child_variable_names.Add (name, true);
@@ -2802,7 +2831,7 @@ namespace Mono.CSharp {
                        this_variable = new VariableInfo (tc, ID, l);
 
                        if (variables == null)
-                               variables = new Hashtable ();
+                               variables = new CaseInsensitiveHashtable ();
                        variables.Add ("this", this_variable);
 
                        return this_variable;
@@ -2811,7 +2840,7 @@ namespace Mono.CSharp {
                public VariableInfo AddVariable (Expression type, string name, Parameters pars, Location l)
                {
                        if (variables == null)
-                               variables = new Hashtable ();
+                               variables = new CaseInsensitiveHashtable ();
 
                        VariableInfo vi = GetVariableInfo (name);
                        if (vi != null) {
@@ -2866,7 +2895,7 @@ namespace Mono.CSharp {
                                return false;
                        
                        if (constants == null)
-                               constants = new Hashtable ();
+                               constants = new CaseInsensitiveHashtable ();
 
                        constants.Add (name, value);
                        return true;
@@ -3061,7 +3090,7 @@ namespace Mono.CSharp {
                        // Process this block variables
                        //
                        if (variables != null){
-                               local_builders = new Hashtable ();
+                               local_builders = new CaseInsensitiveHashtable ();
                                
                                foreach (DictionaryEntry de in variables){
                                        string name = (string) de.Key;
@@ -3404,7 +3433,7 @@ namespace Mono.CSharp {
                                if (converted != null){
                                        Report.Error (-12, loc, "More than one conversion to an integral " +
                                                      " type exists for type `" +
-                                                     TypeManager.CSharpName (Expr.Type)+"'");
+                                                     TypeManager.MonoBASIC_Name (Expr.Type)+"'");
                                        return null;
                                } else
                                        converted = e;
@@ -3430,7 +3459,7 @@ namespace Mono.CSharp {
                {
                        Type compare_type;
                        bool error = false;
-                       Elements = new Hashtable ();
+                       Elements = new CaseInsensitiveHashtable ();
                                
                        got_default = false;
 
@@ -4065,7 +4094,7 @@ namespace Mono.CSharp {
                        if (type.IsValueType){
                                Report.Error (185, loc, "lock statement requires the expression to be " +
                                              " a reference type (type is: `" +
-                                             TypeManager.CSharpName (type) + "'");
+                                             TypeManager.MonoBASIC_Name (type) + "'");
                                return false;
                        }
 
@@ -4420,16 +4449,19 @@ namespace Mono.CSharp {
        public class Catch {
                public readonly string Name;
                public readonly Block  Block;
+               public Expression Clause;
                public readonly Location Location;
 
                Expression type_expr;
+               //Expression clus_expr;
                Type type;
                
-               public Catch (Expression type, string name, Block block, Location l)
+               public Catch (Expression type, string name, Block block, Expression clause, Location l)
                {
                        type_expr = type;
                        Name = name;
                        Block = block;
+                       Clause = clause;
                        Location = l;
                }
 
@@ -4453,7 +4485,7 @@ namespace Mono.CSharp {
                                        return false;
 
                                if (type != TypeManager.exception_type && !type.IsSubclassOf (TypeManager.exception_type)){
-                                       Report.Error (155, Location,
+                                       Report.Error (30665, Location,
                                                      "The type caught or thrown must be derived " +
                                                      "from System.Exception");
                                        return false;
@@ -4461,6 +4493,13 @@ namespace Mono.CSharp {
                        } else
                                type = null;
 
+                       if (Clause != null)     {
+                               Clause = Statement.ResolveBoolean (ec, Clause, Location);
+                               if (Clause == null) {
+                                       return false;
+                               }
+                       }
+
                        if (!Block.Resolve (ec))
                                return false;
 
@@ -4622,17 +4661,47 @@ namespace Mono.CSharp {
                                        ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
                                } else
                                        ig.Emit (OpCodes.Pop);
-                               
-                               if (!c.Block.Emit (ec))
-                                       returns = false;
+
+                               //
+                               // if when clause is there
+                               //
+                               if (c.Clause != null) {
+                                       if (c.Clause is BoolConstant) {
+                                               bool take = ((BoolConstant) c.Clause).Value;
+
+                                               if (take) 
+                                                       if (!c.Block.Emit (ec))
+                                                               returns = false;
+                                       } else {
+                                               EmitBoolExpression (ec, c.Clause, finish, false);
+                                               if (!c.Block.Emit (ec))
+                                                       returns = false;
+                                       }
+                               } else 
+                                       if (!c.Block.Emit (ec))
+                                               returns = false;
                        }
 
                        if (General != null){
                                ig.BeginCatchBlock (TypeManager.object_type);
                                ig.Emit (OpCodes.Pop);
-                               if (!General.Block.Emit (ec))
-                                       returns = false;
+
+                               if (General.Clause != null) {
+                                       if (General.Clause is BoolConstant) {
+                                               bool take = ((BoolConstant) General.Clause).Value;
+                                               if (take) 
+                                                       if (!General.Block.Emit (ec))
+                                                               returns = false;
+                                       } else {
+                                               EmitBoolExpression (ec, General.Clause, finish, false);
+                                               if (!General.Block.Emit (ec))
+                                                       returns = false;
+                                       }
+                               } else 
+                                       if (!General.Block.Emit (ec))
+                                               returns = false;
                        }
+
                        ec.InCatch = old_in_catch;
 
                        ig.MarkLabel (finish);
@@ -4940,7 +5009,7 @@ namespace Mono.CSharp {
                        // Although it is not as important in this case, as the type
                        // will not likely be object (what the enumerator will return).
                        //
-                       conv = Expression.ConvertExplicit (ec, empty, var_type, loc);
+                       conv = Expression.ConvertExplicit (ec, empty, var_type, false, loc);
                        if (conv == null)
                                return false;
 
@@ -5427,25 +5496,36 @@ namespace Mono.CSharp {
        public class AddHandler : Statement {
                Expression EvtId;
                Expression EvtHandler;
-               Expression EvtTarget;
 
-               public AddHandler (Expression evt_id, Expression evt_handler, 
-                                                       Expression evt_target, Location l)
+               //
+               // keeps track whether EvtId is already resolved
+               //
+               bool resolved;
+
+               public AddHandler (Expression evt_id, Expression evt_handler, Location l)
                {
                        EvtId = evt_id;
                        EvtHandler = evt_handler;
-                       EvtTarget = evt_target;
                        loc = l;
+                       resolved = false;
                        //Console.WriteLine ("Adding handler '" + evt_handler + "' for Event '" + evt_id +"'");
                }
 
                public override bool Resolve (EmitContext ec)
                {
+                       //
+                       // if EvetId is of EventExpr type that means
+                       // this is already resolved 
+                       //
+                       if (EvtId is EventExpr) {
+                               resolved = true;
+                               return true;
+                       }
+
                        EvtId = EvtId.Resolve(ec);
                        EvtHandler = EvtHandler.Resolve(ec,ResolveFlags.MethodGroup);
-                       EvtTarget = EvtTarget.Resolve (ec,ResolveFlags.VariableOrValue);
                        if (EvtId == null || (!(EvtId is EventExpr))) {
-                               Report.Error (999, "'AddHandler' statement needs an event designator.");
+                               Report.Error (30676, "Need an event designator.");
                                return false;
                        }
 
@@ -5454,20 +5534,25 @@ namespace Mono.CSharp {
                                Report.Error (999, "'AddHandler' statement needs an event handler.");
                                return false;
                        }
-                       //EventExpr ee = (EventExpr) EvtId;
-                       //MethodGroupExpr me = (MethodGroupExpr) EvtHandler;
-                       //bool b = EvtId.Type.IsSubclassOf (TypeManager.delegate_type);
-                       //ee.EventInfo.AddEventHandler(EvtTarget, new System.Delegate())
+
                        return true;
                }
 
                protected override bool DoEmit (EmitContext ec)
                {
+                       //
+                       // Already resolved and emitted don't do anything
+                       //
+                       if (resolved)
+                               return true;
+
                        Expression e, d;
                        ArrayList args = new ArrayList();
                        Argument arg = new Argument (EvtHandler, Argument.AType.Expression);
                        args.Add (arg);
                        
+                       
+
                        // The even type was already resolved to a delegate, so
                        // we must un-resolve its name to generate a type expression
                        string ts = (EvtId.Type.ToString()).Replace ('+','.');
@@ -5489,5 +5574,179 @@ namespace Mono.CSharp {
 
                        return false;
                }
-       }       
+       }
+
+       /// <summary>
+       ///   RemoveHandler statement
+       /// </summary>
+       public class RemoveHandler : Statement \r
+       {
+               Expression EvtId;
+               Expression EvtHandler;
+
+               public RemoveHandler (Expression evt_id, Expression evt_handler, Location l)
+               {
+                       EvtId = evt_id;
+                       EvtHandler = evt_handler;
+                       loc = l;
+               }
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       EvtId = EvtId.Resolve(ec);
+                       EvtHandler = EvtHandler.Resolve(ec,ResolveFlags.MethodGroup);
+                       if (EvtId == null || (!(EvtId is EventExpr))) \r
+                       {
+                               Report.Error (30676, "Need an event designator.");
+                               return false;
+                       }
+
+                       if (EvtHandler == null) 
+                       {
+                               Report.Error (999, "'AddHandler' statement needs an event handler.");
+                               return false;
+                       }
+                       return true;
+               }
+
+               protected override bool DoEmit (EmitContext ec)
+               {
+                       Expression e, d;
+                       ArrayList args = new ArrayList();
+                       Argument arg = new Argument (EvtHandler, Argument.AType.Expression);
+                       args.Add (arg);
+                       
+                       // The even type was already resolved to a delegate, so
+                       // we must un-resolve its name to generate a type expression
+                       string ts = (EvtId.Type.ToString()).Replace ('+','.');
+                       Expression dtype = Mono.MonoBASIC.Parser.DecomposeQI (ts, Location.Null);
+
+                       // which we can use to declare a new event handler
+                       // of the same type
+                       d = new New (dtype, args, Location.Null);
+                       d = d.Resolve(ec);
+                       // detach the event
+                       e = new CompoundAssign(Binary.Operator.Subtraction, EvtId, d, Location.Null);
+
+                       // we resolve it all and emit the code
+                       e = e.Resolve(ec);
+                       if (e != null) 
+                       {
+                               e.Emit(ec);
+                               return true;
+                       }
+
+                       return false;
+               }
+       }
+
+       public class RedimClause {
+               public Expression Expr;
+               public ArrayList NewIndexes;
+               
+               public RedimClause (Expression e, ArrayList args)
+               {
+                       Expr = e;
+                       NewIndexes = args;
+               }
+       }
+
+       public class ReDim : Statement {
+               ArrayList RedimTargets;
+               Type BaseType;
+               bool Preserve;
+
+               private StatementExpression ReDimExpr;
+
+               public ReDim (ArrayList targets, bool opt_preserve, Location l)
+               {
+                       loc = l;
+                       RedimTargets = targets;
+                       Preserve = opt_preserve;
+               }
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       Expression RedimTarget;
+                       ArrayList NewIndexes;
+
+                       foreach (RedimClause rc in RedimTargets) {
+                               RedimTarget = rc.Expr;
+                               NewIndexes = rc.NewIndexes;
+
+                               RedimTarget = RedimTarget.Resolve (ec);
+                               if (!RedimTarget.Type.IsArray)
+                                       Report.Error (49, "'ReDim' statement requires an array");
+
+                               ArrayList args = new ArrayList();
+                               foreach (Argument a in NewIndexes) {
+                                       if (a.Resolve(ec, loc))
+                                               args.Add (a.Expr);
+                               }
+
+                               for (int x = 0; x < args.Count; x++) {
+                                       args[x] = new Binary (Binary.Operator.Addition,
+                                                               (Expression) args[x], new IntLiteral (1), Location.Null);       
+                               }
+
+                               NewIndexes = args;
+                               if (RedimTarget.Type.GetArrayRank() != args.Count)
+                                       Report.Error (415, "'ReDim' cannot change the number of dimensions of an array.");
+
+                               BaseType = RedimTarget.Type.GetElementType();
+                               Expression BaseTypeExpr = MonoBASIC.Parser.DecomposeQI(BaseType.FullName.ToString(), Location.Null);
+                               ArrayCreation acExpr = new ArrayCreation (BaseTypeExpr, NewIndexes, "", null, Location.Null);   
+                               // TODO: we are in a foreach we probably can't reuse ReDimExpr, must turn it into an array(list)
+                               if (Preserve)
+                               {
+                                       ExpressionStatement PreserveExpr = (ExpressionStatement) new Preserve(RedimTarget, acExpr, loc);
+                                       ReDimExpr = (StatementExpression) new StatementExpression ((ExpressionStatement) new Assign (RedimTarget, PreserveExpr, loc), loc);
+                               }
+                               else
+                                       ReDimExpr = (StatementExpression) new StatementExpression ((ExpressionStatement) new Assign (RedimTarget, acExpr, loc), loc);
+                               ReDimExpr.Resolve(ec);
+                       }
+                       return true;
+               }
+                               
+               protected override bool DoEmit (EmitContext ec)
+               {
+                       ReDimExpr.Emit(ec);
+                       return false;
+               }               
+               
+       }
+       
+       public class Erase : Statement {
+               Expression EraseTarget;
+               
+               private StatementExpression EraseExpr;
+               
+               public Erase (Expression expr, Location l)
+               {
+                       loc = l;
+                       EraseTarget = expr;
+               }
+               
+               public override bool Resolve (EmitContext ec)
+               {
+                       EraseTarget = EraseTarget.Resolve (ec);
+                       if (!EraseTarget.Type.IsArray) 
+                               Report.Error (49, "'Erase' statement requires an array");
+
+                       EraseExpr = (StatementExpression) new StatementExpression ((ExpressionStatement) new Assign (EraseTarget, NullLiteral.Null, loc), loc);
+                       EraseExpr.Resolve(ec);
+                       
+                       return true;
+               }
+                               
+               protected override bool DoEmit (EmitContext ec)
+               {
+                       EraseExpr.Emit(ec);
+                       return false;
+               }               
+               
+       }
+       
+       
 }