2006-08-13 Miguel de Icaza <miguel@novell.com>
[mono.git] / mcs / mbas / statement.cs
index 91442890c2564db3a0dccd167631696984cf782c..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);
@@ -2672,16 +2678,24 @@ namespace Mono.MonoBASIC {
                public Expression Type;
                public LocalBuilder LocalBuilder;
                public Type VariableType;
+               public string Alias;
+               FieldBase FieldAlias;
                public readonly string Name;
                public readonly Location Location;
                public readonly int Block;
-
+               
                public int Number;
                
                public bool Used;
                public bool Assigned;
                public bool ReadOnly;
                
+               public VariableInfo (Expression type, string name, int block, Location l, string Alias)
+                       : this (type, name, block, l)
+               {
+                       this.Alias = Alias;
+               }
+               
                public VariableInfo (Expression type, string name, int block, Location l)
                {
                        Type = type;
@@ -2691,6 +2705,12 @@ namespace Mono.MonoBASIC {
                        Location = l;
                }
 
+               public VariableInfo (TypeContainer tc, int block, Location l, string Alias)
+                       : this (tc, block, l)
+               {
+                       this.Alias = Alias;
+               }
+               
                public VariableInfo (TypeContainer tc, int block, Location l)
                {
                        VariableType = tc.TypeBuilder;
@@ -2775,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)
@@ -2801,8 +2839,8 @@ namespace Mono.MonoBASIC {
                        return "VariableInfo (" + Number + "," + Type + "," + Location + ")";
                }
        }
-               
 
+               
        public class StatementSequence : Expression {
                Block stmtBlock;
                ArrayList args, originalArgs;
@@ -2812,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)
@@ -2888,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;
                }
 
@@ -4425,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);
@@ -4499,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;
@@ -4514,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.
@@ -4525,6 +4764,7 @@ namespace Mono.MonoBASIC {
 
                        return true;
                }
+               
        }
 
        public class Using : Statement {
@@ -4758,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;
@@ -5099,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);
@@ -5169,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);
 
@@ -5299,7 +5580,7 @@ namespace Mono.MonoBASIC {
                public AddHandler (Expression evt_id, Expression evt_handler, Location l)
                {
                        EvtId = evt_id;
-                       EvtHandler = evt_handler;
+                       EvtHandler = Parser.SetAddressOf (evt_handler);
                        loc = l;
                        resolved = false;
                        //Console.WriteLine ("Adding handler '" + evt_handler + "' for Event '" + evt_id +"'");
@@ -5381,7 +5662,7 @@ namespace Mono.MonoBASIC {
                public RemoveHandler (Expression evt_id, Expression evt_handler, Location l)
                {
                        EvtId = evt_id;
-                       EvtHandler = evt_handler;
+                       EvtHandler = Parser.SetAddressOf (evt_handler);
                        loc = l;
                }
 
@@ -5435,23 +5716,100 @@ namespace Mono.MonoBASIC {
        }
 
        public class RedimClause {
-               public Expression Expr;
-               public ArrayList NewIndexes;
+               private Expression RedimTarget;
+               private ArrayList NewIndexes;
+               private Expression AsType;
                
-               public RedimClause (Expression e, ArrayList args)
+               private LocalTemporary localTmp = null;
+               private Expression origRedimTarget = null;
+               private StatementExpression ReDimExpr;
+
+               public RedimClause (Expression e, ArrayList args, Expression e_as)
                {
-                       Expr = e;
+                       if (e is SimpleName)
+                               ((SimpleName) e).IsInvocation = false;
+                       if (e is MemberAccess)
+                               ((MemberAccess) e).IsInvocation = false;
+               
+                       RedimTarget = e;
                        NewIndexes = args;
+                       AsType = e_as;
                }
+
+               public bool Resolve (EmitContext ec, bool Preserve, Location loc)
+               {
+                       RedimTarget = RedimTarget.Resolve (ec);
+
+                       if (AsType != null) {
+                               Report.Error (30811, loc, "'ReDim' statements can no longer be used to declare array variables");
+                               return false;
+                       }
+                       
+                       if (!RedimTarget.Type.IsArray) {
+                               Report.Error (49, loc, "'ReDim' statement requires an array");
+                               return false;
+                       }
+
+                       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() != NewIndexes.Count) {
+                               Report.Error (30415, loc, "'ReDim' cannot change the number of dimensions of an array.");
+                               return false;
+                       }
+                       
+                       Type BaseType = RedimTarget.Type.GetElementType();
+                       Expression BaseTypeExpr = MonoBASIC.Parser.DecomposeQI(BaseType.FullName.ToString(), Location.Null);
+                       ArrayCreation acExpr = new ArrayCreation (BaseTypeExpr, NewIndexes, "", null, Location.Null);   
+                       if (Preserve)
+                       {
+                               ExpressionStatement PreserveExpr = null;
+                               if (RedimTarget is PropertyGroupExpr) {
+                                       localTmp = new LocalTemporary (ec, RedimTarget.Type);
+                                       PropertyGroupExpr pe = RedimTarget as PropertyGroupExpr;
+                                       origRedimTarget = new PropertyGroupExpr (pe.Properties, pe.Arguments, pe.InstanceExpression, loc);
+                                       if ((origRedimTarget = origRedimTarget.Resolve (ec)) == null)  {
+                                               Report.Error (-1, loc, "'ReDim' vs PropertyGroup");
+                                               return false;
+                                       }
+                                       PreserveExpr = (ExpressionStatement) new Preserve(localTmp, acExpr, loc);
+                               } else
+                                       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;            
+               }
+
+               public void DoEmit (EmitContext ec)
+               {
+                       if (ReDimExpr == null)
+                               return;
+                               
+                       if (localTmp != null && origRedimTarget != null) {
+                               origRedimTarget.Emit (ec);
+                               localTmp.Store (ec);
+                       }
+                       ReDimExpr.Emit(ec);
+               }               
+
        }
 
        public class ReDim : Statement {
                ArrayList RedimTargets;
-               Type BaseType;
                bool Preserve;
 
-               private StatementExpression ReDimExpr;
-
                public ReDim (ArrayList targets, bool opt_preserve, Location l)
                {
                        loc = l;
@@ -5461,51 +5819,16 @@ namespace Mono.MonoBASIC {
 
                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;
+                       bool result = true;
+                       foreach (RedimClause rc in RedimTargets)
+                               result = rc.Resolve(ec, Preserve, loc) && result;
+                       return result;
                }
                                
                protected override bool DoEmit (EmitContext ec)
                {
-                       ReDimExpr.Emit(ec);
+                       foreach (RedimClause rc in RedimTargets)
+                               rc.DoEmit(ec);
                        return false;
                }