⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 statement.cs

📁 C#编译器源代码。Micorsoft开放源代码
💻 CS
📖 第 1 页 / 共 5 页
字号:
			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;		}		LocalInfo this_variable = null;		// <summary>		//   Returns the "this" instance variable of this block.		//   See AddThisVariable() for more information.		// </summary>		public LocalInfo ThisVariable {			get { return this_variable; }		}		// <summary>		//   This is used by non-static `struct' constructors which do not have an		//   initializer - in this case, the constructor must initialize all of the		//   struct's fields.  To do this, we add a "this" variable and use the flow		//   analysis code to ensure that it's been fully initialized before control		//   leaves the constructor.		// </summary>		public LocalInfo AddThisVariable (TypeContainer tc, Location l)		{			if (this_variable == null) {				this_variable = new LocalInfo (tc, this, l);				this_variable.Used = true;				this_variable.IsThis = true;				Variables.Add ("this", this_variable);			}			return this_variable;		}		public bool IsThisAssigned (EmitContext ec)		{			return this_variable == null || this_variable.IsThisAssigned (ec, loc);		}		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;		object converted;		Location loc;		Label il_label;		bool  il_label_set;		Label il_label_code;		bool  il_label_code_set;		public static readonly object NullStringCase = new object ();		//		// if expr == null, then it is the default case.		//		public SwitchLabel (Expression expr, Location l)		{			label = expr;			loc = l;		}		public Expression Label {			get {				return label;			}		}		public object Converted {			get {				return converted;			}		}		public Label GetILLabel (EmitContext ec)		{			if (!il_label_set){				il_label = ec.ig.DefineLabel ();				il_label_set = true;			}			return il_label;		}		public Label GetILLabelCode (EmitContext ec)		{			if (!il_label_code_set){				il_label_code = ec.ig.DefineLabel ();				il_label_code_set = true;			}			return il_label_code;		}								//		// Resolves the expression, reduces it to a literal if possible		// and then converts it to the requested type.		//		public bool ResolveAndReduce (EmitContext ec, Type required_type)		{				Expression e = label.Resolve (ec);			if (e == null)				return false;			Constant c = e as Constant;			if (c == null){				Report.Error (150, loc, "A constant value is expected");				return false;			}			if (required_type == TypeManager.string_type && c.GetValue () == null) {				converted = NullStringCase;				return true;			}			c = c.ToType (required_type, loc);			if (c == null)				return false;			converted = c.GetValue ();			return true;		}		public void Erorr_AlreadyOccurs ()		{			string label;			if (converted == null)				label = "default";			else if (converted == NullStringCase)				label = "null";			else				label = converted.ToString ();			Report.Error (152, loc, "The label `case {0}:' already occurs in this switch statement", label);		}	}	public class SwitchSection {		// An array of SwitchLabels.		public readonly ArrayList Labels;		public readonly Block Block;				public SwitchSection (ArrayList labels, Block block)		{			Labels = labels;			Block = block;		}	}		public class Switch : Statement {		public readonly ArrayList Sections;		public Expression Expr;		/// <summary>		///   Maps constants whose type type SwitchType to their  SwitchLabels.		/// </summary>		public IDictionary Elements;		/// <summary>		///   The governing switch type		/// </summary>		public Type SwitchType;		//		// Computed		//		Label default_target;		Expression new_expr;		bool is_constant;		SwitchSection constant_section;		SwitchSection default_section;		//		// The types allowed to be implicitly cast from		// on the governing type		//		static Type [] allowed_types;				public Switch (Expression e, ArrayList sects, Location l)		{			Expr = e;			Sections = sects;			loc = l;		}		public bool GotDefault {			get {				return default_section != null;			}		}		public Label DefaultTarget {			get {				return default_target;			}		}		//		// Determines the governing type for a switch.  The returned		// expression might be the expression from the switch, or an		// expression that includes any potential conversions to the		// integral types or to string.		//		Expression SwitchGoverningType (EmitContext ec, Type t)		{			if (t == TypeManager.byte_type ||			    t == TypeManager.sbyte_type ||			    t == TypeManager.ushort_type ||			    t == TypeManager.short_type ||			    t == TypeManager.uint32_type ||			    t == TypeManager.int32_type ||			    t == TypeManager.uint64_type ||			    t == TypeManager.int64_type ||			    t == TypeManager.char_type ||			    t == TypeManager.string_type ||			    t == TypeManager.bool_type ||			    t.IsSubclassOf (TypeManager.enum_type))				return Expr;			if (allowed_types == null){				allowed_types = new Type [] {					TypeManager.sbyte_type,					TypeManager.byte_type,					TypeManager.short_type,					TypeManager.ushort_type,					TypeManager.int32_type,					TypeManager.uint32_type,					TypeManager.int64_type,					TypeManager.uint64_type,					TypeManager.char_type,					TypeManager.string_type,					TypeManager.bool_type				};			}			//			// Try to find a *user* defined implicit conversion.			//			// If there is no implicit conversion, or if there are multiple			// conversions, we have to report an error			//			Expression converted = null;			foreach (Type tt in allowed_types){				Expression e;								e = Convert.ImplicitUserConversion (ec, Expr, tt, loc);				if (e == null)					continue;				//				// Ignore over-worked ImplicitUserConversions that do				// an implicit conversion in addition to the user conversion.				// 				if (!(e is UserCast))					continue;				if (converted != null){					Report.ExtraInformation (						loc,						String.Format ("reason: more than one conversion to an integral type exist for type {0}",							       TypeManager.CSharpName (Expr.Type)));					return null;				}				converted = e;			}			return converted;		}		//		// Performs the basic sanity checks on the switch statement		// (looks for duplicate keys and non-constant expressions).		//		// It also returns a hashtable with the keys that we will later		// use to compute the switch tables		//		bool CheckSwitch (EmitContext ec)		{			bool error = false;			Elements = Sections.Count > 10 ? 				(IDictionary)new Hashtable () : 				(IDictionary)new ListDictionary ();							foreach (SwitchSection ss in Sections){				foreach (SwitchLabel sl in ss.Labels){					if (sl.Label == null){						if (default_section != null){							sl.Erorr_AlreadyOccurs ();							error = true;						}						default_section = ss;						continue;					}					if (!sl.ResolveAndReduce (ec, SwitchType)){						error = true;						continue;					}										object key = sl.Converted;					try {						Elements.Add (key, sl);					}					catch (ArgumentException) {						 sl.Erorr_AlreadyOccurs ();						 error = true;					 }				}			}			return !error;		}		void EmitObjectInteger (ILGenerator ig, object k)		{			if (k is int)				IntConstant.EmitInt (ig, (int) k);			else if (k is Constant) {				EmitObjectInteger (ig, ((Constant) k).GetValue ());			} 			else if (k is uint)				IntConstant.EmitInt (ig, unchecked ((int) (uint) k));			else if (k is long)			{				if ((long) k >= int.MinValue && (long) k <= int.MaxValue)				{					IntConstant.EmitInt (ig, (int) (long) k);					ig.Emit (OpCodes.Conv_I8);				}				else					LongConstant.EmitLong (ig, (long) k);			}			else if (k is ulong)			{				if ((ulong) k < (1L<<32))				{					IntConstant.EmitInt (ig, (int) (long) k);					ig.Emit (OpCodes.Conv_U8);				}				else				{					LongConstant.EmitLong (ig, unchecked ((long) (ulong) k));				}			}			else if (k is char)				IntConstant.EmitInt (ig, (int) ((char) k));			else if (k is sbyte)				IntConstant.EmitInt (ig, (int) ((sbyte) k));			else if (k is byte)				IntConstant.EmitInt (ig, (int) ((byte) k));			else if (k is short)				IntConstant.EmitInt (ig, (int) ((short) k));			else if (k is ushort)				IntConstant.EmitInt (ig, (int) ((ushort) k));			else if (k is bool)				IntConstant.EmitInt (ig, ((bool) k) ? 1 : 0);			else				throw new Exception ("Unhandled case");		}				// structure used to hold blocks of keys while calculating table switch		class KeyBlock : IComparable		{			public KeyBlock (long _nFirst)			{				nFirst = nLast = _nFirst;			}			public long nFirst;			public long nLast;			public ArrayList rgKeys = null;			// how many items are in the bucket			public int Size = 1;			public int Length			{				get { return (int) (nLast - nFirst + 1); }			}			public static long TotalLength (KeyBlock kbFirst, KeyBlock kbLast)			{				return kbLast.nLast - kbFirst.nFirst + 1;			}			public int CompareTo (object obj)			{				KeyBlock kb = (KeyBlock) obj;				int nLength = Length;				int nLengthOther = kb.Length;				if (nLengthOther == nLength)					return (int) (kb.nFirst - nFirst);				return nLength - nLengthOther;			}		}		/// <summary>		/// This method emits code for a lookup-based switch statement (non-string)		/// Basically it groups the cases into blocks that are at least half full,		/// and then spits out individual lookup opcodes for each block.		/// It emits the longest blocks first, and short blocks are just		/// handled with direct compares.		/// </summary>		/// <param name="ec"></param>		/// <param name="val"></param>		/// <returns></returns>		void TableSwitchEmit (EmitContext ec, LocalBuilder val)		{			int cElements = Elements.Count;			object [] rgKeys = new object [cElements];			Elements.Keys.CopyTo (rgKeys, 0);			Array.Sort (rgKeys);			// initialize the block list with one element per key			ArrayList rgKeyBlocks = new ArrayList ();			foreach (object key in rgKeys)				rgKeyBlocks.Add (new KeyBlock (System.Convert.ToInt64 (key)));			KeyBlock kbCurr;			// iteratively merge the blocks while they are at least half full			// there's probably a really cool way to do this with a tree...			while (rgKeyBlocks.Count > 1)			{				ArrayList rgKeyBlocksNew = new ArrayList ();				kbCurr = (KeyBlock) rgKeyBlocks [0];				for (int ikb = 1; ikb < rgKeyBlocks.Count; ikb++)				{					KeyBlock kb = (KeyBlock) rgKeyBlocks [ikb];					if ((kbCurr.Size + kb.Size) * 2 >=  KeyBlock.TotalLength (kbCurr, kb))					{						// merge blocks						kbCurr.nLast = kb.nLast;						kbCurr.Size += kb.Size;					}					else					{						// start a new block						rgKeyBlocksNew.Add (kbCurr);						kbCurr = kb;					}				}				rgKeyBlocksNew.Add (kbCurr);				if (rgKeyBlocks.Count == rgKeyBlocksNew.Count)					break;				rgKeyBlocks = rgKeyBlocksNew;			}			// initialize the key lists			foreach (KeyBlock kb in rgKeyBlocks)				kb.rgKeys = new ArrayList ();			// fill the key lists			int iBlockCurr = 0;			if (rgKeyBlocks.Count > 0) {				kbCurr = (KeyBlock) rgKeyBlocks [0];				foreach (object key in rgKeys)				{					bool fNextBlock = (key is UInt64) ? (ulong) key > (ulong) kbCurr.nLast :						System.Convert.ToInt64 (key) > kbCurr.nLast;					if (fNextBlock)						kbCurr = (KeyBlock) rgKeyBlocks [++iBlockCurr];					kbCurr.rgKeys.Add (key);				}			}			// sort the blocks so we can tackle the largest ones first			rgKeyBlocks.Sort ();			// okay now we can start...			ILGenerator ig = ec.ig;			Label lblEnd = ig.DefineLabel ();	// at the end ;-)			Label lblDefault = ig.DefineLabel ();			Type typeKeys = null;			if (rgKeys.Length > 0)				typeKeys = rgKeys [0].GetType ();	// used for conversions			Type compare_type;						if (TypeManager.IsEnumType (SwitchType))				compare_type = TypeManager.EnumToUnderlying (SwitchType);			else				compare_type = SwitchType;						for (int iBlock = rgKeyBlocks.Count - 1; iBlock >= 0; --iBlock)			{				KeyBlock kb = ((KeyBlock) rgKeyBlocks [iBlock]);				lblDefault = (iBlock == 0) ? DefaultTarget : ig.DefineLabel ();				if (kb.Length <= 2)				{					foreach (object key in kb.rgKeys)					{						ig.Emit (OpCodes.Ldloc, val);						EmitObjectInteger (ig, key);						SwitchLabel sl = (SwitchLabel) Elements [key];						ig.Emit (OpCodes.Beq, sl.GetILLabel (ec));					}				}				else				{					// TODO: if all the keys in the block are the same and there are					//       no gaps/defaults then just use a range-check.					if (compare_type == TypeManager.int64_type ||						compare_type == TypeManager.uint64_type)					{						// TODO: optimize constant/I4 cases						// check block range (could be > 2^31)						ig.Emit (OpCodes.Ldloc, val);						EmitObjectInteger (ig, System.Convert.ChangeType (kb.nFirst, typeKeys));						ig.Emit (OpCodes.Blt, lblDefault);						ig.Emit (OpCodes.Ldloc, val);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -