X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fexpression.cs;h=5cf7fdb86541dfc754c26b3f3b46d4565786a7e5;hb=8d510ba7f34bbe25a5c6df1046b15bf94ead6acb;hp=09c6a0b030c71b717e51ed408959d78839abffc0;hpb=60867ff34a93c8a91f29664f0b9bf5c5c1fc3f32;p=mono.git diff --git a/mcs/mcs/expression.cs b/mcs/mcs/expression.cs index 09c6a0b030c..5cf7fdb8654 100755 --- a/mcs/mcs/expression.cs +++ b/mcs/mcs/expression.cs @@ -7,1245 +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; 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, // Every Variable should implement LValue - Namespace, - Type, - MethodGroup, - PropertyAccess, - EventAccess, - IndexerAccess, - Nothing, - } - - // - // 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 (TypeContainer tc, int error, string s) - { - tc.RootContext.Report.Error (error, s); - } - - static protected void Error (TypeContainer tc, int error, Location l, string s) - { - tc.RootContext.Report.Error (error, l, s); - } - - // - // Utility wrapper routine for Warning, just to beautify the code - // - static protected void Warning (TypeContainer tc, int warning, string s) - { - tc.RootContext.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 TypeContainer.RootContext.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 (TypeContainer tc); - - - // - // Currently Resolve wraps DoResolve to perform sanity - // checking and assertion checking on what we expect from Resolve - // - - public Expression Resolve (TypeContainer tc) - { - Expression e = DoResolve (tc); - - if (e != 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 (TypeContainer tc, MemberInfo mi) - { - if (mi is EventInfo){ - return new EventExpr ((EventInfo) mi); - } else if (mi is FieldInfo){ - FieldInfo fi = (FieldInfo) mi; - - if (fi.IsLiteral){ - Expression e = Literalize (fi); - e.Resolve (tc); - - return e; - } else - return new FieldExpr (fi); - } else if (mi is PropertyInfo){ - return new PropertyExpr ((PropertyInfo) mi); - } 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 (TypeContainer tc, Type t, string name, - bool same_type, MemberTypes mt, BindingFlags bf) - { - if (same_type) - bf |= BindingFlags.NonPublic; - - MemberInfo [] mi = tc.RootContext.TypeManager.FindMembers ( - t, mt, bf, Type.FilterName, name); - - if (mi == null) - return null; - - if (mi.Length == 1 && !(mi [0] is MethodBase)) - return Expression.ExprClassFromMemberInfo (tc, mi [0]); - - for (int i = 0; i < mi.Length; i++) - if (!(mi [i] is MethodBase)){ - Error (tc, - -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 (TypeContainer tc, Type t, string name, - bool same_type) - { - return MemberLookup (tc, t, name, same_type, AllMemberTypes, AllBindingsFlags); - } - - // - // I am in general unhappy with this implementation. - // - // I need to revise this. - // - static public Expression ResolveMemberAccess (TypeContainer tc, string name) - { - Expression left_e = null; - int dot_pos = name.LastIndexOf ("."); - string left = name.Substring (0, dot_pos); - string right = name.Substring (dot_pos + 1); - Type t; - - if ((t = tc.LookupType (left, false)) != null) - left_e = new TypeExpr (t); - else { - // - // FIXME: IMplement: - - // Handle here: - // T.P Static property access (P) on Type T. - // e.P instance property access on instance e for P. - // p - // - } - - if (left_e == null){ - Error (tc, 246, "Can not find type or namespace `"+left+"'"); - return null; - } - - switch (left_e.ExprClass){ - case ExprClass.Type: - return MemberLookup (tc, - left_e.Type, right, - left_e.Type == tc.TypeBuilder); - - case ExprClass.Namespace: - case ExprClass.PropertyAccess: - case ExprClass.IndexerAccess: - case ExprClass.Variable: - case ExprClass.Value: - case ExprClass.Nothing: - case ExprClass.EventAccess: - case ExprClass.MethodGroup: - case ExprClass.Invalid: - throw new Exception ("Should have got the " + left_e.ExprClass + - " handled before"); - } - - return null; - } - - 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) { - Type [] interfaces = expr_type.FindInterfaces (Module.FilterTypeName, - target_type.FullName); - if (interfaces != null) - return new EmptyCast (expr, target_type); - } - - // 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 new EmptyCast (expr, target_type); - - - // from an array-type S to an array-type of type T - if (expr_type.IsArray && target_type.IsArray) { - - throw new Exception ("Implement array conversion"); - - } - - // from an array-type to System.Array - if (expr_type.IsArray && target_type.IsAssignableFrom (expr_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) - if (target_type.IsAssignableFrom (expr_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.cloneable_interface) - throw new Exception ("Implement conversion to System.ICloneable"); - - // from the null type to any reference-type. - // FIXME : How do we do this ? - - 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 (TypeContainer tc, Expression expr, Type target) - { - ArrayList args = new ArrayList (); - - args.Add (new Argument (expr, Argument.AType.Expression)); - - Console.WriteLine ("The InternalTypeConstructor is: " + expr); - Expression ne = new New (target.FullName, args, - new Location (-1)); - - return ne.Resolve (tc); - } - - // - // 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 (TypeContainer tc, Expression expr, - Type target_type, Location l) - { - 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 (tc, 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 (tc, 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 (tc, 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 (tc, 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 (tc, 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 (tc, 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 (tc, 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 (tc, 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; - } - - // - // User-defined implicit conversions - // - static public Expression ImplicitUserConversion (TypeContainer tc, Expression source, - Type target, Location l) - { - Expression mg1, mg2; - MethodBase method; - ArrayList arguments; - - mg1 = MemberLookup (tc, source.Type, "op_Implicit", false); - mg2 = MemberLookup (tc, target, "op_Implicit", false); - - MethodGroupExpr union = Invocation.MakeUnionSet (mg1, mg2); - - if (union != null) { - arguments = new ArrayList (); - arguments.Add (new Argument (source, Argument.AType.Expression)); - method = Invocation.OverloadResolve (tc, union, arguments, l, true); - - if (method != null) { - MethodInfo mi = (MethodInfo) method; - - if (mi.ReturnType == target) - return new UserImplicitCast (mi, arguments); - } - } - - // If we have a boolean type, we need to check for the True - // and False operators too. - - if (target == TypeManager.bool_type) { - - mg1 = MemberLookup (tc, source.Type, "op_True", false); - mg2 = MemberLookup (tc, target, "op_True", false); - - union = Invocation.MakeUnionSet (mg1, mg2); - - if (union == null) - return null; - - arguments = new ArrayList (); - arguments.Add (new Argument (source, Argument.AType.Expression)); - - method = Invocation.OverloadResolve (tc, union, arguments, l, true); - if (method != null) { - MethodInfo mi = (MethodInfo) method; - - if (mi.ReturnType == target) - return new UserImplicitCast (mi, arguments); - } - } - - 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 (TypeContainer tc, Expression expr, - Type target_type, Location l) - { - Type expr_type = expr.Type; - Expression e; - - if (expr_type == target_type) - return expr; - - e = ImplicitNumericConversion (tc, expr, target_type, l); - if (e != null) - return e; - - e = ImplicitReferenceConversion (expr, target_type); - if (e != null) - return e; - - e = ImplicitUserConversion (tc, expr, target_type, l); - 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 (TypeContainer tc, Expression expr, - Type target_type, Location l) - { - Type expr_type = expr.Type; - Expression e; - - if (expr_type == target_type) - return expr; - - e = ImplicitNumericConversion (tc, expr, target_type, l); - 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 (TypeContainer tc, Expression target, - Type type, Location l) - { - Expression e; - - e = ConvertImplicit (tc, target, type, l); - if (e != null) - return e; - - string msg = "Can not convert implicitly from `"+ - TypeManager.CSharpName (target.Type) + "' to `" + - TypeManager.CSharpName (type) + "'"; - - Error (tc, 29, l, msg); - - return null; - } + // + // 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 StaticCallExpr : ExpressionStatement { + ArrayList args; + MethodInfo mi; - // - // Performs the explicit numeric conversions - // - static Expression ConvertNumericExplicit (TypeContainer tc, Expression expr, - Type target_type) + StaticCallExpr (MethodInfo m, ArrayList a) { - 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 (tc, 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 - // - Console.WriteLine ("Ok, I am a double " + target_type); - 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 (tc, expr, target_type); - } - - // decimal is taken care of by the op_Explicit methods. + mi = m; + args = a; - return null; + type = m.ReturnType; + eclass = ExprClass.Value; } - // - // Implements Explicit Reference conversions - // - static Expression ConvertReferenceExplicit (TypeContainer tc, Expression expr, - Type target_type) + public override Expression DoResolve (EmitContext ec) { - Type expr_type = expr.Type; - bool target_is_value_type = target_type.IsValueType; - // - // From object to any reference type + // We are born fully resolved // - if (expr_type == TypeManager.object_type && !target_is_value_type) - return new ClassCast (expr, expr_type); - - return null; - } - - // - // Performs an explicit conversion of the expression `expr' whose - // type is expr.Type to `target_type'. - // - static public Expression ConvertExplicit (TypeContainer tc, Expression expr, - Type target_type) - { - Expression ne = ConvertImplicit (tc, expr, target_type, Location.Null); - - if (ne != null) - return ne; - - ne = ConvertNumericExplicit (tc, expr, target_type); - if (ne != null) - return ne; - - ne = ConvertReferenceExplicit (tc, expr, target_type); - if (ne != null) - return ne; - - 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 (TypeContainer tc, Location l, Expression expr, string expected) - { - string kind = "Unknown"; - - if (expr != null) - kind = ExprClassName (expr.ExprClass); - - Error (tc, 118, l, "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); - } - - // - // 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". - // - // - - 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 (TypeContainer tc) - { - // This should never be invoked, we are born in fully - // initialized state. - return this; } public override void Emit (EmitContext ec) { - 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 { - - public BoxedCast (Expression expr) - : base (expr, TypeManager.object_type) - { - } + if (args != null) + Invocation.EmitArguments (ec, mi, args); - public override Expression DoResolve (TypeContainer tc) - { - // This should never be invoked, we are born in fully - // initialized state. - - return this; + ec.ig.Emit (OpCodes.Call, mi); + return; } - - public override void Emit (EmitContext ec) - { - base.Emit (ec); - ec.ig.Emit (OpCodes.Box, child.Type); - } - } - - // - // 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; - public OpcodeCast (Expression child, Type return_type, OpCode op) - : base (child, return_type) - - { - this.op = op; - second_valid = false; - } - - public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2) - : base (child, return_type) - + static public Expression MakeSimpleCall (EmitContext ec, MethodGroupExpr mg, + Expression e, Location loc) { - this.op = op; - this.op2 = op2; - second_valid = true; - } - - public override Expression DoResolve (TypeContainer tc) - { - // 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); - - if (second_valid) - ec.ig.Emit (op2); - } - - } - - // - // 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) + ArrayList args; + MethodBase method; - { - } + args = new ArrayList (1); + args.Add (new Argument (e, Argument.AType.Expression)); + method = Invocation.OverloadResolve (ec, (MethodGroupExpr) mg, args, loc); - public override Expression DoResolve (TypeContainer tc) - { - // This should never be invoked, we are born in fully - // initialized state. + if (method == null) + return null; - return this; + return new StaticCallExpr ((MethodInfo) method, args); } - public override void Emit (EmitContext ec) + public override void EmitStatement (EmitContext ec) { - base.Emit (ec); - - ec.ig.Emit (OpCodes.Castclass, type); - } - + Emit (ec); + if (type != TypeManager.void_type) + ec.ig.Emit (OpCodes.Pop); + } } // @@ -1257,24 +84,21 @@ namespace CIR { // ExpressionStatement becuase the pre/post increment/decrement // operators can be used in a statement context. // - public class Unary : ExpressionStatement { - public enum Operator { - Addition, Subtraction, Negate, BitComplement, - Indirection, AddressOf, PreIncrement, - PreDecrement, PostIncrement, PostDecrement + public class Unary : Expression { + public enum Operator : byte { + UnaryPlus, UnaryNegation, LogicalNot, OnesComplement, + Indirection, AddressOf, } Operator oper; Expression expr; - ArrayList Arguments; - MethodBase method; - Location location; + Location loc; public Unary (Operator op, Expression expr, Location loc) { this.oper = op; this.expr = expr; - this.location = loc; + this.loc = loc; } public Expression Expr { @@ -1303,64 +127,52 @@ namespace CIR { string OperName () { switch (oper){ - case Operator.Addition: + case Operator.UnaryPlus: return "+"; - case Operator.Subtraction: + case Operator.UnaryNegation: return "-"; - case Operator.Negate: + case Operator.LogicalNot: return "!"; - case Operator.BitComplement: + case Operator.OnesComplement: return "~"; case Operator.AddressOf: return "&"; case Operator.Indirection: return "*"; - case Operator.PreIncrement : case Operator.PostIncrement : - return "++"; - case Operator.PreDecrement : case Operator.PostDecrement : - return "--"; } return oper.ToString (); } - Expression ForceConversion (TypeContainer tc, Expression expr, Type target_type) + void error23 (Type t) { - if (expr.Type == target_type) - return expr; - - return ConvertImplicit (tc, expr, target_type, new Location (-1)); + Report.Error ( + 23, loc, "Operator " + OperName () + + " cannot be applied to operand of type `" + + TypeManager.CSharpName (t) + "'"); } - void report23 (Report r, Type t) + static Expression TryReduceNegative (Expression expr) { - r.Error (23, "Operator " + OperName () + " cannot be applied to operand of type `" + - TypeManager.CSharpName (t) + "'"); - } + 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); - // - // 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); + return e; } - - Expression ResolveOperator (TypeContainer tc) + + Expression ResolveOperator (EmitContext ec) { Type expr_type = expr.Type; @@ -1369,31 +181,24 @@ 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; - - mg = MemberLookup (tc, expr_type, op_name, false); + + op_name = "op_" + oper; - if (mg == null && expr_type != TypeManager.object_type) - mg = MemberLookup (tc, expr_type.BaseType, op_name, false); + 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) { - Arguments = new ArrayList (); - Arguments.Add (new Argument (expr, Argument.AType.Expression)); - - method = Invocation.OverloadResolve (tc, (MethodGroupExpr) mg, - Arguments, location); - if (method != null) { - MethodInfo mi = (MethodInfo) method; + Expression e = StaticCallExpr.MakeSimpleCall ( + ec, (MethodGroupExpr) mg, expr, loc); - type = mi.ReturnType; - return this; + if (e == null){ + error23 (expr_type); + return null; } + + return e; } // @@ -1401,14 +206,14 @@ namespace CIR { // // Only perform numeric promotions on: - // +, -, ++, -- + // +, - if (expr_type == null) return null; - if (oper == Operator.Negate){ + if (oper == Operator.LogicalNot){ if (expr_type != TypeManager.bool_type) { - report23 (tc.RootContext.Report, expr.Type); + error23 (expr.Type); return null; } @@ -1416,20 +221,20 @@ namespace CIR { return this; } - if (oper == Operator.BitComplement) { + if (oper == Operator.OnesComplement) { if (!((expr_type == TypeManager.int32_type) || (expr_type == TypeManager.uint32_type) || (expr_type == TypeManager.int64_type) || (expr_type == TypeManager.uint64_type) || (expr_type.IsSubclassOf (TypeManager.enum_type)))){ - report23 (tc.RootContext.Report, expr.Type); + error23 (expr.Type); return null; } type = expr_type; return this; } - if (oper == Operator.Addition) { + if (oper == Operator.UnaryPlus) { // // A plus in front of something is just a no-op, so return the child. // @@ -1444,7 +249,7 @@ namespace CIR { // double operator- (double d) // decimal operator- (decimal d) // - if (oper == Operator.Subtraction){ + if (oper == Operator.UnaryNegation){ // // Fold a "- Constant" into a negative constant // @@ -1454,19 +259,10 @@ 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 (tc); + e = e.Resolve (ec); return e; } @@ -1481,8 +277,6 @@ namespace CIR { // It is also not clear if we should convert to Float // or Double initially. // - Location l = new Location (-1); - if (expr_type == TypeManager.uint32_type){ // // FIXME: handle exception to this rule that @@ -1490,7 +284,7 @@ namespace CIR { // bt written as a decimal interger literal // type = TypeManager.int64_type; - expr = ConvertImplicit (tc, expr, type, l); + expr = ConvertImplicit (ec, expr, type, loc); return this; } @@ -1500,212 +294,379 @@ namespace CIR { // -92233720368547758087 (-2^63) to be written as // decimal integer literal. // - report23 (tc.RootContext.Report, expr_type); + error23 (expr_type); return null; } - e = ConvertImplicit (tc, expr, TypeManager.int32_type, l); + e = ConvertImplicit (ec, expr, TypeManager.int32_type, loc); if (e != null){ expr = e; type = e.Type; return this; } - e = ConvertImplicit (tc, expr, TypeManager.int64_type, l); + e = ConvertImplicit (ec, expr, TypeManager.int64_type, loc); if (e != null){ expr = e; type = e.Type; return this; } - e = ConvertImplicit (tc, expr, TypeManager.double_type, l); + e = ConvertImplicit (ec, expr, TypeManager.double_type, loc); if (e != null){ expr = e; type = e.Type; return this; } - report23 (tc.RootContext.Report, expr_type); + error23 (expr_type); 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){ - // - // FIXME: Verify that we have both get and set methods - // - throw new Exception ("Implement me"); - } else { - report118 (tc, location, expr, - "variable, indexer or property access"); - } - } - if (oper == Operator.AddressOf){ if (expr.ExprClass != ExprClass.Variable){ - Error (tc, 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 (tc, 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 (TypeContainer tc) + public override Expression DoResolve (EmitContext ec) { - expr = expr.Resolve (tc); - + expr = expr.Resolve (ec); + if (expr == null) return null; eclass = ExprClass.Value; - return ResolveOperator (tc); + return ResolveOperator (ec); } public override void Emit (EmitContext ec) { ILGenerator ig = ec.ig; Type expr_type = expr.Type; - - if (method != null) { - - // Note that operators are static anyway - - if (Arguments != null) - Invocation.EmitArguments (ec, method, 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){ - ((LValue) expr).Store (ec); - } - return; - } switch (oper) { - case Operator.Addition: + case Operator.UnaryPlus: throw new Exception ("This should be caught by Resolve"); - case Operator.Subtraction: + case Operator.UnaryNegation: expr.Emit (ec); ig.Emit (OpCodes.Neg); break; - case Operator.Negate: + case Operator.LogicalNot: expr.Emit (ec); ig.Emit (OpCodes.Ldc_I4_0); ig.Emit (OpCodes.Ceq); break; - case Operator.BitComplement: + case Operator.OnesComplement: expr.Emit (ec); ig.Emit (OpCodes.Not); break; case Operator.AddressOf: - ((LValue)expr).AddressOf (ec); + ((IMemoryLocation)expr).AddressOf (ec); break; 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); - ((LValue) 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: - if (expr.ExprClass == 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); - ((LValue) expr).Store (ec); } else { - throw new Exception ("Handle Indexers and Properties here"); + 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 { @@ -1714,7 +675,7 @@ namespace CIR { Expression expr; Type probe_type; - public enum Operator { + public enum Operator : byte { Is, As } @@ -1731,14 +692,14 @@ namespace CIR { } } - public override Expression DoResolve (TypeContainer tc) + public override Expression DoResolve (EmitContext ec) { - probe_type = tc.LookupType (ProbeType, false); + probe_type = ec.TypeContainer.LookupType (ProbeType, false); if (probe_type == null) return null; - expr = expr.Resolve (tc); + expr = expr.Resolve (ec); type = TypeManager.bool_type; eclass = ExprClass.Value; @@ -1771,11 +732,13 @@ namespace CIR { public class Cast : Expression { string target_type; Expression expr; + Location loc; - public Cast (string cast_type, Expression expr) + public Cast (string cast_type, Expression expr, Location loc) { this.target_type = cast_type; this.expr = expr; + this.loc = loc; } public string TargetType { @@ -1793,19 +756,19 @@ namespace CIR { } } - public override Expression DoResolve (TypeContainer tc) + public override Expression DoResolve (EmitContext ec) { - expr = expr.Resolve (tc); + expr = expr.Resolve (ec); if (expr == null) return null; - type = tc.LookupType (target_type, false); + type = ec.TypeContainer.LookupType (target_type, false); eclass = ExprClass.Value; if (type == null) return null; - expr = ConvertExplicit (tc, expr, type); + expr = ConvertExplicit (ec, expr, type, loc); return expr; } @@ -1820,7 +783,7 @@ namespace CIR { } public class Binary : Expression { - public enum Operator { + public enum Operator : byte { Multiply, Division, Modulus, Addition, Subtraction, LeftShift, RightShift, @@ -1837,7 +800,7 @@ namespace CIR { Expression left, right; MethodBase method; ArrayList Arguments; - Location location; + Location loc; public Binary (Operator oper, Expression left, Expression right, Location loc) @@ -1845,7 +808,7 @@ namespace CIR { this.oper = oper; this.left = left; this.right = right; - this.location = loc; + this.loc = loc; } public Operator Oper { @@ -1923,19 +886,19 @@ namespace CIR { return oper.ToString (); } - Expression ForceConversion (TypeContainer tc, Expression expr, Type target_type) + Expression ForceConversion (EmitContext ec, Expression expr, Type target_type) { if (expr.Type == target_type) return expr; - return ConvertImplicit (tc, expr, target_type, new Location (-1)); + return ConvertImplicit (ec, expr, target_type, new Location (-1)); } // // Note that handling the case l == Decimal || r == Decimal // is taken care of by the Step 1 Operator Overload resolution. // - void DoNumericPromotions (TypeContainer tc, Type l, Type r) + bool DoNumericPromotions (EmitContext ec, Type l, Type r) { if (l == TypeManager.double_type || r == TypeManager.double_type){ // @@ -1943,9 +906,9 @@ namespace CIR { // conveted to type double. // if (r != TypeManager.double_type) - right = ConvertImplicit (tc, right, TypeManager.double_type, location); + right = ConvertImplicit (ec, right, TypeManager.double_type, loc); if (l != TypeManager.double_type) - left = ConvertImplicit (tc, left, TypeManager.double_type, location); + left = ConvertImplicit (ec, left, TypeManager.double_type, loc); type = TypeManager.double_type; } else if (l == TypeManager.float_type || r == TypeManager.float_type){ @@ -1954,9 +917,9 @@ namespace CIR { // converd to type float. // if (r != TypeManager.double_type) - right = ConvertImplicit (tc, right, TypeManager.float_type, location); + right = ConvertImplicit (ec, right, TypeManager.float_type, loc); if (l != TypeManager.double_type) - left = ConvertImplicit (tc, left, TypeManager.float_type, location); + left = ConvertImplicit (ec, left, TypeManager.float_type, loc); type = TypeManager.float_type; } else if (l == TypeManager.uint64_type || r == TypeManager.uint64_type){ Expression e; @@ -1989,7 +952,7 @@ namespace CIR { (other == TypeManager.int64_type)){ string oper = OperName (); - Error (tc, 34, location, "Operator `" + OperName () + Error (34, loc, "Operator `" + OperName () + "' is ambiguous on operands of type `" + TypeManager.CSharpName (l) + "' " + "and `" + TypeManager.CSharpName (r) @@ -2002,9 +965,9 @@ namespace CIR { // to type long. // if (l != TypeManager.int64_type) - left = ConvertImplicit (tc, left, TypeManager.int64_type, location); + left = ConvertImplicit (ec, left, TypeManager.int64_type, loc); if (r != TypeManager.int64_type) - right = ConvertImplicit (tc, right, TypeManager.int64_type, location); + right = ConvertImplicit (ec, right, TypeManager.int64_type, loc); type = TypeManager.int64_type; } else if (l == TypeManager.uint32_type || r == TypeManager.uint32_type){ @@ -2023,70 +986,81 @@ namespace CIR { if ((other == TypeManager.sbyte_type) || (other == TypeManager.short_type) || (other == TypeManager.int32_type)){ - left = ForceConversion (tc, left, TypeManager.int64_type); - right = ForceConversion (tc, right, TypeManager.int64_type); + left = ForceConversion (ec, left, TypeManager.int64_type); + right = ForceConversion (ec, right, TypeManager.int64_type); type = TypeManager.int64_type; } else { // // if either operand is of type uint, the other // operand is converd to type uint // - left = ForceConversion (tc, left, TypeManager.uint32_type); - right = ForceConversion (tc, right, TypeManager.uint32_type); + left = ForceConversion (ec, left, TypeManager.uint32_type); + right = ForceConversion (ec, right, TypeManager.uint32_type); type = TypeManager.uint32_type; } } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){ if (l != TypeManager.decimal_type) - left = ConvertImplicit (tc, left, TypeManager.decimal_type, location); + left = ConvertImplicit (ec, left, TypeManager.decimal_type, loc); if (r != TypeManager.decimal_type) - right = ConvertImplicit (tc, right, TypeManager.decimal_type, location); + right = ConvertImplicit (ec, right, TypeManager.decimal_type, loc); type = TypeManager.decimal_type; } else { - left = ForceConversion (tc, left, TypeManager.int32_type); - right = ForceConversion (tc, right, TypeManager.int32_type); + Expression l_tmp, r_tmp; + + l_tmp = ForceConversion (ec, left, TypeManager.int32_type); + if (l_tmp == null) + return false; + + 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 (TypeContainer tc) + void error19 () { - Error (tc, 19, + Error (19, loc, "Operator " + OperName () + " cannot be applied to operands of type `" + TypeManager.CSharpName (left.Type) + "' and `" + TypeManager.CSharpName (right.Type) + "'"); } - Expression CheckShiftArguments (TypeContainer tc) + Expression CheckShiftArguments (EmitContext ec) { Expression e; Type l = left.Type; Type r = right.Type; - e = ForceConversion (tc, right, TypeManager.int32_type); + e = ForceConversion (ec, right, TypeManager.int32_type); if (e == null){ - error19 (tc); + error19 (); return null; } right = e; - Location loc = location; - - if (((e = ConvertImplicit (tc, left, TypeManager.int32_type, loc)) != null) || - ((e = ConvertImplicit (tc, left, TypeManager.uint32_type, loc)) != null) || - ((e = ConvertImplicit (tc, left, TypeManager.int64_type, loc)) != null) || - ((e = ConvertImplicit (tc, left, TypeManager.uint64_type, loc)) != null)){ + if (((e = ConvertImplicit (ec, left, TypeManager.int32_type, loc)) != null) || + ((e = ConvertImplicit (ec, left, TypeManager.uint32_type, loc)) != null) || + ((e = ConvertImplicit (ec, left, TypeManager.int64_type, loc)) != null) || + ((e = ConvertImplicit (ec, left, TypeManager.uint64_type, loc)) != null)){ left = e; type = e.Type; return this; } - error19 (tc); + error19 (); return null; } - Expression ResolveOperator (TypeContainer tc) + Expression ResolveOperator (EmitContext ec) { Type l = left.Type; Type r = right.Type; @@ -2098,32 +1072,32 @@ namespace CIR { string op = "op_" + oper; - left_expr = MemberLookup (tc, l, op, false); - - if (left_expr == null && l != TypeManager.object_type) - left_expr = MemberLookup (tc, l.BaseType, op, false); + left_expr = MemberLookup (ec, l, op, false, loc); + if (left_expr == null && l.BaseType != null) + left_expr = MemberLookup (ec, l.BaseType, op, false, loc); - right_expr = MemberLookup (tc, r, op, false); - if (right_expr != null && r != TypeManager.object_type) - right_expr = MemberLookup (tc, r.BaseType, op, false); + right_expr = MemberLookup (ec, r, op, false, loc); + if (right_expr == null && r.BaseType != null) + right_expr = MemberLookup (ec, r.BaseType, op, false, loc); - MethodGroupExpr union = Invocation.MakeUnionSet (left_expr, right_expr); - + if (union != null) { Arguments = new ArrayList (); Arguments.Add (new Argument (left, Argument.AType.Expression)); Arguments.Add (new Argument (right, Argument.AType.Expression)); - - method = Invocation.OverloadResolve (tc, union, Arguments, location); + + method = Invocation.OverloadResolve (ec, union, Arguments, loc); if (method != null) { MethodInfo mi = (MethodInfo) method; - type = mi.ReturnType; return this; + } else { + error19 (); + return null; } } - + // // Step 2: Default operations on CLI native types. // @@ -2137,13 +1111,20 @@ 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 { // string + object method = TypeManager.string_concat_object_object; - right = ConvertImplicit (tc, right, - TypeManager.object_type, location); + right = ConvertImplicit (ec, right, + TypeManager.object_type, loc); } type = TypeManager.string_type; @@ -2160,7 +1141,7 @@ namespace CIR { Arguments.Add (new Argument (left, Argument.AType.Expression)); Arguments.Add (new Argument (right, Argument.AType.Expression)); - left = ConvertImplicit (tc, left, TypeManager.object_type, location); + left = ConvertImplicit (ec, left, TypeManager.object_type, loc); type = TypeManager.string_type; return this; @@ -2172,25 +1153,66 @@ namespace CIR { } if (oper == Operator.LeftShift || oper == Operator.RightShift) - return CheckShiftArguments (tc); + return CheckShiftArguments (ec); if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){ - if (l != TypeManager.bool_type || r != TypeManager.bool_type) - error19 (tc); + 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 (tc, 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; + if (oper == Operator.BitwiseAnd || oper == Operator.BitwiseOr || oper == Operator.ExclusiveOr){ @@ -2198,7 +1220,7 @@ namespace CIR { (l == TypeManager.uint32_type) || (l == TypeManager.int64_type) || (l == TypeManager.uint64_type))){ - error19 (tc); + error19 (); return null; } type = l; @@ -2212,14 +1234,14 @@ namespace CIR { oper == Operator.GreaterThan){ type = TypeManager.bool_type; } - + return this; } - public override Expression DoResolve (TypeContainer tc) + public override Expression DoResolve (EmitContext ec) { - left = left.Resolve (tc); - right = right.Resolve (tc); + left = left.Resolve (ec); + right = right.Resolve (ec); if (left == null || right == null) return null; @@ -2227,15 +1249,15 @@ namespace CIR { if (left.Type == null) throw new Exception ( "Resolve returned non null, but did not set the type! (" + - left + ")"); + left + ") at Line: " + loc.Row); if (right.Type == null) throw new Exception ( "Resolve returned non null, but did not set the type! (" + - right + ")"); + right + ") at Line: "+ loc.Row); eclass = ExprClass.Value; - return ResolveOperator (tc); + return ResolveOperator (ec); } public bool IsBranchable () @@ -2462,18 +1484,42 @@ 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 { Expression expr, trueExpr, falseExpr; - Location l; + Location loc; public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l) { this.expr = expr; this.trueExpr = trueExpr; this.falseExpr = falseExpr; - this.l = l; + this.loc = l; } public Expression Expr { @@ -2494,20 +1540,20 @@ namespace CIR { } } - public override Expression DoResolve (TypeContainer tc) + public override Expression DoResolve (EmitContext ec) { - expr = expr.Resolve (tc); + expr = expr.Resolve (ec); if (expr.Type != TypeManager.bool_type) expr = Expression.ConvertImplicitRequired ( - tc, expr, TypeManager.bool_type, l); + ec, expr, TypeManager.bool_type, loc); - trueExpr = trueExpr.Resolve (tc); - falseExpr = falseExpr.Resolve (tc); + trueExpr = trueExpr.Resolve (ec); + falseExpr = falseExpr.Resolve (ec); if (expr == null || trueExpr == null || falseExpr == null) return null; - + if (trueExpr.Type == falseExpr.Type) type = trueExpr.Type; else { @@ -2517,15 +1563,15 @@ namespace CIR { // First, if an implicit conversion exists from trueExpr // to falseExpr, then the result type is of type falseExpr.Type // - conv = ConvertImplicit (tc, trueExpr, falseExpr.Type, l); + conv = ConvertImplicit (ec, trueExpr, falseExpr.Type, loc); if (conv != null){ type = falseExpr.Type; trueExpr = conv; - } else if ((conv = ConvertImplicit (tc,falseExpr,trueExpr.Type,l)) != null){ + } else if ((conv = ConvertImplicit(ec, falseExpr,trueExpr.Type,loc))!= null){ type = trueExpr.Type; falseExpr = conv; } else { - Error (tc, 173, l, "The type of the conditional expression can " + + Error (173, loc, "The type of the conditional expression can " + "not be computed because there is no implicit conversion" + " from `" + TypeManager.CSharpName (trueExpr.Type) + "'" + " and `" + TypeManager.CSharpName (falseExpr.Type) + "'"); @@ -2533,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; } @@ -2551,134 +1606,30 @@ namespace CIR { falseExpr.Emit (ec); ig.MarkLabel (end_target); } - } - - public class SimpleName : Expression { - public readonly string Name; - public readonly Location Location; - - public SimpleName (string name, Location l) - { - Name = name; - Location = l; - } - - // - // Checks whether we are trying to access an instance - // property, method or field from a static body. - // - Expression MemberStaticCheck (Report r, Expression e) - { - if (e is FieldExpr){ - FieldInfo fi = ((FieldExpr) e).FieldInfo; - - if (!fi.IsStatic){ - r.Error (120, - "An object reference is required " + - "for the non-static field `"+Name+"'"); - return null; - } - } else if (e is MethodGroupExpr){ - // FIXME: Pending reorganization of MemberLookup - // Basically at this point we should have the - // best match already selected for us, and - // we should only have to check a *single* - // Method for its static on/off bit. - return e; - } else if (e is PropertyExpr){ - if (!((PropertyExpr) e).IsStatic){ - r.Error (120, - "An object reference is required " + - "for the non-static property access `"+ - 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. - // - Expression ResolveSimpleName (TypeContainer tc) + public override Expression Reduce (EmitContext ec) { - Expression e; - Report r = tc.RootContext.Report; - - e = MemberLookup (tc, tc.TypeBuilder, Name, true); - if (e != null){ - if (e is TypeExpr) - return e; - else if (e is FieldExpr){ - FieldExpr fe = (FieldExpr) e; - - if (!fe.FieldInfo.IsStatic) - fe.Instance = new This (); - } - - if ((tc.ModFlags & Modifiers.STATIC) != 0) - return MemberStaticCheck (r, e); - else - return e; - } + expr = expr.Reduce (ec); + trueExpr = trueExpr.Reduce (ec); + falseExpr = falseExpr.Reduce (ec); - // - // Do step 3 of the Simple Name resolution. - // - // FIXME: implement me. + if (!(expr is Literal && trueExpr is Literal && falseExpr is Literal)) + return this; - Error (tc, 103, Location, "The name `" + Name + "' does not exist in the class `" + - tc.Name + "'"); + BoolLiteral bl = (BoolLiteral) expr; - return null; - } - - // - // SimpleName needs to handle a multitude of cases: - // - // simple_names and qualified_identifiers are placed on - // the tree equally. - // - public override Expression DoResolve (TypeContainer tc) - { - if (Name.IndexOf (".") != -1) - return ResolveMemberAccess (tc, Name); + if (bl.Value) + return trueExpr; else - return ResolveSimpleName (tc); - } - - public override void Emit (EmitContext ec) - { - throw new Exception ("SimpleNames should be gone from the tree"); + return falseExpr; } } - // - // A simple interface that should be implemeneted by LValues - // - public interface LValue { - - // - // 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); - - // - // The AddressOf method should generate code that loads - // the address of the LValue and leaves it on the stack - // - void AddressOf (EmitContext ec); - } - - public class LocalVariableReference : Expression, LValue { + public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation { public readonly string Name; public readonly Block Block; + + VariableInfo variable_info; public LocalVariableReference (Block block, string name) { @@ -2689,13 +1640,15 @@ namespace CIR { public VariableInfo VariableInfo { get { - return Block.GetVariableInfo (Name); + if (variable_info == null) + variable_info = Block.GetVariableInfo (Name); + return variable_info; } } - public override Expression DoResolve (TypeContainer tc) + public override Expression DoResolve (EmitContext ec) { - VariableInfo vi = Block.GetVariableInfo (Name); + VariableInfo vi = VariableInfo; type = vi.VariableType; return this; @@ -2708,7 +1661,7 @@ namespace CIR { int idx = vi.Idx; vi.Used = true; - + switch (idx){ case 0: ig.Emit (OpCodes.Ldloc_0); @@ -2717,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); @@ -2734,14 +1687,9 @@ namespace CIR { break; } } - - public void Store (EmitContext ec) + + public static void Store (ILGenerator ig, int idx) { - ILGenerator ig = ec.ig; - VariableInfo vi = VariableInfo; - int idx = vi.Idx; - - vi.Assigned = true; switch (idx){ case 0: ig.Emit (OpCodes.Stloc_0); @@ -2768,6 +1716,22 @@ namespace CIR { } } + public void EmitAssign (EmitContext ec, Expression source) + { + ILGenerator ig = ec.ig; + VariableInfo vi = VariableInfo; + + vi.Assigned = true; + + 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; @@ -2783,10 +1747,11 @@ namespace CIR { } } - public class ParameterReference : Expression, LValue { + public class ParameterReference : Expression, IAssignMethod, IMemoryLocation { public readonly Parameters Pars; public readonly String Name; public readonly int Idx; + int arg_idx; public ParameterReference (Parameters pars, int idx, string name) { @@ -2796,38 +1761,44 @@ namespace CIR { eclass = ExprClass.Variable; } - public override Expression DoResolve (TypeContainer tc) + public override Expression DoResolve (EmitContext ec) { - Type [] types = Pars.GetParameterInfo (tc); + Type [] types = Pars.GetParameterInfo (ec.TypeContainer); type = types [Idx]; + arg_idx = Idx; + if (!ec.IsStatic) + arg_idx++; + return this; } public override void Emit (EmitContext ec) { - if (Idx <= 255) - ec.ig.Emit (OpCodes.Ldarg_S, (byte) Idx); + if (arg_idx <= 255) + ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx); else - ec.ig.Emit (OpCodes.Ldarg, Idx); + ec.ig.Emit (OpCodes.Ldarg, arg_idx); } - public void Store (EmitContext ec) + public void EmitAssign (EmitContext ec, Expression source) { - if (Idx <= 255) - ec.ig.Emit (OpCodes.Starg_S, (byte) Idx); + source.Emit (ec); + + if (arg_idx <= 255) + ec.ig.Emit (OpCodes.Starg_S, (byte) arg_idx); else - ec.ig.Emit (OpCodes.Starg, Idx); + ec.ig.Emit (OpCodes.Starg, arg_idx); } public void AddressOf (EmitContext ec) { - if (Idx <= 255) - ec.ig.Emit (OpCodes.Ldarga_S, (byte) Idx); + if (arg_idx <= 255) + ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx); else - ec.ig.Emit (OpCodes.Ldarga, Idx); + ec.ig.Emit (OpCodes.Ldarga, arg_idx); } } @@ -2835,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; - Expression expr; - + 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 { @@ -2860,16 +1831,53 @@ namespace CIR { } } - public bool Resolve (TypeContainer tc) + 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 (tc); + 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); } } @@ -2878,8 +1886,8 @@ namespace CIR { // public class Invocation : ExpressionStatement { public readonly ArrayList Arguments; - public readonly Location Location; - + Location loc; + Expression expr; MethodBase method = null; @@ -2901,7 +1909,7 @@ namespace CIR { { this.expr = expr; Arguments = arguments; - Location = l; + loc = l; } public Expression Expr { @@ -2914,17 +1922,17 @@ namespace CIR { // Returns the Parameters (a ParameterData interface) for the // Method `mb' // - static ParameterData GetParameterData (MethodBase mb) + public static ParameterData GetParameterData (MethodBase mb) { object pd = method_parameter_cache [mb]; - + object ip; + if (pd != null) return (ParameterData) pd; - if (mb is MethodBuilder || mb is ConstructorBuilder){ - MethodCore mc = TypeContainer.LookupMethodByBuilder (mb); - - InternalParameters ip = mc.ParameterInfo; + + ip = TypeContainer.LookupParametersByBuilder (mb); + if (ip != null){ method_parameter_cache [mb] = ip; return (ParameterData) ip; @@ -2943,13 +1951,13 @@ namespace CIR { // // FIXME: we could implement a cache here. // - static bool ConversionExists (TypeContainer tc, Type from, Type to) + static bool ConversionExists (EmitContext ec, Type from, Type to, Location loc) { // Locate user-defined implicit operators Expression mg; - mg = MemberLookup (tc, to, "op_Implicit", false); + mg = MemberLookup (ec, to, "op_Implicit", false, loc); if (mg != null) { MethodGroupExpr me = (MethodGroupExpr) mg; @@ -2964,7 +1972,7 @@ namespace CIR { } } - mg = MemberLookup (tc, from, "op_Implicit", false); + mg = MemberLookup (ec, from, "op_Implicit", false, loc); if (mg != null) { MethodGroupExpr me = (MethodGroupExpr) mg; @@ -2987,10 +1995,10 @@ namespace CIR { // Returns : 1 if a->p is better // 0 if a->q or neither is better // - static int BetterConversion (TypeContainer tc, Argument a, Type p, Type q, bool use_standard) + 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) @@ -3068,9 +2076,9 @@ namespace CIR { Expression tmp; if (use_standard) - tmp = ConvertImplicitStandard (tc, argument_expr, p, Location.Null); + tmp = ConvertImplicitStandard (ec, argument_expr, p, loc); else - tmp = ConvertImplicit (tc, argument_expr, p, Location.Null); + tmp = ConvertImplicit (ec, argument_expr, p, loc); if (tmp != null) return 1; @@ -3079,8 +2087,8 @@ namespace CIR { } - if (ConversionExists (tc, p, q) == true && - ConversionExists (tc, q, p) == false) + if (ConversionExists (ec, p, q, loc) == true && + ConversionExists (ec, q, p, loc) == false) return 1; if (p == TypeManager.sbyte_type) @@ -3109,9 +2117,9 @@ namespace CIR { // 0 if candidate ain't better // 1 if candidate is better than the current best match // - static int BetterFunction (TypeContainer tc, ArrayList args, + static int BetterFunction (EmitContext ec, ArrayList args, MethodBase candidate, MethodBase best, - bool use_standard) + bool use_standard, Location loc) { ParameterData candidate_pd = GetParameterData (candidate); ParameterData best_pd; @@ -3134,8 +2142,8 @@ namespace CIR { Argument a = (Argument) args [j]; x = BetterConversion ( - tc, a, candidate_pd.ParameterType (j), null, - use_standard); + ec, a, candidate_pd.ParameterType (j), null, + use_standard, loc); if (x <= 0) break; @@ -3161,10 +2169,11 @@ namespace CIR { Argument a = (Argument) args [j]; - x = BetterConversion (tc, a, candidate_pd.ParameterType (j), - best_pd.ParameterType (j), use_standard); - y = BetterConversion (tc, a, best_pd.ParameterType (j), - candidate_pd.ParameterType (j), use_standard); + x = BetterConversion (ec, a, candidate_pd.ParameterType (j), + best_pd.ParameterType (j), use_standard, loc); + y = BetterConversion (ec, a, best_pd.ParameterType (j), + candidate_pd.ParameterType (j), use_standard, + loc); rating1 += x; rating2 += y; @@ -3183,13 +2192,16 @@ namespace CIR { { StringBuilder sb = new StringBuilder (mb.Name); ParameterData pd = GetParameterData (mb); - + + int count = pd.Count; sb.Append (" ("); - for (int i = pd.Count; i > 0;) { + + for (int i = count; i > 0; ) { i--; - sb.Append (TypeManager.CSharpName (pd.ParameterType (i))); + + sb.Append (pd.ParameterDesc (count - i - 1)); if (i != 0) - sb.Append (","); + sb.Append (", "); } sb.Append (")"); @@ -3198,37 +2210,154 @@ namespace CIR { public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2) { - - if (mg1 != null || mg2 != null) { - + MemberInfo [] miset; + MethodGroupExpr union; + + if (mg1 != null && mg2 != null) { + MethodGroupExpr left_set = null, right_set = null; int length1 = 0, length2 = 0; - if (mg1 != null) { - left_set = (MethodGroupExpr) mg1; - length1 = left_set.Methods.Length; - } + left_set = (MethodGroupExpr) mg1; + length1 = left_set.Methods.Length; + + right_set = (MethodGroupExpr) mg2; + length2 = right_set.Methods.Length; + + ArrayList common = new ArrayList (); - if (mg2 != null) { - right_set = (MethodGroupExpr) mg2; - length2 = right_set.Methods.Length; + for (int i = 0; i < left_set.Methods.Length; i++) { + for (int j = 0; j < right_set.Methods.Length; j++) { + if (left_set.Methods [i] == right_set.Methods [j]) + common.Add (left_set.Methods [i]); + } } - MemberInfo [] miset = new MemberInfo [length1 + length2]; - if (left_set != null) - left_set.Methods.CopyTo (miset, 0); - if (right_set != null) - right_set.Methods.CopyTo (miset, length1); + miset = new MemberInfo [length1 + length2 - common.Count]; + + left_set.Methods.CopyTo (miset, 0); + + int k = 0; + + for (int j = 0; j < right_set.Methods.Length; j++) + if (!common.Contains (right_set.Methods [j])) + miset [length1 + k++] = right_set.Methods [j]; + + union = new MethodGroupExpr (miset); + + return union; + + } else if (mg1 == null && mg2 != null) { + + MethodGroupExpr me = (MethodGroupExpr) mg2; + + miset = new MemberInfo [me.Methods.Length]; + me.Methods.CopyTo (miset, 0); + + union = new MethodGroupExpr (miset); + + return union; + + } else if (mg2 == null && mg1 != null) { + + MethodGroupExpr me = (MethodGroupExpr) mg1; + + miset = new MemberInfo [me.Methods.Length]; + me.Methods.CopyTo (miset, 0); + + union = new MethodGroupExpr (miset); - MethodGroupExpr union = new MethodGroupExpr (miset); + return union; + } + + 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--; - return union; - - } + Argument a = (Argument) arguments [i]; - return null; + 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) @@ -3242,14 +2371,14 @@ 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) // that is the best match of me on Arguments. // // - public static MethodBase OverloadResolve (TypeContainer tc, MethodGroupExpr me, + public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me, ArrayList Arguments, Location loc, bool use_standard) { @@ -3263,7 +2392,11 @@ namespace CIR { MethodBase candidate = me.Methods [i]; int x; - x = BetterFunction (tc, Arguments, candidate, method, use_standard); + // 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) continue; @@ -3278,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;) { @@ -3296,73 +2449,114 @@ 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 (tc, a_expr, parameter_type, - Location.Null); + conv = ConvertImplicitStandard (ec, a_expr, parameter_type, Location.Null); else - conv = ConvertImplicit (tc, 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 (tc, 1502, loc, - "The best overloaded match for method '" + FullMethodDesc (method) + + Error (1502, loc, + "The best overloaded match for method '" + FullMethodDesc (method)+ "' has some invalid arguments"); - Error (tc, 1503, loc, - "Argument " + (j+1) + - ": Cannot convert from '" + TypeManager.CSharpName (a_expr.Type) - + "' to '" + TypeManager.CSharpName (pd.ParameterType (j)) + "'"); + Error (1503, loc, + "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 (TypeContainer tc, MethodGroupExpr me, + + public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me, ArrayList Arguments, Location loc) { - return OverloadResolve (tc, me, Arguments, loc, false); + return OverloadResolve (ec, me, Arguments, loc, false); } - public override Expression DoResolve (TypeContainer tc) + public override Expression DoResolve (EmitContext ec) { // // First, resolve the expression that is used to // trigger the invocation // - this.expr = expr.Resolve (tc); - if (this.expr == null) + expr = expr.Resolve (ec); + if (expr == null) return null; - if (!(this.expr is MethodGroupExpr)){ - report118 (tc, Location, this.expr, "method group"); + if (!(expr is MethodGroupExpr)) { + Type expr_type = expr.Type; + + if (expr_type != null){ + bool IsDelegate = TypeManager.IsDelegateType (expr_type); + if (IsDelegate) + return (new DelegateInvocation ( + this.expr, Arguments, loc)).Resolve (ec); + } + } + + if (!(expr is MethodGroupExpr)){ + report118 (loc, this.expr, "method group"); return null; } @@ -3374,197 +2568,669 @@ namespace CIR { --i; Argument a = (Argument) Arguments [i]; - if (!a.Resolve (tc)) + if (!a.Resolve (ec, loc)) return null; } } - method = OverloadResolve (tc, (MethodGroupExpr) this.expr, Arguments, - Location); + method = OverloadResolve (ec, (MethodGroupExpr) this.expr, Arguments, loc); if (method == null){ - Error (tc, -6, Location, + Error (-6, loc, "Could not find any applicable function for this argument list"); return null; } - if (method is MethodInfo) - type = ((MethodInfo)method).ReturnType; + if (method is MethodInfo) + type = ((MethodInfo)method).ReturnType; + + eclass = ExprClass.Value; + return this; + } + + // + // 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; + else + top = 0; + + if (mb != null) + pd = GetParameterData (mb); + + for (int i = 0; i < top; i++){ + Argument a = (Argument) arguments [i]; + + if (pd != null){ + if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){ + EmitParams (ec, i, arguments); + return; + } + } + + a.Emit (ec); + } + } + + public static void EmitCall (EmitContext ec, + bool is_static, Expression instance_expr, + MethodBase method, ArrayList Arguments) + { + ILGenerator ig = ec.ig; + bool struct_call = false; + + if (!is_static){ + // + // If this is ourselves, push "this" + // + if (instance_expr == null){ + ig.Emit (OpCodes.Ldarg_0); + } else { + // + // Push the instance expression + // + if (instance_expr.Type.IsSubclassOf (TypeManager.value_type)){ + + struct_call = true; + + // + // If the expression implements IMemoryLocation, then + // we can optimize and use AddressOf on the + // return. + // + // If not we have to use some temporary storage for + // it. + if (instance_expr is IMemoryLocation) + ((IMemoryLocation) instance_expr).AddressOf (ec); + else { + Type t = instance_expr.Type; + + instance_expr.Emit (ec); + LocalBuilder temp = ig.DeclareLocal (t); + ig.Emit (OpCodes.Stloc, temp); + ig.Emit (OpCodes.Ldloca, temp); + } + } else + instance_expr.Emit (ec); + } + } + + if (Arguments != null) + EmitArguments (ec, method, Arguments); + + if (is_static || struct_call){ + if (method is MethodInfo) + ig.Emit (OpCodes.Call, (MethodInfo) method); + else + ig.Emit (OpCodes.Call, (ConstructorInfo) method); + } else { + if (method is MethodInfo) + ig.Emit (OpCodes.Callvirt, (MethodInfo) method); + else + ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method); + } + } + + public override void Emit (EmitContext ec) + { + MethodGroupExpr mg = (MethodGroupExpr) this.expr; + EmitCall (ec, method.IsStatic, mg.InstanceExpression, method, Arguments); + } + + public override void EmitStatement (EmitContext ec) + { + Emit (ec); + + // + // Pop the return value if there is one + // + if (method is MethodInfo){ + if (((MethodInfo)method).ReturnType != TypeManager.void_type) + ec.ig.Emit (OpCodes.Pop); + } + } + } + + public class New : ExpressionStatement { + public readonly ArrayList Arguments; + public readonly string RequestedType; + + Location loc; + MethodBase method = null; + + // + // If set, the new expression is for a value_target, and + // we will not leave anything on the stack. + // + Expression value_target; + + public New (string requested_type, ArrayList arguments, Location l) + { + RequestedType = requested_type; + Arguments = arguments; + loc = l; + } + + public Expression ValueTypeVariable { + get { + return value_target; + } + + set { + value_target = value; + } + } + + public override Expression DoResolve (EmitContext ec) + { + type = ec.TypeContainer.LookupType (RequestedType, false); + + if (type == null) + return null; + + bool IsDelegate = TypeManager.IsDelegateType (type); + + if (IsDelegate) + return (new NewDelegate (type, Arguments, loc)).Resolve (ec); + + Expression ml; + + ml = MemberLookup (ec, type, ".ctor", false, + MemberTypes.Constructor, AllBindingsFlags, loc); + + bool is_struct = false; + is_struct = type.IsSubclassOf (TypeManager.value_type); + + if (! (ml is MethodGroupExpr)){ + if (!is_struct){ + report118 (loc, ml, "method group"); + return null; + } + } + + if (ml != null) { + if (Arguments != null){ + for (int i = Arguments.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 && !is_struct) { + Error (-6, loc, + "New invocation: Can not find a constructor for " + + "this argument list"); + return null; + } + + eclass = ExprClass.Value; + return this; + } + + // + // This DoEmit can be invoked in two contexts: + // * As a mechanism that will leave a value on the stack (new object) + // * As one that wont (init struct) + // + // You can control whether a value is required on the stack by passing + // need_value_on_stack. The code *might* leave a value on the stack + // so it must be popped manually + // + // Returns whether a value is left on the stack + // + bool DoEmit (EmitContext ec, bool need_value_on_stack) + { + if (method == null){ + IMemoryLocation ml = (IMemoryLocation) value_target; + + ml.AddressOf (ec); + } else { + Invocation.EmitArguments (ec, method, Arguments); + ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) method); + return true; + } + + // + // It must be a value type, sanity check + // + if (value_target != null){ + ec.ig.Emit (OpCodes.Initobj, type); + + if (need_value_on_stack){ + value_target.Emit (ec); + return true; + } + return false; + } + + throw new Exception ("No method and no value type"); + } + + public override void Emit (EmitContext ec) + { + DoEmit (ec, true); + } + + public override void EmitStatement (EmitContext ec) + { + if (DoEmit (ec, false)) + ec.ig.Emit (OpCodes.Pop); + } + } + + // + // 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; + ArrayList Arguments; + + 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) + { + RequestedType = requested_type; + Rank = rank; + Initializers = initializers; + loc = l; + + Arguments = new ArrayList (); + + foreach (Expression e in exprs) + Arguments.Add (new Argument (e, Argument.AType.Expression)); + + } + + public ArrayCreation (string requested_type, string rank, ArrayList initializers, Location l) + { + RequestedType = requested_type; + Initializers = initializers; + loc = l; + + Rank = rank.Substring (0, rank.LastIndexOf ("[")); + + string tmp = rank.Substring (rank.LastIndexOf ("[")); + + dimensions = tmp.Length - 1; + } + + public static string FormArrayType (string base_type, int idx_count, string rank) + { + StringBuilder sb = new StringBuilder (base_type); + + sb.Append (rank); + + sb.Append ("["); + for (int i = 1; i < idx_count; i++) + sb.Append (","); + sb.Append ("]"); + + return sb.ToString (); + } + + public static string FormElementType (string base_type, int idx_count, string rank) + { + StringBuilder sb = new StringBuilder (base_type); + + sb.Append ("["); + for (int i = 1; i < idx_count; i++) + sb.Append (","); + sb.Append ("]"); + + sb.Append (rank); - eclass = ExprClass.Value; - return this; + string val = sb.ToString (); + + return val.Substring (0, val.LastIndexOf ("[")); } - public static void EmitArguments (EmitContext ec, MethodBase method, ArrayList Arguments) + void error178 () { - int top; + Report.Error (178, loc, "Incorrectly structured array initializer"); + } - if (Arguments != null) - top = Arguments.Count; - else - top = 0; + bool ValidateInitializers (EmitContext ec) + { + if (Initializers == null) + return true; - for (int i = 0; i < top; i++){ - Argument a = (Argument) Arguments [i]; + Type underlying_type = ec.TypeContainer.LookupType (RequestedType, false); - a.Emit (ec); - } - } + ArrayList probe = Initializers; + + if (Arguments != null) { + for (int i = 0; i < Arguments.Count; i++) { + Argument a = (Argument) Arguments [i]; + + 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 (); - public override void Emit (EmitContext ec) - { - bool is_static = method.IsStatic; + if (probe == null) { + error178 (); + return false; + } + + if (value != probe.Count) { + error178 (); + return false; + } - if (!is_static){ - MethodGroupExpr mg = (MethodGroupExpr) this.expr; + 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); - // - // If this is ourselves, push "this" - // - if (mg.InstanceExpression == null){ - ec.ig.Emit (OpCodes.Ldarg_0); - } else { - // - // Push the instance expression - // - mg.InstanceExpression.Emit (ec); - } - } + Expression conv = ConvertImplicitRequired (ec, tmp, + underlying_type, loc); - if (Arguments != null) - EmitArguments (ec, method, Arguments); + if (conv == null) + return false; + } - if (is_static){ - if (method is MethodInfo) - ec.ig.Emit (OpCodes.Call, (MethodInfo) method); - else - ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method); - } else { - if (method is MethodInfo) - ec.ig.Emit (OpCodes.Callvirt, (MethodInfo) method); - else - ec.ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method); - } - } + probe = null; + } + } - public override void EmitStatement (EmitContext ec) - { - Emit (ec); + } else { + // + // Here is where we update dimension info in the case + // that the user skips doing that + // - // - // Pop the return value if there is one - // - if (method is MethodInfo){ - if (((MethodInfo)method).ReturnType != TypeManager.void_type) - ec.ig.Emit (OpCodes.Pop); - } - } - } + Arguments = new ArrayList (); + + for (probe = Initializers; probe != null; ) { + Expression e = new IntLiteral (probe.Count); - public class New : ExpressionStatement { + Arguments.Add (new Argument (e, Argument.AType.Expression)); - public enum NType { - Object, - Array - }; + 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 readonly NType NewType; - public readonly ArrayList Arguments; - public readonly string RequestedType; - // These are for the case when we have an array - public readonly string Rank; - public readonly ArrayList Indices; - public readonly ArrayList Initializers; + Expression conv = ConvertImplicitRequired (ec, tmp, + underlying_type, loc); - Location Location; - MethodBase method = null; + if (conv == null) + return false; + } + + probe = null; + } + } - public New (string requested_type, ArrayList arguments, Location loc) - { - RequestedType = requested_type; - Arguments = arguments; - NewType = NType.Object; - Location = loc; - } + if (Arguments.Count != dimensions) { + error178 (); + return false; + } + } - public New (string requested_type, ArrayList exprs, string rank, ArrayList initializers, Location loc) - { - RequestedType = requested_type; - Indices = exprs; - Rank = rank; - Initializers = initializers; - NewType = NType.Array; - Location = loc; + return true; } - public override Expression DoResolve (TypeContainer tc) + public override Expression DoResolve (EmitContext ec) { - type = tc.LookupType (RequestedType, false); + int arg_count; - if (type == null) + if (!ValidateInitializers (ec)) return null; - Expression ml; + if (Arguments == null) + arg_count = 0; + else + arg_count = Arguments.Count; + + string array_type = FormArrayType (RequestedType, arg_count, Rank); - ml = MemberLookup (tc, type, ".ctor", false, - MemberTypes.Constructor, AllBindingsFlags); + string element_type = FormElementType (RequestedType, arg_count, Rank); - if (! (ml is MethodGroupExpr)){ - // - // FIXME: Find proper error - // - report118 (tc, Location, ml, "method group"); + type = ec.TypeContainer.LookupType (array_type, false); + + array_element_type = ec.TypeContainer.LookupType (element_type, false); + + if (type == null) return null; - } - if (Arguments != null){ - for (int i = Arguments.Count; i > 0;){ - --i; - Argument a = (Argument) Arguments [i]; + if (arg_count == 1) { + IsOneDimensional = true; + eclass = ExprClass.Value; + return this; + } - if (!a.Resolve (tc)) - return null; + IsBuiltinType = TypeManager.IsBuiltinType (type); + + 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 = Invocation.OverloadResolve (tc, (MethodGroupExpr) ml, Arguments, - Location); + ModuleBuilder mb = ec.TypeContainer.RootContext.ModuleBuilder; - if (method == null) { - Error (tc, -6, Location, - "New invocation: Can not find a constructor for this argument list"); - return null; + 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; + } - - eclass = ExprClass.Value; - return this; } public override void Emit (EmitContext ec) { - Invocation.EmitArguments (ec, method, Arguments); - ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) method); - } + ILGenerator ig = ec.ig; + + if (IsOneDimensional) { + Invocation.EmitArguments (ec, null, Arguments); + ig.Emit (OpCodes.Newarr, array_element_type); + + } else { + 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, LValue { - public override Expression DoResolve (TypeContainer tc) + public class This : Expression, IAssignMethod, IMemoryLocation { + Location loc; + + public This (Location loc) + { + this.loc = loc; + } + + public override Expression DoResolve (EmitContext ec) { eclass = ExprClass.Variable; - type = tc.TypeBuilder; + type = ec.TypeContainer.TypeBuilder; + + if (ec.IsStatic){ + Report.Error (26, loc, + "Keyword this not valid in static code"); + return null; + } + + return this; + } + + public Expression DoResolveLValue (EmitContext ec) + { + DoResolve (ec); + + if (ec.TypeContainer is Class){ + Report.Error (1604, loc, "Cannot assign to `this'"); + return null; + } - // - // FIXME: Verify that this is only used in instance contexts. - // return this; } @@ -3573,14 +3239,9 @@ namespace CIR { ec.ig.Emit (OpCodes.Ldarg_0); } - public void Store (EmitContext ec) + public void EmitAssign (EmitContext ec, Expression source) { - // - // Assignment to the "this" variable. - // - // FIXME: Apparently this is a bug that we - // must catch as `this' seems to be readonly ;-) - // + source.Emit (ec); ec.ig.Emit (OpCodes.Starg, 0); } @@ -3590,29 +3251,34 @@ namespace CIR { } } + // + // Implements the typeof operator + // public class TypeOf : Expression { public readonly string QueriedType; + Type typearg; public TypeOf (string queried_type) { QueriedType = queried_type; } - public override Expression DoResolve (TypeContainer tc) + public override Expression DoResolve (EmitContext ec) { - type = tc.LookupType (QueriedType, false); + typearg = ec.TypeContainer.LookupType (QueriedType, false); - if (type == null) + if (typearg == null) return null; - + + type = TypeManager.type_type; eclass = ExprClass.Type; return this; } public override void Emit (EmitContext ec) { - throw new Exception ("Implement me"); - // FIXME: Implement. + ec.ig.Emit (OpCodes.Ldtoken, typearg); + ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle); } } @@ -3624,7 +3290,7 @@ namespace CIR { this.QueriedType = queried_type; } - public override Expression DoResolve (TypeContainer tc) + public override Expression DoResolve (EmitContext ec) { // FIXME: Implement; throw new Exception ("Unimplemented"); @@ -3641,11 +3307,13 @@ namespace CIR { public readonly string Identifier; Expression expr; Expression member_lookup; + Location loc; - public MemberAccess (Expression expr, string id) + public MemberAccess (Expression expr, string id, Location l) { this.expr = expr; Identifier = id; + loc = l; } public Expression Expr { @@ -3653,45 +3321,139 @@ namespace CIR { 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 (TypeContainer tc) + public override Expression DoResolve (EmitContext ec) { - Expression new_expression = expr.Resolve (tc); + // + // We are the sole users of ResolveWithSimpleName (ie, the only + // ones that can cope with it + // + expr = expr.ResolveWithSimpleName (ec); - if (new_expression == null) + if (expr == null) return null; - member_lookup = MemberLookup (tc, expr.Type, Identifier, false); + 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; - - // - // Bind the instance expression to it + // - // FIXME: This is a horrible way of detecting if it is - // an instance expression. Figure out how to fix this. + // Type.MethodGroup // + if (expr is TypeExpr){ + if (!mg.RemoveInstanceMethods ()){ + SimpleName.Error120 (loc, mg.Methods [0].Name); + return null; + } + + return member_lookup; + } - if (expr is LocalVariableReference || - expr is ParameterReference || - expr is FieldExpr) - mg.InstanceExpression = expr; + // + // Instance.MethodGroup + // + if (!mg.RemoveStaticMethods ()){ + error176 (loc, mg.Methods [0].Name); + return null; + } + + mg.InstanceExpression = expr; return member_lookup; - } else if (member_lookup is FieldExpr){ + } + + if (member_lookup is FieldExpr){ FieldExpr fe = (FieldExpr) member_lookup; + FieldInfo fi = fe.FieldInfo; - fe.Instance = expr; + if (fi.IsLiteral) { + Type t = fi.FieldType; + object o; - return member_lookup; - } else - // - // FIXME: This should generate the proper node - // ie, for a Property Access, it should like call it - // and stuff. + 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); + } - return member_lookup; + 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; } public override void Emit (EmitContext ec) @@ -3701,309 +3463,461 @@ namespace CIR { } - // - // Nodes of type Namespace are created during the semantic - // analysis to resolve member_access/qualified_identifier/simple_name - // accesses. - // - // They are born `resolved'. - // - public class NamespaceExpr : Expression { - public readonly string Name; - - public NamespaceExpr (string name) + public class CheckedExpr : Expression { + + public Expression Expr; + + public CheckedExpr (Expression e) { - Name = name; - eclass = ExprClass.Namespace; + Expr = e; } - public override Expression DoResolve (TypeContainer tc) + public override Expression DoResolve (EmitContext ec) { + Expr = Expr.Resolve (ec); + + if (Expr == null) + return null; + + eclass = Expr.ExprClass; + type = Expr.Type; return this; } public override void Emit (EmitContext ec) { - throw new Exception ("Namespace expressions should never be emitted"); + bool last_check = ec.CheckState; + + ec.CheckState = true; + Expr.Emit (ec); + ec.CheckState = last_check; } + } - // - // Fully resolved expression that evaluates to a type - // - public class TypeExpr : Expression { - public TypeExpr (Type t) + public class UnCheckedExpr : Expression { + + public Expression Expr; + + public UnCheckedExpr (Expression e) { - Type = t; - eclass = ExprClass.Type; + Expr = e; } - override public Expression DoResolve (TypeContainer tc) + public override Expression DoResolve (EmitContext ec) { + Expr = Expr.Resolve (ec); + + if (Expr == null) + return null; + + eclass = Expr.ExprClass; + type = Expr.Type; return this; } - override public void Emit (EmitContext ec) + public override void Emit (EmitContext ec) { - throw new Exception ("Implement me"); + bool last_check = ec.CheckState; + + ec.CheckState = false; + Expr.Emit (ec); + ec.CheckState = last_check; } + } - // - // MethodGroup Expression. - // - // This is a fully resolved expression that evaluates to a type - // - public class MethodGroupExpr : Expression { - public readonly MethodBase [] Methods; - Expression instance_expression = null; + public class ElementAccess : Expression { + public ArrayList Arguments; + public Expression Expr; + public Location loc; - public MethodGroupExpr (MemberInfo [] mi) + public ElementAccess (Expression e, ArrayList e_list, Location l) { - Methods = new MethodBase [mi.Length]; - mi.CopyTo (Methods, 0); - eclass = ExprClass.MethodGroup; + Expr = e; + + Arguments = new ArrayList (); + foreach (Expression tmp in e_list) + Arguments.Add (new Argument (tmp, Argument.AType.Expression)); + + loc = l; } - // - // `A method group may have associated an instance expression' - // - public Expression InstanceExpression { - get { - return instance_expression; - } + bool CommonResolve (EmitContext ec) + { + Expr = Expr.Resolve (ec); - set { - instance_expression = value; + if (Expr == null) + return false; + + if (Arguments == null) + return false; + + for (int i = Arguments.Count; i > 0;){ + --i; + Argument a = (Argument) Arguments [i]; + + if (!a.Resolve (ec, loc)) + return false; } + + return true; } - - override public Expression DoResolve (TypeContainer tc) + + public override Expression DoResolve (EmitContext ec) { - return this; + if (!CommonResolve (ec)) + return null; + + // + // We perform some simple tests, and then to "split" the emit and store + // code we create an instance of a different class, and return that. + // + // I am experimenting with this pattern. + // + if (Expr.Type.IsSubclassOf (TypeManager.array_type)) + return (new ArrayAccess (this)).Resolve (ec); + else + return (new IndexerAccess (this)).Resolve (ec); } - override public void Emit (EmitContext ec) + public override Expression DoResolveLValue (EmitContext ec, Expression right_side) + { + if (!CommonResolve (ec)) + return null; + + if (Expr.Type.IsSubclassOf (TypeManager.array_type)) + return (new ArrayAccess (this)).ResolveLValue (ec, right_side); + else + return (new IndexerAccess (this)).ResolveLValue (ec, right_side); + } + + public override void Emit (EmitContext ec) { - throw new Exception ("This should never be reached"); + throw new Exception ("Should never be reached"); } } - - // Fully resolved expression that evaluates to a Field - // - public class FieldExpr : Expression, LValue { - public readonly FieldInfo FieldInfo; - public Expression Instance; - - public FieldExpr (FieldInfo fi) + + // + // Implements array access + // + public class ArrayAccess : Expression, IAssignMethod { + // + // Points to our "data" repository + // + ElementAccess ea; + + public ArrayAccess (ElementAccess ea_data) { - FieldInfo = fi; + ea = ea_data; eclass = ExprClass.Variable; - type = fi.FieldType; } - override public Expression DoResolve (TypeContainer tc) + public override Expression DoResolve (EmitContext ec) { - if (!FieldInfo.IsStatic){ - if (Instance == 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"); - } + if (ea.Expr.ExprClass != ExprClass.Variable) { + report118 (ea.loc, ea.Expr, "variable"); + return null; + } - Instance = Instance.Resolve (tc); - if (Instance == null) - return null; - + 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; } - override public void Emit (EmitContext ec) + // + // 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) { + int rank = ea.Expr.Type.GetArrayRank (); ILGenerator ig = ec.ig; - if (FieldInfo.IsStatic) - ig.Emit (OpCodes.Ldsfld, FieldInfo); + ea.Expr.Emit (ec); + + foreach (Argument a in ea.Arguments) + a.Expr.Emit (ec); + + if (rank == 1) + EmitLoadOpcode (ig, type); else { - Instance.Emit (ec); + 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.Ldfld, FieldInfo); + ig.Emit (OpCodes.Call, get); } } - public void Store (EmitContext ec) + public void EmitAssign (EmitContext ec, Expression source) { - if (FieldInfo.IsStatic) - ec.ig.Emit (OpCodes.Stsfld, FieldInfo); - else - ec.ig.Emit (OpCodes.Stfld, FieldInfo); - } + int rank = ea.Expr.Type.GetArrayRank (); + ILGenerator ig = ec.ig; - public void AddressOf (EmitContext ec) - { - if (FieldInfo.IsStatic) - ec.ig.Emit (OpCodes.Ldsflda, FieldInfo); + 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 { - Instance.Emit (ec); - ec.ig.Emit (OpCodes.Ldflda, FieldInfo); + 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); } } } - - // - // Fully resolved expression that evaluates to a Property - // - public class PropertyExpr : Expression { - public readonly PropertyInfo PropertyInfo; - public readonly bool IsStatic; - - public PropertyExpr (PropertyInfo pi) - { - PropertyInfo = pi; - eclass = ExprClass.PropertyAccess; - IsStatic = false; - - MethodBase [] acc = pi.GetAccessors (); - - for (int i = 0; i < acc.Length; i++) - if (acc [i].IsStatic) - IsStatic = true; + class Indexers { + public ArrayList getters, setters; + static Hashtable map; - type = pi.PropertyType; + static Indexers () + { + map = new Hashtable (); } - override public Expression DoResolve (TypeContainer tc) + Indexers (MemberInfo [] mi) { - // We are born in resolved state. - return this; - } + foreach (PropertyInfo property in mi){ + MethodInfo get, set; + + get = property.GetGetMethod (true); + if (get != null){ + if (getters == null) + getters = new ArrayList (); - override public void Emit (EmitContext ec) + getters.Add (get); + } + + set = property.GetSetMethod (true); + if (set != null){ + if (setters == null) + setters = new ArrayList (); + setters.Add (set); + } + } + } + + static public Indexers GetIndexersForType (Type t, TypeManager tm, Location loc) { - // FIXME: Implement; - throw new Exception ("Unimplemented"); + Indexers ix = (Indexers) map [t]; + string p_name = TypeManager.IndexerPropertyName (t); + + if (ix != null) + return ix; + + MemberInfo [] mi = tm.FindMembers ( + t, MemberTypes.Property, + BindingFlags.Public | BindingFlags.Instance, + Type.FilterName, p_name); + + if (mi == null || mi.Length == 0){ + Report.Error (21, loc, + "Type `" + TypeManager.CSharpName (t) + "' does not have " + + "any indexers defined"); + return null; + } + + ix = new Indexers (mi); + map [t] = ix; + + return ix; } } // - // Fully resolved expression that evaluates to a Expression + // Expressions that represent an indexer call. // - public class EventExpr : Expression { - public readonly EventInfo EventInfo; + public class IndexerAccess : Expression, IAssignMethod { + // + // Points to our "data" repository + // + ElementAccess ea; + MethodInfo get, set; + Indexers ilist; + ArrayList set_arguments; - public EventExpr (EventInfo ei) - { - EventInfo = ei; - eclass = ExprClass.EventAccess; - } - - override public Expression DoResolve (TypeContainer tc) + public IndexerAccess (ElementAccess ea_data) { - // We are born in resolved state. - return this; + ea = ea_data; + eclass = ExprClass.Value; } - override public void Emit (EmitContext ec) + public override Expression DoResolve (EmitContext ec) { - throw new Exception ("Implement me"); - // FIXME: Implement. - } - } - - public class CheckedExpr : Expression { - - public Expression Expr; + Type indexer_type = ea.Expr.Type; + + // + // Step 1: Query for all `Item' *properties*. Notice + // that the actual methods are pointed from here. + // + // This is a group of properties, piles of them. - public CheckedExpr (Expression e) - { - Expr = e; - } + if (ilist == null) + ilist = Indexers.GetIndexersForType ( + indexer_type, ec.TypeContainer.RootContext.TypeManager, ea.loc); - public override Expression DoResolve (TypeContainer tc) - { - Expr = Expr.Resolve (tc); - if (Expr == null) + // + // 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); + + if (get == null){ + Report.Error (154, ea.loc, + "indexer can not be used in this context, because " + + "it lacks a `get' accessor"); return null; + } - eclass = Expr.ExprClass; - type = Expr.Type; + type = get.ReturnType; + eclass = ExprClass.IndexerAccess; return this; } - public override void Emit (EmitContext ec) + public override Expression DoResolveLValue (EmitContext ec, Expression right_side) { - bool last_check = ec.CheckState; - - ec.CheckState = true; - Expr.Emit (ec); - ec.CheckState = last_check; - } - - } - - public class UnCheckedExpr : Expression { - - public Expression Expr; + Type indexer_type = ea.Expr.Type; + Type right_type = right_side.Type; - public UnCheckedExpr (Expression e) - { - Expr = e; - } + if (ilist == null) + ilist = Indexers.GetIndexersForType ( + indexer_type, ec.TypeContainer.RootContext.TypeManager, ea.loc); - public override Expression DoResolve (TypeContainer tc) - { - Expr = Expr.Resolve (tc); + if (ilist != null && ilist.setters != null && ilist.setters.Count > 0){ + set_arguments = (ArrayList) ea.Arguments.Clone (); + set_arguments.Add (new Argument (right_side, Argument.AType.Expression)); - if (Expr == null) - return null; + set = (MethodInfo) Invocation.OverloadResolve ( + ec, new MethodGroupExpr (ilist.setters), set_arguments, ea.loc); + } + + if (set == null){ + Report.Error (200, ea.loc, + "indexer X.this [" + TypeManager.CSharpName (right_type) + + "] lacks a `set' accessor"); + return null; + } - eclass = Expr.ExprClass; - type = Expr.Type; + type = TypeManager.void_type; + eclass = ExprClass.IndexerAccess; return this; } - - public override void Emit (EmitContext ec) - { - bool last_check = ec.CheckState; - - ec.CheckState = false; - Expr.Emit (ec); - ec.CheckState = last_check; - } - - } - - public class ElementAccess : Expression { - public readonly ArrayList Arguments; - public readonly Expression Expr; - - public ElementAccess (Expression e, ArrayList e_list) + public override void Emit (EmitContext ec) { - Expr = e; - Arguments = e_list; + Invocation.EmitCall (ec, false, ea.Expr, get, ea.Arguments); } - public override Expression DoResolve (TypeContainer tc) - { - // FIXME: Implement; - throw new Exception ("Unimplemented"); - // return this; - } - - public override void Emit (EmitContext ec) + // + // source is ignored, because we already have a copy of it from the + // LValue resolution and we have already constructed a pre-cached + // version of the arguments (ea.set_arguments); + // + public void EmitAssign (EmitContext ec, Expression source) { - // FIXME : Implement ! - throw new Exception ("Unimplemented"); + Invocation.EmitCall (ec, false, ea.Expr, set, set_arguments); } - } public class BaseAccess : Expression { - public enum BaseAccessType { + public enum BaseAccessType : byte { Member, Indexer }; @@ -4020,7 +3934,7 @@ namespace CIR { } - public override Expression DoResolve (TypeContainer tc) + public override Expression DoResolve (EmitContext ec) { // FIXME: Implement; throw new Exception ("Unimplemented"); @@ -4033,22 +3947,54 @@ namespace CIR { } } - public class UserImplicitCast : Expression { + // + // This class exists solely to pass the Type around and to be a dummy + // that can be passed to the conversion functions (this is used by + // foreach implementation to typecast the object return value from + // get_Current into the proper type. All code has been generated and + // we only care about the side effect conversions to be performed + // + + public class EmptyExpression : Expression { + public EmptyExpression () + { + type = TypeManager.object_type; + eclass = ExprClass.Value; + } + + public EmptyExpression (Type t) + { + type = t; + eclass = ExprClass.Value; + } + + public override Expression DoResolve (EmitContext ec) + { + return this; + } + + public override void Emit (EmitContext ec) + { + // nothing, as we only exist to not do anything. + } + } + + public class UserCast : Expression { MethodBase method; - ArrayList arguments; + Expression source; - public UserImplicitCast (MethodInfo method, ArrayList arguments) + public UserCast (MethodInfo method, Expression source) { this.method = method; - this.arguments = arguments; + this.source = source; type = method.ReturnType; eclass = ExprClass.Value; } - public override Expression DoResolve (TypeContainer tc) + public override Expression DoResolve (EmitContext ec) { // - // We are born in a fully resolved state + // We are born fully resolved // return this; } @@ -4056,16 +4002,14 @@ namespace CIR { public override void Emit (EmitContext ec) { ILGenerator ig = ec.ig; - - // Note that operators are static anyway - - if (arguments != null) - Invocation.EmitArguments (ec, method, arguments); + + source.Emit (ec); if (method is MethodInfo) ig.Emit (OpCodes.Call, (MethodInfo) method); else ig.Emit (OpCodes.Call, (ConstructorInfo) method); + } }