2005-11-16 Maverson Eduardo Schulze Rosa <maverson@gmail.com>
[mono.git] / mcs / mbas / block.cs
1 //
2 // block.cs: Block representation for the IL tree.
3 //
4 // Author:
5 //   Rafael Teixeira (rafaelteixeirabr@hotmail.com)
6 //   Miguel de Icaza (miguel@ximian.com)
7 //   Martin Baulig (martin@gnome.org)
8 //       Anirban Bhattacharjee (banirban@novell.com)
9 //   Manjula GHM (mmanjula@novell.com)
10 //   Satya Sudha K (ksathyasudha@novell.com)
11 //
12 // (C) 2001, 2002, 2003, 2004, 2005 Ximian, Inc.
13 //
14
15 using System;
16 using System.Text;
17 using System.Reflection;
18 using System.Reflection.Emit;
19 using System.Diagnostics;
20
21 namespace Mono.MonoBASIC {
22
23         using System.Collections;
24
25         /// <summary>
26         ///   Block represents a VB.NET block.
27         /// </summary>
28         ///
29         /// <remarks>
30         ///   This class is used in a number of places: either to represent
31         ///   explicit blocks that the programmer places or implicit blocks.
32         ///
33         ///   Implicit blocks are used as labels or to introduce variable
34         ///   declarations.
35         /// </remarks>
36         public class Block : Statement {
37                 public Block     Parent;
38                 public readonly bool      Implicit;
39                 public readonly Location  StartLocation;
40                 public Location    EndLocation;
41
42                 //
43                 // The statements in this block
44                 //
45                 public ArrayList statements;
46
47                 //
48                 // An array of Blocks.  We keep track of children just
49                 // to generate the local variable declarations.
50                 //
51                 // Statements and child statements are handled through the
52                 // statements.
53                 //
54                 ArrayList children;
55                 
56                 //
57                 // Labels.  (label, block) pairs.
58                 //
59                 CaseInsensitiveHashtable labels;
60
61                 //
62                 // Keeps track of (name, type) pairs
63                 //
64                 CaseInsensitiveHashtable variables;
65
66                 //
67                 // Keeps track of constants
68                 CaseInsensitiveHashtable constants;
69
70                 //
71                 // Maps variable names to ILGenerator.LocalBuilders
72                 //
73                 //CaseInsensitiveHashtable local_builders;
74
75                 // to hold names of variables required for late binding
76                 public const string lateBindingArgs = "1_LBArgs";
77                 public const string lateBindingArgNames = "1_LBArgsNames";
78                 public const string lateBindingCopyBack = "1_LBCopyBack";
79
80                 bool isLateBindingRequired = false;
81
82                 bool used = false;
83
84                 static int id;
85
86                 int this_id;
87                 
88                 public Block (Block parent)
89                         : this (parent, false, Location.Null, Location.Null)
90                 { }
91
92                 public Block (Block parent, bool implicit_block)
93                         : this (parent, implicit_block, Location.Null, Location.Null)
94                 { }
95
96                 public Block (Block parent, bool implicit_block, Parameters parameters)
97                         : this (parent, implicit_block, parameters, Location.Null, Location.Null)
98                 { }
99
100                 public Block (Block parent, Location start, Location end)
101                         : this (parent, false, start, end)
102                 { }
103
104                 public Block (Block parent, Parameters parameters, Location start, Location end)
105                         : this (parent, false, parameters, start, end)
106                 { }
107
108                 public Block (Block parent, bool implicit_block, Location start, Location end)
109                         : this (parent, implicit_block, Parameters.EmptyReadOnlyParameters,
110                                 start, end)
111                 { }
112
113                 public Block (Block parent, bool implicit_block, Parameters parameters,
114                               Location start, Location end)
115                 {
116                         if (parent != null)
117                                 parent.AddChild (this);
118                         else {
119                                 // Top block
120                                 // Add variables that may be required for late binding
121                                 variables = new CaseInsensitiveHashtable ();
122                                 ArrayList rank_specifier = new ArrayList ();
123                                 ArrayList element = new ArrayList ();
124                                 element.Add (new EmptyExpression ());
125                                 rank_specifier.Add (element);
126                                 Expression e = Mono.MonoBASIC.Parser.DecomposeQI ("System.Object[]", start);
127                                 AddVariable (e, Block.lateBindingArgs, null, start);
128                                 e = Mono.MonoBASIC.Parser.DecomposeQI ("System.String[]", start);
129                                 AddVariable (e, Block.lateBindingArgNames, null, start);
130                                 e = Mono.MonoBASIC.Parser.DecomposeQI ("System.Boolean[]", start);
131                                 AddVariable (e, Block.lateBindingCopyBack, null, start);
132                         }
133                         
134                         this.Parent = parent;
135                         this.Implicit = implicit_block;
136                         this.parameters = parameters;
137                         this.StartLocation = start;
138                         this.EndLocation = end;
139                         this.loc = start;
140                         this_id = id++;
141                         statements = new ArrayList ();
142                 }
143
144                 public bool IsLateBindingRequired {
145                         get {
146                                 return isLateBindingRequired;
147                         }
148                         set {
149                                 isLateBindingRequired = value;
150                         }
151                 }
152
153                 public int ID {
154                         get {
155                                 return this_id;
156                         }
157                 }
158
159                 public void AddChild (Block b)
160                 {
161                         if (children == null)
162                                 children = new ArrayList ();
163                         
164                         children.Add (b);
165                 }
166
167                 public void SetEndLocation (Location loc)
168                 {
169                         EndLocation = loc;
170                 }
171
172                 /// <summary>
173                 ///   Verify if the current block has a labeled statement. 
174                 /// </summary>
175                 ///
176                 /// <returns>
177                 ///   false if desn't exist a labeled statement in this block or in its children. true
178                 ///   otherwise.
179                 /// </returns>
180                 public bool HasLabeledStatement {
181                         get {
182                                 foreach( Statement s in statements ) {
183                                         if( s is LabeledStatement )
184                                                 return true;
185                                         else if (s is Block )
186                                                 return ( ((Block) s).HasLabeledStatement);
187                                 }
188                                 return false;
189                         }
190                 }
191                 
192                 public bool HasGotoStatement {
193                         get {
194                                 foreach( Statement s in statements ) {
195                                         if( s is Goto )
196                                                 return true;
197                                         else if (s is Block )
198                                                 return ( ((Block) s).HasLabeledStatement);
199                                 }
200                                 return false;
201                         }
202                 }
203                 
204                 public string LabelName {
205                         get {
206                                 foreach( Statement s in statements ) {
207                                         if( s is LabeledStatement )
208                                                 return ((LabeledStatement)s).LabelName;
209                                         else if (s is Block )
210                                                 return ( ((Block) s).LabelName);
211                                 }
212                                 return "";
213                         }
214                 }
215                                 
216                 /// <summary>
217                 ///   Adds a label to the current block. 
218                 /// </summary>
219                 ///
220                 /// <returns>
221                 ///   false if the name already exists in this block. true
222                 ///   otherwise.
223                 /// </returns>
224                 ///
225 /**
226                 public bool AddLabel (string name, LabeledStatement target)
227                 {
228                         if (labels == null)
229                                 labels = new CaseInsensitiveHashtable ();
230                         if (labels.Contains (name))
231                                 return false;
232                         
233                         labels.Add (name, target);
234                         return true;
235                 }
236 **/
237
238
239                  public bool AddLabel (string name, LabeledStatement target, Location loc)
240                 {
241 /**
242                         if (switch_block != null)
243                                 return switch_block.AddLabel (name, target, loc);
244 **/
245                         Block cur = this;
246                         while (cur != null) {
247
248                                 if (cur.DoLookupLabel (name) != null) {
249                                         Report.Error (
250                                                 140, loc, "The label '" + name +"' is a duplicate");
251                                         return false;
252                                 }
253
254                                 if (!Implicit)
255                                         break;
256
257                                 cur = cur.Parent;
258                         }
259
260                          while (cur != null) {
261                                 if (cur.DoLookupLabel (name) != null) {
262                                         Report.Error (
263                                                 158, loc,
264                                                 "The label '"+ name +"' shadows another label " +
265                                                 "by the same name in a containing scope.");
266                                         return false;
267                                 }
268
269                                 if (children != null) {
270                                         foreach (Block b in children) {
271                                                 LabeledStatement s = b.DoLookupLabel (name);
272                                                 if (s == null)
273                                                         continue;
274                                                 Report.Error (
275                                                         158, s.Location,
276                                                         "The label '"+ name +"' shadows another " +
277                                                         "label by the same name in a " +
278                                                         "containing scope.");
279                                                 return false;
280                                         }
281                                 }
282                                 cur = cur.Parent;
283                         }
284                          if (labels == null)
285                                 labels = new CaseInsensitiveHashtable ();
286                         if (labels.Contains (name))
287                                 return false;
288
289                         labels.Add (name, target);
290                         return true;
291
292                 }
293                 
294                 public LabeledStatement LookupLabel (string name)
295                 {
296                         LabeledStatement s = DoLookupLabel (name);
297                         if (s != null) 
298                                 return s;
299                         
300                         if (children == null)
301                                 return null;
302
303                         foreach (Block child in children) {
304                         //      if (!child.Implicit)
305                         //              continue;
306
307                                 s = child.LookupLabel (name);
308                                 if (s != null) 
309                                         return s;
310                         }
311
312                         return null;
313                 }
314
315                 public LabeledStatement DoLookupLabel (string name)
316                 {
317                         if (labels != null){
318                                 if (labels.Contains (name))
319                                         return ((LabeledStatement) labels [name]);
320                         }
321 /**
322                         if (Parent != null)
323                                 return Parent.LookupLabel (name);
324 **/
325                         return null;
326                 }
327
328                 VariableInfo this_variable = null;
329
330                 // <summary>
331                 //   Returns the "this" instance variable of this block.
332                 //   See AddThisVariable() for more information.
333                 // </summary>
334                 public VariableInfo ThisVariable {
335                         get {
336                                 if (this_variable != null)
337                                         return this_variable;
338                                 else if (Parent != null)
339                                         return Parent.ThisVariable;
340                                 else
341                                         return null;
342                         }
343                 }
344
345                 Hashtable child_variable_names;
346
347                 // <summary>
348                 //   Marks a variable with name @name as being used in a child block.
349                 //   If a variable name has been used in a child block, it's illegal to
350                 //   declare a variable with the same name in the current block.
351                 // </summary>
352                 public void AddChildVariableName (string name)
353                 {
354                         if (child_variable_names == null)
355                                 child_variable_names = new CaseInsensitiveHashtable ();
356
357                         if (!child_variable_names.Contains (name))
358                                 child_variable_names.Add (name, true);
359                 }
360
361                 // <summary>
362                 //   Marks all variables from block @block and all its children as being
363                 //   used in a child block.
364                 // </summary>
365                 public void AddChildVariableNames (Block block)
366                 {
367                         if (block.Variables != null) {
368                                 foreach (string name in block.Variables.Keys)
369                                         AddChildVariableName (name);
370                         }
371
372                         foreach (Block child in block.children) {
373                                 if (child.Variables != null) {
374                                         foreach (string name in child.Variables.Keys)
375                                                 AddChildVariableName (name);
376                                 }
377                         }
378                 }
379
380                 // <summary>
381                 //   Checks whether a variable name has already been used in a child block.
382                 // </summary>
383                 public bool IsVariableNameUsedInChildBlock (string name)
384                 {
385                         if (child_variable_names == null)
386                                 return false;
387
388                         return child_variable_names.Contains (name);
389                 }
390
391                 // <summary>
392                 //   This is used by non-static 'struct' constructors which do not have an
393                 //   initializer - in this case, the constructor must initialize all of the
394                 //   struct's fields.  To do this, we add a "this" variable and use the flow
395                 //   analysis code to ensure that it's been fully initialized before control
396                 //   leaves the constructor.
397                 // </summary>
398                 public VariableInfo AddThisVariable (TypeContainer tc, Location l)
399                 {
400                         if (this_variable != null)
401                                 return this_variable;
402
403                         this_variable = new VariableInfo (tc, ID, l);
404
405                         if (variables == null)
406                                 variables = new CaseInsensitiveHashtable ();
407                         variables.Add ("this", this_variable);
408
409                         return this_variable;
410                 }
411
412                 public VariableInfo AddVariable (EmitContext ec, Expression type, string name, Location l)
413                 {
414                         if (!variables_initialized)
415                                 throw new InvalidOperationException();
416                                 
417                         VariableInfo vi = AddVariable(type, name, null, loc);
418
419                         int priorCount = count_variables;
420                         DeclSpace ds = ec.DeclSpace;
421
422                         if (!vi.Resolve (ds)) {
423                                 vi.Number = -1;
424                         } else {
425                                 vi.Number = ++count_variables;
426                                 if (vi.StructInfo != null)
427                                         count_variables += vi.StructInfo.Count;
428                         }
429                         if (priorCount < count_variables)
430                                 ec.CurrentBranching.CurrentUsageVector.AddExtraLocals(count_variables - priorCount);
431                                 
432                         return vi;
433                 }
434                 
435                 
436                 
437                 public VariableInfo AddVariable (Expression type, string name, Parameters pars, Location l, string Alias)
438                 {
439                         VariableInfo vi = AddVariable (type, name, pars, l);
440                         if (vi != null) 
441                                 vi.Alias = Alias;
442                                         
443                         return vi;
444                 }
445                 
446                 public VariableInfo AddVariable (Expression type, string name, Parameters pars, Location l)
447                 {
448                         if (variables == null)
449                                 variables = new CaseInsensitiveHashtable ();
450
451                         VariableInfo vi = GetVariableInfo (name);
452                         if (vi != null) {
453                                 if (vi.Block != ID)
454                                         Report.Error (30616, l, "A local variable named '" + name + "' " +
455                                                       "cannot be declared in this scope since it would " +
456                                                       "give a different meaning to '" + name + "', which " +
457                                                       "is already used in a 'parent or current' scope to " +
458                                                       "denote something else");
459                                 else
460                                         Report.Error (30290, l, "A local variable '" + name + "' is already " +
461                                                       "defined in this scope");
462                                 return null;
463                         }
464
465                         if (IsVariableNameUsedInChildBlock (name)) {
466                                 Report.Error (136, l, "A local variable named '" + name + "' " +
467                                               "cannot be declared in this scope since it would " +
468                                               "give a different meaning to '" + name + "', which " +
469                                               "is already used in a 'child' scope to denote something " +
470                                               "else");
471                                 return null;
472                         }
473
474                         if (pars != null) {
475                                 int idx = 0;
476                                 Parameter p = pars.GetParameterByName (name, out idx);
477                                 if (p != null) {
478                                         Report.Error (30616, l, "A local variable named '" + name + "' " +
479                                                       "cannot be declared in this scope since it would " +
480                                                       "give a different meaning to '" + name + "', which " +
481                                                       "is already used in a 'parent or current' scope to " +
482                                                       "denote something else");
483                                         return null;
484                                 }
485                         }
486                         
487                         vi = new VariableInfo (type, name, ID, l);
488
489                         variables.Add (name, vi);
490
491                         return vi;
492                 }
493
494                 public bool AddConstant (Expression type, string name, Expression value, Parameters pars, Location l)
495                 {
496                         if (AddVariable (type, name, pars, l) == null)
497                                 return false;
498                         
499                         if (constants == null)
500                                 constants = new CaseInsensitiveHashtable ();
501
502                         constants.Add (name, value);
503                         return true;
504                 }
505
506                 public Hashtable Variables {
507                         get {
508                                 return variables;
509                         }
510                 }
511
512                 public VariableInfo GetVariableInfo (string name)
513                 {
514                         if (variables != null) {
515                                 object temp;
516                                 temp = variables [name];
517
518                                 if (temp != null){
519                                         return (VariableInfo) temp;
520                                 }
521                         }
522
523                         if (Parent != null)
524                                 return Parent.GetVariableInfo (name);
525
526                         return null;
527                 }
528                 
529                 public Expression GetVariableType (string name)
530                 {
531                         VariableInfo vi = GetVariableInfo (name);
532
533                         if (vi != null)
534                                 return vi.Type;
535
536                         return null;
537                 }
538
539                 public Expression GetConstantExpression (string name)
540                 {
541                         if (constants != null) {
542                                 object temp;
543                                 temp = constants [name];
544                                 
545                                 if (temp != null)
546                                         return (Expression) temp;
547                         }
548                         
549                         if (Parent != null)
550                                 return Parent.GetConstantExpression (name);
551
552                         return null;
553                 }
554                 
555                 /// <summary>
556                 ///   True if the variable named @name has been defined
557                 ///   in this block
558                 /// </summary>
559                 public bool IsVariableDefined (string name)
560                 {
561                         // Console.WriteLine ("Looking up {0} in {1}", name, ID);
562                         if (variables != null) {
563                                 if (variables.Contains (name))
564                                         return true;
565                         }
566                         
567                         if (Parent != null)
568                                 return Parent.IsVariableDefined (name);
569
570                         return false;
571                 }
572
573                 /// <summary>
574                 ///   True if the variable named @name is a constant
575                 ///  </summary>
576                 public bool IsConstant (string name)
577                 {
578                         Expression e = null;
579                         
580                         e = GetConstantExpression (name);
581                         
582                         return e != null;
583                 }
584                 
585                 /// <summary>
586                 ///   Use to fetch the statement associated with this label
587                 /// </summary>
588                 public Statement this [string name] {
589                         get {
590                                 return (Statement) labels [name];
591                         }
592                 }
593
594                 Parameters parameters = null;
595                 public Parameters Parameters {
596                         get {
597                                 if (Parent != null)
598                                         return Parent.Parameters;
599
600                                 return parameters;
601                         }
602                 }
603
604                 /// <returns>
605                 ///   A list of labels that were not used within this block
606                 /// </returns>
607                 public string [] GetUnreferenced ()
608                 {
609                         // FIXME: Implement me
610                         return null;
611                 }
612
613                 public void AddStatement (Statement s)
614                 {
615                         statements.Add (s);
616                         used = true;
617                 }
618
619                 public bool Used {
620                         get {
621                                 return used;
622                         }
623                 }
624
625                 public void Use ()
626                 {
627                         used = true;
628                 }
629
630                 bool variables_initialized = false;
631                 int count_variables = 0, first_variable = 0;
632
633                 void UpdateVariableInfo (EmitContext ec)
634                 {
635                         DeclSpace ds = ec.DeclSpace;
636
637                         first_variable = 0;
638
639                         if (Parent != null)
640                                 first_variable += Parent.CountVariables;
641
642                         count_variables = first_variable;
643                         if (variables != null) {
644                                 foreach (VariableInfo vi in variables.Values) {
645                                         if (!vi.Resolve (ds)) {
646                                                 vi.Number = -1;
647                                                 continue;
648                                         }
649
650                                         vi.Number = ++count_variables;
651
652                                         if (vi.StructInfo != null)
653                                                 count_variables += vi.StructInfo.Count;
654                                 }
655                         }
656
657                         variables_initialized = true;
658                 }
659
660                 //
661                 // <returns>
662                 //   The number of local variables in this block
663                 // </returns>
664                 public int CountVariables
665                 {
666                         get {
667                                 if (!variables_initialized)
668                                         throw new Exception ();
669
670                                 return count_variables;
671                         }
672                 }
673
674                 /// <summary>
675                 ///   Emits the variable declarations and labels.
676                 /// </summary>
677                 /// <remarks>
678                 ///   tc: is our typecontainer (to resolve type references)
679                 ///   ig: is the code generator:
680                 ///   toplevel: the toplevel block.  This is used for checking 
681                 ///             that no two labels with the same name are used.
682                 /// </remarks>
683                 public void EmitMeta (EmitContext ec, Block toplevel)
684                 {
685                         //DeclSpace ds = ec.DeclSpace;
686                         ILGenerator ig = ec.ig;
687
688                         if (!variables_initialized)
689                                 UpdateVariableInfo (ec);
690
691                         //
692                         // Process this block variables
693                         //
694                         if (variables != null){
695                                 //local_builders = new CaseInsensitiveHashtable ();
696                                 
697                                 foreach (DictionaryEntry de in variables){
698                                         string name = (string) de.Key;
699                                         /*
700                                         if (!isLateBindingRequired) {
701                                                 if (name.Equals (Block.lateBindingArgs) || 
702                                                     name.Equals (Block.lateBindingArgNames) ||
703                                                     name.Equals (Block.lateBindingCopyBack))
704                                                         continue;
705                                         }
706                                         */
707                                         VariableInfo vi = (VariableInfo) de.Value;
708
709                                         if (vi.VariableType == null)
710                                                 continue;
711
712                                        if (vi.Alias == null)
713                                                vi.LocalBuilder = ig.DeclareLocal (vi.VariableType);
714
715                                        if (CodeGen.SymbolWriter != null && vi.LocalBuilder != null)
716                                                 vi.LocalBuilder.SetLocalSymInfo (name);
717
718                                         if (constants == null)
719                                                 continue;
720
721                                         Expression cv = (Expression) constants [name];
722                                         if (cv == null)
723                                                 continue;
724
725                                         Expression e = cv.Resolve (ec);
726                                         if (e == null)
727                                                 continue;
728
729                                         if (!(e is Constant)){
730                                                 Report.Error (133, vi.Location,
731                                                               "The expression being assigned to '" +
732                                                               name + "' must be constant (" + e + ")");
733                                                 continue;
734                                         }
735
736                                         constants.Remove (name);
737                                         constants.Add (name, e);
738                                 }
739                         }
740
741                         //
742                         // Now, handle the children
743                         //
744                         if (children != null){
745                                 foreach (Block b in children)
746                                         b.EmitMeta (ec, toplevel);
747                         }
748                 }
749
750                 public void UsageWarning ()
751                 {
752                         string name;
753                         
754                         if (variables != null){
755                                 foreach (DictionaryEntry de in variables){
756                                         VariableInfo vi = (VariableInfo) de.Value;
757                                         
758                                         if (vi.Used)
759                                                 continue;
760                                         
761                                         name = (string) de.Key;
762                                                 
763                                         if (vi.Assigned){
764                                                 Report.Warning (
765                                                         219, vi.Location, "The variable '" + name +
766                                                         "' is assigned but its value is never used");
767                                         } else {
768                                                 if (!(name.Equals(lateBindingArgs)||name.Equals(lateBindingArgNames)||name.Equals(lateBindingCopyBack)))
769                                                 Report.Warning (
770                                                         168, vi.Location, "The variable '" +
771                                                         name +"' is declared but never used");
772                                         } 
773                                 }
774                         }
775
776                         if (children != null)
777                                 foreach (Block b in children)
778                                         b.UsageWarning ();
779                 }
780
781                 bool has_ret = false;
782
783                 public override bool Resolve (EmitContext ec)
784                 {
785                         Block prev_block = ec.CurrentBlock;
786                         bool ok = true;
787
788                         ec.CurrentBlock = this;
789
790                         if (!variables_initialized)
791                                 UpdateVariableInfo (ec);
792                                 
793                         ec.StartFlowBranching (this);
794
795                         Report.Debug (1, "RESOLVE BLOCK", StartLocation, ec.CurrentBranching);
796
797                         ArrayList new_statements = new ArrayList ();
798                         bool unreachable = false, warning_shown = false;
799
800                         foreach (Statement s in statements) {
801                                 
802                                 if (unreachable && !(s is LabeledStatement)) {
803                                         if ( !(s is Block && ((Block)s).HasLabeledStatement) ) {
804                                                 if (!warning_shown && !(s is EmptyStatement)) {
805                                                         warning_shown = true;
806                                                         Warning_DeadCodeFound (s.loc);
807                                                 }
808                                                 continue;
809                                         }
810                                 }                       
811
812                                 if (s.Resolve (ec) == false) {
813                                         ok = false;
814                                         continue;
815                                 }
816
817                                 if (s is LabeledStatement)
818                                         unreachable = false;
819                                 else
820                                         unreachable = ! ec.CurrentBranching.IsReachable ();
821
822                                 new_statements.Add (s);
823                         }
824
825                         statements = new_statements;
826
827                         Report.Debug (1, "RESOLVE BLOCK DONE", StartLocation, ec.CurrentBranching);
828
829                         FlowReturns returns = ec.EndFlowBranching ();
830                         ec.CurrentBlock = prev_block;
831
832                         // If we're a non-static 'struct' constructor which doesn't have an
833                         // initializer, then we must initialize all of the struct's fields.
834                         if ((this_variable != null) && (returns != FlowReturns.EXCEPTION) &&
835                             !this_variable.IsAssigned (ec, loc))
836                                 ok = false;
837
838                         if ((labels != null) && (RootContext.WarningLevel >= 2)) {
839                                 foreach (LabeledStatement label in labels.Values)
840                                         if (!label.HasBeenReferenced)
841                                                 Report.Warning (164, label.Location,
842                                                                 "This label has not been referenced");
843                         }
844
845                         if ((returns == FlowReturns.ALWAYS) ||
846                             (returns == FlowReturns.EXCEPTION) ||
847                             (returns == FlowReturns.UNREACHABLE))
848                                 has_ret = true;
849
850                         return ok;
851                 }
852
853                 protected override bool DoEmit (EmitContext ec)
854                 {
855                         Block prev_block = ec.CurrentBlock;
856
857                         ec.CurrentBlock = this;
858
859                         ec.Mark (StartLocation);
860                         foreach (Statement s in statements)
861                                 s.Emit (ec);
862                                 
863                         ec.Mark (EndLocation); 
864                         
865                         ec.CurrentBlock = prev_block;
866                         return has_ret;
867                 }
868                 
869                 public override string ToString ()
870                 {
871                         return String.Format ("{0} ({1}:{2})", GetType (),ID, StartLocation);
872                 }
873
874         } // class Block
875         
876         /// <summary>
877         ///   Block represents a VB.NET method block.
878         /// </summary>
879         ///
880         /// <remarks>
881         ///   This class is used in a number of places: either to represent
882         ///   explicit blocks that the programmer places or implicit blocks.
883         ///
884         ///   Implicit blocks are used as labels or to introduce variable
885         ///   declarations.
886         /// </remarks>
887         public class MethodBlock : Block {
888                 public readonly string MethodName;
889                 public Block onerror;
890                 public ArrayList Pending_Assigns;
891                 
892                 public MethodBlock (Block parent, string MethodName)
893                         : base (parent, false, Location.Null, Location.Null)
894                 {
895                         this.MethodName = MethodName;
896                 }
897
898                 public MethodBlock (Block parent, bool implicit_block, string MethodName)
899                         : base (parent, implicit_block, Location.Null, Location.Null)
900                 {
901                         this.MethodName = MethodName;
902                 }
903
904                 public MethodBlock (Block parent, bool implicit_block, Parameters parameters, string MethodName)
905                         : base (parent, implicit_block, parameters, Location.Null, Location.Null)
906                 {
907                         this.MethodName = MethodName;
908                 }
909
910                 public MethodBlock (Block parent, Location start, Location end, String MethodName)
911                         : base (parent, false, start, end)
912                 {
913                         this.MethodName = MethodName;
914                 }
915
916                 public MethodBlock (Block parent, Parameters parameters, Location start, Location end, string MethodName)
917                         : base (parent, false, parameters, start, end)
918                 {
919                         this.MethodName = MethodName;
920                 }
921
922                 public MethodBlock (Block parent, bool implicit_block, Location start, Location end, string MethodName)
923                         : base (parent, implicit_block, Parameters.EmptyReadOnlyParameters,
924                                 start, end)
925                 {
926                         this.MethodName = MethodName;
927                 }
928
929                 public MethodBlock (Block parent, bool implicit_block, Parameters parameters,
930                               Location start, Location end, string MethodName)
931                         : base (parent, implicit_block, parameters, start, end)
932                 {
933                         this.MethodName = MethodName;
934                 }
935                 
936         }
937
938 } // namespace Mono.MonoBASIC