2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) 2001 Ximian, Inc.
10 using System.Collections;
11 using System.Diagnostics;
13 using System.Reflection;
14 using System.Reflection.Emit;
17 // The ExprClass class contains the is used to pass the
18 // classification of an expression (value, variable, namespace,
19 // type, method group, property access, event access, indexer access,
22 public enum ExprClass {
26 Variable, // Every Variable should implement LValue
37 // Base class for expressions
39 public abstract class Expression {
40 protected ExprClass eclass;
53 public ExprClass ExprClass {
63 public abstract Expression Resolve (TypeContainer tc);
66 // Return value indicates whether a value is left on the stack or not
68 public abstract bool Emit (EmitContext ec);
71 // Protected constructor. Only derivate types should
72 // be able to be created
75 protected Expression ()
77 eclass = ExprClass.Invalid;
82 // Returns a fully formed expression after a MemberLookup
84 static Expression ExprClassFromMemberInfo (MemberInfo mi)
87 return new EventExpr ((EventInfo) mi);
88 } else if (mi is FieldInfo){
89 return new FieldExpr ((FieldInfo) mi);
90 } else if (mi is PropertyInfo){
91 return new PropertyExpr ((PropertyInfo) mi);
92 } else if (mi is Type)
93 return new TypeExpr ((Type) mi);
99 // FIXME: Probably implement a cache for (t,name,current_access_set)?
101 // FIXME: We need to cope with access permissions here, or this wont
104 // This code could use some optimizations, but we need to do some
105 // measurements. For example, we could use a delegate to `flag' when
106 // something can not any longer be a method-group (because it is something
110 // If the return value is an Array, then it is an array of
113 // If the return value is an MemberInfo, it is anything, but a Method
117 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
118 // the arguments here and have MemberLookup return only the methods that
119 // match the argument count/type, unlike we are doing now (we delay this
122 // This is so we can catch correctly attempts to invoke instance methods
123 // from a static body (scan for error 120 in ResolveSimpleName).
125 public static Expression MemberLookup (RootContext rc, Type t, string name,
126 bool same_type, MemberTypes mt, BindingFlags bf)
129 bf |= BindingFlags.NonPublic;
131 MemberInfo [] mi = rc.TypeManager.FindMembers (t, mt, bf, Type.FilterName, name);
136 if (mi.Length == 1 && !(mi [0] is MethodBase))
137 return Expression.ExprClassFromMemberInfo (mi [0]);
139 for (int i = 0; i < mi.Length; i++)
140 if (!(mi [i] is MethodBase)){
141 rc.Report.Error (-5, "Do not know how to reproduce this case: " +
142 "Methods and non-Method with the same name, report this please");
144 for (i = 0; i < mi.Length; i++){
145 Type tt = mi [i].GetType ();
147 Console.WriteLine (i + ": " + mi [i]);
148 while (tt != TypeManager.object_type){
149 Console.WriteLine (tt);
155 return new MethodGroupExpr (mi);
158 public const MemberTypes AllMemberTypes =
159 MemberTypes.Constructor |
163 MemberTypes.NestedType |
164 MemberTypes.Property;
166 public const BindingFlags AllBindingsFlags =
167 BindingFlags.Public |
168 BindingFlags.Static |
169 BindingFlags.Instance;
171 public static Expression MemberLookup (RootContext rc, Type t, string name,
174 return MemberLookup (rc, t, name, same_type, AllMemberTypes, AllBindingsFlags);
178 // Resolves the E in `E.I' side for a member_access
180 // This is suboptimal and should be merged with ResolveMemberAccess
182 static Expression ResolvePrimary (TypeContainer tc, string name)
184 int dot_pos = name.LastIndexOf (".");
186 if (tc.RootContext.IsNamespace (name))
187 return new NamespaceExpr (name);
191 Type t = tc.LookupType (name, false);
194 return new TypeExpr (t);
200 static public Expression ResolveMemberAccess (TypeContainer tc, string name)
203 int dot_pos = name.LastIndexOf (".");
204 string left = name.Substring (0, dot_pos);
205 string right = name.Substring (dot_pos + 1);
207 left_e = ResolvePrimary (tc, left);
211 switch (left_e.ExprClass){
213 return MemberLookup (tc.RootContext,
215 left_e.Type == tc.TypeBuilder);
217 case ExprClass.Namespace:
218 case ExprClass.PropertyAccess:
219 case ExprClass.IndexerAccess:
220 case ExprClass.Variable:
221 case ExprClass.Value:
222 case ExprClass.Nothing:
223 case ExprClass.EventAccess:
224 case ExprClass.MethodGroup:
225 case ExprClass.Invalid:
226 tc.RootContext.Report.Error (-1000,
227 "Internal compiler error, should have " +
228 "got these handled before");
235 static public Expression ImplicitReferenceConversion (Expression expr, Type target_type)
237 Type expr_type = expr.Type;
239 if (target_type == TypeManager.object_type) {
240 if (expr_type.IsClass)
241 return new EmptyCast (expr, target_type);
242 if (expr_type.IsValueType)
243 return new BoxedCast (expr, target_type);
244 } else if (expr_type.IsSubclassOf (target_type))
245 return new EmptyCast (expr, target_type);
247 // FIXME: missing implicit reference conversions:
249 // from any class-type S to any interface-type T.
250 // from any interface type S to interface-type T.
251 // from an array-type S to an array-type of type T
252 // from an array-type to System.Array
253 // from any delegate type to System.Delegate
254 // from any array-type or delegate type into System.ICloneable.
255 // from the null type to any reference-type.
263 // Converts implicitly the resolved expression `expr' into the
264 // `target_type'. It returns a new expression that can be used
265 // in a context that expects a `target_type'.
267 static public Expression ConvertImplicit (Expression expr, Type target_type)
269 Type expr_type = expr.Type;
271 if (expr_type == target_type){
272 Console.WriteLine ("Hey, ConvertImplicit was called with no job to do");
277 // Step 1: Perform implicit conversions as found on expr.Type
281 // Step 2: Built-in conversions.
283 if (expr_type == TypeManager.sbyte_type){
285 // From sbyte to short, int, long, float, double.
287 if (target_type == TypeManager.int32_type)
288 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
289 if (target_type == TypeManager.int64_type)
290 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
291 if (target_type == TypeManager.double_type)
292 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
293 if (target_type == TypeManager.float_type)
294 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
295 if (target_type == TypeManager.short_type)
296 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
297 } else if (expr_type == TypeManager.byte_type){
299 // From byte to short, ushort, int, uint, long, ulong, float, double
301 if ((target_type == TypeManager.short_type) ||
302 (target_type == TypeManager.ushort_type) ||
303 (target_type == TypeManager.int32_type) ||
304 (target_type == TypeManager.uint32_type))
305 return new EmptyCast (expr, target_type);
307 if (target_type == TypeManager.uint64_type)
308 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
309 if (target_type == TypeManager.int64_type)
310 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
312 if (target_type == TypeManager.float_type)
313 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
314 if (target_type == TypeManager.double_type)
315 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
316 } else if (expr_type == TypeManager.short_type){
318 // From short to int, long, float, double
320 if (target_type == TypeManager.int32_type)
321 return new EmptyCast (expr, target_type);
322 if (target_type == TypeManager.int64_type)
323 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
324 if (target_type == TypeManager.double_type)
325 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
326 if (target_type == TypeManager.float_type)
327 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
328 } else if (expr_type == TypeManager.ushort_type){
330 // From ushort to int, uint, long, ulong, float, double
332 if ((target_type == TypeManager.uint32_type) ||
333 (target_type == TypeManager.uint64_type))
334 return new EmptyCast (expr, target_type);
336 if (target_type == TypeManager.int32_type)
337 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
338 if (target_type == TypeManager.int64_type)
339 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
340 if (target_type == TypeManager.double_type)
341 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
342 if (target_type == TypeManager.float_type)
343 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
344 } else if (expr_type == TypeManager.int32_type){
346 // From int to long, float, double
348 if (target_type == TypeManager.int64_type)
349 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
350 if (target_type == TypeManager.double_type)
351 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
352 if (target_type == TypeManager.float_type)
353 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
354 } else if (expr_type == TypeManager.uint32_type){
356 // From uint to long, ulong, float, double
358 if (target_type == TypeManager.int64_type)
359 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
360 if (target_type == TypeManager.uint64_type)
361 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
362 if (target_type == TypeManager.double_type)
363 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
365 if (target_type == TypeManager.float_type)
366 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
368 } else if ((expr_type == TypeManager.uint64_type) ||
369 (expr_type == TypeManager.int64_type)){
371 // From long to float, double
373 if (target_type == TypeManager.double_type)
374 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
376 if (target_type == TypeManager.float_type)
377 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
379 } else if (expr_type == TypeManager.char_type){
381 // From char to ushort, int, uint, long, ulong, float, double
383 if ((target_type == TypeManager.ushort_type) ||
384 (target_type == TypeManager.int32_type) ||
385 (target_type == TypeManager.uint32_type))
386 return new EmptyCast (expr, target_type);
387 if (target_type == TypeManager.uint64_type)
388 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
389 if (target_type == TypeManager.int64_type)
390 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
391 if (target_type == TypeManager.float_type)
392 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
393 if (target_type == TypeManager.double_type)
394 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
396 return ImplicitReferenceConversion (expr, target_type);
401 // Could not find an implicit cast.
407 // Performs an explicit conversion of the expression `expr' whose
408 // type is expr.Type to `target_type'.
410 static public Expression ConvertExplicit (Expression expr, Type target_type)
415 void report (TypeContainer tc, int error, string s)
417 tc.RootContext.Report.Error (error, s);
420 static string ExprClassName (ExprClass c)
423 case ExprClass.Invalid:
425 case ExprClass.Value:
427 case ExprClass.Variable:
429 case ExprClass.Namespace:
433 case ExprClass.MethodGroup:
434 return "method group";
435 case ExprClass.PropertyAccess:
436 return "property access";
437 case ExprClass.EventAccess:
438 return "event access";
439 case ExprClass.IndexerAccess:
440 return "indexer access";
441 case ExprClass.Nothing:
444 throw new Exception ("Should not happen");
448 // Reports that we were expecting `expr' to be of class `expected'
450 protected void report118 (TypeContainer tc, Expression expr, string expected)
452 report (tc, 118, "Expression denotes a '" + ExprClassName (expr.ExprClass) +
453 "' where an " + expected + " was expected");
458 // This kind of cast is used to encapsulate the child
459 // whose type is child.Type into an expression that is
460 // reported to return "return_type". This is used to encapsulate
461 // expressions which have compatible types, but need to be dealt
462 // at higher levels with.
464 // For example, a "byte" expression could be encapsulated in one
465 // of these as an "unsigned int". The type for the expression
466 // would be "unsigned int".
470 public class EmptyCast : Expression {
471 protected Expression child;
473 public EmptyCast (Expression child, Type return_type)
475 ExprClass = child.ExprClass;
480 public override Expression Resolve (TypeContainer tc)
482 // This should never be invoked, we are born in fully
483 // initialized state.
488 public override bool Emit (EmitContext ec)
490 return child.Emit (ec);
495 // This kind of cast is used to encapsulate Value Types in objects.
497 // The effect of it is to box the value type emitted by the previous
500 public class BoxedCast : EmptyCast {
502 public BoxedCast (Expression expr, Type target_type)
503 : base (expr, target_type)
507 public override Expression Resolve (TypeContainer tc)
509 // This should never be invoked, we are born in fully
510 // initialized state.
515 public override bool Emit (EmitContext ec)
518 ec.ig.Emit (OpCodes.Box, child.Type);
525 // This kind of cast is used to encapsulate a child expression
526 // that can be trivially converted to a target type using one or
527 // two opcodes. The opcodes are passed as arguments.
529 public class OpcodeCast : EmptyCast {
533 public OpcodeCast (Expression child, Type return_type, OpCode op)
534 : base (child, return_type)
538 second_valid = false;
541 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
542 : base (child, return_type)
550 public override Expression Resolve (TypeContainer tc)
552 // This should never be invoked, we are born in fully
553 // initialized state.
558 public override bool Emit (EmitContext ec)
571 public class Unary : Expression {
572 public enum Operator {
573 Add, Subtract, Negate, BitComplement,
574 Indirection, AddressOf, PreIncrement,
575 PreDecrement, PostIncrement, PostDecrement
583 public Unary (Operator op, Expression expr)
589 public Expression Expr {
599 public Operator Oper {
610 // Returns a stringified representation of the Operator
617 case Operator.Subtract:
619 case Operator.Negate:
621 case Operator.BitComplement:
623 case Operator.AddressOf:
625 case Operator.Indirection:
627 case Operator.PreIncrement : case Operator.PostIncrement :
629 case Operator.PreDecrement : case Operator.PostDecrement :
633 return oper.ToString ();
636 Expression ForceConversion (Expression expr, Type target_type)
638 if (expr.Type == target_type)
641 return ConvertImplicit (expr, target_type);
644 void report23 (Report r, Type t)
646 r.Error (23, "Operator " + OperName () + " cannot be applied to operand of type `" +
647 TypeManager.CSharpName (t) + "'");
651 // Returns whether an object of type `t' can be incremented
652 // or decremented with add/sub (ie, basically whether we can
653 // use pre-post incr-decr operations on it, but it is not a
654 // System.Decimal, which we test elsewhere)
656 static bool IsIncrementableNumber (Type t)
658 return (t == TypeManager.sbyte_type) ||
659 (t == TypeManager.byte_type) ||
660 (t == TypeManager.short_type) ||
661 (t == TypeManager.ushort_type) ||
662 (t == TypeManager.int32_type) ||
663 (t == TypeManager.uint32_type) ||
664 (t == TypeManager.int64_type) ||
665 (t == TypeManager.uint64_type) ||
666 (t == TypeManager.char_type) ||
667 (t.IsSubclassOf (TypeManager.enum_type)) ||
668 (t == TypeManager.float_type) ||
669 (t == TypeManager.double_type);
672 Expression ResolveOperator (TypeContainer tc)
674 Type expr_type = expr.Type;
677 // Step 1: Perform Operator Overload location
682 if (oper == Operator.PostIncrement || oper == Operator.PreIncrement)
683 op_name = "op_Increment";
684 else if (oper == Operator.PostDecrement || oper == Operator.PreDecrement)
685 op_name = "op_Decrement";
687 op_name = "op_" + oper;
689 mg = MemberLookup (tc.RootContext, expr_type, op_name, false);
692 Arguments = new ArrayList ();
693 Arguments.Add (new Argument (expr, Argument.AType.Expression));
695 method = Invocation.OverloadResolve ((MethodGroupExpr) mg, Arguments);
701 // Step 2: Default operations on CLI native types.
704 // Only perform numeric promotions on:
707 if (expr_type == null)
710 if (oper == Operator.Negate && expr_type != TypeManager.bool_type) {
711 report23 (tc.RootContext.Report, expr.Type);
714 expr = ForceConversion (expr, TypeManager.int32_type);
715 type = TypeManager.int32_type;
718 if (oper == Operator.BitComplement) {
719 if (!((expr_type == TypeManager.int32_type) ||
720 (expr_type == TypeManager.uint32_type) ||
721 (expr_type == TypeManager.int64_type) ||
722 (expr_type == TypeManager.uint64_type) ||
723 (expr_type.IsSubclassOf (TypeManager.enum_type)))){
724 report23 (tc.RootContext.Report, expr.Type);
731 if (oper == Operator.Add) {
733 // A plus in front of something is just a no-op, so return the child.
738 if (oper == Operator.Subtract){
740 // Fold -Constant into a negative constant
745 if (expr is IntLiteral)
746 e = new IntLiteral (-((IntLiteral) expr).Value);
747 else if (expr is LongLiteral)
748 e = new LongLiteral (-((LongLiteral) expr).Value);
749 else if (expr is FloatLiteral)
750 e = new FloatLiteral (-((FloatLiteral) expr).Value);
757 report23 (tc.RootContext.Report, expr.Type);
762 // The operand of the prefix/postfix increment decrement operators
763 // should be an expression that is classified as a variable,
764 // a property access or an indexer access
766 if (oper == Operator.PreDecrement || oper == Operator.PreIncrement ||
767 oper == Operator.PostDecrement || oper == Operator.PostIncrement){
768 if (expr.ExprClass == ExprClass.Variable){
769 if (IsIncrementableNumber (expr_type) ||
770 expr_type == TypeManager.decimal_type)
772 } else if (expr.ExprClass == ExprClass.IndexerAccess){
774 // FIXME: Verify that we have both get and set methods
776 throw new Exception ("Implement me");
777 } else if (expr.ExprClass == ExprClass.PropertyAccess){
779 // FIXME: Verify that we have both get and set methods
781 throw new Exception ("Implement me");
783 report118 (tc, expr, "variable, indexer or property access");
787 tc.RootContext.Report.Error (187, "No such operator '" + OperName () +
788 "' defined for type '" +
789 TypeManager.CSharpName (expr_type) + "'");
794 public override Expression Resolve (TypeContainer tc)
796 expr = expr.Resolve (tc);
801 return ResolveOperator (tc);
804 public override bool Emit (EmitContext ec)
806 ILGenerator ig = ec.ig;
807 Type expr_type = expr.Type;
809 if (method != null) {
811 // Note that operators are static anyway
813 if (Arguments != null)
814 Invocation.EmitArguments (ec, method, Arguments);
816 if (method is MethodInfo)
817 ig.Emit (OpCodes.Call, (MethodInfo) method);
819 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
826 throw new Exception ("This should be caught by Resolve");
828 case Operator.Subtract:
829 throw new Exception ("THis should have been caught by Resolve");
831 case Operator.Negate:
833 ig.Emit (OpCodes.Ldc_I4_0);
834 ig.Emit (OpCodes.Ceq);
837 case Operator.BitComplement:
839 ig.Emit (OpCodes.Not);
842 case Operator.AddressOf:
843 throw new Exception ("Not implemented yet");
845 case Operator.Indirection:
846 throw new Exception ("Not implemented yet");
848 case Operator.PreIncrement:
849 case Operator.PreDecrement:
850 if (expr.ExprClass == ExprClass.Variable){
851 if (expr_type == TypeManager.decimal_type){
852 throw new Exception ("FIXME: Add pre inc/dec for decimals");
855 // Resolve already verified that it is an "incrementable"
858 ig.Emit (OpCodes.Ldc_I4_1);
860 if (oper == Operator.PreDecrement)
861 ig.Emit (OpCodes.Sub);
863 ig.Emit (OpCodes.Add);
864 ((LValue) expr).Store (ig);
865 ig.Emit (OpCodes.Dup);
868 throw new Exception ("Handle Indexers and Properties here");
872 case Operator.PostIncrement:
873 case Operator.PostDecrement:
874 if (expr.ExprClass == ExprClass.Variable){
875 if (expr_type == TypeManager.decimal_type){
876 throw new Exception ("FIXME: Add pre inc/dec for decimals");
879 // Resolve already verified that it is an "incrementable"
882 ig.Emit (OpCodes.Dup);
883 ig.Emit (OpCodes.Ldc_I4_1);
885 if (oper == Operator.PostDecrement)
886 ig.Emit (OpCodes.Sub);
888 ig.Emit (OpCodes.Add);
889 ((LValue) expr).Store (ig);
892 throw new Exception ("Handle Indexers and Properties here");
897 throw new Exception ("This should not happen: Operator = "
902 // yes, we leave a value on the stack
909 public class Probe : Expression {
914 public enum Operator {
918 public Probe (Operator oper, Expression expr, string probe_type)
921 this.probe_type = probe_type;
925 public Operator Oper {
931 public Expression Expr {
937 public string ProbeType {
943 public override Expression Resolve (TypeContainer tc)
946 throw new Exception ("Unimplemented");
950 public override bool Emit (EmitContext ec)
956 public class Cast : Expression {
960 public Cast (string cast_type, Expression expr)
962 this.target_type = cast_type;
966 public string TargetType {
972 public Expression Expr {
981 public override Expression Resolve (TypeContainer tc)
983 type = tc.LookupType (target_type, false);
984 eclass = ExprClass.Value;
990 // FIXME: Unimplemented
992 throw new Exception ("FINISH ME");
995 public override bool Emit (EmitContext ec)
1001 public class Binary : Expression {
1002 public enum Operator {
1003 Multiply, Divide, Modulo,
1005 ShiftLeft, ShiftRight,
1006 LessThan, GreaterThan, LessOrEqual, GreaterOrEqual,
1016 Expression left, right;
1018 ArrayList Arguments;
1021 public Binary (Operator oper, Expression left, Expression right)
1028 public Operator Oper {
1037 public Expression Left {
1046 public Expression Right {
1057 // Returns a stringified representation of the Operator
1062 case Operator.Multiply:
1064 case Operator.Divide:
1066 case Operator.Modulo:
1070 case Operator.Subtract:
1072 case Operator.ShiftLeft:
1074 case Operator.ShiftRight:
1076 case Operator.LessThan:
1078 case Operator.GreaterThan:
1080 case Operator.LessOrEqual:
1082 case Operator.GreaterOrEqual:
1084 case Operator.Equal:
1086 case Operator.NotEqual:
1088 case Operator.BitwiseAnd:
1090 case Operator.BitwiseOr:
1092 case Operator.ExclusiveOr:
1094 case Operator.LogicalOr:
1096 case Operator.LogicalAnd:
1100 return oper.ToString ();
1103 Expression ForceConversion (Expression expr, Type target_type)
1105 if (expr.Type == target_type)
1108 return ConvertImplicit (expr, target_type);
1112 // Note that handling the case l == Decimal || r == Decimal
1113 // is taken care of by the Step 1 Operator Overload resolution.
1115 void DoNumericPromotions (TypeContainer tc, Type l, Type r)
1117 if (l == TypeManager.double_type || r == TypeManager.double_type){
1119 // If either operand is of type double, the other operand is
1120 // conveted to type double.
1122 if (r != TypeManager.double_type)
1123 right = ConvertImplicit (right, TypeManager.double_type);
1124 if (l != TypeManager.double_type)
1125 left = ConvertImplicit (left, TypeManager.double_type);
1127 type = TypeManager.double_type;
1128 } else if (l == TypeManager.float_type || r == TypeManager.float_type){
1130 // if either operand is of type float, th eother operand is
1131 // converd to type float.
1133 if (r != TypeManager.double_type)
1134 right = ConvertImplicit (right, TypeManager.float_type);
1135 if (l != TypeManager.double_type)
1136 left = ConvertImplicit (left, TypeManager.float_type);
1137 type = TypeManager.float_type;
1138 } else if (l == TypeManager.uint64_type || r == TypeManager.uint64_type){
1140 // If either operand is of type ulong, the other operand is
1141 // converted to type ulong. or an error ocurrs if the other
1142 // operand is of type sbyte, short, int or long
1146 if (l == TypeManager.uint64_type)
1148 else if (r == TypeManager.uint64_type)
1151 if ((other == TypeManager.sbyte_type) ||
1152 (other == TypeManager.short_type) ||
1153 (other == TypeManager.int32_type) ||
1154 (other == TypeManager.int64_type)){
1155 string oper = OperName ();
1157 tc.RootContext.Report.Error (34, "Operator `" + OperName ()
1158 + "' is ambiguous on operands of type `"
1159 + TypeManager.CSharpName (l) + "' "
1160 + "and `" + TypeManager.CSharpName (r)
1163 type = TypeManager.uint64_type;
1164 } else if (l == TypeManager.int64_type || r == TypeManager.int64_type){
1166 // If either operand is of type long, the other operand is converted
1169 if (l != TypeManager.int64_type)
1170 left = ConvertImplicit (left, TypeManager.int64_type);
1171 if (r != TypeManager.int64_type)
1172 right = ConvertImplicit (right, TypeManager.int64_type);
1174 type = TypeManager.int64_type;
1175 } else if (l == TypeManager.uint32_type || r == TypeManager.uint32_type){
1177 // If either operand is of type uint, and the other
1178 // operand is of type sbyte, short or int, othe operands are
1179 // converted to type long.
1183 if (l == TypeManager.uint32_type)
1185 else if (r == TypeManager.uint32_type)
1188 if ((other == TypeManager.sbyte_type) ||
1189 (other == TypeManager.short_type) ||
1190 (other == TypeManager.int32_type)){
1191 left = ForceConversion (left, TypeManager.int64_type);
1192 right = ForceConversion (right, TypeManager.int64_type);
1193 type = TypeManager.int64_type;
1196 // if either operand is of type uint, the other
1197 // operand is converd to type uint
1199 left = ForceConversion (left, TypeManager.uint32_type);
1200 right = ForceConversion (left, TypeManager.uint32_type);
1201 type = TypeManager.uint32_type;
1204 left = ForceConversion (left, TypeManager.int32_type);
1205 right = ForceConversion (right, TypeManager.int32_type);
1206 type = TypeManager.int32_type;
1210 void error19 (TypeContainer tc)
1212 tc.RootContext.Report.Error (
1214 "Operator " + OperName () + " cannot be applied to operands of type `" +
1215 TypeManager.CSharpName (left.Type) + "' and `" +
1216 TypeManager.CSharpName (right.Type) + "'");
1220 Expression CheckShiftArguments (TypeContainer tc)
1224 Type r = right.Type;
1226 e = ForceConversion (right, TypeManager.int32_type);
1233 if (((e = ConvertImplicit (left, TypeManager.int32_type)) != null) ||
1234 ((e = ConvertImplicit (left, TypeManager.uint32_type)) != null) ||
1235 ((e = ConvertImplicit (left, TypeManager.int64_type)) != null) ||
1236 ((e = ConvertImplicit (left, TypeManager.uint64_type)) != null)){
1245 Expression ResolveOperator (TypeContainer tc)
1248 Type r = right.Type;
1251 // Step 1: Perform Operator Overload location
1253 Expression left_expr, right_expr;
1255 string op = "op_" + oper;
1257 left_expr = MemberLookup (tc.RootContext, l, op, false);
1259 right_expr = MemberLookup (tc.RootContext, r, op, false);
1261 if (left_expr != null || right_expr != null) {
1263 // Now we need to form the union of these two sets and
1264 // then call OverloadResolve on that.
1266 MethodGroupExpr left_set = null, right_set = null;
1267 int length1 = 0, length2 = 0;
1269 if (left_expr != null) {
1270 left_set = (MethodGroupExpr) left_expr;
1271 length1 = left_set.Methods.Length;
1274 if (right_expr != null) {
1275 right_set = (MethodGroupExpr) right_expr;
1276 length2 = right_set.Methods.Length;
1279 MemberInfo [] mi = new MemberInfo [length1 + length2];
1280 if (left_set != null)
1281 left_set.Methods.CopyTo (mi, 0);
1282 if (right_set != null)
1283 right_set.Methods.CopyTo (mi, length1);
1285 MethodGroupExpr union = new MethodGroupExpr (mi);
1287 Arguments = new ArrayList ();
1288 Arguments.Add (new Argument (left, Argument.AType.Expression));
1289 Arguments.Add (new Argument (right, Argument.AType.Expression));
1292 method = Invocation.OverloadResolve (union, Arguments);
1298 // Step 2: Default operations on CLI native types.
1301 // Only perform numeric promotions on:
1302 // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
1304 if (oper == Operator.ShiftLeft || oper == Operator.ShiftRight){
1305 return CheckShiftArguments (tc);
1306 } else if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
1308 if (l != TypeManager.bool_type || r != TypeManager.bool_type)
1311 DoNumericPromotions (tc, l, r);
1313 if (left == null || right == null)
1316 if (oper == Operator.BitwiseAnd ||
1317 oper == Operator.BitwiseOr ||
1318 oper == Operator.ExclusiveOr){
1319 if (!((l == TypeManager.int32_type) ||
1320 (l == TypeManager.uint32_type) ||
1321 (l == TypeManager.int64_type) ||
1322 (l == TypeManager.uint64_type))){
1328 if (oper == Operator.Equal ||
1329 oper == Operator.NotEqual ||
1330 oper == Operator.LessOrEqual ||
1331 oper == Operator.LessThan ||
1332 oper == Operator.GreaterOrEqual ||
1333 oper == Operator.GreaterThan){
1334 type = TypeManager.bool_type;
1340 public override Expression Resolve (TypeContainer tc)
1342 left = left.Resolve (tc);
1343 right = right.Resolve (tc);
1345 if (left == null || right == null)
1348 return ResolveOperator (tc);
1351 public bool IsBranchable ()
1353 if (oper == Operator.Equal ||
1354 oper == Operator.NotEqual ||
1355 oper == Operator.LessThan ||
1356 oper == Operator.GreaterThan ||
1357 oper == Operator.LessOrEqual ||
1358 oper == Operator.GreaterOrEqual){
1365 // This entry point is used by routines that might want
1366 // to emit a brfalse/brtrue after an expression, and instead
1367 // they could use a more compact notation.
1369 // Typically the code would generate l.emit/r.emit, followed
1370 // by the comparission and then a brtrue/brfalse. The comparissions
1371 // are sometimes inneficient (there are not as complete as the branches
1372 // look for the hacks in Emit using double ceqs).
1374 // So for those cases we provide EmitBranchable that can emit the
1375 // branch with the test
1377 public void EmitBranchable (EmitContext ec, int target)
1380 bool close_target = false;
1386 case Operator.Equal:
1388 opcode = OpCodes.Beq_S;
1390 opcode = OpCodes.Beq;
1393 case Operator.NotEqual:
1395 opcode = OpCodes.Bne_Un_S;
1397 opcode = OpCodes.Bne_Un;
1400 case Operator.LessThan:
1402 opcode = OpCodes.Blt_S;
1404 opcode = OpCodes.Blt;
1407 case Operator.GreaterThan:
1409 opcode = OpCodes.Bgt_S;
1411 opcode = OpCodes.Bgt;
1414 case Operator.LessOrEqual:
1416 opcode = OpCodes.Ble_S;
1418 opcode = OpCodes.Ble;
1421 case Operator.GreaterOrEqual:
1423 opcode = OpCodes.Bge_S;
1425 opcode = OpCodes.Ble;
1429 throw new Exception ("EmitBranchable called on non-EmitBranchable operator: "
1430 + oper.ToString ());
1433 ec.ig.Emit (opcode, target);
1436 public override bool Emit (EmitContext ec)
1438 ILGenerator ig = ec.ig;
1440 Type r = right.Type;
1443 if (method != null) {
1445 // Note that operators are static anyway
1447 if (Arguments != null)
1448 Invocation.EmitArguments (ec, method, Arguments);
1450 if (method is MethodInfo)
1451 ig.Emit (OpCodes.Call, (MethodInfo) method);
1453 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
1462 case Operator.Multiply:
1464 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
1465 opcode = OpCodes.Mul_Ovf;
1466 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
1467 opcode = OpCodes.Mul_Ovf_Un;
1469 opcode = OpCodes.Mul;
1471 opcode = OpCodes.Mul;
1475 case Operator.Divide:
1476 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
1477 opcode = OpCodes.Div_Un;
1479 opcode = OpCodes.Div;
1482 case Operator.Modulo:
1483 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
1484 opcode = OpCodes.Rem_Un;
1486 opcode = OpCodes.Rem;
1491 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
1492 opcode = OpCodes.Add_Ovf;
1493 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
1494 opcode = OpCodes.Add_Ovf_Un;
1496 opcode = OpCodes.Mul;
1498 opcode = OpCodes.Add;
1501 case Operator.Subtract:
1503 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
1504 opcode = OpCodes.Sub_Ovf;
1505 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
1506 opcode = OpCodes.Sub_Ovf_Un;
1508 opcode = OpCodes.Sub;
1510 opcode = OpCodes.Sub;
1513 case Operator.ShiftRight:
1514 opcode = OpCodes.Shr;
1517 case Operator.ShiftLeft:
1518 opcode = OpCodes.Shl;
1521 case Operator.Equal:
1522 opcode = OpCodes.Ceq;
1525 case Operator.NotEqual:
1526 ec.ig.Emit (OpCodes.Ceq);
1527 ec.ig.Emit (OpCodes.Ldc_I4_0);
1529 opcode = OpCodes.Ceq;
1532 case Operator.LessThan:
1533 opcode = OpCodes.Clt;
1536 case Operator.GreaterThan:
1537 opcode = OpCodes.Cgt;
1540 case Operator.LessOrEqual:
1541 ec.ig.Emit (OpCodes.Cgt);
1542 ec.ig.Emit (OpCodes.Ldc_I4_0);
1544 opcode = OpCodes.Ceq;
1547 case Operator.GreaterOrEqual:
1548 ec.ig.Emit (OpCodes.Clt);
1549 ec.ig.Emit (OpCodes.Ldc_I4_1);
1551 opcode = OpCodes.Sub;
1554 case Operator.LogicalOr:
1555 case Operator.BitwiseOr:
1556 opcode = OpCodes.Or;
1559 case Operator.LogicalAnd:
1560 case Operator.BitwiseAnd:
1561 opcode = OpCodes.And;
1564 case Operator.ExclusiveOr:
1565 opcode = OpCodes.Xor;
1569 throw new Exception ("This should not happen: Operator = "
1570 + oper.ToString ());
1579 public class Conditional : Expression {
1580 Expression expr, trueExpr, falseExpr;
1582 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr)
1585 this.trueExpr = trueExpr;
1586 this.falseExpr = falseExpr;
1589 public Expression Expr {
1595 public Expression TrueExpr {
1601 public Expression FalseExpr {
1607 public override Expression Resolve (TypeContainer tc)
1609 // FIXME: Implement;
1610 throw new Exception ("Unimplemented");
1614 public override bool Emit (EmitContext ec)
1620 public class SimpleName : Expression {
1621 public readonly string Name;
1622 public readonly Location Location;
1624 public SimpleName (string name, Location l)
1631 // Checks whether we are trying to access an instance
1632 // property, method or field from a static body.
1634 Expression MemberStaticCheck (Report r, Expression e)
1636 if (e is FieldExpr){
1637 FieldInfo fi = ((FieldExpr) e).FieldInfo;
1641 "An object reference is required " +
1642 "for the non-static field `"+Name+"'");
1645 } else if (e is MethodGroupExpr){
1646 // FIXME: Pending reorganization of MemberLookup
1647 // Basically at this point we should have the
1648 // best match already selected for us, and
1649 // we should only have to check a *single*
1650 // Method for its static on/off bit.
1652 } else if (e is PropertyExpr){
1653 if (!((PropertyExpr) e).IsStatic){
1655 "An object reference is required " +
1656 "for the non-static property access `"+
1666 // 7.5.2: Simple Names.
1668 // Local Variables and Parameters are handled at
1669 // parse time, so they never occur as SimpleNames.
1671 Expression ResolveSimpleName (TypeContainer tc)
1674 Report r = tc.RootContext.Report;
1676 e = MemberLookup (tc.RootContext, tc.TypeBuilder, Name, true);
1680 else if (e is FieldExpr){
1681 FieldExpr fe = (FieldExpr) e;
1683 if (!fe.FieldInfo.IsStatic)
1684 fe.Instance = new This ();
1687 if ((tc.ModFlags & Modifiers.STATIC) != 0)
1688 return MemberStaticCheck (r, e);
1694 // Do step 3 of the Simple Name resolution.
1696 // FIXME: implement me.
1698 r.Error (103, Location, "The name `" + Name + "' does not exist in the class `" +
1705 // SimpleName needs to handle a multitude of cases:
1707 // simple_names and qualified_identifiers are placed on
1708 // the tree equally.
1710 public override Expression Resolve (TypeContainer tc)
1712 if (Name.IndexOf (".") != -1)
1713 return ResolveMemberAccess (tc, Name);
1715 return ResolveSimpleName (tc);
1718 public override bool Emit (EmitContext ec)
1720 throw new Exception ("SimpleNames should be gone from the tree");
1725 // A simple interface that should be implemeneted by LValues
1727 public interface LValue {
1728 void Store (ILGenerator ig);
1731 public class LocalVariableReference : Expression, LValue {
1732 public readonly string Name;
1733 public readonly Block Block;
1735 public LocalVariableReference (Block block, string name)
1739 eclass = ExprClass.Variable;
1742 public VariableInfo VariableInfo {
1744 return Block.GetVariableInfo (Name);
1748 public override Expression Resolve (TypeContainer tc)
1750 VariableInfo vi = Block.GetVariableInfo (Name);
1752 type = vi.VariableType;
1756 public override bool Emit (EmitContext ec)
1758 VariableInfo vi = VariableInfo;
1759 ILGenerator ig = ec.ig;
1764 ig.Emit (OpCodes.Ldloc_0);
1768 ig.Emit (OpCodes.Ldloc_1);
1772 ig.Emit (OpCodes.Ldloc_2);
1776 ig.Emit (OpCodes.Ldloc_3);
1781 ig.Emit (OpCodes.Ldloc_S, idx);
1783 ig.Emit (OpCodes.Ldloc, idx);
1790 public void Store (ILGenerator ig)
1792 VariableInfo vi = VariableInfo;
1797 ig.Emit (OpCodes.Stloc_0);
1801 ig.Emit (OpCodes.Stloc_1);
1805 ig.Emit (OpCodes.Stloc_2);
1809 ig.Emit (OpCodes.Stloc_3);
1814 ig.Emit (OpCodes.Stloc_S, idx);
1816 ig.Emit (OpCodes.Stloc, idx);
1822 public class ParameterReference : Expression, LValue {
1823 public readonly Parameters Pars;
1824 public readonly String Name;
1825 public readonly int Idx;
1827 public ParameterReference (Parameters pars, int idx, string name)
1832 eclass = ExprClass.Variable;
1835 public override Expression Resolve (TypeContainer tc)
1837 Type [] types = Pars.GetParameterInfo (tc);
1844 public override bool Emit (EmitContext ec)
1847 ec.ig.Emit (OpCodes.Ldarg_S, Idx);
1849 ec.ig.Emit (OpCodes.Ldarg, Idx);
1854 public void Store (ILGenerator ig)
1857 ig.Emit (OpCodes.Starg_S, Idx);
1859 ig.Emit (OpCodes.Starg, Idx);
1865 // Used for arguments to New(), Invocation()
1867 public class Argument {
1874 public readonly AType Type;
1877 public Argument (Expression expr, AType type)
1883 public Expression Expr {
1889 public bool Resolve (TypeContainer tc)
1891 expr = expr.Resolve (tc);
1893 return expr != null;
1896 public bool Emit (EmitContext ec)
1898 return expr.Emit (ec);
1903 // Invocation of methods or delegates.
1905 public class Invocation : Expression {
1906 public readonly ArrayList Arguments;
1907 public readonly Location Location;
1910 MethodBase method = null;
1912 static Hashtable method_parameter_cache;
1914 static Invocation ()
1916 method_parameter_cache = new Hashtable ();
1920 // arguments is an ArrayList, but we do not want to typecast,
1921 // as it might be null.
1923 // FIXME: only allow expr to be a method invocation or a
1924 // delegate invocation (7.5.5)
1926 public Invocation (Expression expr, ArrayList arguments, Location l)
1929 Arguments = arguments;
1933 public Expression Expr {
1940 /// Computes whether Argument `a' and the Type t of the ParameterInfo `pi' are
1941 /// compatible, and if so, how good is the match (in terms of
1942 /// "better conversions" (7.4.2.3).
1944 /// 0 is the best possible match.
1945 /// -1 represents a type mismatch.
1946 /// -2 represents a ref/out mismatch.
1948 static int Badness (Argument a, Type t)
1950 Expression argument_expr = a.Expr;
1951 Type argument_type = argument_expr.Type;
1953 if (argument_type == null){
1954 throw new Exception ("Expression of type " + a.Expr + " does not resolve its type");
1957 if (t == argument_type)
1961 // Now probe whether an implicit constant expression conversion
1964 // An implicit constant expression conversion permits the following
1967 // * A constant-expression of type `int' can be converted to type
1968 // sbyte, byute, short, ushort, uint, ulong provided the value of
1969 // of the expression is withing the range of the destination type.
1971 // * A constant-expression of type long can be converted to type
1972 // ulong, provided the value of the constant expression is not negative
1974 // FIXME: Note that this assumes that constant folding has
1975 // taken place. We dont do constant folding yet.
1978 if (argument_type == TypeManager.int32_type && argument_expr is IntLiteral){
1979 IntLiteral ei = (IntLiteral) argument_expr;
1980 int value = ei.Value;
1982 if (t == TypeManager.sbyte_type){
1983 if (value >= SByte.MinValue && value <= SByte.MaxValue)
1985 } else if (t == TypeManager.byte_type){
1986 if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
1988 } else if (t == TypeManager.short_type){
1989 if (value >= Int16.MinValue && value <= Int16.MaxValue)
1991 } else if (t == TypeManager.ushort_type){
1992 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
1994 } else if (t == TypeManager.uint32_type){
1996 // we can optimize this case: a positive int32
1997 // always fits on a uint32
2001 } else if (t == TypeManager.uint64_type){
2003 // we can optimize this case: a positive int32
2004 // always fits on a uint64
2009 } else if (argument_type == TypeManager.int64_type && argument_expr is LongLiteral){
2010 LongLiteral ll = (LongLiteral) argument_expr;
2012 if (t == TypeManager.uint64_type){
2018 // FIXME: Implement user-defined implicit conversions here.
2019 // FIXME: Implement better conversion here.
2025 // Returns the Parameters (a ParameterData interface) for the
2028 static ParameterData GetParameterData (MethodBase mb)
2030 object pd = method_parameter_cache [mb];
2033 return (ParameterData) pd;
2035 if (mb is MethodBuilder || mb is ConstructorBuilder){
2036 MethodCore mc = TypeContainer.LookupMethodByBuilder (mb);
2038 InternalParameters ip = mc.ParameterInfo;
2039 method_parameter_cache [mb] = ip;
2041 return (ParameterData) ip;
2043 ParameterInfo [] pi = mb.GetParameters ();
2044 ReflectionParameters rp = new ReflectionParameters (pi);
2045 method_parameter_cache [mb] = rp;
2047 return (ParameterData) rp;
2051 static bool ConversionExists (Type from, Type to)
2053 // FIXME : Need to implement this !
2058 // Determines "better conversion" as specified in 7.4.2.3
2059 // Returns : 1 if a->p is better
2060 // 0 if a->q or neither is better
2062 static int BetterConversion (Argument a, Type p, Type q)
2065 Type argument_type = a.Expr.Type;
2066 Expression argument_expr = a.Expr;
2068 if (argument_type == null){
2069 throw new Exception ("Expression of type " + a.Expr + " does not resolve its type");
2075 if (argument_type == p)
2078 if (argument_type == q)
2081 // Implicit conversions come here
2083 //if (ConversionExists (p, q) == true &&
2084 // ConversionExists (q, p) == false)
2088 // Now probe whether an implicit constant expression conversion
2091 // An implicit constant expression conversion permits the following
2094 // * A constant-expression of type `int' can be converted to type
2095 // sbyte, byute, short, ushort, uint, ulong provided the value of
2096 // of the expression is withing the range of the destination type.
2098 // * A constant-expression of type long can be converted to type
2099 // ulong, provided the value of the constant expression is not negative
2101 // FIXME: Note that this assumes that constant folding has
2102 // taken place. We dont do constant folding yet.
2105 if (argument_type == TypeManager.int32_type && argument_expr is IntLiteral){
2106 IntLiteral ei = (IntLiteral) argument_expr;
2107 int value = ei.Value;
2109 if (p == TypeManager.sbyte_type){
2110 if (value >= SByte.MinValue && value <= SByte.MaxValue)
2112 } else if (p == TypeManager.byte_type){
2113 if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
2115 } else if (p == TypeManager.short_type){
2116 if (value >= Int16.MinValue && value <= Int16.MaxValue)
2118 } else if (p == TypeManager.ushort_type){
2119 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
2121 } else if (p == TypeManager.uint32_type){
2123 // we can optimize this case: a positive int32
2124 // always fits on a uint32
2128 } else if (p == TypeManager.uint64_type){
2130 // we can optimize this case: a positive int32
2131 // always fits on a uint64
2136 } else if (argument_type == TypeManager.int64_type && argument_expr is LongLiteral){
2137 LongLiteral ll = (LongLiteral) argument_expr;
2139 if (p == TypeManager.uint64_type){
2146 if (p == TypeManager.sbyte_type)
2147 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
2148 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
2151 if (p == TypeManager.short_type)
2152 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
2153 q == TypeManager.uint64_type)
2156 if (p == TypeManager.int32_type)
2157 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
2160 if (p == TypeManager.int64_type)
2161 if (q == TypeManager.uint64_type)
2168 // Determines "Better function" and returns an integer indicating :
2169 // 0 if candidate ain't better
2170 // 1 if candidate is better than the current best match
2172 static int BetterFunction (ArrayList args, MethodBase candidate, MethodBase best)
2174 ParameterData candidate_pd = GetParameterData (candidate);
2175 ParameterData best_pd;
2181 argument_count = args.Count;
2183 if (candidate_pd.Count == 0 && argument_count == 0)
2187 if (candidate_pd.Count == argument_count) {
2189 for (int j = argument_count; j > 0;) {
2192 Argument a = (Argument) args [j];
2194 x = BetterConversion (a, candidate_pd.ParameterType (j), null);
2211 best_pd = GetParameterData (best);
2213 if (candidate_pd.Count == argument_count && best_pd.Count == argument_count) {
2214 int rating1 = 0, rating2 = 0;
2216 for (int j = argument_count; j > 0;) {
2220 Argument a = (Argument) args [j];
2222 x = BetterConversion (a, candidate_pd.ParameterType (j), best_pd.ParameterType (j));
2223 y = BetterConversion (a, best_pd.ParameterType (j), candidate_pd.ParameterType (j));
2229 if (rating1 > rating2)
2239 // Find the Applicable Function Members (7.4.2.1)
2241 // me: Method Group expression with the members to select.
2242 // it might contain constructors or methods (or anything
2243 // that maps to a method).
2245 // Arguments: ArrayList containing resolved Argument objects.
2247 // Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
2248 // that is the best match of me on Arguments.
2251 public static MethodBase OverloadResolve (MethodGroupExpr me, ArrayList Arguments)
2253 ArrayList afm = new ArrayList ();
2254 int best_match_idx = -1;
2255 MethodBase method = null;
2257 for (int i = me.Methods.Length; i > 0; ){
2259 MethodBase candidate = me.Methods [i];
2262 x = BetterFunction (Arguments, candidate, method);
2268 method = me.Methods [best_match_idx];
2272 if (best_match_idx == -1)
2279 public override Expression Resolve (TypeContainer tc)
2282 // First, resolve the expression that is used to
2283 // trigger the invocation
2285 this.expr = expr.Resolve (tc);
2286 if (this.expr == null)
2289 if (!(this.expr is MethodGroupExpr)){
2290 report118 (tc, this.expr, "method group");
2295 // Next, evaluate all the expressions in the argument list
2297 if (Arguments != null){
2298 for (int i = Arguments.Count; i > 0;){
2300 Argument a = (Argument) Arguments [i];
2302 if (!a.Resolve (tc))
2307 method = OverloadResolve ((MethodGroupExpr) this.expr, Arguments);
2309 if (method == null){
2310 tc.RootContext.Report.Error (-6, Location,
2311 "Figure out error: Can not find a good function for this argument list");
2315 if (method is MethodInfo)
2316 type = ((MethodInfo)method).ReturnType;
2321 public static void EmitArguments (EmitContext ec, MethodBase method, ArrayList Arguments)
2325 if (Arguments != null)
2326 top = Arguments.Count;
2330 for (int i = 0; i < top; i++){
2331 Argument a = (Argument) Arguments [i];
2333 Console.WriteLine ("Perform the actual type widening of arguments here for things like: void fn (sbyte s); ... fn (1)");
2339 public override bool Emit (EmitContext ec)
2341 bool is_static = method.IsStatic;
2344 MethodGroupExpr mg = (MethodGroupExpr) this.expr;
2346 if (mg.InstanceExpression == null){
2347 throw new Exception ("Internal compiler error. Should check in the method groups for static/instance");
2350 mg.InstanceExpression.Emit (ec);
2353 if (Arguments != null)
2354 EmitArguments (ec, method, Arguments);
2357 if (method is MethodInfo)
2358 ec.ig.Emit (OpCodes.Call, (MethodInfo) method);
2360 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
2362 if (method is MethodInfo)
2363 ec.ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
2365 ec.ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
2368 if (method is MethodInfo){
2369 return ((MethodInfo)method).ReturnType != TypeManager.void_type;
2372 // Constructors do not leave any values on the stack
2379 public class New : Expression {
2386 public readonly NType NewType;
2387 public readonly ArrayList Arguments;
2388 public readonly string RequestedType;
2389 // These are for the case when we have an array
2390 public readonly string Rank;
2391 public readonly ArrayList Indices;
2392 public readonly ArrayList Initializers;
2394 MethodBase method = null;
2396 public New (string requested_type, ArrayList arguments)
2398 RequestedType = requested_type;
2399 Arguments = arguments;
2400 NewType = NType.Object;
2403 public New (string requested_type, ArrayList exprs, string rank, ArrayList initializers)
2405 RequestedType = requested_type;
2408 Initializers = initializers;
2409 NewType = NType.Array;
2412 public override Expression Resolve (TypeContainer tc)
2414 type = tc.LookupType (RequestedType, false);
2421 ml = MemberLookup (tc.RootContext, type, ".ctor", false,
2422 MemberTypes.Constructor, AllBindingsFlags);
2424 if (! (ml is MethodGroupExpr)){
2426 // FIXME: Find proper error
2428 report118 (tc, ml, "method group");
2432 if (Arguments != null){
2433 for (int i = Arguments.Count; i > 0;){
2435 Argument a = (Argument) Arguments [i];
2437 if (!a.Resolve (tc))
2442 method = Invocation.OverloadResolve ((MethodGroupExpr) ml, Arguments);
2444 if (method == null) {
2445 tc.RootContext.Report.Error (-6,
2446 "New invocation: Can not find a constructor for this argument list");
2453 public override bool Emit (EmitContext ec)
2455 Invocation.EmitArguments (ec, method, Arguments);
2456 ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
2462 // Represents the `this' construct
2464 public class This : Expression, LValue {
2465 public override Expression Resolve (TypeContainer tc)
2467 eclass = ExprClass.Variable;
2468 type = tc.TypeBuilder;
2471 // FIXME: Verify that this is only used in instance contexts.
2476 public override bool Emit (EmitContext ec)
2478 ec.ig.Emit (OpCodes.Ldarg_0);
2482 public void Store (ILGenerator ig)
2485 // Assignment to the "this" variable
2487 ig.Emit (OpCodes.Starg, 0);
2491 public class TypeOf : Expression {
2492 public readonly string QueriedType;
2494 public TypeOf (string queried_type)
2496 QueriedType = queried_type;
2499 public override Expression Resolve (TypeContainer tc)
2501 type = tc.LookupType (QueriedType, false);
2506 eclass = ExprClass.Type;
2510 public override bool Emit (EmitContext ec)
2512 throw new Exception ("Implement me");
2513 // FIXME: Implement.
2517 public class SizeOf : Expression {
2518 public readonly string QueriedType;
2520 public SizeOf (string queried_type)
2522 this.QueriedType = queried_type;
2525 public override Expression Resolve (TypeContainer tc)
2527 // FIXME: Implement;
2528 throw new Exception ("Unimplemented");
2532 public override bool Emit (EmitContext ec)
2534 throw new Exception ("Implement me");
2538 public class MemberAccess : Expression {
2539 public readonly string Identifier;
2541 Expression member_lookup;
2543 public MemberAccess (Expression expr, string id)
2549 public Expression Expr {
2555 public override Expression Resolve (TypeContainer tc)
2557 Expression new_expression = expr.Resolve (tc);
2559 if (new_expression == null)
2562 member_lookup = MemberLookup (tc.RootContext, expr.Type, Identifier, false);
2564 if (member_lookup is MethodGroupExpr){
2565 MethodGroupExpr mg = (MethodGroupExpr) member_lookup;
2568 // Bind the instance expression to it
2570 // FIXME: This is a horrible way of detecting if it is
2571 // an instance expression. Figure out how to fix this.
2574 if (expr is LocalVariableReference ||
2575 expr is ParameterReference ||
2577 mg.InstanceExpression = expr;
2579 return member_lookup;
2580 } else if (member_lookup is FieldExpr){
2581 FieldExpr fe = (FieldExpr) member_lookup;
2585 return member_lookup;
2588 // FIXME: This should generate the proper node
2589 // ie, for a Property Access, it should like call it
2592 return member_lookup;
2595 public override bool Emit (EmitContext ec)
2597 throw new Exception ("Implement me");
2603 // Nodes of type Namespace are created during the semantic
2604 // analysis to resolve member_access/qualified_identifier/simple_name
2607 // They are born `resolved'.
2609 public class NamespaceExpr : Expression {
2610 public readonly string Name;
2612 public NamespaceExpr (string name)
2615 eclass = ExprClass.Namespace;
2618 public override Expression Resolve (TypeContainer tc)
2623 public override bool Emit (EmitContext ec)
2625 throw new Exception ("Namespace expressions should never be emitted");
2630 // Fully resolved expression that evaluates to a type
2632 public class TypeExpr : Expression {
2633 public TypeExpr (Type t)
2636 eclass = ExprClass.Type;
2639 override public Expression Resolve (TypeContainer tc)
2644 override public bool Emit (EmitContext ec)
2646 throw new Exception ("Implement me");
2651 // MethodGroup Expression.
2653 // This is a fully resolved expression that evaluates to a type
2655 public class MethodGroupExpr : Expression {
2656 public readonly MethodBase [] Methods;
2657 Expression instance_expression = null;
2659 public MethodGroupExpr (MemberInfo [] mi)
2661 Methods = new MethodBase [mi.Length];
2662 mi.CopyTo (Methods, 0);
2663 eclass = ExprClass.MethodGroup;
2667 // `A method group may have associated an instance expression'
2669 public Expression InstanceExpression {
2671 return instance_expression;
2675 instance_expression = value;
2679 override public Expression Resolve (TypeContainer tc)
2684 override public bool Emit (EmitContext ec)
2686 throw new Exception ("This should never be reached");
2690 public class BuiltinTypeAccess : Expression {
2691 public readonly string AccessBase;
2692 public readonly string Method;
2694 public BuiltinTypeAccess (string type, string method)
2696 System.Console.WriteLine ("DUDE! This type should be fully resolved!");
2701 public override Expression Resolve (TypeContainer tc)
2703 // FIXME: Implement;
2704 throw new Exception ("Unimplemented");
2708 public override bool Emit (EmitContext ec)
2710 throw new Exception ("Unimplemented");
2715 // Fully resolved expression that evaluates to a Field
2717 public class FieldExpr : Expression, LValue {
2718 public readonly FieldInfo FieldInfo;
2719 public Expression Instance;
2721 public FieldExpr (FieldInfo fi)
2724 eclass = ExprClass.Variable;
2725 type = fi.FieldType;
2728 override public Expression Resolve (TypeContainer tc)
2730 if (!FieldInfo.IsStatic){
2731 if (Instance == null){
2732 throw new Exception ("non-static FieldExpr without instance var\n" +
2733 "You have to assign the Instance variable\n" +
2734 "Of the FieldExpr to set this\n");
2737 Instance = Instance.Resolve (tc);
2738 if (Instance == null)
2745 override public bool Emit (EmitContext ec)
2747 ILGenerator ig = ec.ig;
2749 if (FieldInfo.IsStatic)
2750 ig.Emit (OpCodes.Ldsfld, FieldInfo);
2754 ig.Emit (OpCodes.Ldfld, FieldInfo);
2760 public void Store (ILGenerator ig)
2762 if (FieldInfo.IsStatic)
2763 ig.Emit (OpCodes.Stsfld, FieldInfo);
2765 ig.Emit (OpCodes.Stfld, FieldInfo);
2770 // Fully resolved expression that evaluates to a Property
2772 public class PropertyExpr : Expression {
2773 public readonly PropertyInfo PropertyInfo;
2774 public readonly bool IsStatic;
2776 public PropertyExpr (PropertyInfo pi)
2779 eclass = ExprClass.PropertyAccess;
2782 MethodBase [] acc = pi.GetAccessors ();
2784 for (int i = 0; i < acc.Length; i++)
2785 if (acc [i].IsStatic)
2788 type = pi.PropertyType;
2791 override public Expression Resolve (TypeContainer tc)
2793 // We are born in resolved state.
2797 override public bool Emit (EmitContext ec)
2799 // FIXME: Implement;
2800 throw new Exception ("Unimplemented");
2805 // Fully resolved expression that evaluates to a Property
2807 public class EventExpr : Expression {
2808 public readonly EventInfo EventInfo;
2810 public EventExpr (EventInfo ei)
2813 eclass = ExprClass.EventAccess;
2816 override public Expression Resolve (TypeContainer tc)
2818 // We are born in resolved state.
2822 override public bool Emit (EmitContext ec)
2824 throw new Exception ("Implement me");
2825 // FIXME: Implement.
2829 public class CheckedExpr : Expression {
2831 public Expression Expr;
2833 public CheckedExpr (Expression e)
2838 public override Expression Resolve (TypeContainer tc)
2840 Expr = Expr.Resolve (tc);
2845 eclass = Expr.ExprClass;
2850 public override bool Emit (EmitContext ec)
2852 bool last_check = ec.CheckState;
2855 ec.CheckState = true;
2859 ec.CheckState = last_check;
2866 public class UnCheckedExpr : Expression {
2868 public Expression Expr;
2870 public UnCheckedExpr (Expression e)
2875 public override Expression Resolve (TypeContainer tc)
2877 Expr = Expr.Resolve (tc);
2882 eclass = Expr.ExprClass;
2887 public override bool Emit (EmitContext ec)
2889 bool last_check = ec.CheckState;
2892 ec.CheckState = false;
2896 ec.CheckState = last_check;
2903 public class ElementAccess : Expression {
2905 public readonly ArrayList Arguments;
2906 public readonly Expression Expr;
2908 public ElementAccess (Expression e, ArrayList e_list)
2914 public override Expression Resolve (TypeContainer tc)
2916 // FIXME: Implement;
2917 throw new Exception ("Unimplemented");
2921 public override bool Emit (EmitContext ec)
2923 // FIXME : Implement !
2924 throw new Exception ("Unimplemented");
2929 public class BaseAccess : Expression {
2931 public enum BaseAccessType {
2936 public readonly BaseAccessType BAType;
2937 public readonly string Member;
2938 public readonly ArrayList Arguments;
2940 public BaseAccess (BaseAccessType t, string member, ArrayList args)
2948 public override Expression Resolve (TypeContainer tc)
2950 // FIXME: Implement;
2951 throw new Exception ("Unimplemented");
2955 public override bool Emit (EmitContext ec)
2957 throw new Exception ("Unimplemented");