Switch to compiler-tester
[mono.git] / mcs / mbas / statement.cs
index 71d5d0af2600232cb4aaca498565191a4ea61a17..889bcc852fab7aff74ae93be46291cefe7063fec 100644 (file)
@@ -4,6 +4,9 @@
 // Author:
 //   Miguel de Icaza (miguel@ximian.com)
 //   Martin Baulig (martin@gnome.org)
+//      Anirban Bhattacharjee (banirban@novell.com)
+//   Manjula GHM (mmanjula@novell.com)
+//   Satya Sudha K (ksathyasudha@novell.com)
 //
 // (C) 2001, 2002 Ximian, Inc.
 //
@@ -14,7 +17,7 @@ using System.Reflection;
 using System.Reflection.Emit;
 using System.Diagnostics;
 
-namespace Mono.CSharp {
+namespace Mono.MonoBASIC {
 
        using System.Collections;
        
@@ -33,7 +36,17 @@ namespace Mono.CSharp {
                /// <summary>
                ///   Return value indicates whether all code paths emitted return.
                /// </summary>
-               public abstract bool Emit (EmitContext ec);
+               protected abstract bool DoEmit (EmitContext ec);
+
+               /// <summary>
+               ///   Return value indicates whether all code paths emitted return.
+               /// </summary>
+               public virtual bool Emit (EmitContext ec)
+               {
+                       ec.Mark (loc);
+                       Report.Debug (8, "MARK", this, loc);
+                       return DoEmit (ec);
+               }
                
                public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
                {
@@ -42,17 +55,15 @@ namespace Mono.CSharp {
                                return null;
                        
                        if (e.Type != TypeManager.bool_type){
-                               e = Expression.ConvertImplicit (ec, e, TypeManager.bool_type,
-                                                               new Location (-1));
+                               e = Expression.ConvertImplicit (ec, e, TypeManager.bool_type, Location.Null);
                        }
 
                        if (e == null){
                                Report.Error (
-                                       31, loc, "Can not convert the expression to a boolean");
+                                       30311, loc, "Can not convert the expression to a boolean");
                        }
 
-                       if (CodeGen.SymbolWriter != null)
-                               ec.Mark (loc);
+                       ec.Mark (loc);
 
                        return e;
                }
@@ -114,7 +125,7 @@ namespace Mono.CSharp {
                        return true;
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        return false;
                }
@@ -173,7 +184,7 @@ namespace Mono.CSharp {
                        return true;
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
                        Label false_target = ig.DefineLabel ();
@@ -226,14 +237,27 @@ namespace Mono.CSharp {
                }
        }
 
+       public enum DoOptions {
+               WHILE,
+               UNTIL,
+               TEST_BEFORE,
+               TEST_AFTER
+       };
+
        public class Do : Statement {
                public Expression expr;
                public readonly Statement  EmbeddedStatement;
+               //public DoOptions type;
+               public DoOptions test;
+               bool infinite, may_return;
+
                
-               public Do (Statement statement, Expression boolExpr, Location l)
+               public Do (Statement statement, Expression boolExpr, DoOptions do_test, Location l)
                {
                        expr = boolExpr;
                        EmbeddedStatement = statement;
+//                     type = do_type;
+                       test = do_test;
                        loc = l;
                }
 
@@ -246,72 +270,91 @@ namespace Mono.CSharp {
                        if (!EmbeddedStatement.Resolve (ec))
                                ok = false;
 
-                       ec.EndFlowBranching ();
-
                        expr = ResolveBoolean (ec, expr, loc);
                        if (expr == null)
                                ok = false;
-                       
+                       else if (expr is BoolConstant){
+                               bool res = ((BoolConstant) expr).Value;
+
+                               if (res)
+                                       infinite = true;
+                       }
+
+                       ec.CurrentBranching.Infinite = infinite;
+                       FlowReturns returns = ec.EndFlowBranching ();
+                       may_return = returns != FlowReturns.NEVER;
+
                        return ok;
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
                        Label loop = ig.DefineLabel ();
                        Label old_begin = ec.LoopBegin;
                        Label old_end = ec.LoopEnd;
                        bool  old_inloop = ec.InLoop;
-                       bool old_breaks = ec.Breaks;
                        int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
                        
                        ec.LoopBegin = ig.DefineLabel ();
                        ec.LoopEnd = ig.DefineLabel ();
                        ec.InLoop = true;
                        ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
-                               
-                       ig.MarkLabel (loop);
-                       ec.Breaks = false;
-                       EmbeddedStatement.Emit (ec);
-                       bool breaks = ec.Breaks;
-                       ig.MarkLabel (ec.LoopBegin);
 
-                       //
-                       // Dead code elimination
-                       //
-                       if (expr is BoolConstant){
-                               bool res = ((BoolConstant) expr).Value;
+                       if (test == DoOptions.TEST_AFTER) {
+                               ig.MarkLabel (loop);
+                               EmbeddedStatement.Emit (ec);
+                               ig.MarkLabel (ec.LoopBegin);
 
-                               if (res)
-                                       ec.ig.Emit (OpCodes.Br, loop); 
-                       } else
-                               EmitBoolExpression (ec, expr, loop, true);
-                       
-                       ig.MarkLabel (ec.LoopEnd);
+                               //
+                               // Dead code elimination
+                               //
+                               if (expr is BoolConstant){
+                                       bool res = ((BoolConstant) expr).Value;
+
+                                       if (res)
+                                               ec.ig.Emit (OpCodes.Br, loop);
+                               } else
+                                       EmitBoolExpression (ec, expr, loop, true);
 
+                               ig.MarkLabel (ec.LoopEnd);
+                       }
+                       else
+                       {
+                               ig.MarkLabel (loop);
+                               ig.MarkLabel (ec.LoopBegin);
+
+                               //
+                               // Dead code elimination
+                               //
+                               if (expr is BoolConstant){
+                                       bool res = ((BoolConstant) expr).Value;
+
+                                       if (res)
+                                               ec.ig.Emit (OpCodes.Br, ec.LoopEnd);
+                               } else
+                                       EmitBoolExpression (ec, expr, ec.LoopEnd, true);
+
+                               EmbeddedStatement.Emit (ec);
+                               ec.ig.Emit (OpCodes.Br, loop);
+                               ig.MarkLabel (ec.LoopEnd);
+                       }
                        ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
                        ec.LoopBegin = old_begin;
                        ec.LoopEnd = old_end;
                        ec.InLoop = old_inloop;
-                       ec.Breaks = old_breaks;
-
-                       //
-                       // Inform whether we are infinite or not
-                       //
-                       if (expr is BoolConstant){
-                               BoolConstant bc = (BoolConstant) expr;
 
-                               if (bc.Value == true)
-                                       return breaks == false;
-                       }
-                       
-                       return false;
+                       if (infinite)
+                               return may_return == false;
+                       else
+                               return false;
                }
        }
 
        public class While : Statement {
                public Expression expr;
                public readonly Statement Statement;
+               bool may_return, empty, infinite;
                
                public While (Expression boolExpr, Statement statement, Location l)
                {
@@ -330,22 +373,47 @@ namespace Mono.CSharp {
 
                        ec.StartFlowBranching (FlowBranchingType.LOOP_BLOCK, loc);
 
+                       //
+                       // Inform whether we are infinite or not
+                       //
+                       if (expr is BoolConstant){
+                               BoolConstant bc = (BoolConstant) expr;
+
+                               if (bc.Value == false){
+                                       Warning_DeadCodeFound (Statement.loc);
+                                       empty = true;
+                               } else
+                                       infinite = true;
+                       } else {
+                               //
+                               // We are not infinite, so the loop may or may not be executed.
+                               //
+                               ec.CurrentBranching.CreateSibling ();
+                       }
+
                        if (!Statement.Resolve (ec))
                                ok = false;
 
-                       ec.EndFlowBranching ();
+                       if (empty)
+                               ec.KillFlowBranching ();
+                       else {
+                               ec.CurrentBranching.Infinite = infinite;
+                               FlowReturns returns = ec.EndFlowBranching ();
+                               may_return = returns != FlowReturns.NEVER;
+                       }
 
                        return ok;
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
+                       if (empty)
+                               return false;
+
                        ILGenerator ig = ec.ig;
                        Label old_begin = ec.LoopBegin;
                        Label old_end = ec.LoopEnd;
                        bool old_inloop = ec.InLoop;
-                       bool old_breaks = ec.Breaks;
-                       Label while_loop = ig.DefineLabel ();
                        int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
                        bool ret;
                        
@@ -354,35 +422,26 @@ namespace Mono.CSharp {
                        ec.InLoop = true;
                        ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
 
-                       ig.Emit (OpCodes.Br, ec.LoopBegin);
-                       ig.MarkLabel (while_loop);
-
                        //
                        // Inform whether we are infinite or not
                        //
                        if (expr is BoolConstant){
-                               BoolConstant bc = (BoolConstant) expr;
-
                                ig.MarkLabel (ec.LoopBegin);
-                               if (bc.Value == false){
-                                       Warning_DeadCodeFound (Statement.loc);
-                                       ret = false;
-                               } else {
-                                       bool breaks;
-                                       
-                                       ec.Breaks = false;
-                                       Statement.Emit (ec);
-                                       breaks = ec.Breaks;
-                                       ig.Emit (OpCodes.Br, ec.LoopBegin);
+                               Statement.Emit (ec);
+                               ig.Emit (OpCodes.Br, ec.LoopBegin);
                                        
-                                       //
-                                       // Inform that we are infinite (ie, `we return'), only
-                                       // if we do not `break' inside the code.
-                                       //
-                                       ret = breaks == false;
-                               }
+                               //
+                               // Inform that we are infinite (ie, `we return'), only
+                               // if we do not `break' inside the code.
+                               //
+                               ret = may_return == false;
                                ig.MarkLabel (ec.LoopEnd);
                        } else {
+                               Label while_loop = ig.DefineLabel ();
+
+                               ig.Emit (OpCodes.Br, ec.LoopBegin);
+                               ig.MarkLabel (while_loop);
+
                                Statement.Emit (ec);
                        
                                ig.MarkLabel (ec.LoopBegin);
@@ -396,7 +455,6 @@ namespace Mono.CSharp {
                        ec.LoopBegin = old_begin;
                        ec.LoopEnd = old_end;
                        ec.InLoop = old_inloop;
-                       ec.Breaks = old_breaks;
                        ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
 
                        return ret;
@@ -404,66 +462,236 @@ namespace Mono.CSharp {
        }
 
        public class For : Statement {
-               Expression Test;
-               readonly Statement InitStatement;
-               readonly Statement Increment;
-               readonly Statement Statement;
+               Expression LoopControlVar;
+               Expression Start;
+               Expression Limit;
+               Expression StepValue;
+               Statement statement, Increment;
+               bool may_return, infinite, empty;
+               private Statement InitStatement;
+               // required when loop control var is of type 'Object'
+               Expression Test, AddnTest;
+               LocalTemporary ltmp;
+               bool is_lcv_object;
                
-               public For (Statement initStatement,
-                           Expression test,
-                           Statement increment,
+               public For (Expression loopVar,
+                           Expression start,
+                           Expression limit,
+                           Expression stepVal,
                            Statement statement,
                            Location l)
                {
-                       InitStatement = initStatement;
-                       Test = test;
-                       Increment = increment;
-                       Statement = statement;
+                       LoopControlVar = loopVar;
+                       Start = start;
+                       Limit = limit;
+                       StepValue = stepVal;
+                       this.statement = statement;
                        loc = l;
+                       ltmp = null;
+
+                       InitStatement = new StatementExpression ((ExpressionStatement) (new Assign (LoopControlVar, Start, loc)), loc);
+                       Increment = new StatementExpression (
+                                               (ExpressionStatement) (new CompoundAssign (Binary.Operator.Addition, 
+                                                                       LoopControlVar, StepValue, loc)), loc);
+                       AddnTest = null;
+                       is_lcv_object = false;
                }
 
                public override bool Resolve (EmitContext ec)
                {
                        bool ok = true;
 
+                       LoopControlVar = LoopControlVar.Resolve (ec);
+                       if (LoopControlVar == null)
+                               return false;
+
+                       Start = Start.Resolve (ec);
+                       Limit = Limit.Resolve (ec);
+                       StepValue = StepValue.Resolve (ec);
+                       if (StepValue == null || Start == null || Limit == null)
+                               return false;
+
+                       double value = 0;
+                       if (StepValue is Constant) {
+
+                               value = GetValue (StepValue);
+                               if (value > 0) // Positive Step value
+                                       Test = new Binary (Binary.Operator.LessThanOrEqual, LoopControlVar, Limit, loc);
+                               else if (value < 0)
+                                       Test = new Binary (Binary.Operator.GreaterThanOrEqual, LoopControlVar, Limit, loc);
+                       }
+
+                       if (Start is Constant && Limit is Constant) {
+                               if (value > 0)
+                                       AddnTest = ConstantFold.BinaryFold (ec, Binary.Operator.LessThanOrEqual,
+                                                                           (Constant) Start, (Constant) Limit, loc);
+                               else  if (value < 0)
+                                       AddnTest = ConstantFold.BinaryFold (ec, Binary.Operator.GreaterThanOrEqual,
+                                                                           (Constant) Start, (Constant) Limit, loc);
+                       }
+
+
+                       string method_to_call = null;
+                       Binary left, right;
+                       left = right = null;
+
+                       switch (Type.GetTypeCode (LoopControlVar.Type)) {
+                       case TypeCode.Boolean :
+                       case TypeCode.Char :
+                       case TypeCode.DateTime :
+                       case TypeCode.String :
+                               Report.Error (30337,loc,"'For' loop control variable cannot be of type '" + LoopControlVar.Type + "'");
+                               return false;
+                       case TypeCode.Byte :
+                               if (Test == null)
+                                       Test = new Binary (Binary.Operator.LessThanOrEqual, LoopControlVar, Limit, loc);
+                               break;
+                       case TypeCode.Int16 :
+                               if (Test == null) {
+                                       left = new Binary (Binary.Operator.ExclusiveOr, 
+                                                          new Binary (Binary.Operator.RightShift, StepValue, new IntLiteral (15), loc),
+                                                          LoopControlVar, 
+                                                          loc);
+                                       right = new Binary (Binary.Operator.ExclusiveOr, 
+                                                           new Binary (Binary.Operator.RightShift, StepValue, new IntLiteral (15), loc),
+                                                           Limit, 
+                                                           loc);
+                                       Test = new Binary (Binary.Operator.LessThanOrEqual, left, right, loc);
+                               }
+                               break;
+                       case TypeCode.Int32 :
+                               if (Test == null) {
+                                       left = new Binary (Binary.Operator.ExclusiveOr, 
+                                                          new Binary (Binary.Operator.RightShift, StepValue, new IntLiteral (31), loc),
+                                                          LoopControlVar, 
+                                                          loc);
+                                       right = new Binary (Binary.Operator.ExclusiveOr, 
+                                                           new Binary (Binary.Operator.RightShift, StepValue, new IntLiteral (31), loc),
+                                                           Limit, 
+                                                           loc);
+                                       Test = new Binary (Binary.Operator.LessThanOrEqual, left, right, loc);
+                               }
+                               break;
+                       case TypeCode.Int64 :
+                               if (Test == null) {
+                                       left = new Binary (Binary.Operator.ExclusiveOr, 
+                                                          new Binary (Binary.Operator.RightShift, StepValue, new IntLiteral (63), loc),
+                                                          LoopControlVar, 
+                                                          loc);
+                                       right = new Binary (Binary.Operator.ExclusiveOr, 
+                                                           new Binary (Binary.Operator.RightShift, StepValue, new IntLiteral (63), loc),
+                                                           Limit, 
+                                                           loc);
+                                       Test = new Binary (Binary.Operator.LessThanOrEqual, left, right, loc);
+                               }
+                               break;
+                       case TypeCode.Decimal :
+                               method_to_call = "Microsoft.VisualBasic.CompilerServices.FlowControl.ForNextCheckDec";
+                               break;
+                       case TypeCode.Single :
+                               method_to_call = "Microsoft.VisualBasic.CompilerServices.FlowControl.ForNextCheckR4";
+                               break;
+                       case TypeCode.Double :
+                               method_to_call = "Microsoft.VisualBasic.CompilerServices.FlowControl.ForNextCheckR8";
+                               break;
+                       case TypeCode.Object :
+                               is_lcv_object = true;
+                               ArrayList initArgs = new ArrayList ();
+                               initArgs.Add (new Argument (LoopControlVar, Argument.AType.Expression));
+                               initArgs.Add (new Argument (Start, Argument.AType.Expression));
+                               initArgs.Add (new Argument (Limit, Argument.AType.Expression));
+                               initArgs.Add (new Argument (StepValue, Argument.AType.Expression));
+                               ltmp = new LocalTemporary (ec, TypeManager.object_type);
+                               initArgs.Add (new Argument (ltmp, Argument.AType.Ref));
+                               initArgs.Add (new Argument (LoopControlVar, Argument.AType.Ref));
+                               Expression sname  = Parser.DecomposeQI ("Microsoft.VisualBasic.CompilerServices.FlowControl.ForLoopInitObj", loc);
+                               AddnTest = new Invocation (sname, initArgs, loc);
+                               //AddnTest = new Binary (Binary.Operator.Inequality, inv, new BoolLiteral (false), loc);
+                               ArrayList args = new ArrayList ();
+                               args.Add (new Argument (LoopControlVar, Argument.AType.Expression));
+                               args.Add (new Argument (ltmp, Argument.AType.Expression));
+                               args.Add (new Argument (LoopControlVar, Argument.AType.Ref));
+                               sname  = Parser.DecomposeQI ("Microsoft.VisualBasic.CompilerServices.FlowControl.ForNextCheckObj", loc);
+                               Test = new Invocation (sname, args, loc);
+                               //Test = new Binary (Binary.Operator.Inequality, inv, new BoolLiteral (false), loc);
+                               break;
+                       }
+
+                       if (method_to_call != null && !method_to_call.Equals ("")) {
+                               ArrayList args = null;
+                               args = new ArrayList ();
+                               args.Add (new Argument (LoopControlVar, Argument.AType.Expression));
+                               args.Add (new Argument (Limit, Argument.AType.Expression));
+                               args.Add (new Argument (StepValue, Argument.AType.Expression));
+                               Expression sname = Parser.DecomposeQI (method_to_call, loc);
+                               Test = new Invocation (sname, args, loc);
+                               //Test = new Binary (Binary.Operator.Inequality, invocation, new BoolLiteral (false), loc);
+                       }
+
                        if (InitStatement != null){
                                if (!InitStatement.Resolve (ec))
                                        ok = false;
                        }
 
+                       if (AddnTest != null) {
+                               AddnTest = ResolveBoolean (ec, AddnTest, loc);
+                               if (AddnTest == null)
+                                       ok = false;
+                       }
+
                        if (Test != null){
                                Test = ResolveBoolean (ec, Test, loc);
                                if (Test == null)
                                        ok = false;
-                       }
+                               else if (Test is BoolConstant){
+                                       BoolConstant bc = (BoolConstant) Test;
 
-                       if (Increment != null){
+                                       if (bc.Value == false){
+                                               Warning_DeadCodeFound (statement.loc);
+                                               empty = true;
+                                       } else
+                                               infinite = true;
+                               }
+                       } else
+                               infinite = true;
+
+                       if (Increment != null) {
                                if (!Increment.Resolve (ec))
                                        ok = false;
                        }
 
                        ec.StartFlowBranching (FlowBranchingType.LOOP_BLOCK, loc);
+                       if (!infinite)
+                               ec.CurrentBranching.CreateSibling ();
 
-                       if (!Statement.Resolve (ec))
+                       if (!statement.Resolve (ec))
                                ok = false;
 
-                       ec.EndFlowBranching ();
+                       if (empty)
+                               ec.KillFlowBranching ();
+                       else {
+                               ec.CurrentBranching.Infinite = infinite;
+                               FlowReturns returns = ec.EndFlowBranching ();
+                               may_return = returns != FlowReturns.NEVER;
+                       }
 
                        return ok;
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
+                       if (empty)
+                               return false;
+
                        ILGenerator ig = ec.ig;
                        Label old_begin = ec.LoopBegin;
                        Label old_end = ec.LoopEnd;
                        bool old_inloop = ec.InLoop;
-                       bool old_breaks = ec.Breaks;
                        int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
                        Label loop = ig.DefineLabel ();
                        Label test = ig.DefineLabel ();
                        
-                       if (InitStatement != null)
+                       if (!is_lcv_object && InitStatement != null)
                                if (! (InitStatement is EmptyStatement))
                                        InitStatement.Emit (ec);
 
@@ -472,14 +700,23 @@ namespace Mono.CSharp {
                        ec.InLoop = true;
                        ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
 
-                       ig.Emit (OpCodes.Br, test);
+                       if (AddnTest != null) {
+                               if (AddnTest is BoolConstant) {
+                                       if (!((BoolConstant) AddnTest).Value)
+                                               // We can actually branch to the end of the loop,
+                                               // but vbc does it this way
+                                               ig.Emit (OpCodes.Br, test);
+                               } else if (is_lcv_object)
+                                       EmitBoolExpression (ec, AddnTest, ec.LoopEnd, false);
+                               else 
+                                       EmitBoolExpression (ec, AddnTest, test, false);
+                       } else 
+                               ig.Emit (OpCodes.Br, test);
                        ig.MarkLabel (loop);
-                       ec.Breaks = false;
-                       Statement.Emit (ec);
-                       bool breaks = ec.Breaks;
+                       statement.Emit (ec);
 
                        ig.MarkLabel (ec.LoopBegin);
-                       if (!(Increment is EmptyStatement))
+                       if (!is_lcv_object && !(Increment is EmptyStatement))
                                Increment.Emit (ec);
 
                        ig.MarkLabel (test);
@@ -496,27 +733,43 @@ namespace Mono.CSharp {
                        ec.LoopBegin = old_begin;
                        ec.LoopEnd = old_end;
                        ec.InLoop = old_inloop;
-                       ec.Breaks = old_breaks;
                        ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
                        
                        //
-                       // Inform whether we are infinite or not
+                       // Inform whether we are infinite or not
                        //
+
+                       if (ltmp != null)
+                               ltmp.Release (ec);
                        if (Test != null){
                                if (Test is BoolConstant){
                                        BoolConstant bc = (BoolConstant) Test;
 
                                        if (bc.Value)
-                                               return breaks == false;
+                                               return may_return == false;
                                }
                                return false;
                        } else
-                               return true;
+                               return may_return == false;
+               }
+
+               private double GetValue (Expression e) {
+                       if (e is DoubleConstant)
+                               return ((DoubleConstant) e).Value;
+                       if (e is FloatConstant)
+                               return (double)((FloatConstant) e).Value;
+                       if (e is IntConstant)
+                               return (double)((IntConstant) e).Value;
+                       if (e is LongConstant)
+                               return (double)((LongConstant) e).Value;
+                       if (e is DecimalConstant)
+                               return (double)((DecimalConstant) e).Value;
+                       return 0;
                }
        }
        
        public class StatementExpression : Statement {
-               Expression expr;
+               public Expression expr;
                
                public StatementExpression (ExpressionStatement expr, Location l)
                {
@@ -530,7 +783,7 @@ namespace Mono.CSharp {
                        return expr != null;
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
                        
@@ -538,7 +791,8 @@ namespace Mono.CSharp {
                                ((ExpressionStatement) expr).EmitStatement (ec);
                        else {
                                expr.Emit (ec);
-                               ig.Emit (OpCodes.Pop);
+                               if (! (expr is StatementSequence))
+                                       ig.Emit (OpCodes.Pop);
                        }
 
                        return false;
@@ -576,10 +830,11 @@ namespace Mono.CSharp {
                                ec.CurrentBranching.AddFinallyVector (vector);
 
                        vector.Returns = FlowReturns.ALWAYS;
+                       vector.Breaks = FlowReturns.ALWAYS;
                        return true;
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        if (ec.InFinally){
                                Report.Error (157,loc,"Control can not leave the body of the finally block");
@@ -594,7 +849,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;
                                }
@@ -635,7 +890,7 @@ namespace Mono.CSharp {
                        label = block.LookupLabel (target);
                        if (label == null){
                                Report.Error (
-                                       159, loc,
+                                       30132, loc,
                                        "No such label `" + target + "' in this scope");
                                return false;
                        }
@@ -662,10 +917,13 @@ namespace Mono.CSharp {
                        }
                }
 
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        Label l = label.LabelTarget (ec);
-                       ec.ig.Emit (OpCodes.Br, l);
+                        if (ec.InTry || ec.InCatch)
+                               ec.ig.Emit (OpCodes.Leave, l);
+                       else 
+                               ec.ig.Emit (OpCodes.Br, l);
                        
                        return false;
                }
@@ -673,7 +931,7 @@ namespace Mono.CSharp {
 
        public class LabeledStatement : Statement {
                public readonly Location Location;
-               string label_name;
+               //string label_name;
                bool defined;
                bool referenced;
                Label label;
@@ -682,7 +940,7 @@ namespace Mono.CSharp {
                
                public LabeledStatement (string label_name, Location l)
                {
-                       this.label_name = label_name;
+                       //this.label_name = label_name;
                        this.Location = l;
                }
 
@@ -720,13 +978,17 @@ namespace Mono.CSharp {
                {
                        if (vectors != null)
                                ec.CurrentBranching.CurrentUsageVector.MergeJumpOrigins (vectors);
+                       else {
+                               ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.NEVER;
+                               ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.NEVER;
+                       }
 
                        referenced = true;
 
                        return true;
                }
 
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        LabelTarget (ec);
                        ec.ig.MarkLabel (label);
@@ -748,12 +1010,11 @@ namespace Mono.CSharp {
 
                public override bool Resolve (EmitContext ec)
                {
-                       ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.UNREACHABLE;
-                       ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
+                       ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.UNREACHABLE;
                        return true;
                }
 
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        if (ec.Switch == null){
                                Report.Error (153, loc, "goto default is only valid in a switch statement");
@@ -761,7 +1022,7 @@ namespace Mono.CSharp {
                        }
 
                        if (!ec.Switch.GotDefault){
-                               Report.Error (159, loc, "No default target on switch statement");
+                               Report.Error (30132, loc, "No default target on switch statement");
                                return false;
                        }
                        ec.ig.Emit (OpCodes.Br, ec.Switch.DefaultTarget);
@@ -794,7 +1055,7 @@ namespace Mono.CSharp {
                                return false;
 
                        if (!(expr is Constant)){
-                               Report.Error (159, loc, "Target expression for goto case is not constant");
+                               Report.Error (30132, loc, "Target expression for goto case is not constant");
                                return false;
                        }
 
@@ -808,18 +1069,17 @@ namespace Mono.CSharp {
 
                        if (sl == null){
                                Report.Error (
-                                       159, loc,
+                                       30132, loc,
                                        "No such label 'case " + val + "': for the goto case");
                        }
 
                        label = sl.ILLabelCode;
 
-                       ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.UNREACHABLE;
-                       ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
+                       ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.UNREACHABLE;
                        return true;
                }
 
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        ec.ig.Emit (OpCodes.Br, label);
                        return true;
@@ -855,7 +1115,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;
@@ -863,10 +1123,11 @@ namespace Mono.CSharp {
                        }
 
                        ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.EXCEPTION;
+                       ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.EXCEPTION;
                        return true;
                }
                        
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        if (expr == null){
                                if (ec.InCatch)
@@ -888,6 +1149,39 @@ namespace Mono.CSharp {
                }
        }
 
+       // Support 'End' Statement which terminates execution immediately
+
+         public class End : Statement {
+
+                public End (Location l)
+                {
+                        loc = l;
+                }
+
+                public override bool Resolve (EmitContext ec)
+                {
+                        return true;
+                }
+
+                protected override bool DoEmit (EmitContext ec)
+                {
+                       Expression e = null;
+                        Expression tmp = Mono.MonoBASIC.Parser.DecomposeQI (
+                                                "Microsoft.VisualBasic.CompilerServices.ProjectData.EndApp",
+                                                        Location.Null);
+
+                       e = new Invocation (tmp, null, loc);
+                       e.Resolve (ec);
+
+                       if (e == null)
+                               return false;
+                       e.Emit (ec);
+
+                        return true;
+                }
+        }
+
+
        public class Break : Statement {
                
                public Break (Location l)
@@ -897,11 +1191,12 @@ namespace Mono.CSharp {
 
                public override bool Resolve (EmitContext ec)
                {
+                       ec.CurrentBranching.MayLeaveLoop = true;
                        ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
                        return true;
                }
 
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
 
@@ -910,7 +1205,6 @@ namespace Mono.CSharp {
                                return false;
                        }
 
-                       ec.Breaks = true;
                        if (ec.InTry || ec.InCatch)
                                ig.Emit (OpCodes.Leave, ec.LoopEnd);
                        else
@@ -919,6 +1213,85 @@ namespace Mono.CSharp {
                        return false;
                }
        }
+       
+       public enum ExitType {
+               DO, 
+               FOR, 
+               WHILE,
+               SELECT,
+               SUB,
+               FUNCTION,
+               PROPERTY,
+               TRY                     
+       };
+       
+       public class Exit : Statement {
+               public readonly ExitType type;
+               public Exit (ExitType t, Location l)
+               {
+                       loc = l;
+                       type = t;
+               }
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       ec.CurrentBranching.MayLeaveLoop = true;
+                       ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
+                       return true;
+               }
+
+               protected override bool DoEmit (EmitContext ec)
+               {
+                       ILGenerator ig = ec.ig;
+
+                       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) 
+                                               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");
+
+                                       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 {
+                                       if(type == ExitType.SUB) {   
+                                                ec.ig.Emit (OpCodes.Ret);
+                                        } else {
+                                               ec.ig.Emit (OpCodes.Ldloc_0);
+                                               ec.ig.Emit (OpCodes.Ret);
+                                       }
+
+                               }
+
+                               return true; 
+                       }
+                       
+                       return false;
+               }
+       }       
 
        public class Continue : Statement {
                
@@ -933,7 +1306,7 @@ namespace Mono.CSharp {
                        return true;
                }
 
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        Label begin = ec.LoopBegin;
                        
@@ -1147,7 +1520,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];
                        }
                }
@@ -1236,6 +1609,16 @@ namespace Mono.CSharp {
                // </summary>
                public ArrayList Siblings;
 
+               // <summary>
+               //   If this is an infinite loop.
+               // </summary>
+               public bool Infinite;
+
+               // <summary>
+               //   If we may leave the current loop.
+               // </summary>
+               public bool MayLeaveLoop;
+
                //
                // Private
                //
@@ -1319,7 +1702,7 @@ namespace Mono.CSharp {
                        //
                        MyBitVector locals, parameters;
                        FlowReturns real_returns, real_breaks;
-                       bool returns_set, breaks_set, is_finally;
+                       bool is_finally;
 
                        static int next_id = 0;
                        int id;
@@ -1339,6 +1722,8 @@ namespace Mono.CSharp {
                                        locals = new MyBitVector (parent.locals, CountLocals);
                                        if (num_params > 0)
                                                parameters = new MyBitVector (parent.parameters, num_params);
+                                       real_returns = parent.Returns;
+                                       real_breaks = parent.Breaks;
                                } else {
                                        locals = new MyBitVector (null, CountLocals);
                                        if (num_params > 0)
@@ -1420,6 +1805,10 @@ namespace Mono.CSharp {
 
                        // <summary>
                        //   Specifies when the current block returns.
+                       //   If this is FlowReturns.UNREACHABLE, then control can never reach the
+                       //   end of the method (so that we don't need to emit a return statement).
+                       //   The same applies for FlowReturns.EXCEPTION, but in this case the return
+                       //   value will never be used.
                        // </summary>
                        public FlowReturns Returns {
                                get {
@@ -1428,7 +1817,6 @@ namespace Mono.CSharp {
 
                                set {
                                        real_returns = value;
-                                       returns_set = true;
                                }
                        }
 
@@ -1436,6 +1824,8 @@ namespace Mono.CSharp {
                        //   Specifies whether control may return to our containing block
                        //   before reaching the end of this block.  This happens if there
                        //   is a break/continue/goto/return in it.
+                       //   This can also be used to find out whether the statement immediately
+                       //   following the current block may be reached or not.
                        // </summary>
                        public FlowReturns Breaks {
                                get {
@@ -1444,7 +1834,34 @@ namespace Mono.CSharp {
 
                                set {
                                        real_breaks = value;
-                                       breaks_set = true;
+                               }
+                       }
+
+                       public bool AlwaysBreaks {
+                               get {
+                                       return (Breaks == FlowReturns.ALWAYS) ||
+                                               (Breaks == FlowReturns.EXCEPTION) ||
+                                               (Breaks == FlowReturns.UNREACHABLE);
+                               }
+                       }
+
+                       public bool MayBreak {
+                               get {
+                                       return Breaks != FlowReturns.NEVER;
+                               }
+                       }
+
+                       public bool AlwaysReturns {
+                               get {
+                                       return (Returns == FlowReturns.ALWAYS) ||
+                                               (Returns == FlowReturns.EXCEPTION);
+                               }
+                       }
+
+                       public bool MayReturn {
+                               get {
+                                       return (Returns == FlowReturns.SOMETIMES) ||
+                                               (Returns == FlowReturns.ALWAYS);
                                }
                        }
 
@@ -1459,22 +1876,24 @@ namespace Mono.CSharp {
                                FlowReturns new_returns = FlowReturns.NEVER;
                                FlowReturns new_breaks = FlowReturns.NEVER;
                                bool new_returns_set = false, new_breaks_set = false;
-                               bool breaks;
 
-                               Report.Debug (1, "MERGING CHILDREN", branching, this);
+                               Report.Debug (2, "MERGING CHILDREN", branching, branching.Type,
+                                             this, children.Count);
 
                                foreach (UsageVector child in children) {
-                                       Report.Debug (1, "  MERGING CHILD", child, child.is_finally);
-
+                                       Report.Debug (2, "  MERGING CHILD", child, child.is_finally);
+                                       
                                        if (!child.is_finally) {
-                                               // If Returns is already set, perform an
-                                               // `And' operation on it, otherwise just set just.
-                                               if (!new_returns_set) {
-                                                       new_returns = child.Returns;
-                                                       new_returns_set = true;
-                                               } else
-                                                       new_returns = AndFlowReturns (
-                                                               new_returns, child.Returns);
+                                               if (child.Breaks != FlowReturns.UNREACHABLE) {
+                                                       // If Returns is already set, perform an
+                                                       // `And' operation on it, otherwise just set just.
+                                                       if (!new_returns_set) {
+                                                               new_returns = child.Returns;
+                                                               new_returns_set = true;
+                                                       } else
+                                                               new_returns = AndFlowReturns (
+                                                                       new_returns, child.Returns);
+                                               }
 
                                                // If Breaks is already set, perform an
                                                // `And' operation on it, otherwise just set just.
@@ -1484,19 +1903,7 @@ namespace Mono.CSharp {
                                                } else
                                                        new_breaks = AndFlowReturns (
                                                                new_breaks, child.Breaks);
-
-                                               // Check whether control may reach the end of this sibling.
-                                               // This happens unless we either always return or always break.
-                                               if ((child.Returns == FlowReturns.EXCEPTION) ||
-                                                   (child.Returns == FlowReturns.ALWAYS) ||
-                                                   ((branching.Type != FlowBranchingType.SWITCH_SECTION) &&
-                                                    (branching.Type != FlowBranchingType.LOOP_BLOCK) &&
-                                                    (child.Breaks == FlowReturns.ALWAYS)))
-                                                       breaks = true;
-                                               else
-                                                       breaks = false;
-                                       } else
-                                               breaks = false;
+                                       }
 
                                        // Ignore unreachable children.
                                        if (child.Returns == FlowReturns.UNREACHABLE)
@@ -1537,42 +1944,60 @@ namespace Mono.CSharp {
                                        // Here, `a' is initialized in line 3 and we must not look at
                                        // line 5 since it always returns.
                                        // 
-                                       if (!breaks) {
-                                               if (new_locals != null)
-                                                       new_locals.And (child.locals);
-                                               else {
+                                       if (child.is_finally) {
+                                               if (new_locals == null)
+                                                       new_locals = locals.Clone ();
+                                               new_locals.Or (child.locals);
+
+                                               if (parameters != null) {
+                                                       if (new_params == null)
+                                                               new_params = parameters.Clone ();
+                                                       new_params.Or (child.parameters);
+                                               }
+
+                                       } else {
+                                               if (!child.AlwaysReturns && !child.AlwaysBreaks) {
+                                                       if (new_locals != null)
+                                                               new_locals.And (child.locals);
+                                                       else {
+                                                               new_locals = locals.Clone ();
+                                                               new_locals.Or (child.locals);
+                                                       }
+                                               } else if (children.Count == 1) {
                                                        new_locals = locals.Clone ();
                                                        new_locals.Or (child.locals);
                                                }
-                                       }
 
-                                       // An `out' parameter must be assigned in all branches which do
-                                       // not always throw an exception.
-                                       if (!child.is_finally && (child.Returns != FlowReturns.EXCEPTION)) {
+                                               // An `out' parameter must be assigned in all branches which do
+                                               // not always throw an exception.
                                                if (parameters != null) {
-                                                       if (new_params != null)
-                                                               new_params.And (child.parameters);
-                                                       else {
+                                                       if (child.Breaks != FlowReturns.EXCEPTION) {
+                                                               if (new_params != null)
+                                                                       new_params.And (child.parameters);
+                                                               else {
+                                                                       new_params = parameters.Clone ();
+                                                                       new_params.Or (child.parameters);
+                                                               }
+                                                       } else if (children.Count == 1) {
                                                                new_params = parameters.Clone ();
                                                                new_params.Or (child.parameters);
                                                        }
                                                }
                                        }
-
-                                       // If we always return, check whether all `out' parameters have
-                                       // been assigned.
-                                       if ((child.Returns == FlowReturns.ALWAYS) && (child.parameters != null)) {
-                                               branching.CheckOutParameters (
-                                                       child.parameters, branching.Location);
-                                       }
                                }
 
-                               // Set new `Returns' status.
-                               if (!returns_set) {
-                                       Returns = new_returns;
-                                       returns_set = true;
-                               } else
-                                       Returns = AndFlowReturns (Returns, new_returns);
+                               Returns = new_returns;
+                               if ((branching.Type == FlowBranchingType.BLOCK) ||
+                                   (branching.Type == FlowBranchingType.EXCEPTION) ||
+                                   (new_breaks == FlowReturns.UNREACHABLE) ||
+                                   (new_breaks == FlowReturns.EXCEPTION))
+                                       Breaks = new_breaks;
+                               else if (branching.Type == FlowBranchingType.SWITCH_SECTION)
+                                       Breaks = new_returns;
+                               else if (branching.Type == FlowBranchingType.SWITCH){
+                                       if (new_breaks == FlowReturns.ALWAYS)
+                                               Breaks = FlowReturns.ALWAYS;
+                               }
 
                                //
                                // We've now either reached the point after the branching or we will
@@ -1583,45 +2008,50 @@ namespace Mono.CSharp {
                                // we need to look at (see above).
                                //
 
-                               bool or_locals = (Returns == FlowReturns.NEVER) ||
-                                       (Returns == FlowReturns.SOMETIMES);
-                               if ((branching.Type != FlowBranchingType.SWITCH_SECTION) &&
-                                   (branching.Type != FlowBranchingType.LOOP_BLOCK))
-                                       or_locals &= ((Breaks == FlowReturns.NEVER) ||
-                                                     (Breaks == FlowReturns.SOMETIMES));
+                               if (((new_breaks != FlowReturns.ALWAYS) &&
+                                    (new_breaks != FlowReturns.EXCEPTION) &&
+                                    (new_breaks != FlowReturns.UNREACHABLE)) ||
+                                   (children.Count == 1)) {
+                                       if (new_locals != null)
+                                               locals.Or (new_locals);
 
-                               if ((new_locals != null) && or_locals) {
-                                       locals.Or (new_locals);
+                                       if (new_params != null)
+                                               parameters.Or (new_params);
                                }
 
-                               if ((new_params != null) && (Breaks == FlowReturns.NEVER))
-                                       parameters.Or (new_params);
-
-                               //
-                               // If we may have returned (this only happens if there was a reachable
-                               // `return' statement in one of the branches), then we may return to our
-                               // parent block before reaching the end of the block, so set `Breaks'.
-                               //
-                               if ((Returns != FlowReturns.NEVER) && (Returns != FlowReturns.SOMETIMES)) {
-                                       // real_breaks = Returns;
-                                       // breaks_set = true;
-                               } else if (branching.Type == FlowBranchingType.BLOCK) {
-                                       //
-                                       // If this is not a loop or switch block, `break' actually breaks.
-                                       //
-
-                                       if (!breaks_set) {
-                                               Breaks = new_breaks;
-                                               breaks_set = true;
-                                       } else
-                                               Breaks = AndFlowReturns (Breaks, new_breaks);
+                               Report.Debug (2, "MERGING CHILDREN DONE", branching.Type,
+                                             new_params, new_locals, new_returns, new_breaks,
+                                             branching.Infinite, branching.MayLeaveLoop, this);
+
+                               if (branching.Type == FlowBranchingType.SWITCH_SECTION) {
+                                       if ((new_breaks != FlowReturns.ALWAYS) &&
+                                           (new_breaks != FlowReturns.EXCEPTION) &&
+                                           (new_breaks != FlowReturns.UNREACHABLE))
+                                               Report.Error (163, branching.Location,
+                                                             "Control cannot fall through from one " +
+                                                             "case label to another");
                                }
 
-                               if (new_returns == FlowReturns.EXCEPTION)
-                                       Breaks = FlowReturns.UNREACHABLE;
+                               if (branching.Infinite && !branching.MayLeaveLoop) {
+                                       Report.Debug (1, "INFINITE", new_returns, new_breaks,
+                                                     Returns, Breaks, this);
+
+                                       // We're actually infinite.
+                                       if (new_returns == FlowReturns.NEVER) {
+                                               Breaks = FlowReturns.UNREACHABLE;
+                                               return FlowReturns.UNREACHABLE;
+                                       }
 
-                               Report.Debug (1, "MERGING CHILDREN DONE", new_params, new_locals,
-                                             new_returns, new_breaks, this);
+                                       // If we're an infinite loop and do not break, the code after
+                                       // the loop can never be reached.  However, if we may return
+                                       // from the loop, then we do always return (or stay in the loop
+                                       // forever).
+                                       if ((new_returns == FlowReturns.SOMETIMES) ||
+                                           (new_returns == FlowReturns.ALWAYS)) {
+                                               Returns = FlowReturns.ALWAYS;
+                                               return FlowReturns.ALWAYS;
+                                       }
+                               }
 
                                return new_returns;
                        }
@@ -1651,7 +2081,7 @@ namespace Mono.CSharp {
                                Report.Debug (1, "MERGING JUMP ORIGIN", this);
 
                                real_breaks = FlowReturns.NEVER;
-                               breaks_set = false;
+                               real_returns = FlowReturns.NEVER;
 
                                foreach (UsageVector vector in origin_vectors) {
                                        Report.Debug (1, "  MERGING JUMP ORIGIN", vector);
@@ -1660,6 +2090,7 @@ namespace Mono.CSharp {
                                        if (parameters != null)
                                                parameters.And (vector.parameters);
                                        Breaks = AndFlowReturns (Breaks, vector.Breaks);
+                                       Returns = AndFlowReturns (Returns, vector.Returns);
                                }
 
                                Report.Debug (1, "MERGING JUMP ORIGIN DONE", this);
@@ -1674,7 +2105,6 @@ namespace Mono.CSharp {
                                Report.Debug (1, "MERGING FINALLY ORIGIN", this);
 
                                real_breaks = FlowReturns.NEVER;
-                               breaks_set = false;
 
                                foreach (UsageVector vector in finally_vectors) {
                                        Report.Debug (1, "  MERGING FINALLY ORIGIN", vector);
@@ -1688,7 +2118,6 @@ namespace Mono.CSharp {
 
                                Report.Debug (1, "MERGING FINALLY ORIGIN DONE", this);
                        }
-
                        // <summary>
                        //   Performs an `or' operation on the locals and the parameters.
                        // </summary>
@@ -1782,10 +2211,10 @@ namespace Mono.CSharp {
                        num_params = 0;
 
                        for (int i = 0; i < count; i++) {
-                               Parameter.Modifier mod = param_info.ParameterModifier (i);
+                               //Parameter.Modifier mod = param_info.ParameterModifier (i);
 
-                               if ((mod & Parameter.Modifier.OUT) == 0)
-                                       continue;
+                       //      if ((mod & Parameter.Modifier.OUT) == 0)
+                       //              continue;
 
                                param_map [i] = ++num_params;
 
@@ -1872,59 +2301,22 @@ namespace Mono.CSharp {
                        CurrentUsageVector.MergeFinallyOrigins (finally_vectors);
                }
 
-               // <summary>
-               //   Check whether all `out' parameters have been assigned.
-               // </summary>
-               public void CheckOutParameters (MyBitVector parameters, Location loc)
-               {
-                       if (InTryBlock ())
-                               return;
-
-                       for (int i = 0; i < param_map.Length; i++) {
-                               int index = param_map [i];
-
-                               if (index == 0)
-                                       continue;
-
-                               if (parameters [index - 1])
-                                       continue;
-
-                               // If it's a struct, we must ensure that all its fields have
-                               // been assigned.  If the struct has any non-public fields, this
-                               // can only be done by assigning the whole struct.
-
-                               MyStructInfo struct_info = struct_params [index - 1];
-                               if ((struct_info == null) || struct_info.HasNonPublicFields) {
-                                       Report.Error (
-                                               177, loc, "The out parameter `" +
-                                               param_info.ParameterName (i) + "' must be " +
-                                               "assigned before control leave the current method.");
-                                       param_map [i] = 0;
-                                       continue;
-                               }
-
-
-                               for (int j = 0; j < struct_info.Count; j++) {
-                                       if (!parameters [index + j]) {
-                                               Report.Error (
-                                                       177, loc, "The out parameter `" +
-                                                       param_info.ParameterName (i) + "' must be " +
-                                                       "assigned before control leave the current method.");
-                                               param_map [i] = 0;
-                                               break;
-                                       }
-                               }
-                       }
-               }
 
                // <summary>
                //   Merge a child branching.
                // </summary>
                public FlowReturns MergeChild (FlowBranching child)
                {
-                       return CurrentUsageVector.MergeChildren (child, child.Siblings);
-               }
+                       FlowReturns returns = CurrentUsageVector.MergeChildren (child, child.Siblings);
+
+                       if (child.Type != FlowBranchingType.LOOP_BLOCK)
+                               MayLeaveLoop |= child.MayLeaveLoop;
+                       else
+                               MayLeaveLoop = false;
 
+                       return returns;
+               }
                // <summary>
                //   Does the toplevel merging.
                // </summary>
@@ -1935,17 +2327,19 @@ namespace Mono.CSharp {
 
                        UsageVector vector = new UsageVector (null, num_params, Block.CountVariables);
 
+                       Report.Debug (1, "MERGING TOP BLOCK", Location, vector);
+
                        vector.MergeChildren (this, Siblings);
 
                        Siblings.Clear ();
                        Siblings.Add (vector);
 
-                       Report.Debug (1, "MERGING TOP BLOCK", vector);
+                       Report.Debug (1, "MERGING TOP BLOCK DONE", Location, vector);
 
-                       if (vector.Returns != FlowReturns.EXCEPTION)
-                               CheckOutParameters (CurrentUsageVector.Parameters, Location);
-
-                       return vector.Returns;
+                       if (vector.Breaks != FlowReturns.EXCEPTION) {
+                               return vector.AlwaysBreaks ? FlowReturns.ALWAYS : vector.Returns;
+                       } else
+                               return FlowReturns.EXCEPTION;
                }
 
                public bool InTryBlock ()
@@ -1973,7 +2367,7 @@ namespace Mono.CSharp {
 
                public bool IsVariableAssigned (VariableInfo vi)
                {
-                       if (CurrentUsageVector.Breaks == FlowReturns.UNREACHABLE)
+                       if (CurrentUsageVector.AlwaysBreaks)
                                return true;
                        else
                                return CurrentUsageVector [vi, 0];
@@ -1981,7 +2375,7 @@ namespace Mono.CSharp {
 
                public bool IsVariableAssigned (VariableInfo vi, int field_idx)
                {
-                       if (CurrentUsageVector.Breaks == FlowReturns.UNREACHABLE)
+                       if (CurrentUsageVector.AlwaysBreaks)
                                return true;
                        else
                                return CurrentUsageVector [vi, field_idx];
@@ -1989,7 +2383,7 @@ namespace Mono.CSharp {
 
                public void SetVariableAssigned (VariableInfo vi)
                {
-                       if (CurrentUsageVector.Breaks == FlowReturns.UNREACHABLE)
+                       if (CurrentUsageVector.AlwaysBreaks)
                                return;
 
                        CurrentUsageVector [vi, 0] = true;
@@ -1997,7 +2391,7 @@ namespace Mono.CSharp {
 
                public void SetVariableAssigned (VariableInfo vi, int field_idx)
                {
-                       if (CurrentUsageVector.Breaks == FlowReturns.UNREACHABLE)
+                       if (CurrentUsageVector.AlwaysBreaks)
                                return;
 
                        CurrentUsageVector [vi, field_idx] = true;
@@ -2035,7 +2429,11 @@ namespace Mono.CSharp {
                        if (index == 0)
                                return true;
 
-                       int field_idx = struct_params [number] [field_name];
+                       MyStructInfo info = (MyStructInfo) struct_params [number];
+                       if (info == null)
+                               return true;
+
+                       int field_idx = info [field_name];
 
                        return CurrentUsageVector [index + field_idx];
                }
@@ -2045,7 +2443,7 @@ namespace Mono.CSharp {
                        if (param_map [number] == 0)
                                return;
 
-                       if (CurrentUsageVector.Breaks == FlowReturns.NEVER)
+                       if (!CurrentUsageVector.AlwaysBreaks)
                                CurrentUsageVector [param_map [number]] = true;
                }
 
@@ -2056,12 +2454,48 @@ namespace Mono.CSharp {
                        if (index == 0)
                                return;
 
-                       int field_idx = struct_params [number] [field_name];
+                       MyStructInfo info = (MyStructInfo) struct_params [number];
+                       if (info == null)
+                               return;
+
+                       int field_idx = info [field_name];
 
-                       if (CurrentUsageVector.Breaks == FlowReturns.NEVER)
+                       if (!CurrentUsageVector.AlwaysBreaks)
                                CurrentUsageVector [index + field_idx] = true;
                }
 
+               public bool IsReachable ()
+               {
+                       bool reachable;
+
+                       switch (Type) {
+                       case FlowBranchingType.SWITCH_SECTION:
+                               // The code following a switch block is reachable unless the switch
+                               // block always returns.
+                               reachable = !CurrentUsageVector.AlwaysReturns;
+                               break;
+
+                       case FlowBranchingType.LOOP_BLOCK:
+                               // The code following a loop is reachable unless the loop always
+                               // returns or it's an infinite loop without any `break's in it.
+                               reachable = !CurrentUsageVector.AlwaysReturns &&
+                                       (CurrentUsageVector.Breaks != FlowReturns.UNREACHABLE);
+                               break;
+
+                       default:
+                               // The code following a block or exception is reachable unless the
+                               // block either always returns or always breaks.
+                               reachable = !CurrentUsageVector.AlwaysBreaks &&
+                                       !CurrentUsageVector.AlwaysReturns;
+                               break;
+                       }
+
+                       Report.Debug (1, "REACHABLE", Type, CurrentUsageVector.Returns,
+                                     CurrentUsageVector.Breaks, CurrentUsageVector, reachable);
+
+                       return reachable;
+               }
+
                public override string ToString ()
                {
                        StringBuilder sb = new StringBuilder ("FlowBranching (");
@@ -2241,7 +2675,7 @@ namespace Mono.CSharp {
                }
 
                public bool IsAssigned (EmitContext ec, Location loc)
-               {
+               {/* FIXME: we shouldn't just skip this!!!
                        if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsVariableAssigned (this))
                                return true;
 
@@ -2266,13 +2700,13 @@ 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;
                                }
                        }
-
+*/
                        return true;
                }
 
@@ -2355,7 +2789,7 @@ namespace Mono.CSharp {
                //
                // The statements in this block
                //
-               ArrayList statements;
+               public ArrayList statements;
 
                //
                // An array of Blocks.  We keep track of children just
@@ -2369,21 +2803,28 @@ 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;
+
+               // to hold names of variables required for late binding
+               public const string lateBindingArgs = "1_LBArgs";
+               public const string lateBindingArgNames = "1_LBArgsNames";
+               public const string lateBindingCopyBack = "1_LBCopyBack";
+
+               bool isLateBindingRequired = false;
 
                bool used = false;
 
@@ -2421,6 +2862,21 @@ namespace Mono.CSharp {
                {
                        if (parent != null)
                                parent.AddChild (this);
+                       else {
+                               // Top block
+                               // Add variables that may be required for late binding
+                               variables = new CaseInsensitiveHashtable ();
+                               ArrayList rank_specifier = new ArrayList ();
+                               ArrayList element = new ArrayList ();
+                               element.Add (new EmptyExpression ());
+                               rank_specifier.Add (element);
+                               Expression e = Mono.MonoBASIC.Parser.DecomposeQI ("System.Object[]", start);
+                               AddVariable (e, Block.lateBindingArgs, null, start);
+                               e = Mono.MonoBASIC.Parser.DecomposeQI ("System.String[]", start);
+                               AddVariable (e, Block.lateBindingArgNames, null, start);
+                               e = Mono.MonoBASIC.Parser.DecomposeQI ("System.Boolean[]", start);
+                               AddVariable (e, Block.lateBindingCopyBack, null, start);
+                       }
                        
                        this.Parent = parent;
                        this.Implicit = implicit_block;
@@ -2432,6 +2888,15 @@ namespace Mono.CSharp {
                        statements = new ArrayList ();
                }
 
+               public bool IsLateBindingRequired {
+                       get {
+                               return isLateBindingRequired;
+                       }
+                       set {
+                               isLateBindingRequired = value;
+                       }
+               }
+
                public int ID {
                        get {
                                return this_id;
@@ -2463,7 +2928,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;
                        
@@ -2511,7 +2976,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);
@@ -2562,7 +3027,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;
@@ -2571,18 +3036,18 @@ 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) {
                                if (vi.Block != ID)
-                                       Report.Error (136, l, "A local variable named `" + name + "' " +
+                                       Report.Error (30616, l, "A local variable named `" + name + "' " +
                                                      "cannot be declared in this scope since it would " +
                                                      "give a different meaning to `" + name + "', which " +
                                                      "is already used in a `parent or current' scope to " +
                                                      "denote something else");
                                else
-                                       Report.Error (128, l, "A local variable `" + name + "' is already " +
+                                       Report.Error (30290, l, "A local variable `" + name + "' is already " +
                                                      "defined in this scope");
                                return null;
                        }
@@ -2600,7 +3065,7 @@ namespace Mono.CSharp {
                                int idx = 0;
                                Parameter p = pars.GetParameterByName (name, out idx);
                                if (p != null) {
-                                       Report.Error (136, l, "A local variable named `" + name + "' " +
+                                       Report.Error (30616, l, "A local variable named `" + name + "' " +
                                                      "cannot be declared in this scope since it would " +
                                                      "give a different meaning to `" + name + "', which " +
                                                      "is already used in a `parent or current' scope to " +
@@ -2626,7 +3091,7 @@ namespace Mono.CSharp {
                                return false;
                        
                        if (constants == null)
-                               constants = new Hashtable ();
+                               constants = new CaseInsensitiveHashtable ();
 
                        constants.Add (name, value);
                        return true;
@@ -2811,7 +3276,7 @@ namespace Mono.CSharp {
                /// </remarks>
                public void EmitMeta (EmitContext ec, Block toplevel)
                {
-                       DeclSpace ds = ec.DeclSpace;
+                       //DeclSpace ds = ec.DeclSpace;
                        ILGenerator ig = ec.ig;
 
                        if (!variables_initialized)
@@ -2821,10 +3286,18 @@ 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;
+                                       /*
+                                       if (!isLateBindingRequired) {
+                                               if (name.Equals (Block.lateBindingArgs) || 
+                                                   name.Equals (Block.lateBindingArgNames) ||
+                                                   name.Equals (Block.lateBindingCopyBack))
+                                                       continue;
+                                       }
+                                       */
                                        VariableInfo vi = (VariableInfo) de.Value;
 
                                        if (vi.VariableType == null)
@@ -2898,25 +3371,50 @@ namespace Mono.CSharp {
                                        b.UsageWarning ();
                }
 
+               bool has_ret = false;
+
                public override bool Resolve (EmitContext ec)
                {
                        Block prev_block = ec.CurrentBlock;
                        bool ok = true;
 
                        ec.CurrentBlock = this;
-                       ec.StartFlowBranching (this);
-
-                       Report.Debug (1, "RESOLVE BLOCK", StartLocation);
 
                        if (!variables_initialized)
                                UpdateVariableInfo (ec);
 
-                       foreach (Statement s in statements){
-                               if (s.Resolve (ec) == false)
-                                       ok = false;
+                       ec.StartFlowBranching (this);
+
+                       Report.Debug (1, "RESOLVE BLOCK", StartLocation, ec.CurrentBranching);
+
+                       ArrayList new_statements = new ArrayList ();
+                       bool unreachable = false, warning_shown = false;
+
+                       foreach (Statement s in statements){
+                               if (unreachable && !(s is LabeledStatement)) {
+                                       if (!warning_shown && !(s is EmptyStatement)) {
+                                               warning_shown = true;
+                                               Warning_DeadCodeFound (s.loc);
+                                       }
+                                       continue;
+                               }
+
+                               if (s.Resolve (ec) == false) {
+                                       ok = false;
+                                       continue;
+                               }
+
+                               if (s is LabeledStatement)
+                                       unreachable = false;
+                               else
+                                       unreachable = ! ec.CurrentBranching.IsReachable ();
+
+                               new_statements.Add (s);
                        }
 
-                       Report.Debug (1, "RESOLVE BLOCK DONE", StartLocation);
+                       statements = new_statements;
+
+                       Report.Debug (1, "RESOLVE BLOCK DONE", StartLocation, ec.CurrentBranching);
 
                        FlowReturns returns = ec.EndFlowBranching ();
                        ec.CurrentBlock = prev_block;
@@ -2934,53 +3432,306 @@ namespace Mono.CSharp {
                                                                "This label has not been referenced");
                        }
 
+                       if ((returns == FlowReturns.ALWAYS) ||
+                           (returns == FlowReturns.EXCEPTION) ||
+                           (returns == FlowReturns.UNREACHABLE))
+                               has_ret = true;
+
                        return ok;
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
-                       bool is_ret = false, this_ret = false;
                        Block prev_block = ec.CurrentBlock;
-                       bool warning_shown = false;
 
                        ec.CurrentBlock = this;
 
-                       if (CodeGen.SymbolWriter != null) {
-                               ec.Mark (StartLocation);
+                       ec.Mark (StartLocation);
+                       foreach (Statement s in statements)
+                               s.Emit (ec);
                                
-                               foreach (Statement s in statements) {
-                                       ec.Mark (s.loc);
-                                       
-                                       if (is_ret && !warning_shown && !(s is EmptyStatement)){
-                                               warning_shown = true;
-                                               Warning_DeadCodeFound (s.loc);
-                                       }
-                                       this_ret = s.Emit (ec);
-                                       if (this_ret)
-                                               is_ret = true;
+                       ec.Mark (EndLocation); 
+                       
+                       ec.CurrentBlock = prev_block;
+                       return has_ret;
+               }
+       }
+
+       public class StatementSequence : Expression {
+               Block stmtBlock;
+               ArrayList args, originalArgs;
+               Expression expr;
+               bool isRetValRequired;
+               bool isLeftHandSide;
+               bool isIndexerAccess;
+               string memberName;
+               Expression type_expr;
+
+               public StatementSequence (Block parent, Location loc, Expression expr) 
+                       : this (parent, loc, expr, null)
+               { }
+
+               public StatementSequence (Block parent, Location loc, Expression expr, string name, 
+                                         Expression type_expr, ArrayList a, bool isRetValRequired,
+                                         bool isLeftHandSide) 
+                       : this (parent, loc, expr, a)
+               {
+                       this.memberName = name;
+                       this.type_expr = type_expr;
+                       this.isRetValRequired = isRetValRequired;
+                       this.isLeftHandSide = isLeftHandSide;
+               }
+
+               public StatementSequence (Block parent, Location loc, Expression expr, ArrayList a,
+                                         bool isRetValRequired, bool isLeftHandSide) 
+                       : this (parent, loc, expr, a)
+               {
+                       this.isRetValRequired = isRetValRequired;
+                       this.isLeftHandSide = isLeftHandSide;
+                       if (expr is MemberAccess) {
+                               this.expr = ((MemberAccess)expr).Expr;
+                               this.memberName = ((MemberAccess)expr).Identifier;
+                               this.isIndexerAccess = false;
+                       } else if (expr is IndexerAccess) {
+                               this.expr = ((IndexerAccess) expr).Instance;
+                               this.memberName = "";
+                               this.isIndexerAccess = true;
+                       }
+               }
+
+               public StatementSequence (Block parent, Location loc, Expression expr, ArrayList a) 
+               {
+                       stmtBlock = new Block (parent);
+                       args = a;
+                       originalArgs = new ArrayList ();
+                       if (args != null) {
+                               for (int index = 0; index < a.Count; index ++) {
+                                       Argument argument = (Argument) args [index];
+                                       originalArgs.Add (new Argument (argument.Expr, argument.ArgType));
                                }
+                       }
 
-                               ec.Mark (EndLocation); 
-                       } else {
-                               foreach (Statement s in statements){
-                                       if (is_ret && !warning_shown && !(s is EmptyStatement)){
-                                               warning_shown = true;
-                                               Warning_DeadCodeFound (s.loc);
-                                       }
-                                       this_ret = s.Emit (ec);
-                                       if (this_ret)
-                                               is_ret = true;
+                       this.expr = expr;
+                       stmtBlock.IsLateBindingRequired = true;
+                       this.loc = loc;
+                       this.isRetValRequired = this.isLeftHandSide = false;
+                       this.memberName = "";
+                       this.type_expr = null;
+               }
+
+               public ArrayList Arguments {
+                       get {
+                               return args;
+                       }
+                       set {
+                               args = value;
+                       }
+               }
+
+               public bool IsLeftHandSide {
+                       set {
+                               isLeftHandSide = value;
+                       }
+               }
+
+               public Block StmtBlock {
+                       get {
+                               return stmtBlock;
+                       }
+               }
+               
+               public override Expression DoResolve (EmitContext ec)
+               {
+                       if (!stmtBlock.Resolve (ec))
+                               return null;
+                       eclass = ExprClass.Value;
+                       type = TypeManager.object_type;
+                       return this;
+               }
+
+               public bool ResolveArguments (EmitContext ec) {
+               
+                       bool argNamesFound = false;
+                       if (Arguments != null)
+                       {
+                               for (int index = 0; index < Arguments.Count; index ++)
+                               {
+                                       Argument a = (Argument) Arguments [index];
+                                       if (a.ParamName == null || a.ParamName == "") {
+                                               if (argNamesFound) {
+                                                       Report.Error (30241, loc, "Named Argument expected");
+                                                       return false;
+                                               }
+                                       } else
+                                               argNamesFound = true;
+                                       if (a.ArgType == Argument.AType.NoArg)
+                                               a = new Argument (Parser.DecomposeQI ("System.Reflection.Missing.Value", loc), Argument.AType.Expression);
+                                       if (!a.Resolve (ec, loc))
+                                               return false;                           
+                                       Arguments [index] = a;
                                }
                        }
+                       return true;
+               }
                        
-                       ec.CurrentBlock = prev_block;
-                       return is_ret;
+               public void GenerateLateBindingStatements ()
+               {
+                       int argCount = 0;
+                       ArrayList arrayInitializers = new ArrayList ();
+                       ArrayList ArgumentNames = null;
+                       if (args != null) {
+                               //arrayInitializers = new ArrayList ();
+                               argCount = args.Count;
+                               for (int index = 0; index < args.Count; index ++) {
+                                       Argument a = (Argument) args [index];
+                                       Expression argument = a.Expr;
+                                       arrayInitializers.Add (argument);
+                                       if (a.ParamName != null && a.ParamName != "") {
+                                               if (ArgumentNames == null)
+                                                       ArgumentNames = new ArrayList ();
+                                               ArgumentNames.Add (new StringLiteral (a.ParamName));
+                                       }
+                               }
+                       }
+
+                       // __LateBindingArgs = new Object () {arg1, arg2 ...}
+                       ArrayCreation new_expr = new ArrayCreation (Parser.DecomposeQI ("System.Object",  loc), "[]", arrayInitializers, loc);
+                       Assign assign_stmt = null;
+
+                       LocalVariableReference v1 = new LocalVariableReference (stmtBlock, Block.lateBindingArgs, loc);
+                       assign_stmt = new Assign (v1, new_expr, loc);
+                       stmtBlock.AddStatement (new StatementExpression ((ExpressionStatement) assign_stmt, loc));
+                       // __LateBindingArgNames = new string () { argument names}
+                       LocalVariableReference v2 = null;
+                       if (ArgumentNames != null && ArgumentNames.Count > 0) {
+                               new_expr = new ArrayCreation (Parser.DecomposeQI ("System.String",  loc), "[]", ArgumentNames, loc);
+                               v2 = new LocalVariableReference (stmtBlock, Block.lateBindingArgNames, loc);
+                               assign_stmt = new Assign (v2, new_expr, loc);
+                               stmtBlock.AddStatement (new StatementExpression ((ExpressionStatement) assign_stmt, loc));
+                       }
+
+                       //string memName = "";
+                       //bool isIndexerAccess = true;
+
+                       ArrayList invocationArgs = new ArrayList ();
+                       if (isIndexerAccess || memberName == "") {
+                               invocationArgs.Add (new Argument (expr, Argument.AType.Expression));
+                               invocationArgs.Add (new Argument (v1, Argument.AType.Expression));
+                               invocationArgs.Add (new Argument (NullLiteral.Null, Argument.AType.Expression));
+                               Expression tmp = null;
+                               if (!isLeftHandSide)
+                                       tmp = Parser.DecomposeQI ("Microsoft.VisualBasic.CompilerServices.LateBinding.LateIndexGet", loc);
+                               else
+                                       tmp = Parser.DecomposeQI ("Microsoft.VisualBasic.CompilerServices.LateBinding.LateIndexSet", loc);
+                               Invocation invStmt = new Invocation (tmp, invocationArgs, Location.Null);
+                               invStmt.IsLateBinding = true;
+                               stmtBlock.AddStatement (new StatementExpression ((ExpressionStatement) invStmt, loc));
+                               return;
+                       }
+
+                       if (expr != null)
+                               invocationArgs.Add (new Argument (expr, Argument.AType.Expression));
+                       else
+                               invocationArgs.Add (new Argument (NullLiteral.Null, Argument.AType.Expression));
+                       if (type_expr != null)
+                               invocationArgs.Add (new Argument (type_expr, Argument.AType.Expression));
+                       else
+                               invocationArgs.Add (new Argument (NullLiteral.Null, Argument.AType.Expression));
+                       invocationArgs.Add (new Argument (new StringLiteral (memberName), Argument.AType.Expression));
+                       invocationArgs.Add (new Argument (v1, Argument.AType.Expression));
+                       if (ArgumentNames != null && ArgumentNames.Count > 0)
+                               invocationArgs.Add (new Argument (v2, Argument.AType.Expression));
+                       else
+                               invocationArgs.Add (new Argument (NullLiteral.Null, Argument.AType.Expression));
+
+                       // __LateBindingCopyBack = new Boolean (no_of_args) {}
+                       bool isCopyBackRequired = false;
+                       if (!isLeftHandSide) {
+                               for (int i = 0; i < argCount; i++) {
+                                       Argument origArg = (Argument) Arguments [i];
+                                       Expression origExpr = origArg.Expr; 
+                                       if (!(origExpr is Constant || origArg.ArgType == Argument.AType.NoArg)) 
+                                               isCopyBackRequired = true;
+                               }
+                       }
+
+                       LocalVariableReference v3 = new LocalVariableReference (stmtBlock, Block.lateBindingCopyBack, loc);
+                       if (isCopyBackRequired) {
+                               ArrayList rank_specifier = new ArrayList ();
+                               rank_specifier.Add (new IntLiteral (argCount));
+                               arrayInitializers = new ArrayList ();
+                               for (int i = 0; i < argCount; i++) {
+                                       Argument a = (Argument) Arguments [i];
+                                       Expression origExpr = a.Expr;
+                                       if (origExpr is Constant || a.ArgType == Argument.AType.NoArg || origExpr is New)
+                                               arrayInitializers.Add (new BoolLiteral (false));
+                                       else 
+                                               arrayInitializers.Add (new BoolLiteral (true));
+                               }
+       
+                               new_expr = new ArrayCreation (Parser.DecomposeQI ("System.Boolean",  loc), "[]", arrayInitializers, loc);
+                               assign_stmt = new Assign (v3, new_expr, loc);
+                               stmtBlock.AddStatement (new StatementExpression ((ExpressionStatement) assign_stmt, loc));
+                               invocationArgs.Add (new Argument (v3, Argument.AType.Expression));
+                       } else if (! isLeftHandSide) {
+                               invocationArgs.Add (new Argument (NullLiteral.Null, Argument.AType.Expression));
+                       }
+
+                       Expression etmp = null;
+                       if (isLeftHandSide) {
+                               // LateSet
+                               etmp = Parser.DecomposeQI ("Microsoft.VisualBasic.CompilerServices.LateBinding.LateSet", loc);
+                       } else if (isRetValRequired) {
+                               // Late Get
+                               etmp = Parser.DecomposeQI ("Microsoft.VisualBasic.CompilerServices.LateBinding.LateGet", loc);
+                       }  else {
+                               etmp = Parser.DecomposeQI ("Microsoft.VisualBasic.CompilerServices.LateBinding.LateCall", loc);
+                       }
+
+                       Invocation inv_stmt = new Invocation (etmp, invocationArgs, Location.Null);
+                       inv_stmt.IsLateBinding = true;
+                       stmtBlock.AddStatement (new StatementExpression ((ExpressionStatement) inv_stmt, loc));
+
+                       if (! isCopyBackRequired)
+                               return;
+
+                       for (int i = argCount - 1; i >= 0; i --) {
+                               Argument arg = (Argument) originalArgs [i];
+                               Expression origExpr = (Expression) arg.Expr;
+                               if (arg.ArgType == Argument.AType.NoArg)
+                                       continue;
+                               if (origExpr is Constant)
+                                       continue;
+                               if (origExpr is New)
+                                       continue;
+
+                               Expression intExpr = new IntLiteral (i);
+                               ArrayList argsLocal = new ArrayList ();
+                               argsLocal.Add (new Argument (intExpr, Argument.AType.Expression));
+                               Expression indexExpr = new Invocation (new SimpleName (Block.lateBindingCopyBack, loc), argsLocal, loc);
+                               Expression value = new Invocation (new SimpleName (Block.lateBindingArgs, loc), argsLocal, loc);
+                               assign_stmt = new Assign (origExpr, value,  loc);
+                               Expression boolExpr = new Binary (Binary.Operator.Inequality, indexExpr, new BoolLiteral (false), loc);
+                               Statement ifStmt = new If (boolExpr, new StatementExpression ((ExpressionStatement) assign_stmt, loc), loc);
+                               stmtBlock.AddStatement (ifStmt);
+                       }
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       stmtBlock.Emit (ec);
                }
        }
 
        public class SwitchLabel {
-               Expression label;
-               object converted;
+               public enum LabelType : byte {
+                       Operator, Range, Label, Else
+               }
+
+               Expression label, start, end;
+               LabelType label_type;
+               Expression label_condition, start_condition, end_condition;
+               Binary.Operator oper;
                public Location loc;
                public Label ILLabel;
                public Label ILLabelCode;
@@ -2988,10 +3739,23 @@ namespace Mono.CSharp {
                //
                // if expr == null, then it is the default case.
                //
-               public SwitchLabel (Expression expr, Location l)
+               public SwitchLabel (Expression start, Expression end, LabelType ltype, Binary.Operator oper, Location l) {
+                       this.start = start;
+                       this.end = end;
+                       this.label_type = ltype;
+                       this.oper = oper;
+                       this.loc = l;
+                       label_condition = start_condition = end_condition = null;
+               }
+
+               public SwitchLabel (Expression expr, LabelType ltype, Binary.Operator oper, Location l)
                {
                        label = expr;
+                       start = end = null;
+                       label_condition = start_condition = end_condition = null;
                        loc = l;
+                       this.label_type = ltype;
+                       this.oper = oper;
                }
 
                public Expression Label {
@@ -3000,9 +3764,27 @@ namespace Mono.CSharp {
                        }
                }
 
-               public object Converted {
+               public LabelType Type {
                        get {
-                               return converted;
+                               return label_type;
+                       }
+               }
+
+               public Expression ConditionStart {
+                       get {
+                               return start_condition;
+                       }
+               }
+
+               public Expression ConditionEnd {
+                       get {
+                               return end_condition;
+                       }
+               }
+
+               public Expression ConditionLabel {
+                       get {
+                               return label_condition;
                        }
                }
 
@@ -3010,37 +3792,55 @@ namespace Mono.CSharp {
                // Resolves the expression, reduces it to a literal if possible
                // and then converts it to the requested type.
                //
-               public bool ResolveAndReduce (EmitContext ec, Type required_type)
+               public bool ResolveAndReduce (EmitContext ec, Expression expr)
                {
                        ILLabel = ec.ig.DefineLabel ();
                        ILLabelCode = ec.ig.DefineLabel ();
 
-                       if (label == null)
+                       Expression e = null;
+                       switch (label_type) {
+                       case LabelType.Label :
+                               if (label == null)
+                                       return false;
+                               e = label.Resolve (ec);
+                               if (e != null)
+                                       e = Expression.ConvertImplicit (ec, e, expr.Type, loc);
+                               if (e == null)
+                                       return false;
+                               label_condition = new Binary (Binary.Operator.Equality, expr, e, loc);
+                               if ((label_condition = label_condition.DoResolve (ec)) == null)
+                                       return false;
+                               return true;
+                       case LabelType.Operator :
+                               e = label.Resolve (ec);
+                               label_condition = new Binary (oper, expr, e, loc);
+                               if ((label_condition = label_condition.DoResolve (ec)) == null)
+                                       return false;
+                               return true;
+                       case LabelType.Range :
+                               if (start == null || end == null)
+                                       return false;
+                               e = start.Resolve (ec);
+                               if (e != null)
+                                       e = Expression.ConvertImplicit (ec, e, expr.Type, loc);
+                               if (e == null)
+                                       return false;
+                               start_condition = new Binary (Binary.Operator.GreaterThanOrEqual, expr, e, loc);
+                               start_condition = start_condition.Resolve (ec);
+                               e = end.Resolve (ec);
+                               if (e != null)
+                                       e = Expression.ConvertImplicit (ec, e, expr.Type, loc);
+                               if (e == null)
+                                       return false;
+                               end_condition = new Binary (Binary.Operator.LessThanOrEqual, expr, e, loc);
+                               end_condition = end_condition.Resolve (ec);
+                               if (start_condition == null || end_condition == null)
+                                       return false;
                                return true;
-                       
-                       Expression e = label.Resolve (ec);
-
-                       if (e == null)
-                               return false;
-
-                       if (!(e is Constant)){
-                               Console.WriteLine ("Value is: " + label);
-                               Report.Error (150, loc, "A constant value is expected");
-                               return false;
-                       }
 
-                       if (e is StringConstant || e is NullLiteral){
-                               if (required_type == TypeManager.string_type){
-                                       converted = label;
-                                       ILLabel = ec.ig.DefineLabel ();
-                                       return true;
-                               }
+                       case LabelType.Else :
+                               break;
                        }
-
-                       converted = Expression.ConvertIntLiteral ((Constant) e, required_type, loc);
-                       if (converted == null)
-                               return false;
-
                        return true;
                }
        }
@@ -3082,7 +3882,7 @@ namespace Mono.CSharp {
                // The types allowed to be implicitly cast from
                // on the governing type
                //
-               static Type [] allowed_types;
+               //static Type [] allowed_types;
                
                public Switch (Expression e, ArrayList sects, Location l)
                {
@@ -3111,20 +3911,21 @@ namespace Mono.CSharp {
                //
                Expression SwitchGoverningType (EmitContext ec, Type t)
                {
-                       if (t == TypeManager.int32_type ||
-                           t == TypeManager.uint32_type ||
-                           t == TypeManager.char_type ||
-                           t == TypeManager.byte_type ||
-                           t == TypeManager.sbyte_type ||
-                           t == TypeManager.ushort_type ||
+                       if (t == TypeManager.byte_type ||
                            t == TypeManager.short_type ||
-                           t == TypeManager.uint64_type ||
+                           t == TypeManager.int32_type ||
                            t == TypeManager.int64_type ||
+                           t == TypeManager.decimal_type ||
+                           t == TypeManager.float_type ||
+                           t == TypeManager.double_type ||
+                           t == TypeManager.date_type ||
+                           t == TypeManager.char_type ||
+                           t == TypeManager.object_type ||
                            t == TypeManager.string_type ||
                                t == TypeManager.bool_type ||
                                t.IsSubclassOf (TypeManager.enum_type))
                                return Expr;
-
+/*
                        if (allowed_types == null){
                                allowed_types = new Type [] {
                                        TypeManager.sbyte_type,
@@ -3158,12 +3959,14 @@ 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;
                        }
                        return converted;
+*/
+                       return null;
                }
 
                void error152 (string n)
@@ -3182,25 +3985,29 @@ namespace Mono.CSharp {
                //
                bool CheckSwitch (EmitContext ec)
                {
-                       Type compare_type;
+                       //Type compare_type;
                        bool error = false;
-                       Elements = new Hashtable ();
+                       Elements = new CaseInsensitiveHashtable ();
                                
                        got_default = false;
 
+/*
                        if (TypeManager.IsEnumType (SwitchType)){
                                compare_type = TypeManager.EnumToUnderlying (SwitchType);
                        } else
                                compare_type = SwitchType;
+*/
                        
-                       foreach (SwitchSection ss in Sections){
-                               foreach (SwitchLabel sl in ss.Labels){
-                                       if (!sl.ResolveAndReduce (ec, SwitchType)){
+                       for (int secIndex = 0; secIndex < Sections.Count; secIndex ++) {
+                               SwitchSection ss = (SwitchSection) Sections [secIndex];
+                               for (int labelIndex = 0; labelIndex < ss.Labels.Count; labelIndex ++) {
+                                       SwitchLabel sl  = (SwitchLabel) ss.Labels [labelIndex];
+                                       if (!sl.ResolveAndReduce (ec, Expr)){
                                                error = true;
                                                continue;
                                        }
 
-                                       if (sl.Label == null){
+                                       if (sl.Type == SwitchLabel.LabelType.Else){
                                                if (got_default){
                                                        error152 ("default");
                                                        error = true;
@@ -3208,111 +4015,6 @@ namespace Mono.CSharp {
                                                got_default = true;
                                                continue;
                                        }
-                                       
-                                       object key = sl.Converted;
-
-                                       if (key is Constant)
-                                               key = ((Constant) key).GetValue ();
-
-                                       if (key == null)
-                                               key = NullLiteral.Null;
-                                       
-                                       string lname = null;
-                                       if (compare_type == TypeManager.uint64_type){
-                                               ulong v = (ulong) key;
-
-                                               if (Elements.Contains (v))
-                                                       lname = v.ToString ();
-                                               else
-                                                       Elements.Add (v, sl);
-                                       } else if (compare_type == TypeManager.int64_type){
-                                               long v = (long) key;
-
-                                               if (Elements.Contains (v))
-                                                       lname = v.ToString ();
-                                               else
-                                                       Elements.Add (v, sl);
-                                       } else if (compare_type == TypeManager.uint32_type){
-                                               uint v = (uint) key;
-
-                                               if (Elements.Contains (v))
-                                                       lname = v.ToString ();
-                                               else
-                                                       Elements.Add (v, sl);
-                                       } else if (compare_type == TypeManager.char_type){
-                                               char v = (char) key;
-                                               
-                                               if (Elements.Contains (v))
-                                                       lname = v.ToString ();
-                                               else
-                                                       Elements.Add (v, sl);
-                                       } else if (compare_type == TypeManager.byte_type){
-                                               byte v = (byte) key;
-                                               
-                                               if (Elements.Contains (v))
-                                                       lname = v.ToString ();
-                                               else
-                                                       Elements.Add (v, sl);
-                                       } else if (compare_type == TypeManager.sbyte_type){
-                                               sbyte v = (sbyte) key;
-                                               
-                                               if (Elements.Contains (v))
-                                                       lname = v.ToString ();
-                                               else
-                                                       Elements.Add (v, sl);
-                                       } else if (compare_type == TypeManager.short_type){
-                                               short v = (short) key;
-                                               
-                                               if (Elements.Contains (v))
-                                                       lname = v.ToString ();
-                                               else
-                                                       Elements.Add (v, sl);
-                                       } else if (compare_type == TypeManager.ushort_type){
-                                               ushort v = (ushort) key;
-                                               
-                                               if (Elements.Contains (v))
-                                                       lname = v.ToString ();
-                                               else
-                                                       Elements.Add (v, sl);
-                                       } else if (compare_type == TypeManager.string_type){
-                                               if (key is NullLiteral){
-                                                       if (Elements.Contains (NullLiteral.Null))
-                                                               lname = "null";
-                                                       else
-                                                               Elements.Add (NullLiteral.Null, null);
-                                               } else {
-                                                       string s = (string) key;
-
-                                                       if (Elements.Contains (s))
-                                                               lname = s;
-                                                       else
-                                                               Elements.Add (s, sl);
-                                               }
-                                       } else if (compare_type == TypeManager.int32_type) {
-                                               int v = (int) key;
-
-                                               if (Elements.Contains (v))
-                                                       lname = v.ToString ();
-                                               else
-                                                       Elements.Add (v, sl);
-                                       } else if (compare_type == TypeManager.bool_type) {
-                                               bool v = (bool) key;
-
-                                               if (Elements.Contains (v))
-                                                       lname = v.ToString ();
-                                               else
-                                                       Elements.Add (v, sl);
-                                       }
-                                       else
-                                       {
-                                               throw new Exception ("Unknown switch type!" +
-                                                                    SwitchType + " " + compare_type);
-                                       }
-
-                                       if (lname != null){
-                                               error152 ("case + " + lname);
-                                               error = true;
-                                       }
                                }
                        }
                        if (error)
@@ -3397,6 +4099,7 @@ namespace Mono.CSharp {
                        }
                }
 
+/*
                /// <summary>
                /// This method emits code for a lookup-based switch statement (non-string)
                /// Basically it groups the cases into blocks that are at least half full,
@@ -3580,7 +4283,8 @@ namespace Mono.CSharp {
                                                fFoundDefault = true;
                                        }
                                }
-                               fAllReturn &= ss.Block.Emit (ec);
+                               bool returns = ss.Block.Emit (ec);
+                               fAllReturn &= returns;
                                //ig.Emit (OpCodes.Br, lblEnd);
                        }
                        
@@ -3628,9 +4332,6 @@ namespace Mono.CSharp {
                                ig.Emit (OpCodes.Call, TypeManager.string_isinterneted_string);
                                ig.Emit (OpCodes.Stloc, val);
                        }
-
-                       SwitchSection last_section;
-                       last_section = (SwitchSection) Sections [Sections.Count-1];
                        
                        foreach (SwitchSection ss in Sections){
                                Label sec_begin = ig.DefineLabel ();
@@ -3683,7 +4384,7 @@ namespace Mono.CSharp {
                                                }
                                        }
                                }
-                               if (label_count != 1 && ss != last_section)
+                               if (label_count != 1)
                                        ig.Emit (OpCodes.Br, next_test);
                                
                                if (null_found)
@@ -3691,7 +4392,9 @@ namespace Mono.CSharp {
                                ig.MarkLabel (sec_begin);
                                foreach (SwitchLabel sl in ss.Labels)
                                        ig.MarkLabel (sl.ILLabelCode);
-                               if (ss.Block.Emit (ec))
+
+                               bool returns = ss.Block.Emit (ec);
+                               if (returns)
                                        pending_goto_end = false;
                                else {
                                        all_return = false;
@@ -3708,6 +4411,7 @@ namespace Mono.CSharp {
                        
                        return all_return;
                }
+*/
 
                public override bool Resolve (EmitContext ec)
                {
@@ -3717,7 +4421,7 @@ namespace Mono.CSharp {
 
                        new_expr = SwitchGoverningType (ec, Expr.Type);
                        if (new_expr == null){
-                               Report.Error (151, loc, "An integer type or string was expected for switch");
+                               Report.Error (30338, loc, "'Select' expression cannot be of type '" + Expr.Type +"'");
                                return false;
                        }
 
@@ -3744,23 +4448,19 @@ namespace Mono.CSharp {
                                        return false;
                        }
 
+
+                       if (!got_default)
+                               ec.CurrentBranching.CreateSibling ();
+
                        ec.EndFlowBranching ();
                        ec.Switch = old_switch;
 
                        return true;
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
-                       // Store variable for comparission purposes
-                       LocalBuilder value = ec.ig.DeclareLocal (SwitchType);
-                       new_expr.Emit (ec);
-                       ec.ig.Emit (OpCodes.Stloc, value);
-
                        ILGenerator ig = ec.ig;
-
-                       default_target = ig.DefineLabel ();
-
                        //
                        // Setup the codegen context
                        //
@@ -3770,12 +4470,47 @@ namespace Mono.CSharp {
                        ec.LoopEnd = ig.DefineLabel ();
                        ec.Switch = this;
 
-                       // Emit Code.
-                       bool all_return;
-                       if (SwitchType == TypeManager.string_type)
-                               all_return = SimpleSwitchEmit (ec, value);
-                       else
-                               all_return = TableSwitchEmit (ec, value);
+                       for (int secIndex = 0; secIndex < Sections.Count; secIndex ++) {
+                               SwitchSection section = (SwitchSection) Sections [secIndex];
+                               Label sLabel = ig.DefineLabel ();
+                               Label lLabel = ig.DefineLabel ();
+                               ArrayList Labels = section.Labels;
+                               for (int labelIndex = 0; labelIndex < Labels.Count; labelIndex ++) {
+                                       SwitchLabel sl = (SwitchLabel) Labels [labelIndex];
+                                       switch (sl.Type) {
+                                       case SwitchLabel.LabelType.Range :
+                                               if (labelIndex + 1 == Labels.Count) {
+                                                       EmitBoolExpression (ec, sl.ConditionStart, sLabel, false);
+                                                       EmitBoolExpression (ec, sl.ConditionEnd, sLabel, false);
+                                                       ig.Emit (OpCodes.Br, lLabel);
+                                               } else {
+                                                       Label newLabel = ig.DefineLabel ();
+                                                       EmitBoolExpression (ec, sl.ConditionStart, newLabel, false);
+                                                       EmitBoolExpression (ec, sl.ConditionEnd, newLabel, false);
+                                                       ig.Emit (OpCodes.Br, lLabel);
+                                                       ig.MarkLabel (newLabel);
+                                               }
+                                               break;
+                                       case SwitchLabel.LabelType.Else :
+                                               // Nothing to be done here
+                                               break;
+                                       case SwitchLabel.LabelType.Operator :
+                                               EmitBoolExpression (ec, sl.ConditionLabel, lLabel, true);
+                                               if (labelIndex + 1 == Labels.Count)
+                                                       ig.Emit (OpCodes.Br, sLabel);
+                                               break;
+                                       case SwitchLabel.LabelType.Label :
+                                               EmitBoolExpression (ec, sl.ConditionLabel, lLabel, true);
+                                               if (labelIndex + 1 == Labels.Count)
+                                                       ig.Emit (OpCodes.Br, sLabel);
+                                               break;
+                                       }
+
+                               }
+                               ig.MarkLabel (lLabel);
+                               section.Block.Emit (ec);
+                               ig.MarkLabel (sLabel);
+                       }
 
                        // Restore context state. 
                        ig.MarkLabel (ec.LoopEnd);
@@ -3785,8 +4520,7 @@ namespace Mono.CSharp {
                        //
                        ec.LoopEnd = old_end;
                        ec.Switch = old_switch;
-                       
-                       return all_return;
+                       return true;
                }
        }
 
@@ -3807,15 +4541,15 @@ namespace Mono.CSharp {
                        return Statement.Resolve (ec) && expr != null;
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        Type type = expr.Type;
                        bool val;
                        
                        if (type.IsValueType){
-                               Report.Error (185, loc, "lock statement requires the expression to be " +
+                               Report.Error (30582, loc, "lock statement requires the expression to be " +
                                              " a reference type (type is: `" +
-                                             TypeManager.CSharpName (type) + "'");
+                                             TypeManager.MonoBASIC_Name (type) + "'");
                                return false;
                        }
 
@@ -3828,7 +4562,7 @@ namespace Mono.CSharp {
                        ig.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object);
 
                        // try
-                       Label end = ig.BeginExceptionBlock ();
+                       ig.BeginExceptionBlock ();
                        bool old_in_try = ec.InTry;
                        ec.InTry = true;
                        Label finish = ig.DefineLabel ();
@@ -3861,7 +4595,7 @@ namespace Mono.CSharp {
                        return Block.Resolve (ec);
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        bool previous_state = ec.CheckState;
                        bool previous_state_const = ec.ConstantCheckState;
@@ -3899,7 +4633,7 @@ namespace Mono.CSharp {
                        return ret;
                }
 
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        bool previous_state = ec.CheckState;
                        bool previous_state_const = ec.ConstantCheckState;
@@ -3935,7 +4669,7 @@ namespace Mono.CSharp {
                        return val;
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        bool previous_state = ec.InUnsafe;
                        bool val;
@@ -4085,7 +4819,7 @@ namespace Mono.CSharp {
                        return statement.Resolve (ec);
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
 
@@ -4170,47 +4904,55 @@ namespace Mono.CSharp {
        public class Catch {
                public readonly string Name;
                public readonly Block  Block;
+               public Expression Clause;
                public readonly Location Location;
 
-               Expression type;
+               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)
                {
-                       this.type = type;
+                       type_expr = type;
                        Name = name;
                        Block = block;
+                       Clause = clause;
                        Location = l;
                }
 
                public Type CatchType {
                        get {
-                               if (type == null)
-                                       throw new InvalidOperationException ();
-
-                               return type.Type;
+                               return type;
                        }
                }
 
                public bool IsGeneral {
                        get {
-                               return type == null;
+                               return type_expr == null;
                        }
                }
 
                public bool Resolve (EmitContext ec)
                {
-                       if (type != null) {
-                               type = type.DoResolve (ec);
+                       if (type_expr != null) {
+                               type = ec.DeclSpace.ResolveType (type_expr, false, Location);
                                if (type == null)
                                        return false;
 
-                               Type t = type.Type;
-                               if (t != TypeManager.exception_type && !t.IsSubclassOf (TypeManager.exception_type)){
-                                       Report.Error (155, Location,
+                               if (type != TypeManager.exception_type && !type.IsSubclassOf (TypeManager.exception_type)){
+                                       Report.Error (30665, Location,
                                                      "The type caught or thrown must be derived " +
                                                      "from System.Exception");
                                        return false;
                                }
+                       } else
+                               type = null;
+
+                       if (Clause != null)     {
+                               Clause = Statement.ResolveBoolean (ec, Clause, Location);
+                               if (Clause == null) {
+                                       return false;
+                               }
                        }
 
                        if (!Block.Resolve (ec))
@@ -4283,12 +5025,12 @@ namespace Mono.CSharp {
 
                                FlowBranching.UsageVector current = ec.CurrentBranching.CurrentUsageVector;
 
-                               if ((current.Returns == FlowReturns.NEVER) ||
-                                   (current.Returns == FlowReturns.SOMETIMES)) {
+                               if (!current.AlwaysReturns && !current.AlwaysBreaks)
                                        vector.AndLocals (current);
-                               }
                        }
 
+                       Report.Debug (1, "END OF CATCH BLOCKS", ec.CurrentBranching);
+
                        if (General != null){
                                ec.CurrentBranching.CreateSibling ();
                                Report.Debug (1, "STARTED SIBLING FOR GENERAL", ec.CurrentBranching);
@@ -4303,16 +5045,16 @@ namespace Mono.CSharp {
 
                                FlowBranching.UsageVector current = ec.CurrentBranching.CurrentUsageVector;
 
-                               if ((current.Returns == FlowReturns.NEVER) ||
-                                   (current.Returns == FlowReturns.SOMETIMES)) {
+                               if (!current.AlwaysReturns && !current.AlwaysBreaks)
                                        vector.AndLocals (current);
-                               }
                        }
 
-                       ec.CurrentBranching.CreateSiblingForFinally ();
-                       Report.Debug (1, "STARTED SIBLING FOR FINALLY", ec.CurrentBranching, vector);
+                       Report.Debug (1, "END OF GENERAL CATCH BLOCKS", ec.CurrentBranching);
 
                        if (Fini != null) {
+                               ec.CurrentBranching.CreateSiblingForFinally ();
+                               Report.Debug (1, "STARTED SIBLING FOR FINALLY", ec.CurrentBranching, vector);
+
                                bool old_in_finally = ec.InFinally;
                                ec.InFinally = true;
 
@@ -4322,16 +5064,11 @@ namespace Mono.CSharp {
                                ec.InFinally = old_in_finally;
                        }
 
-                       FlowBranching.UsageVector f_vector = ec.CurrentBranching.CurrentUsageVector;
-
                        FlowReturns returns = ec.EndFlowBranching ();
 
-                       Report.Debug (1, "END OF FINALLY", ec.CurrentBranching, returns, vector, f_vector);
-
-                       if ((returns == FlowReturns.SOMETIMES) || (returns == FlowReturns.ALWAYS)) {
-                               ec.CurrentBranching.CheckOutParameters (f_vector.Parameters, loc);
-                       }
+                       FlowBranching.UsageVector f_vector = ec.CurrentBranching.CurrentUsageVector;
 
+                       Report.Debug (1, "END OF FINALLY", ec.CurrentBranching, returns, vector, f_vector);
                        ec.CurrentBranching.CurrentUsageVector.Or (vector);
 
                        Report.Debug (1, "END OF TRY", ec.CurrentBranching);
@@ -4339,15 +5076,14 @@ namespace Mono.CSharp {
                        return ok;
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
-                       Label end;
                        Label finish = ig.DefineLabel ();;
                        bool returns;
 
                        ec.TryCatchLevel++;
-                       end = ig.BeginExceptionBlock ();
+                       ig.BeginExceptionBlock ();
                        bool old_in_try = ec.InTry;
                        ec.InTry = true;
                        returns = Block.Emit (ec);
@@ -4359,7 +5095,7 @@ namespace Mono.CSharp {
 
                        bool old_in_catch = ec.InCatch;
                        ec.InCatch = true;
-                       DeclSpace ds = ec.DeclSpace;
+                       //DeclSpace ds = ec.DeclSpace;
 
                        foreach (Catch c in Specific){
                                VariableInfo vi;
@@ -4374,17 +5110,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);
@@ -4415,10 +5181,6 @@ namespace Mono.CSharp {
                }
        }
 
-       //
-       // FIXME: We still do not support the expression variant of the using
-       // statement.
-       //
        public class Using : Statement {
                object expression_or_block;
                Statement Statement;
@@ -4462,7 +5224,7 @@ namespace Mono.CSharp {
                                        if (var == null)
                                                return false;
                                        
-                                       converted_vars [i] = Expression.ConvertImplicit (
+                                       converted_vars [i] = Expression.ConvertImplicitRequired (
                                                ec, var, TypeManager.idisposable_type, loc);
 
                                        if (converted_vars [i] == null)
@@ -4495,7 +5257,7 @@ namespace Mono.CSharp {
                bool ResolveExpression (EmitContext ec)
                {
                        if (!TypeManager.ImplementsInterface (expr_type, TypeManager.idisposable_type)){
-                               conv = Expression.ConvertImplicit (
+                               conv = Expression.ConvertImplicitRequired (
                                        ec, expr, TypeManager.idisposable_type, loc);
 
                                if (conv == null)
@@ -4603,7 +5365,7 @@ namespace Mono.CSharp {
                        return Statement.Resolve (ec);
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        if (expression_or_block is DictionaryEntry)
                                return EmitLocalVariableDecls (ec);
@@ -4615,7 +5377,7 @@ namespace Mono.CSharp {
        }
 
        /// <summary>
-       ///   Implementation of the foreach C# statement
+       ///   Implementation of the for each statement
        /// </summary>
        public class Foreach : Statement {
                Expression type;
@@ -4630,7 +5392,14 @@ namespace Mono.CSharp {
                public Foreach (Expression type, LocalVariableReference var, Expression expr,
                                Statement stmt, Location l)
                {
-                       this.type = type;
+                       if (type != null) {
+                               this.type = type;
+                       }
+                       else
+                       {
+                               VariableInfo vi = var.VariableInfo;
+                               this.type = vi.Type;
+                       }
                        this.variable = var;
                        this.expr = expr;
                        statement = stmt;
@@ -4638,7 +5407,7 @@ namespace Mono.CSharp {
                }
                
                public override bool Resolve (EmitContext ec)
-               {
+               {       
                        expr = expr.Resolve (ec);
                        if (expr == null)
                                return false;
@@ -4655,7 +5424,7 @@ namespace Mono.CSharp {
                        // out to return values in ExprClass?  I think they should.
                        //
                        if (!(expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.Value ||
-                             expr.eclass == ExprClass.PropertyAccess)){
+                             expr.eclass == ExprClass.PropertyAccess || expr.eclass == ExprClass.IndexerAccess)){
                                error1579 (expr.Type);
                                return false;
                        }
@@ -4678,6 +5447,10 @@ namespace Mono.CSharp {
                                empty = new EmptyExpression (hm.element_type);
                        }
 
+                       ec.StartFlowBranching (FlowBranchingType.LOOP_BLOCK, loc);
+                       ec.CurrentBranching.CreateSibling ();
+
+                       //
                        //
                        // FIXME: maybe we can apply the same trick we do in the
                        // array handling to avoid creating empty and conv in some cases.
@@ -4685,16 +5458,18 @@ 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;
 
                        if (variable.ResolveLValue (ec, empty) == null)
                                return false;
-
+                       
                        if (!statement.Resolve (ec))
                                return false;
 
+                       //FlowReturns returns = ec.EndFlowBranching ();
+                       ec.EndFlowBranching ();
                        return true;
                }
                
@@ -4965,11 +5740,10 @@ namespace Mono.CSharp {
                        // Protect the code in a try/finalize block, so that
                        // if the beast implement IDisposable, we get rid of it
                        //
-                       Label l;
                        bool old_in_try = ec.InTry;
 
                        if (hm.is_disposable) {
-                               l = ig.BeginExceptionBlock ();
+                               ig.BeginExceptionBlock ();
                                ec.InTry = true;
                        }
                        
@@ -5136,7 +5910,7 @@ namespace Mono.CSharp {
                        return false;
                }
                
-               public override bool Emit (EmitContext ec)
+               protected override bool DoEmit (EmitContext ec)
                {
                        bool ret_val;
                        
@@ -5163,5 +5937,264 @@ namespace Mono.CSharp {
                        return ret_val;
                }
        }
-}
+       
+       /// <summary>
+       ///   AddHandler statement
+       /// </summary>
+       public class AddHandler : Statement {
+               Expression EvtId;
+               Expression EvtHandler;
+
+               //
+               // 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;
+                       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);
+                       if (EvtId == null || (!(EvtId is EventExpr))) {
+                               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)
+               {
+                       //
+                       // 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 ('+','.');
+                       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);
+                       e = new CompoundAssign(Binary.Operator.Addition, 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;
+               }
+       }
+
+       /// <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 (30415, "'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;
+               }               
+               
+       }
+       
+       
+}