X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fexpression.cs;h=5cf7fdb86541dfc754c26b3f3b46d4565786a7e5;hb=8d510ba7f34bbe25a5c6df1046b15bf94ead6acb;hp=5aca281857fb3dc4c076f6111c3b091cca717c77;hpb=5c3cca9701a6e3048e84f34327e668acea0b29af;p=mono.git diff --git a/mcs/mcs/expression.cs b/mcs/mcs/expression.cs index 5aca281857f..5cf7fdb8654 100755 --- a/mcs/mcs/expression.cs +++ b/mcs/mcs/expression.cs @@ -7,1833 +7,72 @@ // (C) 2001 Ximian, Inc. // // -// Ideas: -// Maybe we should make Resolve be an instance method that just calls -// the virtual DoResolve function and checks conditions like the eclass -// and type being set if a non-null value is returned. For robustness -// purposes. -// - -namespace CIR { - using System; - using System.Collections; - using System.Diagnostics; - using System.Reflection; - using System.Reflection.Emit; - using System.Text; - - // - // 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). - // - public enum ExprClass { - Invalid, - - Value, - Variable, - Namespace, - Type, - MethodGroup, - PropertyAccess, - EventAccess, - IndexerAccess, - Nothing, - } - - // - // An interface provided by expressions that can be used as - // LValues and can store the value on the top of the stack on - // their storage - // - public interface IStackStore { - - // - // The Store method should store the contents of the top - // of the stack into the storage that is implemented by - // the particular implementation of LValue - // - void Store (EmitContext ec); - } - - // - // This interface is implemented by variables - // - public interface IMemoryLocation { - // - // The AddressOf method should generate code that loads - // the address of the object and leaves it on the stack - // - void AddressOf (EmitContext ec); - } - - // - // Base class for expressions - // - public abstract class Expression { - protected ExprClass eclass; - protected Type type; - - public Type Type { - get { - return type; - } - - set { - type = value; - } - } - - public ExprClass ExprClass { - get { - return eclass; - } - - set { - eclass = value; - } - } - - // - // Utility wrapper routine for Error, just to beautify the code - // - static protected void Error (int error, string s) - { - Report.Error (error, s); - } - - static protected void Error (int error, Location loc, string s) - { - Report.Error (error, loc, s); - } - - // - // Utility wrapper routine for Warning, just to beautify the code - // - static protected void Warning (int warning, string s) - { - Report.Warning (warning, s); - } - - // - // Performs semantic analysis on the Expression - // - // - // - // 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). - // - - public abstract Expression DoResolve (EmitContext ec); - - public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side) - { - return DoResolve (ec); - } - - // - // Currently Resolve wraps DoResolve to perform sanity - // checking and assertion checking on what we expect from Resolve - // - public Expression Resolve (EmitContext ec) - { - Expression e = DoResolve (ec); - - if (e != null){ - if (e is SimpleName){ - SimpleName s = (SimpleName) e; - - Report.Error ( - 103, s.Location, - "The name `" + s.Name + "' could not be found in `" + - ec.TypeContainer.Name + "'"); - return null; - } - - if (e.ExprClass == ExprClass.Invalid) - throw new Exception ("Expression " + e + - " ExprClass is Invalid after resolve"); - - if (e.ExprClass != ExprClass.MethodGroup) - if (e.type == null) - throw new Exception ("Expression " + e + - " did not set its type after Resolve"); - } - - return e; - } - - // - // Just like `Resolve' above, but this allows SimpleNames to be returned. - // This is used by MemberAccess to construct long names that can not be - // partially resolved (namespace-qualified names for example). - // - public Expression ResolveWithSimpleName (EmitContext ec) - { - Expression e = DoResolve (ec); - - if (e != null){ - if (e is SimpleName) - return e; - - if (e.ExprClass == ExprClass.Invalid) - throw new Exception ("Expression " + e + - " ExprClass is Invalid after resolve"); - - if (e.ExprClass != ExprClass.MethodGroup) - if (e.type == null) - throw new Exception ("Expression " + e + - " did not set its type after Resolve"); - } - - return e; - } - - // - // Currently ResolveLValue wraps DoResolveLValue to perform sanity - // checking and assertion checking on what we expect from Resolve - // - public Expression ResolveLValue (EmitContext ec, Expression right_side) - { - Expression e = DoResolveLValue (ec, right_side); - - if (e != null){ - if (e is SimpleName){ - SimpleName s = (SimpleName) e; - - Report.Error ( - 103, s.Location, - "The name `" + s.Name + "' could not be found in `" + - ec.TypeContainer.Name + "'"); - return null; - } - - if (e.ExprClass == ExprClass.Invalid) - throw new Exception ("Expression " + e + - " ExprClass is Invalid after resolve"); - - if (e.ExprClass != ExprClass.MethodGroup) - if (e.type == null) - throw new Exception ("Expression " + e + - " did not set its type after Resolve"); - } - - return e; - } - - // - // Emits the code for the expression - // - // - // - // - // The Emit method is invoked to generate the code - // for the expression. - // - // - public abstract void Emit (EmitContext ec); - - // - // Protected constructor. Only derivate types should - // be able to be created - // - - protected Expression () - { - eclass = ExprClass.Invalid; - type = null; - } - - // - // Returns a literalized version of a literal FieldInfo - // - static Expression Literalize (FieldInfo fi) - { - Type t = fi.FieldType; - object v = fi.GetValue (fi); - - if (t == TypeManager.int32_type) - return new IntLiteral ((int) v); - else if (t == TypeManager.uint32_type) - return new UIntLiteral ((uint) v); - else if (t == TypeManager.int64_type) - return new LongLiteral ((long) v); - else if (t == TypeManager.uint64_type) - return new ULongLiteral ((ulong) v); - else if (t == TypeManager.float_type) - return new FloatLiteral ((float) v); - else if (t == TypeManager.double_type) - return new DoubleLiteral ((double) v); - else if (t == TypeManager.string_type) - return new StringLiteral ((string) v); - else if (t == TypeManager.short_type) - return new IntLiteral ((int) ((short)v)); - else if (t == TypeManager.ushort_type) - return new IntLiteral ((int) ((ushort)v)); - else if (t == TypeManager.sbyte_type) - return new IntLiteral ((int) ((sbyte)v)); - else if (t == TypeManager.byte_type) - return new IntLiteral ((int) ((byte)v)); - else if (t == TypeManager.char_type) - return new IntLiteral ((int) ((char)v)); - else - throw new Exception ("Unknown type for literal (" + v.GetType () + - "), details: " + fi); - } - - // - // Returns a fully formed expression after a MemberLookup - // - static Expression ExprClassFromMemberInfo (EmitContext ec, MemberInfo mi, Location loc) - { - if (mi is EventInfo){ - return new EventExpr ((EventInfo) mi, loc); - } else if (mi is FieldInfo){ - FieldInfo fi = (FieldInfo) mi; - - if (fi.IsLiteral){ - Expression e = Literalize (fi); - e.Resolve (ec); - - return e; - } else - return new FieldExpr (fi, loc); - } else if (mi is PropertyInfo){ - return new PropertyExpr ((PropertyInfo) mi, loc); - } else if (mi is Type) - return new TypeExpr ((Type) mi); - - return null; - } - - // - // FIXME: Probably implement a cache for (t,name,current_access_set)? - // - // FIXME: We need to cope with access permissions here, or this wont - // work! - // - // This code could use some optimizations, but we need to do some - // measurements. For example, we could use a delegate to `flag' when - // something can not any longer be a method-group (because it is something - // else). - // - // Return values: - // If the return value is an Array, then it is an array of - // MethodBases - // - // If the return value is an MemberInfo, it is anything, but a Method - // - // null on error. - // - // FIXME: When calling MemberLookup inside an `Invocation', we should pass - // the arguments here and have MemberLookup return only the methods that - // match the argument count/type, unlike we are doing now (we delay this - // decision). - // - // This is so we can catch correctly attempts to invoke instance methods - // from a static body (scan for error 120 in ResolveSimpleName). - // - public static Expression MemberLookup (EmitContext ec, Type t, string name, - bool same_type, MemberTypes mt, - BindingFlags bf, Location loc) - { - if (same_type) - bf |= BindingFlags.NonPublic; - - MemberInfo [] mi = ec.TypeContainer.RootContext.TypeManager.FindMembers ( - t, mt, bf, Type.FilterName, name); - - if (mi == null) - return null; - - // FIXME : How does this wierd case arise ? - if (mi.Length == 0) - return null; - - if (mi.Length == 1 && !(mi [0] is MethodBase)) - return Expression.ExprClassFromMemberInfo (ec, mi [0], loc); - - for (int i = 0; i < mi.Length; i++) - if (!(mi [i] is MethodBase)){ - Error (-5, "Do not know how to reproduce this case: " + - "Methods and non-Method with the same name, " + - "report this please"); - - for (i = 0; i < mi.Length; i++){ - Type tt = mi [i].GetType (); - - Console.WriteLine (i + ": " + mi [i]); - while (tt != TypeManager.object_type){ - Console.WriteLine (tt); - tt = tt.BaseType; - } - } - } - - return new MethodGroupExpr (mi); - } - - public const MemberTypes AllMemberTypes = - MemberTypes.Constructor | - MemberTypes.Event | - MemberTypes.Field | - MemberTypes.Method | - MemberTypes.NestedType | - MemberTypes.Property; - - public const BindingFlags AllBindingsFlags = - BindingFlags.Public | - BindingFlags.Static | - BindingFlags.Instance; - - public static Expression MemberLookup (EmitContext ec, Type t, string name, - bool same_type, Location loc) - { - return MemberLookup (ec, t, name, same_type, AllMemberTypes, AllBindingsFlags, loc); - } - - static public Expression ImplicitReferenceConversion (Expression expr, Type target_type) - { - Type expr_type = expr.Type; - - if (target_type == TypeManager.object_type) { - if (expr_type.IsClass) - return new EmptyCast (expr, target_type); - if (expr_type.IsValueType) - return new BoxedCast (expr); - } else if (expr_type.IsSubclassOf (target_type)) { - return new EmptyCast (expr, target_type); - } else { - // from any class-type S to any interface-type T. - if (expr_type.IsClass && target_type.IsInterface) { - - if (TypeManager.ImplementsInterface (expr_type, target_type)) - return new EmptyCast (expr, target_type); - else - return null; - } - - // from any interface type S to interface-type T. - if (expr_type.IsInterface && target_type.IsInterface) { - - if (TypeManager.ImplementsInterface (expr_type, target_type)) - return new EmptyCast (expr, target_type); - else - return null; - } - - // from an array-type S to an array-type of type T - if (expr_type.IsArray && target_type.IsArray) { - if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) { - - Type expr_element_type = expr_type.GetElementType (); - Type target_element_type = target_type.GetElementType (); - - if (!expr_element_type.IsValueType && !target_element_type.IsValueType) - if (StandardConversionExists (expr_element_type, - target_element_type)) - return new EmptyCast (expr, target_type); - } - } - - - // from an array-type to System.Array - if (expr_type.IsArray && target_type == TypeManager.array_type) - return new EmptyCast (expr, target_type); - - // from any delegate type to System.Delegate - if (expr_type.IsSubclassOf (TypeManager.delegate_type) && - target_type == TypeManager.delegate_type) - return new EmptyCast (expr, target_type); - - // from any array-type or delegate type into System.ICloneable. - if (expr_type.IsArray || expr_type.IsSubclassOf (TypeManager.delegate_type)) - if (target_type == TypeManager.icloneable_type) - return new EmptyCast (expr, target_type); - - // from the null type to any reference-type. - if (expr is NullLiteral) - return new EmptyCast (expr, target_type); - - return null; - - } - - return null; - } - - // - // Handles expressions like this: decimal d; d = 1; - // and changes them into: decimal d; d = new System.Decimal (1); - // - static Expression InternalTypeConstructor (EmitContext ec, Expression expr, Type target) - { - ArrayList args = new ArrayList (); - - args.Add (new Argument (expr, Argument.AType.Expression)); - - Expression ne = new New (target.FullName, args, - new Location (-1)); - - return ne.Resolve (ec); - } - - // - // Implicit Numeric Conversions. - // - // expr is the expression to convert, returns a new expression of type - // target_type or null if an implicit conversion is not possible. - // - // - static public Expression ImplicitNumericConversion (EmitContext ec, Expression expr, - Type target_type, Location loc) - { - Type expr_type = expr.Type; - - // - // Attempt to do the implicit constant expression conversions - - if (expr is IntLiteral){ - Expression e; - - e = TryImplicitIntConversion (target_type, (IntLiteral) expr); - if (e != null) - return e; - } else if (expr is LongLiteral){ - // - // Try the implicit constant expression conversion - // from long to ulong, instead of a nice routine, - // we just inline it - // - if (((LongLiteral) expr).Value > 0) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I8); - } - - if (expr_type == TypeManager.sbyte_type){ - // - // From sbyte to short, int, long, float, double. - // - if (target_type == TypeManager.int32_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I4); - if (target_type == TypeManager.int64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I8); - if (target_type == TypeManager.double_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_R8); - if (target_type == TypeManager.float_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); - if (target_type == TypeManager.short_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I2); - if (target_type == TypeManager.decimal_type) - return InternalTypeConstructor (ec, expr, target_type); - } else if (expr_type == TypeManager.byte_type){ - // - // From byte to short, ushort, int, uint, long, ulong, float, double - // - if ((target_type == TypeManager.short_type) || - (target_type == TypeManager.ushort_type) || - (target_type == TypeManager.int32_type) || - (target_type == TypeManager.uint32_type)) - return new EmptyCast (expr, target_type); - - if (target_type == TypeManager.uint64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U8); - if (target_type == TypeManager.int64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I8); - - if (target_type == TypeManager.float_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); - if (target_type == TypeManager.double_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_R8); - if (target_type == TypeManager.decimal_type) - return InternalTypeConstructor (ec, expr, target_type); - } else if (expr_type == TypeManager.short_type){ - // - // From short to int, long, float, double - // - if (target_type == TypeManager.int32_type) - return new EmptyCast (expr, target_type); - if (target_type == TypeManager.int64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I8); - if (target_type == TypeManager.double_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_R8); - if (target_type == TypeManager.float_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); - if (target_type == TypeManager.decimal_type) - return InternalTypeConstructor (ec, expr, target_type); - } else if (expr_type == TypeManager.ushort_type){ - // - // From ushort to int, uint, long, ulong, float, double - // - if (target_type == TypeManager.uint32_type) - return new EmptyCast (expr, target_type); - - if (target_type == TypeManager.uint64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U8); - if (target_type == TypeManager.int32_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I4); - if (target_type == TypeManager.int64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I8); - if (target_type == TypeManager.double_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_R8); - if (target_type == TypeManager.float_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); - if (target_type == TypeManager.decimal_type) - return InternalTypeConstructor (ec, expr, target_type); - } else if (expr_type == TypeManager.int32_type){ - // - // From int to long, float, double - // - if (target_type == TypeManager.int64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I8); - if (target_type == TypeManager.double_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_R8); - if (target_type == TypeManager.float_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); - if (target_type == TypeManager.decimal_type) - return InternalTypeConstructor (ec, expr, target_type); - } else if (expr_type == TypeManager.uint32_type){ - // - // From uint to long, ulong, float, double - // - if (target_type == TypeManager.int64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U8); - if (target_type == TypeManager.uint64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U8); - if (target_type == TypeManager.double_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un, - OpCodes.Conv_R8); - if (target_type == TypeManager.float_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un, - OpCodes.Conv_R4); - if (target_type == TypeManager.decimal_type) - return InternalTypeConstructor (ec, expr, target_type); - } else if ((expr_type == TypeManager.uint64_type) || - (expr_type == TypeManager.int64_type)){ - // - // From long/ulong to float, double - // - if (target_type == TypeManager.double_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un, - OpCodes.Conv_R8); - if (target_type == TypeManager.float_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un, - OpCodes.Conv_R4); - if (target_type == TypeManager.decimal_type) - return InternalTypeConstructor (ec, expr, target_type); - } else if (expr_type == TypeManager.char_type){ - // - // From char to ushort, int, uint, long, ulong, float, double - // - if ((target_type == TypeManager.ushort_type) || - (target_type == TypeManager.int32_type) || - (target_type == TypeManager.uint32_type)) - return new EmptyCast (expr, target_type); - if (target_type == TypeManager.uint64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U8); - if (target_type == TypeManager.int64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I8); - if (target_type == TypeManager.float_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); - if (target_type == TypeManager.double_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_R8); - if (target_type == TypeManager.decimal_type) - return InternalTypeConstructor (ec, expr, target_type); - } else if (expr_type == TypeManager.float_type){ - // - // float to double - // - if (target_type == TypeManager.double_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_R8); - } - - return null; - } - - // - // Determines if a standard implicit conversion exists from - // expr_type to target_type - // - public static bool StandardConversionExists (Type expr_type, Type target_type) - { - if (expr_type == target_type) - return true; - - // First numeric conversions - - if (expr_type == TypeManager.sbyte_type){ - // - // From sbyte to short, int, long, float, double. - // - if ((target_type == TypeManager.int32_type) || - (target_type == TypeManager.int64_type) || - (target_type == TypeManager.double_type) || - (target_type == TypeManager.float_type) || - (target_type == TypeManager.short_type) || - (target_type == TypeManager.decimal_type)) - return true; - - } else if (expr_type == TypeManager.byte_type){ - // - // From byte to short, ushort, int, uint, long, ulong, float, double - // - if ((target_type == TypeManager.short_type) || - (target_type == TypeManager.ushort_type) || - (target_type == TypeManager.int32_type) || - (target_type == TypeManager.uint32_type) || - (target_type == TypeManager.uint64_type) || - (target_type == TypeManager.int64_type) || - (target_type == TypeManager.float_type) || - (target_type == TypeManager.double_type) || - (target_type == TypeManager.decimal_type)) - return true; - - } else if (expr_type == TypeManager.short_type){ - // - // From short to int, long, float, double - // - if ((target_type == TypeManager.int32_type) || - (target_type == TypeManager.int64_type) || - (target_type == TypeManager.double_type) || - (target_type == TypeManager.float_type) || - (target_type == TypeManager.decimal_type)) - return true; - - } else if (expr_type == TypeManager.ushort_type){ - // - // From ushort to int, uint, long, ulong, float, double - // - if ((target_type == TypeManager.uint32_type) || - (target_type == TypeManager.uint64_type) || - (target_type == TypeManager.int32_type) || - (target_type == TypeManager.int64_type) || - (target_type == TypeManager.double_type) || - (target_type == TypeManager.float_type) || - (target_type == TypeManager.decimal_type)) - return true; - - } else if (expr_type == TypeManager.int32_type){ - // - // From int to long, float, double - // - if ((target_type == TypeManager.int64_type) || - (target_type == TypeManager.double_type) || - (target_type == TypeManager.float_type) || - (target_type == TypeManager.decimal_type)) - return true; - - } else if (expr_type == TypeManager.uint32_type){ - // - // From uint to long, ulong, float, double - // - if ((target_type == TypeManager.int64_type) || - (target_type == TypeManager.uint64_type) || - (target_type == TypeManager.double_type) || - (target_type == TypeManager.float_type) || - (target_type == TypeManager.decimal_type)) - return true; - - } else if ((expr_type == TypeManager.uint64_type) || - (expr_type == TypeManager.int64_type)) { - // - // From long/ulong to float, double - // - if ((target_type == TypeManager.double_type) || - (target_type == TypeManager.float_type) || - (target_type == TypeManager.decimal_type)) - return true; - - } else if (expr_type == TypeManager.char_type){ - // - // From char to ushort, int, uint, long, ulong, float, double - // - if ((target_type == TypeManager.ushort_type) || - (target_type == TypeManager.int32_type) || - (target_type == TypeManager.uint32_type) || - (target_type == TypeManager.uint64_type) || - (target_type == TypeManager.int64_type) || - (target_type == TypeManager.float_type) || - (target_type == TypeManager.double_type) || - (target_type == TypeManager.decimal_type)) - return true; - - } else if (expr_type == TypeManager.float_type){ - // - // float to double - // - if (target_type == TypeManager.double_type) - return true; - } - - // Next reference conversions - - if (target_type == TypeManager.object_type) { - if ((expr_type.IsClass) || - (expr_type.IsValueType)) - return true; - - } else if (expr_type.IsSubclassOf (target_type)) { - return true; - - } else { - // from any class-type S to any interface-type T. - if (expr_type.IsClass && target_type.IsInterface) - return true; - - // from any interface type S to interface-type T. - // FIXME : Is it right to use IsAssignableFrom ? - if (expr_type.IsInterface && target_type.IsInterface) - if (target_type.IsAssignableFrom (expr_type)) - return true; - - // from an array-type S to an array-type of type T - if (expr_type.IsArray && target_type.IsArray) { - if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) { - - Type expr_element_type = expr_type.GetElementType (); - Type target_element_type = target_type.GetElementType (); - - if (!expr_element_type.IsValueType && !target_element_type.IsValueType) - if (StandardConversionExists (expr_element_type, - target_element_type)) - return true; - } - } - - // from an array-type to System.Array - if (expr_type.IsArray && target_type.IsAssignableFrom (expr_type)) - return true; - - // from any delegate type to System.Delegate - if (expr_type.IsSubclassOf (TypeManager.delegate_type) && - target_type == TypeManager.delegate_type) - if (target_type.IsAssignableFrom (expr_type)) - return true; - - // from any array-type or delegate type into System.ICloneable. - if (expr_type.IsArray || expr_type.IsSubclassOf (TypeManager.delegate_type)) - if (target_type == TypeManager.icloneable_type) - return true; - - // from the null type to any reference-type. - // FIXME : How do we do this ? - - } - - return false; - } - - // - // Finds "most encompassed type" according to the spec (13.4.2) - // amongst the methods in the MethodGroupExpr which convert from a - // type encompassing source_type - // - static Type FindMostEncompassedType (MethodGroupExpr me, Type source_type) - { - Type best = null; - - for (int i = me.Methods.Length; i > 0; ) { - i--; - - MethodBase mb = me.Methods [i]; - ParameterData pd = Invocation.GetParameterData (mb); - Type param_type = pd.ParameterType (0); - - if (StandardConversionExists (source_type, param_type)) { - if (best == null) - best = param_type; - - if (StandardConversionExists (param_type, best)) - best = param_type; - } - } - - return best; - } - - // - // Finds "most encompassing type" according to the spec (13.4.2) - // amongst the methods in the MethodGroupExpr which convert to a - // type encompassed by target_type - // - static Type FindMostEncompassingType (MethodGroupExpr me, Type target) - { - Type best = null; - - for (int i = me.Methods.Length; i > 0; ) { - i--; - - MethodInfo mi = (MethodInfo) me.Methods [i]; - Type ret_type = mi.ReturnType; - - if (StandardConversionExists (ret_type, target)) { - if (best == null) - best = ret_type; - - if (!StandardConversionExists (ret_type, best)) - best = ret_type; - } - - } - - return best; - - } - - - // - // User-defined Implicit conversions - // - static public Expression ImplicitUserConversion (EmitContext ec, Expression source, - Type target, Location loc) - { - return UserDefinedConversion (ec, source, target, loc, false); - } - - // - // User-defined Explicit conversions - // - static public Expression ExplicitUserConversion (EmitContext ec, Expression source, - Type target, Location loc) - { - return UserDefinedConversion (ec, source, target, loc, true); - } - - // - // User-defined conversions - // - static public Expression UserDefinedConversion (EmitContext ec, Expression source, - Type target, Location loc, - bool look_for_explicit) - { - Expression mg1 = null, mg2 = null, mg3 = null, mg4 = null; - Expression mg5 = null, mg6 = null, mg7 = null, mg8 = null; - Expression e; - MethodBase method = null; - Type source_type = source.Type; - - string op_name; - - // If we have a boolean type, we need to check for the True operator - - // FIXME : How does the False operator come into the picture ? - // FIXME : This doesn't look complete and very correct ! - if (target == TypeManager.bool_type) - op_name = "op_True"; - else - op_name = "op_Implicit"; - - mg1 = MemberLookup (ec, source_type, op_name, false, loc); - - if (source_type.BaseType != null) - mg2 = MemberLookup (ec, source_type.BaseType, op_name, false, loc); - - mg3 = MemberLookup (ec, target, op_name, false, loc); - - if (target.BaseType != null) - mg4 = MemberLookup (ec, target.BaseType, op_name, false, loc); - - MethodGroupExpr union1 = Invocation.MakeUnionSet (mg1, mg2); - MethodGroupExpr union2 = Invocation.MakeUnionSet (mg3, mg4); - - MethodGroupExpr union3 = Invocation.MakeUnionSet (union1, union2); - - MethodGroupExpr union4 = null; - - if (look_for_explicit) { - - op_name = "op_Explicit"; - - mg5 = MemberLookup (ec, source_type, op_name, false, loc); - - if (source_type.BaseType != null) - mg6 = MemberLookup (ec, source_type.BaseType, op_name, false, loc); - - mg7 = MemberLookup (ec, target, op_name, false, loc); - - if (target.BaseType != null) - mg8 = MemberLookup (ec, target.BaseType, op_name, false, loc); - - MethodGroupExpr union5 = Invocation.MakeUnionSet (mg5, mg6); - MethodGroupExpr union6 = Invocation.MakeUnionSet (mg7, mg8); - - union4 = Invocation.MakeUnionSet (union5, union6); - } - - MethodGroupExpr union = Invocation.MakeUnionSet (union3, union4); - - if (union != null) { - - Type most_specific_source, most_specific_target; - - most_specific_source = FindMostEncompassedType (union, source_type); - if (most_specific_source == null) - return null; - - most_specific_target = FindMostEncompassingType (union, target); - if (most_specific_target == null) - return null; - - int count = 0; - - for (int i = union.Methods.Length; i > 0;) { - i--; - - MethodBase mb = union.Methods [i]; - ParameterData pd = Invocation.GetParameterData (mb); - MethodInfo mi = (MethodInfo) union.Methods [i]; - - if (pd.ParameterType (0) == most_specific_source && - mi.ReturnType == most_specific_target) { - method = mb; - count++; - } - } - - if (method == null || count > 1) { - Report.Error (-11, loc, "Ambiguous user defined conversion"); - return null; - } - - // - // This will do the conversion to the best match that we - // found. Now we need to perform an implict standard conversion - // if the best match was not the type that we were requested - // by target. - // - if (look_for_explicit) - source = ConvertExplicitStandard (ec, source, most_specific_source, loc); - else - source = ConvertImplicitStandard (ec, source, - most_specific_source, loc); - - if (source == null) - return null; - - e = new UserCast ((MethodInfo) method, source); - - if (e.Type != target){ - if (!look_for_explicit) - e = ConvertImplicitStandard (ec, e, target, loc); - else - e = ConvertExplicitStandard (ec, e, target, loc); - - return e; - } else - return e; - } - - return null; - } - - // - // Converts implicitly the resolved expression `expr' into the - // `target_type'. It returns a new expression that can be used - // in a context that expects a `target_type'. - // - static public Expression ConvertImplicit (EmitContext ec, Expression expr, - Type target_type, Location loc) - { - Type expr_type = expr.Type; - Expression e; - - if (expr_type == target_type) - return expr; - - e = ImplicitNumericConversion (ec, expr, target_type, loc); - if (e != null) - return e; - - e = ImplicitReferenceConversion (expr, target_type); - if (e != null) - return e; - - e = ImplicitUserConversion (ec, expr, target_type, loc); - if (e != null) - return e; - - if (target_type.IsSubclassOf (TypeManager.enum_type) && expr is IntLiteral){ - IntLiteral i = (IntLiteral) expr; - - if (i.Value == 0) - return new EmptyCast (expr, target_type); - } - - return null; - } - - - // - // Attempts to apply the `Standard Implicit - // Conversion' rules to the expression `expr' into - // the `target_type'. It returns a new expression - // that can be used in a context that expects a - // `target_type'. - // - // This is different from `ConvertImplicit' in that the - // user defined implicit conversions are excluded. - // - static public Expression ConvertImplicitStandard (EmitContext ec, Expression expr, - Type target_type, Location loc) - { - Type expr_type = expr.Type; - Expression e; - - if (expr_type == target_type) - return expr; - - e = ImplicitNumericConversion (ec, expr, target_type, loc); - if (e != null) - return e; - - e = ImplicitReferenceConversion (expr, target_type); - if (e != null) - return e; - - if (target_type.IsSubclassOf (TypeManager.enum_type) && expr is IntLiteral){ - IntLiteral i = (IntLiteral) expr; - - if (i.Value == 0) - return new EmptyCast (expr, target_type); - } - return null; - } - // - // Attemps to perform an implict constant conversion of the IntLiteral - // into a different data type using casts (See Implicit Constant - // Expression Conversions) - // - static protected Expression TryImplicitIntConversion (Type target_type, IntLiteral il) - { - int value = il.Value; - - if (target_type == TypeManager.sbyte_type){ - if (value >= SByte.MinValue && value <= SByte.MaxValue) - return il; - } else if (target_type == TypeManager.byte_type){ - if (Byte.MinValue >= 0 && value <= Byte.MaxValue) - return il; - } else if (target_type == TypeManager.short_type){ - if (value >= Int16.MinValue && value <= Int16.MaxValue) - return il; - } else if (target_type == TypeManager.ushort_type){ - if (value >= UInt16.MinValue && value <= UInt16.MaxValue) - return il; - } else if (target_type == TypeManager.uint32_type){ - // - // we can optimize this case: a positive int32 - // always fits on a uint32 - // - if (value >= 0) - return il; - } else if (target_type == TypeManager.uint64_type){ - // - // we can optimize this case: a positive int32 - // always fits on a uint64. But we need an opcode - // to do it. - // - if (value >= 0) - return new OpcodeCast (il, target_type, OpCodes.Conv_I8); - } - - return null; - } - - // - // Attemptes to implicityly convert `target' into `type', using - // ConvertImplicit. If there is no implicit conversion, then - // an error is signaled - // - static public Expression ConvertImplicitRequired (EmitContext ec, Expression target, - Type type, Location loc) - { - Expression e; - - e = ConvertImplicit (ec, target, type, loc); - if (e != null) - return e; - - string msg = "Can not convert implicitly from `"+ - TypeManager.CSharpName (target.Type) + "' to `" + - TypeManager.CSharpName (type) + "'"; - - Error (29, loc, msg); - - return null; - } - - // - // Performs the explicit numeric conversions - // - static Expression ConvertNumericExplicit (EmitContext ec, Expression expr, - Type target_type) - { - Type expr_type = expr.Type; - - if (expr_type == TypeManager.sbyte_type){ - // - // From sbyte to byte, ushort, uint, ulong, char - // - if (target_type == TypeManager.byte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U1); - if (target_type == TypeManager.ushort_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); - if (target_type == TypeManager.uint32_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U4); - if (target_type == TypeManager.uint64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I8); - if (target_type == TypeManager.char_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); - } else if (expr_type == TypeManager.byte_type){ - // - // From byte to sbyte and char - // - if (target_type == TypeManager.sbyte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I1); - if (target_type == TypeManager.char_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); - } else if (expr_type == TypeManager.short_type){ - // - // From short to sbyte, byte, ushort, uint, ulong, char - // - if (target_type == TypeManager.sbyte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I1); - if (target_type == TypeManager.byte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U1); - if (target_type == TypeManager.ushort_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); - if (target_type == TypeManager.uint32_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U4); - if (target_type == TypeManager.uint64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I8); - if (target_type == TypeManager.char_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); - } else if (expr_type == TypeManager.ushort_type){ - // - // From ushort to sbyte, byte, short, char - // - if (target_type == TypeManager.sbyte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I1); - if (target_type == TypeManager.byte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U1); - if (target_type == TypeManager.short_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I2); - if (target_type == TypeManager.char_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); - } else if (expr_type == TypeManager.int32_type){ - // - // From int to sbyte, byte, short, ushort, uint, ulong, char - // - if (target_type == TypeManager.sbyte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I1); - if (target_type == TypeManager.byte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U1); - if (target_type == TypeManager.short_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I2); - if (target_type == TypeManager.ushort_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); - if (target_type == TypeManager.uint32_type) - return new EmptyCast (expr, target_type); - if (target_type == TypeManager.uint64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I8); - if (target_type == TypeManager.char_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); - } else if (expr_type == TypeManager.uint32_type){ - // - // From uint to sbyte, byte, short, ushort, int, char - // - if (target_type == TypeManager.sbyte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I1); - if (target_type == TypeManager.byte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U1); - if (target_type == TypeManager.short_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I2); - if (target_type == TypeManager.ushort_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); - if (target_type == TypeManager.int32_type) - return new EmptyCast (expr, target_type); - if (target_type == TypeManager.char_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); - } else if (expr_type == TypeManager.int64_type){ - // - // From long to sbyte, byte, short, ushort, int, uint, ulong, char - // - if (target_type == TypeManager.sbyte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I1); - if (target_type == TypeManager.byte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U1); - if (target_type == TypeManager.short_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I2); - if (target_type == TypeManager.ushort_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); - if (target_type == TypeManager.int32_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I4); - if (target_type == TypeManager.uint32_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U4); - if (target_type == TypeManager.uint64_type) - return new EmptyCast (expr, target_type); - if (target_type == TypeManager.char_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); - } else if (expr_type == TypeManager.uint64_type){ - // - // From ulong to sbyte, byte, short, ushort, int, uint, long, char - // - if (target_type == TypeManager.sbyte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I1); - if (target_type == TypeManager.byte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U1); - if (target_type == TypeManager.short_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I2); - if (target_type == TypeManager.ushort_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); - if (target_type == TypeManager.int32_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I4); - if (target_type == TypeManager.uint32_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U4); - if (target_type == TypeManager.int64_type) - return new EmptyCast (expr, target_type); - if (target_type == TypeManager.char_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); - } else if (expr_type == TypeManager.char_type){ - // - // From char to sbyte, byte, short - // - if (target_type == TypeManager.sbyte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I1); - if (target_type == TypeManager.byte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U1); - if (target_type == TypeManager.short_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I2); - } else if (expr_type == TypeManager.float_type){ - // - // From float to sbyte, byte, short, - // ushort, int, uint, long, ulong, char - // or decimal - // - if (target_type == TypeManager.sbyte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I1); - if (target_type == TypeManager.byte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U1); - if (target_type == TypeManager.short_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I2); - if (target_type == TypeManager.ushort_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); - if (target_type == TypeManager.int32_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I4); - if (target_type == TypeManager.uint32_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U4); - if (target_type == TypeManager.int64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I8); - if (target_type == TypeManager.uint64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U8); - if (target_type == TypeManager.char_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); - if (target_type == TypeManager.decimal_type) - return InternalTypeConstructor (ec, expr, target_type); - } else if (expr_type == TypeManager.double_type){ - // - // From double to byte, byte, short, - // ushort, int, uint, long, ulong, - // char, float or decimal - // - if (target_type == TypeManager.sbyte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I1); - if (target_type == TypeManager.byte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U1); - if (target_type == TypeManager.short_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I2); - if (target_type == TypeManager.ushort_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); - if (target_type == TypeManager.int32_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I4); - if (target_type == TypeManager.uint32_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U4); - if (target_type == TypeManager.int64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_I8); - if (target_type == TypeManager.uint64_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U8); - if (target_type == TypeManager.char_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); - if (target_type == TypeManager.float_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); - if (target_type == TypeManager.decimal_type) - return InternalTypeConstructor (ec, expr, target_type); - } - - // decimal is taken care of by the op_Explicit methods. - - return null; - } - - // - // Returns whether an explicit reference conversion can be performed - // from source_type to target_type - // - static bool ExplicitReferenceConversionExists (Type source_type, Type target_type) - { - bool target_is_value_type = target_type.IsValueType; - - if (source_type == target_type) - return true; - - // - // From object to any reference type - // - if (source_type == TypeManager.object_type && !target_is_value_type) - return true; - - // - // From any class S to any class-type T, provided S is a base class of T - // - if (target_type.IsSubclassOf (source_type)) - return true; - - // - // From any interface type S to any interface T provided S is not derived from T - // - if (source_type.IsInterface && target_type.IsInterface){ - if (!target_type.IsSubclassOf (source_type)) - return true; - } - - // - // From any class type S to any interface T, provides S is not sealed - // and provided S does not implement T. - // - if (target_type.IsInterface && !source_type.IsSealed && - !target_type.IsAssignableFrom (source_type)) - return true; - - // - // From any interface-type S to to any class type T, provided T is not - // sealed, or provided T implements S. - // - if (source_type.IsInterface && - (!target_type.IsSealed || source_type.IsAssignableFrom (target_type))) - return true; - - // From an array type S with an element type Se to an array type T with an - // element type Te provided all the following are true: - // * S and T differe only in element type, in other words, S and T - // have the same number of dimensions. - // * Both Se and Te are reference types - // * An explicit referenc conversions exist from Se to Te - // - if (source_type.IsArray && target_type.IsArray) { - if (source_type.GetArrayRank () == target_type.GetArrayRank ()) { - - Type source_element_type = source_type.GetElementType (); - Type target_element_type = target_type.GetElementType (); - - if (!source_element_type.IsValueType && !target_element_type.IsValueType) - if (ExplicitReferenceConversionExists (source_element_type, - target_element_type)) - return true; - } - } - - - // From System.Array to any array-type - if (source_type == TypeManager.array_type && - target_type.IsSubclassOf (TypeManager.array_type)){ - return true; - } - - // - // From System delegate to any delegate-type - // - if (source_type == TypeManager.delegate_type && - target_type.IsSubclassOf (TypeManager.delegate_type)) - return true; - - // - // From ICloneable to Array or Delegate types - // - if (source_type == TypeManager.icloneable_type && - (target_type == TypeManager.array_type || - target_type == TypeManager.delegate_type)) - return true; - - return false; - } - - // - // Implements Explicit Reference conversions - // - static Expression ConvertReferenceExplicit (Expression source, Type target_type) - { - Type source_type = source.Type; - bool target_is_value_type = target_type.IsValueType; - - // - // From object to any reference type - // - if (source_type == TypeManager.object_type && !target_is_value_type) - return new ClassCast (source, target_type); - - - // - // From any class S to any class-type T, provided S is a base class of T - // - if (target_type.IsSubclassOf (source_type)) - return new ClassCast (source, target_type); - - // - // From any interface type S to any interface T provided S is not derived from T - // - if (source_type.IsInterface && target_type.IsInterface){ - - Type [] ifaces = source_type.GetInterfaces (); - - if (TypeManager.ImplementsInterface (source_type, target_type)) - return null; - else - return new ClassCast (source, target_type); - } - - // - // From any class type S to any interface T, provides S is not sealed - // and provided S does not implement T. - // - if (target_type.IsInterface && !source_type.IsSealed) { - - if (TypeManager.ImplementsInterface (source_type, target_type)) - return null; - else - return new ClassCast (source, target_type); - - } - - // - // From any interface-type S to to any class type T, provided T is not - // sealed, or provided T implements S. - // - if (source_type.IsInterface) { - - if (target_type.IsSealed) - return null; - - if (TypeManager.ImplementsInterface (target_type, source_type)) - return new ClassCast (source, target_type); - else - return null; - } - - // From an array type S with an element type Se to an array type T with an - // element type Te provided all the following are true: - // * S and T differe only in element type, in other words, S and T - // have the same number of dimensions. - // * Both Se and Te are reference types - // * An explicit referenc conversions exist from Se to Te - // - if (source_type.IsArray && target_type.IsArray) { - if (source_type.GetArrayRank () == target_type.GetArrayRank ()) { - - Type source_element_type = source_type.GetElementType (); - Type target_element_type = target_type.GetElementType (); - - if (!source_element_type.IsValueType && !target_element_type.IsValueType) - if (ExplicitReferenceConversionExists (source_element_type, - target_element_type)) - return new ClassCast (source, target_type); - } - } - - - // From System.Array to any array-type - if (source_type == TypeManager.array_type && - target_type.IsSubclassOf (TypeManager.array_type)){ - return new ClassCast (source, target_type); - } - - // - // From System delegate to any delegate-type - // - if (source_type == TypeManager.delegate_type && - target_type.IsSubclassOf (TypeManager.delegate_type)) - return new ClassCast (source, target_type); - - // - // From ICloneable to Array or Delegate types - // - if (source_type == TypeManager.icloneable_type && - (target_type == TypeManager.array_type || - target_type == TypeManager.delegate_type)) - return new ClassCast (source, target_type); - - return null; - } - - // - // Performs an explicit conversion of the expression `expr' whose - // type is expr.Type to `target_type'. - // - static public Expression ConvertExplicit (EmitContext ec, Expression expr, - Type target_type, Location loc) - { - Expression ne = ConvertImplicitStandard (ec, expr, target_type, loc); - - if (ne != null) - return ne; - - ne = ConvertNumericExplicit (ec, expr, target_type); - if (ne != null) - return ne; - - ne = ConvertReferenceExplicit (expr, target_type); - if (ne != null) - return ne; - - ne = ExplicitUserConversion (ec, expr, target_type, loc); - if (ne != null) - return ne; - - Report.Error (30, loc, "Cannot convert type '" + TypeManager.CSharpName (expr.Type) + "' to '" - + TypeManager.CSharpName (target_type) + "'"); - return null; - } - - // - // Same as ConverExplicit, only it doesn't include user defined conversions - // - static public Expression ConvertExplicitStandard (EmitContext ec, Expression expr, - Type target_type, Location l) - { - Expression ne = ConvertImplicitStandard (ec, expr, target_type, l); - - if (ne != null) - return ne; - ne = ConvertNumericExplicit (ec, expr, target_type); - if (ne != null) - return ne; - - ne = ConvertReferenceExplicit (expr, target_type); - if (ne != null) - return ne; - - Report.Error (30, l, "Cannot convert type '" + - TypeManager.CSharpName (expr.Type) + "' to '" + - TypeManager.CSharpName (target_type) + "'"); - return null; - } - - static string ExprClassName (ExprClass c) - { - switch (c){ - case ExprClass.Invalid: - return "Invalid"; - case ExprClass.Value: - return "value"; - case ExprClass.Variable: - return "variable"; - case ExprClass.Namespace: - return "namespace"; - case ExprClass.Type: - return "type"; - case ExprClass.MethodGroup: - return "method group"; - case ExprClass.PropertyAccess: - return "property access"; - case ExprClass.EventAccess: - return "event access"; - case ExprClass.IndexerAccess: - return "indexer access"; - case ExprClass.Nothing: - return "null"; - } - throw new Exception ("Should not happen"); - } - - // - // Reports that we were expecting `expr' to be of class `expected' - // - protected void report118 (Location loc, Expression expr, string expected) - { - string kind = "Unknown"; - - if (expr != null) - kind = ExprClassName (expr.ExprClass); - - Error (118, loc, "Expression denotes a '" + kind + - "' where an " + expected + " was expected"); - } - } - - // - // This is just a base class for expressions that can - // appear on statements (invocations, object creation, - // assignments, post/pre increment and decrement). The idea - // being that they would support an extra Emition interface that - // does not leave a result on the stack. - // - - public abstract class ExpressionStatement : Expression { - - // - // Requests the expression to be emitted in a `statement' - // context. This means that no new value is left on the - // stack after invoking this method (constrasted with - // Emit that will always leave a value on the stack). - // - public abstract void EmitStatement (EmitContext ec); - } +namespace CIR { + using System; + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Reflection.Emit; + using System.Text; // - // This kind of cast is used to encapsulate the child - // whose type is child.Type into an expression that is - // reported to return "return_type". This is used to encapsulate - // expressions which have compatible types, but need to be dealt - // at higher levels with. - // - // For example, a "byte" expression could be encapsulated in one - // of these as an "unsigned int". The type for the expression - // would be "unsigned int". - // + // This is just a helper class, it is generated by Unary, UnaryMutator + // when an overloaded method has been found. It just emits the code for a + // static call. // - - public class EmptyCast : Expression { - protected Expression child; - - public EmptyCast (Expression child, Type return_type) - { - ExprClass = child.ExprClass; - type = return_type; - this.child = child; - } - - public override Expression DoResolve (EmitContext ec) - { - // This should never be invoked, we are born in fully - // initialized state. + public class StaticCallExpr : ExpressionStatement { + ArrayList args; + MethodInfo mi; - return this; - } - - public override void Emit (EmitContext ec) + StaticCallExpr (MethodInfo m, ArrayList a) { - child.Emit (ec); - } - } - - // - // This kind of cast is used to encapsulate Value Types in objects. - // - // The effect of it is to box the value type emitted by the previous - // operation. - // - public class BoxedCast : EmptyCast { + mi = m; + args = a; - public BoxedCast (Expression expr) - : base (expr, TypeManager.object_type) - { + type = m.ReturnType; + eclass = ExprClass.Value; } public override Expression DoResolve (EmitContext ec) { - // This should never be invoked, we are born in fully - // initialized state. - + // + // We are born fully resolved + // return this; } public override void Emit (EmitContext ec) { - base.Emit (ec); - ec.ig.Emit (OpCodes.Box, child.Type); - } - } + if (args != null) + Invocation.EmitArguments (ec, mi, args); - // - // This kind of cast is used to encapsulate a child expression - // that can be trivially converted to a target type using one or - // two opcodes. The opcodes are passed as arguments. - // - public class OpcodeCast : EmptyCast { - OpCode op, op2; - bool second_valid; + ec.ig.Emit (OpCodes.Call, mi); + return; + } - public OpcodeCast (Expression child, Type return_type, OpCode op) - : base (child, return_type) - + static public Expression MakeSimpleCall (EmitContext ec, MethodGroupExpr mg, + Expression e, Location loc) { - this.op = op; - second_valid = false; - } - - public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2) - : base (child, return_type) + ArrayList args; + MethodBase method; - { - this.op = op; - this.op2 = op2; - second_valid = true; - } - - public override Expression DoResolve (EmitContext ec) - { - // This should never be invoked, we are born in fully - // initialized state. - - return this; - } - - public override void Emit (EmitContext ec) - { - base.Emit (ec); - ec.ig.Emit (op); + args = new ArrayList (1); + args.Add (new Argument (e, Argument.AType.Expression)); + method = Invocation.OverloadResolve (ec, (MethodGroupExpr) mg, args, loc); - if (second_valid) - ec.ig.Emit (op2); - } - - } + if (method == null) + return null; - // - // This kind of cast is used to encapsulate a child and cast it - // to the class requested - // - public class ClassCast : EmptyCast { - public ClassCast (Expression child, Type return_type) - : base (child, return_type) - - { + return new StaticCallExpr ((MethodInfo) method, args); } - public override Expression DoResolve (EmitContext ec) + public override void EmitStatement (EmitContext ec) { - // This should never be invoked, we are born in fully - // initialized state. - - return this; + Emit (ec); + if (type != TypeManager.void_type) + ec.ig.Emit (OpCodes.Pop); } - - public override void Emit (EmitContext ec) - { - base.Emit (ec); - - ec.ig.Emit (OpCodes.Castclass, type); - } - } // @@ -1845,17 +84,14 @@ namespace CIR { // ExpressionStatement becuase the pre/post increment/decrement // operators can be used in a statement context. // - public class Unary : ExpressionStatement { - public enum Operator { + public class Unary : Expression { + public enum Operator : byte { UnaryPlus, UnaryNegation, LogicalNot, OnesComplement, - Indirection, AddressOf, PreIncrement, - PreDecrement, PostIncrement, PostDecrement + Indirection, AddressOf, } Operator oper; Expression expr; - ArrayList Arguments; - MethodBase method; Location loc; public Unary (Operator op, Expression expr, Location loc) @@ -1903,53 +139,39 @@ namespace CIR { return "&"; case Operator.Indirection: return "*"; - case Operator.PreIncrement : case Operator.PostIncrement : - return "++"; - case Operator.PreDecrement : case Operator.PostDecrement : - return "--"; } return oper.ToString (); } - Expression ForceConversion (EmitContext ec, Expression expr, Type target_type) - { - if (expr.Type == target_type) - return expr; - - return ConvertImplicit (ec, expr, target_type, new Location (-1)); - } - void error23 (Type t) { - Report.Error ( - 23, loc, "Operator " + OperName () + - " cannot be applied to operand of type `" + - TypeManager.CSharpName (t) + "'"); - } - - // - // Returns whether an object of type `t' can be incremented - // or decremented with add/sub (ie, basically whether we can - // use pre-post incr-decr operations on it, but it is not a - // System.Decimal, which we test elsewhere) - // - static bool IsIncrementableNumber (Type t) - { - return (t == TypeManager.sbyte_type) || - (t == TypeManager.byte_type) || - (t == TypeManager.short_type) || - (t == TypeManager.ushort_type) || - (t == TypeManager.int32_type) || - (t == TypeManager.uint32_type) || - (t == TypeManager.int64_type) || - (t == TypeManager.uint64_type) || - (t == TypeManager.char_type) || - (t.IsSubclassOf (TypeManager.enum_type)) || - (t == TypeManager.float_type) || - (t == TypeManager.double_type); + Report.Error ( + 23, loc, "Operator " + OperName () + + " cannot be applied to operand of type `" + + TypeManager.CSharpName (t) + "'"); } + + static Expression TryReduceNegative (Expression expr) + { + Expression e = null; + if (expr is IntLiteral) + e = new IntLiteral (-((IntLiteral) expr).Value); + else if (expr is UIntLiteral) + e = new LongLiteral (-((UIntLiteral) expr).Value); + else if (expr is LongLiteral) + e = new LongLiteral (-((LongLiteral) expr).Value); + else if (expr is FloatLiteral) + e = new FloatLiteral (-((FloatLiteral) expr).Value); + else if (expr is DoubleLiteral) + e = new DoubleLiteral (-((DoubleLiteral) expr).Value); + else if (expr is DecimalLiteral) + e = new DecimalLiteral (-((DecimalLiteral) expr).Value); + + return e; + } + Expression ResolveOperator (EmitContext ec) { Type expr_type = expr.Type; @@ -1960,12 +182,7 @@ namespace CIR { Expression mg; string op_name; - if (oper == Operator.PostIncrement || oper == Operator.PreIncrement) - op_name = "op_Increment"; - else if (oper == Operator.PostDecrement || oper == Operator.PreDecrement) - op_name = "op_Decrement"; - else - op_name = "op_" + oper; + op_name = "op_" + oper; mg = MemberLookup (ec, expr_type, op_name, false, loc); @@ -1973,20 +190,15 @@ namespace CIR { mg = MemberLookup (ec, expr_type.BaseType, op_name, false, loc); if (mg != null) { - Arguments = new ArrayList (); - Arguments.Add (new Argument (expr, Argument.AType.Expression)); - - method = Invocation.OverloadResolve (ec, (MethodGroupExpr) mg, - Arguments, loc); - if (method != null) { - MethodInfo mi = (MethodInfo) method; - type = mi.ReturnType; - return this; - } else { + Expression e = StaticCallExpr.MakeSimpleCall ( + ec, (MethodGroupExpr) mg, expr, loc); + + if (e == null){ error23 (expr_type); return null; } - + + return e; } // @@ -1994,7 +206,7 @@ namespace CIR { // // Only perform numeric promotions on: - // +, -, ++, -- + // +, - if (expr_type == null) return null; @@ -2047,16 +259,7 @@ namespace CIR { // // Is this a constant? // - if (expr is IntLiteral) - e = new IntLiteral (-((IntLiteral) expr).Value); - else if (expr is LongLiteral) - e = new LongLiteral (-((LongLiteral) expr).Value); - else if (expr is FloatLiteral) - e = new FloatLiteral (-((FloatLiteral) expr).Value); - else if (expr is DoubleLiteral) - e = new DoubleLiteral (-((DoubleLiteral) expr).Value); - else if (expr is DecimalLiteral) - e = new DecimalLiteral (-((DecimalLiteral) expr).Value); + e = TryReduceNegative (expr); if (e != null){ e = e.Resolve (ec); @@ -2120,47 +323,19 @@ namespace CIR { return null; } - // - // The operand of the prefix/postfix increment decrement operators - // should be an expression that is classified as a variable, - // a property access or an indexer access - // - if (oper == Operator.PreDecrement || oper == Operator.PreIncrement || - oper == Operator.PostDecrement || oper == Operator.PostIncrement){ - if (expr.ExprClass == ExprClass.Variable){ - if (IsIncrementableNumber (expr_type) || - expr_type == TypeManager.decimal_type){ - type = expr_type; - return this; - } - } else if (expr.ExprClass == ExprClass.IndexerAccess){ - // - // FIXME: Verify that we have both get and set methods - // - throw new Exception ("Implement me"); - } else if (expr.ExprClass == ExprClass.PropertyAccess){ - PropertyExpr pe = (PropertyExpr) expr; - - if (pe.VerifyAssignable ()) - return this; - return null; - } else { - report118 (loc, expr, "variable, indexer or property access"); - } - } - if (oper == Operator.AddressOf){ if (expr.ExprClass != ExprClass.Variable){ - Error (211, "Cannot take the address of non-variables"); + Error (211, loc, "Cannot take the address of non-variables"); return null; } type = Type.GetType (expr.Type.ToString () + "*"); + + return this; } - Error (187, "No such operator '" + OperName () + "' defined for type '" + + Error (187, loc, "No such operator '" + OperName () + "' defined for type '" + TypeManager.CSharpName (expr_type) + "'"); return null; - } public override Expression DoResolve (EmitContext ec) @@ -2178,41 +353,6 @@ namespace CIR { { ILGenerator ig = ec.ig; Type expr_type = expr.Type; - ExprClass eclass; - - if (method != null) { - - // Note that operators are static anyway - - if (Arguments != null) - Invocation.EmitArguments (ec, Arguments); - - // - // Post increment/decrement operations need a copy at this - // point. - // - if (oper == Operator.PostDecrement || oper == Operator.PostIncrement) - ig.Emit (OpCodes.Dup); - - - ig.Emit (OpCodes.Call, (MethodInfo) method); - - // - // Pre Increment and Decrement operators - // - if (oper == Operator.PreIncrement || oper == Operator.PreDecrement){ - ig.Emit (OpCodes.Dup); - } - - // - // Increment and Decrement should store the result - // - if (oper == Operator.PreDecrement || oper == Operator.PreIncrement || - oper == Operator.PostDecrement || oper == Operator.PostIncrement){ - ((IStackStore) expr).Store (ec); - } - return; - } switch (oper) { case Operator.UnaryPlus: @@ -2241,68 +381,292 @@ namespace CIR { case Operator.Indirection: throw new Exception ("Not implemented yet"); - case Operator.PreIncrement: - case Operator.PreDecrement: - if (expr.ExprClass == ExprClass.Variable){ - // - // Resolve already verified that it is an "incrementable" - // + default: + throw new Exception ("This should not happen: Operator = " + + oper.ToString ()); + } + } + + // + // This will emit the child expression for `ec' avoiding the logical + // not. The parent will take care of changing brfalse/brtrue + // + public void EmitLogicalNot (EmitContext ec) + { + if (oper != Operator.LogicalNot) + throw new Exception ("EmitLogicalNot can only be called with !expr"); + + expr.Emit (ec); + } + + public override Expression Reduce (EmitContext ec) + { + Expression e; + + // + // First, reduce our child. Note that although we handle + // + expr = expr.Reduce (ec); + if (!(expr is Literal)) + return expr; + + switch (oper){ + case Operator.UnaryPlus: + return expr; + + case Operator.UnaryNegation: + e = TryReduceNegative (expr); + if (e == null) + break; + return e; + + case Operator.LogicalNot: + BoolLiteral b = (BoolLiteral) expr; + + return new BoolLiteral (!(b.Value)); + + case Operator.OnesComplement: + Type et = expr.Type; + + if (et == TypeManager.int32_type) + return new IntLiteral (~ ((IntLiteral) expr).Value); + if (et == TypeManager.uint32_type) + return new UIntLiteral (~ ((UIntLiteral) expr).Value); + if (et == TypeManager.int64_type) + return new LongLiteral (~ ((LongLiteral) expr).Value); + if (et == TypeManager.uint64_type) + return new ULongLiteral (~ ((ULongLiteral) expr).Value); + break; + } + return this; + } + } + + // + // Unary Mutator expressions (pre and post ++ and --) + // + // + // + // UnaryMutator implements ++ and -- expressions. It derives from + // ExpressionStatement becuase the pre/post increment/decrement + // operators can be used in a statement context. + // + // + // FIXME: Idea, we could split this up in two classes, one simpler + // for the common case, and one with the extra fields for more complex + // classes (indexers require temporary access; overloaded require method) + // + // Maybe we should have classes PreIncrement, PostIncrement, PreDecrement, + // PostDecrement, that way we could save the `Mode' byte as well. + // + public class UnaryMutator : ExpressionStatement { + public enum Mode : byte { + PreIncrement, PreDecrement, PostIncrement, PostDecrement + } + + Mode mode; + Location loc; + Expression expr; + LocalTemporary temp_storage; + + // + // This is expensive for the simplest case. + // + Expression method; + + public UnaryMutator (Mode m, Expression e, Location l) + { + mode = m; + loc = l; + expr = e; + } + + string OperName () + { + return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ? + "++" : "--"; + } + + void error23 (Type t) + { + Report.Error ( + 23, loc, "Operator " + OperName () + + " cannot be applied to operand of type `" + + TypeManager.CSharpName (t) + "'"); + } + + // + // Returns whether an object of type `t' can be incremented + // or decremented with add/sub (ie, basically whether we can + // use pre-post incr-decr operations on it, but it is not a + // System.Decimal, which we require operator overloading to catch) + // + static bool IsIncrementableNumber (Type t) + { + return (t == TypeManager.sbyte_type) || + (t == TypeManager.byte_type) || + (t == TypeManager.short_type) || + (t == TypeManager.ushort_type) || + (t == TypeManager.int32_type) || + (t == TypeManager.uint32_type) || + (t == TypeManager.int64_type) || + (t == TypeManager.uint64_type) || + (t == TypeManager.char_type) || + (t.IsSubclassOf (TypeManager.enum_type)) || + (t == TypeManager.float_type) || + (t == TypeManager.double_type); + } + + Expression ResolveOperator (EmitContext ec) + { + Type expr_type = expr.Type; + + // + // Step 1: Perform Operator Overload location + // + Expression mg; + string op_name; + + if (mode == Mode.PreIncrement || mode == Mode.PostIncrement) + op_name = "op_Increment"; + else + op_name = "op_Decrement"; + + mg = MemberLookup (ec, expr_type, op_name, false, loc); + + if (mg == null && expr_type.BaseType != null) + mg = MemberLookup (ec, expr_type.BaseType, op_name, false, loc); + + if (mg != null) { + method = StaticCallExpr.MakeSimpleCall ( + ec, (MethodGroupExpr) mg, expr, loc); + + type = method.Type; + return this; + } + + // + // The operand of the prefix/postfix increment decrement operators + // should be an expression that is classified as a variable, + // a property access or an indexer access + // + type = expr_type; + if (expr.ExprClass == ExprClass.Variable){ + if (IsIncrementableNumber (expr_type) || + expr_type == TypeManager.decimal_type){ + return this; + } + } else if (expr.ExprClass == ExprClass.IndexerAccess){ + IndexerAccess ia = (IndexerAccess) expr; + + temp_storage = new LocalTemporary (ec, expr.Type); + + expr = ia.ResolveLValue (ec, temp_storage); + if (expr == null) + return null; + + return this; + } else if (expr.ExprClass == ExprClass.PropertyAccess){ + PropertyExpr pe = (PropertyExpr) expr; + + if (pe.VerifyAssignable ()) + return this; + + return null; + } else { + report118 (loc, expr, "variable, indexer or property access"); + return null; + } + + Error (187, loc, "No such operator '" + OperName () + "' defined for type '" + + TypeManager.CSharpName (expr_type) + "'"); + return null; + } + + public override Expression DoResolve (EmitContext ec) + { + expr = expr.Resolve (ec); + + if (expr == null) + return null; + + eclass = ExprClass.Value; + return ResolveOperator (ec); + } + + + // + // FIXME: We need some way of avoiding the use of temp_storage + // for some types of storage (parameters, local variables, + // static fields) and single-dimension array access. + // + void EmitCode (EmitContext ec, bool is_expr) + { + ILGenerator ig = ec.ig; + IAssignMethod ia = (IAssignMethod) expr; + + if (temp_storage == null) + temp_storage = new LocalTemporary (ec, expr.Type); + + switch (mode){ + case Mode.PreIncrement: + case Mode.PreDecrement: + if (method == null){ expr.Emit (ec); + ig.Emit (OpCodes.Ldc_I4_1); - - if (oper == Operator.PreDecrement) + + if (mode == Mode.PreDecrement) ig.Emit (OpCodes.Sub); else ig.Emit (OpCodes.Add); - ig.Emit (OpCodes.Dup); - ((IStackStore) expr).Store (ec); - } else { - throw new Exception ("Handle Indexers and Properties here"); - } + } else + method.Emit (ec); + + temp_storage.Store (ec); + ia.EmitAssign (ec, temp_storage); + if (is_expr) + temp_storage.Emit (ec); break; - case Operator.PostIncrement: - case Operator.PostDecrement: - eclass = expr.ExprClass; - if (eclass == ExprClass.Variable){ - // - // Resolve already verified that it is an "incrementable" - // + case Mode.PostIncrement: + case Mode.PostDecrement: + if (is_expr) expr.Emit (ec); - ig.Emit (OpCodes.Dup); + + if (method == null){ + if (!is_expr) + expr.Emit (ec); + else + ig.Emit (OpCodes.Dup); + ig.Emit (OpCodes.Ldc_I4_1); - - if (oper == Operator.PostDecrement) + + if (mode == Mode.PostDecrement) ig.Emit (OpCodes.Sub); else ig.Emit (OpCodes.Add); - ((IStackStore) expr).Store (ec); - } else if (eclass == ExprClass.PropertyAccess){ - throw new Exception ("Handle Properties here"); - } else if (eclass == ExprClass.IndexerAccess) { - throw new Exception ("Handle Indexers here"); } else { - Console.WriteLine ("Unknown exprclass: " + eclass); + method.Emit (ec); } - break; - default: - throw new Exception ("This should not happen: Operator = " - + oper.ToString ()); + temp_storage.Store (ec); + ia.EmitAssign (ec, temp_storage); + break; } } - + public override void Emit (EmitContext ec) + { + EmitCode (ec, true); + + } + public override void EmitStatement (EmitContext ec) { - // - // FIXME: we should rewrite this code to generate - // better code for ++ and -- as we know we wont need - // the values on the stack - // - Emit (ec); - ec.ig.Emit (OpCodes.Pop); + EmitCode (ec, false); } + } public class Probe : Expression { @@ -2311,7 +675,7 @@ namespace CIR { Expression expr; Type probe_type; - public enum Operator { + public enum Operator : byte { Is, As } @@ -2419,7 +783,7 @@ namespace CIR { } public class Binary : Expression { - public enum Operator { + public enum Operator : byte { Multiply, Division, Modulus, Addition, Subtraction, LeftShift, RightShift, @@ -2534,7 +898,7 @@ namespace CIR { // Note that handling the case l == Decimal || r == Decimal // is taken care of by the Step 1 Operator Overload resolution. // - void DoNumericPromotions (EmitContext ec, Type l, Type r) + bool DoNumericPromotions (EmitContext ec, Type l, Type r) { if (l == TypeManager.double_type || r == TypeManager.double_type){ // @@ -2645,21 +1009,20 @@ namespace CIR { Expression l_tmp, r_tmp; l_tmp = ForceConversion (ec, left, TypeManager.int32_type); - if (l_tmp == null) { - error19 (); - left = l_tmp; - return; - } + if (l_tmp == null) + return false; - r_tmp = ForceConversion (ec, right, TypeManager.int32_type); - if (r_tmp == null) { - error19 (); - right = r_tmp; - return; - } + r_tmp = ForceConversion (ec, right, TypeManager.int32_type); + if (r_tmp == null) + return false; + + left = l_tmp; + right = r_tmp; type = TypeManager.int32_type; } + + return true; } void error19 () @@ -2723,7 +1086,7 @@ namespace CIR { Arguments = new ArrayList (); Arguments.Add (new Argument (left, Argument.AType.Expression)); Arguments.Add (new Argument (right, Argument.AType.Expression)); - + method = Invocation.OverloadResolve (ec, union, Arguments, loc); if (method != null) { MethodInfo mi = (MethodInfo) method; @@ -2748,6 +1111,13 @@ namespace CIR { // if (l == TypeManager.string_type){ if (r == TypeManager.string_type){ + if (left is Literal && right is Literal){ + StringLiteral ls = (StringLiteral) left; + StringLiteral rs = (StringLiteral) right; + + return new StringLiteral (ls.Value + rs.Value); + } + // string + string method = TypeManager.string_concat_string_string; } else { @@ -2786,18 +1156,58 @@ namespace CIR { return CheckShiftArguments (ec); if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){ - if (l != TypeManager.bool_type || r != TypeManager.bool_type) + if (l != TypeManager.bool_type || r != TypeManager.bool_type){ error19 (); + return null; + } type = TypeManager.bool_type; return this; } + if (oper == Operator.Equality || oper == Operator.Inequality){ + if (l == TypeManager.bool_type || r == TypeManager.bool_type){ + if (r != TypeManager.bool_type || l != TypeManager.bool_type){ + error19 (); + return null; + } + + type = TypeManager.bool_type; + return this; + } + + } + // // We are dealing with numbers // - DoNumericPromotions (ec, l, r); + if (!DoNumericPromotions (ec, l, r)){ + // Attempt: + // + // operator != (object a, object b) + // operator == (object a, object b) + // + + if (oper == Operator.Equality || oper == Operator.Inequality){ + Expression li, ri; + li = ConvertImplicit (ec, left, TypeManager.object_type, loc); + if (li != null){ + ri = ConvertImplicit (ec, right, TypeManager.object_type, + loc); + if (ri != null){ + left = li; + right = ri; + + type = TypeManager.bool_type; + return this; + } + } + } + + error19 (); + return null; + } if (left == null || right == null) return null; @@ -2947,7 +1357,7 @@ namespace CIR { // Note that operators are static anyway if (Arguments != null) - Invocation.EmitArguments (ec, Arguments); + Invocation.EmitArguments (ec, method, Arguments); if (method is MethodInfo) ig.Emit (OpCodes.Call, (MethodInfo) method); @@ -3074,6 +1484,30 @@ namespace CIR { ig.Emit (opcode); } + + // + // Constant expression reducer for binary operations + // + public override Expression Reduce (EmitContext ec) + { + + left = left.Reduce (ec); + right = right.Reduce (ec); + + if (!(left is Literal && right is Literal)) + return this; + + if (method == TypeManager.string_concat_string_string){ + StringLiteral ls = (StringLiteral) left; + StringLiteral rs = (StringLiteral) right; + + return new StringLiteral (ls.Value + rs.Value); + } + + // FINISH ME. + + return this; + } } public class Conditional : Expression { @@ -3119,7 +1553,7 @@ namespace CIR { if (expr == null || trueExpr == null || falseExpr == null) return null; - + if (trueExpr.Type == falseExpr.Type) type = trueExpr.Type; else { @@ -3145,6 +1579,15 @@ namespace CIR { } } + if (expr is BoolLiteral){ + BoolLiteral bl = (BoolLiteral) expr; + + if (bl.Value) + return trueExpr; + else + return falseExpr; + } + eclass = ExprClass.Value; return this; } @@ -3163,159 +1606,26 @@ namespace CIR { falseExpr.Emit (ec); ig.MarkLabel (end_target); } - } - - // - // SimpleName expressions are initially formed of a single - // word and it only happens at the beginning of the expression. - // - // The expression will try to be bound to a Field, a Method - // group or a Property. If those fail we pass the name to our - // caller and the SimpleName is compounded to perform a type - // lookup. The idea behind this process is that we want to avoid - // creating a namespace map from the assemblies, as that requires - // the GetExportedTypes function to be called and a hashtable to - // be constructed which reduces startup time. If later we find - // that this is slower, we should create a `NamespaceExpr' expression - // that fully participates in the resolution process. - // - // For example `System.Console.WriteLine' is decomposed into - // MemberAccess (MemberAccess (SimpleName ("System"), "Console"), "WriteLine") - // - // The first SimpleName wont produce a match on its own, so it will - // be turned into: - // MemberAccess (SimpleName ("System.Console"), "WriteLine"). - // - // System.Console will produce a TypeExpr match. - // - // The downside of this is that we might be hitting `LookupType' too many - // times with this scheme. - // - public class SimpleName : Expression { - public readonly string Name; - public readonly Location Location; - - public SimpleName (string name, Location l) - { - Name = name; - Location = l; - } - - public static void Error120 (Location l, string name) - { - Report.Error ( - 120, l, - "An object reference is required " + - "for the non-static field `"+name+"'"); - } - - // - // Checks whether we are trying to access an instance - // property, method or field from a static body. - // - Expression MemberStaticCheck (Expression e) - { - if (e is FieldExpr){ - FieldInfo fi = ((FieldExpr) e).FieldInfo; - - if (!fi.IsStatic){ - Error120 (Location, Name); - return null; - } - } else if (e is MethodGroupExpr){ - MethodGroupExpr mg = (MethodGroupExpr) e; - - if (!mg.RemoveInstanceMethods ()){ - Error120 (Location, mg.Methods [0].Name); - return null; - } - return e; - } else if (e is PropertyExpr){ - if (!((PropertyExpr) e).IsStatic){ - Error120 (Location, Name); - return null; - } - } - return e; - } - - // - // 7.5.2: Simple Names. - // - // Local Variables and Parameters are handled at - // parse time, so they never occur as SimpleNames. - // - public override Expression DoResolve (EmitContext ec) + public override Expression Reduce (EmitContext ec) { - Expression e; - - // - // Stage 1: Performed by the parser (binding to local or parameters). - // - - // - // Stage 2: Lookup members - // - e = MemberLookup (ec, ec.TypeContainer.TypeBuilder, Name, true, Location); - if (e == null){ - // - // Stage 3: Lookup symbol in the various namespaces. - // - Type t; - - if ((t = ec.TypeContainer.LookupType (Name, true)) != null) - return new TypeExpr (t); + expr = expr.Reduce (ec); + trueExpr = trueExpr.Reduce (ec); + falseExpr = falseExpr.Reduce (ec); - // - // Stage 3 part b: Lookup up if we are an alias to a type - // or a namespace. - // - // Since we are cheating: we only do the Alias lookup for - // namespaces if the name does not include any dots in it - // - - // IMPLEMENT ME. Read mcs/mcs/TODO for ideas, or rewrite - // using NamespaceExprs (dunno how that fixes the alias - // per-file though). - - // No match, maybe our parent can compose us - // into something meaningful. - // + if (!(expr is Literal && trueExpr is Literal && falseExpr is Literal)) return this; - } - - // Step 2, continues here. - if (e is TypeExpr) - return e; - if (e is FieldExpr){ - FieldExpr fe = (FieldExpr) e; - - if (!fe.FieldInfo.IsStatic) - fe.InstanceExpression = new This (Location.Null); - } + BoolLiteral bl = (BoolLiteral) expr; - if (ec.IsStatic) - return MemberStaticCheck (e); + if (bl.Value) + return trueExpr; else - return e; - } - - public override void Emit (EmitContext ec) - { - // - // If this is ever reached, then we failed to - // find the name as a namespace - // - - Error (103, Location, "The name `" + Name + - "' does not exist in the class `" + - ec.TypeContainer.Name + "'"); + return falseExpr; } } - - public class LocalVariableReference : Expression, IStackStore, IMemoryLocation { + + public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation { public readonly string Name; public readonly Block Block; @@ -3351,7 +1661,7 @@ namespace CIR { int idx = vi.Idx; vi.Used = true; - + switch (idx){ case 0: ig.Emit (OpCodes.Ldloc_0); @@ -3360,15 +1670,15 @@ namespace CIR { case 1: ig.Emit (OpCodes.Ldloc_1); break; - + case 2: ig.Emit (OpCodes.Ldloc_2); break; - + case 3: ig.Emit (OpCodes.Ldloc_3); break; - + default: if (idx <= 255) ig.Emit (OpCodes.Ldloc_S, (byte) idx); @@ -3377,7 +1687,7 @@ namespace CIR { break; } } - + public static void Store (ILGenerator ig, int idx) { switch (idx){ @@ -3405,21 +1715,23 @@ namespace CIR { break; } } - - public void Store (EmitContext ec) + + public void EmitAssign (EmitContext ec, Expression source) { ILGenerator ig = ec.ig; VariableInfo vi = VariableInfo; vi.Assigned = true; - // Funny seems the above generates optimal code for us, but + source.Emit (ec); + + // Funny seems the code below generates optimal code for us, but // seems to take too long to generate what we need. // ig.Emit (OpCodes.Stloc, vi.LocalBuilder); Store (ig, vi.Idx); } - + public void AddressOf (EmitContext ec) { VariableInfo vi = VariableInfo; @@ -3435,7 +1747,7 @@ namespace CIR { } } - public class ParameterReference : Expression, IStackStore, IMemoryLocation { + public class ParameterReference : Expression, IAssignMethod, IMemoryLocation { public readonly Parameters Pars; public readonly String Name; public readonly int Idx; @@ -3470,8 +1782,10 @@ namespace CIR { ec.ig.Emit (OpCodes.Ldarg, arg_idx); } - public void Store (EmitContext ec) + public void EmitAssign (EmitContext ec, Expression source) { + source.Emit (ec); + if (arg_idx <= 255) ec.ig.Emit (OpCodes.Starg_S, (byte) arg_idx); else @@ -3492,19 +1806,19 @@ namespace CIR { // Used for arguments to New(), Invocation() // public class Argument { - public enum AType { + public enum AType : byte { Expression, Ref, Out }; - public readonly AType Type; + public readonly AType ArgType; public Expression expr; - + public Argument (Expression expr, AType type) { this.expr = expr; - this.Type = type; + this.ArgType = type; } public Expression Expr { @@ -3517,16 +1831,53 @@ namespace CIR { } } - public bool Resolve (EmitContext ec) + public Type Type { + get { + return expr.Type; + } + } + + public Parameter.Modifier GetParameterModifier () + { + if (ArgType == AType.Ref) + return Parameter.Modifier.REF; + + if (ArgType == AType.Out) + return Parameter.Modifier.OUT; + + return Parameter.Modifier.NONE; + } + + public static string FullDesc (Argument a) + { + return (a.ArgType == AType.Ref ? "ref " : + (a.ArgType == AType.Out ? "out " : "")) + + TypeManager.CSharpName (a.Expr.Type); + } + + public bool Resolve (EmitContext ec, Location loc) { expr = expr.Resolve (ec); + if (ArgType == AType.Expression) + return expr != null; + + if (expr.ExprClass != ExprClass.Variable){ + Report.Error (206, loc, + "A property or indexer can not be passed as an out or ref " + + "parameter"); + return false; + } + return expr != null; } public void Emit (EmitContext ec) { - expr.Emit (ec); + if (ArgType == AType.Ref || ArgType == AType.Out) + ((IMemoryLocation)expr).AddressOf (ec); + else + expr.Emit (ec); } } @@ -3535,7 +1886,7 @@ namespace CIR { // public class Invocation : ExpressionStatement { public readonly ArrayList Arguments; - public readonly Location Location; + Location loc; Expression expr; MethodBase method = null; @@ -3558,7 +1909,7 @@ namespace CIR { { this.expr = expr; Arguments = arguments; - Location = l; + loc = l; } public Expression Expr { @@ -3647,7 +1998,7 @@ namespace CIR { static int BetterConversion (EmitContext ec, Argument a, Type p, Type q, bool use_standard, Location loc) { - Type argument_type = a.Expr.Type; + Type argument_type = a.Type; Expression argument_expr = a.Expr; if (argument_type == null) @@ -3848,7 +2199,7 @@ namespace CIR { for (int i = count; i > 0; ) { i--; - sb.Append (TypeManager.CSharpName (pd.ParameterType (count - i - 1))); + sb.Append (pd.ParameterDesc (count - i - 1)); if (i != 0) sb.Append (", "); } @@ -3922,6 +2273,92 @@ namespace CIR { return null; } + // + // Determines is the candidate method, if a params method, is applicable + // in its expanded form to the given set of arguments + // + static bool IsParamsMethodApplicable (ArrayList arguments, MethodBase candidate) + { + int arg_count; + + if (arguments == null) + arg_count = 0; + else + arg_count = arguments.Count; + + ParameterData pd = GetParameterData (candidate); + + int pd_count = pd.Count; + + if (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) + return false; + + if (pd_count - 1 > arg_count) + return false; + + // If we have come this far, the case which remains is when the number of parameters + // is less than or equal to the argument count. So, we now check if the element type + // of the params array is compatible with each argument type + // + + Type element_type = pd.ParameterType (pd_count - 1).GetElementType (); + + for (int i = pd_count - 1; i < arg_count - 1; i++) { + Argument a = (Argument) arguments [i]; + if (!StandardConversionExists (a.Type, element_type)) + return false; + } + + return true; + } + + // + // Determines if the candidate method is applicable (section 14.4.2.1) + // to the given set of arguments + // + static bool IsApplicable (ArrayList arguments, MethodBase candidate) + { + int arg_count; + + if (arguments == null) + arg_count = 0; + else + arg_count = arguments.Count; + + ParameterData pd = GetParameterData (candidate); + + int pd_count = pd.Count; + + if (arg_count != pd.Count) + return false; + + for (int i = arg_count; i > 0; ) { + i--; + + Argument a = (Argument) arguments [i]; + + Parameter.Modifier a_mod = a.GetParameterModifier (); + Parameter.Modifier p_mod = pd.ParameterModifier (i); + + if (a_mod == p_mod) { + + if (a_mod == Parameter.Modifier.NONE) + if (!StandardConversionExists (a.Type, pd.ParameterType (i))) + return false; + + if (a_mod == Parameter.Modifier.REF || + a_mod == Parameter.Modifier.OUT) + if (pd.ParameterType (i) != a.Type) + return false; + } else + return false; + } + + return true; + } + + + // // Find the Applicable Function Members (7.4.2.1) // @@ -3934,7 +2371,7 @@ namespace CIR { // loc: The location if we want an error to be reported, or a Null // location for "probing" purposes. // - // inside_user_defined: controls whether OverloadResolve should use the + // use_standard: controls whether OverloadResolve should use the // ConvertImplicit or ConvertImplicitStandard during overload resolution. // // Returns: The MethodBase (either a ConstructorInfo or a MethodInfo) @@ -3955,6 +2392,10 @@ namespace CIR { MethodBase candidate = me.Methods [i]; int x; + // Check if candidate is applicable (section 14.4.2.1) + if (!IsApplicable (Arguments, candidate)) + continue; + x = BetterFunction (ec, Arguments, candidate, method, use_standard, loc); if (x == 0) @@ -3970,10 +2411,30 @@ namespace CIR { else argument_count = Arguments.Count; + // + // Now we see if we can find params functions, applicable in their expanded form + // since if they were applicable in their normal form, they would have been selected + // above anyways + // + if (best_match_idx == -1) { + + for (int i = me.Methods.Length; i > 0; ) { + i--; + MethodBase candidate = me.Methods [i]; + + if (IsParamsMethodApplicable (Arguments, candidate)) { + best_match_idx = i; + method = me.Methods [best_match_idx]; + break; + } + } + } + + // + // Now we see if we can at least find a method with the same number of arguments + // ParameterData pd; - // Now we see if we can at least find a method with the same number of arguments - // and then try doing implicit conversion on the arguments if (best_match_idx == -1) { for (int i = me.Methods.Length; i > 0;) { @@ -3988,55 +2449,85 @@ namespace CIR { } else continue; } - } if (method == null) return null; - + // And now convert implicitly, each argument to the required type pd = GetParameterData (method); + int pd_count = pd.Count; + + for (int j = 0; j < argument_count; j++) { - for (int j = argument_count; j > 0;) { - j--; Argument a = (Argument) Arguments [j]; Expression a_expr = a.Expr; Type parameter_type = pd.ParameterType (j); - - if (a_expr.Type != parameter_type){ - Expression conv; + // + // Note that we need to compare against the element type + // when we have a params method + // + if (pd.ParameterModifier (pd_count - 1) == Parameter.Modifier.PARAMS) { + if (j >= pd_count - 1) + parameter_type = pd.ParameterType (pd_count - 1).GetElementType (); + } + + if (a.Type != parameter_type){ + Expression conv; + if (use_standard) - conv = ConvertImplicitStandard (ec, a_expr, parameter_type, - Location.Null); + conv = ConvertImplicitStandard (ec, a_expr, parameter_type, Location.Null); else - conv = ConvertImplicit (ec, a_expr, parameter_type, - Location.Null); + conv = ConvertImplicit (ec, a_expr, parameter_type, Location.Null); - if (conv == null){ + if (conv == null) { if (!Location.IsNull (loc)) { Error (1502, loc, - "The best overloaded match for method '" + FullMethodDesc (method) + + "The best overloaded match for method '" + FullMethodDesc (method)+ "' has some invalid arguments"); Error (1503, loc, - "Argument " + (j+1) + - ": Cannot convert from '" + TypeManager.CSharpName (a_expr.Type) - + "' to '" + TypeManager.CSharpName (pd.ParameterType (j)) + "'"); + "Argument " + (j+1) + + ": Cannot convert from '" + Argument.FullDesc (a) + + "' to '" + pd.ParameterDesc (j) + "'"); } return null; } + + + // // Update the argument with the implicit conversion // if (a_expr != conv) a.Expr = conv; + + // FIXME : For the case of params methods, we need to actually instantiate + // an array and initialize it with the argument values etc etc. + + } + + if (a.GetParameterModifier () != pd.ParameterModifier (j) && + pd.ParameterModifier (j) != Parameter.Modifier.PARAMS) { + if (!Location.IsNull (loc)) { + Error (1502, loc, + "The best overloaded match for method '" + FullMethodDesc (method)+ + "' has some invalid arguments"); + Error (1503, loc, + "Argument " + (j+1) + + ": Cannot convert from '" + Argument.FullDesc (a) + + "' to '" + pd.ParameterDesc (j) + "'"); + } + return null; } + + } return method; } - + public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me, ArrayList Arguments, Location loc) { @@ -4060,12 +2551,12 @@ namespace CIR { bool IsDelegate = TypeManager.IsDelegateType (expr_type); if (IsDelegate) return (new DelegateInvocation ( - this.expr, Arguments, Location)).Resolve (ec); + this.expr, Arguments, loc)).Resolve (ec); } } if (!(expr is MethodGroupExpr)){ - report118 (Location, this.expr, "method group"); + report118 (loc, this.expr, "method group"); return null; } @@ -4077,16 +2568,15 @@ namespace CIR { --i; Argument a = (Argument) Arguments [i]; - if (!a.Resolve (ec)) + if (!a.Resolve (ec, loc)) return null; } } - method = OverloadResolve (ec, (MethodGroupExpr) this.expr, Arguments, - Location); + method = OverloadResolve (ec, (MethodGroupExpr) this.expr, Arguments, loc); if (method == null){ - Error (-6, Location, + Error (-6, loc, "Could not find any applicable function for this argument list"); return null; } @@ -4098,18 +2588,69 @@ namespace CIR { return this; } - public static void EmitArguments (EmitContext ec, ArrayList Arguments) + // + // Emits the list of arguments as an array + // + static void EmitParams (EmitContext ec, int idx, ArrayList arguments) + { + ILGenerator ig = ec.ig; + int count = arguments.Count - idx; + Argument a = (Argument) arguments [idx]; + Type t = a.expr.Type; + string array_type = t.FullName + "[]"; + LocalBuilder array; + + array = ig.DeclareLocal (Type.GetType (array_type)); + IntLiteral.EmitInt (ig, count); + ig.Emit (OpCodes.Newarr, t); + ig.Emit (OpCodes.Stloc, array); + + int top = arguments.Count; + for (int j = idx; j < top; j++){ + a = (Argument) arguments [j]; + + ig.Emit (OpCodes.Ldloc, array); + IntLiteral.EmitInt (ig, j - idx); + a.Emit (ec); + + ArrayAccess.EmitStoreOpcode (ig, t); + } + ig.Emit (OpCodes.Ldloc, array); + } + + // + // Emits a list of resolved Arguments that are in the arguments + // ArrayList. + // + // The MethodBase argument might be null if the + // emission of the arguments is known not to contain + // a `params' field (for example in constructors or other routines + // that keep their arguments in this structure + // + + public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments) { + ParameterData pd = null; int top; - if (Arguments != null) - top = Arguments.Count; + if (arguments != null) + top = arguments.Count; else top = 0; + if (mb != null) + pd = GetParameterData (mb); + for (int i = 0; i < top; i++){ - Argument a = (Argument) Arguments [i]; + Argument a = (Argument) arguments [i]; + if (pd != null){ + if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){ + EmitParams (ec, i, arguments); + return; + } + } + a.Emit (ec); } } @@ -4148,7 +2689,7 @@ namespace CIR { Type t = instance_expr.Type; instance_expr.Emit (ec); - LocalBuilder temp = ec.GetTemporaryStorage (t); + LocalBuilder temp = ig.DeclareLocal (t); ig.Emit (OpCodes.Stloc, temp); ig.Emit (OpCodes.Ldloca, temp); } @@ -4158,7 +2699,7 @@ namespace CIR { } if (Arguments != null) - EmitArguments (ec, Arguments); + EmitArguments (ec, method, Arguments); if (is_static || struct_call){ if (method is MethodInfo) @@ -4197,7 +2738,7 @@ namespace CIR { public readonly ArrayList Arguments; public readonly string RequestedType; - Location Location; + Location loc; MethodBase method = null; // @@ -4206,11 +2747,11 @@ namespace CIR { // Expression value_target; - public New (string requested_type, ArrayList arguments, Location loc) + public New (string requested_type, ArrayList arguments, Location l) { RequestedType = requested_type; Arguments = arguments; - Location = loc; + loc = l; } public Expression ValueTypeVariable { @@ -4233,19 +2774,19 @@ namespace CIR { bool IsDelegate = TypeManager.IsDelegateType (type); if (IsDelegate) - return (new NewDelegate (type, Arguments, Location)).Resolve (ec); + return (new NewDelegate (type, Arguments, loc)).Resolve (ec); Expression ml; ml = MemberLookup (ec, type, ".ctor", false, - MemberTypes.Constructor, AllBindingsFlags, Location); + MemberTypes.Constructor, AllBindingsFlags, loc); bool is_struct = false; is_struct = type.IsSubclassOf (TypeManager.value_type); if (! (ml is MethodGroupExpr)){ if (!is_struct){ - report118 (Location, ml, "method group"); + report118 (loc, ml, "method group"); return null; } } @@ -4256,17 +2797,17 @@ namespace CIR { --i; Argument a = (Argument) Arguments [i]; - if (!a.Resolve (ec)) + if (!a.Resolve (ec, loc)) return null; } } - + method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml, - Arguments, Location); + Arguments, loc); } if (method == null && !is_struct) { - Error (-6, Location, + Error (-6, loc, "New invocation: Can not find a constructor for " + "this argument list"); return null; @@ -4294,7 +2835,7 @@ namespace CIR { ml.AddressOf (ec); } else { - Invocation.EmitArguments (ec, Arguments); + Invocation.EmitArguments (ec, method, Arguments); ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) method); return true; } @@ -4330,13 +2871,27 @@ namespace CIR { // // Represents an array creation expression. // + // + // + // There are two possible scenarios here: one is an array creation + // expression that specifies the dimensions and optionally the + // initialization data + // public class ArrayCreation : ExpressionStatement { + string RequestedType; string Rank; ArrayList Initializers; - Location loc; + Location loc; ArrayList Arguments; - Expression Array; + + MethodBase method = null; + Type array_element_type; + bool IsOneDimensional = false; + + bool IsBuiltinType = false; + + int dimensions = 0; public ArrayCreation (string requested_type, ArrayList exprs, string rank, ArrayList initializers, Location l) @@ -4344,7 +2899,7 @@ namespace CIR { RequestedType = requested_type; Rank = rank; Initializers = initializers; - loc = l; + loc = l; Arguments = new ArrayList (); @@ -4352,64 +2907,18 @@ namespace CIR { Arguments.Add (new Argument (e, Argument.AType.Expression)); } - - public override Expression DoResolve (EmitContext ec) - { - type = ec.TypeContainer.LookupType (RequestedType, false); - - if (TypeManager.IsBuiltinType (type)) - Array = new NewBuiltinArray ( - RequestedType, Rank, Arguments, Initializers, loc) - .Resolve (ec); - else - Array = new NewUserdefinedArray ( - RequestedType, Rank, Arguments, Initializers, loc) - .Resolve (ec); - - if (Array == null) - return null; - - type = Array.Type; - eclass = ExprClass.Value; - - return this; - } - - public override void Emit (EmitContext ec) - { - Array.Emit (ec); - } - public override void EmitStatement (EmitContext ec) + public ArrayCreation (string requested_type, string rank, ArrayList initializers, Location l) { - Emit (ec); - ec.ig.Emit (OpCodes.Pop); - } - } - - // - // Class to create arrays out of built-in types - // - public class NewBuiltinArray : Expression { - - public readonly string RequestedType; - public readonly string Rank; - public ArrayList Arguments; - public ArrayList Initializers; + RequestedType = requested_type; + Initializers = initializers; + loc = l; - Location Location; + Rank = rank.Substring (0, rank.LastIndexOf ("[")); - MethodBase method = null; - Type array_element_type; - bool IsOneDimensional = false; + string tmp = rank.Substring (rank.LastIndexOf ("[")); - public NewBuiltinArray (string type, string rank, ArrayList args, ArrayList initializers, Location loc) - { - RequestedType = type; - Rank = rank; - Arguments = args; - Initializers = initializers; - Location = loc; + dimensions = tmp.Length - 1; } public static string FormArrayType (string base_type, int idx_count, string rank) @@ -4442,201 +2951,256 @@ namespace CIR { return val.Substring (0, val.LastIndexOf ("[")); } - public override Expression DoResolve (EmitContext ec) + void error178 () { - int arg_count; - - if (Arguments == null) - arg_count = 0; - else - arg_count = Arguments.Count; - - string array_type = FormArrayType (RequestedType, arg_count, Rank); - - string element_type = FormElementType (RequestedType, arg_count, Rank); - - type = ec.TypeContainer.LookupType (array_type, false); - - array_element_type = ec.TypeContainer.LookupType (element_type, false); - - if (type == null) - return null; + Report.Error (178, loc, "Incorrectly structured array initializer"); + } - if (arg_count == 1) { - IsOneDimensional = true; - eclass = ExprClass.Value; - return this; - } - - Expression ml; + bool ValidateInitializers (EmitContext ec) + { + if (Initializers == null) + return true; - ml = MemberLookup (ec, type, ".ctor", false, MemberTypes.Constructor, - AllBindingsFlags, Location); + Type underlying_type = ec.TypeContainer.LookupType (RequestedType, false); - if (!(ml is MethodGroupExpr)){ - report118 (Location, ml, "method group"); - return null; - } + ArrayList probe = Initializers; - if (ml == null) { - Report.Error (-6, Location, "New invocation: Can not find a constructor for " + - "this argument list"); - return null; - } - if (Arguments != null) { - for (int i = arg_count; i > 0;){ - --i; + for (int i = 0; i < Arguments.Count; i++) { Argument a = (Argument) Arguments [i]; - if (!a.Resolve (ec)) - return null; - } - } - - method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml, Arguments, Location); + Expression e = Expression.Reduce (ec, a.Expr); + + if (!(e is Literal)) { + Report.Error (150, loc, "A constant value is expected"); + return false; + } + + int value = (int) ((Literal) e).GetValue (); + + if (probe == null) { + error178 (); + return false; + } + + if (value != probe.Count) { + error178 (); + return false; + } - if (method == null) { - Report.Error (-6, Location, "New invocation: Can not find a constructor for " + - "this argument list"); - return null; - } + if (probe [0] is ArrayList) + probe = (ArrayList) probe [0]; + else { + for (int j = 0; j < probe.Count; ++j) { + Expression tmp = (Expression) probe [j]; + + tmp = tmp.Resolve (ec); - eclass = ExprClass.Value; - return this; + Expression conv = ConvertImplicitRequired (ec, tmp, + underlying_type, loc); - } + if (conv == null) + return false; + } - public override void Emit (EmitContext ec) - { - if (IsOneDimensional) { - Invocation.EmitArguments (ec, Arguments); - ec.ig.Emit (OpCodes.Newarr, array_element_type); + probe = null; + } + } } else { - Invocation.EmitArguments (ec, Arguments); - ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) method); - } - } - } - - // - // Class to create arrays out of user defined types - // - public class NewUserdefinedArray : Expression { - - public readonly string RequestedType; - public readonly string Rank; - public ArrayList Arguments; - public ArrayList Initializers; - - Location Location; + // + // Here is where we update dimension info in the case + // that the user skips doing that + // - bool IsOneDimensional = false; + Arguments = new ArrayList (); + + for (probe = Initializers; probe != null; ) { + Expression e = new IntLiteral (probe.Count); - MethodBase method; - Type array_element_type; + Arguments.Add (new Argument (e, Argument.AType.Expression)); - public NewUserdefinedArray (string type, string rank, ArrayList args, ArrayList initializers, Location loc) - { - RequestedType = type; - Rank = rank; - Arguments = args; - Initializers = initializers; - Location = loc; - } + if (probe [0] is ArrayList) + probe = (ArrayList) probe [0]; + else { + for (int j = 0; j < probe.Count; ++j) { + Expression tmp = (Expression) probe [j]; + + tmp = tmp.Resolve (ec); - public static string FormArrayType (string base_type, int idx_count, string rank) - { - StringBuilder sb = new StringBuilder (base_type); + Expression conv = ConvertImplicitRequired (ec, tmp, + underlying_type, loc); - sb.Append ("["); - for (int i = 1; i < idx_count; i++) - sb.Append (","); - sb.Append ("]"); + if (conv == null) + return false; + } + + probe = null; + } + } - sb.Append (rank); - - return sb.ToString (); - } + if (Arguments.Count != dimensions) { + error178 (); + return false; + } + } + return true; + } + public override Expression DoResolve (EmitContext ec) { - ModuleBuilder mb = ec.TypeContainer.RootContext.ModuleBuilder; int arg_count; + if (!ValidateInitializers (ec)) + return null; + if (Arguments == null) arg_count = 0; else arg_count = Arguments.Count; + + string array_type = FormArrayType (RequestedType, arg_count, Rank); - string array_type = NewBuiltinArray.FormArrayType (RequestedType, arg_count, Rank); + string element_type = FormElementType (RequestedType, arg_count, Rank); - string element_type = NewBuiltinArray.FormElementType (RequestedType, arg_count, Rank); + type = ec.TypeContainer.LookupType (array_type, false); + + array_element_type = ec.TypeContainer.LookupType (element_type, false); - type = mb.GetType (array_type); - array_element_type = mb.GetType (element_type); - if (type == null) return null; - + if (arg_count == 1) { IsOneDimensional = true; eclass = ExprClass.Value; return this; } - ArrayList args = new ArrayList (); - if (Arguments != null){ - for (int i = arg_count; i > 0;){ - --i; - Argument a = (Argument) Arguments [i]; - - if (!a.Resolve (ec)) - return null; - - args.Add (a.Expr.Type); - } - } - - Type [] arg_types = null; - - if (args.Count > 0) - arg_types = new Type [args.Count]; + IsBuiltinType = TypeManager.IsBuiltinType (type); - args.CopyTo (arg_types, 0); + if (IsBuiltinType) { + + Expression ml; + + ml = MemberLookup (ec, type, ".ctor", false, MemberTypes.Constructor, + AllBindingsFlags, loc); + + if (!(ml is MethodGroupExpr)){ + report118 (loc, ml, "method group"); + return null; + } + + if (ml == null) { + Report.Error (-6, loc, "New invocation: Can not find a constructor for " + + "this argument list"); + return null; + } + + if (Arguments != null) { + for (int i = arg_count; i > 0;){ + --i; + Argument a = (Argument) Arguments [i]; + + if (!a.Resolve (ec, loc)) + return null; + } + } + + method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml, Arguments, loc); + + if (method == null) { + Report.Error (-6, loc, "New invocation: Can not find a constructor for " + + "this argument list"); + return null; + } + + eclass = ExprClass.Value; + return this; + + } else { - method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null, - arg_types); - - if (method == null) { - Report.Error (-6, Location, "New invocation: Can not find a constructor for " + - "this argument list"); - return null; - } + ModuleBuilder mb = ec.TypeContainer.RootContext.ModuleBuilder; - eclass = ExprClass.Value; - return this; + ArrayList args = new ArrayList (); + if (Arguments != null){ + for (int i = arg_count; i > 0;){ + --i; + Argument a = (Argument) Arguments [i]; + + if (!a.Resolve (ec, loc)) + return null; + + args.Add (a.Type); + } + } + + Type [] arg_types = null; + + if (args.Count > 0) + arg_types = new Type [args.Count]; + + args.CopyTo (arg_types, 0); + + method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null, + arg_types); + + if (method == null) { + Report.Error (-6, loc, "New invocation: Can not find a constructor for " + + "this argument list"); + return null; + } + + eclass = ExprClass.Value; + return this; + + } } public override void Emit (EmitContext ec) { + ILGenerator ig = ec.ig; + if (IsOneDimensional) { - Invocation.EmitArguments (ec, Arguments); - ec.ig.Emit (OpCodes.Newarr, array_element_type); + Invocation.EmitArguments (ec, null, Arguments); + ig.Emit (OpCodes.Newarr, array_element_type); } else { - Invocation.EmitArguments (ec, Arguments); - ec.ig.Emit (OpCodes.Newobj, (MethodInfo) method); + Invocation.EmitArguments (ec, null, Arguments); + + if (IsBuiltinType) + ig.Emit (OpCodes.Newobj, (ConstructorInfo) method); + else + ig.Emit (OpCodes.Newobj, (MethodInfo) method); + } + + if (Initializers != null){ + FieldBuilder fb; + + // FIXME: This is just sample data, need to fill with + // real values. + byte [] a = new byte [4] { 1, 2, 3, 4 }; + + fb = ec.TypeContainer.RootContext.MakeStaticData (a); + + ig.Emit (OpCodes.Dup); + ig.Emit (OpCodes.Ldtoken, fb); + ig.Emit (OpCodes.Call, TypeManager.void_initializearray_array_fieldhandle); } } - + + public override void EmitStatement (EmitContext ec) + { + Emit (ec); + ec.ig.Emit (OpCodes.Pop); + } + } // // Represents the `this' construct // - public class This : Expression, IStackStore, IMemoryLocation { + public class This : Expression, IAssignMethod, IMemoryLocation { Location loc; public This (Location loc) @@ -4675,8 +3239,9 @@ namespace CIR { ec.ig.Emit (OpCodes.Ldarg_0); } - public void Store (EmitContext ec) + public void EmitAssign (EmitContext ec, Expression source) { + source.Emit (ec); ec.ig.Emit (OpCodes.Starg, 0); } @@ -4720,476 +3285,184 @@ namespace CIR { public class SizeOf : Expression { public readonly string QueriedType; - public SizeOf (string queried_type) - { - this.QueriedType = queried_type; - } - - public override Expression DoResolve (EmitContext ec) - { - // FIXME: Implement; - throw new Exception ("Unimplemented"); - // return this; - } - - public override void Emit (EmitContext ec) - { - throw new Exception ("Implement me"); - } - } - - public class MemberAccess : Expression { - public readonly string Identifier; - Expression expr; - Expression member_lookup; - Location loc; - - public MemberAccess (Expression expr, string id, Location l) - { - this.expr = expr; - Identifier = id; - loc = l; - } - - public Expression Expr { - get { - return expr; - } - } - - void error176 (Location loc, string name) - { - Report.Error (176, loc, "Static member `" + - name + "' cannot be accessed " + - "with an instance reference, qualify with a " + - "type name instead"); - } - - public override Expression DoResolve (EmitContext ec) - { - // - // We are the sole users of ResolveWithSimpleName (ie, the only - // ones that can cope with it - // - expr = expr.ResolveWithSimpleName (ec); - - if (expr == null) - return null; - - if (expr is SimpleName){ - SimpleName child_expr = (SimpleName) expr; - - expr = new SimpleName (child_expr.Name + "." + Identifier, loc); - - return expr.Resolve (ec); - } - - member_lookup = MemberLookup (ec, expr.Type, Identifier, false, loc); - - if (member_lookup == null) - return null; - - // - // Method Groups - // - if (member_lookup is MethodGroupExpr){ - MethodGroupExpr mg = (MethodGroupExpr) member_lookup; - - // - // Type.MethodGroup - // - if (expr is TypeExpr){ - if (!mg.RemoveInstanceMethods ()){ - SimpleName.Error120 (loc, mg.Methods [0].Name); - return null; - } - - return member_lookup; - } - - // - // Instance.MethodGroup - // - if (!mg.RemoveStaticMethods ()){ - error176 (loc, mg.Methods [0].Name); - return null; - } - - mg.InstanceExpression = expr; - - return member_lookup; - } - - if (member_lookup is FieldExpr){ - FieldExpr fe = (FieldExpr) member_lookup; - - if (expr is TypeExpr){ - if (!fe.FieldInfo.IsStatic){ - error176 (loc, fe.FieldInfo.Name); - return null; - } - return member_lookup; - } else { - if (fe.FieldInfo.IsStatic){ - error176 (loc, fe.FieldInfo.Name); - return null; - } - fe.InstanceExpression = expr; - - return fe; - } - } - - if (member_lookup is PropertyExpr){ - PropertyExpr pe = (PropertyExpr) member_lookup; - - if (expr is TypeExpr){ - if (!pe.IsStatic){ - SimpleName.Error120 (loc, pe.PropertyInfo.Name); - return null; - } - return pe; - } else { - if (pe.IsStatic){ - error176 (loc, pe.PropertyInfo.Name); - return null; - } - pe.InstanceExpression = expr; - - return pe; - } - } - - Console.WriteLine ("Support for [" + member_lookup + "] is not present yet"); - Environment.Exit (0); - return null; - } - - public override void Emit (EmitContext ec) - { - throw new Exception ("Should not happen I think"); - } - - } - - // - // Fully resolved expression that evaluates to a type - // - public class TypeExpr : Expression { - public TypeExpr (Type t) - { - Type = t; - eclass = ExprClass.Type; - } - - override public Expression DoResolve (EmitContext ec) - { - return this; - } - - override public void Emit (EmitContext ec) - { - throw new Exception ("Implement me"); - } - } - - // - // MethodGroup Expression. - // - // This is a fully resolved expression that evaluates to a type - // - public class MethodGroupExpr : Expression { - public MethodBase [] Methods; - Expression instance_expression = null; - - public MethodGroupExpr (MemberInfo [] mi) - { - Methods = new MethodBase [mi.Length]; - mi.CopyTo (Methods, 0); - eclass = ExprClass.MethodGroup; - } - - public MethodGroupExpr (ArrayList l) - { - Methods = new MethodBase [l.Count]; - - l.CopyTo (Methods, 0); - eclass = ExprClass.MethodGroup; - } - - // - // `A method group may have associated an instance expression' - // - public Expression InstanceExpression { - get { - return instance_expression; - } - - set { - instance_expression = value; - } - } - - override public Expression DoResolve (EmitContext ec) - { - return this; - } - - override public void Emit (EmitContext ec) - { - throw new Exception ("This should never be reached"); - } - - bool RemoveMethods (bool keep_static) - { - ArrayList smethods = new ArrayList (); - int top = Methods.Length; - int i; - - for (i = 0; i < top; i++){ - MethodBase mb = Methods [i]; - - if (mb.IsStatic == keep_static) - smethods.Add (mb); - } - - if (smethods.Count == 0) - return false; - - Methods = new MethodBase [smethods.Count]; - smethods.CopyTo (Methods, 0); - - return true; - } - - // - // Removes any instance methods from the MethodGroup, returns - // false if the resulting set is empty. - // - public bool RemoveInstanceMethods () - { - return RemoveMethods (true); - } - - // - // Removes any static methods from the MethodGroup, returns - // false if the resulting set is empty. - // - public bool RemoveStaticMethods () - { - return RemoveMethods (false); - } - } - - // - // Fully resolved expression that evaluates to a Field - // - public class FieldExpr : Expression, IStackStore, IMemoryLocation { - public readonly FieldInfo FieldInfo; - public Expression InstanceExpression; - Location loc; - - public FieldExpr (FieldInfo fi, Location l) - { - FieldInfo = fi; - eclass = ExprClass.Variable; - type = fi.FieldType; - loc = l; - } - - override public Expression DoResolve (EmitContext ec) - { - if (!FieldInfo.IsStatic){ - if (InstanceExpression == null){ - throw new Exception ("non-static FieldExpr without instance var\n" + - "You have to assign the Instance variable\n" + - "Of the FieldExpr to set this\n"); - } - - InstanceExpression = InstanceExpression.Resolve (ec); - if (InstanceExpression == null) - return null; - - } - return this; - } - - public Expression DoResolveLValue (EmitContext ec) - { - if (!FieldInfo.IsInitOnly) - return this; - - // - // InitOnly fields can only be assigned in constructors - // - - if (ec.IsConstructor) - return this; - - Report.Error (191, loc, - "Readonly field can not be assigned outside " + - "of constructor or variable initializer"); - - return null; - } - - override public void Emit (EmitContext ec) - { - ILGenerator ig = ec.ig; - - if (FieldInfo.IsStatic) - ig.Emit (OpCodes.Ldsfld, FieldInfo); - else { - InstanceExpression.Emit (ec); - - ig.Emit (OpCodes.Ldfld, FieldInfo); - } + public SizeOf (string queried_type) + { + this.QueriedType = queried_type; } - public void Store (EmitContext ec) + public override Expression DoResolve (EmitContext ec) { - if (FieldInfo.IsStatic) - ec.ig.Emit (OpCodes.Stsfld, FieldInfo); - else - ec.ig.Emit (OpCodes.Stfld, FieldInfo); + // FIXME: Implement; + throw new Exception ("Unimplemented"); + // return this; } - public void AddressOf (EmitContext ec) + public override void Emit (EmitContext ec) { - if (FieldInfo.IsStatic) - ec.ig.Emit (OpCodes.Ldsflda, FieldInfo); - else { - InstanceExpression.Emit (ec); - ec.ig.Emit (OpCodes.Ldflda, FieldInfo); - } + throw new Exception ("Implement me"); } } - - // - // Expression that evaluates to a Property. The Assign class - // might set the `Value' expression if we are in an assignment. - // - // This is not an LValue because we need to re-write the expression, we - // can not take data from the stack and store it. - // - public class PropertyExpr : ExpressionStatement, IAssignMethod { - public readonly PropertyInfo PropertyInfo; - public readonly bool IsStatic; - MethodInfo [] Accessors; + + public class MemberAccess : Expression { + public readonly string Identifier; + Expression expr; + Expression member_lookup; Location loc; - Expression instance_expr; - - public PropertyExpr (PropertyInfo pi, Location l) + public MemberAccess (Expression expr, string id, Location l) { - PropertyInfo = pi; - eclass = ExprClass.PropertyAccess; - IsStatic = false; + this.expr = expr; + Identifier = id; loc = l; - Accessors = TypeManager.GetAccessors (pi); - - if (Accessors != null) - for (int i = 0; i < Accessors.Length; i++){ - if (Accessors [i] != null) - if (Accessors [i].IsStatic) - IsStatic = true; - } - else - Accessors = new MethodInfo [2]; - - type = pi.PropertyType; } - // - // The instance expression associated with this expression - // - public Expression InstanceExpression { - set { - instance_expr = value; - } - + public Expression Expr { get { - return instance_expr; + return expr; } } - public bool VerifyAssignable () + void error176 (Location loc, string name) { - if (!PropertyInfo.CanWrite){ - Report.Error (200, loc, - "The property `" + PropertyInfo.Name + - "' can not be assigned to, as it has not set accessor"); - return false; - } - - return true; + Report.Error (176, loc, "Static member `" + + name + "' cannot be accessed " + + "with an instance reference, qualify with a " + + "type name instead"); } - - override public Expression DoResolve (EmitContext ec) + + public override Expression DoResolve (EmitContext ec) { - if (!PropertyInfo.CanRead){ - Report.Error (154, loc, - "The property `" + PropertyInfo.Name + - "' can not be used in " + - "this context because it lacks a get accessor"); + // + // We are the sole users of ResolveWithSimpleName (ie, the only + // ones that can cope with it + // + expr = expr.ResolveWithSimpleName (ec); + + if (expr == null) return null; - } - return this; - } + if (expr is SimpleName){ + SimpleName child_expr = (SimpleName) expr; - override public void Emit (EmitContext ec) - { - Invocation.EmitCall (ec, IsStatic, instance_expr, Accessors [0], null); + expr = new SimpleName (child_expr.Name + "." + Identifier, loc); + + return expr.Resolve (ec); + } + + member_lookup = MemberLookup (ec, expr.Type, Identifier, false, loc); + + if (member_lookup == null) + return null; - } + // + // Method Groups + // + if (member_lookup is MethodGroupExpr){ + MethodGroupExpr mg = (MethodGroupExpr) member_lookup; + + // + // Type.MethodGroup + // + if (expr is TypeExpr){ + if (!mg.RemoveInstanceMethods ()){ + SimpleName.Error120 (loc, mg.Methods [0].Name); + return null; + } - // - // Implements the IAssignMethod interface for assignments - // - public void EmitAssign (EmitContext ec, Expression source) - { - Argument arg = new Argument (source, Argument.AType.Expression); - ArrayList args = new ArrayList (); + return member_lookup; + } - args.Add (arg); - Invocation.EmitCall (ec, IsStatic, instance_expr, Accessors [1], args); - } + // + // Instance.MethodGroup + // + if (!mg.RemoveStaticMethods ()){ + error176 (loc, mg.Methods [0].Name); + return null; + } + + mg.InstanceExpression = expr; + + return member_lookup; + } - override public void EmitStatement (EmitContext ec) - { - Emit (ec); - ec.ig.Emit (OpCodes.Pop); - } - } + if (member_lookup is FieldExpr){ + FieldExpr fe = (FieldExpr) member_lookup; + FieldInfo fi = fe.FieldInfo; - // - // Fully resolved expression that evaluates to a Expression - // - public class EventExpr : Expression { - public readonly EventInfo EventInfo; - Location loc; - - public EventExpr (EventInfo ei, Location loc) - { - EventInfo = ei; - this.loc = loc; - eclass = ExprClass.EventAccess; - } + if (fi.IsLiteral) { + Type t = fi.FieldType; + object o; - override public Expression DoResolve (EmitContext ec) - { - // We are born in resolved state. - return this; + if (fi is FieldBuilder) + o = TypeManager.GetValue ((FieldBuilder) fi); + else + o = fi.GetValue (fi); + + if (t.IsSubclassOf (TypeManager.enum_type)) { + Expression enum_member = MemberLookup (ec, t, "value__", false, loc); + Type underlying_type = enum_member.Type; + + Expression e = Literalize (o, underlying_type); + e.Resolve (ec); + + return new EnumLiteral (e, t); + } + + Expression exp = Literalize (o, t); + exp.Resolve (ec); + + return exp; + } + + if (expr is TypeExpr){ + if (!fe.FieldInfo.IsStatic){ + error176 (loc, fe.FieldInfo.Name); + return null; + } + return member_lookup; + } else { + if (fe.FieldInfo.IsStatic){ + error176 (loc, fe.FieldInfo.Name); + return null; + } + fe.InstanceExpression = expr; + + return fe; + } + } + + if (member_lookup is PropertyExpr){ + PropertyExpr pe = (PropertyExpr) member_lookup; + + if (expr is TypeExpr){ + if (!pe.IsStatic){ + SimpleName.Error120 (loc, pe.PropertyInfo.Name); + return null; + } + return pe; + } else { + if (pe.IsStatic){ + error176 (loc, pe.PropertyInfo.Name); + return null; + } + pe.InstanceExpression = expr; + + return pe; + } + } + + Console.WriteLine ("Support for [" + member_lookup + "] is not present yet"); + Environment.Exit (0); + return null; } - override public void Emit (EmitContext ec) + public override void Emit (EmitContext ec) { - throw new Exception ("Implement me"); - // FIXME: Implement. + throw new Exception ("Should not happen I think"); } + } - + public class CheckedExpr : Expression { public Expression Expr; @@ -5255,7 +3528,6 @@ namespace CIR { } public class ElementAccess : Expression { - public ArrayList Arguments; public Expression Expr; public Location loc; @@ -5285,7 +3557,7 @@ namespace CIR { --i; Argument a = (Argument) Arguments [i]; - if (!a.Resolve (ec)) + if (!a.Resolve (ec, loc)) return false; } @@ -5303,7 +3575,7 @@ namespace CIR { // // I am experimenting with this pattern. // - if (Expr.Type == TypeManager.array_type) + if (Expr.Type.IsSubclassOf (TypeManager.array_type)) return (new ArrayAccess (this)).Resolve (ec); else return (new IndexerAccess (this)).Resolve (ec); @@ -5314,7 +3586,7 @@ namespace CIR { if (!CommonResolve (ec)) return null; - if (Expr.Type == TypeManager.array_type) + if (Expr.Type.IsSubclassOf (TypeManager.array_type)) return (new ArrayAccess (this)).ResolveLValue (ec, right_side); else return (new IndexerAccess (this)).ResolveLValue (ec, right_side); @@ -5326,7 +3598,10 @@ namespace CIR { } } - public class ArrayAccess : Expression, IStackStore { + // + // Implements array access + // + public class ArrayAccess : Expression, IAssignMethod { // // Points to our "data" repository // @@ -5336,38 +3611,155 @@ namespace CIR { { ea = ea_data; eclass = ExprClass.Variable; - - // - // FIXME: Figure out the type here - // } - Expression CommonResolve (EmitContext ec) - { - return this; - } - public override Expression DoResolve (EmitContext ec) { if (ea.Expr.ExprClass != ExprClass.Variable) { report118 (ea.loc, ea.Expr, "variable"); return null; } - - throw new Exception ("Implement me"); + + Type t = ea.Expr.Type; + + if (t.GetArrayRank () != ea.Arguments.Count){ + Report.Error (22, ea.loc, + "Incorrect number of indexes for array " + + " expected: " + t.GetArrayRank () + " got: " + + ea.Arguments.Count); + return null; + } + type = t.GetElementType (); + eclass = ExprClass.Variable; + + return this; } - public void Store (EmitContext ec) - { - throw new Exception ("Implement me !"); + // + // Emits the right opcode to load an object of Type `t' + // from an array of T + // + static public void EmitLoadOpcode (ILGenerator ig, Type type) + { + if (type == TypeManager.byte_type) + ig.Emit (OpCodes.Ldelem_I1); + else if (type == TypeManager.sbyte_type) + ig.Emit (OpCodes.Ldelem_U1); + else if (type == TypeManager.short_type) + ig.Emit (OpCodes.Ldelem_I2); + else if (type == TypeManager.ushort_type) + ig.Emit (OpCodes.Ldelem_U2); + else if (type == TypeManager.int32_type) + ig.Emit (OpCodes.Ldelem_I4); + else if (type == TypeManager.uint32_type) + ig.Emit (OpCodes.Ldelem_U4); + else if (type == TypeManager.uint64_type) + ig.Emit (OpCodes.Ldelem_I8); + else if (type == TypeManager.int64_type) + ig.Emit (OpCodes.Ldelem_I8); + else if (type == TypeManager.float_type) + ig.Emit (OpCodes.Ldelem_R4); + else if (type == TypeManager.double_type) + ig.Emit (OpCodes.Ldelem_R8); + else if (type == TypeManager.intptr_type) + ig.Emit (OpCodes.Ldelem_I); + else + ig.Emit (OpCodes.Ldelem_Ref); } + // + // Emits the right opcode to store an object of Type `t' + // from an array of T. + // + static public void EmitStoreOpcode (ILGenerator ig, Type t) + { + if (t == TypeManager.byte_type || t == TypeManager.sbyte_type) + ig.Emit (OpCodes.Stelem_I1); + else if (t == TypeManager.short_type || t == TypeManager.ushort_type) + ig.Emit (OpCodes.Stelem_I2); + else if (t == TypeManager.int32_type || t == TypeManager.uint32_type) + ig.Emit (OpCodes.Stelem_I4); + else if (t == TypeManager.int64_type || t == TypeManager.uint64_type) + ig.Emit (OpCodes.Stelem_I8); + else if (t == TypeManager.float_type) + ig.Emit (OpCodes.Stelem_R4); + else if (t == TypeManager.double_type) + ig.Emit (OpCodes.Stelem_R8); + else if (t == TypeManager.intptr_type) + ig.Emit (OpCodes.Stelem_I); + else + ig.Emit (OpCodes.Stelem_Ref); + } + public override void Emit (EmitContext ec) { - throw new Exception ("Implement me !"); + int rank = ea.Expr.Type.GetArrayRank (); + ILGenerator ig = ec.ig; + + ea.Expr.Emit (ec); + + foreach (Argument a in ea.Arguments) + a.Expr.Emit (ec); + + if (rank == 1) + EmitLoadOpcode (ig, type); + else { + ModuleBuilder mb = ec.TypeContainer.RootContext.ModuleBuilder; + Type [] args = new Type [ea.Arguments.Count]; + MethodInfo get; + + int i = 0; + + foreach (Argument a in ea.Arguments) + args [i++] = a.Type; + + get = mb.GetArrayMethod ( + ea.Expr.Type, "Get", + CallingConventions.HasThis | + CallingConventions.Standard, + type, args); + + ig.Emit (OpCodes.Call, get); + } } - } + public void EmitAssign (EmitContext ec, Expression source) + { + int rank = ea.Expr.Type.GetArrayRank (); + ILGenerator ig = ec.ig; + + ea.Expr.Emit (ec); + + foreach (Argument a in ea.Arguments) + a.Expr.Emit (ec); + + source.Emit (ec); + + Type t = source.Type; + if (rank == 1) + EmitStoreOpcode (ig, t); + else { + ModuleBuilder mb = ec.TypeContainer.RootContext.ModuleBuilder; + Type [] args = new Type [ea.Arguments.Count + 1]; + MethodInfo set; + + int i = 0; + + foreach (Argument a in ea.Arguments) + args [i++] = a.Type; + + args [i] = type; + + set = mb.GetArrayMethod ( + ea.Expr.Type, "Set", + CallingConventions.HasThis | + CallingConventions.Standard, + TypeManager.void_type, args); + + ig.Emit (OpCodes.Call, set); + } + } + } class Indexers { public ArrayList getters, setters; static Hashtable map; @@ -5425,7 +3817,10 @@ namespace CIR { return ix; } } - + + // + // Expressions that represent an indexer call. + // public class IndexerAccess : Expression, IAssignMethod { // // Points to our "data" repository @@ -5441,11 +3836,6 @@ namespace CIR { eclass = ExprClass.Value; } - public bool VerifyAssignable (Expression source) - { - throw new Exception ("Implement me!"); - } - public override Expression DoResolve (EmitContext ec) { Type indexer_type = ea.Expr.Type; @@ -5459,7 +3849,11 @@ namespace CIR { if (ilist == null) ilist = Indexers.GetIndexersForType ( indexer_type, ec.TypeContainer.RootContext.TypeManager, ea.loc); - + + + // + // Step 2: find the proper match + // if (ilist != null && ilist.getters != null && ilist.getters.Count > 0) get = (MethodInfo) Invocation.OverloadResolve ( ec, new MethodGroupExpr (ilist.getters), ea.Arguments, ea.loc); @@ -5468,11 +3862,11 @@ namespace CIR { Report.Error (154, ea.loc, "indexer can not be used in this context, because " + "it lacks a `get' accessor"); - return null; + return null; } - + type = get.ReturnType; - eclass = ExprClass.Value; + eclass = ExprClass.IndexerAccess; return this; } @@ -5523,7 +3917,7 @@ namespace CIR { public class BaseAccess : Expression { - public enum BaseAccessType { + public enum BaseAccessType : byte { Member, Indexer }; @@ -5568,6 +3962,12 @@ namespace CIR { eclass = ExprClass.Value; } + public EmptyExpression (Type t) + { + type = t; + eclass = ExprClass.Value; + } + public override Expression DoResolve (EmitContext ec) { return this;