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

📄 assign.cs

📁 C#编译器源代码。Micorsoft开放源代码
💻 CS
📖 第 1 页 / 共 2 页
字号:
//// assign.cs: Assignments.//// Author://   Miguel de Icaza (miguel@ximian.com)//   Martin Baulig (martin@ximian.com)//// (C) 2001, 2002, 2003 Ximian, Inc.// (C) 2004 Novell, Inc//using System;using System.Reflection;using System.Reflection.Emit;namespace Mono.CSharp {	/// <summary>	///   This interface is implemented by expressions that can be assigned to.	/// </summary>	/// <remarks>	///   This interface is implemented by Expressions whose values can not	///   store the result on the top of the stack.	///	///   Expressions implementing this (Properties, Indexers and Arrays) would	///   perform an assignment of the Expression "source" into its final	///   location.	///	///   No values on the top of the stack are expected to be left by	///   invoking this method.	/// </remarks>	public interface IAssignMethod {		//		// This is an extra version of Emit. If leave_copy is `true'		// A copy of the expression will be left on the stack at the		// end of the code generated for EmitAssign		//		void Emit (EmitContext ec, bool leave_copy);				//		// This method does the assignment		// `source' will be stored into the location specified by `this'		// if `leave_copy' is true, a copy of `source' will be left on the stack		// if `prepare_for_load' is true, when `source' is emitted, there will		// be data on the stack that it can use to compuatate its value. This is		// for expressions like a [f ()] ++, where you can't call `f ()' twice.		//		void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load);				/*		For simple assignments, this interface is very simple, EmitAssign is called with source		as the source expression and leave_copy and prepare_for_load false.				For compound assignments it gets complicated.				EmitAssign will be called as before, however, prepare_for_load will be		true. The @source expression will contain an expression		which calls Emit. So, the calls look like:				this.EmitAssign (ec, source, false, true) ->			source.Emit (ec); ->				[...] ->					this.Emit (ec, false); ->					end this.Emit (ec, false); ->				end [...]			end source.Emit (ec);		end this.EmitAssign (ec, source, false, true)						When prepare_for_load is true, EmitAssign emits a `token' on the stack that		Emit will use for its state.				Let's take FieldExpr as an example. assume we are emitting f ().y += 1;				Here is the call tree again. This time, each call is annotated with the IL		it produces:				this.EmitAssign (ec, source, false, true)			call f			dup						Binary.Emit ()				this.Emit (ec, false);				ldfld y				end this.Emit (ec, false);								IntConstant.Emit ()				ldc.i4.1				end IntConstant.Emit								add			end Binary.Emit ()						stfld		end this.EmitAssign (ec, source, false, true)				Observe two things:			1) EmitAssign left a token on the stack. It was the result of f ().			2) This token was used by Emit				leave_copy (in both EmitAssign and Emit) tells the compiler to leave a copy		of the expression at that point in evaluation. This is used for pre/post inc/dec		and for a = x += y. Let's do the above example with leave_copy true in EmitAssign				this.EmitAssign (ec, source, true, true)			call f			dup						Binary.Emit ()				this.Emit (ec, false);				ldfld y				end this.Emit (ec, false);								IntConstant.Emit ()				ldc.i4.1				end IntConstant.Emit								add			end Binary.Emit ()						dup			stloc temp			stfld			ldloc temp		end this.EmitAssign (ec, source, true, true)				And with it true in Emit				this.EmitAssign (ec, source, false, true)			call f			dup						Binary.Emit ()				this.Emit (ec, true);				ldfld y				dup				stloc temp				end this.Emit (ec, true);								IntConstant.Emit ()				ldc.i4.1				end IntConstant.Emit								add			end Binary.Emit ()						stfld			ldloc temp		end this.EmitAssign (ec, source, false, true)				Note that these two examples are what happens for ++x and x++, respectively.		*/	}	/// <summary>	///   An Expression to hold a temporary value.	/// </summary>	/// <remarks>	///   The LocalTemporary class is used to hold temporary values of a given	///   type to "simulate" the expression semantics on property and indexer	///   access whose return values are void.	///	///   The local temporary is used to alter the normal flow of code generation	///   basically it creates a local variable, and its emit instruction generates	///   code to access this value, return its address or save its value.	///	///   If `is_address' is true, then the value that we store is the address to the	///   real value, and not the value itself. 	///	///   This is needed for a value type, because otherwise you just end up making a	///   copy of the value on the stack and modifying it. You really need a pointer	///   to the origional value so that you can modify it in that location. This	///   Does not happen with a class because a class is a pointer -- so you always	///   get the indirection.	///	///   The `is_address' stuff is really just a hack. We need to come up with a better	///   way to handle it.	/// </remarks>	public class LocalTemporary : Expression, IMemoryLocation {		LocalBuilder builder;		bool is_address;				public LocalTemporary (EmitContext ec, Type t) : this (ec, t, false) {}					public LocalTemporary (EmitContext ec, Type t, bool is_address) 		{			type = t;			eclass = ExprClass.Value;			loc = Location.Null;			builder = ec.GetTemporaryLocal (is_address ? TypeManager.GetReferenceType (t): t);			this.is_address = is_address;		}		public LocalTemporary (LocalBuilder b, Type t)		{			type = t;			eclass = ExprClass.Value;			loc = Location.Null;			builder = b;		}		public void Release (EmitContext ec)		{			ec.FreeTemporaryLocal (builder, type);			builder = null;		}				public override Expression DoResolve (EmitContext ec)		{			return this;		}		public override void Emit (EmitContext ec)		{			ILGenerator ig = ec.ig;						ig.Emit (OpCodes.Ldloc, builder);			// we need to copy from the pointer			if (is_address)				LoadFromPtr (ig, type);		}		// NB: if you have `is_address' on the stack there must		// be a managed pointer. Otherwise, it is the type from		// the ctor.		public void Store (EmitContext ec)		{			ILGenerator ig = ec.ig;			ig.Emit (OpCodes.Stloc, builder);		}		public void AddressOf (EmitContext ec, AddressOp mode)		{			// if is_address, than this is just the address anyways,			// so we just return this.			ILGenerator ig = ec.ig;							if (is_address)				ig.Emit (OpCodes.Ldloc, builder);			else				ig.Emit (OpCodes.Ldloca, builder);		}		public bool PointsToAddress {			get {				return is_address;			}		}	}	/// <summary>	///   The Assign node takes care of assigning the value of source into	///   the expression represented by target. 	/// </summary>	public class Assign : ExpressionStatement {		protected Expression target, source, real_source;		protected LocalTemporary temp = null, real_temp = null;		protected Assign embedded = null;		protected bool is_embedded = false;		protected bool must_free_temp = false;		public Assign (Expression target, Expression source)			: this (target, source, target.Location)		{		}		public Assign (Expression target, Expression source, Location l)		{			this.target = target;			this.source = this.real_source = source;			this.loc = l;		}		protected Assign (Assign embedded, Location l)			: this (embedded.target, embedded.source, l)		{			this.is_embedded = true;		}		protected virtual Assign GetEmbeddedAssign (Location loc)		{			return new Assign (this, loc);		}		public Expression Target {			get {				return target;			}			set {				target = value;			}		}		public Expression Source {			get {				return source;			}			set {				source = value;			}		}		public static void error70 (EventInfo ei, Location l)		{			Report.Error (70, l, "The event `" + TypeManager.CSharpSignature (ei) +				      "' can only appear on the left hand side of += or -= (except when" +				      " used from within the type `" + ei.DeclaringType + "')");		}		//		// Will return either `this' or an instance of `New'.		//		public override Expression DoResolve (EmitContext ec)		{			// Create an embedded assignment if our source is an assignment.			if (source is Assign)				source = embedded = ((Assign) source).GetEmbeddedAssign (loc);			real_source = source = source.Resolve (ec);			if (source == null) {				// Ensure that we don't propagate the error as spurious "uninitialized variable" errors.				target = target.ResolveLValue (ec, EmptyExpression.Null, Location);				return null;			}			//

⌨️ 快捷键说明

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