X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fexpression.cs;h=5cf7fdb86541dfc754c26b3f3b46d4565786a7e5;hb=8d510ba7f34bbe25a5c6df1046b15bf94ead6acb;hp=7ea4d88ba35b555eef6760df8981e43b38466f44;hpb=267a36159c8f0570965e69478249a76382a6dedf;p=mono.git diff --git a/mcs/mcs/expression.cs b/mcs/mcs/expression.cs index 7ea4d88ba35..5cf7fdb8654 100755 --- a/mcs/mcs/expression.cs +++ b/mcs/mcs/expression.cs @@ -6,606 +6,99 @@ // // (C) 2001 Ximian, Inc. // +// + 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; - } - } - - public abstract Expression Resolve (TypeContainer tc); - - // - // Return value indicates whether a value is left on the stack or not - // - public abstract bool Emit (EmitContext ec); - - // - // Protected constructor. Only derivate types should - // be able to be created - // - - protected Expression () - { - eclass = ExprClass.Invalid; - type = null; - } - - // - // Returns a fully formed expression after a MemberLookup - // - static Expression ExprClassFromMemberInfo (MemberInfo mi) - { - if (mi is EventInfo){ - return new EventExpr ((EventInfo) mi); - } else if (mi is FieldInfo){ - return new FieldExpr ((FieldInfo) mi); - } 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 (RootContext rc, Type t, string name, - bool same_type, MemberTypes mt, BindingFlags bf) - { - if (same_type) - bf |= BindingFlags.NonPublic; - - MemberInfo [] mi = rc.TypeManager.FindMembers (t, mt, bf, Type.FilterName, name); - - if (mi == null) - return null; - - if (mi.Length == 1 && !(mi [0] is MethodBase)) - return Expression.ExprClassFromMemberInfo (mi [0]); - - for (int i = 0; i < mi.Length; i++) - if (!(mi [i] is MethodBase)){ - rc.Report.Error (-5, "Do not know how to reproduce this case: " + - "Methods and non-Method with the same name, report this please"); - - for (i = 0; i < mi.Length; i++){ - Type tt = mi [i].GetType (); - - Console.WriteLine (i + ": " + mi [i]); - while (tt != TypeManager.object_type){ - Console.WriteLine (tt); - tt = tt.BaseType; - } - } - } - return new MethodGroupExpr (mi); - } - - public const MemberTypes AllMemberTypes = - MemberTypes.Constructor | - MemberTypes.Event | - MemberTypes.Field | - MemberTypes.Method | - MemberTypes.NestedType | - MemberTypes.Property; - - public const BindingFlags AllBindingsFlags = - BindingFlags.Public | - BindingFlags.Static | - BindingFlags.Instance; - - public static Expression MemberLookup (RootContext rc, Type t, string name, - bool same_type) - { - return MemberLookup (rc, t, name, same_type, AllMemberTypes, AllBindingsFlags); - } - - // - // Resolves the E in `E.I' side for a member_access - // - // This is suboptimal and should be merged with ResolveMemberAccess - // - static Expression ResolvePrimary (TypeContainer tc, string name) - { - int dot_pos = name.LastIndexOf ("."); - - if (tc.RootContext.IsNamespace (name)) - return new NamespaceExpr (name); - - if (dot_pos != -1){ - } else { - Type t = tc.LookupType (name, false); - - if (t != null) - return new TypeExpr (t); - } + // + // 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; - return null; - } - - static public Expression ResolveMemberAccess (TypeContainer tc, string name) + StaticCallExpr (MethodInfo m, ArrayList a) { - Expression left_e; - int dot_pos = name.LastIndexOf ("."); - string left = name.Substring (0, dot_pos); - string right = name.Substring (dot_pos + 1); - - left_e = ResolvePrimary (tc, left); - if (left_e == null) - return null; + mi = m; + args = a; - switch (left_e.ExprClass){ - case ExprClass.Type: - return MemberLookup (tc.RootContext, - 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: - tc.RootContext.Report.Error (-1000, - "Internal compiler error, should have " + - "got these handled before"); - break; - } - - return null; + type = m.ReturnType; + eclass = ExprClass.Value; } - 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, target_type); - } else if (expr_type.IsSubclassOf (target_type)) - return new EmptyCast (expr, target_type); - else - // FIXME: missing implicit reference conversions: - // - // from any class-type S to any interface-type T. - // from any interface type S to interface-type T. - // from an array-type S to an array-type of type T - // from an array-type to System.Array - // from any delegate type to System.Delegate - // from any array-type or delegate type into System.ICloneable. - // from the null type to any reference-type. - - return null; - - 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 (Expression expr, Type target_type) + public override Expression DoResolve (EmitContext ec) { - Type expr_type = expr.Type; - - if (expr_type == target_type) - return expr; - - // - // Step 1: Perform implicit conversions as found on expr.Type - // - - // - // Step 2: Built-in conversions. - // - 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_U8); - 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); - } 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); - } 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); - } else if (expr_type == TypeManager.ushort_type){ - // - // From ushort to int, uint, long, ulong, float, double - // - if ((target_type == TypeManager.uint32_type) || - (target_type == TypeManager.uint64_type)) - return new EmptyCast (expr, target_type); - - 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); - } 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); - } 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_I8); - 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); - } else if ((expr_type == TypeManager.uint64_type) || - (expr_type == TypeManager.int64_type)){ - // - // From long 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); - } 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); - } else - return ImplicitReferenceConversion (expr, target_type); - - - // - // Could not find an implicit cast. + // We are born fully resolved // - 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 (target, type); - if (e == null){ - string msg = "Can not convert implicity from `"+ - TypeManager.CSharpName (target.Type) + "' to `" + - TypeManager.CSharpName (type) + "'"; - - tc.RootContext.Report.Error (29, l, msg); - } - return e; - } - - // - // Performs an explicit conversion of the expression `expr' whose - // type is expr.Type to `target_type'. - // - static public Expression ConvertExplicit (Expression expr, Type target_type) - { - return expr; + return this; } - void report (TypeContainer tc, int error, string s) + public override void Emit (EmitContext ec) { - tc.RootContext.Report.Error (error, s); - } + if (args != null) + Invocation.EmitArguments (ec, mi, args); - 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"); + ec.ig.Emit (OpCodes.Call, mi); + return; } - // - // Reports that we were expecting `expr' to be of class `expected' - // - protected void report118 (TypeContainer tc, Expression expr, string expected) - { - report (tc, 118, "Expression denotes a '" + ExprClassName (expr.ExprClass) + - "' where an " + expected + " was expected"); - } - } - - // - // 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 Resolve (TypeContainer tc) - { - // This should never be invoked, we are born in fully - // initialized state. - - return this; - } - - public override bool Emit (EmitContext ec) - { - return 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, Type target_type) - : base (expr, target_type) + static public Expression MakeSimpleCall (EmitContext ec, MethodGroupExpr mg, + Expression e, Location loc) { - } + 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 Resolve (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 bool Emit (EmitContext ec) + public override void EmitStatement (EmitContext ec) { - base.Emit (ec); - ec.ig.Emit (OpCodes.Box, child.Type); - return true; + Emit (ec); + if (type != TypeManager.void_type) + ec.ig.Emit (OpCodes.Pop); } } - // - // 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. + // Unary expressions. // - 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) - - { - this.op = op; - this.op2 = op2; - second_valid = true; - } - - public override Expression Resolve (TypeContainer tc) - { - // This should never be invoked, we are born in fully - // initialized state. - - return this; - } - - public override bool Emit (EmitContext ec) - { - base.Emit (ec); - ec.ig.Emit (op); - - if (second_valid) - ec.ig.Emit (op2); - - return true; - } - - } - + // + // + // Unary implements unary expressions. It derives from + // ExpressionStatement becuase the pre/post increment/decrement + // operators can be used in a statement context. + // public class Unary : Expression { - public enum Operator { - Add, Subtract, Negate, BitComplement, - Indirection, AddressOf, PreIncrement, - PreDecrement, PostIncrement, PostDecrement + 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 { @@ -634,64 +127,52 @@ namespace CIR { string OperName () { switch (oper){ - case Operator.Add: + case Operator.UnaryPlus: return "+"; - case Operator.Subtract: + 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 (Expression expr, Type target_type) + void error23 (Type t) { - if (expr.Type == target_type) - return expr; - - return ConvertImplicit (expr, target_type); + 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; @@ -700,24 +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; + + op_name = "op_" + oper; - mg = MemberLookup (tc.RootContext, expr_type, 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 ((MethodGroupExpr) mg, Arguments, tc, location); - if (method != null){ - return this; + Expression e = StaticCallExpr.MakeSimpleCall ( + ec, (MethodGroupExpr) mg, expr, loc); + + if (e == null){ + error23 (expr_type); + return null; } + + return e; } // @@ -725,33 +206,35 @@ 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; - } else - type = TypeManager.bool_type; - } - - if (oper == Operator.BitComplement) { + } + + type = TypeManager.bool_type; + return this; + } + + 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.Add) { + if (oper == Operator.UnaryPlus) { // // A plus in front of something is just a no-op, so return the child. // @@ -766,7 +249,7 @@ namespace CIR { // double operator- (double d) // decimal operator- (decimal d) // - if (oper == Operator.Subtract){ + if (oper == Operator.UnaryNegation){ // // Fold a "- Constant" into a negative constant // @@ -776,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; } @@ -810,7 +284,7 @@ namespace CIR { // bt written as a decimal interger literal // type = TypeManager.int64_type; - expr = ConvertImplicit (expr, type); + expr = ConvertImplicit (ec, expr, type, loc); return this; } @@ -820,287 +294,501 @@ 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 (expr, TypeManager.int32_type); + e = ConvertImplicit (ec, expr, TypeManager.int32_type, loc); if (e != null){ expr = e; type = e.Type; return this; } - e = ConvertImplicit (expr, TypeManager.int64_type); + e = ConvertImplicit (ec, expr, TypeManager.int64_type, loc); if (e != null){ expr = e; type = e.Type; return this; } - e = ConvertImplicit (expr, TypeManager.double_type); + 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, expr, "variable, indexer or property access"); + if (oper == Operator.AddressOf){ + if (expr.ExprClass != ExprClass.Variable){ + Error (211, loc, "Cannot take the address of non-variables"); + return null; } - } + type = Type.GetType (expr.Type.ToString () + "*"); - tc.RootContext.Report.Error (187, "No such operator '" + OperName () + - "' defined for type '" + - TypeManager.CSharpName (expr_type) + "'"); + return this; + } + + Error (187, loc, "No such operator '" + OperName () + "' defined for type '" + + TypeManager.CSharpName (expr_type) + "'"); return null; - } - public override Expression Resolve (TypeContainer tc) + public override Expression DoResolve (EmitContext ec) { - expr = expr.Resolve (tc); - + expr = expr.Resolve (ec); + if (expr == null) return null; - - return ResolveOperator (tc); + + eclass = ExprClass.Value; + return ResolveOperator (ec); } - public override bool Emit (EmitContext 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); - } - - if (method is MethodInfo) - ig.Emit (OpCodes.Call, (MethodInfo) method); - else - ig.Emit (OpCodes.Call, (ConstructorInfo) method); - - return true; - } - switch (oper){ - case Operator.Add: + switch (oper) { + case Operator.UnaryPlus: throw new Exception ("This should be caught by Resolve"); - - case Operator.Subtract: - expr.Emit (ec); + + 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: - throw new Exception ("Not implemented yet"); - - case Operator.Indirection: - throw new Exception ("Not implemented yet"); - - case Operator.PreIncrement: - case Operator.PreDecrement: - if (expr.ExprClass == ExprClass.Variable){ - if (expr_type == TypeManager.decimal_type){ - throw new Exception ("FIXME: Add pre inc/dec for decimals"); - } else { - // - // Resolve already verified that it is an "incrementable" - // - expr.Emit (ec); - ig.Emit (OpCodes.Ldc_I4_1); - - if (oper == Operator.PreDecrement) - ig.Emit (OpCodes.Sub); - else - ig.Emit (OpCodes.Add); - ((LValue) expr).Store (ig); - ig.Emit (OpCodes.Dup); - } - } else { - throw new Exception ("Handle Indexers and Properties here"); - } + ((IMemoryLocation)expr).AddressOf (ec); break; - case Operator.PostIncrement: - case Operator.PostDecrement: - if (expr.ExprClass == ExprClass.Variable){ - if (expr_type == TypeManager.decimal_type){ - throw new Exception ("FIXME: Add pre inc/dec for decimals"); - } else { - // - // Resolve already verified that it is an "incrementable" - // - expr.Emit (ec); - ig.Emit (OpCodes.Dup); - ig.Emit (OpCodes.Ldc_I4_1); - - if (oper == Operator.PostDecrement) - ig.Emit (OpCodes.Sub); - else - ig.Emit (OpCodes.Add); - ((LValue) expr).Store (ig); - } - } else { - throw new Exception ("Handle Indexers and Properties here"); - } - break; + case Operator.Indirection: + throw new Exception ("Not implemented yet"); 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; + // - // yes, we leave a value on the stack + // First, reduce our child. Note that although we handle // - return true; + 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; } - } - - public class Probe : Expression { - string probe_type; + + // + // 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; - Operator oper; + LocalTemporary temp_storage; - public enum Operator { - Is, As + // + // 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) ? + "++" : "--"; } - public Probe (Operator oper, Expression expr, string probe_type) + void error23 (Type t) { - this.oper = oper; - this.probe_type = probe_type; - this.expr = expr; + Report.Error ( + 23, loc, "Operator " + OperName () + + " cannot be applied to operand of type `" + + TypeManager.CSharpName (t) + "'"); } - public Operator Oper { - get { - return oper; - } + // + // 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); } - public Expression Expr { - get { - return expr; + 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; } - } - public string ProbeType { - get { - return probe_type; + // + // 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 Resolve (TypeContainer tc) + public override Expression DoResolve (EmitContext ec) { - // FIXME: Implement; - throw new Exception ("Unimplemented"); - // return this; + expr = expr.Resolve (ec); + + if (expr == null) + return null; + + eclass = ExprClass.Value; + return ResolveOperator (ec); } + - public override bool Emit (EmitContext 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) { - return true; + 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 (mode == Mode.PreDecrement) + ig.Emit (OpCodes.Sub); + else + ig.Emit (OpCodes.Add); + } else + method.Emit (ec); + + temp_storage.Store (ec); + ia.EmitAssign (ec, temp_storage); + if (is_expr) + temp_storage.Emit (ec); + break; + + case Mode.PostIncrement: + case Mode.PostDecrement: + if (is_expr) + expr.Emit (ec); + + if (method == null){ + if (!is_expr) + expr.Emit (ec); + else + ig.Emit (OpCodes.Dup); + + ig.Emit (OpCodes.Ldc_I4_1); + + if (mode == Mode.PostDecrement) + ig.Emit (OpCodes.Sub); + else + ig.Emit (OpCodes.Add); + } else { + method.Emit (ec); + } + + 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) + { + EmitCode (ec, false); } + } - public class Cast : Expression { - string target_type; + public class Probe : Expression { + public readonly string ProbeType; + public readonly Operator Oper; Expression expr; + Type probe_type; - public Cast (string cast_type, Expression expr) + public enum Operator : byte { + Is, As + } + + public Probe (Operator oper, Expression expr, string probe_type) { - this.target_type = cast_type; + Oper = oper; + ProbeType = probe_type; this.expr = expr; } - public string TargetType { - get { - return target_type; - } - } - public Expression Expr { get { return expr; } - set { - expr = value; - } } - public override Expression Resolve (TypeContainer tc) + public override Expression DoResolve (EmitContext ec) { - type = tc.LookupType (target_type, false); - eclass = ExprClass.Value; - - if (type == null) + probe_type = ec.TypeContainer.LookupType (ProbeType, false); + + if (probe_type == null) return null; - // - // FIXME: Unimplemented - // - throw new Exception ("FINISH ME"); + expr = expr.Resolve (ec); + + type = TypeManager.bool_type; + eclass = ExprClass.Value; + + return this; } - public override bool Emit (EmitContext ec) + public override void Emit (EmitContext ec) { - return true; + ILGenerator ig = ec.ig; + + expr.Emit (ec); + + if (Oper == Operator.Is){ + ig.Emit (OpCodes.Isinst, probe_type); + ig.Emit (OpCodes.Ldnull); + ig.Emit (OpCodes.Cgt_Un); + } else { + ig.Emit (OpCodes.Isinst, probe_type); + } + } + } + + // + // This represents a typecast in the source language. + // + // FIXME: Cast expressions have an unusual set of parsing + // rules, we need to figure those out. + // + public class Cast : Expression { + string target_type; + Expression expr; + Location loc; + + public Cast (string cast_type, Expression expr, Location loc) + { + this.target_type = cast_type; + this.expr = expr; + this.loc = loc; + } + + public string TargetType { + get { + return target_type; + } + } + + public Expression Expr { + get { + return expr; + } + set { + expr = value; + } + } + + public override Expression DoResolve (EmitContext ec) + { + expr = expr.Resolve (ec); + if (expr == null) + return null; + + type = ec.TypeContainer.LookupType (target_type, false); + eclass = ExprClass.Value; + + if (type == null) + return null; + + expr = ConvertExplicit (ec, expr, type, loc); + + return expr; + } + + public override void Emit (EmitContext ec) + { + // + // This one will never happen + // + throw new Exception ("Should not happen"); } } public class Binary : Expression { - public enum Operator { - Multiply, Divide, Modulo, - Add, Subtract, - ShiftLeft, ShiftRight, - LessThan, GreaterThan, LessOrEqual, GreaterOrEqual, - Equal, NotEqual, + public enum Operator : byte { + Multiply, Division, Modulus, + Addition, Subtraction, + LeftShift, RightShift, + LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual, + Equality, Inequality, BitwiseAnd, ExclusiveOr, BitwiseOr, @@ -1112,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) @@ -1120,7 +808,7 @@ namespace CIR { this.oper = oper; this.left = left; this.right = right; - this.location = loc; + this.loc = loc; } public Operator Oper { @@ -1159,29 +847,29 @@ namespace CIR { switch (oper){ case Operator.Multiply: return "*"; - case Operator.Divide: + case Operator.Division: return "/"; - case Operator.Modulo: + case Operator.Modulus: return "%"; - case Operator.Add: + case Operator.Addition: return "+"; - case Operator.Subtract: + case Operator.Subtraction: return "-"; - case Operator.ShiftLeft: + case Operator.LeftShift: return "<<"; - case Operator.ShiftRight: + case Operator.RightShift: return ">>"; case Operator.LessThan: return "<"; case Operator.GreaterThan: return ">"; - case Operator.LessOrEqual: + case Operator.LessThanOrEqual: return "<="; - case Operator.GreaterOrEqual: + case Operator.GreaterThanOrEqual: return ">="; - case Operator.Equal: + case Operator.Equality: return "=="; - case Operator.NotEqual: + case Operator.Inequality: return "!="; case Operator.BitwiseAnd: return "&"; @@ -1198,19 +886,19 @@ namespace CIR { return oper.ToString (); } - Expression ForceConversion (Expression expr, Type target_type) + Expression ForceConversion (EmitContext ec, Expression expr, Type target_type) { if (expr.Type == target_type) return expr; - return ConvertImplicit (expr, target_type); + 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){ // @@ -1218,9 +906,9 @@ namespace CIR { // conveted to type double. // if (r != TypeManager.double_type) - right = ConvertImplicit (right, TypeManager.double_type); + right = ConvertImplicit (ec, right, TypeManager.double_type, loc); if (l != TypeManager.double_type) - left = ConvertImplicit (left, TypeManager.double_type); + left = ConvertImplicit (ec, left, TypeManager.double_type, loc); type = TypeManager.double_type; } else if (l == TypeManager.float_type || r == TypeManager.float_type){ @@ -1229,22 +917,34 @@ namespace CIR { // converd to type float. // if (r != TypeManager.double_type) - right = ConvertImplicit (right, TypeManager.float_type); + right = ConvertImplicit (ec, right, TypeManager.float_type, loc); if (l != TypeManager.double_type) - left = ConvertImplicit (left, TypeManager.float_type); + left = ConvertImplicit (ec, left, TypeManager.float_type, loc); type = TypeManager.float_type; } else if (l == TypeManager.uint64_type || r == TypeManager.uint64_type){ + Expression e; + Type other; // // If either operand is of type ulong, the other operand is // converted to type ulong. or an error ocurrs if the other // operand is of type sbyte, short, int or long // - Type other = null; - if (l == TypeManager.uint64_type) - other = r; - else if (r == TypeManager.uint64_type) - other = l; + if (l == TypeManager.uint64_type){ + if (r != TypeManager.uint64_type && right is IntLiteral){ + e = TryImplicitIntConversion (l, (IntLiteral) right); + if (e != null) + right = e; + } + other = right.Type; + } else { + if (left is IntLiteral){ + e = TryImplicitIntConversion (r, (IntLiteral) left); + if (e != null) + left = e; + } + other = left.Type; + } if ((other == TypeManager.sbyte_type) || (other == TypeManager.short_type) || @@ -1252,11 +952,11 @@ namespace CIR { (other == TypeManager.int64_type)){ string oper = OperName (); - tc.RootContext.Report.Error (34, "Operator `" + OperName () - + "' is ambiguous on operands of type `" - + TypeManager.CSharpName (l) + "' " - + "and `" + TypeManager.CSharpName (r) - + "'"); + Error (34, loc, "Operator `" + OperName () + + "' is ambiguous on operands of type `" + + TypeManager.CSharpName (l) + "' " + + "and `" + TypeManager.CSharpName (r) + + "'"); } type = TypeManager.uint64_type; } else if (l == TypeManager.int64_type || r == TypeManager.int64_type){ @@ -1265,9 +965,9 @@ namespace CIR { // to type long. // if (l != TypeManager.int64_type) - left = ConvertImplicit (left, TypeManager.int64_type); + left = ConvertImplicit (ec, left, TypeManager.int64_type, loc); if (r != TypeManager.int64_type) - right = ConvertImplicit (right, TypeManager.int64_type); + right = ConvertImplicit (ec, right, TypeManager.int64_type, loc); type = TypeManager.int64_type; } else if (l == TypeManager.uint32_type || r == TypeManager.uint32_type){ @@ -1286,61 +986,81 @@ namespace CIR { if ((other == TypeManager.sbyte_type) || (other == TypeManager.short_type) || (other == TypeManager.int32_type)){ - left = ForceConversion (left, TypeManager.int64_type); - right = ForceConversion (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 (left, TypeManager.uint32_type); - right = ForceConversion (left, 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 (ec, left, TypeManager.decimal_type, loc); + if (r != TypeManager.decimal_type) + right = ConvertImplicit (ec, right, TypeManager.decimal_type, loc); + + type = TypeManager.decimal_type; } else { - left = ForceConversion (left, TypeManager.int32_type); - right = ForceConversion (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 () { - tc.RootContext.Report.Error ( - 19, - "Operator " + OperName () + " cannot be applied to operands of type `" + - TypeManager.CSharpName (left.Type) + "' and `" + - TypeManager.CSharpName (right.Type) + "'"); + 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 (right, TypeManager.int32_type); + e = ForceConversion (ec, right, TypeManager.int32_type); if (e == null){ - error19 (tc); + error19 (); return null; } right = e; - if (((e = ConvertImplicit (left, TypeManager.int32_type)) != null) || - ((e = ConvertImplicit (left, TypeManager.uint32_type)) != null) || - ((e = ConvertImplicit (left, TypeManager.int64_type)) != null) || - ((e = ConvertImplicit (left, TypeManager.uint64_type)) != 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; @@ -1352,65 +1072,147 @@ namespace CIR { string op = "op_" + oper; - left_expr = MemberLookup (tc.RootContext, l, 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 (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)); - right_expr = MemberLookup (tc.RootContext, r, op, false); + method = Invocation.OverloadResolve (ec, union, Arguments, loc); + if (method != null) { + MethodInfo mi = (MethodInfo) method; + type = mi.ReturnType; + return this; + } else { + error19 (); + return null; + } + } - if (left_expr != null || right_expr != null) { + // + // Step 2: Default operations on CLI native types. + // + + // Only perform numeric promotions on: + // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >= + // + if (oper == Operator.Addition){ // - // Now we need to form the union of these two sets and - // then call OverloadResolve on that. + // If any of the arguments is a string, cast to string // - MethodGroupExpr left_set = null, right_set = null; - int length1 = 0, length2 = 0; + 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 (ec, right, + TypeManager.object_type, loc); + } + type = TypeManager.string_type; + + Arguments = new ArrayList (); + Arguments.Add (new Argument (left, Argument.AType.Expression)); + Arguments.Add (new Argument (right, Argument.AType.Expression)); + + return this; + + } else if (r == TypeManager.string_type){ + // object + string + method = TypeManager.string_concat_object_object; + Arguments = new ArrayList (); + Arguments.Add (new Argument (left, Argument.AType.Expression)); + Arguments.Add (new Argument (right, Argument.AType.Expression)); - if (left_expr != null) { - left_set = (MethodGroupExpr) left_expr; - length1 = left_set.Methods.Length; + left = ConvertImplicit (ec, left, TypeManager.object_type, loc); + type = TypeManager.string_type; + + return this; } - if (right_expr != null) { - right_set = (MethodGroupExpr) right_expr; - length2 = right_set.Methods.Length; + // + // FIXME: is Delegate operator + (D x, D y) handled? + // + } + + if (oper == Operator.LeftShift || oper == Operator.RightShift) + return CheckShiftArguments (ec); + + if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){ + if (l != TypeManager.bool_type || r != TypeManager.bool_type){ + error19 (); + return null; } - MemberInfo [] mi = new MemberInfo [length1 + length2]; - if (left_set != null) - left_set.Methods.CopyTo (mi, 0); - if (right_set != null) - right_set.Methods.CopyTo (mi, length1); - - MethodGroupExpr union = new MethodGroupExpr (mi); - - Arguments = new ArrayList (); - Arguments.Add (new Argument (left, Argument.AType.Expression)); - Arguments.Add (new Argument (right, Argument.AType.Expression)); + type = TypeManager.bool_type; + return this; + } - - method = Invocation.OverloadResolve (union, Arguments, tc, location); - if (method != null) + 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; + } + } // - // Step 2: Default operations on CLI native types. - // - - // Only perform numeric promotions on: - // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >= + // We are dealing with numbers // - if (oper == Operator.ShiftLeft || oper == Operator.ShiftRight){ - return CheckShiftArguments (tc); - } else if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){ - if (l != TypeManager.bool_type || r != TypeManager.bool_type) - error19 (tc); - } else - 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){ @@ -1418,42 +1220,54 @@ namespace CIR { (l == TypeManager.uint32_type) || (l == TypeManager.int64_type) || (l == TypeManager.uint64_type))){ - error19 (tc); + error19 (); return null; } + type = l; } - if (oper == Operator.Equal || - oper == Operator.NotEqual || - oper == Operator.LessOrEqual || + if (oper == Operator.Equality || + oper == Operator.Inequality || + oper == Operator.LessThanOrEqual || oper == Operator.LessThan || - oper == Operator.GreaterOrEqual || + oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){ type = TypeManager.bool_type; } - + return this; } - public override Expression Resolve (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; - return ResolveOperator (tc); + if (left.Type == null) + throw new Exception ( + "Resolve returned non null, but did not set the type! (" + + left + ") at Line: " + loc.Row); + if (right.Type == null) + throw new Exception ( + "Resolve returned non null, but did not set the type! (" + + right + ") at Line: "+ loc.Row); + + eclass = ExprClass.Value; + + return ResolveOperator (ec); } public bool IsBranchable () { - if (oper == Operator.Equal || - oper == Operator.NotEqual || + if (oper == Operator.Equality || + oper == Operator.Inequality || oper == Operator.LessThan || oper == Operator.GreaterThan || - oper == Operator.LessOrEqual || - oper == Operator.GreaterOrEqual){ + oper == Operator.LessThanOrEqual || + oper == Operator.GreaterThanOrEqual){ return true; } else return false; @@ -1481,14 +1295,14 @@ namespace CIR { right.Emit (ec); switch (oper){ - case Operator.Equal: + case Operator.Equality: if (close_target) opcode = OpCodes.Beq_S; else opcode = OpCodes.Beq; break; - case Operator.NotEqual: + case Operator.Inequality: if (close_target) opcode = OpCodes.Bne_Un_S; else @@ -1509,14 +1323,14 @@ namespace CIR { opcode = OpCodes.Bgt; break; - case Operator.LessOrEqual: + case Operator.LessThanOrEqual: if (close_target) opcode = OpCodes.Ble_S; else opcode = OpCodes.Ble; break; - case Operator.GreaterOrEqual: + case Operator.GreaterThanOrEqual: if (close_target) opcode = OpCodes.Bge_S; else @@ -1531,7 +1345,7 @@ namespace CIR { ec.ig.Emit (opcode, target); } - public override bool Emit (EmitContext ec) + public override void Emit (EmitContext ec) { ILGenerator ig = ec.ig; Type l = left.Type; @@ -1549,8 +1363,8 @@ namespace CIR { ig.Emit (OpCodes.Call, (MethodInfo) method); else ig.Emit (OpCodes.Call, (ConstructorInfo) method); - - return true; + + return; } left.Emit (ec); @@ -1570,21 +1384,21 @@ namespace CIR { break; - case Operator.Divide: + case Operator.Division: if (l == TypeManager.uint32_type || l == TypeManager.uint64_type) opcode = OpCodes.Div_Un; else opcode = OpCodes.Div; break; - case Operator.Modulo: + case Operator.Modulus: if (l == TypeManager.uint32_type || l == TypeManager.uint64_type) opcode = OpCodes.Rem_Un; else opcode = OpCodes.Rem; break; - case Operator.Add: + case Operator.Addition: if (ec.CheckState){ if (l == TypeManager.int32_type || l == TypeManager.int64_type) opcode = OpCodes.Add_Ovf; @@ -1596,7 +1410,7 @@ namespace CIR { opcode = OpCodes.Add; break; - case Operator.Subtract: + case Operator.Subtraction: if (ec.CheckState){ if (l == TypeManager.int32_type || l == TypeManager.int64_type) opcode = OpCodes.Sub_Ovf; @@ -1608,19 +1422,19 @@ namespace CIR { opcode = OpCodes.Sub; break; - case Operator.ShiftRight: + case Operator.RightShift: opcode = OpCodes.Shr; break; - case Operator.ShiftLeft: + case Operator.LeftShift: opcode = OpCodes.Shl; break; - case Operator.Equal: + case Operator.Equality: opcode = OpCodes.Ceq; break; - case Operator.NotEqual: + case Operator.Inequality: ec.ig.Emit (OpCodes.Ceq); ec.ig.Emit (OpCodes.Ldc_I4_0); @@ -1635,14 +1449,14 @@ namespace CIR { opcode = OpCodes.Cgt; break; - case Operator.LessOrEqual: + case Operator.LessThanOrEqual: ec.ig.Emit (OpCodes.Cgt); ec.ig.Emit (OpCodes.Ldc_I4_0); opcode = OpCodes.Ceq; break; - case Operator.GreaterOrEqual: + case Operator.GreaterThanOrEqual: ec.ig.Emit (OpCodes.Clt); ec.ig.Emit (OpCodes.Ldc_I4_1); @@ -1669,19 +1483,43 @@ namespace CIR { } ig.Emit (opcode); + } - return true; + // + // 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 loc; - public Conditional (Expression expr, Expression trueExpr, Expression falseExpr) + public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l) { this.expr = expr; this.trueExpr = trueExpr; this.falseExpr = falseExpr; + this.loc = l; } public Expression Expr { @@ -1702,133 +1540,96 @@ namespace CIR { } } - public override Expression Resolve (TypeContainer tc) + public override Expression DoResolve (EmitContext ec) { - // FIXME: Implement; - throw new Exception ("Unimplemented"); - // return this; - } + expr = expr.Resolve (ec); - public override bool Emit (EmitContext ec) - { - return true; - } - } + if (expr.Type != TypeManager.bool_type) + expr = Expression.ConvertImplicitRequired ( + ec, expr, TypeManager.bool_type, loc); + + trueExpr = trueExpr.Resolve (ec); + falseExpr = falseExpr.Resolve (ec); - public class SimpleName : Expression { - public readonly string Name; - public readonly Location Location; - - public SimpleName (string name, Location l) - { - Name = name; - Location = l; - } + if (expr == null || trueExpr == null || falseExpr == null) + return null; - // - // 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+"'"); + if (trueExpr.Type == falseExpr.Type) + type = trueExpr.Type; + else { + Expression conv; + + // + // First, if an implicit conversion exists from trueExpr + // to falseExpr, then the result type is of type falseExpr.Type + // + conv = ConvertImplicit (ec, trueExpr, falseExpr.Type, loc); + if (conv != null){ + type = falseExpr.Type; + trueExpr = conv; + } else if ((conv = ConvertImplicit(ec, falseExpr,trueExpr.Type,loc))!= null){ + type = trueExpr.Type; + falseExpr = conv; + } else { + 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) + "'"); 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) - { - Expression e; - Report r = tc.RootContext.Report; - - e = MemberLookup (tc.RootContext, tc.TypeBuilder, Name, true); - if (e != null){ - if (e is TypeExpr) - return e; - else if (e is FieldExpr){ - FieldExpr fe = (FieldExpr) e; + if (expr is BoolLiteral){ + BoolLiteral bl = (BoolLiteral) expr; - if (!fe.FieldInfo.IsStatic) - fe.Instance = new This (); - } - - if ((tc.ModFlags & Modifiers.STATIC) != 0) - return MemberStaticCheck (r, e); + if (bl.Value) + return trueExpr; else - return e; + return falseExpr; } - - // - // Do step 3 of the Simple Name resolution. - // - // FIXME: implement me. - - r.Error (103, Location, "The name `" + Name + "' does not exist in the class `" + - tc.Name + "'"); - - return null; + + eclass = ExprClass.Value; + return this; } - - // - // SimpleName needs to handle a multitude of cases: - // - // simple_names and qualified_identifiers are placed on - // the tree equally. - // - public override Expression Resolve (TypeContainer tc) + + public override void Emit (EmitContext ec) { - if (Name.IndexOf (".") != -1) - return ResolveMemberAccess (tc, Name); - else - return ResolveSimpleName (tc); + ILGenerator ig = ec.ig; + Label false_target = ig.DefineLabel (); + Label end_target = ig.DefineLabel (); + + expr.Emit (ec); + ig.Emit (OpCodes.Brfalse, false_target); + trueExpr.Emit (ec); + ig.Emit (OpCodes.Br, end_target); + ig.MarkLabel (false_target); + falseExpr.Emit (ec); + ig.MarkLabel (end_target); } - public override bool Emit (EmitContext ec) + public override Expression Reduce (EmitContext ec) { - throw new Exception ("SimpleNames should be gone from the tree"); + expr = expr.Reduce (ec); + trueExpr = trueExpr.Reduce (ec); + falseExpr = falseExpr.Reduce (ec); + + if (!(expr is Literal && trueExpr is Literal && falseExpr is Literal)) + return this; + + BoolLiteral bl = (BoolLiteral) expr; + + if (bl.Value) + return trueExpr; + else + return falseExpr; } } - // - // A simple interface that should be implemeneted by LValues - // - public interface LValue { - void Store (ILGenerator ig); - } - - 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) { @@ -1839,24 +1640,28 @@ 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 Resolve (TypeContainer tc) + public override Expression DoResolve (EmitContext ec) { - VariableInfo vi = Block.GetVariableInfo (Name); + VariableInfo vi = VariableInfo; type = vi.VariableType; return this; } - public override bool Emit (EmitContext ec) + public override void Emit (EmitContext ec) { VariableInfo vi = VariableInfo; ILGenerator ig = ec.ig; int idx = vi.Idx; + vi.Used = true; + switch (idx){ case 0: ig.Emit (OpCodes.Ldloc_0); @@ -1865,31 +1670,26 @@ 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, idx); + if (idx <= 255) + ig.Emit (OpCodes.Ldloc_S, (byte) idx); else ig.Emit (OpCodes.Ldloc, idx); break; } - - return true; } - - public void Store (ILGenerator ig) + + public static void Store (ILGenerator ig, int idx) { - VariableInfo vi = VariableInfo; - int idx = vi.Idx; - switch (idx){ case 0: ig.Emit (OpCodes.Stloc_0); @@ -1908,74 +1708,117 @@ namespace CIR { break; default: - if (idx < 255) - ig.Emit (OpCodes.Stloc_S, idx); + if (idx <= 255) + ig.Emit (OpCodes.Stloc_S, (byte) idx); else ig.Emit (OpCodes.Stloc, idx); break; } } - } - public class ParameterReference : Expression, LValue { - public readonly Parameters Pars; - public readonly String Name; - public readonly int Idx; - - public ParameterReference (Parameters pars, int idx, string name) + public void EmitAssign (EmitContext ec, Expression source) { - Pars = pars; - Idx = idx; - Name = name; - eclass = ExprClass.Variable; - } + ILGenerator ig = ec.ig; + VariableInfo vi = VariableInfo; - public override Expression Resolve (TypeContainer tc) - { - Type [] types = Pars.GetParameterInfo (tc); + 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; + int idx = vi.Idx; + + vi.Used = true; + vi.Assigned = true; + + if (idx <= 255) + ec.ig.Emit (OpCodes.Ldloca_S, (byte) idx); + else + ec.ig.Emit (OpCodes.Ldloca, idx); + } + } + + 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) + { + Pars = pars; + Idx = idx; + Name = name; + eclass = ExprClass.Variable; + } + + public override Expression DoResolve (EmitContext ec) + { + Type [] types = Pars.GetParameterInfo (ec.TypeContainer); type = types [Idx]; + arg_idx = Idx; + if (!ec.IsStatic) + arg_idx++; + return this; } - public override bool Emit (EmitContext ec) + public override void Emit (EmitContext ec) { - if (Idx < 255) - ec.ig.Emit (OpCodes.Ldarg_S, Idx); + if (arg_idx <= 255) + ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx); else - ec.ig.Emit (OpCodes.Ldarg, Idx); - - return true; + ec.ig.Emit (OpCodes.Ldarg, arg_idx); } - public void Store (ILGenerator ig) + public void EmitAssign (EmitContext ec, Expression source) { - if (Idx < 255) - ig.Emit (OpCodes.Starg_S, Idx); + source.Emit (ec); + + if (arg_idx <= 255) + ec.ig.Emit (OpCodes.Starg_S, (byte) arg_idx); else - ig.Emit (OpCodes.Starg, Idx); + ec.ig.Emit (OpCodes.Starg, arg_idx); } + + public void AddressOf (EmitContext ec) + { + if (arg_idx <= 255) + ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx); + else + ec.ig.Emit (OpCodes.Ldarga, arg_idx); + } } // // 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 { @@ -1988,26 +1831,63 @@ namespace CIR { } } - public bool Resolve (TypeContainer tc) + public Type Type { + get { + return expr.Type; + } + } + + public Parameter.Modifier GetParameterModifier () { - expr = expr.Resolve (tc); + if (ArgType == AType.Ref) + return Parameter.Modifier.REF; + + if (ArgType == AType.Out) + return Parameter.Modifier.OUT; + return Parameter.Modifier.NONE; + } + + public static string FullDesc (Argument a) + { + return (a.ArgType == AType.Ref ? "ref " : + (a.ArgType == AType.Out ? "out " : "")) + + TypeManager.CSharpName (a.Expr.Type); + } + + public bool Resolve (EmitContext ec, Location loc) + { + expr = expr.Resolve (ec); + + if (ArgType == AType.Expression) + return expr != null; + + if (expr.ExprClass != ExprClass.Variable){ + Report.Error (206, loc, + "A property or indexer can not be passed as an out or ref " + + "parameter"); + return false; + } + return expr != null; } - public bool Emit (EmitContext ec) + public void Emit (EmitContext ec) { - return expr.Emit (ec); + if (ArgType == AType.Ref || ArgType == AType.Out) + ((IMemoryLocation)expr).AddressOf (ec); + else + expr.Emit (ec); } } // // Invocation of methods or delegates. // - public class Invocation : Expression { + public class Invocation : ExpressionStatement { public readonly ArrayList Arguments; - public readonly Location Location; - + Location loc; + Expression expr; MethodBase method = null; @@ -2029,7 +1909,7 @@ namespace CIR { { this.expr = expr; Arguments = arguments; - Location = l; + loc = l; } public Expression Expr { @@ -2038,106 +1918,21 @@ namespace CIR { } } - /// - /// Computes whether Argument `a' and the Type t of the ParameterInfo `pi' are - /// compatible, and if so, how good is the match (in terms of - /// "better conversions" (7.4.2.3). - /// - /// 0 is the best possible match. - /// -1 represents a type mismatch. - /// -2 represents a ref/out mismatch. - /// - static int Badness (Argument a, Type t) - { - Expression argument_expr = a.Expr; - Type argument_type = argument_expr.Type; - - if (argument_type == null){ - throw new Exception ("Expression of type " + a.Expr + " does not resolve its type"); - } - - if (t == argument_type) - return 0; - - // - // Now probe whether an implicit constant expression conversion - // can be used. - // - // An implicit constant expression conversion permits the following - // conversions: - // - // * A constant-expression of type `int' can be converted to type - // sbyte, byute, short, ushort, uint, ulong provided the value of - // of the expression is withing the range of the destination type. - // - // * A constant-expression of type long can be converted to type - // ulong, provided the value of the constant expression is not negative - // - // FIXME: Note that this assumes that constant folding has - // taken place. We dont do constant folding yet. - // - - if (argument_type == TypeManager.int32_type && argument_expr is IntLiteral){ - IntLiteral ei = (IntLiteral) argument_expr; - int value = ei.Value; - - if (t == TypeManager.sbyte_type){ - if (value >= SByte.MinValue && value <= SByte.MaxValue) - return 1; - } else if (t == TypeManager.byte_type){ - if (Byte.MinValue >= 0 && value <= Byte.MaxValue) - return 1; - } else if (t == TypeManager.short_type){ - if (value >= Int16.MinValue && value <= Int16.MaxValue) - return 1; - } else if (t == TypeManager.ushort_type){ - if (value >= UInt16.MinValue && value <= UInt16.MaxValue) - return 1; - } else if (t == TypeManager.uint32_type){ - // - // we can optimize this case: a positive int32 - // always fits on a uint32 - // - if (value >= 0) - return 1; - } else if (t == TypeManager.uint64_type){ - // - // we can optimize this case: a positive int32 - // always fits on a uint64 - // - if (value >= 0) - return 1; - } - } else if (argument_type == TypeManager.int64_type && argument_expr is LongLiteral){ - LongLiteral ll = (LongLiteral) argument_expr; - - if (t == TypeManager.uint64_type){ - if (ll.Value > 0) - return 1; - } - } - - // FIXME: Implement user-defined implicit conversions here. - // FIXME: Implement better conversion here. - - return -1; - } - // // 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; @@ -2150,13 +1945,19 @@ namespace CIR { } } - static bool ConversionExists (Type from, Type to, TypeContainer tc) + // + // Tells whether a user defined conversion from Type `from' to + // Type `to' exists. + // + // FIXME: we could implement a cache here. + // + static bool ConversionExists (EmitContext ec, Type from, Type to, Location loc) { // Locate user-defined implicit operators Expression mg; - mg = MemberLookup (tc.RootContext, to, "implicit", false); + mg = MemberLookup (ec, to, "op_Implicit", false, loc); if (mg != null) { MethodGroupExpr me = (MethodGroupExpr) mg; @@ -2171,7 +1972,7 @@ namespace CIR { } } - mg = MemberLookup (tc.RootContext, from, "implicit", false); + mg = MemberLookup (ec, from, "op_Implicit", false, loc); if (mg != null) { MethodGroupExpr me = (MethodGroupExpr) mg; @@ -2179,9 +1980,9 @@ namespace CIR { for (int i = me.Methods.Length; i > 0;) { i--; MethodBase mb = me.Methods [i]; - Method method = (Method) TypeContainer.LookupMethodByBuilder (mb); + MethodInfo mi = (MethodInfo) mb; - if (method.GetReturnType (tc) == to) + if (mi.ReturnType == to) return true; } } @@ -2194,19 +1995,18 @@ namespace CIR { // Returns : 1 if a->p is better // 0 if a->q or neither is better // - static int BetterConversion (Argument a, Type p, Type q, TypeContainer tc) + 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) throw new Exception ("Expression of type " + a.Expr + " does not resolve its type"); - - + if (p == q) return 0; - + if (argument_type == p) return 1; @@ -2231,7 +2031,7 @@ namespace CIR { // taken place. We dont do constant folding yet. // - if (argument_type == TypeManager.int32_type && argument_expr is IntLiteral){ + if (argument_expr is IntLiteral){ IntLiteral ei = (IntLiteral) argument_expr; int value = ei.Value; @@ -2271,16 +2071,29 @@ namespace CIR { } } - // User-defined Implicit conversions come here - - if (q != null) - if (ConversionExists (p, q, tc) == true && - ConversionExists (q, p, tc) == false) + if (q == null) { + + Expression tmp; + + if (use_standard) + tmp = ConvertImplicitStandard (ec, argument_expr, p, loc); + else + tmp = ConvertImplicit (ec, argument_expr, p, loc); + + if (tmp != null) return 1; - + else + return 0; + + } + + if (ConversionExists (ec, p, q, loc) == true && + ConversionExists (ec, q, p, loc) == false) + return 1; + if (p == TypeManager.sbyte_type) if (q == TypeManager.byte_type || q == TypeManager.ushort_type || - q == TypeManager.uint32_type || q == TypeManager.uint64_type) + q == TypeManager.uint32_type || q == TypeManager.uint64_type) return 1; if (p == TypeManager.short_type) @@ -2304,7 +2117,9 @@ namespace CIR { // 0 if candidate ain't better // 1 if candidate is better than the current best match // - static int BetterFunction (ArrayList args, MethodBase candidate, MethodBase best, TypeContainer tc) + static int BetterFunction (EmitContext ec, ArrayList args, + MethodBase candidate, MethodBase best, + bool use_standard, Location loc) { ParameterData candidate_pd = GetParameterData (candidate); ParameterData best_pd; @@ -2326,11 +2141,11 @@ namespace CIR { Argument a = (Argument) args [j]; - x = BetterConversion (a, candidate_pd.ParameterType (j), null, tc); + x = BetterConversion ( + ec, a, candidate_pd.ParameterType (j), null, + use_standard, loc); - if (x > 0) - continue; - else + if (x <= 0) break; } @@ -2354,11 +2169,12 @@ namespace CIR { Argument a = (Argument) args [j]; - x = BetterConversion (a, candidate_pd.ParameterType (j), - best_pd.ParameterType (j), tc); - y = BetterConversion (a, best_pd.ParameterType (j), - candidate_pd.ParameterType (j), tc); - + 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; } @@ -2376,19 +2192,173 @@ 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 (")"); return sb.ToString (); } + + public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2) + { + MemberInfo [] miset; + MethodGroupExpr union; + + if (mg1 != null && mg2 != null) { + + MethodGroupExpr left_set = null, right_set = null; + int length1 = 0, length2 = 0; + + left_set = (MethodGroupExpr) mg1; + length1 = left_set.Methods.Length; + + right_set = (MethodGroupExpr) mg2; + length2 = right_set.Methods.Length; + + ArrayList common = new ArrayList (); + + 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]); + } + } + + 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); + + 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--; + + Argument a = (Argument) arguments [i]; + + Parameter.Modifier a_mod = a.GetParameterModifier (); + Parameter.Modifier p_mod = pd.ParameterModifier (i); + + if (a_mod == p_mod) { + + if (a_mod == Parameter.Modifier.NONE) + if (!StandardConversionExists (a.Type, pd.ParameterType (i))) + return false; + + if (a_mod == Parameter.Modifier.REF || + a_mod == Parameter.Modifier.OUT) + if (pd.ParameterType (i) != a.Type) + return false; + } else + return false; + } + + return true; + } + + // // Find the Applicable Function Members (7.4.2.1) // @@ -2398,12 +2368,19 @@ namespace CIR { // // Arguments: ArrayList containing resolved Argument objects. // + // loc: The location if we want an error to be reported, or a Null + // location for "probing" purposes. + // + // 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 (MethodGroupExpr me, ArrayList Arguments, - TypeContainer tc, Location loc) + public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me, + ArrayList Arguments, Location loc, + bool use_standard) { ArrayList afm = new ArrayList (); int best_match_idx = -1; @@ -2414,8 +2391,12 @@ namespace CIR { i--; MethodBase candidate = me.Methods [i]; int x; - - x = BetterFunction (Arguments, candidate, method, tc); + + // 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; @@ -2424,81 +2405,158 @@ namespace CIR { method = me.Methods [best_match_idx]; } } - - if (best_match_idx != -1) - return method; - - // 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 (Arguments == null) argument_count = 0; else argument_count = Arguments.Count; - - ParameterData pd = null; - for (int i = me.Methods.Length; i > 0;) { - i--; - MethodBase mb = me.Methods [i]; - pd = GetParameterData (mb); + // + // 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) { - if (pd.Count == argument_count) { - best_match_idx = i; - method = me.Methods [best_match_idx]; - break; - } else - continue; + 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; + } + } } - if (best_match_idx == -1) - return null; + // + // Now we see if we can at least find a method with the same number of arguments + // + ParameterData pd; + + if (best_match_idx == -1) { + + for (int i = me.Methods.Length; i > 0;) { + i--; + MethodBase mb = me.Methods [i]; + pd = GetParameterData (mb); + + if (pd.Count == argument_count) { + best_match_idx = i; + method = me.Methods [best_match_idx]; + break; + } 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; - - Expression conv = ConvertImplicit (a.Expr, pd.ParameterType (j)); - - if (conv == null) { - tc.RootContext.Report.Error (1502, loc, - "The best overloaded match for method '" + FullMethodDesc (method) + - "' has some invalid arguments"); - tc.RootContext.Report.Error (1503, loc, - "Argument " + (j+1) + - " : Cannot convert from '" + TypeManager.CSharpName (a.Expr.Type) - + "' to '" + TypeManager.CSharpName (pd.ParameterType (j)) + "'"); - return null; - } + Type parameter_type = pd.ParameterType (j); // - // Update the argument with the implicit conversion + // Note that we need to compare against the element type + // when we have a params method // - if (a_expr != conv) - a.Expr = conv; + if (pd.ParameterModifier (pd_count - 1) == Parameter.Modifier.PARAMS) { + if (j >= pd_count - 1) + parameter_type = pd.ParameterType (pd_count - 1).GetElementType (); + } + + if (a.Type != parameter_type){ + Expression conv; + + if (use_standard) + conv = ConvertImplicitStandard (ec, a_expr, parameter_type, Location.Null); + else + conv = ConvertImplicit (ec, a_expr, parameter_type, Location.Null); + + if (conv == null) { + 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; + } + + + + // + // Update the argument with the implicit conversion + // + if (a_expr != conv) + a.Expr = conv; + + // FIXME : For the case of params methods, we need to actually instantiate + // an array and initialize it with the argument values etc etc. + + } + + if (a.GetParameterModifier () != pd.ParameterModifier (j) && + pd.ParameterModifier (j) != Parameter.Modifier.PARAMS) { + if (!Location.IsNull (loc)) { + Error (1502, loc, + "The best overloaded match for method '" + FullMethodDesc (method)+ + "' has some invalid arguments"); + Error (1503, loc, + "Argument " + (j+1) + + ": Cannot convert from '" + Argument.FullDesc (a) + + "' to '" + pd.ParameterDesc (j) + "'"); + } + return null; + } + + } return method; } - + + public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me, + ArrayList Arguments, Location loc) + { + return OverloadResolve (ec, me, Arguments, loc, false); + } - public override Expression Resolve (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, 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; } @@ -2510,221 +2568,717 @@ namespace CIR { --i; Argument a = (Argument) Arguments [i]; - if (!a.Resolve (tc)) + if (!a.Resolve (ec, loc)) return null; } } - method = OverloadResolve ((MethodGroupExpr) this.expr, Arguments, tc, Location); + method = OverloadResolve (ec, (MethodGroupExpr) this.expr, Arguments, loc); + + if (method == null){ + Error (-6, loc, + "Could not find any applicable function for this argument list"); + return null; + } + + 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); - if (method == null){ - tc.RootContext.Report.Error (-6, Location, - "Could not find any applicable function for this argument list"); - return null; - } + string val = sb.ToString (); - if (method is MethodInfo) - type = ((MethodInfo)method).ReturnType; + return val.Substring (0, val.LastIndexOf ("[")); + } - return this; + void error178 () + { + Report.Error (178, loc, "Incorrectly structured array initializer"); } - public static void EmitArguments (EmitContext ec, MethodBase method, ArrayList Arguments) + bool ValidateInitializers (EmitContext ec) { - int top; + if (Initializers == null) + return true; - if (Arguments != null) - top = Arguments.Count; - else - top = 0; + Type underlying_type = ec.TypeContainer.LookupType (RequestedType, false); - for (int i = 0; i < top; i++){ - Argument a = (Argument) Arguments [i]; + ArrayList probe = Initializers; - Console.WriteLine ("Perform the actual type widening of arguments here for things like: void fn (sbyte s); ... fn (1)"); - - a.Emit (ec); - } - } + 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 bool Emit (EmitContext ec) - { - bool is_static = method.IsStatic; - - if (!is_static){ - MethodGroupExpr mg = (MethodGroupExpr) this.expr; + if (probe == null) { + error178 (); + return false; + } + + if (value != probe.Count) { + error178 (); + return false; + } - if (mg.InstanceExpression == null){ - throw new Exception ("Internal compiler error. Should check in the method groups for static/instance"); - } + 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); - 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; + } + } - if (method is MethodInfo){ - return ((MethodInfo)method).ReturnType != TypeManager.void_type; } else { // - // Constructors do not leave any values on the stack + // Here is where we update dimension info in the case + // that the user skips doing that // - return false; - } - } - } - public class New : Expression { + Arguments = new ArrayList (); + + for (probe = Initializers; probe != null; ) { + Expression e = new IntLiteral (probe.Count); - public enum NType { - Object, - Array - }; + Arguments.Add (new Argument (e, Argument.AType.Expression)); - 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; + 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); - Location Location; - MethodBase method = null; + Expression conv = ConvertImplicitRequired (ec, tmp, + underlying_type, loc); - public New (string requested_type, ArrayList arguments, Location loc) - { - RequestedType = requested_type; - Arguments = arguments; - NewType = NType.Object; - Location = loc; - } + if (conv == null) + return false; + } + + probe = null; + } + } - 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; + if (Arguments.Count != dimensions) { + error178 (); + return false; + } + } + + return true; } - public override Expression Resolve (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.RootContext, type, ".ctor", false, - MemberTypes.Constructor, AllBindingsFlags); + string element_type = FormElementType (RequestedType, arg_count, Rank); - if (! (ml is MethodGroupExpr)){ - // - // FIXME: Find proper error - // - report118 (tc, 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 (arg_count == 1) { + IsOneDimensional = true; + eclass = ExprClass.Value; + return this; } + + IsBuiltinType = TypeManager.IsBuiltinType (type); - if (Arguments != null){ - for (int i = Arguments.Count; i > 0;){ - --i; - Argument a = (Argument) Arguments [i]; + 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 { - if (!a.Resolve (tc)) - return null; + ModuleBuilder mb = ec.TypeContainer.RootContext.ModuleBuilder; + + 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; + } + } - method = Invocation.OverloadResolve ((MethodGroupExpr) ml, Arguments, tc, Location); + public override void Emit (EmitContext ec) + { + 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 (method == null) { - tc.RootContext.Report.Error (-6, - "New invocation: Can not find a constructor for this argument list"); - return null; + if (IsBuiltinType) + ig.Emit (OpCodes.Newobj, (ConstructorInfo) method); + else + ig.Emit (OpCodes.Newobj, (MethodInfo) method); } - return this; - } + 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); - public override bool Emit (EmitContext ec) + ig.Emit (OpCodes.Dup); + ig.Emit (OpCodes.Ldtoken, fb); + ig.Emit (OpCodes.Call, TypeManager.void_initializearray_array_fieldhandle); + } + } + + public override void EmitStatement (EmitContext ec) { - Invocation.EmitArguments (ec, method, Arguments); - ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) method); - return true; + Emit (ec); + ec.ig.Emit (OpCodes.Pop); } + } - + // // Represents the `this' construct // - public class This : Expression, LValue { - public override Expression Resolve (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; } - public override bool Emit (EmitContext ec) + public override void Emit (EmitContext ec) { ec.ig.Emit (OpCodes.Ldarg_0); - return true; } - public void Store (ILGenerator ig) + public void EmitAssign (EmitContext ec, Expression source) { - // - // Assignment to the "this" variable - // - ig.Emit (OpCodes.Starg, 0); + source.Emit (ec); + ec.ig.Emit (OpCodes.Starg, 0); + } + + public void AddressOf (EmitContext ec) + { + ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0); } } + // + // 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 Resolve (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 bool Emit (EmitContext ec) + 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); } } @@ -2736,14 +3290,14 @@ namespace CIR { this.QueriedType = queried_type; } - public override Expression Resolve (TypeContainer tc) + public override Expression DoResolve (EmitContext ec) { // FIXME: Implement; throw new Exception ("Unimplemented"); // return this; } - public override bool Emit (EmitContext ec) + public override void Emit (EmitContext ec) { throw new Exception ("Implement me"); } @@ -2753,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 { @@ -2765,384 +3321,603 @@ 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 Resolve (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.RootContext, 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; + } - if (expr is LocalVariableReference || - expr is ParameterReference || - expr is FieldExpr) - mg.InstanceExpression = expr; + return member_lookup; + } + + // + // 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 bool Emit (EmitContext ec) + public override void Emit (EmitContext ec) { - throw new Exception ("Implement me"); + throw new Exception ("Should not happen I think"); } } - // - // 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 Resolve (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 bool Emit (EmitContext ec) + 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 Resolve (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 bool 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; } - } - - override public Expression Resolve (TypeContainer tc) - { - return this; - } - override public bool Emit (EmitContext ec) - { - throw new Exception ("This should never be reached"); + return true; } - } - - public class BuiltinTypeAccess : Expression { - public readonly string AccessBase; - public readonly string Method; - - public BuiltinTypeAccess (string type, string method) + + public override Expression DoResolve (EmitContext ec) { - System.Console.WriteLine ("DUDE! This type should be fully resolved!"); - AccessBase = type; - Method = method; + 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); } - public override Expression Resolve (TypeContainer tc) + public override Expression DoResolveLValue (EmitContext ec, Expression right_side) { - // FIXME: Implement; - throw new Exception ("Unimplemented"); - // return this; - } + if (!CommonResolve (ec)) + return null; - public override bool Emit (EmitContext ec) + 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 ("Unimplemented"); + 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 Resolve (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"); - } - - Instance = Instance.Resolve (tc); - if (Instance == null) - return null; - + if (ea.Expr.ExprClass != ExprClass.Variable) { + report118 (ea.loc, ea.Expr, "variable"); + return null; } - return this; - } - override public bool Emit (EmitContext ec) - { - ILGenerator ig = ec.ig; + Type t = ea.Expr.Type; - if (FieldInfo.IsStatic) - ig.Emit (OpCodes.Ldsfld, FieldInfo); - else { - Instance.Emit (ec); - - ig.Emit (OpCodes.Ldfld, FieldInfo); + 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 true; + return this; } - public void Store (ILGenerator ig) - { - if (FieldInfo.IsStatic) - ig.Emit (OpCodes.Stsfld, FieldInfo); + // + // 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.Stfld, FieldInfo); + 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); } - } - - // - // Fully resolved expression that evaluates to a Property - // - public class PropertyExpr : Expression { - public readonly PropertyInfo PropertyInfo; - public readonly bool IsStatic; - public PropertyExpr (PropertyInfo pi) + public override void Emit (EmitContext ec) { - PropertyInfo = pi; - eclass = ExprClass.PropertyAccess; - IsStatic = false; - - MethodBase [] acc = pi.GetAccessors (); + int rank = ea.Expr.Type.GetArrayRank (); + ILGenerator ig = ec.ig; - for (int i = 0; i < acc.Length; i++) - if (acc [i].IsStatic) - IsStatic = true; + ea.Expr.Emit (ec); - type = pi.PropertyType; - } + foreach (Argument a in ea.Arguments) + a.Expr.Emit (ec); - override public Expression Resolve (TypeContainer tc) - { - // We are born in resolved state. - return this; + if (rank == 1) + EmitLoadOpcode (ig, type); + else { + ModuleBuilder mb = ec.TypeContainer.RootContext.ModuleBuilder; + Type [] args = new Type [ea.Arguments.Count]; + MethodInfo get; + + int i = 0; + + foreach (Argument a in ea.Arguments) + args [i++] = a.Type; + + get = mb.GetArrayMethod ( + ea.Expr.Type, "Get", + CallingConventions.HasThis | + CallingConventions.Standard, + type, args); + + ig.Emit (OpCodes.Call, get); + } } - override public bool Emit (EmitContext ec) + public void EmitAssign (EmitContext ec, Expression source) { - // FIXME: Implement; - throw new Exception ("Unimplemented"); - } - } + int rank = ea.Expr.Type.GetArrayRank (); + ILGenerator ig = ec.ig; - // - // Fully resolved expression that evaluates to a Property - // - public class EventExpr : Expression { - public readonly EventInfo EventInfo; - - public EventExpr (EventInfo ei) - { - EventInfo = ei; - eclass = ExprClass.EventAccess; - } + ea.Expr.Emit (ec); - override public Expression Resolve (TypeContainer tc) - { - // We are born in resolved state. - return this; - } + foreach (Argument a in ea.Arguments) + a.Expr.Emit (ec); - override public bool Emit (EmitContext ec) - { - throw new Exception ("Implement me"); - // FIXME: Implement. + source.Emit (ec); + + Type t = source.Type; + if (rank == 1) + EmitStoreOpcode (ig, t); + else { + ModuleBuilder mb = ec.TypeContainer.RootContext.ModuleBuilder; + Type [] args = new Type [ea.Arguments.Count + 1]; + MethodInfo set; + + int i = 0; + + foreach (Argument a in ea.Arguments) + args [i++] = a.Type; + + args [i] = type; + + set = mb.GetArrayMethod ( + ea.Expr.Type, "Set", + CallingConventions.HasThis | + CallingConventions.Standard, + TypeManager.void_type, args); + + ig.Emit (OpCodes.Call, set); + } } } - - public class CheckedExpr : Expression { - - public Expression Expr; + class Indexers { + public ArrayList getters, setters; + static Hashtable map; - public CheckedExpr (Expression e) + static Indexers () { - Expr = e; + map = new Hashtable (); } - public override Expression Resolve (TypeContainer tc) + Indexers (MemberInfo [] mi) { - Expr = Expr.Resolve (tc); - - if (Expr == null) - return null; + foreach (PropertyInfo property in mi){ + MethodInfo get, set; + + get = property.GetGetMethod (true); + if (get != null){ + if (getters == null) + getters = new ArrayList (); - eclass = Expr.ExprClass; - type = Expr.Type; - return this; + getters.Add (get); + } + + set = property.GetSetMethod (true); + if (set != null){ + if (setters == null) + setters = new ArrayList (); + setters.Add (set); + } + } } - - public override bool Emit (EmitContext ec) + + static public Indexers GetIndexersForType (Type t, TypeManager tm, Location loc) { - bool last_check = ec.CheckState; - bool v; + Indexers ix = (Indexers) map [t]; + string p_name = TypeManager.IndexerPropertyName (t); - ec.CheckState = true; + 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; + } - v = Expr.Emit (ec); + ix = new Indexers (mi); + map [t] = ix; - ec.CheckState = last_check; - - return v; + return ix; } - } - public class UnCheckedExpr : Expression { - - public Expression Expr; - - public UnCheckedExpr (Expression e) + // + // Expressions that represent an indexer call. + // + public class IndexerAccess : Expression, IAssignMethod { + // + // Points to our "data" repository + // + ElementAccess ea; + MethodInfo get, set; + Indexers ilist; + ArrayList set_arguments; + + public IndexerAccess (ElementAccess ea_data) { - Expr = e; + ea = ea_data; + eclass = ExprClass.Value; } - public override Expression Resolve (TypeContainer tc) + public override Expression DoResolve (EmitContext ec) { - Expr = Expr.Resolve (tc); + 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. - if (Expr == null) + if (ilist == null) + ilist = Indexers.GetIndexersForType ( + indexer_type, ec.TypeContainer.RootContext.TypeManager, ea.loc); + + + // + // Step 2: find the proper match + // + if (ilist != null && ilist.getters != null && ilist.getters.Count > 0) + get = (MethodInfo) Invocation.OverloadResolve ( + ec, new MethodGroupExpr (ilist.getters), ea.Arguments, ea.loc); + + 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 bool Emit (EmitContext ec) + public override Expression DoResolveLValue (EmitContext ec, Expression right_side) { - bool last_check = ec.CheckState; - bool v; - - ec.CheckState = false; - - v = Expr.Emit (ec); + Type indexer_type = ea.Expr.Type; + Type right_type = right_side.Type; - ec.CheckState = last_check; + if (ilist == null) + ilist = Indexers.GetIndexersForType ( + indexer_type, ec.TypeContainer.RootContext.TypeManager, ea.loc); + + 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)); - return v; + 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; + } + + type = TypeManager.void_type; + eclass = ExprClass.IndexerAccess; + return this; } - } - - 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 Resolve (TypeContainer tc) - { - // FIXME: Implement; - throw new Exception ("Unimplemented"); - // return this; - } - - public override bool 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 }; @@ -3159,16 +3934,83 @@ namespace CIR { } - public override Expression Resolve (TypeContainer tc) + public override Expression DoResolve (EmitContext ec) { // FIXME: Implement; throw new Exception ("Unimplemented"); // return this; } - public override bool Emit (EmitContext ec) + public override void Emit (EmitContext ec) { throw new Exception ("Unimplemented"); } } + + // + // 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; + Expression source; + + public UserCast (MethodInfo method, Expression source) + { + this.method = method; + this.source = source; + type = method.ReturnType; + eclass = ExprClass.Value; + } + + public override Expression DoResolve (EmitContext ec) + { + // + // We are born fully resolved + // + return this; + } + + public override void Emit (EmitContext ec) + { + ILGenerator ig = ec.ig; + + source.Emit (ec); + + if (method is MethodInfo) + ig.Emit (OpCodes.Call, (MethodInfo) method); + else + ig.Emit (OpCodes.Call, (ConstructorInfo) method); + + } + + } }