svn path=/branches/mono-1-1-9/mcs/; revision=51212
[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 readonly 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                 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                 /// <summary>
193                 ///   Adds a label to the current block. 
194                 /// </summary>
195                 ///
196                 /// <returns>
197                 ///   false if the name already exists in this block. true
198                 ///   otherwise.
199                 /// </returns>
200                 ///
201 /**
202                 public bool AddLabel (string name, LabeledStatement target)
203                 {
204                         if (labels == null)
205                                 labels = new CaseInsensitiveHashtable ();
206                         if (labels.Contains (name))
207                                 return false;
208                         
209                         labels.Add (name, target);
210                         return true;
211                 }
212 **/
213
214
215                  public bool AddLabel (string name, LabeledStatement target, Location loc)
216                 {
217 /**
218                         if (switch_block != null)
219                                 return switch_block.AddLabel (name, target, loc);
220 **/
221                         Block cur = this;
222                         while (cur != null) {
223
224                                 if (cur.DoLookupLabel (name) != null) {
225                                         Report.Error (
226                                                 140, loc, "The label '" + name +"' is a duplicate");
227                                         return false;
228                                 }
229
230                                 if (!Implicit)
231                                         break;
232
233                                 cur = cur.Parent;
234                         }
235
236                          while (cur != null) {
237                                 if (cur.DoLookupLabel (name) != null) {
238                                         Report.Error (
239                                                 158, loc,
240                                                 "The label '"+ name +"' shadows another label " +
241                                                 "by the same name in a containing scope.");
242                                         return false;
243                                 }
244
245                                 if (children != null) {
246                                         foreach (Block b in children) {
247                                                 LabeledStatement s = b.DoLookupLabel (name);
248                                                 if (s == null)
249                                                         continue;
250                                                 Report.Error (
251                                                         158, s.Location,
252                                                         "The label '"+ name +"' shadows another " +
253                                                         "label by the same name in a " +
254                                                         "containing scope.");
255                                                 return false;
256                                         }
257                                 }
258                                 cur = cur.Parent;
259                         }
260                          if (labels == null)
261                                 labels = new CaseInsensitiveHashtable ();
262                         if (labels.Contains (name))
263                                 return false;
264
265                         labels.Add (name, target);
266                         return true;
267
268                 }
269                 
270                 public LabeledStatement LookupLabel (string name)
271                 {
272                         LabeledStatement s = DoLookupLabel (name);
273                         if (s != null) 
274                                 return s;
275                         
276                         if (children == null)
277                                 return null;
278
279                         foreach (Block child in children) {
280                         //      if (!child.Implicit)
281                         //              continue;
282
283                                 s = child.LookupLabel (name);
284                                 if (s != null) 
285                                         return s;
286                         }
287
288                         return null;
289                 }
290
291                 public LabeledStatement DoLookupLabel (string name)
292                 {
293                         if (labels != null){
294                                 if (labels.Contains (name))
295                                         return ((LabeledStatement) labels [name]);
296                         }
297 /**
298                         if (Parent != null)
299                                 return Parent.LookupLabel (name);
300 **/
301                         return null;
302                 }
303
304                 VariableInfo this_variable = null;
305
306                 // <summary>
307                 //   Returns the "this" instance variable of this block.
308                 //   See AddThisVariable() for more information.
309                 // </summary>
310                 public VariableInfo ThisVariable {
311                         get {
312                                 if (this_variable != null)
313                                         return this_variable;
314                                 else if (Parent != null)
315                                         return Parent.ThisVariable;
316                                 else
317                                         return null;
318                         }
319                 }
320
321                 Hashtable child_variable_names;
322
323                 // <summary>
324                 //   Marks a variable with name @name as being used in a child block.
325                 //   If a variable name has been used in a child block, it's illegal to
326                 //   declare a variable with the same name in the current block.
327                 // </summary>
328                 public void AddChildVariableName (string name)
329                 {
330                         if (child_variable_names == null)
331                                 child_variable_names = new CaseInsensitiveHashtable ();
332
333                         if (!child_variable_names.Contains (name))
334                                 child_variable_names.Add (name, true);
335                 }
336
337                 // <summary>
338                 //   Marks all variables from block @block and all its children as being
339                 //   used in a child block.
340                 // </summary>
341                 public void AddChildVariableNames (Block block)
342                 {
343                         if (block.Variables != null) {
344                                 foreach (string name in block.Variables.Keys)
345                                         AddChildVariableName (name);
346                         }
347
348                         foreach (Block child in block.children) {
349                                 if (child.Variables != null) {
350                                         foreach (string name in child.Variables.Keys)
351                                                 AddChildVariableName (name);
352                                 }
353                         }
354                 }
355
356                 // <summary>
357                 //   Checks whether a variable name has already been used in a child block.
358                 // </summary>
359                 public bool IsVariableNameUsedInChildBlock (string name)
360                 {
361                         if (child_variable_names == null)
362                                 return false;
363
364                         return child_variable_names.Contains (name);
365                 }
366
367                 // <summary>
368                 //   This is used by non-static 'struct' constructors which do not have an
369                 //   initializer - in this case, the constructor must initialize all of the
370                 //   struct's fields.  To do this, we add a "this" variable and use the flow
371                 //   analysis code to ensure that it's been fully initialized before control
372                 //   leaves the constructor.
373                 // </summary>
374                 public VariableInfo AddThisVariable (TypeContainer tc, Location l)
375                 {
376                         if (this_variable != null)
377                                 return this_variable;
378
379                         this_variable = new VariableInfo (tc, ID, l);
380
381                         if (variables == null)
382                                 variables = new CaseInsensitiveHashtable ();
383                         variables.Add ("this", this_variable);
384
385                         return this_variable;
386                 }
387
388                 public VariableInfo AddVariable (EmitContext ec, Expression type, string name, Location l)
389                 {
390                         if (!variables_initialized)
391                                 throw new InvalidOperationException();
392                                 
393                         VariableInfo vi = AddVariable(type, name, null, loc);
394
395                         int priorCount = count_variables;
396                         DeclSpace ds = ec.DeclSpace;
397
398                         if (!vi.Resolve (ds)) {
399                                 vi.Number = -1;
400                         } else {
401                                 vi.Number = ++count_variables;
402                                 if (vi.StructInfo != null)
403                                         count_variables += vi.StructInfo.Count;
404                         }
405                         if (priorCount < count_variables)
406                                 ec.CurrentBranching.CurrentUsageVector.AddExtraLocals(count_variables - priorCount);
407                                 
408                         return vi;
409                 }
410                 
411                 
412                 
413                 public VariableInfo AddVariable (Expression type, string name, Parameters pars, Location l, string Alias, bool Static)
414                 {
415                         VariableInfo vi = AddVariable (type, name, pars, l);
416                         if (vi != null) {
417                                 vi.Alias = Alias;
418                                 vi.Static = Static;
419                         }
420                                         
421                         return vi;
422                 }
423                 
424                 public VariableInfo AddVariable (Expression type, string name, Parameters pars, Location l)
425                 {
426                         if (variables == null)
427                                 variables = new CaseInsensitiveHashtable ();
428
429                         VariableInfo vi = GetVariableInfo (name);
430                         if (vi != null) {
431                                 if (vi.Block != ID)
432                                         Report.Error (30616, l, "A local variable named '" + name + "' " +
433                                                       "cannot be declared in this scope since it would " +
434                                                       "give a different meaning to '" + name + "', which " +
435                                                       "is already used in a 'parent or current' scope to " +
436                                                       "denote something else");
437                                 else
438                                         Report.Error (30290, l, "A local variable '" + name + "' is already " +
439                                                       "defined in this scope");
440                                 return null;
441                         }
442
443                         if (IsVariableNameUsedInChildBlock (name)) {
444                                 Report.Error (136, l, "A local variable named '" + name + "' " +
445                                               "cannot be declared in this scope since it would " +
446                                               "give a different meaning to '" + name + "', which " +
447                                               "is already used in a 'child' scope to denote something " +
448                                               "else");
449                                 return null;
450                         }
451
452                         if (pars != null) {
453                                 int idx = 0;
454                                 Parameter p = pars.GetParameterByName (name, out idx);
455                                 if (p != null) {
456                                         Report.Error (30616, l, "A local variable named '" + name + "' " +
457                                                       "cannot be declared in this scope since it would " +
458                                                       "give a different meaning to '" + name + "', which " +
459                                                       "is already used in a 'parent or current' scope to " +
460                                                       "denote something else");
461                                         return null;
462                                 }
463                         }
464                         
465                         vi = new VariableInfo (type, name, ID, l);
466
467                         variables.Add (name, vi);
468
469                         return vi;
470                 }
471
472                 public bool AddConstant (Expression type, string name, Expression value, Parameters pars, Location l)
473                 {
474                         if (AddVariable (type, name, pars, l) == null)
475                                 return false;
476                         
477                         if (constants == null)
478                                 constants = new CaseInsensitiveHashtable ();
479
480                         constants.Add (name, value);
481                         return true;
482                 }
483
484                 public Hashtable Variables {
485                         get {
486                                 return variables;
487                         }
488                 }
489
490                 public VariableInfo GetVariableInfo (string name)
491                 {
492                         if (variables != null) {
493                                 object temp;
494                                 temp = variables [name];
495
496                                 if (temp != null){
497                                         return (VariableInfo) temp;
498                                 }
499                         }
500
501                         if (Parent != null)
502                                 return Parent.GetVariableInfo (name);
503
504                         return null;
505                 }
506                 
507                 public Expression GetVariableType (string name)
508                 {
509                         VariableInfo vi = GetVariableInfo (name);
510
511                         if (vi != null)
512                                 return vi.Type;
513
514                         return null;
515                 }
516
517                 public Expression GetConstantExpression (string name)
518                 {
519                         if (constants != null) {
520                                 object temp;
521                                 temp = constants [name];
522                                 
523                                 if (temp != null)
524                                         return (Expression) temp;
525                         }
526                         
527                         if (Parent != null)
528                                 return Parent.GetConstantExpression (name);
529
530                         return null;
531                 }
532                 
533                 /// <summary>
534                 ///   True if the variable named @name has been defined
535                 ///   in this block
536                 /// </summary>
537                 public bool IsVariableDefined (string name)
538                 {
539                         // Console.WriteLine ("Looking up {0} in {1}", name, ID);
540                         if (variables != null) {
541                                 if (variables.Contains (name))
542                                         return true;
543                         }
544                         
545                         if (Parent != null)
546                                 return Parent.IsVariableDefined (name);
547
548                         return false;
549                 }
550
551                 /// <summary>
552                 ///   True if the variable named @name is a constant
553                 ///  </summary>
554                 public bool IsConstant (string name)
555                 {
556                         Expression e = null;
557                         
558                         e = GetConstantExpression (name);
559                         
560                         return e != null;
561                 }
562                 
563                 /// <summary>
564                 ///   Use to fetch the statement associated with this label
565                 /// </summary>
566                 public Statement this [string name] {
567                         get {
568                                 return (Statement) labels [name];
569                         }
570                 }
571
572                 Parameters parameters = null;
573                 public Parameters Parameters {
574                         get {
575                                 if (Parent != null)
576                                         return Parent.Parameters;
577
578                                 return parameters;
579                         }
580                 }
581
582                 /// <returns>
583                 ///   A list of labels that were not used within this block
584                 /// </returns>
585                 public string [] GetUnreferenced ()
586                 {
587                         // FIXME: Implement me
588                         return null;
589                 }
590
591                 public void AddStatement (Statement s)
592                 {
593                         statements.Add (s);
594                         used = true;
595                 }
596
597                 public bool Used {
598                         get {
599                                 return used;
600                         }
601                 }
602
603                 public void Use ()
604                 {
605                         used = true;
606                 }
607
608                 bool variables_initialized = false;
609                 int count_variables = 0, first_variable = 0;
610
611                 void UpdateVariableInfo (EmitContext ec)
612                 {
613                         DeclSpace ds = ec.DeclSpace;
614
615                         first_variable = 0;
616
617                         if (Parent != null)
618                                 first_variable += Parent.CountVariables;
619
620                         count_variables = first_variable;
621                         if (variables != null) {
622                                 foreach (VariableInfo vi in variables.Values) {
623                                         if (!vi.Resolve (ds)) {
624                                                 vi.Number = -1;
625                                                 continue;
626                                         }
627
628                                         vi.Number = ++count_variables;
629
630                                         if (vi.StructInfo != null)
631                                                 count_variables += vi.StructInfo.Count;
632                                 }
633                         }
634
635                         variables_initialized = true;
636                 }
637
638                 //
639                 // <returns>
640                 //   The number of local variables in this block
641                 // </returns>
642                 public int CountVariables
643                 {
644                         get {
645                                 if (!variables_initialized)
646                                         throw new Exception ();
647
648                                 return count_variables;
649                         }
650                 }
651
652                 /// <summary>
653                 ///   Emits the variable declarations and labels.
654                 /// </summary>
655                 /// <remarks>
656                 ///   tc: is our typecontainer (to resolve type references)
657                 ///   ig: is the code generator:
658                 ///   toplevel: the toplevel block.  This is used for checking 
659                 ///             that no two labels with the same name are used.
660                 /// </remarks>
661                 public void EmitMeta (EmitContext ec, Block toplevel)
662                 {
663                         //DeclSpace ds = ec.DeclSpace;
664                         ILGenerator ig = ec.ig;
665
666                         if (!variables_initialized)
667                                 UpdateVariableInfo (ec);
668
669                         //
670                         // Process this block variables
671                         //
672                         if (variables != null){
673                                 //local_builders = new CaseInsensitiveHashtable ();
674                                 
675                                 foreach (DictionaryEntry de in variables){
676                                         string name = (string) de.Key;
677                                         /*
678                                         if (!isLateBindingRequired) {
679                                                 if (name.Equals (Block.lateBindingArgs) || 
680                                                     name.Equals (Block.lateBindingArgNames) ||
681                                                     name.Equals (Block.lateBindingCopyBack))
682                                                         continue;
683                                         }
684                                         */
685                                         VariableInfo vi = (VariableInfo) de.Value;
686
687                                         if (vi.VariableType == null)
688                                                 continue;
689
690                                         vi.LocalBuilder = ig.DeclareLocal (vi.VariableType);
691
692                                         if (CodeGen.SymbolWriter != null)
693                                                 vi.LocalBuilder.SetLocalSymInfo (name);
694
695                                         if (constants == null)
696                                                 continue;
697
698                                         Expression cv = (Expression) constants [name];
699                                         if (cv == null)
700                                                 continue;
701
702                                         Expression e = cv.Resolve (ec);
703                                         if (e == null)
704                                                 continue;
705
706                                         if (!(e is Constant)){
707                                                 Report.Error (133, vi.Location,
708                                                               "The expression being assigned to '" +
709                                                               name + "' must be constant (" + e + ")");
710                                                 continue;
711                                         }
712
713                                         constants.Remove (name);
714                                         constants.Add (name, e);
715                                 }
716                         }
717
718                         //
719                         // Now, handle the children
720                         //
721                         if (children != null){
722                                 foreach (Block b in children)
723                                         b.EmitMeta (ec, toplevel);
724                         }
725                 }
726
727                 public void UsageWarning ()
728                 {
729                         string name;
730                         
731                         if (variables != null){
732                                 foreach (DictionaryEntry de in variables){
733                                         VariableInfo vi = (VariableInfo) de.Value;
734                                         
735                                         if (vi.Used)
736                                                 continue;
737                                         
738                                         name = (string) de.Key;
739                                                 
740                                         if (vi.Assigned){
741                                                 Report.Warning (
742                                                         219, vi.Location, "The variable '" + name +
743                                                         "' is assigned but its value is never used");
744                                         } else {
745                                                 if (!(name.Equals(lateBindingArgs)||name.Equals(lateBindingArgNames)||name.Equals(lateBindingCopyBack)))
746                                                 Report.Warning (
747                                                         168, vi.Location, "The variable '" +
748                                                         name +"' is declared but never used");
749                                         } 
750                                 }
751                         }
752
753                         if (children != null)
754                                 foreach (Block b in children)
755                                         b.UsageWarning ();
756                 }
757
758                 bool has_ret = false;
759
760                 public override bool Resolve (EmitContext ec)
761                 {
762                         Block prev_block = ec.CurrentBlock;
763                         bool ok = true;
764
765                         ec.CurrentBlock = this;
766
767                         if (!variables_initialized)
768                                 UpdateVariableInfo (ec);
769                                 
770                         ec.StartFlowBranching (this);
771
772                         Report.Debug (1, "RESOLVE BLOCK", StartLocation, ec.CurrentBranching);
773
774                         ArrayList new_statements = new ArrayList ();
775                         bool unreachable = false, warning_shown = false;
776
777                         foreach (Statement s in statements) {
778                                 
779                                 if (unreachable && !(s is LabeledStatement)) {
780                                         if ( !(s is Block && ((Block)s).HasLabeledStatement) ) {
781                                                 if (!warning_shown && !(s is EmptyStatement)) {
782                                                         warning_shown = true;
783                                                         Warning_DeadCodeFound (s.loc);
784                                                 }
785                                                 continue;
786                                         }
787                                 }                       
788
789                                 if (s.Resolve (ec) == false) {
790                                         ok = false;
791                                         continue;
792                                 }
793
794                                 if (s is LabeledStatement)
795                                         unreachable = false;
796                                 else
797                                         unreachable = ! ec.CurrentBranching.IsReachable ();
798
799                                 new_statements.Add (s);
800                         }
801
802                         statements = new_statements;
803
804                         Report.Debug (1, "RESOLVE BLOCK DONE", StartLocation, ec.CurrentBranching);
805
806                         FlowReturns returns = ec.EndFlowBranching ();
807                         ec.CurrentBlock = prev_block;
808
809                         // If we're a non-static 'struct' constructor which doesn't have an
810                         // initializer, then we must initialize all of the struct's fields.
811                         if ((this_variable != null) && (returns != FlowReturns.EXCEPTION) &&
812                             !this_variable.IsAssigned (ec, loc))
813                                 ok = false;
814
815                         if ((labels != null) && (RootContext.WarningLevel >= 2)) {
816                                 foreach (LabeledStatement label in labels.Values)
817                                         if (!label.HasBeenReferenced)
818                                                 Report.Warning (164, label.Location,
819                                                                 "This label has not been referenced");
820                         }
821
822                         if ((returns == FlowReturns.ALWAYS) ||
823                             (returns == FlowReturns.EXCEPTION) ||
824                             (returns == FlowReturns.UNREACHABLE))
825                                 has_ret = true;
826
827                         return ok;
828                 }
829
830                 protected override bool DoEmit (EmitContext ec)
831                 {
832                         Block prev_block = ec.CurrentBlock;
833
834                         ec.CurrentBlock = this;
835
836                         ec.Mark (StartLocation);
837                         foreach (Statement s in statements)
838                                 s.Emit (ec);
839                                 
840                         ec.Mark (EndLocation); 
841                         
842                         ec.CurrentBlock = prev_block;
843                         return has_ret;
844                 }
845                 
846                 public override string ToString ()
847                 {
848                         return String.Format ("{0} ({1}:{2})", GetType (),ID, StartLocation);
849                 }
850
851         } // class Block
852         
853         /// <summary>
854         ///   Block represents a VB.NET method block.
855         /// </summary>
856         ///
857         /// <remarks>
858         ///   This class is used in a number of places: either to represent
859         ///   explicit blocks that the programmer places or implicit blocks.
860         ///
861         ///   Implicit blocks are used as labels or to introduce variable
862         ///   declarations.
863         /// </remarks>
864         public class MethodBlock : Block {
865                 public readonly string MethodName;
866                 
867                 public MethodBlock (Block parent, string MethodName)
868                         : base (parent, false, Location.Null, Location.Null)
869                 {
870                         this.MethodName = MethodName;
871                 }
872
873                 public MethodBlock (Block parent, bool implicit_block, string MethodName)
874                         : base (parent, implicit_block, Location.Null, Location.Null)
875                 {
876                         this.MethodName = MethodName;
877                 }
878
879                 public MethodBlock (Block parent, bool implicit_block, Parameters parameters, string MethodName)
880                         : base (parent, implicit_block, parameters, Location.Null, Location.Null)
881                 {
882                         this.MethodName = MethodName;
883                 }
884
885                 public MethodBlock (Block parent, Location start, Location end, String MethodName)
886                         : base (parent, false, start, end)
887                 {
888                         this.MethodName = MethodName;
889                 }
890
891                 public MethodBlock (Block parent, Parameters parameters, Location start, Location end, string MethodName)
892                         : base (parent, false, parameters, start, end)
893                 {
894                         this.MethodName = MethodName;
895                 }
896
897                 public MethodBlock (Block parent, bool implicit_block, Location start, Location end, string MethodName)
898                         : base (parent, implicit_block, Parameters.EmptyReadOnlyParameters,
899                                 start, end)
900                 {
901                         this.MethodName = MethodName;
902                 }
903
904                 public MethodBlock (Block parent, bool implicit_block, Parameters parameters,
905                               Location start, Location end, string MethodName)
906                         : base (parent, implicit_block, parameters, start, end)
907                 {
908                         this.MethodName = MethodName;
909                 }
910                 
911         }
912
913 } // namespace Mono.MonoBASIC