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 {
25 Value, Variable, Namespace, Type,
26 MethodGroup, PropertyAccess,
27 EventAccess, IndexerAccess, Nothing,
31 // Base class for expressions
33 public abstract class Expression {
34 protected ExprClass eclass;
47 public ExprClass ExprClass {
57 public abstract Expression Resolve (TypeContainer tc);
58 public abstract void Emit (EmitContext ec);
61 // Protected constructor. Only derivate types should
62 // be able to be created
65 protected Expression ()
67 eclass = ExprClass.Invalid;
72 // Returns a fully formed expression after a MemberLookup
74 static Expression ExprClassFromMemberInfo (MemberInfo mi)
77 return new EventExpr ((EventInfo) mi);
78 } else if (mi is FieldInfo){
79 return new FieldExpr ((FieldInfo) mi);
80 } else if (mi is PropertyInfo){
81 return new PropertyExpr ((PropertyInfo) mi);
82 } else if (mi is Type)
83 return new TypeExpr ((Type) mi);
89 // FIXME: Probably implement a cache for (t,name,current_access_set)?
91 // FIXME: We need to cope with access permissions here, or this wont
94 // This code could use some optimizations, but we need to do some
95 // measurements. For example, we could use a delegate to `flag' when
96 // something can not any longer be a method-group (because it is something
100 // If the return value is an Array, then it is an array of
103 // If the return value is an MemberInfo, it is anything, but a Method
107 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
108 // the arguments here and have MemberLookup return only the methods that
109 // match the argument count/type, unlike we are doing now (we delay this
112 // This is so we can catch correctly attempts to invoke instance methods
113 // from a static body (scan for error 120 in ResolveSimpleName).
115 public static Expression MemberLookup (RootContext rc, Type t, string name,
116 bool same_type, MemberTypes mt, BindingFlags bf)
119 bf |= BindingFlags.NonPublic;
121 MemberInfo [] mi = rc.TypeManager.FindMembers (t, mt, bf, Type.FilterName, name);
126 if (mi.Length == 1 && !(mi [0] is MethodBase))
127 return Expression.ExprClassFromMemberInfo (mi [0]);
129 for (int i = 0; i < mi.Length; i++)
130 if (!(mi [i] is MethodBase)){
131 rc.Report.Error (-5, "Do not know how to reproduce this case: " +
132 "Methods and non-Method with the same name, report this please");
134 for (i = 0; i < mi.Length; i++){
135 Type tt = mi [i].GetType ();
137 Console.WriteLine (i + ": " + mi [i]);
138 while (tt != TypeManager.object_type){
139 Console.WriteLine (tt);
145 return new MethodGroupExpr (mi);
148 public const MemberTypes AllMemberTypes =
149 MemberTypes.Constructor |
153 MemberTypes.NestedType |
154 MemberTypes.Property;
156 public const BindingFlags AllBindingsFlags =
157 BindingFlags.Public |
158 BindingFlags.Static |
159 BindingFlags.Instance;
161 public static Expression MemberLookup (RootContext rc, Type t, string name,
164 return MemberLookup (rc, t, name, same_type, AllMemberTypes, AllBindingsFlags);
168 // Resolves the E in `E.I' side for a member_access
170 // This is suboptimal and should be merged with ResolveMemberAccess
171 static Expression ResolvePrimary (TypeContainer tc, string name)
173 int dot_pos = name.LastIndexOf (".");
175 if (tc.RootContext.IsNamespace (name))
176 return new NamespaceExpr (name);
180 Type t = tc.LookupType (name, false);
183 return new TypeExpr (t);
189 static public Expression ResolveMemberAccess (TypeContainer tc, string name)
192 int dot_pos = name.LastIndexOf (".");
193 string left = name.Substring (0, dot_pos);
194 string right = name.Substring (dot_pos + 1);
196 left_e = ResolvePrimary (tc, left);
200 switch (left_e.ExprClass){
202 return MemberLookup (tc.RootContext,
204 left_e.Type == tc.TypeBuilder);
206 case ExprClass.Namespace:
207 case ExprClass.PropertyAccess:
208 case ExprClass.IndexerAccess:
209 case ExprClass.Variable:
210 case ExprClass.Value:
211 case ExprClass.Nothing:
212 case ExprClass.EventAccess:
213 case ExprClass.MethodGroup:
214 case ExprClass.Invalid:
215 tc.RootContext.Report.Error (-1000,
216 "Internal compiler error, should have " +
217 "got these handled before");
224 static public Expression ImplicitReferenceConversion (Expression expr, Type target_type)
226 Type expr_type = expr.Type;
228 if (target_type == TypeManager.object_type) {
229 if (expr_type.IsClass)
230 return new EmptyCast (expr, target_type);
231 if (expr_type.IsValueType)
232 return new BoxedCast (expr, target_type);
233 } else if (expr_type.IsSubclassOf (target_type))
234 return new EmptyCast (expr, target_type);
236 // FIXME: missing implicit reference conversions:
238 // from any class-type S to any interface-type T.
239 // from any interface type S to interface-type T.
240 // from an array-type S to an array-type of type T
241 // from an array-type to System.Array
242 // from any delegate type to System.Delegate
243 // from any array-type or delegate type into System.ICloneable.
244 // from the null type to any reference-type.
252 // Converts implicitly the resolved expression `expr' into the
253 // `target_type'. It returns a new expression that can be used
254 // in a context that expects a `target_type'.
256 static public Expression ConvertImplicit (Expression expr, Type target_type)
258 Type expr_type = expr.Type;
260 if (expr_type == target_type){
261 Console.WriteLine ("Hey, ConvertImplicit was called with no job to do");
266 // Step 1: Perform implicit conversions as found on expr.Type
270 // Step 2: Built-in conversions.
272 if (expr_type == TypeManager.sbyte_type){
274 // From sbyte to short, int, long, float, double.
276 if (target_type == TypeManager.int32_type)
277 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
278 if (target_type == TypeManager.int64_type)
279 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
280 if (target_type == TypeManager.double_type)
281 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
282 if (target_type == TypeManager.float_type)
283 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
284 if (target_type == TypeManager.short_type)
285 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
286 } else if (expr_type == TypeManager.byte_type){
288 // From byte to short, ushort, int, uint, long, ulong, float, double
290 if ((target_type == TypeManager.short_type) ||
291 (target_type == TypeManager.ushort_type) ||
292 (target_type == TypeManager.int32_type) ||
293 (target_type == TypeManager.uint32_type))
294 return new EmptyCast (expr, target_type);
296 if (target_type == TypeManager.uint64_type)
297 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
298 if (target_type == TypeManager.int64_type)
299 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
301 if (target_type == TypeManager.float_type)
302 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
303 if (target_type == TypeManager.double_type)
304 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
305 } else if (expr_type == TypeManager.short_type){
307 // From short to int, long, float, double
309 if (target_type == TypeManager.int32_type)
310 return new EmptyCast (expr, target_type);
311 if (target_type == TypeManager.int64_type)
312 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
313 if (target_type == TypeManager.double_type)
314 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
315 if (target_type == TypeManager.float_type)
316 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
317 } else if (expr_type == TypeManager.ushort_type){
319 // From ushort to int, uint, long, ulong, float, double
321 if ((target_type == TypeManager.uint32_type) ||
322 (target_type == TypeManager.uint64_type))
323 return new EmptyCast (expr, target_type);
325 if (target_type == TypeManager.int32_type)
326 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
327 if (target_type == TypeManager.int64_type)
328 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
329 if (target_type == TypeManager.double_type)
330 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
331 if (target_type == TypeManager.float_type)
332 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
333 } else if (expr_type == TypeManager.int32_type){
335 // From int to long, float, double
337 if (target_type == TypeManager.int64_type)
338 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
339 if (target_type == TypeManager.double_type)
340 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
341 if (target_type == TypeManager.float_type)
342 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
343 } else if (expr_type == TypeManager.uint32_type){
345 // From uint to long, ulong, float, double
347 if (target_type == TypeManager.int64_type)
348 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
349 if (target_type == TypeManager.uint64_type)
350 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
351 if (target_type == TypeManager.double_type)
352 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
354 if (target_type == TypeManager.float_type)
355 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
357 } else if ((expr_type == TypeManager.uint64_type) ||
358 (expr_type == TypeManager.int64_type)){
360 // From long to float, double
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.char_type){
370 // From char to ushort, int, uint, long, ulong, float, double
372 if ((target_type == TypeManager.ushort_type) ||
373 (target_type == TypeManager.int32_type) ||
374 (target_type == TypeManager.uint32_type))
375 return new EmptyCast (expr, target_type);
376 if (target_type == TypeManager.uint64_type)
377 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
378 if (target_type == TypeManager.int64_type)
379 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
380 if (target_type == TypeManager.float_type)
381 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
382 if (target_type == TypeManager.double_type)
383 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
385 return ImplicitReferenceConversion (expr, target_type);
390 // Could not find an implicit cast.
396 // Performs an explicit conversion of the expression `expr' whose
397 // type is expr.Type to `target_type'.
399 static public Expression ConvertExplicit (Expression expr, Type target_type)
407 // This kind of cast is used to encapsulate the child
408 // whose type is child.Type into an expression that is
409 // reported to return "return_type". This is used to encapsulate
410 // expressions which have compatible types, but need to be dealt
411 // at higher levels with.
413 // For example, a "byte" expression could be encapsulated in one
414 // of these as an "unsigned int". The type for the expression
415 // would be "unsigned int".
419 public class EmptyCast : Expression {
420 protected Expression child;
422 public EmptyCast (Expression child, Type return_type)
424 ExprClass = child.ExprClass;
429 public override Expression Resolve (TypeContainer tc)
431 // This should never be invoked, we are born in fully
432 // initialized state.
437 public override void Emit (EmitContext ec)
443 public class BoxedCast : EmptyCast {
445 public BoxedCast (Expression expr, Type target_type)
446 : base (expr, target_type)
450 public override Expression Resolve (TypeContainer tc)
452 // This should never be invoked, we are born in fully
453 // initialized state.
458 public override void Emit (EmitContext ec)
461 ec.ig.Emit (OpCodes.Box, child.Type);
467 // This kind of cast is used to encapsulate a child expression
468 // that can be trivially converted to a target type using one or
469 // two opcodes. The opcodes are passed as arguments.
471 public class OpcodeCast : EmptyCast {
475 public OpcodeCast (Expression child, Type return_type, OpCode op)
476 : base (child, return_type)
480 second_valid = false;
483 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
484 : base (child, return_type)
492 public override Expression Resolve (TypeContainer tc)
494 // This should never be invoked, we are born in fully
495 // initialized state.
500 public override void Emit (EmitContext ec)
511 public class Unary : Expression {
512 public enum Operator {
513 Plus, Minus, Negate, BitComplement,
514 Indirection, AddressOf, PreIncrement,
515 PreDecrement, PostIncrement, PostDecrement
521 public Unary (Operator op, Expression expr)
527 public Expression Expr {
537 public Operator Oper {
547 public override Expression Resolve (TypeContainer tc)
553 public override void Emit (EmitContext ec)
558 public class Probe : Expression {
563 public enum Operator {
567 public Probe (Operator oper, Expression expr, string probe_type)
570 this.probe_type = probe_type;
574 public Operator Oper {
580 public Expression Expr {
586 public string ProbeType {
592 public override Expression Resolve (TypeContainer tc)
598 public override void Emit (EmitContext ec)
603 public class Cast : Expression {
607 public Cast (string cast_type, Expression expr)
609 this.target_type = target_type;
613 public string TargetType {
619 public Expression Expr {
628 public override Expression Resolve (TypeContainer tc)
634 public override void Emit (EmitContext ec)
639 public class Binary : Expression {
640 public enum Operator {
641 Multiply, Divide, Modulo,
643 ShiftLeft, ShiftRight,
644 LessThan, GreaterThan, LessOrEqual, GreaterOrEqual,
654 Expression left, right;
659 public Binary (Operator oper, Expression left, Expression right)
666 public Operator Oper {
675 public Expression Left {
684 public Expression Right {
695 // Retruns a stringified representation of the Operator
700 case Operator.Multiply:
702 case Operator.Divide:
704 case Operator.Modulo:
708 case Operator.Subtract:
710 case Operator.ShiftLeft:
712 case Operator.ShiftRight:
714 case Operator.LessThan:
716 case Operator.GreaterThan:
718 case Operator.LessOrEqual:
720 case Operator.GreaterOrEqual:
724 case Operator.NotEqual:
726 case Operator.BitwiseAnd:
728 case Operator.BitwiseOr:
730 case Operator.ExclusiveOr:
732 case Operator.LogicalOr:
734 case Operator.LogicalAnd:
738 return oper.ToString ();
741 Expression ForceConversion (Expression expr, Type target_type)
743 if (expr.Type == target_type)
746 return ConvertImplicit (expr, target_type);
750 // Note that handling the case l == Decimal || r == Decimal
751 // is taken care of by the Step 1 Operator Overload resolution.
753 void DoNumericPromotions (TypeContainer tc, Type l, Type r)
755 if (l == TypeManager.double_type || r == TypeManager.double_type){
757 // If either operand is of type double, the other operand is
758 // conveted to type double.
760 if (r != TypeManager.double_type)
761 right = ConvertImplicit (right, TypeManager.double_type);
762 if (l != TypeManager.double_type)
763 left = ConvertImplicit (left, TypeManager.double_type);
765 type = TypeManager.double_type;
766 } else if (l == TypeManager.float_type || r == TypeManager.float_type){
768 // if either operand is of type float, th eother operand is
769 // converd to type float.
771 if (r != TypeManager.double_type)
772 right = ConvertImplicit (right, TypeManager.float_type);
773 if (l != TypeManager.double_type)
774 left = ConvertImplicit (left, TypeManager.float_type);
775 type = TypeManager.float_type;
776 } else if (l == TypeManager.uint64_type || r == TypeManager.uint64_type){
778 // If either operand is of type ulong, the other operand is
779 // converted to type ulong. or an error ocurrs if the other
780 // operand is of type sbyte, short, int or long
784 if (l == TypeManager.uint64_type)
786 else if (r == TypeManager.uint64_type)
789 if ((other == TypeManager.sbyte_type) ||
790 (other == TypeManager.short_type) ||
791 (other == TypeManager.int32_type) ||
792 (other == TypeManager.int64_type)){
793 string oper = OperName ();
795 tc.RootContext.Report.Error (34, "Operator `" + OperName ()
796 + "' is ambiguous on operands of type `"
797 + TypeManager.CSharpName (l) + "' "
798 + "and `" + TypeManager.CSharpName (r)
801 type = TypeManager.uint64_type;
802 } else if (l == TypeManager.int64_type || r == TypeManager.int64_type){
804 // If either operand is of type long, the other operand is converted
807 if (l != TypeManager.int64_type)
808 left = ConvertImplicit (left, TypeManager.int64_type);
809 if (r != TypeManager.int64_type)
810 right = ConvertImplicit (right, TypeManager.int64_type);
812 type = TypeManager.int64_type;
813 } else if (l == TypeManager.uint32_type || r == TypeManager.uint32_type){
815 // If either operand is of type uint, and the other
816 // operand is of type sbyte, short or int, othe operands are
817 // converted to type long.
821 if (l == TypeManager.uint32_type)
823 else if (r == TypeManager.uint32_type)
826 if ((other == TypeManager.sbyte_type) ||
827 (other == TypeManager.short_type) ||
828 (other == TypeManager.int32_type)){
829 left = ForceConversion (left, TypeManager.int64_type);
830 right = ForceConversion (right, TypeManager.int64_type);
831 type = TypeManager.int64_type;
834 // if either operand is of type uint, the other
835 // operand is converd to type uint
837 left = ForceConversion (left, TypeManager.uint32_type);
838 right = ForceConversion (left, TypeManager.uint32_type);
839 type = TypeManager.uint32_type;
842 left = ForceConversion (left, TypeManager.int32_type);
843 right = ForceConversion (right, TypeManager.int32_type);
844 type = TypeManager.int32_type;
848 void error19 (TypeContainer tc)
850 tc.RootContext.Report.Error (
852 "Operator " + OperName () + " cannot be applied to operands of type `" +
853 TypeManager.CSharpName (left.Type) + "' and `" +
854 TypeManager.CSharpName (right.Type) + "'");
858 Expression CheckShiftArguments (TypeContainer tc)
864 e = ForceConversion (right, TypeManager.int32_type);
871 if (((e = ConvertImplicit (left, TypeManager.int32_type)) != null) ||
872 ((e = ConvertImplicit (left, TypeManager.uint32_type)) != null) ||
873 ((e = ConvertImplicit (left, TypeManager.int64_type)) != null) ||
874 ((e = ConvertImplicit (left, TypeManager.uint64_type)) != null)){
883 Expression ResolveOperator (TypeContainer tc)
889 // Step 1: Perform Operator Overload location
891 Expression left_expr, right_expr;
893 string op = "Operator" + oper;
895 left_expr = MemberLookup (tc.RootContext, l, op, false);
897 if (!(left_expr is MethodGroupExpr)){
898 // FIXME: Find proper error
899 tc.RootContext.Report.Error (118, "Did find something that is not a method");
903 right_expr = MemberLookup (tc.RootContext, r, op, false);
905 if (!(right_expr is MethodGroupExpr)){
906 // FIXME: Find proper error
907 tc.RootContext.Report.Error (118, "Did find something that is not a method");
911 if (left_expr != null || right_expr != null) {
913 // Now we need to form the union of these two sets and
914 // then call OverloadResolve on that.
916 MethodGroupExpr left_set = null, right_set = null;
917 int length1 = 0, length2 = 0;
919 if (left_expr != null) {
920 left_set = (MethodGroupExpr) left_expr;
921 length1 = left_set.Methods.Length;
924 if (right_expr != null) {
925 right_set = (MethodGroupExpr) right_expr;
926 length2 = right_set.Methods.Length;
929 MemberInfo [] mi = new MemberInfo [length1 + length2];
930 if (left_set != null)
931 left_set.Methods.CopyTo (mi, 0);
932 if (right_set != null)
933 right_set.Methods.CopyTo (mi, length1);
935 MethodGroupExpr union = new MethodGroupExpr (mi);
937 Arguments = new ArrayList ();
938 Arguments.Add (new Argument (left, Argument.AType.Expression));
939 Arguments.Add (new Argument (right, Argument.AType.Expression));
941 method = Invocation.OverloadResolve (union, Arguments);
948 // Step 2: Default operations on CLI native types.
951 // Only perform numeric promotions on:
952 // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
954 if (oper == Operator.ShiftLeft || oper == Operator.ShiftRight){
955 return CheckShiftArguments (tc);
956 } else if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
958 if (l != TypeManager.bool_type || r != TypeManager.bool_type)
961 DoNumericPromotions (tc, l, r);
963 if (left == null || right == null)
966 if (oper == Operator.BitwiseAnd ||
967 oper == Operator.BitwiseOr ||
968 oper == Operator.ExclusiveOr){
969 if (!((l == TypeManager.int32_type) ||
970 (l == TypeManager.uint32_type) ||
971 (l == TypeManager.int64_type) ||
972 (l == TypeManager.uint64_type))){
978 if (oper == Operator.Equal ||
979 oper == Operator.NotEqual ||
980 oper == Operator.LessOrEqual ||
981 oper == Operator.LessThan ||
982 oper == Operator.GreaterOrEqual ||
983 oper == Operator.GreaterThan){
984 type = TypeManager.bool_type;
990 public override Expression Resolve (TypeContainer tc)
992 left = left.Resolve (tc);
993 right = right.Resolve (tc);
995 if (left == null || right == null)
998 return ResolveOperator (tc);
1001 public bool IsBranchable ()
1003 if (oper == Operator.Equal ||
1004 oper == Operator.NotEqual ||
1005 oper == Operator.LessThan ||
1006 oper == Operator.GreaterThan ||
1007 oper == Operator.LessOrEqual ||
1008 oper == Operator.GreaterOrEqual){
1015 // This entry point is used by routines that might want
1016 // to emit a brfalse/brtrue after an expression, and instead
1017 // they could use a more compact notation.
1019 // Typically the code would generate l.emit/r.emit, followed
1020 // by the comparission and then a brtrue/brfalse. The comparissions
1021 // are sometimes inneficient (there are not as complete as the branches
1022 // look for the hacks in Emit using double ceqs).
1024 // So for those cases we provide EmitBranchable that can emit the
1025 // branch with the test
1027 public void EmitBranchable (EmitContext ec, int target)
1030 bool close_target = false;
1036 case Operator.Equal:
1038 opcode = OpCodes.Beq_S;
1040 opcode = OpCodes.Beq;
1043 case Operator.NotEqual:
1045 opcode = OpCodes.Bne_Un_S;
1047 opcode = OpCodes.Bne_Un;
1050 case Operator.LessThan:
1052 opcode = OpCodes.Blt_S;
1054 opcode = OpCodes.Blt;
1057 case Operator.GreaterThan:
1059 opcode = OpCodes.Bgt_S;
1061 opcode = OpCodes.Bgt;
1064 case Operator.LessOrEqual:
1066 opcode = OpCodes.Ble_S;
1068 opcode = OpCodes.Ble;
1071 case Operator.GreaterOrEqual:
1073 opcode = OpCodes.Bge_S;
1075 opcode = OpCodes.Ble;
1079 throw new Exception ("EmitBranchable called on non-EmitBranchable operator: "
1080 + oper.ToString ());
1083 ec.ig.Emit (opcode, target);
1086 public override void Emit (EmitContext ec)
1088 ILGenerator ig = ec.ig;
1090 Type r = right.Type;
1093 if (method != null) {
1095 bool is_static = method.IsStatic;
1097 // FIXME : I am just not able to get this right !!
1098 // There's something wrong with this part which causes
1099 // an InvalidProgramException if this code is emitted
1101 //if (Arguments != null)
1102 // Invocation.EmitArguments (ec, Arguments);
1105 // if (method is MethodInfo)
1106 // ig.Emit (OpCodes.Call, (MethodInfo) method);
1108 // ig.Emit (OpCodes.Call, (ConstructorInfo) method);
1110 // if (method is MethodInfo)
1111 // ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
1113 // ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
1123 case Operator.Multiply:
1125 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
1126 opcode = OpCodes.Mul_Ovf;
1127 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
1128 opcode = OpCodes.Mul_Ovf_Un;
1130 opcode = OpCodes.Mul;
1132 opcode = OpCodes.Mul;
1136 case Operator.Divide:
1137 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
1138 opcode = OpCodes.Div_Un;
1140 opcode = OpCodes.Div;
1143 case Operator.Modulo:
1144 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
1145 opcode = OpCodes.Rem_Un;
1147 opcode = OpCodes.Rem;
1152 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
1153 opcode = OpCodes.Add_Ovf;
1154 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
1155 opcode = OpCodes.Add_Ovf_Un;
1157 opcode = OpCodes.Mul;
1159 opcode = OpCodes.Add;
1162 case Operator.Subtract:
1164 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
1165 opcode = OpCodes.Sub_Ovf;
1166 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
1167 opcode = OpCodes.Sub_Ovf_Un;
1169 opcode = OpCodes.Sub;
1171 opcode = OpCodes.Sub;
1174 case Operator.ShiftRight:
1175 opcode = OpCodes.Shr;
1178 case Operator.ShiftLeft:
1179 opcode = OpCodes.Shl;
1182 case Operator.Equal:
1183 opcode = OpCodes.Ceq;
1186 case Operator.NotEqual:
1187 ec.ig.Emit (OpCodes.Ceq);
1188 ec.ig.Emit (OpCodes.Ldc_I4_0);
1190 opcode = OpCodes.Ceq;
1193 case Operator.LessThan:
1194 opcode = OpCodes.Clt;
1197 case Operator.GreaterThan:
1198 opcode = OpCodes.Cgt;
1201 case Operator.LessOrEqual:
1202 ec.ig.Emit (OpCodes.Cgt);
1203 ec.ig.Emit (OpCodes.Ldc_I4_0);
1205 opcode = OpCodes.Ceq;
1208 case Operator.GreaterOrEqual:
1209 ec.ig.Emit (OpCodes.Clt);
1210 ec.ig.Emit (OpCodes.Ldc_I4_1);
1212 opcode = OpCodes.Sub;
1215 case Operator.LogicalOr:
1216 case Operator.BitwiseOr:
1217 opcode = OpCodes.Or;
1220 case Operator.LogicalAnd:
1221 case Operator.BitwiseAnd:
1222 opcode = OpCodes.And;
1225 case Operator.ExclusiveOr:
1226 opcode = OpCodes.Xor;
1230 throw new Exception ("This should not happen: Operator = "
1231 + oper.ToString ());
1234 ec.ig.Emit (opcode);
1238 public class Conditional : Expression {
1239 Expression expr, trueExpr, falseExpr;
1241 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr)
1244 this.trueExpr = trueExpr;
1245 this.falseExpr = falseExpr;
1248 public Expression Expr {
1254 public Expression TrueExpr {
1260 public Expression FalseExpr {
1266 public override Expression Resolve (TypeContainer tc)
1268 // FIXME: Implement;
1272 public override void Emit (EmitContext ec)
1277 public class SimpleName : Expression {
1280 public SimpleName (string name)
1285 public string Name {
1292 // Checks whether we are trying to access an instance
1293 // property, method or field from a static body.
1295 Expression MemberStaticCheck (Report r, Expression e)
1297 if (e is FieldExpr){
1298 FieldInfo fi = ((FieldExpr) e).FieldInfo;
1302 "An object reference is required " +
1303 "for the non-static field `"+name+"'");
1306 } else if (e is MethodGroupExpr){
1307 // FIXME: Pending reorganization of MemberLookup
1308 // Basically at this point we should have the
1309 // best match already selected for us, and
1310 // we should only have to check a *single*
1311 // Method for its static on/off bit.
1313 } else if (e is PropertyExpr){
1314 if (!((PropertyExpr) e).IsStatic){
1316 "An object reference is required " +
1317 "for the non-static property access `"+
1327 // 7.5.2: Simple Names.
1329 // Local Variables and Parameters are handled at
1330 // parse time, so they never occur as SimpleNames.
1332 Expression ResolveSimpleName (TypeContainer tc)
1335 Report r = tc.RootContext.Report;
1337 e = MemberLookup (tc.RootContext, tc.TypeBuilder, name, true);
1341 else if (e is FieldExpr){
1342 FieldExpr fe = (FieldExpr) e;
1344 if (!fe.FieldInfo.IsStatic)
1345 fe.Instance = new This ();
1348 if ((tc.ModFlags & Modifiers.STATIC) != 0)
1349 return MemberStaticCheck (r, e);
1355 // Do step 3 of the Simple Name resolution.
1357 // FIXME: implement me.
1363 // SimpleName needs to handle a multitude of cases:
1365 // simple_names and qualified_identifiers are placed on
1366 // the tree equally.
1368 public override Expression Resolve (TypeContainer tc)
1370 if (name.IndexOf (".") != -1)
1371 return ResolveMemberAccess (tc, name);
1373 return ResolveSimpleName (tc);
1376 public override void Emit (EmitContext ec)
1381 public class LocalVariableReference : Expression {
1382 public readonly string Name;
1383 public readonly Block Block;
1385 public LocalVariableReference (Block block, string name)
1389 eclass = ExprClass.Variable;
1392 public VariableInfo VariableInfo {
1394 return Block.GetVariableInfo (Name);
1398 public override Expression Resolve (TypeContainer tc)
1400 VariableInfo vi = Block.GetVariableInfo (Name);
1402 type = vi.VariableType;
1406 public override void Emit (EmitContext ec)
1408 VariableInfo vi = VariableInfo;
1409 ILGenerator ig = ec.ig;
1414 ig.Emit (OpCodes.Ldloc_0);
1418 ig.Emit (OpCodes.Ldloc_1);
1422 ig.Emit (OpCodes.Ldloc_2);
1426 ig.Emit (OpCodes.Ldloc_3);
1431 ig.Emit (OpCodes.Ldloc_S, idx);
1433 ig.Emit (OpCodes.Ldloc, idx);
1439 public class ParameterReference : Expression {
1440 public readonly Parameters Pars;
1441 public readonly String Name;
1442 public readonly int Idx;
1444 public ParameterReference (Parameters pars, int idx, string name)
1451 public override Expression Resolve (TypeContainer tc)
1453 Type [] types = Pars.GetParameterInfo (tc);
1460 public override void Emit (EmitContext ec)
1463 ec.ig.Emit (OpCodes.Ldarg_S, Idx);
1465 ec.ig.Emit (OpCodes.Ldarg, Idx);
1470 // Used for arguments to New(), Invocation()
1472 public class Argument {
1479 public readonly AType Type;
1482 public Argument (Expression expr, AType type)
1488 public Expression Expr {
1494 public bool Resolve (TypeContainer tc)
1496 expr = expr.Resolve (tc);
1498 return expr != null;
1501 public void Emit (EmitContext ec)
1508 // Invocation of methods or delegates.
1510 public class Invocation : Expression {
1511 public readonly ArrayList Arguments;
1513 MethodBase method = null;
1515 static Hashtable method_parameter_cache;
1517 static Invocation ()
1519 method_parameter_cache = new Hashtable ();
1523 // arguments is an ArrayList, but we do not want to typecast,
1524 // as it might be null.
1526 // FIXME: only allow expr to be a method invocation or a
1527 // delegate invocation (7.5.5)
1529 public Invocation (Expression expr, ArrayList arguments)
1532 Arguments = arguments;
1535 public Expression Expr {
1542 /// Computes whether Argument `a' and the ParameterInfo `pi' are
1543 /// compatible, and if so, how good is the match (in terms of
1544 /// "better conversions" (7.4.2.3).
1546 /// 0 is the best possible match.
1547 /// -1 represents a type mismatch.
1548 /// -2 represents a ref/out mismatch.
1550 static int Badness (Argument a, Type t)
1552 if (a.Expr.Type == null){
1553 throw new Exception ("Expression of type " + a.Expr + " does not resolve its type");
1556 if (t == a.Expr.Type)
1559 // FIXME: Implement implicit conversions here.
1560 // FIXME: Implement better conversion here.
1566 // Returns the Parameters (a ParameterData interface) for the
1569 static ParameterData GetParameterData (MethodBase mb)
1571 object pd = method_parameter_cache [mb];
1574 return (ParameterData) pd;
1576 if (mb is MethodBuilder || mb is ConstructorBuilder){
1577 MethodCore mc = TypeContainer.LookupMethodByBuilder (mb);
1579 InternalParameters ip = mc.ParameterInfo;
1580 method_parameter_cache [mb] = ip;
1582 return (ParameterData) ip;
1584 ParameterInfo [] pi = mb.GetParameters ();
1585 ReflectionParameters rp = new ReflectionParameters (pi);
1586 method_parameter_cache [mb] = rp;
1588 return (ParameterData) rp;
1593 // Find the Applicable Function Members (7.4.2.1)
1595 // me: Method Group expression with the members to select.
1596 // it might contain constructors or methods (or anything
1597 // that maps to a method).
1599 // Arguments: ArrayList containing resolved Argument objects.
1601 // Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
1602 // that is the best match of me on Arguments.
1605 public static MethodBase OverloadResolve (MethodGroupExpr me, ArrayList Arguments)
1607 ArrayList afm = new ArrayList ();
1608 int best_match = 10000;
1609 int best_match_idx = -1;
1610 MethodBase method = null;
1613 if (Arguments == null)
1616 argument_count = Arguments.Count;
1618 for (int i = me.Methods.Length; i > 0; ){
1620 MethodBase mb = me.Methods [i];
1623 pd = GetParameterData (mb);
1625 // If this is the case, we have a method with no args - presumably
1626 if (pd == null && argument_count == 0)
1627 return me.Methods [0];
1630 // Compute how good this is
1632 if (pd.Count == argument_count){
1635 for (int j = argument_count; j > 0;){
1639 Argument a = (Argument) Arguments [j];
1641 x = Badness (a, pd.ParameterType (j));
1644 badness = best_match;
1651 if (badness < best_match){
1652 best_match = badness;
1653 method = me.Methods [i];
1659 if (best_match_idx == -1)
1666 public override Expression Resolve (TypeContainer tc)
1669 // First, resolve the expression that is used to
1670 // trigger the invocation
1672 this.expr = expr.Resolve (tc);
1673 if (this.expr == null)
1676 if (!(this.expr is MethodGroupExpr)){
1677 tc.RootContext.Report.Error (118,
1678 "Denotes a non-method (Detail: ExprClass=" + this.expr.ExprClass+")");
1683 // Next, evaluate all the expressions in the argument list
1685 if (Arguments != null){
1686 for (int i = Arguments.Count; i > 0;){
1688 Argument a = (Argument) Arguments [i];
1690 if (!a.Resolve (tc))
1695 method = OverloadResolve ((MethodGroupExpr) this.expr, Arguments);
1697 if (method == null){
1698 tc.RootContext.Report.Error (-6,
1699 "Figure out error: Can not find a good function for this argument list");
1703 if (method is MethodInfo)
1704 type = ((MethodInfo)method).ReturnType;
1709 public static void EmitArguments (EmitContext ec, ArrayList Arguments)
1713 if (Arguments != null)
1714 top = Arguments.Count;
1718 for (int i = 0; i < top; i++){
1719 Argument a = (Argument) Arguments [i];
1725 public override void Emit (EmitContext ec)
1727 bool is_static = method.IsStatic;
1730 MethodGroupExpr mg = (MethodGroupExpr) this.expr;
1732 if (mg.InstanceExpression == null){
1733 Console.WriteLine ("Internal compiler error. Should check in the method groups for static/instance");
1736 mg.InstanceExpression.Emit (ec);
1739 if (Arguments != null)
1740 EmitArguments (ec, Arguments);
1743 if (method is MethodInfo)
1744 ec.ig.Emit (OpCodes.Call, (MethodInfo) method);
1746 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
1748 if (method is MethodInfo)
1749 ec.ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
1751 ec.ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
1757 public class New : Expression {
1764 public readonly NType NewType;
1765 public readonly ArrayList Arguments;
1766 public readonly string RequestedType;
1767 // These are for the case when we have an array
1768 public readonly string Rank;
1769 public readonly ArrayList Indices;
1770 public readonly ArrayList Initializers;
1772 MethodBase method = null;
1774 public New (string requested_type, ArrayList arguments)
1776 RequestedType = requested_type;
1777 Arguments = arguments;
1778 NewType = NType.Object;
1781 public New (string requested_type, ArrayList exprs, string rank, ArrayList initializers)
1783 RequestedType = requested_type;
1786 Initializers = initializers;
1787 NewType = NType.Array;
1790 public override Expression Resolve (TypeContainer tc)
1792 type = tc.LookupType (RequestedType, false);
1799 ml = MemberLookup (tc.RootContext, type, ".ctor", false,
1800 MemberTypes.Constructor, AllBindingsFlags);
1802 if (! (ml is MethodGroupExpr)){
1804 // FIXME: Find proper error
1806 tc.RootContext.Report.Error (118, "Did find something that is not a method");
1810 if (Arguments != null){
1811 for (int i = Arguments.Count; i > 0;){
1813 Argument a = (Argument) Arguments [i];
1815 if (!a.Resolve (tc))
1820 method = Invocation.OverloadResolve ((MethodGroupExpr) ml, Arguments);
1822 if (method == null) {
1823 tc.RootContext.Report.Error (-6,
1824 "New invocation: Can not find a constructor for this argument list");
1831 public override void Emit (EmitContext ec)
1833 Invocation.EmitArguments (ec, Arguments);
1834 ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
1839 // Represents the `this' construct
1841 public class This : Expression {
1842 public override Expression Resolve (TypeContainer tc)
1844 eclass = ExprClass.Variable;
1845 type = tc.TypeBuilder;
1850 public override void Emit (EmitContext ec)
1852 ec.ig.Emit (OpCodes.Ldarg_0);
1856 public class TypeOf : Expression {
1857 public readonly string QueriedType;
1859 public TypeOf (string queried_type)
1861 QueriedType = queried_type;
1864 public override Expression Resolve (TypeContainer tc)
1866 type = tc.LookupType (QueriedType, false);
1871 eclass = ExprClass.Type;
1875 public override void Emit (EmitContext ec)
1877 // FIXME: Implement.
1881 public class SizeOf : Expression {
1882 public readonly string QueriedType;
1884 public SizeOf (string queried_type)
1886 this.QueriedType = queried_type;
1889 public override Expression Resolve (TypeContainer tc)
1891 // FIXME: Implement;
1895 public override void Emit (EmitContext ec)
1900 public class MemberAccess : Expression {
1901 public readonly string Identifier;
1903 Expression member_lookup;
1905 public MemberAccess (Expression expr, string id)
1911 public Expression Expr {
1917 public override Expression Resolve (TypeContainer tc)
1919 Expression new_expression = expr.Resolve (tc);
1921 if (new_expression == null)
1924 Console.WriteLine ("This is what I figured: " + expr.Type + "/" + expr.ExprClass);
1926 member_lookup = MemberLookup (tc.RootContext, expr.Type, Identifier, false);
1928 if (member_lookup is MethodGroupExpr){
1929 MethodGroupExpr mg = (MethodGroupExpr) member_lookup;
1932 // Bind the instance expression to it
1934 // FIXME: This is a horrible way of detecting if it is
1935 // an instance expression. Figure out how to fix this.
1938 if (expr is LocalVariableReference ||
1939 expr is ParameterReference ||
1941 mg.InstanceExpression = expr;
1943 return member_lookup;
1944 } else if (member_lookup is FieldExpr){
1945 FieldExpr fe = (FieldExpr) member_lookup;
1949 return member_lookup;
1952 // FIXME: This should generate the proper node
1953 // ie, for a Property Access, it should like call it
1956 return member_lookup;
1959 public override void Emit (EmitContext ec)
1966 // Nodes of type Namespace are created during the semantic
1967 // analysis to resolve member_access/qualified_identifier/simple_name
1970 // They are born `resolved'.
1972 public class NamespaceExpr : Expression {
1973 public readonly string Name;
1975 public NamespaceExpr (string name)
1978 eclass = ExprClass.Namespace;
1981 public override Expression Resolve (TypeContainer tc)
1986 public override void Emit (EmitContext ec)
1992 // Fully resolved expression that evaluates to a type
1994 public class TypeExpr : Expression {
1995 public TypeExpr (Type t)
1998 eclass = ExprClass.Type;
2001 override public Expression Resolve (TypeContainer tc)
2006 override public void Emit (EmitContext ec)
2013 // MethodGroup Expression.
2015 // This is a fully resolved expression that evaluates to a type
2017 public class MethodGroupExpr : Expression {
2018 public readonly MethodBase [] Methods;
2019 Expression instance_expression = null;
2021 public MethodGroupExpr (MemberInfo [] mi)
2023 Methods = new MethodBase [mi.Length];
2024 mi.CopyTo (Methods, 0);
2025 eclass = ExprClass.MethodGroup;
2029 // `A method group may have associated an instance expression'
2031 public Expression InstanceExpression {
2033 return instance_expression;
2037 instance_expression = value;
2041 override public Expression Resolve (TypeContainer tc)
2046 override public void Emit (EmitContext ec)
2052 public class BuiltinTypeAccess : Expression {
2053 public readonly string AccessBase;
2054 public readonly string Method;
2056 public BuiltinTypeAccess (string type, string method)
2058 System.Console.WriteLine ("DUDE! This type should be fully resolved!");
2063 public override Expression Resolve (TypeContainer tc)
2065 // FIXME: Implement;
2069 public override void Emit (EmitContext ec)
2075 // Fully resolved expression that evaluates to a Field
2077 public class FieldExpr : Expression {
2078 public readonly FieldInfo FieldInfo;
2079 public Expression Instance;
2081 public FieldExpr (FieldInfo fi)
2084 eclass = ExprClass.Variable;
2085 type = fi.FieldType;
2088 override public Expression Resolve (TypeContainer tc)
2090 if (!FieldInfo.IsStatic){
2091 if (Instance == null){
2092 throw new Exception ("non-static FieldExpr without instance var\n" +
2093 "You have to assign the Instance variable\n" +
2094 "Of the FieldExpr to set this\n");
2097 Instance = Instance.Resolve (tc);
2098 if (Instance == null)
2105 override public void Emit (EmitContext ec)
2107 ILGenerator ig = ec.ig;
2109 if (FieldInfo.IsStatic)
2110 ig.Emit (OpCodes.Ldsfld, FieldInfo);
2114 ig.Emit (OpCodes.Ldfld, FieldInfo);
2120 // Fully resolved expression that evaluates to a Property
2122 public class PropertyExpr : Expression {
2123 public readonly PropertyInfo PropertyInfo;
2124 public readonly bool IsStatic;
2126 public PropertyExpr (PropertyInfo pi)
2129 eclass = ExprClass.PropertyAccess;
2132 MethodBase [] acc = pi.GetAccessors ();
2134 for (int i = 0; i < acc.Length; i++)
2135 if (acc [i].IsStatic)
2138 type = pi.PropertyType;
2141 override public Expression Resolve (TypeContainer tc)
2143 // We are born in resolved state.
2147 override public void Emit (EmitContext ec)
2149 // FIXME: Implement.
2154 // Fully resolved expression that evaluates to a Property
2156 public class EventExpr : Expression {
2157 public readonly EventInfo EventInfo;
2159 public EventExpr (EventInfo ei)
2162 eclass = ExprClass.EventAccess;
2165 override public Expression Resolve (TypeContainer tc)
2167 // We are born in resolved state.
2171 override public void Emit (EmitContext ec)
2173 // FIXME: Implement.
2177 public class CheckedExpr : Expression {
2179 public readonly Expression Expr;
2181 public CheckedExpr (Expression e)
2186 public override Expression Resolve (TypeContainer tc)
2188 // FIXME : Implement !
2192 public override void Emit (EmitContext ec)
2198 public class UnCheckedExpr : Expression {
2200 public readonly Expression Expr;
2202 public UnCheckedExpr (Expression e)
2207 public override Expression Resolve (TypeContainer tc)
2209 // FIXME : Implement !
2213 public override void Emit (EmitContext ec)
2219 public class ElementAccess : Expression {
2221 public readonly ArrayList Arguments;
2222 public readonly Expression Expr;
2224 public ElementAccess (Expression e, ArrayList e_list)
2230 public override Expression Resolve (TypeContainer tc)
2232 // FIXME : Implement
2236 public override void Emit (EmitContext ec)
2238 // FIXME : Implement !
2243 public class BaseAccess : Expression {
2245 public enum BaseAccessType {
2250 public readonly BaseAccessType BAType;
2251 public readonly string Member;
2252 public readonly ArrayList Arguments;
2254 public BaseAccess (BaseAccessType t, string member, ArrayList args)
2262 public override Expression Resolve (TypeContainer tc)
2264 // FIXME : Implement !
2268 public override void Emit (EmitContext ec)