2006-08-13 Miguel de Icaza <miguel@novell.com>
[mono.git] / mcs / mbas / statement.cs
index 5ffb5bb90efd055ba39e5b00f1c526b0aa1a9765..0914861a26983cae60906917d5bd93e3f00365eb 100644 (file)
@@ -812,6 +812,7 @@ namespace Mono.MonoBASIC {
                
                public Return (Expression expr, Location l)
                {
+                       expr = Parser.SetValueRequiredFlag (expr);
                        Expr = expr;
                        loc = l;
                }
@@ -829,8 +830,10 @@ namespace Mono.MonoBASIC {
                        if (ec.CurrentBranching.InTryBlock ())
                                ec.CurrentBranching.AddFinallyVector (vector);
 
-                       vector.Returns = FlowReturns.ALWAYS;
-                       vector.Breaks = FlowReturns.ALWAYS;
+                       if (! ec.InTry && ! ec.InCatch) {
+                               vector.Returns = FlowReturns.ALWAYS;
+                               vector.Breaks = FlowReturns.ALWAYS;
+                       }
                        return true;
                }
                
@@ -932,7 +935,7 @@ namespace Mono.MonoBASIC {
 
        public class LabeledStatement : Statement {
                public readonly Location Location;
-               //string label_name;
+               string label_name;
                bool defined;
                bool referenced;
                Label label;
@@ -941,9 +944,15 @@ namespace Mono.MonoBASIC {
                
                public LabeledStatement (string label_name, Location l)
                {
-                       //this.label_name = label_name;
+                       this.label_name = label_name;
                        this.Location = l;
                }
+               
+               public string LabelName {
+                       get {
+                               return label_name;
+                       }
+               }
 
                public Label LabelTarget (EmitContext ec)
                {
@@ -1280,11 +1289,8 @@ namespace Mono.MonoBASIC {
                                }
                        
                                if (ec.InTry || ec.InCatch) {
-                                       if (!ec.HasReturnLabel) {
-                                               ec.ReturnLabel = ec.ig.DefineLabel ();
-                                               ec.HasReturnLabel = true;
-                                       }
-                                       ec.ig.Emit (OpCodes.Leave, ec.ReturnLabel);
+                                       if (ec.HasExitLabel)
+                                               ec.ig.Emit (OpCodes.Leave, ec.ExitLabel);
                                } else {
                                        if(type == ExitType.SUB) {   
                                                 ec.ig.Emit (OpCodes.Ret);
@@ -2673,17 +2679,7 @@ namespace Mono.MonoBASIC {
                public LocalBuilder LocalBuilder;
                public Type VariableType;
                public string Alias;
-               
-               bool mod_static;
-               public bool Static {
-                       get {
-                               return mod_static;
-                       }
-                       set {
-                               mod_static = value;
-                       }
-               }
-
+               FieldBase FieldAlias;
                public readonly string Name;
                public readonly Location Location;
                public readonly int Block;
@@ -2799,6 +2795,24 @@ namespace Mono.MonoBASIC {
                                ec.CurrentBranching.SetVariableAssigned (this, StructInfo [name]);
                }
 
+               public FieldBase GetFieldAlias (EmitContext ec)  {
+                       if ( this.FieldAlias != null )
+                               return this.FieldAlias;
+                       else
+                       {
+                               ArrayList fields = ec.TypeContainer.Fields;
+                                for (int i = 0; i < fields.Count; i++) 
+                               {
+                                       if (((Field) fields[i]).Name == this.Alias) 
+                                       {
+                                               this.FieldAlias = (Field) fields[i];
+                                               break;
+                                       }
+                               }
+                               return this.FieldAlias;
+                       }
+               }
+               
                public bool Resolve (DeclSpace decl)
                {
                        if (struct_info != null)
@@ -2836,6 +2850,7 @@ namespace Mono.MonoBASIC {
                bool isIndexerAccess;
                string memberName;
                Expression type_expr;
+               bool is_resolved = false;
 
                public StatementSequence (Block parent, Location loc, Expression expr) 
                        : this (parent, loc, expr, null)
@@ -2912,10 +2927,13 @@ namespace Mono.MonoBASIC {
                
                public override Expression DoResolve (EmitContext ec)
                {
+                       if (is_resolved)
+                               return this;
                        if (!stmtBlock.Resolve (ec))
                                return null;
                        eclass = ExprClass.Value;
                        type = TypeManager.object_type;
+                       is_resolved = true;
                        return this;
                }
 
@@ -4449,11 +4467,13 @@ namespace Mono.MonoBASIC {
                protected override bool DoEmit (EmitContext ec)
                {
                        ILGenerator ig = ec.ig;
-                       Label finish = ig.DefineLabel ();;
                        bool returns;
 
                        ec.TryCatchLevel++;
-                       ig.BeginExceptionBlock ();
+                       Label finish = ig.BeginExceptionBlock ();
+                       ec.HasExitLabel = true;
+                       ec.ExitLabel = finish;
+
                        bool old_in_try = ec.InTry;
                        ec.InTry = true;
                        returns = Block.Emit (ec);
@@ -4523,7 +4543,6 @@ namespace Mono.MonoBASIC {
 
                        ec.InCatch = old_in_catch;
 
-                       ig.MarkLabel (finish);
                        if (Fini != null){
                                ig.BeginFinallyBlock ();
                                bool old_in_finally = ec.InFinally;
@@ -4538,6 +4557,202 @@ namespace Mono.MonoBASIC {
                        if (!returns || ec.InTry || ec.InCatch)
                                return returns;
 
+                       return true;
+               }
+       }
+       
+       public  class Pending_Assign {
+               Statement assign;
+               Block block_to_be_inserted;
+               int statement_index;
+               
+               public Pending_Assign (Block block, Statement assign, int index)
+               {
+                       this.assign = assign;
+                       this.block_to_be_inserted = block;
+                       this.statement_index = index;
+               }
+
+               public  void AddAssign()
+               {
+                       block_to_be_inserted.statements.Insert( statement_index, assign );
+               }       
+       }
+       
+       public class On_Error : Statement {
+               public readonly Block method_block;
+               ArrayList targets;
+               LabeledStatement[] labeledstatements;
+               
+               public On_Error (Block method_block, Location l)
+               {       
+                       //Goto
+                       this.method_block = method_block;
+                       base.loc = l;
+                       targets = new ArrayList();
+               }
+
+               public int AddTarget ( string target )
+               {                               
+                       int i = targets.IndexOf( target ) ;
+                       
+                       if ( i == -1 ) 
+                               return targets.Add ( target );
+                       else
+                               return i;
+               }
+
+               public ArrayList Targets {
+                       get {
+                               return targets;
+                       }
+               }
+
+               public override bool Resolve (EmitContext ec)
+               {
+                       this.labeledstatements = new LabeledStatement[targets.Count];
+                       
+                       bool ok = true;
+                       
+                       ec.StartFlowBranching (FlowBranchingType.EXCEPTION, method_block.StartLocation);
+
+                       Report.Debug (1, "START OF TRY BLOCK", method_block.StartLocation);
+
+                       bool old_in_try = ec.InTry;
+                       ec.InTry = true;
+
+                       if (!method_block.Resolve (ec))
+                               ok = false;
+
+                       ec.InTry = old_in_try;
+
+                       FlowBranching.UsageVector vector = ec.CurrentBranching.CurrentUsageVector;
+
+                       ec.EndFlowBranching ();
+
+                       ec.CurrentBranching.CurrentUsageVector.Or (vector);
+
+                       Report.Debug (1, "END OF TRY", ec.CurrentBranching);
+
+                       //This statement has more than one label in cases of more than one 'on error goto' specification.
+                       for ( int i = 0 ; i < targets.Count ; i++ )
+                       {
+                               labeledstatements[i] = method_block.Parent.LookupLabel ((string) targets[i]);
+
+                               // If this is a forward goto.
+                               if (!labeledstatements[i].IsDefined)
+                                       labeledstatements[i].AddUsageVector (ec.CurrentBranching.CurrentUsageVector);
+
+                               labeledstatements[i].AddReference ();
+                       }
+                       ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
+                       
+                       return ok;
+               }
+               protected override bool DoEmit (EmitContext ec)
+               {       
+                       ILGenerator ig = ec.ig;
+                               
+                       //Try
+
+                       bool returns;
+
+                       ec.TryCatchLevel++;
+                       
+                       Label finish = ig.BeginExceptionBlock ();
+                               ec.HasExitLabel = true;
+                               ec.ExitLabel = finish;
+                               
+                               bool old_in_try = ec.InTry;
+                               ec.InTry = true;
+                               returns = method_block.Emit (ec);
+                               ec.InTry = old_in_try;
+                               bool old_in_catch = ec.InCatch;
+                               ec.InCatch = true;
+
+                       Label error = ig.DefineLabel();
+                       Label endfilter = ig.DefineLabel();
+                       Label verification = ig.DefineLabel();
+                       
+                       ig.BeginExceptFilterBlock();
+                               ig.Emit (OpCodes.Isinst, Type.GetType("System.Exception") );
+                               ig.Emit (OpCodes.Brtrue_S, verification );
+
+                               ig.Emit (OpCodes.Br_S, error);
+                       
+                               ig.MarkLabel ( verification );  
+                               ig.Emit (OpCodes.Ldloc_0);
+                               ig.Emit (OpCodes.Brfalse_S, error);
+                               
+                               ig.Emit (OpCodes.Ldloc_1);
+                               ig.Emit (OpCodes.Brtrue_S, error);
+
+                               ig.Emit (OpCodes.Ldc_I4_1);
+                               ig.Emit (OpCodes.Br_S, endfilter);
+                               
+                               ig.MarkLabel (error);   
+                               ig.Emit (OpCodes.Ldc_I4_0);
+
+                               ig.MarkLabel ( endfilter );     
+                       
+                       
+                       Label endcatch = ig.DefineLabel();              
+                       Label verification2 = ig.DefineLabel();
+                       
+                       ig.BeginCatchBlock (null);
+                               ig.Emit (OpCodes.Castclass, Type.GetType("System.Exception"));
+                               ig.Emit (OpCodes.Dup);
+
+                               Type t = typeof(Microsoft.VisualBasic.CompilerServices.ProjectData);
+                               MethodInfo mi = t.GetMethod("SetProjectError", new Type[] { typeof(System.Exception) } );
+                               ig.Emit (OpCodes.Call, mi);
+                               ig.Emit (OpCodes.Stloc_3);
+                               ig.Emit (OpCodes.Ldloc_1);
+                               ig.Emit (OpCodes.Brfalse_S, verification2 );
+                               ig.Emit (OpCodes.Leave_S, finish );
+                               ig.MarkLabel ( verification2 );
+                               ig.Emit (OpCodes.Ldc_I4_M1);
+                               ig.Emit (OpCodes.Stloc_1);
+                               ig.Emit (OpCodes.Ldloc_0);
+
+                               Label[] lbswitch = new Label[targets.Count + 1];
+                               for ( int i = 0; i <= targets.Count; i++ )
+                                       lbswitch[i] = ig.DefineLabel();
+                               
+                               ig.Emit (OpCodes.Switch, lbswitch);     
+                               ig.MarkLabel ( lbswitch[0] ) ;
+                               ig.Emit (OpCodes.Leave_S, endcatch);    
+                                                               
+                               Label[] labels = new Label[targets.Count];
+                               for ( int i = 0; i < targets.Count; i++ )
+                               {
+                                       labels[i] = labeledstatements[i].LabelTarget(ec);
+
+                                       ig.MarkLabel ( lbswitch[i+1] ) ;
+                                       ig.Emit ( OpCodes.Leave, labels[i] );
+                               }
+
+                               ig.MarkLabel ( endcatch );
+                               ig.Emit ( OpCodes.Rethrow );    
+
+                       ec.InCatch = old_in_catch;
+
+                       ig.EndExceptionBlock ();
+                       ec.TryCatchLevel--;
+
+                       Label end = ig.DefineLabel();
+                       //ig.MarkLabel ( finish ) ;
+                       ig.Emit (OpCodes.Ldloc_1);
+                       ig.Emit (OpCodes.Brfalse_S, end );
+                               
+                       mi = t.GetMethod("ClearProjectError");
+                       ig.Emit (OpCodes.Call, mi);
+
+                       ig.MarkLabel(end) ;
+                       
+                       if (!returns)
+                               return returns;
+
                        // Unfortunately, System.Reflection.Emit automatically emits a leave
                        // to the end of the finally block.  This is a problem if 'returns'
                        // is true since we may jump to a point after the end of the method.
@@ -4549,6 +4764,7 @@ namespace Mono.MonoBASIC {
 
                        return true;
                }
+               
        }
 
        public class Using : Statement {
@@ -4782,6 +4998,19 @@ namespace Mono.MonoBASIC {
                        if (expr == null)
                                return false;
 
+                       if ( variable.VariableInfo.Alias != null )
+                       {
+                               FieldBase fb = variable.VariableInfo.GetFieldAlias(ec);
+
+                               if ( fb == null )
+                               {
+                                       Report.Error (451, loc,"Name '" + variable.VariableInfo.Name  + "' is not declared.");
+                                       return false;
+                               }
+                               else
+                               type = fb.Type;
+                       }
+                                               
                        var_type = ec.DeclSpace.ResolveType (type, false, loc);
                        if (var_type == null)
                                return false;
@@ -5123,9 +5352,25 @@ namespace Mono.MonoBASIC {
                        ig.Emit (OpCodes.Ldloc, enumerator);
                        ig.Emit (OpCodes.Callvirt, hm.move_next);
                        ig.Emit (OpCodes.Brfalse, end_try);
+                       
+                       
+                       FieldBase fb = null;
+                       if ( variable.VariableInfo.Alias != null )
+                       {
+                               fb = variable.VariableInfo.GetFieldAlias(ec);
+                               
+                               if( (fb.ModFlags & Modifiers.STATIC) == 0 )
+                                       ig.Emit (OpCodes.Ldarg_0);
+                       }       
+                                       
                        ig.Emit (OpCodes.Ldloc, enumerator);
                        ig.Emit (OpCodes.Callvirt, hm.get_current);
-                       variable.EmitAssign (ec, conv);
+                       
+                       if ( fb == null)
+                               variable.EmitAssign (ec, conv);
+                       else
+                               variable.EmitAssign (ec, conv, fb);
+                       
                        statement.Emit (ec);
                        ig.Emit (OpCodes.Br, ec.LoopBegin);
                        ig.MarkLabel (end_try);
@@ -5193,11 +5438,23 @@ namespace Mono.MonoBASIC {
                                loop = ig.DefineLabel ();
                                ig.MarkLabel (loop);
 
+                               FieldBase fb = null;
+                               if ( variable.VariableInfo.Alias != null )
+                               {
+                                       fb = variable.VariableInfo.GetFieldAlias(ec);
+
+                                       if( (fb.ModFlags & Modifiers.STATIC) == 0 )
+                                               ig.Emit (OpCodes.Ldarg_0);
+                               }       
+                                       
                                ig.Emit (OpCodes.Ldloc, copy);
                                ig.Emit (OpCodes.Ldloc, counter);
                                ArrayAccess.EmitLoadOpcode (ig, var_type);
 
-                               variable.EmitAssign (ec, conv);
+                               if ( fb == null)
+                                       variable.EmitAssign (ec, conv);
+                               else
+                                       variable.EmitAssign (ec, conv, fb);
 
                                statement.Emit (ec);