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 protected static Expression MemberLookup (RootContext rc, Type t, string name, bool same_type)
118 // MemberTypes.Constructor |
122 MemberTypes.NestedType |
123 MemberTypes.Property;
126 BindingFlags.Public |
127 BindingFlags.Static |
128 BindingFlags.Instance;
131 bf |= BindingFlags.NonPublic;
133 MemberInfo [] mi = rc.TypeManager.FindMembers (t, mt, bf, Type.FilterName, name);
138 if (mi.Length == 1 && !(mi [0] is MethodInfo))
139 return Expression.ExprClassFromMemberInfo (mi [0]);
141 for (int i = 0; i < mi.Length; i++)
142 if (!(mi [i] is MethodInfo)){
143 rc.Report.Error (-5, "Do not know how to reproduce this case: " +
144 "Methods and non-Method with the same name, report this please");
148 return new MethodGroupExpr (mi);
152 // Resolves the E in `E.I' side for a member_access
154 // This is suboptimal and should be merged with ResolveMemberAccess
155 static Expression ResolvePrimary (TypeContainer tc, string name)
157 int dot_pos = name.LastIndexOf (".");
159 if (tc.RootContext.IsNamespace (name))
160 return new NamespaceExpr (name);
164 Type t = tc.LookupType (name, false);
167 return new TypeExpr (t);
173 static public Expression ResolveMemberAccess (TypeContainer tc, string name)
176 int dot_pos = name.LastIndexOf (".");
177 string left = name.Substring (0, dot_pos);
178 string right = name.Substring (dot_pos + 1);
180 left_e = ResolvePrimary (tc, left);
184 switch (left_e.ExprClass){
186 return MemberLookup (tc.RootContext,
188 left_e.Type == tc.TypeBuilder);
190 case ExprClass.Namespace:
191 case ExprClass.PropertyAccess:
192 case ExprClass.IndexerAccess:
193 case ExprClass.Variable:
194 case ExprClass.Value:
195 case ExprClass.Nothing:
196 case ExprClass.EventAccess:
197 case ExprClass.MethodGroup:
198 case ExprClass.Invalid:
199 tc.RootContext.Report.Error (-1000,
200 "Internal compiler error, should have " +
201 "got these handled before");
208 static public Expression ImplicitReferenceConversion (Expression expr, Type target_type)
210 Type expr_type = expr.Type;
212 if (target_type == TypeManager.object_type) {
213 if (expr_type.IsClass)
214 return new EmptyCast (expr, target_type);
215 if (expr_type.IsValueType)
216 return new BoxedCast (expr, target_type);
217 } else if (expr_type.IsSubclassOf (target_type))
218 return new EmptyCast (expr, target_type);
220 // FIXME: missing implicit reference conversions:
222 // from any class-type S to any interface-type T.
223 // from any interface type S to interface-type T.
224 // from an array-type S to an array-type of type T
225 // from an array-type to System.Array
226 // from any delegate type to System.Delegate
227 // from any array-type or delegate type into System.ICloneable.
228 // from the null type to any reference-type.
236 // Converts implicitly the resolved expression `expr' into the
237 // `target_type'. It returns a new expression that can be used
238 // in a context that expects a `target_type'.
240 static public Expression ConvertImplicit (Expression expr, Type target_type)
242 Type expr_type = expr.Type;
244 if (expr_type == target_type){
245 Console.WriteLine ("Hey, ConvertImplicit was called with no job to do");
250 // Step 1: Perform implicit conversions as found on expr.Type
254 // Step 2: Built-in conversions.
256 if (expr_type == TypeManager.sbyte_type){
258 // From sbyte to short, int, long, float, double.
260 if (target_type == TypeManager.int32_type)
261 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
262 if (target_type == TypeManager.int64_type)
263 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
264 if (target_type == TypeManager.double_type)
265 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
266 if (target_type == TypeManager.float_type)
267 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
268 if (target_type == TypeManager.short_type)
269 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
270 } else if (expr_type == TypeManager.byte_type){
272 // From byte to short, ushort, int, uint, long, ulong, float, double
274 if ((target_type == TypeManager.short_type) ||
275 (target_type == TypeManager.ushort_type) ||
276 (target_type == TypeManager.int32_type) ||
277 (target_type == TypeManager.uint32_type))
278 return new EmptyCast (expr, target_type);
280 if (target_type == TypeManager.uint64_type)
281 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
282 if (target_type == TypeManager.int64_type)
283 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
285 if (target_type == TypeManager.float_type)
286 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
287 if (target_type == TypeManager.double_type)
288 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
289 } else if (expr_type == TypeManager.short_type){
291 // From short to int, long, float, double
293 if (target_type == TypeManager.int32_type)
294 return new EmptyCast (expr, target_type);
295 if (target_type == TypeManager.int64_type)
296 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
297 if (target_type == TypeManager.double_type)
298 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
299 if (target_type == TypeManager.float_type)
300 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
301 } else if (expr_type == TypeManager.ushort_type){
303 // From ushort to int, uint, long, ulong, float, double
305 if ((target_type == TypeManager.uint32_type) ||
306 (target_type == TypeManager.uint64_type))
307 return new EmptyCast (expr, target_type);
309 if (target_type == TypeManager.int32_type)
310 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
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.int32_type){
319 // From int to long, float, double
321 if (target_type == TypeManager.int64_type)
322 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
323 if (target_type == TypeManager.double_type)
324 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
325 if (target_type == TypeManager.float_type)
326 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
327 } else if (expr_type == TypeManager.uint32_type){
329 // From uint to long, ulong, float, double
331 if (target_type == TypeManager.int64_type)
332 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
333 if (target_type == TypeManager.uint64_type)
334 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
335 if (target_type == TypeManager.double_type)
336 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
338 if (target_type == TypeManager.float_type)
339 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
341 } else if ((expr_type == TypeManager.uint64_type) ||
342 (expr_type == TypeManager.int64_type)){
344 // From long to float, double
346 if (target_type == TypeManager.double_type)
347 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
349 if (target_type == TypeManager.float_type)
350 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
352 } else if (expr_type == TypeManager.char_type){
354 // From char to ushort, int, uint, long, ulong, float, double
356 if ((target_type == TypeManager.ushort_type) ||
357 (target_type == TypeManager.int32_type) ||
358 (target_type == TypeManager.uint32_type))
359 return new EmptyCast (expr, target_type);
360 if (target_type == TypeManager.uint64_type)
361 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
362 if (target_type == TypeManager.int64_type)
363 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
364 if (target_type == TypeManager.float_type)
365 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
366 if (target_type == TypeManager.double_type)
367 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
369 return ImplicitReferenceConversion (expr, target_type);
374 // Could not find an implicit cast.
380 // Performs an explicit conversion of the expression `expr' whose
381 // type is expr.Type to `target_type'.
383 static public Expression ConvertExplicit (Expression expr, Type target_type)
391 // This kind of cast is used to encapsulate the child
392 // whose type is child.Type into an expression that is
393 // reported to return "return_type". This is used to encapsulate
394 // expressions which have compatible types, but need to be dealt
395 // at higher levels with.
397 // For example, a "byte" expression could be encapsulated in one
398 // of these as an "unsigned int". The type for the expression
399 // would be "unsigned int".
403 public class EmptyCast : Expression {
404 protected Expression child;
406 public EmptyCast (Expression child, Type return_type)
408 ExprClass = child.ExprClass;
413 public override Expression Resolve (TypeContainer tc)
415 // This should never be invoked, we are born in fully
416 // initialized state.
421 public override void Emit (EmitContext ec)
427 public class BoxedCast : EmptyCast {
429 public BoxedCast (Expression expr, Type target_type)
430 : base (expr, target_type)
434 public override Expression Resolve (TypeContainer tc)
436 // This should never be invoked, we are born in fully
437 // initialized state.
442 public override void Emit (EmitContext ec)
445 ec.ig.Emit (OpCodes.Box, child.Type);
451 // This kind of cast is used to encapsulate a child expression
452 // that can be trivially converted to a target type using one or
453 // two opcodes. The opcodes are passed as arguments.
455 public class OpcodeCast : EmptyCast {
459 public OpcodeCast (Expression child, Type return_type, OpCode op)
460 : base (child, return_type)
464 second_valid = false;
467 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
468 : base (child, return_type)
476 public override Expression Resolve (TypeContainer tc)
478 // This should never be invoked, we are born in fully
479 // initialized state.
484 public override void Emit (EmitContext ec)
495 public class Unary : Expression {
496 public enum Operator {
497 Plus, Minus, Negate, BitComplement,
498 Indirection, AddressOf, PreIncrement,
499 PreDecrement, PostIncrement, PostDecrement
505 public Unary (Operator op, Expression expr)
511 public Expression Expr {
521 public Operator Oper {
531 public override Expression Resolve (TypeContainer tc)
537 public override void Emit (EmitContext ec)
542 public class Probe : Expression {
547 public enum Operator {
551 public Probe (Operator oper, Expression expr, string probe_type)
554 this.probe_type = probe_type;
558 public Operator Oper {
564 public Expression Expr {
570 public string ProbeType {
576 public override Expression Resolve (TypeContainer tc)
582 public override void Emit (EmitContext ec)
587 public class Cast : Expression {
591 public Cast (string cast_type, Expression expr)
593 this.target_type = target_type;
597 public string TargetType {
603 public Expression Expr {
612 public override Expression Resolve (TypeContainer tc)
618 public override void Emit (EmitContext ec)
623 public class Binary : Expression {
624 public enum Operator {
625 Multiply, Divide, Modulo,
627 ShiftLeft, ShiftRight,
628 LessThan, GreatherThan, LessOrEqual, GreatherOrEqual,
638 Expression left, right;
640 public Binary (Operator oper, Expression left, Expression right)
647 public Operator Oper {
656 public Expression Left {
665 public Expression Right {
676 // Retruns a stringified representation of the Operator
681 case Operator.Multiply:
683 case Operator.Divide:
685 case Operator.Modulo:
689 case Operator.Substract:
691 case Operator.ShiftLeft:
693 case Operator.ShiftRight:
695 case Operator.LessThan:
697 case Operator.GreatherThan:
699 case Operator.LessOrEqual:
701 case Operator.GreatherOrEqual:
705 case Operator.NotEqual:
707 case Operator.BitwiseAnd:
709 case Operator.BitwiseOr:
711 case Operator.ExclusiveOr:
713 case Operator.LogicalOr:
715 case Operator.LogicalAnd:
719 return oper.ToString ();
722 Expression ForceConversion (Expression expr, Type target_type)
724 if (expr.Type == target_type)
727 return ConvertImplicit (expr, target_type);
731 // Note that handling the case l == Decimal || r == Decimal
732 // is taken care of by the Step 1 Operator Overload resolution.
734 void DoNumericPromotions (TypeContainer tc, Type l, Type r)
736 if (l == TypeManager.double_type || r == TypeManager.double_type){
738 // If either operand is of type double, the other operand is
739 // conveted to type double.
741 if (r != TypeManager.double_type)
742 right = ConvertImplicit (right, TypeManager.double_type);
743 if (l != TypeManager.double_type)
744 left = ConvertImplicit (left, TypeManager.double_type);
746 type = TypeManager.double_type;
747 } else if (l == TypeManager.float_type || r == TypeManager.float_type){
749 // if either operand is of type float, th eother operand is
750 // converd to type float.
752 if (r != TypeManager.double_type)
753 right = ConvertImplicit (right, TypeManager.float_type);
754 if (l != TypeManager.double_type)
755 left = ConvertImplicit (left, TypeManager.float_type);
756 type = TypeManager.float_type;
757 } else if (l == TypeManager.uint64_type || r == TypeManager.uint64_type){
759 // If either operand is of type ulong, the other operand is
760 // converted to type ulong. or an error ocurrs if the other
761 // operand is of type sbyte, short, int or long
765 if (l == TypeManager.uint64_type)
767 else if (r == TypeManager.uint64_type)
770 if ((other == TypeManager.sbyte_type) ||
771 (other == TypeManager.short_type) ||
772 (other == TypeManager.int32_type) ||
773 (other == TypeManager.int64_type)){
774 string oper = OperName ();
776 tc.RootContext.Report.Error (34, "Operator `" + OperName ()
777 + "' is ambiguous on operands of type `"
778 + TypeManager.CSharpName (l) + "' "
779 + "and `" + TypeManager.CSharpName (r)
782 type = TypeManager.uint64_type;
783 } else if (l == TypeManager.int64_type || r == TypeManager.int64_type){
785 // If either operand is of type long, the other operand is converted
788 if (l != TypeManager.int64_type)
789 left = ConvertImplicit (left, TypeManager.int64_type);
790 if (r != TypeManager.int64_type)
791 right = ConvertImplicit (right, TypeManager.int64_type);
793 type = TypeManager.int64_type;
794 } else if (l == TypeManager.uint32_type || r == TypeManager.uint32_type){
796 // If either operand is of type uint, and the other
797 // operand is of type sbyte, short or int, othe operands are
798 // converted to type long.
802 if (l == TypeManager.uint32_type)
804 else if (r == TypeManager.uint32_type)
807 if ((other == TypeManager.sbyte_type) ||
808 (other == TypeManager.short_type) ||
809 (other == TypeManager.int32_type)){
810 left = ForceConversion (left, TypeManager.int64_type);
811 right = ForceConversion (right, TypeManager.int64_type);
812 type = TypeManager.int64_type;
815 // if either operand is of type uint, the other
816 // operand is converd to type uint
818 left = ForceConversion (left, TypeManager.uint32_type);
819 right = ForceConversion (left, TypeManager.uint32_type);
820 type = TypeManager.uint32_type;
823 left = ForceConversion (left, TypeManager.int32_type);
824 right = ForceConversion (right, TypeManager.int32_type);
825 type = TypeManager.int32_type;
829 void error19 (TypeContainer tc)
831 tc.RootContext.Report.Error (
833 "Operator " + OperName () + " cannot be applied to operands of type `" +
834 TypeManager.CSharpName (left.Type) + "' and `" +
835 TypeManager.CSharpName (right.Type) + "'");
839 Expression CheckShiftArguments (TypeContainer tc)
845 e = ForceConversion (right, TypeManager.int32_type);
852 if (((e = ConvertImplicit (left, TypeManager.int32_type)) != null) ||
853 ((e = ConvertImplicit (left, TypeManager.uint32_type)) != null) ||
854 ((e = ConvertImplicit (left, TypeManager.int64_type)) != null) ||
855 ((e = ConvertImplicit (left, TypeManager.uint64_type)) != null)){
864 Expression ResolveOperator (TypeContainer tc)
870 // Step 1: Perform Operator Overload location
875 // Step 2: Default operations on CLI native types.
878 // Only perform numeric promotions on:
879 // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
881 if (oper == Operator.ShiftLeft || oper == Operator.ShiftRight){
882 return CheckShiftArguments (tc);
883 } else if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
885 if (l != TypeManager.bool_type || r != TypeManager.bool_type)
888 DoNumericPromotions (tc, l, r);
890 if (left == null || right == null)
893 if (oper == Operator.BitwiseAnd ||
894 oper == Operator.BitwiseOr ||
895 oper == Operator.ExclusiveOr){
896 if (!((l == TypeManager.int32_type) ||
897 (l == TypeManager.uint32_type) ||
898 (l == TypeManager.int64_type) ||
899 (l == TypeManager.uint64_type))){
905 if (oper == Operator.Equal ||
906 oper == Operator.NotEqual ||
907 oper == Operator.LessOrEqual ||
908 oper == Operator.LessThan ||
909 oper == Operator.GreatherOrEqual ||
910 oper == Operator.GreatherThan){
911 type = TypeManager.bool_type;
917 public override Expression Resolve (TypeContainer tc)
919 left = left.Resolve (tc);
920 right = right.Resolve (tc);
922 if (left == null || right == null)
925 return ResolveOperator (tc);
928 public bool IsBranchable ()
930 if (oper == Operator.Equal ||
931 oper == Operator.NotEqual ||
932 oper == Operator.LessThan ||
933 oper == Operator.GreatherThan ||
934 oper == Operator.LessOrEqual ||
935 oper == Operator.GreatherOrEqual){
942 // This entry point is used by routines that might want
943 // to emit a brfalse/brtrue after an expression, and instead
944 // they could use a more compact notation.
946 // Typically the code would generate l.emit/r.emit, followed
947 // by the comparission and then a brtrue/brfalse. The comparissions
948 // are sometimes inneficient (there are not as complete as the branches
949 // look for the hacks in Emit using double ceqs).
951 // So for those cases we provide EmitBranchable that can emit the
952 // branch with the test
954 public void EmitBranchable (EmitContext ec, int target)
957 bool close_target = false;
965 opcode = OpCodes.Beq_S;
967 opcode = OpCodes.Beq;
970 case Operator.NotEqual:
972 opcode = OpCodes.Bne_Un_S;
974 opcode = OpCodes.Bne_Un;
977 case Operator.LessThan:
979 opcode = OpCodes.Blt_S;
981 opcode = OpCodes.Blt;
984 case Operator.GreatherThan:
986 opcode = OpCodes.Bgt_S;
988 opcode = OpCodes.Bgt;
991 case Operator.LessOrEqual:
993 opcode = OpCodes.Ble_S;
995 opcode = OpCodes.Ble;
998 case Operator.GreatherOrEqual:
1000 opcode = OpCodes.Bge_S;
1002 opcode = OpCodes.Ble;
1006 throw new Exception ("EmitBranchable called on non-EmitBranchable operator: "
1007 + oper.ToString ());
1010 ec.ig.Emit (opcode, target);
1013 public override void Emit (EmitContext ec)
1015 ILGenerator ig = ec.ig;
1017 Type r = right.Type;
1024 case Operator.Multiply:
1026 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
1027 opcode = OpCodes.Mul_Ovf;
1028 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
1029 opcode = OpCodes.Mul_Ovf_Un;
1031 opcode = OpCodes.Mul;
1033 opcode = OpCodes.Mul;
1037 case Operator.Divide:
1038 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
1039 opcode = OpCodes.Div_Un;
1041 opcode = OpCodes.Div;
1044 case Operator.Modulo:
1045 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
1046 opcode = OpCodes.Rem_Un;
1048 opcode = OpCodes.Rem;
1053 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
1054 opcode = OpCodes.Add_Ovf;
1055 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
1056 opcode = OpCodes.Add_Ovf_Un;
1058 opcode = OpCodes.Mul;
1060 opcode = OpCodes.Add;
1063 case Operator.Substract:
1065 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
1066 opcode = OpCodes.Sub_Ovf;
1067 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
1068 opcode = OpCodes.Sub_Ovf_Un;
1070 opcode = OpCodes.Sub;
1072 opcode = OpCodes.Sub;
1075 case Operator.ShiftRight:
1076 opcode = OpCodes.Shr;
1079 case Operator.ShiftLeft:
1080 opcode = OpCodes.Shl;
1083 case Operator.Equal:
1084 opcode = OpCodes.Ceq;
1087 case Operator.NotEqual:
1088 ec.ig.Emit (OpCodes.Ceq);
1089 ec.ig.Emit (OpCodes.Ldc_I4_0);
1091 opcode = OpCodes.Ceq;
1094 case Operator.LessThan:
1095 opcode = OpCodes.Clt;
1098 case Operator.GreatherThan:
1099 opcode = OpCodes.Cgt;
1102 case Operator.LessOrEqual:
1103 ec.ig.Emit (OpCodes.Cgt);
1104 ec.ig.Emit (OpCodes.Ldc_I4_0);
1106 opcode = OpCodes.Ceq;
1109 case Operator.GreatherOrEqual:
1110 ec.ig.Emit (OpCodes.Clt);
1111 ec.ig.Emit (OpCodes.Ldc_I4_1);
1113 opcode = OpCodes.Sub;
1116 case Operator.LogicalOr:
1117 case Operator.BitwiseOr:
1118 opcode = OpCodes.Or;
1121 case Operator.LogicalAnd:
1122 case Operator.BitwiseAnd:
1123 opcode = OpCodes.And;
1126 case Operator.ExclusiveOr:
1127 opcode = OpCodes.Xor;
1131 throw new Exception ("This should not happen: Operator = "
1132 + oper.ToString ());
1135 ec.ig.Emit (opcode);
1139 public class Conditional : Expression {
1140 Expression expr, trueExpr, falseExpr;
1142 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr)
1145 this.trueExpr = trueExpr;
1146 this.falseExpr = falseExpr;
1149 public Expression Expr {
1155 public Expression TrueExpr {
1161 public Expression FalseExpr {
1167 public override Expression Resolve (TypeContainer tc)
1169 // FIXME: Implement;
1173 public override void Emit (EmitContext ec)
1178 public class SimpleName : Expression {
1181 public SimpleName (string name)
1186 public string Name {
1193 // Checks whether we are trying to access an instance
1194 // property, method or field from a static body.
1196 Expression MemberStaticCheck (Report r, Expression e)
1198 if (e is FieldExpr){
1199 FieldInfo fi = ((FieldExpr) e).FieldInfo;
1203 "An object reference is required " +
1204 "for the non-static field `"+name+"'");
1207 } else if (e is MethodGroupExpr){
1208 // FIXME: Pending reorganization of MemberLookup
1209 // Basically at this point we should have the
1210 // best match already selected for us, and
1211 // we should only have to check a *single*
1212 // Method for its static on/off bit.
1214 } else if (e is PropertyExpr){
1215 if (!((PropertyExpr) e).IsStatic){
1217 "An object reference is required " +
1218 "for the non-static property access `"+
1228 // 7.5.2: Simple Names.
1230 // Local Variables and Parameters are handled at
1231 // parse time, so they never occur as SimpleNames.
1233 Expression ResolveSimpleName (TypeContainer tc)
1236 Report r = tc.RootContext.Report;
1238 e = MemberLookup (tc.RootContext, tc.TypeBuilder, name, true);
1242 if ((tc.ModFlags & Modifiers.STATIC) != 0)
1243 return MemberStaticCheck (r, e);
1249 // Do step 3 of the Simple Name resolution.
1251 // FIXME: implement me.
1257 // SimpleName needs to handle a multitude of cases:
1259 // simple_names and qualified_identifiers are placed on
1260 // the tree equally.
1262 public override Expression Resolve (TypeContainer tc)
1264 if (name.IndexOf (".") != -1)
1265 return ResolveMemberAccess (tc, name);
1267 return ResolveSimpleName (tc);
1270 public override void Emit (EmitContext ec)
1275 public class LocalVariableReference : Expression {
1276 public readonly string Name;
1277 public readonly Block Block;
1279 public LocalVariableReference (Block block, string name)
1283 eclass = ExprClass.Variable;
1286 public VariableInfo VariableInfo {
1288 return Block.GetVariableInfo (Name);
1292 public override Expression Resolve (TypeContainer tc)
1294 VariableInfo vi = Block.GetVariableInfo (Name);
1296 type = vi.VariableType;
1300 public override void Emit (EmitContext ec)
1302 VariableInfo vi = VariableInfo;
1303 ILGenerator ig = ec.ig;
1308 ig.Emit (OpCodes.Ldloc_0);
1312 ig.Emit (OpCodes.Ldloc_1);
1316 ig.Emit (OpCodes.Ldloc_2);
1320 ig.Emit (OpCodes.Ldloc_3);
1325 ig.Emit (OpCodes.Ldloc_S, idx);
1327 ig.Emit (OpCodes.Ldloc, idx);
1333 public class ParameterReference : Expression {
1334 public readonly Parameters Pars;
1335 public readonly String Name;
1336 public readonly int Idx;
1338 public ParameterReference (Parameters pars, int idx, string name)
1345 public override Expression Resolve (TypeContainer tc)
1347 Type [] types = Pars.GetParameterInfo (tc);
1354 public override void Emit (EmitContext ec)
1357 ec.ig.Emit (OpCodes.Ldarg_S, Idx);
1359 ec.ig.Emit (OpCodes.Ldarg, Idx);
1364 // Used for arguments to New(), Invocation()
1366 public class Argument {
1373 public readonly AType Type;
1376 public Argument (Expression expr, AType type)
1382 public Expression Expr {
1388 public bool Resolve (TypeContainer tc)
1390 expr = expr.Resolve (tc);
1392 return expr != null;
1395 public void Emit (EmitContext ec)
1402 // Invocation of methods or delegates.
1404 public class Invocation : Expression {
1405 public readonly ArrayList Arguments;
1407 MethodInfo method = null;
1409 static Hashtable method_parameter_cache;
1412 // arguments is an ArrayList, but we do not want to typecast,
1413 // as it might be null.
1415 // FIXME: only allow expr to be a method invocation or a
1416 // delegate invocation (7.5.5)
1418 public Invocation (Expression expr, ArrayList arguments)
1421 Arguments = arguments;
1424 public Expression Expr {
1431 /// Computes whether Argument `a' and the ParameterInfo `pi' are
1432 /// compatible, and if so, how good is the match (in terms of
1433 /// "better conversions" (7.4.2.3).
1435 /// 0 is the best possible match.
1436 /// -1 represents a type mismatch.
1437 /// -2 represents a ref/out mismatch.
1439 static int Badness (Argument a, Type t)
1441 if (a.Expr.Type == null){
1442 throw new Exception ("Expression of type " + a.Expr + " does not resolve its type");
1445 if (t == a.Expr.Type)
1448 // FIXME: Implement implicit conversions here.
1449 // FIXME: Implement better conversion here.
1454 static ParameterData GetParameterData (TypeContainer tc, MethodBase mb)
1456 object pd = method_parameter_cache [mb];
1459 return (ParameterData) pd;
1461 if (mb is MethodBuilder){
1462 Method m = tc.LookupMethodByBuilder ((MethodBuilder) mb);
1464 InternalParameters ip = m.GetParameters ();
1465 method_parameter_cache [mb] = ip;
1467 return (ParameterData) ip;
1469 ParameterInfo [] pi = mb.GetParameters ();
1470 ReflectionParameters rp = new ReflectionParameters (pi);
1471 method_parameter_cache [mb] = rp;
1473 return (ParameterData) rp;
1478 // Find the Applicable Function Members (7.4.2.1)
1480 static MethodInfo OverloadResolve (TypeContainer tc, MethodGroupExpr me, ArrayList Arguments)
1482 ArrayList afm = new ArrayList ();
1483 int best_match = 10000;
1484 int best_match_idx = -1;
1485 MethodInfo method = null;
1487 for (int i = me.Methods.Length; i > 0; ){
1489 MethodBase mb = me.Methods [i];
1492 pd = GetParameterData (tc, mb);
1495 // Compute how good this is
1497 if (pd.Count == Arguments.Count){
1500 for (int j = Arguments.Count; j > 0;){
1504 Argument a = (Argument) Arguments [j];
1506 x = Badness (a, pd.ParameterType (j));
1509 badness = best_match;
1516 if (badness < best_match){
1517 best_match = badness;
1518 method = me.Methods [i];
1524 if (best_match_idx == -1)
1531 public override Expression Resolve (TypeContainer tc)
1534 // First, resolve the expression that is used to
1535 // trigger the invocation
1537 this.expr = expr.Resolve (tc);
1538 if (this.expr == null)
1541 if (!(this.expr is MethodGroupExpr)){
1542 tc.RootContext.Report.Error (118,
1543 "Denotes an " + this.expr.ExprClass + " while a method was expected");
1547 if (method_parameter_cache == null)
1548 method_parameter_cache = new Hashtable ();
1551 // Next, evaluate all the expressions in the argument list
1553 if (Arguments != null){
1554 for (int i = Arguments.Count; i > 0;){
1556 Argument a = (Argument) Arguments [i];
1558 if (!a.Resolve (tc))
1563 method = OverloadResolve (tc, (MethodGroupExpr) this.expr, Arguments);
1565 if (method == null){
1566 tc.RootContext.Report.Error (-6,
1567 "Figure out error: Can not find a good function for this argument list");
1571 type = method.ReturnType;
1575 public override void Emit (EmitContext ec)
1577 int top = Arguments.Count;
1579 for (int i = 0; i < top; i++){
1580 Argument a = (Argument) Arguments [i];
1585 ec.ig.Emit (OpCodes.Call, (MethodInfo) method);
1589 public class New : Expression {
1596 public readonly NType NewType;
1597 public readonly ArrayList Arguments;
1598 public readonly string RequestedType;
1599 // These are for the case when we have an array
1600 public readonly string Rank;
1601 public readonly ArrayList Indices;
1602 public readonly ArrayList Initializers;
1605 public New (string requested_type, ArrayList arguments)
1607 RequestedType = requested_type;
1608 Arguments = arguments;
1609 NewType = NType.Object;
1612 public New (string requested_type, ArrayList exprs, string rank, ArrayList initializers)
1614 RequestedType = requested_type;
1617 Initializers = initializers;
1618 NewType = NType.Array;
1621 public override Expression Resolve (TypeContainer tc)
1623 // FIXME: Implement;
1627 public override void Emit (EmitContext ec)
1632 public class This : Expression {
1633 public override Expression Resolve (TypeContainer tc)
1635 // FIXME: Implement;
1639 public override void Emit (EmitContext ec)
1644 public class TypeOf : Expression {
1645 public readonly string QueriedType;
1647 public TypeOf (string queried_type)
1649 QueriedType = queried_type;
1652 public override Expression Resolve (TypeContainer tc)
1654 // FIXME: Implement;
1658 public override void Emit (EmitContext ec)
1663 public class SizeOf : Expression {
1664 public readonly string QueriedType;
1666 public SizeOf (string queried_type)
1668 this.QueriedType = queried_type;
1671 public override Expression Resolve (TypeContainer tc)
1673 // FIXME: Implement;
1677 public override void Emit (EmitContext ec)
1682 public class MemberAccess : Expression {
1683 public readonly string Identifier;
1686 public MemberAccess (Expression expr, string id)
1692 public Expression Expr {
1698 public override Expression Resolve (TypeContainer tc)
1700 // FIXME: Implement;
1704 public override void Emit (EmitContext ec)
1711 // Nodes of type Namespace are created during the semantic
1712 // analysis to resolve member_access/qualified_identifier/simple_name
1715 // They are born `resolved'.
1717 public class NamespaceExpr : Expression {
1718 public readonly string Name;
1720 public NamespaceExpr (string name)
1723 eclass = ExprClass.Namespace;
1726 public override Expression Resolve (TypeContainer tc)
1731 public override void Emit (EmitContext ec)
1737 // Fully resolved expression that evaluates to a type
1739 public class TypeExpr : Expression {
1740 public TypeExpr (Type t)
1743 eclass = ExprClass.Type;
1746 override public Expression Resolve (TypeContainer tc)
1751 override public void Emit (EmitContext ec)
1758 // Fully resolved expression that evaluates to a type
1760 public class MethodGroupExpr : Expression {
1761 public readonly MethodInfo [] Methods;
1763 public MethodGroupExpr (MemberInfo [] mi)
1765 Methods = new MethodInfo [mi.Length];
1766 mi.CopyTo (Methods, 0);
1767 eclass = ExprClass.MethodGroup;
1770 override public Expression Resolve (TypeContainer tc)
1775 override public void Emit (EmitContext ec)
1781 public class BuiltinTypeAccess : Expression {
1782 public readonly string AccessBase;
1783 public readonly string Method;
1785 public BuiltinTypeAccess (string type, string method)
1787 System.Console.WriteLine ("DUDE! This type should be fully resolved!");
1792 public override Expression Resolve (TypeContainer tc)
1794 // FIXME: Implement;
1798 public override void Emit (EmitContext ec)
1804 // Fully resolved expression that evaluates to a Field
1806 public class FieldExpr : Expression {
1807 public readonly FieldInfo FieldInfo;
1809 public FieldExpr (FieldInfo fi)
1812 eclass = ExprClass.Variable;
1815 override public Expression Resolve (TypeContainer tc)
1817 // We are born in resolved state.
1821 override public void Emit (EmitContext ec)
1823 // FIXME: Assert that this should not be reached?
1828 // Fully resolved expression that evaluates to a Property
1830 public class PropertyExpr : Expression {
1831 public readonly PropertyInfo PropertyInfo;
1832 public readonly bool IsStatic;
1834 public PropertyExpr (PropertyInfo pi)
1837 eclass = ExprClass.PropertyAccess;
1840 MethodInfo [] acc = pi.GetAccessors ();
1842 for (int i = 0; i < acc.Length; i++)
1843 if (acc [i].IsStatic)
1847 override public Expression Resolve (TypeContainer tc)
1849 // We are born in resolved state.
1853 override public void Emit (EmitContext ec)
1855 // FIXME: Implement.
1860 // Fully resolved expression that evaluates to a Property
1862 public class EventExpr : Expression {
1863 public readonly EventInfo EventInfo;
1865 public EventExpr (EventInfo ei)
1868 eclass = ExprClass.EventAccess;
1871 override public Expression Resolve (TypeContainer tc)
1873 // We are born in resolved state.
1877 override public void Emit (EmitContext ec)
1879 // FIXME: Implement.
1883 public class CheckedExpr : Expression {
1885 public readonly Expression Expr;
1887 public CheckedExpr (Expression e)
1892 public override Expression Resolve (TypeContainer tc)
1894 // FIXME : Implement !
1898 public override void Emit (EmitContext ec)
1904 public class UnCheckedExpr : Expression {
1906 public readonly Expression Expr;
1908 public UnCheckedExpr (Expression e)
1913 public override Expression Resolve (TypeContainer tc)
1915 // FIXME : Implement !
1919 public override void Emit (EmitContext ec)
1925 public class ElementAccess : Expression {
1927 public readonly ArrayList Arguments;
1928 public readonly Expression Expr;
1930 public ElementAccess (Expression e, ArrayList e_list)
1936 public override Expression Resolve (TypeContainer tc)
1938 // FIXME : Implement
1942 public override void Emit (EmitContext ec)
1944 // FIXME : Implement !
1949 public class BaseAccess : Expression {
1951 public enum BaseAccessType {
1956 public readonly BaseAccessType BAType;
1957 public readonly string Member;
1958 public readonly ArrayList Arguments;
1960 public BaseAccess (BaseAccessType t, string member, ArrayList args)
1968 public override Expression Resolve (TypeContainer tc)
1970 // FIXME : Implement !
1974 public override void Emit (EmitContext ec)