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;
658 public Binary (Operator oper, Expression left, Expression right)
665 public Operator Oper {
674 public Expression Left {
683 public Expression Right {
694 // Retruns a stringified representation of the Operator
699 case Operator.Multiply:
701 case Operator.Divide:
703 case Operator.Modulo:
707 case Operator.Subtract:
709 case Operator.ShiftLeft:
711 case Operator.ShiftRight:
713 case Operator.LessThan:
715 case Operator.GreaterThan:
717 case Operator.LessOrEqual:
719 case Operator.GreaterOrEqual:
723 case Operator.NotEqual:
725 case Operator.BitwiseAnd:
727 case Operator.BitwiseOr:
729 case Operator.ExclusiveOr:
731 case Operator.LogicalOr:
733 case Operator.LogicalAnd:
737 return oper.ToString ();
740 Expression ForceConversion (Expression expr, Type target_type)
742 if (expr.Type == target_type)
745 return ConvertImplicit (expr, target_type);
749 // Note that handling the case l == Decimal || r == Decimal
750 // is taken care of by the Step 1 Operator Overload resolution.
752 void DoNumericPromotions (TypeContainer tc, Type l, Type r)
754 if (l == TypeManager.double_type || r == TypeManager.double_type){
756 // If either operand is of type double, the other operand is
757 // conveted to type double.
759 if (r != TypeManager.double_type)
760 right = ConvertImplicit (right, TypeManager.double_type);
761 if (l != TypeManager.double_type)
762 left = ConvertImplicit (left, TypeManager.double_type);
764 type = TypeManager.double_type;
765 } else if (l == TypeManager.float_type || r == TypeManager.float_type){
767 // if either operand is of type float, th eother operand is
768 // converd to type float.
770 if (r != TypeManager.double_type)
771 right = ConvertImplicit (right, TypeManager.float_type);
772 if (l != TypeManager.double_type)
773 left = ConvertImplicit (left, TypeManager.float_type);
774 type = TypeManager.float_type;
775 } else if (l == TypeManager.uint64_type || r == TypeManager.uint64_type){
777 // If either operand is of type ulong, the other operand is
778 // converted to type ulong. or an error ocurrs if the other
779 // operand is of type sbyte, short, int or long
783 if (l == TypeManager.uint64_type)
785 else if (r == TypeManager.uint64_type)
788 if ((other == TypeManager.sbyte_type) ||
789 (other == TypeManager.short_type) ||
790 (other == TypeManager.int32_type) ||
791 (other == TypeManager.int64_type)){
792 string oper = OperName ();
794 tc.RootContext.Report.Error (34, "Operator `" + OperName ()
795 + "' is ambiguous on operands of type `"
796 + TypeManager.CSharpName (l) + "' "
797 + "and `" + TypeManager.CSharpName (r)
800 type = TypeManager.uint64_type;
801 } else if (l == TypeManager.int64_type || r == TypeManager.int64_type){
803 // If either operand is of type long, the other operand is converted
806 if (l != TypeManager.int64_type)
807 left = ConvertImplicit (left, TypeManager.int64_type);
808 if (r != TypeManager.int64_type)
809 right = ConvertImplicit (right, TypeManager.int64_type);
811 type = TypeManager.int64_type;
812 } else if (l == TypeManager.uint32_type || r == TypeManager.uint32_type){
814 // If either operand is of type uint, and the other
815 // operand is of type sbyte, short or int, othe operands are
816 // converted to type long.
820 if (l == TypeManager.uint32_type)
822 else if (r == TypeManager.uint32_type)
825 if ((other == TypeManager.sbyte_type) ||
826 (other == TypeManager.short_type) ||
827 (other == TypeManager.int32_type)){
828 left = ForceConversion (left, TypeManager.int64_type);
829 right = ForceConversion (right, TypeManager.int64_type);
830 type = TypeManager.int64_type;
833 // if either operand is of type uint, the other
834 // operand is converd to type uint
836 left = ForceConversion (left, TypeManager.uint32_type);
837 right = ForceConversion (left, TypeManager.uint32_type);
838 type = TypeManager.uint32_type;
841 left = ForceConversion (left, TypeManager.int32_type);
842 right = ForceConversion (right, TypeManager.int32_type);
843 type = TypeManager.int32_type;
847 void error19 (TypeContainer tc)
849 tc.RootContext.Report.Error (
851 "Operator " + OperName () + " cannot be applied to operands of type `" +
852 TypeManager.CSharpName (left.Type) + "' and `" +
853 TypeManager.CSharpName (right.Type) + "'");
857 Expression CheckShiftArguments (TypeContainer tc)
863 e = ForceConversion (right, TypeManager.int32_type);
870 if (((e = ConvertImplicit (left, TypeManager.int32_type)) != null) ||
871 ((e = ConvertImplicit (left, TypeManager.uint32_type)) != null) ||
872 ((e = ConvertImplicit (left, TypeManager.int64_type)) != null) ||
873 ((e = ConvertImplicit (left, TypeManager.uint64_type)) != null)){
882 Expression ResolveOperator (TypeContainer tc)
888 // Step 1: Perform Operator Overload location
890 Expression left_expr, right_expr;
892 string op = "Operator" + oper;
894 left_expr = MemberLookup (tc.RootContext, l, op, false);
896 if (!(left_expr is MethodGroupExpr)){
897 // FIXME: Find proper error
898 tc.RootContext.Report.Error (118, "Did find something that is not a method");
902 right_expr = MemberLookup (tc.RootContext, r, op, false);
904 if (!(right_expr is MethodGroupExpr)){
905 // FIXME: Find proper error
906 tc.RootContext.Report.Error (118, "Did find something that is not a method");
910 if (left_expr != null || right_expr != null) {
912 // Now we need to form the union of these two sets and
913 // then call OverloadResolve
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) {
1094 if (method is MethodInfo) {
1095 Invocation.EmitArguments (ec, Arguments);
1096 ec.ig.Emit (OpCodes.Call, (MethodInfo) method);
1105 case Operator.Multiply:
1107 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
1108 opcode = OpCodes.Mul_Ovf;
1109 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
1110 opcode = OpCodes.Mul_Ovf_Un;
1112 opcode = OpCodes.Mul;
1114 opcode = OpCodes.Mul;
1118 case Operator.Divide:
1119 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
1120 opcode = OpCodes.Div_Un;
1122 opcode = OpCodes.Div;
1125 case Operator.Modulo:
1126 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
1127 opcode = OpCodes.Rem_Un;
1129 opcode = OpCodes.Rem;
1134 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
1135 opcode = OpCodes.Add_Ovf;
1136 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
1137 opcode = OpCodes.Add_Ovf_Un;
1139 opcode = OpCodes.Mul;
1141 opcode = OpCodes.Add;
1144 case Operator.Subtract:
1146 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
1147 opcode = OpCodes.Sub_Ovf;
1148 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
1149 opcode = OpCodes.Sub_Ovf_Un;
1151 opcode = OpCodes.Sub;
1153 opcode = OpCodes.Sub;
1156 case Operator.ShiftRight:
1157 opcode = OpCodes.Shr;
1160 case Operator.ShiftLeft:
1161 opcode = OpCodes.Shl;
1164 case Operator.Equal:
1165 opcode = OpCodes.Ceq;
1168 case Operator.NotEqual:
1169 ec.ig.Emit (OpCodes.Ceq);
1170 ec.ig.Emit (OpCodes.Ldc_I4_0);
1172 opcode = OpCodes.Ceq;
1175 case Operator.LessThan:
1176 opcode = OpCodes.Clt;
1179 case Operator.GreaterThan:
1180 opcode = OpCodes.Cgt;
1183 case Operator.LessOrEqual:
1184 ec.ig.Emit (OpCodes.Cgt);
1185 ec.ig.Emit (OpCodes.Ldc_I4_0);
1187 opcode = OpCodes.Ceq;
1190 case Operator.GreaterOrEqual:
1191 ec.ig.Emit (OpCodes.Clt);
1192 ec.ig.Emit (OpCodes.Ldc_I4_1);
1194 opcode = OpCodes.Sub;
1197 case Operator.LogicalOr:
1198 case Operator.BitwiseOr:
1199 opcode = OpCodes.Or;
1202 case Operator.LogicalAnd:
1203 case Operator.BitwiseAnd:
1204 opcode = OpCodes.And;
1207 case Operator.ExclusiveOr:
1208 opcode = OpCodes.Xor;
1212 throw new Exception ("This should not happen: Operator = "
1213 + oper.ToString ());
1216 ec.ig.Emit (opcode);
1220 public class Conditional : Expression {
1221 Expression expr, trueExpr, falseExpr;
1223 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr)
1226 this.trueExpr = trueExpr;
1227 this.falseExpr = falseExpr;
1230 public Expression Expr {
1236 public Expression TrueExpr {
1242 public Expression FalseExpr {
1248 public override Expression Resolve (TypeContainer tc)
1250 // FIXME: Implement;
1254 public override void Emit (EmitContext ec)
1259 public class SimpleName : Expression {
1262 public SimpleName (string name)
1267 public string Name {
1274 // Checks whether we are trying to access an instance
1275 // property, method or field from a static body.
1277 Expression MemberStaticCheck (Report r, Expression e)
1279 if (e is FieldExpr){
1280 FieldInfo fi = ((FieldExpr) e).FieldInfo;
1284 "An object reference is required " +
1285 "for the non-static field `"+name+"'");
1288 } else if (e is MethodGroupExpr){
1289 // FIXME: Pending reorganization of MemberLookup
1290 // Basically at this point we should have the
1291 // best match already selected for us, and
1292 // we should only have to check a *single*
1293 // Method for its static on/off bit.
1295 } else if (e is PropertyExpr){
1296 if (!((PropertyExpr) e).IsStatic){
1298 "An object reference is required " +
1299 "for the non-static property access `"+
1309 // 7.5.2: Simple Names.
1311 // Local Variables and Parameters are handled at
1312 // parse time, so they never occur as SimpleNames.
1314 Expression ResolveSimpleName (TypeContainer tc)
1317 Report r = tc.RootContext.Report;
1319 e = MemberLookup (tc.RootContext, tc.TypeBuilder, name, true);
1323 if ((tc.ModFlags & Modifiers.STATIC) != 0)
1324 return MemberStaticCheck (r, e);
1330 // Do step 3 of the Simple Name resolution.
1332 // FIXME: implement me.
1338 // SimpleName needs to handle a multitude of cases:
1340 // simple_names and qualified_identifiers are placed on
1341 // the tree equally.
1343 public override Expression Resolve (TypeContainer tc)
1345 if (name.IndexOf (".") != -1)
1346 return ResolveMemberAccess (tc, name);
1348 return ResolveSimpleName (tc);
1351 public override void Emit (EmitContext ec)
1356 public class LocalVariableReference : Expression {
1357 public readonly string Name;
1358 public readonly Block Block;
1360 public LocalVariableReference (Block block, string name)
1364 eclass = ExprClass.Variable;
1367 public VariableInfo VariableInfo {
1369 return Block.GetVariableInfo (Name);
1373 public override Expression Resolve (TypeContainer tc)
1375 VariableInfo vi = Block.GetVariableInfo (Name);
1377 type = vi.VariableType;
1381 public override void Emit (EmitContext ec)
1383 VariableInfo vi = VariableInfo;
1384 ILGenerator ig = ec.ig;
1389 ig.Emit (OpCodes.Ldloc_0);
1393 ig.Emit (OpCodes.Ldloc_1);
1397 ig.Emit (OpCodes.Ldloc_2);
1401 ig.Emit (OpCodes.Ldloc_3);
1406 ig.Emit (OpCodes.Ldloc_S, idx);
1408 ig.Emit (OpCodes.Ldloc, idx);
1414 public class ParameterReference : Expression {
1415 public readonly Parameters Pars;
1416 public readonly String Name;
1417 public readonly int Idx;
1419 public ParameterReference (Parameters pars, int idx, string name)
1426 public override Expression Resolve (TypeContainer tc)
1428 Type [] types = Pars.GetParameterInfo (tc);
1435 public override void Emit (EmitContext ec)
1438 ec.ig.Emit (OpCodes.Ldarg_S, Idx);
1440 ec.ig.Emit (OpCodes.Ldarg, Idx);
1445 // Used for arguments to New(), Invocation()
1447 public class Argument {
1454 public readonly AType Type;
1457 public Argument (Expression expr, AType type)
1463 public Expression Expr {
1469 public bool Resolve (TypeContainer tc)
1471 expr = expr.Resolve (tc);
1473 return expr != null;
1476 public void Emit (EmitContext ec)
1483 // Invocation of methods or delegates.
1485 public class Invocation : Expression {
1486 public readonly ArrayList Arguments;
1488 MethodBase method = null;
1490 static Hashtable method_parameter_cache;
1492 static Invocation ()
1494 method_parameter_cache = new Hashtable ();
1498 // arguments is an ArrayList, but we do not want to typecast,
1499 // as it might be null.
1501 // FIXME: only allow expr to be a method invocation or a
1502 // delegate invocation (7.5.5)
1504 public Invocation (Expression expr, ArrayList arguments)
1507 Arguments = arguments;
1510 public Expression Expr {
1517 /// Computes whether Argument `a' and the ParameterInfo `pi' are
1518 /// compatible, and if so, how good is the match (in terms of
1519 /// "better conversions" (7.4.2.3).
1521 /// 0 is the best possible match.
1522 /// -1 represents a type mismatch.
1523 /// -2 represents a ref/out mismatch.
1525 static int Badness (Argument a, Type t)
1527 if (a.Expr.Type == null){
1528 throw new Exception ("Expression of type " + a.Expr + " does not resolve its type");
1531 if (t == a.Expr.Type)
1534 // FIXME: Implement implicit conversions here.
1535 // FIXME: Implement better conversion here.
1541 // Returns the Parameters (a ParameterData interface) for the
1544 static ParameterData GetParameterData (MethodBase mb)
1546 object pd = method_parameter_cache [mb];
1549 return (ParameterData) pd;
1551 if (mb is MethodBuilder || mb is ConstructorBuilder){
1552 MethodCore mc = TypeContainer.LookupMethodByBuilder (mb);
1554 InternalParameters ip = mc.ParameterInfo;
1555 method_parameter_cache [mb] = ip;
1557 return (ParameterData) ip;
1559 ParameterInfo [] pi = mb.GetParameters ();
1560 ReflectionParameters rp = new ReflectionParameters (pi);
1561 method_parameter_cache [mb] = rp;
1563 return (ParameterData) rp;
1568 // Find the Applicable Function Members (7.4.2.1)
1570 // me: Method Group expression with the members to select.
1571 // it might contain constructors or methods (or anything
1572 // that maps to a method).
1574 // Arguments: ArrayList containing resolved Argument objects.
1576 // Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
1577 // that is the best match of me on Arguments.
1580 public static MethodBase OverloadResolve (MethodGroupExpr me, ArrayList Arguments)
1582 ArrayList afm = new ArrayList ();
1583 int best_match = 10000;
1584 int best_match_idx = -1;
1585 MethodBase method = null;
1588 if (Arguments == null)
1591 argument_count = Arguments.Count;
1593 for (int i = me.Methods.Length; i > 0; ){
1595 MethodBase mb = me.Methods [i];
1598 pd = GetParameterData (mb);
1600 // If this is the case, we have a method with no args - presumably
1601 if (pd == null && argument_count == 0)
1602 return me.Methods [0];
1605 // Compute how good this is
1607 if (pd.Count == argument_count){
1610 for (int j = argument_count; j > 0;){
1614 Argument a = (Argument) Arguments [j];
1616 x = Badness (a, pd.ParameterType (j));
1619 badness = best_match;
1626 if (badness < best_match){
1627 best_match = badness;
1628 method = me.Methods [i];
1634 if (best_match_idx == -1)
1641 public override Expression Resolve (TypeContainer tc)
1644 // First, resolve the expression that is used to
1645 // trigger the invocation
1647 this.expr = expr.Resolve (tc);
1648 if (this.expr == null)
1651 if (!(this.expr is MethodGroupExpr)){
1652 tc.RootContext.Report.Error (118,
1653 "Denotes a non-method (Detail: ExprClass=" + this.expr.ExprClass+")");
1658 // Next, evaluate all the expressions in the argument list
1660 if (Arguments != null){
1661 for (int i = Arguments.Count; i > 0;){
1663 Argument a = (Argument) Arguments [i];
1665 if (!a.Resolve (tc))
1670 method = OverloadResolve ((MethodGroupExpr) this.expr, Arguments);
1672 if (method == null){
1673 tc.RootContext.Report.Error (-6,
1674 "Figure out error: Can not find a good function for this argument list");
1678 if (method is MethodInfo)
1679 type = ((MethodInfo)method).ReturnType;
1684 public static void EmitArguments (EmitContext ec, ArrayList Arguments)
1688 if (Arguments != null)
1689 top = Arguments.Count;
1693 for (int i = 0; i < top; i++){
1694 Argument a = (Argument) Arguments [i];
1700 public override void Emit (EmitContext ec)
1702 bool is_static = method.IsStatic;
1705 MethodGroupExpr mg = (MethodGroupExpr) this.expr;
1707 if (mg.InstanceExpression == null){
1708 Console.WriteLine ("Internal compiler error. Should check in the method groups for static/instance");
1711 mg.InstanceExpression.Emit (ec);
1714 if (Arguments != null)
1715 EmitArguments (ec, Arguments);
1717 if (method.IsStatic){
1718 if (method is MethodInfo)
1719 ec.ig.Emit (OpCodes.Call, (MethodInfo) method);
1721 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
1723 if (method is MethodInfo)
1724 ec.ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
1726 ec.ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
1732 public class New : Expression {
1739 public readonly NType NewType;
1740 public readonly ArrayList Arguments;
1741 public readonly string RequestedType;
1742 // These are for the case when we have an array
1743 public readonly string Rank;
1744 public readonly ArrayList Indices;
1745 public readonly ArrayList Initializers;
1747 MethodBase method = null;
1749 public New (string requested_type, ArrayList arguments)
1751 RequestedType = requested_type;
1752 Arguments = arguments;
1753 NewType = NType.Object;
1756 public New (string requested_type, ArrayList exprs, string rank, ArrayList initializers)
1758 RequestedType = requested_type;
1761 Initializers = initializers;
1762 NewType = NType.Array;
1765 public override Expression Resolve (TypeContainer tc)
1767 type = tc.LookupType (RequestedType, false);
1774 ml = MemberLookup (tc.RootContext, type, ".ctor", false,
1775 MemberTypes.Constructor, AllBindingsFlags);
1777 if (! (ml is MethodGroupExpr)){
1779 // FIXME: Find proper error
1781 tc.RootContext.Report.Error (118, "Did find something that is not a method");
1785 if (Arguments != null){
1786 for (int i = Arguments.Count; i > 0;){
1788 Argument a = (Argument) Arguments [i];
1790 if (!a.Resolve (tc))
1795 method = Invocation.OverloadResolve ((MethodGroupExpr) ml, Arguments);
1797 if (method == null){
1798 tc.RootContext.Report.Error (-6,
1799 "New invocation: Can not find a constructor for this argument list");
1806 public override void Emit (EmitContext ec)
1808 Invocation.EmitArguments (ec, Arguments);
1809 ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
1813 public class This : Expression {
1814 public override Expression Resolve (TypeContainer tc)
1816 // FIXME: Implement;
1820 public override void Emit (EmitContext ec)
1825 public class TypeOf : Expression {
1826 public readonly string QueriedType;
1828 public TypeOf (string queried_type)
1830 QueriedType = queried_type;
1833 public override Expression Resolve (TypeContainer tc)
1835 // FIXME: Implement;
1839 public override void Emit (EmitContext ec)
1844 public class SizeOf : Expression {
1845 public readonly string QueriedType;
1847 public SizeOf (string queried_type)
1849 this.QueriedType = queried_type;
1852 public override Expression Resolve (TypeContainer tc)
1854 // FIXME: Implement;
1858 public override void Emit (EmitContext ec)
1863 public class MemberAccess : Expression {
1864 public readonly string Identifier;
1866 Expression member_lookup;
1868 public MemberAccess (Expression expr, string id)
1874 public Expression Expr {
1880 public override Expression Resolve (TypeContainer tc)
1882 Expression new_expression = expr.Resolve (tc);
1884 if (new_expression == null)
1887 Console.WriteLine ("This is what I figured: " + expr.Type + "/" + expr.ExprClass);
1889 member_lookup = MemberLookup (tc.RootContext, expr.Type, Identifier, false);
1891 if (member_lookup is MethodGroupExpr){
1892 MethodGroupExpr mg = (MethodGroupExpr) member_lookup;
1895 // Bind the instance expression to it
1897 // FIXME: This is a horrible way of detecting if it is
1898 // an instance expression. Figure out how to fix this.
1900 Console.WriteLine ("FIXME: Horrible way of figuring if something is an isntance");
1902 if (expr is LocalVariableReference)
1903 mg.InstanceExpression = expr;
1905 return member_lookup;
1908 // FIXME: This should generate the proper node
1909 // ie, for a Property Access, it should like call it
1915 public override void Emit (EmitContext ec)
1922 // Nodes of type Namespace are created during the semantic
1923 // analysis to resolve member_access/qualified_identifier/simple_name
1926 // They are born `resolved'.
1928 public class NamespaceExpr : Expression {
1929 public readonly string Name;
1931 public NamespaceExpr (string name)
1934 eclass = ExprClass.Namespace;
1937 public override Expression Resolve (TypeContainer tc)
1942 public override void Emit (EmitContext ec)
1948 // Fully resolved expression that evaluates to a type
1950 public class TypeExpr : Expression {
1951 public TypeExpr (Type t)
1954 eclass = ExprClass.Type;
1957 override public Expression Resolve (TypeContainer tc)
1962 override public void Emit (EmitContext ec)
1969 // MethodGroup Expression.
1971 // This is a fully resolved expression that evaluates to a type
1973 public class MethodGroupExpr : Expression {
1974 public readonly MethodBase [] Methods;
1975 Expression instance_expression = null;
1977 public MethodGroupExpr (MemberInfo [] mi)
1979 Methods = new MethodBase [mi.Length];
1980 mi.CopyTo (Methods, 0);
1981 eclass = ExprClass.MethodGroup;
1985 // `A method group may have associated an instance expression'
1987 public Expression InstanceExpression {
1989 return instance_expression;
1993 instance_expression = value;
1997 override public Expression Resolve (TypeContainer tc)
2002 override public void Emit (EmitContext ec)
2008 public class BuiltinTypeAccess : Expression {
2009 public readonly string AccessBase;
2010 public readonly string Method;
2012 public BuiltinTypeAccess (string type, string method)
2014 System.Console.WriteLine ("DUDE! This type should be fully resolved!");
2019 public override Expression Resolve (TypeContainer tc)
2021 // FIXME: Implement;
2025 public override void Emit (EmitContext ec)
2031 // Fully resolved expression that evaluates to a Field
2033 public class FieldExpr : Expression {
2034 public readonly FieldInfo FieldInfo;
2036 public FieldExpr (FieldInfo fi)
2039 eclass = ExprClass.Variable;
2040 type = fi.FieldType;
2043 override public Expression Resolve (TypeContainer tc)
2045 // We are born in resolved state.
2049 override public void Emit (EmitContext ec)
2051 // FIXME: Assert that this should not be reached?
2056 // Fully resolved expression that evaluates to a Property
2058 public class PropertyExpr : Expression {
2059 public readonly PropertyInfo PropertyInfo;
2060 public readonly bool IsStatic;
2062 public PropertyExpr (PropertyInfo pi)
2065 eclass = ExprClass.PropertyAccess;
2068 MethodBase [] acc = pi.GetAccessors ();
2070 for (int i = 0; i < acc.Length; i++)
2071 if (acc [i].IsStatic)
2074 type = pi.PropertyType;
2077 override public Expression Resolve (TypeContainer tc)
2079 // We are born in resolved state.
2083 override public void Emit (EmitContext ec)
2085 // FIXME: Implement.
2090 // Fully resolved expression that evaluates to a Property
2092 public class EventExpr : Expression {
2093 public readonly EventInfo EventInfo;
2095 public EventExpr (EventInfo ei)
2098 eclass = ExprClass.EventAccess;
2101 override public Expression Resolve (TypeContainer tc)
2103 // We are born in resolved state.
2107 override public void Emit (EmitContext ec)
2109 // FIXME: Implement.
2113 public class CheckedExpr : Expression {
2115 public readonly Expression Expr;
2117 public CheckedExpr (Expression e)
2122 public override Expression Resolve (TypeContainer tc)
2124 // FIXME : Implement !
2128 public override void Emit (EmitContext ec)
2134 public class UnCheckedExpr : Expression {
2136 public readonly Expression Expr;
2138 public UnCheckedExpr (Expression e)
2143 public override Expression Resolve (TypeContainer tc)
2145 // FIXME : Implement !
2149 public override void Emit (EmitContext ec)
2155 public class ElementAccess : Expression {
2157 public readonly ArrayList Arguments;
2158 public readonly Expression Expr;
2160 public ElementAccess (Expression e, ArrayList e_list)
2166 public override Expression Resolve (TypeContainer tc)
2168 // FIXME : Implement
2172 public override void Emit (EmitContext ec)
2174 // FIXME : Implement !
2179 public class BaseAccess : Expression {
2181 public enum BaseAccessType {
2186 public readonly BaseAccessType BAType;
2187 public readonly string Member;
2188 public readonly ArrayList Arguments;
2190 public BaseAccess (BaseAccessType t, string member, ArrayList args)
2198 public override Expression Resolve (TypeContainer tc)
2200 // FIXME : Implement !
2204 public override void Emit (EmitContext ec)