📄 ecore.cs
字号:
//// ecore.cs: Core of the Expression representation for the intermediate tree.//// Author:// Miguel de Icaza (miguel@ximian.com)//// (C) 2001, 2002, 2003 Ximian, Inc.////namespace Mono.CSharp { using System; using System.Collections; using System.Diagnostics; using System.Reflection; using System.Reflection.Emit; using System.Text; /// <remarks> /// The ExprClass class contains the is used to pass the /// classification of an expression (value, variable, namespace, /// type, method group, property access, event access, indexer access, /// nothing). /// </remarks> public enum ExprClass : byte { Invalid, Value, Variable, Namespace, Type, MethodGroup, PropertyAccess, EventAccess, IndexerAccess, Nothing, } /// <remarks> /// This is used to tell Resolve in which types of expressions we're /// interested. /// </remarks> [Flags] public enum ResolveFlags { // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess. VariableOrValue = 1, // Returns a type expression. Type = 2, // Returns a method group. MethodGroup = 4, // Mask of all the expression class flags. MaskExprClass = 7, // Disable control flow analysis while resolving the expression. // This is used when resolving the instance expression of a field expression. DisableFlowAnalysis = 8, // Set if this is resolving the first part of a MemberAccess. Intermediate = 16, // Disable control flow analysis _of struct_ while resolving the expression. // This is used when resolving the instance expression of a field expression. DisableStructFlowAnalysis = 32, } // // This is just as a hint to AddressOf of what will be done with the // address. [Flags] public enum AddressOp { Store = 1, Load = 2, LoadStore = 3 }; /// <summary> /// This interface is implemented by variables /// </summary> public interface IMemoryLocation { /// <summary> /// The AddressOf method should generate code that loads /// the address of the object and leaves it on the stack. /// /// The `mode' argument is used to notify the expression /// of whether this will be used to read from the address or /// write to the address. /// /// This is just a hint that can be used to provide good error /// reporting, and should have no other side effects. /// </summary> void AddressOf (EmitContext ec, AddressOp mode); } /// <summary> /// This interface is implemented by variables /// </summary> public interface IVariable { VariableInfo VariableInfo { get; } bool VerifyFixed (); } /// <remarks> /// Base class for expressions /// </remarks> public abstract class Expression { public ExprClass eclass; protected Type type; protected Location loc; public Type Type { get { return type; } set { type = value; } } public virtual Location Location { get { return loc; } } /// <summary> /// Utility wrapper routine for Error, just to beautify the code /// </summary> public void Error (int error, string s) { if (loc.IsNull) Report.Error (error, s); else Report.Error (error, loc, s); } /// <summary> /// Utility wrapper routine for Warning, just to beautify the code /// </summary> public void Warning (int code, string format, params object[] args) { Report.Warning (code, loc, format, args); } // Not nice but we have broken hierarchy public virtual void CheckMarshallByRefAccess (Type container) {} public virtual string GetSignatureForError () { return TypeManager.CSharpName (type); } public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check) { MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask; must_do_cs1540_check = false; // by default we do not check for this // // If only accessible to the current class or children // if (ma == MethodAttributes.Private) return invocation_type == mi.DeclaringType || TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType); if (mi.DeclaringType.Assembly == invocation_type.Assembly) { if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem) return true; } else { if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem) return false; } // Family and FamANDAssem require that we derive. // FamORAssem requires that we derive if in different assemblies. if (ma == MethodAttributes.Family || ma == MethodAttributes.FamANDAssem || ma == MethodAttributes.FamORAssem) { if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType)) return false; if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType)) must_do_cs1540_check = true; return true; } return true; } /// <summary> /// Performs semantic analysis on the Expression /// </summary> /// /// <remarks> /// The Resolve method is invoked to perform the semantic analysis /// on the node. /// /// The return value is an expression (it can be the /// same expression in some cases) or a new /// expression that better represents this node. /// /// For example, optimizations of Unary (LiteralInt) /// would return a new LiteralInt with a negated /// value. /// /// If there is an error during semantic analysis, /// then an error should be reported (using Report) /// and a null value should be returned. /// /// There are two side effects expected from calling /// Resolve(): the the field variable "eclass" should /// be set to any value of the enumeration /// `ExprClass' and the type variable should be set /// to a valid type (this is the type of the /// expression). /// </remarks> public abstract Expression DoResolve (EmitContext ec); public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side) { return null; } // // This is used if the expression should be resolved as a type or namespace name. // the default implementation fails. // public virtual FullNamedExpression ResolveAsTypeStep (EmitContext ec, bool silent) { return null; } // // This is used to resolve the expression as a type, a null // value will be returned if the expression is not a type // reference // public TypeExpr ResolveAsTypeTerminal (EmitContext ec, bool silent) { int errors = Report.Errors; FullNamedExpression fne = ResolveAsTypeStep (ec, silent); if (fne == null) return null; if (fne.eclass != ExprClass.Type) { if (!silent && errors == Report.Errors) fne.Error_UnexpectedKind (null, "type", loc); return null; } TypeExpr te = fne as TypeExpr; if (!te.CheckAccessLevel (ec.DeclSpace)) { ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type)); return null; } te.loc = loc; return te; } public static void ErrorIsInaccesible (Location loc, string name) { Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name); } protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container) { Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}';" + " the qualifier must be of type `{2}' (or derived from it)", TypeManager.GetFullNameSignature (m), TypeManager.CSharpName (qualifier), TypeManager.CSharpName (container)); } public virtual void Error_ValueCannotBeConverted (Location loc, Type target, bool expl) { if (Type.Name == target.Name){ Report.ExtraInformation (loc, String.Format ( "The type {0} has two conflicting definitions, one comes from {1} and the other from {2}", Type.Name, Type.Assembly.FullName, target.Assembly.FullName)); } if (expl) { Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'", GetSignatureForError (), TypeManager.CSharpName (target)); return; } Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this; bool b = Convert.ExplicitNumericConversion (e, target) != null; if (b || Convert.ExplicitReferenceConversionExists (Type, target) || Convert.ExplicitUnsafe (e, target) != null) { Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)", TypeManager.CSharpName (Type), TypeManager.CSharpName (target)); return; } if (Type != TypeManager.string_type && this is Constant && !(this is NullCast)) { Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'", GetSignatureForError (), TypeManager.CSharpName (target)); return; } Report.Error (29, loc, "Cannot implicitly convert type {0} to `{1}'", Type == TypeManager.anonymous_method_type ? "anonymous method" : "`" + GetSignatureForError () + "'", TypeManager.CSharpName (target)); } protected static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name) { Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'", TypeManager.CSharpName (type), name); } ResolveFlags ExprClassToResolveFlags () { switch (eclass) { case ExprClass.Type: case ExprClass.Namespace: return ResolveFlags.Type; case ExprClass.MethodGroup: return ResolveFlags.MethodGroup; case ExprClass.Value: case ExprClass.Variable: case ExprClass.PropertyAccess: case ExprClass.EventAccess: case ExprClass.IndexerAccess: return ResolveFlags.VariableOrValue; default: throw new Exception ("Expression " + GetType () + " ExprClass is Invalid after resolve"); } } /// <summary> /// Resolves an expression and performs semantic analysis on it. /// </summary> /// /// <remarks> /// Currently Resolve wraps DoResolve to perform sanity /// checking and assertion checking on what we expect from Resolve. /// </remarks> public Expression Resolve (EmitContext ec, ResolveFlags flags) { if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type) return ResolveAsTypeStep (ec, false); bool old_do_flow_analysis = ec.DoFlowAnalysis; bool old_omit_struct_analysis = ec.OmitStructFlowAnalysis; if ((flags & ResolveFlags.DisableFlowAnalysis) != 0) ec.DoFlowAnalysis = false; if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0) ec.OmitStructFlowAnalysis = true; Expression e; bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate; if (this is SimpleName) e = ((SimpleName) this).DoResolve (ec, intermediate); else e = DoResolve (ec); ec.DoFlowAnalysis = old_do_flow_analysis; ec.OmitStructFlowAnalysis = old_omit_struct_analysis; if (e == null) return null; if ((flags & e.ExprClassToResolveFlags ()) == 0) { e.Error_UnexpectedKind (flags, loc); return null; } if (e.type == null && !(e is Namespace)) { throw new Exception ( "Expression " + e.GetType () + " did not set its type after Resolve\n" + "called from: " + this.GetType ()); } return e; } /// <summary> /// Resolves an expression and performs semantic analysis on it. /// </summary> public Expression Resolve (EmitContext ec) { Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup); if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) { ((MethodGroupExpr) e).ReportUsageError (); return null; } return e; } public Constant ResolveAsConstant (EmitContext ec, MemberCore mc) { Expression e = Resolve (ec); if (e != null) { Constant c = e as Constant; if (c != null) return c; EmptyCast empty = e as EmptyCast; if (empty != null) { c = empty.Child as Constant; if (c != null) { // TODO: not sure about this maybe there is easier way how to use EmptyCast if (e.Type.IsEnum) c.Type = e.Type; return c; } } } Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ()); return null; } /// <summary> /// Resolves an expression for LValue assignment /// </summary> /// /// <remarks> /// Currently ResolveLValue wraps DoResolveLValue to perform sanity /// checking and assertion checking on what we expect from Resolve /// </remarks> public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc) { int errors = Report.Errors; Expression e = DoResolveLValue (ec, right_side); if (e == null) { if (errors == Report.Errors) Report.Error (131, loc, "The left-hand side of an assignment or mutating operation must be a variable, property or indexer"); return null; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -