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 {
37 public readonly Block Parent;
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 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);
193 /// Adds a label to the current block.
197 /// false if the name already exists in this block. true
202 public bool AddLabel (string name, LabeledStatement target)
205 labels = new CaseInsensitiveHashtable ();
206 if (labels.Contains (name))
209 labels.Add (name, target);
215 public bool AddLabel (string name, LabeledStatement target, Location loc)
218 if (switch_block != null)
219 return switch_block.AddLabel (name, target, loc);
222 while (cur != null) {
224 if (cur.DoLookupLabel (name) != null) {
226 140, loc, "The label '" + name +"' is a duplicate");
236 while (cur != null) {
237 if (cur.DoLookupLabel (name) != null) {
240 "The label '"+ name +"' shadows another label " +
241 "by the same name in a containing scope.");
245 if (children != null) {
246 foreach (Block b in children) {
247 LabeledStatement s = b.DoLookupLabel (name);
252 "The label '"+ name +"' shadows another " +
253 "label by the same name in a " +
254 "containing scope.");
261 labels = new CaseInsensitiveHashtable ();
262 if (labels.Contains (name))
265 labels.Add (name, target);
270 public LabeledStatement LookupLabel (string name)
272 LabeledStatement s = DoLookupLabel (name);
276 if (children == null)
279 foreach (Block child in children) {
280 // if (!child.Implicit)
283 s = child.LookupLabel (name);
291 public LabeledStatement DoLookupLabel (string name)
294 if (labels.Contains (name))
295 return ((LabeledStatement) labels [name]);
299 return Parent.LookupLabel (name);
304 VariableInfo this_variable = null;
307 // Returns the "this" instance variable of this block.
308 // See AddThisVariable() for more information.
310 public VariableInfo ThisVariable {
312 if (this_variable != null)
313 return this_variable;
314 else if (Parent != null)
315 return Parent.ThisVariable;
321 Hashtable child_variable_names;
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.
328 public void AddChildVariableName (string name)
330 if (child_variable_names == null)
331 child_variable_names = new CaseInsensitiveHashtable ();
333 if (!child_variable_names.Contains (name))
334 child_variable_names.Add (name, true);
338 // Marks all variables from block @block and all its children as being
339 // used in a child block.
341 public void AddChildVariableNames (Block block)
343 if (block.Variables != null) {
344 foreach (string name in block.Variables.Keys)
345 AddChildVariableName (name);
348 foreach (Block child in block.children) {
349 if (child.Variables != null) {
350 foreach (string name in child.Variables.Keys)
351 AddChildVariableName (name);
357 // Checks whether a variable name has already been used in a child block.
359 public bool IsVariableNameUsedInChildBlock (string name)
361 if (child_variable_names == null)
364 return child_variable_names.Contains (name);
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.
374 public VariableInfo AddThisVariable (TypeContainer tc, Location l)
376 if (this_variable != null)
377 return this_variable;
379 this_variable = new VariableInfo (tc, ID, l);
381 if (variables == null)
382 variables = new CaseInsensitiveHashtable ();
383 variables.Add ("this", this_variable);
385 return this_variable;
388 public VariableInfo AddVariable (EmitContext ec, Expression type, string name, Location l)
390 if (!variables_initialized)
391 throw new InvalidOperationException();
393 VariableInfo vi = AddVariable(type, name, null, loc);
395 int priorCount = count_variables;
396 DeclSpace ds = ec.DeclSpace;
398 if (!vi.Resolve (ds)) {
401 vi.Number = ++count_variables;
402 if (vi.StructInfo != null)
403 count_variables += vi.StructInfo.Count;
405 if (priorCount < count_variables)
406 ec.CurrentBranching.CurrentUsageVector.AddExtraLocals(count_variables - priorCount);
413 public VariableInfo AddVariable (Expression type, string name, Parameters pars, Location l, string Alias, bool Static)
415 VariableInfo vi = AddVariable (type, name, pars, l);
424 public VariableInfo AddVariable (Expression type, string name, Parameters pars, Location l)
426 if (variables == null)
427 variables = new CaseInsensitiveHashtable ();
429 VariableInfo vi = GetVariableInfo (name);
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");
438 Report.Error (30290, l, "A local variable '" + name + "' is already " +
439 "defined in this scope");
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 " +
454 Parameter p = pars.GetParameterByName (name, out idx);
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");
465 vi = new VariableInfo (type, name, ID, l);
467 variables.Add (name, vi);
472 public bool AddConstant (Expression type, string name, Expression value, Parameters pars, Location l)
474 if (AddVariable (type, name, pars, l) == null)
477 if (constants == null)
478 constants = new CaseInsensitiveHashtable ();
480 constants.Add (name, value);
484 public Hashtable Variables {
490 public VariableInfo GetVariableInfo (string name)
492 if (variables != null) {
494 temp = variables [name];
497 return (VariableInfo) temp;
502 return Parent.GetVariableInfo (name);
507 public Expression GetVariableType (string name)
509 VariableInfo vi = GetVariableInfo (name);
517 public Expression GetConstantExpression (string name)
519 if (constants != null) {
521 temp = constants [name];
524 return (Expression) temp;
528 return Parent.GetConstantExpression (name);
534 /// True if the variable named @name has been defined
537 public bool IsVariableDefined (string name)
539 // Console.WriteLine ("Looking up {0} in {1}", name, ID);
540 if (variables != null) {
541 if (variables.Contains (name))
546 return Parent.IsVariableDefined (name);
552 /// True if the variable named @name is a constant
554 public bool IsConstant (string name)
558 e = GetConstantExpression (name);
564 /// Use to fetch the statement associated with this label
566 public Statement this [string name] {
568 return (Statement) labels [name];
572 Parameters parameters = null;
573 public Parameters Parameters {
576 return Parent.Parameters;
583 /// A list of labels that were not used within this block
585 public string [] GetUnreferenced ()
587 // FIXME: Implement me
591 public void AddStatement (Statement s)
608 bool variables_initialized = false;
609 int count_variables = 0, first_variable = 0;
611 void UpdateVariableInfo (EmitContext ec)
613 DeclSpace ds = ec.DeclSpace;
618 first_variable += Parent.CountVariables;
620 count_variables = first_variable;
621 if (variables != null) {
622 foreach (VariableInfo vi in variables.Values) {
623 if (!vi.Resolve (ds)) {
628 vi.Number = ++count_variables;
630 if (vi.StructInfo != null)
631 count_variables += vi.StructInfo.Count;
635 variables_initialized = true;
640 // The number of local variables in this block
642 public int CountVariables
645 if (!variables_initialized)
646 throw new Exception ();
648 return count_variables;
653 /// Emits the variable declarations and labels.
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.
661 public void EmitMeta (EmitContext ec, Block toplevel)
663 //DeclSpace ds = ec.DeclSpace;
664 ILGenerator ig = ec.ig;
666 if (!variables_initialized)
667 UpdateVariableInfo (ec);
670 // Process this block variables
672 if (variables != null){
673 //local_builders = new CaseInsensitiveHashtable ();
675 foreach (DictionaryEntry de in variables){
676 string name = (string) de.Key;
678 if (!isLateBindingRequired) {
679 if (name.Equals (Block.lateBindingArgs) ||
680 name.Equals (Block.lateBindingArgNames) ||
681 name.Equals (Block.lateBindingCopyBack))
685 VariableInfo vi = (VariableInfo) de.Value;
687 if (vi.VariableType == null)
690 vi.LocalBuilder = ig.DeclareLocal (vi.VariableType);
692 if (CodeGen.SymbolWriter != null)
693 vi.LocalBuilder.SetLocalSymInfo (name);
695 if (constants == null)
698 Expression cv = (Expression) constants [name];
702 Expression e = cv.Resolve (ec);
706 if (!(e is Constant)){
707 Report.Error (133, vi.Location,
708 "The expression being assigned to '" +
709 name + "' must be constant (" + e + ")");
713 constants.Remove (name);
714 constants.Add (name, e);
719 // Now, handle the children
721 if (children != null){
722 foreach (Block b in children)
723 b.EmitMeta (ec, toplevel);
727 public void UsageWarning ()
731 if (variables != null){
732 foreach (DictionaryEntry de in variables){
733 VariableInfo vi = (VariableInfo) de.Value;
738 name = (string) de.Key;
742 219, vi.Location, "The variable '" + name +
743 "' is assigned but its value is never used");
745 if (!(name.Equals(lateBindingArgs)||name.Equals(lateBindingArgNames)||name.Equals(lateBindingCopyBack)))
747 168, vi.Location, "The variable '" +
748 name +"' is declared but never used");
753 if (children != null)
754 foreach (Block b in children)
758 bool has_ret = false;
760 public override bool Resolve (EmitContext ec)
762 Block prev_block = ec.CurrentBlock;
765 ec.CurrentBlock = this;
767 if (!variables_initialized)
768 UpdateVariableInfo (ec);
770 ec.StartFlowBranching (this);
772 Report.Debug (1, "RESOLVE BLOCK", StartLocation, ec.CurrentBranching);
774 ArrayList new_statements = new ArrayList ();
775 bool unreachable = false, warning_shown = false;
777 foreach (Statement s in statements) {
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);
789 if (s.Resolve (ec) == false) {
794 if (s is LabeledStatement)
797 unreachable = ! ec.CurrentBranching.IsReachable ();
799 new_statements.Add (s);
802 statements = new_statements;
804 Report.Debug (1, "RESOLVE BLOCK DONE", StartLocation, ec.CurrentBranching);
806 FlowReturns returns = ec.EndFlowBranching ();
807 ec.CurrentBlock = prev_block;
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))
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");
822 if ((returns == FlowReturns.ALWAYS) ||
823 (returns == FlowReturns.EXCEPTION) ||
824 (returns == FlowReturns.UNREACHABLE))
830 protected override bool DoEmit (EmitContext ec)
832 Block prev_block = ec.CurrentBlock;
834 ec.CurrentBlock = this;
836 ec.Mark (StartLocation);
837 foreach (Statement s in statements)
840 ec.Mark (EndLocation);
842 ec.CurrentBlock = prev_block;
846 public override string ToString ()
848 return String.Format ("{0} ({1}:{2})", GetType (),ID, StartLocation);
854 /// Block represents a VB.NET method block.
858 /// This class is used in a number of places: either to represent
859 /// explicit blocks that the programmer places or implicit blocks.
861 /// Implicit blocks are used as labels or to introduce variable
864 public class MethodBlock : Block {
865 public readonly string MethodName;
867 public MethodBlock (Block parent, string MethodName)
868 : base (parent, false, Location.Null, Location.Null)
870 this.MethodName = MethodName;
873 public MethodBlock (Block parent, bool implicit_block, string MethodName)
874 : base (parent, implicit_block, Location.Null, Location.Null)
876 this.MethodName = MethodName;
879 public MethodBlock (Block parent, bool implicit_block, Parameters parameters, string MethodName)
880 : base (parent, implicit_block, parameters, Location.Null, Location.Null)
882 this.MethodName = MethodName;
885 public MethodBlock (Block parent, Location start, Location end, String MethodName)
886 : base (parent, false, start, end)
888 this.MethodName = MethodName;
891 public MethodBlock (Block parent, Parameters parameters, Location start, Location end, string MethodName)
892 : base (parent, false, parameters, start, end)
894 this.MethodName = MethodName;
897 public MethodBlock (Block parent, bool implicit_block, Location start, Location end, string MethodName)
898 : base (parent, implicit_block, Parameters.EmptyReadOnlyParameters,
901 this.MethodName = MethodName;
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)
908 this.MethodName = MethodName;
913 } // namespace Mono.MonoBASIC