2 // block.cs: Block representation for the IL tree.
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)
12 // (C) 2001, 2002, 2003, 2004, 2005 Ximian, Inc.
17 using System
.Reflection
;
18 using System
.Reflection
.Emit
;
19 using System
.Diagnostics
;
21 namespace Mono
.MonoBASIC
{
23 using System
.Collections
;
26 /// Block represents a VB.NET block.
30 /// This class is used in a number of places: either to represent
31 /// explicit blocks that the programmer places or implicit blocks.
33 /// Implicit blocks are used as labels or to introduce variable
36 public class Block
: Statement
{
38 public readonly bool Implicit
;
39 public readonly Location StartLocation
;
40 public Location EndLocation
;
43 // The statements in this block
45 public ArrayList statements
;
48 // An array of Blocks. We keep track of children just
49 // to generate the local variable declarations.
51 // Statements and child statements are handled through the
57 // Labels. (label, block) pairs.
59 CaseInsensitiveHashtable labels
;
62 // Keeps track of (name, type) pairs
64 CaseInsensitiveHashtable variables
;
67 // Keeps track of constants
68 CaseInsensitiveHashtable constants
;
71 // Maps variable names to ILGenerator.LocalBuilders
73 //CaseInsensitiveHashtable local_builders;
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";
80 bool isLateBindingRequired
= false;
88 public Block (Block parent
)
89 : this (parent
, false, Location
.Null
, Location
.Null
)
92 public Block (Block parent
, bool implicit_block
)
93 : this (parent
, implicit_block
, Location
.Null
, Location
.Null
)
96 public Block (Block parent
, bool implicit_block
, Parameters parameters
)
97 : this (parent
, implicit_block
, parameters
, Location
.Null
, Location
.Null
)
100 public Block (Block parent
, Location start
, Location end
)
101 : this (parent
, false, start
, end
)
104 public Block (Block parent
, Parameters parameters
, Location start
, Location end
)
105 : this (parent
, false, parameters
, start
, end
)
108 public Block (Block parent
, bool implicit_block
, Location start
, Location end
)
109 : this (parent
, implicit_block
, Parameters
.EmptyReadOnlyParameters
,
113 public Block (Block parent
, bool implicit_block
, Parameters parameters
,
114 Location start
, Location end
)
117 parent
.AddChild (this);
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
);
134 this.Parent
= parent
;
135 this.Implicit
= implicit_block
;
136 this.parameters
= parameters
;
137 this.StartLocation
= start
;
138 this.EndLocation
= end
;
141 statements
= new ArrayList ();
144 public bool IsLateBindingRequired
{
146 return isLateBindingRequired
;
149 isLateBindingRequired
= value;
159 public void AddChild (Block b
)
161 if (children
== null)
162 children
= new ArrayList ();
167 public void SetEndLocation (Location loc
)
173 /// Verify if the current block has a labeled statement.
177 /// false if desn't exist a labeled statement in this block or in its children. true
180 public bool HasLabeledStatement
{
182 foreach( Statement s
in statements
) {
183 if( s
is LabeledStatement
)
185 else if (s
is Block
)
186 return ( ((Block
) s
).HasLabeledStatement
);
192 public bool HasGotoStatement
{
194 foreach( Statement s
in statements
) {
197 else if (s
is Block
)
198 return ( ((Block
) s
).HasLabeledStatement
);
204 public string LabelName
{
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
);
217 /// Adds a label to the current block.
221 /// false if the name already exists in this block. true
226 public bool AddLabel (string name, LabeledStatement target)
229 labels = new CaseInsensitiveHashtable ();
230 if (labels.Contains (name))
233 labels.Add (name, target);
239 public bool AddLabel (string name
, LabeledStatement target
, Location loc
)
242 if (switch_block != null)
243 return switch_block.AddLabel (name, target, loc);
246 while (cur
!= null) {
248 if (cur
.DoLookupLabel (name
) != null) {
250 140, loc
, "The label '" + name
+"' is a duplicate");
260 while (cur
!= null) {
261 if (cur
.DoLookupLabel (name
) != null) {
264 "The label '"+ name
+"' shadows another label " +
265 "by the same name in a containing scope.");
269 if (children
!= null) {
270 foreach (Block b
in children
) {
271 LabeledStatement s
= b
.DoLookupLabel (name
);
276 "The label '"+ name
+"' shadows another " +
277 "label by the same name in a " +
278 "containing scope.");
285 labels
= new CaseInsensitiveHashtable ();
286 if (labels
.Contains (name
))
289 labels
.Add (name
, target
);
294 public LabeledStatement
LookupLabel (string name
)
296 LabeledStatement s
= DoLookupLabel (name
);
300 if (children
== null)
303 foreach (Block child
in children
) {
304 // if (!child.Implicit)
307 s
= child
.LookupLabel (name
);
315 public LabeledStatement
DoLookupLabel (string name
)
318 if (labels
.Contains (name
))
319 return ((LabeledStatement
) labels
[name
]);
323 return Parent.LookupLabel (name);
328 VariableInfo this_variable
= null;
331 // Returns the "this" instance variable of this block.
332 // See AddThisVariable() for more information.
334 public VariableInfo ThisVariable
{
336 if (this_variable
!= null)
337 return this_variable
;
338 else if (Parent
!= null)
339 return Parent
.ThisVariable
;
345 Hashtable child_variable_names
;
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.
352 public void AddChildVariableName (string name
)
354 if (child_variable_names
== null)
355 child_variable_names
= new CaseInsensitiveHashtable ();
357 if (!child_variable_names
.Contains (name
))
358 child_variable_names
.Add (name
, true);
362 // Marks all variables from block @block and all its children as being
363 // used in a child block.
365 public void AddChildVariableNames (Block block
)
367 if (block
.Variables
!= null) {
368 foreach (string name
in block
.Variables
.Keys
)
369 AddChildVariableName (name
);
372 foreach (Block child
in block
.children
) {
373 if (child
.Variables
!= null) {
374 foreach (string name
in child
.Variables
.Keys
)
375 AddChildVariableName (name
);
381 // Checks whether a variable name has already been used in a child block.
383 public bool IsVariableNameUsedInChildBlock (string name
)
385 if (child_variable_names
== null)
388 return child_variable_names
.Contains (name
);
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.
398 public VariableInfo
AddThisVariable (TypeContainer tc
, Location l
)
400 if (this_variable
!= null)
401 return this_variable
;
403 this_variable
= new VariableInfo (tc
, ID
, l
);
405 if (variables
== null)
406 variables
= new CaseInsensitiveHashtable ();
407 variables
.Add ("this", this_variable
);
409 return this_variable
;
412 public VariableInfo
AddVariable (EmitContext ec
, Expression type
, string name
, Location l
)
414 if (!variables_initialized
)
415 throw new InvalidOperationException();
417 VariableInfo vi
= AddVariable(type
, name
, null, loc
);
419 int priorCount
= count_variables
;
420 DeclSpace ds
= ec
.DeclSpace
;
422 if (!vi
.Resolve (ds
)) {
425 vi
.Number
= ++count_variables
;
426 if (vi
.StructInfo
!= null)
427 count_variables
+= vi
.StructInfo
.Count
;
429 if (priorCount
< count_variables
)
430 ec
.CurrentBranching
.CurrentUsageVector
.AddExtraLocals(count_variables
- priorCount
);
437 public VariableInfo
AddVariable (Expression type
, string name
, Parameters pars
, Location l
, string Alias
)
439 VariableInfo vi
= AddVariable (type
, name
, pars
, l
);
446 public VariableInfo
AddVariable (Expression type
, string name
, Parameters pars
, Location l
)
448 if (variables
== null)
449 variables
= new CaseInsensitiveHashtable ();
451 VariableInfo vi
= GetVariableInfo (name
);
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");
460 Report
.Error (30290, l
, "A local variable '" + name
+ "' is already " +
461 "defined in this scope");
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 " +
476 Parameter p
= pars
.GetParameterByName (name
, out idx
);
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");
487 vi
= new VariableInfo (type
, name
, ID
, l
);
489 variables
.Add (name
, vi
);
494 public bool AddConstant (Expression type
, string name
, Expression
value, Parameters pars
, Location l
)
496 if (AddVariable (type
, name
, pars
, l
) == null)
499 if (constants
== null)
500 constants
= new CaseInsensitiveHashtable ();
502 constants
.Add (name
, value);
506 public Hashtable Variables
{
512 public VariableInfo
GetVariableInfo (string name
)
514 if (variables
!= null) {
516 temp
= variables
[name
];
519 return (VariableInfo
) temp
;
524 return Parent
.GetVariableInfo (name
);
529 public Expression
GetVariableType (string name
)
531 VariableInfo vi
= GetVariableInfo (name
);
539 public Expression
GetConstantExpression (string name
)
541 if (constants
!= null) {
543 temp
= constants
[name
];
546 return (Expression
) temp
;
550 return Parent
.GetConstantExpression (name
);
556 /// True if the variable named @name has been defined
559 public bool IsVariableDefined (string name
)
561 // Console.WriteLine ("Looking up {0} in {1}", name, ID);
562 if (variables
!= null) {
563 if (variables
.Contains (name
))
568 return Parent
.IsVariableDefined (name
);
574 /// True if the variable named @name is a constant
576 public bool IsConstant (string name
)
580 e
= GetConstantExpression (name
);
586 /// Use to fetch the statement associated with this label
588 public Statement
this [string name
] {
590 return (Statement
) labels
[name
];
594 Parameters parameters
= null;
595 public Parameters Parameters
{
598 return Parent
.Parameters
;
605 /// A list of labels that were not used within this block
607 public string [] GetUnreferenced ()
609 // FIXME: Implement me
613 public void AddStatement (Statement s
)
630 bool variables_initialized
= false;
631 int count_variables
= 0, first_variable
= 0;
633 void UpdateVariableInfo (EmitContext ec
)
635 DeclSpace ds
= ec
.DeclSpace
;
640 first_variable
+= Parent
.CountVariables
;
642 count_variables
= first_variable
;
643 if (variables
!= null) {
644 foreach (VariableInfo vi
in variables
.Values
) {
645 if (!vi
.Resolve (ds
)) {
650 vi
.Number
= ++count_variables
;
652 if (vi
.StructInfo
!= null)
653 count_variables
+= vi
.StructInfo
.Count
;
657 variables_initialized
= true;
662 // The number of local variables in this block
664 public int CountVariables
667 if (!variables_initialized
)
668 throw new Exception ();
670 return count_variables
;
675 /// Emits the variable declarations and labels.
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.
683 public void EmitMeta (EmitContext ec
, Block toplevel
)
685 //DeclSpace ds = ec.DeclSpace;
686 ILGenerator ig
= ec
.ig
;
688 if (!variables_initialized
)
689 UpdateVariableInfo (ec
);
692 // Process this block variables
694 if (variables
!= null){
695 //local_builders = new CaseInsensitiveHashtable ();
697 foreach (DictionaryEntry de
in variables
){
698 string name
= (string) de
.Key
;
700 if (!isLateBindingRequired) {
701 if (name.Equals (Block.lateBindingArgs) ||
702 name.Equals (Block.lateBindingArgNames) ||
703 name.Equals (Block.lateBindingCopyBack))
707 VariableInfo vi
= (VariableInfo
) de
.Value
;
709 if (vi
.VariableType
== null)
712 if (vi
.Alias
== null)
713 vi
.LocalBuilder
= ig
.DeclareLocal (vi
.VariableType
);
715 if (CodeGen
.SymbolWriter
!= null && vi
.LocalBuilder
!= null)
716 vi
.LocalBuilder
.SetLocalSymInfo (name
);
718 if (constants
== null)
721 Expression cv
= (Expression
) constants
[name
];
725 Expression e
= cv
.Resolve (ec
);
729 if (!(e
is Constant
)){
730 Report
.Error (133, vi
.Location
,
731 "The expression being assigned to '" +
732 name
+ "' must be constant (" + e
+ ")");
736 constants
.Remove (name
);
737 constants
.Add (name
, e
);
742 // Now, handle the children
744 if (children
!= null){
745 foreach (Block b
in children
)
746 b
.EmitMeta (ec
, toplevel
);
750 public void UsageWarning ()
754 if (variables
!= null){
755 foreach (DictionaryEntry de
in variables
){
756 VariableInfo vi
= (VariableInfo
) de
.Value
;
761 name
= (string) de
.Key
;
765 219, vi
.Location
, "The variable '" + name
+
766 "' is assigned but its value is never used");
768 if (!(name
.Equals(lateBindingArgs
)||name
.Equals(lateBindingArgNames
)||name
.Equals(lateBindingCopyBack
)))
770 168, vi
.Location
, "The variable '" +
771 name
+"' is declared but never used");
776 if (children
!= null)
777 foreach (Block b
in children
)
781 bool has_ret
= false;
783 public override bool Resolve (EmitContext ec
)
785 Block prev_block
= ec
.CurrentBlock
;
788 ec
.CurrentBlock
= this;
790 if (!variables_initialized
)
791 UpdateVariableInfo (ec
);
793 ec
.StartFlowBranching (this);
795 Report
.Debug (1, "RESOLVE BLOCK", StartLocation
, ec
.CurrentBranching
);
797 ArrayList new_statements
= new ArrayList ();
798 bool unreachable
= false, warning_shown
= false;
800 foreach (Statement s
in statements
) {
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
);
812 if (s
.Resolve (ec
) == false) {
817 if (s
is LabeledStatement
)
820 unreachable
= ! ec
.CurrentBranching
.IsReachable ();
822 new_statements
.Add (s
);
825 statements
= new_statements
;
827 Report
.Debug (1, "RESOLVE BLOCK DONE", StartLocation
, ec
.CurrentBranching
);
829 FlowReturns returns
= ec
.EndFlowBranching ();
830 ec
.CurrentBlock
= prev_block
;
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
))
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");
845 if ((returns
== FlowReturns
.ALWAYS
) ||
846 (returns
== FlowReturns
.EXCEPTION
) ||
847 (returns
== FlowReturns
.UNREACHABLE
))
853 protected override bool DoEmit (EmitContext ec
)
855 Block prev_block
= ec
.CurrentBlock
;
857 ec
.CurrentBlock
= this;
859 ec
.Mark (StartLocation
);
860 foreach (Statement s
in statements
)
863 ec
.Mark (EndLocation
);
865 ec
.CurrentBlock
= prev_block
;
869 public override string ToString ()
871 return String
.Format ("{0} ({1}:{2})", GetType (),ID
, StartLocation
);
877 /// Block represents a VB.NET method block.
881 /// This class is used in a number of places: either to represent
882 /// explicit blocks that the programmer places or implicit blocks.
884 /// Implicit blocks are used as labels or to introduce variable
887 public class MethodBlock
: Block
{
888 public readonly string MethodName
;
889 public Block onerror
;
890 public ArrayList Pending_Assigns
;
892 public MethodBlock (Block parent
, string MethodName
)
893 : base (parent
, false, Location
.Null
, Location
.Null
)
895 this.MethodName
= MethodName
;
898 public MethodBlock (Block parent
, bool implicit_block
, string MethodName
)
899 : base (parent
, implicit_block
, Location
.Null
, Location
.Null
)
901 this.MethodName
= MethodName
;
904 public MethodBlock (Block parent
, bool implicit_block
, Parameters parameters
, string MethodName
)
905 : base (parent
, implicit_block
, parameters
, Location
.Null
, Location
.Null
)
907 this.MethodName
= MethodName
;
910 public MethodBlock (Block parent
, Location start
, Location end
, String MethodName
)
911 : base (parent
, false, start
, end
)
913 this.MethodName
= MethodName
;
916 public MethodBlock (Block parent
, Parameters parameters
, Location start
, Location end
, string MethodName
)
917 : base (parent
, false, parameters
, start
, end
)
919 this.MethodName
= MethodName
;
922 public MethodBlock (Block parent
, bool implicit_block
, Location start
, Location end
, string MethodName
)
923 : base (parent
, implicit_block
, Parameters
.EmptyReadOnlyParameters
,
926 this.MethodName
= MethodName
;
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
)
933 this.MethodName
= MethodName
;
938 } // namespace Mono.MonoBASIC