📄 statement.cs
字号:
} } public override string ToString () { return String.Format ("LocalInfo ({0},{1},{2},{3})", Name, Type, VariableInfo, Location); } public bool Used { get { return (flags & Flags.Used) != 0; } set { flags = value ? (flags | Flags.Used) : (unchecked (flags & ~Flags.Used)); } } public bool ReadOnly { get { return (flags & Flags.ReadOnly) != 0; } } public void SetReadOnlyContext (ReadOnlyContext context) { flags |= Flags.ReadOnly; ro_context = context; } public string GetReadOnlyContext () { if (!ReadOnly) throw new InternalErrorException ("Variable is not readonly"); switch (ro_context) { case ReadOnlyContext.Fixed: return "fixed variable"; case ReadOnlyContext.Foreach: return "foreach iteration variable"; case ReadOnlyContext.Using: return "using variable"; } throw new NotImplementedException (); } // // Whether the variable is pinned, if Pinned the variable has been // allocated in a pinned slot with DeclareLocal. // public bool Pinned { get { return (flags & Flags.Pinned) != 0; } set { flags = value ? (flags | Flags.Pinned) : (flags & ~Flags.Pinned); } } public bool IsThis { get { return (flags & Flags.IsThis) != 0; } set { flags = value ? (flags | Flags.IsThis) : (flags & ~Flags.IsThis); } } } /// <summary> /// Block represents a C# block. /// </summary> /// /// <remarks> /// This class is used in a number of places: either to represent /// explicit blocks that the programmer places or implicit blocks. /// /// Implicit blocks are used as labels or to introduce variable /// declarations. /// /// Top-level blocks derive from Block, and they are called ToplevelBlock /// they contain extra information that is not necessary on normal blocks. /// </remarks> public class Block : Statement { public Block Parent; public readonly Location StartLocation; public Location EndLocation = Location.Null; public readonly ToplevelBlock Toplevel; [Flags] public enum Flags : ushort { Implicit = 1, Unchecked = 2, BlockUsed = 4, VariablesInitialized = 8, HasRet = 16, IsDestructor = 32, IsToplevel = 64, Unsafe = 128, HasVarargs = 256 // Used in ToplevelBlock } protected Flags flags; public bool Implicit { get { return (flags & Flags.Implicit) != 0; } } public bool Unchecked { get { return (flags & Flags.Unchecked) != 0; } set { flags |= Flags.Unchecked; } } public bool Unsafe { get { return (flags & Flags.Unsafe) != 0; } set { flags |= Flags.Unsafe; } } // // The statements in this block // ArrayList statements; int num_statements; // // An array of Blocks. We keep track of children just // to generate the local variable declarations. // // Statements and child statements are handled through the // statements. // ArrayList children; // // Labels. (label, block) pairs. // Hashtable labels; // // Keeps track of (name, type) pairs // IDictionary variables; // // Keeps track of constants Hashtable constants; // // Temporary variables. // ArrayList temporary_variables; // // If this is a switch section, the enclosing switch block. // Block switch_block; protected static int id; int this_id; public Block (Block parent) : this (parent, (Flags) 0, Location.Null, Location.Null) { } public Block (Block parent, Flags flags) : this (parent, flags, Location.Null, Location.Null) { } public Block (Block parent, Location start, Location end) : this (parent, (Flags) 0, start, end) { } public Block (Block parent, Flags flags, Location start, Location end) { if (parent != null) parent.AddChild (this); this.Parent = parent; this.flags = flags; this.StartLocation = start; this.EndLocation = end; this.loc = start; this_id = id++; statements = new ArrayList (); if ((flags & Flags.IsToplevel) != 0) Toplevel = (ToplevelBlock) this; else Toplevel = parent.Toplevel; if (parent != null && Implicit) { if (parent.known_variables == null) parent.known_variables = new Hashtable (); // share with parent known_variables = parent.known_variables; } } public Block CreateSwitchBlock (Location start) { Block new_block = new Block (this, start, start); new_block.switch_block = this; return new_block; } public int ID { get { return this_id; } } protected IDictionary Variables { get { if (variables == null) variables = new ListDictionary (); return variables; } } void AddChild (Block b) { if (children == null) children = new ArrayList (); children.Add (b); } public void SetEndLocation (Location loc) { EndLocation = loc; } /// <summary> /// Adds a label to the current block. /// </summary> /// /// <returns> /// false if the name already exists in this block. true /// otherwise. /// </returns> /// public bool AddLabel (string name, LabeledStatement target, Location loc) { if (switch_block != null) return switch_block.AddLabel (name, target, loc); Block cur = this; while (cur != null) { if (cur.DoLookupLabel (name) != null) { Report.Error ( 140, loc, "The label `{0}' is a duplicate", name); return false; } if (!Implicit) break; cur = cur.Parent; } while (cur != null) { if (cur.DoLookupLabel (name) != null) { Report.Error ( 158, loc, "The label `{0}' shadows another label " + "by the same name in a contained scope.", name); return false; } if (children != null) { foreach (Block b in children) { LabeledStatement s = b.DoLookupLabel (name); if (s == null) continue; Report.Error ( 158, s.loc, "The label `{0}' shadows another " + "label by the same name in a " + "contained scope.", name); return false; } } cur = cur.Parent; } if (labels == null) labels = new Hashtable (); labels.Add (name, target); return true; } public LabeledStatement LookupLabel (string name) { LabeledStatement s = DoLookupLabel (name); if (s != null) return s; if (children == null) return null; foreach (Block child in children) { if (!child.Implicit) continue; s = child.LookupLabel (name); if (s != null) return s; } return null; } LabeledStatement DoLookupLabel (string name) { if (switch_block != null) return switch_block.LookupLabel (name); if (labels != null) if (labels.Contains (name)) return ((LabeledStatement) labels [name]); return null; } Hashtable known_variables; // <summary> // Marks a variable with name @name as being used in this or a child block. // If a variable name has been used in a child block, it's illegal to // declare a variable with the same name in the current block. // </summary> void AddKnownVariable (string name, LocalInfo info) { if (known_variables == null) known_variables = new Hashtable (); known_variables [name] = info; } LocalInfo GetKnownVariableInfo (string name) { if (known_variables == null) return null; return (LocalInfo) known_variables [name]; } public bool CheckInvariantMeaningInBlock (string name, Expression e, Location loc) { Block b = this; LocalInfo kvi = b.GetKnownVariableInfo (name); while (kvi == null) { while (b.Implicit) b = b.Parent; b = b.Parent; if (b == null) return true; kvi = b.GetKnownVariableInfo (name); } if (kvi.Block == b) return true; // Is kvi.Block nested inside 'b' if (b.known_variables != kvi.Block.known_variables) { // // If a variable by the same name it defined in a nested block of this // block, we violate the invariant meaning in a block. // if (b == this) { Report.SymbolRelatedToPreviousError (kvi.Location, name); Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", name); return false; } // // It's ok if the definition is in a nested subblock of b, but not // nested inside this block -- a definition in a sibling block // should not affect us. // return true; } // // Block 'b' and kvi.Block are the same textual block. // However, different variables are extant. // // Check if the variable is in scope in both blocks. We use // an indirect check that depends on AddVariable doing its // part in maintaining the invariant-meaning-in-block property. // if (e is LocalVariableReference || (e is Constant && b.GetLocalInfo (name) != null)) return true; // // Even though we detected the error when the name is used, we // treat it as if the variable declaration was in error. // Report.SymbolRelatedToPreviousError (loc, name); Error_AlreadyDeclared (kvi.Location, name, "parent or current"); return false; } public LocalInfo AddVariable (Expression type, string name, Location l) { LocalInfo vi = GetLocalInfo (name); if (vi != null) { Report.SymbolRelatedToPreviousError (vi.Location, name); if (known_variables == vi.Block.known_variables) Report.Error (128, l, "A local variable named `{0}' is already defined in this scope", name); else Error_AlreadyDeclared (l, name, "parent"); return null; } vi = GetKnownVariableInfo (name); if (vi != null) { Report.SymbolRelatedToPreviousError (vi.Location, name); Error_AlreadyDeclared (l, name, "child"); return null; } int idx; Parameter p = Toplevel.Parameters.GetParameterByName (name, out idx); if (p != null) { Report.SymbolRelatedToPreviousError (p.Location, name); Error_AlreadyDeclared (l, name, "method argument"); return null; } vi = new LocalInfo (type, name, this, l); Variables.Add (name, vi); for (Block b = this; b != null; b = b.Parent) b.AddKnownVariable (name, vi); if ((flags & Flags.VariablesInitialized) != 0) throw new Exception (); return vi; } void Error_AlreadyDeclared (Location loc, string var, string reason) { Report.Error (136, loc, "A local variable named `{0}' cannot be declared in this scope because it would give a different meaning to `{0}', " + "which is already used in a `{1}' scope", var, reason); } public bool AddConstant (Expression type, string name, Expression value, Location l) { if (AddVariable (type, name, l) == null) return false; if (constants == null) constants = new Hashtable (); constants.Add (name, value); // A block is considered used if we perform an initialization in a local declaration, even if it is constant. Use (); return true; } static int next_temp_id = 0; public LocalInfo AddTemporaryVariable (TypeExpr te, Location loc) { if (temporary_variables == null) temporary_variables = new ArrayList (); int id = ++next_temp_id; string name = "$s_" + id.ToString (); LocalInfo li = new LocalInfo (te, name, this, loc); li.CompilerGenerated = true; temporary_variables.Add (li); return li; } public LocalInfo GetLocalInfo (string name) { for (Block b = this; b != null; b = b.Parent) { if (b.variables != null) { LocalInfo ret = b.variables [name] as LocalInfo; if (ret != null) return ret; } } return null; } public Expression GetVariableType (string name) { LocalInfo vi = GetLocalInfo (name); return vi == null ? null : vi.Type; } public Expression GetConstantExpression (string name) { for (Block b = this; b != null; b = b.Parent) { if (b.constants != null) { Expression ret = b.constants [name] as Expression; if (ret != null) return ret; } } return null; } public void AddStatement (Statement s) { statements.Add (s); flags |= Flags.BlockUsed; } public bool Used { get { return (flags & Flags.BlockUsed) != 0; } } public void Use () { flags |= Flags.BlockUsed; } public bool HasRet { get { return (flags & Flags.HasRet) != 0; } } public bool IsDestructor { get { return (flags & Flags.IsDestructor) != 0; } } public void SetDestructor () { flags |= Flags.IsDestructor; } VariableMap param_map, local_map; public VariableMap ParameterMap { get { if ((flags & Flags.VariablesInitialized) == 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -