+
+ //
+ // A toplevel block contains extra information, the split is done
+ // only to separate information that would otherwise bloat the more
+ // lightweight Block.
+ //
+ // In particular, this was introduced when the support for Anonymous
+ // Methods was implemented.
+ //
+ public class ToplevelBlock : Block {
+ //
+ // Pointer to the host of this anonymous method, or null
+ // if we are the topmost block
+ //
+ ToplevelBlock container;
+ CaptureContext capture_context;
+ FlowBranching top_level_branching;
+
+ Hashtable capture_contexts;
+ ArrayList children;
+
+ //
+ // The parameters for the block.
+ //
+ public readonly Parameters Parameters;
+
+ public void RegisterCaptureContext (CaptureContext cc)
+ {
+ if (capture_contexts == null)
+ capture_contexts = new Hashtable ();
+ capture_contexts [cc] = cc;
+ }
+
+ public void CompleteContexts ()
+ {
+ if (capture_contexts == null)
+ return;
+
+ foreach (CaptureContext cc in capture_contexts.Keys){
+ cc.AdjustScopes ();
+ }
+ }
+
+ public CaptureContext ToplevelBlockCaptureContext {
+ get {
+ return capture_context;
+ }
+ }
+
+ public ToplevelBlock Container {
+ get {
+ return container;
+ }
+ }
+
+ protected void AddChild (ToplevelBlock block)
+ {
+ if (children == null)
+ children = new ArrayList ();
+
+ children.Add (block);
+ }
+
+ //
+ // Parent is only used by anonymous blocks to link back to their
+ // parents
+ //
+ public ToplevelBlock (ToplevelBlock container, Parameters parameters, Location start) :
+ this (container, (Flags) 0, parameters, start)
+ {
+ }
+
+ public ToplevelBlock (Parameters parameters, Location start) :
+ this (null, (Flags) 0, parameters, start)
+ {
+ }
+
+ public ToplevelBlock (Flags flags, Parameters parameters, Location start) :
+ this (null, flags, parameters, start)
+ {
+ }
+
+ public ToplevelBlock (ToplevelBlock container, Flags flags, Parameters parameters, Location start) :
+ base (null, flags | Flags.IsToplevel, start, Location.Null)
+ {
+ Parameters = parameters == null ? Parameters.EmptyReadOnlyParameters : parameters;
+ this.container = container;
+
+ if (container != null)
+ container.AddChild (this);
+ }
+
+ public ToplevelBlock (Location loc) : this (null, (Flags) 0, null, loc)
+ {
+ }
+
+ public void SetHaveAnonymousMethods (Location loc, AnonymousContainer host)
+ {
+ if (capture_context == null)
+ capture_context = new CaptureContext (this, loc, host);
+ }
+
+ public CaptureContext CaptureContext {
+ get {
+ return capture_context;
+ }
+ }
+
+ public FlowBranching TopLevelBranching {
+ get {
+ return top_level_branching;
+ }
+ }
+
+ //
+ // This is used if anonymous methods are used inside an iterator
+ // (see 2test-22.cs for an example).
+ //
+ // The AnonymousMethod is created while parsing - at a time when we don't
+ // know yet that we're inside an iterator, so it's `Container' is initially
+ // null. Later on, when resolving the iterator, we need to move the
+ // anonymous method into that iterator.
+ //
+ public void ReParent (ToplevelBlock new_parent, AnonymousContainer new_host)
+ {
+ foreach (ToplevelBlock block in children) {
+ if (block.CaptureContext == null)
+ continue;
+
+ block.container = new_parent;
+ block.CaptureContext.ReParent (new_parent, new_host);
+ }
+ }
+
+ //
+ // Returns a `ParameterReference' for the given name, or null if there
+ // is no such parameter
+ //
+ public ParameterReference GetParameterReference (string name, Location loc)
+ {
+ Parameter par;
+ int idx;
+
+ for (ToplevelBlock t = this; t != null; t = t.Container) {
+ Parameters pars = t.Parameters;
+ par = pars.GetParameterByName (name, out idx);
+ if (par != null)
+ return new ParameterReference (pars, this, idx, name, loc);
+ }
+ return null;
+ }
+
+ //
+ // Whether the parameter named `name' is local to this block,
+ // or false, if the parameter belongs to an encompassing block.
+ //
+ public bool IsLocalParameter (string name)
+ {
+ return Parameters.GetParameterByName (name) != null;
+ }
+
+ //
+ // Whether the `name' is a parameter reference
+ //
+ public bool IsParameterReference (string name)
+ {
+ for (ToplevelBlock t = this; t != null; t = t.Container) {
+ if (t.IsLocalParameter (name))
+ return true;
+ }
+ return false;
+ }
+
+ public bool ResolveMeta (EmitContext ec, InternalParameters ip)
+ {
+ int errors = Report.Errors;
+
+ if (top_level_branching != null)
+ return true;
+
+ ResolveMeta (this, ec, ip);
+
+ top_level_branching = ec.StartFlowBranching (this);
+
+ return Report.Errors == errors;
+ }
+ }
+
+ public class SwitchLabel {
+ Expression label;